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*58283286Sha137994 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 241ae08745Sheppo * Use is subject to license terms. 251ae08745Sheppo */ 261ae08745Sheppo 271ae08745Sheppo #pragma ident "%Z%%M% %I% %E% SMI" 281ae08745Sheppo 291ae08745Sheppo /* 30e1ebb9ecSlm66018 * sun4v LDC Link Layer 311ae08745Sheppo */ 321ae08745Sheppo #include <sys/types.h> 331ae08745Sheppo #include <sys/file.h> 341ae08745Sheppo #include <sys/errno.h> 351ae08745Sheppo #include <sys/open.h> 361ae08745Sheppo #include <sys/cred.h> 371ae08745Sheppo #include <sys/kmem.h> 381ae08745Sheppo #include <sys/conf.h> 391ae08745Sheppo #include <sys/cmn_err.h> 401ae08745Sheppo #include <sys/ksynch.h> 411ae08745Sheppo #include <sys/modctl.h> 421ae08745Sheppo #include <sys/stat.h> /* needed for S_IFBLK and S_IFCHR */ 431ae08745Sheppo #include <sys/debug.h> 441ae08745Sheppo #include <sys/types.h> 451ae08745Sheppo #include <sys/cred.h> 461ae08745Sheppo #include <sys/promif.h> 471ae08745Sheppo #include <sys/ddi.h> 481ae08745Sheppo #include <sys/sunddi.h> 491ae08745Sheppo #include <sys/cyclic.h> 501ae08745Sheppo #include <sys/machsystm.h> 511ae08745Sheppo #include <sys/vm.h> 521ae08745Sheppo #include <sys/cpu.h> 531ae08745Sheppo #include <sys/intreg.h> 541ae08745Sheppo #include <sys/machcpuvar.h> 554bac2208Snarayan #include <sys/mmu.h> 564bac2208Snarayan #include <sys/pte.h> 574bac2208Snarayan #include <vm/hat.h> 584bac2208Snarayan #include <vm/as.h> 594bac2208Snarayan #include <vm/hat_sfmmu.h> 604bac2208Snarayan #include <sys/vm_machparam.h> 614bac2208Snarayan #include <vm/seg_kmem.h> 624bac2208Snarayan #include <vm/seg_kpm.h> 631ae08745Sheppo #include <sys/note.h> 641ae08745Sheppo #include <sys/ivintr.h> 651ae08745Sheppo #include <sys/hypervisor_api.h> 661ae08745Sheppo #include <sys/ldc.h> 671ae08745Sheppo #include <sys/ldc_impl.h> 681ae08745Sheppo #include <sys/cnex.h> 691ae08745Sheppo #include <sys/hsvc.h> 70*58283286Sha137994 #include <sys/sdt.h> 711ae08745Sheppo 721ae08745Sheppo /* Core internal functions */ 731ae08745Sheppo static int i_ldc_h2v_error(int h_error); 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); 76a8ea4edeSnarayan static int i_ldc_rxq_drain(ldc_chan_t *ldcp); 771ae08745Sheppo static void i_ldc_reset_state(ldc_chan_t *ldcp); 783af08d82Slm66018 static void i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset); 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 87*58283286Sha137994 static int i_ldc_set_rxdq_head(ldc_chan_t *ldcp, uint64_t head); 88*58283286Sha137994 static void i_ldc_rxdq_copy(ldc_chan_t *ldcp, uint64_t *head); 89*58283286Sha137994 static uint64_t i_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, 90*58283286Sha137994 uint64_t *tail, uint64_t *link_state); 91*58283286Sha137994 static uint64_t i_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, 92*58283286Sha137994 uint64_t *tail, uint64_t *link_state); 93*58283286Sha137994 static int i_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head, 94*58283286Sha137994 uint64_t rx_tail); 95*58283286Sha137994 static uint_t i_ldc_chkq(ldc_chan_t *ldcp); 96*58283286Sha137994 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); 100*58283286Sha137994 static uint_t i_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client, 101*58283286Sha137994 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 /* Memory synchronization internal functions */ 1291ae08745Sheppo static int i_ldc_mem_acquire_release(ldc_mem_handle_t mhandle, 1301ae08745Sheppo uint8_t direction, uint64_t offset, size_t size); 1311ae08745Sheppo static int i_ldc_dring_acquire_release(ldc_dring_handle_t dhandle, 1321ae08745Sheppo uint8_t direction, uint64_t start, uint64_t end); 1331ae08745Sheppo 1341ae08745Sheppo /* LDC Version */ 1351ae08745Sheppo static ldc_ver_t ldc_versions[] = { {1, 0} }; 1361ae08745Sheppo 1371ae08745Sheppo /* number of supported versions */ 1381ae08745Sheppo #define LDC_NUM_VERS (sizeof (ldc_versions) / sizeof (ldc_versions[0])) 1391ae08745Sheppo 140*58283286Sha137994 /* Invalid value for the ldc_chan_t rx_ack_head field */ 141*58283286Sha137994 #define ACKPEEK_HEAD_INVALID ((uint64_t)-1) 142*58283286Sha137994 143*58283286Sha137994 1441ae08745Sheppo /* Module State Pointer */ 1451ae08745Sheppo static ldc_soft_state_t *ldcssp; 1461ae08745Sheppo 1471ae08745Sheppo static struct modldrv md = { 1481ae08745Sheppo &mod_miscops, /* This is a misc module */ 1491ae08745Sheppo "sun4v LDC module v%I%", /* Name of the module */ 1501ae08745Sheppo }; 1511ae08745Sheppo 1521ae08745Sheppo static struct modlinkage ml = { 1531ae08745Sheppo MODREV_1, 1541ae08745Sheppo &md, 1551ae08745Sheppo NULL 1561ae08745Sheppo }; 1571ae08745Sheppo 1581ae08745Sheppo static uint64_t ldc_sup_minor; /* Supported minor number */ 1591ae08745Sheppo static hsvc_info_t ldc_hsvc = { 1601ae08745Sheppo HSVC_REV_1, NULL, HSVC_GROUP_LDC, 1, 0, "ldc" 1611ae08745Sheppo }; 1621ae08745Sheppo 1634bac2208Snarayan /* 1644bac2208Snarayan * LDC framework supports mapping remote domain's memory 1654bac2208Snarayan * either directly or via shadow memory pages. Default 1664bac2208Snarayan * support is currently implemented via shadow copy. 1674bac2208Snarayan * Direct map can be enabled by setting 'ldc_shmem_enabled' 1684bac2208Snarayan */ 1694bac2208Snarayan int ldc_shmem_enabled = 0; 170e1ebb9ecSlm66018 1710a55fbb7Slm66018 /* 172e1ebb9ecSlm66018 * The no. of MTU size messages that can be stored in 173e1ebb9ecSlm66018 * the LDC Tx queue. The number of Tx queue entries is 174e1ebb9ecSlm66018 * then computed as (mtu * mtu_msgs)/sizeof(queue_entry) 175e1ebb9ecSlm66018 */ 176e1ebb9ecSlm66018 uint64_t ldc_mtu_msgs = LDC_MTU_MSGS; 177e1ebb9ecSlm66018 178e1ebb9ecSlm66018 /* 179e1ebb9ecSlm66018 * The minimum queue length. This is the size of the smallest 180e1ebb9ecSlm66018 * LDC queue. If the computed value is less than this default, 181e1ebb9ecSlm66018 * the queue length is rounded up to 'ldc_queue_entries'. 182e1ebb9ecSlm66018 */ 183e1ebb9ecSlm66018 uint64_t ldc_queue_entries = LDC_QUEUE_ENTRIES; 184e1ebb9ecSlm66018 185e1ebb9ecSlm66018 /* 186*58283286Sha137994 * The length of the reliable-mode data queue in terms of the LDC 187*58283286Sha137994 * receive queue length. i.e., the number of times larger than the 188*58283286Sha137994 * LDC receive queue that the data queue should be. The HV receive 189*58283286Sha137994 * queue is required to be a power of 2 and this implementation 190*58283286Sha137994 * assumes the data queue will also be a power of 2. By making the 191*58283286Sha137994 * multiplier a power of 2, we ensure the data queue will be a 192*58283286Sha137994 * power of 2. We use a multiplier because the receive queue is 193*58283286Sha137994 * sized to be sane relative to the MTU and the same is needed for 194*58283286Sha137994 * the data queue. 195*58283286Sha137994 */ 196*58283286Sha137994 uint64_t ldc_rxdq_multiplier = LDC_RXDQ_MULTIPLIER; 197*58283286Sha137994 198*58283286Sha137994 /* 199e1ebb9ecSlm66018 * Pages exported for remote access over each channel is 200e1ebb9ecSlm66018 * maintained in a table registered with the Hypervisor. 201e1ebb9ecSlm66018 * The default number of entries in the table is set to 202e1ebb9ecSlm66018 * 'ldc_mtbl_entries'. 203e1ebb9ecSlm66018 */ 204e1ebb9ecSlm66018 uint64_t ldc_maptable_entries = LDC_MTBL_ENTRIES; 205e1ebb9ecSlm66018 206e1ebb9ecSlm66018 /* 207e1ebb9ecSlm66018 * LDC retry count and delay - when the HV returns EWOULDBLOCK 208e1ebb9ecSlm66018 * the operation is retried 'ldc_max_retries' times with a 209e1ebb9ecSlm66018 * wait of 'ldc_delay' usecs between each retry. 2100a55fbb7Slm66018 */ 2110a55fbb7Slm66018 int ldc_max_retries = LDC_MAX_RETRIES; 2120a55fbb7Slm66018 clock_t ldc_delay = LDC_DELAY; 2130a55fbb7Slm66018 2144d39be2bSsg70180 /* 2154d39be2bSsg70180 * delay between each retry of channel unregistration in 2164d39be2bSsg70180 * ldc_close(), to wait for pending interrupts to complete. 2174d39be2bSsg70180 */ 2184d39be2bSsg70180 clock_t ldc_close_delay = LDC_CLOSE_DELAY; 2194d39be2bSsg70180 2201ae08745Sheppo #ifdef DEBUG 2211ae08745Sheppo 2221ae08745Sheppo /* 2231ae08745Sheppo * Print debug messages 2241ae08745Sheppo * 2251ae08745Sheppo * set ldcdbg to 0x7 for enabling all msgs 2261ae08745Sheppo * 0x4 - Warnings 2271ae08745Sheppo * 0x2 - All debug messages 2281ae08745Sheppo * 0x1 - Minimal debug messages 2291ae08745Sheppo * 2301ae08745Sheppo * set ldcdbgchan to the channel number you want to debug 2311ae08745Sheppo * setting it to -1 prints debug messages for all channels 2321ae08745Sheppo * NOTE: ldcdbgchan has no effect on error messages 2331ae08745Sheppo */ 2341ae08745Sheppo 2351ae08745Sheppo #define DBG_ALL_LDCS -1 2361ae08745Sheppo 2371ae08745Sheppo int ldcdbg = 0x0; 2381ae08745Sheppo int64_t ldcdbgchan = DBG_ALL_LDCS; 23983d3bc6fSnarayan uint64_t ldc_inject_err_flag = 0; 2401ae08745Sheppo 2411ae08745Sheppo static void 2421ae08745Sheppo ldcdebug(int64_t id, const char *fmt, ...) 2431ae08745Sheppo { 2441ae08745Sheppo char buf[512]; 2451ae08745Sheppo va_list ap; 2461ae08745Sheppo 2471ae08745Sheppo /* 2481ae08745Sheppo * Do not return if, 2491ae08745Sheppo * caller wants to print it anyway - (id == DBG_ALL_LDCS) 2501ae08745Sheppo * debug channel is set to all LDCs - (ldcdbgchan == DBG_ALL_LDCS) 2511ae08745Sheppo * debug channel = caller specified channel 2521ae08745Sheppo */ 2531ae08745Sheppo if ((id != DBG_ALL_LDCS) && 2541ae08745Sheppo (ldcdbgchan != DBG_ALL_LDCS) && 2551ae08745Sheppo (ldcdbgchan != id)) { 2561ae08745Sheppo return; 2571ae08745Sheppo } 2581ae08745Sheppo 2591ae08745Sheppo va_start(ap, fmt); 2601ae08745Sheppo (void) vsprintf(buf, fmt, ap); 2611ae08745Sheppo va_end(ap); 2621ae08745Sheppo 2633af08d82Slm66018 cmn_err(CE_CONT, "?%s", buf); 2643af08d82Slm66018 } 2653af08d82Slm66018 26683d3bc6fSnarayan #define LDC_ERR_RESET 0x1 26783d3bc6fSnarayan #define LDC_ERR_PKTLOSS 0x2 268*58283286Sha137994 #define LDC_ERR_DQFULL 0x4 26983d3bc6fSnarayan 2703af08d82Slm66018 static boolean_t 27183d3bc6fSnarayan ldc_inject_error(ldc_chan_t *ldcp, uint64_t error) 2723af08d82Slm66018 { 2733af08d82Slm66018 if ((ldcdbgchan != DBG_ALL_LDCS) && (ldcdbgchan != ldcp->id)) 2743af08d82Slm66018 return (B_FALSE); 2753af08d82Slm66018 27683d3bc6fSnarayan if ((ldc_inject_err_flag & error) == 0) 2773af08d82Slm66018 return (B_FALSE); 2783af08d82Slm66018 2793af08d82Slm66018 /* clear the injection state */ 28083d3bc6fSnarayan ldc_inject_err_flag &= ~error; 2813af08d82Slm66018 2823af08d82Slm66018 return (B_TRUE); 2831ae08745Sheppo } 2841ae08745Sheppo 2851ae08745Sheppo #define D1 \ 2861ae08745Sheppo if (ldcdbg & 0x01) \ 2871ae08745Sheppo ldcdebug 2881ae08745Sheppo 2891ae08745Sheppo #define D2 \ 2901ae08745Sheppo if (ldcdbg & 0x02) \ 2911ae08745Sheppo ldcdebug 2921ae08745Sheppo 2931ae08745Sheppo #define DWARN \ 2941ae08745Sheppo if (ldcdbg & 0x04) \ 2951ae08745Sheppo ldcdebug 2961ae08745Sheppo 2971ae08745Sheppo #define DUMP_PAYLOAD(id, addr) \ 2981ae08745Sheppo { \ 2991ae08745Sheppo char buf[65*3]; \ 3001ae08745Sheppo int i; \ 3011ae08745Sheppo uint8_t *src = (uint8_t *)addr; \ 3021ae08745Sheppo for (i = 0; i < 64; i++, src++) \ 3031ae08745Sheppo (void) sprintf(&buf[i * 3], "|%02x", *src); \ 3041ae08745Sheppo (void) sprintf(&buf[i * 3], "|\n"); \ 3051ae08745Sheppo D2((id), "payload: %s", buf); \ 3061ae08745Sheppo } 3071ae08745Sheppo 3081ae08745Sheppo #define DUMP_LDC_PKT(c, s, addr) \ 3091ae08745Sheppo { \ 3101ae08745Sheppo ldc_msg_t *msg = (ldc_msg_t *)(addr); \ 3111ae08745Sheppo uint32_t mid = ((c)->mode != LDC_MODE_RAW) ? msg->seqid : 0; \ 3121ae08745Sheppo if (msg->type == LDC_DATA) { \ 3131ae08745Sheppo D2((c)->id, "%s: msg%d (/%x/%x/%x/,env[%c%c,sz=%d])", \ 3141ae08745Sheppo (s), mid, msg->type, msg->stype, msg->ctrl, \ 3151ae08745Sheppo (msg->env & LDC_FRAG_START) ? 'B' : ' ', \ 3161ae08745Sheppo (msg->env & LDC_FRAG_STOP) ? 'E' : ' ', \ 3171ae08745Sheppo (msg->env & LDC_LEN_MASK)); \ 3181ae08745Sheppo } else { \ 3191ae08745Sheppo D2((c)->id, "%s: msg%d (/%x/%x/%x/,env=%x)", (s), \ 3201ae08745Sheppo mid, msg->type, msg->stype, msg->ctrl, msg->env); \ 3211ae08745Sheppo } \ 3221ae08745Sheppo } 3231ae08745Sheppo 32483d3bc6fSnarayan #define LDC_INJECT_RESET(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_RESET) 32583d3bc6fSnarayan #define LDC_INJECT_PKTLOSS(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_PKTLOSS) 326*58283286Sha137994 #define LDC_INJECT_DQFULL(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_DQFULL) 3273af08d82Slm66018 3281ae08745Sheppo #else 3291ae08745Sheppo 3301ae08745Sheppo #define DBG_ALL_LDCS -1 3311ae08745Sheppo 3321ae08745Sheppo #define D1 3331ae08745Sheppo #define D2 3341ae08745Sheppo #define DWARN 3351ae08745Sheppo 3361ae08745Sheppo #define DUMP_PAYLOAD(id, addr) 3371ae08745Sheppo #define DUMP_LDC_PKT(c, s, addr) 3381ae08745Sheppo 3393af08d82Slm66018 #define LDC_INJECT_RESET(_ldcp) (B_FALSE) 34083d3bc6fSnarayan #define LDC_INJECT_PKTLOSS(_ldcp) (B_FALSE) 341*58283286Sha137994 #define LDC_INJECT_DQFULL(_ldcp) (B_FALSE) 3423af08d82Slm66018 3431ae08745Sheppo #endif 3441ae08745Sheppo 345*58283286Sha137994 /* 346*58283286Sha137994 * dtrace SDT probes to ease tracing of the rx data queue and HV queue 347*58283286Sha137994 * lengths. Just pass the head, tail, and entries values so that the 348*58283286Sha137994 * length can be calculated in a dtrace script when the probe is enabled. 349*58283286Sha137994 */ 350*58283286Sha137994 #define TRACE_RXDQ_LENGTH(ldcp) \ 351*58283286Sha137994 DTRACE_PROBE4(rxdq__size, \ 352*58283286Sha137994 uint64_t, ldcp->id, \ 353*58283286Sha137994 uint64_t, ldcp->rx_dq_head, \ 354*58283286Sha137994 uint64_t, ldcp->rx_dq_tail, \ 355*58283286Sha137994 uint64_t, ldcp->rx_dq_entries) 356*58283286Sha137994 357*58283286Sha137994 #define TRACE_RXHVQ_LENGTH(ldcp, head, tail) \ 358*58283286Sha137994 DTRACE_PROBE4(rxhvq__size, \ 359*58283286Sha137994 uint64_t, ldcp->id, \ 360*58283286Sha137994 uint64_t, head, \ 361*58283286Sha137994 uint64_t, tail, \ 362*58283286Sha137994 uint64_t, ldcp->rx_q_entries) 363*58283286Sha137994 364*58283286Sha137994 /* A dtrace SDT probe to ease tracing of data queue copy operations */ 365*58283286Sha137994 #define TRACE_RXDQ_COPY(ldcp, bytes) \ 366*58283286Sha137994 DTRACE_PROBE2(rxdq__copy, uint64_t, ldcp->id, uint64_t, bytes) \ 367*58283286Sha137994 368*58283286Sha137994 /* The amount of contiguous space at the tail of the queue */ 369*58283286Sha137994 #define Q_CONTIG_SPACE(head, tail, size) \ 370*58283286Sha137994 ((head) <= (tail) ? ((size) - (tail)) : \ 371*58283286Sha137994 ((head) - (tail) - LDC_PACKET_SIZE)) 372*58283286Sha137994 3731ae08745Sheppo #define ZERO_PKT(p) \ 3741ae08745Sheppo bzero((p), sizeof (ldc_msg_t)); 3751ae08745Sheppo 3761ae08745Sheppo #define IDX2COOKIE(idx, pg_szc, pg_shift) \ 3771ae08745Sheppo (((pg_szc) << LDC_COOKIE_PGSZC_SHIFT) | ((idx) << (pg_shift))) 3781ae08745Sheppo 3791ae08745Sheppo int 3801ae08745Sheppo _init(void) 3811ae08745Sheppo { 3821ae08745Sheppo int status; 3831ae08745Sheppo 3841ae08745Sheppo status = hsvc_register(&ldc_hsvc, &ldc_sup_minor); 3851ae08745Sheppo if (status != 0) { 386d66f8315Sjb145095 cmn_err(CE_NOTE, "!%s: cannot negotiate hypervisor LDC services" 3871ae08745Sheppo " group: 0x%lx major: %ld minor: %ld errno: %d", 3881ae08745Sheppo ldc_hsvc.hsvc_modname, ldc_hsvc.hsvc_group, 3891ae08745Sheppo ldc_hsvc.hsvc_major, ldc_hsvc.hsvc_minor, status); 3901ae08745Sheppo return (-1); 3911ae08745Sheppo } 3921ae08745Sheppo 3931ae08745Sheppo /* allocate soft state structure */ 3941ae08745Sheppo ldcssp = kmem_zalloc(sizeof (ldc_soft_state_t), KM_SLEEP); 3951ae08745Sheppo 3961ae08745Sheppo /* Link the module into the system */ 3971ae08745Sheppo status = mod_install(&ml); 3981ae08745Sheppo if (status != 0) { 3991ae08745Sheppo kmem_free(ldcssp, sizeof (ldc_soft_state_t)); 4001ae08745Sheppo return (status); 4011ae08745Sheppo } 4021ae08745Sheppo 4031ae08745Sheppo /* Initialize the LDC state structure */ 4041ae08745Sheppo mutex_init(&ldcssp->lock, NULL, MUTEX_DRIVER, NULL); 4051ae08745Sheppo 4061ae08745Sheppo mutex_enter(&ldcssp->lock); 4071ae08745Sheppo 4084bac2208Snarayan /* Create a cache for memory handles */ 4094bac2208Snarayan ldcssp->memhdl_cache = kmem_cache_create("ldc_memhdl_cache", 4104bac2208Snarayan sizeof (ldc_mhdl_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 4114bac2208Snarayan if (ldcssp->memhdl_cache == NULL) { 4124bac2208Snarayan DWARN(DBG_ALL_LDCS, "_init: ldc_memhdl cache create failed\n"); 4134bac2208Snarayan mutex_exit(&ldcssp->lock); 4144bac2208Snarayan return (-1); 4154bac2208Snarayan } 4164bac2208Snarayan 4174bac2208Snarayan /* Create cache for memory segment structures */ 4184bac2208Snarayan ldcssp->memseg_cache = kmem_cache_create("ldc_memseg_cache", 4194bac2208Snarayan sizeof (ldc_memseg_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 4204bac2208Snarayan if (ldcssp->memseg_cache == NULL) { 4214bac2208Snarayan DWARN(DBG_ALL_LDCS, "_init: ldc_memseg cache create failed\n"); 4224bac2208Snarayan mutex_exit(&ldcssp->lock); 4234bac2208Snarayan return (-1); 4244bac2208Snarayan } 4254bac2208Snarayan 4264bac2208Snarayan 4271ae08745Sheppo ldcssp->channel_count = 0; 4281ae08745Sheppo ldcssp->channels_open = 0; 4291ae08745Sheppo ldcssp->chan_list = NULL; 4301ae08745Sheppo ldcssp->dring_list = NULL; 4311ae08745Sheppo 4321ae08745Sheppo mutex_exit(&ldcssp->lock); 4331ae08745Sheppo 4341ae08745Sheppo return (0); 4351ae08745Sheppo } 4361ae08745Sheppo 4371ae08745Sheppo int 4381ae08745Sheppo _info(struct modinfo *modinfop) 4391ae08745Sheppo { 4401ae08745Sheppo /* Report status of the dynamically loadable driver module */ 4411ae08745Sheppo return (mod_info(&ml, modinfop)); 4421ae08745Sheppo } 4431ae08745Sheppo 4441ae08745Sheppo int 4451ae08745Sheppo _fini(void) 4461ae08745Sheppo { 4471ae08745Sheppo int rv, status; 44822f747efSnarayan ldc_chan_t *tmp_ldcp, *ldcp; 44922f747efSnarayan ldc_dring_t *tmp_dringp, *dringp; 4501ae08745Sheppo ldc_mem_info_t minfo; 4511ae08745Sheppo 4521ae08745Sheppo /* Unlink the driver module from the system */ 4531ae08745Sheppo status = mod_remove(&ml); 4541ae08745Sheppo if (status) { 4551ae08745Sheppo DWARN(DBG_ALL_LDCS, "_fini: mod_remove failed\n"); 4561ae08745Sheppo return (EIO); 4571ae08745Sheppo } 4581ae08745Sheppo 4591ae08745Sheppo /* Free descriptor rings */ 4601ae08745Sheppo dringp = ldcssp->dring_list; 4611ae08745Sheppo while (dringp != NULL) { 46222f747efSnarayan tmp_dringp = dringp->next; 4631ae08745Sheppo 4641ae08745Sheppo rv = ldc_mem_dring_info((ldc_dring_handle_t)dringp, &minfo); 4651ae08745Sheppo if (rv == 0 && minfo.status != LDC_UNBOUND) { 4661ae08745Sheppo if (minfo.status == LDC_BOUND) { 4671ae08745Sheppo (void) ldc_mem_dring_unbind( 4681ae08745Sheppo (ldc_dring_handle_t)dringp); 4691ae08745Sheppo } 4701ae08745Sheppo if (minfo.status == LDC_MAPPED) { 4711ae08745Sheppo (void) ldc_mem_dring_unmap( 4721ae08745Sheppo (ldc_dring_handle_t)dringp); 4731ae08745Sheppo } 4741ae08745Sheppo } 4751ae08745Sheppo 4761ae08745Sheppo (void) ldc_mem_dring_destroy((ldc_dring_handle_t)dringp); 47722f747efSnarayan dringp = tmp_dringp; 4781ae08745Sheppo } 4791ae08745Sheppo ldcssp->dring_list = NULL; 4801ae08745Sheppo 48122f747efSnarayan /* close and finalize channels */ 48222f747efSnarayan ldcp = ldcssp->chan_list; 48322f747efSnarayan while (ldcp != NULL) { 48422f747efSnarayan tmp_ldcp = ldcp->next; 48522f747efSnarayan 48622f747efSnarayan (void) ldc_close((ldc_handle_t)ldcp); 48722f747efSnarayan (void) ldc_fini((ldc_handle_t)ldcp); 48822f747efSnarayan 48922f747efSnarayan ldcp = tmp_ldcp; 49022f747efSnarayan } 49122f747efSnarayan ldcssp->chan_list = NULL; 49222f747efSnarayan 4934bac2208Snarayan /* Destroy kmem caches */ 4944bac2208Snarayan kmem_cache_destroy(ldcssp->memhdl_cache); 4954bac2208Snarayan kmem_cache_destroy(ldcssp->memseg_cache); 4964bac2208Snarayan 4971ae08745Sheppo /* 4981ae08745Sheppo * We have successfully "removed" the driver. 4991ae08745Sheppo * Destroying soft states 5001ae08745Sheppo */ 5011ae08745Sheppo mutex_destroy(&ldcssp->lock); 5021ae08745Sheppo kmem_free(ldcssp, sizeof (ldc_soft_state_t)); 5031ae08745Sheppo 5041ae08745Sheppo (void) hsvc_unregister(&ldc_hsvc); 5051ae08745Sheppo 5061ae08745Sheppo return (status); 5071ae08745Sheppo } 5081ae08745Sheppo 5091ae08745Sheppo /* -------------------------------------------------------------------------- */ 5101ae08745Sheppo 5111ae08745Sheppo /* 512e1ebb9ecSlm66018 * LDC Link Layer Internal Functions 5131ae08745Sheppo */ 5141ae08745Sheppo 5151ae08745Sheppo /* 5161ae08745Sheppo * Translate HV Errors to sun4v error codes 5171ae08745Sheppo */ 5181ae08745Sheppo static int 5191ae08745Sheppo i_ldc_h2v_error(int h_error) 5201ae08745Sheppo { 5211ae08745Sheppo switch (h_error) { 5221ae08745Sheppo 5231ae08745Sheppo case H_EOK: 5241ae08745Sheppo return (0); 5251ae08745Sheppo 5261ae08745Sheppo case H_ENORADDR: 5271ae08745Sheppo return (EFAULT); 5281ae08745Sheppo 5291ae08745Sheppo case H_EBADPGSZ: 5301ae08745Sheppo case H_EINVAL: 5311ae08745Sheppo return (EINVAL); 5321ae08745Sheppo 5331ae08745Sheppo case H_EWOULDBLOCK: 5341ae08745Sheppo return (EWOULDBLOCK); 5351ae08745Sheppo 5361ae08745Sheppo case H_ENOACCESS: 5371ae08745Sheppo case H_ENOMAP: 5381ae08745Sheppo return (EACCES); 5391ae08745Sheppo 5401ae08745Sheppo case H_EIO: 5411ae08745Sheppo case H_ECPUERROR: 5421ae08745Sheppo return (EIO); 5431ae08745Sheppo 5441ae08745Sheppo case H_ENOTSUPPORTED: 5451ae08745Sheppo return (ENOTSUP); 5461ae08745Sheppo 5471ae08745Sheppo case H_ETOOMANY: 5481ae08745Sheppo return (ENOSPC); 5491ae08745Sheppo 5501ae08745Sheppo case H_ECHANNEL: 5511ae08745Sheppo return (ECHRNG); 5521ae08745Sheppo default: 5531ae08745Sheppo break; 5541ae08745Sheppo } 5551ae08745Sheppo 5561ae08745Sheppo return (EIO); 5571ae08745Sheppo } 5581ae08745Sheppo 5591ae08745Sheppo /* 5601ae08745Sheppo * Reconfigure the transmit queue 5611ae08745Sheppo */ 5621ae08745Sheppo static int 5631ae08745Sheppo i_ldc_txq_reconf(ldc_chan_t *ldcp) 5641ae08745Sheppo { 5651ae08745Sheppo int rv; 5661ae08745Sheppo 5671ae08745Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 568d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 569d10e4ef2Snarayan 5701ae08745Sheppo rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries); 5711ae08745Sheppo if (rv) { 5721ae08745Sheppo cmn_err(CE_WARN, 5733af08d82Slm66018 "i_ldc_txq_reconf: (0x%lx) cannot set qconf", ldcp->id); 5741ae08745Sheppo return (EIO); 5751ae08745Sheppo } 5761ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id, &(ldcp->tx_head), 5771ae08745Sheppo &(ldcp->tx_tail), &(ldcp->link_state)); 5781ae08745Sheppo if (rv) { 5791ae08745Sheppo cmn_err(CE_WARN, 5803af08d82Slm66018 "i_ldc_txq_reconf: (0x%lx) cannot get qptrs", ldcp->id); 5811ae08745Sheppo return (EIO); 5821ae08745Sheppo } 5833af08d82Slm66018 D1(ldcp->id, "i_ldc_txq_reconf: (0x%llx) h=0x%llx,t=0x%llx," 5841ae08745Sheppo "s=0x%llx\n", ldcp->id, ldcp->tx_head, ldcp->tx_tail, 5851ae08745Sheppo ldcp->link_state); 5861ae08745Sheppo 5871ae08745Sheppo return (0); 5881ae08745Sheppo } 5891ae08745Sheppo 5901ae08745Sheppo /* 5911ae08745Sheppo * Reconfigure the receive queue 5921ae08745Sheppo */ 5931ae08745Sheppo static int 5943af08d82Slm66018 i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset) 5951ae08745Sheppo { 5961ae08745Sheppo int rv; 5971ae08745Sheppo uint64_t rx_head, rx_tail; 5981ae08745Sheppo 5991ae08745Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 6001ae08745Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 6011ae08745Sheppo &(ldcp->link_state)); 6021ae08745Sheppo if (rv) { 6031ae08745Sheppo cmn_err(CE_WARN, 6043af08d82Slm66018 "i_ldc_rxq_reconf: (0x%lx) cannot get state", 6051ae08745Sheppo ldcp->id); 6061ae08745Sheppo return (EIO); 6071ae08745Sheppo } 6081ae08745Sheppo 6093af08d82Slm66018 if (force_reset || (ldcp->tstate & ~TS_IN_RESET) == TS_UP) { 6101ae08745Sheppo rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra, 6111ae08745Sheppo ldcp->rx_q_entries); 6121ae08745Sheppo if (rv) { 6131ae08745Sheppo cmn_err(CE_WARN, 6143af08d82Slm66018 "i_ldc_rxq_reconf: (0x%lx) cannot set qconf", 6151ae08745Sheppo ldcp->id); 6161ae08745Sheppo return (EIO); 6171ae08745Sheppo } 6183af08d82Slm66018 D1(ldcp->id, "i_ldc_rxq_reconf: (0x%llx) completed q reconf", 6191ae08745Sheppo ldcp->id); 6201ae08745Sheppo } 6211ae08745Sheppo 6221ae08745Sheppo return (0); 6231ae08745Sheppo } 6241ae08745Sheppo 625a8ea4edeSnarayan 626a8ea4edeSnarayan /* 627a8ea4edeSnarayan * Drain the contents of the receive queue 628a8ea4edeSnarayan */ 629a8ea4edeSnarayan static int 630a8ea4edeSnarayan i_ldc_rxq_drain(ldc_chan_t *ldcp) 631a8ea4edeSnarayan { 632a8ea4edeSnarayan int rv; 633a8ea4edeSnarayan uint64_t rx_head, rx_tail; 634a8ea4edeSnarayan 635a8ea4edeSnarayan ASSERT(MUTEX_HELD(&ldcp->lock)); 636a8ea4edeSnarayan rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 637a8ea4edeSnarayan &(ldcp->link_state)); 638a8ea4edeSnarayan if (rv) { 639a8ea4edeSnarayan cmn_err(CE_WARN, "i_ldc_rxq_drain: (0x%lx) cannot get state", 640a8ea4edeSnarayan ldcp->id); 641a8ea4edeSnarayan return (EIO); 642a8ea4edeSnarayan } 643a8ea4edeSnarayan 644a8ea4edeSnarayan /* flush contents by setting the head = tail */ 645a8ea4edeSnarayan return (i_ldc_set_rx_head(ldcp, rx_tail)); 646a8ea4edeSnarayan } 647a8ea4edeSnarayan 648a8ea4edeSnarayan 6491ae08745Sheppo /* 6501ae08745Sheppo * Reset LDC state structure and its contents 6511ae08745Sheppo */ 6521ae08745Sheppo static void 6531ae08745Sheppo i_ldc_reset_state(ldc_chan_t *ldcp) 6541ae08745Sheppo { 6551ae08745Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 6561ae08745Sheppo ldcp->last_msg_snt = LDC_INIT_SEQID; 6571ae08745Sheppo ldcp->last_ack_rcd = 0; 6581ae08745Sheppo ldcp->last_msg_rcd = 0; 6591ae08745Sheppo ldcp->tx_ackd_head = ldcp->tx_head; 660*58283286Sha137994 ldcp->stream_remains = 0; 6611ae08745Sheppo ldcp->next_vidx = 0; 6621ae08745Sheppo ldcp->hstate = 0; 6631ae08745Sheppo ldcp->tstate = TS_OPEN; 6641ae08745Sheppo ldcp->status = LDC_OPEN; 665*58283286Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID; 666*58283286Sha137994 ldcp->rx_dq_head = 0; 667*58283286Sha137994 ldcp->rx_dq_tail = 0; 6681ae08745Sheppo 6691ae08745Sheppo if (ldcp->link_state == LDC_CHANNEL_UP || 6701ae08745Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 6711ae08745Sheppo 6721ae08745Sheppo if (ldcp->mode == LDC_MODE_RAW) { 6731ae08745Sheppo ldcp->status = LDC_UP; 6741ae08745Sheppo ldcp->tstate = TS_UP; 6751ae08745Sheppo } else { 6761ae08745Sheppo ldcp->status = LDC_READY; 6771ae08745Sheppo ldcp->tstate |= TS_LINK_READY; 6781ae08745Sheppo } 6791ae08745Sheppo } 6801ae08745Sheppo } 6811ae08745Sheppo 6821ae08745Sheppo /* 6831ae08745Sheppo * Reset a LDC channel 6841ae08745Sheppo */ 6851ae08745Sheppo static void 6863af08d82Slm66018 i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset) 6871ae08745Sheppo { 68883d3bc6fSnarayan DWARN(ldcp->id, "i_ldc_reset: (0x%llx) channel reset\n", ldcp->id); 6891ae08745Sheppo 690d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->lock)); 691d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 692d10e4ef2Snarayan 6933af08d82Slm66018 /* reconfig Tx and Rx queues */ 6941ae08745Sheppo (void) i_ldc_txq_reconf(ldcp); 6953af08d82Slm66018 (void) i_ldc_rxq_reconf(ldcp, force_reset); 6963af08d82Slm66018 6973af08d82Slm66018 /* Clear Tx and Rx interrupts */ 6983af08d82Slm66018 (void) i_ldc_clear_intr(ldcp, CNEX_TX_INTR); 6993af08d82Slm66018 (void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 7003af08d82Slm66018 7013af08d82Slm66018 /* Reset channel state */ 7021ae08745Sheppo i_ldc_reset_state(ldcp); 7033af08d82Slm66018 7043af08d82Slm66018 /* Mark channel in reset */ 7053af08d82Slm66018 ldcp->tstate |= TS_IN_RESET; 7061ae08745Sheppo } 7071ae08745Sheppo 7084bac2208Snarayan 7091ae08745Sheppo /* 7101ae08745Sheppo * Clear pending interrupts 7111ae08745Sheppo */ 7121ae08745Sheppo static void 7131ae08745Sheppo i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype) 7141ae08745Sheppo { 7151ae08745Sheppo ldc_cnex_t *cinfo = &ldcssp->cinfo; 7161ae08745Sheppo 7171ae08745Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 7183af08d82Slm66018 ASSERT(cinfo->dip != NULL); 7194bac2208Snarayan 7203af08d82Slm66018 switch (itype) { 7213af08d82Slm66018 case CNEX_TX_INTR: 7224bac2208Snarayan /* check Tx interrupt */ 7233af08d82Slm66018 if (ldcp->tx_intr_state) 7243af08d82Slm66018 ldcp->tx_intr_state = LDC_INTR_NONE; 7254bac2208Snarayan else 7264bac2208Snarayan return; 7273af08d82Slm66018 break; 7283af08d82Slm66018 7293af08d82Slm66018 case CNEX_RX_INTR: 7304bac2208Snarayan /* check Rx interrupt */ 7313af08d82Slm66018 if (ldcp->rx_intr_state) 7323af08d82Slm66018 ldcp->rx_intr_state = LDC_INTR_NONE; 7334bac2208Snarayan else 7344bac2208Snarayan return; 7353af08d82Slm66018 break; 7364bac2208Snarayan } 7374bac2208Snarayan 7381ae08745Sheppo (void) cinfo->clr_intr(cinfo->dip, ldcp->id, itype); 7394bac2208Snarayan D2(ldcp->id, 7404bac2208Snarayan "i_ldc_clear_intr: (0x%llx) cleared 0x%x intr\n", 7414bac2208Snarayan ldcp->id, itype); 7421ae08745Sheppo } 7431ae08745Sheppo 7441ae08745Sheppo /* 7451ae08745Sheppo * Set the receive queue head 7460a55fbb7Slm66018 * Resets connection and returns an error if it fails. 7471ae08745Sheppo */ 7481ae08745Sheppo static int 7491ae08745Sheppo i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head) 7501ae08745Sheppo { 7511ae08745Sheppo int rv; 7520a55fbb7Slm66018 int retries; 7531ae08745Sheppo 7541ae08745Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 7550a55fbb7Slm66018 for (retries = 0; retries < ldc_max_retries; retries++) { 7560a55fbb7Slm66018 7570a55fbb7Slm66018 if ((rv = hv_ldc_rx_set_qhead(ldcp->id, head)) == 0) 7580a55fbb7Slm66018 return (0); 7590a55fbb7Slm66018 7600a55fbb7Slm66018 if (rv != H_EWOULDBLOCK) 7610a55fbb7Slm66018 break; 7620a55fbb7Slm66018 7630a55fbb7Slm66018 /* wait for ldc_delay usecs */ 7640a55fbb7Slm66018 drv_usecwait(ldc_delay); 7651ae08745Sheppo } 7661ae08745Sheppo 7670a55fbb7Slm66018 cmn_err(CE_WARN, "ldc_rx_set_qhead: (0x%lx) cannot set qhead 0x%lx", 7680a55fbb7Slm66018 ldcp->id, head); 769d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 7703af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 771d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 7720a55fbb7Slm66018 7730a55fbb7Slm66018 return (ECONNRESET); 7741ae08745Sheppo } 7751ae08745Sheppo 77622f747efSnarayan /* 77722f747efSnarayan * Returns the tx_head to be used for transfer 77822f747efSnarayan */ 77922f747efSnarayan static void 78022f747efSnarayan i_ldc_get_tx_head(ldc_chan_t *ldcp, uint64_t *head) 78122f747efSnarayan { 78222f747efSnarayan ldc_msg_t *pkt; 78322f747efSnarayan 78422f747efSnarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 78522f747efSnarayan 78622f747efSnarayan /* get current Tx head */ 78722f747efSnarayan *head = ldcp->tx_head; 78822f747efSnarayan 78922f747efSnarayan /* 79022f747efSnarayan * Reliable mode will use the ACKd head instead of the regular tx_head. 79122f747efSnarayan * Also in Reliable mode, advance ackd_head for all non DATA/INFO pkts, 79222f747efSnarayan * up to the current location of tx_head. This needs to be done 79322f747efSnarayan * as the peer will only ACK DATA/INFO pkts. 79422f747efSnarayan */ 79522f747efSnarayan if (ldcp->mode == LDC_MODE_RELIABLE || ldcp->mode == LDC_MODE_STREAM) { 79622f747efSnarayan while (ldcp->tx_ackd_head != ldcp->tx_head) { 79722f747efSnarayan pkt = (ldc_msg_t *)(ldcp->tx_q_va + ldcp->tx_ackd_head); 79822f747efSnarayan if ((pkt->type & LDC_DATA) && (pkt->stype & LDC_INFO)) { 79922f747efSnarayan break; 80022f747efSnarayan } 80122f747efSnarayan /* advance ACKd head */ 80222f747efSnarayan ldcp->tx_ackd_head = 80322f747efSnarayan (ldcp->tx_ackd_head + LDC_PACKET_SIZE) % 80422f747efSnarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 80522f747efSnarayan } 80622f747efSnarayan *head = ldcp->tx_ackd_head; 80722f747efSnarayan } 80822f747efSnarayan } 8091ae08745Sheppo 8101ae08745Sheppo /* 8111ae08745Sheppo * Returns the tx_tail to be used for transfer 8121ae08745Sheppo * Re-reads the TX queue ptrs if and only if the 8131ae08745Sheppo * the cached head and tail are equal (queue is full) 8141ae08745Sheppo */ 8151ae08745Sheppo static int 8161ae08745Sheppo i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail) 8171ae08745Sheppo { 8181ae08745Sheppo int rv; 8191ae08745Sheppo uint64_t current_head, new_tail; 8201ae08745Sheppo 821d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 8221ae08745Sheppo /* Read the head and tail ptrs from HV */ 8231ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 8241ae08745Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 8251ae08745Sheppo if (rv) { 8261ae08745Sheppo cmn_err(CE_WARN, 8271ae08745Sheppo "i_ldc_get_tx_tail: (0x%lx) cannot read qptrs\n", 8281ae08745Sheppo ldcp->id); 8291ae08745Sheppo return (EIO); 8301ae08745Sheppo } 8311ae08745Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN) { 832cb112a14Slm66018 D1(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) channel not ready\n", 8331ae08745Sheppo ldcp->id); 8341ae08745Sheppo return (ECONNRESET); 8351ae08745Sheppo } 8361ae08745Sheppo 83722f747efSnarayan i_ldc_get_tx_head(ldcp, ¤t_head); 8381ae08745Sheppo 8391ae08745Sheppo /* increment the tail */ 8401ae08745Sheppo new_tail = (ldcp->tx_tail + LDC_PACKET_SIZE) % 8411ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 8421ae08745Sheppo 8431ae08745Sheppo if (new_tail == current_head) { 8441ae08745Sheppo DWARN(ldcp->id, 8451ae08745Sheppo "i_ldc_get_tx_tail: (0x%llx) TX queue is full\n", 8461ae08745Sheppo ldcp->id); 8471ae08745Sheppo return (EWOULDBLOCK); 8481ae08745Sheppo } 8491ae08745Sheppo 8501ae08745Sheppo D2(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) head=0x%llx, tail=0x%llx\n", 8511ae08745Sheppo ldcp->id, ldcp->tx_head, ldcp->tx_tail); 8521ae08745Sheppo 8531ae08745Sheppo *tail = ldcp->tx_tail; 8541ae08745Sheppo return (0); 8551ae08745Sheppo } 8561ae08745Sheppo 8571ae08745Sheppo /* 8581ae08745Sheppo * Set the tail pointer. If HV returns EWOULDBLOCK, it will back off 8590a55fbb7Slm66018 * and retry ldc_max_retries times before returning an error. 8601ae08745Sheppo * Returns 0, EWOULDBLOCK or EIO 8611ae08745Sheppo */ 8621ae08745Sheppo static int 8631ae08745Sheppo i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail) 8641ae08745Sheppo { 8651ae08745Sheppo int rv, retval = EWOULDBLOCK; 8660a55fbb7Slm66018 int retries; 8671ae08745Sheppo 868d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 8690a55fbb7Slm66018 for (retries = 0; retries < ldc_max_retries; retries++) { 8701ae08745Sheppo 8711ae08745Sheppo if ((rv = hv_ldc_tx_set_qtail(ldcp->id, tail)) == 0) { 8721ae08745Sheppo retval = 0; 8731ae08745Sheppo break; 8741ae08745Sheppo } 8751ae08745Sheppo if (rv != H_EWOULDBLOCK) { 8761ae08745Sheppo DWARN(ldcp->id, "i_ldc_set_tx_tail: (0x%llx) set " 8771ae08745Sheppo "qtail=0x%llx failed, rv=%d\n", ldcp->id, tail, rv); 8781ae08745Sheppo retval = EIO; 8791ae08745Sheppo break; 8801ae08745Sheppo } 8811ae08745Sheppo 8820a55fbb7Slm66018 /* wait for ldc_delay usecs */ 8830a55fbb7Slm66018 drv_usecwait(ldc_delay); 8841ae08745Sheppo } 8851ae08745Sheppo return (retval); 8861ae08745Sheppo } 8871ae08745Sheppo 8881ae08745Sheppo /* 889*58283286Sha137994 * Copy a data packet from the HV receive queue to the data queue. 890*58283286Sha137994 * Caller must ensure that the data queue is not already full. 891*58283286Sha137994 * 892*58283286Sha137994 * The *head argument represents the current head pointer for the HV 893*58283286Sha137994 * receive queue. After copying a packet from the HV receive queue, 894*58283286Sha137994 * the *head pointer will be updated. This allows the caller to update 895*58283286Sha137994 * the head pointer in HV using the returned *head value. 896*58283286Sha137994 */ 897*58283286Sha137994 void 898*58283286Sha137994 i_ldc_rxdq_copy(ldc_chan_t *ldcp, uint64_t *head) 899*58283286Sha137994 { 900*58283286Sha137994 uint64_t q_size, dq_size; 901*58283286Sha137994 902*58283286Sha137994 ASSERT(MUTEX_HELD(&ldcp->lock)); 903*58283286Sha137994 904*58283286Sha137994 q_size = ldcp->rx_q_entries << LDC_PACKET_SHIFT; 905*58283286Sha137994 dq_size = ldcp->rx_dq_entries << LDC_PACKET_SHIFT; 906*58283286Sha137994 907*58283286Sha137994 ASSERT(Q_CONTIG_SPACE(ldcp->rx_dq_head, ldcp->rx_dq_tail, 908*58283286Sha137994 dq_size) >= LDC_PACKET_SIZE); 909*58283286Sha137994 910*58283286Sha137994 bcopy((void *)(ldcp->rx_q_va + *head), 911*58283286Sha137994 (void *)(ldcp->rx_dq_va + ldcp->rx_dq_tail), LDC_PACKET_SIZE); 912*58283286Sha137994 TRACE_RXDQ_COPY(ldcp, LDC_PACKET_SIZE); 913*58283286Sha137994 914*58283286Sha137994 /* Update rx head */ 915*58283286Sha137994 *head = (*head + LDC_PACKET_SIZE) % q_size; 916*58283286Sha137994 917*58283286Sha137994 /* Update dq tail */ 918*58283286Sha137994 ldcp->rx_dq_tail = (ldcp->rx_dq_tail + LDC_PACKET_SIZE) % dq_size; 919*58283286Sha137994 } 920*58283286Sha137994 921*58283286Sha137994 /* 922*58283286Sha137994 * Update the Rx data queue head pointer 923*58283286Sha137994 */ 924*58283286Sha137994 static int 925*58283286Sha137994 i_ldc_set_rxdq_head(ldc_chan_t *ldcp, uint64_t head) 926*58283286Sha137994 { 927*58283286Sha137994 ldcp->rx_dq_head = head; 928*58283286Sha137994 return (0); 929*58283286Sha137994 } 930*58283286Sha137994 931*58283286Sha137994 /* 932*58283286Sha137994 * Get the Rx data queue head and tail pointers 933*58283286Sha137994 */ 934*58283286Sha137994 static uint64_t 935*58283286Sha137994 i_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail, 936*58283286Sha137994 uint64_t *link_state) 937*58283286Sha137994 { 938*58283286Sha137994 _NOTE(ARGUNUSED(link_state)) 939*58283286Sha137994 *head = ldcp->rx_dq_head; 940*58283286Sha137994 *tail = ldcp->rx_dq_tail; 941*58283286Sha137994 return (0); 942*58283286Sha137994 } 943*58283286Sha137994 944*58283286Sha137994 /* 945*58283286Sha137994 * Wrapper for the Rx HV queue set head function. Giving the 946*58283286Sha137994 * data queue and HV queue set head functions the same type. 947*58283286Sha137994 */ 948*58283286Sha137994 static uint64_t 949*58283286Sha137994 i_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail, 950*58283286Sha137994 uint64_t *link_state) 951*58283286Sha137994 { 952*58283286Sha137994 return (i_ldc_h2v_error(hv_ldc_rx_get_state(ldcp->id, head, tail, 953*58283286Sha137994 link_state))); 954*58283286Sha137994 } 955*58283286Sha137994 956*58283286Sha137994 /* 957*58283286Sha137994 * LDC receive interrupt handler 958*58283286Sha137994 * triggered for channel with data pending to read 959*58283286Sha137994 * i.e. Rx queue content changes 960*58283286Sha137994 */ 961*58283286Sha137994 static uint_t 962*58283286Sha137994 i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2) 963*58283286Sha137994 { 964*58283286Sha137994 _NOTE(ARGUNUSED(arg2)) 965*58283286Sha137994 966*58283286Sha137994 ldc_chan_t *ldcp; 967*58283286Sha137994 boolean_t notify; 968*58283286Sha137994 uint64_t event; 969*58283286Sha137994 int rv; 970*58283286Sha137994 971*58283286Sha137994 /* Get the channel for which interrupt was received */ 972*58283286Sha137994 if (arg1 == NULL) { 973*58283286Sha137994 cmn_err(CE_WARN, "i_ldc_rx_hdlr: invalid arg\n"); 974*58283286Sha137994 return (DDI_INTR_UNCLAIMED); 975*58283286Sha137994 } 976*58283286Sha137994 977*58283286Sha137994 ldcp = (ldc_chan_t *)arg1; 978*58283286Sha137994 979*58283286Sha137994 D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n", 980*58283286Sha137994 ldcp->id, ldcp); 981*58283286Sha137994 D1(ldcp->id, "i_ldc_rx_hdlr: (%llx) USR%lx/TS%lx/HS%lx, LSTATE=%lx\n", 982*58283286Sha137994 ldcp->id, ldcp->status, ldcp->tstate, ldcp->hstate, 983*58283286Sha137994 ldcp->link_state); 984*58283286Sha137994 985*58283286Sha137994 /* Lock channel */ 986*58283286Sha137994 mutex_enter(&ldcp->lock); 987*58283286Sha137994 988*58283286Sha137994 /* Mark the interrupt as being actively handled */ 989*58283286Sha137994 ldcp->rx_intr_state = LDC_INTR_ACTIVE; 990*58283286Sha137994 991*58283286Sha137994 (void) i_ldc_rx_process_hvq(ldcp, ¬ify, &event); 992*58283286Sha137994 993*58283286Sha137994 if (ldcp->mode != LDC_MODE_STREAM) { 994*58283286Sha137994 /* 995*58283286Sha137994 * If there are no data packets on the queue, clear 996*58283286Sha137994 * the interrupt. Otherwise, the ldc_read will clear 997*58283286Sha137994 * interrupts after draining the queue. To indicate the 998*58283286Sha137994 * interrupt has not yet been cleared, it is marked 999*58283286Sha137994 * as pending. 1000*58283286Sha137994 */ 1001*58283286Sha137994 if ((event & LDC_EVT_READ) == 0) { 1002*58283286Sha137994 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 1003*58283286Sha137994 } else { 1004*58283286Sha137994 ldcp->rx_intr_state = LDC_INTR_PEND; 1005*58283286Sha137994 } 1006*58283286Sha137994 } 1007*58283286Sha137994 1008*58283286Sha137994 /* if callbacks are disabled, do not notify */ 1009*58283286Sha137994 if (notify && ldcp->cb_enabled) { 1010*58283286Sha137994 ldcp->cb_inprogress = B_TRUE; 1011*58283286Sha137994 mutex_exit(&ldcp->lock); 1012*58283286Sha137994 rv = ldcp->cb(event, ldcp->cb_arg); 1013*58283286Sha137994 if (rv) { 1014*58283286Sha137994 DWARN(ldcp->id, 1015*58283286Sha137994 "i_ldc_rx_hdlr: (0x%llx) callback failure", 1016*58283286Sha137994 ldcp->id); 1017*58283286Sha137994 } 1018*58283286Sha137994 mutex_enter(&ldcp->lock); 1019*58283286Sha137994 ldcp->cb_inprogress = B_FALSE; 1020*58283286Sha137994 } 1021*58283286Sha137994 1022*58283286Sha137994 if (ldcp->mode == LDC_MODE_STREAM) { 1023*58283286Sha137994 /* 1024*58283286Sha137994 * If we are using a secondary data queue, clear the 1025*58283286Sha137994 * interrupt. We should have processed all CTRL packets 1026*58283286Sha137994 * and copied all DATA packets to the secondary queue. 1027*58283286Sha137994 * Even if secondary queue filled up, clear the interrupts, 1028*58283286Sha137994 * this will trigger another interrupt and force the 1029*58283286Sha137994 * handler to copy more data. 1030*58283286Sha137994 */ 1031*58283286Sha137994 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 1032*58283286Sha137994 } 1033*58283286Sha137994 1034*58283286Sha137994 mutex_exit(&ldcp->lock); 1035*58283286Sha137994 1036*58283286Sha137994 D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) exiting handler", ldcp->id); 1037*58283286Sha137994 1038*58283286Sha137994 return (DDI_INTR_CLAIMED); 1039*58283286Sha137994 } 1040*58283286Sha137994 1041*58283286Sha137994 /* 1042*58283286Sha137994 * Wrapper for the Rx HV queue processing function to be used when 1043*58283286Sha137994 * checking the Rx HV queue for data packets. Unlike the interrupt 1044*58283286Sha137994 * handler code flow, the Rx interrupt is not cleared here and 1045*58283286Sha137994 * callbacks are not made. 1046*58283286Sha137994 */ 1047*58283286Sha137994 static uint_t 1048*58283286Sha137994 i_ldc_chkq(ldc_chan_t *ldcp) 1049*58283286Sha137994 { 1050*58283286Sha137994 boolean_t notify; 1051*58283286Sha137994 uint64_t event; 1052*58283286Sha137994 1053*58283286Sha137994 return (i_ldc_rx_process_hvq(ldcp, ¬ify, &event)); 1054*58283286Sha137994 } 1055*58283286Sha137994 1056*58283286Sha137994 /* 10571ae08745Sheppo * Send a LDC message 10581ae08745Sheppo */ 10591ae08745Sheppo static int 10601ae08745Sheppo i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype, 10611ae08745Sheppo uint8_t ctrlmsg) 10621ae08745Sheppo { 10631ae08745Sheppo int rv; 10641ae08745Sheppo ldc_msg_t *pkt; 10651ae08745Sheppo uint64_t tx_tail; 106622f747efSnarayan uint32_t curr_seqid; 10671ae08745Sheppo 1068d10e4ef2Snarayan /* Obtain Tx lock */ 1069d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 1070d10e4ef2Snarayan 107122f747efSnarayan curr_seqid = ldcp->last_msg_snt; 107222f747efSnarayan 10731ae08745Sheppo /* get the current tail for the message */ 10741ae08745Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 10751ae08745Sheppo if (rv) { 10761ae08745Sheppo DWARN(ldcp->id, 10771ae08745Sheppo "i_ldc_send_pkt: (0x%llx) error sending pkt, " 10781ae08745Sheppo "type=0x%x,subtype=0x%x,ctrl=0x%x\n", 10791ae08745Sheppo ldcp->id, pkttype, subtype, ctrlmsg); 1080d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 10811ae08745Sheppo return (rv); 10821ae08745Sheppo } 10831ae08745Sheppo 10841ae08745Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 10851ae08745Sheppo ZERO_PKT(pkt); 10861ae08745Sheppo 10871ae08745Sheppo /* Initialize the packet */ 10881ae08745Sheppo pkt->type = pkttype; 10891ae08745Sheppo pkt->stype = subtype; 10901ae08745Sheppo pkt->ctrl = ctrlmsg; 10911ae08745Sheppo 10921ae08745Sheppo /* Store ackid/seqid iff it is RELIABLE mode & not a RTS/RTR message */ 10931ae08745Sheppo if (((ctrlmsg & LDC_CTRL_MASK) != LDC_RTS) && 10941ae08745Sheppo ((ctrlmsg & LDC_CTRL_MASK) != LDC_RTR)) { 10951ae08745Sheppo curr_seqid++; 10961ae08745Sheppo if (ldcp->mode != LDC_MODE_RAW) { 10971ae08745Sheppo pkt->seqid = curr_seqid; 10981ae08745Sheppo pkt->ackid = ldcp->last_msg_rcd; 10991ae08745Sheppo } 11001ae08745Sheppo } 11011ae08745Sheppo DUMP_LDC_PKT(ldcp, "i_ldc_send_pkt", (uint64_t)pkt); 11021ae08745Sheppo 11031ae08745Sheppo /* initiate the send by calling into HV and set the new tail */ 11041ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 11051ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 11061ae08745Sheppo 11071ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 11081ae08745Sheppo if (rv) { 11091ae08745Sheppo DWARN(ldcp->id, 11101ae08745Sheppo "i_ldc_send_pkt:(0x%llx) error sending pkt, " 11111ae08745Sheppo "type=0x%x,stype=0x%x,ctrl=0x%x\n", 11121ae08745Sheppo ldcp->id, pkttype, subtype, ctrlmsg); 1113d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 11141ae08745Sheppo return (EIO); 11151ae08745Sheppo } 11161ae08745Sheppo 11171ae08745Sheppo ldcp->last_msg_snt = curr_seqid; 11181ae08745Sheppo ldcp->tx_tail = tx_tail; 11191ae08745Sheppo 1120d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 11211ae08745Sheppo return (0); 11221ae08745Sheppo } 11231ae08745Sheppo 11241ae08745Sheppo /* 11251ae08745Sheppo * Checks if packet was received in right order 1126e1ebb9ecSlm66018 * in the case of a reliable link. 11271ae08745Sheppo * Returns 0 if in order, else EIO 11281ae08745Sheppo */ 11291ae08745Sheppo static int 11301ae08745Sheppo i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *msg) 11311ae08745Sheppo { 11321ae08745Sheppo /* No seqid checking for RAW mode */ 11331ae08745Sheppo if (ldcp->mode == LDC_MODE_RAW) 11341ae08745Sheppo return (0); 11351ae08745Sheppo 11361ae08745Sheppo /* No seqid checking for version, RTS, RTR message */ 11371ae08745Sheppo if (msg->ctrl == LDC_VER || 11381ae08745Sheppo msg->ctrl == LDC_RTS || 11391ae08745Sheppo msg->ctrl == LDC_RTR) 11401ae08745Sheppo return (0); 11411ae08745Sheppo 11421ae08745Sheppo /* Initial seqid to use is sent in RTS/RTR and saved in last_msg_rcd */ 11431ae08745Sheppo if (msg->seqid != (ldcp->last_msg_rcd + 1)) { 11441ae08745Sheppo DWARN(ldcp->id, 11451ae08745Sheppo "i_ldc_check_seqid: (0x%llx) out-of-order pkt, got 0x%x, " 11461ae08745Sheppo "expecting 0x%x\n", ldcp->id, msg->seqid, 11471ae08745Sheppo (ldcp->last_msg_rcd + 1)); 11481ae08745Sheppo return (EIO); 11491ae08745Sheppo } 11501ae08745Sheppo 115183d3bc6fSnarayan #ifdef DEBUG 115283d3bc6fSnarayan if (LDC_INJECT_PKTLOSS(ldcp)) { 115383d3bc6fSnarayan DWARN(ldcp->id, 115483d3bc6fSnarayan "i_ldc_check_seqid: (0x%llx) inject pkt loss\n", ldcp->id); 115583d3bc6fSnarayan return (EIO); 115683d3bc6fSnarayan } 115783d3bc6fSnarayan #endif 115883d3bc6fSnarayan 11591ae08745Sheppo return (0); 11601ae08745Sheppo } 11611ae08745Sheppo 11621ae08745Sheppo 11631ae08745Sheppo /* 11641ae08745Sheppo * Process an incoming version ctrl message 11651ae08745Sheppo */ 11661ae08745Sheppo static int 11671ae08745Sheppo i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg) 11681ae08745Sheppo { 11691ae08745Sheppo int rv = 0, idx = ldcp->next_vidx; 11701ae08745Sheppo ldc_msg_t *pkt; 11711ae08745Sheppo uint64_t tx_tail; 11721ae08745Sheppo ldc_ver_t *rcvd_ver; 11731ae08745Sheppo 11741ae08745Sheppo /* get the received version */ 11751ae08745Sheppo rcvd_ver = (ldc_ver_t *)((uint64_t)msg + LDC_PAYLOAD_VER_OFF); 11761ae08745Sheppo 11771ae08745Sheppo D2(ldcp->id, "i_ldc_process_VER: (0x%llx) received VER v%u.%u\n", 11781ae08745Sheppo ldcp->id, rcvd_ver->major, rcvd_ver->minor); 11791ae08745Sheppo 1180d10e4ef2Snarayan /* Obtain Tx lock */ 1181d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 1182d10e4ef2Snarayan 11831ae08745Sheppo switch (msg->stype) { 11841ae08745Sheppo case LDC_INFO: 11851ae08745Sheppo 11863af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) { 11873af08d82Slm66018 (void) i_ldc_txq_reconf(ldcp); 11883af08d82Slm66018 i_ldc_reset_state(ldcp); 11893af08d82Slm66018 mutex_exit(&ldcp->tx_lock); 11903af08d82Slm66018 return (EAGAIN); 11913af08d82Slm66018 } 11923af08d82Slm66018 11931ae08745Sheppo /* get the current tail and pkt for the response */ 11941ae08745Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 11951ae08745Sheppo if (rv != 0) { 11961ae08745Sheppo DWARN(ldcp->id, 11971ae08745Sheppo "i_ldc_process_VER: (0x%llx) err sending " 11981ae08745Sheppo "version ACK/NACK\n", ldcp->id); 11993af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1200d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 12011ae08745Sheppo return (ECONNRESET); 12021ae08745Sheppo } 12031ae08745Sheppo 12041ae08745Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 12051ae08745Sheppo ZERO_PKT(pkt); 12061ae08745Sheppo 12071ae08745Sheppo /* initialize the packet */ 12081ae08745Sheppo pkt->type = LDC_CTRL; 12091ae08745Sheppo pkt->ctrl = LDC_VER; 12101ae08745Sheppo 12111ae08745Sheppo for (;;) { 12121ae08745Sheppo 12131ae08745Sheppo D1(ldcp->id, "i_ldc_process_VER: got %u.%u chk %u.%u\n", 12141ae08745Sheppo rcvd_ver->major, rcvd_ver->minor, 12151ae08745Sheppo ldc_versions[idx].major, ldc_versions[idx].minor); 12161ae08745Sheppo 12171ae08745Sheppo if (rcvd_ver->major == ldc_versions[idx].major) { 12181ae08745Sheppo /* major version match - ACK version */ 12191ae08745Sheppo pkt->stype = LDC_ACK; 12201ae08745Sheppo 12211ae08745Sheppo /* 12221ae08745Sheppo * lower minor version to the one this endpt 12231ae08745Sheppo * supports, if necessary 12241ae08745Sheppo */ 12251ae08745Sheppo if (rcvd_ver->minor > ldc_versions[idx].minor) 12261ae08745Sheppo rcvd_ver->minor = 12271ae08745Sheppo ldc_versions[idx].minor; 12281ae08745Sheppo bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver)); 12291ae08745Sheppo 12301ae08745Sheppo break; 12311ae08745Sheppo } 12321ae08745Sheppo 12331ae08745Sheppo if (rcvd_ver->major > ldc_versions[idx].major) { 12341ae08745Sheppo 12351ae08745Sheppo D1(ldcp->id, "i_ldc_process_VER: using next" 12361ae08745Sheppo " lower idx=%d, v%u.%u\n", idx, 12371ae08745Sheppo ldc_versions[idx].major, 12381ae08745Sheppo ldc_versions[idx].minor); 12391ae08745Sheppo 12401ae08745Sheppo /* nack with next lower version */ 12411ae08745Sheppo pkt->stype = LDC_NACK; 12421ae08745Sheppo bcopy(&ldc_versions[idx], pkt->udata, 12431ae08745Sheppo sizeof (ldc_versions[idx])); 12441ae08745Sheppo ldcp->next_vidx = idx; 12451ae08745Sheppo break; 12461ae08745Sheppo } 12471ae08745Sheppo 12481ae08745Sheppo /* next major version */ 12491ae08745Sheppo idx++; 12501ae08745Sheppo 12511ae08745Sheppo D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx); 12521ae08745Sheppo 12531ae08745Sheppo if (idx == LDC_NUM_VERS) { 12541ae08745Sheppo /* no version match - send NACK */ 12551ae08745Sheppo pkt->stype = LDC_NACK; 12561ae08745Sheppo bzero(pkt->udata, sizeof (ldc_ver_t)); 12571ae08745Sheppo ldcp->next_vidx = 0; 12581ae08745Sheppo break; 12591ae08745Sheppo } 12601ae08745Sheppo } 12611ae08745Sheppo 12621ae08745Sheppo /* initiate the send by calling into HV and set the new tail */ 12631ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 12641ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 12651ae08745Sheppo 12661ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 12671ae08745Sheppo if (rv == 0) { 12681ae08745Sheppo ldcp->tx_tail = tx_tail; 12691ae08745Sheppo if (pkt->stype == LDC_ACK) { 12701ae08745Sheppo D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent" 12711ae08745Sheppo " version ACK\n", ldcp->id); 12721ae08745Sheppo /* Save the ACK'd version */ 12731ae08745Sheppo ldcp->version.major = rcvd_ver->major; 12741ae08745Sheppo ldcp->version.minor = rcvd_ver->minor; 12750a55fbb7Slm66018 ldcp->hstate |= TS_RCVD_VER; 12761ae08745Sheppo ldcp->tstate |= TS_VER_DONE; 127783d3bc6fSnarayan D1(DBG_ALL_LDCS, 12783af08d82Slm66018 "(0x%llx) Sent ACK, " 12793af08d82Slm66018 "Agreed on version v%u.%u\n", 12801ae08745Sheppo ldcp->id, rcvd_ver->major, rcvd_ver->minor); 12811ae08745Sheppo } 12821ae08745Sheppo } else { 12831ae08745Sheppo DWARN(ldcp->id, 12841ae08745Sheppo "i_ldc_process_VER: (0x%llx) error sending " 12851ae08745Sheppo "ACK/NACK\n", ldcp->id); 12863af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1287d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 12881ae08745Sheppo return (ECONNRESET); 12891ae08745Sheppo } 12901ae08745Sheppo 12911ae08745Sheppo break; 12921ae08745Sheppo 12931ae08745Sheppo case LDC_ACK: 12943af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) { 12953af08d82Slm66018 if (ldcp->version.major != rcvd_ver->major || 12963af08d82Slm66018 ldcp->version.minor != rcvd_ver->minor) { 12973af08d82Slm66018 12983af08d82Slm66018 /* mismatched version - reset connection */ 12993af08d82Slm66018 DWARN(ldcp->id, 13003af08d82Slm66018 "i_ldc_process_VER: (0x%llx) recvd" 13013af08d82Slm66018 " ACK ver != sent ACK ver\n", ldcp->id); 13023af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 13033af08d82Slm66018 mutex_exit(&ldcp->tx_lock); 13043af08d82Slm66018 return (ECONNRESET); 13053af08d82Slm66018 } 13063af08d82Slm66018 } else { 13071ae08745Sheppo /* SUCCESS - we have agreed on a version */ 13081ae08745Sheppo ldcp->version.major = rcvd_ver->major; 13091ae08745Sheppo ldcp->version.minor = rcvd_ver->minor; 13101ae08745Sheppo ldcp->tstate |= TS_VER_DONE; 13113af08d82Slm66018 } 13121ae08745Sheppo 1313cb112a14Slm66018 D1(ldcp->id, "(0x%llx) Got ACK, Agreed on version v%u.%u\n", 13141ae08745Sheppo ldcp->id, rcvd_ver->major, rcvd_ver->minor); 13151ae08745Sheppo 13161ae08745Sheppo /* initiate RTS-RTR-RDX handshake */ 13171ae08745Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 13181ae08745Sheppo if (rv) { 13191ae08745Sheppo DWARN(ldcp->id, 13201ae08745Sheppo "i_ldc_process_VER: (0x%llx) cannot send RTS\n", 13211ae08745Sheppo ldcp->id); 13223af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1323d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 13241ae08745Sheppo return (ECONNRESET); 13251ae08745Sheppo } 13261ae08745Sheppo 13271ae08745Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 13281ae08745Sheppo ZERO_PKT(pkt); 13291ae08745Sheppo 13301ae08745Sheppo pkt->type = LDC_CTRL; 13311ae08745Sheppo pkt->stype = LDC_INFO; 13321ae08745Sheppo pkt->ctrl = LDC_RTS; 13331ae08745Sheppo pkt->env = ldcp->mode; 13341ae08745Sheppo if (ldcp->mode != LDC_MODE_RAW) 13351ae08745Sheppo pkt->seqid = LDC_INIT_SEQID; 13361ae08745Sheppo 13371ae08745Sheppo ldcp->last_msg_rcd = LDC_INIT_SEQID; 13381ae08745Sheppo 13391ae08745Sheppo DUMP_LDC_PKT(ldcp, "i_ldc_process_VER snd rts", (uint64_t)pkt); 13401ae08745Sheppo 13411ae08745Sheppo /* initiate the send by calling into HV and set the new tail */ 13421ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 13431ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 13441ae08745Sheppo 13451ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 13461ae08745Sheppo if (rv) { 13471ae08745Sheppo D2(ldcp->id, 13481ae08745Sheppo "i_ldc_process_VER: (0x%llx) no listener\n", 13491ae08745Sheppo ldcp->id); 13503af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1351d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 13521ae08745Sheppo return (ECONNRESET); 13531ae08745Sheppo } 13541ae08745Sheppo 13551ae08745Sheppo ldcp->tx_tail = tx_tail; 13561ae08745Sheppo ldcp->hstate |= TS_SENT_RTS; 13571ae08745Sheppo 13581ae08745Sheppo break; 13591ae08745Sheppo 13601ae08745Sheppo case LDC_NACK: 13611ae08745Sheppo /* check if version in NACK is zero */ 13621ae08745Sheppo if (rcvd_ver->major == 0 && rcvd_ver->minor == 0) { 13631ae08745Sheppo /* version handshake failure */ 13641ae08745Sheppo DWARN(DBG_ALL_LDCS, 13651ae08745Sheppo "i_ldc_process_VER: (0x%llx) no version match\n", 13661ae08745Sheppo ldcp->id); 13673af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1368d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 13691ae08745Sheppo return (ECONNRESET); 13701ae08745Sheppo } 13711ae08745Sheppo 13721ae08745Sheppo /* get the current tail and pkt for the response */ 13731ae08745Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 13741ae08745Sheppo if (rv != 0) { 13751ae08745Sheppo cmn_err(CE_NOTE, 13761ae08745Sheppo "i_ldc_process_VER: (0x%lx) err sending " 13771ae08745Sheppo "version ACK/NACK\n", ldcp->id); 13783af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1379d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 13801ae08745Sheppo return (ECONNRESET); 13811ae08745Sheppo } 13821ae08745Sheppo 13831ae08745Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 13841ae08745Sheppo ZERO_PKT(pkt); 13851ae08745Sheppo 13861ae08745Sheppo /* initialize the packet */ 13871ae08745Sheppo pkt->type = LDC_CTRL; 13881ae08745Sheppo pkt->ctrl = LDC_VER; 13891ae08745Sheppo pkt->stype = LDC_INFO; 13901ae08745Sheppo 13911ae08745Sheppo /* check ver in NACK msg has a match */ 13921ae08745Sheppo for (;;) { 13931ae08745Sheppo if (rcvd_ver->major == ldc_versions[idx].major) { 13941ae08745Sheppo /* 13951ae08745Sheppo * major version match - resubmit request 13961ae08745Sheppo * if lower minor version to the one this endpt 13971ae08745Sheppo * supports, if necessary 13981ae08745Sheppo */ 13991ae08745Sheppo if (rcvd_ver->minor > ldc_versions[idx].minor) 14001ae08745Sheppo rcvd_ver->minor = 14011ae08745Sheppo ldc_versions[idx].minor; 14021ae08745Sheppo bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver)); 14031ae08745Sheppo break; 14041ae08745Sheppo } 14051ae08745Sheppo 14061ae08745Sheppo if (rcvd_ver->major > ldc_versions[idx].major) { 14071ae08745Sheppo 14081ae08745Sheppo D1(ldcp->id, "i_ldc_process_VER: using next" 14091ae08745Sheppo " lower idx=%d, v%u.%u\n", idx, 14101ae08745Sheppo ldc_versions[idx].major, 14111ae08745Sheppo ldc_versions[idx].minor); 14121ae08745Sheppo 14131ae08745Sheppo /* send next lower version */ 14141ae08745Sheppo bcopy(&ldc_versions[idx], pkt->udata, 14151ae08745Sheppo sizeof (ldc_versions[idx])); 14161ae08745Sheppo ldcp->next_vidx = idx; 14171ae08745Sheppo break; 14181ae08745Sheppo } 14191ae08745Sheppo 14201ae08745Sheppo /* next version */ 14211ae08745Sheppo idx++; 14221ae08745Sheppo 14231ae08745Sheppo D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx); 14241ae08745Sheppo 14251ae08745Sheppo if (idx == LDC_NUM_VERS) { 14261ae08745Sheppo /* no version match - terminate */ 14271ae08745Sheppo ldcp->next_vidx = 0; 1428d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 14291ae08745Sheppo return (ECONNRESET); 14301ae08745Sheppo } 14311ae08745Sheppo } 14321ae08745Sheppo 14331ae08745Sheppo /* initiate the send by calling into HV and set the new tail */ 14341ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 14351ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 14361ae08745Sheppo 14371ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 14381ae08745Sheppo if (rv == 0) { 14391ae08745Sheppo D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent version" 14401ae08745Sheppo "INFO v%u.%u\n", ldcp->id, ldc_versions[idx].major, 14411ae08745Sheppo ldc_versions[idx].minor); 14421ae08745Sheppo ldcp->tx_tail = tx_tail; 14431ae08745Sheppo } else { 14441ae08745Sheppo cmn_err(CE_NOTE, 14451ae08745Sheppo "i_ldc_process_VER: (0x%lx) error sending version" 14461ae08745Sheppo "INFO\n", ldcp->id); 14473af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1448d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 14491ae08745Sheppo return (ECONNRESET); 14501ae08745Sheppo } 14511ae08745Sheppo 14521ae08745Sheppo break; 14531ae08745Sheppo } 14541ae08745Sheppo 1455d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 14561ae08745Sheppo return (rv); 14571ae08745Sheppo } 14581ae08745Sheppo 14591ae08745Sheppo 14601ae08745Sheppo /* 14611ae08745Sheppo * Process an incoming RTS ctrl message 14621ae08745Sheppo */ 14631ae08745Sheppo static int 14641ae08745Sheppo i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg) 14651ae08745Sheppo { 14661ae08745Sheppo int rv = 0; 14671ae08745Sheppo ldc_msg_t *pkt; 14681ae08745Sheppo uint64_t tx_tail; 14691ae08745Sheppo boolean_t sent_NACK = B_FALSE; 14701ae08745Sheppo 14711ae08745Sheppo D2(ldcp->id, "i_ldc_process_RTS: (0x%llx) received RTS\n", ldcp->id); 14721ae08745Sheppo 14731ae08745Sheppo switch (msg->stype) { 14741ae08745Sheppo case LDC_NACK: 14751ae08745Sheppo DWARN(ldcp->id, 14761ae08745Sheppo "i_ldc_process_RTS: (0x%llx) RTS NACK received\n", 14771ae08745Sheppo ldcp->id); 14781ae08745Sheppo 14791ae08745Sheppo /* Reset the channel -- as we cannot continue */ 1480d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 14813af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1482d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 14831ae08745Sheppo rv = ECONNRESET; 14841ae08745Sheppo break; 14851ae08745Sheppo 14861ae08745Sheppo case LDC_INFO: 14871ae08745Sheppo 14881ae08745Sheppo /* check mode */ 14891ae08745Sheppo if (ldcp->mode != (ldc_mode_t)msg->env) { 14901ae08745Sheppo cmn_err(CE_NOTE, 14911ae08745Sheppo "i_ldc_process_RTS: (0x%lx) mode mismatch\n", 14921ae08745Sheppo ldcp->id); 14931ae08745Sheppo /* 14941ae08745Sheppo * send NACK in response to MODE message 14951ae08745Sheppo * get the current tail for the response 14961ae08745Sheppo */ 14971ae08745Sheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTS); 14981ae08745Sheppo if (rv) { 14991ae08745Sheppo /* if cannot send NACK - reset channel */ 1500d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 15013af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1502d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 15031ae08745Sheppo rv = ECONNRESET; 15041ae08745Sheppo break; 15051ae08745Sheppo } 15061ae08745Sheppo sent_NACK = B_TRUE; 15071ae08745Sheppo } 15081ae08745Sheppo break; 15091ae08745Sheppo default: 15101ae08745Sheppo DWARN(ldcp->id, "i_ldc_process_RTS: (0x%llx) unexp ACK\n", 15111ae08745Sheppo ldcp->id); 1512d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 15133af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1514d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 15151ae08745Sheppo rv = ECONNRESET; 15161ae08745Sheppo break; 15171ae08745Sheppo } 15181ae08745Sheppo 15191ae08745Sheppo /* 15201ae08745Sheppo * If either the connection was reset (when rv != 0) or 15211ae08745Sheppo * a NACK was sent, we return. In the case of a NACK 15221ae08745Sheppo * we dont want to consume the packet that came in but 15231ae08745Sheppo * not record that we received the RTS 15241ae08745Sheppo */ 15251ae08745Sheppo if (rv || sent_NACK) 15261ae08745Sheppo return (rv); 15271ae08745Sheppo 15281ae08745Sheppo /* record RTS received */ 15291ae08745Sheppo ldcp->hstate |= TS_RCVD_RTS; 15301ae08745Sheppo 15311ae08745Sheppo /* store initial SEQID info */ 15321ae08745Sheppo ldcp->last_msg_snt = msg->seqid; 15331ae08745Sheppo 1534d10e4ef2Snarayan /* Obtain Tx lock */ 1535d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 1536d10e4ef2Snarayan 15371ae08745Sheppo /* get the current tail for the response */ 15381ae08745Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 15391ae08745Sheppo if (rv != 0) { 15401ae08745Sheppo cmn_err(CE_NOTE, 15411ae08745Sheppo "i_ldc_process_RTS: (0x%lx) err sending RTR\n", 15421ae08745Sheppo ldcp->id); 15433af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1544d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 15451ae08745Sheppo return (ECONNRESET); 15461ae08745Sheppo } 15471ae08745Sheppo 15481ae08745Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 15491ae08745Sheppo ZERO_PKT(pkt); 15501ae08745Sheppo 15511ae08745Sheppo /* initialize the packet */ 15521ae08745Sheppo pkt->type = LDC_CTRL; 15531ae08745Sheppo pkt->stype = LDC_INFO; 15541ae08745Sheppo pkt->ctrl = LDC_RTR; 15551ae08745Sheppo pkt->env = ldcp->mode; 15561ae08745Sheppo if (ldcp->mode != LDC_MODE_RAW) 15571ae08745Sheppo pkt->seqid = LDC_INIT_SEQID; 15581ae08745Sheppo 15591ae08745Sheppo ldcp->last_msg_rcd = msg->seqid; 15601ae08745Sheppo 15611ae08745Sheppo /* initiate the send by calling into HV and set the new tail */ 15621ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 15631ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 15641ae08745Sheppo 15651ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 15661ae08745Sheppo if (rv == 0) { 15671ae08745Sheppo D2(ldcp->id, 15681ae08745Sheppo "i_ldc_process_RTS: (0x%llx) sent RTR\n", ldcp->id); 15691ae08745Sheppo DUMP_LDC_PKT(ldcp, "i_ldc_process_RTS sent rtr", (uint64_t)pkt); 15701ae08745Sheppo 15711ae08745Sheppo ldcp->tx_tail = tx_tail; 15721ae08745Sheppo ldcp->hstate |= TS_SENT_RTR; 15731ae08745Sheppo 15741ae08745Sheppo } else { 15751ae08745Sheppo cmn_err(CE_NOTE, 15761ae08745Sheppo "i_ldc_process_RTS: (0x%lx) error sending RTR\n", 15771ae08745Sheppo ldcp->id); 15783af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1579d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 15801ae08745Sheppo return (ECONNRESET); 15811ae08745Sheppo } 15821ae08745Sheppo 1583d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 15841ae08745Sheppo return (0); 15851ae08745Sheppo } 15861ae08745Sheppo 15871ae08745Sheppo /* 15881ae08745Sheppo * Process an incoming RTR ctrl message 15891ae08745Sheppo */ 15901ae08745Sheppo static int 15911ae08745Sheppo i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg) 15921ae08745Sheppo { 15931ae08745Sheppo int rv = 0; 15941ae08745Sheppo boolean_t sent_NACK = B_FALSE; 15951ae08745Sheppo 15961ae08745Sheppo D2(ldcp->id, "i_ldc_process_RTR: (0x%llx) received RTR\n", ldcp->id); 15971ae08745Sheppo 15981ae08745Sheppo switch (msg->stype) { 15991ae08745Sheppo case LDC_NACK: 16001ae08745Sheppo /* RTR NACK received */ 16011ae08745Sheppo DWARN(ldcp->id, 16021ae08745Sheppo "i_ldc_process_RTR: (0x%llx) RTR NACK received\n", 16031ae08745Sheppo ldcp->id); 16041ae08745Sheppo 16051ae08745Sheppo /* Reset the channel -- as we cannot continue */ 1606d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 16073af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1608d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 16091ae08745Sheppo rv = ECONNRESET; 16101ae08745Sheppo 16111ae08745Sheppo break; 16121ae08745Sheppo 16131ae08745Sheppo case LDC_INFO: 16141ae08745Sheppo 16151ae08745Sheppo /* check mode */ 16161ae08745Sheppo if (ldcp->mode != (ldc_mode_t)msg->env) { 16171ae08745Sheppo DWARN(ldcp->id, 1618cb112a14Slm66018 "i_ldc_process_RTR: (0x%llx) mode mismatch, " 1619cb112a14Slm66018 "expecting 0x%x, got 0x%x\n", 1620cb112a14Slm66018 ldcp->id, ldcp->mode, (ldc_mode_t)msg->env); 16211ae08745Sheppo /* 16221ae08745Sheppo * send NACK in response to MODE message 16231ae08745Sheppo * get the current tail for the response 16241ae08745Sheppo */ 16251ae08745Sheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTR); 16261ae08745Sheppo if (rv) { 16271ae08745Sheppo /* if cannot send NACK - reset channel */ 1628d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 16293af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1630d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 16311ae08745Sheppo rv = ECONNRESET; 16321ae08745Sheppo break; 16331ae08745Sheppo } 16341ae08745Sheppo sent_NACK = B_TRUE; 16351ae08745Sheppo } 16361ae08745Sheppo break; 16371ae08745Sheppo 16381ae08745Sheppo default: 16391ae08745Sheppo DWARN(ldcp->id, "i_ldc_process_RTR: (0x%llx) unexp ACK\n", 16401ae08745Sheppo ldcp->id); 16411ae08745Sheppo 16421ae08745Sheppo /* Reset the channel -- as we cannot continue */ 1643d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 16443af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1645d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 16461ae08745Sheppo rv = ECONNRESET; 16471ae08745Sheppo break; 16481ae08745Sheppo } 16491ae08745Sheppo 16501ae08745Sheppo /* 16511ae08745Sheppo * If either the connection was reset (when rv != 0) or 16521ae08745Sheppo * a NACK was sent, we return. In the case of a NACK 16531ae08745Sheppo * we dont want to consume the packet that came in but 16541ae08745Sheppo * not record that we received the RTR 16551ae08745Sheppo */ 16561ae08745Sheppo if (rv || sent_NACK) 16571ae08745Sheppo return (rv); 16581ae08745Sheppo 16591ae08745Sheppo ldcp->last_msg_snt = msg->seqid; 16601ae08745Sheppo ldcp->hstate |= TS_RCVD_RTR; 16611ae08745Sheppo 16621ae08745Sheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_INFO, LDC_RDX); 16631ae08745Sheppo if (rv) { 16641ae08745Sheppo cmn_err(CE_NOTE, 16651ae08745Sheppo "i_ldc_process_RTR: (0x%lx) cannot send RDX\n", 16661ae08745Sheppo ldcp->id); 1667d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 16683af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1669d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 16701ae08745Sheppo return (ECONNRESET); 16711ae08745Sheppo } 16721ae08745Sheppo D2(ldcp->id, 16731ae08745Sheppo "i_ldc_process_RTR: (0x%llx) sent RDX\n", ldcp->id); 16741ae08745Sheppo 16751ae08745Sheppo ldcp->hstate |= TS_SENT_RDX; 16761ae08745Sheppo ldcp->tstate |= TS_HSHAKE_DONE; 16773af08d82Slm66018 if ((ldcp->tstate & TS_IN_RESET) == 0) 16781ae08745Sheppo ldcp->status = LDC_UP; 16791ae08745Sheppo 1680cb112a14Slm66018 D1(ldcp->id, "(0x%llx) Handshake Complete\n", ldcp->id); 16811ae08745Sheppo 16821ae08745Sheppo return (0); 16831ae08745Sheppo } 16841ae08745Sheppo 16851ae08745Sheppo 16861ae08745Sheppo /* 16871ae08745Sheppo * Process an incoming RDX ctrl message 16881ae08745Sheppo */ 16891ae08745Sheppo static int 16901ae08745Sheppo i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg) 16911ae08745Sheppo { 16921ae08745Sheppo int rv = 0; 16931ae08745Sheppo 16941ae08745Sheppo D2(ldcp->id, "i_ldc_process_RDX: (0x%llx) received RDX\n", ldcp->id); 16951ae08745Sheppo 16961ae08745Sheppo switch (msg->stype) { 16971ae08745Sheppo case LDC_NACK: 16981ae08745Sheppo /* RDX NACK received */ 16991ae08745Sheppo DWARN(ldcp->id, 17001ae08745Sheppo "i_ldc_process_RDX: (0x%llx) RDX NACK received\n", 17011ae08745Sheppo ldcp->id); 17021ae08745Sheppo 17031ae08745Sheppo /* Reset the channel -- as we cannot continue */ 1704d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 17053af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1706d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 17071ae08745Sheppo rv = ECONNRESET; 17081ae08745Sheppo 17091ae08745Sheppo break; 17101ae08745Sheppo 17111ae08745Sheppo case LDC_INFO: 17121ae08745Sheppo 17131ae08745Sheppo /* 17141ae08745Sheppo * if channel is UP and a RDX received after data transmission 17151ae08745Sheppo * has commenced it is an error 17161ae08745Sheppo */ 17171ae08745Sheppo if ((ldcp->tstate == TS_UP) && (ldcp->hstate & TS_RCVD_RDX)) { 17181ae08745Sheppo DWARN(DBG_ALL_LDCS, 17191ae08745Sheppo "i_ldc_process_RDX: (0x%llx) unexpected RDX" 17201ae08745Sheppo " - LDC reset\n", 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 17271ae08745Sheppo ldcp->hstate |= TS_RCVD_RDX; 17281ae08745Sheppo ldcp->tstate |= TS_HSHAKE_DONE; 17293af08d82Slm66018 if ((ldcp->tstate & TS_IN_RESET) == 0) 17301ae08745Sheppo ldcp->status = LDC_UP; 17311ae08745Sheppo 17321ae08745Sheppo D1(DBG_ALL_LDCS, "(0x%llx) Handshake Complete\n", ldcp->id); 17331ae08745Sheppo break; 17341ae08745Sheppo 17351ae08745Sheppo default: 17361ae08745Sheppo DWARN(ldcp->id, "i_ldc_process_RDX: (0x%llx) unexp ACK\n", 17371ae08745Sheppo ldcp->id); 17381ae08745Sheppo 17391ae08745Sheppo /* Reset the channel -- as we cannot continue */ 1740d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 17413af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1742d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 17431ae08745Sheppo rv = ECONNRESET; 17441ae08745Sheppo break; 17451ae08745Sheppo } 17461ae08745Sheppo 17471ae08745Sheppo return (rv); 17481ae08745Sheppo } 17491ae08745Sheppo 17501ae08745Sheppo /* 17511ae08745Sheppo * Process an incoming ACK for a data packet 17521ae08745Sheppo */ 17531ae08745Sheppo static int 17541ae08745Sheppo i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg) 17551ae08745Sheppo { 17561ae08745Sheppo int rv; 17571ae08745Sheppo uint64_t tx_head; 17581ae08745Sheppo ldc_msg_t *pkt; 17591ae08745Sheppo 1760d10e4ef2Snarayan /* Obtain Tx lock */ 1761d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 1762d10e4ef2Snarayan 17631ae08745Sheppo /* 1764d10e4ef2Snarayan * Read the current Tx head and tail 17651ae08745Sheppo */ 17661ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 17671ae08745Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 17681ae08745Sheppo if (rv != 0) { 17691ae08745Sheppo cmn_err(CE_WARN, 17701ae08745Sheppo "i_ldc_process_data_ACK: (0x%lx) cannot read qptrs\n", 17711ae08745Sheppo ldcp->id); 1772d10e4ef2Snarayan 1773d10e4ef2Snarayan /* Reset the channel -- as we cannot continue */ 17743af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1775d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 1776d10e4ef2Snarayan return (ECONNRESET); 17771ae08745Sheppo } 17781ae08745Sheppo 17791ae08745Sheppo /* 17801ae08745Sheppo * loop from where the previous ACK location was to the 17811ae08745Sheppo * current head location. This is how far the HV has 17821ae08745Sheppo * actually send pkts. Pkts between head and tail are 17831ae08745Sheppo * yet to be sent by HV. 17841ae08745Sheppo */ 17851ae08745Sheppo tx_head = ldcp->tx_ackd_head; 17861ae08745Sheppo for (;;) { 17871ae08745Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_head); 17881ae08745Sheppo tx_head = (tx_head + LDC_PACKET_SIZE) % 17891ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 17901ae08745Sheppo 17911ae08745Sheppo if (pkt->seqid == msg->ackid) { 17921ae08745Sheppo D2(ldcp->id, 17931ae08745Sheppo "i_ldc_process_data_ACK: (0x%llx) found packet\n", 17941ae08745Sheppo ldcp->id); 17951ae08745Sheppo ldcp->last_ack_rcd = msg->ackid; 17961ae08745Sheppo ldcp->tx_ackd_head = tx_head; 17971ae08745Sheppo break; 17981ae08745Sheppo } 17991ae08745Sheppo if (tx_head == ldcp->tx_head) { 18001ae08745Sheppo /* could not find packet */ 18011ae08745Sheppo DWARN(ldcp->id, 18021ae08745Sheppo "i_ldc_process_data_ACK: (0x%llx) invalid ACKid\n", 18031ae08745Sheppo ldcp->id); 1804d10e4ef2Snarayan 1805d10e4ef2Snarayan /* Reset the channel -- as we cannot continue */ 18063af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 1807d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 1808d10e4ef2Snarayan return (ECONNRESET); 18091ae08745Sheppo } 18101ae08745Sheppo } 18111ae08745Sheppo 1812d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 18131ae08745Sheppo return (0); 18141ae08745Sheppo } 18151ae08745Sheppo 18161ae08745Sheppo /* 18171ae08745Sheppo * Process incoming control message 18181ae08745Sheppo * Return 0 - session can continue 18191ae08745Sheppo * EAGAIN - reprocess packet - state was changed 18201ae08745Sheppo * ECONNRESET - channel was reset 18211ae08745Sheppo */ 18221ae08745Sheppo static int 18231ae08745Sheppo i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *msg) 18241ae08745Sheppo { 18251ae08745Sheppo int rv = 0; 18261ae08745Sheppo 18273af08d82Slm66018 D1(ldcp->id, "i_ldc_ctrlmsg: (%llx) tstate = %lx, hstate = %lx\n", 18283af08d82Slm66018 ldcp->id, ldcp->tstate, ldcp->hstate); 18293af08d82Slm66018 18303af08d82Slm66018 switch (ldcp->tstate & ~TS_IN_RESET) { 18311ae08745Sheppo 18321ae08745Sheppo case TS_OPEN: 18331ae08745Sheppo case TS_READY: 18341ae08745Sheppo 18351ae08745Sheppo switch (msg->ctrl & LDC_CTRL_MASK) { 18361ae08745Sheppo case LDC_VER: 18371ae08745Sheppo /* process version message */ 18381ae08745Sheppo rv = i_ldc_process_VER(ldcp, msg); 18391ae08745Sheppo break; 18401ae08745Sheppo default: 18411ae08745Sheppo DWARN(ldcp->id, 18421ae08745Sheppo "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x " 18431ae08745Sheppo "tstate=0x%x\n", ldcp->id, 18441ae08745Sheppo (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate); 18451ae08745Sheppo break; 18461ae08745Sheppo } 18471ae08745Sheppo 18481ae08745Sheppo break; 18491ae08745Sheppo 18501ae08745Sheppo case TS_VREADY: 18511ae08745Sheppo 18521ae08745Sheppo switch (msg->ctrl & LDC_CTRL_MASK) { 18531ae08745Sheppo case LDC_VER: 18543af08d82Slm66018 /* process version message */ 18553af08d82Slm66018 rv = i_ldc_process_VER(ldcp, msg); 18561ae08745Sheppo break; 18571ae08745Sheppo case LDC_RTS: 18581ae08745Sheppo /* process RTS message */ 18591ae08745Sheppo rv = i_ldc_process_RTS(ldcp, msg); 18601ae08745Sheppo break; 18611ae08745Sheppo case LDC_RTR: 18621ae08745Sheppo /* process RTR message */ 18631ae08745Sheppo rv = i_ldc_process_RTR(ldcp, msg); 18641ae08745Sheppo break; 18651ae08745Sheppo case LDC_RDX: 18661ae08745Sheppo /* process RDX message */ 18671ae08745Sheppo rv = i_ldc_process_RDX(ldcp, msg); 18681ae08745Sheppo break; 18691ae08745Sheppo default: 18701ae08745Sheppo DWARN(ldcp->id, 18711ae08745Sheppo "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x " 18721ae08745Sheppo "tstate=0x%x\n", ldcp->id, 18731ae08745Sheppo (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate); 18741ae08745Sheppo break; 18751ae08745Sheppo } 18761ae08745Sheppo 18771ae08745Sheppo break; 18781ae08745Sheppo 18791ae08745Sheppo case TS_UP: 18801ae08745Sheppo 18811ae08745Sheppo switch (msg->ctrl & LDC_CTRL_MASK) { 18821ae08745Sheppo case LDC_VER: 18831ae08745Sheppo DWARN(ldcp->id, 18841ae08745Sheppo "i_ldc_ctrlmsg: (0x%llx) unexpected VER " 18851ae08745Sheppo "- LDC reset\n", ldcp->id); 18861ae08745Sheppo /* peer is redoing version negotiation */ 1887d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 18881ae08745Sheppo (void) i_ldc_txq_reconf(ldcp); 18891ae08745Sheppo i_ldc_reset_state(ldcp); 1890d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 18911ae08745Sheppo rv = EAGAIN; 18921ae08745Sheppo break; 18931ae08745Sheppo 18941ae08745Sheppo case LDC_RDX: 18951ae08745Sheppo /* process RDX message */ 18961ae08745Sheppo rv = i_ldc_process_RDX(ldcp, msg); 18971ae08745Sheppo break; 18981ae08745Sheppo 18991ae08745Sheppo default: 19001ae08745Sheppo DWARN(ldcp->id, 19011ae08745Sheppo "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x " 19021ae08745Sheppo "tstate=0x%x\n", ldcp->id, 19031ae08745Sheppo (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate); 19041ae08745Sheppo break; 19051ae08745Sheppo } 19061ae08745Sheppo } 19071ae08745Sheppo 19081ae08745Sheppo return (rv); 19091ae08745Sheppo } 19101ae08745Sheppo 19111ae08745Sheppo /* 19121ae08745Sheppo * Register channel with the channel nexus 19131ae08745Sheppo */ 19141ae08745Sheppo static int 19151ae08745Sheppo i_ldc_register_channel(ldc_chan_t *ldcp) 19161ae08745Sheppo { 19171ae08745Sheppo int rv = 0; 19181ae08745Sheppo ldc_cnex_t *cinfo = &ldcssp->cinfo; 19191ae08745Sheppo 19201ae08745Sheppo if (cinfo->dip == NULL) { 19211ae08745Sheppo DWARN(ldcp->id, 19221ae08745Sheppo "i_ldc_register_channel: cnex has not registered\n"); 19231ae08745Sheppo return (EAGAIN); 19241ae08745Sheppo } 19251ae08745Sheppo 19261ae08745Sheppo rv = cinfo->reg_chan(cinfo->dip, ldcp->id, ldcp->devclass); 19271ae08745Sheppo if (rv) { 19281ae08745Sheppo DWARN(ldcp->id, 19291ae08745Sheppo "i_ldc_register_channel: cannot register channel\n"); 19301ae08745Sheppo return (rv); 19311ae08745Sheppo } 19321ae08745Sheppo 19331ae08745Sheppo rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR, 19341ae08745Sheppo i_ldc_tx_hdlr, ldcp, NULL); 19351ae08745Sheppo if (rv) { 19361ae08745Sheppo DWARN(ldcp->id, 19371ae08745Sheppo "i_ldc_register_channel: cannot add Tx interrupt\n"); 19381ae08745Sheppo (void) cinfo->unreg_chan(cinfo->dip, ldcp->id); 19391ae08745Sheppo return (rv); 19401ae08745Sheppo } 19411ae08745Sheppo 19421ae08745Sheppo rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR, 19431ae08745Sheppo i_ldc_rx_hdlr, ldcp, NULL); 19441ae08745Sheppo if (rv) { 19451ae08745Sheppo DWARN(ldcp->id, 19461ae08745Sheppo "i_ldc_register_channel: cannot add Rx interrupt\n"); 19471ae08745Sheppo (void) cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR); 19481ae08745Sheppo (void) cinfo->unreg_chan(cinfo->dip, ldcp->id); 19491ae08745Sheppo return (rv); 19501ae08745Sheppo } 19511ae08745Sheppo 19521ae08745Sheppo ldcp->tstate |= TS_CNEX_RDY; 19531ae08745Sheppo 19541ae08745Sheppo return (0); 19551ae08745Sheppo } 19561ae08745Sheppo 19571ae08745Sheppo /* 19581ae08745Sheppo * Unregister a channel with the channel nexus 19591ae08745Sheppo */ 19601ae08745Sheppo static int 19611ae08745Sheppo i_ldc_unregister_channel(ldc_chan_t *ldcp) 19621ae08745Sheppo { 19631ae08745Sheppo int rv = 0; 19641ae08745Sheppo ldc_cnex_t *cinfo = &ldcssp->cinfo; 19651ae08745Sheppo 19661ae08745Sheppo if (cinfo->dip == NULL) { 19671ae08745Sheppo DWARN(ldcp->id, 19681ae08745Sheppo "i_ldc_unregister_channel: cnex has not registered\n"); 19691ae08745Sheppo return (EAGAIN); 19701ae08745Sheppo } 19711ae08745Sheppo 19721ae08745Sheppo if (ldcp->tstate & TS_CNEX_RDY) { 19731ae08745Sheppo 1974d10e4ef2Snarayan /* Remove the Rx interrupt */ 19751ae08745Sheppo rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR); 19761ae08745Sheppo if (rv) { 19773af08d82Slm66018 if (rv != EAGAIN) { 19781ae08745Sheppo DWARN(ldcp->id, 19793af08d82Slm66018 "i_ldc_unregister_channel: err removing " 19803af08d82Slm66018 "Rx intr\n"); 1981d10e4ef2Snarayan return (rv); 19821ae08745Sheppo } 1983d10e4ef2Snarayan 19843af08d82Slm66018 /* 19853af08d82Slm66018 * If interrupts are pending and handler has 19863af08d82Slm66018 * finished running, clear interrupt and try 19873af08d82Slm66018 * again 19883af08d82Slm66018 */ 19893af08d82Slm66018 if (ldcp->rx_intr_state != LDC_INTR_PEND) 19903af08d82Slm66018 return (rv); 19913af08d82Slm66018 19923af08d82Slm66018 (void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 19933af08d82Slm66018 rv = cinfo->rem_intr(cinfo->dip, ldcp->id, 19943af08d82Slm66018 CNEX_RX_INTR); 19953af08d82Slm66018 if (rv) { 19963af08d82Slm66018 DWARN(ldcp->id, "i_ldc_unregister_channel: " 19973af08d82Slm66018 "err removing Rx interrupt\n"); 19983af08d82Slm66018 return (rv); 19993af08d82Slm66018 } 20003af08d82Slm66018 } 20013af08d82Slm66018 2002d10e4ef2Snarayan /* Remove the Tx interrupt */ 20031ae08745Sheppo rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR); 20041ae08745Sheppo if (rv) { 20051ae08745Sheppo DWARN(ldcp->id, 20061ae08745Sheppo "i_ldc_unregister_channel: err removing Tx intr\n"); 2007d10e4ef2Snarayan return (rv); 20081ae08745Sheppo } 2009d10e4ef2Snarayan 2010d10e4ef2Snarayan /* Unregister the channel */ 20111ae08745Sheppo rv = cinfo->unreg_chan(ldcssp->cinfo.dip, ldcp->id); 20121ae08745Sheppo if (rv) { 20131ae08745Sheppo DWARN(ldcp->id, 20141ae08745Sheppo "i_ldc_unregister_channel: cannot unreg channel\n"); 2015d10e4ef2Snarayan return (rv); 20161ae08745Sheppo } 20171ae08745Sheppo 20181ae08745Sheppo ldcp->tstate &= ~TS_CNEX_RDY; 20191ae08745Sheppo } 20201ae08745Sheppo 20211ae08745Sheppo return (0); 20221ae08745Sheppo } 20231ae08745Sheppo 20241ae08745Sheppo 20251ae08745Sheppo /* 20261ae08745Sheppo * LDC transmit interrupt handler 20271ae08745Sheppo * triggered for chanel up/down/reset events 20281ae08745Sheppo * and Tx queue content changes 20291ae08745Sheppo */ 20301ae08745Sheppo static uint_t 20311ae08745Sheppo i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2) 20321ae08745Sheppo { 20331ae08745Sheppo _NOTE(ARGUNUSED(arg2)) 20341ae08745Sheppo 20351ae08745Sheppo int rv; 20361ae08745Sheppo ldc_chan_t *ldcp; 20371ae08745Sheppo boolean_t notify_client = B_FALSE; 20383af08d82Slm66018 uint64_t notify_event = 0, link_state; 20391ae08745Sheppo 20401ae08745Sheppo /* Get the channel for which interrupt was received */ 20411ae08745Sheppo ASSERT(arg1 != NULL); 20421ae08745Sheppo ldcp = (ldc_chan_t *)arg1; 20431ae08745Sheppo 20441ae08745Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n", 20451ae08745Sheppo ldcp->id, ldcp); 20461ae08745Sheppo 20471ae08745Sheppo /* Lock channel */ 20481ae08745Sheppo mutex_enter(&ldcp->lock); 20491ae08745Sheppo 2050d10e4ef2Snarayan /* Obtain Tx lock */ 2051d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 2052d10e4ef2Snarayan 20534bac2208Snarayan /* mark interrupt as pending */ 20543af08d82Slm66018 ldcp->tx_intr_state = LDC_INTR_ACTIVE; 20553af08d82Slm66018 20563af08d82Slm66018 /* save current link state */ 20573af08d82Slm66018 link_state = ldcp->link_state; 20584bac2208Snarayan 20591ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id, &ldcp->tx_head, &ldcp->tx_tail, 20601ae08745Sheppo &ldcp->link_state); 20611ae08745Sheppo if (rv) { 20621ae08745Sheppo cmn_err(CE_WARN, 20631ae08745Sheppo "i_ldc_tx_hdlr: (0x%lx) cannot read queue ptrs rv=0x%d\n", 20641ae08745Sheppo ldcp->id, rv); 20654bac2208Snarayan i_ldc_clear_intr(ldcp, CNEX_TX_INTR); 2066d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 20671ae08745Sheppo mutex_exit(&ldcp->lock); 20681ae08745Sheppo return (DDI_INTR_CLAIMED); 20691ae08745Sheppo } 20701ae08745Sheppo 20711ae08745Sheppo /* 20721ae08745Sheppo * reset the channel state if the channel went down 20731ae08745Sheppo * (other side unconfigured queue) or channel was reset 20741ae08745Sheppo * (other side reconfigured its queue) 20751ae08745Sheppo */ 20763af08d82Slm66018 if (link_state != ldcp->link_state && 20773af08d82Slm66018 ldcp->link_state == LDC_CHANNEL_DOWN) { 20781ae08745Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: channel link down\n", ldcp->id); 20793af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 20801ae08745Sheppo notify_client = B_TRUE; 20811ae08745Sheppo notify_event = LDC_EVT_DOWN; 20821ae08745Sheppo } 20831ae08745Sheppo 20843af08d82Slm66018 if (link_state != ldcp->link_state && 20853af08d82Slm66018 ldcp->link_state == LDC_CHANNEL_RESET) { 20861ae08745Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: channel link reset\n", ldcp->id); 20873af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 20881ae08745Sheppo notify_client = B_TRUE; 20891ae08745Sheppo notify_event = LDC_EVT_RESET; 20901ae08745Sheppo } 20911ae08745Sheppo 20923af08d82Slm66018 if (link_state != ldcp->link_state && 20933af08d82Slm66018 (ldcp->tstate & ~TS_IN_RESET) == TS_OPEN && 20943af08d82Slm66018 ldcp->link_state == LDC_CHANNEL_UP) { 20951ae08745Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: channel link up\n", ldcp->id); 20961ae08745Sheppo notify_client = B_TRUE; 20971ae08745Sheppo notify_event = LDC_EVT_RESET; 20981ae08745Sheppo ldcp->tstate |= TS_LINK_READY; 20991ae08745Sheppo ldcp->status = LDC_READY; 21001ae08745Sheppo } 21011ae08745Sheppo 21021ae08745Sheppo /* if callbacks are disabled, do not notify */ 21031ae08745Sheppo if (!ldcp->cb_enabled) 21041ae08745Sheppo notify_client = B_FALSE; 21051ae08745Sheppo 21064d39be2bSsg70180 i_ldc_clear_intr(ldcp, CNEX_TX_INTR); 210722f747efSnarayan mutex_exit(&ldcp->tx_lock); 21081ae08745Sheppo 21091ae08745Sheppo if (notify_client) { 21103af08d82Slm66018 ldcp->cb_inprogress = B_TRUE; 21113af08d82Slm66018 mutex_exit(&ldcp->lock); 21121ae08745Sheppo rv = ldcp->cb(notify_event, ldcp->cb_arg); 21131ae08745Sheppo if (rv) { 21141ae08745Sheppo DWARN(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) callback " 21151ae08745Sheppo "failure", ldcp->id); 21161ae08745Sheppo } 21171ae08745Sheppo mutex_enter(&ldcp->lock); 21181ae08745Sheppo ldcp->cb_inprogress = B_FALSE; 21191ae08745Sheppo } 21201ae08745Sheppo 21211ae08745Sheppo mutex_exit(&ldcp->lock); 21221ae08745Sheppo 21231ae08745Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) exiting handler", ldcp->id); 21241ae08745Sheppo 21251ae08745Sheppo return (DDI_INTR_CLAIMED); 21261ae08745Sheppo } 21271ae08745Sheppo 21281ae08745Sheppo /* 2129*58283286Sha137994 * Process the Rx HV queue. 2130*58283286Sha137994 * 2131*58283286Sha137994 * Returns 0 if data packets were found and no errors were encountered, 2132*58283286Sha137994 * otherwise returns an error. In either case, the *notify argument is 2133*58283286Sha137994 * set to indicate whether or not the client callback function should 2134*58283286Sha137994 * be invoked. The *event argument is set to contain the callback event. 2135*58283286Sha137994 * 2136*58283286Sha137994 * Depending on the channel mode, packets are handled differently: 2137*58283286Sha137994 * 2138*58283286Sha137994 * RAW MODE 2139*58283286Sha137994 * For raw mode channels, when a data packet is encountered, 2140*58283286Sha137994 * processing stops and all packets are left on the queue to be removed 2141*58283286Sha137994 * and processed by the ldc_read code path. 2142*58283286Sha137994 * 2143*58283286Sha137994 * UNRELIABLE MODE 2144*58283286Sha137994 * For unreliable mode, when a data packet is encountered, processing 2145*58283286Sha137994 * stops, and all packets are left on the queue to be removed and 2146*58283286Sha137994 * processed by the ldc_read code path. Control packets are processed 2147*58283286Sha137994 * inline if they are encountered before any data packets. 2148*58283286Sha137994 * 2149*58283286Sha137994 * STEAMING MODE 2150*58283286Sha137994 * For streaming mode channels, all packets on the receive queue 2151*58283286Sha137994 * are processed: data packets are copied to the data queue and 2152*58283286Sha137994 * control packets are processed inline. Packets are only left on 2153*58283286Sha137994 * the receive queue when the data queue is full. 21541ae08745Sheppo */ 21551ae08745Sheppo static uint_t 2156*58283286Sha137994 i_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client, 2157*58283286Sha137994 uint64_t *notify_event) 21581ae08745Sheppo { 21591ae08745Sheppo int rv; 21601ae08745Sheppo uint64_t rx_head, rx_tail; 21611ae08745Sheppo ldc_msg_t *msg; 21623af08d82Slm66018 uint64_t link_state, first_fragment = 0; 2163*58283286Sha137994 boolean_t trace_length = B_TRUE; 21643af08d82Slm66018 2165*58283286Sha137994 ASSERT(MUTEX_HELD(&ldcp->lock)); 2166*58283286Sha137994 *notify_client = B_FALSE; 2167*58283286Sha137994 *notify_event = 0; 21681ae08745Sheppo 21691ae08745Sheppo /* 21701ae08745Sheppo * Read packet(s) from the queue 21711ae08745Sheppo */ 21721ae08745Sheppo for (;;) { 21731ae08745Sheppo 21743af08d82Slm66018 link_state = ldcp->link_state; 21751ae08745Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 21761ae08745Sheppo &ldcp->link_state); 21771ae08745Sheppo if (rv) { 21781ae08745Sheppo cmn_err(CE_WARN, 2179*58283286Sha137994 "i_ldc_rx_process_hvq: (0x%lx) cannot read " 21801ae08745Sheppo "queue ptrs, rv=0x%d\n", ldcp->id, rv); 21811ae08745Sheppo i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 2182*58283286Sha137994 return (EIO); 21831ae08745Sheppo } 21841ae08745Sheppo 21851ae08745Sheppo /* 21861ae08745Sheppo * reset the channel state if the channel went down 21871ae08745Sheppo * (other side unconfigured queue) or channel was reset 21883af08d82Slm66018 * (other side reconfigured its queue) 21891ae08745Sheppo */ 21903af08d82Slm66018 21913af08d82Slm66018 if (link_state != ldcp->link_state) { 2192cb112a14Slm66018 21933af08d82Slm66018 switch (ldcp->link_state) { 21943af08d82Slm66018 case LDC_CHANNEL_DOWN: 2195*58283286Sha137994 D1(ldcp->id, "i_ldc_rx_process_hvq: channel " 21963af08d82Slm66018 "link down\n", ldcp->id); 2197d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 21983af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 2199d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 2200*58283286Sha137994 *notify_client = B_TRUE; 2201*58283286Sha137994 *notify_event = LDC_EVT_DOWN; 22023af08d82Slm66018 goto loop_exit; 22031ae08745Sheppo 22043af08d82Slm66018 case LDC_CHANNEL_UP: 2205*58283286Sha137994 D1(ldcp->id, "i_ldc_rx_process_hvq: " 22063af08d82Slm66018 "channel link up\n", ldcp->id); 22073af08d82Slm66018 22083af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) == TS_OPEN) { 2209*58283286Sha137994 *notify_client = B_TRUE; 2210*58283286Sha137994 *notify_event = LDC_EVT_RESET; 22111ae08745Sheppo ldcp->tstate |= TS_LINK_READY; 22121ae08745Sheppo ldcp->status = LDC_READY; 22131ae08745Sheppo } 22143af08d82Slm66018 break; 22153af08d82Slm66018 22163af08d82Slm66018 case LDC_CHANNEL_RESET: 22173af08d82Slm66018 default: 22183af08d82Slm66018 #ifdef DEBUG 22193af08d82Slm66018 force_reset: 22203af08d82Slm66018 #endif 2221*58283286Sha137994 D1(ldcp->id, "i_ldc_rx_process_hvq: channel " 22223af08d82Slm66018 "link reset\n", ldcp->id); 22233af08d82Slm66018 mutex_enter(&ldcp->tx_lock); 22243af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 22253af08d82Slm66018 mutex_exit(&ldcp->tx_lock); 2226*58283286Sha137994 *notify_client = B_TRUE; 2227*58283286Sha137994 *notify_event = LDC_EVT_RESET; 22283af08d82Slm66018 break; 22293af08d82Slm66018 } 22303af08d82Slm66018 } 22313af08d82Slm66018 22323af08d82Slm66018 #ifdef DEBUG 22333af08d82Slm66018 if (LDC_INJECT_RESET(ldcp)) 22343af08d82Slm66018 goto force_reset; 22353af08d82Slm66018 #endif 2236*58283286Sha137994 if (trace_length) { 2237*58283286Sha137994 TRACE_RXHVQ_LENGTH(ldcp, rx_head, rx_tail); 2238*58283286Sha137994 trace_length = B_FALSE; 2239*58283286Sha137994 } 22401ae08745Sheppo 22411ae08745Sheppo if (rx_head == rx_tail) { 2242*58283286Sha137994 D2(ldcp->id, "i_ldc_rx_process_hvq: (0x%llx) " 2243*58283286Sha137994 "No packets\n", ldcp->id); 22441ae08745Sheppo break; 22451ae08745Sheppo } 22463af08d82Slm66018 2247*58283286Sha137994 D2(ldcp->id, "i_ldc_rx_process_hvq: head=0x%llx, " 2248*58283286Sha137994 "tail=0x%llx\n", rx_head, rx_tail); 2249*58283286Sha137994 DUMP_LDC_PKT(ldcp, "i_ldc_rx_process_hvq rcd", 22501ae08745Sheppo ldcp->rx_q_va + rx_head); 22511ae08745Sheppo 22521ae08745Sheppo /* get the message */ 22531ae08745Sheppo msg = (ldc_msg_t *)(ldcp->rx_q_va + rx_head); 22541ae08745Sheppo 22551ae08745Sheppo /* if channel is in RAW mode or data pkt, notify and return */ 22561ae08745Sheppo if (ldcp->mode == LDC_MODE_RAW) { 2257*58283286Sha137994 *notify_client = B_TRUE; 2258*58283286Sha137994 *notify_event |= LDC_EVT_READ; 22591ae08745Sheppo break; 22601ae08745Sheppo } 22611ae08745Sheppo 22621ae08745Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) { 22631ae08745Sheppo 22641ae08745Sheppo /* discard packet if channel is not up */ 22653af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) != TS_UP) { 22661ae08745Sheppo 22671ae08745Sheppo /* move the head one position */ 22681ae08745Sheppo rx_head = (rx_head + LDC_PACKET_SIZE) % 22691ae08745Sheppo (ldcp->rx_q_entries << LDC_PACKET_SHIFT); 22701ae08745Sheppo 22711ae08745Sheppo if (rv = i_ldc_set_rx_head(ldcp, rx_head)) 22721ae08745Sheppo break; 22731ae08745Sheppo 22741ae08745Sheppo continue; 22751ae08745Sheppo } else { 2276*58283286Sha137994 uint64_t dq_head, dq_tail; 2277*58283286Sha137994 2278*58283286Sha137994 /* process only STREAM mode data packets */ 2279*58283286Sha137994 if (ldcp->mode != LDC_MODE_STREAM) { 22803af08d82Slm66018 if ((ldcp->tstate & TS_IN_RESET) == 0) 2281*58283286Sha137994 *notify_client = B_TRUE; 2282*58283286Sha137994 *notify_event |= LDC_EVT_READ; 22831ae08745Sheppo break; 22841ae08745Sheppo } 2285*58283286Sha137994 2286*58283286Sha137994 /* don't process packet if queue full */ 2287*58283286Sha137994 (void) i_ldc_dq_rx_get_state(ldcp, &dq_head, 2288*58283286Sha137994 &dq_tail, NULL); 2289*58283286Sha137994 dq_tail = (dq_tail + LDC_PACKET_SIZE) % 2290*58283286Sha137994 (ldcp->rx_dq_entries << LDC_PACKET_SHIFT); 2291*58283286Sha137994 if (dq_tail == dq_head || 2292*58283286Sha137994 LDC_INJECT_DQFULL(ldcp)) { 2293*58283286Sha137994 rv = ENOSPC; 2294*58283286Sha137994 break; 2295*58283286Sha137994 } 2296*58283286Sha137994 } 22971ae08745Sheppo } 22981ae08745Sheppo 22991ae08745Sheppo /* Check the sequence ID for the message received */ 23003af08d82Slm66018 rv = i_ldc_check_seqid(ldcp, msg); 23013af08d82Slm66018 if (rv != 0) { 23021ae08745Sheppo 2303*58283286Sha137994 DWARN(ldcp->id, "i_ldc_rx_process_hvq: (0x%llx) " 2304*58283286Sha137994 "seqid error, q_ptrs=0x%lx,0x%lx", ldcp->id, 2305*58283286Sha137994 rx_head, rx_tail); 23061ae08745Sheppo 23071ae08745Sheppo /* Reset last_msg_rcd to start of message */ 2308d10e4ef2Snarayan if (first_fragment != 0) { 2309d10e4ef2Snarayan ldcp->last_msg_rcd = first_fragment - 1; 2310d10e4ef2Snarayan first_fragment = 0; 23111ae08745Sheppo } 2312d10e4ef2Snarayan 23131ae08745Sheppo /* 23141ae08745Sheppo * Send a NACK due to seqid mismatch 23151ae08745Sheppo */ 231622f747efSnarayan rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK, 23171ae08745Sheppo (msg->ctrl & LDC_CTRL_MASK)); 23181ae08745Sheppo 23191ae08745Sheppo if (rv) { 2320*58283286Sha137994 cmn_err(CE_NOTE, "i_ldc_rx_process_hvq: " 2321*58283286Sha137994 "(0x%lx) err sending CTRL/DATA NACK msg\n", 2322*58283286Sha137994 ldcp->id); 2323d10e4ef2Snarayan 2324d10e4ef2Snarayan /* if cannot send NACK - reset channel */ 2325d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 23263af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 2327d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 232883d3bc6fSnarayan 2329*58283286Sha137994 *notify_client = B_TRUE; 2330*58283286Sha137994 *notify_event = LDC_EVT_RESET; 2331d10e4ef2Snarayan break; 23321ae08745Sheppo } 23331ae08745Sheppo 23341ae08745Sheppo /* purge receive queue */ 23351ae08745Sheppo (void) i_ldc_set_rx_head(ldcp, rx_tail); 23361ae08745Sheppo break; 23371ae08745Sheppo } 23381ae08745Sheppo 23391ae08745Sheppo /* record the message ID */ 23401ae08745Sheppo ldcp->last_msg_rcd = msg->seqid; 23411ae08745Sheppo 23421ae08745Sheppo /* process control messages */ 23431ae08745Sheppo if (msg->type & LDC_CTRL) { 23441ae08745Sheppo /* save current internal state */ 23451ae08745Sheppo uint64_t tstate = ldcp->tstate; 23461ae08745Sheppo 23471ae08745Sheppo rv = i_ldc_ctrlmsg(ldcp, msg); 23481ae08745Sheppo if (rv == EAGAIN) { 23491ae08745Sheppo /* re-process pkt - state was adjusted */ 23501ae08745Sheppo continue; 23511ae08745Sheppo } 23521ae08745Sheppo if (rv == ECONNRESET) { 2353*58283286Sha137994 *notify_client = B_TRUE; 2354*58283286Sha137994 *notify_event = LDC_EVT_RESET; 23551ae08745Sheppo break; 23561ae08745Sheppo } 23571ae08745Sheppo 23581ae08745Sheppo /* 23591ae08745Sheppo * control message processing was successful 23601ae08745Sheppo * channel transitioned to ready for communication 23611ae08745Sheppo */ 23621ae08745Sheppo if (rv == 0 && ldcp->tstate == TS_UP && 23633af08d82Slm66018 (tstate & ~TS_IN_RESET) != 23643af08d82Slm66018 (ldcp->tstate & ~TS_IN_RESET)) { 2365*58283286Sha137994 *notify_client = B_TRUE; 2366*58283286Sha137994 *notify_event = LDC_EVT_UP; 23671ae08745Sheppo } 23681ae08745Sheppo } 23691ae08745Sheppo 237083d3bc6fSnarayan /* process data NACKs */ 237183d3bc6fSnarayan if ((msg->type & LDC_DATA) && (msg->stype & LDC_NACK)) { 237283d3bc6fSnarayan DWARN(ldcp->id, 2373*58283286Sha137994 "i_ldc_rx_process_hvq: (0x%llx) received DATA/NACK", 237483d3bc6fSnarayan ldcp->id); 237583d3bc6fSnarayan mutex_enter(&ldcp->tx_lock); 237683d3bc6fSnarayan i_ldc_reset(ldcp, B_TRUE); 237783d3bc6fSnarayan mutex_exit(&ldcp->tx_lock); 2378*58283286Sha137994 *notify_client = B_TRUE; 2379*58283286Sha137994 *notify_event = LDC_EVT_RESET; 238083d3bc6fSnarayan break; 238183d3bc6fSnarayan } 238283d3bc6fSnarayan 23831ae08745Sheppo /* process data ACKs */ 23841ae08745Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) { 2385d10e4ef2Snarayan if (rv = i_ldc_process_data_ACK(ldcp, msg)) { 2386*58283286Sha137994 *notify_client = B_TRUE; 2387*58283286Sha137994 *notify_event = LDC_EVT_RESET; 2388d10e4ef2Snarayan break; 2389d10e4ef2Snarayan } 23901ae08745Sheppo } 23911ae08745Sheppo 2392*58283286Sha137994 if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) { 2393*58283286Sha137994 ASSERT(ldcp->mode == LDC_MODE_STREAM); 2394*58283286Sha137994 2395*58283286Sha137994 /* 2396*58283286Sha137994 * Copy the data packet to the data queue. Note 2397*58283286Sha137994 * that the copy routine updates the rx_head pointer. 2398*58283286Sha137994 */ 2399*58283286Sha137994 i_ldc_rxdq_copy(ldcp, &rx_head); 2400*58283286Sha137994 2401*58283286Sha137994 if ((ldcp->tstate & TS_IN_RESET) == 0) 2402*58283286Sha137994 *notify_client = B_TRUE; 2403*58283286Sha137994 *notify_event |= LDC_EVT_READ; 2404*58283286Sha137994 } else { 24051ae08745Sheppo rx_head = (rx_head + LDC_PACKET_SIZE) % 24061ae08745Sheppo (ldcp->rx_q_entries << LDC_PACKET_SHIFT); 2407*58283286Sha137994 } 2408*58283286Sha137994 2409*58283286Sha137994 /* move the head one position */ 24100a55fbb7Slm66018 if (rv = i_ldc_set_rx_head(ldcp, rx_head)) { 2411*58283286Sha137994 *notify_client = B_TRUE; 2412*58283286Sha137994 *notify_event = LDC_EVT_RESET; 24131ae08745Sheppo break; 24140a55fbb7Slm66018 } 24151ae08745Sheppo 24161ae08745Sheppo } /* for */ 24171ae08745Sheppo 24183af08d82Slm66018 loop_exit: 24193af08d82Slm66018 2420*58283286Sha137994 if (ldcp->mode == LDC_MODE_STREAM) { 2421*58283286Sha137994 /* ACK data packets */ 2422*58283286Sha137994 if ((*notify_event & 2423*58283286Sha137994 (LDC_EVT_READ | LDC_EVT_RESET)) == LDC_EVT_READ) { 2424*58283286Sha137994 int ack_rv; 2425*58283286Sha137994 ack_rv = i_ldc_send_pkt(ldcp, LDC_DATA, LDC_ACK, 0); 2426*58283286Sha137994 if (ack_rv && ack_rv != EWOULDBLOCK) { 2427*58283286Sha137994 cmn_err(CE_NOTE, 2428*58283286Sha137994 "i_ldc_rx_process_hvq: (0x%lx) cannot " 2429*58283286Sha137994 "send ACK\n", ldcp->id); 2430*58283286Sha137994 2431*58283286Sha137994 mutex_enter(&ldcp->tx_lock); 2432*58283286Sha137994 i_ldc_reset(ldcp, B_FALSE); 2433*58283286Sha137994 mutex_exit(&ldcp->tx_lock); 2434*58283286Sha137994 2435*58283286Sha137994 *notify_client = B_TRUE; 2436*58283286Sha137994 *notify_event = LDC_EVT_RESET; 2437*58283286Sha137994 goto skip_ackpeek; 2438*58283286Sha137994 } 2439*58283286Sha137994 } 24401ae08745Sheppo 24413af08d82Slm66018 /* 2442*58283286Sha137994 * If we have no more space on the data queue, make sure 2443*58283286Sha137994 * there are no ACKs on the rx queue waiting to be processed. 24443af08d82Slm66018 */ 2445*58283286Sha137994 if (rv == ENOSPC) { 2446*58283286Sha137994 if (i_ldc_rx_ackpeek(ldcp, rx_head, rx_tail) != 0) { 2447*58283286Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID; 2448*58283286Sha137994 *notify_client = B_TRUE; 2449*58283286Sha137994 *notify_event = LDC_EVT_RESET; 24501ae08745Sheppo } 2451*58283286Sha137994 } else { 2452*58283286Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID; 2453*58283286Sha137994 } 24541ae08745Sheppo } 24551ae08745Sheppo 2456*58283286Sha137994 skip_ackpeek: 24574d39be2bSsg70180 2458*58283286Sha137994 /* Return, indicating whether or not data packets were found */ 2459*58283286Sha137994 if ((*notify_event & (LDC_EVT_READ | LDC_EVT_RESET)) == LDC_EVT_READ) 2460*58283286Sha137994 return (0); 2461*58283286Sha137994 2462*58283286Sha137994 return (ENOMSG); 24631ae08745Sheppo } 24641ae08745Sheppo 2465*58283286Sha137994 /* 2466*58283286Sha137994 * Process any ACK packets on the HV receive queue. 2467*58283286Sha137994 * 2468*58283286Sha137994 * This function is only used by STREAMING mode channels when the 2469*58283286Sha137994 * secondary data queue fills up and there are packets remaining on 2470*58283286Sha137994 * the HV receive queue. 2471*58283286Sha137994 */ 2472*58283286Sha137994 int 2473*58283286Sha137994 i_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head, uint64_t rx_tail) 2474*58283286Sha137994 { 2475*58283286Sha137994 int rv = 0; 2476*58283286Sha137994 ldc_msg_t *msg; 2477*58283286Sha137994 2478*58283286Sha137994 if (ldcp->rx_ack_head == ACKPEEK_HEAD_INVALID) 2479*58283286Sha137994 ldcp->rx_ack_head = rx_head; 2480*58283286Sha137994 2481*58283286Sha137994 while (ldcp->rx_ack_head != rx_tail) { 2482*58283286Sha137994 msg = (ldc_msg_t *)(ldcp->rx_q_va + ldcp->rx_ack_head); 2483*58283286Sha137994 2484*58283286Sha137994 if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) { 2485*58283286Sha137994 if (rv = i_ldc_process_data_ACK(ldcp, msg)) 2486*58283286Sha137994 break; 2487*58283286Sha137994 msg->stype &= ~LDC_ACK; 2488*58283286Sha137994 } 2489*58283286Sha137994 2490*58283286Sha137994 ldcp->rx_ack_head = 2491*58283286Sha137994 (ldcp->rx_ack_head + LDC_PACKET_SIZE) % 2492*58283286Sha137994 (ldcp->rx_q_entries << LDC_PACKET_SHIFT); 2493*58283286Sha137994 } 2494*58283286Sha137994 return (rv); 2495*58283286Sha137994 } 24961ae08745Sheppo 24971ae08745Sheppo /* -------------------------------------------------------------------------- */ 24981ae08745Sheppo 24991ae08745Sheppo /* 25001ae08745Sheppo * LDC API functions 25011ae08745Sheppo */ 25021ae08745Sheppo 25031ae08745Sheppo /* 25041ae08745Sheppo * Initialize the channel. Allocate internal structure and memory for 25051ae08745Sheppo * TX/RX queues, and initialize locks. 25061ae08745Sheppo */ 25071ae08745Sheppo int 25081ae08745Sheppo ldc_init(uint64_t id, ldc_attr_t *attr, ldc_handle_t *handle) 25091ae08745Sheppo { 25101ae08745Sheppo ldc_chan_t *ldcp; 25111ae08745Sheppo int rv, exit_val; 25121ae08745Sheppo uint64_t ra_base, nentries; 2513e1ebb9ecSlm66018 uint64_t qlen; 25141ae08745Sheppo 25151ae08745Sheppo exit_val = EINVAL; /* guarantee an error if exit on failure */ 25161ae08745Sheppo 25171ae08745Sheppo if (attr == NULL) { 25181ae08745Sheppo DWARN(id, "ldc_init: (0x%llx) invalid attr\n", id); 25191ae08745Sheppo return (EINVAL); 25201ae08745Sheppo } 25211ae08745Sheppo if (handle == NULL) { 25221ae08745Sheppo DWARN(id, "ldc_init: (0x%llx) invalid handle\n", id); 25231ae08745Sheppo return (EINVAL); 25241ae08745Sheppo } 25251ae08745Sheppo 25261ae08745Sheppo /* check if channel is valid */ 25271ae08745Sheppo rv = hv_ldc_tx_qinfo(id, &ra_base, &nentries); 25281ae08745Sheppo if (rv == H_ECHANNEL) { 25291ae08745Sheppo DWARN(id, "ldc_init: (0x%llx) invalid channel id\n", id); 25301ae08745Sheppo return (EINVAL); 25311ae08745Sheppo } 25321ae08745Sheppo 25331ae08745Sheppo /* check if the channel has already been initialized */ 25341ae08745Sheppo mutex_enter(&ldcssp->lock); 25351ae08745Sheppo ldcp = ldcssp->chan_list; 25361ae08745Sheppo while (ldcp != NULL) { 25371ae08745Sheppo if (ldcp->id == id) { 25381ae08745Sheppo DWARN(id, "ldc_init: (0x%llx) already initialized\n", 25391ae08745Sheppo id); 25401ae08745Sheppo mutex_exit(&ldcssp->lock); 25411ae08745Sheppo return (EADDRINUSE); 25421ae08745Sheppo } 25431ae08745Sheppo ldcp = ldcp->next; 25441ae08745Sheppo } 25451ae08745Sheppo mutex_exit(&ldcssp->lock); 25461ae08745Sheppo 25471ae08745Sheppo ASSERT(ldcp == NULL); 25481ae08745Sheppo 25491ae08745Sheppo *handle = 0; 25501ae08745Sheppo 25511ae08745Sheppo /* Allocate an ldcp structure */ 25521ae08745Sheppo ldcp = kmem_zalloc(sizeof (ldc_chan_t), KM_SLEEP); 25531ae08745Sheppo 2554d10e4ef2Snarayan /* 2555d10e4ef2Snarayan * Initialize the channel and Tx lock 2556d10e4ef2Snarayan * 2557d10e4ef2Snarayan * The channel 'lock' protects the entire channel and 2558d10e4ef2Snarayan * should be acquired before initializing, resetting, 2559d10e4ef2Snarayan * destroying or reading from a channel. 2560d10e4ef2Snarayan * 2561d10e4ef2Snarayan * The 'tx_lock' should be acquired prior to transmitting 2562d10e4ef2Snarayan * data over the channel. The lock should also be acquired 2563d10e4ef2Snarayan * prior to channel reconfiguration (in order to prevent 2564d10e4ef2Snarayan * concurrent writes). 2565d10e4ef2Snarayan * 2566d10e4ef2Snarayan * ORDERING: When both locks are being acquired, to prevent 2567d10e4ef2Snarayan * deadlocks, the channel lock should be always acquired prior 2568d10e4ef2Snarayan * to the tx_lock. 2569d10e4ef2Snarayan */ 25701ae08745Sheppo mutex_init(&ldcp->lock, NULL, MUTEX_DRIVER, NULL); 2571d10e4ef2Snarayan mutex_init(&ldcp->tx_lock, NULL, MUTEX_DRIVER, NULL); 25721ae08745Sheppo 25731ae08745Sheppo /* Initialize the channel */ 25741ae08745Sheppo ldcp->id = id; 25751ae08745Sheppo ldcp->cb = NULL; 25761ae08745Sheppo ldcp->cb_arg = NULL; 25771ae08745Sheppo ldcp->cb_inprogress = B_FALSE; 25781ae08745Sheppo ldcp->cb_enabled = B_FALSE; 25791ae08745Sheppo ldcp->next = NULL; 25801ae08745Sheppo 25811ae08745Sheppo /* Read attributes */ 25821ae08745Sheppo ldcp->mode = attr->mode; 25831ae08745Sheppo ldcp->devclass = attr->devclass; 25841ae08745Sheppo ldcp->devinst = attr->instance; 2585e1ebb9ecSlm66018 ldcp->mtu = (attr->mtu > 0) ? attr->mtu : LDC_DEFAULT_MTU; 25861ae08745Sheppo 25871ae08745Sheppo D1(ldcp->id, 25881ae08745Sheppo "ldc_init: (0x%llx) channel attributes, class=0x%x, " 2589e1ebb9ecSlm66018 "instance=0x%llx, mode=%d, mtu=%d\n", 2590e1ebb9ecSlm66018 ldcp->id, ldcp->devclass, ldcp->devinst, ldcp->mode, ldcp->mtu); 25911ae08745Sheppo 25921ae08745Sheppo ldcp->next_vidx = 0; 25933af08d82Slm66018 ldcp->tstate = TS_IN_RESET; 25941ae08745Sheppo ldcp->hstate = 0; 25951ae08745Sheppo ldcp->last_msg_snt = LDC_INIT_SEQID; 25961ae08745Sheppo ldcp->last_ack_rcd = 0; 25971ae08745Sheppo ldcp->last_msg_rcd = 0; 2598*58283286Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID; 25991ae08745Sheppo 26001ae08745Sheppo ldcp->stream_bufferp = NULL; 26011ae08745Sheppo ldcp->exp_dring_list = NULL; 26021ae08745Sheppo ldcp->imp_dring_list = NULL; 26031ae08745Sheppo ldcp->mhdl_list = NULL; 26041ae08745Sheppo 26053af08d82Slm66018 ldcp->tx_intr_state = LDC_INTR_NONE; 26063af08d82Slm66018 ldcp->rx_intr_state = LDC_INTR_NONE; 26073af08d82Slm66018 26081ae08745Sheppo /* Initialize payload size depending on whether channel is reliable */ 26091ae08745Sheppo switch (ldcp->mode) { 26101ae08745Sheppo case LDC_MODE_RAW: 26111ae08745Sheppo ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RAW; 26121ae08745Sheppo ldcp->read_p = i_ldc_read_raw; 26131ae08745Sheppo ldcp->write_p = i_ldc_write_raw; 26141ae08745Sheppo break; 26151ae08745Sheppo case LDC_MODE_UNRELIABLE: 26161ae08745Sheppo ldcp->pkt_payload = LDC_PAYLOAD_SIZE_UNRELIABLE; 26171ae08745Sheppo ldcp->read_p = i_ldc_read_packet; 26181ae08745Sheppo ldcp->write_p = i_ldc_write_packet; 26191ae08745Sheppo break; 26201ae08745Sheppo case LDC_MODE_RELIABLE: 26211ae08745Sheppo ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RELIABLE; 26221ae08745Sheppo ldcp->read_p = i_ldc_read_packet; 26231ae08745Sheppo ldcp->write_p = i_ldc_write_packet; 26241ae08745Sheppo break; 26251ae08745Sheppo case LDC_MODE_STREAM: 26261ae08745Sheppo ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RELIABLE; 26271ae08745Sheppo 26281ae08745Sheppo ldcp->stream_remains = 0; 26291ae08745Sheppo ldcp->stream_offset = 0; 26301ae08745Sheppo ldcp->stream_bufferp = kmem_alloc(ldcp->mtu, KM_SLEEP); 26311ae08745Sheppo ldcp->read_p = i_ldc_read_stream; 26321ae08745Sheppo ldcp->write_p = i_ldc_write_stream; 26331ae08745Sheppo break; 26341ae08745Sheppo default: 26351ae08745Sheppo exit_val = EINVAL; 26361ae08745Sheppo goto cleanup_on_exit; 26371ae08745Sheppo } 26381ae08745Sheppo 2639e1ebb9ecSlm66018 /* 2640e1ebb9ecSlm66018 * qlen is (mtu * ldc_mtu_msgs) / pkt_payload. If this 2641e1ebb9ecSlm66018 * value is smaller than default length of ldc_queue_entries, 264222f747efSnarayan * qlen is set to ldc_queue_entries. Ensure that computed 264322f747efSnarayan * length is a power-of-two value. 2644e1ebb9ecSlm66018 */ 2645e1ebb9ecSlm66018 qlen = (ldcp->mtu * ldc_mtu_msgs) / ldcp->pkt_payload; 264622f747efSnarayan if (!ISP2(qlen)) { 264722f747efSnarayan uint64_t tmp = 1; 264822f747efSnarayan while (qlen) { 264922f747efSnarayan qlen >>= 1; tmp <<= 1; 265022f747efSnarayan } 265122f747efSnarayan qlen = tmp; 265222f747efSnarayan } 265322f747efSnarayan 2654e1ebb9ecSlm66018 ldcp->rx_q_entries = 2655e1ebb9ecSlm66018 (qlen < ldc_queue_entries) ? ldc_queue_entries : qlen; 2656e1ebb9ecSlm66018 ldcp->tx_q_entries = ldcp->rx_q_entries; 2657e1ebb9ecSlm66018 265822f747efSnarayan D1(ldcp->id, "ldc_init: queue length = 0x%llx\n", ldcp->rx_q_entries); 2659e1ebb9ecSlm66018 26601ae08745Sheppo /* Create a transmit queue */ 26611ae08745Sheppo ldcp->tx_q_va = (uint64_t) 26621ae08745Sheppo contig_mem_alloc(ldcp->tx_q_entries << LDC_PACKET_SHIFT); 26631ae08745Sheppo if (ldcp->tx_q_va == NULL) { 26641ae08745Sheppo cmn_err(CE_WARN, 26651ae08745Sheppo "ldc_init: (0x%lx) TX queue allocation failed\n", 26661ae08745Sheppo ldcp->id); 26671ae08745Sheppo exit_val = ENOMEM; 26681ae08745Sheppo goto cleanup_on_exit; 26691ae08745Sheppo } 26701ae08745Sheppo ldcp->tx_q_ra = va_to_pa((caddr_t)ldcp->tx_q_va); 26711ae08745Sheppo 26721ae08745Sheppo D2(ldcp->id, "ldc_init: txq_va=0x%llx, txq_ra=0x%llx, entries=0x%llx\n", 26731ae08745Sheppo ldcp->tx_q_va, ldcp->tx_q_ra, ldcp->tx_q_entries); 26741ae08745Sheppo 26751ae08745Sheppo ldcp->tstate |= TS_TXQ_RDY; 26761ae08745Sheppo 26771ae08745Sheppo /* Create a receive queue */ 26781ae08745Sheppo ldcp->rx_q_va = (uint64_t) 26791ae08745Sheppo contig_mem_alloc(ldcp->rx_q_entries << LDC_PACKET_SHIFT); 26801ae08745Sheppo if (ldcp->rx_q_va == NULL) { 26811ae08745Sheppo cmn_err(CE_WARN, 26821ae08745Sheppo "ldc_init: (0x%lx) RX queue allocation failed\n", 26831ae08745Sheppo ldcp->id); 26841ae08745Sheppo exit_val = ENOMEM; 26851ae08745Sheppo goto cleanup_on_exit; 26861ae08745Sheppo } 26871ae08745Sheppo ldcp->rx_q_ra = va_to_pa((caddr_t)ldcp->rx_q_va); 26881ae08745Sheppo 26891ae08745Sheppo D2(ldcp->id, "ldc_init: rxq_va=0x%llx, rxq_ra=0x%llx, entries=0x%llx\n", 26901ae08745Sheppo ldcp->rx_q_va, ldcp->rx_q_ra, ldcp->rx_q_entries); 26911ae08745Sheppo 26921ae08745Sheppo ldcp->tstate |= TS_RXQ_RDY; 26931ae08745Sheppo 2694*58283286Sha137994 /* Setup a separate read data queue */ 2695*58283286Sha137994 if (ldcp->mode == LDC_MODE_STREAM) { 2696*58283286Sha137994 ldcp->readq_get_state = i_ldc_dq_rx_get_state; 2697*58283286Sha137994 ldcp->readq_set_head = i_ldc_set_rxdq_head; 2698*58283286Sha137994 2699*58283286Sha137994 /* Make sure the data queue multiplier is a power of 2 */ 2700*58283286Sha137994 if (!ISP2(ldc_rxdq_multiplier)) { 2701*58283286Sha137994 D1(ldcp->id, "ldc_init: (0x%llx) ldc_rxdq_multiplier " 2702*58283286Sha137994 "not a power of 2, resetting", ldcp->id); 2703*58283286Sha137994 ldc_rxdq_multiplier = LDC_RXDQ_MULTIPLIER; 2704*58283286Sha137994 } 2705*58283286Sha137994 2706*58283286Sha137994 ldcp->rx_dq_entries = ldc_rxdq_multiplier * ldcp->rx_q_entries; 2707*58283286Sha137994 ldcp->rx_dq_va = (uint64_t) 2708*58283286Sha137994 kmem_alloc(ldcp->rx_dq_entries << LDC_PACKET_SHIFT, 2709*58283286Sha137994 KM_SLEEP); 2710*58283286Sha137994 if (ldcp->rx_dq_va == NULL) { 2711*58283286Sha137994 cmn_err(CE_WARN, 2712*58283286Sha137994 "ldc_init: (0x%lx) RX data queue " 2713*58283286Sha137994 "allocation failed\n", ldcp->id); 2714*58283286Sha137994 exit_val = ENOMEM; 2715*58283286Sha137994 goto cleanup_on_exit; 2716*58283286Sha137994 } 2717*58283286Sha137994 2718*58283286Sha137994 ldcp->rx_dq_head = ldcp->rx_dq_tail = 0; 2719*58283286Sha137994 2720*58283286Sha137994 D2(ldcp->id, "ldc_init: rx_dq_va=0x%llx, " 2721*58283286Sha137994 "rx_dq_entries=0x%llx\n", ldcp->rx_dq_va, 2722*58283286Sha137994 ldcp->rx_dq_entries); 2723*58283286Sha137994 } else { 2724*58283286Sha137994 ldcp->readq_get_state = i_ldc_hvq_rx_get_state; 2725*58283286Sha137994 ldcp->readq_set_head = i_ldc_set_rx_head; 2726*58283286Sha137994 } 2727*58283286Sha137994 27281ae08745Sheppo /* Init descriptor ring and memory handle list lock */ 27291ae08745Sheppo mutex_init(&ldcp->exp_dlist_lock, NULL, MUTEX_DRIVER, NULL); 27301ae08745Sheppo mutex_init(&ldcp->imp_dlist_lock, NULL, MUTEX_DRIVER, NULL); 27311ae08745Sheppo mutex_init(&ldcp->mlist_lock, NULL, MUTEX_DRIVER, NULL); 27321ae08745Sheppo 27331ae08745Sheppo /* mark status as INITialized */ 27341ae08745Sheppo ldcp->status = LDC_INIT; 27351ae08745Sheppo 27361ae08745Sheppo /* Add to channel list */ 27371ae08745Sheppo mutex_enter(&ldcssp->lock); 27381ae08745Sheppo ldcp->next = ldcssp->chan_list; 27391ae08745Sheppo ldcssp->chan_list = ldcp; 27401ae08745Sheppo ldcssp->channel_count++; 27411ae08745Sheppo mutex_exit(&ldcssp->lock); 27421ae08745Sheppo 27431ae08745Sheppo /* set the handle */ 27441ae08745Sheppo *handle = (ldc_handle_t)ldcp; 27451ae08745Sheppo 27461ae08745Sheppo D1(ldcp->id, "ldc_init: (0x%llx) channel initialized\n", ldcp->id); 27471ae08745Sheppo 27481ae08745Sheppo return (0); 27491ae08745Sheppo 27501ae08745Sheppo cleanup_on_exit: 27511ae08745Sheppo 27521ae08745Sheppo if (ldcp->mode == LDC_MODE_STREAM && ldcp->stream_bufferp) 27531ae08745Sheppo kmem_free(ldcp->stream_bufferp, ldcp->mtu); 27541ae08745Sheppo 27551ae08745Sheppo if (ldcp->tstate & TS_TXQ_RDY) 27561ae08745Sheppo contig_mem_free((caddr_t)ldcp->tx_q_va, 27571ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT)); 27581ae08745Sheppo 27591ae08745Sheppo if (ldcp->tstate & TS_RXQ_RDY) 27601ae08745Sheppo contig_mem_free((caddr_t)ldcp->rx_q_va, 27611ae08745Sheppo (ldcp->rx_q_entries << LDC_PACKET_SHIFT)); 27621ae08745Sheppo 2763d10e4ef2Snarayan mutex_destroy(&ldcp->tx_lock); 27641ae08745Sheppo mutex_destroy(&ldcp->lock); 27651ae08745Sheppo 27661ae08745Sheppo if (ldcp) 27671ae08745Sheppo kmem_free(ldcp, sizeof (ldc_chan_t)); 27681ae08745Sheppo 27691ae08745Sheppo return (exit_val); 27701ae08745Sheppo } 27711ae08745Sheppo 27721ae08745Sheppo /* 27731ae08745Sheppo * Finalizes the LDC connection. It will return EBUSY if the 27741ae08745Sheppo * channel is open. A ldc_close() has to be done prior to 27751ae08745Sheppo * a ldc_fini operation. It frees TX/RX queues, associated 27761ae08745Sheppo * with the channel 27771ae08745Sheppo */ 27781ae08745Sheppo int 27791ae08745Sheppo ldc_fini(ldc_handle_t handle) 27801ae08745Sheppo { 27811ae08745Sheppo ldc_chan_t *ldcp; 27821ae08745Sheppo ldc_chan_t *tmp_ldcp; 27831ae08745Sheppo uint64_t id; 27841ae08745Sheppo 27851ae08745Sheppo if (handle == NULL) { 27861ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel handle\n"); 27871ae08745Sheppo return (EINVAL); 27881ae08745Sheppo } 27891ae08745Sheppo ldcp = (ldc_chan_t *)handle; 27901ae08745Sheppo id = ldcp->id; 27911ae08745Sheppo 27921ae08745Sheppo mutex_enter(&ldcp->lock); 27931ae08745Sheppo 27943af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) > TS_INIT) { 27951ae08745Sheppo DWARN(ldcp->id, "ldc_fini: (0x%llx) channel is open\n", 27961ae08745Sheppo ldcp->id); 27971ae08745Sheppo mutex_exit(&ldcp->lock); 27981ae08745Sheppo return (EBUSY); 27991ae08745Sheppo } 28001ae08745Sheppo 28011ae08745Sheppo /* Remove from the channel list */ 28021ae08745Sheppo mutex_enter(&ldcssp->lock); 28031ae08745Sheppo tmp_ldcp = ldcssp->chan_list; 28041ae08745Sheppo if (tmp_ldcp == ldcp) { 28051ae08745Sheppo ldcssp->chan_list = ldcp->next; 28061ae08745Sheppo ldcp->next = NULL; 28071ae08745Sheppo } else { 28081ae08745Sheppo while (tmp_ldcp != NULL) { 28091ae08745Sheppo if (tmp_ldcp->next == ldcp) { 28101ae08745Sheppo tmp_ldcp->next = ldcp->next; 28111ae08745Sheppo ldcp->next = NULL; 28121ae08745Sheppo break; 28131ae08745Sheppo } 28141ae08745Sheppo tmp_ldcp = tmp_ldcp->next; 28151ae08745Sheppo } 28161ae08745Sheppo if (tmp_ldcp == NULL) { 28171ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel hdl\n"); 28181ae08745Sheppo mutex_exit(&ldcssp->lock); 28191ae08745Sheppo mutex_exit(&ldcp->lock); 28201ae08745Sheppo return (EINVAL); 28211ae08745Sheppo } 28221ae08745Sheppo } 28231ae08745Sheppo 28241ae08745Sheppo ldcssp->channel_count--; 28251ae08745Sheppo 28261ae08745Sheppo mutex_exit(&ldcssp->lock); 28271ae08745Sheppo 28281ae08745Sheppo /* Free the map table for this channel */ 28291ae08745Sheppo if (ldcp->mtbl) { 28301ae08745Sheppo (void) hv_ldc_set_map_table(ldcp->id, NULL, NULL); 28313af08d82Slm66018 if (ldcp->mtbl->contigmem) 28321ae08745Sheppo contig_mem_free(ldcp->mtbl->table, ldcp->mtbl->size); 28333af08d82Slm66018 else 28343af08d82Slm66018 kmem_free(ldcp->mtbl->table, ldcp->mtbl->size); 28351ae08745Sheppo mutex_destroy(&ldcp->mtbl->lock); 28361ae08745Sheppo kmem_free(ldcp->mtbl, sizeof (ldc_mtbl_t)); 28371ae08745Sheppo } 28381ae08745Sheppo 28391ae08745Sheppo /* Destroy descriptor ring and memory handle list lock */ 28401ae08745Sheppo mutex_destroy(&ldcp->exp_dlist_lock); 28411ae08745Sheppo mutex_destroy(&ldcp->imp_dlist_lock); 28421ae08745Sheppo mutex_destroy(&ldcp->mlist_lock); 28431ae08745Sheppo 28441ae08745Sheppo /* Free the stream buffer for STREAM_MODE */ 28451ae08745Sheppo if (ldcp->mode == LDC_MODE_STREAM && ldcp->stream_bufferp) 28461ae08745Sheppo kmem_free(ldcp->stream_bufferp, ldcp->mtu); 28471ae08745Sheppo 28481ae08745Sheppo /* Free the RX queue */ 28491ae08745Sheppo contig_mem_free((caddr_t)ldcp->rx_q_va, 28501ae08745Sheppo (ldcp->rx_q_entries << LDC_PACKET_SHIFT)); 28511ae08745Sheppo ldcp->tstate &= ~TS_RXQ_RDY; 28521ae08745Sheppo 2853*58283286Sha137994 /* Free the RX data queue */ 2854*58283286Sha137994 if (ldcp->mode == LDC_MODE_STREAM) { 2855*58283286Sha137994 kmem_free((caddr_t)ldcp->rx_dq_va, 2856*58283286Sha137994 (ldcp->rx_dq_entries << LDC_PACKET_SHIFT)); 2857*58283286Sha137994 } 2858*58283286Sha137994 28591ae08745Sheppo /* Free the TX queue */ 28601ae08745Sheppo contig_mem_free((caddr_t)ldcp->tx_q_va, 28611ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT)); 28621ae08745Sheppo ldcp->tstate &= ~TS_TXQ_RDY; 28631ae08745Sheppo 28641ae08745Sheppo mutex_exit(&ldcp->lock); 28651ae08745Sheppo 28661ae08745Sheppo /* Destroy mutex */ 2867d10e4ef2Snarayan mutex_destroy(&ldcp->tx_lock); 28681ae08745Sheppo mutex_destroy(&ldcp->lock); 28691ae08745Sheppo 28701ae08745Sheppo /* free channel structure */ 28711ae08745Sheppo kmem_free(ldcp, sizeof (ldc_chan_t)); 28721ae08745Sheppo 28731ae08745Sheppo D1(id, "ldc_fini: (0x%llx) channel finalized\n", id); 28741ae08745Sheppo 28751ae08745Sheppo return (0); 28761ae08745Sheppo } 28771ae08745Sheppo 28781ae08745Sheppo /* 28791ae08745Sheppo * Open the LDC channel for use. It registers the TX/RX queues 28801ae08745Sheppo * with the Hypervisor. It also specifies the interrupt number 28811ae08745Sheppo * and target CPU for this channel 28821ae08745Sheppo */ 28831ae08745Sheppo int 28841ae08745Sheppo ldc_open(ldc_handle_t handle) 28851ae08745Sheppo { 28861ae08745Sheppo ldc_chan_t *ldcp; 28871ae08745Sheppo int rv; 28881ae08745Sheppo 28891ae08745Sheppo if (handle == NULL) { 28901ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_open: invalid channel handle\n"); 28911ae08745Sheppo return (EINVAL); 28921ae08745Sheppo } 28931ae08745Sheppo 28941ae08745Sheppo ldcp = (ldc_chan_t *)handle; 28951ae08745Sheppo 28961ae08745Sheppo mutex_enter(&ldcp->lock); 28971ae08745Sheppo 28981ae08745Sheppo if (ldcp->tstate < TS_INIT) { 28991ae08745Sheppo DWARN(ldcp->id, 29001ae08745Sheppo "ldc_open: (0x%llx) channel not initialized\n", ldcp->id); 29011ae08745Sheppo mutex_exit(&ldcp->lock); 29021ae08745Sheppo return (EFAULT); 29031ae08745Sheppo } 29043af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) >= TS_OPEN) { 29051ae08745Sheppo DWARN(ldcp->id, 29061ae08745Sheppo "ldc_open: (0x%llx) channel is already open\n", ldcp->id); 29071ae08745Sheppo mutex_exit(&ldcp->lock); 29081ae08745Sheppo return (EFAULT); 29091ae08745Sheppo } 29101ae08745Sheppo 29111ae08745Sheppo /* 29121ae08745Sheppo * Unregister/Register the tx queue with the hypervisor 29131ae08745Sheppo */ 29141ae08745Sheppo rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 29151ae08745Sheppo if (rv) { 29161ae08745Sheppo cmn_err(CE_WARN, 29171ae08745Sheppo "ldc_open: (0x%lx) channel tx queue unconf failed\n", 29181ae08745Sheppo ldcp->id); 29191ae08745Sheppo mutex_exit(&ldcp->lock); 29201ae08745Sheppo return (EIO); 29211ae08745Sheppo } 29221ae08745Sheppo 29231ae08745Sheppo rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries); 29241ae08745Sheppo if (rv) { 29251ae08745Sheppo cmn_err(CE_WARN, 29261ae08745Sheppo "ldc_open: (0x%lx) channel tx queue conf failed\n", 29271ae08745Sheppo ldcp->id); 29281ae08745Sheppo mutex_exit(&ldcp->lock); 29291ae08745Sheppo return (EIO); 29301ae08745Sheppo } 29311ae08745Sheppo 29321ae08745Sheppo D2(ldcp->id, "ldc_open: (0x%llx) registered tx queue with LDC\n", 29331ae08745Sheppo ldcp->id); 29341ae08745Sheppo 29351ae08745Sheppo /* 29361ae08745Sheppo * Unregister/Register the rx queue with the hypervisor 29371ae08745Sheppo */ 29381ae08745Sheppo rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 29391ae08745Sheppo if (rv) { 29401ae08745Sheppo cmn_err(CE_WARN, 29411ae08745Sheppo "ldc_open: (0x%lx) channel rx queue unconf failed\n", 29421ae08745Sheppo ldcp->id); 29431ae08745Sheppo mutex_exit(&ldcp->lock); 29441ae08745Sheppo return (EIO); 29451ae08745Sheppo } 29461ae08745Sheppo 29471ae08745Sheppo rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra, ldcp->rx_q_entries); 29481ae08745Sheppo if (rv) { 29491ae08745Sheppo cmn_err(CE_WARN, 29501ae08745Sheppo "ldc_open: (0x%lx) channel rx queue conf failed\n", 29511ae08745Sheppo ldcp->id); 29521ae08745Sheppo mutex_exit(&ldcp->lock); 29531ae08745Sheppo return (EIO); 29541ae08745Sheppo } 29551ae08745Sheppo 29561ae08745Sheppo D2(ldcp->id, "ldc_open: (0x%llx) registered rx queue with LDC\n", 29571ae08745Sheppo ldcp->id); 29581ae08745Sheppo 29591ae08745Sheppo ldcp->tstate |= TS_QCONF_RDY; 29601ae08745Sheppo 29611ae08745Sheppo /* Register the channel with the channel nexus */ 29621ae08745Sheppo rv = i_ldc_register_channel(ldcp); 29631ae08745Sheppo if (rv && rv != EAGAIN) { 29641ae08745Sheppo cmn_err(CE_WARN, 29651ae08745Sheppo "ldc_open: (0x%lx) channel register failed\n", ldcp->id); 29661ae08745Sheppo (void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 29671ae08745Sheppo (void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 29681ae08745Sheppo mutex_exit(&ldcp->lock); 29691ae08745Sheppo return (EIO); 29701ae08745Sheppo } 29711ae08745Sheppo 29721ae08745Sheppo /* mark channel in OPEN state */ 29731ae08745Sheppo ldcp->status = LDC_OPEN; 29741ae08745Sheppo 29751ae08745Sheppo /* Read channel state */ 29761ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 29771ae08745Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 29781ae08745Sheppo if (rv) { 29791ae08745Sheppo cmn_err(CE_WARN, 29801ae08745Sheppo "ldc_open: (0x%lx) cannot read channel state\n", 29811ae08745Sheppo ldcp->id); 29821ae08745Sheppo (void) i_ldc_unregister_channel(ldcp); 29831ae08745Sheppo (void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 29841ae08745Sheppo (void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 29851ae08745Sheppo mutex_exit(&ldcp->lock); 29861ae08745Sheppo return (EIO); 29871ae08745Sheppo } 29881ae08745Sheppo 29891ae08745Sheppo /* 29901ae08745Sheppo * set the ACKd head to current head location for reliable & 29911ae08745Sheppo * streaming mode 29921ae08745Sheppo */ 29931ae08745Sheppo ldcp->tx_ackd_head = ldcp->tx_head; 29941ae08745Sheppo 29951ae08745Sheppo /* mark channel ready if HV report link is UP (peer alloc'd Rx queue) */ 29961ae08745Sheppo if (ldcp->link_state == LDC_CHANNEL_UP || 29971ae08745Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 29981ae08745Sheppo ldcp->tstate |= TS_LINK_READY; 29991ae08745Sheppo ldcp->status = LDC_READY; 30001ae08745Sheppo } 30011ae08745Sheppo 30021ae08745Sheppo /* 30031ae08745Sheppo * if channel is being opened in RAW mode - no handshake is needed 30041ae08745Sheppo * switch the channel READY and UP state 30051ae08745Sheppo */ 30061ae08745Sheppo if (ldcp->mode == LDC_MODE_RAW) { 30071ae08745Sheppo ldcp->tstate = TS_UP; /* set bits associated with LDC UP */ 30081ae08745Sheppo ldcp->status = LDC_UP; 30091ae08745Sheppo } 30101ae08745Sheppo 30111ae08745Sheppo mutex_exit(&ldcp->lock); 30121ae08745Sheppo 30131ae08745Sheppo /* 30141ae08745Sheppo * Increment number of open channels 30151ae08745Sheppo */ 30161ae08745Sheppo mutex_enter(&ldcssp->lock); 30171ae08745Sheppo ldcssp->channels_open++; 30181ae08745Sheppo mutex_exit(&ldcssp->lock); 30191ae08745Sheppo 3020cb112a14Slm66018 D1(ldcp->id, 30213af08d82Slm66018 "ldc_open: (0x%llx) channel (0x%p) open for use " 30223af08d82Slm66018 "(tstate=0x%x, status=0x%x)\n", 30233af08d82Slm66018 ldcp->id, ldcp, ldcp->tstate, ldcp->status); 30241ae08745Sheppo 30251ae08745Sheppo return (0); 30261ae08745Sheppo } 30271ae08745Sheppo 30281ae08745Sheppo /* 30291ae08745Sheppo * Close the LDC connection. It will return EBUSY if there 30301ae08745Sheppo * are memory segments or descriptor rings either bound to or 30311ae08745Sheppo * mapped over the channel 30321ae08745Sheppo */ 30331ae08745Sheppo int 30341ae08745Sheppo ldc_close(ldc_handle_t handle) 30351ae08745Sheppo { 30361ae08745Sheppo ldc_chan_t *ldcp; 3037d10e4ef2Snarayan int rv = 0, retries = 0; 30381ae08745Sheppo boolean_t chk_done = B_FALSE; 30391ae08745Sheppo 30401ae08745Sheppo if (handle == NULL) { 30411ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_close: invalid channel handle\n"); 30421ae08745Sheppo return (EINVAL); 30431ae08745Sheppo } 30441ae08745Sheppo ldcp = (ldc_chan_t *)handle; 30451ae08745Sheppo 30461ae08745Sheppo mutex_enter(&ldcp->lock); 30471ae08745Sheppo 30481ae08745Sheppo /* return error if channel is not open */ 30493af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) < TS_OPEN) { 30501ae08745Sheppo DWARN(ldcp->id, 30511ae08745Sheppo "ldc_close: (0x%llx) channel is not open\n", ldcp->id); 30521ae08745Sheppo mutex_exit(&ldcp->lock); 30531ae08745Sheppo return (EFAULT); 30541ae08745Sheppo } 30551ae08745Sheppo 30561ae08745Sheppo /* if any memory handles, drings, are bound or mapped cannot close */ 30571ae08745Sheppo if (ldcp->mhdl_list != NULL) { 30581ae08745Sheppo DWARN(ldcp->id, 30591ae08745Sheppo "ldc_close: (0x%llx) channel has bound memory handles\n", 30601ae08745Sheppo ldcp->id); 30611ae08745Sheppo mutex_exit(&ldcp->lock); 30621ae08745Sheppo return (EBUSY); 30631ae08745Sheppo } 30641ae08745Sheppo if (ldcp->exp_dring_list != NULL) { 30651ae08745Sheppo DWARN(ldcp->id, 30661ae08745Sheppo "ldc_close: (0x%llx) channel has bound descriptor rings\n", 30671ae08745Sheppo ldcp->id); 30681ae08745Sheppo mutex_exit(&ldcp->lock); 30691ae08745Sheppo return (EBUSY); 30701ae08745Sheppo } 30711ae08745Sheppo if (ldcp->imp_dring_list != NULL) { 30721ae08745Sheppo DWARN(ldcp->id, 30731ae08745Sheppo "ldc_close: (0x%llx) channel has mapped descriptor rings\n", 30741ae08745Sheppo ldcp->id); 30751ae08745Sheppo mutex_exit(&ldcp->lock); 30761ae08745Sheppo return (EBUSY); 30771ae08745Sheppo } 30781ae08745Sheppo 30794d39be2bSsg70180 if (ldcp->cb_inprogress) { 30804d39be2bSsg70180 DWARN(ldcp->id, "ldc_close: (0x%llx) callback active\n", 30814d39be2bSsg70180 ldcp->id); 30824d39be2bSsg70180 mutex_exit(&ldcp->lock); 30834d39be2bSsg70180 return (EWOULDBLOCK); 30844d39be2bSsg70180 } 30854d39be2bSsg70180 3086d10e4ef2Snarayan /* Obtain Tx lock */ 3087d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 3088d10e4ef2Snarayan 30891ae08745Sheppo /* 30901ae08745Sheppo * Wait for pending transmits to complete i.e Tx queue to drain 30911ae08745Sheppo * if there are pending pkts - wait 1 ms and retry again 30921ae08745Sheppo */ 30931ae08745Sheppo for (;;) { 30941ae08745Sheppo 30951ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 30961ae08745Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 30971ae08745Sheppo if (rv) { 30981ae08745Sheppo cmn_err(CE_WARN, 30991ae08745Sheppo "ldc_close: (0x%lx) cannot read qptrs\n", ldcp->id); 3100d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 31011ae08745Sheppo mutex_exit(&ldcp->lock); 31021ae08745Sheppo return (EIO); 31031ae08745Sheppo } 31041ae08745Sheppo 31051ae08745Sheppo if (ldcp->tx_head == ldcp->tx_tail || 31061ae08745Sheppo ldcp->link_state != LDC_CHANNEL_UP) { 31071ae08745Sheppo break; 31081ae08745Sheppo } 31091ae08745Sheppo 31101ae08745Sheppo if (chk_done) { 31111ae08745Sheppo DWARN(ldcp->id, 31121ae08745Sheppo "ldc_close: (0x%llx) Tx queue drain timeout\n", 31131ae08745Sheppo ldcp->id); 31141ae08745Sheppo break; 31151ae08745Sheppo } 31161ae08745Sheppo 31171ae08745Sheppo /* wait for one ms and try again */ 31181ae08745Sheppo delay(drv_usectohz(1000)); 31191ae08745Sheppo chk_done = B_TRUE; 31201ae08745Sheppo } 31211ae08745Sheppo 31221ae08745Sheppo /* 3123a8ea4edeSnarayan * Drain the Tx and Rx queues as we are closing the 3124a8ea4edeSnarayan * channel. We dont care about any pending packets. 3125a8ea4edeSnarayan * We have to also drain the queue prior to clearing 3126a8ea4edeSnarayan * pending interrupts, otherwise the HV will trigger 3127a8ea4edeSnarayan * an interrupt the moment the interrupt state is 3128a8ea4edeSnarayan * cleared. 31293af08d82Slm66018 */ 31303af08d82Slm66018 (void) i_ldc_txq_reconf(ldcp); 3131a8ea4edeSnarayan (void) i_ldc_rxq_drain(ldcp); 31323af08d82Slm66018 31333af08d82Slm66018 /* 31341ae08745Sheppo * Unregister the channel with the nexus 31351ae08745Sheppo */ 3136d10e4ef2Snarayan while ((rv = i_ldc_unregister_channel(ldcp)) != 0) { 3137d10e4ef2Snarayan 3138d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 31391ae08745Sheppo mutex_exit(&ldcp->lock); 3140d10e4ef2Snarayan 3141d10e4ef2Snarayan /* if any error other than EAGAIN return back */ 3142a8ea4edeSnarayan if (rv != EAGAIN || retries >= ldc_max_retries) { 3143d10e4ef2Snarayan cmn_err(CE_WARN, 3144d10e4ef2Snarayan "ldc_close: (0x%lx) unregister failed, %d\n", 3145d10e4ef2Snarayan ldcp->id, rv); 31461ae08745Sheppo return (rv); 31471ae08745Sheppo } 31481ae08745Sheppo 31491ae08745Sheppo /* 3150d10e4ef2Snarayan * As there could be pending interrupts we need 3151d10e4ef2Snarayan * to wait and try again 3152d10e4ef2Snarayan */ 31534d39be2bSsg70180 drv_usecwait(ldc_close_delay); 3154d10e4ef2Snarayan mutex_enter(&ldcp->lock); 3155d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 3156d10e4ef2Snarayan retries++; 3157d10e4ef2Snarayan } 3158d10e4ef2Snarayan 3159d10e4ef2Snarayan /* 31601ae08745Sheppo * Unregister queues 31611ae08745Sheppo */ 31621ae08745Sheppo rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 31631ae08745Sheppo if (rv) { 31641ae08745Sheppo cmn_err(CE_WARN, 31651ae08745Sheppo "ldc_close: (0x%lx) channel TX queue unconf failed\n", 31661ae08745Sheppo ldcp->id); 3167d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 31681ae08745Sheppo mutex_exit(&ldcp->lock); 31691ae08745Sheppo return (EIO); 31701ae08745Sheppo } 31711ae08745Sheppo rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 31721ae08745Sheppo if (rv) { 31731ae08745Sheppo cmn_err(CE_WARN, 31741ae08745Sheppo "ldc_close: (0x%lx) channel RX queue unconf failed\n", 31751ae08745Sheppo ldcp->id); 3176d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 31771ae08745Sheppo mutex_exit(&ldcp->lock); 31781ae08745Sheppo return (EIO); 31791ae08745Sheppo } 31801ae08745Sheppo 31811ae08745Sheppo ldcp->tstate &= ~TS_QCONF_RDY; 31821ae08745Sheppo 31831ae08745Sheppo /* Reset channel state information */ 31841ae08745Sheppo i_ldc_reset_state(ldcp); 31851ae08745Sheppo 31861ae08745Sheppo /* Mark channel as down and in initialized state */ 31871ae08745Sheppo ldcp->tx_ackd_head = 0; 31881ae08745Sheppo ldcp->tx_head = 0; 31893af08d82Slm66018 ldcp->tstate = TS_IN_RESET|TS_INIT; 31901ae08745Sheppo ldcp->status = LDC_INIT; 31911ae08745Sheppo 3192d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 31931ae08745Sheppo mutex_exit(&ldcp->lock); 31941ae08745Sheppo 31951ae08745Sheppo /* Decrement number of open channels */ 31961ae08745Sheppo mutex_enter(&ldcssp->lock); 31971ae08745Sheppo ldcssp->channels_open--; 31981ae08745Sheppo mutex_exit(&ldcssp->lock); 31991ae08745Sheppo 32001ae08745Sheppo D1(ldcp->id, "ldc_close: (0x%llx) channel closed\n", ldcp->id); 32011ae08745Sheppo 32021ae08745Sheppo return (0); 32031ae08745Sheppo } 32041ae08745Sheppo 32051ae08745Sheppo /* 32061ae08745Sheppo * Register channel callback 32071ae08745Sheppo */ 32081ae08745Sheppo int 32091ae08745Sheppo ldc_reg_callback(ldc_handle_t handle, 32101ae08745Sheppo uint_t(*cb)(uint64_t event, caddr_t arg), caddr_t arg) 32111ae08745Sheppo { 32121ae08745Sheppo ldc_chan_t *ldcp; 32131ae08745Sheppo 32141ae08745Sheppo if (handle == NULL) { 32151ae08745Sheppo DWARN(DBG_ALL_LDCS, 32161ae08745Sheppo "ldc_reg_callback: invalid channel handle\n"); 32171ae08745Sheppo return (EINVAL); 32181ae08745Sheppo } 32191ae08745Sheppo if (((uint64_t)cb) < KERNELBASE) { 32201ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_reg_callback: invalid callback\n"); 32211ae08745Sheppo return (EINVAL); 32221ae08745Sheppo } 32231ae08745Sheppo ldcp = (ldc_chan_t *)handle; 32241ae08745Sheppo 32251ae08745Sheppo mutex_enter(&ldcp->lock); 32261ae08745Sheppo 32271ae08745Sheppo if (ldcp->cb) { 32281ae08745Sheppo DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback exists\n", 32291ae08745Sheppo ldcp->id); 32301ae08745Sheppo mutex_exit(&ldcp->lock); 32311ae08745Sheppo return (EIO); 32321ae08745Sheppo } 32331ae08745Sheppo if (ldcp->cb_inprogress) { 32341ae08745Sheppo DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback active\n", 32351ae08745Sheppo ldcp->id); 32361ae08745Sheppo mutex_exit(&ldcp->lock); 32371ae08745Sheppo return (EWOULDBLOCK); 32381ae08745Sheppo } 32391ae08745Sheppo 32401ae08745Sheppo ldcp->cb = cb; 32411ae08745Sheppo ldcp->cb_arg = arg; 32421ae08745Sheppo ldcp->cb_enabled = B_TRUE; 32431ae08745Sheppo 32441ae08745Sheppo D1(ldcp->id, 32451ae08745Sheppo "ldc_reg_callback: (0x%llx) registered callback for channel\n", 32461ae08745Sheppo ldcp->id); 32471ae08745Sheppo 32481ae08745Sheppo mutex_exit(&ldcp->lock); 32491ae08745Sheppo 32501ae08745Sheppo return (0); 32511ae08745Sheppo } 32521ae08745Sheppo 32531ae08745Sheppo /* 32541ae08745Sheppo * Unregister channel callback 32551ae08745Sheppo */ 32561ae08745Sheppo int 32571ae08745Sheppo ldc_unreg_callback(ldc_handle_t handle) 32581ae08745Sheppo { 32591ae08745Sheppo ldc_chan_t *ldcp; 32601ae08745Sheppo 32611ae08745Sheppo if (handle == NULL) { 32621ae08745Sheppo DWARN(DBG_ALL_LDCS, 32631ae08745Sheppo "ldc_unreg_callback: invalid channel handle\n"); 32641ae08745Sheppo return (EINVAL); 32651ae08745Sheppo } 32661ae08745Sheppo ldcp = (ldc_chan_t *)handle; 32671ae08745Sheppo 32681ae08745Sheppo mutex_enter(&ldcp->lock); 32691ae08745Sheppo 32701ae08745Sheppo if (ldcp->cb == NULL) { 32711ae08745Sheppo DWARN(ldcp->id, 32721ae08745Sheppo "ldc_unreg_callback: (0x%llx) no callback exists\n", 32731ae08745Sheppo ldcp->id); 32741ae08745Sheppo mutex_exit(&ldcp->lock); 32751ae08745Sheppo return (EIO); 32761ae08745Sheppo } 32771ae08745Sheppo if (ldcp->cb_inprogress) { 32781ae08745Sheppo DWARN(ldcp->id, 32791ae08745Sheppo "ldc_unreg_callback: (0x%llx) callback active\n", 32801ae08745Sheppo ldcp->id); 32811ae08745Sheppo mutex_exit(&ldcp->lock); 32821ae08745Sheppo return (EWOULDBLOCK); 32831ae08745Sheppo } 32841ae08745Sheppo 32851ae08745Sheppo ldcp->cb = NULL; 32861ae08745Sheppo ldcp->cb_arg = NULL; 32871ae08745Sheppo ldcp->cb_enabled = B_FALSE; 32881ae08745Sheppo 32891ae08745Sheppo D1(ldcp->id, 32901ae08745Sheppo "ldc_unreg_callback: (0x%llx) unregistered callback for channel\n", 32911ae08745Sheppo ldcp->id); 32921ae08745Sheppo 32931ae08745Sheppo mutex_exit(&ldcp->lock); 32941ae08745Sheppo 32951ae08745Sheppo return (0); 32961ae08745Sheppo } 32971ae08745Sheppo 32981ae08745Sheppo 32991ae08745Sheppo /* 33001ae08745Sheppo * Bring a channel up by initiating a handshake with the peer 33011ae08745Sheppo * This call is asynchronous. It will complete at a later point 33021ae08745Sheppo * in time when the peer responds back with an RTR. 33031ae08745Sheppo */ 33041ae08745Sheppo int 33051ae08745Sheppo ldc_up(ldc_handle_t handle) 33061ae08745Sheppo { 33071ae08745Sheppo int rv; 33081ae08745Sheppo ldc_chan_t *ldcp; 33091ae08745Sheppo ldc_msg_t *ldcmsg; 331057e6a936Ssb155480 uint64_t tx_tail, tstate, link_state; 33111ae08745Sheppo 33121ae08745Sheppo if (handle == NULL) { 33131ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_up: invalid channel handle\n"); 33141ae08745Sheppo return (EINVAL); 33151ae08745Sheppo } 33161ae08745Sheppo ldcp = (ldc_chan_t *)handle; 33171ae08745Sheppo 33181ae08745Sheppo mutex_enter(&ldcp->lock); 33191ae08745Sheppo 33203af08d82Slm66018 D1(ldcp->id, "ldc_up: (0x%llx) doing channel UP\n", ldcp->id); 33213af08d82Slm66018 33223af08d82Slm66018 /* clear the reset state */ 33233af08d82Slm66018 tstate = ldcp->tstate; 33243af08d82Slm66018 ldcp->tstate &= ~TS_IN_RESET; 33253af08d82Slm66018 33261ae08745Sheppo if (ldcp->tstate == TS_UP) { 33273af08d82Slm66018 DWARN(ldcp->id, 33281ae08745Sheppo "ldc_up: (0x%llx) channel is already in UP state\n", 33291ae08745Sheppo ldcp->id); 33303af08d82Slm66018 33313af08d82Slm66018 /* mark channel as up */ 33323af08d82Slm66018 ldcp->status = LDC_UP; 33333af08d82Slm66018 33343af08d82Slm66018 /* 33353af08d82Slm66018 * if channel was in reset state and there was 33363af08d82Slm66018 * pending data clear interrupt state. this will 33373af08d82Slm66018 * trigger an interrupt, causing the RX handler to 33383af08d82Slm66018 * to invoke the client's callback 33393af08d82Slm66018 */ 33403af08d82Slm66018 if ((tstate & TS_IN_RESET) && 33413af08d82Slm66018 ldcp->rx_intr_state == LDC_INTR_PEND) { 3342cb112a14Slm66018 D1(ldcp->id, 33433af08d82Slm66018 "ldc_up: (0x%llx) channel has pending data, " 33443af08d82Slm66018 "clearing interrupt\n", ldcp->id); 33453af08d82Slm66018 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 33463af08d82Slm66018 } 33473af08d82Slm66018 33481ae08745Sheppo mutex_exit(&ldcp->lock); 33491ae08745Sheppo return (0); 33501ae08745Sheppo } 33511ae08745Sheppo 33521ae08745Sheppo /* if the channel is in RAW mode - mark it as UP, if READY */ 33531ae08745Sheppo if (ldcp->mode == LDC_MODE_RAW && ldcp->tstate >= TS_READY) { 33541ae08745Sheppo ldcp->tstate = TS_UP; 33551ae08745Sheppo mutex_exit(&ldcp->lock); 33561ae08745Sheppo return (0); 33571ae08745Sheppo } 33581ae08745Sheppo 33591ae08745Sheppo /* Don't start another handshake if there is one in progress */ 33601ae08745Sheppo if (ldcp->hstate) { 33613af08d82Slm66018 D1(ldcp->id, 33621ae08745Sheppo "ldc_up: (0x%llx) channel handshake in progress\n", 33631ae08745Sheppo ldcp->id); 33641ae08745Sheppo mutex_exit(&ldcp->lock); 33651ae08745Sheppo return (0); 33661ae08745Sheppo } 33671ae08745Sheppo 3368d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 3369d10e4ef2Snarayan 337057e6a936Ssb155480 /* save current link state */ 337157e6a936Ssb155480 link_state = ldcp->link_state; 337257e6a936Ssb155480 33731ae08745Sheppo /* get the current tail for the LDC msg */ 33741ae08745Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 33751ae08745Sheppo if (rv) { 3376cb112a14Slm66018 D1(ldcp->id, "ldc_up: (0x%llx) cannot initiate handshake\n", 33771ae08745Sheppo ldcp->id); 3378d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 33791ae08745Sheppo mutex_exit(&ldcp->lock); 33801ae08745Sheppo return (ECONNREFUSED); 33811ae08745Sheppo } 33821ae08745Sheppo 338357e6a936Ssb155480 /* 338457e6a936Ssb155480 * If i_ldc_get_tx_tail() changed link_state to either RESET or UP, 338557e6a936Ssb155480 * from a previous state of DOWN, then mark the channel as 338657e6a936Ssb155480 * being ready for handshake. 338757e6a936Ssb155480 */ 338857e6a936Ssb155480 if ((link_state == LDC_CHANNEL_DOWN) && 338957e6a936Ssb155480 (link_state != ldcp->link_state)) { 339057e6a936Ssb155480 339157e6a936Ssb155480 ASSERT((ldcp->link_state == LDC_CHANNEL_RESET) || 339257e6a936Ssb155480 (ldcp->link_state == LDC_CHANNEL_UP)); 339357e6a936Ssb155480 339457e6a936Ssb155480 if (ldcp->mode == LDC_MODE_RAW) { 339557e6a936Ssb155480 ldcp->status = LDC_UP; 339657e6a936Ssb155480 ldcp->tstate = TS_UP; 339757e6a936Ssb155480 mutex_exit(&ldcp->tx_lock); 339857e6a936Ssb155480 mutex_exit(&ldcp->lock); 339957e6a936Ssb155480 return (0); 340057e6a936Ssb155480 } else { 340157e6a936Ssb155480 ldcp->status = LDC_READY; 340257e6a936Ssb155480 ldcp->tstate |= TS_LINK_READY; 340357e6a936Ssb155480 } 340457e6a936Ssb155480 340557e6a936Ssb155480 } 340657e6a936Ssb155480 34071ae08745Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 34081ae08745Sheppo ZERO_PKT(ldcmsg); 34091ae08745Sheppo 34101ae08745Sheppo ldcmsg->type = LDC_CTRL; 34111ae08745Sheppo ldcmsg->stype = LDC_INFO; 34121ae08745Sheppo ldcmsg->ctrl = LDC_VER; 34131ae08745Sheppo ldcp->next_vidx = 0; 34141ae08745Sheppo bcopy(&ldc_versions[0], ldcmsg->udata, sizeof (ldc_versions[0])); 34151ae08745Sheppo 34161ae08745Sheppo DUMP_LDC_PKT(ldcp, "ldc_up snd ver", (uint64_t)ldcmsg); 34171ae08745Sheppo 34181ae08745Sheppo /* initiate the send by calling into HV and set the new tail */ 34191ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 34201ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 34211ae08745Sheppo 34221ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 34231ae08745Sheppo if (rv) { 34241ae08745Sheppo DWARN(ldcp->id, 34251ae08745Sheppo "ldc_up: (0x%llx) cannot initiate handshake rv=%d\n", 34261ae08745Sheppo ldcp->id, rv); 3427d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 34281ae08745Sheppo mutex_exit(&ldcp->lock); 34291ae08745Sheppo return (rv); 34301ae08745Sheppo } 34311ae08745Sheppo 34320a55fbb7Slm66018 ldcp->hstate |= TS_SENT_VER; 34331ae08745Sheppo ldcp->tx_tail = tx_tail; 34341ae08745Sheppo D1(ldcp->id, "ldc_up: (0x%llx) channel up initiated\n", ldcp->id); 34351ae08745Sheppo 3436d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 34371ae08745Sheppo mutex_exit(&ldcp->lock); 34381ae08745Sheppo 34391ae08745Sheppo return (rv); 34401ae08745Sheppo } 34411ae08745Sheppo 34421ae08745Sheppo 34431ae08745Sheppo /* 3444e1ebb9ecSlm66018 * Bring a channel down by resetting its state and queues 34451ae08745Sheppo */ 34461ae08745Sheppo int 3447e1ebb9ecSlm66018 ldc_down(ldc_handle_t handle) 34481ae08745Sheppo { 34491ae08745Sheppo ldc_chan_t *ldcp; 34501ae08745Sheppo 34511ae08745Sheppo if (handle == NULL) { 3452e1ebb9ecSlm66018 DWARN(DBG_ALL_LDCS, "ldc_down: invalid channel handle\n"); 34531ae08745Sheppo return (EINVAL); 34541ae08745Sheppo } 34551ae08745Sheppo ldcp = (ldc_chan_t *)handle; 34561ae08745Sheppo mutex_enter(&ldcp->lock); 3457d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 34583af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 3459d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 34601ae08745Sheppo mutex_exit(&ldcp->lock); 34611ae08745Sheppo 34621ae08745Sheppo return (0); 34631ae08745Sheppo } 34641ae08745Sheppo 34651ae08745Sheppo /* 34661ae08745Sheppo * Get the current channel status 34671ae08745Sheppo */ 34681ae08745Sheppo int 34691ae08745Sheppo ldc_status(ldc_handle_t handle, ldc_status_t *status) 34701ae08745Sheppo { 34711ae08745Sheppo ldc_chan_t *ldcp; 34721ae08745Sheppo 34731ae08745Sheppo if (handle == NULL || status == NULL) { 34741ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_status: invalid argument\n"); 34751ae08745Sheppo return (EINVAL); 34761ae08745Sheppo } 34771ae08745Sheppo ldcp = (ldc_chan_t *)handle; 34781ae08745Sheppo 34791ae08745Sheppo *status = ((ldc_chan_t *)handle)->status; 34801ae08745Sheppo 3481cb112a14Slm66018 D1(ldcp->id, 34821ae08745Sheppo "ldc_status: (0x%llx) returned status %d\n", ldcp->id, *status); 34831ae08745Sheppo return (0); 34841ae08745Sheppo } 34851ae08745Sheppo 34861ae08745Sheppo 34871ae08745Sheppo /* 34881ae08745Sheppo * Set the channel's callback mode - enable/disable callbacks 34891ae08745Sheppo */ 34901ae08745Sheppo int 34911ae08745Sheppo ldc_set_cb_mode(ldc_handle_t handle, ldc_cb_mode_t cmode) 34921ae08745Sheppo { 34931ae08745Sheppo ldc_chan_t *ldcp; 34941ae08745Sheppo 34951ae08745Sheppo if (handle == NULL) { 34961ae08745Sheppo DWARN(DBG_ALL_LDCS, 34971ae08745Sheppo "ldc_set_intr_mode: invalid channel handle\n"); 34981ae08745Sheppo return (EINVAL); 34991ae08745Sheppo } 35001ae08745Sheppo ldcp = (ldc_chan_t *)handle; 35011ae08745Sheppo 35021ae08745Sheppo /* 35031ae08745Sheppo * Record no callbacks should be invoked 35041ae08745Sheppo */ 35051ae08745Sheppo mutex_enter(&ldcp->lock); 35061ae08745Sheppo 35071ae08745Sheppo switch (cmode) { 35081ae08745Sheppo case LDC_CB_DISABLE: 35091ae08745Sheppo if (!ldcp->cb_enabled) { 35101ae08745Sheppo DWARN(ldcp->id, 35111ae08745Sheppo "ldc_set_cb_mode: (0x%llx) callbacks disabled\n", 35121ae08745Sheppo ldcp->id); 35131ae08745Sheppo break; 35141ae08745Sheppo } 35151ae08745Sheppo ldcp->cb_enabled = B_FALSE; 35161ae08745Sheppo 35171ae08745Sheppo D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) disabled callbacks\n", 35181ae08745Sheppo ldcp->id); 35191ae08745Sheppo break; 35201ae08745Sheppo 35211ae08745Sheppo case LDC_CB_ENABLE: 35221ae08745Sheppo if (ldcp->cb_enabled) { 35231ae08745Sheppo DWARN(ldcp->id, 35241ae08745Sheppo "ldc_set_cb_mode: (0x%llx) callbacks enabled\n", 35251ae08745Sheppo ldcp->id); 35261ae08745Sheppo break; 35271ae08745Sheppo } 35281ae08745Sheppo ldcp->cb_enabled = B_TRUE; 35291ae08745Sheppo 35301ae08745Sheppo D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) enabled callbacks\n", 35311ae08745Sheppo ldcp->id); 35321ae08745Sheppo break; 35331ae08745Sheppo } 35341ae08745Sheppo 35351ae08745Sheppo mutex_exit(&ldcp->lock); 35361ae08745Sheppo 35371ae08745Sheppo return (0); 35381ae08745Sheppo } 35391ae08745Sheppo 35401ae08745Sheppo /* 35411ae08745Sheppo * Check to see if there are packets on the incoming queue 3542e1ebb9ecSlm66018 * Will return hasdata = B_FALSE if there are no packets 35431ae08745Sheppo */ 35441ae08745Sheppo int 3545e1ebb9ecSlm66018 ldc_chkq(ldc_handle_t handle, boolean_t *hasdata) 35461ae08745Sheppo { 35471ae08745Sheppo int rv; 35481ae08745Sheppo uint64_t rx_head, rx_tail; 35491ae08745Sheppo ldc_chan_t *ldcp; 35501ae08745Sheppo 35511ae08745Sheppo if (handle == NULL) { 35521ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_chkq: invalid channel handle\n"); 35531ae08745Sheppo return (EINVAL); 35541ae08745Sheppo } 35551ae08745Sheppo ldcp = (ldc_chan_t *)handle; 35561ae08745Sheppo 3557e1ebb9ecSlm66018 *hasdata = B_FALSE; 35581ae08745Sheppo 35591ae08745Sheppo mutex_enter(&ldcp->lock); 35601ae08745Sheppo 35611ae08745Sheppo if (ldcp->tstate != TS_UP) { 35621ae08745Sheppo D1(ldcp->id, 35631ae08745Sheppo "ldc_chkq: (0x%llx) channel is not up\n", ldcp->id); 35641ae08745Sheppo mutex_exit(&ldcp->lock); 35651ae08745Sheppo return (ECONNRESET); 35661ae08745Sheppo } 35671ae08745Sheppo 35681ae08745Sheppo /* Read packet(s) from the queue */ 35691ae08745Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 35701ae08745Sheppo &ldcp->link_state); 35711ae08745Sheppo if (rv != 0) { 35721ae08745Sheppo cmn_err(CE_WARN, 35731ae08745Sheppo "ldc_chkq: (0x%lx) unable to read queue ptrs", ldcp->id); 35741ae08745Sheppo mutex_exit(&ldcp->lock); 35751ae08745Sheppo return (EIO); 35761ae08745Sheppo } 3577*58283286Sha137994 35781ae08745Sheppo /* reset the channel state if the channel went down */ 35791ae08745Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN || 35801ae08745Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 3581d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 35823af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 3583d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 35841ae08745Sheppo mutex_exit(&ldcp->lock); 35851ae08745Sheppo return (ECONNRESET); 35861ae08745Sheppo } 35871ae08745Sheppo 3588*58283286Sha137994 switch (ldcp->mode) { 3589*58283286Sha137994 case LDC_MODE_RAW: 3590*58283286Sha137994 /* 3591*58283286Sha137994 * In raw mode, there are no ctrl packets, so checking 3592*58283286Sha137994 * if the queue is non-empty is sufficient. 3593*58283286Sha137994 */ 3594*58283286Sha137994 *hasdata = (rx_head != rx_tail); 3595*58283286Sha137994 break; 3596*58283286Sha137994 3597*58283286Sha137994 case LDC_MODE_UNRELIABLE: 3598*58283286Sha137994 /* 3599*58283286Sha137994 * In unreliable mode, if the queue is non-empty, we need 3600*58283286Sha137994 * to check if it actually contains unread data packets. 3601*58283286Sha137994 * The queue may just contain ctrl packets. 3602*58283286Sha137994 */ 3603*58283286Sha137994 if (rx_head != rx_tail) 3604*58283286Sha137994 *hasdata = (i_ldc_chkq(ldcp) == 0); 3605*58283286Sha137994 break; 3606*58283286Sha137994 3607*58283286Sha137994 case LDC_MODE_STREAM: 3608*58283286Sha137994 /* 3609*58283286Sha137994 * In stream mode, first check for 'stream_remains' > 0. 3610*58283286Sha137994 * Otherwise, if the data queue head and tail pointers 3611*58283286Sha137994 * differ, there must be data to read. 3612*58283286Sha137994 */ 3613*58283286Sha137994 if (ldcp->stream_remains > 0) 3614e1ebb9ecSlm66018 *hasdata = B_TRUE; 3615*58283286Sha137994 else 3616*58283286Sha137994 *hasdata = (ldcp->rx_dq_head != ldcp->rx_dq_tail); 3617*58283286Sha137994 break; 3618*58283286Sha137994 3619*58283286Sha137994 default: 3620*58283286Sha137994 cmn_err(CE_WARN, "ldc_chkq: (0x%lx) unexpected channel mode " 3621*58283286Sha137994 "(0x%x)", ldcp->id, ldcp->mode); 3622*58283286Sha137994 mutex_exit(&ldcp->lock); 3623*58283286Sha137994 return (EIO); 36241ae08745Sheppo } 36251ae08745Sheppo 36261ae08745Sheppo mutex_exit(&ldcp->lock); 36271ae08745Sheppo 36281ae08745Sheppo return (0); 36291ae08745Sheppo } 36301ae08745Sheppo 36311ae08745Sheppo 36321ae08745Sheppo /* 36331ae08745Sheppo * Read 'size' amount of bytes or less. If incoming buffer 36341ae08745Sheppo * is more than 'size', ENOBUFS is returned. 36351ae08745Sheppo * 36361ae08745Sheppo * On return, size contains the number of bytes read. 36371ae08745Sheppo */ 36381ae08745Sheppo int 36391ae08745Sheppo ldc_read(ldc_handle_t handle, caddr_t bufp, size_t *sizep) 36401ae08745Sheppo { 36411ae08745Sheppo ldc_chan_t *ldcp; 36421ae08745Sheppo uint64_t rx_head = 0, rx_tail = 0; 36431ae08745Sheppo int rv = 0, exit_val; 36441ae08745Sheppo 36451ae08745Sheppo if (handle == NULL) { 36461ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_read: invalid channel handle\n"); 36471ae08745Sheppo return (EINVAL); 36481ae08745Sheppo } 36491ae08745Sheppo 36501ae08745Sheppo ldcp = (ldc_chan_t *)handle; 36511ae08745Sheppo 36521ae08745Sheppo /* channel lock */ 36531ae08745Sheppo mutex_enter(&ldcp->lock); 36541ae08745Sheppo 36551ae08745Sheppo if (ldcp->tstate != TS_UP) { 36561ae08745Sheppo DWARN(ldcp->id, 36571ae08745Sheppo "ldc_read: (0x%llx) channel is not in UP state\n", 36581ae08745Sheppo ldcp->id); 36591ae08745Sheppo exit_val = ECONNRESET; 3660*58283286Sha137994 } else if (ldcp->mode == LDC_MODE_STREAM) { 3661*58283286Sha137994 TRACE_RXDQ_LENGTH(ldcp); 3662*58283286Sha137994 exit_val = ldcp->read_p(ldcp, bufp, sizep); 3663*58283286Sha137994 mutex_exit(&ldcp->lock); 3664*58283286Sha137994 return (exit_val); 36651ae08745Sheppo } else { 36661ae08745Sheppo exit_val = ldcp->read_p(ldcp, bufp, sizep); 36671ae08745Sheppo } 36681ae08745Sheppo 36691ae08745Sheppo /* 36701ae08745Sheppo * if queue has been drained - clear interrupt 36711ae08745Sheppo */ 36721ae08745Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 36731ae08745Sheppo &ldcp->link_state); 3674cb112a14Slm66018 if (rv != 0) { 3675cb112a14Slm66018 cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs", 3676cb112a14Slm66018 ldcp->id); 3677cb112a14Slm66018 mutex_enter(&ldcp->tx_lock); 3678cb112a14Slm66018 i_ldc_reset(ldcp, B_TRUE); 3679cb112a14Slm66018 mutex_exit(&ldcp->tx_lock); 3680bd8f0338Snarayan mutex_exit(&ldcp->lock); 3681cb112a14Slm66018 return (ECONNRESET); 3682cb112a14Slm66018 } 36833af08d82Slm66018 36843af08d82Slm66018 if (exit_val == 0) { 36853af08d82Slm66018 if (ldcp->link_state == LDC_CHANNEL_DOWN || 36863af08d82Slm66018 ldcp->link_state == LDC_CHANNEL_RESET) { 36873af08d82Slm66018 mutex_enter(&ldcp->tx_lock); 36883af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 36893af08d82Slm66018 exit_val = ECONNRESET; 36903af08d82Slm66018 mutex_exit(&ldcp->tx_lock); 36913af08d82Slm66018 } 36923af08d82Slm66018 if ((rv == 0) && 36933af08d82Slm66018 (ldcp->rx_intr_state == LDC_INTR_PEND) && 36943af08d82Slm66018 (rx_head == rx_tail)) { 36951ae08745Sheppo i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 36961ae08745Sheppo } 36973af08d82Slm66018 } 36981ae08745Sheppo 36991ae08745Sheppo mutex_exit(&ldcp->lock); 37001ae08745Sheppo return (exit_val); 37011ae08745Sheppo } 37021ae08745Sheppo 37031ae08745Sheppo /* 37041ae08745Sheppo * Basic raw mondo read - 37051ae08745Sheppo * no interpretation of mondo contents at all. 37061ae08745Sheppo * 37071ae08745Sheppo * Enter and exit with ldcp->lock held by caller 37081ae08745Sheppo */ 37091ae08745Sheppo static int 37101ae08745Sheppo i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep) 37111ae08745Sheppo { 37121ae08745Sheppo uint64_t q_size_mask; 37131ae08745Sheppo ldc_msg_t *msgp; 37141ae08745Sheppo uint8_t *msgbufp; 37151ae08745Sheppo int rv = 0, space; 37161ae08745Sheppo uint64_t rx_head, rx_tail; 37171ae08745Sheppo 37181ae08745Sheppo space = *sizep; 37191ae08745Sheppo 37201ae08745Sheppo if (space < LDC_PAYLOAD_SIZE_RAW) 37211ae08745Sheppo return (ENOBUFS); 37221ae08745Sheppo 37231ae08745Sheppo ASSERT(mutex_owned(&ldcp->lock)); 37241ae08745Sheppo 37251ae08745Sheppo /* compute mask for increment */ 37261ae08745Sheppo q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT; 37271ae08745Sheppo 37281ae08745Sheppo /* 37291ae08745Sheppo * Read packet(s) from the queue 37301ae08745Sheppo */ 37311ae08745Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 37321ae08745Sheppo &ldcp->link_state); 37331ae08745Sheppo if (rv != 0) { 37341ae08745Sheppo cmn_err(CE_WARN, 37351ae08745Sheppo "ldc_read_raw: (0x%lx) unable to read queue ptrs", 37361ae08745Sheppo ldcp->id); 37371ae08745Sheppo return (EIO); 37381ae08745Sheppo } 37391ae08745Sheppo D1(ldcp->id, "ldc_read_raw: (0x%llx) rxh=0x%llx," 37401ae08745Sheppo " rxt=0x%llx, st=0x%llx\n", 37411ae08745Sheppo ldcp->id, rx_head, rx_tail, ldcp->link_state); 37421ae08745Sheppo 37431ae08745Sheppo /* reset the channel state if the channel went down */ 37443af08d82Slm66018 if (ldcp->link_state == LDC_CHANNEL_DOWN || 37453af08d82Slm66018 ldcp->link_state == LDC_CHANNEL_RESET) { 3746d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 37473af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 3748d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 37491ae08745Sheppo return (ECONNRESET); 37501ae08745Sheppo } 37511ae08745Sheppo 37521ae08745Sheppo /* 37531ae08745Sheppo * Check for empty queue 37541ae08745Sheppo */ 37551ae08745Sheppo if (rx_head == rx_tail) { 37561ae08745Sheppo *sizep = 0; 37571ae08745Sheppo return (0); 37581ae08745Sheppo } 37591ae08745Sheppo 37601ae08745Sheppo /* get the message */ 37611ae08745Sheppo msgp = (ldc_msg_t *)(ldcp->rx_q_va + rx_head); 37621ae08745Sheppo 37631ae08745Sheppo /* if channel is in RAW mode, copy data and return */ 37641ae08745Sheppo msgbufp = (uint8_t *)&(msgp->raw[0]); 37651ae08745Sheppo 37661ae08745Sheppo bcopy(msgbufp, target_bufp, LDC_PAYLOAD_SIZE_RAW); 37671ae08745Sheppo 37681ae08745Sheppo DUMP_PAYLOAD(ldcp->id, msgbufp); 37691ae08745Sheppo 37701ae08745Sheppo *sizep = LDC_PAYLOAD_SIZE_RAW; 37711ae08745Sheppo 37721ae08745Sheppo rx_head = (rx_head + LDC_PACKET_SIZE) & q_size_mask; 37730a55fbb7Slm66018 rv = i_ldc_set_rx_head(ldcp, rx_head); 37741ae08745Sheppo 37751ae08745Sheppo return (rv); 37761ae08745Sheppo } 37771ae08745Sheppo 37781ae08745Sheppo /* 37791ae08745Sheppo * Process LDC mondos to build larger packets 37801ae08745Sheppo * with either un-reliable or reliable delivery. 37811ae08745Sheppo * 37821ae08745Sheppo * Enter and exit with ldcp->lock held by caller 37831ae08745Sheppo */ 37841ae08745Sheppo static int 37851ae08745Sheppo i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep) 37861ae08745Sheppo { 37871ae08745Sheppo int rv = 0; 37881ae08745Sheppo uint64_t rx_head = 0, rx_tail = 0; 37891ae08745Sheppo uint64_t curr_head = 0; 37901ae08745Sheppo ldc_msg_t *msg; 37911ae08745Sheppo caddr_t target; 37921ae08745Sheppo size_t len = 0, bytes_read = 0; 37930a55fbb7Slm66018 int retries = 0; 3794*58283286Sha137994 uint64_t q_va, q_size_mask; 3795d10e4ef2Snarayan uint64_t first_fragment = 0; 37961ae08745Sheppo 37971ae08745Sheppo target = target_bufp; 37981ae08745Sheppo 37991ae08745Sheppo ASSERT(mutex_owned(&ldcp->lock)); 38001ae08745Sheppo 38013af08d82Slm66018 /* check if the buffer and size are valid */ 38023af08d82Slm66018 if (target_bufp == NULL || *sizep == 0) { 38033af08d82Slm66018 DWARN(ldcp->id, "ldc_read: (0x%llx) invalid buffer/size\n", 38043af08d82Slm66018 ldcp->id); 38053af08d82Slm66018 return (EINVAL); 38063af08d82Slm66018 } 38073af08d82Slm66018 3808*58283286Sha137994 /* Set q_va and compute increment mask for the appropriate queue */ 3809*58283286Sha137994 if (ldcp->mode == LDC_MODE_STREAM) { 3810*58283286Sha137994 q_va = ldcp->rx_dq_va; 3811*58283286Sha137994 q_size_mask = (ldcp->rx_dq_entries-1)<<LDC_PACKET_SHIFT; 3812*58283286Sha137994 } else { 3813*58283286Sha137994 q_va = ldcp->rx_q_va; 38141ae08745Sheppo q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT; 3815*58283286Sha137994 } 38161ae08745Sheppo 38171ae08745Sheppo /* 38181ae08745Sheppo * Read packet(s) from the queue 38191ae08745Sheppo */ 3820*58283286Sha137994 rv = ldcp->readq_get_state(ldcp, &curr_head, &rx_tail, 38211ae08745Sheppo &ldcp->link_state); 38221ae08745Sheppo if (rv != 0) { 38233af08d82Slm66018 cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs", 38241ae08745Sheppo ldcp->id); 38253af08d82Slm66018 mutex_enter(&ldcp->tx_lock); 38263af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 38273af08d82Slm66018 mutex_exit(&ldcp->tx_lock); 38283af08d82Slm66018 return (ECONNRESET); 38291ae08745Sheppo } 38301ae08745Sheppo D1(ldcp->id, "ldc_read: (0x%llx) chd=0x%llx, tl=0x%llx, st=0x%llx\n", 38311ae08745Sheppo ldcp->id, curr_head, rx_tail, ldcp->link_state); 38321ae08745Sheppo 38331ae08745Sheppo /* reset the channel state if the channel went down */ 38343af08d82Slm66018 if (ldcp->link_state != LDC_CHANNEL_UP) 38353af08d82Slm66018 goto channel_is_reset; 38361ae08745Sheppo 38371ae08745Sheppo for (;;) { 38381ae08745Sheppo 38391ae08745Sheppo if (curr_head == rx_tail) { 3840*58283286Sha137994 /* 3841*58283286Sha137994 * If a data queue is being used, check the Rx HV 3842*58283286Sha137994 * queue. This will copy over any new data packets 3843*58283286Sha137994 * that have arrived. 3844*58283286Sha137994 */ 3845*58283286Sha137994 if (ldcp->mode == LDC_MODE_STREAM) 3846*58283286Sha137994 (void) i_ldc_chkq(ldcp); 3847*58283286Sha137994 3848*58283286Sha137994 rv = ldcp->readq_get_state(ldcp, 38491ae08745Sheppo &rx_head, &rx_tail, &ldcp->link_state); 38501ae08745Sheppo if (rv != 0) { 38511ae08745Sheppo cmn_err(CE_WARN, 38521ae08745Sheppo "ldc_read: (0x%lx) cannot read queue ptrs", 38531ae08745Sheppo ldcp->id); 3854d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 38553af08d82Slm66018 i_ldc_reset(ldcp, B_TRUE); 3856d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 38571ae08745Sheppo return (ECONNRESET); 38581ae08745Sheppo } 3859*58283286Sha137994 38603af08d82Slm66018 if (ldcp->link_state != LDC_CHANNEL_UP) 38613af08d82Slm66018 goto channel_is_reset; 38621ae08745Sheppo 38631ae08745Sheppo if (curr_head == rx_tail) { 38641ae08745Sheppo 38651ae08745Sheppo /* If in the middle of a fragmented xfer */ 3866d10e4ef2Snarayan if (first_fragment != 0) { 38670a55fbb7Slm66018 38680a55fbb7Slm66018 /* wait for ldc_delay usecs */ 38690a55fbb7Slm66018 drv_usecwait(ldc_delay); 38700a55fbb7Slm66018 38710a55fbb7Slm66018 if (++retries < ldc_max_retries) 38721ae08745Sheppo continue; 38730a55fbb7Slm66018 38741ae08745Sheppo *sizep = 0; 3875*58283286Sha137994 if (ldcp->mode != LDC_MODE_STREAM) 3876*58283286Sha137994 ldcp->last_msg_rcd = 3877*58283286Sha137994 first_fragment - 1; 38783af08d82Slm66018 DWARN(DBG_ALL_LDCS, "ldc_read: " 387922f747efSnarayan "(0x%llx) read timeout", ldcp->id); 38803af08d82Slm66018 return (EAGAIN); 38811ae08745Sheppo } 38821ae08745Sheppo *sizep = 0; 38831ae08745Sheppo break; 38841ae08745Sheppo } 38853af08d82Slm66018 } 38860a55fbb7Slm66018 retries = 0; 38871ae08745Sheppo 38881ae08745Sheppo D2(ldcp->id, 38891ae08745Sheppo "ldc_read: (0x%llx) chd=0x%llx, rxhd=0x%llx, rxtl=0x%llx\n", 38901ae08745Sheppo ldcp->id, curr_head, rx_head, rx_tail); 38911ae08745Sheppo 38921ae08745Sheppo /* get the message */ 3893*58283286Sha137994 msg = (ldc_msg_t *)(q_va + curr_head); 38941ae08745Sheppo 38951ae08745Sheppo DUMP_LDC_PKT(ldcp, "ldc_read received pkt", 38961ae08745Sheppo ldcp->rx_q_va + curr_head); 38971ae08745Sheppo 38981ae08745Sheppo /* Check the message ID for the message received */ 3899*58283286Sha137994 if (ldcp->mode != LDC_MODE_STREAM) { 39001ae08745Sheppo if ((rv = i_ldc_check_seqid(ldcp, msg)) != 0) { 39011ae08745Sheppo 3902*58283286Sha137994 DWARN(ldcp->id, "ldc_read: (0x%llx) seqid " 3903*58283286Sha137994 "error, q_ptrs=0x%lx,0x%lx", 3904*58283286Sha137994 ldcp->id, rx_head, rx_tail); 39051ae08745Sheppo 39060a55fbb7Slm66018 /* throw away data */ 39070a55fbb7Slm66018 bytes_read = 0; 39080a55fbb7Slm66018 39091ae08745Sheppo /* Reset last_msg_rcd to start of message */ 3910d10e4ef2Snarayan if (first_fragment != 0) { 3911d10e4ef2Snarayan ldcp->last_msg_rcd = first_fragment - 1; 3912d10e4ef2Snarayan first_fragment = 0; 39131ae08745Sheppo } 39141ae08745Sheppo /* 39151ae08745Sheppo * Send a NACK -- invalid seqid 39161ae08745Sheppo * get the current tail for the response 39171ae08745Sheppo */ 39181ae08745Sheppo rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK, 39191ae08745Sheppo (msg->ctrl & LDC_CTRL_MASK)); 39201ae08745Sheppo if (rv) { 39211ae08745Sheppo cmn_err(CE_NOTE, 39221ae08745Sheppo "ldc_read: (0x%lx) err sending " 39231ae08745Sheppo "NACK msg\n", ldcp->id); 3924d10e4ef2Snarayan 3925*58283286Sha137994 /* if cannot send NACK - reset chan */ 3926d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 39273af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 3928d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 3929d10e4ef2Snarayan rv = ECONNRESET; 3930d10e4ef2Snarayan break; 39311ae08745Sheppo } 39321ae08745Sheppo 39331ae08745Sheppo /* purge receive queue */ 39340a55fbb7Slm66018 rv = i_ldc_set_rx_head(ldcp, rx_tail); 39351ae08745Sheppo 39361ae08745Sheppo break; 39371ae08745Sheppo } 39381ae08745Sheppo 39391ae08745Sheppo /* 39401ae08745Sheppo * Process any messages of type CTRL messages 3941e1ebb9ecSlm66018 * Future implementations should try to pass these 3942e1ebb9ecSlm66018 * to LDC link by resetting the intr state. 39431ae08745Sheppo * 3944*58283286Sha137994 * NOTE: not done as a switch() as type can be 3945*58283286Sha137994 * both ctrl+data 39461ae08745Sheppo */ 39471ae08745Sheppo if (msg->type & LDC_CTRL) { 39481ae08745Sheppo if (rv = i_ldc_ctrlmsg(ldcp, msg)) { 39491ae08745Sheppo if (rv == EAGAIN) 39501ae08745Sheppo continue; 39510a55fbb7Slm66018 rv = i_ldc_set_rx_head(ldcp, rx_tail); 39521ae08745Sheppo *sizep = 0; 39531ae08745Sheppo bytes_read = 0; 39541ae08745Sheppo break; 39551ae08745Sheppo } 39561ae08745Sheppo } 39571ae08745Sheppo 39581ae08745Sheppo /* process data ACKs */ 39591ae08745Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) { 3960d10e4ef2Snarayan if (rv = i_ldc_process_data_ACK(ldcp, msg)) { 3961d10e4ef2Snarayan *sizep = 0; 3962d10e4ef2Snarayan bytes_read = 0; 3963d10e4ef2Snarayan break; 3964d10e4ef2Snarayan } 39651ae08745Sheppo } 39661ae08745Sheppo 396783d3bc6fSnarayan /* process data NACKs */ 396883d3bc6fSnarayan if ((msg->type & LDC_DATA) && (msg->stype & LDC_NACK)) { 396983d3bc6fSnarayan DWARN(ldcp->id, 3970*58283286Sha137994 "ldc_read: (0x%llx) received DATA/NACK", 3971*58283286Sha137994 ldcp->id); 397283d3bc6fSnarayan mutex_enter(&ldcp->tx_lock); 397383d3bc6fSnarayan i_ldc_reset(ldcp, B_TRUE); 397483d3bc6fSnarayan mutex_exit(&ldcp->tx_lock); 397583d3bc6fSnarayan return (ECONNRESET); 397683d3bc6fSnarayan } 3977*58283286Sha137994 } 397883d3bc6fSnarayan 39791ae08745Sheppo /* process data messages */ 39801ae08745Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) { 39811ae08745Sheppo 39821ae08745Sheppo uint8_t *msgbuf = (uint8_t *)( 39831ae08745Sheppo (ldcp->mode == LDC_MODE_RELIABLE || 398422f747efSnarayan ldcp->mode == LDC_MODE_STREAM) ? 398522f747efSnarayan msg->rdata : msg->udata); 39861ae08745Sheppo 39871ae08745Sheppo D2(ldcp->id, 39881ae08745Sheppo "ldc_read: (0x%llx) received data msg\n", ldcp->id); 39891ae08745Sheppo 39901ae08745Sheppo /* get the packet length */ 39911ae08745Sheppo len = (msg->env & LDC_LEN_MASK); 39921ae08745Sheppo 39931ae08745Sheppo /* 39941ae08745Sheppo * FUTURE OPTIMIZATION: 39951ae08745Sheppo * dont need to set q head for every 39961ae08745Sheppo * packet we read just need to do this when 39971ae08745Sheppo * we are done or need to wait for more 39981ae08745Sheppo * mondos to make a full packet - this is 39991ae08745Sheppo * currently expensive. 40001ae08745Sheppo */ 40011ae08745Sheppo 4002d10e4ef2Snarayan if (first_fragment == 0) { 40031ae08745Sheppo 40041ae08745Sheppo /* 40051ae08745Sheppo * first packets should always have the start 40061ae08745Sheppo * bit set (even for a single packet). If not 40071ae08745Sheppo * throw away the packet 40081ae08745Sheppo */ 40091ae08745Sheppo if (!(msg->env & LDC_FRAG_START)) { 40101ae08745Sheppo 40111ae08745Sheppo DWARN(DBG_ALL_LDCS, 40121ae08745Sheppo "ldc_read: (0x%llx) not start - " 40131ae08745Sheppo "frag=%x\n", ldcp->id, 40141ae08745Sheppo (msg->env) & LDC_FRAG_MASK); 40151ae08745Sheppo 40161ae08745Sheppo /* toss pkt, inc head, cont reading */ 40171ae08745Sheppo bytes_read = 0; 40181ae08745Sheppo target = target_bufp; 40191ae08745Sheppo curr_head = 40201ae08745Sheppo (curr_head + LDC_PACKET_SIZE) 40211ae08745Sheppo & q_size_mask; 4022*58283286Sha137994 if (rv = ldcp->readq_set_head(ldcp, 40231ae08745Sheppo curr_head)) 40241ae08745Sheppo break; 40251ae08745Sheppo 40261ae08745Sheppo continue; 40271ae08745Sheppo } 40281ae08745Sheppo 4029d10e4ef2Snarayan first_fragment = msg->seqid; 40301ae08745Sheppo } else { 40311ae08745Sheppo /* check to see if this is a pkt w/ START bit */ 40321ae08745Sheppo if (msg->env & LDC_FRAG_START) { 40331ae08745Sheppo DWARN(DBG_ALL_LDCS, 40341ae08745Sheppo "ldc_read:(0x%llx) unexpected pkt" 40351ae08745Sheppo " env=0x%x discarding %d bytes," 40361ae08745Sheppo " lastmsg=%d, currentmsg=%d\n", 40371ae08745Sheppo ldcp->id, msg->env&LDC_FRAG_MASK, 40381ae08745Sheppo bytes_read, ldcp->last_msg_rcd, 40391ae08745Sheppo msg->seqid); 40401ae08745Sheppo 40411ae08745Sheppo /* throw data we have read so far */ 40421ae08745Sheppo bytes_read = 0; 40431ae08745Sheppo target = target_bufp; 4044d10e4ef2Snarayan first_fragment = msg->seqid; 40451ae08745Sheppo 4046*58283286Sha137994 if (rv = ldcp->readq_set_head(ldcp, 40471ae08745Sheppo curr_head)) 40481ae08745Sheppo break; 40491ae08745Sheppo } 40501ae08745Sheppo } 40511ae08745Sheppo 40521ae08745Sheppo /* copy (next) pkt into buffer */ 40531ae08745Sheppo if (len <= (*sizep - bytes_read)) { 40541ae08745Sheppo bcopy(msgbuf, target, len); 40551ae08745Sheppo target += len; 40561ae08745Sheppo bytes_read += len; 40571ae08745Sheppo } else { 40581ae08745Sheppo /* 40591ae08745Sheppo * there is not enough space in the buffer to 40601ae08745Sheppo * read this pkt. throw message away & continue 40611ae08745Sheppo * reading data from queue 40621ae08745Sheppo */ 40631ae08745Sheppo DWARN(DBG_ALL_LDCS, 40641ae08745Sheppo "ldc_read: (0x%llx) buffer too small, " 40651ae08745Sheppo "head=0x%lx, expect=%d, got=%d\n", ldcp->id, 40661ae08745Sheppo curr_head, *sizep, bytes_read+len); 40671ae08745Sheppo 4068d10e4ef2Snarayan first_fragment = 0; 40691ae08745Sheppo target = target_bufp; 40701ae08745Sheppo bytes_read = 0; 40711ae08745Sheppo 40721ae08745Sheppo /* throw away everything received so far */ 4073*58283286Sha137994 if (rv = ldcp->readq_set_head(ldcp, curr_head)) 40741ae08745Sheppo break; 40751ae08745Sheppo 40761ae08745Sheppo /* continue reading remaining pkts */ 40771ae08745Sheppo continue; 40781ae08745Sheppo } 40791ae08745Sheppo } 40801ae08745Sheppo 40811ae08745Sheppo /* set the message id */ 4082*58283286Sha137994 if (ldcp->mode != LDC_MODE_STREAM) 40831ae08745Sheppo ldcp->last_msg_rcd = msg->seqid; 40841ae08745Sheppo 40851ae08745Sheppo /* move the head one position */ 40861ae08745Sheppo curr_head = (curr_head + LDC_PACKET_SIZE) & q_size_mask; 40871ae08745Sheppo 40881ae08745Sheppo if (msg->env & LDC_FRAG_STOP) { 40891ae08745Sheppo 40901ae08745Sheppo /* 40911ae08745Sheppo * All pkts that are part of this fragmented transfer 40921ae08745Sheppo * have been read or this was a single pkt read 40931ae08745Sheppo * or there was an error 40941ae08745Sheppo */ 40951ae08745Sheppo 40961ae08745Sheppo /* set the queue head */ 4097*58283286Sha137994 if (rv = ldcp->readq_set_head(ldcp, curr_head)) 40981ae08745Sheppo bytes_read = 0; 40991ae08745Sheppo 41001ae08745Sheppo *sizep = bytes_read; 41011ae08745Sheppo 41021ae08745Sheppo break; 41031ae08745Sheppo } 41041ae08745Sheppo 4105332608acSnarayan /* advance head if it is a CTRL packet or a DATA ACK packet */ 4106332608acSnarayan if ((msg->type & LDC_CTRL) || 4107332608acSnarayan ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK))) { 41081ae08745Sheppo 41091ae08745Sheppo /* set the queue head */ 4110*58283286Sha137994 if (rv = ldcp->readq_set_head(ldcp, curr_head)) { 41111ae08745Sheppo bytes_read = 0; 41121ae08745Sheppo break; 41131ae08745Sheppo } 41141ae08745Sheppo 41151ae08745Sheppo D2(ldcp->id, "ldc_read: (0x%llx) set ACK qhead 0x%llx", 41161ae08745Sheppo ldcp->id, curr_head); 41171ae08745Sheppo } 41181ae08745Sheppo 41191ae08745Sheppo } /* for (;;) */ 41201ae08745Sheppo 41211ae08745Sheppo D2(ldcp->id, "ldc_read: (0x%llx) end size=%d", ldcp->id, *sizep); 41221ae08745Sheppo 41231ae08745Sheppo return (rv); 41243af08d82Slm66018 41253af08d82Slm66018 channel_is_reset: 41263af08d82Slm66018 mutex_enter(&ldcp->tx_lock); 41273af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 41283af08d82Slm66018 mutex_exit(&ldcp->tx_lock); 41293af08d82Slm66018 return (ECONNRESET); 41301ae08745Sheppo } 41311ae08745Sheppo 41321ae08745Sheppo /* 41331ae08745Sheppo * Use underlying reliable packet mechanism to fetch 41341ae08745Sheppo * and buffer incoming packets so we can hand them back as 41351ae08745Sheppo * a basic byte stream. 41361ae08745Sheppo * 41371ae08745Sheppo * Enter and exit with ldcp->lock held by caller 41381ae08745Sheppo */ 41391ae08745Sheppo static int 41401ae08745Sheppo i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep) 41411ae08745Sheppo { 41421ae08745Sheppo int rv; 41431ae08745Sheppo size_t size; 41441ae08745Sheppo 41451ae08745Sheppo ASSERT(mutex_owned(&ldcp->lock)); 41461ae08745Sheppo 41471ae08745Sheppo D2(ldcp->id, "i_ldc_read_stream: (0x%llx) buffer size=%d", 41481ae08745Sheppo ldcp->id, *sizep); 41491ae08745Sheppo 41501ae08745Sheppo if (ldcp->stream_remains == 0) { 41511ae08745Sheppo size = ldcp->mtu; 41521ae08745Sheppo rv = i_ldc_read_packet(ldcp, 41531ae08745Sheppo (caddr_t)ldcp->stream_bufferp, &size); 41541ae08745Sheppo D2(ldcp->id, "i_ldc_read_stream: read packet (0x%llx) size=%d", 41551ae08745Sheppo ldcp->id, size); 41561ae08745Sheppo 41571ae08745Sheppo if (rv != 0) 41581ae08745Sheppo return (rv); 41591ae08745Sheppo 41601ae08745Sheppo ldcp->stream_remains = size; 41611ae08745Sheppo ldcp->stream_offset = 0; 41621ae08745Sheppo } 41631ae08745Sheppo 41641ae08745Sheppo size = MIN(ldcp->stream_remains, *sizep); 41651ae08745Sheppo 41661ae08745Sheppo bcopy(ldcp->stream_bufferp + ldcp->stream_offset, target_bufp, size); 41671ae08745Sheppo ldcp->stream_offset += size; 41681ae08745Sheppo ldcp->stream_remains -= size; 41691ae08745Sheppo 41701ae08745Sheppo D2(ldcp->id, "i_ldc_read_stream: (0x%llx) fill from buffer size=%d", 41711ae08745Sheppo ldcp->id, size); 41721ae08745Sheppo 41731ae08745Sheppo *sizep = size; 41741ae08745Sheppo return (0); 41751ae08745Sheppo } 41761ae08745Sheppo 41771ae08745Sheppo /* 41781ae08745Sheppo * Write specified amount of bytes to the channel 41791ae08745Sheppo * in multiple pkts of pkt_payload size. Each 41801ae08745Sheppo * packet is tagged with an unique packet ID in 4181e1ebb9ecSlm66018 * the case of a reliable link. 41821ae08745Sheppo * 41831ae08745Sheppo * On return, size contains the number of bytes written. 41841ae08745Sheppo */ 41851ae08745Sheppo int 41861ae08745Sheppo ldc_write(ldc_handle_t handle, caddr_t buf, size_t *sizep) 41871ae08745Sheppo { 41881ae08745Sheppo ldc_chan_t *ldcp; 41891ae08745Sheppo int rv = 0; 41901ae08745Sheppo 41911ae08745Sheppo if (handle == NULL) { 41921ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_write: invalid channel handle\n"); 41931ae08745Sheppo return (EINVAL); 41941ae08745Sheppo } 41951ae08745Sheppo ldcp = (ldc_chan_t *)handle; 41961ae08745Sheppo 4197d10e4ef2Snarayan /* check if writes can occur */ 4198d10e4ef2Snarayan if (!mutex_tryenter(&ldcp->tx_lock)) { 4199d10e4ef2Snarayan /* 4200d10e4ef2Snarayan * Could not get the lock - channel could 4201d10e4ef2Snarayan * be in the process of being unconfigured 4202d10e4ef2Snarayan * or reader has encountered an error 4203d10e4ef2Snarayan */ 4204d10e4ef2Snarayan return (EAGAIN); 4205d10e4ef2Snarayan } 42061ae08745Sheppo 42071ae08745Sheppo /* check if non-zero data to write */ 42081ae08745Sheppo if (buf == NULL || sizep == NULL) { 42091ae08745Sheppo DWARN(ldcp->id, "ldc_write: (0x%llx) invalid data write\n", 42101ae08745Sheppo ldcp->id); 4211d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 42121ae08745Sheppo return (EINVAL); 42131ae08745Sheppo } 42141ae08745Sheppo 42151ae08745Sheppo if (*sizep == 0) { 42161ae08745Sheppo DWARN(ldcp->id, "ldc_write: (0x%llx) write size of zero\n", 42171ae08745Sheppo ldcp->id); 4218d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 42191ae08745Sheppo return (0); 42201ae08745Sheppo } 42211ae08745Sheppo 42221ae08745Sheppo /* Check if channel is UP for data exchange */ 42231ae08745Sheppo if (ldcp->tstate != TS_UP) { 42241ae08745Sheppo DWARN(ldcp->id, 42251ae08745Sheppo "ldc_write: (0x%llx) channel is not in UP state\n", 42261ae08745Sheppo ldcp->id); 42271ae08745Sheppo *sizep = 0; 42281ae08745Sheppo rv = ECONNRESET; 42291ae08745Sheppo } else { 42301ae08745Sheppo rv = ldcp->write_p(ldcp, buf, sizep); 42311ae08745Sheppo } 42321ae08745Sheppo 4233d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 42341ae08745Sheppo 42351ae08745Sheppo return (rv); 42361ae08745Sheppo } 42371ae08745Sheppo 42381ae08745Sheppo /* 42391ae08745Sheppo * Write a raw packet to the channel 42401ae08745Sheppo * On return, size contains the number of bytes written. 42411ae08745Sheppo */ 42421ae08745Sheppo static int 42431ae08745Sheppo i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep) 42441ae08745Sheppo { 42451ae08745Sheppo ldc_msg_t *ldcmsg; 42461ae08745Sheppo uint64_t tx_head, tx_tail, new_tail; 42471ae08745Sheppo int rv = 0; 42481ae08745Sheppo size_t size; 42491ae08745Sheppo 4250d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 42511ae08745Sheppo ASSERT(ldcp->mode == LDC_MODE_RAW); 42521ae08745Sheppo 42531ae08745Sheppo size = *sizep; 42541ae08745Sheppo 42551ae08745Sheppo /* 42561ae08745Sheppo * Check to see if the packet size is less than or 42571ae08745Sheppo * equal to packet size support in raw mode 42581ae08745Sheppo */ 42591ae08745Sheppo if (size > ldcp->pkt_payload) { 42601ae08745Sheppo DWARN(ldcp->id, 42611ae08745Sheppo "ldc_write: (0x%llx) invalid size (0x%llx) for RAW mode\n", 42621ae08745Sheppo ldcp->id, *sizep); 42631ae08745Sheppo *sizep = 0; 42641ae08745Sheppo return (EMSGSIZE); 42651ae08745Sheppo } 42661ae08745Sheppo 42671ae08745Sheppo /* get the qptrs for the tx queue */ 42681ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 42691ae08745Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 42701ae08745Sheppo if (rv != 0) { 42711ae08745Sheppo cmn_err(CE_WARN, 42721ae08745Sheppo "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id); 42731ae08745Sheppo *sizep = 0; 42741ae08745Sheppo return (EIO); 42751ae08745Sheppo } 42761ae08745Sheppo 42771ae08745Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN || 42781ae08745Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 42791ae08745Sheppo DWARN(ldcp->id, 42801ae08745Sheppo "ldc_write: (0x%llx) channel down/reset\n", ldcp->id); 4281d10e4ef2Snarayan 42821ae08745Sheppo *sizep = 0; 4283d10e4ef2Snarayan if (mutex_tryenter(&ldcp->lock)) { 42843af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 4285d10e4ef2Snarayan mutex_exit(&ldcp->lock); 4286d10e4ef2Snarayan } else { 4287d10e4ef2Snarayan /* 4288d10e4ef2Snarayan * Release Tx lock, and then reacquire channel 4289d10e4ef2Snarayan * and Tx lock in correct order 4290d10e4ef2Snarayan */ 4291d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 4292d10e4ef2Snarayan mutex_enter(&ldcp->lock); 4293d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 42943af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 4295d10e4ef2Snarayan mutex_exit(&ldcp->lock); 4296d10e4ef2Snarayan } 42971ae08745Sheppo return (ECONNRESET); 42981ae08745Sheppo } 42991ae08745Sheppo 43001ae08745Sheppo tx_tail = ldcp->tx_tail; 43011ae08745Sheppo tx_head = ldcp->tx_head; 43021ae08745Sheppo new_tail = (tx_tail + LDC_PACKET_SIZE) & 43031ae08745Sheppo ((ldcp->tx_q_entries-1) << LDC_PACKET_SHIFT); 43041ae08745Sheppo 43051ae08745Sheppo if (new_tail == tx_head) { 43061ae08745Sheppo DWARN(DBG_ALL_LDCS, 43071ae08745Sheppo "ldc_write: (0x%llx) TX queue is full\n", ldcp->id); 43081ae08745Sheppo *sizep = 0; 43091ae08745Sheppo return (EWOULDBLOCK); 43101ae08745Sheppo } 43111ae08745Sheppo 43121ae08745Sheppo D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d", 43131ae08745Sheppo ldcp->id, size); 43141ae08745Sheppo 43151ae08745Sheppo /* Send the data now */ 43161ae08745Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 43171ae08745Sheppo 43181ae08745Sheppo /* copy the data into pkt */ 43191ae08745Sheppo bcopy((uint8_t *)buf, ldcmsg, size); 43201ae08745Sheppo 43211ae08745Sheppo /* increment tail */ 43221ae08745Sheppo tx_tail = new_tail; 43231ae08745Sheppo 43241ae08745Sheppo /* 43251ae08745Sheppo * All packets have been copied into the TX queue 43261ae08745Sheppo * update the tail ptr in the HV 43271ae08745Sheppo */ 43281ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 43291ae08745Sheppo if (rv) { 43301ae08745Sheppo if (rv == EWOULDBLOCK) { 43311ae08745Sheppo DWARN(ldcp->id, "ldc_write: (0x%llx) write timed out\n", 43321ae08745Sheppo ldcp->id); 43331ae08745Sheppo *sizep = 0; 43341ae08745Sheppo return (EWOULDBLOCK); 43351ae08745Sheppo } 43361ae08745Sheppo 43371ae08745Sheppo *sizep = 0; 4338d10e4ef2Snarayan if (mutex_tryenter(&ldcp->lock)) { 43393af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 4340d10e4ef2Snarayan mutex_exit(&ldcp->lock); 4341d10e4ef2Snarayan } else { 4342d10e4ef2Snarayan /* 4343d10e4ef2Snarayan * Release Tx lock, and then reacquire channel 4344d10e4ef2Snarayan * and Tx lock in correct order 4345d10e4ef2Snarayan */ 4346d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 4347d10e4ef2Snarayan mutex_enter(&ldcp->lock); 4348d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 43493af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 4350d10e4ef2Snarayan mutex_exit(&ldcp->lock); 4351d10e4ef2Snarayan } 43521ae08745Sheppo return (ECONNRESET); 43531ae08745Sheppo } 43541ae08745Sheppo 43551ae08745Sheppo ldcp->tx_tail = tx_tail; 43561ae08745Sheppo *sizep = size; 43571ae08745Sheppo 43581ae08745Sheppo D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, size); 43591ae08745Sheppo 43601ae08745Sheppo return (rv); 43611ae08745Sheppo } 43621ae08745Sheppo 43631ae08745Sheppo 43641ae08745Sheppo /* 43651ae08745Sheppo * Write specified amount of bytes to the channel 43661ae08745Sheppo * in multiple pkts of pkt_payload size. Each 43671ae08745Sheppo * packet is tagged with an unique packet ID in 4368e1ebb9ecSlm66018 * the case of a reliable link. 43691ae08745Sheppo * 43701ae08745Sheppo * On return, size contains the number of bytes written. 43711ae08745Sheppo * This function needs to ensure that the write size is < MTU size 43721ae08745Sheppo */ 43731ae08745Sheppo static int 43741ae08745Sheppo i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t buf, size_t *size) 43751ae08745Sheppo { 43761ae08745Sheppo ldc_msg_t *ldcmsg; 43771ae08745Sheppo uint64_t tx_head, tx_tail, new_tail, start; 43781ae08745Sheppo uint64_t txq_size_mask, numavail; 43791ae08745Sheppo uint8_t *msgbuf, *source = (uint8_t *)buf; 43801ae08745Sheppo size_t len, bytes_written = 0, remaining; 43811ae08745Sheppo int rv; 43821ae08745Sheppo uint32_t curr_seqid; 43831ae08745Sheppo 4384d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 43851ae08745Sheppo 43861ae08745Sheppo ASSERT(ldcp->mode == LDC_MODE_RELIABLE || 43871ae08745Sheppo ldcp->mode == LDC_MODE_UNRELIABLE || 43881ae08745Sheppo ldcp->mode == LDC_MODE_STREAM); 43891ae08745Sheppo 43901ae08745Sheppo /* compute mask for increment */ 43911ae08745Sheppo txq_size_mask = (ldcp->tx_q_entries - 1) << LDC_PACKET_SHIFT; 43921ae08745Sheppo 43931ae08745Sheppo /* get the qptrs for the tx queue */ 43941ae08745Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 43951ae08745Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 43961ae08745Sheppo if (rv != 0) { 43971ae08745Sheppo cmn_err(CE_WARN, 43981ae08745Sheppo "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id); 43991ae08745Sheppo *size = 0; 44001ae08745Sheppo return (EIO); 44011ae08745Sheppo } 44021ae08745Sheppo 44031ae08745Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN || 44041ae08745Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 44051ae08745Sheppo DWARN(ldcp->id, 44061ae08745Sheppo "ldc_write: (0x%llx) channel down/reset\n", ldcp->id); 44071ae08745Sheppo *size = 0; 4408d10e4ef2Snarayan if (mutex_tryenter(&ldcp->lock)) { 44093af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 4410d10e4ef2Snarayan mutex_exit(&ldcp->lock); 4411d10e4ef2Snarayan } else { 4412d10e4ef2Snarayan /* 4413d10e4ef2Snarayan * Release Tx lock, and then reacquire channel 4414d10e4ef2Snarayan * and Tx lock in correct order 4415d10e4ef2Snarayan */ 4416d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 4417d10e4ef2Snarayan mutex_enter(&ldcp->lock); 4418d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 44193af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 4420d10e4ef2Snarayan mutex_exit(&ldcp->lock); 4421d10e4ef2Snarayan } 44221ae08745Sheppo return (ECONNRESET); 44231ae08745Sheppo } 44241ae08745Sheppo 44251ae08745Sheppo tx_tail = ldcp->tx_tail; 44261ae08745Sheppo new_tail = (tx_tail + LDC_PACKET_SIZE) % 44271ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 44281ae08745Sheppo 44291ae08745Sheppo /* 443022f747efSnarayan * Check to see if the queue is full. The check is done using 443122f747efSnarayan * the appropriate head based on the link mode. 44321ae08745Sheppo */ 443322f747efSnarayan i_ldc_get_tx_head(ldcp, &tx_head); 443422f747efSnarayan 44351ae08745Sheppo if (new_tail == tx_head) { 44361ae08745Sheppo DWARN(DBG_ALL_LDCS, 44371ae08745Sheppo "ldc_write: (0x%llx) TX queue is full\n", ldcp->id); 44381ae08745Sheppo *size = 0; 44391ae08745Sheppo return (EWOULDBLOCK); 44401ae08745Sheppo } 44411ae08745Sheppo 44421ae08745Sheppo /* 44431ae08745Sheppo * Make sure that the LDC Tx queue has enough space 44441ae08745Sheppo */ 44451ae08745Sheppo numavail = (tx_head >> LDC_PACKET_SHIFT) - (tx_tail >> LDC_PACKET_SHIFT) 44461ae08745Sheppo + ldcp->tx_q_entries - 1; 44471ae08745Sheppo numavail %= ldcp->tx_q_entries; 44481ae08745Sheppo 44491ae08745Sheppo if (*size > (numavail * ldcp->pkt_payload)) { 44501ae08745Sheppo DWARN(DBG_ALL_LDCS, 44511ae08745Sheppo "ldc_write: (0x%llx) TX queue has no space\n", ldcp->id); 44521ae08745Sheppo return (EWOULDBLOCK); 44531ae08745Sheppo } 44541ae08745Sheppo 44551ae08745Sheppo D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d", 44561ae08745Sheppo ldcp->id, *size); 44571ae08745Sheppo 44581ae08745Sheppo /* Send the data now */ 44591ae08745Sheppo bytes_written = 0; 44601ae08745Sheppo curr_seqid = ldcp->last_msg_snt; 44611ae08745Sheppo start = tx_tail; 44621ae08745Sheppo 44631ae08745Sheppo while (*size > bytes_written) { 44641ae08745Sheppo 44651ae08745Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 44661ae08745Sheppo 44671ae08745Sheppo msgbuf = (uint8_t *)((ldcp->mode == LDC_MODE_RELIABLE || 446822f747efSnarayan ldcp->mode == LDC_MODE_STREAM) ? 446922f747efSnarayan ldcmsg->rdata : ldcmsg->udata); 44701ae08745Sheppo 44711ae08745Sheppo ldcmsg->type = LDC_DATA; 44721ae08745Sheppo ldcmsg->stype = LDC_INFO; 44731ae08745Sheppo ldcmsg->ctrl = 0; 44741ae08745Sheppo 44751ae08745Sheppo remaining = *size - bytes_written; 44761ae08745Sheppo len = min(ldcp->pkt_payload, remaining); 44771ae08745Sheppo ldcmsg->env = (uint8_t)len; 44781ae08745Sheppo 44791ae08745Sheppo curr_seqid++; 44801ae08745Sheppo ldcmsg->seqid = curr_seqid; 44811ae08745Sheppo 44821ae08745Sheppo /* copy the data into pkt */ 44831ae08745Sheppo bcopy(source, msgbuf, len); 44841ae08745Sheppo 44851ae08745Sheppo source += len; 44861ae08745Sheppo bytes_written += len; 44871ae08745Sheppo 44881ae08745Sheppo /* increment tail */ 44891ae08745Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) & txq_size_mask; 44901ae08745Sheppo 44911ae08745Sheppo ASSERT(tx_tail != tx_head); 44921ae08745Sheppo } 44931ae08745Sheppo 44941ae08745Sheppo /* Set the start and stop bits */ 44951ae08745Sheppo ldcmsg->env |= LDC_FRAG_STOP; 44961ae08745Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + start); 44971ae08745Sheppo ldcmsg->env |= LDC_FRAG_START; 44981ae08745Sheppo 44991ae08745Sheppo /* 45001ae08745Sheppo * All packets have been copied into the TX queue 45011ae08745Sheppo * update the tail ptr in the HV 45021ae08745Sheppo */ 45031ae08745Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 45041ae08745Sheppo if (rv == 0) { 45051ae08745Sheppo ldcp->tx_tail = tx_tail; 45061ae08745Sheppo ldcp->last_msg_snt = curr_seqid; 45071ae08745Sheppo *size = bytes_written; 45081ae08745Sheppo } else { 45091ae08745Sheppo int rv2; 45101ae08745Sheppo 45111ae08745Sheppo if (rv != EWOULDBLOCK) { 45121ae08745Sheppo *size = 0; 4513d10e4ef2Snarayan if (mutex_tryenter(&ldcp->lock)) { 45143af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 4515d10e4ef2Snarayan mutex_exit(&ldcp->lock); 4516d10e4ef2Snarayan } else { 4517d10e4ef2Snarayan /* 4518d10e4ef2Snarayan * Release Tx lock, and then reacquire channel 4519d10e4ef2Snarayan * and Tx lock in correct order 4520d10e4ef2Snarayan */ 4521d10e4ef2Snarayan mutex_exit(&ldcp->tx_lock); 4522d10e4ef2Snarayan mutex_enter(&ldcp->lock); 4523d10e4ef2Snarayan mutex_enter(&ldcp->tx_lock); 45243af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 4525d10e4ef2Snarayan mutex_exit(&ldcp->lock); 4526d10e4ef2Snarayan } 45271ae08745Sheppo return (ECONNRESET); 45281ae08745Sheppo } 45291ae08745Sheppo 4530cb112a14Slm66018 D1(ldcp->id, "hv_tx_set_tail returns 0x%x (head 0x%x, " 45311ae08745Sheppo "old tail 0x%x, new tail 0x%x, qsize=0x%x)\n", 45321ae08745Sheppo rv, ldcp->tx_head, ldcp->tx_tail, tx_tail, 45331ae08745Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT)); 45341ae08745Sheppo 45351ae08745Sheppo rv2 = hv_ldc_tx_get_state(ldcp->id, 45361ae08745Sheppo &tx_head, &tx_tail, &ldcp->link_state); 45371ae08745Sheppo 4538cb112a14Slm66018 D1(ldcp->id, "hv_ldc_tx_get_state returns 0x%x " 45391ae08745Sheppo "(head 0x%x, tail 0x%x state 0x%x)\n", 45401ae08745Sheppo rv2, tx_head, tx_tail, ldcp->link_state); 45411ae08745Sheppo 45421ae08745Sheppo *size = 0; 45431ae08745Sheppo } 45441ae08745Sheppo 45451ae08745Sheppo D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, *size); 45461ae08745Sheppo 45471ae08745Sheppo return (rv); 45481ae08745Sheppo } 45491ae08745Sheppo 45501ae08745Sheppo /* 45511ae08745Sheppo * Write specified amount of bytes to the channel 45521ae08745Sheppo * in multiple pkts of pkt_payload size. Each 45531ae08745Sheppo * packet is tagged with an unique packet ID in 4554e1ebb9ecSlm66018 * the case of a reliable link. 45551ae08745Sheppo * 45561ae08745Sheppo * On return, size contains the number of bytes written. 45571ae08745Sheppo * This function needs to ensure that the write size is < MTU size 45581ae08745Sheppo */ 45591ae08745Sheppo static int 45601ae08745Sheppo i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep) 45611ae08745Sheppo { 4562d10e4ef2Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 45631ae08745Sheppo ASSERT(ldcp->mode == LDC_MODE_STREAM); 45641ae08745Sheppo 45651ae08745Sheppo /* Truncate packet to max of MTU size */ 45661ae08745Sheppo if (*sizep > ldcp->mtu) *sizep = ldcp->mtu; 45671ae08745Sheppo return (i_ldc_write_packet(ldcp, buf, sizep)); 45681ae08745Sheppo } 45691ae08745Sheppo 45701ae08745Sheppo 45711ae08745Sheppo /* 45721ae08745Sheppo * Interfaces for channel nexus to register/unregister with LDC module 45731ae08745Sheppo * The nexus will register functions to be used to register individual 45741ae08745Sheppo * channels with the nexus and enable interrupts for the channels 45751ae08745Sheppo */ 45761ae08745Sheppo int 45771ae08745Sheppo ldc_register(ldc_cnex_t *cinfo) 45781ae08745Sheppo { 45791ae08745Sheppo ldc_chan_t *ldcp; 45801ae08745Sheppo 45811ae08745Sheppo if (cinfo == NULL || cinfo->dip == NULL || 45821ae08745Sheppo cinfo->reg_chan == NULL || cinfo->unreg_chan == NULL || 45831ae08745Sheppo cinfo->add_intr == NULL || cinfo->rem_intr == NULL || 45841ae08745Sheppo cinfo->clr_intr == NULL) { 45851ae08745Sheppo 45861ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_register: invalid nexus info\n"); 45871ae08745Sheppo return (EINVAL); 45881ae08745Sheppo } 45891ae08745Sheppo 45901ae08745Sheppo mutex_enter(&ldcssp->lock); 45911ae08745Sheppo 45921ae08745Sheppo /* nexus registration */ 45931ae08745Sheppo ldcssp->cinfo.dip = cinfo->dip; 45941ae08745Sheppo ldcssp->cinfo.reg_chan = cinfo->reg_chan; 45951ae08745Sheppo ldcssp->cinfo.unreg_chan = cinfo->unreg_chan; 45961ae08745Sheppo ldcssp->cinfo.add_intr = cinfo->add_intr; 45971ae08745Sheppo ldcssp->cinfo.rem_intr = cinfo->rem_intr; 45981ae08745Sheppo ldcssp->cinfo.clr_intr = cinfo->clr_intr; 45991ae08745Sheppo 46001ae08745Sheppo /* register any channels that might have been previously initialized */ 46011ae08745Sheppo ldcp = ldcssp->chan_list; 46021ae08745Sheppo while (ldcp) { 46031ae08745Sheppo if ((ldcp->tstate & TS_QCONF_RDY) && 46041ae08745Sheppo (ldcp->tstate & TS_CNEX_RDY) == 0) 46051ae08745Sheppo (void) i_ldc_register_channel(ldcp); 46061ae08745Sheppo 46071ae08745Sheppo ldcp = ldcp->next; 46081ae08745Sheppo } 46091ae08745Sheppo 46101ae08745Sheppo mutex_exit(&ldcssp->lock); 46111ae08745Sheppo 46121ae08745Sheppo return (0); 46131ae08745Sheppo } 46141ae08745Sheppo 46151ae08745Sheppo int 46161ae08745Sheppo ldc_unregister(ldc_cnex_t *cinfo) 46171ae08745Sheppo { 46181ae08745Sheppo if (cinfo == NULL || cinfo->dip == NULL) { 46191ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid nexus info\n"); 46201ae08745Sheppo return (EINVAL); 46211ae08745Sheppo } 46221ae08745Sheppo 46231ae08745Sheppo mutex_enter(&ldcssp->lock); 46241ae08745Sheppo 46251ae08745Sheppo if (cinfo->dip != ldcssp->cinfo.dip) { 46261ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid dip\n"); 46271ae08745Sheppo mutex_exit(&ldcssp->lock); 46281ae08745Sheppo return (EINVAL); 46291ae08745Sheppo } 46301ae08745Sheppo 46311ae08745Sheppo /* nexus unregister */ 46321ae08745Sheppo ldcssp->cinfo.dip = NULL; 46331ae08745Sheppo ldcssp->cinfo.reg_chan = NULL; 46341ae08745Sheppo ldcssp->cinfo.unreg_chan = NULL; 46351ae08745Sheppo ldcssp->cinfo.add_intr = NULL; 46361ae08745Sheppo ldcssp->cinfo.rem_intr = NULL; 46371ae08745Sheppo ldcssp->cinfo.clr_intr = NULL; 46381ae08745Sheppo 46391ae08745Sheppo mutex_exit(&ldcssp->lock); 46401ae08745Sheppo 46411ae08745Sheppo return (0); 46421ae08745Sheppo } 46431ae08745Sheppo 46441ae08745Sheppo 46451ae08745Sheppo /* ------------------------------------------------------------------------- */ 46461ae08745Sheppo 46471ae08745Sheppo /* 46481ae08745Sheppo * Allocate a memory handle for the channel and link it into the list 46491ae08745Sheppo * Also choose which memory table to use if this is the first handle 46501ae08745Sheppo * being assigned to this channel 46511ae08745Sheppo */ 46521ae08745Sheppo int 46531ae08745Sheppo ldc_mem_alloc_handle(ldc_handle_t handle, ldc_mem_handle_t *mhandle) 46541ae08745Sheppo { 46551ae08745Sheppo ldc_chan_t *ldcp; 46561ae08745Sheppo ldc_mhdl_t *mhdl; 46571ae08745Sheppo 46581ae08745Sheppo if (handle == NULL) { 46591ae08745Sheppo DWARN(DBG_ALL_LDCS, 46601ae08745Sheppo "ldc_mem_alloc_handle: invalid channel handle\n"); 46611ae08745Sheppo return (EINVAL); 46621ae08745Sheppo } 46631ae08745Sheppo ldcp = (ldc_chan_t *)handle; 46641ae08745Sheppo 46651ae08745Sheppo mutex_enter(&ldcp->lock); 46661ae08745Sheppo 46671ae08745Sheppo /* check to see if channel is initalized */ 46683af08d82Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) < TS_INIT) { 46691ae08745Sheppo DWARN(ldcp->id, 46701ae08745Sheppo "ldc_mem_alloc_handle: (0x%llx) channel not initialized\n", 46711ae08745Sheppo ldcp->id); 46721ae08745Sheppo mutex_exit(&ldcp->lock); 46731ae08745Sheppo return (EINVAL); 46741ae08745Sheppo } 46751ae08745Sheppo 46761ae08745Sheppo /* allocate handle for channel */ 46774bac2208Snarayan mhdl = kmem_cache_alloc(ldcssp->memhdl_cache, KM_SLEEP); 46781ae08745Sheppo 46791ae08745Sheppo /* initialize the lock */ 46801ae08745Sheppo mutex_init(&mhdl->lock, NULL, MUTEX_DRIVER, NULL); 46811ae08745Sheppo 46824bac2208Snarayan mhdl->myshadow = B_FALSE; 46834bac2208Snarayan mhdl->memseg = NULL; 46841ae08745Sheppo mhdl->ldcp = ldcp; 46854bac2208Snarayan mhdl->status = LDC_UNBOUND; 46861ae08745Sheppo 46871ae08745Sheppo /* insert memory handle (@ head) into list */ 46881ae08745Sheppo if (ldcp->mhdl_list == NULL) { 46891ae08745Sheppo ldcp->mhdl_list = mhdl; 46901ae08745Sheppo mhdl->next = NULL; 46911ae08745Sheppo } else { 46921ae08745Sheppo /* insert @ head */ 46931ae08745Sheppo mhdl->next = ldcp->mhdl_list; 46941ae08745Sheppo ldcp->mhdl_list = mhdl; 46951ae08745Sheppo } 46961ae08745Sheppo 46971ae08745Sheppo /* return the handle */ 46981ae08745Sheppo *mhandle = (ldc_mem_handle_t)mhdl; 46991ae08745Sheppo 47001ae08745Sheppo mutex_exit(&ldcp->lock); 47011ae08745Sheppo 47021ae08745Sheppo D1(ldcp->id, "ldc_mem_alloc_handle: (0x%llx) allocated handle 0x%llx\n", 47031ae08745Sheppo ldcp->id, mhdl); 47041ae08745Sheppo 47051ae08745Sheppo return (0); 47061ae08745Sheppo } 47071ae08745Sheppo 47081ae08745Sheppo /* 47091ae08745Sheppo * Free memory handle for the channel and unlink it from the list 47101ae08745Sheppo */ 47111ae08745Sheppo int 47121ae08745Sheppo ldc_mem_free_handle(ldc_mem_handle_t mhandle) 47131ae08745Sheppo { 47141ae08745Sheppo ldc_mhdl_t *mhdl, *phdl; 47151ae08745Sheppo ldc_chan_t *ldcp; 47161ae08745Sheppo 47171ae08745Sheppo if (mhandle == NULL) { 47181ae08745Sheppo DWARN(DBG_ALL_LDCS, 47191ae08745Sheppo "ldc_mem_free_handle: invalid memory handle\n"); 47201ae08745Sheppo return (EINVAL); 47211ae08745Sheppo } 47221ae08745Sheppo mhdl = (ldc_mhdl_t *)mhandle; 47231ae08745Sheppo 47241ae08745Sheppo mutex_enter(&mhdl->lock); 47251ae08745Sheppo 47261ae08745Sheppo ldcp = mhdl->ldcp; 47271ae08745Sheppo 47281ae08745Sheppo if (mhdl->status == LDC_BOUND || mhdl->status == LDC_MAPPED) { 47291ae08745Sheppo DWARN(ldcp->id, 47301ae08745Sheppo "ldc_mem_free_handle: cannot free, 0x%llx hdl bound\n", 47311ae08745Sheppo mhdl); 47321ae08745Sheppo mutex_exit(&mhdl->lock); 47331ae08745Sheppo return (EINVAL); 47341ae08745Sheppo } 47351ae08745Sheppo mutex_exit(&mhdl->lock); 47361ae08745Sheppo 47371ae08745Sheppo mutex_enter(&ldcp->mlist_lock); 47381ae08745Sheppo 47391ae08745Sheppo phdl = ldcp->mhdl_list; 47401ae08745Sheppo 47411ae08745Sheppo /* first handle */ 47421ae08745Sheppo if (phdl == mhdl) { 47431ae08745Sheppo ldcp->mhdl_list = mhdl->next; 47441ae08745Sheppo mutex_destroy(&mhdl->lock); 47454bac2208Snarayan kmem_cache_free(ldcssp->memhdl_cache, mhdl); 47464bac2208Snarayan 47471ae08745Sheppo D1(ldcp->id, 47481ae08745Sheppo "ldc_mem_free_handle: (0x%llx) freed handle 0x%llx\n", 47491ae08745Sheppo ldcp->id, mhdl); 47501ae08745Sheppo } else { 47511ae08745Sheppo /* walk the list - unlink and free */ 47521ae08745Sheppo while (phdl != NULL) { 47531ae08745Sheppo if (phdl->next == mhdl) { 47541ae08745Sheppo phdl->next = mhdl->next; 47551ae08745Sheppo mutex_destroy(&mhdl->lock); 47564bac2208Snarayan kmem_cache_free(ldcssp->memhdl_cache, mhdl); 47571ae08745Sheppo D1(ldcp->id, 47581ae08745Sheppo "ldc_mem_free_handle: (0x%llx) freed " 47591ae08745Sheppo "handle 0x%llx\n", ldcp->id, mhdl); 47601ae08745Sheppo break; 47611ae08745Sheppo } 47621ae08745Sheppo phdl = phdl->next; 47631ae08745Sheppo } 47641ae08745Sheppo } 47651ae08745Sheppo 47661ae08745Sheppo if (phdl == NULL) { 47671ae08745Sheppo DWARN(ldcp->id, 47681ae08745Sheppo "ldc_mem_free_handle: invalid handle 0x%llx\n", mhdl); 47691ae08745Sheppo mutex_exit(&ldcp->mlist_lock); 47701ae08745Sheppo return (EINVAL); 47711ae08745Sheppo } 47721ae08745Sheppo 47731ae08745Sheppo mutex_exit(&ldcp->mlist_lock); 47741ae08745Sheppo 47751ae08745Sheppo return (0); 47761ae08745Sheppo } 47771ae08745Sheppo 47781ae08745Sheppo /* 47791ae08745Sheppo * Bind a memory handle to a virtual address. 47801ae08745Sheppo * The virtual address is converted to the corresponding real addresses. 47811ae08745Sheppo * Returns pointer to the first ldc_mem_cookie and the total number 47821ae08745Sheppo * of cookies for this virtual address. Other cookies can be obtained 47831ae08745Sheppo * using the ldc_mem_nextcookie() call. If the pages are stored in 47841ae08745Sheppo * consecutive locations in the table, a single cookie corresponding to 47851ae08745Sheppo * the first location is returned. The cookie size spans all the entries. 47861ae08745Sheppo * 47871ae08745Sheppo * If the VA corresponds to a page that is already being exported, reuse 47881ae08745Sheppo * the page and do not export it again. Bump the page's use count. 47891ae08745Sheppo */ 47901ae08745Sheppo int 47911ae08745Sheppo ldc_mem_bind_handle(ldc_mem_handle_t mhandle, caddr_t vaddr, size_t len, 47921ae08745Sheppo uint8_t mtype, uint8_t perm, ldc_mem_cookie_t *cookie, uint32_t *ccount) 47931ae08745Sheppo { 47941ae08745Sheppo ldc_mhdl_t *mhdl; 47951ae08745Sheppo ldc_chan_t *ldcp; 47961ae08745Sheppo ldc_mtbl_t *mtbl; 47971ae08745Sheppo ldc_memseg_t *memseg; 47981ae08745Sheppo ldc_mte_t tmp_mte; 47991ae08745Sheppo uint64_t index, prev_index = 0; 48001ae08745Sheppo int64_t cookie_idx; 48011ae08745Sheppo uintptr_t raddr, ra_aligned; 48021ae08745Sheppo uint64_t psize, poffset, v_offset; 48031ae08745Sheppo uint64_t pg_shift, pg_size, pg_size_code, pg_mask; 48041ae08745Sheppo pgcnt_t npages; 48051ae08745Sheppo caddr_t v_align, addr; 48064bac2208Snarayan int i, rv; 48071ae08745Sheppo 48081ae08745Sheppo if (mhandle == NULL) { 48091ae08745Sheppo DWARN(DBG_ALL_LDCS, 48101ae08745Sheppo "ldc_mem_bind_handle: invalid memory handle\n"); 48111ae08745Sheppo return (EINVAL); 48121ae08745Sheppo } 48131ae08745Sheppo mhdl = (ldc_mhdl_t *)mhandle; 48141ae08745Sheppo ldcp = mhdl->ldcp; 48151ae08745Sheppo 48161ae08745Sheppo /* clear count */ 48171ae08745Sheppo *ccount = 0; 48181ae08745Sheppo 48191ae08745Sheppo mutex_enter(&mhdl->lock); 48201ae08745Sheppo 48211ae08745Sheppo if (mhdl->status == LDC_BOUND || mhdl->memseg != NULL) { 48221ae08745Sheppo DWARN(ldcp->id, 48231ae08745Sheppo "ldc_mem_bind_handle: (0x%x) handle already bound\n", 48241ae08745Sheppo mhandle); 48251ae08745Sheppo mutex_exit(&mhdl->lock); 48261ae08745Sheppo return (EINVAL); 48271ae08745Sheppo } 48281ae08745Sheppo 48291ae08745Sheppo /* Force address and size to be 8-byte aligned */ 48301ae08745Sheppo if ((((uintptr_t)vaddr | len) & 0x7) != 0) { 48311ae08745Sheppo DWARN(ldcp->id, 48321ae08745Sheppo "ldc_mem_bind_handle: addr/size is not 8-byte aligned\n"); 48331ae08745Sheppo mutex_exit(&mhdl->lock); 48341ae08745Sheppo return (EINVAL); 48351ae08745Sheppo } 48361ae08745Sheppo 48374bac2208Snarayan /* 48384bac2208Snarayan * If this channel is binding a memory handle for the 48394bac2208Snarayan * first time allocate it a memory map table and initialize it 48404bac2208Snarayan */ 48414bac2208Snarayan if ((mtbl = ldcp->mtbl) == NULL) { 48424bac2208Snarayan 48434bac2208Snarayan mutex_enter(&ldcp->lock); 48444bac2208Snarayan 48454bac2208Snarayan /* Allocate and initialize the map table structure */ 48464bac2208Snarayan mtbl = kmem_zalloc(sizeof (ldc_mtbl_t), KM_SLEEP); 48474bac2208Snarayan mtbl->num_entries = mtbl->num_avail = ldc_maptable_entries; 48484bac2208Snarayan mtbl->size = ldc_maptable_entries * sizeof (ldc_mte_slot_t); 48494bac2208Snarayan mtbl->next_entry = NULL; 48503af08d82Slm66018 mtbl->contigmem = B_TRUE; 48514bac2208Snarayan 48524bac2208Snarayan /* Allocate the table itself */ 48534bac2208Snarayan mtbl->table = (ldc_mte_slot_t *) 48544bac2208Snarayan contig_mem_alloc_align(mtbl->size, MMU_PAGESIZE); 48554bac2208Snarayan if (mtbl->table == NULL) { 48563af08d82Slm66018 48573af08d82Slm66018 /* allocate a page of memory using kmem_alloc */ 48583af08d82Slm66018 mtbl->table = kmem_alloc(MMU_PAGESIZE, KM_SLEEP); 48593af08d82Slm66018 mtbl->size = MMU_PAGESIZE; 48603af08d82Slm66018 mtbl->contigmem = B_FALSE; 48613af08d82Slm66018 mtbl->num_entries = mtbl->num_avail = 48623af08d82Slm66018 mtbl->size / sizeof (ldc_mte_slot_t); 48633af08d82Slm66018 DWARN(ldcp->id, 48643af08d82Slm66018 "ldc_mem_bind_handle: (0x%llx) reduced tbl size " 48653af08d82Slm66018 "to %lx entries\n", ldcp->id, mtbl->num_entries); 48664bac2208Snarayan } 48674bac2208Snarayan 48684bac2208Snarayan /* zero out the memory */ 48694bac2208Snarayan bzero(mtbl->table, mtbl->size); 48704bac2208Snarayan 48714bac2208Snarayan /* initialize the lock */ 48724bac2208Snarayan mutex_init(&mtbl->lock, NULL, MUTEX_DRIVER, NULL); 48734bac2208Snarayan 48744bac2208Snarayan /* register table for this channel */ 48754bac2208Snarayan rv = hv_ldc_set_map_table(ldcp->id, 48764bac2208Snarayan va_to_pa(mtbl->table), mtbl->num_entries); 48774bac2208Snarayan if (rv != 0) { 48784bac2208Snarayan cmn_err(CE_WARN, 48794bac2208Snarayan "ldc_mem_bind_handle: (0x%lx) err %d mapping tbl", 48804bac2208Snarayan ldcp->id, rv); 48813af08d82Slm66018 if (mtbl->contigmem) 48824bac2208Snarayan contig_mem_free(mtbl->table, mtbl->size); 48833af08d82Slm66018 else 48843af08d82Slm66018 kmem_free(mtbl->table, mtbl->size); 48854bac2208Snarayan mutex_destroy(&mtbl->lock); 48864bac2208Snarayan kmem_free(mtbl, sizeof (ldc_mtbl_t)); 48874bac2208Snarayan mutex_exit(&ldcp->lock); 48884bac2208Snarayan mutex_exit(&mhdl->lock); 48894bac2208Snarayan return (EIO); 48904bac2208Snarayan } 48914bac2208Snarayan 48924bac2208Snarayan ldcp->mtbl = mtbl; 48934bac2208Snarayan mutex_exit(&ldcp->lock); 48944bac2208Snarayan 48954bac2208Snarayan D1(ldcp->id, 48964bac2208Snarayan "ldc_mem_bind_handle: (0x%llx) alloc'd map table 0x%llx\n", 48974bac2208Snarayan ldcp->id, ldcp->mtbl->table); 48984bac2208Snarayan } 48994bac2208Snarayan 49001ae08745Sheppo /* FUTURE: get the page size, pgsz code, and shift */ 49011ae08745Sheppo pg_size = MMU_PAGESIZE; 49021ae08745Sheppo pg_size_code = page_szc(pg_size); 49031ae08745Sheppo pg_shift = page_get_shift(pg_size_code); 49041ae08745Sheppo pg_mask = ~(pg_size - 1); 49051ae08745Sheppo 49061ae08745Sheppo D1(ldcp->id, "ldc_mem_bind_handle: (0x%llx) binding " 49071ae08745Sheppo "va 0x%llx pgsz=0x%llx, pgszc=0x%llx, pg_shift=0x%llx\n", 49081ae08745Sheppo ldcp->id, vaddr, pg_size, pg_size_code, pg_shift); 49091ae08745Sheppo 49101ae08745Sheppo /* aligned VA and its offset */ 49111ae08745Sheppo v_align = (caddr_t)(((uintptr_t)vaddr) & ~(pg_size - 1)); 49121ae08745Sheppo v_offset = ((uintptr_t)vaddr) & (pg_size - 1); 49131ae08745Sheppo 49141ae08745Sheppo npages = (len+v_offset)/pg_size; 49151ae08745Sheppo npages = ((len+v_offset)%pg_size == 0) ? npages : npages+1; 49161ae08745Sheppo 49171ae08745Sheppo D1(ldcp->id, "ldc_mem_bind_handle: binding " 49181ae08745Sheppo "(0x%llx) v=0x%llx,val=0x%llx,off=0x%x,pgs=0x%x\n", 49191ae08745Sheppo ldcp->id, vaddr, v_align, v_offset, npages); 49201ae08745Sheppo 49211ae08745Sheppo /* lock the memory table - exclusive access to channel */ 49221ae08745Sheppo mutex_enter(&mtbl->lock); 49231ae08745Sheppo 49241ae08745Sheppo if (npages > mtbl->num_avail) { 49253af08d82Slm66018 D1(ldcp->id, "ldc_mem_bind_handle: (0x%llx) no table entries\n", 49261ae08745Sheppo ldcp->id); 49271ae08745Sheppo mutex_exit(&mtbl->lock); 49281ae08745Sheppo mutex_exit(&mhdl->lock); 49291ae08745Sheppo return (ENOMEM); 49301ae08745Sheppo } 49311ae08745Sheppo 49321ae08745Sheppo /* Allocate a memseg structure */ 49334bac2208Snarayan memseg = mhdl->memseg = 49344bac2208Snarayan kmem_cache_alloc(ldcssp->memseg_cache, KM_SLEEP); 49351ae08745Sheppo 49361ae08745Sheppo /* Allocate memory to store all pages and cookies */ 49371ae08745Sheppo memseg->pages = kmem_zalloc((sizeof (ldc_page_t) * npages), KM_SLEEP); 49381ae08745Sheppo memseg->cookies = 49391ae08745Sheppo kmem_zalloc((sizeof (ldc_mem_cookie_t) * npages), KM_SLEEP); 49401ae08745Sheppo 49411ae08745Sheppo D2(ldcp->id, "ldc_mem_bind_handle: (0x%llx) processing 0x%llx pages\n", 49421ae08745Sheppo ldcp->id, npages); 49431ae08745Sheppo 49441ae08745Sheppo addr = v_align; 49451ae08745Sheppo 49461ae08745Sheppo /* 49474bac2208Snarayan * Check if direct shared memory map is enabled, if not change 49484bac2208Snarayan * the mapping type to include SHADOW_MAP. 49494bac2208Snarayan */ 49504bac2208Snarayan if (ldc_shmem_enabled == 0) 49514bac2208Snarayan mtype = LDC_SHADOW_MAP; 49524bac2208Snarayan 49534bac2208Snarayan /* 49541ae08745Sheppo * Table slots are used in a round-robin manner. The algorithm permits 49551ae08745Sheppo * inserting duplicate entries. Slots allocated earlier will typically 49561ae08745Sheppo * get freed before we get back to reusing the slot.Inserting duplicate 49571ae08745Sheppo * entries should be OK as we only lookup entries using the cookie addr 49581ae08745Sheppo * i.e. tbl index, during export, unexport and copy operation. 49591ae08745Sheppo * 49601ae08745Sheppo * One implementation what was tried was to search for a duplicate 49611ae08745Sheppo * page entry first and reuse it. The search overhead is very high and 49621ae08745Sheppo * in the vnet case dropped the perf by almost half, 50 to 24 mbps. 49631ae08745Sheppo * So it does make sense to avoid searching for duplicates. 49641ae08745Sheppo * 49651ae08745Sheppo * But during the process of searching for a free slot, if we find a 49661ae08745Sheppo * duplicate entry we will go ahead and use it, and bump its use count. 49671ae08745Sheppo */ 49681ae08745Sheppo 49691ae08745Sheppo /* index to start searching from */ 49701ae08745Sheppo index = mtbl->next_entry; 49711ae08745Sheppo cookie_idx = -1; 49721ae08745Sheppo 49731ae08745Sheppo tmp_mte.ll = 0; /* initialise fields to 0 */ 49741ae08745Sheppo 49751ae08745Sheppo if (mtype & LDC_DIRECT_MAP) { 49761ae08745Sheppo tmp_mte.mte_r = (perm & LDC_MEM_R) ? 1 : 0; 49771ae08745Sheppo tmp_mte.mte_w = (perm & LDC_MEM_W) ? 1 : 0; 49781ae08745Sheppo tmp_mte.mte_x = (perm & LDC_MEM_X) ? 1 : 0; 49791ae08745Sheppo } 49801ae08745Sheppo 49811ae08745Sheppo if (mtype & LDC_SHADOW_MAP) { 49821ae08745Sheppo tmp_mte.mte_cr = (perm & LDC_MEM_R) ? 1 : 0; 49831ae08745Sheppo tmp_mte.mte_cw = (perm & LDC_MEM_W) ? 1 : 0; 49841ae08745Sheppo } 49851ae08745Sheppo 49861ae08745Sheppo if (mtype & LDC_IO_MAP) { 49871ae08745Sheppo tmp_mte.mte_ir = (perm & LDC_MEM_R) ? 1 : 0; 49881ae08745Sheppo tmp_mte.mte_iw = (perm & LDC_MEM_W) ? 1 : 0; 49891ae08745Sheppo } 49901ae08745Sheppo 49911ae08745Sheppo D1(ldcp->id, "ldc_mem_bind_handle mte=0x%llx\n", tmp_mte.ll); 49921ae08745Sheppo 49931ae08745Sheppo tmp_mte.mte_pgszc = pg_size_code; 49941ae08745Sheppo 49951ae08745Sheppo /* initialize each mem table entry */ 49961ae08745Sheppo for (i = 0; i < npages; i++) { 49971ae08745Sheppo 49981ae08745Sheppo /* check if slot is available in the table */ 49991ae08745Sheppo while (mtbl->table[index].entry.ll != 0) { 50001ae08745Sheppo 50011ae08745Sheppo index = (index + 1) % mtbl->num_entries; 50021ae08745Sheppo 50031ae08745Sheppo if (index == mtbl->next_entry) { 50041ae08745Sheppo /* we have looped around */ 50051ae08745Sheppo DWARN(DBG_ALL_LDCS, 50061ae08745Sheppo "ldc_mem_bind_handle: (0x%llx) cannot find " 50071ae08745Sheppo "entry\n", ldcp->id); 50081ae08745Sheppo *ccount = 0; 50091ae08745Sheppo 50101ae08745Sheppo /* NOTE: free memory, remove previous entries */ 50111ae08745Sheppo /* this shouldnt happen as num_avail was ok */ 50121ae08745Sheppo 50131ae08745Sheppo mutex_exit(&mtbl->lock); 50141ae08745Sheppo mutex_exit(&mhdl->lock); 50151ae08745Sheppo return (ENOMEM); 50161ae08745Sheppo } 50171ae08745Sheppo } 50181ae08745Sheppo 50191ae08745Sheppo /* get the real address */ 50201ae08745Sheppo raddr = va_to_pa((void *)addr); 50211ae08745Sheppo ra_aligned = ((uintptr_t)raddr & pg_mask); 50221ae08745Sheppo 50231ae08745Sheppo /* build the mte */ 50241ae08745Sheppo tmp_mte.mte_rpfn = ra_aligned >> pg_shift; 50251ae08745Sheppo 50261ae08745Sheppo D1(ldcp->id, "ldc_mem_bind_handle mte=0x%llx\n", tmp_mte.ll); 50271ae08745Sheppo 50281ae08745Sheppo /* update entry in table */ 50291ae08745Sheppo mtbl->table[index].entry = tmp_mte; 50301ae08745Sheppo 50311ae08745Sheppo D2(ldcp->id, "ldc_mem_bind_handle: (0x%llx) stored MTE 0x%llx" 50321ae08745Sheppo " into loc 0x%llx\n", ldcp->id, tmp_mte.ll, index); 50331ae08745Sheppo 50341ae08745Sheppo /* calculate the size and offset for this export range */ 50351ae08745Sheppo if (i == 0) { 50361ae08745Sheppo /* first page */ 50371ae08745Sheppo psize = min((pg_size - v_offset), len); 50381ae08745Sheppo poffset = v_offset; 50391ae08745Sheppo 50401ae08745Sheppo } else if (i == (npages - 1)) { 50411ae08745Sheppo /* last page */ 50421ae08745Sheppo psize = (((uintptr_t)(vaddr + len)) & 50431ae08745Sheppo ((uint64_t)(pg_size-1))); 50441ae08745Sheppo if (psize == 0) 50451ae08745Sheppo psize = pg_size; 50461ae08745Sheppo poffset = 0; 50471ae08745Sheppo 50481ae08745Sheppo } else { 50491ae08745Sheppo /* middle pages */ 50501ae08745Sheppo psize = pg_size; 50511ae08745Sheppo poffset = 0; 50521ae08745Sheppo } 50531ae08745Sheppo 50541ae08745Sheppo /* store entry for this page */ 50551ae08745Sheppo memseg->pages[i].index = index; 50561ae08745Sheppo memseg->pages[i].raddr = raddr; 50571ae08745Sheppo memseg->pages[i].offset = poffset; 50581ae08745Sheppo memseg->pages[i].size = psize; 50591ae08745Sheppo memseg->pages[i].mte = &(mtbl->table[index]); 50601ae08745Sheppo 50611ae08745Sheppo /* create the cookie */ 50621ae08745Sheppo if (i == 0 || (index != prev_index + 1)) { 50631ae08745Sheppo cookie_idx++; 50641ae08745Sheppo memseg->cookies[cookie_idx].addr = 50651ae08745Sheppo IDX2COOKIE(index, pg_size_code, pg_shift); 50661ae08745Sheppo memseg->cookies[cookie_idx].addr |= poffset; 50671ae08745Sheppo memseg->cookies[cookie_idx].size = psize; 50681ae08745Sheppo 50691ae08745Sheppo } else { 50701ae08745Sheppo memseg->cookies[cookie_idx].size += psize; 50711ae08745Sheppo } 50721ae08745Sheppo 50731ae08745Sheppo D1(ldcp->id, "ldc_mem_bind_handle: bound " 50741ae08745Sheppo "(0x%llx) va=0x%llx, idx=0x%llx, " 50751ae08745Sheppo "ra=0x%llx(sz=0x%x,off=0x%x)\n", 50761ae08745Sheppo ldcp->id, addr, index, raddr, psize, poffset); 50771ae08745Sheppo 50781ae08745Sheppo /* decrement number of available entries */ 50791ae08745Sheppo mtbl->num_avail--; 50801ae08745Sheppo 50811ae08745Sheppo /* increment va by page size */ 50821ae08745Sheppo addr += pg_size; 50831ae08745Sheppo 50841ae08745Sheppo /* increment index */ 50851ae08745Sheppo prev_index = index; 50861ae08745Sheppo index = (index + 1) % mtbl->num_entries; 50871ae08745Sheppo 50881ae08745Sheppo /* save the next slot */ 50891ae08745Sheppo mtbl->next_entry = index; 50901ae08745Sheppo } 50911ae08745Sheppo 50921ae08745Sheppo mutex_exit(&mtbl->lock); 50931ae08745Sheppo 50941ae08745Sheppo /* memory handle = bound */ 50951ae08745Sheppo mhdl->mtype = mtype; 50961ae08745Sheppo mhdl->perm = perm; 50971ae08745Sheppo mhdl->status = LDC_BOUND; 50981ae08745Sheppo 50991ae08745Sheppo /* update memseg_t */ 51001ae08745Sheppo memseg->vaddr = vaddr; 51011ae08745Sheppo memseg->raddr = memseg->pages[0].raddr; 51021ae08745Sheppo memseg->size = len; 51031ae08745Sheppo memseg->npages = npages; 51041ae08745Sheppo memseg->ncookies = cookie_idx + 1; 51051ae08745Sheppo memseg->next_cookie = (memseg->ncookies > 1) ? 1 : 0; 51061ae08745Sheppo 51071ae08745Sheppo /* return count and first cookie */ 51081ae08745Sheppo *ccount = memseg->ncookies; 51091ae08745Sheppo cookie->addr = memseg->cookies[0].addr; 51101ae08745Sheppo cookie->size = memseg->cookies[0].size; 51111ae08745Sheppo 51121ae08745Sheppo D1(ldcp->id, 51131ae08745Sheppo "ldc_mem_bind_handle: (0x%llx) bound 0x%llx, va=0x%llx, " 51141ae08745Sheppo "pgs=0x%llx cookies=0x%llx\n", 51151ae08745Sheppo ldcp->id, mhdl, vaddr, npages, memseg->ncookies); 51161ae08745Sheppo 51171ae08745Sheppo mutex_exit(&mhdl->lock); 51181ae08745Sheppo return (0); 51191ae08745Sheppo } 51201ae08745Sheppo 51211ae08745Sheppo /* 51221ae08745Sheppo * Return the next cookie associated with the specified memory handle 51231ae08745Sheppo */ 51241ae08745Sheppo int 51251ae08745Sheppo ldc_mem_nextcookie(ldc_mem_handle_t mhandle, ldc_mem_cookie_t *cookie) 51261ae08745Sheppo { 51271ae08745Sheppo ldc_mhdl_t *mhdl; 51281ae08745Sheppo ldc_chan_t *ldcp; 51291ae08745Sheppo ldc_memseg_t *memseg; 51301ae08745Sheppo 51311ae08745Sheppo if (mhandle == NULL) { 51321ae08745Sheppo DWARN(DBG_ALL_LDCS, 51331ae08745Sheppo "ldc_mem_nextcookie: invalid memory handle\n"); 51341ae08745Sheppo return (EINVAL); 51351ae08745Sheppo } 51361ae08745Sheppo mhdl = (ldc_mhdl_t *)mhandle; 51371ae08745Sheppo 51381ae08745Sheppo mutex_enter(&mhdl->lock); 51391ae08745Sheppo 51401ae08745Sheppo ldcp = mhdl->ldcp; 51411ae08745Sheppo memseg = mhdl->memseg; 51421ae08745Sheppo 51431ae08745Sheppo if (cookie == 0) { 51441ae08745Sheppo DWARN(ldcp->id, 51451ae08745Sheppo "ldc_mem_nextcookie:(0x%llx) invalid cookie arg\n", 51461ae08745Sheppo ldcp->id); 51471ae08745Sheppo mutex_exit(&mhdl->lock); 51481ae08745Sheppo return (EINVAL); 51491ae08745Sheppo } 51501ae08745Sheppo 51511ae08745Sheppo if (memseg->next_cookie != 0) { 51521ae08745Sheppo cookie->addr = memseg->cookies[memseg->next_cookie].addr; 51531ae08745Sheppo cookie->size = memseg->cookies[memseg->next_cookie].size; 51541ae08745Sheppo memseg->next_cookie++; 51551ae08745Sheppo if (memseg->next_cookie == memseg->ncookies) 51561ae08745Sheppo memseg->next_cookie = 0; 51571ae08745Sheppo 51581ae08745Sheppo } else { 51591ae08745Sheppo DWARN(ldcp->id, 51601ae08745Sheppo "ldc_mem_nextcookie:(0x%llx) no more cookies\n", ldcp->id); 51611ae08745Sheppo cookie->addr = 0; 51621ae08745Sheppo cookie->size = 0; 51631ae08745Sheppo mutex_exit(&mhdl->lock); 51641ae08745Sheppo return (EINVAL); 51651ae08745Sheppo } 51661ae08745Sheppo 51671ae08745Sheppo D1(ldcp->id, 51681ae08745Sheppo "ldc_mem_nextcookie: (0x%llx) cookie addr=0x%llx,sz=0x%llx\n", 51691ae08745Sheppo ldcp->id, cookie->addr, cookie->size); 51701ae08745Sheppo 51711ae08745Sheppo mutex_exit(&mhdl->lock); 51721ae08745Sheppo return (0); 51731ae08745Sheppo } 51741ae08745Sheppo 51751ae08745Sheppo /* 51761ae08745Sheppo * Unbind the virtual memory region associated with the specified 51771ae08745Sheppo * memory handle. Allassociated cookies are freed and the corresponding 51781ae08745Sheppo * RA space is no longer exported. 51791ae08745Sheppo */ 51801ae08745Sheppo int 51811ae08745Sheppo ldc_mem_unbind_handle(ldc_mem_handle_t mhandle) 51821ae08745Sheppo { 51831ae08745Sheppo ldc_mhdl_t *mhdl; 51841ae08745Sheppo ldc_chan_t *ldcp; 51851ae08745Sheppo ldc_mtbl_t *mtbl; 51861ae08745Sheppo ldc_memseg_t *memseg; 51874bac2208Snarayan uint64_t cookie_addr; 51884bac2208Snarayan uint64_t pg_shift, pg_size_code; 51894bac2208Snarayan int i, rv; 51901ae08745Sheppo 51911ae08745Sheppo if (mhandle == NULL) { 51921ae08745Sheppo DWARN(DBG_ALL_LDCS, 51931ae08745Sheppo "ldc_mem_unbind_handle: invalid memory handle\n"); 51941ae08745Sheppo return (EINVAL); 51951ae08745Sheppo } 51961ae08745Sheppo mhdl = (ldc_mhdl_t *)mhandle; 51971ae08745Sheppo 51981ae08745Sheppo mutex_enter(&mhdl->lock); 51991ae08745Sheppo 52001ae08745Sheppo if (mhdl->status == LDC_UNBOUND) { 52011ae08745Sheppo DWARN(DBG_ALL_LDCS, 52021ae08745Sheppo "ldc_mem_unbind_handle: (0x%x) handle is not bound\n", 52031ae08745Sheppo mhandle); 52041ae08745Sheppo mutex_exit(&mhdl->lock); 52051ae08745Sheppo return (EINVAL); 52061ae08745Sheppo } 52071ae08745Sheppo 52081ae08745Sheppo ldcp = mhdl->ldcp; 52091ae08745Sheppo mtbl = ldcp->mtbl; 52101ae08745Sheppo 52111ae08745Sheppo memseg = mhdl->memseg; 52121ae08745Sheppo 52131ae08745Sheppo /* lock the memory table - exclusive access to channel */ 52141ae08745Sheppo mutex_enter(&mtbl->lock); 52151ae08745Sheppo 52161ae08745Sheppo /* undo the pages exported */ 52171ae08745Sheppo for (i = 0; i < memseg->npages; i++) { 52181ae08745Sheppo 52194bac2208Snarayan /* check for mapped pages, revocation cookie != 0 */ 52201ae08745Sheppo if (memseg->pages[i].mte->cookie) { 52214bac2208Snarayan 52224bac2208Snarayan pg_size_code = page_szc(memseg->pages[i].size); 52234bac2208Snarayan pg_shift = page_get_shift(memseg->pages[i].size); 52244bac2208Snarayan cookie_addr = IDX2COOKIE(memseg->pages[i].index, 52254bac2208Snarayan pg_size_code, pg_shift); 52264bac2208Snarayan 52274bac2208Snarayan D1(ldcp->id, "ldc_mem_unbind_handle: (0x%llx) revoke " 52284bac2208Snarayan "cookie 0x%llx, rcookie 0x%llx\n", ldcp->id, 52294bac2208Snarayan cookie_addr, memseg->pages[i].mte->cookie); 52304bac2208Snarayan rv = hv_ldc_revoke(ldcp->id, cookie_addr, 52314bac2208Snarayan memseg->pages[i].mte->cookie); 52324bac2208Snarayan if (rv) { 52334bac2208Snarayan DWARN(ldcp->id, 52344bac2208Snarayan "ldc_mem_unbind_handle: (0x%llx) cannot " 52354bac2208Snarayan "revoke mapping, cookie %llx\n", ldcp->id, 52364bac2208Snarayan cookie_addr); 52374bac2208Snarayan } 52381ae08745Sheppo } 52391ae08745Sheppo 52401ae08745Sheppo /* clear the entry from the table */ 52411ae08745Sheppo memseg->pages[i].mte->entry.ll = 0; 52421ae08745Sheppo mtbl->num_avail++; 52431ae08745Sheppo } 52441ae08745Sheppo mutex_exit(&mtbl->lock); 52451ae08745Sheppo 52461ae08745Sheppo /* free the allocated memseg and page structures */ 52471ae08745Sheppo kmem_free(memseg->pages, (sizeof (ldc_page_t) * memseg->npages)); 52481ae08745Sheppo kmem_free(memseg->cookies, 52491ae08745Sheppo (sizeof (ldc_mem_cookie_t) * memseg->npages)); 52504bac2208Snarayan kmem_cache_free(ldcssp->memseg_cache, memseg); 52511ae08745Sheppo 52521ae08745Sheppo /* uninitialize the memory handle */ 52531ae08745Sheppo mhdl->memseg = NULL; 52541ae08745Sheppo mhdl->status = LDC_UNBOUND; 52551ae08745Sheppo 52561ae08745Sheppo D1(ldcp->id, "ldc_mem_unbind_handle: (0x%llx) unbound handle 0x%llx\n", 52571ae08745Sheppo ldcp->id, mhdl); 52581ae08745Sheppo 52591ae08745Sheppo mutex_exit(&mhdl->lock); 52601ae08745Sheppo return (0); 52611ae08745Sheppo } 52621ae08745Sheppo 52631ae08745Sheppo /* 52641ae08745Sheppo * Get information about the dring. The base address of the descriptor 52651ae08745Sheppo * ring along with the type and permission are returned back. 52661ae08745Sheppo */ 52671ae08745Sheppo int 52681ae08745Sheppo ldc_mem_info(ldc_mem_handle_t mhandle, ldc_mem_info_t *minfo) 52691ae08745Sheppo { 52701ae08745Sheppo ldc_mhdl_t *mhdl; 52711ae08745Sheppo 52721ae08745Sheppo if (mhandle == NULL) { 52731ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_mem_info: invalid memory handle\n"); 52741ae08745Sheppo return (EINVAL); 52751ae08745Sheppo } 52761ae08745Sheppo mhdl = (ldc_mhdl_t *)mhandle; 52771ae08745Sheppo 52781ae08745Sheppo if (minfo == NULL) { 52791ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_mem_info: invalid args\n"); 52801ae08745Sheppo return (EINVAL); 52811ae08745Sheppo } 52821ae08745Sheppo 52831ae08745Sheppo mutex_enter(&mhdl->lock); 52841ae08745Sheppo 52851ae08745Sheppo minfo->status = mhdl->status; 52861ae08745Sheppo if (mhdl->status == LDC_BOUND || mhdl->status == LDC_MAPPED) { 52871ae08745Sheppo minfo->vaddr = mhdl->memseg->vaddr; 52881ae08745Sheppo minfo->raddr = mhdl->memseg->raddr; 52891ae08745Sheppo minfo->mtype = mhdl->mtype; 52901ae08745Sheppo minfo->perm = mhdl->perm; 52911ae08745Sheppo } 52921ae08745Sheppo mutex_exit(&mhdl->lock); 52931ae08745Sheppo 52941ae08745Sheppo return (0); 52951ae08745Sheppo } 52961ae08745Sheppo 52971ae08745Sheppo /* 52981ae08745Sheppo * Copy data either from or to the client specified virtual address 52991ae08745Sheppo * space to or from the exported memory associated with the cookies. 53001ae08745Sheppo * The direction argument determines whether the data is read from or 53011ae08745Sheppo * written to exported memory. 53021ae08745Sheppo */ 53031ae08745Sheppo int 53041ae08745Sheppo ldc_mem_copy(ldc_handle_t handle, caddr_t vaddr, uint64_t off, size_t *size, 53051ae08745Sheppo ldc_mem_cookie_t *cookies, uint32_t ccount, uint8_t direction) 53061ae08745Sheppo { 53071ae08745Sheppo ldc_chan_t *ldcp; 53081ae08745Sheppo uint64_t local_voff, local_valign; 53091ae08745Sheppo uint64_t cookie_addr, cookie_size; 53101ae08745Sheppo uint64_t pg_shift, pg_size, pg_size_code; 53111ae08745Sheppo uint64_t export_caddr, export_poff, export_psize, export_size; 53121ae08745Sheppo uint64_t local_ra, local_poff, local_psize; 53131ae08745Sheppo uint64_t copy_size, copied_len = 0, total_bal = 0, idx = 0; 53141ae08745Sheppo pgcnt_t npages; 53151ae08745Sheppo size_t len = *size; 53161ae08745Sheppo int i, rv = 0; 53171ae08745Sheppo 53183af08d82Slm66018 uint64_t chid; 53193af08d82Slm66018 53201ae08745Sheppo if (handle == NULL) { 53211ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_mem_copy: invalid channel handle\n"); 53221ae08745Sheppo return (EINVAL); 53231ae08745Sheppo } 53241ae08745Sheppo ldcp = (ldc_chan_t *)handle; 53253af08d82Slm66018 chid = ldcp->id; 53261ae08745Sheppo 53271ae08745Sheppo /* check to see if channel is UP */ 53281ae08745Sheppo if (ldcp->tstate != TS_UP) { 53293af08d82Slm66018 DWARN(chid, "ldc_mem_copy: (0x%llx) channel is not UP\n", 53303af08d82Slm66018 chid); 53313af08d82Slm66018 return (ECONNRESET); 53321ae08745Sheppo } 53331ae08745Sheppo 53341ae08745Sheppo /* Force address and size to be 8-byte aligned */ 53351ae08745Sheppo if ((((uintptr_t)vaddr | len) & 0x7) != 0) { 53363af08d82Slm66018 DWARN(chid, 53371ae08745Sheppo "ldc_mem_copy: addr/sz is not 8-byte aligned\n"); 53381ae08745Sheppo return (EINVAL); 53391ae08745Sheppo } 53401ae08745Sheppo 53411ae08745Sheppo /* Find the size of the exported memory */ 53421ae08745Sheppo export_size = 0; 53431ae08745Sheppo for (i = 0; i < ccount; i++) 53441ae08745Sheppo export_size += cookies[i].size; 53451ae08745Sheppo 53461ae08745Sheppo /* check to see if offset is valid */ 53471ae08745Sheppo if (off > export_size) { 53483af08d82Slm66018 DWARN(chid, 53491ae08745Sheppo "ldc_mem_copy: (0x%llx) start offset > export mem size\n", 53503af08d82Slm66018 chid); 53511ae08745Sheppo return (EINVAL); 53521ae08745Sheppo } 53531ae08745Sheppo 53541ae08745Sheppo /* 53551ae08745Sheppo * Check to see if the export size is smaller than the size we 53561ae08745Sheppo * are requesting to copy - if so flag an error 53571ae08745Sheppo */ 53581ae08745Sheppo if ((export_size - off) < *size) { 53593af08d82Slm66018 DWARN(chid, 53601ae08745Sheppo "ldc_mem_copy: (0x%llx) copy size > export mem size\n", 53613af08d82Slm66018 chid); 53621ae08745Sheppo return (EINVAL); 53631ae08745Sheppo } 53641ae08745Sheppo 53651ae08745Sheppo total_bal = min(export_size, *size); 53661ae08745Sheppo 53671ae08745Sheppo /* FUTURE: get the page size, pgsz code, and shift */ 53681ae08745Sheppo pg_size = MMU_PAGESIZE; 53691ae08745Sheppo pg_size_code = page_szc(pg_size); 53701ae08745Sheppo pg_shift = page_get_shift(pg_size_code); 53711ae08745Sheppo 53723af08d82Slm66018 D1(chid, "ldc_mem_copy: copying data " 53731ae08745Sheppo "(0x%llx) va 0x%llx pgsz=0x%llx, pgszc=0x%llx, pg_shift=0x%llx\n", 53743af08d82Slm66018 chid, vaddr, pg_size, pg_size_code, pg_shift); 53751ae08745Sheppo 53761ae08745Sheppo /* aligned VA and its offset */ 53771ae08745Sheppo local_valign = (((uintptr_t)vaddr) & ~(pg_size - 1)); 53781ae08745Sheppo local_voff = ((uintptr_t)vaddr) & (pg_size - 1); 53791ae08745Sheppo 53801ae08745Sheppo npages = (len+local_voff)/pg_size; 53811ae08745Sheppo npages = ((len+local_voff)%pg_size == 0) ? npages : npages+1; 53821ae08745Sheppo 53833af08d82Slm66018 D1(chid, 53841ae08745Sheppo "ldc_mem_copy: (0x%llx) v=0x%llx,val=0x%llx,off=0x%x,pgs=0x%x\n", 53853af08d82Slm66018 chid, vaddr, local_valign, local_voff, npages); 53861ae08745Sheppo 53871ae08745Sheppo local_ra = va_to_pa((void *)local_valign); 53881ae08745Sheppo local_poff = local_voff; 53891ae08745Sheppo local_psize = min(len, (pg_size - local_voff)); 53901ae08745Sheppo 53911ae08745Sheppo len -= local_psize; 53921ae08745Sheppo 53931ae08745Sheppo /* 53941ae08745Sheppo * find the first cookie in the list of cookies 53951ae08745Sheppo * if the offset passed in is not zero 53961ae08745Sheppo */ 53971ae08745Sheppo for (idx = 0; idx < ccount; idx++) { 53981ae08745Sheppo cookie_size = cookies[idx].size; 53991ae08745Sheppo if (off < cookie_size) 54001ae08745Sheppo break; 54011ae08745Sheppo off -= cookie_size; 54021ae08745Sheppo } 54031ae08745Sheppo 54041ae08745Sheppo cookie_addr = cookies[idx].addr + off; 54051ae08745Sheppo cookie_size = cookies[idx].size - off; 54061ae08745Sheppo 54071ae08745Sheppo export_caddr = cookie_addr & ~(pg_size - 1); 54081ae08745Sheppo export_poff = cookie_addr & (pg_size - 1); 54091ae08745Sheppo export_psize = min(cookie_size, (pg_size - export_poff)); 54101ae08745Sheppo 54111ae08745Sheppo for (;;) { 54121ae08745Sheppo 54131ae08745Sheppo copy_size = min(export_psize, local_psize); 54141ae08745Sheppo 54153af08d82Slm66018 D1(chid, 54161ae08745Sheppo "ldc_mem_copy:(0x%llx) dir=0x%x, caddr=0x%llx," 54171ae08745Sheppo " loc_ra=0x%llx, exp_poff=0x%llx, loc_poff=0x%llx," 54181ae08745Sheppo " exp_psz=0x%llx, loc_psz=0x%llx, copy_sz=0x%llx," 54191ae08745Sheppo " total_bal=0x%llx\n", 54203af08d82Slm66018 chid, direction, export_caddr, local_ra, export_poff, 54211ae08745Sheppo local_poff, export_psize, local_psize, copy_size, 54221ae08745Sheppo total_bal); 54231ae08745Sheppo 54243af08d82Slm66018 rv = hv_ldc_copy(chid, direction, 54251ae08745Sheppo (export_caddr + export_poff), (local_ra + local_poff), 54261ae08745Sheppo copy_size, &copied_len); 54271ae08745Sheppo 54281ae08745Sheppo if (rv != 0) { 54293af08d82Slm66018 int error = EIO; 54303af08d82Slm66018 uint64_t rx_hd, rx_tl; 54313af08d82Slm66018 54323af08d82Slm66018 DWARN(chid, 54333af08d82Slm66018 "ldc_mem_copy: (0x%llx) err %d during copy\n", 54343af08d82Slm66018 (unsigned long long)chid, rv); 54353af08d82Slm66018 DWARN(chid, 54363af08d82Slm66018 "ldc_mem_copy: (0x%llx) dir=0x%x, caddr=0x%lx, " 54374bac2208Snarayan "loc_ra=0x%lx, exp_poff=0x%lx, loc_poff=0x%lx," 54384bac2208Snarayan " exp_psz=0x%lx, loc_psz=0x%lx, copy_sz=0x%lx," 54394bac2208Snarayan " copied_len=0x%lx, total_bal=0x%lx\n", 54403af08d82Slm66018 chid, direction, export_caddr, local_ra, 54411ae08745Sheppo export_poff, local_poff, export_psize, local_psize, 54421ae08745Sheppo copy_size, copied_len, total_bal); 54431ae08745Sheppo 54441ae08745Sheppo *size = *size - total_bal; 54453af08d82Slm66018 54463af08d82Slm66018 /* 54473af08d82Slm66018 * check if reason for copy error was due to 54483af08d82Slm66018 * a channel reset. we need to grab the lock 54493af08d82Slm66018 * just in case we have to do a reset. 54503af08d82Slm66018 */ 54513af08d82Slm66018 mutex_enter(&ldcp->lock); 54523af08d82Slm66018 mutex_enter(&ldcp->tx_lock); 54533af08d82Slm66018 54543af08d82Slm66018 rv = hv_ldc_rx_get_state(ldcp->id, 54553af08d82Slm66018 &rx_hd, &rx_tl, &(ldcp->link_state)); 54563af08d82Slm66018 if (ldcp->link_state == LDC_CHANNEL_DOWN || 54573af08d82Slm66018 ldcp->link_state == LDC_CHANNEL_RESET) { 54583af08d82Slm66018 i_ldc_reset(ldcp, B_FALSE); 54593af08d82Slm66018 error = ECONNRESET; 54603af08d82Slm66018 } 54613af08d82Slm66018 54623af08d82Slm66018 mutex_exit(&ldcp->tx_lock); 54631ae08745Sheppo mutex_exit(&ldcp->lock); 54643af08d82Slm66018 54653af08d82Slm66018 return (error); 54661ae08745Sheppo } 54671ae08745Sheppo 54681ae08745Sheppo ASSERT(copied_len <= copy_size); 54691ae08745Sheppo 54703af08d82Slm66018 D2(chid, "ldc_mem_copy: copied=0x%llx\n", copied_len); 54711ae08745Sheppo export_poff += copied_len; 54721ae08745Sheppo local_poff += copied_len; 54731ae08745Sheppo export_psize -= copied_len; 54741ae08745Sheppo local_psize -= copied_len; 54751ae08745Sheppo cookie_size -= copied_len; 54761ae08745Sheppo 54771ae08745Sheppo total_bal -= copied_len; 54781ae08745Sheppo 54791ae08745Sheppo if (copy_size != copied_len) 54801ae08745Sheppo continue; 54811ae08745Sheppo 54821ae08745Sheppo if (export_psize == 0 && total_bal != 0) { 54831ae08745Sheppo 54841ae08745Sheppo if (cookie_size == 0) { 54851ae08745Sheppo idx++; 54861ae08745Sheppo cookie_addr = cookies[idx].addr; 54871ae08745Sheppo cookie_size = cookies[idx].size; 54881ae08745Sheppo 54891ae08745Sheppo export_caddr = cookie_addr & ~(pg_size - 1); 54901ae08745Sheppo export_poff = cookie_addr & (pg_size - 1); 54911ae08745Sheppo export_psize = 54921ae08745Sheppo min(cookie_size, (pg_size-export_poff)); 54931ae08745Sheppo } else { 54941ae08745Sheppo export_caddr += pg_size; 54951ae08745Sheppo export_poff = 0; 54961ae08745Sheppo export_psize = min(cookie_size, pg_size); 54971ae08745Sheppo } 54981ae08745Sheppo } 54991ae08745Sheppo 55001ae08745Sheppo if (local_psize == 0 && total_bal != 0) { 55011ae08745Sheppo local_valign += pg_size; 55021ae08745Sheppo local_ra = va_to_pa((void *)local_valign); 55031ae08745Sheppo local_poff = 0; 55041ae08745Sheppo local_psize = min(pg_size, len); 55051ae08745Sheppo len -= local_psize; 55061ae08745Sheppo } 55071ae08745Sheppo 55081ae08745Sheppo /* check if we are all done */ 55091ae08745Sheppo if (total_bal == 0) 55101ae08745Sheppo break; 55111ae08745Sheppo } 55121ae08745Sheppo 55131ae08745Sheppo 55143af08d82Slm66018 D1(chid, 55151ae08745Sheppo "ldc_mem_copy: (0x%llx) done copying sz=0x%llx\n", 55163af08d82Slm66018 chid, *size); 55171ae08745Sheppo 55181ae08745Sheppo return (0); 55191ae08745Sheppo } 55201ae08745Sheppo 55211ae08745Sheppo /* 55221ae08745Sheppo * Copy data either from or to the client specified virtual address 55231ae08745Sheppo * space to or from HV physical memory. 55241ae08745Sheppo * 55251ae08745Sheppo * The direction argument determines whether the data is read from or 55261ae08745Sheppo * written to HV memory. direction values are LDC_COPY_IN/OUT similar 55271ae08745Sheppo * to the ldc_mem_copy interface 55281ae08745Sheppo */ 55291ae08745Sheppo int 55303af08d82Slm66018 ldc_mem_rdwr_cookie(ldc_handle_t handle, caddr_t vaddr, size_t *size, 55311ae08745Sheppo caddr_t paddr, uint8_t direction) 55321ae08745Sheppo { 55331ae08745Sheppo ldc_chan_t *ldcp; 55341ae08745Sheppo uint64_t local_voff, local_valign; 55351ae08745Sheppo uint64_t pg_shift, pg_size, pg_size_code; 55361ae08745Sheppo uint64_t target_pa, target_poff, target_psize, target_size; 55371ae08745Sheppo uint64_t local_ra, local_poff, local_psize; 55381ae08745Sheppo uint64_t copy_size, copied_len = 0; 55391ae08745Sheppo pgcnt_t npages; 55401ae08745Sheppo size_t len = *size; 55411ae08745Sheppo int rv = 0; 55421ae08745Sheppo 55431ae08745Sheppo if (handle == NULL) { 55441ae08745Sheppo DWARN(DBG_ALL_LDCS, 55453af08d82Slm66018 "ldc_mem_rdwr_cookie: invalid channel handle\n"); 55461ae08745Sheppo return (EINVAL); 55471ae08745Sheppo } 55481ae08745Sheppo ldcp = (ldc_chan_t *)handle; 55491ae08745Sheppo 55501ae08745Sheppo mutex_enter(&ldcp->lock); 55511ae08745Sheppo 55521ae08745Sheppo /* check to see if channel is UP */ 55531ae08745Sheppo if (ldcp->tstate != TS_UP) { 55541ae08745Sheppo DWARN(ldcp->id, 55553af08d82Slm66018 "ldc_mem_rdwr_cookie: (0x%llx) channel is not UP\n", 55561ae08745Sheppo ldcp->id); 55571ae08745Sheppo mutex_exit(&ldcp->lock); 55583af08d82Slm66018 return (ECONNRESET); 55591ae08745Sheppo } 55601ae08745Sheppo 55611ae08745Sheppo /* Force address and size to be 8-byte aligned */ 55621ae08745Sheppo if ((((uintptr_t)vaddr | len) & 0x7) != 0) { 55631ae08745Sheppo DWARN(ldcp->id, 55643af08d82Slm66018 "ldc_mem_rdwr_cookie: addr/size is not 8-byte aligned\n"); 55651ae08745Sheppo mutex_exit(&ldcp->lock); 55661ae08745Sheppo return (EINVAL); 55671ae08745Sheppo } 55681ae08745Sheppo 55691ae08745Sheppo target_size = *size; 55701ae08745Sheppo 55711ae08745Sheppo /* FUTURE: get the page size, pgsz code, and shift */ 55721ae08745Sheppo pg_size = MMU_PAGESIZE; 55731ae08745Sheppo pg_size_code = page_szc(pg_size); 55741ae08745Sheppo pg_shift = page_get_shift(pg_size_code); 55751ae08745Sheppo 55763af08d82Slm66018 D1(ldcp->id, "ldc_mem_rdwr_cookie: copying data " 55771ae08745Sheppo "(0x%llx) va 0x%llx pgsz=0x%llx, pgszc=0x%llx, pg_shift=0x%llx\n", 55781ae08745Sheppo ldcp->id, vaddr, pg_size, pg_size_code, pg_shift); 55791ae08745Sheppo 55801ae08745Sheppo /* aligned VA and its offset */ 55811ae08745Sheppo local_valign = ((uintptr_t)vaddr) & ~(pg_size - 1); 55821ae08745Sheppo local_voff = ((uintptr_t)vaddr) & (pg_size - 1); 55831ae08745Sheppo 55841ae08745Sheppo npages = (len + local_voff) / pg_size; 55851ae08745Sheppo npages = ((len + local_voff) % pg_size == 0) ? npages : npages+1; 55861ae08745Sheppo 55873af08d82Slm66018 D1(ldcp->id, "ldc_mem_rdwr_cookie: (0x%llx) v=0x%llx, " 55883af08d82Slm66018 "val=0x%llx,off=0x%x,pgs=0x%x\n", 55891ae08745Sheppo ldcp->id, vaddr, local_valign, local_voff, npages); 55901ae08745Sheppo 55911ae08745Sheppo local_ra = va_to_pa((void *)local_valign); 55921ae08745Sheppo local_poff = local_voff; 55931ae08745Sheppo local_psize = min(len, (pg_size - local_voff)); 55941ae08745Sheppo 55951ae08745Sheppo len -= local_psize; 55961ae08745Sheppo 55971ae08745Sheppo target_pa = ((uintptr_t)paddr) & ~(pg_size - 1); 55981ae08745Sheppo target_poff = ((uintptr_t)paddr) & (pg_size - 1); 55991ae08745Sheppo target_psize = pg_size - target_poff; 56001ae08745Sheppo 56011ae08745Sheppo for (;;) { 56021ae08745Sheppo 56031ae08745Sheppo copy_size = min(target_psize, local_psize); 56041ae08745Sheppo 56051ae08745Sheppo D1(ldcp->id, 56063af08d82Slm66018 "ldc_mem_rdwr_cookie: (0x%llx) dir=0x%x, tar_pa=0x%llx," 56071ae08745Sheppo " loc_ra=0x%llx, tar_poff=0x%llx, loc_poff=0x%llx," 56081ae08745Sheppo " tar_psz=0x%llx, loc_psz=0x%llx, copy_sz=0x%llx," 56091ae08745Sheppo " total_bal=0x%llx\n", 56101ae08745Sheppo ldcp->id, direction, target_pa, local_ra, target_poff, 56111ae08745Sheppo local_poff, target_psize, local_psize, copy_size, 56121ae08745Sheppo target_size); 56131ae08745Sheppo 56141ae08745Sheppo rv = hv_ldc_copy(ldcp->id, direction, 56151ae08745Sheppo (target_pa + target_poff), (local_ra + local_poff), 56161ae08745Sheppo copy_size, &copied_len); 56171ae08745Sheppo 56181ae08745Sheppo if (rv != 0) { 56193af08d82Slm66018 DWARN(DBG_ALL_LDCS, 56203af08d82Slm66018 "ldc_mem_rdwr_cookie: (0x%lx) err %d during copy\n", 56211ae08745Sheppo ldcp->id, rv); 56221ae08745Sheppo DWARN(DBG_ALL_LDCS, 56233af08d82Slm66018 "ldc_mem_rdwr_cookie: (0x%llx) dir=%lld, " 56243af08d82Slm66018 "tar_pa=0x%llx, loc_ra=0x%llx, tar_poff=0x%llx, " 56253af08d82Slm66018 "loc_poff=0x%llx, tar_psz=0x%llx, loc_psz=0x%llx, " 56263af08d82Slm66018 "copy_sz=0x%llx, total_bal=0x%llx\n", 56271ae08745Sheppo ldcp->id, direction, target_pa, local_ra, 56281ae08745Sheppo target_poff, local_poff, target_psize, local_psize, 56291ae08745Sheppo copy_size, target_size); 56301ae08745Sheppo 56311ae08745Sheppo *size = *size - target_size; 56321ae08745Sheppo mutex_exit(&ldcp->lock); 56331ae08745Sheppo return (i_ldc_h2v_error(rv)); 56341ae08745Sheppo } 56351ae08745Sheppo 56363af08d82Slm66018 D2(ldcp->id, "ldc_mem_rdwr_cookie: copied=0x%llx\n", 56373af08d82Slm66018 copied_len); 56381ae08745Sheppo target_poff += copied_len; 56391ae08745Sheppo local_poff += copied_len; 56401ae08745Sheppo target_psize -= copied_len; 56411ae08745Sheppo local_psize -= copied_len; 56421ae08745Sheppo 56431ae08745Sheppo target_size -= copied_len; 56441ae08745Sheppo 56451ae08745Sheppo if (copy_size != copied_len) 56461ae08745Sheppo continue; 56471ae08745Sheppo 56481ae08745Sheppo if (target_psize == 0 && target_size != 0) { 56491ae08745Sheppo target_pa += pg_size; 56501ae08745Sheppo target_poff = 0; 56511ae08745Sheppo target_psize = min(pg_size, target_size); 56521ae08745Sheppo } 56531ae08745Sheppo 56541ae08745Sheppo if (local_psize == 0 && target_size != 0) { 56551ae08745Sheppo local_valign += pg_size; 56561ae08745Sheppo local_ra = va_to_pa((void *)local_valign); 56571ae08745Sheppo local_poff = 0; 56581ae08745Sheppo local_psize = min(pg_size, len); 56591ae08745Sheppo len -= local_psize; 56601ae08745Sheppo } 56611ae08745Sheppo 56621ae08745Sheppo /* check if we are all done */ 56631ae08745Sheppo if (target_size == 0) 56641ae08745Sheppo break; 56651ae08745Sheppo } 56661ae08745Sheppo 56671ae08745Sheppo mutex_exit(&ldcp->lock); 56681ae08745Sheppo 56693af08d82Slm66018 D1(ldcp->id, "ldc_mem_rdwr_cookie: (0x%llx) done copying sz=0x%llx\n", 56701ae08745Sheppo ldcp->id, *size); 56711ae08745Sheppo 56721ae08745Sheppo return (0); 56731ae08745Sheppo } 56741ae08745Sheppo 56751ae08745Sheppo /* 56761ae08745Sheppo * Map an exported memory segment into the local address space. If the 56771ae08745Sheppo * memory range was exported for direct map access, a HV call is made 56781ae08745Sheppo * to allocate a RA range. If the map is done via a shadow copy, local 56791ae08745Sheppo * shadow memory is allocated and the base VA is returned in 'vaddr'. If 56801ae08745Sheppo * the mapping is a direct map then the RA is returned in 'raddr'. 56811ae08745Sheppo */ 56821ae08745Sheppo int 56831ae08745Sheppo ldc_mem_map(ldc_mem_handle_t mhandle, ldc_mem_cookie_t *cookie, uint32_t ccount, 56844bac2208Snarayan uint8_t mtype, uint8_t perm, caddr_t *vaddr, caddr_t *raddr) 56851ae08745Sheppo { 56864bac2208Snarayan int i, j, idx, rv, retries; 56871ae08745Sheppo ldc_chan_t *ldcp; 56881ae08745Sheppo ldc_mhdl_t *mhdl; 56891ae08745Sheppo ldc_memseg_t *memseg; 56904bac2208Snarayan caddr_t tmpaddr; 56914bac2208Snarayan uint64_t map_perm = perm; 56924bac2208Snarayan uint64_t pg_size, pg_shift, pg_size_code, pg_mask; 56934bac2208Snarayan uint64_t exp_size = 0, base_off, map_size, npages; 56944bac2208Snarayan uint64_t cookie_addr, cookie_off, cookie_size; 56954bac2208Snarayan tte_t ldc_tte; 56961ae08745Sheppo 56971ae08745Sheppo if (mhandle == NULL) { 56981ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_mem_map: invalid memory handle\n"); 56991ae08745Sheppo return (EINVAL); 57001ae08745Sheppo } 57011ae08745Sheppo mhdl = (ldc_mhdl_t *)mhandle; 57021ae08745Sheppo 57031ae08745Sheppo mutex_enter(&mhdl->lock); 57041ae08745Sheppo 57051ae08745Sheppo if (mhdl->status == LDC_BOUND || mhdl->status == LDC_MAPPED || 57061ae08745Sheppo mhdl->memseg != NULL) { 57071ae08745Sheppo DWARN(DBG_ALL_LDCS, 57081ae08745Sheppo "ldc_mem_map: (0x%llx) handle bound/mapped\n", mhandle); 57091ae08745Sheppo mutex_exit(&mhdl->lock); 57101ae08745Sheppo return (EINVAL); 57111ae08745Sheppo } 57121ae08745Sheppo 57131ae08745Sheppo ldcp = mhdl->ldcp; 57141ae08745Sheppo 57151ae08745Sheppo mutex_enter(&ldcp->lock); 57161ae08745Sheppo 57171ae08745Sheppo if (ldcp->tstate != TS_UP) { 57181ae08745Sheppo DWARN(ldcp->id, 57191ae08745Sheppo "ldc_mem_dring_map: (0x%llx) channel is not UP\n", 57201ae08745Sheppo ldcp->id); 57211ae08745Sheppo mutex_exit(&ldcp->lock); 57221ae08745Sheppo mutex_exit(&mhdl->lock); 57233af08d82Slm66018 return (ECONNRESET); 57241ae08745Sheppo } 57251ae08745Sheppo 57261ae08745Sheppo if ((mtype & (LDC_SHADOW_MAP|LDC_DIRECT_MAP|LDC_IO_MAP)) == 0) { 57271ae08745Sheppo DWARN(ldcp->id, "ldc_mem_map: invalid map type\n"); 57281ae08745Sheppo mutex_exit(&ldcp->lock); 57291ae08745Sheppo mutex_exit(&mhdl->lock); 57301ae08745Sheppo return (EINVAL); 57311ae08745Sheppo } 57321ae08745Sheppo 57331ae08745Sheppo D1(ldcp->id, "ldc_mem_map: (0x%llx) cookie = 0x%llx,0x%llx\n", 5734d10e4ef2Snarayan ldcp->id, cookie->addr, cookie->size); 57351ae08745Sheppo 57361ae08745Sheppo /* FUTURE: get the page size, pgsz code, and shift */ 57371ae08745Sheppo pg_size = MMU_PAGESIZE; 57381ae08745Sheppo pg_size_code = page_szc(pg_size); 57391ae08745Sheppo pg_shift = page_get_shift(pg_size_code); 57404bac2208Snarayan pg_mask = ~(pg_size - 1); 57411ae08745Sheppo 57421ae08745Sheppo /* calculate the number of pages in the exported cookie */ 57434bac2208Snarayan base_off = cookie[0].addr & (pg_size - 1); 57444bac2208Snarayan for (idx = 0; idx < ccount; idx++) 57451ae08745Sheppo exp_size += cookie[idx].size; 57464bac2208Snarayan map_size = P2ROUNDUP((exp_size + base_off), pg_size); 57474bac2208Snarayan npages = (map_size >> pg_shift); 57481ae08745Sheppo 57491ae08745Sheppo /* Allocate memseg structure */ 57504bac2208Snarayan memseg = mhdl->memseg = 57514bac2208Snarayan kmem_cache_alloc(ldcssp->memseg_cache, KM_SLEEP); 57521ae08745Sheppo 57531ae08745Sheppo /* Allocate memory to store all pages and cookies */ 57541ae08745Sheppo memseg->pages = kmem_zalloc((sizeof (ldc_page_t) * npages), KM_SLEEP); 57551ae08745Sheppo memseg->cookies = 57561ae08745Sheppo kmem_zalloc((sizeof (ldc_mem_cookie_t) * ccount), KM_SLEEP); 57571ae08745Sheppo 57584bac2208Snarayan D2(ldcp->id, "ldc_mem_map: (0x%llx) exp_size=0x%llx, map_size=0x%llx," 57594bac2208Snarayan "pages=0x%llx\n", ldcp->id, exp_size, map_size, npages); 57601ae08745Sheppo 57614bac2208Snarayan /* 57624bac2208Snarayan * Check if direct map over shared memory is enabled, if not change 57634bac2208Snarayan * the mapping type to SHADOW_MAP. 57644bac2208Snarayan */ 57654bac2208Snarayan if (ldc_shmem_enabled == 0) 57664bac2208Snarayan mtype = LDC_SHADOW_MAP; 57674bac2208Snarayan 57684bac2208Snarayan /* 57694bac2208Snarayan * Check to see if the client is requesting direct or shadow map 57704bac2208Snarayan * If direct map is requested, try to map remote memory first, 57714bac2208Snarayan * and if that fails, revert to shadow map 57724bac2208Snarayan */ 57734bac2208Snarayan if (mtype == LDC_DIRECT_MAP) { 57744bac2208Snarayan 57754bac2208Snarayan /* Allocate kernel virtual space for mapping */ 57764bac2208Snarayan memseg->vaddr = vmem_xalloc(heap_arena, map_size, 57774bac2208Snarayan pg_size, 0, 0, NULL, NULL, VM_NOSLEEP); 57784bac2208Snarayan if (memseg->vaddr == NULL) { 57794bac2208Snarayan cmn_err(CE_WARN, 57804bac2208Snarayan "ldc_mem_map: (0x%lx) memory map failed\n", 57814bac2208Snarayan ldcp->id); 57824bac2208Snarayan kmem_free(memseg->cookies, 57834bac2208Snarayan (sizeof (ldc_mem_cookie_t) * ccount)); 57844bac2208Snarayan kmem_free(memseg->pages, 57854bac2208Snarayan (sizeof (ldc_page_t) * npages)); 57864bac2208Snarayan kmem_cache_free(ldcssp->memseg_cache, memseg); 57874bac2208Snarayan 57884bac2208Snarayan mutex_exit(&ldcp->lock); 57894bac2208Snarayan mutex_exit(&mhdl->lock); 57904bac2208Snarayan return (ENOMEM); 57914bac2208Snarayan } 57924bac2208Snarayan 57934bac2208Snarayan /* Unload previous mapping */ 57944bac2208Snarayan hat_unload(kas.a_hat, memseg->vaddr, map_size, 57954bac2208Snarayan HAT_UNLOAD_NOSYNC | HAT_UNLOAD_UNLOCK); 57964bac2208Snarayan 57974bac2208Snarayan /* for each cookie passed in - map into address space */ 57984bac2208Snarayan idx = 0; 57994bac2208Snarayan cookie_size = 0; 58004bac2208Snarayan tmpaddr = memseg->vaddr; 58014bac2208Snarayan 58024bac2208Snarayan for (i = 0; i < npages; i++) { 58034bac2208Snarayan 58044bac2208Snarayan if (cookie_size == 0) { 58054bac2208Snarayan ASSERT(idx < ccount); 58064bac2208Snarayan cookie_addr = cookie[idx].addr & pg_mask; 58074bac2208Snarayan cookie_off = cookie[idx].addr & (pg_size - 1); 58084bac2208Snarayan cookie_size = 58094bac2208Snarayan P2ROUNDUP((cookie_off + cookie[idx].size), 58104bac2208Snarayan pg_size); 58114bac2208Snarayan idx++; 58124bac2208Snarayan } 58134bac2208Snarayan 58144bac2208Snarayan D1(ldcp->id, "ldc_mem_map: (0x%llx) mapping " 58154bac2208Snarayan "cookie 0x%llx, bal=0x%llx\n", ldcp->id, 58164bac2208Snarayan cookie_addr, cookie_size); 58174bac2208Snarayan 58184bac2208Snarayan /* map the cookie into address space */ 58194bac2208Snarayan for (retries = 0; retries < ldc_max_retries; 58204bac2208Snarayan retries++) { 58214bac2208Snarayan 58224bac2208Snarayan rv = hv_ldc_mapin(ldcp->id, cookie_addr, 58234bac2208Snarayan &memseg->pages[i].raddr, &map_perm); 58244bac2208Snarayan if (rv != H_EWOULDBLOCK && rv != H_ETOOMANY) 58254bac2208Snarayan break; 58264bac2208Snarayan 58274bac2208Snarayan drv_usecwait(ldc_delay); 58284bac2208Snarayan } 58294bac2208Snarayan 58304bac2208Snarayan if (rv || memseg->pages[i].raddr == 0) { 58314bac2208Snarayan DWARN(ldcp->id, 58324bac2208Snarayan "ldc_mem_map: (0x%llx) hv mapin err %d\n", 58334bac2208Snarayan ldcp->id, rv); 58344bac2208Snarayan 58354bac2208Snarayan /* remove previous mapins */ 58364bac2208Snarayan hat_unload(kas.a_hat, memseg->vaddr, map_size, 58374bac2208Snarayan HAT_UNLOAD_NOSYNC | HAT_UNLOAD_UNLOCK); 58384bac2208Snarayan for (j = 0; j < i; j++) { 58394bac2208Snarayan rv = hv_ldc_unmap( 58404bac2208Snarayan memseg->pages[j].raddr); 58414bac2208Snarayan if (rv) { 58424bac2208Snarayan DWARN(ldcp->id, 58434bac2208Snarayan "ldc_mem_map: (0x%llx) " 58444bac2208Snarayan "cannot unmap ra=0x%llx\n", 58454bac2208Snarayan ldcp->id, 58464bac2208Snarayan memseg->pages[j].raddr); 58474bac2208Snarayan } 58484bac2208Snarayan } 58494bac2208Snarayan 58504bac2208Snarayan /* free kernel virtual space */ 58514bac2208Snarayan vmem_free(heap_arena, (void *)memseg->vaddr, 58527636cb21Slm66018 map_size); 58534bac2208Snarayan 58544bac2208Snarayan /* direct map failed - revert to shadow map */ 58554bac2208Snarayan mtype = LDC_SHADOW_MAP; 58564bac2208Snarayan break; 58574bac2208Snarayan 58584bac2208Snarayan } else { 58594bac2208Snarayan 58604bac2208Snarayan D1(ldcp->id, 58614bac2208Snarayan "ldc_mem_map: (0x%llx) vtop map 0x%llx -> " 58624bac2208Snarayan "0x%llx, cookie=0x%llx, perm=0x%llx\n", 58634bac2208Snarayan ldcp->id, tmpaddr, memseg->pages[i].raddr, 58644bac2208Snarayan cookie_addr, perm); 58654bac2208Snarayan 58664bac2208Snarayan /* 58674bac2208Snarayan * NOTE: Calling hat_devload directly, causes it 58684bac2208Snarayan * to look for page_t using the pfn. Since this 58694bac2208Snarayan * addr is greater than the memlist, it treates 58704bac2208Snarayan * it as non-memory 58714bac2208Snarayan */ 58724bac2208Snarayan sfmmu_memtte(&ldc_tte, 58734bac2208Snarayan (pfn_t)(memseg->pages[i].raddr >> pg_shift), 58744bac2208Snarayan PROT_READ | PROT_WRITE | HAT_NOSYNC, TTE8K); 58754bac2208Snarayan 58764bac2208Snarayan D1(ldcp->id, 58774bac2208Snarayan "ldc_mem_map: (0x%llx) ra 0x%llx -> " 58784bac2208Snarayan "tte 0x%llx\n", ldcp->id, 58794bac2208Snarayan memseg->pages[i].raddr, ldc_tte); 58804bac2208Snarayan 58814bac2208Snarayan sfmmu_tteload(kas.a_hat, &ldc_tte, tmpaddr, 58824bac2208Snarayan NULL, HAT_LOAD_LOCK); 58834bac2208Snarayan 58844bac2208Snarayan cookie_size -= pg_size; 58854bac2208Snarayan cookie_addr += pg_size; 58864bac2208Snarayan tmpaddr += pg_size; 58874bac2208Snarayan } 58884bac2208Snarayan } 58894bac2208Snarayan } 58904bac2208Snarayan 58911ae08745Sheppo if (mtype == LDC_SHADOW_MAP) { 58921ae08745Sheppo if (*vaddr == NULL) { 58933af08d82Slm66018 memseg->vaddr = kmem_zalloc(exp_size, KM_SLEEP); 58941ae08745Sheppo mhdl->myshadow = B_TRUE; 58951ae08745Sheppo 58961ae08745Sheppo D1(ldcp->id, "ldc_mem_map: (0x%llx) allocated " 58974bac2208Snarayan "shadow page va=0x%llx\n", ldcp->id, memseg->vaddr); 58981ae08745Sheppo } else { 58991ae08745Sheppo /* 59004bac2208Snarayan * Use client supplied memory for memseg->vaddr 59011ae08745Sheppo * WARNING: assuming that client mem is >= exp_size 59021ae08745Sheppo */ 59034bac2208Snarayan memseg->vaddr = *vaddr; 59041ae08745Sheppo } 59051ae08745Sheppo 59061ae08745Sheppo /* Save all page and cookie information */ 59074bac2208Snarayan for (i = 0, tmpaddr = memseg->vaddr; i < npages; i++) { 59081ae08745Sheppo memseg->pages[i].raddr = va_to_pa(tmpaddr); 59091ae08745Sheppo memseg->pages[i].size = pg_size; 59101ae08745Sheppo tmpaddr += pg_size; 59111ae08745Sheppo } 59124bac2208Snarayan 59131ae08745Sheppo } 59141ae08745Sheppo 59154bac2208Snarayan /* save all cookies */ 59164bac2208Snarayan bcopy(cookie, memseg->cookies, ccount * sizeof (ldc_mem_cookie_t)); 59174bac2208Snarayan 59181ae08745Sheppo /* update memseg_t */ 59191ae08745Sheppo memseg->raddr = memseg->pages[0].raddr; 59204bac2208Snarayan memseg->size = (mtype == LDC_SHADOW_MAP) ? exp_size : map_size; 59211ae08745Sheppo memseg->npages = npages; 59221ae08745Sheppo memseg->ncookies = ccount; 59231ae08745Sheppo memseg->next_cookie = 0; 59241ae08745Sheppo 59251ae08745Sheppo /* memory handle = mapped */ 59261ae08745Sheppo mhdl->mtype = mtype; 59274bac2208Snarayan mhdl->perm = perm; 59281ae08745Sheppo mhdl->status = LDC_MAPPED; 59291ae08745Sheppo 59301ae08745Sheppo D1(ldcp->id, "ldc_mem_map: (0x%llx) mapped 0x%llx, ra=0x%llx, " 59311ae08745Sheppo "va=0x%llx, pgs=0x%llx cookies=0x%llx\n", 59321ae08745Sheppo ldcp->id, mhdl, memseg->raddr, memseg->vaddr, 59331ae08745Sheppo memseg->npages, memseg->ncookies); 59341ae08745Sheppo 59354bac2208Snarayan if (mtype == LDC_SHADOW_MAP) 59364bac2208Snarayan base_off = 0; 59371ae08745Sheppo if (raddr) 59384bac2208Snarayan *raddr = (caddr_t)(memseg->raddr | base_off); 59391ae08745Sheppo if (vaddr) 59404bac2208Snarayan *vaddr = (caddr_t)((uintptr_t)memseg->vaddr | base_off); 59411ae08745Sheppo 59421ae08745Sheppo mutex_exit(&ldcp->lock); 59431ae08745Sheppo mutex_exit(&mhdl->lock); 59441ae08745Sheppo return (0); 59451ae08745Sheppo } 59461ae08745Sheppo 59471ae08745Sheppo /* 59481ae08745Sheppo * Unmap a memory segment. Free shadow memory (if any). 59491ae08745Sheppo */ 59501ae08745Sheppo int 59511ae08745Sheppo ldc_mem_unmap(ldc_mem_handle_t mhandle) 59521ae08745Sheppo { 59534bac2208Snarayan int i, rv; 59541ae08745Sheppo ldc_mhdl_t *mhdl = (ldc_mhdl_t *)mhandle; 59551ae08745Sheppo ldc_chan_t *ldcp; 59561ae08745Sheppo ldc_memseg_t *memseg; 59571ae08745Sheppo 59581ae08745Sheppo if (mhdl == 0 || mhdl->status != LDC_MAPPED) { 59591ae08745Sheppo DWARN(DBG_ALL_LDCS, 59601ae08745Sheppo "ldc_mem_unmap: (0x%llx) handle is not mapped\n", 59611ae08745Sheppo mhandle); 59621ae08745Sheppo return (EINVAL); 59631ae08745Sheppo } 59641ae08745Sheppo 59651ae08745Sheppo mutex_enter(&mhdl->lock); 59661ae08745Sheppo 59671ae08745Sheppo ldcp = mhdl->ldcp; 59681ae08745Sheppo memseg = mhdl->memseg; 59691ae08745Sheppo 59701ae08745Sheppo D1(ldcp->id, "ldc_mem_unmap: (0x%llx) unmapping handle 0x%llx\n", 59711ae08745Sheppo ldcp->id, mhdl); 59721ae08745Sheppo 59731ae08745Sheppo /* if we allocated shadow memory - free it */ 59741ae08745Sheppo if (mhdl->mtype == LDC_SHADOW_MAP && mhdl->myshadow) { 59753af08d82Slm66018 kmem_free(memseg->vaddr, memseg->size); 59764bac2208Snarayan } else if (mhdl->mtype == LDC_DIRECT_MAP) { 59774bac2208Snarayan 59784bac2208Snarayan /* unmap in the case of DIRECT_MAP */ 59794bac2208Snarayan hat_unload(kas.a_hat, memseg->vaddr, memseg->size, 59804bac2208Snarayan HAT_UNLOAD_UNLOCK); 59814bac2208Snarayan 59824bac2208Snarayan for (i = 0; i < memseg->npages; i++) { 59834bac2208Snarayan rv = hv_ldc_unmap(memseg->pages[i].raddr); 59844bac2208Snarayan if (rv) { 59854bac2208Snarayan cmn_err(CE_WARN, 59864bac2208Snarayan "ldc_mem_map: (0x%lx) hv unmap err %d\n", 59874bac2208Snarayan ldcp->id, rv); 59884bac2208Snarayan } 59894bac2208Snarayan } 59904bac2208Snarayan 59914bac2208Snarayan vmem_free(heap_arena, (void *)memseg->vaddr, memseg->size); 59921ae08745Sheppo } 59931ae08745Sheppo 59941ae08745Sheppo /* free the allocated memseg and page structures */ 59951ae08745Sheppo kmem_free(memseg->pages, (sizeof (ldc_page_t) * memseg->npages)); 59961ae08745Sheppo kmem_free(memseg->cookies, 59971ae08745Sheppo (sizeof (ldc_mem_cookie_t) * memseg->ncookies)); 59984bac2208Snarayan kmem_cache_free(ldcssp->memseg_cache, memseg); 59991ae08745Sheppo 60001ae08745Sheppo /* uninitialize the memory handle */ 60011ae08745Sheppo mhdl->memseg = NULL; 60021ae08745Sheppo mhdl->status = LDC_UNBOUND; 60031ae08745Sheppo 60041ae08745Sheppo D1(ldcp->id, "ldc_mem_unmap: (0x%llx) unmapped handle 0x%llx\n", 60051ae08745Sheppo ldcp->id, mhdl); 60061ae08745Sheppo 60071ae08745Sheppo mutex_exit(&mhdl->lock); 60081ae08745Sheppo return (0); 60091ae08745Sheppo } 60101ae08745Sheppo 60111ae08745Sheppo /* 60121ae08745Sheppo * Internal entry point for LDC mapped memory entry consistency 60131ae08745Sheppo * semantics. Acquire copies the contents of the remote memory 60141ae08745Sheppo * into the local shadow copy. The release operation copies the local 60151ae08745Sheppo * contents into the remote memory. The offset and size specify the 60161ae08745Sheppo * bounds for the memory range being synchronized. 60171ae08745Sheppo */ 60181ae08745Sheppo static int 60191ae08745Sheppo i_ldc_mem_acquire_release(ldc_mem_handle_t mhandle, uint8_t direction, 60201ae08745Sheppo uint64_t offset, size_t size) 60211ae08745Sheppo { 60221ae08745Sheppo int err; 60231ae08745Sheppo ldc_mhdl_t *mhdl; 60241ae08745Sheppo ldc_chan_t *ldcp; 60251ae08745Sheppo ldc_memseg_t *memseg; 60261ae08745Sheppo caddr_t local_vaddr; 60271ae08745Sheppo size_t copy_size; 60281ae08745Sheppo 60291ae08745Sheppo if (mhandle == NULL) { 60301ae08745Sheppo DWARN(DBG_ALL_LDCS, 60311ae08745Sheppo "i_ldc_mem_acquire_release: invalid memory handle\n"); 60321ae08745Sheppo return (EINVAL); 60331ae08745Sheppo } 60341ae08745Sheppo mhdl = (ldc_mhdl_t *)mhandle; 60351ae08745Sheppo 60361ae08745Sheppo mutex_enter(&mhdl->lock); 60371ae08745Sheppo 60381ae08745Sheppo if (mhdl->status != LDC_MAPPED || mhdl->ldcp == NULL) { 60391ae08745Sheppo DWARN(DBG_ALL_LDCS, 60401ae08745Sheppo "i_ldc_mem_acquire_release: not mapped memory\n"); 60411ae08745Sheppo mutex_exit(&mhdl->lock); 60421ae08745Sheppo return (EINVAL); 60431ae08745Sheppo } 60441ae08745Sheppo 60454bac2208Snarayan /* do nothing for direct map */ 60464bac2208Snarayan if (mhdl->mtype == LDC_DIRECT_MAP) { 60474bac2208Snarayan mutex_exit(&mhdl->lock); 60484bac2208Snarayan return (0); 60494bac2208Snarayan } 60504bac2208Snarayan 60514bac2208Snarayan /* do nothing if COPY_IN+MEM_W and COPY_OUT+MEM_R */ 60524bac2208Snarayan if ((direction == LDC_COPY_IN && (mhdl->perm & LDC_MEM_R) == 0) || 60534bac2208Snarayan (direction == LDC_COPY_OUT && (mhdl->perm & LDC_MEM_W) == 0)) { 60544bac2208Snarayan mutex_exit(&mhdl->lock); 60554bac2208Snarayan return (0); 60564bac2208Snarayan } 60574bac2208Snarayan 60581ae08745Sheppo if (offset >= mhdl->memseg->size || 60591ae08745Sheppo (offset + size) > mhdl->memseg->size) { 60601ae08745Sheppo DWARN(DBG_ALL_LDCS, 60611ae08745Sheppo "i_ldc_mem_acquire_release: memory out of range\n"); 60621ae08745Sheppo mutex_exit(&mhdl->lock); 60631ae08745Sheppo return (EINVAL); 60641ae08745Sheppo } 60651ae08745Sheppo 60661ae08745Sheppo /* get the channel handle and memory segment */ 60671ae08745Sheppo ldcp = mhdl->ldcp; 60681ae08745Sheppo memseg = mhdl->memseg; 60691ae08745Sheppo 60701ae08745Sheppo if (mhdl->mtype == LDC_SHADOW_MAP) { 60711ae08745Sheppo 60721ae08745Sheppo local_vaddr = memseg->vaddr + offset; 60731ae08745Sheppo copy_size = size; 60741ae08745Sheppo 60751ae08745Sheppo /* copy to/from remote from/to local memory */ 60761ae08745Sheppo err = ldc_mem_copy((ldc_handle_t)ldcp, local_vaddr, offset, 60771ae08745Sheppo ©_size, memseg->cookies, memseg->ncookies, 60781ae08745Sheppo direction); 60791ae08745Sheppo if (err || copy_size != size) { 6080cb112a14Slm66018 DWARN(ldcp->id, 60811ae08745Sheppo "i_ldc_mem_acquire_release: copy failed\n"); 60821ae08745Sheppo mutex_exit(&mhdl->lock); 60831ae08745Sheppo return (err); 60841ae08745Sheppo } 60851ae08745Sheppo } 60861ae08745Sheppo 60871ae08745Sheppo mutex_exit(&mhdl->lock); 60881ae08745Sheppo 60891ae08745Sheppo return (0); 60901ae08745Sheppo } 60911ae08745Sheppo 60921ae08745Sheppo /* 60931ae08745Sheppo * Ensure that the contents in the remote memory seg are consistent 60941ae08745Sheppo * with the contents if of local segment 60951ae08745Sheppo */ 60961ae08745Sheppo int 60971ae08745Sheppo ldc_mem_acquire(ldc_mem_handle_t mhandle, uint64_t offset, uint64_t size) 60981ae08745Sheppo { 60991ae08745Sheppo return (i_ldc_mem_acquire_release(mhandle, LDC_COPY_IN, offset, size)); 61001ae08745Sheppo } 61011ae08745Sheppo 61021ae08745Sheppo 61031ae08745Sheppo /* 61041ae08745Sheppo * Ensure that the contents in the local memory seg are consistent 61051ae08745Sheppo * with the contents if of remote segment 61061ae08745Sheppo */ 61071ae08745Sheppo int 61081ae08745Sheppo ldc_mem_release(ldc_mem_handle_t mhandle, uint64_t offset, uint64_t size) 61091ae08745Sheppo { 61101ae08745Sheppo return (i_ldc_mem_acquire_release(mhandle, LDC_COPY_OUT, offset, size)); 61111ae08745Sheppo } 61121ae08745Sheppo 61131ae08745Sheppo /* 61141ae08745Sheppo * Allocate a descriptor ring. The size of each each descriptor 61151ae08745Sheppo * must be 8-byte aligned and the entire ring should be a multiple 61161ae08745Sheppo * of MMU_PAGESIZE. 61171ae08745Sheppo */ 61181ae08745Sheppo int 61191ae08745Sheppo ldc_mem_dring_create(uint32_t len, uint32_t dsize, ldc_dring_handle_t *dhandle) 61201ae08745Sheppo { 61211ae08745Sheppo ldc_dring_t *dringp; 61221ae08745Sheppo size_t size = (dsize * len); 61231ae08745Sheppo 61241ae08745Sheppo D1(DBG_ALL_LDCS, "ldc_mem_dring_create: len=0x%x, size=0x%x\n", 61251ae08745Sheppo len, dsize); 61261ae08745Sheppo 61271ae08745Sheppo if (dhandle == NULL) { 61281ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_mem_dring_create: invalid dhandle\n"); 61291ae08745Sheppo return (EINVAL); 61301ae08745Sheppo } 61311ae08745Sheppo 61321ae08745Sheppo if (len == 0) { 61331ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_mem_dring_create: invalid length\n"); 61341ae08745Sheppo return (EINVAL); 61351ae08745Sheppo } 61361ae08745Sheppo 61371ae08745Sheppo /* descriptor size should be 8-byte aligned */ 61381ae08745Sheppo if (dsize == 0 || (dsize & 0x7)) { 61391ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_mem_dring_create: invalid size\n"); 61401ae08745Sheppo return (EINVAL); 61411ae08745Sheppo } 61421ae08745Sheppo 61431ae08745Sheppo *dhandle = 0; 61441ae08745Sheppo 61451ae08745Sheppo /* Allocate a desc ring structure */ 61461ae08745Sheppo dringp = kmem_zalloc(sizeof (ldc_dring_t), KM_SLEEP); 61471ae08745Sheppo 61481ae08745Sheppo /* Initialize dring */ 61491ae08745Sheppo dringp->length = len; 61501ae08745Sheppo dringp->dsize = dsize; 61511ae08745Sheppo 61521ae08745Sheppo /* round off to multiple of pagesize */ 61531ae08745Sheppo dringp->size = (size & MMU_PAGEMASK); 61541ae08745Sheppo if (size & MMU_PAGEOFFSET) 61551ae08745Sheppo dringp->size += MMU_PAGESIZE; 61561ae08745Sheppo 61571ae08745Sheppo dringp->status = LDC_UNBOUND; 61581ae08745Sheppo 61591ae08745Sheppo /* allocate descriptor ring memory */ 61603af08d82Slm66018 dringp->base = kmem_zalloc(dringp->size, KM_SLEEP); 61611ae08745Sheppo 61621ae08745Sheppo /* initialize the desc ring lock */ 61631ae08745Sheppo mutex_init(&dringp->lock, NULL, MUTEX_DRIVER, NULL); 61641ae08745Sheppo 61651ae08745Sheppo /* Add descriptor ring to the head of global list */ 61661ae08745Sheppo mutex_enter(&ldcssp->lock); 61671ae08745Sheppo dringp->next = ldcssp->dring_list; 61681ae08745Sheppo ldcssp->dring_list = dringp; 61691ae08745Sheppo mutex_exit(&ldcssp->lock); 61701ae08745Sheppo 61711ae08745Sheppo *dhandle = (ldc_dring_handle_t)dringp; 61721ae08745Sheppo 61731ae08745Sheppo D1(DBG_ALL_LDCS, "ldc_mem_dring_create: dring allocated\n"); 61741ae08745Sheppo 61751ae08745Sheppo return (0); 61761ae08745Sheppo } 61771ae08745Sheppo 61781ae08745Sheppo 61791ae08745Sheppo /* 61801ae08745Sheppo * Destroy a descriptor ring. 61811ae08745Sheppo */ 61821ae08745Sheppo int 61831ae08745Sheppo ldc_mem_dring_destroy(ldc_dring_handle_t dhandle) 61841ae08745Sheppo { 61851ae08745Sheppo ldc_dring_t *dringp; 61861ae08745Sheppo ldc_dring_t *tmp_dringp; 61871ae08745Sheppo 61881ae08745Sheppo D1(DBG_ALL_LDCS, "ldc_mem_dring_destroy: entered\n"); 61891ae08745Sheppo 61901ae08745Sheppo if (dhandle == NULL) { 61911ae08745Sheppo DWARN(DBG_ALL_LDCS, 61921ae08745Sheppo "ldc_mem_dring_destroy: invalid desc ring handle\n"); 61931ae08745Sheppo return (EINVAL); 61941ae08745Sheppo } 61951ae08745Sheppo dringp = (ldc_dring_t *)dhandle; 61961ae08745Sheppo 61971ae08745Sheppo if (dringp->status == LDC_BOUND) { 61981ae08745Sheppo DWARN(DBG_ALL_LDCS, 61991ae08745Sheppo "ldc_mem_dring_destroy: desc ring is bound\n"); 62001ae08745Sheppo return (EACCES); 62011ae08745Sheppo } 62021ae08745Sheppo 62031ae08745Sheppo mutex_enter(&dringp->lock); 62041ae08745Sheppo mutex_enter(&ldcssp->lock); 62051ae08745Sheppo 62061ae08745Sheppo /* remove from linked list - if not bound */ 62071ae08745Sheppo tmp_dringp = ldcssp->dring_list; 62081ae08745Sheppo if (tmp_dringp == dringp) { 62091ae08745Sheppo ldcssp->dring_list = dringp->next; 62101ae08745Sheppo dringp->next = NULL; 62111ae08745Sheppo 62121ae08745Sheppo } else { 62131ae08745Sheppo while (tmp_dringp != NULL) { 62141ae08745Sheppo if (tmp_dringp->next == dringp) { 62151ae08745Sheppo tmp_dringp->next = dringp->next; 62161ae08745Sheppo dringp->next = NULL; 62171ae08745Sheppo break; 62181ae08745Sheppo } 62191ae08745Sheppo tmp_dringp = tmp_dringp->next; 62201ae08745Sheppo } 62211ae08745Sheppo if (tmp_dringp == NULL) { 62221ae08745Sheppo DWARN(DBG_ALL_LDCS, 62231ae08745Sheppo "ldc_mem_dring_destroy: invalid descriptor\n"); 62241ae08745Sheppo mutex_exit(&ldcssp->lock); 62251ae08745Sheppo mutex_exit(&dringp->lock); 62261ae08745Sheppo return (EINVAL); 62271ae08745Sheppo } 62281ae08745Sheppo } 62291ae08745Sheppo 62301ae08745Sheppo mutex_exit(&ldcssp->lock); 62311ae08745Sheppo 62321ae08745Sheppo /* free the descriptor ring */ 62333af08d82Slm66018 kmem_free(dringp->base, dringp->size); 62341ae08745Sheppo 62351ae08745Sheppo mutex_exit(&dringp->lock); 62361ae08745Sheppo 62371ae08745Sheppo /* destroy dring lock */ 62381ae08745Sheppo mutex_destroy(&dringp->lock); 62391ae08745Sheppo 62401ae08745Sheppo /* free desc ring object */ 62411ae08745Sheppo kmem_free(dringp, sizeof (ldc_dring_t)); 62421ae08745Sheppo 62431ae08745Sheppo return (0); 62441ae08745Sheppo } 62451ae08745Sheppo 62461ae08745Sheppo /* 62471ae08745Sheppo * Bind a previously allocated dring to a channel. The channel should 62481ae08745Sheppo * be OPEN in order to bind the ring to the channel. Returns back a 62491ae08745Sheppo * descriptor ring cookie. The descriptor ring is exported for remote 62501ae08745Sheppo * access by the client at the other end of the channel. An entry for 62511ae08745Sheppo * dring pages is stored in map table (via call to ldc_mem_bind_handle). 62521ae08745Sheppo */ 62531ae08745Sheppo int 62541ae08745Sheppo ldc_mem_dring_bind(ldc_handle_t handle, ldc_dring_handle_t dhandle, 62551ae08745Sheppo uint8_t mtype, uint8_t perm, ldc_mem_cookie_t *cookie, uint32_t *ccount) 62561ae08745Sheppo { 62571ae08745Sheppo int err; 62581ae08745Sheppo ldc_chan_t *ldcp; 62591ae08745Sheppo ldc_dring_t *dringp; 62601ae08745Sheppo ldc_mem_handle_t mhandle; 62611ae08745Sheppo 62621ae08745Sheppo /* check to see if channel is initalized */ 62631ae08745Sheppo if (handle == NULL) { 62641ae08745Sheppo DWARN(DBG_ALL_LDCS, 62651ae08745Sheppo "ldc_mem_dring_bind: invalid channel handle\n"); 62661ae08745Sheppo return (EINVAL); 62671ae08745Sheppo } 62681ae08745Sheppo ldcp = (ldc_chan_t *)handle; 62691ae08745Sheppo 62701ae08745Sheppo if (dhandle == NULL) { 62711ae08745Sheppo DWARN(DBG_ALL_LDCS, 62721ae08745Sheppo "ldc_mem_dring_bind: invalid desc ring handle\n"); 62731ae08745Sheppo return (EINVAL); 62741ae08745Sheppo } 62751ae08745Sheppo dringp = (ldc_dring_t *)dhandle; 62761ae08745Sheppo 62771ae08745Sheppo if (cookie == NULL) { 62781ae08745Sheppo DWARN(ldcp->id, 62791ae08745Sheppo "ldc_mem_dring_bind: invalid cookie arg\n"); 62801ae08745Sheppo return (EINVAL); 62811ae08745Sheppo } 62821ae08745Sheppo 62831ae08745Sheppo mutex_enter(&dringp->lock); 62841ae08745Sheppo 62851ae08745Sheppo if (dringp->status == LDC_BOUND) { 62861ae08745Sheppo DWARN(DBG_ALL_LDCS, 62871ae08745Sheppo "ldc_mem_dring_bind: (0x%llx) descriptor ring is bound\n", 62881ae08745Sheppo ldcp->id); 62891ae08745Sheppo mutex_exit(&dringp->lock); 62901ae08745Sheppo return (EINVAL); 62911ae08745Sheppo } 62921ae08745Sheppo 62931ae08745Sheppo if ((perm & LDC_MEM_RW) == 0) { 62941ae08745Sheppo DWARN(DBG_ALL_LDCS, 62951ae08745Sheppo "ldc_mem_dring_bind: invalid permissions\n"); 62961ae08745Sheppo mutex_exit(&dringp->lock); 62971ae08745Sheppo return (EINVAL); 62981ae08745Sheppo } 62991ae08745Sheppo 63001ae08745Sheppo if ((mtype & (LDC_SHADOW_MAP|LDC_DIRECT_MAP|LDC_IO_MAP)) == 0) { 63011ae08745Sheppo DWARN(DBG_ALL_LDCS, "ldc_mem_dring_bind: invalid type\n"); 63021ae08745Sheppo mutex_exit(&dringp->lock); 63031ae08745Sheppo return (EINVAL); 63041ae08745Sheppo } 63051ae08745Sheppo 63061ae08745Sheppo dringp->ldcp = ldcp; 63071ae08745Sheppo 63081ae08745Sheppo /* create an memory handle */ 63091ae08745Sheppo err = ldc_mem_alloc_handle(handle, &mhandle); 63101ae08745Sheppo if (err || mhandle == NULL) { 63111ae08745Sheppo DWARN(DBG_ALL_LDCS, 63121ae08745Sheppo "ldc_mem_dring_bind: (0x%llx) error allocating mhandle\n", 63131ae08745Sheppo ldcp->id); 63141ae08745Sheppo mutex_exit(&dringp->lock); 63151ae08745Sheppo return (err); 63161ae08745Sheppo } 63171ae08745Sheppo dringp->mhdl = mhandle; 63181ae08745Sheppo 63191ae08745Sheppo /* bind the descriptor ring to channel */ 63201ae08745Sheppo err = ldc_mem_bind_handle(mhandle, dringp->base, dringp->size, 63211ae08745Sheppo mtype, perm, cookie, ccount); 63221ae08745Sheppo if (err) { 63231ae08745Sheppo DWARN(ldcp->id, 63241ae08745Sheppo "ldc_mem_dring_bind: (0x%llx) error binding mhandle\n", 63251ae08745Sheppo ldcp->id); 63261ae08745Sheppo mutex_exit(&dringp->lock); 63271ae08745Sheppo return (err); 63281ae08745Sheppo } 63291ae08745Sheppo 63301ae08745Sheppo /* 63311ae08745Sheppo * For now return error if we get more than one cookie 63321ae08745Sheppo * FUTURE: Return multiple cookies .. 63331ae08745Sheppo */ 63341ae08745Sheppo if (*ccount > 1) { 63351ae08745Sheppo (void) ldc_mem_unbind_handle(mhandle); 63361ae08745Sheppo (void) ldc_mem_free_handle(mhandle); 63371ae08745Sheppo 63381ae08745Sheppo dringp->ldcp = NULL; 63391ae08745Sheppo dringp->mhdl = NULL; 63401ae08745Sheppo *ccount = 0; 63411ae08745Sheppo 63421ae08745Sheppo mutex_exit(&dringp->lock); 63431ae08745Sheppo return (EAGAIN); 63441ae08745Sheppo } 63451ae08745Sheppo 63461ae08745Sheppo /* Add descriptor ring to channel's exported dring list */ 63471ae08745Sheppo mutex_enter(&ldcp->exp_dlist_lock); 63481ae08745Sheppo dringp->ch_next = ldcp->exp_dring_list; 63491ae08745Sheppo ldcp->exp_dring_list = dringp; 63501ae08745Sheppo mutex_exit(&ldcp->exp_dlist_lock); 63511ae08745Sheppo 63521ae08745Sheppo dringp->status = LDC_BOUND; 63531ae08745Sheppo 63541ae08745Sheppo mutex_exit(&dringp->lock); 63551ae08745Sheppo 63561ae08745Sheppo return (0); 63571ae08745Sheppo } 63581ae08745Sheppo 63591ae08745Sheppo /* 63601ae08745Sheppo * Return the next cookie associated with the specified dring handle 63611ae08745Sheppo */ 63621ae08745Sheppo int 63631ae08745Sheppo ldc_mem_dring_nextcookie(ldc_dring_handle_t dhandle, ldc_mem_cookie_t *cookie) 63641ae08745Sheppo { 63651ae08745Sheppo int rv = 0; 63661ae08745Sheppo ldc_dring_t *dringp; 63671ae08745Sheppo ldc_chan_t *ldcp; 63681ae08745Sheppo 63691ae08745Sheppo if (dhandle == NULL) { 63701ae08745Sheppo DWARN(DBG_ALL_LDCS, 63711ae08745Sheppo "ldc_mem_dring_nextcookie: invalid desc ring handle\n"); 63721ae08745Sheppo return (EINVAL); 63731ae08745Sheppo } 63741ae08745Sheppo dringp = (ldc_dring_t *)dhandle; 63751ae08745Sheppo mutex_enter(&dringp->lock); 63761ae08745Sheppo 63771ae08745Sheppo if (dringp->status != LDC_BOUND) { 63781ae08745Sheppo DWARN(DBG_ALL_LDCS, 63791ae08745Sheppo "ldc_mem_dring_nextcookie: descriptor ring 0x%llx " 63801ae08745Sheppo "is not bound\n", dringp); 63811ae08745Sheppo mutex_exit(&dringp->lock); 63821ae08745Sheppo return (EINVAL); 63831ae08745Sheppo } 63841ae08745Sheppo 63851ae08745Sheppo ldcp = dringp->ldcp; 63861ae08745Sheppo 63871ae08745Sheppo if (cookie == NULL) { 63881ae08745Sheppo DWARN(ldcp->id, 63891ae08745Sheppo "ldc_mem_dring_nextcookie:(0x%llx) invalid cookie arg\n", 63901ae08745Sheppo ldcp->id); 63911ae08745Sheppo mutex_exit(&dringp->lock); 63921ae08745Sheppo return (EINVAL); 63931ae08745Sheppo } 63941ae08745Sheppo 63951ae08745Sheppo rv = ldc_mem_nextcookie((ldc_mem_handle_t)dringp->mhdl, cookie); 63961ae08745Sheppo mutex_exit(&dringp->lock); 63971ae08745Sheppo 63981ae08745Sheppo return (rv); 63991ae08745Sheppo } 64001ae08745Sheppo /* 64011ae08745Sheppo * Unbind a previously bound dring from a channel. 64021ae08745Sheppo */ 64031ae08745Sheppo int 64041ae08745Sheppo ldc_mem_dring_unbind(ldc_dring_handle_t dhandle) 64051ae08745Sheppo { 64061ae08745Sheppo ldc_dring_t *dringp; 64071ae08745Sheppo ldc_dring_t *tmp_dringp; 64081ae08745Sheppo ldc_chan_t *ldcp; 64091ae08745Sheppo 64101ae08745Sheppo if (dhandle == NULL) { 64111ae08745Sheppo DWARN(DBG_ALL_LDCS, 64121ae08745Sheppo "ldc_mem_dring_unbind: invalid desc ring handle\n"); 64131ae08745Sheppo return (EINVAL); 64141ae08745Sheppo } 64151ae08745Sheppo dringp = (ldc_dring_t *)dhandle; 64161ae08745Sheppo 64171ae08745Sheppo mutex_enter(&dringp->lock); 64181ae08745Sheppo 64191ae08745Sheppo if (dringp->status == LDC_UNBOUND) { 64201ae08745Sheppo DWARN(DBG_ALL_LDCS, 64211ae08745Sheppo "ldc_mem_dring_bind: descriptor ring 0x%llx is unbound\n", 64221ae08745Sheppo dringp); 64231ae08745Sheppo mutex_exit(&dringp->lock); 64241ae08745Sheppo return (EINVAL); 64251ae08745Sheppo } 64261ae08745Sheppo ldcp = dringp->ldcp; 64271ae08745Sheppo 64281ae08745Sheppo mutex_enter(&ldcp->exp_dlist_lock); 64291ae08745Sheppo 64301ae08745Sheppo tmp_dringp = ldcp->exp_dring_list; 64311ae08745Sheppo if (tmp_dringp == dringp) { 64321ae08745Sheppo ldcp->exp_dring_list = dringp->ch_next; 64331ae08745Sheppo dringp->ch_next = NULL; 64341ae08745Sheppo 64351ae08745Sheppo } else { 64361ae08745Sheppo while (tmp_dringp != NULL) { 64371ae08745Sheppo if (tmp_dringp->ch_next == dringp) { 64381ae08745Sheppo tmp_dringp->ch_next = dringp->ch_next; 64391ae08745Sheppo dringp->ch_next = NULL; 64401ae08745Sheppo break; 64411ae08745Sheppo } 64421ae08745Sheppo tmp_dringp = tmp_dringp->ch_next; 64431ae08745Sheppo } 64441ae08745Sheppo if (tmp_dringp == NULL) { 64451ae08745Sheppo DWARN(DBG_ALL_LDCS, 64461ae08745Sheppo "ldc_mem_dring_unbind: invalid descriptor\n"); 64471ae08745Sheppo mutex_exit(&ldcp->exp_dlist_lock); 64481ae08745Sheppo mutex_exit(&dringp->lock); 64491ae08745Sheppo return (EINVAL); 64501ae08745Sheppo } 64511ae08745Sheppo } 64521ae08745Sheppo 64531ae08745Sheppo mutex_exit(&ldcp->exp_dlist_lock); 64541ae08745Sheppo 64551ae08745Sheppo (void) ldc_mem_unbind_handle((ldc_mem_handle_t)dringp->mhdl); 64561ae08745Sheppo (void) ldc_mem_free_handle((ldc_mem_handle_t)dringp->mhdl); 64571ae08745Sheppo 64581ae08745Sheppo dringp->ldcp = NULL; 64591ae08745Sheppo dringp->mhdl = NULL; 64601ae08745Sheppo dringp->status = LDC_UNBOUND; 64611ae08745Sheppo 64621ae08745Sheppo mutex_exit(&dringp->lock); 64631ae08745Sheppo 64641ae08745Sheppo return (0); 64651ae08745Sheppo } 64661ae08745Sheppo 64671ae08745Sheppo /* 64681ae08745Sheppo * Get information about the dring. The base address of the descriptor 64691ae08745Sheppo * ring along with the type and permission are returned back. 64701ae08745Sheppo */ 64711ae08745Sheppo int 64721ae08745Sheppo ldc_mem_dring_info(ldc_dring_handle_t dhandle, ldc_mem_info_t *minfo) 64731ae08745Sheppo { 64741ae08745Sheppo ldc_dring_t *dringp; 64751ae08745Sheppo int rv; 64761ae08745Sheppo 64771ae08745Sheppo if (dhandle == NULL) { 64781ae08745Sheppo DWARN(DBG_ALL_LDCS, 64791ae08745Sheppo "ldc_mem_dring_info: invalid desc ring handle\n"); 64801ae08745Sheppo return (EINVAL); 64811ae08745Sheppo } 64821ae08745Sheppo dringp = (ldc_dring_t *)dhandle; 64831ae08745Sheppo 64841ae08745Sheppo mutex_enter(&dringp->lock); 64851ae08745Sheppo 64861ae08745Sheppo if (dringp->mhdl) { 64871ae08745Sheppo rv = ldc_mem_info(dringp->mhdl, minfo); 64881ae08745Sheppo if (rv) { 64891ae08745Sheppo DWARN(DBG_ALL_LDCS, 64901ae08745Sheppo "ldc_mem_dring_info: error reading mem info\n"); 64911ae08745Sheppo mutex_exit(&dringp->lock); 64921ae08745Sheppo return (rv); 64931ae08745Sheppo } 64941ae08745Sheppo } else { 64951ae08745Sheppo minfo->vaddr = dringp->base; 64961ae08745Sheppo minfo->raddr = NULL; 64971ae08745Sheppo minfo->status = dringp->status; 64981ae08745Sheppo } 64991ae08745Sheppo 65001ae08745Sheppo mutex_exit(&dringp->lock); 65011ae08745Sheppo 65021ae08745Sheppo return (0); 65031ae08745Sheppo } 65041ae08745Sheppo 65051ae08745Sheppo /* 65061ae08745Sheppo * Map an exported descriptor ring into the local address space. If the 65071ae08745Sheppo * descriptor ring was exported for direct map access, a HV call is made 65081ae08745Sheppo * to allocate a RA range. If the map is done via a shadow copy, local 65091ae08745Sheppo * shadow memory is allocated. 65101ae08745Sheppo */ 65111ae08745Sheppo int 65121ae08745Sheppo ldc_mem_dring_map(ldc_handle_t handle, ldc_mem_cookie_t *cookie, 65131ae08745Sheppo uint32_t ccount, uint32_t len, uint32_t dsize, uint8_t mtype, 65141ae08745Sheppo ldc_dring_handle_t *dhandle) 65151ae08745Sheppo { 65161ae08745Sheppo int err; 65171ae08745Sheppo ldc_chan_t *ldcp = (ldc_chan_t *)handle; 65181ae08745Sheppo ldc_mem_handle_t mhandle; 65191ae08745Sheppo ldc_dring_t *dringp; 65201ae08745Sheppo size_t dring_size; 65211ae08745Sheppo 65221ae08745Sheppo if (dhandle == NULL) { 65231ae08745Sheppo DWARN(DBG_ALL_LDCS, 65241ae08745Sheppo "ldc_mem_dring_map: invalid dhandle\n"); 65251ae08745Sheppo return (EINVAL); 65261ae08745Sheppo } 65271ae08745Sheppo 65281ae08745Sheppo /* check to see if channel is initalized */ 65291ae08745Sheppo if (handle == NULL) { 65301ae08745Sheppo DWARN(DBG_ALL_LDCS, 65311ae08745Sheppo "ldc_mem_dring_map: invalid channel handle\n"); 65321ae08745Sheppo return (EINVAL); 65331ae08745Sheppo } 65341ae08745Sheppo ldcp = (ldc_chan_t *)handle; 65351ae08745Sheppo 65361ae08745Sheppo if (cookie == NULL) { 65371ae08745Sheppo DWARN(ldcp->id, 65381ae08745Sheppo "ldc_mem_dring_map: (0x%llx) invalid cookie\n", 65391ae08745Sheppo ldcp->id); 65401ae08745Sheppo return (EINVAL); 65411ae08745Sheppo } 65421ae08745Sheppo 65431ae08745Sheppo /* FUTURE: For now we support only one cookie per dring */ 65441ae08745Sheppo ASSERT(ccount == 1); 65451ae08745Sheppo 65461ae08745Sheppo if (cookie->size < (dsize * len)) { 65471ae08745Sheppo DWARN(ldcp->id, 65481ae08745Sheppo "ldc_mem_dring_map: (0x%llx) invalid dsize/len\n", 65491ae08745Sheppo ldcp->id); 65501ae08745Sheppo return (EINVAL); 65511ae08745Sheppo } 65521ae08745Sheppo 65531ae08745Sheppo *dhandle = 0; 65541ae08745Sheppo 65551ae08745Sheppo /* Allocate an dring structure */ 65561ae08745Sheppo dringp = kmem_zalloc(sizeof (ldc_dring_t), KM_SLEEP); 65571ae08745Sheppo 65581ae08745Sheppo D1(ldcp->id, 65591ae08745Sheppo "ldc_mem_dring_map: 0x%x,0x%x,0x%x,0x%llx,0x%llx\n", 65601ae08745Sheppo mtype, len, dsize, cookie->addr, cookie->size); 65611ae08745Sheppo 65621ae08745Sheppo /* Initialize dring */ 65631ae08745Sheppo dringp->length = len; 65641ae08745Sheppo dringp->dsize = dsize; 65651ae08745Sheppo 65661ae08745Sheppo /* round of to multiple of page size */ 65671ae08745Sheppo dring_size = len * dsize; 65681ae08745Sheppo dringp->size = (dring_size & MMU_PAGEMASK); 65691ae08745Sheppo if (dring_size & MMU_PAGEOFFSET) 65701ae08745Sheppo dringp->size += MMU_PAGESIZE; 65711ae08745Sheppo 65721ae08745Sheppo dringp->ldcp = ldcp; 65731ae08745Sheppo 65741ae08745Sheppo /* create an memory handle */ 65751ae08745Sheppo err = ldc_mem_alloc_handle(handle, &mhandle); 65761ae08745Sheppo if (err || mhandle == NULL) { 65771ae08745Sheppo DWARN(DBG_ALL_LDCS, 65781ae08745Sheppo "ldc_mem_dring_map: cannot alloc hdl err=%d\n", 65791ae08745Sheppo err); 65801ae08745Sheppo kmem_free(dringp, sizeof (ldc_dring_t)); 65811ae08745Sheppo return (ENOMEM); 65821ae08745Sheppo } 65831ae08745Sheppo 65841ae08745Sheppo dringp->mhdl = mhandle; 65851ae08745Sheppo dringp->base = NULL; 65861ae08745Sheppo 65871ae08745Sheppo /* map the dring into local memory */ 65884bac2208Snarayan err = ldc_mem_map(mhandle, cookie, ccount, mtype, LDC_MEM_RW, 65891ae08745Sheppo &(dringp->base), NULL); 65901ae08745Sheppo if (err || dringp->base == NULL) { 65911ae08745Sheppo cmn_err(CE_WARN, 65921ae08745Sheppo "ldc_mem_dring_map: cannot map desc ring err=%d\n", err); 65931ae08745Sheppo (void) ldc_mem_free_handle(mhandle); 65941ae08745Sheppo kmem_free(dringp, sizeof (ldc_dring_t)); 65951ae08745Sheppo return (ENOMEM); 65961ae08745Sheppo } 65971ae08745Sheppo 65981ae08745Sheppo /* initialize the desc ring lock */ 65991ae08745Sheppo mutex_init(&dringp->lock, NULL, MUTEX_DRIVER, NULL); 66001ae08745Sheppo 66011ae08745Sheppo /* Add descriptor ring to channel's imported dring list */ 66021ae08745Sheppo mutex_enter(&ldcp->imp_dlist_lock); 66031ae08745Sheppo dringp->ch_next = ldcp->imp_dring_list; 66041ae08745Sheppo ldcp->imp_dring_list = dringp; 66051ae08745Sheppo mutex_exit(&ldcp->imp_dlist_lock); 66061ae08745Sheppo 66071ae08745Sheppo dringp->status = LDC_MAPPED; 66081ae08745Sheppo 66091ae08745Sheppo *dhandle = (ldc_dring_handle_t)dringp; 66101ae08745Sheppo 66111ae08745Sheppo return (0); 66121ae08745Sheppo } 66131ae08745Sheppo 66141ae08745Sheppo /* 66151ae08745Sheppo * Unmap a descriptor ring. Free shadow memory (if any). 66161ae08745Sheppo */ 66171ae08745Sheppo int 66181ae08745Sheppo ldc_mem_dring_unmap(ldc_dring_handle_t dhandle) 66191ae08745Sheppo { 66201ae08745Sheppo ldc_dring_t *dringp; 66211ae08745Sheppo ldc_dring_t *tmp_dringp; 66221ae08745Sheppo ldc_chan_t *ldcp; 66231ae08745Sheppo 66241ae08745Sheppo if (dhandle == NULL) { 66251ae08745Sheppo DWARN(DBG_ALL_LDCS, 66261ae08745Sheppo "ldc_mem_dring_unmap: invalid desc ring handle\n"); 66271ae08745Sheppo return (EINVAL); 66281ae08745Sheppo } 66291ae08745Sheppo dringp = (ldc_dring_t *)dhandle; 66301ae08745Sheppo 66311ae08745Sheppo if (dringp->status != LDC_MAPPED) { 66321ae08745Sheppo DWARN(DBG_ALL_LDCS, 66331ae08745Sheppo "ldc_mem_dring_unmap: not a mapped desc ring\n"); 66341ae08745Sheppo return (EINVAL); 66351ae08745Sheppo } 66361ae08745Sheppo 66371ae08745Sheppo mutex_enter(&dringp->lock); 66381ae08745Sheppo 66391ae08745Sheppo ldcp = dringp->ldcp; 66401ae08745Sheppo 66411ae08745Sheppo mutex_enter(&ldcp->imp_dlist_lock); 66421ae08745Sheppo 66431ae08745Sheppo /* find and unlink the desc ring from channel import list */ 66441ae08745Sheppo tmp_dringp = ldcp->imp_dring_list; 66451ae08745Sheppo if (tmp_dringp == dringp) { 66461ae08745Sheppo ldcp->imp_dring_list = dringp->ch_next; 66471ae08745Sheppo dringp->ch_next = NULL; 66481ae08745Sheppo 66491ae08745Sheppo } else { 66501ae08745Sheppo while (tmp_dringp != NULL) { 66511ae08745Sheppo if (tmp_dringp->ch_next == dringp) { 66521ae08745Sheppo tmp_dringp->ch_next = dringp->ch_next; 66531ae08745Sheppo dringp->ch_next = NULL; 66541ae08745Sheppo break; 66551ae08745Sheppo } 66561ae08745Sheppo tmp_dringp = tmp_dringp->ch_next; 66571ae08745Sheppo } 66581ae08745Sheppo if (tmp_dringp == NULL) { 66591ae08745Sheppo DWARN(DBG_ALL_LDCS, 66601ae08745Sheppo "ldc_mem_dring_unmap: invalid descriptor\n"); 66611ae08745Sheppo mutex_exit(&ldcp->imp_dlist_lock); 66621ae08745Sheppo mutex_exit(&dringp->lock); 66631ae08745Sheppo return (EINVAL); 66641ae08745Sheppo } 66651ae08745Sheppo } 66661ae08745Sheppo 66671ae08745Sheppo mutex_exit(&ldcp->imp_dlist_lock); 66681ae08745Sheppo 66691ae08745Sheppo /* do a LDC memory handle unmap and free */ 66701ae08745Sheppo (void) ldc_mem_unmap(dringp->mhdl); 66711ae08745Sheppo (void) ldc_mem_free_handle((ldc_mem_handle_t)dringp->mhdl); 66721ae08745Sheppo 66731ae08745Sheppo dringp->status = 0; 66741ae08745Sheppo dringp->ldcp = NULL; 66751ae08745Sheppo 66761ae08745Sheppo mutex_exit(&dringp->lock); 66771ae08745Sheppo 66781ae08745Sheppo /* destroy dring lock */ 66791ae08745Sheppo mutex_destroy(&dringp->lock); 66801ae08745Sheppo 66811ae08745Sheppo /* free desc ring object */ 66821ae08745Sheppo kmem_free(dringp, sizeof (ldc_dring_t)); 66831ae08745Sheppo 66841ae08745Sheppo return (0); 66851ae08745Sheppo } 66861ae08745Sheppo 66871ae08745Sheppo /* 66881ae08745Sheppo * Internal entry point for descriptor ring access entry consistency 66891ae08745Sheppo * semantics. Acquire copies the contents of the remote descriptor ring 66901ae08745Sheppo * into the local shadow copy. The release operation copies the local 66911ae08745Sheppo * contents into the remote dring. The start and end locations specify 66921ae08745Sheppo * bounds for the entries being synchronized. 66931ae08745Sheppo */ 66941ae08745Sheppo static int 66951ae08745Sheppo i_ldc_dring_acquire_release(ldc_dring_handle_t dhandle, 66961ae08745Sheppo uint8_t direction, uint64_t start, uint64_t end) 66971ae08745Sheppo { 66981ae08745Sheppo int err; 66991ae08745Sheppo ldc_dring_t *dringp; 67001ae08745Sheppo ldc_chan_t *ldcp; 67011ae08745Sheppo uint64_t soff; 67021ae08745Sheppo size_t copy_size; 67031ae08745Sheppo 67041ae08745Sheppo if (dhandle == NULL) { 67051ae08745Sheppo DWARN(DBG_ALL_LDCS, 67061ae08745Sheppo "i_ldc_dring_acquire_release: invalid desc ring handle\n"); 67071ae08745Sheppo return (EINVAL); 67081ae08745Sheppo } 67091ae08745Sheppo dringp = (ldc_dring_t *)dhandle; 67101ae08745Sheppo mutex_enter(&dringp->lock); 67111ae08745Sheppo 67121ae08745Sheppo if (dringp->status != LDC_MAPPED || dringp->ldcp == NULL) { 67131ae08745Sheppo DWARN(DBG_ALL_LDCS, 67141ae08745Sheppo "i_ldc_dring_acquire_release: not a mapped desc ring\n"); 67151ae08745Sheppo mutex_exit(&dringp->lock); 67161ae08745Sheppo return (EINVAL); 67171ae08745Sheppo } 67181ae08745Sheppo 67191ae08745Sheppo if (start >= dringp->length || end >= dringp->length) { 67201ae08745Sheppo DWARN(DBG_ALL_LDCS, 67211ae08745Sheppo "i_ldc_dring_acquire_release: index out of range\n"); 67221ae08745Sheppo mutex_exit(&dringp->lock); 67231ae08745Sheppo return (EINVAL); 67241ae08745Sheppo } 67251ae08745Sheppo 67261ae08745Sheppo /* get the channel handle */ 67271ae08745Sheppo ldcp = dringp->ldcp; 67281ae08745Sheppo 67291ae08745Sheppo copy_size = (start <= end) ? (((end - start) + 1) * dringp->dsize) : 67301ae08745Sheppo ((dringp->length - start) * dringp->dsize); 67311ae08745Sheppo 67321ae08745Sheppo /* Calculate the relative offset for the first desc */ 67331ae08745Sheppo soff = (start * dringp->dsize); 67341ae08745Sheppo 67351ae08745Sheppo /* copy to/from remote from/to local memory */ 67361ae08745Sheppo D1(ldcp->id, "i_ldc_dring_acquire_release: c1 off=0x%llx sz=0x%llx\n", 67371ae08745Sheppo soff, copy_size); 67381ae08745Sheppo err = i_ldc_mem_acquire_release((ldc_mem_handle_t)dringp->mhdl, 67391ae08745Sheppo direction, soff, copy_size); 67401ae08745Sheppo if (err) { 67411ae08745Sheppo DWARN(ldcp->id, 67421ae08745Sheppo "i_ldc_dring_acquire_release: copy failed\n"); 67431ae08745Sheppo mutex_exit(&dringp->lock); 67441ae08745Sheppo return (err); 67451ae08745Sheppo } 67461ae08745Sheppo 67471ae08745Sheppo /* do the balance */ 67481ae08745Sheppo if (start > end) { 67491ae08745Sheppo copy_size = ((end + 1) * dringp->dsize); 67501ae08745Sheppo soff = 0; 67511ae08745Sheppo 67521ae08745Sheppo /* copy to/from remote from/to local memory */ 67531ae08745Sheppo D1(ldcp->id, "i_ldc_dring_acquire_release: c2 " 67541ae08745Sheppo "off=0x%llx sz=0x%llx\n", soff, copy_size); 67551ae08745Sheppo err = i_ldc_mem_acquire_release((ldc_mem_handle_t)dringp->mhdl, 67561ae08745Sheppo direction, soff, copy_size); 67571ae08745Sheppo if (err) { 67581ae08745Sheppo DWARN(ldcp->id, 67591ae08745Sheppo "i_ldc_dring_acquire_release: copy failed\n"); 67601ae08745Sheppo mutex_exit(&dringp->lock); 67611ae08745Sheppo return (err); 67621ae08745Sheppo } 67631ae08745Sheppo } 67641ae08745Sheppo 67651ae08745Sheppo mutex_exit(&dringp->lock); 67661ae08745Sheppo 67671ae08745Sheppo return (0); 67681ae08745Sheppo } 67691ae08745Sheppo 67701ae08745Sheppo /* 67711ae08745Sheppo * Ensure that the contents in the local dring are consistent 67721ae08745Sheppo * with the contents if of remote dring 67731ae08745Sheppo */ 67741ae08745Sheppo int 67751ae08745Sheppo ldc_mem_dring_acquire(ldc_dring_handle_t dhandle, uint64_t start, uint64_t end) 67761ae08745Sheppo { 67771ae08745Sheppo return (i_ldc_dring_acquire_release(dhandle, LDC_COPY_IN, start, end)); 67781ae08745Sheppo } 67791ae08745Sheppo 67801ae08745Sheppo /* 67811ae08745Sheppo * Ensure that the contents in the remote dring are consistent 67821ae08745Sheppo * with the contents if of local dring 67831ae08745Sheppo */ 67841ae08745Sheppo int 67851ae08745Sheppo ldc_mem_dring_release(ldc_dring_handle_t dhandle, uint64_t start, uint64_t end) 67861ae08745Sheppo { 67871ae08745Sheppo return (i_ldc_dring_acquire_release(dhandle, LDC_COPY_OUT, start, end)); 67881ae08745Sheppo } 67891ae08745Sheppo 67901ae08745Sheppo 67911ae08745Sheppo /* ------------------------------------------------------------------------- */ 6792