11991Sheppo /* 21991Sheppo * CDDL HEADER START 31991Sheppo * 41991Sheppo * The contents of this file are subject to the terms of the 51991Sheppo * Common Development and Distribution License (the "License"). 61991Sheppo * You may not use this file except in compliance with the License. 71991Sheppo * 81991Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91991Sheppo * or http://www.opensolaris.org/os/licensing. 101991Sheppo * See the License for the specific language governing permissions 111991Sheppo * and limitations under the License. 121991Sheppo * 131991Sheppo * When distributing Covered Code, include this CDDL HEADER in each 141991Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151991Sheppo * If applicable, add the following below this CDDL HEADER, with the 161991Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 171991Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 181991Sheppo * 191991Sheppo * CDDL HEADER END 201991Sheppo */ 211991Sheppo 221991Sheppo /* 235944Sha137994 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 241991Sheppo * Use is subject to license terms. 251991Sheppo */ 261991Sheppo 271991Sheppo /* 282410Slm66018 * sun4v LDC Link Layer 291991Sheppo */ 301991Sheppo #include <sys/types.h> 311991Sheppo #include <sys/file.h> 321991Sheppo #include <sys/errno.h> 331991Sheppo #include <sys/open.h> 341991Sheppo #include <sys/cred.h> 351991Sheppo #include <sys/kmem.h> 361991Sheppo #include <sys/conf.h> 371991Sheppo #include <sys/cmn_err.h> 381991Sheppo #include <sys/ksynch.h> 391991Sheppo #include <sys/modctl.h> 401991Sheppo #include <sys/stat.h> /* needed for S_IFBLK and S_IFCHR */ 411991Sheppo #include <sys/debug.h> 421991Sheppo #include <sys/cred.h> 431991Sheppo #include <sys/promif.h> 441991Sheppo #include <sys/ddi.h> 451991Sheppo #include <sys/sunddi.h> 461991Sheppo #include <sys/cyclic.h> 471991Sheppo #include <sys/machsystm.h> 481991Sheppo #include <sys/vm.h> 491991Sheppo #include <sys/cpu.h> 501991Sheppo #include <sys/intreg.h> 511991Sheppo #include <sys/machcpuvar.h> 522531Snarayan #include <sys/mmu.h> 532531Snarayan #include <sys/pte.h> 542531Snarayan #include <vm/hat.h> 552531Snarayan #include <vm/as.h> 562531Snarayan #include <vm/hat_sfmmu.h> 572531Snarayan #include <sys/vm_machparam.h> 582531Snarayan #include <vm/seg_kmem.h> 592531Snarayan #include <vm/seg_kpm.h> 601991Sheppo #include <sys/note.h> 611991Sheppo #include <sys/ivintr.h> 621991Sheppo #include <sys/hypervisor_api.h> 631991Sheppo #include <sys/ldc.h> 641991Sheppo #include <sys/ldc_impl.h> 651991Sheppo #include <sys/cnex.h> 661991Sheppo #include <sys/hsvc.h> 675944Sha137994 #include <sys/sdt.h> 681991Sheppo 691991Sheppo /* Core internal functions */ 706408Sha137994 int i_ldc_h2v_error(int h_error); 716408Sha137994 void i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset); 726408Sha137994 731991Sheppo static int i_ldc_txq_reconf(ldc_chan_t *ldcp); 742793Slm66018 static int i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset); 752841Snarayan static int i_ldc_rxq_drain(ldc_chan_t *ldcp); 761991Sheppo static void i_ldc_reset_state(ldc_chan_t *ldcp); 771991Sheppo 781991Sheppo static int i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail); 794690Snarayan static void i_ldc_get_tx_head(ldc_chan_t *ldcp, uint64_t *head); 801991Sheppo static int i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail); 811991Sheppo static int i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head); 821991Sheppo static int i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype, 831991Sheppo uint8_t ctrlmsg); 841991Sheppo 855944Sha137994 static int i_ldc_set_rxdq_head(ldc_chan_t *ldcp, uint64_t head); 865944Sha137994 static void i_ldc_rxdq_copy(ldc_chan_t *ldcp, uint64_t *head); 875944Sha137994 static uint64_t i_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, 885944Sha137994 uint64_t *tail, uint64_t *link_state); 895944Sha137994 static uint64_t i_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, 905944Sha137994 uint64_t *tail, uint64_t *link_state); 915944Sha137994 static int i_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head, 925944Sha137994 uint64_t rx_tail); 935944Sha137994 static uint_t i_ldc_chkq(ldc_chan_t *ldcp); 945944Sha137994 951991Sheppo /* Interrupt handling functions */ 961991Sheppo static uint_t i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2); 971991Sheppo static uint_t i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2); 985944Sha137994 static uint_t i_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client, 995944Sha137994 uint64_t *notify_event); 1001991Sheppo static void i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype); 1011991Sheppo 1021991Sheppo /* Read method functions */ 1031991Sheppo static int i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep); 1041991Sheppo static int i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp, 1051991Sheppo size_t *sizep); 1061991Sheppo static int i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp, 1071991Sheppo size_t *sizep); 1081991Sheppo 1091991Sheppo /* Write method functions */ 1101991Sheppo static int i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t target_bufp, 1111991Sheppo size_t *sizep); 1121991Sheppo static int i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t target_bufp, 1131991Sheppo size_t *sizep); 1141991Sheppo static int i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t target_bufp, 1151991Sheppo size_t *sizep); 1161991Sheppo 1171991Sheppo /* Pkt processing internal functions */ 1181991Sheppo static int i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg); 1191991Sheppo static int i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg); 1201991Sheppo static int i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg); 1211991Sheppo static int i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg); 1221991Sheppo static int i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg); 1231991Sheppo static int i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg); 1241991Sheppo static int i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg); 1251991Sheppo 1261991Sheppo /* LDC Version */ 1271991Sheppo static ldc_ver_t ldc_versions[] = { {1, 0} }; 1281991Sheppo 1291991Sheppo /* number of supported versions */ 1301991Sheppo #define LDC_NUM_VERS (sizeof (ldc_versions) / sizeof (ldc_versions[0])) 1311991Sheppo 1325944Sha137994 /* Invalid value for the ldc_chan_t rx_ack_head field */ 1335944Sha137994 #define ACKPEEK_HEAD_INVALID ((uint64_t)-1) 1345944Sha137994 1355944Sha137994 1361991Sheppo /* Module State Pointer */ 1376408Sha137994 ldc_soft_state_t *ldcssp; 1381991Sheppo 1391991Sheppo static struct modldrv md = { 1401991Sheppo &mod_miscops, /* This is a misc module */ 141*7799SRichard.Bean@Sun.COM "sun4v LDC module", /* Name of the module */ 1421991Sheppo }; 1431991Sheppo 1441991Sheppo static struct modlinkage ml = { 1451991Sheppo MODREV_1, 1461991Sheppo &md, 1471991Sheppo NULL 1481991Sheppo }; 1491991Sheppo 1501991Sheppo static uint64_t ldc_sup_minor; /* Supported minor number */ 1511991Sheppo static hsvc_info_t ldc_hsvc = { 1526845Sha137994 HSVC_REV_1, NULL, HSVC_GROUP_LDC, 1, 1, "ldc" 1531991Sheppo }; 1541991Sheppo 1552531Snarayan /* 1562410Slm66018 * The no. of MTU size messages that can be stored in 1572410Slm66018 * the LDC Tx queue. The number of Tx queue entries is 1582410Slm66018 * then computed as (mtu * mtu_msgs)/sizeof(queue_entry) 1592410Slm66018 */ 1602410Slm66018 uint64_t ldc_mtu_msgs = LDC_MTU_MSGS; 1612410Slm66018 1622410Slm66018 /* 1632410Slm66018 * The minimum queue length. This is the size of the smallest 1642410Slm66018 * LDC queue. If the computed value is less than this default, 1652410Slm66018 * the queue length is rounded up to 'ldc_queue_entries'. 1662410Slm66018 */ 1672410Slm66018 uint64_t ldc_queue_entries = LDC_QUEUE_ENTRIES; 1682410Slm66018 1692410Slm66018 /* 1705944Sha137994 * The length of the reliable-mode data queue in terms of the LDC 1715944Sha137994 * receive queue length. i.e., the number of times larger than the 1725944Sha137994 * LDC receive queue that the data queue should be. The HV receive 1735944Sha137994 * queue is required to be a power of 2 and this implementation 1745944Sha137994 * assumes the data queue will also be a power of 2. By making the 1755944Sha137994 * multiplier a power of 2, we ensure the data queue will be a 1765944Sha137994 * power of 2. We use a multiplier because the receive queue is 1775944Sha137994 * sized to be sane relative to the MTU and the same is needed for 1785944Sha137994 * the data queue. 1795944Sha137994 */ 1805944Sha137994 uint64_t ldc_rxdq_multiplier = LDC_RXDQ_MULTIPLIER; 1815944Sha137994 1825944Sha137994 /* 1832410Slm66018 * LDC retry count and delay - when the HV returns EWOULDBLOCK 1842410Slm66018 * the operation is retried 'ldc_max_retries' times with a 1852410Slm66018 * wait of 'ldc_delay' usecs between each retry. 1862032Slm66018 */ 1872032Slm66018 int ldc_max_retries = LDC_MAX_RETRIES; 1882032Slm66018 clock_t ldc_delay = LDC_DELAY; 1892032Slm66018 1903151Ssg70180 /* 1913151Ssg70180 * delay between each retry of channel unregistration in 1923151Ssg70180 * ldc_close(), to wait for pending interrupts to complete. 1933151Ssg70180 */ 1943151Ssg70180 clock_t ldc_close_delay = LDC_CLOSE_DELAY; 1953151Ssg70180 1961991Sheppo #ifdef DEBUG 1971991Sheppo 1981991Sheppo /* 1991991Sheppo * Print debug messages 2001991Sheppo * 2011991Sheppo * set ldcdbg to 0x7 for enabling all msgs 2021991Sheppo * 0x4 - Warnings 2031991Sheppo * 0x2 - All debug messages 2041991Sheppo * 0x1 - Minimal debug messages 2051991Sheppo * 2061991Sheppo * set ldcdbgchan to the channel number you want to debug 2071991Sheppo * setting it to -1 prints debug messages for all channels 2081991Sheppo * NOTE: ldcdbgchan has no effect on error messages 2091991Sheppo */ 2101991Sheppo 2111991Sheppo int ldcdbg = 0x0; 2121991Sheppo int64_t ldcdbgchan = DBG_ALL_LDCS; 2133560Snarayan uint64_t ldc_inject_err_flag = 0; 2141991Sheppo 2156408Sha137994 void 2161991Sheppo ldcdebug(int64_t id, const char *fmt, ...) 2171991Sheppo { 2181991Sheppo char buf[512]; 2191991Sheppo va_list ap; 2201991Sheppo 2211991Sheppo /* 2221991Sheppo * Do not return if, 2231991Sheppo * caller wants to print it anyway - (id == DBG_ALL_LDCS) 2241991Sheppo * debug channel is set to all LDCs - (ldcdbgchan == DBG_ALL_LDCS) 2251991Sheppo * debug channel = caller specified channel 2261991Sheppo */ 2271991Sheppo if ((id != DBG_ALL_LDCS) && 2281991Sheppo (ldcdbgchan != DBG_ALL_LDCS) && 2291991Sheppo (ldcdbgchan != id)) { 2301991Sheppo return; 2311991Sheppo } 2321991Sheppo 2331991Sheppo va_start(ap, fmt); 2341991Sheppo (void) vsprintf(buf, fmt, ap); 2351991Sheppo va_end(ap); 2361991Sheppo 2372793Slm66018 cmn_err(CE_CONT, "?%s", buf); 2382793Slm66018 } 2392793Slm66018 2406845Sha137994 #define LDC_ERR_RESET 0x1 2416845Sha137994 #define LDC_ERR_PKTLOSS 0x2 2426845Sha137994 #define LDC_ERR_DQFULL 0x4 2436845Sha137994 #define LDC_ERR_DRNGCLEAR 0x8 2443560Snarayan 2452793Slm66018 static boolean_t 2463560Snarayan ldc_inject_error(ldc_chan_t *ldcp, uint64_t error) 2472793Slm66018 { 2482793Slm66018 if ((ldcdbgchan != DBG_ALL_LDCS) && (ldcdbgchan != ldcp->id)) 2492793Slm66018 return (B_FALSE); 2502793Slm66018 2513560Snarayan if ((ldc_inject_err_flag & error) == 0) 2522793Slm66018 return (B_FALSE); 2532793Slm66018 2542793Slm66018 /* clear the injection state */ 2553560Snarayan ldc_inject_err_flag &= ~error; 2562793Slm66018 2572793Slm66018 return (B_TRUE); 2581991Sheppo } 2591991Sheppo 2601991Sheppo #define D1 \ 2611991Sheppo if (ldcdbg & 0x01) \ 2621991Sheppo ldcdebug 2631991Sheppo 2641991Sheppo #define D2 \ 2651991Sheppo if (ldcdbg & 0x02) \ 2661991Sheppo ldcdebug 2671991Sheppo 2681991Sheppo #define DWARN \ 2691991Sheppo if (ldcdbg & 0x04) \ 2701991Sheppo ldcdebug 2711991Sheppo 2721991Sheppo #define DUMP_PAYLOAD(id, addr) \ 2731991Sheppo { \ 2741991Sheppo char buf[65*3]; \ 2751991Sheppo int i; \ 2761991Sheppo uint8_t *src = (uint8_t *)addr; \ 2771991Sheppo for (i = 0; i < 64; i++, src++) \ 2781991Sheppo (void) sprintf(&buf[i * 3], "|%02x", *src); \ 2791991Sheppo (void) sprintf(&buf[i * 3], "|\n"); \ 2801991Sheppo D2((id), "payload: %s", buf); \ 2811991Sheppo } 2821991Sheppo 2831991Sheppo #define DUMP_LDC_PKT(c, s, addr) \ 2841991Sheppo { \ 2851991Sheppo ldc_msg_t *msg = (ldc_msg_t *)(addr); \ 2861991Sheppo uint32_t mid = ((c)->mode != LDC_MODE_RAW) ? msg->seqid : 0; \ 2871991Sheppo if (msg->type == LDC_DATA) { \ 2881991Sheppo D2((c)->id, "%s: msg%d (/%x/%x/%x/,env[%c%c,sz=%d])", \ 2891991Sheppo (s), mid, msg->type, msg->stype, msg->ctrl, \ 2901991Sheppo (msg->env & LDC_FRAG_START) ? 'B' : ' ', \ 2911991Sheppo (msg->env & LDC_FRAG_STOP) ? 'E' : ' ', \ 2921991Sheppo (msg->env & LDC_LEN_MASK)); \ 2931991Sheppo } else { \ 2941991Sheppo D2((c)->id, "%s: msg%d (/%x/%x/%x/,env=%x)", (s), \ 2951991Sheppo mid, msg->type, msg->stype, msg->ctrl, msg->env); \ 2961991Sheppo } \ 2971991Sheppo } 2981991Sheppo 2993560Snarayan #define LDC_INJECT_RESET(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_RESET) 3003560Snarayan #define LDC_INJECT_PKTLOSS(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_PKTLOSS) 3015944Sha137994 #define LDC_INJECT_DQFULL(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_DQFULL) 3026845Sha137994 #define LDC_INJECT_DRNGCLEAR(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_DRNGCLEAR) 3036845Sha137994 extern void i_ldc_mem_inject_dring_clear(ldc_chan_t *ldcp); 3042793Slm66018 3051991Sheppo #else 3061991Sheppo 3071991Sheppo #define DBG_ALL_LDCS -1 3081991Sheppo 3091991Sheppo #define D1 3101991Sheppo #define D2 3111991Sheppo #define DWARN 3121991Sheppo 3131991Sheppo #define DUMP_PAYLOAD(id, addr) 3141991Sheppo #define DUMP_LDC_PKT(c, s, addr) 3151991Sheppo 3162793Slm66018 #define LDC_INJECT_RESET(_ldcp) (B_FALSE) 3173560Snarayan #define LDC_INJECT_PKTLOSS(_ldcp) (B_FALSE) 3185944Sha137994 #define LDC_INJECT_DQFULL(_ldcp) (B_FALSE) 3196845Sha137994 #define LDC_INJECT_DRNGCLEAR(_ldcp) (B_FALSE) 3202793Slm66018 3211991Sheppo #endif 3221991Sheppo 3235944Sha137994 /* 3245944Sha137994 * dtrace SDT probes to ease tracing of the rx data queue and HV queue 3255944Sha137994 * lengths. Just pass the head, tail, and entries values so that the 3265944Sha137994 * length can be calculated in a dtrace script when the probe is enabled. 3275944Sha137994 */ 3285944Sha137994 #define TRACE_RXDQ_LENGTH(ldcp) \ 3295944Sha137994 DTRACE_PROBE4(rxdq__size, \ 3305944Sha137994 uint64_t, ldcp->id, \ 3315944Sha137994 uint64_t, ldcp->rx_dq_head, \ 3325944Sha137994 uint64_t, ldcp->rx_dq_tail, \ 3335944Sha137994 uint64_t, ldcp->rx_dq_entries) 3345944Sha137994 3355944Sha137994 #define TRACE_RXHVQ_LENGTH(ldcp, head, tail) \ 3365944Sha137994 DTRACE_PROBE4(rxhvq__size, \ 3375944Sha137994 uint64_t, ldcp->id, \ 3385944Sha137994 uint64_t, head, \ 3395944Sha137994 uint64_t, tail, \ 3405944Sha137994 uint64_t, ldcp->rx_q_entries) 3415944Sha137994 3425944Sha137994 /* A dtrace SDT probe to ease tracing of data queue copy operations */ 3435944Sha137994 #define TRACE_RXDQ_COPY(ldcp, bytes) \ 3445944Sha137994 DTRACE_PROBE2(rxdq__copy, uint64_t, ldcp->id, uint64_t, bytes) \ 3455944Sha137994 3465944Sha137994 /* The amount of contiguous space at the tail of the queue */ 3475944Sha137994 #define Q_CONTIG_SPACE(head, tail, size) \ 3485944Sha137994 ((head) <= (tail) ? ((size) - (tail)) : \ 3495944Sha137994 ((head) - (tail) - LDC_PACKET_SIZE)) 3505944Sha137994 3511991Sheppo #define ZERO_PKT(p) \ 3521991Sheppo bzero((p), sizeof (ldc_msg_t)); 3531991Sheppo 3541991Sheppo #define IDX2COOKIE(idx, pg_szc, pg_shift) \ 3551991Sheppo (((pg_szc) << LDC_COOKIE_PGSZC_SHIFT) | ((idx) << (pg_shift))) 3561991Sheppo 3571991Sheppo int 3581991Sheppo _init(void) 3591991Sheppo { 3601991Sheppo int status; 3616845Sha137994 extern void i_ldc_mem_set_hsvc_vers(uint64_t major, uint64_t minor); 3621991Sheppo 3631991Sheppo status = hsvc_register(&ldc_hsvc, &ldc_sup_minor); 3641991Sheppo if (status != 0) { 3654423Sjb145095 cmn_err(CE_NOTE, "!%s: cannot negotiate hypervisor LDC services" 3661991Sheppo " group: 0x%lx major: %ld minor: %ld errno: %d", 3671991Sheppo ldc_hsvc.hsvc_modname, ldc_hsvc.hsvc_group, 3681991Sheppo ldc_hsvc.hsvc_major, ldc_hsvc.hsvc_minor, status); 3691991Sheppo return (-1); 3701991Sheppo } 3711991Sheppo 3726845Sha137994 /* Initialize shared memory HV API version checking */ 3736845Sha137994 i_ldc_mem_set_hsvc_vers(ldc_hsvc.hsvc_major, ldc_sup_minor); 3746845Sha137994 3751991Sheppo /* allocate soft state structure */ 3761991Sheppo ldcssp = kmem_zalloc(sizeof (ldc_soft_state_t), KM_SLEEP); 3771991Sheppo 3781991Sheppo /* Link the module into the system */ 3791991Sheppo status = mod_install(&ml); 3801991Sheppo if (status != 0) { 3811991Sheppo kmem_free(ldcssp, sizeof (ldc_soft_state_t)); 3821991Sheppo return (status); 3831991Sheppo } 3841991Sheppo 3851991Sheppo /* Initialize the LDC state structure */ 3861991Sheppo mutex_init(&ldcssp->lock, NULL, MUTEX_DRIVER, NULL); 3871991Sheppo 3881991Sheppo mutex_enter(&ldcssp->lock); 3891991Sheppo 3902531Snarayan /* Create a cache for memory handles */ 3912531Snarayan ldcssp->memhdl_cache = kmem_cache_create("ldc_memhdl_cache", 3922531Snarayan sizeof (ldc_mhdl_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 3932531Snarayan if (ldcssp->memhdl_cache == NULL) { 3942531Snarayan DWARN(DBG_ALL_LDCS, "_init: ldc_memhdl cache create failed\n"); 3952531Snarayan mutex_exit(&ldcssp->lock); 3962531Snarayan return (-1); 3972531Snarayan } 3982531Snarayan 3992531Snarayan /* Create cache for memory segment structures */ 4002531Snarayan ldcssp->memseg_cache = kmem_cache_create("ldc_memseg_cache", 4012531Snarayan sizeof (ldc_memseg_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 4022531Snarayan if (ldcssp->memseg_cache == NULL) { 4032531Snarayan DWARN(DBG_ALL_LDCS, "_init: ldc_memseg cache create failed\n"); 4042531Snarayan mutex_exit(&ldcssp->lock); 4052531Snarayan return (-1); 4062531Snarayan } 4072531Snarayan 4082531Snarayan 4091991Sheppo ldcssp->channel_count = 0; 4101991Sheppo ldcssp->channels_open = 0; 4111991Sheppo ldcssp->chan_list = NULL; 4121991Sheppo ldcssp->dring_list = NULL; 4131991Sheppo 4141991Sheppo mutex_exit(&ldcssp->lock); 4151991Sheppo 4161991Sheppo return (0); 4171991Sheppo } 4181991Sheppo 4191991Sheppo int 4201991Sheppo _info(struct modinfo *modinfop) 4211991Sheppo { 4221991Sheppo /* Report status of the dynamically loadable driver module */ 4231991Sheppo return (mod_info(&ml, modinfop)); 4241991Sheppo } 4251991Sheppo 4261991Sheppo int 4271991Sheppo _fini(void) 4281991Sheppo { 4291991Sheppo int rv, status; 4304690Snarayan ldc_chan_t *tmp_ldcp, *ldcp; 4314690Snarayan ldc_dring_t *tmp_dringp, *dringp; 4321991Sheppo ldc_mem_info_t minfo; 4331991Sheppo 4341991Sheppo /* Unlink the driver module from the system */ 4351991Sheppo status = mod_remove(&ml); 4361991Sheppo if (status) { 4371991Sheppo DWARN(DBG_ALL_LDCS, "_fini: mod_remove failed\n"); 4381991Sheppo return (EIO); 4391991Sheppo } 4401991Sheppo 4411991Sheppo /* Free descriptor rings */ 4421991Sheppo dringp = ldcssp->dring_list; 4431991Sheppo while (dringp != NULL) { 4444690Snarayan tmp_dringp = dringp->next; 4451991Sheppo 4461991Sheppo rv = ldc_mem_dring_info((ldc_dring_handle_t)dringp, &minfo); 4471991Sheppo if (rv == 0 && minfo.status != LDC_UNBOUND) { 4481991Sheppo if (minfo.status == LDC_BOUND) { 4491991Sheppo (void) ldc_mem_dring_unbind( 4504690Snarayan (ldc_dring_handle_t)dringp); 4511991Sheppo } 4521991Sheppo if (minfo.status == LDC_MAPPED) { 4531991Sheppo (void) ldc_mem_dring_unmap( 4544690Snarayan (ldc_dring_handle_t)dringp); 4551991Sheppo } 4561991Sheppo } 4571991Sheppo 4581991Sheppo (void) ldc_mem_dring_destroy((ldc_dring_handle_t)dringp); 4594690Snarayan dringp = tmp_dringp; 4601991Sheppo } 4611991Sheppo ldcssp->dring_list = NULL; 4621991Sheppo 4634690Snarayan /* close and finalize channels */ 4644690Snarayan ldcp = ldcssp->chan_list; 4654690Snarayan while (ldcp != NULL) { 4664690Snarayan tmp_ldcp = ldcp->next; 4674690Snarayan 4684690Snarayan (void) ldc_close((ldc_handle_t)ldcp); 4694690Snarayan (void) ldc_fini((ldc_handle_t)ldcp); 4704690Snarayan 4714690Snarayan ldcp = tmp_ldcp; 4724690Snarayan } 4734690Snarayan ldcssp->chan_list = NULL; 4744690Snarayan 4752531Snarayan /* Destroy kmem caches */ 4762531Snarayan kmem_cache_destroy(ldcssp->memhdl_cache); 4772531Snarayan kmem_cache_destroy(ldcssp->memseg_cache); 4782531Snarayan 4791991Sheppo /* 4801991Sheppo * We have successfully "removed" the driver. 4811991Sheppo * Destroying soft states 4821991Sheppo */ 4831991Sheppo mutex_destroy(&ldcssp->lock); 4841991Sheppo kmem_free(ldcssp, sizeof (ldc_soft_state_t)); 4851991Sheppo 4861991Sheppo (void) hsvc_unregister(&ldc_hsvc); 4871991Sheppo 4881991Sheppo return (status); 4891991Sheppo } 4901991Sheppo 4911991Sheppo /* -------------------------------------------------------------------------- */ 4921991Sheppo 4931991Sheppo /* 4942410Slm66018 * LDC Link Layer Internal Functions 4951991Sheppo */ 4961991Sheppo 4971991Sheppo /* 4981991Sheppo * Translate HV Errors to sun4v error codes 4991991Sheppo */ 5006408Sha137994 int 5011991Sheppo i_ldc_h2v_error(int h_error) 5021991Sheppo { 5031991Sheppo switch (h_error) { 5041991Sheppo 5051991Sheppo case H_EOK: 5061991Sheppo return (0); 5071991Sheppo 5081991Sheppo case H_ENORADDR: 5091991Sheppo return (EFAULT); 5101991Sheppo 5111991Sheppo case H_EBADPGSZ: 5121991Sheppo case H_EINVAL: 5131991Sheppo return (EINVAL); 5141991Sheppo 5151991Sheppo case H_EWOULDBLOCK: 5161991Sheppo return (EWOULDBLOCK); 5171991Sheppo 5181991Sheppo case H_ENOACCESS: 5191991Sheppo case H_ENOMAP: 5201991Sheppo return (EACCES); 5211991Sheppo 5221991Sheppo case H_EIO: 5231991Sheppo case H_ECPUERROR: 5241991Sheppo return (EIO); 5251991Sheppo 5261991Sheppo case H_ENOTSUPPORTED: 5271991Sheppo return (ENOTSUP); 5281991Sheppo 5291991Sheppo case H_ETOOMANY: 5301991Sheppo return (ENOSPC); 5311991Sheppo 5321991Sheppo case H_ECHANNEL: 5331991Sheppo return (ECHRNG); 5341991Sheppo default: 5351991Sheppo break; 5361991Sheppo } 5371991Sheppo 5381991Sheppo return (EIO); 5391991Sheppo } 5401991Sheppo 5411991Sheppo /* 5421991Sheppo * Reconfigure the transmit queue 5431991Sheppo */ 5441991Sheppo static int 5451991Sheppo i_ldc_txq_reconf(ldc_chan_t *ldcp) 5461991Sheppo { 5471991Sheppo int rv; 5481991Sheppo 5491991Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 5502336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 5512336Snarayan 5521991Sheppo rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries); 5531991Sheppo if (rv) { 5541991Sheppo cmn_err(CE_WARN, 5552793Slm66018 "i_ldc_txq_reconf: (0x%lx) cannot set qconf", ldcp->id); 5561991Sheppo return (EIO); 5571991Sheppo } 5581991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, &(ldcp->tx_head), 5591991Sheppo &(ldcp->tx_tail), &(ldcp->link_state)); 5601991Sheppo if (rv) { 5611991Sheppo cmn_err(CE_WARN, 5622793Slm66018 "i_ldc_txq_reconf: (0x%lx) cannot get qptrs", ldcp->id); 5631991Sheppo return (EIO); 5641991Sheppo } 5652793Slm66018 D1(ldcp->id, "i_ldc_txq_reconf: (0x%llx) h=0x%llx,t=0x%llx," 5661991Sheppo "s=0x%llx\n", ldcp->id, ldcp->tx_head, ldcp->tx_tail, 5671991Sheppo ldcp->link_state); 5681991Sheppo 5691991Sheppo return (0); 5701991Sheppo } 5711991Sheppo 5721991Sheppo /* 5731991Sheppo * Reconfigure the receive queue 5741991Sheppo */ 5751991Sheppo static int 5762793Slm66018 i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset) 5771991Sheppo { 5781991Sheppo int rv; 5791991Sheppo uint64_t rx_head, rx_tail; 5801991Sheppo 5811991Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 5821991Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 5831991Sheppo &(ldcp->link_state)); 5841991Sheppo if (rv) { 5851991Sheppo cmn_err(CE_WARN, 5862793Slm66018 "i_ldc_rxq_reconf: (0x%lx) cannot get state", 5871991Sheppo ldcp->id); 5881991Sheppo return (EIO); 5891991Sheppo } 5901991Sheppo 5912793Slm66018 if (force_reset || (ldcp->tstate & ~TS_IN_RESET) == TS_UP) { 5921991Sheppo rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra, 5934690Snarayan ldcp->rx_q_entries); 5941991Sheppo if (rv) { 5951991Sheppo cmn_err(CE_WARN, 5962793Slm66018 "i_ldc_rxq_reconf: (0x%lx) cannot set qconf", 5971991Sheppo ldcp->id); 5981991Sheppo return (EIO); 5991991Sheppo } 6002793Slm66018 D1(ldcp->id, "i_ldc_rxq_reconf: (0x%llx) completed q reconf", 6011991Sheppo ldcp->id); 6021991Sheppo } 6031991Sheppo 6041991Sheppo return (0); 6051991Sheppo } 6061991Sheppo 6072841Snarayan 6082841Snarayan /* 6092841Snarayan * Drain the contents of the receive queue 6102841Snarayan */ 6112841Snarayan static int 6122841Snarayan i_ldc_rxq_drain(ldc_chan_t *ldcp) 6132841Snarayan { 6142841Snarayan int rv; 6152841Snarayan uint64_t rx_head, rx_tail; 6162841Snarayan 6172841Snarayan ASSERT(MUTEX_HELD(&ldcp->lock)); 6182841Snarayan rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 6192841Snarayan &(ldcp->link_state)); 6202841Snarayan if (rv) { 6212841Snarayan cmn_err(CE_WARN, "i_ldc_rxq_drain: (0x%lx) cannot get state", 6222841Snarayan ldcp->id); 6232841Snarayan return (EIO); 6242841Snarayan } 6252841Snarayan 6262841Snarayan /* flush contents by setting the head = tail */ 6272841Snarayan return (i_ldc_set_rx_head(ldcp, rx_tail)); 6282841Snarayan } 6292841Snarayan 6302841Snarayan 6311991Sheppo /* 6321991Sheppo * Reset LDC state structure and its contents 6331991Sheppo */ 6341991Sheppo static void 6351991Sheppo i_ldc_reset_state(ldc_chan_t *ldcp) 6361991Sheppo { 6371991Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 6381991Sheppo ldcp->last_msg_snt = LDC_INIT_SEQID; 6391991Sheppo ldcp->last_ack_rcd = 0; 6401991Sheppo ldcp->last_msg_rcd = 0; 6411991Sheppo ldcp->tx_ackd_head = ldcp->tx_head; 6425944Sha137994 ldcp->stream_remains = 0; 6431991Sheppo ldcp->next_vidx = 0; 6441991Sheppo ldcp->hstate = 0; 6451991Sheppo ldcp->tstate = TS_OPEN; 6461991Sheppo ldcp->status = LDC_OPEN; 6475944Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID; 6485944Sha137994 ldcp->rx_dq_head = 0; 6495944Sha137994 ldcp->rx_dq_tail = 0; 6501991Sheppo 6511991Sheppo if (ldcp->link_state == LDC_CHANNEL_UP || 6521991Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 6531991Sheppo 6541991Sheppo if (ldcp->mode == LDC_MODE_RAW) { 6551991Sheppo ldcp->status = LDC_UP; 6561991Sheppo ldcp->tstate = TS_UP; 6571991Sheppo } else { 6581991Sheppo ldcp->status = LDC_READY; 6591991Sheppo ldcp->tstate |= TS_LINK_READY; 6601991Sheppo } 6611991Sheppo } 6621991Sheppo } 6631991Sheppo 6641991Sheppo /* 6651991Sheppo * Reset a LDC channel 6661991Sheppo */ 6676408Sha137994 void 6682793Slm66018 i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset) 6691991Sheppo { 6703560Snarayan DWARN(ldcp->id, "i_ldc_reset: (0x%llx) channel reset\n", ldcp->id); 6711991Sheppo 6722336Snarayan ASSERT(MUTEX_HELD(&ldcp->lock)); 6732336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 6742336Snarayan 6752793Slm66018 /* reconfig Tx and Rx queues */ 6761991Sheppo (void) i_ldc_txq_reconf(ldcp); 6772793Slm66018 (void) i_ldc_rxq_reconf(ldcp, force_reset); 6782793Slm66018 6792793Slm66018 /* Clear Tx and Rx interrupts */ 6802793Slm66018 (void) i_ldc_clear_intr(ldcp, CNEX_TX_INTR); 6812793Slm66018 (void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 6822793Slm66018 6832793Slm66018 /* Reset channel state */ 6841991Sheppo i_ldc_reset_state(ldcp); 6852793Slm66018 6862793Slm66018 /* Mark channel in reset */ 6872793Slm66018 ldcp->tstate |= TS_IN_RESET; 6881991Sheppo } 6891991Sheppo 6902531Snarayan 6911991Sheppo /* 6921991Sheppo * Clear pending interrupts 6931991Sheppo */ 6941991Sheppo static void 6951991Sheppo i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype) 6961991Sheppo { 6971991Sheppo ldc_cnex_t *cinfo = &ldcssp->cinfo; 6981991Sheppo 6991991Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 7002793Slm66018 ASSERT(cinfo->dip != NULL); 7012793Slm66018 7022793Slm66018 switch (itype) { 7032793Slm66018 case CNEX_TX_INTR: 7042531Snarayan /* check Tx interrupt */ 7052793Slm66018 if (ldcp->tx_intr_state) 7062793Slm66018 ldcp->tx_intr_state = LDC_INTR_NONE; 7072793Slm66018 else 7082793Slm66018 return; 7092793Slm66018 break; 7102793Slm66018 7112793Slm66018 case CNEX_RX_INTR: 7122531Snarayan /* check Rx interrupt */ 7132793Slm66018 if (ldcp->rx_intr_state) 7142793Slm66018 ldcp->rx_intr_state = LDC_INTR_NONE; 7152793Slm66018 else 7162793Slm66018 return; 7172793Slm66018 break; 7182793Slm66018 } 7192793Slm66018 7202793Slm66018 (void) cinfo->clr_intr(cinfo->dip, ldcp->id, itype); 7212793Slm66018 D2(ldcp->id, 7222793Slm66018 "i_ldc_clear_intr: (0x%llx) cleared 0x%x intr\n", 7232793Slm66018 ldcp->id, itype); 7241991Sheppo } 7251991Sheppo 7261991Sheppo /* 7271991Sheppo * Set the receive queue head 7282032Slm66018 * Resets connection and returns an error if it fails. 7291991Sheppo */ 7301991Sheppo static int 7311991Sheppo i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head) 7321991Sheppo { 7332032Slm66018 int rv; 7342032Slm66018 int retries; 7351991Sheppo 7361991Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 7372032Slm66018 for (retries = 0; retries < ldc_max_retries; retries++) { 7382032Slm66018 7392032Slm66018 if ((rv = hv_ldc_rx_set_qhead(ldcp->id, head)) == 0) 7402032Slm66018 return (0); 7412032Slm66018 7422032Slm66018 if (rv != H_EWOULDBLOCK) 7432032Slm66018 break; 7442032Slm66018 7452032Slm66018 /* wait for ldc_delay usecs */ 7462032Slm66018 drv_usecwait(ldc_delay); 7472032Slm66018 } 7482032Slm66018 7492032Slm66018 cmn_err(CE_WARN, "ldc_rx_set_qhead: (0x%lx) cannot set qhead 0x%lx", 7504690Snarayan ldcp->id, head); 7512336Snarayan mutex_enter(&ldcp->tx_lock); 7522793Slm66018 i_ldc_reset(ldcp, B_TRUE); 7532336Snarayan mutex_exit(&ldcp->tx_lock); 7542032Slm66018 7552032Slm66018 return (ECONNRESET); 7561991Sheppo } 7571991Sheppo 7584690Snarayan /* 7594690Snarayan * Returns the tx_head to be used for transfer 7604690Snarayan */ 7614690Snarayan static void 7624690Snarayan i_ldc_get_tx_head(ldc_chan_t *ldcp, uint64_t *head) 7634690Snarayan { 7644690Snarayan ldc_msg_t *pkt; 7654690Snarayan 7664690Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 7674690Snarayan 7684690Snarayan /* get current Tx head */ 7694690Snarayan *head = ldcp->tx_head; 7704690Snarayan 7714690Snarayan /* 7724690Snarayan * Reliable mode will use the ACKd head instead of the regular tx_head. 7734690Snarayan * Also in Reliable mode, advance ackd_head for all non DATA/INFO pkts, 7744690Snarayan * up to the current location of tx_head. This needs to be done 7754690Snarayan * as the peer will only ACK DATA/INFO pkts. 7764690Snarayan */ 7776408Sha137994 if (ldcp->mode == LDC_MODE_RELIABLE) { 7784690Snarayan while (ldcp->tx_ackd_head != ldcp->tx_head) { 7794690Snarayan pkt = (ldc_msg_t *)(ldcp->tx_q_va + ldcp->tx_ackd_head); 7804690Snarayan if ((pkt->type & LDC_DATA) && (pkt->stype & LDC_INFO)) { 7814690Snarayan break; 7824690Snarayan } 7834690Snarayan /* advance ACKd head */ 7844690Snarayan ldcp->tx_ackd_head = 7854690Snarayan (ldcp->tx_ackd_head + LDC_PACKET_SIZE) % 7864690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 7874690Snarayan } 7884690Snarayan *head = ldcp->tx_ackd_head; 7894690Snarayan } 7904690Snarayan } 7911991Sheppo 7921991Sheppo /* 7931991Sheppo * Returns the tx_tail to be used for transfer 7941991Sheppo * Re-reads the TX queue ptrs if and only if the 7951991Sheppo * the cached head and tail are equal (queue is full) 7961991Sheppo */ 7971991Sheppo static int 7981991Sheppo i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail) 7991991Sheppo { 8001991Sheppo int rv; 8011991Sheppo uint64_t current_head, new_tail; 8021991Sheppo 8032336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 8041991Sheppo /* Read the head and tail ptrs from HV */ 8051991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 8061991Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 8071991Sheppo if (rv) { 8081991Sheppo cmn_err(CE_WARN, 8091991Sheppo "i_ldc_get_tx_tail: (0x%lx) cannot read qptrs\n", 8101991Sheppo ldcp->id); 8111991Sheppo return (EIO); 8121991Sheppo } 8131991Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN) { 8143010Slm66018 D1(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) channel not ready\n", 8151991Sheppo ldcp->id); 8161991Sheppo return (ECONNRESET); 8171991Sheppo } 8181991Sheppo 8194690Snarayan i_ldc_get_tx_head(ldcp, ¤t_head); 8201991Sheppo 8211991Sheppo /* increment the tail */ 8221991Sheppo new_tail = (ldcp->tx_tail + LDC_PACKET_SIZE) % 8234690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 8241991Sheppo 8251991Sheppo if (new_tail == current_head) { 8261991Sheppo DWARN(ldcp->id, 8271991Sheppo "i_ldc_get_tx_tail: (0x%llx) TX queue is full\n", 8281991Sheppo ldcp->id); 8291991Sheppo return (EWOULDBLOCK); 8301991Sheppo } 8311991Sheppo 8321991Sheppo D2(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) head=0x%llx, tail=0x%llx\n", 8331991Sheppo ldcp->id, ldcp->tx_head, ldcp->tx_tail); 8341991Sheppo 8351991Sheppo *tail = ldcp->tx_tail; 8361991Sheppo return (0); 8371991Sheppo } 8381991Sheppo 8391991Sheppo /* 8401991Sheppo * Set the tail pointer. If HV returns EWOULDBLOCK, it will back off 8412032Slm66018 * and retry ldc_max_retries times before returning an error. 8421991Sheppo * Returns 0, EWOULDBLOCK or EIO 8431991Sheppo */ 8441991Sheppo static int 8451991Sheppo i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail) 8461991Sheppo { 8471991Sheppo int rv, retval = EWOULDBLOCK; 8482032Slm66018 int retries; 8491991Sheppo 8502336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 8512032Slm66018 for (retries = 0; retries < ldc_max_retries; retries++) { 8521991Sheppo 8531991Sheppo if ((rv = hv_ldc_tx_set_qtail(ldcp->id, tail)) == 0) { 8541991Sheppo retval = 0; 8551991Sheppo break; 8561991Sheppo } 8571991Sheppo if (rv != H_EWOULDBLOCK) { 8581991Sheppo DWARN(ldcp->id, "i_ldc_set_tx_tail: (0x%llx) set " 8591991Sheppo "qtail=0x%llx failed, rv=%d\n", ldcp->id, tail, rv); 8601991Sheppo retval = EIO; 8611991Sheppo break; 8621991Sheppo } 8631991Sheppo 8642032Slm66018 /* wait for ldc_delay usecs */ 8652032Slm66018 drv_usecwait(ldc_delay); 8661991Sheppo } 8671991Sheppo return (retval); 8681991Sheppo } 8691991Sheppo 8701991Sheppo /* 8715944Sha137994 * Copy a data packet from the HV receive queue to the data queue. 8725944Sha137994 * Caller must ensure that the data queue is not already full. 8735944Sha137994 * 8745944Sha137994 * The *head argument represents the current head pointer for the HV 8755944Sha137994 * receive queue. After copying a packet from the HV receive queue, 8765944Sha137994 * the *head pointer will be updated. This allows the caller to update 8775944Sha137994 * the head pointer in HV using the returned *head value. 8785944Sha137994 */ 8795944Sha137994 void 8805944Sha137994 i_ldc_rxdq_copy(ldc_chan_t *ldcp, uint64_t *head) 8815944Sha137994 { 8825944Sha137994 uint64_t q_size, dq_size; 8835944Sha137994 8845944Sha137994 ASSERT(MUTEX_HELD(&ldcp->lock)); 8855944Sha137994 8865944Sha137994 q_size = ldcp->rx_q_entries << LDC_PACKET_SHIFT; 8875944Sha137994 dq_size = ldcp->rx_dq_entries << LDC_PACKET_SHIFT; 8885944Sha137994 8895944Sha137994 ASSERT(Q_CONTIG_SPACE(ldcp->rx_dq_head, ldcp->rx_dq_tail, 8905944Sha137994 dq_size) >= LDC_PACKET_SIZE); 8915944Sha137994 8925944Sha137994 bcopy((void *)(ldcp->rx_q_va + *head), 8935944Sha137994 (void *)(ldcp->rx_dq_va + ldcp->rx_dq_tail), LDC_PACKET_SIZE); 8945944Sha137994 TRACE_RXDQ_COPY(ldcp, LDC_PACKET_SIZE); 8955944Sha137994 8965944Sha137994 /* Update rx head */ 8975944Sha137994 *head = (*head + LDC_PACKET_SIZE) % q_size; 8985944Sha137994 8995944Sha137994 /* Update dq tail */ 9005944Sha137994 ldcp->rx_dq_tail = (ldcp->rx_dq_tail + LDC_PACKET_SIZE) % dq_size; 9015944Sha137994 } 9025944Sha137994 9035944Sha137994 /* 9045944Sha137994 * Update the Rx data queue head pointer 9055944Sha137994 */ 9065944Sha137994 static int 9075944Sha137994 i_ldc_set_rxdq_head(ldc_chan_t *ldcp, uint64_t head) 9085944Sha137994 { 9095944Sha137994 ldcp->rx_dq_head = head; 9105944Sha137994 return (0); 9115944Sha137994 } 9125944Sha137994 9135944Sha137994 /* 9145944Sha137994 * Get the Rx data queue head and tail pointers 9155944Sha137994 */ 9165944Sha137994 static uint64_t 9175944Sha137994 i_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail, 9185944Sha137994 uint64_t *link_state) 9195944Sha137994 { 9205944Sha137994 _NOTE(ARGUNUSED(link_state)) 9215944Sha137994 *head = ldcp->rx_dq_head; 9225944Sha137994 *tail = ldcp->rx_dq_tail; 9235944Sha137994 return (0); 9245944Sha137994 } 9255944Sha137994 9265944Sha137994 /* 9275944Sha137994 * Wrapper for the Rx HV queue set head function. Giving the 9285944Sha137994 * data queue and HV queue set head functions the same type. 9295944Sha137994 */ 9305944Sha137994 static uint64_t 9315944Sha137994 i_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail, 9325944Sha137994 uint64_t *link_state) 9335944Sha137994 { 9345944Sha137994 return (i_ldc_h2v_error(hv_ldc_rx_get_state(ldcp->id, head, tail, 9355944Sha137994 link_state))); 9365944Sha137994 } 9375944Sha137994 9385944Sha137994 /* 9395944Sha137994 * LDC receive interrupt handler 9405944Sha137994 * triggered for channel with data pending to read 9415944Sha137994 * i.e. Rx queue content changes 9425944Sha137994 */ 9435944Sha137994 static uint_t 9445944Sha137994 i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2) 9455944Sha137994 { 9465944Sha137994 _NOTE(ARGUNUSED(arg2)) 9475944Sha137994 9485944Sha137994 ldc_chan_t *ldcp; 9495944Sha137994 boolean_t notify; 9505944Sha137994 uint64_t event; 9516944Sha137994 int rv, status; 9525944Sha137994 9535944Sha137994 /* Get the channel for which interrupt was received */ 9545944Sha137994 if (arg1 == NULL) { 9555944Sha137994 cmn_err(CE_WARN, "i_ldc_rx_hdlr: invalid arg\n"); 9565944Sha137994 return (DDI_INTR_UNCLAIMED); 9575944Sha137994 } 9585944Sha137994 9595944Sha137994 ldcp = (ldc_chan_t *)arg1; 9605944Sha137994 9615944Sha137994 D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n", 9625944Sha137994 ldcp->id, ldcp); 9635944Sha137994 D1(ldcp->id, "i_ldc_rx_hdlr: (%llx) USR%lx/TS%lx/HS%lx, LSTATE=%lx\n", 9645944Sha137994 ldcp->id, ldcp->status, ldcp->tstate, ldcp->hstate, 9655944Sha137994 ldcp->link_state); 9665944Sha137994 9675944Sha137994 /* Lock channel */ 9685944Sha137994 mutex_enter(&ldcp->lock); 9695944Sha137994 9705944Sha137994 /* Mark the interrupt as being actively handled */ 9715944Sha137994 ldcp->rx_intr_state = LDC_INTR_ACTIVE; 9725944Sha137994 9736944Sha137994 status = i_ldc_rx_process_hvq(ldcp, ¬ify, &event); 9745944Sha137994 9756408Sha137994 if (ldcp->mode != LDC_MODE_RELIABLE) { 9765944Sha137994 /* 9775944Sha137994 * If there are no data packets on the queue, clear 9785944Sha137994 * the interrupt. Otherwise, the ldc_read will clear 9795944Sha137994 * interrupts after draining the queue. To indicate the 9805944Sha137994 * interrupt has not yet been cleared, it is marked 9815944Sha137994 * as pending. 9825944Sha137994 */ 9835944Sha137994 if ((event & LDC_EVT_READ) == 0) { 9845944Sha137994 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 9855944Sha137994 } else { 9865944Sha137994 ldcp->rx_intr_state = LDC_INTR_PEND; 9875944Sha137994 } 9885944Sha137994 } 9895944Sha137994 9905944Sha137994 /* if callbacks are disabled, do not notify */ 9915944Sha137994 if (notify && ldcp->cb_enabled) { 9925944Sha137994 ldcp->cb_inprogress = B_TRUE; 9935944Sha137994 mutex_exit(&ldcp->lock); 9945944Sha137994 rv = ldcp->cb(event, ldcp->cb_arg); 9955944Sha137994 if (rv) { 9965944Sha137994 DWARN(ldcp->id, 9975944Sha137994 "i_ldc_rx_hdlr: (0x%llx) callback failure", 9985944Sha137994 ldcp->id); 9995944Sha137994 } 10005944Sha137994 mutex_enter(&ldcp->lock); 10015944Sha137994 ldcp->cb_inprogress = B_FALSE; 10025944Sha137994 } 10035944Sha137994 10046408Sha137994 if (ldcp->mode == LDC_MODE_RELIABLE) { 10056944Sha137994 if (status == ENOSPC) { 10066944Sha137994 /* 10076944Sha137994 * Here, ENOSPC indicates the secondary data 10086944Sha137994 * queue is full and the Rx queue is non-empty. 10096944Sha137994 * Much like how reliable and raw modes are 10106944Sha137994 * handled above, since the Rx queue is non- 10116944Sha137994 * empty, we mark the interrupt as pending to 10126944Sha137994 * indicate it has not yet been cleared. 10136944Sha137994 */ 10146944Sha137994 ldcp->rx_intr_state = LDC_INTR_PEND; 10156944Sha137994 } else { 10166944Sha137994 /* 10176944Sha137994 * We have processed all CTRL packets and 10186944Sha137994 * copied all DATA packets to the secondary 10196944Sha137994 * queue. Clear the interrupt. 10206944Sha137994 */ 10216944Sha137994 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 10226944Sha137994 } 10235944Sha137994 } 10245944Sha137994 10255944Sha137994 mutex_exit(&ldcp->lock); 10265944Sha137994 10275944Sha137994 D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) exiting handler", ldcp->id); 10285944Sha137994 10295944Sha137994 return (DDI_INTR_CLAIMED); 10305944Sha137994 } 10315944Sha137994 10325944Sha137994 /* 10335944Sha137994 * Wrapper for the Rx HV queue processing function to be used when 10345944Sha137994 * checking the Rx HV queue for data packets. Unlike the interrupt 10355944Sha137994 * handler code flow, the Rx interrupt is not cleared here and 10365944Sha137994 * callbacks are not made. 10375944Sha137994 */ 10385944Sha137994 static uint_t 10395944Sha137994 i_ldc_chkq(ldc_chan_t *ldcp) 10405944Sha137994 { 10415944Sha137994 boolean_t notify; 10425944Sha137994 uint64_t event; 10435944Sha137994 10445944Sha137994 return (i_ldc_rx_process_hvq(ldcp, ¬ify, &event)); 10455944Sha137994 } 10465944Sha137994 10475944Sha137994 /* 10481991Sheppo * Send a LDC message 10491991Sheppo */ 10501991Sheppo static int 10511991Sheppo i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype, 10521991Sheppo uint8_t ctrlmsg) 10531991Sheppo { 10541991Sheppo int rv; 10551991Sheppo ldc_msg_t *pkt; 10561991Sheppo uint64_t tx_tail; 10574690Snarayan uint32_t curr_seqid; 10581991Sheppo 10592336Snarayan /* Obtain Tx lock */ 10602336Snarayan mutex_enter(&ldcp->tx_lock); 10612336Snarayan 10624690Snarayan curr_seqid = ldcp->last_msg_snt; 10634690Snarayan 10641991Sheppo /* get the current tail for the message */ 10651991Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 10661991Sheppo if (rv) { 10671991Sheppo DWARN(ldcp->id, 10681991Sheppo "i_ldc_send_pkt: (0x%llx) error sending pkt, " 10691991Sheppo "type=0x%x,subtype=0x%x,ctrl=0x%x\n", 10701991Sheppo ldcp->id, pkttype, subtype, ctrlmsg); 10712336Snarayan mutex_exit(&ldcp->tx_lock); 10721991Sheppo return (rv); 10731991Sheppo } 10741991Sheppo 10751991Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 10761991Sheppo ZERO_PKT(pkt); 10771991Sheppo 10781991Sheppo /* Initialize the packet */ 10791991Sheppo pkt->type = pkttype; 10801991Sheppo pkt->stype = subtype; 10811991Sheppo pkt->ctrl = ctrlmsg; 10821991Sheppo 10831991Sheppo /* Store ackid/seqid iff it is RELIABLE mode & not a RTS/RTR message */ 10841991Sheppo if (((ctrlmsg & LDC_CTRL_MASK) != LDC_RTS) && 10851991Sheppo ((ctrlmsg & LDC_CTRL_MASK) != LDC_RTR)) { 10861991Sheppo curr_seqid++; 10871991Sheppo if (ldcp->mode != LDC_MODE_RAW) { 10881991Sheppo pkt->seqid = curr_seqid; 10891991Sheppo pkt->ackid = ldcp->last_msg_rcd; 10901991Sheppo } 10911991Sheppo } 10921991Sheppo DUMP_LDC_PKT(ldcp, "i_ldc_send_pkt", (uint64_t)pkt); 10931991Sheppo 10941991Sheppo /* initiate the send by calling into HV and set the new tail */ 10951991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 10964690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 10971991Sheppo 10981991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 10991991Sheppo if (rv) { 11001991Sheppo DWARN(ldcp->id, 11011991Sheppo "i_ldc_send_pkt:(0x%llx) error sending pkt, " 11021991Sheppo "type=0x%x,stype=0x%x,ctrl=0x%x\n", 11031991Sheppo ldcp->id, pkttype, subtype, ctrlmsg); 11042336Snarayan mutex_exit(&ldcp->tx_lock); 11051991Sheppo return (EIO); 11061991Sheppo } 11071991Sheppo 11081991Sheppo ldcp->last_msg_snt = curr_seqid; 11091991Sheppo ldcp->tx_tail = tx_tail; 11101991Sheppo 11112336Snarayan mutex_exit(&ldcp->tx_lock); 11121991Sheppo return (0); 11131991Sheppo } 11141991Sheppo 11151991Sheppo /* 11161991Sheppo * Checks if packet was received in right order 11172410Slm66018 * in the case of a reliable link. 11181991Sheppo * Returns 0 if in order, else EIO 11191991Sheppo */ 11201991Sheppo static int 11211991Sheppo i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *msg) 11221991Sheppo { 11231991Sheppo /* No seqid checking for RAW mode */ 11241991Sheppo if (ldcp->mode == LDC_MODE_RAW) 11251991Sheppo return (0); 11261991Sheppo 11271991Sheppo /* No seqid checking for version, RTS, RTR message */ 11281991Sheppo if (msg->ctrl == LDC_VER || 11291991Sheppo msg->ctrl == LDC_RTS || 11301991Sheppo msg->ctrl == LDC_RTR) 11311991Sheppo return (0); 11321991Sheppo 11331991Sheppo /* Initial seqid to use is sent in RTS/RTR and saved in last_msg_rcd */ 11341991Sheppo if (msg->seqid != (ldcp->last_msg_rcd + 1)) { 11351991Sheppo DWARN(ldcp->id, 11361991Sheppo "i_ldc_check_seqid: (0x%llx) out-of-order pkt, got 0x%x, " 11371991Sheppo "expecting 0x%x\n", ldcp->id, msg->seqid, 11381991Sheppo (ldcp->last_msg_rcd + 1)); 11391991Sheppo return (EIO); 11401991Sheppo } 11411991Sheppo 11423560Snarayan #ifdef DEBUG 11433560Snarayan if (LDC_INJECT_PKTLOSS(ldcp)) { 11443560Snarayan DWARN(ldcp->id, 11453560Snarayan "i_ldc_check_seqid: (0x%llx) inject pkt loss\n", ldcp->id); 11463560Snarayan return (EIO); 11473560Snarayan } 11483560Snarayan #endif 11493560Snarayan 11501991Sheppo return (0); 11511991Sheppo } 11521991Sheppo 11531991Sheppo 11541991Sheppo /* 11551991Sheppo * Process an incoming version ctrl message 11561991Sheppo */ 11571991Sheppo static int 11581991Sheppo i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg) 11591991Sheppo { 11601991Sheppo int rv = 0, idx = ldcp->next_vidx; 11611991Sheppo ldc_msg_t *pkt; 11621991Sheppo uint64_t tx_tail; 11631991Sheppo ldc_ver_t *rcvd_ver; 11641991Sheppo 11651991Sheppo /* get the received version */ 11661991Sheppo rcvd_ver = (ldc_ver_t *)((uint64_t)msg + LDC_PAYLOAD_VER_OFF); 11671991Sheppo 11681991Sheppo D2(ldcp->id, "i_ldc_process_VER: (0x%llx) received VER v%u.%u\n", 11691991Sheppo ldcp->id, rcvd_ver->major, rcvd_ver->minor); 11701991Sheppo 11712336Snarayan /* Obtain Tx lock */ 11722336Snarayan mutex_enter(&ldcp->tx_lock); 11732336Snarayan 11741991Sheppo switch (msg->stype) { 11751991Sheppo case LDC_INFO: 11761991Sheppo 11772793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) { 11782793Slm66018 (void) i_ldc_txq_reconf(ldcp); 11792793Slm66018 i_ldc_reset_state(ldcp); 11802793Slm66018 mutex_exit(&ldcp->tx_lock); 11812793Slm66018 return (EAGAIN); 11822793Slm66018 } 11832793Slm66018 11841991Sheppo /* get the current tail and pkt for the response */ 11851991Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 11861991Sheppo if (rv != 0) { 11871991Sheppo DWARN(ldcp->id, 11881991Sheppo "i_ldc_process_VER: (0x%llx) err sending " 11891991Sheppo "version ACK/NACK\n", ldcp->id); 11902793Slm66018 i_ldc_reset(ldcp, B_TRUE); 11912336Snarayan mutex_exit(&ldcp->tx_lock); 11921991Sheppo return (ECONNRESET); 11931991Sheppo } 11941991Sheppo 11951991Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 11961991Sheppo ZERO_PKT(pkt); 11971991Sheppo 11981991Sheppo /* initialize the packet */ 11991991Sheppo pkt->type = LDC_CTRL; 12001991Sheppo pkt->ctrl = LDC_VER; 12011991Sheppo 12021991Sheppo for (;;) { 12031991Sheppo 12041991Sheppo D1(ldcp->id, "i_ldc_process_VER: got %u.%u chk %u.%u\n", 12051991Sheppo rcvd_ver->major, rcvd_ver->minor, 12061991Sheppo ldc_versions[idx].major, ldc_versions[idx].minor); 12071991Sheppo 12081991Sheppo if (rcvd_ver->major == ldc_versions[idx].major) { 12091991Sheppo /* major version match - ACK version */ 12101991Sheppo pkt->stype = LDC_ACK; 12111991Sheppo 12121991Sheppo /* 12131991Sheppo * lower minor version to the one this endpt 12141991Sheppo * supports, if necessary 12151991Sheppo */ 12161991Sheppo if (rcvd_ver->minor > ldc_versions[idx].minor) 12171991Sheppo rcvd_ver->minor = 12184690Snarayan ldc_versions[idx].minor; 12191991Sheppo bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver)); 12201991Sheppo 12211991Sheppo break; 12221991Sheppo } 12231991Sheppo 12241991Sheppo if (rcvd_ver->major > ldc_versions[idx].major) { 12251991Sheppo 12261991Sheppo D1(ldcp->id, "i_ldc_process_VER: using next" 12271991Sheppo " lower idx=%d, v%u.%u\n", idx, 12281991Sheppo ldc_versions[idx].major, 12291991Sheppo ldc_versions[idx].minor); 12301991Sheppo 12311991Sheppo /* nack with next lower version */ 12321991Sheppo pkt->stype = LDC_NACK; 12331991Sheppo bcopy(&ldc_versions[idx], pkt->udata, 12341991Sheppo sizeof (ldc_versions[idx])); 12351991Sheppo ldcp->next_vidx = idx; 12361991Sheppo break; 12371991Sheppo } 12381991Sheppo 12391991Sheppo /* next major version */ 12401991Sheppo idx++; 12411991Sheppo 12421991Sheppo D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx); 12431991Sheppo 12441991Sheppo if (idx == LDC_NUM_VERS) { 12451991Sheppo /* no version match - send NACK */ 12461991Sheppo pkt->stype = LDC_NACK; 12471991Sheppo bzero(pkt->udata, sizeof (ldc_ver_t)); 12481991Sheppo ldcp->next_vidx = 0; 12491991Sheppo break; 12501991Sheppo } 12511991Sheppo } 12521991Sheppo 12531991Sheppo /* initiate the send by calling into HV and set the new tail */ 12541991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 12554690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 12561991Sheppo 12571991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 12581991Sheppo if (rv == 0) { 12591991Sheppo ldcp->tx_tail = tx_tail; 12601991Sheppo if (pkt->stype == LDC_ACK) { 12611991Sheppo D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent" 12621991Sheppo " version ACK\n", ldcp->id); 12631991Sheppo /* Save the ACK'd version */ 12641991Sheppo ldcp->version.major = rcvd_ver->major; 12651991Sheppo ldcp->version.minor = rcvd_ver->minor; 12662032Slm66018 ldcp->hstate |= TS_RCVD_VER; 12671991Sheppo ldcp->tstate |= TS_VER_DONE; 12683560Snarayan D1(DBG_ALL_LDCS, 12692793Slm66018 "(0x%llx) Sent ACK, " 12702793Slm66018 "Agreed on version v%u.%u\n", 12711991Sheppo ldcp->id, rcvd_ver->major, rcvd_ver->minor); 12721991Sheppo } 12731991Sheppo } else { 12741991Sheppo DWARN(ldcp->id, 12751991Sheppo "i_ldc_process_VER: (0x%llx) error sending " 12761991Sheppo "ACK/NACK\n", ldcp->id); 12772793Slm66018 i_ldc_reset(ldcp, B_TRUE); 12782336Snarayan mutex_exit(&ldcp->tx_lock); 12791991Sheppo return (ECONNRESET); 12801991Sheppo } 12811991Sheppo 12821991Sheppo break; 12831991Sheppo 12841991Sheppo case LDC_ACK: 12852793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) { 12862793Slm66018 if (ldcp->version.major != rcvd_ver->major || 12874690Snarayan ldcp->version.minor != rcvd_ver->minor) { 12882793Slm66018 12892793Slm66018 /* mismatched version - reset connection */ 12902793Slm66018 DWARN(ldcp->id, 12914690Snarayan "i_ldc_process_VER: (0x%llx) recvd" 12924690Snarayan " ACK ver != sent ACK ver\n", ldcp->id); 12932793Slm66018 i_ldc_reset(ldcp, B_TRUE); 12942793Slm66018 mutex_exit(&ldcp->tx_lock); 12952793Slm66018 return (ECONNRESET); 12962793Slm66018 } 12972793Slm66018 } else { 12982793Slm66018 /* SUCCESS - we have agreed on a version */ 12992793Slm66018 ldcp->version.major = rcvd_ver->major; 13002793Slm66018 ldcp->version.minor = rcvd_ver->minor; 13012793Slm66018 ldcp->tstate |= TS_VER_DONE; 13022793Slm66018 } 13032793Slm66018 13043010Slm66018 D1(ldcp->id, "(0x%llx) Got ACK, Agreed on version v%u.%u\n", 13051991Sheppo ldcp->id, rcvd_ver->major, rcvd_ver->minor); 13061991Sheppo 13071991Sheppo /* initiate RTS-RTR-RDX handshake */ 13081991Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 13091991Sheppo if (rv) { 13101991Sheppo DWARN(ldcp->id, 13112793Slm66018 "i_ldc_process_VER: (0x%llx) cannot send RTS\n", 13121991Sheppo ldcp->id); 13132793Slm66018 i_ldc_reset(ldcp, B_TRUE); 13142336Snarayan mutex_exit(&ldcp->tx_lock); 13151991Sheppo return (ECONNRESET); 13161991Sheppo } 13171991Sheppo 13181991Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 13191991Sheppo ZERO_PKT(pkt); 13201991Sheppo 13211991Sheppo pkt->type = LDC_CTRL; 13221991Sheppo pkt->stype = LDC_INFO; 13231991Sheppo pkt->ctrl = LDC_RTS; 13241991Sheppo pkt->env = ldcp->mode; 13251991Sheppo if (ldcp->mode != LDC_MODE_RAW) 13261991Sheppo pkt->seqid = LDC_INIT_SEQID; 13271991Sheppo 13281991Sheppo ldcp->last_msg_rcd = LDC_INIT_SEQID; 13291991Sheppo 13301991Sheppo DUMP_LDC_PKT(ldcp, "i_ldc_process_VER snd rts", (uint64_t)pkt); 13311991Sheppo 13321991Sheppo /* initiate the send by calling into HV and set the new tail */ 13331991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 13344690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 13351991Sheppo 13361991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 13371991Sheppo if (rv) { 13381991Sheppo D2(ldcp->id, 13391991Sheppo "i_ldc_process_VER: (0x%llx) no listener\n", 13401991Sheppo ldcp->id); 13412793Slm66018 i_ldc_reset(ldcp, B_TRUE); 13422336Snarayan mutex_exit(&ldcp->tx_lock); 13431991Sheppo return (ECONNRESET); 13441991Sheppo } 13451991Sheppo 13461991Sheppo ldcp->tx_tail = tx_tail; 13471991Sheppo ldcp->hstate |= TS_SENT_RTS; 13481991Sheppo 13491991Sheppo break; 13501991Sheppo 13511991Sheppo case LDC_NACK: 13521991Sheppo /* check if version in NACK is zero */ 13531991Sheppo if (rcvd_ver->major == 0 && rcvd_ver->minor == 0) { 13541991Sheppo /* version handshake failure */ 13551991Sheppo DWARN(DBG_ALL_LDCS, 13561991Sheppo "i_ldc_process_VER: (0x%llx) no version match\n", 13571991Sheppo ldcp->id); 13582793Slm66018 i_ldc_reset(ldcp, B_TRUE); 13592336Snarayan mutex_exit(&ldcp->tx_lock); 13601991Sheppo return (ECONNRESET); 13611991Sheppo } 13621991Sheppo 13631991Sheppo /* get the current tail and pkt for the response */ 13641991Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 13651991Sheppo if (rv != 0) { 13661991Sheppo cmn_err(CE_NOTE, 13671991Sheppo "i_ldc_process_VER: (0x%lx) err sending " 13681991Sheppo "version ACK/NACK\n", ldcp->id); 13692793Slm66018 i_ldc_reset(ldcp, B_TRUE); 13702336Snarayan mutex_exit(&ldcp->tx_lock); 13711991Sheppo return (ECONNRESET); 13721991Sheppo } 13731991Sheppo 13741991Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 13751991Sheppo ZERO_PKT(pkt); 13761991Sheppo 13771991Sheppo /* initialize the packet */ 13781991Sheppo pkt->type = LDC_CTRL; 13791991Sheppo pkt->ctrl = LDC_VER; 13801991Sheppo pkt->stype = LDC_INFO; 13811991Sheppo 13821991Sheppo /* check ver in NACK msg has a match */ 13831991Sheppo for (;;) { 13841991Sheppo if (rcvd_ver->major == ldc_versions[idx].major) { 13851991Sheppo /* 13861991Sheppo * major version match - resubmit request 13871991Sheppo * if lower minor version to the one this endpt 13881991Sheppo * supports, if necessary 13891991Sheppo */ 13901991Sheppo if (rcvd_ver->minor > ldc_versions[idx].minor) 13911991Sheppo rcvd_ver->minor = 13924690Snarayan ldc_versions[idx].minor; 13931991Sheppo bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver)); 13941991Sheppo break; 13951991Sheppo } 13961991Sheppo 13971991Sheppo if (rcvd_ver->major > ldc_versions[idx].major) { 13981991Sheppo 13991991Sheppo D1(ldcp->id, "i_ldc_process_VER: using next" 14001991Sheppo " lower idx=%d, v%u.%u\n", idx, 14011991Sheppo ldc_versions[idx].major, 14021991Sheppo ldc_versions[idx].minor); 14031991Sheppo 14041991Sheppo /* send next lower version */ 14051991Sheppo bcopy(&ldc_versions[idx], pkt->udata, 14061991Sheppo sizeof (ldc_versions[idx])); 14071991Sheppo ldcp->next_vidx = idx; 14081991Sheppo break; 14091991Sheppo } 14101991Sheppo 14111991Sheppo /* next version */ 14121991Sheppo idx++; 14131991Sheppo 14141991Sheppo D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx); 14151991Sheppo 14161991Sheppo if (idx == LDC_NUM_VERS) { 14171991Sheppo /* no version match - terminate */ 14181991Sheppo ldcp->next_vidx = 0; 14192336Snarayan mutex_exit(&ldcp->tx_lock); 14201991Sheppo return (ECONNRESET); 14211991Sheppo } 14221991Sheppo } 14231991Sheppo 14241991Sheppo /* initiate the send by calling into HV and set the new tail */ 14251991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 14264690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 14271991Sheppo 14281991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 14291991Sheppo if (rv == 0) { 14301991Sheppo D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent version" 14311991Sheppo "INFO v%u.%u\n", ldcp->id, ldc_versions[idx].major, 14321991Sheppo ldc_versions[idx].minor); 14331991Sheppo ldcp->tx_tail = tx_tail; 14341991Sheppo } else { 14351991Sheppo cmn_err(CE_NOTE, 14361991Sheppo "i_ldc_process_VER: (0x%lx) error sending version" 14371991Sheppo "INFO\n", ldcp->id); 14382793Slm66018 i_ldc_reset(ldcp, B_TRUE); 14392336Snarayan mutex_exit(&ldcp->tx_lock); 14401991Sheppo return (ECONNRESET); 14411991Sheppo } 14421991Sheppo 14431991Sheppo break; 14441991Sheppo } 14451991Sheppo 14462336Snarayan mutex_exit(&ldcp->tx_lock); 14471991Sheppo return (rv); 14481991Sheppo } 14491991Sheppo 14501991Sheppo 14511991Sheppo /* 14521991Sheppo * Process an incoming RTS ctrl message 14531991Sheppo */ 14541991Sheppo static int 14551991Sheppo i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg) 14561991Sheppo { 14571991Sheppo int rv = 0; 14581991Sheppo ldc_msg_t *pkt; 14591991Sheppo uint64_t tx_tail; 14601991Sheppo boolean_t sent_NACK = B_FALSE; 14611991Sheppo 14621991Sheppo D2(ldcp->id, "i_ldc_process_RTS: (0x%llx) received RTS\n", ldcp->id); 14631991Sheppo 14641991Sheppo switch (msg->stype) { 14651991Sheppo case LDC_NACK: 14661991Sheppo DWARN(ldcp->id, 14671991Sheppo "i_ldc_process_RTS: (0x%llx) RTS NACK received\n", 14681991Sheppo ldcp->id); 14691991Sheppo 14701991Sheppo /* Reset the channel -- as we cannot continue */ 14712336Snarayan mutex_enter(&ldcp->tx_lock); 14722793Slm66018 i_ldc_reset(ldcp, B_TRUE); 14732336Snarayan mutex_exit(&ldcp->tx_lock); 14741991Sheppo rv = ECONNRESET; 14751991Sheppo break; 14761991Sheppo 14771991Sheppo case LDC_INFO: 14781991Sheppo 14791991Sheppo /* check mode */ 14801991Sheppo if (ldcp->mode != (ldc_mode_t)msg->env) { 14811991Sheppo cmn_err(CE_NOTE, 14821991Sheppo "i_ldc_process_RTS: (0x%lx) mode mismatch\n", 14831991Sheppo ldcp->id); 14841991Sheppo /* 14851991Sheppo * send NACK in response to MODE message 14861991Sheppo * get the current tail for the response 14871991Sheppo */ 14881991Sheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTS); 14891991Sheppo if (rv) { 14901991Sheppo /* if cannot send NACK - reset channel */ 14912336Snarayan mutex_enter(&ldcp->tx_lock); 14922793Slm66018 i_ldc_reset(ldcp, B_TRUE); 14932336Snarayan mutex_exit(&ldcp->tx_lock); 14941991Sheppo rv = ECONNRESET; 14951991Sheppo break; 14961991Sheppo } 14971991Sheppo sent_NACK = B_TRUE; 14981991Sheppo } 14991991Sheppo break; 15001991Sheppo default: 15011991Sheppo DWARN(ldcp->id, "i_ldc_process_RTS: (0x%llx) unexp ACK\n", 15021991Sheppo ldcp->id); 15032336Snarayan mutex_enter(&ldcp->tx_lock); 15042793Slm66018 i_ldc_reset(ldcp, B_TRUE); 15052336Snarayan mutex_exit(&ldcp->tx_lock); 15061991Sheppo rv = ECONNRESET; 15071991Sheppo break; 15081991Sheppo } 15091991Sheppo 15101991Sheppo /* 15111991Sheppo * If either the connection was reset (when rv != 0) or 15121991Sheppo * a NACK was sent, we return. In the case of a NACK 15131991Sheppo * we dont want to consume the packet that came in but 15141991Sheppo * not record that we received the RTS 15151991Sheppo */ 15161991Sheppo if (rv || sent_NACK) 15171991Sheppo return (rv); 15181991Sheppo 15191991Sheppo /* record RTS received */ 15201991Sheppo ldcp->hstate |= TS_RCVD_RTS; 15211991Sheppo 15221991Sheppo /* store initial SEQID info */ 15231991Sheppo ldcp->last_msg_snt = msg->seqid; 15241991Sheppo 15252336Snarayan /* Obtain Tx lock */ 15262336Snarayan mutex_enter(&ldcp->tx_lock); 15272336Snarayan 15281991Sheppo /* get the current tail for the response */ 15291991Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 15301991Sheppo if (rv != 0) { 15311991Sheppo cmn_err(CE_NOTE, 15321991Sheppo "i_ldc_process_RTS: (0x%lx) err sending RTR\n", 15331991Sheppo ldcp->id); 15342793Slm66018 i_ldc_reset(ldcp, B_TRUE); 15352336Snarayan mutex_exit(&ldcp->tx_lock); 15361991Sheppo return (ECONNRESET); 15371991Sheppo } 15381991Sheppo 15391991Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 15401991Sheppo ZERO_PKT(pkt); 15411991Sheppo 15421991Sheppo /* initialize the packet */ 15431991Sheppo pkt->type = LDC_CTRL; 15441991Sheppo pkt->stype = LDC_INFO; 15451991Sheppo pkt->ctrl = LDC_RTR; 15461991Sheppo pkt->env = ldcp->mode; 15471991Sheppo if (ldcp->mode != LDC_MODE_RAW) 15481991Sheppo pkt->seqid = LDC_INIT_SEQID; 15491991Sheppo 15501991Sheppo ldcp->last_msg_rcd = msg->seqid; 15511991Sheppo 15521991Sheppo /* initiate the send by calling into HV and set the new tail */ 15531991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 15544690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 15551991Sheppo 15561991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 15571991Sheppo if (rv == 0) { 15581991Sheppo D2(ldcp->id, 15591991Sheppo "i_ldc_process_RTS: (0x%llx) sent RTR\n", ldcp->id); 15601991Sheppo DUMP_LDC_PKT(ldcp, "i_ldc_process_RTS sent rtr", (uint64_t)pkt); 15611991Sheppo 15621991Sheppo ldcp->tx_tail = tx_tail; 15631991Sheppo ldcp->hstate |= TS_SENT_RTR; 15641991Sheppo 15651991Sheppo } else { 15661991Sheppo cmn_err(CE_NOTE, 15671991Sheppo "i_ldc_process_RTS: (0x%lx) error sending RTR\n", 15681991Sheppo ldcp->id); 15692793Slm66018 i_ldc_reset(ldcp, B_TRUE); 15702336Snarayan mutex_exit(&ldcp->tx_lock); 15711991Sheppo return (ECONNRESET); 15721991Sheppo } 15731991Sheppo 15742336Snarayan mutex_exit(&ldcp->tx_lock); 15751991Sheppo return (0); 15761991Sheppo } 15771991Sheppo 15781991Sheppo /* 15791991Sheppo * Process an incoming RTR ctrl message 15801991Sheppo */ 15811991Sheppo static int 15821991Sheppo i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg) 15831991Sheppo { 15841991Sheppo int rv = 0; 15851991Sheppo boolean_t sent_NACK = B_FALSE; 15861991Sheppo 15871991Sheppo D2(ldcp->id, "i_ldc_process_RTR: (0x%llx) received RTR\n", ldcp->id); 15881991Sheppo 15891991Sheppo switch (msg->stype) { 15901991Sheppo case LDC_NACK: 15911991Sheppo /* RTR NACK received */ 15921991Sheppo DWARN(ldcp->id, 15931991Sheppo "i_ldc_process_RTR: (0x%llx) RTR NACK received\n", 15941991Sheppo ldcp->id); 15951991Sheppo 15961991Sheppo /* Reset the channel -- as we cannot continue */ 15972336Snarayan mutex_enter(&ldcp->tx_lock); 15982793Slm66018 i_ldc_reset(ldcp, B_TRUE); 15992336Snarayan mutex_exit(&ldcp->tx_lock); 16001991Sheppo rv = ECONNRESET; 16011991Sheppo 16021991Sheppo break; 16031991Sheppo 16041991Sheppo case LDC_INFO: 16051991Sheppo 16061991Sheppo /* check mode */ 16071991Sheppo if (ldcp->mode != (ldc_mode_t)msg->env) { 16081991Sheppo DWARN(ldcp->id, 16093010Slm66018 "i_ldc_process_RTR: (0x%llx) mode mismatch, " 16103010Slm66018 "expecting 0x%x, got 0x%x\n", 16113010Slm66018 ldcp->id, ldcp->mode, (ldc_mode_t)msg->env); 16121991Sheppo /* 16131991Sheppo * send NACK in response to MODE message 16141991Sheppo * get the current tail for the response 16151991Sheppo */ 16161991Sheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTR); 16171991Sheppo if (rv) { 16181991Sheppo /* if cannot send NACK - reset channel */ 16192336Snarayan mutex_enter(&ldcp->tx_lock); 16202793Slm66018 i_ldc_reset(ldcp, B_TRUE); 16212336Snarayan mutex_exit(&ldcp->tx_lock); 16221991Sheppo rv = ECONNRESET; 16231991Sheppo break; 16241991Sheppo } 16251991Sheppo sent_NACK = B_TRUE; 16261991Sheppo } 16271991Sheppo break; 16281991Sheppo 16291991Sheppo default: 16301991Sheppo DWARN(ldcp->id, "i_ldc_process_RTR: (0x%llx) unexp ACK\n", 16311991Sheppo ldcp->id); 16321991Sheppo 16331991Sheppo /* Reset the channel -- as we cannot continue */ 16342336Snarayan mutex_enter(&ldcp->tx_lock); 16352793Slm66018 i_ldc_reset(ldcp, B_TRUE); 16362336Snarayan mutex_exit(&ldcp->tx_lock); 16371991Sheppo rv = ECONNRESET; 16381991Sheppo break; 16391991Sheppo } 16401991Sheppo 16411991Sheppo /* 16421991Sheppo * If either the connection was reset (when rv != 0) or 16431991Sheppo * a NACK was sent, we return. In the case of a NACK 16441991Sheppo * we dont want to consume the packet that came in but 16451991Sheppo * not record that we received the RTR 16461991Sheppo */ 16471991Sheppo if (rv || sent_NACK) 16481991Sheppo return (rv); 16491991Sheppo 16501991Sheppo ldcp->last_msg_snt = msg->seqid; 16511991Sheppo ldcp->hstate |= TS_RCVD_RTR; 16521991Sheppo 16531991Sheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_INFO, LDC_RDX); 16541991Sheppo if (rv) { 16551991Sheppo cmn_err(CE_NOTE, 16561991Sheppo "i_ldc_process_RTR: (0x%lx) cannot send RDX\n", 16571991Sheppo ldcp->id); 16582336Snarayan mutex_enter(&ldcp->tx_lock); 16592793Slm66018 i_ldc_reset(ldcp, B_TRUE); 16602336Snarayan mutex_exit(&ldcp->tx_lock); 16611991Sheppo return (ECONNRESET); 16621991Sheppo } 16631991Sheppo D2(ldcp->id, 16641991Sheppo "i_ldc_process_RTR: (0x%llx) sent RDX\n", ldcp->id); 16651991Sheppo 16661991Sheppo ldcp->hstate |= TS_SENT_RDX; 16671991Sheppo ldcp->tstate |= TS_HSHAKE_DONE; 16682793Slm66018 if ((ldcp->tstate & TS_IN_RESET) == 0) 16692793Slm66018 ldcp->status = LDC_UP; 16701991Sheppo 16713010Slm66018 D1(ldcp->id, "(0x%llx) Handshake Complete\n", ldcp->id); 16721991Sheppo 16731991Sheppo return (0); 16741991Sheppo } 16751991Sheppo 16761991Sheppo 16771991Sheppo /* 16781991Sheppo * Process an incoming RDX ctrl message 16791991Sheppo */ 16801991Sheppo static int 16811991Sheppo i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg) 16821991Sheppo { 16831991Sheppo int rv = 0; 16841991Sheppo 16851991Sheppo D2(ldcp->id, "i_ldc_process_RDX: (0x%llx) received RDX\n", ldcp->id); 16861991Sheppo 16871991Sheppo switch (msg->stype) { 16881991Sheppo case LDC_NACK: 16891991Sheppo /* RDX NACK received */ 16901991Sheppo DWARN(ldcp->id, 16911991Sheppo "i_ldc_process_RDX: (0x%llx) RDX NACK received\n", 16921991Sheppo ldcp->id); 16931991Sheppo 16941991Sheppo /* Reset the channel -- as we cannot continue */ 16952336Snarayan mutex_enter(&ldcp->tx_lock); 16962793Slm66018 i_ldc_reset(ldcp, B_TRUE); 16972336Snarayan mutex_exit(&ldcp->tx_lock); 16981991Sheppo rv = ECONNRESET; 16991991Sheppo 17001991Sheppo break; 17011991Sheppo 17021991Sheppo case LDC_INFO: 17031991Sheppo 17041991Sheppo /* 17051991Sheppo * if channel is UP and a RDX received after data transmission 17061991Sheppo * has commenced it is an error 17071991Sheppo */ 17081991Sheppo if ((ldcp->tstate == TS_UP) && (ldcp->hstate & TS_RCVD_RDX)) { 17091991Sheppo DWARN(DBG_ALL_LDCS, 17101991Sheppo "i_ldc_process_RDX: (0x%llx) unexpected RDX" 17111991Sheppo " - LDC reset\n", ldcp->id); 17122336Snarayan mutex_enter(&ldcp->tx_lock); 17132793Slm66018 i_ldc_reset(ldcp, B_TRUE); 17142336Snarayan mutex_exit(&ldcp->tx_lock); 17151991Sheppo return (ECONNRESET); 17161991Sheppo } 17171991Sheppo 17181991Sheppo ldcp->hstate |= TS_RCVD_RDX; 17191991Sheppo ldcp->tstate |= TS_HSHAKE_DONE; 17202793Slm66018 if ((ldcp->tstate & TS_IN_RESET) == 0) 17212793Slm66018 ldcp->status = LDC_UP; 17221991Sheppo 17231991Sheppo D1(DBG_ALL_LDCS, "(0x%llx) Handshake Complete\n", ldcp->id); 17241991Sheppo break; 17251991Sheppo 17261991Sheppo default: 17271991Sheppo DWARN(ldcp->id, "i_ldc_process_RDX: (0x%llx) unexp ACK\n", 17281991Sheppo ldcp->id); 17291991Sheppo 17301991Sheppo /* Reset the channel -- as we cannot continue */ 17312336Snarayan mutex_enter(&ldcp->tx_lock); 17322793Slm66018 i_ldc_reset(ldcp, B_TRUE); 17332336Snarayan mutex_exit(&ldcp->tx_lock); 17341991Sheppo rv = ECONNRESET; 17351991Sheppo break; 17361991Sheppo } 17371991Sheppo 17381991Sheppo return (rv); 17391991Sheppo } 17401991Sheppo 17411991Sheppo /* 17421991Sheppo * Process an incoming ACK for a data packet 17431991Sheppo */ 17441991Sheppo static int 17451991Sheppo i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg) 17461991Sheppo { 17471991Sheppo int rv; 17481991Sheppo uint64_t tx_head; 17491991Sheppo ldc_msg_t *pkt; 17501991Sheppo 17512336Snarayan /* Obtain Tx lock */ 17522336Snarayan mutex_enter(&ldcp->tx_lock); 17532336Snarayan 17541991Sheppo /* 17552336Snarayan * Read the current Tx head and tail 17561991Sheppo */ 17571991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 17581991Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 17591991Sheppo if (rv != 0) { 17601991Sheppo cmn_err(CE_WARN, 17611991Sheppo "i_ldc_process_data_ACK: (0x%lx) cannot read qptrs\n", 17621991Sheppo ldcp->id); 17632336Snarayan 17642336Snarayan /* Reset the channel -- as we cannot continue */ 17652793Slm66018 i_ldc_reset(ldcp, B_TRUE); 17662336Snarayan mutex_exit(&ldcp->tx_lock); 17672336Snarayan return (ECONNRESET); 17681991Sheppo } 17691991Sheppo 17701991Sheppo /* 17711991Sheppo * loop from where the previous ACK location was to the 17721991Sheppo * current head location. This is how far the HV has 17731991Sheppo * actually send pkts. Pkts between head and tail are 17741991Sheppo * yet to be sent by HV. 17751991Sheppo */ 17761991Sheppo tx_head = ldcp->tx_ackd_head; 17771991Sheppo for (;;) { 17781991Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_head); 17791991Sheppo tx_head = (tx_head + LDC_PACKET_SIZE) % 17804690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 17811991Sheppo 17821991Sheppo if (pkt->seqid == msg->ackid) { 17831991Sheppo D2(ldcp->id, 17841991Sheppo "i_ldc_process_data_ACK: (0x%llx) found packet\n", 17851991Sheppo ldcp->id); 17861991Sheppo ldcp->last_ack_rcd = msg->ackid; 17871991Sheppo ldcp->tx_ackd_head = tx_head; 17881991Sheppo break; 17891991Sheppo } 17901991Sheppo if (tx_head == ldcp->tx_head) { 17911991Sheppo /* could not find packet */ 17921991Sheppo DWARN(ldcp->id, 17931991Sheppo "i_ldc_process_data_ACK: (0x%llx) invalid ACKid\n", 17941991Sheppo ldcp->id); 17952336Snarayan 17962336Snarayan /* Reset the channel -- as we cannot continue */ 17972793Slm66018 i_ldc_reset(ldcp, B_TRUE); 17982336Snarayan mutex_exit(&ldcp->tx_lock); 17992336Snarayan return (ECONNRESET); 18001991Sheppo } 18011991Sheppo } 18021991Sheppo 18032336Snarayan mutex_exit(&ldcp->tx_lock); 18041991Sheppo return (0); 18051991Sheppo } 18061991Sheppo 18071991Sheppo /* 18081991Sheppo * Process incoming control message 18091991Sheppo * Return 0 - session can continue 18101991Sheppo * EAGAIN - reprocess packet - state was changed 18111991Sheppo * ECONNRESET - channel was reset 18121991Sheppo */ 18131991Sheppo static int 18141991Sheppo i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *msg) 18151991Sheppo { 18161991Sheppo int rv = 0; 18171991Sheppo 18182793Slm66018 D1(ldcp->id, "i_ldc_ctrlmsg: (%llx) tstate = %lx, hstate = %lx\n", 18192793Slm66018 ldcp->id, ldcp->tstate, ldcp->hstate); 18202793Slm66018 18212793Slm66018 switch (ldcp->tstate & ~TS_IN_RESET) { 18221991Sheppo 18231991Sheppo case TS_OPEN: 18241991Sheppo case TS_READY: 18251991Sheppo 18261991Sheppo switch (msg->ctrl & LDC_CTRL_MASK) { 18271991Sheppo case LDC_VER: 18281991Sheppo /* process version message */ 18291991Sheppo rv = i_ldc_process_VER(ldcp, msg); 18301991Sheppo break; 18311991Sheppo default: 18321991Sheppo DWARN(ldcp->id, 18331991Sheppo "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x " 18341991Sheppo "tstate=0x%x\n", ldcp->id, 18351991Sheppo (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate); 18361991Sheppo break; 18371991Sheppo } 18381991Sheppo 18391991Sheppo break; 18401991Sheppo 18411991Sheppo case TS_VREADY: 18421991Sheppo 18431991Sheppo switch (msg->ctrl & LDC_CTRL_MASK) { 18441991Sheppo case LDC_VER: 18452793Slm66018 /* process version message */ 18462793Slm66018 rv = i_ldc_process_VER(ldcp, msg); 18471991Sheppo break; 18481991Sheppo case LDC_RTS: 18491991Sheppo /* process RTS message */ 18501991Sheppo rv = i_ldc_process_RTS(ldcp, msg); 18511991Sheppo break; 18521991Sheppo case LDC_RTR: 18531991Sheppo /* process RTR message */ 18541991Sheppo rv = i_ldc_process_RTR(ldcp, msg); 18551991Sheppo break; 18561991Sheppo case LDC_RDX: 18571991Sheppo /* process RDX message */ 18581991Sheppo rv = i_ldc_process_RDX(ldcp, msg); 18591991Sheppo break; 18601991Sheppo default: 18611991Sheppo DWARN(ldcp->id, 18621991Sheppo "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x " 18631991Sheppo "tstate=0x%x\n", ldcp->id, 18641991Sheppo (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate); 18651991Sheppo break; 18661991Sheppo } 18671991Sheppo 18681991Sheppo break; 18691991Sheppo 18701991Sheppo case TS_UP: 18711991Sheppo 18721991Sheppo switch (msg->ctrl & LDC_CTRL_MASK) { 18731991Sheppo case LDC_VER: 18741991Sheppo DWARN(ldcp->id, 18751991Sheppo "i_ldc_ctrlmsg: (0x%llx) unexpected VER " 18761991Sheppo "- LDC reset\n", ldcp->id); 18771991Sheppo /* peer is redoing version negotiation */ 18782336Snarayan mutex_enter(&ldcp->tx_lock); 18791991Sheppo (void) i_ldc_txq_reconf(ldcp); 18801991Sheppo i_ldc_reset_state(ldcp); 18812336Snarayan mutex_exit(&ldcp->tx_lock); 18821991Sheppo rv = EAGAIN; 18831991Sheppo break; 18841991Sheppo 18851991Sheppo case LDC_RDX: 18861991Sheppo /* process RDX message */ 18871991Sheppo rv = i_ldc_process_RDX(ldcp, msg); 18881991Sheppo break; 18891991Sheppo 18901991Sheppo default: 18911991Sheppo DWARN(ldcp->id, 18921991Sheppo "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x " 18931991Sheppo "tstate=0x%x\n", ldcp->id, 18941991Sheppo (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate); 18951991Sheppo break; 18961991Sheppo } 18971991Sheppo } 18981991Sheppo 18991991Sheppo return (rv); 19001991Sheppo } 19011991Sheppo 19021991Sheppo /* 19031991Sheppo * Register channel with the channel nexus 19041991Sheppo */ 19051991Sheppo static int 19061991Sheppo i_ldc_register_channel(ldc_chan_t *ldcp) 19071991Sheppo { 19081991Sheppo int rv = 0; 19091991Sheppo ldc_cnex_t *cinfo = &ldcssp->cinfo; 19101991Sheppo 19111991Sheppo if (cinfo->dip == NULL) { 19121991Sheppo DWARN(ldcp->id, 19131991Sheppo "i_ldc_register_channel: cnex has not registered\n"); 19141991Sheppo return (EAGAIN); 19151991Sheppo } 19161991Sheppo 19171991Sheppo rv = cinfo->reg_chan(cinfo->dip, ldcp->id, ldcp->devclass); 19181991Sheppo if (rv) { 19191991Sheppo DWARN(ldcp->id, 19201991Sheppo "i_ldc_register_channel: cannot register channel\n"); 19211991Sheppo return (rv); 19221991Sheppo } 19231991Sheppo 19241991Sheppo rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR, 19251991Sheppo i_ldc_tx_hdlr, ldcp, NULL); 19261991Sheppo if (rv) { 19271991Sheppo DWARN(ldcp->id, 19281991Sheppo "i_ldc_register_channel: cannot add Tx interrupt\n"); 19291991Sheppo (void) cinfo->unreg_chan(cinfo->dip, ldcp->id); 19301991Sheppo return (rv); 19311991Sheppo } 19321991Sheppo 19331991Sheppo rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR, 19341991Sheppo i_ldc_rx_hdlr, ldcp, NULL); 19351991Sheppo if (rv) { 19361991Sheppo DWARN(ldcp->id, 19371991Sheppo "i_ldc_register_channel: cannot add Rx interrupt\n"); 19381991Sheppo (void) cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR); 19391991Sheppo (void) cinfo->unreg_chan(cinfo->dip, ldcp->id); 19401991Sheppo return (rv); 19411991Sheppo } 19421991Sheppo 19431991Sheppo ldcp->tstate |= TS_CNEX_RDY; 19441991Sheppo 19451991Sheppo return (0); 19461991Sheppo } 19471991Sheppo 19481991Sheppo /* 19491991Sheppo * Unregister a channel with the channel nexus 19501991Sheppo */ 19511991Sheppo static int 19521991Sheppo i_ldc_unregister_channel(ldc_chan_t *ldcp) 19531991Sheppo { 19541991Sheppo int rv = 0; 19551991Sheppo ldc_cnex_t *cinfo = &ldcssp->cinfo; 19561991Sheppo 19571991Sheppo if (cinfo->dip == NULL) { 19581991Sheppo DWARN(ldcp->id, 19591991Sheppo "i_ldc_unregister_channel: cnex has not registered\n"); 19601991Sheppo return (EAGAIN); 19611991Sheppo } 19621991Sheppo 19631991Sheppo if (ldcp->tstate & TS_CNEX_RDY) { 19641991Sheppo 19652336Snarayan /* Remove the Rx interrupt */ 19661991Sheppo rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR); 19671991Sheppo if (rv) { 19682793Slm66018 if (rv != EAGAIN) { 19692793Slm66018 DWARN(ldcp->id, 19702793Slm66018 "i_ldc_unregister_channel: err removing " 19712793Slm66018 "Rx intr\n"); 19722793Slm66018 return (rv); 19732793Slm66018 } 19742793Slm66018 19752793Slm66018 /* 19762793Slm66018 * If interrupts are pending and handler has 19772793Slm66018 * finished running, clear interrupt and try 19782793Slm66018 * again 19792793Slm66018 */ 19802793Slm66018 if (ldcp->rx_intr_state != LDC_INTR_PEND) 19812793Slm66018 return (rv); 19822793Slm66018 19832793Slm66018 (void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 19842793Slm66018 rv = cinfo->rem_intr(cinfo->dip, ldcp->id, 19852793Slm66018 CNEX_RX_INTR); 19862793Slm66018 if (rv) { 19872793Slm66018 DWARN(ldcp->id, "i_ldc_unregister_channel: " 19882793Slm66018 "err removing Rx interrupt\n"); 19892793Slm66018 return (rv); 19902793Slm66018 } 19911991Sheppo } 19922336Snarayan 19932336Snarayan /* Remove the Tx interrupt */ 19941991Sheppo rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR); 19951991Sheppo if (rv) { 19961991Sheppo DWARN(ldcp->id, 19971991Sheppo "i_ldc_unregister_channel: err removing Tx intr\n"); 19982336Snarayan return (rv); 19991991Sheppo } 20002336Snarayan 20012336Snarayan /* Unregister the channel */ 20021991Sheppo rv = cinfo->unreg_chan(ldcssp->cinfo.dip, ldcp->id); 20031991Sheppo if (rv) { 20041991Sheppo DWARN(ldcp->id, 20051991Sheppo "i_ldc_unregister_channel: cannot unreg channel\n"); 20062336Snarayan return (rv); 20071991Sheppo } 20081991Sheppo 20091991Sheppo ldcp->tstate &= ~TS_CNEX_RDY; 20101991Sheppo } 20111991Sheppo 20121991Sheppo return (0); 20131991Sheppo } 20141991Sheppo 20151991Sheppo 20161991Sheppo /* 20171991Sheppo * LDC transmit interrupt handler 20181991Sheppo * triggered for chanel up/down/reset events 20191991Sheppo * and Tx queue content changes 20201991Sheppo */ 20211991Sheppo static uint_t 20221991Sheppo i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2) 20231991Sheppo { 20241991Sheppo _NOTE(ARGUNUSED(arg2)) 20251991Sheppo 20261991Sheppo int rv; 20271991Sheppo ldc_chan_t *ldcp; 20281991Sheppo boolean_t notify_client = B_FALSE; 20292793Slm66018 uint64_t notify_event = 0, link_state; 20301991Sheppo 20311991Sheppo /* Get the channel for which interrupt was received */ 20321991Sheppo ASSERT(arg1 != NULL); 20331991Sheppo ldcp = (ldc_chan_t *)arg1; 20341991Sheppo 20351991Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n", 20361991Sheppo ldcp->id, ldcp); 20371991Sheppo 20381991Sheppo /* Lock channel */ 20391991Sheppo mutex_enter(&ldcp->lock); 20401991Sheppo 20412336Snarayan /* Obtain Tx lock */ 20422336Snarayan mutex_enter(&ldcp->tx_lock); 20432336Snarayan 20442531Snarayan /* mark interrupt as pending */ 20452793Slm66018 ldcp->tx_intr_state = LDC_INTR_ACTIVE; 20462793Slm66018 20472793Slm66018 /* save current link state */ 20482793Slm66018 link_state = ldcp->link_state; 20492531Snarayan 20501991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, &ldcp->tx_head, &ldcp->tx_tail, 20511991Sheppo &ldcp->link_state); 20521991Sheppo if (rv) { 20531991Sheppo cmn_err(CE_WARN, 20541991Sheppo "i_ldc_tx_hdlr: (0x%lx) cannot read queue ptrs rv=0x%d\n", 20551991Sheppo ldcp->id, rv); 20562531Snarayan i_ldc_clear_intr(ldcp, CNEX_TX_INTR); 20572336Snarayan mutex_exit(&ldcp->tx_lock); 20581991Sheppo mutex_exit(&ldcp->lock); 20591991Sheppo return (DDI_INTR_CLAIMED); 20601991Sheppo } 20611991Sheppo 20621991Sheppo /* 20631991Sheppo * reset the channel state if the channel went down 20641991Sheppo * (other side unconfigured queue) or channel was reset 20651991Sheppo * (other side reconfigured its queue) 20661991Sheppo */ 20672793Slm66018 if (link_state != ldcp->link_state && 20682793Slm66018 ldcp->link_state == LDC_CHANNEL_DOWN) { 20691991Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: channel link down\n", ldcp->id); 20702793Slm66018 i_ldc_reset(ldcp, B_FALSE); 20711991Sheppo notify_client = B_TRUE; 20721991Sheppo notify_event = LDC_EVT_DOWN; 20731991Sheppo } 20741991Sheppo 20752793Slm66018 if (link_state != ldcp->link_state && 20762793Slm66018 ldcp->link_state == LDC_CHANNEL_RESET) { 20771991Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: channel link reset\n", ldcp->id); 20782793Slm66018 i_ldc_reset(ldcp, B_FALSE); 20791991Sheppo notify_client = B_TRUE; 20801991Sheppo notify_event = LDC_EVT_RESET; 20811991Sheppo } 20821991Sheppo 20832793Slm66018 if (link_state != ldcp->link_state && 20842793Slm66018 (ldcp->tstate & ~TS_IN_RESET) == TS_OPEN && 20852793Slm66018 ldcp->link_state == LDC_CHANNEL_UP) { 20861991Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: channel link up\n", ldcp->id); 20871991Sheppo notify_client = B_TRUE; 20881991Sheppo notify_event = LDC_EVT_RESET; 20891991Sheppo ldcp->tstate |= TS_LINK_READY; 20901991Sheppo ldcp->status = LDC_READY; 20911991Sheppo } 20921991Sheppo 20931991Sheppo /* if callbacks are disabled, do not notify */ 20941991Sheppo if (!ldcp->cb_enabled) 20951991Sheppo notify_client = B_FALSE; 20961991Sheppo 20973151Ssg70180 i_ldc_clear_intr(ldcp, CNEX_TX_INTR); 20984690Snarayan mutex_exit(&ldcp->tx_lock); 20991991Sheppo 21001991Sheppo if (notify_client) { 21012793Slm66018 ldcp->cb_inprogress = B_TRUE; 21022793Slm66018 mutex_exit(&ldcp->lock); 21031991Sheppo rv = ldcp->cb(notify_event, ldcp->cb_arg); 21041991Sheppo if (rv) { 21051991Sheppo DWARN(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) callback " 21061991Sheppo "failure", ldcp->id); 21071991Sheppo } 21081991Sheppo mutex_enter(&ldcp->lock); 21091991Sheppo ldcp->cb_inprogress = B_FALSE; 21102793Slm66018 } 21112793Slm66018 21121991Sheppo mutex_exit(&ldcp->lock); 21131991Sheppo 21141991Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) exiting handler", ldcp->id); 21151991Sheppo 21161991Sheppo return (DDI_INTR_CLAIMED); 21171991Sheppo } 21181991Sheppo 21191991Sheppo /* 21205944Sha137994 * Process the Rx HV queue. 21215944Sha137994 * 21225944Sha137994 * Returns 0 if data packets were found and no errors were encountered, 21235944Sha137994 * otherwise returns an error. In either case, the *notify argument is 21245944Sha137994 * set to indicate whether or not the client callback function should 21255944Sha137994 * be invoked. The *event argument is set to contain the callback event. 21265944Sha137994 * 21275944Sha137994 * Depending on the channel mode, packets are handled differently: 21285944Sha137994 * 21295944Sha137994 * RAW MODE 21305944Sha137994 * For raw mode channels, when a data packet is encountered, 21315944Sha137994 * processing stops and all packets are left on the queue to be removed 21325944Sha137994 * and processed by the ldc_read code path. 21335944Sha137994 * 21345944Sha137994 * UNRELIABLE MODE 21355944Sha137994 * For unreliable mode, when a data packet is encountered, processing 21365944Sha137994 * stops, and all packets are left on the queue to be removed and 21375944Sha137994 * processed by the ldc_read code path. Control packets are processed 21385944Sha137994 * inline if they are encountered before any data packets. 21395944Sha137994 * 21406408Sha137994 * RELIABLE MODE 21416408Sha137994 * For reliable mode channels, all packets on the receive queue 21425944Sha137994 * are processed: data packets are copied to the data queue and 21435944Sha137994 * control packets are processed inline. Packets are only left on 21445944Sha137994 * the receive queue when the data queue is full. 21451991Sheppo */ 21461991Sheppo static uint_t 21475944Sha137994 i_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client, 21485944Sha137994 uint64_t *notify_event) 21491991Sheppo { 21501991Sheppo int rv; 21511991Sheppo uint64_t rx_head, rx_tail; 21521991Sheppo ldc_msg_t *msg; 21532793Slm66018 uint64_t link_state, first_fragment = 0; 21545944Sha137994 boolean_t trace_length = B_TRUE; 21555944Sha137994 21565944Sha137994 ASSERT(MUTEX_HELD(&ldcp->lock)); 21575944Sha137994 *notify_client = B_FALSE; 21585944Sha137994 *notify_event = 0; 21591991Sheppo 21601991Sheppo /* 21611991Sheppo * Read packet(s) from the queue 21621991Sheppo */ 21631991Sheppo for (;;) { 21641991Sheppo 21652793Slm66018 link_state = ldcp->link_state; 21661991Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 21671991Sheppo &ldcp->link_state); 21681991Sheppo if (rv) { 21691991Sheppo cmn_err(CE_WARN, 21705944Sha137994 "i_ldc_rx_process_hvq: (0x%lx) cannot read " 21711991Sheppo "queue ptrs, rv=0x%d\n", ldcp->id, rv); 21721991Sheppo i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 21735944Sha137994 return (EIO); 21741991Sheppo } 21751991Sheppo 21761991Sheppo /* 21771991Sheppo * reset the channel state if the channel went down 21781991Sheppo * (other side unconfigured queue) or channel was reset 21792793Slm66018 * (other side reconfigured its queue) 21801991Sheppo */ 21812793Slm66018 21822793Slm66018 if (link_state != ldcp->link_state) { 21833010Slm66018 21842793Slm66018 switch (ldcp->link_state) { 21852793Slm66018 case LDC_CHANNEL_DOWN: 21865944Sha137994 D1(ldcp->id, "i_ldc_rx_process_hvq: channel " 21872793Slm66018 "link down\n", ldcp->id); 21882793Slm66018 mutex_enter(&ldcp->tx_lock); 21892793Slm66018 i_ldc_reset(ldcp, B_FALSE); 21902793Slm66018 mutex_exit(&ldcp->tx_lock); 21915944Sha137994 *notify_client = B_TRUE; 21925944Sha137994 *notify_event = LDC_EVT_DOWN; 21932793Slm66018 goto loop_exit; 21942793Slm66018 21952793Slm66018 case LDC_CHANNEL_UP: 21965944Sha137994 D1(ldcp->id, "i_ldc_rx_process_hvq: " 21972793Slm66018 "channel link up\n", ldcp->id); 21982793Slm66018 21992793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) == TS_OPEN) { 22005944Sha137994 *notify_client = B_TRUE; 22015944Sha137994 *notify_event = LDC_EVT_RESET; 22022793Slm66018 ldcp->tstate |= TS_LINK_READY; 22032793Slm66018 ldcp->status = LDC_READY; 22042793Slm66018 } 22052793Slm66018 break; 22062793Slm66018 22072793Slm66018 case LDC_CHANNEL_RESET: 22082793Slm66018 default: 22092793Slm66018 #ifdef DEBUG 22102793Slm66018 force_reset: 22112793Slm66018 #endif 22125944Sha137994 D1(ldcp->id, "i_ldc_rx_process_hvq: channel " 22132793Slm66018 "link reset\n", ldcp->id); 22142793Slm66018 mutex_enter(&ldcp->tx_lock); 22152793Slm66018 i_ldc_reset(ldcp, B_FALSE); 22162793Slm66018 mutex_exit(&ldcp->tx_lock); 22175944Sha137994 *notify_client = B_TRUE; 22185944Sha137994 *notify_event = LDC_EVT_RESET; 22192793Slm66018 break; 22202793Slm66018 } 22211991Sheppo } 22222793Slm66018 22232793Slm66018 #ifdef DEBUG 22242793Slm66018 if (LDC_INJECT_RESET(ldcp)) 22252793Slm66018 goto force_reset; 22266845Sha137994 if (LDC_INJECT_DRNGCLEAR(ldcp)) 22276845Sha137994 i_ldc_mem_inject_dring_clear(ldcp); 22282793Slm66018 #endif 22295944Sha137994 if (trace_length) { 22305944Sha137994 TRACE_RXHVQ_LENGTH(ldcp, rx_head, rx_tail); 22315944Sha137994 trace_length = B_FALSE; 22325944Sha137994 } 22331991Sheppo 22341991Sheppo if (rx_head == rx_tail) { 22355944Sha137994 D2(ldcp->id, "i_ldc_rx_process_hvq: (0x%llx) " 22365944Sha137994 "No packets\n", ldcp->id); 22371991Sheppo break; 22381991Sheppo } 22392793Slm66018 22405944Sha137994 D2(ldcp->id, "i_ldc_rx_process_hvq: head=0x%llx, " 22415944Sha137994 "tail=0x%llx\n", rx_head, rx_tail); 22425944Sha137994 DUMP_LDC_PKT(ldcp, "i_ldc_rx_process_hvq rcd", 22431991Sheppo ldcp->rx_q_va + rx_head); 22441991Sheppo 22451991Sheppo /* get the message */ 22461991Sheppo msg = (ldc_msg_t *)(ldcp->rx_q_va + rx_head); 22471991Sheppo 22481991Sheppo /* if channel is in RAW mode or data pkt, notify and return */ 22491991Sheppo if (ldcp->mode == LDC_MODE_RAW) { 22505944Sha137994 *notify_client = B_TRUE; 22515944Sha137994 *notify_event |= LDC_EVT_READ; 22521991Sheppo break; 22531991Sheppo } 22541991Sheppo 22551991Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) { 22561991Sheppo 22571991Sheppo /* discard packet if channel is not up */ 22582793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) != TS_UP) { 22591991Sheppo 22601991Sheppo /* move the head one position */ 22611991Sheppo rx_head = (rx_head + LDC_PACKET_SIZE) % 22624690Snarayan (ldcp->rx_q_entries << LDC_PACKET_SHIFT); 22631991Sheppo 22641991Sheppo if (rv = i_ldc_set_rx_head(ldcp, rx_head)) 22651991Sheppo break; 22661991Sheppo 22671991Sheppo continue; 22681991Sheppo } else { 22695944Sha137994 uint64_t dq_head, dq_tail; 22705944Sha137994 22716408Sha137994 /* process only RELIABLE mode data packets */ 22726408Sha137994 if (ldcp->mode != LDC_MODE_RELIABLE) { 22735944Sha137994 if ((ldcp->tstate & TS_IN_RESET) == 0) 22745944Sha137994 *notify_client = B_TRUE; 22755944Sha137994 *notify_event |= LDC_EVT_READ; 22765944Sha137994 break; 22775944Sha137994 } 22785944Sha137994 22795944Sha137994 /* don't process packet if queue full */ 22805944Sha137994 (void) i_ldc_dq_rx_get_state(ldcp, &dq_head, 22815944Sha137994 &dq_tail, NULL); 22825944Sha137994 dq_tail = (dq_tail + LDC_PACKET_SIZE) % 22835944Sha137994 (ldcp->rx_dq_entries << LDC_PACKET_SHIFT); 22845944Sha137994 if (dq_tail == dq_head || 22855944Sha137994 LDC_INJECT_DQFULL(ldcp)) { 22865944Sha137994 rv = ENOSPC; 22875944Sha137994 break; 22885944Sha137994 } 22891991Sheppo } 22901991Sheppo } 22911991Sheppo 22921991Sheppo /* Check the sequence ID for the message received */ 22932793Slm66018 rv = i_ldc_check_seqid(ldcp, msg); 22942793Slm66018 if (rv != 0) { 22951991Sheppo 22965944Sha137994 DWARN(ldcp->id, "i_ldc_rx_process_hvq: (0x%llx) " 22975944Sha137994 "seqid error, q_ptrs=0x%lx,0x%lx", ldcp->id, 22985944Sha137994 rx_head, rx_tail); 22991991Sheppo 23001991Sheppo /* Reset last_msg_rcd to start of message */ 23012336Snarayan if (first_fragment != 0) { 23022336Snarayan ldcp->last_msg_rcd = first_fragment - 1; 23032336Snarayan first_fragment = 0; 23041991Sheppo } 23052336Snarayan 23061991Sheppo /* 23071991Sheppo * Send a NACK due to seqid mismatch 23081991Sheppo */ 23094690Snarayan rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK, 23101991Sheppo (msg->ctrl & LDC_CTRL_MASK)); 23111991Sheppo 23121991Sheppo if (rv) { 23135944Sha137994 cmn_err(CE_NOTE, "i_ldc_rx_process_hvq: " 23145944Sha137994 "(0x%lx) err sending CTRL/DATA NACK msg\n", 23155944Sha137994 ldcp->id); 23162336Snarayan 23172336Snarayan /* if cannot send NACK - reset channel */ 23182336Snarayan mutex_enter(&ldcp->tx_lock); 23192793Slm66018 i_ldc_reset(ldcp, B_TRUE); 23202336Snarayan mutex_exit(&ldcp->tx_lock); 23213560Snarayan 23225944Sha137994 *notify_client = B_TRUE; 23235944Sha137994 *notify_event = LDC_EVT_RESET; 23242336Snarayan break; 23251991Sheppo } 23261991Sheppo 23271991Sheppo /* purge receive queue */ 23281991Sheppo (void) i_ldc_set_rx_head(ldcp, rx_tail); 23291991Sheppo break; 23301991Sheppo } 23311991Sheppo 23321991Sheppo /* record the message ID */ 23331991Sheppo ldcp->last_msg_rcd = msg->seqid; 23341991Sheppo 23351991Sheppo /* process control messages */ 23361991Sheppo if (msg->type & LDC_CTRL) { 23371991Sheppo /* save current internal state */ 23381991Sheppo uint64_t tstate = ldcp->tstate; 23391991Sheppo 23401991Sheppo rv = i_ldc_ctrlmsg(ldcp, msg); 23411991Sheppo if (rv == EAGAIN) { 23421991Sheppo /* re-process pkt - state was adjusted */ 23431991Sheppo continue; 23441991Sheppo } 23451991Sheppo if (rv == ECONNRESET) { 23465944Sha137994 *notify_client = B_TRUE; 23475944Sha137994 *notify_event = LDC_EVT_RESET; 23481991Sheppo break; 23491991Sheppo } 23501991Sheppo 23511991Sheppo /* 23521991Sheppo * control message processing was successful 23531991Sheppo * channel transitioned to ready for communication 23541991Sheppo */ 23551991Sheppo if (rv == 0 && ldcp->tstate == TS_UP && 23562793Slm66018 (tstate & ~TS_IN_RESET) != 23572793Slm66018 (ldcp->tstate & ~TS_IN_RESET)) { 23585944Sha137994 *notify_client = B_TRUE; 23595944Sha137994 *notify_event = LDC_EVT_UP; 23601991Sheppo } 23611991Sheppo } 23621991Sheppo 23633560Snarayan /* process data NACKs */ 23643560Snarayan if ((msg->type & LDC_DATA) && (msg->stype & LDC_NACK)) { 23653560Snarayan DWARN(ldcp->id, 23665944Sha137994 "i_ldc_rx_process_hvq: (0x%llx) received DATA/NACK", 23673560Snarayan ldcp->id); 23683560Snarayan mutex_enter(&ldcp->tx_lock); 23693560Snarayan i_ldc_reset(ldcp, B_TRUE); 23703560Snarayan mutex_exit(&ldcp->tx_lock); 23715944Sha137994 *notify_client = B_TRUE; 23725944Sha137994 *notify_event = LDC_EVT_RESET; 23733560Snarayan break; 23743560Snarayan } 23753560Snarayan 23761991Sheppo /* process data ACKs */ 23771991Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) { 23782336Snarayan if (rv = i_ldc_process_data_ACK(ldcp, msg)) { 23795944Sha137994 *notify_client = B_TRUE; 23805944Sha137994 *notify_event = LDC_EVT_RESET; 23812336Snarayan break; 23822336Snarayan } 23831991Sheppo } 23841991Sheppo 23855944Sha137994 if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) { 23866408Sha137994 ASSERT(ldcp->mode == LDC_MODE_RELIABLE); 23875944Sha137994 23885944Sha137994 /* 23895944Sha137994 * Copy the data packet to the data queue. Note 23905944Sha137994 * that the copy routine updates the rx_head pointer. 23915944Sha137994 */ 23925944Sha137994 i_ldc_rxdq_copy(ldcp, &rx_head); 23935944Sha137994 23945944Sha137994 if ((ldcp->tstate & TS_IN_RESET) == 0) 23955944Sha137994 *notify_client = B_TRUE; 23965944Sha137994 *notify_event |= LDC_EVT_READ; 23975944Sha137994 } else { 23985944Sha137994 rx_head = (rx_head + LDC_PACKET_SIZE) % 23995944Sha137994 (ldcp->rx_q_entries << LDC_PACKET_SHIFT); 24005944Sha137994 } 24015944Sha137994 24021991Sheppo /* move the head one position */ 24032032Slm66018 if (rv = i_ldc_set_rx_head(ldcp, rx_head)) { 24045944Sha137994 *notify_client = B_TRUE; 24055944Sha137994 *notify_event = LDC_EVT_RESET; 24061991Sheppo break; 24072032Slm66018 } 24081991Sheppo 24091991Sheppo } /* for */ 24101991Sheppo 24112793Slm66018 loop_exit: 24122793Slm66018 24136408Sha137994 if (ldcp->mode == LDC_MODE_RELIABLE) { 24145944Sha137994 /* ACK data packets */ 24155944Sha137994 if ((*notify_event & 24165944Sha137994 (LDC_EVT_READ | LDC_EVT_RESET)) == LDC_EVT_READ) { 24175944Sha137994 int ack_rv; 24185944Sha137994 ack_rv = i_ldc_send_pkt(ldcp, LDC_DATA, LDC_ACK, 0); 24195944Sha137994 if (ack_rv && ack_rv != EWOULDBLOCK) { 24205944Sha137994 cmn_err(CE_NOTE, 24215944Sha137994 "i_ldc_rx_process_hvq: (0x%lx) cannot " 24225944Sha137994 "send ACK\n", ldcp->id); 24235944Sha137994 24245944Sha137994 mutex_enter(&ldcp->tx_lock); 24255944Sha137994 i_ldc_reset(ldcp, B_FALSE); 24265944Sha137994 mutex_exit(&ldcp->tx_lock); 24275944Sha137994 24285944Sha137994 *notify_client = B_TRUE; 24295944Sha137994 *notify_event = LDC_EVT_RESET; 24305944Sha137994 goto skip_ackpeek; 24315944Sha137994 } 24325944Sha137994 } 24335944Sha137994 24345944Sha137994 /* 24355944Sha137994 * If we have no more space on the data queue, make sure 24365944Sha137994 * there are no ACKs on the rx queue waiting to be processed. 24375944Sha137994 */ 24385944Sha137994 if (rv == ENOSPC) { 24395944Sha137994 if (i_ldc_rx_ackpeek(ldcp, rx_head, rx_tail) != 0) { 24405944Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID; 24415944Sha137994 *notify_client = B_TRUE; 24425944Sha137994 *notify_event = LDC_EVT_RESET; 24435944Sha137994 } 24446944Sha137994 return (rv); 24455944Sha137994 } else { 24465944Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID; 24471991Sheppo } 24485944Sha137994 } 24495944Sha137994 24505944Sha137994 skip_ackpeek: 24515944Sha137994 24525944Sha137994 /* Return, indicating whether or not data packets were found */ 24535944Sha137994 if ((*notify_event & (LDC_EVT_READ | LDC_EVT_RESET)) == LDC_EVT_READ) 24545944Sha137994 return (0); 24555944Sha137994 24565944Sha137994 return (ENOMSG); 24571991Sheppo } 24581991Sheppo 24595944Sha137994 /* 24605944Sha137994 * Process any ACK packets on the HV receive queue. 24615944Sha137994 * 24626408Sha137994 * This function is only used by RELIABLE mode channels when the 24635944Sha137994 * secondary data queue fills up and there are packets remaining on 24645944Sha137994 * the HV receive queue. 24655944Sha137994 */ 24665944Sha137994 int 24675944Sha137994 i_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head, uint64_t rx_tail) 24685944Sha137994 { 24695944Sha137994 int rv = 0; 24705944Sha137994 ldc_msg_t *msg; 24715944Sha137994 24725944Sha137994 if (ldcp->rx_ack_head == ACKPEEK_HEAD_INVALID) 24735944Sha137994 ldcp->rx_ack_head = rx_head; 24745944Sha137994 24755944Sha137994 while (ldcp->rx_ack_head != rx_tail) { 24765944Sha137994 msg = (ldc_msg_t *)(ldcp->rx_q_va + ldcp->rx_ack_head); 24775944Sha137994 24785944Sha137994 if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) { 24795944Sha137994 if (rv = i_ldc_process_data_ACK(ldcp, msg)) 24805944Sha137994 break; 24815944Sha137994 msg->stype &= ~LDC_ACK; 24825944Sha137994 } 24835944Sha137994 24845944Sha137994 ldcp->rx_ack_head = 24855944Sha137994 (ldcp->rx_ack_head + LDC_PACKET_SIZE) % 24865944Sha137994 (ldcp->rx_q_entries << LDC_PACKET_SHIFT); 24875944Sha137994 } 24885944Sha137994 return (rv); 24895944Sha137994 } 24901991Sheppo 24911991Sheppo /* -------------------------------------------------------------------------- */ 24921991Sheppo 24931991Sheppo /* 24941991Sheppo * LDC API functions 24951991Sheppo */ 24961991Sheppo 24971991Sheppo /* 24981991Sheppo * Initialize the channel. Allocate internal structure and memory for 24991991Sheppo * TX/RX queues, and initialize locks. 25001991Sheppo */ 25011991Sheppo int 25021991Sheppo ldc_init(uint64_t id, ldc_attr_t *attr, ldc_handle_t *handle) 25031991Sheppo { 25041991Sheppo ldc_chan_t *ldcp; 25051991Sheppo int rv, exit_val; 25061991Sheppo uint64_t ra_base, nentries; 25072410Slm66018 uint64_t qlen; 25081991Sheppo 25091991Sheppo exit_val = EINVAL; /* guarantee an error if exit on failure */ 25101991Sheppo 25111991Sheppo if (attr == NULL) { 25121991Sheppo DWARN(id, "ldc_init: (0x%llx) invalid attr\n", id); 25131991Sheppo return (EINVAL); 25141991Sheppo } 25151991Sheppo if (handle == NULL) { 25161991Sheppo DWARN(id, "ldc_init: (0x%llx) invalid handle\n", id); 25171991Sheppo return (EINVAL); 25181991Sheppo } 25191991Sheppo 25201991Sheppo /* check if channel is valid */ 25211991Sheppo rv = hv_ldc_tx_qinfo(id, &ra_base, &nentries); 25221991Sheppo if (rv == H_ECHANNEL) { 25231991Sheppo DWARN(id, "ldc_init: (0x%llx) invalid channel id\n", id); 25241991Sheppo return (EINVAL); 25251991Sheppo } 25261991Sheppo 25271991Sheppo /* check if the channel has already been initialized */ 25281991Sheppo mutex_enter(&ldcssp->lock); 25291991Sheppo ldcp = ldcssp->chan_list; 25301991Sheppo while (ldcp != NULL) { 25311991Sheppo if (ldcp->id == id) { 25321991Sheppo DWARN(id, "ldc_init: (0x%llx) already initialized\n", 25331991Sheppo id); 25341991Sheppo mutex_exit(&ldcssp->lock); 25351991Sheppo return (EADDRINUSE); 25361991Sheppo } 25371991Sheppo ldcp = ldcp->next; 25381991Sheppo } 25391991Sheppo mutex_exit(&ldcssp->lock); 25401991Sheppo 25411991Sheppo ASSERT(ldcp == NULL); 25421991Sheppo 25431991Sheppo *handle = 0; 25441991Sheppo 25451991Sheppo /* Allocate an ldcp structure */ 25461991Sheppo ldcp = kmem_zalloc(sizeof (ldc_chan_t), KM_SLEEP); 25471991Sheppo 25482336Snarayan /* 25492336Snarayan * Initialize the channel and Tx lock 25502336Snarayan * 25512336Snarayan * The channel 'lock' protects the entire channel and 25522336Snarayan * should be acquired before initializing, resetting, 25532336Snarayan * destroying or reading from a channel. 25542336Snarayan * 25552336Snarayan * The 'tx_lock' should be acquired prior to transmitting 25562336Snarayan * data over the channel. The lock should also be acquired 25572336Snarayan * prior to channel reconfiguration (in order to prevent 25582336Snarayan * concurrent writes). 25592336Snarayan * 25602336Snarayan * ORDERING: When both locks are being acquired, to prevent 25612336Snarayan * deadlocks, the channel lock should be always acquired prior 25622336Snarayan * to the tx_lock. 25632336Snarayan */ 25641991Sheppo mutex_init(&ldcp->lock, NULL, MUTEX_DRIVER, NULL); 25652336Snarayan mutex_init(&ldcp->tx_lock, NULL, MUTEX_DRIVER, NULL); 25661991Sheppo 25671991Sheppo /* Initialize the channel */ 25681991Sheppo ldcp->id = id; 25691991Sheppo ldcp->cb = NULL; 25701991Sheppo ldcp->cb_arg = NULL; 25711991Sheppo ldcp->cb_inprogress = B_FALSE; 25721991Sheppo ldcp->cb_enabled = B_FALSE; 25731991Sheppo ldcp->next = NULL; 25741991Sheppo 25751991Sheppo /* Read attributes */ 25761991Sheppo ldcp->mode = attr->mode; 25771991Sheppo ldcp->devclass = attr->devclass; 25781991Sheppo ldcp->devinst = attr->instance; 25792410Slm66018 ldcp->mtu = (attr->mtu > 0) ? attr->mtu : LDC_DEFAULT_MTU; 25801991Sheppo 25811991Sheppo D1(ldcp->id, 25821991Sheppo "ldc_init: (0x%llx) channel attributes, class=0x%x, " 25832410Slm66018 "instance=0x%llx, mode=%d, mtu=%d\n", 25842410Slm66018 ldcp->id, ldcp->devclass, ldcp->devinst, ldcp->mode, ldcp->mtu); 25851991Sheppo 25861991Sheppo ldcp->next_vidx = 0; 25872793Slm66018 ldcp->tstate = TS_IN_RESET; 25881991Sheppo ldcp->hstate = 0; 25891991Sheppo ldcp->last_msg_snt = LDC_INIT_SEQID; 25901991Sheppo ldcp->last_ack_rcd = 0; 25911991Sheppo ldcp->last_msg_rcd = 0; 25925944Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID; 25931991Sheppo 25941991Sheppo ldcp->stream_bufferp = NULL; 25951991Sheppo ldcp->exp_dring_list = NULL; 25961991Sheppo ldcp->imp_dring_list = NULL; 25971991Sheppo ldcp->mhdl_list = NULL; 25981991Sheppo 25992793Slm66018 ldcp->tx_intr_state = LDC_INTR_NONE; 26002793Slm66018 ldcp->rx_intr_state = LDC_INTR_NONE; 26012793Slm66018 26021991Sheppo /* Initialize payload size depending on whether channel is reliable */ 26031991Sheppo switch (ldcp->mode) { 26041991Sheppo case LDC_MODE_RAW: 26051991Sheppo ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RAW; 26061991Sheppo ldcp->read_p = i_ldc_read_raw; 26071991Sheppo ldcp->write_p = i_ldc_write_raw; 26081991Sheppo break; 26091991Sheppo case LDC_MODE_UNRELIABLE: 26101991Sheppo ldcp->pkt_payload = LDC_PAYLOAD_SIZE_UNRELIABLE; 26111991Sheppo ldcp->read_p = i_ldc_read_packet; 26121991Sheppo ldcp->write_p = i_ldc_write_packet; 26131991Sheppo break; 26141991Sheppo case LDC_MODE_RELIABLE: 26151991Sheppo ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RELIABLE; 26161991Sheppo 26171991Sheppo ldcp->stream_remains = 0; 26181991Sheppo ldcp->stream_offset = 0; 26191991Sheppo ldcp->stream_bufferp = kmem_alloc(ldcp->mtu, KM_SLEEP); 26201991Sheppo ldcp->read_p = i_ldc_read_stream; 26211991Sheppo ldcp->write_p = i_ldc_write_stream; 26221991Sheppo break; 26231991Sheppo default: 26241991Sheppo exit_val = EINVAL; 26251991Sheppo goto cleanup_on_exit; 26261991Sheppo } 26271991Sheppo 26282410Slm66018 /* 26292410Slm66018 * qlen is (mtu * ldc_mtu_msgs) / pkt_payload. If this 26302410Slm66018 * value is smaller than default length of ldc_queue_entries, 26314690Snarayan * qlen is set to ldc_queue_entries. Ensure that computed 26324690Snarayan * length is a power-of-two value. 26332410Slm66018 */ 26342410Slm66018 qlen = (ldcp->mtu * ldc_mtu_msgs) / ldcp->pkt_payload; 26354690Snarayan if (!ISP2(qlen)) { 26364690Snarayan uint64_t tmp = 1; 26374690Snarayan while (qlen) { 26384690Snarayan qlen >>= 1; tmp <<= 1; 26394690Snarayan } 26404690Snarayan qlen = tmp; 26414690Snarayan } 26424690Snarayan 26432410Slm66018 ldcp->rx_q_entries = 26444690Snarayan (qlen < ldc_queue_entries) ? ldc_queue_entries : qlen; 26452410Slm66018 ldcp->tx_q_entries = ldcp->rx_q_entries; 26462410Slm66018 26474690Snarayan D1(ldcp->id, "ldc_init: queue length = 0x%llx\n", ldcp->rx_q_entries); 26482410Slm66018 26491991Sheppo /* Create a transmit queue */ 26501991Sheppo ldcp->tx_q_va = (uint64_t) 26514690Snarayan contig_mem_alloc(ldcp->tx_q_entries << LDC_PACKET_SHIFT); 26521991Sheppo if (ldcp->tx_q_va == NULL) { 26531991Sheppo cmn_err(CE_WARN, 26541991Sheppo "ldc_init: (0x%lx) TX queue allocation failed\n", 26551991Sheppo ldcp->id); 26561991Sheppo exit_val = ENOMEM; 26571991Sheppo goto cleanup_on_exit; 26581991Sheppo } 26591991Sheppo ldcp->tx_q_ra = va_to_pa((caddr_t)ldcp->tx_q_va); 26601991Sheppo 26611991Sheppo D2(ldcp->id, "ldc_init: txq_va=0x%llx, txq_ra=0x%llx, entries=0x%llx\n", 26621991Sheppo ldcp->tx_q_va, ldcp->tx_q_ra, ldcp->tx_q_entries); 26631991Sheppo 26641991Sheppo ldcp->tstate |= TS_TXQ_RDY; 26651991Sheppo 26661991Sheppo /* Create a receive queue */ 26671991Sheppo ldcp->rx_q_va = (uint64_t) 26684690Snarayan contig_mem_alloc(ldcp->rx_q_entries << LDC_PACKET_SHIFT); 26691991Sheppo if (ldcp->rx_q_va == NULL) { 26701991Sheppo cmn_err(CE_WARN, 26711991Sheppo "ldc_init: (0x%lx) RX queue allocation failed\n", 26721991Sheppo ldcp->id); 26731991Sheppo exit_val = ENOMEM; 26741991Sheppo goto cleanup_on_exit; 26751991Sheppo } 26761991Sheppo ldcp->rx_q_ra = va_to_pa((caddr_t)ldcp->rx_q_va); 26771991Sheppo 26781991Sheppo D2(ldcp->id, "ldc_init: rxq_va=0x%llx, rxq_ra=0x%llx, entries=0x%llx\n", 26791991Sheppo ldcp->rx_q_va, ldcp->rx_q_ra, ldcp->rx_q_entries); 26801991Sheppo 26811991Sheppo ldcp->tstate |= TS_RXQ_RDY; 26821991Sheppo 26835944Sha137994 /* Setup a separate read data queue */ 26846408Sha137994 if (ldcp->mode == LDC_MODE_RELIABLE) { 26855944Sha137994 ldcp->readq_get_state = i_ldc_dq_rx_get_state; 26865944Sha137994 ldcp->readq_set_head = i_ldc_set_rxdq_head; 26875944Sha137994 26885944Sha137994 /* Make sure the data queue multiplier is a power of 2 */ 26895944Sha137994 if (!ISP2(ldc_rxdq_multiplier)) { 26905944Sha137994 D1(ldcp->id, "ldc_init: (0x%llx) ldc_rxdq_multiplier " 26915944Sha137994 "not a power of 2, resetting", ldcp->id); 26925944Sha137994 ldc_rxdq_multiplier = LDC_RXDQ_MULTIPLIER; 26935944Sha137994 } 26945944Sha137994 26955944Sha137994 ldcp->rx_dq_entries = ldc_rxdq_multiplier * ldcp->rx_q_entries; 26965944Sha137994 ldcp->rx_dq_va = (uint64_t) 26975944Sha137994 kmem_alloc(ldcp->rx_dq_entries << LDC_PACKET_SHIFT, 26985944Sha137994 KM_SLEEP); 26995944Sha137994 if (ldcp->rx_dq_va == NULL) { 27005944Sha137994 cmn_err(CE_WARN, 27015944Sha137994 "ldc_init: (0x%lx) RX data queue " 27025944Sha137994 "allocation failed\n", ldcp->id); 27035944Sha137994 exit_val = ENOMEM; 27045944Sha137994 goto cleanup_on_exit; 27055944Sha137994 } 27065944Sha137994 27075944Sha137994 ldcp->rx_dq_head = ldcp->rx_dq_tail = 0; 27085944Sha137994 27095944Sha137994 D2(ldcp->id, "ldc_init: rx_dq_va=0x%llx, " 27105944Sha137994 "rx_dq_entries=0x%llx\n", ldcp->rx_dq_va, 27115944Sha137994 ldcp->rx_dq_entries); 27125944Sha137994 } else { 27135944Sha137994 ldcp->readq_get_state = i_ldc_hvq_rx_get_state; 27145944Sha137994 ldcp->readq_set_head = i_ldc_set_rx_head; 27155944Sha137994 } 27165944Sha137994 27171991Sheppo /* Init descriptor ring and memory handle list lock */ 27181991Sheppo mutex_init(&ldcp->exp_dlist_lock, NULL, MUTEX_DRIVER, NULL); 27191991Sheppo mutex_init(&ldcp->imp_dlist_lock, NULL, MUTEX_DRIVER, NULL); 27201991Sheppo mutex_init(&ldcp->mlist_lock, NULL, MUTEX_DRIVER, NULL); 27211991Sheppo 27221991Sheppo /* mark status as INITialized */ 27231991Sheppo ldcp->status = LDC_INIT; 27241991Sheppo 27251991Sheppo /* Add to channel list */ 27261991Sheppo mutex_enter(&ldcssp->lock); 27271991Sheppo ldcp->next = ldcssp->chan_list; 27281991Sheppo ldcssp->chan_list = ldcp; 27291991Sheppo ldcssp->channel_count++; 27301991Sheppo mutex_exit(&ldcssp->lock); 27311991Sheppo 27321991Sheppo /* set the handle */ 27331991Sheppo *handle = (ldc_handle_t)ldcp; 27341991Sheppo 27351991Sheppo D1(ldcp->id, "ldc_init: (0x%llx) channel initialized\n", ldcp->id); 27361991Sheppo 27371991Sheppo return (0); 27381991Sheppo 27391991Sheppo cleanup_on_exit: 27401991Sheppo 27416408Sha137994 if (ldcp->mode == LDC_MODE_RELIABLE && ldcp->stream_bufferp) 27421991Sheppo kmem_free(ldcp->stream_bufferp, ldcp->mtu); 27431991Sheppo 27441991Sheppo if (ldcp->tstate & TS_TXQ_RDY) 27451991Sheppo contig_mem_free((caddr_t)ldcp->tx_q_va, 27461991Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT)); 27471991Sheppo 27481991Sheppo if (ldcp->tstate & TS_RXQ_RDY) 27491991Sheppo contig_mem_free((caddr_t)ldcp->rx_q_va, 27501991Sheppo (ldcp->rx_q_entries << LDC_PACKET_SHIFT)); 27511991Sheppo 27522336Snarayan mutex_destroy(&ldcp->tx_lock); 27531991Sheppo mutex_destroy(&ldcp->lock); 27541991Sheppo 27551991Sheppo if (ldcp) 27561991Sheppo kmem_free(ldcp, sizeof (ldc_chan_t)); 27571991Sheppo 27581991Sheppo return (exit_val); 27591991Sheppo } 27601991Sheppo 27611991Sheppo /* 27621991Sheppo * Finalizes the LDC connection. It will return EBUSY if the 27631991Sheppo * channel is open. A ldc_close() has to be done prior to 27641991Sheppo * a ldc_fini operation. It frees TX/RX queues, associated 27651991Sheppo * with the channel 27661991Sheppo */ 27671991Sheppo int 27681991Sheppo ldc_fini(ldc_handle_t handle) 27691991Sheppo { 27701991Sheppo ldc_chan_t *ldcp; 27711991Sheppo ldc_chan_t *tmp_ldcp; 27721991Sheppo uint64_t id; 27731991Sheppo 27741991Sheppo if (handle == NULL) { 27751991Sheppo DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel handle\n"); 27761991Sheppo return (EINVAL); 27771991Sheppo } 27781991Sheppo ldcp = (ldc_chan_t *)handle; 27791991Sheppo id = ldcp->id; 27801991Sheppo 27811991Sheppo mutex_enter(&ldcp->lock); 27821991Sheppo 27832793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) > TS_INIT) { 27841991Sheppo DWARN(ldcp->id, "ldc_fini: (0x%llx) channel is open\n", 27851991Sheppo ldcp->id); 27861991Sheppo mutex_exit(&ldcp->lock); 27871991Sheppo return (EBUSY); 27881991Sheppo } 27891991Sheppo 27901991Sheppo /* Remove from the channel list */ 27911991Sheppo mutex_enter(&ldcssp->lock); 27921991Sheppo tmp_ldcp = ldcssp->chan_list; 27931991Sheppo if (tmp_ldcp == ldcp) { 27941991Sheppo ldcssp->chan_list = ldcp->next; 27951991Sheppo ldcp->next = NULL; 27961991Sheppo } else { 27971991Sheppo while (tmp_ldcp != NULL) { 27981991Sheppo if (tmp_ldcp->next == ldcp) { 27991991Sheppo tmp_ldcp->next = ldcp->next; 28001991Sheppo ldcp->next = NULL; 28011991Sheppo break; 28021991Sheppo } 28031991Sheppo tmp_ldcp = tmp_ldcp->next; 28041991Sheppo } 28051991Sheppo if (tmp_ldcp == NULL) { 28061991Sheppo DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel hdl\n"); 28071991Sheppo mutex_exit(&ldcssp->lock); 28081991Sheppo mutex_exit(&ldcp->lock); 28091991Sheppo return (EINVAL); 28101991Sheppo } 28111991Sheppo } 28121991Sheppo 28131991Sheppo ldcssp->channel_count--; 28141991Sheppo 28151991Sheppo mutex_exit(&ldcssp->lock); 28161991Sheppo 28171991Sheppo /* Free the map table for this channel */ 28181991Sheppo if (ldcp->mtbl) { 28191991Sheppo (void) hv_ldc_set_map_table(ldcp->id, NULL, NULL); 28202793Slm66018 if (ldcp->mtbl->contigmem) 28212793Slm66018 contig_mem_free(ldcp->mtbl->table, ldcp->mtbl->size); 28222793Slm66018 else 28232793Slm66018 kmem_free(ldcp->mtbl->table, ldcp->mtbl->size); 28241991Sheppo mutex_destroy(&ldcp->mtbl->lock); 28251991Sheppo kmem_free(ldcp->mtbl, sizeof (ldc_mtbl_t)); 28261991Sheppo } 28271991Sheppo 28281991Sheppo /* Destroy descriptor ring and memory handle list lock */ 28291991Sheppo mutex_destroy(&ldcp->exp_dlist_lock); 28301991Sheppo mutex_destroy(&ldcp->imp_dlist_lock); 28311991Sheppo mutex_destroy(&ldcp->mlist_lock); 28321991Sheppo 28336408Sha137994 /* Free the stream buffer for RELIABLE_MODE */ 28346408Sha137994 if (ldcp->mode == LDC_MODE_RELIABLE && ldcp->stream_bufferp) 28351991Sheppo kmem_free(ldcp->stream_bufferp, ldcp->mtu); 28361991Sheppo 28371991Sheppo /* Free the RX queue */ 28381991Sheppo contig_mem_free((caddr_t)ldcp->rx_q_va, 28391991Sheppo (ldcp->rx_q_entries << LDC_PACKET_SHIFT)); 28401991Sheppo ldcp->tstate &= ~TS_RXQ_RDY; 28411991Sheppo 28425944Sha137994 /* Free the RX data queue */ 28436408Sha137994 if (ldcp->mode == LDC_MODE_RELIABLE) { 28445944Sha137994 kmem_free((caddr_t)ldcp->rx_dq_va, 28455944Sha137994 (ldcp->rx_dq_entries << LDC_PACKET_SHIFT)); 28465944Sha137994 } 28475944Sha137994 28481991Sheppo /* Free the TX queue */ 28491991Sheppo contig_mem_free((caddr_t)ldcp->tx_q_va, 28501991Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT)); 28511991Sheppo ldcp->tstate &= ~TS_TXQ_RDY; 28521991Sheppo 28531991Sheppo mutex_exit(&ldcp->lock); 28541991Sheppo 28551991Sheppo /* Destroy mutex */ 28562336Snarayan mutex_destroy(&ldcp->tx_lock); 28571991Sheppo mutex_destroy(&ldcp->lock); 28581991Sheppo 28591991Sheppo /* free channel structure */ 28601991Sheppo kmem_free(ldcp, sizeof (ldc_chan_t)); 28611991Sheppo 28621991Sheppo D1(id, "ldc_fini: (0x%llx) channel finalized\n", id); 28631991Sheppo 28641991Sheppo return (0); 28651991Sheppo } 28661991Sheppo 28671991Sheppo /* 28681991Sheppo * Open the LDC channel for use. It registers the TX/RX queues 28691991Sheppo * with the Hypervisor. It also specifies the interrupt number 28701991Sheppo * and target CPU for this channel 28711991Sheppo */ 28721991Sheppo int 28731991Sheppo ldc_open(ldc_handle_t handle) 28741991Sheppo { 28751991Sheppo ldc_chan_t *ldcp; 28761991Sheppo int rv; 28771991Sheppo 28781991Sheppo if (handle == NULL) { 28791991Sheppo DWARN(DBG_ALL_LDCS, "ldc_open: invalid channel handle\n"); 28801991Sheppo return (EINVAL); 28811991Sheppo } 28821991Sheppo 28831991Sheppo ldcp = (ldc_chan_t *)handle; 28841991Sheppo 28851991Sheppo mutex_enter(&ldcp->lock); 28861991Sheppo 28871991Sheppo if (ldcp->tstate < TS_INIT) { 28881991Sheppo DWARN(ldcp->id, 28891991Sheppo "ldc_open: (0x%llx) channel not initialized\n", ldcp->id); 28901991Sheppo mutex_exit(&ldcp->lock); 28911991Sheppo return (EFAULT); 28921991Sheppo } 28932793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) >= TS_OPEN) { 28941991Sheppo DWARN(ldcp->id, 28951991Sheppo "ldc_open: (0x%llx) channel is already open\n", ldcp->id); 28961991Sheppo mutex_exit(&ldcp->lock); 28971991Sheppo return (EFAULT); 28981991Sheppo } 28991991Sheppo 29001991Sheppo /* 29011991Sheppo * Unregister/Register the tx queue with the hypervisor 29021991Sheppo */ 29031991Sheppo rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 29041991Sheppo if (rv) { 29051991Sheppo cmn_err(CE_WARN, 29061991Sheppo "ldc_open: (0x%lx) channel tx queue unconf failed\n", 29071991Sheppo ldcp->id); 29081991Sheppo mutex_exit(&ldcp->lock); 29091991Sheppo return (EIO); 29101991Sheppo } 29111991Sheppo 29121991Sheppo rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries); 29131991Sheppo if (rv) { 29141991Sheppo cmn_err(CE_WARN, 29151991Sheppo "ldc_open: (0x%lx) channel tx queue conf failed\n", 29161991Sheppo ldcp->id); 29171991Sheppo mutex_exit(&ldcp->lock); 29181991Sheppo return (EIO); 29191991Sheppo } 29201991Sheppo 29211991Sheppo D2(ldcp->id, "ldc_open: (0x%llx) registered tx queue with LDC\n", 29221991Sheppo ldcp->id); 29231991Sheppo 29241991Sheppo /* 29251991Sheppo * Unregister/Register the rx queue with the hypervisor 29261991Sheppo */ 29271991Sheppo rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 29281991Sheppo if (rv) { 29291991Sheppo cmn_err(CE_WARN, 29301991Sheppo "ldc_open: (0x%lx) channel rx queue unconf failed\n", 29311991Sheppo ldcp->id); 29321991Sheppo mutex_exit(&ldcp->lock); 29331991Sheppo return (EIO); 29341991Sheppo } 29351991Sheppo 29361991Sheppo rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra, ldcp->rx_q_entries); 29371991Sheppo if (rv) { 29381991Sheppo cmn_err(CE_WARN, 29391991Sheppo "ldc_open: (0x%lx) channel rx queue conf failed\n", 29401991Sheppo ldcp->id); 29411991Sheppo mutex_exit(&ldcp->lock); 29421991Sheppo return (EIO); 29431991Sheppo } 29441991Sheppo 29451991Sheppo D2(ldcp->id, "ldc_open: (0x%llx) registered rx queue with LDC\n", 29461991Sheppo ldcp->id); 29471991Sheppo 29481991Sheppo ldcp->tstate |= TS_QCONF_RDY; 29491991Sheppo 29501991Sheppo /* Register the channel with the channel nexus */ 29511991Sheppo rv = i_ldc_register_channel(ldcp); 29521991Sheppo if (rv && rv != EAGAIN) { 29531991Sheppo cmn_err(CE_WARN, 29541991Sheppo "ldc_open: (0x%lx) channel register failed\n", ldcp->id); 29551991Sheppo (void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 29561991Sheppo (void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 29571991Sheppo mutex_exit(&ldcp->lock); 29581991Sheppo return (EIO); 29591991Sheppo } 29601991Sheppo 29611991Sheppo /* mark channel in OPEN state */ 29621991Sheppo ldcp->status = LDC_OPEN; 29631991Sheppo 29641991Sheppo /* Read channel state */ 29651991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 29661991Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 29671991Sheppo if (rv) { 29681991Sheppo cmn_err(CE_WARN, 29691991Sheppo "ldc_open: (0x%lx) cannot read channel state\n", 29701991Sheppo ldcp->id); 29711991Sheppo (void) i_ldc_unregister_channel(ldcp); 29721991Sheppo (void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 29731991Sheppo (void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 29741991Sheppo mutex_exit(&ldcp->lock); 29751991Sheppo return (EIO); 29761991Sheppo } 29771991Sheppo 29781991Sheppo /* 29796408Sha137994 * set the ACKd head to current head location for reliable 29801991Sheppo */ 29811991Sheppo ldcp->tx_ackd_head = ldcp->tx_head; 29821991Sheppo 29831991Sheppo /* mark channel ready if HV report link is UP (peer alloc'd Rx queue) */ 29841991Sheppo if (ldcp->link_state == LDC_CHANNEL_UP || 29851991Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 29861991Sheppo ldcp->tstate |= TS_LINK_READY; 29871991Sheppo ldcp->status = LDC_READY; 29881991Sheppo } 29891991Sheppo 29901991Sheppo /* 29911991Sheppo * if channel is being opened in RAW mode - no handshake is needed 29921991Sheppo * switch the channel READY and UP state 29931991Sheppo */ 29941991Sheppo if (ldcp->mode == LDC_MODE_RAW) { 29951991Sheppo ldcp->tstate = TS_UP; /* set bits associated with LDC UP */ 29961991Sheppo ldcp->status = LDC_UP; 29971991Sheppo } 29981991Sheppo 29991991Sheppo mutex_exit(&ldcp->lock); 30001991Sheppo 30011991Sheppo /* 30021991Sheppo * Increment number of open channels 30031991Sheppo */ 30041991Sheppo mutex_enter(&ldcssp->lock); 30051991Sheppo ldcssp->channels_open++; 30061991Sheppo mutex_exit(&ldcssp->lock); 30071991Sheppo 30083010Slm66018 D1(ldcp->id, 30092793Slm66018 "ldc_open: (0x%llx) channel (0x%p) open for use " 30102793Slm66018 "(tstate=0x%x, status=0x%x)\n", 30112793Slm66018 ldcp->id, ldcp, ldcp->tstate, ldcp->status); 30121991Sheppo 30131991Sheppo return (0); 30141991Sheppo } 30151991Sheppo 30161991Sheppo /* 30171991Sheppo * Close the LDC connection. It will return EBUSY if there 30181991Sheppo * are memory segments or descriptor rings either bound to or 30191991Sheppo * mapped over the channel 30201991Sheppo */ 30211991Sheppo int 30221991Sheppo ldc_close(ldc_handle_t handle) 30231991Sheppo { 30241991Sheppo ldc_chan_t *ldcp; 30252336Snarayan int rv = 0, retries = 0; 30261991Sheppo boolean_t chk_done = B_FALSE; 30271991Sheppo 30281991Sheppo if (handle == NULL) { 30291991Sheppo DWARN(DBG_ALL_LDCS, "ldc_close: invalid channel handle\n"); 30301991Sheppo return (EINVAL); 30311991Sheppo } 30321991Sheppo ldcp = (ldc_chan_t *)handle; 30331991Sheppo 30341991Sheppo mutex_enter(&ldcp->lock); 30351991Sheppo 30361991Sheppo /* return error if channel is not open */ 30372793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) < TS_OPEN) { 30381991Sheppo DWARN(ldcp->id, 30391991Sheppo "ldc_close: (0x%llx) channel is not open\n", ldcp->id); 30401991Sheppo mutex_exit(&ldcp->lock); 30411991Sheppo return (EFAULT); 30421991Sheppo } 30431991Sheppo 30441991Sheppo /* if any memory handles, drings, are bound or mapped cannot close */ 30451991Sheppo if (ldcp->mhdl_list != NULL) { 30461991Sheppo DWARN(ldcp->id, 30471991Sheppo "ldc_close: (0x%llx) channel has bound memory handles\n", 30481991Sheppo ldcp->id); 30491991Sheppo mutex_exit(&ldcp->lock); 30501991Sheppo return (EBUSY); 30511991Sheppo } 30521991Sheppo if (ldcp->exp_dring_list != NULL) { 30531991Sheppo DWARN(ldcp->id, 30541991Sheppo "ldc_close: (0x%llx) channel has bound descriptor rings\n", 30551991Sheppo ldcp->id); 30561991Sheppo mutex_exit(&ldcp->lock); 30571991Sheppo return (EBUSY); 30581991Sheppo } 30591991Sheppo if (ldcp->imp_dring_list != NULL) { 30601991Sheppo DWARN(ldcp->id, 30611991Sheppo "ldc_close: (0x%llx) channel has mapped descriptor rings\n", 30621991Sheppo ldcp->id); 30631991Sheppo mutex_exit(&ldcp->lock); 30641991Sheppo return (EBUSY); 30651991Sheppo } 30661991Sheppo 30673151Ssg70180 if (ldcp->cb_inprogress) { 30683151Ssg70180 DWARN(ldcp->id, "ldc_close: (0x%llx) callback active\n", 30693151Ssg70180 ldcp->id); 30703151Ssg70180 mutex_exit(&ldcp->lock); 30713151Ssg70180 return (EWOULDBLOCK); 30723151Ssg70180 } 30733151Ssg70180 30742336Snarayan /* Obtain Tx lock */ 30752336Snarayan mutex_enter(&ldcp->tx_lock); 30762336Snarayan 30771991Sheppo /* 30781991Sheppo * Wait for pending transmits to complete i.e Tx queue to drain 30791991Sheppo * if there are pending pkts - wait 1 ms and retry again 30801991Sheppo */ 30811991Sheppo for (;;) { 30821991Sheppo 30831991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 30841991Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 30851991Sheppo if (rv) { 30861991Sheppo cmn_err(CE_WARN, 30871991Sheppo "ldc_close: (0x%lx) cannot read qptrs\n", ldcp->id); 30882336Snarayan mutex_exit(&ldcp->tx_lock); 30891991Sheppo mutex_exit(&ldcp->lock); 30901991Sheppo return (EIO); 30911991Sheppo } 30921991Sheppo 30931991Sheppo if (ldcp->tx_head == ldcp->tx_tail || 30941991Sheppo ldcp->link_state != LDC_CHANNEL_UP) { 30951991Sheppo break; 30961991Sheppo } 30971991Sheppo 30981991Sheppo if (chk_done) { 30991991Sheppo DWARN(ldcp->id, 31001991Sheppo "ldc_close: (0x%llx) Tx queue drain timeout\n", 31011991Sheppo ldcp->id); 31021991Sheppo break; 31031991Sheppo } 31041991Sheppo 31051991Sheppo /* wait for one ms and try again */ 31061991Sheppo delay(drv_usectohz(1000)); 31071991Sheppo chk_done = B_TRUE; 31081991Sheppo } 31091991Sheppo 31101991Sheppo /* 31112841Snarayan * Drain the Tx and Rx queues as we are closing the 31122841Snarayan * channel. We dont care about any pending packets. 31132841Snarayan * We have to also drain the queue prior to clearing 31142841Snarayan * pending interrupts, otherwise the HV will trigger 31152841Snarayan * an interrupt the moment the interrupt state is 31162841Snarayan * cleared. 31172793Slm66018 */ 31182793Slm66018 (void) i_ldc_txq_reconf(ldcp); 31192841Snarayan (void) i_ldc_rxq_drain(ldcp); 31202793Slm66018 31212793Slm66018 /* 31221991Sheppo * Unregister the channel with the nexus 31231991Sheppo */ 31242336Snarayan while ((rv = i_ldc_unregister_channel(ldcp)) != 0) { 31252336Snarayan 31262336Snarayan mutex_exit(&ldcp->tx_lock); 31271991Sheppo mutex_exit(&ldcp->lock); 31282336Snarayan 31292336Snarayan /* if any error other than EAGAIN return back */ 31302841Snarayan if (rv != EAGAIN || retries >= ldc_max_retries) { 31312336Snarayan cmn_err(CE_WARN, 31322336Snarayan "ldc_close: (0x%lx) unregister failed, %d\n", 31332336Snarayan ldcp->id, rv); 31342336Snarayan return (rv); 31352336Snarayan } 31362336Snarayan 31372336Snarayan /* 31382336Snarayan * As there could be pending interrupts we need 31392336Snarayan * to wait and try again 31402336Snarayan */ 31413151Ssg70180 drv_usecwait(ldc_close_delay); 31422336Snarayan mutex_enter(&ldcp->lock); 31432336Snarayan mutex_enter(&ldcp->tx_lock); 31442336Snarayan retries++; 31451991Sheppo } 31461991Sheppo 31471991Sheppo /* 31481991Sheppo * Unregister queues 31491991Sheppo */ 31501991Sheppo rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 31511991Sheppo if (rv) { 31521991Sheppo cmn_err(CE_WARN, 31531991Sheppo "ldc_close: (0x%lx) channel TX queue unconf failed\n", 31541991Sheppo ldcp->id); 31552336Snarayan mutex_exit(&ldcp->tx_lock); 31561991Sheppo mutex_exit(&ldcp->lock); 31571991Sheppo return (EIO); 31581991Sheppo } 31591991Sheppo rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 31601991Sheppo if (rv) { 31611991Sheppo cmn_err(CE_WARN, 31621991Sheppo "ldc_close: (0x%lx) channel RX queue unconf failed\n", 31631991Sheppo ldcp->id); 31642336Snarayan mutex_exit(&ldcp->tx_lock); 31651991Sheppo mutex_exit(&ldcp->lock); 31661991Sheppo return (EIO); 31671991Sheppo } 31681991Sheppo 31691991Sheppo ldcp->tstate &= ~TS_QCONF_RDY; 31701991Sheppo 31711991Sheppo /* Reset channel state information */ 31721991Sheppo i_ldc_reset_state(ldcp); 31731991Sheppo 31741991Sheppo /* Mark channel as down and in initialized state */ 31751991Sheppo ldcp->tx_ackd_head = 0; 31761991Sheppo ldcp->tx_head = 0; 31772793Slm66018 ldcp->tstate = TS_IN_RESET|TS_INIT; 31781991Sheppo ldcp->status = LDC_INIT; 31791991Sheppo 31802336Snarayan mutex_exit(&ldcp->tx_lock); 31811991Sheppo mutex_exit(&ldcp->lock); 31821991Sheppo 31831991Sheppo /* Decrement number of open channels */ 31841991Sheppo mutex_enter(&ldcssp->lock); 31851991Sheppo ldcssp->channels_open--; 31861991Sheppo mutex_exit(&ldcssp->lock); 31871991Sheppo 31881991Sheppo D1(ldcp->id, "ldc_close: (0x%llx) channel closed\n", ldcp->id); 31891991Sheppo 31901991Sheppo return (0); 31911991Sheppo } 31921991Sheppo 31931991Sheppo /* 31941991Sheppo * Register channel callback 31951991Sheppo */ 31961991Sheppo int 31971991Sheppo ldc_reg_callback(ldc_handle_t handle, 31981991Sheppo uint_t(*cb)(uint64_t event, caddr_t arg), caddr_t arg) 31991991Sheppo { 32001991Sheppo ldc_chan_t *ldcp; 32011991Sheppo 32021991Sheppo if (handle == NULL) { 32031991Sheppo DWARN(DBG_ALL_LDCS, 32041991Sheppo "ldc_reg_callback: invalid channel handle\n"); 32051991Sheppo return (EINVAL); 32061991Sheppo } 32071991Sheppo if (((uint64_t)cb) < KERNELBASE) { 32081991Sheppo DWARN(DBG_ALL_LDCS, "ldc_reg_callback: invalid callback\n"); 32091991Sheppo return (EINVAL); 32101991Sheppo } 32111991Sheppo ldcp = (ldc_chan_t *)handle; 32121991Sheppo 32131991Sheppo mutex_enter(&ldcp->lock); 32141991Sheppo 32151991Sheppo if (ldcp->cb) { 32161991Sheppo DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback exists\n", 32171991Sheppo ldcp->id); 32181991Sheppo mutex_exit(&ldcp->lock); 32191991Sheppo return (EIO); 32201991Sheppo } 32211991Sheppo if (ldcp->cb_inprogress) { 32221991Sheppo DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback active\n", 32231991Sheppo ldcp->id); 32241991Sheppo mutex_exit(&ldcp->lock); 32251991Sheppo return (EWOULDBLOCK); 32261991Sheppo } 32271991Sheppo 32281991Sheppo ldcp->cb = cb; 32291991Sheppo ldcp->cb_arg = arg; 32301991Sheppo ldcp->cb_enabled = B_TRUE; 32311991Sheppo 32321991Sheppo D1(ldcp->id, 32331991Sheppo "ldc_reg_callback: (0x%llx) registered callback for channel\n", 32341991Sheppo ldcp->id); 32351991Sheppo 32361991Sheppo mutex_exit(&ldcp->lock); 32371991Sheppo 32381991Sheppo return (0); 32391991Sheppo } 32401991Sheppo 32411991Sheppo /* 32421991Sheppo * Unregister channel callback 32431991Sheppo */ 32441991Sheppo int 32451991Sheppo ldc_unreg_callback(ldc_handle_t handle) 32461991Sheppo { 32471991Sheppo ldc_chan_t *ldcp; 32481991Sheppo 32491991Sheppo if (handle == NULL) { 32501991Sheppo DWARN(DBG_ALL_LDCS, 32511991Sheppo "ldc_unreg_callback: invalid channel handle\n"); 32521991Sheppo return (EINVAL); 32531991Sheppo } 32541991Sheppo ldcp = (ldc_chan_t *)handle; 32551991Sheppo 32561991Sheppo mutex_enter(&ldcp->lock); 32571991Sheppo 32581991Sheppo if (ldcp->cb == NULL) { 32591991Sheppo DWARN(ldcp->id, 32601991Sheppo "ldc_unreg_callback: (0x%llx) no callback exists\n", 32611991Sheppo ldcp->id); 32621991Sheppo mutex_exit(&ldcp->lock); 32631991Sheppo return (EIO); 32641991Sheppo } 32651991Sheppo if (ldcp->cb_inprogress) { 32661991Sheppo DWARN(ldcp->id, 32671991Sheppo "ldc_unreg_callback: (0x%llx) callback active\n", 32681991Sheppo ldcp->id); 32691991Sheppo mutex_exit(&ldcp->lock); 32701991Sheppo return (EWOULDBLOCK); 32711991Sheppo } 32721991Sheppo 32731991Sheppo ldcp->cb = NULL; 32741991Sheppo ldcp->cb_arg = NULL; 32751991Sheppo ldcp->cb_enabled = B_FALSE; 32761991Sheppo 32771991Sheppo D1(ldcp->id, 32781991Sheppo "ldc_unreg_callback: (0x%llx) unregistered callback for channel\n", 32791991Sheppo ldcp->id); 32801991Sheppo 32811991Sheppo mutex_exit(&ldcp->lock); 32821991Sheppo 32831991Sheppo return (0); 32841991Sheppo } 32851991Sheppo 32861991Sheppo 32871991Sheppo /* 32881991Sheppo * Bring a channel up by initiating a handshake with the peer 32891991Sheppo * This call is asynchronous. It will complete at a later point 32901991Sheppo * in time when the peer responds back with an RTR. 32911991Sheppo */ 32921991Sheppo int 32931991Sheppo ldc_up(ldc_handle_t handle) 32941991Sheppo { 32951991Sheppo int rv; 32961991Sheppo ldc_chan_t *ldcp; 32971991Sheppo ldc_msg_t *ldcmsg; 32983808Ssb155480 uint64_t tx_tail, tstate, link_state; 32991991Sheppo 33001991Sheppo if (handle == NULL) { 33011991Sheppo DWARN(DBG_ALL_LDCS, "ldc_up: invalid channel handle\n"); 33021991Sheppo return (EINVAL); 33031991Sheppo } 33041991Sheppo ldcp = (ldc_chan_t *)handle; 33051991Sheppo 33061991Sheppo mutex_enter(&ldcp->lock); 33071991Sheppo 33082793Slm66018 D1(ldcp->id, "ldc_up: (0x%llx) doing channel UP\n", ldcp->id); 33092793Slm66018 33102793Slm66018 /* clear the reset state */ 33112793Slm66018 tstate = ldcp->tstate; 33122793Slm66018 ldcp->tstate &= ~TS_IN_RESET; 33132793Slm66018 33141991Sheppo if (ldcp->tstate == TS_UP) { 33152793Slm66018 DWARN(ldcp->id, 33161991Sheppo "ldc_up: (0x%llx) channel is already in UP state\n", 33171991Sheppo ldcp->id); 33182793Slm66018 33192793Slm66018 /* mark channel as up */ 33202793Slm66018 ldcp->status = LDC_UP; 33212793Slm66018 33222793Slm66018 /* 33232793Slm66018 * if channel was in reset state and there was 33242793Slm66018 * pending data clear interrupt state. this will 33252793Slm66018 * trigger an interrupt, causing the RX handler to 33262793Slm66018 * to invoke the client's callback 33272793Slm66018 */ 33282793Slm66018 if ((tstate & TS_IN_RESET) && 33292793Slm66018 ldcp->rx_intr_state == LDC_INTR_PEND) { 33303010Slm66018 D1(ldcp->id, 33312793Slm66018 "ldc_up: (0x%llx) channel has pending data, " 33322793Slm66018 "clearing interrupt\n", ldcp->id); 33332793Slm66018 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 33342793Slm66018 } 33352793Slm66018 33361991Sheppo mutex_exit(&ldcp->lock); 33371991Sheppo return (0); 33381991Sheppo } 33391991Sheppo 33401991Sheppo /* if the channel is in RAW mode - mark it as UP, if READY */ 33411991Sheppo if (ldcp->mode == LDC_MODE_RAW && ldcp->tstate >= TS_READY) { 33421991Sheppo ldcp->tstate = TS_UP; 33431991Sheppo mutex_exit(&ldcp->lock); 33441991Sheppo return (0); 33451991Sheppo } 33461991Sheppo 33471991Sheppo /* Don't start another handshake if there is one in progress */ 33481991Sheppo if (ldcp->hstate) { 33492793Slm66018 D1(ldcp->id, 33501991Sheppo "ldc_up: (0x%llx) channel handshake in progress\n", 33511991Sheppo ldcp->id); 33521991Sheppo mutex_exit(&ldcp->lock); 33531991Sheppo return (0); 33541991Sheppo } 33551991Sheppo 33562336Snarayan mutex_enter(&ldcp->tx_lock); 33572336Snarayan 33583808Ssb155480 /* save current link state */ 33593808Ssb155480 link_state = ldcp->link_state; 33603808Ssb155480 33611991Sheppo /* get the current tail for the LDC msg */ 33621991Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 33631991Sheppo if (rv) { 33643010Slm66018 D1(ldcp->id, "ldc_up: (0x%llx) cannot initiate handshake\n", 33651991Sheppo ldcp->id); 33662336Snarayan mutex_exit(&ldcp->tx_lock); 33671991Sheppo mutex_exit(&ldcp->lock); 33681991Sheppo return (ECONNREFUSED); 33691991Sheppo } 33701991Sheppo 33713808Ssb155480 /* 33723808Ssb155480 * If i_ldc_get_tx_tail() changed link_state to either RESET or UP, 33733808Ssb155480 * from a previous state of DOWN, then mark the channel as 33743808Ssb155480 * being ready for handshake. 33753808Ssb155480 */ 33763808Ssb155480 if ((link_state == LDC_CHANNEL_DOWN) && 33773808Ssb155480 (link_state != ldcp->link_state)) { 33783808Ssb155480 33793808Ssb155480 ASSERT((ldcp->link_state == LDC_CHANNEL_RESET) || 33803808Ssb155480 (ldcp->link_state == LDC_CHANNEL_UP)); 33813808Ssb155480 33823808Ssb155480 if (ldcp->mode == LDC_MODE_RAW) { 33833808Ssb155480 ldcp->status = LDC_UP; 33843808Ssb155480 ldcp->tstate = TS_UP; 33853808Ssb155480 mutex_exit(&ldcp->tx_lock); 33863808Ssb155480 mutex_exit(&ldcp->lock); 33873808Ssb155480 return (0); 33883808Ssb155480 } else { 33893808Ssb155480 ldcp->status = LDC_READY; 33903808Ssb155480 ldcp->tstate |= TS_LINK_READY; 33913808Ssb155480 } 33923808Ssb155480 33933808Ssb155480 } 33943808Ssb155480 33951991Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 33961991Sheppo ZERO_PKT(ldcmsg); 33971991Sheppo 33981991Sheppo ldcmsg->type = LDC_CTRL; 33991991Sheppo ldcmsg->stype = LDC_INFO; 34001991Sheppo ldcmsg->ctrl = LDC_VER; 34011991Sheppo ldcp->next_vidx = 0; 34021991Sheppo bcopy(&ldc_versions[0], ldcmsg->udata, sizeof (ldc_versions[0])); 34031991Sheppo 34041991Sheppo DUMP_LDC_PKT(ldcp, "ldc_up snd ver", (uint64_t)ldcmsg); 34051991Sheppo 34061991Sheppo /* initiate the send by calling into HV and set the new tail */ 34071991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 34084690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 34091991Sheppo 34101991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 34111991Sheppo if (rv) { 34121991Sheppo DWARN(ldcp->id, 34131991Sheppo "ldc_up: (0x%llx) cannot initiate handshake rv=%d\n", 34141991Sheppo ldcp->id, rv); 34152336Snarayan mutex_exit(&ldcp->tx_lock); 34161991Sheppo mutex_exit(&ldcp->lock); 34171991Sheppo return (rv); 34181991Sheppo } 34191991Sheppo 34202032Slm66018 ldcp->hstate |= TS_SENT_VER; 34211991Sheppo ldcp->tx_tail = tx_tail; 34221991Sheppo D1(ldcp->id, "ldc_up: (0x%llx) channel up initiated\n", ldcp->id); 34231991Sheppo 34242336Snarayan mutex_exit(&ldcp->tx_lock); 34251991Sheppo mutex_exit(&ldcp->lock); 34261991Sheppo 34271991Sheppo return (rv); 34281991Sheppo } 34291991Sheppo 34301991Sheppo 34311991Sheppo /* 34322410Slm66018 * Bring a channel down by resetting its state and queues 34331991Sheppo */ 34341991Sheppo int 34352410Slm66018 ldc_down(ldc_handle_t handle) 34361991Sheppo { 34371991Sheppo ldc_chan_t *ldcp; 34381991Sheppo 34391991Sheppo if (handle == NULL) { 34402410Slm66018 DWARN(DBG_ALL_LDCS, "ldc_down: invalid channel handle\n"); 34411991Sheppo return (EINVAL); 34421991Sheppo } 34431991Sheppo ldcp = (ldc_chan_t *)handle; 34441991Sheppo mutex_enter(&ldcp->lock); 34452336Snarayan mutex_enter(&ldcp->tx_lock); 34462793Slm66018 i_ldc_reset(ldcp, B_TRUE); 34472336Snarayan mutex_exit(&ldcp->tx_lock); 34481991Sheppo mutex_exit(&ldcp->lock); 34491991Sheppo 34501991Sheppo return (0); 34511991Sheppo } 34521991Sheppo 34531991Sheppo /* 34541991Sheppo * Get the current channel status 34551991Sheppo */ 34561991Sheppo int 34571991Sheppo ldc_status(ldc_handle_t handle, ldc_status_t *status) 34581991Sheppo { 34591991Sheppo ldc_chan_t *ldcp; 34601991Sheppo 34611991Sheppo if (handle == NULL || status == NULL) { 34621991Sheppo DWARN(DBG_ALL_LDCS, "ldc_status: invalid argument\n"); 34631991Sheppo return (EINVAL); 34641991Sheppo } 34651991Sheppo ldcp = (ldc_chan_t *)handle; 34661991Sheppo 34671991Sheppo *status = ((ldc_chan_t *)handle)->status; 34681991Sheppo 34693010Slm66018 D1(ldcp->id, 34701991Sheppo "ldc_status: (0x%llx) returned status %d\n", ldcp->id, *status); 34711991Sheppo return (0); 34721991Sheppo } 34731991Sheppo 34741991Sheppo 34751991Sheppo /* 34761991Sheppo * Set the channel's callback mode - enable/disable callbacks 34771991Sheppo */ 34781991Sheppo int 34791991Sheppo ldc_set_cb_mode(ldc_handle_t handle, ldc_cb_mode_t cmode) 34801991Sheppo { 34811991Sheppo ldc_chan_t *ldcp; 34821991Sheppo 34831991Sheppo if (handle == NULL) { 34841991Sheppo DWARN(DBG_ALL_LDCS, 34851991Sheppo "ldc_set_intr_mode: invalid channel handle\n"); 34861991Sheppo return (EINVAL); 34871991Sheppo } 34881991Sheppo ldcp = (ldc_chan_t *)handle; 34891991Sheppo 34901991Sheppo /* 34911991Sheppo * Record no callbacks should be invoked 34921991Sheppo */ 34931991Sheppo mutex_enter(&ldcp->lock); 34941991Sheppo 34951991Sheppo switch (cmode) { 34961991Sheppo case LDC_CB_DISABLE: 34971991Sheppo if (!ldcp->cb_enabled) { 34981991Sheppo DWARN(ldcp->id, 34991991Sheppo "ldc_set_cb_mode: (0x%llx) callbacks disabled\n", 35001991Sheppo ldcp->id); 35011991Sheppo break; 35021991Sheppo } 35031991Sheppo ldcp->cb_enabled = B_FALSE; 35041991Sheppo 35051991Sheppo D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) disabled callbacks\n", 35061991Sheppo ldcp->id); 35071991Sheppo break; 35081991Sheppo 35091991Sheppo case LDC_CB_ENABLE: 35101991Sheppo if (ldcp->cb_enabled) { 35111991Sheppo DWARN(ldcp->id, 35121991Sheppo "ldc_set_cb_mode: (0x%llx) callbacks enabled\n", 35131991Sheppo ldcp->id); 35141991Sheppo break; 35151991Sheppo } 35161991Sheppo ldcp->cb_enabled = B_TRUE; 35171991Sheppo 35181991Sheppo D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) enabled callbacks\n", 35191991Sheppo ldcp->id); 35201991Sheppo break; 35211991Sheppo } 35221991Sheppo 35231991Sheppo mutex_exit(&ldcp->lock); 35241991Sheppo 35251991Sheppo return (0); 35261991Sheppo } 35271991Sheppo 35281991Sheppo /* 35291991Sheppo * Check to see if there are packets on the incoming queue 35302410Slm66018 * Will return hasdata = B_FALSE if there are no packets 35311991Sheppo */ 35321991Sheppo int 35332410Slm66018 ldc_chkq(ldc_handle_t handle, boolean_t *hasdata) 35341991Sheppo { 35351991Sheppo int rv; 35361991Sheppo uint64_t rx_head, rx_tail; 35371991Sheppo ldc_chan_t *ldcp; 35381991Sheppo 35391991Sheppo if (handle == NULL) { 35401991Sheppo DWARN(DBG_ALL_LDCS, "ldc_chkq: invalid channel handle\n"); 35411991Sheppo return (EINVAL); 35421991Sheppo } 35431991Sheppo ldcp = (ldc_chan_t *)handle; 35441991Sheppo 35452410Slm66018 *hasdata = B_FALSE; 35461991Sheppo 35471991Sheppo mutex_enter(&ldcp->lock); 35481991Sheppo 35491991Sheppo if (ldcp->tstate != TS_UP) { 35501991Sheppo D1(ldcp->id, 35511991Sheppo "ldc_chkq: (0x%llx) channel is not up\n", ldcp->id); 35521991Sheppo mutex_exit(&ldcp->lock); 35531991Sheppo return (ECONNRESET); 35541991Sheppo } 35551991Sheppo 35561991Sheppo /* Read packet(s) from the queue */ 35571991Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 35581991Sheppo &ldcp->link_state); 35591991Sheppo if (rv != 0) { 35601991Sheppo cmn_err(CE_WARN, 35611991Sheppo "ldc_chkq: (0x%lx) unable to read queue ptrs", ldcp->id); 35621991Sheppo mutex_exit(&ldcp->lock); 35631991Sheppo return (EIO); 35641991Sheppo } 35655944Sha137994 35661991Sheppo /* reset the channel state if the channel went down */ 35671991Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN || 35681991Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 35692336Snarayan mutex_enter(&ldcp->tx_lock); 35702793Slm66018 i_ldc_reset(ldcp, B_FALSE); 35712336Snarayan mutex_exit(&ldcp->tx_lock); 35721991Sheppo mutex_exit(&ldcp->lock); 35731991Sheppo return (ECONNRESET); 35741991Sheppo } 35751991Sheppo 35765944Sha137994 switch (ldcp->mode) { 35775944Sha137994 case LDC_MODE_RAW: 35785944Sha137994 /* 35795944Sha137994 * In raw mode, there are no ctrl packets, so checking 35805944Sha137994 * if the queue is non-empty is sufficient. 35815944Sha137994 */ 35825944Sha137994 *hasdata = (rx_head != rx_tail); 35835944Sha137994 break; 35845944Sha137994 35855944Sha137994 case LDC_MODE_UNRELIABLE: 35865944Sha137994 /* 35875944Sha137994 * In unreliable mode, if the queue is non-empty, we need 35885944Sha137994 * to check if it actually contains unread data packets. 35895944Sha137994 * The queue may just contain ctrl packets. 35905944Sha137994 */ 35916446Sha137994 if (rx_head != rx_tail) { 35925944Sha137994 *hasdata = (i_ldc_chkq(ldcp) == 0); 35936446Sha137994 /* 35946446Sha137994 * If no data packets were found on the queue, 35956446Sha137994 * all packets must have been control packets 35966446Sha137994 * which will now have been processed, leaving 35976446Sha137994 * the queue empty. If the interrupt state 35986446Sha137994 * is pending, we need to clear the interrupt 35996446Sha137994 * here. 36006446Sha137994 */ 36016446Sha137994 if (*hasdata == B_FALSE && 36026446Sha137994 ldcp->rx_intr_state == LDC_INTR_PEND) { 36036446Sha137994 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 36046446Sha137994 } 36056446Sha137994 } 36065944Sha137994 break; 36075944Sha137994 36086408Sha137994 case LDC_MODE_RELIABLE: 36095944Sha137994 /* 36106408Sha137994 * In reliable mode, first check for 'stream_remains' > 0. 36115944Sha137994 * Otherwise, if the data queue head and tail pointers 36125944Sha137994 * differ, there must be data to read. 36135944Sha137994 */ 36145944Sha137994 if (ldcp->stream_remains > 0) 36155944Sha137994 *hasdata = B_TRUE; 36165944Sha137994 else 36175944Sha137994 *hasdata = (ldcp->rx_dq_head != ldcp->rx_dq_tail); 36185944Sha137994 break; 36195944Sha137994 36205944Sha137994 default: 36215944Sha137994 cmn_err(CE_WARN, "ldc_chkq: (0x%lx) unexpected channel mode " 36225944Sha137994 "(0x%x)", ldcp->id, ldcp->mode); 36235944Sha137994 mutex_exit(&ldcp->lock); 36245944Sha137994 return (EIO); 36251991Sheppo } 36261991Sheppo 36271991Sheppo mutex_exit(&ldcp->lock); 36281991Sheppo 36291991Sheppo return (0); 36301991Sheppo } 36311991Sheppo 36321991Sheppo 36331991Sheppo /* 36341991Sheppo * Read 'size' amount of bytes or less. If incoming buffer 36351991Sheppo * is more than 'size', ENOBUFS is returned. 36361991Sheppo * 36371991Sheppo * On return, size contains the number of bytes read. 36381991Sheppo */ 36391991Sheppo int 36401991Sheppo ldc_read(ldc_handle_t handle, caddr_t bufp, size_t *sizep) 36411991Sheppo { 36421991Sheppo ldc_chan_t *ldcp; 36431991Sheppo uint64_t rx_head = 0, rx_tail = 0; 36441991Sheppo int rv = 0, exit_val; 36451991Sheppo 36461991Sheppo if (handle == NULL) { 36471991Sheppo DWARN(DBG_ALL_LDCS, "ldc_read: invalid channel handle\n"); 36481991Sheppo return (EINVAL); 36491991Sheppo } 36501991Sheppo 36511991Sheppo ldcp = (ldc_chan_t *)handle; 36521991Sheppo 36531991Sheppo /* channel lock */ 36541991Sheppo mutex_enter(&ldcp->lock); 36551991Sheppo 36561991Sheppo if (ldcp->tstate != TS_UP) { 36571991Sheppo DWARN(ldcp->id, 36581991Sheppo "ldc_read: (0x%llx) channel is not in UP state\n", 36591991Sheppo ldcp->id); 36601991Sheppo exit_val = ECONNRESET; 36616408Sha137994 } else if (ldcp->mode == LDC_MODE_RELIABLE) { 36625944Sha137994 TRACE_RXDQ_LENGTH(ldcp); 36635944Sha137994 exit_val = ldcp->read_p(ldcp, bufp, sizep); 36646944Sha137994 36656944Sha137994 /* 36666944Sha137994 * For reliable mode channels, the interrupt 36676944Sha137994 * state is only set to pending during 36686944Sha137994 * interrupt handling when the secondary data 36696944Sha137994 * queue became full, leaving unprocessed 36706944Sha137994 * packets on the Rx queue. If the interrupt 36716944Sha137994 * state is pending and space is now available 36726944Sha137994 * on the data queue, clear the interrupt. 36736944Sha137994 */ 36746944Sha137994 if (ldcp->rx_intr_state == LDC_INTR_PEND && 36756944Sha137994 Q_CONTIG_SPACE(ldcp->rx_dq_head, ldcp->rx_dq_tail, 36766944Sha137994 ldcp->rx_dq_entries << LDC_PACKET_SHIFT) >= 36776944Sha137994 LDC_PACKET_SIZE) { 36786944Sha137994 /* data queue is not full */ 36796944Sha137994 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 36806944Sha137994 } 36816944Sha137994 36825944Sha137994 mutex_exit(&ldcp->lock); 36835944Sha137994 return (exit_val); 36841991Sheppo } else { 36851991Sheppo exit_val = ldcp->read_p(ldcp, bufp, sizep); 36861991Sheppo } 36871991Sheppo 36881991Sheppo /* 36891991Sheppo * if queue has been drained - clear interrupt 36901991Sheppo */ 36911991Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 36921991Sheppo &ldcp->link_state); 36933010Slm66018 if (rv != 0) { 36943010Slm66018 cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs", 36953010Slm66018 ldcp->id); 36963010Slm66018 mutex_enter(&ldcp->tx_lock); 36973010Slm66018 i_ldc_reset(ldcp, B_TRUE); 36983010Slm66018 mutex_exit(&ldcp->tx_lock); 36993653Snarayan mutex_exit(&ldcp->lock); 37003010Slm66018 return (ECONNRESET); 37013010Slm66018 } 37022793Slm66018 37032793Slm66018 if (exit_val == 0) { 37042793Slm66018 if (ldcp->link_state == LDC_CHANNEL_DOWN || 37052793Slm66018 ldcp->link_state == LDC_CHANNEL_RESET) { 37062793Slm66018 mutex_enter(&ldcp->tx_lock); 37072793Slm66018 i_ldc_reset(ldcp, B_FALSE); 37082793Slm66018 exit_val = ECONNRESET; 37092793Slm66018 mutex_exit(&ldcp->tx_lock); 37102793Slm66018 } 37112793Slm66018 if ((rv == 0) && 37122793Slm66018 (ldcp->rx_intr_state == LDC_INTR_PEND) && 37132793Slm66018 (rx_head == rx_tail)) { 37142793Slm66018 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 37152793Slm66018 } 37161991Sheppo } 37171991Sheppo 37181991Sheppo mutex_exit(&ldcp->lock); 37191991Sheppo return (exit_val); 37201991Sheppo } 37211991Sheppo 37221991Sheppo /* 37231991Sheppo * Basic raw mondo read - 37241991Sheppo * no interpretation of mondo contents at all. 37251991Sheppo * 37261991Sheppo * Enter and exit with ldcp->lock held by caller 37271991Sheppo */ 37281991Sheppo static int 37291991Sheppo i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep) 37301991Sheppo { 37311991Sheppo uint64_t q_size_mask; 37321991Sheppo ldc_msg_t *msgp; 37331991Sheppo uint8_t *msgbufp; 37341991Sheppo int rv = 0, space; 37351991Sheppo uint64_t rx_head, rx_tail; 37361991Sheppo 37371991Sheppo space = *sizep; 37381991Sheppo 37391991Sheppo if (space < LDC_PAYLOAD_SIZE_RAW) 37401991Sheppo return (ENOBUFS); 37411991Sheppo 37421991Sheppo ASSERT(mutex_owned(&ldcp->lock)); 37431991Sheppo 37441991Sheppo /* compute mask for increment */ 37451991Sheppo q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT; 37461991Sheppo 37471991Sheppo /* 37481991Sheppo * Read packet(s) from the queue 37491991Sheppo */ 37501991Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 37511991Sheppo &ldcp->link_state); 37521991Sheppo if (rv != 0) { 37531991Sheppo cmn_err(CE_WARN, 37541991Sheppo "ldc_read_raw: (0x%lx) unable to read queue ptrs", 37551991Sheppo ldcp->id); 37561991Sheppo return (EIO); 37571991Sheppo } 37581991Sheppo D1(ldcp->id, "ldc_read_raw: (0x%llx) rxh=0x%llx," 37594690Snarayan " rxt=0x%llx, st=0x%llx\n", 37604690Snarayan ldcp->id, rx_head, rx_tail, ldcp->link_state); 37611991Sheppo 37621991Sheppo /* reset the channel state if the channel went down */ 37632793Slm66018 if (ldcp->link_state == LDC_CHANNEL_DOWN || 37642793Slm66018 ldcp->link_state == LDC_CHANNEL_RESET) { 37652336Snarayan mutex_enter(&ldcp->tx_lock); 37662793Slm66018 i_ldc_reset(ldcp, B_FALSE); 37672336Snarayan mutex_exit(&ldcp->tx_lock); 37681991Sheppo return (ECONNRESET); 37691991Sheppo } 37701991Sheppo 37711991Sheppo /* 37721991Sheppo * Check for empty queue 37731991Sheppo */ 37741991Sheppo if (rx_head == rx_tail) { 37751991Sheppo *sizep = 0; 37761991Sheppo return (0); 37771991Sheppo } 37781991Sheppo 37791991Sheppo /* get the message */ 37801991Sheppo msgp = (ldc_msg_t *)(ldcp->rx_q_va + rx_head); 37811991Sheppo 37821991Sheppo /* if channel is in RAW mode, copy data and return */ 37831991Sheppo msgbufp = (uint8_t *)&(msgp->raw[0]); 37841991Sheppo 37851991Sheppo bcopy(msgbufp, target_bufp, LDC_PAYLOAD_SIZE_RAW); 37861991Sheppo 37871991Sheppo DUMP_PAYLOAD(ldcp->id, msgbufp); 37881991Sheppo 37891991Sheppo *sizep = LDC_PAYLOAD_SIZE_RAW; 37901991Sheppo 37911991Sheppo rx_head = (rx_head + LDC_PACKET_SIZE) & q_size_mask; 37922032Slm66018 rv = i_ldc_set_rx_head(ldcp, rx_head); 37931991Sheppo 37941991Sheppo return (rv); 37951991Sheppo } 37961991Sheppo 37971991Sheppo /* 37981991Sheppo * Process LDC mondos to build larger packets 37991991Sheppo * with either un-reliable or reliable delivery. 38001991Sheppo * 38011991Sheppo * Enter and exit with ldcp->lock held by caller 38021991Sheppo */ 38031991Sheppo static int 38041991Sheppo i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep) 38051991Sheppo { 38061991Sheppo int rv = 0; 38071991Sheppo uint64_t rx_head = 0, rx_tail = 0; 38081991Sheppo uint64_t curr_head = 0; 38091991Sheppo ldc_msg_t *msg; 38101991Sheppo caddr_t target; 38111991Sheppo size_t len = 0, bytes_read = 0; 38122032Slm66018 int retries = 0; 38135944Sha137994 uint64_t q_va, q_size_mask; 38142336Snarayan uint64_t first_fragment = 0; 38151991Sheppo 38161991Sheppo target = target_bufp; 38171991Sheppo 38181991Sheppo ASSERT(mutex_owned(&ldcp->lock)); 38191991Sheppo 38202793Slm66018 /* check if the buffer and size are valid */ 38212793Slm66018 if (target_bufp == NULL || *sizep == 0) { 38222793Slm66018 DWARN(ldcp->id, "ldc_read: (0x%llx) invalid buffer/size\n", 38232793Slm66018 ldcp->id); 38242793Slm66018 return (EINVAL); 38252793Slm66018 } 38262793Slm66018 38275944Sha137994 /* Set q_va and compute increment mask for the appropriate queue */ 38286408Sha137994 if (ldcp->mode == LDC_MODE_RELIABLE) { 38295944Sha137994 q_va = ldcp->rx_dq_va; 38305944Sha137994 q_size_mask = (ldcp->rx_dq_entries-1)<<LDC_PACKET_SHIFT; 38315944Sha137994 } else { 38325944Sha137994 q_va = ldcp->rx_q_va; 38335944Sha137994 q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT; 38345944Sha137994 } 38351991Sheppo 38361991Sheppo /* 38371991Sheppo * Read packet(s) from the queue 38381991Sheppo */ 38395944Sha137994 rv = ldcp->readq_get_state(ldcp, &curr_head, &rx_tail, 38401991Sheppo &ldcp->link_state); 38411991Sheppo if (rv != 0) { 38422793Slm66018 cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs", 38431991Sheppo ldcp->id); 38442793Slm66018 mutex_enter(&ldcp->tx_lock); 38452793Slm66018 i_ldc_reset(ldcp, B_TRUE); 38462793Slm66018 mutex_exit(&ldcp->tx_lock); 38472793Slm66018 return (ECONNRESET); 38481991Sheppo } 38491991Sheppo D1(ldcp->id, "ldc_read: (0x%llx) chd=0x%llx, tl=0x%llx, st=0x%llx\n", 38501991Sheppo ldcp->id, curr_head, rx_tail, ldcp->link_state); 38511991Sheppo 38521991Sheppo /* reset the channel state if the channel went down */ 38532793Slm66018 if (ldcp->link_state != LDC_CHANNEL_UP) 38542793Slm66018 goto channel_is_reset; 38551991Sheppo 38561991Sheppo for (;;) { 38571991Sheppo 38581991Sheppo if (curr_head == rx_tail) { 38595944Sha137994 /* 38605944Sha137994 * If a data queue is being used, check the Rx HV 38615944Sha137994 * queue. This will copy over any new data packets 38625944Sha137994 * that have arrived. 38635944Sha137994 */ 38646408Sha137994 if (ldcp->mode == LDC_MODE_RELIABLE) 38655944Sha137994 (void) i_ldc_chkq(ldcp); 38665944Sha137994 38675944Sha137994 rv = ldcp->readq_get_state(ldcp, 38681991Sheppo &rx_head, &rx_tail, &ldcp->link_state); 38691991Sheppo if (rv != 0) { 38701991Sheppo cmn_err(CE_WARN, 38711991Sheppo "ldc_read: (0x%lx) cannot read queue ptrs", 38721991Sheppo ldcp->id); 38732336Snarayan mutex_enter(&ldcp->tx_lock); 38742793Slm66018 i_ldc_reset(ldcp, B_TRUE); 38752336Snarayan mutex_exit(&ldcp->tx_lock); 38761991Sheppo return (ECONNRESET); 38771991Sheppo } 38785944Sha137994 38792793Slm66018 if (ldcp->link_state != LDC_CHANNEL_UP) 38802793Slm66018 goto channel_is_reset; 38812793Slm66018 38822793Slm66018 if (curr_head == rx_tail) { 38832793Slm66018 38842793Slm66018 /* If in the middle of a fragmented xfer */ 38852793Slm66018 if (first_fragment != 0) { 38862793Slm66018 38872793Slm66018 /* wait for ldc_delay usecs */ 38882793Slm66018 drv_usecwait(ldc_delay); 38892793Slm66018 38902793Slm66018 if (++retries < ldc_max_retries) 38912793Slm66018 continue; 38922793Slm66018 38932793Slm66018 *sizep = 0; 38946408Sha137994 if (ldcp->mode != LDC_MODE_RELIABLE) 38955944Sha137994 ldcp->last_msg_rcd = 38965944Sha137994 first_fragment - 1; 38972793Slm66018 DWARN(DBG_ALL_LDCS, "ldc_read: " 38984690Snarayan "(0x%llx) read timeout", ldcp->id); 38992793Slm66018 return (EAGAIN); 39002793Slm66018 } 39012032Slm66018 *sizep = 0; 39022793Slm66018 break; 39031991Sheppo } 39041991Sheppo } 39052032Slm66018 retries = 0; 39061991Sheppo 39071991Sheppo D2(ldcp->id, 39081991Sheppo "ldc_read: (0x%llx) chd=0x%llx, rxhd=0x%llx, rxtl=0x%llx\n", 39091991Sheppo ldcp->id, curr_head, rx_head, rx_tail); 39101991Sheppo 39111991Sheppo /* get the message */ 39125944Sha137994 msg = (ldc_msg_t *)(q_va + curr_head); 39131991Sheppo 39141991Sheppo DUMP_LDC_PKT(ldcp, "ldc_read received pkt", 39151991Sheppo ldcp->rx_q_va + curr_head); 39161991Sheppo 39171991Sheppo /* Check the message ID for the message received */ 39186408Sha137994 if (ldcp->mode != LDC_MODE_RELIABLE) { 39195944Sha137994 if ((rv = i_ldc_check_seqid(ldcp, msg)) != 0) { 39205944Sha137994 39215944Sha137994 DWARN(ldcp->id, "ldc_read: (0x%llx) seqid " 39225944Sha137994 "error, q_ptrs=0x%lx,0x%lx", 39235944Sha137994 ldcp->id, rx_head, rx_tail); 39245944Sha137994 39255944Sha137994 /* throw away data */ 39265944Sha137994 bytes_read = 0; 39275944Sha137994 39285944Sha137994 /* Reset last_msg_rcd to start of message */ 39295944Sha137994 if (first_fragment != 0) { 39305944Sha137994 ldcp->last_msg_rcd = first_fragment - 1; 39315944Sha137994 first_fragment = 0; 39325944Sha137994 } 39335944Sha137994 /* 39345944Sha137994 * Send a NACK -- invalid seqid 39355944Sha137994 * get the current tail for the response 39365944Sha137994 */ 39375944Sha137994 rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK, 39385944Sha137994 (msg->ctrl & LDC_CTRL_MASK)); 39395944Sha137994 if (rv) { 39405944Sha137994 cmn_err(CE_NOTE, 39415944Sha137994 "ldc_read: (0x%lx) err sending " 39425944Sha137994 "NACK msg\n", ldcp->id); 39435944Sha137994 39445944Sha137994 /* if cannot send NACK - reset chan */ 39455944Sha137994 mutex_enter(&ldcp->tx_lock); 39465944Sha137994 i_ldc_reset(ldcp, B_FALSE); 39475944Sha137994 mutex_exit(&ldcp->tx_lock); 39485944Sha137994 rv = ECONNRESET; 39495944Sha137994 break; 39505944Sha137994 } 39515944Sha137994 39525944Sha137994 /* purge receive queue */ 39535944Sha137994 rv = i_ldc_set_rx_head(ldcp, rx_tail); 39545944Sha137994 39552336Snarayan break; 39561991Sheppo } 39571991Sheppo 39585944Sha137994 /* 39595944Sha137994 * Process any messages of type CTRL messages 39605944Sha137994 * Future implementations should try to pass these 39615944Sha137994 * to LDC link by resetting the intr state. 39625944Sha137994 * 39635944Sha137994 * NOTE: not done as a switch() as type can be 39645944Sha137994 * both ctrl+data 39655944Sha137994 */ 39665944Sha137994 if (msg->type & LDC_CTRL) { 39675944Sha137994 if (rv = i_ldc_ctrlmsg(ldcp, msg)) { 39685944Sha137994 if (rv == EAGAIN) 39695944Sha137994 continue; 39705944Sha137994 rv = i_ldc_set_rx_head(ldcp, rx_tail); 39715944Sha137994 *sizep = 0; 39725944Sha137994 bytes_read = 0; 39735944Sha137994 break; 39745944Sha137994 } 39751991Sheppo } 39765944Sha137994 39775944Sha137994 /* process data ACKs */ 39785944Sha137994 if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) { 39795944Sha137994 if (rv = i_ldc_process_data_ACK(ldcp, msg)) { 39805944Sha137994 *sizep = 0; 39815944Sha137994 bytes_read = 0; 39825944Sha137994 break; 39835944Sha137994 } 39842336Snarayan } 39855944Sha137994 39865944Sha137994 /* process data NACKs */ 39875944Sha137994 if ((msg->type & LDC_DATA) && (msg->stype & LDC_NACK)) { 39885944Sha137994 DWARN(ldcp->id, 39895944Sha137994 "ldc_read: (0x%llx) received DATA/NACK", 39905944Sha137994 ldcp->id); 39915944Sha137994 mutex_enter(&ldcp->tx_lock); 39925944Sha137994 i_ldc_reset(ldcp, B_TRUE); 39935944Sha137994 mutex_exit(&ldcp->tx_lock); 39945944Sha137994 return (ECONNRESET); 39955944Sha137994 } 39963560Snarayan } 39973560Snarayan 39981991Sheppo /* process data messages */ 39991991Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) { 40001991Sheppo 40011991Sheppo uint8_t *msgbuf = (uint8_t *)( 40026408Sha137994 (ldcp->mode == LDC_MODE_RELIABLE) ? 40034690Snarayan msg->rdata : msg->udata); 40041991Sheppo 40051991Sheppo D2(ldcp->id, 40061991Sheppo "ldc_read: (0x%llx) received data msg\n", ldcp->id); 40071991Sheppo 40081991Sheppo /* get the packet length */ 40091991Sheppo len = (msg->env & LDC_LEN_MASK); 40101991Sheppo 40111991Sheppo /* 40121991Sheppo * FUTURE OPTIMIZATION: 40131991Sheppo * dont need to set q head for every 40141991Sheppo * packet we read just need to do this when 40151991Sheppo * we are done or need to wait for more 40161991Sheppo * mondos to make a full packet - this is 40171991Sheppo * currently expensive. 40181991Sheppo */ 40191991Sheppo 40202336Snarayan if (first_fragment == 0) { 40211991Sheppo 40221991Sheppo /* 40231991Sheppo * first packets should always have the start 40241991Sheppo * bit set (even for a single packet). If not 40251991Sheppo * throw away the packet 40261991Sheppo */ 40271991Sheppo if (!(msg->env & LDC_FRAG_START)) { 40281991Sheppo 40291991Sheppo DWARN(DBG_ALL_LDCS, 40301991Sheppo "ldc_read: (0x%llx) not start - " 40311991Sheppo "frag=%x\n", ldcp->id, 40321991Sheppo (msg->env) & LDC_FRAG_MASK); 40331991Sheppo 40341991Sheppo /* toss pkt, inc head, cont reading */ 40351991Sheppo bytes_read = 0; 40361991Sheppo target = target_bufp; 40371991Sheppo curr_head = 40384690Snarayan (curr_head + LDC_PACKET_SIZE) 40394690Snarayan & q_size_mask; 40405944Sha137994 if (rv = ldcp->readq_set_head(ldcp, 40414690Snarayan curr_head)) 40421991Sheppo break; 40431991Sheppo 40441991Sheppo continue; 40451991Sheppo } 40461991Sheppo 40472336Snarayan first_fragment = msg->seqid; 40481991Sheppo } else { 40491991Sheppo /* check to see if this is a pkt w/ START bit */ 40501991Sheppo if (msg->env & LDC_FRAG_START) { 40511991Sheppo DWARN(DBG_ALL_LDCS, 40521991Sheppo "ldc_read:(0x%llx) unexpected pkt" 40531991Sheppo " env=0x%x discarding %d bytes," 40541991Sheppo " lastmsg=%d, currentmsg=%d\n", 40551991Sheppo ldcp->id, msg->env&LDC_FRAG_MASK, 40561991Sheppo bytes_read, ldcp->last_msg_rcd, 40571991Sheppo msg->seqid); 40581991Sheppo 40591991Sheppo /* throw data we have read so far */ 40601991Sheppo bytes_read = 0; 40611991Sheppo target = target_bufp; 40622336Snarayan first_fragment = msg->seqid; 40631991Sheppo 40645944Sha137994 if (rv = ldcp->readq_set_head(ldcp, 40654690Snarayan curr_head)) 40661991Sheppo break; 40671991Sheppo } 40681991Sheppo } 40691991Sheppo 40701991Sheppo /* copy (next) pkt into buffer */ 40711991Sheppo if (len <= (*sizep - bytes_read)) { 40721991Sheppo bcopy(msgbuf, target, len); 40731991Sheppo target += len; 40741991Sheppo bytes_read += len; 40751991Sheppo } else { 40761991Sheppo /* 40771991Sheppo * there is not enough space in the buffer to 40781991Sheppo * read this pkt. throw message away & continue 40791991Sheppo * reading data from queue 40801991Sheppo */ 40811991Sheppo DWARN(DBG_ALL_LDCS, 40821991Sheppo "ldc_read: (0x%llx) buffer too small, " 40831991Sheppo "head=0x%lx, expect=%d, got=%d\n", ldcp->id, 40841991Sheppo curr_head, *sizep, bytes_read+len); 40851991Sheppo 40862336Snarayan first_fragment = 0; 40871991Sheppo target = target_bufp; 40881991Sheppo bytes_read = 0; 40891991Sheppo 40901991Sheppo /* throw away everything received so far */ 40915944Sha137994 if (rv = ldcp->readq_set_head(ldcp, curr_head)) 40921991Sheppo break; 40931991Sheppo 40941991Sheppo /* continue reading remaining pkts */ 40951991Sheppo continue; 40961991Sheppo } 40971991Sheppo } 40981991Sheppo 40991991Sheppo /* set the message id */ 41006408Sha137994 if (ldcp->mode != LDC_MODE_RELIABLE) 41015944Sha137994 ldcp->last_msg_rcd = msg->seqid; 41021991Sheppo 41031991Sheppo /* move the head one position */ 41041991Sheppo curr_head = (curr_head + LDC_PACKET_SIZE) & q_size_mask; 41051991Sheppo 41061991Sheppo if (msg->env & LDC_FRAG_STOP) { 41071991Sheppo 41081991Sheppo /* 41091991Sheppo * All pkts that are part of this fragmented transfer 41101991Sheppo * have been read or this was a single pkt read 41111991Sheppo * or there was an error 41121991Sheppo */ 41131991Sheppo 41141991Sheppo /* set the queue head */ 41155944Sha137994 if (rv = ldcp->readq_set_head(ldcp, curr_head)) 41161991Sheppo bytes_read = 0; 41171991Sheppo 41181991Sheppo *sizep = bytes_read; 41191991Sheppo 41201991Sheppo break; 41211991Sheppo } 41221991Sheppo 41234890Snarayan /* advance head if it is a CTRL packet or a DATA ACK packet */ 41244890Snarayan if ((msg->type & LDC_CTRL) || 41254890Snarayan ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK))) { 41261991Sheppo 41271991Sheppo /* set the queue head */ 41285944Sha137994 if (rv = ldcp->readq_set_head(ldcp, curr_head)) { 41291991Sheppo bytes_read = 0; 41301991Sheppo break; 41311991Sheppo } 41321991Sheppo 41331991Sheppo D2(ldcp->id, "ldc_read: (0x%llx) set ACK qhead 0x%llx", 41341991Sheppo ldcp->id, curr_head); 41351991Sheppo } 41361991Sheppo 41371991Sheppo } /* for (;;) */ 41381991Sheppo 41391991Sheppo D2(ldcp->id, "ldc_read: (0x%llx) end size=%d", ldcp->id, *sizep); 41401991Sheppo 41411991Sheppo return (rv); 41422793Slm66018 41432793Slm66018 channel_is_reset: 41442793Slm66018 mutex_enter(&ldcp->tx_lock); 41452793Slm66018 i_ldc_reset(ldcp, B_FALSE); 41462793Slm66018 mutex_exit(&ldcp->tx_lock); 41472793Slm66018 return (ECONNRESET); 41481991Sheppo } 41491991Sheppo 41501991Sheppo /* 41516408Sha137994 * Fetch and buffer incoming packets so we can hand them back as 41521991Sheppo * a basic byte stream. 41531991Sheppo * 41541991Sheppo * Enter and exit with ldcp->lock held by caller 41551991Sheppo */ 41561991Sheppo static int 41571991Sheppo i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep) 41581991Sheppo { 41591991Sheppo int rv; 41601991Sheppo size_t size; 41611991Sheppo 41621991Sheppo ASSERT(mutex_owned(&ldcp->lock)); 41631991Sheppo 41641991Sheppo D2(ldcp->id, "i_ldc_read_stream: (0x%llx) buffer size=%d", 41654690Snarayan ldcp->id, *sizep); 41661991Sheppo 41671991Sheppo if (ldcp->stream_remains == 0) { 41681991Sheppo size = ldcp->mtu; 41691991Sheppo rv = i_ldc_read_packet(ldcp, 41704690Snarayan (caddr_t)ldcp->stream_bufferp, &size); 41711991Sheppo D2(ldcp->id, "i_ldc_read_stream: read packet (0x%llx) size=%d", 41724690Snarayan ldcp->id, size); 41731991Sheppo 41741991Sheppo if (rv != 0) 41751991Sheppo return (rv); 41761991Sheppo 41771991Sheppo ldcp->stream_remains = size; 41781991Sheppo ldcp->stream_offset = 0; 41791991Sheppo } 41801991Sheppo 41811991Sheppo size = MIN(ldcp->stream_remains, *sizep); 41821991Sheppo 41831991Sheppo bcopy(ldcp->stream_bufferp + ldcp->stream_offset, target_bufp, size); 41841991Sheppo ldcp->stream_offset += size; 41851991Sheppo ldcp->stream_remains -= size; 41861991Sheppo 41871991Sheppo D2(ldcp->id, "i_ldc_read_stream: (0x%llx) fill from buffer size=%d", 41884690Snarayan ldcp->id, size); 41891991Sheppo 41901991Sheppo *sizep = size; 41911991Sheppo return (0); 41921991Sheppo } 41931991Sheppo 41941991Sheppo /* 41951991Sheppo * Write specified amount of bytes to the channel 41961991Sheppo * in multiple pkts of pkt_payload size. Each 41971991Sheppo * packet is tagged with an unique packet ID in 41982410Slm66018 * the case of a reliable link. 41991991Sheppo * 42001991Sheppo * On return, size contains the number of bytes written. 42011991Sheppo */ 42021991Sheppo int 42031991Sheppo ldc_write(ldc_handle_t handle, caddr_t buf, size_t *sizep) 42041991Sheppo { 42051991Sheppo ldc_chan_t *ldcp; 42061991Sheppo int rv = 0; 42071991Sheppo 42081991Sheppo if (handle == NULL) { 42091991Sheppo DWARN(DBG_ALL_LDCS, "ldc_write: invalid channel handle\n"); 42101991Sheppo return (EINVAL); 42111991Sheppo } 42121991Sheppo ldcp = (ldc_chan_t *)handle; 42131991Sheppo 42142336Snarayan /* check if writes can occur */ 42152336Snarayan if (!mutex_tryenter(&ldcp->tx_lock)) { 42162336Snarayan /* 42172336Snarayan * Could not get the lock - channel could 42182336Snarayan * be in the process of being unconfigured 42192336Snarayan * or reader has encountered an error 42202336Snarayan */ 42212336Snarayan return (EAGAIN); 42222336Snarayan } 42231991Sheppo 42241991Sheppo /* check if non-zero data to write */ 42251991Sheppo if (buf == NULL || sizep == NULL) { 42261991Sheppo DWARN(ldcp->id, "ldc_write: (0x%llx) invalid data write\n", 42271991Sheppo ldcp->id); 42282336Snarayan mutex_exit(&ldcp->tx_lock); 42291991Sheppo return (EINVAL); 42301991Sheppo } 42311991Sheppo 42321991Sheppo if (*sizep == 0) { 42331991Sheppo DWARN(ldcp->id, "ldc_write: (0x%llx) write size of zero\n", 42341991Sheppo ldcp->id); 42352336Snarayan mutex_exit(&ldcp->tx_lock); 42361991Sheppo return (0); 42371991Sheppo } 42381991Sheppo 42391991Sheppo /* Check if channel is UP for data exchange */ 42401991Sheppo if (ldcp->tstate != TS_UP) { 42411991Sheppo DWARN(ldcp->id, 42421991Sheppo "ldc_write: (0x%llx) channel is not in UP state\n", 42431991Sheppo ldcp->id); 42441991Sheppo *sizep = 0; 42451991Sheppo rv = ECONNRESET; 42461991Sheppo } else { 42471991Sheppo rv = ldcp->write_p(ldcp, buf, sizep); 42481991Sheppo } 42491991Sheppo 42502336Snarayan mutex_exit(&ldcp->tx_lock); 42511991Sheppo 42521991Sheppo return (rv); 42531991Sheppo } 42541991Sheppo 42551991Sheppo /* 42561991Sheppo * Write a raw packet to the channel 42571991Sheppo * On return, size contains the number of bytes written. 42581991Sheppo */ 42591991Sheppo static int 42601991Sheppo i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep) 42611991Sheppo { 42621991Sheppo ldc_msg_t *ldcmsg; 42631991Sheppo uint64_t tx_head, tx_tail, new_tail; 42641991Sheppo int rv = 0; 42651991Sheppo size_t size; 42661991Sheppo 42672336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 42681991Sheppo ASSERT(ldcp->mode == LDC_MODE_RAW); 42691991Sheppo 42701991Sheppo size = *sizep; 42711991Sheppo 42721991Sheppo /* 42731991Sheppo * Check to see if the packet size is less than or 42741991Sheppo * equal to packet size support in raw mode 42751991Sheppo */ 42761991Sheppo if (size > ldcp->pkt_payload) { 42771991Sheppo DWARN(ldcp->id, 42781991Sheppo "ldc_write: (0x%llx) invalid size (0x%llx) for RAW mode\n", 42791991Sheppo ldcp->id, *sizep); 42801991Sheppo *sizep = 0; 42811991Sheppo return (EMSGSIZE); 42821991Sheppo } 42831991Sheppo 42841991Sheppo /* get the qptrs for the tx queue */ 42851991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 42861991Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 42871991Sheppo if (rv != 0) { 42881991Sheppo cmn_err(CE_WARN, 42891991Sheppo "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id); 42901991Sheppo *sizep = 0; 42911991Sheppo return (EIO); 42921991Sheppo } 42931991Sheppo 42941991Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN || 42951991Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 42961991Sheppo DWARN(ldcp->id, 42971991Sheppo "ldc_write: (0x%llx) channel down/reset\n", ldcp->id); 42982336Snarayan 42991991Sheppo *sizep = 0; 43002336Snarayan if (mutex_tryenter(&ldcp->lock)) { 43012793Slm66018 i_ldc_reset(ldcp, B_FALSE); 43022336Snarayan mutex_exit(&ldcp->lock); 43032336Snarayan } else { 43042336Snarayan /* 43052336Snarayan * Release Tx lock, and then reacquire channel 43062336Snarayan * and Tx lock in correct order 43072336Snarayan */ 43082336Snarayan mutex_exit(&ldcp->tx_lock); 43092336Snarayan mutex_enter(&ldcp->lock); 43102336Snarayan mutex_enter(&ldcp->tx_lock); 43112793Slm66018 i_ldc_reset(ldcp, B_FALSE); 43122336Snarayan mutex_exit(&ldcp->lock); 43132336Snarayan } 43141991Sheppo return (ECONNRESET); 43151991Sheppo } 43161991Sheppo 43171991Sheppo tx_tail = ldcp->tx_tail; 43181991Sheppo tx_head = ldcp->tx_head; 43191991Sheppo new_tail = (tx_tail + LDC_PACKET_SIZE) & 43204690Snarayan ((ldcp->tx_q_entries-1) << LDC_PACKET_SHIFT); 43211991Sheppo 43221991Sheppo if (new_tail == tx_head) { 43231991Sheppo DWARN(DBG_ALL_LDCS, 43241991Sheppo "ldc_write: (0x%llx) TX queue is full\n", ldcp->id); 43251991Sheppo *sizep = 0; 43261991Sheppo return (EWOULDBLOCK); 43271991Sheppo } 43281991Sheppo 43291991Sheppo D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d", 43301991Sheppo ldcp->id, size); 43311991Sheppo 43321991Sheppo /* Send the data now */ 43331991Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 43341991Sheppo 43352336Snarayan /* copy the data into pkt */ 43361991Sheppo bcopy((uint8_t *)buf, ldcmsg, size); 43371991Sheppo 43382336Snarayan /* increment tail */ 43391991Sheppo tx_tail = new_tail; 43401991Sheppo 43411991Sheppo /* 43421991Sheppo * All packets have been copied into the TX queue 43431991Sheppo * update the tail ptr in the HV 43441991Sheppo */ 43451991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 43461991Sheppo if (rv) { 43471991Sheppo if (rv == EWOULDBLOCK) { 43481991Sheppo DWARN(ldcp->id, "ldc_write: (0x%llx) write timed out\n", 43491991Sheppo ldcp->id); 43501991Sheppo *sizep = 0; 43511991Sheppo return (EWOULDBLOCK); 43521991Sheppo } 43531991Sheppo 43541991Sheppo *sizep = 0; 43552336Snarayan if (mutex_tryenter(&ldcp->lock)) { 43562793Slm66018 i_ldc_reset(ldcp, B_FALSE); 43572336Snarayan mutex_exit(&ldcp->lock); 43582336Snarayan } else { 43592336Snarayan /* 43602336Snarayan * Release Tx lock, and then reacquire channel 43612336Snarayan * and Tx lock in correct order 43622336Snarayan */ 43632336Snarayan mutex_exit(&ldcp->tx_lock); 43642336Snarayan mutex_enter(&ldcp->lock); 43652336Snarayan mutex_enter(&ldcp->tx_lock); 43662793Slm66018 i_ldc_reset(ldcp, B_FALSE); 43672336Snarayan mutex_exit(&ldcp->lock); 43682336Snarayan } 43691991Sheppo return (ECONNRESET); 43701991Sheppo } 43711991Sheppo 43721991Sheppo ldcp->tx_tail = tx_tail; 43731991Sheppo *sizep = size; 43741991Sheppo 43751991Sheppo D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, size); 43761991Sheppo 43771991Sheppo return (rv); 43781991Sheppo } 43791991Sheppo 43801991Sheppo 43811991Sheppo /* 43821991Sheppo * Write specified amount of bytes to the channel 43831991Sheppo * in multiple pkts of pkt_payload size. Each 43841991Sheppo * packet is tagged with an unique packet ID in 43852410Slm66018 * the case of a reliable link. 43861991Sheppo * 43871991Sheppo * On return, size contains the number of bytes written. 43881991Sheppo * This function needs to ensure that the write size is < MTU size 43891991Sheppo */ 43901991Sheppo static int 43911991Sheppo i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t buf, size_t *size) 43921991Sheppo { 43931991Sheppo ldc_msg_t *ldcmsg; 43941991Sheppo uint64_t tx_head, tx_tail, new_tail, start; 43951991Sheppo uint64_t txq_size_mask, numavail; 43961991Sheppo uint8_t *msgbuf, *source = (uint8_t *)buf; 43971991Sheppo size_t len, bytes_written = 0, remaining; 43981991Sheppo int rv; 43991991Sheppo uint32_t curr_seqid; 44001991Sheppo 44012336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 44021991Sheppo 44031991Sheppo ASSERT(ldcp->mode == LDC_MODE_RELIABLE || 44046408Sha137994 ldcp->mode == LDC_MODE_UNRELIABLE); 44051991Sheppo 44061991Sheppo /* compute mask for increment */ 44071991Sheppo txq_size_mask = (ldcp->tx_q_entries - 1) << LDC_PACKET_SHIFT; 44081991Sheppo 44091991Sheppo /* get the qptrs for the tx queue */ 44101991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 44111991Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 44121991Sheppo if (rv != 0) { 44131991Sheppo cmn_err(CE_WARN, 44141991Sheppo "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id); 44151991Sheppo *size = 0; 44161991Sheppo return (EIO); 44171991Sheppo } 44181991Sheppo 44191991Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN || 44201991Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 44211991Sheppo DWARN(ldcp->id, 44221991Sheppo "ldc_write: (0x%llx) channel down/reset\n", ldcp->id); 44231991Sheppo *size = 0; 44242336Snarayan if (mutex_tryenter(&ldcp->lock)) { 44252793Slm66018 i_ldc_reset(ldcp, B_FALSE); 44262336Snarayan mutex_exit(&ldcp->lock); 44272336Snarayan } else { 44282336Snarayan /* 44292336Snarayan * Release Tx lock, and then reacquire channel 44302336Snarayan * and Tx lock in correct order 44312336Snarayan */ 44322336Snarayan mutex_exit(&ldcp->tx_lock); 44332336Snarayan mutex_enter(&ldcp->lock); 44342336Snarayan mutex_enter(&ldcp->tx_lock); 44352793Slm66018 i_ldc_reset(ldcp, B_FALSE); 44362336Snarayan mutex_exit(&ldcp->lock); 44372336Snarayan } 44381991Sheppo return (ECONNRESET); 44391991Sheppo } 44401991Sheppo 44411991Sheppo tx_tail = ldcp->tx_tail; 44421991Sheppo new_tail = (tx_tail + LDC_PACKET_SIZE) % 44434690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 44441991Sheppo 44451991Sheppo /* 44464690Snarayan * Check to see if the queue is full. The check is done using 44474690Snarayan * the appropriate head based on the link mode. 44481991Sheppo */ 44494690Snarayan i_ldc_get_tx_head(ldcp, &tx_head); 44504690Snarayan 44511991Sheppo if (new_tail == tx_head) { 44521991Sheppo DWARN(DBG_ALL_LDCS, 44531991Sheppo "ldc_write: (0x%llx) TX queue is full\n", ldcp->id); 44541991Sheppo *size = 0; 44551991Sheppo return (EWOULDBLOCK); 44561991Sheppo } 44571991Sheppo 44581991Sheppo /* 44591991Sheppo * Make sure that the LDC Tx queue has enough space 44601991Sheppo */ 44611991Sheppo numavail = (tx_head >> LDC_PACKET_SHIFT) - (tx_tail >> LDC_PACKET_SHIFT) 44624690Snarayan + ldcp->tx_q_entries - 1; 44631991Sheppo numavail %= ldcp->tx_q_entries; 44641991Sheppo 44651991Sheppo if (*size > (numavail * ldcp->pkt_payload)) { 44661991Sheppo DWARN(DBG_ALL_LDCS, 44671991Sheppo "ldc_write: (0x%llx) TX queue has no space\n", ldcp->id); 44681991Sheppo return (EWOULDBLOCK); 44691991Sheppo } 44701991Sheppo 44711991Sheppo D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d", 44721991Sheppo ldcp->id, *size); 44731991Sheppo 44741991Sheppo /* Send the data now */ 44751991Sheppo bytes_written = 0; 44761991Sheppo curr_seqid = ldcp->last_msg_snt; 44771991Sheppo start = tx_tail; 44781991Sheppo 44791991Sheppo while (*size > bytes_written) { 44801991Sheppo 44811991Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 44821991Sheppo 44836408Sha137994 msgbuf = (uint8_t *)((ldcp->mode == LDC_MODE_RELIABLE) ? 44844690Snarayan ldcmsg->rdata : ldcmsg->udata); 44851991Sheppo 44861991Sheppo ldcmsg->type = LDC_DATA; 44871991Sheppo ldcmsg->stype = LDC_INFO; 44881991Sheppo ldcmsg->ctrl = 0; 44891991Sheppo 44901991Sheppo remaining = *size - bytes_written; 44911991Sheppo len = min(ldcp->pkt_payload, remaining); 44921991Sheppo ldcmsg->env = (uint8_t)len; 44931991Sheppo 44941991Sheppo curr_seqid++; 44951991Sheppo ldcmsg->seqid = curr_seqid; 44961991Sheppo 44971991Sheppo /* copy the data into pkt */ 44981991Sheppo bcopy(source, msgbuf, len); 44991991Sheppo 45001991Sheppo source += len; 45011991Sheppo bytes_written += len; 45021991Sheppo 45031991Sheppo /* increment tail */ 45041991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) & txq_size_mask; 45051991Sheppo 45061991Sheppo ASSERT(tx_tail != tx_head); 45071991Sheppo } 45081991Sheppo 45091991Sheppo /* Set the start and stop bits */ 45101991Sheppo ldcmsg->env |= LDC_FRAG_STOP; 45111991Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + start); 45121991Sheppo ldcmsg->env |= LDC_FRAG_START; 45131991Sheppo 45141991Sheppo /* 45151991Sheppo * All packets have been copied into the TX queue 45161991Sheppo * update the tail ptr in the HV 45171991Sheppo */ 45181991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 45191991Sheppo if (rv == 0) { 45201991Sheppo ldcp->tx_tail = tx_tail; 45211991Sheppo ldcp->last_msg_snt = curr_seqid; 45221991Sheppo *size = bytes_written; 45231991Sheppo } else { 45241991Sheppo int rv2; 45251991Sheppo 45261991Sheppo if (rv != EWOULDBLOCK) { 45271991Sheppo *size = 0; 45282336Snarayan if (mutex_tryenter(&ldcp->lock)) { 45292793Slm66018 i_ldc_reset(ldcp, B_FALSE); 45302336Snarayan mutex_exit(&ldcp->lock); 45312336Snarayan } else { 45322336Snarayan /* 45332336Snarayan * Release Tx lock, and then reacquire channel 45342336Snarayan * and Tx lock in correct order 45352336Snarayan */ 45362336Snarayan mutex_exit(&ldcp->tx_lock); 45372336Snarayan mutex_enter(&ldcp->lock); 45382336Snarayan mutex_enter(&ldcp->tx_lock); 45392793Slm66018 i_ldc_reset(ldcp, B_FALSE); 45402336Snarayan mutex_exit(&ldcp->lock); 45412336Snarayan } 45421991Sheppo return (ECONNRESET); 45431991Sheppo } 45441991Sheppo 45453010Slm66018 D1(ldcp->id, "hv_tx_set_tail returns 0x%x (head 0x%x, " 45464690Snarayan "old tail 0x%x, new tail 0x%x, qsize=0x%x)\n", 45474690Snarayan rv, ldcp->tx_head, ldcp->tx_tail, tx_tail, 45484690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT)); 45491991Sheppo 45501991Sheppo rv2 = hv_ldc_tx_get_state(ldcp->id, 45511991Sheppo &tx_head, &tx_tail, &ldcp->link_state); 45521991Sheppo 45533010Slm66018 D1(ldcp->id, "hv_ldc_tx_get_state returns 0x%x " 45544690Snarayan "(head 0x%x, tail 0x%x state 0x%x)\n", 45554690Snarayan rv2, tx_head, tx_tail, ldcp->link_state); 45561991Sheppo 45571991Sheppo *size = 0; 45581991Sheppo } 45591991Sheppo 45601991Sheppo D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, *size); 45611991Sheppo 45621991Sheppo return (rv); 45631991Sheppo } 45641991Sheppo 45651991Sheppo /* 45661991Sheppo * Write specified amount of bytes to the channel 45671991Sheppo * in multiple pkts of pkt_payload size. Each 45681991Sheppo * packet is tagged with an unique packet ID in 45692410Slm66018 * the case of a reliable link. 45701991Sheppo * 45711991Sheppo * On return, size contains the number of bytes written. 45721991Sheppo * This function needs to ensure that the write size is < MTU size 45731991Sheppo */ 45741991Sheppo static int 45751991Sheppo i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep) 45761991Sheppo { 45772336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 45786408Sha137994 ASSERT(ldcp->mode == LDC_MODE_RELIABLE); 45791991Sheppo 45801991Sheppo /* Truncate packet to max of MTU size */ 45811991Sheppo if (*sizep > ldcp->mtu) *sizep = ldcp->mtu; 45821991Sheppo return (i_ldc_write_packet(ldcp, buf, sizep)); 45831991Sheppo } 45841991Sheppo 45851991Sheppo 45861991Sheppo /* 45871991Sheppo * Interfaces for channel nexus to register/unregister with LDC module 45881991Sheppo * The nexus will register functions to be used to register individual 45891991Sheppo * channels with the nexus and enable interrupts for the channels 45901991Sheppo */ 45911991Sheppo int 45921991Sheppo ldc_register(ldc_cnex_t *cinfo) 45931991Sheppo { 45941991Sheppo ldc_chan_t *ldcp; 45951991Sheppo 45961991Sheppo if (cinfo == NULL || cinfo->dip == NULL || 45971991Sheppo cinfo->reg_chan == NULL || cinfo->unreg_chan == NULL || 45981991Sheppo cinfo->add_intr == NULL || cinfo->rem_intr == NULL || 45991991Sheppo cinfo->clr_intr == NULL) { 46001991Sheppo 46011991Sheppo DWARN(DBG_ALL_LDCS, "ldc_register: invalid nexus info\n"); 46021991Sheppo return (EINVAL); 46031991Sheppo } 46041991Sheppo 46051991Sheppo mutex_enter(&ldcssp->lock); 46061991Sheppo 46071991Sheppo /* nexus registration */ 46081991Sheppo ldcssp->cinfo.dip = cinfo->dip; 46091991Sheppo ldcssp->cinfo.reg_chan = cinfo->reg_chan; 46101991Sheppo ldcssp->cinfo.unreg_chan = cinfo->unreg_chan; 46111991Sheppo ldcssp->cinfo.add_intr = cinfo->add_intr; 46121991Sheppo ldcssp->cinfo.rem_intr = cinfo->rem_intr; 46131991Sheppo ldcssp->cinfo.clr_intr = cinfo->clr_intr; 46141991Sheppo 46151991Sheppo /* register any channels that might have been previously initialized */ 46161991Sheppo ldcp = ldcssp->chan_list; 46171991Sheppo while (ldcp) { 46181991Sheppo if ((ldcp->tstate & TS_QCONF_RDY) && 46191991Sheppo (ldcp->tstate & TS_CNEX_RDY) == 0) 46201991Sheppo (void) i_ldc_register_channel(ldcp); 46211991Sheppo 46221991Sheppo ldcp = ldcp->next; 46231991Sheppo } 46241991Sheppo 46251991Sheppo mutex_exit(&ldcssp->lock); 46261991Sheppo 46271991Sheppo return (0); 46281991Sheppo } 46291991Sheppo 46301991Sheppo int 46311991Sheppo ldc_unregister(ldc_cnex_t *cinfo) 46321991Sheppo { 46331991Sheppo if (cinfo == NULL || cinfo->dip == NULL) { 46341991Sheppo DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid nexus info\n"); 46351991Sheppo return (EINVAL); 46361991Sheppo } 46371991Sheppo 46381991Sheppo mutex_enter(&ldcssp->lock); 46391991Sheppo 46401991Sheppo if (cinfo->dip != ldcssp->cinfo.dip) { 46411991Sheppo DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid dip\n"); 46421991Sheppo mutex_exit(&ldcssp->lock); 46431991Sheppo return (EINVAL); 46441991Sheppo } 46451991Sheppo 46461991Sheppo /* nexus unregister */ 46471991Sheppo ldcssp->cinfo.dip = NULL; 46481991Sheppo ldcssp->cinfo.reg_chan = NULL; 46491991Sheppo ldcssp->cinfo.unreg_chan = NULL; 46501991Sheppo ldcssp->cinfo.add_intr = NULL; 46511991Sheppo ldcssp->cinfo.rem_intr = NULL; 46521991Sheppo ldcssp->cinfo.clr_intr = NULL; 46531991Sheppo 46541991Sheppo mutex_exit(&ldcssp->lock); 46551991Sheppo 46561991Sheppo return (0); 46571991Sheppo } 4658