11ae08745Sheppo /* 21ae08745Sheppo * CDDL HEADER START 31ae08745Sheppo * 41ae08745Sheppo * The contents of this file are subject to the terms of the 51ae08745Sheppo * Common Development and Distribution License (the "License"). 61ae08745Sheppo * You may not use this file except in compliance with the License. 71ae08745Sheppo * 81ae08745Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91ae08745Sheppo * or http://www.opensolaris.org/os/licensing. 101ae08745Sheppo * See the License for the specific language governing permissions 111ae08745Sheppo * and limitations under the License. 121ae08745Sheppo * 131ae08745Sheppo * When distributing Covered Code, include this CDDL HEADER in each 141ae08745Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151ae08745Sheppo * If applicable, add the following below this CDDL HEADER, with the 161ae08745Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 171ae08745Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 181ae08745Sheppo * 191ae08745Sheppo * CDDL HEADER END 201ae08745Sheppo */ 211ae08745Sheppo 221ae08745Sheppo /* 23*7bd3a2e2SSriharsha Basavapatna * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 241ae08745Sheppo * Use is subject to license terms. 251ae08745Sheppo */ 261ae08745Sheppo 271ae08745Sheppo /* 28e1ebb9ecSlm66018 * sun4v LDC Link Layer 291ae08745Sheppo */ 301ae08745Sheppo #include <sys/types.h> 311ae08745Sheppo #include <sys/file.h> 321ae08745Sheppo #include <sys/errno.h> 331ae08745Sheppo #include <sys/open.h> 341ae08745Sheppo #include <sys/cred.h> 351ae08745Sheppo #include <sys/kmem.h> 361ae08745Sheppo #include <sys/conf.h> 371ae08745Sheppo #include <sys/cmn_err.h> 381ae08745Sheppo #include <sys/ksynch.h> 391ae08745Sheppo #include <sys/modctl.h> 401ae08745Sheppo #include <sys/stat.h> /* needed for S_IFBLK and S_IFCHR */ 411ae08745Sheppo #include <sys/debug.h> 421ae08745Sheppo #include <sys/cred.h> 431ae08745Sheppo #include <sys/promif.h> 441ae08745Sheppo #include <sys/ddi.h> 451ae08745Sheppo #include <sys/sunddi.h> 461ae08745Sheppo #include <sys/cyclic.h> 471ae08745Sheppo #include <sys/machsystm.h> 481ae08745Sheppo #include <sys/vm.h> 491ae08745Sheppo #include <sys/cpu.h> 501ae08745Sheppo #include <sys/intreg.h> 511ae08745Sheppo #include <sys/machcpuvar.h> 524bac2208Snarayan #include <sys/mmu.h> 534bac2208Snarayan #include <sys/pte.h> 544bac2208Snarayan #include <vm/hat.h> 554bac2208Snarayan #include <vm/as.h> 564bac2208Snarayan #include <vm/hat_sfmmu.h> 574bac2208Snarayan #include <sys/vm_machparam.h> 584bac2208Snarayan #include <vm/seg_kmem.h> 594bac2208Snarayan #include <vm/seg_kpm.h> 601ae08745Sheppo #include <sys/note.h> 611ae08745Sheppo #include <sys/ivintr.h> 621ae08745Sheppo #include <sys/hypervisor_api.h> 631ae08745Sheppo #include <sys/ldc.h> 641ae08745Sheppo #include <sys/ldc_impl.h> 651ae08745Sheppo #include <sys/cnex.h> 661ae08745Sheppo #include <sys/hsvc.h> 6758283286Sha137994 #include <sys/sdt.h> 685699897cSHaik Aftandilian #include <sys/kldc.h> 691ae08745Sheppo 701ae08745Sheppo /* Core internal functions */ 7120ae46ebSha137994 int i_ldc_h2v_error(int h_error); 7220ae46ebSha137994 void i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset); 7320ae46ebSha137994 741ae08745Sheppo static int i_ldc_txq_reconf(ldc_chan_t *ldcp); 753af08d82Slm66018 static int i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset); 76305dbad4SKevin Crowe static void i_ldc_rxq_drain(ldc_chan_t *ldcp); 771ae08745Sheppo static void i_ldc_reset_state(ldc_chan_t *ldcp); 785699897cSHaik Aftandilian static void i_ldc_debug_enter(void); 791ae08745Sheppo 801ae08745Sheppo static int i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail); 8122f747efSnarayan static void i_ldc_get_tx_head(ldc_chan_t *ldcp, uint64_t *head); 821ae08745Sheppo static int i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail); 831ae08745Sheppo static int i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head); 841ae08745Sheppo static int i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype, 851ae08745Sheppo uint8_t ctrlmsg); 861ae08745Sheppo 8758283286Sha137994 static int i_ldc_set_rxdq_head(ldc_chan_t *ldcp, uint64_t head); 8858283286Sha137994 static void i_ldc_rxdq_copy(ldc_chan_t *ldcp, uint64_t *head); 8958283286Sha137994 static uint64_t i_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, 9058283286Sha137994 uint64_t *tail, uint64_t *link_state); 9158283286Sha137994 static uint64_t i_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, 9258283286Sha137994 uint64_t *tail, uint64_t *link_state); 9358283286Sha137994 static int i_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head, 9458283286Sha137994 uint64_t rx_tail); 9558283286Sha137994 static uint_t i_ldc_chkq(ldc_chan_t *ldcp); 9658283286Sha137994 971ae08745Sheppo /* Interrupt handling functions */ 981ae08745Sheppo static uint_t i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2); 991ae08745Sheppo static uint_t i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2); 10058283286Sha137994 static uint_t i_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client, 10158283286Sha137994 uint64_t *notify_event); 1021ae08745Sheppo static void i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype); 1031ae08745Sheppo 1041ae08745Sheppo /* Read method functions */ 1051ae08745Sheppo static int i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep); 1061ae08745Sheppo static int i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp, 1071ae08745Sheppo size_t *sizep); 1081ae08745Sheppo static int i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp, 1091ae08745Sheppo size_t *sizep); 1101ae08745Sheppo 1111ae08745Sheppo /* Write method functions */ 1121ae08745Sheppo static int i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t target_bufp, 1131ae08745Sheppo size_t *sizep); 1141ae08745Sheppo static int i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t target_bufp, 1151ae08745Sheppo size_t *sizep); 1161ae08745Sheppo static int i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t target_bufp, 1171ae08745Sheppo size_t *sizep); 1181ae08745Sheppo 1191ae08745Sheppo /* Pkt processing internal functions */ 1201ae08745Sheppo static int i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg); 1211ae08745Sheppo static int i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg); 1221ae08745Sheppo static int i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg); 1231ae08745Sheppo static int i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg); 1241ae08745Sheppo static int i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg); 1251ae08745Sheppo static int i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg); 1261ae08745Sheppo static int i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg); 1271ae08745Sheppo 1281ae08745Sheppo /* LDC Version */ 1291ae08745Sheppo static ldc_ver_t ldc_versions[] = { {1, 0} }; 1301ae08745Sheppo 1311ae08745Sheppo /* number of supported versions */ 1321ae08745Sheppo #define LDC_NUM_VERS (sizeof (ldc_versions) / sizeof (ldc_versions[0])) 1331ae08745Sheppo 13458283286Sha137994 /* Invalid value for the ldc_chan_t rx_ack_head field */ 13558283286Sha137994 #define ACKPEEK_HEAD_INVALID ((uint64_t)-1) 13658283286Sha137994 13758283286Sha137994 1381ae08745Sheppo /* Module State Pointer */ 13920ae46ebSha137994 ldc_soft_state_t *ldcssp; 1401ae08745Sheppo 1411ae08745Sheppo static struct modldrv md = { 1421ae08745Sheppo &mod_miscops, /* This is a misc module */ 143f500b196SRichard Bean "sun4v LDC module", /* Name of the module */ 1441ae08745Sheppo }; 1451ae08745Sheppo 1461ae08745Sheppo static struct modlinkage ml = { 1471ae08745Sheppo MODREV_1, 1481ae08745Sheppo &md, 1491ae08745Sheppo NULL 1501ae08745Sheppo }; 1511ae08745Sheppo 1521ae08745Sheppo static uint64_t ldc_sup_minor; /* Supported minor number */ 1531ae08745Sheppo static hsvc_info_t ldc_hsvc = { 154bbfa0259Sha137994 HSVC_REV_1, NULL, HSVC_GROUP_LDC, 1, 1, "ldc" 1551ae08745Sheppo }; 1561ae08745Sheppo 1574bac2208Snarayan /* 158e1ebb9ecSlm66018 * The no. of MTU size messages that can be stored in 159e1ebb9ecSlm66018 * the LDC Tx queue. The number of Tx queue entries is 160e1ebb9ecSlm66018 * then computed as (mtu * mtu_msgs)/sizeof(queue_entry) 161e1ebb9ecSlm66018 */ 162e1ebb9ecSlm66018 uint64_t ldc_mtu_msgs = LDC_MTU_MSGS; 163e1ebb9ecSlm66018 164e1ebb9ecSlm66018 /* 165e1ebb9ecSlm66018 * The minimum queue length. This is the size of the smallest 166e1ebb9ecSlm66018 * LDC queue. If the computed value is less than this default, 167e1ebb9ecSlm66018 * the queue length is rounded up to 'ldc_queue_entries'. 168e1ebb9ecSlm66018 */ 169e1ebb9ecSlm66018 uint64_t ldc_queue_entries = LDC_QUEUE_ENTRIES; 170e1ebb9ecSlm66018 171e1ebb9ecSlm66018 /* 17258283286Sha137994 * The length of the reliable-mode data queue in terms of the LDC 17358283286Sha137994 * receive queue length. i.e., the number of times larger than the 17458283286Sha137994 * LDC receive queue that the data queue should be. The HV receive 17558283286Sha137994 * queue is required to be a power of 2 and this implementation 17658283286Sha137994 * assumes the data queue will also be a power of 2. By making the 17758283286Sha137994 * multiplier a power of 2, we ensure the data queue will be a 17858283286Sha137994 * power of 2. We use a multiplier because the receive queue is 17958283286Sha137994 * sized to be sane relative to the MTU and the same is needed for 18058283286Sha137994 * the data queue. 18158283286Sha137994 */ 18258283286Sha137994 uint64_t ldc_rxdq_multiplier = LDC_RXDQ_MULTIPLIER; 18358283286Sha137994 18458283286Sha137994 /* 185e1ebb9ecSlm66018 * LDC retry count and delay - when the HV returns EWOULDBLOCK 186e1ebb9ecSlm66018 * the operation is retried 'ldc_max_retries' times with a 187e1ebb9ecSlm66018 * wait of 'ldc_delay' usecs between each retry. 1880a55fbb7Slm66018 */ 1890a55fbb7Slm66018 int ldc_max_retries = LDC_MAX_RETRIES; 1900a55fbb7Slm66018 clock_t ldc_delay = LDC_DELAY; 1910a55fbb7Slm66018 1924d39be2bSsg70180 /* 1935699897cSHaik Aftandilian * Channels which have a devclass satisfying the following 1945699897cSHaik Aftandilian * will be reset when entering the prom or kmdb. 1955699897cSHaik Aftandilian * 1965699897cSHaik Aftandilian * LDC_DEVCLASS_PROM_RESET(devclass) != 0 1975699897cSHaik Aftandilian * 1985699897cSHaik Aftandilian * By default, only block device service channels are reset. 1995699897cSHaik Aftandilian */ 2005699897cSHaik Aftandilian #define LDC_DEVCLASS_BIT(dc) (0x1 << (dc)) 2015699897cSHaik Aftandilian #define LDC_DEVCLASS_PROM_RESET(dc) \ 2025699897cSHaik Aftandilian (LDC_DEVCLASS_BIT(dc) & ldc_debug_reset_mask) 203d16449dbSZach Kissel static uint64_t ldc_debug_reset_mask = LDC_DEVCLASS_BIT(LDC_DEV_BLK_SVC) | 204d16449dbSZach Kissel LDC_DEVCLASS_BIT(LDC_DEV_GENERIC); 2055699897cSHaik Aftandilian 2065699897cSHaik Aftandilian /* 2074d39be2bSsg70180 * delay between each retry of channel unregistration in 2084d39be2bSsg70180 * ldc_close(), to wait for pending interrupts to complete. 2094d39be2bSsg70180 */ 2104d39be2bSsg70180 clock_t ldc_close_delay = LDC_CLOSE_DELAY; 2114d39be2bSsg70180 2121ae08745Sheppo #ifdef DEBUG 2131ae08745Sheppo 2141ae08745Sheppo /* 2151ae08745Sheppo * Print debug messages 2161ae08745Sheppo * 2171ae08745Sheppo * set ldcdbg to 0x7 for enabling all msgs 2181ae08745Sheppo * 0x4 - Warnings 2191ae08745Sheppo * 0x2 - All debug messages 2201ae08745Sheppo * 0x1 - Minimal debug messages 2211ae08745Sheppo * 2221ae08745Sheppo * set ldcdbgchan to the channel number you want to debug 2231ae08745Sheppo * setting it to -1 prints debug messages for all channels 2241ae08745Sheppo * NOTE: ldcdbgchan has no effect on error messages 2251ae08745Sheppo */ 2261ae08745Sheppo 2271ae08745Sheppo int ldcdbg = 0x0; 2281ae08745Sheppo int64_t ldcdbgchan = DBG_ALL_LDCS; 22983d3bc6fSnarayan uint64_t ldc_inject_err_flag = 0; 2301ae08745Sheppo 23120ae46ebSha137994 void 2321ae08745Sheppo ldcdebug(int64_t id, const char *fmt, ...) 2331ae08745Sheppo { 2341ae08745Sheppo char buf[512]; 2351ae08745Sheppo va_list ap; 2361ae08745Sheppo 2371ae08745Sheppo /* 2381ae08745Sheppo * Do not return if, 2391ae08745Sheppo * caller wants to print it anyway - (id == DBG_ALL_LDCS) 2401ae08745Sheppo * debug channel is set to all LDCs - (ldcdbgchan == DBG_ALL_LDCS) 2411ae08745Sheppo * debug channel = caller specified channel 2421ae08745Sheppo */ 2431ae08745Sheppo if ((id != DBG_ALL_LDCS) && 2441ae08745Sheppo (ldcdbgchan != DBG_ALL_LDCS) && 2451ae08745Sheppo (ldcdbgchan != id)) { 2461ae08745Sheppo return; 2471ae08745Sheppo } 2481ae08745Sheppo 2491ae08745Sheppo va_start(ap, fmt); 2501ae08745Sheppo (void) vsprintf(buf, fmt, ap); 2511ae08745Sheppo va_end(ap); 2521ae08745Sheppo 2533af08d82Slm66018 cmn_err(CE_CONT, "?%s", buf); 2543af08d82Slm66018 } 2553af08d82Slm66018 25683d3bc6fSnarayan #define LDC_ERR_RESET 0x1 25783d3bc6fSnarayan #define LDC_ERR_PKTLOSS 0x2 25858283286Sha137994 #define LDC_ERR_DQFULL 0x4 259bbfa0259Sha137994 #define LDC_ERR_DRNGCLEAR 0x8 26083d3bc6fSnarayan 2613af08d82Slm66018 static boolean_t 26283d3bc6fSnarayan ldc_inject_error(ldc_chan_t *ldcp, uint64_t error) 2633af08d82Slm66018 { 2643af08d82Slm66018 if ((ldcdbgchan != DBG_ALL_LDCS) && (ldcdbgchan != ldcp->id)) 2653af08d82Slm66018 return (B_FALSE); 2663af08d82Slm66018 26783d3bc6fSnarayan if ((ldc_inject_err_flag & error) == 0) 2683af08d82Slm66018 return (B_FALSE); 2693af08d82Slm66018 2703af08d82Slm66018 /* clear the injection state */ 27183d3bc6fSnarayan ldc_inject_err_flag &= ~error; 2723af08d82Slm66018 2733af08d82Slm66018 return (B_TRUE); 2741ae08745Sheppo } 2751ae08745Sheppo 2761ae08745Sheppo #define D1 \ 2771ae08745Sheppo if (ldcdbg & 0x01) \ 2781ae08745Sheppo ldcdebug 2791ae08745Sheppo 2801ae08745Sheppo #define D2 \ 2811ae08745Sheppo if (ldcdbg & 0x02) \ 2821ae08745Sheppo ldcdebug 2831ae08745Sheppo 2841ae08745Sheppo #define DWARN \ 2851ae08745Sheppo if (ldcdbg & 0x04) \ 2861ae08745Sheppo ldcdebug 2871ae08745Sheppo 2881ae08745Sheppo #define DUMP_PAYLOAD(id, addr) \ 2891ae08745Sheppo { \ 2901ae08745Sheppo char buf[65*3]; \ 2911ae08745Sheppo int i; \ 2921ae08745Sheppo uint8_t *src = (uint8_t *)addr; \ 2931ae08745Sheppo for (i = 0; i < 64; i++, src++) \ 2941ae08745Sheppo (void) sprintf(&buf[i * 3], "|%02x", *src); \ 2951ae08745Sheppo (void) sprintf(&buf[i * 3], "|\n"); \ 2961ae08745Sheppo D2((id), "payload: %s", buf); \ 2971ae08745Sheppo } 2981ae08745Sheppo 2991ae08745Sheppo #define DUMP_LDC_PKT(c, s, addr) \ 3001ae08745Sheppo { \ 3011ae08745Sheppo ldc_msg_t *msg = (ldc_msg_t *)(addr); \ 3021ae08745Sheppo uint32_t mid = ((c)->mode != LDC_MODE_RAW) ? msg->seqid : 0; \ 3031ae08745Sheppo if (msg->type == LDC_DATA) { \ 3041ae08745Sheppo D2((c)->id, "%s: msg%d (/%x/%x/%x/,env[%c%c,sz=%d])", \ 3051ae08745Sheppo (s), mid, msg->type, msg->stype, msg->ctrl, \ 3061ae08745Sheppo (msg->env & LDC_FRAG_START) ? 'B' : ' ', \ 3071ae08745Sheppo (msg->env & LDC_FRAG_STOP) ? 'E' : ' ', \ 3081ae08745Sheppo (msg->env & LDC_LEN_MASK)); \ 3091ae08745Sheppo } else { \ 3101ae08745Sheppo D2((c)->id, "%s: msg%d (/%x/%x/%x/,env=%x)", (s), \ 3111ae08745Sheppo mid, msg->type, msg->stype, msg->ctrl, msg->env); \ 3121ae08745Sheppo } \ 3131ae08745Sheppo } 3141ae08745Sheppo 31583d3bc6fSnarayan #define LDC_INJECT_RESET(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_RESET) 31683d3bc6fSnarayan #define LDC_INJECT_PKTLOSS(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_PKTLOSS) 31758283286Sha137994 #define LDC_INJECT_DQFULL(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_DQFULL) 318bbfa0259Sha137994 #define LDC_INJECT_DRNGCLEAR(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_DRNGCLEAR) 319bbfa0259Sha137994 extern void i_ldc_mem_inject_dring_clear(ldc_chan_t *ldcp); 3203af08d82Slm66018 3211ae08745Sheppo #else 3221ae08745Sheppo 3231ae08745Sheppo #define DBG_ALL_LDCS -1 3241ae08745Sheppo 3251ae08745Sheppo #define D1 3261ae08745Sheppo #define D2 3271ae08745Sheppo #define DWARN 3281ae08745Sheppo 3291ae08745Sheppo #define DUMP_PAYLOAD(id, addr) 3301ae08745Sheppo #define DUMP_LDC_PKT(c, s, addr) 3311ae08745Sheppo 3323af08d82Slm66018 #define LDC_INJECT_RESET(_ldcp) (B_FALSE) 33383d3bc6fSnarayan #define LDC_INJECT_PKTLOSS(_ldcp) (B_FALSE) 33458283286Sha137994 #define LDC_INJECT_DQFULL(_ldcp) (B_FALSE) 335bbfa0259Sha137994 #define LDC_INJECT_DRNGCLEAR(_ldcp) (B_FALSE) 3363af08d82Slm66018 3371ae08745Sheppo #endif 3381ae08745Sheppo 33958283286Sha137994 /* 34058283286Sha137994 * dtrace SDT probes to ease tracing of the rx data queue and HV queue 34158283286Sha137994 * lengths. Just pass the head, tail, and entries values so that the 34258283286Sha137994 * length can be calculated in a dtrace script when the probe is enabled. 34358283286Sha137994 */ 34458283286Sha137994 #define TRACE_RXDQ_LENGTH(ldcp) \ 34558283286Sha137994 DTRACE_PROBE4(rxdq__size, \ 34658283286Sha137994 uint64_t, ldcp->id, \ 34758283286Sha137994 uint64_t, ldcp->rx_dq_head, \ 34858283286Sha137994 uint64_t, ldcp->rx_dq_tail, \ 34958283286Sha137994 uint64_t, ldcp->rx_dq_entries) 35058283286Sha137994 35158283286Sha137994 #define TRACE_RXHVQ_LENGTH(ldcp, head, tail) \ 35258283286Sha137994 DTRACE_PROBE4(rxhvq__size, \ 35358283286Sha137994 uint64_t, ldcp->id, \ 35458283286Sha137994 uint64_t, head, \ 35558283286Sha137994 uint64_t, tail, \ 35658283286Sha137994 uint64_t, ldcp->rx_q_entries) 35758283286Sha137994 35858283286Sha137994 /* A dtrace SDT probe to ease tracing of data queue copy operations */ 35958283286Sha137994 #define TRACE_RXDQ_COPY(ldcp, bytes) \ 36058283286Sha137994 DTRACE_PROBE2(rxdq__copy, uint64_t, ldcp->id, uint64_t, bytes) \ 36158283286Sha137994 36258283286Sha137994 /* The amount of contiguous space at the tail of the queue */ 36358283286Sha137994 #define Q_CONTIG_SPACE(head, tail, size) \ 36458283286Sha137994 ((head) <= (tail) ? ((size) - (tail)) : \ 36558283286Sha137994 ((head) - (tail) - LDC_PACKET_SIZE)) 36658283286Sha137994 3671ae08745Sheppo #define ZERO_PKT(p) \ 3681ae08745Sheppo bzero((p), sizeof (ldc_msg_t)); 3691ae08745Sheppo 3701ae08745Sheppo #define IDX2COOKIE(idx, pg_szc, pg_shift) \ 3711ae08745Sheppo (((pg_szc) << LDC_COOKIE_PGSZC_SHIFT) | ((idx) << (pg_shift))) 3721ae08745Sheppo 3731ae08745Sheppo int 3741ae08745Sheppo _init(void) 3751ae08745Sheppo { 3761ae08745Sheppo int status; 377bbfa0259Sha137994 extern void i_ldc_mem_set_hsvc_vers(uint64_t major, uint64_t minor); 3781ae08745Sheppo 3791ae08745Sheppo status = hsvc_register(&ldc_hsvc, &ldc_sup_minor); 3801ae08745Sheppo if (status != 0) { 381d66f8315Sjb145095 cmn_err(CE_NOTE, "!%s: cannot negotiate hypervisor LDC services" 3821ae08745Sheppo " group: 0x%lx major: %ld minor: %ld errno: %d", 3831ae08745Sheppo ldc_hsvc.hsvc_modname, ldc_hsvc.hsvc_group, 3841ae08745Sheppo ldc_hsvc.hsvc_major, ldc_hsvc.hsvc_minor, status); 3851ae08745Sheppo return (-1); 3861ae08745Sheppo } 3871ae08745Sheppo 388bbfa0259Sha137994 /* Initialize shared memory HV API version checking */ 389bbfa0259Sha137994 i_ldc_mem_set_hsvc_vers(ldc_hsvc.hsvc_major, ldc_sup_minor); 390bbfa0259Sha137994 3911ae08745Sheppo /* allocate soft state structure */ 3921ae08745Sheppo ldcssp = kmem_zalloc(sizeof (ldc_soft_state_t), KM_SLEEP); 3931ae08745Sheppo 3941ae08745Sheppo /* Link the module into the system */ 3951ae08745Sheppo status = mod_install(&ml); 3961ae08745Sheppo if (status != 0) { 3971ae08745Sheppo kmem_free(ldcssp, sizeof (ldc_soft_state_t)); 3981ae08745Sheppo return (status); 3991ae08745Sheppo } 4001ae08745Sheppo 4011ae08745Sheppo /* Initialize the LDC state structure */ 4021ae08745Sheppo mutex_init(&ldcssp->lock, NULL, MUTEX_DRIVER, NULL); 4031ae08745Sheppo 4041ae08745Sheppo mutex_enter(&ldcssp->lock); 4051ae08745Sheppo 4064bac2208Snarayan /* Create a cache for memory handles */ 4074bac2208Snarayan ldcssp->memhdl_cache = kmem_cache_create("ldc_memhdl_cache", 4084bac2208Snarayan sizeof (ldc_mhdl_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 4094bac2208Snarayan if (ldcssp->memhdl_cache == NULL) { 4104bac2208Snarayan DWARN(DBG_ALL_LDCS, "_init: ldc_memhdl cache create failed\n"); 4114bac2208Snarayan mutex_exit(&ldcssp->lock); 4124bac2208Snarayan return (-1); 4134bac2208Snarayan } 4144bac2208Snarayan 4154bac2208Snarayan /* Create cache for memory segment structures */ 4164bac2208Snarayan ldcssp->memseg_cache = kmem_cache_create("ldc_memseg_cache", 4174bac2208Snarayan sizeof (ldc_memseg_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 4184bac2208Snarayan if (ldcssp->memseg_cache == NULL) { 4194bac2208Snarayan DWARN(DBG_ALL_LDCS, "_init: ldc_memseg cache create failed\n"); 4204bac2208Snarayan mutex_exit(&ldcssp->lock); 4214bac2208Snarayan return (-1); 4224bac2208Snarayan } 4234bac2208Snarayan 4244bac2208Snarayan 4251ae08745Sheppo ldcssp->channel_count = 0; 4261ae08745Sheppo ldcssp->channels_open = 0; 4271ae08745Sheppo ldcssp->chan_list = NULL; 4281ae08745Sheppo ldcssp->dring_list = NULL; 4291ae08745Sheppo 4305699897cSHaik Aftandilian /* Register debug_enter callback */ 4315699897cSHaik Aftandilian kldc_set_debug_cb(&i_ldc_debug_enter); 4325699897cSHaik Aftandilian 4331ae08745Sheppo mutex_exit(&ldcssp->lock); 4341ae08745Sheppo 4351ae08745Sheppo return (0); 4361ae08745Sheppo } 4371ae08745Sheppo 4381ae08745Sheppo int 4391ae08745Sheppo _info(struct modinfo *modinfop) 4401ae08745Sheppo { 4411ae08745Sheppo /* Report status of the dynamically loadable driver module */ 4421ae08745Sheppo return (mod_info(&ml, modinfop)); 4431ae08745Sheppo } 4441ae08745Sheppo 4451ae08745Sheppo int 4461ae08745Sheppo _fini(void) 4471ae08745Sheppo { 4481ae08745Sheppo int rv, status; 44922f747efSnarayan ldc_chan_t *tmp_ldcp, *ldcp; 45022f747efSnarayan ldc_dring_t *tmp_dringp, *dringp; 4511ae08745Sheppo ldc_mem_info_t minfo; 4521ae08745Sheppo 4531ae08745Sheppo /* Unlink the driver module from the system */ 4541ae08745Sheppo status = mod_remove(&ml); 4551ae08745Sheppo if (status) { 4561ae08745Sheppo DWARN(DBG_ALL_LDCS, "_fini: mod_remove failed\n"); 4571ae08745Sheppo return (EIO); 4581ae08745Sheppo } 4591ae08745Sheppo 4605699897cSHaik Aftandilian /* Unregister debug_enter callback */ 4615699897cSHaik Aftandilian kldc_set_debug_cb(NULL); 4625699897cSHaik Aftandilian 4631ae08745Sheppo /* Free descriptor rings */ 4641ae08745Sheppo dringp = ldcssp->dring_list; 4651ae08745Sheppo while (dringp != NULL) { 46622f747efSnarayan tmp_dringp = dringp->next; 4671ae08745Sheppo 4681ae08745Sheppo rv = ldc_mem_dring_info((ldc_dring_handle_t)dringp, &minfo); 4691ae08745Sheppo if (rv == 0 && minfo.status != LDC_UNBOUND) { 4701ae08745Sheppo if (minfo.status == LDC_BOUND) { 4711ae08745Sheppo (void) ldc_mem_dring_unbind( 4721ae08745Sheppo (ldc_dring_handle_t)dringp); 4731ae08745Sheppo } 4741ae08745Sheppo if (minfo.status == LDC_MAPPED) { 4751ae08745Sheppo (void) ldc_mem_dring_unmap( 4761ae08745Sheppo (ldc_dring_handle_t)dringp); 4771ae08745Sheppo } 4781ae08745Sheppo } 4791ae08745Sheppo 4801ae08745Sheppo (void) ldc_mem_dring_destroy((ldc_dring_handle_t)dringp); 48122f747efSnarayan dringp = tmp_dringp; 4821ae08745Sheppo } 4831ae08745Sheppo ldcssp->dring_list = NULL; 4841ae08745Sheppo 48522f747efSnarayan /* close and finalize channels */ 48622f747efSnarayan ldcp = ldcssp->chan_list; 48722f747efSnarayan while (ldcp != NULL) { 48822f747efSnarayan tmp_ldcp = ldcp->next; 48922f747efSnarayan 49022f747efSnarayan (void) ldc_close((ldc_handle_t)ldcp); 49122f747efSnarayan (void) ldc_fini((ldc_handle_t)ldcp); 49222f747efSnarayan 49322f747efSnarayan ldcp = tmp_ldcp; 49422f747efSnarayan } 49522f747efSnarayan ldcssp->chan_list = NULL; 49622f747efSnarayan 4974bac2208Snarayan /* Destroy kmem caches */ 4984bac2208Snarayan kmem_cache_destroy(ldcssp->memhdl_cache); 4994bac2208Snarayan kmem_cache_destroy(ldcssp->memseg_cache); 5004bac2208Snarayan 5011ae08745Sheppo /* 5021ae08745Sheppo * We have successfully "removed" the driver. 5031ae08745Sheppo * Destroying soft states 5041ae08745Sheppo */ 5051ae08745Sheppo mutex_destroy(&ldcssp->lock); 5061ae08745Sheppo kmem_free(ldcssp, sizeof (ldc_soft_state_t)); 5071ae08745Sheppo 5081ae08745Sheppo (void) hsvc_unregister(&ldc_hsvc); 5091ae08745Sheppo 5101ae08745Sheppo return (status); 5111ae08745Sheppo } 5121ae08745Sheppo 5131ae08745Sheppo /* -------------------------------------------------------------------------- */ 5141ae08745Sheppo 5151ae08745Sheppo /* 516e1ebb9ecSlm66018 * LDC Link Layer Internal Functions 5171ae08745Sheppo */ 5181ae08745Sheppo 5191ae08745Sheppo /* 5201ae08745Sheppo * Translate HV Errors to sun4v error codes 5211ae08745Sheppo */ 52220ae46ebSha137994 int 5231ae08745Sheppo i_ldc_h2v_error(int h_error) 5241ae08745Sheppo { 5251ae08745Sheppo switch (h_error) { 5261ae08745Sheppo 5271ae08745Sheppo case H_EOK: 5281ae08745Sheppo return (0); 5291ae08745Sheppo 5301ae08745Sheppo case H_ENORADDR: 5311ae08745Sheppo return (EFAULT); 5321ae08745Sheppo 5331ae08745Sheppo case H_EBADPGSZ: 5341ae08745Sheppo case H_EINVAL: 5351ae08745Sheppo return (EINVAL); 5361ae08745Sheppo 5371ae08745Sheppo case H_EWOULDBLOCK: 5381ae08745Sheppo return (EWOULDBLOCK); 5391ae08745Sheppo 5401ae08745Sheppo case H_ENOACCESS: 5411ae08745Sheppo case H_ENOMAP: 5421ae08745Sheppo return (EACCES); 5431ae08745Sheppo 5441ae08745Sheppo case H_EIO: 5451ae08745Sheppo case H_ECPUERROR: 5461ae08745Sheppo return (EIO); 5471ae08745Sheppo 5481ae08745Sheppo case H_ENOTSUPPORTED: 5491ae08745Sheppo return (ENOTSUP); 5501ae08745Sheppo 5511ae08745Sheppo case H_ETOOMANY: 5521ae08745Sheppo return (ENOSPC); 5531ae08745Sheppo 5541ae08745Sheppo case H_ECHANNEL: 5551ae08745Sheppo return (ECHRNG); 5561ae08745Sheppo default: 5571ae08745Sheppo break; 5581ae08745Sheppo } 5591ae08745Sheppo 5601ae08745Sheppo return (EIO); 5611ae08745Sheppo } 5621ae08745Sheppo 5631ae08745Sheppo /* 5641ae08745Sheppo * Reconfigure the transmit queue 5651ae08745Sheppo */ 5661ae08745Sheppo static int 5671ae08745Sheppo i_ldc_txq_reconf(ldc_chan_t *ldcp) 5681ae08745Sheppo { 5691ae08745Sheppo int rv; 5701ae08745Sheppo 5711ae08745Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 572d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 573d10e4ef2Snarayan 5741ae08745Sheppo rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries); 5751ae08745Sheppo if (rv) { 5761ae08745Sheppo cmn_err(CE_WARN, 5773af08d82Slm66018 "i_ldc_txq_reconf: (0x%lx) cannot set qconf", ldcp->id); 5781ae08745Sheppo return (EIO); 5791ae08745Sheppo } 5801ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id, &(ldcp->tx_head), 5811ae08745Sheppo &(ldcp->tx_tail), &(ldcp->link_state)); 5821ae08745Sheppo if (rv) { 5831ae08745Sheppo cmn_err(CE_WARN, 5843af08d82Slm66018 "i_ldc_txq_reconf: (0x%lx) cannot get qptrs", ldcp->id); 5851ae08745Sheppo return (EIO); 5861ae08745Sheppo } 5873af08d82Slm66018 D1(ldcp->id, "i_ldc_txq_reconf: (0x%llx) h=0x%llx,t=0x%llx," 5881ae08745Sheppo "s=0x%llx\n", ldcp->id, ldcp->tx_head, ldcp->tx_tail, 5891ae08745Sheppo ldcp->link_state); 5901ae08745Sheppo 5911ae08745Sheppo return (0); 5921ae08745Sheppo } 5931ae08745Sheppo 5941ae08745Sheppo /* 5951ae08745Sheppo * Reconfigure the receive queue 5961ae08745Sheppo */ 5971ae08745Sheppo static int 5983af08d82Slm66018 i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset) 5991ae08745Sheppo { 6001ae08745Sheppo int rv; 6011ae08745Sheppo uint64_t rx_head, rx_tail; 6021ae08745Sheppo 6031ae08745Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 6041ae08745Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 6051ae08745Sheppo &(ldcp->link_state)); 6061ae08745Sheppo if (rv) { 6071ae08745Sheppo cmn_err(CE_WARN, 6083af08d82Slm66018 "i_ldc_rxq_reconf: (0x%lx) cannot get state", 6091ae08745Sheppo ldcp->id); 6101ae08745Sheppo return (EIO); 6111ae08745Sheppo } 6121ae08745Sheppo 6133af08d82Slm66018 if (force_reset || (ldcp->tstate & ~TS_IN_RESET) == TS_UP) { 6141ae08745Sheppo rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra, 6151ae08745Sheppo ldcp->rx_q_entries); 6161ae08745Sheppo if (rv) { 6171ae08745Sheppo cmn_err(CE_WARN, 6183af08d82Slm66018 "i_ldc_rxq_reconf: (0x%lx) cannot set qconf", 6191ae08745Sheppo ldcp->id); 6201ae08745Sheppo return (EIO); 6211ae08745Sheppo } 6223af08d82Slm66018 D1(ldcp->id, "i_ldc_rxq_reconf: (0x%llx) completed q reconf", 6231ae08745Sheppo ldcp->id); 6241ae08745Sheppo } 6251ae08745Sheppo 6261ae08745Sheppo return (0); 6271ae08745Sheppo } 6281ae08745Sheppo 629a8ea4edeSnarayan 630a8ea4edeSnarayan /* 631a8ea4edeSnarayan * Drain the contents of the receive queue 632a8ea4edeSnarayan */ 633305dbad4SKevin Crowe static void 634a8ea4edeSnarayan i_ldc_rxq_drain(ldc_chan_t *ldcp) 635a8ea4edeSnarayan { 636a8ea4edeSnarayan int rv; 637a8ea4edeSnarayan uint64_t rx_head, rx_tail; 638305dbad4SKevin Crowe int retries = 0; 639a8ea4edeSnarayan 640a8ea4edeSnarayan ASSERT(MUTEX_HELD(&ldcp->lock)); 641a8ea4edeSnarayan rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 642a8ea4edeSnarayan &(ldcp->link_state)); 643a8ea4edeSnarayan if (rv) { 644305dbad4SKevin Crowe cmn_err(CE_WARN, "i_ldc_rxq_drain: (0x%lx) cannot get state, " 645305dbad4SKevin Crowe "rv = 0x%x", ldcp->id, rv); 646305dbad4SKevin Crowe return; 647a8ea4edeSnarayan } 648a8ea4edeSnarayan 64932225099SZach Kissel /* If the queue is already empty just return success. */ 65032225099SZach Kissel if (rx_head == rx_tail) 651305dbad4SKevin Crowe return; 65232225099SZach Kissel 653305dbad4SKevin Crowe /* 654305dbad4SKevin Crowe * We are draining the queue in order to close the channel. 655305dbad4SKevin Crowe * Call hv_ldc_rx_set_qhead directly instead of i_ldc_set_rx_head 656305dbad4SKevin Crowe * because we do not need to reset the channel if the set 657305dbad4SKevin Crowe * qhead fails. 658305dbad4SKevin Crowe */ 659305dbad4SKevin Crowe if ((rv = hv_ldc_rx_set_qhead(ldcp->id, rx_tail)) == 0) 660305dbad4SKevin Crowe return; 661305dbad4SKevin Crowe 662305dbad4SKevin Crowe while ((rv == H_EWOULDBLOCK) && (retries++ < ldc_max_retries)) { 663305dbad4SKevin Crowe drv_usecwait(ldc_delay); 664305dbad4SKevin Crowe if ((rv = hv_ldc_rx_set_qhead(ldcp->id, rx_tail)) == 0) 665305dbad4SKevin Crowe return; 666305dbad4SKevin Crowe } 667305dbad4SKevin Crowe 668305dbad4SKevin Crowe cmn_err(CE_WARN, "i_ldc_rxq_drain: (0x%lx) cannot set qhead 0x%lx, " 669305dbad4SKevin Crowe "rv = 0x%x", ldcp->id, rx_tail, rv); 670a8ea4edeSnarayan } 671a8ea4edeSnarayan 672a8ea4edeSnarayan 6731ae08745Sheppo /* 6741ae08745Sheppo * Reset LDC state structure and its contents 6751ae08745Sheppo */ 6761ae08745Sheppo static void 6771ae08745Sheppo i_ldc_reset_state(ldc_chan_t *ldcp) 6781ae08745Sheppo { 6791ae08745Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 6801ae08745Sheppo ldcp->last_msg_snt = LDC_INIT_SEQID; 6811ae08745Sheppo ldcp->last_ack_rcd = 0; 6821ae08745Sheppo ldcp->last_msg_rcd = 0; 6831ae08745Sheppo ldcp->tx_ackd_head = ldcp->tx_head; 68458283286Sha137994 ldcp->stream_remains = 0; 6851ae08745Sheppo ldcp->next_vidx = 0; 6861ae08745Sheppo ldcp->hstate = 0; 6871ae08745Sheppo ldcp->tstate = TS_OPEN; 6881ae08745Sheppo ldcp->status = LDC_OPEN; 68958283286Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID; 69058283286Sha137994 ldcp->rx_dq_head = 0; 69158283286Sha137994 ldcp->rx_dq_tail = 0; 6921ae08745Sheppo 6931ae08745Sheppo if (ldcp->link_state == LDC_CHANNEL_UP || 6941ae08745Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 6951ae08745Sheppo 6961ae08745Sheppo if (ldcp->mode == LDC_MODE_RAW) { 6971ae08745Sheppo ldcp->status = LDC_UP; 6981ae08745Sheppo ldcp->tstate = TS_UP; 6991ae08745Sheppo } else { 7001ae08745Sheppo ldcp->status = LDC_READY; 7011ae08745Sheppo ldcp->tstate |= TS_LINK_READY; 7021ae08745Sheppo } 7031ae08745Sheppo } 7041ae08745Sheppo } 7051ae08745Sheppo 7061ae08745Sheppo /* 7071ae08745Sheppo * Reset a LDC channel 7081ae08745Sheppo */ 70920ae46ebSha137994 void 7103af08d82Slm66018 i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset) 7111ae08745Sheppo { 71283d3bc6fSnarayan DWARN(ldcp->id, "i_ldc_reset: (0x%llx) channel reset\n", ldcp->id); 7131ae08745Sheppo 714d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->lock)); 715d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 716d10e4ef2Snarayan 7173af08d82Slm66018 /* reconfig Tx and Rx queues */ 7181ae08745Sheppo (void) i_ldc_txq_reconf(ldcp); 7193af08d82Slm66018 (void) i_ldc_rxq_reconf(ldcp, force_reset); 7203af08d82Slm66018 7213af08d82Slm66018 /* Clear Tx and Rx interrupts */ 7223af08d82Slm66018 (void) i_ldc_clear_intr(ldcp, CNEX_TX_INTR); 7233af08d82Slm66018 (void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 7243af08d82Slm66018 7253af08d82Slm66018 /* Reset channel state */ 7261ae08745Sheppo i_ldc_reset_state(ldcp); 7273af08d82Slm66018 7283af08d82Slm66018 /* Mark channel in reset */ 7293af08d82Slm66018 ldcp->tstate |= TS_IN_RESET; 7301ae08745Sheppo } 7311ae08745Sheppo 7325699897cSHaik Aftandilian /* 7335699897cSHaik Aftandilian * Walk the channel list and reset channels if they are of the right 7345699897cSHaik Aftandilian * devclass and their Rx queues have been configured. No locks are 7355699897cSHaik Aftandilian * taken because the function is only invoked by the kernel just before 7365699897cSHaik Aftandilian * entering the prom or debugger when the system is single-threaded. 7375699897cSHaik Aftandilian */ 7385699897cSHaik Aftandilian static void 7395699897cSHaik Aftandilian i_ldc_debug_enter(void) 7405699897cSHaik Aftandilian { 7415699897cSHaik Aftandilian ldc_chan_t *ldcp; 7425699897cSHaik Aftandilian 7435699897cSHaik Aftandilian ldcp = ldcssp->chan_list; 7445699897cSHaik Aftandilian while (ldcp != NULL) { 7455699897cSHaik Aftandilian if (((ldcp->tstate & TS_QCONF_RDY) == TS_QCONF_RDY) && 7465699897cSHaik Aftandilian (LDC_DEVCLASS_PROM_RESET(ldcp->devclass) != 0)) { 7475699897cSHaik Aftandilian (void) hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra, 7485699897cSHaik Aftandilian ldcp->rx_q_entries); 7495699897cSHaik Aftandilian } 7505699897cSHaik Aftandilian ldcp = ldcp->next; 7515699897cSHaik Aftandilian } 7525699897cSHaik Aftandilian } 7534bac2208Snarayan 7541ae08745Sheppo /* 7551ae08745Sheppo * Clear pending interrupts 7561ae08745Sheppo */ 7571ae08745Sheppo static void 7581ae08745Sheppo i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype) 7591ae08745Sheppo { 7601ae08745Sheppo ldc_cnex_t *cinfo = &ldcssp->cinfo; 7611ae08745Sheppo 7621ae08745Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 7633af08d82Slm66018 ASSERT(cinfo->dip != NULL); 7644bac2208Snarayan 7653af08d82Slm66018 switch (itype) { 7663af08d82Slm66018 case CNEX_TX_INTR: 7674bac2208Snarayan /* check Tx interrupt */ 7683af08d82Slm66018 if (ldcp->tx_intr_state) 7693af08d82Slm66018 ldcp->tx_intr_state = LDC_INTR_NONE; 7704bac2208Snarayan else 7714bac2208Snarayan return; 7723af08d82Slm66018 break; 7733af08d82Slm66018 7743af08d82Slm66018 case CNEX_RX_INTR: 7754bac2208Snarayan /* check Rx interrupt */ 7763af08d82Slm66018 if (ldcp->rx_intr_state) 7773af08d82Slm66018 ldcp->rx_intr_state = LDC_INTR_NONE; 7784bac2208Snarayan else 7794bac2208Snarayan return; 7803af08d82Slm66018 break; 7814bac2208Snarayan } 7824bac2208Snarayan 7831ae08745Sheppo (void) cinfo->clr_intr(cinfo->dip, ldcp->id, itype); 7844bac2208Snarayan D2(ldcp->id, 7854bac2208Snarayan "i_ldc_clear_intr: (0x%llx) cleared 0x%x intr\n", 7864bac2208Snarayan ldcp->id, itype); 7871ae08745Sheppo } 7881ae08745Sheppo 7891ae08745Sheppo /* 7901ae08745Sheppo * Set the receive queue head 7910a55fbb7Slm66018 * Resets connection and returns an error if it fails. 7921ae08745Sheppo */ 7931ae08745Sheppo static int 7941ae08745Sheppo i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head) 7951ae08745Sheppo { 7961ae08745Sheppo int rv; 7970a55fbb7Slm66018 int retries; 7981ae08745Sheppo 7991ae08745Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 8000a55fbb7Slm66018 for (retries = 0; retries < ldc_max_retries; retries++) { 8010a55fbb7Slm66018 8020a55fbb7Slm66018 if ((rv = hv_ldc_rx_set_qhead(ldcp->id, head)) == 0) 8030a55fbb7Slm66018 return (0); 8040a55fbb7Slm66018 8050a55fbb7Slm66018 if (rv != H_EWOULDBLOCK) 8060a55fbb7Slm66018 break; 8070a55fbb7Slm66018 8080a55fbb7Slm66018 /* wait for ldc_delay usecs */ 8090a55fbb7Slm66018 drv_usecwait(ldc_delay); 8101ae08745Sheppo } 8111ae08745Sheppo 812305dbad4SKevin Crowe cmn_err(CE_WARN, "ldc_set_rx_qhead: (0x%lx) cannot set qhead 0x%lx, " 813305dbad4SKevin Crowe "rv = 0x%x", ldcp->id, head, rv); 814d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 8153af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 816d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 8170a55fbb7Slm66018 8180a55fbb7Slm66018 return (ECONNRESET); 8191ae08745Sheppo } 8201ae08745Sheppo 82122f747efSnarayan /* 82222f747efSnarayan * Returns the tx_head to be used for transfer 82322f747efSnarayan */ 82422f747efSnarayan static void 82522f747efSnarayan i_ldc_get_tx_head(ldc_chan_t *ldcp, uint64_t *head) 82622f747efSnarayan { 82722f747efSnarayan ldc_msg_t *pkt; 82822f747efSnarayan 82922f747efSnarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 83022f747efSnarayan 83122f747efSnarayan /* get current Tx head */ 83222f747efSnarayan *head = ldcp->tx_head; 83322f747efSnarayan 83422f747efSnarayan /* 83522f747efSnarayan * Reliable mode will use the ACKd head instead of the regular tx_head. 83622f747efSnarayan * Also in Reliable mode, advance ackd_head for all non DATA/INFO pkts, 83722f747efSnarayan * up to the current location of tx_head. This needs to be done 83822f747efSnarayan * as the peer will only ACK DATA/INFO pkts. 83922f747efSnarayan */ 84020ae46ebSha137994 if (ldcp->mode == LDC_MODE_RELIABLE) { 84122f747efSnarayan while (ldcp->tx_ackd_head != ldcp->tx_head) { 84222f747efSnarayan pkt = (ldc_msg_t *)(ldcp->tx_q_va + ldcp->tx_ackd_head); 84322f747efSnarayan if ((pkt->type & LDC_DATA) && (pkt->stype & LDC_INFO)) { 84422f747efSnarayan break; 84522f747efSnarayan } 84622f747efSnarayan /* advance ACKd head */ 84722f747efSnarayan ldcp->tx_ackd_head = 84822f747efSnarayan (ldcp->tx_ackd_head + LDC_PACKET_SIZE) % 84922f747efSnarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 85022f747efSnarayan } 85122f747efSnarayan *head = ldcp->tx_ackd_head; 85222f747efSnarayan } 85322f747efSnarayan } 8541ae08745Sheppo 8551ae08745Sheppo /* 8561ae08745Sheppo * Returns the tx_tail to be used for transfer 8571ae08745Sheppo * Re-reads the TX queue ptrs if and only if the 8581ae08745Sheppo * the cached head and tail are equal (queue is full) 8591ae08745Sheppo */ 8601ae08745Sheppo static int 8611ae08745Sheppo i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail) 8621ae08745Sheppo { 8631ae08745Sheppo int rv; 8641ae08745Sheppo uint64_t current_head, new_tail; 8651ae08745Sheppo 866d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 8671ae08745Sheppo /* Read the head and tail ptrs from HV */ 8681ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 8691ae08745Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 8701ae08745Sheppo if (rv) { 8711ae08745Sheppo cmn_err(CE_WARN, 8721ae08745Sheppo "i_ldc_get_tx_tail: (0x%lx) cannot read qptrs\n", 8731ae08745Sheppo ldcp->id); 8741ae08745Sheppo return (EIO); 8751ae08745Sheppo } 8761ae08745Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN) { 877cb112a14Slm66018 D1(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) channel not ready\n", 8781ae08745Sheppo ldcp->id); 8791ae08745Sheppo return (ECONNRESET); 8801ae08745Sheppo } 8811ae08745Sheppo 88222f747efSnarayan i_ldc_get_tx_head(ldcp, ¤t_head); 8831ae08745Sheppo 8841ae08745Sheppo /* increment the tail */ 8851ae08745Sheppo new_tail = (ldcp->tx_tail + LDC_PACKET_SIZE) % 8861ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 8871ae08745Sheppo 8881ae08745Sheppo if (new_tail == current_head) { 8891ae08745Sheppo DWARN(ldcp->id, 8901ae08745Sheppo "i_ldc_get_tx_tail: (0x%llx) TX queue is full\n", 8911ae08745Sheppo ldcp->id); 8921ae08745Sheppo return (EWOULDBLOCK); 8931ae08745Sheppo } 8941ae08745Sheppo 8951ae08745Sheppo D2(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) head=0x%llx, tail=0x%llx\n", 8961ae08745Sheppo ldcp->id, ldcp->tx_head, ldcp->tx_tail); 8971ae08745Sheppo 8981ae08745Sheppo *tail = ldcp->tx_tail; 8991ae08745Sheppo return (0); 9001ae08745Sheppo } 9011ae08745Sheppo 9021ae08745Sheppo /* 9031ae08745Sheppo * Set the tail pointer. If HV returns EWOULDBLOCK, it will back off 9040a55fbb7Slm66018 * and retry ldc_max_retries times before returning an error. 9051ae08745Sheppo * Returns 0, EWOULDBLOCK or EIO 9061ae08745Sheppo */ 9071ae08745Sheppo static int 9081ae08745Sheppo i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail) 9091ae08745Sheppo { 9101ae08745Sheppo int rv, retval = EWOULDBLOCK; 9110a55fbb7Slm66018 int retries; 9121ae08745Sheppo 913d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 9140a55fbb7Slm66018 for (retries = 0; retries < ldc_max_retries; retries++) { 9151ae08745Sheppo 9161ae08745Sheppo if ((rv = hv_ldc_tx_set_qtail(ldcp->id, tail)) == 0) { 9171ae08745Sheppo retval = 0; 9181ae08745Sheppo break; 9191ae08745Sheppo } 9201ae08745Sheppo if (rv != H_EWOULDBLOCK) { 9211ae08745Sheppo DWARN(ldcp->id, "i_ldc_set_tx_tail: (0x%llx) set " 9221ae08745Sheppo "qtail=0x%llx failed, rv=%d\n", ldcp->id, tail, rv); 9231ae08745Sheppo retval = EIO; 9241ae08745Sheppo break; 9251ae08745Sheppo } 9261ae08745Sheppo 9270a55fbb7Slm66018 /* wait for ldc_delay usecs */ 9280a55fbb7Slm66018 drv_usecwait(ldc_delay); 9291ae08745Sheppo } 9301ae08745Sheppo return (retval); 9311ae08745Sheppo } 9321ae08745Sheppo 9331ae08745Sheppo /* 93458283286Sha137994 * Copy a data packet from the HV receive queue to the data queue. 93558283286Sha137994 * Caller must ensure that the data queue is not already full. 93658283286Sha137994 * 93758283286Sha137994 * The *head argument represents the current head pointer for the HV 93858283286Sha137994 * receive queue. After copying a packet from the HV receive queue, 93958283286Sha137994 * the *head pointer will be updated. This allows the caller to update 94058283286Sha137994 * the head pointer in HV using the returned *head value. 94158283286Sha137994 */ 94258283286Sha137994 void 94358283286Sha137994 i_ldc_rxdq_copy(ldc_chan_t *ldcp, uint64_t *head) 94458283286Sha137994 { 94558283286Sha137994 uint64_t q_size, dq_size; 94658283286Sha137994 94758283286Sha137994 ASSERT(MUTEX_HELD(&ldcp->lock)); 94858283286Sha137994 94958283286Sha137994 q_size = ldcp->rx_q_entries << LDC_PACKET_SHIFT; 95058283286Sha137994 dq_size = ldcp->rx_dq_entries << LDC_PACKET_SHIFT; 95158283286Sha137994 95258283286Sha137994 ASSERT(Q_CONTIG_SPACE(ldcp->rx_dq_head, ldcp->rx_dq_tail, 95358283286Sha137994 dq_size) >= LDC_PACKET_SIZE); 95458283286Sha137994 95558283286Sha137994 bcopy((void *)(ldcp->rx_q_va + *head), 95658283286Sha137994 (void *)(ldcp->rx_dq_va + ldcp->rx_dq_tail), LDC_PACKET_SIZE); 95758283286Sha137994 TRACE_RXDQ_COPY(ldcp, LDC_PACKET_SIZE); 95858283286Sha137994 95958283286Sha137994 /* Update rx head */ 96058283286Sha137994 *head = (*head + LDC_PACKET_SIZE) % q_size; 96158283286Sha137994 96258283286Sha137994 /* Update dq tail */ 96358283286Sha137994 ldcp->rx_dq_tail = (ldcp->rx_dq_tail + LDC_PACKET_SIZE) % dq_size; 96458283286Sha137994 } 96558283286Sha137994 96658283286Sha137994 /* 96758283286Sha137994 * Update the Rx data queue head pointer 96858283286Sha137994 */ 96958283286Sha137994 static int 97058283286Sha137994 i_ldc_set_rxdq_head(ldc_chan_t *ldcp, uint64_t head) 97158283286Sha137994 { 97258283286Sha137994 ldcp->rx_dq_head = head; 97358283286Sha137994 return (0); 97458283286Sha137994 } 97558283286Sha137994 97658283286Sha137994 /* 97758283286Sha137994 * Get the Rx data queue head and tail pointers 97858283286Sha137994 */ 97958283286Sha137994 static uint64_t 98058283286Sha137994 i_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail, 98158283286Sha137994 uint64_t *link_state) 98258283286Sha137994 { 98358283286Sha137994 _NOTE(ARGUNUSED(link_state)) 98458283286Sha137994 *head = ldcp->rx_dq_head; 98558283286Sha137994 *tail = ldcp->rx_dq_tail; 98658283286Sha137994 return (0); 98758283286Sha137994 } 98858283286Sha137994 98958283286Sha137994 /* 99058283286Sha137994 * Wrapper for the Rx HV queue set head function. Giving the 99158283286Sha137994 * data queue and HV queue set head functions the same type. 99258283286Sha137994 */ 99358283286Sha137994 static uint64_t 99458283286Sha137994 i_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail, 99558283286Sha137994 uint64_t *link_state) 99658283286Sha137994 { 99758283286Sha137994 return (i_ldc_h2v_error(hv_ldc_rx_get_state(ldcp->id, head, tail, 99858283286Sha137994 link_state))); 99958283286Sha137994 } 100058283286Sha137994 100158283286Sha137994 /* 100258283286Sha137994 * LDC receive interrupt handler 100358283286Sha137994 * triggered for channel with data pending to read 100458283286Sha137994 * i.e. Rx queue content changes 100558283286Sha137994 */ 100658283286Sha137994 static uint_t 100758283286Sha137994 i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2) 100858283286Sha137994 { 100958283286Sha137994 _NOTE(ARGUNUSED(arg2)) 101058283286Sha137994 101158283286Sha137994 ldc_chan_t *ldcp; 101258283286Sha137994 boolean_t notify; 101358283286Sha137994 uint64_t event; 101412f80fa6Sha137994 int rv, status; 101558283286Sha137994 101658283286Sha137994 /* Get the channel for which interrupt was received */ 101758283286Sha137994 if (arg1 == NULL) { 101858283286Sha137994 cmn_err(CE_WARN, "i_ldc_rx_hdlr: invalid arg\n"); 101958283286Sha137994 return (DDI_INTR_UNCLAIMED); 102058283286Sha137994 } 102158283286Sha137994 102258283286Sha137994 ldcp = (ldc_chan_t *)arg1; 102358283286Sha137994 102458283286Sha137994 D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n", 102558283286Sha137994 ldcp->id, ldcp); 102658283286Sha137994 D1(ldcp->id, "i_ldc_rx_hdlr: (%llx) USR%lx/TS%lx/HS%lx, LSTATE=%lx\n", 102758283286Sha137994 ldcp->id, ldcp->status, ldcp->tstate, ldcp->hstate, 102858283286Sha137994 ldcp->link_state); 102958283286Sha137994 103058283286Sha137994 /* Lock channel */ 103158283286Sha137994 mutex_enter(&ldcp->lock); 103258283286Sha137994 103358283286Sha137994 /* Mark the interrupt as being actively handled */ 103458283286Sha137994 ldcp->rx_intr_state = LDC_INTR_ACTIVE; 103558283286Sha137994 103612f80fa6Sha137994 status = i_ldc_rx_process_hvq(ldcp, ¬ify, &event); 103758283286Sha137994 103820ae46ebSha137994 if (ldcp->mode != LDC_MODE_RELIABLE) { 103958283286Sha137994 /* 104058283286Sha137994 * If there are no data packets on the queue, clear 104158283286Sha137994 * the interrupt. Otherwise, the ldc_read will clear 104258283286Sha137994 * interrupts after draining the queue. To indicate the 104358283286Sha137994 * interrupt has not yet been cleared, it is marked 104458283286Sha137994 * as pending. 104558283286Sha137994 */ 104658283286Sha137994 if ((event & LDC_EVT_READ) == 0) { 104758283286Sha137994 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 104858283286Sha137994 } else { 104958283286Sha137994 ldcp->rx_intr_state = LDC_INTR_PEND; 105058283286Sha137994 } 105158283286Sha137994 } 105258283286Sha137994 105358283286Sha137994 /* if callbacks are disabled, do not notify */ 105458283286Sha137994 if (notify && ldcp->cb_enabled) { 105558283286Sha137994 ldcp->cb_inprogress = B_TRUE; 105658283286Sha137994 mutex_exit(&ldcp->lock); 105758283286Sha137994 rv = ldcp->cb(event, ldcp->cb_arg); 105858283286Sha137994 if (rv) { 105958283286Sha137994 DWARN(ldcp->id, 106058283286Sha137994 "i_ldc_rx_hdlr: (0x%llx) callback failure", 106158283286Sha137994 ldcp->id); 106258283286Sha137994 } 106358283286Sha137994 mutex_enter(&ldcp->lock); 106458283286Sha137994 ldcp->cb_inprogress = B_FALSE; 106558283286Sha137994 } 106658283286Sha137994 106720ae46ebSha137994 if (ldcp->mode == LDC_MODE_RELIABLE) { 106812f80fa6Sha137994 if (status == ENOSPC) { 106958283286Sha137994 /* 107012f80fa6Sha137994 * Here, ENOSPC indicates the secondary data 107112f80fa6Sha137994 * queue is full and the Rx queue is non-empty. 107212f80fa6Sha137994 * Much like how reliable and raw modes are 107312f80fa6Sha137994 * handled above, since the Rx queue is non- 107412f80fa6Sha137994 * empty, we mark the interrupt as pending to 107512f80fa6Sha137994 * indicate it has not yet been cleared. 107612f80fa6Sha137994 */ 107712f80fa6Sha137994 ldcp->rx_intr_state = LDC_INTR_PEND; 107812f80fa6Sha137994 } else { 107912f80fa6Sha137994 /* 108012f80fa6Sha137994 * We have processed all CTRL packets and 108112f80fa6Sha137994 * copied all DATA packets to the secondary 108212f80fa6Sha137994 * queue. Clear the interrupt. 108358283286Sha137994 */ 108458283286Sha137994 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 108558283286Sha137994 } 108612f80fa6Sha137994 } 108758283286Sha137994 108858283286Sha137994 mutex_exit(&ldcp->lock); 108958283286Sha137994 109058283286Sha137994 D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) exiting handler", ldcp->id); 109158283286Sha137994 109258283286Sha137994 return (DDI_INTR_CLAIMED); 109358283286Sha137994 } 109458283286Sha137994 109558283286Sha137994 /* 109658283286Sha137994 * Wrapper for the Rx HV queue processing function to be used when 109758283286Sha137994 * checking the Rx HV queue for data packets. Unlike the interrupt 109858283286Sha137994 * handler code flow, the Rx interrupt is not cleared here and 109958283286Sha137994 * callbacks are not made. 110058283286Sha137994 */ 110158283286Sha137994 static uint_t 110258283286Sha137994 i_ldc_chkq(ldc_chan_t *ldcp) 110358283286Sha137994 { 110458283286Sha137994 boolean_t notify; 110558283286Sha137994 uint64_t event; 110658283286Sha137994 110758283286Sha137994 return (i_ldc_rx_process_hvq(ldcp, ¬ify, &event)); 110858283286Sha137994 } 110958283286Sha137994 111058283286Sha137994 /* 11111ae08745Sheppo * Send a LDC message 11121ae08745Sheppo */ 11131ae08745Sheppo static int 11141ae08745Sheppo i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype, 11151ae08745Sheppo uint8_t ctrlmsg) 11161ae08745Sheppo { 11171ae08745Sheppo int rv; 11181ae08745Sheppo ldc_msg_t *pkt; 11191ae08745Sheppo uint64_t tx_tail; 112022f747efSnarayan uint32_t curr_seqid; 11211ae08745Sheppo 1122d10e4ef2Snarayan /* Obtain Tx lock */ 1123d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 1124d10e4ef2Snarayan 112522f747efSnarayan curr_seqid = ldcp->last_msg_snt; 112622f747efSnarayan 11271ae08745Sheppo /* get the current tail for the message */ 11281ae08745Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 11291ae08745Sheppo if (rv) { 11301ae08745Sheppo DWARN(ldcp->id, 11311ae08745Sheppo "i_ldc_send_pkt: (0x%llx) error sending pkt, " 11321ae08745Sheppo "type=0x%x,subtype=0x%x,ctrl=0x%x\n", 11331ae08745Sheppo ldcp->id, pkttype, subtype, ctrlmsg); 1134d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 11351ae08745Sheppo return (rv); 11361ae08745Sheppo } 11371ae08745Sheppo 11381ae08745Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 11391ae08745Sheppo ZERO_PKT(pkt); 11401ae08745Sheppo 11411ae08745Sheppo /* Initialize the packet */ 11421ae08745Sheppo pkt->type = pkttype; 11431ae08745Sheppo pkt->stype = subtype; 11441ae08745Sheppo pkt->ctrl = ctrlmsg; 11451ae08745Sheppo 11461ae08745Sheppo /* Store ackid/seqid iff it is RELIABLE mode & not a RTS/RTR message */ 11471ae08745Sheppo if (((ctrlmsg & LDC_CTRL_MASK) != LDC_RTS) && 11481ae08745Sheppo ((ctrlmsg & LDC_CTRL_MASK) != LDC_RTR)) { 11491ae08745Sheppo curr_seqid++; 11501ae08745Sheppo if (ldcp->mode != LDC_MODE_RAW) { 11511ae08745Sheppo pkt->seqid = curr_seqid; 11521ae08745Sheppo pkt->ackid = ldcp->last_msg_rcd; 11531ae08745Sheppo } 11541ae08745Sheppo } 11551ae08745Sheppo DUMP_LDC_PKT(ldcp, "i_ldc_send_pkt", (uint64_t)pkt); 11561ae08745Sheppo 11571ae08745Sheppo /* initiate the send by calling into HV and set the new tail */ 11581ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 11591ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 11601ae08745Sheppo 11611ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 11621ae08745Sheppo if (rv) { 11631ae08745Sheppo DWARN(ldcp->id, 11641ae08745Sheppo "i_ldc_send_pkt:(0x%llx) error sending pkt, " 11651ae08745Sheppo "type=0x%x,stype=0x%x,ctrl=0x%x\n", 11661ae08745Sheppo ldcp->id, pkttype, subtype, ctrlmsg); 1167d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 11681ae08745Sheppo return (EIO); 11691ae08745Sheppo } 11701ae08745Sheppo 11711ae08745Sheppo ldcp->last_msg_snt = curr_seqid; 11721ae08745Sheppo ldcp->tx_tail = tx_tail; 11731ae08745Sheppo 1174d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 11751ae08745Sheppo return (0); 11761ae08745Sheppo } 11771ae08745Sheppo 11781ae08745Sheppo /* 11791ae08745Sheppo * Checks if packet was received in right order 1180e1ebb9ecSlm66018 * in the case of a reliable link. 11811ae08745Sheppo * Returns 0 if in order, else EIO 11821ae08745Sheppo */ 11831ae08745Sheppo static int 11841ae08745Sheppo i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *msg) 11851ae08745Sheppo { 11861ae08745Sheppo /* No seqid checking for RAW mode */ 11871ae08745Sheppo if (ldcp->mode == LDC_MODE_RAW) 11881ae08745Sheppo return (0); 11891ae08745Sheppo 11901ae08745Sheppo /* No seqid checking for version, RTS, RTR message */ 11911ae08745Sheppo if (msg->ctrl == LDC_VER || 11921ae08745Sheppo msg->ctrl == LDC_RTS || 11931ae08745Sheppo msg->ctrl == LDC_RTR) 11941ae08745Sheppo return (0); 11951ae08745Sheppo 11961ae08745Sheppo /* Initial seqid to use is sent in RTS/RTR and saved in last_msg_rcd */ 11971ae08745Sheppo if (msg->seqid != (ldcp->last_msg_rcd + 1)) { 11981ae08745Sheppo DWARN(ldcp->id, 11991ae08745Sheppo "i_ldc_check_seqid: (0x%llx) out-of-order pkt, got 0x%x, " 12001ae08745Sheppo "expecting 0x%x\n", ldcp->id, msg->seqid, 12011ae08745Sheppo (ldcp->last_msg_rcd + 1)); 12021ae08745Sheppo return (EIO); 12031ae08745Sheppo } 12041ae08745Sheppo 120583d3bc6fSnarayan #ifdef DEBUG 120683d3bc6fSnarayan if (LDC_INJECT_PKTLOSS(ldcp)) { 120783d3bc6fSnarayan DWARN(ldcp->id, 120883d3bc6fSnarayan "i_ldc_check_seqid: (0x%llx) inject pkt loss\n", ldcp->id); 120983d3bc6fSnarayan return (EIO); 121083d3bc6fSnarayan } 121183d3bc6fSnarayan #endif 121283d3bc6fSnarayan 12131ae08745Sheppo return (0); 12141ae08745Sheppo } 12151ae08745Sheppo 12161ae08745Sheppo 12171ae08745Sheppo /* 12181ae08745Sheppo * Process an incoming version ctrl message 12191ae08745Sheppo */ 12201ae08745Sheppo static int 12211ae08745Sheppo i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg) 12221ae08745Sheppo { 12231ae08745Sheppo int rv = 0, idx = ldcp->next_vidx; 12241ae08745Sheppo ldc_msg_t *pkt; 12251ae08745Sheppo uint64_t tx_tail; 12261ae08745Sheppo ldc_ver_t *rcvd_ver; 12271ae08745Sheppo 12281ae08745Sheppo /* get the received version */ 12291ae08745Sheppo rcvd_ver = (ldc_ver_t *)((uint64_t)msg + LDC_PAYLOAD_VER_OFF); 12301ae08745Sheppo 12311ae08745Sheppo D2(ldcp->id, "i_ldc_process_VER: (0x%llx) received VER v%u.%u\n", 12321ae08745Sheppo ldcp->id, rcvd_ver->major, rcvd_ver->minor); 12331ae08745Sheppo 1234d10e4ef2Snarayan /* Obtain Tx lock */ 1235d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 1236d10e4ef2Snarayan 12371ae08745Sheppo switch (msg->stype) { 12381ae08745Sheppo case LDC_INFO: 12391ae08745Sheppo 12403af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) { 12413af08d82Slm66018 (void) i_ldc_txq_reconf(ldcp); 12423af08d82Slm66018 i_ldc_reset_state(ldcp); 12433af08d82Slm66018 mutex_exit(&ldcp->tx_lock); 12443af08d82Slm66018 return (EAGAIN); 12453af08d82Slm66018 } 12463af08d82Slm66018 12471ae08745Sheppo /* get the current tail and pkt for the response */ 12481ae08745Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 12491ae08745Sheppo if (rv != 0) { 12501ae08745Sheppo DWARN(ldcp->id, 12511ae08745Sheppo "i_ldc_process_VER: (0x%llx) err sending " 12521ae08745Sheppo "version ACK/NACK\n", ldcp->id); 12533af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1254d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 12551ae08745Sheppo return (ECONNRESET); 12561ae08745Sheppo } 12571ae08745Sheppo 12581ae08745Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 12591ae08745Sheppo ZERO_PKT(pkt); 12601ae08745Sheppo 12611ae08745Sheppo /* initialize the packet */ 12621ae08745Sheppo pkt->type = LDC_CTRL; 12631ae08745Sheppo pkt->ctrl = LDC_VER; 12641ae08745Sheppo 12651ae08745Sheppo for (;;) { 12661ae08745Sheppo 12671ae08745Sheppo D1(ldcp->id, "i_ldc_process_VER: got %u.%u chk %u.%u\n", 12681ae08745Sheppo rcvd_ver->major, rcvd_ver->minor, 12691ae08745Sheppo ldc_versions[idx].major, ldc_versions[idx].minor); 12701ae08745Sheppo 12711ae08745Sheppo if (rcvd_ver->major == ldc_versions[idx].major) { 12721ae08745Sheppo /* major version match - ACK version */ 12731ae08745Sheppo pkt->stype = LDC_ACK; 12741ae08745Sheppo 12751ae08745Sheppo /* 12761ae08745Sheppo * lower minor version to the one this endpt 12771ae08745Sheppo * supports, if necessary 12781ae08745Sheppo */ 12791ae08745Sheppo if (rcvd_ver->minor > ldc_versions[idx].minor) 12801ae08745Sheppo rcvd_ver->minor = 12811ae08745Sheppo ldc_versions[idx].minor; 12821ae08745Sheppo bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver)); 12831ae08745Sheppo 12841ae08745Sheppo break; 12851ae08745Sheppo } 12861ae08745Sheppo 12871ae08745Sheppo if (rcvd_ver->major > ldc_versions[idx].major) { 12881ae08745Sheppo 12891ae08745Sheppo D1(ldcp->id, "i_ldc_process_VER: using next" 12901ae08745Sheppo " lower idx=%d, v%u.%u\n", idx, 12911ae08745Sheppo ldc_versions[idx].major, 12921ae08745Sheppo ldc_versions[idx].minor); 12931ae08745Sheppo 12941ae08745Sheppo /* nack with next lower version */ 12951ae08745Sheppo pkt->stype = LDC_NACK; 12961ae08745Sheppo bcopy(&ldc_versions[idx], pkt->udata, 12971ae08745Sheppo sizeof (ldc_versions[idx])); 12981ae08745Sheppo ldcp->next_vidx = idx; 12991ae08745Sheppo break; 13001ae08745Sheppo } 13011ae08745Sheppo 13021ae08745Sheppo /* next major version */ 13031ae08745Sheppo idx++; 13041ae08745Sheppo 13051ae08745Sheppo D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx); 13061ae08745Sheppo 13071ae08745Sheppo if (idx == LDC_NUM_VERS) { 13081ae08745Sheppo /* no version match - send NACK */ 13091ae08745Sheppo pkt->stype = LDC_NACK; 13101ae08745Sheppo bzero(pkt->udata, sizeof (ldc_ver_t)); 13111ae08745Sheppo ldcp->next_vidx = 0; 13121ae08745Sheppo break; 13131ae08745Sheppo } 13141ae08745Sheppo } 13151ae08745Sheppo 13161ae08745Sheppo /* initiate the send by calling into HV and set the new tail */ 13171ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 13181ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 13191ae08745Sheppo 13201ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 13211ae08745Sheppo if (rv == 0) { 13221ae08745Sheppo ldcp->tx_tail = tx_tail; 13231ae08745Sheppo if (pkt->stype == LDC_ACK) { 13241ae08745Sheppo D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent" 13251ae08745Sheppo " version ACK\n", ldcp->id); 13261ae08745Sheppo /* Save the ACK'd version */ 13271ae08745Sheppo ldcp->version.major = rcvd_ver->major; 13281ae08745Sheppo ldcp->version.minor = rcvd_ver->minor; 13290a55fbb7Slm66018 ldcp->hstate |= TS_RCVD_VER; 13301ae08745Sheppo ldcp->tstate |= TS_VER_DONE; 133183d3bc6fSnarayan D1(DBG_ALL_LDCS, 13323af08d82Slm66018 "(0x%llx) Sent ACK, " 13333af08d82Slm66018 "Agreed on version v%u.%u\n", 13341ae08745Sheppo ldcp->id, rcvd_ver->major, rcvd_ver->minor); 13351ae08745Sheppo } 13361ae08745Sheppo } else { 13371ae08745Sheppo DWARN(ldcp->id, 13381ae08745Sheppo "i_ldc_process_VER: (0x%llx) error sending " 13391ae08745Sheppo "ACK/NACK\n", ldcp->id); 13403af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1341d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 13421ae08745Sheppo return (ECONNRESET); 13431ae08745Sheppo } 13441ae08745Sheppo 13451ae08745Sheppo break; 13461ae08745Sheppo 13471ae08745Sheppo case LDC_ACK: 13483af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) { 13493af08d82Slm66018 if (ldcp->version.major != rcvd_ver->major || 13503af08d82Slm66018 ldcp->version.minor != rcvd_ver->minor) { 13513af08d82Slm66018 13523af08d82Slm66018 /* mismatched version - reset connection */ 13533af08d82Slm66018 DWARN(ldcp->id, 13543af08d82Slm66018 "i_ldc_process_VER: (0x%llx) recvd" 13553af08d82Slm66018 " ACK ver != sent ACK ver\n", ldcp->id); 13563af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 13573af08d82Slm66018 mutex_exit(&ldcp->tx_lock); 13583af08d82Slm66018 return (ECONNRESET); 13593af08d82Slm66018 } 13603af08d82Slm66018 } else { 13611ae08745Sheppo /* SUCCESS - we have agreed on a version */ 13621ae08745Sheppo ldcp->version.major = rcvd_ver->major; 13631ae08745Sheppo ldcp->version.minor = rcvd_ver->minor; 13641ae08745Sheppo ldcp->tstate |= TS_VER_DONE; 13653af08d82Slm66018 } 13661ae08745Sheppo 1367cb112a14Slm66018 D1(ldcp->id, "(0x%llx) Got ACK, Agreed on version v%u.%u\n", 13681ae08745Sheppo ldcp->id, rcvd_ver->major, rcvd_ver->minor); 13691ae08745Sheppo 13701ae08745Sheppo /* initiate RTS-RTR-RDX handshake */ 13711ae08745Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 13721ae08745Sheppo if (rv) { 13731ae08745Sheppo DWARN(ldcp->id, 13741ae08745Sheppo "i_ldc_process_VER: (0x%llx) cannot send RTS\n", 13751ae08745Sheppo ldcp->id); 13763af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1377d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 13781ae08745Sheppo return (ECONNRESET); 13791ae08745Sheppo } 13801ae08745Sheppo 13811ae08745Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 13821ae08745Sheppo ZERO_PKT(pkt); 13831ae08745Sheppo 13841ae08745Sheppo pkt->type = LDC_CTRL; 13851ae08745Sheppo pkt->stype = LDC_INFO; 13861ae08745Sheppo pkt->ctrl = LDC_RTS; 13871ae08745Sheppo pkt->env = ldcp->mode; 13881ae08745Sheppo if (ldcp->mode != LDC_MODE_RAW) 13891ae08745Sheppo pkt->seqid = LDC_INIT_SEQID; 13901ae08745Sheppo 13911ae08745Sheppo ldcp->last_msg_rcd = LDC_INIT_SEQID; 13921ae08745Sheppo 13931ae08745Sheppo DUMP_LDC_PKT(ldcp, "i_ldc_process_VER snd rts", (uint64_t)pkt); 13941ae08745Sheppo 13951ae08745Sheppo /* initiate the send by calling into HV and set the new tail */ 13961ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 13971ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 13981ae08745Sheppo 13991ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 14001ae08745Sheppo if (rv) { 14011ae08745Sheppo D2(ldcp->id, 14021ae08745Sheppo "i_ldc_process_VER: (0x%llx) no listener\n", 14031ae08745Sheppo ldcp->id); 14043af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1405d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 14061ae08745Sheppo return (ECONNRESET); 14071ae08745Sheppo } 14081ae08745Sheppo 14091ae08745Sheppo ldcp->tx_tail = tx_tail; 14101ae08745Sheppo ldcp->hstate |= TS_SENT_RTS; 14111ae08745Sheppo 14121ae08745Sheppo break; 14131ae08745Sheppo 14141ae08745Sheppo case LDC_NACK: 14151ae08745Sheppo /* check if version in NACK is zero */ 14161ae08745Sheppo if (rcvd_ver->major == 0 && rcvd_ver->minor == 0) { 14171ae08745Sheppo /* version handshake failure */ 14181ae08745Sheppo DWARN(DBG_ALL_LDCS, 14191ae08745Sheppo "i_ldc_process_VER: (0x%llx) no version match\n", 14201ae08745Sheppo ldcp->id); 14213af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1422d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 14231ae08745Sheppo return (ECONNRESET); 14241ae08745Sheppo } 14251ae08745Sheppo 14261ae08745Sheppo /* get the current tail and pkt for the response */ 14271ae08745Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 14281ae08745Sheppo if (rv != 0) { 14291ae08745Sheppo cmn_err(CE_NOTE, 14301ae08745Sheppo "i_ldc_process_VER: (0x%lx) err sending " 14311ae08745Sheppo "version ACK/NACK\n", ldcp->id); 14323af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1433d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 14341ae08745Sheppo return (ECONNRESET); 14351ae08745Sheppo } 14361ae08745Sheppo 14371ae08745Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 14381ae08745Sheppo ZERO_PKT(pkt); 14391ae08745Sheppo 14401ae08745Sheppo /* initialize the packet */ 14411ae08745Sheppo pkt->type = LDC_CTRL; 14421ae08745Sheppo pkt->ctrl = LDC_VER; 14431ae08745Sheppo pkt->stype = LDC_INFO; 14441ae08745Sheppo 14451ae08745Sheppo /* check ver in NACK msg has a match */ 14461ae08745Sheppo for (;;) { 14471ae08745Sheppo if (rcvd_ver->major == ldc_versions[idx].major) { 14481ae08745Sheppo /* 14491ae08745Sheppo * major version match - resubmit request 14501ae08745Sheppo * if lower minor version to the one this endpt 14511ae08745Sheppo * supports, if necessary 14521ae08745Sheppo */ 14531ae08745Sheppo if (rcvd_ver->minor > ldc_versions[idx].minor) 14541ae08745Sheppo rcvd_ver->minor = 14551ae08745Sheppo ldc_versions[idx].minor; 14561ae08745Sheppo bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver)); 14571ae08745Sheppo break; 14581ae08745Sheppo } 14591ae08745Sheppo 14601ae08745Sheppo if (rcvd_ver->major > ldc_versions[idx].major) { 14611ae08745Sheppo 14621ae08745Sheppo D1(ldcp->id, "i_ldc_process_VER: using next" 14631ae08745Sheppo " lower idx=%d, v%u.%u\n", idx, 14641ae08745Sheppo ldc_versions[idx].major, 14651ae08745Sheppo ldc_versions[idx].minor); 14661ae08745Sheppo 14671ae08745Sheppo /* send next lower version */ 14681ae08745Sheppo bcopy(&ldc_versions[idx], pkt->udata, 14691ae08745Sheppo sizeof (ldc_versions[idx])); 14701ae08745Sheppo ldcp->next_vidx = idx; 14711ae08745Sheppo break; 14721ae08745Sheppo } 14731ae08745Sheppo 14741ae08745Sheppo /* next version */ 14751ae08745Sheppo idx++; 14761ae08745Sheppo 14771ae08745Sheppo D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx); 14781ae08745Sheppo 14791ae08745Sheppo if (idx == LDC_NUM_VERS) { 14801ae08745Sheppo /* no version match - terminate */ 14811ae08745Sheppo ldcp->next_vidx = 0; 1482d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 14831ae08745Sheppo return (ECONNRESET); 14841ae08745Sheppo } 14851ae08745Sheppo } 14861ae08745Sheppo 14871ae08745Sheppo /* initiate the send by calling into HV and set the new tail */ 14881ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 14891ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 14901ae08745Sheppo 14911ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 14921ae08745Sheppo if (rv == 0) { 14931ae08745Sheppo D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent version" 14941ae08745Sheppo "INFO v%u.%u\n", ldcp->id, ldc_versions[idx].major, 14951ae08745Sheppo ldc_versions[idx].minor); 14961ae08745Sheppo ldcp->tx_tail = tx_tail; 14971ae08745Sheppo } else { 14981ae08745Sheppo cmn_err(CE_NOTE, 14991ae08745Sheppo "i_ldc_process_VER: (0x%lx) error sending version" 15001ae08745Sheppo "INFO\n", ldcp->id); 15013af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1502d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 15031ae08745Sheppo return (ECONNRESET); 15041ae08745Sheppo } 15051ae08745Sheppo 15061ae08745Sheppo break; 15071ae08745Sheppo } 15081ae08745Sheppo 1509d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 15101ae08745Sheppo return (rv); 15111ae08745Sheppo } 15121ae08745Sheppo 15131ae08745Sheppo 15141ae08745Sheppo /* 15151ae08745Sheppo * Process an incoming RTS ctrl message 15161ae08745Sheppo */ 15171ae08745Sheppo static int 15181ae08745Sheppo i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg) 15191ae08745Sheppo { 15201ae08745Sheppo int rv = 0; 15211ae08745Sheppo ldc_msg_t *pkt; 15221ae08745Sheppo uint64_t tx_tail; 15231ae08745Sheppo boolean_t sent_NACK = B_FALSE; 15241ae08745Sheppo 15251ae08745Sheppo D2(ldcp->id, "i_ldc_process_RTS: (0x%llx) received RTS\n", ldcp->id); 15261ae08745Sheppo 15271ae08745Sheppo switch (msg->stype) { 15281ae08745Sheppo case LDC_NACK: 15291ae08745Sheppo DWARN(ldcp->id, 15301ae08745Sheppo "i_ldc_process_RTS: (0x%llx) RTS NACK received\n", 15311ae08745Sheppo ldcp->id); 15321ae08745Sheppo 15331ae08745Sheppo /* Reset the channel -- as we cannot continue */ 1534d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 15353af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1536d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 15371ae08745Sheppo rv = ECONNRESET; 15381ae08745Sheppo break; 15391ae08745Sheppo 15401ae08745Sheppo case LDC_INFO: 15411ae08745Sheppo 15421ae08745Sheppo /* check mode */ 15431ae08745Sheppo if (ldcp->mode != (ldc_mode_t)msg->env) { 15441ae08745Sheppo cmn_err(CE_NOTE, 15451ae08745Sheppo "i_ldc_process_RTS: (0x%lx) mode mismatch\n", 15461ae08745Sheppo ldcp->id); 15471ae08745Sheppo /* 15481ae08745Sheppo * send NACK in response to MODE message 15491ae08745Sheppo * get the current tail for the response 15501ae08745Sheppo */ 15511ae08745Sheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTS); 15521ae08745Sheppo if (rv) { 15531ae08745Sheppo /* if cannot send NACK - reset channel */ 1554d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 15553af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1556d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 15571ae08745Sheppo rv = ECONNRESET; 15581ae08745Sheppo break; 15591ae08745Sheppo } 15601ae08745Sheppo sent_NACK = B_TRUE; 15611ae08745Sheppo } 15621ae08745Sheppo break; 15631ae08745Sheppo default: 15641ae08745Sheppo DWARN(ldcp->id, "i_ldc_process_RTS: (0x%llx) unexp ACK\n", 15651ae08745Sheppo ldcp->id); 1566d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 15673af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1568d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 15691ae08745Sheppo rv = ECONNRESET; 15701ae08745Sheppo break; 15711ae08745Sheppo } 15721ae08745Sheppo 15731ae08745Sheppo /* 15741ae08745Sheppo * If either the connection was reset (when rv != 0) or 15751ae08745Sheppo * a NACK was sent, we return. In the case of a NACK 15761ae08745Sheppo * we dont want to consume the packet that came in but 15771ae08745Sheppo * not record that we received the RTS 15781ae08745Sheppo */ 15791ae08745Sheppo if (rv || sent_NACK) 15801ae08745Sheppo return (rv); 15811ae08745Sheppo 15821ae08745Sheppo /* record RTS received */ 15831ae08745Sheppo ldcp->hstate |= TS_RCVD_RTS; 15841ae08745Sheppo 15851ae08745Sheppo /* store initial SEQID info */ 15861ae08745Sheppo ldcp->last_msg_snt = msg->seqid; 15871ae08745Sheppo 1588d10e4ef2Snarayan /* Obtain Tx lock */ 1589d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 1590d10e4ef2Snarayan 15911ae08745Sheppo /* get the current tail for the response */ 15921ae08745Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 15931ae08745Sheppo if (rv != 0) { 15941ae08745Sheppo cmn_err(CE_NOTE, 15951ae08745Sheppo "i_ldc_process_RTS: (0x%lx) err sending RTR\n", 15961ae08745Sheppo ldcp->id); 15973af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1598d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 15991ae08745Sheppo return (ECONNRESET); 16001ae08745Sheppo } 16011ae08745Sheppo 16021ae08745Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 16031ae08745Sheppo ZERO_PKT(pkt); 16041ae08745Sheppo 16051ae08745Sheppo /* initialize the packet */ 16061ae08745Sheppo pkt->type = LDC_CTRL; 16071ae08745Sheppo pkt->stype = LDC_INFO; 16081ae08745Sheppo pkt->ctrl = LDC_RTR; 16091ae08745Sheppo pkt->env = ldcp->mode; 16101ae08745Sheppo if (ldcp->mode != LDC_MODE_RAW) 16111ae08745Sheppo pkt->seqid = LDC_INIT_SEQID; 16121ae08745Sheppo 16131ae08745Sheppo ldcp->last_msg_rcd = msg->seqid; 16141ae08745Sheppo 16151ae08745Sheppo /* initiate the send by calling into HV and set the new tail */ 16161ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 16171ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 16181ae08745Sheppo 16191ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 16201ae08745Sheppo if (rv == 0) { 16211ae08745Sheppo D2(ldcp->id, 16221ae08745Sheppo "i_ldc_process_RTS: (0x%llx) sent RTR\n", ldcp->id); 16231ae08745Sheppo DUMP_LDC_PKT(ldcp, "i_ldc_process_RTS sent rtr", (uint64_t)pkt); 16241ae08745Sheppo 16251ae08745Sheppo ldcp->tx_tail = tx_tail; 16261ae08745Sheppo ldcp->hstate |= TS_SENT_RTR; 16271ae08745Sheppo 16281ae08745Sheppo } else { 16291ae08745Sheppo cmn_err(CE_NOTE, 16301ae08745Sheppo "i_ldc_process_RTS: (0x%lx) error sending RTR\n", 16311ae08745Sheppo ldcp->id); 16323af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1633d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 16341ae08745Sheppo return (ECONNRESET); 16351ae08745Sheppo } 16361ae08745Sheppo 1637d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 16381ae08745Sheppo return (0); 16391ae08745Sheppo } 16401ae08745Sheppo 16411ae08745Sheppo /* 16421ae08745Sheppo * Process an incoming RTR ctrl message 16431ae08745Sheppo */ 16441ae08745Sheppo static int 16451ae08745Sheppo i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg) 16461ae08745Sheppo { 16471ae08745Sheppo int rv = 0; 16481ae08745Sheppo boolean_t sent_NACK = B_FALSE; 16491ae08745Sheppo 16501ae08745Sheppo D2(ldcp->id, "i_ldc_process_RTR: (0x%llx) received RTR\n", ldcp->id); 16511ae08745Sheppo 16521ae08745Sheppo switch (msg->stype) { 16531ae08745Sheppo case LDC_NACK: 16541ae08745Sheppo /* RTR NACK received */ 16551ae08745Sheppo DWARN(ldcp->id, 16561ae08745Sheppo "i_ldc_process_RTR: (0x%llx) RTR NACK received\n", 16571ae08745Sheppo ldcp->id); 16581ae08745Sheppo 16591ae08745Sheppo /* Reset the channel -- as we cannot continue */ 1660d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 16613af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1662d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 16631ae08745Sheppo rv = ECONNRESET; 16641ae08745Sheppo 16651ae08745Sheppo break; 16661ae08745Sheppo 16671ae08745Sheppo case LDC_INFO: 16681ae08745Sheppo 16691ae08745Sheppo /* check mode */ 16701ae08745Sheppo if (ldcp->mode != (ldc_mode_t)msg->env) { 16711ae08745Sheppo DWARN(ldcp->id, 1672cb112a14Slm66018 "i_ldc_process_RTR: (0x%llx) mode mismatch, " 1673cb112a14Slm66018 "expecting 0x%x, got 0x%x\n", 1674cb112a14Slm66018 ldcp->id, ldcp->mode, (ldc_mode_t)msg->env); 16751ae08745Sheppo /* 16761ae08745Sheppo * send NACK in response to MODE message 16771ae08745Sheppo * get the current tail for the response 16781ae08745Sheppo */ 16791ae08745Sheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTR); 16801ae08745Sheppo if (rv) { 16811ae08745Sheppo /* if cannot send NACK - reset channel */ 1682d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 16833af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1684d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 16851ae08745Sheppo rv = ECONNRESET; 16861ae08745Sheppo break; 16871ae08745Sheppo } 16881ae08745Sheppo sent_NACK = B_TRUE; 16891ae08745Sheppo } 16901ae08745Sheppo break; 16911ae08745Sheppo 16921ae08745Sheppo default: 16931ae08745Sheppo DWARN(ldcp->id, "i_ldc_process_RTR: (0x%llx) unexp ACK\n", 16941ae08745Sheppo ldcp->id); 16951ae08745Sheppo 16961ae08745Sheppo /* Reset the channel -- as we cannot continue */ 1697d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 16983af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1699d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 17001ae08745Sheppo rv = ECONNRESET; 17011ae08745Sheppo break; 17021ae08745Sheppo } 17031ae08745Sheppo 17041ae08745Sheppo /* 17051ae08745Sheppo * If either the connection was reset (when rv != 0) or 17061ae08745Sheppo * a NACK was sent, we return. In the case of a NACK 17071ae08745Sheppo * we dont want to consume the packet that came in but 17081ae08745Sheppo * not record that we received the RTR 17091ae08745Sheppo */ 17101ae08745Sheppo if (rv || sent_NACK) 17111ae08745Sheppo return (rv); 17121ae08745Sheppo 17131ae08745Sheppo ldcp->last_msg_snt = msg->seqid; 17141ae08745Sheppo ldcp->hstate |= TS_RCVD_RTR; 17151ae08745Sheppo 17161ae08745Sheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_INFO, LDC_RDX); 17171ae08745Sheppo if (rv) { 17181ae08745Sheppo cmn_err(CE_NOTE, 17191ae08745Sheppo "i_ldc_process_RTR: (0x%lx) cannot send RDX\n", 17201ae08745Sheppo ldcp->id); 1721d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 17223af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1723d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 17241ae08745Sheppo return (ECONNRESET); 17251ae08745Sheppo } 17261ae08745Sheppo D2(ldcp->id, 17271ae08745Sheppo "i_ldc_process_RTR: (0x%llx) sent RDX\n", ldcp->id); 17281ae08745Sheppo 17291ae08745Sheppo ldcp->hstate |= TS_SENT_RDX; 17301ae08745Sheppo ldcp->tstate |= TS_HSHAKE_DONE; 17313af08d82Slm66018 if ((ldcp->tstate & TS_IN_RESET) == 0) 17321ae08745Sheppo ldcp->status = LDC_UP; 17331ae08745Sheppo 1734cb112a14Slm66018 D1(ldcp->id, "(0x%llx) Handshake Complete\n", ldcp->id); 17351ae08745Sheppo 17361ae08745Sheppo return (0); 17371ae08745Sheppo } 17381ae08745Sheppo 17391ae08745Sheppo 17401ae08745Sheppo /* 17411ae08745Sheppo * Process an incoming RDX ctrl message 17421ae08745Sheppo */ 17431ae08745Sheppo static int 17441ae08745Sheppo i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg) 17451ae08745Sheppo { 17461ae08745Sheppo int rv = 0; 17471ae08745Sheppo 17481ae08745Sheppo D2(ldcp->id, "i_ldc_process_RDX: (0x%llx) received RDX\n", ldcp->id); 17491ae08745Sheppo 17501ae08745Sheppo switch (msg->stype) { 17511ae08745Sheppo case LDC_NACK: 17521ae08745Sheppo /* RDX NACK received */ 17531ae08745Sheppo DWARN(ldcp->id, 17541ae08745Sheppo "i_ldc_process_RDX: (0x%llx) RDX NACK received\n", 17551ae08745Sheppo ldcp->id); 17561ae08745Sheppo 17571ae08745Sheppo /* Reset the channel -- as we cannot continue */ 1758d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 17593af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1760d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 17611ae08745Sheppo rv = ECONNRESET; 17621ae08745Sheppo 17631ae08745Sheppo break; 17641ae08745Sheppo 17651ae08745Sheppo case LDC_INFO: 17661ae08745Sheppo 17671ae08745Sheppo /* 17681ae08745Sheppo * if channel is UP and a RDX received after data transmission 17691ae08745Sheppo * has commenced it is an error 17701ae08745Sheppo */ 17711ae08745Sheppo if ((ldcp->tstate == TS_UP) && (ldcp->hstate & TS_RCVD_RDX)) { 17721ae08745Sheppo DWARN(DBG_ALL_LDCS, 17731ae08745Sheppo "i_ldc_process_RDX: (0x%llx) unexpected RDX" 17741ae08745Sheppo " - LDC reset\n", ldcp->id); 1775d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 17763af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1777d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 17781ae08745Sheppo return (ECONNRESET); 17791ae08745Sheppo } 17801ae08745Sheppo 17811ae08745Sheppo ldcp->hstate |= TS_RCVD_RDX; 17821ae08745Sheppo ldcp->tstate |= TS_HSHAKE_DONE; 17833af08d82Slm66018 if ((ldcp->tstate & TS_IN_RESET) == 0) 17841ae08745Sheppo ldcp->status = LDC_UP; 17851ae08745Sheppo 17861ae08745Sheppo D1(DBG_ALL_LDCS, "(0x%llx) Handshake Complete\n", ldcp->id); 17871ae08745Sheppo break; 17881ae08745Sheppo 17891ae08745Sheppo default: 17901ae08745Sheppo DWARN(ldcp->id, "i_ldc_process_RDX: (0x%llx) unexp ACK\n", 17911ae08745Sheppo ldcp->id); 17921ae08745Sheppo 17931ae08745Sheppo /* Reset the channel -- as we cannot continue */ 1794d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 17953af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1796d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 17971ae08745Sheppo rv = ECONNRESET; 17981ae08745Sheppo break; 17991ae08745Sheppo } 18001ae08745Sheppo 18011ae08745Sheppo return (rv); 18021ae08745Sheppo } 18031ae08745Sheppo 18041ae08745Sheppo /* 18051ae08745Sheppo * Process an incoming ACK for a data packet 18061ae08745Sheppo */ 18071ae08745Sheppo static int 18081ae08745Sheppo i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg) 18091ae08745Sheppo { 18101ae08745Sheppo int rv; 18111ae08745Sheppo uint64_t tx_head; 18121ae08745Sheppo ldc_msg_t *pkt; 18131ae08745Sheppo 1814d10e4ef2Snarayan /* Obtain Tx lock */ 1815d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 1816d10e4ef2Snarayan 18171ae08745Sheppo /* 1818d10e4ef2Snarayan * Read the current Tx head and tail 18191ae08745Sheppo */ 18201ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 18211ae08745Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 18221ae08745Sheppo if (rv != 0) { 18231ae08745Sheppo cmn_err(CE_WARN, 18241ae08745Sheppo "i_ldc_process_data_ACK: (0x%lx) cannot read qptrs\n", 18251ae08745Sheppo ldcp->id); 1826d10e4ef2Snarayan 1827d10e4ef2Snarayan /* Reset the channel -- as we cannot continue */ 18283af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1829d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 1830d10e4ef2Snarayan return (ECONNRESET); 18311ae08745Sheppo } 18321ae08745Sheppo 18331ae08745Sheppo /* 18341ae08745Sheppo * loop from where the previous ACK location was to the 18351ae08745Sheppo * current head location. This is how far the HV has 18361ae08745Sheppo * actually send pkts. Pkts between head and tail are 18371ae08745Sheppo * yet to be sent by HV. 18381ae08745Sheppo */ 18391ae08745Sheppo tx_head = ldcp->tx_ackd_head; 18401ae08745Sheppo for (;;) { 18411ae08745Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_head); 18421ae08745Sheppo tx_head = (tx_head + LDC_PACKET_SIZE) % 18431ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 18441ae08745Sheppo 18451ae08745Sheppo if (pkt->seqid == msg->ackid) { 18461ae08745Sheppo D2(ldcp->id, 18471ae08745Sheppo "i_ldc_process_data_ACK: (0x%llx) found packet\n", 18481ae08745Sheppo ldcp->id); 18491ae08745Sheppo ldcp->last_ack_rcd = msg->ackid; 18501ae08745Sheppo ldcp->tx_ackd_head = tx_head; 18511ae08745Sheppo break; 18521ae08745Sheppo } 18531ae08745Sheppo if (tx_head == ldcp->tx_head) { 18541ae08745Sheppo /* could not find packet */ 18551ae08745Sheppo DWARN(ldcp->id, 18561ae08745Sheppo "i_ldc_process_data_ACK: (0x%llx) invalid ACKid\n", 18571ae08745Sheppo ldcp->id); 1858d10e4ef2Snarayan 1859d10e4ef2Snarayan /* Reset the channel -- as we cannot continue */ 18603af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1861d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 1862d10e4ef2Snarayan return (ECONNRESET); 18631ae08745Sheppo } 18641ae08745Sheppo } 18651ae08745Sheppo 1866d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 18671ae08745Sheppo return (0); 18681ae08745Sheppo } 18691ae08745Sheppo 18701ae08745Sheppo /* 18711ae08745Sheppo * Process incoming control message 18721ae08745Sheppo * Return 0 - session can continue 18731ae08745Sheppo * EAGAIN - reprocess packet - state was changed 18741ae08745Sheppo * ECONNRESET - channel was reset 18751ae08745Sheppo */ 18761ae08745Sheppo static int 18771ae08745Sheppo i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *msg) 18781ae08745Sheppo { 18791ae08745Sheppo int rv = 0; 18801ae08745Sheppo 18813af08d82Slm66018 D1(ldcp->id, "i_ldc_ctrlmsg: (%llx) tstate = %lx, hstate = %lx\n", 18823af08d82Slm66018 ldcp->id, ldcp->tstate, ldcp->hstate); 18833af08d82Slm66018 18843af08d82Slm66018 switch (ldcp->tstate & ~TS_IN_RESET) { 18851ae08745Sheppo 18861ae08745Sheppo case TS_OPEN: 18871ae08745Sheppo case TS_READY: 18881ae08745Sheppo 18891ae08745Sheppo switch (msg->ctrl & LDC_CTRL_MASK) { 18901ae08745Sheppo case LDC_VER: 18911ae08745Sheppo /* process version message */ 18921ae08745Sheppo rv = i_ldc_process_VER(ldcp, msg); 18931ae08745Sheppo break; 18941ae08745Sheppo default: 18951ae08745Sheppo DWARN(ldcp->id, 18961ae08745Sheppo "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x " 18971ae08745Sheppo "tstate=0x%x\n", ldcp->id, 18981ae08745Sheppo (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate); 18991ae08745Sheppo break; 19001ae08745Sheppo } 19011ae08745Sheppo 19021ae08745Sheppo break; 19031ae08745Sheppo 19041ae08745Sheppo case TS_VREADY: 19051ae08745Sheppo 19061ae08745Sheppo switch (msg->ctrl & LDC_CTRL_MASK) { 19071ae08745Sheppo case LDC_VER: 19083af08d82Slm66018 /* process version message */ 19093af08d82Slm66018 rv = i_ldc_process_VER(ldcp, msg); 19101ae08745Sheppo break; 19111ae08745Sheppo case LDC_RTS: 19121ae08745Sheppo /* process RTS message */ 19131ae08745Sheppo rv = i_ldc_process_RTS(ldcp, msg); 19141ae08745Sheppo break; 19151ae08745Sheppo case LDC_RTR: 19161ae08745Sheppo /* process RTR message */ 19171ae08745Sheppo rv = i_ldc_process_RTR(ldcp, msg); 19181ae08745Sheppo break; 19191ae08745Sheppo case LDC_RDX: 19201ae08745Sheppo /* process RDX message */ 19211ae08745Sheppo rv = i_ldc_process_RDX(ldcp, msg); 19221ae08745Sheppo break; 19231ae08745Sheppo default: 19241ae08745Sheppo DWARN(ldcp->id, 19251ae08745Sheppo "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x " 19261ae08745Sheppo "tstate=0x%x\n", ldcp->id, 19271ae08745Sheppo (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate); 19281ae08745Sheppo break; 19291ae08745Sheppo } 19301ae08745Sheppo 19311ae08745Sheppo break; 19321ae08745Sheppo 19331ae08745Sheppo case TS_UP: 19341ae08745Sheppo 19351ae08745Sheppo switch (msg->ctrl & LDC_CTRL_MASK) { 19361ae08745Sheppo case LDC_VER: 19371ae08745Sheppo DWARN(ldcp->id, 19381ae08745Sheppo "i_ldc_ctrlmsg: (0x%llx) unexpected VER " 19391ae08745Sheppo "- LDC reset\n", ldcp->id); 19401ae08745Sheppo /* peer is redoing version negotiation */ 1941d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 19421ae08745Sheppo (void) i_ldc_txq_reconf(ldcp); 19431ae08745Sheppo i_ldc_reset_state(ldcp); 1944d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 19451ae08745Sheppo rv = EAGAIN; 19461ae08745Sheppo break; 19471ae08745Sheppo 19481ae08745Sheppo case LDC_RDX: 19491ae08745Sheppo /* process RDX message */ 19501ae08745Sheppo rv = i_ldc_process_RDX(ldcp, msg); 19511ae08745Sheppo break; 19521ae08745Sheppo 19531ae08745Sheppo default: 19541ae08745Sheppo DWARN(ldcp->id, 19551ae08745Sheppo "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x " 19561ae08745Sheppo "tstate=0x%x\n", ldcp->id, 19571ae08745Sheppo (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate); 19581ae08745Sheppo break; 19591ae08745Sheppo } 19601ae08745Sheppo } 19611ae08745Sheppo 19621ae08745Sheppo return (rv); 19631ae08745Sheppo } 19641ae08745Sheppo 19651ae08745Sheppo /* 19661ae08745Sheppo * Register channel with the channel nexus 19671ae08745Sheppo */ 19681ae08745Sheppo static int 19691ae08745Sheppo i_ldc_register_channel(ldc_chan_t *ldcp) 19701ae08745Sheppo { 19711ae08745Sheppo int rv = 0; 19721ae08745Sheppo ldc_cnex_t *cinfo = &ldcssp->cinfo; 19731ae08745Sheppo 19741ae08745Sheppo if (cinfo->dip == NULL) { 19751ae08745Sheppo DWARN(ldcp->id, 19761ae08745Sheppo "i_ldc_register_channel: cnex has not registered\n"); 19771ae08745Sheppo return (EAGAIN); 19781ae08745Sheppo } 19791ae08745Sheppo 19801ae08745Sheppo rv = cinfo->reg_chan(cinfo->dip, ldcp->id, ldcp->devclass); 19811ae08745Sheppo if (rv) { 19821ae08745Sheppo DWARN(ldcp->id, 19831ae08745Sheppo "i_ldc_register_channel: cannot register channel\n"); 19841ae08745Sheppo return (rv); 19851ae08745Sheppo } 19861ae08745Sheppo 19871ae08745Sheppo rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR, 19881ae08745Sheppo i_ldc_tx_hdlr, ldcp, NULL); 19891ae08745Sheppo if (rv) { 19901ae08745Sheppo DWARN(ldcp->id, 19911ae08745Sheppo "i_ldc_register_channel: cannot add Tx interrupt\n"); 19921ae08745Sheppo (void) cinfo->unreg_chan(cinfo->dip, ldcp->id); 19931ae08745Sheppo return (rv); 19941ae08745Sheppo } 19951ae08745Sheppo 19961ae08745Sheppo rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR, 19971ae08745Sheppo i_ldc_rx_hdlr, ldcp, NULL); 19981ae08745Sheppo if (rv) { 19991ae08745Sheppo DWARN(ldcp->id, 20001ae08745Sheppo "i_ldc_register_channel: cannot add Rx interrupt\n"); 20011ae08745Sheppo (void) cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR); 20021ae08745Sheppo (void) cinfo->unreg_chan(cinfo->dip, ldcp->id); 20031ae08745Sheppo return (rv); 20041ae08745Sheppo } 20051ae08745Sheppo 20061ae08745Sheppo ldcp->tstate |= TS_CNEX_RDY; 20071ae08745Sheppo 20081ae08745Sheppo return (0); 20091ae08745Sheppo } 20101ae08745Sheppo 20111ae08745Sheppo /* 20121ae08745Sheppo * Unregister a channel with the channel nexus 20131ae08745Sheppo */ 20141ae08745Sheppo static int 20151ae08745Sheppo i_ldc_unregister_channel(ldc_chan_t *ldcp) 20161ae08745Sheppo { 20171ae08745Sheppo int rv = 0; 20181ae08745Sheppo ldc_cnex_t *cinfo = &ldcssp->cinfo; 20191ae08745Sheppo 20201ae08745Sheppo if (cinfo->dip == NULL) { 20211ae08745Sheppo DWARN(ldcp->id, 20221ae08745Sheppo "i_ldc_unregister_channel: cnex has not registered\n"); 20231ae08745Sheppo return (EAGAIN); 20241ae08745Sheppo } 20251ae08745Sheppo 20261ae08745Sheppo if (ldcp->tstate & TS_CNEX_RDY) { 20271ae08745Sheppo 2028d10e4ef2Snarayan /* Remove the Rx interrupt */ 20291ae08745Sheppo rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR); 20301ae08745Sheppo if (rv) { 20313af08d82Slm66018 if (rv != EAGAIN) { 20321ae08745Sheppo DWARN(ldcp->id, 20333af08d82Slm66018 "i_ldc_unregister_channel: err removing " 20343af08d82Slm66018 "Rx intr\n"); 2035d10e4ef2Snarayan return (rv); 20361ae08745Sheppo } 2037d10e4ef2Snarayan 20383af08d82Slm66018 /* 20393af08d82Slm66018 * If interrupts are pending and handler has 20403af08d82Slm66018 * finished running, clear interrupt and try 20413af08d82Slm66018 * again 20423af08d82Slm66018 */ 20433af08d82Slm66018 if (ldcp->rx_intr_state != LDC_INTR_PEND) 20443af08d82Slm66018 return (rv); 20453af08d82Slm66018 20463af08d82Slm66018 (void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 20473af08d82Slm66018 rv = cinfo->rem_intr(cinfo->dip, ldcp->id, 20483af08d82Slm66018 CNEX_RX_INTR); 20493af08d82Slm66018 if (rv) { 20503af08d82Slm66018 DWARN(ldcp->id, "i_ldc_unregister_channel: " 20513af08d82Slm66018 "err removing Rx interrupt\n"); 20523af08d82Slm66018 return (rv); 20533af08d82Slm66018 } 20543af08d82Slm66018 } 20553af08d82Slm66018 2056d10e4ef2Snarayan /* Remove the Tx interrupt */ 20571ae08745Sheppo rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR); 20581ae08745Sheppo if (rv) { 20591ae08745Sheppo DWARN(ldcp->id, 20601ae08745Sheppo "i_ldc_unregister_channel: err removing Tx intr\n"); 2061d10e4ef2Snarayan return (rv); 20621ae08745Sheppo } 2063d10e4ef2Snarayan 2064d10e4ef2Snarayan /* Unregister the channel */ 20651ae08745Sheppo rv = cinfo->unreg_chan(ldcssp->cinfo.dip, ldcp->id); 20661ae08745Sheppo if (rv) { 20671ae08745Sheppo DWARN(ldcp->id, 20681ae08745Sheppo "i_ldc_unregister_channel: cannot unreg channel\n"); 2069d10e4ef2Snarayan return (rv); 20701ae08745Sheppo } 20711ae08745Sheppo 20721ae08745Sheppo ldcp->tstate &= ~TS_CNEX_RDY; 20731ae08745Sheppo } 20741ae08745Sheppo 20751ae08745Sheppo return (0); 20761ae08745Sheppo } 20771ae08745Sheppo 20781ae08745Sheppo 20791ae08745Sheppo /* 20801ae08745Sheppo * LDC transmit interrupt handler 20811ae08745Sheppo * triggered for chanel up/down/reset events 20821ae08745Sheppo * and Tx queue content changes 20831ae08745Sheppo */ 20841ae08745Sheppo static uint_t 20851ae08745Sheppo i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2) 20861ae08745Sheppo { 20871ae08745Sheppo _NOTE(ARGUNUSED(arg2)) 20881ae08745Sheppo 20891ae08745Sheppo int rv; 20901ae08745Sheppo ldc_chan_t *ldcp; 20911ae08745Sheppo boolean_t notify_client = B_FALSE; 20923af08d82Slm66018 uint64_t notify_event = 0, link_state; 20931ae08745Sheppo 20941ae08745Sheppo /* Get the channel for which interrupt was received */ 20951ae08745Sheppo ASSERT(arg1 != NULL); 20961ae08745Sheppo ldcp = (ldc_chan_t *)arg1; 20971ae08745Sheppo 20981ae08745Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n", 20991ae08745Sheppo ldcp->id, ldcp); 21001ae08745Sheppo 21011ae08745Sheppo /* Lock channel */ 21021ae08745Sheppo mutex_enter(&ldcp->lock); 21031ae08745Sheppo 2104d10e4ef2Snarayan /* Obtain Tx lock */ 2105d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 2106d10e4ef2Snarayan 21074bac2208Snarayan /* mark interrupt as pending */ 21083af08d82Slm66018 ldcp->tx_intr_state = LDC_INTR_ACTIVE; 21093af08d82Slm66018 21103af08d82Slm66018 /* save current link state */ 21113af08d82Slm66018 link_state = ldcp->link_state; 21124bac2208Snarayan 21131ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id, &ldcp->tx_head, &ldcp->tx_tail, 21141ae08745Sheppo &ldcp->link_state); 21151ae08745Sheppo if (rv) { 21161ae08745Sheppo cmn_err(CE_WARN, 21171ae08745Sheppo "i_ldc_tx_hdlr: (0x%lx) cannot read queue ptrs rv=0x%d\n", 21181ae08745Sheppo ldcp->id, rv); 21194bac2208Snarayan i_ldc_clear_intr(ldcp, CNEX_TX_INTR); 2120d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 21211ae08745Sheppo mutex_exit(&ldcp->lock); 21221ae08745Sheppo return (DDI_INTR_CLAIMED); 21231ae08745Sheppo } 21241ae08745Sheppo 21251ae08745Sheppo /* 21261ae08745Sheppo * reset the channel state if the channel went down 21271ae08745Sheppo * (other side unconfigured queue) or channel was reset 21281ae08745Sheppo * (other side reconfigured its queue) 21291ae08745Sheppo */ 21303af08d82Slm66018 if (link_state != ldcp->link_state && 21313af08d82Slm66018 ldcp->link_state == LDC_CHANNEL_DOWN) { 21321ae08745Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: channel link down\n", ldcp->id); 21333af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 21341ae08745Sheppo notify_client = B_TRUE; 21351ae08745Sheppo notify_event = LDC_EVT_DOWN; 21361ae08745Sheppo } 21371ae08745Sheppo 21383af08d82Slm66018 if (link_state != ldcp->link_state && 21393af08d82Slm66018 ldcp->link_state == LDC_CHANNEL_RESET) { 21401ae08745Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: channel link reset\n", ldcp->id); 21413af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 21421ae08745Sheppo notify_client = B_TRUE; 21431ae08745Sheppo notify_event = LDC_EVT_RESET; 21441ae08745Sheppo } 21451ae08745Sheppo 21463af08d82Slm66018 if (link_state != ldcp->link_state && 21473af08d82Slm66018 (ldcp->tstate & ~TS_IN_RESET) == TS_OPEN && 21483af08d82Slm66018 ldcp->link_state == LDC_CHANNEL_UP) { 21491ae08745Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: channel link up\n", ldcp->id); 21501ae08745Sheppo notify_client = B_TRUE; 21511ae08745Sheppo notify_event = LDC_EVT_RESET; 21521ae08745Sheppo ldcp->tstate |= TS_LINK_READY; 21531ae08745Sheppo ldcp->status = LDC_READY; 21541ae08745Sheppo } 21551ae08745Sheppo 21561ae08745Sheppo /* if callbacks are disabled, do not notify */ 21571ae08745Sheppo if (!ldcp->cb_enabled) 21581ae08745Sheppo notify_client = B_FALSE; 21591ae08745Sheppo 21604d39be2bSsg70180 i_ldc_clear_intr(ldcp, CNEX_TX_INTR); 216122f747efSnarayan mutex_exit(&ldcp->tx_lock); 21621ae08745Sheppo 21631ae08745Sheppo if (notify_client) { 21643af08d82Slm66018 ldcp->cb_inprogress = B_TRUE; 21653af08d82Slm66018 mutex_exit(&ldcp->lock); 21661ae08745Sheppo rv = ldcp->cb(notify_event, ldcp->cb_arg); 21671ae08745Sheppo if (rv) { 21681ae08745Sheppo DWARN(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) callback " 21691ae08745Sheppo "failure", ldcp->id); 21701ae08745Sheppo } 21711ae08745Sheppo mutex_enter(&ldcp->lock); 21721ae08745Sheppo ldcp->cb_inprogress = B_FALSE; 21731ae08745Sheppo } 21741ae08745Sheppo 21751ae08745Sheppo mutex_exit(&ldcp->lock); 21761ae08745Sheppo 21771ae08745Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) exiting handler", ldcp->id); 21781ae08745Sheppo 21791ae08745Sheppo return (DDI_INTR_CLAIMED); 21801ae08745Sheppo } 21811ae08745Sheppo 21821ae08745Sheppo /* 218358283286Sha137994 * Process the Rx HV queue. 218458283286Sha137994 * 218558283286Sha137994 * Returns 0 if data packets were found and no errors were encountered, 218658283286Sha137994 * otherwise returns an error. In either case, the *notify argument is 218758283286Sha137994 * set to indicate whether or not the client callback function should 218858283286Sha137994 * be invoked. The *event argument is set to contain the callback event. 218958283286Sha137994 * 219058283286Sha137994 * Depending on the channel mode, packets are handled differently: 219158283286Sha137994 * 219258283286Sha137994 * RAW MODE 219358283286Sha137994 * For raw mode channels, when a data packet is encountered, 219458283286Sha137994 * processing stops and all packets are left on the queue to be removed 219558283286Sha137994 * and processed by the ldc_read code path. 219658283286Sha137994 * 219758283286Sha137994 * UNRELIABLE MODE 219858283286Sha137994 * For unreliable mode, when a data packet is encountered, processing 219958283286Sha137994 * stops, and all packets are left on the queue to be removed and 220058283286Sha137994 * processed by the ldc_read code path. Control packets are processed 220158283286Sha137994 * inline if they are encountered before any data packets. 220258283286Sha137994 * 220320ae46ebSha137994 * RELIABLE MODE 220420ae46ebSha137994 * For reliable mode channels, all packets on the receive queue 220558283286Sha137994 * are processed: data packets are copied to the data queue and 220658283286Sha137994 * control packets are processed inline. Packets are only left on 220758283286Sha137994 * the receive queue when the data queue is full. 22081ae08745Sheppo */ 22091ae08745Sheppo static uint_t 221058283286Sha137994 i_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client, 221158283286Sha137994 uint64_t *notify_event) 22121ae08745Sheppo { 22131ae08745Sheppo int rv; 22141ae08745Sheppo uint64_t rx_head, rx_tail; 22151ae08745Sheppo ldc_msg_t *msg; 22163af08d82Slm66018 uint64_t link_state, first_fragment = 0; 221758283286Sha137994 boolean_t trace_length = B_TRUE; 22183af08d82Slm66018 221958283286Sha137994 ASSERT(MUTEX_HELD(&ldcp->lock)); 222058283286Sha137994 *notify_client = B_FALSE; 222158283286Sha137994 *notify_event = 0; 22221ae08745Sheppo 22231ae08745Sheppo /* 22241ae08745Sheppo * Read packet(s) from the queue 22251ae08745Sheppo */ 22261ae08745Sheppo for (;;) { 22271ae08745Sheppo 22283af08d82Slm66018 link_state = ldcp->link_state; 22291ae08745Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 22301ae08745Sheppo &ldcp->link_state); 22311ae08745Sheppo if (rv) { 22321ae08745Sheppo cmn_err(CE_WARN, 223358283286Sha137994 "i_ldc_rx_process_hvq: (0x%lx) cannot read " 22341ae08745Sheppo "queue ptrs, rv=0x%d\n", ldcp->id, rv); 22351ae08745Sheppo i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 223658283286Sha137994 return (EIO); 22371ae08745Sheppo } 22381ae08745Sheppo 22391ae08745Sheppo /* 22401ae08745Sheppo * reset the channel state if the channel went down 22411ae08745Sheppo * (other side unconfigured queue) or channel was reset 22423af08d82Slm66018 * (other side reconfigured its queue) 22431ae08745Sheppo */ 22443af08d82Slm66018 22453af08d82Slm66018 if (link_state != ldcp->link_state) { 2246cb112a14Slm66018 22473af08d82Slm66018 switch (ldcp->link_state) { 22483af08d82Slm66018 case LDC_CHANNEL_DOWN: 224958283286Sha137994 D1(ldcp->id, "i_ldc_rx_process_hvq: channel " 22503af08d82Slm66018 "link down\n", ldcp->id); 2251d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 22523af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 2253d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 225458283286Sha137994 *notify_client = B_TRUE; 225558283286Sha137994 *notify_event = LDC_EVT_DOWN; 22563af08d82Slm66018 goto loop_exit; 22571ae08745Sheppo 22583af08d82Slm66018 case LDC_CHANNEL_UP: 225958283286Sha137994 D1(ldcp->id, "i_ldc_rx_process_hvq: " 22603af08d82Slm66018 "channel link up\n", ldcp->id); 22613af08d82Slm66018 22623af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) == TS_OPEN) { 226358283286Sha137994 *notify_client = B_TRUE; 226458283286Sha137994 *notify_event = LDC_EVT_RESET; 22651ae08745Sheppo ldcp->tstate |= TS_LINK_READY; 22661ae08745Sheppo ldcp->status = LDC_READY; 22671ae08745Sheppo } 22683af08d82Slm66018 break; 22693af08d82Slm66018 22703af08d82Slm66018 case LDC_CHANNEL_RESET: 22713af08d82Slm66018 default: 22723af08d82Slm66018 #ifdef DEBUG 22733af08d82Slm66018 force_reset: 22743af08d82Slm66018 #endif 227558283286Sha137994 D1(ldcp->id, "i_ldc_rx_process_hvq: channel " 22763af08d82Slm66018 "link reset\n", ldcp->id); 22773af08d82Slm66018 mutex_enter(&ldcp->tx_lock); 22783af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 22793af08d82Slm66018 mutex_exit(&ldcp->tx_lock); 228058283286Sha137994 *notify_client = B_TRUE; 228158283286Sha137994 *notify_event = LDC_EVT_RESET; 22823af08d82Slm66018 break; 22833af08d82Slm66018 } 22843af08d82Slm66018 } 22853af08d82Slm66018 22863af08d82Slm66018 #ifdef DEBUG 22873af08d82Slm66018 if (LDC_INJECT_RESET(ldcp)) 22883af08d82Slm66018 goto force_reset; 2289bbfa0259Sha137994 if (LDC_INJECT_DRNGCLEAR(ldcp)) 2290bbfa0259Sha137994 i_ldc_mem_inject_dring_clear(ldcp); 22913af08d82Slm66018 #endif 229258283286Sha137994 if (trace_length) { 229358283286Sha137994 TRACE_RXHVQ_LENGTH(ldcp, rx_head, rx_tail); 229458283286Sha137994 trace_length = B_FALSE; 229558283286Sha137994 } 22961ae08745Sheppo 22971ae08745Sheppo if (rx_head == rx_tail) { 229858283286Sha137994 D2(ldcp->id, "i_ldc_rx_process_hvq: (0x%llx) " 229958283286Sha137994 "No packets\n", ldcp->id); 23001ae08745Sheppo break; 23011ae08745Sheppo } 23023af08d82Slm66018 230358283286Sha137994 D2(ldcp->id, "i_ldc_rx_process_hvq: head=0x%llx, " 230458283286Sha137994 "tail=0x%llx\n", rx_head, rx_tail); 230558283286Sha137994 DUMP_LDC_PKT(ldcp, "i_ldc_rx_process_hvq rcd", 23061ae08745Sheppo ldcp->rx_q_va + rx_head); 23071ae08745Sheppo 23081ae08745Sheppo /* get the message */ 23091ae08745Sheppo msg = (ldc_msg_t *)(ldcp->rx_q_va + rx_head); 23101ae08745Sheppo 23111ae08745Sheppo /* if channel is in RAW mode or data pkt, notify and return */ 23121ae08745Sheppo if (ldcp->mode == LDC_MODE_RAW) { 231358283286Sha137994 *notify_client = B_TRUE; 231458283286Sha137994 *notify_event |= LDC_EVT_READ; 23151ae08745Sheppo break; 23161ae08745Sheppo } 23171ae08745Sheppo 23181ae08745Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) { 23191ae08745Sheppo 23201ae08745Sheppo /* discard packet if channel is not up */ 23213af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) != TS_UP) { 23221ae08745Sheppo 23231ae08745Sheppo /* move the head one position */ 23241ae08745Sheppo rx_head = (rx_head + LDC_PACKET_SIZE) % 23251ae08745Sheppo (ldcp->rx_q_entries << LDC_PACKET_SHIFT); 23261ae08745Sheppo 23271ae08745Sheppo if (rv = i_ldc_set_rx_head(ldcp, rx_head)) 23281ae08745Sheppo break; 23291ae08745Sheppo 23301ae08745Sheppo continue; 23311ae08745Sheppo } else { 233258283286Sha137994 uint64_t dq_head, dq_tail; 233358283286Sha137994 233420ae46ebSha137994 /* process only RELIABLE mode data packets */ 233520ae46ebSha137994 if (ldcp->mode != LDC_MODE_RELIABLE) { 23363af08d82Slm66018 if ((ldcp->tstate & TS_IN_RESET) == 0) 233758283286Sha137994 *notify_client = B_TRUE; 233858283286Sha137994 *notify_event |= LDC_EVT_READ; 23391ae08745Sheppo break; 23401ae08745Sheppo } 234158283286Sha137994 234258283286Sha137994 /* don't process packet if queue full */ 234358283286Sha137994 (void) i_ldc_dq_rx_get_state(ldcp, &dq_head, 234458283286Sha137994 &dq_tail, NULL); 234558283286Sha137994 dq_tail = (dq_tail + LDC_PACKET_SIZE) % 234658283286Sha137994 (ldcp->rx_dq_entries << LDC_PACKET_SHIFT); 234758283286Sha137994 if (dq_tail == dq_head || 234858283286Sha137994 LDC_INJECT_DQFULL(ldcp)) { 234958283286Sha137994 rv = ENOSPC; 235058283286Sha137994 break; 235158283286Sha137994 } 235258283286Sha137994 } 23531ae08745Sheppo } 23541ae08745Sheppo 23551ae08745Sheppo /* Check the sequence ID for the message received */ 23563af08d82Slm66018 rv = i_ldc_check_seqid(ldcp, msg); 23573af08d82Slm66018 if (rv != 0) { 23581ae08745Sheppo 235958283286Sha137994 DWARN(ldcp->id, "i_ldc_rx_process_hvq: (0x%llx) " 236058283286Sha137994 "seqid error, q_ptrs=0x%lx,0x%lx", ldcp->id, 236158283286Sha137994 rx_head, rx_tail); 23621ae08745Sheppo 23631ae08745Sheppo /* Reset last_msg_rcd to start of message */ 2364d10e4ef2Snarayan if (first_fragment != 0) { 2365d10e4ef2Snarayan ldcp->last_msg_rcd = first_fragment - 1; 2366d10e4ef2Snarayan first_fragment = 0; 23671ae08745Sheppo } 2368d10e4ef2Snarayan 23691ae08745Sheppo /* 23701ae08745Sheppo * Send a NACK due to seqid mismatch 23711ae08745Sheppo */ 237222f747efSnarayan rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK, 23731ae08745Sheppo (msg->ctrl & LDC_CTRL_MASK)); 23741ae08745Sheppo 23751ae08745Sheppo if (rv) { 237658283286Sha137994 cmn_err(CE_NOTE, "i_ldc_rx_process_hvq: " 237758283286Sha137994 "(0x%lx) err sending CTRL/DATA NACK msg\n", 237858283286Sha137994 ldcp->id); 2379d10e4ef2Snarayan 2380d10e4ef2Snarayan /* if cannot send NACK - reset channel */ 2381d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 23823af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 2383d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 238483d3bc6fSnarayan 238558283286Sha137994 *notify_client = B_TRUE; 238658283286Sha137994 *notify_event = LDC_EVT_RESET; 2387d10e4ef2Snarayan break; 23881ae08745Sheppo } 23891ae08745Sheppo 23901ae08745Sheppo /* purge receive queue */ 23911ae08745Sheppo (void) i_ldc_set_rx_head(ldcp, rx_tail); 23921ae08745Sheppo break; 23931ae08745Sheppo } 23941ae08745Sheppo 23951ae08745Sheppo /* record the message ID */ 23961ae08745Sheppo ldcp->last_msg_rcd = msg->seqid; 23971ae08745Sheppo 23981ae08745Sheppo /* process control messages */ 23991ae08745Sheppo if (msg->type & LDC_CTRL) { 24001ae08745Sheppo /* save current internal state */ 24011ae08745Sheppo uint64_t tstate = ldcp->tstate; 24021ae08745Sheppo 24031ae08745Sheppo rv = i_ldc_ctrlmsg(ldcp, msg); 24041ae08745Sheppo if (rv == EAGAIN) { 24051ae08745Sheppo /* re-process pkt - state was adjusted */ 24061ae08745Sheppo continue; 24071ae08745Sheppo } 24081ae08745Sheppo if (rv == ECONNRESET) { 240958283286Sha137994 *notify_client = B_TRUE; 241058283286Sha137994 *notify_event = LDC_EVT_RESET; 24111ae08745Sheppo break; 24121ae08745Sheppo } 24131ae08745Sheppo 24141ae08745Sheppo /* 24151ae08745Sheppo * control message processing was successful 24161ae08745Sheppo * channel transitioned to ready for communication 24171ae08745Sheppo */ 24181ae08745Sheppo if (rv == 0 && ldcp->tstate == TS_UP && 24193af08d82Slm66018 (tstate & ~TS_IN_RESET) != 24203af08d82Slm66018 (ldcp->tstate & ~TS_IN_RESET)) { 242158283286Sha137994 *notify_client = B_TRUE; 242258283286Sha137994 *notify_event = LDC_EVT_UP; 24231ae08745Sheppo } 24241ae08745Sheppo } 24251ae08745Sheppo 242683d3bc6fSnarayan /* process data NACKs */ 242783d3bc6fSnarayan if ((msg->type & LDC_DATA) && (msg->stype & LDC_NACK)) { 242883d3bc6fSnarayan DWARN(ldcp->id, 242958283286Sha137994 "i_ldc_rx_process_hvq: (0x%llx) received DATA/NACK", 243083d3bc6fSnarayan ldcp->id); 243183d3bc6fSnarayan mutex_enter(&ldcp->tx_lock); 243283d3bc6fSnarayan i_ldc_reset(ldcp, B_TRUE); 243383d3bc6fSnarayan mutex_exit(&ldcp->tx_lock); 243458283286Sha137994 *notify_client = B_TRUE; 243558283286Sha137994 *notify_event = LDC_EVT_RESET; 243683d3bc6fSnarayan break; 243783d3bc6fSnarayan } 243883d3bc6fSnarayan 24391ae08745Sheppo /* process data ACKs */ 24401ae08745Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) { 2441d10e4ef2Snarayan if (rv = i_ldc_process_data_ACK(ldcp, msg)) { 244258283286Sha137994 *notify_client = B_TRUE; 244358283286Sha137994 *notify_event = LDC_EVT_RESET; 2444d10e4ef2Snarayan break; 2445d10e4ef2Snarayan } 24461ae08745Sheppo } 24471ae08745Sheppo 244858283286Sha137994 if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) { 244920ae46ebSha137994 ASSERT(ldcp->mode == LDC_MODE_RELIABLE); 245058283286Sha137994 245158283286Sha137994 /* 245258283286Sha137994 * Copy the data packet to the data queue. Note 245358283286Sha137994 * that the copy routine updates the rx_head pointer. 245458283286Sha137994 */ 245558283286Sha137994 i_ldc_rxdq_copy(ldcp, &rx_head); 245658283286Sha137994 245758283286Sha137994 if ((ldcp->tstate & TS_IN_RESET) == 0) 245858283286Sha137994 *notify_client = B_TRUE; 245958283286Sha137994 *notify_event |= LDC_EVT_READ; 246058283286Sha137994 } else { 24611ae08745Sheppo rx_head = (rx_head + LDC_PACKET_SIZE) % 24621ae08745Sheppo (ldcp->rx_q_entries << LDC_PACKET_SHIFT); 246358283286Sha137994 } 246458283286Sha137994 246558283286Sha137994 /* move the head one position */ 24660a55fbb7Slm66018 if (rv = i_ldc_set_rx_head(ldcp, rx_head)) { 246758283286Sha137994 *notify_client = B_TRUE; 246858283286Sha137994 *notify_event = LDC_EVT_RESET; 24691ae08745Sheppo break; 24700a55fbb7Slm66018 } 24711ae08745Sheppo 24721ae08745Sheppo } /* for */ 24731ae08745Sheppo 24743af08d82Slm66018 loop_exit: 24753af08d82Slm66018 247620ae46ebSha137994 if (ldcp->mode == LDC_MODE_RELIABLE) { 247758283286Sha137994 /* ACK data packets */ 247858283286Sha137994 if ((*notify_event & 247958283286Sha137994 (LDC_EVT_READ | LDC_EVT_RESET)) == LDC_EVT_READ) { 248058283286Sha137994 int ack_rv; 248158283286Sha137994 ack_rv = i_ldc_send_pkt(ldcp, LDC_DATA, LDC_ACK, 0); 248258283286Sha137994 if (ack_rv && ack_rv != EWOULDBLOCK) { 248358283286Sha137994 cmn_err(CE_NOTE, 248458283286Sha137994 "i_ldc_rx_process_hvq: (0x%lx) cannot " 248558283286Sha137994 "send ACK\n", ldcp->id); 248658283286Sha137994 248758283286Sha137994 mutex_enter(&ldcp->tx_lock); 248858283286Sha137994 i_ldc_reset(ldcp, B_FALSE); 248958283286Sha137994 mutex_exit(&ldcp->tx_lock); 249058283286Sha137994 249158283286Sha137994 *notify_client = B_TRUE; 249258283286Sha137994 *notify_event = LDC_EVT_RESET; 249358283286Sha137994 goto skip_ackpeek; 249458283286Sha137994 } 249558283286Sha137994 } 24961ae08745Sheppo 24973af08d82Slm66018 /* 249858283286Sha137994 * If we have no more space on the data queue, make sure 249958283286Sha137994 * there are no ACKs on the rx queue waiting to be processed. 25003af08d82Slm66018 */ 250158283286Sha137994 if (rv == ENOSPC) { 250258283286Sha137994 if (i_ldc_rx_ackpeek(ldcp, rx_head, rx_tail) != 0) { 250358283286Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID; 250458283286Sha137994 *notify_client = B_TRUE; 250558283286Sha137994 *notify_event = LDC_EVT_RESET; 25061ae08745Sheppo } 250712f80fa6Sha137994 return (rv); 250858283286Sha137994 } else { 250958283286Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID; 251058283286Sha137994 } 25111ae08745Sheppo } 25121ae08745Sheppo 251358283286Sha137994 skip_ackpeek: 25144d39be2bSsg70180 251558283286Sha137994 /* Return, indicating whether or not data packets were found */ 251658283286Sha137994 if ((*notify_event & (LDC_EVT_READ | LDC_EVT_RESET)) == LDC_EVT_READ) 251758283286Sha137994 return (0); 251858283286Sha137994 251958283286Sha137994 return (ENOMSG); 25201ae08745Sheppo } 25211ae08745Sheppo 252258283286Sha137994 /* 252358283286Sha137994 * Process any ACK packets on the HV receive queue. 252458283286Sha137994 * 252520ae46ebSha137994 * This function is only used by RELIABLE mode channels when the 252658283286Sha137994 * secondary data queue fills up and there are packets remaining on 252758283286Sha137994 * the HV receive queue. 252858283286Sha137994 */ 252958283286Sha137994 int 253058283286Sha137994 i_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head, uint64_t rx_tail) 253158283286Sha137994 { 253258283286Sha137994 int rv = 0; 253358283286Sha137994 ldc_msg_t *msg; 253458283286Sha137994 253558283286Sha137994 if (ldcp->rx_ack_head == ACKPEEK_HEAD_INVALID) 253658283286Sha137994 ldcp->rx_ack_head = rx_head; 253758283286Sha137994 253858283286Sha137994 while (ldcp->rx_ack_head != rx_tail) { 253958283286Sha137994 msg = (ldc_msg_t *)(ldcp->rx_q_va + ldcp->rx_ack_head); 254058283286Sha137994 254158283286Sha137994 if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) { 254258283286Sha137994 if (rv = i_ldc_process_data_ACK(ldcp, msg)) 254358283286Sha137994 break; 254458283286Sha137994 msg->stype &= ~LDC_ACK; 254558283286Sha137994 } 254658283286Sha137994 254758283286Sha137994 ldcp->rx_ack_head = 254858283286Sha137994 (ldcp->rx_ack_head + LDC_PACKET_SIZE) % 254958283286Sha137994 (ldcp->rx_q_entries << LDC_PACKET_SHIFT); 255058283286Sha137994 } 255158283286Sha137994 return (rv); 255258283286Sha137994 } 25531ae08745Sheppo 25541ae08745Sheppo /* -------------------------------------------------------------------------- */ 25551ae08745Sheppo 25561ae08745Sheppo /* 25571ae08745Sheppo * LDC API functions 25581ae08745Sheppo */ 25591ae08745Sheppo 25601ae08745Sheppo /* 25611ae08745Sheppo * Initialize the channel. Allocate internal structure and memory for 25621ae08745Sheppo * TX/RX queues, and initialize locks. 25631ae08745Sheppo */ 25641ae08745Sheppo int 25651ae08745Sheppo ldc_init(uint64_t id, ldc_attr_t *attr, ldc_handle_t *handle) 25661ae08745Sheppo { 25671ae08745Sheppo ldc_chan_t *ldcp; 25681ae08745Sheppo int rv, exit_val; 25691ae08745Sheppo uint64_t ra_base, nentries; 2570e1ebb9ecSlm66018 uint64_t qlen; 25711ae08745Sheppo 25721ae08745Sheppo exit_val = EINVAL; /* guarantee an error if exit on failure */ 25731ae08745Sheppo 25741ae08745Sheppo if (attr == NULL) { 25751ae08745Sheppo DWARN(id, "ldc_init: (0x%llx) invalid attr\n", id); 25761ae08745Sheppo return (EINVAL); 25771ae08745Sheppo } 25781ae08745Sheppo if (handle == NULL) { 25791ae08745Sheppo DWARN(id, "ldc_init: (0x%llx) invalid handle\n", id); 25801ae08745Sheppo return (EINVAL); 25811ae08745Sheppo } 25821ae08745Sheppo 25831ae08745Sheppo /* check if channel is valid */ 25841ae08745Sheppo rv = hv_ldc_tx_qinfo(id, &ra_base, &nentries); 25851ae08745Sheppo if (rv == H_ECHANNEL) { 25861ae08745Sheppo DWARN(id, "ldc_init: (0x%llx) invalid channel id\n", id); 25871ae08745Sheppo return (EINVAL); 25881ae08745Sheppo } 25891ae08745Sheppo 25901ae08745Sheppo /* check if the channel has already been initialized */ 25911ae08745Sheppo mutex_enter(&ldcssp->lock); 25921ae08745Sheppo ldcp = ldcssp->chan_list; 25931ae08745Sheppo while (ldcp != NULL) { 25941ae08745Sheppo if (ldcp->id == id) { 25951ae08745Sheppo DWARN(id, "ldc_init: (0x%llx) already initialized\n", 25961ae08745Sheppo id); 25971ae08745Sheppo mutex_exit(&ldcssp->lock); 25981ae08745Sheppo return (EADDRINUSE); 25991ae08745Sheppo } 26001ae08745Sheppo ldcp = ldcp->next; 26011ae08745Sheppo } 26021ae08745Sheppo mutex_exit(&ldcssp->lock); 26031ae08745Sheppo 26041ae08745Sheppo ASSERT(ldcp == NULL); 26051ae08745Sheppo 26061ae08745Sheppo *handle = 0; 26071ae08745Sheppo 26081ae08745Sheppo /* Allocate an ldcp structure */ 26091ae08745Sheppo ldcp = kmem_zalloc(sizeof (ldc_chan_t), KM_SLEEP); 26101ae08745Sheppo 2611d10e4ef2Snarayan /* 2612d10e4ef2Snarayan * Initialize the channel and Tx lock 2613d10e4ef2Snarayan * 2614d10e4ef2Snarayan * The channel 'lock' protects the entire channel and 2615d10e4ef2Snarayan * should be acquired before initializing, resetting, 2616d10e4ef2Snarayan * destroying or reading from a channel. 2617d10e4ef2Snarayan * 2618d10e4ef2Snarayan * The 'tx_lock' should be acquired prior to transmitting 2619d10e4ef2Snarayan * data over the channel. The lock should also be acquired 2620d10e4ef2Snarayan * prior to channel reconfiguration (in order to prevent 2621d10e4ef2Snarayan * concurrent writes). 2622d10e4ef2Snarayan * 2623d10e4ef2Snarayan * ORDERING: When both locks are being acquired, to prevent 2624d10e4ef2Snarayan * deadlocks, the channel lock should be always acquired prior 2625d10e4ef2Snarayan * to the tx_lock. 2626d10e4ef2Snarayan */ 26271ae08745Sheppo mutex_init(&ldcp->lock, NULL, MUTEX_DRIVER, NULL); 2628d10e4ef2Snarayan mutex_init(&ldcp->tx_lock, NULL, MUTEX_DRIVER, NULL); 26291ae08745Sheppo 26301ae08745Sheppo /* Initialize the channel */ 26311ae08745Sheppo ldcp->id = id; 26321ae08745Sheppo ldcp->cb = NULL; 26331ae08745Sheppo ldcp->cb_arg = NULL; 26341ae08745Sheppo ldcp->cb_inprogress = B_FALSE; 26351ae08745Sheppo ldcp->cb_enabled = B_FALSE; 26361ae08745Sheppo ldcp->next = NULL; 26371ae08745Sheppo 26381ae08745Sheppo /* Read attributes */ 26391ae08745Sheppo ldcp->mode = attr->mode; 26401ae08745Sheppo ldcp->devclass = attr->devclass; 26411ae08745Sheppo ldcp->devinst = attr->instance; 2642e1ebb9ecSlm66018 ldcp->mtu = (attr->mtu > 0) ? attr->mtu : LDC_DEFAULT_MTU; 26431ae08745Sheppo 26441ae08745Sheppo D1(ldcp->id, 26451ae08745Sheppo "ldc_init: (0x%llx) channel attributes, class=0x%x, " 2646e1ebb9ecSlm66018 "instance=0x%llx, mode=%d, mtu=%d\n", 2647e1ebb9ecSlm66018 ldcp->id, ldcp->devclass, ldcp->devinst, ldcp->mode, ldcp->mtu); 26481ae08745Sheppo 26491ae08745Sheppo ldcp->next_vidx = 0; 26503af08d82Slm66018 ldcp->tstate = TS_IN_RESET; 26511ae08745Sheppo ldcp->hstate = 0; 26521ae08745Sheppo ldcp->last_msg_snt = LDC_INIT_SEQID; 26531ae08745Sheppo ldcp->last_ack_rcd = 0; 26541ae08745Sheppo ldcp->last_msg_rcd = 0; 265558283286Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID; 26561ae08745Sheppo 26571ae08745Sheppo ldcp->stream_bufferp = NULL; 26581ae08745Sheppo ldcp->exp_dring_list = NULL; 26591ae08745Sheppo ldcp->imp_dring_list = NULL; 26601ae08745Sheppo ldcp->mhdl_list = NULL; 26611ae08745Sheppo 26623af08d82Slm66018 ldcp->tx_intr_state = LDC_INTR_NONE; 26633af08d82Slm66018 ldcp->rx_intr_state = LDC_INTR_NONE; 26643af08d82Slm66018 26651ae08745Sheppo /* Initialize payload size depending on whether channel is reliable */ 26661ae08745Sheppo switch (ldcp->mode) { 26671ae08745Sheppo case LDC_MODE_RAW: 26681ae08745Sheppo ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RAW; 26691ae08745Sheppo ldcp->read_p = i_ldc_read_raw; 26701ae08745Sheppo ldcp->write_p = i_ldc_write_raw; 26711ae08745Sheppo break; 26721ae08745Sheppo case LDC_MODE_UNRELIABLE: 26731ae08745Sheppo ldcp->pkt_payload = LDC_PAYLOAD_SIZE_UNRELIABLE; 26741ae08745Sheppo ldcp->read_p = i_ldc_read_packet; 26751ae08745Sheppo ldcp->write_p = i_ldc_write_packet; 26761ae08745Sheppo break; 26771ae08745Sheppo case LDC_MODE_RELIABLE: 26781ae08745Sheppo ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RELIABLE; 26791ae08745Sheppo 26801ae08745Sheppo ldcp->stream_remains = 0; 26811ae08745Sheppo ldcp->stream_offset = 0; 26821ae08745Sheppo ldcp->stream_bufferp = kmem_alloc(ldcp->mtu, KM_SLEEP); 26831ae08745Sheppo ldcp->read_p = i_ldc_read_stream; 26841ae08745Sheppo ldcp->write_p = i_ldc_write_stream; 26851ae08745Sheppo break; 26861ae08745Sheppo default: 26871ae08745Sheppo exit_val = EINVAL; 26881ae08745Sheppo goto cleanup_on_exit; 26891ae08745Sheppo } 26901ae08745Sheppo 2691e1ebb9ecSlm66018 /* 2692e1ebb9ecSlm66018 * qlen is (mtu * ldc_mtu_msgs) / pkt_payload. If this 2693e1ebb9ecSlm66018 * value is smaller than default length of ldc_queue_entries, 269422f747efSnarayan * qlen is set to ldc_queue_entries. Ensure that computed 269522f747efSnarayan * length is a power-of-two value. 2696e1ebb9ecSlm66018 */ 2697e1ebb9ecSlm66018 qlen = (ldcp->mtu * ldc_mtu_msgs) / ldcp->pkt_payload; 269822f747efSnarayan if (!ISP2(qlen)) { 269922f747efSnarayan uint64_t tmp = 1; 270022f747efSnarayan while (qlen) { 270122f747efSnarayan qlen >>= 1; tmp <<= 1; 270222f747efSnarayan } 270322f747efSnarayan qlen = tmp; 270422f747efSnarayan } 270522f747efSnarayan 2706e1ebb9ecSlm66018 ldcp->rx_q_entries = 2707e1ebb9ecSlm66018 (qlen < ldc_queue_entries) ? ldc_queue_entries : qlen; 2708e1ebb9ecSlm66018 ldcp->tx_q_entries = ldcp->rx_q_entries; 2709e1ebb9ecSlm66018 271022f747efSnarayan D1(ldcp->id, "ldc_init: queue length = 0x%llx\n", ldcp->rx_q_entries); 2711e1ebb9ecSlm66018 27121ae08745Sheppo /* Create a transmit queue */ 27131ae08745Sheppo ldcp->tx_q_va = (uint64_t) 27141ae08745Sheppo contig_mem_alloc(ldcp->tx_q_entries << LDC_PACKET_SHIFT); 27151ae08745Sheppo if (ldcp->tx_q_va == NULL) { 27161ae08745Sheppo cmn_err(CE_WARN, 27171ae08745Sheppo "ldc_init: (0x%lx) TX queue allocation failed\n", 27181ae08745Sheppo ldcp->id); 27191ae08745Sheppo exit_val = ENOMEM; 27201ae08745Sheppo goto cleanup_on_exit; 27211ae08745Sheppo } 27221ae08745Sheppo ldcp->tx_q_ra = va_to_pa((caddr_t)ldcp->tx_q_va); 27231ae08745Sheppo 27241ae08745Sheppo D2(ldcp->id, "ldc_init: txq_va=0x%llx, txq_ra=0x%llx, entries=0x%llx\n", 27251ae08745Sheppo ldcp->tx_q_va, ldcp->tx_q_ra, ldcp->tx_q_entries); 27261ae08745Sheppo 27271ae08745Sheppo ldcp->tstate |= TS_TXQ_RDY; 27281ae08745Sheppo 27291ae08745Sheppo /* Create a receive queue */ 27301ae08745Sheppo ldcp->rx_q_va = (uint64_t) 27311ae08745Sheppo contig_mem_alloc(ldcp->rx_q_entries << LDC_PACKET_SHIFT); 27321ae08745Sheppo if (ldcp->rx_q_va == NULL) { 27331ae08745Sheppo cmn_err(CE_WARN, 27341ae08745Sheppo "ldc_init: (0x%lx) RX queue allocation failed\n", 27351ae08745Sheppo ldcp->id); 27361ae08745Sheppo exit_val = ENOMEM; 27371ae08745Sheppo goto cleanup_on_exit; 27381ae08745Sheppo } 27391ae08745Sheppo ldcp->rx_q_ra = va_to_pa((caddr_t)ldcp->rx_q_va); 27401ae08745Sheppo 27411ae08745Sheppo D2(ldcp->id, "ldc_init: rxq_va=0x%llx, rxq_ra=0x%llx, entries=0x%llx\n", 27421ae08745Sheppo ldcp->rx_q_va, ldcp->rx_q_ra, ldcp->rx_q_entries); 27431ae08745Sheppo 27441ae08745Sheppo ldcp->tstate |= TS_RXQ_RDY; 27451ae08745Sheppo 274658283286Sha137994 /* Setup a separate read data queue */ 274720ae46ebSha137994 if (ldcp->mode == LDC_MODE_RELIABLE) { 274858283286Sha137994 ldcp->readq_get_state = i_ldc_dq_rx_get_state; 274958283286Sha137994 ldcp->readq_set_head = i_ldc_set_rxdq_head; 275058283286Sha137994 275158283286Sha137994 /* Make sure the data queue multiplier is a power of 2 */ 275258283286Sha137994 if (!ISP2(ldc_rxdq_multiplier)) { 275358283286Sha137994 D1(ldcp->id, "ldc_init: (0x%llx) ldc_rxdq_multiplier " 275458283286Sha137994 "not a power of 2, resetting", ldcp->id); 275558283286Sha137994 ldc_rxdq_multiplier = LDC_RXDQ_MULTIPLIER; 275658283286Sha137994 } 275758283286Sha137994 275858283286Sha137994 ldcp->rx_dq_entries = ldc_rxdq_multiplier * ldcp->rx_q_entries; 275958283286Sha137994 ldcp->rx_dq_va = (uint64_t) 276058283286Sha137994 kmem_alloc(ldcp->rx_dq_entries << LDC_PACKET_SHIFT, 276158283286Sha137994 KM_SLEEP); 276258283286Sha137994 if (ldcp->rx_dq_va == NULL) { 276358283286Sha137994 cmn_err(CE_WARN, 276458283286Sha137994 "ldc_init: (0x%lx) RX data queue " 276558283286Sha137994 "allocation failed\n", ldcp->id); 276658283286Sha137994 exit_val = ENOMEM; 276758283286Sha137994 goto cleanup_on_exit; 276858283286Sha137994 } 276958283286Sha137994 277058283286Sha137994 ldcp->rx_dq_head = ldcp->rx_dq_tail = 0; 277158283286Sha137994 277258283286Sha137994 D2(ldcp->id, "ldc_init: rx_dq_va=0x%llx, " 277358283286Sha137994 "rx_dq_entries=0x%llx\n", ldcp->rx_dq_va, 277458283286Sha137994 ldcp->rx_dq_entries); 277558283286Sha137994 } else { 277658283286Sha137994 ldcp->readq_get_state = i_ldc_hvq_rx_get_state; 277758283286Sha137994 ldcp->readq_set_head = i_ldc_set_rx_head; 277858283286Sha137994 } 277958283286Sha137994 27801ae08745Sheppo /* Init descriptor ring and memory handle list lock */ 27811ae08745Sheppo mutex_init(&ldcp->exp_dlist_lock, NULL, MUTEX_DRIVER, NULL); 27821ae08745Sheppo mutex_init(&ldcp->imp_dlist_lock, NULL, MUTEX_DRIVER, NULL); 27831ae08745Sheppo mutex_init(&ldcp->mlist_lock, NULL, MUTEX_DRIVER, NULL); 27841ae08745Sheppo 27851ae08745Sheppo /* mark status as INITialized */ 27861ae08745Sheppo ldcp->status = LDC_INIT; 27871ae08745Sheppo 27881ae08745Sheppo /* Add to channel list */ 27891ae08745Sheppo mutex_enter(&ldcssp->lock); 27901ae08745Sheppo ldcp->next = ldcssp->chan_list; 27911ae08745Sheppo ldcssp->chan_list = ldcp; 27921ae08745Sheppo ldcssp->channel_count++; 27931ae08745Sheppo mutex_exit(&ldcssp->lock); 27941ae08745Sheppo 27951ae08745Sheppo /* set the handle */ 27961ae08745Sheppo *handle = (ldc_handle_t)ldcp; 27971ae08745Sheppo 27981ae08745Sheppo D1(ldcp->id, "ldc_init: (0x%llx) channel initialized\n", ldcp->id); 27991ae08745Sheppo 28001ae08745Sheppo return (0); 28011ae08745Sheppo 28021ae08745Sheppo cleanup_on_exit: 28031ae08745Sheppo 280420ae46ebSha137994 if (ldcp->mode == LDC_MODE_RELIABLE && ldcp->stream_bufferp) 28051ae08745Sheppo kmem_free(ldcp->stream_bufferp, ldcp->mtu); 28061ae08745Sheppo 28071ae08745Sheppo if (ldcp->tstate & TS_TXQ_RDY) 28081ae08745Sheppo contig_mem_free((caddr_t)ldcp->tx_q_va, 28091ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT)); 28101ae08745Sheppo 28111ae08745Sheppo if (ldcp->tstate & TS_RXQ_RDY) 28121ae08745Sheppo contig_mem_free((caddr_t)ldcp->rx_q_va, 28131ae08745Sheppo (ldcp->rx_q_entries << LDC_PACKET_SHIFT)); 28141ae08745Sheppo 2815d10e4ef2Snarayan mutex_destroy(&ldcp->tx_lock); 28161ae08745Sheppo mutex_destroy(&ldcp->lock); 28171ae08745Sheppo 28181ae08745Sheppo if (ldcp) 28191ae08745Sheppo kmem_free(ldcp, sizeof (ldc_chan_t)); 28201ae08745Sheppo 28211ae08745Sheppo return (exit_val); 28221ae08745Sheppo } 28231ae08745Sheppo 28241ae08745Sheppo /* 28251ae08745Sheppo * Finalizes the LDC connection. It will return EBUSY if the 28261ae08745Sheppo * channel is open. A ldc_close() has to be done prior to 28271ae08745Sheppo * a ldc_fini operation. It frees TX/RX queues, associated 28281ae08745Sheppo * with the channel 28291ae08745Sheppo */ 28301ae08745Sheppo int 28311ae08745Sheppo ldc_fini(ldc_handle_t handle) 28321ae08745Sheppo { 28331ae08745Sheppo ldc_chan_t *ldcp; 28341ae08745Sheppo ldc_chan_t *tmp_ldcp; 28351ae08745Sheppo uint64_t id; 28361ae08745Sheppo 28371ae08745Sheppo if (handle == NULL) { 28381ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel handle\n"); 28391ae08745Sheppo return (EINVAL); 28401ae08745Sheppo } 28411ae08745Sheppo ldcp = (ldc_chan_t *)handle; 28421ae08745Sheppo id = ldcp->id; 28431ae08745Sheppo 28441ae08745Sheppo mutex_enter(&ldcp->lock); 28451ae08745Sheppo 28463af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) > TS_INIT) { 28471ae08745Sheppo DWARN(ldcp->id, "ldc_fini: (0x%llx) channel is open\n", 28481ae08745Sheppo ldcp->id); 28491ae08745Sheppo mutex_exit(&ldcp->lock); 28501ae08745Sheppo return (EBUSY); 28511ae08745Sheppo } 28521ae08745Sheppo 28531ae08745Sheppo /* Remove from the channel list */ 28541ae08745Sheppo mutex_enter(&ldcssp->lock); 28551ae08745Sheppo tmp_ldcp = ldcssp->chan_list; 28561ae08745Sheppo if (tmp_ldcp == ldcp) { 28571ae08745Sheppo ldcssp->chan_list = ldcp->next; 28581ae08745Sheppo ldcp->next = NULL; 28591ae08745Sheppo } else { 28601ae08745Sheppo while (tmp_ldcp != NULL) { 28611ae08745Sheppo if (tmp_ldcp->next == ldcp) { 28621ae08745Sheppo tmp_ldcp->next = ldcp->next; 28631ae08745Sheppo ldcp->next = NULL; 28641ae08745Sheppo break; 28651ae08745Sheppo } 28661ae08745Sheppo tmp_ldcp = tmp_ldcp->next; 28671ae08745Sheppo } 28681ae08745Sheppo if (tmp_ldcp == NULL) { 28691ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel hdl\n"); 28701ae08745Sheppo mutex_exit(&ldcssp->lock); 28711ae08745Sheppo mutex_exit(&ldcp->lock); 28721ae08745Sheppo return (EINVAL); 28731ae08745Sheppo } 28741ae08745Sheppo } 28751ae08745Sheppo 28761ae08745Sheppo ldcssp->channel_count--; 28771ae08745Sheppo 28781ae08745Sheppo mutex_exit(&ldcssp->lock); 28791ae08745Sheppo 28801ae08745Sheppo /* Free the map table for this channel */ 28811ae08745Sheppo if (ldcp->mtbl) { 28821ae08745Sheppo (void) hv_ldc_set_map_table(ldcp->id, NULL, NULL); 28833af08d82Slm66018 if (ldcp->mtbl->contigmem) 28841ae08745Sheppo contig_mem_free(ldcp->mtbl->table, ldcp->mtbl->size); 28853af08d82Slm66018 else 28863af08d82Slm66018 kmem_free(ldcp->mtbl->table, ldcp->mtbl->size); 28871ae08745Sheppo mutex_destroy(&ldcp->mtbl->lock); 28881ae08745Sheppo kmem_free(ldcp->mtbl, sizeof (ldc_mtbl_t)); 28891ae08745Sheppo } 28901ae08745Sheppo 28911ae08745Sheppo /* Destroy descriptor ring and memory handle list lock */ 28921ae08745Sheppo mutex_destroy(&ldcp->exp_dlist_lock); 28931ae08745Sheppo mutex_destroy(&ldcp->imp_dlist_lock); 28941ae08745Sheppo mutex_destroy(&ldcp->mlist_lock); 28951ae08745Sheppo 289620ae46ebSha137994 /* Free the stream buffer for RELIABLE_MODE */ 289720ae46ebSha137994 if (ldcp->mode == LDC_MODE_RELIABLE && ldcp->stream_bufferp) 28981ae08745Sheppo kmem_free(ldcp->stream_bufferp, ldcp->mtu); 28991ae08745Sheppo 29001ae08745Sheppo /* Free the RX queue */ 29011ae08745Sheppo contig_mem_free((caddr_t)ldcp->rx_q_va, 29021ae08745Sheppo (ldcp->rx_q_entries << LDC_PACKET_SHIFT)); 29031ae08745Sheppo ldcp->tstate &= ~TS_RXQ_RDY; 29041ae08745Sheppo 290558283286Sha137994 /* Free the RX data queue */ 290620ae46ebSha137994 if (ldcp->mode == LDC_MODE_RELIABLE) { 290758283286Sha137994 kmem_free((caddr_t)ldcp->rx_dq_va, 290858283286Sha137994 (ldcp->rx_dq_entries << LDC_PACKET_SHIFT)); 290958283286Sha137994 } 291058283286Sha137994 29111ae08745Sheppo /* Free the TX queue */ 29121ae08745Sheppo contig_mem_free((caddr_t)ldcp->tx_q_va, 29131ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT)); 29141ae08745Sheppo ldcp->tstate &= ~TS_TXQ_RDY; 29151ae08745Sheppo 29161ae08745Sheppo mutex_exit(&ldcp->lock); 29171ae08745Sheppo 29181ae08745Sheppo /* Destroy mutex */ 2919d10e4ef2Snarayan mutex_destroy(&ldcp->tx_lock); 29201ae08745Sheppo mutex_destroy(&ldcp->lock); 29211ae08745Sheppo 29221ae08745Sheppo /* free channel structure */ 29231ae08745Sheppo kmem_free(ldcp, sizeof (ldc_chan_t)); 29241ae08745Sheppo 29251ae08745Sheppo D1(id, "ldc_fini: (0x%llx) channel finalized\n", id); 29261ae08745Sheppo 29271ae08745Sheppo return (0); 29281ae08745Sheppo } 29291ae08745Sheppo 29301ae08745Sheppo /* 29311ae08745Sheppo * Open the LDC channel for use. It registers the TX/RX queues 29321ae08745Sheppo * with the Hypervisor. It also specifies the interrupt number 29331ae08745Sheppo * and target CPU for this channel 29341ae08745Sheppo */ 29351ae08745Sheppo int 29361ae08745Sheppo ldc_open(ldc_handle_t handle) 29371ae08745Sheppo { 29381ae08745Sheppo ldc_chan_t *ldcp; 29391ae08745Sheppo int rv; 29401ae08745Sheppo 29411ae08745Sheppo if (handle == NULL) { 29421ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_open: invalid channel handle\n"); 29431ae08745Sheppo return (EINVAL); 29441ae08745Sheppo } 29451ae08745Sheppo 29461ae08745Sheppo ldcp = (ldc_chan_t *)handle; 29471ae08745Sheppo 29481ae08745Sheppo mutex_enter(&ldcp->lock); 29491ae08745Sheppo 29501ae08745Sheppo if (ldcp->tstate < TS_INIT) { 29511ae08745Sheppo DWARN(ldcp->id, 29521ae08745Sheppo "ldc_open: (0x%llx) channel not initialized\n", ldcp->id); 29531ae08745Sheppo mutex_exit(&ldcp->lock); 29541ae08745Sheppo return (EFAULT); 29551ae08745Sheppo } 29563af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) >= TS_OPEN) { 29571ae08745Sheppo DWARN(ldcp->id, 29581ae08745Sheppo "ldc_open: (0x%llx) channel is already open\n", ldcp->id); 29591ae08745Sheppo mutex_exit(&ldcp->lock); 29601ae08745Sheppo return (EFAULT); 29611ae08745Sheppo } 29621ae08745Sheppo 29631ae08745Sheppo /* 29641ae08745Sheppo * Unregister/Register the tx queue with the hypervisor 29651ae08745Sheppo */ 29661ae08745Sheppo rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 29671ae08745Sheppo if (rv) { 29681ae08745Sheppo cmn_err(CE_WARN, 29691ae08745Sheppo "ldc_open: (0x%lx) channel tx queue unconf failed\n", 29701ae08745Sheppo ldcp->id); 29711ae08745Sheppo mutex_exit(&ldcp->lock); 29721ae08745Sheppo return (EIO); 29731ae08745Sheppo } 29741ae08745Sheppo 29751ae08745Sheppo rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries); 29761ae08745Sheppo if (rv) { 29771ae08745Sheppo cmn_err(CE_WARN, 29781ae08745Sheppo "ldc_open: (0x%lx) channel tx queue conf failed\n", 29791ae08745Sheppo ldcp->id); 29801ae08745Sheppo mutex_exit(&ldcp->lock); 29811ae08745Sheppo return (EIO); 29821ae08745Sheppo } 29831ae08745Sheppo 29841ae08745Sheppo D2(ldcp->id, "ldc_open: (0x%llx) registered tx queue with LDC\n", 29851ae08745Sheppo ldcp->id); 29861ae08745Sheppo 29871ae08745Sheppo /* 29881ae08745Sheppo * Unregister/Register the rx queue with the hypervisor 29891ae08745Sheppo */ 29901ae08745Sheppo rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 29911ae08745Sheppo if (rv) { 29921ae08745Sheppo cmn_err(CE_WARN, 29931ae08745Sheppo "ldc_open: (0x%lx) channel rx queue unconf failed\n", 29941ae08745Sheppo ldcp->id); 29951ae08745Sheppo mutex_exit(&ldcp->lock); 29961ae08745Sheppo return (EIO); 29971ae08745Sheppo } 29981ae08745Sheppo 29991ae08745Sheppo rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra, ldcp->rx_q_entries); 30001ae08745Sheppo if (rv) { 30011ae08745Sheppo cmn_err(CE_WARN, 30021ae08745Sheppo "ldc_open: (0x%lx) channel rx queue conf failed\n", 30031ae08745Sheppo ldcp->id); 30041ae08745Sheppo mutex_exit(&ldcp->lock); 30051ae08745Sheppo return (EIO); 30061ae08745Sheppo } 30071ae08745Sheppo 30081ae08745Sheppo D2(ldcp->id, "ldc_open: (0x%llx) registered rx queue with LDC\n", 30091ae08745Sheppo ldcp->id); 30101ae08745Sheppo 30111ae08745Sheppo ldcp->tstate |= TS_QCONF_RDY; 30121ae08745Sheppo 30131ae08745Sheppo /* Register the channel with the channel nexus */ 30141ae08745Sheppo rv = i_ldc_register_channel(ldcp); 30151ae08745Sheppo if (rv && rv != EAGAIN) { 30161ae08745Sheppo cmn_err(CE_WARN, 30171ae08745Sheppo "ldc_open: (0x%lx) channel register failed\n", ldcp->id); 30185699897cSHaik Aftandilian ldcp->tstate &= ~TS_QCONF_RDY; 30191ae08745Sheppo (void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 30201ae08745Sheppo (void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 30211ae08745Sheppo mutex_exit(&ldcp->lock); 30221ae08745Sheppo return (EIO); 30231ae08745Sheppo } 30241ae08745Sheppo 30251ae08745Sheppo /* mark channel in OPEN state */ 30261ae08745Sheppo ldcp->status = LDC_OPEN; 30271ae08745Sheppo 30281ae08745Sheppo /* Read channel state */ 30291ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 30301ae08745Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 30311ae08745Sheppo if (rv) { 30321ae08745Sheppo cmn_err(CE_WARN, 30331ae08745Sheppo "ldc_open: (0x%lx) cannot read channel state\n", 30341ae08745Sheppo ldcp->id); 30351ae08745Sheppo (void) i_ldc_unregister_channel(ldcp); 30365699897cSHaik Aftandilian ldcp->tstate &= ~TS_QCONF_RDY; 30371ae08745Sheppo (void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 30381ae08745Sheppo (void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 30391ae08745Sheppo mutex_exit(&ldcp->lock); 30401ae08745Sheppo return (EIO); 30411ae08745Sheppo } 30421ae08745Sheppo 30431ae08745Sheppo /* 304420ae46ebSha137994 * set the ACKd head to current head location for reliable 30451ae08745Sheppo */ 30461ae08745Sheppo ldcp->tx_ackd_head = ldcp->tx_head; 30471ae08745Sheppo 30481ae08745Sheppo /* mark channel ready if HV report link is UP (peer alloc'd Rx queue) */ 30491ae08745Sheppo if (ldcp->link_state == LDC_CHANNEL_UP || 30501ae08745Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 30511ae08745Sheppo ldcp->tstate |= TS_LINK_READY; 30521ae08745Sheppo ldcp->status = LDC_READY; 30531ae08745Sheppo } 30541ae08745Sheppo 30551ae08745Sheppo /* 30561ae08745Sheppo * if channel is being opened in RAW mode - no handshake is needed 30571ae08745Sheppo * switch the channel READY and UP state 30581ae08745Sheppo */ 30591ae08745Sheppo if (ldcp->mode == LDC_MODE_RAW) { 30601ae08745Sheppo ldcp->tstate = TS_UP; /* set bits associated with LDC UP */ 30611ae08745Sheppo ldcp->status = LDC_UP; 30621ae08745Sheppo } 30631ae08745Sheppo 30641ae08745Sheppo mutex_exit(&ldcp->lock); 30651ae08745Sheppo 30661ae08745Sheppo /* 30671ae08745Sheppo * Increment number of open channels 30681ae08745Sheppo */ 30691ae08745Sheppo mutex_enter(&ldcssp->lock); 30701ae08745Sheppo ldcssp->channels_open++; 30711ae08745Sheppo mutex_exit(&ldcssp->lock); 30721ae08745Sheppo 3073cb112a14Slm66018 D1(ldcp->id, 30743af08d82Slm66018 "ldc_open: (0x%llx) channel (0x%p) open for use " 30753af08d82Slm66018 "(tstate=0x%x, status=0x%x)\n", 30763af08d82Slm66018 ldcp->id, ldcp, ldcp->tstate, ldcp->status); 30771ae08745Sheppo 30781ae08745Sheppo return (0); 30791ae08745Sheppo } 30801ae08745Sheppo 30811ae08745Sheppo /* 30821ae08745Sheppo * Close the LDC connection. It will return EBUSY if there 30831ae08745Sheppo * are memory segments or descriptor rings either bound to or 30841ae08745Sheppo * mapped over the channel 30851ae08745Sheppo */ 30861ae08745Sheppo int 30871ae08745Sheppo ldc_close(ldc_handle_t handle) 30881ae08745Sheppo { 30891ae08745Sheppo ldc_chan_t *ldcp; 3090d10e4ef2Snarayan int rv = 0, retries = 0; 30911ae08745Sheppo boolean_t chk_done = B_FALSE; 30921ae08745Sheppo 30931ae08745Sheppo if (handle == NULL) { 30941ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_close: invalid channel handle\n"); 30951ae08745Sheppo return (EINVAL); 30961ae08745Sheppo } 30971ae08745Sheppo ldcp = (ldc_chan_t *)handle; 30981ae08745Sheppo 30991ae08745Sheppo mutex_enter(&ldcp->lock); 31001ae08745Sheppo 31011ae08745Sheppo /* return error if channel is not open */ 31023af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) < TS_OPEN) { 31031ae08745Sheppo DWARN(ldcp->id, 31041ae08745Sheppo "ldc_close: (0x%llx) channel is not open\n", ldcp->id); 31051ae08745Sheppo mutex_exit(&ldcp->lock); 31061ae08745Sheppo return (EFAULT); 31071ae08745Sheppo } 31081ae08745Sheppo 31091ae08745Sheppo /* if any memory handles, drings, are bound or mapped cannot close */ 31101ae08745Sheppo if (ldcp->mhdl_list != NULL) { 31111ae08745Sheppo DWARN(ldcp->id, 31121ae08745Sheppo "ldc_close: (0x%llx) channel has bound memory handles\n", 31131ae08745Sheppo ldcp->id); 31141ae08745Sheppo mutex_exit(&ldcp->lock); 31151ae08745Sheppo return (EBUSY); 31161ae08745Sheppo } 31171ae08745Sheppo if (ldcp->exp_dring_list != NULL) { 31181ae08745Sheppo DWARN(ldcp->id, 31191ae08745Sheppo "ldc_close: (0x%llx) channel has bound descriptor rings\n", 31201ae08745Sheppo ldcp->id); 31211ae08745Sheppo mutex_exit(&ldcp->lock); 31221ae08745Sheppo return (EBUSY); 31231ae08745Sheppo } 31241ae08745Sheppo if (ldcp->imp_dring_list != NULL) { 31251ae08745Sheppo DWARN(ldcp->id, 31261ae08745Sheppo "ldc_close: (0x%llx) channel has mapped descriptor rings\n", 31271ae08745Sheppo ldcp->id); 31281ae08745Sheppo mutex_exit(&ldcp->lock); 31291ae08745Sheppo return (EBUSY); 31301ae08745Sheppo } 31311ae08745Sheppo 31324d39be2bSsg70180 if (ldcp->cb_inprogress) { 31334d39be2bSsg70180 DWARN(ldcp->id, "ldc_close: (0x%llx) callback active\n", 31344d39be2bSsg70180 ldcp->id); 31354d39be2bSsg70180 mutex_exit(&ldcp->lock); 31364d39be2bSsg70180 return (EWOULDBLOCK); 31374d39be2bSsg70180 } 31384d39be2bSsg70180 3139d10e4ef2Snarayan /* Obtain Tx lock */ 3140d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 3141d10e4ef2Snarayan 31421ae08745Sheppo /* 31431ae08745Sheppo * Wait for pending transmits to complete i.e Tx queue to drain 31441ae08745Sheppo * if there are pending pkts - wait 1 ms and retry again 31451ae08745Sheppo */ 31461ae08745Sheppo for (;;) { 31471ae08745Sheppo 31481ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 31491ae08745Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 31501ae08745Sheppo if (rv) { 31511ae08745Sheppo cmn_err(CE_WARN, 31521ae08745Sheppo "ldc_close: (0x%lx) cannot read qptrs\n", ldcp->id); 3153d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 31541ae08745Sheppo mutex_exit(&ldcp->lock); 31551ae08745Sheppo return (EIO); 31561ae08745Sheppo } 31571ae08745Sheppo 31581ae08745Sheppo if (ldcp->tx_head == ldcp->tx_tail || 31591ae08745Sheppo ldcp->link_state != LDC_CHANNEL_UP) { 31601ae08745Sheppo break; 31611ae08745Sheppo } 31621ae08745Sheppo 31631ae08745Sheppo if (chk_done) { 31641ae08745Sheppo DWARN(ldcp->id, 31651ae08745Sheppo "ldc_close: (0x%llx) Tx queue drain timeout\n", 31661ae08745Sheppo ldcp->id); 31671ae08745Sheppo break; 31681ae08745Sheppo } 31691ae08745Sheppo 31701ae08745Sheppo /* wait for one ms and try again */ 31711ae08745Sheppo delay(drv_usectohz(1000)); 31721ae08745Sheppo chk_done = B_TRUE; 31731ae08745Sheppo } 31741ae08745Sheppo 31751ae08745Sheppo /* 3176a8ea4edeSnarayan * Drain the Tx and Rx queues as we are closing the 3177a8ea4edeSnarayan * channel. We dont care about any pending packets. 3178a8ea4edeSnarayan * We have to also drain the queue prior to clearing 3179a8ea4edeSnarayan * pending interrupts, otherwise the HV will trigger 3180a8ea4edeSnarayan * an interrupt the moment the interrupt state is 3181a8ea4edeSnarayan * cleared. 31823af08d82Slm66018 */ 31833af08d82Slm66018 (void) i_ldc_txq_reconf(ldcp); 3184305dbad4SKevin Crowe i_ldc_rxq_drain(ldcp); 31853af08d82Slm66018 31863af08d82Slm66018 /* 31871ae08745Sheppo * Unregister the channel with the nexus 31881ae08745Sheppo */ 3189d10e4ef2Snarayan while ((rv = i_ldc_unregister_channel(ldcp)) != 0) { 3190d10e4ef2Snarayan 3191d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 31921ae08745Sheppo mutex_exit(&ldcp->lock); 3193d10e4ef2Snarayan 3194d10e4ef2Snarayan /* if any error other than EAGAIN return back */ 3195a8ea4edeSnarayan if (rv != EAGAIN || retries >= ldc_max_retries) { 3196d10e4ef2Snarayan cmn_err(CE_WARN, 3197d10e4ef2Snarayan "ldc_close: (0x%lx) unregister failed, %d\n", 3198d10e4ef2Snarayan ldcp->id, rv); 31991ae08745Sheppo return (rv); 32001ae08745Sheppo } 32011ae08745Sheppo 32021ae08745Sheppo /* 3203d10e4ef2Snarayan * As there could be pending interrupts we need 3204d10e4ef2Snarayan * to wait and try again 3205d10e4ef2Snarayan */ 32064d39be2bSsg70180 drv_usecwait(ldc_close_delay); 3207d10e4ef2Snarayan mutex_enter(&ldcp->lock); 3208d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 3209d10e4ef2Snarayan retries++; 3210d10e4ef2Snarayan } 3211d10e4ef2Snarayan 32125699897cSHaik Aftandilian ldcp->tstate &= ~TS_QCONF_RDY; 32135699897cSHaik Aftandilian 3214d10e4ef2Snarayan /* 32151ae08745Sheppo * Unregister queues 32161ae08745Sheppo */ 32171ae08745Sheppo rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 32181ae08745Sheppo if (rv) { 32191ae08745Sheppo cmn_err(CE_WARN, 32201ae08745Sheppo "ldc_close: (0x%lx) channel TX queue unconf failed\n", 32211ae08745Sheppo ldcp->id); 3222d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 32231ae08745Sheppo mutex_exit(&ldcp->lock); 32241ae08745Sheppo return (EIO); 32251ae08745Sheppo } 32261ae08745Sheppo rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 32271ae08745Sheppo if (rv) { 32281ae08745Sheppo cmn_err(CE_WARN, 32291ae08745Sheppo "ldc_close: (0x%lx) channel RX queue unconf failed\n", 32301ae08745Sheppo ldcp->id); 3231d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 32321ae08745Sheppo mutex_exit(&ldcp->lock); 32331ae08745Sheppo return (EIO); 32341ae08745Sheppo } 32351ae08745Sheppo 32361ae08745Sheppo /* Reset channel state information */ 32371ae08745Sheppo i_ldc_reset_state(ldcp); 32381ae08745Sheppo 32391ae08745Sheppo /* Mark channel as down and in initialized state */ 32401ae08745Sheppo ldcp->tx_ackd_head = 0; 32411ae08745Sheppo ldcp->tx_head = 0; 32423af08d82Slm66018 ldcp->tstate = TS_IN_RESET|TS_INIT; 32431ae08745Sheppo ldcp->status = LDC_INIT; 32441ae08745Sheppo 3245d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 32461ae08745Sheppo mutex_exit(&ldcp->lock); 32471ae08745Sheppo 32481ae08745Sheppo /* Decrement number of open channels */ 32491ae08745Sheppo mutex_enter(&ldcssp->lock); 32501ae08745Sheppo ldcssp->channels_open--; 32511ae08745Sheppo mutex_exit(&ldcssp->lock); 32521ae08745Sheppo 32531ae08745Sheppo D1(ldcp->id, "ldc_close: (0x%llx) channel closed\n", ldcp->id); 32541ae08745Sheppo 32551ae08745Sheppo return (0); 32561ae08745Sheppo } 32571ae08745Sheppo 32581ae08745Sheppo /* 32591ae08745Sheppo * Register channel callback 32601ae08745Sheppo */ 32611ae08745Sheppo int 32621ae08745Sheppo ldc_reg_callback(ldc_handle_t handle, 32631ae08745Sheppo uint_t(*cb)(uint64_t event, caddr_t arg), caddr_t arg) 32641ae08745Sheppo { 32651ae08745Sheppo ldc_chan_t *ldcp; 32661ae08745Sheppo 32671ae08745Sheppo if (handle == NULL) { 32681ae08745Sheppo DWARN(DBG_ALL_LDCS, 32691ae08745Sheppo "ldc_reg_callback: invalid channel handle\n"); 32701ae08745Sheppo return (EINVAL); 32711ae08745Sheppo } 32721ae08745Sheppo if (((uint64_t)cb) < KERNELBASE) { 32731ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_reg_callback: invalid callback\n"); 32741ae08745Sheppo return (EINVAL); 32751ae08745Sheppo } 32761ae08745Sheppo ldcp = (ldc_chan_t *)handle; 32771ae08745Sheppo 32781ae08745Sheppo mutex_enter(&ldcp->lock); 32791ae08745Sheppo 32801ae08745Sheppo if (ldcp->cb) { 32811ae08745Sheppo DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback exists\n", 32821ae08745Sheppo ldcp->id); 32831ae08745Sheppo mutex_exit(&ldcp->lock); 32841ae08745Sheppo return (EIO); 32851ae08745Sheppo } 32861ae08745Sheppo if (ldcp->cb_inprogress) { 32871ae08745Sheppo DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback active\n", 32881ae08745Sheppo ldcp->id); 32891ae08745Sheppo mutex_exit(&ldcp->lock); 32901ae08745Sheppo return (EWOULDBLOCK); 32911ae08745Sheppo } 32921ae08745Sheppo 32931ae08745Sheppo ldcp->cb = cb; 32941ae08745Sheppo ldcp->cb_arg = arg; 32951ae08745Sheppo ldcp->cb_enabled = B_TRUE; 32961ae08745Sheppo 32971ae08745Sheppo D1(ldcp->id, 32981ae08745Sheppo "ldc_reg_callback: (0x%llx) registered callback for channel\n", 32991ae08745Sheppo ldcp->id); 33001ae08745Sheppo 33011ae08745Sheppo mutex_exit(&ldcp->lock); 33021ae08745Sheppo 33031ae08745Sheppo return (0); 33041ae08745Sheppo } 33051ae08745Sheppo 33061ae08745Sheppo /* 33071ae08745Sheppo * Unregister channel callback 33081ae08745Sheppo */ 33091ae08745Sheppo int 33101ae08745Sheppo ldc_unreg_callback(ldc_handle_t handle) 33111ae08745Sheppo { 33121ae08745Sheppo ldc_chan_t *ldcp; 33131ae08745Sheppo 33141ae08745Sheppo if (handle == NULL) { 33151ae08745Sheppo DWARN(DBG_ALL_LDCS, 33161ae08745Sheppo "ldc_unreg_callback: invalid channel handle\n"); 33171ae08745Sheppo return (EINVAL); 33181ae08745Sheppo } 33191ae08745Sheppo ldcp = (ldc_chan_t *)handle; 33201ae08745Sheppo 33211ae08745Sheppo mutex_enter(&ldcp->lock); 33221ae08745Sheppo 33231ae08745Sheppo if (ldcp->cb == NULL) { 33241ae08745Sheppo DWARN(ldcp->id, 33251ae08745Sheppo "ldc_unreg_callback: (0x%llx) no callback exists\n", 33261ae08745Sheppo ldcp->id); 33271ae08745Sheppo mutex_exit(&ldcp->lock); 33281ae08745Sheppo return (EIO); 33291ae08745Sheppo } 33301ae08745Sheppo if (ldcp->cb_inprogress) { 33311ae08745Sheppo DWARN(ldcp->id, 33321ae08745Sheppo "ldc_unreg_callback: (0x%llx) callback active\n", 33331ae08745Sheppo ldcp->id); 33341ae08745Sheppo mutex_exit(&ldcp->lock); 33351ae08745Sheppo return (EWOULDBLOCK); 33361ae08745Sheppo } 33371ae08745Sheppo 33381ae08745Sheppo ldcp->cb = NULL; 33391ae08745Sheppo ldcp->cb_arg = NULL; 33401ae08745Sheppo ldcp->cb_enabled = B_FALSE; 33411ae08745Sheppo 33421ae08745Sheppo D1(ldcp->id, 33431ae08745Sheppo "ldc_unreg_callback: (0x%llx) unregistered callback for channel\n", 33441ae08745Sheppo ldcp->id); 33451ae08745Sheppo 33461ae08745Sheppo mutex_exit(&ldcp->lock); 33471ae08745Sheppo 33481ae08745Sheppo return (0); 33491ae08745Sheppo } 33501ae08745Sheppo 33511ae08745Sheppo 33521ae08745Sheppo /* 33531ae08745Sheppo * Bring a channel up by initiating a handshake with the peer 33541ae08745Sheppo * This call is asynchronous. It will complete at a later point 33551ae08745Sheppo * in time when the peer responds back with an RTR. 33561ae08745Sheppo */ 33571ae08745Sheppo int 33581ae08745Sheppo ldc_up(ldc_handle_t handle) 33591ae08745Sheppo { 33601ae08745Sheppo int rv; 33611ae08745Sheppo ldc_chan_t *ldcp; 33621ae08745Sheppo ldc_msg_t *ldcmsg; 336357e6a936Ssb155480 uint64_t tx_tail, tstate, link_state; 33641ae08745Sheppo 33651ae08745Sheppo if (handle == NULL) { 33661ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_up: invalid channel handle\n"); 33671ae08745Sheppo return (EINVAL); 33681ae08745Sheppo } 33691ae08745Sheppo ldcp = (ldc_chan_t *)handle; 33701ae08745Sheppo 33711ae08745Sheppo mutex_enter(&ldcp->lock); 33721ae08745Sheppo 33733af08d82Slm66018 D1(ldcp->id, "ldc_up: (0x%llx) doing channel UP\n", ldcp->id); 33743af08d82Slm66018 33753af08d82Slm66018 /* clear the reset state */ 33763af08d82Slm66018 tstate = ldcp->tstate; 33773af08d82Slm66018 ldcp->tstate &= ~TS_IN_RESET; 33783af08d82Slm66018 33791ae08745Sheppo if (ldcp->tstate == TS_UP) { 33803af08d82Slm66018 DWARN(ldcp->id, 33811ae08745Sheppo "ldc_up: (0x%llx) channel is already in UP state\n", 33821ae08745Sheppo ldcp->id); 33833af08d82Slm66018 33843af08d82Slm66018 /* mark channel as up */ 33853af08d82Slm66018 ldcp->status = LDC_UP; 33863af08d82Slm66018 33873af08d82Slm66018 /* 33883af08d82Slm66018 * if channel was in reset state and there was 33893af08d82Slm66018 * pending data clear interrupt state. this will 33903af08d82Slm66018 * trigger an interrupt, causing the RX handler to 33913af08d82Slm66018 * to invoke the client's callback 33923af08d82Slm66018 */ 33933af08d82Slm66018 if ((tstate & TS_IN_RESET) && 33943af08d82Slm66018 ldcp->rx_intr_state == LDC_INTR_PEND) { 3395cb112a14Slm66018 D1(ldcp->id, 33963af08d82Slm66018 "ldc_up: (0x%llx) channel has pending data, " 33973af08d82Slm66018 "clearing interrupt\n", ldcp->id); 33983af08d82Slm66018 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 33993af08d82Slm66018 } 34003af08d82Slm66018 34011ae08745Sheppo mutex_exit(&ldcp->lock); 34021ae08745Sheppo return (0); 34031ae08745Sheppo } 34041ae08745Sheppo 34051ae08745Sheppo /* if the channel is in RAW mode - mark it as UP, if READY */ 34061ae08745Sheppo if (ldcp->mode == LDC_MODE_RAW && ldcp->tstate >= TS_READY) { 34071ae08745Sheppo ldcp->tstate = TS_UP; 34081ae08745Sheppo mutex_exit(&ldcp->lock); 34091ae08745Sheppo return (0); 34101ae08745Sheppo } 34111ae08745Sheppo 34121ae08745Sheppo /* Don't start another handshake if there is one in progress */ 34131ae08745Sheppo if (ldcp->hstate) { 34143af08d82Slm66018 D1(ldcp->id, 34151ae08745Sheppo "ldc_up: (0x%llx) channel handshake in progress\n", 34161ae08745Sheppo ldcp->id); 34171ae08745Sheppo mutex_exit(&ldcp->lock); 34181ae08745Sheppo return (0); 34191ae08745Sheppo } 34201ae08745Sheppo 3421d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 3422d10e4ef2Snarayan 342357e6a936Ssb155480 /* save current link state */ 342457e6a936Ssb155480 link_state = ldcp->link_state; 342557e6a936Ssb155480 34261ae08745Sheppo /* get the current tail for the LDC msg */ 34271ae08745Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 34281ae08745Sheppo if (rv) { 3429cb112a14Slm66018 D1(ldcp->id, "ldc_up: (0x%llx) cannot initiate handshake\n", 34301ae08745Sheppo ldcp->id); 3431d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 34321ae08745Sheppo mutex_exit(&ldcp->lock); 34331ae08745Sheppo return (ECONNREFUSED); 34341ae08745Sheppo } 34351ae08745Sheppo 343657e6a936Ssb155480 /* 343757e6a936Ssb155480 * If i_ldc_get_tx_tail() changed link_state to either RESET or UP, 343857e6a936Ssb155480 * from a previous state of DOWN, then mark the channel as 343957e6a936Ssb155480 * being ready for handshake. 344057e6a936Ssb155480 */ 344157e6a936Ssb155480 if ((link_state == LDC_CHANNEL_DOWN) && 344257e6a936Ssb155480 (link_state != ldcp->link_state)) { 344357e6a936Ssb155480 344457e6a936Ssb155480 ASSERT((ldcp->link_state == LDC_CHANNEL_RESET) || 344557e6a936Ssb155480 (ldcp->link_state == LDC_CHANNEL_UP)); 344657e6a936Ssb155480 344757e6a936Ssb155480 if (ldcp->mode == LDC_MODE_RAW) { 344857e6a936Ssb155480 ldcp->status = LDC_UP; 344957e6a936Ssb155480 ldcp->tstate = TS_UP; 345057e6a936Ssb155480 mutex_exit(&ldcp->tx_lock); 345157e6a936Ssb155480 mutex_exit(&ldcp->lock); 345257e6a936Ssb155480 return (0); 345357e6a936Ssb155480 } else { 345457e6a936Ssb155480 ldcp->status = LDC_READY; 345557e6a936Ssb155480 ldcp->tstate |= TS_LINK_READY; 345657e6a936Ssb155480 } 345757e6a936Ssb155480 345857e6a936Ssb155480 } 345957e6a936Ssb155480 34601ae08745Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 34611ae08745Sheppo ZERO_PKT(ldcmsg); 34621ae08745Sheppo 34631ae08745Sheppo ldcmsg->type = LDC_CTRL; 34641ae08745Sheppo ldcmsg->stype = LDC_INFO; 34651ae08745Sheppo ldcmsg->ctrl = LDC_VER; 34661ae08745Sheppo ldcp->next_vidx = 0; 34671ae08745Sheppo bcopy(&ldc_versions[0], ldcmsg->udata, sizeof (ldc_versions[0])); 34681ae08745Sheppo 34691ae08745Sheppo DUMP_LDC_PKT(ldcp, "ldc_up snd ver", (uint64_t)ldcmsg); 34701ae08745Sheppo 34711ae08745Sheppo /* initiate the send by calling into HV and set the new tail */ 34721ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 34731ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 34741ae08745Sheppo 34751ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 34761ae08745Sheppo if (rv) { 34771ae08745Sheppo DWARN(ldcp->id, 34781ae08745Sheppo "ldc_up: (0x%llx) cannot initiate handshake rv=%d\n", 34791ae08745Sheppo ldcp->id, rv); 3480d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 34811ae08745Sheppo mutex_exit(&ldcp->lock); 34821ae08745Sheppo return (rv); 34831ae08745Sheppo } 34841ae08745Sheppo 34850a55fbb7Slm66018 ldcp->hstate |= TS_SENT_VER; 34861ae08745Sheppo ldcp->tx_tail = tx_tail; 34871ae08745Sheppo D1(ldcp->id, "ldc_up: (0x%llx) channel up initiated\n", ldcp->id); 34881ae08745Sheppo 3489d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 34901ae08745Sheppo mutex_exit(&ldcp->lock); 34911ae08745Sheppo 34921ae08745Sheppo return (rv); 34931ae08745Sheppo } 34941ae08745Sheppo 34951ae08745Sheppo 34961ae08745Sheppo /* 3497e1ebb9ecSlm66018 * Bring a channel down by resetting its state and queues 34981ae08745Sheppo */ 34991ae08745Sheppo int 3500e1ebb9ecSlm66018 ldc_down(ldc_handle_t handle) 35011ae08745Sheppo { 35021ae08745Sheppo ldc_chan_t *ldcp; 35031ae08745Sheppo 35041ae08745Sheppo if (handle == NULL) { 3505e1ebb9ecSlm66018 DWARN(DBG_ALL_LDCS, "ldc_down: invalid channel handle\n"); 35061ae08745Sheppo return (EINVAL); 35071ae08745Sheppo } 35081ae08745Sheppo ldcp = (ldc_chan_t *)handle; 35091ae08745Sheppo mutex_enter(&ldcp->lock); 3510d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 35113af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 3512d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 35131ae08745Sheppo mutex_exit(&ldcp->lock); 35141ae08745Sheppo 35151ae08745Sheppo return (0); 35161ae08745Sheppo } 35171ae08745Sheppo 35181ae08745Sheppo /* 35191ae08745Sheppo * Get the current channel status 35201ae08745Sheppo */ 35211ae08745Sheppo int 35221ae08745Sheppo ldc_status(ldc_handle_t handle, ldc_status_t *status) 35231ae08745Sheppo { 35241ae08745Sheppo ldc_chan_t *ldcp; 35251ae08745Sheppo 35261ae08745Sheppo if (handle == NULL || status == NULL) { 35271ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_status: invalid argument\n"); 35281ae08745Sheppo return (EINVAL); 35291ae08745Sheppo } 35301ae08745Sheppo ldcp = (ldc_chan_t *)handle; 35311ae08745Sheppo 35321ae08745Sheppo *status = ((ldc_chan_t *)handle)->status; 35331ae08745Sheppo 3534cb112a14Slm66018 D1(ldcp->id, 35351ae08745Sheppo "ldc_status: (0x%llx) returned status %d\n", ldcp->id, *status); 35361ae08745Sheppo return (0); 35371ae08745Sheppo } 35381ae08745Sheppo 35391ae08745Sheppo 35401ae08745Sheppo /* 35411ae08745Sheppo * Set the channel's callback mode - enable/disable callbacks 35421ae08745Sheppo */ 35431ae08745Sheppo int 35441ae08745Sheppo ldc_set_cb_mode(ldc_handle_t handle, ldc_cb_mode_t cmode) 35451ae08745Sheppo { 35461ae08745Sheppo ldc_chan_t *ldcp; 35471ae08745Sheppo 35481ae08745Sheppo if (handle == NULL) { 35491ae08745Sheppo DWARN(DBG_ALL_LDCS, 35501ae08745Sheppo "ldc_set_intr_mode: invalid channel handle\n"); 35511ae08745Sheppo return (EINVAL); 35521ae08745Sheppo } 35531ae08745Sheppo ldcp = (ldc_chan_t *)handle; 35541ae08745Sheppo 35551ae08745Sheppo /* 35561ae08745Sheppo * Record no callbacks should be invoked 35571ae08745Sheppo */ 35581ae08745Sheppo mutex_enter(&ldcp->lock); 35591ae08745Sheppo 35601ae08745Sheppo switch (cmode) { 35611ae08745Sheppo case LDC_CB_DISABLE: 35621ae08745Sheppo if (!ldcp->cb_enabled) { 35631ae08745Sheppo DWARN(ldcp->id, 35641ae08745Sheppo "ldc_set_cb_mode: (0x%llx) callbacks disabled\n", 35651ae08745Sheppo ldcp->id); 35661ae08745Sheppo break; 35671ae08745Sheppo } 35681ae08745Sheppo ldcp->cb_enabled = B_FALSE; 35691ae08745Sheppo 35701ae08745Sheppo D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) disabled callbacks\n", 35711ae08745Sheppo ldcp->id); 35721ae08745Sheppo break; 35731ae08745Sheppo 35741ae08745Sheppo case LDC_CB_ENABLE: 35751ae08745Sheppo if (ldcp->cb_enabled) { 35761ae08745Sheppo DWARN(ldcp->id, 35771ae08745Sheppo "ldc_set_cb_mode: (0x%llx) callbacks enabled\n", 35781ae08745Sheppo ldcp->id); 35791ae08745Sheppo break; 35801ae08745Sheppo } 35811ae08745Sheppo ldcp->cb_enabled = B_TRUE; 35821ae08745Sheppo 35831ae08745Sheppo D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) enabled callbacks\n", 35841ae08745Sheppo ldcp->id); 35851ae08745Sheppo break; 35861ae08745Sheppo } 35871ae08745Sheppo 35881ae08745Sheppo mutex_exit(&ldcp->lock); 35891ae08745Sheppo 35901ae08745Sheppo return (0); 35911ae08745Sheppo } 35921ae08745Sheppo 35931ae08745Sheppo /* 35941ae08745Sheppo * Check to see if there are packets on the incoming queue 3595e1ebb9ecSlm66018 * Will return hasdata = B_FALSE if there are no packets 35961ae08745Sheppo */ 35971ae08745Sheppo int 3598e1ebb9ecSlm66018 ldc_chkq(ldc_handle_t handle, boolean_t *hasdata) 35991ae08745Sheppo { 36001ae08745Sheppo int rv; 36011ae08745Sheppo uint64_t rx_head, rx_tail; 36021ae08745Sheppo ldc_chan_t *ldcp; 36031ae08745Sheppo 36041ae08745Sheppo if (handle == NULL) { 36051ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_chkq: invalid channel handle\n"); 36061ae08745Sheppo return (EINVAL); 36071ae08745Sheppo } 36081ae08745Sheppo ldcp = (ldc_chan_t *)handle; 36091ae08745Sheppo 3610e1ebb9ecSlm66018 *hasdata = B_FALSE; 36111ae08745Sheppo 36121ae08745Sheppo mutex_enter(&ldcp->lock); 36131ae08745Sheppo 36141ae08745Sheppo if (ldcp->tstate != TS_UP) { 36151ae08745Sheppo D1(ldcp->id, 36161ae08745Sheppo "ldc_chkq: (0x%llx) channel is not up\n", ldcp->id); 36171ae08745Sheppo mutex_exit(&ldcp->lock); 36181ae08745Sheppo return (ECONNRESET); 36191ae08745Sheppo } 36201ae08745Sheppo 36211ae08745Sheppo /* Read packet(s) from the queue */ 36221ae08745Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 36231ae08745Sheppo &ldcp->link_state); 36241ae08745Sheppo if (rv != 0) { 36251ae08745Sheppo cmn_err(CE_WARN, 36261ae08745Sheppo "ldc_chkq: (0x%lx) unable to read queue ptrs", ldcp->id); 36271ae08745Sheppo mutex_exit(&ldcp->lock); 36281ae08745Sheppo return (EIO); 36291ae08745Sheppo } 363058283286Sha137994 36311ae08745Sheppo /* reset the channel state if the channel went down */ 36321ae08745Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN || 36331ae08745Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 3634d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 36353af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 3636d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 36371ae08745Sheppo mutex_exit(&ldcp->lock); 36381ae08745Sheppo return (ECONNRESET); 36391ae08745Sheppo } 36401ae08745Sheppo 364158283286Sha137994 switch (ldcp->mode) { 364258283286Sha137994 case LDC_MODE_RAW: 364358283286Sha137994 /* 364458283286Sha137994 * In raw mode, there are no ctrl packets, so checking 364558283286Sha137994 * if the queue is non-empty is sufficient. 364658283286Sha137994 */ 364758283286Sha137994 *hasdata = (rx_head != rx_tail); 364858283286Sha137994 break; 364958283286Sha137994 365058283286Sha137994 case LDC_MODE_UNRELIABLE: 365158283286Sha137994 /* 365258283286Sha137994 * In unreliable mode, if the queue is non-empty, we need 365358283286Sha137994 * to check if it actually contains unread data packets. 365458283286Sha137994 * The queue may just contain ctrl packets. 365558283286Sha137994 */ 3656a74caf9bSha137994 if (rx_head != rx_tail) { 365758283286Sha137994 *hasdata = (i_ldc_chkq(ldcp) == 0); 3658a74caf9bSha137994 /* 3659a74caf9bSha137994 * If no data packets were found on the queue, 3660a74caf9bSha137994 * all packets must have been control packets 3661a74caf9bSha137994 * which will now have been processed, leaving 3662a74caf9bSha137994 * the queue empty. If the interrupt state 3663a74caf9bSha137994 * is pending, we need to clear the interrupt 3664a74caf9bSha137994 * here. 3665a74caf9bSha137994 */ 3666a74caf9bSha137994 if (*hasdata == B_FALSE && 3667a74caf9bSha137994 ldcp->rx_intr_state == LDC_INTR_PEND) { 3668a74caf9bSha137994 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 3669a74caf9bSha137994 } 3670a74caf9bSha137994 } 367158283286Sha137994 break; 367258283286Sha137994 367320ae46ebSha137994 case LDC_MODE_RELIABLE: 367458283286Sha137994 /* 367520ae46ebSha137994 * In reliable mode, first check for 'stream_remains' > 0. 367658283286Sha137994 * Otherwise, if the data queue head and tail pointers 367758283286Sha137994 * differ, there must be data to read. 367858283286Sha137994 */ 367958283286Sha137994 if (ldcp->stream_remains > 0) 3680e1ebb9ecSlm66018 *hasdata = B_TRUE; 368158283286Sha137994 else 368258283286Sha137994 *hasdata = (ldcp->rx_dq_head != ldcp->rx_dq_tail); 368358283286Sha137994 break; 368458283286Sha137994 368558283286Sha137994 default: 368658283286Sha137994 cmn_err(CE_WARN, "ldc_chkq: (0x%lx) unexpected channel mode " 368758283286Sha137994 "(0x%x)", ldcp->id, ldcp->mode); 368858283286Sha137994 mutex_exit(&ldcp->lock); 368958283286Sha137994 return (EIO); 36901ae08745Sheppo } 36911ae08745Sheppo 36921ae08745Sheppo mutex_exit(&ldcp->lock); 36931ae08745Sheppo 36941ae08745Sheppo return (0); 36951ae08745Sheppo } 36961ae08745Sheppo 36971ae08745Sheppo 36981ae08745Sheppo /* 36991ae08745Sheppo * Read 'size' amount of bytes or less. If incoming buffer 37001ae08745Sheppo * is more than 'size', ENOBUFS is returned. 37011ae08745Sheppo * 37021ae08745Sheppo * On return, size contains the number of bytes read. 37031ae08745Sheppo */ 37041ae08745Sheppo int 37051ae08745Sheppo ldc_read(ldc_handle_t handle, caddr_t bufp, size_t *sizep) 37061ae08745Sheppo { 37071ae08745Sheppo ldc_chan_t *ldcp; 37081ae08745Sheppo uint64_t rx_head = 0, rx_tail = 0; 37091ae08745Sheppo int rv = 0, exit_val; 37101ae08745Sheppo 37111ae08745Sheppo if (handle == NULL) { 37121ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_read: invalid channel handle\n"); 37131ae08745Sheppo return (EINVAL); 37141ae08745Sheppo } 37151ae08745Sheppo 37161ae08745Sheppo ldcp = (ldc_chan_t *)handle; 37171ae08745Sheppo 37181ae08745Sheppo /* channel lock */ 37191ae08745Sheppo mutex_enter(&ldcp->lock); 37201ae08745Sheppo 37211ae08745Sheppo if (ldcp->tstate != TS_UP) { 37221ae08745Sheppo DWARN(ldcp->id, 37231ae08745Sheppo "ldc_read: (0x%llx) channel is not in UP state\n", 37241ae08745Sheppo ldcp->id); 37251ae08745Sheppo exit_val = ECONNRESET; 372620ae46ebSha137994 } else if (ldcp->mode == LDC_MODE_RELIABLE) { 372758283286Sha137994 TRACE_RXDQ_LENGTH(ldcp); 372858283286Sha137994 exit_val = ldcp->read_p(ldcp, bufp, sizep); 372912f80fa6Sha137994 373012f80fa6Sha137994 /* 373112f80fa6Sha137994 * For reliable mode channels, the interrupt 373212f80fa6Sha137994 * state is only set to pending during 373312f80fa6Sha137994 * interrupt handling when the secondary data 373412f80fa6Sha137994 * queue became full, leaving unprocessed 373512f80fa6Sha137994 * packets on the Rx queue. If the interrupt 373612f80fa6Sha137994 * state is pending and space is now available 373712f80fa6Sha137994 * on the data queue, clear the interrupt. 373812f80fa6Sha137994 */ 373912f80fa6Sha137994 if (ldcp->rx_intr_state == LDC_INTR_PEND && 374012f80fa6Sha137994 Q_CONTIG_SPACE(ldcp->rx_dq_head, ldcp->rx_dq_tail, 374112f80fa6Sha137994 ldcp->rx_dq_entries << LDC_PACKET_SHIFT) >= 374212f80fa6Sha137994 LDC_PACKET_SIZE) { 374312f80fa6Sha137994 /* data queue is not full */ 374412f80fa6Sha137994 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 374512f80fa6Sha137994 } 374612f80fa6Sha137994 374758283286Sha137994 mutex_exit(&ldcp->lock); 374858283286Sha137994 return (exit_val); 37491ae08745Sheppo } else { 37501ae08745Sheppo exit_val = ldcp->read_p(ldcp, bufp, sizep); 37511ae08745Sheppo } 37521ae08745Sheppo 37531ae08745Sheppo /* 37541ae08745Sheppo * if queue has been drained - clear interrupt 37551ae08745Sheppo */ 37561ae08745Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 37571ae08745Sheppo &ldcp->link_state); 3758cb112a14Slm66018 if (rv != 0) { 3759cb112a14Slm66018 cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs", 3760cb112a14Slm66018 ldcp->id); 3761cb112a14Slm66018 mutex_enter(&ldcp->tx_lock); 3762cb112a14Slm66018 i_ldc_reset(ldcp, B_TRUE); 3763cb112a14Slm66018 mutex_exit(&ldcp->tx_lock); 3764bd8f0338Snarayan mutex_exit(&ldcp->lock); 3765cb112a14Slm66018 return (ECONNRESET); 3766cb112a14Slm66018 } 37673af08d82Slm66018 37683af08d82Slm66018 if (exit_val == 0) { 37693af08d82Slm66018 if (ldcp->link_state == LDC_CHANNEL_DOWN || 37703af08d82Slm66018 ldcp->link_state == LDC_CHANNEL_RESET) { 37713af08d82Slm66018 mutex_enter(&ldcp->tx_lock); 37723af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 37733af08d82Slm66018 exit_val = ECONNRESET; 37743af08d82Slm66018 mutex_exit(&ldcp->tx_lock); 37753af08d82Slm66018 } 37763af08d82Slm66018 if ((rv == 0) && 37773af08d82Slm66018 (ldcp->rx_intr_state == LDC_INTR_PEND) && 37783af08d82Slm66018 (rx_head == rx_tail)) { 37791ae08745Sheppo i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 37801ae08745Sheppo } 37813af08d82Slm66018 } 37821ae08745Sheppo 37831ae08745Sheppo mutex_exit(&ldcp->lock); 37841ae08745Sheppo return (exit_val); 37851ae08745Sheppo } 37861ae08745Sheppo 37871ae08745Sheppo /* 37881ae08745Sheppo * Basic raw mondo read - 37891ae08745Sheppo * no interpretation of mondo contents at all. 37901ae08745Sheppo * 37911ae08745Sheppo * Enter and exit with ldcp->lock held by caller 37921ae08745Sheppo */ 37931ae08745Sheppo static int 37941ae08745Sheppo i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep) 37951ae08745Sheppo { 37961ae08745Sheppo uint64_t q_size_mask; 37971ae08745Sheppo ldc_msg_t *msgp; 37981ae08745Sheppo uint8_t *msgbufp; 37991ae08745Sheppo int rv = 0, space; 38001ae08745Sheppo uint64_t rx_head, rx_tail; 38011ae08745Sheppo 38021ae08745Sheppo space = *sizep; 38031ae08745Sheppo 38041ae08745Sheppo if (space < LDC_PAYLOAD_SIZE_RAW) 38051ae08745Sheppo return (ENOBUFS); 38061ae08745Sheppo 38071ae08745Sheppo ASSERT(mutex_owned(&ldcp->lock)); 38081ae08745Sheppo 38091ae08745Sheppo /* compute mask for increment */ 38101ae08745Sheppo q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT; 38111ae08745Sheppo 38121ae08745Sheppo /* 38131ae08745Sheppo * Read packet(s) from the queue 38141ae08745Sheppo */ 38151ae08745Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 38161ae08745Sheppo &ldcp->link_state); 38171ae08745Sheppo if (rv != 0) { 38181ae08745Sheppo cmn_err(CE_WARN, 38191ae08745Sheppo "ldc_read_raw: (0x%lx) unable to read queue ptrs", 38201ae08745Sheppo ldcp->id); 38211ae08745Sheppo return (EIO); 38221ae08745Sheppo } 38231ae08745Sheppo D1(ldcp->id, "ldc_read_raw: (0x%llx) rxh=0x%llx," 38241ae08745Sheppo " rxt=0x%llx, st=0x%llx\n", 38251ae08745Sheppo ldcp->id, rx_head, rx_tail, ldcp->link_state); 38261ae08745Sheppo 38271ae08745Sheppo /* reset the channel state if the channel went down */ 38283af08d82Slm66018 if (ldcp->link_state == LDC_CHANNEL_DOWN || 38293af08d82Slm66018 ldcp->link_state == LDC_CHANNEL_RESET) { 3830d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 38313af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 3832d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 38331ae08745Sheppo return (ECONNRESET); 38341ae08745Sheppo } 38351ae08745Sheppo 38361ae08745Sheppo /* 38371ae08745Sheppo * Check for empty queue 38381ae08745Sheppo */ 38391ae08745Sheppo if (rx_head == rx_tail) { 38401ae08745Sheppo *sizep = 0; 38411ae08745Sheppo return (0); 38421ae08745Sheppo } 38431ae08745Sheppo 38441ae08745Sheppo /* get the message */ 38451ae08745Sheppo msgp = (ldc_msg_t *)(ldcp->rx_q_va + rx_head); 38461ae08745Sheppo 38471ae08745Sheppo /* if channel is in RAW mode, copy data and return */ 38481ae08745Sheppo msgbufp = (uint8_t *)&(msgp->raw[0]); 38491ae08745Sheppo 38501ae08745Sheppo bcopy(msgbufp, target_bufp, LDC_PAYLOAD_SIZE_RAW); 38511ae08745Sheppo 38521ae08745Sheppo DUMP_PAYLOAD(ldcp->id, msgbufp); 38531ae08745Sheppo 38541ae08745Sheppo *sizep = LDC_PAYLOAD_SIZE_RAW; 38551ae08745Sheppo 38561ae08745Sheppo rx_head = (rx_head + LDC_PACKET_SIZE) & q_size_mask; 38570a55fbb7Slm66018 rv = i_ldc_set_rx_head(ldcp, rx_head); 38581ae08745Sheppo 38591ae08745Sheppo return (rv); 38601ae08745Sheppo } 38611ae08745Sheppo 38621ae08745Sheppo /* 38631ae08745Sheppo * Process LDC mondos to build larger packets 38641ae08745Sheppo * with either un-reliable or reliable delivery. 38651ae08745Sheppo * 38661ae08745Sheppo * Enter and exit with ldcp->lock held by caller 38671ae08745Sheppo */ 38681ae08745Sheppo static int 38691ae08745Sheppo i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep) 38701ae08745Sheppo { 38711ae08745Sheppo int rv = 0; 38721ae08745Sheppo uint64_t rx_head = 0, rx_tail = 0; 38731ae08745Sheppo uint64_t curr_head = 0; 38741ae08745Sheppo ldc_msg_t *msg; 38751ae08745Sheppo caddr_t target; 38761ae08745Sheppo size_t len = 0, bytes_read = 0; 38770a55fbb7Slm66018 int retries = 0; 387858283286Sha137994 uint64_t q_va, q_size_mask; 3879d10e4ef2Snarayan uint64_t first_fragment = 0; 38801ae08745Sheppo 38811ae08745Sheppo target = target_bufp; 38821ae08745Sheppo 38831ae08745Sheppo ASSERT(mutex_owned(&ldcp->lock)); 38841ae08745Sheppo 38853af08d82Slm66018 /* check if the buffer and size are valid */ 38863af08d82Slm66018 if (target_bufp == NULL || *sizep == 0) { 38873af08d82Slm66018 DWARN(ldcp->id, "ldc_read: (0x%llx) invalid buffer/size\n", 38883af08d82Slm66018 ldcp->id); 38893af08d82Slm66018 return (EINVAL); 38903af08d82Slm66018 } 38913af08d82Slm66018 389258283286Sha137994 /* Set q_va and compute increment mask for the appropriate queue */ 389320ae46ebSha137994 if (ldcp->mode == LDC_MODE_RELIABLE) { 389458283286Sha137994 q_va = ldcp->rx_dq_va; 389558283286Sha137994 q_size_mask = (ldcp->rx_dq_entries-1)<<LDC_PACKET_SHIFT; 389658283286Sha137994 } else { 389758283286Sha137994 q_va = ldcp->rx_q_va; 38981ae08745Sheppo q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT; 389958283286Sha137994 } 39001ae08745Sheppo 39011ae08745Sheppo /* 39021ae08745Sheppo * Read packet(s) from the queue 39031ae08745Sheppo */ 390458283286Sha137994 rv = ldcp->readq_get_state(ldcp, &curr_head, &rx_tail, 39051ae08745Sheppo &ldcp->link_state); 39061ae08745Sheppo if (rv != 0) { 39073af08d82Slm66018 cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs", 39081ae08745Sheppo ldcp->id); 39093af08d82Slm66018 mutex_enter(&ldcp->tx_lock); 39103af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 39113af08d82Slm66018 mutex_exit(&ldcp->tx_lock); 39123af08d82Slm66018 return (ECONNRESET); 39131ae08745Sheppo } 39141ae08745Sheppo D1(ldcp->id, "ldc_read: (0x%llx) chd=0x%llx, tl=0x%llx, st=0x%llx\n", 39151ae08745Sheppo ldcp->id, curr_head, rx_tail, ldcp->link_state); 39161ae08745Sheppo 39171ae08745Sheppo /* reset the channel state if the channel went down */ 39183af08d82Slm66018 if (ldcp->link_state != LDC_CHANNEL_UP) 39193af08d82Slm66018 goto channel_is_reset; 39201ae08745Sheppo 39211ae08745Sheppo for (;;) { 39221ae08745Sheppo 39231ae08745Sheppo if (curr_head == rx_tail) { 392458283286Sha137994 /* 392558283286Sha137994 * If a data queue is being used, check the Rx HV 392658283286Sha137994 * queue. This will copy over any new data packets 392758283286Sha137994 * that have arrived. 392858283286Sha137994 */ 392920ae46ebSha137994 if (ldcp->mode == LDC_MODE_RELIABLE) 393058283286Sha137994 (void) i_ldc_chkq(ldcp); 393158283286Sha137994 393258283286Sha137994 rv = ldcp->readq_get_state(ldcp, 39331ae08745Sheppo &rx_head, &rx_tail, &ldcp->link_state); 39341ae08745Sheppo if (rv != 0) { 39351ae08745Sheppo cmn_err(CE_WARN, 39361ae08745Sheppo "ldc_read: (0x%lx) cannot read queue ptrs", 39371ae08745Sheppo ldcp->id); 3938d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 39393af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 3940d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 39411ae08745Sheppo return (ECONNRESET); 39421ae08745Sheppo } 394358283286Sha137994 39443af08d82Slm66018 if (ldcp->link_state != LDC_CHANNEL_UP) 39453af08d82Slm66018 goto channel_is_reset; 39461ae08745Sheppo 39471ae08745Sheppo if (curr_head == rx_tail) { 39481ae08745Sheppo 39491ae08745Sheppo /* If in the middle of a fragmented xfer */ 3950d10e4ef2Snarayan if (first_fragment != 0) { 39510a55fbb7Slm66018 39520a55fbb7Slm66018 /* wait for ldc_delay usecs */ 39530a55fbb7Slm66018 drv_usecwait(ldc_delay); 39540a55fbb7Slm66018 39550a55fbb7Slm66018 if (++retries < ldc_max_retries) 39561ae08745Sheppo continue; 39570a55fbb7Slm66018 39581ae08745Sheppo *sizep = 0; 395920ae46ebSha137994 if (ldcp->mode != LDC_MODE_RELIABLE) 396058283286Sha137994 ldcp->last_msg_rcd = 396158283286Sha137994 first_fragment - 1; 39623af08d82Slm66018 DWARN(DBG_ALL_LDCS, "ldc_read: " 396322f747efSnarayan "(0x%llx) read timeout", ldcp->id); 39643af08d82Slm66018 return (EAGAIN); 39651ae08745Sheppo } 39661ae08745Sheppo *sizep = 0; 39671ae08745Sheppo break; 39681ae08745Sheppo } 39693af08d82Slm66018 } 39700a55fbb7Slm66018 retries = 0; 39711ae08745Sheppo 39721ae08745Sheppo D2(ldcp->id, 39731ae08745Sheppo "ldc_read: (0x%llx) chd=0x%llx, rxhd=0x%llx, rxtl=0x%llx\n", 39741ae08745Sheppo ldcp->id, curr_head, rx_head, rx_tail); 39751ae08745Sheppo 39761ae08745Sheppo /* get the message */ 397758283286Sha137994 msg = (ldc_msg_t *)(q_va + curr_head); 39781ae08745Sheppo 39791ae08745Sheppo DUMP_LDC_PKT(ldcp, "ldc_read received pkt", 39801ae08745Sheppo ldcp->rx_q_va + curr_head); 39811ae08745Sheppo 39821ae08745Sheppo /* Check the message ID for the message received */ 398320ae46ebSha137994 if (ldcp->mode != LDC_MODE_RELIABLE) { 39841ae08745Sheppo if ((rv = i_ldc_check_seqid(ldcp, msg)) != 0) { 39851ae08745Sheppo 398658283286Sha137994 DWARN(ldcp->id, "ldc_read: (0x%llx) seqid " 398758283286Sha137994 "error, q_ptrs=0x%lx,0x%lx", 398858283286Sha137994 ldcp->id, rx_head, rx_tail); 39891ae08745Sheppo 39900a55fbb7Slm66018 /* throw away data */ 39910a55fbb7Slm66018 bytes_read = 0; 39920a55fbb7Slm66018 39931ae08745Sheppo /* Reset last_msg_rcd to start of message */ 3994d10e4ef2Snarayan if (first_fragment != 0) { 3995d10e4ef2Snarayan ldcp->last_msg_rcd = first_fragment - 1; 3996d10e4ef2Snarayan first_fragment = 0; 39971ae08745Sheppo } 39981ae08745Sheppo /* 39991ae08745Sheppo * Send a NACK -- invalid seqid 40001ae08745Sheppo * get the current tail for the response 40011ae08745Sheppo */ 40021ae08745Sheppo rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK, 40031ae08745Sheppo (msg->ctrl & LDC_CTRL_MASK)); 40041ae08745Sheppo if (rv) { 40051ae08745Sheppo cmn_err(CE_NOTE, 40061ae08745Sheppo "ldc_read: (0x%lx) err sending " 40071ae08745Sheppo "NACK msg\n", ldcp->id); 4008d10e4ef2Snarayan 400958283286Sha137994 /* if cannot send NACK - reset chan */ 4010d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 40113af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 4012d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 4013d10e4ef2Snarayan rv = ECONNRESET; 4014d10e4ef2Snarayan break; 40151ae08745Sheppo } 40161ae08745Sheppo 40171ae08745Sheppo /* purge receive queue */ 40180a55fbb7Slm66018 rv = i_ldc_set_rx_head(ldcp, rx_tail); 40191ae08745Sheppo 40201ae08745Sheppo break; 40211ae08745Sheppo } 40221ae08745Sheppo 40231ae08745Sheppo /* 40241ae08745Sheppo * Process any messages of type CTRL messages 4025e1ebb9ecSlm66018 * Future implementations should try to pass these 4026e1ebb9ecSlm66018 * to LDC link by resetting the intr state. 40271ae08745Sheppo * 402858283286Sha137994 * NOTE: not done as a switch() as type can be 402958283286Sha137994 * both ctrl+data 40301ae08745Sheppo */ 40311ae08745Sheppo if (msg->type & LDC_CTRL) { 40321ae08745Sheppo if (rv = i_ldc_ctrlmsg(ldcp, msg)) { 40331ae08745Sheppo if (rv == EAGAIN) 40341ae08745Sheppo continue; 40350a55fbb7Slm66018 rv = i_ldc_set_rx_head(ldcp, rx_tail); 40361ae08745Sheppo *sizep = 0; 40371ae08745Sheppo bytes_read = 0; 40381ae08745Sheppo break; 40391ae08745Sheppo } 40401ae08745Sheppo } 40411ae08745Sheppo 40421ae08745Sheppo /* process data ACKs */ 40431ae08745Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) { 4044d10e4ef2Snarayan if (rv = i_ldc_process_data_ACK(ldcp, msg)) { 4045d10e4ef2Snarayan *sizep = 0; 4046d10e4ef2Snarayan bytes_read = 0; 4047d10e4ef2Snarayan break; 4048d10e4ef2Snarayan } 40491ae08745Sheppo } 40501ae08745Sheppo 405183d3bc6fSnarayan /* process data NACKs */ 405283d3bc6fSnarayan if ((msg->type & LDC_DATA) && (msg->stype & LDC_NACK)) { 405383d3bc6fSnarayan DWARN(ldcp->id, 405458283286Sha137994 "ldc_read: (0x%llx) received DATA/NACK", 405558283286Sha137994 ldcp->id); 405683d3bc6fSnarayan mutex_enter(&ldcp->tx_lock); 405783d3bc6fSnarayan i_ldc_reset(ldcp, B_TRUE); 405883d3bc6fSnarayan mutex_exit(&ldcp->tx_lock); 405983d3bc6fSnarayan return (ECONNRESET); 406083d3bc6fSnarayan } 406158283286Sha137994 } 406283d3bc6fSnarayan 40631ae08745Sheppo /* process data messages */ 40641ae08745Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) { 40651ae08745Sheppo 40661ae08745Sheppo uint8_t *msgbuf = (uint8_t *)( 406720ae46ebSha137994 (ldcp->mode == LDC_MODE_RELIABLE) ? 406822f747efSnarayan msg->rdata : msg->udata); 40691ae08745Sheppo 40701ae08745Sheppo D2(ldcp->id, 40711ae08745Sheppo "ldc_read: (0x%llx) received data msg\n", ldcp->id); 40721ae08745Sheppo 40731ae08745Sheppo /* get the packet length */ 40741ae08745Sheppo len = (msg->env & LDC_LEN_MASK); 40751ae08745Sheppo 40761ae08745Sheppo /* 40771ae08745Sheppo * FUTURE OPTIMIZATION: 40781ae08745Sheppo * dont need to set q head for every 40791ae08745Sheppo * packet we read just need to do this when 40801ae08745Sheppo * we are done or need to wait for more 40811ae08745Sheppo * mondos to make a full packet - this is 40821ae08745Sheppo * currently expensive. 40831ae08745Sheppo */ 40841ae08745Sheppo 4085d10e4ef2Snarayan if (first_fragment == 0) { 40861ae08745Sheppo 40871ae08745Sheppo /* 40881ae08745Sheppo * first packets should always have the start 40891ae08745Sheppo * bit set (even for a single packet). If not 40901ae08745Sheppo * throw away the packet 40911ae08745Sheppo */ 40921ae08745Sheppo if (!(msg->env & LDC_FRAG_START)) { 40931ae08745Sheppo 40941ae08745Sheppo DWARN(DBG_ALL_LDCS, 40951ae08745Sheppo "ldc_read: (0x%llx) not start - " 40961ae08745Sheppo "frag=%x\n", ldcp->id, 40971ae08745Sheppo (msg->env) & LDC_FRAG_MASK); 40981ae08745Sheppo 40991ae08745Sheppo /* toss pkt, inc head, cont reading */ 41001ae08745Sheppo bytes_read = 0; 41011ae08745Sheppo target = target_bufp; 41021ae08745Sheppo curr_head = 41031ae08745Sheppo (curr_head + LDC_PACKET_SIZE) 41041ae08745Sheppo & q_size_mask; 410558283286Sha137994 if (rv = ldcp->readq_set_head(ldcp, 41061ae08745Sheppo curr_head)) 41071ae08745Sheppo break; 41081ae08745Sheppo 41091ae08745Sheppo continue; 41101ae08745Sheppo } 41111ae08745Sheppo 4112d10e4ef2Snarayan first_fragment = msg->seqid; 41131ae08745Sheppo } else { 41141ae08745Sheppo /* check to see if this is a pkt w/ START bit */ 41151ae08745Sheppo if (msg->env & LDC_FRAG_START) { 41161ae08745Sheppo DWARN(DBG_ALL_LDCS, 41171ae08745Sheppo "ldc_read:(0x%llx) unexpected pkt" 41181ae08745Sheppo " env=0x%x discarding %d bytes," 41191ae08745Sheppo " lastmsg=%d, currentmsg=%d\n", 41201ae08745Sheppo ldcp->id, msg->env&LDC_FRAG_MASK, 41211ae08745Sheppo bytes_read, ldcp->last_msg_rcd, 41221ae08745Sheppo msg->seqid); 41231ae08745Sheppo 41241ae08745Sheppo /* throw data we have read so far */ 41251ae08745Sheppo bytes_read = 0; 41261ae08745Sheppo target = target_bufp; 4127d10e4ef2Snarayan first_fragment = msg->seqid; 41281ae08745Sheppo 412958283286Sha137994 if (rv = ldcp->readq_set_head(ldcp, 41301ae08745Sheppo curr_head)) 41311ae08745Sheppo break; 41321ae08745Sheppo } 41331ae08745Sheppo } 41341ae08745Sheppo 41351ae08745Sheppo /* copy (next) pkt into buffer */ 41361ae08745Sheppo if (len <= (*sizep - bytes_read)) { 41371ae08745Sheppo bcopy(msgbuf, target, len); 41381ae08745Sheppo target += len; 41391ae08745Sheppo bytes_read += len; 41401ae08745Sheppo } else { 41411ae08745Sheppo /* 41421ae08745Sheppo * there is not enough space in the buffer to 41431ae08745Sheppo * read this pkt. throw message away & continue 41441ae08745Sheppo * reading data from queue 41451ae08745Sheppo */ 41461ae08745Sheppo DWARN(DBG_ALL_LDCS, 41471ae08745Sheppo "ldc_read: (0x%llx) buffer too small, " 41481ae08745Sheppo "head=0x%lx, expect=%d, got=%d\n", ldcp->id, 41491ae08745Sheppo curr_head, *sizep, bytes_read+len); 41501ae08745Sheppo 4151d10e4ef2Snarayan first_fragment = 0; 41521ae08745Sheppo target = target_bufp; 41531ae08745Sheppo bytes_read = 0; 41541ae08745Sheppo 41551ae08745Sheppo /* throw away everything received so far */ 415658283286Sha137994 if (rv = ldcp->readq_set_head(ldcp, curr_head)) 41571ae08745Sheppo break; 41581ae08745Sheppo 41591ae08745Sheppo /* continue reading remaining pkts */ 41601ae08745Sheppo continue; 41611ae08745Sheppo } 41621ae08745Sheppo } 41631ae08745Sheppo 41641ae08745Sheppo /* set the message id */ 416520ae46ebSha137994 if (ldcp->mode != LDC_MODE_RELIABLE) 41661ae08745Sheppo ldcp->last_msg_rcd = msg->seqid; 41671ae08745Sheppo 41681ae08745Sheppo /* move the head one position */ 41691ae08745Sheppo curr_head = (curr_head + LDC_PACKET_SIZE) & q_size_mask; 41701ae08745Sheppo 41711ae08745Sheppo if (msg->env & LDC_FRAG_STOP) { 41721ae08745Sheppo 41731ae08745Sheppo /* 41741ae08745Sheppo * All pkts that are part of this fragmented transfer 41751ae08745Sheppo * have been read or this was a single pkt read 41761ae08745Sheppo * or there was an error 41771ae08745Sheppo */ 41781ae08745Sheppo 41791ae08745Sheppo /* set the queue head */ 418058283286Sha137994 if (rv = ldcp->readq_set_head(ldcp, curr_head)) 41811ae08745Sheppo bytes_read = 0; 41821ae08745Sheppo 41831ae08745Sheppo *sizep = bytes_read; 41841ae08745Sheppo 41851ae08745Sheppo break; 41861ae08745Sheppo } 41871ae08745Sheppo 4188332608acSnarayan /* advance head if it is a CTRL packet or a DATA ACK packet */ 4189332608acSnarayan if ((msg->type & LDC_CTRL) || 4190332608acSnarayan ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK))) { 41911ae08745Sheppo 41921ae08745Sheppo /* set the queue head */ 419358283286Sha137994 if (rv = ldcp->readq_set_head(ldcp, curr_head)) { 41941ae08745Sheppo bytes_read = 0; 41951ae08745Sheppo break; 41961ae08745Sheppo } 41971ae08745Sheppo 41981ae08745Sheppo D2(ldcp->id, "ldc_read: (0x%llx) set ACK qhead 0x%llx", 41991ae08745Sheppo ldcp->id, curr_head); 42001ae08745Sheppo } 42011ae08745Sheppo 42021ae08745Sheppo } /* for (;;) */ 42031ae08745Sheppo 42041ae08745Sheppo D2(ldcp->id, "ldc_read: (0x%llx) end size=%d", ldcp->id, *sizep); 42051ae08745Sheppo 42061ae08745Sheppo return (rv); 42073af08d82Slm66018 42083af08d82Slm66018 channel_is_reset: 42093af08d82Slm66018 mutex_enter(&ldcp->tx_lock); 42103af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 42113af08d82Slm66018 mutex_exit(&ldcp->tx_lock); 42123af08d82Slm66018 return (ECONNRESET); 42131ae08745Sheppo } 42141ae08745Sheppo 42151ae08745Sheppo /* 421620ae46ebSha137994 * Fetch and buffer incoming packets so we can hand them back as 42171ae08745Sheppo * a basic byte stream. 42181ae08745Sheppo * 42191ae08745Sheppo * Enter and exit with ldcp->lock held by caller 42201ae08745Sheppo */ 42211ae08745Sheppo static int 42221ae08745Sheppo i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep) 42231ae08745Sheppo { 42241ae08745Sheppo int rv; 42251ae08745Sheppo size_t size; 42261ae08745Sheppo 42271ae08745Sheppo ASSERT(mutex_owned(&ldcp->lock)); 42281ae08745Sheppo 42291ae08745Sheppo D2(ldcp->id, "i_ldc_read_stream: (0x%llx) buffer size=%d", 42301ae08745Sheppo ldcp->id, *sizep); 42311ae08745Sheppo 42321ae08745Sheppo if (ldcp->stream_remains == 0) { 42331ae08745Sheppo size = ldcp->mtu; 42341ae08745Sheppo rv = i_ldc_read_packet(ldcp, 42351ae08745Sheppo (caddr_t)ldcp->stream_bufferp, &size); 42361ae08745Sheppo D2(ldcp->id, "i_ldc_read_stream: read packet (0x%llx) size=%d", 42371ae08745Sheppo ldcp->id, size); 42381ae08745Sheppo 42391ae08745Sheppo if (rv != 0) 42401ae08745Sheppo return (rv); 42411ae08745Sheppo 42421ae08745Sheppo ldcp->stream_remains = size; 42431ae08745Sheppo ldcp->stream_offset = 0; 42441ae08745Sheppo } 42451ae08745Sheppo 42461ae08745Sheppo size = MIN(ldcp->stream_remains, *sizep); 42471ae08745Sheppo 42481ae08745Sheppo bcopy(ldcp->stream_bufferp + ldcp->stream_offset, target_bufp, size); 42491ae08745Sheppo ldcp->stream_offset += size; 42501ae08745Sheppo ldcp->stream_remains -= size; 42511ae08745Sheppo 42521ae08745Sheppo D2(ldcp->id, "i_ldc_read_stream: (0x%llx) fill from buffer size=%d", 42531ae08745Sheppo ldcp->id, size); 42541ae08745Sheppo 42551ae08745Sheppo *sizep = size; 42561ae08745Sheppo return (0); 42571ae08745Sheppo } 42581ae08745Sheppo 42591ae08745Sheppo /* 42601ae08745Sheppo * Write specified amount of bytes to the channel 42611ae08745Sheppo * in multiple pkts of pkt_payload size. Each 42621ae08745Sheppo * packet is tagged with an unique packet ID in 4263e1ebb9ecSlm66018 * the case of a reliable link. 42641ae08745Sheppo * 42651ae08745Sheppo * On return, size contains the number of bytes written. 42661ae08745Sheppo */ 42671ae08745Sheppo int 42681ae08745Sheppo ldc_write(ldc_handle_t handle, caddr_t buf, size_t *sizep) 42691ae08745Sheppo { 42701ae08745Sheppo ldc_chan_t *ldcp; 42711ae08745Sheppo int rv = 0; 42721ae08745Sheppo 42731ae08745Sheppo if (handle == NULL) { 42741ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_write: invalid channel handle\n"); 42751ae08745Sheppo return (EINVAL); 42761ae08745Sheppo } 42771ae08745Sheppo ldcp = (ldc_chan_t *)handle; 42781ae08745Sheppo 4279*7bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->tx_lock); 42801ae08745Sheppo 42811ae08745Sheppo /* check if non-zero data to write */ 42821ae08745Sheppo if (buf == NULL || sizep == NULL) { 42831ae08745Sheppo DWARN(ldcp->id, "ldc_write: (0x%llx) invalid data write\n", 42841ae08745Sheppo ldcp->id); 4285d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 42861ae08745Sheppo return (EINVAL); 42871ae08745Sheppo } 42881ae08745Sheppo 42891ae08745Sheppo if (*sizep == 0) { 42901ae08745Sheppo DWARN(ldcp->id, "ldc_write: (0x%llx) write size of zero\n", 42911ae08745Sheppo ldcp->id); 4292d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 42931ae08745Sheppo return (0); 42941ae08745Sheppo } 42951ae08745Sheppo 42961ae08745Sheppo /* Check if channel is UP for data exchange */ 42971ae08745Sheppo if (ldcp->tstate != TS_UP) { 42981ae08745Sheppo DWARN(ldcp->id, 42991ae08745Sheppo "ldc_write: (0x%llx) channel is not in UP state\n", 43001ae08745Sheppo ldcp->id); 43011ae08745Sheppo *sizep = 0; 43021ae08745Sheppo rv = ECONNRESET; 43031ae08745Sheppo } else { 43041ae08745Sheppo rv = ldcp->write_p(ldcp, buf, sizep); 43051ae08745Sheppo } 43061ae08745Sheppo 4307d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 43081ae08745Sheppo 43091ae08745Sheppo return (rv); 43101ae08745Sheppo } 43111ae08745Sheppo 43121ae08745Sheppo /* 43131ae08745Sheppo * Write a raw packet to the channel 43141ae08745Sheppo * On return, size contains the number of bytes written. 43151ae08745Sheppo */ 43161ae08745Sheppo static int 43171ae08745Sheppo i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep) 43181ae08745Sheppo { 43191ae08745Sheppo ldc_msg_t *ldcmsg; 43201ae08745Sheppo uint64_t tx_head, tx_tail, new_tail; 43211ae08745Sheppo int rv = 0; 43221ae08745Sheppo size_t size; 43231ae08745Sheppo 4324d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 43251ae08745Sheppo ASSERT(ldcp->mode == LDC_MODE_RAW); 43261ae08745Sheppo 43271ae08745Sheppo size = *sizep; 43281ae08745Sheppo 43291ae08745Sheppo /* 43301ae08745Sheppo * Check to see if the packet size is less than or 43311ae08745Sheppo * equal to packet size support in raw mode 43321ae08745Sheppo */ 43331ae08745Sheppo if (size > ldcp->pkt_payload) { 43341ae08745Sheppo DWARN(ldcp->id, 43351ae08745Sheppo "ldc_write: (0x%llx) invalid size (0x%llx) for RAW mode\n", 43361ae08745Sheppo ldcp->id, *sizep); 43371ae08745Sheppo *sizep = 0; 43381ae08745Sheppo return (EMSGSIZE); 43391ae08745Sheppo } 43401ae08745Sheppo 43411ae08745Sheppo /* get the qptrs for the tx queue */ 43421ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 43431ae08745Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 43441ae08745Sheppo if (rv != 0) { 43451ae08745Sheppo cmn_err(CE_WARN, 43461ae08745Sheppo "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id); 43471ae08745Sheppo *sizep = 0; 43481ae08745Sheppo return (EIO); 43491ae08745Sheppo } 43501ae08745Sheppo 43511ae08745Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN || 43521ae08745Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 43531ae08745Sheppo DWARN(ldcp->id, 43541ae08745Sheppo "ldc_write: (0x%llx) channel down/reset\n", ldcp->id); 4355d10e4ef2Snarayan 43561ae08745Sheppo *sizep = 0; 4357d10e4ef2Snarayan if (mutex_tryenter(&ldcp->lock)) { 43583af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 4359d10e4ef2Snarayan mutex_exit(&ldcp->lock); 4360d10e4ef2Snarayan } else { 4361d10e4ef2Snarayan /* 4362d10e4ef2Snarayan * Release Tx lock, and then reacquire channel 4363d10e4ef2Snarayan * and Tx lock in correct order 4364d10e4ef2Snarayan */ 4365d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 4366d10e4ef2Snarayan mutex_enter(&ldcp->lock); 4367d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 43683af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 4369d10e4ef2Snarayan mutex_exit(&ldcp->lock); 4370d10e4ef2Snarayan } 43711ae08745Sheppo return (ECONNRESET); 43721ae08745Sheppo } 43731ae08745Sheppo 43741ae08745Sheppo tx_tail = ldcp->tx_tail; 43751ae08745Sheppo tx_head = ldcp->tx_head; 43761ae08745Sheppo new_tail = (tx_tail + LDC_PACKET_SIZE) & 43771ae08745Sheppo ((ldcp->tx_q_entries-1) << LDC_PACKET_SHIFT); 43781ae08745Sheppo 43791ae08745Sheppo if (new_tail == tx_head) { 43801ae08745Sheppo DWARN(DBG_ALL_LDCS, 43811ae08745Sheppo "ldc_write: (0x%llx) TX queue is full\n", ldcp->id); 43821ae08745Sheppo *sizep = 0; 43831ae08745Sheppo return (EWOULDBLOCK); 43841ae08745Sheppo } 43851ae08745Sheppo 43861ae08745Sheppo D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d", 43871ae08745Sheppo ldcp->id, size); 43881ae08745Sheppo 43891ae08745Sheppo /* Send the data now */ 43901ae08745Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 43911ae08745Sheppo 43921ae08745Sheppo /* copy the data into pkt */ 43931ae08745Sheppo bcopy((uint8_t *)buf, ldcmsg, size); 43941ae08745Sheppo 43951ae08745Sheppo /* increment tail */ 43961ae08745Sheppo tx_tail = new_tail; 43971ae08745Sheppo 43981ae08745Sheppo /* 43991ae08745Sheppo * All packets have been copied into the TX queue 44001ae08745Sheppo * update the tail ptr in the HV 44011ae08745Sheppo */ 44021ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 44031ae08745Sheppo if (rv) { 44041ae08745Sheppo if (rv == EWOULDBLOCK) { 44051ae08745Sheppo DWARN(ldcp->id, "ldc_write: (0x%llx) write timed out\n", 44061ae08745Sheppo ldcp->id); 44071ae08745Sheppo *sizep = 0; 44081ae08745Sheppo return (EWOULDBLOCK); 44091ae08745Sheppo } 44101ae08745Sheppo 44111ae08745Sheppo *sizep = 0; 4412d10e4ef2Snarayan if (mutex_tryenter(&ldcp->lock)) { 44133af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 4414d10e4ef2Snarayan mutex_exit(&ldcp->lock); 4415d10e4ef2Snarayan } else { 4416d10e4ef2Snarayan /* 4417d10e4ef2Snarayan * Release Tx lock, and then reacquire channel 4418d10e4ef2Snarayan * and Tx lock in correct order 4419d10e4ef2Snarayan */ 4420d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 4421d10e4ef2Snarayan mutex_enter(&ldcp->lock); 4422d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 44233af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 4424d10e4ef2Snarayan mutex_exit(&ldcp->lock); 4425d10e4ef2Snarayan } 44261ae08745Sheppo return (ECONNRESET); 44271ae08745Sheppo } 44281ae08745Sheppo 44291ae08745Sheppo ldcp->tx_tail = tx_tail; 44301ae08745Sheppo *sizep = size; 44311ae08745Sheppo 44321ae08745Sheppo D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, size); 44331ae08745Sheppo 44341ae08745Sheppo return (rv); 44351ae08745Sheppo } 44361ae08745Sheppo 44371ae08745Sheppo 44381ae08745Sheppo /* 44391ae08745Sheppo * Write specified amount of bytes to the channel 44401ae08745Sheppo * in multiple pkts of pkt_payload size. Each 44411ae08745Sheppo * packet is tagged with an unique packet ID in 4442e1ebb9ecSlm66018 * the case of a reliable link. 44431ae08745Sheppo * 44441ae08745Sheppo * On return, size contains the number of bytes written. 44451ae08745Sheppo * This function needs to ensure that the write size is < MTU size 44461ae08745Sheppo */ 44471ae08745Sheppo static int 44481ae08745Sheppo i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t buf, size_t *size) 44491ae08745Sheppo { 44501ae08745Sheppo ldc_msg_t *ldcmsg; 44511ae08745Sheppo uint64_t tx_head, tx_tail, new_tail, start; 44521ae08745Sheppo uint64_t txq_size_mask, numavail; 44531ae08745Sheppo uint8_t *msgbuf, *source = (uint8_t *)buf; 44541ae08745Sheppo size_t len, bytes_written = 0, remaining; 44551ae08745Sheppo int rv; 44561ae08745Sheppo uint32_t curr_seqid; 44571ae08745Sheppo 4458d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 44591ae08745Sheppo 44601ae08745Sheppo ASSERT(ldcp->mode == LDC_MODE_RELIABLE || 446120ae46ebSha137994 ldcp->mode == LDC_MODE_UNRELIABLE); 44621ae08745Sheppo 44631ae08745Sheppo /* compute mask for increment */ 44641ae08745Sheppo txq_size_mask = (ldcp->tx_q_entries - 1) << LDC_PACKET_SHIFT; 44651ae08745Sheppo 44661ae08745Sheppo /* get the qptrs for the tx queue */ 44671ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 44681ae08745Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 44691ae08745Sheppo if (rv != 0) { 44701ae08745Sheppo cmn_err(CE_WARN, 44711ae08745Sheppo "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id); 44721ae08745Sheppo *size = 0; 44731ae08745Sheppo return (EIO); 44741ae08745Sheppo } 44751ae08745Sheppo 44761ae08745Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN || 44771ae08745Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 44781ae08745Sheppo DWARN(ldcp->id, 44791ae08745Sheppo "ldc_write: (0x%llx) channel down/reset\n", ldcp->id); 44801ae08745Sheppo *size = 0; 4481d10e4ef2Snarayan if (mutex_tryenter(&ldcp->lock)) { 44823af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 4483d10e4ef2Snarayan mutex_exit(&ldcp->lock); 4484d10e4ef2Snarayan } else { 4485d10e4ef2Snarayan /* 4486d10e4ef2Snarayan * Release Tx lock, and then reacquire channel 4487d10e4ef2Snarayan * and Tx lock in correct order 4488d10e4ef2Snarayan */ 4489d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 4490d10e4ef2Snarayan mutex_enter(&ldcp->lock); 4491d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 44923af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 4493d10e4ef2Snarayan mutex_exit(&ldcp->lock); 4494d10e4ef2Snarayan } 44951ae08745Sheppo return (ECONNRESET); 44961ae08745Sheppo } 44971ae08745Sheppo 44981ae08745Sheppo tx_tail = ldcp->tx_tail; 44991ae08745Sheppo new_tail = (tx_tail + LDC_PACKET_SIZE) % 45001ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 45011ae08745Sheppo 45021ae08745Sheppo /* 450322f747efSnarayan * Check to see if the queue is full. The check is done using 450422f747efSnarayan * the appropriate head based on the link mode. 45051ae08745Sheppo */ 450622f747efSnarayan i_ldc_get_tx_head(ldcp, &tx_head); 450722f747efSnarayan 45081ae08745Sheppo if (new_tail == tx_head) { 45091ae08745Sheppo DWARN(DBG_ALL_LDCS, 45101ae08745Sheppo "ldc_write: (0x%llx) TX queue is full\n", ldcp->id); 45111ae08745Sheppo *size = 0; 45121ae08745Sheppo return (EWOULDBLOCK); 45131ae08745Sheppo } 45141ae08745Sheppo 45151ae08745Sheppo /* 45161ae08745Sheppo * Make sure that the LDC Tx queue has enough space 45171ae08745Sheppo */ 45181ae08745Sheppo numavail = (tx_head >> LDC_PACKET_SHIFT) - (tx_tail >> LDC_PACKET_SHIFT) 45191ae08745Sheppo + ldcp->tx_q_entries - 1; 45201ae08745Sheppo numavail %= ldcp->tx_q_entries; 45211ae08745Sheppo 45221ae08745Sheppo if (*size > (numavail * ldcp->pkt_payload)) { 45231ae08745Sheppo DWARN(DBG_ALL_LDCS, 45241ae08745Sheppo "ldc_write: (0x%llx) TX queue has no space\n", ldcp->id); 45251ae08745Sheppo return (EWOULDBLOCK); 45261ae08745Sheppo } 45271ae08745Sheppo 45281ae08745Sheppo D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d", 45291ae08745Sheppo ldcp->id, *size); 45301ae08745Sheppo 45311ae08745Sheppo /* Send the data now */ 45321ae08745Sheppo bytes_written = 0; 45331ae08745Sheppo curr_seqid = ldcp->last_msg_snt; 45341ae08745Sheppo start = tx_tail; 45351ae08745Sheppo 45361ae08745Sheppo while (*size > bytes_written) { 45371ae08745Sheppo 45381ae08745Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 45391ae08745Sheppo 454020ae46ebSha137994 msgbuf = (uint8_t *)((ldcp->mode == LDC_MODE_RELIABLE) ? 454122f747efSnarayan ldcmsg->rdata : ldcmsg->udata); 45421ae08745Sheppo 45431ae08745Sheppo ldcmsg->type = LDC_DATA; 45441ae08745Sheppo ldcmsg->stype = LDC_INFO; 45451ae08745Sheppo ldcmsg->ctrl = 0; 45461ae08745Sheppo 45471ae08745Sheppo remaining = *size - bytes_written; 45481ae08745Sheppo len = min(ldcp->pkt_payload, remaining); 45491ae08745Sheppo ldcmsg->env = (uint8_t)len; 45501ae08745Sheppo 45511ae08745Sheppo curr_seqid++; 45521ae08745Sheppo ldcmsg->seqid = curr_seqid; 45531ae08745Sheppo 45541ae08745Sheppo /* copy the data into pkt */ 45551ae08745Sheppo bcopy(source, msgbuf, len); 45561ae08745Sheppo 45571ae08745Sheppo source += len; 45581ae08745Sheppo bytes_written += len; 45591ae08745Sheppo 45601ae08745Sheppo /* increment tail */ 45611ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) & txq_size_mask; 45621ae08745Sheppo 45631ae08745Sheppo ASSERT(tx_tail != tx_head); 45641ae08745Sheppo } 45651ae08745Sheppo 45661ae08745Sheppo /* Set the start and stop bits */ 45671ae08745Sheppo ldcmsg->env |= LDC_FRAG_STOP; 45681ae08745Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + start); 45691ae08745Sheppo ldcmsg->env |= LDC_FRAG_START; 45701ae08745Sheppo 45711ae08745Sheppo /* 45721ae08745Sheppo * All packets have been copied into the TX queue 45731ae08745Sheppo * update the tail ptr in the HV 45741ae08745Sheppo */ 45751ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 45761ae08745Sheppo if (rv == 0) { 45771ae08745Sheppo ldcp->tx_tail = tx_tail; 45781ae08745Sheppo ldcp->last_msg_snt = curr_seqid; 45791ae08745Sheppo *size = bytes_written; 45801ae08745Sheppo } else { 45811ae08745Sheppo int rv2; 45821ae08745Sheppo 45831ae08745Sheppo if (rv != EWOULDBLOCK) { 45841ae08745Sheppo *size = 0; 4585d10e4ef2Snarayan if (mutex_tryenter(&ldcp->lock)) { 45863af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 4587d10e4ef2Snarayan mutex_exit(&ldcp->lock); 4588d10e4ef2Snarayan } else { 4589d10e4ef2Snarayan /* 4590d10e4ef2Snarayan * Release Tx lock, and then reacquire channel 4591d10e4ef2Snarayan * and Tx lock in correct order 4592d10e4ef2Snarayan */ 4593d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 4594d10e4ef2Snarayan mutex_enter(&ldcp->lock); 4595d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 45963af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 4597d10e4ef2Snarayan mutex_exit(&ldcp->lock); 4598d10e4ef2Snarayan } 45991ae08745Sheppo return (ECONNRESET); 46001ae08745Sheppo } 46011ae08745Sheppo 4602cb112a14Slm66018 D1(ldcp->id, "hv_tx_set_tail returns 0x%x (head 0x%x, " 46031ae08745Sheppo "old tail 0x%x, new tail 0x%x, qsize=0x%x)\n", 46041ae08745Sheppo rv, ldcp->tx_head, ldcp->tx_tail, tx_tail, 46051ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT)); 46061ae08745Sheppo 46071ae08745Sheppo rv2 = hv_ldc_tx_get_state(ldcp->id, 46081ae08745Sheppo &tx_head, &tx_tail, &ldcp->link_state); 46091ae08745Sheppo 4610cb112a14Slm66018 D1(ldcp->id, "hv_ldc_tx_get_state returns 0x%x " 46111ae08745Sheppo "(head 0x%x, tail 0x%x state 0x%x)\n", 46121ae08745Sheppo rv2, tx_head, tx_tail, ldcp->link_state); 46131ae08745Sheppo 46141ae08745Sheppo *size = 0; 46151ae08745Sheppo } 46161ae08745Sheppo 46171ae08745Sheppo D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, *size); 46181ae08745Sheppo 46191ae08745Sheppo return (rv); 46201ae08745Sheppo } 46211ae08745Sheppo 46221ae08745Sheppo /* 46231ae08745Sheppo * Write specified amount of bytes to the channel 46241ae08745Sheppo * in multiple pkts of pkt_payload size. Each 46251ae08745Sheppo * packet is tagged with an unique packet ID in 4626e1ebb9ecSlm66018 * the case of a reliable link. 46271ae08745Sheppo * 46281ae08745Sheppo * On return, size contains the number of bytes written. 46291ae08745Sheppo * This function needs to ensure that the write size is < MTU size 46301ae08745Sheppo */ 46311ae08745Sheppo static int 46321ae08745Sheppo i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep) 46331ae08745Sheppo { 4634d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 463520ae46ebSha137994 ASSERT(ldcp->mode == LDC_MODE_RELIABLE); 46361ae08745Sheppo 46371ae08745Sheppo /* Truncate packet to max of MTU size */ 46381ae08745Sheppo if (*sizep > ldcp->mtu) *sizep = ldcp->mtu; 46391ae08745Sheppo return (i_ldc_write_packet(ldcp, buf, sizep)); 46401ae08745Sheppo } 46411ae08745Sheppo 46421ae08745Sheppo 46431ae08745Sheppo /* 46441ae08745Sheppo * Interfaces for channel nexus to register/unregister with LDC module 46451ae08745Sheppo * The nexus will register functions to be used to register individual 46461ae08745Sheppo * channels with the nexus and enable interrupts for the channels 46471ae08745Sheppo */ 46481ae08745Sheppo int 46491ae08745Sheppo ldc_register(ldc_cnex_t *cinfo) 46501ae08745Sheppo { 46511ae08745Sheppo ldc_chan_t *ldcp; 46521ae08745Sheppo 46531ae08745Sheppo if (cinfo == NULL || cinfo->dip == NULL || 46541ae08745Sheppo cinfo->reg_chan == NULL || cinfo->unreg_chan == NULL || 46551ae08745Sheppo cinfo->add_intr == NULL || cinfo->rem_intr == NULL || 46561ae08745Sheppo cinfo->clr_intr == NULL) { 46571ae08745Sheppo 46581ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_register: invalid nexus info\n"); 46591ae08745Sheppo return (EINVAL); 46601ae08745Sheppo } 46611ae08745Sheppo 46621ae08745Sheppo mutex_enter(&ldcssp->lock); 46631ae08745Sheppo 46641ae08745Sheppo /* nexus registration */ 46651ae08745Sheppo ldcssp->cinfo.dip = cinfo->dip; 46661ae08745Sheppo ldcssp->cinfo.reg_chan = cinfo->reg_chan; 46671ae08745Sheppo ldcssp->cinfo.unreg_chan = cinfo->unreg_chan; 46681ae08745Sheppo ldcssp->cinfo.add_intr = cinfo->add_intr; 46691ae08745Sheppo ldcssp->cinfo.rem_intr = cinfo->rem_intr; 46701ae08745Sheppo ldcssp->cinfo.clr_intr = cinfo->clr_intr; 46711ae08745Sheppo 46721ae08745Sheppo /* register any channels that might have been previously initialized */ 46731ae08745Sheppo ldcp = ldcssp->chan_list; 46741ae08745Sheppo while (ldcp) { 46751ae08745Sheppo if ((ldcp->tstate & TS_QCONF_RDY) && 46761ae08745Sheppo (ldcp->tstate & TS_CNEX_RDY) == 0) 46771ae08745Sheppo (void) i_ldc_register_channel(ldcp); 46781ae08745Sheppo 46791ae08745Sheppo ldcp = ldcp->next; 46801ae08745Sheppo } 46811ae08745Sheppo 46821ae08745Sheppo mutex_exit(&ldcssp->lock); 46831ae08745Sheppo 46841ae08745Sheppo return (0); 46851ae08745Sheppo } 46861ae08745Sheppo 46871ae08745Sheppo int 46881ae08745Sheppo ldc_unregister(ldc_cnex_t *cinfo) 46891ae08745Sheppo { 46901ae08745Sheppo if (cinfo == NULL || cinfo->dip == NULL) { 46911ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid nexus info\n"); 46921ae08745Sheppo return (EINVAL); 46931ae08745Sheppo } 46941ae08745Sheppo 46951ae08745Sheppo mutex_enter(&ldcssp->lock); 46961ae08745Sheppo 46971ae08745Sheppo if (cinfo->dip != ldcssp->cinfo.dip) { 46981ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid dip\n"); 46991ae08745Sheppo mutex_exit(&ldcssp->lock); 47001ae08745Sheppo return (EINVAL); 47011ae08745Sheppo } 47021ae08745Sheppo 47031ae08745Sheppo /* nexus unregister */ 47041ae08745Sheppo ldcssp->cinfo.dip = NULL; 47051ae08745Sheppo ldcssp->cinfo.reg_chan = NULL; 47061ae08745Sheppo ldcssp->cinfo.unreg_chan = NULL; 47071ae08745Sheppo ldcssp->cinfo.add_intr = NULL; 47081ae08745Sheppo ldcssp->cinfo.rem_intr = NULL; 47091ae08745Sheppo ldcssp->cinfo.clr_intr = NULL; 47101ae08745Sheppo 47111ae08745Sheppo mutex_exit(&ldcssp->lock); 47121ae08745Sheppo 47131ae08745Sheppo return (0); 47141ae08745Sheppo } 4715