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 /* 233653Snarayan * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 241991Sheppo * Use is subject to license terms. 251991Sheppo */ 261991Sheppo 271991Sheppo #pragma ident "%Z%%M% %I% %E% SMI" 281991Sheppo 291991Sheppo #include <sys/types.h> 301991Sheppo #include <sys/errno.h> 311991Sheppo #include <sys/param.h> 321991Sheppo #include <sys/stream.h> 334647Sraghuram #include <sys/strsubr.h> 341991Sheppo #include <sys/kmem.h> 351991Sheppo #include <sys/conf.h> 361991Sheppo #include <sys/devops.h> 371991Sheppo #include <sys/ksynch.h> 381991Sheppo #include <sys/stat.h> 391991Sheppo #include <sys/modctl.h> 401991Sheppo #include <sys/debug.h> 411991Sheppo #include <sys/ethernet.h> 421991Sheppo #include <sys/ddi.h> 431991Sheppo #include <sys/sunddi.h> 441991Sheppo #include <sys/strsun.h> 451991Sheppo #include <sys/note.h> 461991Sheppo #include <sys/mac.h> 472311Sseb #include <sys/mac_ether.h> 481991Sheppo #include <sys/ldc.h> 491991Sheppo #include <sys/mach_descrip.h> 501991Sheppo #include <sys/mdeg.h> 514647Sraghuram #include <net/if.h> 524647Sraghuram #include <sys/vnet.h> 531991Sheppo #include <sys/vio_mailbox.h> 541991Sheppo #include <sys/vio_common.h> 551991Sheppo #include <sys/vnet_common.h> 562336Snarayan #include <sys/vnet_mailbox.h> 572336Snarayan #include <sys/vio_util.h> 581991Sheppo #include <sys/vnet_gen.h> 594647Sraghuram #include <sys/callb.h> 604647Sraghuram #include <sys/sdt.h> 614647Sraghuram #include <sys/intr.h> 624647Sraghuram #include <sys/pattr.h> 631991Sheppo 641991Sheppo /* 651991Sheppo * Implementation of the mac functionality for vnet using the 661991Sheppo * generic(default) transport layer of sun4v Logical Domain Channels(LDC). 671991Sheppo */ 681991Sheppo 691991Sheppo /* 701991Sheppo * Function prototypes. 711991Sheppo */ 721991Sheppo /* vgen proxy entry points */ 732311Sseb int vgen_init(void *vnetp, dev_info_t *vnetdip, const uint8_t *macaddr, 742311Sseb mac_register_t **vgenmacp); 752336Snarayan int vgen_uninit(void *arg); 761991Sheppo static int vgen_start(void *arg); 771991Sheppo static void vgen_stop(void *arg); 781991Sheppo static mblk_t *vgen_tx(void *arg, mblk_t *mp); 791991Sheppo static int vgen_multicst(void *arg, boolean_t add, 801991Sheppo const uint8_t *mca); 811991Sheppo static int vgen_promisc(void *arg, boolean_t on); 821991Sheppo static int vgen_unicst(void *arg, const uint8_t *mca); 832311Sseb static int vgen_stat(void *arg, uint_t stat, uint64_t *val); 841991Sheppo static void vgen_ioctl(void *arg, queue_t *wq, mblk_t *mp); 851991Sheppo 861991Sheppo /* externs - functions provided by vnet to add/remove/modify entries in fdb */ 871991Sheppo void vnet_add_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg); 881991Sheppo void vnet_del_fdb(void *arg, uint8_t *macaddr); 892793Slm66018 void vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, 902793Slm66018 void *txarg, boolean_t upgrade); 911991Sheppo void vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg); 921991Sheppo void vnet_del_def_rte(void *arg); 932311Sseb void vnet_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp); 942311Sseb void vnet_tx_update(void *arg); 951991Sheppo 961991Sheppo /* vgen internal functions */ 971991Sheppo static void vgen_detach_ports(vgen_t *vgenp); 981991Sheppo static void vgen_port_detach(vgen_port_t *portp); 991991Sheppo static void vgen_port_list_insert(vgen_port_t *portp); 1001991Sheppo static void vgen_port_list_remove(vgen_port_t *portp); 1011991Sheppo static vgen_port_t *vgen_port_lookup(vgen_portlist_t *plistp, 1021991Sheppo int port_num); 1031991Sheppo static int vgen_mdeg_reg(vgen_t *vgenp); 1041991Sheppo static void vgen_mdeg_unreg(vgen_t *vgenp); 1051991Sheppo static int vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp); 1061991Sheppo static int vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex); 1071991Sheppo static int vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex); 1081991Sheppo static int vgen_port_attach_mdeg(vgen_t *vgenp, int port_num, uint64_t *ldcids, 1091991Sheppo int num_ids, struct ether_addr *macaddr, boolean_t vsw_port); 1101991Sheppo static void vgen_port_detach_mdeg(vgen_port_t *portp); 1111991Sheppo static int vgen_update_port(vgen_t *vgenp, md_t *curr_mdp, 1121991Sheppo mde_cookie_t curr_mdex, md_t *prev_mdp, mde_cookie_t prev_mdex); 1132311Sseb static uint64_t vgen_port_stat(vgen_port_t *portp, uint_t stat); 1141991Sheppo 1151991Sheppo static int vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id); 1161991Sheppo static void vgen_ldc_detach(vgen_ldc_t *ldcp); 1171991Sheppo static int vgen_alloc_tx_ring(vgen_ldc_t *ldcp); 1181991Sheppo static void vgen_free_tx_ring(vgen_ldc_t *ldcp); 1191991Sheppo static void vgen_init_ports(vgen_t *vgenp); 1201991Sheppo static void vgen_port_init(vgen_port_t *portp); 1211991Sheppo static void vgen_uninit_ports(vgen_t *vgenp); 1221991Sheppo static void vgen_port_uninit(vgen_port_t *portp); 1231991Sheppo static void vgen_init_ldcs(vgen_port_t *portp); 1241991Sheppo static void vgen_uninit_ldcs(vgen_port_t *portp); 1251991Sheppo static int vgen_ldc_init(vgen_ldc_t *ldcp); 1261991Sheppo static void vgen_ldc_uninit(vgen_ldc_t *ldcp); 1271991Sheppo static int vgen_init_tbufs(vgen_ldc_t *ldcp); 1281991Sheppo static void vgen_uninit_tbufs(vgen_ldc_t *ldcp); 1291991Sheppo static void vgen_clobber_tbufs(vgen_ldc_t *ldcp); 1301991Sheppo static void vgen_clobber_rxds(vgen_ldc_t *ldcp); 1312311Sseb static uint64_t vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat); 1321991Sheppo static uint_t vgen_ldc_cb(uint64_t event, caddr_t arg); 1331991Sheppo static int vgen_portsend(vgen_port_t *portp, mblk_t *mp); 1341991Sheppo static int vgen_ldcsend(vgen_ldc_t *ldcp, mblk_t *mp); 1351991Sheppo static void vgen_reclaim(vgen_ldc_t *ldcp); 1361991Sheppo static void vgen_reclaim_dring(vgen_ldc_t *ldcp); 1371991Sheppo static int vgen_num_txpending(vgen_ldc_t *ldcp); 1381991Sheppo static int vgen_tx_dring_full(vgen_ldc_t *ldcp); 1391991Sheppo static int vgen_ldc_txtimeout(vgen_ldc_t *ldcp); 1401991Sheppo static void vgen_ldc_watchdog(void *arg); 1411991Sheppo static int vgen_setup_kstats(vgen_ldc_t *ldcp); 1421991Sheppo static void vgen_destroy_kstats(vgen_ldc_t *ldcp); 1431991Sheppo static int vgen_kstat_update(kstat_t *ksp, int rw); 1441991Sheppo 1451991Sheppo /* vgen handshake functions */ 1461991Sheppo static vgen_ldc_t *vh_nextphase(vgen_ldc_t *ldcp); 1471991Sheppo static int vgen_supported_version(vgen_ldc_t *ldcp, uint16_t ver_major, 1481991Sheppo uint16_t ver_minor); 1491991Sheppo static int vgen_next_version(vgen_ldc_t *ldcp, vgen_ver_t *verp); 1501991Sheppo static int vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg, size_t msglen, 1511991Sheppo boolean_t caller_holds_lock); 1521991Sheppo static int vgen_send_version_negotiate(vgen_ldc_t *ldcp); 1531991Sheppo static int vgen_send_attr_info(vgen_ldc_t *ldcp); 1541991Sheppo static int vgen_send_dring_reg(vgen_ldc_t *ldcp); 1551991Sheppo static int vgen_send_rdx_info(vgen_ldc_t *ldcp); 1562336Snarayan static int vgen_send_dring_data(vgen_ldc_t *ldcp, uint32_t start, int32_t end); 1571991Sheppo static int vgen_send_mcast_info(vgen_ldc_t *ldcp); 1581991Sheppo static int vgen_handshake_phase2(vgen_ldc_t *ldcp); 1591991Sheppo static void vgen_handshake_reset(vgen_ldc_t *ldcp); 1601991Sheppo static void vgen_reset_hphase(vgen_ldc_t *ldcp); 1611991Sheppo static void vgen_handshake(vgen_ldc_t *ldcp); 1621991Sheppo static int vgen_handshake_done(vgen_ldc_t *ldcp); 1631991Sheppo static void vgen_handshake_retry(vgen_ldc_t *ldcp); 1642793Slm66018 static int vgen_handle_version_negotiate(vgen_ldc_t *ldcp, 1651991Sheppo vio_msg_tag_t *tagp); 1662793Slm66018 static int vgen_handle_attr_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1672793Slm66018 static int vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1682793Slm66018 static int vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1692793Slm66018 static int vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1702793Slm66018 static int vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1714647Sraghuram static int vgen_handle_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1724647Sraghuram static int vgen_handle_dring_data_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1734647Sraghuram static int vgen_process_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1744647Sraghuram static int vgen_handle_dring_data_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1754647Sraghuram static int vgen_handle_dring_data_nack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1762793Slm66018 static int vgen_send_dring_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, 1772336Snarayan uint32_t start, int32_t end, uint8_t pstate); 1784647Sraghuram static int vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1791991Sheppo static void vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1802793Slm66018 static void vgen_handle_evt_up(vgen_ldc_t *ldcp, boolean_t flag); 1812793Slm66018 static void vgen_handle_evt_reset(vgen_ldc_t *ldcp, boolean_t flag); 1821991Sheppo static int vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1831991Sheppo static uint64_t vgen_macaddr_strtoul(const uint8_t *macaddr); 1841991Sheppo static int vgen_macaddr_ultostr(uint64_t value, uint8_t *macaddr); 1851991Sheppo static caddr_t vgen_print_ethaddr(uint8_t *a, char *ebuf); 1861991Sheppo static void vgen_hwatchdog(void *arg); 1871991Sheppo static void vgen_print_attr_info(vgen_ldc_t *ldcp, int endpoint); 1881991Sheppo static void vgen_print_hparams(vgen_hparams_t *hp); 1891991Sheppo static void vgen_print_ldcinfo(vgen_ldc_t *ldcp); 1904647Sraghuram static uint_t vgen_ldc_rcv_softintr(caddr_t arg1, caddr_t arg2); 1914647Sraghuram static void vgen_stop_rcv_thread(vgen_ldc_t *ldcp); 1924647Sraghuram static void vgen_ldc_rcv_worker(void *arg); 1934647Sraghuram static void vgen_handle_evt_read(vgen_ldc_t *ldcp); 1944647Sraghuram static void vgen_ldc_queue_data(vgen_ldc_t *ldcp, 1954647Sraghuram mblk_t *rhead, mblk_t *rtail); 1961991Sheppo 1971991Sheppo /* 1981991Sheppo * The handshake process consists of 5 phases defined below, with VH_PHASE0 1991991Sheppo * being the pre-handshake phase and VH_DONE is the phase to indicate 2001991Sheppo * successful completion of all phases. 2011991Sheppo * Each phase may have one to several handshake states which are required 2021991Sheppo * to complete successfully to move to the next phase. 2031991Sheppo * Refer to the functions vgen_handshake() and vgen_handshake_done() for 2041991Sheppo * more details. 2051991Sheppo */ 2061991Sheppo /* handshake phases */ 2071991Sheppo enum { VH_PHASE0, VH_PHASE1, VH_PHASE2, VH_PHASE3, VH_DONE = 0x80 }; 2081991Sheppo 2091991Sheppo /* handshake states */ 2101991Sheppo enum { 2111991Sheppo 2121991Sheppo VER_INFO_SENT = 0x1, 2131991Sheppo VER_ACK_RCVD = 0x2, 2141991Sheppo VER_INFO_RCVD = 0x4, 2151991Sheppo VER_ACK_SENT = 0x8, 2161991Sheppo VER_NEGOTIATED = (VER_ACK_RCVD | VER_ACK_SENT), 2171991Sheppo 2181991Sheppo ATTR_INFO_SENT = 0x10, 2191991Sheppo ATTR_ACK_RCVD = 0x20, 2201991Sheppo ATTR_INFO_RCVD = 0x40, 2211991Sheppo ATTR_ACK_SENT = 0x80, 2221991Sheppo ATTR_INFO_EXCHANGED = (ATTR_ACK_RCVD | ATTR_ACK_SENT), 2231991Sheppo 2241991Sheppo DRING_INFO_SENT = 0x100, 2251991Sheppo DRING_ACK_RCVD = 0x200, 2261991Sheppo DRING_INFO_RCVD = 0x400, 2271991Sheppo DRING_ACK_SENT = 0x800, 2281991Sheppo DRING_INFO_EXCHANGED = (DRING_ACK_RCVD | DRING_ACK_SENT), 2291991Sheppo 2301991Sheppo RDX_INFO_SENT = 0x1000, 2311991Sheppo RDX_ACK_RCVD = 0x2000, 2321991Sheppo RDX_INFO_RCVD = 0x4000, 2331991Sheppo RDX_ACK_SENT = 0x8000, 2341991Sheppo RDX_EXCHANGED = (RDX_ACK_RCVD | RDX_ACK_SENT) 2351991Sheppo 2361991Sheppo }; 2371991Sheppo 2381991Sheppo #define LDC_LOCK(ldcp) \ 2391991Sheppo mutex_enter(&((ldcp)->cblock));\ 2404647Sraghuram mutex_enter(&((ldcp)->rxlock));\ 2414647Sraghuram mutex_enter(&((ldcp)->wrlock));\ 2421991Sheppo mutex_enter(&((ldcp)->txlock));\ 2431991Sheppo mutex_enter(&((ldcp)->tclock)); 2441991Sheppo #define LDC_UNLOCK(ldcp) \ 2451991Sheppo mutex_exit(&((ldcp)->tclock));\ 2461991Sheppo mutex_exit(&((ldcp)->txlock));\ 2474647Sraghuram mutex_exit(&((ldcp)->wrlock));\ 2484647Sraghuram mutex_exit(&((ldcp)->rxlock));\ 2491991Sheppo mutex_exit(&((ldcp)->cblock)); 2501991Sheppo 2511991Sheppo static struct ether_addr etherbroadcastaddr = { 2521991Sheppo 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 2531991Sheppo }; 2541991Sheppo /* 2551991Sheppo * MIB II broadcast/multicast packets 2561991Sheppo */ 2571991Sheppo #define IS_BROADCAST(ehp) \ 2581991Sheppo (ether_cmp(&ehp->ether_dhost, ðerbroadcastaddr) == 0) 2591991Sheppo #define IS_MULTICAST(ehp) \ 2601991Sheppo ((ehp->ether_dhost.ether_addr_octet[0] & 01) == 1) 2611991Sheppo 2621991Sheppo /* 2631991Sheppo * Property names 2641991Sheppo */ 2651991Sheppo static char macaddr_propname[] = "mac-address"; 2661991Sheppo static char rmacaddr_propname[] = "remote-mac-address"; 2671991Sheppo static char channel_propname[] = "channel-endpoint"; 2681991Sheppo static char reg_propname[] = "reg"; 2691991Sheppo static char port_propname[] = "port"; 2701991Sheppo static char swport_propname[] = "switch-port"; 2711991Sheppo static char id_propname[] = "id"; 2721991Sheppo 2731991Sheppo /* versions supported - in decreasing order */ 2741991Sheppo static vgen_ver_t vgen_versions[VGEN_NUM_VER] = { {1, 0} }; 2751991Sheppo 2761991Sheppo /* Tunables */ 277*5171Ssb155480 uint32_t vgen_hwd_interval = 5; /* handshake watchdog freq in sec */ 2783297Ssb155480 uint32_t vgen_max_hretries = VNET_NUM_HANDSHAKES; /* # of handshake retries */ 2791991Sheppo uint32_t vgen_ldcwr_retries = 10; /* max # of ldc_write() retries */ 2802109Slm66018 uint32_t vgen_ldcup_retries = 5; /* max # of ldc_up() retries */ 2812336Snarayan uint32_t vgen_recv_delay = 1; /* delay when rx descr not ready */ 2822336Snarayan uint32_t vgen_recv_retries = 10; /* retry when rx descr not ready */ 2835022Sraghuram uint32_t vgen_tx_retries = 0x4; /* retry when tx descr not available */ 2845022Sraghuram uint32_t vgen_tx_delay = 0x30; /* delay when tx descr not available */ 2851991Sheppo 2864647Sraghuram int vgen_rcv_thread_enabled = 1; /* Enable Recieve thread */ 2874647Sraghuram 2884647Sraghuram /* 2894647Sraghuram * max # of packets accumulated prior to sending them up. It is best 2904647Sraghuram * to keep this at 60% of the number of recieve buffers. 2914647Sraghuram */ 2924647Sraghuram uint32_t vgen_chain_len = (VGEN_NRBUFS * 0.6); 2934647Sraghuram 2944647Sraghuram /* 2954647Sraghuram * Tunables for each receive buffer size and number of buffers for 2964647Sraghuram * each buffer size. 2974647Sraghuram */ 2984647Sraghuram uint32_t vgen_rbufsz1 = VGEN_DBLK_SZ_128; 2994647Sraghuram uint32_t vgen_rbufsz2 = VGEN_DBLK_SZ_256; 3004647Sraghuram uint32_t vgen_rbufsz3 = VGEN_DBLK_SZ_2048; 3014647Sraghuram 3024647Sraghuram uint32_t vgen_nrbufs1 = VGEN_NRBUFS; 3034647Sraghuram uint32_t vgen_nrbufs2 = VGEN_NRBUFS; 3044647Sraghuram uint32_t vgen_nrbufs3 = VGEN_NRBUFS; 3054647Sraghuram 3061991Sheppo #ifdef DEBUG 3071991Sheppo /* flags to simulate error conditions for debugging */ 3081991Sheppo int vgen_trigger_txtimeout = 0; 3091991Sheppo int vgen_trigger_rxlost = 0; 3101991Sheppo #endif 3111991Sheppo 3121991Sheppo /* MD update matching structure */ 3131991Sheppo static md_prop_match_t vport_prop_match[] = { 3141991Sheppo { MDET_PROP_VAL, "id" }, 3151991Sheppo { MDET_LIST_END, NULL } 3161991Sheppo }; 3171991Sheppo 3181991Sheppo static mdeg_node_match_t vport_match = { "virtual-device-port", 3191991Sheppo vport_prop_match }; 3201991Sheppo 3211991Sheppo /* template for matching a particular vnet instance */ 3221991Sheppo static mdeg_prop_spec_t vgen_prop_template[] = { 3231991Sheppo { MDET_PROP_STR, "name", "network" }, 3241991Sheppo { MDET_PROP_VAL, "cfg-handle", NULL }, 3251991Sheppo { MDET_LIST_END, NULL, NULL } 3261991Sheppo }; 3271991Sheppo 3281991Sheppo #define VGEN_SET_MDEG_PROP_INST(specp, val) (specp)[1].ps_val = (val) 3291991Sheppo 3301991Sheppo static int vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp); 3311991Sheppo 3322311Sseb static mac_callbacks_t vgen_m_callbacks = { 3332311Sseb 0, 3342311Sseb vgen_stat, 3352311Sseb vgen_start, 3362311Sseb vgen_stop, 3372311Sseb vgen_promisc, 3382311Sseb vgen_multicst, 3392311Sseb vgen_unicst, 3402311Sseb vgen_tx, 3412311Sseb NULL, 3422311Sseb NULL, 3432311Sseb NULL 3442311Sseb }; 3452311Sseb 3461991Sheppo /* externs */ 3474647Sraghuram extern pri_t maxclsyspri; 3484647Sraghuram extern proc_t p0; 3491991Sheppo extern uint32_t vnet_ntxds; 3501991Sheppo extern uint32_t vnet_ldcwd_interval; 3511991Sheppo extern uint32_t vnet_ldcwd_txtimeout; 3522410Slm66018 extern uint32_t vnet_ldc_mtu; 3532336Snarayan extern uint32_t vnet_nrbufs; 3544647Sraghuram 3551991Sheppo 3561991Sheppo #ifdef DEBUG 3571991Sheppo 3584647Sraghuram extern int vnet_dbglevel; 3594647Sraghuram static void debug_printf(const char *fname, vgen_t *vgenp, 3604647Sraghuram vgen_ldc_t *ldcp, const char *fmt, ...); 3614647Sraghuram 3624647Sraghuram /* -1 for all LDCs info, or ldc_id for a specific LDC info */ 3634647Sraghuram int vgendbg_ldcid = -1; 3641991Sheppo 3651991Sheppo /* simulate handshake error conditions for debug */ 3661991Sheppo uint32_t vgen_hdbg; 3671991Sheppo #define HDBG_VERSION 0x1 3681991Sheppo #define HDBG_TIMEOUT 0x2 3691991Sheppo #define HDBG_BAD_SID 0x4 3701991Sheppo #define HDBG_OUT_STATE 0x8 3711991Sheppo 3721991Sheppo #endif 3731991Sheppo 3742336Snarayan 3751991Sheppo 3761991Sheppo /* 3771991Sheppo * vgen_init() is called by an instance of vnet driver to initialize the 3781991Sheppo * corresponding generic proxy transport layer. The arguments passed by vnet 3791991Sheppo * are - an opaque pointer to the vnet instance, pointers to dev_info_t and 3802311Sseb * the mac address of the vnet device, and a pointer to mac_register_t of 3812311Sseb * the generic transport is returned in the last argument. 3821991Sheppo */ 3831991Sheppo int 3842311Sseb vgen_init(void *vnetp, dev_info_t *vnetdip, const uint8_t *macaddr, 3852311Sseb mac_register_t **vgenmacp) 3861991Sheppo { 3871991Sheppo vgen_t *vgenp; 3882311Sseb mac_register_t *macp; 3891991Sheppo int instance; 3901991Sheppo 3912311Sseb if ((vnetp == NULL) || (vnetdip == NULL)) 3921991Sheppo return (DDI_FAILURE); 3931991Sheppo 3941991Sheppo instance = ddi_get_instance(vnetdip); 3951991Sheppo 3964647Sraghuram DBG1(NULL, NULL, "vnet(%d):%s: enter\n", instance); 3971991Sheppo 3981991Sheppo vgenp = kmem_zalloc(sizeof (vgen_t), KM_SLEEP); 3991991Sheppo 4001991Sheppo vgenp->vnetp = vnetp; 4011991Sheppo vgenp->vnetdip = vnetdip; 4021991Sheppo bcopy(macaddr, &(vgenp->macaddr), ETHERADDRL); 4031991Sheppo 4042311Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 4052311Sseb KMEM_FREE(vgenp); 4062311Sseb return (DDI_FAILURE); 4072311Sseb } 4082311Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 4092311Sseb macp->m_driver = vgenp; 4102311Sseb macp->m_dip = vnetdip; 4112311Sseb macp->m_src_addr = (uint8_t *)&(vgenp->macaddr); 4122311Sseb macp->m_callbacks = &vgen_m_callbacks; 4132311Sseb macp->m_min_sdu = 0; 4142311Sseb macp->m_max_sdu = ETHERMTU; 4152311Sseb vgenp->macp = macp; 4162311Sseb 4171991Sheppo /* allocate multicast table */ 4181991Sheppo vgenp->mctab = kmem_zalloc(VGEN_INIT_MCTAB_SIZE * 4191991Sheppo sizeof (struct ether_addr), KM_SLEEP); 4201991Sheppo vgenp->mccount = 0; 4211991Sheppo vgenp->mcsize = VGEN_INIT_MCTAB_SIZE; 4221991Sheppo 4231991Sheppo mutex_init(&vgenp->lock, NULL, MUTEX_DRIVER, NULL); 4241991Sheppo 4251991Sheppo /* register with MD event generator */ 4261991Sheppo if (vgen_mdeg_reg(vgenp) != DDI_SUCCESS) { 4271991Sheppo mutex_destroy(&vgenp->lock); 4281991Sheppo kmem_free(vgenp->mctab, VGEN_INIT_MCTAB_SIZE * 4291991Sheppo sizeof (struct ether_addr)); 4302311Sseb mac_free(vgenp->macp); 4311991Sheppo KMEM_FREE(vgenp); 4321991Sheppo return (DDI_FAILURE); 4331991Sheppo } 4341991Sheppo 4352311Sseb /* register macp of this vgen_t with vnet */ 4362311Sseb *vgenmacp = vgenp->macp; 4371991Sheppo 4384647Sraghuram DBG1(NULL, NULL, "vnet(%d):%s: exit\n", instance); 4391991Sheppo return (DDI_SUCCESS); 4401991Sheppo } 4411991Sheppo 4421991Sheppo /* 4431991Sheppo * Called by vnet to undo the initializations done by vgen_init(). 4441991Sheppo * The handle provided by generic transport during vgen_init() is the argument. 4451991Sheppo */ 4462336Snarayan int 4471991Sheppo vgen_uninit(void *arg) 4481991Sheppo { 4491991Sheppo vgen_t *vgenp = (vgen_t *)arg; 4502336Snarayan vio_mblk_pool_t *rp, *nrp; 4512336Snarayan 4522336Snarayan if (vgenp == NULL) { 4532336Snarayan return (DDI_FAILURE); 4542336Snarayan } 4551991Sheppo 4564647Sraghuram DBG1(vgenp, NULL, "enter\n"); 4571991Sheppo 4581991Sheppo /* unregister with MD event generator */ 4591991Sheppo vgen_mdeg_unreg(vgenp); 4601991Sheppo 4611991Sheppo mutex_enter(&vgenp->lock); 4621991Sheppo 4631991Sheppo /* detach all ports from the device */ 4641991Sheppo vgen_detach_ports(vgenp); 4651991Sheppo 4662336Snarayan /* 4672336Snarayan * free any pending rx mblk pools, 4682336Snarayan * that couldn't be freed previously during channel detach. 4692336Snarayan */ 4702336Snarayan rp = vgenp->rmp; 4712336Snarayan while (rp != NULL) { 4722336Snarayan nrp = vgenp->rmp = rp->nextp; 4732336Snarayan if (vio_destroy_mblks(rp)) { 4742336Snarayan vgenp->rmp = rp; 4752336Snarayan mutex_exit(&vgenp->lock); 4762336Snarayan return (DDI_FAILURE); 4772336Snarayan } 4782336Snarayan rp = nrp; 4792336Snarayan } 4802336Snarayan 4811991Sheppo /* free multicast table */ 4821991Sheppo kmem_free(vgenp->mctab, vgenp->mcsize * sizeof (struct ether_addr)); 4831991Sheppo 4842311Sseb mac_free(vgenp->macp); 4852311Sseb 4861991Sheppo mutex_exit(&vgenp->lock); 4871991Sheppo 4881991Sheppo mutex_destroy(&vgenp->lock); 4891991Sheppo 4901991Sheppo KMEM_FREE(vgenp); 4911991Sheppo 4924647Sraghuram DBG1(vgenp, NULL, "exit\n"); 4932336Snarayan 4942336Snarayan return (DDI_SUCCESS); 4951991Sheppo } 4961991Sheppo 4971991Sheppo /* enable transmit/receive for the device */ 4982311Sseb int 4991991Sheppo vgen_start(void *arg) 5001991Sheppo { 5011991Sheppo vgen_t *vgenp = (vgen_t *)arg; 5021991Sheppo 5034647Sraghuram DBG1(vgenp, NULL, "enter\n"); 5041991Sheppo 5051991Sheppo mutex_enter(&vgenp->lock); 5061991Sheppo vgen_init_ports(vgenp); 5071991Sheppo vgenp->flags |= VGEN_STARTED; 5081991Sheppo mutex_exit(&vgenp->lock); 5091991Sheppo 5104647Sraghuram DBG1(vgenp, NULL, "exit\n"); 5111991Sheppo return (DDI_SUCCESS); 5121991Sheppo } 5131991Sheppo 5141991Sheppo /* stop transmit/receive */ 5152311Sseb void 5161991Sheppo vgen_stop(void *arg) 5171991Sheppo { 5181991Sheppo vgen_t *vgenp = (vgen_t *)arg; 5191991Sheppo 5204647Sraghuram DBG1(vgenp, NULL, "enter\n"); 5211991Sheppo 5221991Sheppo mutex_enter(&vgenp->lock); 5231991Sheppo vgen_uninit_ports(vgenp); 5241991Sheppo vgenp->flags &= ~(VGEN_STARTED); 5251991Sheppo mutex_exit(&vgenp->lock); 5261991Sheppo 5274647Sraghuram DBG1(vgenp, NULL, "exit\n"); 5281991Sheppo } 5291991Sheppo 5301991Sheppo /* vgen transmit function */ 5311991Sheppo static mblk_t * 5321991Sheppo vgen_tx(void *arg, mblk_t *mp) 5331991Sheppo { 5345022Sraghuram int i; 5351991Sheppo vgen_port_t *portp; 5365022Sraghuram int status = VGEN_FAILURE; 5371991Sheppo 5381991Sheppo portp = (vgen_port_t *)arg; 5395022Sraghuram /* 5405022Sraghuram * Retry so that we avoid reporting a failure 5415022Sraghuram * to the upper layer. Returning a failure may cause the 5425022Sraghuram * upper layer to go into single threaded mode there by 5435022Sraghuram * causing performance degradation, especially for a large 5445022Sraghuram * number of connections. 5455022Sraghuram */ 5465022Sraghuram for (i = 0; i < vgen_tx_retries; ) { 5475022Sraghuram status = vgen_portsend(portp, mp); 5485022Sraghuram if (status == VGEN_SUCCESS) { 5495022Sraghuram break; 5505022Sraghuram } 5515022Sraghuram if (++i < vgen_tx_retries) 5525022Sraghuram delay(drv_usectohz(vgen_tx_delay)); 5535022Sraghuram } 5541991Sheppo if (status != VGEN_SUCCESS) { 5551991Sheppo /* failure */ 5561991Sheppo return (mp); 5571991Sheppo } 5581991Sheppo /* success */ 5591991Sheppo return (NULL); 5601991Sheppo } 5611991Sheppo 5621991Sheppo /* transmit packets over the given port */ 5631991Sheppo static int 5641991Sheppo vgen_portsend(vgen_port_t *portp, mblk_t *mp) 5651991Sheppo { 5661991Sheppo vgen_ldclist_t *ldclp; 5671991Sheppo vgen_ldc_t *ldcp; 5681991Sheppo int status; 5695022Sraghuram int rv = VGEN_SUCCESS; 5701991Sheppo 5711991Sheppo ldclp = &portp->ldclist; 5721991Sheppo READ_ENTER(&ldclp->rwlock); 5731991Sheppo /* 5742336Snarayan * NOTE: for now, we will assume we have a single channel. 5751991Sheppo */ 5761991Sheppo if (ldclp->headp == NULL) { 5771991Sheppo RW_EXIT(&ldclp->rwlock); 5781991Sheppo return (VGEN_FAILURE); 5791991Sheppo } 5801991Sheppo ldcp = ldclp->headp; 5811991Sheppo 5821991Sheppo status = vgen_ldcsend(ldcp, mp); 5835022Sraghuram 5841991Sheppo RW_EXIT(&ldclp->rwlock); 5851991Sheppo 5865022Sraghuram if (status != VGEN_TX_SUCCESS) { 5875022Sraghuram rv = VGEN_FAILURE; 5885022Sraghuram } 5895022Sraghuram return (rv); 5901991Sheppo } 5911991Sheppo 5921991Sheppo /* channel transmit function */ 5931991Sheppo static int 5941991Sheppo vgen_ldcsend(vgen_ldc_t *ldcp, mblk_t *mp) 5951991Sheppo { 5961991Sheppo vgen_private_desc_t *tbufp; 5974647Sraghuram vgen_private_desc_t *rtbufp; 5984647Sraghuram vnet_public_desc_t *rtxdp; 5991991Sheppo vgen_private_desc_t *ntbufp; 6001991Sheppo vnet_public_desc_t *txdp; 6014647Sraghuram vio_dring_entry_hdr_t *hdrp; 6021991Sheppo vgen_stats_t *statsp; 6031991Sheppo struct ether_header *ehp; 6041991Sheppo boolean_t is_bcast = B_FALSE; 6051991Sheppo boolean_t is_mcast = B_FALSE; 6062336Snarayan size_t mblksz; 6072336Snarayan caddr_t dst; 6082336Snarayan mblk_t *bp; 6094647Sraghuram size_t size; 6104647Sraghuram int rv = 0; 6112793Slm66018 ldc_status_t istatus; 6124647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 6134647Sraghuram 6141991Sheppo statsp = ldcp->statsp; 6152109Slm66018 size = msgsize(mp); 6162109Slm66018 6174647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 6184647Sraghuram 6192109Slm66018 if (ldcp->ldc_status != LDC_UP) { 6204647Sraghuram DWARN(vgenp, ldcp, "status(%d), dropping packet\n", 6214647Sraghuram ldcp->ldc_status); 6222109Slm66018 /* retry ldc_up() if needed */ 6232109Slm66018 if (ldcp->flags & CHANNEL_STARTED) 6242109Slm66018 (void) ldc_up(ldcp->ldc_handle); 6252109Slm66018 goto vgen_tx_exit; 6261991Sheppo } 6271991Sheppo 6284647Sraghuram /* drop the packet if ldc is not up or handshake is not done */ 6292109Slm66018 if (ldcp->hphase != VH_DONE) { 6304647Sraghuram DWARN(vgenp, ldcp, "hphase(%x), dropping packet\n", 6314647Sraghuram ldcp->hphase); 6322109Slm66018 goto vgen_tx_exit; 6332109Slm66018 } 6342109Slm66018 6351991Sheppo if (size > (size_t)ETHERMAX) { 6364647Sraghuram DWARN(vgenp, ldcp, "invalid size(%d)\n", size); 6371991Sheppo goto vgen_tx_exit; 6381991Sheppo } 6394647Sraghuram if (size < ETHERMIN) 6404647Sraghuram size = ETHERMIN; 6414647Sraghuram 6424647Sraghuram ehp = (struct ether_header *)mp->b_rptr; 6434647Sraghuram is_bcast = IS_BROADCAST(ehp); 6444647Sraghuram is_mcast = IS_MULTICAST(ehp); 6454647Sraghuram 6464647Sraghuram mutex_enter(&ldcp->txlock); 6471991Sheppo /* 6481991Sheppo * allocate a descriptor 6491991Sheppo */ 6501991Sheppo tbufp = ldcp->next_tbufp; 6511991Sheppo ntbufp = NEXTTBUF(ldcp, tbufp); 6522336Snarayan if (ntbufp == ldcp->cur_tbufp) { /* out of tbufs/txds */ 6531991Sheppo 6541991Sheppo mutex_enter(&ldcp->tclock); 6554647Sraghuram /* Try reclaiming now */ 6564647Sraghuram vgen_reclaim_dring(ldcp); 6574647Sraghuram ldcp->reclaim_lbolt = ddi_get_lbolt(); 6584647Sraghuram 6592336Snarayan if (ntbufp == ldcp->cur_tbufp) { 6604647Sraghuram /* Now we are really out of tbuf/txds */ 6611991Sheppo ldcp->need_resched = B_TRUE; 6622336Snarayan mutex_exit(&ldcp->tclock); 6632336Snarayan 6642336Snarayan statsp->tx_no_desc++; 6652336Snarayan mutex_exit(&ldcp->txlock); 6662336Snarayan 6672336Snarayan return (VGEN_TX_NORESOURCES); 6682336Snarayan } 6691991Sheppo mutex_exit(&ldcp->tclock); 6701991Sheppo } 6714647Sraghuram /* update next available tbuf in the ring and update tx index */ 6724647Sraghuram ldcp->next_tbufp = ntbufp; 6734647Sraghuram INCR_TXI(ldcp->next_txi, ldcp); 6744647Sraghuram 6754647Sraghuram /* Mark the buffer busy before releasing the lock */ 6764647Sraghuram tbufp->flags = VGEN_PRIV_DESC_BUSY; 6774647Sraghuram mutex_exit(&ldcp->txlock); 6782109Slm66018 6792109Slm66018 /* copy data into pre-allocated transmit buffer */ 6802336Snarayan dst = tbufp->datap + VNET_IPALIGN; 6812336Snarayan for (bp = mp; bp != NULL; bp = bp->b_cont) { 6822336Snarayan mblksz = MBLKL(bp); 6832336Snarayan bcopy(bp->b_rptr, dst, mblksz); 6842336Snarayan dst += mblksz; 6851991Sheppo } 6861991Sheppo 6872109Slm66018 tbufp->datalen = size; 6881991Sheppo 6891991Sheppo /* initialize the corresponding public descriptor (txd) */ 6901991Sheppo txdp = tbufp->descp; 6911991Sheppo hdrp = &txdp->hdr; 6922109Slm66018 txdp->nbytes = size; 6932109Slm66018 txdp->ncookies = tbufp->ncookies; 6941991Sheppo bcopy((tbufp->memcookie), (txdp->memcookie), 6954650Sraghuram tbufp->ncookies * sizeof (ldc_mem_cookie_t)); 6964647Sraghuram 6974647Sraghuram mutex_enter(&ldcp->wrlock); 6984647Sraghuram /* 6994647Sraghuram * If the flags not set to BUSY, it implies that the clobber 7004647Sraghuram * was done while we were copying the data. In such case, 7014647Sraghuram * discard the packet and return. 7024647Sraghuram */ 7034647Sraghuram if (tbufp->flags != VGEN_PRIV_DESC_BUSY) { 7044647Sraghuram statsp->oerrors++; 7054647Sraghuram mutex_exit(&ldcp->wrlock); 7064647Sraghuram goto vgen_tx_exit; 7074647Sraghuram } 7082336Snarayan hdrp->dstate = VIO_DESC_READY; 7091991Sheppo 7101991Sheppo /* update stats */ 7111991Sheppo statsp->opackets++; 7122109Slm66018 statsp->obytes += size; 7131991Sheppo if (is_bcast) 7141991Sheppo statsp->brdcstxmt++; 7151991Sheppo else if (is_mcast) 7161991Sheppo statsp->multixmt++; 7171991Sheppo 7184647Sraghuram /* send dring datamsg to the peer */ 7194647Sraghuram if (ldcp->resched_peer) { 7204647Sraghuram 7214647Sraghuram rtbufp = &ldcp->tbufp[ldcp->resched_peer_txi]; 7224647Sraghuram rtxdp = rtbufp->descp; 7234647Sraghuram 7244647Sraghuram if (rtxdp->hdr.dstate == VIO_DESC_READY) { 7254647Sraghuram 7264647Sraghuram rv = vgen_send_dring_data(ldcp, 7274647Sraghuram (uint32_t)ldcp->resched_peer_txi, -1); 7284647Sraghuram if (rv != 0) { 7294647Sraghuram /* error: drop the packet */ 7304647Sraghuram DWARN(vgenp, ldcp, "vgen_send_dring_data " 7314650Sraghuram "failed: rv(%d) len(%d)\n", 7324650Sraghuram ldcp->ldc_id, rv, size); 7334647Sraghuram statsp->oerrors++; 7344647Sraghuram } else { 7354647Sraghuram ldcp->resched_peer = B_FALSE; 7364647Sraghuram } 7374647Sraghuram 7384647Sraghuram } 7394647Sraghuram 7404647Sraghuram } 7414647Sraghuram 7424647Sraghuram mutex_exit(&ldcp->wrlock); 7434647Sraghuram 7441991Sheppo vgen_tx_exit: 7452793Slm66018 if (rv == ECONNRESET) { 7462793Slm66018 /* 7472793Slm66018 * Check if either callback thread or another tx thread is 7482793Slm66018 * already running. Calling mutex_enter() will result in a 7492793Slm66018 * deadlock if the other thread already holds cblock and is 7502793Slm66018 * blocked in vnet_modify_fdb() (which is called from 7512793Slm66018 * vgen_handle_evt_reset()) waiting for write access on rwlock, 7522793Slm66018 * as this transmit thread already holds that lock as a reader 7532793Slm66018 * in vnet_m_tx(). See comments in vnet_modify_fdb() in vnet.c. 7542793Slm66018 */ 7552793Slm66018 if (mutex_tryenter(&ldcp->cblock)) { 7562793Slm66018 if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 7574647Sraghuram DWARN(vgenp, ldcp, "ldc_status() error\n"); 7582793Slm66018 } else { 7592793Slm66018 ldcp->ldc_status = istatus; 7602793Slm66018 } 7612793Slm66018 if (ldcp->ldc_status != LDC_UP) { 7622793Slm66018 /* 7632793Slm66018 * Second arg is TRUE, as we know that 7642793Slm66018 * the caller of this function - vnet_m_tx(), 7652793Slm66018 * already holds fdb-rwlock as a reader. 7662793Slm66018 */ 7672793Slm66018 vgen_handle_evt_reset(ldcp, B_TRUE); 7682793Slm66018 } 7692793Slm66018 mutex_exit(&ldcp->cblock); 7702793Slm66018 } 7712793Slm66018 } 7722109Slm66018 freemsg(mp); 7734647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 7742109Slm66018 return (VGEN_TX_SUCCESS); 7751991Sheppo } 7761991Sheppo 7771991Sheppo /* enable/disable a multicast address */ 7782311Sseb int 7791991Sheppo vgen_multicst(void *arg, boolean_t add, const uint8_t *mca) 7801991Sheppo { 7811991Sheppo vgen_t *vgenp; 7821991Sheppo vnet_mcast_msg_t mcastmsg; 7831991Sheppo vio_msg_tag_t *tagp; 7841991Sheppo vgen_port_t *portp; 7851991Sheppo vgen_portlist_t *plistp; 7861991Sheppo vgen_ldc_t *ldcp; 7871991Sheppo vgen_ldclist_t *ldclp; 7881991Sheppo struct ether_addr *addrp; 7893653Snarayan int rv = DDI_FAILURE; 7901991Sheppo uint32_t i; 7911991Sheppo 7921991Sheppo vgenp = (vgen_t *)arg; 7931991Sheppo addrp = (struct ether_addr *)mca; 7941991Sheppo tagp = &mcastmsg.tag; 7951991Sheppo bzero(&mcastmsg, sizeof (mcastmsg)); 7961991Sheppo 7971991Sheppo mutex_enter(&vgenp->lock); 7981991Sheppo 7991991Sheppo plistp = &(vgenp->vgenports); 8001991Sheppo 8011991Sheppo READ_ENTER(&plistp->rwlock); 8021991Sheppo 8031991Sheppo portp = vgenp->vsw_portp; 8041991Sheppo if (portp == NULL) { 8051991Sheppo RW_EXIT(&plistp->rwlock); 8063653Snarayan mutex_exit(&vgenp->lock); 8073653Snarayan return (rv); 8081991Sheppo } 8091991Sheppo ldclp = &portp->ldclist; 8101991Sheppo 8111991Sheppo READ_ENTER(&ldclp->rwlock); 8121991Sheppo 8131991Sheppo ldcp = ldclp->headp; 8143653Snarayan if (ldcp == NULL) 8151991Sheppo goto vgen_mcast_exit; 8161991Sheppo 8171991Sheppo mutex_enter(&ldcp->cblock); 8181991Sheppo 8191991Sheppo if (ldcp->hphase == VH_DONE) { 8201991Sheppo /* 8211991Sheppo * If handshake is done, send a msg to vsw to add/remove 822*5171Ssb155480 * the multicast address. Otherwise, we just update this 823*5171Ssb155480 * mcast address in our table and the table will be sync'd 824*5171Ssb155480 * with vsw when handshake completes. 8251991Sheppo */ 8261991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 8271991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 8281991Sheppo tagp->vio_subtype_env = VNET_MCAST_INFO; 8291991Sheppo tagp->vio_sid = ldcp->local_sid; 8301991Sheppo bcopy(mca, &(mcastmsg.mca), ETHERADDRL); 8311991Sheppo mcastmsg.set = add; 8321991Sheppo mcastmsg.count = 1; 8333653Snarayan if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (mcastmsg), 8343653Snarayan B_FALSE) != VGEN_SUCCESS) { 8354647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n"); 8363653Snarayan mutex_exit(&ldcp->cblock); 8373653Snarayan goto vgen_mcast_exit; 8381991Sheppo } 8391991Sheppo } 8401991Sheppo 8411991Sheppo mutex_exit(&ldcp->cblock); 8421991Sheppo 8431991Sheppo if (add) { 8441991Sheppo 8451991Sheppo /* expand multicast table if necessary */ 8461991Sheppo if (vgenp->mccount >= vgenp->mcsize) { 8471991Sheppo struct ether_addr *newtab; 8481991Sheppo uint32_t newsize; 8491991Sheppo 8501991Sheppo 8511991Sheppo newsize = vgenp->mcsize * 2; 8521991Sheppo 8531991Sheppo newtab = kmem_zalloc(newsize * 8541991Sheppo sizeof (struct ether_addr), KM_NOSLEEP); 8553653Snarayan if (newtab == NULL) 8563653Snarayan goto vgen_mcast_exit; 8571991Sheppo bcopy(vgenp->mctab, newtab, vgenp->mcsize * 8581991Sheppo sizeof (struct ether_addr)); 8591991Sheppo kmem_free(vgenp->mctab, 8601991Sheppo vgenp->mcsize * sizeof (struct ether_addr)); 8611991Sheppo 8621991Sheppo vgenp->mctab = newtab; 8631991Sheppo vgenp->mcsize = newsize; 8641991Sheppo } 8651991Sheppo 8661991Sheppo /* add address to the table */ 8671991Sheppo vgenp->mctab[vgenp->mccount++] = *addrp; 8681991Sheppo 8691991Sheppo } else { 8701991Sheppo 8711991Sheppo /* delete address from the table */ 8721991Sheppo for (i = 0; i < vgenp->mccount; i++) { 8731991Sheppo if (ether_cmp(addrp, &(vgenp->mctab[i])) == 0) { 8741991Sheppo 8751991Sheppo /* 8761991Sheppo * If there's more than one address in this 8771991Sheppo * table, delete the unwanted one by moving 8781991Sheppo * the last one in the list over top of it; 8791991Sheppo * otherwise, just remove it. 8801991Sheppo */ 8811991Sheppo if (vgenp->mccount > 1) { 8821991Sheppo vgenp->mctab[i] = 8834650Sraghuram vgenp->mctab[vgenp->mccount-1]; 8841991Sheppo } 8851991Sheppo vgenp->mccount--; 8861991Sheppo break; 8871991Sheppo } 8881991Sheppo } 8891991Sheppo } 8901991Sheppo 8913653Snarayan rv = DDI_SUCCESS; 8923653Snarayan 8933653Snarayan vgen_mcast_exit: 8941991Sheppo RW_EXIT(&ldclp->rwlock); 8951991Sheppo RW_EXIT(&plistp->rwlock); 8961991Sheppo 8971991Sheppo mutex_exit(&vgenp->lock); 8983653Snarayan return (rv); 8991991Sheppo } 9001991Sheppo 9011991Sheppo /* set or clear promiscuous mode on the device */ 9021991Sheppo static int 9031991Sheppo vgen_promisc(void *arg, boolean_t on) 9041991Sheppo { 9051991Sheppo _NOTE(ARGUNUSED(arg, on)) 9061991Sheppo return (DDI_SUCCESS); 9071991Sheppo } 9081991Sheppo 9091991Sheppo /* set the unicast mac address of the device */ 9101991Sheppo static int 9111991Sheppo vgen_unicst(void *arg, const uint8_t *mca) 9121991Sheppo { 9131991Sheppo _NOTE(ARGUNUSED(arg, mca)) 9141991Sheppo return (DDI_SUCCESS); 9151991Sheppo } 9161991Sheppo 9171991Sheppo /* get device statistics */ 9182311Sseb int 9192311Sseb vgen_stat(void *arg, uint_t stat, uint64_t *val) 9201991Sheppo { 9211991Sheppo vgen_t *vgenp = (vgen_t *)arg; 9221991Sheppo vgen_port_t *portp; 9231991Sheppo vgen_portlist_t *plistp; 9242311Sseb 9252311Sseb *val = 0; 9261991Sheppo 9271991Sheppo plistp = &(vgenp->vgenports); 9281991Sheppo READ_ENTER(&plistp->rwlock); 9291991Sheppo 9301991Sheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) { 9312311Sseb *val += vgen_port_stat(portp, stat); 9321991Sheppo } 9331991Sheppo 9341991Sheppo RW_EXIT(&plistp->rwlock); 9351991Sheppo 9362311Sseb return (0); 9371991Sheppo } 9381991Sheppo 9391991Sheppo static void 9401991Sheppo vgen_ioctl(void *arg, queue_t *wq, mblk_t *mp) 9411991Sheppo { 9421991Sheppo _NOTE(ARGUNUSED(arg, wq, mp)) 9431991Sheppo } 9441991Sheppo 9451991Sheppo /* vgen internal functions */ 9461991Sheppo /* detach all ports from the device */ 9471991Sheppo static void 9481991Sheppo vgen_detach_ports(vgen_t *vgenp) 9491991Sheppo { 9501991Sheppo vgen_port_t *portp; 9511991Sheppo vgen_portlist_t *plistp; 9521991Sheppo 9531991Sheppo plistp = &(vgenp->vgenports); 9541991Sheppo WRITE_ENTER(&plistp->rwlock); 9551991Sheppo 9561991Sheppo while ((portp = plistp->headp) != NULL) { 9571991Sheppo vgen_port_detach(portp); 9581991Sheppo } 9591991Sheppo 9601991Sheppo RW_EXIT(&plistp->rwlock); 9611991Sheppo } 9621991Sheppo 9631991Sheppo /* 9641991Sheppo * detach the given port. 9651991Sheppo */ 9661991Sheppo static void 9671991Sheppo vgen_port_detach(vgen_port_t *portp) 9681991Sheppo { 9691991Sheppo vgen_t *vgenp; 9701991Sheppo vgen_ldclist_t *ldclp; 9711991Sheppo int port_num; 9721991Sheppo 9731991Sheppo vgenp = portp->vgenp; 9741991Sheppo port_num = portp->port_num; 9751991Sheppo 9764647Sraghuram DBG1(vgenp, NULL, "port(%d):enter\n", port_num); 9771991Sheppo 9781991Sheppo /* remove it from port list */ 9791991Sheppo vgen_port_list_remove(portp); 9801991Sheppo 9811991Sheppo /* detach channels from this port */ 9821991Sheppo ldclp = &portp->ldclist; 9831991Sheppo WRITE_ENTER(&ldclp->rwlock); 9841991Sheppo while (ldclp->headp) { 9851991Sheppo vgen_ldc_detach(ldclp->headp); 9861991Sheppo } 9871991Sheppo RW_EXIT(&ldclp->rwlock); 9881991Sheppo 9891991Sheppo if (vgenp->vsw_portp == portp) { 9901991Sheppo vgenp->vsw_portp = NULL; 9911991Sheppo } 9921991Sheppo KMEM_FREE(portp); 9931991Sheppo 9944647Sraghuram DBG1(vgenp, NULL, "port(%d):exit\n", port_num); 9951991Sheppo } 9961991Sheppo 9971991Sheppo /* add a port to port list */ 9981991Sheppo static void 9991991Sheppo vgen_port_list_insert(vgen_port_t *portp) 10001991Sheppo { 10011991Sheppo vgen_portlist_t *plistp; 10021991Sheppo vgen_t *vgenp; 10031991Sheppo 10041991Sheppo vgenp = portp->vgenp; 10051991Sheppo plistp = &(vgenp->vgenports); 10061991Sheppo 10071991Sheppo if (plistp->headp == NULL) { 10081991Sheppo plistp->headp = portp; 10091991Sheppo } else { 10101991Sheppo plistp->tailp->nextp = portp; 10111991Sheppo } 10121991Sheppo plistp->tailp = portp; 10131991Sheppo portp->nextp = NULL; 10141991Sheppo } 10151991Sheppo 10161991Sheppo /* remove a port from port list */ 10171991Sheppo static void 10181991Sheppo vgen_port_list_remove(vgen_port_t *portp) 10191991Sheppo { 10201991Sheppo vgen_port_t *prevp; 10211991Sheppo vgen_port_t *nextp; 10221991Sheppo vgen_portlist_t *plistp; 10231991Sheppo vgen_t *vgenp; 10241991Sheppo 10251991Sheppo vgenp = portp->vgenp; 10261991Sheppo 10271991Sheppo plistp = &(vgenp->vgenports); 10281991Sheppo 10291991Sheppo if (plistp->headp == NULL) 10301991Sheppo return; 10311991Sheppo 10321991Sheppo if (portp == plistp->headp) { 10331991Sheppo plistp->headp = portp->nextp; 10341991Sheppo if (portp == plistp->tailp) 10351991Sheppo plistp->tailp = plistp->headp; 10361991Sheppo } else { 10374650Sraghuram for (prevp = plistp->headp; 10384650Sraghuram ((nextp = prevp->nextp) != NULL) && (nextp != portp); 10394650Sraghuram prevp = nextp) 10404650Sraghuram ; 10411991Sheppo if (nextp == portp) { 10421991Sheppo prevp->nextp = portp->nextp; 10431991Sheppo } 10441991Sheppo if (portp == plistp->tailp) 10451991Sheppo plistp->tailp = prevp; 10461991Sheppo } 10471991Sheppo } 10481991Sheppo 10491991Sheppo /* lookup a port in the list based on port_num */ 10501991Sheppo static vgen_port_t * 10511991Sheppo vgen_port_lookup(vgen_portlist_t *plistp, int port_num) 10521991Sheppo { 10531991Sheppo vgen_port_t *portp = NULL; 10541991Sheppo 10551991Sheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) { 10561991Sheppo if (portp->port_num == port_num) { 10571991Sheppo break; 10581991Sheppo } 10591991Sheppo } 10601991Sheppo 10611991Sheppo return (portp); 10621991Sheppo } 10631991Sheppo 10641991Sheppo /* enable ports for transmit/receive */ 10651991Sheppo static void 10661991Sheppo vgen_init_ports(vgen_t *vgenp) 10671991Sheppo { 10681991Sheppo vgen_port_t *portp; 10691991Sheppo vgen_portlist_t *plistp; 10701991Sheppo 10711991Sheppo plistp = &(vgenp->vgenports); 10721991Sheppo READ_ENTER(&plistp->rwlock); 10731991Sheppo 10741991Sheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) { 10751991Sheppo vgen_port_init(portp); 10761991Sheppo } 10771991Sheppo 10781991Sheppo RW_EXIT(&plistp->rwlock); 10791991Sheppo } 10801991Sheppo 10811991Sheppo static void 10821991Sheppo vgen_port_init(vgen_port_t *portp) 10831991Sheppo { 10841991Sheppo vgen_t *vgenp; 10851991Sheppo 10861991Sheppo vgenp = portp->vgenp; 10871991Sheppo /* 10881991Sheppo * Create fdb entry in vnet, corresponding to the mac 10891991Sheppo * address of this port. Note that the port specified 10901991Sheppo * is vsw-port. This is done so that vsw-port acts 10911991Sheppo * as the route to reach this macaddr, until the 10921991Sheppo * channel for this port comes up (LDC_UP) and 10931991Sheppo * handshake is done successfully. 10941991Sheppo * eg, if the peer is OBP-vnet, it may not bring the 10951991Sheppo * channel up for this port and may communicate via 10961991Sheppo * vsw to reach this port. 10971991Sheppo * Later, when Solaris-vnet comes up at the other end 10981991Sheppo * of the channel for this port and brings up the channel, 10991991Sheppo * it is an indication that peer vnet is capable of 11001991Sheppo * distributed switching, so the direct route through this 11011991Sheppo * port is specified in fdb, using vnet_modify_fdb(macaddr); 11021991Sheppo */ 11031991Sheppo vnet_add_fdb(vgenp->vnetp, (uint8_t *)&portp->macaddr, 11041991Sheppo vgen_tx, vgenp->vsw_portp); 11051991Sheppo 11061991Sheppo if (portp == vgenp->vsw_portp) { 11071991Sheppo /* 11081991Sheppo * create the default route entry in vnet's fdb. 11091991Sheppo * This is the entry used by vnet to reach 11101991Sheppo * unknown destinations, which basically goes 11111991Sheppo * through vsw on domain0 and out through the 11121991Sheppo * physical device bound to vsw. 11131991Sheppo */ 11141991Sheppo vnet_add_def_rte(vgenp->vnetp, vgen_tx, portp); 11151991Sheppo } 11161991Sheppo 11171991Sheppo /* Bring up the channels of this port */ 11181991Sheppo vgen_init_ldcs(portp); 11191991Sheppo } 11201991Sheppo 11211991Sheppo /* disable transmit/receive on ports */ 11221991Sheppo static void 11231991Sheppo vgen_uninit_ports(vgen_t *vgenp) 11241991Sheppo { 11251991Sheppo vgen_port_t *portp; 11261991Sheppo vgen_portlist_t *plistp; 11271991Sheppo 11281991Sheppo plistp = &(vgenp->vgenports); 11291991Sheppo READ_ENTER(&plistp->rwlock); 11301991Sheppo 11311991Sheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) { 11321991Sheppo vgen_port_uninit(portp); 11331991Sheppo } 11341991Sheppo 11351991Sheppo RW_EXIT(&plistp->rwlock); 11361991Sheppo } 11371991Sheppo 11381991Sheppo static void 11391991Sheppo vgen_port_uninit(vgen_port_t *portp) 11401991Sheppo { 11411991Sheppo vgen_t *vgenp; 11421991Sheppo 11431991Sheppo vgenp = portp->vgenp; 11441991Sheppo 11451991Sheppo vgen_uninit_ldcs(portp); 11461991Sheppo /* delete the entry in vnet's fdb for this port */ 11471991Sheppo vnet_del_fdb(vgenp->vnetp, (uint8_t *)&portp->macaddr); 11481991Sheppo if (portp == vgenp->vsw_portp) { 11491991Sheppo /* 11501991Sheppo * if this is vsw-port, then delete the default 11511991Sheppo * route entry in vnet's fdb. 11521991Sheppo */ 11531991Sheppo vnet_del_def_rte(vgenp->vnetp); 11541991Sheppo } 11551991Sheppo } 11561991Sheppo 11571991Sheppo /* register with MD event generator */ 11581991Sheppo static int 11591991Sheppo vgen_mdeg_reg(vgen_t *vgenp) 11601991Sheppo { 11611991Sheppo mdeg_prop_spec_t *pspecp; 11621991Sheppo mdeg_node_spec_t *parentp; 11631991Sheppo uint_t templatesz; 11641991Sheppo int rv; 11651991Sheppo mdeg_handle_t hdl; 11661991Sheppo int i; 11671991Sheppo 11681991Sheppo i = ddi_prop_get_int(DDI_DEV_T_ANY, vgenp->vnetdip, 11694650Sraghuram DDI_PROP_DONTPASS, reg_propname, -1); 11701991Sheppo if (i == -1) { 11711991Sheppo return (DDI_FAILURE); 11721991Sheppo } 11731991Sheppo templatesz = sizeof (vgen_prop_template); 11741991Sheppo pspecp = kmem_zalloc(templatesz, KM_NOSLEEP); 11751991Sheppo if (pspecp == NULL) { 11761991Sheppo return (DDI_FAILURE); 11771991Sheppo } 11781991Sheppo parentp = kmem_zalloc(sizeof (mdeg_node_spec_t), KM_NOSLEEP); 11791991Sheppo if (parentp == NULL) { 11801991Sheppo kmem_free(pspecp, templatesz); 11811991Sheppo return (DDI_FAILURE); 11821991Sheppo } 11831991Sheppo 11841991Sheppo bcopy(vgen_prop_template, pspecp, templatesz); 11851991Sheppo 11861991Sheppo /* 11871991Sheppo * NOTE: The instance here refers to the value of "reg" property and 11881991Sheppo * not the dev_info instance (ddi_get_instance()) of vnet. 11891991Sheppo */ 11901991Sheppo VGEN_SET_MDEG_PROP_INST(pspecp, i); 11911991Sheppo 11921991Sheppo parentp->namep = "virtual-device"; 11931991Sheppo parentp->specp = pspecp; 11941991Sheppo 11951991Sheppo /* save parentp in vgen_t */ 11961991Sheppo vgenp->mdeg_parentp = parentp; 11971991Sheppo 11981991Sheppo rv = mdeg_register(parentp, &vport_match, vgen_mdeg_cb, vgenp, &hdl); 11991991Sheppo if (rv != MDEG_SUCCESS) { 12004647Sraghuram DERR(vgenp, NULL, "mdeg_register failed\n"); 12011991Sheppo KMEM_FREE(parentp); 12021991Sheppo kmem_free(pspecp, templatesz); 12031991Sheppo vgenp->mdeg_parentp = NULL; 12041991Sheppo return (DDI_FAILURE); 12051991Sheppo } 12061991Sheppo 12071991Sheppo /* save mdeg handle in vgen_t */ 12081991Sheppo vgenp->mdeg_hdl = hdl; 12091991Sheppo 12101991Sheppo return (DDI_SUCCESS); 12111991Sheppo } 12121991Sheppo 12131991Sheppo /* unregister with MD event generator */ 12141991Sheppo static void 12151991Sheppo vgen_mdeg_unreg(vgen_t *vgenp) 12161991Sheppo { 12171991Sheppo (void) mdeg_unregister(vgenp->mdeg_hdl); 12183297Ssb155480 kmem_free(vgenp->mdeg_parentp->specp, sizeof (vgen_prop_template)); 12191991Sheppo KMEM_FREE(vgenp->mdeg_parentp); 12201991Sheppo vgenp->mdeg_parentp = NULL; 12211991Sheppo vgenp->mdeg_hdl = NULL; 12221991Sheppo } 12231991Sheppo 12241991Sheppo /* callback function registered with MD event generator */ 12251991Sheppo static int 12261991Sheppo vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp) 12271991Sheppo { 12281991Sheppo int idx; 12291991Sheppo int vsw_idx = -1; 12301991Sheppo uint64_t val; 12311991Sheppo vgen_t *vgenp; 12321991Sheppo 12331991Sheppo if ((resp == NULL) || (cb_argp == NULL)) { 12341991Sheppo return (MDEG_FAILURE); 12351991Sheppo } 12361991Sheppo 12371991Sheppo vgenp = (vgen_t *)cb_argp; 12384647Sraghuram DBG1(vgenp, NULL, "enter\n"); 12391991Sheppo 12401991Sheppo mutex_enter(&vgenp->lock); 12411991Sheppo 12424647Sraghuram DBG1(vgenp, NULL, "ports: removed(%x), " 12434647Sraghuram "added(%x), updated(%x)\n", resp->removed.nelem, 12444647Sraghuram resp->added.nelem, resp->match_curr.nelem); 12451991Sheppo 12461991Sheppo for (idx = 0; idx < resp->removed.nelem; idx++) { 12471991Sheppo (void) vgen_remove_port(vgenp, resp->removed.mdp, 12481991Sheppo resp->removed.mdep[idx]); 12491991Sheppo } 12501991Sheppo 12511991Sheppo if (vgenp->vsw_portp == NULL) { 12521991Sheppo /* 12531991Sheppo * find vsw_port and add it first, because other ports need 12541991Sheppo * this when adding fdb entry (see vgen_port_init()). 12551991Sheppo */ 12561991Sheppo for (idx = 0; idx < resp->added.nelem; idx++) { 12571991Sheppo if (!(md_get_prop_val(resp->added.mdp, 12581991Sheppo resp->added.mdep[idx], swport_propname, &val))) { 12591991Sheppo if (val == 0) { 12601991Sheppo /* 12611991Sheppo * This port is connected to the 12621991Sheppo * vsw on dom0. 12631991Sheppo */ 12641991Sheppo vsw_idx = idx; 12654663Szk194757 if (vgen_add_port(vgenp, 12661991Sheppo resp->added.mdp, 12674663Szk194757 resp->added.mdep[idx]) != 12684663Szk194757 DDI_SUCCESS) { 12694663Szk194757 cmn_err(CE_NOTE, "vnet%d Could " 12704663Szk194757 "not initialize virtual " 12714663Szk194757 "switch port.", 12724663Szk194757 ddi_get_instance(vgenp-> 12734663Szk194757 vnetdip)); 12744663Szk194757 mutex_exit(&vgenp->lock); 12754663Szk194757 return (MDEG_FAILURE); 12764663Szk194757 } 12771991Sheppo break; 12781991Sheppo } 12791991Sheppo } 12801991Sheppo } 12814666Szk194757 if (vsw_idx == -1) { 12824647Sraghuram DWARN(vgenp, NULL, "can't find vsw_port\n"); 12834663Szk194757 mutex_exit(&vgenp->lock); 12841991Sheppo return (MDEG_FAILURE); 12851991Sheppo } 12861991Sheppo } 12871991Sheppo 12881991Sheppo for (idx = 0; idx < resp->added.nelem; idx++) { 12891991Sheppo if ((vsw_idx != -1) && (vsw_idx == idx)) /* skip vsw_port */ 12901991Sheppo continue; 12914663Szk194757 12924663Szk194757 /* If this port can't be added just skip it. */ 12931991Sheppo (void) vgen_add_port(vgenp, resp->added.mdp, 12941991Sheppo resp->added.mdep[idx]); 12951991Sheppo } 12961991Sheppo 12971991Sheppo for (idx = 0; idx < resp->match_curr.nelem; idx++) { 12981991Sheppo (void) vgen_update_port(vgenp, resp->match_curr.mdp, 12991991Sheppo resp->match_curr.mdep[idx], 13001991Sheppo resp->match_prev.mdp, 13011991Sheppo resp->match_prev.mdep[idx]); 13021991Sheppo } 13031991Sheppo 13041991Sheppo mutex_exit(&vgenp->lock); 13054647Sraghuram DBG1(vgenp, NULL, "exit\n"); 13061991Sheppo return (MDEG_SUCCESS); 13071991Sheppo } 13081991Sheppo 13091991Sheppo /* add a new port to the device */ 13101991Sheppo static int 13111991Sheppo vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex) 13121991Sheppo { 13131991Sheppo uint64_t port_num; 13141991Sheppo uint64_t *ldc_ids; 13151991Sheppo uint64_t macaddr; 13161991Sheppo uint64_t val; 13171991Sheppo int num_ldcs; 13181991Sheppo int vsw_port = B_FALSE; 13191991Sheppo int i; 13201991Sheppo int addrsz; 13211991Sheppo int num_nodes = 0; 13221991Sheppo int listsz = 0; 13234663Szk194757 int rv = DDI_SUCCESS; 13241991Sheppo mde_cookie_t *listp = NULL; 13251991Sheppo uint8_t *addrp; 13261991Sheppo struct ether_addr ea; 13271991Sheppo 13281991Sheppo /* read "id" property to get the port number */ 13291991Sheppo if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) { 13304647Sraghuram DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname); 13311991Sheppo return (DDI_FAILURE); 13321991Sheppo } 13331991Sheppo 13341991Sheppo /* 13351991Sheppo * Find the channel endpoint node(s) under this port node. 13361991Sheppo */ 13371991Sheppo if ((num_nodes = md_node_count(mdp)) <= 0) { 13384647Sraghuram DWARN(vgenp, NULL, "invalid number of nodes found (%d)", 13394647Sraghuram num_nodes); 13401991Sheppo return (DDI_FAILURE); 13411991Sheppo } 13421991Sheppo 13431991Sheppo /* allocate space for node list */ 13441991Sheppo listsz = num_nodes * sizeof (mde_cookie_t); 13451991Sheppo listp = kmem_zalloc(listsz, KM_NOSLEEP); 13461991Sheppo if (listp == NULL) 13471991Sheppo return (DDI_FAILURE); 13481991Sheppo 13491991Sheppo num_ldcs = md_scan_dag(mdp, mdex, 13504650Sraghuram md_find_name(mdp, channel_propname), 13514650Sraghuram md_find_name(mdp, "fwd"), listp); 13521991Sheppo 13531991Sheppo if (num_ldcs <= 0) { 13544647Sraghuram DWARN(vgenp, NULL, "can't find %s nodes", channel_propname); 13551991Sheppo kmem_free(listp, listsz); 13561991Sheppo return (DDI_FAILURE); 13571991Sheppo } 13581991Sheppo 13594647Sraghuram DBG2(vgenp, NULL, "num_ldcs %d", num_ldcs); 13601991Sheppo 13611991Sheppo ldc_ids = kmem_zalloc(num_ldcs * sizeof (uint64_t), KM_NOSLEEP); 13621991Sheppo if (ldc_ids == NULL) { 13631991Sheppo kmem_free(listp, listsz); 13641991Sheppo return (DDI_FAILURE); 13651991Sheppo } 13661991Sheppo 13671991Sheppo for (i = 0; i < num_ldcs; i++) { 13681991Sheppo /* read channel ids */ 13691991Sheppo if (md_get_prop_val(mdp, listp[i], id_propname, &ldc_ids[i])) { 13704647Sraghuram DWARN(vgenp, NULL, "prop(%s) not found\n", 13714647Sraghuram id_propname); 13721991Sheppo kmem_free(listp, listsz); 13731991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 13741991Sheppo return (DDI_FAILURE); 13751991Sheppo } 13764647Sraghuram DBG2(vgenp, NULL, "ldc_id 0x%llx", ldc_ids[i]); 13771991Sheppo } 13781991Sheppo 13791991Sheppo kmem_free(listp, listsz); 13801991Sheppo 13811991Sheppo if (md_get_prop_data(mdp, mdex, rmacaddr_propname, &addrp, 13821991Sheppo &addrsz)) { 13834647Sraghuram DWARN(vgenp, NULL, "prop(%s) not found\n", rmacaddr_propname); 13841991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 13851991Sheppo return (DDI_FAILURE); 13861991Sheppo } 13871991Sheppo 13881991Sheppo if (addrsz < ETHERADDRL) { 13894647Sraghuram DWARN(vgenp, NULL, "invalid address size (%d)\n", addrsz); 13901991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 13911991Sheppo return (DDI_FAILURE); 13921991Sheppo } 13931991Sheppo 13941991Sheppo macaddr = *((uint64_t *)addrp); 13951991Sheppo 13964647Sraghuram DBG2(vgenp, NULL, "remote mac address 0x%llx\n", macaddr); 13971991Sheppo 13981991Sheppo for (i = ETHERADDRL - 1; i >= 0; i--) { 13991991Sheppo ea.ether_addr_octet[i] = macaddr & 0xFF; 14001991Sheppo macaddr >>= 8; 14011991Sheppo } 14021991Sheppo 14031991Sheppo if (vgenp->vsw_portp == NULL) { 14041991Sheppo if (!(md_get_prop_val(mdp, mdex, swport_propname, &val))) { 14051991Sheppo if (val == 0) { 14061991Sheppo /* This port is connected to the vsw on dom0 */ 14071991Sheppo vsw_port = B_TRUE; 14081991Sheppo } 14091991Sheppo } 14101991Sheppo } 14114663Szk194757 if (vgen_port_attach_mdeg(vgenp, (int)port_num, ldc_ids, num_ldcs, 14124663Szk194757 &ea, vsw_port) != DDI_SUCCESS) { 14134663Szk194757 cmn_err(CE_NOTE, "vnet%d failed to attach port %d remote MAC " 14144663Szk194757 "address %s", ddi_get_instance(vgenp->vnetdip), 14154663Szk194757 (int)port_num, ether_sprintf(&ea)); 14164663Szk194757 rv = DDI_FAILURE; 14174663Szk194757 } 14181991Sheppo 14191991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 14201991Sheppo 14214663Szk194757 return (rv); 14221991Sheppo } 14231991Sheppo 14241991Sheppo /* remove a port from the device */ 14251991Sheppo static int 14261991Sheppo vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex) 14271991Sheppo { 14281991Sheppo uint64_t port_num; 14291991Sheppo vgen_port_t *portp; 14301991Sheppo vgen_portlist_t *plistp; 14311991Sheppo 14321991Sheppo /* read "id" property to get the port number */ 14331991Sheppo if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) { 14344647Sraghuram DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname); 14351991Sheppo return (DDI_FAILURE); 14361991Sheppo } 14371991Sheppo 14381991Sheppo plistp = &(vgenp->vgenports); 14391991Sheppo 14401991Sheppo WRITE_ENTER(&plistp->rwlock); 14411991Sheppo portp = vgen_port_lookup(plistp, (int)port_num); 14421991Sheppo if (portp == NULL) { 14434647Sraghuram DWARN(vgenp, NULL, "can't find port(%lx)\n", port_num); 14441991Sheppo RW_EXIT(&plistp->rwlock); 14451991Sheppo return (DDI_FAILURE); 14461991Sheppo } 14471991Sheppo 14481991Sheppo vgen_port_detach_mdeg(portp); 14491991Sheppo RW_EXIT(&plistp->rwlock); 14501991Sheppo 14511991Sheppo return (DDI_SUCCESS); 14521991Sheppo } 14531991Sheppo 14541991Sheppo /* attach a port to the device based on mdeg data */ 14551991Sheppo static int 14561991Sheppo vgen_port_attach_mdeg(vgen_t *vgenp, int port_num, uint64_t *ldcids, 14571991Sheppo int num_ids, struct ether_addr *macaddr, boolean_t vsw_port) 14581991Sheppo { 14591991Sheppo vgen_port_t *portp; 14601991Sheppo vgen_portlist_t *plistp; 14611991Sheppo int i; 14621991Sheppo 14631991Sheppo portp = kmem_zalloc(sizeof (vgen_port_t), KM_NOSLEEP); 14641991Sheppo if (portp == NULL) { 14651991Sheppo return (DDI_FAILURE); 14661991Sheppo } 14671991Sheppo portp->vgenp = vgenp; 14681991Sheppo portp->port_num = port_num; 14691991Sheppo 14704647Sraghuram DBG1(vgenp, NULL, "port_num(%d)\n", portp->port_num); 14711991Sheppo 14721991Sheppo portp->ldclist.num_ldcs = 0; 14731991Sheppo portp->ldclist.headp = NULL; 14741991Sheppo rw_init(&portp->ldclist.rwlock, NULL, RW_DRIVER, NULL); 14751991Sheppo 14761991Sheppo ether_copy(macaddr, &portp->macaddr); 14771991Sheppo for (i = 0; i < num_ids; i++) { 14784647Sraghuram DBG2(vgenp, NULL, "ldcid (%lx)\n", ldcids[i]); 14794663Szk194757 if (vgen_ldc_attach(portp, ldcids[i]) == DDI_FAILURE) { 14804663Szk194757 rw_destroy(&portp->ldclist.rwlock); 14814663Szk194757 vgen_port_detach(portp); 14824663Szk194757 return (DDI_FAILURE); 14834663Szk194757 } 14841991Sheppo } 14851991Sheppo 14861991Sheppo /* link it into the list of ports */ 14871991Sheppo plistp = &(vgenp->vgenports); 14881991Sheppo WRITE_ENTER(&plistp->rwlock); 14891991Sheppo vgen_port_list_insert(portp); 14901991Sheppo RW_EXIT(&plistp->rwlock); 14911991Sheppo 14921991Sheppo /* This port is connected to the vsw on domain0 */ 14931991Sheppo if (vsw_port) 14941991Sheppo vgenp->vsw_portp = portp; 14951991Sheppo 14961991Sheppo if (vgenp->flags & VGEN_STARTED) { /* interface is configured */ 14971991Sheppo vgen_port_init(portp); 14981991Sheppo } 14991991Sheppo 15004647Sraghuram DBG1(vgenp, NULL, "exit: port_num(%d)\n", portp->port_num); 15011991Sheppo return (DDI_SUCCESS); 15021991Sheppo } 15031991Sheppo 15041991Sheppo /* detach a port from the device based on mdeg data */ 15051991Sheppo static void 15061991Sheppo vgen_port_detach_mdeg(vgen_port_t *portp) 15071991Sheppo { 15081991Sheppo vgen_t *vgenp = portp->vgenp; 15091991Sheppo 15104647Sraghuram DBG1(vgenp, NULL, "enter: port_num(%d)\n", portp->port_num); 15111991Sheppo /* stop the port if needed */ 15121991Sheppo if (vgenp->flags & VGEN_STARTED) { 15131991Sheppo vgen_port_uninit(portp); 15141991Sheppo } 15151991Sheppo vgen_port_detach(portp); 15161991Sheppo 15174647Sraghuram DBG1(vgenp, NULL, "exit: port_num(%d)\n", portp->port_num); 15181991Sheppo } 15191991Sheppo 15201991Sheppo static int 15211991Sheppo vgen_update_port(vgen_t *vgenp, md_t *curr_mdp, mde_cookie_t curr_mdex, 15221991Sheppo md_t *prev_mdp, mde_cookie_t prev_mdex) 15231991Sheppo { 15241991Sheppo _NOTE(ARGUNUSED(vgenp, curr_mdp, curr_mdex, prev_mdp, prev_mdex)) 15251991Sheppo 15262793Slm66018 /* NOTE: TBD */ 15271991Sheppo return (DDI_SUCCESS); 15281991Sheppo } 15291991Sheppo 15301991Sheppo static uint64_t 15312311Sseb vgen_port_stat(vgen_port_t *portp, uint_t stat) 15321991Sheppo { 15331991Sheppo vgen_ldclist_t *ldclp; 15341991Sheppo vgen_ldc_t *ldcp; 15351991Sheppo uint64_t val; 15361991Sheppo 15371991Sheppo val = 0; 15381991Sheppo ldclp = &portp->ldclist; 15391991Sheppo 15401991Sheppo READ_ENTER(&ldclp->rwlock); 15411991Sheppo for (ldcp = ldclp->headp; ldcp != NULL; ldcp = ldcp->nextp) { 15421991Sheppo val += vgen_ldc_stat(ldcp, stat); 15431991Sheppo } 15441991Sheppo RW_EXIT(&ldclp->rwlock); 15451991Sheppo 15461991Sheppo return (val); 15471991Sheppo } 15481991Sheppo 15491991Sheppo /* attach the channel corresponding to the given ldc_id to the port */ 15501991Sheppo static int 15511991Sheppo vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id) 15521991Sheppo { 15531991Sheppo vgen_t *vgenp; 15541991Sheppo vgen_ldclist_t *ldclp; 15551991Sheppo vgen_ldc_t *ldcp, **prev_ldcp; 15561991Sheppo ldc_attr_t attr; 15571991Sheppo int status; 15581991Sheppo ldc_status_t istatus; 15594647Sraghuram enum {AST_init = 0x0, AST_ldc_alloc = 0x1, 15604647Sraghuram AST_mutex_init = 0x2, AST_ldc_init = 0x4, 15614647Sraghuram AST_ldc_reg_cb = 0x8, AST_alloc_tx_ring = 0x10, 15624647Sraghuram AST_create_rxmblks = 0x20, AST_add_softintr = 0x40, 15634647Sraghuram AST_create_rcv_thread = 0x80} attach_state; 15641991Sheppo 15651991Sheppo attach_state = AST_init; 15661991Sheppo vgenp = portp->vgenp; 15671991Sheppo ldclp = &portp->ldclist; 15681991Sheppo 15691991Sheppo ldcp = kmem_zalloc(sizeof (vgen_ldc_t), KM_NOSLEEP); 15701991Sheppo if (ldcp == NULL) { 15711991Sheppo goto ldc_attach_failed; 15721991Sheppo } 15731991Sheppo ldcp->ldc_id = ldc_id; 15741991Sheppo ldcp->portp = portp; 15751991Sheppo 15761991Sheppo attach_state |= AST_ldc_alloc; 15771991Sheppo 15781991Sheppo mutex_init(&ldcp->txlock, NULL, MUTEX_DRIVER, NULL); 15791991Sheppo mutex_init(&ldcp->cblock, NULL, MUTEX_DRIVER, NULL); 15801991Sheppo mutex_init(&ldcp->tclock, NULL, MUTEX_DRIVER, NULL); 15814647Sraghuram mutex_init(&ldcp->wrlock, NULL, MUTEX_DRIVER, NULL); 15824647Sraghuram mutex_init(&ldcp->rxlock, NULL, MUTEX_DRIVER, NULL); 15831991Sheppo 15841991Sheppo attach_state |= AST_mutex_init; 15851991Sheppo 15861991Sheppo attr.devclass = LDC_DEV_NT; 15871991Sheppo attr.instance = ddi_get_instance(vgenp->vnetdip); 15881991Sheppo attr.mode = LDC_MODE_UNRELIABLE; 15892410Slm66018 attr.mtu = vnet_ldc_mtu; 15901991Sheppo status = ldc_init(ldc_id, &attr, &ldcp->ldc_handle); 15911991Sheppo if (status != 0) { 15924647Sraghuram DWARN(vgenp, ldcp, "ldc_init failed,rv (%d)\n", status); 15931991Sheppo goto ldc_attach_failed; 15941991Sheppo } 15951991Sheppo attach_state |= AST_ldc_init; 15961991Sheppo 15974647Sraghuram if (vgen_rcv_thread_enabled) { 15984647Sraghuram ldcp->rcv_thr_flags = 0; 15994647Sraghuram ldcp->rcv_mhead = ldcp->rcv_mtail = NULL; 16004647Sraghuram ldcp->soft_pri = PIL_6; 16014647Sraghuram 16024647Sraghuram status = ddi_intr_add_softint(vgenp->vnetdip, 16034650Sraghuram &ldcp->soft_handle, ldcp->soft_pri, 16044650Sraghuram vgen_ldc_rcv_softintr, (void *)ldcp); 16054647Sraghuram if (status != DDI_SUCCESS) { 16064647Sraghuram DWARN(vgenp, ldcp, "add_softint failed, rv (%d)\n", 16074647Sraghuram status); 16084647Sraghuram goto ldc_attach_failed; 16094647Sraghuram } 16104647Sraghuram 16114647Sraghuram /* 16124650Sraghuram * Initialize the soft_lock with the same priority as 16134650Sraghuram * the soft interrupt to protect from the soft interrupt. 16144650Sraghuram */ 16154647Sraghuram mutex_init(&ldcp->soft_lock, NULL, MUTEX_DRIVER, 16164647Sraghuram DDI_INTR_PRI(ldcp->soft_pri)); 16174647Sraghuram attach_state |= AST_add_softintr; 16184647Sraghuram 16194647Sraghuram mutex_init(&ldcp->rcv_thr_lock, NULL, MUTEX_DRIVER, NULL); 16204647Sraghuram cv_init(&ldcp->rcv_thr_cv, NULL, CV_DRIVER, NULL); 16214647Sraghuram ldcp->rcv_thread = thread_create(NULL, 2 * DEFAULTSTKSZ, 16224647Sraghuram vgen_ldc_rcv_worker, ldcp, 0, &p0, TS_RUN, maxclsyspri); 16234647Sraghuram 16244647Sraghuram attach_state |= AST_create_rcv_thread; 16254647Sraghuram if (ldcp->rcv_thread == NULL) { 16264647Sraghuram DWARN(vgenp, ldcp, "Failed to create worker thread"); 16274647Sraghuram goto ldc_attach_failed; 16284647Sraghuram } 16294647Sraghuram } 16304647Sraghuram 16311991Sheppo status = ldc_reg_callback(ldcp->ldc_handle, vgen_ldc_cb, (caddr_t)ldcp); 16321991Sheppo if (status != 0) { 16334647Sraghuram DWARN(vgenp, ldcp, "ldc_reg_callback failed, rv (%d)\n", 16344647Sraghuram status); 16351991Sheppo goto ldc_attach_failed; 16361991Sheppo } 16371991Sheppo attach_state |= AST_ldc_reg_cb; 16381991Sheppo 16391991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 16401991Sheppo ASSERT(istatus == LDC_INIT); 16411991Sheppo ldcp->ldc_status = istatus; 16421991Sheppo 16431991Sheppo /* allocate transmit resources */ 16441991Sheppo status = vgen_alloc_tx_ring(ldcp); 16451991Sheppo if (status != 0) { 16461991Sheppo goto ldc_attach_failed; 16471991Sheppo } 16481991Sheppo attach_state |= AST_alloc_tx_ring; 16491991Sheppo 16502336Snarayan /* allocate receive resources */ 16514647Sraghuram status = vio_init_multipools(&ldcp->vmp, VGEN_NUM_VMPOOLS, 16524650Sraghuram vgen_rbufsz1, vgen_rbufsz2, vgen_rbufsz3, 16534650Sraghuram vgen_nrbufs1, vgen_nrbufs2, vgen_nrbufs3); 16542336Snarayan if (status != 0) { 16552336Snarayan goto ldc_attach_failed; 16562336Snarayan } 16572336Snarayan attach_state |= AST_create_rxmblks; 16582336Snarayan 16591991Sheppo /* Setup kstats for the channel */ 16601991Sheppo status = vgen_setup_kstats(ldcp); 16611991Sheppo if (status != VGEN_SUCCESS) { 16621991Sheppo goto ldc_attach_failed; 16631991Sheppo } 16641991Sheppo 16651991Sheppo /* initialize vgen_versions supported */ 16661991Sheppo bcopy(vgen_versions, ldcp->vgen_versions, sizeof (ldcp->vgen_versions)); 16671991Sheppo 16681991Sheppo /* link it into the list of channels for this port */ 16691991Sheppo WRITE_ENTER(&ldclp->rwlock); 16701991Sheppo prev_ldcp = (vgen_ldc_t **)(&ldclp->headp); 16711991Sheppo ldcp->nextp = *prev_ldcp; 16721991Sheppo *prev_ldcp = ldcp; 16731991Sheppo ldclp->num_ldcs++; 16741991Sheppo RW_EXIT(&ldclp->rwlock); 16751991Sheppo 16761991Sheppo ldcp->flags |= CHANNEL_ATTACHED; 16771991Sheppo return (DDI_SUCCESS); 16781991Sheppo 16791991Sheppo ldc_attach_failed: 16804647Sraghuram if (attach_state & AST_ldc_reg_cb) { 16814647Sraghuram (void) ldc_unreg_callback(ldcp->ldc_handle); 16824647Sraghuram } 16834647Sraghuram if (attach_state & AST_add_softintr) { 16844647Sraghuram (void) ddi_intr_remove_softint(ldcp->soft_handle); 16854647Sraghuram mutex_destroy(&ldcp->soft_lock); 16864647Sraghuram } 16874647Sraghuram if (attach_state & AST_create_rcv_thread) { 16884647Sraghuram if (ldcp->rcv_thread != NULL) { 16894647Sraghuram vgen_stop_rcv_thread(ldcp); 16904647Sraghuram } 16914647Sraghuram mutex_destroy(&ldcp->rcv_thr_lock); 16924647Sraghuram cv_destroy(&ldcp->rcv_thr_cv); 16934647Sraghuram } 16942336Snarayan if (attach_state & AST_create_rxmblks) { 16954647Sraghuram vio_mblk_pool_t *fvmp = NULL; 16964647Sraghuram 16974647Sraghuram vio_destroy_multipools(&ldcp->vmp, &fvmp); 16984647Sraghuram ASSERT(fvmp == NULL); 16992336Snarayan } 17001991Sheppo if (attach_state & AST_alloc_tx_ring) { 17011991Sheppo vgen_free_tx_ring(ldcp); 17021991Sheppo } 17031991Sheppo if (attach_state & AST_ldc_init) { 17041991Sheppo (void) ldc_fini(ldcp->ldc_handle); 17051991Sheppo } 17061991Sheppo if (attach_state & AST_mutex_init) { 17071991Sheppo mutex_destroy(&ldcp->tclock); 17081991Sheppo mutex_destroy(&ldcp->txlock); 17091991Sheppo mutex_destroy(&ldcp->cblock); 17104647Sraghuram mutex_destroy(&ldcp->wrlock); 17114647Sraghuram mutex_destroy(&ldcp->rxlock); 17121991Sheppo } 17131991Sheppo if (attach_state & AST_ldc_alloc) { 17141991Sheppo KMEM_FREE(ldcp); 17151991Sheppo } 17161991Sheppo return (DDI_FAILURE); 17171991Sheppo } 17181991Sheppo 17191991Sheppo /* detach a channel from the port */ 17201991Sheppo static void 17211991Sheppo vgen_ldc_detach(vgen_ldc_t *ldcp) 17221991Sheppo { 17231991Sheppo vgen_port_t *portp; 17241991Sheppo vgen_t *vgenp; 17251991Sheppo vgen_ldc_t *pldcp; 17261991Sheppo vgen_ldc_t **prev_ldcp; 17271991Sheppo vgen_ldclist_t *ldclp; 17281991Sheppo 17291991Sheppo portp = ldcp->portp; 17301991Sheppo vgenp = portp->vgenp; 17311991Sheppo ldclp = &portp->ldclist; 17321991Sheppo 17331991Sheppo prev_ldcp = (vgen_ldc_t **)&ldclp->headp; 17341991Sheppo for (; (pldcp = *prev_ldcp) != NULL; prev_ldcp = &pldcp->nextp) { 17351991Sheppo if (pldcp == ldcp) { 17361991Sheppo break; 17371991Sheppo } 17381991Sheppo } 17391991Sheppo 17401991Sheppo if (pldcp == NULL) { 17411991Sheppo /* invalid ldcp? */ 17421991Sheppo return; 17431991Sheppo } 17441991Sheppo 17451991Sheppo if (ldcp->ldc_status != LDC_INIT) { 17464647Sraghuram DWARN(vgenp, ldcp, "ldc_status is not INIT\n"); 17471991Sheppo } 17481991Sheppo 17491991Sheppo if (ldcp->flags & CHANNEL_ATTACHED) { 17501991Sheppo ldcp->flags &= ~(CHANNEL_ATTACHED); 17511991Sheppo 17524647Sraghuram (void) ldc_unreg_callback(ldcp->ldc_handle); 17534647Sraghuram if (ldcp->rcv_thread != NULL) { 17544647Sraghuram /* First stop the receive thread */ 17554647Sraghuram vgen_stop_rcv_thread(ldcp); 17564647Sraghuram (void) ddi_intr_remove_softint(ldcp->soft_handle); 17574647Sraghuram mutex_destroy(&ldcp->soft_lock); 17584647Sraghuram mutex_destroy(&ldcp->rcv_thr_lock); 17594647Sraghuram cv_destroy(&ldcp->rcv_thr_cv); 17604647Sraghuram } 17614647Sraghuram /* Free any queued messages */ 17624647Sraghuram if (ldcp->rcv_mhead != NULL) { 17634647Sraghuram freemsgchain(ldcp->rcv_mhead); 17644647Sraghuram ldcp->rcv_mhead = NULL; 17654647Sraghuram } 17664647Sraghuram 17671991Sheppo vgen_destroy_kstats(ldcp); 17684647Sraghuram /* 17694647Sraghuram * if we cannot reclaim all mblks, put this 17704647Sraghuram * on the list of pools(vgenp->rmp) to be reclaimed when the 17714647Sraghuram * device gets detached (see vgen_uninit()). 17724647Sraghuram */ 17734647Sraghuram vio_destroy_multipools(&ldcp->vmp, &vgenp->rmp); 17742336Snarayan 17751991Sheppo /* free transmit resources */ 17761991Sheppo vgen_free_tx_ring(ldcp); 17772336Snarayan 17781991Sheppo (void) ldc_fini(ldcp->ldc_handle); 17791991Sheppo mutex_destroy(&ldcp->tclock); 17801991Sheppo mutex_destroy(&ldcp->txlock); 17811991Sheppo mutex_destroy(&ldcp->cblock); 17824647Sraghuram mutex_destroy(&ldcp->wrlock); 17834647Sraghuram mutex_destroy(&ldcp->rxlock); 17841991Sheppo 17851991Sheppo /* unlink it from the list */ 17861991Sheppo *prev_ldcp = ldcp->nextp; 17871991Sheppo ldclp->num_ldcs--; 17881991Sheppo KMEM_FREE(ldcp); 17891991Sheppo } 17901991Sheppo } 17911991Sheppo 17921991Sheppo /* 17931991Sheppo * This function allocates transmit resources for the channel. 17941991Sheppo * The resources consist of a transmit descriptor ring and an associated 17951991Sheppo * transmit buffer ring. 17961991Sheppo */ 17971991Sheppo static int 17981991Sheppo vgen_alloc_tx_ring(vgen_ldc_t *ldcp) 17991991Sheppo { 18001991Sheppo void *tbufp; 18011991Sheppo ldc_mem_info_t minfo; 18021991Sheppo uint32_t txdsize; 18031991Sheppo uint32_t tbufsize; 18041991Sheppo int status; 18054647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 18061991Sheppo 18071991Sheppo ldcp->num_txds = vnet_ntxds; 18081991Sheppo txdsize = sizeof (vnet_public_desc_t); 18091991Sheppo tbufsize = sizeof (vgen_private_desc_t); 18101991Sheppo 18111991Sheppo /* allocate transmit buffer ring */ 18121991Sheppo tbufp = kmem_zalloc(ldcp->num_txds * tbufsize, KM_NOSLEEP); 18131991Sheppo if (tbufp == NULL) { 18141991Sheppo return (DDI_FAILURE); 18151991Sheppo } 18161991Sheppo 18171991Sheppo /* create transmit descriptor ring */ 18181991Sheppo status = ldc_mem_dring_create(ldcp->num_txds, txdsize, 18191991Sheppo &ldcp->tx_dhandle); 18201991Sheppo if (status) { 18214647Sraghuram DWARN(vgenp, ldcp, "ldc_mem_dring_create() failed\n"); 18221991Sheppo kmem_free(tbufp, ldcp->num_txds * tbufsize); 18231991Sheppo return (DDI_FAILURE); 18241991Sheppo } 18251991Sheppo 18261991Sheppo /* get the addr of descripror ring */ 18271991Sheppo status = ldc_mem_dring_info(ldcp->tx_dhandle, &minfo); 18281991Sheppo if (status) { 18294647Sraghuram DWARN(vgenp, ldcp, "ldc_mem_dring_info() failed\n"); 18301991Sheppo kmem_free(tbufp, ldcp->num_txds * tbufsize); 18311991Sheppo (void) ldc_mem_dring_destroy(ldcp->tx_dhandle); 18321991Sheppo ldcp->tbufp = NULL; 18331991Sheppo return (DDI_FAILURE); 18341991Sheppo } 18351991Sheppo ldcp->txdp = (vnet_public_desc_t *)(minfo.vaddr); 18361991Sheppo ldcp->tbufp = tbufp; 18371991Sheppo 18381991Sheppo ldcp->txdendp = &((ldcp->txdp)[ldcp->num_txds]); 18391991Sheppo ldcp->tbufendp = &((ldcp->tbufp)[ldcp->num_txds]); 18401991Sheppo 18411991Sheppo return (DDI_SUCCESS); 18421991Sheppo } 18431991Sheppo 18441991Sheppo /* Free transmit resources for the channel */ 18451991Sheppo static void 18461991Sheppo vgen_free_tx_ring(vgen_ldc_t *ldcp) 18471991Sheppo { 18481991Sheppo int tbufsize = sizeof (vgen_private_desc_t); 18491991Sheppo 18501991Sheppo /* free transmit descriptor ring */ 18511991Sheppo (void) ldc_mem_dring_destroy(ldcp->tx_dhandle); 18521991Sheppo 18531991Sheppo /* free transmit buffer ring */ 18541991Sheppo kmem_free(ldcp->tbufp, ldcp->num_txds * tbufsize); 18551991Sheppo ldcp->txdp = ldcp->txdendp = NULL; 18561991Sheppo ldcp->tbufp = ldcp->tbufendp = NULL; 18571991Sheppo } 18581991Sheppo 18591991Sheppo /* enable transmit/receive on the channels for the port */ 18601991Sheppo static void 18611991Sheppo vgen_init_ldcs(vgen_port_t *portp) 18621991Sheppo { 18631991Sheppo vgen_ldclist_t *ldclp = &portp->ldclist; 18641991Sheppo vgen_ldc_t *ldcp; 18651991Sheppo 18661991Sheppo READ_ENTER(&ldclp->rwlock); 18671991Sheppo ldcp = ldclp->headp; 18681991Sheppo for (; ldcp != NULL; ldcp = ldcp->nextp) { 18691991Sheppo (void) vgen_ldc_init(ldcp); 18701991Sheppo } 18711991Sheppo RW_EXIT(&ldclp->rwlock); 18721991Sheppo } 18731991Sheppo 18741991Sheppo /* stop transmit/receive on the channels for the port */ 18751991Sheppo static void 18761991Sheppo vgen_uninit_ldcs(vgen_port_t *portp) 18771991Sheppo { 18781991Sheppo vgen_ldclist_t *ldclp = &portp->ldclist; 18791991Sheppo vgen_ldc_t *ldcp; 18801991Sheppo 18811991Sheppo READ_ENTER(&ldclp->rwlock); 18821991Sheppo ldcp = ldclp->headp; 18831991Sheppo for (; ldcp != NULL; ldcp = ldcp->nextp) { 18841991Sheppo vgen_ldc_uninit(ldcp); 18851991Sheppo } 18861991Sheppo RW_EXIT(&ldclp->rwlock); 18871991Sheppo } 18881991Sheppo 18891991Sheppo /* enable transmit/receive on the channel */ 18901991Sheppo static int 18911991Sheppo vgen_ldc_init(vgen_ldc_t *ldcp) 18921991Sheppo { 18934647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 18941991Sheppo ldc_status_t istatus; 18951991Sheppo int rv; 18962109Slm66018 uint32_t retries = 0; 18974647Sraghuram enum { ST_init = 0x0, ST_ldc_open = 0x1, 18984647Sraghuram ST_init_tbufs = 0x2, ST_cb_enable = 0x4} init_state; 18991991Sheppo init_state = ST_init; 19001991Sheppo 19014647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 19021991Sheppo LDC_LOCK(ldcp); 19031991Sheppo 19041991Sheppo rv = ldc_open(ldcp->ldc_handle); 19051991Sheppo if (rv != 0) { 19064647Sraghuram DWARN(vgenp, ldcp, "ldc_open failed: rv(%d)\n", rv); 19071991Sheppo goto ldcinit_failed; 19081991Sheppo } 19091991Sheppo init_state |= ST_ldc_open; 19101991Sheppo 19111991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 19121991Sheppo if (istatus != LDC_OPEN && istatus != LDC_READY) { 19134647Sraghuram DWARN(vgenp, ldcp, "status(%d) is not OPEN/READY\n", istatus); 19141991Sheppo goto ldcinit_failed; 19151991Sheppo } 19161991Sheppo ldcp->ldc_status = istatus; 19171991Sheppo 19181991Sheppo rv = vgen_init_tbufs(ldcp); 19191991Sheppo if (rv != 0) { 19204647Sraghuram DWARN(vgenp, ldcp, "vgen_init_tbufs() failed\n"); 19211991Sheppo goto ldcinit_failed; 19221991Sheppo } 19231991Sheppo init_state |= ST_init_tbufs; 19241991Sheppo 19252748Slm66018 rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_ENABLE); 19262748Slm66018 if (rv != 0) { 19274647Sraghuram DWARN(vgenp, ldcp, "ldc_set_cb_mode failed: rv(%d)\n", rv); 19282748Slm66018 goto ldcinit_failed; 19292748Slm66018 } 19302748Slm66018 19312748Slm66018 init_state |= ST_cb_enable; 19322748Slm66018 19332109Slm66018 do { 19342109Slm66018 rv = ldc_up(ldcp->ldc_handle); 19352109Slm66018 if ((rv != 0) && (rv == EWOULDBLOCK)) { 19364647Sraghuram DBG2(vgenp, ldcp, "ldc_up err rv(%d)\n", rv); 19372109Slm66018 drv_usecwait(VGEN_LDC_UP_DELAY); 19382109Slm66018 } 19392109Slm66018 if (retries++ >= vgen_ldcup_retries) 19402109Slm66018 break; 19412109Slm66018 } while (rv == EWOULDBLOCK); 19421991Sheppo 19431991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 19442793Slm66018 if (istatus == LDC_UP) { 19454647Sraghuram DWARN(vgenp, ldcp, "status(%d) is UP\n", istatus); 19461991Sheppo } 19472793Slm66018 19481991Sheppo ldcp->ldc_status = istatus; 19491991Sheppo 19501991Sheppo /* initialize transmit watchdog timeout */ 19511991Sheppo ldcp->wd_tid = timeout(vgen_ldc_watchdog, (caddr_t)ldcp, 19521991Sheppo drv_usectohz(vnet_ldcwd_interval * 1000)); 19531991Sheppo 19542793Slm66018 ldcp->hphase = -1; 19551991Sheppo ldcp->flags |= CHANNEL_STARTED; 19561991Sheppo 19572793Slm66018 /* if channel is already UP - start handshake */ 19582793Slm66018 if (istatus == LDC_UP) { 19592793Slm66018 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 19602793Slm66018 if (ldcp->portp != vgenp->vsw_portp) { 19612793Slm66018 /* 19622793Slm66018 * modify fdb entry to use this port as the 19632793Slm66018 * channel is up, instead of going through the 19642793Slm66018 * vsw-port (see comments in vgen_port_init()) 19652793Slm66018 */ 19664647Sraghuram vnet_modify_fdb(vgenp->vnetp, 19672793Slm66018 (uint8_t *)&ldcp->portp->macaddr, 19682793Slm66018 vgen_tx, ldcp->portp, B_FALSE); 19692793Slm66018 } 19702793Slm66018 19712793Slm66018 /* Initialize local session id */ 19722793Slm66018 ldcp->local_sid = ddi_get_lbolt(); 19732793Slm66018 19742793Slm66018 /* clear peer session id */ 19752793Slm66018 ldcp->peer_sid = 0; 19762793Slm66018 ldcp->hretries = 0; 19772793Slm66018 19782793Slm66018 /* Initiate Handshake process with peer ldc endpoint */ 19792793Slm66018 vgen_reset_hphase(ldcp); 19802793Slm66018 19812793Slm66018 mutex_exit(&ldcp->tclock); 19822793Slm66018 mutex_exit(&ldcp->txlock); 19834647Sraghuram mutex_exit(&ldcp->wrlock); 19842793Slm66018 vgen_handshake(vh_nextphase(ldcp)); 19854647Sraghuram mutex_exit(&ldcp->rxlock); 19862793Slm66018 mutex_exit(&ldcp->cblock); 19872793Slm66018 } else { 19882793Slm66018 LDC_UNLOCK(ldcp); 19892793Slm66018 } 19902793Slm66018 19911991Sheppo return (DDI_SUCCESS); 19921991Sheppo 19931991Sheppo ldcinit_failed: 19942748Slm66018 if (init_state & ST_cb_enable) { 19952748Slm66018 (void) ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE); 19962748Slm66018 } 19971991Sheppo if (init_state & ST_init_tbufs) { 19981991Sheppo vgen_uninit_tbufs(ldcp); 19991991Sheppo } 20001991Sheppo if (init_state & ST_ldc_open) { 20011991Sheppo (void) ldc_close(ldcp->ldc_handle); 20021991Sheppo } 20031991Sheppo LDC_UNLOCK(ldcp); 20044647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 20051991Sheppo return (DDI_FAILURE); 20061991Sheppo } 20071991Sheppo 20081991Sheppo /* stop transmit/receive on the channel */ 20091991Sheppo static void 20101991Sheppo vgen_ldc_uninit(vgen_ldc_t *ldcp) 20111991Sheppo { 20124647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 20131991Sheppo int rv; 20141991Sheppo 20154647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 20161991Sheppo LDC_LOCK(ldcp); 20171991Sheppo 20181991Sheppo if ((ldcp->flags & CHANNEL_STARTED) == 0) { 20191991Sheppo LDC_UNLOCK(ldcp); 20204647Sraghuram DWARN(vgenp, ldcp, "CHANNEL_STARTED flag is not set\n"); 20211991Sheppo return; 20221991Sheppo } 20231991Sheppo 20241991Sheppo /* disable further callbacks */ 20251991Sheppo rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE); 20261991Sheppo if (rv != 0) { 20274647Sraghuram DWARN(vgenp, ldcp, "ldc_set_cb_mode failed\n"); 20281991Sheppo } 20291991Sheppo 20303653Snarayan /* 20313653Snarayan * clear handshake done bit and wait for pending tx and cb to finish. 20323653Snarayan * release locks before untimeout(9F) is invoked to cancel timeouts. 20333653Snarayan */ 20341991Sheppo ldcp->hphase &= ~(VH_DONE); 20351991Sheppo LDC_UNLOCK(ldcp); 20363653Snarayan 20373653Snarayan /* cancel handshake watchdog timeout */ 20383653Snarayan if (ldcp->htid) { 20393653Snarayan (void) untimeout(ldcp->htid); 20403653Snarayan ldcp->htid = 0; 20413653Snarayan } 20423653Snarayan 20433653Snarayan /* cancel transmit watchdog timeout */ 20441991Sheppo if (ldcp->wd_tid) { 20451991Sheppo (void) untimeout(ldcp->wd_tid); 20461991Sheppo ldcp->wd_tid = 0; 20471991Sheppo } 20481991Sheppo 20493653Snarayan drv_usecwait(1000); 20503653Snarayan 20513653Snarayan /* acquire locks again; any pending transmits and callbacks are done */ 20523653Snarayan LDC_LOCK(ldcp); 20533653Snarayan 20543653Snarayan vgen_reset_hphase(ldcp); 20553653Snarayan 20561991Sheppo vgen_uninit_tbufs(ldcp); 20571991Sheppo 20581991Sheppo rv = ldc_close(ldcp->ldc_handle); 20591991Sheppo if (rv != 0) { 20604647Sraghuram DWARN(vgenp, ldcp, "ldc_close err\n"); 20611991Sheppo } 20621991Sheppo ldcp->ldc_status = LDC_INIT; 20631991Sheppo ldcp->flags &= ~(CHANNEL_STARTED); 20641991Sheppo 20651991Sheppo LDC_UNLOCK(ldcp); 20661991Sheppo 20674647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 20681991Sheppo } 20691991Sheppo 20701991Sheppo /* Initialize the transmit buffer ring for the channel */ 20711991Sheppo static int 20721991Sheppo vgen_init_tbufs(vgen_ldc_t *ldcp) 20731991Sheppo { 20741991Sheppo vgen_private_desc_t *tbufp; 20751991Sheppo vnet_public_desc_t *txdp; 20761991Sheppo vio_dring_entry_hdr_t *hdrp; 20771991Sheppo int i; 20781991Sheppo int rv; 20792109Slm66018 caddr_t datap = NULL; 20802109Slm66018 int ci; 20812109Slm66018 uint32_t ncookies; 20821991Sheppo 20831991Sheppo bzero(ldcp->tbufp, sizeof (*tbufp) * (ldcp->num_txds)); 20841991Sheppo bzero(ldcp->txdp, sizeof (*txdp) * (ldcp->num_txds)); 20851991Sheppo 20864647Sraghuram datap = kmem_zalloc(ldcp->num_txds * VGEN_TXDBLK_SZ, KM_SLEEP); 20872109Slm66018 ldcp->tx_datap = datap; 20882109Slm66018 20891991Sheppo /* 20902109Slm66018 * for each private descriptor, allocate a ldc mem_handle which is 20911991Sheppo * required to map the data during transmit, set the flags 20921991Sheppo * to free (available for use by transmit routine). 20931991Sheppo */ 20941991Sheppo 20951991Sheppo for (i = 0; i < ldcp->num_txds; i++) { 20962109Slm66018 20971991Sheppo tbufp = &(ldcp->tbufp[i]); 20981991Sheppo rv = ldc_mem_alloc_handle(ldcp->ldc_handle, 20994650Sraghuram &(tbufp->memhandle)); 21001991Sheppo if (rv) { 21011991Sheppo tbufp->memhandle = 0; 21021991Sheppo goto init_tbufs_failed; 21031991Sheppo } 21042109Slm66018 21052109Slm66018 /* 21062109Slm66018 * bind ldc memhandle to the corresponding transmit buffer. 21072109Slm66018 */ 21082109Slm66018 ci = ncookies = 0; 21092109Slm66018 rv = ldc_mem_bind_handle(tbufp->memhandle, 21104647Sraghuram (caddr_t)datap, VGEN_TXDBLK_SZ, LDC_SHADOW_MAP, 21112109Slm66018 LDC_MEM_R, &(tbufp->memcookie[ci]), &ncookies); 21122109Slm66018 if (rv != 0) { 21132109Slm66018 goto init_tbufs_failed; 21142109Slm66018 } 21152109Slm66018 21162109Slm66018 /* 21172109Slm66018 * successful in binding the handle to tx data buffer. 21182109Slm66018 * set datap in the private descr to this buffer. 21192109Slm66018 */ 21202109Slm66018 tbufp->datap = datap; 21212109Slm66018 21222109Slm66018 if ((ncookies == 0) || 21234650Sraghuram (ncookies > MAX_COOKIES)) { 21242109Slm66018 goto init_tbufs_failed; 21252109Slm66018 } 21262109Slm66018 21272109Slm66018 for (ci = 1; ci < ncookies; ci++) { 21282109Slm66018 rv = ldc_mem_nextcookie(tbufp->memhandle, 21294650Sraghuram &(tbufp->memcookie[ci])); 21302109Slm66018 if (rv != 0) { 21312109Slm66018 goto init_tbufs_failed; 21322109Slm66018 } 21332109Slm66018 } 21342109Slm66018 21352109Slm66018 tbufp->ncookies = ncookies; 21364647Sraghuram datap += VGEN_TXDBLK_SZ; 21372109Slm66018 21381991Sheppo tbufp->flags = VGEN_PRIV_DESC_FREE; 21391991Sheppo txdp = &(ldcp->txdp[i]); 21401991Sheppo hdrp = &txdp->hdr; 21411991Sheppo hdrp->dstate = VIO_DESC_FREE; 21421991Sheppo hdrp->ack = B_FALSE; 21431991Sheppo tbufp->descp = txdp; 21442109Slm66018 21451991Sheppo } 21461991Sheppo 21471991Sheppo /* reset tbuf walking pointers */ 21481991Sheppo ldcp->next_tbufp = ldcp->tbufp; 21491991Sheppo ldcp->cur_tbufp = ldcp->tbufp; 21501991Sheppo 21511991Sheppo /* initialize tx seqnum and index */ 21521991Sheppo ldcp->next_txseq = VNET_ISS; 21531991Sheppo ldcp->next_txi = 0; 21541991Sheppo 21552336Snarayan ldcp->resched_peer = B_TRUE; 21564647Sraghuram ldcp->resched_peer_txi = 0; 21572336Snarayan 21581991Sheppo return (DDI_SUCCESS); 21591991Sheppo 21601991Sheppo init_tbufs_failed:; 21611991Sheppo vgen_uninit_tbufs(ldcp); 21621991Sheppo return (DDI_FAILURE); 21631991Sheppo } 21641991Sheppo 21651991Sheppo /* Uninitialize transmit buffer ring for the channel */ 21661991Sheppo static void 21671991Sheppo vgen_uninit_tbufs(vgen_ldc_t *ldcp) 21681991Sheppo { 21691991Sheppo vgen_private_desc_t *tbufp = ldcp->tbufp; 21701991Sheppo int i; 21711991Sheppo 21721991Sheppo /* for each tbuf (priv_desc), free ldc mem_handle */ 21731991Sheppo for (i = 0; i < ldcp->num_txds; i++) { 21741991Sheppo 21751991Sheppo tbufp = &(ldcp->tbufp[i]); 21761991Sheppo 21772109Slm66018 if (tbufp->datap) { /* if bound to a ldc memhandle */ 21781991Sheppo (void) ldc_mem_unbind_handle(tbufp->memhandle); 21792109Slm66018 tbufp->datap = NULL; 21801991Sheppo } 21811991Sheppo if (tbufp->memhandle) { 21821991Sheppo (void) ldc_mem_free_handle(tbufp->memhandle); 21831991Sheppo tbufp->memhandle = 0; 21841991Sheppo } 21851991Sheppo } 21861991Sheppo 21872109Slm66018 if (ldcp->tx_datap) { 21882109Slm66018 /* prealloc'd tx data buffer */ 21894647Sraghuram kmem_free(ldcp->tx_datap, ldcp->num_txds * VGEN_TXDBLK_SZ); 21902109Slm66018 ldcp->tx_datap = NULL; 21912109Slm66018 } 21922109Slm66018 21932748Slm66018 bzero(ldcp->tbufp, sizeof (vgen_private_desc_t) * (ldcp->num_txds)); 21942748Slm66018 bzero(ldcp->txdp, sizeof (vnet_public_desc_t) * (ldcp->num_txds)); 21951991Sheppo } 21961991Sheppo 21971991Sheppo /* clobber tx descriptor ring */ 21981991Sheppo static void 21991991Sheppo vgen_clobber_tbufs(vgen_ldc_t *ldcp) 22001991Sheppo { 22011991Sheppo vnet_public_desc_t *txdp; 22021991Sheppo vgen_private_desc_t *tbufp; 22034647Sraghuram vio_dring_entry_hdr_t *hdrp; 22044647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 22051991Sheppo int i; 22061991Sheppo #ifdef DEBUG 22071991Sheppo int ndone = 0; 22081991Sheppo #endif 22091991Sheppo 22101991Sheppo for (i = 0; i < ldcp->num_txds; i++) { 22111991Sheppo 22121991Sheppo tbufp = &(ldcp->tbufp[i]); 22131991Sheppo txdp = tbufp->descp; 22141991Sheppo hdrp = &txdp->hdr; 22151991Sheppo 22161991Sheppo if (tbufp->flags & VGEN_PRIV_DESC_BUSY) { 22171991Sheppo tbufp->flags = VGEN_PRIV_DESC_FREE; 22181991Sheppo #ifdef DEBUG 22191991Sheppo if (hdrp->dstate == VIO_DESC_DONE) 22201991Sheppo ndone++; 22211991Sheppo #endif 22221991Sheppo hdrp->dstate = VIO_DESC_FREE; 22231991Sheppo hdrp->ack = B_FALSE; 22241991Sheppo } 22251991Sheppo } 22261991Sheppo /* reset tbuf walking pointers */ 22271991Sheppo ldcp->next_tbufp = ldcp->tbufp; 22281991Sheppo ldcp->cur_tbufp = ldcp->tbufp; 22291991Sheppo 22301991Sheppo /* reset tx seqnum and index */ 22311991Sheppo ldcp->next_txseq = VNET_ISS; 22321991Sheppo ldcp->next_txi = 0; 22332336Snarayan 22342336Snarayan ldcp->resched_peer = B_TRUE; 22354647Sraghuram ldcp->resched_peer_txi = 0; 22364647Sraghuram 22374647Sraghuram DBG2(vgenp, ldcp, "num descrs done (%d)\n", ndone); 22381991Sheppo } 22391991Sheppo 22401991Sheppo /* clobber receive descriptor ring */ 22411991Sheppo static void 22421991Sheppo vgen_clobber_rxds(vgen_ldc_t *ldcp) 22431991Sheppo { 22441991Sheppo ldcp->rx_dhandle = 0; 22451991Sheppo bzero(&ldcp->rx_dcookie, sizeof (ldcp->rx_dcookie)); 22461991Sheppo ldcp->rxdp = NULL; 22471991Sheppo ldcp->next_rxi = 0; 22481991Sheppo ldcp->num_rxds = 0; 22491991Sheppo ldcp->next_rxseq = VNET_ISS; 22501991Sheppo } 22511991Sheppo 22521991Sheppo /* initialize receive descriptor ring */ 22531991Sheppo static int 22541991Sheppo vgen_init_rxds(vgen_ldc_t *ldcp, uint32_t num_desc, uint32_t desc_size, 22551991Sheppo ldc_mem_cookie_t *dcookie, uint32_t ncookies) 22561991Sheppo { 22571991Sheppo int rv; 22581991Sheppo ldc_mem_info_t minfo; 22591991Sheppo 22601991Sheppo rv = ldc_mem_dring_map(ldcp->ldc_handle, dcookie, ncookies, num_desc, 22611991Sheppo desc_size, LDC_SHADOW_MAP, &(ldcp->rx_dhandle)); 22621991Sheppo if (rv != 0) { 22631991Sheppo return (DDI_FAILURE); 22641991Sheppo } 22651991Sheppo 22661991Sheppo /* 22671991Sheppo * sucessfully mapped, now try to 22681991Sheppo * get info about the mapped dring 22691991Sheppo */ 22701991Sheppo rv = ldc_mem_dring_info(ldcp->rx_dhandle, &minfo); 22711991Sheppo if (rv != 0) { 22721991Sheppo (void) ldc_mem_dring_unmap(ldcp->rx_dhandle); 22731991Sheppo return (DDI_FAILURE); 22741991Sheppo } 22751991Sheppo 22761991Sheppo /* 22771991Sheppo * save ring address, number of descriptors. 22781991Sheppo */ 22791991Sheppo ldcp->rxdp = (vnet_public_desc_t *)(minfo.vaddr); 22801991Sheppo bcopy(dcookie, &(ldcp->rx_dcookie), sizeof (*dcookie)); 22811991Sheppo ldcp->num_rxdcookies = ncookies; 22821991Sheppo ldcp->num_rxds = num_desc; 22831991Sheppo ldcp->next_rxi = 0; 22841991Sheppo ldcp->next_rxseq = VNET_ISS; 22851991Sheppo 22861991Sheppo return (DDI_SUCCESS); 22871991Sheppo } 22881991Sheppo 22891991Sheppo /* get channel statistics */ 22901991Sheppo static uint64_t 22912311Sseb vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat) 22921991Sheppo { 22931991Sheppo vgen_stats_t *statsp; 22941991Sheppo uint64_t val; 22951991Sheppo 22961991Sheppo val = 0; 22971991Sheppo statsp = ldcp->statsp; 22981991Sheppo switch (stat) { 22991991Sheppo 23001991Sheppo case MAC_STAT_MULTIRCV: 23011991Sheppo val = statsp->multircv; 23021991Sheppo break; 23031991Sheppo 23041991Sheppo case MAC_STAT_BRDCSTRCV: 23051991Sheppo val = statsp->brdcstrcv; 23061991Sheppo break; 23071991Sheppo 23081991Sheppo case MAC_STAT_MULTIXMT: 23091991Sheppo val = statsp->multixmt; 23101991Sheppo break; 23111991Sheppo 23121991Sheppo case MAC_STAT_BRDCSTXMT: 23131991Sheppo val = statsp->brdcstxmt; 23141991Sheppo break; 23151991Sheppo 23161991Sheppo case MAC_STAT_NORCVBUF: 23171991Sheppo val = statsp->norcvbuf; 23181991Sheppo break; 23191991Sheppo 23201991Sheppo case MAC_STAT_IERRORS: 23211991Sheppo val = statsp->ierrors; 23221991Sheppo break; 23231991Sheppo 23241991Sheppo case MAC_STAT_NOXMTBUF: 23251991Sheppo val = statsp->noxmtbuf; 23261991Sheppo break; 23271991Sheppo 23281991Sheppo case MAC_STAT_OERRORS: 23291991Sheppo val = statsp->oerrors; 23301991Sheppo break; 23311991Sheppo 23321991Sheppo case MAC_STAT_COLLISIONS: 23331991Sheppo break; 23341991Sheppo 23351991Sheppo case MAC_STAT_RBYTES: 23361991Sheppo val = statsp->rbytes; 23371991Sheppo break; 23381991Sheppo 23391991Sheppo case MAC_STAT_IPACKETS: 23401991Sheppo val = statsp->ipackets; 23411991Sheppo break; 23421991Sheppo 23431991Sheppo case MAC_STAT_OBYTES: 23441991Sheppo val = statsp->obytes; 23451991Sheppo break; 23461991Sheppo 23471991Sheppo case MAC_STAT_OPACKETS: 23481991Sheppo val = statsp->opackets; 23491991Sheppo break; 23501991Sheppo 23511991Sheppo /* stats not relevant to ldc, return 0 */ 23521991Sheppo case MAC_STAT_IFSPEED: 23532311Sseb case ETHER_STAT_ALIGN_ERRORS: 23542311Sseb case ETHER_STAT_FCS_ERRORS: 23552311Sseb case ETHER_STAT_FIRST_COLLISIONS: 23562311Sseb case ETHER_STAT_MULTI_COLLISIONS: 23572311Sseb case ETHER_STAT_DEFER_XMTS: 23582311Sseb case ETHER_STAT_TX_LATE_COLLISIONS: 23592311Sseb case ETHER_STAT_EX_COLLISIONS: 23602311Sseb case ETHER_STAT_MACXMT_ERRORS: 23612311Sseb case ETHER_STAT_CARRIER_ERRORS: 23622311Sseb case ETHER_STAT_TOOLONG_ERRORS: 23632311Sseb case ETHER_STAT_XCVR_ADDR: 23642311Sseb case ETHER_STAT_XCVR_ID: 23652311Sseb case ETHER_STAT_XCVR_INUSE: 23662311Sseb case ETHER_STAT_CAP_1000FDX: 23672311Sseb case ETHER_STAT_CAP_1000HDX: 23682311Sseb case ETHER_STAT_CAP_100FDX: 23692311Sseb case ETHER_STAT_CAP_100HDX: 23702311Sseb case ETHER_STAT_CAP_10FDX: 23712311Sseb case ETHER_STAT_CAP_10HDX: 23722311Sseb case ETHER_STAT_CAP_ASMPAUSE: 23732311Sseb case ETHER_STAT_CAP_PAUSE: 23742311Sseb case ETHER_STAT_CAP_AUTONEG: 23752311Sseb case ETHER_STAT_ADV_CAP_1000FDX: 23762311Sseb case ETHER_STAT_ADV_CAP_1000HDX: 23772311Sseb case ETHER_STAT_ADV_CAP_100FDX: 23782311Sseb case ETHER_STAT_ADV_CAP_100HDX: 23792311Sseb case ETHER_STAT_ADV_CAP_10FDX: 23802311Sseb case ETHER_STAT_ADV_CAP_10HDX: 23812311Sseb case ETHER_STAT_ADV_CAP_ASMPAUSE: 23822311Sseb case ETHER_STAT_ADV_CAP_PAUSE: 23832311Sseb case ETHER_STAT_ADV_CAP_AUTONEG: 23842311Sseb case ETHER_STAT_LP_CAP_1000FDX: 23852311Sseb case ETHER_STAT_LP_CAP_1000HDX: 23862311Sseb case ETHER_STAT_LP_CAP_100FDX: 23872311Sseb case ETHER_STAT_LP_CAP_100HDX: 23882311Sseb case ETHER_STAT_LP_CAP_10FDX: 23892311Sseb case ETHER_STAT_LP_CAP_10HDX: 23902311Sseb case ETHER_STAT_LP_CAP_ASMPAUSE: 23912311Sseb case ETHER_STAT_LP_CAP_PAUSE: 23922311Sseb case ETHER_STAT_LP_CAP_AUTONEG: 23932311Sseb case ETHER_STAT_LINK_ASMPAUSE: 23942311Sseb case ETHER_STAT_LINK_PAUSE: 23952311Sseb case ETHER_STAT_LINK_AUTONEG: 23962311Sseb case ETHER_STAT_LINK_DUPLEX: 23971991Sheppo default: 23981991Sheppo val = 0; 23991991Sheppo break; 24001991Sheppo 24011991Sheppo } 24021991Sheppo return (val); 24031991Sheppo } 24041991Sheppo 24052793Slm66018 /* 24062793Slm66018 * LDC channel is UP, start handshake process with peer. 24072793Slm66018 * Flag tells vnet_modify_fdb() about the context: set to B_TRUE if this 24082793Slm66018 * function is being called from transmit routine, otherwise B_FALSE. 24092793Slm66018 */ 24102793Slm66018 static void 24112793Slm66018 vgen_handle_evt_up(vgen_ldc_t *ldcp, boolean_t flag) 24122793Slm66018 { 24132793Slm66018 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 24144647Sraghuram 24154647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 24162793Slm66018 24172793Slm66018 ASSERT(MUTEX_HELD(&ldcp->cblock)); 24182793Slm66018 24192793Slm66018 if (ldcp->portp != vgenp->vsw_portp) { 24202793Slm66018 /* 24212793Slm66018 * modify fdb entry to use this port as the 24222793Slm66018 * channel is up, instead of going through the 24232793Slm66018 * vsw-port (see comments in vgen_port_init()) 24242793Slm66018 */ 24254647Sraghuram vnet_modify_fdb(vgenp->vnetp, (uint8_t *)&ldcp->portp->macaddr, 24262793Slm66018 vgen_tx, ldcp->portp, flag); 24272793Slm66018 } 24282793Slm66018 24292793Slm66018 /* Initialize local session id */ 24302793Slm66018 ldcp->local_sid = ddi_get_lbolt(); 24312793Slm66018 24322793Slm66018 /* clear peer session id */ 24332793Slm66018 ldcp->peer_sid = 0; 24342793Slm66018 ldcp->hretries = 0; 24352793Slm66018 24362793Slm66018 if (ldcp->hphase != VH_PHASE0) { 24372793Slm66018 vgen_handshake_reset(ldcp); 24382793Slm66018 } 24392793Slm66018 24402793Slm66018 /* Initiate Handshake process with peer ldc endpoint */ 24412793Slm66018 vgen_handshake(vh_nextphase(ldcp)); 24422793Slm66018 24434647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 24442793Slm66018 } 24452793Slm66018 24462793Slm66018 /* 24472793Slm66018 * LDC channel is Reset, terminate connection with peer and try to 24482793Slm66018 * bring the channel up again. 24492793Slm66018 * Flag tells vnet_modify_fdb() about the context: set to B_TRUE if this 24502793Slm66018 * function is being called from transmit routine, otherwise B_FALSE. 24512793Slm66018 */ 24522793Slm66018 static void 24532793Slm66018 vgen_handle_evt_reset(vgen_ldc_t *ldcp, boolean_t flag) 24542793Slm66018 { 24552793Slm66018 ldc_status_t istatus; 24562793Slm66018 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 24572793Slm66018 int rv; 24582793Slm66018 24594647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 24602793Slm66018 24612793Slm66018 ASSERT(MUTEX_HELD(&ldcp->cblock)); 24622793Slm66018 24632793Slm66018 if ((ldcp->portp != vgenp->vsw_portp) && 24644650Sraghuram (vgenp->vsw_portp != NULL)) { 24652793Slm66018 /* 24662793Slm66018 * modify fdb entry to use vsw-port as the 24672793Slm66018 * channel is reset and we don't have a direct 24682793Slm66018 * link to the destination (see comments 24692793Slm66018 * in vgen_port_init()). 24702793Slm66018 */ 24714647Sraghuram vnet_modify_fdb(vgenp->vnetp, (uint8_t *)&ldcp->portp->macaddr, 24722793Slm66018 vgen_tx, vgenp->vsw_portp, flag); 24732793Slm66018 } 24742793Slm66018 24752793Slm66018 if (ldcp->hphase != VH_PHASE0) { 24762793Slm66018 vgen_handshake_reset(ldcp); 24772793Slm66018 } 24782793Slm66018 24792793Slm66018 /* try to bring the channel up */ 24802793Slm66018 rv = ldc_up(ldcp->ldc_handle); 24812793Slm66018 if (rv != 0) { 24824647Sraghuram DWARN(vgenp, ldcp, "ldc_up err rv(%d)\n", rv); 24832793Slm66018 } 24842793Slm66018 24852793Slm66018 if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 24864647Sraghuram DWARN(vgenp, ldcp, "ldc_status err\n"); 24872793Slm66018 } else { 24882793Slm66018 ldcp->ldc_status = istatus; 24892793Slm66018 } 24902793Slm66018 24912793Slm66018 /* if channel is already UP - restart handshake */ 24922793Slm66018 if (ldcp->ldc_status == LDC_UP) { 24932793Slm66018 vgen_handle_evt_up(ldcp, flag); 24942793Slm66018 } 24952793Slm66018 24964647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 24972793Slm66018 } 24982793Slm66018 24991991Sheppo /* Interrupt handler for the channel */ 25001991Sheppo static uint_t 25011991Sheppo vgen_ldc_cb(uint64_t event, caddr_t arg) 25021991Sheppo { 25031991Sheppo _NOTE(ARGUNUSED(event)) 25041991Sheppo vgen_ldc_t *ldcp; 25051991Sheppo vgen_t *vgenp; 25061991Sheppo ldc_status_t istatus; 25071991Sheppo mblk_t *bp = NULL; 25081991Sheppo vgen_stats_t *statsp; 25091991Sheppo 25101991Sheppo ldcp = (vgen_ldc_t *)arg; 25111991Sheppo vgenp = LDC_TO_VGEN(ldcp); 25121991Sheppo statsp = ldcp->statsp; 25131991Sheppo 25144647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 25151991Sheppo 25161991Sheppo mutex_enter(&ldcp->cblock); 25171991Sheppo statsp->callbacks++; 25181991Sheppo if ((ldcp->ldc_status == LDC_INIT) || (ldcp->ldc_handle == NULL)) { 25194647Sraghuram DWARN(vgenp, ldcp, "status(%d) is LDC_INIT\n", 25204647Sraghuram ldcp->ldc_status); 25211991Sheppo mutex_exit(&ldcp->cblock); 25221991Sheppo return (LDC_SUCCESS); 25231991Sheppo } 25241991Sheppo 25252793Slm66018 /* 25262793Slm66018 * NOTE: not using switch() as event could be triggered by 25272793Slm66018 * a state change and a read request. Also the ordering of the 25282793Slm66018 * check for the event types is deliberate. 25292793Slm66018 */ 25302793Slm66018 if (event & LDC_EVT_UP) { 25312793Slm66018 if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 25324647Sraghuram DWARN(vgenp, ldcp, "ldc_status err\n"); 25332793Slm66018 } else { 25341991Sheppo ldcp->ldc_status = istatus; 25352793Slm66018 } 25362793Slm66018 ASSERT(ldcp->ldc_status == LDC_UP); 25374647Sraghuram DWARN(vgenp, ldcp, "event(%lx) UP, status(%d)\n", 25384647Sraghuram event, ldcp->ldc_status); 25392793Slm66018 25402793Slm66018 vgen_handle_evt_up(ldcp, B_FALSE); 25412793Slm66018 25422793Slm66018 ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0); 25432793Slm66018 } 25442793Slm66018 25452793Slm66018 if (event & LDC_EVT_READ) { 25464647Sraghuram DBG2(vgenp, ldcp, "event(%lx) READ, status(%d)\n", 25474647Sraghuram event, ldcp->ldc_status); 25482793Slm66018 25492793Slm66018 ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0); 25504647Sraghuram 25514647Sraghuram if (ldcp->rcv_thread != NULL) { 25524647Sraghuram /* 25534647Sraghuram * If the receive thread is enabled, then 25544647Sraghuram * wakeup the receive thread to process the 25554647Sraghuram * LDC messages. 25564647Sraghuram */ 25574647Sraghuram mutex_exit(&ldcp->cblock); 25584647Sraghuram mutex_enter(&ldcp->rcv_thr_lock); 25594647Sraghuram if (!(ldcp->rcv_thr_flags & VGEN_WTHR_DATARCVD)) { 25604647Sraghuram ldcp->rcv_thr_flags |= VGEN_WTHR_DATARCVD; 25614647Sraghuram cv_signal(&ldcp->rcv_thr_cv); 25624647Sraghuram } 25634647Sraghuram mutex_exit(&ldcp->rcv_thr_lock); 25644647Sraghuram mutex_enter(&ldcp->cblock); 25654647Sraghuram } else { 25664647Sraghuram vgen_handle_evt_read(ldcp); 25674647Sraghuram bp = ldcp->rcv_mhead; 25684647Sraghuram ldcp->rcv_mhead = ldcp->rcv_mtail = NULL; 25694647Sraghuram } 25702793Slm66018 } 25712793Slm66018 25722793Slm66018 if (event & (LDC_EVT_RESET | LDC_EVT_DOWN)) { 25732793Slm66018 if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 25744647Sraghuram DWARN(vgenp, ldcp, "ldc_status error\n"); 25752793Slm66018 } else { 25762793Slm66018 ldcp->ldc_status = istatus; 25771991Sheppo } 25784647Sraghuram DWARN(vgenp, ldcp, "event(%lx) RESET/DOWN, status(%d)\n", 25794647Sraghuram event, ldcp->ldc_status); 25802793Slm66018 25812793Slm66018 vgen_handle_evt_reset(ldcp, B_FALSE); 25821991Sheppo } 25832793Slm66018 mutex_exit(&ldcp->cblock); 25844647Sraghuram 25854647Sraghuram /* send up the received packets to MAC layer */ 25864647Sraghuram if (bp != NULL) { 25874647Sraghuram vnet_rx(vgenp->vnetp, NULL, bp); 25884647Sraghuram } 25894647Sraghuram 25904647Sraghuram if (ldcp->cancel_htid) { 25914647Sraghuram /* 25924647Sraghuram * Cancel handshake timer. 25934647Sraghuram * untimeout(9F) will not return until the pending callback is 25944647Sraghuram * cancelled or has run. No problems will result from calling 25954647Sraghuram * untimeout if the handler has already completed. 25964647Sraghuram * If the timeout handler did run, then it would just 25974647Sraghuram * return as cancel_htid is set. 25984647Sraghuram */ 25994647Sraghuram (void) untimeout(ldcp->cancel_htid); 26004647Sraghuram ldcp->cancel_htid = 0; 26014647Sraghuram } 26024647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 26034647Sraghuram 26044647Sraghuram return (LDC_SUCCESS); 26054647Sraghuram } 26064647Sraghuram 26074647Sraghuram static void 26084647Sraghuram vgen_handle_evt_read(vgen_ldc_t *ldcp) 26094647Sraghuram { 26104647Sraghuram int rv; 26114647Sraghuram uint64_t ldcmsg[7]; 26124647Sraghuram size_t msglen; 26134647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 26144647Sraghuram vio_msg_tag_t *tagp; 26154647Sraghuram ldc_status_t istatus; 26164647Sraghuram boolean_t has_data; 26174647Sraghuram 26184647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 26194647Sraghuram 26204647Sraghuram /* 26214647Sraghuram * If the receive thread is enabled, then the cblock 26224647Sraghuram * need to be acquired here. If not, the vgen_ldc_cb() 26234647Sraghuram * calls this function with cblock held already. 26244647Sraghuram */ 26254647Sraghuram if (ldcp->rcv_thread != NULL) { 26264647Sraghuram mutex_enter(&ldcp->cblock); 26274647Sraghuram } else { 26284647Sraghuram ASSERT(MUTEX_HELD(&ldcp->cblock)); 26294647Sraghuram } 26304647Sraghuram 26314647Sraghuram vgen_evt_read: 26321991Sheppo do { 26331991Sheppo msglen = sizeof (ldcmsg); 26341991Sheppo rv = ldc_read(ldcp->ldc_handle, (caddr_t)&ldcmsg, &msglen); 26351991Sheppo 26361991Sheppo if (rv != 0) { 26374647Sraghuram DWARN(vgenp, ldcp, "err rv(%d) len(%d)\n", 26384647Sraghuram rv, msglen); 26392793Slm66018 if (rv == ECONNRESET) 26404647Sraghuram goto vgen_evtread_error; 26411991Sheppo break; 26421991Sheppo } 26431991Sheppo if (msglen == 0) { 26444647Sraghuram DBG2(vgenp, ldcp, "ldc_read NODATA"); 26451991Sheppo break; 26461991Sheppo } 26474647Sraghuram DBG2(vgenp, ldcp, "ldc_read msglen(%d)", msglen); 26481991Sheppo 26491991Sheppo tagp = (vio_msg_tag_t *)ldcmsg; 26501991Sheppo 26511991Sheppo if (ldcp->peer_sid) { 26521991Sheppo /* 26531991Sheppo * check sid only after we have received peer's sid 26541991Sheppo * in the version negotiate msg. 26551991Sheppo */ 26561991Sheppo #ifdef DEBUG 26571991Sheppo if (vgen_hdbg & HDBG_BAD_SID) { 26581991Sheppo /* simulate bad sid condition */ 26591991Sheppo tagp->vio_sid = 0; 26601991Sheppo vgen_hdbg &= ~(HDBG_BAD_SID); 26611991Sheppo } 26621991Sheppo #endif 26632793Slm66018 rv = vgen_check_sid(ldcp, tagp); 26642793Slm66018 if (rv != VGEN_SUCCESS) { 26651991Sheppo /* 26661991Sheppo * If sid mismatch is detected, 26671991Sheppo * reset the channel. 26681991Sheppo */ 26691991Sheppo ldcp->need_ldc_reset = B_TRUE; 26704647Sraghuram goto vgen_evtread_error; 26711991Sheppo } 26721991Sheppo } 26731991Sheppo 26741991Sheppo switch (tagp->vio_msgtype) { 26751991Sheppo case VIO_TYPE_CTRL: 26762793Slm66018 rv = vgen_handle_ctrlmsg(ldcp, tagp); 26771991Sheppo break; 26781991Sheppo 26791991Sheppo case VIO_TYPE_DATA: 26804647Sraghuram rv = vgen_handle_datamsg(ldcp, tagp); 26811991Sheppo break; 26821991Sheppo 26831991Sheppo case VIO_TYPE_ERR: 26841991Sheppo vgen_handle_errmsg(ldcp, tagp); 26851991Sheppo break; 26861991Sheppo 26871991Sheppo default: 26884647Sraghuram DWARN(vgenp, ldcp, "Unknown VIO_TYPE(%x)\n", 26894647Sraghuram tagp->vio_msgtype); 26901991Sheppo break; 26911991Sheppo } 26921991Sheppo 26934647Sraghuram /* 26944647Sraghuram * If an error is encountered, stop processing and 26954647Sraghuram * handle the error. 26964647Sraghuram */ 26974647Sraghuram if (rv != 0) { 26984647Sraghuram goto vgen_evtread_error; 26992793Slm66018 } 27002793Slm66018 27011991Sheppo } while (msglen); 27021991Sheppo 27034647Sraghuram /* check once more before exiting */ 27044647Sraghuram rv = ldc_chkq(ldcp->ldc_handle, &has_data); 27054647Sraghuram if ((rv == 0) && (has_data == B_TRUE)) { 27064647Sraghuram DTRACE_PROBE(vgen_chkq); 27074647Sraghuram goto vgen_evt_read; 27084647Sraghuram } 27094647Sraghuram 27104647Sraghuram vgen_evtread_error: 27114647Sraghuram if (rv == ECONNRESET) { 27124647Sraghuram if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 27134647Sraghuram DWARN(vgenp, ldcp, "ldc_status err\n"); 27144647Sraghuram } else { 27154647Sraghuram ldcp->ldc_status = istatus; 27164647Sraghuram } 27174647Sraghuram vgen_handle_evt_reset(ldcp, B_FALSE); 27184647Sraghuram } else if (rv) { 27194647Sraghuram vgen_handshake_retry(ldcp); 27204647Sraghuram } 27214647Sraghuram 27224647Sraghuram /* 27234647Sraghuram * If the receive thread is not enabled, then cancel the 27244647Sraghuram * handshake timeout here. 27254647Sraghuram */ 27264647Sraghuram if (ldcp->rcv_thread != NULL) { 27274647Sraghuram mutex_exit(&ldcp->cblock); 27284647Sraghuram if (ldcp->cancel_htid) { 27294647Sraghuram /* 27304647Sraghuram * Cancel handshake timer. untimeout(9F) will 27314647Sraghuram * not return until the pending callback is cancelled 27324647Sraghuram * or has run. No problems will result from calling 27334647Sraghuram * untimeout if the handler has already completed. 27344647Sraghuram * If the timeout handler did run, then it would just 27354647Sraghuram * return as cancel_htid is set. 27364647Sraghuram */ 27374647Sraghuram (void) untimeout(ldcp->cancel_htid); 27384647Sraghuram ldcp->cancel_htid = 0; 27394647Sraghuram } 27404647Sraghuram } 27414647Sraghuram 27424647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 27431991Sheppo } 27441991Sheppo 27451991Sheppo /* vgen handshake functions */ 27461991Sheppo 27471991Sheppo /* change the hphase for the channel to the next phase */ 27481991Sheppo static vgen_ldc_t * 27491991Sheppo vh_nextphase(vgen_ldc_t *ldcp) 27501991Sheppo { 27511991Sheppo if (ldcp->hphase == VH_PHASE3) { 27521991Sheppo ldcp->hphase = VH_DONE; 27531991Sheppo } else { 27541991Sheppo ldcp->hphase++; 27551991Sheppo } 27561991Sheppo return (ldcp); 27571991Sheppo } 27581991Sheppo 27591991Sheppo /* 27601991Sheppo * Check whether the given version is supported or not and 27611991Sheppo * return VGEN_SUCCESS if supported. 27621991Sheppo */ 27631991Sheppo static int 27641991Sheppo vgen_supported_version(vgen_ldc_t *ldcp, uint16_t ver_major, 27651991Sheppo uint16_t ver_minor) 27661991Sheppo { 27671991Sheppo vgen_ver_t *versions = ldcp->vgen_versions; 27681991Sheppo int i = 0; 27691991Sheppo 27701991Sheppo while (i < VGEN_NUM_VER) { 27711991Sheppo if ((versions[i].ver_major == 0) && 27721991Sheppo (versions[i].ver_minor == 0)) { 27731991Sheppo break; 27741991Sheppo } 27751991Sheppo if ((versions[i].ver_major == ver_major) && 27764650Sraghuram (versions[i].ver_minor == ver_minor)) { 27771991Sheppo return (VGEN_SUCCESS); 27781991Sheppo } 27791991Sheppo i++; 27801991Sheppo } 27811991Sheppo return (VGEN_FAILURE); 27821991Sheppo } 27831991Sheppo 27841991Sheppo /* 27851991Sheppo * Given a version, return VGEN_SUCCESS if a lower version is supported. 27861991Sheppo */ 27871991Sheppo static int 27881991Sheppo vgen_next_version(vgen_ldc_t *ldcp, vgen_ver_t *verp) 27891991Sheppo { 27901991Sheppo vgen_ver_t *versions = ldcp->vgen_versions; 27911991Sheppo int i = 0; 27921991Sheppo 27931991Sheppo while (i < VGEN_NUM_VER) { 27941991Sheppo if ((versions[i].ver_major == 0) && 27951991Sheppo (versions[i].ver_minor == 0)) { 27961991Sheppo break; 27971991Sheppo } 27981991Sheppo /* 27991991Sheppo * if we support a lower minor version within the same major 28001991Sheppo * version, or if we support a lower major version, 28011991Sheppo * update the verp parameter with this lower version and 28021991Sheppo * return success. 28031991Sheppo */ 28041991Sheppo if (((versions[i].ver_major == verp->ver_major) && 28054650Sraghuram (versions[i].ver_minor < verp->ver_minor)) || 28064650Sraghuram (versions[i].ver_major < verp->ver_major)) { 28074650Sraghuram verp->ver_major = versions[i].ver_major; 28084650Sraghuram verp->ver_minor = versions[i].ver_minor; 28094650Sraghuram return (VGEN_SUCCESS); 28101991Sheppo } 28111991Sheppo i++; 28121991Sheppo } 28131991Sheppo 28141991Sheppo return (VGEN_FAILURE); 28151991Sheppo } 28161991Sheppo 28171991Sheppo /* 28181991Sheppo * wrapper routine to send the given message over ldc using ldc_write(). 28191991Sheppo */ 28201991Sheppo static int 28211991Sheppo vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg, size_t msglen, 28221991Sheppo boolean_t caller_holds_lock) 28231991Sheppo { 28241991Sheppo int rv; 28251991Sheppo size_t len; 28261991Sheppo uint32_t retries = 0; 28274647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 28281991Sheppo 28291991Sheppo len = msglen; 28301991Sheppo if ((len == 0) || (msg == NULL)) 28311991Sheppo return (VGEN_FAILURE); 28321991Sheppo 28331991Sheppo if (!caller_holds_lock) { 28344647Sraghuram mutex_enter(&ldcp->wrlock); 28351991Sheppo } 28361991Sheppo 28371991Sheppo do { 28381991Sheppo len = msglen; 28391991Sheppo rv = ldc_write(ldcp->ldc_handle, (caddr_t)msg, &len); 28401991Sheppo if (retries++ >= vgen_ldcwr_retries) 28411991Sheppo break; 28421991Sheppo } while (rv == EWOULDBLOCK); 28431991Sheppo 28441991Sheppo if (!caller_holds_lock) { 28454647Sraghuram mutex_exit(&ldcp->wrlock); 28461991Sheppo } 28471991Sheppo 28482793Slm66018 if (rv != 0) { 28494647Sraghuram DWARN(vgenp, ldcp, "ldc_write failed: rv(%d)\n", 28504647Sraghuram rv, msglen); 28512793Slm66018 return (rv); 28522793Slm66018 } 28532793Slm66018 28542793Slm66018 if (len != msglen) { 28554647Sraghuram DWARN(vgenp, ldcp, "ldc_write failed: rv(%d) msglen (%d)\n", 28564647Sraghuram rv, msglen); 28571991Sheppo return (VGEN_FAILURE); 28581991Sheppo } 28592793Slm66018 28601991Sheppo return (VGEN_SUCCESS); 28611991Sheppo } 28621991Sheppo 28631991Sheppo /* send version negotiate message to the peer over ldc */ 28641991Sheppo static int 28651991Sheppo vgen_send_version_negotiate(vgen_ldc_t *ldcp) 28661991Sheppo { 28674647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 28681991Sheppo vio_ver_msg_t vermsg; 28691991Sheppo vio_msg_tag_t *tagp = &vermsg.tag; 28701991Sheppo int rv; 28711991Sheppo 28721991Sheppo bzero(&vermsg, sizeof (vermsg)); 28731991Sheppo 28741991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 28751991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 28761991Sheppo tagp->vio_subtype_env = VIO_VER_INFO; 28771991Sheppo tagp->vio_sid = ldcp->local_sid; 28781991Sheppo 28791991Sheppo /* get version msg payload from ldcp->local */ 28801991Sheppo vermsg.ver_major = ldcp->local_hparams.ver_major; 28811991Sheppo vermsg.ver_minor = ldcp->local_hparams.ver_minor; 28821991Sheppo vermsg.dev_class = ldcp->local_hparams.dev_class; 28831991Sheppo 28841991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vermsg), B_FALSE); 28851991Sheppo if (rv != VGEN_SUCCESS) { 28864647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n"); 28872793Slm66018 return (rv); 28881991Sheppo } 28891991Sheppo 28901991Sheppo ldcp->hstate |= VER_INFO_SENT; 28914647Sraghuram DBG2(vgenp, ldcp, "VER_INFO_SENT ver(%d,%d)\n", 28924647Sraghuram vermsg.ver_major, vermsg.ver_minor); 28931991Sheppo 28941991Sheppo return (VGEN_SUCCESS); 28951991Sheppo } 28961991Sheppo 28971991Sheppo /* send attr info message to the peer over ldc */ 28981991Sheppo static int 28991991Sheppo vgen_send_attr_info(vgen_ldc_t *ldcp) 29001991Sheppo { 29014647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 29021991Sheppo vnet_attr_msg_t attrmsg; 29031991Sheppo vio_msg_tag_t *tagp = &attrmsg.tag; 29041991Sheppo int rv; 29051991Sheppo 29061991Sheppo bzero(&attrmsg, sizeof (attrmsg)); 29071991Sheppo 29081991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 29091991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 29101991Sheppo tagp->vio_subtype_env = VIO_ATTR_INFO; 29111991Sheppo tagp->vio_sid = ldcp->local_sid; 29121991Sheppo 29131991Sheppo /* get attr msg payload from ldcp->local */ 29141991Sheppo attrmsg.mtu = ldcp->local_hparams.mtu; 29151991Sheppo attrmsg.addr = ldcp->local_hparams.addr; 29161991Sheppo attrmsg.addr_type = ldcp->local_hparams.addr_type; 29171991Sheppo attrmsg.xfer_mode = ldcp->local_hparams.xfer_mode; 29181991Sheppo attrmsg.ack_freq = ldcp->local_hparams.ack_freq; 29191991Sheppo 29201991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (attrmsg), B_FALSE); 29211991Sheppo if (rv != VGEN_SUCCESS) { 29224647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n"); 29232793Slm66018 return (rv); 29241991Sheppo } 29251991Sheppo 29261991Sheppo ldcp->hstate |= ATTR_INFO_SENT; 29274647Sraghuram DBG2(vgenp, ldcp, "ATTR_INFO_SENT\n"); 29281991Sheppo 29291991Sheppo return (VGEN_SUCCESS); 29301991Sheppo } 29311991Sheppo 29321991Sheppo /* send descriptor ring register message to the peer over ldc */ 29331991Sheppo static int 29341991Sheppo vgen_send_dring_reg(vgen_ldc_t *ldcp) 29351991Sheppo { 29364647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 29371991Sheppo vio_dring_reg_msg_t msg; 29381991Sheppo vio_msg_tag_t *tagp = &msg.tag; 29391991Sheppo int rv; 29401991Sheppo 29411991Sheppo bzero(&msg, sizeof (msg)); 29421991Sheppo 29431991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 29441991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 29451991Sheppo tagp->vio_subtype_env = VIO_DRING_REG; 29461991Sheppo tagp->vio_sid = ldcp->local_sid; 29471991Sheppo 29481991Sheppo /* get dring info msg payload from ldcp->local */ 29491991Sheppo bcopy(&(ldcp->local_hparams.dring_cookie), (msg.cookie), 29504650Sraghuram sizeof (ldc_mem_cookie_t)); 29511991Sheppo msg.ncookies = ldcp->local_hparams.num_dcookies; 29521991Sheppo msg.num_descriptors = ldcp->local_hparams.num_desc; 29531991Sheppo msg.descriptor_size = ldcp->local_hparams.desc_size; 29541991Sheppo 29551991Sheppo /* 29561991Sheppo * dring_ident is set to 0. After mapping the dring, peer sets this 29571991Sheppo * value and sends it in the ack, which is saved in 29581991Sheppo * vgen_handle_dring_reg(). 29591991Sheppo */ 29601991Sheppo msg.dring_ident = 0; 29611991Sheppo 29621991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (msg), B_FALSE); 29631991Sheppo if (rv != VGEN_SUCCESS) { 29644647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n"); 29652793Slm66018 return (rv); 29661991Sheppo } 29671991Sheppo 29681991Sheppo ldcp->hstate |= DRING_INFO_SENT; 29694647Sraghuram DBG2(vgenp, ldcp, "DRING_INFO_SENT \n"); 29701991Sheppo 29711991Sheppo return (VGEN_SUCCESS); 29721991Sheppo } 29731991Sheppo 29741991Sheppo static int 29751991Sheppo vgen_send_rdx_info(vgen_ldc_t *ldcp) 29761991Sheppo { 29774647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 29781991Sheppo vio_rdx_msg_t rdxmsg; 29791991Sheppo vio_msg_tag_t *tagp = &rdxmsg.tag; 29801991Sheppo int rv; 29811991Sheppo 29821991Sheppo bzero(&rdxmsg, sizeof (rdxmsg)); 29831991Sheppo 29841991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 29851991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 29861991Sheppo tagp->vio_subtype_env = VIO_RDX; 29871991Sheppo tagp->vio_sid = ldcp->local_sid; 29881991Sheppo 29891991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (rdxmsg), B_FALSE); 29901991Sheppo if (rv != VGEN_SUCCESS) { 29914647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n"); 29922793Slm66018 return (rv); 29931991Sheppo } 29941991Sheppo 29951991Sheppo ldcp->hstate |= RDX_INFO_SENT; 29964647Sraghuram DBG2(vgenp, ldcp, "RDX_INFO_SENT\n"); 29971991Sheppo 29981991Sheppo return (VGEN_SUCCESS); 29991991Sheppo } 30001991Sheppo 30011991Sheppo /* send descriptor ring data message to the peer over ldc */ 30021991Sheppo static int 30032336Snarayan vgen_send_dring_data(vgen_ldc_t *ldcp, uint32_t start, int32_t end) 30041991Sheppo { 30054647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 30061991Sheppo vio_dring_msg_t dringmsg, *msgp = &dringmsg; 30071991Sheppo vio_msg_tag_t *tagp = &msgp->tag; 30081991Sheppo int rv; 30091991Sheppo 30101991Sheppo bzero(msgp, sizeof (*msgp)); 30111991Sheppo 30121991Sheppo tagp->vio_msgtype = VIO_TYPE_DATA; 30131991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 30141991Sheppo tagp->vio_subtype_env = VIO_DRING_DATA; 30151991Sheppo tagp->vio_sid = ldcp->local_sid; 30161991Sheppo 30172336Snarayan msgp->seq_num = ldcp->next_txseq; 30181991Sheppo msgp->dring_ident = ldcp->local_hparams.dring_ident; 30191991Sheppo msgp->start_idx = start; 30201991Sheppo msgp->end_idx = end; 30211991Sheppo 30221991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (dringmsg), B_TRUE); 30231991Sheppo if (rv != VGEN_SUCCESS) { 30244647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n"); 30252793Slm66018 return (rv); 30261991Sheppo } 30271991Sheppo 30282336Snarayan ldcp->next_txseq++; 30292336Snarayan ldcp->statsp->dring_data_msgs++; 30302336Snarayan 30314647Sraghuram DBG2(vgenp, ldcp, "DRING_DATA_SENT \n"); 30321991Sheppo 30331991Sheppo return (VGEN_SUCCESS); 30341991Sheppo } 30351991Sheppo 30361991Sheppo /* send multicast addr info message to vsw */ 30371991Sheppo static int 30381991Sheppo vgen_send_mcast_info(vgen_ldc_t *ldcp) 30391991Sheppo { 30401991Sheppo vnet_mcast_msg_t mcastmsg; 30411991Sheppo vnet_mcast_msg_t *msgp; 30421991Sheppo vio_msg_tag_t *tagp; 30431991Sheppo vgen_t *vgenp; 30441991Sheppo struct ether_addr *mca; 30451991Sheppo int rv; 30461991Sheppo int i; 30471991Sheppo uint32_t size; 30481991Sheppo uint32_t mccount; 30491991Sheppo uint32_t n; 30501991Sheppo 30511991Sheppo msgp = &mcastmsg; 30521991Sheppo tagp = &msgp->tag; 30531991Sheppo vgenp = LDC_TO_VGEN(ldcp); 30541991Sheppo 30551991Sheppo mccount = vgenp->mccount; 30561991Sheppo i = 0; 30571991Sheppo 30581991Sheppo do { 30591991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 30601991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 30611991Sheppo tagp->vio_subtype_env = VNET_MCAST_INFO; 30621991Sheppo tagp->vio_sid = ldcp->local_sid; 30631991Sheppo 30641991Sheppo n = ((mccount >= VNET_NUM_MCAST) ? VNET_NUM_MCAST : mccount); 30651991Sheppo size = n * sizeof (struct ether_addr); 30661991Sheppo 30671991Sheppo mca = &(vgenp->mctab[i]); 30681991Sheppo bcopy(mca, (msgp->mca), size); 30691991Sheppo msgp->set = B_TRUE; 30701991Sheppo msgp->count = n; 30711991Sheppo 30721991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp), 30731991Sheppo B_FALSE); 30741991Sheppo if (rv != VGEN_SUCCESS) { 30754647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg err(%d)\n", rv); 30762793Slm66018 return (rv); 30771991Sheppo } 30781991Sheppo 30791991Sheppo mccount -= n; 30801991Sheppo i += n; 30811991Sheppo 30821991Sheppo } while (mccount); 30831991Sheppo 30841991Sheppo return (VGEN_SUCCESS); 30851991Sheppo } 30861991Sheppo 30871991Sheppo /* Initiate Phase 2 of handshake */ 30881991Sheppo static int 30891991Sheppo vgen_handshake_phase2(vgen_ldc_t *ldcp) 30901991Sheppo { 30911991Sheppo int rv; 30922793Slm66018 uint32_t ncookies = 0; 30934647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 30944647Sraghuram 30951991Sheppo #ifdef DEBUG 30961991Sheppo if (vgen_hdbg & HDBG_OUT_STATE) { 30971991Sheppo /* simulate out of state condition */ 30981991Sheppo vgen_hdbg &= ~(HDBG_OUT_STATE); 30991991Sheppo rv = vgen_send_rdx_info(ldcp); 31001991Sheppo return (rv); 31011991Sheppo } 31021991Sheppo if (vgen_hdbg & HDBG_TIMEOUT) { 31031991Sheppo /* simulate timeout condition */ 31041991Sheppo vgen_hdbg &= ~(HDBG_TIMEOUT); 31051991Sheppo return (VGEN_SUCCESS); 31061991Sheppo } 31071991Sheppo #endif 31082793Slm66018 rv = vgen_send_attr_info(ldcp); 31092793Slm66018 if (rv != VGEN_SUCCESS) { 31101991Sheppo return (rv); 31111991Sheppo } 31122793Slm66018 31132793Slm66018 /* Bind descriptor ring to the channel */ 31142793Slm66018 if (ldcp->num_txdcookies == 0) { 31152793Slm66018 rv = ldc_mem_dring_bind(ldcp->ldc_handle, ldcp->tx_dhandle, 31162793Slm66018 LDC_SHADOW_MAP, LDC_MEM_RW, &ldcp->tx_dcookie, &ncookies); 31172793Slm66018 if (rv != 0) { 31184647Sraghuram DWARN(vgenp, ldcp, "ldc_mem_dring_bind failed " 31194650Sraghuram "rv(%x)\n", rv); 31202793Slm66018 return (rv); 31212793Slm66018 } 31222793Slm66018 ASSERT(ncookies == 1); 31232793Slm66018 ldcp->num_txdcookies = ncookies; 31242793Slm66018 } 31252793Slm66018 31262793Slm66018 /* update local dring_info params */ 31272793Slm66018 bcopy(&(ldcp->tx_dcookie), &(ldcp->local_hparams.dring_cookie), 31284650Sraghuram sizeof (ldc_mem_cookie_t)); 31292793Slm66018 ldcp->local_hparams.num_dcookies = ldcp->num_txdcookies; 31302793Slm66018 ldcp->local_hparams.num_desc = ldcp->num_txds; 31312793Slm66018 ldcp->local_hparams.desc_size = sizeof (vnet_public_desc_t); 31322793Slm66018 31332793Slm66018 rv = vgen_send_dring_reg(ldcp); 31342793Slm66018 if (rv != VGEN_SUCCESS) { 31351991Sheppo return (rv); 31361991Sheppo } 31371991Sheppo 31381991Sheppo return (VGEN_SUCCESS); 31391991Sheppo } 31401991Sheppo 31411991Sheppo /* 31421991Sheppo * This function resets the handshake phase to VH_PHASE0(pre-handshake phase). 31431991Sheppo * This can happen after a channel comes up (status: LDC_UP) or 31441991Sheppo * when handshake gets terminated due to various conditions. 31451991Sheppo */ 31461991Sheppo static void 31471991Sheppo vgen_reset_hphase(vgen_ldc_t *ldcp) 31481991Sheppo { 31494647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 31501991Sheppo ldc_status_t istatus; 31512793Slm66018 int rv; 31521991Sheppo 31534647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 31541991Sheppo /* reset hstate and hphase */ 31551991Sheppo ldcp->hstate = 0; 31561991Sheppo ldcp->hphase = VH_PHASE0; 31571991Sheppo 31583653Snarayan /* 31593653Snarayan * Save the id of pending handshake timer in cancel_htid. 31603653Snarayan * This will be checked in vgen_ldc_cb() and the handshake timer will 31613653Snarayan * be cancelled after releasing cblock. 31623653Snarayan */ 31631991Sheppo if (ldcp->htid) { 31643653Snarayan ldcp->cancel_htid = ldcp->htid; 31651991Sheppo ldcp->htid = 0; 31661991Sheppo } 31671991Sheppo 31681991Sheppo if (ldcp->local_hparams.dring_ready) { 31691991Sheppo ldcp->local_hparams.dring_ready = B_FALSE; 31702793Slm66018 } 31712793Slm66018 31722793Slm66018 /* Unbind tx descriptor ring from the channel */ 31732793Slm66018 if (ldcp->num_txdcookies) { 31742793Slm66018 rv = ldc_mem_dring_unbind(ldcp->tx_dhandle); 31752793Slm66018 if (rv != 0) { 31764647Sraghuram DWARN(vgenp, ldcp, "ldc_mem_dring_unbind failed\n"); 31772793Slm66018 } 31782793Slm66018 ldcp->num_txdcookies = 0; 31791991Sheppo } 31801991Sheppo 31811991Sheppo if (ldcp->peer_hparams.dring_ready) { 31821991Sheppo ldcp->peer_hparams.dring_ready = B_FALSE; 31831991Sheppo /* Unmap peer's dring */ 31841991Sheppo (void) ldc_mem_dring_unmap(ldcp->rx_dhandle); 31851991Sheppo vgen_clobber_rxds(ldcp); 31861991Sheppo } 31871991Sheppo 31881991Sheppo vgen_clobber_tbufs(ldcp); 31891991Sheppo 31901991Sheppo /* 31911991Sheppo * clear local handshake params and initialize. 31921991Sheppo */ 31931991Sheppo bzero(&(ldcp->local_hparams), sizeof (ldcp->local_hparams)); 31941991Sheppo 31951991Sheppo /* set version to the highest version supported */ 31961991Sheppo ldcp->local_hparams.ver_major = 31974650Sraghuram ldcp->vgen_versions[0].ver_major; 31981991Sheppo ldcp->local_hparams.ver_minor = 31994650Sraghuram ldcp->vgen_versions[0].ver_minor; 32001991Sheppo ldcp->local_hparams.dev_class = VDEV_NETWORK; 32011991Sheppo 32021991Sheppo /* set attr_info params */ 32031991Sheppo ldcp->local_hparams.mtu = ETHERMAX; 32041991Sheppo ldcp->local_hparams.addr = 32054650Sraghuram vgen_macaddr_strtoul(vgenp->macaddr); 32061991Sheppo ldcp->local_hparams.addr_type = ADDR_TYPE_MAC; 32071991Sheppo ldcp->local_hparams.xfer_mode = VIO_DRING_MODE; 32081991Sheppo ldcp->local_hparams.ack_freq = 0; /* don't need acks */ 32091991Sheppo 32101991Sheppo /* 32112793Slm66018 * Note: dring is created, but not bound yet. 32122793Slm66018 * local dring_info params will be updated when we bind the dring in 32132793Slm66018 * vgen_handshake_phase2(). 32141991Sheppo * dring_ident is set to 0. After mapping the dring, peer sets this 32151991Sheppo * value and sends it in the ack, which is saved in 32161991Sheppo * vgen_handle_dring_reg(). 32171991Sheppo */ 32181991Sheppo ldcp->local_hparams.dring_ident = 0; 32191991Sheppo 32201991Sheppo /* clear peer_hparams */ 32211991Sheppo bzero(&(ldcp->peer_hparams), sizeof (ldcp->peer_hparams)); 32221991Sheppo 32231991Sheppo /* reset the channel if required */ 32241991Sheppo if (ldcp->need_ldc_reset) { 32254647Sraghuram DWARN(vgenp, ldcp, "Doing Channel Reset...\n"); 32261991Sheppo ldcp->need_ldc_reset = B_FALSE; 32272410Slm66018 (void) ldc_down(ldcp->ldc_handle); 32281991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 32294647Sraghuram DBG2(vgenp, ldcp, "Reset Done,ldc_status(%x)\n", istatus); 32301991Sheppo ldcp->ldc_status = istatus; 32312793Slm66018 32321991Sheppo /* clear sids */ 32331991Sheppo ldcp->local_sid = 0; 32341991Sheppo ldcp->peer_sid = 0; 32352793Slm66018 32362793Slm66018 /* try to bring the channel up */ 32372793Slm66018 rv = ldc_up(ldcp->ldc_handle); 32382793Slm66018 if (rv != 0) { 32394647Sraghuram DWARN(vgenp, ldcp, "ldc_up err rv(%d)\n", rv); 32402793Slm66018 } 32412793Slm66018 32422793Slm66018 if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 32434647Sraghuram DWARN(vgenp, ldcp, "ldc_status err\n"); 32442793Slm66018 } else { 32452793Slm66018 ldcp->ldc_status = istatus; 32462793Slm66018 } 32471991Sheppo } 32481991Sheppo } 32491991Sheppo 32501991Sheppo /* wrapper function for vgen_reset_hphase */ 32511991Sheppo static void 32521991Sheppo vgen_handshake_reset(vgen_ldc_t *ldcp) 32531991Sheppo { 32541991Sheppo ASSERT(MUTEX_HELD(&ldcp->cblock)); 32554647Sraghuram mutex_enter(&ldcp->rxlock); 32564647Sraghuram mutex_enter(&ldcp->wrlock); 32571991Sheppo mutex_enter(&ldcp->txlock); 32581991Sheppo mutex_enter(&ldcp->tclock); 32591991Sheppo 32601991Sheppo vgen_reset_hphase(ldcp); 32611991Sheppo 32621991Sheppo mutex_exit(&ldcp->tclock); 32631991Sheppo mutex_exit(&ldcp->txlock); 32644647Sraghuram mutex_exit(&ldcp->wrlock); 32654647Sraghuram mutex_exit(&ldcp->rxlock); 32661991Sheppo } 32671991Sheppo 32681991Sheppo /* 32691991Sheppo * Initiate handshake with the peer by sending various messages 32701991Sheppo * based on the handshake-phase that the channel is currently in. 32711991Sheppo */ 32721991Sheppo static void 32731991Sheppo vgen_handshake(vgen_ldc_t *ldcp) 32741991Sheppo { 32751991Sheppo uint32_t hphase = ldcp->hphase; 32761991Sheppo vgen_t *vgenp = LDC_TO_VGEN(ldcp); 32772793Slm66018 ldc_status_t istatus; 32782793Slm66018 int rv = 0; 32791991Sheppo 32801991Sheppo switch (hphase) { 32811991Sheppo 32821991Sheppo case VH_PHASE1: 32831991Sheppo 32841991Sheppo /* 32851991Sheppo * start timer, for entire handshake process, turn this timer 32861991Sheppo * off if all phases of handshake complete successfully and 32871991Sheppo * hphase goes to VH_DONE(below) or 32881991Sheppo * vgen_reset_hphase() gets called or 32891991Sheppo * channel is reset due to errors or 32901991Sheppo * vgen_ldc_uninit() is invoked(vgen_stop). 32911991Sheppo */ 32921991Sheppo ldcp->htid = timeout(vgen_hwatchdog, (caddr_t)ldcp, 3293*5171Ssb155480 drv_usectohz(vgen_hwd_interval * MICROSEC)); 32941991Sheppo 32951991Sheppo /* Phase 1 involves negotiating the version */ 32962793Slm66018 rv = vgen_send_version_negotiate(ldcp); 32971991Sheppo break; 32981991Sheppo 32991991Sheppo case VH_PHASE2: 33002793Slm66018 rv = vgen_handshake_phase2(ldcp); 33011991Sheppo break; 33021991Sheppo 33031991Sheppo case VH_PHASE3: 33042793Slm66018 rv = vgen_send_rdx_info(ldcp); 33051991Sheppo break; 33061991Sheppo 33071991Sheppo case VH_DONE: 33083653Snarayan /* 33093653Snarayan * Save the id of pending handshake timer in cancel_htid. 33103653Snarayan * This will be checked in vgen_ldc_cb() and the handshake 33113653Snarayan * timer will be cancelled after releasing cblock. 33123653Snarayan */ 33131991Sheppo if (ldcp->htid) { 33143653Snarayan ldcp->cancel_htid = ldcp->htid; 33151991Sheppo ldcp->htid = 0; 33161991Sheppo } 33171991Sheppo ldcp->hretries = 0; 33184647Sraghuram DBG1(vgenp, ldcp, "Handshake Done\n"); 33191991Sheppo 3320*5171Ssb155480 if (ldcp->portp == vgenp->vsw_portp) { 3321*5171Ssb155480 /* 3322*5171Ssb155480 * If this channel(port) is connected to vsw, 3323*5171Ssb155480 * need to sync multicast table with vsw. 3324*5171Ssb155480 */ 33251991Sheppo mutex_exit(&ldcp->cblock); 33261991Sheppo 33271991Sheppo mutex_enter(&vgenp->lock); 33282793Slm66018 rv = vgen_send_mcast_info(ldcp); 33291991Sheppo mutex_exit(&vgenp->lock); 33301991Sheppo 33311991Sheppo mutex_enter(&ldcp->cblock); 33322793Slm66018 if (rv != VGEN_SUCCESS) 33332793Slm66018 break; 33341991Sheppo } 33352793Slm66018 33362793Slm66018 /* 33372793Slm66018 * Check if mac layer should be notified to restart 33382793Slm66018 * transmissions. This can happen if the channel got 33392793Slm66018 * reset and vgen_clobber_tbufs() is called, while 33402793Slm66018 * need_resched is set. 33412793Slm66018 */ 33422793Slm66018 mutex_enter(&ldcp->tclock); 33432793Slm66018 if (ldcp->need_resched) { 33442793Slm66018 ldcp->need_resched = B_FALSE; 33452793Slm66018 vnet_tx_update(vgenp->vnetp); 33462793Slm66018 } 33472793Slm66018 mutex_exit(&ldcp->tclock); 33482793Slm66018 33491991Sheppo break; 33501991Sheppo 33511991Sheppo default: 33521991Sheppo break; 33531991Sheppo } 33542793Slm66018 33552793Slm66018 if (rv == ECONNRESET) { 33562793Slm66018 if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 33574647Sraghuram DWARN(vgenp, ldcp, "ldc_status err\n"); 33582793Slm66018 } else { 33592793Slm66018 ldcp->ldc_status = istatus; 33602793Slm66018 } 33612793Slm66018 vgen_handle_evt_reset(ldcp, B_FALSE); 33622793Slm66018 } else if (rv) { 33632793Slm66018 vgen_handshake_reset(ldcp); 33642793Slm66018 } 33651991Sheppo } 33661991Sheppo 33671991Sheppo /* 33681991Sheppo * Check if the current handshake phase has completed successfully and 33691991Sheppo * return the status. 33701991Sheppo */ 33711991Sheppo static int 33721991Sheppo vgen_handshake_done(vgen_ldc_t *ldcp) 33731991Sheppo { 33744647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 33751991Sheppo uint32_t hphase = ldcp->hphase; 33761991Sheppo int status = 0; 33771991Sheppo 33781991Sheppo switch (hphase) { 33791991Sheppo 33801991Sheppo case VH_PHASE1: 33811991Sheppo /* 33821991Sheppo * Phase1 is done, if version negotiation 33831991Sheppo * completed successfully. 33841991Sheppo */ 33851991Sheppo status = ((ldcp->hstate & VER_NEGOTIATED) == 33864650Sraghuram VER_NEGOTIATED); 33871991Sheppo break; 33881991Sheppo 33891991Sheppo case VH_PHASE2: 33901991Sheppo /* 33911991Sheppo * Phase 2 is done, if attr info and dring info 33921991Sheppo * have been exchanged successfully. 33931991Sheppo */ 33941991Sheppo status = (((ldcp->hstate & ATTR_INFO_EXCHANGED) == 33954650Sraghuram ATTR_INFO_EXCHANGED) && 33964650Sraghuram ((ldcp->hstate & DRING_INFO_EXCHANGED) == 33974650Sraghuram DRING_INFO_EXCHANGED)); 33981991Sheppo break; 33991991Sheppo 34001991Sheppo case VH_PHASE3: 34011991Sheppo /* Phase 3 is done, if rdx msg has been exchanged */ 34021991Sheppo status = ((ldcp->hstate & RDX_EXCHANGED) == 34034650Sraghuram RDX_EXCHANGED); 34041991Sheppo break; 34051991Sheppo 34061991Sheppo default: 34071991Sheppo break; 34081991Sheppo } 34091991Sheppo 34101991Sheppo if (status == 0) { 34111991Sheppo return (VGEN_FAILURE); 34121991Sheppo } 34134647Sraghuram DBG2(vgenp, ldcp, "PHASE(%d)\n", hphase); 34141991Sheppo return (VGEN_SUCCESS); 34151991Sheppo } 34161991Sheppo 34171991Sheppo /* retry handshake on failure */ 34181991Sheppo static void 34191991Sheppo vgen_handshake_retry(vgen_ldc_t *ldcp) 34201991Sheppo { 34211991Sheppo /* reset handshake phase */ 34221991Sheppo vgen_handshake_reset(ldcp); 34233653Snarayan 34243653Snarayan /* handshake retry is specified and the channel is UP */ 34253653Snarayan if (vgen_max_hretries && (ldcp->ldc_status == LDC_UP)) { 34263653Snarayan if (ldcp->hretries++ < vgen_max_hretries) { 34273653Snarayan ldcp->local_sid = ddi_get_lbolt(); 34281991Sheppo vgen_handshake(vh_nextphase(ldcp)); 34293653Snarayan } 34301991Sheppo } 34311991Sheppo } 34321991Sheppo 34331991Sheppo /* 34341991Sheppo * Handle a version info msg from the peer or an ACK/NACK from the peer 34351991Sheppo * to a version info msg that we sent. 34361991Sheppo */ 34372793Slm66018 static int 34381991Sheppo vgen_handle_version_negotiate(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 34391991Sheppo { 34404647Sraghuram vgen_t *vgenp; 34411991Sheppo vio_ver_msg_t *vermsg = (vio_ver_msg_t *)tagp; 34421991Sheppo int ack = 0; 34431991Sheppo int failed = 0; 34441991Sheppo int idx; 34451991Sheppo vgen_ver_t *versions = ldcp->vgen_versions; 34462793Slm66018 int rv = 0; 34471991Sheppo 34484647Sraghuram vgenp = LDC_TO_VGEN(ldcp); 34494647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 34501991Sheppo switch (tagp->vio_subtype) { 34511991Sheppo case VIO_SUBTYPE_INFO: 34521991Sheppo 34531991Sheppo /* Cache sid of peer if this is the first time */ 34541991Sheppo if (ldcp->peer_sid == 0) { 34554647Sraghuram DBG2(vgenp, ldcp, "Caching peer_sid(%x)\n", 34564647Sraghuram tagp->vio_sid); 34571991Sheppo ldcp->peer_sid = tagp->vio_sid; 34581991Sheppo } 34591991Sheppo 34601991Sheppo if (ldcp->hphase != VH_PHASE1) { 34611991Sheppo /* 34621991Sheppo * If we are not already in VH_PHASE1, reset to 34631991Sheppo * pre-handshake state, and initiate handshake 34641991Sheppo * to the peer too. 34651991Sheppo */ 34661991Sheppo vgen_handshake_reset(ldcp); 34671991Sheppo vgen_handshake(vh_nextphase(ldcp)); 34681991Sheppo } 34691991Sheppo ldcp->hstate |= VER_INFO_RCVD; 34701991Sheppo 34711991Sheppo /* save peer's requested values */ 34721991Sheppo ldcp->peer_hparams.ver_major = vermsg->ver_major; 34731991Sheppo ldcp->peer_hparams.ver_minor = vermsg->ver_minor; 34741991Sheppo ldcp->peer_hparams.dev_class = vermsg->dev_class; 34751991Sheppo 34761991Sheppo if ((vermsg->dev_class != VDEV_NETWORK) && 34771991Sheppo (vermsg->dev_class != VDEV_NETWORK_SWITCH)) { 34781991Sheppo /* unsupported dev_class, send NACK */ 34791991Sheppo 34804647Sraghuram DWARN(vgenp, ldcp, "Version Negotiation Failed\n"); 34812793Slm66018 34821991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 34831991Sheppo tagp->vio_sid = ldcp->local_sid; 34841991Sheppo /* send reply msg back to peer */ 34852793Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, 34861991Sheppo sizeof (*vermsg), B_FALSE); 34872793Slm66018 if (rv != VGEN_SUCCESS) { 34882793Slm66018 return (rv); 34892793Slm66018 } 34902793Slm66018 return (VGEN_FAILURE); 34911991Sheppo } 34921991Sheppo 34934647Sraghuram DBG2(vgenp, ldcp, "VER_INFO_RCVD, ver(%d,%d)\n", 34944647Sraghuram vermsg->ver_major, vermsg->ver_minor); 34951991Sheppo 34961991Sheppo idx = 0; 34971991Sheppo 34981991Sheppo for (;;) { 34991991Sheppo 35001991Sheppo if (vermsg->ver_major > versions[idx].ver_major) { 35011991Sheppo 35021991Sheppo /* nack with next lower version */ 35031991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 35041991Sheppo vermsg->ver_major = versions[idx].ver_major; 35051991Sheppo vermsg->ver_minor = versions[idx].ver_minor; 35061991Sheppo break; 35071991Sheppo } 35081991Sheppo 35091991Sheppo if (vermsg->ver_major == versions[idx].ver_major) { 35101991Sheppo 35111991Sheppo /* major version match - ACK version */ 35121991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 35131991Sheppo ack = 1; 35141991Sheppo 35151991Sheppo /* 35161991Sheppo * lower minor version to the one this endpt 35171991Sheppo * supports, if necessary 35181991Sheppo */ 35191991Sheppo if (vermsg->ver_minor > 35201991Sheppo versions[idx].ver_minor) { 35211991Sheppo vermsg->ver_minor = 35224650Sraghuram versions[idx].ver_minor; 35231991Sheppo ldcp->peer_hparams.ver_minor = 35244650Sraghuram versions[idx].ver_minor; 35251991Sheppo } 35261991Sheppo break; 35271991Sheppo } 35281991Sheppo 35291991Sheppo idx++; 35301991Sheppo 35311991Sheppo if (idx == VGEN_NUM_VER) { 35321991Sheppo 35331991Sheppo /* no version match - send NACK */ 35341991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 35351991Sheppo vermsg->ver_major = 0; 35361991Sheppo vermsg->ver_minor = 0; 35371991Sheppo failed = 1; 35381991Sheppo break; 35391991Sheppo } 35401991Sheppo 35411991Sheppo } 35421991Sheppo 35431991Sheppo tagp->vio_sid = ldcp->local_sid; 35441991Sheppo 35451991Sheppo /* send reply msg back to peer */ 35462793Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*vermsg), 35472793Slm66018 B_FALSE); 35482793Slm66018 if (rv != VGEN_SUCCESS) { 35492793Slm66018 return (rv); 35501991Sheppo } 35511991Sheppo 35521991Sheppo if (ack) { 35531991Sheppo ldcp->hstate |= VER_ACK_SENT; 35544647Sraghuram DBG2(vgenp, ldcp, "VER_ACK_SENT, ver(%d,%d) \n", 35554647Sraghuram vermsg->ver_major, vermsg->ver_minor); 35561991Sheppo } 35571991Sheppo if (failed) { 35584647Sraghuram DWARN(vgenp, ldcp, "Negotiation Failed\n"); 35592793Slm66018 return (VGEN_FAILURE); 35601991Sheppo } 35611991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 35621991Sheppo 35631991Sheppo /* VER_ACK_SENT and VER_ACK_RCVD */ 35641991Sheppo 35651991Sheppo /* local and peer versions match? */ 35661991Sheppo ASSERT((ldcp->local_hparams.ver_major == 35674650Sraghuram ldcp->peer_hparams.ver_major) && 35684650Sraghuram (ldcp->local_hparams.ver_minor == 35694650Sraghuram ldcp->peer_hparams.ver_minor)); 35701991Sheppo 35711991Sheppo /* move to the next phase */ 35721991Sheppo vgen_handshake(vh_nextphase(ldcp)); 35731991Sheppo } 35741991Sheppo 35751991Sheppo break; 35761991Sheppo 35771991Sheppo case VIO_SUBTYPE_ACK: 35781991Sheppo 35791991Sheppo if (ldcp->hphase != VH_PHASE1) { 35801991Sheppo /* This should not happen. */ 35814647Sraghuram DWARN(vgenp, ldcp, "Invalid Phase(%u)\n", ldcp->hphase); 35822793Slm66018 return (VGEN_FAILURE); 35831991Sheppo } 35841991Sheppo 35851991Sheppo /* SUCCESS - we have agreed on a version */ 35861991Sheppo ldcp->local_hparams.ver_major = vermsg->ver_major; 35871991Sheppo ldcp->local_hparams.ver_minor = vermsg->ver_minor; 35881991Sheppo ldcp->hstate |= VER_ACK_RCVD; 35891991Sheppo 35904647Sraghuram DBG2(vgenp, ldcp, "VER_ACK_RCVD, ver(%d,%d) \n", 35914647Sraghuram vermsg->ver_major, vermsg->ver_minor); 35921991Sheppo 35931991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 35941991Sheppo 35951991Sheppo /* VER_ACK_SENT and VER_ACK_RCVD */ 35961991Sheppo 35971991Sheppo /* local and peer versions match? */ 35981991Sheppo ASSERT((ldcp->local_hparams.ver_major == 35994650Sraghuram ldcp->peer_hparams.ver_major) && 36004650Sraghuram (ldcp->local_hparams.ver_minor == 36014650Sraghuram ldcp->peer_hparams.ver_minor)); 36021991Sheppo 36031991Sheppo /* move to the next phase */ 36041991Sheppo vgen_handshake(vh_nextphase(ldcp)); 36051991Sheppo } 36061991Sheppo break; 36071991Sheppo 36081991Sheppo case VIO_SUBTYPE_NACK: 36091991Sheppo 36101991Sheppo if (ldcp->hphase != VH_PHASE1) { 36111991Sheppo /* This should not happen. */ 36124647Sraghuram DWARN(vgenp, ldcp, "VER_NACK_RCVD Invalid " 36134647Sraghuram "Phase(%u)\n", ldcp->hphase); 36142793Slm66018 return (VGEN_FAILURE); 36151991Sheppo } 36161991Sheppo 36174647Sraghuram DBG2(vgenp, ldcp, "VER_NACK_RCVD next ver(%d,%d)\n", 36184647Sraghuram vermsg->ver_major, vermsg->ver_minor); 36191991Sheppo 36201991Sheppo /* check if version in NACK is zero */ 36211991Sheppo if (vermsg->ver_major == 0 && vermsg->ver_minor == 0) { 36221991Sheppo /* 36231991Sheppo * Version Negotiation has failed. 36241991Sheppo */ 36254647Sraghuram DWARN(vgenp, ldcp, "Version Negotiation Failed\n"); 36262793Slm66018 return (VGEN_FAILURE); 36271991Sheppo } 36281991Sheppo 36291991Sheppo idx = 0; 36301991Sheppo 36311991Sheppo for (;;) { 36321991Sheppo 36331991Sheppo if (vermsg->ver_major > versions[idx].ver_major) { 36341991Sheppo /* select next lower version */ 36351991Sheppo 36361991Sheppo ldcp->local_hparams.ver_major = 36374650Sraghuram versions[idx].ver_major; 36381991Sheppo ldcp->local_hparams.ver_minor = 36394650Sraghuram versions[idx].ver_minor; 36401991Sheppo break; 36411991Sheppo } 36421991Sheppo 36431991Sheppo if (vermsg->ver_major == versions[idx].ver_major) { 36441991Sheppo /* major version match */ 36451991Sheppo 36461991Sheppo ldcp->local_hparams.ver_major = 36474650Sraghuram versions[idx].ver_major; 36481991Sheppo 36491991Sheppo ldcp->local_hparams.ver_minor = 36504650Sraghuram versions[idx].ver_minor; 36511991Sheppo break; 36521991Sheppo } 36531991Sheppo 36541991Sheppo idx++; 36551991Sheppo 36561991Sheppo if (idx == VGEN_NUM_VER) { 36571991Sheppo /* 36581991Sheppo * no version match. 36591991Sheppo * Version Negotiation has failed. 36601991Sheppo */ 36614647Sraghuram DWARN(vgenp, ldcp, 36624647Sraghuram "Version Negotiation Failed\n"); 36632793Slm66018 return (VGEN_FAILURE); 36641991Sheppo } 36651991Sheppo 36661991Sheppo } 36671991Sheppo 36682793Slm66018 rv = vgen_send_version_negotiate(ldcp); 36692793Slm66018 if (rv != VGEN_SUCCESS) { 36702793Slm66018 return (rv); 36711991Sheppo } 36721991Sheppo 36731991Sheppo break; 36741991Sheppo } 36752793Slm66018 36764647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 36772793Slm66018 return (VGEN_SUCCESS); 36781991Sheppo } 36791991Sheppo 36801991Sheppo /* Check if the attributes are supported */ 36811991Sheppo static int 36821991Sheppo vgen_check_attr_info(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg) 36831991Sheppo { 36841991Sheppo _NOTE(ARGUNUSED(ldcp)) 36851991Sheppo 36861991Sheppo /* 36871991Sheppo * currently, we support these attr values: 36881991Sheppo * mtu of ethernet, addr_type of mac, xfer_mode of 36891991Sheppo * ldc shared memory, ack_freq of 0 (data is acked if 36901991Sheppo * the ack bit is set in the descriptor) and the address should 36911991Sheppo * match the address in the port node. 36921991Sheppo */ 36931991Sheppo if ((msg->mtu != ETHERMAX) || 36941991Sheppo (msg->addr_type != ADDR_TYPE_MAC) || 36951991Sheppo (msg->xfer_mode != VIO_DRING_MODE) || 36961991Sheppo (msg->ack_freq > 64)) { 36971991Sheppo return (VGEN_FAILURE); 36981991Sheppo } 36991991Sheppo 37001991Sheppo return (VGEN_SUCCESS); 37011991Sheppo } 37021991Sheppo 37031991Sheppo /* 37041991Sheppo * Handle an attribute info msg from the peer or an ACK/NACK from the peer 37051991Sheppo * to an attr info msg that we sent. 37061991Sheppo */ 37072793Slm66018 static int 37081991Sheppo vgen_handle_attr_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 37091991Sheppo { 37104647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 37111991Sheppo vnet_attr_msg_t *attrmsg = (vnet_attr_msg_t *)tagp; 37121991Sheppo int ack = 0; 37132793Slm66018 int rv = 0; 37141991Sheppo 37154647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 37161991Sheppo if (ldcp->hphase != VH_PHASE2) { 37174647Sraghuram DWARN(vgenp, ldcp, "Rcvd ATTR_INFO subtype(%d)," 37184647Sraghuram " Invalid Phase(%u)\n", 37194647Sraghuram tagp->vio_subtype, ldcp->hphase); 37202793Slm66018 return (VGEN_FAILURE); 37211991Sheppo } 37221991Sheppo switch (tagp->vio_subtype) { 37231991Sheppo case VIO_SUBTYPE_INFO: 37241991Sheppo 37254647Sraghuram DBG2(vgenp, ldcp, "ATTR_INFO_RCVD \n"); 37261991Sheppo ldcp->hstate |= ATTR_INFO_RCVD; 37271991Sheppo 37281991Sheppo /* save peer's values */ 37291991Sheppo ldcp->peer_hparams.mtu = attrmsg->mtu; 37301991Sheppo ldcp->peer_hparams.addr = attrmsg->addr; 37311991Sheppo ldcp->peer_hparams.addr_type = attrmsg->addr_type; 37321991Sheppo ldcp->peer_hparams.xfer_mode = attrmsg->xfer_mode; 37331991Sheppo ldcp->peer_hparams.ack_freq = attrmsg->ack_freq; 37341991Sheppo 37351991Sheppo if (vgen_check_attr_info(ldcp, attrmsg) == VGEN_FAILURE) { 37361991Sheppo /* unsupported attr, send NACK */ 37371991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 37381991Sheppo } else { 37391991Sheppo ack = 1; 37401991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 37411991Sheppo } 37421991Sheppo tagp->vio_sid = ldcp->local_sid; 37431991Sheppo 37441991Sheppo /* send reply msg back to peer */ 37452793Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*attrmsg), 37462793Slm66018 B_FALSE); 37472793Slm66018 if (rv != VGEN_SUCCESS) { 37482793Slm66018 return (rv); 37491991Sheppo } 37501991Sheppo 37511991Sheppo if (ack) { 37521991Sheppo ldcp->hstate |= ATTR_ACK_SENT; 37534647Sraghuram DBG2(vgenp, ldcp, "ATTR_ACK_SENT \n"); 37541991Sheppo } else { 37551991Sheppo /* failed */ 37564647Sraghuram DWARN(vgenp, ldcp, "ATTR_NACK_SENT \n"); 37572793Slm66018 return (VGEN_FAILURE); 37581991Sheppo } 37591991Sheppo 37601991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 37611991Sheppo vgen_handshake(vh_nextphase(ldcp)); 37621991Sheppo } 37631991Sheppo 37641991Sheppo break; 37651991Sheppo 37661991Sheppo case VIO_SUBTYPE_ACK: 37671991Sheppo 37681991Sheppo ldcp->hstate |= ATTR_ACK_RCVD; 37691991Sheppo 37704647Sraghuram DBG2(vgenp, ldcp, "ATTR_ACK_RCVD \n"); 37711991Sheppo 37721991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 37731991Sheppo vgen_handshake(vh_nextphase(ldcp)); 37741991Sheppo } 37751991Sheppo break; 37761991Sheppo 37771991Sheppo case VIO_SUBTYPE_NACK: 37781991Sheppo 37794647Sraghuram DBG2(vgenp, ldcp, "ATTR_NACK_RCVD \n"); 37802793Slm66018 return (VGEN_FAILURE); 37811991Sheppo } 37824647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 37832793Slm66018 return (VGEN_SUCCESS); 37841991Sheppo } 37851991Sheppo 37861991Sheppo /* Check if the dring info msg is ok */ 37871991Sheppo static int 37881991Sheppo vgen_check_dring_reg(vio_dring_reg_msg_t *msg) 37891991Sheppo { 37901991Sheppo /* check if msg contents are ok */ 37911991Sheppo if ((msg->num_descriptors < 128) || (msg->descriptor_size < 37921991Sheppo sizeof (vnet_public_desc_t))) { 37931991Sheppo return (VGEN_FAILURE); 37941991Sheppo } 37951991Sheppo return (VGEN_SUCCESS); 37961991Sheppo } 37971991Sheppo 37981991Sheppo /* 37991991Sheppo * Handle a descriptor ring register msg from the peer or an ACK/NACK from 38001991Sheppo * the peer to a dring register msg that we sent. 38011991Sheppo */ 38022793Slm66018 static int 38031991Sheppo vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 38041991Sheppo { 38051991Sheppo vio_dring_reg_msg_t *msg = (vio_dring_reg_msg_t *)tagp; 38061991Sheppo ldc_mem_cookie_t dcookie; 38074647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 38081991Sheppo int ack = 0; 38091991Sheppo int rv = 0; 38101991Sheppo 38114647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 38121991Sheppo if (ldcp->hphase < VH_PHASE2) { 38131991Sheppo /* dring_info can be rcvd in any of the phases after Phase1 */ 38144647Sraghuram DWARN(vgenp, ldcp, 38154647Sraghuram "Rcvd DRING_INFO Subtype (%d), Invalid Phase(%u)\n", 38164650Sraghuram tagp->vio_subtype, ldcp->hphase); 38172793Slm66018 return (VGEN_FAILURE); 38181991Sheppo } 38191991Sheppo switch (tagp->vio_subtype) { 38201991Sheppo case VIO_SUBTYPE_INFO: 38211991Sheppo 38224647Sraghuram DBG2(vgenp, ldcp, "DRING_INFO_RCVD \n"); 38231991Sheppo ldcp->hstate |= DRING_INFO_RCVD; 38241991Sheppo bcopy((msg->cookie), &dcookie, sizeof (dcookie)); 38251991Sheppo 38261991Sheppo ASSERT(msg->ncookies == 1); 38271991Sheppo 38281991Sheppo if (vgen_check_dring_reg(msg) == VGEN_SUCCESS) { 38291991Sheppo /* 38301991Sheppo * verified dring info msg to be ok, 38311991Sheppo * now try to map the remote dring. 38321991Sheppo */ 38331991Sheppo rv = vgen_init_rxds(ldcp, msg->num_descriptors, 38341991Sheppo msg->descriptor_size, &dcookie, 38351991Sheppo msg->ncookies); 38361991Sheppo if (rv == DDI_SUCCESS) { 38371991Sheppo /* now we can ack the peer */ 38381991Sheppo ack = 1; 38391991Sheppo } 38401991Sheppo } 38411991Sheppo if (ack == 0) { 38421991Sheppo /* failed, send NACK */ 38431991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 38441991Sheppo } else { 38451991Sheppo if (!(ldcp->peer_hparams.dring_ready)) { 38461991Sheppo 38471991Sheppo /* save peer's dring_info values */ 38481991Sheppo bcopy(&dcookie, 38491991Sheppo &(ldcp->peer_hparams.dring_cookie), 38501991Sheppo sizeof (dcookie)); 38511991Sheppo ldcp->peer_hparams.num_desc = 38524650Sraghuram msg->num_descriptors; 38531991Sheppo ldcp->peer_hparams.desc_size = 38544650Sraghuram msg->descriptor_size; 38551991Sheppo ldcp->peer_hparams.num_dcookies = 38564650Sraghuram msg->ncookies; 38571991Sheppo 38581991Sheppo /* set dring_ident for the peer */ 38591991Sheppo ldcp->peer_hparams.dring_ident = 38604650Sraghuram (uint64_t)ldcp->rxdp; 38611991Sheppo /* return the dring_ident in ack msg */ 38621991Sheppo msg->dring_ident = 38634650Sraghuram (uint64_t)ldcp->rxdp; 38641991Sheppo 38651991Sheppo ldcp->peer_hparams.dring_ready = B_TRUE; 38661991Sheppo } 38671991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 38681991Sheppo } 38691991Sheppo tagp->vio_sid = ldcp->local_sid; 38701991Sheppo /* send reply msg back to peer */ 38712793Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msg), 38722793Slm66018 B_FALSE); 38732793Slm66018 if (rv != VGEN_SUCCESS) { 38742793Slm66018 return (rv); 38751991Sheppo } 38761991Sheppo 38771991Sheppo if (ack) { 38781991Sheppo ldcp->hstate |= DRING_ACK_SENT; 38794647Sraghuram DBG2(vgenp, ldcp, "DRING_ACK_SENT"); 38801991Sheppo } else { 38814647Sraghuram DWARN(vgenp, ldcp, "DRING_NACK_SENT"); 38822793Slm66018 return (VGEN_FAILURE); 38831991Sheppo } 38841991Sheppo 38851991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 38861991Sheppo vgen_handshake(vh_nextphase(ldcp)); 38871991Sheppo } 38881991Sheppo 38891991Sheppo break; 38901991Sheppo 38911991Sheppo case VIO_SUBTYPE_ACK: 38921991Sheppo 38931991Sheppo ldcp->hstate |= DRING_ACK_RCVD; 38941991Sheppo 38954647Sraghuram DBG2(vgenp, ldcp, "DRING_ACK_RCVD"); 38961991Sheppo 38971991Sheppo if (!(ldcp->local_hparams.dring_ready)) { 38981991Sheppo /* local dring is now ready */ 38991991Sheppo ldcp->local_hparams.dring_ready = B_TRUE; 39001991Sheppo 39011991Sheppo /* save dring_ident acked by peer */ 39021991Sheppo ldcp->local_hparams.dring_ident = 39034650Sraghuram msg->dring_ident; 39041991Sheppo } 39051991Sheppo 39061991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 39071991Sheppo vgen_handshake(vh_nextphase(ldcp)); 39081991Sheppo } 39091991Sheppo 39101991Sheppo break; 39111991Sheppo 39121991Sheppo case VIO_SUBTYPE_NACK: 39131991Sheppo 39144647Sraghuram DBG2(vgenp, ldcp, "DRING_NACK_RCVD"); 39152793Slm66018 return (VGEN_FAILURE); 39161991Sheppo } 39174647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 39182793Slm66018 return (VGEN_SUCCESS); 39191991Sheppo } 39201991Sheppo 39211991Sheppo /* 39221991Sheppo * Handle a rdx info msg from the peer or an ACK/NACK 39231991Sheppo * from the peer to a rdx info msg that we sent. 39241991Sheppo */ 39252793Slm66018 static int 39261991Sheppo vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 39271991Sheppo { 39282793Slm66018 int rv = 0; 39294647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 39304647Sraghuram 39314647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 39321991Sheppo if (ldcp->hphase != VH_PHASE3) { 39334647Sraghuram DWARN(vgenp, ldcp, 39344647Sraghuram "Rcvd RDX_INFO Subtype (%d), Invalid Phase(%u)\n", 39354650Sraghuram tagp->vio_subtype, ldcp->hphase); 39362793Slm66018 return (VGEN_FAILURE); 39371991Sheppo } 39381991Sheppo switch (tagp->vio_subtype) { 39391991Sheppo case VIO_SUBTYPE_INFO: 39401991Sheppo 39414647Sraghuram DBG2(vgenp, ldcp, "RDX_INFO_RCVD \n"); 39421991Sheppo ldcp->hstate |= RDX_INFO_RCVD; 39431991Sheppo 39441991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 39451991Sheppo tagp->vio_sid = ldcp->local_sid; 39461991Sheppo /* send reply msg back to peer */ 39472793Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vio_rdx_msg_t), 39482793Slm66018 B_FALSE); 39492793Slm66018 if (rv != VGEN_SUCCESS) { 39502793Slm66018 return (rv); 39511991Sheppo } 39521991Sheppo 39531991Sheppo ldcp->hstate |= RDX_ACK_SENT; 39544647Sraghuram DBG2(vgenp, ldcp, "RDX_ACK_SENT \n"); 39551991Sheppo 39561991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 39571991Sheppo vgen_handshake(vh_nextphase(ldcp)); 39581991Sheppo } 39591991Sheppo 39601991Sheppo break; 39611991Sheppo 39621991Sheppo case VIO_SUBTYPE_ACK: 39631991Sheppo 39641991Sheppo ldcp->hstate |= RDX_ACK_RCVD; 39651991Sheppo 39664647Sraghuram DBG2(vgenp, ldcp, "RDX_ACK_RCVD \n"); 39671991Sheppo 39681991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 39691991Sheppo vgen_handshake(vh_nextphase(ldcp)); 39701991Sheppo } 39711991Sheppo break; 39721991Sheppo 39731991Sheppo case VIO_SUBTYPE_NACK: 39741991Sheppo 39754647Sraghuram DBG2(vgenp, ldcp, "RDX_NACK_RCVD \n"); 39762793Slm66018 return (VGEN_FAILURE); 39771991Sheppo } 39784647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 39792793Slm66018 return (VGEN_SUCCESS); 39801991Sheppo } 39811991Sheppo 39821991Sheppo /* Handle ACK/NACK from vsw to a set multicast msg that we sent */ 39832793Slm66018 static int 39841991Sheppo vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 39851991Sheppo { 39861991Sheppo vgen_t *vgenp = LDC_TO_VGEN(ldcp); 39871991Sheppo vnet_mcast_msg_t *msgp = (vnet_mcast_msg_t *)tagp; 39881991Sheppo struct ether_addr *addrp; 39891991Sheppo int count; 39901991Sheppo int i; 39911991Sheppo 39924647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 39931991Sheppo switch (tagp->vio_subtype) { 39941991Sheppo 39951991Sheppo case VIO_SUBTYPE_INFO: 39961991Sheppo 39971991Sheppo /* vnet shouldn't recv set mcast msg, only vsw handles it */ 39984647Sraghuram DWARN(vgenp, ldcp, "rcvd SET_MCAST_INFO \n"); 39991991Sheppo break; 40001991Sheppo 40011991Sheppo case VIO_SUBTYPE_ACK: 40021991Sheppo 40031991Sheppo /* success adding/removing multicast addr */ 40044647Sraghuram DBG1(vgenp, ldcp, "rcvd SET_MCAST_ACK \n"); 40051991Sheppo break; 40061991Sheppo 40071991Sheppo case VIO_SUBTYPE_NACK: 40081991Sheppo 40094647Sraghuram DWARN(vgenp, ldcp, "rcvd SET_MCAST_NACK \n"); 40101991Sheppo if (!(msgp->set)) { 40111991Sheppo /* multicast remove request failed */ 40121991Sheppo break; 40131991Sheppo } 40141991Sheppo 40151991Sheppo /* multicast add request failed */ 40161991Sheppo for (count = 0; count < msgp->count; count++) { 40171991Sheppo addrp = &(msgp->mca[count]); 40181991Sheppo 40191991Sheppo /* delete address from the table */ 40201991Sheppo for (i = 0; i < vgenp->mccount; i++) { 40211991Sheppo if (ether_cmp(addrp, 40221991Sheppo &(vgenp->mctab[i])) == 0) { 40231991Sheppo if (vgenp->mccount > 1) { 40244647Sraghuram int t = vgenp->mccount - 1; 40251991Sheppo vgenp->mctab[i] = 40264650Sraghuram vgenp->mctab[t]; 40271991Sheppo } 40281991Sheppo vgenp->mccount--; 40291991Sheppo break; 40301991Sheppo } 40311991Sheppo } 40321991Sheppo } 40331991Sheppo break; 40341991Sheppo 40351991Sheppo } 40364647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 40372793Slm66018 40382793Slm66018 return (VGEN_SUCCESS); 40391991Sheppo } 40401991Sheppo 40411991Sheppo /* handler for control messages received from the peer ldc end-point */ 40422793Slm66018 static int 40431991Sheppo vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 40441991Sheppo { 40452793Slm66018 int rv = 0; 40464647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 40474647Sraghuram 40484647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 40491991Sheppo switch (tagp->vio_subtype_env) { 40501991Sheppo 40511991Sheppo case VIO_VER_INFO: 40522793Slm66018 rv = vgen_handle_version_negotiate(ldcp, tagp); 40531991Sheppo break; 40541991Sheppo 40551991Sheppo case VIO_ATTR_INFO: 40562793Slm66018 rv = vgen_handle_attr_info(ldcp, tagp); 40571991Sheppo break; 40581991Sheppo 40591991Sheppo case VIO_DRING_REG: 40602793Slm66018 rv = vgen_handle_dring_reg(ldcp, tagp); 40611991Sheppo break; 40621991Sheppo 40631991Sheppo case VIO_RDX: 40642793Slm66018 rv = vgen_handle_rdx_info(ldcp, tagp); 40651991Sheppo break; 40661991Sheppo 40671991Sheppo case VNET_MCAST_INFO: 40682793Slm66018 rv = vgen_handle_mcast_info(ldcp, tagp); 40691991Sheppo break; 40701991Sheppo 40711991Sheppo } 40722793Slm66018 40734647Sraghuram DBG1(vgenp, ldcp, "exit rv(%d)\n", rv); 40742793Slm66018 return (rv); 40751991Sheppo } 40761991Sheppo 40771991Sheppo /* handler for data messages received from the peer ldc end-point */ 40782793Slm66018 static int 40794647Sraghuram vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 40801991Sheppo { 40812793Slm66018 int rv = 0; 40824647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 40834647Sraghuram 40844647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 40851991Sheppo 40861991Sheppo if (ldcp->hphase != VH_DONE) 40872793Slm66018 return (rv); 40881991Sheppo switch (tagp->vio_subtype_env) { 40891991Sheppo case VIO_DRING_DATA: 40904647Sraghuram rv = vgen_handle_dring_data(ldcp, tagp); 40911991Sheppo break; 40921991Sheppo default: 40931991Sheppo break; 40941991Sheppo } 40951991Sheppo 40964647Sraghuram DBG1(vgenp, ldcp, "exit rv(%d)\n", rv); 40972793Slm66018 return (rv); 40981991Sheppo } 40991991Sheppo 41002793Slm66018 static int 41012336Snarayan vgen_send_dring_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, uint32_t start, 41022336Snarayan int32_t end, uint8_t pstate) 41032336Snarayan { 41044647Sraghuram int rv = 0; 41054647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 41062336Snarayan vio_dring_msg_t *msgp = (vio_dring_msg_t *)tagp; 41072336Snarayan 41082336Snarayan tagp->vio_subtype = VIO_SUBTYPE_ACK; 41092336Snarayan tagp->vio_sid = ldcp->local_sid; 41102336Snarayan msgp->start_idx = start; 41112336Snarayan msgp->end_idx = end; 41122336Snarayan msgp->dring_process_state = pstate; 41132793Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp), B_FALSE); 41142793Slm66018 if (rv != VGEN_SUCCESS) { 41154647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n"); 41162336Snarayan } 41172793Slm66018 return (rv); 41182336Snarayan } 41192336Snarayan 41202793Slm66018 static int 41214647Sraghuram vgen_handle_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 41221991Sheppo { 41232793Slm66018 int rv = 0; 41244647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 41254647Sraghuram 41264647Sraghuram 41274647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 41281991Sheppo switch (tagp->vio_subtype) { 41291991Sheppo 41301991Sheppo case VIO_SUBTYPE_INFO: 41311991Sheppo /* 41324647Sraghuram * To reduce the locking contention, release the 41334647Sraghuram * cblock here and re-acquire it once we are done 41344647Sraghuram * receiving packets. 41351991Sheppo */ 41364647Sraghuram mutex_exit(&ldcp->cblock); 41374647Sraghuram mutex_enter(&ldcp->rxlock); 41384647Sraghuram rv = vgen_handle_dring_data_info(ldcp, tagp); 41394647Sraghuram mutex_exit(&ldcp->rxlock); 41404647Sraghuram mutex_enter(&ldcp->cblock); 41414647Sraghuram break; 41424647Sraghuram 41434647Sraghuram case VIO_SUBTYPE_ACK: 41444647Sraghuram rv = vgen_handle_dring_data_ack(ldcp, tagp); 41454647Sraghuram break; 41464647Sraghuram 41474647Sraghuram case VIO_SUBTYPE_NACK: 41484647Sraghuram rv = vgen_handle_dring_data_nack(ldcp, tagp); 41494647Sraghuram break; 41504647Sraghuram } 41514647Sraghuram DBG1(vgenp, ldcp, "exit rv(%d)\n", rv); 41524647Sraghuram return (rv); 41534647Sraghuram } 41544647Sraghuram 41554647Sraghuram static int 41564647Sraghuram vgen_handle_dring_data_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 41574647Sraghuram { 41584647Sraghuram uint32_t start; 41594647Sraghuram int32_t end; 41604647Sraghuram int rv = 0; 41614647Sraghuram vio_dring_msg_t *dringmsg = (vio_dring_msg_t *)tagp; 41624647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 41634647Sraghuram #ifdef VGEN_HANDLE_LOST_PKTS 41644647Sraghuram vgen_stats_t *statsp = ldcp->statsp; 41654647Sraghuram uint32_t rxi; 41664647Sraghuram int n; 41674647Sraghuram #endif 41684647Sraghuram 41694647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 41704647Sraghuram 41714647Sraghuram start = dringmsg->start_idx; 41724647Sraghuram end = dringmsg->end_idx; 41734647Sraghuram /* 41744647Sraghuram * received a data msg, which contains the start and end 41754647Sraghuram * indices of the descriptors within the rx ring holding data, 41764647Sraghuram * the seq_num of data packet corresponding to the start index, 41774647Sraghuram * and the dring_ident. 41784647Sraghuram * We can now read the contents of each of these descriptors 41794647Sraghuram * and gather data from it. 41804647Sraghuram */ 41814647Sraghuram DBG1(vgenp, ldcp, "INFO: start(%d), end(%d)\n", 41824650Sraghuram start, end); 41834647Sraghuram 41844647Sraghuram /* validate rx start and end indeces */ 41854647Sraghuram if (!(CHECK_RXI(start, ldcp)) || ((end != -1) && 41864647Sraghuram !(CHECK_RXI(end, ldcp)))) { 41874647Sraghuram DWARN(vgenp, ldcp, "Invalid Rx start(%d) or end(%d)\n", 41884647Sraghuram start, end); 41894647Sraghuram /* drop the message if invalid index */ 41904647Sraghuram return (rv); 41914647Sraghuram } 41924647Sraghuram 41934647Sraghuram /* validate dring_ident */ 41944647Sraghuram if (dringmsg->dring_ident != ldcp->peer_hparams.dring_ident) { 41954647Sraghuram DWARN(vgenp, ldcp, "Invalid dring ident 0x%x\n", 41964647Sraghuram dringmsg->dring_ident); 41974647Sraghuram /* invalid dring_ident, drop the msg */ 41984647Sraghuram return (rv); 41994647Sraghuram } 42001991Sheppo #ifdef DEBUG 42014647Sraghuram if (vgen_trigger_rxlost) { 42024647Sraghuram /* drop this msg to simulate lost pkts for debugging */ 42034647Sraghuram vgen_trigger_rxlost = 0; 42044647Sraghuram return (rv); 42054647Sraghuram } 42061991Sheppo #endif 42071991Sheppo 42081991Sheppo #ifdef VGEN_HANDLE_LOST_PKTS 42091991Sheppo 42104647Sraghuram /* receive start index doesn't match expected index */ 42114647Sraghuram if (ldcp->next_rxi != start) { 42124647Sraghuram DWARN(vgenp, ldcp, "next_rxi(%d) != start(%d)\n", 42134647Sraghuram ldcp->next_rxi, start); 42144647Sraghuram 42154647Sraghuram /* calculate the number of pkts lost */ 42164647Sraghuram if (start >= ldcp->next_rxi) { 42174647Sraghuram n = start - ldcp->next_rxi; 42184647Sraghuram } else { 42194647Sraghuram n = ldcp->num_rxds - (ldcp->next_rxi - start); 42204647Sraghuram } 42214647Sraghuram 42224647Sraghuram /* 42234647Sraghuram * sequence number of dring data message 42244647Sraghuram * is less than the next sequence number that 42254647Sraghuram * is expected: 42264647Sraghuram * 42274647Sraghuram * drop the message and the corresponding packets. 42284647Sraghuram */ 42294647Sraghuram if (ldcp->next_rxseq > dringmsg->seq_num) { 42304647Sraghuram DWARN(vgenp, ldcp, "dropping pkts, expected " 42314647Sraghuram "rxseq(0x%lx) > recvd(0x%lx)\n", 42324647Sraghuram ldcp->next_rxseq, dringmsg->seq_num); 42331991Sheppo /* 42344647Sraghuram * duplicate/multiple retransmissions from 42354647Sraghuram * sender?? drop this msg. 42361991Sheppo */ 42374647Sraghuram return (rv); 42381991Sheppo } 42391991Sheppo 42401991Sheppo /* 42414647Sraghuram * sequence number of dring data message 42424647Sraghuram * is greater than the next expected sequence number 42434647Sraghuram * 42444647Sraghuram * send a NACK back to the peer to indicate lost 42454647Sraghuram * packets. 42461991Sheppo */ 42474647Sraghuram if (dringmsg->seq_num > ldcp->next_rxseq) { 42484647Sraghuram statsp->rx_lost_pkts += n; 42494647Sraghuram tagp->vio_subtype = VIO_SUBTYPE_NACK; 42504647Sraghuram tagp->vio_sid = ldcp->local_sid; 42514647Sraghuram /* indicate the range of lost descriptors */ 42524647Sraghuram dringmsg->start_idx = ldcp->next_rxi; 42534647Sraghuram rxi = start; 42544647Sraghuram DECR_RXI(rxi, ldcp); 42554647Sraghuram dringmsg->end_idx = rxi; 42564647Sraghuram /* dring ident is left unchanged */ 42574647Sraghuram rv = vgen_sendmsg(ldcp, (caddr_t)tagp, 42584647Sraghuram sizeof (*dringmsg), B_FALSE); 42594647Sraghuram if (rv != VGEN_SUCCESS) { 42604647Sraghuram DWARN(vgenp, ldcp, 42614647Sraghuram "vgen_sendmsg failed, stype:NACK\n"); 42624647Sraghuram return (rv); 42632336Snarayan } 42644647Sraghuram #ifdef VGEN_REXMIT 42654647Sraghuram /* 42664647Sraghuram * stop further processing until peer 42674647Sraghuram * retransmits with the right index. 42684647Sraghuram * update next_rxseq expected. 42694647Sraghuram */ 42704647Sraghuram ldcp->next_rxseq += 1; 42714647Sraghuram return (rv); 42724647Sraghuram #else /* VGEN_REXMIT */ 42734647Sraghuram /* 42744647Sraghuram * treat this range of descrs/pkts as dropped 42754647Sraghuram * and set the new expected values for next_rxi 42764647Sraghuram * and next_rxseq. continue(below) to process 42774647Sraghuram * from the new start index. 42784647Sraghuram */ 42794647Sraghuram ldcp->next_rxi = start; 42804647Sraghuram ldcp->next_rxseq += 1; 42814647Sraghuram #endif /* VGEN_REXMIT */ 42824647Sraghuram 42834647Sraghuram } else if (dringmsg->seq_num == ldcp->next_rxseq) { 42844647Sraghuram /* 42854647Sraghuram * expected and received seqnums match, but 42864647Sraghuram * the descriptor indeces don't? 42874647Sraghuram * 42884647Sraghuram * restart handshake with peer. 42894647Sraghuram */ 42904647Sraghuram DWARN(vgenp, ldcp, "next_rxseq(0x%lx)==" 42914650Sraghuram "seq_num(0x%lx)\n", ldcp->next_rxseq, 42924650Sraghuram dringmsg->seq_num); 42934647Sraghuram 42944647Sraghuram } 42954647Sraghuram 42964647Sraghuram } else { 42974647Sraghuram /* expected and start dring indeces match */ 42984647Sraghuram 42994647Sraghuram if (dringmsg->seq_num != ldcp->next_rxseq) { 43004647Sraghuram 43014647Sraghuram /* seqnums don't match */ 43024647Sraghuram 43034647Sraghuram DWARN(vgenp, ldcp, 43044647Sraghuram "next_rxseq(0x%lx) != seq_num(0x%lx)\n", 43054647Sraghuram ldcp->next_rxseq, dringmsg->seq_num); 43064647Sraghuram } 43074647Sraghuram } 43084647Sraghuram 43094647Sraghuram #endif /* VGEN_HANDLE_LOST_PKTS */ 43104647Sraghuram 43114647Sraghuram /* Now receive messages */ 43124647Sraghuram rv = vgen_process_dring_data(ldcp, tagp); 43134647Sraghuram 43144647Sraghuram DBG1(vgenp, ldcp, "exit rv(%d)\n", rv); 43154647Sraghuram return (rv); 43164647Sraghuram } 43174647Sraghuram 43184647Sraghuram static int 43194647Sraghuram vgen_process_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 43204647Sraghuram { 43214647Sraghuram boolean_t set_ack_start = B_FALSE; 43224647Sraghuram uint32_t start; 43234647Sraghuram uint32_t ack_end; 43244647Sraghuram uint32_t next_rxi; 43254647Sraghuram uint32_t rxi; 43264647Sraghuram int count = 0; 43274647Sraghuram int rv = 0; 43284647Sraghuram uint32_t retries = 0; 43294647Sraghuram vgen_stats_t *statsp; 43304647Sraghuram vnet_public_desc_t *rxdp; 43314647Sraghuram vio_dring_entry_hdr_t *hdrp; 43324647Sraghuram mblk_t *bp = NULL; 43334647Sraghuram mblk_t *bpt = NULL; 43344647Sraghuram uint32_t ack_start; 43354647Sraghuram uint32_t datalen; 43364647Sraghuram uint32_t ncookies; 43374647Sraghuram boolean_t rxd_err = B_FALSE; 43384647Sraghuram mblk_t *mp = NULL; 43394647Sraghuram size_t nbytes; 43404647Sraghuram boolean_t ack_needed = B_FALSE; 43414647Sraghuram size_t nread; 43424647Sraghuram uint64_t off = 0; 43434647Sraghuram struct ether_header *ehp; 43444647Sraghuram vio_dring_msg_t *dringmsg = (vio_dring_msg_t *)tagp; 43454647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 43464647Sraghuram 43474647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 43484647Sraghuram 43494647Sraghuram statsp = ldcp->statsp; 43504647Sraghuram start = dringmsg->start_idx; 43514647Sraghuram 43524647Sraghuram /* 43534647Sraghuram * start processing the descriptors from the specified 43544647Sraghuram * start index, up to the index a descriptor is not ready 43554647Sraghuram * to be processed or we process the entire descriptor ring 43564647Sraghuram * and wrap around upto the start index. 43574647Sraghuram */ 43584647Sraghuram 43594647Sraghuram /* need to set the start index of descriptors to be ack'd */ 43604647Sraghuram set_ack_start = B_TRUE; 43614647Sraghuram 43624647Sraghuram /* index upto which we have ack'd */ 43634647Sraghuram ack_end = start; 43644647Sraghuram DECR_RXI(ack_end, ldcp); 43654647Sraghuram 43664647Sraghuram next_rxi = rxi = start; 43674647Sraghuram do { 43684647Sraghuram vgen_recv_retry: 43694647Sraghuram rv = ldc_mem_dring_acquire(ldcp->rx_dhandle, rxi, rxi); 43704647Sraghuram if (rv != 0) { 43714647Sraghuram DWARN(vgenp, ldcp, "ldc_mem_dring_acquire() failed" 43724647Sraghuram " rv(%d)\n", rv); 43734647Sraghuram statsp->ierrors++; 43744647Sraghuram return (rv); 43754647Sraghuram } 43764647Sraghuram 43774647Sraghuram rxdp = &(ldcp->rxdp[rxi]); 43784647Sraghuram hdrp = &rxdp->hdr; 43794647Sraghuram 43804647Sraghuram if (hdrp->dstate != VIO_DESC_READY) { 43814647Sraghuram /* 43824647Sraghuram * Before waiting and retry here, queue 43834647Sraghuram * the messages that are received already. 43844647Sraghuram * This will help the soft interrupt to 43854647Sraghuram * send them up with less latency. 43864647Sraghuram */ 43874647Sraghuram if (bp != NULL) { 43884647Sraghuram DTRACE_PROBE1(vgen_rcv_msgs, int, count); 43894647Sraghuram vgen_ldc_queue_data(ldcp, bp, bpt); 43904647Sraghuram count = 0; 43914647Sraghuram bp = bpt = NULL; 43924647Sraghuram } 43934647Sraghuram /* 43944647Sraghuram * descriptor is not ready. 43954647Sraghuram * retry descriptor acquire, stop processing 43964647Sraghuram * after max # retries. 43974647Sraghuram */ 43984647Sraghuram if (retries == vgen_recv_retries) 43994647Sraghuram break; 44004647Sraghuram retries++; 44014647Sraghuram drv_usecwait(vgen_recv_delay); 44024647Sraghuram goto vgen_recv_retry; 44034647Sraghuram } 44044647Sraghuram retries = 0; 44054647Sraghuram 44064647Sraghuram if (set_ack_start) { 44074647Sraghuram /* 44084647Sraghuram * initialize the start index of the range 44094647Sraghuram * of descriptors to be ack'd. 44104647Sraghuram */ 44114647Sraghuram ack_start = rxi; 44124647Sraghuram set_ack_start = B_FALSE; 44134647Sraghuram } 44144647Sraghuram 44154647Sraghuram datalen = rxdp->nbytes; 44164647Sraghuram ncookies = rxdp->ncookies; 44174647Sraghuram if ((datalen < ETHERMIN) || 44184647Sraghuram (ncookies == 0) || 44194647Sraghuram (ncookies > MAX_COOKIES)) { 44204647Sraghuram rxd_err = B_TRUE; 44214647Sraghuram } else { 44224647Sraghuram /* 44234647Sraghuram * Try to allocate an mblk from the free pool 44244647Sraghuram * of recv mblks for the channel. 44254647Sraghuram * If this fails, use allocb(). 44264647Sraghuram */ 44274647Sraghuram nbytes = (VNET_IPALIGN + datalen + 7) & ~7; 44284647Sraghuram mp = vio_multipool_allocb(&ldcp->vmp, nbytes); 44294647Sraghuram if (!mp) { 44302336Snarayan /* 44314647Sraghuram * The data buffer returned by 44324647Sraghuram * allocb(9F) is 8byte aligned. We 44334647Sraghuram * allocate extra 8 bytes to ensure 44344647Sraghuram * size is multiple of 8 bytes for 44354647Sraghuram * ldc_mem_copy(). 44361991Sheppo */ 44374647Sraghuram statsp->rx_vio_allocb_fail++; 44384647Sraghuram mp = allocb(VNET_IPALIGN + datalen + 8, 44394647Sraghuram BPRI_MED); 44401991Sheppo } 44414647Sraghuram } 44424647Sraghuram if ((rxd_err) || (mp == NULL)) { 44434647Sraghuram /* 44444647Sraghuram * rxd_err or allocb() failure, 44454647Sraghuram * drop this packet, get next. 44464647Sraghuram */ 44474647Sraghuram if (rxd_err) { 44482793Slm66018 statsp->ierrors++; 44494647Sraghuram rxd_err = B_FALSE; 44504647Sraghuram } else { 44514647Sraghuram statsp->rx_allocb_fail++; 44522793Slm66018 } 44532793Slm66018 44542793Slm66018 ack_needed = hdrp->ack; 44554647Sraghuram 44564647Sraghuram /* set descriptor done bit */ 44571991Sheppo hdrp->dstate = VIO_DESC_DONE; 44581991Sheppo 44594647Sraghuram rv = ldc_mem_dring_release(ldcp->rx_dhandle, 44604647Sraghuram rxi, rxi); 44612793Slm66018 if (rv != 0) { 44624647Sraghuram DWARN(vgenp, ldcp, 44634647Sraghuram "ldc_mem_dring_release err rv(%d)\n", rv); 44644647Sraghuram return (rv); 44652793Slm66018 } 44662336Snarayan 44672793Slm66018 if (ack_needed) { 44682793Slm66018 ack_needed = B_FALSE; 44691991Sheppo /* 44702336Snarayan * sender needs ack for this packet, 44712336Snarayan * ack pkts upto this index. 44721991Sheppo */ 44732336Snarayan ack_end = rxi; 44742336Snarayan 44752793Slm66018 rv = vgen_send_dring_ack(ldcp, tagp, 44764647Sraghuram ack_start, ack_end, 44774647Sraghuram VIO_DP_ACTIVE); 44782793Slm66018 if (rv != VGEN_SUCCESS) { 44792793Slm66018 goto error_ret; 44802793Slm66018 } 44812336Snarayan 44822336Snarayan /* need to set new ack start index */ 44832336Snarayan set_ack_start = B_TRUE; 44841991Sheppo } 44854647Sraghuram goto vgen_next_rxi; 44864647Sraghuram } 44874647Sraghuram 44884647Sraghuram nread = nbytes; 44894647Sraghuram rv = ldc_mem_copy(ldcp->ldc_handle, 44904647Sraghuram (caddr_t)mp->b_rptr, off, &nread, 44914647Sraghuram rxdp->memcookie, ncookies, LDC_COPY_IN); 44924647Sraghuram 44934647Sraghuram /* if ldc_mem_copy() failed */ 44944647Sraghuram if (rv) { 44954647Sraghuram DWARN(vgenp, ldcp, "ldc_mem_copy err rv(%d)\n", rv); 44964647Sraghuram statsp->ierrors++; 44974647Sraghuram freemsg(mp); 44984647Sraghuram goto error_ret; 44994647Sraghuram } 45004647Sraghuram 45014647Sraghuram ack_needed = hdrp->ack; 45024647Sraghuram hdrp->dstate = VIO_DESC_DONE; 45034647Sraghuram 45044647Sraghuram rv = ldc_mem_dring_release(ldcp->rx_dhandle, rxi, rxi); 45054647Sraghuram if (rv != 0) { 45064647Sraghuram DWARN(vgenp, ldcp, 45074647Sraghuram "ldc_mem_dring_release err rv(%d)\n", rv); 45084647Sraghuram goto error_ret; 45094647Sraghuram } 45104647Sraghuram 45114647Sraghuram mp->b_rptr += VNET_IPALIGN; 45124647Sraghuram 45134647Sraghuram if (ack_needed) { 45144647Sraghuram ack_needed = B_FALSE; 45154647Sraghuram /* 45164647Sraghuram * sender needs ack for this packet, 45174647Sraghuram * ack pkts upto this index. 45184647Sraghuram */ 45194647Sraghuram ack_end = rxi; 45204647Sraghuram 45214647Sraghuram rv = vgen_send_dring_ack(ldcp, tagp, 45224647Sraghuram ack_start, ack_end, VIO_DP_ACTIVE); 45234647Sraghuram if (rv != VGEN_SUCCESS) { 45244647Sraghuram goto error_ret; 45251991Sheppo } 45261991Sheppo 45274647Sraghuram /* need to set new ack start index */ 45284647Sraghuram set_ack_start = B_TRUE; 45294647Sraghuram } 45304647Sraghuram 45314647Sraghuram if (nread != nbytes) { 45324647Sraghuram DWARN(vgenp, ldcp, 45334647Sraghuram "ldc_mem_copy nread(%lx), nbytes(%lx)\n", 45344647Sraghuram nread, nbytes); 45354647Sraghuram statsp->ierrors++; 45364647Sraghuram freemsg(mp); 45374647Sraghuram goto vgen_next_rxi; 45384647Sraghuram } 45394647Sraghuram 45404647Sraghuram /* point to the actual end of data */ 45414647Sraghuram mp->b_wptr = mp->b_rptr + datalen; 45424647Sraghuram 45434647Sraghuram /* update stats */ 45444647Sraghuram statsp->ipackets++; 45454647Sraghuram statsp->rbytes += datalen; 45464647Sraghuram ehp = (struct ether_header *)mp->b_rptr; 45474647Sraghuram if (IS_BROADCAST(ehp)) 45484647Sraghuram statsp->brdcstrcv++; 45494647Sraghuram else if (IS_MULTICAST(ehp)) 45504647Sraghuram statsp->multircv++; 45514647Sraghuram 45524647Sraghuram /* build a chain of received packets */ 45534647Sraghuram if (bp == NULL) { 45544647Sraghuram /* first pkt */ 45554647Sraghuram bp = mp; 45564647Sraghuram bpt = bp; 45574647Sraghuram bpt->b_next = NULL; 45584647Sraghuram } else { 45594647Sraghuram mp->b_next = NULL; 45604647Sraghuram bpt->b_next = mp; 45614647Sraghuram bpt = mp; 45624647Sraghuram } 45634647Sraghuram 45644647Sraghuram if (count++ > vgen_chain_len) { 45654647Sraghuram DTRACE_PROBE1(vgen_rcv_msgs, int, count); 45664647Sraghuram vgen_ldc_queue_data(ldcp, bp, bpt); 45674647Sraghuram count = 0; 45684647Sraghuram bp = bpt = NULL; 45694647Sraghuram } 45702336Snarayan 45712336Snarayan vgen_next_rxi: 45724647Sraghuram /* update end index of range of descrs to be ack'd */ 45734647Sraghuram ack_end = rxi; 45744647Sraghuram 45754647Sraghuram /* update the next index to be processed */ 45764647Sraghuram INCR_RXI(next_rxi, ldcp); 45774647Sraghuram if (next_rxi == start) { 45782336Snarayan /* 45794647Sraghuram * processed the entire descriptor ring upto 45804647Sraghuram * the index at which we started. 45812336Snarayan */ 45822336Snarayan break; 45832336Snarayan } 45842336Snarayan 45854647Sraghuram rxi = next_rxi; 45864647Sraghuram 45874647Sraghuram _NOTE(CONSTCOND) 45884647Sraghuram } while (1); 45894647Sraghuram 45904647Sraghuram /* 45914647Sraghuram * send an ack message to peer indicating that we have stopped 45924647Sraghuram * processing descriptors. 45934647Sraghuram */ 45944647Sraghuram if (set_ack_start) { 45952336Snarayan /* 45964647Sraghuram * We have ack'd upto some index and we have not 45974647Sraghuram * processed any descriptors beyond that index. 45984647Sraghuram * Use the last ack'd index as both the start and 45994647Sraghuram * end of range of descrs being ack'd. 46004647Sraghuram * Note: This results in acking the last index twice 46014647Sraghuram * and should be harmless. 46022336Snarayan */ 46034647Sraghuram ack_start = ack_end; 46044647Sraghuram } 46054647Sraghuram 46064647Sraghuram rv = vgen_send_dring_ack(ldcp, tagp, ack_start, ack_end, 46074647Sraghuram VIO_DP_STOPPED); 46084647Sraghuram if (rv != VGEN_SUCCESS) { 46094647Sraghuram goto error_ret; 46104647Sraghuram } 46114647Sraghuram 46124647Sraghuram /* save new recv index and expected seqnum of next dring msg */ 46134647Sraghuram ldcp->next_rxi = next_rxi; 46144647Sraghuram ldcp->next_rxseq += 1; 46154647Sraghuram 46164647Sraghuram error_ret: 46174647Sraghuram /* queue the packets received so far */ 46184647Sraghuram if (bp != NULL) { 46194647Sraghuram DTRACE_PROBE1(vgen_rcv_msgs, int, count); 46204647Sraghuram vgen_ldc_queue_data(ldcp, bp, bpt); 46214647Sraghuram bp = bpt = NULL; 46224647Sraghuram } 46234647Sraghuram DBG1(vgenp, ldcp, "exit rv(%d)\n", rv); 46244647Sraghuram return (rv); 46254647Sraghuram 46264647Sraghuram } 46274647Sraghuram 46284647Sraghuram static int 46294647Sraghuram vgen_handle_dring_data_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 46304647Sraghuram { 46314647Sraghuram int rv = 0; 46324647Sraghuram uint32_t start; 46334647Sraghuram int32_t end; 46344647Sraghuram uint32_t txi; 46354647Sraghuram boolean_t ready_txd = B_FALSE; 46364647Sraghuram vgen_stats_t *statsp; 46374647Sraghuram vgen_private_desc_t *tbufp; 46384647Sraghuram vnet_public_desc_t *txdp; 46394647Sraghuram vio_dring_entry_hdr_t *hdrp; 46404647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 46414647Sraghuram vio_dring_msg_t *dringmsg = (vio_dring_msg_t *)tagp; 46424647Sraghuram 46434647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 46444647Sraghuram start = dringmsg->start_idx; 46454647Sraghuram end = dringmsg->end_idx; 46464647Sraghuram statsp = ldcp->statsp; 46474647Sraghuram 46484647Sraghuram /* 46494647Sraghuram * received an ack corresponding to a specific descriptor for 46504647Sraghuram * which we had set the ACK bit in the descriptor (during 46514647Sraghuram * transmit). This enables us to reclaim descriptors. 46524647Sraghuram */ 46534647Sraghuram 46544647Sraghuram DBG2(vgenp, ldcp, "ACK: start(%d), end(%d)\n", start, end); 46554647Sraghuram 46564647Sraghuram /* validate start and end indeces in the tx ack msg */ 46574647Sraghuram if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) { 46584647Sraghuram /* drop the message if invalid index */ 46594647Sraghuram DWARN(vgenp, ldcp, "Invalid Tx ack start(%d) or end(%d)\n", 46604647Sraghuram start, end); 46614647Sraghuram return (rv); 46624647Sraghuram } 46634647Sraghuram /* validate dring_ident */ 46644647Sraghuram if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) { 46654647Sraghuram /* invalid dring_ident, drop the msg */ 46664647Sraghuram DWARN(vgenp, ldcp, "Invalid dring ident 0x%x\n", 46674647Sraghuram dringmsg->dring_ident); 46684647Sraghuram return (rv); 46694647Sraghuram } 46704647Sraghuram statsp->dring_data_acks++; 46714647Sraghuram 46724647Sraghuram /* reclaim descriptors that are done */ 46734647Sraghuram vgen_reclaim(ldcp); 46744647Sraghuram 46754647Sraghuram if (dringmsg->dring_process_state != VIO_DP_STOPPED) { 46762336Snarayan /* 46774647Sraghuram * receiver continued processing descriptors after 46784647Sraghuram * sending us the ack. 46792336Snarayan */ 46804647Sraghuram return (rv); 46814647Sraghuram } 46824647Sraghuram 46834647Sraghuram statsp->dring_stopped_acks++; 46844647Sraghuram 46854647Sraghuram /* receiver stopped processing descriptors */ 46864647Sraghuram mutex_enter(&ldcp->wrlock); 46874647Sraghuram mutex_enter(&ldcp->tclock); 46884647Sraghuram 46894647Sraghuram /* 46904647Sraghuram * determine if there are any pending tx descriptors 46914647Sraghuram * ready to be processed by the receiver(peer) and if so, 46924647Sraghuram * send a message to the peer to restart receiving. 46934647Sraghuram */ 46944647Sraghuram ready_txd = B_FALSE; 46954647Sraghuram 46964647Sraghuram /* 46974647Sraghuram * using the end index of the descriptor range for which 46984647Sraghuram * we received the ack, check if the next descriptor is 46994647Sraghuram * ready. 47004647Sraghuram */ 47014647Sraghuram txi = end; 47024647Sraghuram INCR_TXI(txi, ldcp); 47034647Sraghuram tbufp = &ldcp->tbufp[txi]; 47044647Sraghuram txdp = tbufp->descp; 47054647Sraghuram hdrp = &txdp->hdr; 47064647Sraghuram if (hdrp->dstate == VIO_DESC_READY) { 47074647Sraghuram ready_txd = B_TRUE; 47084647Sraghuram } else { 47094647Sraghuram /* 47104647Sraghuram * descr next to the end of ack'd descr range is not 47114647Sraghuram * ready. 47124647Sraghuram * starting from the current reclaim index, check 47134647Sraghuram * if any descriptor is ready. 47144647Sraghuram */ 47154647Sraghuram 47164647Sraghuram txi = ldcp->cur_tbufp - ldcp->tbufp; 47172336Snarayan tbufp = &ldcp->tbufp[txi]; 47184647Sraghuram 47192336Snarayan txdp = tbufp->descp; 47202336Snarayan hdrp = &txdp->hdr; 47212336Snarayan if (hdrp->dstate == VIO_DESC_READY) { 47222336Snarayan ready_txd = B_TRUE; 47234647Sraghuram } 47244647Sraghuram 47254647Sraghuram } 47264647Sraghuram 47274647Sraghuram if (ready_txd) { 47284647Sraghuram /* 47294647Sraghuram * we have tx descriptor(s) ready to be 47304647Sraghuram * processed by the receiver. 47314647Sraghuram * send a message to the peer with the start index 47324647Sraghuram * of ready descriptors. 47334647Sraghuram */ 47344647Sraghuram rv = vgen_send_dring_data(ldcp, txi, -1); 47354647Sraghuram if (rv != VGEN_SUCCESS) { 47364647Sraghuram ldcp->resched_peer = B_TRUE; 47374647Sraghuram ldcp->resched_peer_txi = txi; 47384647Sraghuram mutex_exit(&ldcp->tclock); 47394647Sraghuram mutex_exit(&ldcp->wrlock); 47404647Sraghuram return (rv); 47412336Snarayan } 47424647Sraghuram } else { 47434647Sraghuram /* 47444647Sraghuram * no ready tx descriptors. set the flag to send a 47454647Sraghuram * message to peer when tx descriptors are ready in 47464647Sraghuram * transmit routine. 47474647Sraghuram */ 47484647Sraghuram ldcp->resched_peer = B_TRUE; 47494647Sraghuram ldcp->resched_peer_txi = ldcp->cur_tbufp - ldcp->tbufp; 47504647Sraghuram } 47514647Sraghuram 47524647Sraghuram mutex_exit(&ldcp->tclock); 47534647Sraghuram mutex_exit(&ldcp->wrlock); 47544647Sraghuram DBG1(vgenp, ldcp, "exit rv(%d)\n", rv); 47554647Sraghuram return (rv); 47564647Sraghuram } 47574647Sraghuram 47584647Sraghuram static int 47594647Sraghuram vgen_handle_dring_data_nack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 47604647Sraghuram { 47614647Sraghuram int rv = 0; 47624647Sraghuram uint32_t start; 47634647Sraghuram int32_t end; 47644647Sraghuram uint32_t txi; 47654647Sraghuram vnet_public_desc_t *txdp; 47664647Sraghuram vio_dring_entry_hdr_t *hdrp; 47674647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 47684647Sraghuram vio_dring_msg_t *dringmsg = (vio_dring_msg_t *)tagp; 47694647Sraghuram #ifdef VGEN_REXMIT 47704647Sraghuram vgen_stats_t *statsp = ldcp->statsp; 47714647Sraghuram #endif 47724647Sraghuram 47734647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 47744647Sraghuram start = dringmsg->start_idx; 47754647Sraghuram end = dringmsg->end_idx; 47764647Sraghuram 47774647Sraghuram /* 47784647Sraghuram * peer sent a NACK msg to indicate lost packets. 47794647Sraghuram * The start and end correspond to the range of descriptors 47804647Sraghuram * for which the peer didn't receive a dring data msg and so 47814647Sraghuram * didn't receive the corresponding data. 47824647Sraghuram */ 47834647Sraghuram DWARN(vgenp, ldcp, "NACK: start(%d), end(%d)\n", start, end); 47844647Sraghuram 47854647Sraghuram /* validate start and end indeces in the tx nack msg */ 47864647Sraghuram if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) { 47874647Sraghuram /* drop the message if invalid index */ 47884647Sraghuram DWARN(vgenp, ldcp, "Invalid Tx nack start(%d) or end(%d)\n", 47894647Sraghuram start, end); 47904647Sraghuram return (rv); 47914647Sraghuram } 47924647Sraghuram /* validate dring_ident */ 47934647Sraghuram if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) { 47944647Sraghuram /* invalid dring_ident, drop the msg */ 47954647Sraghuram DWARN(vgenp, ldcp, "Invalid dring ident 0x%x\n", 47964647Sraghuram dringmsg->dring_ident); 47974647Sraghuram return (rv); 47984647Sraghuram } 47994647Sraghuram mutex_enter(&ldcp->txlock); 48004647Sraghuram mutex_enter(&ldcp->tclock); 48014647Sraghuram 48024647Sraghuram if (ldcp->next_tbufp == ldcp->cur_tbufp) { 48034647Sraghuram /* no busy descriptors, bogus nack ? */ 48042336Snarayan mutex_exit(&ldcp->tclock); 48052336Snarayan mutex_exit(&ldcp->txlock); 48064647Sraghuram return (rv); 48074647Sraghuram } 48081991Sheppo 48091991Sheppo #ifdef VGEN_REXMIT 48104647Sraghuram /* send a new dring data msg including the lost descrs */ 48114647Sraghuram end = ldcp->next_tbufp - ldcp->tbufp; 48124647Sraghuram DECR_TXI(end, ldcp); 48134647Sraghuram rv = vgen_send_dring_data(ldcp, start, end); 48144647Sraghuram if (rv != 0) { 48154647Sraghuram /* 48164647Sraghuram * vgen_send_dring_data() error: drop all packets 48174647Sraghuram * in this descr range 48184647Sraghuram */ 48194647Sraghuram DWARN(vgenp, ldcp, "vgen_send_dring_data failed: rv(%d)\n", rv); 48204647Sraghuram for (txi = start; txi <= end; ) { 48214647Sraghuram tbufp = &(ldcp->tbufp[txi]); 48224647Sraghuram txdp = tbufp->descp; 48234647Sraghuram hdrp = &txdp->hdr; 48244647Sraghuram tbufp->flags = VGEN_PRIV_DESC_FREE; 48254647Sraghuram hdrp->dstate = VIO_DESC_FREE; 48264647Sraghuram hdrp->ack = B_FALSE; 48274647Sraghuram statsp->oerrors++; 48281991Sheppo } 48294647Sraghuram 48304647Sraghuram /* update next pointer */ 48314647Sraghuram ldcp->next_tbufp = &(ldcp->tbufp[start]); 48324647Sraghuram ldcp->next_txi = start; 48334647Sraghuram } 48344647Sraghuram DBG2(vgenp, ldcp, "rexmit: start(%d) end(%d)\n", start, end); 48351991Sheppo #else /* VGEN_REXMIT */ 48364647Sraghuram /* we just mark the descrs as done so they can be reclaimed */ 48374647Sraghuram for (txi = start; txi <= end; ) { 48384647Sraghuram txdp = &(ldcp->txdp[txi]); 48394647Sraghuram hdrp = &txdp->hdr; 48404647Sraghuram if (hdrp->dstate == VIO_DESC_READY) 48414647Sraghuram hdrp->dstate = VIO_DESC_DONE; 48424647Sraghuram INCR_TXI(txi, ldcp); 48434647Sraghuram } 48441991Sheppo #endif /* VGEN_REXMIT */ 48454647Sraghuram mutex_exit(&ldcp->tclock); 48464647Sraghuram mutex_exit(&ldcp->txlock); 48474647Sraghuram DBG1(vgenp, ldcp, "exit rv(%d)\n", rv); 48482793Slm66018 return (rv); 48491991Sheppo } 48501991Sheppo 48511991Sheppo static void 48521991Sheppo vgen_reclaim(vgen_ldc_t *ldcp) 48531991Sheppo { 48542336Snarayan mutex_enter(&ldcp->tclock); 48552336Snarayan 48561991Sheppo vgen_reclaim_dring(ldcp); 48571991Sheppo ldcp->reclaim_lbolt = ddi_get_lbolt(); 48582336Snarayan 48591991Sheppo mutex_exit(&ldcp->tclock); 48601991Sheppo } 48611991Sheppo 48621991Sheppo /* 48631991Sheppo * transmit reclaim function. starting from the current reclaim index 48641991Sheppo * look for descriptors marked DONE and reclaim the descriptor and the 48651991Sheppo * corresponding buffers (tbuf). 48661991Sheppo */ 48671991Sheppo static void 48681991Sheppo vgen_reclaim_dring(vgen_ldc_t *ldcp) 48691991Sheppo { 48705022Sraghuram int count = 0; 48711991Sheppo vnet_public_desc_t *txdp; 48721991Sheppo vgen_private_desc_t *tbufp; 48731991Sheppo vio_dring_entry_hdr_t *hdrp; 48742336Snarayan vgen_t *vgenp = LDC_TO_VGEN(ldcp); 48751991Sheppo 48761991Sheppo #ifdef DEBUG 48771991Sheppo if (vgen_trigger_txtimeout) 48781991Sheppo return; 48791991Sheppo #endif 48801991Sheppo 48811991Sheppo tbufp = ldcp->cur_tbufp; 48821991Sheppo txdp = tbufp->descp; 48831991Sheppo hdrp = &txdp->hdr; 48841991Sheppo 48851991Sheppo while ((hdrp->dstate == VIO_DESC_DONE) && 48861991Sheppo (tbufp != ldcp->next_tbufp)) { 48871991Sheppo tbufp->flags = VGEN_PRIV_DESC_FREE; 48881991Sheppo hdrp->dstate = VIO_DESC_FREE; 48891991Sheppo hdrp->ack = B_FALSE; 48901991Sheppo 48911991Sheppo tbufp = NEXTTBUF(ldcp, tbufp); 48921991Sheppo txdp = tbufp->descp; 48931991Sheppo hdrp = &txdp->hdr; 48945022Sraghuram count++; 48951991Sheppo } 48961991Sheppo 48971991Sheppo ldcp->cur_tbufp = tbufp; 48981991Sheppo 48991991Sheppo /* 49001991Sheppo * Check if mac layer should be notified to restart transmissions 49011991Sheppo */ 49025022Sraghuram if ((ldcp->need_resched) && (count > 0)) { 49031991Sheppo ldcp->need_resched = B_FALSE; 49042311Sseb vnet_tx_update(vgenp->vnetp); 49051991Sheppo } 49061991Sheppo } 49071991Sheppo 49081991Sheppo /* return the number of pending transmits for the channel */ 49091991Sheppo static int 49101991Sheppo vgen_num_txpending(vgen_ldc_t *ldcp) 49111991Sheppo { 49121991Sheppo int n; 49131991Sheppo 49141991Sheppo if (ldcp->next_tbufp >= ldcp->cur_tbufp) { 49151991Sheppo n = ldcp->next_tbufp - ldcp->cur_tbufp; 49161991Sheppo } else { 49171991Sheppo /* cur_tbufp > next_tbufp */ 49181991Sheppo n = ldcp->num_txds - (ldcp->cur_tbufp - ldcp->next_tbufp); 49191991Sheppo } 49201991Sheppo 49211991Sheppo return (n); 49221991Sheppo } 49231991Sheppo 49241991Sheppo /* determine if the transmit descriptor ring is full */ 49251991Sheppo static int 49261991Sheppo vgen_tx_dring_full(vgen_ldc_t *ldcp) 49271991Sheppo { 49281991Sheppo vgen_private_desc_t *tbufp; 49291991Sheppo vgen_private_desc_t *ntbufp; 49301991Sheppo 49311991Sheppo tbufp = ldcp->next_tbufp; 49321991Sheppo ntbufp = NEXTTBUF(ldcp, tbufp); 49331991Sheppo if (ntbufp == ldcp->cur_tbufp) { /* out of tbufs/txds */ 49341991Sheppo return (VGEN_SUCCESS); 49351991Sheppo } 49361991Sheppo return (VGEN_FAILURE); 49371991Sheppo } 49381991Sheppo 49391991Sheppo /* determine if timeout condition has occured */ 49401991Sheppo static int 49411991Sheppo vgen_ldc_txtimeout(vgen_ldc_t *ldcp) 49421991Sheppo { 49431991Sheppo if (((ddi_get_lbolt() - ldcp->reclaim_lbolt) > 49444650Sraghuram drv_usectohz(vnet_ldcwd_txtimeout * 1000)) && 49454650Sraghuram (vnet_ldcwd_txtimeout) && 49464650Sraghuram (vgen_tx_dring_full(ldcp) == VGEN_SUCCESS)) { 49471991Sheppo return (VGEN_SUCCESS); 49481991Sheppo } else { 49491991Sheppo return (VGEN_FAILURE); 49501991Sheppo } 49511991Sheppo } 49521991Sheppo 49531991Sheppo /* transmit watchdog timeout handler */ 49541991Sheppo static void 49551991Sheppo vgen_ldc_watchdog(void *arg) 49561991Sheppo { 49571991Sheppo vgen_ldc_t *ldcp; 49582336Snarayan vgen_t *vgenp; 49591991Sheppo int rv; 49601991Sheppo 49611991Sheppo ldcp = (vgen_ldc_t *)arg; 49622336Snarayan vgenp = LDC_TO_VGEN(ldcp); 49631991Sheppo 49641991Sheppo rv = vgen_ldc_txtimeout(ldcp); 49651991Sheppo if (rv == VGEN_SUCCESS) { 49664647Sraghuram DWARN(vgenp, ldcp, "transmit timeout\n"); 49671991Sheppo #ifdef DEBUG 49681991Sheppo if (vgen_trigger_txtimeout) { 49691991Sheppo /* tx timeout triggered for debugging */ 49701991Sheppo vgen_trigger_txtimeout = 0; 49711991Sheppo } 49721991Sheppo #endif 49731991Sheppo mutex_enter(&ldcp->cblock); 49742793Slm66018 ldcp->need_ldc_reset = B_TRUE; 49753653Snarayan vgen_handshake_retry(ldcp); 49761991Sheppo mutex_exit(&ldcp->cblock); 49771991Sheppo if (ldcp->need_resched) { 49781991Sheppo ldcp->need_resched = B_FALSE; 49792336Snarayan vnet_tx_update(vgenp->vnetp); 49801991Sheppo } 49811991Sheppo } 49821991Sheppo 49831991Sheppo ldcp->wd_tid = timeout(vgen_ldc_watchdog, (caddr_t)ldcp, 49841991Sheppo drv_usectohz(vnet_ldcwd_interval * 1000)); 49851991Sheppo } 49861991Sheppo 49871991Sheppo static int 49881991Sheppo vgen_setup_kstats(vgen_ldc_t *ldcp) 49891991Sheppo { 49901991Sheppo vgen_t *vgenp; 49911991Sheppo struct kstat *ksp; 49921991Sheppo vgen_stats_t *statsp; 49931991Sheppo vgen_kstats_t *ldckp; 49941991Sheppo int instance; 49951991Sheppo size_t size; 49961991Sheppo char name[MAXNAMELEN]; 49971991Sheppo 49981991Sheppo vgenp = LDC_TO_VGEN(ldcp); 49991991Sheppo instance = ddi_get_instance(vgenp->vnetdip); 50001991Sheppo (void) sprintf(name, "vnetldc0x%lx", ldcp->ldc_id); 50011991Sheppo statsp = kmem_zalloc(sizeof (vgen_stats_t), KM_SLEEP); 50021991Sheppo if (statsp == NULL) { 50031991Sheppo return (VGEN_FAILURE); 50041991Sheppo } 50051991Sheppo size = sizeof (vgen_kstats_t) / sizeof (kstat_named_t); 50061991Sheppo ksp = kstat_create("vnet", instance, name, "net", KSTAT_TYPE_NAMED, 50074650Sraghuram size, 0); 50081991Sheppo if (ksp == NULL) { 50091991Sheppo KMEM_FREE(statsp); 50101991Sheppo return (VGEN_FAILURE); 50111991Sheppo } 50121991Sheppo 50131991Sheppo ldckp = (vgen_kstats_t *)ksp->ks_data; 50141991Sheppo kstat_named_init(&ldckp->ipackets, "ipackets", 50154650Sraghuram KSTAT_DATA_ULONG); 50161991Sheppo kstat_named_init(&ldckp->ipackets64, "ipackets64", 50174650Sraghuram KSTAT_DATA_ULONGLONG); 50181991Sheppo kstat_named_init(&ldckp->ierrors, "ierrors", 50194650Sraghuram KSTAT_DATA_ULONG); 50201991Sheppo kstat_named_init(&ldckp->opackets, "opackets", 50214650Sraghuram KSTAT_DATA_ULONG); 50221991Sheppo kstat_named_init(&ldckp->opackets64, "opackets64", 50234650Sraghuram KSTAT_DATA_ULONGLONG); 50241991Sheppo kstat_named_init(&ldckp->oerrors, "oerrors", 50254650Sraghuram KSTAT_DATA_ULONG); 50261991Sheppo 50271991Sheppo 50281991Sheppo /* MIB II kstat variables */ 50291991Sheppo kstat_named_init(&ldckp->rbytes, "rbytes", 50304650Sraghuram KSTAT_DATA_ULONG); 50311991Sheppo kstat_named_init(&ldckp->rbytes64, "rbytes64", 50324650Sraghuram KSTAT_DATA_ULONGLONG); 50331991Sheppo kstat_named_init(&ldckp->obytes, "obytes", 50344650Sraghuram KSTAT_DATA_ULONG); 50351991Sheppo kstat_named_init(&ldckp->obytes64, "obytes64", 50364650Sraghuram KSTAT_DATA_ULONGLONG); 50371991Sheppo kstat_named_init(&ldckp->multircv, "multircv", 50384650Sraghuram KSTAT_DATA_ULONG); 50391991Sheppo kstat_named_init(&ldckp->multixmt, "multixmt", 50404650Sraghuram KSTAT_DATA_ULONG); 50411991Sheppo kstat_named_init(&ldckp->brdcstrcv, "brdcstrcv", 50424650Sraghuram KSTAT_DATA_ULONG); 50431991Sheppo kstat_named_init(&ldckp->brdcstxmt, "brdcstxmt", 50444650Sraghuram KSTAT_DATA_ULONG); 50451991Sheppo kstat_named_init(&ldckp->norcvbuf, "norcvbuf", 50464650Sraghuram KSTAT_DATA_ULONG); 50471991Sheppo kstat_named_init(&ldckp->noxmtbuf, "noxmtbuf", 50484650Sraghuram KSTAT_DATA_ULONG); 50491991Sheppo 50501991Sheppo /* Tx stats */ 50511991Sheppo kstat_named_init(&ldckp->tx_no_desc, "tx_no_desc", 50524650Sraghuram KSTAT_DATA_ULONG); 50531991Sheppo 50541991Sheppo /* Rx stats */ 50552336Snarayan kstat_named_init(&ldckp->rx_allocb_fail, "rx_allocb_fail", 50564650Sraghuram KSTAT_DATA_ULONG); 50572336Snarayan kstat_named_init(&ldckp->rx_vio_allocb_fail, "rx_vio_allocb_fail", 50584650Sraghuram KSTAT_DATA_ULONG); 50591991Sheppo kstat_named_init(&ldckp->rx_lost_pkts, "rx_lost_pkts", 50604650Sraghuram KSTAT_DATA_ULONG); 50611991Sheppo 50621991Sheppo /* Interrupt stats */ 50631991Sheppo kstat_named_init(&ldckp->callbacks, "callbacks", 50644650Sraghuram KSTAT_DATA_ULONG); 50651991Sheppo kstat_named_init(&ldckp->dring_data_acks, "dring_data_acks", 50664650Sraghuram KSTAT_DATA_ULONG); 50672336Snarayan kstat_named_init(&ldckp->dring_stopped_acks, "dring_stopped_acks", 50684650Sraghuram KSTAT_DATA_ULONG); 50692336Snarayan kstat_named_init(&ldckp->dring_data_msgs, "dring_data_msgs", 50704650Sraghuram KSTAT_DATA_ULONG); 50711991Sheppo 50721991Sheppo ksp->ks_update = vgen_kstat_update; 50731991Sheppo ksp->ks_private = (void *)ldcp; 50741991Sheppo kstat_install(ksp); 50751991Sheppo 50761991Sheppo ldcp->ksp = ksp; 50771991Sheppo ldcp->statsp = statsp; 50781991Sheppo return (VGEN_SUCCESS); 50791991Sheppo } 50801991Sheppo 50811991Sheppo static void 50821991Sheppo vgen_destroy_kstats(vgen_ldc_t *ldcp) 50831991Sheppo { 50841991Sheppo if (ldcp->ksp) 50851991Sheppo kstat_delete(ldcp->ksp); 50861991Sheppo KMEM_FREE(ldcp->statsp); 50871991Sheppo } 50881991Sheppo 50891991Sheppo static int 50901991Sheppo vgen_kstat_update(kstat_t *ksp, int rw) 50911991Sheppo { 50921991Sheppo vgen_ldc_t *ldcp; 50931991Sheppo vgen_stats_t *statsp; 50941991Sheppo vgen_kstats_t *ldckp; 50951991Sheppo 50961991Sheppo ldcp = (vgen_ldc_t *)ksp->ks_private; 50971991Sheppo statsp = ldcp->statsp; 50981991Sheppo ldckp = (vgen_kstats_t *)ksp->ks_data; 50991991Sheppo 51001991Sheppo if (rw == KSTAT_READ) { 51011991Sheppo ldckp->ipackets.value.ul = (uint32_t)statsp->ipackets; 51021991Sheppo ldckp->ipackets64.value.ull = statsp->ipackets; 51031991Sheppo ldckp->ierrors.value.ul = statsp->ierrors; 51041991Sheppo ldckp->opackets.value.ul = (uint32_t)statsp->opackets; 51051991Sheppo ldckp->opackets64.value.ull = statsp->opackets; 51061991Sheppo ldckp->oerrors.value.ul = statsp->oerrors; 51071991Sheppo 51081991Sheppo /* 51091991Sheppo * MIB II kstat variables 51101991Sheppo */ 51111991Sheppo ldckp->rbytes.value.ul = (uint32_t)statsp->rbytes; 51121991Sheppo ldckp->rbytes64.value.ull = statsp->rbytes; 51131991Sheppo ldckp->obytes.value.ul = (uint32_t)statsp->obytes; 51141991Sheppo ldckp->obytes64.value.ull = statsp->obytes; 51151991Sheppo ldckp->multircv.value.ul = statsp->multircv; 51161991Sheppo ldckp->multixmt.value.ul = statsp->multixmt; 51171991Sheppo ldckp->brdcstrcv.value.ul = statsp->brdcstrcv; 51181991Sheppo ldckp->brdcstxmt.value.ul = statsp->brdcstxmt; 51191991Sheppo ldckp->norcvbuf.value.ul = statsp->norcvbuf; 51201991Sheppo ldckp->noxmtbuf.value.ul = statsp->noxmtbuf; 51211991Sheppo 51221991Sheppo ldckp->tx_no_desc.value.ul = statsp->tx_no_desc; 51232336Snarayan 51241991Sheppo ldckp->rx_allocb_fail.value.ul = statsp->rx_allocb_fail; 51252336Snarayan ldckp->rx_vio_allocb_fail.value.ul = statsp->rx_vio_allocb_fail; 51261991Sheppo ldckp->rx_lost_pkts.value.ul = statsp->rx_lost_pkts; 51271991Sheppo 51281991Sheppo ldckp->callbacks.value.ul = statsp->callbacks; 51291991Sheppo ldckp->dring_data_acks.value.ul = statsp->dring_data_acks; 51302336Snarayan ldckp->dring_stopped_acks.value.ul = statsp->dring_stopped_acks; 51312336Snarayan ldckp->dring_data_msgs.value.ul = statsp->dring_data_msgs; 51321991Sheppo } else { 51331991Sheppo statsp->ipackets = ldckp->ipackets64.value.ull; 51341991Sheppo statsp->ierrors = ldckp->ierrors.value.ul; 51351991Sheppo statsp->opackets = ldckp->opackets64.value.ull; 51361991Sheppo statsp->oerrors = ldckp->oerrors.value.ul; 51371991Sheppo 51381991Sheppo /* 51391991Sheppo * MIB II kstat variables 51401991Sheppo */ 51411991Sheppo statsp->rbytes = ldckp->rbytes64.value.ull; 51421991Sheppo statsp->obytes = ldckp->obytes64.value.ull; 51431991Sheppo statsp->multircv = ldckp->multircv.value.ul; 51441991Sheppo statsp->multixmt = ldckp->multixmt.value.ul; 51451991Sheppo statsp->brdcstrcv = ldckp->brdcstrcv.value.ul; 51461991Sheppo statsp->brdcstxmt = ldckp->brdcstxmt.value.ul; 51471991Sheppo statsp->norcvbuf = ldckp->norcvbuf.value.ul; 51481991Sheppo statsp->noxmtbuf = ldckp->noxmtbuf.value.ul; 51491991Sheppo 51501991Sheppo statsp->tx_no_desc = ldckp->tx_no_desc.value.ul; 51512336Snarayan 51521991Sheppo statsp->rx_allocb_fail = ldckp->rx_allocb_fail.value.ul; 51532336Snarayan statsp->rx_vio_allocb_fail = ldckp->rx_vio_allocb_fail.value.ul; 51541991Sheppo statsp->rx_lost_pkts = ldckp->rx_lost_pkts.value.ul; 51551991Sheppo 51561991Sheppo statsp->callbacks = ldckp->callbacks.value.ul; 51571991Sheppo statsp->dring_data_acks = ldckp->dring_data_acks.value.ul; 51582336Snarayan statsp->dring_stopped_acks = ldckp->dring_stopped_acks.value.ul; 51592336Snarayan statsp->dring_data_msgs = ldckp->dring_data_msgs.value.ul; 51601991Sheppo } 51611991Sheppo 51621991Sheppo return (VGEN_SUCCESS); 51631991Sheppo } 51641991Sheppo 51651991Sheppo /* handler for error messages received from the peer ldc end-point */ 51661991Sheppo static void 51671991Sheppo vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 51681991Sheppo { 51691991Sheppo _NOTE(ARGUNUSED(ldcp, tagp)) 51701991Sheppo } 51711991Sheppo 51721991Sheppo /* Check if the session id in the received message is valid */ 51731991Sheppo static int 51741991Sheppo vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 51751991Sheppo { 51764647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 51774647Sraghuram 51781991Sheppo if (tagp->vio_sid != ldcp->peer_sid) { 51794647Sraghuram DWARN(vgenp, ldcp, "sid mismatch: expected(%x), rcvd(%x)\n", 51804647Sraghuram ldcp->peer_sid, tagp->vio_sid); 51811991Sheppo return (VGEN_FAILURE); 51821991Sheppo } 51831991Sheppo else 51841991Sheppo return (VGEN_SUCCESS); 51851991Sheppo } 51861991Sheppo 51871991Sheppo /* convert mac address from string to uint64_t */ 51881991Sheppo static uint64_t 51891991Sheppo vgen_macaddr_strtoul(const uint8_t *macaddr) 51901991Sheppo { 51911991Sheppo uint64_t val = 0; 51921991Sheppo int i; 51931991Sheppo 51941991Sheppo for (i = 0; i < ETHERADDRL; i++) { 51951991Sheppo val <<= 8; 51961991Sheppo val |= macaddr[i]; 51971991Sheppo } 51981991Sheppo 51991991Sheppo return (val); 52001991Sheppo } 52011991Sheppo 52021991Sheppo /* convert mac address from uint64_t to string */ 52031991Sheppo static int 52041991Sheppo vgen_macaddr_ultostr(uint64_t val, uint8_t *macaddr) 52051991Sheppo { 52061991Sheppo int i; 52071991Sheppo uint64_t value; 52081991Sheppo 52091991Sheppo value = val; 52101991Sheppo for (i = ETHERADDRL - 1; i >= 0; i--) { 52111991Sheppo macaddr[i] = value & 0xFF; 52121991Sheppo value >>= 8; 52131991Sheppo } 52141991Sheppo return (VGEN_SUCCESS); 52151991Sheppo } 52161991Sheppo 52171991Sheppo static caddr_t 52181991Sheppo vgen_print_ethaddr(uint8_t *a, char *ebuf) 52191991Sheppo { 52201991Sheppo (void) sprintf(ebuf, 52214650Sraghuram "%x:%x:%x:%x:%x:%x", a[0], a[1], a[2], a[3], a[4], a[5]); 52221991Sheppo return (ebuf); 52231991Sheppo } 52241991Sheppo 52251991Sheppo /* Handshake watchdog timeout handler */ 52261991Sheppo static void 52271991Sheppo vgen_hwatchdog(void *arg) 52281991Sheppo { 52291991Sheppo vgen_ldc_t *ldcp = (vgen_ldc_t *)arg; 52304647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 52314647Sraghuram 52324647Sraghuram DWARN(vgenp, ldcp, 52334647Sraghuram "handshake timeout ldc(%lx) phase(%x) state(%x)\n", 52344647Sraghuram ldcp->hphase, ldcp->hstate); 52351991Sheppo 52361991Sheppo mutex_enter(&ldcp->cblock); 52373653Snarayan if (ldcp->cancel_htid) { 52383653Snarayan ldcp->cancel_htid = 0; 52393653Snarayan mutex_exit(&ldcp->cblock); 52403653Snarayan return; 52413653Snarayan } 52421991Sheppo ldcp->htid = 0; 52432841Snarayan ldcp->need_ldc_reset = B_TRUE; 52441991Sheppo vgen_handshake_retry(ldcp); 52451991Sheppo mutex_exit(&ldcp->cblock); 52461991Sheppo } 52471991Sheppo 52481991Sheppo static void 52491991Sheppo vgen_print_hparams(vgen_hparams_t *hp) 52501991Sheppo { 52511991Sheppo uint8_t addr[6]; 52521991Sheppo char ea[6]; 52531991Sheppo ldc_mem_cookie_t *dc; 52541991Sheppo 52551991Sheppo cmn_err(CE_CONT, "version_info:\n"); 52561991Sheppo cmn_err(CE_CONT, 52571991Sheppo "\tver_major: %d, ver_minor: %d, dev_class: %d\n", 52581991Sheppo hp->ver_major, hp->ver_minor, hp->dev_class); 52591991Sheppo 52601991Sheppo (void) vgen_macaddr_ultostr(hp->addr, addr); 52611991Sheppo cmn_err(CE_CONT, "attr_info:\n"); 52621991Sheppo cmn_err(CE_CONT, "\tMTU: %lx, addr: %s\n", hp->mtu, 52631991Sheppo vgen_print_ethaddr(addr, ea)); 52641991Sheppo cmn_err(CE_CONT, 52651991Sheppo "\taddr_type: %x, xfer_mode: %x, ack_freq: %x\n", 52661991Sheppo hp->addr_type, hp->xfer_mode, hp->ack_freq); 52671991Sheppo 52681991Sheppo dc = &hp->dring_cookie; 52691991Sheppo cmn_err(CE_CONT, "dring_info:\n"); 52701991Sheppo cmn_err(CE_CONT, 52711991Sheppo "\tlength: %d, dsize: %d\n", hp->num_desc, hp->desc_size); 52721991Sheppo cmn_err(CE_CONT, 52731991Sheppo "\tldc_addr: 0x%lx, ldc_size: %ld\n", 52741991Sheppo dc->addr, dc->size); 52751991Sheppo cmn_err(CE_CONT, "\tdring_ident: 0x%lx\n", hp->dring_ident); 52761991Sheppo } 52771991Sheppo 52781991Sheppo static void 52791991Sheppo vgen_print_ldcinfo(vgen_ldc_t *ldcp) 52801991Sheppo { 52811991Sheppo vgen_hparams_t *hp; 52821991Sheppo 52831991Sheppo cmn_err(CE_CONT, "Channel Information:\n"); 52841991Sheppo cmn_err(CE_CONT, 52851991Sheppo "\tldc_id: 0x%lx, ldc_status: 0x%x\n", 52861991Sheppo ldcp->ldc_id, ldcp->ldc_status); 52871991Sheppo cmn_err(CE_CONT, 52881991Sheppo "\tlocal_sid: 0x%x, peer_sid: 0x%x\n", 52891991Sheppo ldcp->local_sid, ldcp->peer_sid); 52901991Sheppo cmn_err(CE_CONT, 52911991Sheppo "\thphase: 0x%x, hstate: 0x%x\n", 52921991Sheppo ldcp->hphase, ldcp->hstate); 52931991Sheppo 52941991Sheppo cmn_err(CE_CONT, "Local handshake params:\n"); 52951991Sheppo hp = &ldcp->local_hparams; 52961991Sheppo vgen_print_hparams(hp); 52971991Sheppo 52981991Sheppo cmn_err(CE_CONT, "Peer handshake params:\n"); 52991991Sheppo hp = &ldcp->peer_hparams; 53001991Sheppo vgen_print_hparams(hp); 53011991Sheppo } 53024647Sraghuram 53034647Sraghuram /* 53044647Sraghuram * vgen_ldc_queue_data -- Queue data in the LDC. 53054647Sraghuram */ 53064647Sraghuram static void 53074647Sraghuram vgen_ldc_queue_data(vgen_ldc_t *ldcp, mblk_t *rhead, mblk_t *rtail) 53084647Sraghuram { 53094647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 53104647Sraghuram 53114647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 53124647Sraghuram /* 53134647Sraghuram * If the receive thread is enabled, then the queue 53144647Sraghuram * is protected by the soft_lock. After queuing, trigger 53154647Sraghuram * the soft interrupt so that the interrupt handler sends these 53164647Sraghuram * messages up the stack. 53174647Sraghuram * 53184647Sraghuram * If the receive thread is not enabled, then the list is 53194647Sraghuram * automatically protected by the cblock lock, so no need 53204647Sraghuram * to hold any additional locks. 53214647Sraghuram */ 53224647Sraghuram if (ldcp->rcv_thread != NULL) { 53234647Sraghuram mutex_enter(&ldcp->soft_lock); 53244647Sraghuram } 53254647Sraghuram if (ldcp->rcv_mhead == NULL) { 53264647Sraghuram ldcp->rcv_mhead = rhead; 53274647Sraghuram ldcp->rcv_mtail = rtail; 53284647Sraghuram } else { 53294647Sraghuram ldcp->rcv_mtail->b_next = rhead; 53304647Sraghuram ldcp->rcv_mtail = rtail; 53314647Sraghuram } 53324647Sraghuram if (ldcp->rcv_thread != NULL) { 53334647Sraghuram mutex_exit(&ldcp->soft_lock); 53344647Sraghuram (void) ddi_intr_trigger_softint(ldcp->soft_handle, NULL); 53354647Sraghuram } 53364647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 53374647Sraghuram } 53384647Sraghuram 53394647Sraghuram /* 53404647Sraghuram * vgen_ldc_rcv_worker -- A per LDC worker thread to receive data. 53414647Sraghuram * This thread is woken up by the LDC interrupt handler to process 53424647Sraghuram * LDC packets and receive data. 53434647Sraghuram */ 53444647Sraghuram static void 53454647Sraghuram vgen_ldc_rcv_worker(void *arg) 53464647Sraghuram { 53474647Sraghuram callb_cpr_t cprinfo; 53484647Sraghuram vgen_ldc_t *ldcp = (vgen_ldc_t *)arg; 53494647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 53504647Sraghuram 53514647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 53524647Sraghuram CALLB_CPR_INIT(&cprinfo, &ldcp->rcv_thr_lock, callb_generic_cpr, 53534650Sraghuram "vnet_rcv_thread"); 53544647Sraghuram mutex_enter(&ldcp->rcv_thr_lock); 53554647Sraghuram ldcp->rcv_thr_flags |= VGEN_WTHR_RUNNING; 53564647Sraghuram while (!(ldcp->rcv_thr_flags & VGEN_WTHR_STOP)) { 53574647Sraghuram 53584647Sraghuram CALLB_CPR_SAFE_BEGIN(&cprinfo); 53594647Sraghuram /* 53604647Sraghuram * Wait until the data is received or a stop 53614647Sraghuram * request is received. 53624647Sraghuram */ 53634647Sraghuram while (!(ldcp->rcv_thr_flags & 53644647Sraghuram (VGEN_WTHR_DATARCVD | VGEN_WTHR_STOP))) { 53654647Sraghuram cv_wait(&ldcp->rcv_thr_cv, &ldcp->rcv_thr_lock); 53664647Sraghuram } 53674647Sraghuram CALLB_CPR_SAFE_END(&cprinfo, &ldcp->rcv_thr_lock) 53684647Sraghuram 53694647Sraghuram /* 53704647Sraghuram * First process the stop request. 53714647Sraghuram */ 53724647Sraghuram if (ldcp->rcv_thr_flags & VGEN_WTHR_STOP) { 53734647Sraghuram DBG2(vgenp, ldcp, "stopped\n"); 53744647Sraghuram break; 53754647Sraghuram } 53764647Sraghuram ldcp->rcv_thr_flags &= ~VGEN_WTHR_DATARCVD; 53774647Sraghuram mutex_exit(&ldcp->rcv_thr_lock); 53784647Sraghuram DBG2(vgenp, ldcp, "calling vgen_handle_evt_read\n"); 53794647Sraghuram vgen_handle_evt_read(ldcp); 53804647Sraghuram mutex_enter(&ldcp->rcv_thr_lock); 53814647Sraghuram } 53824647Sraghuram 53834647Sraghuram /* 53844647Sraghuram * Update the run status and wakeup the thread that 53854647Sraghuram * has sent the stop request. 53864647Sraghuram */ 53874647Sraghuram ldcp->rcv_thr_flags &= ~VGEN_WTHR_RUNNING; 53884647Sraghuram cv_signal(&ldcp->rcv_thr_cv); 53894647Sraghuram CALLB_CPR_EXIT(&cprinfo); 53904647Sraghuram thread_exit(); 53914647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 53924647Sraghuram } 53934647Sraghuram 53944647Sraghuram /* vgen_stop_rcv_thread -- Co-ordinate with receive thread to stop it */ 53954647Sraghuram static void 53964647Sraghuram vgen_stop_rcv_thread(vgen_ldc_t *ldcp) 53974647Sraghuram { 53984647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 53994647Sraghuram 54004647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 54014647Sraghuram /* 54024647Sraghuram * Send a stop request by setting the stop flag and 54034647Sraghuram * wait until the receive thread stops. 54044647Sraghuram */ 54054647Sraghuram mutex_enter(&ldcp->rcv_thr_lock); 54064647Sraghuram if (ldcp->rcv_thr_flags & VGEN_WTHR_RUNNING) { 54074647Sraghuram ldcp->rcv_thr_flags |= VGEN_WTHR_STOP; 54084647Sraghuram cv_signal(&ldcp->rcv_thr_cv); 54094647Sraghuram DBG2(vgenp, ldcp, "waiting..."); 54104647Sraghuram while (ldcp->rcv_thr_flags & VGEN_WTHR_RUNNING) { 54114647Sraghuram cv_wait(&ldcp->rcv_thr_cv, &ldcp->rcv_thr_lock); 54124647Sraghuram } 54134647Sraghuram } 54144647Sraghuram mutex_exit(&ldcp->rcv_thr_lock); 54154647Sraghuram ldcp->rcv_thread = NULL; 54164647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 54174647Sraghuram } 54184647Sraghuram 54194647Sraghuram /* 54204647Sraghuram * vgen_ldc_rcv_softintr -- LDC Soft interrupt handler function. 54214647Sraghuram * Its job is to pickup the recieved packets that are queued in the 54224647Sraghuram * LDC and send them up. 54234647Sraghuram * 54244647Sraghuram * NOTE: An interrupt handler is being used to handle the upper 54254647Sraghuram * layer(s) requirement to send up only at interrupt context. 54264647Sraghuram */ 54274647Sraghuram /* ARGSUSED */ 54284647Sraghuram static uint_t 54294647Sraghuram vgen_ldc_rcv_softintr(caddr_t arg1, caddr_t arg2) 54304647Sraghuram { 54314647Sraghuram mblk_t *mp; 54324647Sraghuram vgen_ldc_t *ldcp = (vgen_ldc_t *)arg1; 54334647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 54344647Sraghuram 54354647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 54364647Sraghuram DTRACE_PROBE1(vgen_soft_intr, uint64_t, ldcp->ldc_id); 54374647Sraghuram mutex_enter(&ldcp->soft_lock); 54384647Sraghuram mp = ldcp->rcv_mhead; 54394647Sraghuram ldcp->rcv_mhead = ldcp->rcv_mtail = NULL; 54404647Sraghuram mutex_exit(&ldcp->soft_lock); 54414647Sraghuram if (mp != NULL) { 54424647Sraghuram vnet_rx(vgenp->vnetp, NULL, mp); 54434647Sraghuram } 54444647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 54454647Sraghuram return (DDI_INTR_CLAIMED); 54464647Sraghuram } 54474647Sraghuram 54484647Sraghuram #if DEBUG 54494647Sraghuram 54504647Sraghuram /* 54514647Sraghuram * Print debug messages - set to 0xf to enable all msgs 54524647Sraghuram */ 54534647Sraghuram static void 54544647Sraghuram debug_printf(const char *fname, vgen_t *vgenp, 54554647Sraghuram vgen_ldc_t *ldcp, const char *fmt, ...) 54564647Sraghuram { 54574647Sraghuram char buf[256]; 54584647Sraghuram char *bufp = buf; 54594647Sraghuram va_list ap; 54604647Sraghuram 54614647Sraghuram if ((vgenp != NULL) && (vgenp->vnetp != NULL)) { 54624647Sraghuram (void) sprintf(bufp, "vnet%d:", 54634650Sraghuram ((vnet_t *)(vgenp->vnetp))->instance); 54644647Sraghuram bufp += strlen(bufp); 54654647Sraghuram } 54664647Sraghuram if (ldcp != NULL) { 54674647Sraghuram (void) sprintf(bufp, "ldc(%ld):", ldcp->ldc_id); 54684647Sraghuram bufp += strlen(bufp); 54694647Sraghuram } 54704647Sraghuram (void) sprintf(bufp, "%s: ", fname); 54714647Sraghuram bufp += strlen(bufp); 54724647Sraghuram 54734647Sraghuram va_start(ap, fmt); 54744647Sraghuram (void) vsprintf(bufp, fmt, ap); 54754647Sraghuram va_end(ap); 54764647Sraghuram 54774647Sraghuram if ((ldcp == NULL) ||(vgendbg_ldcid == -1) || 54784647Sraghuram (vgendbg_ldcid == ldcp->ldc_id)) { 54794647Sraghuram cmn_err(CE_CONT, "%s\n", buf); 54804647Sraghuram } 54814647Sraghuram } 54824647Sraghuram #endif 5483