1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * CDDL HEADER START
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * The contents of this file are subject to the terms of the
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Common Development and Distribution License (the "License").
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * You may not use this file except in compliance with the License.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * See the License for the specific language governing permissions
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * and limitations under the License.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * When distributing Covered Code, include this CDDL HEADER in each
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * If applicable, add the following below this CDDL HEADER, with the
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * fields enclosed by brackets "[]" replaced with your own identifying
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * information: Portions Copyright [yyyy] [name of copyright owner]
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * CDDL HEADER END
34f94fbc7a730740933e4776ade5f74009afe4ceWENTAO YANG * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lm * sun4v LDC Link Layer
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#include <sys/stat.h> /* needed for S_IFBLK and S_IFCHR */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* Core internal functions */
20ae46ebaff1237662e05edf9db61538aa85d448havoid i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset);
3af08d828975d7e2581b6829e0eecff14d87a483lmstatic int i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset);
5699897cfc22a71e1441854892e3659f179ee0bcHaik Aftandilianstatic void i_ldc_debug_enter(void);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail);
22f747ef037d84d7799b60247ff9a3df1604a7eenarayanstatic void i_ldc_get_tx_head(ldc_chan_t *ldcp, uint64_t *head);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype,
582832867ac00db0b1619c1bb890285984d338c9hastatic int i_ldc_set_rxdq_head(ldc_chan_t *ldcp, uint64_t head);
582832867ac00db0b1619c1bb890285984d338c9hastatic void i_ldc_rxdq_copy(ldc_chan_t *ldcp, uint64_t *head);
582832867ac00db0b1619c1bb890285984d338c9hastatic uint64_t i_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head,
582832867ac00db0b1619c1bb890285984d338c9hastatic uint64_t i_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head,
582832867ac00db0b1619c1bb890285984d338c9hastatic int i_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* Interrupt handling functions */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic uint_t i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic uint_t i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2);
582832867ac00db0b1619c1bb890285984d338c9hastatic uint_t i_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic void i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* Read method functions */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* Write method functions */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t target_bufp,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t target_bufp,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t target_bufp,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* Pkt processing internal functions */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg);
34f94fbc7a730740933e4776ade5f74009afe4ceWENTAO YANG/* Imported functions */
34f94fbc7a730740933e4776ade5f74009afe4ceWENTAO YANGextern void i_ldc_mem_set_hsvc_vers(uint64_t major, uint64_t minor);
34f94fbc7a730740933e4776ade5f74009afe4ceWENTAO YANGextern void i_ldc_init_mapin(ldc_soft_state_t *ldcssp, uint64_t major,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* LDC Version */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* number of supported versions */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#define LDC_NUM_VERS (sizeof (ldc_versions) / sizeof (ldc_versions[0]))
582832867ac00db0b1619c1bb890285984d338c9ha/* Invalid value for the ldc_chan_t rx_ack_head field */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* Module State Pointer */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic uint64_t ldc_sup_minor; /* Supported minor number */
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lm * The no. of MTU size messages that can be stored in
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lm * the LDC Tx queue. The number of Tx queue entries is
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lm * then computed as (mtu * mtu_msgs)/sizeof(queue_entry)
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lm * The minimum queue length. This is the size of the smallest
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lm * LDC queue. If the computed value is less than this default,
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lm * the queue length is rounded up to 'ldc_queue_entries'.
582832867ac00db0b1619c1bb890285984d338c9ha * The length of the reliable-mode data queue in terms of the LDC
582832867ac00db0b1619c1bb890285984d338c9ha * receive queue length. i.e., the number of times larger than the
582832867ac00db0b1619c1bb890285984d338c9ha * LDC receive queue that the data queue should be. The HV receive
582832867ac00db0b1619c1bb890285984d338c9ha * queue is required to be a power of 2 and this implementation
582832867ac00db0b1619c1bb890285984d338c9ha * assumes the data queue will also be a power of 2. By making the
582832867ac00db0b1619c1bb890285984d338c9ha * multiplier a power of 2, we ensure the data queue will be a
582832867ac00db0b1619c1bb890285984d338c9ha * power of 2. We use a multiplier because the receive queue is
582832867ac00db0b1619c1bb890285984d338c9ha * sized to be sane relative to the MTU and the same is needed for
582832867ac00db0b1619c1bb890285984d338c9ha * the data queue.
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lm * LDC retry count and delay - when the HV returns EWOULDBLOCK
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lm * the operation is retried 'ldc_max_retries' times with a
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lm * wait of 'ldc_delay' usecs between each retry.
5699897cfc22a71e1441854892e3659f179ee0bcHaik Aftandilian * Channels which have a devclass satisfying the following
5699897cfc22a71e1441854892e3659f179ee0bcHaik Aftandilian * will be reset when entering the prom or kmdb.
5699897cfc22a71e1441854892e3659f179ee0bcHaik Aftandilian * LDC_DEVCLASS_PROM_RESET(devclass) != 0
5699897cfc22a71e1441854892e3659f179ee0bcHaik Aftandilian * By default, only block device service channels are reset.
5699897cfc22a71e1441854892e3659f179ee0bcHaik Aftandilian (LDC_DEVCLASS_BIT(dc) & ldc_debug_reset_mask)
d16449db47fba8bd718a61fc5d506d05ec79ff93Zach Kisselstatic uint64_t ldc_debug_reset_mask = LDC_DEVCLASS_BIT(LDC_DEV_BLK_SVC) |
4d39be2b45b5ac811d28452e6eb629ac64aebfc4sg * delay between each retry of channel unregistration in
4d39be2b45b5ac811d28452e6eb629ac64aebfc4sg * ldc_close(), to wait for pending interrupts to complete.
34f94fbc7a730740933e4776ade5f74009afe4ceWENTAO YANG * Reserved mapin space for descriptor rings.
34f94fbc7a730740933e4776ade5f74009afe4ceWENTAO YANGuint64_t ldc_dring_direct_map_rsvd = LDC_DIRECT_MAP_SIZE_DEFAULT;
34f94fbc7a730740933e4776ade5f74009afe4ceWENTAO YANG * Maximum direct map space allowed per channel.
34f94fbc7a730740933e4776ade5f74009afe4ceWENTAO YANGuint64_t ldc_direct_map_size_max = (16 * 1024 * 1024); /* 16 MB */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Print debug messages
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * set ldcdbg to 0x7 for enabling all msgs
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * 0x4 - Warnings
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * 0x2 - All debug messages
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * 0x1 - Minimal debug messages
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * set ldcdbgchan to the channel number you want to debug
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * setting it to -1 prints debug messages for all channels
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * NOTE: ldcdbgchan has no effect on error messages
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Do not return if,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * caller wants to print it anyway - (id == DBG_ALL_LDCS)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * debug channel is set to all LDCs - (ldcdbgchan == DBG_ALL_LDCS)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * debug channel = caller specified channel
3af08d828975d7e2581b6829e0eecff14d87a483lm if ((ldcdbgchan != DBG_ALL_LDCS) && (ldcdbgchan != ldcp->id))
3af08d828975d7e2581b6829e0eecff14d87a483lm /* clear the injection state */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo uint32_t mid = ((c)->mode != LDC_MODE_RAW) ? msg->seqid : 0; \
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D2((c)->id, "%s: msg%d (/%x/%x/%x/,env[%c%c,sz=%d])", \
83d3bc6f9969f95595135be43a57b8066f5e3273narayan#define LDC_INJECT_RESET(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_RESET)
83d3bc6f9969f95595135be43a57b8066f5e3273narayan#define LDC_INJECT_PKTLOSS(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_PKTLOSS)
582832867ac00db0b1619c1bb890285984d338c9ha#define LDC_INJECT_DQFULL(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_DQFULL)
bbfa0259e68b6b625e9e085053d41d620f185eeeha#define LDC_INJECT_DRNGCLEAR(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_DRNGCLEAR)
bbfa0259e68b6b625e9e085053d41d620f185eeehaextern void i_ldc_mem_inject_dring_clear(ldc_chan_t *ldcp);
582832867ac00db0b1619c1bb890285984d338c9ha * dtrace SDT probes to ease tracing of the rx data queue and HV queue
582832867ac00db0b1619c1bb890285984d338c9ha * lengths. Just pass the head, tail, and entries values so that the
582832867ac00db0b1619c1bb890285984d338c9ha * length can be calculated in a dtrace script when the probe is enabled.
582832867ac00db0b1619c1bb890285984d338c9ha/* A dtrace SDT probe to ease tracing of data queue copy operations */
582832867ac00db0b1619c1bb890285984d338c9ha DTRACE_PROBE2(rxdq__copy, uint64_t, ldcp->id, uint64_t, bytes) \
582832867ac00db0b1619c1bb890285984d338c9ha/* The amount of contiguous space at the tail of the queue */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (((pg_szc) << LDC_COOKIE_PGSZC_SHIFT) | ((idx) << (pg_shift)))
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (status != 0) {
d66f83158d97c12b2a78b9363a07d9d365762606jb cmn_err(CE_NOTE, "!%s: cannot negotiate hypervisor LDC services"
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo " group: 0x%lx major: %ld minor: %ld errno: %d",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (-1);
bbfa0259e68b6b625e9e085053d41d620f185eeeha /* Initialize shared memory HV API version checking */
bbfa0259e68b6b625e9e085053d41d620f185eeeha i_ldc_mem_set_hsvc_vers(ldc_hsvc.hsvc_major, ldc_sup_minor);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* allocate soft state structure */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo ldcssp = kmem_zalloc(sizeof (ldc_soft_state_t), KM_SLEEP);
34f94fbc7a730740933e4776ade5f74009afe4ceWENTAO YANG i_ldc_init_mapin(ldcssp, ldc_hsvc.hsvc_major, ldc_sup_minor);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Link the module into the system */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (status != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Initialize the LDC state structure */
4bac220845f606f60663ed6f3a2b88caa00ae87enarayan /* Create a cache for memory handles */
4bac220845f606f60663ed6f3a2b88caa00ae87enarayan ldcssp->memhdl_cache = kmem_cache_create("ldc_memhdl_cache",
4bac220845f606f60663ed6f3a2b88caa00ae87enarayan sizeof (ldc_mhdl_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
4bac220845f606f60663ed6f3a2b88caa00ae87enarayan DWARN(DBG_ALL_LDCS, "_init: ldc_memhdl cache create failed\n");
4bac220845f606f60663ed6f3a2b88caa00ae87enarayan return (-1);
4bac220845f606f60663ed6f3a2b88caa00ae87enarayan /* Create cache for memory segment structures */
4bac220845f606f60663ed6f3a2b88caa00ae87enarayan ldcssp->memseg_cache = kmem_cache_create("ldc_memseg_cache",
4bac220845f606f60663ed6f3a2b88caa00ae87enarayan sizeof (ldc_memseg_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
4bac220845f606f60663ed6f3a2b88caa00ae87enarayan DWARN(DBG_ALL_LDCS, "_init: ldc_memseg cache create failed\n");
4bac220845f606f60663ed6f3a2b88caa00ae87enarayan return (-1);
5699897cfc22a71e1441854892e3659f179ee0bcHaik Aftandilian /* Register debug_enter callback */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Report status of the dynamically loadable driver module */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Unlink the driver module from the system */
5699897cfc22a71e1441854892e3659f179ee0bcHaik Aftandilian /* Unregister debug_enter callback */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Free descriptor rings */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = ldc_mem_dring_info((ldc_dring_handle_t)dringp, &minfo);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (void) ldc_mem_dring_destroy((ldc_dring_handle_t)dringp);
22f747ef037d84d7799b60247ff9a3df1604a7eenarayan /* close and finalize channels */
4bac220845f606f60663ed6f3a2b88caa00ae87enarayan /* Destroy kmem caches */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * We have successfully "removed" the driver.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Destroying soft states
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* -------------------------------------------------------------------------- */
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lm * LDC Link Layer Internal Functions
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Translate HV Errors to sun4v error codes
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Reconfigure the transmit queue
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries);
3af08d828975d7e2581b6829e0eecff14d87a483lm D1(ldcp->id, "i_ldc_txq_reconf: (0x%llx) h=0x%llx,t=0x%llx,"
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Reconfigure the receive queue
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
3af08d828975d7e2581b6829e0eecff14d87a483lm "i_ldc_rxq_reconf: (0x%lx) cannot get state",
3af08d828975d7e2581b6829e0eecff14d87a483lm if (force_reset || (ldcp->tstate & ~TS_IN_RESET) == TS_UP) {
3af08d828975d7e2581b6829e0eecff14d87a483lm "i_ldc_rxq_reconf: (0x%lx) cannot set qconf",
3af08d828975d7e2581b6829e0eecff14d87a483lm D1(ldcp->id, "i_ldc_rxq_reconf: (0x%llx) completed q reconf",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
a8ea4ede2107d9ad3895b91946b9f33a83c5f7eenarayan * Drain the contents of the receive queue
a8ea4ede2107d9ad3895b91946b9f33a83c5f7eenarayan rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
305dbad45ddcb5d7fc7a5021e7d7d45a9a2c0a91Kevin Crowe cmn_err(CE_WARN, "i_ldc_rxq_drain: (0x%lx) cannot get state, "
32225099e54624ac7ab99ad6597a3ca99ca53c25Zach Kissel /* If the queue is already empty just return success. */
305dbad45ddcb5d7fc7a5021e7d7d45a9a2c0a91Kevin Crowe * We are draining the queue in order to close the channel.
305dbad45ddcb5d7fc7a5021e7d7d45a9a2c0a91Kevin Crowe * Call hv_ldc_rx_set_qhead directly instead of i_ldc_set_rx_head
305dbad45ddcb5d7fc7a5021e7d7d45a9a2c0a91Kevin Crowe * because we do not need to reset the channel if the set
305dbad45ddcb5d7fc7a5021e7d7d45a9a2c0a91Kevin Crowe * qhead fails.
305dbad45ddcb5d7fc7a5021e7d7d45a9a2c0a91Kevin Crowe if ((rv = hv_ldc_rx_set_qhead(ldcp->id, rx_tail)) == 0)
305dbad45ddcb5d7fc7a5021e7d7d45a9a2c0a91Kevin Crowe while ((rv == H_EWOULDBLOCK) && (retries++ < ldc_max_retries)) {
305dbad45ddcb5d7fc7a5021e7d7d45a9a2c0a91Kevin Crowe if ((rv = hv_ldc_rx_set_qhead(ldcp->id, rx_tail)) == 0)
305dbad45ddcb5d7fc7a5021e7d7d45a9a2c0a91Kevin Crowe cmn_err(CE_WARN, "i_ldc_rxq_drain: (0x%lx) cannot set qhead 0x%lx, "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Reset LDC state structure and its contents
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Reset a LDC channel
83d3bc6f9969f95595135be43a57b8066f5e3273narayan DWARN(ldcp->id, "i_ldc_reset: (0x%llx) channel reset\n", ldcp->id);
3af08d828975d7e2581b6829e0eecff14d87a483lm /* reconfig Tx and Rx queues */
3af08d828975d7e2581b6829e0eecff14d87a483lm /* Clear Tx and Rx interrupts */
3af08d828975d7e2581b6829e0eecff14d87a483lm /* Reset channel state */
3af08d828975d7e2581b6829e0eecff14d87a483lm /* Mark channel in reset */
5699897cfc22a71e1441854892e3659f179ee0bcHaik Aftandilian * Walk the channel list and reset channels if they are of the right
5699897cfc22a71e1441854892e3659f179ee0bcHaik Aftandilian * devclass and their Rx queues have been configured. No locks are
5699897cfc22a71e1441854892e3659f179ee0bcHaik Aftandilian * taken because the function is only invoked by the kernel just before
5699897cfc22a71e1441854892e3659f179ee0bcHaik Aftandilian * entering the prom or debugger when the system is single-threaded.
5699897cfc22a71e1441854892e3659f179ee0bcHaik Aftandilian if (((ldcp->tstate & TS_QCONF_RDY) == TS_QCONF_RDY) &&
5699897cfc22a71e1441854892e3659f179ee0bcHaik Aftandilian (LDC_DEVCLASS_PROM_RESET(ldcp->devclass) != 0)) {
5699897cfc22a71e1441854892e3659f179ee0bcHaik Aftandilian (void) hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Clear pending interrupts
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppoi_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype)
3af08d828975d7e2581b6829e0eecff14d87a483lm switch (itype) {
4bac220845f606f60663ed6f3a2b88caa00ae87enarayan /* check Tx interrupt */
3af08d828975d7e2581b6829e0eecff14d87a483lm /* check Rx interrupt */
3af08d828975d7e2581b6829e0eecff14d87a483lm "i_ldc_clear_intr: (0x%llx) cleared 0x%x intr\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Set the receive queue head
0a55fbb79ee31ed09f84a9ae28e9747bc23f4a08lm * Resets connection and returns an error if it fails.
0a55fbb79ee31ed09f84a9ae28e9747bc23f4a08lm for (retries = 0; retries < ldc_max_retries; retries++) {
0a55fbb79ee31ed09f84a9ae28e9747bc23f4a08lm return (0);
0a55fbb79ee31ed09f84a9ae28e9747bc23f4a08lm /* wait for ldc_delay usecs */
305dbad45ddcb5d7fc7a5021e7d7d45a9a2c0a91Kevin Crowe cmn_err(CE_WARN, "ldc_set_rx_qhead: (0x%lx) cannot set qhead 0x%lx, "
22f747ef037d84d7799b60247ff9a3df1604a7eenarayan * Returns the tx_head to be used for transfer
22f747ef037d84d7799b60247ff9a3df1604a7eenarayan /* get current Tx head */
22f747ef037d84d7799b60247ff9a3df1604a7eenarayan * Reliable mode will use the ACKd head instead of the regular tx_head.
22f747ef037d84d7799b60247ff9a3df1604a7eenarayan * Also in Reliable mode, advance ackd_head for all non DATA/INFO pkts,
22f747ef037d84d7799b60247ff9a3df1604a7eenarayan * up to the current location of tx_head. This needs to be done
22f747ef037d84d7799b60247ff9a3df1604a7eenarayan * as the peer will only ACK DATA/INFO pkts.
22f747ef037d84d7799b60247ff9a3df1604a7eenarayan pkt = (ldc_msg_t *)(ldcp->tx_q_va + ldcp->tx_ackd_head);
22f747ef037d84d7799b60247ff9a3df1604a7eenarayan if ((pkt->type & LDC_DATA) && (pkt->stype & LDC_INFO)) {
22f747ef037d84d7799b60247ff9a3df1604a7eenarayan /* advance ACKd head */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Returns the tx_tail to be used for transfer
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Re-reads the TX queue ptrs if and only if the
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * the cached head and tail are equal (queue is full)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Read the head and tail ptrs from HV */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_get_tx_tail: (0x%lx) cannot read qptrs\n",
cb112a141f667f84bf442a77589d1705a2336dbelm D1(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) channel not ready\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* increment the tail */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_get_tx_tail: (0x%llx) TX queue is full\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D2(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) head=0x%llx, tail=0x%llx\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Set the tail pointer. If HV returns EWOULDBLOCK, it will back off
0a55fbb79ee31ed09f84a9ae28e9747bc23f4a08lm * and retry ldc_max_retries times before returning an error.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Returns 0, EWOULDBLOCK or EIO
0a55fbb79ee31ed09f84a9ae28e9747bc23f4a08lm for (retries = 0; retries < ldc_max_retries; retries++) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if ((rv = hv_ldc_tx_set_qtail(ldcp->id, tail)) == 0) {
0a55fbb79ee31ed09f84a9ae28e9747bc23f4a08lm /* wait for ldc_delay usecs */
582832867ac00db0b1619c1bb890285984d338c9ha * Copy a data packet from the HV receive queue to the data queue.
582832867ac00db0b1619c1bb890285984d338c9ha * Caller must ensure that the data queue is not already full.
582832867ac00db0b1619c1bb890285984d338c9ha * The *head argument represents the current head pointer for the HV
582832867ac00db0b1619c1bb890285984d338c9ha * receive queue. After copying a packet from the HV receive queue,
582832867ac00db0b1619c1bb890285984d338c9ha * the *head pointer will be updated. This allows the caller to update
582832867ac00db0b1619c1bb890285984d338c9ha * the head pointer in HV using the returned *head value.
582832867ac00db0b1619c1bb890285984d338c9ha ASSERT(Q_CONTIG_SPACE(ldcp->rx_dq_head, ldcp->rx_dq_tail,
582832867ac00db0b1619c1bb890285984d338c9ha (void *)(ldcp->rx_dq_va + ldcp->rx_dq_tail), LDC_PACKET_SIZE);
582832867ac00db0b1619c1bb890285984d338c9ha /* Update rx head */
582832867ac00db0b1619c1bb890285984d338c9ha /* Update dq tail */
582832867ac00db0b1619c1bb890285984d338c9ha ldcp->rx_dq_tail = (ldcp->rx_dq_tail + LDC_PACKET_SIZE) % dq_size;
582832867ac00db0b1619c1bb890285984d338c9ha * Update the Rx data queue head pointer
582832867ac00db0b1619c1bb890285984d338c9ha return (0);
582832867ac00db0b1619c1bb890285984d338c9ha * Get the Rx data queue head and tail pointers
582832867ac00db0b1619c1bb890285984d338c9hai_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail,
582832867ac00db0b1619c1bb890285984d338c9ha return (0);
582832867ac00db0b1619c1bb890285984d338c9ha * Wrapper for the Rx HV queue set head function. Giving the
582832867ac00db0b1619c1bb890285984d338c9ha * data queue and HV queue set head functions the same type.
582832867ac00db0b1619c1bb890285984d338c9hai_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail,
582832867ac00db0b1619c1bb890285984d338c9ha return (i_ldc_h2v_error(hv_ldc_rx_get_state(ldcp->id, head, tail,
582832867ac00db0b1619c1bb890285984d338c9ha * LDC receive interrupt handler
582832867ac00db0b1619c1bb890285984d338c9ha * triggered for channel with data pending to read
582832867ac00db0b1619c1bb890285984d338c9ha * i.e. Rx queue content changes
582832867ac00db0b1619c1bb890285984d338c9ha /* Get the channel for which interrupt was received */
582832867ac00db0b1619c1bb890285984d338c9ha D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n",
582832867ac00db0b1619c1bb890285984d338c9ha D1(ldcp->id, "i_ldc_rx_hdlr: (%llx) USR%lx/TS%lx/HS%lx, LSTATE=%lx\n",
582832867ac00db0b1619c1bb890285984d338c9ha /* Lock channel */
582832867ac00db0b1619c1bb890285984d338c9ha /* Mark the interrupt as being actively handled */
582832867ac00db0b1619c1bb890285984d338c9ha * If there are no data packets on the queue, clear
582832867ac00db0b1619c1bb890285984d338c9ha * the interrupt. Otherwise, the ldc_read will clear
582832867ac00db0b1619c1bb890285984d338c9ha * interrupts after draining the queue. To indicate the
582832867ac00db0b1619c1bb890285984d338c9ha * interrupt has not yet been cleared, it is marked
582832867ac00db0b1619c1bb890285984d338c9ha * as pending.
582832867ac00db0b1619c1bb890285984d338c9ha /* if callbacks are disabled, do not notify */
582832867ac00db0b1619c1bb890285984d338c9ha "i_ldc_rx_hdlr: (0x%llx) callback failure",
12f80fa62ea9b3208390b1204a47ed5498881e7dha * Here, ENOSPC indicates the secondary data
12f80fa62ea9b3208390b1204a47ed5498881e7dha * queue is full and the Rx queue is non-empty.
12f80fa62ea9b3208390b1204a47ed5498881e7dha * Much like how reliable and raw modes are
12f80fa62ea9b3208390b1204a47ed5498881e7dha * handled above, since the Rx queue is non-
12f80fa62ea9b3208390b1204a47ed5498881e7dha * empty, we mark the interrupt as pending to
12f80fa62ea9b3208390b1204a47ed5498881e7dha * indicate it has not yet been cleared.
12f80fa62ea9b3208390b1204a47ed5498881e7dha * We have processed all CTRL packets and
12f80fa62ea9b3208390b1204a47ed5498881e7dha * copied all DATA packets to the secondary
12f80fa62ea9b3208390b1204a47ed5498881e7dha * queue. Clear the interrupt.
582832867ac00db0b1619c1bb890285984d338c9ha D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) exiting handler", ldcp->id);
582832867ac00db0b1619c1bb890285984d338c9ha * Wrapper for the Rx HV queue processing function to be used when
582832867ac00db0b1619c1bb890285984d338c9ha * checking the Rx HV queue for data packets. Unlike the interrupt
582832867ac00db0b1619c1bb890285984d338c9ha * handler code flow, the Rx interrupt is not cleared here and
582832867ac00db0b1619c1bb890285984d338c9ha * callbacks are not made.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Send a LDC message
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppoi_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype,
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* Obtain Tx lock */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* get the current tail for the message */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_send_pkt: (0x%llx) error sending pkt, "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "type=0x%x,subtype=0x%x,ctrl=0x%x\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Initialize the packet */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Store ackid/seqid iff it is RELIABLE mode & not a RTS/RTR message */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* initiate the send by calling into HV and set the new tail */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_send_pkt:(0x%llx) error sending pkt, "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "type=0x%x,stype=0x%x,ctrl=0x%x\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Checks if packet was received in right order
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lm * in the case of a reliable link.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Returns 0 if in order, else EIO
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* No seqid checking for RAW mode */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* No seqid checking for version, RTS, RTR message */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Initial seqid to use is sent in RTS/RTR and saved in last_msg_rcd */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_check_seqid: (0x%llx) out-of-order pkt, got 0x%x, "
83d3bc6f9969f95595135be43a57b8066f5e3273narayan "i_ldc_check_seqid: (0x%llx) inject pkt loss\n", ldcp->id);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Process an incoming version ctrl message
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* get the received version */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rcvd_ver = (ldc_ver_t *)((uint64_t)msg + LDC_PAYLOAD_VER_OFF);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D2(ldcp->id, "i_ldc_process_VER: (0x%llx) received VER v%u.%u\n",
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* Obtain Tx lock */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* get the current tail and pkt for the response */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_process_VER: (0x%llx) err sending "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* initialize the packet */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1(ldcp->id, "i_ldc_process_VER: got %u.%u chk %u.%u\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* major version match - ACK version */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * lower minor version to the one this endpt
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * supports, if necessary
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* nack with next lower version */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* next major version */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* no version match - send NACK */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* initiate the send by calling into HV and set the new tail */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv == 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Save the ACK'd version */
3af08d828975d7e2581b6829e0eecff14d87a483lm "(0x%llx) Sent ACK, "
3af08d828975d7e2581b6829e0eecff14d87a483lm "Agreed on version v%u.%u\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_process_VER: (0x%llx) error sending "
3af08d828975d7e2581b6829e0eecff14d87a483lm /* mismatched version - reset connection */
22f747ef037d84d7799b60247ff9a3df1604a7eenarayan "i_ldc_process_VER: (0x%llx) recvd"
3af08d828975d7e2581b6829e0eecff14d87a483lm /* SUCCESS - we have agreed on a version */
cb112a141f667f84bf442a77589d1705a2336dbelm D1(ldcp->id, "(0x%llx) Got ACK, Agreed on version v%u.%u\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* initiate RTS-RTR-RDX handshake */
3af08d828975d7e2581b6829e0eecff14d87a483lm "i_ldc_process_VER: (0x%llx) cannot send RTS\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DUMP_LDC_PKT(ldcp, "i_ldc_process_VER snd rts", (uint64_t)pkt);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* initiate the send by calling into HV and set the new tail */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_process_VER: (0x%llx) no listener\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* check if version in NACK is zero */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* version handshake failure */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_process_VER: (0x%llx) no version match\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* get the current tail and pkt for the response */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_process_VER: (0x%lx) err sending "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* initialize the packet */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* check ver in NACK msg has a match */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * major version match - resubmit request
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * if lower minor version to the one this endpt
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * supports, if necessary
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* send next lower version */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* next version */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* no version match - terminate */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* initiate the send by calling into HV and set the new tail */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv == 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent version"
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_process_VER: (0x%lx) error sending version"
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Process an incoming RTS ctrl message
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D2(ldcp->id, "i_ldc_process_RTS: (0x%llx) received RTS\n", ldcp->id);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_process_RTS: (0x%llx) RTS NACK received\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Reset the channel -- as we cannot continue */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* check mode */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_process_RTS: (0x%lx) mode mismatch\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * send NACK in response to MODE message
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * get the current tail for the response
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTS);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* if cannot send NACK - reset channel */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN(ldcp->id, "i_ldc_process_RTS: (0x%llx) unexp ACK\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * If either the connection was reset (when rv != 0) or
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * a NACK was sent, we return. In the case of a NACK
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * we dont want to consume the packet that came in but
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * not record that we received the RTS
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* record RTS received */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* store initial SEQID info */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* Obtain Tx lock */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* get the current tail for the response */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_process_RTS: (0x%lx) err sending RTR\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* initialize the packet */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* initiate the send by calling into HV and set the new tail */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv == 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DUMP_LDC_PKT(ldcp, "i_ldc_process_RTS sent rtr", (uint64_t)pkt);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_process_RTS: (0x%lx) error sending RTR\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Process an incoming RTR ctrl message
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D2(ldcp->id, "i_ldc_process_RTR: (0x%llx) received RTR\n", ldcp->id);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* RTR NACK received */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_process_RTR: (0x%llx) RTR NACK received\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Reset the channel -- as we cannot continue */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* check mode */
cb112a141f667f84bf442a77589d1705a2336dbelm "i_ldc_process_RTR: (0x%llx) mode mismatch, "
cb112a141f667f84bf442a77589d1705a2336dbelm "expecting 0x%x, got 0x%x\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * send NACK in response to MODE message
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * get the current tail for the response
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTR);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* if cannot send NACK - reset channel */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN(ldcp->id, "i_ldc_process_RTR: (0x%llx) unexp ACK\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Reset the channel -- as we cannot continue */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * If either the connection was reset (when rv != 0) or
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * a NACK was sent, we return. In the case of a NACK
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * we dont want to consume the packet that came in but
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * not record that we received the RTR
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_INFO, LDC_RDX);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_process_RTR: (0x%lx) cannot send RDX\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Process an incoming RDX ctrl message
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D2(ldcp->id, "i_ldc_process_RDX: (0x%llx) received RDX\n", ldcp->id);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* RDX NACK received */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_process_RDX: (0x%llx) RDX NACK received\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Reset the channel -- as we cannot continue */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * if channel is UP and a RDX received after data transmission
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * has commenced it is an error
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if ((ldcp->tstate == TS_UP) && (ldcp->hstate & TS_RCVD_RDX)) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_process_RDX: (0x%llx) unexpected RDX"
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1(DBG_ALL_LDCS, "(0x%llx) Handshake Complete\n", ldcp->id);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN(ldcp->id, "i_ldc_process_RDX: (0x%llx) unexp ACK\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Reset the channel -- as we cannot continue */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Process an incoming ACK for a data packet
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppoi_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg)
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* Obtain Tx lock */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * Read the current Tx head and tail
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_process_data_ACK: (0x%lx) cannot read qptrs\n",
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* Reset the channel -- as we cannot continue */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * loop from where the previous ACK location was to the
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * current head location. This is how far the HV has
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * actually send pkts. Pkts between head and tail are
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * yet to be sent by HV.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_process_data_ACK: (0x%llx) found packet\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* could not find packet */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_process_data_ACK: (0x%llx) invalid ACKid\n",
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* Reset the channel -- as we cannot continue */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Process incoming control message
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Return 0 - session can continue
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * EAGAIN - reprocess packet - state was changed
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * ECONNRESET - channel was reset
3af08d828975d7e2581b6829e0eecff14d87a483lm D1(ldcp->id, "i_ldc_ctrlmsg: (%llx) tstate = %lx, hstate = %lx\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* process version message */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x "
3af08d828975d7e2581b6829e0eecff14d87a483lm /* process version message */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* process RTS message */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* process RTR message */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* process RDX message */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_ctrlmsg: (0x%llx) unexpected VER "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* peer is redoing version negotiation */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* process RDX message */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Register channel with the channel nexus
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_register_channel: cnex has not registered\n");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = cinfo->reg_chan(cinfo->dip, ldcp->id, ldcp->devclass);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_register_channel: cannot register channel\n");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_register_channel: cannot add Tx interrupt\n");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_register_channel: cannot add Rx interrupt\n");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (void) cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Unregister a channel with the channel nexus
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_unregister_channel: cnex has not registered\n");
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* Remove the Rx interrupt */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR);
3af08d828975d7e2581b6829e0eecff14d87a483lm "i_ldc_unregister_channel: err removing "
3af08d828975d7e2581b6829e0eecff14d87a483lm "Rx intr\n");
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
3af08d828975d7e2581b6829e0eecff14d87a483lm * If interrupts are pending and handler has
3af08d828975d7e2581b6829e0eecff14d87a483lm * finished running, clear interrupt and try
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
3af08d828975d7e2581b6829e0eecff14d87a483lm "err removing Rx interrupt\n");
3af08d828975d7e2581b6829e0eecff14d87a483lm return (rv);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* Remove the Tx interrupt */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_unregister_channel: err removing Tx intr\n");
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* Unregister the channel */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_unregister_channel: cannot unreg channel\n");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * LDC transmit interrupt handler
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * triggered for chanel up/down/reset events
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * and Tx queue content changes
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Get the channel for which interrupt was received */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Lock channel */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* Obtain Tx lock */
4bac220845f606f60663ed6f3a2b88caa00ae87enarayan /* mark interrupt as pending */
3af08d828975d7e2581b6829e0eecff14d87a483lm /* save current link state */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = hv_ldc_tx_get_state(ldcp->id, &ldcp->tx_head, &ldcp->tx_tail,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "i_ldc_tx_hdlr: (0x%lx) cannot read queue ptrs rv=0x%d\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * reset the channel state if the channel went down
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * (other side unconfigured queue) or channel was reset
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * (other side reconfigured its queue)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1(ldcp->id, "i_ldc_tx_hdlr: channel link down\n", ldcp->id);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1(ldcp->id, "i_ldc_tx_hdlr: channel link reset\n", ldcp->id);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1(ldcp->id, "i_ldc_tx_hdlr: channel link up\n", ldcp->id);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* if callbacks are disabled, do not notify */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) exiting handler", ldcp->id);
582832867ac00db0b1619c1bb890285984d338c9ha * Process the Rx HV queue.
582832867ac00db0b1619c1bb890285984d338c9ha * Returns 0 if data packets were found and no errors were encountered,
582832867ac00db0b1619c1bb890285984d338c9ha * otherwise returns an error. In either case, the *notify argument is
582832867ac00db0b1619c1bb890285984d338c9ha * set to indicate whether or not the client callback function should
582832867ac00db0b1619c1bb890285984d338c9ha * be invoked. The *event argument is set to contain the callback event.
582832867ac00db0b1619c1bb890285984d338c9ha * Depending on the channel mode, packets are handled differently:
582832867ac00db0b1619c1bb890285984d338c9ha * RAW MODE
582832867ac00db0b1619c1bb890285984d338c9ha * For raw mode channels, when a data packet is encountered,
582832867ac00db0b1619c1bb890285984d338c9ha * processing stops and all packets are left on the queue to be removed
582832867ac00db0b1619c1bb890285984d338c9ha * and processed by the ldc_read code path.
582832867ac00db0b1619c1bb890285984d338c9ha * UNRELIABLE MODE
582832867ac00db0b1619c1bb890285984d338c9ha * For unreliable mode, when a data packet is encountered, processing
582832867ac00db0b1619c1bb890285984d338c9ha * stops, and all packets are left on the queue to be removed and
582832867ac00db0b1619c1bb890285984d338c9ha * processed by the ldc_read code path. Control packets are processed
582832867ac00db0b1619c1bb890285984d338c9ha * inline if they are encountered before any data packets.
20ae46ebaff1237662e05edf9db61538aa85d448ha * RELIABLE MODE
20ae46ebaff1237662e05edf9db61538aa85d448ha * For reliable mode channels, all packets on the receive queue
582832867ac00db0b1619c1bb890285984d338c9ha * are processed: data packets are copied to the data queue and
582832867ac00db0b1619c1bb890285984d338c9ha * control packets are processed inline. Packets are only left on
582832867ac00db0b1619c1bb890285984d338c9ha * the receive queue when the data queue is full.
582832867ac00db0b1619c1bb890285984d338c9hai_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Read packet(s) from the queue
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
582832867ac00db0b1619c1bb890285984d338c9ha "i_ldc_rx_process_hvq: (0x%lx) cannot read "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * reset the channel state if the channel went down
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * (other side unconfigured queue) or channel was reset
3af08d828975d7e2581b6829e0eecff14d87a483lm * (other side reconfigured its queue)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* get the message */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* if channel is in RAW mode or data pkt, notify and return */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* discard packet if channel is not up */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* move the head one position */
20ae46ebaff1237662e05edf9db61538aa85d448ha /* process only RELIABLE mode data packets */
582832867ac00db0b1619c1bb890285984d338c9ha /* don't process packet if queue full */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Check the sequence ID for the message received */
3af08d828975d7e2581b6829e0eecff14d87a483lm if (rv != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Reset last_msg_rcd to start of message */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Send a NACK due to seqid mismatch
582832867ac00db0b1619c1bb890285984d338c9ha "(0x%lx) err sending CTRL/DATA NACK msg\n",
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* if cannot send NACK - reset channel */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* purge receive queue */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* record the message ID */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* process control messages */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* save current internal state */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* re-process pkt - state was adjusted */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * control message processing was successful
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * channel transitioned to ready for communication
83d3bc6f9969f95595135be43a57b8066f5e3273narayan /* process data NACKs */
83d3bc6f9969f95595135be43a57b8066f5e3273narayan if ((msg->type & LDC_DATA) && (msg->stype & LDC_NACK)) {
582832867ac00db0b1619c1bb890285984d338c9ha "i_ldc_rx_process_hvq: (0x%llx) received DATA/NACK",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* process data ACKs */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) {
582832867ac00db0b1619c1bb890285984d338c9ha * Copy the data packet to the data queue. Note
582832867ac00db0b1619c1bb890285984d338c9ha * that the copy routine updates the rx_head pointer.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* move the head one position */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo } /* for */
582832867ac00db0b1619c1bb890285984d338c9ha /* ACK data packets */
582832867ac00db0b1619c1bb890285984d338c9ha "i_ldc_rx_process_hvq: (0x%lx) cannot "
582832867ac00db0b1619c1bb890285984d338c9ha * If we have no more space on the data queue, make sure
582832867ac00db0b1619c1bb890285984d338c9ha * there are no ACKs on the rx queue waiting to be processed.
12f80fa62ea9b3208390b1204a47ed5498881e7dha return (rv);
582832867ac00db0b1619c1bb890285984d338c9ha /* Return, indicating whether or not data packets were found */
582832867ac00db0b1619c1bb890285984d338c9ha if ((*notify_event & (LDC_EVT_READ | LDC_EVT_RESET)) == LDC_EVT_READ)
582832867ac00db0b1619c1bb890285984d338c9ha return (0);
582832867ac00db0b1619c1bb890285984d338c9ha * Process any ACK packets on the HV receive queue.
20ae46ebaff1237662e05edf9db61538aa85d448ha * This function is only used by RELIABLE mode channels when the
582832867ac00db0b1619c1bb890285984d338c9ha * secondary data queue fills up and there are packets remaining on
582832867ac00db0b1619c1bb890285984d338c9ha * the HV receive queue.
582832867ac00db0b1619c1bb890285984d338c9hai_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head, uint64_t rx_tail)
582832867ac00db0b1619c1bb890285984d338c9ha return (rv);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/* -------------------------------------------------------------------------- */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * LDC API functions
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Initialize the channel. Allocate internal structure and memory for
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * TX/RX queues, and initialize locks.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppoldc_init(uint64_t id, ldc_attr_t *attr, ldc_handle_t *handle)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo exit_val = EINVAL; /* guarantee an error if exit on failure */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* check if channel is valid */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN(id, "ldc_init: (0x%llx) invalid channel id\n", id);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* check if the channel has already been initialized */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Allocate an ldcp structure */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * Initialize the channel and Tx lock
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * The channel 'lock' protects the entire channel and
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * should be acquired before initializing, resetting,
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * destroying or reading from a channel.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * The 'tx_lock' should be acquired prior to transmitting
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * data over the channel. The lock should also be acquired
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * prior to channel reconfiguration (in order to prevent
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * concurrent writes).
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * ORDERING: When both locks are being acquired, to prevent
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * deadlocks, the channel lock should be always acquired prior
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * to the tx_lock.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan mutex_init(&ldcp->tx_lock, NULL, MUTEX_DRIVER, NULL);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Initialize the channel */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Read attributes */
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lm ldcp->mtu = (attr->mtu > 0) ? attr->mtu : LDC_DEFAULT_MTU;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_init: (0x%llx) channel attributes, class=0x%x, "
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lm "instance=0x%llx, mode=%d, mtu=%d\n",
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lm ldcp->id, ldcp->devclass, ldcp->devinst, ldcp->mode, ldcp->mtu);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Initialize payload size depending on whether channel is reliable */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo ldcp->stream_bufferp = kmem_alloc(ldcp->mtu, KM_SLEEP);
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lm * qlen is (mtu * ldc_mtu_msgs) / pkt_payload. If this
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lm * value is smaller than default length of ldc_queue_entries,
22f747ef037d84d7799b60247ff9a3df1604a7eenarayan * qlen is set to ldc_queue_entries. Ensure that computed
22f747ef037d84d7799b60247ff9a3df1604a7eenarayan * length is a power-of-two value.
22f747ef037d84d7799b60247ff9a3df1604a7eenarayan (qlen < ldc_queue_entries) ? ldc_queue_entries : qlen;
22f747ef037d84d7799b60247ff9a3df1604a7eenarayan D1(ldcp->id, "ldc_init: queue length = 0x%llx\n", ldcp->rx_q_entries);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Create a transmit queue */
22f747ef037d84d7799b60247ff9a3df1604a7eenarayan contig_mem_alloc(ldcp->tx_q_entries << LDC_PACKET_SHIFT);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_init: (0x%lx) TX queue allocation failed\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D2(ldcp->id, "ldc_init: txq_va=0x%llx, txq_ra=0x%llx, entries=0x%llx\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Create a receive queue */
22f747ef037d84d7799b60247ff9a3df1604a7eenarayan contig_mem_alloc(ldcp->rx_q_entries << LDC_PACKET_SHIFT);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_init: (0x%lx) RX queue allocation failed\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D2(ldcp->id, "ldc_init: rxq_va=0x%llx, rxq_ra=0x%llx, entries=0x%llx\n",
582832867ac00db0b1619c1bb890285984d338c9ha /* Setup a separate read data queue */
582832867ac00db0b1619c1bb890285984d338c9ha /* Make sure the data queue multiplier is a power of 2 */
582832867ac00db0b1619c1bb890285984d338c9ha ldcp->rx_dq_entries = ldc_rxdq_multiplier * ldcp->rx_q_entries;
582832867ac00db0b1619c1bb890285984d338c9ha "ldc_init: (0x%lx) RX data queue "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Init descriptor ring and memory handle list lock */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo mutex_init(&ldcp->exp_dlist_lock, NULL, MUTEX_DRIVER, NULL);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo mutex_init(&ldcp->imp_dlist_lock, NULL, MUTEX_DRIVER, NULL);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo mutex_init(&ldcp->mlist_lock, NULL, MUTEX_DRIVER, NULL);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* mark status as INITialized */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Add to channel list */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* set the handle */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1(ldcp->id, "ldc_init: (0x%llx) channel initialized\n", ldcp->id);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
20ae46ebaff1237662e05edf9db61538aa85d448ha if (ldcp->mode == LDC_MODE_RELIABLE && ldcp->stream_bufferp)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Finalizes the LDC connection. It will return EBUSY if the
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * channel is open. A ldc_close() has to be done prior to
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * a ldc_fini operation. It frees TX/RX queues, associated
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * with the channel
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel handle\n");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN(ldcp->id, "ldc_fini: (0x%llx) channel is open\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Remove from the channel list */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel hdl\n");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Free the map table for this channel */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Destroy descriptor ring and memory handle list lock */
20ae46ebaff1237662e05edf9db61538aa85d448ha /* Free the stream buffer for RELIABLE_MODE */
20ae46ebaff1237662e05edf9db61538aa85d448ha if (ldcp->mode == LDC_MODE_RELIABLE && ldcp->stream_bufferp)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Free the RX queue */
582832867ac00db0b1619c1bb890285984d338c9ha /* Free the RX data queue */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Free the TX queue */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Destroy mutex */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* free channel structure */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Open the LDC channel for use. It registers the TX/RX queues
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * with the Hypervisor. It also specifies the interrupt number
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * and target CPU for this channel
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN(DBG_ALL_LDCS, "ldc_open: invalid channel handle\n");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_open: (0x%llx) channel not initialized\n", ldcp->id);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_open: (0x%llx) channel is already open\n", ldcp->id);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Unregister/Register the tx queue with the hypervisor
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_open: (0x%lx) channel tx queue unconf failed\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_open: (0x%lx) channel tx queue conf failed\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D2(ldcp->id, "ldc_open: (0x%llx) registered tx queue with LDC\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Unregister/Register the rx queue with the hypervisor
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_open: (0x%lx) channel rx queue unconf failed\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra, ldcp->rx_q_entries);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_open: (0x%lx) channel rx queue conf failed\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D2(ldcp->id, "ldc_open: (0x%llx) registered rx queue with LDC\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Register the channel with the channel nexus */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_open: (0x%lx) channel register failed\n", ldcp->id);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* mark channel in OPEN state */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Read channel state */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_open: (0x%lx) cannot read channel state\n",
20ae46ebaff1237662e05edf9db61538aa85d448ha * set the ACKd head to current head location for reliable
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* mark channel ready if HV report link is UP (peer alloc'd Rx queue) */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * if channel is being opened in RAW mode - no handshake is needed
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * switch the channel READY and UP state
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo ldcp->tstate = TS_UP; /* set bits associated with LDC UP */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Increment number of open channels
3af08d828975d7e2581b6829e0eecff14d87a483lm "ldc_open: (0x%llx) channel (0x%p) open for use "
3af08d828975d7e2581b6829e0eecff14d87a483lm "(tstate=0x%x, status=0x%x)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Close the LDC connection. It will return EBUSY if there
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * are memory segments or descriptor rings either bound to or
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * mapped over the channel
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN(DBG_ALL_LDCS, "ldc_close: invalid channel handle\n");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* return error if channel is not open */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_close: (0x%llx) channel is not open\n", ldcp->id);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* if any memory handles, drings, are bound or mapped cannot close */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_close: (0x%llx) channel has bound memory handles\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_close: (0x%llx) channel has bound descriptor rings\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_close: (0x%llx) channel has mapped descriptor rings\n",
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* Obtain Tx lock */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Wait for pending transmits to complete i.e Tx queue to drain
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * if there are pending pkts - wait 1 ms and retry again
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_close: (0x%llx) Tx queue drain timeout\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* wait for one ms and try again */
a8ea4ede2107d9ad3895b91946b9f33a83c5f7eenarayan * Drain the Tx and Rx queues as we are closing the
a8ea4ede2107d9ad3895b91946b9f33a83c5f7eenarayan * channel. We dont care about any pending packets.
a8ea4ede2107d9ad3895b91946b9f33a83c5f7eenarayan * We have to also drain the queue prior to clearing
a8ea4ede2107d9ad3895b91946b9f33a83c5f7eenarayan * pending interrupts, otherwise the HV will trigger
a8ea4ede2107d9ad3895b91946b9f33a83c5f7eenarayan * an interrupt the moment the interrupt state is
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Unregister the channel with the nexus
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan while ((rv = i_ldc_unregister_channel(ldcp)) != 0) {
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* if any error other than EAGAIN return back */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan "ldc_close: (0x%lx) unregister failed, %d\n",
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * As there could be pending interrupts we need
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * to wait and try again
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Unregister queues
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_close: (0x%lx) channel TX queue unconf failed\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_close: (0x%lx) channel RX queue unconf failed\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Reset channel state information */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Mark channel as down and in initialized state */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Decrement number of open channels */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1(ldcp->id, "ldc_close: (0x%llx) channel closed\n", ldcp->id);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Register channel callback
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo uint_t(*cb)(uint64_t event, caddr_t arg), caddr_t arg)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_reg_callback: invalid channel handle\n");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN(DBG_ALL_LDCS, "ldc_reg_callback: invalid callback\n");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback exists\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback active\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_reg_callback: (0x%llx) registered callback for channel\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Unregister channel callback
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_unreg_callback: invalid channel handle\n");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_unreg_callback: (0x%llx) no callback exists\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_unreg_callback: (0x%llx) callback active\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_unreg_callback: (0x%llx) unregistered callback for channel\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Bring a channel up by initiating a handshake with the peer
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * This call is asynchronous. It will complete at a later point
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * in time when the peer responds back with an RTR.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN(DBG_ALL_LDCS, "ldc_up: invalid channel handle\n");
3af08d828975d7e2581b6829e0eecff14d87a483lm D1(ldcp->id, "ldc_up: (0x%llx) doing channel UP\n", ldcp->id);
3af08d828975d7e2581b6829e0eecff14d87a483lm /* clear the reset state */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_up: (0x%llx) channel is already in UP state\n",
3af08d828975d7e2581b6829e0eecff14d87a483lm /* mark channel as up */
3af08d828975d7e2581b6829e0eecff14d87a483lm * if channel was in reset state and there was
3af08d828975d7e2581b6829e0eecff14d87a483lm * pending data clear interrupt state. this will
3af08d828975d7e2581b6829e0eecff14d87a483lm * trigger an interrupt, causing the RX handler to
3af08d828975d7e2581b6829e0eecff14d87a483lm * to invoke the client's callback
3af08d828975d7e2581b6829e0eecff14d87a483lm "ldc_up: (0x%llx) channel has pending data, "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* if the channel is in RAW mode - mark it as UP, if READY */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (ldcp->mode == LDC_MODE_RAW && ldcp->tstate >= TS_READY) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Don't start another handshake if there is one in progress */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_up: (0x%llx) channel handshake in progress\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
57e6a93630ed85fdb571833112c244a2c6749d74sb /* save current link state */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* get the current tail for the LDC msg */
cb112a141f667f84bf442a77589d1705a2336dbelm D1(ldcp->id, "ldc_up: (0x%llx) cannot initiate handshake\n",
57e6a93630ed85fdb571833112c244a2c6749d74sb * If i_ldc_get_tx_tail() changed link_state to either RESET or UP,
57e6a93630ed85fdb571833112c244a2c6749d74sb * from a previous state of DOWN, then mark the channel as
57e6a93630ed85fdb571833112c244a2c6749d74sb * being ready for handshake.
57e6a93630ed85fdb571833112c244a2c6749d74sb return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo bcopy(&ldc_versions[0], ldcmsg->udata, sizeof (ldc_versions[0]));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DUMP_LDC_PKT(ldcp, "ldc_up snd ver", (uint64_t)ldcmsg);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* initiate the send by calling into HV and set the new tail */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_up: (0x%llx) cannot initiate handshake rv=%d\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1(ldcp->id, "ldc_up: (0x%llx) channel up initiated\n", ldcp->id);
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lm * Bring a channel down by resetting its state and queues
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lm DWARN(DBG_ALL_LDCS, "ldc_down: invalid channel handle\n");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Get the current channel status
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN(DBG_ALL_LDCS, "ldc_status: invalid argument\n");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_status: (0x%llx) returned status %d\n", ldcp->id, *status);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Set the channel's callback mode - enable/disable callbacks
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppoldc_set_cb_mode(ldc_handle_t handle, ldc_cb_mode_t cmode)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_set_intr_mode: invalid channel handle\n");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Record no callbacks should be invoked
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_set_cb_mode: (0x%llx) callbacks disabled\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) disabled callbacks\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_set_cb_mode: (0x%llx) callbacks enabled\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) enabled callbacks\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Check to see if there are packets on the incoming queue
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lm * Will return hasdata = B_FALSE if there are no packets
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN(DBG_ALL_LDCS, "ldc_chkq: invalid channel handle\n");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Read packet(s) from the queue */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_chkq: (0x%lx) unable to read queue ptrs", ldcp->id);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* reset the channel state if the channel went down */
582832867ac00db0b1619c1bb890285984d338c9ha * In raw mode, there are no ctrl packets, so checking
582832867ac00db0b1619c1bb890285984d338c9ha * if the queue is non-empty is sufficient.
582832867ac00db0b1619c1bb890285984d338c9ha * In unreliable mode, if the queue is non-empty, we need
582832867ac00db0b1619c1bb890285984d338c9ha * to check if it actually contains unread data packets.
582832867ac00db0b1619c1bb890285984d338c9ha * The queue may just contain ctrl packets.
a74caf9bd0de633ff7fc1bfd722039f74795b85dha * If no data packets were found on the queue,
a74caf9bd0de633ff7fc1bfd722039f74795b85dha * all packets must have been control packets
a74caf9bd0de633ff7fc1bfd722039f74795b85dha * which will now have been processed, leaving
a74caf9bd0de633ff7fc1bfd722039f74795b85dha * the queue empty. If the interrupt state
a74caf9bd0de633ff7fc1bfd722039f74795b85dha * is pending, we need to clear the interrupt
20ae46ebaff1237662e05edf9db61538aa85d448ha * In reliable mode, first check for 'stream_remains' > 0.
582832867ac00db0b1619c1bb890285984d338c9ha * Otherwise, if the data queue head and tail pointers
582832867ac00db0b1619c1bb890285984d338c9ha * differ, there must be data to read.
582832867ac00db0b1619c1bb890285984d338c9ha cmn_err(CE_WARN, "ldc_chkq: (0x%lx) unexpected channel mode "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Read 'size' amount of bytes or less. If incoming buffer
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * is more than 'size', ENOBUFS is returned.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * On return, size contains the number of bytes read.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppoldc_read(ldc_handle_t handle, caddr_t bufp, size_t *sizep)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN(DBG_ALL_LDCS, "ldc_read: invalid channel handle\n");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* channel lock */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_read: (0x%llx) channel is not in UP state\n",
12f80fa62ea9b3208390b1204a47ed5498881e7dha * For reliable mode channels, the interrupt
12f80fa62ea9b3208390b1204a47ed5498881e7dha * state is only set to pending during
12f80fa62ea9b3208390b1204a47ed5498881e7dha * interrupt handling when the secondary data
12f80fa62ea9b3208390b1204a47ed5498881e7dha * queue became full, leaving unprocessed
12f80fa62ea9b3208390b1204a47ed5498881e7dha * packets on the Rx queue. If the interrupt
12f80fa62ea9b3208390b1204a47ed5498881e7dha * state is pending and space is now available
12f80fa62ea9b3208390b1204a47ed5498881e7dha * on the data queue, clear the interrupt.
12f80fa62ea9b3208390b1204a47ed5498881e7dha /* data queue is not full */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * if queue has been drained - clear interrupt
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
cb112a141f667f84bf442a77589d1705a2336dbelm if (rv != 0) {
cb112a141f667f84bf442a77589d1705a2336dbelm cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs",
3af08d828975d7e2581b6829e0eecff14d87a483lm if (exit_val == 0) {
3af08d828975d7e2581b6829e0eecff14d87a483lm if ((rv == 0) &&
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Basic raw mondo read -
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * no interpretation of mondo contents at all.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Enter and exit with ldcp->lock held by caller
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppoi_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* compute mask for increment */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Read packet(s) from the queue
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_read_raw: (0x%lx) unable to read queue ptrs",
22f747ef037d84d7799b60247ff9a3df1604a7eenarayan " rxt=0x%llx, st=0x%llx\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* reset the channel state if the channel went down */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Check for empty queue
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* get the message */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* if channel is in RAW mode, copy data and return */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Process LDC mondos to build larger packets
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * with either un-reliable or reliable delivery.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Enter and exit with ldcp->lock held by caller
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppoi_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep)
3af08d828975d7e2581b6829e0eecff14d87a483lm /* check if the buffer and size are valid */
3af08d828975d7e2581b6829e0eecff14d87a483lm DWARN(ldcp->id, "ldc_read: (0x%llx) invalid buffer/size\n",
582832867ac00db0b1619c1bb890285984d338c9ha /* Set q_va and compute increment mask for the appropriate queue */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Read packet(s) from the queue
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv != 0) {
3af08d828975d7e2581b6829e0eecff14d87a483lm cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D1(ldcp->id, "ldc_read: (0x%llx) chd=0x%llx, tl=0x%llx, st=0x%llx\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* reset the channel state if the channel went down */
582832867ac00db0b1619c1bb890285984d338c9ha * If a data queue is being used, check the Rx HV
582832867ac00db0b1619c1bb890285984d338c9ha * queue. This will copy over any new data packets
582832867ac00db0b1619c1bb890285984d338c9ha * that have arrived.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_read: (0x%lx) cannot read queue ptrs",
3af08d828975d7e2581b6829e0eecff14d87a483lm /* If in the middle of a fragmented xfer */
3af08d828975d7e2581b6829e0eecff14d87a483lm /* wait for ldc_delay usecs */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_read: (0x%llx) chd=0x%llx, rxhd=0x%llx, rxtl=0x%llx\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* get the message */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Check the message ID for the message received */
582832867ac00db0b1619c1bb890285984d338c9ha "error, q_ptrs=0x%lx,0x%lx",
582832867ac00db0b1619c1bb890285984d338c9ha /* throw away data */
582832867ac00db0b1619c1bb890285984d338c9ha /* Reset last_msg_rcd to start of message */
582832867ac00db0b1619c1bb890285984d338c9ha * Send a NACK -- invalid seqid
582832867ac00db0b1619c1bb890285984d338c9ha * get the current tail for the response
582832867ac00db0b1619c1bb890285984d338c9ha "ldc_read: (0x%lx) err sending "
582832867ac00db0b1619c1bb890285984d338c9ha /* if cannot send NACK - reset chan */
582832867ac00db0b1619c1bb890285984d338c9ha /* purge receive queue */
582832867ac00db0b1619c1bb890285984d338c9ha * Process any messages of type CTRL messages
582832867ac00db0b1619c1bb890285984d338c9ha * Future implementations should try to pass these
582832867ac00db0b1619c1bb890285984d338c9ha * to LDC link by resetting the intr state.
582832867ac00db0b1619c1bb890285984d338c9ha * NOTE: not done as a switch() as type can be
582832867ac00db0b1619c1bb890285984d338c9ha * both ctrl+data
582832867ac00db0b1619c1bb890285984d338c9ha /* process data ACKs */
582832867ac00db0b1619c1bb890285984d338c9ha /* process data NACKs */
582832867ac00db0b1619c1bb890285984d338c9ha "ldc_read: (0x%llx) received DATA/NACK",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* process data messages */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* get the packet length */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * FUTURE OPTIMIZATION:
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * dont need to set q head for every
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * packet we read just need to do this when
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * we are done or need to wait for more
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * mondos to make a full packet - this is
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * currently expensive.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * first packets should always have the start
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * bit set (even for a single packet). If not
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * throw away the packet
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_read: (0x%llx) not start - "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* toss pkt, inc head, cont reading */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* check to see if this is a pkt w/ START bit */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_read:(0x%llx) unexpected pkt"
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo " env=0x%x discarding %d bytes,"
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo " lastmsg=%d, currentmsg=%d\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* throw data we have read so far */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* copy (next) pkt into buffer */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * there is not enough space in the buffer to
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * read this pkt. throw message away & continue
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * reading data from queue
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_read: (0x%llx) buffer too small, "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* throw away everything received so far */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* continue reading remaining pkts */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* set the message id */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* move the head one position */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo curr_head = (curr_head + LDC_PACKET_SIZE) & q_size_mask;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * All pkts that are part of this fragmented transfer
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * have been read or this was a single pkt read
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * or there was an error
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* set the queue head */
332608ac9554f08178b41e86935f5eef65453071narayan /* advance head if it is a CTRL packet or a DATA ACK packet */
332608ac9554f08178b41e86935f5eef65453071narayan ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK))) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* set the queue head */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D2(ldcp->id, "ldc_read: (0x%llx) set ACK qhead 0x%llx",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo } /* for (;;) */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D2(ldcp->id, "ldc_read: (0x%llx) end size=%d", ldcp->id, *sizep);
20ae46ebaff1237662e05edf9db61538aa85d448ha * Fetch and buffer incoming packets so we can hand them back as
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * a basic byte stream.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Enter and exit with ldcp->lock held by caller
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppoi_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D2(ldcp->id, "i_ldc_read_stream: (0x%llx) buffer size=%d",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D2(ldcp->id, "i_ldc_read_stream: read packet (0x%llx) size=%d",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo bcopy(ldcp->stream_bufferp + ldcp->stream_offset, target_bufp, size);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D2(ldcp->id, "i_ldc_read_stream: (0x%llx) fill from buffer size=%d",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Write specified amount of bytes to the channel
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * in multiple pkts of pkt_payload size. Each
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * packet is tagged with an unique packet ID in
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lm * the case of a reliable link.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * On return, size contains the number of bytes written.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppoldc_write(ldc_handle_t handle, caddr_t buf, size_t *sizep)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN(DBG_ALL_LDCS, "ldc_write: invalid channel handle\n");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* check if non-zero data to write */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN(ldcp->id, "ldc_write: (0x%llx) invalid data write\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (*sizep == 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN(ldcp->id, "ldc_write: (0x%llx) write size of zero\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Check if channel is UP for data exchange */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_write: (0x%llx) channel is not in UP state\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Write a raw packet to the channel
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * On return, size contains the number of bytes written.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppoi_ldc_write_raw(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Check to see if the packet size is less than or
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * equal to packet size support in raw mode
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_write: (0x%llx) invalid size (0x%llx) for RAW mode\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* get the qptrs for the tx queue */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_write: (0x%llx) channel down/reset\n", ldcp->id);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * Release Tx lock, and then reacquire channel
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * and Tx lock in correct order
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Send the data now */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* copy the data into pkt */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* increment tail */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * All packets have been copied into the TX queue
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * update the tail ptr in the HV
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN(ldcp->id, "ldc_write: (0x%llx) write timed out\n",
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * Release Tx lock, and then reacquire channel
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * and Tx lock in correct order
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, size);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Write specified amount of bytes to the channel
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * in multiple pkts of pkt_payload size. Each
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * packet is tagged with an unique packet ID in
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lm * the case of a reliable link.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * On return, size contains the number of bytes written.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * This function needs to ensure that the write size is < MTU size
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppoi_ldc_write_packet(ldc_chan_t *ldcp, caddr_t buf, size_t *size)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* compute mask for increment */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo txq_size_mask = (ldcp->tx_q_entries - 1) << LDC_PACKET_SHIFT;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* get the qptrs for the tx queue */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv != 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_write: (0x%llx) channel down/reset\n", ldcp->id);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * Release Tx lock, and then reacquire channel
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * and Tx lock in correct order
22f747ef037d84d7799b60247ff9a3df1604a7eenarayan * Check to see if the queue is full. The check is done using
22f747ef037d84d7799b60247ff9a3df1604a7eenarayan * the appropriate head based on the link mode.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Make sure that the LDC Tx queue has enough space
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo numavail = (tx_head >> LDC_PACKET_SHIFT) - (tx_tail >> LDC_PACKET_SHIFT)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "ldc_write: (0x%llx) TX queue has no space\n", ldcp->id);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Send the data now */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* copy the data into pkt */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* increment tail */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) & txq_size_mask;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Set the start and stop bits */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * All packets have been copied into the TX queue
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * update the tail ptr in the HV
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rv == 0) {
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * Release Tx lock, and then reacquire channel
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * and Tx lock in correct order
22f747ef037d84d7799b60247ff9a3df1604a7eenarayan "old tail 0x%x, new tail 0x%x, qsize=0x%x)\n",
22f747ef037d84d7799b60247ff9a3df1604a7eenarayan "(head 0x%x, tail 0x%x state 0x%x)\n",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, *size);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Write specified amount of bytes to the channel
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * in multiple pkts of pkt_payload size. Each
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * packet is tagged with an unique packet ID in
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lm * the case of a reliable link.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * On return, size contains the number of bytes written.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * This function needs to ensure that the write size is < MTU size
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppoi_ldc_write_stream(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Truncate packet to max of MTU size */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Interfaces for channel nexus to register/unregister with LDC module
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * The nexus will register functions to be used to register individual
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * channels with the nexus and enable interrupts for the channels
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo cinfo->reg_chan == NULL || cinfo->unreg_chan == NULL ||
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN(DBG_ALL_LDCS, "ldc_register: invalid nexus info\n");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* nexus registration */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* register any channels that might have been previously initialized */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid nexus info\n");
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* nexus unregister */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
34f94fbc7a730740933e4776ade5f74009afe4ceWENTAO YANG DWARN(DBG_ALL_LDCS, "ldc_get_info: invalid args\n");
34f94fbc7a730740933e4776ade5f74009afe4ceWENTAO YANG /* check to see if channel is initalized */
34f94fbc7a730740933e4776ade5f74009afe4ceWENTAO YANG "ldc_get_info: (0x%llx) channel not initialized\n",
34f94fbc7a730740933e4776ade5f74009afe4ceWENTAO YANG * ldcssp->mapin_size is the max amount of shared memory supported by
34f94fbc7a730740933e4776ade5f74009afe4ceWENTAO YANG * the Hypervisor per guest. e.g, legacy HV supports 64MB; latest HV
34f94fbc7a730740933e4776ade5f74009afe4ceWENTAO YANG * support 1GB. This size is read during ldc module initialization.
34f94fbc7a730740933e4776ade5f74009afe4ceWENTAO YANG * ldc_dring_direct_map_rsvd is the amount of memory reserved for
34f94fbc7a730740933e4776ade5f74009afe4ceWENTAO YANG * mapping in descriptor rings. In the initial implementation, we use a
34f94fbc7a730740933e4776ade5f74009afe4ceWENTAO YANG * simple approach to determine the amount of mapin space available per
34f94fbc7a730740933e4776ade5f74009afe4ceWENTAO YANG * channel. In future, we may implement strict accounting of the actual
34f94fbc7a730740933e4776ade5f74009afe4ceWENTAO YANG * memory consumed to determine the exact amount available per channel.
34f94fbc7a730740933e4776ade5f74009afe4ceWENTAO YANG if (ldcssp->mapin_size <= ldc_dring_direct_map_rsvd) {
34f94fbc7a730740933e4776ade5f74009afe4ceWENTAO YANG avail = ldcssp->mapin_size - ldc_dring_direct_map_rsvd;