11991Sheppo /* 21991Sheppo * CDDL HEADER START 31991Sheppo * 41991Sheppo * The contents of this file are subject to the terms of the 51991Sheppo * Common Development and Distribution License (the "License"). 61991Sheppo * You may not use this file except in compliance with the License. 71991Sheppo * 81991Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91991Sheppo * or http://www.opensolaris.org/os/licensing. 101991Sheppo * See the License for the specific language governing permissions 111991Sheppo * and limitations under the License. 121991Sheppo * 131991Sheppo * When distributing Covered Code, include this CDDL HEADER in each 141991Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151991Sheppo * If applicable, add the following below this CDDL HEADER, with the 161991Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 171991Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 181991Sheppo * 191991Sheppo * CDDL HEADER END 201991Sheppo */ 211991Sheppo 221991Sheppo /* 231991Sheppo * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 241991Sheppo * Use is subject to license terms. 251991Sheppo */ 261991Sheppo 271991Sheppo #pragma ident "%Z%%M% %I% %E% SMI" 281991Sheppo 291991Sheppo /* 302410Slm66018 * sun4v LDC Link Layer 311991Sheppo */ 321991Sheppo #include <sys/types.h> 331991Sheppo #include <sys/file.h> 341991Sheppo #include <sys/errno.h> 351991Sheppo #include <sys/open.h> 361991Sheppo #include <sys/cred.h> 371991Sheppo #include <sys/kmem.h> 381991Sheppo #include <sys/conf.h> 391991Sheppo #include <sys/cmn_err.h> 401991Sheppo #include <sys/ksynch.h> 411991Sheppo #include <sys/modctl.h> 421991Sheppo #include <sys/stat.h> /* needed for S_IFBLK and S_IFCHR */ 431991Sheppo #include <sys/debug.h> 441991Sheppo #include <sys/types.h> 451991Sheppo #include <sys/cred.h> 461991Sheppo #include <sys/promif.h> 471991Sheppo #include <sys/ddi.h> 481991Sheppo #include <sys/sunddi.h> 491991Sheppo #include <sys/cyclic.h> 501991Sheppo #include <sys/machsystm.h> 511991Sheppo #include <sys/vm.h> 521991Sheppo #include <sys/cpu.h> 531991Sheppo #include <sys/intreg.h> 541991Sheppo #include <sys/machcpuvar.h> 552531Snarayan #include <sys/mmu.h> 562531Snarayan #include <sys/pte.h> 572531Snarayan #include <vm/hat.h> 582531Snarayan #include <vm/as.h> 592531Snarayan #include <vm/hat_sfmmu.h> 602531Snarayan #include <sys/vm_machparam.h> 612531Snarayan #include <vm/seg_kmem.h> 622531Snarayan #include <vm/seg_kpm.h> 631991Sheppo #include <sys/note.h> 641991Sheppo #include <sys/ivintr.h> 651991Sheppo #include <sys/hypervisor_api.h> 661991Sheppo #include <sys/ldc.h> 671991Sheppo #include <sys/ldc_impl.h> 681991Sheppo #include <sys/cnex.h> 691991Sheppo #include <sys/hsvc.h> 701991Sheppo 711991Sheppo /* Core internal functions */ 721991Sheppo static int i_ldc_h2v_error(int h_error); 731991Sheppo static int i_ldc_txq_reconf(ldc_chan_t *ldcp); 742793Slm66018 static int i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset); 752841Snarayan static int i_ldc_rxq_drain(ldc_chan_t *ldcp); 761991Sheppo static void i_ldc_reset_state(ldc_chan_t *ldcp); 772793Slm66018 static void i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset); 781991Sheppo 791991Sheppo static int i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail); 801991Sheppo static int i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail); 811991Sheppo static int i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head); 821991Sheppo static int i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype, 831991Sheppo uint8_t ctrlmsg); 841991Sheppo 851991Sheppo /* Interrupt handling functions */ 861991Sheppo static uint_t i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2); 871991Sheppo static uint_t i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2); 881991Sheppo static void i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype); 891991Sheppo 901991Sheppo /* Read method functions */ 911991Sheppo static int i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep); 921991Sheppo static int i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp, 931991Sheppo size_t *sizep); 941991Sheppo static int i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp, 951991Sheppo size_t *sizep); 961991Sheppo 971991Sheppo /* Write method functions */ 981991Sheppo static int i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t target_bufp, 991991Sheppo size_t *sizep); 1001991Sheppo static int i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t target_bufp, 1011991Sheppo size_t *sizep); 1021991Sheppo static int i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t target_bufp, 1031991Sheppo size_t *sizep); 1041991Sheppo 1051991Sheppo /* Pkt processing internal functions */ 1061991Sheppo static int i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg); 1071991Sheppo static int i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg); 1081991Sheppo static int i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg); 1091991Sheppo static int i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg); 1101991Sheppo static int i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg); 1111991Sheppo static int i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg); 1121991Sheppo static int i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg); 1131991Sheppo 1141991Sheppo /* Memory synchronization internal functions */ 1151991Sheppo static int i_ldc_mem_acquire_release(ldc_mem_handle_t mhandle, 1161991Sheppo uint8_t direction, uint64_t offset, size_t size); 1171991Sheppo static int i_ldc_dring_acquire_release(ldc_dring_handle_t dhandle, 1181991Sheppo uint8_t direction, uint64_t start, uint64_t end); 1191991Sheppo 1201991Sheppo /* LDC Version */ 1211991Sheppo static ldc_ver_t ldc_versions[] = { {1, 0} }; 1221991Sheppo 1231991Sheppo /* number of supported versions */ 1241991Sheppo #define LDC_NUM_VERS (sizeof (ldc_versions) / sizeof (ldc_versions[0])) 1251991Sheppo 1261991Sheppo /* Module State Pointer */ 1271991Sheppo static ldc_soft_state_t *ldcssp; 1281991Sheppo 1291991Sheppo static struct modldrv md = { 1301991Sheppo &mod_miscops, /* This is a misc module */ 1311991Sheppo "sun4v LDC module v%I%", /* Name of the module */ 1321991Sheppo }; 1331991Sheppo 1341991Sheppo static struct modlinkage ml = { 1351991Sheppo MODREV_1, 1361991Sheppo &md, 1371991Sheppo NULL 1381991Sheppo }; 1391991Sheppo 1401991Sheppo static uint64_t ldc_sup_minor; /* Supported minor number */ 1411991Sheppo static hsvc_info_t ldc_hsvc = { 1421991Sheppo HSVC_REV_1, NULL, HSVC_GROUP_LDC, 1, 0, "ldc" 1431991Sheppo }; 1441991Sheppo 1451991Sheppo static uint64_t intr_sup_minor; /* Supported minor number */ 1461991Sheppo static hsvc_info_t intr_hsvc = { 1471991Sheppo HSVC_REV_1, NULL, HSVC_GROUP_INTR, 1, 0, "ldc" 1481991Sheppo }; 1491991Sheppo 1502531Snarayan /* 1512531Snarayan * LDC framework supports mapping remote domain's memory 1522531Snarayan * either directly or via shadow memory pages. Default 1532531Snarayan * support is currently implemented via shadow copy. 1542531Snarayan * Direct map can be enabled by setting 'ldc_shmem_enabled' 1552531Snarayan */ 1562531Snarayan int ldc_shmem_enabled = 0; 1572410Slm66018 1582032Slm66018 /* 1592410Slm66018 * The no. of MTU size messages that can be stored in 1602410Slm66018 * the LDC Tx queue. The number of Tx queue entries is 1612410Slm66018 * then computed as (mtu * mtu_msgs)/sizeof(queue_entry) 1622410Slm66018 */ 1632410Slm66018 uint64_t ldc_mtu_msgs = LDC_MTU_MSGS; 1642410Slm66018 1652410Slm66018 /* 1662410Slm66018 * The minimum queue length. This is the size of the smallest 1672410Slm66018 * LDC queue. If the computed value is less than this default, 1682410Slm66018 * the queue length is rounded up to 'ldc_queue_entries'. 1692410Slm66018 */ 1702410Slm66018 uint64_t ldc_queue_entries = LDC_QUEUE_ENTRIES; 1712410Slm66018 1722410Slm66018 /* 1732410Slm66018 * Pages exported for remote access over each channel is 1742410Slm66018 * maintained in a table registered with the Hypervisor. 1752410Slm66018 * The default number of entries in the table is set to 1762410Slm66018 * 'ldc_mtbl_entries'. 1772410Slm66018 */ 1782410Slm66018 uint64_t ldc_maptable_entries = LDC_MTBL_ENTRIES; 1792410Slm66018 1802410Slm66018 /* 1812410Slm66018 * LDC retry count and delay - when the HV returns EWOULDBLOCK 1822410Slm66018 * the operation is retried 'ldc_max_retries' times with a 1832410Slm66018 * wait of 'ldc_delay' usecs between each retry. 1842032Slm66018 */ 1852032Slm66018 int ldc_max_retries = LDC_MAX_RETRIES; 1862032Slm66018 clock_t ldc_delay = LDC_DELAY; 1872032Slm66018 188*3151Ssg70180 /* 189*3151Ssg70180 * delay between each retry of channel unregistration in 190*3151Ssg70180 * ldc_close(), to wait for pending interrupts to complete. 191*3151Ssg70180 */ 192*3151Ssg70180 clock_t ldc_close_delay = LDC_CLOSE_DELAY; 193*3151Ssg70180 1941991Sheppo #ifdef DEBUG 1951991Sheppo 1961991Sheppo /* 1971991Sheppo * Print debug messages 1981991Sheppo * 1991991Sheppo * set ldcdbg to 0x7 for enabling all msgs 2001991Sheppo * 0x4 - Warnings 2011991Sheppo * 0x2 - All debug messages 2021991Sheppo * 0x1 - Minimal debug messages 2031991Sheppo * 2041991Sheppo * set ldcdbgchan to the channel number you want to debug 2051991Sheppo * setting it to -1 prints debug messages for all channels 2061991Sheppo * NOTE: ldcdbgchan has no effect on error messages 2071991Sheppo */ 2081991Sheppo 2091991Sheppo #define DBG_ALL_LDCS -1 2101991Sheppo 2111991Sheppo int ldcdbg = 0x0; 2121991Sheppo int64_t ldcdbgchan = DBG_ALL_LDCS; 2132793Slm66018 boolean_t ldc_inject_reset_flag = B_FALSE; 2141991Sheppo 2151991Sheppo static void 2161991Sheppo ldcdebug(int64_t id, const char *fmt, ...) 2171991Sheppo { 2181991Sheppo char buf[512]; 2191991Sheppo va_list ap; 2201991Sheppo 2211991Sheppo /* 2221991Sheppo * Do not return if, 2231991Sheppo * caller wants to print it anyway - (id == DBG_ALL_LDCS) 2241991Sheppo * debug channel is set to all LDCs - (ldcdbgchan == DBG_ALL_LDCS) 2251991Sheppo * debug channel = caller specified channel 2261991Sheppo */ 2271991Sheppo if ((id != DBG_ALL_LDCS) && 2281991Sheppo (ldcdbgchan != DBG_ALL_LDCS) && 2291991Sheppo (ldcdbgchan != id)) { 2301991Sheppo return; 2311991Sheppo } 2321991Sheppo 2331991Sheppo va_start(ap, fmt); 2341991Sheppo (void) vsprintf(buf, fmt, ap); 2351991Sheppo va_end(ap); 2361991Sheppo 2372793Slm66018 cmn_err(CE_CONT, "?%s", buf); 2382793Slm66018 } 2392793Slm66018 2402793Slm66018 static boolean_t 2412793Slm66018 ldc_inject_reset(ldc_chan_t *ldcp) 2422793Slm66018 { 2432793Slm66018 if ((ldcdbgchan != DBG_ALL_LDCS) && (ldcdbgchan != ldcp->id)) 2442793Slm66018 return (B_FALSE); 2452793Slm66018 2462793Slm66018 if (!ldc_inject_reset_flag) 2472793Slm66018 return (B_FALSE); 2482793Slm66018 2492793Slm66018 /* clear the injection state */ 2502793Slm66018 ldc_inject_reset_flag = 0; 2512793Slm66018 2522793Slm66018 return (B_TRUE); 2531991Sheppo } 2541991Sheppo 2551991Sheppo #define D1 \ 2561991Sheppo if (ldcdbg & 0x01) \ 2571991Sheppo ldcdebug 2581991Sheppo 2591991Sheppo #define D2 \ 2601991Sheppo if (ldcdbg & 0x02) \ 2611991Sheppo ldcdebug 2621991Sheppo 2631991Sheppo #define DWARN \ 2641991Sheppo if (ldcdbg & 0x04) \ 2651991Sheppo ldcdebug 2661991Sheppo 2671991Sheppo #define DUMP_PAYLOAD(id, addr) \ 2681991Sheppo { \ 2691991Sheppo char buf[65*3]; \ 2701991Sheppo int i; \ 2711991Sheppo uint8_t *src = (uint8_t *)addr; \ 2721991Sheppo for (i = 0; i < 64; i++, src++) \ 2731991Sheppo (void) sprintf(&buf[i * 3], "|%02x", *src); \ 2741991Sheppo (void) sprintf(&buf[i * 3], "|\n"); \ 2751991Sheppo D2((id), "payload: %s", buf); \ 2761991Sheppo } 2771991Sheppo 2781991Sheppo #define DUMP_LDC_PKT(c, s, addr) \ 2791991Sheppo { \ 2801991Sheppo ldc_msg_t *msg = (ldc_msg_t *)(addr); \ 2811991Sheppo uint32_t mid = ((c)->mode != LDC_MODE_RAW) ? msg->seqid : 0; \ 2821991Sheppo if (msg->type == LDC_DATA) { \ 2831991Sheppo D2((c)->id, "%s: msg%d (/%x/%x/%x/,env[%c%c,sz=%d])", \ 2841991Sheppo (s), mid, msg->type, msg->stype, msg->ctrl, \ 2851991Sheppo (msg->env & LDC_FRAG_START) ? 'B' : ' ', \ 2861991Sheppo (msg->env & LDC_FRAG_STOP) ? 'E' : ' ', \ 2871991Sheppo (msg->env & LDC_LEN_MASK)); \ 2881991Sheppo } else { \ 2891991Sheppo D2((c)->id, "%s: msg%d (/%x/%x/%x/,env=%x)", (s), \ 2901991Sheppo mid, msg->type, msg->stype, msg->ctrl, msg->env); \ 2911991Sheppo } \ 2921991Sheppo } 2931991Sheppo 2942793Slm66018 #define LDC_INJECT_RESET(_ldcp) ldc_inject_reset(_ldcp) 2952793Slm66018 2961991Sheppo #else 2971991Sheppo 2981991Sheppo #define DBG_ALL_LDCS -1 2991991Sheppo 3001991Sheppo #define D1 3011991Sheppo #define D2 3021991Sheppo #define DWARN 3031991Sheppo 3041991Sheppo #define DUMP_PAYLOAD(id, addr) 3051991Sheppo #define DUMP_LDC_PKT(c, s, addr) 3061991Sheppo 3072793Slm66018 #define LDC_INJECT_RESET(_ldcp) (B_FALSE) 3082793Slm66018 3091991Sheppo #endif 3101991Sheppo 3111991Sheppo #define ZERO_PKT(p) \ 3121991Sheppo bzero((p), sizeof (ldc_msg_t)); 3131991Sheppo 3141991Sheppo #define IDX2COOKIE(idx, pg_szc, pg_shift) \ 3151991Sheppo (((pg_szc) << LDC_COOKIE_PGSZC_SHIFT) | ((idx) << (pg_shift))) 3161991Sheppo 3171991Sheppo 3181991Sheppo int 3191991Sheppo _init(void) 3201991Sheppo { 3211991Sheppo int status; 3221991Sheppo 3231991Sheppo status = hsvc_register(&ldc_hsvc, &ldc_sup_minor); 3241991Sheppo if (status != 0) { 3251991Sheppo cmn_err(CE_WARN, "%s: cannot negotiate hypervisor LDC services" 3261991Sheppo " group: 0x%lx major: %ld minor: %ld errno: %d", 3271991Sheppo ldc_hsvc.hsvc_modname, ldc_hsvc.hsvc_group, 3281991Sheppo ldc_hsvc.hsvc_major, ldc_hsvc.hsvc_minor, status); 3291991Sheppo return (-1); 3301991Sheppo } 3311991Sheppo 3321991Sheppo status = hsvc_register(&intr_hsvc, &intr_sup_minor); 3331991Sheppo if (status != 0) { 3341991Sheppo cmn_err(CE_WARN, "%s: cannot negotiate hypervisor interrupt " 3351991Sheppo "services group: 0x%lx major: %ld minor: %ld errno: %d", 3361991Sheppo intr_hsvc.hsvc_modname, intr_hsvc.hsvc_group, 3371991Sheppo intr_hsvc.hsvc_major, intr_hsvc.hsvc_minor, status); 3381991Sheppo (void) hsvc_unregister(&ldc_hsvc); 3391991Sheppo return (-1); 3401991Sheppo } 3411991Sheppo 3421991Sheppo /* allocate soft state structure */ 3431991Sheppo ldcssp = kmem_zalloc(sizeof (ldc_soft_state_t), KM_SLEEP); 3441991Sheppo 3451991Sheppo /* Link the module into the system */ 3461991Sheppo status = mod_install(&ml); 3471991Sheppo if (status != 0) { 3481991Sheppo kmem_free(ldcssp, sizeof (ldc_soft_state_t)); 3491991Sheppo return (status); 3501991Sheppo } 3511991Sheppo 3521991Sheppo /* Initialize the LDC state structure */ 3531991Sheppo mutex_init(&ldcssp->lock, NULL, MUTEX_DRIVER, NULL); 3541991Sheppo 3551991Sheppo mutex_enter(&ldcssp->lock); 3561991Sheppo 3572531Snarayan /* Create a cache for memory handles */ 3582531Snarayan ldcssp->memhdl_cache = kmem_cache_create("ldc_memhdl_cache", 3592531Snarayan sizeof (ldc_mhdl_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 3602531Snarayan if (ldcssp->memhdl_cache == NULL) { 3612531Snarayan DWARN(DBG_ALL_LDCS, "_init: ldc_memhdl cache create failed\n"); 3622531Snarayan mutex_exit(&ldcssp->lock); 3632531Snarayan return (-1); 3642531Snarayan } 3652531Snarayan 3662531Snarayan /* Create cache for memory segment structures */ 3672531Snarayan ldcssp->memseg_cache = kmem_cache_create("ldc_memseg_cache", 3682531Snarayan sizeof (ldc_memseg_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 3692531Snarayan if (ldcssp->memseg_cache == NULL) { 3702531Snarayan DWARN(DBG_ALL_LDCS, "_init: ldc_memseg cache create failed\n"); 3712531Snarayan mutex_exit(&ldcssp->lock); 3722531Snarayan return (-1); 3732531Snarayan } 3742531Snarayan 3752531Snarayan 3761991Sheppo ldcssp->channel_count = 0; 3771991Sheppo ldcssp->channels_open = 0; 3781991Sheppo ldcssp->chan_list = NULL; 3791991Sheppo ldcssp->dring_list = NULL; 3801991Sheppo 3811991Sheppo mutex_exit(&ldcssp->lock); 3821991Sheppo 3831991Sheppo return (0); 3841991Sheppo } 3851991Sheppo 3861991Sheppo int 3871991Sheppo _info(struct modinfo *modinfop) 3881991Sheppo { 3891991Sheppo /* Report status of the dynamically loadable driver module */ 3901991Sheppo return (mod_info(&ml, modinfop)); 3911991Sheppo } 3921991Sheppo 3931991Sheppo int 3941991Sheppo _fini(void) 3951991Sheppo { 3961991Sheppo int rv, status; 3971991Sheppo ldc_chan_t *ldcp; 3981991Sheppo ldc_dring_t *dringp; 3991991Sheppo ldc_mem_info_t minfo; 4001991Sheppo 4011991Sheppo /* Unlink the driver module from the system */ 4021991Sheppo status = mod_remove(&ml); 4031991Sheppo if (status) { 4041991Sheppo DWARN(DBG_ALL_LDCS, "_fini: mod_remove failed\n"); 4051991Sheppo return (EIO); 4061991Sheppo } 4071991Sheppo 4081991Sheppo /* close and finalize channels */ 4091991Sheppo ldcp = ldcssp->chan_list; 4101991Sheppo while (ldcp != NULL) { 4111991Sheppo (void) ldc_close((ldc_handle_t)ldcp); 4121991Sheppo (void) ldc_fini((ldc_handle_t)ldcp); 4131991Sheppo 4141991Sheppo ldcp = ldcp->next; 4151991Sheppo } 4161991Sheppo 4171991Sheppo /* Free descriptor rings */ 4181991Sheppo dringp = ldcssp->dring_list; 4191991Sheppo while (dringp != NULL) { 4201991Sheppo dringp = dringp->next; 4211991Sheppo 4221991Sheppo rv = ldc_mem_dring_info((ldc_dring_handle_t)dringp, &minfo); 4231991Sheppo if (rv == 0 && minfo.status != LDC_UNBOUND) { 4241991Sheppo if (minfo.status == LDC_BOUND) { 4251991Sheppo (void) ldc_mem_dring_unbind( 4261991Sheppo (ldc_dring_handle_t)dringp); 4271991Sheppo } 4281991Sheppo if (minfo.status == LDC_MAPPED) { 4291991Sheppo (void) ldc_mem_dring_unmap( 4301991Sheppo (ldc_dring_handle_t)dringp); 4311991Sheppo } 4321991Sheppo } 4331991Sheppo 4341991Sheppo (void) ldc_mem_dring_destroy((ldc_dring_handle_t)dringp); 4351991Sheppo } 4361991Sheppo ldcssp->dring_list = NULL; 4371991Sheppo 4382531Snarayan /* Destroy kmem caches */ 4392531Snarayan kmem_cache_destroy(ldcssp->memhdl_cache); 4402531Snarayan kmem_cache_destroy(ldcssp->memseg_cache); 4412531Snarayan 4421991Sheppo /* 4431991Sheppo * We have successfully "removed" the driver. 4441991Sheppo * Destroying soft states 4451991Sheppo */ 4461991Sheppo mutex_destroy(&ldcssp->lock); 4471991Sheppo kmem_free(ldcssp, sizeof (ldc_soft_state_t)); 4481991Sheppo 4491991Sheppo (void) hsvc_unregister(&ldc_hsvc); 4501991Sheppo (void) hsvc_unregister(&intr_hsvc); 4511991Sheppo 4521991Sheppo return (status); 4531991Sheppo } 4541991Sheppo 4551991Sheppo /* -------------------------------------------------------------------------- */ 4561991Sheppo 4571991Sheppo /* 4582410Slm66018 * LDC Link Layer Internal Functions 4591991Sheppo */ 4601991Sheppo 4611991Sheppo /* 4621991Sheppo * Translate HV Errors to sun4v error codes 4631991Sheppo */ 4641991Sheppo static int 4651991Sheppo i_ldc_h2v_error(int h_error) 4661991Sheppo { 4671991Sheppo switch (h_error) { 4681991Sheppo 4691991Sheppo case H_EOK: 4701991Sheppo return (0); 4711991Sheppo 4721991Sheppo case H_ENORADDR: 4731991Sheppo return (EFAULT); 4741991Sheppo 4751991Sheppo case H_EBADPGSZ: 4761991Sheppo case H_EINVAL: 4771991Sheppo return (EINVAL); 4781991Sheppo 4791991Sheppo case H_EWOULDBLOCK: 4801991Sheppo return (EWOULDBLOCK); 4811991Sheppo 4821991Sheppo case H_ENOACCESS: 4831991Sheppo case H_ENOMAP: 4841991Sheppo return (EACCES); 4851991Sheppo 4861991Sheppo case H_EIO: 4871991Sheppo case H_ECPUERROR: 4881991Sheppo return (EIO); 4891991Sheppo 4901991Sheppo case H_ENOTSUPPORTED: 4911991Sheppo return (ENOTSUP); 4921991Sheppo 4931991Sheppo case H_ETOOMANY: 4941991Sheppo return (ENOSPC); 4951991Sheppo 4961991Sheppo case H_ECHANNEL: 4971991Sheppo return (ECHRNG); 4981991Sheppo default: 4991991Sheppo break; 5001991Sheppo } 5011991Sheppo 5021991Sheppo return (EIO); 5031991Sheppo } 5041991Sheppo 5051991Sheppo /* 5061991Sheppo * Reconfigure the transmit queue 5071991Sheppo */ 5081991Sheppo static int 5091991Sheppo i_ldc_txq_reconf(ldc_chan_t *ldcp) 5101991Sheppo { 5111991Sheppo int rv; 5121991Sheppo 5131991Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 5142336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 5152336Snarayan 5161991Sheppo rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries); 5171991Sheppo if (rv) { 5181991Sheppo cmn_err(CE_WARN, 5192793Slm66018 "i_ldc_txq_reconf: (0x%lx) cannot set qconf", ldcp->id); 5201991Sheppo return (EIO); 5211991Sheppo } 5221991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, &(ldcp->tx_head), 5231991Sheppo &(ldcp->tx_tail), &(ldcp->link_state)); 5241991Sheppo if (rv) { 5251991Sheppo cmn_err(CE_WARN, 5262793Slm66018 "i_ldc_txq_reconf: (0x%lx) cannot get qptrs", ldcp->id); 5271991Sheppo return (EIO); 5281991Sheppo } 5292793Slm66018 D1(ldcp->id, "i_ldc_txq_reconf: (0x%llx) h=0x%llx,t=0x%llx," 5301991Sheppo "s=0x%llx\n", ldcp->id, ldcp->tx_head, ldcp->tx_tail, 5311991Sheppo ldcp->link_state); 5321991Sheppo 5331991Sheppo return (0); 5341991Sheppo } 5351991Sheppo 5361991Sheppo /* 5371991Sheppo * Reconfigure the receive queue 5381991Sheppo */ 5391991Sheppo static int 5402793Slm66018 i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset) 5411991Sheppo { 5421991Sheppo int rv; 5431991Sheppo uint64_t rx_head, rx_tail; 5441991Sheppo 5451991Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 5461991Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 5471991Sheppo &(ldcp->link_state)); 5481991Sheppo if (rv) { 5491991Sheppo cmn_err(CE_WARN, 5502793Slm66018 "i_ldc_rxq_reconf: (0x%lx) cannot get state", 5511991Sheppo ldcp->id); 5521991Sheppo return (EIO); 5531991Sheppo } 5541991Sheppo 5552793Slm66018 if (force_reset || (ldcp->tstate & ~TS_IN_RESET) == TS_UP) { 5561991Sheppo rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra, 5571991Sheppo ldcp->rx_q_entries); 5581991Sheppo if (rv) { 5591991Sheppo cmn_err(CE_WARN, 5602793Slm66018 "i_ldc_rxq_reconf: (0x%lx) cannot set qconf", 5611991Sheppo ldcp->id); 5621991Sheppo return (EIO); 5631991Sheppo } 5642793Slm66018 D1(ldcp->id, "i_ldc_rxq_reconf: (0x%llx) completed q reconf", 5651991Sheppo ldcp->id); 5661991Sheppo } 5671991Sheppo 5681991Sheppo return (0); 5691991Sheppo } 5701991Sheppo 5712841Snarayan 5722841Snarayan /* 5732841Snarayan * Drain the contents of the receive queue 5742841Snarayan */ 5752841Snarayan static int 5762841Snarayan i_ldc_rxq_drain(ldc_chan_t *ldcp) 5772841Snarayan { 5782841Snarayan int rv; 5792841Snarayan uint64_t rx_head, rx_tail; 5802841Snarayan 5812841Snarayan ASSERT(MUTEX_HELD(&ldcp->lock)); 5822841Snarayan rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 5832841Snarayan &(ldcp->link_state)); 5842841Snarayan if (rv) { 5852841Snarayan cmn_err(CE_WARN, "i_ldc_rxq_drain: (0x%lx) cannot get state", 5862841Snarayan ldcp->id); 5872841Snarayan return (EIO); 5882841Snarayan } 5892841Snarayan 5902841Snarayan /* flush contents by setting the head = tail */ 5912841Snarayan return (i_ldc_set_rx_head(ldcp, rx_tail)); 5922841Snarayan } 5932841Snarayan 5942841Snarayan 5951991Sheppo /* 5961991Sheppo * Reset LDC state structure and its contents 5971991Sheppo */ 5981991Sheppo static void 5991991Sheppo i_ldc_reset_state(ldc_chan_t *ldcp) 6001991Sheppo { 6011991Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 6021991Sheppo ldcp->last_msg_snt = LDC_INIT_SEQID; 6031991Sheppo ldcp->last_ack_rcd = 0; 6041991Sheppo ldcp->last_msg_rcd = 0; 6051991Sheppo ldcp->tx_ackd_head = ldcp->tx_head; 6061991Sheppo ldcp->next_vidx = 0; 6071991Sheppo ldcp->hstate = 0; 6081991Sheppo ldcp->tstate = TS_OPEN; 6091991Sheppo ldcp->status = LDC_OPEN; 6101991Sheppo 6111991Sheppo if (ldcp->link_state == LDC_CHANNEL_UP || 6121991Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 6131991Sheppo 6141991Sheppo if (ldcp->mode == LDC_MODE_RAW) { 6151991Sheppo ldcp->status = LDC_UP; 6161991Sheppo ldcp->tstate = TS_UP; 6171991Sheppo } else { 6181991Sheppo ldcp->status = LDC_READY; 6191991Sheppo ldcp->tstate |= TS_LINK_READY; 6201991Sheppo } 6211991Sheppo } 6221991Sheppo } 6231991Sheppo 6241991Sheppo /* 6251991Sheppo * Reset a LDC channel 6261991Sheppo */ 6271991Sheppo static void 6282793Slm66018 i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset) 6291991Sheppo { 6303010Slm66018 D1(ldcp->id, "i_ldc_reset: (0x%llx) channel reset\n", ldcp->id); 6311991Sheppo 6322336Snarayan ASSERT(MUTEX_HELD(&ldcp->lock)); 6332336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 6342336Snarayan 6352793Slm66018 /* reconfig Tx and Rx queues */ 6361991Sheppo (void) i_ldc_txq_reconf(ldcp); 6372793Slm66018 (void) i_ldc_rxq_reconf(ldcp, force_reset); 6382793Slm66018 6392793Slm66018 /* Clear Tx and Rx interrupts */ 6402793Slm66018 (void) i_ldc_clear_intr(ldcp, CNEX_TX_INTR); 6412793Slm66018 (void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 6422793Slm66018 6432793Slm66018 /* Reset channel state */ 6441991Sheppo i_ldc_reset_state(ldcp); 6452793Slm66018 6462793Slm66018 /* Mark channel in reset */ 6472793Slm66018 ldcp->tstate |= TS_IN_RESET; 6481991Sheppo } 6491991Sheppo 6502531Snarayan 6511991Sheppo /* 6521991Sheppo * Clear pending interrupts 6531991Sheppo */ 6541991Sheppo static void 6551991Sheppo i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype) 6561991Sheppo { 6571991Sheppo ldc_cnex_t *cinfo = &ldcssp->cinfo; 6581991Sheppo 6591991Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 6602793Slm66018 ASSERT(cinfo->dip != NULL); 6612793Slm66018 6622793Slm66018 switch (itype) { 6632793Slm66018 case CNEX_TX_INTR: 6642531Snarayan /* check Tx interrupt */ 6652793Slm66018 if (ldcp->tx_intr_state) 6662793Slm66018 ldcp->tx_intr_state = LDC_INTR_NONE; 6672793Slm66018 else 6682793Slm66018 return; 6692793Slm66018 break; 6702793Slm66018 6712793Slm66018 case CNEX_RX_INTR: 6722531Snarayan /* check Rx interrupt */ 6732793Slm66018 if (ldcp->rx_intr_state) 6742793Slm66018 ldcp->rx_intr_state = LDC_INTR_NONE; 6752793Slm66018 else 6762793Slm66018 return; 6772793Slm66018 break; 6782793Slm66018 } 6792793Slm66018 6802793Slm66018 (void) cinfo->clr_intr(cinfo->dip, ldcp->id, itype); 6812793Slm66018 D2(ldcp->id, 6822793Slm66018 "i_ldc_clear_intr: (0x%llx) cleared 0x%x intr\n", 6832793Slm66018 ldcp->id, itype); 6841991Sheppo } 6851991Sheppo 6861991Sheppo /* 6871991Sheppo * Set the receive queue head 6882032Slm66018 * Resets connection and returns an error if it fails. 6891991Sheppo */ 6901991Sheppo static int 6911991Sheppo i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head) 6921991Sheppo { 6932032Slm66018 int rv; 6942032Slm66018 int retries; 6951991Sheppo 6961991Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 6972032Slm66018 for (retries = 0; retries < ldc_max_retries; retries++) { 6982032Slm66018 6992032Slm66018 if ((rv = hv_ldc_rx_set_qhead(ldcp->id, head)) == 0) 7002032Slm66018 return (0); 7012032Slm66018 7022032Slm66018 if (rv != H_EWOULDBLOCK) 7032032Slm66018 break; 7042032Slm66018 7052032Slm66018 /* wait for ldc_delay usecs */ 7062032Slm66018 drv_usecwait(ldc_delay); 7072032Slm66018 } 7082032Slm66018 7092032Slm66018 cmn_err(CE_WARN, "ldc_rx_set_qhead: (0x%lx) cannot set qhead 0x%lx", 7102032Slm66018 ldcp->id, head); 7112336Snarayan mutex_enter(&ldcp->tx_lock); 7122793Slm66018 i_ldc_reset(ldcp, B_TRUE); 7132336Snarayan mutex_exit(&ldcp->tx_lock); 7142032Slm66018 7152032Slm66018 return (ECONNRESET); 7161991Sheppo } 7171991Sheppo 7181991Sheppo 7191991Sheppo /* 7201991Sheppo * Returns the tx_tail to be used for transfer 7211991Sheppo * Re-reads the TX queue ptrs if and only if the 7221991Sheppo * the cached head and tail are equal (queue is full) 7231991Sheppo */ 7241991Sheppo static int 7251991Sheppo i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail) 7261991Sheppo { 7271991Sheppo int rv; 7281991Sheppo uint64_t current_head, new_tail; 7291991Sheppo 7302336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 7311991Sheppo /* Read the head and tail ptrs from HV */ 7321991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 7331991Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 7341991Sheppo if (rv) { 7351991Sheppo cmn_err(CE_WARN, 7361991Sheppo "i_ldc_get_tx_tail: (0x%lx) cannot read qptrs\n", 7371991Sheppo ldcp->id); 7381991Sheppo return (EIO); 7391991Sheppo } 7401991Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN) { 7413010Slm66018 D1(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) channel not ready\n", 7421991Sheppo ldcp->id); 7431991Sheppo return (ECONNRESET); 7441991Sheppo } 7451991Sheppo 7461991Sheppo /* In reliable mode, check against last ACKd msg */ 7471991Sheppo current_head = (ldcp->mode == LDC_MODE_RELIABLE || 7481991Sheppo ldcp->mode == LDC_MODE_STREAM) 7491991Sheppo ? ldcp->tx_ackd_head : ldcp->tx_head; 7501991Sheppo 7511991Sheppo /* increment the tail */ 7521991Sheppo new_tail = (ldcp->tx_tail + LDC_PACKET_SIZE) % 7531991Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 7541991Sheppo 7551991Sheppo if (new_tail == current_head) { 7561991Sheppo DWARN(ldcp->id, 7571991Sheppo "i_ldc_get_tx_tail: (0x%llx) TX queue is full\n", 7581991Sheppo ldcp->id); 7591991Sheppo return (EWOULDBLOCK); 7601991Sheppo } 7611991Sheppo 7621991Sheppo D2(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) head=0x%llx, tail=0x%llx\n", 7631991Sheppo ldcp->id, ldcp->tx_head, ldcp->tx_tail); 7641991Sheppo 7651991Sheppo *tail = ldcp->tx_tail; 7661991Sheppo return (0); 7671991Sheppo } 7681991Sheppo 7691991Sheppo /* 7701991Sheppo * Set the tail pointer. If HV returns EWOULDBLOCK, it will back off 7712032Slm66018 * and retry ldc_max_retries times before returning an error. 7721991Sheppo * Returns 0, EWOULDBLOCK or EIO 7731991Sheppo */ 7741991Sheppo static int 7751991Sheppo i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail) 7761991Sheppo { 7771991Sheppo int rv, retval = EWOULDBLOCK; 7782032Slm66018 int retries; 7791991Sheppo 7802336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 7812032Slm66018 for (retries = 0; retries < ldc_max_retries; retries++) { 7821991Sheppo 7831991Sheppo if ((rv = hv_ldc_tx_set_qtail(ldcp->id, tail)) == 0) { 7841991Sheppo retval = 0; 7851991Sheppo break; 7861991Sheppo } 7871991Sheppo if (rv != H_EWOULDBLOCK) { 7881991Sheppo DWARN(ldcp->id, "i_ldc_set_tx_tail: (0x%llx) set " 7891991Sheppo "qtail=0x%llx failed, rv=%d\n", ldcp->id, tail, rv); 7901991Sheppo retval = EIO; 7911991Sheppo break; 7921991Sheppo } 7931991Sheppo 7942032Slm66018 /* wait for ldc_delay usecs */ 7952032Slm66018 drv_usecwait(ldc_delay); 7961991Sheppo } 7971991Sheppo return (retval); 7981991Sheppo } 7991991Sheppo 8001991Sheppo /* 8011991Sheppo * Send a LDC message 8021991Sheppo */ 8031991Sheppo static int 8041991Sheppo i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype, 8051991Sheppo uint8_t ctrlmsg) 8061991Sheppo { 8071991Sheppo int rv; 8081991Sheppo ldc_msg_t *pkt; 8091991Sheppo uint64_t tx_tail; 8101991Sheppo uint32_t curr_seqid = ldcp->last_msg_snt; 8111991Sheppo 8122336Snarayan /* Obtain Tx lock */ 8132336Snarayan mutex_enter(&ldcp->tx_lock); 8142336Snarayan 8151991Sheppo /* get the current tail for the message */ 8161991Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 8171991Sheppo if (rv) { 8181991Sheppo DWARN(ldcp->id, 8191991Sheppo "i_ldc_send_pkt: (0x%llx) error sending pkt, " 8201991Sheppo "type=0x%x,subtype=0x%x,ctrl=0x%x\n", 8211991Sheppo ldcp->id, pkttype, subtype, ctrlmsg); 8222336Snarayan mutex_exit(&ldcp->tx_lock); 8231991Sheppo return (rv); 8241991Sheppo } 8251991Sheppo 8261991Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 8271991Sheppo ZERO_PKT(pkt); 8281991Sheppo 8291991Sheppo /* Initialize the packet */ 8301991Sheppo pkt->type = pkttype; 8311991Sheppo pkt->stype = subtype; 8321991Sheppo pkt->ctrl = ctrlmsg; 8331991Sheppo 8341991Sheppo /* Store ackid/seqid iff it is RELIABLE mode & not a RTS/RTR message */ 8351991Sheppo if (((ctrlmsg & LDC_CTRL_MASK) != LDC_RTS) && 8361991Sheppo ((ctrlmsg & LDC_CTRL_MASK) != LDC_RTR)) { 8371991Sheppo curr_seqid++; 8381991Sheppo if (ldcp->mode != LDC_MODE_RAW) { 8391991Sheppo pkt->seqid = curr_seqid; 8401991Sheppo pkt->ackid = ldcp->last_msg_rcd; 8411991Sheppo } 8421991Sheppo } 8431991Sheppo DUMP_LDC_PKT(ldcp, "i_ldc_send_pkt", (uint64_t)pkt); 8441991Sheppo 8451991Sheppo /* initiate the send by calling into HV and set the new tail */ 8461991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 8471991Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 8481991Sheppo 8491991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 8501991Sheppo if (rv) { 8511991Sheppo DWARN(ldcp->id, 8521991Sheppo "i_ldc_send_pkt:(0x%llx) error sending pkt, " 8531991Sheppo "type=0x%x,stype=0x%x,ctrl=0x%x\n", 8541991Sheppo ldcp->id, pkttype, subtype, ctrlmsg); 8552336Snarayan mutex_exit(&ldcp->tx_lock); 8561991Sheppo return (EIO); 8571991Sheppo } 8581991Sheppo 8591991Sheppo ldcp->last_msg_snt = curr_seqid; 8601991Sheppo ldcp->tx_tail = tx_tail; 8611991Sheppo 8622336Snarayan mutex_exit(&ldcp->tx_lock); 8631991Sheppo return (0); 8641991Sheppo } 8651991Sheppo 8661991Sheppo /* 8671991Sheppo * Checks if packet was received in right order 8682410Slm66018 * in the case of a reliable link. 8691991Sheppo * Returns 0 if in order, else EIO 8701991Sheppo */ 8711991Sheppo static int 8721991Sheppo i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *msg) 8731991Sheppo { 8741991Sheppo /* No seqid checking for RAW mode */ 8751991Sheppo if (ldcp->mode == LDC_MODE_RAW) 8761991Sheppo return (0); 8771991Sheppo 8781991Sheppo /* No seqid checking for version, RTS, RTR message */ 8791991Sheppo if (msg->ctrl == LDC_VER || 8801991Sheppo msg->ctrl == LDC_RTS || 8811991Sheppo msg->ctrl == LDC_RTR) 8821991Sheppo return (0); 8831991Sheppo 8841991Sheppo /* Initial seqid to use is sent in RTS/RTR and saved in last_msg_rcd */ 8851991Sheppo if (msg->seqid != (ldcp->last_msg_rcd + 1)) { 8861991Sheppo DWARN(ldcp->id, 8871991Sheppo "i_ldc_check_seqid: (0x%llx) out-of-order pkt, got 0x%x, " 8881991Sheppo "expecting 0x%x\n", ldcp->id, msg->seqid, 8891991Sheppo (ldcp->last_msg_rcd + 1)); 8901991Sheppo return (EIO); 8911991Sheppo } 8921991Sheppo 8931991Sheppo return (0); 8941991Sheppo } 8951991Sheppo 8961991Sheppo 8971991Sheppo /* 8981991Sheppo * Process an incoming version ctrl message 8991991Sheppo */ 9001991Sheppo static int 9011991Sheppo i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg) 9021991Sheppo { 9031991Sheppo int rv = 0, idx = ldcp->next_vidx; 9041991Sheppo ldc_msg_t *pkt; 9051991Sheppo uint64_t tx_tail; 9061991Sheppo ldc_ver_t *rcvd_ver; 9071991Sheppo 9081991Sheppo /* get the received version */ 9091991Sheppo rcvd_ver = (ldc_ver_t *)((uint64_t)msg + LDC_PAYLOAD_VER_OFF); 9101991Sheppo 9111991Sheppo D2(ldcp->id, "i_ldc_process_VER: (0x%llx) received VER v%u.%u\n", 9121991Sheppo ldcp->id, rcvd_ver->major, rcvd_ver->minor); 9131991Sheppo 9142336Snarayan /* Obtain Tx lock */ 9152336Snarayan mutex_enter(&ldcp->tx_lock); 9162336Snarayan 9171991Sheppo switch (msg->stype) { 9181991Sheppo case LDC_INFO: 9191991Sheppo 9202793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) { 9212793Slm66018 (void) i_ldc_txq_reconf(ldcp); 9222793Slm66018 i_ldc_reset_state(ldcp); 9232793Slm66018 mutex_exit(&ldcp->tx_lock); 9242793Slm66018 return (EAGAIN); 9252793Slm66018 } 9262793Slm66018 9271991Sheppo /* get the current tail and pkt for the response */ 9281991Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 9291991Sheppo if (rv != 0) { 9301991Sheppo DWARN(ldcp->id, 9311991Sheppo "i_ldc_process_VER: (0x%llx) err sending " 9321991Sheppo "version ACK/NACK\n", ldcp->id); 9332793Slm66018 i_ldc_reset(ldcp, B_TRUE); 9342336Snarayan mutex_exit(&ldcp->tx_lock); 9351991Sheppo return (ECONNRESET); 9361991Sheppo } 9371991Sheppo 9381991Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 9391991Sheppo ZERO_PKT(pkt); 9401991Sheppo 9411991Sheppo /* initialize the packet */ 9421991Sheppo pkt->type = LDC_CTRL; 9431991Sheppo pkt->ctrl = LDC_VER; 9441991Sheppo 9451991Sheppo for (;;) { 9461991Sheppo 9471991Sheppo D1(ldcp->id, "i_ldc_process_VER: got %u.%u chk %u.%u\n", 9481991Sheppo rcvd_ver->major, rcvd_ver->minor, 9491991Sheppo ldc_versions[idx].major, ldc_versions[idx].minor); 9501991Sheppo 9511991Sheppo if (rcvd_ver->major == ldc_versions[idx].major) { 9521991Sheppo /* major version match - ACK version */ 9531991Sheppo pkt->stype = LDC_ACK; 9541991Sheppo 9551991Sheppo /* 9561991Sheppo * lower minor version to the one this endpt 9571991Sheppo * supports, if necessary 9581991Sheppo */ 9591991Sheppo if (rcvd_ver->minor > ldc_versions[idx].minor) 9601991Sheppo rcvd_ver->minor = 9611991Sheppo ldc_versions[idx].minor; 9621991Sheppo bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver)); 9631991Sheppo 9641991Sheppo break; 9651991Sheppo } 9661991Sheppo 9671991Sheppo if (rcvd_ver->major > ldc_versions[idx].major) { 9681991Sheppo 9691991Sheppo D1(ldcp->id, "i_ldc_process_VER: using next" 9701991Sheppo " lower idx=%d, v%u.%u\n", idx, 9711991Sheppo ldc_versions[idx].major, 9721991Sheppo ldc_versions[idx].minor); 9731991Sheppo 9741991Sheppo /* nack with next lower version */ 9751991Sheppo pkt->stype = LDC_NACK; 9761991Sheppo bcopy(&ldc_versions[idx], pkt->udata, 9771991Sheppo sizeof (ldc_versions[idx])); 9781991Sheppo ldcp->next_vidx = idx; 9791991Sheppo break; 9801991Sheppo } 9811991Sheppo 9821991Sheppo /* next major version */ 9831991Sheppo idx++; 9841991Sheppo 9851991Sheppo D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx); 9861991Sheppo 9871991Sheppo if (idx == LDC_NUM_VERS) { 9881991Sheppo /* no version match - send NACK */ 9891991Sheppo pkt->stype = LDC_NACK; 9901991Sheppo bzero(pkt->udata, sizeof (ldc_ver_t)); 9911991Sheppo ldcp->next_vidx = 0; 9921991Sheppo break; 9931991Sheppo } 9941991Sheppo } 9951991Sheppo 9961991Sheppo /* initiate the send by calling into HV and set the new tail */ 9971991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 9981991Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 9991991Sheppo 10001991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 10011991Sheppo if (rv == 0) { 10021991Sheppo ldcp->tx_tail = tx_tail; 10031991Sheppo if (pkt->stype == LDC_ACK) { 10041991Sheppo D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent" 10051991Sheppo " version ACK\n", ldcp->id); 10061991Sheppo /* Save the ACK'd version */ 10071991Sheppo ldcp->version.major = rcvd_ver->major; 10081991Sheppo ldcp->version.minor = rcvd_ver->minor; 10092032Slm66018 ldcp->hstate |= TS_RCVD_VER; 10101991Sheppo ldcp->tstate |= TS_VER_DONE; 10111991Sheppo DWARN(DBG_ALL_LDCS, 10122793Slm66018 "(0x%llx) Sent ACK, " 10132793Slm66018 "Agreed on version v%u.%u\n", 10141991Sheppo ldcp->id, rcvd_ver->major, rcvd_ver->minor); 10151991Sheppo } 10161991Sheppo } else { 10171991Sheppo DWARN(ldcp->id, 10181991Sheppo "i_ldc_process_VER: (0x%llx) error sending " 10191991Sheppo "ACK/NACK\n", ldcp->id); 10202793Slm66018 i_ldc_reset(ldcp, B_TRUE); 10212336Snarayan mutex_exit(&ldcp->tx_lock); 10221991Sheppo return (ECONNRESET); 10231991Sheppo } 10241991Sheppo 10251991Sheppo break; 10261991Sheppo 10271991Sheppo case LDC_ACK: 10282793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) { 10292793Slm66018 if (ldcp->version.major != rcvd_ver->major || 10302793Slm66018 ldcp->version.minor != rcvd_ver->minor) { 10312793Slm66018 10322793Slm66018 /* mismatched version - reset connection */ 10332793Slm66018 DWARN(ldcp->id, 10342793Slm66018 "i_ldc_process_VER: (0x%llx) recvd" 10352793Slm66018 " ACK ver != sent ACK ver\n", ldcp->id); 10362793Slm66018 i_ldc_reset(ldcp, B_TRUE); 10372793Slm66018 mutex_exit(&ldcp->tx_lock); 10382793Slm66018 return (ECONNRESET); 10392793Slm66018 } 10402793Slm66018 } else { 10412793Slm66018 /* SUCCESS - we have agreed on a version */ 10422793Slm66018 ldcp->version.major = rcvd_ver->major; 10432793Slm66018 ldcp->version.minor = rcvd_ver->minor; 10442793Slm66018 ldcp->tstate |= TS_VER_DONE; 10452793Slm66018 } 10462793Slm66018 10473010Slm66018 D1(ldcp->id, "(0x%llx) Got ACK, Agreed on version v%u.%u\n", 10481991Sheppo ldcp->id, rcvd_ver->major, rcvd_ver->minor); 10491991Sheppo 10501991Sheppo /* initiate RTS-RTR-RDX handshake */ 10511991Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 10521991Sheppo if (rv) { 10531991Sheppo DWARN(ldcp->id, 10542793Slm66018 "i_ldc_process_VER: (0x%llx) cannot send RTS\n", 10551991Sheppo ldcp->id); 10562793Slm66018 i_ldc_reset(ldcp, B_TRUE); 10572336Snarayan mutex_exit(&ldcp->tx_lock); 10581991Sheppo return (ECONNRESET); 10591991Sheppo } 10601991Sheppo 10611991Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 10621991Sheppo ZERO_PKT(pkt); 10631991Sheppo 10641991Sheppo pkt->type = LDC_CTRL; 10651991Sheppo pkt->stype = LDC_INFO; 10661991Sheppo pkt->ctrl = LDC_RTS; 10671991Sheppo pkt->env = ldcp->mode; 10681991Sheppo if (ldcp->mode != LDC_MODE_RAW) 10691991Sheppo pkt->seqid = LDC_INIT_SEQID; 10701991Sheppo 10711991Sheppo ldcp->last_msg_rcd = LDC_INIT_SEQID; 10721991Sheppo 10731991Sheppo DUMP_LDC_PKT(ldcp, "i_ldc_process_VER snd rts", (uint64_t)pkt); 10741991Sheppo 10751991Sheppo /* initiate the send by calling into HV and set the new tail */ 10761991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 10771991Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 10781991Sheppo 10791991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 10801991Sheppo if (rv) { 10811991Sheppo D2(ldcp->id, 10821991Sheppo "i_ldc_process_VER: (0x%llx) no listener\n", 10831991Sheppo ldcp->id); 10842793Slm66018 i_ldc_reset(ldcp, B_TRUE); 10852336Snarayan mutex_exit(&ldcp->tx_lock); 10861991Sheppo return (ECONNRESET); 10871991Sheppo } 10881991Sheppo 10891991Sheppo ldcp->tx_tail = tx_tail; 10901991Sheppo ldcp->hstate |= TS_SENT_RTS; 10911991Sheppo 10921991Sheppo break; 10931991Sheppo 10941991Sheppo case LDC_NACK: 10951991Sheppo /* check if version in NACK is zero */ 10961991Sheppo if (rcvd_ver->major == 0 && rcvd_ver->minor == 0) { 10971991Sheppo /* version handshake failure */ 10981991Sheppo DWARN(DBG_ALL_LDCS, 10991991Sheppo "i_ldc_process_VER: (0x%llx) no version match\n", 11001991Sheppo ldcp->id); 11012793Slm66018 i_ldc_reset(ldcp, B_TRUE); 11022336Snarayan mutex_exit(&ldcp->tx_lock); 11031991Sheppo return (ECONNRESET); 11041991Sheppo } 11051991Sheppo 11061991Sheppo /* get the current tail and pkt for the response */ 11071991Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 11081991Sheppo if (rv != 0) { 11091991Sheppo cmn_err(CE_NOTE, 11101991Sheppo "i_ldc_process_VER: (0x%lx) err sending " 11111991Sheppo "version ACK/NACK\n", ldcp->id); 11122793Slm66018 i_ldc_reset(ldcp, B_TRUE); 11132336Snarayan mutex_exit(&ldcp->tx_lock); 11141991Sheppo return (ECONNRESET); 11151991Sheppo } 11161991Sheppo 11171991Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 11181991Sheppo ZERO_PKT(pkt); 11191991Sheppo 11201991Sheppo /* initialize the packet */ 11211991Sheppo pkt->type = LDC_CTRL; 11221991Sheppo pkt->ctrl = LDC_VER; 11231991Sheppo pkt->stype = LDC_INFO; 11241991Sheppo 11251991Sheppo /* check ver in NACK msg has a match */ 11261991Sheppo for (;;) { 11271991Sheppo if (rcvd_ver->major == ldc_versions[idx].major) { 11281991Sheppo /* 11291991Sheppo * major version match - resubmit request 11301991Sheppo * if lower minor version to the one this endpt 11311991Sheppo * supports, if necessary 11321991Sheppo */ 11331991Sheppo if (rcvd_ver->minor > ldc_versions[idx].minor) 11341991Sheppo rcvd_ver->minor = 11351991Sheppo ldc_versions[idx].minor; 11361991Sheppo bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver)); 11371991Sheppo break; 11381991Sheppo 11391991Sheppo } 11401991Sheppo 11411991Sheppo if (rcvd_ver->major > ldc_versions[idx].major) { 11421991Sheppo 11431991Sheppo D1(ldcp->id, "i_ldc_process_VER: using next" 11441991Sheppo " lower idx=%d, v%u.%u\n", idx, 11451991Sheppo ldc_versions[idx].major, 11461991Sheppo ldc_versions[idx].minor); 11471991Sheppo 11481991Sheppo /* send next lower version */ 11491991Sheppo bcopy(&ldc_versions[idx], pkt->udata, 11501991Sheppo sizeof (ldc_versions[idx])); 11511991Sheppo ldcp->next_vidx = idx; 11521991Sheppo break; 11531991Sheppo } 11541991Sheppo 11551991Sheppo /* next version */ 11561991Sheppo idx++; 11571991Sheppo 11581991Sheppo D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx); 11591991Sheppo 11601991Sheppo if (idx == LDC_NUM_VERS) { 11611991Sheppo /* no version match - terminate */ 11621991Sheppo ldcp->next_vidx = 0; 11632336Snarayan mutex_exit(&ldcp->tx_lock); 11641991Sheppo return (ECONNRESET); 11651991Sheppo } 11661991Sheppo } 11671991Sheppo 11681991Sheppo /* initiate the send by calling into HV and set the new tail */ 11691991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 11701991Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 11711991Sheppo 11721991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 11731991Sheppo if (rv == 0) { 11741991Sheppo D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent version" 11751991Sheppo "INFO v%u.%u\n", ldcp->id, ldc_versions[idx].major, 11761991Sheppo ldc_versions[idx].minor); 11771991Sheppo ldcp->tx_tail = tx_tail; 11781991Sheppo } else { 11791991Sheppo cmn_err(CE_NOTE, 11801991Sheppo "i_ldc_process_VER: (0x%lx) error sending version" 11811991Sheppo "INFO\n", ldcp->id); 11822793Slm66018 i_ldc_reset(ldcp, B_TRUE); 11832336Snarayan mutex_exit(&ldcp->tx_lock); 11841991Sheppo return (ECONNRESET); 11851991Sheppo } 11861991Sheppo 11871991Sheppo break; 11881991Sheppo } 11891991Sheppo 11902336Snarayan mutex_exit(&ldcp->tx_lock); 11911991Sheppo return (rv); 11921991Sheppo } 11931991Sheppo 11941991Sheppo 11951991Sheppo /* 11961991Sheppo * Process an incoming RTS ctrl message 11971991Sheppo */ 11981991Sheppo static int 11991991Sheppo i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg) 12001991Sheppo { 12011991Sheppo int rv = 0; 12021991Sheppo ldc_msg_t *pkt; 12031991Sheppo uint64_t tx_tail; 12041991Sheppo boolean_t sent_NACK = B_FALSE; 12051991Sheppo 12061991Sheppo D2(ldcp->id, "i_ldc_process_RTS: (0x%llx) received RTS\n", ldcp->id); 12071991Sheppo 12081991Sheppo switch (msg->stype) { 12091991Sheppo case LDC_NACK: 12101991Sheppo DWARN(ldcp->id, 12111991Sheppo "i_ldc_process_RTS: (0x%llx) RTS NACK received\n", 12121991Sheppo ldcp->id); 12131991Sheppo 12141991Sheppo /* Reset the channel -- as we cannot continue */ 12152336Snarayan mutex_enter(&ldcp->tx_lock); 12162793Slm66018 i_ldc_reset(ldcp, B_TRUE); 12172336Snarayan mutex_exit(&ldcp->tx_lock); 12181991Sheppo rv = ECONNRESET; 12191991Sheppo break; 12201991Sheppo 12211991Sheppo case LDC_INFO: 12221991Sheppo 12231991Sheppo /* check mode */ 12241991Sheppo if (ldcp->mode != (ldc_mode_t)msg->env) { 12251991Sheppo cmn_err(CE_NOTE, 12261991Sheppo "i_ldc_process_RTS: (0x%lx) mode mismatch\n", 12271991Sheppo ldcp->id); 12281991Sheppo /* 12291991Sheppo * send NACK in response to MODE message 12301991Sheppo * get the current tail for the response 12311991Sheppo */ 12321991Sheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTS); 12331991Sheppo if (rv) { 12341991Sheppo /* if cannot send NACK - reset channel */ 12352336Snarayan mutex_enter(&ldcp->tx_lock); 12362793Slm66018 i_ldc_reset(ldcp, B_TRUE); 12372336Snarayan mutex_exit(&ldcp->tx_lock); 12381991Sheppo rv = ECONNRESET; 12391991Sheppo break; 12401991Sheppo } 12411991Sheppo sent_NACK = B_TRUE; 12421991Sheppo } 12431991Sheppo break; 12441991Sheppo default: 12451991Sheppo DWARN(ldcp->id, "i_ldc_process_RTS: (0x%llx) unexp ACK\n", 12461991Sheppo ldcp->id); 12472336Snarayan mutex_enter(&ldcp->tx_lock); 12482793Slm66018 i_ldc_reset(ldcp, B_TRUE); 12492336Snarayan mutex_exit(&ldcp->tx_lock); 12501991Sheppo rv = ECONNRESET; 12511991Sheppo break; 12521991Sheppo } 12531991Sheppo 12541991Sheppo /* 12551991Sheppo * If either the connection was reset (when rv != 0) or 12561991Sheppo * a NACK was sent, we return. In the case of a NACK 12571991Sheppo * we dont want to consume the packet that came in but 12581991Sheppo * not record that we received the RTS 12591991Sheppo */ 12601991Sheppo if (rv || sent_NACK) 12611991Sheppo return (rv); 12621991Sheppo 12631991Sheppo /* record RTS received */ 12641991Sheppo ldcp->hstate |= TS_RCVD_RTS; 12651991Sheppo 12661991Sheppo /* store initial SEQID info */ 12671991Sheppo ldcp->last_msg_snt = msg->seqid; 12681991Sheppo 12692336Snarayan /* Obtain Tx lock */ 12702336Snarayan mutex_enter(&ldcp->tx_lock); 12712336Snarayan 12721991Sheppo /* get the current tail for the response */ 12731991Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 12741991Sheppo if (rv != 0) { 12751991Sheppo cmn_err(CE_NOTE, 12761991Sheppo "i_ldc_process_RTS: (0x%lx) err sending RTR\n", 12771991Sheppo ldcp->id); 12782793Slm66018 i_ldc_reset(ldcp, B_TRUE); 12792336Snarayan mutex_exit(&ldcp->tx_lock); 12801991Sheppo return (ECONNRESET); 12811991Sheppo } 12821991Sheppo 12831991Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 12841991Sheppo ZERO_PKT(pkt); 12851991Sheppo 12861991Sheppo /* initialize the packet */ 12871991Sheppo pkt->type = LDC_CTRL; 12881991Sheppo pkt->stype = LDC_INFO; 12891991Sheppo pkt->ctrl = LDC_RTR; 12901991Sheppo pkt->env = ldcp->mode; 12911991Sheppo if (ldcp->mode != LDC_MODE_RAW) 12921991Sheppo pkt->seqid = LDC_INIT_SEQID; 12931991Sheppo 12941991Sheppo ldcp->last_msg_rcd = msg->seqid; 12951991Sheppo 12961991Sheppo /* initiate the send by calling into HV and set the new tail */ 12971991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 12981991Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 12991991Sheppo 13001991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 13011991Sheppo if (rv == 0) { 13021991Sheppo D2(ldcp->id, 13031991Sheppo "i_ldc_process_RTS: (0x%llx) sent RTR\n", ldcp->id); 13041991Sheppo DUMP_LDC_PKT(ldcp, "i_ldc_process_RTS sent rtr", (uint64_t)pkt); 13051991Sheppo 13061991Sheppo ldcp->tx_tail = tx_tail; 13071991Sheppo ldcp->hstate |= TS_SENT_RTR; 13081991Sheppo 13091991Sheppo } else { 13101991Sheppo cmn_err(CE_NOTE, 13111991Sheppo "i_ldc_process_RTS: (0x%lx) error sending RTR\n", 13121991Sheppo ldcp->id); 13132793Slm66018 i_ldc_reset(ldcp, B_TRUE); 13142336Snarayan mutex_exit(&ldcp->tx_lock); 13151991Sheppo return (ECONNRESET); 13161991Sheppo } 13171991Sheppo 13182336Snarayan mutex_exit(&ldcp->tx_lock); 13191991Sheppo return (0); 13201991Sheppo } 13211991Sheppo 13221991Sheppo /* 13231991Sheppo * Process an incoming RTR ctrl message 13241991Sheppo */ 13251991Sheppo static int 13261991Sheppo i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg) 13271991Sheppo { 13281991Sheppo int rv = 0; 13291991Sheppo boolean_t sent_NACK = B_FALSE; 13301991Sheppo 13311991Sheppo D2(ldcp->id, "i_ldc_process_RTR: (0x%llx) received RTR\n", ldcp->id); 13321991Sheppo 13331991Sheppo switch (msg->stype) { 13341991Sheppo case LDC_NACK: 13351991Sheppo /* RTR NACK received */ 13361991Sheppo DWARN(ldcp->id, 13371991Sheppo "i_ldc_process_RTR: (0x%llx) RTR NACK received\n", 13381991Sheppo ldcp->id); 13391991Sheppo 13401991Sheppo /* Reset the channel -- as we cannot continue */ 13412336Snarayan mutex_enter(&ldcp->tx_lock); 13422793Slm66018 i_ldc_reset(ldcp, B_TRUE); 13432336Snarayan mutex_exit(&ldcp->tx_lock); 13441991Sheppo rv = ECONNRESET; 13451991Sheppo 13461991Sheppo break; 13471991Sheppo 13481991Sheppo case LDC_INFO: 13491991Sheppo 13501991Sheppo /* check mode */ 13511991Sheppo if (ldcp->mode != (ldc_mode_t)msg->env) { 13521991Sheppo DWARN(ldcp->id, 13533010Slm66018 "i_ldc_process_RTR: (0x%llx) mode mismatch, " 13543010Slm66018 "expecting 0x%x, got 0x%x\n", 13553010Slm66018 ldcp->id, ldcp->mode, (ldc_mode_t)msg->env); 13561991Sheppo /* 13571991Sheppo * send NACK in response to MODE message 13581991Sheppo * get the current tail for the response 13591991Sheppo */ 13601991Sheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTR); 13611991Sheppo if (rv) { 13621991Sheppo /* if cannot send NACK - reset channel */ 13632336Snarayan mutex_enter(&ldcp->tx_lock); 13642793Slm66018 i_ldc_reset(ldcp, B_TRUE); 13652336Snarayan mutex_exit(&ldcp->tx_lock); 13661991Sheppo rv = ECONNRESET; 13671991Sheppo break; 13681991Sheppo } 13691991Sheppo sent_NACK = B_TRUE; 13701991Sheppo } 13711991Sheppo break; 13721991Sheppo 13731991Sheppo default: 13741991Sheppo DWARN(ldcp->id, "i_ldc_process_RTR: (0x%llx) unexp ACK\n", 13751991Sheppo ldcp->id); 13761991Sheppo 13771991Sheppo /* Reset the channel -- as we cannot continue */ 13782336Snarayan mutex_enter(&ldcp->tx_lock); 13792793Slm66018 i_ldc_reset(ldcp, B_TRUE); 13802336Snarayan mutex_exit(&ldcp->tx_lock); 13811991Sheppo rv = ECONNRESET; 13821991Sheppo break; 13831991Sheppo } 13841991Sheppo 13851991Sheppo /* 13861991Sheppo * If either the connection was reset (when rv != 0) or 13871991Sheppo * a NACK was sent, we return. In the case of a NACK 13881991Sheppo * we dont want to consume the packet that came in but 13891991Sheppo * not record that we received the RTR 13901991Sheppo */ 13911991Sheppo if (rv || sent_NACK) 13921991Sheppo return (rv); 13931991Sheppo 13941991Sheppo ldcp->last_msg_snt = msg->seqid; 13951991Sheppo ldcp->hstate |= TS_RCVD_RTR; 13961991Sheppo 13971991Sheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_INFO, LDC_RDX); 13981991Sheppo if (rv) { 13991991Sheppo cmn_err(CE_NOTE, 14001991Sheppo "i_ldc_process_RTR: (0x%lx) cannot send RDX\n", 14011991Sheppo ldcp->id); 14022336Snarayan mutex_enter(&ldcp->tx_lock); 14032793Slm66018 i_ldc_reset(ldcp, B_TRUE); 14042336Snarayan mutex_exit(&ldcp->tx_lock); 14051991Sheppo return (ECONNRESET); 14061991Sheppo } 14071991Sheppo D2(ldcp->id, 14081991Sheppo "i_ldc_process_RTR: (0x%llx) sent RDX\n", ldcp->id); 14091991Sheppo 14101991Sheppo ldcp->hstate |= TS_SENT_RDX; 14111991Sheppo ldcp->tstate |= TS_HSHAKE_DONE; 14122793Slm66018 if ((ldcp->tstate & TS_IN_RESET) == 0) 14132793Slm66018 ldcp->status = LDC_UP; 14141991Sheppo 14153010Slm66018 D1(ldcp->id, "(0x%llx) Handshake Complete\n", ldcp->id); 14161991Sheppo 14171991Sheppo return (0); 14181991Sheppo } 14191991Sheppo 14201991Sheppo 14211991Sheppo /* 14221991Sheppo * Process an incoming RDX ctrl message 14231991Sheppo */ 14241991Sheppo static int 14251991Sheppo i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg) 14261991Sheppo { 14271991Sheppo int rv = 0; 14281991Sheppo 14291991Sheppo D2(ldcp->id, "i_ldc_process_RDX: (0x%llx) received RDX\n", ldcp->id); 14301991Sheppo 14311991Sheppo switch (msg->stype) { 14321991Sheppo case LDC_NACK: 14331991Sheppo /* RDX NACK received */ 14341991Sheppo DWARN(ldcp->id, 14351991Sheppo "i_ldc_process_RDX: (0x%llx) RDX NACK received\n", 14361991Sheppo ldcp->id); 14371991Sheppo 14381991Sheppo /* Reset the channel -- as we cannot continue */ 14392336Snarayan mutex_enter(&ldcp->tx_lock); 14402793Slm66018 i_ldc_reset(ldcp, B_TRUE); 14412336Snarayan mutex_exit(&ldcp->tx_lock); 14421991Sheppo rv = ECONNRESET; 14431991Sheppo 14441991Sheppo break; 14451991Sheppo 14461991Sheppo case LDC_INFO: 14471991Sheppo 14481991Sheppo /* 14491991Sheppo * if channel is UP and a RDX received after data transmission 14501991Sheppo * has commenced it is an error 14511991Sheppo */ 14521991Sheppo if ((ldcp->tstate == TS_UP) && (ldcp->hstate & TS_RCVD_RDX)) { 14531991Sheppo DWARN(DBG_ALL_LDCS, 14541991Sheppo "i_ldc_process_RDX: (0x%llx) unexpected RDX" 14551991Sheppo " - LDC reset\n", ldcp->id); 14562336Snarayan mutex_enter(&ldcp->tx_lock); 14572793Slm66018 i_ldc_reset(ldcp, B_TRUE); 14582336Snarayan mutex_exit(&ldcp->tx_lock); 14591991Sheppo return (ECONNRESET); 14601991Sheppo } 14611991Sheppo 14621991Sheppo ldcp->hstate |= TS_RCVD_RDX; 14631991Sheppo ldcp->tstate |= TS_HSHAKE_DONE; 14642793Slm66018 if ((ldcp->tstate & TS_IN_RESET) == 0) 14652793Slm66018 ldcp->status = LDC_UP; 14661991Sheppo 14671991Sheppo D1(DBG_ALL_LDCS, "(0x%llx) Handshake Complete\n", ldcp->id); 14681991Sheppo break; 14691991Sheppo 14701991Sheppo default: 14711991Sheppo DWARN(ldcp->id, "i_ldc_process_RDX: (0x%llx) unexp ACK\n", 14721991Sheppo ldcp->id); 14731991Sheppo 14741991Sheppo /* Reset the channel -- as we cannot continue */ 14752336Snarayan mutex_enter(&ldcp->tx_lock); 14762793Slm66018 i_ldc_reset(ldcp, B_TRUE); 14772336Snarayan mutex_exit(&ldcp->tx_lock); 14781991Sheppo rv = ECONNRESET; 14791991Sheppo break; 14801991Sheppo } 14811991Sheppo 14821991Sheppo return (rv); 14831991Sheppo } 14841991Sheppo 14851991Sheppo /* 14861991Sheppo * Process an incoming ACK for a data packet 14871991Sheppo */ 14881991Sheppo static int 14891991Sheppo i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg) 14901991Sheppo { 14911991Sheppo int rv; 14921991Sheppo uint64_t tx_head; 14931991Sheppo ldc_msg_t *pkt; 14941991Sheppo 14952336Snarayan /* Obtain Tx lock */ 14962336Snarayan mutex_enter(&ldcp->tx_lock); 14972336Snarayan 14981991Sheppo /* 14992336Snarayan * Read the current Tx head and tail 15001991Sheppo */ 15011991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 15021991Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 15031991Sheppo if (rv != 0) { 15041991Sheppo cmn_err(CE_WARN, 15051991Sheppo "i_ldc_process_data_ACK: (0x%lx) cannot read qptrs\n", 15061991Sheppo ldcp->id); 15072336Snarayan 15082336Snarayan /* Reset the channel -- as we cannot continue */ 15092793Slm66018 i_ldc_reset(ldcp, B_TRUE); 15102336Snarayan mutex_exit(&ldcp->tx_lock); 15112336Snarayan return (ECONNRESET); 15121991Sheppo } 15131991Sheppo 15141991Sheppo /* 15151991Sheppo * loop from where the previous ACK location was to the 15161991Sheppo * current head location. This is how far the HV has 15171991Sheppo * actually send pkts. Pkts between head and tail are 15181991Sheppo * yet to be sent by HV. 15191991Sheppo */ 15201991Sheppo tx_head = ldcp->tx_ackd_head; 15211991Sheppo for (;;) { 15221991Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_head); 15231991Sheppo tx_head = (tx_head + LDC_PACKET_SIZE) % 15241991Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 15251991Sheppo 15261991Sheppo if (pkt->seqid == msg->ackid) { 15271991Sheppo D2(ldcp->id, 15281991Sheppo "i_ldc_process_data_ACK: (0x%llx) found packet\n", 15291991Sheppo ldcp->id); 15301991Sheppo ldcp->last_ack_rcd = msg->ackid; 15311991Sheppo ldcp->tx_ackd_head = tx_head; 15321991Sheppo break; 15331991Sheppo } 15341991Sheppo if (tx_head == ldcp->tx_head) { 15351991Sheppo /* could not find packet */ 15361991Sheppo DWARN(ldcp->id, 15371991Sheppo "i_ldc_process_data_ACK: (0x%llx) invalid ACKid\n", 15381991Sheppo ldcp->id); 15392336Snarayan 15402336Snarayan /* Reset the channel -- as we cannot continue */ 15412793Slm66018 i_ldc_reset(ldcp, B_TRUE); 15422336Snarayan mutex_exit(&ldcp->tx_lock); 15432336Snarayan return (ECONNRESET); 15441991Sheppo } 15451991Sheppo } 15461991Sheppo 15472336Snarayan mutex_exit(&ldcp->tx_lock); 15481991Sheppo return (0); 15491991Sheppo } 15501991Sheppo 15511991Sheppo /* 15521991Sheppo * Process incoming control message 15531991Sheppo * Return 0 - session can continue 15541991Sheppo * EAGAIN - reprocess packet - state was changed 15551991Sheppo * ECONNRESET - channel was reset 15561991Sheppo */ 15571991Sheppo static int 15581991Sheppo i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *msg) 15591991Sheppo { 15601991Sheppo int rv = 0; 15611991Sheppo 15622793Slm66018 D1(ldcp->id, "i_ldc_ctrlmsg: (%llx) tstate = %lx, hstate = %lx\n", 15632793Slm66018 ldcp->id, ldcp->tstate, ldcp->hstate); 15642793Slm66018 15652793Slm66018 switch (ldcp->tstate & ~TS_IN_RESET) { 15661991Sheppo 15671991Sheppo case TS_OPEN: 15681991Sheppo case TS_READY: 15691991Sheppo 15701991Sheppo switch (msg->ctrl & LDC_CTRL_MASK) { 15711991Sheppo case LDC_VER: 15721991Sheppo /* process version message */ 15731991Sheppo rv = i_ldc_process_VER(ldcp, msg); 15741991Sheppo break; 15751991Sheppo default: 15761991Sheppo DWARN(ldcp->id, 15771991Sheppo "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x " 15781991Sheppo "tstate=0x%x\n", ldcp->id, 15791991Sheppo (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate); 15801991Sheppo break; 15811991Sheppo } 15821991Sheppo 15831991Sheppo break; 15841991Sheppo 15851991Sheppo case TS_VREADY: 15861991Sheppo 15871991Sheppo switch (msg->ctrl & LDC_CTRL_MASK) { 15881991Sheppo case LDC_VER: 15892793Slm66018 /* process version message */ 15902793Slm66018 rv = i_ldc_process_VER(ldcp, msg); 15911991Sheppo break; 15921991Sheppo case LDC_RTS: 15931991Sheppo /* process RTS message */ 15941991Sheppo rv = i_ldc_process_RTS(ldcp, msg); 15951991Sheppo break; 15961991Sheppo case LDC_RTR: 15971991Sheppo /* process RTR message */ 15981991Sheppo rv = i_ldc_process_RTR(ldcp, msg); 15991991Sheppo break; 16001991Sheppo case LDC_RDX: 16011991Sheppo /* process RDX message */ 16021991Sheppo rv = i_ldc_process_RDX(ldcp, msg); 16031991Sheppo break; 16041991Sheppo default: 16051991Sheppo DWARN(ldcp->id, 16061991Sheppo "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x " 16071991Sheppo "tstate=0x%x\n", ldcp->id, 16081991Sheppo (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate); 16091991Sheppo break; 16101991Sheppo } 16111991Sheppo 16121991Sheppo break; 16131991Sheppo 16141991Sheppo case TS_UP: 16151991Sheppo 16161991Sheppo switch (msg->ctrl & LDC_CTRL_MASK) { 16171991Sheppo case LDC_VER: 16181991Sheppo DWARN(ldcp->id, 16191991Sheppo "i_ldc_ctrlmsg: (0x%llx) unexpected VER " 16201991Sheppo "- LDC reset\n", ldcp->id); 16211991Sheppo /* peer is redoing version negotiation */ 16222336Snarayan mutex_enter(&ldcp->tx_lock); 16231991Sheppo (void) i_ldc_txq_reconf(ldcp); 16241991Sheppo i_ldc_reset_state(ldcp); 16252336Snarayan mutex_exit(&ldcp->tx_lock); 16261991Sheppo rv = EAGAIN; 16271991Sheppo break; 16281991Sheppo 16291991Sheppo case LDC_RDX: 16301991Sheppo /* process RDX message */ 16311991Sheppo rv = i_ldc_process_RDX(ldcp, msg); 16321991Sheppo break; 16331991Sheppo 16341991Sheppo default: 16351991Sheppo DWARN(ldcp->id, 16361991Sheppo "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x " 16371991Sheppo "tstate=0x%x\n", ldcp->id, 16381991Sheppo (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate); 16391991Sheppo break; 16401991Sheppo } 16411991Sheppo } 16421991Sheppo 16431991Sheppo return (rv); 16441991Sheppo } 16451991Sheppo 16461991Sheppo /* 16471991Sheppo * Register channel with the channel nexus 16481991Sheppo */ 16491991Sheppo static int 16501991Sheppo i_ldc_register_channel(ldc_chan_t *ldcp) 16511991Sheppo { 16521991Sheppo int rv = 0; 16531991Sheppo ldc_cnex_t *cinfo = &ldcssp->cinfo; 16541991Sheppo 16551991Sheppo if (cinfo->dip == NULL) { 16561991Sheppo DWARN(ldcp->id, 16571991Sheppo "i_ldc_register_channel: cnex has not registered\n"); 16581991Sheppo return (EAGAIN); 16591991Sheppo } 16601991Sheppo 16611991Sheppo rv = cinfo->reg_chan(cinfo->dip, ldcp->id, ldcp->devclass); 16621991Sheppo if (rv) { 16631991Sheppo DWARN(ldcp->id, 16641991Sheppo "i_ldc_register_channel: cannot register channel\n"); 16651991Sheppo return (rv); 16661991Sheppo } 16671991Sheppo 16681991Sheppo rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR, 16691991Sheppo i_ldc_tx_hdlr, ldcp, NULL); 16701991Sheppo if (rv) { 16711991Sheppo DWARN(ldcp->id, 16721991Sheppo "i_ldc_register_channel: cannot add Tx interrupt\n"); 16731991Sheppo (void) cinfo->unreg_chan(cinfo->dip, ldcp->id); 16741991Sheppo return (rv); 16751991Sheppo } 16761991Sheppo 16771991Sheppo rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR, 16781991Sheppo i_ldc_rx_hdlr, ldcp, NULL); 16791991Sheppo if (rv) { 16801991Sheppo DWARN(ldcp->id, 16811991Sheppo "i_ldc_register_channel: cannot add Rx interrupt\n"); 16821991Sheppo (void) cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR); 16831991Sheppo (void) cinfo->unreg_chan(cinfo->dip, ldcp->id); 16841991Sheppo return (rv); 16851991Sheppo } 16861991Sheppo 16871991Sheppo ldcp->tstate |= TS_CNEX_RDY; 16881991Sheppo 16891991Sheppo return (0); 16901991Sheppo } 16911991Sheppo 16921991Sheppo /* 16931991Sheppo * Unregister a channel with the channel nexus 16941991Sheppo */ 16951991Sheppo static int 16961991Sheppo i_ldc_unregister_channel(ldc_chan_t *ldcp) 16971991Sheppo { 16981991Sheppo int rv = 0; 16991991Sheppo ldc_cnex_t *cinfo = &ldcssp->cinfo; 17001991Sheppo 17011991Sheppo if (cinfo->dip == NULL) { 17021991Sheppo DWARN(ldcp->id, 17031991Sheppo "i_ldc_unregister_channel: cnex has not registered\n"); 17041991Sheppo return (EAGAIN); 17051991Sheppo } 17061991Sheppo 17071991Sheppo if (ldcp->tstate & TS_CNEX_RDY) { 17081991Sheppo 17092336Snarayan /* Remove the Rx interrupt */ 17101991Sheppo rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR); 17111991Sheppo if (rv) { 17122793Slm66018 if (rv != EAGAIN) { 17132793Slm66018 DWARN(ldcp->id, 17142793Slm66018 "i_ldc_unregister_channel: err removing " 17152793Slm66018 "Rx intr\n"); 17162793Slm66018 return (rv); 17172793Slm66018 } 17182793Slm66018 17192793Slm66018 /* 17202793Slm66018 * If interrupts are pending and handler has 17212793Slm66018 * finished running, clear interrupt and try 17222793Slm66018 * again 17232793Slm66018 */ 17242793Slm66018 if (ldcp->rx_intr_state != LDC_INTR_PEND) 17252793Slm66018 return (rv); 17262793Slm66018 17272793Slm66018 (void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 17282793Slm66018 rv = cinfo->rem_intr(cinfo->dip, ldcp->id, 17292793Slm66018 CNEX_RX_INTR); 17302793Slm66018 if (rv) { 17312793Slm66018 DWARN(ldcp->id, "i_ldc_unregister_channel: " 17322793Slm66018 "err removing Rx interrupt\n"); 17332793Slm66018 return (rv); 17342793Slm66018 } 17351991Sheppo } 17362336Snarayan 17372336Snarayan /* Remove the Tx interrupt */ 17381991Sheppo rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR); 17391991Sheppo if (rv) { 17401991Sheppo DWARN(ldcp->id, 17411991Sheppo "i_ldc_unregister_channel: err removing Tx intr\n"); 17422336Snarayan return (rv); 17431991Sheppo } 17442336Snarayan 17452336Snarayan /* Unregister the channel */ 17461991Sheppo rv = cinfo->unreg_chan(ldcssp->cinfo.dip, ldcp->id); 17471991Sheppo if (rv) { 17481991Sheppo DWARN(ldcp->id, 17491991Sheppo "i_ldc_unregister_channel: cannot unreg channel\n"); 17502336Snarayan return (rv); 17511991Sheppo } 17521991Sheppo 17531991Sheppo ldcp->tstate &= ~TS_CNEX_RDY; 17541991Sheppo } 17551991Sheppo 17561991Sheppo return (0); 17571991Sheppo } 17581991Sheppo 17591991Sheppo 17601991Sheppo /* 17611991Sheppo * LDC transmit interrupt handler 17621991Sheppo * triggered for chanel up/down/reset events 17631991Sheppo * and Tx queue content changes 17641991Sheppo */ 17651991Sheppo static uint_t 17661991Sheppo i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2) 17671991Sheppo { 17681991Sheppo _NOTE(ARGUNUSED(arg2)) 17691991Sheppo 17701991Sheppo int rv; 17711991Sheppo ldc_chan_t *ldcp; 17721991Sheppo boolean_t notify_client = B_FALSE; 17732793Slm66018 uint64_t notify_event = 0, link_state; 17741991Sheppo 17751991Sheppo /* Get the channel for which interrupt was received */ 17761991Sheppo ASSERT(arg1 != NULL); 17771991Sheppo ldcp = (ldc_chan_t *)arg1; 17781991Sheppo 17791991Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n", 17801991Sheppo ldcp->id, ldcp); 17811991Sheppo 17821991Sheppo /* Lock channel */ 17831991Sheppo mutex_enter(&ldcp->lock); 17841991Sheppo 17852336Snarayan /* Obtain Tx lock */ 17862336Snarayan mutex_enter(&ldcp->tx_lock); 17872336Snarayan 17882531Snarayan /* mark interrupt as pending */ 17892793Slm66018 ldcp->tx_intr_state = LDC_INTR_ACTIVE; 17902793Slm66018 17912793Slm66018 /* save current link state */ 17922793Slm66018 link_state = ldcp->link_state; 17932531Snarayan 17941991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, &ldcp->tx_head, &ldcp->tx_tail, 17951991Sheppo &ldcp->link_state); 17961991Sheppo if (rv) { 17971991Sheppo cmn_err(CE_WARN, 17981991Sheppo "i_ldc_tx_hdlr: (0x%lx) cannot read queue ptrs rv=0x%d\n", 17991991Sheppo ldcp->id, rv); 18002531Snarayan i_ldc_clear_intr(ldcp, CNEX_TX_INTR); 18012336Snarayan mutex_exit(&ldcp->tx_lock); 18021991Sheppo mutex_exit(&ldcp->lock); 18031991Sheppo return (DDI_INTR_CLAIMED); 18041991Sheppo } 18051991Sheppo 18061991Sheppo /* 18071991Sheppo * reset the channel state if the channel went down 18081991Sheppo * (other side unconfigured queue) or channel was reset 18091991Sheppo * (other side reconfigured its queue) 18101991Sheppo */ 18112793Slm66018 if (link_state != ldcp->link_state && 18122793Slm66018 ldcp->link_state == LDC_CHANNEL_DOWN) { 18131991Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: channel link down\n", ldcp->id); 18142793Slm66018 i_ldc_reset(ldcp, B_FALSE); 18151991Sheppo notify_client = B_TRUE; 18161991Sheppo notify_event = LDC_EVT_DOWN; 18171991Sheppo } 18181991Sheppo 18192793Slm66018 if (link_state != ldcp->link_state && 18202793Slm66018 ldcp->link_state == LDC_CHANNEL_RESET) { 18211991Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: channel link reset\n", ldcp->id); 18222793Slm66018 i_ldc_reset(ldcp, B_FALSE); 18231991Sheppo notify_client = B_TRUE; 18241991Sheppo notify_event = LDC_EVT_RESET; 18251991Sheppo } 18261991Sheppo 18272793Slm66018 if (link_state != ldcp->link_state && 18282793Slm66018 (ldcp->tstate & ~TS_IN_RESET) == TS_OPEN && 18292793Slm66018 ldcp->link_state == LDC_CHANNEL_UP) { 18301991Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: channel link up\n", ldcp->id); 18311991Sheppo notify_client = B_TRUE; 18321991Sheppo notify_event = LDC_EVT_RESET; 18331991Sheppo ldcp->tstate |= TS_LINK_READY; 18341991Sheppo ldcp->status = LDC_READY; 18351991Sheppo } 18361991Sheppo 18371991Sheppo /* if callbacks are disabled, do not notify */ 18381991Sheppo if (!ldcp->cb_enabled) 18391991Sheppo notify_client = B_FALSE; 18401991Sheppo 1841*3151Ssg70180 i_ldc_clear_intr(ldcp, CNEX_TX_INTR); 18421991Sheppo 18431991Sheppo if (notify_client) { 18442793Slm66018 ldcp->cb_inprogress = B_TRUE; 18452793Slm66018 mutex_exit(&ldcp->tx_lock); 18462793Slm66018 mutex_exit(&ldcp->lock); 18471991Sheppo rv = ldcp->cb(notify_event, ldcp->cb_arg); 18481991Sheppo if (rv) { 18491991Sheppo DWARN(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) callback " 18501991Sheppo "failure", ldcp->id); 18511991Sheppo } 18521991Sheppo mutex_enter(&ldcp->lock); 18531991Sheppo ldcp->cb_inprogress = B_FALSE; 18542793Slm66018 } 18552793Slm66018 18561991Sheppo mutex_exit(&ldcp->lock); 18571991Sheppo 18581991Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) exiting handler", ldcp->id); 18591991Sheppo 18601991Sheppo return (DDI_INTR_CLAIMED); 18611991Sheppo } 18621991Sheppo 18631991Sheppo /* 18641991Sheppo * LDC receive interrupt handler 18651991Sheppo * triggered for channel with data pending to read 18661991Sheppo * i.e. Rx queue content changes 18671991Sheppo */ 18681991Sheppo static uint_t 18691991Sheppo i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2) 18701991Sheppo { 18711991Sheppo _NOTE(ARGUNUSED(arg2)) 18721991Sheppo 18731991Sheppo int rv; 18741991Sheppo uint64_t rx_head, rx_tail; 18751991Sheppo ldc_msg_t *msg; 18761991Sheppo ldc_chan_t *ldcp; 18771991Sheppo boolean_t notify_client = B_FALSE; 18781991Sheppo uint64_t notify_event = 0; 18792793Slm66018 uint64_t link_state, first_fragment = 0; 18802793Slm66018 18811991Sheppo 18821991Sheppo /* Get the channel for which interrupt was received */ 18831991Sheppo if (arg1 == NULL) { 18841991Sheppo cmn_err(CE_WARN, "i_ldc_rx_hdlr: invalid arg\n"); 18851991Sheppo return (DDI_INTR_UNCLAIMED); 18861991Sheppo } 18871991Sheppo 18881991Sheppo ldcp = (ldc_chan_t *)arg1; 18891991Sheppo 18901991Sheppo D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n", 18911991Sheppo ldcp->id, ldcp); 18922793Slm66018 D1(ldcp->id, "i_ldc_rx_hdlr: (%llx) USR%lx/TS%lx/HS%lx, LSTATE=%lx\n", 18932793Slm66018 ldcp->id, ldcp->status, ldcp->tstate, ldcp->hstate, 18942793Slm66018 ldcp->link_state); 18951991Sheppo 18961991Sheppo /* Lock channel */ 18971991Sheppo mutex_enter(&ldcp->lock); 18981991Sheppo 18991991Sheppo /* mark interrupt as pending */ 19002793Slm66018 ldcp->rx_intr_state = LDC_INTR_ACTIVE; 19011991Sheppo 19021991Sheppo /* 19031991Sheppo * Read packet(s) from the queue 19041991Sheppo */ 19051991Sheppo for (;;) { 19061991Sheppo 19072793Slm66018 link_state = ldcp->link_state; 19081991Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 19091991Sheppo &ldcp->link_state); 19101991Sheppo if (rv) { 19111991Sheppo cmn_err(CE_WARN, 19121991Sheppo "i_ldc_rx_hdlr: (0x%lx) cannot read " 19131991Sheppo "queue ptrs, rv=0x%d\n", ldcp->id, rv); 19141991Sheppo i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 19151991Sheppo mutex_exit(&ldcp->lock); 19161991Sheppo return (DDI_INTR_CLAIMED); 19171991Sheppo } 19181991Sheppo 19191991Sheppo /* 19201991Sheppo * reset the channel state if the channel went down 19211991Sheppo * (other side unconfigured queue) or channel was reset 19222793Slm66018 * (other side reconfigured its queue) 19231991Sheppo */ 19242793Slm66018 19252793Slm66018 if (link_state != ldcp->link_state) { 19263010Slm66018 19272793Slm66018 switch (ldcp->link_state) { 19282793Slm66018 case LDC_CHANNEL_DOWN: 19292793Slm66018 D1(ldcp->id, "i_ldc_rx_hdlr: channel " 19302793Slm66018 "link down\n", ldcp->id); 19312793Slm66018 mutex_enter(&ldcp->tx_lock); 19322793Slm66018 i_ldc_reset(ldcp, B_FALSE); 19332793Slm66018 mutex_exit(&ldcp->tx_lock); 19342793Slm66018 notify_client = B_TRUE; 19352793Slm66018 notify_event = LDC_EVT_DOWN; 19362793Slm66018 goto loop_exit; 19372793Slm66018 19382793Slm66018 case LDC_CHANNEL_UP: 19392793Slm66018 D1(ldcp->id, "i_ldc_rx_hdlr: " 19402793Slm66018 "channel link up\n", ldcp->id); 19412793Slm66018 19422793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) == TS_OPEN) { 19432793Slm66018 notify_client = B_TRUE; 19442793Slm66018 notify_event = LDC_EVT_RESET; 19452793Slm66018 ldcp->tstate |= TS_LINK_READY; 19462793Slm66018 ldcp->status = LDC_READY; 19472793Slm66018 } 19482793Slm66018 break; 19492793Slm66018 19502793Slm66018 case LDC_CHANNEL_RESET: 19512793Slm66018 default: 19522793Slm66018 #ifdef DEBUG 19532793Slm66018 force_reset: 19542793Slm66018 #endif 19552793Slm66018 D1(ldcp->id, "i_ldc_rx_hdlr: channel " 19562793Slm66018 "link reset\n", ldcp->id); 19572793Slm66018 mutex_enter(&ldcp->tx_lock); 19582793Slm66018 i_ldc_reset(ldcp, B_FALSE); 19592793Slm66018 mutex_exit(&ldcp->tx_lock); 19602793Slm66018 notify_client = B_TRUE; 19612793Slm66018 notify_event = LDC_EVT_RESET; 19622793Slm66018 break; 19632793Slm66018 } 19641991Sheppo } 19652793Slm66018 19662793Slm66018 #ifdef DEBUG 19672793Slm66018 if (LDC_INJECT_RESET(ldcp)) 19682793Slm66018 goto force_reset; 19692793Slm66018 #endif 19701991Sheppo 19711991Sheppo if (rx_head == rx_tail) { 19721991Sheppo D2(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) No packets\n", 19731991Sheppo ldcp->id); 19741991Sheppo break; 19751991Sheppo } 19762793Slm66018 19771991Sheppo D2(ldcp->id, "i_ldc_rx_hdlr: head=0x%llx, tail=0x%llx\n", 19781991Sheppo rx_head, rx_tail); 19791991Sheppo DUMP_LDC_PKT(ldcp, "i_ldc_rx_hdlr rcd", 19801991Sheppo ldcp->rx_q_va + rx_head); 19811991Sheppo 19821991Sheppo /* get the message */ 19831991Sheppo msg = (ldc_msg_t *)(ldcp->rx_q_va + rx_head); 19841991Sheppo 19851991Sheppo /* if channel is in RAW mode or data pkt, notify and return */ 19861991Sheppo if (ldcp->mode == LDC_MODE_RAW) { 19871991Sheppo notify_client = B_TRUE; 19881991Sheppo notify_event |= LDC_EVT_READ; 19891991Sheppo break; 19901991Sheppo } 19911991Sheppo 19921991Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) { 19931991Sheppo 19941991Sheppo /* discard packet if channel is not up */ 19952793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) != TS_UP) { 19961991Sheppo 19971991Sheppo /* move the head one position */ 19981991Sheppo rx_head = (rx_head + LDC_PACKET_SIZE) % 19991991Sheppo (ldcp->rx_q_entries << LDC_PACKET_SHIFT); 20001991Sheppo 20011991Sheppo if (rv = i_ldc_set_rx_head(ldcp, rx_head)) 20021991Sheppo break; 20031991Sheppo 20041991Sheppo continue; 20051991Sheppo } else { 20062793Slm66018 if ((ldcp->tstate & TS_IN_RESET) == 0) 20072793Slm66018 notify_client = B_TRUE; 20081991Sheppo notify_event |= LDC_EVT_READ; 20091991Sheppo break; 20101991Sheppo } 20111991Sheppo } 20121991Sheppo 20131991Sheppo /* Check the sequence ID for the message received */ 20142793Slm66018 rv = i_ldc_check_seqid(ldcp, msg); 20152793Slm66018 if (rv != 0) { 20161991Sheppo 20171991Sheppo DWARN(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) seqid error, " 20181991Sheppo "q_ptrs=0x%lx,0x%lx", ldcp->id, rx_head, rx_tail); 20191991Sheppo 20201991Sheppo /* Reset last_msg_rcd to start of message */ 20212336Snarayan if (first_fragment != 0) { 20222336Snarayan ldcp->last_msg_rcd = first_fragment - 1; 20232336Snarayan first_fragment = 0; 20241991Sheppo } 20252336Snarayan 20261991Sheppo /* 20271991Sheppo * Send a NACK due to seqid mismatch 20281991Sheppo */ 20291991Sheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, 20301991Sheppo (msg->ctrl & LDC_CTRL_MASK)); 20311991Sheppo 20321991Sheppo if (rv) { 20331991Sheppo cmn_err(CE_NOTE, 20341991Sheppo "i_ldc_rx_hdlr: (0x%lx) err sending " 20351991Sheppo "CTRL/NACK msg\n", ldcp->id); 20362336Snarayan 20372336Snarayan /* if cannot send NACK - reset channel */ 20382336Snarayan mutex_enter(&ldcp->tx_lock); 20392793Slm66018 i_ldc_reset(ldcp, B_TRUE); 20402336Snarayan mutex_exit(&ldcp->tx_lock); 20412336Snarayan rv = ECONNRESET; 20422336Snarayan break; 20431991Sheppo } 20441991Sheppo 20451991Sheppo /* purge receive queue */ 20461991Sheppo (void) i_ldc_set_rx_head(ldcp, rx_tail); 20471991Sheppo break; 20481991Sheppo } 20491991Sheppo 20501991Sheppo /* record the message ID */ 20511991Sheppo ldcp->last_msg_rcd = msg->seqid; 20521991Sheppo 20531991Sheppo /* process control messages */ 20541991Sheppo if (msg->type & LDC_CTRL) { 20551991Sheppo /* save current internal state */ 20561991Sheppo uint64_t tstate = ldcp->tstate; 20571991Sheppo 20581991Sheppo rv = i_ldc_ctrlmsg(ldcp, msg); 20591991Sheppo if (rv == EAGAIN) { 20601991Sheppo /* re-process pkt - state was adjusted */ 20611991Sheppo continue; 20621991Sheppo } 20631991Sheppo if (rv == ECONNRESET) { 20641991Sheppo notify_client = B_TRUE; 20651991Sheppo notify_event = LDC_EVT_RESET; 20661991Sheppo break; 20671991Sheppo } 20681991Sheppo 20691991Sheppo /* 20701991Sheppo * control message processing was successful 20711991Sheppo * channel transitioned to ready for communication 20721991Sheppo */ 20731991Sheppo if (rv == 0 && ldcp->tstate == TS_UP && 20742793Slm66018 (tstate & ~TS_IN_RESET) != 20752793Slm66018 (ldcp->tstate & ~TS_IN_RESET)) { 20761991Sheppo notify_client = B_TRUE; 20771991Sheppo notify_event = LDC_EVT_UP; 20781991Sheppo } 20791991Sheppo } 20801991Sheppo 20811991Sheppo /* process data ACKs */ 20821991Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) { 20832336Snarayan if (rv = i_ldc_process_data_ACK(ldcp, msg)) { 20842336Snarayan notify_client = B_TRUE; 20852336Snarayan notify_event = LDC_EVT_RESET; 20862336Snarayan break; 20872336Snarayan } 20881991Sheppo } 20891991Sheppo 20901991Sheppo /* move the head one position */ 20911991Sheppo rx_head = (rx_head + LDC_PACKET_SIZE) % 20921991Sheppo (ldcp->rx_q_entries << LDC_PACKET_SHIFT); 20932032Slm66018 if (rv = i_ldc_set_rx_head(ldcp, rx_head)) { 20942032Slm66018 notify_client = B_TRUE; 20952032Slm66018 notify_event = LDC_EVT_RESET; 20961991Sheppo break; 20972032Slm66018 } 20981991Sheppo 20991991Sheppo } /* for */ 21001991Sheppo 21012793Slm66018 loop_exit: 21022793Slm66018 21031991Sheppo /* if callbacks are disabled, do not notify */ 21041991Sheppo if (!ldcp->cb_enabled) 21051991Sheppo notify_client = B_FALSE; 21061991Sheppo 21072793Slm66018 /* 21082793Slm66018 * If there are data packets in the queue, the ldc_read will 21092793Slm66018 * clear interrupts after draining the queue, else clear interrupts 21102793Slm66018 */ 21112793Slm66018 if ((notify_event & LDC_EVT_READ) == 0) { 21122793Slm66018 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 21132793Slm66018 } else 21142793Slm66018 ldcp->rx_intr_state = LDC_INTR_PEND; 21152793Slm66018 21161991Sheppo 21171991Sheppo if (notify_client) { 2118*3151Ssg70180 ldcp->cb_inprogress = B_TRUE; 2119*3151Ssg70180 mutex_exit(&ldcp->lock); 21201991Sheppo rv = ldcp->cb(notify_event, ldcp->cb_arg); 21211991Sheppo if (rv) { 21221991Sheppo DWARN(ldcp->id, 21231991Sheppo "i_ldc_rx_hdlr: (0x%llx) callback failure", 21241991Sheppo ldcp->id); 21251991Sheppo } 2126*3151Ssg70180 mutex_enter(&ldcp->lock); 2127*3151Ssg70180 ldcp->cb_inprogress = B_FALSE; 2128*3151Ssg70180 } 2129*3151Ssg70180 2130*3151Ssg70180 mutex_exit(&ldcp->lock); 21311991Sheppo 21321991Sheppo D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) exiting handler", ldcp->id); 21331991Sheppo return (DDI_INTR_CLAIMED); 21341991Sheppo } 21351991Sheppo 21361991Sheppo 21371991Sheppo /* -------------------------------------------------------------------------- */ 21381991Sheppo 21391991Sheppo /* 21401991Sheppo * LDC API functions 21411991Sheppo */ 21421991Sheppo 21431991Sheppo /* 21441991Sheppo * Initialize the channel. Allocate internal structure and memory for 21451991Sheppo * TX/RX queues, and initialize locks. 21461991Sheppo */ 21471991Sheppo int 21481991Sheppo ldc_init(uint64_t id, ldc_attr_t *attr, ldc_handle_t *handle) 21491991Sheppo { 21501991Sheppo ldc_chan_t *ldcp; 21511991Sheppo int rv, exit_val; 21521991Sheppo uint64_t ra_base, nentries; 21532410Slm66018 uint64_t qlen; 21541991Sheppo 21551991Sheppo exit_val = EINVAL; /* guarantee an error if exit on failure */ 21561991Sheppo 21571991Sheppo if (attr == NULL) { 21581991Sheppo DWARN(id, "ldc_init: (0x%llx) invalid attr\n", id); 21591991Sheppo return (EINVAL); 21601991Sheppo } 21611991Sheppo if (handle == NULL) { 21621991Sheppo DWARN(id, "ldc_init: (0x%llx) invalid handle\n", id); 21631991Sheppo return (EINVAL); 21641991Sheppo } 21651991Sheppo 21661991Sheppo /* check if channel is valid */ 21671991Sheppo rv = hv_ldc_tx_qinfo(id, &ra_base, &nentries); 21681991Sheppo if (rv == H_ECHANNEL) { 21691991Sheppo DWARN(id, "ldc_init: (0x%llx) invalid channel id\n", id); 21701991Sheppo return (EINVAL); 21711991Sheppo } 21721991Sheppo 21731991Sheppo /* check if the channel has already been initialized */ 21741991Sheppo mutex_enter(&ldcssp->lock); 21751991Sheppo ldcp = ldcssp->chan_list; 21761991Sheppo while (ldcp != NULL) { 21771991Sheppo if (ldcp->id == id) { 21781991Sheppo DWARN(id, "ldc_init: (0x%llx) already initialized\n", 21791991Sheppo id); 21801991Sheppo mutex_exit(&ldcssp->lock); 21811991Sheppo return (EADDRINUSE); 21821991Sheppo } 21831991Sheppo ldcp = ldcp->next; 21841991Sheppo } 21851991Sheppo mutex_exit(&ldcssp->lock); 21861991Sheppo 21871991Sheppo ASSERT(ldcp == NULL); 21881991Sheppo 21891991Sheppo *handle = 0; 21901991Sheppo 21911991Sheppo /* Allocate an ldcp structure */ 21921991Sheppo ldcp = kmem_zalloc(sizeof (ldc_chan_t), KM_SLEEP); 21931991Sheppo 21942336Snarayan /* 21952336Snarayan * Initialize the channel and Tx lock 21962336Snarayan * 21972336Snarayan * The channel 'lock' protects the entire channel and 21982336Snarayan * should be acquired before initializing, resetting, 21992336Snarayan * destroying or reading from a channel. 22002336Snarayan * 22012336Snarayan * The 'tx_lock' should be acquired prior to transmitting 22022336Snarayan * data over the channel. The lock should also be acquired 22032336Snarayan * prior to channel reconfiguration (in order to prevent 22042336Snarayan * concurrent writes). 22052336Snarayan * 22062336Snarayan * ORDERING: When both locks are being acquired, to prevent 22072336Snarayan * deadlocks, the channel lock should be always acquired prior 22082336Snarayan * to the tx_lock. 22092336Snarayan */ 22101991Sheppo mutex_init(&ldcp->lock, NULL, MUTEX_DRIVER, NULL); 22112336Snarayan mutex_init(&ldcp->tx_lock, NULL, MUTEX_DRIVER, NULL); 22121991Sheppo 22131991Sheppo /* Initialize the channel */ 22141991Sheppo ldcp->id = id; 22151991Sheppo ldcp->cb = NULL; 22161991Sheppo ldcp->cb_arg = NULL; 22171991Sheppo ldcp->cb_inprogress = B_FALSE; 22181991Sheppo ldcp->cb_enabled = B_FALSE; 22191991Sheppo ldcp->next = NULL; 22201991Sheppo 22211991Sheppo /* Read attributes */ 22221991Sheppo ldcp->mode = attr->mode; 22231991Sheppo ldcp->devclass = attr->devclass; 22241991Sheppo ldcp->devinst = attr->instance; 22252410Slm66018 ldcp->mtu = (attr->mtu > 0) ? attr->mtu : LDC_DEFAULT_MTU; 22261991Sheppo 22271991Sheppo D1(ldcp->id, 22281991Sheppo "ldc_init: (0x%llx) channel attributes, class=0x%x, " 22292410Slm66018 "instance=0x%llx, mode=%d, mtu=%d\n", 22302410Slm66018 ldcp->id, ldcp->devclass, ldcp->devinst, ldcp->mode, ldcp->mtu); 22311991Sheppo 22321991Sheppo ldcp->next_vidx = 0; 22332793Slm66018 ldcp->tstate = TS_IN_RESET; 22341991Sheppo ldcp->hstate = 0; 22351991Sheppo ldcp->last_msg_snt = LDC_INIT_SEQID; 22361991Sheppo ldcp->last_ack_rcd = 0; 22371991Sheppo ldcp->last_msg_rcd = 0; 22381991Sheppo 22391991Sheppo ldcp->stream_bufferp = NULL; 22401991Sheppo ldcp->exp_dring_list = NULL; 22411991Sheppo ldcp->imp_dring_list = NULL; 22421991Sheppo ldcp->mhdl_list = NULL; 22431991Sheppo 22442793Slm66018 ldcp->tx_intr_state = LDC_INTR_NONE; 22452793Slm66018 ldcp->rx_intr_state = LDC_INTR_NONE; 22462793Slm66018 22471991Sheppo /* Initialize payload size depending on whether channel is reliable */ 22481991Sheppo switch (ldcp->mode) { 22491991Sheppo case LDC_MODE_RAW: 22501991Sheppo ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RAW; 22511991Sheppo ldcp->read_p = i_ldc_read_raw; 22521991Sheppo ldcp->write_p = i_ldc_write_raw; 22531991Sheppo break; 22541991Sheppo case LDC_MODE_UNRELIABLE: 22551991Sheppo ldcp->pkt_payload = LDC_PAYLOAD_SIZE_UNRELIABLE; 22561991Sheppo ldcp->read_p = i_ldc_read_packet; 22571991Sheppo ldcp->write_p = i_ldc_write_packet; 22581991Sheppo break; 22591991Sheppo case LDC_MODE_RELIABLE: 22601991Sheppo ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RELIABLE; 22611991Sheppo ldcp->read_p = i_ldc_read_packet; 22621991Sheppo ldcp->write_p = i_ldc_write_packet; 22631991Sheppo break; 22641991Sheppo case LDC_MODE_STREAM: 22651991Sheppo ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RELIABLE; 22661991Sheppo 22671991Sheppo ldcp->stream_remains = 0; 22681991Sheppo ldcp->stream_offset = 0; 22691991Sheppo ldcp->stream_bufferp = kmem_alloc(ldcp->mtu, KM_SLEEP); 22701991Sheppo ldcp->read_p = i_ldc_read_stream; 22711991Sheppo ldcp->write_p = i_ldc_write_stream; 22721991Sheppo break; 22731991Sheppo default: 22741991Sheppo exit_val = EINVAL; 22751991Sheppo goto cleanup_on_exit; 22761991Sheppo } 22771991Sheppo 22782410Slm66018 /* 22792410Slm66018 * qlen is (mtu * ldc_mtu_msgs) / pkt_payload. If this 22802410Slm66018 * value is smaller than default length of ldc_queue_entries, 22812410Slm66018 * qlen is set to ldc_queue_entries.. 22822410Slm66018 */ 22832410Slm66018 qlen = (ldcp->mtu * ldc_mtu_msgs) / ldcp->pkt_payload; 22842410Slm66018 ldcp->rx_q_entries = 22852410Slm66018 (qlen < ldc_queue_entries) ? ldc_queue_entries : qlen; 22862410Slm66018 ldcp->tx_q_entries = ldcp->rx_q_entries; 22872410Slm66018 22882410Slm66018 D1(ldcp->id, "ldc_init: queue length = 0x%llx\n", qlen); 22892410Slm66018 22901991Sheppo /* Create a transmit queue */ 22911991Sheppo ldcp->tx_q_va = (uint64_t) 22921991Sheppo contig_mem_alloc(ldcp->tx_q_entries << LDC_PACKET_SHIFT); 22931991Sheppo if (ldcp->tx_q_va == NULL) { 22941991Sheppo cmn_err(CE_WARN, 22951991Sheppo "ldc_init: (0x%lx) TX queue allocation failed\n", 22961991Sheppo ldcp->id); 22971991Sheppo exit_val = ENOMEM; 22981991Sheppo goto cleanup_on_exit; 22991991Sheppo } 23001991Sheppo ldcp->tx_q_ra = va_to_pa((caddr_t)ldcp->tx_q_va); 23011991Sheppo 23021991Sheppo D2(ldcp->id, "ldc_init: txq_va=0x%llx, txq_ra=0x%llx, entries=0x%llx\n", 23031991Sheppo ldcp->tx_q_va, ldcp->tx_q_ra, ldcp->tx_q_entries); 23041991Sheppo 23051991Sheppo ldcp->tstate |= TS_TXQ_RDY; 23061991Sheppo 23071991Sheppo /* Create a receive queue */ 23081991Sheppo ldcp->rx_q_va = (uint64_t) 23091991Sheppo contig_mem_alloc(ldcp->rx_q_entries << LDC_PACKET_SHIFT); 23101991Sheppo if (ldcp->rx_q_va == NULL) { 23111991Sheppo cmn_err(CE_WARN, 23121991Sheppo "ldc_init: (0x%lx) RX queue allocation failed\n", 23131991Sheppo ldcp->id); 23141991Sheppo exit_val = ENOMEM; 23151991Sheppo goto cleanup_on_exit; 23161991Sheppo } 23171991Sheppo ldcp->rx_q_ra = va_to_pa((caddr_t)ldcp->rx_q_va); 23181991Sheppo 23191991Sheppo D2(ldcp->id, "ldc_init: rxq_va=0x%llx, rxq_ra=0x%llx, entries=0x%llx\n", 23201991Sheppo ldcp->rx_q_va, ldcp->rx_q_ra, ldcp->rx_q_entries); 23211991Sheppo 23221991Sheppo ldcp->tstate |= TS_RXQ_RDY; 23231991Sheppo 23241991Sheppo /* Init descriptor ring and memory handle list lock */ 23251991Sheppo mutex_init(&ldcp->exp_dlist_lock, NULL, MUTEX_DRIVER, NULL); 23261991Sheppo mutex_init(&ldcp->imp_dlist_lock, NULL, MUTEX_DRIVER, NULL); 23271991Sheppo mutex_init(&ldcp->mlist_lock, NULL, MUTEX_DRIVER, NULL); 23281991Sheppo 23291991Sheppo /* mark status as INITialized */ 23301991Sheppo ldcp->status = LDC_INIT; 23311991Sheppo 23321991Sheppo /* Add to channel list */ 23331991Sheppo mutex_enter(&ldcssp->lock); 23341991Sheppo ldcp->next = ldcssp->chan_list; 23351991Sheppo ldcssp->chan_list = ldcp; 23361991Sheppo ldcssp->channel_count++; 23371991Sheppo mutex_exit(&ldcssp->lock); 23381991Sheppo 23391991Sheppo /* set the handle */ 23401991Sheppo *handle = (ldc_handle_t)ldcp; 23411991Sheppo 23421991Sheppo D1(ldcp->id, "ldc_init: (0x%llx) channel initialized\n", ldcp->id); 23431991Sheppo 23441991Sheppo return (0); 23451991Sheppo 23461991Sheppo cleanup_on_exit: 23471991Sheppo 23481991Sheppo if (ldcp->mode == LDC_MODE_STREAM && ldcp->stream_bufferp) 23491991Sheppo kmem_free(ldcp->stream_bufferp, ldcp->mtu); 23501991Sheppo 23511991Sheppo if (ldcp->tstate & TS_TXQ_RDY) 23521991Sheppo contig_mem_free((caddr_t)ldcp->tx_q_va, 23531991Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT)); 23541991Sheppo 23551991Sheppo if (ldcp->tstate & TS_RXQ_RDY) 23561991Sheppo contig_mem_free((caddr_t)ldcp->rx_q_va, 23571991Sheppo (ldcp->rx_q_entries << LDC_PACKET_SHIFT)); 23581991Sheppo 23592336Snarayan mutex_destroy(&ldcp->tx_lock); 23601991Sheppo mutex_destroy(&ldcp->lock); 23611991Sheppo 23621991Sheppo if (ldcp) 23631991Sheppo kmem_free(ldcp, sizeof (ldc_chan_t)); 23641991Sheppo 23651991Sheppo return (exit_val); 23661991Sheppo } 23671991Sheppo 23681991Sheppo /* 23691991Sheppo * Finalizes the LDC connection. It will return EBUSY if the 23701991Sheppo * channel is open. A ldc_close() has to be done prior to 23711991Sheppo * a ldc_fini operation. It frees TX/RX queues, associated 23721991Sheppo * with the channel 23731991Sheppo */ 23741991Sheppo int 23751991Sheppo ldc_fini(ldc_handle_t handle) 23761991Sheppo { 23771991Sheppo ldc_chan_t *ldcp; 23781991Sheppo ldc_chan_t *tmp_ldcp; 23791991Sheppo uint64_t id; 23801991Sheppo 23811991Sheppo if (handle == NULL) { 23821991Sheppo DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel handle\n"); 23831991Sheppo return (EINVAL); 23841991Sheppo } 23851991Sheppo ldcp = (ldc_chan_t *)handle; 23861991Sheppo id = ldcp->id; 23871991Sheppo 23881991Sheppo mutex_enter(&ldcp->lock); 23891991Sheppo 23902793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) > TS_INIT) { 23911991Sheppo DWARN(ldcp->id, "ldc_fini: (0x%llx) channel is open\n", 23921991Sheppo ldcp->id); 23931991Sheppo mutex_exit(&ldcp->lock); 23941991Sheppo return (EBUSY); 23951991Sheppo } 23961991Sheppo 23971991Sheppo /* Remove from the channel list */ 23981991Sheppo mutex_enter(&ldcssp->lock); 23991991Sheppo tmp_ldcp = ldcssp->chan_list; 24001991Sheppo if (tmp_ldcp == ldcp) { 24011991Sheppo ldcssp->chan_list = ldcp->next; 24021991Sheppo ldcp->next = NULL; 24031991Sheppo } else { 24041991Sheppo while (tmp_ldcp != NULL) { 24051991Sheppo if (tmp_ldcp->next == ldcp) { 24061991Sheppo tmp_ldcp->next = ldcp->next; 24071991Sheppo ldcp->next = NULL; 24081991Sheppo break; 24091991Sheppo } 24101991Sheppo tmp_ldcp = tmp_ldcp->next; 24111991Sheppo } 24121991Sheppo if (tmp_ldcp == NULL) { 24131991Sheppo DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel hdl\n"); 24141991Sheppo mutex_exit(&ldcssp->lock); 24151991Sheppo mutex_exit(&ldcp->lock); 24161991Sheppo return (EINVAL); 24171991Sheppo } 24181991Sheppo } 24191991Sheppo 24201991Sheppo ldcssp->channel_count--; 24211991Sheppo 24221991Sheppo mutex_exit(&ldcssp->lock); 24231991Sheppo 24241991Sheppo /* Free the map table for this channel */ 24251991Sheppo if (ldcp->mtbl) { 24261991Sheppo (void) hv_ldc_set_map_table(ldcp->id, NULL, NULL); 24272793Slm66018 if (ldcp->mtbl->contigmem) 24282793Slm66018 contig_mem_free(ldcp->mtbl->table, ldcp->mtbl->size); 24292793Slm66018 else 24302793Slm66018 kmem_free(ldcp->mtbl->table, ldcp->mtbl->size); 24311991Sheppo mutex_destroy(&ldcp->mtbl->lock); 24321991Sheppo kmem_free(ldcp->mtbl, sizeof (ldc_mtbl_t)); 24331991Sheppo } 24341991Sheppo 24351991Sheppo /* Destroy descriptor ring and memory handle list lock */ 24361991Sheppo mutex_destroy(&ldcp->exp_dlist_lock); 24371991Sheppo mutex_destroy(&ldcp->imp_dlist_lock); 24381991Sheppo mutex_destroy(&ldcp->mlist_lock); 24391991Sheppo 24401991Sheppo /* Free the stream buffer for STREAM_MODE */ 24411991Sheppo if (ldcp->mode == LDC_MODE_STREAM && ldcp->stream_bufferp) 24421991Sheppo kmem_free(ldcp->stream_bufferp, ldcp->mtu); 24431991Sheppo 24441991Sheppo /* Free the RX queue */ 24451991Sheppo contig_mem_free((caddr_t)ldcp->rx_q_va, 24461991Sheppo (ldcp->rx_q_entries << LDC_PACKET_SHIFT)); 24471991Sheppo ldcp->tstate &= ~TS_RXQ_RDY; 24481991Sheppo 24491991Sheppo /* Free the TX queue */ 24501991Sheppo contig_mem_free((caddr_t)ldcp->tx_q_va, 24511991Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT)); 24521991Sheppo ldcp->tstate &= ~TS_TXQ_RDY; 24531991Sheppo 24541991Sheppo mutex_exit(&ldcp->lock); 24551991Sheppo 24561991Sheppo /* Destroy mutex */ 24572336Snarayan mutex_destroy(&ldcp->tx_lock); 24581991Sheppo mutex_destroy(&ldcp->lock); 24591991Sheppo 24601991Sheppo /* free channel structure */ 24611991Sheppo kmem_free(ldcp, sizeof (ldc_chan_t)); 24621991Sheppo 24631991Sheppo D1(id, "ldc_fini: (0x%llx) channel finalized\n", id); 24641991Sheppo 24651991Sheppo return (0); 24661991Sheppo } 24671991Sheppo 24681991Sheppo /* 24691991Sheppo * Open the LDC channel for use. It registers the TX/RX queues 24701991Sheppo * with the Hypervisor. It also specifies the interrupt number 24711991Sheppo * and target CPU for this channel 24721991Sheppo */ 24731991Sheppo int 24741991Sheppo ldc_open(ldc_handle_t handle) 24751991Sheppo { 24761991Sheppo ldc_chan_t *ldcp; 24771991Sheppo int rv; 24781991Sheppo 24791991Sheppo if (handle == NULL) { 24801991Sheppo DWARN(DBG_ALL_LDCS, "ldc_open: invalid channel handle\n"); 24811991Sheppo return (EINVAL); 24821991Sheppo } 24831991Sheppo 24841991Sheppo ldcp = (ldc_chan_t *)handle; 24851991Sheppo 24861991Sheppo mutex_enter(&ldcp->lock); 24871991Sheppo 24881991Sheppo if (ldcp->tstate < TS_INIT) { 24891991Sheppo DWARN(ldcp->id, 24901991Sheppo "ldc_open: (0x%llx) channel not initialized\n", ldcp->id); 24911991Sheppo mutex_exit(&ldcp->lock); 24921991Sheppo return (EFAULT); 24931991Sheppo } 24942793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) >= TS_OPEN) { 24951991Sheppo DWARN(ldcp->id, 24961991Sheppo "ldc_open: (0x%llx) channel is already open\n", ldcp->id); 24971991Sheppo mutex_exit(&ldcp->lock); 24981991Sheppo return (EFAULT); 24991991Sheppo } 25001991Sheppo 25011991Sheppo /* 25021991Sheppo * Unregister/Register the tx queue with the hypervisor 25031991Sheppo */ 25041991Sheppo rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 25051991Sheppo if (rv) { 25061991Sheppo cmn_err(CE_WARN, 25071991Sheppo "ldc_open: (0x%lx) channel tx queue unconf failed\n", 25081991Sheppo ldcp->id); 25091991Sheppo mutex_exit(&ldcp->lock); 25101991Sheppo return (EIO); 25111991Sheppo } 25121991Sheppo 25131991Sheppo rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries); 25141991Sheppo if (rv) { 25151991Sheppo cmn_err(CE_WARN, 25161991Sheppo "ldc_open: (0x%lx) channel tx queue conf failed\n", 25171991Sheppo ldcp->id); 25181991Sheppo mutex_exit(&ldcp->lock); 25191991Sheppo return (EIO); 25201991Sheppo } 25211991Sheppo 25221991Sheppo D2(ldcp->id, "ldc_open: (0x%llx) registered tx queue with LDC\n", 25231991Sheppo ldcp->id); 25241991Sheppo 25251991Sheppo /* 25261991Sheppo * Unregister/Register the rx queue with the hypervisor 25271991Sheppo */ 25281991Sheppo rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 25291991Sheppo if (rv) { 25301991Sheppo cmn_err(CE_WARN, 25311991Sheppo "ldc_open: (0x%lx) channel rx queue unconf failed\n", 25321991Sheppo ldcp->id); 25331991Sheppo mutex_exit(&ldcp->lock); 25341991Sheppo return (EIO); 25351991Sheppo } 25361991Sheppo 25371991Sheppo rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra, ldcp->rx_q_entries); 25381991Sheppo if (rv) { 25391991Sheppo cmn_err(CE_WARN, 25401991Sheppo "ldc_open: (0x%lx) channel rx queue conf failed\n", 25411991Sheppo ldcp->id); 25421991Sheppo mutex_exit(&ldcp->lock); 25431991Sheppo return (EIO); 25441991Sheppo } 25451991Sheppo 25461991Sheppo D2(ldcp->id, "ldc_open: (0x%llx) registered rx queue with LDC\n", 25471991Sheppo ldcp->id); 25481991Sheppo 25491991Sheppo ldcp->tstate |= TS_QCONF_RDY; 25501991Sheppo 25511991Sheppo /* Register the channel with the channel nexus */ 25521991Sheppo rv = i_ldc_register_channel(ldcp); 25531991Sheppo if (rv && rv != EAGAIN) { 25541991Sheppo cmn_err(CE_WARN, 25551991Sheppo "ldc_open: (0x%lx) channel register failed\n", ldcp->id); 25561991Sheppo (void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 25571991Sheppo (void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 25581991Sheppo mutex_exit(&ldcp->lock); 25591991Sheppo return (EIO); 25601991Sheppo } 25611991Sheppo 25621991Sheppo /* mark channel in OPEN state */ 25631991Sheppo ldcp->status = LDC_OPEN; 25641991Sheppo 25651991Sheppo /* Read channel state */ 25661991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 25671991Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 25681991Sheppo if (rv) { 25691991Sheppo cmn_err(CE_WARN, 25701991Sheppo "ldc_open: (0x%lx) cannot read channel state\n", 25711991Sheppo ldcp->id); 25721991Sheppo (void) i_ldc_unregister_channel(ldcp); 25731991Sheppo (void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 25741991Sheppo (void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 25751991Sheppo mutex_exit(&ldcp->lock); 25761991Sheppo return (EIO); 25771991Sheppo } 25781991Sheppo 25791991Sheppo /* 25801991Sheppo * set the ACKd head to current head location for reliable & 25811991Sheppo * streaming mode 25821991Sheppo */ 25831991Sheppo ldcp->tx_ackd_head = ldcp->tx_head; 25841991Sheppo 25851991Sheppo /* mark channel ready if HV report link is UP (peer alloc'd Rx queue) */ 25861991Sheppo if (ldcp->link_state == LDC_CHANNEL_UP || 25871991Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 25881991Sheppo ldcp->tstate |= TS_LINK_READY; 25891991Sheppo ldcp->status = LDC_READY; 25901991Sheppo } 25911991Sheppo 25921991Sheppo /* 25931991Sheppo * if channel is being opened in RAW mode - no handshake is needed 25941991Sheppo * switch the channel READY and UP state 25951991Sheppo */ 25961991Sheppo if (ldcp->mode == LDC_MODE_RAW) { 25971991Sheppo ldcp->tstate = TS_UP; /* set bits associated with LDC UP */ 25981991Sheppo ldcp->status = LDC_UP; 25991991Sheppo } 26001991Sheppo 26011991Sheppo mutex_exit(&ldcp->lock); 26021991Sheppo 26031991Sheppo /* 26041991Sheppo * Increment number of open channels 26051991Sheppo */ 26061991Sheppo mutex_enter(&ldcssp->lock); 26071991Sheppo ldcssp->channels_open++; 26081991Sheppo mutex_exit(&ldcssp->lock); 26091991Sheppo 26103010Slm66018 D1(ldcp->id, 26112793Slm66018 "ldc_open: (0x%llx) channel (0x%p) open for use " 26122793Slm66018 "(tstate=0x%x, status=0x%x)\n", 26132793Slm66018 ldcp->id, ldcp, ldcp->tstate, ldcp->status); 26141991Sheppo 26151991Sheppo return (0); 26161991Sheppo } 26171991Sheppo 26181991Sheppo /* 26191991Sheppo * Close the LDC connection. It will return EBUSY if there 26201991Sheppo * are memory segments or descriptor rings either bound to or 26211991Sheppo * mapped over the channel 26221991Sheppo */ 26231991Sheppo int 26241991Sheppo ldc_close(ldc_handle_t handle) 26251991Sheppo { 26261991Sheppo ldc_chan_t *ldcp; 26272336Snarayan int rv = 0, retries = 0; 26281991Sheppo boolean_t chk_done = B_FALSE; 26291991Sheppo 26301991Sheppo if (handle == NULL) { 26311991Sheppo DWARN(DBG_ALL_LDCS, "ldc_close: invalid channel handle\n"); 26321991Sheppo return (EINVAL); 26331991Sheppo } 26341991Sheppo ldcp = (ldc_chan_t *)handle; 26351991Sheppo 26361991Sheppo mutex_enter(&ldcp->lock); 26371991Sheppo 26381991Sheppo /* return error if channel is not open */ 26392793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) < TS_OPEN) { 26401991Sheppo DWARN(ldcp->id, 26411991Sheppo "ldc_close: (0x%llx) channel is not open\n", ldcp->id); 26421991Sheppo mutex_exit(&ldcp->lock); 26431991Sheppo return (EFAULT); 26441991Sheppo } 26451991Sheppo 26461991Sheppo /* if any memory handles, drings, are bound or mapped cannot close */ 26471991Sheppo if (ldcp->mhdl_list != NULL) { 26481991Sheppo DWARN(ldcp->id, 26491991Sheppo "ldc_close: (0x%llx) channel has bound memory handles\n", 26501991Sheppo ldcp->id); 26511991Sheppo mutex_exit(&ldcp->lock); 26521991Sheppo return (EBUSY); 26531991Sheppo } 26541991Sheppo if (ldcp->exp_dring_list != NULL) { 26551991Sheppo DWARN(ldcp->id, 26561991Sheppo "ldc_close: (0x%llx) channel has bound descriptor rings\n", 26571991Sheppo ldcp->id); 26581991Sheppo mutex_exit(&ldcp->lock); 26591991Sheppo return (EBUSY); 26601991Sheppo } 26611991Sheppo if (ldcp->imp_dring_list != NULL) { 26621991Sheppo DWARN(ldcp->id, 26631991Sheppo "ldc_close: (0x%llx) channel has mapped descriptor rings\n", 26641991Sheppo ldcp->id); 26651991Sheppo mutex_exit(&ldcp->lock); 26661991Sheppo return (EBUSY); 26671991Sheppo } 26681991Sheppo 2669*3151Ssg70180 if (ldcp->cb_inprogress) { 2670*3151Ssg70180 DWARN(ldcp->id, "ldc_close: (0x%llx) callback active\n", 2671*3151Ssg70180 ldcp->id); 2672*3151Ssg70180 mutex_exit(&ldcp->lock); 2673*3151Ssg70180 return (EWOULDBLOCK); 2674*3151Ssg70180 } 2675*3151Ssg70180 26762336Snarayan /* Obtain Tx lock */ 26772336Snarayan mutex_enter(&ldcp->tx_lock); 26782336Snarayan 26791991Sheppo /* 26801991Sheppo * Wait for pending transmits to complete i.e Tx queue to drain 26811991Sheppo * if there are pending pkts - wait 1 ms and retry again 26821991Sheppo */ 26831991Sheppo for (;;) { 26841991Sheppo 26851991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 26861991Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 26871991Sheppo if (rv) { 26881991Sheppo cmn_err(CE_WARN, 26891991Sheppo "ldc_close: (0x%lx) cannot read qptrs\n", ldcp->id); 26902336Snarayan mutex_exit(&ldcp->tx_lock); 26911991Sheppo mutex_exit(&ldcp->lock); 26921991Sheppo return (EIO); 26931991Sheppo } 26941991Sheppo 26951991Sheppo if (ldcp->tx_head == ldcp->tx_tail || 26961991Sheppo ldcp->link_state != LDC_CHANNEL_UP) { 26971991Sheppo break; 26981991Sheppo } 26991991Sheppo 27001991Sheppo if (chk_done) { 27011991Sheppo DWARN(ldcp->id, 27021991Sheppo "ldc_close: (0x%llx) Tx queue drain timeout\n", 27031991Sheppo ldcp->id); 27041991Sheppo break; 27051991Sheppo } 27061991Sheppo 27071991Sheppo /* wait for one ms and try again */ 27081991Sheppo delay(drv_usectohz(1000)); 27091991Sheppo chk_done = B_TRUE; 27101991Sheppo } 27111991Sheppo 27121991Sheppo /* 27132841Snarayan * Drain the Tx and Rx queues as we are closing the 27142841Snarayan * channel. We dont care about any pending packets. 27152841Snarayan * We have to also drain the queue prior to clearing 27162841Snarayan * pending interrupts, otherwise the HV will trigger 27172841Snarayan * an interrupt the moment the interrupt state is 27182841Snarayan * cleared. 27192793Slm66018 */ 27202793Slm66018 (void) i_ldc_txq_reconf(ldcp); 27212841Snarayan (void) i_ldc_rxq_drain(ldcp); 27222793Slm66018 27232793Slm66018 /* 27241991Sheppo * Unregister the channel with the nexus 27251991Sheppo */ 27262336Snarayan while ((rv = i_ldc_unregister_channel(ldcp)) != 0) { 27272336Snarayan 27282336Snarayan mutex_exit(&ldcp->tx_lock); 27291991Sheppo mutex_exit(&ldcp->lock); 27302336Snarayan 27312336Snarayan /* if any error other than EAGAIN return back */ 27322841Snarayan if (rv != EAGAIN || retries >= ldc_max_retries) { 27332336Snarayan cmn_err(CE_WARN, 27342336Snarayan "ldc_close: (0x%lx) unregister failed, %d\n", 27352336Snarayan ldcp->id, rv); 27362336Snarayan return (rv); 27372336Snarayan } 27382336Snarayan 27392336Snarayan /* 27402336Snarayan * As there could be pending interrupts we need 27412336Snarayan * to wait and try again 27422336Snarayan */ 2743*3151Ssg70180 drv_usecwait(ldc_close_delay); 27442336Snarayan mutex_enter(&ldcp->lock); 27452336Snarayan mutex_enter(&ldcp->tx_lock); 27462336Snarayan retries++; 27471991Sheppo } 27481991Sheppo 27491991Sheppo /* 27501991Sheppo * Unregister queues 27511991Sheppo */ 27521991Sheppo rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 27531991Sheppo if (rv) { 27541991Sheppo cmn_err(CE_WARN, 27551991Sheppo "ldc_close: (0x%lx) channel TX queue unconf failed\n", 27561991Sheppo ldcp->id); 27572336Snarayan mutex_exit(&ldcp->tx_lock); 27581991Sheppo mutex_exit(&ldcp->lock); 27591991Sheppo return (EIO); 27601991Sheppo } 27611991Sheppo rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 27621991Sheppo if (rv) { 27631991Sheppo cmn_err(CE_WARN, 27641991Sheppo "ldc_close: (0x%lx) channel RX queue unconf failed\n", 27651991Sheppo ldcp->id); 27662336Snarayan mutex_exit(&ldcp->tx_lock); 27671991Sheppo mutex_exit(&ldcp->lock); 27681991Sheppo return (EIO); 27691991Sheppo } 27701991Sheppo 27711991Sheppo ldcp->tstate &= ~TS_QCONF_RDY; 27721991Sheppo 27731991Sheppo /* Reset channel state information */ 27741991Sheppo i_ldc_reset_state(ldcp); 27751991Sheppo 27761991Sheppo /* Mark channel as down and in initialized state */ 27771991Sheppo ldcp->tx_ackd_head = 0; 27781991Sheppo ldcp->tx_head = 0; 27792793Slm66018 ldcp->tstate = TS_IN_RESET|TS_INIT; 27801991Sheppo ldcp->status = LDC_INIT; 27811991Sheppo 27822336Snarayan mutex_exit(&ldcp->tx_lock); 27831991Sheppo mutex_exit(&ldcp->lock); 27841991Sheppo 27851991Sheppo /* Decrement number of open channels */ 27861991Sheppo mutex_enter(&ldcssp->lock); 27871991Sheppo ldcssp->channels_open--; 27881991Sheppo mutex_exit(&ldcssp->lock); 27891991Sheppo 27901991Sheppo D1(ldcp->id, "ldc_close: (0x%llx) channel closed\n", ldcp->id); 27911991Sheppo 27921991Sheppo return (0); 27931991Sheppo } 27941991Sheppo 27951991Sheppo /* 27961991Sheppo * Register channel callback 27971991Sheppo */ 27981991Sheppo int 27991991Sheppo ldc_reg_callback(ldc_handle_t handle, 28001991Sheppo uint_t(*cb)(uint64_t event, caddr_t arg), caddr_t arg) 28011991Sheppo { 28021991Sheppo ldc_chan_t *ldcp; 28031991Sheppo 28041991Sheppo if (handle == NULL) { 28051991Sheppo DWARN(DBG_ALL_LDCS, 28061991Sheppo "ldc_reg_callback: invalid channel handle\n"); 28071991Sheppo return (EINVAL); 28081991Sheppo } 28091991Sheppo if (((uint64_t)cb) < KERNELBASE) { 28101991Sheppo DWARN(DBG_ALL_LDCS, "ldc_reg_callback: invalid callback\n"); 28111991Sheppo return (EINVAL); 28121991Sheppo } 28131991Sheppo ldcp = (ldc_chan_t *)handle; 28141991Sheppo 28151991Sheppo mutex_enter(&ldcp->lock); 28161991Sheppo 28171991Sheppo if (ldcp->cb) { 28181991Sheppo DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback exists\n", 28191991Sheppo ldcp->id); 28201991Sheppo mutex_exit(&ldcp->lock); 28211991Sheppo return (EIO); 28221991Sheppo } 28231991Sheppo if (ldcp->cb_inprogress) { 28241991Sheppo DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback active\n", 28251991Sheppo ldcp->id); 28261991Sheppo mutex_exit(&ldcp->lock); 28271991Sheppo return (EWOULDBLOCK); 28281991Sheppo } 28291991Sheppo 28301991Sheppo ldcp->cb = cb; 28311991Sheppo ldcp->cb_arg = arg; 28321991Sheppo ldcp->cb_enabled = B_TRUE; 28331991Sheppo 28341991Sheppo D1(ldcp->id, 28351991Sheppo "ldc_reg_callback: (0x%llx) registered callback for channel\n", 28361991Sheppo ldcp->id); 28371991Sheppo 28381991Sheppo mutex_exit(&ldcp->lock); 28391991Sheppo 28401991Sheppo return (0); 28411991Sheppo } 28421991Sheppo 28431991Sheppo /* 28441991Sheppo * Unregister channel callback 28451991Sheppo */ 28461991Sheppo int 28471991Sheppo ldc_unreg_callback(ldc_handle_t handle) 28481991Sheppo { 28491991Sheppo ldc_chan_t *ldcp; 28501991Sheppo 28511991Sheppo if (handle == NULL) { 28521991Sheppo DWARN(DBG_ALL_LDCS, 28531991Sheppo "ldc_unreg_callback: invalid channel handle\n"); 28541991Sheppo return (EINVAL); 28551991Sheppo } 28561991Sheppo ldcp = (ldc_chan_t *)handle; 28571991Sheppo 28581991Sheppo mutex_enter(&ldcp->lock); 28591991Sheppo 28601991Sheppo if (ldcp->cb == NULL) { 28611991Sheppo DWARN(ldcp->id, 28621991Sheppo "ldc_unreg_callback: (0x%llx) no callback exists\n", 28631991Sheppo ldcp->id); 28641991Sheppo mutex_exit(&ldcp->lock); 28651991Sheppo return (EIO); 28661991Sheppo } 28671991Sheppo if (ldcp->cb_inprogress) { 28681991Sheppo DWARN(ldcp->id, 28691991Sheppo "ldc_unreg_callback: (0x%llx) callback active\n", 28701991Sheppo ldcp->id); 28711991Sheppo mutex_exit(&ldcp->lock); 28721991Sheppo return (EWOULDBLOCK); 28731991Sheppo } 28741991Sheppo 28751991Sheppo ldcp->cb = NULL; 28761991Sheppo ldcp->cb_arg = NULL; 28771991Sheppo ldcp->cb_enabled = B_FALSE; 28781991Sheppo 28791991Sheppo D1(ldcp->id, 28801991Sheppo "ldc_unreg_callback: (0x%llx) unregistered callback for channel\n", 28811991Sheppo ldcp->id); 28821991Sheppo 28831991Sheppo mutex_exit(&ldcp->lock); 28841991Sheppo 28851991Sheppo return (0); 28861991Sheppo } 28871991Sheppo 28881991Sheppo 28891991Sheppo /* 28901991Sheppo * Bring a channel up by initiating a handshake with the peer 28911991Sheppo * This call is asynchronous. It will complete at a later point 28921991Sheppo * in time when the peer responds back with an RTR. 28931991Sheppo */ 28941991Sheppo int 28951991Sheppo ldc_up(ldc_handle_t handle) 28961991Sheppo { 28971991Sheppo int rv; 28981991Sheppo ldc_chan_t *ldcp; 28991991Sheppo ldc_msg_t *ldcmsg; 29002793Slm66018 uint64_t tx_tail, tstate; 29011991Sheppo 29021991Sheppo if (handle == NULL) { 29031991Sheppo DWARN(DBG_ALL_LDCS, "ldc_up: invalid channel handle\n"); 29041991Sheppo return (EINVAL); 29051991Sheppo } 29061991Sheppo ldcp = (ldc_chan_t *)handle; 29071991Sheppo 29081991Sheppo mutex_enter(&ldcp->lock); 29091991Sheppo 29102793Slm66018 D1(ldcp->id, "ldc_up: (0x%llx) doing channel UP\n", ldcp->id); 29112793Slm66018 29122793Slm66018 /* clear the reset state */ 29132793Slm66018 tstate = ldcp->tstate; 29142793Slm66018 ldcp->tstate &= ~TS_IN_RESET; 29152793Slm66018 29161991Sheppo if (ldcp->tstate == TS_UP) { 29172793Slm66018 DWARN(ldcp->id, 29181991Sheppo "ldc_up: (0x%llx) channel is already in UP state\n", 29191991Sheppo ldcp->id); 29202793Slm66018 29212793Slm66018 /* mark channel as up */ 29222793Slm66018 ldcp->status = LDC_UP; 29232793Slm66018 29242793Slm66018 /* 29252793Slm66018 * if channel was in reset state and there was 29262793Slm66018 * pending data clear interrupt state. this will 29272793Slm66018 * trigger an interrupt, causing the RX handler to 29282793Slm66018 * to invoke the client's callback 29292793Slm66018 */ 29302793Slm66018 if ((tstate & TS_IN_RESET) && 29312793Slm66018 ldcp->rx_intr_state == LDC_INTR_PEND) { 29323010Slm66018 D1(ldcp->id, 29332793Slm66018 "ldc_up: (0x%llx) channel has pending data, " 29342793Slm66018 "clearing interrupt\n", ldcp->id); 29352793Slm66018 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 29362793Slm66018 } 29372793Slm66018 29381991Sheppo mutex_exit(&ldcp->lock); 29391991Sheppo return (0); 29401991Sheppo } 29411991Sheppo 29421991Sheppo /* if the channel is in RAW mode - mark it as UP, if READY */ 29431991Sheppo if (ldcp->mode == LDC_MODE_RAW && ldcp->tstate >= TS_READY) { 29441991Sheppo ldcp->tstate = TS_UP; 29451991Sheppo mutex_exit(&ldcp->lock); 29461991Sheppo return (0); 29471991Sheppo } 29481991Sheppo 29491991Sheppo /* Don't start another handshake if there is one in progress */ 29501991Sheppo if (ldcp->hstate) { 29512793Slm66018 D1(ldcp->id, 29521991Sheppo "ldc_up: (0x%llx) channel handshake in progress\n", 29531991Sheppo ldcp->id); 29541991Sheppo mutex_exit(&ldcp->lock); 29551991Sheppo return (0); 29561991Sheppo } 29571991Sheppo 29582336Snarayan mutex_enter(&ldcp->tx_lock); 29592336Snarayan 29601991Sheppo /* get the current tail for the LDC msg */ 29611991Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 29621991Sheppo if (rv) { 29633010Slm66018 D1(ldcp->id, "ldc_up: (0x%llx) cannot initiate handshake\n", 29641991Sheppo ldcp->id); 29652336Snarayan mutex_exit(&ldcp->tx_lock); 29661991Sheppo mutex_exit(&ldcp->lock); 29671991Sheppo return (ECONNREFUSED); 29681991Sheppo } 29691991Sheppo 29701991Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 29711991Sheppo ZERO_PKT(ldcmsg); 29721991Sheppo 29731991Sheppo ldcmsg->type = LDC_CTRL; 29741991Sheppo ldcmsg->stype = LDC_INFO; 29751991Sheppo ldcmsg->ctrl = LDC_VER; 29761991Sheppo ldcp->next_vidx = 0; 29771991Sheppo bcopy(&ldc_versions[0], ldcmsg->udata, sizeof (ldc_versions[0])); 29781991Sheppo 29791991Sheppo DUMP_LDC_PKT(ldcp, "ldc_up snd ver", (uint64_t)ldcmsg); 29801991Sheppo 29811991Sheppo /* initiate the send by calling into HV and set the new tail */ 29821991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 29831991Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 29841991Sheppo 29851991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 29861991Sheppo if (rv) { 29871991Sheppo DWARN(ldcp->id, 29881991Sheppo "ldc_up: (0x%llx) cannot initiate handshake rv=%d\n", 29891991Sheppo ldcp->id, rv); 29902336Snarayan mutex_exit(&ldcp->tx_lock); 29911991Sheppo mutex_exit(&ldcp->lock); 29921991Sheppo return (rv); 29931991Sheppo } 29941991Sheppo 29952032Slm66018 ldcp->hstate |= TS_SENT_VER; 29961991Sheppo ldcp->tx_tail = tx_tail; 29971991Sheppo D1(ldcp->id, "ldc_up: (0x%llx) channel up initiated\n", ldcp->id); 29981991Sheppo 29992336Snarayan mutex_exit(&ldcp->tx_lock); 30001991Sheppo mutex_exit(&ldcp->lock); 30011991Sheppo 30021991Sheppo return (rv); 30031991Sheppo } 30041991Sheppo 30051991Sheppo 30061991Sheppo /* 30072410Slm66018 * Bring a channel down by resetting its state and queues 30081991Sheppo */ 30091991Sheppo int 30102410Slm66018 ldc_down(ldc_handle_t handle) 30111991Sheppo { 30121991Sheppo ldc_chan_t *ldcp; 30131991Sheppo 30141991Sheppo if (handle == NULL) { 30152410Slm66018 DWARN(DBG_ALL_LDCS, "ldc_down: invalid channel handle\n"); 30161991Sheppo return (EINVAL); 30171991Sheppo } 30181991Sheppo ldcp = (ldc_chan_t *)handle; 30191991Sheppo mutex_enter(&ldcp->lock); 30202336Snarayan mutex_enter(&ldcp->tx_lock); 30212793Slm66018 i_ldc_reset(ldcp, B_TRUE); 30222336Snarayan mutex_exit(&ldcp->tx_lock); 30231991Sheppo mutex_exit(&ldcp->lock); 30241991Sheppo 30251991Sheppo return (0); 30261991Sheppo } 30271991Sheppo 30281991Sheppo /* 30291991Sheppo * Get the current channel status 30301991Sheppo */ 30311991Sheppo int 30321991Sheppo ldc_status(ldc_handle_t handle, ldc_status_t *status) 30331991Sheppo { 30341991Sheppo ldc_chan_t *ldcp; 30351991Sheppo 30361991Sheppo if (handle == NULL || status == NULL) { 30371991Sheppo DWARN(DBG_ALL_LDCS, "ldc_status: invalid argument\n"); 30381991Sheppo return (EINVAL); 30391991Sheppo } 30401991Sheppo ldcp = (ldc_chan_t *)handle; 30411991Sheppo 30421991Sheppo *status = ((ldc_chan_t *)handle)->status; 30431991Sheppo 30443010Slm66018 D1(ldcp->id, 30451991Sheppo "ldc_status: (0x%llx) returned status %d\n", ldcp->id, *status); 30461991Sheppo return (0); 30471991Sheppo } 30481991Sheppo 30491991Sheppo 30501991Sheppo /* 30511991Sheppo * Set the channel's callback mode - enable/disable callbacks 30521991Sheppo */ 30531991Sheppo int 30541991Sheppo ldc_set_cb_mode(ldc_handle_t handle, ldc_cb_mode_t cmode) 30551991Sheppo { 30561991Sheppo ldc_chan_t *ldcp; 30571991Sheppo 30581991Sheppo if (handle == NULL) { 30591991Sheppo DWARN(DBG_ALL_LDCS, 30601991Sheppo "ldc_set_intr_mode: invalid channel handle\n"); 30611991Sheppo return (EINVAL); 30621991Sheppo } 30631991Sheppo ldcp = (ldc_chan_t *)handle; 30641991Sheppo 30651991Sheppo /* 30661991Sheppo * Record no callbacks should be invoked 30671991Sheppo */ 30681991Sheppo mutex_enter(&ldcp->lock); 30691991Sheppo 30701991Sheppo switch (cmode) { 30711991Sheppo case LDC_CB_DISABLE: 30721991Sheppo if (!ldcp->cb_enabled) { 30731991Sheppo DWARN(ldcp->id, 30741991Sheppo "ldc_set_cb_mode: (0x%llx) callbacks disabled\n", 30751991Sheppo ldcp->id); 30761991Sheppo break; 30771991Sheppo } 30781991Sheppo ldcp->cb_enabled = B_FALSE; 30791991Sheppo 30801991Sheppo D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) disabled callbacks\n", 30811991Sheppo ldcp->id); 30821991Sheppo break; 30831991Sheppo 30841991Sheppo case LDC_CB_ENABLE: 30851991Sheppo if (ldcp->cb_enabled) { 30861991Sheppo DWARN(ldcp->id, 30871991Sheppo "ldc_set_cb_mode: (0x%llx) callbacks enabled\n", 30881991Sheppo ldcp->id); 30891991Sheppo break; 30901991Sheppo } 30911991Sheppo ldcp->cb_enabled = B_TRUE; 30921991Sheppo 30931991Sheppo D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) enabled callbacks\n", 30941991Sheppo ldcp->id); 30951991Sheppo break; 30961991Sheppo } 30971991Sheppo 30981991Sheppo mutex_exit(&ldcp->lock); 30991991Sheppo 31001991Sheppo return (0); 31011991Sheppo } 31021991Sheppo 31031991Sheppo /* 31041991Sheppo * Check to see if there are packets on the incoming queue 31052410Slm66018 * Will return hasdata = B_FALSE if there are no packets 31061991Sheppo */ 31071991Sheppo int 31082410Slm66018 ldc_chkq(ldc_handle_t handle, boolean_t *hasdata) 31091991Sheppo { 31101991Sheppo int rv; 31111991Sheppo uint64_t rx_head, rx_tail; 31121991Sheppo ldc_chan_t *ldcp; 31131991Sheppo 31141991Sheppo if (handle == NULL) { 31151991Sheppo DWARN(DBG_ALL_LDCS, "ldc_chkq: invalid channel handle\n"); 31161991Sheppo return (EINVAL); 31171991Sheppo } 31181991Sheppo ldcp = (ldc_chan_t *)handle; 31191991Sheppo 31202410Slm66018 *hasdata = B_FALSE; 31211991Sheppo 31221991Sheppo mutex_enter(&ldcp->lock); 31231991Sheppo 31241991Sheppo if (ldcp->tstate != TS_UP) { 31251991Sheppo D1(ldcp->id, 31261991Sheppo "ldc_chkq: (0x%llx) channel is not up\n", ldcp->id); 31271991Sheppo mutex_exit(&ldcp->lock); 31281991Sheppo return (ECONNRESET); 31291991Sheppo } 31301991Sheppo 31311991Sheppo /* Read packet(s) from the queue */ 31321991Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 31331991Sheppo &ldcp->link_state); 31341991Sheppo if (rv != 0) { 31351991Sheppo cmn_err(CE_WARN, 31361991Sheppo "ldc_chkq: (0x%lx) unable to read queue ptrs", ldcp->id); 31371991Sheppo mutex_exit(&ldcp->lock); 31381991Sheppo return (EIO); 31391991Sheppo } 31401991Sheppo /* reset the channel state if the channel went down */ 31411991Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN || 31421991Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 31432336Snarayan mutex_enter(&ldcp->tx_lock); 31442793Slm66018 i_ldc_reset(ldcp, B_FALSE); 31452336Snarayan mutex_exit(&ldcp->tx_lock); 31461991Sheppo mutex_exit(&ldcp->lock); 31471991Sheppo return (ECONNRESET); 31481991Sheppo } 31491991Sheppo 31502531Snarayan if ((rx_head != rx_tail) || 31512531Snarayan (ldcp->mode == LDC_MODE_STREAM && ldcp->stream_remains > 0)) { 31522531Snarayan D1(ldcp->id, 31532531Snarayan "ldc_chkq: (0x%llx) queue has pkt(s) or buffered data\n", 31542531Snarayan ldcp->id); 31552410Slm66018 *hasdata = B_TRUE; 31561991Sheppo } 31571991Sheppo 31581991Sheppo mutex_exit(&ldcp->lock); 31591991Sheppo 31601991Sheppo return (0); 31611991Sheppo } 31621991Sheppo 31631991Sheppo 31641991Sheppo /* 31651991Sheppo * Read 'size' amount of bytes or less. If incoming buffer 31661991Sheppo * is more than 'size', ENOBUFS is returned. 31671991Sheppo * 31681991Sheppo * On return, size contains the number of bytes read. 31691991Sheppo */ 31701991Sheppo int 31711991Sheppo ldc_read(ldc_handle_t handle, caddr_t bufp, size_t *sizep) 31721991Sheppo { 31731991Sheppo ldc_chan_t *ldcp; 31741991Sheppo uint64_t rx_head = 0, rx_tail = 0; 31751991Sheppo int rv = 0, exit_val; 31761991Sheppo 31771991Sheppo if (handle == NULL) { 31781991Sheppo DWARN(DBG_ALL_LDCS, "ldc_read: invalid channel handle\n"); 31791991Sheppo return (EINVAL); 31801991Sheppo } 31811991Sheppo 31821991Sheppo ldcp = (ldc_chan_t *)handle; 31831991Sheppo 31841991Sheppo /* channel lock */ 31851991Sheppo mutex_enter(&ldcp->lock); 31861991Sheppo 31871991Sheppo if (ldcp->tstate != TS_UP) { 31881991Sheppo DWARN(ldcp->id, 31891991Sheppo "ldc_read: (0x%llx) channel is not in UP state\n", 31901991Sheppo ldcp->id); 31911991Sheppo exit_val = ECONNRESET; 31921991Sheppo } else { 31931991Sheppo exit_val = ldcp->read_p(ldcp, bufp, sizep); 31941991Sheppo } 31951991Sheppo 31961991Sheppo /* 31971991Sheppo * if queue has been drained - clear interrupt 31981991Sheppo */ 31991991Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 32001991Sheppo &ldcp->link_state); 32013010Slm66018 if (rv != 0) { 32023010Slm66018 cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs", 32033010Slm66018 ldcp->id); 32043010Slm66018 mutex_enter(&ldcp->tx_lock); 32053010Slm66018 i_ldc_reset(ldcp, B_TRUE); 32063010Slm66018 mutex_exit(&ldcp->tx_lock); 32073010Slm66018 return (ECONNRESET); 32083010Slm66018 } 32092793Slm66018 32102793Slm66018 if (exit_val == 0) { 32112793Slm66018 if (ldcp->link_state == LDC_CHANNEL_DOWN || 32122793Slm66018 ldcp->link_state == LDC_CHANNEL_RESET) { 32132793Slm66018 mutex_enter(&ldcp->tx_lock); 32142793Slm66018 i_ldc_reset(ldcp, B_FALSE); 32152793Slm66018 exit_val = ECONNRESET; 32162793Slm66018 mutex_exit(&ldcp->tx_lock); 32172793Slm66018 } 32182793Slm66018 if ((rv == 0) && 32192793Slm66018 (ldcp->rx_intr_state == LDC_INTR_PEND) && 32202793Slm66018 (rx_head == rx_tail)) { 32212793Slm66018 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 32222793Slm66018 } 32231991Sheppo } 32241991Sheppo 32251991Sheppo mutex_exit(&ldcp->lock); 32261991Sheppo return (exit_val); 32271991Sheppo } 32281991Sheppo 32291991Sheppo /* 32301991Sheppo * Basic raw mondo read - 32311991Sheppo * no interpretation of mondo contents at all. 32321991Sheppo * 32331991Sheppo * Enter and exit with ldcp->lock held by caller 32341991Sheppo */ 32351991Sheppo static int 32361991Sheppo i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep) 32371991Sheppo { 32381991Sheppo uint64_t q_size_mask; 32391991Sheppo ldc_msg_t *msgp; 32401991Sheppo uint8_t *msgbufp; 32411991Sheppo int rv = 0, space; 32421991Sheppo uint64_t rx_head, rx_tail; 32431991Sheppo 32441991Sheppo space = *sizep; 32451991Sheppo 32461991Sheppo if (space < LDC_PAYLOAD_SIZE_RAW) 32471991Sheppo return (ENOBUFS); 32481991Sheppo 32491991Sheppo ASSERT(mutex_owned(&ldcp->lock)); 32501991Sheppo 32511991Sheppo /* compute mask for increment */ 32521991Sheppo q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT; 32531991Sheppo 32541991Sheppo /* 32551991Sheppo * Read packet(s) from the queue 32561991Sheppo */ 32571991Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 32581991Sheppo &ldcp->link_state); 32591991Sheppo if (rv != 0) { 32601991Sheppo cmn_err(CE_WARN, 32611991Sheppo "ldc_read_raw: (0x%lx) unable to read queue ptrs", 32621991Sheppo ldcp->id); 32631991Sheppo return (EIO); 32641991Sheppo } 32651991Sheppo D1(ldcp->id, "ldc_read_raw: (0x%llx) rxh=0x%llx," 32661991Sheppo " rxt=0x%llx, st=0x%llx\n", 32671991Sheppo ldcp->id, rx_head, rx_tail, ldcp->link_state); 32681991Sheppo 32691991Sheppo /* reset the channel state if the channel went down */ 32702793Slm66018 if (ldcp->link_state == LDC_CHANNEL_DOWN || 32712793Slm66018 ldcp->link_state == LDC_CHANNEL_RESET) { 32722336Snarayan mutex_enter(&ldcp->tx_lock); 32732793Slm66018 i_ldc_reset(ldcp, B_FALSE); 32742336Snarayan mutex_exit(&ldcp->tx_lock); 32751991Sheppo return (ECONNRESET); 32761991Sheppo } 32771991Sheppo 32781991Sheppo /* 32791991Sheppo * Check for empty queue 32801991Sheppo */ 32811991Sheppo if (rx_head == rx_tail) { 32821991Sheppo *sizep = 0; 32831991Sheppo return (0); 32841991Sheppo } 32851991Sheppo 32861991Sheppo /* get the message */ 32871991Sheppo msgp = (ldc_msg_t *)(ldcp->rx_q_va + rx_head); 32881991Sheppo 32891991Sheppo /* if channel is in RAW mode, copy data and return */ 32901991Sheppo msgbufp = (uint8_t *)&(msgp->raw[0]); 32911991Sheppo 32921991Sheppo bcopy(msgbufp, target_bufp, LDC_PAYLOAD_SIZE_RAW); 32931991Sheppo 32941991Sheppo DUMP_PAYLOAD(ldcp->id, msgbufp); 32951991Sheppo 32961991Sheppo *sizep = LDC_PAYLOAD_SIZE_RAW; 32971991Sheppo 32981991Sheppo rx_head = (rx_head + LDC_PACKET_SIZE) & q_size_mask; 32992032Slm66018 rv = i_ldc_set_rx_head(ldcp, rx_head); 33001991Sheppo 33011991Sheppo return (rv); 33021991Sheppo } 33031991Sheppo 33041991Sheppo /* 33051991Sheppo * Process LDC mondos to build larger packets 33061991Sheppo * with either un-reliable or reliable delivery. 33071991Sheppo * 33081991Sheppo * Enter and exit with ldcp->lock held by caller 33091991Sheppo */ 33101991Sheppo static int 33111991Sheppo i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep) 33121991Sheppo { 33131991Sheppo int rv = 0; 33141991Sheppo uint64_t rx_head = 0, rx_tail = 0; 33151991Sheppo uint64_t curr_head = 0; 33161991Sheppo ldc_msg_t *msg; 33171991Sheppo caddr_t target; 33181991Sheppo size_t len = 0, bytes_read = 0; 33192032Slm66018 int retries = 0; 33201991Sheppo uint64_t q_size_mask; 33212336Snarayan uint64_t first_fragment = 0; 33221991Sheppo 33231991Sheppo target = target_bufp; 33241991Sheppo 33251991Sheppo ASSERT(mutex_owned(&ldcp->lock)); 33261991Sheppo 33272793Slm66018 /* check if the buffer and size are valid */ 33282793Slm66018 if (target_bufp == NULL || *sizep == 0) { 33292793Slm66018 DWARN(ldcp->id, "ldc_read: (0x%llx) invalid buffer/size\n", 33302793Slm66018 ldcp->id); 33312793Slm66018 return (EINVAL); 33322793Slm66018 } 33332793Slm66018 33341991Sheppo /* compute mask for increment */ 33351991Sheppo q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT; 33361991Sheppo 33371991Sheppo /* 33381991Sheppo * Read packet(s) from the queue 33391991Sheppo */ 33401991Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &curr_head, &rx_tail, 33411991Sheppo &ldcp->link_state); 33421991Sheppo if (rv != 0) { 33432793Slm66018 cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs", 33441991Sheppo ldcp->id); 33452793Slm66018 mutex_enter(&ldcp->tx_lock); 33462793Slm66018 i_ldc_reset(ldcp, B_TRUE); 33472793Slm66018 mutex_exit(&ldcp->tx_lock); 33482793Slm66018 return (ECONNRESET); 33491991Sheppo } 33501991Sheppo D1(ldcp->id, "ldc_read: (0x%llx) chd=0x%llx, tl=0x%llx, st=0x%llx\n", 33511991Sheppo ldcp->id, curr_head, rx_tail, ldcp->link_state); 33521991Sheppo 33531991Sheppo /* reset the channel state if the channel went down */ 33542793Slm66018 if (ldcp->link_state != LDC_CHANNEL_UP) 33552793Slm66018 goto channel_is_reset; 33561991Sheppo 33571991Sheppo for (;;) { 33581991Sheppo 33591991Sheppo if (curr_head == rx_tail) { 33601991Sheppo rv = hv_ldc_rx_get_state(ldcp->id, 33611991Sheppo &rx_head, &rx_tail, &ldcp->link_state); 33621991Sheppo if (rv != 0) { 33631991Sheppo cmn_err(CE_WARN, 33641991Sheppo "ldc_read: (0x%lx) cannot read queue ptrs", 33651991Sheppo ldcp->id); 33662336Snarayan mutex_enter(&ldcp->tx_lock); 33672793Slm66018 i_ldc_reset(ldcp, B_TRUE); 33682336Snarayan mutex_exit(&ldcp->tx_lock); 33691991Sheppo return (ECONNRESET); 33701991Sheppo } 33712793Slm66018 if (ldcp->link_state != LDC_CHANNEL_UP) 33722793Slm66018 goto channel_is_reset; 33732793Slm66018 33742793Slm66018 if (curr_head == rx_tail) { 33752793Slm66018 33762793Slm66018 /* If in the middle of a fragmented xfer */ 33772793Slm66018 if (first_fragment != 0) { 33782793Slm66018 33792793Slm66018 /* wait for ldc_delay usecs */ 33802793Slm66018 drv_usecwait(ldc_delay); 33812793Slm66018 33822793Slm66018 if (++retries < ldc_max_retries) 33832793Slm66018 continue; 33842793Slm66018 33852793Slm66018 *sizep = 0; 33862793Slm66018 ldcp->last_msg_rcd = first_fragment - 1; 33872793Slm66018 DWARN(DBG_ALL_LDCS, "ldc_read: " 33882793Slm66018 "(0x%llx) read timeout", 33892793Slm66018 ldcp->id); 33902793Slm66018 return (EAGAIN); 33912793Slm66018 } 33922032Slm66018 *sizep = 0; 33932793Slm66018 break; 33941991Sheppo } 33951991Sheppo } 33962032Slm66018 retries = 0; 33971991Sheppo 33981991Sheppo D2(ldcp->id, 33991991Sheppo "ldc_read: (0x%llx) chd=0x%llx, rxhd=0x%llx, rxtl=0x%llx\n", 34001991Sheppo ldcp->id, curr_head, rx_head, rx_tail); 34011991Sheppo 34021991Sheppo /* get the message */ 34031991Sheppo msg = (ldc_msg_t *)(ldcp->rx_q_va + curr_head); 34041991Sheppo 34051991Sheppo DUMP_LDC_PKT(ldcp, "ldc_read received pkt", 34061991Sheppo ldcp->rx_q_va + curr_head); 34071991Sheppo 34081991Sheppo /* Check the message ID for the message received */ 34091991Sheppo if ((rv = i_ldc_check_seqid(ldcp, msg)) != 0) { 34101991Sheppo 34111991Sheppo DWARN(ldcp->id, "ldc_read: (0x%llx) seqid error, " 34121991Sheppo "q_ptrs=0x%lx,0x%lx", ldcp->id, rx_head, rx_tail); 34131991Sheppo 34142032Slm66018 /* throw away data */ 34152032Slm66018 bytes_read = 0; 34162032Slm66018 34171991Sheppo /* Reset last_msg_rcd to start of message */ 34182336Snarayan if (first_fragment != 0) { 34192336Snarayan ldcp->last_msg_rcd = first_fragment - 1; 34202336Snarayan first_fragment = 0; 34211991Sheppo } 34221991Sheppo /* 34231991Sheppo * Send a NACK -- invalid seqid 34241991Sheppo * get the current tail for the response 34251991Sheppo */ 34261991Sheppo rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK, 34271991Sheppo (msg->ctrl & LDC_CTRL_MASK)); 34281991Sheppo if (rv) { 34291991Sheppo cmn_err(CE_NOTE, 34301991Sheppo "ldc_read: (0x%lx) err sending " 34311991Sheppo "NACK msg\n", ldcp->id); 34322336Snarayan 34332336Snarayan /* if cannot send NACK - reset channel */ 34342336Snarayan mutex_enter(&ldcp->tx_lock); 34352793Slm66018 i_ldc_reset(ldcp, B_FALSE); 34362336Snarayan mutex_exit(&ldcp->tx_lock); 34372336Snarayan rv = ECONNRESET; 34382336Snarayan break; 34391991Sheppo } 34401991Sheppo 34411991Sheppo /* purge receive queue */ 34422032Slm66018 rv = i_ldc_set_rx_head(ldcp, rx_tail); 34431991Sheppo 34441991Sheppo break; 34451991Sheppo } 34461991Sheppo 34471991Sheppo /* 34481991Sheppo * Process any messages of type CTRL messages 34492410Slm66018 * Future implementations should try to pass these 34502410Slm66018 * to LDC link by resetting the intr state. 34511991Sheppo * 34521991Sheppo * NOTE: not done as a switch() as type can be both ctrl+data 34531991Sheppo */ 34541991Sheppo if (msg->type & LDC_CTRL) { 34551991Sheppo if (rv = i_ldc_ctrlmsg(ldcp, msg)) { 34561991Sheppo if (rv == EAGAIN) 34571991Sheppo continue; 34582032Slm66018 rv = i_ldc_set_rx_head(ldcp, rx_tail); 34591991Sheppo *sizep = 0; 34601991Sheppo bytes_read = 0; 34611991Sheppo break; 34621991Sheppo } 34631991Sheppo } 34641991Sheppo 34651991Sheppo /* process data ACKs */ 34661991Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) { 34672336Snarayan if (rv = i_ldc_process_data_ACK(ldcp, msg)) { 34682336Snarayan *sizep = 0; 34692336Snarayan bytes_read = 0; 34702336Snarayan break; 34712336Snarayan } 34721991Sheppo } 34731991Sheppo 34741991Sheppo /* process data messages */ 34751991Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) { 34761991Sheppo 34771991Sheppo uint8_t *msgbuf = (uint8_t *)( 34781991Sheppo (ldcp->mode == LDC_MODE_RELIABLE || 34791991Sheppo ldcp->mode == LDC_MODE_STREAM) 34801991Sheppo ? msg->rdata : msg->udata); 34811991Sheppo 34821991Sheppo D2(ldcp->id, 34831991Sheppo "ldc_read: (0x%llx) received data msg\n", ldcp->id); 34841991Sheppo 34851991Sheppo /* get the packet length */ 34861991Sheppo len = (msg->env & LDC_LEN_MASK); 34871991Sheppo 34881991Sheppo /* 34891991Sheppo * FUTURE OPTIMIZATION: 34901991Sheppo * dont need to set q head for every 34911991Sheppo * packet we read just need to do this when 34921991Sheppo * we are done or need to wait for more 34931991Sheppo * mondos to make a full packet - this is 34941991Sheppo * currently expensive. 34951991Sheppo */ 34961991Sheppo 34972336Snarayan if (first_fragment == 0) { 34981991Sheppo 34991991Sheppo /* 35001991Sheppo * first packets should always have the start 35011991Sheppo * bit set (even for a single packet). If not 35021991Sheppo * throw away the packet 35031991Sheppo */ 35041991Sheppo if (!(msg->env & LDC_FRAG_START)) { 35051991Sheppo 35061991Sheppo DWARN(DBG_ALL_LDCS, 35071991Sheppo "ldc_read: (0x%llx) not start - " 35081991Sheppo "frag=%x\n", ldcp->id, 35091991Sheppo (msg->env) & LDC_FRAG_MASK); 35101991Sheppo 35111991Sheppo /* toss pkt, inc head, cont reading */ 35121991Sheppo bytes_read = 0; 35131991Sheppo target = target_bufp; 35141991Sheppo curr_head = 35151991Sheppo (curr_head + LDC_PACKET_SIZE) 35161991Sheppo & q_size_mask; 35171991Sheppo if (rv = i_ldc_set_rx_head(ldcp, 35181991Sheppo curr_head)) 35191991Sheppo break; 35201991Sheppo 35211991Sheppo continue; 35221991Sheppo } 35231991Sheppo 35242336Snarayan first_fragment = msg->seqid; 35251991Sheppo } else { 35261991Sheppo /* check to see if this is a pkt w/ START bit */ 35271991Sheppo if (msg->env & LDC_FRAG_START) { 35281991Sheppo DWARN(DBG_ALL_LDCS, 35291991Sheppo "ldc_read:(0x%llx) unexpected pkt" 35301991Sheppo " env=0x%x discarding %d bytes," 35311991Sheppo " lastmsg=%d, currentmsg=%d\n", 35321991Sheppo ldcp->id, msg->env&LDC_FRAG_MASK, 35331991Sheppo bytes_read, ldcp->last_msg_rcd, 35341991Sheppo msg->seqid); 35351991Sheppo 35361991Sheppo /* throw data we have read so far */ 35371991Sheppo bytes_read = 0; 35381991Sheppo target = target_bufp; 35392336Snarayan first_fragment = msg->seqid; 35401991Sheppo 35411991Sheppo if (rv = i_ldc_set_rx_head(ldcp, 35421991Sheppo curr_head)) 35431991Sheppo break; 35441991Sheppo } 35451991Sheppo } 35461991Sheppo 35471991Sheppo /* copy (next) pkt into buffer */ 35481991Sheppo if (len <= (*sizep - bytes_read)) { 35491991Sheppo bcopy(msgbuf, target, len); 35501991Sheppo target += len; 35511991Sheppo bytes_read += len; 35521991Sheppo } else { 35531991Sheppo /* 35541991Sheppo * there is not enough space in the buffer to 35551991Sheppo * read this pkt. throw message away & continue 35561991Sheppo * reading data from queue 35571991Sheppo */ 35581991Sheppo DWARN(DBG_ALL_LDCS, 35591991Sheppo "ldc_read: (0x%llx) buffer too small, " 35601991Sheppo "head=0x%lx, expect=%d, got=%d\n", ldcp->id, 35611991Sheppo curr_head, *sizep, bytes_read+len); 35621991Sheppo 35632336Snarayan first_fragment = 0; 35641991Sheppo target = target_bufp; 35651991Sheppo bytes_read = 0; 35661991Sheppo 35671991Sheppo /* throw away everything received so far */ 35681991Sheppo if (rv = i_ldc_set_rx_head(ldcp, curr_head)) 35691991Sheppo break; 35701991Sheppo 35711991Sheppo /* continue reading remaining pkts */ 35721991Sheppo continue; 35731991Sheppo } 35741991Sheppo } 35751991Sheppo 35761991Sheppo /* set the message id */ 35771991Sheppo ldcp->last_msg_rcd = msg->seqid; 35781991Sheppo 35791991Sheppo /* move the head one position */ 35801991Sheppo curr_head = (curr_head + LDC_PACKET_SIZE) & q_size_mask; 35811991Sheppo 35821991Sheppo if (msg->env & LDC_FRAG_STOP) { 35831991Sheppo 35841991Sheppo /* 35851991Sheppo * All pkts that are part of this fragmented transfer 35861991Sheppo * have been read or this was a single pkt read 35871991Sheppo * or there was an error 35881991Sheppo */ 35891991Sheppo 35901991Sheppo /* set the queue head */ 35911991Sheppo if (rv = i_ldc_set_rx_head(ldcp, curr_head)) 35921991Sheppo bytes_read = 0; 35931991Sheppo 35941991Sheppo *sizep = bytes_read; 35951991Sheppo 35961991Sheppo break; 35971991Sheppo } 35981991Sheppo 35991991Sheppo /* advance head if it is a DATA ACK */ 36001991Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) { 36011991Sheppo 36021991Sheppo /* set the queue head */ 36031991Sheppo if (rv = i_ldc_set_rx_head(ldcp, curr_head)) { 36041991Sheppo bytes_read = 0; 36051991Sheppo break; 36061991Sheppo } 36071991Sheppo 36081991Sheppo D2(ldcp->id, "ldc_read: (0x%llx) set ACK qhead 0x%llx", 36091991Sheppo ldcp->id, curr_head); 36101991Sheppo } 36111991Sheppo 36121991Sheppo } /* for (;;) */ 36131991Sheppo 36141991Sheppo 36151991Sheppo /* 36161991Sheppo * If useful data was read - Send msg ACK 36171991Sheppo * OPTIMIZE: do not send ACK for all msgs - use some frequency 36181991Sheppo */ 36191991Sheppo if ((bytes_read > 0) && (ldcp->mode == LDC_MODE_RELIABLE || 36201991Sheppo ldcp->mode == LDC_MODE_STREAM)) { 36211991Sheppo 36221991Sheppo rv = i_ldc_send_pkt(ldcp, LDC_DATA, LDC_ACK, 0); 36232793Slm66018 if (rv && rv != EWOULDBLOCK) { 36241991Sheppo cmn_err(CE_NOTE, 36251991Sheppo "ldc_read: (0x%lx) cannot send ACK\n", ldcp->id); 36262336Snarayan 36272336Snarayan /* if cannot send ACK - reset channel */ 36282793Slm66018 goto channel_is_reset; 36291991Sheppo } 36301991Sheppo } 36311991Sheppo 36321991Sheppo D2(ldcp->id, "ldc_read: (0x%llx) end size=%d", ldcp->id, *sizep); 36331991Sheppo 36341991Sheppo return (rv); 36352793Slm66018 36362793Slm66018 channel_is_reset: 36372793Slm66018 mutex_enter(&ldcp->tx_lock); 36382793Slm66018 i_ldc_reset(ldcp, B_FALSE); 36392793Slm66018 mutex_exit(&ldcp->tx_lock); 36402793Slm66018 return (ECONNRESET); 36411991Sheppo } 36421991Sheppo 36431991Sheppo /* 36441991Sheppo * Use underlying reliable packet mechanism to fetch 36451991Sheppo * and buffer incoming packets so we can hand them back as 36461991Sheppo * a basic byte stream. 36471991Sheppo * 36481991Sheppo * Enter and exit with ldcp->lock held by caller 36491991Sheppo */ 36501991Sheppo static int 36511991Sheppo i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep) 36521991Sheppo { 36531991Sheppo int rv; 36541991Sheppo size_t size; 36551991Sheppo 36561991Sheppo ASSERT(mutex_owned(&ldcp->lock)); 36571991Sheppo 36581991Sheppo D2(ldcp->id, "i_ldc_read_stream: (0x%llx) buffer size=%d", 36591991Sheppo ldcp->id, *sizep); 36601991Sheppo 36611991Sheppo if (ldcp->stream_remains == 0) { 36621991Sheppo size = ldcp->mtu; 36631991Sheppo rv = i_ldc_read_packet(ldcp, 36641991Sheppo (caddr_t)ldcp->stream_bufferp, &size); 36651991Sheppo D2(ldcp->id, "i_ldc_read_stream: read packet (0x%llx) size=%d", 36661991Sheppo ldcp->id, size); 36671991Sheppo 36681991Sheppo if (rv != 0) 36691991Sheppo return (rv); 36701991Sheppo 36711991Sheppo ldcp->stream_remains = size; 36721991Sheppo ldcp->stream_offset = 0; 36731991Sheppo } 36741991Sheppo 36751991Sheppo size = MIN(ldcp->stream_remains, *sizep); 36761991Sheppo 36771991Sheppo bcopy(ldcp->stream_bufferp + ldcp->stream_offset, target_bufp, size); 36781991Sheppo ldcp->stream_offset += size; 36791991Sheppo ldcp->stream_remains -= size; 36801991Sheppo 36811991Sheppo D2(ldcp->id, "i_ldc_read_stream: (0x%llx) fill from buffer size=%d", 36821991Sheppo ldcp->id, size); 36831991Sheppo 36841991Sheppo *sizep = size; 36851991Sheppo return (0); 36861991Sheppo } 36871991Sheppo 36881991Sheppo /* 36891991Sheppo * Write specified amount of bytes to the channel 36901991Sheppo * in multiple pkts of pkt_payload size. Each 36911991Sheppo * packet is tagged with an unique packet ID in 36922410Slm66018 * the case of a reliable link. 36931991Sheppo * 36941991Sheppo * On return, size contains the number of bytes written. 36951991Sheppo */ 36961991Sheppo int 36971991Sheppo ldc_write(ldc_handle_t handle, caddr_t buf, size_t *sizep) 36981991Sheppo { 36991991Sheppo ldc_chan_t *ldcp; 37001991Sheppo int rv = 0; 37011991Sheppo 37021991Sheppo if (handle == NULL) { 37031991Sheppo DWARN(DBG_ALL_LDCS, "ldc_write: invalid channel handle\n"); 37041991Sheppo return (EINVAL); 37051991Sheppo } 37061991Sheppo ldcp = (ldc_chan_t *)handle; 37071991Sheppo 37082336Snarayan /* check if writes can occur */ 37092336Snarayan if (!mutex_tryenter(&ldcp->tx_lock)) { 37102336Snarayan /* 37112336Snarayan * Could not get the lock - channel could 37122336Snarayan * be in the process of being unconfigured 37132336Snarayan * or reader has encountered an error 37142336Snarayan */ 37152336Snarayan return (EAGAIN); 37162336Snarayan } 37171991Sheppo 37181991Sheppo /* check if non-zero data to write */ 37191991Sheppo if (buf == NULL || sizep == NULL) { 37201991Sheppo DWARN(ldcp->id, "ldc_write: (0x%llx) invalid data write\n", 37211991Sheppo ldcp->id); 37222336Snarayan mutex_exit(&ldcp->tx_lock); 37231991Sheppo return (EINVAL); 37241991Sheppo } 37251991Sheppo 37261991Sheppo if (*sizep == 0) { 37271991Sheppo DWARN(ldcp->id, "ldc_write: (0x%llx) write size of zero\n", 37281991Sheppo ldcp->id); 37292336Snarayan mutex_exit(&ldcp->tx_lock); 37301991Sheppo return (0); 37311991Sheppo } 37321991Sheppo 37331991Sheppo /* Check if channel is UP for data exchange */ 37341991Sheppo if (ldcp->tstate != TS_UP) { 37351991Sheppo DWARN(ldcp->id, 37361991Sheppo "ldc_write: (0x%llx) channel is not in UP state\n", 37371991Sheppo ldcp->id); 37381991Sheppo *sizep = 0; 37391991Sheppo rv = ECONNRESET; 37401991Sheppo } else { 37411991Sheppo rv = ldcp->write_p(ldcp, buf, sizep); 37421991Sheppo } 37431991Sheppo 37442336Snarayan mutex_exit(&ldcp->tx_lock); 37451991Sheppo 37461991Sheppo return (rv); 37471991Sheppo } 37481991Sheppo 37491991Sheppo /* 37501991Sheppo * Write a raw packet to the channel 37511991Sheppo * On return, size contains the number of bytes written. 37521991Sheppo */ 37531991Sheppo static int 37541991Sheppo i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep) 37551991Sheppo { 37561991Sheppo ldc_msg_t *ldcmsg; 37571991Sheppo uint64_t tx_head, tx_tail, new_tail; 37581991Sheppo int rv = 0; 37591991Sheppo size_t size; 37601991Sheppo 37612336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 37621991Sheppo ASSERT(ldcp->mode == LDC_MODE_RAW); 37631991Sheppo 37641991Sheppo size = *sizep; 37651991Sheppo 37661991Sheppo /* 37671991Sheppo * Check to see if the packet size is less than or 37681991Sheppo * equal to packet size support in raw mode 37691991Sheppo */ 37701991Sheppo if (size > ldcp->pkt_payload) { 37711991Sheppo DWARN(ldcp->id, 37721991Sheppo "ldc_write: (0x%llx) invalid size (0x%llx) for RAW mode\n", 37731991Sheppo ldcp->id, *sizep); 37741991Sheppo *sizep = 0; 37751991Sheppo return (EMSGSIZE); 37761991Sheppo } 37771991Sheppo 37781991Sheppo /* get the qptrs for the tx queue */ 37791991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 37801991Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 37811991Sheppo if (rv != 0) { 37821991Sheppo cmn_err(CE_WARN, 37831991Sheppo "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id); 37841991Sheppo *sizep = 0; 37851991Sheppo return (EIO); 37861991Sheppo } 37871991Sheppo 37881991Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN || 37891991Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 37901991Sheppo DWARN(ldcp->id, 37911991Sheppo "ldc_write: (0x%llx) channel down/reset\n", ldcp->id); 37922336Snarayan 37931991Sheppo *sizep = 0; 37942336Snarayan if (mutex_tryenter(&ldcp->lock)) { 37952793Slm66018 i_ldc_reset(ldcp, B_FALSE); 37962336Snarayan mutex_exit(&ldcp->lock); 37972336Snarayan } else { 37982336Snarayan /* 37992336Snarayan * Release Tx lock, and then reacquire channel 38002336Snarayan * and Tx lock in correct order 38012336Snarayan */ 38022336Snarayan mutex_exit(&ldcp->tx_lock); 38032336Snarayan mutex_enter(&ldcp->lock); 38042336Snarayan mutex_enter(&ldcp->tx_lock); 38052793Slm66018 i_ldc_reset(ldcp, B_FALSE); 38062336Snarayan mutex_exit(&ldcp->lock); 38072336Snarayan } 38081991Sheppo return (ECONNRESET); 38091991Sheppo } 38101991Sheppo 38111991Sheppo tx_tail = ldcp->tx_tail; 38121991Sheppo tx_head = ldcp->tx_head; 38131991Sheppo new_tail = (tx_tail + LDC_PACKET_SIZE) & 38141991Sheppo ((ldcp->tx_q_entries-1) << LDC_PACKET_SHIFT); 38151991Sheppo 38161991Sheppo if (new_tail == tx_head) { 38171991Sheppo DWARN(DBG_ALL_LDCS, 38181991Sheppo "ldc_write: (0x%llx) TX queue is full\n", ldcp->id); 38191991Sheppo *sizep = 0; 38201991Sheppo return (EWOULDBLOCK); 38211991Sheppo } 38221991Sheppo 38231991Sheppo D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d", 38241991Sheppo ldcp->id, size); 38251991Sheppo 38261991Sheppo /* Send the data now */ 38271991Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 38281991Sheppo 38292336Snarayan /* copy the data into pkt */ 38301991Sheppo bcopy((uint8_t *)buf, ldcmsg, size); 38311991Sheppo 38322336Snarayan /* increment tail */ 38331991Sheppo tx_tail = new_tail; 38341991Sheppo 38351991Sheppo /* 38361991Sheppo * All packets have been copied into the TX queue 38371991Sheppo * update the tail ptr in the HV 38381991Sheppo */ 38391991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 38401991Sheppo if (rv) { 38411991Sheppo if (rv == EWOULDBLOCK) { 38421991Sheppo DWARN(ldcp->id, "ldc_write: (0x%llx) write timed out\n", 38431991Sheppo ldcp->id); 38441991Sheppo *sizep = 0; 38451991Sheppo return (EWOULDBLOCK); 38461991Sheppo } 38471991Sheppo 38481991Sheppo *sizep = 0; 38492336Snarayan if (mutex_tryenter(&ldcp->lock)) { 38502793Slm66018 i_ldc_reset(ldcp, B_FALSE); 38512336Snarayan mutex_exit(&ldcp->lock); 38522336Snarayan } else { 38532336Snarayan /* 38542336Snarayan * Release Tx lock, and then reacquire channel 38552336Snarayan * and Tx lock in correct order 38562336Snarayan */ 38572336Snarayan mutex_exit(&ldcp->tx_lock); 38582336Snarayan mutex_enter(&ldcp->lock); 38592336Snarayan mutex_enter(&ldcp->tx_lock); 38602793Slm66018 i_ldc_reset(ldcp, B_FALSE); 38612336Snarayan mutex_exit(&ldcp->lock); 38622336Snarayan } 38631991Sheppo return (ECONNRESET); 38641991Sheppo } 38651991Sheppo 38661991Sheppo ldcp->tx_tail = tx_tail; 38671991Sheppo *sizep = size; 38681991Sheppo 38691991Sheppo D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, size); 38701991Sheppo 38711991Sheppo return (rv); 38721991Sheppo } 38731991Sheppo 38741991Sheppo 38751991Sheppo /* 38761991Sheppo * Write specified amount of bytes to the channel 38771991Sheppo * in multiple pkts of pkt_payload size. Each 38781991Sheppo * packet is tagged with an unique packet ID in 38792410Slm66018 * the case of a reliable link. 38801991Sheppo * 38811991Sheppo * On return, size contains the number of bytes written. 38821991Sheppo * This function needs to ensure that the write size is < MTU size 38831991Sheppo */ 38841991Sheppo static int 38851991Sheppo i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t buf, size_t *size) 38861991Sheppo { 38871991Sheppo ldc_msg_t *ldcmsg; 38881991Sheppo uint64_t tx_head, tx_tail, new_tail, start; 38891991Sheppo uint64_t txq_size_mask, numavail; 38901991Sheppo uint8_t *msgbuf, *source = (uint8_t *)buf; 38911991Sheppo size_t len, bytes_written = 0, remaining; 38921991Sheppo int rv; 38931991Sheppo uint32_t curr_seqid; 38941991Sheppo 38952336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 38961991Sheppo 38971991Sheppo ASSERT(ldcp->mode == LDC_MODE_RELIABLE || 38981991Sheppo ldcp->mode == LDC_MODE_UNRELIABLE || 38991991Sheppo ldcp->mode == LDC_MODE_STREAM); 39001991Sheppo 39011991Sheppo /* compute mask for increment */ 39021991Sheppo txq_size_mask = (ldcp->tx_q_entries - 1) << LDC_PACKET_SHIFT; 39031991Sheppo 39041991Sheppo /* get the qptrs for the tx queue */ 39051991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 39061991Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 39071991Sheppo if (rv != 0) { 39081991Sheppo cmn_err(CE_WARN, 39091991Sheppo "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id); 39101991Sheppo *size = 0; 39111991Sheppo return (EIO); 39121991Sheppo } 39131991Sheppo 39141991Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN || 39151991Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 39161991Sheppo DWARN(ldcp->id, 39171991Sheppo "ldc_write: (0x%llx) channel down/reset\n", ldcp->id); 39181991Sheppo *size = 0; 39192336Snarayan if (mutex_tryenter(&ldcp->lock)) { 39202793Slm66018 i_ldc_reset(ldcp, B_FALSE); 39212336Snarayan mutex_exit(&ldcp->lock); 39222336Snarayan } else { 39232336Snarayan /* 39242336Snarayan * Release Tx lock, and then reacquire channel 39252336Snarayan * and Tx lock in correct order 39262336Snarayan */ 39272336Snarayan mutex_exit(&ldcp->tx_lock); 39282336Snarayan mutex_enter(&ldcp->lock); 39292336Snarayan mutex_enter(&ldcp->tx_lock); 39302793Slm66018 i_ldc_reset(ldcp, B_FALSE); 39312336Snarayan mutex_exit(&ldcp->lock); 39322336Snarayan } 39331991Sheppo return (ECONNRESET); 39341991Sheppo } 39351991Sheppo 39361991Sheppo tx_tail = ldcp->tx_tail; 39371991Sheppo new_tail = (tx_tail + LDC_PACKET_SIZE) % 39381991Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 39391991Sheppo 39401991Sheppo /* 39412410Slm66018 * Link mode determines whether we use HV Tx head or the 39421991Sheppo * private protocol head (corresponding to last ACKd pkt) for 39431991Sheppo * determining how much we can write 39441991Sheppo */ 39451991Sheppo tx_head = (ldcp->mode == LDC_MODE_RELIABLE || 39461991Sheppo ldcp->mode == LDC_MODE_STREAM) 39471991Sheppo ? ldcp->tx_ackd_head : ldcp->tx_head; 39481991Sheppo if (new_tail == tx_head) { 39491991Sheppo DWARN(DBG_ALL_LDCS, 39501991Sheppo "ldc_write: (0x%llx) TX queue is full\n", ldcp->id); 39511991Sheppo *size = 0; 39521991Sheppo return (EWOULDBLOCK); 39531991Sheppo } 39541991Sheppo 39551991Sheppo /* 39561991Sheppo * Make sure that the LDC Tx queue has enough space 39571991Sheppo */ 39581991Sheppo numavail = (tx_head >> LDC_PACKET_SHIFT) - (tx_tail >> LDC_PACKET_SHIFT) 39591991Sheppo + ldcp->tx_q_entries - 1; 39601991Sheppo numavail %= ldcp->tx_q_entries; 39611991Sheppo 39621991Sheppo if (*size > (numavail * ldcp->pkt_payload)) { 39631991Sheppo DWARN(DBG_ALL_LDCS, 39641991Sheppo "ldc_write: (0x%llx) TX queue has no space\n", ldcp->id); 39651991Sheppo return (EWOULDBLOCK); 39661991Sheppo } 39671991Sheppo 39681991Sheppo D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d", 39691991Sheppo ldcp->id, *size); 39701991Sheppo 39711991Sheppo /* Send the data now */ 39721991Sheppo bytes_written = 0; 39731991Sheppo curr_seqid = ldcp->last_msg_snt; 39741991Sheppo start = tx_tail; 39751991Sheppo 39761991Sheppo while (*size > bytes_written) { 39771991Sheppo 39781991Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 39791991Sheppo 39801991Sheppo msgbuf = (uint8_t *)((ldcp->mode == LDC_MODE_RELIABLE || 39811991Sheppo ldcp->mode == LDC_MODE_STREAM) 39821991Sheppo ? ldcmsg->rdata : ldcmsg->udata); 39831991Sheppo 39841991Sheppo ldcmsg->type = LDC_DATA; 39851991Sheppo ldcmsg->stype = LDC_INFO; 39861991Sheppo ldcmsg->ctrl = 0; 39871991Sheppo 39881991Sheppo remaining = *size - bytes_written; 39891991Sheppo len = min(ldcp->pkt_payload, remaining); 39901991Sheppo ldcmsg->env = (uint8_t)len; 39911991Sheppo 39921991Sheppo curr_seqid++; 39931991Sheppo ldcmsg->seqid = curr_seqid; 39941991Sheppo 39951991Sheppo /* copy the data into pkt */ 39961991Sheppo bcopy(source, msgbuf, len); 39971991Sheppo 39981991Sheppo source += len; 39991991Sheppo bytes_written += len; 40001991Sheppo 40011991Sheppo /* increment tail */ 40021991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) & txq_size_mask; 40031991Sheppo 40041991Sheppo ASSERT(tx_tail != tx_head); 40051991Sheppo } 40061991Sheppo 40071991Sheppo /* Set the start and stop bits */ 40081991Sheppo ldcmsg->env |= LDC_FRAG_STOP; 40091991Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + start); 40101991Sheppo ldcmsg->env |= LDC_FRAG_START; 40111991Sheppo 40121991Sheppo /* 40131991Sheppo * All packets have been copied into the TX queue 40141991Sheppo * update the tail ptr in the HV 40151991Sheppo */ 40161991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 40171991Sheppo if (rv == 0) { 40181991Sheppo ldcp->tx_tail = tx_tail; 40191991Sheppo ldcp->last_msg_snt = curr_seqid; 40201991Sheppo *size = bytes_written; 40211991Sheppo } else { 40221991Sheppo int rv2; 40231991Sheppo 40241991Sheppo if (rv != EWOULDBLOCK) { 40251991Sheppo *size = 0; 40262336Snarayan if (mutex_tryenter(&ldcp->lock)) { 40272793Slm66018 i_ldc_reset(ldcp, B_FALSE); 40282336Snarayan mutex_exit(&ldcp->lock); 40292336Snarayan } else { 40302336Snarayan /* 40312336Snarayan * Release Tx lock, and then reacquire channel 40322336Snarayan * and Tx lock in correct order 40332336Snarayan */ 40342336Snarayan mutex_exit(&ldcp->tx_lock); 40352336Snarayan mutex_enter(&ldcp->lock); 40362336Snarayan mutex_enter(&ldcp->tx_lock); 40372793Slm66018 i_ldc_reset(ldcp, B_FALSE); 40382336Snarayan mutex_exit(&ldcp->lock); 40392336Snarayan } 40401991Sheppo return (ECONNRESET); 40411991Sheppo } 40421991Sheppo 40433010Slm66018 D1(ldcp->id, "hv_tx_set_tail returns 0x%x (head 0x%x, " 40441991Sheppo "old tail 0x%x, new tail 0x%x, qsize=0x%x)\n", 40451991Sheppo rv, ldcp->tx_head, ldcp->tx_tail, tx_tail, 40461991Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT)); 40471991Sheppo 40481991Sheppo rv2 = hv_ldc_tx_get_state(ldcp->id, 40491991Sheppo &tx_head, &tx_tail, &ldcp->link_state); 40501991Sheppo 40513010Slm66018 D1(ldcp->id, "hv_ldc_tx_get_state returns 0x%x " 40521991Sheppo "(head 0x%x, tail 0x%x state 0x%x)\n", 40531991Sheppo rv2, tx_head, tx_tail, ldcp->link_state); 40541991Sheppo 40551991Sheppo *size = 0; 40561991Sheppo } 40571991Sheppo 40581991Sheppo D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, *size); 40591991Sheppo 40601991Sheppo return (rv); 40611991Sheppo } 40621991Sheppo 40631991Sheppo /* 40641991Sheppo * Write specified amount of bytes to the channel 40651991Sheppo * in multiple pkts of pkt_payload size. Each 40661991Sheppo * packet is tagged with an unique packet ID in 40672410Slm66018 * the case of a reliable link. 40681991Sheppo * 40691991Sheppo * On return, size contains the number of bytes written. 40701991Sheppo * This function needs to ensure that the write size is < MTU size 40711991Sheppo */ 40721991Sheppo static int 40731991Sheppo i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep) 40741991Sheppo { 40752336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 40761991Sheppo ASSERT(ldcp->mode == LDC_MODE_STREAM); 40771991Sheppo 40781991Sheppo /* Truncate packet to max of MTU size */ 40791991Sheppo if (*sizep > ldcp->mtu) *sizep = ldcp->mtu; 40801991Sheppo return (i_ldc_write_packet(ldcp, buf, sizep)); 40811991Sheppo } 40821991Sheppo 40831991Sheppo 40841991Sheppo /* 40851991Sheppo * Interfaces for channel nexus to register/unregister with LDC module 40861991Sheppo * The nexus will register functions to be used to register individual 40871991Sheppo * channels with the nexus and enable interrupts for the channels 40881991Sheppo */ 40891991Sheppo int 40901991Sheppo ldc_register(ldc_cnex_t *cinfo) 40911991Sheppo { 40921991Sheppo ldc_chan_t *ldcp; 40931991Sheppo 40941991Sheppo if (cinfo == NULL || cinfo->dip == NULL || 40951991Sheppo cinfo->reg_chan == NULL || cinfo->unreg_chan == NULL || 40961991Sheppo cinfo->add_intr == NULL || cinfo->rem_intr == NULL || 40971991Sheppo cinfo->clr_intr == NULL) { 40981991Sheppo 40991991Sheppo DWARN(DBG_ALL_LDCS, "ldc_register: invalid nexus info\n"); 41001991Sheppo return (EINVAL); 41011991Sheppo } 41021991Sheppo 41031991Sheppo mutex_enter(&ldcssp->lock); 41041991Sheppo 41051991Sheppo /* nexus registration */ 41061991Sheppo ldcssp->cinfo.dip = cinfo->dip; 41071991Sheppo ldcssp->cinfo.reg_chan = cinfo->reg_chan; 41081991Sheppo ldcssp->cinfo.unreg_chan = cinfo->unreg_chan; 41091991Sheppo ldcssp->cinfo.add_intr = cinfo->add_intr; 41101991Sheppo ldcssp->cinfo.rem_intr = cinfo->rem_intr; 41111991Sheppo ldcssp->cinfo.clr_intr = cinfo->clr_intr; 41121991Sheppo 41131991Sheppo /* register any channels that might have been previously initialized */ 41141991Sheppo ldcp = ldcssp->chan_list; 41151991Sheppo while (ldcp) { 41161991Sheppo if ((ldcp->tstate & TS_QCONF_RDY) && 41171991Sheppo (ldcp->tstate & TS_CNEX_RDY) == 0) 41181991Sheppo (void) i_ldc_register_channel(ldcp); 41191991Sheppo 41201991Sheppo ldcp = ldcp->next; 41211991Sheppo } 41221991Sheppo 41231991Sheppo mutex_exit(&ldcssp->lock); 41241991Sheppo 41251991Sheppo return (0); 41261991Sheppo } 41271991Sheppo 41281991Sheppo int 41291991Sheppo ldc_unregister(ldc_cnex_t *cinfo) 41301991Sheppo { 41311991Sheppo if (cinfo == NULL || cinfo->dip == NULL) { 41321991Sheppo DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid nexus info\n"); 41331991Sheppo return (EINVAL); 41341991Sheppo } 41351991Sheppo 41361991Sheppo mutex_enter(&ldcssp->lock); 41371991Sheppo 41381991Sheppo if (cinfo->dip != ldcssp->cinfo.dip) { 41391991Sheppo DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid dip\n"); 41401991Sheppo mutex_exit(&ldcssp->lock); 41411991Sheppo return (EINVAL); 41421991Sheppo } 41431991Sheppo 41441991Sheppo /* nexus unregister */ 41451991Sheppo ldcssp->cinfo.dip = NULL; 41461991Sheppo ldcssp->cinfo.reg_chan = NULL; 41471991Sheppo ldcssp->cinfo.unreg_chan = NULL; 41481991Sheppo ldcssp->cinfo.add_intr = NULL; 41491991Sheppo ldcssp->cinfo.rem_intr = NULL; 41501991Sheppo ldcssp->cinfo.clr_intr = NULL; 41511991Sheppo 41521991Sheppo mutex_exit(&ldcssp->lock); 41531991Sheppo 41541991Sheppo return (0); 41551991Sheppo } 41561991Sheppo 41571991Sheppo 41581991Sheppo /* ------------------------------------------------------------------------- */ 41591991Sheppo 41601991Sheppo /* 41611991Sheppo * Allocate a memory handle for the channel and link it into the list 41621991Sheppo * Also choose which memory table to use if this is the first handle 41631991Sheppo * being assigned to this channel 41641991Sheppo */ 41651991Sheppo int 41661991Sheppo ldc_mem_alloc_handle(ldc_handle_t handle, ldc_mem_handle_t *mhandle) 41671991Sheppo { 41681991Sheppo ldc_chan_t *ldcp; 41691991Sheppo ldc_mhdl_t *mhdl; 41701991Sheppo 41711991Sheppo if (handle == NULL) { 41721991Sheppo DWARN(DBG_ALL_LDCS, 41731991Sheppo "ldc_mem_alloc_handle: invalid channel handle\n"); 41741991Sheppo return (EINVAL); 41751991Sheppo } 41761991Sheppo ldcp = (ldc_chan_t *)handle; 41771991Sheppo 41781991Sheppo mutex_enter(&ldcp->lock); 41791991Sheppo 41801991Sheppo /* check to see if channel is initalized */ 41812793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) < TS_INIT) { 41821991Sheppo DWARN(ldcp->id, 41831991Sheppo "ldc_mem_alloc_handle: (0x%llx) channel not initialized\n", 41841991Sheppo ldcp->id); 41851991Sheppo mutex_exit(&ldcp->lock); 41861991Sheppo return (EINVAL); 41871991Sheppo } 41881991Sheppo 41891991Sheppo /* allocate handle for channel */ 41902531Snarayan mhdl = kmem_cache_alloc(ldcssp->memhdl_cache, KM_SLEEP); 41911991Sheppo 41921991Sheppo /* initialize the lock */ 41931991Sheppo mutex_init(&mhdl->lock, NULL, MUTEX_DRIVER, NULL); 41941991Sheppo 41952531Snarayan mhdl->myshadow = B_FALSE; 41962531Snarayan mhdl->memseg = NULL; 41972531Snarayan mhdl->ldcp = ldcp; 41981991Sheppo mhdl->status = LDC_UNBOUND; 41991991Sheppo 42001991Sheppo /* insert memory handle (@ head) into list */ 42011991Sheppo if (ldcp->mhdl_list == NULL) { 42021991Sheppo ldcp->mhdl_list = mhdl; 42031991Sheppo mhdl->next = NULL; 42041991Sheppo } else { 42051991Sheppo /* insert @ head */ 42061991Sheppo mhdl->next = ldcp->mhdl_list; 42071991Sheppo ldcp->mhdl_list = mhdl; 42081991Sheppo } 42091991Sheppo 42101991Sheppo /* return the handle */ 42111991Sheppo *mhandle = (ldc_mem_handle_t)mhdl; 42121991Sheppo 42131991Sheppo mutex_exit(&ldcp->lock); 42141991Sheppo 42151991Sheppo D1(ldcp->id, "ldc_mem_alloc_handle: (0x%llx) allocated handle 0x%llx\n", 42161991Sheppo ldcp->id, mhdl); 42171991Sheppo 42181991Sheppo return (0); 42191991Sheppo } 42201991Sheppo 42211991Sheppo /* 42221991Sheppo * Free memory handle for the channel and unlink it from the list 42231991Sheppo */ 42241991Sheppo int 42251991Sheppo ldc_mem_free_handle(ldc_mem_handle_t mhandle) 42261991Sheppo { 42271991Sheppo ldc_mhdl_t *mhdl, *phdl; 42281991Sheppo ldc_chan_t *ldcp; 42291991Sheppo 42301991Sheppo if (mhandle == NULL) { 42311991Sheppo DWARN(DBG_ALL_LDCS, 42321991Sheppo "ldc_mem_free_handle: invalid memory handle\n"); 42331991Sheppo return (EINVAL); 42341991Sheppo } 42351991Sheppo mhdl = (ldc_mhdl_t *)mhandle; 42361991Sheppo 42371991Sheppo mutex_enter(&mhdl->lock); 42381991Sheppo 42391991Sheppo ldcp = mhdl->ldcp; 42401991Sheppo 42411991Sheppo if (mhdl->status == LDC_BOUND || mhdl->status == LDC_MAPPED) { 42421991Sheppo DWARN(ldcp->id, 42431991Sheppo "ldc_mem_free_handle: cannot free, 0x%llx hdl bound\n", 42441991Sheppo mhdl); 42451991Sheppo mutex_exit(&mhdl->lock); 42461991Sheppo return (EINVAL); 42471991Sheppo } 42481991Sheppo mutex_exit(&mhdl->lock); 42491991Sheppo 42501991Sheppo mutex_enter(&ldcp->mlist_lock); 42511991Sheppo 42521991Sheppo phdl = ldcp->mhdl_list; 42531991Sheppo 42541991Sheppo /* first handle */ 42551991Sheppo if (phdl == mhdl) { 42561991Sheppo ldcp->mhdl_list = mhdl->next; 42571991Sheppo mutex_destroy(&mhdl->lock); 42582531Snarayan kmem_cache_free(ldcssp->memhdl_cache, mhdl); 42592531Snarayan 42601991Sheppo D1(ldcp->id, 42611991Sheppo "ldc_mem_free_handle: (0x%llx) freed handle 0x%llx\n", 42621991Sheppo ldcp->id, mhdl); 42631991Sheppo } else { 42641991Sheppo /* walk the list - unlink and free */ 42651991Sheppo while (phdl != NULL) { 42661991Sheppo if (phdl->next == mhdl) { 42671991Sheppo phdl->next = mhdl->next; 42681991Sheppo mutex_destroy(&mhdl->lock); 42692531Snarayan kmem_cache_free(ldcssp->memhdl_cache, mhdl); 42701991Sheppo D1(ldcp->id, 42711991Sheppo "ldc_mem_free_handle: (0x%llx) freed " 42721991Sheppo "handle 0x%llx\n", ldcp->id, mhdl); 42731991Sheppo break; 42741991Sheppo } 42751991Sheppo phdl = phdl->next; 42761991Sheppo } 42771991Sheppo } 42781991Sheppo 42791991Sheppo if (phdl == NULL) { 42801991Sheppo DWARN(ldcp->id, 42811991Sheppo "ldc_mem_free_handle: invalid handle 0x%llx\n", mhdl); 42821991Sheppo mutex_exit(&ldcp->mlist_lock); 42831991Sheppo return (EINVAL); 42841991Sheppo } 42851991Sheppo 42861991Sheppo mutex_exit(&ldcp->mlist_lock); 42871991Sheppo 42881991Sheppo return (0); 42891991Sheppo } 42901991Sheppo 42911991Sheppo /* 42921991Sheppo * Bind a memory handle to a virtual address. 42931991Sheppo * The virtual address is converted to the corresponding real addresses. 42941991Sheppo * Returns pointer to the first ldc_mem_cookie and the total number 42951991Sheppo * of cookies for this virtual address. Other cookies can be obtained 42961991Sheppo * using the ldc_mem_nextcookie() call. If the pages are stored in 42971991Sheppo * consecutive locations in the table, a single cookie corresponding to 42981991Sheppo * the first location is returned. The cookie size spans all the entries. 42991991Sheppo * 43001991Sheppo * If the VA corresponds to a page that is already being exported, reuse 43011991Sheppo * the page and do not export it again. Bump the page's use count. 43021991Sheppo */ 43031991Sheppo int 43041991Sheppo ldc_mem_bind_handle(ldc_mem_handle_t mhandle, caddr_t vaddr, size_t len, 43051991Sheppo uint8_t mtype, uint8_t perm, ldc_mem_cookie_t *cookie, uint32_t *ccount) 43061991Sheppo { 43071991Sheppo ldc_mhdl_t *mhdl; 43081991Sheppo ldc_chan_t *ldcp; 43091991Sheppo ldc_mtbl_t *mtbl; 43101991Sheppo ldc_memseg_t *memseg; 43111991Sheppo ldc_mte_t tmp_mte; 43121991Sheppo uint64_t index, prev_index = 0; 43131991Sheppo int64_t cookie_idx; 43141991Sheppo uintptr_t raddr, ra_aligned; 43151991Sheppo uint64_t psize, poffset, v_offset; 43161991Sheppo uint64_t pg_shift, pg_size, pg_size_code, pg_mask; 43171991Sheppo pgcnt_t npages; 43181991Sheppo caddr_t v_align, addr; 43192531Snarayan int i, rv; 43201991Sheppo 43211991Sheppo if (mhandle == NULL) { 43221991Sheppo DWARN(DBG_ALL_LDCS, 43231991Sheppo "ldc_mem_bind_handle: invalid memory handle\n"); 43241991Sheppo return (EINVAL); 43251991Sheppo } 43261991Sheppo mhdl = (ldc_mhdl_t *)mhandle; 43271991Sheppo ldcp = mhdl->ldcp; 43281991Sheppo 43291991Sheppo /* clear count */ 43301991Sheppo *ccount = 0; 43311991Sheppo 43321991Sheppo mutex_enter(&mhdl->lock); 43331991Sheppo 43341991Sheppo if (mhdl->status == LDC_BOUND || mhdl->memseg != NULL) { 43351991Sheppo DWARN(ldcp->id, 43361991Sheppo "ldc_mem_bind_handle: (0x%x) handle already bound\n", 43371991Sheppo mhandle); 43381991Sheppo mutex_exit(&mhdl->lock); 43391991Sheppo return (EINVAL); 43401991Sheppo } 43411991Sheppo 43421991Sheppo /* Force address and size to be 8-byte aligned */ 43431991Sheppo if ((((uintptr_t)vaddr | len) & 0x7) != 0) { 43441991Sheppo DWARN(ldcp->id, 43451991Sheppo "ldc_mem_bind_handle: addr/size is not 8-byte aligned\n"); 43461991Sheppo mutex_exit(&mhdl->lock); 43471991Sheppo return (EINVAL); 43481991Sheppo } 43491991Sheppo 43502531Snarayan /* 43512531Snarayan * If this channel is binding a memory handle for the 43522531Snarayan * first time allocate it a memory map table and initialize it 43532531Snarayan */ 43542531Snarayan if ((mtbl = ldcp->mtbl) == NULL) { 43552531Snarayan 43562531Snarayan mutex_enter(&ldcp->lock); 43572531Snarayan 43582531Snarayan /* Allocate and initialize the map table structure */ 43592531Snarayan mtbl = kmem_zalloc(sizeof (ldc_mtbl_t), KM_SLEEP); 43602531Snarayan mtbl->num_entries = mtbl->num_avail = ldc_maptable_entries; 43612531Snarayan mtbl->size = ldc_maptable_entries * sizeof (ldc_mte_slot_t); 43622531Snarayan mtbl->next_entry = NULL; 43632793Slm66018 mtbl->contigmem = B_TRUE; 43642531Snarayan 43652531Snarayan /* Allocate the table itself */ 43662531Snarayan mtbl->table = (ldc_mte_slot_t *) 43672531Snarayan contig_mem_alloc_align(mtbl->size, MMU_PAGESIZE); 43682531Snarayan if (mtbl->table == NULL) { 43692793Slm66018 43702793Slm66018 /* allocate a page of memory using kmem_alloc */ 43712793Slm66018 mtbl->table = kmem_alloc(MMU_PAGESIZE, KM_SLEEP); 43722793Slm66018 mtbl->size = MMU_PAGESIZE; 43732793Slm66018 mtbl->contigmem = B_FALSE; 43742793Slm66018 mtbl->num_entries = mtbl->num_avail = 43752793Slm66018 mtbl->size / sizeof (ldc_mte_slot_t); 43762793Slm66018 DWARN(ldcp->id, 43772793Slm66018 "ldc_mem_bind_handle: (0x%llx) reduced tbl size " 43782793Slm66018 "to %lx entries\n", ldcp->id, mtbl->num_entries); 43792531Snarayan } 43802531Snarayan 43812531Snarayan /* zero out the memory */ 43822531Snarayan bzero(mtbl->table, mtbl->size); 43832531Snarayan 43842531Snarayan /* initialize the lock */ 43852531Snarayan mutex_init(&mtbl->lock, NULL, MUTEX_DRIVER, NULL); 43862531Snarayan 43872531Snarayan /* register table for this channel */ 43882531Snarayan rv = hv_ldc_set_map_table(ldcp->id, 43892531Snarayan va_to_pa(mtbl->table), mtbl->num_entries); 43902531Snarayan if (rv != 0) { 43912531Snarayan cmn_err(CE_WARN, 43922531Snarayan "ldc_mem_bind_handle: (0x%lx) err %d mapping tbl", 43932531Snarayan ldcp->id, rv); 43942793Slm66018 if (mtbl->contigmem) 43952793Slm66018 contig_mem_free(mtbl->table, mtbl->size); 43962793Slm66018 else 43972793Slm66018 kmem_free(mtbl->table, mtbl->size); 43982531Snarayan mutex_destroy(&mtbl->lock); 43992531Snarayan kmem_free(mtbl, sizeof (ldc_mtbl_t)); 44002531Snarayan mutex_exit(&ldcp->lock); 44012531Snarayan mutex_exit(&mhdl->lock); 44022531Snarayan return (EIO); 44032531Snarayan } 44042531Snarayan 44052531Snarayan ldcp->mtbl = mtbl; 44062531Snarayan mutex_exit(&ldcp->lock); 44072531Snarayan 44082531Snarayan D1(ldcp->id, 44092531Snarayan "ldc_mem_bind_handle: (0x%llx) alloc'd map table 0x%llx\n", 44102531Snarayan ldcp->id, ldcp->mtbl->table); 44112531Snarayan } 44122531Snarayan 44131991Sheppo /* FUTURE: get the page size, pgsz code, and shift */ 44141991Sheppo pg_size = MMU_PAGESIZE; 44151991Sheppo pg_size_code = page_szc(pg_size); 44161991Sheppo pg_shift = page_get_shift(pg_size_code); 44171991Sheppo pg_mask = ~(pg_size - 1); 44181991Sheppo 44191991Sheppo D1(ldcp->id, "ldc_mem_bind_handle: (0x%llx) binding " 44201991Sheppo "va 0x%llx pgsz=0x%llx, pgszc=0x%llx, pg_shift=0x%llx\n", 44211991Sheppo ldcp->id, vaddr, pg_size, pg_size_code, pg_shift); 44221991Sheppo 44231991Sheppo /* aligned VA and its offset */ 44241991Sheppo v_align = (caddr_t)(((uintptr_t)vaddr) & ~(pg_size - 1)); 44251991Sheppo v_offset = ((uintptr_t)vaddr) & (pg_size - 1); 44261991Sheppo 44271991Sheppo npages = (len+v_offset)/pg_size; 44281991Sheppo npages = ((len+v_offset)%pg_size == 0) ? npages : npages+1; 44291991Sheppo 44301991Sheppo D1(ldcp->id, "ldc_mem_bind_handle: binding " 44311991Sheppo "(0x%llx) v=0x%llx,val=0x%llx,off=0x%x,pgs=0x%x\n", 44321991Sheppo ldcp->id, vaddr, v_align, v_offset, npages); 44331991Sheppo 44341991Sheppo /* lock the memory table - exclusive access to channel */ 44351991Sheppo mutex_enter(&mtbl->lock); 44361991Sheppo 44371991Sheppo if (npages > mtbl->num_avail) { 44382793Slm66018 D1(ldcp->id, "ldc_mem_bind_handle: (0x%llx) no table entries\n", 44391991Sheppo ldcp->id); 44401991Sheppo mutex_exit(&mtbl->lock); 44411991Sheppo mutex_exit(&mhdl->lock); 44421991Sheppo return (ENOMEM); 44431991Sheppo } 44441991Sheppo 44451991Sheppo /* Allocate a memseg structure */ 44462531Snarayan memseg = mhdl->memseg = 44472531Snarayan kmem_cache_alloc(ldcssp->memseg_cache, KM_SLEEP); 44481991Sheppo 44491991Sheppo /* Allocate memory to store all pages and cookies */ 44501991Sheppo memseg->pages = kmem_zalloc((sizeof (ldc_page_t) * npages), KM_SLEEP); 44511991Sheppo memseg->cookies = 44521991Sheppo kmem_zalloc((sizeof (ldc_mem_cookie_t) * npages), KM_SLEEP); 44531991Sheppo 44541991Sheppo D2(ldcp->id, "ldc_mem_bind_handle: (0x%llx) processing 0x%llx pages\n", 44551991Sheppo ldcp->id, npages); 44561991Sheppo 44571991Sheppo addr = v_align; 44581991Sheppo 44591991Sheppo /* 44602531Snarayan * Check if direct shared memory map is enabled, if not change 44612531Snarayan * the mapping type to include SHADOW_MAP. 44622531Snarayan */ 44632531Snarayan if (ldc_shmem_enabled == 0) 44642531Snarayan mtype = LDC_SHADOW_MAP; 44652531Snarayan 44662531Snarayan /* 44671991Sheppo * Table slots are used in a round-robin manner. The algorithm permits 44681991Sheppo * inserting duplicate entries. Slots allocated earlier will typically 44691991Sheppo * get freed before we get back to reusing the slot.Inserting duplicate 44701991Sheppo * entries should be OK as we only lookup entries using the cookie addr 44711991Sheppo * i.e. tbl index, during export, unexport and copy operation. 44721991Sheppo * 44731991Sheppo * One implementation what was tried was to search for a duplicate 44741991Sheppo * page entry first and reuse it. The search overhead is very high and 44751991Sheppo * in the vnet case dropped the perf by almost half, 50 to 24 mbps. 44761991Sheppo * So it does make sense to avoid searching for duplicates. 44771991Sheppo * 44781991Sheppo * But during the process of searching for a free slot, if we find a 44791991Sheppo * duplicate entry we will go ahead and use it, and bump its use count. 44801991Sheppo */ 44811991Sheppo 44821991Sheppo /* index to start searching from */ 44831991Sheppo index = mtbl->next_entry; 44841991Sheppo cookie_idx = -1; 44851991Sheppo 44861991Sheppo tmp_mte.ll = 0; /* initialise fields to 0 */ 44871991Sheppo 44881991Sheppo if (mtype & LDC_DIRECT_MAP) { 44891991Sheppo tmp_mte.mte_r = (perm & LDC_MEM_R) ? 1 : 0; 44901991Sheppo tmp_mte.mte_w = (perm & LDC_MEM_W) ? 1 : 0; 44911991Sheppo tmp_mte.mte_x = (perm & LDC_MEM_X) ? 1 : 0; 44921991Sheppo } 44931991Sheppo 44941991Sheppo if (mtype & LDC_SHADOW_MAP) { 44951991Sheppo tmp_mte.mte_cr = (perm & LDC_MEM_R) ? 1 : 0; 44961991Sheppo tmp_mte.mte_cw = (perm & LDC_MEM_W) ? 1 : 0; 44971991Sheppo } 44981991Sheppo 44991991Sheppo if (mtype & LDC_IO_MAP) { 45001991Sheppo tmp_mte.mte_ir = (perm & LDC_MEM_R) ? 1 : 0; 45011991Sheppo tmp_mte.mte_iw = (perm & LDC_MEM_W) ? 1 : 0; 45021991Sheppo } 45031991Sheppo 45041991Sheppo D1(ldcp->id, "ldc_mem_bind_handle mte=0x%llx\n", tmp_mte.ll); 45051991Sheppo 45061991Sheppo tmp_mte.mte_pgszc = pg_size_code; 45071991Sheppo 45081991Sheppo /* initialize each mem table entry */ 45091991Sheppo for (i = 0; i < npages; i++) { 45101991Sheppo 45111991Sheppo /* check if slot is available in the table */ 45121991Sheppo while (mtbl->table[index].entry.ll != 0) { 45131991Sheppo 45141991Sheppo index = (index + 1) % mtbl->num_entries; 45151991Sheppo 45161991Sheppo if (index == mtbl->next_entry) { 45171991Sheppo /* we have looped around */ 45181991Sheppo DWARN(DBG_ALL_LDCS, 45191991Sheppo "ldc_mem_bind_handle: (0x%llx) cannot find " 45201991Sheppo "entry\n", ldcp->id); 45211991Sheppo *ccount = 0; 45221991Sheppo 45231991Sheppo /* NOTE: free memory, remove previous entries */ 45241991Sheppo /* this shouldnt happen as num_avail was ok */ 45251991Sheppo 45261991Sheppo mutex_exit(&mtbl->lock); 45271991Sheppo mutex_exit(&mhdl->lock); 45281991Sheppo return (ENOMEM); 45291991Sheppo } 45301991Sheppo } 45311991Sheppo 45321991Sheppo /* get the real address */ 45331991Sheppo raddr = va_to_pa((void *)addr); 45341991Sheppo ra_aligned = ((uintptr_t)raddr & pg_mask); 45351991Sheppo 45361991Sheppo /* build the mte */ 45371991Sheppo tmp_mte.mte_rpfn = ra_aligned >> pg_shift; 45381991Sheppo 45391991Sheppo D1(ldcp->id, "ldc_mem_bind_handle mte=0x%llx\n", tmp_mte.ll); 45401991Sheppo 45411991Sheppo /* update entry in table */ 45421991Sheppo mtbl->table[index].entry = tmp_mte; 45431991Sheppo 45441991Sheppo D2(ldcp->id, "ldc_mem_bind_handle: (0x%llx) stored MTE 0x%llx" 45451991Sheppo " into loc 0x%llx\n", ldcp->id, tmp_mte.ll, index); 45461991Sheppo 45471991Sheppo /* calculate the size and offset for this export range */ 45481991Sheppo if (i == 0) { 45491991Sheppo /* first page */ 45501991Sheppo psize = min((pg_size - v_offset), len); 45511991Sheppo poffset = v_offset; 45521991Sheppo 45531991Sheppo } else if (i == (npages - 1)) { 45541991Sheppo /* last page */ 45551991Sheppo psize = (((uintptr_t)(vaddr + len)) & 45561991Sheppo ((uint64_t)(pg_size-1))); 45571991Sheppo if (psize == 0) 45581991Sheppo psize = pg_size; 45591991Sheppo poffset = 0; 45601991Sheppo 45611991Sheppo } else { 45621991Sheppo /* middle pages */ 45631991Sheppo psize = pg_size; 45641991Sheppo poffset = 0; 45651991Sheppo } 45661991Sheppo 45671991Sheppo /* store entry for this page */ 45681991Sheppo memseg->pages[i].index = index; 45691991Sheppo memseg->pages[i].raddr = raddr; 45701991Sheppo memseg->pages[i].offset = poffset; 45711991Sheppo memseg->pages[i].size = psize; 45721991Sheppo memseg->pages[i].mte = &(mtbl->table[index]); 45731991Sheppo 45741991Sheppo /* create the cookie */ 45751991Sheppo if (i == 0 || (index != prev_index + 1)) { 45761991Sheppo cookie_idx++; 45771991Sheppo memseg->cookies[cookie_idx].addr = 45781991Sheppo IDX2COOKIE(index, pg_size_code, pg_shift); 45791991Sheppo memseg->cookies[cookie_idx].addr |= poffset; 45801991Sheppo memseg->cookies[cookie_idx].size = psize; 45811991Sheppo 45821991Sheppo } else { 45831991Sheppo memseg->cookies[cookie_idx].size += psize; 45841991Sheppo } 45851991Sheppo 45861991Sheppo D1(ldcp->id, "ldc_mem_bind_handle: bound " 45871991Sheppo "(0x%llx) va=0x%llx, idx=0x%llx, " 45881991Sheppo "ra=0x%llx(sz=0x%x,off=0x%x)\n", 45891991Sheppo ldcp->id, addr, index, raddr, psize, poffset); 45901991Sheppo 45911991Sheppo /* decrement number of available entries */ 45921991Sheppo mtbl->num_avail--; 45931991Sheppo 45941991Sheppo /* increment va by page size */ 45951991Sheppo addr += pg_size; 45961991Sheppo 45971991Sheppo /* increment index */ 45981991Sheppo prev_index = index; 45991991Sheppo index = (index + 1) % mtbl->num_entries; 46001991Sheppo 46011991Sheppo /* save the next slot */ 46021991Sheppo mtbl->next_entry = index; 46031991Sheppo } 46041991Sheppo 46051991Sheppo mutex_exit(&mtbl->lock); 46061991Sheppo 46071991Sheppo /* memory handle = bound */ 46081991Sheppo mhdl->mtype = mtype; 46091991Sheppo mhdl->perm = perm; 46101991Sheppo mhdl->status = LDC_BOUND; 46111991Sheppo 46121991Sheppo /* update memseg_t */ 46131991Sheppo memseg->vaddr = vaddr; 46141991Sheppo memseg->raddr = memseg->pages[0].raddr; 46151991Sheppo memseg->size = len; 46161991Sheppo memseg->npages = npages; 46171991Sheppo memseg->ncookies = cookie_idx + 1; 46181991Sheppo memseg->next_cookie = (memseg->ncookies > 1) ? 1 : 0; 46191991Sheppo 46201991Sheppo /* return count and first cookie */ 46211991Sheppo *ccount = memseg->ncookies; 46221991Sheppo cookie->addr = memseg->cookies[0].addr; 46231991Sheppo cookie->size = memseg->cookies[0].size; 46241991Sheppo 46251991Sheppo D1(ldcp->id, 46261991Sheppo "ldc_mem_bind_handle: (0x%llx) bound 0x%llx, va=0x%llx, " 46271991Sheppo "pgs=0x%llx cookies=0x%llx\n", 46281991Sheppo ldcp->id, mhdl, vaddr, npages, memseg->ncookies); 46291991Sheppo 46301991Sheppo mutex_exit(&mhdl->lock); 46311991Sheppo return (0); 46321991Sheppo } 46331991Sheppo 46341991Sheppo /* 46351991Sheppo * Return the next cookie associated with the specified memory handle 46361991Sheppo */ 46371991Sheppo int 46381991Sheppo ldc_mem_nextcookie(ldc_mem_handle_t mhandle, ldc_mem_cookie_t *cookie) 46391991Sheppo { 46401991Sheppo ldc_mhdl_t *mhdl; 46411991Sheppo ldc_chan_t *ldcp; 46421991Sheppo ldc_memseg_t *memseg; 46431991Sheppo 46441991Sheppo if (mhandle == NULL) { 46451991Sheppo DWARN(DBG_ALL_LDCS, 46461991Sheppo "ldc_mem_nextcookie: invalid memory handle\n"); 46471991Sheppo return (EINVAL); 46481991Sheppo } 46491991Sheppo mhdl = (ldc_mhdl_t *)mhandle; 46501991Sheppo 46511991Sheppo mutex_enter(&mhdl->lock); 46521991Sheppo 46531991Sheppo ldcp = mhdl->ldcp; 46541991Sheppo memseg = mhdl->memseg; 46551991Sheppo 46561991Sheppo if (cookie == 0) { 46571991Sheppo DWARN(ldcp->id, 46581991Sheppo "ldc_mem_nextcookie:(0x%llx) invalid cookie arg\n", 46591991Sheppo ldcp->id); 46601991Sheppo mutex_exit(&mhdl->lock); 46611991Sheppo return (EINVAL); 46621991Sheppo } 46631991Sheppo 46641991Sheppo if (memseg->next_cookie != 0) { 46651991Sheppo cookie->addr = memseg->cookies[memseg->next_cookie].addr; 46661991Sheppo cookie->size = memseg->cookies[memseg->next_cookie].size; 46671991Sheppo memseg->next_cookie++; 46681991Sheppo if (memseg->next_cookie == memseg->ncookies) 46691991Sheppo memseg->next_cookie = 0; 46701991Sheppo 46711991Sheppo } else { 46721991Sheppo DWARN(ldcp->id, 46731991Sheppo "ldc_mem_nextcookie:(0x%llx) no more cookies\n", ldcp->id); 46741991Sheppo cookie->addr = 0; 46751991Sheppo cookie->size = 0; 46761991Sheppo mutex_exit(&mhdl->lock); 46771991Sheppo return (EINVAL); 46781991Sheppo } 46791991Sheppo 46801991Sheppo D1(ldcp->id, 46811991Sheppo "ldc_mem_nextcookie: (0x%llx) cookie addr=0x%llx,sz=0x%llx\n", 46821991Sheppo ldcp->id, cookie->addr, cookie->size); 46831991Sheppo 46841991Sheppo mutex_exit(&mhdl->lock); 46851991Sheppo return (0); 46861991Sheppo } 46871991Sheppo 46881991Sheppo /* 46891991Sheppo * Unbind the virtual memory region associated with the specified 46901991Sheppo * memory handle. Allassociated cookies are freed and the corresponding 46911991Sheppo * RA space is no longer exported. 46921991Sheppo */ 46931991Sheppo int 46941991Sheppo ldc_mem_unbind_handle(ldc_mem_handle_t mhandle) 46951991Sheppo { 46961991Sheppo ldc_mhdl_t *mhdl; 46971991Sheppo ldc_chan_t *ldcp; 46981991Sheppo ldc_mtbl_t *mtbl; 46991991Sheppo ldc_memseg_t *memseg; 47002531Snarayan uint64_t cookie_addr; 47012531Snarayan uint64_t pg_shift, pg_size_code; 47022531Snarayan int i, rv; 47031991Sheppo 47041991Sheppo if (mhandle == NULL) { 47051991Sheppo DWARN(DBG_ALL_LDCS, 47061991Sheppo "ldc_mem_unbind_handle: invalid memory handle\n"); 47071991Sheppo return (EINVAL); 47081991Sheppo } 47091991Sheppo mhdl = (ldc_mhdl_t *)mhandle; 47101991Sheppo 47111991Sheppo mutex_enter(&mhdl->lock); 47121991Sheppo 47131991Sheppo if (mhdl->status == LDC_UNBOUND) { 47141991Sheppo DWARN(DBG_ALL_LDCS, 47151991Sheppo "ldc_mem_unbind_handle: (0x%x) handle is not bound\n", 47161991Sheppo mhandle); 47171991Sheppo mutex_exit(&mhdl->lock); 47181991Sheppo return (EINVAL); 47191991Sheppo } 47201991Sheppo 47211991Sheppo ldcp = mhdl->ldcp; 47221991Sheppo mtbl = ldcp->mtbl; 47231991Sheppo 47241991Sheppo memseg = mhdl->memseg; 47251991Sheppo 47261991Sheppo /* lock the memory table - exclusive access to channel */ 47271991Sheppo mutex_enter(&mtbl->lock); 47281991Sheppo 47291991Sheppo /* undo the pages exported */ 47301991Sheppo for (i = 0; i < memseg->npages; i++) { 47311991Sheppo 47322531Snarayan /* check for mapped pages, revocation cookie != 0 */ 47331991Sheppo if (memseg->pages[i].mte->cookie) { 47342531Snarayan 47352531Snarayan pg_size_code = page_szc(memseg->pages[i].size); 47362531Snarayan pg_shift = page_get_shift(memseg->pages[i].size); 47372531Snarayan cookie_addr = IDX2COOKIE(memseg->pages[i].index, 47382531Snarayan pg_size_code, pg_shift); 47392531Snarayan 47402531Snarayan D1(ldcp->id, "ldc_mem_unbind_handle: (0x%llx) revoke " 47412531Snarayan "cookie 0x%llx, rcookie 0x%llx\n", ldcp->id, 47422531Snarayan cookie_addr, memseg->pages[i].mte->cookie); 47432531Snarayan rv = hv_ldc_revoke(ldcp->id, cookie_addr, 47442531Snarayan memseg->pages[i].mte->cookie); 47452531Snarayan if (rv) { 47462531Snarayan DWARN(ldcp->id, 47472531Snarayan "ldc_mem_unbind_handle: (0x%llx) cannot " 47482531Snarayan "revoke mapping, cookie %llx\n", ldcp->id, 47492531Snarayan cookie_addr); 47502531Snarayan } 47511991Sheppo } 47521991Sheppo 47531991Sheppo /* clear the entry from the table */ 47541991Sheppo memseg->pages[i].mte->entry.ll = 0; 47551991Sheppo mtbl->num_avail++; 47561991Sheppo } 47571991Sheppo mutex_exit(&mtbl->lock); 47581991Sheppo 47591991Sheppo /* free the allocated memseg and page structures */ 47601991Sheppo kmem_free(memseg->pages, (sizeof (ldc_page_t) * memseg->npages)); 47611991Sheppo kmem_free(memseg->cookies, 47621991Sheppo (sizeof (ldc_mem_cookie_t) * memseg->npages)); 47632531Snarayan kmem_cache_free(ldcssp->memseg_cache, memseg); 47641991Sheppo 47651991Sheppo /* uninitialize the memory handle */ 47661991Sheppo mhdl->memseg = NULL; 47671991Sheppo mhdl->status = LDC_UNBOUND; 47681991Sheppo 47691991Sheppo D1(ldcp->id, "ldc_mem_unbind_handle: (0x%llx) unbound handle 0x%llx\n", 47701991Sheppo ldcp->id, mhdl); 47711991Sheppo 47721991Sheppo mutex_exit(&mhdl->lock); 47731991Sheppo return (0); 47741991Sheppo } 47751991Sheppo 47761991Sheppo /* 47771991Sheppo * Get information about the dring. The base address of the descriptor 47781991Sheppo * ring along with the type and permission are returned back. 47791991Sheppo */ 47801991Sheppo int 47811991Sheppo ldc_mem_info(ldc_mem_handle_t mhandle, ldc_mem_info_t *minfo) 47821991Sheppo { 47831991Sheppo ldc_mhdl_t *mhdl; 47841991Sheppo 47851991Sheppo if (mhandle == NULL) { 47861991Sheppo DWARN(DBG_ALL_LDCS, "ldc_mem_info: invalid memory handle\n"); 47871991Sheppo return (EINVAL); 47881991Sheppo } 47891991Sheppo mhdl = (ldc_mhdl_t *)mhandle; 47901991Sheppo 47911991Sheppo if (minfo == NULL) { 47921991Sheppo DWARN(DBG_ALL_LDCS, "ldc_mem_info: invalid args\n"); 47931991Sheppo return (EINVAL); 47941991Sheppo } 47951991Sheppo 47961991Sheppo mutex_enter(&mhdl->lock); 47971991Sheppo 47981991Sheppo minfo->status = mhdl->status; 47991991Sheppo if (mhdl->status == LDC_BOUND || mhdl->status == LDC_MAPPED) { 48001991Sheppo minfo->vaddr = mhdl->memseg->vaddr; 48011991Sheppo minfo->raddr = mhdl->memseg->raddr; 48021991Sheppo minfo->mtype = mhdl->mtype; 48031991Sheppo minfo->perm = mhdl->perm; 48041991Sheppo } 48051991Sheppo mutex_exit(&mhdl->lock); 48061991Sheppo 48071991Sheppo return (0); 48081991Sheppo } 48091991Sheppo 48101991Sheppo /* 48111991Sheppo * Copy data either from or to the client specified virtual address 48121991Sheppo * space to or from the exported memory associated with the cookies. 48131991Sheppo * The direction argument determines whether the data is read from or 48141991Sheppo * written to exported memory. 48151991Sheppo */ 48161991Sheppo int 48171991Sheppo ldc_mem_copy(ldc_handle_t handle, caddr_t vaddr, uint64_t off, size_t *size, 48181991Sheppo ldc_mem_cookie_t *cookies, uint32_t ccount, uint8_t direction) 48191991Sheppo { 48201991Sheppo ldc_chan_t *ldcp; 48211991Sheppo uint64_t local_voff, local_valign; 48221991Sheppo uint64_t cookie_addr, cookie_size; 48231991Sheppo uint64_t pg_shift, pg_size, pg_size_code; 48241991Sheppo uint64_t export_caddr, export_poff, export_psize, export_size; 48251991Sheppo uint64_t local_ra, local_poff, local_psize; 48261991Sheppo uint64_t copy_size, copied_len = 0, total_bal = 0, idx = 0; 48271991Sheppo pgcnt_t npages; 48281991Sheppo size_t len = *size; 48291991Sheppo int i, rv = 0; 48301991Sheppo 48312793Slm66018 uint64_t chid; 48322793Slm66018 48331991Sheppo if (handle == NULL) { 48341991Sheppo DWARN(DBG_ALL_LDCS, "ldc_mem_copy: invalid channel handle\n"); 48351991Sheppo return (EINVAL); 48361991Sheppo } 48371991Sheppo ldcp = (ldc_chan_t *)handle; 48382793Slm66018 chid = ldcp->id; 48391991Sheppo 48401991Sheppo /* check to see if channel is UP */ 48411991Sheppo if (ldcp->tstate != TS_UP) { 48422793Slm66018 DWARN(chid, "ldc_mem_copy: (0x%llx) channel is not UP\n", 48432793Slm66018 chid); 48442793Slm66018 return (ECONNRESET); 48451991Sheppo } 48461991Sheppo 48471991Sheppo /* Force address and size to be 8-byte aligned */ 48481991Sheppo if ((((uintptr_t)vaddr | len) & 0x7) != 0) { 48492793Slm66018 DWARN(chid, 48501991Sheppo "ldc_mem_copy: addr/sz is not 8-byte aligned\n"); 48511991Sheppo return (EINVAL); 48521991Sheppo } 48531991Sheppo 48541991Sheppo /* Find the size of the exported memory */ 48551991Sheppo export_size = 0; 48561991Sheppo for (i = 0; i < ccount; i++) 48571991Sheppo export_size += cookies[i].size; 48581991Sheppo 48591991Sheppo /* check to see if offset is valid */ 48601991Sheppo if (off > export_size) { 48612793Slm66018 DWARN(chid, 48621991Sheppo "ldc_mem_copy: (0x%llx) start offset > export mem size\n", 48632793Slm66018 chid); 48641991Sheppo return (EINVAL); 48651991Sheppo } 48661991Sheppo 48671991Sheppo /* 48681991Sheppo * Check to see if the export size is smaller than the size we 48691991Sheppo * are requesting to copy - if so flag an error 48701991Sheppo */ 48711991Sheppo if ((export_size - off) < *size) { 48722793Slm66018 DWARN(chid, 48731991Sheppo "ldc_mem_copy: (0x%llx) copy size > export mem size\n", 48742793Slm66018 chid); 48751991Sheppo return (EINVAL); 48761991Sheppo } 48771991Sheppo 48781991Sheppo total_bal = min(export_size, *size); 48791991Sheppo 48801991Sheppo /* FUTURE: get the page size, pgsz code, and shift */ 48811991Sheppo pg_size = MMU_PAGESIZE; 48821991Sheppo pg_size_code = page_szc(pg_size); 48831991Sheppo pg_shift = page_get_shift(pg_size_code); 48841991Sheppo 48852793Slm66018 D1(chid, "ldc_mem_copy: copying data " 48861991Sheppo "(0x%llx) va 0x%llx pgsz=0x%llx, pgszc=0x%llx, pg_shift=0x%llx\n", 48872793Slm66018 chid, vaddr, pg_size, pg_size_code, pg_shift); 48881991Sheppo 48891991Sheppo /* aligned VA and its offset */ 48901991Sheppo local_valign = (((uintptr_t)vaddr) & ~(pg_size - 1)); 48911991Sheppo local_voff = ((uintptr_t)vaddr) & (pg_size - 1); 48921991Sheppo 48931991Sheppo npages = (len+local_voff)/pg_size; 48941991Sheppo npages = ((len+local_voff)%pg_size == 0) ? npages : npages+1; 48951991Sheppo 48962793Slm66018 D1(chid, 48971991Sheppo "ldc_mem_copy: (0x%llx) v=0x%llx,val=0x%llx,off=0x%x,pgs=0x%x\n", 48982793Slm66018 chid, vaddr, local_valign, local_voff, npages); 48991991Sheppo 49001991Sheppo local_ra = va_to_pa((void *)local_valign); 49011991Sheppo local_poff = local_voff; 49021991Sheppo local_psize = min(len, (pg_size - local_voff)); 49031991Sheppo 49041991Sheppo len -= local_psize; 49051991Sheppo 49061991Sheppo /* 49071991Sheppo * find the first cookie in the list of cookies 49081991Sheppo * if the offset passed in is not zero 49091991Sheppo */ 49101991Sheppo for (idx = 0; idx < ccount; idx++) { 49111991Sheppo cookie_size = cookies[idx].size; 49121991Sheppo if (off < cookie_size) 49131991Sheppo break; 49141991Sheppo off -= cookie_size; 49151991Sheppo } 49161991Sheppo 49171991Sheppo cookie_addr = cookies[idx].addr + off; 49181991Sheppo cookie_size = cookies[idx].size - off; 49191991Sheppo 49201991Sheppo export_caddr = cookie_addr & ~(pg_size - 1); 49211991Sheppo export_poff = cookie_addr & (pg_size - 1); 49221991Sheppo export_psize = min(cookie_size, (pg_size - export_poff)); 49231991Sheppo 49241991Sheppo for (;;) { 49251991Sheppo 49261991Sheppo copy_size = min(export_psize, local_psize); 49271991Sheppo 49282793Slm66018 D1(chid, 49291991Sheppo "ldc_mem_copy:(0x%llx) dir=0x%x, caddr=0x%llx," 49301991Sheppo " loc_ra=0x%llx, exp_poff=0x%llx, loc_poff=0x%llx," 49311991Sheppo " exp_psz=0x%llx, loc_psz=0x%llx, copy_sz=0x%llx," 49321991Sheppo " total_bal=0x%llx\n", 49332793Slm66018 chid, direction, export_caddr, local_ra, export_poff, 49341991Sheppo local_poff, export_psize, local_psize, copy_size, 49351991Sheppo total_bal); 49361991Sheppo 49372793Slm66018 rv = hv_ldc_copy(chid, direction, 49381991Sheppo (export_caddr + export_poff), (local_ra + local_poff), 49391991Sheppo copy_size, &copied_len); 49401991Sheppo 49411991Sheppo if (rv != 0) { 49422793Slm66018 int error = EIO; 49432793Slm66018 uint64_t rx_hd, rx_tl; 49442793Slm66018 49452793Slm66018 DWARN(chid, 49462793Slm66018 "ldc_mem_copy: (0x%llx) err %d during copy\n", 49472793Slm66018 (unsigned long long)chid, rv); 49482793Slm66018 DWARN(chid, 49492793Slm66018 "ldc_mem_copy: (0x%llx) dir=0x%x, caddr=0x%lx, " 49502531Snarayan "loc_ra=0x%lx, exp_poff=0x%lx, loc_poff=0x%lx," 49512531Snarayan " exp_psz=0x%lx, loc_psz=0x%lx, copy_sz=0x%lx," 49522531Snarayan " copied_len=0x%lx, total_bal=0x%lx\n", 49532793Slm66018 chid, direction, export_caddr, local_ra, 49541991Sheppo export_poff, local_poff, export_psize, local_psize, 49551991Sheppo copy_size, copied_len, total_bal); 49561991Sheppo 49571991Sheppo *size = *size - total_bal; 49582793Slm66018 49592793Slm66018 /* 49602793Slm66018 * check if reason for copy error was due to 49612793Slm66018 * a channel reset. we need to grab the lock 49622793Slm66018 * just in case we have to do a reset. 49632793Slm66018 */ 49642793Slm66018 mutex_enter(&ldcp->lock); 49652793Slm66018 mutex_enter(&ldcp->tx_lock); 49662793Slm66018 49672793Slm66018 rv = hv_ldc_rx_get_state(ldcp->id, 49682793Slm66018 &rx_hd, &rx_tl, &(ldcp->link_state)); 49692793Slm66018 if (ldcp->link_state == LDC_CHANNEL_DOWN || 49702793Slm66018 ldcp->link_state == LDC_CHANNEL_RESET) { 49712793Slm66018 i_ldc_reset(ldcp, B_FALSE); 49722793Slm66018 error = ECONNRESET; 49732793Slm66018 } 49742793Slm66018 49752793Slm66018 mutex_exit(&ldcp->tx_lock); 49761991Sheppo mutex_exit(&ldcp->lock); 49772793Slm66018 49782793Slm66018 return (error); 49791991Sheppo } 49801991Sheppo 49811991Sheppo ASSERT(copied_len <= copy_size); 49821991Sheppo 49832793Slm66018 D2(chid, "ldc_mem_copy: copied=0x%llx\n", copied_len); 49841991Sheppo export_poff += copied_len; 49851991Sheppo local_poff += copied_len; 49861991Sheppo export_psize -= copied_len; 49871991Sheppo local_psize -= copied_len; 49881991Sheppo cookie_size -= copied_len; 49891991Sheppo 49901991Sheppo total_bal -= copied_len; 49911991Sheppo 49921991Sheppo if (copy_size != copied_len) 49931991Sheppo continue; 49941991Sheppo 49951991Sheppo if (export_psize == 0 && total_bal != 0) { 49961991Sheppo 49971991Sheppo if (cookie_size == 0) { 49981991Sheppo idx++; 49991991Sheppo cookie_addr = cookies[idx].addr; 50001991Sheppo cookie_size = cookies[idx].size; 50011991Sheppo 50021991Sheppo export_caddr = cookie_addr & ~(pg_size - 1); 50031991Sheppo export_poff = cookie_addr & (pg_size - 1); 50041991Sheppo export_psize = 50051991Sheppo min(cookie_size, (pg_size-export_poff)); 50061991Sheppo } else { 50071991Sheppo export_caddr += pg_size; 50081991Sheppo export_poff = 0; 50091991Sheppo export_psize = min(cookie_size, pg_size); 50101991Sheppo } 50111991Sheppo } 50121991Sheppo 50131991Sheppo if (local_psize == 0 && total_bal != 0) { 50141991Sheppo local_valign += pg_size; 50151991Sheppo local_ra = va_to_pa((void *)local_valign); 50161991Sheppo local_poff = 0; 50171991Sheppo local_psize = min(pg_size, len); 50181991Sheppo len -= local_psize; 50191991Sheppo } 50201991Sheppo 50211991Sheppo /* check if we are all done */ 50221991Sheppo if (total_bal == 0) 50231991Sheppo break; 50241991Sheppo } 50251991Sheppo 50262793Slm66018 50272793Slm66018 D1(chid, 50281991Sheppo "ldc_mem_copy: (0x%llx) done copying sz=0x%llx\n", 50292793Slm66018 chid, *size); 50301991Sheppo 50311991Sheppo return (0); 50321991Sheppo } 50331991Sheppo 50341991Sheppo /* 50351991Sheppo * Copy data either from or to the client specified virtual address 50361991Sheppo * space to or from HV physical memory. 50371991Sheppo * 50381991Sheppo * The direction argument determines whether the data is read from or 50391991Sheppo * written to HV memory. direction values are LDC_COPY_IN/OUT similar 50401991Sheppo * to the ldc_mem_copy interface 50411991Sheppo */ 50421991Sheppo int 50432793Slm66018 ldc_mem_rdwr_cookie(ldc_handle_t handle, caddr_t vaddr, size_t *size, 50441991Sheppo caddr_t paddr, uint8_t direction) 50451991Sheppo { 50461991Sheppo ldc_chan_t *ldcp; 50471991Sheppo uint64_t local_voff, local_valign; 50481991Sheppo uint64_t pg_shift, pg_size, pg_size_code; 50491991Sheppo uint64_t target_pa, target_poff, target_psize, target_size; 50501991Sheppo uint64_t local_ra, local_poff, local_psize; 50511991Sheppo uint64_t copy_size, copied_len = 0; 50521991Sheppo pgcnt_t npages; 50531991Sheppo size_t len = *size; 50541991Sheppo int rv = 0; 50551991Sheppo 50561991Sheppo if (handle == NULL) { 50571991Sheppo DWARN(DBG_ALL_LDCS, 50582793Slm66018 "ldc_mem_rdwr_cookie: invalid channel handle\n"); 50591991Sheppo return (EINVAL); 50601991Sheppo } 50611991Sheppo ldcp = (ldc_chan_t *)handle; 50621991Sheppo 50631991Sheppo mutex_enter(&ldcp->lock); 50641991Sheppo 50651991Sheppo /* check to see if channel is UP */ 50661991Sheppo if (ldcp->tstate != TS_UP) { 50671991Sheppo DWARN(ldcp->id, 50682793Slm66018 "ldc_mem_rdwr_cookie: (0x%llx) channel is not UP\n", 50691991Sheppo ldcp->id); 50701991Sheppo mutex_exit(&ldcp->lock); 50712793Slm66018 return (ECONNRESET); 50721991Sheppo } 50731991Sheppo 50741991Sheppo /* Force address and size to be 8-byte aligned */ 50751991Sheppo if ((((uintptr_t)vaddr | len) & 0x7) != 0) { 50761991Sheppo DWARN(ldcp->id, 50772793Slm66018 "ldc_mem_rdwr_cookie: addr/size is not 8-byte aligned\n"); 50781991Sheppo mutex_exit(&ldcp->lock); 50791991Sheppo return (EINVAL); 50801991Sheppo } 50811991Sheppo 50821991Sheppo target_size = *size; 50831991Sheppo 50841991Sheppo /* FUTURE: get the page size, pgsz code, and shift */ 50851991Sheppo pg_size = MMU_PAGESIZE; 50861991Sheppo pg_size_code = page_szc(pg_size); 50871991Sheppo pg_shift = page_get_shift(pg_size_code); 50881991Sheppo 50892793Slm66018 D1(ldcp->id, "ldc_mem_rdwr_cookie: copying data " 50901991Sheppo "(0x%llx) va 0x%llx pgsz=0x%llx, pgszc=0x%llx, pg_shift=0x%llx\n", 50911991Sheppo ldcp->id, vaddr, pg_size, pg_size_code, pg_shift); 50921991Sheppo 50931991Sheppo /* aligned VA and its offset */ 50941991Sheppo local_valign = ((uintptr_t)vaddr) & ~(pg_size - 1); 50951991Sheppo local_voff = ((uintptr_t)vaddr) & (pg_size - 1); 50961991Sheppo 50971991Sheppo npages = (len + local_voff) / pg_size; 50981991Sheppo npages = ((len + local_voff) % pg_size == 0) ? npages : npages+1; 50991991Sheppo 51002793Slm66018 D1(ldcp->id, "ldc_mem_rdwr_cookie: (0x%llx) v=0x%llx, " 51012793Slm66018 "val=0x%llx,off=0x%x,pgs=0x%x\n", 51021991Sheppo ldcp->id, vaddr, local_valign, local_voff, npages); 51031991Sheppo 51041991Sheppo local_ra = va_to_pa((void *)local_valign); 51051991Sheppo local_poff = local_voff; 51061991Sheppo local_psize = min(len, (pg_size - local_voff)); 51071991Sheppo 51081991Sheppo len -= local_psize; 51091991Sheppo 51101991Sheppo target_pa = ((uintptr_t)paddr) & ~(pg_size - 1); 51111991Sheppo target_poff = ((uintptr_t)paddr) & (pg_size - 1); 51121991Sheppo target_psize = pg_size - target_poff; 51131991Sheppo 51141991Sheppo for (;;) { 51151991Sheppo 51161991Sheppo copy_size = min(target_psize, local_psize); 51171991Sheppo 51181991Sheppo D1(ldcp->id, 51192793Slm66018 "ldc_mem_rdwr_cookie: (0x%llx) dir=0x%x, tar_pa=0x%llx," 51201991Sheppo " loc_ra=0x%llx, tar_poff=0x%llx, loc_poff=0x%llx," 51211991Sheppo " tar_psz=0x%llx, loc_psz=0x%llx, copy_sz=0x%llx," 51221991Sheppo " total_bal=0x%llx\n", 51231991Sheppo ldcp->id, direction, target_pa, local_ra, target_poff, 51241991Sheppo local_poff, target_psize, local_psize, copy_size, 51251991Sheppo target_size); 51261991Sheppo 51271991Sheppo rv = hv_ldc_copy(ldcp->id, direction, 51281991Sheppo (target_pa + target_poff), (local_ra + local_poff), 51291991Sheppo copy_size, &copied_len); 51301991Sheppo 51311991Sheppo if (rv != 0) { 51322793Slm66018 DWARN(DBG_ALL_LDCS, 51332793Slm66018 "ldc_mem_rdwr_cookie: (0x%lx) err %d during copy\n", 51341991Sheppo ldcp->id, rv); 51351991Sheppo DWARN(DBG_ALL_LDCS, 51362793Slm66018 "ldc_mem_rdwr_cookie: (0x%llx) dir=%lld, " 51372793Slm66018 "tar_pa=0x%llx, loc_ra=0x%llx, tar_poff=0x%llx, " 51382793Slm66018 "loc_poff=0x%llx, tar_psz=0x%llx, loc_psz=0x%llx, " 51392793Slm66018 "copy_sz=0x%llx, total_bal=0x%llx\n", 51401991Sheppo ldcp->id, direction, target_pa, local_ra, 51411991Sheppo target_poff, local_poff, target_psize, local_psize, 51421991Sheppo copy_size, target_size); 51431991Sheppo 51441991Sheppo *size = *size - target_size; 51451991Sheppo mutex_exit(&ldcp->lock); 51461991Sheppo return (i_ldc_h2v_error(rv)); 51471991Sheppo } 51481991Sheppo 51492793Slm66018 D2(ldcp->id, "ldc_mem_rdwr_cookie: copied=0x%llx\n", 51502793Slm66018 copied_len); 51511991Sheppo target_poff += copied_len; 51521991Sheppo local_poff += copied_len; 51531991Sheppo target_psize -= copied_len; 51541991Sheppo local_psize -= copied_len; 51551991Sheppo 51561991Sheppo target_size -= copied_len; 51571991Sheppo 51581991Sheppo if (copy_size != copied_len) 51591991Sheppo continue; 51601991Sheppo 51611991Sheppo if (target_psize == 0 && target_size != 0) { 51621991Sheppo target_pa += pg_size; 51631991Sheppo target_poff = 0; 51641991Sheppo target_psize = min(pg_size, target_size); 51651991Sheppo } 51661991Sheppo 51671991Sheppo if (local_psize == 0 && target_size != 0) { 51681991Sheppo local_valign += pg_size; 51691991Sheppo local_ra = va_to_pa((void *)local_valign); 51701991Sheppo local_poff = 0; 51711991Sheppo local_psize = min(pg_size, len); 51721991Sheppo len -= local_psize; 51731991Sheppo } 51741991Sheppo 51751991Sheppo /* check if we are all done */ 51761991Sheppo if (target_size == 0) 51771991Sheppo break; 51781991Sheppo } 51791991Sheppo 51801991Sheppo mutex_exit(&ldcp->lock); 51811991Sheppo 51822793Slm66018 D1(ldcp->id, "ldc_mem_rdwr_cookie: (0x%llx) done copying sz=0x%llx\n", 51831991Sheppo ldcp->id, *size); 51841991Sheppo 51851991Sheppo return (0); 51861991Sheppo } 51871991Sheppo 51881991Sheppo /* 51891991Sheppo * Map an exported memory segment into the local address space. If the 51901991Sheppo * memory range was exported for direct map access, a HV call is made 51911991Sheppo * to allocate a RA range. If the map is done via a shadow copy, local 51921991Sheppo * shadow memory is allocated and the base VA is returned in 'vaddr'. If 51931991Sheppo * the mapping is a direct map then the RA is returned in 'raddr'. 51941991Sheppo */ 51951991Sheppo int 51961991Sheppo ldc_mem_map(ldc_mem_handle_t mhandle, ldc_mem_cookie_t *cookie, uint32_t ccount, 51972531Snarayan uint8_t mtype, uint8_t perm, caddr_t *vaddr, caddr_t *raddr) 51981991Sheppo { 51992531Snarayan int i, j, idx, rv, retries; 52001991Sheppo ldc_chan_t *ldcp; 52011991Sheppo ldc_mhdl_t *mhdl; 52021991Sheppo ldc_memseg_t *memseg; 52032531Snarayan caddr_t tmpaddr; 52042531Snarayan uint64_t map_perm = perm; 52052531Snarayan uint64_t pg_size, pg_shift, pg_size_code, pg_mask; 52062531Snarayan uint64_t exp_size = 0, base_off, map_size, npages; 52072531Snarayan uint64_t cookie_addr, cookie_off, cookie_size; 52082531Snarayan tte_t ldc_tte; 52091991Sheppo 52101991Sheppo if (mhandle == NULL) { 52111991Sheppo DWARN(DBG_ALL_LDCS, "ldc_mem_map: invalid memory handle\n"); 52121991Sheppo return (EINVAL); 52131991Sheppo } 52141991Sheppo mhdl = (ldc_mhdl_t *)mhandle; 52151991Sheppo 52161991Sheppo mutex_enter(&mhdl->lock); 52171991Sheppo 52181991Sheppo if (mhdl->status == LDC_BOUND || mhdl->status == LDC_MAPPED || 52191991Sheppo mhdl->memseg != NULL) { 52201991Sheppo DWARN(DBG_ALL_LDCS, 52211991Sheppo "ldc_mem_map: (0x%llx) handle bound/mapped\n", mhandle); 52221991Sheppo mutex_exit(&mhdl->lock); 52231991Sheppo return (EINVAL); 52241991Sheppo } 52251991Sheppo 52261991Sheppo ldcp = mhdl->ldcp; 52271991Sheppo 52281991Sheppo mutex_enter(&ldcp->lock); 52291991Sheppo 52301991Sheppo if (ldcp->tstate != TS_UP) { 52311991Sheppo DWARN(ldcp->id, 52321991Sheppo "ldc_mem_dring_map: (0x%llx) channel is not UP\n", 52331991Sheppo ldcp->id); 52341991Sheppo mutex_exit(&ldcp->lock); 52351991Sheppo mutex_exit(&mhdl->lock); 52362793Slm66018 return (ECONNRESET); 52371991Sheppo } 52381991Sheppo 52391991Sheppo if ((mtype & (LDC_SHADOW_MAP|LDC_DIRECT_MAP|LDC_IO_MAP)) == 0) { 52401991Sheppo DWARN(ldcp->id, "ldc_mem_map: invalid map type\n"); 52411991Sheppo mutex_exit(&ldcp->lock); 52421991Sheppo mutex_exit(&mhdl->lock); 52431991Sheppo return (EINVAL); 52441991Sheppo } 52451991Sheppo 52461991Sheppo D1(ldcp->id, "ldc_mem_map: (0x%llx) cookie = 0x%llx,0x%llx\n", 52472336Snarayan ldcp->id, cookie->addr, cookie->size); 52481991Sheppo 52491991Sheppo /* FUTURE: get the page size, pgsz code, and shift */ 52501991Sheppo pg_size = MMU_PAGESIZE; 52511991Sheppo pg_size_code = page_szc(pg_size); 52521991Sheppo pg_shift = page_get_shift(pg_size_code); 52532531Snarayan pg_mask = ~(pg_size - 1); 52541991Sheppo 52551991Sheppo /* calculate the number of pages in the exported cookie */ 52562531Snarayan base_off = cookie[0].addr & (pg_size - 1); 52572531Snarayan for (idx = 0; idx < ccount; idx++) 52581991Sheppo exp_size += cookie[idx].size; 52592531Snarayan map_size = P2ROUNDUP((exp_size + base_off), pg_size); 52602531Snarayan npages = (map_size >> pg_shift); 52611991Sheppo 52621991Sheppo /* Allocate memseg structure */ 52632531Snarayan memseg = mhdl->memseg = 52642531Snarayan kmem_cache_alloc(ldcssp->memseg_cache, KM_SLEEP); 52651991Sheppo 52661991Sheppo /* Allocate memory to store all pages and cookies */ 52671991Sheppo memseg->pages = kmem_zalloc((sizeof (ldc_page_t) * npages), KM_SLEEP); 52681991Sheppo memseg->cookies = 52691991Sheppo kmem_zalloc((sizeof (ldc_mem_cookie_t) * ccount), KM_SLEEP); 52701991Sheppo 52712531Snarayan D2(ldcp->id, "ldc_mem_map: (0x%llx) exp_size=0x%llx, map_size=0x%llx," 52722531Snarayan "pages=0x%llx\n", ldcp->id, exp_size, map_size, npages); 52732531Snarayan 52742531Snarayan /* 52752531Snarayan * Check if direct map over shared memory is enabled, if not change 52762531Snarayan * the mapping type to SHADOW_MAP. 52772531Snarayan */ 52782531Snarayan if (ldc_shmem_enabled == 0) 52792531Snarayan mtype = LDC_SHADOW_MAP; 52802531Snarayan 52812531Snarayan /* 52822531Snarayan * Check to see if the client is requesting direct or shadow map 52832531Snarayan * If direct map is requested, try to map remote memory first, 52842531Snarayan * and if that fails, revert to shadow map 52852531Snarayan */ 52862531Snarayan if (mtype == LDC_DIRECT_MAP) { 52872531Snarayan 52882531Snarayan /* Allocate kernel virtual space for mapping */ 52892531Snarayan memseg->vaddr = vmem_xalloc(heap_arena, map_size, 52902531Snarayan pg_size, 0, 0, NULL, NULL, VM_NOSLEEP); 52912531Snarayan if (memseg->vaddr == NULL) { 52922531Snarayan cmn_err(CE_WARN, 52932531Snarayan "ldc_mem_map: (0x%lx) memory map failed\n", 52942531Snarayan ldcp->id); 52952531Snarayan kmem_free(memseg->cookies, 52962531Snarayan (sizeof (ldc_mem_cookie_t) * ccount)); 52972531Snarayan kmem_free(memseg->pages, 52982531Snarayan (sizeof (ldc_page_t) * npages)); 52992531Snarayan kmem_cache_free(ldcssp->memseg_cache, memseg); 53002531Snarayan 53012531Snarayan mutex_exit(&ldcp->lock); 53022531Snarayan mutex_exit(&mhdl->lock); 53032531Snarayan return (ENOMEM); 53042531Snarayan } 53052531Snarayan 53062531Snarayan /* Unload previous mapping */ 53072531Snarayan hat_unload(kas.a_hat, memseg->vaddr, map_size, 53082531Snarayan HAT_UNLOAD_NOSYNC | HAT_UNLOAD_UNLOCK); 53092531Snarayan 53102531Snarayan /* for each cookie passed in - map into address space */ 53112531Snarayan idx = 0; 53122531Snarayan cookie_size = 0; 53132531Snarayan tmpaddr = memseg->vaddr; 53142531Snarayan 53152531Snarayan for (i = 0; i < npages; i++) { 53162531Snarayan 53172531Snarayan if (cookie_size == 0) { 53182531Snarayan ASSERT(idx < ccount); 53192531Snarayan cookie_addr = cookie[idx].addr & pg_mask; 53202531Snarayan cookie_off = cookie[idx].addr & (pg_size - 1); 53212531Snarayan cookie_size = 53222531Snarayan P2ROUNDUP((cookie_off + cookie[idx].size), 53232531Snarayan pg_size); 53242531Snarayan idx++; 53252531Snarayan } 53262531Snarayan 53272531Snarayan D1(ldcp->id, "ldc_mem_map: (0x%llx) mapping " 53282531Snarayan "cookie 0x%llx, bal=0x%llx\n", ldcp->id, 53292531Snarayan cookie_addr, cookie_size); 53302531Snarayan 53312531Snarayan /* map the cookie into address space */ 53322531Snarayan for (retries = 0; retries < ldc_max_retries; 53332531Snarayan retries++) { 53342531Snarayan 53352531Snarayan rv = hv_ldc_mapin(ldcp->id, cookie_addr, 53362531Snarayan &memseg->pages[i].raddr, &map_perm); 53372531Snarayan if (rv != H_EWOULDBLOCK && rv != H_ETOOMANY) 53382531Snarayan break; 53392531Snarayan 53402531Snarayan drv_usecwait(ldc_delay); 53412531Snarayan } 53422531Snarayan 53432531Snarayan if (rv || memseg->pages[i].raddr == 0) { 53442531Snarayan DWARN(ldcp->id, 53452531Snarayan "ldc_mem_map: (0x%llx) hv mapin err %d\n", 53462531Snarayan ldcp->id, rv); 53472531Snarayan 53482531Snarayan /* remove previous mapins */ 53492531Snarayan hat_unload(kas.a_hat, memseg->vaddr, map_size, 53502531Snarayan HAT_UNLOAD_NOSYNC | HAT_UNLOAD_UNLOCK); 53512531Snarayan for (j = 0; j < i; j++) { 53522531Snarayan rv = hv_ldc_unmap( 53532531Snarayan memseg->pages[j].raddr); 53542531Snarayan if (rv) { 53552531Snarayan DWARN(ldcp->id, 53562531Snarayan "ldc_mem_map: (0x%llx) " 53572531Snarayan "cannot unmap ra=0x%llx\n", 53582531Snarayan ldcp->id, 53592531Snarayan memseg->pages[j].raddr); 53602531Snarayan } 53612531Snarayan } 53622531Snarayan 53632531Snarayan /* free kernel virtual space */ 53642531Snarayan vmem_free(heap_arena, (void *)memseg->vaddr, 53652748Slm66018 map_size); 53662531Snarayan 53672531Snarayan /* direct map failed - revert to shadow map */ 53682531Snarayan mtype = LDC_SHADOW_MAP; 53692531Snarayan break; 53702531Snarayan 53712531Snarayan } else { 53722531Snarayan 53732531Snarayan D1(ldcp->id, 53742531Snarayan "ldc_mem_map: (0x%llx) vtop map 0x%llx -> " 53752531Snarayan "0x%llx, cookie=0x%llx, perm=0x%llx\n", 53762531Snarayan ldcp->id, tmpaddr, memseg->pages[i].raddr, 53772531Snarayan cookie_addr, perm); 53782531Snarayan 53792531Snarayan /* 53802531Snarayan * NOTE: Calling hat_devload directly, causes it 53812531Snarayan * to look for page_t using the pfn. Since this 53822531Snarayan * addr is greater than the memlist, it treates 53832531Snarayan * it as non-memory 53842531Snarayan */ 53852531Snarayan sfmmu_memtte(&ldc_tte, 53862531Snarayan (pfn_t)(memseg->pages[i].raddr >> pg_shift), 53872531Snarayan PROT_READ | PROT_WRITE | HAT_NOSYNC, TTE8K); 53882531Snarayan 53892531Snarayan D1(ldcp->id, 53902531Snarayan "ldc_mem_map: (0x%llx) ra 0x%llx -> " 53912531Snarayan "tte 0x%llx\n", ldcp->id, 53922531Snarayan memseg->pages[i].raddr, ldc_tte); 53932531Snarayan 53942531Snarayan sfmmu_tteload(kas.a_hat, &ldc_tte, tmpaddr, 53952531Snarayan NULL, HAT_LOAD_LOCK); 53962531Snarayan 53972531Snarayan cookie_size -= pg_size; 53982531Snarayan cookie_addr += pg_size; 53992531Snarayan tmpaddr += pg_size; 54002531Snarayan } 54012531Snarayan } 54022531Snarayan } 54032531Snarayan 54041991Sheppo if (mtype == LDC_SHADOW_MAP) { 54051991Sheppo if (*vaddr == NULL) { 54062793Slm66018 memseg->vaddr = kmem_zalloc(exp_size, KM_SLEEP); 54071991Sheppo mhdl->myshadow = B_TRUE; 54081991Sheppo 54091991Sheppo D1(ldcp->id, "ldc_mem_map: (0x%llx) allocated " 54102531Snarayan "shadow page va=0x%llx\n", ldcp->id, memseg->vaddr); 54111991Sheppo } else { 54121991Sheppo /* 54132531Snarayan * Use client supplied memory for memseg->vaddr 54141991Sheppo * WARNING: assuming that client mem is >= exp_size 54151991Sheppo */ 54162531Snarayan memseg->vaddr = *vaddr; 54171991Sheppo } 54182531Snarayan 54192531Snarayan /* Save all page and cookie information */ 54202531Snarayan for (i = 0, tmpaddr = memseg->vaddr; i < npages; i++) { 54212531Snarayan memseg->pages[i].raddr = va_to_pa(tmpaddr); 54222531Snarayan memseg->pages[i].size = pg_size; 54232531Snarayan tmpaddr += pg_size; 54242531Snarayan } 54252531Snarayan 54262531Snarayan } 54272531Snarayan 54282531Snarayan /* save all cookies */ 54292531Snarayan bcopy(cookie, memseg->cookies, ccount * sizeof (ldc_mem_cookie_t)); 54301991Sheppo 54311991Sheppo /* update memseg_t */ 54321991Sheppo memseg->raddr = memseg->pages[0].raddr; 54332531Snarayan memseg->size = (mtype == LDC_SHADOW_MAP) ? exp_size : map_size; 54341991Sheppo memseg->npages = npages; 54351991Sheppo memseg->ncookies = ccount; 54361991Sheppo memseg->next_cookie = 0; 54371991Sheppo 54381991Sheppo /* memory handle = mapped */ 54391991Sheppo mhdl->mtype = mtype; 54402531Snarayan mhdl->perm = perm; 54411991Sheppo mhdl->status = LDC_MAPPED; 54421991Sheppo 54431991Sheppo D1(ldcp->id, "ldc_mem_map: (0x%llx) mapped 0x%llx, ra=0x%llx, " 54441991Sheppo "va=0x%llx, pgs=0x%llx cookies=0x%llx\n", 54451991Sheppo ldcp->id, mhdl, memseg->raddr, memseg->vaddr, 54461991Sheppo memseg->npages, memseg->ncookies); 54471991Sheppo 54482531Snarayan if (mtype == LDC_SHADOW_MAP) 54492531Snarayan base_off = 0; 54501991Sheppo if (raddr) 54512531Snarayan *raddr = (caddr_t)(memseg->raddr | base_off); 54521991Sheppo if (vaddr) 54532531Snarayan *vaddr = (caddr_t)((uintptr_t)memseg->vaddr | base_off); 54541991Sheppo 54551991Sheppo mutex_exit(&ldcp->lock); 54561991Sheppo mutex_exit(&mhdl->lock); 54571991Sheppo return (0); 54581991Sheppo } 54591991Sheppo 54601991Sheppo /* 54611991Sheppo * Unmap a memory segment. Free shadow memory (if any). 54621991Sheppo */ 54631991Sheppo int 54641991Sheppo ldc_mem_unmap(ldc_mem_handle_t mhandle) 54651991Sheppo { 54662531Snarayan int i, rv; 54671991Sheppo ldc_mhdl_t *mhdl = (ldc_mhdl_t *)mhandle; 54681991Sheppo ldc_chan_t *ldcp; 54691991Sheppo ldc_memseg_t *memseg; 54701991Sheppo 54711991Sheppo if (mhdl == 0 || mhdl->status != LDC_MAPPED) { 54721991Sheppo DWARN(DBG_ALL_LDCS, 54731991Sheppo "ldc_mem_unmap: (0x%llx) handle is not mapped\n", 54741991Sheppo mhandle); 54751991Sheppo return (EINVAL); 54761991Sheppo } 54771991Sheppo 54781991Sheppo mutex_enter(&mhdl->lock); 54791991Sheppo 54801991Sheppo ldcp = mhdl->ldcp; 54811991Sheppo memseg = mhdl->memseg; 54821991Sheppo 54831991Sheppo D1(ldcp->id, "ldc_mem_unmap: (0x%llx) unmapping handle 0x%llx\n", 54841991Sheppo ldcp->id, mhdl); 54851991Sheppo 54861991Sheppo /* if we allocated shadow memory - free it */ 54871991Sheppo if (mhdl->mtype == LDC_SHADOW_MAP && mhdl->myshadow) { 54882793Slm66018 kmem_free(memseg->vaddr, memseg->size); 54892531Snarayan } else if (mhdl->mtype == LDC_DIRECT_MAP) { 54902531Snarayan 54912531Snarayan /* unmap in the case of DIRECT_MAP */ 54922531Snarayan hat_unload(kas.a_hat, memseg->vaddr, memseg->size, 54932531Snarayan HAT_UNLOAD_UNLOCK); 54942531Snarayan 54952531Snarayan for (i = 0; i < memseg->npages; i++) { 54962531Snarayan rv = hv_ldc_unmap(memseg->pages[i].raddr); 54972531Snarayan if (rv) { 54982531Snarayan cmn_err(CE_WARN, 54992531Snarayan "ldc_mem_map: (0x%lx) hv unmap err %d\n", 55002531Snarayan ldcp->id, rv); 55012531Snarayan } 55022531Snarayan } 55032531Snarayan 55042531Snarayan vmem_free(heap_arena, (void *)memseg->vaddr, memseg->size); 55051991Sheppo } 55061991Sheppo 55071991Sheppo /* free the allocated memseg and page structures */ 55081991Sheppo kmem_free(memseg->pages, (sizeof (ldc_page_t) * memseg->npages)); 55091991Sheppo kmem_free(memseg->cookies, 55101991Sheppo (sizeof (ldc_mem_cookie_t) * memseg->ncookies)); 55112531Snarayan kmem_cache_free(ldcssp->memseg_cache, memseg); 55121991Sheppo 55131991Sheppo /* uninitialize the memory handle */ 55141991Sheppo mhdl->memseg = NULL; 55151991Sheppo mhdl->status = LDC_UNBOUND; 55161991Sheppo 55171991Sheppo D1(ldcp->id, "ldc_mem_unmap: (0x%llx) unmapped handle 0x%llx\n", 55181991Sheppo ldcp->id, mhdl); 55191991Sheppo 55201991Sheppo mutex_exit(&mhdl->lock); 55211991Sheppo return (0); 55221991Sheppo } 55231991Sheppo 55241991Sheppo /* 55251991Sheppo * Internal entry point for LDC mapped memory entry consistency 55261991Sheppo * semantics. Acquire copies the contents of the remote memory 55271991Sheppo * into the local shadow copy. The release operation copies the local 55281991Sheppo * contents into the remote memory. The offset and size specify the 55291991Sheppo * bounds for the memory range being synchronized. 55301991Sheppo */ 55311991Sheppo static int 55321991Sheppo i_ldc_mem_acquire_release(ldc_mem_handle_t mhandle, uint8_t direction, 55331991Sheppo uint64_t offset, size_t size) 55341991Sheppo { 55351991Sheppo int err; 55361991Sheppo ldc_mhdl_t *mhdl; 55371991Sheppo ldc_chan_t *ldcp; 55381991Sheppo ldc_memseg_t *memseg; 55391991Sheppo caddr_t local_vaddr; 55401991Sheppo size_t copy_size; 55411991Sheppo 55421991Sheppo if (mhandle == NULL) { 55431991Sheppo DWARN(DBG_ALL_LDCS, 55441991Sheppo "i_ldc_mem_acquire_release: invalid memory handle\n"); 55451991Sheppo return (EINVAL); 55461991Sheppo } 55471991Sheppo mhdl = (ldc_mhdl_t *)mhandle; 55481991Sheppo 55491991Sheppo mutex_enter(&mhdl->lock); 55501991Sheppo 55511991Sheppo if (mhdl->status != LDC_MAPPED || mhdl->ldcp == NULL) { 55521991Sheppo DWARN(DBG_ALL_LDCS, 55531991Sheppo "i_ldc_mem_acquire_release: not mapped memory\n"); 55541991Sheppo mutex_exit(&mhdl->lock); 55551991Sheppo return (EINVAL); 55561991Sheppo } 55571991Sheppo 55582531Snarayan /* do nothing for direct map */ 55592531Snarayan if (mhdl->mtype == LDC_DIRECT_MAP) { 55602531Snarayan mutex_exit(&mhdl->lock); 55612531Snarayan return (0); 55622531Snarayan } 55632531Snarayan 55642531Snarayan /* do nothing if COPY_IN+MEM_W and COPY_OUT+MEM_R */ 55652531Snarayan if ((direction == LDC_COPY_IN && (mhdl->perm & LDC_MEM_R) == 0) || 55662531Snarayan (direction == LDC_COPY_OUT && (mhdl->perm & LDC_MEM_W) == 0)) { 55672531Snarayan mutex_exit(&mhdl->lock); 55682531Snarayan return (0); 55692531Snarayan } 55702531Snarayan 55711991Sheppo if (offset >= mhdl->memseg->size || 55721991Sheppo (offset + size) > mhdl->memseg->size) { 55731991Sheppo DWARN(DBG_ALL_LDCS, 55741991Sheppo "i_ldc_mem_acquire_release: memory out of range\n"); 55751991Sheppo mutex_exit(&mhdl->lock); 55761991Sheppo return (EINVAL); 55771991Sheppo } 55781991Sheppo 55791991Sheppo /* get the channel handle and memory segment */ 55801991Sheppo ldcp = mhdl->ldcp; 55811991Sheppo memseg = mhdl->memseg; 55821991Sheppo 55831991Sheppo if (mhdl->mtype == LDC_SHADOW_MAP) { 55841991Sheppo 55851991Sheppo local_vaddr = memseg->vaddr + offset; 55861991Sheppo copy_size = size; 55871991Sheppo 55881991Sheppo /* copy to/from remote from/to local memory */ 55891991Sheppo err = ldc_mem_copy((ldc_handle_t)ldcp, local_vaddr, offset, 55901991Sheppo ©_size, memseg->cookies, memseg->ncookies, 55911991Sheppo direction); 55921991Sheppo if (err || copy_size != size) { 55933010Slm66018 DWARN(ldcp->id, 55941991Sheppo "i_ldc_mem_acquire_release: copy failed\n"); 55951991Sheppo mutex_exit(&mhdl->lock); 55961991Sheppo return (err); 55971991Sheppo } 55981991Sheppo } 55991991Sheppo 56001991Sheppo mutex_exit(&mhdl->lock); 56011991Sheppo 56021991Sheppo return (0); 56031991Sheppo } 56041991Sheppo 56051991Sheppo /* 56061991Sheppo * Ensure that the contents in the remote memory seg are consistent 56071991Sheppo * with the contents if of local segment 56081991Sheppo */ 56091991Sheppo int 56101991Sheppo ldc_mem_acquire(ldc_mem_handle_t mhandle, uint64_t offset, uint64_t size) 56111991Sheppo { 56121991Sheppo return (i_ldc_mem_acquire_release(mhandle, LDC_COPY_IN, offset, size)); 56131991Sheppo } 56141991Sheppo 56151991Sheppo 56161991Sheppo /* 56171991Sheppo * Ensure that the contents in the local memory seg are consistent 56181991Sheppo * with the contents if of remote segment 56191991Sheppo */ 56201991Sheppo int 56211991Sheppo ldc_mem_release(ldc_mem_handle_t mhandle, uint64_t offset, uint64_t size) 56221991Sheppo { 56231991Sheppo return (i_ldc_mem_acquire_release(mhandle, LDC_COPY_OUT, offset, size)); 56241991Sheppo } 56251991Sheppo 56261991Sheppo /* 56271991Sheppo * Allocate a descriptor ring. The size of each each descriptor 56281991Sheppo * must be 8-byte aligned and the entire ring should be a multiple 56291991Sheppo * of MMU_PAGESIZE. 56301991Sheppo */ 56311991Sheppo int 56321991Sheppo ldc_mem_dring_create(uint32_t len, uint32_t dsize, ldc_dring_handle_t *dhandle) 56331991Sheppo { 56341991Sheppo ldc_dring_t *dringp; 56351991Sheppo size_t size = (dsize * len); 56361991Sheppo 56371991Sheppo D1(DBG_ALL_LDCS, "ldc_mem_dring_create: len=0x%x, size=0x%x\n", 56381991Sheppo len, dsize); 56391991Sheppo 56401991Sheppo if (dhandle == NULL) { 56411991Sheppo DWARN(DBG_ALL_LDCS, "ldc_mem_dring_create: invalid dhandle\n"); 56421991Sheppo return (EINVAL); 56431991Sheppo } 56441991Sheppo 56451991Sheppo if (len == 0) { 56461991Sheppo DWARN(DBG_ALL_LDCS, "ldc_mem_dring_create: invalid length\n"); 56471991Sheppo return (EINVAL); 56481991Sheppo } 56491991Sheppo 56501991Sheppo /* descriptor size should be 8-byte aligned */ 56511991Sheppo if (dsize == 0 || (dsize & 0x7)) { 56521991Sheppo DWARN(DBG_ALL_LDCS, "ldc_mem_dring_create: invalid size\n"); 56531991Sheppo return (EINVAL); 56541991Sheppo } 56551991Sheppo 56561991Sheppo *dhandle = 0; 56571991Sheppo 56581991Sheppo /* Allocate a desc ring structure */ 56591991Sheppo dringp = kmem_zalloc(sizeof (ldc_dring_t), KM_SLEEP); 56601991Sheppo 56611991Sheppo /* Initialize dring */ 56621991Sheppo dringp->length = len; 56631991Sheppo dringp->dsize = dsize; 56641991Sheppo 56651991Sheppo /* round off to multiple of pagesize */ 56661991Sheppo dringp->size = (size & MMU_PAGEMASK); 56671991Sheppo if (size & MMU_PAGEOFFSET) 56681991Sheppo dringp->size += MMU_PAGESIZE; 56691991Sheppo 56701991Sheppo dringp->status = LDC_UNBOUND; 56711991Sheppo 56721991Sheppo /* allocate descriptor ring memory */ 56732793Slm66018 dringp->base = kmem_zalloc(dringp->size, KM_SLEEP); 56741991Sheppo 56751991Sheppo /* initialize the desc ring lock */ 56761991Sheppo mutex_init(&dringp->lock, NULL, MUTEX_DRIVER, NULL); 56771991Sheppo 56781991Sheppo /* Add descriptor ring to the head of global list */ 56791991Sheppo mutex_enter(&ldcssp->lock); 56801991Sheppo dringp->next = ldcssp->dring_list; 56811991Sheppo ldcssp->dring_list = dringp; 56821991Sheppo mutex_exit(&ldcssp->lock); 56831991Sheppo 56841991Sheppo *dhandle = (ldc_dring_handle_t)dringp; 56851991Sheppo 56861991Sheppo D1(DBG_ALL_LDCS, "ldc_mem_dring_create: dring allocated\n"); 56871991Sheppo 56881991Sheppo return (0); 56891991Sheppo } 56901991Sheppo 56911991Sheppo 56921991Sheppo /* 56931991Sheppo * Destroy a descriptor ring. 56941991Sheppo */ 56951991Sheppo int 56961991Sheppo ldc_mem_dring_destroy(ldc_dring_handle_t dhandle) 56971991Sheppo { 56981991Sheppo ldc_dring_t *dringp; 56991991Sheppo ldc_dring_t *tmp_dringp; 57001991Sheppo 57011991Sheppo D1(DBG_ALL_LDCS, "ldc_mem_dring_destroy: entered\n"); 57021991Sheppo 57031991Sheppo if (dhandle == NULL) { 57041991Sheppo DWARN(DBG_ALL_LDCS, 57051991Sheppo "ldc_mem_dring_destroy: invalid desc ring handle\n"); 57061991Sheppo return (EINVAL); 57071991Sheppo } 57081991Sheppo dringp = (ldc_dring_t *)dhandle; 57091991Sheppo 57101991Sheppo if (dringp->status == LDC_BOUND) { 57111991Sheppo DWARN(DBG_ALL_LDCS, 57121991Sheppo "ldc_mem_dring_destroy: desc ring is bound\n"); 57131991Sheppo return (EACCES); 57141991Sheppo } 57151991Sheppo 57161991Sheppo mutex_enter(&dringp->lock); 57171991Sheppo mutex_enter(&ldcssp->lock); 57181991Sheppo 57191991Sheppo /* remove from linked list - if not bound */ 57201991Sheppo tmp_dringp = ldcssp->dring_list; 57211991Sheppo if (tmp_dringp == dringp) { 57221991Sheppo ldcssp->dring_list = dringp->next; 57231991Sheppo dringp->next = NULL; 57241991Sheppo 57251991Sheppo } else { 57261991Sheppo while (tmp_dringp != NULL) { 57271991Sheppo if (tmp_dringp->next == dringp) { 57281991Sheppo tmp_dringp->next = dringp->next; 57291991Sheppo dringp->next = NULL; 57301991Sheppo break; 57311991Sheppo } 57321991Sheppo tmp_dringp = tmp_dringp->next; 57331991Sheppo } 57341991Sheppo if (tmp_dringp == NULL) { 57351991Sheppo DWARN(DBG_ALL_LDCS, 57361991Sheppo "ldc_mem_dring_destroy: invalid descriptor\n"); 57371991Sheppo mutex_exit(&ldcssp->lock); 57381991Sheppo mutex_exit(&dringp->lock); 57391991Sheppo return (EINVAL); 57401991Sheppo } 57411991Sheppo } 57421991Sheppo 57431991Sheppo mutex_exit(&ldcssp->lock); 57441991Sheppo 57451991Sheppo /* free the descriptor ring */ 57462793Slm66018 kmem_free(dringp->base, dringp->size); 57471991Sheppo 57481991Sheppo mutex_exit(&dringp->lock); 57491991Sheppo 57501991Sheppo /* destroy dring lock */ 57511991Sheppo mutex_destroy(&dringp->lock); 57521991Sheppo 57531991Sheppo /* free desc ring object */ 57541991Sheppo kmem_free(dringp, sizeof (ldc_dring_t)); 57551991Sheppo 57561991Sheppo return (0); 57571991Sheppo } 57581991Sheppo 57591991Sheppo /* 57601991Sheppo * Bind a previously allocated dring to a channel. The channel should 57611991Sheppo * be OPEN in order to bind the ring to the channel. Returns back a 57621991Sheppo * descriptor ring cookie. The descriptor ring is exported for remote 57631991Sheppo * access by the client at the other end of the channel. An entry for 57641991Sheppo * dring pages is stored in map table (via call to ldc_mem_bind_handle). 57651991Sheppo */ 57661991Sheppo int 57671991Sheppo ldc_mem_dring_bind(ldc_handle_t handle, ldc_dring_handle_t dhandle, 57681991Sheppo uint8_t mtype, uint8_t perm, ldc_mem_cookie_t *cookie, uint32_t *ccount) 57691991Sheppo { 57701991Sheppo int err; 57711991Sheppo ldc_chan_t *ldcp; 57721991Sheppo ldc_dring_t *dringp; 57731991Sheppo ldc_mem_handle_t mhandle; 57741991Sheppo 57751991Sheppo /* check to see if channel is initalized */ 57761991Sheppo if (handle == NULL) { 57771991Sheppo DWARN(DBG_ALL_LDCS, 57781991Sheppo "ldc_mem_dring_bind: invalid channel handle\n"); 57791991Sheppo return (EINVAL); 57801991Sheppo } 57811991Sheppo ldcp = (ldc_chan_t *)handle; 57821991Sheppo 57831991Sheppo if (dhandle == NULL) { 57841991Sheppo DWARN(DBG_ALL_LDCS, 57851991Sheppo "ldc_mem_dring_bind: invalid desc ring handle\n"); 57861991Sheppo return (EINVAL); 57871991Sheppo } 57881991Sheppo dringp = (ldc_dring_t *)dhandle; 57891991Sheppo 57901991Sheppo if (cookie == NULL) { 57911991Sheppo DWARN(ldcp->id, 57921991Sheppo "ldc_mem_dring_bind: invalid cookie arg\n"); 57931991Sheppo return (EINVAL); 57941991Sheppo } 57951991Sheppo 57961991Sheppo mutex_enter(&dringp->lock); 57971991Sheppo 57981991Sheppo if (dringp->status == LDC_BOUND) { 57991991Sheppo DWARN(DBG_ALL_LDCS, 58001991Sheppo "ldc_mem_dring_bind: (0x%llx) descriptor ring is bound\n", 58011991Sheppo ldcp->id); 58021991Sheppo mutex_exit(&dringp->lock); 58031991Sheppo return (EINVAL); 58041991Sheppo } 58051991Sheppo 58061991Sheppo if ((perm & LDC_MEM_RW) == 0) { 58071991Sheppo DWARN(DBG_ALL_LDCS, 58081991Sheppo "ldc_mem_dring_bind: invalid permissions\n"); 58091991Sheppo mutex_exit(&dringp->lock); 58101991Sheppo return (EINVAL); 58111991Sheppo } 58121991Sheppo 58131991Sheppo if ((mtype & (LDC_SHADOW_MAP|LDC_DIRECT_MAP|LDC_IO_MAP)) == 0) { 58141991Sheppo DWARN(DBG_ALL_LDCS, "ldc_mem_dring_bind: invalid type\n"); 58151991Sheppo mutex_exit(&dringp->lock); 58161991Sheppo return (EINVAL); 58171991Sheppo } 58181991Sheppo 58191991Sheppo dringp->ldcp = ldcp; 58201991Sheppo 58211991Sheppo /* create an memory handle */ 58221991Sheppo err = ldc_mem_alloc_handle(handle, &mhandle); 58231991Sheppo if (err || mhandle == NULL) { 58241991Sheppo DWARN(DBG_ALL_LDCS, 58251991Sheppo "ldc_mem_dring_bind: (0x%llx) error allocating mhandle\n", 58261991Sheppo ldcp->id); 58271991Sheppo mutex_exit(&dringp->lock); 58281991Sheppo return (err); 58291991Sheppo } 58301991Sheppo dringp->mhdl = mhandle; 58311991Sheppo 58321991Sheppo /* bind the descriptor ring to channel */ 58331991Sheppo err = ldc_mem_bind_handle(mhandle, dringp->base, dringp->size, 58341991Sheppo mtype, perm, cookie, ccount); 58351991Sheppo if (err) { 58361991Sheppo DWARN(ldcp->id, 58371991Sheppo "ldc_mem_dring_bind: (0x%llx) error binding mhandle\n", 58381991Sheppo ldcp->id); 58391991Sheppo mutex_exit(&dringp->lock); 58401991Sheppo return (err); 58411991Sheppo } 58421991Sheppo 58431991Sheppo /* 58441991Sheppo * For now return error if we get more than one cookie 58451991Sheppo * FUTURE: Return multiple cookies .. 58461991Sheppo */ 58471991Sheppo if (*ccount > 1) { 58481991Sheppo (void) ldc_mem_unbind_handle(mhandle); 58491991Sheppo (void) ldc_mem_free_handle(mhandle); 58501991Sheppo 58511991Sheppo dringp->ldcp = NULL; 58521991Sheppo dringp->mhdl = NULL; 58531991Sheppo *ccount = 0; 58541991Sheppo 58551991Sheppo mutex_exit(&dringp->lock); 58561991Sheppo return (EAGAIN); 58571991Sheppo } 58581991Sheppo 58591991Sheppo /* Add descriptor ring to channel's exported dring list */ 58601991Sheppo mutex_enter(&ldcp->exp_dlist_lock); 58611991Sheppo dringp->ch_next = ldcp->exp_dring_list; 58621991Sheppo ldcp->exp_dring_list = dringp; 58631991Sheppo mutex_exit(&ldcp->exp_dlist_lock); 58641991Sheppo 58651991Sheppo dringp->status = LDC_BOUND; 58661991Sheppo 58671991Sheppo mutex_exit(&dringp->lock); 58681991Sheppo 58691991Sheppo return (0); 58701991Sheppo } 58711991Sheppo 58721991Sheppo /* 58731991Sheppo * Return the next cookie associated with the specified dring handle 58741991Sheppo */ 58751991Sheppo int 58761991Sheppo ldc_mem_dring_nextcookie(ldc_dring_handle_t dhandle, ldc_mem_cookie_t *cookie) 58771991Sheppo { 58781991Sheppo int rv = 0; 58791991Sheppo ldc_dring_t *dringp; 58801991Sheppo ldc_chan_t *ldcp; 58811991Sheppo 58821991Sheppo if (dhandle == NULL) { 58831991Sheppo DWARN(DBG_ALL_LDCS, 58841991Sheppo "ldc_mem_dring_nextcookie: invalid desc ring handle\n"); 58851991Sheppo return (EINVAL); 58861991Sheppo } 58871991Sheppo dringp = (ldc_dring_t *)dhandle; 58881991Sheppo mutex_enter(&dringp->lock); 58891991Sheppo 58901991Sheppo if (dringp->status != LDC_BOUND) { 58911991Sheppo DWARN(DBG_ALL_LDCS, 58921991Sheppo "ldc_mem_dring_nextcookie: descriptor ring 0x%llx " 58931991Sheppo "is not bound\n", dringp); 58941991Sheppo mutex_exit(&dringp->lock); 58951991Sheppo return (EINVAL); 58961991Sheppo } 58971991Sheppo 58981991Sheppo ldcp = dringp->ldcp; 58991991Sheppo 59001991Sheppo if (cookie == NULL) { 59011991Sheppo DWARN(ldcp->id, 59021991Sheppo "ldc_mem_dring_nextcookie:(0x%llx) invalid cookie arg\n", 59031991Sheppo ldcp->id); 59041991Sheppo mutex_exit(&dringp->lock); 59051991Sheppo return (EINVAL); 59061991Sheppo } 59071991Sheppo 59081991Sheppo rv = ldc_mem_nextcookie((ldc_mem_handle_t)dringp->mhdl, cookie); 59091991Sheppo mutex_exit(&dringp->lock); 59101991Sheppo 59111991Sheppo return (rv); 59121991Sheppo } 59131991Sheppo /* 59141991Sheppo * Unbind a previously bound dring from a channel. 59151991Sheppo */ 59161991Sheppo int 59171991Sheppo ldc_mem_dring_unbind(ldc_dring_handle_t dhandle) 59181991Sheppo { 59191991Sheppo ldc_dring_t *dringp; 59201991Sheppo ldc_dring_t *tmp_dringp; 59211991Sheppo ldc_chan_t *ldcp; 59221991Sheppo 59231991Sheppo if (dhandle == NULL) { 59241991Sheppo DWARN(DBG_ALL_LDCS, 59251991Sheppo "ldc_mem_dring_unbind: invalid desc ring handle\n"); 59261991Sheppo return (EINVAL); 59271991Sheppo } 59281991Sheppo dringp = (ldc_dring_t *)dhandle; 59291991Sheppo 59301991Sheppo mutex_enter(&dringp->lock); 59311991Sheppo 59321991Sheppo if (dringp->status == LDC_UNBOUND) { 59331991Sheppo DWARN(DBG_ALL_LDCS, 59341991Sheppo "ldc_mem_dring_bind: descriptor ring 0x%llx is unbound\n", 59351991Sheppo dringp); 59361991Sheppo mutex_exit(&dringp->lock); 59371991Sheppo return (EINVAL); 59381991Sheppo } 59391991Sheppo ldcp = dringp->ldcp; 59401991Sheppo 59411991Sheppo mutex_enter(&ldcp->exp_dlist_lock); 59421991Sheppo 59431991Sheppo tmp_dringp = ldcp->exp_dring_list; 59441991Sheppo if (tmp_dringp == dringp) { 59451991Sheppo ldcp->exp_dring_list = dringp->ch_next; 59461991Sheppo dringp->ch_next = NULL; 59471991Sheppo 59481991Sheppo } else { 59491991Sheppo while (tmp_dringp != NULL) { 59501991Sheppo if (tmp_dringp->ch_next == dringp) { 59511991Sheppo tmp_dringp->ch_next = dringp->ch_next; 59521991Sheppo dringp->ch_next = NULL; 59531991Sheppo break; 59541991Sheppo } 59551991Sheppo tmp_dringp = tmp_dringp->ch_next; 59561991Sheppo } 59571991Sheppo if (tmp_dringp == NULL) { 59581991Sheppo DWARN(DBG_ALL_LDCS, 59591991Sheppo "ldc_mem_dring_unbind: invalid descriptor\n"); 59601991Sheppo mutex_exit(&ldcp->exp_dlist_lock); 59611991Sheppo mutex_exit(&dringp->lock); 59621991Sheppo return (EINVAL); 59631991Sheppo } 59641991Sheppo } 59651991Sheppo 59661991Sheppo mutex_exit(&ldcp->exp_dlist_lock); 59671991Sheppo 59681991Sheppo (void) ldc_mem_unbind_handle((ldc_mem_handle_t)dringp->mhdl); 59691991Sheppo (void) ldc_mem_free_handle((ldc_mem_handle_t)dringp->mhdl); 59701991Sheppo 59711991Sheppo dringp->ldcp = NULL; 59721991Sheppo dringp->mhdl = NULL; 59731991Sheppo dringp->status = LDC_UNBOUND; 59741991Sheppo 59751991Sheppo mutex_exit(&dringp->lock); 59761991Sheppo 59771991Sheppo return (0); 59781991Sheppo } 59791991Sheppo 59801991Sheppo /* 59811991Sheppo * Get information about the dring. The base address of the descriptor 59821991Sheppo * ring along with the type and permission are returned back. 59831991Sheppo */ 59841991Sheppo int 59851991Sheppo ldc_mem_dring_info(ldc_dring_handle_t dhandle, ldc_mem_info_t *minfo) 59861991Sheppo { 59871991Sheppo ldc_dring_t *dringp; 59881991Sheppo int rv; 59891991Sheppo 59901991Sheppo if (dhandle == NULL) { 59911991Sheppo DWARN(DBG_ALL_LDCS, 59921991Sheppo "ldc_mem_dring_info: invalid desc ring handle\n"); 59931991Sheppo return (EINVAL); 59941991Sheppo } 59951991Sheppo dringp = (ldc_dring_t *)dhandle; 59961991Sheppo 59971991Sheppo mutex_enter(&dringp->lock); 59981991Sheppo 59991991Sheppo if (dringp->mhdl) { 60001991Sheppo rv = ldc_mem_info(dringp->mhdl, minfo); 60011991Sheppo if (rv) { 60021991Sheppo DWARN(DBG_ALL_LDCS, 60031991Sheppo "ldc_mem_dring_info: error reading mem info\n"); 60041991Sheppo mutex_exit(&dringp->lock); 60051991Sheppo return (rv); 60061991Sheppo } 60071991Sheppo } else { 60081991Sheppo minfo->vaddr = dringp->base; 60091991Sheppo minfo->raddr = NULL; 60101991Sheppo minfo->status = dringp->status; 60111991Sheppo } 60121991Sheppo 60131991Sheppo mutex_exit(&dringp->lock); 60141991Sheppo 60151991Sheppo return (0); 60161991Sheppo } 60171991Sheppo 60181991Sheppo /* 60191991Sheppo * Map an exported descriptor ring into the local address space. If the 60201991Sheppo * descriptor ring was exported for direct map access, a HV call is made 60211991Sheppo * to allocate a RA range. If the map is done via a shadow copy, local 60221991Sheppo * shadow memory is allocated. 60231991Sheppo */ 60241991Sheppo int 60251991Sheppo ldc_mem_dring_map(ldc_handle_t handle, ldc_mem_cookie_t *cookie, 60261991Sheppo uint32_t ccount, uint32_t len, uint32_t dsize, uint8_t mtype, 60271991Sheppo ldc_dring_handle_t *dhandle) 60281991Sheppo { 60291991Sheppo int err; 60301991Sheppo ldc_chan_t *ldcp = (ldc_chan_t *)handle; 60311991Sheppo ldc_mem_handle_t mhandle; 60321991Sheppo ldc_dring_t *dringp; 60331991Sheppo size_t dring_size; 60341991Sheppo 60351991Sheppo if (dhandle == NULL) { 60361991Sheppo DWARN(DBG_ALL_LDCS, 60371991Sheppo "ldc_mem_dring_map: invalid dhandle\n"); 60381991Sheppo return (EINVAL); 60391991Sheppo } 60401991Sheppo 60411991Sheppo /* check to see if channel is initalized */ 60421991Sheppo if (handle == NULL) { 60431991Sheppo DWARN(DBG_ALL_LDCS, 60441991Sheppo "ldc_mem_dring_map: invalid channel handle\n"); 60451991Sheppo return (EINVAL); 60461991Sheppo } 60471991Sheppo ldcp = (ldc_chan_t *)handle; 60481991Sheppo 60491991Sheppo if (cookie == NULL) { 60501991Sheppo DWARN(ldcp->id, 60511991Sheppo "ldc_mem_dring_map: (0x%llx) invalid cookie\n", 60521991Sheppo ldcp->id); 60531991Sheppo return (EINVAL); 60541991Sheppo } 60551991Sheppo 60561991Sheppo /* FUTURE: For now we support only one cookie per dring */ 60571991Sheppo ASSERT(ccount == 1); 60581991Sheppo 60591991Sheppo if (cookie->size < (dsize * len)) { 60601991Sheppo DWARN(ldcp->id, 60611991Sheppo "ldc_mem_dring_map: (0x%llx) invalid dsize/len\n", 60621991Sheppo ldcp->id); 60631991Sheppo return (EINVAL); 60641991Sheppo } 60651991Sheppo 60661991Sheppo *dhandle = 0; 60671991Sheppo 60681991Sheppo /* Allocate an dring structure */ 60691991Sheppo dringp = kmem_zalloc(sizeof (ldc_dring_t), KM_SLEEP); 60701991Sheppo 60711991Sheppo D1(ldcp->id, 60721991Sheppo "ldc_mem_dring_map: 0x%x,0x%x,0x%x,0x%llx,0x%llx\n", 60731991Sheppo mtype, len, dsize, cookie->addr, cookie->size); 60741991Sheppo 60751991Sheppo /* Initialize dring */ 60761991Sheppo dringp->length = len; 60771991Sheppo dringp->dsize = dsize; 60781991Sheppo 60791991Sheppo /* round of to multiple of page size */ 60801991Sheppo dring_size = len * dsize; 60811991Sheppo dringp->size = (dring_size & MMU_PAGEMASK); 60821991Sheppo if (dring_size & MMU_PAGEOFFSET) 60831991Sheppo dringp->size += MMU_PAGESIZE; 60841991Sheppo 60851991Sheppo dringp->ldcp = ldcp; 60861991Sheppo 60871991Sheppo /* create an memory handle */ 60881991Sheppo err = ldc_mem_alloc_handle(handle, &mhandle); 60891991Sheppo if (err || mhandle == NULL) { 60901991Sheppo DWARN(DBG_ALL_LDCS, 60911991Sheppo "ldc_mem_dring_map: cannot alloc hdl err=%d\n", 60921991Sheppo err); 60931991Sheppo kmem_free(dringp, sizeof (ldc_dring_t)); 60941991Sheppo return (ENOMEM); 60951991Sheppo } 60961991Sheppo 60971991Sheppo dringp->mhdl = mhandle; 60981991Sheppo dringp->base = NULL; 60991991Sheppo 61001991Sheppo /* map the dring into local memory */ 61012531Snarayan err = ldc_mem_map(mhandle, cookie, ccount, mtype, LDC_MEM_RW, 61021991Sheppo &(dringp->base), NULL); 61031991Sheppo if (err || dringp->base == NULL) { 61041991Sheppo cmn_err(CE_WARN, 61051991Sheppo "ldc_mem_dring_map: cannot map desc ring err=%d\n", err); 61061991Sheppo (void) ldc_mem_free_handle(mhandle); 61071991Sheppo kmem_free(dringp, sizeof (ldc_dring_t)); 61081991Sheppo return (ENOMEM); 61091991Sheppo } 61101991Sheppo 61111991Sheppo /* initialize the desc ring lock */ 61121991Sheppo mutex_init(&dringp->lock, NULL, MUTEX_DRIVER, NULL); 61131991Sheppo 61141991Sheppo /* Add descriptor ring to channel's imported dring list */ 61151991Sheppo mutex_enter(&ldcp->imp_dlist_lock); 61161991Sheppo dringp->ch_next = ldcp->imp_dring_list; 61171991Sheppo ldcp->imp_dring_list = dringp; 61181991Sheppo mutex_exit(&ldcp->imp_dlist_lock); 61191991Sheppo 61201991Sheppo dringp->status = LDC_MAPPED; 61211991Sheppo 61221991Sheppo *dhandle = (ldc_dring_handle_t)dringp; 61231991Sheppo 61241991Sheppo return (0); 61251991Sheppo } 61261991Sheppo 61271991Sheppo /* 61281991Sheppo * Unmap a descriptor ring. Free shadow memory (if any). 61291991Sheppo */ 61301991Sheppo int 61311991Sheppo ldc_mem_dring_unmap(ldc_dring_handle_t dhandle) 61321991Sheppo { 61331991Sheppo ldc_dring_t *dringp; 61341991Sheppo ldc_dring_t *tmp_dringp; 61351991Sheppo ldc_chan_t *ldcp; 61361991Sheppo 61371991Sheppo if (dhandle == NULL) { 61381991Sheppo DWARN(DBG_ALL_LDCS, 61391991Sheppo "ldc_mem_dring_unmap: invalid desc ring handle\n"); 61401991Sheppo return (EINVAL); 61411991Sheppo } 61421991Sheppo dringp = (ldc_dring_t *)dhandle; 61431991Sheppo 61441991Sheppo if (dringp->status != LDC_MAPPED) { 61451991Sheppo DWARN(DBG_ALL_LDCS, 61461991Sheppo "ldc_mem_dring_unmap: not a mapped desc ring\n"); 61471991Sheppo return (EINVAL); 61481991Sheppo } 61491991Sheppo 61501991Sheppo mutex_enter(&dringp->lock); 61511991Sheppo 61521991Sheppo ldcp = dringp->ldcp; 61531991Sheppo 61541991Sheppo mutex_enter(&ldcp->imp_dlist_lock); 61551991Sheppo 61561991Sheppo /* find and unlink the desc ring from channel import list */ 61571991Sheppo tmp_dringp = ldcp->imp_dring_list; 61581991Sheppo if (tmp_dringp == dringp) { 61591991Sheppo ldcp->imp_dring_list = dringp->ch_next; 61601991Sheppo dringp->ch_next = NULL; 61611991Sheppo 61621991Sheppo } else { 61631991Sheppo while (tmp_dringp != NULL) { 61641991Sheppo if (tmp_dringp->ch_next == dringp) { 61651991Sheppo tmp_dringp->ch_next = dringp->ch_next; 61661991Sheppo dringp->ch_next = NULL; 61671991Sheppo break; 61681991Sheppo } 61691991Sheppo tmp_dringp = tmp_dringp->ch_next; 61701991Sheppo } 61711991Sheppo if (tmp_dringp == NULL) { 61721991Sheppo DWARN(DBG_ALL_LDCS, 61731991Sheppo "ldc_mem_dring_unmap: invalid descriptor\n"); 61741991Sheppo mutex_exit(&ldcp->imp_dlist_lock); 61751991Sheppo mutex_exit(&dringp->lock); 61761991Sheppo return (EINVAL); 61771991Sheppo } 61781991Sheppo } 61791991Sheppo 61801991Sheppo mutex_exit(&ldcp->imp_dlist_lock); 61811991Sheppo 61821991Sheppo /* do a LDC memory handle unmap and free */ 61831991Sheppo (void) ldc_mem_unmap(dringp->mhdl); 61841991Sheppo (void) ldc_mem_free_handle((ldc_mem_handle_t)dringp->mhdl); 61851991Sheppo 61861991Sheppo dringp->status = 0; 61871991Sheppo dringp->ldcp = NULL; 61881991Sheppo 61891991Sheppo mutex_exit(&dringp->lock); 61901991Sheppo 61911991Sheppo /* destroy dring lock */ 61921991Sheppo mutex_destroy(&dringp->lock); 61931991Sheppo 61941991Sheppo /* free desc ring object */ 61951991Sheppo kmem_free(dringp, sizeof (ldc_dring_t)); 61961991Sheppo 61971991Sheppo return (0); 61981991Sheppo } 61991991Sheppo 62001991Sheppo /* 62011991Sheppo * Internal entry point for descriptor ring access entry consistency 62021991Sheppo * semantics. Acquire copies the contents of the remote descriptor ring 62031991Sheppo * into the local shadow copy. The release operation copies the local 62041991Sheppo * contents into the remote dring. The start and end locations specify 62051991Sheppo * bounds for the entries being synchronized. 62061991Sheppo */ 62071991Sheppo static int 62081991Sheppo i_ldc_dring_acquire_release(ldc_dring_handle_t dhandle, 62091991Sheppo uint8_t direction, uint64_t start, uint64_t end) 62101991Sheppo { 62111991Sheppo int err; 62121991Sheppo ldc_dring_t *dringp; 62131991Sheppo ldc_chan_t *ldcp; 62141991Sheppo uint64_t soff; 62151991Sheppo size_t copy_size; 62161991Sheppo 62171991Sheppo if (dhandle == NULL) { 62181991Sheppo DWARN(DBG_ALL_LDCS, 62191991Sheppo "i_ldc_dring_acquire_release: invalid desc ring handle\n"); 62201991Sheppo return (EINVAL); 62211991Sheppo } 62221991Sheppo dringp = (ldc_dring_t *)dhandle; 62231991Sheppo mutex_enter(&dringp->lock); 62241991Sheppo 62251991Sheppo if (dringp->status != LDC_MAPPED || dringp->ldcp == NULL) { 62261991Sheppo DWARN(DBG_ALL_LDCS, 62271991Sheppo "i_ldc_dring_acquire_release: not a mapped desc ring\n"); 62281991Sheppo mutex_exit(&dringp->lock); 62291991Sheppo return (EINVAL); 62301991Sheppo } 62311991Sheppo 62321991Sheppo if (start >= dringp->length || end >= dringp->length) { 62331991Sheppo DWARN(DBG_ALL_LDCS, 62341991Sheppo "i_ldc_dring_acquire_release: index out of range\n"); 62351991Sheppo mutex_exit(&dringp->lock); 62361991Sheppo return (EINVAL); 62371991Sheppo } 62381991Sheppo 62391991Sheppo /* get the channel handle */ 62401991Sheppo ldcp = dringp->ldcp; 62411991Sheppo 62421991Sheppo copy_size = (start <= end) ? (((end - start) + 1) * dringp->dsize) : 62431991Sheppo ((dringp->length - start) * dringp->dsize); 62441991Sheppo 62451991Sheppo /* Calculate the relative offset for the first desc */ 62461991Sheppo soff = (start * dringp->dsize); 62471991Sheppo 62481991Sheppo /* copy to/from remote from/to local memory */ 62491991Sheppo D1(ldcp->id, "i_ldc_dring_acquire_release: c1 off=0x%llx sz=0x%llx\n", 62501991Sheppo soff, copy_size); 62511991Sheppo err = i_ldc_mem_acquire_release((ldc_mem_handle_t)dringp->mhdl, 62521991Sheppo direction, soff, copy_size); 62531991Sheppo if (err) { 62541991Sheppo DWARN(ldcp->id, 62551991Sheppo "i_ldc_dring_acquire_release: copy failed\n"); 62561991Sheppo mutex_exit(&dringp->lock); 62571991Sheppo return (err); 62581991Sheppo } 62591991Sheppo 62601991Sheppo /* do the balance */ 62611991Sheppo if (start > end) { 62621991Sheppo copy_size = ((end + 1) * dringp->dsize); 62631991Sheppo soff = 0; 62641991Sheppo 62651991Sheppo /* copy to/from remote from/to local memory */ 62661991Sheppo D1(ldcp->id, "i_ldc_dring_acquire_release: c2 " 62671991Sheppo "off=0x%llx sz=0x%llx\n", soff, copy_size); 62681991Sheppo err = i_ldc_mem_acquire_release((ldc_mem_handle_t)dringp->mhdl, 62691991Sheppo direction, soff, copy_size); 62701991Sheppo if (err) { 62711991Sheppo DWARN(ldcp->id, 62721991Sheppo "i_ldc_dring_acquire_release: copy failed\n"); 62731991Sheppo mutex_exit(&dringp->lock); 62741991Sheppo return (err); 62751991Sheppo } 62761991Sheppo } 62771991Sheppo 62781991Sheppo mutex_exit(&dringp->lock); 62791991Sheppo 62801991Sheppo return (0); 62811991Sheppo } 62821991Sheppo 62831991Sheppo /* 62841991Sheppo * Ensure that the contents in the local dring are consistent 62851991Sheppo * with the contents if of remote dring 62861991Sheppo */ 62871991Sheppo int 62881991Sheppo ldc_mem_dring_acquire(ldc_dring_handle_t dhandle, uint64_t start, uint64_t end) 62891991Sheppo { 62901991Sheppo return (i_ldc_dring_acquire_release(dhandle, LDC_COPY_IN, start, end)); 62911991Sheppo } 62921991Sheppo 62931991Sheppo /* 62941991Sheppo * Ensure that the contents in the remote dring are consistent 62951991Sheppo * with the contents if of local dring 62961991Sheppo */ 62971991Sheppo int 62981991Sheppo ldc_mem_dring_release(ldc_dring_handle_t dhandle, uint64_t start, uint64_t end) 62991991Sheppo { 63001991Sheppo return (i_ldc_dring_acquire_release(dhandle, LDC_COPY_OUT, start, end)); 63011991Sheppo } 63021991Sheppo 63031991Sheppo 63041991Sheppo /* ------------------------------------------------------------------------- */ 6305