11ae08745Sheppo /* 21ae08745Sheppo * CDDL HEADER START 31ae08745Sheppo * 41ae08745Sheppo * The contents of this file are subject to the terms of the 51ae08745Sheppo * Common Development and Distribution License (the "License"). 61ae08745Sheppo * You may not use this file except in compliance with the License. 71ae08745Sheppo * 81ae08745Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91ae08745Sheppo * or http://www.opensolaris.org/os/licensing. 101ae08745Sheppo * See the License for the specific language governing permissions 111ae08745Sheppo * and limitations under the License. 121ae08745Sheppo * 131ae08745Sheppo * When distributing Covered Code, include this CDDL HEADER in each 141ae08745Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151ae08745Sheppo * If applicable, add the following below this CDDL HEADER, with the 161ae08745Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 171ae08745Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 181ae08745Sheppo * 191ae08745Sheppo * CDDL HEADER END 201ae08745Sheppo */ 211ae08745Sheppo 221ae08745Sheppo /* 2358283286Sha137994 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 241ae08745Sheppo * Use is subject to license terms. 251ae08745Sheppo */ 261ae08745Sheppo 271ae08745Sheppo #pragma ident "%Z%%M% %I% %E% SMI" 281ae08745Sheppo 291ae08745Sheppo /* 30e1ebb9ecSlm66018 * sun4v LDC Link Layer 311ae08745Sheppo */ 321ae08745Sheppo #include <sys/types.h> 331ae08745Sheppo #include <sys/file.h> 341ae08745Sheppo #include <sys/errno.h> 351ae08745Sheppo #include <sys/open.h> 361ae08745Sheppo #include <sys/cred.h> 371ae08745Sheppo #include <sys/kmem.h> 381ae08745Sheppo #include <sys/conf.h> 391ae08745Sheppo #include <sys/cmn_err.h> 401ae08745Sheppo #include <sys/ksynch.h> 411ae08745Sheppo #include <sys/modctl.h> 421ae08745Sheppo #include <sys/stat.h> /* needed for S_IFBLK and S_IFCHR */ 431ae08745Sheppo #include <sys/debug.h> 441ae08745Sheppo #include <sys/cred.h> 451ae08745Sheppo #include <sys/promif.h> 461ae08745Sheppo #include <sys/ddi.h> 471ae08745Sheppo #include <sys/sunddi.h> 481ae08745Sheppo #include <sys/cyclic.h> 491ae08745Sheppo #include <sys/machsystm.h> 501ae08745Sheppo #include <sys/vm.h> 511ae08745Sheppo #include <sys/cpu.h> 521ae08745Sheppo #include <sys/intreg.h> 531ae08745Sheppo #include <sys/machcpuvar.h> 544bac2208Snarayan #include <sys/mmu.h> 554bac2208Snarayan #include <sys/pte.h> 564bac2208Snarayan #include <vm/hat.h> 574bac2208Snarayan #include <vm/as.h> 584bac2208Snarayan #include <vm/hat_sfmmu.h> 594bac2208Snarayan #include <sys/vm_machparam.h> 604bac2208Snarayan #include <vm/seg_kmem.h> 614bac2208Snarayan #include <vm/seg_kpm.h> 621ae08745Sheppo #include <sys/note.h> 631ae08745Sheppo #include <sys/ivintr.h> 641ae08745Sheppo #include <sys/hypervisor_api.h> 651ae08745Sheppo #include <sys/ldc.h> 661ae08745Sheppo #include <sys/ldc_impl.h> 671ae08745Sheppo #include <sys/cnex.h> 681ae08745Sheppo #include <sys/hsvc.h> 6958283286Sha137994 #include <sys/sdt.h> 701ae08745Sheppo 711ae08745Sheppo /* Core internal functions */ 7220ae46ebSha137994 int i_ldc_h2v_error(int h_error); 7320ae46ebSha137994 void i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset); 7420ae46ebSha137994 751ae08745Sheppo static int i_ldc_txq_reconf(ldc_chan_t *ldcp); 763af08d82Slm66018 static int i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset); 77a8ea4edeSnarayan static int i_ldc_rxq_drain(ldc_chan_t *ldcp); 781ae08745Sheppo static void i_ldc_reset_state(ldc_chan_t *ldcp); 791ae08745Sheppo 801ae08745Sheppo static int i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail); 8122f747efSnarayan static void i_ldc_get_tx_head(ldc_chan_t *ldcp, uint64_t *head); 821ae08745Sheppo static int i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail); 831ae08745Sheppo static int i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head); 841ae08745Sheppo static int i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype, 851ae08745Sheppo uint8_t ctrlmsg); 861ae08745Sheppo 8758283286Sha137994 static int i_ldc_set_rxdq_head(ldc_chan_t *ldcp, uint64_t head); 8858283286Sha137994 static void i_ldc_rxdq_copy(ldc_chan_t *ldcp, uint64_t *head); 8958283286Sha137994 static uint64_t i_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, 9058283286Sha137994 uint64_t *tail, uint64_t *link_state); 9158283286Sha137994 static uint64_t i_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, 9258283286Sha137994 uint64_t *tail, uint64_t *link_state); 9358283286Sha137994 static int i_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head, 9458283286Sha137994 uint64_t rx_tail); 9558283286Sha137994 static uint_t i_ldc_chkq(ldc_chan_t *ldcp); 9658283286Sha137994 971ae08745Sheppo /* Interrupt handling functions */ 981ae08745Sheppo static uint_t i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2); 991ae08745Sheppo static uint_t i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2); 10058283286Sha137994 static uint_t i_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client, 10158283286Sha137994 uint64_t *notify_event); 1021ae08745Sheppo static void i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype); 1031ae08745Sheppo 1041ae08745Sheppo /* Read method functions */ 1051ae08745Sheppo static int i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep); 1061ae08745Sheppo static int i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp, 1071ae08745Sheppo size_t *sizep); 1081ae08745Sheppo static int i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp, 1091ae08745Sheppo size_t *sizep); 1101ae08745Sheppo 1111ae08745Sheppo /* Write method functions */ 1121ae08745Sheppo static int i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t target_bufp, 1131ae08745Sheppo size_t *sizep); 1141ae08745Sheppo static int i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t target_bufp, 1151ae08745Sheppo size_t *sizep); 1161ae08745Sheppo static int i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t target_bufp, 1171ae08745Sheppo size_t *sizep); 1181ae08745Sheppo 1191ae08745Sheppo /* Pkt processing internal functions */ 1201ae08745Sheppo static int i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg); 1211ae08745Sheppo static int i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg); 1221ae08745Sheppo static int i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg); 1231ae08745Sheppo static int i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg); 1241ae08745Sheppo static int i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg); 1251ae08745Sheppo static int i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg); 1261ae08745Sheppo static int i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg); 1271ae08745Sheppo 1281ae08745Sheppo /* LDC Version */ 1291ae08745Sheppo static ldc_ver_t ldc_versions[] = { {1, 0} }; 1301ae08745Sheppo 1311ae08745Sheppo /* number of supported versions */ 1321ae08745Sheppo #define LDC_NUM_VERS (sizeof (ldc_versions) / sizeof (ldc_versions[0])) 1331ae08745Sheppo 13458283286Sha137994 /* Invalid value for the ldc_chan_t rx_ack_head field */ 13558283286Sha137994 #define ACKPEEK_HEAD_INVALID ((uint64_t)-1) 13658283286Sha137994 13758283286Sha137994 1381ae08745Sheppo /* Module State Pointer */ 13920ae46ebSha137994 ldc_soft_state_t *ldcssp; 1401ae08745Sheppo 1411ae08745Sheppo static struct modldrv md = { 1421ae08745Sheppo &mod_miscops, /* This is a misc module */ 1431ae08745Sheppo "sun4v LDC module v%I%", /* Name of the module */ 1441ae08745Sheppo }; 1451ae08745Sheppo 1461ae08745Sheppo static struct modlinkage ml = { 1471ae08745Sheppo MODREV_1, 1481ae08745Sheppo &md, 1491ae08745Sheppo NULL 1501ae08745Sheppo }; 1511ae08745Sheppo 1521ae08745Sheppo static uint64_t ldc_sup_minor; /* Supported minor number */ 1531ae08745Sheppo static hsvc_info_t ldc_hsvc = { 1541ae08745Sheppo HSVC_REV_1, NULL, HSVC_GROUP_LDC, 1, 0, "ldc" 1551ae08745Sheppo }; 1561ae08745Sheppo 1574bac2208Snarayan /* 158e1ebb9ecSlm66018 * The no. of MTU size messages that can be stored in 159e1ebb9ecSlm66018 * the LDC Tx queue. The number of Tx queue entries is 160e1ebb9ecSlm66018 * then computed as (mtu * mtu_msgs)/sizeof(queue_entry) 161e1ebb9ecSlm66018 */ 162e1ebb9ecSlm66018 uint64_t ldc_mtu_msgs = LDC_MTU_MSGS; 163e1ebb9ecSlm66018 164e1ebb9ecSlm66018 /* 165e1ebb9ecSlm66018 * The minimum queue length. This is the size of the smallest 166e1ebb9ecSlm66018 * LDC queue. If the computed value is less than this default, 167e1ebb9ecSlm66018 * the queue length is rounded up to 'ldc_queue_entries'. 168e1ebb9ecSlm66018 */ 169e1ebb9ecSlm66018 uint64_t ldc_queue_entries = LDC_QUEUE_ENTRIES; 170e1ebb9ecSlm66018 171e1ebb9ecSlm66018 /* 17258283286Sha137994 * The length of the reliable-mode data queue in terms of the LDC 17358283286Sha137994 * receive queue length. i.e., the number of times larger than the 17458283286Sha137994 * LDC receive queue that the data queue should be. The HV receive 17558283286Sha137994 * queue is required to be a power of 2 and this implementation 17658283286Sha137994 * assumes the data queue will also be a power of 2. By making the 17758283286Sha137994 * multiplier a power of 2, we ensure the data queue will be a 17858283286Sha137994 * power of 2. We use a multiplier because the receive queue is 17958283286Sha137994 * sized to be sane relative to the MTU and the same is needed for 18058283286Sha137994 * the data queue. 18158283286Sha137994 */ 18258283286Sha137994 uint64_t ldc_rxdq_multiplier = LDC_RXDQ_MULTIPLIER; 18358283286Sha137994 18458283286Sha137994 /* 185e1ebb9ecSlm66018 * LDC retry count and delay - when the HV returns EWOULDBLOCK 186e1ebb9ecSlm66018 * the operation is retried 'ldc_max_retries' times with a 187e1ebb9ecSlm66018 * wait of 'ldc_delay' usecs between each retry. 1880a55fbb7Slm66018 */ 1890a55fbb7Slm66018 int ldc_max_retries = LDC_MAX_RETRIES; 1900a55fbb7Slm66018 clock_t ldc_delay = LDC_DELAY; 1910a55fbb7Slm66018 1924d39be2bSsg70180 /* 1934d39be2bSsg70180 * delay between each retry of channel unregistration in 1944d39be2bSsg70180 * ldc_close(), to wait for pending interrupts to complete. 1954d39be2bSsg70180 */ 1964d39be2bSsg70180 clock_t ldc_close_delay = LDC_CLOSE_DELAY; 1974d39be2bSsg70180 1981ae08745Sheppo #ifdef DEBUG 1991ae08745Sheppo 2001ae08745Sheppo /* 2011ae08745Sheppo * Print debug messages 2021ae08745Sheppo * 2031ae08745Sheppo * set ldcdbg to 0x7 for enabling all msgs 2041ae08745Sheppo * 0x4 - Warnings 2051ae08745Sheppo * 0x2 - All debug messages 2061ae08745Sheppo * 0x1 - Minimal debug messages 2071ae08745Sheppo * 2081ae08745Sheppo * set ldcdbgchan to the channel number you want to debug 2091ae08745Sheppo * setting it to -1 prints debug messages for all channels 2101ae08745Sheppo * NOTE: ldcdbgchan has no effect on error messages 2111ae08745Sheppo */ 2121ae08745Sheppo 2131ae08745Sheppo int ldcdbg = 0x0; 2141ae08745Sheppo int64_t ldcdbgchan = DBG_ALL_LDCS; 21583d3bc6fSnarayan uint64_t ldc_inject_err_flag = 0; 2161ae08745Sheppo 21720ae46ebSha137994 void 2181ae08745Sheppo ldcdebug(int64_t id, const char *fmt, ...) 2191ae08745Sheppo { 2201ae08745Sheppo char buf[512]; 2211ae08745Sheppo va_list ap; 2221ae08745Sheppo 2231ae08745Sheppo /* 2241ae08745Sheppo * Do not return if, 2251ae08745Sheppo * caller wants to print it anyway - (id == DBG_ALL_LDCS) 2261ae08745Sheppo * debug channel is set to all LDCs - (ldcdbgchan == DBG_ALL_LDCS) 2271ae08745Sheppo * debug channel = caller specified channel 2281ae08745Sheppo */ 2291ae08745Sheppo if ((id != DBG_ALL_LDCS) && 2301ae08745Sheppo (ldcdbgchan != DBG_ALL_LDCS) && 2311ae08745Sheppo (ldcdbgchan != id)) { 2321ae08745Sheppo return; 2331ae08745Sheppo } 2341ae08745Sheppo 2351ae08745Sheppo va_start(ap, fmt); 2361ae08745Sheppo (void) vsprintf(buf, fmt, ap); 2371ae08745Sheppo va_end(ap); 2381ae08745Sheppo 2393af08d82Slm66018 cmn_err(CE_CONT, "?%s", buf); 2403af08d82Slm66018 } 2413af08d82Slm66018 24283d3bc6fSnarayan #define LDC_ERR_RESET 0x1 24383d3bc6fSnarayan #define LDC_ERR_PKTLOSS 0x2 24458283286Sha137994 #define LDC_ERR_DQFULL 0x4 24583d3bc6fSnarayan 2463af08d82Slm66018 static boolean_t 24783d3bc6fSnarayan ldc_inject_error(ldc_chan_t *ldcp, uint64_t error) 2483af08d82Slm66018 { 2493af08d82Slm66018 if ((ldcdbgchan != DBG_ALL_LDCS) && (ldcdbgchan != ldcp->id)) 2503af08d82Slm66018 return (B_FALSE); 2513af08d82Slm66018 25283d3bc6fSnarayan if ((ldc_inject_err_flag & error) == 0) 2533af08d82Slm66018 return (B_FALSE); 2543af08d82Slm66018 2553af08d82Slm66018 /* clear the injection state */ 25683d3bc6fSnarayan ldc_inject_err_flag &= ~error; 2573af08d82Slm66018 2583af08d82Slm66018 return (B_TRUE); 2591ae08745Sheppo } 2601ae08745Sheppo 2611ae08745Sheppo #define D1 \ 2621ae08745Sheppo if (ldcdbg & 0x01) \ 2631ae08745Sheppo ldcdebug 2641ae08745Sheppo 2651ae08745Sheppo #define D2 \ 2661ae08745Sheppo if (ldcdbg & 0x02) \ 2671ae08745Sheppo ldcdebug 2681ae08745Sheppo 2691ae08745Sheppo #define DWARN \ 2701ae08745Sheppo if (ldcdbg & 0x04) \ 2711ae08745Sheppo ldcdebug 2721ae08745Sheppo 2731ae08745Sheppo #define DUMP_PAYLOAD(id, addr) \ 2741ae08745Sheppo { \ 2751ae08745Sheppo char buf[65*3]; \ 2761ae08745Sheppo int i; \ 2771ae08745Sheppo uint8_t *src = (uint8_t *)addr; \ 2781ae08745Sheppo for (i = 0; i < 64; i++, src++) \ 2791ae08745Sheppo (void) sprintf(&buf[i * 3], "|%02x", *src); \ 2801ae08745Sheppo (void) sprintf(&buf[i * 3], "|\n"); \ 2811ae08745Sheppo D2((id), "payload: %s", buf); \ 2821ae08745Sheppo } 2831ae08745Sheppo 2841ae08745Sheppo #define DUMP_LDC_PKT(c, s, addr) \ 2851ae08745Sheppo { \ 2861ae08745Sheppo ldc_msg_t *msg = (ldc_msg_t *)(addr); \ 2871ae08745Sheppo uint32_t mid = ((c)->mode != LDC_MODE_RAW) ? msg->seqid : 0; \ 2881ae08745Sheppo if (msg->type == LDC_DATA) { \ 2891ae08745Sheppo D2((c)->id, "%s: msg%d (/%x/%x/%x/,env[%c%c,sz=%d])", \ 2901ae08745Sheppo (s), mid, msg->type, msg->stype, msg->ctrl, \ 2911ae08745Sheppo (msg->env & LDC_FRAG_START) ? 'B' : ' ', \ 2921ae08745Sheppo (msg->env & LDC_FRAG_STOP) ? 'E' : ' ', \ 2931ae08745Sheppo (msg->env & LDC_LEN_MASK)); \ 2941ae08745Sheppo } else { \ 2951ae08745Sheppo D2((c)->id, "%s: msg%d (/%x/%x/%x/,env=%x)", (s), \ 2961ae08745Sheppo mid, msg->type, msg->stype, msg->ctrl, msg->env); \ 2971ae08745Sheppo } \ 2981ae08745Sheppo } 2991ae08745Sheppo 30083d3bc6fSnarayan #define LDC_INJECT_RESET(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_RESET) 30183d3bc6fSnarayan #define LDC_INJECT_PKTLOSS(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_PKTLOSS) 30258283286Sha137994 #define LDC_INJECT_DQFULL(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_DQFULL) 3033af08d82Slm66018 3041ae08745Sheppo #else 3051ae08745Sheppo 3061ae08745Sheppo #define DBG_ALL_LDCS -1 3071ae08745Sheppo 3081ae08745Sheppo #define D1 3091ae08745Sheppo #define D2 3101ae08745Sheppo #define DWARN 3111ae08745Sheppo 3121ae08745Sheppo #define DUMP_PAYLOAD(id, addr) 3131ae08745Sheppo #define DUMP_LDC_PKT(c, s, addr) 3141ae08745Sheppo 3153af08d82Slm66018 #define LDC_INJECT_RESET(_ldcp) (B_FALSE) 31683d3bc6fSnarayan #define LDC_INJECT_PKTLOSS(_ldcp) (B_FALSE) 31758283286Sha137994 #define LDC_INJECT_DQFULL(_ldcp) (B_FALSE) 3183af08d82Slm66018 3191ae08745Sheppo #endif 3201ae08745Sheppo 32158283286Sha137994 /* 32258283286Sha137994 * dtrace SDT probes to ease tracing of the rx data queue and HV queue 32358283286Sha137994 * lengths. Just pass the head, tail, and entries values so that the 32458283286Sha137994 * length can be calculated in a dtrace script when the probe is enabled. 32558283286Sha137994 */ 32658283286Sha137994 #define TRACE_RXDQ_LENGTH(ldcp) \ 32758283286Sha137994 DTRACE_PROBE4(rxdq__size, \ 32858283286Sha137994 uint64_t, ldcp->id, \ 32958283286Sha137994 uint64_t, ldcp->rx_dq_head, \ 33058283286Sha137994 uint64_t, ldcp->rx_dq_tail, \ 33158283286Sha137994 uint64_t, ldcp->rx_dq_entries) 33258283286Sha137994 33358283286Sha137994 #define TRACE_RXHVQ_LENGTH(ldcp, head, tail) \ 33458283286Sha137994 DTRACE_PROBE4(rxhvq__size, \ 33558283286Sha137994 uint64_t, ldcp->id, \ 33658283286Sha137994 uint64_t, head, \ 33758283286Sha137994 uint64_t, tail, \ 33858283286Sha137994 uint64_t, ldcp->rx_q_entries) 33958283286Sha137994 34058283286Sha137994 /* A dtrace SDT probe to ease tracing of data queue copy operations */ 34158283286Sha137994 #define TRACE_RXDQ_COPY(ldcp, bytes) \ 34258283286Sha137994 DTRACE_PROBE2(rxdq__copy, uint64_t, ldcp->id, uint64_t, bytes) \ 34358283286Sha137994 34458283286Sha137994 /* The amount of contiguous space at the tail of the queue */ 34558283286Sha137994 #define Q_CONTIG_SPACE(head, tail, size) \ 34658283286Sha137994 ((head) <= (tail) ? ((size) - (tail)) : \ 34758283286Sha137994 ((head) - (tail) - LDC_PACKET_SIZE)) 34858283286Sha137994 3491ae08745Sheppo #define ZERO_PKT(p) \ 3501ae08745Sheppo bzero((p), sizeof (ldc_msg_t)); 3511ae08745Sheppo 3521ae08745Sheppo #define IDX2COOKIE(idx, pg_szc, pg_shift) \ 3531ae08745Sheppo (((pg_szc) << LDC_COOKIE_PGSZC_SHIFT) | ((idx) << (pg_shift))) 3541ae08745Sheppo 3551ae08745Sheppo int 3561ae08745Sheppo _init(void) 3571ae08745Sheppo { 3581ae08745Sheppo int status; 3591ae08745Sheppo 3601ae08745Sheppo status = hsvc_register(&ldc_hsvc, &ldc_sup_minor); 3611ae08745Sheppo if (status != 0) { 362d66f8315Sjb145095 cmn_err(CE_NOTE, "!%s: cannot negotiate hypervisor LDC services" 3631ae08745Sheppo " group: 0x%lx major: %ld minor: %ld errno: %d", 3641ae08745Sheppo ldc_hsvc.hsvc_modname, ldc_hsvc.hsvc_group, 3651ae08745Sheppo ldc_hsvc.hsvc_major, ldc_hsvc.hsvc_minor, status); 3661ae08745Sheppo return (-1); 3671ae08745Sheppo } 3681ae08745Sheppo 3691ae08745Sheppo /* allocate soft state structure */ 3701ae08745Sheppo ldcssp = kmem_zalloc(sizeof (ldc_soft_state_t), KM_SLEEP); 3711ae08745Sheppo 3721ae08745Sheppo /* Link the module into the system */ 3731ae08745Sheppo status = mod_install(&ml); 3741ae08745Sheppo if (status != 0) { 3751ae08745Sheppo kmem_free(ldcssp, sizeof (ldc_soft_state_t)); 3761ae08745Sheppo return (status); 3771ae08745Sheppo } 3781ae08745Sheppo 3791ae08745Sheppo /* Initialize the LDC state structure */ 3801ae08745Sheppo mutex_init(&ldcssp->lock, NULL, MUTEX_DRIVER, NULL); 3811ae08745Sheppo 3821ae08745Sheppo mutex_enter(&ldcssp->lock); 3831ae08745Sheppo 3844bac2208Snarayan /* Create a cache for memory handles */ 3854bac2208Snarayan ldcssp->memhdl_cache = kmem_cache_create("ldc_memhdl_cache", 3864bac2208Snarayan sizeof (ldc_mhdl_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 3874bac2208Snarayan if (ldcssp->memhdl_cache == NULL) { 3884bac2208Snarayan DWARN(DBG_ALL_LDCS, "_init: ldc_memhdl cache create failed\n"); 3894bac2208Snarayan mutex_exit(&ldcssp->lock); 3904bac2208Snarayan return (-1); 3914bac2208Snarayan } 3924bac2208Snarayan 3934bac2208Snarayan /* Create cache for memory segment structures */ 3944bac2208Snarayan ldcssp->memseg_cache = kmem_cache_create("ldc_memseg_cache", 3954bac2208Snarayan sizeof (ldc_memseg_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 3964bac2208Snarayan if (ldcssp->memseg_cache == NULL) { 3974bac2208Snarayan DWARN(DBG_ALL_LDCS, "_init: ldc_memseg cache create failed\n"); 3984bac2208Snarayan mutex_exit(&ldcssp->lock); 3994bac2208Snarayan return (-1); 4004bac2208Snarayan } 4014bac2208Snarayan 4024bac2208Snarayan 4031ae08745Sheppo ldcssp->channel_count = 0; 4041ae08745Sheppo ldcssp->channels_open = 0; 4051ae08745Sheppo ldcssp->chan_list = NULL; 4061ae08745Sheppo ldcssp->dring_list = NULL; 4071ae08745Sheppo 4081ae08745Sheppo mutex_exit(&ldcssp->lock); 4091ae08745Sheppo 4101ae08745Sheppo return (0); 4111ae08745Sheppo } 4121ae08745Sheppo 4131ae08745Sheppo int 4141ae08745Sheppo _info(struct modinfo *modinfop) 4151ae08745Sheppo { 4161ae08745Sheppo /* Report status of the dynamically loadable driver module */ 4171ae08745Sheppo return (mod_info(&ml, modinfop)); 4181ae08745Sheppo } 4191ae08745Sheppo 4201ae08745Sheppo int 4211ae08745Sheppo _fini(void) 4221ae08745Sheppo { 4231ae08745Sheppo int rv, status; 42422f747efSnarayan ldc_chan_t *tmp_ldcp, *ldcp; 42522f747efSnarayan ldc_dring_t *tmp_dringp, *dringp; 4261ae08745Sheppo ldc_mem_info_t minfo; 4271ae08745Sheppo 4281ae08745Sheppo /* Unlink the driver module from the system */ 4291ae08745Sheppo status = mod_remove(&ml); 4301ae08745Sheppo if (status) { 4311ae08745Sheppo DWARN(DBG_ALL_LDCS, "_fini: mod_remove failed\n"); 4321ae08745Sheppo return (EIO); 4331ae08745Sheppo } 4341ae08745Sheppo 4351ae08745Sheppo /* Free descriptor rings */ 4361ae08745Sheppo dringp = ldcssp->dring_list; 4371ae08745Sheppo while (dringp != NULL) { 43822f747efSnarayan tmp_dringp = dringp->next; 4391ae08745Sheppo 4401ae08745Sheppo rv = ldc_mem_dring_info((ldc_dring_handle_t)dringp, &minfo); 4411ae08745Sheppo if (rv == 0 && minfo.status != LDC_UNBOUND) { 4421ae08745Sheppo if (minfo.status == LDC_BOUND) { 4431ae08745Sheppo (void) ldc_mem_dring_unbind( 4441ae08745Sheppo (ldc_dring_handle_t)dringp); 4451ae08745Sheppo } 4461ae08745Sheppo if (minfo.status == LDC_MAPPED) { 4471ae08745Sheppo (void) ldc_mem_dring_unmap( 4481ae08745Sheppo (ldc_dring_handle_t)dringp); 4491ae08745Sheppo } 4501ae08745Sheppo } 4511ae08745Sheppo 4521ae08745Sheppo (void) ldc_mem_dring_destroy((ldc_dring_handle_t)dringp); 45322f747efSnarayan dringp = tmp_dringp; 4541ae08745Sheppo } 4551ae08745Sheppo ldcssp->dring_list = NULL; 4561ae08745Sheppo 45722f747efSnarayan /* close and finalize channels */ 45822f747efSnarayan ldcp = ldcssp->chan_list; 45922f747efSnarayan while (ldcp != NULL) { 46022f747efSnarayan tmp_ldcp = ldcp->next; 46122f747efSnarayan 46222f747efSnarayan (void) ldc_close((ldc_handle_t)ldcp); 46322f747efSnarayan (void) ldc_fini((ldc_handle_t)ldcp); 46422f747efSnarayan 46522f747efSnarayan ldcp = tmp_ldcp; 46622f747efSnarayan } 46722f747efSnarayan ldcssp->chan_list = NULL; 46822f747efSnarayan 4694bac2208Snarayan /* Destroy kmem caches */ 4704bac2208Snarayan kmem_cache_destroy(ldcssp->memhdl_cache); 4714bac2208Snarayan kmem_cache_destroy(ldcssp->memseg_cache); 4724bac2208Snarayan 4731ae08745Sheppo /* 4741ae08745Sheppo * We have successfully "removed" the driver. 4751ae08745Sheppo * Destroying soft states 4761ae08745Sheppo */ 4771ae08745Sheppo mutex_destroy(&ldcssp->lock); 4781ae08745Sheppo kmem_free(ldcssp, sizeof (ldc_soft_state_t)); 4791ae08745Sheppo 4801ae08745Sheppo (void) hsvc_unregister(&ldc_hsvc); 4811ae08745Sheppo 4821ae08745Sheppo return (status); 4831ae08745Sheppo } 4841ae08745Sheppo 4851ae08745Sheppo /* -------------------------------------------------------------------------- */ 4861ae08745Sheppo 4871ae08745Sheppo /* 488e1ebb9ecSlm66018 * LDC Link Layer Internal Functions 4891ae08745Sheppo */ 4901ae08745Sheppo 4911ae08745Sheppo /* 4921ae08745Sheppo * Translate HV Errors to sun4v error codes 4931ae08745Sheppo */ 49420ae46ebSha137994 int 4951ae08745Sheppo i_ldc_h2v_error(int h_error) 4961ae08745Sheppo { 4971ae08745Sheppo switch (h_error) { 4981ae08745Sheppo 4991ae08745Sheppo case H_EOK: 5001ae08745Sheppo return (0); 5011ae08745Sheppo 5021ae08745Sheppo case H_ENORADDR: 5031ae08745Sheppo return (EFAULT); 5041ae08745Sheppo 5051ae08745Sheppo case H_EBADPGSZ: 5061ae08745Sheppo case H_EINVAL: 5071ae08745Sheppo return (EINVAL); 5081ae08745Sheppo 5091ae08745Sheppo case H_EWOULDBLOCK: 5101ae08745Sheppo return (EWOULDBLOCK); 5111ae08745Sheppo 5121ae08745Sheppo case H_ENOACCESS: 5131ae08745Sheppo case H_ENOMAP: 5141ae08745Sheppo return (EACCES); 5151ae08745Sheppo 5161ae08745Sheppo case H_EIO: 5171ae08745Sheppo case H_ECPUERROR: 5181ae08745Sheppo return (EIO); 5191ae08745Sheppo 5201ae08745Sheppo case H_ENOTSUPPORTED: 5211ae08745Sheppo return (ENOTSUP); 5221ae08745Sheppo 5231ae08745Sheppo case H_ETOOMANY: 5241ae08745Sheppo return (ENOSPC); 5251ae08745Sheppo 5261ae08745Sheppo case H_ECHANNEL: 5271ae08745Sheppo return (ECHRNG); 5281ae08745Sheppo default: 5291ae08745Sheppo break; 5301ae08745Sheppo } 5311ae08745Sheppo 5321ae08745Sheppo return (EIO); 5331ae08745Sheppo } 5341ae08745Sheppo 5351ae08745Sheppo /* 5361ae08745Sheppo * Reconfigure the transmit queue 5371ae08745Sheppo */ 5381ae08745Sheppo static int 5391ae08745Sheppo i_ldc_txq_reconf(ldc_chan_t *ldcp) 5401ae08745Sheppo { 5411ae08745Sheppo int rv; 5421ae08745Sheppo 5431ae08745Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 544d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 545d10e4ef2Snarayan 5461ae08745Sheppo rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries); 5471ae08745Sheppo if (rv) { 5481ae08745Sheppo cmn_err(CE_WARN, 5493af08d82Slm66018 "i_ldc_txq_reconf: (0x%lx) cannot set qconf", ldcp->id); 5501ae08745Sheppo return (EIO); 5511ae08745Sheppo } 5521ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id, &(ldcp->tx_head), 5531ae08745Sheppo &(ldcp->tx_tail), &(ldcp->link_state)); 5541ae08745Sheppo if (rv) { 5551ae08745Sheppo cmn_err(CE_WARN, 5563af08d82Slm66018 "i_ldc_txq_reconf: (0x%lx) cannot get qptrs", ldcp->id); 5571ae08745Sheppo return (EIO); 5581ae08745Sheppo } 5593af08d82Slm66018 D1(ldcp->id, "i_ldc_txq_reconf: (0x%llx) h=0x%llx,t=0x%llx," 5601ae08745Sheppo "s=0x%llx\n", ldcp->id, ldcp->tx_head, ldcp->tx_tail, 5611ae08745Sheppo ldcp->link_state); 5621ae08745Sheppo 5631ae08745Sheppo return (0); 5641ae08745Sheppo } 5651ae08745Sheppo 5661ae08745Sheppo /* 5671ae08745Sheppo * Reconfigure the receive queue 5681ae08745Sheppo */ 5691ae08745Sheppo static int 5703af08d82Slm66018 i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset) 5711ae08745Sheppo { 5721ae08745Sheppo int rv; 5731ae08745Sheppo uint64_t rx_head, rx_tail; 5741ae08745Sheppo 5751ae08745Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 5761ae08745Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 5771ae08745Sheppo &(ldcp->link_state)); 5781ae08745Sheppo if (rv) { 5791ae08745Sheppo cmn_err(CE_WARN, 5803af08d82Slm66018 "i_ldc_rxq_reconf: (0x%lx) cannot get state", 5811ae08745Sheppo ldcp->id); 5821ae08745Sheppo return (EIO); 5831ae08745Sheppo } 5841ae08745Sheppo 5853af08d82Slm66018 if (force_reset || (ldcp->tstate & ~TS_IN_RESET) == TS_UP) { 5861ae08745Sheppo rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra, 5871ae08745Sheppo ldcp->rx_q_entries); 5881ae08745Sheppo if (rv) { 5891ae08745Sheppo cmn_err(CE_WARN, 5903af08d82Slm66018 "i_ldc_rxq_reconf: (0x%lx) cannot set qconf", 5911ae08745Sheppo ldcp->id); 5921ae08745Sheppo return (EIO); 5931ae08745Sheppo } 5943af08d82Slm66018 D1(ldcp->id, "i_ldc_rxq_reconf: (0x%llx) completed q reconf", 5951ae08745Sheppo ldcp->id); 5961ae08745Sheppo } 5971ae08745Sheppo 5981ae08745Sheppo return (0); 5991ae08745Sheppo } 6001ae08745Sheppo 601a8ea4edeSnarayan 602a8ea4edeSnarayan /* 603a8ea4edeSnarayan * Drain the contents of the receive queue 604a8ea4edeSnarayan */ 605a8ea4edeSnarayan static int 606a8ea4edeSnarayan i_ldc_rxq_drain(ldc_chan_t *ldcp) 607a8ea4edeSnarayan { 608a8ea4edeSnarayan int rv; 609a8ea4edeSnarayan uint64_t rx_head, rx_tail; 610a8ea4edeSnarayan 611a8ea4edeSnarayan ASSERT(MUTEX_HELD(&ldcp->lock)); 612a8ea4edeSnarayan rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 613a8ea4edeSnarayan &(ldcp->link_state)); 614a8ea4edeSnarayan if (rv) { 615a8ea4edeSnarayan cmn_err(CE_WARN, "i_ldc_rxq_drain: (0x%lx) cannot get state", 616a8ea4edeSnarayan ldcp->id); 617a8ea4edeSnarayan return (EIO); 618a8ea4edeSnarayan } 619a8ea4edeSnarayan 620a8ea4edeSnarayan /* flush contents by setting the head = tail */ 621a8ea4edeSnarayan return (i_ldc_set_rx_head(ldcp, rx_tail)); 622a8ea4edeSnarayan } 623a8ea4edeSnarayan 624a8ea4edeSnarayan 6251ae08745Sheppo /* 6261ae08745Sheppo * Reset LDC state structure and its contents 6271ae08745Sheppo */ 6281ae08745Sheppo static void 6291ae08745Sheppo i_ldc_reset_state(ldc_chan_t *ldcp) 6301ae08745Sheppo { 6311ae08745Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 6321ae08745Sheppo ldcp->last_msg_snt = LDC_INIT_SEQID; 6331ae08745Sheppo ldcp->last_ack_rcd = 0; 6341ae08745Sheppo ldcp->last_msg_rcd = 0; 6351ae08745Sheppo ldcp->tx_ackd_head = ldcp->tx_head; 63658283286Sha137994 ldcp->stream_remains = 0; 6371ae08745Sheppo ldcp->next_vidx = 0; 6381ae08745Sheppo ldcp->hstate = 0; 6391ae08745Sheppo ldcp->tstate = TS_OPEN; 6401ae08745Sheppo ldcp->status = LDC_OPEN; 64158283286Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID; 64258283286Sha137994 ldcp->rx_dq_head = 0; 64358283286Sha137994 ldcp->rx_dq_tail = 0; 6441ae08745Sheppo 6451ae08745Sheppo if (ldcp->link_state == LDC_CHANNEL_UP || 6461ae08745Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 6471ae08745Sheppo 6481ae08745Sheppo if (ldcp->mode == LDC_MODE_RAW) { 6491ae08745Sheppo ldcp->status = LDC_UP; 6501ae08745Sheppo ldcp->tstate = TS_UP; 6511ae08745Sheppo } else { 6521ae08745Sheppo ldcp->status = LDC_READY; 6531ae08745Sheppo ldcp->tstate |= TS_LINK_READY; 6541ae08745Sheppo } 6551ae08745Sheppo } 6561ae08745Sheppo } 6571ae08745Sheppo 6581ae08745Sheppo /* 6591ae08745Sheppo * Reset a LDC channel 6601ae08745Sheppo */ 66120ae46ebSha137994 void 6623af08d82Slm66018 i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset) 6631ae08745Sheppo { 66483d3bc6fSnarayan DWARN(ldcp->id, "i_ldc_reset: (0x%llx) channel reset\n", ldcp->id); 6651ae08745Sheppo 666d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->lock)); 667d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 668d10e4ef2Snarayan 6693af08d82Slm66018 /* reconfig Tx and Rx queues */ 6701ae08745Sheppo (void) i_ldc_txq_reconf(ldcp); 6713af08d82Slm66018 (void) i_ldc_rxq_reconf(ldcp, force_reset); 6723af08d82Slm66018 6733af08d82Slm66018 /* Clear Tx and Rx interrupts */ 6743af08d82Slm66018 (void) i_ldc_clear_intr(ldcp, CNEX_TX_INTR); 6753af08d82Slm66018 (void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 6763af08d82Slm66018 6773af08d82Slm66018 /* Reset channel state */ 6781ae08745Sheppo i_ldc_reset_state(ldcp); 6793af08d82Slm66018 6803af08d82Slm66018 /* Mark channel in reset */ 6813af08d82Slm66018 ldcp->tstate |= TS_IN_RESET; 6821ae08745Sheppo } 6831ae08745Sheppo 6844bac2208Snarayan 6851ae08745Sheppo /* 6861ae08745Sheppo * Clear pending interrupts 6871ae08745Sheppo */ 6881ae08745Sheppo static void 6891ae08745Sheppo i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype) 6901ae08745Sheppo { 6911ae08745Sheppo ldc_cnex_t *cinfo = &ldcssp->cinfo; 6921ae08745Sheppo 6931ae08745Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 6943af08d82Slm66018 ASSERT(cinfo->dip != NULL); 6954bac2208Snarayan 6963af08d82Slm66018 switch (itype) { 6973af08d82Slm66018 case CNEX_TX_INTR: 6984bac2208Snarayan /* check Tx interrupt */ 6993af08d82Slm66018 if (ldcp->tx_intr_state) 7003af08d82Slm66018 ldcp->tx_intr_state = LDC_INTR_NONE; 7014bac2208Snarayan else 7024bac2208Snarayan return; 7033af08d82Slm66018 break; 7043af08d82Slm66018 7053af08d82Slm66018 case CNEX_RX_INTR: 7064bac2208Snarayan /* check Rx interrupt */ 7073af08d82Slm66018 if (ldcp->rx_intr_state) 7083af08d82Slm66018 ldcp->rx_intr_state = LDC_INTR_NONE; 7094bac2208Snarayan else 7104bac2208Snarayan return; 7113af08d82Slm66018 break; 7124bac2208Snarayan } 7134bac2208Snarayan 7141ae08745Sheppo (void) cinfo->clr_intr(cinfo->dip, ldcp->id, itype); 7154bac2208Snarayan D2(ldcp->id, 7164bac2208Snarayan "i_ldc_clear_intr: (0x%llx) cleared 0x%x intr\n", 7174bac2208Snarayan ldcp->id, itype); 7181ae08745Sheppo } 7191ae08745Sheppo 7201ae08745Sheppo /* 7211ae08745Sheppo * Set the receive queue head 7220a55fbb7Slm66018 * Resets connection and returns an error if it fails. 7231ae08745Sheppo */ 7241ae08745Sheppo static int 7251ae08745Sheppo i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head) 7261ae08745Sheppo { 7271ae08745Sheppo int rv; 7280a55fbb7Slm66018 int retries; 7291ae08745Sheppo 7301ae08745Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 7310a55fbb7Slm66018 for (retries = 0; retries < ldc_max_retries; retries++) { 7320a55fbb7Slm66018 7330a55fbb7Slm66018 if ((rv = hv_ldc_rx_set_qhead(ldcp->id, head)) == 0) 7340a55fbb7Slm66018 return (0); 7350a55fbb7Slm66018 7360a55fbb7Slm66018 if (rv != H_EWOULDBLOCK) 7370a55fbb7Slm66018 break; 7380a55fbb7Slm66018 7390a55fbb7Slm66018 /* wait for ldc_delay usecs */ 7400a55fbb7Slm66018 drv_usecwait(ldc_delay); 7411ae08745Sheppo } 7421ae08745Sheppo 7430a55fbb7Slm66018 cmn_err(CE_WARN, "ldc_rx_set_qhead: (0x%lx) cannot set qhead 0x%lx", 7440a55fbb7Slm66018 ldcp->id, head); 745d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 7463af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 747d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 7480a55fbb7Slm66018 7490a55fbb7Slm66018 return (ECONNRESET); 7501ae08745Sheppo } 7511ae08745Sheppo 75222f747efSnarayan /* 75322f747efSnarayan * Returns the tx_head to be used for transfer 75422f747efSnarayan */ 75522f747efSnarayan static void 75622f747efSnarayan i_ldc_get_tx_head(ldc_chan_t *ldcp, uint64_t *head) 75722f747efSnarayan { 75822f747efSnarayan ldc_msg_t *pkt; 75922f747efSnarayan 76022f747efSnarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 76122f747efSnarayan 76222f747efSnarayan /* get current Tx head */ 76322f747efSnarayan *head = ldcp->tx_head; 76422f747efSnarayan 76522f747efSnarayan /* 76622f747efSnarayan * Reliable mode will use the ACKd head instead of the regular tx_head. 76722f747efSnarayan * Also in Reliable mode, advance ackd_head for all non DATA/INFO pkts, 76822f747efSnarayan * up to the current location of tx_head. This needs to be done 76922f747efSnarayan * as the peer will only ACK DATA/INFO pkts. 77022f747efSnarayan */ 77120ae46ebSha137994 if (ldcp->mode == LDC_MODE_RELIABLE) { 77222f747efSnarayan while (ldcp->tx_ackd_head != ldcp->tx_head) { 77322f747efSnarayan pkt = (ldc_msg_t *)(ldcp->tx_q_va + ldcp->tx_ackd_head); 77422f747efSnarayan if ((pkt->type & LDC_DATA) && (pkt->stype & LDC_INFO)) { 77522f747efSnarayan break; 77622f747efSnarayan } 77722f747efSnarayan /* advance ACKd head */ 77822f747efSnarayan ldcp->tx_ackd_head = 77922f747efSnarayan (ldcp->tx_ackd_head + LDC_PACKET_SIZE) % 78022f747efSnarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 78122f747efSnarayan } 78222f747efSnarayan *head = ldcp->tx_ackd_head; 78322f747efSnarayan } 78422f747efSnarayan } 7851ae08745Sheppo 7861ae08745Sheppo /* 7871ae08745Sheppo * Returns the tx_tail to be used for transfer 7881ae08745Sheppo * Re-reads the TX queue ptrs if and only if the 7891ae08745Sheppo * the cached head and tail are equal (queue is full) 7901ae08745Sheppo */ 7911ae08745Sheppo static int 7921ae08745Sheppo i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail) 7931ae08745Sheppo { 7941ae08745Sheppo int rv; 7951ae08745Sheppo uint64_t current_head, new_tail; 7961ae08745Sheppo 797d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 7981ae08745Sheppo /* Read the head and tail ptrs from HV */ 7991ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 8001ae08745Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 8011ae08745Sheppo if (rv) { 8021ae08745Sheppo cmn_err(CE_WARN, 8031ae08745Sheppo "i_ldc_get_tx_tail: (0x%lx) cannot read qptrs\n", 8041ae08745Sheppo ldcp->id); 8051ae08745Sheppo return (EIO); 8061ae08745Sheppo } 8071ae08745Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN) { 808cb112a14Slm66018 D1(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) channel not ready\n", 8091ae08745Sheppo ldcp->id); 8101ae08745Sheppo return (ECONNRESET); 8111ae08745Sheppo } 8121ae08745Sheppo 81322f747efSnarayan i_ldc_get_tx_head(ldcp, ¤t_head); 8141ae08745Sheppo 8151ae08745Sheppo /* increment the tail */ 8161ae08745Sheppo new_tail = (ldcp->tx_tail + LDC_PACKET_SIZE) % 8171ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 8181ae08745Sheppo 8191ae08745Sheppo if (new_tail == current_head) { 8201ae08745Sheppo DWARN(ldcp->id, 8211ae08745Sheppo "i_ldc_get_tx_tail: (0x%llx) TX queue is full\n", 8221ae08745Sheppo ldcp->id); 8231ae08745Sheppo return (EWOULDBLOCK); 8241ae08745Sheppo } 8251ae08745Sheppo 8261ae08745Sheppo D2(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) head=0x%llx, tail=0x%llx\n", 8271ae08745Sheppo ldcp->id, ldcp->tx_head, ldcp->tx_tail); 8281ae08745Sheppo 8291ae08745Sheppo *tail = ldcp->tx_tail; 8301ae08745Sheppo return (0); 8311ae08745Sheppo } 8321ae08745Sheppo 8331ae08745Sheppo /* 8341ae08745Sheppo * Set the tail pointer. If HV returns EWOULDBLOCK, it will back off 8350a55fbb7Slm66018 * and retry ldc_max_retries times before returning an error. 8361ae08745Sheppo * Returns 0, EWOULDBLOCK or EIO 8371ae08745Sheppo */ 8381ae08745Sheppo static int 8391ae08745Sheppo i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail) 8401ae08745Sheppo { 8411ae08745Sheppo int rv, retval = EWOULDBLOCK; 8420a55fbb7Slm66018 int retries; 8431ae08745Sheppo 844d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 8450a55fbb7Slm66018 for (retries = 0; retries < ldc_max_retries; retries++) { 8461ae08745Sheppo 8471ae08745Sheppo if ((rv = hv_ldc_tx_set_qtail(ldcp->id, tail)) == 0) { 8481ae08745Sheppo retval = 0; 8491ae08745Sheppo break; 8501ae08745Sheppo } 8511ae08745Sheppo if (rv != H_EWOULDBLOCK) { 8521ae08745Sheppo DWARN(ldcp->id, "i_ldc_set_tx_tail: (0x%llx) set " 8531ae08745Sheppo "qtail=0x%llx failed, rv=%d\n", ldcp->id, tail, rv); 8541ae08745Sheppo retval = EIO; 8551ae08745Sheppo break; 8561ae08745Sheppo } 8571ae08745Sheppo 8580a55fbb7Slm66018 /* wait for ldc_delay usecs */ 8590a55fbb7Slm66018 drv_usecwait(ldc_delay); 8601ae08745Sheppo } 8611ae08745Sheppo return (retval); 8621ae08745Sheppo } 8631ae08745Sheppo 8641ae08745Sheppo /* 86558283286Sha137994 * Copy a data packet from the HV receive queue to the data queue. 86658283286Sha137994 * Caller must ensure that the data queue is not already full. 86758283286Sha137994 * 86858283286Sha137994 * The *head argument represents the current head pointer for the HV 86958283286Sha137994 * receive queue. After copying a packet from the HV receive queue, 87058283286Sha137994 * the *head pointer will be updated. This allows the caller to update 87158283286Sha137994 * the head pointer in HV using the returned *head value. 87258283286Sha137994 */ 87358283286Sha137994 void 87458283286Sha137994 i_ldc_rxdq_copy(ldc_chan_t *ldcp, uint64_t *head) 87558283286Sha137994 { 87658283286Sha137994 uint64_t q_size, dq_size; 87758283286Sha137994 87858283286Sha137994 ASSERT(MUTEX_HELD(&ldcp->lock)); 87958283286Sha137994 88058283286Sha137994 q_size = ldcp->rx_q_entries << LDC_PACKET_SHIFT; 88158283286Sha137994 dq_size = ldcp->rx_dq_entries << LDC_PACKET_SHIFT; 88258283286Sha137994 88358283286Sha137994 ASSERT(Q_CONTIG_SPACE(ldcp->rx_dq_head, ldcp->rx_dq_tail, 88458283286Sha137994 dq_size) >= LDC_PACKET_SIZE); 88558283286Sha137994 88658283286Sha137994 bcopy((void *)(ldcp->rx_q_va + *head), 88758283286Sha137994 (void *)(ldcp->rx_dq_va + ldcp->rx_dq_tail), LDC_PACKET_SIZE); 88858283286Sha137994 TRACE_RXDQ_COPY(ldcp, LDC_PACKET_SIZE); 88958283286Sha137994 89058283286Sha137994 /* Update rx head */ 89158283286Sha137994 *head = (*head + LDC_PACKET_SIZE) % q_size; 89258283286Sha137994 89358283286Sha137994 /* Update dq tail */ 89458283286Sha137994 ldcp->rx_dq_tail = (ldcp->rx_dq_tail + LDC_PACKET_SIZE) % dq_size; 89558283286Sha137994 } 89658283286Sha137994 89758283286Sha137994 /* 89858283286Sha137994 * Update the Rx data queue head pointer 89958283286Sha137994 */ 90058283286Sha137994 static int 90158283286Sha137994 i_ldc_set_rxdq_head(ldc_chan_t *ldcp, uint64_t head) 90258283286Sha137994 { 90358283286Sha137994 ldcp->rx_dq_head = head; 90458283286Sha137994 return (0); 90558283286Sha137994 } 90658283286Sha137994 90758283286Sha137994 /* 90858283286Sha137994 * Get the Rx data queue head and tail pointers 90958283286Sha137994 */ 91058283286Sha137994 static uint64_t 91158283286Sha137994 i_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail, 91258283286Sha137994 uint64_t *link_state) 91358283286Sha137994 { 91458283286Sha137994 _NOTE(ARGUNUSED(link_state)) 91558283286Sha137994 *head = ldcp->rx_dq_head; 91658283286Sha137994 *tail = ldcp->rx_dq_tail; 91758283286Sha137994 return (0); 91858283286Sha137994 } 91958283286Sha137994 92058283286Sha137994 /* 92158283286Sha137994 * Wrapper for the Rx HV queue set head function. Giving the 92258283286Sha137994 * data queue and HV queue set head functions the same type. 92358283286Sha137994 */ 92458283286Sha137994 static uint64_t 92558283286Sha137994 i_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail, 92658283286Sha137994 uint64_t *link_state) 92758283286Sha137994 { 92858283286Sha137994 return (i_ldc_h2v_error(hv_ldc_rx_get_state(ldcp->id, head, tail, 92958283286Sha137994 link_state))); 93058283286Sha137994 } 93158283286Sha137994 93258283286Sha137994 /* 93358283286Sha137994 * LDC receive interrupt handler 93458283286Sha137994 * triggered for channel with data pending to read 93558283286Sha137994 * i.e. Rx queue content changes 93658283286Sha137994 */ 93758283286Sha137994 static uint_t 93858283286Sha137994 i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2) 93958283286Sha137994 { 94058283286Sha137994 _NOTE(ARGUNUSED(arg2)) 94158283286Sha137994 94258283286Sha137994 ldc_chan_t *ldcp; 94358283286Sha137994 boolean_t notify; 94458283286Sha137994 uint64_t event; 94558283286Sha137994 int rv; 94658283286Sha137994 94758283286Sha137994 /* Get the channel for which interrupt was received */ 94858283286Sha137994 if (arg1 == NULL) { 94958283286Sha137994 cmn_err(CE_WARN, "i_ldc_rx_hdlr: invalid arg\n"); 95058283286Sha137994 return (DDI_INTR_UNCLAIMED); 95158283286Sha137994 } 95258283286Sha137994 95358283286Sha137994 ldcp = (ldc_chan_t *)arg1; 95458283286Sha137994 95558283286Sha137994 D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n", 95658283286Sha137994 ldcp->id, ldcp); 95758283286Sha137994 D1(ldcp->id, "i_ldc_rx_hdlr: (%llx) USR%lx/TS%lx/HS%lx, LSTATE=%lx\n", 95858283286Sha137994 ldcp->id, ldcp->status, ldcp->tstate, ldcp->hstate, 95958283286Sha137994 ldcp->link_state); 96058283286Sha137994 96158283286Sha137994 /* Lock channel */ 96258283286Sha137994 mutex_enter(&ldcp->lock); 96358283286Sha137994 96458283286Sha137994 /* Mark the interrupt as being actively handled */ 96558283286Sha137994 ldcp->rx_intr_state = LDC_INTR_ACTIVE; 96658283286Sha137994 96758283286Sha137994 (void) i_ldc_rx_process_hvq(ldcp, ¬ify, &event); 96858283286Sha137994 96920ae46ebSha137994 if (ldcp->mode != LDC_MODE_RELIABLE) { 97058283286Sha137994 /* 97158283286Sha137994 * If there are no data packets on the queue, clear 97258283286Sha137994 * the interrupt. Otherwise, the ldc_read will clear 97358283286Sha137994 * interrupts after draining the queue. To indicate the 97458283286Sha137994 * interrupt has not yet been cleared, it is marked 97558283286Sha137994 * as pending. 97658283286Sha137994 */ 97758283286Sha137994 if ((event & LDC_EVT_READ) == 0) { 97858283286Sha137994 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 97958283286Sha137994 } else { 98058283286Sha137994 ldcp->rx_intr_state = LDC_INTR_PEND; 98158283286Sha137994 } 98258283286Sha137994 } 98358283286Sha137994 98458283286Sha137994 /* if callbacks are disabled, do not notify */ 98558283286Sha137994 if (notify && ldcp->cb_enabled) { 98658283286Sha137994 ldcp->cb_inprogress = B_TRUE; 98758283286Sha137994 mutex_exit(&ldcp->lock); 98858283286Sha137994 rv = ldcp->cb(event, ldcp->cb_arg); 98958283286Sha137994 if (rv) { 99058283286Sha137994 DWARN(ldcp->id, 99158283286Sha137994 "i_ldc_rx_hdlr: (0x%llx) callback failure", 99258283286Sha137994 ldcp->id); 99358283286Sha137994 } 99458283286Sha137994 mutex_enter(&ldcp->lock); 99558283286Sha137994 ldcp->cb_inprogress = B_FALSE; 99658283286Sha137994 } 99758283286Sha137994 99820ae46ebSha137994 if (ldcp->mode == LDC_MODE_RELIABLE) { 99958283286Sha137994 /* 100058283286Sha137994 * If we are using a secondary data queue, clear the 100158283286Sha137994 * interrupt. We should have processed all CTRL packets 100258283286Sha137994 * and copied all DATA packets to the secondary queue. 100358283286Sha137994 * Even if secondary queue filled up, clear the interrupts, 100458283286Sha137994 * this will trigger another interrupt and force the 100558283286Sha137994 * handler to copy more data. 100658283286Sha137994 */ 100758283286Sha137994 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 100858283286Sha137994 } 100958283286Sha137994 101058283286Sha137994 mutex_exit(&ldcp->lock); 101158283286Sha137994 101258283286Sha137994 D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) exiting handler", ldcp->id); 101358283286Sha137994 101458283286Sha137994 return (DDI_INTR_CLAIMED); 101558283286Sha137994 } 101658283286Sha137994 101758283286Sha137994 /* 101858283286Sha137994 * Wrapper for the Rx HV queue processing function to be used when 101958283286Sha137994 * checking the Rx HV queue for data packets. Unlike the interrupt 102058283286Sha137994 * handler code flow, the Rx interrupt is not cleared here and 102158283286Sha137994 * callbacks are not made. 102258283286Sha137994 */ 102358283286Sha137994 static uint_t 102458283286Sha137994 i_ldc_chkq(ldc_chan_t *ldcp) 102558283286Sha137994 { 102658283286Sha137994 boolean_t notify; 102758283286Sha137994 uint64_t event; 102858283286Sha137994 102958283286Sha137994 return (i_ldc_rx_process_hvq(ldcp, ¬ify, &event)); 103058283286Sha137994 } 103158283286Sha137994 103258283286Sha137994 /* 10331ae08745Sheppo * Send a LDC message 10341ae08745Sheppo */ 10351ae08745Sheppo static int 10361ae08745Sheppo i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype, 10371ae08745Sheppo uint8_t ctrlmsg) 10381ae08745Sheppo { 10391ae08745Sheppo int rv; 10401ae08745Sheppo ldc_msg_t *pkt; 10411ae08745Sheppo uint64_t tx_tail; 104222f747efSnarayan uint32_t curr_seqid; 10431ae08745Sheppo 1044d10e4ef2Snarayan /* Obtain Tx lock */ 1045d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 1046d10e4ef2Snarayan 104722f747efSnarayan curr_seqid = ldcp->last_msg_snt; 104822f747efSnarayan 10491ae08745Sheppo /* get the current tail for the message */ 10501ae08745Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 10511ae08745Sheppo if (rv) { 10521ae08745Sheppo DWARN(ldcp->id, 10531ae08745Sheppo "i_ldc_send_pkt: (0x%llx) error sending pkt, " 10541ae08745Sheppo "type=0x%x,subtype=0x%x,ctrl=0x%x\n", 10551ae08745Sheppo ldcp->id, pkttype, subtype, ctrlmsg); 1056d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 10571ae08745Sheppo return (rv); 10581ae08745Sheppo } 10591ae08745Sheppo 10601ae08745Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 10611ae08745Sheppo ZERO_PKT(pkt); 10621ae08745Sheppo 10631ae08745Sheppo /* Initialize the packet */ 10641ae08745Sheppo pkt->type = pkttype; 10651ae08745Sheppo pkt->stype = subtype; 10661ae08745Sheppo pkt->ctrl = ctrlmsg; 10671ae08745Sheppo 10681ae08745Sheppo /* Store ackid/seqid iff it is RELIABLE mode & not a RTS/RTR message */ 10691ae08745Sheppo if (((ctrlmsg & LDC_CTRL_MASK) != LDC_RTS) && 10701ae08745Sheppo ((ctrlmsg & LDC_CTRL_MASK) != LDC_RTR)) { 10711ae08745Sheppo curr_seqid++; 10721ae08745Sheppo if (ldcp->mode != LDC_MODE_RAW) { 10731ae08745Sheppo pkt->seqid = curr_seqid; 10741ae08745Sheppo pkt->ackid = ldcp->last_msg_rcd; 10751ae08745Sheppo } 10761ae08745Sheppo } 10771ae08745Sheppo DUMP_LDC_PKT(ldcp, "i_ldc_send_pkt", (uint64_t)pkt); 10781ae08745Sheppo 10791ae08745Sheppo /* initiate the send by calling into HV and set the new tail */ 10801ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 10811ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 10821ae08745Sheppo 10831ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 10841ae08745Sheppo if (rv) { 10851ae08745Sheppo DWARN(ldcp->id, 10861ae08745Sheppo "i_ldc_send_pkt:(0x%llx) error sending pkt, " 10871ae08745Sheppo "type=0x%x,stype=0x%x,ctrl=0x%x\n", 10881ae08745Sheppo ldcp->id, pkttype, subtype, ctrlmsg); 1089d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 10901ae08745Sheppo return (EIO); 10911ae08745Sheppo } 10921ae08745Sheppo 10931ae08745Sheppo ldcp->last_msg_snt = curr_seqid; 10941ae08745Sheppo ldcp->tx_tail = tx_tail; 10951ae08745Sheppo 1096d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 10971ae08745Sheppo return (0); 10981ae08745Sheppo } 10991ae08745Sheppo 11001ae08745Sheppo /* 11011ae08745Sheppo * Checks if packet was received in right order 1102e1ebb9ecSlm66018 * in the case of a reliable link. 11031ae08745Sheppo * Returns 0 if in order, else EIO 11041ae08745Sheppo */ 11051ae08745Sheppo static int 11061ae08745Sheppo i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *msg) 11071ae08745Sheppo { 11081ae08745Sheppo /* No seqid checking for RAW mode */ 11091ae08745Sheppo if (ldcp->mode == LDC_MODE_RAW) 11101ae08745Sheppo return (0); 11111ae08745Sheppo 11121ae08745Sheppo /* No seqid checking for version, RTS, RTR message */ 11131ae08745Sheppo if (msg->ctrl == LDC_VER || 11141ae08745Sheppo msg->ctrl == LDC_RTS || 11151ae08745Sheppo msg->ctrl == LDC_RTR) 11161ae08745Sheppo return (0); 11171ae08745Sheppo 11181ae08745Sheppo /* Initial seqid to use is sent in RTS/RTR and saved in last_msg_rcd */ 11191ae08745Sheppo if (msg->seqid != (ldcp->last_msg_rcd + 1)) { 11201ae08745Sheppo DWARN(ldcp->id, 11211ae08745Sheppo "i_ldc_check_seqid: (0x%llx) out-of-order pkt, got 0x%x, " 11221ae08745Sheppo "expecting 0x%x\n", ldcp->id, msg->seqid, 11231ae08745Sheppo (ldcp->last_msg_rcd + 1)); 11241ae08745Sheppo return (EIO); 11251ae08745Sheppo } 11261ae08745Sheppo 112783d3bc6fSnarayan #ifdef DEBUG 112883d3bc6fSnarayan if (LDC_INJECT_PKTLOSS(ldcp)) { 112983d3bc6fSnarayan DWARN(ldcp->id, 113083d3bc6fSnarayan "i_ldc_check_seqid: (0x%llx) inject pkt loss\n", ldcp->id); 113183d3bc6fSnarayan return (EIO); 113283d3bc6fSnarayan } 113383d3bc6fSnarayan #endif 113483d3bc6fSnarayan 11351ae08745Sheppo return (0); 11361ae08745Sheppo } 11371ae08745Sheppo 11381ae08745Sheppo 11391ae08745Sheppo /* 11401ae08745Sheppo * Process an incoming version ctrl message 11411ae08745Sheppo */ 11421ae08745Sheppo static int 11431ae08745Sheppo i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg) 11441ae08745Sheppo { 11451ae08745Sheppo int rv = 0, idx = ldcp->next_vidx; 11461ae08745Sheppo ldc_msg_t *pkt; 11471ae08745Sheppo uint64_t tx_tail; 11481ae08745Sheppo ldc_ver_t *rcvd_ver; 11491ae08745Sheppo 11501ae08745Sheppo /* get the received version */ 11511ae08745Sheppo rcvd_ver = (ldc_ver_t *)((uint64_t)msg + LDC_PAYLOAD_VER_OFF); 11521ae08745Sheppo 11531ae08745Sheppo D2(ldcp->id, "i_ldc_process_VER: (0x%llx) received VER v%u.%u\n", 11541ae08745Sheppo ldcp->id, rcvd_ver->major, rcvd_ver->minor); 11551ae08745Sheppo 1156d10e4ef2Snarayan /* Obtain Tx lock */ 1157d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 1158d10e4ef2Snarayan 11591ae08745Sheppo switch (msg->stype) { 11601ae08745Sheppo case LDC_INFO: 11611ae08745Sheppo 11623af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) { 11633af08d82Slm66018 (void) i_ldc_txq_reconf(ldcp); 11643af08d82Slm66018 i_ldc_reset_state(ldcp); 11653af08d82Slm66018 mutex_exit(&ldcp->tx_lock); 11663af08d82Slm66018 return (EAGAIN); 11673af08d82Slm66018 } 11683af08d82Slm66018 11691ae08745Sheppo /* get the current tail and pkt for the response */ 11701ae08745Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 11711ae08745Sheppo if (rv != 0) { 11721ae08745Sheppo DWARN(ldcp->id, 11731ae08745Sheppo "i_ldc_process_VER: (0x%llx) err sending " 11741ae08745Sheppo "version ACK/NACK\n", ldcp->id); 11753af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1176d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 11771ae08745Sheppo return (ECONNRESET); 11781ae08745Sheppo } 11791ae08745Sheppo 11801ae08745Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 11811ae08745Sheppo ZERO_PKT(pkt); 11821ae08745Sheppo 11831ae08745Sheppo /* initialize the packet */ 11841ae08745Sheppo pkt->type = LDC_CTRL; 11851ae08745Sheppo pkt->ctrl = LDC_VER; 11861ae08745Sheppo 11871ae08745Sheppo for (;;) { 11881ae08745Sheppo 11891ae08745Sheppo D1(ldcp->id, "i_ldc_process_VER: got %u.%u chk %u.%u\n", 11901ae08745Sheppo rcvd_ver->major, rcvd_ver->minor, 11911ae08745Sheppo ldc_versions[idx].major, ldc_versions[idx].minor); 11921ae08745Sheppo 11931ae08745Sheppo if (rcvd_ver->major == ldc_versions[idx].major) { 11941ae08745Sheppo /* major version match - ACK version */ 11951ae08745Sheppo pkt->stype = LDC_ACK; 11961ae08745Sheppo 11971ae08745Sheppo /* 11981ae08745Sheppo * lower minor version to the one this endpt 11991ae08745Sheppo * supports, if necessary 12001ae08745Sheppo */ 12011ae08745Sheppo if (rcvd_ver->minor > ldc_versions[idx].minor) 12021ae08745Sheppo rcvd_ver->minor = 12031ae08745Sheppo ldc_versions[idx].minor; 12041ae08745Sheppo bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver)); 12051ae08745Sheppo 12061ae08745Sheppo break; 12071ae08745Sheppo } 12081ae08745Sheppo 12091ae08745Sheppo if (rcvd_ver->major > ldc_versions[idx].major) { 12101ae08745Sheppo 12111ae08745Sheppo D1(ldcp->id, "i_ldc_process_VER: using next" 12121ae08745Sheppo " lower idx=%d, v%u.%u\n", idx, 12131ae08745Sheppo ldc_versions[idx].major, 12141ae08745Sheppo ldc_versions[idx].minor); 12151ae08745Sheppo 12161ae08745Sheppo /* nack with next lower version */ 12171ae08745Sheppo pkt->stype = LDC_NACK; 12181ae08745Sheppo bcopy(&ldc_versions[idx], pkt->udata, 12191ae08745Sheppo sizeof (ldc_versions[idx])); 12201ae08745Sheppo ldcp->next_vidx = idx; 12211ae08745Sheppo break; 12221ae08745Sheppo } 12231ae08745Sheppo 12241ae08745Sheppo /* next major version */ 12251ae08745Sheppo idx++; 12261ae08745Sheppo 12271ae08745Sheppo D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx); 12281ae08745Sheppo 12291ae08745Sheppo if (idx == LDC_NUM_VERS) { 12301ae08745Sheppo /* no version match - send NACK */ 12311ae08745Sheppo pkt->stype = LDC_NACK; 12321ae08745Sheppo bzero(pkt->udata, sizeof (ldc_ver_t)); 12331ae08745Sheppo ldcp->next_vidx = 0; 12341ae08745Sheppo break; 12351ae08745Sheppo } 12361ae08745Sheppo } 12371ae08745Sheppo 12381ae08745Sheppo /* initiate the send by calling into HV and set the new tail */ 12391ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 12401ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 12411ae08745Sheppo 12421ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 12431ae08745Sheppo if (rv == 0) { 12441ae08745Sheppo ldcp->tx_tail = tx_tail; 12451ae08745Sheppo if (pkt->stype == LDC_ACK) { 12461ae08745Sheppo D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent" 12471ae08745Sheppo " version ACK\n", ldcp->id); 12481ae08745Sheppo /* Save the ACK'd version */ 12491ae08745Sheppo ldcp->version.major = rcvd_ver->major; 12501ae08745Sheppo ldcp->version.minor = rcvd_ver->minor; 12510a55fbb7Slm66018 ldcp->hstate |= TS_RCVD_VER; 12521ae08745Sheppo ldcp->tstate |= TS_VER_DONE; 125383d3bc6fSnarayan D1(DBG_ALL_LDCS, 12543af08d82Slm66018 "(0x%llx) Sent ACK, " 12553af08d82Slm66018 "Agreed on version v%u.%u\n", 12561ae08745Sheppo ldcp->id, rcvd_ver->major, rcvd_ver->minor); 12571ae08745Sheppo } 12581ae08745Sheppo } else { 12591ae08745Sheppo DWARN(ldcp->id, 12601ae08745Sheppo "i_ldc_process_VER: (0x%llx) error sending " 12611ae08745Sheppo "ACK/NACK\n", ldcp->id); 12623af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1263d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 12641ae08745Sheppo return (ECONNRESET); 12651ae08745Sheppo } 12661ae08745Sheppo 12671ae08745Sheppo break; 12681ae08745Sheppo 12691ae08745Sheppo case LDC_ACK: 12703af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) { 12713af08d82Slm66018 if (ldcp->version.major != rcvd_ver->major || 12723af08d82Slm66018 ldcp->version.minor != rcvd_ver->minor) { 12733af08d82Slm66018 12743af08d82Slm66018 /* mismatched version - reset connection */ 12753af08d82Slm66018 DWARN(ldcp->id, 12763af08d82Slm66018 "i_ldc_process_VER: (0x%llx) recvd" 12773af08d82Slm66018 " ACK ver != sent ACK ver\n", ldcp->id); 12783af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 12793af08d82Slm66018 mutex_exit(&ldcp->tx_lock); 12803af08d82Slm66018 return (ECONNRESET); 12813af08d82Slm66018 } 12823af08d82Slm66018 } else { 12831ae08745Sheppo /* SUCCESS - we have agreed on a version */ 12841ae08745Sheppo ldcp->version.major = rcvd_ver->major; 12851ae08745Sheppo ldcp->version.minor = rcvd_ver->minor; 12861ae08745Sheppo ldcp->tstate |= TS_VER_DONE; 12873af08d82Slm66018 } 12881ae08745Sheppo 1289cb112a14Slm66018 D1(ldcp->id, "(0x%llx) Got ACK, Agreed on version v%u.%u\n", 12901ae08745Sheppo ldcp->id, rcvd_ver->major, rcvd_ver->minor); 12911ae08745Sheppo 12921ae08745Sheppo /* initiate RTS-RTR-RDX handshake */ 12931ae08745Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 12941ae08745Sheppo if (rv) { 12951ae08745Sheppo DWARN(ldcp->id, 12961ae08745Sheppo "i_ldc_process_VER: (0x%llx) cannot send RTS\n", 12971ae08745Sheppo ldcp->id); 12983af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1299d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 13001ae08745Sheppo return (ECONNRESET); 13011ae08745Sheppo } 13021ae08745Sheppo 13031ae08745Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 13041ae08745Sheppo ZERO_PKT(pkt); 13051ae08745Sheppo 13061ae08745Sheppo pkt->type = LDC_CTRL; 13071ae08745Sheppo pkt->stype = LDC_INFO; 13081ae08745Sheppo pkt->ctrl = LDC_RTS; 13091ae08745Sheppo pkt->env = ldcp->mode; 13101ae08745Sheppo if (ldcp->mode != LDC_MODE_RAW) 13111ae08745Sheppo pkt->seqid = LDC_INIT_SEQID; 13121ae08745Sheppo 13131ae08745Sheppo ldcp->last_msg_rcd = LDC_INIT_SEQID; 13141ae08745Sheppo 13151ae08745Sheppo DUMP_LDC_PKT(ldcp, "i_ldc_process_VER snd rts", (uint64_t)pkt); 13161ae08745Sheppo 13171ae08745Sheppo /* initiate the send by calling into HV and set the new tail */ 13181ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 13191ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 13201ae08745Sheppo 13211ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 13221ae08745Sheppo if (rv) { 13231ae08745Sheppo D2(ldcp->id, 13241ae08745Sheppo "i_ldc_process_VER: (0x%llx) no listener\n", 13251ae08745Sheppo ldcp->id); 13263af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1327d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 13281ae08745Sheppo return (ECONNRESET); 13291ae08745Sheppo } 13301ae08745Sheppo 13311ae08745Sheppo ldcp->tx_tail = tx_tail; 13321ae08745Sheppo ldcp->hstate |= TS_SENT_RTS; 13331ae08745Sheppo 13341ae08745Sheppo break; 13351ae08745Sheppo 13361ae08745Sheppo case LDC_NACK: 13371ae08745Sheppo /* check if version in NACK is zero */ 13381ae08745Sheppo if (rcvd_ver->major == 0 && rcvd_ver->minor == 0) { 13391ae08745Sheppo /* version handshake failure */ 13401ae08745Sheppo DWARN(DBG_ALL_LDCS, 13411ae08745Sheppo "i_ldc_process_VER: (0x%llx) no version match\n", 13421ae08745Sheppo ldcp->id); 13433af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1344d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 13451ae08745Sheppo return (ECONNRESET); 13461ae08745Sheppo } 13471ae08745Sheppo 13481ae08745Sheppo /* get the current tail and pkt for the response */ 13491ae08745Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 13501ae08745Sheppo if (rv != 0) { 13511ae08745Sheppo cmn_err(CE_NOTE, 13521ae08745Sheppo "i_ldc_process_VER: (0x%lx) err sending " 13531ae08745Sheppo "version ACK/NACK\n", ldcp->id); 13543af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1355d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 13561ae08745Sheppo return (ECONNRESET); 13571ae08745Sheppo } 13581ae08745Sheppo 13591ae08745Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 13601ae08745Sheppo ZERO_PKT(pkt); 13611ae08745Sheppo 13621ae08745Sheppo /* initialize the packet */ 13631ae08745Sheppo pkt->type = LDC_CTRL; 13641ae08745Sheppo pkt->ctrl = LDC_VER; 13651ae08745Sheppo pkt->stype = LDC_INFO; 13661ae08745Sheppo 13671ae08745Sheppo /* check ver in NACK msg has a match */ 13681ae08745Sheppo for (;;) { 13691ae08745Sheppo if (rcvd_ver->major == ldc_versions[idx].major) { 13701ae08745Sheppo /* 13711ae08745Sheppo * major version match - resubmit request 13721ae08745Sheppo * if lower minor version to the one this endpt 13731ae08745Sheppo * supports, if necessary 13741ae08745Sheppo */ 13751ae08745Sheppo if (rcvd_ver->minor > ldc_versions[idx].minor) 13761ae08745Sheppo rcvd_ver->minor = 13771ae08745Sheppo ldc_versions[idx].minor; 13781ae08745Sheppo bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver)); 13791ae08745Sheppo break; 13801ae08745Sheppo } 13811ae08745Sheppo 13821ae08745Sheppo if (rcvd_ver->major > ldc_versions[idx].major) { 13831ae08745Sheppo 13841ae08745Sheppo D1(ldcp->id, "i_ldc_process_VER: using next" 13851ae08745Sheppo " lower idx=%d, v%u.%u\n", idx, 13861ae08745Sheppo ldc_versions[idx].major, 13871ae08745Sheppo ldc_versions[idx].minor); 13881ae08745Sheppo 13891ae08745Sheppo /* send next lower version */ 13901ae08745Sheppo bcopy(&ldc_versions[idx], pkt->udata, 13911ae08745Sheppo sizeof (ldc_versions[idx])); 13921ae08745Sheppo ldcp->next_vidx = idx; 13931ae08745Sheppo break; 13941ae08745Sheppo } 13951ae08745Sheppo 13961ae08745Sheppo /* next version */ 13971ae08745Sheppo idx++; 13981ae08745Sheppo 13991ae08745Sheppo D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx); 14001ae08745Sheppo 14011ae08745Sheppo if (idx == LDC_NUM_VERS) { 14021ae08745Sheppo /* no version match - terminate */ 14031ae08745Sheppo ldcp->next_vidx = 0; 1404d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 14051ae08745Sheppo return (ECONNRESET); 14061ae08745Sheppo } 14071ae08745Sheppo } 14081ae08745Sheppo 14091ae08745Sheppo /* initiate the send by calling into HV and set the new tail */ 14101ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 14111ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 14121ae08745Sheppo 14131ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 14141ae08745Sheppo if (rv == 0) { 14151ae08745Sheppo D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent version" 14161ae08745Sheppo "INFO v%u.%u\n", ldcp->id, ldc_versions[idx].major, 14171ae08745Sheppo ldc_versions[idx].minor); 14181ae08745Sheppo ldcp->tx_tail = tx_tail; 14191ae08745Sheppo } else { 14201ae08745Sheppo cmn_err(CE_NOTE, 14211ae08745Sheppo "i_ldc_process_VER: (0x%lx) error sending version" 14221ae08745Sheppo "INFO\n", ldcp->id); 14233af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1424d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 14251ae08745Sheppo return (ECONNRESET); 14261ae08745Sheppo } 14271ae08745Sheppo 14281ae08745Sheppo break; 14291ae08745Sheppo } 14301ae08745Sheppo 1431d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 14321ae08745Sheppo return (rv); 14331ae08745Sheppo } 14341ae08745Sheppo 14351ae08745Sheppo 14361ae08745Sheppo /* 14371ae08745Sheppo * Process an incoming RTS ctrl message 14381ae08745Sheppo */ 14391ae08745Sheppo static int 14401ae08745Sheppo i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg) 14411ae08745Sheppo { 14421ae08745Sheppo int rv = 0; 14431ae08745Sheppo ldc_msg_t *pkt; 14441ae08745Sheppo uint64_t tx_tail; 14451ae08745Sheppo boolean_t sent_NACK = B_FALSE; 14461ae08745Sheppo 14471ae08745Sheppo D2(ldcp->id, "i_ldc_process_RTS: (0x%llx) received RTS\n", ldcp->id); 14481ae08745Sheppo 14491ae08745Sheppo switch (msg->stype) { 14501ae08745Sheppo case LDC_NACK: 14511ae08745Sheppo DWARN(ldcp->id, 14521ae08745Sheppo "i_ldc_process_RTS: (0x%llx) RTS NACK received\n", 14531ae08745Sheppo ldcp->id); 14541ae08745Sheppo 14551ae08745Sheppo /* Reset the channel -- as we cannot continue */ 1456d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 14573af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1458d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 14591ae08745Sheppo rv = ECONNRESET; 14601ae08745Sheppo break; 14611ae08745Sheppo 14621ae08745Sheppo case LDC_INFO: 14631ae08745Sheppo 14641ae08745Sheppo /* check mode */ 14651ae08745Sheppo if (ldcp->mode != (ldc_mode_t)msg->env) { 14661ae08745Sheppo cmn_err(CE_NOTE, 14671ae08745Sheppo "i_ldc_process_RTS: (0x%lx) mode mismatch\n", 14681ae08745Sheppo ldcp->id); 14691ae08745Sheppo /* 14701ae08745Sheppo * send NACK in response to MODE message 14711ae08745Sheppo * get the current tail for the response 14721ae08745Sheppo */ 14731ae08745Sheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTS); 14741ae08745Sheppo if (rv) { 14751ae08745Sheppo /* if cannot send NACK - reset channel */ 1476d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 14773af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1478d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 14791ae08745Sheppo rv = ECONNRESET; 14801ae08745Sheppo break; 14811ae08745Sheppo } 14821ae08745Sheppo sent_NACK = B_TRUE; 14831ae08745Sheppo } 14841ae08745Sheppo break; 14851ae08745Sheppo default: 14861ae08745Sheppo DWARN(ldcp->id, "i_ldc_process_RTS: (0x%llx) unexp ACK\n", 14871ae08745Sheppo ldcp->id); 1488d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 14893af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1490d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 14911ae08745Sheppo rv = ECONNRESET; 14921ae08745Sheppo break; 14931ae08745Sheppo } 14941ae08745Sheppo 14951ae08745Sheppo /* 14961ae08745Sheppo * If either the connection was reset (when rv != 0) or 14971ae08745Sheppo * a NACK was sent, we return. In the case of a NACK 14981ae08745Sheppo * we dont want to consume the packet that came in but 14991ae08745Sheppo * not record that we received the RTS 15001ae08745Sheppo */ 15011ae08745Sheppo if (rv || sent_NACK) 15021ae08745Sheppo return (rv); 15031ae08745Sheppo 15041ae08745Sheppo /* record RTS received */ 15051ae08745Sheppo ldcp->hstate |= TS_RCVD_RTS; 15061ae08745Sheppo 15071ae08745Sheppo /* store initial SEQID info */ 15081ae08745Sheppo ldcp->last_msg_snt = msg->seqid; 15091ae08745Sheppo 1510d10e4ef2Snarayan /* Obtain Tx lock */ 1511d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 1512d10e4ef2Snarayan 15131ae08745Sheppo /* get the current tail for the response */ 15141ae08745Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 15151ae08745Sheppo if (rv != 0) { 15161ae08745Sheppo cmn_err(CE_NOTE, 15171ae08745Sheppo "i_ldc_process_RTS: (0x%lx) err sending RTR\n", 15181ae08745Sheppo ldcp->id); 15193af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1520d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 15211ae08745Sheppo return (ECONNRESET); 15221ae08745Sheppo } 15231ae08745Sheppo 15241ae08745Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 15251ae08745Sheppo ZERO_PKT(pkt); 15261ae08745Sheppo 15271ae08745Sheppo /* initialize the packet */ 15281ae08745Sheppo pkt->type = LDC_CTRL; 15291ae08745Sheppo pkt->stype = LDC_INFO; 15301ae08745Sheppo pkt->ctrl = LDC_RTR; 15311ae08745Sheppo pkt->env = ldcp->mode; 15321ae08745Sheppo if (ldcp->mode != LDC_MODE_RAW) 15331ae08745Sheppo pkt->seqid = LDC_INIT_SEQID; 15341ae08745Sheppo 15351ae08745Sheppo ldcp->last_msg_rcd = msg->seqid; 15361ae08745Sheppo 15371ae08745Sheppo /* initiate the send by calling into HV and set the new tail */ 15381ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 15391ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 15401ae08745Sheppo 15411ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 15421ae08745Sheppo if (rv == 0) { 15431ae08745Sheppo D2(ldcp->id, 15441ae08745Sheppo "i_ldc_process_RTS: (0x%llx) sent RTR\n", ldcp->id); 15451ae08745Sheppo DUMP_LDC_PKT(ldcp, "i_ldc_process_RTS sent rtr", (uint64_t)pkt); 15461ae08745Sheppo 15471ae08745Sheppo ldcp->tx_tail = tx_tail; 15481ae08745Sheppo ldcp->hstate |= TS_SENT_RTR; 15491ae08745Sheppo 15501ae08745Sheppo } else { 15511ae08745Sheppo cmn_err(CE_NOTE, 15521ae08745Sheppo "i_ldc_process_RTS: (0x%lx) error sending RTR\n", 15531ae08745Sheppo ldcp->id); 15543af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1555d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 15561ae08745Sheppo return (ECONNRESET); 15571ae08745Sheppo } 15581ae08745Sheppo 1559d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 15601ae08745Sheppo return (0); 15611ae08745Sheppo } 15621ae08745Sheppo 15631ae08745Sheppo /* 15641ae08745Sheppo * Process an incoming RTR ctrl message 15651ae08745Sheppo */ 15661ae08745Sheppo static int 15671ae08745Sheppo i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg) 15681ae08745Sheppo { 15691ae08745Sheppo int rv = 0; 15701ae08745Sheppo boolean_t sent_NACK = B_FALSE; 15711ae08745Sheppo 15721ae08745Sheppo D2(ldcp->id, "i_ldc_process_RTR: (0x%llx) received RTR\n", ldcp->id); 15731ae08745Sheppo 15741ae08745Sheppo switch (msg->stype) { 15751ae08745Sheppo case LDC_NACK: 15761ae08745Sheppo /* RTR NACK received */ 15771ae08745Sheppo DWARN(ldcp->id, 15781ae08745Sheppo "i_ldc_process_RTR: (0x%llx) RTR NACK received\n", 15791ae08745Sheppo ldcp->id); 15801ae08745Sheppo 15811ae08745Sheppo /* Reset the channel -- as we cannot continue */ 1582d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 15833af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1584d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 15851ae08745Sheppo rv = ECONNRESET; 15861ae08745Sheppo 15871ae08745Sheppo break; 15881ae08745Sheppo 15891ae08745Sheppo case LDC_INFO: 15901ae08745Sheppo 15911ae08745Sheppo /* check mode */ 15921ae08745Sheppo if (ldcp->mode != (ldc_mode_t)msg->env) { 15931ae08745Sheppo DWARN(ldcp->id, 1594cb112a14Slm66018 "i_ldc_process_RTR: (0x%llx) mode mismatch, " 1595cb112a14Slm66018 "expecting 0x%x, got 0x%x\n", 1596cb112a14Slm66018 ldcp->id, ldcp->mode, (ldc_mode_t)msg->env); 15971ae08745Sheppo /* 15981ae08745Sheppo * send NACK in response to MODE message 15991ae08745Sheppo * get the current tail for the response 16001ae08745Sheppo */ 16011ae08745Sheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTR); 16021ae08745Sheppo if (rv) { 16031ae08745Sheppo /* if cannot send NACK - reset channel */ 1604d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 16053af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1606d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 16071ae08745Sheppo rv = ECONNRESET; 16081ae08745Sheppo break; 16091ae08745Sheppo } 16101ae08745Sheppo sent_NACK = B_TRUE; 16111ae08745Sheppo } 16121ae08745Sheppo break; 16131ae08745Sheppo 16141ae08745Sheppo default: 16151ae08745Sheppo DWARN(ldcp->id, "i_ldc_process_RTR: (0x%llx) unexp ACK\n", 16161ae08745Sheppo ldcp->id); 16171ae08745Sheppo 16181ae08745Sheppo /* Reset the channel -- as we cannot continue */ 1619d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 16203af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1621d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 16221ae08745Sheppo rv = ECONNRESET; 16231ae08745Sheppo break; 16241ae08745Sheppo } 16251ae08745Sheppo 16261ae08745Sheppo /* 16271ae08745Sheppo * If either the connection was reset (when rv != 0) or 16281ae08745Sheppo * a NACK was sent, we return. In the case of a NACK 16291ae08745Sheppo * we dont want to consume the packet that came in but 16301ae08745Sheppo * not record that we received the RTR 16311ae08745Sheppo */ 16321ae08745Sheppo if (rv || sent_NACK) 16331ae08745Sheppo return (rv); 16341ae08745Sheppo 16351ae08745Sheppo ldcp->last_msg_snt = msg->seqid; 16361ae08745Sheppo ldcp->hstate |= TS_RCVD_RTR; 16371ae08745Sheppo 16381ae08745Sheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_INFO, LDC_RDX); 16391ae08745Sheppo if (rv) { 16401ae08745Sheppo cmn_err(CE_NOTE, 16411ae08745Sheppo "i_ldc_process_RTR: (0x%lx) cannot send RDX\n", 16421ae08745Sheppo ldcp->id); 1643d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 16443af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1645d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 16461ae08745Sheppo return (ECONNRESET); 16471ae08745Sheppo } 16481ae08745Sheppo D2(ldcp->id, 16491ae08745Sheppo "i_ldc_process_RTR: (0x%llx) sent RDX\n", ldcp->id); 16501ae08745Sheppo 16511ae08745Sheppo ldcp->hstate |= TS_SENT_RDX; 16521ae08745Sheppo ldcp->tstate |= TS_HSHAKE_DONE; 16533af08d82Slm66018 if ((ldcp->tstate & TS_IN_RESET) == 0) 16541ae08745Sheppo ldcp->status = LDC_UP; 16551ae08745Sheppo 1656cb112a14Slm66018 D1(ldcp->id, "(0x%llx) Handshake Complete\n", ldcp->id); 16571ae08745Sheppo 16581ae08745Sheppo return (0); 16591ae08745Sheppo } 16601ae08745Sheppo 16611ae08745Sheppo 16621ae08745Sheppo /* 16631ae08745Sheppo * Process an incoming RDX ctrl message 16641ae08745Sheppo */ 16651ae08745Sheppo static int 16661ae08745Sheppo i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg) 16671ae08745Sheppo { 16681ae08745Sheppo int rv = 0; 16691ae08745Sheppo 16701ae08745Sheppo D2(ldcp->id, "i_ldc_process_RDX: (0x%llx) received RDX\n", ldcp->id); 16711ae08745Sheppo 16721ae08745Sheppo switch (msg->stype) { 16731ae08745Sheppo case LDC_NACK: 16741ae08745Sheppo /* RDX NACK received */ 16751ae08745Sheppo DWARN(ldcp->id, 16761ae08745Sheppo "i_ldc_process_RDX: (0x%llx) RDX NACK received\n", 16771ae08745Sheppo ldcp->id); 16781ae08745Sheppo 16791ae08745Sheppo /* Reset the channel -- as we cannot continue */ 1680d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 16813af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1682d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 16831ae08745Sheppo rv = ECONNRESET; 16841ae08745Sheppo 16851ae08745Sheppo break; 16861ae08745Sheppo 16871ae08745Sheppo case LDC_INFO: 16881ae08745Sheppo 16891ae08745Sheppo /* 16901ae08745Sheppo * if channel is UP and a RDX received after data transmission 16911ae08745Sheppo * has commenced it is an error 16921ae08745Sheppo */ 16931ae08745Sheppo if ((ldcp->tstate == TS_UP) && (ldcp->hstate & TS_RCVD_RDX)) { 16941ae08745Sheppo DWARN(DBG_ALL_LDCS, 16951ae08745Sheppo "i_ldc_process_RDX: (0x%llx) unexpected RDX" 16961ae08745Sheppo " - LDC reset\n", ldcp->id); 1697d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 16983af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1699d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 17001ae08745Sheppo return (ECONNRESET); 17011ae08745Sheppo } 17021ae08745Sheppo 17031ae08745Sheppo ldcp->hstate |= TS_RCVD_RDX; 17041ae08745Sheppo ldcp->tstate |= TS_HSHAKE_DONE; 17053af08d82Slm66018 if ((ldcp->tstate & TS_IN_RESET) == 0) 17061ae08745Sheppo ldcp->status = LDC_UP; 17071ae08745Sheppo 17081ae08745Sheppo D1(DBG_ALL_LDCS, "(0x%llx) Handshake Complete\n", ldcp->id); 17091ae08745Sheppo break; 17101ae08745Sheppo 17111ae08745Sheppo default: 17121ae08745Sheppo DWARN(ldcp->id, "i_ldc_process_RDX: (0x%llx) unexp ACK\n", 17131ae08745Sheppo ldcp->id); 17141ae08745Sheppo 17151ae08745Sheppo /* Reset the channel -- as we cannot continue */ 1716d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 17173af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1718d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 17191ae08745Sheppo rv = ECONNRESET; 17201ae08745Sheppo break; 17211ae08745Sheppo } 17221ae08745Sheppo 17231ae08745Sheppo return (rv); 17241ae08745Sheppo } 17251ae08745Sheppo 17261ae08745Sheppo /* 17271ae08745Sheppo * Process an incoming ACK for a data packet 17281ae08745Sheppo */ 17291ae08745Sheppo static int 17301ae08745Sheppo i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg) 17311ae08745Sheppo { 17321ae08745Sheppo int rv; 17331ae08745Sheppo uint64_t tx_head; 17341ae08745Sheppo ldc_msg_t *pkt; 17351ae08745Sheppo 1736d10e4ef2Snarayan /* Obtain Tx lock */ 1737d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 1738d10e4ef2Snarayan 17391ae08745Sheppo /* 1740d10e4ef2Snarayan * Read the current Tx head and tail 17411ae08745Sheppo */ 17421ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 17431ae08745Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 17441ae08745Sheppo if (rv != 0) { 17451ae08745Sheppo cmn_err(CE_WARN, 17461ae08745Sheppo "i_ldc_process_data_ACK: (0x%lx) cannot read qptrs\n", 17471ae08745Sheppo ldcp->id); 1748d10e4ef2Snarayan 1749d10e4ef2Snarayan /* Reset the channel -- as we cannot continue */ 17503af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1751d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 1752d10e4ef2Snarayan return (ECONNRESET); 17531ae08745Sheppo } 17541ae08745Sheppo 17551ae08745Sheppo /* 17561ae08745Sheppo * loop from where the previous ACK location was to the 17571ae08745Sheppo * current head location. This is how far the HV has 17581ae08745Sheppo * actually send pkts. Pkts between head and tail are 17591ae08745Sheppo * yet to be sent by HV. 17601ae08745Sheppo */ 17611ae08745Sheppo tx_head = ldcp->tx_ackd_head; 17621ae08745Sheppo for (;;) { 17631ae08745Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_head); 17641ae08745Sheppo tx_head = (tx_head + LDC_PACKET_SIZE) % 17651ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 17661ae08745Sheppo 17671ae08745Sheppo if (pkt->seqid == msg->ackid) { 17681ae08745Sheppo D2(ldcp->id, 17691ae08745Sheppo "i_ldc_process_data_ACK: (0x%llx) found packet\n", 17701ae08745Sheppo ldcp->id); 17711ae08745Sheppo ldcp->last_ack_rcd = msg->ackid; 17721ae08745Sheppo ldcp->tx_ackd_head = tx_head; 17731ae08745Sheppo break; 17741ae08745Sheppo } 17751ae08745Sheppo if (tx_head == ldcp->tx_head) { 17761ae08745Sheppo /* could not find packet */ 17771ae08745Sheppo DWARN(ldcp->id, 17781ae08745Sheppo "i_ldc_process_data_ACK: (0x%llx) invalid ACKid\n", 17791ae08745Sheppo ldcp->id); 1780d10e4ef2Snarayan 1781d10e4ef2Snarayan /* Reset the channel -- as we cannot continue */ 17823af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1783d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 1784d10e4ef2Snarayan return (ECONNRESET); 17851ae08745Sheppo } 17861ae08745Sheppo } 17871ae08745Sheppo 1788d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 17891ae08745Sheppo return (0); 17901ae08745Sheppo } 17911ae08745Sheppo 17921ae08745Sheppo /* 17931ae08745Sheppo * Process incoming control message 17941ae08745Sheppo * Return 0 - session can continue 17951ae08745Sheppo * EAGAIN - reprocess packet - state was changed 17961ae08745Sheppo * ECONNRESET - channel was reset 17971ae08745Sheppo */ 17981ae08745Sheppo static int 17991ae08745Sheppo i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *msg) 18001ae08745Sheppo { 18011ae08745Sheppo int rv = 0; 18021ae08745Sheppo 18033af08d82Slm66018 D1(ldcp->id, "i_ldc_ctrlmsg: (%llx) tstate = %lx, hstate = %lx\n", 18043af08d82Slm66018 ldcp->id, ldcp->tstate, ldcp->hstate); 18053af08d82Slm66018 18063af08d82Slm66018 switch (ldcp->tstate & ~TS_IN_RESET) { 18071ae08745Sheppo 18081ae08745Sheppo case TS_OPEN: 18091ae08745Sheppo case TS_READY: 18101ae08745Sheppo 18111ae08745Sheppo switch (msg->ctrl & LDC_CTRL_MASK) { 18121ae08745Sheppo case LDC_VER: 18131ae08745Sheppo /* process version message */ 18141ae08745Sheppo rv = i_ldc_process_VER(ldcp, msg); 18151ae08745Sheppo break; 18161ae08745Sheppo default: 18171ae08745Sheppo DWARN(ldcp->id, 18181ae08745Sheppo "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x " 18191ae08745Sheppo "tstate=0x%x\n", ldcp->id, 18201ae08745Sheppo (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate); 18211ae08745Sheppo break; 18221ae08745Sheppo } 18231ae08745Sheppo 18241ae08745Sheppo break; 18251ae08745Sheppo 18261ae08745Sheppo case TS_VREADY: 18271ae08745Sheppo 18281ae08745Sheppo switch (msg->ctrl & LDC_CTRL_MASK) { 18291ae08745Sheppo case LDC_VER: 18303af08d82Slm66018 /* process version message */ 18313af08d82Slm66018 rv = i_ldc_process_VER(ldcp, msg); 18321ae08745Sheppo break; 18331ae08745Sheppo case LDC_RTS: 18341ae08745Sheppo /* process RTS message */ 18351ae08745Sheppo rv = i_ldc_process_RTS(ldcp, msg); 18361ae08745Sheppo break; 18371ae08745Sheppo case LDC_RTR: 18381ae08745Sheppo /* process RTR message */ 18391ae08745Sheppo rv = i_ldc_process_RTR(ldcp, msg); 18401ae08745Sheppo break; 18411ae08745Sheppo case LDC_RDX: 18421ae08745Sheppo /* process RDX message */ 18431ae08745Sheppo rv = i_ldc_process_RDX(ldcp, msg); 18441ae08745Sheppo break; 18451ae08745Sheppo default: 18461ae08745Sheppo DWARN(ldcp->id, 18471ae08745Sheppo "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x " 18481ae08745Sheppo "tstate=0x%x\n", ldcp->id, 18491ae08745Sheppo (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate); 18501ae08745Sheppo break; 18511ae08745Sheppo } 18521ae08745Sheppo 18531ae08745Sheppo break; 18541ae08745Sheppo 18551ae08745Sheppo case TS_UP: 18561ae08745Sheppo 18571ae08745Sheppo switch (msg->ctrl & LDC_CTRL_MASK) { 18581ae08745Sheppo case LDC_VER: 18591ae08745Sheppo DWARN(ldcp->id, 18601ae08745Sheppo "i_ldc_ctrlmsg: (0x%llx) unexpected VER " 18611ae08745Sheppo "- LDC reset\n", ldcp->id); 18621ae08745Sheppo /* peer is redoing version negotiation */ 1863d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 18641ae08745Sheppo (void) i_ldc_txq_reconf(ldcp); 18651ae08745Sheppo i_ldc_reset_state(ldcp); 1866d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 18671ae08745Sheppo rv = EAGAIN; 18681ae08745Sheppo break; 18691ae08745Sheppo 18701ae08745Sheppo case LDC_RDX: 18711ae08745Sheppo /* process RDX message */ 18721ae08745Sheppo rv = i_ldc_process_RDX(ldcp, msg); 18731ae08745Sheppo break; 18741ae08745Sheppo 18751ae08745Sheppo default: 18761ae08745Sheppo DWARN(ldcp->id, 18771ae08745Sheppo "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x " 18781ae08745Sheppo "tstate=0x%x\n", ldcp->id, 18791ae08745Sheppo (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate); 18801ae08745Sheppo break; 18811ae08745Sheppo } 18821ae08745Sheppo } 18831ae08745Sheppo 18841ae08745Sheppo return (rv); 18851ae08745Sheppo } 18861ae08745Sheppo 18871ae08745Sheppo /* 18881ae08745Sheppo * Register channel with the channel nexus 18891ae08745Sheppo */ 18901ae08745Sheppo static int 18911ae08745Sheppo i_ldc_register_channel(ldc_chan_t *ldcp) 18921ae08745Sheppo { 18931ae08745Sheppo int rv = 0; 18941ae08745Sheppo ldc_cnex_t *cinfo = &ldcssp->cinfo; 18951ae08745Sheppo 18961ae08745Sheppo if (cinfo->dip == NULL) { 18971ae08745Sheppo DWARN(ldcp->id, 18981ae08745Sheppo "i_ldc_register_channel: cnex has not registered\n"); 18991ae08745Sheppo return (EAGAIN); 19001ae08745Sheppo } 19011ae08745Sheppo 19021ae08745Sheppo rv = cinfo->reg_chan(cinfo->dip, ldcp->id, ldcp->devclass); 19031ae08745Sheppo if (rv) { 19041ae08745Sheppo DWARN(ldcp->id, 19051ae08745Sheppo "i_ldc_register_channel: cannot register channel\n"); 19061ae08745Sheppo return (rv); 19071ae08745Sheppo } 19081ae08745Sheppo 19091ae08745Sheppo rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR, 19101ae08745Sheppo i_ldc_tx_hdlr, ldcp, NULL); 19111ae08745Sheppo if (rv) { 19121ae08745Sheppo DWARN(ldcp->id, 19131ae08745Sheppo "i_ldc_register_channel: cannot add Tx interrupt\n"); 19141ae08745Sheppo (void) cinfo->unreg_chan(cinfo->dip, ldcp->id); 19151ae08745Sheppo return (rv); 19161ae08745Sheppo } 19171ae08745Sheppo 19181ae08745Sheppo rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR, 19191ae08745Sheppo i_ldc_rx_hdlr, ldcp, NULL); 19201ae08745Sheppo if (rv) { 19211ae08745Sheppo DWARN(ldcp->id, 19221ae08745Sheppo "i_ldc_register_channel: cannot add Rx interrupt\n"); 19231ae08745Sheppo (void) cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR); 19241ae08745Sheppo (void) cinfo->unreg_chan(cinfo->dip, ldcp->id); 19251ae08745Sheppo return (rv); 19261ae08745Sheppo } 19271ae08745Sheppo 19281ae08745Sheppo ldcp->tstate |= TS_CNEX_RDY; 19291ae08745Sheppo 19301ae08745Sheppo return (0); 19311ae08745Sheppo } 19321ae08745Sheppo 19331ae08745Sheppo /* 19341ae08745Sheppo * Unregister a channel with the channel nexus 19351ae08745Sheppo */ 19361ae08745Sheppo static int 19371ae08745Sheppo i_ldc_unregister_channel(ldc_chan_t *ldcp) 19381ae08745Sheppo { 19391ae08745Sheppo int rv = 0; 19401ae08745Sheppo ldc_cnex_t *cinfo = &ldcssp->cinfo; 19411ae08745Sheppo 19421ae08745Sheppo if (cinfo->dip == NULL) { 19431ae08745Sheppo DWARN(ldcp->id, 19441ae08745Sheppo "i_ldc_unregister_channel: cnex has not registered\n"); 19451ae08745Sheppo return (EAGAIN); 19461ae08745Sheppo } 19471ae08745Sheppo 19481ae08745Sheppo if (ldcp->tstate & TS_CNEX_RDY) { 19491ae08745Sheppo 1950d10e4ef2Snarayan /* Remove the Rx interrupt */ 19511ae08745Sheppo rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR); 19521ae08745Sheppo if (rv) { 19533af08d82Slm66018 if (rv != EAGAIN) { 19541ae08745Sheppo DWARN(ldcp->id, 19553af08d82Slm66018 "i_ldc_unregister_channel: err removing " 19563af08d82Slm66018 "Rx intr\n"); 1957d10e4ef2Snarayan return (rv); 19581ae08745Sheppo } 1959d10e4ef2Snarayan 19603af08d82Slm66018 /* 19613af08d82Slm66018 * If interrupts are pending and handler has 19623af08d82Slm66018 * finished running, clear interrupt and try 19633af08d82Slm66018 * again 19643af08d82Slm66018 */ 19653af08d82Slm66018 if (ldcp->rx_intr_state != LDC_INTR_PEND) 19663af08d82Slm66018 return (rv); 19673af08d82Slm66018 19683af08d82Slm66018 (void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 19693af08d82Slm66018 rv = cinfo->rem_intr(cinfo->dip, ldcp->id, 19703af08d82Slm66018 CNEX_RX_INTR); 19713af08d82Slm66018 if (rv) { 19723af08d82Slm66018 DWARN(ldcp->id, "i_ldc_unregister_channel: " 19733af08d82Slm66018 "err removing Rx interrupt\n"); 19743af08d82Slm66018 return (rv); 19753af08d82Slm66018 } 19763af08d82Slm66018 } 19773af08d82Slm66018 1978d10e4ef2Snarayan /* Remove the Tx interrupt */ 19791ae08745Sheppo rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR); 19801ae08745Sheppo if (rv) { 19811ae08745Sheppo DWARN(ldcp->id, 19821ae08745Sheppo "i_ldc_unregister_channel: err removing Tx intr\n"); 1983d10e4ef2Snarayan return (rv); 19841ae08745Sheppo } 1985d10e4ef2Snarayan 1986d10e4ef2Snarayan /* Unregister the channel */ 19871ae08745Sheppo rv = cinfo->unreg_chan(ldcssp->cinfo.dip, ldcp->id); 19881ae08745Sheppo if (rv) { 19891ae08745Sheppo DWARN(ldcp->id, 19901ae08745Sheppo "i_ldc_unregister_channel: cannot unreg channel\n"); 1991d10e4ef2Snarayan return (rv); 19921ae08745Sheppo } 19931ae08745Sheppo 19941ae08745Sheppo ldcp->tstate &= ~TS_CNEX_RDY; 19951ae08745Sheppo } 19961ae08745Sheppo 19971ae08745Sheppo return (0); 19981ae08745Sheppo } 19991ae08745Sheppo 20001ae08745Sheppo 20011ae08745Sheppo /* 20021ae08745Sheppo * LDC transmit interrupt handler 20031ae08745Sheppo * triggered for chanel up/down/reset events 20041ae08745Sheppo * and Tx queue content changes 20051ae08745Sheppo */ 20061ae08745Sheppo static uint_t 20071ae08745Sheppo i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2) 20081ae08745Sheppo { 20091ae08745Sheppo _NOTE(ARGUNUSED(arg2)) 20101ae08745Sheppo 20111ae08745Sheppo int rv; 20121ae08745Sheppo ldc_chan_t *ldcp; 20131ae08745Sheppo boolean_t notify_client = B_FALSE; 20143af08d82Slm66018 uint64_t notify_event = 0, link_state; 20151ae08745Sheppo 20161ae08745Sheppo /* Get the channel for which interrupt was received */ 20171ae08745Sheppo ASSERT(arg1 != NULL); 20181ae08745Sheppo ldcp = (ldc_chan_t *)arg1; 20191ae08745Sheppo 20201ae08745Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n", 20211ae08745Sheppo ldcp->id, ldcp); 20221ae08745Sheppo 20231ae08745Sheppo /* Lock channel */ 20241ae08745Sheppo mutex_enter(&ldcp->lock); 20251ae08745Sheppo 2026d10e4ef2Snarayan /* Obtain Tx lock */ 2027d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 2028d10e4ef2Snarayan 20294bac2208Snarayan /* mark interrupt as pending */ 20303af08d82Slm66018 ldcp->tx_intr_state = LDC_INTR_ACTIVE; 20313af08d82Slm66018 20323af08d82Slm66018 /* save current link state */ 20333af08d82Slm66018 link_state = ldcp->link_state; 20344bac2208Snarayan 20351ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id, &ldcp->tx_head, &ldcp->tx_tail, 20361ae08745Sheppo &ldcp->link_state); 20371ae08745Sheppo if (rv) { 20381ae08745Sheppo cmn_err(CE_WARN, 20391ae08745Sheppo "i_ldc_tx_hdlr: (0x%lx) cannot read queue ptrs rv=0x%d\n", 20401ae08745Sheppo ldcp->id, rv); 20414bac2208Snarayan i_ldc_clear_intr(ldcp, CNEX_TX_INTR); 2042d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 20431ae08745Sheppo mutex_exit(&ldcp->lock); 20441ae08745Sheppo return (DDI_INTR_CLAIMED); 20451ae08745Sheppo } 20461ae08745Sheppo 20471ae08745Sheppo /* 20481ae08745Sheppo * reset the channel state if the channel went down 20491ae08745Sheppo * (other side unconfigured queue) or channel was reset 20501ae08745Sheppo * (other side reconfigured its queue) 20511ae08745Sheppo */ 20523af08d82Slm66018 if (link_state != ldcp->link_state && 20533af08d82Slm66018 ldcp->link_state == LDC_CHANNEL_DOWN) { 20541ae08745Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: channel link down\n", ldcp->id); 20553af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 20561ae08745Sheppo notify_client = B_TRUE; 20571ae08745Sheppo notify_event = LDC_EVT_DOWN; 20581ae08745Sheppo } 20591ae08745Sheppo 20603af08d82Slm66018 if (link_state != ldcp->link_state && 20613af08d82Slm66018 ldcp->link_state == LDC_CHANNEL_RESET) { 20621ae08745Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: channel link reset\n", ldcp->id); 20633af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 20641ae08745Sheppo notify_client = B_TRUE; 20651ae08745Sheppo notify_event = LDC_EVT_RESET; 20661ae08745Sheppo } 20671ae08745Sheppo 20683af08d82Slm66018 if (link_state != ldcp->link_state && 20693af08d82Slm66018 (ldcp->tstate & ~TS_IN_RESET) == TS_OPEN && 20703af08d82Slm66018 ldcp->link_state == LDC_CHANNEL_UP) { 20711ae08745Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: channel link up\n", ldcp->id); 20721ae08745Sheppo notify_client = B_TRUE; 20731ae08745Sheppo notify_event = LDC_EVT_RESET; 20741ae08745Sheppo ldcp->tstate |= TS_LINK_READY; 20751ae08745Sheppo ldcp->status = LDC_READY; 20761ae08745Sheppo } 20771ae08745Sheppo 20781ae08745Sheppo /* if callbacks are disabled, do not notify */ 20791ae08745Sheppo if (!ldcp->cb_enabled) 20801ae08745Sheppo notify_client = B_FALSE; 20811ae08745Sheppo 20824d39be2bSsg70180 i_ldc_clear_intr(ldcp, CNEX_TX_INTR); 208322f747efSnarayan mutex_exit(&ldcp->tx_lock); 20841ae08745Sheppo 20851ae08745Sheppo if (notify_client) { 20863af08d82Slm66018 ldcp->cb_inprogress = B_TRUE; 20873af08d82Slm66018 mutex_exit(&ldcp->lock); 20881ae08745Sheppo rv = ldcp->cb(notify_event, ldcp->cb_arg); 20891ae08745Sheppo if (rv) { 20901ae08745Sheppo DWARN(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) callback " 20911ae08745Sheppo "failure", ldcp->id); 20921ae08745Sheppo } 20931ae08745Sheppo mutex_enter(&ldcp->lock); 20941ae08745Sheppo ldcp->cb_inprogress = B_FALSE; 20951ae08745Sheppo } 20961ae08745Sheppo 20971ae08745Sheppo mutex_exit(&ldcp->lock); 20981ae08745Sheppo 20991ae08745Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) exiting handler", ldcp->id); 21001ae08745Sheppo 21011ae08745Sheppo return (DDI_INTR_CLAIMED); 21021ae08745Sheppo } 21031ae08745Sheppo 21041ae08745Sheppo /* 210558283286Sha137994 * Process the Rx HV queue. 210658283286Sha137994 * 210758283286Sha137994 * Returns 0 if data packets were found and no errors were encountered, 210858283286Sha137994 * otherwise returns an error. In either case, the *notify argument is 210958283286Sha137994 * set to indicate whether or not the client callback function should 211058283286Sha137994 * be invoked. The *event argument is set to contain the callback event. 211158283286Sha137994 * 211258283286Sha137994 * Depending on the channel mode, packets are handled differently: 211358283286Sha137994 * 211458283286Sha137994 * RAW MODE 211558283286Sha137994 * For raw mode channels, when a data packet is encountered, 211658283286Sha137994 * processing stops and all packets are left on the queue to be removed 211758283286Sha137994 * and processed by the ldc_read code path. 211858283286Sha137994 * 211958283286Sha137994 * UNRELIABLE MODE 212058283286Sha137994 * For unreliable mode, when a data packet is encountered, processing 212158283286Sha137994 * stops, and all packets are left on the queue to be removed and 212258283286Sha137994 * processed by the ldc_read code path. Control packets are processed 212358283286Sha137994 * inline if they are encountered before any data packets. 212458283286Sha137994 * 212520ae46ebSha137994 * RELIABLE MODE 212620ae46ebSha137994 * For reliable mode channels, all packets on the receive queue 212758283286Sha137994 * are processed: data packets are copied to the data queue and 212858283286Sha137994 * control packets are processed inline. Packets are only left on 212958283286Sha137994 * the receive queue when the data queue is full. 21301ae08745Sheppo */ 21311ae08745Sheppo static uint_t 213258283286Sha137994 i_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client, 213358283286Sha137994 uint64_t *notify_event) 21341ae08745Sheppo { 21351ae08745Sheppo int rv; 21361ae08745Sheppo uint64_t rx_head, rx_tail; 21371ae08745Sheppo ldc_msg_t *msg; 21383af08d82Slm66018 uint64_t link_state, first_fragment = 0; 213958283286Sha137994 boolean_t trace_length = B_TRUE; 21403af08d82Slm66018 214158283286Sha137994 ASSERT(MUTEX_HELD(&ldcp->lock)); 214258283286Sha137994 *notify_client = B_FALSE; 214358283286Sha137994 *notify_event = 0; 21441ae08745Sheppo 21451ae08745Sheppo /* 21461ae08745Sheppo * Read packet(s) from the queue 21471ae08745Sheppo */ 21481ae08745Sheppo for (;;) { 21491ae08745Sheppo 21503af08d82Slm66018 link_state = ldcp->link_state; 21511ae08745Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 21521ae08745Sheppo &ldcp->link_state); 21531ae08745Sheppo if (rv) { 21541ae08745Sheppo cmn_err(CE_WARN, 215558283286Sha137994 "i_ldc_rx_process_hvq: (0x%lx) cannot read " 21561ae08745Sheppo "queue ptrs, rv=0x%d\n", ldcp->id, rv); 21571ae08745Sheppo i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 215858283286Sha137994 return (EIO); 21591ae08745Sheppo } 21601ae08745Sheppo 21611ae08745Sheppo /* 21621ae08745Sheppo * reset the channel state if the channel went down 21631ae08745Sheppo * (other side unconfigured queue) or channel was reset 21643af08d82Slm66018 * (other side reconfigured its queue) 21651ae08745Sheppo */ 21663af08d82Slm66018 21673af08d82Slm66018 if (link_state != ldcp->link_state) { 2168cb112a14Slm66018 21693af08d82Slm66018 switch (ldcp->link_state) { 21703af08d82Slm66018 case LDC_CHANNEL_DOWN: 217158283286Sha137994 D1(ldcp->id, "i_ldc_rx_process_hvq: channel " 21723af08d82Slm66018 "link down\n", ldcp->id); 2173d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 21743af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 2175d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 217658283286Sha137994 *notify_client = B_TRUE; 217758283286Sha137994 *notify_event = LDC_EVT_DOWN; 21783af08d82Slm66018 goto loop_exit; 21791ae08745Sheppo 21803af08d82Slm66018 case LDC_CHANNEL_UP: 218158283286Sha137994 D1(ldcp->id, "i_ldc_rx_process_hvq: " 21823af08d82Slm66018 "channel link up\n", ldcp->id); 21833af08d82Slm66018 21843af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) == TS_OPEN) { 218558283286Sha137994 *notify_client = B_TRUE; 218658283286Sha137994 *notify_event = LDC_EVT_RESET; 21871ae08745Sheppo ldcp->tstate |= TS_LINK_READY; 21881ae08745Sheppo ldcp->status = LDC_READY; 21891ae08745Sheppo } 21903af08d82Slm66018 break; 21913af08d82Slm66018 21923af08d82Slm66018 case LDC_CHANNEL_RESET: 21933af08d82Slm66018 default: 21943af08d82Slm66018 #ifdef DEBUG 21953af08d82Slm66018 force_reset: 21963af08d82Slm66018 #endif 219758283286Sha137994 D1(ldcp->id, "i_ldc_rx_process_hvq: channel " 21983af08d82Slm66018 "link reset\n", ldcp->id); 21993af08d82Slm66018 mutex_enter(&ldcp->tx_lock); 22003af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 22013af08d82Slm66018 mutex_exit(&ldcp->tx_lock); 220258283286Sha137994 *notify_client = B_TRUE; 220358283286Sha137994 *notify_event = LDC_EVT_RESET; 22043af08d82Slm66018 break; 22053af08d82Slm66018 } 22063af08d82Slm66018 } 22073af08d82Slm66018 22083af08d82Slm66018 #ifdef DEBUG 22093af08d82Slm66018 if (LDC_INJECT_RESET(ldcp)) 22103af08d82Slm66018 goto force_reset; 22113af08d82Slm66018 #endif 221258283286Sha137994 if (trace_length) { 221358283286Sha137994 TRACE_RXHVQ_LENGTH(ldcp, rx_head, rx_tail); 221458283286Sha137994 trace_length = B_FALSE; 221558283286Sha137994 } 22161ae08745Sheppo 22171ae08745Sheppo if (rx_head == rx_tail) { 221858283286Sha137994 D2(ldcp->id, "i_ldc_rx_process_hvq: (0x%llx) " 221958283286Sha137994 "No packets\n", ldcp->id); 22201ae08745Sheppo break; 22211ae08745Sheppo } 22223af08d82Slm66018 222358283286Sha137994 D2(ldcp->id, "i_ldc_rx_process_hvq: head=0x%llx, " 222458283286Sha137994 "tail=0x%llx\n", rx_head, rx_tail); 222558283286Sha137994 DUMP_LDC_PKT(ldcp, "i_ldc_rx_process_hvq rcd", 22261ae08745Sheppo ldcp->rx_q_va + rx_head); 22271ae08745Sheppo 22281ae08745Sheppo /* get the message */ 22291ae08745Sheppo msg = (ldc_msg_t *)(ldcp->rx_q_va + rx_head); 22301ae08745Sheppo 22311ae08745Sheppo /* if channel is in RAW mode or data pkt, notify and return */ 22321ae08745Sheppo if (ldcp->mode == LDC_MODE_RAW) { 223358283286Sha137994 *notify_client = B_TRUE; 223458283286Sha137994 *notify_event |= LDC_EVT_READ; 22351ae08745Sheppo break; 22361ae08745Sheppo } 22371ae08745Sheppo 22381ae08745Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) { 22391ae08745Sheppo 22401ae08745Sheppo /* discard packet if channel is not up */ 22413af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) != TS_UP) { 22421ae08745Sheppo 22431ae08745Sheppo /* move the head one position */ 22441ae08745Sheppo rx_head = (rx_head + LDC_PACKET_SIZE) % 22451ae08745Sheppo (ldcp->rx_q_entries << LDC_PACKET_SHIFT); 22461ae08745Sheppo 22471ae08745Sheppo if (rv = i_ldc_set_rx_head(ldcp, rx_head)) 22481ae08745Sheppo break; 22491ae08745Sheppo 22501ae08745Sheppo continue; 22511ae08745Sheppo } else { 225258283286Sha137994 uint64_t dq_head, dq_tail; 225358283286Sha137994 225420ae46ebSha137994 /* process only RELIABLE mode data packets */ 225520ae46ebSha137994 if (ldcp->mode != LDC_MODE_RELIABLE) { 22563af08d82Slm66018 if ((ldcp->tstate & TS_IN_RESET) == 0) 225758283286Sha137994 *notify_client = B_TRUE; 225858283286Sha137994 *notify_event |= LDC_EVT_READ; 22591ae08745Sheppo break; 22601ae08745Sheppo } 226158283286Sha137994 226258283286Sha137994 /* don't process packet if queue full */ 226358283286Sha137994 (void) i_ldc_dq_rx_get_state(ldcp, &dq_head, 226458283286Sha137994 &dq_tail, NULL); 226558283286Sha137994 dq_tail = (dq_tail + LDC_PACKET_SIZE) % 226658283286Sha137994 (ldcp->rx_dq_entries << LDC_PACKET_SHIFT); 226758283286Sha137994 if (dq_tail == dq_head || 226858283286Sha137994 LDC_INJECT_DQFULL(ldcp)) { 226958283286Sha137994 rv = ENOSPC; 227058283286Sha137994 break; 227158283286Sha137994 } 227258283286Sha137994 } 22731ae08745Sheppo } 22741ae08745Sheppo 22751ae08745Sheppo /* Check the sequence ID for the message received */ 22763af08d82Slm66018 rv = i_ldc_check_seqid(ldcp, msg); 22773af08d82Slm66018 if (rv != 0) { 22781ae08745Sheppo 227958283286Sha137994 DWARN(ldcp->id, "i_ldc_rx_process_hvq: (0x%llx) " 228058283286Sha137994 "seqid error, q_ptrs=0x%lx,0x%lx", ldcp->id, 228158283286Sha137994 rx_head, rx_tail); 22821ae08745Sheppo 22831ae08745Sheppo /* Reset last_msg_rcd to start of message */ 2284d10e4ef2Snarayan if (first_fragment != 0) { 2285d10e4ef2Snarayan ldcp->last_msg_rcd = first_fragment - 1; 2286d10e4ef2Snarayan first_fragment = 0; 22871ae08745Sheppo } 2288d10e4ef2Snarayan 22891ae08745Sheppo /* 22901ae08745Sheppo * Send a NACK due to seqid mismatch 22911ae08745Sheppo */ 229222f747efSnarayan rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK, 22931ae08745Sheppo (msg->ctrl & LDC_CTRL_MASK)); 22941ae08745Sheppo 22951ae08745Sheppo if (rv) { 229658283286Sha137994 cmn_err(CE_NOTE, "i_ldc_rx_process_hvq: " 229758283286Sha137994 "(0x%lx) err sending CTRL/DATA NACK msg\n", 229858283286Sha137994 ldcp->id); 2299d10e4ef2Snarayan 2300d10e4ef2Snarayan /* if cannot send NACK - reset channel */ 2301d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 23023af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 2303d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 230483d3bc6fSnarayan 230558283286Sha137994 *notify_client = B_TRUE; 230658283286Sha137994 *notify_event = LDC_EVT_RESET; 2307d10e4ef2Snarayan break; 23081ae08745Sheppo } 23091ae08745Sheppo 23101ae08745Sheppo /* purge receive queue */ 23111ae08745Sheppo (void) i_ldc_set_rx_head(ldcp, rx_tail); 23121ae08745Sheppo break; 23131ae08745Sheppo } 23141ae08745Sheppo 23151ae08745Sheppo /* record the message ID */ 23161ae08745Sheppo ldcp->last_msg_rcd = msg->seqid; 23171ae08745Sheppo 23181ae08745Sheppo /* process control messages */ 23191ae08745Sheppo if (msg->type & LDC_CTRL) { 23201ae08745Sheppo /* save current internal state */ 23211ae08745Sheppo uint64_t tstate = ldcp->tstate; 23221ae08745Sheppo 23231ae08745Sheppo rv = i_ldc_ctrlmsg(ldcp, msg); 23241ae08745Sheppo if (rv == EAGAIN) { 23251ae08745Sheppo /* re-process pkt - state was adjusted */ 23261ae08745Sheppo continue; 23271ae08745Sheppo } 23281ae08745Sheppo if (rv == ECONNRESET) { 232958283286Sha137994 *notify_client = B_TRUE; 233058283286Sha137994 *notify_event = LDC_EVT_RESET; 23311ae08745Sheppo break; 23321ae08745Sheppo } 23331ae08745Sheppo 23341ae08745Sheppo /* 23351ae08745Sheppo * control message processing was successful 23361ae08745Sheppo * channel transitioned to ready for communication 23371ae08745Sheppo */ 23381ae08745Sheppo if (rv == 0 && ldcp->tstate == TS_UP && 23393af08d82Slm66018 (tstate & ~TS_IN_RESET) != 23403af08d82Slm66018 (ldcp->tstate & ~TS_IN_RESET)) { 234158283286Sha137994 *notify_client = B_TRUE; 234258283286Sha137994 *notify_event = LDC_EVT_UP; 23431ae08745Sheppo } 23441ae08745Sheppo } 23451ae08745Sheppo 234683d3bc6fSnarayan /* process data NACKs */ 234783d3bc6fSnarayan if ((msg->type & LDC_DATA) && (msg->stype & LDC_NACK)) { 234883d3bc6fSnarayan DWARN(ldcp->id, 234958283286Sha137994 "i_ldc_rx_process_hvq: (0x%llx) received DATA/NACK", 235083d3bc6fSnarayan ldcp->id); 235183d3bc6fSnarayan mutex_enter(&ldcp->tx_lock); 235283d3bc6fSnarayan i_ldc_reset(ldcp, B_TRUE); 235383d3bc6fSnarayan mutex_exit(&ldcp->tx_lock); 235458283286Sha137994 *notify_client = B_TRUE; 235558283286Sha137994 *notify_event = LDC_EVT_RESET; 235683d3bc6fSnarayan break; 235783d3bc6fSnarayan } 235883d3bc6fSnarayan 23591ae08745Sheppo /* process data ACKs */ 23601ae08745Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) { 2361d10e4ef2Snarayan if (rv = i_ldc_process_data_ACK(ldcp, msg)) { 236258283286Sha137994 *notify_client = B_TRUE; 236358283286Sha137994 *notify_event = LDC_EVT_RESET; 2364d10e4ef2Snarayan break; 2365d10e4ef2Snarayan } 23661ae08745Sheppo } 23671ae08745Sheppo 236858283286Sha137994 if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) { 236920ae46ebSha137994 ASSERT(ldcp->mode == LDC_MODE_RELIABLE); 237058283286Sha137994 237158283286Sha137994 /* 237258283286Sha137994 * Copy the data packet to the data queue. Note 237358283286Sha137994 * that the copy routine updates the rx_head pointer. 237458283286Sha137994 */ 237558283286Sha137994 i_ldc_rxdq_copy(ldcp, &rx_head); 237658283286Sha137994 237758283286Sha137994 if ((ldcp->tstate & TS_IN_RESET) == 0) 237858283286Sha137994 *notify_client = B_TRUE; 237958283286Sha137994 *notify_event |= LDC_EVT_READ; 238058283286Sha137994 } else { 23811ae08745Sheppo rx_head = (rx_head + LDC_PACKET_SIZE) % 23821ae08745Sheppo (ldcp->rx_q_entries << LDC_PACKET_SHIFT); 238358283286Sha137994 } 238458283286Sha137994 238558283286Sha137994 /* move the head one position */ 23860a55fbb7Slm66018 if (rv = i_ldc_set_rx_head(ldcp, rx_head)) { 238758283286Sha137994 *notify_client = B_TRUE; 238858283286Sha137994 *notify_event = LDC_EVT_RESET; 23891ae08745Sheppo break; 23900a55fbb7Slm66018 } 23911ae08745Sheppo 23921ae08745Sheppo } /* for */ 23931ae08745Sheppo 23943af08d82Slm66018 loop_exit: 23953af08d82Slm66018 239620ae46ebSha137994 if (ldcp->mode == LDC_MODE_RELIABLE) { 239758283286Sha137994 /* ACK data packets */ 239858283286Sha137994 if ((*notify_event & 239958283286Sha137994 (LDC_EVT_READ | LDC_EVT_RESET)) == LDC_EVT_READ) { 240058283286Sha137994 int ack_rv; 240158283286Sha137994 ack_rv = i_ldc_send_pkt(ldcp, LDC_DATA, LDC_ACK, 0); 240258283286Sha137994 if (ack_rv && ack_rv != EWOULDBLOCK) { 240358283286Sha137994 cmn_err(CE_NOTE, 240458283286Sha137994 "i_ldc_rx_process_hvq: (0x%lx) cannot " 240558283286Sha137994 "send ACK\n", ldcp->id); 240658283286Sha137994 240758283286Sha137994 mutex_enter(&ldcp->tx_lock); 240858283286Sha137994 i_ldc_reset(ldcp, B_FALSE); 240958283286Sha137994 mutex_exit(&ldcp->tx_lock); 241058283286Sha137994 241158283286Sha137994 *notify_client = B_TRUE; 241258283286Sha137994 *notify_event = LDC_EVT_RESET; 241358283286Sha137994 goto skip_ackpeek; 241458283286Sha137994 } 241558283286Sha137994 } 24161ae08745Sheppo 24173af08d82Slm66018 /* 241858283286Sha137994 * If we have no more space on the data queue, make sure 241958283286Sha137994 * there are no ACKs on the rx queue waiting to be processed. 24203af08d82Slm66018 */ 242158283286Sha137994 if (rv == ENOSPC) { 242258283286Sha137994 if (i_ldc_rx_ackpeek(ldcp, rx_head, rx_tail) != 0) { 242358283286Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID; 242458283286Sha137994 *notify_client = B_TRUE; 242558283286Sha137994 *notify_event = LDC_EVT_RESET; 24261ae08745Sheppo } 242758283286Sha137994 } else { 242858283286Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID; 242958283286Sha137994 } 24301ae08745Sheppo } 24311ae08745Sheppo 243258283286Sha137994 skip_ackpeek: 24334d39be2bSsg70180 243458283286Sha137994 /* Return, indicating whether or not data packets were found */ 243558283286Sha137994 if ((*notify_event & (LDC_EVT_READ | LDC_EVT_RESET)) == LDC_EVT_READ) 243658283286Sha137994 return (0); 243758283286Sha137994 243858283286Sha137994 return (ENOMSG); 24391ae08745Sheppo } 24401ae08745Sheppo 244158283286Sha137994 /* 244258283286Sha137994 * Process any ACK packets on the HV receive queue. 244358283286Sha137994 * 244420ae46ebSha137994 * This function is only used by RELIABLE mode channels when the 244558283286Sha137994 * secondary data queue fills up and there are packets remaining on 244658283286Sha137994 * the HV receive queue. 244758283286Sha137994 */ 244858283286Sha137994 int 244958283286Sha137994 i_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head, uint64_t rx_tail) 245058283286Sha137994 { 245158283286Sha137994 int rv = 0; 245258283286Sha137994 ldc_msg_t *msg; 245358283286Sha137994 245458283286Sha137994 if (ldcp->rx_ack_head == ACKPEEK_HEAD_INVALID) 245558283286Sha137994 ldcp->rx_ack_head = rx_head; 245658283286Sha137994 245758283286Sha137994 while (ldcp->rx_ack_head != rx_tail) { 245858283286Sha137994 msg = (ldc_msg_t *)(ldcp->rx_q_va + ldcp->rx_ack_head); 245958283286Sha137994 246058283286Sha137994 if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) { 246158283286Sha137994 if (rv = i_ldc_process_data_ACK(ldcp, msg)) 246258283286Sha137994 break; 246358283286Sha137994 msg->stype &= ~LDC_ACK; 246458283286Sha137994 } 246558283286Sha137994 246658283286Sha137994 ldcp->rx_ack_head = 246758283286Sha137994 (ldcp->rx_ack_head + LDC_PACKET_SIZE) % 246858283286Sha137994 (ldcp->rx_q_entries << LDC_PACKET_SHIFT); 246958283286Sha137994 } 247058283286Sha137994 return (rv); 247158283286Sha137994 } 24721ae08745Sheppo 24731ae08745Sheppo /* -------------------------------------------------------------------------- */ 24741ae08745Sheppo 24751ae08745Sheppo /* 24761ae08745Sheppo * LDC API functions 24771ae08745Sheppo */ 24781ae08745Sheppo 24791ae08745Sheppo /* 24801ae08745Sheppo * Initialize the channel. Allocate internal structure and memory for 24811ae08745Sheppo * TX/RX queues, and initialize locks. 24821ae08745Sheppo */ 24831ae08745Sheppo int 24841ae08745Sheppo ldc_init(uint64_t id, ldc_attr_t *attr, ldc_handle_t *handle) 24851ae08745Sheppo { 24861ae08745Sheppo ldc_chan_t *ldcp; 24871ae08745Sheppo int rv, exit_val; 24881ae08745Sheppo uint64_t ra_base, nentries; 2489e1ebb9ecSlm66018 uint64_t qlen; 24901ae08745Sheppo 24911ae08745Sheppo exit_val = EINVAL; /* guarantee an error if exit on failure */ 24921ae08745Sheppo 24931ae08745Sheppo if (attr == NULL) { 24941ae08745Sheppo DWARN(id, "ldc_init: (0x%llx) invalid attr\n", id); 24951ae08745Sheppo return (EINVAL); 24961ae08745Sheppo } 24971ae08745Sheppo if (handle == NULL) { 24981ae08745Sheppo DWARN(id, "ldc_init: (0x%llx) invalid handle\n", id); 24991ae08745Sheppo return (EINVAL); 25001ae08745Sheppo } 25011ae08745Sheppo 25021ae08745Sheppo /* check if channel is valid */ 25031ae08745Sheppo rv = hv_ldc_tx_qinfo(id, &ra_base, &nentries); 25041ae08745Sheppo if (rv == H_ECHANNEL) { 25051ae08745Sheppo DWARN(id, "ldc_init: (0x%llx) invalid channel id\n", id); 25061ae08745Sheppo return (EINVAL); 25071ae08745Sheppo } 25081ae08745Sheppo 25091ae08745Sheppo /* check if the channel has already been initialized */ 25101ae08745Sheppo mutex_enter(&ldcssp->lock); 25111ae08745Sheppo ldcp = ldcssp->chan_list; 25121ae08745Sheppo while (ldcp != NULL) { 25131ae08745Sheppo if (ldcp->id == id) { 25141ae08745Sheppo DWARN(id, "ldc_init: (0x%llx) already initialized\n", 25151ae08745Sheppo id); 25161ae08745Sheppo mutex_exit(&ldcssp->lock); 25171ae08745Sheppo return (EADDRINUSE); 25181ae08745Sheppo } 25191ae08745Sheppo ldcp = ldcp->next; 25201ae08745Sheppo } 25211ae08745Sheppo mutex_exit(&ldcssp->lock); 25221ae08745Sheppo 25231ae08745Sheppo ASSERT(ldcp == NULL); 25241ae08745Sheppo 25251ae08745Sheppo *handle = 0; 25261ae08745Sheppo 25271ae08745Sheppo /* Allocate an ldcp structure */ 25281ae08745Sheppo ldcp = kmem_zalloc(sizeof (ldc_chan_t), KM_SLEEP); 25291ae08745Sheppo 2530d10e4ef2Snarayan /* 2531d10e4ef2Snarayan * Initialize the channel and Tx lock 2532d10e4ef2Snarayan * 2533d10e4ef2Snarayan * The channel 'lock' protects the entire channel and 2534d10e4ef2Snarayan * should be acquired before initializing, resetting, 2535d10e4ef2Snarayan * destroying or reading from a channel. 2536d10e4ef2Snarayan * 2537d10e4ef2Snarayan * The 'tx_lock' should be acquired prior to transmitting 2538d10e4ef2Snarayan * data over the channel. The lock should also be acquired 2539d10e4ef2Snarayan * prior to channel reconfiguration (in order to prevent 2540d10e4ef2Snarayan * concurrent writes). 2541d10e4ef2Snarayan * 2542d10e4ef2Snarayan * ORDERING: When both locks are being acquired, to prevent 2543d10e4ef2Snarayan * deadlocks, the channel lock should be always acquired prior 2544d10e4ef2Snarayan * to the tx_lock. 2545d10e4ef2Snarayan */ 25461ae08745Sheppo mutex_init(&ldcp->lock, NULL, MUTEX_DRIVER, NULL); 2547d10e4ef2Snarayan mutex_init(&ldcp->tx_lock, NULL, MUTEX_DRIVER, NULL); 25481ae08745Sheppo 25491ae08745Sheppo /* Initialize the channel */ 25501ae08745Sheppo ldcp->id = id; 25511ae08745Sheppo ldcp->cb = NULL; 25521ae08745Sheppo ldcp->cb_arg = NULL; 25531ae08745Sheppo ldcp->cb_inprogress = B_FALSE; 25541ae08745Sheppo ldcp->cb_enabled = B_FALSE; 25551ae08745Sheppo ldcp->next = NULL; 25561ae08745Sheppo 25571ae08745Sheppo /* Read attributes */ 25581ae08745Sheppo ldcp->mode = attr->mode; 25591ae08745Sheppo ldcp->devclass = attr->devclass; 25601ae08745Sheppo ldcp->devinst = attr->instance; 2561e1ebb9ecSlm66018 ldcp->mtu = (attr->mtu > 0) ? attr->mtu : LDC_DEFAULT_MTU; 25621ae08745Sheppo 25631ae08745Sheppo D1(ldcp->id, 25641ae08745Sheppo "ldc_init: (0x%llx) channel attributes, class=0x%x, " 2565e1ebb9ecSlm66018 "instance=0x%llx, mode=%d, mtu=%d\n", 2566e1ebb9ecSlm66018 ldcp->id, ldcp->devclass, ldcp->devinst, ldcp->mode, ldcp->mtu); 25671ae08745Sheppo 25681ae08745Sheppo ldcp->next_vidx = 0; 25693af08d82Slm66018 ldcp->tstate = TS_IN_RESET; 25701ae08745Sheppo ldcp->hstate = 0; 25711ae08745Sheppo ldcp->last_msg_snt = LDC_INIT_SEQID; 25721ae08745Sheppo ldcp->last_ack_rcd = 0; 25731ae08745Sheppo ldcp->last_msg_rcd = 0; 257458283286Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID; 25751ae08745Sheppo 25761ae08745Sheppo ldcp->stream_bufferp = NULL; 25771ae08745Sheppo ldcp->exp_dring_list = NULL; 25781ae08745Sheppo ldcp->imp_dring_list = NULL; 25791ae08745Sheppo ldcp->mhdl_list = NULL; 25801ae08745Sheppo 25813af08d82Slm66018 ldcp->tx_intr_state = LDC_INTR_NONE; 25823af08d82Slm66018 ldcp->rx_intr_state = LDC_INTR_NONE; 25833af08d82Slm66018 25841ae08745Sheppo /* Initialize payload size depending on whether channel is reliable */ 25851ae08745Sheppo switch (ldcp->mode) { 25861ae08745Sheppo case LDC_MODE_RAW: 25871ae08745Sheppo ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RAW; 25881ae08745Sheppo ldcp->read_p = i_ldc_read_raw; 25891ae08745Sheppo ldcp->write_p = i_ldc_write_raw; 25901ae08745Sheppo break; 25911ae08745Sheppo case LDC_MODE_UNRELIABLE: 25921ae08745Sheppo ldcp->pkt_payload = LDC_PAYLOAD_SIZE_UNRELIABLE; 25931ae08745Sheppo ldcp->read_p = i_ldc_read_packet; 25941ae08745Sheppo ldcp->write_p = i_ldc_write_packet; 25951ae08745Sheppo break; 25961ae08745Sheppo case LDC_MODE_RELIABLE: 25971ae08745Sheppo ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RELIABLE; 25981ae08745Sheppo 25991ae08745Sheppo ldcp->stream_remains = 0; 26001ae08745Sheppo ldcp->stream_offset = 0; 26011ae08745Sheppo ldcp->stream_bufferp = kmem_alloc(ldcp->mtu, KM_SLEEP); 26021ae08745Sheppo ldcp->read_p = i_ldc_read_stream; 26031ae08745Sheppo ldcp->write_p = i_ldc_write_stream; 26041ae08745Sheppo break; 26051ae08745Sheppo default: 26061ae08745Sheppo exit_val = EINVAL; 26071ae08745Sheppo goto cleanup_on_exit; 26081ae08745Sheppo } 26091ae08745Sheppo 2610e1ebb9ecSlm66018 /* 2611e1ebb9ecSlm66018 * qlen is (mtu * ldc_mtu_msgs) / pkt_payload. If this 2612e1ebb9ecSlm66018 * value is smaller than default length of ldc_queue_entries, 261322f747efSnarayan * qlen is set to ldc_queue_entries. Ensure that computed 261422f747efSnarayan * length is a power-of-two value. 2615e1ebb9ecSlm66018 */ 2616e1ebb9ecSlm66018 qlen = (ldcp->mtu * ldc_mtu_msgs) / ldcp->pkt_payload; 261722f747efSnarayan if (!ISP2(qlen)) { 261822f747efSnarayan uint64_t tmp = 1; 261922f747efSnarayan while (qlen) { 262022f747efSnarayan qlen >>= 1; tmp <<= 1; 262122f747efSnarayan } 262222f747efSnarayan qlen = tmp; 262322f747efSnarayan } 262422f747efSnarayan 2625e1ebb9ecSlm66018 ldcp->rx_q_entries = 2626e1ebb9ecSlm66018 (qlen < ldc_queue_entries) ? ldc_queue_entries : qlen; 2627e1ebb9ecSlm66018 ldcp->tx_q_entries = ldcp->rx_q_entries; 2628e1ebb9ecSlm66018 262922f747efSnarayan D1(ldcp->id, "ldc_init: queue length = 0x%llx\n", ldcp->rx_q_entries); 2630e1ebb9ecSlm66018 26311ae08745Sheppo /* Create a transmit queue */ 26321ae08745Sheppo ldcp->tx_q_va = (uint64_t) 26331ae08745Sheppo contig_mem_alloc(ldcp->tx_q_entries << LDC_PACKET_SHIFT); 26341ae08745Sheppo if (ldcp->tx_q_va == NULL) { 26351ae08745Sheppo cmn_err(CE_WARN, 26361ae08745Sheppo "ldc_init: (0x%lx) TX queue allocation failed\n", 26371ae08745Sheppo ldcp->id); 26381ae08745Sheppo exit_val = ENOMEM; 26391ae08745Sheppo goto cleanup_on_exit; 26401ae08745Sheppo } 26411ae08745Sheppo ldcp->tx_q_ra = va_to_pa((caddr_t)ldcp->tx_q_va); 26421ae08745Sheppo 26431ae08745Sheppo D2(ldcp->id, "ldc_init: txq_va=0x%llx, txq_ra=0x%llx, entries=0x%llx\n", 26441ae08745Sheppo ldcp->tx_q_va, ldcp->tx_q_ra, ldcp->tx_q_entries); 26451ae08745Sheppo 26461ae08745Sheppo ldcp->tstate |= TS_TXQ_RDY; 26471ae08745Sheppo 26481ae08745Sheppo /* Create a receive queue */ 26491ae08745Sheppo ldcp->rx_q_va = (uint64_t) 26501ae08745Sheppo contig_mem_alloc(ldcp->rx_q_entries << LDC_PACKET_SHIFT); 26511ae08745Sheppo if (ldcp->rx_q_va == NULL) { 26521ae08745Sheppo cmn_err(CE_WARN, 26531ae08745Sheppo "ldc_init: (0x%lx) RX queue allocation failed\n", 26541ae08745Sheppo ldcp->id); 26551ae08745Sheppo exit_val = ENOMEM; 26561ae08745Sheppo goto cleanup_on_exit; 26571ae08745Sheppo } 26581ae08745Sheppo ldcp->rx_q_ra = va_to_pa((caddr_t)ldcp->rx_q_va); 26591ae08745Sheppo 26601ae08745Sheppo D2(ldcp->id, "ldc_init: rxq_va=0x%llx, rxq_ra=0x%llx, entries=0x%llx\n", 26611ae08745Sheppo ldcp->rx_q_va, ldcp->rx_q_ra, ldcp->rx_q_entries); 26621ae08745Sheppo 26631ae08745Sheppo ldcp->tstate |= TS_RXQ_RDY; 26641ae08745Sheppo 266558283286Sha137994 /* Setup a separate read data queue */ 266620ae46ebSha137994 if (ldcp->mode == LDC_MODE_RELIABLE) { 266758283286Sha137994 ldcp->readq_get_state = i_ldc_dq_rx_get_state; 266858283286Sha137994 ldcp->readq_set_head = i_ldc_set_rxdq_head; 266958283286Sha137994 267058283286Sha137994 /* Make sure the data queue multiplier is a power of 2 */ 267158283286Sha137994 if (!ISP2(ldc_rxdq_multiplier)) { 267258283286Sha137994 D1(ldcp->id, "ldc_init: (0x%llx) ldc_rxdq_multiplier " 267358283286Sha137994 "not a power of 2, resetting", ldcp->id); 267458283286Sha137994 ldc_rxdq_multiplier = LDC_RXDQ_MULTIPLIER; 267558283286Sha137994 } 267658283286Sha137994 267758283286Sha137994 ldcp->rx_dq_entries = ldc_rxdq_multiplier * ldcp->rx_q_entries; 267858283286Sha137994 ldcp->rx_dq_va = (uint64_t) 267958283286Sha137994 kmem_alloc(ldcp->rx_dq_entries << LDC_PACKET_SHIFT, 268058283286Sha137994 KM_SLEEP); 268158283286Sha137994 if (ldcp->rx_dq_va == NULL) { 268258283286Sha137994 cmn_err(CE_WARN, 268358283286Sha137994 "ldc_init: (0x%lx) RX data queue " 268458283286Sha137994 "allocation failed\n", ldcp->id); 268558283286Sha137994 exit_val = ENOMEM; 268658283286Sha137994 goto cleanup_on_exit; 268758283286Sha137994 } 268858283286Sha137994 268958283286Sha137994 ldcp->rx_dq_head = ldcp->rx_dq_tail = 0; 269058283286Sha137994 269158283286Sha137994 D2(ldcp->id, "ldc_init: rx_dq_va=0x%llx, " 269258283286Sha137994 "rx_dq_entries=0x%llx\n", ldcp->rx_dq_va, 269358283286Sha137994 ldcp->rx_dq_entries); 269458283286Sha137994 } else { 269558283286Sha137994 ldcp->readq_get_state = i_ldc_hvq_rx_get_state; 269658283286Sha137994 ldcp->readq_set_head = i_ldc_set_rx_head; 269758283286Sha137994 } 269858283286Sha137994 26991ae08745Sheppo /* Init descriptor ring and memory handle list lock */ 27001ae08745Sheppo mutex_init(&ldcp->exp_dlist_lock, NULL, MUTEX_DRIVER, NULL); 27011ae08745Sheppo mutex_init(&ldcp->imp_dlist_lock, NULL, MUTEX_DRIVER, NULL); 27021ae08745Sheppo mutex_init(&ldcp->mlist_lock, NULL, MUTEX_DRIVER, NULL); 27031ae08745Sheppo 27041ae08745Sheppo /* mark status as INITialized */ 27051ae08745Sheppo ldcp->status = LDC_INIT; 27061ae08745Sheppo 27071ae08745Sheppo /* Add to channel list */ 27081ae08745Sheppo mutex_enter(&ldcssp->lock); 27091ae08745Sheppo ldcp->next = ldcssp->chan_list; 27101ae08745Sheppo ldcssp->chan_list = ldcp; 27111ae08745Sheppo ldcssp->channel_count++; 27121ae08745Sheppo mutex_exit(&ldcssp->lock); 27131ae08745Sheppo 27141ae08745Sheppo /* set the handle */ 27151ae08745Sheppo *handle = (ldc_handle_t)ldcp; 27161ae08745Sheppo 27171ae08745Sheppo D1(ldcp->id, "ldc_init: (0x%llx) channel initialized\n", ldcp->id); 27181ae08745Sheppo 27191ae08745Sheppo return (0); 27201ae08745Sheppo 27211ae08745Sheppo cleanup_on_exit: 27221ae08745Sheppo 272320ae46ebSha137994 if (ldcp->mode == LDC_MODE_RELIABLE && ldcp->stream_bufferp) 27241ae08745Sheppo kmem_free(ldcp->stream_bufferp, ldcp->mtu); 27251ae08745Sheppo 27261ae08745Sheppo if (ldcp->tstate & TS_TXQ_RDY) 27271ae08745Sheppo contig_mem_free((caddr_t)ldcp->tx_q_va, 27281ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT)); 27291ae08745Sheppo 27301ae08745Sheppo if (ldcp->tstate & TS_RXQ_RDY) 27311ae08745Sheppo contig_mem_free((caddr_t)ldcp->rx_q_va, 27321ae08745Sheppo (ldcp->rx_q_entries << LDC_PACKET_SHIFT)); 27331ae08745Sheppo 2734d10e4ef2Snarayan mutex_destroy(&ldcp->tx_lock); 27351ae08745Sheppo mutex_destroy(&ldcp->lock); 27361ae08745Sheppo 27371ae08745Sheppo if (ldcp) 27381ae08745Sheppo kmem_free(ldcp, sizeof (ldc_chan_t)); 27391ae08745Sheppo 27401ae08745Sheppo return (exit_val); 27411ae08745Sheppo } 27421ae08745Sheppo 27431ae08745Sheppo /* 27441ae08745Sheppo * Finalizes the LDC connection. It will return EBUSY if the 27451ae08745Sheppo * channel is open. A ldc_close() has to be done prior to 27461ae08745Sheppo * a ldc_fini operation. It frees TX/RX queues, associated 27471ae08745Sheppo * with the channel 27481ae08745Sheppo */ 27491ae08745Sheppo int 27501ae08745Sheppo ldc_fini(ldc_handle_t handle) 27511ae08745Sheppo { 27521ae08745Sheppo ldc_chan_t *ldcp; 27531ae08745Sheppo ldc_chan_t *tmp_ldcp; 27541ae08745Sheppo uint64_t id; 27551ae08745Sheppo 27561ae08745Sheppo if (handle == NULL) { 27571ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel handle\n"); 27581ae08745Sheppo return (EINVAL); 27591ae08745Sheppo } 27601ae08745Sheppo ldcp = (ldc_chan_t *)handle; 27611ae08745Sheppo id = ldcp->id; 27621ae08745Sheppo 27631ae08745Sheppo mutex_enter(&ldcp->lock); 27641ae08745Sheppo 27653af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) > TS_INIT) { 27661ae08745Sheppo DWARN(ldcp->id, "ldc_fini: (0x%llx) channel is open\n", 27671ae08745Sheppo ldcp->id); 27681ae08745Sheppo mutex_exit(&ldcp->lock); 27691ae08745Sheppo return (EBUSY); 27701ae08745Sheppo } 27711ae08745Sheppo 27721ae08745Sheppo /* Remove from the channel list */ 27731ae08745Sheppo mutex_enter(&ldcssp->lock); 27741ae08745Sheppo tmp_ldcp = ldcssp->chan_list; 27751ae08745Sheppo if (tmp_ldcp == ldcp) { 27761ae08745Sheppo ldcssp->chan_list = ldcp->next; 27771ae08745Sheppo ldcp->next = NULL; 27781ae08745Sheppo } else { 27791ae08745Sheppo while (tmp_ldcp != NULL) { 27801ae08745Sheppo if (tmp_ldcp->next == ldcp) { 27811ae08745Sheppo tmp_ldcp->next = ldcp->next; 27821ae08745Sheppo ldcp->next = NULL; 27831ae08745Sheppo break; 27841ae08745Sheppo } 27851ae08745Sheppo tmp_ldcp = tmp_ldcp->next; 27861ae08745Sheppo } 27871ae08745Sheppo if (tmp_ldcp == NULL) { 27881ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel hdl\n"); 27891ae08745Sheppo mutex_exit(&ldcssp->lock); 27901ae08745Sheppo mutex_exit(&ldcp->lock); 27911ae08745Sheppo return (EINVAL); 27921ae08745Sheppo } 27931ae08745Sheppo } 27941ae08745Sheppo 27951ae08745Sheppo ldcssp->channel_count--; 27961ae08745Sheppo 27971ae08745Sheppo mutex_exit(&ldcssp->lock); 27981ae08745Sheppo 27991ae08745Sheppo /* Free the map table for this channel */ 28001ae08745Sheppo if (ldcp->mtbl) { 28011ae08745Sheppo (void) hv_ldc_set_map_table(ldcp->id, NULL, NULL); 28023af08d82Slm66018 if (ldcp->mtbl->contigmem) 28031ae08745Sheppo contig_mem_free(ldcp->mtbl->table, ldcp->mtbl->size); 28043af08d82Slm66018 else 28053af08d82Slm66018 kmem_free(ldcp->mtbl->table, ldcp->mtbl->size); 28061ae08745Sheppo mutex_destroy(&ldcp->mtbl->lock); 28071ae08745Sheppo kmem_free(ldcp->mtbl, sizeof (ldc_mtbl_t)); 28081ae08745Sheppo } 28091ae08745Sheppo 28101ae08745Sheppo /* Destroy descriptor ring and memory handle list lock */ 28111ae08745Sheppo mutex_destroy(&ldcp->exp_dlist_lock); 28121ae08745Sheppo mutex_destroy(&ldcp->imp_dlist_lock); 28131ae08745Sheppo mutex_destroy(&ldcp->mlist_lock); 28141ae08745Sheppo 281520ae46ebSha137994 /* Free the stream buffer for RELIABLE_MODE */ 281620ae46ebSha137994 if (ldcp->mode == LDC_MODE_RELIABLE && ldcp->stream_bufferp) 28171ae08745Sheppo kmem_free(ldcp->stream_bufferp, ldcp->mtu); 28181ae08745Sheppo 28191ae08745Sheppo /* Free the RX queue */ 28201ae08745Sheppo contig_mem_free((caddr_t)ldcp->rx_q_va, 28211ae08745Sheppo (ldcp->rx_q_entries << LDC_PACKET_SHIFT)); 28221ae08745Sheppo ldcp->tstate &= ~TS_RXQ_RDY; 28231ae08745Sheppo 282458283286Sha137994 /* Free the RX data queue */ 282520ae46ebSha137994 if (ldcp->mode == LDC_MODE_RELIABLE) { 282658283286Sha137994 kmem_free((caddr_t)ldcp->rx_dq_va, 282758283286Sha137994 (ldcp->rx_dq_entries << LDC_PACKET_SHIFT)); 282858283286Sha137994 } 282958283286Sha137994 28301ae08745Sheppo /* Free the TX queue */ 28311ae08745Sheppo contig_mem_free((caddr_t)ldcp->tx_q_va, 28321ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT)); 28331ae08745Sheppo ldcp->tstate &= ~TS_TXQ_RDY; 28341ae08745Sheppo 28351ae08745Sheppo mutex_exit(&ldcp->lock); 28361ae08745Sheppo 28371ae08745Sheppo /* Destroy mutex */ 2838d10e4ef2Snarayan mutex_destroy(&ldcp->tx_lock); 28391ae08745Sheppo mutex_destroy(&ldcp->lock); 28401ae08745Sheppo 28411ae08745Sheppo /* free channel structure */ 28421ae08745Sheppo kmem_free(ldcp, sizeof (ldc_chan_t)); 28431ae08745Sheppo 28441ae08745Sheppo D1(id, "ldc_fini: (0x%llx) channel finalized\n", id); 28451ae08745Sheppo 28461ae08745Sheppo return (0); 28471ae08745Sheppo } 28481ae08745Sheppo 28491ae08745Sheppo /* 28501ae08745Sheppo * Open the LDC channel for use. It registers the TX/RX queues 28511ae08745Sheppo * with the Hypervisor. It also specifies the interrupt number 28521ae08745Sheppo * and target CPU for this channel 28531ae08745Sheppo */ 28541ae08745Sheppo int 28551ae08745Sheppo ldc_open(ldc_handle_t handle) 28561ae08745Sheppo { 28571ae08745Sheppo ldc_chan_t *ldcp; 28581ae08745Sheppo int rv; 28591ae08745Sheppo 28601ae08745Sheppo if (handle == NULL) { 28611ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_open: invalid channel handle\n"); 28621ae08745Sheppo return (EINVAL); 28631ae08745Sheppo } 28641ae08745Sheppo 28651ae08745Sheppo ldcp = (ldc_chan_t *)handle; 28661ae08745Sheppo 28671ae08745Sheppo mutex_enter(&ldcp->lock); 28681ae08745Sheppo 28691ae08745Sheppo if (ldcp->tstate < TS_INIT) { 28701ae08745Sheppo DWARN(ldcp->id, 28711ae08745Sheppo "ldc_open: (0x%llx) channel not initialized\n", ldcp->id); 28721ae08745Sheppo mutex_exit(&ldcp->lock); 28731ae08745Sheppo return (EFAULT); 28741ae08745Sheppo } 28753af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) >= TS_OPEN) { 28761ae08745Sheppo DWARN(ldcp->id, 28771ae08745Sheppo "ldc_open: (0x%llx) channel is already open\n", ldcp->id); 28781ae08745Sheppo mutex_exit(&ldcp->lock); 28791ae08745Sheppo return (EFAULT); 28801ae08745Sheppo } 28811ae08745Sheppo 28821ae08745Sheppo /* 28831ae08745Sheppo * Unregister/Register the tx queue with the hypervisor 28841ae08745Sheppo */ 28851ae08745Sheppo rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 28861ae08745Sheppo if (rv) { 28871ae08745Sheppo cmn_err(CE_WARN, 28881ae08745Sheppo "ldc_open: (0x%lx) channel tx queue unconf failed\n", 28891ae08745Sheppo ldcp->id); 28901ae08745Sheppo mutex_exit(&ldcp->lock); 28911ae08745Sheppo return (EIO); 28921ae08745Sheppo } 28931ae08745Sheppo 28941ae08745Sheppo rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries); 28951ae08745Sheppo if (rv) { 28961ae08745Sheppo cmn_err(CE_WARN, 28971ae08745Sheppo "ldc_open: (0x%lx) channel tx queue conf failed\n", 28981ae08745Sheppo ldcp->id); 28991ae08745Sheppo mutex_exit(&ldcp->lock); 29001ae08745Sheppo return (EIO); 29011ae08745Sheppo } 29021ae08745Sheppo 29031ae08745Sheppo D2(ldcp->id, "ldc_open: (0x%llx) registered tx queue with LDC\n", 29041ae08745Sheppo ldcp->id); 29051ae08745Sheppo 29061ae08745Sheppo /* 29071ae08745Sheppo * Unregister/Register the rx queue with the hypervisor 29081ae08745Sheppo */ 29091ae08745Sheppo rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 29101ae08745Sheppo if (rv) { 29111ae08745Sheppo cmn_err(CE_WARN, 29121ae08745Sheppo "ldc_open: (0x%lx) channel rx queue unconf failed\n", 29131ae08745Sheppo ldcp->id); 29141ae08745Sheppo mutex_exit(&ldcp->lock); 29151ae08745Sheppo return (EIO); 29161ae08745Sheppo } 29171ae08745Sheppo 29181ae08745Sheppo rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra, ldcp->rx_q_entries); 29191ae08745Sheppo if (rv) { 29201ae08745Sheppo cmn_err(CE_WARN, 29211ae08745Sheppo "ldc_open: (0x%lx) channel rx queue conf failed\n", 29221ae08745Sheppo ldcp->id); 29231ae08745Sheppo mutex_exit(&ldcp->lock); 29241ae08745Sheppo return (EIO); 29251ae08745Sheppo } 29261ae08745Sheppo 29271ae08745Sheppo D2(ldcp->id, "ldc_open: (0x%llx) registered rx queue with LDC\n", 29281ae08745Sheppo ldcp->id); 29291ae08745Sheppo 29301ae08745Sheppo ldcp->tstate |= TS_QCONF_RDY; 29311ae08745Sheppo 29321ae08745Sheppo /* Register the channel with the channel nexus */ 29331ae08745Sheppo rv = i_ldc_register_channel(ldcp); 29341ae08745Sheppo if (rv && rv != EAGAIN) { 29351ae08745Sheppo cmn_err(CE_WARN, 29361ae08745Sheppo "ldc_open: (0x%lx) channel register failed\n", ldcp->id); 29371ae08745Sheppo (void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 29381ae08745Sheppo (void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 29391ae08745Sheppo mutex_exit(&ldcp->lock); 29401ae08745Sheppo return (EIO); 29411ae08745Sheppo } 29421ae08745Sheppo 29431ae08745Sheppo /* mark channel in OPEN state */ 29441ae08745Sheppo ldcp->status = LDC_OPEN; 29451ae08745Sheppo 29461ae08745Sheppo /* Read channel state */ 29471ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 29481ae08745Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 29491ae08745Sheppo if (rv) { 29501ae08745Sheppo cmn_err(CE_WARN, 29511ae08745Sheppo "ldc_open: (0x%lx) cannot read channel state\n", 29521ae08745Sheppo ldcp->id); 29531ae08745Sheppo (void) i_ldc_unregister_channel(ldcp); 29541ae08745Sheppo (void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 29551ae08745Sheppo (void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 29561ae08745Sheppo mutex_exit(&ldcp->lock); 29571ae08745Sheppo return (EIO); 29581ae08745Sheppo } 29591ae08745Sheppo 29601ae08745Sheppo /* 296120ae46ebSha137994 * set the ACKd head to current head location for reliable 29621ae08745Sheppo */ 29631ae08745Sheppo ldcp->tx_ackd_head = ldcp->tx_head; 29641ae08745Sheppo 29651ae08745Sheppo /* mark channel ready if HV report link is UP (peer alloc'd Rx queue) */ 29661ae08745Sheppo if (ldcp->link_state == LDC_CHANNEL_UP || 29671ae08745Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 29681ae08745Sheppo ldcp->tstate |= TS_LINK_READY; 29691ae08745Sheppo ldcp->status = LDC_READY; 29701ae08745Sheppo } 29711ae08745Sheppo 29721ae08745Sheppo /* 29731ae08745Sheppo * if channel is being opened in RAW mode - no handshake is needed 29741ae08745Sheppo * switch the channel READY and UP state 29751ae08745Sheppo */ 29761ae08745Sheppo if (ldcp->mode == LDC_MODE_RAW) { 29771ae08745Sheppo ldcp->tstate = TS_UP; /* set bits associated with LDC UP */ 29781ae08745Sheppo ldcp->status = LDC_UP; 29791ae08745Sheppo } 29801ae08745Sheppo 29811ae08745Sheppo mutex_exit(&ldcp->lock); 29821ae08745Sheppo 29831ae08745Sheppo /* 29841ae08745Sheppo * Increment number of open channels 29851ae08745Sheppo */ 29861ae08745Sheppo mutex_enter(&ldcssp->lock); 29871ae08745Sheppo ldcssp->channels_open++; 29881ae08745Sheppo mutex_exit(&ldcssp->lock); 29891ae08745Sheppo 2990cb112a14Slm66018 D1(ldcp->id, 29913af08d82Slm66018 "ldc_open: (0x%llx) channel (0x%p) open for use " 29923af08d82Slm66018 "(tstate=0x%x, status=0x%x)\n", 29933af08d82Slm66018 ldcp->id, ldcp, ldcp->tstate, ldcp->status); 29941ae08745Sheppo 29951ae08745Sheppo return (0); 29961ae08745Sheppo } 29971ae08745Sheppo 29981ae08745Sheppo /* 29991ae08745Sheppo * Close the LDC connection. It will return EBUSY if there 30001ae08745Sheppo * are memory segments or descriptor rings either bound to or 30011ae08745Sheppo * mapped over the channel 30021ae08745Sheppo */ 30031ae08745Sheppo int 30041ae08745Sheppo ldc_close(ldc_handle_t handle) 30051ae08745Sheppo { 30061ae08745Sheppo ldc_chan_t *ldcp; 3007d10e4ef2Snarayan int rv = 0, retries = 0; 30081ae08745Sheppo boolean_t chk_done = B_FALSE; 30091ae08745Sheppo 30101ae08745Sheppo if (handle == NULL) { 30111ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_close: invalid channel handle\n"); 30121ae08745Sheppo return (EINVAL); 30131ae08745Sheppo } 30141ae08745Sheppo ldcp = (ldc_chan_t *)handle; 30151ae08745Sheppo 30161ae08745Sheppo mutex_enter(&ldcp->lock); 30171ae08745Sheppo 30181ae08745Sheppo /* return error if channel is not open */ 30193af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) < TS_OPEN) { 30201ae08745Sheppo DWARN(ldcp->id, 30211ae08745Sheppo "ldc_close: (0x%llx) channel is not open\n", ldcp->id); 30221ae08745Sheppo mutex_exit(&ldcp->lock); 30231ae08745Sheppo return (EFAULT); 30241ae08745Sheppo } 30251ae08745Sheppo 30261ae08745Sheppo /* if any memory handles, drings, are bound or mapped cannot close */ 30271ae08745Sheppo if (ldcp->mhdl_list != NULL) { 30281ae08745Sheppo DWARN(ldcp->id, 30291ae08745Sheppo "ldc_close: (0x%llx) channel has bound memory handles\n", 30301ae08745Sheppo ldcp->id); 30311ae08745Sheppo mutex_exit(&ldcp->lock); 30321ae08745Sheppo return (EBUSY); 30331ae08745Sheppo } 30341ae08745Sheppo if (ldcp->exp_dring_list != NULL) { 30351ae08745Sheppo DWARN(ldcp->id, 30361ae08745Sheppo "ldc_close: (0x%llx) channel has bound descriptor rings\n", 30371ae08745Sheppo ldcp->id); 30381ae08745Sheppo mutex_exit(&ldcp->lock); 30391ae08745Sheppo return (EBUSY); 30401ae08745Sheppo } 30411ae08745Sheppo if (ldcp->imp_dring_list != NULL) { 30421ae08745Sheppo DWARN(ldcp->id, 30431ae08745Sheppo "ldc_close: (0x%llx) channel has mapped descriptor rings\n", 30441ae08745Sheppo ldcp->id); 30451ae08745Sheppo mutex_exit(&ldcp->lock); 30461ae08745Sheppo return (EBUSY); 30471ae08745Sheppo } 30481ae08745Sheppo 30494d39be2bSsg70180 if (ldcp->cb_inprogress) { 30504d39be2bSsg70180 DWARN(ldcp->id, "ldc_close: (0x%llx) callback active\n", 30514d39be2bSsg70180 ldcp->id); 30524d39be2bSsg70180 mutex_exit(&ldcp->lock); 30534d39be2bSsg70180 return (EWOULDBLOCK); 30544d39be2bSsg70180 } 30554d39be2bSsg70180 3056d10e4ef2Snarayan /* Obtain Tx lock */ 3057d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 3058d10e4ef2Snarayan 30591ae08745Sheppo /* 30601ae08745Sheppo * Wait for pending transmits to complete i.e Tx queue to drain 30611ae08745Sheppo * if there are pending pkts - wait 1 ms and retry again 30621ae08745Sheppo */ 30631ae08745Sheppo for (;;) { 30641ae08745Sheppo 30651ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 30661ae08745Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 30671ae08745Sheppo if (rv) { 30681ae08745Sheppo cmn_err(CE_WARN, 30691ae08745Sheppo "ldc_close: (0x%lx) cannot read qptrs\n", ldcp->id); 3070d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 30711ae08745Sheppo mutex_exit(&ldcp->lock); 30721ae08745Sheppo return (EIO); 30731ae08745Sheppo } 30741ae08745Sheppo 30751ae08745Sheppo if (ldcp->tx_head == ldcp->tx_tail || 30761ae08745Sheppo ldcp->link_state != LDC_CHANNEL_UP) { 30771ae08745Sheppo break; 30781ae08745Sheppo } 30791ae08745Sheppo 30801ae08745Sheppo if (chk_done) { 30811ae08745Sheppo DWARN(ldcp->id, 30821ae08745Sheppo "ldc_close: (0x%llx) Tx queue drain timeout\n", 30831ae08745Sheppo ldcp->id); 30841ae08745Sheppo break; 30851ae08745Sheppo } 30861ae08745Sheppo 30871ae08745Sheppo /* wait for one ms and try again */ 30881ae08745Sheppo delay(drv_usectohz(1000)); 30891ae08745Sheppo chk_done = B_TRUE; 30901ae08745Sheppo } 30911ae08745Sheppo 30921ae08745Sheppo /* 3093a8ea4edeSnarayan * Drain the Tx and Rx queues as we are closing the 3094a8ea4edeSnarayan * channel. We dont care about any pending packets. 3095a8ea4edeSnarayan * We have to also drain the queue prior to clearing 3096a8ea4edeSnarayan * pending interrupts, otherwise the HV will trigger 3097a8ea4edeSnarayan * an interrupt the moment the interrupt state is 3098a8ea4edeSnarayan * cleared. 30993af08d82Slm66018 */ 31003af08d82Slm66018 (void) i_ldc_txq_reconf(ldcp); 3101a8ea4edeSnarayan (void) i_ldc_rxq_drain(ldcp); 31023af08d82Slm66018 31033af08d82Slm66018 /* 31041ae08745Sheppo * Unregister the channel with the nexus 31051ae08745Sheppo */ 3106d10e4ef2Snarayan while ((rv = i_ldc_unregister_channel(ldcp)) != 0) { 3107d10e4ef2Snarayan 3108d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 31091ae08745Sheppo mutex_exit(&ldcp->lock); 3110d10e4ef2Snarayan 3111d10e4ef2Snarayan /* if any error other than EAGAIN return back */ 3112a8ea4edeSnarayan if (rv != EAGAIN || retries >= ldc_max_retries) { 3113d10e4ef2Snarayan cmn_err(CE_WARN, 3114d10e4ef2Snarayan "ldc_close: (0x%lx) unregister failed, %d\n", 3115d10e4ef2Snarayan ldcp->id, rv); 31161ae08745Sheppo return (rv); 31171ae08745Sheppo } 31181ae08745Sheppo 31191ae08745Sheppo /* 3120d10e4ef2Snarayan * As there could be pending interrupts we need 3121d10e4ef2Snarayan * to wait and try again 3122d10e4ef2Snarayan */ 31234d39be2bSsg70180 drv_usecwait(ldc_close_delay); 3124d10e4ef2Snarayan mutex_enter(&ldcp->lock); 3125d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 3126d10e4ef2Snarayan retries++; 3127d10e4ef2Snarayan } 3128d10e4ef2Snarayan 3129d10e4ef2Snarayan /* 31301ae08745Sheppo * Unregister queues 31311ae08745Sheppo */ 31321ae08745Sheppo rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 31331ae08745Sheppo if (rv) { 31341ae08745Sheppo cmn_err(CE_WARN, 31351ae08745Sheppo "ldc_close: (0x%lx) channel TX queue unconf failed\n", 31361ae08745Sheppo ldcp->id); 3137d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 31381ae08745Sheppo mutex_exit(&ldcp->lock); 31391ae08745Sheppo return (EIO); 31401ae08745Sheppo } 31411ae08745Sheppo rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 31421ae08745Sheppo if (rv) { 31431ae08745Sheppo cmn_err(CE_WARN, 31441ae08745Sheppo "ldc_close: (0x%lx) channel RX queue unconf failed\n", 31451ae08745Sheppo ldcp->id); 3146d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 31471ae08745Sheppo mutex_exit(&ldcp->lock); 31481ae08745Sheppo return (EIO); 31491ae08745Sheppo } 31501ae08745Sheppo 31511ae08745Sheppo ldcp->tstate &= ~TS_QCONF_RDY; 31521ae08745Sheppo 31531ae08745Sheppo /* Reset channel state information */ 31541ae08745Sheppo i_ldc_reset_state(ldcp); 31551ae08745Sheppo 31561ae08745Sheppo /* Mark channel as down and in initialized state */ 31571ae08745Sheppo ldcp->tx_ackd_head = 0; 31581ae08745Sheppo ldcp->tx_head = 0; 31593af08d82Slm66018 ldcp->tstate = TS_IN_RESET|TS_INIT; 31601ae08745Sheppo ldcp->status = LDC_INIT; 31611ae08745Sheppo 3162d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 31631ae08745Sheppo mutex_exit(&ldcp->lock); 31641ae08745Sheppo 31651ae08745Sheppo /* Decrement number of open channels */ 31661ae08745Sheppo mutex_enter(&ldcssp->lock); 31671ae08745Sheppo ldcssp->channels_open--; 31681ae08745Sheppo mutex_exit(&ldcssp->lock); 31691ae08745Sheppo 31701ae08745Sheppo D1(ldcp->id, "ldc_close: (0x%llx) channel closed\n", ldcp->id); 31711ae08745Sheppo 31721ae08745Sheppo return (0); 31731ae08745Sheppo } 31741ae08745Sheppo 31751ae08745Sheppo /* 31761ae08745Sheppo * Register channel callback 31771ae08745Sheppo */ 31781ae08745Sheppo int 31791ae08745Sheppo ldc_reg_callback(ldc_handle_t handle, 31801ae08745Sheppo uint_t(*cb)(uint64_t event, caddr_t arg), caddr_t arg) 31811ae08745Sheppo { 31821ae08745Sheppo ldc_chan_t *ldcp; 31831ae08745Sheppo 31841ae08745Sheppo if (handle == NULL) { 31851ae08745Sheppo DWARN(DBG_ALL_LDCS, 31861ae08745Sheppo "ldc_reg_callback: invalid channel handle\n"); 31871ae08745Sheppo return (EINVAL); 31881ae08745Sheppo } 31891ae08745Sheppo if (((uint64_t)cb) < KERNELBASE) { 31901ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_reg_callback: invalid callback\n"); 31911ae08745Sheppo return (EINVAL); 31921ae08745Sheppo } 31931ae08745Sheppo ldcp = (ldc_chan_t *)handle; 31941ae08745Sheppo 31951ae08745Sheppo mutex_enter(&ldcp->lock); 31961ae08745Sheppo 31971ae08745Sheppo if (ldcp->cb) { 31981ae08745Sheppo DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback exists\n", 31991ae08745Sheppo ldcp->id); 32001ae08745Sheppo mutex_exit(&ldcp->lock); 32011ae08745Sheppo return (EIO); 32021ae08745Sheppo } 32031ae08745Sheppo if (ldcp->cb_inprogress) { 32041ae08745Sheppo DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback active\n", 32051ae08745Sheppo ldcp->id); 32061ae08745Sheppo mutex_exit(&ldcp->lock); 32071ae08745Sheppo return (EWOULDBLOCK); 32081ae08745Sheppo } 32091ae08745Sheppo 32101ae08745Sheppo ldcp->cb = cb; 32111ae08745Sheppo ldcp->cb_arg = arg; 32121ae08745Sheppo ldcp->cb_enabled = B_TRUE; 32131ae08745Sheppo 32141ae08745Sheppo D1(ldcp->id, 32151ae08745Sheppo "ldc_reg_callback: (0x%llx) registered callback for channel\n", 32161ae08745Sheppo ldcp->id); 32171ae08745Sheppo 32181ae08745Sheppo mutex_exit(&ldcp->lock); 32191ae08745Sheppo 32201ae08745Sheppo return (0); 32211ae08745Sheppo } 32221ae08745Sheppo 32231ae08745Sheppo /* 32241ae08745Sheppo * Unregister channel callback 32251ae08745Sheppo */ 32261ae08745Sheppo int 32271ae08745Sheppo ldc_unreg_callback(ldc_handle_t handle) 32281ae08745Sheppo { 32291ae08745Sheppo ldc_chan_t *ldcp; 32301ae08745Sheppo 32311ae08745Sheppo if (handle == NULL) { 32321ae08745Sheppo DWARN(DBG_ALL_LDCS, 32331ae08745Sheppo "ldc_unreg_callback: invalid channel handle\n"); 32341ae08745Sheppo return (EINVAL); 32351ae08745Sheppo } 32361ae08745Sheppo ldcp = (ldc_chan_t *)handle; 32371ae08745Sheppo 32381ae08745Sheppo mutex_enter(&ldcp->lock); 32391ae08745Sheppo 32401ae08745Sheppo if (ldcp->cb == NULL) { 32411ae08745Sheppo DWARN(ldcp->id, 32421ae08745Sheppo "ldc_unreg_callback: (0x%llx) no callback exists\n", 32431ae08745Sheppo ldcp->id); 32441ae08745Sheppo mutex_exit(&ldcp->lock); 32451ae08745Sheppo return (EIO); 32461ae08745Sheppo } 32471ae08745Sheppo if (ldcp->cb_inprogress) { 32481ae08745Sheppo DWARN(ldcp->id, 32491ae08745Sheppo "ldc_unreg_callback: (0x%llx) callback active\n", 32501ae08745Sheppo ldcp->id); 32511ae08745Sheppo mutex_exit(&ldcp->lock); 32521ae08745Sheppo return (EWOULDBLOCK); 32531ae08745Sheppo } 32541ae08745Sheppo 32551ae08745Sheppo ldcp->cb = NULL; 32561ae08745Sheppo ldcp->cb_arg = NULL; 32571ae08745Sheppo ldcp->cb_enabled = B_FALSE; 32581ae08745Sheppo 32591ae08745Sheppo D1(ldcp->id, 32601ae08745Sheppo "ldc_unreg_callback: (0x%llx) unregistered callback for channel\n", 32611ae08745Sheppo ldcp->id); 32621ae08745Sheppo 32631ae08745Sheppo mutex_exit(&ldcp->lock); 32641ae08745Sheppo 32651ae08745Sheppo return (0); 32661ae08745Sheppo } 32671ae08745Sheppo 32681ae08745Sheppo 32691ae08745Sheppo /* 32701ae08745Sheppo * Bring a channel up by initiating a handshake with the peer 32711ae08745Sheppo * This call is asynchronous. It will complete at a later point 32721ae08745Sheppo * in time when the peer responds back with an RTR. 32731ae08745Sheppo */ 32741ae08745Sheppo int 32751ae08745Sheppo ldc_up(ldc_handle_t handle) 32761ae08745Sheppo { 32771ae08745Sheppo int rv; 32781ae08745Sheppo ldc_chan_t *ldcp; 32791ae08745Sheppo ldc_msg_t *ldcmsg; 328057e6a936Ssb155480 uint64_t tx_tail, tstate, link_state; 32811ae08745Sheppo 32821ae08745Sheppo if (handle == NULL) { 32831ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_up: invalid channel handle\n"); 32841ae08745Sheppo return (EINVAL); 32851ae08745Sheppo } 32861ae08745Sheppo ldcp = (ldc_chan_t *)handle; 32871ae08745Sheppo 32881ae08745Sheppo mutex_enter(&ldcp->lock); 32891ae08745Sheppo 32903af08d82Slm66018 D1(ldcp->id, "ldc_up: (0x%llx) doing channel UP\n", ldcp->id); 32913af08d82Slm66018 32923af08d82Slm66018 /* clear the reset state */ 32933af08d82Slm66018 tstate = ldcp->tstate; 32943af08d82Slm66018 ldcp->tstate &= ~TS_IN_RESET; 32953af08d82Slm66018 32961ae08745Sheppo if (ldcp->tstate == TS_UP) { 32973af08d82Slm66018 DWARN(ldcp->id, 32981ae08745Sheppo "ldc_up: (0x%llx) channel is already in UP state\n", 32991ae08745Sheppo ldcp->id); 33003af08d82Slm66018 33013af08d82Slm66018 /* mark channel as up */ 33023af08d82Slm66018 ldcp->status = LDC_UP; 33033af08d82Slm66018 33043af08d82Slm66018 /* 33053af08d82Slm66018 * if channel was in reset state and there was 33063af08d82Slm66018 * pending data clear interrupt state. this will 33073af08d82Slm66018 * trigger an interrupt, causing the RX handler to 33083af08d82Slm66018 * to invoke the client's callback 33093af08d82Slm66018 */ 33103af08d82Slm66018 if ((tstate & TS_IN_RESET) && 33113af08d82Slm66018 ldcp->rx_intr_state == LDC_INTR_PEND) { 3312cb112a14Slm66018 D1(ldcp->id, 33133af08d82Slm66018 "ldc_up: (0x%llx) channel has pending data, " 33143af08d82Slm66018 "clearing interrupt\n", ldcp->id); 33153af08d82Slm66018 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 33163af08d82Slm66018 } 33173af08d82Slm66018 33181ae08745Sheppo mutex_exit(&ldcp->lock); 33191ae08745Sheppo return (0); 33201ae08745Sheppo } 33211ae08745Sheppo 33221ae08745Sheppo /* if the channel is in RAW mode - mark it as UP, if READY */ 33231ae08745Sheppo if (ldcp->mode == LDC_MODE_RAW && ldcp->tstate >= TS_READY) { 33241ae08745Sheppo ldcp->tstate = TS_UP; 33251ae08745Sheppo mutex_exit(&ldcp->lock); 33261ae08745Sheppo return (0); 33271ae08745Sheppo } 33281ae08745Sheppo 33291ae08745Sheppo /* Don't start another handshake if there is one in progress */ 33301ae08745Sheppo if (ldcp->hstate) { 33313af08d82Slm66018 D1(ldcp->id, 33321ae08745Sheppo "ldc_up: (0x%llx) channel handshake in progress\n", 33331ae08745Sheppo ldcp->id); 33341ae08745Sheppo mutex_exit(&ldcp->lock); 33351ae08745Sheppo return (0); 33361ae08745Sheppo } 33371ae08745Sheppo 3338d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 3339d10e4ef2Snarayan 334057e6a936Ssb155480 /* save current link state */ 334157e6a936Ssb155480 link_state = ldcp->link_state; 334257e6a936Ssb155480 33431ae08745Sheppo /* get the current tail for the LDC msg */ 33441ae08745Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 33451ae08745Sheppo if (rv) { 3346cb112a14Slm66018 D1(ldcp->id, "ldc_up: (0x%llx) cannot initiate handshake\n", 33471ae08745Sheppo ldcp->id); 3348d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 33491ae08745Sheppo mutex_exit(&ldcp->lock); 33501ae08745Sheppo return (ECONNREFUSED); 33511ae08745Sheppo } 33521ae08745Sheppo 335357e6a936Ssb155480 /* 335457e6a936Ssb155480 * If i_ldc_get_tx_tail() changed link_state to either RESET or UP, 335557e6a936Ssb155480 * from a previous state of DOWN, then mark the channel as 335657e6a936Ssb155480 * being ready for handshake. 335757e6a936Ssb155480 */ 335857e6a936Ssb155480 if ((link_state == LDC_CHANNEL_DOWN) && 335957e6a936Ssb155480 (link_state != ldcp->link_state)) { 336057e6a936Ssb155480 336157e6a936Ssb155480 ASSERT((ldcp->link_state == LDC_CHANNEL_RESET) || 336257e6a936Ssb155480 (ldcp->link_state == LDC_CHANNEL_UP)); 336357e6a936Ssb155480 336457e6a936Ssb155480 if (ldcp->mode == LDC_MODE_RAW) { 336557e6a936Ssb155480 ldcp->status = LDC_UP; 336657e6a936Ssb155480 ldcp->tstate = TS_UP; 336757e6a936Ssb155480 mutex_exit(&ldcp->tx_lock); 336857e6a936Ssb155480 mutex_exit(&ldcp->lock); 336957e6a936Ssb155480 return (0); 337057e6a936Ssb155480 } else { 337157e6a936Ssb155480 ldcp->status = LDC_READY; 337257e6a936Ssb155480 ldcp->tstate |= TS_LINK_READY; 337357e6a936Ssb155480 } 337457e6a936Ssb155480 337557e6a936Ssb155480 } 337657e6a936Ssb155480 33771ae08745Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 33781ae08745Sheppo ZERO_PKT(ldcmsg); 33791ae08745Sheppo 33801ae08745Sheppo ldcmsg->type = LDC_CTRL; 33811ae08745Sheppo ldcmsg->stype = LDC_INFO; 33821ae08745Sheppo ldcmsg->ctrl = LDC_VER; 33831ae08745Sheppo ldcp->next_vidx = 0; 33841ae08745Sheppo bcopy(&ldc_versions[0], ldcmsg->udata, sizeof (ldc_versions[0])); 33851ae08745Sheppo 33861ae08745Sheppo DUMP_LDC_PKT(ldcp, "ldc_up snd ver", (uint64_t)ldcmsg); 33871ae08745Sheppo 33881ae08745Sheppo /* initiate the send by calling into HV and set the new tail */ 33891ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 33901ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 33911ae08745Sheppo 33921ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 33931ae08745Sheppo if (rv) { 33941ae08745Sheppo DWARN(ldcp->id, 33951ae08745Sheppo "ldc_up: (0x%llx) cannot initiate handshake rv=%d\n", 33961ae08745Sheppo ldcp->id, rv); 3397d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 33981ae08745Sheppo mutex_exit(&ldcp->lock); 33991ae08745Sheppo return (rv); 34001ae08745Sheppo } 34011ae08745Sheppo 34020a55fbb7Slm66018 ldcp->hstate |= TS_SENT_VER; 34031ae08745Sheppo ldcp->tx_tail = tx_tail; 34041ae08745Sheppo D1(ldcp->id, "ldc_up: (0x%llx) channel up initiated\n", ldcp->id); 34051ae08745Sheppo 3406d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 34071ae08745Sheppo mutex_exit(&ldcp->lock); 34081ae08745Sheppo 34091ae08745Sheppo return (rv); 34101ae08745Sheppo } 34111ae08745Sheppo 34121ae08745Sheppo 34131ae08745Sheppo /* 3414e1ebb9ecSlm66018 * Bring a channel down by resetting its state and queues 34151ae08745Sheppo */ 34161ae08745Sheppo int 3417e1ebb9ecSlm66018 ldc_down(ldc_handle_t handle) 34181ae08745Sheppo { 34191ae08745Sheppo ldc_chan_t *ldcp; 34201ae08745Sheppo 34211ae08745Sheppo if (handle == NULL) { 3422e1ebb9ecSlm66018 DWARN(DBG_ALL_LDCS, "ldc_down: invalid channel handle\n"); 34231ae08745Sheppo return (EINVAL); 34241ae08745Sheppo } 34251ae08745Sheppo ldcp = (ldc_chan_t *)handle; 34261ae08745Sheppo mutex_enter(&ldcp->lock); 3427d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 34283af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 3429d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 34301ae08745Sheppo mutex_exit(&ldcp->lock); 34311ae08745Sheppo 34321ae08745Sheppo return (0); 34331ae08745Sheppo } 34341ae08745Sheppo 34351ae08745Sheppo /* 34361ae08745Sheppo * Get the current channel status 34371ae08745Sheppo */ 34381ae08745Sheppo int 34391ae08745Sheppo ldc_status(ldc_handle_t handle, ldc_status_t *status) 34401ae08745Sheppo { 34411ae08745Sheppo ldc_chan_t *ldcp; 34421ae08745Sheppo 34431ae08745Sheppo if (handle == NULL || status == NULL) { 34441ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_status: invalid argument\n"); 34451ae08745Sheppo return (EINVAL); 34461ae08745Sheppo } 34471ae08745Sheppo ldcp = (ldc_chan_t *)handle; 34481ae08745Sheppo 34491ae08745Sheppo *status = ((ldc_chan_t *)handle)->status; 34501ae08745Sheppo 3451cb112a14Slm66018 D1(ldcp->id, 34521ae08745Sheppo "ldc_status: (0x%llx) returned status %d\n", ldcp->id, *status); 34531ae08745Sheppo return (0); 34541ae08745Sheppo } 34551ae08745Sheppo 34561ae08745Sheppo 34571ae08745Sheppo /* 34581ae08745Sheppo * Set the channel's callback mode - enable/disable callbacks 34591ae08745Sheppo */ 34601ae08745Sheppo int 34611ae08745Sheppo ldc_set_cb_mode(ldc_handle_t handle, ldc_cb_mode_t cmode) 34621ae08745Sheppo { 34631ae08745Sheppo ldc_chan_t *ldcp; 34641ae08745Sheppo 34651ae08745Sheppo if (handle == NULL) { 34661ae08745Sheppo DWARN(DBG_ALL_LDCS, 34671ae08745Sheppo "ldc_set_intr_mode: invalid channel handle\n"); 34681ae08745Sheppo return (EINVAL); 34691ae08745Sheppo } 34701ae08745Sheppo ldcp = (ldc_chan_t *)handle; 34711ae08745Sheppo 34721ae08745Sheppo /* 34731ae08745Sheppo * Record no callbacks should be invoked 34741ae08745Sheppo */ 34751ae08745Sheppo mutex_enter(&ldcp->lock); 34761ae08745Sheppo 34771ae08745Sheppo switch (cmode) { 34781ae08745Sheppo case LDC_CB_DISABLE: 34791ae08745Sheppo if (!ldcp->cb_enabled) { 34801ae08745Sheppo DWARN(ldcp->id, 34811ae08745Sheppo "ldc_set_cb_mode: (0x%llx) callbacks disabled\n", 34821ae08745Sheppo ldcp->id); 34831ae08745Sheppo break; 34841ae08745Sheppo } 34851ae08745Sheppo ldcp->cb_enabled = B_FALSE; 34861ae08745Sheppo 34871ae08745Sheppo D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) disabled callbacks\n", 34881ae08745Sheppo ldcp->id); 34891ae08745Sheppo break; 34901ae08745Sheppo 34911ae08745Sheppo case LDC_CB_ENABLE: 34921ae08745Sheppo if (ldcp->cb_enabled) { 34931ae08745Sheppo DWARN(ldcp->id, 34941ae08745Sheppo "ldc_set_cb_mode: (0x%llx) callbacks enabled\n", 34951ae08745Sheppo ldcp->id); 34961ae08745Sheppo break; 34971ae08745Sheppo } 34981ae08745Sheppo ldcp->cb_enabled = B_TRUE; 34991ae08745Sheppo 35001ae08745Sheppo D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) enabled callbacks\n", 35011ae08745Sheppo ldcp->id); 35021ae08745Sheppo break; 35031ae08745Sheppo } 35041ae08745Sheppo 35051ae08745Sheppo mutex_exit(&ldcp->lock); 35061ae08745Sheppo 35071ae08745Sheppo return (0); 35081ae08745Sheppo } 35091ae08745Sheppo 35101ae08745Sheppo /* 35111ae08745Sheppo * Check to see if there are packets on the incoming queue 3512e1ebb9ecSlm66018 * Will return hasdata = B_FALSE if there are no packets 35131ae08745Sheppo */ 35141ae08745Sheppo int 3515e1ebb9ecSlm66018 ldc_chkq(ldc_handle_t handle, boolean_t *hasdata) 35161ae08745Sheppo { 35171ae08745Sheppo int rv; 35181ae08745Sheppo uint64_t rx_head, rx_tail; 35191ae08745Sheppo ldc_chan_t *ldcp; 35201ae08745Sheppo 35211ae08745Sheppo if (handle == NULL) { 35221ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_chkq: invalid channel handle\n"); 35231ae08745Sheppo return (EINVAL); 35241ae08745Sheppo } 35251ae08745Sheppo ldcp = (ldc_chan_t *)handle; 35261ae08745Sheppo 3527e1ebb9ecSlm66018 *hasdata = B_FALSE; 35281ae08745Sheppo 35291ae08745Sheppo mutex_enter(&ldcp->lock); 35301ae08745Sheppo 35311ae08745Sheppo if (ldcp->tstate != TS_UP) { 35321ae08745Sheppo D1(ldcp->id, 35331ae08745Sheppo "ldc_chkq: (0x%llx) channel is not up\n", ldcp->id); 35341ae08745Sheppo mutex_exit(&ldcp->lock); 35351ae08745Sheppo return (ECONNRESET); 35361ae08745Sheppo } 35371ae08745Sheppo 35381ae08745Sheppo /* Read packet(s) from the queue */ 35391ae08745Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 35401ae08745Sheppo &ldcp->link_state); 35411ae08745Sheppo if (rv != 0) { 35421ae08745Sheppo cmn_err(CE_WARN, 35431ae08745Sheppo "ldc_chkq: (0x%lx) unable to read queue ptrs", ldcp->id); 35441ae08745Sheppo mutex_exit(&ldcp->lock); 35451ae08745Sheppo return (EIO); 35461ae08745Sheppo } 354758283286Sha137994 35481ae08745Sheppo /* reset the channel state if the channel went down */ 35491ae08745Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN || 35501ae08745Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 3551d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 35523af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 3553d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 35541ae08745Sheppo mutex_exit(&ldcp->lock); 35551ae08745Sheppo return (ECONNRESET); 35561ae08745Sheppo } 35571ae08745Sheppo 355858283286Sha137994 switch (ldcp->mode) { 355958283286Sha137994 case LDC_MODE_RAW: 356058283286Sha137994 /* 356158283286Sha137994 * In raw mode, there are no ctrl packets, so checking 356258283286Sha137994 * if the queue is non-empty is sufficient. 356358283286Sha137994 */ 356458283286Sha137994 *hasdata = (rx_head != rx_tail); 356558283286Sha137994 break; 356658283286Sha137994 356758283286Sha137994 case LDC_MODE_UNRELIABLE: 356858283286Sha137994 /* 356958283286Sha137994 * In unreliable mode, if the queue is non-empty, we need 357058283286Sha137994 * to check if it actually contains unread data packets. 357158283286Sha137994 * The queue may just contain ctrl packets. 357258283286Sha137994 */ 3573*a74caf9bSha137994 if (rx_head != rx_tail) { 357458283286Sha137994 *hasdata = (i_ldc_chkq(ldcp) == 0); 3575*a74caf9bSha137994 /* 3576*a74caf9bSha137994 * If no data packets were found on the queue, 3577*a74caf9bSha137994 * all packets must have been control packets 3578*a74caf9bSha137994 * which will now have been processed, leaving 3579*a74caf9bSha137994 * the queue empty. If the interrupt state 3580*a74caf9bSha137994 * is pending, we need to clear the interrupt 3581*a74caf9bSha137994 * here. 3582*a74caf9bSha137994 */ 3583*a74caf9bSha137994 if (*hasdata == B_FALSE && 3584*a74caf9bSha137994 ldcp->rx_intr_state == LDC_INTR_PEND) { 3585*a74caf9bSha137994 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 3586*a74caf9bSha137994 } 3587*a74caf9bSha137994 } 358858283286Sha137994 break; 358958283286Sha137994 359020ae46ebSha137994 case LDC_MODE_RELIABLE: 359158283286Sha137994 /* 359220ae46ebSha137994 * In reliable mode, first check for 'stream_remains' > 0. 359358283286Sha137994 * Otherwise, if the data queue head and tail pointers 359458283286Sha137994 * differ, there must be data to read. 359558283286Sha137994 */ 359658283286Sha137994 if (ldcp->stream_remains > 0) 3597e1ebb9ecSlm66018 *hasdata = B_TRUE; 359858283286Sha137994 else 359958283286Sha137994 *hasdata = (ldcp->rx_dq_head != ldcp->rx_dq_tail); 360058283286Sha137994 break; 360158283286Sha137994 360258283286Sha137994 default: 360358283286Sha137994 cmn_err(CE_WARN, "ldc_chkq: (0x%lx) unexpected channel mode " 360458283286Sha137994 "(0x%x)", ldcp->id, ldcp->mode); 360558283286Sha137994 mutex_exit(&ldcp->lock); 360658283286Sha137994 return (EIO); 36071ae08745Sheppo } 36081ae08745Sheppo 36091ae08745Sheppo mutex_exit(&ldcp->lock); 36101ae08745Sheppo 36111ae08745Sheppo return (0); 36121ae08745Sheppo } 36131ae08745Sheppo 36141ae08745Sheppo 36151ae08745Sheppo /* 36161ae08745Sheppo * Read 'size' amount of bytes or less. If incoming buffer 36171ae08745Sheppo * is more than 'size', ENOBUFS is returned. 36181ae08745Sheppo * 36191ae08745Sheppo * On return, size contains the number of bytes read. 36201ae08745Sheppo */ 36211ae08745Sheppo int 36221ae08745Sheppo ldc_read(ldc_handle_t handle, caddr_t bufp, size_t *sizep) 36231ae08745Sheppo { 36241ae08745Sheppo ldc_chan_t *ldcp; 36251ae08745Sheppo uint64_t rx_head = 0, rx_tail = 0; 36261ae08745Sheppo int rv = 0, exit_val; 36271ae08745Sheppo 36281ae08745Sheppo if (handle == NULL) { 36291ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_read: invalid channel handle\n"); 36301ae08745Sheppo return (EINVAL); 36311ae08745Sheppo } 36321ae08745Sheppo 36331ae08745Sheppo ldcp = (ldc_chan_t *)handle; 36341ae08745Sheppo 36351ae08745Sheppo /* channel lock */ 36361ae08745Sheppo mutex_enter(&ldcp->lock); 36371ae08745Sheppo 36381ae08745Sheppo if (ldcp->tstate != TS_UP) { 36391ae08745Sheppo DWARN(ldcp->id, 36401ae08745Sheppo "ldc_read: (0x%llx) channel is not in UP state\n", 36411ae08745Sheppo ldcp->id); 36421ae08745Sheppo exit_val = ECONNRESET; 364320ae46ebSha137994 } else if (ldcp->mode == LDC_MODE_RELIABLE) { 364458283286Sha137994 TRACE_RXDQ_LENGTH(ldcp); 364558283286Sha137994 exit_val = ldcp->read_p(ldcp, bufp, sizep); 364658283286Sha137994 mutex_exit(&ldcp->lock); 364758283286Sha137994 return (exit_val); 36481ae08745Sheppo } else { 36491ae08745Sheppo exit_val = ldcp->read_p(ldcp, bufp, sizep); 36501ae08745Sheppo } 36511ae08745Sheppo 36521ae08745Sheppo /* 36531ae08745Sheppo * if queue has been drained - clear interrupt 36541ae08745Sheppo */ 36551ae08745Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 36561ae08745Sheppo &ldcp->link_state); 3657cb112a14Slm66018 if (rv != 0) { 3658cb112a14Slm66018 cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs", 3659cb112a14Slm66018 ldcp->id); 3660cb112a14Slm66018 mutex_enter(&ldcp->tx_lock); 3661cb112a14Slm66018 i_ldc_reset(ldcp, B_TRUE); 3662cb112a14Slm66018 mutex_exit(&ldcp->tx_lock); 3663bd8f0338Snarayan mutex_exit(&ldcp->lock); 3664cb112a14Slm66018 return (ECONNRESET); 3665cb112a14Slm66018 } 36663af08d82Slm66018 36673af08d82Slm66018 if (exit_val == 0) { 36683af08d82Slm66018 if (ldcp->link_state == LDC_CHANNEL_DOWN || 36693af08d82Slm66018 ldcp->link_state == LDC_CHANNEL_RESET) { 36703af08d82Slm66018 mutex_enter(&ldcp->tx_lock); 36713af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 36723af08d82Slm66018 exit_val = ECONNRESET; 36733af08d82Slm66018 mutex_exit(&ldcp->tx_lock); 36743af08d82Slm66018 } 36753af08d82Slm66018 if ((rv == 0) && 36763af08d82Slm66018 (ldcp->rx_intr_state == LDC_INTR_PEND) && 36773af08d82Slm66018 (rx_head == rx_tail)) { 36781ae08745Sheppo i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 36791ae08745Sheppo } 36803af08d82Slm66018 } 36811ae08745Sheppo 36821ae08745Sheppo mutex_exit(&ldcp->lock); 36831ae08745Sheppo return (exit_val); 36841ae08745Sheppo } 36851ae08745Sheppo 36861ae08745Sheppo /* 36871ae08745Sheppo * Basic raw mondo read - 36881ae08745Sheppo * no interpretation of mondo contents at all. 36891ae08745Sheppo * 36901ae08745Sheppo * Enter and exit with ldcp->lock held by caller 36911ae08745Sheppo */ 36921ae08745Sheppo static int 36931ae08745Sheppo i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep) 36941ae08745Sheppo { 36951ae08745Sheppo uint64_t q_size_mask; 36961ae08745Sheppo ldc_msg_t *msgp; 36971ae08745Sheppo uint8_t *msgbufp; 36981ae08745Sheppo int rv = 0, space; 36991ae08745Sheppo uint64_t rx_head, rx_tail; 37001ae08745Sheppo 37011ae08745Sheppo space = *sizep; 37021ae08745Sheppo 37031ae08745Sheppo if (space < LDC_PAYLOAD_SIZE_RAW) 37041ae08745Sheppo return (ENOBUFS); 37051ae08745Sheppo 37061ae08745Sheppo ASSERT(mutex_owned(&ldcp->lock)); 37071ae08745Sheppo 37081ae08745Sheppo /* compute mask for increment */ 37091ae08745Sheppo q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT; 37101ae08745Sheppo 37111ae08745Sheppo /* 37121ae08745Sheppo * Read packet(s) from the queue 37131ae08745Sheppo */ 37141ae08745Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 37151ae08745Sheppo &ldcp->link_state); 37161ae08745Sheppo if (rv != 0) { 37171ae08745Sheppo cmn_err(CE_WARN, 37181ae08745Sheppo "ldc_read_raw: (0x%lx) unable to read queue ptrs", 37191ae08745Sheppo ldcp->id); 37201ae08745Sheppo return (EIO); 37211ae08745Sheppo } 37221ae08745Sheppo D1(ldcp->id, "ldc_read_raw: (0x%llx) rxh=0x%llx," 37231ae08745Sheppo " rxt=0x%llx, st=0x%llx\n", 37241ae08745Sheppo ldcp->id, rx_head, rx_tail, ldcp->link_state); 37251ae08745Sheppo 37261ae08745Sheppo /* reset the channel state if the channel went down */ 37273af08d82Slm66018 if (ldcp->link_state == LDC_CHANNEL_DOWN || 37283af08d82Slm66018 ldcp->link_state == LDC_CHANNEL_RESET) { 3729d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 37303af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 3731d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 37321ae08745Sheppo return (ECONNRESET); 37331ae08745Sheppo } 37341ae08745Sheppo 37351ae08745Sheppo /* 37361ae08745Sheppo * Check for empty queue 37371ae08745Sheppo */ 37381ae08745Sheppo if (rx_head == rx_tail) { 37391ae08745Sheppo *sizep = 0; 37401ae08745Sheppo return (0); 37411ae08745Sheppo } 37421ae08745Sheppo 37431ae08745Sheppo /* get the message */ 37441ae08745Sheppo msgp = (ldc_msg_t *)(ldcp->rx_q_va + rx_head); 37451ae08745Sheppo 37461ae08745Sheppo /* if channel is in RAW mode, copy data and return */ 37471ae08745Sheppo msgbufp = (uint8_t *)&(msgp->raw[0]); 37481ae08745Sheppo 37491ae08745Sheppo bcopy(msgbufp, target_bufp, LDC_PAYLOAD_SIZE_RAW); 37501ae08745Sheppo 37511ae08745Sheppo DUMP_PAYLOAD(ldcp->id, msgbufp); 37521ae08745Sheppo 37531ae08745Sheppo *sizep = LDC_PAYLOAD_SIZE_RAW; 37541ae08745Sheppo 37551ae08745Sheppo rx_head = (rx_head + LDC_PACKET_SIZE) & q_size_mask; 37560a55fbb7Slm66018 rv = i_ldc_set_rx_head(ldcp, rx_head); 37571ae08745Sheppo 37581ae08745Sheppo return (rv); 37591ae08745Sheppo } 37601ae08745Sheppo 37611ae08745Sheppo /* 37621ae08745Sheppo * Process LDC mondos to build larger packets 37631ae08745Sheppo * with either un-reliable or reliable delivery. 37641ae08745Sheppo * 37651ae08745Sheppo * Enter and exit with ldcp->lock held by caller 37661ae08745Sheppo */ 37671ae08745Sheppo static int 37681ae08745Sheppo i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep) 37691ae08745Sheppo { 37701ae08745Sheppo int rv = 0; 37711ae08745Sheppo uint64_t rx_head = 0, rx_tail = 0; 37721ae08745Sheppo uint64_t curr_head = 0; 37731ae08745Sheppo ldc_msg_t *msg; 37741ae08745Sheppo caddr_t target; 37751ae08745Sheppo size_t len = 0, bytes_read = 0; 37760a55fbb7Slm66018 int retries = 0; 377758283286Sha137994 uint64_t q_va, q_size_mask; 3778d10e4ef2Snarayan uint64_t first_fragment = 0; 37791ae08745Sheppo 37801ae08745Sheppo target = target_bufp; 37811ae08745Sheppo 37821ae08745Sheppo ASSERT(mutex_owned(&ldcp->lock)); 37831ae08745Sheppo 37843af08d82Slm66018 /* check if the buffer and size are valid */ 37853af08d82Slm66018 if (target_bufp == NULL || *sizep == 0) { 37863af08d82Slm66018 DWARN(ldcp->id, "ldc_read: (0x%llx) invalid buffer/size\n", 37873af08d82Slm66018 ldcp->id); 37883af08d82Slm66018 return (EINVAL); 37893af08d82Slm66018 } 37903af08d82Slm66018 379158283286Sha137994 /* Set q_va and compute increment mask for the appropriate queue */ 379220ae46ebSha137994 if (ldcp->mode == LDC_MODE_RELIABLE) { 379358283286Sha137994 q_va = ldcp->rx_dq_va; 379458283286Sha137994 q_size_mask = (ldcp->rx_dq_entries-1)<<LDC_PACKET_SHIFT; 379558283286Sha137994 } else { 379658283286Sha137994 q_va = ldcp->rx_q_va; 37971ae08745Sheppo q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT; 379858283286Sha137994 } 37991ae08745Sheppo 38001ae08745Sheppo /* 38011ae08745Sheppo * Read packet(s) from the queue 38021ae08745Sheppo */ 380358283286Sha137994 rv = ldcp->readq_get_state(ldcp, &curr_head, &rx_tail, 38041ae08745Sheppo &ldcp->link_state); 38051ae08745Sheppo if (rv != 0) { 38063af08d82Slm66018 cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs", 38071ae08745Sheppo ldcp->id); 38083af08d82Slm66018 mutex_enter(&ldcp->tx_lock); 38093af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 38103af08d82Slm66018 mutex_exit(&ldcp->tx_lock); 38113af08d82Slm66018 return (ECONNRESET); 38121ae08745Sheppo } 38131ae08745Sheppo D1(ldcp->id, "ldc_read: (0x%llx) chd=0x%llx, tl=0x%llx, st=0x%llx\n", 38141ae08745Sheppo ldcp->id, curr_head, rx_tail, ldcp->link_state); 38151ae08745Sheppo 38161ae08745Sheppo /* reset the channel state if the channel went down */ 38173af08d82Slm66018 if (ldcp->link_state != LDC_CHANNEL_UP) 38183af08d82Slm66018 goto channel_is_reset; 38191ae08745Sheppo 38201ae08745Sheppo for (;;) { 38211ae08745Sheppo 38221ae08745Sheppo if (curr_head == rx_tail) { 382358283286Sha137994 /* 382458283286Sha137994 * If a data queue is being used, check the Rx HV 382558283286Sha137994 * queue. This will copy over any new data packets 382658283286Sha137994 * that have arrived. 382758283286Sha137994 */ 382820ae46ebSha137994 if (ldcp->mode == LDC_MODE_RELIABLE) 382958283286Sha137994 (void) i_ldc_chkq(ldcp); 383058283286Sha137994 383158283286Sha137994 rv = ldcp->readq_get_state(ldcp, 38321ae08745Sheppo &rx_head, &rx_tail, &ldcp->link_state); 38331ae08745Sheppo if (rv != 0) { 38341ae08745Sheppo cmn_err(CE_WARN, 38351ae08745Sheppo "ldc_read: (0x%lx) cannot read queue ptrs", 38361ae08745Sheppo ldcp->id); 3837d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 38383af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 3839d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 38401ae08745Sheppo return (ECONNRESET); 38411ae08745Sheppo } 384258283286Sha137994 38433af08d82Slm66018 if (ldcp->link_state != LDC_CHANNEL_UP) 38443af08d82Slm66018 goto channel_is_reset; 38451ae08745Sheppo 38461ae08745Sheppo if (curr_head == rx_tail) { 38471ae08745Sheppo 38481ae08745Sheppo /* If in the middle of a fragmented xfer */ 3849d10e4ef2Snarayan if (first_fragment != 0) { 38500a55fbb7Slm66018 38510a55fbb7Slm66018 /* wait for ldc_delay usecs */ 38520a55fbb7Slm66018 drv_usecwait(ldc_delay); 38530a55fbb7Slm66018 38540a55fbb7Slm66018 if (++retries < ldc_max_retries) 38551ae08745Sheppo continue; 38560a55fbb7Slm66018 38571ae08745Sheppo *sizep = 0; 385820ae46ebSha137994 if (ldcp->mode != LDC_MODE_RELIABLE) 385958283286Sha137994 ldcp->last_msg_rcd = 386058283286Sha137994 first_fragment - 1; 38613af08d82Slm66018 DWARN(DBG_ALL_LDCS, "ldc_read: " 386222f747efSnarayan "(0x%llx) read timeout", ldcp->id); 38633af08d82Slm66018 return (EAGAIN); 38641ae08745Sheppo } 38651ae08745Sheppo *sizep = 0; 38661ae08745Sheppo break; 38671ae08745Sheppo } 38683af08d82Slm66018 } 38690a55fbb7Slm66018 retries = 0; 38701ae08745Sheppo 38711ae08745Sheppo D2(ldcp->id, 38721ae08745Sheppo "ldc_read: (0x%llx) chd=0x%llx, rxhd=0x%llx, rxtl=0x%llx\n", 38731ae08745Sheppo ldcp->id, curr_head, rx_head, rx_tail); 38741ae08745Sheppo 38751ae08745Sheppo /* get the message */ 387658283286Sha137994 msg = (ldc_msg_t *)(q_va + curr_head); 38771ae08745Sheppo 38781ae08745Sheppo DUMP_LDC_PKT(ldcp, "ldc_read received pkt", 38791ae08745Sheppo ldcp->rx_q_va + curr_head); 38801ae08745Sheppo 38811ae08745Sheppo /* Check the message ID for the message received */ 388220ae46ebSha137994 if (ldcp->mode != LDC_MODE_RELIABLE) { 38831ae08745Sheppo if ((rv = i_ldc_check_seqid(ldcp, msg)) != 0) { 38841ae08745Sheppo 388558283286Sha137994 DWARN(ldcp->id, "ldc_read: (0x%llx) seqid " 388658283286Sha137994 "error, q_ptrs=0x%lx,0x%lx", 388758283286Sha137994 ldcp->id, rx_head, rx_tail); 38881ae08745Sheppo 38890a55fbb7Slm66018 /* throw away data */ 38900a55fbb7Slm66018 bytes_read = 0; 38910a55fbb7Slm66018 38921ae08745Sheppo /* Reset last_msg_rcd to start of message */ 3893d10e4ef2Snarayan if (first_fragment != 0) { 3894d10e4ef2Snarayan ldcp->last_msg_rcd = first_fragment - 1; 3895d10e4ef2Snarayan first_fragment = 0; 38961ae08745Sheppo } 38971ae08745Sheppo /* 38981ae08745Sheppo * Send a NACK -- invalid seqid 38991ae08745Sheppo * get the current tail for the response 39001ae08745Sheppo */ 39011ae08745Sheppo rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK, 39021ae08745Sheppo (msg->ctrl & LDC_CTRL_MASK)); 39031ae08745Sheppo if (rv) { 39041ae08745Sheppo cmn_err(CE_NOTE, 39051ae08745Sheppo "ldc_read: (0x%lx) err sending " 39061ae08745Sheppo "NACK msg\n", ldcp->id); 3907d10e4ef2Snarayan 390858283286Sha137994 /* if cannot send NACK - reset chan */ 3909d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 39103af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 3911d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 3912d10e4ef2Snarayan rv = ECONNRESET; 3913d10e4ef2Snarayan break; 39141ae08745Sheppo } 39151ae08745Sheppo 39161ae08745Sheppo /* purge receive queue */ 39170a55fbb7Slm66018 rv = i_ldc_set_rx_head(ldcp, rx_tail); 39181ae08745Sheppo 39191ae08745Sheppo break; 39201ae08745Sheppo } 39211ae08745Sheppo 39221ae08745Sheppo /* 39231ae08745Sheppo * Process any messages of type CTRL messages 3924e1ebb9ecSlm66018 * Future implementations should try to pass these 3925e1ebb9ecSlm66018 * to LDC link by resetting the intr state. 39261ae08745Sheppo * 392758283286Sha137994 * NOTE: not done as a switch() as type can be 392858283286Sha137994 * both ctrl+data 39291ae08745Sheppo */ 39301ae08745Sheppo if (msg->type & LDC_CTRL) { 39311ae08745Sheppo if (rv = i_ldc_ctrlmsg(ldcp, msg)) { 39321ae08745Sheppo if (rv == EAGAIN) 39331ae08745Sheppo continue; 39340a55fbb7Slm66018 rv = i_ldc_set_rx_head(ldcp, rx_tail); 39351ae08745Sheppo *sizep = 0; 39361ae08745Sheppo bytes_read = 0; 39371ae08745Sheppo break; 39381ae08745Sheppo } 39391ae08745Sheppo } 39401ae08745Sheppo 39411ae08745Sheppo /* process data ACKs */ 39421ae08745Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) { 3943d10e4ef2Snarayan if (rv = i_ldc_process_data_ACK(ldcp, msg)) { 3944d10e4ef2Snarayan *sizep = 0; 3945d10e4ef2Snarayan bytes_read = 0; 3946d10e4ef2Snarayan break; 3947d10e4ef2Snarayan } 39481ae08745Sheppo } 39491ae08745Sheppo 395083d3bc6fSnarayan /* process data NACKs */ 395183d3bc6fSnarayan if ((msg->type & LDC_DATA) && (msg->stype & LDC_NACK)) { 395283d3bc6fSnarayan DWARN(ldcp->id, 395358283286Sha137994 "ldc_read: (0x%llx) received DATA/NACK", 395458283286Sha137994 ldcp->id); 395583d3bc6fSnarayan mutex_enter(&ldcp->tx_lock); 395683d3bc6fSnarayan i_ldc_reset(ldcp, B_TRUE); 395783d3bc6fSnarayan mutex_exit(&ldcp->tx_lock); 395883d3bc6fSnarayan return (ECONNRESET); 395983d3bc6fSnarayan } 396058283286Sha137994 } 396183d3bc6fSnarayan 39621ae08745Sheppo /* process data messages */ 39631ae08745Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) { 39641ae08745Sheppo 39651ae08745Sheppo uint8_t *msgbuf = (uint8_t *)( 396620ae46ebSha137994 (ldcp->mode == LDC_MODE_RELIABLE) ? 396722f747efSnarayan msg->rdata : msg->udata); 39681ae08745Sheppo 39691ae08745Sheppo D2(ldcp->id, 39701ae08745Sheppo "ldc_read: (0x%llx) received data msg\n", ldcp->id); 39711ae08745Sheppo 39721ae08745Sheppo /* get the packet length */ 39731ae08745Sheppo len = (msg->env & LDC_LEN_MASK); 39741ae08745Sheppo 39751ae08745Sheppo /* 39761ae08745Sheppo * FUTURE OPTIMIZATION: 39771ae08745Sheppo * dont need to set q head for every 39781ae08745Sheppo * packet we read just need to do this when 39791ae08745Sheppo * we are done or need to wait for more 39801ae08745Sheppo * mondos to make a full packet - this is 39811ae08745Sheppo * currently expensive. 39821ae08745Sheppo */ 39831ae08745Sheppo 3984d10e4ef2Snarayan if (first_fragment == 0) { 39851ae08745Sheppo 39861ae08745Sheppo /* 39871ae08745Sheppo * first packets should always have the start 39881ae08745Sheppo * bit set (even for a single packet). If not 39891ae08745Sheppo * throw away the packet 39901ae08745Sheppo */ 39911ae08745Sheppo if (!(msg->env & LDC_FRAG_START)) { 39921ae08745Sheppo 39931ae08745Sheppo DWARN(DBG_ALL_LDCS, 39941ae08745Sheppo "ldc_read: (0x%llx) not start - " 39951ae08745Sheppo "frag=%x\n", ldcp->id, 39961ae08745Sheppo (msg->env) & LDC_FRAG_MASK); 39971ae08745Sheppo 39981ae08745Sheppo /* toss pkt, inc head, cont reading */ 39991ae08745Sheppo bytes_read = 0; 40001ae08745Sheppo target = target_bufp; 40011ae08745Sheppo curr_head = 40021ae08745Sheppo (curr_head + LDC_PACKET_SIZE) 40031ae08745Sheppo & q_size_mask; 400458283286Sha137994 if (rv = ldcp->readq_set_head(ldcp, 40051ae08745Sheppo curr_head)) 40061ae08745Sheppo break; 40071ae08745Sheppo 40081ae08745Sheppo continue; 40091ae08745Sheppo } 40101ae08745Sheppo 4011d10e4ef2Snarayan first_fragment = msg->seqid; 40121ae08745Sheppo } else { 40131ae08745Sheppo /* check to see if this is a pkt w/ START bit */ 40141ae08745Sheppo if (msg->env & LDC_FRAG_START) { 40151ae08745Sheppo DWARN(DBG_ALL_LDCS, 40161ae08745Sheppo "ldc_read:(0x%llx) unexpected pkt" 40171ae08745Sheppo " env=0x%x discarding %d bytes," 40181ae08745Sheppo " lastmsg=%d, currentmsg=%d\n", 40191ae08745Sheppo ldcp->id, msg->env&LDC_FRAG_MASK, 40201ae08745Sheppo bytes_read, ldcp->last_msg_rcd, 40211ae08745Sheppo msg->seqid); 40221ae08745Sheppo 40231ae08745Sheppo /* throw data we have read so far */ 40241ae08745Sheppo bytes_read = 0; 40251ae08745Sheppo target = target_bufp; 4026d10e4ef2Snarayan first_fragment = msg->seqid; 40271ae08745Sheppo 402858283286Sha137994 if (rv = ldcp->readq_set_head(ldcp, 40291ae08745Sheppo curr_head)) 40301ae08745Sheppo break; 40311ae08745Sheppo } 40321ae08745Sheppo } 40331ae08745Sheppo 40341ae08745Sheppo /* copy (next) pkt into buffer */ 40351ae08745Sheppo if (len <= (*sizep - bytes_read)) { 40361ae08745Sheppo bcopy(msgbuf, target, len); 40371ae08745Sheppo target += len; 40381ae08745Sheppo bytes_read += len; 40391ae08745Sheppo } else { 40401ae08745Sheppo /* 40411ae08745Sheppo * there is not enough space in the buffer to 40421ae08745Sheppo * read this pkt. throw message away & continue 40431ae08745Sheppo * reading data from queue 40441ae08745Sheppo */ 40451ae08745Sheppo DWARN(DBG_ALL_LDCS, 40461ae08745Sheppo "ldc_read: (0x%llx) buffer too small, " 40471ae08745Sheppo "head=0x%lx, expect=%d, got=%d\n", ldcp->id, 40481ae08745Sheppo curr_head, *sizep, bytes_read+len); 40491ae08745Sheppo 4050d10e4ef2Snarayan first_fragment = 0; 40511ae08745Sheppo target = target_bufp; 40521ae08745Sheppo bytes_read = 0; 40531ae08745Sheppo 40541ae08745Sheppo /* throw away everything received so far */ 405558283286Sha137994 if (rv = ldcp->readq_set_head(ldcp, curr_head)) 40561ae08745Sheppo break; 40571ae08745Sheppo 40581ae08745Sheppo /* continue reading remaining pkts */ 40591ae08745Sheppo continue; 40601ae08745Sheppo } 40611ae08745Sheppo } 40621ae08745Sheppo 40631ae08745Sheppo /* set the message id */ 406420ae46ebSha137994 if (ldcp->mode != LDC_MODE_RELIABLE) 40651ae08745Sheppo ldcp->last_msg_rcd = msg->seqid; 40661ae08745Sheppo 40671ae08745Sheppo /* move the head one position */ 40681ae08745Sheppo curr_head = (curr_head + LDC_PACKET_SIZE) & q_size_mask; 40691ae08745Sheppo 40701ae08745Sheppo if (msg->env & LDC_FRAG_STOP) { 40711ae08745Sheppo 40721ae08745Sheppo /* 40731ae08745Sheppo * All pkts that are part of this fragmented transfer 40741ae08745Sheppo * have been read or this was a single pkt read 40751ae08745Sheppo * or there was an error 40761ae08745Sheppo */ 40771ae08745Sheppo 40781ae08745Sheppo /* set the queue head */ 407958283286Sha137994 if (rv = ldcp->readq_set_head(ldcp, curr_head)) 40801ae08745Sheppo bytes_read = 0; 40811ae08745Sheppo 40821ae08745Sheppo *sizep = bytes_read; 40831ae08745Sheppo 40841ae08745Sheppo break; 40851ae08745Sheppo } 40861ae08745Sheppo 4087332608acSnarayan /* advance head if it is a CTRL packet or a DATA ACK packet */ 4088332608acSnarayan if ((msg->type & LDC_CTRL) || 4089332608acSnarayan ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK))) { 40901ae08745Sheppo 40911ae08745Sheppo /* set the queue head */ 409258283286Sha137994 if (rv = ldcp->readq_set_head(ldcp, curr_head)) { 40931ae08745Sheppo bytes_read = 0; 40941ae08745Sheppo break; 40951ae08745Sheppo } 40961ae08745Sheppo 40971ae08745Sheppo D2(ldcp->id, "ldc_read: (0x%llx) set ACK qhead 0x%llx", 40981ae08745Sheppo ldcp->id, curr_head); 40991ae08745Sheppo } 41001ae08745Sheppo 41011ae08745Sheppo } /* for (;;) */ 41021ae08745Sheppo 41031ae08745Sheppo D2(ldcp->id, "ldc_read: (0x%llx) end size=%d", ldcp->id, *sizep); 41041ae08745Sheppo 41051ae08745Sheppo return (rv); 41063af08d82Slm66018 41073af08d82Slm66018 channel_is_reset: 41083af08d82Slm66018 mutex_enter(&ldcp->tx_lock); 41093af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 41103af08d82Slm66018 mutex_exit(&ldcp->tx_lock); 41113af08d82Slm66018 return (ECONNRESET); 41121ae08745Sheppo } 41131ae08745Sheppo 41141ae08745Sheppo /* 411520ae46ebSha137994 * Fetch and buffer incoming packets so we can hand them back as 41161ae08745Sheppo * a basic byte stream. 41171ae08745Sheppo * 41181ae08745Sheppo * Enter and exit with ldcp->lock held by caller 41191ae08745Sheppo */ 41201ae08745Sheppo static int 41211ae08745Sheppo i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep) 41221ae08745Sheppo { 41231ae08745Sheppo int rv; 41241ae08745Sheppo size_t size; 41251ae08745Sheppo 41261ae08745Sheppo ASSERT(mutex_owned(&ldcp->lock)); 41271ae08745Sheppo 41281ae08745Sheppo D2(ldcp->id, "i_ldc_read_stream: (0x%llx) buffer size=%d", 41291ae08745Sheppo ldcp->id, *sizep); 41301ae08745Sheppo 41311ae08745Sheppo if (ldcp->stream_remains == 0) { 41321ae08745Sheppo size = ldcp->mtu; 41331ae08745Sheppo rv = i_ldc_read_packet(ldcp, 41341ae08745Sheppo (caddr_t)ldcp->stream_bufferp, &size); 41351ae08745Sheppo D2(ldcp->id, "i_ldc_read_stream: read packet (0x%llx) size=%d", 41361ae08745Sheppo ldcp->id, size); 41371ae08745Sheppo 41381ae08745Sheppo if (rv != 0) 41391ae08745Sheppo return (rv); 41401ae08745Sheppo 41411ae08745Sheppo ldcp->stream_remains = size; 41421ae08745Sheppo ldcp->stream_offset = 0; 41431ae08745Sheppo } 41441ae08745Sheppo 41451ae08745Sheppo size = MIN(ldcp->stream_remains, *sizep); 41461ae08745Sheppo 41471ae08745Sheppo bcopy(ldcp->stream_bufferp + ldcp->stream_offset, target_bufp, size); 41481ae08745Sheppo ldcp->stream_offset += size; 41491ae08745Sheppo ldcp->stream_remains -= size; 41501ae08745Sheppo 41511ae08745Sheppo D2(ldcp->id, "i_ldc_read_stream: (0x%llx) fill from buffer size=%d", 41521ae08745Sheppo ldcp->id, size); 41531ae08745Sheppo 41541ae08745Sheppo *sizep = size; 41551ae08745Sheppo return (0); 41561ae08745Sheppo } 41571ae08745Sheppo 41581ae08745Sheppo /* 41591ae08745Sheppo * Write specified amount of bytes to the channel 41601ae08745Sheppo * in multiple pkts of pkt_payload size. Each 41611ae08745Sheppo * packet is tagged with an unique packet ID in 4162e1ebb9ecSlm66018 * the case of a reliable link. 41631ae08745Sheppo * 41641ae08745Sheppo * On return, size contains the number of bytes written. 41651ae08745Sheppo */ 41661ae08745Sheppo int 41671ae08745Sheppo ldc_write(ldc_handle_t handle, caddr_t buf, size_t *sizep) 41681ae08745Sheppo { 41691ae08745Sheppo ldc_chan_t *ldcp; 41701ae08745Sheppo int rv = 0; 41711ae08745Sheppo 41721ae08745Sheppo if (handle == NULL) { 41731ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_write: invalid channel handle\n"); 41741ae08745Sheppo return (EINVAL); 41751ae08745Sheppo } 41761ae08745Sheppo ldcp = (ldc_chan_t *)handle; 41771ae08745Sheppo 4178d10e4ef2Snarayan /* check if writes can occur */ 4179d10e4ef2Snarayan if (!mutex_tryenter(&ldcp->tx_lock)) { 4180d10e4ef2Snarayan /* 4181d10e4ef2Snarayan * Could not get the lock - channel could 4182d10e4ef2Snarayan * be in the process of being unconfigured 4183d10e4ef2Snarayan * or reader has encountered an error 4184d10e4ef2Snarayan */ 4185d10e4ef2Snarayan return (EAGAIN); 4186d10e4ef2Snarayan } 41871ae08745Sheppo 41881ae08745Sheppo /* check if non-zero data to write */ 41891ae08745Sheppo if (buf == NULL || sizep == NULL) { 41901ae08745Sheppo DWARN(ldcp->id, "ldc_write: (0x%llx) invalid data write\n", 41911ae08745Sheppo ldcp->id); 4192d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 41931ae08745Sheppo return (EINVAL); 41941ae08745Sheppo } 41951ae08745Sheppo 41961ae08745Sheppo if (*sizep == 0) { 41971ae08745Sheppo DWARN(ldcp->id, "ldc_write: (0x%llx) write size of zero\n", 41981ae08745Sheppo ldcp->id); 4199d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 42001ae08745Sheppo return (0); 42011ae08745Sheppo } 42021ae08745Sheppo 42031ae08745Sheppo /* Check if channel is UP for data exchange */ 42041ae08745Sheppo if (ldcp->tstate != TS_UP) { 42051ae08745Sheppo DWARN(ldcp->id, 42061ae08745Sheppo "ldc_write: (0x%llx) channel is not in UP state\n", 42071ae08745Sheppo ldcp->id); 42081ae08745Sheppo *sizep = 0; 42091ae08745Sheppo rv = ECONNRESET; 42101ae08745Sheppo } else { 42111ae08745Sheppo rv = ldcp->write_p(ldcp, buf, sizep); 42121ae08745Sheppo } 42131ae08745Sheppo 4214d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 42151ae08745Sheppo 42161ae08745Sheppo return (rv); 42171ae08745Sheppo } 42181ae08745Sheppo 42191ae08745Sheppo /* 42201ae08745Sheppo * Write a raw packet to the channel 42211ae08745Sheppo * On return, size contains the number of bytes written. 42221ae08745Sheppo */ 42231ae08745Sheppo static int 42241ae08745Sheppo i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep) 42251ae08745Sheppo { 42261ae08745Sheppo ldc_msg_t *ldcmsg; 42271ae08745Sheppo uint64_t tx_head, tx_tail, new_tail; 42281ae08745Sheppo int rv = 0; 42291ae08745Sheppo size_t size; 42301ae08745Sheppo 4231d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 42321ae08745Sheppo ASSERT(ldcp->mode == LDC_MODE_RAW); 42331ae08745Sheppo 42341ae08745Sheppo size = *sizep; 42351ae08745Sheppo 42361ae08745Sheppo /* 42371ae08745Sheppo * Check to see if the packet size is less than or 42381ae08745Sheppo * equal to packet size support in raw mode 42391ae08745Sheppo */ 42401ae08745Sheppo if (size > ldcp->pkt_payload) { 42411ae08745Sheppo DWARN(ldcp->id, 42421ae08745Sheppo "ldc_write: (0x%llx) invalid size (0x%llx) for RAW mode\n", 42431ae08745Sheppo ldcp->id, *sizep); 42441ae08745Sheppo *sizep = 0; 42451ae08745Sheppo return (EMSGSIZE); 42461ae08745Sheppo } 42471ae08745Sheppo 42481ae08745Sheppo /* get the qptrs for the tx queue */ 42491ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 42501ae08745Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 42511ae08745Sheppo if (rv != 0) { 42521ae08745Sheppo cmn_err(CE_WARN, 42531ae08745Sheppo "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id); 42541ae08745Sheppo *sizep = 0; 42551ae08745Sheppo return (EIO); 42561ae08745Sheppo } 42571ae08745Sheppo 42581ae08745Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN || 42591ae08745Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 42601ae08745Sheppo DWARN(ldcp->id, 42611ae08745Sheppo "ldc_write: (0x%llx) channel down/reset\n", ldcp->id); 4262d10e4ef2Snarayan 42631ae08745Sheppo *sizep = 0; 4264d10e4ef2Snarayan if (mutex_tryenter(&ldcp->lock)) { 42653af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 4266d10e4ef2Snarayan mutex_exit(&ldcp->lock); 4267d10e4ef2Snarayan } else { 4268d10e4ef2Snarayan /* 4269d10e4ef2Snarayan * Release Tx lock, and then reacquire channel 4270d10e4ef2Snarayan * and Tx lock in correct order 4271d10e4ef2Snarayan */ 4272d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 4273d10e4ef2Snarayan mutex_enter(&ldcp->lock); 4274d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 42753af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 4276d10e4ef2Snarayan mutex_exit(&ldcp->lock); 4277d10e4ef2Snarayan } 42781ae08745Sheppo return (ECONNRESET); 42791ae08745Sheppo } 42801ae08745Sheppo 42811ae08745Sheppo tx_tail = ldcp->tx_tail; 42821ae08745Sheppo tx_head = ldcp->tx_head; 42831ae08745Sheppo new_tail = (tx_tail + LDC_PACKET_SIZE) & 42841ae08745Sheppo ((ldcp->tx_q_entries-1) << LDC_PACKET_SHIFT); 42851ae08745Sheppo 42861ae08745Sheppo if (new_tail == tx_head) { 42871ae08745Sheppo DWARN(DBG_ALL_LDCS, 42881ae08745Sheppo "ldc_write: (0x%llx) TX queue is full\n", ldcp->id); 42891ae08745Sheppo *sizep = 0; 42901ae08745Sheppo return (EWOULDBLOCK); 42911ae08745Sheppo } 42921ae08745Sheppo 42931ae08745Sheppo D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d", 42941ae08745Sheppo ldcp->id, size); 42951ae08745Sheppo 42961ae08745Sheppo /* Send the data now */ 42971ae08745Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 42981ae08745Sheppo 42991ae08745Sheppo /* copy the data into pkt */ 43001ae08745Sheppo bcopy((uint8_t *)buf, ldcmsg, size); 43011ae08745Sheppo 43021ae08745Sheppo /* increment tail */ 43031ae08745Sheppo tx_tail = new_tail; 43041ae08745Sheppo 43051ae08745Sheppo /* 43061ae08745Sheppo * All packets have been copied into the TX queue 43071ae08745Sheppo * update the tail ptr in the HV 43081ae08745Sheppo */ 43091ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 43101ae08745Sheppo if (rv) { 43111ae08745Sheppo if (rv == EWOULDBLOCK) { 43121ae08745Sheppo DWARN(ldcp->id, "ldc_write: (0x%llx) write timed out\n", 43131ae08745Sheppo ldcp->id); 43141ae08745Sheppo *sizep = 0; 43151ae08745Sheppo return (EWOULDBLOCK); 43161ae08745Sheppo } 43171ae08745Sheppo 43181ae08745Sheppo *sizep = 0; 4319d10e4ef2Snarayan if (mutex_tryenter(&ldcp->lock)) { 43203af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 4321d10e4ef2Snarayan mutex_exit(&ldcp->lock); 4322d10e4ef2Snarayan } else { 4323d10e4ef2Snarayan /* 4324d10e4ef2Snarayan * Release Tx lock, and then reacquire channel 4325d10e4ef2Snarayan * and Tx lock in correct order 4326d10e4ef2Snarayan */ 4327d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 4328d10e4ef2Snarayan mutex_enter(&ldcp->lock); 4329d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 43303af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 4331d10e4ef2Snarayan mutex_exit(&ldcp->lock); 4332d10e4ef2Snarayan } 43331ae08745Sheppo return (ECONNRESET); 43341ae08745Sheppo } 43351ae08745Sheppo 43361ae08745Sheppo ldcp->tx_tail = tx_tail; 43371ae08745Sheppo *sizep = size; 43381ae08745Sheppo 43391ae08745Sheppo D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, size); 43401ae08745Sheppo 43411ae08745Sheppo return (rv); 43421ae08745Sheppo } 43431ae08745Sheppo 43441ae08745Sheppo 43451ae08745Sheppo /* 43461ae08745Sheppo * Write specified amount of bytes to the channel 43471ae08745Sheppo * in multiple pkts of pkt_payload size. Each 43481ae08745Sheppo * packet is tagged with an unique packet ID in 4349e1ebb9ecSlm66018 * the case of a reliable link. 43501ae08745Sheppo * 43511ae08745Sheppo * On return, size contains the number of bytes written. 43521ae08745Sheppo * This function needs to ensure that the write size is < MTU size 43531ae08745Sheppo */ 43541ae08745Sheppo static int 43551ae08745Sheppo i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t buf, size_t *size) 43561ae08745Sheppo { 43571ae08745Sheppo ldc_msg_t *ldcmsg; 43581ae08745Sheppo uint64_t tx_head, tx_tail, new_tail, start; 43591ae08745Sheppo uint64_t txq_size_mask, numavail; 43601ae08745Sheppo uint8_t *msgbuf, *source = (uint8_t *)buf; 43611ae08745Sheppo size_t len, bytes_written = 0, remaining; 43621ae08745Sheppo int rv; 43631ae08745Sheppo uint32_t curr_seqid; 43641ae08745Sheppo 4365d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 43661ae08745Sheppo 43671ae08745Sheppo ASSERT(ldcp->mode == LDC_MODE_RELIABLE || 436820ae46ebSha137994 ldcp->mode == LDC_MODE_UNRELIABLE); 43691ae08745Sheppo 43701ae08745Sheppo /* compute mask for increment */ 43711ae08745Sheppo txq_size_mask = (ldcp->tx_q_entries - 1) << LDC_PACKET_SHIFT; 43721ae08745Sheppo 43731ae08745Sheppo /* get the qptrs for the tx queue */ 43741ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 43751ae08745Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 43761ae08745Sheppo if (rv != 0) { 43771ae08745Sheppo cmn_err(CE_WARN, 43781ae08745Sheppo "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id); 43791ae08745Sheppo *size = 0; 43801ae08745Sheppo return (EIO); 43811ae08745Sheppo } 43821ae08745Sheppo 43831ae08745Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN || 43841ae08745Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 43851ae08745Sheppo DWARN(ldcp->id, 43861ae08745Sheppo "ldc_write: (0x%llx) channel down/reset\n", ldcp->id); 43871ae08745Sheppo *size = 0; 4388d10e4ef2Snarayan if (mutex_tryenter(&ldcp->lock)) { 43893af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 4390d10e4ef2Snarayan mutex_exit(&ldcp->lock); 4391d10e4ef2Snarayan } else { 4392d10e4ef2Snarayan /* 4393d10e4ef2Snarayan * Release Tx lock, and then reacquire channel 4394d10e4ef2Snarayan * and Tx lock in correct order 4395d10e4ef2Snarayan */ 4396d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 4397d10e4ef2Snarayan mutex_enter(&ldcp->lock); 4398d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 43993af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 4400d10e4ef2Snarayan mutex_exit(&ldcp->lock); 4401d10e4ef2Snarayan } 44021ae08745Sheppo return (ECONNRESET); 44031ae08745Sheppo } 44041ae08745Sheppo 44051ae08745Sheppo tx_tail = ldcp->tx_tail; 44061ae08745Sheppo new_tail = (tx_tail + LDC_PACKET_SIZE) % 44071ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 44081ae08745Sheppo 44091ae08745Sheppo /* 441022f747efSnarayan * Check to see if the queue is full. The check is done using 441122f747efSnarayan * the appropriate head based on the link mode. 44121ae08745Sheppo */ 441322f747efSnarayan i_ldc_get_tx_head(ldcp, &tx_head); 441422f747efSnarayan 44151ae08745Sheppo if (new_tail == tx_head) { 44161ae08745Sheppo DWARN(DBG_ALL_LDCS, 44171ae08745Sheppo "ldc_write: (0x%llx) TX queue is full\n", ldcp->id); 44181ae08745Sheppo *size = 0; 44191ae08745Sheppo return (EWOULDBLOCK); 44201ae08745Sheppo } 44211ae08745Sheppo 44221ae08745Sheppo /* 44231ae08745Sheppo * Make sure that the LDC Tx queue has enough space 44241ae08745Sheppo */ 44251ae08745Sheppo numavail = (tx_head >> LDC_PACKET_SHIFT) - (tx_tail >> LDC_PACKET_SHIFT) 44261ae08745Sheppo + ldcp->tx_q_entries - 1; 44271ae08745Sheppo numavail %= ldcp->tx_q_entries; 44281ae08745Sheppo 44291ae08745Sheppo if (*size > (numavail * ldcp->pkt_payload)) { 44301ae08745Sheppo DWARN(DBG_ALL_LDCS, 44311ae08745Sheppo "ldc_write: (0x%llx) TX queue has no space\n", ldcp->id); 44321ae08745Sheppo return (EWOULDBLOCK); 44331ae08745Sheppo } 44341ae08745Sheppo 44351ae08745Sheppo D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d", 44361ae08745Sheppo ldcp->id, *size); 44371ae08745Sheppo 44381ae08745Sheppo /* Send the data now */ 44391ae08745Sheppo bytes_written = 0; 44401ae08745Sheppo curr_seqid = ldcp->last_msg_snt; 44411ae08745Sheppo start = tx_tail; 44421ae08745Sheppo 44431ae08745Sheppo while (*size > bytes_written) { 44441ae08745Sheppo 44451ae08745Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 44461ae08745Sheppo 444720ae46ebSha137994 msgbuf = (uint8_t *)((ldcp->mode == LDC_MODE_RELIABLE) ? 444822f747efSnarayan ldcmsg->rdata : ldcmsg->udata); 44491ae08745Sheppo 44501ae08745Sheppo ldcmsg->type = LDC_DATA; 44511ae08745Sheppo ldcmsg->stype = LDC_INFO; 44521ae08745Sheppo ldcmsg->ctrl = 0; 44531ae08745Sheppo 44541ae08745Sheppo remaining = *size - bytes_written; 44551ae08745Sheppo len = min(ldcp->pkt_payload, remaining); 44561ae08745Sheppo ldcmsg->env = (uint8_t)len; 44571ae08745Sheppo 44581ae08745Sheppo curr_seqid++; 44591ae08745Sheppo ldcmsg->seqid = curr_seqid; 44601ae08745Sheppo 44611ae08745Sheppo /* copy the data into pkt */ 44621ae08745Sheppo bcopy(source, msgbuf, len); 44631ae08745Sheppo 44641ae08745Sheppo source += len; 44651ae08745Sheppo bytes_written += len; 44661ae08745Sheppo 44671ae08745Sheppo /* increment tail */ 44681ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) & txq_size_mask; 44691ae08745Sheppo 44701ae08745Sheppo ASSERT(tx_tail != tx_head); 44711ae08745Sheppo } 44721ae08745Sheppo 44731ae08745Sheppo /* Set the start and stop bits */ 44741ae08745Sheppo ldcmsg->env |= LDC_FRAG_STOP; 44751ae08745Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + start); 44761ae08745Sheppo ldcmsg->env |= LDC_FRAG_START; 44771ae08745Sheppo 44781ae08745Sheppo /* 44791ae08745Sheppo * All packets have been copied into the TX queue 44801ae08745Sheppo * update the tail ptr in the HV 44811ae08745Sheppo */ 44821ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 44831ae08745Sheppo if (rv == 0) { 44841ae08745Sheppo ldcp->tx_tail = tx_tail; 44851ae08745Sheppo ldcp->last_msg_snt = curr_seqid; 44861ae08745Sheppo *size = bytes_written; 44871ae08745Sheppo } else { 44881ae08745Sheppo int rv2; 44891ae08745Sheppo 44901ae08745Sheppo if (rv != EWOULDBLOCK) { 44911ae08745Sheppo *size = 0; 4492d10e4ef2Snarayan if (mutex_tryenter(&ldcp->lock)) { 44933af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 4494d10e4ef2Snarayan mutex_exit(&ldcp->lock); 4495d10e4ef2Snarayan } else { 4496d10e4ef2Snarayan /* 4497d10e4ef2Snarayan * Release Tx lock, and then reacquire channel 4498d10e4ef2Snarayan * and Tx lock in correct order 4499d10e4ef2Snarayan */ 4500d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 4501d10e4ef2Snarayan mutex_enter(&ldcp->lock); 4502d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 45033af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 4504d10e4ef2Snarayan mutex_exit(&ldcp->lock); 4505d10e4ef2Snarayan } 45061ae08745Sheppo return (ECONNRESET); 45071ae08745Sheppo } 45081ae08745Sheppo 4509cb112a14Slm66018 D1(ldcp->id, "hv_tx_set_tail returns 0x%x (head 0x%x, " 45101ae08745Sheppo "old tail 0x%x, new tail 0x%x, qsize=0x%x)\n", 45111ae08745Sheppo rv, ldcp->tx_head, ldcp->tx_tail, tx_tail, 45121ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT)); 45131ae08745Sheppo 45141ae08745Sheppo rv2 = hv_ldc_tx_get_state(ldcp->id, 45151ae08745Sheppo &tx_head, &tx_tail, &ldcp->link_state); 45161ae08745Sheppo 4517cb112a14Slm66018 D1(ldcp->id, "hv_ldc_tx_get_state returns 0x%x " 45181ae08745Sheppo "(head 0x%x, tail 0x%x state 0x%x)\n", 45191ae08745Sheppo rv2, tx_head, tx_tail, ldcp->link_state); 45201ae08745Sheppo 45211ae08745Sheppo *size = 0; 45221ae08745Sheppo } 45231ae08745Sheppo 45241ae08745Sheppo D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, *size); 45251ae08745Sheppo 45261ae08745Sheppo return (rv); 45271ae08745Sheppo } 45281ae08745Sheppo 45291ae08745Sheppo /* 45301ae08745Sheppo * Write specified amount of bytes to the channel 45311ae08745Sheppo * in multiple pkts of pkt_payload size. Each 45321ae08745Sheppo * packet is tagged with an unique packet ID in 4533e1ebb9ecSlm66018 * the case of a reliable link. 45341ae08745Sheppo * 45351ae08745Sheppo * On return, size contains the number of bytes written. 45361ae08745Sheppo * This function needs to ensure that the write size is < MTU size 45371ae08745Sheppo */ 45381ae08745Sheppo static int 45391ae08745Sheppo i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep) 45401ae08745Sheppo { 4541d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 454220ae46ebSha137994 ASSERT(ldcp->mode == LDC_MODE_RELIABLE); 45431ae08745Sheppo 45441ae08745Sheppo /* Truncate packet to max of MTU size */ 45451ae08745Sheppo if (*sizep > ldcp->mtu) *sizep = ldcp->mtu; 45461ae08745Sheppo return (i_ldc_write_packet(ldcp, buf, sizep)); 45471ae08745Sheppo } 45481ae08745Sheppo 45491ae08745Sheppo 45501ae08745Sheppo /* 45511ae08745Sheppo * Interfaces for channel nexus to register/unregister with LDC module 45521ae08745Sheppo * The nexus will register functions to be used to register individual 45531ae08745Sheppo * channels with the nexus and enable interrupts for the channels 45541ae08745Sheppo */ 45551ae08745Sheppo int 45561ae08745Sheppo ldc_register(ldc_cnex_t *cinfo) 45571ae08745Sheppo { 45581ae08745Sheppo ldc_chan_t *ldcp; 45591ae08745Sheppo 45601ae08745Sheppo if (cinfo == NULL || cinfo->dip == NULL || 45611ae08745Sheppo cinfo->reg_chan == NULL || cinfo->unreg_chan == NULL || 45621ae08745Sheppo cinfo->add_intr == NULL || cinfo->rem_intr == NULL || 45631ae08745Sheppo cinfo->clr_intr == NULL) { 45641ae08745Sheppo 45651ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_register: invalid nexus info\n"); 45661ae08745Sheppo return (EINVAL); 45671ae08745Sheppo } 45681ae08745Sheppo 45691ae08745Sheppo mutex_enter(&ldcssp->lock); 45701ae08745Sheppo 45711ae08745Sheppo /* nexus registration */ 45721ae08745Sheppo ldcssp->cinfo.dip = cinfo->dip; 45731ae08745Sheppo ldcssp->cinfo.reg_chan = cinfo->reg_chan; 45741ae08745Sheppo ldcssp->cinfo.unreg_chan = cinfo->unreg_chan; 45751ae08745Sheppo ldcssp->cinfo.add_intr = cinfo->add_intr; 45761ae08745Sheppo ldcssp->cinfo.rem_intr = cinfo->rem_intr; 45771ae08745Sheppo ldcssp->cinfo.clr_intr = cinfo->clr_intr; 45781ae08745Sheppo 45791ae08745Sheppo /* register any channels that might have been previously initialized */ 45801ae08745Sheppo ldcp = ldcssp->chan_list; 45811ae08745Sheppo while (ldcp) { 45821ae08745Sheppo if ((ldcp->tstate & TS_QCONF_RDY) && 45831ae08745Sheppo (ldcp->tstate & TS_CNEX_RDY) == 0) 45841ae08745Sheppo (void) i_ldc_register_channel(ldcp); 45851ae08745Sheppo 45861ae08745Sheppo ldcp = ldcp->next; 45871ae08745Sheppo } 45881ae08745Sheppo 45891ae08745Sheppo mutex_exit(&ldcssp->lock); 45901ae08745Sheppo 45911ae08745Sheppo return (0); 45921ae08745Sheppo } 45931ae08745Sheppo 45941ae08745Sheppo int 45951ae08745Sheppo ldc_unregister(ldc_cnex_t *cinfo) 45961ae08745Sheppo { 45971ae08745Sheppo if (cinfo == NULL || cinfo->dip == NULL) { 45981ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid nexus info\n"); 45991ae08745Sheppo return (EINVAL); 46001ae08745Sheppo } 46011ae08745Sheppo 46021ae08745Sheppo mutex_enter(&ldcssp->lock); 46031ae08745Sheppo 46041ae08745Sheppo if (cinfo->dip != ldcssp->cinfo.dip) { 46051ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid dip\n"); 46061ae08745Sheppo mutex_exit(&ldcssp->lock); 46071ae08745Sheppo return (EINVAL); 46081ae08745Sheppo } 46091ae08745Sheppo 46101ae08745Sheppo /* nexus unregister */ 46111ae08745Sheppo ldcssp->cinfo.dip = NULL; 46121ae08745Sheppo ldcssp->cinfo.reg_chan = NULL; 46131ae08745Sheppo ldcssp->cinfo.unreg_chan = NULL; 46141ae08745Sheppo ldcssp->cinfo.add_intr = NULL; 46151ae08745Sheppo ldcssp->cinfo.rem_intr = NULL; 46161ae08745Sheppo ldcssp->cinfo.clr_intr = NULL; 46171ae08745Sheppo 46181ae08745Sheppo mutex_exit(&ldcssp->lock); 46191ae08745Sheppo 46201ae08745Sheppo return (0); 46211ae08745Sheppo } 4622