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 /* 238542SHaik.Aftandilian@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 241991Sheppo * Use is subject to license terms. 251991Sheppo */ 261991Sheppo 271991Sheppo /* 282410Slm66018 * sun4v LDC Link Layer 291991Sheppo */ 301991Sheppo #include <sys/types.h> 311991Sheppo #include <sys/file.h> 321991Sheppo #include <sys/errno.h> 331991Sheppo #include <sys/open.h> 341991Sheppo #include <sys/cred.h> 351991Sheppo #include <sys/kmem.h> 361991Sheppo #include <sys/conf.h> 371991Sheppo #include <sys/cmn_err.h> 381991Sheppo #include <sys/ksynch.h> 391991Sheppo #include <sys/modctl.h> 401991Sheppo #include <sys/stat.h> /* needed for S_IFBLK and S_IFCHR */ 411991Sheppo #include <sys/debug.h> 421991Sheppo #include <sys/cred.h> 431991Sheppo #include <sys/promif.h> 441991Sheppo #include <sys/ddi.h> 451991Sheppo #include <sys/sunddi.h> 461991Sheppo #include <sys/cyclic.h> 471991Sheppo #include <sys/machsystm.h> 481991Sheppo #include <sys/vm.h> 491991Sheppo #include <sys/cpu.h> 501991Sheppo #include <sys/intreg.h> 511991Sheppo #include <sys/machcpuvar.h> 522531Snarayan #include <sys/mmu.h> 532531Snarayan #include <sys/pte.h> 542531Snarayan #include <vm/hat.h> 552531Snarayan #include <vm/as.h> 562531Snarayan #include <vm/hat_sfmmu.h> 572531Snarayan #include <sys/vm_machparam.h> 582531Snarayan #include <vm/seg_kmem.h> 592531Snarayan #include <vm/seg_kpm.h> 601991Sheppo #include <sys/note.h> 611991Sheppo #include <sys/ivintr.h> 621991Sheppo #include <sys/hypervisor_api.h> 631991Sheppo #include <sys/ldc.h> 641991Sheppo #include <sys/ldc_impl.h> 651991Sheppo #include <sys/cnex.h> 661991Sheppo #include <sys/hsvc.h> 675944Sha137994 #include <sys/sdt.h> 688542SHaik.Aftandilian@Sun.COM #include <sys/kldc.h> 691991Sheppo 701991Sheppo /* Core internal functions */ 716408Sha137994 int i_ldc_h2v_error(int h_error); 726408Sha137994 void i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset); 736408Sha137994 741991Sheppo static int i_ldc_txq_reconf(ldc_chan_t *ldcp); 752793Slm66018 static int i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset); 76*10055SKevin.Crowe@Sun.COM static void i_ldc_rxq_drain(ldc_chan_t *ldcp); 771991Sheppo static void i_ldc_reset_state(ldc_chan_t *ldcp); 788542SHaik.Aftandilian@Sun.COM static void i_ldc_debug_enter(void); 791991Sheppo 801991Sheppo static int i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail); 814690Snarayan static void i_ldc_get_tx_head(ldc_chan_t *ldcp, uint64_t *head); 821991Sheppo static int i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail); 831991Sheppo static int i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head); 841991Sheppo static int i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype, 851991Sheppo uint8_t ctrlmsg); 861991Sheppo 875944Sha137994 static int i_ldc_set_rxdq_head(ldc_chan_t *ldcp, uint64_t head); 885944Sha137994 static void i_ldc_rxdq_copy(ldc_chan_t *ldcp, uint64_t *head); 895944Sha137994 static uint64_t i_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, 905944Sha137994 uint64_t *tail, uint64_t *link_state); 915944Sha137994 static uint64_t i_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, 925944Sha137994 uint64_t *tail, uint64_t *link_state); 935944Sha137994 static int i_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head, 945944Sha137994 uint64_t rx_tail); 955944Sha137994 static uint_t i_ldc_chkq(ldc_chan_t *ldcp); 965944Sha137994 971991Sheppo /* Interrupt handling functions */ 981991Sheppo static uint_t i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2); 991991Sheppo static uint_t i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2); 1005944Sha137994 static uint_t i_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client, 1015944Sha137994 uint64_t *notify_event); 1021991Sheppo static void i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype); 1031991Sheppo 1041991Sheppo /* Read method functions */ 1051991Sheppo static int i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep); 1061991Sheppo static int i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp, 1071991Sheppo size_t *sizep); 1081991Sheppo static int i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp, 1091991Sheppo size_t *sizep); 1101991Sheppo 1111991Sheppo /* Write method functions */ 1121991Sheppo static int i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t target_bufp, 1131991Sheppo size_t *sizep); 1141991Sheppo static int i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t target_bufp, 1151991Sheppo size_t *sizep); 1161991Sheppo static int i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t target_bufp, 1171991Sheppo size_t *sizep); 1181991Sheppo 1191991Sheppo /* Pkt processing internal functions */ 1201991Sheppo static int i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg); 1211991Sheppo static int i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *ldcmsg); 1221991Sheppo static int i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg); 1231991Sheppo static int i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg); 1241991Sheppo static int i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg); 1251991Sheppo static int i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg); 1261991Sheppo static int i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg); 1271991Sheppo 1281991Sheppo /* LDC Version */ 1291991Sheppo static ldc_ver_t ldc_versions[] = { {1, 0} }; 1301991Sheppo 1311991Sheppo /* number of supported versions */ 1321991Sheppo #define LDC_NUM_VERS (sizeof (ldc_versions) / sizeof (ldc_versions[0])) 1331991Sheppo 1345944Sha137994 /* Invalid value for the ldc_chan_t rx_ack_head field */ 1355944Sha137994 #define ACKPEEK_HEAD_INVALID ((uint64_t)-1) 1365944Sha137994 1375944Sha137994 1381991Sheppo /* Module State Pointer */ 1396408Sha137994 ldc_soft_state_t *ldcssp; 1401991Sheppo 1411991Sheppo static struct modldrv md = { 1421991Sheppo &mod_miscops, /* This is a misc module */ 1437799SRichard.Bean@Sun.COM "sun4v LDC module", /* Name of the module */ 1441991Sheppo }; 1451991Sheppo 1461991Sheppo static struct modlinkage ml = { 1471991Sheppo MODREV_1, 1481991Sheppo &md, 1491991Sheppo NULL 1501991Sheppo }; 1511991Sheppo 1521991Sheppo static uint64_t ldc_sup_minor; /* Supported minor number */ 1531991Sheppo static hsvc_info_t ldc_hsvc = { 1546845Sha137994 HSVC_REV_1, NULL, HSVC_GROUP_LDC, 1, 1, "ldc" 1551991Sheppo }; 1561991Sheppo 1572531Snarayan /* 1582410Slm66018 * The no. of MTU size messages that can be stored in 1592410Slm66018 * the LDC Tx queue. The number of Tx queue entries is 1602410Slm66018 * then computed as (mtu * mtu_msgs)/sizeof(queue_entry) 1612410Slm66018 */ 1622410Slm66018 uint64_t ldc_mtu_msgs = LDC_MTU_MSGS; 1632410Slm66018 1642410Slm66018 /* 1652410Slm66018 * The minimum queue length. This is the size of the smallest 1662410Slm66018 * LDC queue. If the computed value is less than this default, 1672410Slm66018 * the queue length is rounded up to 'ldc_queue_entries'. 1682410Slm66018 */ 1692410Slm66018 uint64_t ldc_queue_entries = LDC_QUEUE_ENTRIES; 1702410Slm66018 1712410Slm66018 /* 1725944Sha137994 * The length of the reliable-mode data queue in terms of the LDC 1735944Sha137994 * receive queue length. i.e., the number of times larger than the 1745944Sha137994 * LDC receive queue that the data queue should be. The HV receive 1755944Sha137994 * queue is required to be a power of 2 and this implementation 1765944Sha137994 * assumes the data queue will also be a power of 2. By making the 1775944Sha137994 * multiplier a power of 2, we ensure the data queue will be a 1785944Sha137994 * power of 2. We use a multiplier because the receive queue is 1795944Sha137994 * sized to be sane relative to the MTU and the same is needed for 1805944Sha137994 * the data queue. 1815944Sha137994 */ 1825944Sha137994 uint64_t ldc_rxdq_multiplier = LDC_RXDQ_MULTIPLIER; 1835944Sha137994 1845944Sha137994 /* 1852410Slm66018 * LDC retry count and delay - when the HV returns EWOULDBLOCK 1862410Slm66018 * the operation is retried 'ldc_max_retries' times with a 1872410Slm66018 * wait of 'ldc_delay' usecs between each retry. 1882032Slm66018 */ 1892032Slm66018 int ldc_max_retries = LDC_MAX_RETRIES; 1902032Slm66018 clock_t ldc_delay = LDC_DELAY; 1912032Slm66018 1923151Ssg70180 /* 1938542SHaik.Aftandilian@Sun.COM * Channels which have a devclass satisfying the following 1948542SHaik.Aftandilian@Sun.COM * will be reset when entering the prom or kmdb. 1958542SHaik.Aftandilian@Sun.COM * 1968542SHaik.Aftandilian@Sun.COM * LDC_DEVCLASS_PROM_RESET(devclass) != 0 1978542SHaik.Aftandilian@Sun.COM * 1988542SHaik.Aftandilian@Sun.COM * By default, only block device service channels are reset. 1998542SHaik.Aftandilian@Sun.COM */ 2008542SHaik.Aftandilian@Sun.COM #define LDC_DEVCLASS_BIT(dc) (0x1 << (dc)) 2018542SHaik.Aftandilian@Sun.COM #define LDC_DEVCLASS_PROM_RESET(dc) \ 2028542SHaik.Aftandilian@Sun.COM (LDC_DEVCLASS_BIT(dc) & ldc_debug_reset_mask) 2038542SHaik.Aftandilian@Sun.COM static uint64_t ldc_debug_reset_mask = LDC_DEVCLASS_BIT(LDC_DEV_BLK_SVC); 2048542SHaik.Aftandilian@Sun.COM 2058542SHaik.Aftandilian@Sun.COM /* 2063151Ssg70180 * delay between each retry of channel unregistration in 2073151Ssg70180 * ldc_close(), to wait for pending interrupts to complete. 2083151Ssg70180 */ 2093151Ssg70180 clock_t ldc_close_delay = LDC_CLOSE_DELAY; 2103151Ssg70180 2111991Sheppo #ifdef DEBUG 2121991Sheppo 2131991Sheppo /* 2141991Sheppo * Print debug messages 2151991Sheppo * 2161991Sheppo * set ldcdbg to 0x7 for enabling all msgs 2171991Sheppo * 0x4 - Warnings 2181991Sheppo * 0x2 - All debug messages 2191991Sheppo * 0x1 - Minimal debug messages 2201991Sheppo * 2211991Sheppo * set ldcdbgchan to the channel number you want to debug 2221991Sheppo * setting it to -1 prints debug messages for all channels 2231991Sheppo * NOTE: ldcdbgchan has no effect on error messages 2241991Sheppo */ 2251991Sheppo 2261991Sheppo int ldcdbg = 0x0; 2271991Sheppo int64_t ldcdbgchan = DBG_ALL_LDCS; 2283560Snarayan uint64_t ldc_inject_err_flag = 0; 2291991Sheppo 2306408Sha137994 void 2311991Sheppo ldcdebug(int64_t id, const char *fmt, ...) 2321991Sheppo { 2331991Sheppo char buf[512]; 2341991Sheppo va_list ap; 2351991Sheppo 2361991Sheppo /* 2371991Sheppo * Do not return if, 2381991Sheppo * caller wants to print it anyway - (id == DBG_ALL_LDCS) 2391991Sheppo * debug channel is set to all LDCs - (ldcdbgchan == DBG_ALL_LDCS) 2401991Sheppo * debug channel = caller specified channel 2411991Sheppo */ 2421991Sheppo if ((id != DBG_ALL_LDCS) && 2431991Sheppo (ldcdbgchan != DBG_ALL_LDCS) && 2441991Sheppo (ldcdbgchan != id)) { 2451991Sheppo return; 2461991Sheppo } 2471991Sheppo 2481991Sheppo va_start(ap, fmt); 2491991Sheppo (void) vsprintf(buf, fmt, ap); 2501991Sheppo va_end(ap); 2511991Sheppo 2522793Slm66018 cmn_err(CE_CONT, "?%s", buf); 2532793Slm66018 } 2542793Slm66018 2556845Sha137994 #define LDC_ERR_RESET 0x1 2566845Sha137994 #define LDC_ERR_PKTLOSS 0x2 2576845Sha137994 #define LDC_ERR_DQFULL 0x4 2586845Sha137994 #define LDC_ERR_DRNGCLEAR 0x8 2593560Snarayan 2602793Slm66018 static boolean_t 2613560Snarayan ldc_inject_error(ldc_chan_t *ldcp, uint64_t error) 2622793Slm66018 { 2632793Slm66018 if ((ldcdbgchan != DBG_ALL_LDCS) && (ldcdbgchan != ldcp->id)) 2642793Slm66018 return (B_FALSE); 2652793Slm66018 2663560Snarayan if ((ldc_inject_err_flag & error) == 0) 2672793Slm66018 return (B_FALSE); 2682793Slm66018 2692793Slm66018 /* clear the injection state */ 2703560Snarayan ldc_inject_err_flag &= ~error; 2712793Slm66018 2722793Slm66018 return (B_TRUE); 2731991Sheppo } 2741991Sheppo 2751991Sheppo #define D1 \ 2761991Sheppo if (ldcdbg & 0x01) \ 2771991Sheppo ldcdebug 2781991Sheppo 2791991Sheppo #define D2 \ 2801991Sheppo if (ldcdbg & 0x02) \ 2811991Sheppo ldcdebug 2821991Sheppo 2831991Sheppo #define DWARN \ 2841991Sheppo if (ldcdbg & 0x04) \ 2851991Sheppo ldcdebug 2861991Sheppo 2871991Sheppo #define DUMP_PAYLOAD(id, addr) \ 2881991Sheppo { \ 2891991Sheppo char buf[65*3]; \ 2901991Sheppo int i; \ 2911991Sheppo uint8_t *src = (uint8_t *)addr; \ 2921991Sheppo for (i = 0; i < 64; i++, src++) \ 2931991Sheppo (void) sprintf(&buf[i * 3], "|%02x", *src); \ 2941991Sheppo (void) sprintf(&buf[i * 3], "|\n"); \ 2951991Sheppo D2((id), "payload: %s", buf); \ 2961991Sheppo } 2971991Sheppo 2981991Sheppo #define DUMP_LDC_PKT(c, s, addr) \ 2991991Sheppo { \ 3001991Sheppo ldc_msg_t *msg = (ldc_msg_t *)(addr); \ 3011991Sheppo uint32_t mid = ((c)->mode != LDC_MODE_RAW) ? msg->seqid : 0; \ 3021991Sheppo if (msg->type == LDC_DATA) { \ 3031991Sheppo D2((c)->id, "%s: msg%d (/%x/%x/%x/,env[%c%c,sz=%d])", \ 3041991Sheppo (s), mid, msg->type, msg->stype, msg->ctrl, \ 3051991Sheppo (msg->env & LDC_FRAG_START) ? 'B' : ' ', \ 3061991Sheppo (msg->env & LDC_FRAG_STOP) ? 'E' : ' ', \ 3071991Sheppo (msg->env & LDC_LEN_MASK)); \ 3081991Sheppo } else { \ 3091991Sheppo D2((c)->id, "%s: msg%d (/%x/%x/%x/,env=%x)", (s), \ 3101991Sheppo mid, msg->type, msg->stype, msg->ctrl, msg->env); \ 3111991Sheppo } \ 3121991Sheppo } 3131991Sheppo 3143560Snarayan #define LDC_INJECT_RESET(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_RESET) 3153560Snarayan #define LDC_INJECT_PKTLOSS(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_PKTLOSS) 3165944Sha137994 #define LDC_INJECT_DQFULL(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_DQFULL) 3176845Sha137994 #define LDC_INJECT_DRNGCLEAR(_ldcp) ldc_inject_error(_ldcp, LDC_ERR_DRNGCLEAR) 3186845Sha137994 extern void i_ldc_mem_inject_dring_clear(ldc_chan_t *ldcp); 3192793Slm66018 3201991Sheppo #else 3211991Sheppo 3221991Sheppo #define DBG_ALL_LDCS -1 3231991Sheppo 3241991Sheppo #define D1 3251991Sheppo #define D2 3261991Sheppo #define DWARN 3271991Sheppo 3281991Sheppo #define DUMP_PAYLOAD(id, addr) 3291991Sheppo #define DUMP_LDC_PKT(c, s, addr) 3301991Sheppo 3312793Slm66018 #define LDC_INJECT_RESET(_ldcp) (B_FALSE) 3323560Snarayan #define LDC_INJECT_PKTLOSS(_ldcp) (B_FALSE) 3335944Sha137994 #define LDC_INJECT_DQFULL(_ldcp) (B_FALSE) 3346845Sha137994 #define LDC_INJECT_DRNGCLEAR(_ldcp) (B_FALSE) 3352793Slm66018 3361991Sheppo #endif 3371991Sheppo 3385944Sha137994 /* 3395944Sha137994 * dtrace SDT probes to ease tracing of the rx data queue and HV queue 3405944Sha137994 * lengths. Just pass the head, tail, and entries values so that the 3415944Sha137994 * length can be calculated in a dtrace script when the probe is enabled. 3425944Sha137994 */ 3435944Sha137994 #define TRACE_RXDQ_LENGTH(ldcp) \ 3445944Sha137994 DTRACE_PROBE4(rxdq__size, \ 3455944Sha137994 uint64_t, ldcp->id, \ 3465944Sha137994 uint64_t, ldcp->rx_dq_head, \ 3475944Sha137994 uint64_t, ldcp->rx_dq_tail, \ 3485944Sha137994 uint64_t, ldcp->rx_dq_entries) 3495944Sha137994 3505944Sha137994 #define TRACE_RXHVQ_LENGTH(ldcp, head, tail) \ 3515944Sha137994 DTRACE_PROBE4(rxhvq__size, \ 3525944Sha137994 uint64_t, ldcp->id, \ 3535944Sha137994 uint64_t, head, \ 3545944Sha137994 uint64_t, tail, \ 3555944Sha137994 uint64_t, ldcp->rx_q_entries) 3565944Sha137994 3575944Sha137994 /* A dtrace SDT probe to ease tracing of data queue copy operations */ 3585944Sha137994 #define TRACE_RXDQ_COPY(ldcp, bytes) \ 3595944Sha137994 DTRACE_PROBE2(rxdq__copy, uint64_t, ldcp->id, uint64_t, bytes) \ 3605944Sha137994 3615944Sha137994 /* The amount of contiguous space at the tail of the queue */ 3625944Sha137994 #define Q_CONTIG_SPACE(head, tail, size) \ 3635944Sha137994 ((head) <= (tail) ? ((size) - (tail)) : \ 3645944Sha137994 ((head) - (tail) - LDC_PACKET_SIZE)) 3655944Sha137994 3661991Sheppo #define ZERO_PKT(p) \ 3671991Sheppo bzero((p), sizeof (ldc_msg_t)); 3681991Sheppo 3691991Sheppo #define IDX2COOKIE(idx, pg_szc, pg_shift) \ 3701991Sheppo (((pg_szc) << LDC_COOKIE_PGSZC_SHIFT) | ((idx) << (pg_shift))) 3711991Sheppo 3721991Sheppo int 3731991Sheppo _init(void) 3741991Sheppo { 3751991Sheppo int status; 3766845Sha137994 extern void i_ldc_mem_set_hsvc_vers(uint64_t major, uint64_t minor); 3771991Sheppo 3781991Sheppo status = hsvc_register(&ldc_hsvc, &ldc_sup_minor); 3791991Sheppo if (status != 0) { 3804423Sjb145095 cmn_err(CE_NOTE, "!%s: cannot negotiate hypervisor LDC services" 3811991Sheppo " group: 0x%lx major: %ld minor: %ld errno: %d", 3821991Sheppo ldc_hsvc.hsvc_modname, ldc_hsvc.hsvc_group, 3831991Sheppo ldc_hsvc.hsvc_major, ldc_hsvc.hsvc_minor, status); 3841991Sheppo return (-1); 3851991Sheppo } 3861991Sheppo 3876845Sha137994 /* Initialize shared memory HV API version checking */ 3886845Sha137994 i_ldc_mem_set_hsvc_vers(ldc_hsvc.hsvc_major, ldc_sup_minor); 3896845Sha137994 3901991Sheppo /* allocate soft state structure */ 3911991Sheppo ldcssp = kmem_zalloc(sizeof (ldc_soft_state_t), KM_SLEEP); 3921991Sheppo 3931991Sheppo /* Link the module into the system */ 3941991Sheppo status = mod_install(&ml); 3951991Sheppo if (status != 0) { 3961991Sheppo kmem_free(ldcssp, sizeof (ldc_soft_state_t)); 3971991Sheppo return (status); 3981991Sheppo } 3991991Sheppo 4001991Sheppo /* Initialize the LDC state structure */ 4011991Sheppo mutex_init(&ldcssp->lock, NULL, MUTEX_DRIVER, NULL); 4021991Sheppo 4031991Sheppo mutex_enter(&ldcssp->lock); 4041991Sheppo 4052531Snarayan /* Create a cache for memory handles */ 4062531Snarayan ldcssp->memhdl_cache = kmem_cache_create("ldc_memhdl_cache", 4072531Snarayan sizeof (ldc_mhdl_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 4082531Snarayan if (ldcssp->memhdl_cache == NULL) { 4092531Snarayan DWARN(DBG_ALL_LDCS, "_init: ldc_memhdl cache create failed\n"); 4102531Snarayan mutex_exit(&ldcssp->lock); 4112531Snarayan return (-1); 4122531Snarayan } 4132531Snarayan 4142531Snarayan /* Create cache for memory segment structures */ 4152531Snarayan ldcssp->memseg_cache = kmem_cache_create("ldc_memseg_cache", 4162531Snarayan sizeof (ldc_memseg_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 4172531Snarayan if (ldcssp->memseg_cache == NULL) { 4182531Snarayan DWARN(DBG_ALL_LDCS, "_init: ldc_memseg cache create failed\n"); 4192531Snarayan mutex_exit(&ldcssp->lock); 4202531Snarayan return (-1); 4212531Snarayan } 4222531Snarayan 4232531Snarayan 4241991Sheppo ldcssp->channel_count = 0; 4251991Sheppo ldcssp->channels_open = 0; 4261991Sheppo ldcssp->chan_list = NULL; 4271991Sheppo ldcssp->dring_list = NULL; 4281991Sheppo 4298542SHaik.Aftandilian@Sun.COM /* Register debug_enter callback */ 4308542SHaik.Aftandilian@Sun.COM kldc_set_debug_cb(&i_ldc_debug_enter); 4318542SHaik.Aftandilian@Sun.COM 4321991Sheppo mutex_exit(&ldcssp->lock); 4331991Sheppo 4341991Sheppo return (0); 4351991Sheppo } 4361991Sheppo 4371991Sheppo int 4381991Sheppo _info(struct modinfo *modinfop) 4391991Sheppo { 4401991Sheppo /* Report status of the dynamically loadable driver module */ 4411991Sheppo return (mod_info(&ml, modinfop)); 4421991Sheppo } 4431991Sheppo 4441991Sheppo int 4451991Sheppo _fini(void) 4461991Sheppo { 4471991Sheppo int rv, status; 4484690Snarayan ldc_chan_t *tmp_ldcp, *ldcp; 4494690Snarayan ldc_dring_t *tmp_dringp, *dringp; 4501991Sheppo ldc_mem_info_t minfo; 4511991Sheppo 4521991Sheppo /* Unlink the driver module from the system */ 4531991Sheppo status = mod_remove(&ml); 4541991Sheppo if (status) { 4551991Sheppo DWARN(DBG_ALL_LDCS, "_fini: mod_remove failed\n"); 4561991Sheppo return (EIO); 4571991Sheppo } 4581991Sheppo 4598542SHaik.Aftandilian@Sun.COM /* Unregister debug_enter callback */ 4608542SHaik.Aftandilian@Sun.COM kldc_set_debug_cb(NULL); 4618542SHaik.Aftandilian@Sun.COM 4621991Sheppo /* Free descriptor rings */ 4631991Sheppo dringp = ldcssp->dring_list; 4641991Sheppo while (dringp != NULL) { 4654690Snarayan tmp_dringp = dringp->next; 4661991Sheppo 4671991Sheppo rv = ldc_mem_dring_info((ldc_dring_handle_t)dringp, &minfo); 4681991Sheppo if (rv == 0 && minfo.status != LDC_UNBOUND) { 4691991Sheppo if (minfo.status == LDC_BOUND) { 4701991Sheppo (void) ldc_mem_dring_unbind( 4714690Snarayan (ldc_dring_handle_t)dringp); 4721991Sheppo } 4731991Sheppo if (minfo.status == LDC_MAPPED) { 4741991Sheppo (void) ldc_mem_dring_unmap( 4754690Snarayan (ldc_dring_handle_t)dringp); 4761991Sheppo } 4771991Sheppo } 4781991Sheppo 4791991Sheppo (void) ldc_mem_dring_destroy((ldc_dring_handle_t)dringp); 4804690Snarayan dringp = tmp_dringp; 4811991Sheppo } 4821991Sheppo ldcssp->dring_list = NULL; 4831991Sheppo 4844690Snarayan /* close and finalize channels */ 4854690Snarayan ldcp = ldcssp->chan_list; 4864690Snarayan while (ldcp != NULL) { 4874690Snarayan tmp_ldcp = ldcp->next; 4884690Snarayan 4894690Snarayan (void) ldc_close((ldc_handle_t)ldcp); 4904690Snarayan (void) ldc_fini((ldc_handle_t)ldcp); 4914690Snarayan 4924690Snarayan ldcp = tmp_ldcp; 4934690Snarayan } 4944690Snarayan ldcssp->chan_list = NULL; 4954690Snarayan 4962531Snarayan /* Destroy kmem caches */ 4972531Snarayan kmem_cache_destroy(ldcssp->memhdl_cache); 4982531Snarayan kmem_cache_destroy(ldcssp->memseg_cache); 4992531Snarayan 5001991Sheppo /* 5011991Sheppo * We have successfully "removed" the driver. 5021991Sheppo * Destroying soft states 5031991Sheppo */ 5041991Sheppo mutex_destroy(&ldcssp->lock); 5051991Sheppo kmem_free(ldcssp, sizeof (ldc_soft_state_t)); 5061991Sheppo 5071991Sheppo (void) hsvc_unregister(&ldc_hsvc); 5081991Sheppo 5091991Sheppo return (status); 5101991Sheppo } 5111991Sheppo 5121991Sheppo /* -------------------------------------------------------------------------- */ 5131991Sheppo 5141991Sheppo /* 5152410Slm66018 * LDC Link Layer Internal Functions 5161991Sheppo */ 5171991Sheppo 5181991Sheppo /* 5191991Sheppo * Translate HV Errors to sun4v error codes 5201991Sheppo */ 5216408Sha137994 int 5221991Sheppo i_ldc_h2v_error(int h_error) 5231991Sheppo { 5241991Sheppo switch (h_error) { 5251991Sheppo 5261991Sheppo case H_EOK: 5271991Sheppo return (0); 5281991Sheppo 5291991Sheppo case H_ENORADDR: 5301991Sheppo return (EFAULT); 5311991Sheppo 5321991Sheppo case H_EBADPGSZ: 5331991Sheppo case H_EINVAL: 5341991Sheppo return (EINVAL); 5351991Sheppo 5361991Sheppo case H_EWOULDBLOCK: 5371991Sheppo return (EWOULDBLOCK); 5381991Sheppo 5391991Sheppo case H_ENOACCESS: 5401991Sheppo case H_ENOMAP: 5411991Sheppo return (EACCES); 5421991Sheppo 5431991Sheppo case H_EIO: 5441991Sheppo case H_ECPUERROR: 5451991Sheppo return (EIO); 5461991Sheppo 5471991Sheppo case H_ENOTSUPPORTED: 5481991Sheppo return (ENOTSUP); 5491991Sheppo 5501991Sheppo case H_ETOOMANY: 5511991Sheppo return (ENOSPC); 5521991Sheppo 5531991Sheppo case H_ECHANNEL: 5541991Sheppo return (ECHRNG); 5551991Sheppo default: 5561991Sheppo break; 5571991Sheppo } 5581991Sheppo 5591991Sheppo return (EIO); 5601991Sheppo } 5611991Sheppo 5621991Sheppo /* 5631991Sheppo * Reconfigure the transmit queue 5641991Sheppo */ 5651991Sheppo static int 5661991Sheppo i_ldc_txq_reconf(ldc_chan_t *ldcp) 5671991Sheppo { 5681991Sheppo int rv; 5691991Sheppo 5701991Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 5712336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 5722336Snarayan 5731991Sheppo rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries); 5741991Sheppo if (rv) { 5751991Sheppo cmn_err(CE_WARN, 5762793Slm66018 "i_ldc_txq_reconf: (0x%lx) cannot set qconf", ldcp->id); 5771991Sheppo return (EIO); 5781991Sheppo } 5791991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, &(ldcp->tx_head), 5801991Sheppo &(ldcp->tx_tail), &(ldcp->link_state)); 5811991Sheppo if (rv) { 5821991Sheppo cmn_err(CE_WARN, 5832793Slm66018 "i_ldc_txq_reconf: (0x%lx) cannot get qptrs", ldcp->id); 5841991Sheppo return (EIO); 5851991Sheppo } 5862793Slm66018 D1(ldcp->id, "i_ldc_txq_reconf: (0x%llx) h=0x%llx,t=0x%llx," 5871991Sheppo "s=0x%llx\n", ldcp->id, ldcp->tx_head, ldcp->tx_tail, 5881991Sheppo ldcp->link_state); 5891991Sheppo 5901991Sheppo return (0); 5911991Sheppo } 5921991Sheppo 5931991Sheppo /* 5941991Sheppo * Reconfigure the receive queue 5951991Sheppo */ 5961991Sheppo static int 5972793Slm66018 i_ldc_rxq_reconf(ldc_chan_t *ldcp, boolean_t force_reset) 5981991Sheppo { 5991991Sheppo int rv; 6001991Sheppo uint64_t rx_head, rx_tail; 6011991Sheppo 6021991Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 6031991Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 6041991Sheppo &(ldcp->link_state)); 6051991Sheppo if (rv) { 6061991Sheppo cmn_err(CE_WARN, 6072793Slm66018 "i_ldc_rxq_reconf: (0x%lx) cannot get state", 6081991Sheppo ldcp->id); 6091991Sheppo return (EIO); 6101991Sheppo } 6111991Sheppo 6122793Slm66018 if (force_reset || (ldcp->tstate & ~TS_IN_RESET) == TS_UP) { 6131991Sheppo rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra, 6144690Snarayan ldcp->rx_q_entries); 6151991Sheppo if (rv) { 6161991Sheppo cmn_err(CE_WARN, 6172793Slm66018 "i_ldc_rxq_reconf: (0x%lx) cannot set qconf", 6181991Sheppo ldcp->id); 6191991Sheppo return (EIO); 6201991Sheppo } 6212793Slm66018 D1(ldcp->id, "i_ldc_rxq_reconf: (0x%llx) completed q reconf", 6221991Sheppo ldcp->id); 6231991Sheppo } 6241991Sheppo 6251991Sheppo return (0); 6261991Sheppo } 6271991Sheppo 6282841Snarayan 6292841Snarayan /* 6302841Snarayan * Drain the contents of the receive queue 6312841Snarayan */ 632*10055SKevin.Crowe@Sun.COM static void 6332841Snarayan i_ldc_rxq_drain(ldc_chan_t *ldcp) 6342841Snarayan { 6352841Snarayan int rv; 6362841Snarayan uint64_t rx_head, rx_tail; 637*10055SKevin.Crowe@Sun.COM int retries = 0; 6382841Snarayan 6392841Snarayan ASSERT(MUTEX_HELD(&ldcp->lock)); 6402841Snarayan rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 6412841Snarayan &(ldcp->link_state)); 6422841Snarayan if (rv) { 643*10055SKevin.Crowe@Sun.COM cmn_err(CE_WARN, "i_ldc_rxq_drain: (0x%lx) cannot get state, " 644*10055SKevin.Crowe@Sun.COM "rv = 0x%x", ldcp->id, rv); 645*10055SKevin.Crowe@Sun.COM return; 6462841Snarayan } 6472841Snarayan 6489787SZachary.Kissel@Sun.COM /* If the queue is already empty just return success. */ 6499787SZachary.Kissel@Sun.COM if (rx_head == rx_tail) 650*10055SKevin.Crowe@Sun.COM return; 651*10055SKevin.Crowe@Sun.COM 652*10055SKevin.Crowe@Sun.COM /* 653*10055SKevin.Crowe@Sun.COM * We are draining the queue in order to close the channel. 654*10055SKevin.Crowe@Sun.COM * Call hv_ldc_rx_set_qhead directly instead of i_ldc_set_rx_head 655*10055SKevin.Crowe@Sun.COM * because we do not need to reset the channel if the set 656*10055SKevin.Crowe@Sun.COM * qhead fails. 657*10055SKevin.Crowe@Sun.COM */ 658*10055SKevin.Crowe@Sun.COM if ((rv = hv_ldc_rx_set_qhead(ldcp->id, rx_tail)) == 0) 659*10055SKevin.Crowe@Sun.COM return; 660*10055SKevin.Crowe@Sun.COM 661*10055SKevin.Crowe@Sun.COM while ((rv == H_EWOULDBLOCK) && (retries++ < ldc_max_retries)) { 662*10055SKevin.Crowe@Sun.COM drv_usecwait(ldc_delay); 663*10055SKevin.Crowe@Sun.COM if ((rv = hv_ldc_rx_set_qhead(ldcp->id, rx_tail)) == 0) 664*10055SKevin.Crowe@Sun.COM return; 665*10055SKevin.Crowe@Sun.COM } 666*10055SKevin.Crowe@Sun.COM 667*10055SKevin.Crowe@Sun.COM cmn_err(CE_WARN, "i_ldc_rxq_drain: (0x%lx) cannot set qhead 0x%lx, " 668*10055SKevin.Crowe@Sun.COM "rv = 0x%x", ldcp->id, rx_tail, rv); 6692841Snarayan } 6702841Snarayan 6712841Snarayan 6721991Sheppo /* 6731991Sheppo * Reset LDC state structure and its contents 6741991Sheppo */ 6751991Sheppo static void 6761991Sheppo i_ldc_reset_state(ldc_chan_t *ldcp) 6771991Sheppo { 6781991Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 6791991Sheppo ldcp->last_msg_snt = LDC_INIT_SEQID; 6801991Sheppo ldcp->last_ack_rcd = 0; 6811991Sheppo ldcp->last_msg_rcd = 0; 6821991Sheppo ldcp->tx_ackd_head = ldcp->tx_head; 6835944Sha137994 ldcp->stream_remains = 0; 6841991Sheppo ldcp->next_vidx = 0; 6851991Sheppo ldcp->hstate = 0; 6861991Sheppo ldcp->tstate = TS_OPEN; 6871991Sheppo ldcp->status = LDC_OPEN; 6885944Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID; 6895944Sha137994 ldcp->rx_dq_head = 0; 6905944Sha137994 ldcp->rx_dq_tail = 0; 6911991Sheppo 6921991Sheppo if (ldcp->link_state == LDC_CHANNEL_UP || 6931991Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 6941991Sheppo 6951991Sheppo if (ldcp->mode == LDC_MODE_RAW) { 6961991Sheppo ldcp->status = LDC_UP; 6971991Sheppo ldcp->tstate = TS_UP; 6981991Sheppo } else { 6991991Sheppo ldcp->status = LDC_READY; 7001991Sheppo ldcp->tstate |= TS_LINK_READY; 7011991Sheppo } 7021991Sheppo } 7031991Sheppo } 7041991Sheppo 7051991Sheppo /* 7061991Sheppo * Reset a LDC channel 7071991Sheppo */ 7086408Sha137994 void 7092793Slm66018 i_ldc_reset(ldc_chan_t *ldcp, boolean_t force_reset) 7101991Sheppo { 7113560Snarayan DWARN(ldcp->id, "i_ldc_reset: (0x%llx) channel reset\n", ldcp->id); 7121991Sheppo 7132336Snarayan ASSERT(MUTEX_HELD(&ldcp->lock)); 7142336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 7152336Snarayan 7162793Slm66018 /* reconfig Tx and Rx queues */ 7171991Sheppo (void) i_ldc_txq_reconf(ldcp); 7182793Slm66018 (void) i_ldc_rxq_reconf(ldcp, force_reset); 7192793Slm66018 7202793Slm66018 /* Clear Tx and Rx interrupts */ 7212793Slm66018 (void) i_ldc_clear_intr(ldcp, CNEX_TX_INTR); 7222793Slm66018 (void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 7232793Slm66018 7242793Slm66018 /* Reset channel state */ 7251991Sheppo i_ldc_reset_state(ldcp); 7262793Slm66018 7272793Slm66018 /* Mark channel in reset */ 7282793Slm66018 ldcp->tstate |= TS_IN_RESET; 7291991Sheppo } 7301991Sheppo 7318542SHaik.Aftandilian@Sun.COM /* 7328542SHaik.Aftandilian@Sun.COM * Walk the channel list and reset channels if they are of the right 7338542SHaik.Aftandilian@Sun.COM * devclass and their Rx queues have been configured. No locks are 7348542SHaik.Aftandilian@Sun.COM * taken because the function is only invoked by the kernel just before 7358542SHaik.Aftandilian@Sun.COM * entering the prom or debugger when the system is single-threaded. 7368542SHaik.Aftandilian@Sun.COM */ 7378542SHaik.Aftandilian@Sun.COM static void 7388542SHaik.Aftandilian@Sun.COM i_ldc_debug_enter(void) 7398542SHaik.Aftandilian@Sun.COM { 7408542SHaik.Aftandilian@Sun.COM ldc_chan_t *ldcp; 7418542SHaik.Aftandilian@Sun.COM 7428542SHaik.Aftandilian@Sun.COM ldcp = ldcssp->chan_list; 7438542SHaik.Aftandilian@Sun.COM while (ldcp != NULL) { 7448542SHaik.Aftandilian@Sun.COM if (((ldcp->tstate & TS_QCONF_RDY) == TS_QCONF_RDY) && 7458542SHaik.Aftandilian@Sun.COM (LDC_DEVCLASS_PROM_RESET(ldcp->devclass) != 0)) { 7468542SHaik.Aftandilian@Sun.COM (void) hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra, 7478542SHaik.Aftandilian@Sun.COM ldcp->rx_q_entries); 7488542SHaik.Aftandilian@Sun.COM } 7498542SHaik.Aftandilian@Sun.COM ldcp = ldcp->next; 7508542SHaik.Aftandilian@Sun.COM } 7518542SHaik.Aftandilian@Sun.COM } 7522531Snarayan 7531991Sheppo /* 7541991Sheppo * Clear pending interrupts 7551991Sheppo */ 7561991Sheppo static void 7571991Sheppo i_ldc_clear_intr(ldc_chan_t *ldcp, cnex_intrtype_t itype) 7581991Sheppo { 7591991Sheppo ldc_cnex_t *cinfo = &ldcssp->cinfo; 7601991Sheppo 7611991Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 7622793Slm66018 ASSERT(cinfo->dip != NULL); 7632793Slm66018 7642793Slm66018 switch (itype) { 7652793Slm66018 case CNEX_TX_INTR: 7662531Snarayan /* check Tx interrupt */ 7672793Slm66018 if (ldcp->tx_intr_state) 7682793Slm66018 ldcp->tx_intr_state = LDC_INTR_NONE; 7692793Slm66018 else 7702793Slm66018 return; 7712793Slm66018 break; 7722793Slm66018 7732793Slm66018 case CNEX_RX_INTR: 7742531Snarayan /* check Rx interrupt */ 7752793Slm66018 if (ldcp->rx_intr_state) 7762793Slm66018 ldcp->rx_intr_state = LDC_INTR_NONE; 7772793Slm66018 else 7782793Slm66018 return; 7792793Slm66018 break; 7802793Slm66018 } 7812793Slm66018 7822793Slm66018 (void) cinfo->clr_intr(cinfo->dip, ldcp->id, itype); 7832793Slm66018 D2(ldcp->id, 7842793Slm66018 "i_ldc_clear_intr: (0x%llx) cleared 0x%x intr\n", 7852793Slm66018 ldcp->id, itype); 7861991Sheppo } 7871991Sheppo 7881991Sheppo /* 7891991Sheppo * Set the receive queue head 7902032Slm66018 * Resets connection and returns an error if it fails. 7911991Sheppo */ 7921991Sheppo static int 7931991Sheppo i_ldc_set_rx_head(ldc_chan_t *ldcp, uint64_t head) 7941991Sheppo { 7952032Slm66018 int rv; 7962032Slm66018 int retries; 7971991Sheppo 7981991Sheppo ASSERT(MUTEX_HELD(&ldcp->lock)); 7992032Slm66018 for (retries = 0; retries < ldc_max_retries; retries++) { 8002032Slm66018 8012032Slm66018 if ((rv = hv_ldc_rx_set_qhead(ldcp->id, head)) == 0) 8022032Slm66018 return (0); 8032032Slm66018 8042032Slm66018 if (rv != H_EWOULDBLOCK) 8052032Slm66018 break; 8062032Slm66018 8072032Slm66018 /* wait for ldc_delay usecs */ 8082032Slm66018 drv_usecwait(ldc_delay); 8092032Slm66018 } 8102032Slm66018 811*10055SKevin.Crowe@Sun.COM cmn_err(CE_WARN, "ldc_set_rx_qhead: (0x%lx) cannot set qhead 0x%lx, " 812*10055SKevin.Crowe@Sun.COM "rv = 0x%x", ldcp->id, head, rv); 8132336Snarayan mutex_enter(&ldcp->tx_lock); 8142793Slm66018 i_ldc_reset(ldcp, B_TRUE); 8152336Snarayan mutex_exit(&ldcp->tx_lock); 8162032Slm66018 8172032Slm66018 return (ECONNRESET); 8181991Sheppo } 8191991Sheppo 8204690Snarayan /* 8214690Snarayan * Returns the tx_head to be used for transfer 8224690Snarayan */ 8234690Snarayan static void 8244690Snarayan i_ldc_get_tx_head(ldc_chan_t *ldcp, uint64_t *head) 8254690Snarayan { 8264690Snarayan ldc_msg_t *pkt; 8274690Snarayan 8284690Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 8294690Snarayan 8304690Snarayan /* get current Tx head */ 8314690Snarayan *head = ldcp->tx_head; 8324690Snarayan 8334690Snarayan /* 8344690Snarayan * Reliable mode will use the ACKd head instead of the regular tx_head. 8354690Snarayan * Also in Reliable mode, advance ackd_head for all non DATA/INFO pkts, 8364690Snarayan * up to the current location of tx_head. This needs to be done 8374690Snarayan * as the peer will only ACK DATA/INFO pkts. 8384690Snarayan */ 8396408Sha137994 if (ldcp->mode == LDC_MODE_RELIABLE) { 8404690Snarayan while (ldcp->tx_ackd_head != ldcp->tx_head) { 8414690Snarayan pkt = (ldc_msg_t *)(ldcp->tx_q_va + ldcp->tx_ackd_head); 8424690Snarayan if ((pkt->type & LDC_DATA) && (pkt->stype & LDC_INFO)) { 8434690Snarayan break; 8444690Snarayan } 8454690Snarayan /* advance ACKd head */ 8464690Snarayan ldcp->tx_ackd_head = 8474690Snarayan (ldcp->tx_ackd_head + LDC_PACKET_SIZE) % 8484690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 8494690Snarayan } 8504690Snarayan *head = ldcp->tx_ackd_head; 8514690Snarayan } 8524690Snarayan } 8531991Sheppo 8541991Sheppo /* 8551991Sheppo * Returns the tx_tail to be used for transfer 8561991Sheppo * Re-reads the TX queue ptrs if and only if the 8571991Sheppo * the cached head and tail are equal (queue is full) 8581991Sheppo */ 8591991Sheppo static int 8601991Sheppo i_ldc_get_tx_tail(ldc_chan_t *ldcp, uint64_t *tail) 8611991Sheppo { 8621991Sheppo int rv; 8631991Sheppo uint64_t current_head, new_tail; 8641991Sheppo 8652336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 8661991Sheppo /* Read the head and tail ptrs from HV */ 8671991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 8681991Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 8691991Sheppo if (rv) { 8701991Sheppo cmn_err(CE_WARN, 8711991Sheppo "i_ldc_get_tx_tail: (0x%lx) cannot read qptrs\n", 8721991Sheppo ldcp->id); 8731991Sheppo return (EIO); 8741991Sheppo } 8751991Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN) { 8763010Slm66018 D1(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) channel not ready\n", 8771991Sheppo ldcp->id); 8781991Sheppo return (ECONNRESET); 8791991Sheppo } 8801991Sheppo 8814690Snarayan i_ldc_get_tx_head(ldcp, ¤t_head); 8821991Sheppo 8831991Sheppo /* increment the tail */ 8841991Sheppo new_tail = (ldcp->tx_tail + LDC_PACKET_SIZE) % 8854690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 8861991Sheppo 8871991Sheppo if (new_tail == current_head) { 8881991Sheppo DWARN(ldcp->id, 8891991Sheppo "i_ldc_get_tx_tail: (0x%llx) TX queue is full\n", 8901991Sheppo ldcp->id); 8911991Sheppo return (EWOULDBLOCK); 8921991Sheppo } 8931991Sheppo 8941991Sheppo D2(ldcp->id, "i_ldc_get_tx_tail: (0x%llx) head=0x%llx, tail=0x%llx\n", 8951991Sheppo ldcp->id, ldcp->tx_head, ldcp->tx_tail); 8961991Sheppo 8971991Sheppo *tail = ldcp->tx_tail; 8981991Sheppo return (0); 8991991Sheppo } 9001991Sheppo 9011991Sheppo /* 9021991Sheppo * Set the tail pointer. If HV returns EWOULDBLOCK, it will back off 9032032Slm66018 * and retry ldc_max_retries times before returning an error. 9041991Sheppo * Returns 0, EWOULDBLOCK or EIO 9051991Sheppo */ 9061991Sheppo static int 9071991Sheppo i_ldc_set_tx_tail(ldc_chan_t *ldcp, uint64_t tail) 9081991Sheppo { 9091991Sheppo int rv, retval = EWOULDBLOCK; 9102032Slm66018 int retries; 9111991Sheppo 9122336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 9132032Slm66018 for (retries = 0; retries < ldc_max_retries; retries++) { 9141991Sheppo 9151991Sheppo if ((rv = hv_ldc_tx_set_qtail(ldcp->id, tail)) == 0) { 9161991Sheppo retval = 0; 9171991Sheppo break; 9181991Sheppo } 9191991Sheppo if (rv != H_EWOULDBLOCK) { 9201991Sheppo DWARN(ldcp->id, "i_ldc_set_tx_tail: (0x%llx) set " 9211991Sheppo "qtail=0x%llx failed, rv=%d\n", ldcp->id, tail, rv); 9221991Sheppo retval = EIO; 9231991Sheppo break; 9241991Sheppo } 9251991Sheppo 9262032Slm66018 /* wait for ldc_delay usecs */ 9272032Slm66018 drv_usecwait(ldc_delay); 9281991Sheppo } 9291991Sheppo return (retval); 9301991Sheppo } 9311991Sheppo 9321991Sheppo /* 9335944Sha137994 * Copy a data packet from the HV receive queue to the data queue. 9345944Sha137994 * Caller must ensure that the data queue is not already full. 9355944Sha137994 * 9365944Sha137994 * The *head argument represents the current head pointer for the HV 9375944Sha137994 * receive queue. After copying a packet from the HV receive queue, 9385944Sha137994 * the *head pointer will be updated. This allows the caller to update 9395944Sha137994 * the head pointer in HV using the returned *head value. 9405944Sha137994 */ 9415944Sha137994 void 9425944Sha137994 i_ldc_rxdq_copy(ldc_chan_t *ldcp, uint64_t *head) 9435944Sha137994 { 9445944Sha137994 uint64_t q_size, dq_size; 9455944Sha137994 9465944Sha137994 ASSERT(MUTEX_HELD(&ldcp->lock)); 9475944Sha137994 9485944Sha137994 q_size = ldcp->rx_q_entries << LDC_PACKET_SHIFT; 9495944Sha137994 dq_size = ldcp->rx_dq_entries << LDC_PACKET_SHIFT; 9505944Sha137994 9515944Sha137994 ASSERT(Q_CONTIG_SPACE(ldcp->rx_dq_head, ldcp->rx_dq_tail, 9525944Sha137994 dq_size) >= LDC_PACKET_SIZE); 9535944Sha137994 9545944Sha137994 bcopy((void *)(ldcp->rx_q_va + *head), 9555944Sha137994 (void *)(ldcp->rx_dq_va + ldcp->rx_dq_tail), LDC_PACKET_SIZE); 9565944Sha137994 TRACE_RXDQ_COPY(ldcp, LDC_PACKET_SIZE); 9575944Sha137994 9585944Sha137994 /* Update rx head */ 9595944Sha137994 *head = (*head + LDC_PACKET_SIZE) % q_size; 9605944Sha137994 9615944Sha137994 /* Update dq tail */ 9625944Sha137994 ldcp->rx_dq_tail = (ldcp->rx_dq_tail + LDC_PACKET_SIZE) % dq_size; 9635944Sha137994 } 9645944Sha137994 9655944Sha137994 /* 9665944Sha137994 * Update the Rx data queue head pointer 9675944Sha137994 */ 9685944Sha137994 static int 9695944Sha137994 i_ldc_set_rxdq_head(ldc_chan_t *ldcp, uint64_t head) 9705944Sha137994 { 9715944Sha137994 ldcp->rx_dq_head = head; 9725944Sha137994 return (0); 9735944Sha137994 } 9745944Sha137994 9755944Sha137994 /* 9765944Sha137994 * Get the Rx data queue head and tail pointers 9775944Sha137994 */ 9785944Sha137994 static uint64_t 9795944Sha137994 i_ldc_dq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail, 9805944Sha137994 uint64_t *link_state) 9815944Sha137994 { 9825944Sha137994 _NOTE(ARGUNUSED(link_state)) 9835944Sha137994 *head = ldcp->rx_dq_head; 9845944Sha137994 *tail = ldcp->rx_dq_tail; 9855944Sha137994 return (0); 9865944Sha137994 } 9875944Sha137994 9885944Sha137994 /* 9895944Sha137994 * Wrapper for the Rx HV queue set head function. Giving the 9905944Sha137994 * data queue and HV queue set head functions the same type. 9915944Sha137994 */ 9925944Sha137994 static uint64_t 9935944Sha137994 i_ldc_hvq_rx_get_state(ldc_chan_t *ldcp, uint64_t *head, uint64_t *tail, 9945944Sha137994 uint64_t *link_state) 9955944Sha137994 { 9965944Sha137994 return (i_ldc_h2v_error(hv_ldc_rx_get_state(ldcp->id, head, tail, 9975944Sha137994 link_state))); 9985944Sha137994 } 9995944Sha137994 10005944Sha137994 /* 10015944Sha137994 * LDC receive interrupt handler 10025944Sha137994 * triggered for channel with data pending to read 10035944Sha137994 * i.e. Rx queue content changes 10045944Sha137994 */ 10055944Sha137994 static uint_t 10065944Sha137994 i_ldc_rx_hdlr(caddr_t arg1, caddr_t arg2) 10075944Sha137994 { 10085944Sha137994 _NOTE(ARGUNUSED(arg2)) 10095944Sha137994 10105944Sha137994 ldc_chan_t *ldcp; 10115944Sha137994 boolean_t notify; 10125944Sha137994 uint64_t event; 10136944Sha137994 int rv, status; 10145944Sha137994 10155944Sha137994 /* Get the channel for which interrupt was received */ 10165944Sha137994 if (arg1 == NULL) { 10175944Sha137994 cmn_err(CE_WARN, "i_ldc_rx_hdlr: invalid arg\n"); 10185944Sha137994 return (DDI_INTR_UNCLAIMED); 10195944Sha137994 } 10205944Sha137994 10215944Sha137994 ldcp = (ldc_chan_t *)arg1; 10225944Sha137994 10235944Sha137994 D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n", 10245944Sha137994 ldcp->id, ldcp); 10255944Sha137994 D1(ldcp->id, "i_ldc_rx_hdlr: (%llx) USR%lx/TS%lx/HS%lx, LSTATE=%lx\n", 10265944Sha137994 ldcp->id, ldcp->status, ldcp->tstate, ldcp->hstate, 10275944Sha137994 ldcp->link_state); 10285944Sha137994 10295944Sha137994 /* Lock channel */ 10305944Sha137994 mutex_enter(&ldcp->lock); 10315944Sha137994 10325944Sha137994 /* Mark the interrupt as being actively handled */ 10335944Sha137994 ldcp->rx_intr_state = LDC_INTR_ACTIVE; 10345944Sha137994 10356944Sha137994 status = i_ldc_rx_process_hvq(ldcp, ¬ify, &event); 10365944Sha137994 10376408Sha137994 if (ldcp->mode != LDC_MODE_RELIABLE) { 10385944Sha137994 /* 10395944Sha137994 * If there are no data packets on the queue, clear 10405944Sha137994 * the interrupt. Otherwise, the ldc_read will clear 10415944Sha137994 * interrupts after draining the queue. To indicate the 10425944Sha137994 * interrupt has not yet been cleared, it is marked 10435944Sha137994 * as pending. 10445944Sha137994 */ 10455944Sha137994 if ((event & LDC_EVT_READ) == 0) { 10465944Sha137994 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 10475944Sha137994 } else { 10485944Sha137994 ldcp->rx_intr_state = LDC_INTR_PEND; 10495944Sha137994 } 10505944Sha137994 } 10515944Sha137994 10525944Sha137994 /* if callbacks are disabled, do not notify */ 10535944Sha137994 if (notify && ldcp->cb_enabled) { 10545944Sha137994 ldcp->cb_inprogress = B_TRUE; 10555944Sha137994 mutex_exit(&ldcp->lock); 10565944Sha137994 rv = ldcp->cb(event, ldcp->cb_arg); 10575944Sha137994 if (rv) { 10585944Sha137994 DWARN(ldcp->id, 10595944Sha137994 "i_ldc_rx_hdlr: (0x%llx) callback failure", 10605944Sha137994 ldcp->id); 10615944Sha137994 } 10625944Sha137994 mutex_enter(&ldcp->lock); 10635944Sha137994 ldcp->cb_inprogress = B_FALSE; 10645944Sha137994 } 10655944Sha137994 10666408Sha137994 if (ldcp->mode == LDC_MODE_RELIABLE) { 10676944Sha137994 if (status == ENOSPC) { 10686944Sha137994 /* 10696944Sha137994 * Here, ENOSPC indicates the secondary data 10706944Sha137994 * queue is full and the Rx queue is non-empty. 10716944Sha137994 * Much like how reliable and raw modes are 10726944Sha137994 * handled above, since the Rx queue is non- 10736944Sha137994 * empty, we mark the interrupt as pending to 10746944Sha137994 * indicate it has not yet been cleared. 10756944Sha137994 */ 10766944Sha137994 ldcp->rx_intr_state = LDC_INTR_PEND; 10776944Sha137994 } else { 10786944Sha137994 /* 10796944Sha137994 * We have processed all CTRL packets and 10806944Sha137994 * copied all DATA packets to the secondary 10816944Sha137994 * queue. Clear the interrupt. 10826944Sha137994 */ 10836944Sha137994 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 10846944Sha137994 } 10855944Sha137994 } 10865944Sha137994 10875944Sha137994 mutex_exit(&ldcp->lock); 10885944Sha137994 10895944Sha137994 D1(ldcp->id, "i_ldc_rx_hdlr: (0x%llx) exiting handler", ldcp->id); 10905944Sha137994 10915944Sha137994 return (DDI_INTR_CLAIMED); 10925944Sha137994 } 10935944Sha137994 10945944Sha137994 /* 10955944Sha137994 * Wrapper for the Rx HV queue processing function to be used when 10965944Sha137994 * checking the Rx HV queue for data packets. Unlike the interrupt 10975944Sha137994 * handler code flow, the Rx interrupt is not cleared here and 10985944Sha137994 * callbacks are not made. 10995944Sha137994 */ 11005944Sha137994 static uint_t 11015944Sha137994 i_ldc_chkq(ldc_chan_t *ldcp) 11025944Sha137994 { 11035944Sha137994 boolean_t notify; 11045944Sha137994 uint64_t event; 11055944Sha137994 11065944Sha137994 return (i_ldc_rx_process_hvq(ldcp, ¬ify, &event)); 11075944Sha137994 } 11085944Sha137994 11095944Sha137994 /* 11101991Sheppo * Send a LDC message 11111991Sheppo */ 11121991Sheppo static int 11131991Sheppo i_ldc_send_pkt(ldc_chan_t *ldcp, uint8_t pkttype, uint8_t subtype, 11141991Sheppo uint8_t ctrlmsg) 11151991Sheppo { 11161991Sheppo int rv; 11171991Sheppo ldc_msg_t *pkt; 11181991Sheppo uint64_t tx_tail; 11194690Snarayan uint32_t curr_seqid; 11201991Sheppo 11212336Snarayan /* Obtain Tx lock */ 11222336Snarayan mutex_enter(&ldcp->tx_lock); 11232336Snarayan 11244690Snarayan curr_seqid = ldcp->last_msg_snt; 11254690Snarayan 11261991Sheppo /* get the current tail for the message */ 11271991Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 11281991Sheppo if (rv) { 11291991Sheppo DWARN(ldcp->id, 11301991Sheppo "i_ldc_send_pkt: (0x%llx) error sending pkt, " 11311991Sheppo "type=0x%x,subtype=0x%x,ctrl=0x%x\n", 11321991Sheppo ldcp->id, pkttype, subtype, ctrlmsg); 11332336Snarayan mutex_exit(&ldcp->tx_lock); 11341991Sheppo return (rv); 11351991Sheppo } 11361991Sheppo 11371991Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 11381991Sheppo ZERO_PKT(pkt); 11391991Sheppo 11401991Sheppo /* Initialize the packet */ 11411991Sheppo pkt->type = pkttype; 11421991Sheppo pkt->stype = subtype; 11431991Sheppo pkt->ctrl = ctrlmsg; 11441991Sheppo 11451991Sheppo /* Store ackid/seqid iff it is RELIABLE mode & not a RTS/RTR message */ 11461991Sheppo if (((ctrlmsg & LDC_CTRL_MASK) != LDC_RTS) && 11471991Sheppo ((ctrlmsg & LDC_CTRL_MASK) != LDC_RTR)) { 11481991Sheppo curr_seqid++; 11491991Sheppo if (ldcp->mode != LDC_MODE_RAW) { 11501991Sheppo pkt->seqid = curr_seqid; 11511991Sheppo pkt->ackid = ldcp->last_msg_rcd; 11521991Sheppo } 11531991Sheppo } 11541991Sheppo DUMP_LDC_PKT(ldcp, "i_ldc_send_pkt", (uint64_t)pkt); 11551991Sheppo 11561991Sheppo /* initiate the send by calling into HV and set the new tail */ 11571991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 11584690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 11591991Sheppo 11601991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 11611991Sheppo if (rv) { 11621991Sheppo DWARN(ldcp->id, 11631991Sheppo "i_ldc_send_pkt:(0x%llx) error sending pkt, " 11641991Sheppo "type=0x%x,stype=0x%x,ctrl=0x%x\n", 11651991Sheppo ldcp->id, pkttype, subtype, ctrlmsg); 11662336Snarayan mutex_exit(&ldcp->tx_lock); 11671991Sheppo return (EIO); 11681991Sheppo } 11691991Sheppo 11701991Sheppo ldcp->last_msg_snt = curr_seqid; 11711991Sheppo ldcp->tx_tail = tx_tail; 11721991Sheppo 11732336Snarayan mutex_exit(&ldcp->tx_lock); 11741991Sheppo return (0); 11751991Sheppo } 11761991Sheppo 11771991Sheppo /* 11781991Sheppo * Checks if packet was received in right order 11792410Slm66018 * in the case of a reliable link. 11801991Sheppo * Returns 0 if in order, else EIO 11811991Sheppo */ 11821991Sheppo static int 11831991Sheppo i_ldc_check_seqid(ldc_chan_t *ldcp, ldc_msg_t *msg) 11841991Sheppo { 11851991Sheppo /* No seqid checking for RAW mode */ 11861991Sheppo if (ldcp->mode == LDC_MODE_RAW) 11871991Sheppo return (0); 11881991Sheppo 11891991Sheppo /* No seqid checking for version, RTS, RTR message */ 11901991Sheppo if (msg->ctrl == LDC_VER || 11911991Sheppo msg->ctrl == LDC_RTS || 11921991Sheppo msg->ctrl == LDC_RTR) 11931991Sheppo return (0); 11941991Sheppo 11951991Sheppo /* Initial seqid to use is sent in RTS/RTR and saved in last_msg_rcd */ 11961991Sheppo if (msg->seqid != (ldcp->last_msg_rcd + 1)) { 11971991Sheppo DWARN(ldcp->id, 11981991Sheppo "i_ldc_check_seqid: (0x%llx) out-of-order pkt, got 0x%x, " 11991991Sheppo "expecting 0x%x\n", ldcp->id, msg->seqid, 12001991Sheppo (ldcp->last_msg_rcd + 1)); 12011991Sheppo return (EIO); 12021991Sheppo } 12031991Sheppo 12043560Snarayan #ifdef DEBUG 12053560Snarayan if (LDC_INJECT_PKTLOSS(ldcp)) { 12063560Snarayan DWARN(ldcp->id, 12073560Snarayan "i_ldc_check_seqid: (0x%llx) inject pkt loss\n", ldcp->id); 12083560Snarayan return (EIO); 12093560Snarayan } 12103560Snarayan #endif 12113560Snarayan 12121991Sheppo return (0); 12131991Sheppo } 12141991Sheppo 12151991Sheppo 12161991Sheppo /* 12171991Sheppo * Process an incoming version ctrl message 12181991Sheppo */ 12191991Sheppo static int 12201991Sheppo i_ldc_process_VER(ldc_chan_t *ldcp, ldc_msg_t *msg) 12211991Sheppo { 12221991Sheppo int rv = 0, idx = ldcp->next_vidx; 12231991Sheppo ldc_msg_t *pkt; 12241991Sheppo uint64_t tx_tail; 12251991Sheppo ldc_ver_t *rcvd_ver; 12261991Sheppo 12271991Sheppo /* get the received version */ 12281991Sheppo rcvd_ver = (ldc_ver_t *)((uint64_t)msg + LDC_PAYLOAD_VER_OFF); 12291991Sheppo 12301991Sheppo D2(ldcp->id, "i_ldc_process_VER: (0x%llx) received VER v%u.%u\n", 12311991Sheppo ldcp->id, rcvd_ver->major, rcvd_ver->minor); 12321991Sheppo 12332336Snarayan /* Obtain Tx lock */ 12342336Snarayan mutex_enter(&ldcp->tx_lock); 12352336Snarayan 12361991Sheppo switch (msg->stype) { 12371991Sheppo case LDC_INFO: 12381991Sheppo 12392793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) { 12402793Slm66018 (void) i_ldc_txq_reconf(ldcp); 12412793Slm66018 i_ldc_reset_state(ldcp); 12422793Slm66018 mutex_exit(&ldcp->tx_lock); 12432793Slm66018 return (EAGAIN); 12442793Slm66018 } 12452793Slm66018 12461991Sheppo /* get the current tail and pkt for the response */ 12471991Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 12481991Sheppo if (rv != 0) { 12491991Sheppo DWARN(ldcp->id, 12501991Sheppo "i_ldc_process_VER: (0x%llx) err sending " 12511991Sheppo "version ACK/NACK\n", ldcp->id); 12522793Slm66018 i_ldc_reset(ldcp, B_TRUE); 12532336Snarayan mutex_exit(&ldcp->tx_lock); 12541991Sheppo return (ECONNRESET); 12551991Sheppo } 12561991Sheppo 12571991Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 12581991Sheppo ZERO_PKT(pkt); 12591991Sheppo 12601991Sheppo /* initialize the packet */ 12611991Sheppo pkt->type = LDC_CTRL; 12621991Sheppo pkt->ctrl = LDC_VER; 12631991Sheppo 12641991Sheppo for (;;) { 12651991Sheppo 12661991Sheppo D1(ldcp->id, "i_ldc_process_VER: got %u.%u chk %u.%u\n", 12671991Sheppo rcvd_ver->major, rcvd_ver->minor, 12681991Sheppo ldc_versions[idx].major, ldc_versions[idx].minor); 12691991Sheppo 12701991Sheppo if (rcvd_ver->major == ldc_versions[idx].major) { 12711991Sheppo /* major version match - ACK version */ 12721991Sheppo pkt->stype = LDC_ACK; 12731991Sheppo 12741991Sheppo /* 12751991Sheppo * lower minor version to the one this endpt 12761991Sheppo * supports, if necessary 12771991Sheppo */ 12781991Sheppo if (rcvd_ver->minor > ldc_versions[idx].minor) 12791991Sheppo rcvd_ver->minor = 12804690Snarayan ldc_versions[idx].minor; 12811991Sheppo bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver)); 12821991Sheppo 12831991Sheppo break; 12841991Sheppo } 12851991Sheppo 12861991Sheppo if (rcvd_ver->major > ldc_versions[idx].major) { 12871991Sheppo 12881991Sheppo D1(ldcp->id, "i_ldc_process_VER: using next" 12891991Sheppo " lower idx=%d, v%u.%u\n", idx, 12901991Sheppo ldc_versions[idx].major, 12911991Sheppo ldc_versions[idx].minor); 12921991Sheppo 12931991Sheppo /* nack with next lower version */ 12941991Sheppo pkt->stype = LDC_NACK; 12951991Sheppo bcopy(&ldc_versions[idx], pkt->udata, 12961991Sheppo sizeof (ldc_versions[idx])); 12971991Sheppo ldcp->next_vidx = idx; 12981991Sheppo break; 12991991Sheppo } 13001991Sheppo 13011991Sheppo /* next major version */ 13021991Sheppo idx++; 13031991Sheppo 13041991Sheppo D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx); 13051991Sheppo 13061991Sheppo if (idx == LDC_NUM_VERS) { 13071991Sheppo /* no version match - send NACK */ 13081991Sheppo pkt->stype = LDC_NACK; 13091991Sheppo bzero(pkt->udata, sizeof (ldc_ver_t)); 13101991Sheppo ldcp->next_vidx = 0; 13111991Sheppo break; 13121991Sheppo } 13131991Sheppo } 13141991Sheppo 13151991Sheppo /* initiate the send by calling into HV and set the new tail */ 13161991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 13174690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 13181991Sheppo 13191991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 13201991Sheppo if (rv == 0) { 13211991Sheppo ldcp->tx_tail = tx_tail; 13221991Sheppo if (pkt->stype == LDC_ACK) { 13231991Sheppo D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent" 13241991Sheppo " version ACK\n", ldcp->id); 13251991Sheppo /* Save the ACK'd version */ 13261991Sheppo ldcp->version.major = rcvd_ver->major; 13271991Sheppo ldcp->version.minor = rcvd_ver->minor; 13282032Slm66018 ldcp->hstate |= TS_RCVD_VER; 13291991Sheppo ldcp->tstate |= TS_VER_DONE; 13303560Snarayan D1(DBG_ALL_LDCS, 13312793Slm66018 "(0x%llx) Sent ACK, " 13322793Slm66018 "Agreed on version v%u.%u\n", 13331991Sheppo ldcp->id, rcvd_ver->major, rcvd_ver->minor); 13341991Sheppo } 13351991Sheppo } else { 13361991Sheppo DWARN(ldcp->id, 13371991Sheppo "i_ldc_process_VER: (0x%llx) error sending " 13381991Sheppo "ACK/NACK\n", ldcp->id); 13392793Slm66018 i_ldc_reset(ldcp, B_TRUE); 13402336Snarayan mutex_exit(&ldcp->tx_lock); 13411991Sheppo return (ECONNRESET); 13421991Sheppo } 13431991Sheppo 13441991Sheppo break; 13451991Sheppo 13461991Sheppo case LDC_ACK: 13472793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) == TS_VREADY) { 13482793Slm66018 if (ldcp->version.major != rcvd_ver->major || 13494690Snarayan ldcp->version.minor != rcvd_ver->minor) { 13502793Slm66018 13512793Slm66018 /* mismatched version - reset connection */ 13522793Slm66018 DWARN(ldcp->id, 13534690Snarayan "i_ldc_process_VER: (0x%llx) recvd" 13544690Snarayan " ACK ver != sent ACK ver\n", ldcp->id); 13552793Slm66018 i_ldc_reset(ldcp, B_TRUE); 13562793Slm66018 mutex_exit(&ldcp->tx_lock); 13572793Slm66018 return (ECONNRESET); 13582793Slm66018 } 13592793Slm66018 } else { 13602793Slm66018 /* SUCCESS - we have agreed on a version */ 13612793Slm66018 ldcp->version.major = rcvd_ver->major; 13622793Slm66018 ldcp->version.minor = rcvd_ver->minor; 13632793Slm66018 ldcp->tstate |= TS_VER_DONE; 13642793Slm66018 } 13652793Slm66018 13663010Slm66018 D1(ldcp->id, "(0x%llx) Got ACK, Agreed on version v%u.%u\n", 13671991Sheppo ldcp->id, rcvd_ver->major, rcvd_ver->minor); 13681991Sheppo 13691991Sheppo /* initiate RTS-RTR-RDX handshake */ 13701991Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 13711991Sheppo if (rv) { 13721991Sheppo DWARN(ldcp->id, 13732793Slm66018 "i_ldc_process_VER: (0x%llx) cannot send RTS\n", 13741991Sheppo ldcp->id); 13752793Slm66018 i_ldc_reset(ldcp, B_TRUE); 13762336Snarayan mutex_exit(&ldcp->tx_lock); 13771991Sheppo return (ECONNRESET); 13781991Sheppo } 13791991Sheppo 13801991Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 13811991Sheppo ZERO_PKT(pkt); 13821991Sheppo 13831991Sheppo pkt->type = LDC_CTRL; 13841991Sheppo pkt->stype = LDC_INFO; 13851991Sheppo pkt->ctrl = LDC_RTS; 13861991Sheppo pkt->env = ldcp->mode; 13871991Sheppo if (ldcp->mode != LDC_MODE_RAW) 13881991Sheppo pkt->seqid = LDC_INIT_SEQID; 13891991Sheppo 13901991Sheppo ldcp->last_msg_rcd = LDC_INIT_SEQID; 13911991Sheppo 13921991Sheppo DUMP_LDC_PKT(ldcp, "i_ldc_process_VER snd rts", (uint64_t)pkt); 13931991Sheppo 13941991Sheppo /* initiate the send by calling into HV and set the new tail */ 13951991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 13964690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 13971991Sheppo 13981991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 13991991Sheppo if (rv) { 14001991Sheppo D2(ldcp->id, 14011991Sheppo "i_ldc_process_VER: (0x%llx) no listener\n", 14021991Sheppo ldcp->id); 14032793Slm66018 i_ldc_reset(ldcp, B_TRUE); 14042336Snarayan mutex_exit(&ldcp->tx_lock); 14051991Sheppo return (ECONNRESET); 14061991Sheppo } 14071991Sheppo 14081991Sheppo ldcp->tx_tail = tx_tail; 14091991Sheppo ldcp->hstate |= TS_SENT_RTS; 14101991Sheppo 14111991Sheppo break; 14121991Sheppo 14131991Sheppo case LDC_NACK: 14141991Sheppo /* check if version in NACK is zero */ 14151991Sheppo if (rcvd_ver->major == 0 && rcvd_ver->minor == 0) { 14161991Sheppo /* version handshake failure */ 14171991Sheppo DWARN(DBG_ALL_LDCS, 14181991Sheppo "i_ldc_process_VER: (0x%llx) no version match\n", 14191991Sheppo ldcp->id); 14202793Slm66018 i_ldc_reset(ldcp, B_TRUE); 14212336Snarayan mutex_exit(&ldcp->tx_lock); 14221991Sheppo return (ECONNRESET); 14231991Sheppo } 14241991Sheppo 14251991Sheppo /* get the current tail and pkt for the response */ 14261991Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 14271991Sheppo if (rv != 0) { 14281991Sheppo cmn_err(CE_NOTE, 14291991Sheppo "i_ldc_process_VER: (0x%lx) err sending " 14301991Sheppo "version ACK/NACK\n", ldcp->id); 14312793Slm66018 i_ldc_reset(ldcp, B_TRUE); 14322336Snarayan mutex_exit(&ldcp->tx_lock); 14331991Sheppo return (ECONNRESET); 14341991Sheppo } 14351991Sheppo 14361991Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 14371991Sheppo ZERO_PKT(pkt); 14381991Sheppo 14391991Sheppo /* initialize the packet */ 14401991Sheppo pkt->type = LDC_CTRL; 14411991Sheppo pkt->ctrl = LDC_VER; 14421991Sheppo pkt->stype = LDC_INFO; 14431991Sheppo 14441991Sheppo /* check ver in NACK msg has a match */ 14451991Sheppo for (;;) { 14461991Sheppo if (rcvd_ver->major == ldc_versions[idx].major) { 14471991Sheppo /* 14481991Sheppo * major version match - resubmit request 14491991Sheppo * if lower minor version to the one this endpt 14501991Sheppo * supports, if necessary 14511991Sheppo */ 14521991Sheppo if (rcvd_ver->minor > ldc_versions[idx].minor) 14531991Sheppo rcvd_ver->minor = 14544690Snarayan ldc_versions[idx].minor; 14551991Sheppo bcopy(rcvd_ver, pkt->udata, sizeof (*rcvd_ver)); 14561991Sheppo break; 14571991Sheppo } 14581991Sheppo 14591991Sheppo if (rcvd_ver->major > ldc_versions[idx].major) { 14601991Sheppo 14611991Sheppo D1(ldcp->id, "i_ldc_process_VER: using next" 14621991Sheppo " lower idx=%d, v%u.%u\n", idx, 14631991Sheppo ldc_versions[idx].major, 14641991Sheppo ldc_versions[idx].minor); 14651991Sheppo 14661991Sheppo /* send next lower version */ 14671991Sheppo bcopy(&ldc_versions[idx], pkt->udata, 14681991Sheppo sizeof (ldc_versions[idx])); 14691991Sheppo ldcp->next_vidx = idx; 14701991Sheppo break; 14711991Sheppo } 14721991Sheppo 14731991Sheppo /* next version */ 14741991Sheppo idx++; 14751991Sheppo 14761991Sheppo D1(ldcp->id, "i_ldc_process_VER: inc idx %x\n", idx); 14771991Sheppo 14781991Sheppo if (idx == LDC_NUM_VERS) { 14791991Sheppo /* no version match - terminate */ 14801991Sheppo ldcp->next_vidx = 0; 14812336Snarayan mutex_exit(&ldcp->tx_lock); 14821991Sheppo return (ECONNRESET); 14831991Sheppo } 14841991Sheppo } 14851991Sheppo 14861991Sheppo /* initiate the send by calling into HV and set the new tail */ 14871991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 14884690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 14891991Sheppo 14901991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 14911991Sheppo if (rv == 0) { 14921991Sheppo D2(ldcp->id, "i_ldc_process_VER: (0x%llx) sent version" 14931991Sheppo "INFO v%u.%u\n", ldcp->id, ldc_versions[idx].major, 14941991Sheppo ldc_versions[idx].minor); 14951991Sheppo ldcp->tx_tail = tx_tail; 14961991Sheppo } else { 14971991Sheppo cmn_err(CE_NOTE, 14981991Sheppo "i_ldc_process_VER: (0x%lx) error sending version" 14991991Sheppo "INFO\n", ldcp->id); 15002793Slm66018 i_ldc_reset(ldcp, B_TRUE); 15012336Snarayan mutex_exit(&ldcp->tx_lock); 15021991Sheppo return (ECONNRESET); 15031991Sheppo } 15041991Sheppo 15051991Sheppo break; 15061991Sheppo } 15071991Sheppo 15082336Snarayan mutex_exit(&ldcp->tx_lock); 15091991Sheppo return (rv); 15101991Sheppo } 15111991Sheppo 15121991Sheppo 15131991Sheppo /* 15141991Sheppo * Process an incoming RTS ctrl message 15151991Sheppo */ 15161991Sheppo static int 15171991Sheppo i_ldc_process_RTS(ldc_chan_t *ldcp, ldc_msg_t *msg) 15181991Sheppo { 15191991Sheppo int rv = 0; 15201991Sheppo ldc_msg_t *pkt; 15211991Sheppo uint64_t tx_tail; 15221991Sheppo boolean_t sent_NACK = B_FALSE; 15231991Sheppo 15241991Sheppo D2(ldcp->id, "i_ldc_process_RTS: (0x%llx) received RTS\n", ldcp->id); 15251991Sheppo 15261991Sheppo switch (msg->stype) { 15271991Sheppo case LDC_NACK: 15281991Sheppo DWARN(ldcp->id, 15291991Sheppo "i_ldc_process_RTS: (0x%llx) RTS NACK received\n", 15301991Sheppo ldcp->id); 15311991Sheppo 15321991Sheppo /* Reset the channel -- as we cannot continue */ 15332336Snarayan mutex_enter(&ldcp->tx_lock); 15342793Slm66018 i_ldc_reset(ldcp, B_TRUE); 15352336Snarayan mutex_exit(&ldcp->tx_lock); 15361991Sheppo rv = ECONNRESET; 15371991Sheppo break; 15381991Sheppo 15391991Sheppo case LDC_INFO: 15401991Sheppo 15411991Sheppo /* check mode */ 15421991Sheppo if (ldcp->mode != (ldc_mode_t)msg->env) { 15431991Sheppo cmn_err(CE_NOTE, 15441991Sheppo "i_ldc_process_RTS: (0x%lx) mode mismatch\n", 15451991Sheppo ldcp->id); 15461991Sheppo /* 15471991Sheppo * send NACK in response to MODE message 15481991Sheppo * get the current tail for the response 15491991Sheppo */ 15501991Sheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTS); 15511991Sheppo if (rv) { 15521991Sheppo /* if cannot send NACK - reset channel */ 15532336Snarayan mutex_enter(&ldcp->tx_lock); 15542793Slm66018 i_ldc_reset(ldcp, B_TRUE); 15552336Snarayan mutex_exit(&ldcp->tx_lock); 15561991Sheppo rv = ECONNRESET; 15571991Sheppo break; 15581991Sheppo } 15591991Sheppo sent_NACK = B_TRUE; 15601991Sheppo } 15611991Sheppo break; 15621991Sheppo default: 15631991Sheppo DWARN(ldcp->id, "i_ldc_process_RTS: (0x%llx) unexp ACK\n", 15641991Sheppo ldcp->id); 15652336Snarayan mutex_enter(&ldcp->tx_lock); 15662793Slm66018 i_ldc_reset(ldcp, B_TRUE); 15672336Snarayan mutex_exit(&ldcp->tx_lock); 15681991Sheppo rv = ECONNRESET; 15691991Sheppo break; 15701991Sheppo } 15711991Sheppo 15721991Sheppo /* 15731991Sheppo * If either the connection was reset (when rv != 0) or 15741991Sheppo * a NACK was sent, we return. In the case of a NACK 15751991Sheppo * we dont want to consume the packet that came in but 15761991Sheppo * not record that we received the RTS 15771991Sheppo */ 15781991Sheppo if (rv || sent_NACK) 15791991Sheppo return (rv); 15801991Sheppo 15811991Sheppo /* record RTS received */ 15821991Sheppo ldcp->hstate |= TS_RCVD_RTS; 15831991Sheppo 15841991Sheppo /* store initial SEQID info */ 15851991Sheppo ldcp->last_msg_snt = msg->seqid; 15861991Sheppo 15872336Snarayan /* Obtain Tx lock */ 15882336Snarayan mutex_enter(&ldcp->tx_lock); 15892336Snarayan 15901991Sheppo /* get the current tail for the response */ 15911991Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 15921991Sheppo if (rv != 0) { 15931991Sheppo cmn_err(CE_NOTE, 15941991Sheppo "i_ldc_process_RTS: (0x%lx) err sending RTR\n", 15951991Sheppo ldcp->id); 15962793Slm66018 i_ldc_reset(ldcp, B_TRUE); 15972336Snarayan mutex_exit(&ldcp->tx_lock); 15981991Sheppo return (ECONNRESET); 15991991Sheppo } 16001991Sheppo 16011991Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 16021991Sheppo ZERO_PKT(pkt); 16031991Sheppo 16041991Sheppo /* initialize the packet */ 16051991Sheppo pkt->type = LDC_CTRL; 16061991Sheppo pkt->stype = LDC_INFO; 16071991Sheppo pkt->ctrl = LDC_RTR; 16081991Sheppo pkt->env = ldcp->mode; 16091991Sheppo if (ldcp->mode != LDC_MODE_RAW) 16101991Sheppo pkt->seqid = LDC_INIT_SEQID; 16111991Sheppo 16121991Sheppo ldcp->last_msg_rcd = msg->seqid; 16131991Sheppo 16141991Sheppo /* initiate the send by calling into HV and set the new tail */ 16151991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 16164690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 16171991Sheppo 16181991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 16191991Sheppo if (rv == 0) { 16201991Sheppo D2(ldcp->id, 16211991Sheppo "i_ldc_process_RTS: (0x%llx) sent RTR\n", ldcp->id); 16221991Sheppo DUMP_LDC_PKT(ldcp, "i_ldc_process_RTS sent rtr", (uint64_t)pkt); 16231991Sheppo 16241991Sheppo ldcp->tx_tail = tx_tail; 16251991Sheppo ldcp->hstate |= TS_SENT_RTR; 16261991Sheppo 16271991Sheppo } else { 16281991Sheppo cmn_err(CE_NOTE, 16291991Sheppo "i_ldc_process_RTS: (0x%lx) error sending RTR\n", 16301991Sheppo ldcp->id); 16312793Slm66018 i_ldc_reset(ldcp, B_TRUE); 16322336Snarayan mutex_exit(&ldcp->tx_lock); 16331991Sheppo return (ECONNRESET); 16341991Sheppo } 16351991Sheppo 16362336Snarayan mutex_exit(&ldcp->tx_lock); 16371991Sheppo return (0); 16381991Sheppo } 16391991Sheppo 16401991Sheppo /* 16411991Sheppo * Process an incoming RTR ctrl message 16421991Sheppo */ 16431991Sheppo static int 16441991Sheppo i_ldc_process_RTR(ldc_chan_t *ldcp, ldc_msg_t *msg) 16451991Sheppo { 16461991Sheppo int rv = 0; 16471991Sheppo boolean_t sent_NACK = B_FALSE; 16481991Sheppo 16491991Sheppo D2(ldcp->id, "i_ldc_process_RTR: (0x%llx) received RTR\n", ldcp->id); 16501991Sheppo 16511991Sheppo switch (msg->stype) { 16521991Sheppo case LDC_NACK: 16531991Sheppo /* RTR NACK received */ 16541991Sheppo DWARN(ldcp->id, 16551991Sheppo "i_ldc_process_RTR: (0x%llx) RTR NACK received\n", 16561991Sheppo ldcp->id); 16571991Sheppo 16581991Sheppo /* Reset the channel -- as we cannot continue */ 16592336Snarayan mutex_enter(&ldcp->tx_lock); 16602793Slm66018 i_ldc_reset(ldcp, B_TRUE); 16612336Snarayan mutex_exit(&ldcp->tx_lock); 16621991Sheppo rv = ECONNRESET; 16631991Sheppo 16641991Sheppo break; 16651991Sheppo 16661991Sheppo case LDC_INFO: 16671991Sheppo 16681991Sheppo /* check mode */ 16691991Sheppo if (ldcp->mode != (ldc_mode_t)msg->env) { 16701991Sheppo DWARN(ldcp->id, 16713010Slm66018 "i_ldc_process_RTR: (0x%llx) mode mismatch, " 16723010Slm66018 "expecting 0x%x, got 0x%x\n", 16733010Slm66018 ldcp->id, ldcp->mode, (ldc_mode_t)msg->env); 16741991Sheppo /* 16751991Sheppo * send NACK in response to MODE message 16761991Sheppo * get the current tail for the response 16771991Sheppo */ 16781991Sheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_NACK, LDC_RTR); 16791991Sheppo if (rv) { 16801991Sheppo /* if cannot send NACK - reset channel */ 16812336Snarayan mutex_enter(&ldcp->tx_lock); 16822793Slm66018 i_ldc_reset(ldcp, B_TRUE); 16832336Snarayan mutex_exit(&ldcp->tx_lock); 16841991Sheppo rv = ECONNRESET; 16851991Sheppo break; 16861991Sheppo } 16871991Sheppo sent_NACK = B_TRUE; 16881991Sheppo } 16891991Sheppo break; 16901991Sheppo 16911991Sheppo default: 16921991Sheppo DWARN(ldcp->id, "i_ldc_process_RTR: (0x%llx) unexp ACK\n", 16931991Sheppo ldcp->id); 16941991Sheppo 16951991Sheppo /* Reset the channel -- as we cannot continue */ 16962336Snarayan mutex_enter(&ldcp->tx_lock); 16972793Slm66018 i_ldc_reset(ldcp, B_TRUE); 16982336Snarayan mutex_exit(&ldcp->tx_lock); 16991991Sheppo rv = ECONNRESET; 17001991Sheppo break; 17011991Sheppo } 17021991Sheppo 17031991Sheppo /* 17041991Sheppo * If either the connection was reset (when rv != 0) or 17051991Sheppo * a NACK was sent, we return. In the case of a NACK 17061991Sheppo * we dont want to consume the packet that came in but 17071991Sheppo * not record that we received the RTR 17081991Sheppo */ 17091991Sheppo if (rv || sent_NACK) 17101991Sheppo return (rv); 17111991Sheppo 17121991Sheppo ldcp->last_msg_snt = msg->seqid; 17131991Sheppo ldcp->hstate |= TS_RCVD_RTR; 17141991Sheppo 17151991Sheppo rv = i_ldc_send_pkt(ldcp, LDC_CTRL, LDC_INFO, LDC_RDX); 17161991Sheppo if (rv) { 17171991Sheppo cmn_err(CE_NOTE, 17181991Sheppo "i_ldc_process_RTR: (0x%lx) cannot send RDX\n", 17191991Sheppo ldcp->id); 17202336Snarayan mutex_enter(&ldcp->tx_lock); 17212793Slm66018 i_ldc_reset(ldcp, B_TRUE); 17222336Snarayan mutex_exit(&ldcp->tx_lock); 17231991Sheppo return (ECONNRESET); 17241991Sheppo } 17251991Sheppo D2(ldcp->id, 17261991Sheppo "i_ldc_process_RTR: (0x%llx) sent RDX\n", ldcp->id); 17271991Sheppo 17281991Sheppo ldcp->hstate |= TS_SENT_RDX; 17291991Sheppo ldcp->tstate |= TS_HSHAKE_DONE; 17302793Slm66018 if ((ldcp->tstate & TS_IN_RESET) == 0) 17312793Slm66018 ldcp->status = LDC_UP; 17321991Sheppo 17333010Slm66018 D1(ldcp->id, "(0x%llx) Handshake Complete\n", ldcp->id); 17341991Sheppo 17351991Sheppo return (0); 17361991Sheppo } 17371991Sheppo 17381991Sheppo 17391991Sheppo /* 17401991Sheppo * Process an incoming RDX ctrl message 17411991Sheppo */ 17421991Sheppo static int 17431991Sheppo i_ldc_process_RDX(ldc_chan_t *ldcp, ldc_msg_t *msg) 17441991Sheppo { 17451991Sheppo int rv = 0; 17461991Sheppo 17471991Sheppo D2(ldcp->id, "i_ldc_process_RDX: (0x%llx) received RDX\n", ldcp->id); 17481991Sheppo 17491991Sheppo switch (msg->stype) { 17501991Sheppo case LDC_NACK: 17511991Sheppo /* RDX NACK received */ 17521991Sheppo DWARN(ldcp->id, 17531991Sheppo "i_ldc_process_RDX: (0x%llx) RDX NACK received\n", 17541991Sheppo ldcp->id); 17551991Sheppo 17561991Sheppo /* Reset the channel -- as we cannot continue */ 17572336Snarayan mutex_enter(&ldcp->tx_lock); 17582793Slm66018 i_ldc_reset(ldcp, B_TRUE); 17592336Snarayan mutex_exit(&ldcp->tx_lock); 17601991Sheppo rv = ECONNRESET; 17611991Sheppo 17621991Sheppo break; 17631991Sheppo 17641991Sheppo case LDC_INFO: 17651991Sheppo 17661991Sheppo /* 17671991Sheppo * if channel is UP and a RDX received after data transmission 17681991Sheppo * has commenced it is an error 17691991Sheppo */ 17701991Sheppo if ((ldcp->tstate == TS_UP) && (ldcp->hstate & TS_RCVD_RDX)) { 17711991Sheppo DWARN(DBG_ALL_LDCS, 17721991Sheppo "i_ldc_process_RDX: (0x%llx) unexpected RDX" 17731991Sheppo " - LDC reset\n", ldcp->id); 17742336Snarayan mutex_enter(&ldcp->tx_lock); 17752793Slm66018 i_ldc_reset(ldcp, B_TRUE); 17762336Snarayan mutex_exit(&ldcp->tx_lock); 17771991Sheppo return (ECONNRESET); 17781991Sheppo } 17791991Sheppo 17801991Sheppo ldcp->hstate |= TS_RCVD_RDX; 17811991Sheppo ldcp->tstate |= TS_HSHAKE_DONE; 17822793Slm66018 if ((ldcp->tstate & TS_IN_RESET) == 0) 17832793Slm66018 ldcp->status = LDC_UP; 17841991Sheppo 17851991Sheppo D1(DBG_ALL_LDCS, "(0x%llx) Handshake Complete\n", ldcp->id); 17861991Sheppo break; 17871991Sheppo 17881991Sheppo default: 17891991Sheppo DWARN(ldcp->id, "i_ldc_process_RDX: (0x%llx) unexp ACK\n", 17901991Sheppo ldcp->id); 17911991Sheppo 17921991Sheppo /* Reset the channel -- as we cannot continue */ 17932336Snarayan mutex_enter(&ldcp->tx_lock); 17942793Slm66018 i_ldc_reset(ldcp, B_TRUE); 17952336Snarayan mutex_exit(&ldcp->tx_lock); 17961991Sheppo rv = ECONNRESET; 17971991Sheppo break; 17981991Sheppo } 17991991Sheppo 18001991Sheppo return (rv); 18011991Sheppo } 18021991Sheppo 18031991Sheppo /* 18041991Sheppo * Process an incoming ACK for a data packet 18051991Sheppo */ 18061991Sheppo static int 18071991Sheppo i_ldc_process_data_ACK(ldc_chan_t *ldcp, ldc_msg_t *msg) 18081991Sheppo { 18091991Sheppo int rv; 18101991Sheppo uint64_t tx_head; 18111991Sheppo ldc_msg_t *pkt; 18121991Sheppo 18132336Snarayan /* Obtain Tx lock */ 18142336Snarayan mutex_enter(&ldcp->tx_lock); 18152336Snarayan 18161991Sheppo /* 18172336Snarayan * Read the current Tx head and tail 18181991Sheppo */ 18191991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 18201991Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 18211991Sheppo if (rv != 0) { 18221991Sheppo cmn_err(CE_WARN, 18231991Sheppo "i_ldc_process_data_ACK: (0x%lx) cannot read qptrs\n", 18241991Sheppo ldcp->id); 18252336Snarayan 18262336Snarayan /* Reset the channel -- as we cannot continue */ 18272793Slm66018 i_ldc_reset(ldcp, B_TRUE); 18282336Snarayan mutex_exit(&ldcp->tx_lock); 18292336Snarayan return (ECONNRESET); 18301991Sheppo } 18311991Sheppo 18321991Sheppo /* 18331991Sheppo * loop from where the previous ACK location was to the 18341991Sheppo * current head location. This is how far the HV has 18351991Sheppo * actually send pkts. Pkts between head and tail are 18361991Sheppo * yet to be sent by HV. 18371991Sheppo */ 18381991Sheppo tx_head = ldcp->tx_ackd_head; 18391991Sheppo for (;;) { 18401991Sheppo pkt = (ldc_msg_t *)(ldcp->tx_q_va + tx_head); 18411991Sheppo tx_head = (tx_head + LDC_PACKET_SIZE) % 18424690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 18431991Sheppo 18441991Sheppo if (pkt->seqid == msg->ackid) { 18451991Sheppo D2(ldcp->id, 18461991Sheppo "i_ldc_process_data_ACK: (0x%llx) found packet\n", 18471991Sheppo ldcp->id); 18481991Sheppo ldcp->last_ack_rcd = msg->ackid; 18491991Sheppo ldcp->tx_ackd_head = tx_head; 18501991Sheppo break; 18511991Sheppo } 18521991Sheppo if (tx_head == ldcp->tx_head) { 18531991Sheppo /* could not find packet */ 18541991Sheppo DWARN(ldcp->id, 18551991Sheppo "i_ldc_process_data_ACK: (0x%llx) invalid ACKid\n", 18561991Sheppo ldcp->id); 18572336Snarayan 18582336Snarayan /* Reset the channel -- as we cannot continue */ 18592793Slm66018 i_ldc_reset(ldcp, B_TRUE); 18602336Snarayan mutex_exit(&ldcp->tx_lock); 18612336Snarayan return (ECONNRESET); 18621991Sheppo } 18631991Sheppo } 18641991Sheppo 18652336Snarayan mutex_exit(&ldcp->tx_lock); 18661991Sheppo return (0); 18671991Sheppo } 18681991Sheppo 18691991Sheppo /* 18701991Sheppo * Process incoming control message 18711991Sheppo * Return 0 - session can continue 18721991Sheppo * EAGAIN - reprocess packet - state was changed 18731991Sheppo * ECONNRESET - channel was reset 18741991Sheppo */ 18751991Sheppo static int 18761991Sheppo i_ldc_ctrlmsg(ldc_chan_t *ldcp, ldc_msg_t *msg) 18771991Sheppo { 18781991Sheppo int rv = 0; 18791991Sheppo 18802793Slm66018 D1(ldcp->id, "i_ldc_ctrlmsg: (%llx) tstate = %lx, hstate = %lx\n", 18812793Slm66018 ldcp->id, ldcp->tstate, ldcp->hstate); 18822793Slm66018 18832793Slm66018 switch (ldcp->tstate & ~TS_IN_RESET) { 18841991Sheppo 18851991Sheppo case TS_OPEN: 18861991Sheppo case TS_READY: 18871991Sheppo 18881991Sheppo switch (msg->ctrl & LDC_CTRL_MASK) { 18891991Sheppo case LDC_VER: 18901991Sheppo /* process version message */ 18911991Sheppo rv = i_ldc_process_VER(ldcp, msg); 18921991Sheppo break; 18931991Sheppo default: 18941991Sheppo DWARN(ldcp->id, 18951991Sheppo "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x " 18961991Sheppo "tstate=0x%x\n", ldcp->id, 18971991Sheppo (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate); 18981991Sheppo break; 18991991Sheppo } 19001991Sheppo 19011991Sheppo break; 19021991Sheppo 19031991Sheppo case TS_VREADY: 19041991Sheppo 19051991Sheppo switch (msg->ctrl & LDC_CTRL_MASK) { 19061991Sheppo case LDC_VER: 19072793Slm66018 /* process version message */ 19082793Slm66018 rv = i_ldc_process_VER(ldcp, msg); 19091991Sheppo break; 19101991Sheppo case LDC_RTS: 19111991Sheppo /* process RTS message */ 19121991Sheppo rv = i_ldc_process_RTS(ldcp, msg); 19131991Sheppo break; 19141991Sheppo case LDC_RTR: 19151991Sheppo /* process RTR message */ 19161991Sheppo rv = i_ldc_process_RTR(ldcp, msg); 19171991Sheppo break; 19181991Sheppo case LDC_RDX: 19191991Sheppo /* process RDX message */ 19201991Sheppo rv = i_ldc_process_RDX(ldcp, msg); 19211991Sheppo break; 19221991Sheppo default: 19231991Sheppo DWARN(ldcp->id, 19241991Sheppo "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x " 19251991Sheppo "tstate=0x%x\n", ldcp->id, 19261991Sheppo (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate); 19271991Sheppo break; 19281991Sheppo } 19291991Sheppo 19301991Sheppo break; 19311991Sheppo 19321991Sheppo case TS_UP: 19331991Sheppo 19341991Sheppo switch (msg->ctrl & LDC_CTRL_MASK) { 19351991Sheppo case LDC_VER: 19361991Sheppo DWARN(ldcp->id, 19371991Sheppo "i_ldc_ctrlmsg: (0x%llx) unexpected VER " 19381991Sheppo "- LDC reset\n", ldcp->id); 19391991Sheppo /* peer is redoing version negotiation */ 19402336Snarayan mutex_enter(&ldcp->tx_lock); 19411991Sheppo (void) i_ldc_txq_reconf(ldcp); 19421991Sheppo i_ldc_reset_state(ldcp); 19432336Snarayan mutex_exit(&ldcp->tx_lock); 19441991Sheppo rv = EAGAIN; 19451991Sheppo break; 19461991Sheppo 19471991Sheppo case LDC_RDX: 19481991Sheppo /* process RDX message */ 19491991Sheppo rv = i_ldc_process_RDX(ldcp, msg); 19501991Sheppo break; 19511991Sheppo 19521991Sheppo default: 19531991Sheppo DWARN(ldcp->id, 19541991Sheppo "i_ldc_ctrlmsg: (0x%llx) unexp ctrl 0x%x " 19551991Sheppo "tstate=0x%x\n", ldcp->id, 19561991Sheppo (msg->ctrl & LDC_CTRL_MASK), ldcp->tstate); 19571991Sheppo break; 19581991Sheppo } 19591991Sheppo } 19601991Sheppo 19611991Sheppo return (rv); 19621991Sheppo } 19631991Sheppo 19641991Sheppo /* 19651991Sheppo * Register channel with the channel nexus 19661991Sheppo */ 19671991Sheppo static int 19681991Sheppo i_ldc_register_channel(ldc_chan_t *ldcp) 19691991Sheppo { 19701991Sheppo int rv = 0; 19711991Sheppo ldc_cnex_t *cinfo = &ldcssp->cinfo; 19721991Sheppo 19731991Sheppo if (cinfo->dip == NULL) { 19741991Sheppo DWARN(ldcp->id, 19751991Sheppo "i_ldc_register_channel: cnex has not registered\n"); 19761991Sheppo return (EAGAIN); 19771991Sheppo } 19781991Sheppo 19791991Sheppo rv = cinfo->reg_chan(cinfo->dip, ldcp->id, ldcp->devclass); 19801991Sheppo if (rv) { 19811991Sheppo DWARN(ldcp->id, 19821991Sheppo "i_ldc_register_channel: cannot register channel\n"); 19831991Sheppo return (rv); 19841991Sheppo } 19851991Sheppo 19861991Sheppo rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR, 19871991Sheppo i_ldc_tx_hdlr, ldcp, NULL); 19881991Sheppo if (rv) { 19891991Sheppo DWARN(ldcp->id, 19901991Sheppo "i_ldc_register_channel: cannot add Tx interrupt\n"); 19911991Sheppo (void) cinfo->unreg_chan(cinfo->dip, ldcp->id); 19921991Sheppo return (rv); 19931991Sheppo } 19941991Sheppo 19951991Sheppo rv = cinfo->add_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR, 19961991Sheppo i_ldc_rx_hdlr, ldcp, NULL); 19971991Sheppo if (rv) { 19981991Sheppo DWARN(ldcp->id, 19991991Sheppo "i_ldc_register_channel: cannot add Rx interrupt\n"); 20001991Sheppo (void) cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR); 20011991Sheppo (void) cinfo->unreg_chan(cinfo->dip, ldcp->id); 20021991Sheppo return (rv); 20031991Sheppo } 20041991Sheppo 20051991Sheppo ldcp->tstate |= TS_CNEX_RDY; 20061991Sheppo 20071991Sheppo return (0); 20081991Sheppo } 20091991Sheppo 20101991Sheppo /* 20111991Sheppo * Unregister a channel with the channel nexus 20121991Sheppo */ 20131991Sheppo static int 20141991Sheppo i_ldc_unregister_channel(ldc_chan_t *ldcp) 20151991Sheppo { 20161991Sheppo int rv = 0; 20171991Sheppo ldc_cnex_t *cinfo = &ldcssp->cinfo; 20181991Sheppo 20191991Sheppo if (cinfo->dip == NULL) { 20201991Sheppo DWARN(ldcp->id, 20211991Sheppo "i_ldc_unregister_channel: cnex has not registered\n"); 20221991Sheppo return (EAGAIN); 20231991Sheppo } 20241991Sheppo 20251991Sheppo if (ldcp->tstate & TS_CNEX_RDY) { 20261991Sheppo 20272336Snarayan /* Remove the Rx interrupt */ 20281991Sheppo rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_RX_INTR); 20291991Sheppo if (rv) { 20302793Slm66018 if (rv != EAGAIN) { 20312793Slm66018 DWARN(ldcp->id, 20322793Slm66018 "i_ldc_unregister_channel: err removing " 20332793Slm66018 "Rx intr\n"); 20342793Slm66018 return (rv); 20352793Slm66018 } 20362793Slm66018 20372793Slm66018 /* 20382793Slm66018 * If interrupts are pending and handler has 20392793Slm66018 * finished running, clear interrupt and try 20402793Slm66018 * again 20412793Slm66018 */ 20422793Slm66018 if (ldcp->rx_intr_state != LDC_INTR_PEND) 20432793Slm66018 return (rv); 20442793Slm66018 20452793Slm66018 (void) i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 20462793Slm66018 rv = cinfo->rem_intr(cinfo->dip, ldcp->id, 20472793Slm66018 CNEX_RX_INTR); 20482793Slm66018 if (rv) { 20492793Slm66018 DWARN(ldcp->id, "i_ldc_unregister_channel: " 20502793Slm66018 "err removing Rx interrupt\n"); 20512793Slm66018 return (rv); 20522793Slm66018 } 20531991Sheppo } 20542336Snarayan 20552336Snarayan /* Remove the Tx interrupt */ 20561991Sheppo rv = cinfo->rem_intr(cinfo->dip, ldcp->id, CNEX_TX_INTR); 20571991Sheppo if (rv) { 20581991Sheppo DWARN(ldcp->id, 20591991Sheppo "i_ldc_unregister_channel: err removing Tx intr\n"); 20602336Snarayan return (rv); 20611991Sheppo } 20622336Snarayan 20632336Snarayan /* Unregister the channel */ 20641991Sheppo rv = cinfo->unreg_chan(ldcssp->cinfo.dip, ldcp->id); 20651991Sheppo if (rv) { 20661991Sheppo DWARN(ldcp->id, 20671991Sheppo "i_ldc_unregister_channel: cannot unreg channel\n"); 20682336Snarayan return (rv); 20691991Sheppo } 20701991Sheppo 20711991Sheppo ldcp->tstate &= ~TS_CNEX_RDY; 20721991Sheppo } 20731991Sheppo 20741991Sheppo return (0); 20751991Sheppo } 20761991Sheppo 20771991Sheppo 20781991Sheppo /* 20791991Sheppo * LDC transmit interrupt handler 20801991Sheppo * triggered for chanel up/down/reset events 20811991Sheppo * and Tx queue content changes 20821991Sheppo */ 20831991Sheppo static uint_t 20841991Sheppo i_ldc_tx_hdlr(caddr_t arg1, caddr_t arg2) 20851991Sheppo { 20861991Sheppo _NOTE(ARGUNUSED(arg2)) 20871991Sheppo 20881991Sheppo int rv; 20891991Sheppo ldc_chan_t *ldcp; 20901991Sheppo boolean_t notify_client = B_FALSE; 20912793Slm66018 uint64_t notify_event = 0, link_state; 20921991Sheppo 20931991Sheppo /* Get the channel for which interrupt was received */ 20941991Sheppo ASSERT(arg1 != NULL); 20951991Sheppo ldcp = (ldc_chan_t *)arg1; 20961991Sheppo 20971991Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) Received intr, ldcp=0x%p\n", 20981991Sheppo ldcp->id, ldcp); 20991991Sheppo 21001991Sheppo /* Lock channel */ 21011991Sheppo mutex_enter(&ldcp->lock); 21021991Sheppo 21032336Snarayan /* Obtain Tx lock */ 21042336Snarayan mutex_enter(&ldcp->tx_lock); 21052336Snarayan 21062531Snarayan /* mark interrupt as pending */ 21072793Slm66018 ldcp->tx_intr_state = LDC_INTR_ACTIVE; 21082793Slm66018 21092793Slm66018 /* save current link state */ 21102793Slm66018 link_state = ldcp->link_state; 21112531Snarayan 21121991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, &ldcp->tx_head, &ldcp->tx_tail, 21131991Sheppo &ldcp->link_state); 21141991Sheppo if (rv) { 21151991Sheppo cmn_err(CE_WARN, 21161991Sheppo "i_ldc_tx_hdlr: (0x%lx) cannot read queue ptrs rv=0x%d\n", 21171991Sheppo ldcp->id, rv); 21182531Snarayan i_ldc_clear_intr(ldcp, CNEX_TX_INTR); 21192336Snarayan mutex_exit(&ldcp->tx_lock); 21201991Sheppo mutex_exit(&ldcp->lock); 21211991Sheppo return (DDI_INTR_CLAIMED); 21221991Sheppo } 21231991Sheppo 21241991Sheppo /* 21251991Sheppo * reset the channel state if the channel went down 21261991Sheppo * (other side unconfigured queue) or channel was reset 21271991Sheppo * (other side reconfigured its queue) 21281991Sheppo */ 21292793Slm66018 if (link_state != ldcp->link_state && 21302793Slm66018 ldcp->link_state == LDC_CHANNEL_DOWN) { 21311991Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: channel link down\n", ldcp->id); 21322793Slm66018 i_ldc_reset(ldcp, B_FALSE); 21331991Sheppo notify_client = B_TRUE; 21341991Sheppo notify_event = LDC_EVT_DOWN; 21351991Sheppo } 21361991Sheppo 21372793Slm66018 if (link_state != ldcp->link_state && 21382793Slm66018 ldcp->link_state == LDC_CHANNEL_RESET) { 21391991Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: channel link reset\n", ldcp->id); 21402793Slm66018 i_ldc_reset(ldcp, B_FALSE); 21411991Sheppo notify_client = B_TRUE; 21421991Sheppo notify_event = LDC_EVT_RESET; 21431991Sheppo } 21441991Sheppo 21452793Slm66018 if (link_state != ldcp->link_state && 21462793Slm66018 (ldcp->tstate & ~TS_IN_RESET) == TS_OPEN && 21472793Slm66018 ldcp->link_state == LDC_CHANNEL_UP) { 21481991Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: channel link up\n", ldcp->id); 21491991Sheppo notify_client = B_TRUE; 21501991Sheppo notify_event = LDC_EVT_RESET; 21511991Sheppo ldcp->tstate |= TS_LINK_READY; 21521991Sheppo ldcp->status = LDC_READY; 21531991Sheppo } 21541991Sheppo 21551991Sheppo /* if callbacks are disabled, do not notify */ 21561991Sheppo if (!ldcp->cb_enabled) 21571991Sheppo notify_client = B_FALSE; 21581991Sheppo 21593151Ssg70180 i_ldc_clear_intr(ldcp, CNEX_TX_INTR); 21604690Snarayan mutex_exit(&ldcp->tx_lock); 21611991Sheppo 21621991Sheppo if (notify_client) { 21632793Slm66018 ldcp->cb_inprogress = B_TRUE; 21642793Slm66018 mutex_exit(&ldcp->lock); 21651991Sheppo rv = ldcp->cb(notify_event, ldcp->cb_arg); 21661991Sheppo if (rv) { 21671991Sheppo DWARN(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) callback " 21681991Sheppo "failure", ldcp->id); 21691991Sheppo } 21701991Sheppo mutex_enter(&ldcp->lock); 21711991Sheppo ldcp->cb_inprogress = B_FALSE; 21722793Slm66018 } 21732793Slm66018 21741991Sheppo mutex_exit(&ldcp->lock); 21751991Sheppo 21761991Sheppo D1(ldcp->id, "i_ldc_tx_hdlr: (0x%llx) exiting handler", ldcp->id); 21771991Sheppo 21781991Sheppo return (DDI_INTR_CLAIMED); 21791991Sheppo } 21801991Sheppo 21811991Sheppo /* 21825944Sha137994 * Process the Rx HV queue. 21835944Sha137994 * 21845944Sha137994 * Returns 0 if data packets were found and no errors were encountered, 21855944Sha137994 * otherwise returns an error. In either case, the *notify argument is 21865944Sha137994 * set to indicate whether or not the client callback function should 21875944Sha137994 * be invoked. The *event argument is set to contain the callback event. 21885944Sha137994 * 21895944Sha137994 * Depending on the channel mode, packets are handled differently: 21905944Sha137994 * 21915944Sha137994 * RAW MODE 21925944Sha137994 * For raw mode channels, when a data packet is encountered, 21935944Sha137994 * processing stops and all packets are left on the queue to be removed 21945944Sha137994 * and processed by the ldc_read code path. 21955944Sha137994 * 21965944Sha137994 * UNRELIABLE MODE 21975944Sha137994 * For unreliable mode, when a data packet is encountered, processing 21985944Sha137994 * stops, and all packets are left on the queue to be removed and 21995944Sha137994 * processed by the ldc_read code path. Control packets are processed 22005944Sha137994 * inline if they are encountered before any data packets. 22015944Sha137994 * 22026408Sha137994 * RELIABLE MODE 22036408Sha137994 * For reliable mode channels, all packets on the receive queue 22045944Sha137994 * are processed: data packets are copied to the data queue and 22055944Sha137994 * control packets are processed inline. Packets are only left on 22065944Sha137994 * the receive queue when the data queue is full. 22071991Sheppo */ 22081991Sheppo static uint_t 22095944Sha137994 i_ldc_rx_process_hvq(ldc_chan_t *ldcp, boolean_t *notify_client, 22105944Sha137994 uint64_t *notify_event) 22111991Sheppo { 22121991Sheppo int rv; 22131991Sheppo uint64_t rx_head, rx_tail; 22141991Sheppo ldc_msg_t *msg; 22152793Slm66018 uint64_t link_state, first_fragment = 0; 22165944Sha137994 boolean_t trace_length = B_TRUE; 22175944Sha137994 22185944Sha137994 ASSERT(MUTEX_HELD(&ldcp->lock)); 22195944Sha137994 *notify_client = B_FALSE; 22205944Sha137994 *notify_event = 0; 22211991Sheppo 22221991Sheppo /* 22231991Sheppo * Read packet(s) from the queue 22241991Sheppo */ 22251991Sheppo for (;;) { 22261991Sheppo 22272793Slm66018 link_state = ldcp->link_state; 22281991Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 22291991Sheppo &ldcp->link_state); 22301991Sheppo if (rv) { 22311991Sheppo cmn_err(CE_WARN, 22325944Sha137994 "i_ldc_rx_process_hvq: (0x%lx) cannot read " 22331991Sheppo "queue ptrs, rv=0x%d\n", ldcp->id, rv); 22341991Sheppo i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 22355944Sha137994 return (EIO); 22361991Sheppo } 22371991Sheppo 22381991Sheppo /* 22391991Sheppo * reset the channel state if the channel went down 22401991Sheppo * (other side unconfigured queue) or channel was reset 22412793Slm66018 * (other side reconfigured its queue) 22421991Sheppo */ 22432793Slm66018 22442793Slm66018 if (link_state != ldcp->link_state) { 22453010Slm66018 22462793Slm66018 switch (ldcp->link_state) { 22472793Slm66018 case LDC_CHANNEL_DOWN: 22485944Sha137994 D1(ldcp->id, "i_ldc_rx_process_hvq: channel " 22492793Slm66018 "link down\n", ldcp->id); 22502793Slm66018 mutex_enter(&ldcp->tx_lock); 22512793Slm66018 i_ldc_reset(ldcp, B_FALSE); 22522793Slm66018 mutex_exit(&ldcp->tx_lock); 22535944Sha137994 *notify_client = B_TRUE; 22545944Sha137994 *notify_event = LDC_EVT_DOWN; 22552793Slm66018 goto loop_exit; 22562793Slm66018 22572793Slm66018 case LDC_CHANNEL_UP: 22585944Sha137994 D1(ldcp->id, "i_ldc_rx_process_hvq: " 22592793Slm66018 "channel link up\n", ldcp->id); 22602793Slm66018 22612793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) == TS_OPEN) { 22625944Sha137994 *notify_client = B_TRUE; 22635944Sha137994 *notify_event = LDC_EVT_RESET; 22642793Slm66018 ldcp->tstate |= TS_LINK_READY; 22652793Slm66018 ldcp->status = LDC_READY; 22662793Slm66018 } 22672793Slm66018 break; 22682793Slm66018 22692793Slm66018 case LDC_CHANNEL_RESET: 22702793Slm66018 default: 22712793Slm66018 #ifdef DEBUG 22722793Slm66018 force_reset: 22732793Slm66018 #endif 22745944Sha137994 D1(ldcp->id, "i_ldc_rx_process_hvq: channel " 22752793Slm66018 "link reset\n", ldcp->id); 22762793Slm66018 mutex_enter(&ldcp->tx_lock); 22772793Slm66018 i_ldc_reset(ldcp, B_FALSE); 22782793Slm66018 mutex_exit(&ldcp->tx_lock); 22795944Sha137994 *notify_client = B_TRUE; 22805944Sha137994 *notify_event = LDC_EVT_RESET; 22812793Slm66018 break; 22822793Slm66018 } 22831991Sheppo } 22842793Slm66018 22852793Slm66018 #ifdef DEBUG 22862793Slm66018 if (LDC_INJECT_RESET(ldcp)) 22872793Slm66018 goto force_reset; 22886845Sha137994 if (LDC_INJECT_DRNGCLEAR(ldcp)) 22896845Sha137994 i_ldc_mem_inject_dring_clear(ldcp); 22902793Slm66018 #endif 22915944Sha137994 if (trace_length) { 22925944Sha137994 TRACE_RXHVQ_LENGTH(ldcp, rx_head, rx_tail); 22935944Sha137994 trace_length = B_FALSE; 22945944Sha137994 } 22951991Sheppo 22961991Sheppo if (rx_head == rx_tail) { 22975944Sha137994 D2(ldcp->id, "i_ldc_rx_process_hvq: (0x%llx) " 22985944Sha137994 "No packets\n", ldcp->id); 22991991Sheppo break; 23001991Sheppo } 23012793Slm66018 23025944Sha137994 D2(ldcp->id, "i_ldc_rx_process_hvq: head=0x%llx, " 23035944Sha137994 "tail=0x%llx\n", rx_head, rx_tail); 23045944Sha137994 DUMP_LDC_PKT(ldcp, "i_ldc_rx_process_hvq rcd", 23051991Sheppo ldcp->rx_q_va + rx_head); 23061991Sheppo 23071991Sheppo /* get the message */ 23081991Sheppo msg = (ldc_msg_t *)(ldcp->rx_q_va + rx_head); 23091991Sheppo 23101991Sheppo /* if channel is in RAW mode or data pkt, notify and return */ 23111991Sheppo if (ldcp->mode == LDC_MODE_RAW) { 23125944Sha137994 *notify_client = B_TRUE; 23135944Sha137994 *notify_event |= LDC_EVT_READ; 23141991Sheppo break; 23151991Sheppo } 23161991Sheppo 23171991Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) { 23181991Sheppo 23191991Sheppo /* discard packet if channel is not up */ 23202793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) != TS_UP) { 23211991Sheppo 23221991Sheppo /* move the head one position */ 23231991Sheppo rx_head = (rx_head + LDC_PACKET_SIZE) % 23244690Snarayan (ldcp->rx_q_entries << LDC_PACKET_SHIFT); 23251991Sheppo 23261991Sheppo if (rv = i_ldc_set_rx_head(ldcp, rx_head)) 23271991Sheppo break; 23281991Sheppo 23291991Sheppo continue; 23301991Sheppo } else { 23315944Sha137994 uint64_t dq_head, dq_tail; 23325944Sha137994 23336408Sha137994 /* process only RELIABLE mode data packets */ 23346408Sha137994 if (ldcp->mode != LDC_MODE_RELIABLE) { 23355944Sha137994 if ((ldcp->tstate & TS_IN_RESET) == 0) 23365944Sha137994 *notify_client = B_TRUE; 23375944Sha137994 *notify_event |= LDC_EVT_READ; 23385944Sha137994 break; 23395944Sha137994 } 23405944Sha137994 23415944Sha137994 /* don't process packet if queue full */ 23425944Sha137994 (void) i_ldc_dq_rx_get_state(ldcp, &dq_head, 23435944Sha137994 &dq_tail, NULL); 23445944Sha137994 dq_tail = (dq_tail + LDC_PACKET_SIZE) % 23455944Sha137994 (ldcp->rx_dq_entries << LDC_PACKET_SHIFT); 23465944Sha137994 if (dq_tail == dq_head || 23475944Sha137994 LDC_INJECT_DQFULL(ldcp)) { 23485944Sha137994 rv = ENOSPC; 23495944Sha137994 break; 23505944Sha137994 } 23511991Sheppo } 23521991Sheppo } 23531991Sheppo 23541991Sheppo /* Check the sequence ID for the message received */ 23552793Slm66018 rv = i_ldc_check_seqid(ldcp, msg); 23562793Slm66018 if (rv != 0) { 23571991Sheppo 23585944Sha137994 DWARN(ldcp->id, "i_ldc_rx_process_hvq: (0x%llx) " 23595944Sha137994 "seqid error, q_ptrs=0x%lx,0x%lx", ldcp->id, 23605944Sha137994 rx_head, rx_tail); 23611991Sheppo 23621991Sheppo /* Reset last_msg_rcd to start of message */ 23632336Snarayan if (first_fragment != 0) { 23642336Snarayan ldcp->last_msg_rcd = first_fragment - 1; 23652336Snarayan first_fragment = 0; 23661991Sheppo } 23672336Snarayan 23681991Sheppo /* 23691991Sheppo * Send a NACK due to seqid mismatch 23701991Sheppo */ 23714690Snarayan rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK, 23721991Sheppo (msg->ctrl & LDC_CTRL_MASK)); 23731991Sheppo 23741991Sheppo if (rv) { 23755944Sha137994 cmn_err(CE_NOTE, "i_ldc_rx_process_hvq: " 23765944Sha137994 "(0x%lx) err sending CTRL/DATA NACK msg\n", 23775944Sha137994 ldcp->id); 23782336Snarayan 23792336Snarayan /* if cannot send NACK - reset channel */ 23802336Snarayan mutex_enter(&ldcp->tx_lock); 23812793Slm66018 i_ldc_reset(ldcp, B_TRUE); 23822336Snarayan mutex_exit(&ldcp->tx_lock); 23833560Snarayan 23845944Sha137994 *notify_client = B_TRUE; 23855944Sha137994 *notify_event = LDC_EVT_RESET; 23862336Snarayan break; 23871991Sheppo } 23881991Sheppo 23891991Sheppo /* purge receive queue */ 23901991Sheppo (void) i_ldc_set_rx_head(ldcp, rx_tail); 23911991Sheppo break; 23921991Sheppo } 23931991Sheppo 23941991Sheppo /* record the message ID */ 23951991Sheppo ldcp->last_msg_rcd = msg->seqid; 23961991Sheppo 23971991Sheppo /* process control messages */ 23981991Sheppo if (msg->type & LDC_CTRL) { 23991991Sheppo /* save current internal state */ 24001991Sheppo uint64_t tstate = ldcp->tstate; 24011991Sheppo 24021991Sheppo rv = i_ldc_ctrlmsg(ldcp, msg); 24031991Sheppo if (rv == EAGAIN) { 24041991Sheppo /* re-process pkt - state was adjusted */ 24051991Sheppo continue; 24061991Sheppo } 24071991Sheppo if (rv == ECONNRESET) { 24085944Sha137994 *notify_client = B_TRUE; 24095944Sha137994 *notify_event = LDC_EVT_RESET; 24101991Sheppo break; 24111991Sheppo } 24121991Sheppo 24131991Sheppo /* 24141991Sheppo * control message processing was successful 24151991Sheppo * channel transitioned to ready for communication 24161991Sheppo */ 24171991Sheppo if (rv == 0 && ldcp->tstate == TS_UP && 24182793Slm66018 (tstate & ~TS_IN_RESET) != 24192793Slm66018 (ldcp->tstate & ~TS_IN_RESET)) { 24205944Sha137994 *notify_client = B_TRUE; 24215944Sha137994 *notify_event = LDC_EVT_UP; 24221991Sheppo } 24231991Sheppo } 24241991Sheppo 24253560Snarayan /* process data NACKs */ 24263560Snarayan if ((msg->type & LDC_DATA) && (msg->stype & LDC_NACK)) { 24273560Snarayan DWARN(ldcp->id, 24285944Sha137994 "i_ldc_rx_process_hvq: (0x%llx) received DATA/NACK", 24293560Snarayan ldcp->id); 24303560Snarayan mutex_enter(&ldcp->tx_lock); 24313560Snarayan i_ldc_reset(ldcp, B_TRUE); 24323560Snarayan mutex_exit(&ldcp->tx_lock); 24335944Sha137994 *notify_client = B_TRUE; 24345944Sha137994 *notify_event = LDC_EVT_RESET; 24353560Snarayan break; 24363560Snarayan } 24373560Snarayan 24381991Sheppo /* process data ACKs */ 24391991Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) { 24402336Snarayan if (rv = i_ldc_process_data_ACK(ldcp, msg)) { 24415944Sha137994 *notify_client = B_TRUE; 24425944Sha137994 *notify_event = LDC_EVT_RESET; 24432336Snarayan break; 24442336Snarayan } 24451991Sheppo } 24461991Sheppo 24475944Sha137994 if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) { 24486408Sha137994 ASSERT(ldcp->mode == LDC_MODE_RELIABLE); 24495944Sha137994 24505944Sha137994 /* 24515944Sha137994 * Copy the data packet to the data queue. Note 24525944Sha137994 * that the copy routine updates the rx_head pointer. 24535944Sha137994 */ 24545944Sha137994 i_ldc_rxdq_copy(ldcp, &rx_head); 24555944Sha137994 24565944Sha137994 if ((ldcp->tstate & TS_IN_RESET) == 0) 24575944Sha137994 *notify_client = B_TRUE; 24585944Sha137994 *notify_event |= LDC_EVT_READ; 24595944Sha137994 } else { 24605944Sha137994 rx_head = (rx_head + LDC_PACKET_SIZE) % 24615944Sha137994 (ldcp->rx_q_entries << LDC_PACKET_SHIFT); 24625944Sha137994 } 24635944Sha137994 24641991Sheppo /* move the head one position */ 24652032Slm66018 if (rv = i_ldc_set_rx_head(ldcp, rx_head)) { 24665944Sha137994 *notify_client = B_TRUE; 24675944Sha137994 *notify_event = LDC_EVT_RESET; 24681991Sheppo break; 24692032Slm66018 } 24701991Sheppo 24711991Sheppo } /* for */ 24721991Sheppo 24732793Slm66018 loop_exit: 24742793Slm66018 24756408Sha137994 if (ldcp->mode == LDC_MODE_RELIABLE) { 24765944Sha137994 /* ACK data packets */ 24775944Sha137994 if ((*notify_event & 24785944Sha137994 (LDC_EVT_READ | LDC_EVT_RESET)) == LDC_EVT_READ) { 24795944Sha137994 int ack_rv; 24805944Sha137994 ack_rv = i_ldc_send_pkt(ldcp, LDC_DATA, LDC_ACK, 0); 24815944Sha137994 if (ack_rv && ack_rv != EWOULDBLOCK) { 24825944Sha137994 cmn_err(CE_NOTE, 24835944Sha137994 "i_ldc_rx_process_hvq: (0x%lx) cannot " 24845944Sha137994 "send ACK\n", ldcp->id); 24855944Sha137994 24865944Sha137994 mutex_enter(&ldcp->tx_lock); 24875944Sha137994 i_ldc_reset(ldcp, B_FALSE); 24885944Sha137994 mutex_exit(&ldcp->tx_lock); 24895944Sha137994 24905944Sha137994 *notify_client = B_TRUE; 24915944Sha137994 *notify_event = LDC_EVT_RESET; 24925944Sha137994 goto skip_ackpeek; 24935944Sha137994 } 24945944Sha137994 } 24955944Sha137994 24965944Sha137994 /* 24975944Sha137994 * If we have no more space on the data queue, make sure 24985944Sha137994 * there are no ACKs on the rx queue waiting to be processed. 24995944Sha137994 */ 25005944Sha137994 if (rv == ENOSPC) { 25015944Sha137994 if (i_ldc_rx_ackpeek(ldcp, rx_head, rx_tail) != 0) { 25025944Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID; 25035944Sha137994 *notify_client = B_TRUE; 25045944Sha137994 *notify_event = LDC_EVT_RESET; 25055944Sha137994 } 25066944Sha137994 return (rv); 25075944Sha137994 } else { 25085944Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID; 25091991Sheppo } 25105944Sha137994 } 25115944Sha137994 25125944Sha137994 skip_ackpeek: 25135944Sha137994 25145944Sha137994 /* Return, indicating whether or not data packets were found */ 25155944Sha137994 if ((*notify_event & (LDC_EVT_READ | LDC_EVT_RESET)) == LDC_EVT_READ) 25165944Sha137994 return (0); 25175944Sha137994 25185944Sha137994 return (ENOMSG); 25191991Sheppo } 25201991Sheppo 25215944Sha137994 /* 25225944Sha137994 * Process any ACK packets on the HV receive queue. 25235944Sha137994 * 25246408Sha137994 * This function is only used by RELIABLE mode channels when the 25255944Sha137994 * secondary data queue fills up and there are packets remaining on 25265944Sha137994 * the HV receive queue. 25275944Sha137994 */ 25285944Sha137994 int 25295944Sha137994 i_ldc_rx_ackpeek(ldc_chan_t *ldcp, uint64_t rx_head, uint64_t rx_tail) 25305944Sha137994 { 25315944Sha137994 int rv = 0; 25325944Sha137994 ldc_msg_t *msg; 25335944Sha137994 25345944Sha137994 if (ldcp->rx_ack_head == ACKPEEK_HEAD_INVALID) 25355944Sha137994 ldcp->rx_ack_head = rx_head; 25365944Sha137994 25375944Sha137994 while (ldcp->rx_ack_head != rx_tail) { 25385944Sha137994 msg = (ldc_msg_t *)(ldcp->rx_q_va + ldcp->rx_ack_head); 25395944Sha137994 25405944Sha137994 if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) { 25415944Sha137994 if (rv = i_ldc_process_data_ACK(ldcp, msg)) 25425944Sha137994 break; 25435944Sha137994 msg->stype &= ~LDC_ACK; 25445944Sha137994 } 25455944Sha137994 25465944Sha137994 ldcp->rx_ack_head = 25475944Sha137994 (ldcp->rx_ack_head + LDC_PACKET_SIZE) % 25485944Sha137994 (ldcp->rx_q_entries << LDC_PACKET_SHIFT); 25495944Sha137994 } 25505944Sha137994 return (rv); 25515944Sha137994 } 25521991Sheppo 25531991Sheppo /* -------------------------------------------------------------------------- */ 25541991Sheppo 25551991Sheppo /* 25561991Sheppo * LDC API functions 25571991Sheppo */ 25581991Sheppo 25591991Sheppo /* 25601991Sheppo * Initialize the channel. Allocate internal structure and memory for 25611991Sheppo * TX/RX queues, and initialize locks. 25621991Sheppo */ 25631991Sheppo int 25641991Sheppo ldc_init(uint64_t id, ldc_attr_t *attr, ldc_handle_t *handle) 25651991Sheppo { 25661991Sheppo ldc_chan_t *ldcp; 25671991Sheppo int rv, exit_val; 25681991Sheppo uint64_t ra_base, nentries; 25692410Slm66018 uint64_t qlen; 25701991Sheppo 25711991Sheppo exit_val = EINVAL; /* guarantee an error if exit on failure */ 25721991Sheppo 25731991Sheppo if (attr == NULL) { 25741991Sheppo DWARN(id, "ldc_init: (0x%llx) invalid attr\n", id); 25751991Sheppo return (EINVAL); 25761991Sheppo } 25771991Sheppo if (handle == NULL) { 25781991Sheppo DWARN(id, "ldc_init: (0x%llx) invalid handle\n", id); 25791991Sheppo return (EINVAL); 25801991Sheppo } 25811991Sheppo 25821991Sheppo /* check if channel is valid */ 25831991Sheppo rv = hv_ldc_tx_qinfo(id, &ra_base, &nentries); 25841991Sheppo if (rv == H_ECHANNEL) { 25851991Sheppo DWARN(id, "ldc_init: (0x%llx) invalid channel id\n", id); 25861991Sheppo return (EINVAL); 25871991Sheppo } 25881991Sheppo 25891991Sheppo /* check if the channel has already been initialized */ 25901991Sheppo mutex_enter(&ldcssp->lock); 25911991Sheppo ldcp = ldcssp->chan_list; 25921991Sheppo while (ldcp != NULL) { 25931991Sheppo if (ldcp->id == id) { 25941991Sheppo DWARN(id, "ldc_init: (0x%llx) already initialized\n", 25951991Sheppo id); 25961991Sheppo mutex_exit(&ldcssp->lock); 25971991Sheppo return (EADDRINUSE); 25981991Sheppo } 25991991Sheppo ldcp = ldcp->next; 26001991Sheppo } 26011991Sheppo mutex_exit(&ldcssp->lock); 26021991Sheppo 26031991Sheppo ASSERT(ldcp == NULL); 26041991Sheppo 26051991Sheppo *handle = 0; 26061991Sheppo 26071991Sheppo /* Allocate an ldcp structure */ 26081991Sheppo ldcp = kmem_zalloc(sizeof (ldc_chan_t), KM_SLEEP); 26091991Sheppo 26102336Snarayan /* 26112336Snarayan * Initialize the channel and Tx lock 26122336Snarayan * 26132336Snarayan * The channel 'lock' protects the entire channel and 26142336Snarayan * should be acquired before initializing, resetting, 26152336Snarayan * destroying or reading from a channel. 26162336Snarayan * 26172336Snarayan * The 'tx_lock' should be acquired prior to transmitting 26182336Snarayan * data over the channel. The lock should also be acquired 26192336Snarayan * prior to channel reconfiguration (in order to prevent 26202336Snarayan * concurrent writes). 26212336Snarayan * 26222336Snarayan * ORDERING: When both locks are being acquired, to prevent 26232336Snarayan * deadlocks, the channel lock should be always acquired prior 26242336Snarayan * to the tx_lock. 26252336Snarayan */ 26261991Sheppo mutex_init(&ldcp->lock, NULL, MUTEX_DRIVER, NULL); 26272336Snarayan mutex_init(&ldcp->tx_lock, NULL, MUTEX_DRIVER, NULL); 26281991Sheppo 26291991Sheppo /* Initialize the channel */ 26301991Sheppo ldcp->id = id; 26311991Sheppo ldcp->cb = NULL; 26321991Sheppo ldcp->cb_arg = NULL; 26331991Sheppo ldcp->cb_inprogress = B_FALSE; 26341991Sheppo ldcp->cb_enabled = B_FALSE; 26351991Sheppo ldcp->next = NULL; 26361991Sheppo 26371991Sheppo /* Read attributes */ 26381991Sheppo ldcp->mode = attr->mode; 26391991Sheppo ldcp->devclass = attr->devclass; 26401991Sheppo ldcp->devinst = attr->instance; 26412410Slm66018 ldcp->mtu = (attr->mtu > 0) ? attr->mtu : LDC_DEFAULT_MTU; 26421991Sheppo 26431991Sheppo D1(ldcp->id, 26441991Sheppo "ldc_init: (0x%llx) channel attributes, class=0x%x, " 26452410Slm66018 "instance=0x%llx, mode=%d, mtu=%d\n", 26462410Slm66018 ldcp->id, ldcp->devclass, ldcp->devinst, ldcp->mode, ldcp->mtu); 26471991Sheppo 26481991Sheppo ldcp->next_vidx = 0; 26492793Slm66018 ldcp->tstate = TS_IN_RESET; 26501991Sheppo ldcp->hstate = 0; 26511991Sheppo ldcp->last_msg_snt = LDC_INIT_SEQID; 26521991Sheppo ldcp->last_ack_rcd = 0; 26531991Sheppo ldcp->last_msg_rcd = 0; 26545944Sha137994 ldcp->rx_ack_head = ACKPEEK_HEAD_INVALID; 26551991Sheppo 26561991Sheppo ldcp->stream_bufferp = NULL; 26571991Sheppo ldcp->exp_dring_list = NULL; 26581991Sheppo ldcp->imp_dring_list = NULL; 26591991Sheppo ldcp->mhdl_list = NULL; 26601991Sheppo 26612793Slm66018 ldcp->tx_intr_state = LDC_INTR_NONE; 26622793Slm66018 ldcp->rx_intr_state = LDC_INTR_NONE; 26632793Slm66018 26641991Sheppo /* Initialize payload size depending on whether channel is reliable */ 26651991Sheppo switch (ldcp->mode) { 26661991Sheppo case LDC_MODE_RAW: 26671991Sheppo ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RAW; 26681991Sheppo ldcp->read_p = i_ldc_read_raw; 26691991Sheppo ldcp->write_p = i_ldc_write_raw; 26701991Sheppo break; 26711991Sheppo case LDC_MODE_UNRELIABLE: 26721991Sheppo ldcp->pkt_payload = LDC_PAYLOAD_SIZE_UNRELIABLE; 26731991Sheppo ldcp->read_p = i_ldc_read_packet; 26741991Sheppo ldcp->write_p = i_ldc_write_packet; 26751991Sheppo break; 26761991Sheppo case LDC_MODE_RELIABLE: 26771991Sheppo ldcp->pkt_payload = LDC_PAYLOAD_SIZE_RELIABLE; 26781991Sheppo 26791991Sheppo ldcp->stream_remains = 0; 26801991Sheppo ldcp->stream_offset = 0; 26811991Sheppo ldcp->stream_bufferp = kmem_alloc(ldcp->mtu, KM_SLEEP); 26821991Sheppo ldcp->read_p = i_ldc_read_stream; 26831991Sheppo ldcp->write_p = i_ldc_write_stream; 26841991Sheppo break; 26851991Sheppo default: 26861991Sheppo exit_val = EINVAL; 26871991Sheppo goto cleanup_on_exit; 26881991Sheppo } 26891991Sheppo 26902410Slm66018 /* 26912410Slm66018 * qlen is (mtu * ldc_mtu_msgs) / pkt_payload. If this 26922410Slm66018 * value is smaller than default length of ldc_queue_entries, 26934690Snarayan * qlen is set to ldc_queue_entries. Ensure that computed 26944690Snarayan * length is a power-of-two value. 26952410Slm66018 */ 26962410Slm66018 qlen = (ldcp->mtu * ldc_mtu_msgs) / ldcp->pkt_payload; 26974690Snarayan if (!ISP2(qlen)) { 26984690Snarayan uint64_t tmp = 1; 26994690Snarayan while (qlen) { 27004690Snarayan qlen >>= 1; tmp <<= 1; 27014690Snarayan } 27024690Snarayan qlen = tmp; 27034690Snarayan } 27044690Snarayan 27052410Slm66018 ldcp->rx_q_entries = 27064690Snarayan (qlen < ldc_queue_entries) ? ldc_queue_entries : qlen; 27072410Slm66018 ldcp->tx_q_entries = ldcp->rx_q_entries; 27082410Slm66018 27094690Snarayan D1(ldcp->id, "ldc_init: queue length = 0x%llx\n", ldcp->rx_q_entries); 27102410Slm66018 27111991Sheppo /* Create a transmit queue */ 27121991Sheppo ldcp->tx_q_va = (uint64_t) 27134690Snarayan contig_mem_alloc(ldcp->tx_q_entries << LDC_PACKET_SHIFT); 27141991Sheppo if (ldcp->tx_q_va == NULL) { 27151991Sheppo cmn_err(CE_WARN, 27161991Sheppo "ldc_init: (0x%lx) TX queue allocation failed\n", 27171991Sheppo ldcp->id); 27181991Sheppo exit_val = ENOMEM; 27191991Sheppo goto cleanup_on_exit; 27201991Sheppo } 27211991Sheppo ldcp->tx_q_ra = va_to_pa((caddr_t)ldcp->tx_q_va); 27221991Sheppo 27231991Sheppo D2(ldcp->id, "ldc_init: txq_va=0x%llx, txq_ra=0x%llx, entries=0x%llx\n", 27241991Sheppo ldcp->tx_q_va, ldcp->tx_q_ra, ldcp->tx_q_entries); 27251991Sheppo 27261991Sheppo ldcp->tstate |= TS_TXQ_RDY; 27271991Sheppo 27281991Sheppo /* Create a receive queue */ 27291991Sheppo ldcp->rx_q_va = (uint64_t) 27304690Snarayan contig_mem_alloc(ldcp->rx_q_entries << LDC_PACKET_SHIFT); 27311991Sheppo if (ldcp->rx_q_va == NULL) { 27321991Sheppo cmn_err(CE_WARN, 27331991Sheppo "ldc_init: (0x%lx) RX queue allocation failed\n", 27341991Sheppo ldcp->id); 27351991Sheppo exit_val = ENOMEM; 27361991Sheppo goto cleanup_on_exit; 27371991Sheppo } 27381991Sheppo ldcp->rx_q_ra = va_to_pa((caddr_t)ldcp->rx_q_va); 27391991Sheppo 27401991Sheppo D2(ldcp->id, "ldc_init: rxq_va=0x%llx, rxq_ra=0x%llx, entries=0x%llx\n", 27411991Sheppo ldcp->rx_q_va, ldcp->rx_q_ra, ldcp->rx_q_entries); 27421991Sheppo 27431991Sheppo ldcp->tstate |= TS_RXQ_RDY; 27441991Sheppo 27455944Sha137994 /* Setup a separate read data queue */ 27466408Sha137994 if (ldcp->mode == LDC_MODE_RELIABLE) { 27475944Sha137994 ldcp->readq_get_state = i_ldc_dq_rx_get_state; 27485944Sha137994 ldcp->readq_set_head = i_ldc_set_rxdq_head; 27495944Sha137994 27505944Sha137994 /* Make sure the data queue multiplier is a power of 2 */ 27515944Sha137994 if (!ISP2(ldc_rxdq_multiplier)) { 27525944Sha137994 D1(ldcp->id, "ldc_init: (0x%llx) ldc_rxdq_multiplier " 27535944Sha137994 "not a power of 2, resetting", ldcp->id); 27545944Sha137994 ldc_rxdq_multiplier = LDC_RXDQ_MULTIPLIER; 27555944Sha137994 } 27565944Sha137994 27575944Sha137994 ldcp->rx_dq_entries = ldc_rxdq_multiplier * ldcp->rx_q_entries; 27585944Sha137994 ldcp->rx_dq_va = (uint64_t) 27595944Sha137994 kmem_alloc(ldcp->rx_dq_entries << LDC_PACKET_SHIFT, 27605944Sha137994 KM_SLEEP); 27615944Sha137994 if (ldcp->rx_dq_va == NULL) { 27625944Sha137994 cmn_err(CE_WARN, 27635944Sha137994 "ldc_init: (0x%lx) RX data queue " 27645944Sha137994 "allocation failed\n", ldcp->id); 27655944Sha137994 exit_val = ENOMEM; 27665944Sha137994 goto cleanup_on_exit; 27675944Sha137994 } 27685944Sha137994 27695944Sha137994 ldcp->rx_dq_head = ldcp->rx_dq_tail = 0; 27705944Sha137994 27715944Sha137994 D2(ldcp->id, "ldc_init: rx_dq_va=0x%llx, " 27725944Sha137994 "rx_dq_entries=0x%llx\n", ldcp->rx_dq_va, 27735944Sha137994 ldcp->rx_dq_entries); 27745944Sha137994 } else { 27755944Sha137994 ldcp->readq_get_state = i_ldc_hvq_rx_get_state; 27765944Sha137994 ldcp->readq_set_head = i_ldc_set_rx_head; 27775944Sha137994 } 27785944Sha137994 27791991Sheppo /* Init descriptor ring and memory handle list lock */ 27801991Sheppo mutex_init(&ldcp->exp_dlist_lock, NULL, MUTEX_DRIVER, NULL); 27811991Sheppo mutex_init(&ldcp->imp_dlist_lock, NULL, MUTEX_DRIVER, NULL); 27821991Sheppo mutex_init(&ldcp->mlist_lock, NULL, MUTEX_DRIVER, NULL); 27831991Sheppo 27841991Sheppo /* mark status as INITialized */ 27851991Sheppo ldcp->status = LDC_INIT; 27861991Sheppo 27871991Sheppo /* Add to channel list */ 27881991Sheppo mutex_enter(&ldcssp->lock); 27891991Sheppo ldcp->next = ldcssp->chan_list; 27901991Sheppo ldcssp->chan_list = ldcp; 27911991Sheppo ldcssp->channel_count++; 27921991Sheppo mutex_exit(&ldcssp->lock); 27931991Sheppo 27941991Sheppo /* set the handle */ 27951991Sheppo *handle = (ldc_handle_t)ldcp; 27961991Sheppo 27971991Sheppo D1(ldcp->id, "ldc_init: (0x%llx) channel initialized\n", ldcp->id); 27981991Sheppo 27991991Sheppo return (0); 28001991Sheppo 28011991Sheppo cleanup_on_exit: 28021991Sheppo 28036408Sha137994 if (ldcp->mode == LDC_MODE_RELIABLE && ldcp->stream_bufferp) 28041991Sheppo kmem_free(ldcp->stream_bufferp, ldcp->mtu); 28051991Sheppo 28061991Sheppo if (ldcp->tstate & TS_TXQ_RDY) 28071991Sheppo contig_mem_free((caddr_t)ldcp->tx_q_va, 28081991Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT)); 28091991Sheppo 28101991Sheppo if (ldcp->tstate & TS_RXQ_RDY) 28111991Sheppo contig_mem_free((caddr_t)ldcp->rx_q_va, 28121991Sheppo (ldcp->rx_q_entries << LDC_PACKET_SHIFT)); 28131991Sheppo 28142336Snarayan mutex_destroy(&ldcp->tx_lock); 28151991Sheppo mutex_destroy(&ldcp->lock); 28161991Sheppo 28171991Sheppo if (ldcp) 28181991Sheppo kmem_free(ldcp, sizeof (ldc_chan_t)); 28191991Sheppo 28201991Sheppo return (exit_val); 28211991Sheppo } 28221991Sheppo 28231991Sheppo /* 28241991Sheppo * Finalizes the LDC connection. It will return EBUSY if the 28251991Sheppo * channel is open. A ldc_close() has to be done prior to 28261991Sheppo * a ldc_fini operation. It frees TX/RX queues, associated 28271991Sheppo * with the channel 28281991Sheppo */ 28291991Sheppo int 28301991Sheppo ldc_fini(ldc_handle_t handle) 28311991Sheppo { 28321991Sheppo ldc_chan_t *ldcp; 28331991Sheppo ldc_chan_t *tmp_ldcp; 28341991Sheppo uint64_t id; 28351991Sheppo 28361991Sheppo if (handle == NULL) { 28371991Sheppo DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel handle\n"); 28381991Sheppo return (EINVAL); 28391991Sheppo } 28401991Sheppo ldcp = (ldc_chan_t *)handle; 28411991Sheppo id = ldcp->id; 28421991Sheppo 28431991Sheppo mutex_enter(&ldcp->lock); 28441991Sheppo 28452793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) > TS_INIT) { 28461991Sheppo DWARN(ldcp->id, "ldc_fini: (0x%llx) channel is open\n", 28471991Sheppo ldcp->id); 28481991Sheppo mutex_exit(&ldcp->lock); 28491991Sheppo return (EBUSY); 28501991Sheppo } 28511991Sheppo 28521991Sheppo /* Remove from the channel list */ 28531991Sheppo mutex_enter(&ldcssp->lock); 28541991Sheppo tmp_ldcp = ldcssp->chan_list; 28551991Sheppo if (tmp_ldcp == ldcp) { 28561991Sheppo ldcssp->chan_list = ldcp->next; 28571991Sheppo ldcp->next = NULL; 28581991Sheppo } else { 28591991Sheppo while (tmp_ldcp != NULL) { 28601991Sheppo if (tmp_ldcp->next == ldcp) { 28611991Sheppo tmp_ldcp->next = ldcp->next; 28621991Sheppo ldcp->next = NULL; 28631991Sheppo break; 28641991Sheppo } 28651991Sheppo tmp_ldcp = tmp_ldcp->next; 28661991Sheppo } 28671991Sheppo if (tmp_ldcp == NULL) { 28681991Sheppo DWARN(DBG_ALL_LDCS, "ldc_fini: invalid channel hdl\n"); 28691991Sheppo mutex_exit(&ldcssp->lock); 28701991Sheppo mutex_exit(&ldcp->lock); 28711991Sheppo return (EINVAL); 28721991Sheppo } 28731991Sheppo } 28741991Sheppo 28751991Sheppo ldcssp->channel_count--; 28761991Sheppo 28771991Sheppo mutex_exit(&ldcssp->lock); 28781991Sheppo 28791991Sheppo /* Free the map table for this channel */ 28801991Sheppo if (ldcp->mtbl) { 28811991Sheppo (void) hv_ldc_set_map_table(ldcp->id, NULL, NULL); 28822793Slm66018 if (ldcp->mtbl->contigmem) 28832793Slm66018 contig_mem_free(ldcp->mtbl->table, ldcp->mtbl->size); 28842793Slm66018 else 28852793Slm66018 kmem_free(ldcp->mtbl->table, ldcp->mtbl->size); 28861991Sheppo mutex_destroy(&ldcp->mtbl->lock); 28871991Sheppo kmem_free(ldcp->mtbl, sizeof (ldc_mtbl_t)); 28881991Sheppo } 28891991Sheppo 28901991Sheppo /* Destroy descriptor ring and memory handle list lock */ 28911991Sheppo mutex_destroy(&ldcp->exp_dlist_lock); 28921991Sheppo mutex_destroy(&ldcp->imp_dlist_lock); 28931991Sheppo mutex_destroy(&ldcp->mlist_lock); 28941991Sheppo 28956408Sha137994 /* Free the stream buffer for RELIABLE_MODE */ 28966408Sha137994 if (ldcp->mode == LDC_MODE_RELIABLE && ldcp->stream_bufferp) 28971991Sheppo kmem_free(ldcp->stream_bufferp, ldcp->mtu); 28981991Sheppo 28991991Sheppo /* Free the RX queue */ 29001991Sheppo contig_mem_free((caddr_t)ldcp->rx_q_va, 29011991Sheppo (ldcp->rx_q_entries << LDC_PACKET_SHIFT)); 29021991Sheppo ldcp->tstate &= ~TS_RXQ_RDY; 29031991Sheppo 29045944Sha137994 /* Free the RX data queue */ 29056408Sha137994 if (ldcp->mode == LDC_MODE_RELIABLE) { 29065944Sha137994 kmem_free((caddr_t)ldcp->rx_dq_va, 29075944Sha137994 (ldcp->rx_dq_entries << LDC_PACKET_SHIFT)); 29085944Sha137994 } 29095944Sha137994 29101991Sheppo /* Free the TX queue */ 29111991Sheppo contig_mem_free((caddr_t)ldcp->tx_q_va, 29121991Sheppo (ldcp->tx_q_entries << LDC_PACKET_SHIFT)); 29131991Sheppo ldcp->tstate &= ~TS_TXQ_RDY; 29141991Sheppo 29151991Sheppo mutex_exit(&ldcp->lock); 29161991Sheppo 29171991Sheppo /* Destroy mutex */ 29182336Snarayan mutex_destroy(&ldcp->tx_lock); 29191991Sheppo mutex_destroy(&ldcp->lock); 29201991Sheppo 29211991Sheppo /* free channel structure */ 29221991Sheppo kmem_free(ldcp, sizeof (ldc_chan_t)); 29231991Sheppo 29241991Sheppo D1(id, "ldc_fini: (0x%llx) channel finalized\n", id); 29251991Sheppo 29261991Sheppo return (0); 29271991Sheppo } 29281991Sheppo 29291991Sheppo /* 29301991Sheppo * Open the LDC channel for use. It registers the TX/RX queues 29311991Sheppo * with the Hypervisor. It also specifies the interrupt number 29321991Sheppo * and target CPU for this channel 29331991Sheppo */ 29341991Sheppo int 29351991Sheppo ldc_open(ldc_handle_t handle) 29361991Sheppo { 29371991Sheppo ldc_chan_t *ldcp; 29381991Sheppo int rv; 29391991Sheppo 29401991Sheppo if (handle == NULL) { 29411991Sheppo DWARN(DBG_ALL_LDCS, "ldc_open: invalid channel handle\n"); 29421991Sheppo return (EINVAL); 29431991Sheppo } 29441991Sheppo 29451991Sheppo ldcp = (ldc_chan_t *)handle; 29461991Sheppo 29471991Sheppo mutex_enter(&ldcp->lock); 29481991Sheppo 29491991Sheppo if (ldcp->tstate < TS_INIT) { 29501991Sheppo DWARN(ldcp->id, 29511991Sheppo "ldc_open: (0x%llx) channel not initialized\n", ldcp->id); 29521991Sheppo mutex_exit(&ldcp->lock); 29531991Sheppo return (EFAULT); 29541991Sheppo } 29552793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) >= TS_OPEN) { 29561991Sheppo DWARN(ldcp->id, 29571991Sheppo "ldc_open: (0x%llx) channel is already open\n", ldcp->id); 29581991Sheppo mutex_exit(&ldcp->lock); 29591991Sheppo return (EFAULT); 29601991Sheppo } 29611991Sheppo 29621991Sheppo /* 29631991Sheppo * Unregister/Register the tx queue with the hypervisor 29641991Sheppo */ 29651991Sheppo rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 29661991Sheppo if (rv) { 29671991Sheppo cmn_err(CE_WARN, 29681991Sheppo "ldc_open: (0x%lx) channel tx queue unconf failed\n", 29691991Sheppo ldcp->id); 29701991Sheppo mutex_exit(&ldcp->lock); 29711991Sheppo return (EIO); 29721991Sheppo } 29731991Sheppo 29741991Sheppo rv = hv_ldc_tx_qconf(ldcp->id, ldcp->tx_q_ra, ldcp->tx_q_entries); 29751991Sheppo if (rv) { 29761991Sheppo cmn_err(CE_WARN, 29771991Sheppo "ldc_open: (0x%lx) channel tx queue conf failed\n", 29781991Sheppo ldcp->id); 29791991Sheppo mutex_exit(&ldcp->lock); 29801991Sheppo return (EIO); 29811991Sheppo } 29821991Sheppo 29831991Sheppo D2(ldcp->id, "ldc_open: (0x%llx) registered tx queue with LDC\n", 29841991Sheppo ldcp->id); 29851991Sheppo 29861991Sheppo /* 29871991Sheppo * Unregister/Register the rx queue with the hypervisor 29881991Sheppo */ 29891991Sheppo rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 29901991Sheppo if (rv) { 29911991Sheppo cmn_err(CE_WARN, 29921991Sheppo "ldc_open: (0x%lx) channel rx queue unconf failed\n", 29931991Sheppo ldcp->id); 29941991Sheppo mutex_exit(&ldcp->lock); 29951991Sheppo return (EIO); 29961991Sheppo } 29971991Sheppo 29981991Sheppo rv = hv_ldc_rx_qconf(ldcp->id, ldcp->rx_q_ra, ldcp->rx_q_entries); 29991991Sheppo if (rv) { 30001991Sheppo cmn_err(CE_WARN, 30011991Sheppo "ldc_open: (0x%lx) channel rx queue conf failed\n", 30021991Sheppo ldcp->id); 30031991Sheppo mutex_exit(&ldcp->lock); 30041991Sheppo return (EIO); 30051991Sheppo } 30061991Sheppo 30071991Sheppo D2(ldcp->id, "ldc_open: (0x%llx) registered rx queue with LDC\n", 30081991Sheppo ldcp->id); 30091991Sheppo 30101991Sheppo ldcp->tstate |= TS_QCONF_RDY; 30111991Sheppo 30121991Sheppo /* Register the channel with the channel nexus */ 30131991Sheppo rv = i_ldc_register_channel(ldcp); 30141991Sheppo if (rv && rv != EAGAIN) { 30151991Sheppo cmn_err(CE_WARN, 30161991Sheppo "ldc_open: (0x%lx) channel register failed\n", ldcp->id); 30178542SHaik.Aftandilian@Sun.COM ldcp->tstate &= ~TS_QCONF_RDY; 30181991Sheppo (void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 30191991Sheppo (void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 30201991Sheppo mutex_exit(&ldcp->lock); 30211991Sheppo return (EIO); 30221991Sheppo } 30231991Sheppo 30241991Sheppo /* mark channel in OPEN state */ 30251991Sheppo ldcp->status = LDC_OPEN; 30261991Sheppo 30271991Sheppo /* Read channel state */ 30281991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 30291991Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 30301991Sheppo if (rv) { 30311991Sheppo cmn_err(CE_WARN, 30321991Sheppo "ldc_open: (0x%lx) cannot read channel state\n", 30331991Sheppo ldcp->id); 30341991Sheppo (void) i_ldc_unregister_channel(ldcp); 30358542SHaik.Aftandilian@Sun.COM ldcp->tstate &= ~TS_QCONF_RDY; 30361991Sheppo (void) hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 30371991Sheppo (void) hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 30381991Sheppo mutex_exit(&ldcp->lock); 30391991Sheppo return (EIO); 30401991Sheppo } 30411991Sheppo 30421991Sheppo /* 30436408Sha137994 * set the ACKd head to current head location for reliable 30441991Sheppo */ 30451991Sheppo ldcp->tx_ackd_head = ldcp->tx_head; 30461991Sheppo 30471991Sheppo /* mark channel ready if HV report link is UP (peer alloc'd Rx queue) */ 30481991Sheppo if (ldcp->link_state == LDC_CHANNEL_UP || 30491991Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 30501991Sheppo ldcp->tstate |= TS_LINK_READY; 30511991Sheppo ldcp->status = LDC_READY; 30521991Sheppo } 30531991Sheppo 30541991Sheppo /* 30551991Sheppo * if channel is being opened in RAW mode - no handshake is needed 30561991Sheppo * switch the channel READY and UP state 30571991Sheppo */ 30581991Sheppo if (ldcp->mode == LDC_MODE_RAW) { 30591991Sheppo ldcp->tstate = TS_UP; /* set bits associated with LDC UP */ 30601991Sheppo ldcp->status = LDC_UP; 30611991Sheppo } 30621991Sheppo 30631991Sheppo mutex_exit(&ldcp->lock); 30641991Sheppo 30651991Sheppo /* 30661991Sheppo * Increment number of open channels 30671991Sheppo */ 30681991Sheppo mutex_enter(&ldcssp->lock); 30691991Sheppo ldcssp->channels_open++; 30701991Sheppo mutex_exit(&ldcssp->lock); 30711991Sheppo 30723010Slm66018 D1(ldcp->id, 30732793Slm66018 "ldc_open: (0x%llx) channel (0x%p) open for use " 30742793Slm66018 "(tstate=0x%x, status=0x%x)\n", 30752793Slm66018 ldcp->id, ldcp, ldcp->tstate, ldcp->status); 30761991Sheppo 30771991Sheppo return (0); 30781991Sheppo } 30791991Sheppo 30801991Sheppo /* 30811991Sheppo * Close the LDC connection. It will return EBUSY if there 30821991Sheppo * are memory segments or descriptor rings either bound to or 30831991Sheppo * mapped over the channel 30841991Sheppo */ 30851991Sheppo int 30861991Sheppo ldc_close(ldc_handle_t handle) 30871991Sheppo { 30881991Sheppo ldc_chan_t *ldcp; 30892336Snarayan int rv = 0, retries = 0; 30901991Sheppo boolean_t chk_done = B_FALSE; 30911991Sheppo 30921991Sheppo if (handle == NULL) { 30931991Sheppo DWARN(DBG_ALL_LDCS, "ldc_close: invalid channel handle\n"); 30941991Sheppo return (EINVAL); 30951991Sheppo } 30961991Sheppo ldcp = (ldc_chan_t *)handle; 30971991Sheppo 30981991Sheppo mutex_enter(&ldcp->lock); 30991991Sheppo 31001991Sheppo /* return error if channel is not open */ 31012793Slm66018 if ((ldcp->tstate & ~TS_IN_RESET) < TS_OPEN) { 31021991Sheppo DWARN(ldcp->id, 31031991Sheppo "ldc_close: (0x%llx) channel is not open\n", ldcp->id); 31041991Sheppo mutex_exit(&ldcp->lock); 31051991Sheppo return (EFAULT); 31061991Sheppo } 31071991Sheppo 31081991Sheppo /* if any memory handles, drings, are bound or mapped cannot close */ 31091991Sheppo if (ldcp->mhdl_list != NULL) { 31101991Sheppo DWARN(ldcp->id, 31111991Sheppo "ldc_close: (0x%llx) channel has bound memory handles\n", 31121991Sheppo ldcp->id); 31131991Sheppo mutex_exit(&ldcp->lock); 31141991Sheppo return (EBUSY); 31151991Sheppo } 31161991Sheppo if (ldcp->exp_dring_list != NULL) { 31171991Sheppo DWARN(ldcp->id, 31181991Sheppo "ldc_close: (0x%llx) channel has bound descriptor rings\n", 31191991Sheppo ldcp->id); 31201991Sheppo mutex_exit(&ldcp->lock); 31211991Sheppo return (EBUSY); 31221991Sheppo } 31231991Sheppo if (ldcp->imp_dring_list != NULL) { 31241991Sheppo DWARN(ldcp->id, 31251991Sheppo "ldc_close: (0x%llx) channel has mapped descriptor rings\n", 31261991Sheppo ldcp->id); 31271991Sheppo mutex_exit(&ldcp->lock); 31281991Sheppo return (EBUSY); 31291991Sheppo } 31301991Sheppo 31313151Ssg70180 if (ldcp->cb_inprogress) { 31323151Ssg70180 DWARN(ldcp->id, "ldc_close: (0x%llx) callback active\n", 31333151Ssg70180 ldcp->id); 31343151Ssg70180 mutex_exit(&ldcp->lock); 31353151Ssg70180 return (EWOULDBLOCK); 31363151Ssg70180 } 31373151Ssg70180 31382336Snarayan /* Obtain Tx lock */ 31392336Snarayan mutex_enter(&ldcp->tx_lock); 31402336Snarayan 31411991Sheppo /* 31421991Sheppo * Wait for pending transmits to complete i.e Tx queue to drain 31431991Sheppo * if there are pending pkts - wait 1 ms and retry again 31441991Sheppo */ 31451991Sheppo for (;;) { 31461991Sheppo 31471991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 31481991Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 31491991Sheppo if (rv) { 31501991Sheppo cmn_err(CE_WARN, 31511991Sheppo "ldc_close: (0x%lx) cannot read qptrs\n", ldcp->id); 31522336Snarayan mutex_exit(&ldcp->tx_lock); 31531991Sheppo mutex_exit(&ldcp->lock); 31541991Sheppo return (EIO); 31551991Sheppo } 31561991Sheppo 31571991Sheppo if (ldcp->tx_head == ldcp->tx_tail || 31581991Sheppo ldcp->link_state != LDC_CHANNEL_UP) { 31591991Sheppo break; 31601991Sheppo } 31611991Sheppo 31621991Sheppo if (chk_done) { 31631991Sheppo DWARN(ldcp->id, 31641991Sheppo "ldc_close: (0x%llx) Tx queue drain timeout\n", 31651991Sheppo ldcp->id); 31661991Sheppo break; 31671991Sheppo } 31681991Sheppo 31691991Sheppo /* wait for one ms and try again */ 31701991Sheppo delay(drv_usectohz(1000)); 31711991Sheppo chk_done = B_TRUE; 31721991Sheppo } 31731991Sheppo 31741991Sheppo /* 31752841Snarayan * Drain the Tx and Rx queues as we are closing the 31762841Snarayan * channel. We dont care about any pending packets. 31772841Snarayan * We have to also drain the queue prior to clearing 31782841Snarayan * pending interrupts, otherwise the HV will trigger 31792841Snarayan * an interrupt the moment the interrupt state is 31802841Snarayan * cleared. 31812793Slm66018 */ 31822793Slm66018 (void) i_ldc_txq_reconf(ldcp); 3183*10055SKevin.Crowe@Sun.COM i_ldc_rxq_drain(ldcp); 31842793Slm66018 31852793Slm66018 /* 31861991Sheppo * Unregister the channel with the nexus 31871991Sheppo */ 31882336Snarayan while ((rv = i_ldc_unregister_channel(ldcp)) != 0) { 31892336Snarayan 31902336Snarayan mutex_exit(&ldcp->tx_lock); 31911991Sheppo mutex_exit(&ldcp->lock); 31922336Snarayan 31932336Snarayan /* if any error other than EAGAIN return back */ 31942841Snarayan if (rv != EAGAIN || retries >= ldc_max_retries) { 31952336Snarayan cmn_err(CE_WARN, 31962336Snarayan "ldc_close: (0x%lx) unregister failed, %d\n", 31972336Snarayan ldcp->id, rv); 31982336Snarayan return (rv); 31992336Snarayan } 32002336Snarayan 32012336Snarayan /* 32022336Snarayan * As there could be pending interrupts we need 32032336Snarayan * to wait and try again 32042336Snarayan */ 32053151Ssg70180 drv_usecwait(ldc_close_delay); 32062336Snarayan mutex_enter(&ldcp->lock); 32072336Snarayan mutex_enter(&ldcp->tx_lock); 32082336Snarayan retries++; 32091991Sheppo } 32101991Sheppo 32118542SHaik.Aftandilian@Sun.COM ldcp->tstate &= ~TS_QCONF_RDY; 32128542SHaik.Aftandilian@Sun.COM 32131991Sheppo /* 32141991Sheppo * Unregister queues 32151991Sheppo */ 32161991Sheppo rv = hv_ldc_tx_qconf(ldcp->id, NULL, NULL); 32171991Sheppo if (rv) { 32181991Sheppo cmn_err(CE_WARN, 32191991Sheppo "ldc_close: (0x%lx) channel TX queue unconf failed\n", 32201991Sheppo ldcp->id); 32212336Snarayan mutex_exit(&ldcp->tx_lock); 32221991Sheppo mutex_exit(&ldcp->lock); 32231991Sheppo return (EIO); 32241991Sheppo } 32251991Sheppo rv = hv_ldc_rx_qconf(ldcp->id, NULL, NULL); 32261991Sheppo if (rv) { 32271991Sheppo cmn_err(CE_WARN, 32281991Sheppo "ldc_close: (0x%lx) channel RX queue unconf failed\n", 32291991Sheppo ldcp->id); 32302336Snarayan mutex_exit(&ldcp->tx_lock); 32311991Sheppo mutex_exit(&ldcp->lock); 32321991Sheppo return (EIO); 32331991Sheppo } 32341991Sheppo 32351991Sheppo /* Reset channel state information */ 32361991Sheppo i_ldc_reset_state(ldcp); 32371991Sheppo 32381991Sheppo /* Mark channel as down and in initialized state */ 32391991Sheppo ldcp->tx_ackd_head = 0; 32401991Sheppo ldcp->tx_head = 0; 32412793Slm66018 ldcp->tstate = TS_IN_RESET|TS_INIT; 32421991Sheppo ldcp->status = LDC_INIT; 32431991Sheppo 32442336Snarayan mutex_exit(&ldcp->tx_lock); 32451991Sheppo mutex_exit(&ldcp->lock); 32461991Sheppo 32471991Sheppo /* Decrement number of open channels */ 32481991Sheppo mutex_enter(&ldcssp->lock); 32491991Sheppo ldcssp->channels_open--; 32501991Sheppo mutex_exit(&ldcssp->lock); 32511991Sheppo 32521991Sheppo D1(ldcp->id, "ldc_close: (0x%llx) channel closed\n", ldcp->id); 32531991Sheppo 32541991Sheppo return (0); 32551991Sheppo } 32561991Sheppo 32571991Sheppo /* 32581991Sheppo * Register channel callback 32591991Sheppo */ 32601991Sheppo int 32611991Sheppo ldc_reg_callback(ldc_handle_t handle, 32621991Sheppo uint_t(*cb)(uint64_t event, caddr_t arg), caddr_t arg) 32631991Sheppo { 32641991Sheppo ldc_chan_t *ldcp; 32651991Sheppo 32661991Sheppo if (handle == NULL) { 32671991Sheppo DWARN(DBG_ALL_LDCS, 32681991Sheppo "ldc_reg_callback: invalid channel handle\n"); 32691991Sheppo return (EINVAL); 32701991Sheppo } 32711991Sheppo if (((uint64_t)cb) < KERNELBASE) { 32721991Sheppo DWARN(DBG_ALL_LDCS, "ldc_reg_callback: invalid callback\n"); 32731991Sheppo return (EINVAL); 32741991Sheppo } 32751991Sheppo ldcp = (ldc_chan_t *)handle; 32761991Sheppo 32771991Sheppo mutex_enter(&ldcp->lock); 32781991Sheppo 32791991Sheppo if (ldcp->cb) { 32801991Sheppo DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback exists\n", 32811991Sheppo ldcp->id); 32821991Sheppo mutex_exit(&ldcp->lock); 32831991Sheppo return (EIO); 32841991Sheppo } 32851991Sheppo if (ldcp->cb_inprogress) { 32861991Sheppo DWARN(ldcp->id, "ldc_reg_callback: (0x%llx) callback active\n", 32871991Sheppo ldcp->id); 32881991Sheppo mutex_exit(&ldcp->lock); 32891991Sheppo return (EWOULDBLOCK); 32901991Sheppo } 32911991Sheppo 32921991Sheppo ldcp->cb = cb; 32931991Sheppo ldcp->cb_arg = arg; 32941991Sheppo ldcp->cb_enabled = B_TRUE; 32951991Sheppo 32961991Sheppo D1(ldcp->id, 32971991Sheppo "ldc_reg_callback: (0x%llx) registered callback for channel\n", 32981991Sheppo ldcp->id); 32991991Sheppo 33001991Sheppo mutex_exit(&ldcp->lock); 33011991Sheppo 33021991Sheppo return (0); 33031991Sheppo } 33041991Sheppo 33051991Sheppo /* 33061991Sheppo * Unregister channel callback 33071991Sheppo */ 33081991Sheppo int 33091991Sheppo ldc_unreg_callback(ldc_handle_t handle) 33101991Sheppo { 33111991Sheppo ldc_chan_t *ldcp; 33121991Sheppo 33131991Sheppo if (handle == NULL) { 33141991Sheppo DWARN(DBG_ALL_LDCS, 33151991Sheppo "ldc_unreg_callback: invalid channel handle\n"); 33161991Sheppo return (EINVAL); 33171991Sheppo } 33181991Sheppo ldcp = (ldc_chan_t *)handle; 33191991Sheppo 33201991Sheppo mutex_enter(&ldcp->lock); 33211991Sheppo 33221991Sheppo if (ldcp->cb == NULL) { 33231991Sheppo DWARN(ldcp->id, 33241991Sheppo "ldc_unreg_callback: (0x%llx) no callback exists\n", 33251991Sheppo ldcp->id); 33261991Sheppo mutex_exit(&ldcp->lock); 33271991Sheppo return (EIO); 33281991Sheppo } 33291991Sheppo if (ldcp->cb_inprogress) { 33301991Sheppo DWARN(ldcp->id, 33311991Sheppo "ldc_unreg_callback: (0x%llx) callback active\n", 33321991Sheppo ldcp->id); 33331991Sheppo mutex_exit(&ldcp->lock); 33341991Sheppo return (EWOULDBLOCK); 33351991Sheppo } 33361991Sheppo 33371991Sheppo ldcp->cb = NULL; 33381991Sheppo ldcp->cb_arg = NULL; 33391991Sheppo ldcp->cb_enabled = B_FALSE; 33401991Sheppo 33411991Sheppo D1(ldcp->id, 33421991Sheppo "ldc_unreg_callback: (0x%llx) unregistered callback for channel\n", 33431991Sheppo ldcp->id); 33441991Sheppo 33451991Sheppo mutex_exit(&ldcp->lock); 33461991Sheppo 33471991Sheppo return (0); 33481991Sheppo } 33491991Sheppo 33501991Sheppo 33511991Sheppo /* 33521991Sheppo * Bring a channel up by initiating a handshake with the peer 33531991Sheppo * This call is asynchronous. It will complete at a later point 33541991Sheppo * in time when the peer responds back with an RTR. 33551991Sheppo */ 33561991Sheppo int 33571991Sheppo ldc_up(ldc_handle_t handle) 33581991Sheppo { 33591991Sheppo int rv; 33601991Sheppo ldc_chan_t *ldcp; 33611991Sheppo ldc_msg_t *ldcmsg; 33623808Ssb155480 uint64_t tx_tail, tstate, link_state; 33631991Sheppo 33641991Sheppo if (handle == NULL) { 33651991Sheppo DWARN(DBG_ALL_LDCS, "ldc_up: invalid channel handle\n"); 33661991Sheppo return (EINVAL); 33671991Sheppo } 33681991Sheppo ldcp = (ldc_chan_t *)handle; 33691991Sheppo 33701991Sheppo mutex_enter(&ldcp->lock); 33711991Sheppo 33722793Slm66018 D1(ldcp->id, "ldc_up: (0x%llx) doing channel UP\n", ldcp->id); 33732793Slm66018 33742793Slm66018 /* clear the reset state */ 33752793Slm66018 tstate = ldcp->tstate; 33762793Slm66018 ldcp->tstate &= ~TS_IN_RESET; 33772793Slm66018 33781991Sheppo if (ldcp->tstate == TS_UP) { 33792793Slm66018 DWARN(ldcp->id, 33801991Sheppo "ldc_up: (0x%llx) channel is already in UP state\n", 33811991Sheppo ldcp->id); 33822793Slm66018 33832793Slm66018 /* mark channel as up */ 33842793Slm66018 ldcp->status = LDC_UP; 33852793Slm66018 33862793Slm66018 /* 33872793Slm66018 * if channel was in reset state and there was 33882793Slm66018 * pending data clear interrupt state. this will 33892793Slm66018 * trigger an interrupt, causing the RX handler to 33902793Slm66018 * to invoke the client's callback 33912793Slm66018 */ 33922793Slm66018 if ((tstate & TS_IN_RESET) && 33932793Slm66018 ldcp->rx_intr_state == LDC_INTR_PEND) { 33943010Slm66018 D1(ldcp->id, 33952793Slm66018 "ldc_up: (0x%llx) channel has pending data, " 33962793Slm66018 "clearing interrupt\n", ldcp->id); 33972793Slm66018 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 33982793Slm66018 } 33992793Slm66018 34001991Sheppo mutex_exit(&ldcp->lock); 34011991Sheppo return (0); 34021991Sheppo } 34031991Sheppo 34041991Sheppo /* if the channel is in RAW mode - mark it as UP, if READY */ 34051991Sheppo if (ldcp->mode == LDC_MODE_RAW && ldcp->tstate >= TS_READY) { 34061991Sheppo ldcp->tstate = TS_UP; 34071991Sheppo mutex_exit(&ldcp->lock); 34081991Sheppo return (0); 34091991Sheppo } 34101991Sheppo 34111991Sheppo /* Don't start another handshake if there is one in progress */ 34121991Sheppo if (ldcp->hstate) { 34132793Slm66018 D1(ldcp->id, 34141991Sheppo "ldc_up: (0x%llx) channel handshake in progress\n", 34151991Sheppo ldcp->id); 34161991Sheppo mutex_exit(&ldcp->lock); 34171991Sheppo return (0); 34181991Sheppo } 34191991Sheppo 34202336Snarayan mutex_enter(&ldcp->tx_lock); 34212336Snarayan 34223808Ssb155480 /* save current link state */ 34233808Ssb155480 link_state = ldcp->link_state; 34243808Ssb155480 34251991Sheppo /* get the current tail for the LDC msg */ 34261991Sheppo rv = i_ldc_get_tx_tail(ldcp, &tx_tail); 34271991Sheppo if (rv) { 34283010Slm66018 D1(ldcp->id, "ldc_up: (0x%llx) cannot initiate handshake\n", 34291991Sheppo ldcp->id); 34302336Snarayan mutex_exit(&ldcp->tx_lock); 34311991Sheppo mutex_exit(&ldcp->lock); 34321991Sheppo return (ECONNREFUSED); 34331991Sheppo } 34341991Sheppo 34353808Ssb155480 /* 34363808Ssb155480 * If i_ldc_get_tx_tail() changed link_state to either RESET or UP, 34373808Ssb155480 * from a previous state of DOWN, then mark the channel as 34383808Ssb155480 * being ready for handshake. 34393808Ssb155480 */ 34403808Ssb155480 if ((link_state == LDC_CHANNEL_DOWN) && 34413808Ssb155480 (link_state != ldcp->link_state)) { 34423808Ssb155480 34433808Ssb155480 ASSERT((ldcp->link_state == LDC_CHANNEL_RESET) || 34443808Ssb155480 (ldcp->link_state == LDC_CHANNEL_UP)); 34453808Ssb155480 34463808Ssb155480 if (ldcp->mode == LDC_MODE_RAW) { 34473808Ssb155480 ldcp->status = LDC_UP; 34483808Ssb155480 ldcp->tstate = TS_UP; 34493808Ssb155480 mutex_exit(&ldcp->tx_lock); 34503808Ssb155480 mutex_exit(&ldcp->lock); 34513808Ssb155480 return (0); 34523808Ssb155480 } else { 34533808Ssb155480 ldcp->status = LDC_READY; 34543808Ssb155480 ldcp->tstate |= TS_LINK_READY; 34553808Ssb155480 } 34563808Ssb155480 34573808Ssb155480 } 34583808Ssb155480 34591991Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 34601991Sheppo ZERO_PKT(ldcmsg); 34611991Sheppo 34621991Sheppo ldcmsg->type = LDC_CTRL; 34631991Sheppo ldcmsg->stype = LDC_INFO; 34641991Sheppo ldcmsg->ctrl = LDC_VER; 34651991Sheppo ldcp->next_vidx = 0; 34661991Sheppo bcopy(&ldc_versions[0], ldcmsg->udata, sizeof (ldc_versions[0])); 34671991Sheppo 34681991Sheppo DUMP_LDC_PKT(ldcp, "ldc_up snd ver", (uint64_t)ldcmsg); 34691991Sheppo 34701991Sheppo /* initiate the send by calling into HV and set the new tail */ 34711991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) % 34724690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 34731991Sheppo 34741991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 34751991Sheppo if (rv) { 34761991Sheppo DWARN(ldcp->id, 34771991Sheppo "ldc_up: (0x%llx) cannot initiate handshake rv=%d\n", 34781991Sheppo ldcp->id, rv); 34792336Snarayan mutex_exit(&ldcp->tx_lock); 34801991Sheppo mutex_exit(&ldcp->lock); 34811991Sheppo return (rv); 34821991Sheppo } 34831991Sheppo 34842032Slm66018 ldcp->hstate |= TS_SENT_VER; 34851991Sheppo ldcp->tx_tail = tx_tail; 34861991Sheppo D1(ldcp->id, "ldc_up: (0x%llx) channel up initiated\n", ldcp->id); 34871991Sheppo 34882336Snarayan mutex_exit(&ldcp->tx_lock); 34891991Sheppo mutex_exit(&ldcp->lock); 34901991Sheppo 34911991Sheppo return (rv); 34921991Sheppo } 34931991Sheppo 34941991Sheppo 34951991Sheppo /* 34962410Slm66018 * Bring a channel down by resetting its state and queues 34971991Sheppo */ 34981991Sheppo int 34992410Slm66018 ldc_down(ldc_handle_t handle) 35001991Sheppo { 35011991Sheppo ldc_chan_t *ldcp; 35021991Sheppo 35031991Sheppo if (handle == NULL) { 35042410Slm66018 DWARN(DBG_ALL_LDCS, "ldc_down: invalid channel handle\n"); 35051991Sheppo return (EINVAL); 35061991Sheppo } 35071991Sheppo ldcp = (ldc_chan_t *)handle; 35081991Sheppo mutex_enter(&ldcp->lock); 35092336Snarayan mutex_enter(&ldcp->tx_lock); 35102793Slm66018 i_ldc_reset(ldcp, B_TRUE); 35112336Snarayan mutex_exit(&ldcp->tx_lock); 35121991Sheppo mutex_exit(&ldcp->lock); 35131991Sheppo 35141991Sheppo return (0); 35151991Sheppo } 35161991Sheppo 35171991Sheppo /* 35181991Sheppo * Get the current channel status 35191991Sheppo */ 35201991Sheppo int 35211991Sheppo ldc_status(ldc_handle_t handle, ldc_status_t *status) 35221991Sheppo { 35231991Sheppo ldc_chan_t *ldcp; 35241991Sheppo 35251991Sheppo if (handle == NULL || status == NULL) { 35261991Sheppo DWARN(DBG_ALL_LDCS, "ldc_status: invalid argument\n"); 35271991Sheppo return (EINVAL); 35281991Sheppo } 35291991Sheppo ldcp = (ldc_chan_t *)handle; 35301991Sheppo 35311991Sheppo *status = ((ldc_chan_t *)handle)->status; 35321991Sheppo 35333010Slm66018 D1(ldcp->id, 35341991Sheppo "ldc_status: (0x%llx) returned status %d\n", ldcp->id, *status); 35351991Sheppo return (0); 35361991Sheppo } 35371991Sheppo 35381991Sheppo 35391991Sheppo /* 35401991Sheppo * Set the channel's callback mode - enable/disable callbacks 35411991Sheppo */ 35421991Sheppo int 35431991Sheppo ldc_set_cb_mode(ldc_handle_t handle, ldc_cb_mode_t cmode) 35441991Sheppo { 35451991Sheppo ldc_chan_t *ldcp; 35461991Sheppo 35471991Sheppo if (handle == NULL) { 35481991Sheppo DWARN(DBG_ALL_LDCS, 35491991Sheppo "ldc_set_intr_mode: invalid channel handle\n"); 35501991Sheppo return (EINVAL); 35511991Sheppo } 35521991Sheppo ldcp = (ldc_chan_t *)handle; 35531991Sheppo 35541991Sheppo /* 35551991Sheppo * Record no callbacks should be invoked 35561991Sheppo */ 35571991Sheppo mutex_enter(&ldcp->lock); 35581991Sheppo 35591991Sheppo switch (cmode) { 35601991Sheppo case LDC_CB_DISABLE: 35611991Sheppo if (!ldcp->cb_enabled) { 35621991Sheppo DWARN(ldcp->id, 35631991Sheppo "ldc_set_cb_mode: (0x%llx) callbacks disabled\n", 35641991Sheppo ldcp->id); 35651991Sheppo break; 35661991Sheppo } 35671991Sheppo ldcp->cb_enabled = B_FALSE; 35681991Sheppo 35691991Sheppo D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) disabled callbacks\n", 35701991Sheppo ldcp->id); 35711991Sheppo break; 35721991Sheppo 35731991Sheppo case LDC_CB_ENABLE: 35741991Sheppo if (ldcp->cb_enabled) { 35751991Sheppo DWARN(ldcp->id, 35761991Sheppo "ldc_set_cb_mode: (0x%llx) callbacks enabled\n", 35771991Sheppo ldcp->id); 35781991Sheppo break; 35791991Sheppo } 35801991Sheppo ldcp->cb_enabled = B_TRUE; 35811991Sheppo 35821991Sheppo D1(ldcp->id, "ldc_set_cb_mode: (0x%llx) enabled callbacks\n", 35831991Sheppo ldcp->id); 35841991Sheppo break; 35851991Sheppo } 35861991Sheppo 35871991Sheppo mutex_exit(&ldcp->lock); 35881991Sheppo 35891991Sheppo return (0); 35901991Sheppo } 35911991Sheppo 35921991Sheppo /* 35931991Sheppo * Check to see if there are packets on the incoming queue 35942410Slm66018 * Will return hasdata = B_FALSE if there are no packets 35951991Sheppo */ 35961991Sheppo int 35972410Slm66018 ldc_chkq(ldc_handle_t handle, boolean_t *hasdata) 35981991Sheppo { 35991991Sheppo int rv; 36001991Sheppo uint64_t rx_head, rx_tail; 36011991Sheppo ldc_chan_t *ldcp; 36021991Sheppo 36031991Sheppo if (handle == NULL) { 36041991Sheppo DWARN(DBG_ALL_LDCS, "ldc_chkq: invalid channel handle\n"); 36051991Sheppo return (EINVAL); 36061991Sheppo } 36071991Sheppo ldcp = (ldc_chan_t *)handle; 36081991Sheppo 36092410Slm66018 *hasdata = B_FALSE; 36101991Sheppo 36111991Sheppo mutex_enter(&ldcp->lock); 36121991Sheppo 36131991Sheppo if (ldcp->tstate != TS_UP) { 36141991Sheppo D1(ldcp->id, 36151991Sheppo "ldc_chkq: (0x%llx) channel is not up\n", ldcp->id); 36161991Sheppo mutex_exit(&ldcp->lock); 36171991Sheppo return (ECONNRESET); 36181991Sheppo } 36191991Sheppo 36201991Sheppo /* Read packet(s) from the queue */ 36211991Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 36221991Sheppo &ldcp->link_state); 36231991Sheppo if (rv != 0) { 36241991Sheppo cmn_err(CE_WARN, 36251991Sheppo "ldc_chkq: (0x%lx) unable to read queue ptrs", ldcp->id); 36261991Sheppo mutex_exit(&ldcp->lock); 36271991Sheppo return (EIO); 36281991Sheppo } 36295944Sha137994 36301991Sheppo /* reset the channel state if the channel went down */ 36311991Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN || 36321991Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 36332336Snarayan mutex_enter(&ldcp->tx_lock); 36342793Slm66018 i_ldc_reset(ldcp, B_FALSE); 36352336Snarayan mutex_exit(&ldcp->tx_lock); 36361991Sheppo mutex_exit(&ldcp->lock); 36371991Sheppo return (ECONNRESET); 36381991Sheppo } 36391991Sheppo 36405944Sha137994 switch (ldcp->mode) { 36415944Sha137994 case LDC_MODE_RAW: 36425944Sha137994 /* 36435944Sha137994 * In raw mode, there are no ctrl packets, so checking 36445944Sha137994 * if the queue is non-empty is sufficient. 36455944Sha137994 */ 36465944Sha137994 *hasdata = (rx_head != rx_tail); 36475944Sha137994 break; 36485944Sha137994 36495944Sha137994 case LDC_MODE_UNRELIABLE: 36505944Sha137994 /* 36515944Sha137994 * In unreliable mode, if the queue is non-empty, we need 36525944Sha137994 * to check if it actually contains unread data packets. 36535944Sha137994 * The queue may just contain ctrl packets. 36545944Sha137994 */ 36556446Sha137994 if (rx_head != rx_tail) { 36565944Sha137994 *hasdata = (i_ldc_chkq(ldcp) == 0); 36576446Sha137994 /* 36586446Sha137994 * If no data packets were found on the queue, 36596446Sha137994 * all packets must have been control packets 36606446Sha137994 * which will now have been processed, leaving 36616446Sha137994 * the queue empty. If the interrupt state 36626446Sha137994 * is pending, we need to clear the interrupt 36636446Sha137994 * here. 36646446Sha137994 */ 36656446Sha137994 if (*hasdata == B_FALSE && 36666446Sha137994 ldcp->rx_intr_state == LDC_INTR_PEND) { 36676446Sha137994 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 36686446Sha137994 } 36696446Sha137994 } 36705944Sha137994 break; 36715944Sha137994 36726408Sha137994 case LDC_MODE_RELIABLE: 36735944Sha137994 /* 36746408Sha137994 * In reliable mode, first check for 'stream_remains' > 0. 36755944Sha137994 * Otherwise, if the data queue head and tail pointers 36765944Sha137994 * differ, there must be data to read. 36775944Sha137994 */ 36785944Sha137994 if (ldcp->stream_remains > 0) 36795944Sha137994 *hasdata = B_TRUE; 36805944Sha137994 else 36815944Sha137994 *hasdata = (ldcp->rx_dq_head != ldcp->rx_dq_tail); 36825944Sha137994 break; 36835944Sha137994 36845944Sha137994 default: 36855944Sha137994 cmn_err(CE_WARN, "ldc_chkq: (0x%lx) unexpected channel mode " 36865944Sha137994 "(0x%x)", ldcp->id, ldcp->mode); 36875944Sha137994 mutex_exit(&ldcp->lock); 36885944Sha137994 return (EIO); 36891991Sheppo } 36901991Sheppo 36911991Sheppo mutex_exit(&ldcp->lock); 36921991Sheppo 36931991Sheppo return (0); 36941991Sheppo } 36951991Sheppo 36961991Sheppo 36971991Sheppo /* 36981991Sheppo * Read 'size' amount of bytes or less. If incoming buffer 36991991Sheppo * is more than 'size', ENOBUFS is returned. 37001991Sheppo * 37011991Sheppo * On return, size contains the number of bytes read. 37021991Sheppo */ 37031991Sheppo int 37041991Sheppo ldc_read(ldc_handle_t handle, caddr_t bufp, size_t *sizep) 37051991Sheppo { 37061991Sheppo ldc_chan_t *ldcp; 37071991Sheppo uint64_t rx_head = 0, rx_tail = 0; 37081991Sheppo int rv = 0, exit_val; 37091991Sheppo 37101991Sheppo if (handle == NULL) { 37111991Sheppo DWARN(DBG_ALL_LDCS, "ldc_read: invalid channel handle\n"); 37121991Sheppo return (EINVAL); 37131991Sheppo } 37141991Sheppo 37151991Sheppo ldcp = (ldc_chan_t *)handle; 37161991Sheppo 37171991Sheppo /* channel lock */ 37181991Sheppo mutex_enter(&ldcp->lock); 37191991Sheppo 37201991Sheppo if (ldcp->tstate != TS_UP) { 37211991Sheppo DWARN(ldcp->id, 37221991Sheppo "ldc_read: (0x%llx) channel is not in UP state\n", 37231991Sheppo ldcp->id); 37241991Sheppo exit_val = ECONNRESET; 37256408Sha137994 } else if (ldcp->mode == LDC_MODE_RELIABLE) { 37265944Sha137994 TRACE_RXDQ_LENGTH(ldcp); 37275944Sha137994 exit_val = ldcp->read_p(ldcp, bufp, sizep); 37286944Sha137994 37296944Sha137994 /* 37306944Sha137994 * For reliable mode channels, the interrupt 37316944Sha137994 * state is only set to pending during 37326944Sha137994 * interrupt handling when the secondary data 37336944Sha137994 * queue became full, leaving unprocessed 37346944Sha137994 * packets on the Rx queue. If the interrupt 37356944Sha137994 * state is pending and space is now available 37366944Sha137994 * on the data queue, clear the interrupt. 37376944Sha137994 */ 37386944Sha137994 if (ldcp->rx_intr_state == LDC_INTR_PEND && 37396944Sha137994 Q_CONTIG_SPACE(ldcp->rx_dq_head, ldcp->rx_dq_tail, 37406944Sha137994 ldcp->rx_dq_entries << LDC_PACKET_SHIFT) >= 37416944Sha137994 LDC_PACKET_SIZE) { 37426944Sha137994 /* data queue is not full */ 37436944Sha137994 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 37446944Sha137994 } 37456944Sha137994 37465944Sha137994 mutex_exit(&ldcp->lock); 37475944Sha137994 return (exit_val); 37481991Sheppo } else { 37491991Sheppo exit_val = ldcp->read_p(ldcp, bufp, sizep); 37501991Sheppo } 37511991Sheppo 37521991Sheppo /* 37531991Sheppo * if queue has been drained - clear interrupt 37541991Sheppo */ 37551991Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 37561991Sheppo &ldcp->link_state); 37573010Slm66018 if (rv != 0) { 37583010Slm66018 cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs", 37593010Slm66018 ldcp->id); 37603010Slm66018 mutex_enter(&ldcp->tx_lock); 37613010Slm66018 i_ldc_reset(ldcp, B_TRUE); 37623010Slm66018 mutex_exit(&ldcp->tx_lock); 37633653Snarayan mutex_exit(&ldcp->lock); 37643010Slm66018 return (ECONNRESET); 37653010Slm66018 } 37662793Slm66018 37672793Slm66018 if (exit_val == 0) { 37682793Slm66018 if (ldcp->link_state == LDC_CHANNEL_DOWN || 37692793Slm66018 ldcp->link_state == LDC_CHANNEL_RESET) { 37702793Slm66018 mutex_enter(&ldcp->tx_lock); 37712793Slm66018 i_ldc_reset(ldcp, B_FALSE); 37722793Slm66018 exit_val = ECONNRESET; 37732793Slm66018 mutex_exit(&ldcp->tx_lock); 37742793Slm66018 } 37752793Slm66018 if ((rv == 0) && 37762793Slm66018 (ldcp->rx_intr_state == LDC_INTR_PEND) && 37772793Slm66018 (rx_head == rx_tail)) { 37782793Slm66018 i_ldc_clear_intr(ldcp, CNEX_RX_INTR); 37792793Slm66018 } 37801991Sheppo } 37811991Sheppo 37821991Sheppo mutex_exit(&ldcp->lock); 37831991Sheppo return (exit_val); 37841991Sheppo } 37851991Sheppo 37861991Sheppo /* 37871991Sheppo * Basic raw mondo read - 37881991Sheppo * no interpretation of mondo contents at all. 37891991Sheppo * 37901991Sheppo * Enter and exit with ldcp->lock held by caller 37911991Sheppo */ 37921991Sheppo static int 37931991Sheppo i_ldc_read_raw(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep) 37941991Sheppo { 37951991Sheppo uint64_t q_size_mask; 37961991Sheppo ldc_msg_t *msgp; 37971991Sheppo uint8_t *msgbufp; 37981991Sheppo int rv = 0, space; 37991991Sheppo uint64_t rx_head, rx_tail; 38001991Sheppo 38011991Sheppo space = *sizep; 38021991Sheppo 38031991Sheppo if (space < LDC_PAYLOAD_SIZE_RAW) 38041991Sheppo return (ENOBUFS); 38051991Sheppo 38061991Sheppo ASSERT(mutex_owned(&ldcp->lock)); 38071991Sheppo 38081991Sheppo /* compute mask for increment */ 38091991Sheppo q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT; 38101991Sheppo 38111991Sheppo /* 38121991Sheppo * Read packet(s) from the queue 38131991Sheppo */ 38141991Sheppo rv = hv_ldc_rx_get_state(ldcp->id, &rx_head, &rx_tail, 38151991Sheppo &ldcp->link_state); 38161991Sheppo if (rv != 0) { 38171991Sheppo cmn_err(CE_WARN, 38181991Sheppo "ldc_read_raw: (0x%lx) unable to read queue ptrs", 38191991Sheppo ldcp->id); 38201991Sheppo return (EIO); 38211991Sheppo } 38221991Sheppo D1(ldcp->id, "ldc_read_raw: (0x%llx) rxh=0x%llx," 38234690Snarayan " rxt=0x%llx, st=0x%llx\n", 38244690Snarayan ldcp->id, rx_head, rx_tail, ldcp->link_state); 38251991Sheppo 38261991Sheppo /* reset the channel state if the channel went down */ 38272793Slm66018 if (ldcp->link_state == LDC_CHANNEL_DOWN || 38282793Slm66018 ldcp->link_state == LDC_CHANNEL_RESET) { 38292336Snarayan mutex_enter(&ldcp->tx_lock); 38302793Slm66018 i_ldc_reset(ldcp, B_FALSE); 38312336Snarayan mutex_exit(&ldcp->tx_lock); 38321991Sheppo return (ECONNRESET); 38331991Sheppo } 38341991Sheppo 38351991Sheppo /* 38361991Sheppo * Check for empty queue 38371991Sheppo */ 38381991Sheppo if (rx_head == rx_tail) { 38391991Sheppo *sizep = 0; 38401991Sheppo return (0); 38411991Sheppo } 38421991Sheppo 38431991Sheppo /* get the message */ 38441991Sheppo msgp = (ldc_msg_t *)(ldcp->rx_q_va + rx_head); 38451991Sheppo 38461991Sheppo /* if channel is in RAW mode, copy data and return */ 38471991Sheppo msgbufp = (uint8_t *)&(msgp->raw[0]); 38481991Sheppo 38491991Sheppo bcopy(msgbufp, target_bufp, LDC_PAYLOAD_SIZE_RAW); 38501991Sheppo 38511991Sheppo DUMP_PAYLOAD(ldcp->id, msgbufp); 38521991Sheppo 38531991Sheppo *sizep = LDC_PAYLOAD_SIZE_RAW; 38541991Sheppo 38551991Sheppo rx_head = (rx_head + LDC_PACKET_SIZE) & q_size_mask; 38562032Slm66018 rv = i_ldc_set_rx_head(ldcp, rx_head); 38571991Sheppo 38581991Sheppo return (rv); 38591991Sheppo } 38601991Sheppo 38611991Sheppo /* 38621991Sheppo * Process LDC mondos to build larger packets 38631991Sheppo * with either un-reliable or reliable delivery. 38641991Sheppo * 38651991Sheppo * Enter and exit with ldcp->lock held by caller 38661991Sheppo */ 38671991Sheppo static int 38681991Sheppo i_ldc_read_packet(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep) 38691991Sheppo { 38701991Sheppo int rv = 0; 38711991Sheppo uint64_t rx_head = 0, rx_tail = 0; 38721991Sheppo uint64_t curr_head = 0; 38731991Sheppo ldc_msg_t *msg; 38741991Sheppo caddr_t target; 38751991Sheppo size_t len = 0, bytes_read = 0; 38762032Slm66018 int retries = 0; 38775944Sha137994 uint64_t q_va, q_size_mask; 38782336Snarayan uint64_t first_fragment = 0; 38791991Sheppo 38801991Sheppo target = target_bufp; 38811991Sheppo 38821991Sheppo ASSERT(mutex_owned(&ldcp->lock)); 38831991Sheppo 38842793Slm66018 /* check if the buffer and size are valid */ 38852793Slm66018 if (target_bufp == NULL || *sizep == 0) { 38862793Slm66018 DWARN(ldcp->id, "ldc_read: (0x%llx) invalid buffer/size\n", 38872793Slm66018 ldcp->id); 38882793Slm66018 return (EINVAL); 38892793Slm66018 } 38902793Slm66018 38915944Sha137994 /* Set q_va and compute increment mask for the appropriate queue */ 38926408Sha137994 if (ldcp->mode == LDC_MODE_RELIABLE) { 38935944Sha137994 q_va = ldcp->rx_dq_va; 38945944Sha137994 q_size_mask = (ldcp->rx_dq_entries-1)<<LDC_PACKET_SHIFT; 38955944Sha137994 } else { 38965944Sha137994 q_va = ldcp->rx_q_va; 38975944Sha137994 q_size_mask = (ldcp->rx_q_entries-1)<<LDC_PACKET_SHIFT; 38985944Sha137994 } 38991991Sheppo 39001991Sheppo /* 39011991Sheppo * Read packet(s) from the queue 39021991Sheppo */ 39035944Sha137994 rv = ldcp->readq_get_state(ldcp, &curr_head, &rx_tail, 39041991Sheppo &ldcp->link_state); 39051991Sheppo if (rv != 0) { 39062793Slm66018 cmn_err(CE_WARN, "ldc_read: (0x%lx) unable to read queue ptrs", 39071991Sheppo ldcp->id); 39082793Slm66018 mutex_enter(&ldcp->tx_lock); 39092793Slm66018 i_ldc_reset(ldcp, B_TRUE); 39102793Slm66018 mutex_exit(&ldcp->tx_lock); 39112793Slm66018 return (ECONNRESET); 39121991Sheppo } 39131991Sheppo D1(ldcp->id, "ldc_read: (0x%llx) chd=0x%llx, tl=0x%llx, st=0x%llx\n", 39141991Sheppo ldcp->id, curr_head, rx_tail, ldcp->link_state); 39151991Sheppo 39161991Sheppo /* reset the channel state if the channel went down */ 39172793Slm66018 if (ldcp->link_state != LDC_CHANNEL_UP) 39182793Slm66018 goto channel_is_reset; 39191991Sheppo 39201991Sheppo for (;;) { 39211991Sheppo 39221991Sheppo if (curr_head == rx_tail) { 39235944Sha137994 /* 39245944Sha137994 * If a data queue is being used, check the Rx HV 39255944Sha137994 * queue. This will copy over any new data packets 39265944Sha137994 * that have arrived. 39275944Sha137994 */ 39286408Sha137994 if (ldcp->mode == LDC_MODE_RELIABLE) 39295944Sha137994 (void) i_ldc_chkq(ldcp); 39305944Sha137994 39315944Sha137994 rv = ldcp->readq_get_state(ldcp, 39321991Sheppo &rx_head, &rx_tail, &ldcp->link_state); 39331991Sheppo if (rv != 0) { 39341991Sheppo cmn_err(CE_WARN, 39351991Sheppo "ldc_read: (0x%lx) cannot read queue ptrs", 39361991Sheppo ldcp->id); 39372336Snarayan mutex_enter(&ldcp->tx_lock); 39382793Slm66018 i_ldc_reset(ldcp, B_TRUE); 39392336Snarayan mutex_exit(&ldcp->tx_lock); 39401991Sheppo return (ECONNRESET); 39411991Sheppo } 39425944Sha137994 39432793Slm66018 if (ldcp->link_state != LDC_CHANNEL_UP) 39442793Slm66018 goto channel_is_reset; 39452793Slm66018 39462793Slm66018 if (curr_head == rx_tail) { 39472793Slm66018 39482793Slm66018 /* If in the middle of a fragmented xfer */ 39492793Slm66018 if (first_fragment != 0) { 39502793Slm66018 39512793Slm66018 /* wait for ldc_delay usecs */ 39522793Slm66018 drv_usecwait(ldc_delay); 39532793Slm66018 39542793Slm66018 if (++retries < ldc_max_retries) 39552793Slm66018 continue; 39562793Slm66018 39572793Slm66018 *sizep = 0; 39586408Sha137994 if (ldcp->mode != LDC_MODE_RELIABLE) 39595944Sha137994 ldcp->last_msg_rcd = 39605944Sha137994 first_fragment - 1; 39612793Slm66018 DWARN(DBG_ALL_LDCS, "ldc_read: " 39624690Snarayan "(0x%llx) read timeout", ldcp->id); 39632793Slm66018 return (EAGAIN); 39642793Slm66018 } 39652032Slm66018 *sizep = 0; 39662793Slm66018 break; 39671991Sheppo } 39681991Sheppo } 39692032Slm66018 retries = 0; 39701991Sheppo 39711991Sheppo D2(ldcp->id, 39721991Sheppo "ldc_read: (0x%llx) chd=0x%llx, rxhd=0x%llx, rxtl=0x%llx\n", 39731991Sheppo ldcp->id, curr_head, rx_head, rx_tail); 39741991Sheppo 39751991Sheppo /* get the message */ 39765944Sha137994 msg = (ldc_msg_t *)(q_va + curr_head); 39771991Sheppo 39781991Sheppo DUMP_LDC_PKT(ldcp, "ldc_read received pkt", 39791991Sheppo ldcp->rx_q_va + curr_head); 39801991Sheppo 39811991Sheppo /* Check the message ID for the message received */ 39826408Sha137994 if (ldcp->mode != LDC_MODE_RELIABLE) { 39835944Sha137994 if ((rv = i_ldc_check_seqid(ldcp, msg)) != 0) { 39845944Sha137994 39855944Sha137994 DWARN(ldcp->id, "ldc_read: (0x%llx) seqid " 39865944Sha137994 "error, q_ptrs=0x%lx,0x%lx", 39875944Sha137994 ldcp->id, rx_head, rx_tail); 39885944Sha137994 39895944Sha137994 /* throw away data */ 39905944Sha137994 bytes_read = 0; 39915944Sha137994 39925944Sha137994 /* Reset last_msg_rcd to start of message */ 39935944Sha137994 if (first_fragment != 0) { 39945944Sha137994 ldcp->last_msg_rcd = first_fragment - 1; 39955944Sha137994 first_fragment = 0; 39965944Sha137994 } 39975944Sha137994 /* 39985944Sha137994 * Send a NACK -- invalid seqid 39995944Sha137994 * get the current tail for the response 40005944Sha137994 */ 40015944Sha137994 rv = i_ldc_send_pkt(ldcp, msg->type, LDC_NACK, 40025944Sha137994 (msg->ctrl & LDC_CTRL_MASK)); 40035944Sha137994 if (rv) { 40045944Sha137994 cmn_err(CE_NOTE, 40055944Sha137994 "ldc_read: (0x%lx) err sending " 40065944Sha137994 "NACK msg\n", ldcp->id); 40075944Sha137994 40085944Sha137994 /* if cannot send NACK - reset chan */ 40095944Sha137994 mutex_enter(&ldcp->tx_lock); 40105944Sha137994 i_ldc_reset(ldcp, B_FALSE); 40115944Sha137994 mutex_exit(&ldcp->tx_lock); 40125944Sha137994 rv = ECONNRESET; 40135944Sha137994 break; 40145944Sha137994 } 40155944Sha137994 40165944Sha137994 /* purge receive queue */ 40175944Sha137994 rv = i_ldc_set_rx_head(ldcp, rx_tail); 40185944Sha137994 40192336Snarayan break; 40201991Sheppo } 40211991Sheppo 40225944Sha137994 /* 40235944Sha137994 * Process any messages of type CTRL messages 40245944Sha137994 * Future implementations should try to pass these 40255944Sha137994 * to LDC link by resetting the intr state. 40265944Sha137994 * 40275944Sha137994 * NOTE: not done as a switch() as type can be 40285944Sha137994 * both ctrl+data 40295944Sha137994 */ 40305944Sha137994 if (msg->type & LDC_CTRL) { 40315944Sha137994 if (rv = i_ldc_ctrlmsg(ldcp, msg)) { 40325944Sha137994 if (rv == EAGAIN) 40335944Sha137994 continue; 40345944Sha137994 rv = i_ldc_set_rx_head(ldcp, rx_tail); 40355944Sha137994 *sizep = 0; 40365944Sha137994 bytes_read = 0; 40375944Sha137994 break; 40385944Sha137994 } 40391991Sheppo } 40405944Sha137994 40415944Sha137994 /* process data ACKs */ 40425944Sha137994 if ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK)) { 40435944Sha137994 if (rv = i_ldc_process_data_ACK(ldcp, msg)) { 40445944Sha137994 *sizep = 0; 40455944Sha137994 bytes_read = 0; 40465944Sha137994 break; 40475944Sha137994 } 40482336Snarayan } 40495944Sha137994 40505944Sha137994 /* process data NACKs */ 40515944Sha137994 if ((msg->type & LDC_DATA) && (msg->stype & LDC_NACK)) { 40525944Sha137994 DWARN(ldcp->id, 40535944Sha137994 "ldc_read: (0x%llx) received DATA/NACK", 40545944Sha137994 ldcp->id); 40555944Sha137994 mutex_enter(&ldcp->tx_lock); 40565944Sha137994 i_ldc_reset(ldcp, B_TRUE); 40575944Sha137994 mutex_exit(&ldcp->tx_lock); 40585944Sha137994 return (ECONNRESET); 40595944Sha137994 } 40603560Snarayan } 40613560Snarayan 40621991Sheppo /* process data messages */ 40631991Sheppo if ((msg->type & LDC_DATA) && (msg->stype & LDC_INFO)) { 40641991Sheppo 40651991Sheppo uint8_t *msgbuf = (uint8_t *)( 40666408Sha137994 (ldcp->mode == LDC_MODE_RELIABLE) ? 40674690Snarayan msg->rdata : msg->udata); 40681991Sheppo 40691991Sheppo D2(ldcp->id, 40701991Sheppo "ldc_read: (0x%llx) received data msg\n", ldcp->id); 40711991Sheppo 40721991Sheppo /* get the packet length */ 40731991Sheppo len = (msg->env & LDC_LEN_MASK); 40741991Sheppo 40751991Sheppo /* 40761991Sheppo * FUTURE OPTIMIZATION: 40771991Sheppo * dont need to set q head for every 40781991Sheppo * packet we read just need to do this when 40791991Sheppo * we are done or need to wait for more 40801991Sheppo * mondos to make a full packet - this is 40811991Sheppo * currently expensive. 40821991Sheppo */ 40831991Sheppo 40842336Snarayan if (first_fragment == 0) { 40851991Sheppo 40861991Sheppo /* 40871991Sheppo * first packets should always have the start 40881991Sheppo * bit set (even for a single packet). If not 40891991Sheppo * throw away the packet 40901991Sheppo */ 40911991Sheppo if (!(msg->env & LDC_FRAG_START)) { 40921991Sheppo 40931991Sheppo DWARN(DBG_ALL_LDCS, 40941991Sheppo "ldc_read: (0x%llx) not start - " 40951991Sheppo "frag=%x\n", ldcp->id, 40961991Sheppo (msg->env) & LDC_FRAG_MASK); 40971991Sheppo 40981991Sheppo /* toss pkt, inc head, cont reading */ 40991991Sheppo bytes_read = 0; 41001991Sheppo target = target_bufp; 41011991Sheppo curr_head = 41024690Snarayan (curr_head + LDC_PACKET_SIZE) 41034690Snarayan & q_size_mask; 41045944Sha137994 if (rv = ldcp->readq_set_head(ldcp, 41054690Snarayan curr_head)) 41061991Sheppo break; 41071991Sheppo 41081991Sheppo continue; 41091991Sheppo } 41101991Sheppo 41112336Snarayan first_fragment = msg->seqid; 41121991Sheppo } else { 41131991Sheppo /* check to see if this is a pkt w/ START bit */ 41141991Sheppo if (msg->env & LDC_FRAG_START) { 41151991Sheppo DWARN(DBG_ALL_LDCS, 41161991Sheppo "ldc_read:(0x%llx) unexpected pkt" 41171991Sheppo " env=0x%x discarding %d bytes," 41181991Sheppo " lastmsg=%d, currentmsg=%d\n", 41191991Sheppo ldcp->id, msg->env&LDC_FRAG_MASK, 41201991Sheppo bytes_read, ldcp->last_msg_rcd, 41211991Sheppo msg->seqid); 41221991Sheppo 41231991Sheppo /* throw data we have read so far */ 41241991Sheppo bytes_read = 0; 41251991Sheppo target = target_bufp; 41262336Snarayan first_fragment = msg->seqid; 41271991Sheppo 41285944Sha137994 if (rv = ldcp->readq_set_head(ldcp, 41294690Snarayan curr_head)) 41301991Sheppo break; 41311991Sheppo } 41321991Sheppo } 41331991Sheppo 41341991Sheppo /* copy (next) pkt into buffer */ 41351991Sheppo if (len <= (*sizep - bytes_read)) { 41361991Sheppo bcopy(msgbuf, target, len); 41371991Sheppo target += len; 41381991Sheppo bytes_read += len; 41391991Sheppo } else { 41401991Sheppo /* 41411991Sheppo * there is not enough space in the buffer to 41421991Sheppo * read this pkt. throw message away & continue 41431991Sheppo * reading data from queue 41441991Sheppo */ 41451991Sheppo DWARN(DBG_ALL_LDCS, 41461991Sheppo "ldc_read: (0x%llx) buffer too small, " 41471991Sheppo "head=0x%lx, expect=%d, got=%d\n", ldcp->id, 41481991Sheppo curr_head, *sizep, bytes_read+len); 41491991Sheppo 41502336Snarayan first_fragment = 0; 41511991Sheppo target = target_bufp; 41521991Sheppo bytes_read = 0; 41531991Sheppo 41541991Sheppo /* throw away everything received so far */ 41555944Sha137994 if (rv = ldcp->readq_set_head(ldcp, curr_head)) 41561991Sheppo break; 41571991Sheppo 41581991Sheppo /* continue reading remaining pkts */ 41591991Sheppo continue; 41601991Sheppo } 41611991Sheppo } 41621991Sheppo 41631991Sheppo /* set the message id */ 41646408Sha137994 if (ldcp->mode != LDC_MODE_RELIABLE) 41655944Sha137994 ldcp->last_msg_rcd = msg->seqid; 41661991Sheppo 41671991Sheppo /* move the head one position */ 41681991Sheppo curr_head = (curr_head + LDC_PACKET_SIZE) & q_size_mask; 41691991Sheppo 41701991Sheppo if (msg->env & LDC_FRAG_STOP) { 41711991Sheppo 41721991Sheppo /* 41731991Sheppo * All pkts that are part of this fragmented transfer 41741991Sheppo * have been read or this was a single pkt read 41751991Sheppo * or there was an error 41761991Sheppo */ 41771991Sheppo 41781991Sheppo /* set the queue head */ 41795944Sha137994 if (rv = ldcp->readq_set_head(ldcp, curr_head)) 41801991Sheppo bytes_read = 0; 41811991Sheppo 41821991Sheppo *sizep = bytes_read; 41831991Sheppo 41841991Sheppo break; 41851991Sheppo } 41861991Sheppo 41874890Snarayan /* advance head if it is a CTRL packet or a DATA ACK packet */ 41884890Snarayan if ((msg->type & LDC_CTRL) || 41894890Snarayan ((msg->type & LDC_DATA) && (msg->stype & LDC_ACK))) { 41901991Sheppo 41911991Sheppo /* set the queue head */ 41925944Sha137994 if (rv = ldcp->readq_set_head(ldcp, curr_head)) { 41931991Sheppo bytes_read = 0; 41941991Sheppo break; 41951991Sheppo } 41961991Sheppo 41971991Sheppo D2(ldcp->id, "ldc_read: (0x%llx) set ACK qhead 0x%llx", 41981991Sheppo ldcp->id, curr_head); 41991991Sheppo } 42001991Sheppo 42011991Sheppo } /* for (;;) */ 42021991Sheppo 42031991Sheppo D2(ldcp->id, "ldc_read: (0x%llx) end size=%d", ldcp->id, *sizep); 42041991Sheppo 42051991Sheppo return (rv); 42062793Slm66018 42072793Slm66018 channel_is_reset: 42082793Slm66018 mutex_enter(&ldcp->tx_lock); 42092793Slm66018 i_ldc_reset(ldcp, B_FALSE); 42102793Slm66018 mutex_exit(&ldcp->tx_lock); 42112793Slm66018 return (ECONNRESET); 42121991Sheppo } 42131991Sheppo 42141991Sheppo /* 42156408Sha137994 * Fetch and buffer incoming packets so we can hand them back as 42161991Sheppo * a basic byte stream. 42171991Sheppo * 42181991Sheppo * Enter and exit with ldcp->lock held by caller 42191991Sheppo */ 42201991Sheppo static int 42211991Sheppo i_ldc_read_stream(ldc_chan_t *ldcp, caddr_t target_bufp, size_t *sizep) 42221991Sheppo { 42231991Sheppo int rv; 42241991Sheppo size_t size; 42251991Sheppo 42261991Sheppo ASSERT(mutex_owned(&ldcp->lock)); 42271991Sheppo 42281991Sheppo D2(ldcp->id, "i_ldc_read_stream: (0x%llx) buffer size=%d", 42294690Snarayan ldcp->id, *sizep); 42301991Sheppo 42311991Sheppo if (ldcp->stream_remains == 0) { 42321991Sheppo size = ldcp->mtu; 42331991Sheppo rv = i_ldc_read_packet(ldcp, 42344690Snarayan (caddr_t)ldcp->stream_bufferp, &size); 42351991Sheppo D2(ldcp->id, "i_ldc_read_stream: read packet (0x%llx) size=%d", 42364690Snarayan ldcp->id, size); 42371991Sheppo 42381991Sheppo if (rv != 0) 42391991Sheppo return (rv); 42401991Sheppo 42411991Sheppo ldcp->stream_remains = size; 42421991Sheppo ldcp->stream_offset = 0; 42431991Sheppo } 42441991Sheppo 42451991Sheppo size = MIN(ldcp->stream_remains, *sizep); 42461991Sheppo 42471991Sheppo bcopy(ldcp->stream_bufferp + ldcp->stream_offset, target_bufp, size); 42481991Sheppo ldcp->stream_offset += size; 42491991Sheppo ldcp->stream_remains -= size; 42501991Sheppo 42511991Sheppo D2(ldcp->id, "i_ldc_read_stream: (0x%llx) fill from buffer size=%d", 42524690Snarayan ldcp->id, size); 42531991Sheppo 42541991Sheppo *sizep = size; 42551991Sheppo return (0); 42561991Sheppo } 42571991Sheppo 42581991Sheppo /* 42591991Sheppo * Write specified amount of bytes to the channel 42601991Sheppo * in multiple pkts of pkt_payload size. Each 42611991Sheppo * packet is tagged with an unique packet ID in 42622410Slm66018 * the case of a reliable link. 42631991Sheppo * 42641991Sheppo * On return, size contains the number of bytes written. 42651991Sheppo */ 42661991Sheppo int 42671991Sheppo ldc_write(ldc_handle_t handle, caddr_t buf, size_t *sizep) 42681991Sheppo { 42691991Sheppo ldc_chan_t *ldcp; 42701991Sheppo int rv = 0; 42711991Sheppo 42721991Sheppo if (handle == NULL) { 42731991Sheppo DWARN(DBG_ALL_LDCS, "ldc_write: invalid channel handle\n"); 42741991Sheppo return (EINVAL); 42751991Sheppo } 42761991Sheppo ldcp = (ldc_chan_t *)handle; 42771991Sheppo 42782336Snarayan /* check if writes can occur */ 42792336Snarayan if (!mutex_tryenter(&ldcp->tx_lock)) { 42802336Snarayan /* 42812336Snarayan * Could not get the lock - channel could 42822336Snarayan * be in the process of being unconfigured 42832336Snarayan * or reader has encountered an error 42842336Snarayan */ 42852336Snarayan return (EAGAIN); 42862336Snarayan } 42871991Sheppo 42881991Sheppo /* check if non-zero data to write */ 42891991Sheppo if (buf == NULL || sizep == NULL) { 42901991Sheppo DWARN(ldcp->id, "ldc_write: (0x%llx) invalid data write\n", 42911991Sheppo ldcp->id); 42922336Snarayan mutex_exit(&ldcp->tx_lock); 42931991Sheppo return (EINVAL); 42941991Sheppo } 42951991Sheppo 42961991Sheppo if (*sizep == 0) { 42971991Sheppo DWARN(ldcp->id, "ldc_write: (0x%llx) write size of zero\n", 42981991Sheppo ldcp->id); 42992336Snarayan mutex_exit(&ldcp->tx_lock); 43001991Sheppo return (0); 43011991Sheppo } 43021991Sheppo 43031991Sheppo /* Check if channel is UP for data exchange */ 43041991Sheppo if (ldcp->tstate != TS_UP) { 43051991Sheppo DWARN(ldcp->id, 43061991Sheppo "ldc_write: (0x%llx) channel is not in UP state\n", 43071991Sheppo ldcp->id); 43081991Sheppo *sizep = 0; 43091991Sheppo rv = ECONNRESET; 43101991Sheppo } else { 43111991Sheppo rv = ldcp->write_p(ldcp, buf, sizep); 43121991Sheppo } 43131991Sheppo 43142336Snarayan mutex_exit(&ldcp->tx_lock); 43151991Sheppo 43161991Sheppo return (rv); 43171991Sheppo } 43181991Sheppo 43191991Sheppo /* 43201991Sheppo * Write a raw packet to the channel 43211991Sheppo * On return, size contains the number of bytes written. 43221991Sheppo */ 43231991Sheppo static int 43241991Sheppo i_ldc_write_raw(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep) 43251991Sheppo { 43261991Sheppo ldc_msg_t *ldcmsg; 43271991Sheppo uint64_t tx_head, tx_tail, new_tail; 43281991Sheppo int rv = 0; 43291991Sheppo size_t size; 43301991Sheppo 43312336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 43321991Sheppo ASSERT(ldcp->mode == LDC_MODE_RAW); 43331991Sheppo 43341991Sheppo size = *sizep; 43351991Sheppo 43361991Sheppo /* 43371991Sheppo * Check to see if the packet size is less than or 43381991Sheppo * equal to packet size support in raw mode 43391991Sheppo */ 43401991Sheppo if (size > ldcp->pkt_payload) { 43411991Sheppo DWARN(ldcp->id, 43421991Sheppo "ldc_write: (0x%llx) invalid size (0x%llx) for RAW mode\n", 43431991Sheppo ldcp->id, *sizep); 43441991Sheppo *sizep = 0; 43451991Sheppo return (EMSGSIZE); 43461991Sheppo } 43471991Sheppo 43481991Sheppo /* get the qptrs for the tx queue */ 43491991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 43501991Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 43511991Sheppo if (rv != 0) { 43521991Sheppo cmn_err(CE_WARN, 43531991Sheppo "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id); 43541991Sheppo *sizep = 0; 43551991Sheppo return (EIO); 43561991Sheppo } 43571991Sheppo 43581991Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN || 43591991Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 43601991Sheppo DWARN(ldcp->id, 43611991Sheppo "ldc_write: (0x%llx) channel down/reset\n", ldcp->id); 43622336Snarayan 43631991Sheppo *sizep = 0; 43642336Snarayan if (mutex_tryenter(&ldcp->lock)) { 43652793Slm66018 i_ldc_reset(ldcp, B_FALSE); 43662336Snarayan mutex_exit(&ldcp->lock); 43672336Snarayan } else { 43682336Snarayan /* 43692336Snarayan * Release Tx lock, and then reacquire channel 43702336Snarayan * and Tx lock in correct order 43712336Snarayan */ 43722336Snarayan mutex_exit(&ldcp->tx_lock); 43732336Snarayan mutex_enter(&ldcp->lock); 43742336Snarayan mutex_enter(&ldcp->tx_lock); 43752793Slm66018 i_ldc_reset(ldcp, B_FALSE); 43762336Snarayan mutex_exit(&ldcp->lock); 43772336Snarayan } 43781991Sheppo return (ECONNRESET); 43791991Sheppo } 43801991Sheppo 43811991Sheppo tx_tail = ldcp->tx_tail; 43821991Sheppo tx_head = ldcp->tx_head; 43831991Sheppo new_tail = (tx_tail + LDC_PACKET_SIZE) & 43844690Snarayan ((ldcp->tx_q_entries-1) << LDC_PACKET_SHIFT); 43851991Sheppo 43861991Sheppo if (new_tail == tx_head) { 43871991Sheppo DWARN(DBG_ALL_LDCS, 43881991Sheppo "ldc_write: (0x%llx) TX queue is full\n", ldcp->id); 43891991Sheppo *sizep = 0; 43901991Sheppo return (EWOULDBLOCK); 43911991Sheppo } 43921991Sheppo 43931991Sheppo D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d", 43941991Sheppo ldcp->id, size); 43951991Sheppo 43961991Sheppo /* Send the data now */ 43971991Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 43981991Sheppo 43992336Snarayan /* copy the data into pkt */ 44001991Sheppo bcopy((uint8_t *)buf, ldcmsg, size); 44011991Sheppo 44022336Snarayan /* increment tail */ 44031991Sheppo tx_tail = new_tail; 44041991Sheppo 44051991Sheppo /* 44061991Sheppo * All packets have been copied into the TX queue 44071991Sheppo * update the tail ptr in the HV 44081991Sheppo */ 44091991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 44101991Sheppo if (rv) { 44111991Sheppo if (rv == EWOULDBLOCK) { 44121991Sheppo DWARN(ldcp->id, "ldc_write: (0x%llx) write timed out\n", 44131991Sheppo ldcp->id); 44141991Sheppo *sizep = 0; 44151991Sheppo return (EWOULDBLOCK); 44161991Sheppo } 44171991Sheppo 44181991Sheppo *sizep = 0; 44192336Snarayan if (mutex_tryenter(&ldcp->lock)) { 44202793Slm66018 i_ldc_reset(ldcp, B_FALSE); 44212336Snarayan mutex_exit(&ldcp->lock); 44222336Snarayan } else { 44232336Snarayan /* 44242336Snarayan * Release Tx lock, and then reacquire channel 44252336Snarayan * and Tx lock in correct order 44262336Snarayan */ 44272336Snarayan mutex_exit(&ldcp->tx_lock); 44282336Snarayan mutex_enter(&ldcp->lock); 44292336Snarayan mutex_enter(&ldcp->tx_lock); 44302793Slm66018 i_ldc_reset(ldcp, B_FALSE); 44312336Snarayan mutex_exit(&ldcp->lock); 44322336Snarayan } 44331991Sheppo return (ECONNRESET); 44341991Sheppo } 44351991Sheppo 44361991Sheppo ldcp->tx_tail = tx_tail; 44371991Sheppo *sizep = size; 44381991Sheppo 44391991Sheppo D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, size); 44401991Sheppo 44411991Sheppo return (rv); 44421991Sheppo } 44431991Sheppo 44441991Sheppo 44451991Sheppo /* 44461991Sheppo * Write specified amount of bytes to the channel 44471991Sheppo * in multiple pkts of pkt_payload size. Each 44481991Sheppo * packet is tagged with an unique packet ID in 44492410Slm66018 * the case of a reliable link. 44501991Sheppo * 44511991Sheppo * On return, size contains the number of bytes written. 44521991Sheppo * This function needs to ensure that the write size is < MTU size 44531991Sheppo */ 44541991Sheppo static int 44551991Sheppo i_ldc_write_packet(ldc_chan_t *ldcp, caddr_t buf, size_t *size) 44561991Sheppo { 44571991Sheppo ldc_msg_t *ldcmsg; 44581991Sheppo uint64_t tx_head, tx_tail, new_tail, start; 44591991Sheppo uint64_t txq_size_mask, numavail; 44601991Sheppo uint8_t *msgbuf, *source = (uint8_t *)buf; 44611991Sheppo size_t len, bytes_written = 0, remaining; 44621991Sheppo int rv; 44631991Sheppo uint32_t curr_seqid; 44641991Sheppo 44652336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 44661991Sheppo 44671991Sheppo ASSERT(ldcp->mode == LDC_MODE_RELIABLE || 44686408Sha137994 ldcp->mode == LDC_MODE_UNRELIABLE); 44691991Sheppo 44701991Sheppo /* compute mask for increment */ 44711991Sheppo txq_size_mask = (ldcp->tx_q_entries - 1) << LDC_PACKET_SHIFT; 44721991Sheppo 44731991Sheppo /* get the qptrs for the tx queue */ 44741991Sheppo rv = hv_ldc_tx_get_state(ldcp->id, 44751991Sheppo &ldcp->tx_head, &ldcp->tx_tail, &ldcp->link_state); 44761991Sheppo if (rv != 0) { 44771991Sheppo cmn_err(CE_WARN, 44781991Sheppo "ldc_write: (0x%lx) cannot read queue ptrs\n", ldcp->id); 44791991Sheppo *size = 0; 44801991Sheppo return (EIO); 44811991Sheppo } 44821991Sheppo 44831991Sheppo if (ldcp->link_state == LDC_CHANNEL_DOWN || 44841991Sheppo ldcp->link_state == LDC_CHANNEL_RESET) { 44851991Sheppo DWARN(ldcp->id, 44861991Sheppo "ldc_write: (0x%llx) channel down/reset\n", ldcp->id); 44871991Sheppo *size = 0; 44882336Snarayan if (mutex_tryenter(&ldcp->lock)) { 44892793Slm66018 i_ldc_reset(ldcp, B_FALSE); 44902336Snarayan mutex_exit(&ldcp->lock); 44912336Snarayan } else { 44922336Snarayan /* 44932336Snarayan * Release Tx lock, and then reacquire channel 44942336Snarayan * and Tx lock in correct order 44952336Snarayan */ 44962336Snarayan mutex_exit(&ldcp->tx_lock); 44972336Snarayan mutex_enter(&ldcp->lock); 44982336Snarayan mutex_enter(&ldcp->tx_lock); 44992793Slm66018 i_ldc_reset(ldcp, B_FALSE); 45002336Snarayan mutex_exit(&ldcp->lock); 45012336Snarayan } 45021991Sheppo return (ECONNRESET); 45031991Sheppo } 45041991Sheppo 45051991Sheppo tx_tail = ldcp->tx_tail; 45061991Sheppo new_tail = (tx_tail + LDC_PACKET_SIZE) % 45074690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT); 45081991Sheppo 45091991Sheppo /* 45104690Snarayan * Check to see if the queue is full. The check is done using 45114690Snarayan * the appropriate head based on the link mode. 45121991Sheppo */ 45134690Snarayan i_ldc_get_tx_head(ldcp, &tx_head); 45144690Snarayan 45151991Sheppo if (new_tail == tx_head) { 45161991Sheppo DWARN(DBG_ALL_LDCS, 45171991Sheppo "ldc_write: (0x%llx) TX queue is full\n", ldcp->id); 45181991Sheppo *size = 0; 45191991Sheppo return (EWOULDBLOCK); 45201991Sheppo } 45211991Sheppo 45221991Sheppo /* 45231991Sheppo * Make sure that the LDC Tx queue has enough space 45241991Sheppo */ 45251991Sheppo numavail = (tx_head >> LDC_PACKET_SHIFT) - (tx_tail >> LDC_PACKET_SHIFT) 45264690Snarayan + ldcp->tx_q_entries - 1; 45271991Sheppo numavail %= ldcp->tx_q_entries; 45281991Sheppo 45291991Sheppo if (*size > (numavail * ldcp->pkt_payload)) { 45301991Sheppo DWARN(DBG_ALL_LDCS, 45311991Sheppo "ldc_write: (0x%llx) TX queue has no space\n", ldcp->id); 45321991Sheppo return (EWOULDBLOCK); 45331991Sheppo } 45341991Sheppo 45351991Sheppo D2(ldcp->id, "ldc_write: (0x%llx) start xfer size=%d", 45361991Sheppo ldcp->id, *size); 45371991Sheppo 45381991Sheppo /* Send the data now */ 45391991Sheppo bytes_written = 0; 45401991Sheppo curr_seqid = ldcp->last_msg_snt; 45411991Sheppo start = tx_tail; 45421991Sheppo 45431991Sheppo while (*size > bytes_written) { 45441991Sheppo 45451991Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + tx_tail); 45461991Sheppo 45476408Sha137994 msgbuf = (uint8_t *)((ldcp->mode == LDC_MODE_RELIABLE) ? 45484690Snarayan ldcmsg->rdata : ldcmsg->udata); 45491991Sheppo 45501991Sheppo ldcmsg->type = LDC_DATA; 45511991Sheppo ldcmsg->stype = LDC_INFO; 45521991Sheppo ldcmsg->ctrl = 0; 45531991Sheppo 45541991Sheppo remaining = *size - bytes_written; 45551991Sheppo len = min(ldcp->pkt_payload, remaining); 45561991Sheppo ldcmsg->env = (uint8_t)len; 45571991Sheppo 45581991Sheppo curr_seqid++; 45591991Sheppo ldcmsg->seqid = curr_seqid; 45601991Sheppo 45611991Sheppo /* copy the data into pkt */ 45621991Sheppo bcopy(source, msgbuf, len); 45631991Sheppo 45641991Sheppo source += len; 45651991Sheppo bytes_written += len; 45661991Sheppo 45671991Sheppo /* increment tail */ 45681991Sheppo tx_tail = (tx_tail + LDC_PACKET_SIZE) & txq_size_mask; 45691991Sheppo 45701991Sheppo ASSERT(tx_tail != tx_head); 45711991Sheppo } 45721991Sheppo 45731991Sheppo /* Set the start and stop bits */ 45741991Sheppo ldcmsg->env |= LDC_FRAG_STOP; 45751991Sheppo ldcmsg = (ldc_msg_t *)(ldcp->tx_q_va + start); 45761991Sheppo ldcmsg->env |= LDC_FRAG_START; 45771991Sheppo 45781991Sheppo /* 45791991Sheppo * All packets have been copied into the TX queue 45801991Sheppo * update the tail ptr in the HV 45811991Sheppo */ 45821991Sheppo rv = i_ldc_set_tx_tail(ldcp, tx_tail); 45831991Sheppo if (rv == 0) { 45841991Sheppo ldcp->tx_tail = tx_tail; 45851991Sheppo ldcp->last_msg_snt = curr_seqid; 45861991Sheppo *size = bytes_written; 45871991Sheppo } else { 45881991Sheppo int rv2; 45891991Sheppo 45901991Sheppo if (rv != EWOULDBLOCK) { 45911991Sheppo *size = 0; 45922336Snarayan if (mutex_tryenter(&ldcp->lock)) { 45932793Slm66018 i_ldc_reset(ldcp, B_FALSE); 45942336Snarayan mutex_exit(&ldcp->lock); 45952336Snarayan } else { 45962336Snarayan /* 45972336Snarayan * Release Tx lock, and then reacquire channel 45982336Snarayan * and Tx lock in correct order 45992336Snarayan */ 46002336Snarayan mutex_exit(&ldcp->tx_lock); 46012336Snarayan mutex_enter(&ldcp->lock); 46022336Snarayan mutex_enter(&ldcp->tx_lock); 46032793Slm66018 i_ldc_reset(ldcp, B_FALSE); 46042336Snarayan mutex_exit(&ldcp->lock); 46052336Snarayan } 46061991Sheppo return (ECONNRESET); 46071991Sheppo } 46081991Sheppo 46093010Slm66018 D1(ldcp->id, "hv_tx_set_tail returns 0x%x (head 0x%x, " 46104690Snarayan "old tail 0x%x, new tail 0x%x, qsize=0x%x)\n", 46114690Snarayan rv, ldcp->tx_head, ldcp->tx_tail, tx_tail, 46124690Snarayan (ldcp->tx_q_entries << LDC_PACKET_SHIFT)); 46131991Sheppo 46141991Sheppo rv2 = hv_ldc_tx_get_state(ldcp->id, 46151991Sheppo &tx_head, &tx_tail, &ldcp->link_state); 46161991Sheppo 46173010Slm66018 D1(ldcp->id, "hv_ldc_tx_get_state returns 0x%x " 46184690Snarayan "(head 0x%x, tail 0x%x state 0x%x)\n", 46194690Snarayan rv2, tx_head, tx_tail, ldcp->link_state); 46201991Sheppo 46211991Sheppo *size = 0; 46221991Sheppo } 46231991Sheppo 46241991Sheppo D2(ldcp->id, "ldc_write: (0x%llx) end xfer size=%d", ldcp->id, *size); 46251991Sheppo 46261991Sheppo return (rv); 46271991Sheppo } 46281991Sheppo 46291991Sheppo /* 46301991Sheppo * Write specified amount of bytes to the channel 46311991Sheppo * in multiple pkts of pkt_payload size. Each 46321991Sheppo * packet is tagged with an unique packet ID in 46332410Slm66018 * the case of a reliable link. 46341991Sheppo * 46351991Sheppo * On return, size contains the number of bytes written. 46361991Sheppo * This function needs to ensure that the write size is < MTU size 46371991Sheppo */ 46381991Sheppo static int 46391991Sheppo i_ldc_write_stream(ldc_chan_t *ldcp, caddr_t buf, size_t *sizep) 46401991Sheppo { 46412336Snarayan ASSERT(MUTEX_HELD(&ldcp->tx_lock)); 46426408Sha137994 ASSERT(ldcp->mode == LDC_MODE_RELIABLE); 46431991Sheppo 46441991Sheppo /* Truncate packet to max of MTU size */ 46451991Sheppo if (*sizep > ldcp->mtu) *sizep = ldcp->mtu; 46461991Sheppo return (i_ldc_write_packet(ldcp, buf, sizep)); 46471991Sheppo } 46481991Sheppo 46491991Sheppo 46501991Sheppo /* 46511991Sheppo * Interfaces for channel nexus to register/unregister with LDC module 46521991Sheppo * The nexus will register functions to be used to register individual 46531991Sheppo * channels with the nexus and enable interrupts for the channels 46541991Sheppo */ 46551991Sheppo int 46561991Sheppo ldc_register(ldc_cnex_t *cinfo) 46571991Sheppo { 46581991Sheppo ldc_chan_t *ldcp; 46591991Sheppo 46601991Sheppo if (cinfo == NULL || cinfo->dip == NULL || 46611991Sheppo cinfo->reg_chan == NULL || cinfo->unreg_chan == NULL || 46621991Sheppo cinfo->add_intr == NULL || cinfo->rem_intr == NULL || 46631991Sheppo cinfo->clr_intr == NULL) { 46641991Sheppo 46651991Sheppo DWARN(DBG_ALL_LDCS, "ldc_register: invalid nexus info\n"); 46661991Sheppo return (EINVAL); 46671991Sheppo } 46681991Sheppo 46691991Sheppo mutex_enter(&ldcssp->lock); 46701991Sheppo 46711991Sheppo /* nexus registration */ 46721991Sheppo ldcssp->cinfo.dip = cinfo->dip; 46731991Sheppo ldcssp->cinfo.reg_chan = cinfo->reg_chan; 46741991Sheppo ldcssp->cinfo.unreg_chan = cinfo->unreg_chan; 46751991Sheppo ldcssp->cinfo.add_intr = cinfo->add_intr; 46761991Sheppo ldcssp->cinfo.rem_intr = cinfo->rem_intr; 46771991Sheppo ldcssp->cinfo.clr_intr = cinfo->clr_intr; 46781991Sheppo 46791991Sheppo /* register any channels that might have been previously initialized */ 46801991Sheppo ldcp = ldcssp->chan_list; 46811991Sheppo while (ldcp) { 46821991Sheppo if ((ldcp->tstate & TS_QCONF_RDY) && 46831991Sheppo (ldcp->tstate & TS_CNEX_RDY) == 0) 46841991Sheppo (void) i_ldc_register_channel(ldcp); 46851991Sheppo 46861991Sheppo ldcp = ldcp->next; 46871991Sheppo } 46881991Sheppo 46891991Sheppo mutex_exit(&ldcssp->lock); 46901991Sheppo 46911991Sheppo return (0); 46921991Sheppo } 46931991Sheppo 46941991Sheppo int 46951991Sheppo ldc_unregister(ldc_cnex_t *cinfo) 46961991Sheppo { 46971991Sheppo if (cinfo == NULL || cinfo->dip == NULL) { 46981991Sheppo DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid nexus info\n"); 46991991Sheppo return (EINVAL); 47001991Sheppo } 47011991Sheppo 47021991Sheppo mutex_enter(&ldcssp->lock); 47031991Sheppo 47041991Sheppo if (cinfo->dip != ldcssp->cinfo.dip) { 47051991Sheppo DWARN(DBG_ALL_LDCS, "ldc_unregister: invalid dip\n"); 47061991Sheppo mutex_exit(&ldcssp->lock); 47071991Sheppo return (EINVAL); 47081991Sheppo } 47091991Sheppo 47101991Sheppo /* nexus unregister */ 47111991Sheppo ldcssp->cinfo.dip = NULL; 47121991Sheppo ldcssp->cinfo.reg_chan = NULL; 47131991Sheppo ldcssp->cinfo.unreg_chan = NULL; 47141991Sheppo ldcssp->cinfo.add_intr = NULL; 47151991Sheppo ldcssp->cinfo.rem_intr = NULL; 47161991Sheppo ldcssp->cinfo.clr_intr = NULL; 47171991Sheppo 47181991Sheppo mutex_exit(&ldcssp->lock); 47191991Sheppo 47201991Sheppo return (0); 47211991Sheppo } 4722