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 /* 23*3653Snarayan * 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> 331991Sheppo #include <sys/kmem.h> 341991Sheppo #include <sys/conf.h> 351991Sheppo #include <sys/devops.h> 361991Sheppo #include <sys/ksynch.h> 371991Sheppo #include <sys/stat.h> 381991Sheppo #include <sys/modctl.h> 391991Sheppo #include <sys/debug.h> 401991Sheppo #include <sys/ethernet.h> 411991Sheppo #include <sys/ddi.h> 421991Sheppo #include <sys/sunddi.h> 431991Sheppo #include <sys/strsun.h> 441991Sheppo #include <sys/note.h> 451991Sheppo #include <sys/mac.h> 462311Sseb #include <sys/mac_ether.h> 471991Sheppo #include <sys/ldc.h> 481991Sheppo #include <sys/mach_descrip.h> 491991Sheppo #include <sys/mdeg.h> 501991Sheppo #include <sys/vio_mailbox.h> 511991Sheppo #include <sys/vio_common.h> 521991Sheppo #include <sys/vnet_common.h> 532336Snarayan #include <sys/vnet_mailbox.h> 542336Snarayan #include <sys/vio_util.h> 551991Sheppo #include <sys/vnet_gen.h> 561991Sheppo 571991Sheppo /* 581991Sheppo * Implementation of the mac functionality for vnet using the 591991Sheppo * generic(default) transport layer of sun4v Logical Domain Channels(LDC). 601991Sheppo */ 611991Sheppo 621991Sheppo /* 631991Sheppo * Function prototypes. 641991Sheppo */ 651991Sheppo /* vgen proxy entry points */ 662311Sseb int vgen_init(void *vnetp, dev_info_t *vnetdip, const uint8_t *macaddr, 672311Sseb mac_register_t **vgenmacp); 682336Snarayan int vgen_uninit(void *arg); 691991Sheppo static int vgen_start(void *arg); 701991Sheppo static void vgen_stop(void *arg); 711991Sheppo static mblk_t *vgen_tx(void *arg, mblk_t *mp); 721991Sheppo static int vgen_multicst(void *arg, boolean_t add, 731991Sheppo const uint8_t *mca); 741991Sheppo static int vgen_promisc(void *arg, boolean_t on); 751991Sheppo static int vgen_unicst(void *arg, const uint8_t *mca); 762311Sseb static int vgen_stat(void *arg, uint_t stat, uint64_t *val); 771991Sheppo static void vgen_ioctl(void *arg, queue_t *wq, mblk_t *mp); 781991Sheppo 791991Sheppo /* externs - functions provided by vnet to add/remove/modify entries in fdb */ 801991Sheppo void vnet_add_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg); 811991Sheppo void vnet_del_fdb(void *arg, uint8_t *macaddr); 822793Slm66018 void vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, 832793Slm66018 void *txarg, boolean_t upgrade); 841991Sheppo void vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg); 851991Sheppo void vnet_del_def_rte(void *arg); 862311Sseb void vnet_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp); 872311Sseb void vnet_tx_update(void *arg); 881991Sheppo 891991Sheppo /* vgen internal functions */ 901991Sheppo static void vgen_detach_ports(vgen_t *vgenp); 911991Sheppo static void vgen_port_detach(vgen_port_t *portp); 921991Sheppo static void vgen_port_list_insert(vgen_port_t *portp); 931991Sheppo static void vgen_port_list_remove(vgen_port_t *portp); 941991Sheppo static vgen_port_t *vgen_port_lookup(vgen_portlist_t *plistp, 951991Sheppo int port_num); 961991Sheppo static int vgen_mdeg_reg(vgen_t *vgenp); 971991Sheppo static void vgen_mdeg_unreg(vgen_t *vgenp); 981991Sheppo static int vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp); 991991Sheppo static int vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex); 1001991Sheppo static int vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex); 1011991Sheppo static int vgen_port_attach_mdeg(vgen_t *vgenp, int port_num, uint64_t *ldcids, 1021991Sheppo int num_ids, struct ether_addr *macaddr, boolean_t vsw_port); 1031991Sheppo static void vgen_port_detach_mdeg(vgen_port_t *portp); 1041991Sheppo static int vgen_update_port(vgen_t *vgenp, md_t *curr_mdp, 1051991Sheppo mde_cookie_t curr_mdex, md_t *prev_mdp, mde_cookie_t prev_mdex); 1062311Sseb static uint64_t vgen_port_stat(vgen_port_t *portp, uint_t stat); 1071991Sheppo 1081991Sheppo static int vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id); 1091991Sheppo static void vgen_ldc_detach(vgen_ldc_t *ldcp); 1101991Sheppo static int vgen_alloc_tx_ring(vgen_ldc_t *ldcp); 1111991Sheppo static void vgen_free_tx_ring(vgen_ldc_t *ldcp); 1121991Sheppo static void vgen_init_ports(vgen_t *vgenp); 1131991Sheppo static void vgen_port_init(vgen_port_t *portp); 1141991Sheppo static void vgen_uninit_ports(vgen_t *vgenp); 1151991Sheppo static void vgen_port_uninit(vgen_port_t *portp); 1161991Sheppo static void vgen_init_ldcs(vgen_port_t *portp); 1171991Sheppo static void vgen_uninit_ldcs(vgen_port_t *portp); 1181991Sheppo static int vgen_ldc_init(vgen_ldc_t *ldcp); 1191991Sheppo static void vgen_ldc_uninit(vgen_ldc_t *ldcp); 1201991Sheppo static int vgen_init_tbufs(vgen_ldc_t *ldcp); 1211991Sheppo static void vgen_uninit_tbufs(vgen_ldc_t *ldcp); 1221991Sheppo static void vgen_clobber_tbufs(vgen_ldc_t *ldcp); 1231991Sheppo static void vgen_clobber_rxds(vgen_ldc_t *ldcp); 1242311Sseb static uint64_t vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat); 1251991Sheppo static uint_t vgen_ldc_cb(uint64_t event, caddr_t arg); 1261991Sheppo static int vgen_portsend(vgen_port_t *portp, mblk_t *mp); 1271991Sheppo static int vgen_ldcsend(vgen_ldc_t *ldcp, mblk_t *mp); 1281991Sheppo static void vgen_reclaim(vgen_ldc_t *ldcp); 1291991Sheppo static void vgen_reclaim_dring(vgen_ldc_t *ldcp); 1301991Sheppo static int vgen_num_txpending(vgen_ldc_t *ldcp); 1311991Sheppo static int vgen_tx_dring_full(vgen_ldc_t *ldcp); 1321991Sheppo static int vgen_ldc_txtimeout(vgen_ldc_t *ldcp); 1331991Sheppo static void vgen_ldc_watchdog(void *arg); 1341991Sheppo static int vgen_setup_kstats(vgen_ldc_t *ldcp); 1351991Sheppo static void vgen_destroy_kstats(vgen_ldc_t *ldcp); 1361991Sheppo static int vgen_kstat_update(kstat_t *ksp, int rw); 1371991Sheppo 1381991Sheppo /* vgen handshake functions */ 1391991Sheppo static vgen_ldc_t *vh_nextphase(vgen_ldc_t *ldcp); 1401991Sheppo static int vgen_supported_version(vgen_ldc_t *ldcp, uint16_t ver_major, 1411991Sheppo uint16_t ver_minor); 1421991Sheppo static int vgen_next_version(vgen_ldc_t *ldcp, vgen_ver_t *verp); 1431991Sheppo static int vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg, size_t msglen, 1441991Sheppo boolean_t caller_holds_lock); 1451991Sheppo static int vgen_send_version_negotiate(vgen_ldc_t *ldcp); 1461991Sheppo static int vgen_send_attr_info(vgen_ldc_t *ldcp); 1471991Sheppo static int vgen_send_dring_reg(vgen_ldc_t *ldcp); 1481991Sheppo static int vgen_send_rdx_info(vgen_ldc_t *ldcp); 1492336Snarayan static int vgen_send_dring_data(vgen_ldc_t *ldcp, uint32_t start, int32_t end); 1501991Sheppo static int vgen_send_mcast_info(vgen_ldc_t *ldcp); 1511991Sheppo static int vgen_handshake_phase2(vgen_ldc_t *ldcp); 1521991Sheppo static void vgen_handshake_reset(vgen_ldc_t *ldcp); 1531991Sheppo static void vgen_reset_hphase(vgen_ldc_t *ldcp); 1541991Sheppo static void vgen_handshake(vgen_ldc_t *ldcp); 1551991Sheppo static int vgen_handshake_done(vgen_ldc_t *ldcp); 1561991Sheppo static void vgen_handshake_retry(vgen_ldc_t *ldcp); 1572793Slm66018 static int vgen_handle_version_negotiate(vgen_ldc_t *ldcp, 1581991Sheppo vio_msg_tag_t *tagp); 1592793Slm66018 static int vgen_handle_attr_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1602793Slm66018 static int vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1612793Slm66018 static int vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1622793Slm66018 static int vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1632793Slm66018 static int vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1642793Slm66018 static int vgen_handle_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, 1651991Sheppo mblk_t **headp, mblk_t **tailp); 1662793Slm66018 static int vgen_send_dring_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, 1672336Snarayan uint32_t start, int32_t end, uint8_t pstate); 1682793Slm66018 static int vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, 1691991Sheppo mblk_t **headp, mblk_t **tailp); 1701991Sheppo static void vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1712793Slm66018 static void vgen_handle_evt_up(vgen_ldc_t *ldcp, boolean_t flag); 1722793Slm66018 static void vgen_handle_evt_reset(vgen_ldc_t *ldcp, boolean_t flag); 1731991Sheppo static int vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1741991Sheppo static uint64_t vgen_macaddr_strtoul(const uint8_t *macaddr); 1751991Sheppo static int vgen_macaddr_ultostr(uint64_t value, uint8_t *macaddr); 1761991Sheppo static caddr_t vgen_print_ethaddr(uint8_t *a, char *ebuf); 1771991Sheppo static void vgen_hwatchdog(void *arg); 1781991Sheppo static void vgen_print_attr_info(vgen_ldc_t *ldcp, int endpoint); 1791991Sheppo static void vgen_print_hparams(vgen_hparams_t *hp); 1801991Sheppo static void vgen_print_ldcinfo(vgen_ldc_t *ldcp); 1811991Sheppo 1821991Sheppo /* 1831991Sheppo * The handshake process consists of 5 phases defined below, with VH_PHASE0 1841991Sheppo * being the pre-handshake phase and VH_DONE is the phase to indicate 1851991Sheppo * successful completion of all phases. 1861991Sheppo * Each phase may have one to several handshake states which are required 1871991Sheppo * to complete successfully to move to the next phase. 1881991Sheppo * Refer to the functions vgen_handshake() and vgen_handshake_done() for 1891991Sheppo * more details. 1901991Sheppo */ 1911991Sheppo /* handshake phases */ 1921991Sheppo enum { VH_PHASE0, VH_PHASE1, VH_PHASE2, VH_PHASE3, VH_DONE = 0x80 }; 1931991Sheppo 1941991Sheppo /* handshake states */ 1951991Sheppo enum { 1961991Sheppo 1971991Sheppo VER_INFO_SENT = 0x1, 1981991Sheppo VER_ACK_RCVD = 0x2, 1991991Sheppo VER_INFO_RCVD = 0x4, 2001991Sheppo VER_ACK_SENT = 0x8, 2011991Sheppo VER_NEGOTIATED = (VER_ACK_RCVD | VER_ACK_SENT), 2021991Sheppo 2031991Sheppo ATTR_INFO_SENT = 0x10, 2041991Sheppo ATTR_ACK_RCVD = 0x20, 2051991Sheppo ATTR_INFO_RCVD = 0x40, 2061991Sheppo ATTR_ACK_SENT = 0x80, 2071991Sheppo ATTR_INFO_EXCHANGED = (ATTR_ACK_RCVD | ATTR_ACK_SENT), 2081991Sheppo 2091991Sheppo DRING_INFO_SENT = 0x100, 2101991Sheppo DRING_ACK_RCVD = 0x200, 2111991Sheppo DRING_INFO_RCVD = 0x400, 2121991Sheppo DRING_ACK_SENT = 0x800, 2131991Sheppo DRING_INFO_EXCHANGED = (DRING_ACK_RCVD | DRING_ACK_SENT), 2141991Sheppo 2151991Sheppo RDX_INFO_SENT = 0x1000, 2161991Sheppo RDX_ACK_RCVD = 0x2000, 2171991Sheppo RDX_INFO_RCVD = 0x4000, 2181991Sheppo RDX_ACK_SENT = 0x8000, 2191991Sheppo RDX_EXCHANGED = (RDX_ACK_RCVD | RDX_ACK_SENT) 2201991Sheppo 2211991Sheppo }; 2221991Sheppo 2231991Sheppo #define LDC_LOCK(ldcp) \ 2241991Sheppo mutex_enter(&((ldcp)->cblock));\ 2251991Sheppo mutex_enter(&((ldcp)->txlock));\ 2261991Sheppo mutex_enter(&((ldcp)->tclock)); 2271991Sheppo #define LDC_UNLOCK(ldcp) \ 2281991Sheppo mutex_exit(&((ldcp)->tclock));\ 2291991Sheppo mutex_exit(&((ldcp)->txlock));\ 2301991Sheppo mutex_exit(&((ldcp)->cblock)); 2311991Sheppo 2321991Sheppo static struct ether_addr etherbroadcastaddr = { 2331991Sheppo 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 2341991Sheppo }; 2351991Sheppo /* 2361991Sheppo * MIB II broadcast/multicast packets 2371991Sheppo */ 2381991Sheppo #define IS_BROADCAST(ehp) \ 2391991Sheppo (ether_cmp(&ehp->ether_dhost, ðerbroadcastaddr) == 0) 2401991Sheppo #define IS_MULTICAST(ehp) \ 2411991Sheppo ((ehp->ether_dhost.ether_addr_octet[0] & 01) == 1) 2421991Sheppo 2431991Sheppo /* 2441991Sheppo * Property names 2451991Sheppo */ 2461991Sheppo static char macaddr_propname[] = "mac-address"; 2471991Sheppo static char rmacaddr_propname[] = "remote-mac-address"; 2481991Sheppo static char channel_propname[] = "channel-endpoint"; 2491991Sheppo static char reg_propname[] = "reg"; 2501991Sheppo static char port_propname[] = "port"; 2511991Sheppo static char swport_propname[] = "switch-port"; 2521991Sheppo static char id_propname[] = "id"; 2531991Sheppo 2541991Sheppo /* versions supported - in decreasing order */ 2551991Sheppo static vgen_ver_t vgen_versions[VGEN_NUM_VER] = { {1, 0} }; 2561991Sheppo 2571991Sheppo /* Tunables */ 2581991Sheppo uint32_t vgen_hwd_interval = 1000; /* handshake watchdog freq in msec */ 2593297Ssb155480 uint32_t vgen_max_hretries = VNET_NUM_HANDSHAKES; /* # of handshake retries */ 2601991Sheppo uint32_t vgen_ldcwr_retries = 10; /* max # of ldc_write() retries */ 2612109Slm66018 uint32_t vgen_ldcup_retries = 5; /* max # of ldc_up() retries */ 2622336Snarayan uint32_t vgen_recv_delay = 1; /* delay when rx descr not ready */ 2632336Snarayan uint32_t vgen_recv_retries = 10; /* retry when rx descr not ready */ 2641991Sheppo 2651991Sheppo #ifdef DEBUG 2661991Sheppo /* flags to simulate error conditions for debugging */ 2671991Sheppo int vgen_trigger_txtimeout = 0; 2681991Sheppo int vgen_trigger_rxlost = 0; 2691991Sheppo #endif 2701991Sheppo 2711991Sheppo /* MD update matching structure */ 2721991Sheppo static md_prop_match_t vport_prop_match[] = { 2731991Sheppo { MDET_PROP_VAL, "id" }, 2741991Sheppo { MDET_LIST_END, NULL } 2751991Sheppo }; 2761991Sheppo 2771991Sheppo static mdeg_node_match_t vport_match = { "virtual-device-port", 2781991Sheppo vport_prop_match }; 2791991Sheppo 2801991Sheppo /* template for matching a particular vnet instance */ 2811991Sheppo static mdeg_prop_spec_t vgen_prop_template[] = { 2821991Sheppo { MDET_PROP_STR, "name", "network" }, 2831991Sheppo { MDET_PROP_VAL, "cfg-handle", NULL }, 2841991Sheppo { MDET_LIST_END, NULL, NULL } 2851991Sheppo }; 2861991Sheppo 2871991Sheppo #define VGEN_SET_MDEG_PROP_INST(specp, val) (specp)[1].ps_val = (val) 2881991Sheppo 2891991Sheppo static int vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp); 2901991Sheppo 2912311Sseb static mac_callbacks_t vgen_m_callbacks = { 2922311Sseb 0, 2932311Sseb vgen_stat, 2942311Sseb vgen_start, 2952311Sseb vgen_stop, 2962311Sseb vgen_promisc, 2972311Sseb vgen_multicst, 2982311Sseb vgen_unicst, 2992311Sseb vgen_tx, 3002311Sseb NULL, 3012311Sseb NULL, 3022311Sseb NULL 3032311Sseb }; 3042311Sseb 3051991Sheppo /* externs */ 3061991Sheppo extern uint32_t vnet_ntxds; 3071991Sheppo extern uint32_t vnet_ldcwd_interval; 3081991Sheppo extern uint32_t vnet_ldcwd_txtimeout; 3092410Slm66018 extern uint32_t vnet_ldc_mtu; 3102336Snarayan extern uint32_t vnet_nrbufs; 3111991Sheppo extern int _vnet_dbglevel; 3121991Sheppo extern void _vnetdebug_printf(void *vnetp, const char *fmt, ...); 3131991Sheppo 3141991Sheppo #ifdef DEBUG 3151991Sheppo 3161991Sheppo /* 3172793Slm66018 * NOTE: definitions below need to be in sync with those in vnet.c 3181991Sheppo */ 3191991Sheppo 3201991Sheppo /* 3211991Sheppo * debug levels: 3221991Sheppo * DBG_LEVEL1: Function entry/exit tracing 3231991Sheppo * DBG_LEVEL2: Info messages 3241991Sheppo * DBG_LEVEL3: Warning messages 3251991Sheppo * DBG_LEVEL4: Error messages 3261991Sheppo */ 3271991Sheppo 3281991Sheppo enum { DBG_LEVEL1 = 0x01, DBG_LEVEL2 = 0x02, DBG_LEVEL3 = 0x04, 3291991Sheppo DBG_LEVEL4 = 0x08 }; 3301991Sheppo 3311991Sheppo #define DBG1(_s) do { \ 3321991Sheppo if ((_vnet_dbglevel & DBG_LEVEL1) != 0) { \ 3331991Sheppo _vnetdebug_printf _s; \ 3341991Sheppo } \ 3351991Sheppo _NOTE(CONSTCOND) } while (0) 3361991Sheppo 3371991Sheppo #define DBG2(_s) do { \ 3381991Sheppo if ((_vnet_dbglevel & DBG_LEVEL2) != 0) { \ 3391991Sheppo _vnetdebug_printf _s; \ 3401991Sheppo } \ 3411991Sheppo _NOTE(CONSTCOND) } while (0) 3421991Sheppo 3431991Sheppo #define DWARN(_s) do { \ 3441991Sheppo if ((_vnet_dbglevel & DBG_LEVEL3) != 0) { \ 3451991Sheppo _vnetdebug_printf _s; \ 3461991Sheppo } \ 3471991Sheppo _NOTE(CONSTCOND) } while (0) 3481991Sheppo 3491991Sheppo #define DERR(_s) do { \ 3501991Sheppo if ((_vnet_dbglevel & DBG_LEVEL4) != 0) { \ 3511991Sheppo _vnetdebug_printf _s; \ 3521991Sheppo } \ 3531991Sheppo _NOTE(CONSTCOND) } while (0) 3541991Sheppo 3551991Sheppo #else 3561991Sheppo 3571991Sheppo #define DBG1(_s) if (0) _vnetdebug_printf _s 3581991Sheppo #define DBG2(_s) if (0) _vnetdebug_printf _s 3591991Sheppo #define DWARN(_s) if (0) _vnetdebug_printf _s 3601991Sheppo #define DERR(_s) if (0) _vnetdebug_printf _s 3611991Sheppo 3621991Sheppo #endif 3631991Sheppo 3641991Sheppo #ifdef DEBUG 3651991Sheppo 3661991Sheppo /* simulate handshake error conditions for debug */ 3671991Sheppo uint32_t vgen_hdbg; 3681991Sheppo #define HDBG_VERSION 0x1 3691991Sheppo #define HDBG_TIMEOUT 0x2 3701991Sheppo #define HDBG_BAD_SID 0x4 3711991Sheppo #define HDBG_OUT_STATE 0x8 3721991Sheppo 3731991Sheppo #endif 3741991Sheppo 3752336Snarayan 3761991Sheppo 3771991Sheppo /* 3781991Sheppo * vgen_init() is called by an instance of vnet driver to initialize the 3791991Sheppo * corresponding generic proxy transport layer. The arguments passed by vnet 3801991Sheppo * are - an opaque pointer to the vnet instance, pointers to dev_info_t and 3812311Sseb * the mac address of the vnet device, and a pointer to mac_register_t of 3822311Sseb * the generic transport is returned in the last argument. 3831991Sheppo */ 3841991Sheppo int 3852311Sseb vgen_init(void *vnetp, dev_info_t *vnetdip, const uint8_t *macaddr, 3862311Sseb mac_register_t **vgenmacp) 3871991Sheppo { 3881991Sheppo vgen_t *vgenp; 3892311Sseb mac_register_t *macp; 3901991Sheppo int instance; 3911991Sheppo 3922311Sseb if ((vnetp == NULL) || (vnetdip == NULL)) 3931991Sheppo return (DDI_FAILURE); 3941991Sheppo 3951991Sheppo instance = ddi_get_instance(vnetdip); 3961991Sheppo 3971991Sheppo DBG1((vnetp, "vgen_init: enter vnet_instance(%d)\n", instance)); 3981991Sheppo 3991991Sheppo vgenp = kmem_zalloc(sizeof (vgen_t), KM_SLEEP); 4001991Sheppo 4011991Sheppo vgenp->vnetp = vnetp; 4021991Sheppo vgenp->vnetdip = vnetdip; 4031991Sheppo bcopy(macaddr, &(vgenp->macaddr), ETHERADDRL); 4041991Sheppo 4052311Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 4062311Sseb KMEM_FREE(vgenp); 4072311Sseb return (DDI_FAILURE); 4082311Sseb } 4092311Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 4102311Sseb macp->m_driver = vgenp; 4112311Sseb macp->m_dip = vnetdip; 4122311Sseb macp->m_src_addr = (uint8_t *)&(vgenp->macaddr); 4132311Sseb macp->m_callbacks = &vgen_m_callbacks; 4142311Sseb macp->m_min_sdu = 0; 4152311Sseb macp->m_max_sdu = ETHERMTU; 4162311Sseb vgenp->macp = macp; 4172311Sseb 4181991Sheppo /* allocate multicast table */ 4191991Sheppo vgenp->mctab = kmem_zalloc(VGEN_INIT_MCTAB_SIZE * 4201991Sheppo sizeof (struct ether_addr), KM_SLEEP); 4211991Sheppo vgenp->mccount = 0; 4221991Sheppo vgenp->mcsize = VGEN_INIT_MCTAB_SIZE; 4231991Sheppo 4241991Sheppo mutex_init(&vgenp->lock, NULL, MUTEX_DRIVER, NULL); 4251991Sheppo 4261991Sheppo /* register with MD event generator */ 4271991Sheppo if (vgen_mdeg_reg(vgenp) != DDI_SUCCESS) { 4281991Sheppo mutex_destroy(&vgenp->lock); 4291991Sheppo kmem_free(vgenp->mctab, VGEN_INIT_MCTAB_SIZE * 4301991Sheppo sizeof (struct ether_addr)); 4312311Sseb mac_free(vgenp->macp); 4321991Sheppo KMEM_FREE(vgenp); 4331991Sheppo return (DDI_FAILURE); 4341991Sheppo } 4351991Sheppo 4362311Sseb /* register macp of this vgen_t with vnet */ 4372311Sseb *vgenmacp = vgenp->macp; 4381991Sheppo 4391991Sheppo DBG1((vnetp, "vgen_init: exit vnet_instance(%d)\n", instance)); 4401991Sheppo return (DDI_SUCCESS); 4411991Sheppo } 4421991Sheppo 4431991Sheppo /* 4441991Sheppo * Called by vnet to undo the initializations done by vgen_init(). 4451991Sheppo * The handle provided by generic transport during vgen_init() is the argument. 4461991Sheppo */ 4472336Snarayan int 4481991Sheppo vgen_uninit(void *arg) 4491991Sheppo { 4501991Sheppo vgen_t *vgenp = (vgen_t *)arg; 4511991Sheppo void *vnetp; 4521991Sheppo int instance; 4532336Snarayan vio_mblk_pool_t *rp, *nrp; 4542336Snarayan 4552336Snarayan if (vgenp == NULL) { 4562336Snarayan return (DDI_FAILURE); 4572336Snarayan } 4581991Sheppo 4591991Sheppo instance = ddi_get_instance(vgenp->vnetdip); 4601991Sheppo vnetp = vgenp->vnetp; 4611991Sheppo 4621991Sheppo DBG1((vnetp, "vgen_uninit: enter vnet_instance(%d)\n", instance)); 4631991Sheppo 4641991Sheppo /* unregister with MD event generator */ 4651991Sheppo vgen_mdeg_unreg(vgenp); 4661991Sheppo 4671991Sheppo mutex_enter(&vgenp->lock); 4681991Sheppo 4691991Sheppo /* detach all ports from the device */ 4701991Sheppo vgen_detach_ports(vgenp); 4711991Sheppo 4722336Snarayan /* 4732336Snarayan * free any pending rx mblk pools, 4742336Snarayan * that couldn't be freed previously during channel detach. 4752336Snarayan */ 4762336Snarayan rp = vgenp->rmp; 4772336Snarayan while (rp != NULL) { 4782336Snarayan nrp = vgenp->rmp = rp->nextp; 4792336Snarayan if (vio_destroy_mblks(rp)) { 4802336Snarayan vgenp->rmp = rp; 4812336Snarayan mutex_exit(&vgenp->lock); 4822336Snarayan return (DDI_FAILURE); 4832336Snarayan } 4842336Snarayan rp = nrp; 4852336Snarayan } 4862336Snarayan 4871991Sheppo /* free multicast table */ 4881991Sheppo kmem_free(vgenp->mctab, vgenp->mcsize * sizeof (struct ether_addr)); 4891991Sheppo 4902311Sseb mac_free(vgenp->macp); 4912311Sseb 4921991Sheppo mutex_exit(&vgenp->lock); 4931991Sheppo 4941991Sheppo mutex_destroy(&vgenp->lock); 4951991Sheppo 4961991Sheppo KMEM_FREE(vgenp); 4971991Sheppo 4981991Sheppo DBG1((vnetp, "vgen_uninit: exit vnet_instance(%d)\n", instance)); 4992336Snarayan 5002336Snarayan return (DDI_SUCCESS); 5011991Sheppo } 5021991Sheppo 5031991Sheppo /* enable transmit/receive for the device */ 5042311Sseb int 5051991Sheppo vgen_start(void *arg) 5061991Sheppo { 5071991Sheppo vgen_t *vgenp = (vgen_t *)arg; 5081991Sheppo 5091991Sheppo DBG1((vgenp->vnetp, "vgen_start: enter\n")); 5101991Sheppo 5111991Sheppo mutex_enter(&vgenp->lock); 5121991Sheppo vgen_init_ports(vgenp); 5131991Sheppo vgenp->flags |= VGEN_STARTED; 5141991Sheppo mutex_exit(&vgenp->lock); 5151991Sheppo 5161991Sheppo DBG1((vgenp->vnetp, "vgen_start: exit\n")); 5171991Sheppo return (DDI_SUCCESS); 5181991Sheppo } 5191991Sheppo 5201991Sheppo /* stop transmit/receive */ 5212311Sseb void 5221991Sheppo vgen_stop(void *arg) 5231991Sheppo { 5241991Sheppo vgen_t *vgenp = (vgen_t *)arg; 5251991Sheppo 5261991Sheppo DBG1((vgenp->vnetp, "vgen_stop: enter\n")); 5271991Sheppo 5281991Sheppo mutex_enter(&vgenp->lock); 5291991Sheppo vgen_uninit_ports(vgenp); 5301991Sheppo vgenp->flags &= ~(VGEN_STARTED); 5311991Sheppo mutex_exit(&vgenp->lock); 5321991Sheppo 5331991Sheppo DBG1((vgenp->vnetp, "vgen_stop: exit\n")); 5341991Sheppo } 5351991Sheppo 5361991Sheppo /* vgen transmit function */ 5371991Sheppo static mblk_t * 5381991Sheppo vgen_tx(void *arg, mblk_t *mp) 5391991Sheppo { 5401991Sheppo vgen_port_t *portp; 5411991Sheppo int status; 5421991Sheppo 5431991Sheppo portp = (vgen_port_t *)arg; 5441991Sheppo status = vgen_portsend(portp, mp); 5451991Sheppo if (status != VGEN_SUCCESS) { 5461991Sheppo /* failure */ 5471991Sheppo return (mp); 5481991Sheppo } 5491991Sheppo /* success */ 5501991Sheppo return (NULL); 5511991Sheppo } 5521991Sheppo 5531991Sheppo /* transmit packets over the given port */ 5541991Sheppo static int 5551991Sheppo vgen_portsend(vgen_port_t *portp, mblk_t *mp) 5561991Sheppo { 5571991Sheppo vgen_ldclist_t *ldclp; 5581991Sheppo vgen_ldc_t *ldcp; 5591991Sheppo int status; 5601991Sheppo 5611991Sheppo ldclp = &portp->ldclist; 5621991Sheppo READ_ENTER(&ldclp->rwlock); 5631991Sheppo /* 5642336Snarayan * NOTE: for now, we will assume we have a single channel. 5651991Sheppo */ 5661991Sheppo if (ldclp->headp == NULL) { 5671991Sheppo RW_EXIT(&ldclp->rwlock); 5681991Sheppo return (VGEN_FAILURE); 5691991Sheppo } 5701991Sheppo ldcp = ldclp->headp; 5711991Sheppo 5721991Sheppo if (ldcp->need_resched) { 5731991Sheppo /* out of tx resources, see vgen_ldcsend() for details. */ 5741991Sheppo mutex_enter(&ldcp->txlock); 5751991Sheppo ldcp->statsp->tx_no_desc++; 5761991Sheppo mutex_exit(&ldcp->txlock); 5771991Sheppo 5781991Sheppo RW_EXIT(&ldclp->rwlock); 5792336Snarayan return (VGEN_FAILURE); 5801991Sheppo } 5811991Sheppo 5821991Sheppo status = vgen_ldcsend(ldcp, mp); 5831991Sheppo RW_EXIT(&ldclp->rwlock); 5841991Sheppo 5851991Sheppo if (status != VGEN_TX_SUCCESS) 5861991Sheppo return (VGEN_FAILURE); 5871991Sheppo 5881991Sheppo return (VGEN_SUCCESS); 5891991Sheppo } 5901991Sheppo 5911991Sheppo /* channel transmit function */ 5921991Sheppo static int 5931991Sheppo vgen_ldcsend(vgen_ldc_t *ldcp, mblk_t *mp) 5941991Sheppo { 5951991Sheppo void *vnetp; 5961991Sheppo size_t size; 5972793Slm66018 int rv = 0; 5982336Snarayan uint64_t tbuf_ix; 5991991Sheppo vgen_private_desc_t *tbufp; 6001991Sheppo vgen_private_desc_t *ntbufp; 6011991Sheppo vnet_public_desc_t *txdp; 6021991Sheppo vio_dring_entry_hdr_t *hdrp; 6031991Sheppo vgen_stats_t *statsp; 6041991Sheppo struct ether_header *ehp; 6051991Sheppo boolean_t is_bcast = B_FALSE; 6061991Sheppo boolean_t is_mcast = B_FALSE; 6072336Snarayan size_t mblksz; 6082336Snarayan caddr_t dst; 6092336Snarayan mblk_t *bp; 6102793Slm66018 ldc_status_t istatus; 6111991Sheppo 6121991Sheppo vnetp = LDC_TO_VNET(ldcp); 6131991Sheppo statsp = ldcp->statsp; 6142109Slm66018 size = msgsize(mp); 6152109Slm66018 6161991Sheppo DBG1((vnetp, "vgen_ldcsend: enter ldcid(%lx)\n", ldcp->ldc_id)); 6171991Sheppo 6182109Slm66018 mutex_enter(&ldcp->txlock); 6192109Slm66018 6202109Slm66018 /* drop the packet if ldc is not up or handshake is not done */ 6212109Slm66018 if (ldcp->ldc_status != LDC_UP) { 6221991Sheppo DWARN((vnetp, 6231991Sheppo "vgen_ldcsend: id(%lx) status(%d), dropping packet\n", 6241991Sheppo ldcp->ldc_id, ldcp->ldc_status)); 6252109Slm66018 /* retry ldc_up() if needed */ 6262109Slm66018 if (ldcp->flags & CHANNEL_STARTED) 6272109Slm66018 (void) ldc_up(ldcp->ldc_handle); 6282109Slm66018 goto vgen_tx_exit; 6291991Sheppo } 6301991Sheppo 6312109Slm66018 if (ldcp->hphase != VH_DONE) { 6322109Slm66018 DWARN((vnetp, 6332109Slm66018 "vgen_ldcsend: id(%lx) hphase(%x), dropping packet\n", 6342109Slm66018 ldcp->ldc_id, ldcp->hphase)); 6352109Slm66018 goto vgen_tx_exit; 6362109Slm66018 } 6372109Slm66018 6381991Sheppo if (size > (size_t)ETHERMAX) { 6391991Sheppo DWARN((vnetp, "vgen_ldcsend: id(%lx) invalid size(%d)\n", 6401991Sheppo ldcp->ldc_id, size)); 6411991Sheppo goto vgen_tx_exit; 6421991Sheppo } 6431991Sheppo 6441991Sheppo /* 6451991Sheppo * allocate a descriptor 6461991Sheppo */ 6471991Sheppo tbufp = ldcp->next_tbufp; 6481991Sheppo ntbufp = NEXTTBUF(ldcp, tbufp); 6492336Snarayan if (ntbufp == ldcp->cur_tbufp) { /* out of tbufs/txds */ 6501991Sheppo 6511991Sheppo mutex_enter(&ldcp->tclock); 6522336Snarayan if (ntbufp == ldcp->cur_tbufp) { 6531991Sheppo ldcp->need_resched = B_TRUE; 6542336Snarayan mutex_exit(&ldcp->tclock); 6552336Snarayan 6562336Snarayan statsp->tx_no_desc++; 6572336Snarayan mutex_exit(&ldcp->txlock); 6582336Snarayan 6592336Snarayan return (VGEN_TX_NORESOURCES); 6602336Snarayan } 6611991Sheppo mutex_exit(&ldcp->tclock); 6621991Sheppo } 6631991Sheppo 6642109Slm66018 if (size < ETHERMIN) 6652109Slm66018 size = ETHERMIN; 6662109Slm66018 6672109Slm66018 /* copy data into pre-allocated transmit buffer */ 6682336Snarayan dst = tbufp->datap + VNET_IPALIGN; 6692336Snarayan for (bp = mp; bp != NULL; bp = bp->b_cont) { 6702336Snarayan mblksz = MBLKL(bp); 6712336Snarayan bcopy(bp->b_rptr, dst, mblksz); 6722336Snarayan dst += mblksz; 6731991Sheppo } 6741991Sheppo 6752336Snarayan tbuf_ix = tbufp - ldcp->tbufp; 6761991Sheppo 6772109Slm66018 ehp = (struct ether_header *)tbufp->datap; 6781991Sheppo is_bcast = IS_BROADCAST(ehp); 6791991Sheppo is_mcast = IS_MULTICAST(ehp); 6802109Slm66018 6811991Sheppo tbufp->flags = VGEN_PRIV_DESC_BUSY; 6822109Slm66018 tbufp->datalen = size; 6831991Sheppo 6841991Sheppo /* initialize the corresponding public descriptor (txd) */ 6851991Sheppo txdp = tbufp->descp; 6861991Sheppo hdrp = &txdp->hdr; 6872109Slm66018 txdp->nbytes = size; 6882109Slm66018 txdp->ncookies = tbufp->ncookies; 6891991Sheppo bcopy((tbufp->memcookie), (txdp->memcookie), 6902336Snarayan tbufp->ncookies * sizeof (ldc_mem_cookie_t)); 6912336Snarayan hdrp->dstate = VIO_DESC_READY; 6921991Sheppo 6931991Sheppo /* send dring datamsg to the peer */ 6942336Snarayan if (ldcp->resched_peer) { 6952336Snarayan rv = vgen_send_dring_data(ldcp, (uint32_t)tbuf_ix, -1); 6962336Snarayan if (rv != 0) { 6972336Snarayan /* vgen_send_dring_data() error: drop the packet */ 6982336Snarayan DWARN((vnetp, 6992336Snarayan "vgen_ldcsend: vgen_send_dring_data(): failed: " 7002336Snarayan "id(%lx) rv(%d) len (%d)\n", 7012336Snarayan ldcp->ldc_id, rv, size)); 7022336Snarayan tbufp->flags = VGEN_PRIV_DESC_FREE; /* free tbuf */ 7032336Snarayan hdrp->dstate = VIO_DESC_FREE; /* free txd */ 7042336Snarayan hdrp->ack = B_FALSE; 7052336Snarayan statsp->oerrors++; 7062336Snarayan goto vgen_tx_exit; 7072336Snarayan } 7082336Snarayan ldcp->resched_peer = B_FALSE; 7091991Sheppo } 7101991Sheppo 7111991Sheppo /* update next available tbuf in the ring */ 7121991Sheppo ldcp->next_tbufp = ntbufp; 7132336Snarayan 7142336Snarayan /* update tx index */ 7151991Sheppo INCR_TXI(ldcp->next_txi, ldcp); 7161991Sheppo 7171991Sheppo /* update stats */ 7181991Sheppo statsp->opackets++; 7192109Slm66018 statsp->obytes += size; 7201991Sheppo if (is_bcast) 7211991Sheppo statsp->brdcstxmt++; 7221991Sheppo else if (is_mcast) 7231991Sheppo statsp->multixmt++; 7241991Sheppo 7251991Sheppo vgen_tx_exit: 7261991Sheppo mutex_exit(&ldcp->txlock); 7271991Sheppo 7282793Slm66018 if (rv == ECONNRESET) { 7292793Slm66018 /* 7302793Slm66018 * Check if either callback thread or another tx thread is 7312793Slm66018 * already running. Calling mutex_enter() will result in a 7322793Slm66018 * deadlock if the other thread already holds cblock and is 7332793Slm66018 * blocked in vnet_modify_fdb() (which is called from 7342793Slm66018 * vgen_handle_evt_reset()) waiting for write access on rwlock, 7352793Slm66018 * as this transmit thread already holds that lock as a reader 7362793Slm66018 * in vnet_m_tx(). See comments in vnet_modify_fdb() in vnet.c. 7372793Slm66018 */ 7382793Slm66018 if (mutex_tryenter(&ldcp->cblock)) { 7392793Slm66018 if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 7402793Slm66018 DWARN((vnetp, 7412793Slm66018 "vgen_ldcsend: ldc_status err id(%lx)\n")); 7422793Slm66018 } else { 7432793Slm66018 ldcp->ldc_status = istatus; 7442793Slm66018 } 7452793Slm66018 if (ldcp->ldc_status != LDC_UP) { 7462793Slm66018 /* 7472793Slm66018 * Second arg is TRUE, as we know that 7482793Slm66018 * the caller of this function - vnet_m_tx(), 7492793Slm66018 * already holds fdb-rwlock as a reader. 7502793Slm66018 */ 7512793Slm66018 vgen_handle_evt_reset(ldcp, B_TRUE); 7522793Slm66018 } 7532793Slm66018 mutex_exit(&ldcp->cblock); 7542793Slm66018 } 7552793Slm66018 } 7562793Slm66018 7571991Sheppo DBG1((vnetp, "vgen_ldcsend: exit: ldcid (%lx)\n", ldcp->ldc_id)); 7581991Sheppo 7592109Slm66018 freemsg(mp); 7602109Slm66018 return (VGEN_TX_SUCCESS); 7611991Sheppo } 7621991Sheppo 7631991Sheppo /* enable/disable a multicast address */ 7642311Sseb int 7651991Sheppo vgen_multicst(void *arg, boolean_t add, const uint8_t *mca) 7661991Sheppo { 7671991Sheppo vgen_t *vgenp; 7681991Sheppo vnet_mcast_msg_t mcastmsg; 7691991Sheppo vio_msg_tag_t *tagp; 7701991Sheppo vgen_port_t *portp; 7711991Sheppo vgen_portlist_t *plistp; 7721991Sheppo vgen_ldc_t *ldcp; 7731991Sheppo vgen_ldclist_t *ldclp; 7741991Sheppo void *vnetp; 7751991Sheppo struct ether_addr *addrp; 776*3653Snarayan int rv = DDI_FAILURE; 7771991Sheppo uint32_t i; 7781991Sheppo 7791991Sheppo vgenp = (vgen_t *)arg; 7801991Sheppo vnetp = vgenp->vnetp; 7811991Sheppo addrp = (struct ether_addr *)mca; 7821991Sheppo tagp = &mcastmsg.tag; 7831991Sheppo bzero(&mcastmsg, sizeof (mcastmsg)); 7841991Sheppo 7851991Sheppo mutex_enter(&vgenp->lock); 7861991Sheppo 7871991Sheppo plistp = &(vgenp->vgenports); 7881991Sheppo 7891991Sheppo READ_ENTER(&plistp->rwlock); 7901991Sheppo 7911991Sheppo portp = vgenp->vsw_portp; 7921991Sheppo if (portp == NULL) { 7931991Sheppo RW_EXIT(&plistp->rwlock); 794*3653Snarayan mutex_exit(&vgenp->lock); 795*3653Snarayan return (rv); 7961991Sheppo } 7971991Sheppo ldclp = &portp->ldclist; 7981991Sheppo 7991991Sheppo READ_ENTER(&ldclp->rwlock); 8001991Sheppo 8011991Sheppo ldcp = ldclp->headp; 802*3653Snarayan if (ldcp == NULL) 8031991Sheppo goto vgen_mcast_exit; 8041991Sheppo 8051991Sheppo mutex_enter(&ldcp->cblock); 8061991Sheppo 8071991Sheppo if (ldcp->hphase == VH_DONE) { 8081991Sheppo /* 8091991Sheppo * If handshake is done, send a msg to vsw to add/remove 8101991Sheppo * the multicast address. 8111991Sheppo */ 8121991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 8131991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 8141991Sheppo tagp->vio_subtype_env = VNET_MCAST_INFO; 8151991Sheppo tagp->vio_sid = ldcp->local_sid; 8161991Sheppo bcopy(mca, &(mcastmsg.mca), ETHERADDRL); 8171991Sheppo mcastmsg.set = add; 8181991Sheppo mcastmsg.count = 1; 819*3653Snarayan if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (mcastmsg), 820*3653Snarayan B_FALSE) != VGEN_SUCCESS) { 8211991Sheppo DWARN((vnetp, "vgen_mutlicst: vgen_sendmsg failed" 8221991Sheppo "id (%lx)\n", ldcp->ldc_id)); 823*3653Snarayan mutex_exit(&ldcp->cblock); 824*3653Snarayan goto vgen_mcast_exit; 8251991Sheppo } 8261991Sheppo } else { 8271991Sheppo /* set the flag to send a msg to vsw after handshake is done */ 8281991Sheppo ldcp->need_mcast_sync = B_TRUE; 8291991Sheppo } 8301991Sheppo 8311991Sheppo mutex_exit(&ldcp->cblock); 8321991Sheppo 8331991Sheppo if (add) { 8341991Sheppo 8351991Sheppo /* expand multicast table if necessary */ 8361991Sheppo if (vgenp->mccount >= vgenp->mcsize) { 8371991Sheppo struct ether_addr *newtab; 8381991Sheppo uint32_t newsize; 8391991Sheppo 8401991Sheppo 8411991Sheppo newsize = vgenp->mcsize * 2; 8421991Sheppo 8431991Sheppo newtab = kmem_zalloc(newsize * 8441991Sheppo sizeof (struct ether_addr), KM_NOSLEEP); 845*3653Snarayan if (newtab == NULL) 846*3653Snarayan goto vgen_mcast_exit; 8471991Sheppo bcopy(vgenp->mctab, newtab, vgenp->mcsize * 8481991Sheppo sizeof (struct ether_addr)); 8491991Sheppo kmem_free(vgenp->mctab, 8501991Sheppo vgenp->mcsize * sizeof (struct ether_addr)); 8511991Sheppo 8521991Sheppo vgenp->mctab = newtab; 8531991Sheppo vgenp->mcsize = newsize; 8541991Sheppo } 8551991Sheppo 8561991Sheppo /* add address to the table */ 8571991Sheppo vgenp->mctab[vgenp->mccount++] = *addrp; 8581991Sheppo 8591991Sheppo } else { 8601991Sheppo 8611991Sheppo /* delete address from the table */ 8621991Sheppo for (i = 0; i < vgenp->mccount; i++) { 8631991Sheppo if (ether_cmp(addrp, &(vgenp->mctab[i])) == 0) { 8641991Sheppo 8651991Sheppo /* 8661991Sheppo * If there's more than one address in this 8671991Sheppo * table, delete the unwanted one by moving 8681991Sheppo * the last one in the list over top of it; 8691991Sheppo * otherwise, just remove it. 8701991Sheppo */ 8711991Sheppo if (vgenp->mccount > 1) { 8721991Sheppo vgenp->mctab[i] = 8731991Sheppo vgenp->mctab[vgenp->mccount-1]; 8741991Sheppo } 8751991Sheppo vgenp->mccount--; 8761991Sheppo break; 8771991Sheppo } 8781991Sheppo } 8791991Sheppo } 8801991Sheppo 881*3653Snarayan rv = DDI_SUCCESS; 882*3653Snarayan 883*3653Snarayan vgen_mcast_exit: 8841991Sheppo RW_EXIT(&ldclp->rwlock); 8851991Sheppo RW_EXIT(&plistp->rwlock); 8861991Sheppo 8871991Sheppo mutex_exit(&vgenp->lock); 888*3653Snarayan return (rv); 8891991Sheppo } 8901991Sheppo 8911991Sheppo /* set or clear promiscuous mode on the device */ 8921991Sheppo static int 8931991Sheppo vgen_promisc(void *arg, boolean_t on) 8941991Sheppo { 8951991Sheppo _NOTE(ARGUNUSED(arg, on)) 8961991Sheppo return (DDI_SUCCESS); 8971991Sheppo } 8981991Sheppo 8991991Sheppo /* set the unicast mac address of the device */ 9001991Sheppo static int 9011991Sheppo vgen_unicst(void *arg, const uint8_t *mca) 9021991Sheppo { 9031991Sheppo _NOTE(ARGUNUSED(arg, mca)) 9041991Sheppo return (DDI_SUCCESS); 9051991Sheppo } 9061991Sheppo 9071991Sheppo /* get device statistics */ 9082311Sseb int 9092311Sseb vgen_stat(void *arg, uint_t stat, uint64_t *val) 9101991Sheppo { 9111991Sheppo vgen_t *vgenp = (vgen_t *)arg; 9121991Sheppo vgen_port_t *portp; 9131991Sheppo vgen_portlist_t *plistp; 9142311Sseb 9152311Sseb *val = 0; 9161991Sheppo 9171991Sheppo plistp = &(vgenp->vgenports); 9181991Sheppo READ_ENTER(&plistp->rwlock); 9191991Sheppo 9201991Sheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) { 9212311Sseb *val += vgen_port_stat(portp, stat); 9221991Sheppo } 9231991Sheppo 9241991Sheppo RW_EXIT(&plistp->rwlock); 9251991Sheppo 9262311Sseb return (0); 9271991Sheppo } 9281991Sheppo 9291991Sheppo static void 9301991Sheppo vgen_ioctl(void *arg, queue_t *wq, mblk_t *mp) 9311991Sheppo { 9321991Sheppo _NOTE(ARGUNUSED(arg, wq, mp)) 9331991Sheppo } 9341991Sheppo 9351991Sheppo /* vgen internal functions */ 9361991Sheppo /* detach all ports from the device */ 9371991Sheppo static void 9381991Sheppo vgen_detach_ports(vgen_t *vgenp) 9391991Sheppo { 9401991Sheppo vgen_port_t *portp; 9411991Sheppo vgen_portlist_t *plistp; 9421991Sheppo 9431991Sheppo plistp = &(vgenp->vgenports); 9441991Sheppo WRITE_ENTER(&plistp->rwlock); 9451991Sheppo 9461991Sheppo while ((portp = plistp->headp) != NULL) { 9471991Sheppo vgen_port_detach(portp); 9481991Sheppo } 9491991Sheppo 9501991Sheppo RW_EXIT(&plistp->rwlock); 9511991Sheppo } 9521991Sheppo 9531991Sheppo /* 9541991Sheppo * detach the given port. 9551991Sheppo */ 9561991Sheppo static void 9571991Sheppo vgen_port_detach(vgen_port_t *portp) 9581991Sheppo { 9591991Sheppo vgen_t *vgenp; 9601991Sheppo vgen_ldclist_t *ldclp; 9611991Sheppo int port_num; 9621991Sheppo 9631991Sheppo vgenp = portp->vgenp; 9641991Sheppo port_num = portp->port_num; 9651991Sheppo 9661991Sheppo DBG1((vgenp->vnetp, 9671991Sheppo "vgen_port_detach: enter: port_num(%d)\n", port_num)); 9681991Sheppo 9691991Sheppo /* remove it from port list */ 9701991Sheppo vgen_port_list_remove(portp); 9711991Sheppo 9721991Sheppo /* detach channels from this port */ 9731991Sheppo ldclp = &portp->ldclist; 9741991Sheppo WRITE_ENTER(&ldclp->rwlock); 9751991Sheppo while (ldclp->headp) { 9761991Sheppo vgen_ldc_detach(ldclp->headp); 9771991Sheppo } 9781991Sheppo RW_EXIT(&ldclp->rwlock); 9791991Sheppo 9801991Sheppo if (vgenp->vsw_portp == portp) { 9811991Sheppo vgenp->vsw_portp = NULL; 9821991Sheppo } 9831991Sheppo KMEM_FREE(portp); 9841991Sheppo 9851991Sheppo DBG1((vgenp->vnetp, 9861991Sheppo "vgen_port_detach: exit: port_num(%d)\n", port_num)); 9871991Sheppo } 9881991Sheppo 9891991Sheppo /* add a port to port list */ 9901991Sheppo static void 9911991Sheppo vgen_port_list_insert(vgen_port_t *portp) 9921991Sheppo { 9931991Sheppo vgen_portlist_t *plistp; 9941991Sheppo vgen_t *vgenp; 9951991Sheppo 9961991Sheppo vgenp = portp->vgenp; 9971991Sheppo plistp = &(vgenp->vgenports); 9981991Sheppo 9991991Sheppo if (plistp->headp == NULL) { 10001991Sheppo plistp->headp = portp; 10011991Sheppo } else { 10021991Sheppo plistp->tailp->nextp = portp; 10031991Sheppo } 10041991Sheppo plistp->tailp = portp; 10051991Sheppo portp->nextp = NULL; 10061991Sheppo } 10071991Sheppo 10081991Sheppo /* remove a port from port list */ 10091991Sheppo static void 10101991Sheppo vgen_port_list_remove(vgen_port_t *portp) 10111991Sheppo { 10121991Sheppo vgen_port_t *prevp; 10131991Sheppo vgen_port_t *nextp; 10141991Sheppo vgen_portlist_t *plistp; 10151991Sheppo vgen_t *vgenp; 10161991Sheppo 10171991Sheppo vgenp = portp->vgenp; 10181991Sheppo 10191991Sheppo plistp = &(vgenp->vgenports); 10201991Sheppo 10211991Sheppo if (plistp->headp == NULL) 10221991Sheppo return; 10231991Sheppo 10241991Sheppo if (portp == plistp->headp) { 10251991Sheppo plistp->headp = portp->nextp; 10261991Sheppo if (portp == plistp->tailp) 10271991Sheppo plistp->tailp = plistp->headp; 10281991Sheppo } else { 10291991Sheppo for (prevp = plistp->headp; ((nextp = prevp->nextp) != NULL) && 10301991Sheppo (nextp != portp); prevp = nextp); 10311991Sheppo if (nextp == portp) { 10321991Sheppo prevp->nextp = portp->nextp; 10331991Sheppo } 10341991Sheppo if (portp == plistp->tailp) 10351991Sheppo plistp->tailp = prevp; 10361991Sheppo } 10371991Sheppo } 10381991Sheppo 10391991Sheppo /* lookup a port in the list based on port_num */ 10401991Sheppo static vgen_port_t * 10411991Sheppo vgen_port_lookup(vgen_portlist_t *plistp, int port_num) 10421991Sheppo { 10431991Sheppo vgen_port_t *portp = NULL; 10441991Sheppo 10451991Sheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) { 10461991Sheppo if (portp->port_num == port_num) { 10471991Sheppo break; 10481991Sheppo } 10491991Sheppo } 10501991Sheppo 10511991Sheppo return (portp); 10521991Sheppo } 10531991Sheppo 10541991Sheppo /* enable ports for transmit/receive */ 10551991Sheppo static void 10561991Sheppo vgen_init_ports(vgen_t *vgenp) 10571991Sheppo { 10581991Sheppo vgen_port_t *portp; 10591991Sheppo vgen_portlist_t *plistp; 10601991Sheppo 10611991Sheppo plistp = &(vgenp->vgenports); 10621991Sheppo READ_ENTER(&plistp->rwlock); 10631991Sheppo 10641991Sheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) { 10651991Sheppo vgen_port_init(portp); 10661991Sheppo } 10671991Sheppo 10681991Sheppo RW_EXIT(&plistp->rwlock); 10691991Sheppo } 10701991Sheppo 10711991Sheppo static void 10721991Sheppo vgen_port_init(vgen_port_t *portp) 10731991Sheppo { 10741991Sheppo vgen_t *vgenp; 10751991Sheppo 10761991Sheppo vgenp = portp->vgenp; 10771991Sheppo /* 10781991Sheppo * Create fdb entry in vnet, corresponding to the mac 10791991Sheppo * address of this port. Note that the port specified 10801991Sheppo * is vsw-port. This is done so that vsw-port acts 10811991Sheppo * as the route to reach this macaddr, until the 10821991Sheppo * channel for this port comes up (LDC_UP) and 10831991Sheppo * handshake is done successfully. 10841991Sheppo * eg, if the peer is OBP-vnet, it may not bring the 10851991Sheppo * channel up for this port and may communicate via 10861991Sheppo * vsw to reach this port. 10871991Sheppo * Later, when Solaris-vnet comes up at the other end 10881991Sheppo * of the channel for this port and brings up the channel, 10891991Sheppo * it is an indication that peer vnet is capable of 10901991Sheppo * distributed switching, so the direct route through this 10911991Sheppo * port is specified in fdb, using vnet_modify_fdb(macaddr); 10921991Sheppo */ 10931991Sheppo vnet_add_fdb(vgenp->vnetp, (uint8_t *)&portp->macaddr, 10941991Sheppo vgen_tx, vgenp->vsw_portp); 10951991Sheppo 10961991Sheppo if (portp == vgenp->vsw_portp) { 10971991Sheppo /* 10981991Sheppo * create the default route entry in vnet's fdb. 10991991Sheppo * This is the entry used by vnet to reach 11001991Sheppo * unknown destinations, which basically goes 11011991Sheppo * through vsw on domain0 and out through the 11021991Sheppo * physical device bound to vsw. 11031991Sheppo */ 11041991Sheppo vnet_add_def_rte(vgenp->vnetp, vgen_tx, portp); 11051991Sheppo } 11061991Sheppo 11071991Sheppo /* Bring up the channels of this port */ 11081991Sheppo vgen_init_ldcs(portp); 11091991Sheppo } 11101991Sheppo 11111991Sheppo /* disable transmit/receive on ports */ 11121991Sheppo static void 11131991Sheppo vgen_uninit_ports(vgen_t *vgenp) 11141991Sheppo { 11151991Sheppo vgen_port_t *portp; 11161991Sheppo vgen_portlist_t *plistp; 11171991Sheppo 11181991Sheppo plistp = &(vgenp->vgenports); 11191991Sheppo READ_ENTER(&plistp->rwlock); 11201991Sheppo 11211991Sheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) { 11221991Sheppo vgen_port_uninit(portp); 11231991Sheppo } 11241991Sheppo 11251991Sheppo RW_EXIT(&plistp->rwlock); 11261991Sheppo } 11271991Sheppo 11281991Sheppo static void 11291991Sheppo vgen_port_uninit(vgen_port_t *portp) 11301991Sheppo { 11311991Sheppo vgen_t *vgenp; 11321991Sheppo 11331991Sheppo vgenp = portp->vgenp; 11341991Sheppo 11351991Sheppo vgen_uninit_ldcs(portp); 11361991Sheppo /* delete the entry in vnet's fdb for this port */ 11371991Sheppo vnet_del_fdb(vgenp->vnetp, (uint8_t *)&portp->macaddr); 11381991Sheppo if (portp == vgenp->vsw_portp) { 11391991Sheppo /* 11401991Sheppo * if this is vsw-port, then delete the default 11411991Sheppo * route entry in vnet's fdb. 11421991Sheppo */ 11431991Sheppo vnet_del_def_rte(vgenp->vnetp); 11441991Sheppo } 11451991Sheppo } 11461991Sheppo 11471991Sheppo /* register with MD event generator */ 11481991Sheppo static int 11491991Sheppo vgen_mdeg_reg(vgen_t *vgenp) 11501991Sheppo { 11511991Sheppo mdeg_prop_spec_t *pspecp; 11521991Sheppo mdeg_node_spec_t *parentp; 11531991Sheppo uint_t templatesz; 11541991Sheppo int rv; 11551991Sheppo mdeg_handle_t hdl; 11561991Sheppo int i; 11571991Sheppo void *vnetp = vgenp->vnetp; 11581991Sheppo 11591991Sheppo i = ddi_prop_get_int(DDI_DEV_T_ANY, vgenp->vnetdip, 11601991Sheppo DDI_PROP_DONTPASS, reg_propname, -1); 11611991Sheppo if (i == -1) { 11621991Sheppo return (DDI_FAILURE); 11631991Sheppo } 11641991Sheppo templatesz = sizeof (vgen_prop_template); 11651991Sheppo pspecp = kmem_zalloc(templatesz, KM_NOSLEEP); 11661991Sheppo if (pspecp == NULL) { 11671991Sheppo return (DDI_FAILURE); 11681991Sheppo } 11691991Sheppo parentp = kmem_zalloc(sizeof (mdeg_node_spec_t), KM_NOSLEEP); 11701991Sheppo if (parentp == NULL) { 11711991Sheppo kmem_free(pspecp, templatesz); 11721991Sheppo return (DDI_FAILURE); 11731991Sheppo } 11741991Sheppo 11751991Sheppo bcopy(vgen_prop_template, pspecp, templatesz); 11761991Sheppo 11771991Sheppo /* 11781991Sheppo * NOTE: The instance here refers to the value of "reg" property and 11791991Sheppo * not the dev_info instance (ddi_get_instance()) of vnet. 11801991Sheppo */ 11811991Sheppo VGEN_SET_MDEG_PROP_INST(pspecp, i); 11821991Sheppo 11831991Sheppo parentp->namep = "virtual-device"; 11841991Sheppo parentp->specp = pspecp; 11851991Sheppo 11861991Sheppo /* save parentp in vgen_t */ 11871991Sheppo vgenp->mdeg_parentp = parentp; 11881991Sheppo 11891991Sheppo rv = mdeg_register(parentp, &vport_match, vgen_mdeg_cb, vgenp, &hdl); 11901991Sheppo if (rv != MDEG_SUCCESS) { 11911991Sheppo DERR((vnetp, "vgen_mdeg_reg: mdeg_register failed\n")); 11921991Sheppo KMEM_FREE(parentp); 11931991Sheppo kmem_free(pspecp, templatesz); 11941991Sheppo vgenp->mdeg_parentp = NULL; 11951991Sheppo return (DDI_FAILURE); 11961991Sheppo } 11971991Sheppo 11981991Sheppo /* save mdeg handle in vgen_t */ 11991991Sheppo vgenp->mdeg_hdl = hdl; 12001991Sheppo 12011991Sheppo return (DDI_SUCCESS); 12021991Sheppo } 12031991Sheppo 12041991Sheppo /* unregister with MD event generator */ 12051991Sheppo static void 12061991Sheppo vgen_mdeg_unreg(vgen_t *vgenp) 12071991Sheppo { 12081991Sheppo (void) mdeg_unregister(vgenp->mdeg_hdl); 12093297Ssb155480 kmem_free(vgenp->mdeg_parentp->specp, sizeof (vgen_prop_template)); 12101991Sheppo KMEM_FREE(vgenp->mdeg_parentp); 12111991Sheppo vgenp->mdeg_parentp = NULL; 12121991Sheppo vgenp->mdeg_hdl = NULL; 12131991Sheppo } 12141991Sheppo 12151991Sheppo /* callback function registered with MD event generator */ 12161991Sheppo static int 12171991Sheppo vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp) 12181991Sheppo { 12191991Sheppo int idx; 12201991Sheppo int vsw_idx = -1; 12211991Sheppo uint64_t val; 12221991Sheppo vgen_t *vgenp; 12231991Sheppo 12241991Sheppo if ((resp == NULL) || (cb_argp == NULL)) { 12251991Sheppo return (MDEG_FAILURE); 12261991Sheppo } 12271991Sheppo 12281991Sheppo vgenp = (vgen_t *)cb_argp; 12291991Sheppo DBG1((vgenp->vnetp, "vgen_mdeg_cb: enter\n")); 12301991Sheppo 12311991Sheppo mutex_enter(&vgenp->lock); 12321991Sheppo 12331991Sheppo DBG1((vgenp->vnetp, 12341991Sheppo "vgen_mdeg_cb: ports: removed(%x), added(%x), updated(%x)\n", 12351991Sheppo resp->removed.nelem, resp->added.nelem, resp->match_curr.nelem)); 12361991Sheppo 12371991Sheppo for (idx = 0; idx < resp->removed.nelem; idx++) { 12381991Sheppo (void) vgen_remove_port(vgenp, resp->removed.mdp, 12391991Sheppo resp->removed.mdep[idx]); 12401991Sheppo } 12411991Sheppo 12421991Sheppo if (vgenp->vsw_portp == NULL) { 12431991Sheppo /* 12441991Sheppo * find vsw_port and add it first, because other ports need 12451991Sheppo * this when adding fdb entry (see vgen_port_init()). 12461991Sheppo */ 12471991Sheppo for (idx = 0; idx < resp->added.nelem; idx++) { 12481991Sheppo if (!(md_get_prop_val(resp->added.mdp, 12491991Sheppo resp->added.mdep[idx], swport_propname, &val))) { 12501991Sheppo if (val == 0) { 12511991Sheppo /* 12521991Sheppo * This port is connected to the 12531991Sheppo * vsw on dom0. 12541991Sheppo */ 12551991Sheppo vsw_idx = idx; 12561991Sheppo (void) vgen_add_port(vgenp, 12571991Sheppo resp->added.mdp, 12581991Sheppo resp->added.mdep[idx]); 12591991Sheppo break; 12601991Sheppo } 12611991Sheppo } 12621991Sheppo } 12631991Sheppo if (vsw_idx == -1) { 12641991Sheppo DWARN((vgenp->vnetp, "vgen_mdeg_cb: " 12651991Sheppo "can't find vsw_port\n")); 12661991Sheppo return (MDEG_FAILURE); 12671991Sheppo } 12681991Sheppo } 12691991Sheppo 12701991Sheppo for (idx = 0; idx < resp->added.nelem; idx++) { 12711991Sheppo if ((vsw_idx != -1) && (vsw_idx == idx)) /* skip vsw_port */ 12721991Sheppo continue; 12731991Sheppo (void) vgen_add_port(vgenp, resp->added.mdp, 12741991Sheppo resp->added.mdep[idx]); 12751991Sheppo } 12761991Sheppo 12771991Sheppo for (idx = 0; idx < resp->match_curr.nelem; idx++) { 12781991Sheppo (void) vgen_update_port(vgenp, resp->match_curr.mdp, 12791991Sheppo resp->match_curr.mdep[idx], 12801991Sheppo resp->match_prev.mdp, 12811991Sheppo resp->match_prev.mdep[idx]); 12821991Sheppo } 12831991Sheppo 12841991Sheppo mutex_exit(&vgenp->lock); 12851991Sheppo DBG1((vgenp->vnetp, "vgen_mdeg_cb: exit\n")); 12861991Sheppo return (MDEG_SUCCESS); 12871991Sheppo } 12881991Sheppo 12891991Sheppo /* add a new port to the device */ 12901991Sheppo static int 12911991Sheppo vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex) 12921991Sheppo { 12931991Sheppo uint64_t port_num; 12941991Sheppo uint64_t *ldc_ids; 12951991Sheppo uint64_t macaddr; 12961991Sheppo uint64_t val; 12971991Sheppo int num_ldcs; 12981991Sheppo int vsw_port = B_FALSE; 12991991Sheppo int i; 13001991Sheppo int addrsz; 13011991Sheppo int num_nodes = 0; 13021991Sheppo int listsz = 0; 13031991Sheppo mde_cookie_t *listp = NULL; 13041991Sheppo uint8_t *addrp; 13051991Sheppo struct ether_addr ea; 13061991Sheppo 13071991Sheppo /* read "id" property to get the port number */ 13081991Sheppo if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) { 13091991Sheppo DWARN((vgenp->vnetp, 13101991Sheppo "vgen_add_port: prop(%s) not found\n", id_propname)); 13111991Sheppo return (DDI_FAILURE); 13121991Sheppo } 13131991Sheppo 13141991Sheppo /* 13151991Sheppo * Find the channel endpoint node(s) under this port node. 13161991Sheppo */ 13171991Sheppo if ((num_nodes = md_node_count(mdp)) <= 0) { 13181991Sheppo DWARN((vgenp->vnetp, 13191991Sheppo "vgen_add_port: invalid number of nodes found (%d)", 13201991Sheppo num_nodes)); 13211991Sheppo return (DDI_FAILURE); 13221991Sheppo } 13231991Sheppo 13241991Sheppo /* allocate space for node list */ 13251991Sheppo listsz = num_nodes * sizeof (mde_cookie_t); 13261991Sheppo listp = kmem_zalloc(listsz, KM_NOSLEEP); 13271991Sheppo if (listp == NULL) 13281991Sheppo return (DDI_FAILURE); 13291991Sheppo 13301991Sheppo num_ldcs = md_scan_dag(mdp, mdex, 13311991Sheppo md_find_name(mdp, channel_propname), 13321991Sheppo md_find_name(mdp, "fwd"), listp); 13331991Sheppo 13341991Sheppo if (num_ldcs <= 0) { 13351991Sheppo DWARN((vgenp->vnetp, 13361991Sheppo "vgen_add_port: can't find %s nodes", channel_propname)); 13371991Sheppo kmem_free(listp, listsz); 13381991Sheppo return (DDI_FAILURE); 13391991Sheppo } 13401991Sheppo 13411991Sheppo DBG2((vgenp->vnetp, "vgen_add_port: num_ldcs %d", num_ldcs)); 13421991Sheppo 13431991Sheppo ldc_ids = kmem_zalloc(num_ldcs * sizeof (uint64_t), KM_NOSLEEP); 13441991Sheppo if (ldc_ids == NULL) { 13451991Sheppo kmem_free(listp, listsz); 13461991Sheppo return (DDI_FAILURE); 13471991Sheppo } 13481991Sheppo 13491991Sheppo for (i = 0; i < num_ldcs; i++) { 13501991Sheppo /* read channel ids */ 13511991Sheppo if (md_get_prop_val(mdp, listp[i], id_propname, &ldc_ids[i])) { 13521991Sheppo DWARN((vgenp->vnetp, 13531991Sheppo "vgen_add_port: prop(%s) not found\n", 13541991Sheppo id_propname)); 13551991Sheppo kmem_free(listp, listsz); 13561991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 13571991Sheppo return (DDI_FAILURE); 13581991Sheppo } 13591991Sheppo DBG2((vgenp->vnetp, "vgen_add_port: ldc_id 0x%llx", 13601991Sheppo ldc_ids[i])); 13611991Sheppo } 13621991Sheppo 13631991Sheppo kmem_free(listp, listsz); 13641991Sheppo 13651991Sheppo if (md_get_prop_data(mdp, mdex, rmacaddr_propname, &addrp, 13661991Sheppo &addrsz)) { 13671991Sheppo DWARN((vgenp->vnetp, 13681991Sheppo "vgen_add_port: prop(%s) not found\n", rmacaddr_propname)); 13691991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 13701991Sheppo return (DDI_FAILURE); 13711991Sheppo } 13721991Sheppo 13731991Sheppo if (addrsz < ETHERADDRL) { 13741991Sheppo DWARN((vgenp->vnetp, 13751991Sheppo "vgen_add_port: invalid address size (%d)\n", addrsz)); 13761991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 13771991Sheppo return (DDI_FAILURE); 13781991Sheppo } 13791991Sheppo 13801991Sheppo macaddr = *((uint64_t *)addrp); 13811991Sheppo 13821991Sheppo DBG2((vgenp->vnetp, "vgen_add_port: remote mac address 0x%llx\n", 13831991Sheppo macaddr)); 13841991Sheppo 13851991Sheppo for (i = ETHERADDRL - 1; i >= 0; i--) { 13861991Sheppo ea.ether_addr_octet[i] = macaddr & 0xFF; 13871991Sheppo macaddr >>= 8; 13881991Sheppo } 13891991Sheppo 13901991Sheppo if (vgenp->vsw_portp == NULL) { 13911991Sheppo if (!(md_get_prop_val(mdp, mdex, swport_propname, &val))) { 13921991Sheppo if (val == 0) { 13931991Sheppo /* This port is connected to the vsw on dom0 */ 13941991Sheppo vsw_port = B_TRUE; 13951991Sheppo } 13961991Sheppo } 13971991Sheppo } 13981991Sheppo (void) vgen_port_attach_mdeg(vgenp, (int)port_num, ldc_ids, num_ldcs, 13991991Sheppo &ea, vsw_port); 14001991Sheppo 14011991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 14021991Sheppo 14031991Sheppo return (DDI_SUCCESS); 14041991Sheppo } 14051991Sheppo 14061991Sheppo /* remove a port from the device */ 14071991Sheppo static int 14081991Sheppo vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex) 14091991Sheppo { 14101991Sheppo uint64_t port_num; 14111991Sheppo vgen_port_t *portp; 14121991Sheppo vgen_portlist_t *plistp; 14131991Sheppo 14141991Sheppo /* read "id" property to get the port number */ 14151991Sheppo if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) { 14161991Sheppo DWARN((vgenp->vnetp, 14171991Sheppo "vgen_remove_port: prop(%s) not found\n", id_propname)); 14181991Sheppo return (DDI_FAILURE); 14191991Sheppo } 14201991Sheppo 14211991Sheppo plistp = &(vgenp->vgenports); 14221991Sheppo 14231991Sheppo WRITE_ENTER(&plistp->rwlock); 14241991Sheppo portp = vgen_port_lookup(plistp, (int)port_num); 14251991Sheppo if (portp == NULL) { 14261991Sheppo DWARN((vgenp->vnetp, "vgen_remove_port: can't find port(%lx)\n", 14271991Sheppo port_num)); 14281991Sheppo RW_EXIT(&plistp->rwlock); 14291991Sheppo return (DDI_FAILURE); 14301991Sheppo } 14311991Sheppo 14321991Sheppo vgen_port_detach_mdeg(portp); 14331991Sheppo RW_EXIT(&plistp->rwlock); 14341991Sheppo 14351991Sheppo return (DDI_SUCCESS); 14361991Sheppo } 14371991Sheppo 14381991Sheppo /* attach a port to the device based on mdeg data */ 14391991Sheppo static int 14401991Sheppo vgen_port_attach_mdeg(vgen_t *vgenp, int port_num, uint64_t *ldcids, 14411991Sheppo int num_ids, struct ether_addr *macaddr, boolean_t vsw_port) 14421991Sheppo { 14431991Sheppo vgen_port_t *portp; 14441991Sheppo vgen_portlist_t *plistp; 14451991Sheppo int i; 14461991Sheppo 14471991Sheppo portp = kmem_zalloc(sizeof (vgen_port_t), KM_NOSLEEP); 14481991Sheppo if (portp == NULL) { 14491991Sheppo return (DDI_FAILURE); 14501991Sheppo } 14511991Sheppo portp->vgenp = vgenp; 14521991Sheppo portp->port_num = port_num; 14531991Sheppo 14541991Sheppo DBG1((vgenp->vnetp, 14551991Sheppo "vgen_port_attach_mdeg: port_num(%d)\n", portp->port_num)); 14561991Sheppo 14571991Sheppo portp->ldclist.num_ldcs = 0; 14581991Sheppo portp->ldclist.headp = NULL; 14591991Sheppo rw_init(&portp->ldclist.rwlock, NULL, RW_DRIVER, NULL); 14601991Sheppo 14611991Sheppo ether_copy(macaddr, &portp->macaddr); 14621991Sheppo for (i = 0; i < num_ids; i++) { 14631991Sheppo DBG2((vgenp->vnetp, "vgen_port_attach_mdeg: ldcid (%lx)\n", 14641991Sheppo ldcids[i])); 14651991Sheppo (void) vgen_ldc_attach(portp, ldcids[i]); 14661991Sheppo } 14671991Sheppo 14681991Sheppo /* link it into the list of ports */ 14691991Sheppo plistp = &(vgenp->vgenports); 14701991Sheppo WRITE_ENTER(&plistp->rwlock); 14711991Sheppo vgen_port_list_insert(portp); 14721991Sheppo RW_EXIT(&plistp->rwlock); 14731991Sheppo 14741991Sheppo /* This port is connected to the vsw on domain0 */ 14751991Sheppo if (vsw_port) 14761991Sheppo vgenp->vsw_portp = portp; 14771991Sheppo 14781991Sheppo if (vgenp->flags & VGEN_STARTED) { /* interface is configured */ 14791991Sheppo vgen_port_init(portp); 14801991Sheppo } 14811991Sheppo 14821991Sheppo DBG1((vgenp->vnetp, 14831991Sheppo "vgen_port_attach_mdeg: exit: port_num(%d)\n", portp->port_num)); 14841991Sheppo return (DDI_SUCCESS); 14851991Sheppo } 14861991Sheppo 14871991Sheppo /* detach a port from the device based on mdeg data */ 14881991Sheppo static void 14891991Sheppo vgen_port_detach_mdeg(vgen_port_t *portp) 14901991Sheppo { 14911991Sheppo vgen_t *vgenp = portp->vgenp; 14921991Sheppo 14931991Sheppo DBG1((vgenp->vnetp, 14941991Sheppo "vgen_port_detach_mdeg: enter: port_num(%d)\n", portp->port_num)); 14951991Sheppo /* stop the port if needed */ 14961991Sheppo if (vgenp->flags & VGEN_STARTED) { 14971991Sheppo vgen_port_uninit(portp); 14981991Sheppo } 14991991Sheppo vgen_port_detach(portp); 15001991Sheppo 15011991Sheppo DBG1((vgenp->vnetp, 15021991Sheppo "vgen_port_detach_mdeg: exit: port_num(%d)\n", portp->port_num)); 15031991Sheppo } 15041991Sheppo 15051991Sheppo static int 15061991Sheppo vgen_update_port(vgen_t *vgenp, md_t *curr_mdp, mde_cookie_t curr_mdex, 15071991Sheppo md_t *prev_mdp, mde_cookie_t prev_mdex) 15081991Sheppo { 15091991Sheppo _NOTE(ARGUNUSED(vgenp, curr_mdp, curr_mdex, prev_mdp, prev_mdex)) 15101991Sheppo 15112793Slm66018 /* NOTE: TBD */ 15121991Sheppo return (DDI_SUCCESS); 15131991Sheppo } 15141991Sheppo 15151991Sheppo static uint64_t 15162311Sseb vgen_port_stat(vgen_port_t *portp, uint_t stat) 15171991Sheppo { 15181991Sheppo vgen_ldclist_t *ldclp; 15191991Sheppo vgen_ldc_t *ldcp; 15201991Sheppo uint64_t val; 15211991Sheppo 15221991Sheppo val = 0; 15231991Sheppo ldclp = &portp->ldclist; 15241991Sheppo 15251991Sheppo READ_ENTER(&ldclp->rwlock); 15261991Sheppo for (ldcp = ldclp->headp; ldcp != NULL; ldcp = ldcp->nextp) { 15271991Sheppo val += vgen_ldc_stat(ldcp, stat); 15281991Sheppo } 15291991Sheppo RW_EXIT(&ldclp->rwlock); 15301991Sheppo 15311991Sheppo return (val); 15321991Sheppo } 15331991Sheppo 15341991Sheppo /* attach the channel corresponding to the given ldc_id to the port */ 15351991Sheppo static int 15361991Sheppo vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id) 15371991Sheppo { 15381991Sheppo vgen_t *vgenp; 15391991Sheppo vgen_ldclist_t *ldclp; 15401991Sheppo vgen_ldc_t *ldcp, **prev_ldcp; 15411991Sheppo ldc_attr_t attr; 15421991Sheppo int status; 15431991Sheppo ldc_status_t istatus; 15441991Sheppo enum {AST_init = 0x0, AST_ldc_alloc = 0x1, 15451991Sheppo AST_mutex_init = 0x2, AST_ldc_init = 0x4, 15462336Snarayan AST_ldc_reg_cb = 0x8, AST_alloc_tx_ring = 0x10, 15472336Snarayan AST_create_rxmblks = 0x20} 15481991Sheppo attach_state; 15491991Sheppo 15501991Sheppo attach_state = AST_init; 15511991Sheppo vgenp = portp->vgenp; 15521991Sheppo ldclp = &portp->ldclist; 15531991Sheppo 15541991Sheppo ldcp = kmem_zalloc(sizeof (vgen_ldc_t), KM_NOSLEEP); 15551991Sheppo if (ldcp == NULL) { 15561991Sheppo goto ldc_attach_failed; 15571991Sheppo } 15581991Sheppo ldcp->ldc_id = ldc_id; 15591991Sheppo ldcp->portp = portp; 15601991Sheppo 15611991Sheppo attach_state |= AST_ldc_alloc; 15621991Sheppo 15631991Sheppo mutex_init(&ldcp->txlock, NULL, MUTEX_DRIVER, NULL); 15641991Sheppo mutex_init(&ldcp->cblock, NULL, MUTEX_DRIVER, NULL); 15651991Sheppo mutex_init(&ldcp->tclock, NULL, MUTEX_DRIVER, NULL); 15661991Sheppo 15671991Sheppo attach_state |= AST_mutex_init; 15681991Sheppo 15691991Sheppo attr.devclass = LDC_DEV_NT; 15701991Sheppo attr.instance = ddi_get_instance(vgenp->vnetdip); 15711991Sheppo attr.mode = LDC_MODE_UNRELIABLE; 15722410Slm66018 attr.mtu = vnet_ldc_mtu; 15731991Sheppo status = ldc_init(ldc_id, &attr, &ldcp->ldc_handle); 15741991Sheppo if (status != 0) { 15751991Sheppo DWARN((vgenp->vnetp, "ldc_init failed, id (%lx) rv (%d)\n", 15761991Sheppo ldc_id, status)); 15771991Sheppo goto ldc_attach_failed; 15781991Sheppo } 15791991Sheppo attach_state |= AST_ldc_init; 15801991Sheppo 15811991Sheppo status = ldc_reg_callback(ldcp->ldc_handle, vgen_ldc_cb, (caddr_t)ldcp); 15821991Sheppo if (status != 0) { 15831991Sheppo DWARN((vgenp->vnetp, 15841991Sheppo "ldc_reg_callback failed, id (%lx) rv (%d)\n", 15851991Sheppo ldc_id, status)); 15861991Sheppo goto ldc_attach_failed; 15871991Sheppo } 15881991Sheppo attach_state |= AST_ldc_reg_cb; 15891991Sheppo 15901991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 15911991Sheppo ASSERT(istatus == LDC_INIT); 15921991Sheppo ldcp->ldc_status = istatus; 15931991Sheppo 15941991Sheppo /* allocate transmit resources */ 15951991Sheppo status = vgen_alloc_tx_ring(ldcp); 15961991Sheppo if (status != 0) { 15971991Sheppo goto ldc_attach_failed; 15981991Sheppo } 15991991Sheppo attach_state |= AST_alloc_tx_ring; 16001991Sheppo 16012336Snarayan /* allocate receive resources */ 16022336Snarayan ldcp->num_rbufs = vnet_nrbufs; 16032336Snarayan ldcp->rmp = NULL; 16042336Snarayan status = vio_create_mblks(ldcp->num_rbufs, VGEN_DBLK_SZ, 16052336Snarayan &(ldcp->rmp)); 16062336Snarayan if (status != 0) { 16072336Snarayan goto ldc_attach_failed; 16082336Snarayan } 16092336Snarayan attach_state |= AST_create_rxmblks; 16102336Snarayan 16111991Sheppo /* Setup kstats for the channel */ 16121991Sheppo status = vgen_setup_kstats(ldcp); 16131991Sheppo if (status != VGEN_SUCCESS) { 16141991Sheppo goto ldc_attach_failed; 16151991Sheppo } 16161991Sheppo 16171991Sheppo /* initialize vgen_versions supported */ 16181991Sheppo bcopy(vgen_versions, ldcp->vgen_versions, sizeof (ldcp->vgen_versions)); 16191991Sheppo 16201991Sheppo /* link it into the list of channels for this port */ 16211991Sheppo WRITE_ENTER(&ldclp->rwlock); 16221991Sheppo prev_ldcp = (vgen_ldc_t **)(&ldclp->headp); 16231991Sheppo ldcp->nextp = *prev_ldcp; 16241991Sheppo *prev_ldcp = ldcp; 16251991Sheppo ldclp->num_ldcs++; 16261991Sheppo RW_EXIT(&ldclp->rwlock); 16271991Sheppo 16281991Sheppo ldcp->flags |= CHANNEL_ATTACHED; 16291991Sheppo return (DDI_SUCCESS); 16301991Sheppo 16311991Sheppo ldc_attach_failed: 16322336Snarayan if (attach_state & AST_create_rxmblks) { 16332336Snarayan (void) vio_destroy_mblks(ldcp->rmp); 16342336Snarayan } 16351991Sheppo if (attach_state & AST_alloc_tx_ring) { 16361991Sheppo vgen_free_tx_ring(ldcp); 16371991Sheppo } 16381991Sheppo if (attach_state & AST_ldc_reg_cb) { 16391991Sheppo (void) ldc_unreg_callback(ldcp->ldc_handle); 16401991Sheppo } 16411991Sheppo if (attach_state & AST_ldc_init) { 16421991Sheppo (void) ldc_fini(ldcp->ldc_handle); 16431991Sheppo } 16441991Sheppo if (attach_state & AST_mutex_init) { 16451991Sheppo mutex_destroy(&ldcp->tclock); 16461991Sheppo mutex_destroy(&ldcp->txlock); 16471991Sheppo mutex_destroy(&ldcp->cblock); 16481991Sheppo } 16491991Sheppo if (attach_state & AST_ldc_alloc) { 16501991Sheppo KMEM_FREE(ldcp); 16511991Sheppo } 16521991Sheppo return (DDI_FAILURE); 16531991Sheppo } 16541991Sheppo 16551991Sheppo /* detach a channel from the port */ 16561991Sheppo static void 16571991Sheppo vgen_ldc_detach(vgen_ldc_t *ldcp) 16581991Sheppo { 16591991Sheppo vgen_port_t *portp; 16601991Sheppo vgen_t *vgenp; 16611991Sheppo vgen_ldc_t *pldcp; 16621991Sheppo vgen_ldc_t **prev_ldcp; 16631991Sheppo vgen_ldclist_t *ldclp; 16641991Sheppo 16651991Sheppo portp = ldcp->portp; 16661991Sheppo vgenp = portp->vgenp; 16671991Sheppo ldclp = &portp->ldclist; 16681991Sheppo 16691991Sheppo prev_ldcp = (vgen_ldc_t **)&ldclp->headp; 16701991Sheppo for (; (pldcp = *prev_ldcp) != NULL; prev_ldcp = &pldcp->nextp) { 16711991Sheppo if (pldcp == ldcp) { 16721991Sheppo break; 16731991Sheppo } 16741991Sheppo } 16751991Sheppo 16761991Sheppo if (pldcp == NULL) { 16771991Sheppo /* invalid ldcp? */ 16781991Sheppo return; 16791991Sheppo } 16801991Sheppo 16811991Sheppo if (ldcp->ldc_status != LDC_INIT) { 16821991Sheppo DWARN((vgenp->vnetp, 16831991Sheppo "vgen_ldc_detach: ldc_status is not INIT id(%lx)\n", 16841991Sheppo ldcp->ldc_id)); 16851991Sheppo } 16861991Sheppo 16871991Sheppo if (ldcp->flags & CHANNEL_ATTACHED) { 16881991Sheppo ldcp->flags &= ~(CHANNEL_ATTACHED); 16891991Sheppo 16901991Sheppo vgen_destroy_kstats(ldcp); 16912336Snarayan 16922336Snarayan /* free receive resources */ 16932336Snarayan if (vio_destroy_mblks(ldcp->rmp)) { 16942336Snarayan /* 16952336Snarayan * if we cannot reclaim all mblks, put this 16962336Snarayan * on the list of pools to be reclaimed when the 16972336Snarayan * device gets detached (see vgen_uninit()). 16982336Snarayan */ 16992336Snarayan ldcp->rmp->nextp = vgenp->rmp; 17002336Snarayan vgenp->rmp = ldcp->rmp; 17012336Snarayan } 17022336Snarayan 17031991Sheppo /* free transmit resources */ 17041991Sheppo vgen_free_tx_ring(ldcp); 17052336Snarayan 17061991Sheppo (void) ldc_unreg_callback(ldcp->ldc_handle); 17071991Sheppo (void) ldc_fini(ldcp->ldc_handle); 17081991Sheppo mutex_destroy(&ldcp->tclock); 17091991Sheppo mutex_destroy(&ldcp->txlock); 17101991Sheppo mutex_destroy(&ldcp->cblock); 17111991Sheppo 17121991Sheppo /* unlink it from the list */ 17131991Sheppo *prev_ldcp = ldcp->nextp; 17141991Sheppo ldclp->num_ldcs--; 17151991Sheppo KMEM_FREE(ldcp); 17161991Sheppo } 17171991Sheppo } 17181991Sheppo 17191991Sheppo /* 17201991Sheppo * This function allocates transmit resources for the channel. 17211991Sheppo * The resources consist of a transmit descriptor ring and an associated 17221991Sheppo * transmit buffer ring. 17231991Sheppo */ 17241991Sheppo static int 17251991Sheppo vgen_alloc_tx_ring(vgen_ldc_t *ldcp) 17261991Sheppo { 17271991Sheppo void *tbufp; 17281991Sheppo ldc_mem_info_t minfo; 17291991Sheppo uint32_t txdsize; 17301991Sheppo uint32_t tbufsize; 17311991Sheppo int status; 17321991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 17331991Sheppo 17341991Sheppo ldcp->num_txds = vnet_ntxds; 17351991Sheppo txdsize = sizeof (vnet_public_desc_t); 17361991Sheppo tbufsize = sizeof (vgen_private_desc_t); 17371991Sheppo 17381991Sheppo /* allocate transmit buffer ring */ 17391991Sheppo tbufp = kmem_zalloc(ldcp->num_txds * tbufsize, KM_NOSLEEP); 17401991Sheppo if (tbufp == NULL) { 17411991Sheppo return (DDI_FAILURE); 17421991Sheppo } 17431991Sheppo 17441991Sheppo /* create transmit descriptor ring */ 17451991Sheppo status = ldc_mem_dring_create(ldcp->num_txds, txdsize, 17461991Sheppo &ldcp->tx_dhandle); 17471991Sheppo if (status) { 17481991Sheppo DWARN((vnetp, "vgen_alloc_tx_ring: ldc_mem_dring_create() " 17491991Sheppo "failed, id(%lx)\n", ldcp->ldc_id)); 17501991Sheppo kmem_free(tbufp, ldcp->num_txds * tbufsize); 17511991Sheppo return (DDI_FAILURE); 17521991Sheppo } 17531991Sheppo 17541991Sheppo /* get the addr of descripror ring */ 17551991Sheppo status = ldc_mem_dring_info(ldcp->tx_dhandle, &minfo); 17561991Sheppo if (status) { 17571991Sheppo DWARN((vnetp, "vgen_alloc_tx_ring: ldc_mem_dring_info() " 17581991Sheppo "failed, id(%lx)\n", ldcp->ldc_id)); 17591991Sheppo kmem_free(tbufp, ldcp->num_txds * tbufsize); 17601991Sheppo (void) ldc_mem_dring_destroy(ldcp->tx_dhandle); 17611991Sheppo ldcp->tbufp = NULL; 17621991Sheppo return (DDI_FAILURE); 17631991Sheppo } 17641991Sheppo ldcp->txdp = (vnet_public_desc_t *)(minfo.vaddr); 17651991Sheppo ldcp->tbufp = tbufp; 17661991Sheppo 17671991Sheppo ldcp->txdendp = &((ldcp->txdp)[ldcp->num_txds]); 17681991Sheppo ldcp->tbufendp = &((ldcp->tbufp)[ldcp->num_txds]); 17691991Sheppo 17701991Sheppo return (DDI_SUCCESS); 17711991Sheppo } 17721991Sheppo 17731991Sheppo /* Free transmit resources for the channel */ 17741991Sheppo static void 17751991Sheppo vgen_free_tx_ring(vgen_ldc_t *ldcp) 17761991Sheppo { 17771991Sheppo int tbufsize = sizeof (vgen_private_desc_t); 17781991Sheppo 17791991Sheppo /* free transmit descriptor ring */ 17801991Sheppo (void) ldc_mem_dring_destroy(ldcp->tx_dhandle); 17811991Sheppo 17821991Sheppo /* free transmit buffer ring */ 17831991Sheppo kmem_free(ldcp->tbufp, ldcp->num_txds * tbufsize); 17841991Sheppo ldcp->txdp = ldcp->txdendp = NULL; 17851991Sheppo ldcp->tbufp = ldcp->tbufendp = NULL; 17861991Sheppo } 17871991Sheppo 17881991Sheppo /* enable transmit/receive on the channels for the port */ 17891991Sheppo static void 17901991Sheppo vgen_init_ldcs(vgen_port_t *portp) 17911991Sheppo { 17921991Sheppo vgen_ldclist_t *ldclp = &portp->ldclist; 17931991Sheppo vgen_ldc_t *ldcp; 17941991Sheppo 17951991Sheppo READ_ENTER(&ldclp->rwlock); 17961991Sheppo ldcp = ldclp->headp; 17971991Sheppo for (; ldcp != NULL; ldcp = ldcp->nextp) { 17981991Sheppo (void) vgen_ldc_init(ldcp); 17991991Sheppo } 18001991Sheppo RW_EXIT(&ldclp->rwlock); 18011991Sheppo } 18021991Sheppo 18031991Sheppo /* stop transmit/receive on the channels for the port */ 18041991Sheppo static void 18051991Sheppo vgen_uninit_ldcs(vgen_port_t *portp) 18061991Sheppo { 18071991Sheppo vgen_ldclist_t *ldclp = &portp->ldclist; 18081991Sheppo vgen_ldc_t *ldcp; 18091991Sheppo 18101991Sheppo READ_ENTER(&ldclp->rwlock); 18111991Sheppo ldcp = ldclp->headp; 18121991Sheppo for (; ldcp != NULL; ldcp = ldcp->nextp) { 18131991Sheppo vgen_ldc_uninit(ldcp); 18141991Sheppo } 18151991Sheppo RW_EXIT(&ldclp->rwlock); 18161991Sheppo } 18171991Sheppo 18181991Sheppo /* enable transmit/receive on the channel */ 18191991Sheppo static int 18201991Sheppo vgen_ldc_init(vgen_ldc_t *ldcp) 18211991Sheppo { 18221991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 18231991Sheppo ldc_status_t istatus; 18241991Sheppo int rv; 18252793Slm66018 enum { ST_init = 0x0, ST_ldc_open = 0x1, 18262793Slm66018 ST_init_tbufs = 0x2, ST_cb_enable = 0x4 18271991Sheppo } 18281991Sheppo init_state; 18292109Slm66018 uint32_t retries = 0; 18301991Sheppo 18311991Sheppo init_state = ST_init; 18321991Sheppo 18331991Sheppo LDC_LOCK(ldcp); 18341991Sheppo 18351991Sheppo rv = ldc_open(ldcp->ldc_handle); 18361991Sheppo if (rv != 0) { 18371991Sheppo DWARN((vnetp, 18381991Sheppo "vgen_ldcinit: ldc_open failed: id<%lx> rv(%d)\n", 18391991Sheppo ldcp->ldc_id, rv)); 18401991Sheppo goto ldcinit_failed; 18411991Sheppo } 18421991Sheppo init_state |= ST_ldc_open; 18431991Sheppo 18441991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 18451991Sheppo if (istatus != LDC_OPEN && istatus != LDC_READY) { 18461991Sheppo DWARN((vnetp, 18471991Sheppo "vgen_ldcinit: id (%lx) status(%d) is not OPEN/READY\n", 18481991Sheppo ldcp->ldc_id, istatus)); 18491991Sheppo goto ldcinit_failed; 18501991Sheppo } 18511991Sheppo ldcp->ldc_status = istatus; 18521991Sheppo 18531991Sheppo rv = vgen_init_tbufs(ldcp); 18541991Sheppo if (rv != 0) { 18551991Sheppo DWARN((vnetp, 18561991Sheppo "vgen_ldcinit: vgen_init_tbufs() failed: id(%lx)\n", 18571991Sheppo ldcp->ldc_id)); 18581991Sheppo goto ldcinit_failed; 18591991Sheppo } 18601991Sheppo init_state |= ST_init_tbufs; 18611991Sheppo 18622748Slm66018 rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_ENABLE); 18632748Slm66018 if (rv != 0) { 18642793Slm66018 DWARN((vnetp, "vgen_ldc_init: ldc_set_cb_mode failed: id(%lx) " 18652793Slm66018 "rv(%d)\n", ldcp->ldc_id, rv)); 18662748Slm66018 goto ldcinit_failed; 18672748Slm66018 } 18682748Slm66018 18692748Slm66018 init_state |= ST_cb_enable; 18702748Slm66018 18712109Slm66018 do { 18722109Slm66018 rv = ldc_up(ldcp->ldc_handle); 18732109Slm66018 if ((rv != 0) && (rv == EWOULDBLOCK)) { 18742109Slm66018 DBG2((vnetp, 18752109Slm66018 "vgen_ldcinit: ldc_up err id(%lx) rv(%d)\n", 18762109Slm66018 ldcp->ldc_id, rv)); 18772109Slm66018 drv_usecwait(VGEN_LDC_UP_DELAY); 18782109Slm66018 } 18792109Slm66018 if (retries++ >= vgen_ldcup_retries) 18802109Slm66018 break; 18812109Slm66018 } while (rv == EWOULDBLOCK); 18821991Sheppo 18831991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 18842793Slm66018 if (istatus == LDC_UP) { 18852793Slm66018 DWARN((vnetp, "vgen_ldc_init: id(%lx) status(%d) is UP\n", 18861991Sheppo ldcp->ldc_id, istatus)); 18871991Sheppo } 18882793Slm66018 18891991Sheppo ldcp->ldc_status = istatus; 18901991Sheppo 18911991Sheppo /* initialize transmit watchdog timeout */ 18921991Sheppo ldcp->wd_tid = timeout(vgen_ldc_watchdog, (caddr_t)ldcp, 18931991Sheppo drv_usectohz(vnet_ldcwd_interval * 1000)); 18941991Sheppo 18952793Slm66018 ldcp->hphase = -1; 18961991Sheppo ldcp->flags |= CHANNEL_STARTED; 18971991Sheppo 18982793Slm66018 /* if channel is already UP - start handshake */ 18992793Slm66018 if (istatus == LDC_UP) { 19002793Slm66018 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 19012793Slm66018 if (ldcp->portp != vgenp->vsw_portp) { 19022793Slm66018 /* 19032793Slm66018 * modify fdb entry to use this port as the 19042793Slm66018 * channel is up, instead of going through the 19052793Slm66018 * vsw-port (see comments in vgen_port_init()) 19062793Slm66018 */ 19072793Slm66018 vnet_modify_fdb(vnetp, 19082793Slm66018 (uint8_t *)&ldcp->portp->macaddr, 19092793Slm66018 vgen_tx, ldcp->portp, B_FALSE); 19102793Slm66018 } 19112793Slm66018 19122793Slm66018 /* Initialize local session id */ 19132793Slm66018 ldcp->local_sid = ddi_get_lbolt(); 19142793Slm66018 19152793Slm66018 /* clear peer session id */ 19162793Slm66018 ldcp->peer_sid = 0; 19172793Slm66018 ldcp->hretries = 0; 19182793Slm66018 19192793Slm66018 /* Initiate Handshake process with peer ldc endpoint */ 19202793Slm66018 vgen_reset_hphase(ldcp); 19212793Slm66018 19222793Slm66018 mutex_exit(&ldcp->tclock); 19232793Slm66018 mutex_exit(&ldcp->txlock); 19242793Slm66018 vgen_handshake(vh_nextphase(ldcp)); 19252793Slm66018 mutex_exit(&ldcp->cblock); 19262793Slm66018 } else { 19272793Slm66018 LDC_UNLOCK(ldcp); 19282793Slm66018 } 19292793Slm66018 19301991Sheppo return (DDI_SUCCESS); 19311991Sheppo 19321991Sheppo ldcinit_failed: 19332748Slm66018 if (init_state & ST_cb_enable) { 19342748Slm66018 (void) ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE); 19352748Slm66018 } 19361991Sheppo if (init_state & ST_init_tbufs) { 19371991Sheppo vgen_uninit_tbufs(ldcp); 19381991Sheppo } 19391991Sheppo if (init_state & ST_ldc_open) { 19401991Sheppo (void) ldc_close(ldcp->ldc_handle); 19411991Sheppo } 19421991Sheppo LDC_UNLOCK(ldcp); 19431991Sheppo return (DDI_FAILURE); 19441991Sheppo } 19451991Sheppo 19461991Sheppo /* stop transmit/receive on the channel */ 19471991Sheppo static void 19481991Sheppo vgen_ldc_uninit(vgen_ldc_t *ldcp) 19491991Sheppo { 19501991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 19511991Sheppo int rv; 19521991Sheppo 19531991Sheppo DBG1((vnetp, "vgen_ldc_uninit: enter: id(%lx)\n", ldcp->ldc_id)); 19541991Sheppo LDC_LOCK(ldcp); 19551991Sheppo 19561991Sheppo if ((ldcp->flags & CHANNEL_STARTED) == 0) { 19571991Sheppo LDC_UNLOCK(ldcp); 19581991Sheppo DWARN((vnetp, "vgen_ldc_uninit: id(%lx) CHANNEL_STARTED" 19591991Sheppo " flag is not set\n", ldcp->ldc_id)); 19601991Sheppo return; 19611991Sheppo } 19621991Sheppo 19631991Sheppo /* disable further callbacks */ 19641991Sheppo rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE); 19651991Sheppo if (rv != 0) { 19661991Sheppo DWARN((vnetp, "vgen_ldc_uninit: id (%lx) " 19671991Sheppo "ldc_set_cb_mode failed\n", ldcp->ldc_id)); 19681991Sheppo } 19691991Sheppo 1970*3653Snarayan /* 1971*3653Snarayan * clear handshake done bit and wait for pending tx and cb to finish. 1972*3653Snarayan * release locks before untimeout(9F) is invoked to cancel timeouts. 1973*3653Snarayan */ 19741991Sheppo ldcp->hphase &= ~(VH_DONE); 19751991Sheppo LDC_UNLOCK(ldcp); 1976*3653Snarayan 1977*3653Snarayan /* cancel handshake watchdog timeout */ 1978*3653Snarayan if (ldcp->htid) { 1979*3653Snarayan (void) untimeout(ldcp->htid); 1980*3653Snarayan ldcp->htid = 0; 1981*3653Snarayan } 1982*3653Snarayan 1983*3653Snarayan /* cancel transmit watchdog timeout */ 19841991Sheppo if (ldcp->wd_tid) { 19851991Sheppo (void) untimeout(ldcp->wd_tid); 19861991Sheppo ldcp->wd_tid = 0; 19871991Sheppo } 19881991Sheppo 1989*3653Snarayan drv_usecwait(1000); 1990*3653Snarayan 1991*3653Snarayan /* acquire locks again; any pending transmits and callbacks are done */ 1992*3653Snarayan LDC_LOCK(ldcp); 1993*3653Snarayan 1994*3653Snarayan vgen_reset_hphase(ldcp); 1995*3653Snarayan 19961991Sheppo vgen_uninit_tbufs(ldcp); 19971991Sheppo 19981991Sheppo rv = ldc_close(ldcp->ldc_handle); 19991991Sheppo if (rv != 0) { 20001991Sheppo DWARN((vnetp, "vgen_ldcuninit: ldc_close err id(%lx)\n", 20011991Sheppo ldcp->ldc_id)); 20021991Sheppo } 20031991Sheppo ldcp->ldc_status = LDC_INIT; 20041991Sheppo ldcp->flags &= ~(CHANNEL_STARTED); 20051991Sheppo 20061991Sheppo LDC_UNLOCK(ldcp); 20071991Sheppo 20081991Sheppo DBG1((vnetp, "vgen_ldc_uninit: exit: id(%lx)\n", ldcp->ldc_id)); 20091991Sheppo } 20101991Sheppo 20111991Sheppo /* Initialize the transmit buffer ring for the channel */ 20121991Sheppo static int 20131991Sheppo vgen_init_tbufs(vgen_ldc_t *ldcp) 20141991Sheppo { 20151991Sheppo vgen_private_desc_t *tbufp; 20161991Sheppo vnet_public_desc_t *txdp; 20171991Sheppo vio_dring_entry_hdr_t *hdrp; 20181991Sheppo int i; 20191991Sheppo int rv; 20202109Slm66018 caddr_t datap = NULL; 20212109Slm66018 int ci; 20222109Slm66018 uint32_t ncookies; 20231991Sheppo 20241991Sheppo bzero(ldcp->tbufp, sizeof (*tbufp) * (ldcp->num_txds)); 20251991Sheppo bzero(ldcp->txdp, sizeof (*txdp) * (ldcp->num_txds)); 20261991Sheppo 20272336Snarayan datap = kmem_zalloc(ldcp->num_txds * VGEN_DBLK_SZ, KM_SLEEP); 20282109Slm66018 ldcp->tx_datap = datap; 20292109Slm66018 20301991Sheppo /* 20312109Slm66018 * for each private descriptor, allocate a ldc mem_handle which is 20321991Sheppo * required to map the data during transmit, set the flags 20331991Sheppo * to free (available for use by transmit routine). 20341991Sheppo */ 20351991Sheppo 20361991Sheppo for (i = 0; i < ldcp->num_txds; i++) { 20372109Slm66018 20381991Sheppo tbufp = &(ldcp->tbufp[i]); 20391991Sheppo rv = ldc_mem_alloc_handle(ldcp->ldc_handle, 20401991Sheppo &(tbufp->memhandle)); 20411991Sheppo if (rv) { 20421991Sheppo tbufp->memhandle = 0; 20431991Sheppo goto init_tbufs_failed; 20441991Sheppo } 20452109Slm66018 20462109Slm66018 /* 20472109Slm66018 * bind ldc memhandle to the corresponding transmit buffer. 20482109Slm66018 */ 20492109Slm66018 ci = ncookies = 0; 20502109Slm66018 rv = ldc_mem_bind_handle(tbufp->memhandle, 20512336Snarayan (caddr_t)datap, VGEN_DBLK_SZ, LDC_SHADOW_MAP, 20522109Slm66018 LDC_MEM_R, &(tbufp->memcookie[ci]), &ncookies); 20532109Slm66018 if (rv != 0) { 20542109Slm66018 goto init_tbufs_failed; 20552109Slm66018 } 20562109Slm66018 20572109Slm66018 /* 20582109Slm66018 * successful in binding the handle to tx data buffer. 20592109Slm66018 * set datap in the private descr to this buffer. 20602109Slm66018 */ 20612109Slm66018 tbufp->datap = datap; 20622109Slm66018 20632109Slm66018 if ((ncookies == 0) || 20642336Snarayan (ncookies > MAX_COOKIES)) { 20652109Slm66018 goto init_tbufs_failed; 20662109Slm66018 } 20672109Slm66018 20682109Slm66018 for (ci = 1; ci < ncookies; ci++) { 20692109Slm66018 rv = ldc_mem_nextcookie(tbufp->memhandle, 20702336Snarayan &(tbufp->memcookie[ci])); 20712109Slm66018 if (rv != 0) { 20722109Slm66018 goto init_tbufs_failed; 20732109Slm66018 } 20742109Slm66018 } 20752109Slm66018 20762109Slm66018 tbufp->ncookies = ncookies; 20772336Snarayan datap += VGEN_DBLK_SZ; 20782109Slm66018 20791991Sheppo tbufp->flags = VGEN_PRIV_DESC_FREE; 20801991Sheppo txdp = &(ldcp->txdp[i]); 20811991Sheppo hdrp = &txdp->hdr; 20821991Sheppo hdrp->dstate = VIO_DESC_FREE; 20831991Sheppo hdrp->ack = B_FALSE; 20841991Sheppo tbufp->descp = txdp; 20852109Slm66018 20861991Sheppo } 20871991Sheppo 20881991Sheppo /* reset tbuf walking pointers */ 20891991Sheppo ldcp->next_tbufp = ldcp->tbufp; 20901991Sheppo ldcp->cur_tbufp = ldcp->tbufp; 20911991Sheppo 20921991Sheppo /* initialize tx seqnum and index */ 20931991Sheppo ldcp->next_txseq = VNET_ISS; 20941991Sheppo ldcp->next_txi = 0; 20951991Sheppo 20962336Snarayan ldcp->resched_peer = B_TRUE; 20972336Snarayan 20981991Sheppo return (DDI_SUCCESS); 20991991Sheppo 21001991Sheppo init_tbufs_failed:; 21011991Sheppo vgen_uninit_tbufs(ldcp); 21021991Sheppo return (DDI_FAILURE); 21031991Sheppo } 21041991Sheppo 21051991Sheppo /* Uninitialize transmit buffer ring for the channel */ 21061991Sheppo static void 21071991Sheppo vgen_uninit_tbufs(vgen_ldc_t *ldcp) 21081991Sheppo { 21091991Sheppo vgen_private_desc_t *tbufp = ldcp->tbufp; 21101991Sheppo int i; 21111991Sheppo 21121991Sheppo /* for each tbuf (priv_desc), free ldc mem_handle */ 21131991Sheppo for (i = 0; i < ldcp->num_txds; i++) { 21141991Sheppo 21151991Sheppo tbufp = &(ldcp->tbufp[i]); 21161991Sheppo 21172109Slm66018 if (tbufp->datap) { /* if bound to a ldc memhandle */ 21181991Sheppo (void) ldc_mem_unbind_handle(tbufp->memhandle); 21192109Slm66018 tbufp->datap = NULL; 21201991Sheppo } 21211991Sheppo if (tbufp->memhandle) { 21221991Sheppo (void) ldc_mem_free_handle(tbufp->memhandle); 21231991Sheppo tbufp->memhandle = 0; 21241991Sheppo } 21251991Sheppo } 21261991Sheppo 21272109Slm66018 if (ldcp->tx_datap) { 21282109Slm66018 /* prealloc'd tx data buffer */ 21292336Snarayan kmem_free(ldcp->tx_datap, ldcp->num_txds * VGEN_DBLK_SZ); 21302109Slm66018 ldcp->tx_datap = NULL; 21312109Slm66018 } 21322109Slm66018 21332748Slm66018 bzero(ldcp->tbufp, sizeof (vgen_private_desc_t) * (ldcp->num_txds)); 21342748Slm66018 bzero(ldcp->txdp, sizeof (vnet_public_desc_t) * (ldcp->num_txds)); 21351991Sheppo } 21361991Sheppo 21371991Sheppo /* clobber tx descriptor ring */ 21381991Sheppo static void 21391991Sheppo vgen_clobber_tbufs(vgen_ldc_t *ldcp) 21401991Sheppo { 21411991Sheppo vnet_public_desc_t *txdp; 21421991Sheppo vgen_private_desc_t *tbufp; 21431991Sheppo vio_dring_entry_hdr_t *hdrp; 21441991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 21451991Sheppo int i; 21461991Sheppo #ifdef DEBUG 21471991Sheppo int ndone = 0; 21481991Sheppo #endif 21491991Sheppo 21501991Sheppo for (i = 0; i < ldcp->num_txds; i++) { 21511991Sheppo 21521991Sheppo tbufp = &(ldcp->tbufp[i]); 21531991Sheppo txdp = tbufp->descp; 21541991Sheppo hdrp = &txdp->hdr; 21551991Sheppo 21561991Sheppo if (tbufp->flags & VGEN_PRIV_DESC_BUSY) { 21571991Sheppo tbufp->flags = VGEN_PRIV_DESC_FREE; 21581991Sheppo #ifdef DEBUG 21591991Sheppo if (hdrp->dstate == VIO_DESC_DONE) 21601991Sheppo ndone++; 21611991Sheppo #endif 21621991Sheppo hdrp->dstate = VIO_DESC_FREE; 21631991Sheppo hdrp->ack = B_FALSE; 21641991Sheppo } 21651991Sheppo } 21661991Sheppo /* reset tbuf walking pointers */ 21671991Sheppo ldcp->next_tbufp = ldcp->tbufp; 21681991Sheppo ldcp->cur_tbufp = ldcp->tbufp; 21691991Sheppo 21701991Sheppo /* reset tx seqnum and index */ 21711991Sheppo ldcp->next_txseq = VNET_ISS; 21721991Sheppo ldcp->next_txi = 0; 21732336Snarayan 21742336Snarayan ldcp->resched_peer = B_TRUE; 21752336Snarayan 21761991Sheppo #ifdef DEBUG 21771991Sheppo DBG2((vnetp, 21781991Sheppo "vgen_clobber_tbufs: id(0x%lx) num descrs done (%d)\n", 21791991Sheppo ldcp->ldc_id, ndone)); 21801991Sheppo #endif 21811991Sheppo } 21821991Sheppo 21831991Sheppo /* clobber receive descriptor ring */ 21841991Sheppo static void 21851991Sheppo vgen_clobber_rxds(vgen_ldc_t *ldcp) 21861991Sheppo { 21871991Sheppo ldcp->rx_dhandle = 0; 21881991Sheppo bzero(&ldcp->rx_dcookie, sizeof (ldcp->rx_dcookie)); 21891991Sheppo ldcp->rxdp = NULL; 21901991Sheppo ldcp->next_rxi = 0; 21911991Sheppo ldcp->num_rxds = 0; 21921991Sheppo ldcp->next_rxseq = VNET_ISS; 21931991Sheppo } 21941991Sheppo 21951991Sheppo /* initialize receive descriptor ring */ 21961991Sheppo static int 21971991Sheppo vgen_init_rxds(vgen_ldc_t *ldcp, uint32_t num_desc, uint32_t desc_size, 21981991Sheppo ldc_mem_cookie_t *dcookie, uint32_t ncookies) 21991991Sheppo { 22001991Sheppo int rv; 22011991Sheppo ldc_mem_info_t minfo; 22021991Sheppo 22031991Sheppo rv = ldc_mem_dring_map(ldcp->ldc_handle, dcookie, ncookies, num_desc, 22041991Sheppo desc_size, LDC_SHADOW_MAP, &(ldcp->rx_dhandle)); 22051991Sheppo if (rv != 0) { 22061991Sheppo return (DDI_FAILURE); 22071991Sheppo } 22081991Sheppo 22091991Sheppo /* 22101991Sheppo * sucessfully mapped, now try to 22111991Sheppo * get info about the mapped dring 22121991Sheppo */ 22131991Sheppo rv = ldc_mem_dring_info(ldcp->rx_dhandle, &minfo); 22141991Sheppo if (rv != 0) { 22151991Sheppo (void) ldc_mem_dring_unmap(ldcp->rx_dhandle); 22161991Sheppo return (DDI_FAILURE); 22171991Sheppo } 22181991Sheppo 22191991Sheppo /* 22201991Sheppo * save ring address, number of descriptors. 22211991Sheppo */ 22221991Sheppo ldcp->rxdp = (vnet_public_desc_t *)(minfo.vaddr); 22231991Sheppo bcopy(dcookie, &(ldcp->rx_dcookie), sizeof (*dcookie)); 22241991Sheppo ldcp->num_rxdcookies = ncookies; 22251991Sheppo ldcp->num_rxds = num_desc; 22261991Sheppo ldcp->next_rxi = 0; 22271991Sheppo ldcp->next_rxseq = VNET_ISS; 22281991Sheppo 22291991Sheppo return (DDI_SUCCESS); 22301991Sheppo } 22311991Sheppo 22321991Sheppo /* get channel statistics */ 22331991Sheppo static uint64_t 22342311Sseb vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat) 22351991Sheppo { 22361991Sheppo vgen_stats_t *statsp; 22371991Sheppo uint64_t val; 22381991Sheppo 22391991Sheppo val = 0; 22401991Sheppo statsp = ldcp->statsp; 22411991Sheppo switch (stat) { 22421991Sheppo 22431991Sheppo case MAC_STAT_MULTIRCV: 22441991Sheppo val = statsp->multircv; 22451991Sheppo break; 22461991Sheppo 22471991Sheppo case MAC_STAT_BRDCSTRCV: 22481991Sheppo val = statsp->brdcstrcv; 22491991Sheppo break; 22501991Sheppo 22511991Sheppo case MAC_STAT_MULTIXMT: 22521991Sheppo val = statsp->multixmt; 22531991Sheppo break; 22541991Sheppo 22551991Sheppo case MAC_STAT_BRDCSTXMT: 22561991Sheppo val = statsp->brdcstxmt; 22571991Sheppo break; 22581991Sheppo 22591991Sheppo case MAC_STAT_NORCVBUF: 22601991Sheppo val = statsp->norcvbuf; 22611991Sheppo break; 22621991Sheppo 22631991Sheppo case MAC_STAT_IERRORS: 22641991Sheppo val = statsp->ierrors; 22651991Sheppo break; 22661991Sheppo 22671991Sheppo case MAC_STAT_NOXMTBUF: 22681991Sheppo val = statsp->noxmtbuf; 22691991Sheppo break; 22701991Sheppo 22711991Sheppo case MAC_STAT_OERRORS: 22721991Sheppo val = statsp->oerrors; 22731991Sheppo break; 22741991Sheppo 22751991Sheppo case MAC_STAT_COLLISIONS: 22761991Sheppo break; 22771991Sheppo 22781991Sheppo case MAC_STAT_RBYTES: 22791991Sheppo val = statsp->rbytes; 22801991Sheppo break; 22811991Sheppo 22821991Sheppo case MAC_STAT_IPACKETS: 22831991Sheppo val = statsp->ipackets; 22841991Sheppo break; 22851991Sheppo 22861991Sheppo case MAC_STAT_OBYTES: 22871991Sheppo val = statsp->obytes; 22881991Sheppo break; 22891991Sheppo 22901991Sheppo case MAC_STAT_OPACKETS: 22911991Sheppo val = statsp->opackets; 22921991Sheppo break; 22931991Sheppo 22941991Sheppo /* stats not relevant to ldc, return 0 */ 22951991Sheppo case MAC_STAT_IFSPEED: 22962311Sseb case ETHER_STAT_ALIGN_ERRORS: 22972311Sseb case ETHER_STAT_FCS_ERRORS: 22982311Sseb case ETHER_STAT_FIRST_COLLISIONS: 22992311Sseb case ETHER_STAT_MULTI_COLLISIONS: 23002311Sseb case ETHER_STAT_DEFER_XMTS: 23012311Sseb case ETHER_STAT_TX_LATE_COLLISIONS: 23022311Sseb case ETHER_STAT_EX_COLLISIONS: 23032311Sseb case ETHER_STAT_MACXMT_ERRORS: 23042311Sseb case ETHER_STAT_CARRIER_ERRORS: 23052311Sseb case ETHER_STAT_TOOLONG_ERRORS: 23062311Sseb case ETHER_STAT_XCVR_ADDR: 23072311Sseb case ETHER_STAT_XCVR_ID: 23082311Sseb case ETHER_STAT_XCVR_INUSE: 23092311Sseb case ETHER_STAT_CAP_1000FDX: 23102311Sseb case ETHER_STAT_CAP_1000HDX: 23112311Sseb case ETHER_STAT_CAP_100FDX: 23122311Sseb case ETHER_STAT_CAP_100HDX: 23132311Sseb case ETHER_STAT_CAP_10FDX: 23142311Sseb case ETHER_STAT_CAP_10HDX: 23152311Sseb case ETHER_STAT_CAP_ASMPAUSE: 23162311Sseb case ETHER_STAT_CAP_PAUSE: 23172311Sseb case ETHER_STAT_CAP_AUTONEG: 23182311Sseb case ETHER_STAT_ADV_CAP_1000FDX: 23192311Sseb case ETHER_STAT_ADV_CAP_1000HDX: 23202311Sseb case ETHER_STAT_ADV_CAP_100FDX: 23212311Sseb case ETHER_STAT_ADV_CAP_100HDX: 23222311Sseb case ETHER_STAT_ADV_CAP_10FDX: 23232311Sseb case ETHER_STAT_ADV_CAP_10HDX: 23242311Sseb case ETHER_STAT_ADV_CAP_ASMPAUSE: 23252311Sseb case ETHER_STAT_ADV_CAP_PAUSE: 23262311Sseb case ETHER_STAT_ADV_CAP_AUTONEG: 23272311Sseb case ETHER_STAT_LP_CAP_1000FDX: 23282311Sseb case ETHER_STAT_LP_CAP_1000HDX: 23292311Sseb case ETHER_STAT_LP_CAP_100FDX: 23302311Sseb case ETHER_STAT_LP_CAP_100HDX: 23312311Sseb case ETHER_STAT_LP_CAP_10FDX: 23322311Sseb case ETHER_STAT_LP_CAP_10HDX: 23332311Sseb case ETHER_STAT_LP_CAP_ASMPAUSE: 23342311Sseb case ETHER_STAT_LP_CAP_PAUSE: 23352311Sseb case ETHER_STAT_LP_CAP_AUTONEG: 23362311Sseb case ETHER_STAT_LINK_ASMPAUSE: 23372311Sseb case ETHER_STAT_LINK_PAUSE: 23382311Sseb case ETHER_STAT_LINK_AUTONEG: 23392311Sseb case ETHER_STAT_LINK_DUPLEX: 23401991Sheppo default: 23411991Sheppo val = 0; 23421991Sheppo break; 23431991Sheppo 23441991Sheppo } 23451991Sheppo return (val); 23461991Sheppo } 23471991Sheppo 23482793Slm66018 /* 23492793Slm66018 * LDC channel is UP, start handshake process with peer. 23502793Slm66018 * Flag tells vnet_modify_fdb() about the context: set to B_TRUE if this 23512793Slm66018 * function is being called from transmit routine, otherwise B_FALSE. 23522793Slm66018 */ 23532793Slm66018 static void 23542793Slm66018 vgen_handle_evt_up(vgen_ldc_t *ldcp, boolean_t flag) 23552793Slm66018 { 23562793Slm66018 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 23572793Slm66018 void *vnetp = LDC_TO_VNET(ldcp); 23582793Slm66018 23592793Slm66018 DBG1((vnetp, "vgen_handle_evt_up: enter: id(%lx)\n", ldcp->ldc_id)); 23602793Slm66018 23612793Slm66018 ASSERT(MUTEX_HELD(&ldcp->cblock)); 23622793Slm66018 23632793Slm66018 if (ldcp->portp != vgenp->vsw_portp) { 23642793Slm66018 /* 23652793Slm66018 * modify fdb entry to use this port as the 23662793Slm66018 * channel is up, instead of going through the 23672793Slm66018 * vsw-port (see comments in vgen_port_init()) 23682793Slm66018 */ 23692793Slm66018 vnet_modify_fdb(vnetp, (uint8_t *)&ldcp->portp->macaddr, 23702793Slm66018 vgen_tx, ldcp->portp, flag); 23712793Slm66018 } 23722793Slm66018 23732793Slm66018 /* Initialize local session id */ 23742793Slm66018 ldcp->local_sid = ddi_get_lbolt(); 23752793Slm66018 23762793Slm66018 /* clear peer session id */ 23772793Slm66018 ldcp->peer_sid = 0; 23782793Slm66018 ldcp->hretries = 0; 23792793Slm66018 23802793Slm66018 if (ldcp->hphase != VH_PHASE0) { 23812793Slm66018 vgen_handshake_reset(ldcp); 23822793Slm66018 } 23832793Slm66018 23842793Slm66018 /* Initiate Handshake process with peer ldc endpoint */ 23852793Slm66018 vgen_handshake(vh_nextphase(ldcp)); 23862793Slm66018 23872793Slm66018 DBG1((vnetp, "vgen_handle_evt_up: exit: id(%lx)\n", ldcp->ldc_id)); 23882793Slm66018 } 23892793Slm66018 23902793Slm66018 /* 23912793Slm66018 * LDC channel is Reset, terminate connection with peer and try to 23922793Slm66018 * bring the channel up again. 23932793Slm66018 * Flag tells vnet_modify_fdb() about the context: set to B_TRUE if this 23942793Slm66018 * function is being called from transmit routine, otherwise B_FALSE. 23952793Slm66018 */ 23962793Slm66018 static void 23972793Slm66018 vgen_handle_evt_reset(vgen_ldc_t *ldcp, boolean_t flag) 23982793Slm66018 { 23992793Slm66018 ldc_status_t istatus; 24002793Slm66018 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 24012793Slm66018 void *vnetp = LDC_TO_VNET(ldcp); 24022793Slm66018 int rv; 24032793Slm66018 24042793Slm66018 DBG1((vnetp, "vgen_handle_evt_reset: enter: id(%lx)\n", ldcp->ldc_id)); 24052793Slm66018 24062793Slm66018 ASSERT(MUTEX_HELD(&ldcp->cblock)); 24072793Slm66018 24082793Slm66018 if ((ldcp->portp != vgenp->vsw_portp) && 24092793Slm66018 (vgenp->vsw_portp != NULL)) { 24102793Slm66018 /* 24112793Slm66018 * modify fdb entry to use vsw-port as the 24122793Slm66018 * channel is reset and we don't have a direct 24132793Slm66018 * link to the destination (see comments 24142793Slm66018 * in vgen_port_init()). 24152793Slm66018 */ 24162793Slm66018 vnet_modify_fdb(vnetp, (uint8_t *)&ldcp->portp->macaddr, 24172793Slm66018 vgen_tx, vgenp->vsw_portp, flag); 24182793Slm66018 } 24192793Slm66018 24202793Slm66018 if (ldcp->hphase != VH_PHASE0) { 24212793Slm66018 vgen_handshake_reset(ldcp); 24222793Slm66018 } 24232793Slm66018 24242793Slm66018 /* try to bring the channel up */ 24252793Slm66018 rv = ldc_up(ldcp->ldc_handle); 24262793Slm66018 if (rv != 0) { 24272793Slm66018 DWARN((vnetp, 24282793Slm66018 "vgen_handle_evt_reset: ldc_up err id(%lx) rv(%d)\n", 24292793Slm66018 ldcp->ldc_id, rv)); 24302793Slm66018 } 24312793Slm66018 24322793Slm66018 if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 24332793Slm66018 DWARN((vnetp, 24342793Slm66018 "vgen_handle_evt_reset: ldc_status err id(%lx)\n")); 24352793Slm66018 } else { 24362793Slm66018 ldcp->ldc_status = istatus; 24372793Slm66018 } 24382793Slm66018 24392793Slm66018 /* if channel is already UP - restart handshake */ 24402793Slm66018 if (ldcp->ldc_status == LDC_UP) { 24412793Slm66018 vgen_handle_evt_up(ldcp, flag); 24422793Slm66018 } 24432793Slm66018 24442793Slm66018 DBG1((vnetp, "vgen_handle_evt_reset: exit: id(%lx)\n", ldcp->ldc_id)); 24452793Slm66018 } 24462793Slm66018 24471991Sheppo /* Interrupt handler for the channel */ 24481991Sheppo static uint_t 24491991Sheppo vgen_ldc_cb(uint64_t event, caddr_t arg) 24501991Sheppo { 24511991Sheppo _NOTE(ARGUNUSED(event)) 24521991Sheppo vgen_ldc_t *ldcp; 24531991Sheppo void *vnetp; 24541991Sheppo vgen_t *vgenp; 24551991Sheppo size_t msglen; 24561991Sheppo ldc_status_t istatus; 24571991Sheppo uint64_t ldcmsg[7]; 24582793Slm66018 int rv = 0; 24591991Sheppo vio_msg_tag_t *tagp; 24601991Sheppo mblk_t *mp = NULL; 24611991Sheppo mblk_t *bp = NULL; 24621991Sheppo mblk_t *bpt = NULL; 24631991Sheppo mblk_t *headp = NULL; 24641991Sheppo mblk_t *tailp = NULL; 24651991Sheppo vgen_stats_t *statsp; 24661991Sheppo 24671991Sheppo ldcp = (vgen_ldc_t *)arg; 24681991Sheppo vgenp = LDC_TO_VGEN(ldcp); 24691991Sheppo vnetp = LDC_TO_VNET(ldcp); 24701991Sheppo statsp = ldcp->statsp; 24711991Sheppo 24721991Sheppo DBG1((vnetp, "vgen_ldc_cb enter: ldcid (%lx)\n", ldcp->ldc_id)); 24731991Sheppo 24741991Sheppo mutex_enter(&ldcp->cblock); 24751991Sheppo statsp->callbacks++; 24761991Sheppo if ((ldcp->ldc_status == LDC_INIT) || (ldcp->ldc_handle == NULL)) { 24771991Sheppo DWARN((vnetp, "vgen_ldc_cb: id(%lx), status(%d) is LDC_INIT\n", 24781991Sheppo ldcp->ldc_id, ldcp->ldc_status)); 24791991Sheppo mutex_exit(&ldcp->cblock); 24801991Sheppo return (LDC_SUCCESS); 24811991Sheppo } 24821991Sheppo 24832793Slm66018 /* 24842793Slm66018 * NOTE: not using switch() as event could be triggered by 24852793Slm66018 * a state change and a read request. Also the ordering of the 24862793Slm66018 * check for the event types is deliberate. 24872793Slm66018 */ 24882793Slm66018 if (event & LDC_EVT_UP) { 24892793Slm66018 if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 24902793Slm66018 DWARN((vnetp, 24912793Slm66018 "vgen_ldc_cb: ldc_status err id(%lx)\n")); 24922793Slm66018 } else { 24931991Sheppo ldcp->ldc_status = istatus; 24942793Slm66018 } 24952793Slm66018 ASSERT(ldcp->ldc_status == LDC_UP); 24962793Slm66018 DWARN((vnetp, 24972793Slm66018 "vgen_ldc_cb: id(%lx) event(%lx) UP, status(%d)\n", 24982793Slm66018 ldcp->ldc_id, event, ldcp->ldc_status)); 24992793Slm66018 25002793Slm66018 vgen_handle_evt_up(ldcp, B_FALSE); 25012793Slm66018 25022793Slm66018 ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0); 25032793Slm66018 } 25042793Slm66018 25052793Slm66018 if (event & LDC_EVT_READ) { 25062793Slm66018 DBG2((vnetp, 25072793Slm66018 "vgen_ldc_cb: id(%lx) event(%lx) READ, status(%d)\n", 25082793Slm66018 ldcp->ldc_id, event, ldcp->ldc_status)); 25092793Slm66018 25102793Slm66018 ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0); 25112793Slm66018 goto vgen_ldccb_rcv; 25122793Slm66018 } 25132793Slm66018 25142793Slm66018 if (event & (LDC_EVT_RESET | LDC_EVT_DOWN)) { 25152793Slm66018 if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 25161991Sheppo DWARN((vnetp, 25172793Slm66018 "vgen_ldc_cb: ldc_status err id(%lx)\n")); 25182793Slm66018 } else { 25192793Slm66018 ldcp->ldc_status = istatus; 25201991Sheppo } 25212793Slm66018 DWARN((vnetp, 25222793Slm66018 "vgen_ldc_cb: id(%lx) event(%lx) RESET/DOWN, status(%d)\n", 25232793Slm66018 ldcp->ldc_id, event, ldcp->ldc_status)); 25242793Slm66018 25252793Slm66018 vgen_handle_evt_reset(ldcp, B_FALSE); 25261991Sheppo } 25271991Sheppo 25282793Slm66018 mutex_exit(&ldcp->cblock); 2529*3653Snarayan goto vgen_ldccb_exit; 25302793Slm66018 25312793Slm66018 vgen_ldccb_rcv: 25322793Slm66018 25332793Slm66018 /* if event is LDC_EVT_READ, receive all packets */ 25341991Sheppo do { 25351991Sheppo msglen = sizeof (ldcmsg); 25361991Sheppo rv = ldc_read(ldcp->ldc_handle, (caddr_t)&ldcmsg, &msglen); 25371991Sheppo 25381991Sheppo if (rv != 0) { 25391991Sheppo DWARN((vnetp, 25401991Sheppo "vgen_ldc_cb:ldc_read err id(%lx) rv(%d) " 25411991Sheppo "len(%d)\n", ldcp->ldc_id, rv, msglen)); 25422793Slm66018 if (rv == ECONNRESET) 2543*3653Snarayan goto vgen_ldccb_error; 25441991Sheppo break; 25451991Sheppo } 25461991Sheppo if (msglen == 0) { 25471991Sheppo DBG2((vnetp, "vgen_ldc_cb: ldc_read id(%lx) NODATA", 25481991Sheppo ldcp->ldc_id)); 25491991Sheppo break; 25501991Sheppo } 25511991Sheppo DBG2((vnetp, "vgen_ldc_cb: ldc_read id(%lx): msglen(%d)", 25521991Sheppo ldcp->ldc_id, msglen)); 25531991Sheppo 25541991Sheppo tagp = (vio_msg_tag_t *)ldcmsg; 25551991Sheppo 25561991Sheppo if (ldcp->peer_sid) { 25571991Sheppo /* 25581991Sheppo * check sid only after we have received peer's sid 25591991Sheppo * in the version negotiate msg. 25601991Sheppo */ 25611991Sheppo #ifdef DEBUG 25621991Sheppo if (vgen_hdbg & HDBG_BAD_SID) { 25631991Sheppo /* simulate bad sid condition */ 25641991Sheppo tagp->vio_sid = 0; 25651991Sheppo vgen_hdbg &= ~(HDBG_BAD_SID); 25661991Sheppo } 25671991Sheppo #endif 25682793Slm66018 rv = vgen_check_sid(ldcp, tagp); 25692793Slm66018 if (rv != VGEN_SUCCESS) { 25701991Sheppo /* 25711991Sheppo * If sid mismatch is detected, 25721991Sheppo * reset the channel. 25731991Sheppo */ 25741991Sheppo ldcp->need_ldc_reset = B_TRUE; 2575*3653Snarayan goto vgen_ldccb_error; 25761991Sheppo } 25771991Sheppo } 25781991Sheppo 25791991Sheppo switch (tagp->vio_msgtype) { 25801991Sheppo case VIO_TYPE_CTRL: 25812793Slm66018 rv = vgen_handle_ctrlmsg(ldcp, tagp); 25821991Sheppo break; 25831991Sheppo 25841991Sheppo case VIO_TYPE_DATA: 25851991Sheppo headp = tailp = NULL; 25862793Slm66018 rv = vgen_handle_datamsg(ldcp, tagp, &headp, &tailp); 25871991Sheppo /* build a chain of received packets */ 25881991Sheppo if (headp != NULL) { 25891991Sheppo if (bp == NULL) { 25901991Sheppo bp = headp; 25911991Sheppo bpt = tailp; 25921991Sheppo } else { 25931991Sheppo bpt->b_next = headp; 25941991Sheppo bpt = tailp; 25951991Sheppo } 25961991Sheppo } 25971991Sheppo break; 25981991Sheppo 25991991Sheppo case VIO_TYPE_ERR: 26001991Sheppo vgen_handle_errmsg(ldcp, tagp); 26011991Sheppo break; 26021991Sheppo 26031991Sheppo default: 26041991Sheppo DWARN((vnetp, 26051991Sheppo "vgen_ldc_cb: Unknown VIO_TYPE(%x)\n", 26061991Sheppo tagp->vio_msgtype)); 26071991Sheppo break; 26081991Sheppo } 26091991Sheppo 2610*3653Snarayan vgen_ldccb_error: 26112793Slm66018 if (rv == ECONNRESET) { 26122793Slm66018 if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 26132793Slm66018 DWARN((vnetp, 26142793Slm66018 "vgen_ldc_cb: ldc_status err id(%lx)\n")); 26152793Slm66018 } else { 26162793Slm66018 ldcp->ldc_status = istatus; 26172793Slm66018 } 26182793Slm66018 vgen_handle_evt_reset(ldcp, B_FALSE); 26192793Slm66018 break; 26202793Slm66018 } else if (rv) { 26212793Slm66018 vgen_handshake_retry(ldcp); 26222793Slm66018 break; 26232793Slm66018 } 26242793Slm66018 26251991Sheppo } while (msglen); 26261991Sheppo 26271991Sheppo mutex_exit(&ldcp->cblock); 26282793Slm66018 26291991Sheppo /* send up the received packets to MAC layer */ 26301991Sheppo while (bp != NULL) { 26311991Sheppo mp = bp; 26321991Sheppo bp = bp->b_next; 26331991Sheppo mp->b_next = mp->b_prev = NULL; 26341991Sheppo DBG2((vnetp, "vgen_ldc_cb: id(%lx) rx pkt len (%lx)\n", 26351991Sheppo ldcp->ldc_id, MBLKL(mp))); 26362311Sseb vnet_rx(vgenp->vnetp, NULL, mp); 26371991Sheppo } 2638*3653Snarayan 2639*3653Snarayan vgen_ldccb_exit: 2640*3653Snarayan if (ldcp->cancel_htid) { 2641*3653Snarayan /* 2642*3653Snarayan * Cancel handshake timer. 2643*3653Snarayan * untimeout(9F) will not return until the pending callback is 2644*3653Snarayan * cancelled or has run. No problems will result from calling 2645*3653Snarayan * untimeout if the handler has already completed. 2646*3653Snarayan * If the timeout handler did run, then it would just 2647*3653Snarayan * return as cancel_htid is set. 2648*3653Snarayan */ 2649*3653Snarayan (void) untimeout(ldcp->cancel_htid); 2650*3653Snarayan ldcp->cancel_htid = 0; 2651*3653Snarayan } 26521991Sheppo DBG1((vnetp, "vgen_ldc_cb exit: ldcid (%lx)\n", ldcp->ldc_id)); 26531991Sheppo 26541991Sheppo return (LDC_SUCCESS); 26551991Sheppo } 26561991Sheppo 26571991Sheppo /* vgen handshake functions */ 26581991Sheppo 26591991Sheppo /* change the hphase for the channel to the next phase */ 26601991Sheppo static vgen_ldc_t * 26611991Sheppo vh_nextphase(vgen_ldc_t *ldcp) 26621991Sheppo { 26631991Sheppo if (ldcp->hphase == VH_PHASE3) { 26641991Sheppo ldcp->hphase = VH_DONE; 26651991Sheppo } else { 26661991Sheppo ldcp->hphase++; 26671991Sheppo } 26681991Sheppo return (ldcp); 26691991Sheppo } 26701991Sheppo 26711991Sheppo /* 26721991Sheppo * Check whether the given version is supported or not and 26731991Sheppo * return VGEN_SUCCESS if supported. 26741991Sheppo */ 26751991Sheppo static int 26761991Sheppo vgen_supported_version(vgen_ldc_t *ldcp, uint16_t ver_major, 26771991Sheppo uint16_t ver_minor) 26781991Sheppo { 26791991Sheppo vgen_ver_t *versions = ldcp->vgen_versions; 26801991Sheppo int i = 0; 26811991Sheppo 26821991Sheppo while (i < VGEN_NUM_VER) { 26831991Sheppo if ((versions[i].ver_major == 0) && 26841991Sheppo (versions[i].ver_minor == 0)) { 26851991Sheppo break; 26861991Sheppo } 26871991Sheppo if ((versions[i].ver_major == ver_major) && 26881991Sheppo (versions[i].ver_minor == ver_minor)) { 26891991Sheppo return (VGEN_SUCCESS); 26901991Sheppo } 26911991Sheppo i++; 26921991Sheppo } 26931991Sheppo return (VGEN_FAILURE); 26941991Sheppo } 26951991Sheppo 26961991Sheppo /* 26971991Sheppo * Given a version, return VGEN_SUCCESS if a lower version is supported. 26981991Sheppo */ 26991991Sheppo static int 27001991Sheppo vgen_next_version(vgen_ldc_t *ldcp, vgen_ver_t *verp) 27011991Sheppo { 27021991Sheppo vgen_ver_t *versions = ldcp->vgen_versions; 27031991Sheppo int i = 0; 27041991Sheppo 27051991Sheppo while (i < VGEN_NUM_VER) { 27061991Sheppo if ((versions[i].ver_major == 0) && 27071991Sheppo (versions[i].ver_minor == 0)) { 27081991Sheppo break; 27091991Sheppo } 27101991Sheppo /* 27111991Sheppo * if we support a lower minor version within the same major 27121991Sheppo * version, or if we support a lower major version, 27131991Sheppo * update the verp parameter with this lower version and 27141991Sheppo * return success. 27151991Sheppo */ 27161991Sheppo if (((versions[i].ver_major == verp->ver_major) && 27171991Sheppo (versions[i].ver_minor < verp->ver_minor)) || 27181991Sheppo (versions[i].ver_major < verp->ver_major)) { 27191991Sheppo verp->ver_major = versions[i].ver_major; 27201991Sheppo verp->ver_minor = versions[i].ver_minor; 27211991Sheppo return (VGEN_SUCCESS); 27221991Sheppo } 27231991Sheppo i++; 27241991Sheppo } 27251991Sheppo 27261991Sheppo return (VGEN_FAILURE); 27271991Sheppo } 27281991Sheppo 27291991Sheppo /* 27301991Sheppo * wrapper routine to send the given message over ldc using ldc_write(). 27311991Sheppo */ 27321991Sheppo static int 27331991Sheppo vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg, size_t msglen, 27341991Sheppo boolean_t caller_holds_lock) 27351991Sheppo { 27361991Sheppo int rv; 27371991Sheppo size_t len; 27381991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 27391991Sheppo uint32_t retries = 0; 27401991Sheppo 27411991Sheppo len = msglen; 27421991Sheppo if ((len == 0) || (msg == NULL)) 27431991Sheppo return (VGEN_FAILURE); 27441991Sheppo 27451991Sheppo if (!caller_holds_lock) { 27461991Sheppo mutex_enter(&ldcp->txlock); 27471991Sheppo } 27481991Sheppo 27491991Sheppo do { 27501991Sheppo len = msglen; 27511991Sheppo rv = ldc_write(ldcp->ldc_handle, (caddr_t)msg, &len); 27521991Sheppo if (retries++ >= vgen_ldcwr_retries) 27531991Sheppo break; 27541991Sheppo } while (rv == EWOULDBLOCK); 27551991Sheppo 27561991Sheppo if (!caller_holds_lock) { 27571991Sheppo mutex_exit(&ldcp->txlock); 27581991Sheppo } 27591991Sheppo 27602793Slm66018 if (rv != 0) { 27612793Slm66018 DWARN((vnetp, 27622793Slm66018 "vgen_sendmsg: ldc_write failed: id(%lx) rv(%d)\n", 27632793Slm66018 ldcp->ldc_id, rv, msglen)); 27642793Slm66018 return (rv); 27652793Slm66018 } 27662793Slm66018 27672793Slm66018 if (len != msglen) { 27681991Sheppo DWARN((vnetp, 27691991Sheppo "vgen_sendmsg: ldc_write failed: id(%lx) rv(%d)" 27701991Sheppo " msglen (%d)\n", ldcp->ldc_id, rv, msglen)); 27711991Sheppo return (VGEN_FAILURE); 27721991Sheppo } 27732793Slm66018 27741991Sheppo return (VGEN_SUCCESS); 27751991Sheppo } 27761991Sheppo 27771991Sheppo /* send version negotiate message to the peer over ldc */ 27781991Sheppo static int 27791991Sheppo vgen_send_version_negotiate(vgen_ldc_t *ldcp) 27801991Sheppo { 27811991Sheppo vio_ver_msg_t vermsg; 27821991Sheppo vio_msg_tag_t *tagp = &vermsg.tag; 27831991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 27841991Sheppo int rv; 27851991Sheppo 27861991Sheppo bzero(&vermsg, sizeof (vermsg)); 27871991Sheppo 27881991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 27891991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 27901991Sheppo tagp->vio_subtype_env = VIO_VER_INFO; 27911991Sheppo tagp->vio_sid = ldcp->local_sid; 27921991Sheppo 27931991Sheppo /* get version msg payload from ldcp->local */ 27941991Sheppo vermsg.ver_major = ldcp->local_hparams.ver_major; 27951991Sheppo vermsg.ver_minor = ldcp->local_hparams.ver_minor; 27961991Sheppo vermsg.dev_class = ldcp->local_hparams.dev_class; 27971991Sheppo 27981991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vermsg), B_FALSE); 27991991Sheppo if (rv != VGEN_SUCCESS) { 28001991Sheppo DWARN((vnetp, "vgen_send_version_negotiate: vgen_sendmsg failed" 28011991Sheppo "id (%lx)\n", ldcp->ldc_id)); 28022793Slm66018 return (rv); 28031991Sheppo } 28041991Sheppo 28051991Sheppo ldcp->hstate |= VER_INFO_SENT; 28061991Sheppo DBG2((vnetp, 28071991Sheppo "vgen_send_version_negotiate: VER_INFO_SENT id (%lx) ver(%d,%d)\n", 28081991Sheppo ldcp->ldc_id, vermsg.ver_major, vermsg.ver_minor)); 28091991Sheppo 28101991Sheppo return (VGEN_SUCCESS); 28111991Sheppo } 28121991Sheppo 28131991Sheppo /* send attr info message to the peer over ldc */ 28141991Sheppo static int 28151991Sheppo vgen_send_attr_info(vgen_ldc_t *ldcp) 28161991Sheppo { 28171991Sheppo vnet_attr_msg_t attrmsg; 28181991Sheppo vio_msg_tag_t *tagp = &attrmsg.tag; 28191991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 28201991Sheppo int rv; 28211991Sheppo 28221991Sheppo bzero(&attrmsg, sizeof (attrmsg)); 28231991Sheppo 28241991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 28251991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 28261991Sheppo tagp->vio_subtype_env = VIO_ATTR_INFO; 28271991Sheppo tagp->vio_sid = ldcp->local_sid; 28281991Sheppo 28291991Sheppo /* get attr msg payload from ldcp->local */ 28301991Sheppo attrmsg.mtu = ldcp->local_hparams.mtu; 28311991Sheppo attrmsg.addr = ldcp->local_hparams.addr; 28321991Sheppo attrmsg.addr_type = ldcp->local_hparams.addr_type; 28331991Sheppo attrmsg.xfer_mode = ldcp->local_hparams.xfer_mode; 28341991Sheppo attrmsg.ack_freq = ldcp->local_hparams.ack_freq; 28351991Sheppo 28361991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (attrmsg), B_FALSE); 28371991Sheppo if (rv != VGEN_SUCCESS) { 28381991Sheppo DWARN((vnetp, "vgen_send_attr_info: vgen_sendmsg failed" 28391991Sheppo "id (%lx)\n", ldcp->ldc_id)); 28402793Slm66018 return (rv); 28411991Sheppo } 28421991Sheppo 28431991Sheppo ldcp->hstate |= ATTR_INFO_SENT; 28441991Sheppo DBG2((vnetp, "vgen_send_attr_info: ATTR_INFO_SENT id (%lx)\n", 28451991Sheppo ldcp->ldc_id)); 28461991Sheppo 28471991Sheppo return (VGEN_SUCCESS); 28481991Sheppo } 28491991Sheppo 28501991Sheppo /* send descriptor ring register message to the peer over ldc */ 28511991Sheppo static int 28521991Sheppo vgen_send_dring_reg(vgen_ldc_t *ldcp) 28531991Sheppo { 28541991Sheppo vio_dring_reg_msg_t msg; 28551991Sheppo vio_msg_tag_t *tagp = &msg.tag; 28561991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 28571991Sheppo int rv; 28581991Sheppo 28591991Sheppo bzero(&msg, sizeof (msg)); 28601991Sheppo 28611991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 28621991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 28631991Sheppo tagp->vio_subtype_env = VIO_DRING_REG; 28641991Sheppo tagp->vio_sid = ldcp->local_sid; 28651991Sheppo 28661991Sheppo /* get dring info msg payload from ldcp->local */ 28671991Sheppo bcopy(&(ldcp->local_hparams.dring_cookie), (msg.cookie), 28681991Sheppo sizeof (ldc_mem_cookie_t)); 28691991Sheppo msg.ncookies = ldcp->local_hparams.num_dcookies; 28701991Sheppo msg.num_descriptors = ldcp->local_hparams.num_desc; 28711991Sheppo msg.descriptor_size = ldcp->local_hparams.desc_size; 28721991Sheppo 28731991Sheppo /* 28741991Sheppo * dring_ident is set to 0. After mapping the dring, peer sets this 28751991Sheppo * value and sends it in the ack, which is saved in 28761991Sheppo * vgen_handle_dring_reg(). 28771991Sheppo */ 28781991Sheppo msg.dring_ident = 0; 28791991Sheppo 28801991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (msg), B_FALSE); 28811991Sheppo if (rv != VGEN_SUCCESS) { 28821991Sheppo DWARN((vnetp, "vgen_send_dring_reg: vgen_sendmsg failed" 28831991Sheppo "id (%lx)\n", ldcp->ldc_id)); 28842793Slm66018 return (rv); 28851991Sheppo } 28861991Sheppo 28871991Sheppo ldcp->hstate |= DRING_INFO_SENT; 28881991Sheppo DBG2((vnetp, "vgen_send_dring_reg: DRING_INFO_SENT id (%lx)\n", 28891991Sheppo ldcp->ldc_id)); 28901991Sheppo 28911991Sheppo return (VGEN_SUCCESS); 28921991Sheppo } 28931991Sheppo 28941991Sheppo static int 28951991Sheppo vgen_send_rdx_info(vgen_ldc_t *ldcp) 28961991Sheppo { 28971991Sheppo vio_rdx_msg_t rdxmsg; 28981991Sheppo vio_msg_tag_t *tagp = &rdxmsg.tag; 28991991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 29001991Sheppo int rv; 29011991Sheppo 29021991Sheppo bzero(&rdxmsg, sizeof (rdxmsg)); 29031991Sheppo 29041991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 29051991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 29061991Sheppo tagp->vio_subtype_env = VIO_RDX; 29071991Sheppo tagp->vio_sid = ldcp->local_sid; 29081991Sheppo 29091991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (rdxmsg), B_FALSE); 29101991Sheppo if (rv != VGEN_SUCCESS) { 29111991Sheppo DWARN((vnetp, "vgen_send_rdx_info: vgen_sendmsg failed" 29121991Sheppo "id (%lx)\n", ldcp->ldc_id)); 29132793Slm66018 return (rv); 29141991Sheppo } 29151991Sheppo 29161991Sheppo ldcp->hstate |= RDX_INFO_SENT; 29171991Sheppo DBG2((vnetp, "vgen_send_rdx_info: RDX_INFO_SENT id (%lx)\n", 29181991Sheppo ldcp->ldc_id)); 29191991Sheppo 29201991Sheppo return (VGEN_SUCCESS); 29211991Sheppo } 29221991Sheppo 29231991Sheppo /* send descriptor ring data message to the peer over ldc */ 29241991Sheppo static int 29252336Snarayan vgen_send_dring_data(vgen_ldc_t *ldcp, uint32_t start, int32_t end) 29261991Sheppo { 29271991Sheppo vio_dring_msg_t dringmsg, *msgp = &dringmsg; 29281991Sheppo vio_msg_tag_t *tagp = &msgp->tag; 29291991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 29301991Sheppo int rv; 29311991Sheppo 29321991Sheppo bzero(msgp, sizeof (*msgp)); 29331991Sheppo 29341991Sheppo tagp->vio_msgtype = VIO_TYPE_DATA; 29351991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 29361991Sheppo tagp->vio_subtype_env = VIO_DRING_DATA; 29371991Sheppo tagp->vio_sid = ldcp->local_sid; 29381991Sheppo 29392336Snarayan msgp->seq_num = ldcp->next_txseq; 29401991Sheppo msgp->dring_ident = ldcp->local_hparams.dring_ident; 29411991Sheppo msgp->start_idx = start; 29421991Sheppo msgp->end_idx = end; 29431991Sheppo 29441991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (dringmsg), B_TRUE); 29451991Sheppo if (rv != VGEN_SUCCESS) { 29461991Sheppo DWARN((vnetp, "vgen_send_dring_data: vgen_sendmsg failed" 29472793Slm66018 " id (%lx)\n", ldcp->ldc_id)); 29482793Slm66018 return (rv); 29491991Sheppo } 29501991Sheppo 29512336Snarayan ldcp->next_txseq++; 29522336Snarayan ldcp->statsp->dring_data_msgs++; 29532336Snarayan 29541991Sheppo DBG2((vnetp, "vgen_send_dring_data: DRING_DATA_SENT id (%lx)\n", 29551991Sheppo ldcp->ldc_id)); 29561991Sheppo 29571991Sheppo return (VGEN_SUCCESS); 29581991Sheppo } 29591991Sheppo 29601991Sheppo /* send multicast addr info message to vsw */ 29611991Sheppo static int 29621991Sheppo vgen_send_mcast_info(vgen_ldc_t *ldcp) 29631991Sheppo { 29641991Sheppo vnet_mcast_msg_t mcastmsg; 29651991Sheppo vnet_mcast_msg_t *msgp; 29661991Sheppo vio_msg_tag_t *tagp; 29671991Sheppo vgen_t *vgenp; 29681991Sheppo void *vnetp; 29691991Sheppo struct ether_addr *mca; 29701991Sheppo int rv; 29711991Sheppo int i; 29721991Sheppo uint32_t size; 29731991Sheppo uint32_t mccount; 29741991Sheppo uint32_t n; 29751991Sheppo 29761991Sheppo msgp = &mcastmsg; 29771991Sheppo tagp = &msgp->tag; 29781991Sheppo vgenp = LDC_TO_VGEN(ldcp); 29791991Sheppo vnetp = LDC_TO_VNET(ldcp); 29801991Sheppo 29811991Sheppo mccount = vgenp->mccount; 29821991Sheppo i = 0; 29831991Sheppo 29841991Sheppo do { 29851991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 29861991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 29871991Sheppo tagp->vio_subtype_env = VNET_MCAST_INFO; 29881991Sheppo tagp->vio_sid = ldcp->local_sid; 29891991Sheppo 29901991Sheppo n = ((mccount >= VNET_NUM_MCAST) ? VNET_NUM_MCAST : mccount); 29911991Sheppo size = n * sizeof (struct ether_addr); 29921991Sheppo 29931991Sheppo mca = &(vgenp->mctab[i]); 29941991Sheppo bcopy(mca, (msgp->mca), size); 29951991Sheppo msgp->set = B_TRUE; 29961991Sheppo msgp->count = n; 29971991Sheppo 29981991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp), 29991991Sheppo B_FALSE); 30001991Sheppo if (rv != VGEN_SUCCESS) { 30011991Sheppo DWARN((vnetp, "vgen_send_mcast_info: vgen_sendmsg err" 30021991Sheppo "id (%lx)\n", ldcp->ldc_id)); 30032793Slm66018 return (rv); 30041991Sheppo } 30051991Sheppo 30061991Sheppo mccount -= n; 30071991Sheppo i += n; 30081991Sheppo 30091991Sheppo } while (mccount); 30101991Sheppo 30111991Sheppo return (VGEN_SUCCESS); 30121991Sheppo } 30131991Sheppo 30141991Sheppo /* Initiate Phase 2 of handshake */ 30151991Sheppo static int 30161991Sheppo vgen_handshake_phase2(vgen_ldc_t *ldcp) 30171991Sheppo { 30181991Sheppo int rv; 30192793Slm66018 uint32_t ncookies = 0; 30202793Slm66018 void *vnetp = LDC_TO_VNET(ldcp); 30211991Sheppo #ifdef DEBUG 30221991Sheppo if (vgen_hdbg & HDBG_OUT_STATE) { 30231991Sheppo /* simulate out of state condition */ 30241991Sheppo vgen_hdbg &= ~(HDBG_OUT_STATE); 30251991Sheppo rv = vgen_send_rdx_info(ldcp); 30261991Sheppo return (rv); 30271991Sheppo } 30281991Sheppo if (vgen_hdbg & HDBG_TIMEOUT) { 30291991Sheppo /* simulate timeout condition */ 30301991Sheppo vgen_hdbg &= ~(HDBG_TIMEOUT); 30311991Sheppo return (VGEN_SUCCESS); 30321991Sheppo } 30331991Sheppo #endif 30342793Slm66018 rv = vgen_send_attr_info(ldcp); 30352793Slm66018 if (rv != VGEN_SUCCESS) { 30361991Sheppo return (rv); 30371991Sheppo } 30382793Slm66018 30392793Slm66018 /* Bind descriptor ring to the channel */ 30402793Slm66018 if (ldcp->num_txdcookies == 0) { 30412793Slm66018 rv = ldc_mem_dring_bind(ldcp->ldc_handle, ldcp->tx_dhandle, 30422793Slm66018 LDC_SHADOW_MAP, LDC_MEM_RW, &ldcp->tx_dcookie, &ncookies); 30432793Slm66018 if (rv != 0) { 30442793Slm66018 DWARN((vnetp, "vgen_handshake_phase2: id (%lx) " 30452793Slm66018 "ldc_mem_dring_bind failed rv(%x)\n", 30462793Slm66018 ldcp->ldc_id, rv)); 30472793Slm66018 return (rv); 30482793Slm66018 } 30492793Slm66018 ASSERT(ncookies == 1); 30502793Slm66018 ldcp->num_txdcookies = ncookies; 30512793Slm66018 } 30522793Slm66018 30532793Slm66018 /* update local dring_info params */ 30542793Slm66018 bcopy(&(ldcp->tx_dcookie), &(ldcp->local_hparams.dring_cookie), 30552793Slm66018 sizeof (ldc_mem_cookie_t)); 30562793Slm66018 ldcp->local_hparams.num_dcookies = ldcp->num_txdcookies; 30572793Slm66018 ldcp->local_hparams.num_desc = ldcp->num_txds; 30582793Slm66018 ldcp->local_hparams.desc_size = sizeof (vnet_public_desc_t); 30592793Slm66018 30602793Slm66018 rv = vgen_send_dring_reg(ldcp); 30612793Slm66018 if (rv != VGEN_SUCCESS) { 30621991Sheppo return (rv); 30631991Sheppo } 30641991Sheppo 30651991Sheppo return (VGEN_SUCCESS); 30661991Sheppo } 30671991Sheppo 30681991Sheppo /* 30691991Sheppo * This function resets the handshake phase to VH_PHASE0(pre-handshake phase). 30701991Sheppo * This can happen after a channel comes up (status: LDC_UP) or 30711991Sheppo * when handshake gets terminated due to various conditions. 30721991Sheppo */ 30731991Sheppo static void 30741991Sheppo vgen_reset_hphase(vgen_ldc_t *ldcp) 30751991Sheppo { 30761991Sheppo vgen_t *vgenp = LDC_TO_VGEN(ldcp); 30771991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 30781991Sheppo ldc_status_t istatus; 30792793Slm66018 int rv; 30801991Sheppo 30811991Sheppo DBG2((vnetp, "vgen_reset_hphase: id(0x%lx)\n", ldcp->ldc_id)); 30821991Sheppo /* reset hstate and hphase */ 30831991Sheppo ldcp->hstate = 0; 30841991Sheppo ldcp->hphase = VH_PHASE0; 30851991Sheppo 3086*3653Snarayan /* 3087*3653Snarayan * Save the id of pending handshake timer in cancel_htid. 3088*3653Snarayan * This will be checked in vgen_ldc_cb() and the handshake timer will 3089*3653Snarayan * be cancelled after releasing cblock. 3090*3653Snarayan */ 30911991Sheppo if (ldcp->htid) { 3092*3653Snarayan ldcp->cancel_htid = ldcp->htid; 30931991Sheppo ldcp->htid = 0; 30941991Sheppo } 30951991Sheppo 30961991Sheppo if (ldcp->local_hparams.dring_ready) { 30971991Sheppo ldcp->local_hparams.dring_ready = B_FALSE; 30982793Slm66018 } 30992793Slm66018 31002793Slm66018 /* Unbind tx descriptor ring from the channel */ 31012793Slm66018 if (ldcp->num_txdcookies) { 31022793Slm66018 rv = ldc_mem_dring_unbind(ldcp->tx_dhandle); 31032793Slm66018 if (rv != 0) { 31042793Slm66018 DWARN((vnetp, 31052793Slm66018 "vgen_reset_hphase: ldc_mem_dring_unbind " 31062793Slm66018 "failed id(%lx)\n", ldcp->ldc_id)); 31072793Slm66018 } 31082793Slm66018 ldcp->num_txdcookies = 0; 31091991Sheppo } 31101991Sheppo 31111991Sheppo if (ldcp->peer_hparams.dring_ready) { 31121991Sheppo ldcp->peer_hparams.dring_ready = B_FALSE; 31131991Sheppo /* Unmap peer's dring */ 31141991Sheppo (void) ldc_mem_dring_unmap(ldcp->rx_dhandle); 31151991Sheppo vgen_clobber_rxds(ldcp); 31161991Sheppo } 31171991Sheppo 31181991Sheppo vgen_clobber_tbufs(ldcp); 31191991Sheppo 31201991Sheppo /* 31211991Sheppo * clear local handshake params and initialize. 31221991Sheppo */ 31231991Sheppo bzero(&(ldcp->local_hparams), sizeof (ldcp->local_hparams)); 31241991Sheppo 31251991Sheppo /* set version to the highest version supported */ 31261991Sheppo ldcp->local_hparams.ver_major = 31271991Sheppo ldcp->vgen_versions[0].ver_major; 31281991Sheppo ldcp->local_hparams.ver_minor = 31291991Sheppo ldcp->vgen_versions[0].ver_minor; 31301991Sheppo ldcp->local_hparams.dev_class = VDEV_NETWORK; 31311991Sheppo 31321991Sheppo /* set attr_info params */ 31331991Sheppo ldcp->local_hparams.mtu = ETHERMAX; 31341991Sheppo ldcp->local_hparams.addr = 31351991Sheppo vgen_macaddr_strtoul(vgenp->macaddr); 31361991Sheppo ldcp->local_hparams.addr_type = ADDR_TYPE_MAC; 31371991Sheppo ldcp->local_hparams.xfer_mode = VIO_DRING_MODE; 31381991Sheppo ldcp->local_hparams.ack_freq = 0; /* don't need acks */ 31391991Sheppo 31401991Sheppo /* 31412793Slm66018 * Note: dring is created, but not bound yet. 31422793Slm66018 * local dring_info params will be updated when we bind the dring in 31432793Slm66018 * vgen_handshake_phase2(). 31441991Sheppo * dring_ident is set to 0. After mapping the dring, peer sets this 31451991Sheppo * value and sends it in the ack, which is saved in 31461991Sheppo * vgen_handle_dring_reg(). 31471991Sheppo */ 31481991Sheppo ldcp->local_hparams.dring_ident = 0; 31491991Sheppo 31501991Sheppo /* clear peer_hparams */ 31511991Sheppo bzero(&(ldcp->peer_hparams), sizeof (ldcp->peer_hparams)); 31521991Sheppo 31531991Sheppo /* reset the channel if required */ 31541991Sheppo if (ldcp->need_ldc_reset) { 31551991Sheppo DWARN((vnetp, 31561991Sheppo "vgen_reset_hphase: id (%lx), Doing Channel Reset...\n", 31571991Sheppo ldcp->ldc_id)); 31581991Sheppo ldcp->need_ldc_reset = B_FALSE; 31592410Slm66018 (void) ldc_down(ldcp->ldc_handle); 31601991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 31611991Sheppo DBG2((vnetp, 31622793Slm66018 "vgen_reset_hphase: id (%lx), Reset Done,ldc_status(%x)\n", 31631991Sheppo ldcp->ldc_id, istatus)); 31641991Sheppo ldcp->ldc_status = istatus; 31652793Slm66018 31661991Sheppo /* clear sids */ 31671991Sheppo ldcp->local_sid = 0; 31681991Sheppo ldcp->peer_sid = 0; 31692793Slm66018 31702793Slm66018 /* try to bring the channel up */ 31712793Slm66018 rv = ldc_up(ldcp->ldc_handle); 31722793Slm66018 if (rv != 0) { 31732793Slm66018 DWARN((vnetp, 31742793Slm66018 "vgen_reset_hphase: ldc_up err id(%lx) rv(%d)\n", 31752793Slm66018 ldcp->ldc_id, rv)); 31762793Slm66018 } 31772793Slm66018 31782793Slm66018 if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 31792793Slm66018 DWARN((vnetp, 31802793Slm66018 "vgen_reset_hphase: ldc_status err id(%lx)\n")); 31812793Slm66018 } else { 31822793Slm66018 ldcp->ldc_status = istatus; 31832793Slm66018 } 31841991Sheppo } 31851991Sheppo } 31861991Sheppo 31871991Sheppo /* wrapper function for vgen_reset_hphase */ 31881991Sheppo static void 31891991Sheppo vgen_handshake_reset(vgen_ldc_t *ldcp) 31901991Sheppo { 31911991Sheppo ASSERT(MUTEX_HELD(&ldcp->cblock)); 31921991Sheppo mutex_enter(&ldcp->txlock); 31931991Sheppo mutex_enter(&ldcp->tclock); 31941991Sheppo 31951991Sheppo vgen_reset_hphase(ldcp); 31961991Sheppo 31971991Sheppo mutex_exit(&ldcp->tclock); 31981991Sheppo mutex_exit(&ldcp->txlock); 31991991Sheppo } 32001991Sheppo 32011991Sheppo /* 32021991Sheppo * Initiate handshake with the peer by sending various messages 32031991Sheppo * based on the handshake-phase that the channel is currently in. 32041991Sheppo */ 32051991Sheppo static void 32061991Sheppo vgen_handshake(vgen_ldc_t *ldcp) 32071991Sheppo { 32081991Sheppo uint32_t hphase = ldcp->hphase; 32091991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 32101991Sheppo vgen_t *vgenp = LDC_TO_VGEN(ldcp); 32112793Slm66018 ldc_status_t istatus; 32122793Slm66018 int rv = 0; 32131991Sheppo 32141991Sheppo switch (hphase) { 32151991Sheppo 32161991Sheppo case VH_PHASE1: 32171991Sheppo 32181991Sheppo /* 32191991Sheppo * start timer, for entire handshake process, turn this timer 32201991Sheppo * off if all phases of handshake complete successfully and 32211991Sheppo * hphase goes to VH_DONE(below) or 32221991Sheppo * vgen_reset_hphase() gets called or 32231991Sheppo * channel is reset due to errors or 32241991Sheppo * vgen_ldc_uninit() is invoked(vgen_stop). 32251991Sheppo */ 32261991Sheppo ldcp->htid = timeout(vgen_hwatchdog, (caddr_t)ldcp, 32271991Sheppo drv_usectohz(vgen_hwd_interval * 1000)); 32281991Sheppo 32291991Sheppo /* Phase 1 involves negotiating the version */ 32302793Slm66018 rv = vgen_send_version_negotiate(ldcp); 32311991Sheppo break; 32321991Sheppo 32331991Sheppo case VH_PHASE2: 32342793Slm66018 rv = vgen_handshake_phase2(ldcp); 32351991Sheppo break; 32361991Sheppo 32371991Sheppo case VH_PHASE3: 32382793Slm66018 rv = vgen_send_rdx_info(ldcp); 32391991Sheppo break; 32401991Sheppo 32411991Sheppo case VH_DONE: 3242*3653Snarayan /* 3243*3653Snarayan * Save the id of pending handshake timer in cancel_htid. 3244*3653Snarayan * This will be checked in vgen_ldc_cb() and the handshake 3245*3653Snarayan * timer will be cancelled after releasing cblock. 3246*3653Snarayan */ 32471991Sheppo if (ldcp->htid) { 3248*3653Snarayan ldcp->cancel_htid = ldcp->htid; 32491991Sheppo ldcp->htid = 0; 32501991Sheppo } 32511991Sheppo ldcp->hretries = 0; 32521991Sheppo #if 0 32531991Sheppo vgen_print_ldcinfo(ldcp); 32541991Sheppo #endif 32551991Sheppo DBG1((vnetp, "vgen_handshake: id(0x%lx) Handshake Done\n", 32561991Sheppo ldcp->ldc_id)); 32571991Sheppo 32581991Sheppo if (ldcp->need_mcast_sync) { 32591991Sheppo /* need to sync multicast table with vsw */ 32601991Sheppo 32611991Sheppo ldcp->need_mcast_sync = B_FALSE; 32621991Sheppo mutex_exit(&ldcp->cblock); 32631991Sheppo 32641991Sheppo mutex_enter(&vgenp->lock); 32652793Slm66018 rv = vgen_send_mcast_info(ldcp); 32661991Sheppo mutex_exit(&vgenp->lock); 32671991Sheppo 32681991Sheppo mutex_enter(&ldcp->cblock); 32692793Slm66018 if (rv != VGEN_SUCCESS) 32702793Slm66018 break; 32711991Sheppo } 32722793Slm66018 32732793Slm66018 /* 32742793Slm66018 * Check if mac layer should be notified to restart 32752793Slm66018 * transmissions. This can happen if the channel got 32762793Slm66018 * reset and vgen_clobber_tbufs() is called, while 32772793Slm66018 * need_resched is set. 32782793Slm66018 */ 32792793Slm66018 mutex_enter(&ldcp->tclock); 32802793Slm66018 if (ldcp->need_resched) { 32812793Slm66018 ldcp->need_resched = B_FALSE; 32822793Slm66018 vnet_tx_update(vgenp->vnetp); 32832793Slm66018 } 32842793Slm66018 mutex_exit(&ldcp->tclock); 32852793Slm66018 32861991Sheppo break; 32871991Sheppo 32881991Sheppo default: 32891991Sheppo break; 32901991Sheppo } 32912793Slm66018 32922793Slm66018 if (rv == ECONNRESET) { 32932793Slm66018 if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 32942793Slm66018 DWARN((vnetp, 32952793Slm66018 "vgen_handshake: ldc_status err id(%lx)\n")); 32962793Slm66018 } else { 32972793Slm66018 ldcp->ldc_status = istatus; 32982793Slm66018 } 32992793Slm66018 vgen_handle_evt_reset(ldcp, B_FALSE); 33002793Slm66018 } else if (rv) { 33012793Slm66018 vgen_handshake_reset(ldcp); 33022793Slm66018 } 33031991Sheppo } 33041991Sheppo 33051991Sheppo /* 33061991Sheppo * Check if the current handshake phase has completed successfully and 33071991Sheppo * return the status. 33081991Sheppo */ 33091991Sheppo static int 33101991Sheppo vgen_handshake_done(vgen_ldc_t *ldcp) 33111991Sheppo { 33121991Sheppo uint32_t hphase = ldcp->hphase; 33131991Sheppo int status = 0; 33141991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 33151991Sheppo 33161991Sheppo switch (hphase) { 33171991Sheppo 33181991Sheppo case VH_PHASE1: 33191991Sheppo /* 33201991Sheppo * Phase1 is done, if version negotiation 33211991Sheppo * completed successfully. 33221991Sheppo */ 33231991Sheppo status = ((ldcp->hstate & VER_NEGOTIATED) == 33241991Sheppo VER_NEGOTIATED); 33251991Sheppo break; 33261991Sheppo 33271991Sheppo case VH_PHASE2: 33281991Sheppo /* 33291991Sheppo * Phase 2 is done, if attr info and dring info 33301991Sheppo * have been exchanged successfully. 33311991Sheppo */ 33321991Sheppo status = (((ldcp->hstate & ATTR_INFO_EXCHANGED) == 33331991Sheppo ATTR_INFO_EXCHANGED) && 33341991Sheppo ((ldcp->hstate & DRING_INFO_EXCHANGED) == 33351991Sheppo DRING_INFO_EXCHANGED)); 33361991Sheppo break; 33371991Sheppo 33381991Sheppo case VH_PHASE3: 33391991Sheppo /* Phase 3 is done, if rdx msg has been exchanged */ 33401991Sheppo status = ((ldcp->hstate & RDX_EXCHANGED) == 33411991Sheppo RDX_EXCHANGED); 33421991Sheppo break; 33431991Sheppo 33441991Sheppo default: 33451991Sheppo break; 33461991Sheppo } 33471991Sheppo 33481991Sheppo if (status == 0) { 33491991Sheppo return (VGEN_FAILURE); 33501991Sheppo } 33511991Sheppo DBG2((vnetp, "VNET_HANDSHAKE_DONE: PHASE(%d)\n", hphase)); 33521991Sheppo return (VGEN_SUCCESS); 33531991Sheppo } 33541991Sheppo 33551991Sheppo /* retry handshake on failure */ 33561991Sheppo static void 33571991Sheppo vgen_handshake_retry(vgen_ldc_t *ldcp) 33581991Sheppo { 33591991Sheppo /* reset handshake phase */ 33601991Sheppo vgen_handshake_reset(ldcp); 3361*3653Snarayan 3362*3653Snarayan /* handshake retry is specified and the channel is UP */ 3363*3653Snarayan if (vgen_max_hretries && (ldcp->ldc_status == LDC_UP)) { 3364*3653Snarayan if (ldcp->hretries++ < vgen_max_hretries) { 3365*3653Snarayan ldcp->local_sid = ddi_get_lbolt(); 33661991Sheppo vgen_handshake(vh_nextphase(ldcp)); 3367*3653Snarayan } 33681991Sheppo } 33691991Sheppo } 33701991Sheppo 33711991Sheppo /* 33721991Sheppo * Handle a version info msg from the peer or an ACK/NACK from the peer 33731991Sheppo * to a version info msg that we sent. 33741991Sheppo */ 33752793Slm66018 static int 33761991Sheppo vgen_handle_version_negotiate(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 33771991Sheppo { 33781991Sheppo vio_ver_msg_t *vermsg = (vio_ver_msg_t *)tagp; 33791991Sheppo int ack = 0; 33801991Sheppo int failed = 0; 33811991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 33821991Sheppo int idx; 33831991Sheppo vgen_ver_t *versions = ldcp->vgen_versions; 33842793Slm66018 int rv = 0; 33851991Sheppo 33861991Sheppo DBG1((vnetp, "vgen_handle_version_negotiate: enter\n")); 33871991Sheppo switch (tagp->vio_subtype) { 33881991Sheppo case VIO_SUBTYPE_INFO: 33891991Sheppo 33901991Sheppo /* Cache sid of peer if this is the first time */ 33911991Sheppo if (ldcp->peer_sid == 0) { 33921991Sheppo DBG2((vnetp, 33931991Sheppo "vgen_handle_version_negotiate: id (%lx) Caching" 33941991Sheppo " peer_sid(%x)\n", ldcp->ldc_id, tagp->vio_sid)); 33951991Sheppo ldcp->peer_sid = tagp->vio_sid; 33961991Sheppo } 33971991Sheppo 33981991Sheppo if (ldcp->hphase != VH_PHASE1) { 33991991Sheppo /* 34001991Sheppo * If we are not already in VH_PHASE1, reset to 34011991Sheppo * pre-handshake state, and initiate handshake 34021991Sheppo * to the peer too. 34031991Sheppo */ 34041991Sheppo vgen_handshake_reset(ldcp); 34051991Sheppo vgen_handshake(vh_nextphase(ldcp)); 34061991Sheppo } 34071991Sheppo ldcp->hstate |= VER_INFO_RCVD; 34081991Sheppo 34091991Sheppo /* save peer's requested values */ 34101991Sheppo ldcp->peer_hparams.ver_major = vermsg->ver_major; 34111991Sheppo ldcp->peer_hparams.ver_minor = vermsg->ver_minor; 34121991Sheppo ldcp->peer_hparams.dev_class = vermsg->dev_class; 34131991Sheppo 34141991Sheppo if ((vermsg->dev_class != VDEV_NETWORK) && 34151991Sheppo (vermsg->dev_class != VDEV_NETWORK_SWITCH)) { 34161991Sheppo /* unsupported dev_class, send NACK */ 34171991Sheppo 34182793Slm66018 DWARN((vnetp, 34192793Slm66018 "vgen_handle_version_negotiate: Version" 34202793Slm66018 " Negotiation Failed id (%lx)\n", ldcp->ldc_id)); 34212793Slm66018 34221991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 34231991Sheppo tagp->vio_sid = ldcp->local_sid; 34241991Sheppo /* send reply msg back to peer */ 34252793Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, 34261991Sheppo sizeof (*vermsg), B_FALSE); 34272793Slm66018 if (rv != VGEN_SUCCESS) { 34282793Slm66018 return (rv); 34292793Slm66018 } 34302793Slm66018 return (VGEN_FAILURE); 34311991Sheppo } 34321991Sheppo 34331991Sheppo DBG2((vnetp, "vgen_handle_version_negotiate: VER_INFO_RCVD," 34341991Sheppo " id (%lx), ver(%d,%d)\n", ldcp->ldc_id, 34351991Sheppo vermsg->ver_major, vermsg->ver_minor)); 34361991Sheppo 34371991Sheppo idx = 0; 34381991Sheppo 34391991Sheppo for (;;) { 34401991Sheppo 34411991Sheppo if (vermsg->ver_major > versions[idx].ver_major) { 34421991Sheppo 34431991Sheppo /* nack with next lower version */ 34441991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 34451991Sheppo vermsg->ver_major = versions[idx].ver_major; 34461991Sheppo vermsg->ver_minor = versions[idx].ver_minor; 34471991Sheppo break; 34481991Sheppo } 34491991Sheppo 34501991Sheppo if (vermsg->ver_major == versions[idx].ver_major) { 34511991Sheppo 34521991Sheppo /* major version match - ACK version */ 34531991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 34541991Sheppo ack = 1; 34551991Sheppo 34561991Sheppo /* 34571991Sheppo * lower minor version to the one this endpt 34581991Sheppo * supports, if necessary 34591991Sheppo */ 34601991Sheppo if (vermsg->ver_minor > 34611991Sheppo versions[idx].ver_minor) { 34621991Sheppo vermsg->ver_minor = 34631991Sheppo versions[idx].ver_minor; 34641991Sheppo ldcp->peer_hparams.ver_minor = 34651991Sheppo versions[idx].ver_minor; 34661991Sheppo } 34671991Sheppo break; 34681991Sheppo } 34691991Sheppo 34701991Sheppo idx++; 34711991Sheppo 34721991Sheppo if (idx == VGEN_NUM_VER) { 34731991Sheppo 34741991Sheppo /* no version match - send NACK */ 34751991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 34761991Sheppo vermsg->ver_major = 0; 34771991Sheppo vermsg->ver_minor = 0; 34781991Sheppo failed = 1; 34791991Sheppo break; 34801991Sheppo } 34811991Sheppo 34821991Sheppo } 34831991Sheppo 34841991Sheppo tagp->vio_sid = ldcp->local_sid; 34851991Sheppo 34861991Sheppo /* send reply msg back to peer */ 34872793Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*vermsg), 34882793Slm66018 B_FALSE); 34892793Slm66018 if (rv != VGEN_SUCCESS) { 34902793Slm66018 return (rv); 34911991Sheppo } 34921991Sheppo 34931991Sheppo if (ack) { 34941991Sheppo ldcp->hstate |= VER_ACK_SENT; 34951991Sheppo DBG2((vnetp, "vgen_handle_version_negotiate:" 34961991Sheppo " VER_ACK_SENT, id (%lx) ver(%d,%d) \n", 34971991Sheppo ldcp->ldc_id, vermsg->ver_major, 34981991Sheppo vermsg->ver_minor)); 34991991Sheppo } 35001991Sheppo if (failed) { 35011991Sheppo DWARN((vnetp, "vgen_handle_version_negotiate:" 35021991Sheppo " Version Negotiation Failed id (%lx)\n", 35031991Sheppo ldcp->ldc_id)); 35042793Slm66018 return (VGEN_FAILURE); 35051991Sheppo } 35061991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 35071991Sheppo 35081991Sheppo /* VER_ACK_SENT and VER_ACK_RCVD */ 35091991Sheppo 35101991Sheppo /* local and peer versions match? */ 35111991Sheppo ASSERT((ldcp->local_hparams.ver_major == 35121991Sheppo ldcp->peer_hparams.ver_major) && 35131991Sheppo (ldcp->local_hparams.ver_minor == 35141991Sheppo ldcp->peer_hparams.ver_minor)); 35151991Sheppo 35161991Sheppo /* move to the next phase */ 35171991Sheppo vgen_handshake(vh_nextphase(ldcp)); 35181991Sheppo } 35191991Sheppo 35201991Sheppo break; 35211991Sheppo 35221991Sheppo case VIO_SUBTYPE_ACK: 35231991Sheppo 35241991Sheppo if (ldcp->hphase != VH_PHASE1) { 35251991Sheppo /* This should not happen. */ 35261991Sheppo DWARN((vnetp, 35271991Sheppo "vgen_handle_version_negotiate:" 35281991Sheppo " VER_ACK_RCVD id (%lx) Invalid Phase(%u)\n", 35291991Sheppo ldcp->ldc_id, ldcp->hphase)); 35302793Slm66018 return (VGEN_FAILURE); 35311991Sheppo } 35321991Sheppo 35331991Sheppo /* SUCCESS - we have agreed on a version */ 35341991Sheppo ldcp->local_hparams.ver_major = vermsg->ver_major; 35351991Sheppo ldcp->local_hparams.ver_minor = vermsg->ver_minor; 35361991Sheppo ldcp->hstate |= VER_ACK_RCVD; 35371991Sheppo 35381991Sheppo DBG2((vnetp, "vgen_handle_version_negotiate:" 35391991Sheppo " VER_ACK_RCVD, id (%lx) ver(%d,%d) \n", 35401991Sheppo ldcp->ldc_id, vermsg->ver_major, vermsg->ver_minor)); 35411991Sheppo 35421991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 35431991Sheppo 35441991Sheppo /* VER_ACK_SENT and VER_ACK_RCVD */ 35451991Sheppo 35461991Sheppo /* local and peer versions match? */ 35471991Sheppo ASSERT((ldcp->local_hparams.ver_major == 35481991Sheppo ldcp->peer_hparams.ver_major) && 35491991Sheppo (ldcp->local_hparams.ver_minor == 35501991Sheppo ldcp->peer_hparams.ver_minor)); 35511991Sheppo 35521991Sheppo /* move to the next phase */ 35531991Sheppo vgen_handshake(vh_nextphase(ldcp)); 35541991Sheppo } 35551991Sheppo break; 35561991Sheppo 35571991Sheppo case VIO_SUBTYPE_NACK: 35581991Sheppo 35591991Sheppo if (ldcp->hphase != VH_PHASE1) { 35601991Sheppo /* This should not happen. */ 35611991Sheppo DWARN((vnetp, 35621991Sheppo "vgen_handle_version_negotiate:" 35631991Sheppo " VER_NACK_RCVD id (%lx) Invalid Phase(%u)\n", 35641991Sheppo ldcp->ldc_id, ldcp->hphase)); 35652793Slm66018 return (VGEN_FAILURE); 35661991Sheppo } 35671991Sheppo 35681991Sheppo DBG2((vnetp, "vgen_handle_version_negotiate:" 35691991Sheppo " VER_NACK_RCVD id(%lx) next ver(%d,%d)\n", 35701991Sheppo ldcp->ldc_id, vermsg->ver_major, vermsg->ver_minor)); 35711991Sheppo 35721991Sheppo /* check if version in NACK is zero */ 35731991Sheppo if (vermsg->ver_major == 0 && vermsg->ver_minor == 0) { 35741991Sheppo /* 35751991Sheppo * Version Negotiation has failed. 35761991Sheppo */ 35771991Sheppo DWARN((vnetp, "vgen_handle_version_negotiate:" 35781991Sheppo " Version Negotiation Failed id (%lx)\n", 35791991Sheppo ldcp->ldc_id)); 35802793Slm66018 return (VGEN_FAILURE); 35811991Sheppo } 35821991Sheppo 35831991Sheppo idx = 0; 35841991Sheppo 35851991Sheppo for (;;) { 35861991Sheppo 35871991Sheppo if (vermsg->ver_major > versions[idx].ver_major) { 35881991Sheppo /* select next lower version */ 35891991Sheppo 35901991Sheppo ldcp->local_hparams.ver_major = 35911991Sheppo versions[idx].ver_major; 35921991Sheppo ldcp->local_hparams.ver_minor = 35931991Sheppo versions[idx].ver_minor; 35941991Sheppo break; 35951991Sheppo } 35961991Sheppo 35971991Sheppo if (vermsg->ver_major == versions[idx].ver_major) { 35981991Sheppo /* major version match */ 35991991Sheppo 36001991Sheppo ldcp->local_hparams.ver_major = 36011991Sheppo versions[idx].ver_major; 36021991Sheppo 36031991Sheppo ldcp->local_hparams.ver_minor = 36041991Sheppo versions[idx].ver_minor; 36051991Sheppo break; 36061991Sheppo } 36071991Sheppo 36081991Sheppo idx++; 36091991Sheppo 36101991Sheppo if (idx == VGEN_NUM_VER) { 36111991Sheppo /* 36121991Sheppo * no version match. 36131991Sheppo * Version Negotiation has failed. 36141991Sheppo */ 36151991Sheppo DWARN((vnetp, "vgen_handle_version_negotiate:" 36161991Sheppo " Version Negotiation Failed id (%lx)\n", 36171991Sheppo ldcp->ldc_id)); 36182793Slm66018 return (VGEN_FAILURE); 36191991Sheppo } 36201991Sheppo 36211991Sheppo } 36221991Sheppo 36232793Slm66018 rv = vgen_send_version_negotiate(ldcp); 36242793Slm66018 if (rv != VGEN_SUCCESS) { 36252793Slm66018 return (rv); 36261991Sheppo } 36271991Sheppo 36281991Sheppo break; 36291991Sheppo } 36302793Slm66018 36311991Sheppo DBG1((vnetp, "vgen_handle_version_negotiate: exit\n")); 36322793Slm66018 return (VGEN_SUCCESS); 36331991Sheppo } 36341991Sheppo 36351991Sheppo /* Check if the attributes are supported */ 36361991Sheppo static int 36371991Sheppo vgen_check_attr_info(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg) 36381991Sheppo { 36391991Sheppo _NOTE(ARGUNUSED(ldcp)) 36401991Sheppo 36411991Sheppo #if 0 36421991Sheppo uint64_t port_macaddr; 36431991Sheppo port_macaddr = vgen_macaddr_strtoul((uint8_t *) 36441991Sheppo &(ldcp->portp->macaddr)); 36451991Sheppo #endif 36461991Sheppo /* 36471991Sheppo * currently, we support these attr values: 36481991Sheppo * mtu of ethernet, addr_type of mac, xfer_mode of 36491991Sheppo * ldc shared memory, ack_freq of 0 (data is acked if 36501991Sheppo * the ack bit is set in the descriptor) and the address should 36511991Sheppo * match the address in the port node. 36521991Sheppo */ 36531991Sheppo if ((msg->mtu != ETHERMAX) || 36541991Sheppo (msg->addr_type != ADDR_TYPE_MAC) || 36551991Sheppo (msg->xfer_mode != VIO_DRING_MODE) || 36561991Sheppo (msg->ack_freq > 64)) { 36571991Sheppo #if 0 36581991Sheppo (msg->addr != port_macaddr)) 36591991Sheppo cmn_err(CE_CONT, "vgen_check_attr_info: msg->addr(%lx), port_macaddr(%lx)\n", 36601991Sheppo msg->addr, port_macaddr); 36611991Sheppo #endif 36621991Sheppo return (VGEN_FAILURE); 36631991Sheppo } 36641991Sheppo 36651991Sheppo return (VGEN_SUCCESS); 36661991Sheppo } 36671991Sheppo 36681991Sheppo /* 36691991Sheppo * Handle an attribute info msg from the peer or an ACK/NACK from the peer 36701991Sheppo * to an attr info msg that we sent. 36711991Sheppo */ 36722793Slm66018 static int 36731991Sheppo vgen_handle_attr_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 36741991Sheppo { 36751991Sheppo vnet_attr_msg_t *attrmsg = (vnet_attr_msg_t *)tagp; 36761991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 36771991Sheppo int ack = 0; 36782793Slm66018 int rv = 0; 36791991Sheppo 36801991Sheppo DBG1((vnetp, "vgen_handle_attr_info: enter\n")); 36811991Sheppo if (ldcp->hphase != VH_PHASE2) { 36821991Sheppo DWARN((vnetp, 36831991Sheppo "vgen_handle_attr_info: Rcvd ATTR_INFO id(%lx)" 36841991Sheppo " subtype (%d), Invalid Phase(%u)\n", ldcp->ldc_id, 36851991Sheppo tagp->vio_subtype, ldcp->hphase)); 36862793Slm66018 return (VGEN_FAILURE); 36871991Sheppo } 36881991Sheppo switch (tagp->vio_subtype) { 36891991Sheppo case VIO_SUBTYPE_INFO: 36901991Sheppo 36911991Sheppo DBG2((vnetp, "vgen_handle_attr_info: ATTR_INFO_RCVD id(%lx)\n", 36921991Sheppo ldcp->ldc_id)); 36931991Sheppo ldcp->hstate |= ATTR_INFO_RCVD; 36941991Sheppo 36951991Sheppo /* save peer's values */ 36961991Sheppo ldcp->peer_hparams.mtu = attrmsg->mtu; 36971991Sheppo ldcp->peer_hparams.addr = attrmsg->addr; 36981991Sheppo ldcp->peer_hparams.addr_type = attrmsg->addr_type; 36991991Sheppo ldcp->peer_hparams.xfer_mode = attrmsg->xfer_mode; 37001991Sheppo ldcp->peer_hparams.ack_freq = attrmsg->ack_freq; 37011991Sheppo 37021991Sheppo if (vgen_check_attr_info(ldcp, attrmsg) == VGEN_FAILURE) { 37031991Sheppo /* unsupported attr, send NACK */ 37041991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 37051991Sheppo } else { 37061991Sheppo ack = 1; 37071991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 37081991Sheppo } 37091991Sheppo tagp->vio_sid = ldcp->local_sid; 37101991Sheppo 37111991Sheppo /* send reply msg back to peer */ 37122793Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*attrmsg), 37132793Slm66018 B_FALSE); 37142793Slm66018 if (rv != VGEN_SUCCESS) { 37152793Slm66018 return (rv); 37161991Sheppo } 37171991Sheppo 37181991Sheppo if (ack) { 37191991Sheppo ldcp->hstate |= ATTR_ACK_SENT; 37201991Sheppo DBG2((vnetp, "vgen_handle_attr_info:" 37211991Sheppo " ATTR_ACK_SENT id(%lx)\n", ldcp->ldc_id)); 37221991Sheppo } else { 37231991Sheppo /* failed */ 37241991Sheppo DWARN((vnetp, "vgen_handle_attr_info:" 37251991Sheppo " ATTR_NACK_SENT id(%lx)\n", ldcp->ldc_id)); 37262793Slm66018 return (VGEN_FAILURE); 37271991Sheppo } 37281991Sheppo 37291991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 37301991Sheppo vgen_handshake(vh_nextphase(ldcp)); 37311991Sheppo } 37321991Sheppo 37331991Sheppo break; 37341991Sheppo 37351991Sheppo case VIO_SUBTYPE_ACK: 37361991Sheppo 37371991Sheppo ldcp->hstate |= ATTR_ACK_RCVD; 37381991Sheppo 37391991Sheppo DBG2((vnetp, "vgen_handle_attr_info: ATTR_ACK_RCVD id(%lx)\n", 37401991Sheppo ldcp->ldc_id)); 37411991Sheppo 37421991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 37431991Sheppo vgen_handshake(vh_nextphase(ldcp)); 37441991Sheppo } 37451991Sheppo break; 37461991Sheppo 37471991Sheppo case VIO_SUBTYPE_NACK: 37481991Sheppo 37491991Sheppo DBG2((vnetp, "vgen_handle_attr_info: ATTR_NACK_RCVD id(%lx)\n", 37501991Sheppo ldcp->ldc_id)); 37512793Slm66018 return (VGEN_FAILURE); 37521991Sheppo } 37531991Sheppo DBG1((vnetp, "vgen_handle_attr_info: exit\n")); 37542793Slm66018 return (VGEN_SUCCESS); 37551991Sheppo } 37561991Sheppo 37571991Sheppo /* Check if the dring info msg is ok */ 37581991Sheppo static int 37591991Sheppo vgen_check_dring_reg(vio_dring_reg_msg_t *msg) 37601991Sheppo { 37611991Sheppo /* check if msg contents are ok */ 37621991Sheppo if ((msg->num_descriptors < 128) || (msg->descriptor_size < 37631991Sheppo sizeof (vnet_public_desc_t))) { 37641991Sheppo return (VGEN_FAILURE); 37651991Sheppo } 37661991Sheppo return (VGEN_SUCCESS); 37671991Sheppo } 37681991Sheppo 37691991Sheppo /* 37701991Sheppo * Handle a descriptor ring register msg from the peer or an ACK/NACK from 37711991Sheppo * the peer to a dring register msg that we sent. 37721991Sheppo */ 37732793Slm66018 static int 37741991Sheppo vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 37751991Sheppo { 37761991Sheppo vio_dring_reg_msg_t *msg = (vio_dring_reg_msg_t *)tagp; 37771991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 37781991Sheppo ldc_mem_cookie_t dcookie; 37791991Sheppo int ack = 0; 37801991Sheppo int rv = 0; 37811991Sheppo 37821991Sheppo DBG1((vnetp, "vgen_handle_dring_reg: enter\n")); 37831991Sheppo if (ldcp->hphase < VH_PHASE2) { 37841991Sheppo /* dring_info can be rcvd in any of the phases after Phase1 */ 37851991Sheppo DWARN((vnetp, 37861991Sheppo "vgen_handle_dring_reg: Rcvd DRING_INFO, id (%lx)" 37871991Sheppo " Subtype (%d), Invalid Phase(%u)\n", ldcp->ldc_id, 37881991Sheppo tagp->vio_subtype, ldcp->hphase)); 37892793Slm66018 return (VGEN_FAILURE); 37901991Sheppo } 37911991Sheppo switch (tagp->vio_subtype) { 37921991Sheppo case VIO_SUBTYPE_INFO: 37931991Sheppo 37941991Sheppo DBG2((vnetp, "vgen_handle_dring_reg: DRING_INFO_RCVD id(%lx)\n", 37951991Sheppo ldcp->ldc_id)); 37961991Sheppo ldcp->hstate |= DRING_INFO_RCVD; 37971991Sheppo bcopy((msg->cookie), &dcookie, sizeof (dcookie)); 37981991Sheppo 37991991Sheppo ASSERT(msg->ncookies == 1); 38001991Sheppo 38011991Sheppo if (vgen_check_dring_reg(msg) == VGEN_SUCCESS) { 38021991Sheppo /* 38031991Sheppo * verified dring info msg to be ok, 38041991Sheppo * now try to map the remote dring. 38051991Sheppo */ 38061991Sheppo rv = vgen_init_rxds(ldcp, msg->num_descriptors, 38071991Sheppo msg->descriptor_size, &dcookie, 38081991Sheppo msg->ncookies); 38091991Sheppo if (rv == DDI_SUCCESS) { 38101991Sheppo /* now we can ack the peer */ 38111991Sheppo ack = 1; 38121991Sheppo } 38131991Sheppo } 38141991Sheppo if (ack == 0) { 38151991Sheppo /* failed, send NACK */ 38161991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 38171991Sheppo } else { 38181991Sheppo if (!(ldcp->peer_hparams.dring_ready)) { 38191991Sheppo 38201991Sheppo /* save peer's dring_info values */ 38211991Sheppo bcopy(&dcookie, 38221991Sheppo &(ldcp->peer_hparams.dring_cookie), 38231991Sheppo sizeof (dcookie)); 38241991Sheppo ldcp->peer_hparams.num_desc = 38251991Sheppo msg->num_descriptors; 38261991Sheppo ldcp->peer_hparams.desc_size = 38271991Sheppo msg->descriptor_size; 38281991Sheppo ldcp->peer_hparams.num_dcookies = 38291991Sheppo msg->ncookies; 38301991Sheppo 38311991Sheppo /* set dring_ident for the peer */ 38321991Sheppo ldcp->peer_hparams.dring_ident = 38331991Sheppo (uint64_t)ldcp->rxdp; 38341991Sheppo /* return the dring_ident in ack msg */ 38351991Sheppo msg->dring_ident = 38361991Sheppo (uint64_t)ldcp->rxdp; 38371991Sheppo 38381991Sheppo ldcp->peer_hparams.dring_ready = B_TRUE; 38391991Sheppo } 38401991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 38411991Sheppo } 38421991Sheppo tagp->vio_sid = ldcp->local_sid; 38431991Sheppo /* send reply msg back to peer */ 38442793Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msg), 38452793Slm66018 B_FALSE); 38462793Slm66018 if (rv != VGEN_SUCCESS) { 38472793Slm66018 return (rv); 38481991Sheppo } 38491991Sheppo 38501991Sheppo if (ack) { 38511991Sheppo ldcp->hstate |= DRING_ACK_SENT; 38521991Sheppo DBG2((vnetp, "vgen_handle_dring_reg: DRING_ACK_SENT" 38531991Sheppo " id (%lx)\n", ldcp->ldc_id)); 38541991Sheppo } else { 38551991Sheppo DWARN((vnetp, "vgen_handle_dring_reg: DRING_NACK_SENT" 38561991Sheppo " id (%lx)\n", ldcp->ldc_id)); 38572793Slm66018 return (VGEN_FAILURE); 38581991Sheppo } 38591991Sheppo 38601991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 38611991Sheppo vgen_handshake(vh_nextphase(ldcp)); 38621991Sheppo } 38631991Sheppo 38641991Sheppo break; 38651991Sheppo 38661991Sheppo case VIO_SUBTYPE_ACK: 38671991Sheppo 38681991Sheppo ldcp->hstate |= DRING_ACK_RCVD; 38691991Sheppo 38701991Sheppo DBG2((vnetp, "vgen_handle_dring_reg: DRING_ACK_RCVD" 38711991Sheppo " id (%lx)\n", ldcp->ldc_id)); 38721991Sheppo 38731991Sheppo if (!(ldcp->local_hparams.dring_ready)) { 38741991Sheppo /* local dring is now ready */ 38751991Sheppo ldcp->local_hparams.dring_ready = B_TRUE; 38761991Sheppo 38771991Sheppo /* save dring_ident acked by peer */ 38781991Sheppo ldcp->local_hparams.dring_ident = 38791991Sheppo msg->dring_ident; 38801991Sheppo } 38811991Sheppo 38821991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 38831991Sheppo vgen_handshake(vh_nextphase(ldcp)); 38841991Sheppo } 38851991Sheppo 38861991Sheppo break; 38871991Sheppo 38881991Sheppo case VIO_SUBTYPE_NACK: 38891991Sheppo 38901991Sheppo DBG2((vnetp, "vgen_handle_dring_reg: DRING_NACK_RCVD" 38911991Sheppo " id (%lx)\n", ldcp->ldc_id)); 38922793Slm66018 return (VGEN_FAILURE); 38931991Sheppo } 38941991Sheppo DBG1((vnetp, "vgen_handle_dring_reg: exit\n")); 38952793Slm66018 return (VGEN_SUCCESS); 38961991Sheppo } 38971991Sheppo 38981991Sheppo /* 38991991Sheppo * Handle a rdx info msg from the peer or an ACK/NACK 39001991Sheppo * from the peer to a rdx info msg that we sent. 39011991Sheppo */ 39022793Slm66018 static int 39031991Sheppo vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 39041991Sheppo { 39051991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 39062793Slm66018 int rv = 0; 39071991Sheppo 39081991Sheppo DBG1((vnetp, "vgen_handle_rdx_info: enter\n")); 39091991Sheppo if (ldcp->hphase != VH_PHASE3) { 39101991Sheppo DWARN((vnetp, 39111991Sheppo "vgen_handle_rdx_info: Rcvd RDX_INFO, id (%lx)" 39121991Sheppo " Subtype (%d), Invalid Phase(%u)\n", ldcp->ldc_id, 39131991Sheppo tagp->vio_subtype, ldcp->hphase)); 39142793Slm66018 return (VGEN_FAILURE); 39151991Sheppo } 39161991Sheppo switch (tagp->vio_subtype) { 39171991Sheppo case VIO_SUBTYPE_INFO: 39181991Sheppo 39191991Sheppo DBG2((vnetp, "vgen_handle_rdx_info: RDX_INFO_RCVD id (%lx)\n", 39201991Sheppo ldcp->ldc_id)); 39211991Sheppo ldcp->hstate |= RDX_INFO_RCVD; 39221991Sheppo 39231991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 39241991Sheppo tagp->vio_sid = ldcp->local_sid; 39251991Sheppo /* send reply msg back to peer */ 39262793Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vio_rdx_msg_t), 39272793Slm66018 B_FALSE); 39282793Slm66018 if (rv != VGEN_SUCCESS) { 39292793Slm66018 return (rv); 39301991Sheppo } 39311991Sheppo 39321991Sheppo ldcp->hstate |= RDX_ACK_SENT; 39331991Sheppo DBG2((vnetp, "vgen_handle_rdx_info: RDX_ACK_SENT id (%lx)\n", 39341991Sheppo ldcp->ldc_id)); 39351991Sheppo 39361991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 39371991Sheppo vgen_handshake(vh_nextphase(ldcp)); 39381991Sheppo } 39391991Sheppo 39401991Sheppo break; 39411991Sheppo 39421991Sheppo case VIO_SUBTYPE_ACK: 39431991Sheppo 39441991Sheppo ldcp->hstate |= RDX_ACK_RCVD; 39451991Sheppo 39461991Sheppo DBG2((vnetp, "vgen_handle_rdx_info: RDX_ACK_RCVD id (%lx)\n", 39471991Sheppo ldcp->ldc_id)); 39481991Sheppo 39491991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 39501991Sheppo vgen_handshake(vh_nextphase(ldcp)); 39511991Sheppo } 39521991Sheppo break; 39531991Sheppo 39541991Sheppo case VIO_SUBTYPE_NACK: 39551991Sheppo 39561991Sheppo DBG2((vnetp, "vgen_handle_rdx_info: RDX_NACK_RCVD id (%lx)\n", 39571991Sheppo ldcp->ldc_id)); 39582793Slm66018 return (VGEN_FAILURE); 39591991Sheppo } 39601991Sheppo DBG1((vnetp, "vgen_handle_rdx_info: exit\n")); 39612793Slm66018 return (VGEN_SUCCESS); 39621991Sheppo } 39631991Sheppo 39641991Sheppo /* Handle ACK/NACK from vsw to a set multicast msg that we sent */ 39652793Slm66018 static int 39661991Sheppo vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 39671991Sheppo { 39681991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 39691991Sheppo vgen_t *vgenp = LDC_TO_VGEN(ldcp); 39701991Sheppo vnet_mcast_msg_t *msgp = (vnet_mcast_msg_t *)tagp; 39711991Sheppo struct ether_addr *addrp; 39721991Sheppo int count; 39731991Sheppo int i; 39741991Sheppo 39751991Sheppo DBG1((vnetp, "vgen_handle_mcast_info: enter\n")); 39761991Sheppo switch (tagp->vio_subtype) { 39771991Sheppo 39781991Sheppo case VIO_SUBTYPE_INFO: 39791991Sheppo 39801991Sheppo /* vnet shouldn't recv set mcast msg, only vsw handles it */ 39811991Sheppo DWARN((vnetp, 39821991Sheppo "vgen_handle_mcast_info: rcvd SET_MCAST_INFO id (%lx)\n", 39831991Sheppo ldcp->ldc_id)); 39841991Sheppo break; 39851991Sheppo 39861991Sheppo case VIO_SUBTYPE_ACK: 39871991Sheppo 39881991Sheppo /* success adding/removing multicast addr */ 39891991Sheppo DBG2((vnetp, 39901991Sheppo "vgen_handle_mcast_info: rcvd SET_MCAST_ACK id (%lx)\n", 39911991Sheppo ldcp->ldc_id)); 39921991Sheppo break; 39931991Sheppo 39941991Sheppo case VIO_SUBTYPE_NACK: 39951991Sheppo 39961991Sheppo DWARN((vnetp, 39971991Sheppo "vgen_handle_mcast_info: rcvd SET_MCAST_NACK id (%lx)\n", 39981991Sheppo ldcp->ldc_id)); 39991991Sheppo if (!(msgp->set)) { 40001991Sheppo /* multicast remove request failed */ 40011991Sheppo break; 40021991Sheppo } 40031991Sheppo 40041991Sheppo /* multicast add request failed */ 40051991Sheppo for (count = 0; count < msgp->count; count++) { 40061991Sheppo addrp = &(msgp->mca[count]); 40071991Sheppo 40081991Sheppo /* delete address from the table */ 40091991Sheppo for (i = 0; i < vgenp->mccount; i++) { 40101991Sheppo if (ether_cmp(addrp, 40111991Sheppo &(vgenp->mctab[i])) == 0) { 40121991Sheppo if (vgenp->mccount > 1) { 40131991Sheppo vgenp->mctab[i] = 40141991Sheppo vgenp->mctab[vgenp->mccount-1]; 40151991Sheppo } 40161991Sheppo vgenp->mccount--; 40171991Sheppo break; 40181991Sheppo } 40191991Sheppo } 40201991Sheppo } 40211991Sheppo break; 40221991Sheppo 40231991Sheppo } 40241991Sheppo DBG1((vnetp, "vgen_handle_mcast_info: exit\n")); 40252793Slm66018 40262793Slm66018 return (VGEN_SUCCESS); 40271991Sheppo } 40281991Sheppo 40291991Sheppo /* handler for control messages received from the peer ldc end-point */ 40302793Slm66018 static int 40311991Sheppo vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 40321991Sheppo { 40331991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 40342793Slm66018 int rv = 0; 40351991Sheppo 40361991Sheppo DBG1((vnetp, "vgen_handle_ctrlmsg: enter\n")); 40371991Sheppo switch (tagp->vio_subtype_env) { 40381991Sheppo 40391991Sheppo case VIO_VER_INFO: 40402793Slm66018 rv = vgen_handle_version_negotiate(ldcp, tagp); 40411991Sheppo break; 40421991Sheppo 40431991Sheppo case VIO_ATTR_INFO: 40442793Slm66018 rv = vgen_handle_attr_info(ldcp, tagp); 40451991Sheppo break; 40461991Sheppo 40471991Sheppo case VIO_DRING_REG: 40482793Slm66018 rv = vgen_handle_dring_reg(ldcp, tagp); 40491991Sheppo break; 40501991Sheppo 40511991Sheppo case VIO_RDX: 40522793Slm66018 rv = vgen_handle_rdx_info(ldcp, tagp); 40531991Sheppo break; 40541991Sheppo 40551991Sheppo case VNET_MCAST_INFO: 40562793Slm66018 rv = vgen_handle_mcast_info(ldcp, tagp); 40571991Sheppo break; 40581991Sheppo 40591991Sheppo } 40602793Slm66018 40611991Sheppo DBG1((vnetp, "vgen_handle_ctrlmsg: exit\n")); 40622793Slm66018 return (rv); 40631991Sheppo } 40641991Sheppo 40651991Sheppo /* handler for data messages received from the peer ldc end-point */ 40662793Slm66018 static int 40671991Sheppo vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, 40681991Sheppo mblk_t **headp, mblk_t **tailp) 40691991Sheppo { 40701991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 40712793Slm66018 int rv = 0; 40721991Sheppo 40731991Sheppo DBG1((vnetp, "vgen_handle_datamsg: enter\n")); 40741991Sheppo 40751991Sheppo if (ldcp->hphase != VH_DONE) 40762793Slm66018 return (rv); 40771991Sheppo switch (tagp->vio_subtype_env) { 40781991Sheppo case VIO_DRING_DATA: 40792793Slm66018 rv = vgen_handle_dring_data(ldcp, tagp, headp, tailp); 40801991Sheppo break; 40811991Sheppo default: 40821991Sheppo break; 40831991Sheppo } 40841991Sheppo 40851991Sheppo DBG1((vnetp, "vgen_handle_datamsg: exit\n")); 40862793Slm66018 return (rv); 40871991Sheppo } 40881991Sheppo 40892793Slm66018 static int 40902336Snarayan vgen_send_dring_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, uint32_t start, 40912336Snarayan int32_t end, uint8_t pstate) 40922336Snarayan { 40932336Snarayan vio_dring_msg_t *msgp = (vio_dring_msg_t *)tagp; 40942336Snarayan void *vnetp = LDC_TO_VNET(ldcp); 40952793Slm66018 int rv = 0; 40962336Snarayan 40972336Snarayan tagp->vio_subtype = VIO_SUBTYPE_ACK; 40982336Snarayan tagp->vio_sid = ldcp->local_sid; 40992336Snarayan msgp->start_idx = start; 41002336Snarayan msgp->end_idx = end; 41012336Snarayan msgp->dring_process_state = pstate; 41022793Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp), B_FALSE); 41032793Slm66018 if (rv != VGEN_SUCCESS) { 41042336Snarayan DWARN((vnetp, "vgen_send_dring_ack: id(%lx) vgen_sendmsg " 41052336Snarayan "failed\n", (ldcp)->ldc_id)); 41062336Snarayan } 41072793Slm66018 return (rv); 41082336Snarayan } 41092336Snarayan 41102793Slm66018 static int 41111991Sheppo vgen_handle_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, 41121991Sheppo mblk_t **headp, mblk_t **tailp) 41131991Sheppo { 41141991Sheppo vio_dring_msg_t *dringmsg; 41151991Sheppo vnet_public_desc_t *rxdp; 41161991Sheppo vnet_public_desc_t *txdp; 41171991Sheppo vio_dring_entry_hdr_t *hdrp; 41181991Sheppo vgen_stats_t *statsp; 41191991Sheppo struct ether_header *ehp; 41201991Sheppo mblk_t *mp = NULL; 41211991Sheppo mblk_t *bp = NULL; 41221991Sheppo mblk_t *bpt = NULL; 41231991Sheppo size_t nbytes; 41241991Sheppo size_t nread; 41251991Sheppo uint64_t off = 0; 41261991Sheppo uint32_t start; 41272336Snarayan int32_t end; 41281991Sheppo uint32_t datalen; 41291991Sheppo uint32_t ncookies; 41302336Snarayan uint32_t ack_start; 41312336Snarayan uint32_t ack_end; 41321991Sheppo uint32_t rxi; 41331991Sheppo uint32_t txi; 41342793Slm66018 int rv = 0; 41351991Sheppo boolean_t rxd_err = B_FALSE; 41362336Snarayan boolean_t set_ack_start = B_FALSE; 41372336Snarayan vgen_private_desc_t *tbufp; 41382336Snarayan uint32_t next_rxi; 41392336Snarayan boolean_t ready_txd = B_FALSE; 41402336Snarayan uint32_t retries = 0; 41411991Sheppo #ifdef VGEN_HANDLE_LOST_PKTS 41421991Sheppo int n; 41431991Sheppo #endif 41441991Sheppo #ifdef VGEN_REXMIT 41451991Sheppo uint64_t seqnum; 41461991Sheppo #endif 41471991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 41482793Slm66018 boolean_t ack_needed = B_FALSE; 41491991Sheppo 41501991Sheppo dringmsg = (vio_dring_msg_t *)tagp; 41511991Sheppo start = dringmsg->start_idx; 41521991Sheppo end = dringmsg->end_idx; 41531991Sheppo statsp = ldcp->statsp; 41541991Sheppo 41551991Sheppo DBG1((vnetp, "vgen_handle_dring_data: enter\n")); 41561991Sheppo switch (tagp->vio_subtype) { 41571991Sheppo 41581991Sheppo case VIO_SUBTYPE_INFO: 41591991Sheppo /* 41601991Sheppo * received a data msg, which contains the start and end 41611991Sheppo * indeces of the descriptors within the rx ring holding data, 41621991Sheppo * the seq_num of data packet corresponding to the start index, 41631991Sheppo * and the dring_ident. 41641991Sheppo * We can now read the contents of each of these descriptors 41651991Sheppo * and gather data from it. 41661991Sheppo */ 41671991Sheppo DBG2((vnetp, 41681991Sheppo "vgen_handle_dring_data: INFO: start(%d), end(%d)\n", 41691991Sheppo start, end)); 41701991Sheppo 41711991Sheppo /* validate rx start and end indeces */ 41722336Snarayan if (!(CHECK_RXI(start, ldcp)) || ((end != -1) && 41732336Snarayan !(CHECK_RXI(end, ldcp)))) { 41741991Sheppo /* drop the message if invalid index */ 41751991Sheppo break; 41761991Sheppo } 41771991Sheppo 41781991Sheppo /* validate dring_ident */ 41791991Sheppo if (dringmsg->dring_ident != ldcp->peer_hparams.dring_ident) { 41801991Sheppo /* invalid dring_ident, drop the msg */ 41811991Sheppo break; 41821991Sheppo } 41831991Sheppo #ifdef DEBUG 41841991Sheppo if (vgen_trigger_rxlost) { 41851991Sheppo /* drop this msg to simulate lost pkts for debugging */ 41861991Sheppo vgen_trigger_rxlost = 0; 41871991Sheppo break; 41881991Sheppo } 41891991Sheppo #endif 41901991Sheppo 41911991Sheppo #ifdef VGEN_HANDLE_LOST_PKTS 41921991Sheppo 41931991Sheppo /* receive start index doesn't match expected index */ 41941991Sheppo if (ldcp->next_rxi != start) { 41951991Sheppo 41961991Sheppo DWARN((vnetp, "vgen_handle_dring_data: id(%lx) " 41971991Sheppo "next_rxi(%d) != start(%d)\n", 41981991Sheppo ldcp->ldc_id, ldcp->next_rxi, start)); 41991991Sheppo 42001991Sheppo /* calculate the number of pkts lost */ 42011991Sheppo if (start >= ldcp->next_rxi) { 42021991Sheppo n = start - ldcp->next_rxi; 42031991Sheppo } else { 42041991Sheppo n = ldcp->num_rxds - (ldcp->next_rxi - start); 42051991Sheppo } 42061991Sheppo 42071991Sheppo /* 42082336Snarayan * sequence number of dring data message 42091991Sheppo * is less than the next sequence number that 42101991Sheppo * is expected: 42111991Sheppo * 42121991Sheppo * drop the message and the corresponding packets. 42131991Sheppo */ 42141991Sheppo if (ldcp->next_rxseq > dringmsg->seq_num) { 42151991Sheppo DWARN((vnetp, "vgen_handle_dring_data: id(%lx) " 42161991Sheppo "dropping pkts, expected rxseq(0x%lx) " 42171991Sheppo "> recvd(0x%lx)\n", 42181991Sheppo ldcp->ldc_id, ldcp->next_rxseq, 42191991Sheppo dringmsg->seq_num)); 42201991Sheppo /* 42211991Sheppo * duplicate/multiple retransmissions from 42221991Sheppo * sender?? drop this msg. 42231991Sheppo */ 42241991Sheppo break; 42251991Sheppo } 42261991Sheppo 42271991Sheppo /* 42282336Snarayan * sequence number of dring data message 42291991Sheppo * is greater than the next expected sequence number 42301991Sheppo * 42311991Sheppo * send a NACK back to the peer to indicate lost 42321991Sheppo * packets. 42331991Sheppo */ 42341991Sheppo if (dringmsg->seq_num > ldcp->next_rxseq) { 42351991Sheppo statsp->rx_lost_pkts += n; 42361991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 42371991Sheppo tagp->vio_sid = ldcp->local_sid; 42381991Sheppo /* indicate the range of lost descriptors */ 42391991Sheppo dringmsg->start_idx = ldcp->next_rxi; 42401991Sheppo rxi = start; 42411991Sheppo DECR_RXI(rxi, ldcp); 42421991Sheppo dringmsg->end_idx = rxi; 42431991Sheppo /* dring ident is left unchanged */ 42442793Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, 42452793Slm66018 sizeof (*dringmsg), B_FALSE); 42462793Slm66018 if (rv != VGEN_SUCCESS) { 42471991Sheppo DWARN((vnetp, 42481991Sheppo "vgen_handle_dring_data: id(%lx) " 42491991Sheppo "vgen_sendmsg failed, " 42501991Sheppo "stype: NACK\n", ldcp->ldc_id)); 42512793Slm66018 goto error_ret; 42521991Sheppo } 42531991Sheppo #ifdef VGEN_REXMIT 42541991Sheppo /* 42551991Sheppo * stop further processing until peer 42562336Snarayan * retransmits with the right index. 42572336Snarayan * update next_rxseq expected. 42581991Sheppo */ 42592336Snarayan ldcp->next_rxseq += 1; 42601991Sheppo break; 42611991Sheppo #else /* VGEN_REXMIT */ 42621991Sheppo /* 42631991Sheppo * treat this range of descrs/pkts as dropped 42641991Sheppo * and set the new expected values for next_rxi 42651991Sheppo * and next_rxseq. continue(below) to process 42661991Sheppo * from the new start index. 42671991Sheppo */ 42681991Sheppo ldcp->next_rxi = start; 42692336Snarayan ldcp->next_rxseq += 1; 42701991Sheppo #endif /* VGEN_REXMIT */ 42711991Sheppo 42721991Sheppo } else if (dringmsg->seq_num == ldcp->next_rxseq) { 42731991Sheppo /* 42742336Snarayan * expected and received seqnums match, but 42751991Sheppo * the descriptor indeces don't? 42761991Sheppo * 42771991Sheppo * restart handshake with peer. 42781991Sheppo */ 42791991Sheppo DWARN((vnetp, 42801991Sheppo "vgen_handle_dring_data: id(%lx) " 42811991Sheppo "next_rxseq(0x%lx) == seq_num(0x%lx)\n", 42821991Sheppo ldcp->ldc_id, ldcp->next_rxseq, 42831991Sheppo dringmsg->seq_num)); 42841991Sheppo 42851991Sheppo } 42861991Sheppo 42871991Sheppo } else { 42881991Sheppo /* expected and start dring indeces match */ 42891991Sheppo 42901991Sheppo if (dringmsg->seq_num != ldcp->next_rxseq) { 42911991Sheppo 42921991Sheppo /* seqnums don't match */ 42931991Sheppo 42941991Sheppo DWARN((vnetp, 42951991Sheppo "vgen_handle_dring_data: id(%lx) " 42961991Sheppo "next_rxseq(0x%lx) != seq_num(0x%lx)\n", 42971991Sheppo ldcp->ldc_id, ldcp->next_rxseq, 42981991Sheppo dringmsg->seq_num)); 42991991Sheppo } 43001991Sheppo } 43011991Sheppo 43021991Sheppo #endif /* VGEN_HANDLE_LOST_PKTS */ 43031991Sheppo 43041991Sheppo /* 43052336Snarayan * start processing the descriptors from the specified 43062336Snarayan * start index, up to the index a descriptor is not ready 43072336Snarayan * to be processed or we process the entire descriptor ring 43082336Snarayan * and wrap around upto the start index. 43091991Sheppo */ 43102336Snarayan 43112336Snarayan /* need to set the start index of descriptors to be ack'd */ 43122336Snarayan set_ack_start = B_TRUE; 43132336Snarayan 43142336Snarayan /* index upto which we have ack'd */ 43152336Snarayan ack_end = start; 43162336Snarayan DECR_RXI(ack_end, ldcp); 43172336Snarayan 43182336Snarayan next_rxi = rxi = start; 43191991Sheppo do { 43202336Snarayan 43212793Slm66018 vgen_recv_retry: rv = ldc_mem_dring_acquire(ldcp->rx_dhandle, rxi, rxi); 43222793Slm66018 if (rv != 0) { 43232336Snarayan DWARN((vnetp, "vgen_handle_dring_data: " 43242793Slm66018 "ldc_mem_dring_acquire() failed" 43252793Slm66018 " id(%lx) rv(%d)\n", ldcp->ldc_id, rv)); 43262336Snarayan statsp->ierrors++; 43272793Slm66018 goto error_ret; 43282336Snarayan } 43291991Sheppo 43301991Sheppo rxdp = &(ldcp->rxdp[rxi]); 43311991Sheppo hdrp = &rxdp->hdr; 43321991Sheppo 43332336Snarayan if (hdrp->dstate != VIO_DESC_READY) { 43342336Snarayan /* 43352336Snarayan * descriptor is not ready. 43362336Snarayan * retry descriptor acquire, stop processing 43372336Snarayan * after max # retries. 43382336Snarayan */ 43392336Snarayan if (retries == vgen_recv_retries) 43402336Snarayan break; 43412336Snarayan retries++; 43422336Snarayan drv_usecwait(vgen_recv_delay); 43432336Snarayan goto vgen_recv_retry; 43442336Snarayan } 43452336Snarayan retries = 0; 43462336Snarayan 43472336Snarayan if (set_ack_start) { 43482336Snarayan /* 43492336Snarayan * initialize the start index of the range 43502336Snarayan * of descriptors to be ack'd. 43512336Snarayan */ 43522336Snarayan ack_start = rxi; 43532336Snarayan set_ack_start = B_FALSE; 43542336Snarayan } 43552336Snarayan 43561991Sheppo datalen = rxdp->nbytes; 43571991Sheppo ncookies = rxdp->ncookies; 43581991Sheppo if ((datalen < ETHERMIN) || 43591991Sheppo (ncookies == 0) || 43602336Snarayan (ncookies > MAX_COOKIES)) { 43611991Sheppo rxd_err = B_TRUE; 43621991Sheppo } else { 43631991Sheppo /* 43642336Snarayan * Try to allocate an mblk from the free pool 43652336Snarayan * of recv mblks for the channel. 43662336Snarayan * If this fails, use allocb(). 43671991Sheppo */ 43682336Snarayan mp = vio_allocb(ldcp->rmp); 43692336Snarayan if (!mp) { 43702336Snarayan /* 43712336Snarayan * The data buffer returned by 43722336Snarayan * allocb(9F) is 8byte aligned. We 43732336Snarayan * allocate extra 8 bytes to ensure 43742336Snarayan * size is multiple of 8 bytes for 43752336Snarayan * ldc_mem_copy(). 43762336Snarayan */ 43772336Snarayan statsp->rx_vio_allocb_fail++; 43782336Snarayan mp = allocb(VNET_IPALIGN + datalen + 8, 43792336Snarayan BPRI_MED); 43802336Snarayan } 43812336Snarayan nbytes = (VNET_IPALIGN + datalen + 7) & ~7; 43821991Sheppo } 43831991Sheppo if ((rxd_err) || (mp == NULL)) { 43841991Sheppo /* 43851991Sheppo * rxd_err or allocb() failure, 43861991Sheppo * drop this packet, get next. 43871991Sheppo */ 43881991Sheppo if (rxd_err) { 43891991Sheppo statsp->ierrors++; 43901991Sheppo rxd_err = B_FALSE; 43911991Sheppo } else { 43921991Sheppo statsp->rx_allocb_fail++; 43931991Sheppo } 43941991Sheppo 43952793Slm66018 ack_needed = hdrp->ack; 43962793Slm66018 43971991Sheppo /* set descriptor done bit */ 43981991Sheppo hdrp->dstate = VIO_DESC_DONE; 43991991Sheppo 44002793Slm66018 rv = ldc_mem_dring_release(ldcp->rx_dhandle, 44012336Snarayan rxi, rxi); 44022793Slm66018 if (rv != 0) { 44032793Slm66018 DWARN((vnetp, "vgen_handle_dring_data: " 44042793Slm66018 "ldc_mem_dring_release err id(%lx)" 44052793Slm66018 " rv(%d)\n", ldcp->ldc_id, rv)); 44062793Slm66018 goto error_ret; 44072793Slm66018 } 44082793Slm66018 44092793Slm66018 if (ack_needed) { 44102793Slm66018 ack_needed = B_FALSE; 44111991Sheppo /* 44122336Snarayan * sender needs ack for this packet, 44132336Snarayan * ack pkts upto this index. 44141991Sheppo */ 44152336Snarayan ack_end = rxi; 44162336Snarayan 44172793Slm66018 rv = vgen_send_dring_ack(ldcp, tagp, 44182336Snarayan ack_start, ack_end, 44192336Snarayan VIO_DP_ACTIVE); 44202793Slm66018 if (rv != VGEN_SUCCESS) { 44212793Slm66018 goto error_ret; 44222793Slm66018 } 44232336Snarayan 44242336Snarayan /* need to set new ack start index */ 44252336Snarayan set_ack_start = B_TRUE; 44261991Sheppo } 44271991Sheppo goto vgen_next_rxi; 44281991Sheppo } 44291991Sheppo 44301991Sheppo nread = nbytes; 44311991Sheppo rv = ldc_mem_copy(ldcp->ldc_handle, 44321991Sheppo (caddr_t)mp->b_rptr, off, &nread, 44331991Sheppo rxdp->memcookie, ncookies, LDC_COPY_IN); 44341991Sheppo 44352793Slm66018 /* if ldc_mem_copy() failed */ 44362793Slm66018 if (rv) { 44372793Slm66018 DWARN((vnetp, 44382793Slm66018 "vgen_handle_dring_data: ldc_mem_copy err " 44392793Slm66018 " id(%lx) rv(%d)\n", ldcp->ldc_id, rv)); 44402793Slm66018 statsp->ierrors++; 44412793Slm66018 freemsg(mp); 44422793Slm66018 goto error_ret; 44432793Slm66018 } 44442793Slm66018 44452793Slm66018 ack_needed = hdrp->ack; 44461991Sheppo hdrp->dstate = VIO_DESC_DONE; 44471991Sheppo 44482793Slm66018 rv = ldc_mem_dring_release(ldcp->rx_dhandle, rxi, rxi); 44492793Slm66018 if (rv != 0) { 44502793Slm66018 DWARN((vnetp, "vgen_handle_dring_data: " 44512793Slm66018 "ldc_mem_dring_release err id(%lx)" 44522793Slm66018 " rv(%d)\n", ldcp->ldc_id, rv)); 44532793Slm66018 goto error_ret; 44542793Slm66018 } 44552336Snarayan 44562336Snarayan mp->b_rptr += VNET_IPALIGN; 44572336Snarayan 44582793Slm66018 if (ack_needed) { 44592793Slm66018 ack_needed = B_FALSE; 44601991Sheppo /* 44612336Snarayan * sender needs ack for this packet, 44622336Snarayan * ack pkts upto this index. 44631991Sheppo */ 44642336Snarayan ack_end = rxi; 44652336Snarayan 44662793Slm66018 rv = vgen_send_dring_ack(ldcp, tagp, 44672336Snarayan ack_start, ack_end, VIO_DP_ACTIVE); 44682793Slm66018 if (rv != VGEN_SUCCESS) { 44692793Slm66018 goto error_ret; 44702793Slm66018 } 44712336Snarayan 44722336Snarayan /* need to set new ack start index */ 44732336Snarayan set_ack_start = B_TRUE; 44741991Sheppo } 44752336Snarayan 44761991Sheppo if (nread != nbytes) { 44771991Sheppo DWARN((vnetp, 44781991Sheppo "vgen_handle_dring_data: id(%lx) " 44791991Sheppo "ldc_mem_copy nread(%lx), nbytes(%lx)\n", 44801991Sheppo ldcp->ldc_id, nread, nbytes)); 44811991Sheppo statsp->ierrors++; 44821991Sheppo freemsg(mp); 44831991Sheppo goto vgen_next_rxi; 44841991Sheppo } 44851991Sheppo 44861991Sheppo /* point to the actual end of data */ 44871991Sheppo mp->b_wptr = mp->b_rptr + datalen; 44881991Sheppo 44891991Sheppo /* update stats */ 44901991Sheppo statsp->ipackets++; 44911991Sheppo statsp->rbytes += datalen; 44921991Sheppo ehp = (struct ether_header *)mp->b_rptr; 44931991Sheppo if (IS_BROADCAST(ehp)) 44941991Sheppo statsp->brdcstrcv++; 44951991Sheppo else if (IS_MULTICAST(ehp)) 44961991Sheppo statsp->multircv++; 44971991Sheppo 44981991Sheppo /* build a chain of received packets */ 44991991Sheppo if (bp == NULL) { 45001991Sheppo /* first pkt */ 45011991Sheppo bp = mp; 45021991Sheppo bpt = bp; 45031991Sheppo bpt->b_next = NULL; 45041991Sheppo } else { 45051991Sheppo mp->b_next = NULL; 45061991Sheppo bpt->b_next = mp; 45071991Sheppo bpt = mp; 45081991Sheppo } 45091991Sheppo 45102336Snarayan 45112336Snarayan vgen_next_rxi: 45122336Snarayan /* update end index of range of descrs to be ack'd */ 45132336Snarayan ack_end = rxi; 45142336Snarayan 45152336Snarayan /* update the next index to be processed */ 45162336Snarayan INCR_RXI(next_rxi, ldcp); 45172336Snarayan if (next_rxi == start) { 45182336Snarayan /* 45192336Snarayan * processed the entire descriptor ring upto 45202336Snarayan * the index at which we started. 45212336Snarayan */ 45221991Sheppo break; 45231991Sheppo } 45242336Snarayan 45252336Snarayan rxi = next_rxi; 45261991Sheppo 45271991Sheppo _NOTE(CONSTCOND) 45281991Sheppo } while (1); 45291991Sheppo 45302336Snarayan /* 45312336Snarayan * send an ack message to peer indicating that we have stopped 45322336Snarayan * processing descriptors. 45332336Snarayan */ 45342336Snarayan if (set_ack_start) { 45352336Snarayan /* 45362336Snarayan * We have ack'd upto some index and we have not 45372336Snarayan * processed any descriptors beyond that index. 45382336Snarayan * Use the last ack'd index as both the start and 45392336Snarayan * end of range of descrs being ack'd. 45402336Snarayan * Note: This results in acking the last index twice 45412336Snarayan * and should be harmless. 45422336Snarayan */ 45432336Snarayan ack_start = ack_end; 45441991Sheppo } 45451991Sheppo 45462793Slm66018 rv = vgen_send_dring_ack(ldcp, tagp, ack_start, ack_end, 45472336Snarayan VIO_DP_STOPPED); 45482793Slm66018 if (rv != VGEN_SUCCESS) { 45492793Slm66018 goto error_ret; 45502793Slm66018 } 45512336Snarayan 45522336Snarayan /* save new recv index and expected seqnum of next dring msg */ 45532336Snarayan ldcp->next_rxi = next_rxi; 45542336Snarayan ldcp->next_rxseq += 1; 45552336Snarayan 45561991Sheppo break; 45571991Sheppo 45581991Sheppo case VIO_SUBTYPE_ACK: 45591991Sheppo /* 45601991Sheppo * received an ack corresponding to a specific descriptor for 45611991Sheppo * which we had set the ACK bit in the descriptor (during 45621991Sheppo * transmit). This enables us to reclaim descriptors. 45631991Sheppo */ 45642336Snarayan 45651991Sheppo DBG2((vnetp, 45661991Sheppo "vgen_handle_dring_data: ACK: start(%d), end(%d)\n", 45671991Sheppo start, end)); 45681991Sheppo 45691991Sheppo /* validate start and end indeces in the tx ack msg */ 45701991Sheppo if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) { 45711991Sheppo /* drop the message if invalid index */ 45721991Sheppo break; 45731991Sheppo } 45741991Sheppo /* validate dring_ident */ 45751991Sheppo if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) { 45761991Sheppo /* invalid dring_ident, drop the msg */ 45771991Sheppo break; 45781991Sheppo } 45791991Sheppo statsp->dring_data_acks++; 45802336Snarayan 45812336Snarayan /* reclaim descriptors that are done */ 45821991Sheppo vgen_reclaim(ldcp); 45832336Snarayan 45842336Snarayan if (dringmsg->dring_process_state != VIO_DP_STOPPED) { 45852336Snarayan /* 45862336Snarayan * receiver continued processing descriptors after 45872336Snarayan * sending us the ack. 45882336Snarayan */ 45892336Snarayan break; 45902336Snarayan } 45912336Snarayan 45922336Snarayan statsp->dring_stopped_acks++; 45932336Snarayan 45942336Snarayan /* receiver stopped processing descriptors */ 45952336Snarayan mutex_enter(&ldcp->txlock); 45962336Snarayan mutex_enter(&ldcp->tclock); 45972336Snarayan 45982336Snarayan /* 45992336Snarayan * determine if there are any pending tx descriptors 46002336Snarayan * ready to be processed by the receiver(peer) and if so, 46012336Snarayan * send a message to the peer to restart receiving. 46022336Snarayan */ 46032336Snarayan ready_txd = B_FALSE; 46042336Snarayan 46052336Snarayan /* 46062336Snarayan * using the end index of the descriptor range for which 46072336Snarayan * we received the ack, check if the next descriptor is 46082336Snarayan * ready. 46092336Snarayan */ 46102336Snarayan txi = end; 46112336Snarayan INCR_TXI(txi, ldcp); 46122336Snarayan tbufp = &ldcp->tbufp[txi]; 46132336Snarayan txdp = tbufp->descp; 46142336Snarayan hdrp = &txdp->hdr; 46152336Snarayan if (hdrp->dstate == VIO_DESC_READY) { 46162336Snarayan ready_txd = B_TRUE; 46172336Snarayan } else { 46182336Snarayan /* 46192336Snarayan * descr next to the end of ack'd descr range is not 46202336Snarayan * ready. 46212336Snarayan * starting from the current reclaim index, check 46222336Snarayan * if any descriptor is ready. 46232336Snarayan */ 46242336Snarayan 46252336Snarayan txi = ldcp->cur_tbufp - ldcp->tbufp; 46262336Snarayan tbufp = &ldcp->tbufp[txi]; 46272336Snarayan 46282336Snarayan while (tbufp != ldcp->next_tbufp) { 46292336Snarayan 46302336Snarayan txdp = tbufp->descp; 46312336Snarayan hdrp = &txdp->hdr; 46322336Snarayan if (hdrp->dstate == VIO_DESC_READY) { 46332336Snarayan break; 46342336Snarayan } 46352336Snarayan 46362336Snarayan INCR_TXI(txi, ldcp); 46372336Snarayan tbufp = &ldcp->tbufp[txi]; 46382336Snarayan 46392336Snarayan } 46402336Snarayan 46412336Snarayan if (tbufp != ldcp->next_tbufp) 46422336Snarayan ready_txd = B_TRUE; 46432336Snarayan } 46442336Snarayan 46452336Snarayan if (ready_txd) { 46462336Snarayan /* 46472336Snarayan * we have tx descriptor(s) ready to be 46482336Snarayan * processed by the receiver. 46492336Snarayan * send a message to the peer with the start index 46502336Snarayan * of ready descriptors. 46512336Snarayan */ 46522336Snarayan rv = vgen_send_dring_data(ldcp, txi, -1); 46532793Slm66018 if (rv != VGEN_SUCCESS) { 46542336Snarayan ldcp->resched_peer = B_TRUE; 46552793Slm66018 mutex_exit(&ldcp->tclock); 46562793Slm66018 mutex_exit(&ldcp->txlock); 46572793Slm66018 goto error_ret; 46582336Snarayan } 46592336Snarayan } else { 46602336Snarayan /* 46612336Snarayan * no ready tx descriptors. set the flag to send a 46622336Snarayan * message to peer when tx descriptors are ready in 46632336Snarayan * transmit routine. 46642336Snarayan */ 46652336Snarayan ldcp->resched_peer = B_TRUE; 46662336Snarayan } 46672336Snarayan 46682336Snarayan mutex_exit(&ldcp->tclock); 46692336Snarayan mutex_exit(&ldcp->txlock); 46702336Snarayan 46711991Sheppo break; 46721991Sheppo 46731991Sheppo case VIO_SUBTYPE_NACK: 46741991Sheppo /* 46751991Sheppo * peer sent a NACK msg to indicate lost packets. 46761991Sheppo * The start and end correspond to the range of descriptors 46771991Sheppo * for which the peer didn't receive a dring data msg and so 46781991Sheppo * didn't receive the corresponding data. 46791991Sheppo */ 46801991Sheppo DWARN((vnetp, 46811991Sheppo "vgen_handle_dring_data: NACK: start(%d), end(%d)\n", 46821991Sheppo start, end)); 46831991Sheppo 46841991Sheppo /* validate start and end indeces in the tx nack msg */ 46851991Sheppo if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) { 46861991Sheppo /* drop the message if invalid index */ 46871991Sheppo break; 46881991Sheppo } 46891991Sheppo /* validate dring_ident */ 46901991Sheppo if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) { 46911991Sheppo /* invalid dring_ident, drop the msg */ 46921991Sheppo break; 46931991Sheppo } 46941991Sheppo mutex_enter(&ldcp->txlock); 46951991Sheppo mutex_enter(&ldcp->tclock); 46961991Sheppo 46971991Sheppo if (ldcp->next_tbufp == ldcp->cur_tbufp) { 46981991Sheppo /* no busy descriptors, bogus nack ? */ 46991991Sheppo mutex_exit(&ldcp->tclock); 47001991Sheppo mutex_exit(&ldcp->txlock); 47011991Sheppo break; 47021991Sheppo } 47031991Sheppo 47041991Sheppo #ifdef VGEN_REXMIT 47051991Sheppo /* send a new dring data msg including the lost descrs */ 47061991Sheppo end = ldcp->next_tbufp - ldcp->tbufp; 47071991Sheppo DECR_TXI(end, ldcp); 47082336Snarayan rv = vgen_send_dring_data(ldcp, start, end); 47091991Sheppo if (rv != 0) { 47101991Sheppo /* 47111991Sheppo * vgen_send_dring_data() error: drop all packets 47121991Sheppo * in this descr range 47131991Sheppo */ 47141991Sheppo DWARN((vnetp, 47151991Sheppo "vgen_handle_dring_data: " 47161991Sheppo "vgen_send_dring_data failed :" 47171991Sheppo "id(%lx) rv(%d)\n", ldcp->ldc_id, rv)); 47181991Sheppo for (txi = start; txi <= end; ) { 47191991Sheppo tbufp = &(ldcp->tbufp[txi]); 47201991Sheppo txdp = tbufp->descp; 47211991Sheppo hdrp = &txdp->hdr; 47221991Sheppo tbufp->flags = VGEN_PRIV_DESC_FREE; 47231991Sheppo hdrp->dstate = VIO_DESC_FREE; 47241991Sheppo hdrp->ack = B_FALSE; 47251991Sheppo statsp->oerrors++; 47261991Sheppo } 47271991Sheppo 47281991Sheppo /* update next pointer */ 47291991Sheppo ldcp->next_tbufp = &(ldcp->tbufp[start]); 47301991Sheppo ldcp->next_txi = start; 47311991Sheppo } 47321991Sheppo DBG2((vnetp, 47331991Sheppo "vgen_handle_dring_data: rexmit: start(%d) end(%d)\n", 47341991Sheppo start, end)); 47351991Sheppo #else /* VGEN_REXMIT */ 47361991Sheppo /* we just mark the descrs as done so they can be reclaimed */ 47371991Sheppo for (txi = start; txi <= end; ) { 47381991Sheppo txdp = &(ldcp->txdp[txi]); 47391991Sheppo hdrp = &txdp->hdr; 47401991Sheppo if (hdrp->dstate == VIO_DESC_READY) 47411991Sheppo hdrp->dstate = VIO_DESC_DONE; 47421991Sheppo INCR_TXI(txi, ldcp); 47431991Sheppo } 47441991Sheppo #endif /* VGEN_REXMIT */ 47451991Sheppo mutex_exit(&ldcp->tclock); 47461991Sheppo mutex_exit(&ldcp->txlock); 47471991Sheppo 47481991Sheppo break; 47491991Sheppo } 47501991Sheppo 47512793Slm66018 error_ret: 47522793Slm66018 47531991Sheppo DBG1((vnetp, "vgen_handle_dring_data: exit\n")); 47541991Sheppo *headp = bp; 47551991Sheppo *tailp = bpt; 47562336Snarayan 47572793Slm66018 return (rv); 47581991Sheppo } 47591991Sheppo 47601991Sheppo static void 47611991Sheppo vgen_reclaim(vgen_ldc_t *ldcp) 47621991Sheppo { 47632336Snarayan mutex_enter(&ldcp->tclock); 47642336Snarayan 47651991Sheppo vgen_reclaim_dring(ldcp); 47661991Sheppo ldcp->reclaim_lbolt = ddi_get_lbolt(); 47672336Snarayan 47681991Sheppo mutex_exit(&ldcp->tclock); 47691991Sheppo } 47701991Sheppo 47711991Sheppo /* 47721991Sheppo * transmit reclaim function. starting from the current reclaim index 47731991Sheppo * look for descriptors marked DONE and reclaim the descriptor and the 47741991Sheppo * corresponding buffers (tbuf). 47751991Sheppo */ 47761991Sheppo static void 47771991Sheppo vgen_reclaim_dring(vgen_ldc_t *ldcp) 47781991Sheppo { 47791991Sheppo vnet_public_desc_t *txdp; 47801991Sheppo vgen_private_desc_t *tbufp; 47811991Sheppo vio_dring_entry_hdr_t *hdrp; 47822336Snarayan vgen_t *vgenp = LDC_TO_VGEN(ldcp); 47831991Sheppo 47841991Sheppo #ifdef DEBUG 47851991Sheppo if (vgen_trigger_txtimeout) 47861991Sheppo return; 47871991Sheppo #endif 47881991Sheppo 47891991Sheppo tbufp = ldcp->cur_tbufp; 47901991Sheppo txdp = tbufp->descp; 47911991Sheppo hdrp = &txdp->hdr; 47921991Sheppo 47931991Sheppo while ((hdrp->dstate == VIO_DESC_DONE) && 47941991Sheppo (tbufp != ldcp->next_tbufp)) { 47951991Sheppo tbufp->flags = VGEN_PRIV_DESC_FREE; 47961991Sheppo hdrp->dstate = VIO_DESC_FREE; 47971991Sheppo hdrp->ack = B_FALSE; 47981991Sheppo 47991991Sheppo tbufp = NEXTTBUF(ldcp, tbufp); 48001991Sheppo txdp = tbufp->descp; 48011991Sheppo hdrp = &txdp->hdr; 48021991Sheppo } 48031991Sheppo 48041991Sheppo ldcp->cur_tbufp = tbufp; 48051991Sheppo 48061991Sheppo /* 48071991Sheppo * Check if mac layer should be notified to restart transmissions 48081991Sheppo */ 48091991Sheppo if (ldcp->need_resched) { 48101991Sheppo ldcp->need_resched = B_FALSE; 48112311Sseb vnet_tx_update(vgenp->vnetp); 48121991Sheppo } 48131991Sheppo } 48141991Sheppo 48151991Sheppo /* return the number of pending transmits for the channel */ 48161991Sheppo static int 48171991Sheppo vgen_num_txpending(vgen_ldc_t *ldcp) 48181991Sheppo { 48191991Sheppo int n; 48201991Sheppo 48211991Sheppo if (ldcp->next_tbufp >= ldcp->cur_tbufp) { 48221991Sheppo n = ldcp->next_tbufp - ldcp->cur_tbufp; 48231991Sheppo } else { 48241991Sheppo /* cur_tbufp > next_tbufp */ 48251991Sheppo n = ldcp->num_txds - (ldcp->cur_tbufp - ldcp->next_tbufp); 48261991Sheppo } 48271991Sheppo 48281991Sheppo return (n); 48291991Sheppo } 48301991Sheppo 48311991Sheppo /* determine if the transmit descriptor ring is full */ 48321991Sheppo static int 48331991Sheppo vgen_tx_dring_full(vgen_ldc_t *ldcp) 48341991Sheppo { 48351991Sheppo vgen_private_desc_t *tbufp; 48361991Sheppo vgen_private_desc_t *ntbufp; 48371991Sheppo 48381991Sheppo tbufp = ldcp->next_tbufp; 48391991Sheppo ntbufp = NEXTTBUF(ldcp, tbufp); 48401991Sheppo if (ntbufp == ldcp->cur_tbufp) { /* out of tbufs/txds */ 48411991Sheppo return (VGEN_SUCCESS); 48421991Sheppo } 48431991Sheppo return (VGEN_FAILURE); 48441991Sheppo } 48451991Sheppo 48461991Sheppo /* determine if timeout condition has occured */ 48471991Sheppo static int 48481991Sheppo vgen_ldc_txtimeout(vgen_ldc_t *ldcp) 48491991Sheppo { 48501991Sheppo if (((ddi_get_lbolt() - ldcp->reclaim_lbolt) > 48511991Sheppo drv_usectohz(vnet_ldcwd_txtimeout * 1000)) && 48521991Sheppo (vnet_ldcwd_txtimeout) && 48531991Sheppo (vgen_tx_dring_full(ldcp) == VGEN_SUCCESS)) { 48541991Sheppo return (VGEN_SUCCESS); 48551991Sheppo } else { 48561991Sheppo return (VGEN_FAILURE); 48571991Sheppo } 48581991Sheppo } 48591991Sheppo 48601991Sheppo /* transmit watchdog timeout handler */ 48611991Sheppo static void 48621991Sheppo vgen_ldc_watchdog(void *arg) 48631991Sheppo { 48641991Sheppo vgen_ldc_t *ldcp; 48652336Snarayan vgen_t *vgenp; 48661991Sheppo void *vnetp; 48671991Sheppo int rv; 48681991Sheppo 48691991Sheppo ldcp = (vgen_ldc_t *)arg; 48702336Snarayan vgenp = LDC_TO_VGEN(ldcp); 48711991Sheppo vnetp = LDC_TO_VNET(ldcp); 48721991Sheppo 48731991Sheppo rv = vgen_ldc_txtimeout(ldcp); 48741991Sheppo if (rv == VGEN_SUCCESS) { 48751991Sheppo DWARN((vnetp, 48761991Sheppo "vgen_ldc_watchdog: transmit timeout ldcid(%lx)\n", 48771991Sheppo ldcp->ldc_id)); 48781991Sheppo #ifdef DEBUG 48791991Sheppo if (vgen_trigger_txtimeout) { 48801991Sheppo /* tx timeout triggered for debugging */ 48811991Sheppo vgen_trigger_txtimeout = 0; 48821991Sheppo } 48831991Sheppo #endif 48841991Sheppo mutex_enter(&ldcp->cblock); 48852793Slm66018 ldcp->need_ldc_reset = B_TRUE; 4886*3653Snarayan vgen_handshake_retry(ldcp); 48871991Sheppo mutex_exit(&ldcp->cblock); 48881991Sheppo if (ldcp->need_resched) { 48891991Sheppo ldcp->need_resched = B_FALSE; 48902336Snarayan vnet_tx_update(vgenp->vnetp); 48911991Sheppo } 48921991Sheppo } 48931991Sheppo 48941991Sheppo ldcp->wd_tid = timeout(vgen_ldc_watchdog, (caddr_t)ldcp, 48951991Sheppo drv_usectohz(vnet_ldcwd_interval * 1000)); 48961991Sheppo } 48971991Sheppo 48981991Sheppo static int 48991991Sheppo vgen_setup_kstats(vgen_ldc_t *ldcp) 49001991Sheppo { 49011991Sheppo vgen_t *vgenp; 49021991Sheppo struct kstat *ksp; 49031991Sheppo vgen_stats_t *statsp; 49041991Sheppo vgen_kstats_t *ldckp; 49051991Sheppo int instance; 49061991Sheppo size_t size; 49071991Sheppo char name[MAXNAMELEN]; 49081991Sheppo 49091991Sheppo vgenp = LDC_TO_VGEN(ldcp); 49101991Sheppo instance = ddi_get_instance(vgenp->vnetdip); 49111991Sheppo (void) sprintf(name, "vnetldc0x%lx", ldcp->ldc_id); 49121991Sheppo statsp = kmem_zalloc(sizeof (vgen_stats_t), KM_SLEEP); 49131991Sheppo if (statsp == NULL) { 49141991Sheppo return (VGEN_FAILURE); 49151991Sheppo } 49161991Sheppo size = sizeof (vgen_kstats_t) / sizeof (kstat_named_t); 49171991Sheppo ksp = kstat_create("vnet", instance, name, "net", KSTAT_TYPE_NAMED, 49181991Sheppo size, 0); 49191991Sheppo if (ksp == NULL) { 49201991Sheppo KMEM_FREE(statsp); 49211991Sheppo return (VGEN_FAILURE); 49221991Sheppo } 49231991Sheppo 49241991Sheppo ldckp = (vgen_kstats_t *)ksp->ks_data; 49251991Sheppo kstat_named_init(&ldckp->ipackets, "ipackets", 49261991Sheppo KSTAT_DATA_ULONG); 49271991Sheppo kstat_named_init(&ldckp->ipackets64, "ipackets64", 49281991Sheppo KSTAT_DATA_ULONGLONG); 49291991Sheppo kstat_named_init(&ldckp->ierrors, "ierrors", 49301991Sheppo KSTAT_DATA_ULONG); 49311991Sheppo kstat_named_init(&ldckp->opackets, "opackets", 49321991Sheppo KSTAT_DATA_ULONG); 49331991Sheppo kstat_named_init(&ldckp->opackets64, "opackets64", 49341991Sheppo KSTAT_DATA_ULONGLONG); 49351991Sheppo kstat_named_init(&ldckp->oerrors, "oerrors", 49361991Sheppo KSTAT_DATA_ULONG); 49371991Sheppo 49381991Sheppo 49391991Sheppo /* MIB II kstat variables */ 49401991Sheppo kstat_named_init(&ldckp->rbytes, "rbytes", 49411991Sheppo KSTAT_DATA_ULONG); 49421991Sheppo kstat_named_init(&ldckp->rbytes64, "rbytes64", 49431991Sheppo KSTAT_DATA_ULONGLONG); 49441991Sheppo kstat_named_init(&ldckp->obytes, "obytes", 49451991Sheppo KSTAT_DATA_ULONG); 49461991Sheppo kstat_named_init(&ldckp->obytes64, "obytes64", 49471991Sheppo KSTAT_DATA_ULONGLONG); 49481991Sheppo kstat_named_init(&ldckp->multircv, "multircv", 49491991Sheppo KSTAT_DATA_ULONG); 49501991Sheppo kstat_named_init(&ldckp->multixmt, "multixmt", 49511991Sheppo KSTAT_DATA_ULONG); 49521991Sheppo kstat_named_init(&ldckp->brdcstrcv, "brdcstrcv", 49531991Sheppo KSTAT_DATA_ULONG); 49541991Sheppo kstat_named_init(&ldckp->brdcstxmt, "brdcstxmt", 49551991Sheppo KSTAT_DATA_ULONG); 49561991Sheppo kstat_named_init(&ldckp->norcvbuf, "norcvbuf", 49571991Sheppo KSTAT_DATA_ULONG); 49581991Sheppo kstat_named_init(&ldckp->noxmtbuf, "noxmtbuf", 49591991Sheppo KSTAT_DATA_ULONG); 49601991Sheppo 49611991Sheppo /* Tx stats */ 49621991Sheppo kstat_named_init(&ldckp->tx_no_desc, "tx_no_desc", 49631991Sheppo KSTAT_DATA_ULONG); 49641991Sheppo 49651991Sheppo /* Rx stats */ 49662336Snarayan kstat_named_init(&ldckp->rx_allocb_fail, "rx_allocb_fail", 49671991Sheppo KSTAT_DATA_ULONG); 49682336Snarayan kstat_named_init(&ldckp->rx_vio_allocb_fail, "rx_vio_allocb_fail", 49691991Sheppo KSTAT_DATA_ULONG); 49701991Sheppo kstat_named_init(&ldckp->rx_lost_pkts, "rx_lost_pkts", 49711991Sheppo KSTAT_DATA_ULONG); 49721991Sheppo 49731991Sheppo /* Interrupt stats */ 49741991Sheppo kstat_named_init(&ldckp->callbacks, "callbacks", 49751991Sheppo KSTAT_DATA_ULONG); 49761991Sheppo kstat_named_init(&ldckp->dring_data_acks, "dring_data_acks", 49771991Sheppo KSTAT_DATA_ULONG); 49782336Snarayan kstat_named_init(&ldckp->dring_stopped_acks, "dring_stopped_acks", 49792336Snarayan KSTAT_DATA_ULONG); 49802336Snarayan kstat_named_init(&ldckp->dring_data_msgs, "dring_data_msgs", 49812336Snarayan KSTAT_DATA_ULONG); 49821991Sheppo 49831991Sheppo ksp->ks_update = vgen_kstat_update; 49841991Sheppo ksp->ks_private = (void *)ldcp; 49851991Sheppo kstat_install(ksp); 49861991Sheppo 49871991Sheppo ldcp->ksp = ksp; 49881991Sheppo ldcp->statsp = statsp; 49891991Sheppo return (VGEN_SUCCESS); 49901991Sheppo } 49911991Sheppo 49921991Sheppo static void 49931991Sheppo vgen_destroy_kstats(vgen_ldc_t *ldcp) 49941991Sheppo { 49951991Sheppo if (ldcp->ksp) 49961991Sheppo kstat_delete(ldcp->ksp); 49971991Sheppo KMEM_FREE(ldcp->statsp); 49981991Sheppo } 49991991Sheppo 50001991Sheppo static int 50011991Sheppo vgen_kstat_update(kstat_t *ksp, int rw) 50021991Sheppo { 50031991Sheppo vgen_ldc_t *ldcp; 50041991Sheppo vgen_stats_t *statsp; 50051991Sheppo vgen_kstats_t *ldckp; 50061991Sheppo 50071991Sheppo ldcp = (vgen_ldc_t *)ksp->ks_private; 50081991Sheppo statsp = ldcp->statsp; 50091991Sheppo ldckp = (vgen_kstats_t *)ksp->ks_data; 50101991Sheppo 50111991Sheppo if (rw == KSTAT_READ) { 50121991Sheppo ldckp->ipackets.value.ul = (uint32_t)statsp->ipackets; 50131991Sheppo ldckp->ipackets64.value.ull = statsp->ipackets; 50141991Sheppo ldckp->ierrors.value.ul = statsp->ierrors; 50151991Sheppo ldckp->opackets.value.ul = (uint32_t)statsp->opackets; 50161991Sheppo ldckp->opackets64.value.ull = statsp->opackets; 50171991Sheppo ldckp->oerrors.value.ul = statsp->oerrors; 50181991Sheppo 50191991Sheppo /* 50201991Sheppo * MIB II kstat variables 50211991Sheppo */ 50221991Sheppo ldckp->rbytes.value.ul = (uint32_t)statsp->rbytes; 50231991Sheppo ldckp->rbytes64.value.ull = statsp->rbytes; 50241991Sheppo ldckp->obytes.value.ul = (uint32_t)statsp->obytes; 50251991Sheppo ldckp->obytes64.value.ull = statsp->obytes; 50261991Sheppo ldckp->multircv.value.ul = statsp->multircv; 50271991Sheppo ldckp->multixmt.value.ul = statsp->multixmt; 50281991Sheppo ldckp->brdcstrcv.value.ul = statsp->brdcstrcv; 50291991Sheppo ldckp->brdcstxmt.value.ul = statsp->brdcstxmt; 50301991Sheppo ldckp->norcvbuf.value.ul = statsp->norcvbuf; 50311991Sheppo ldckp->noxmtbuf.value.ul = statsp->noxmtbuf; 50321991Sheppo 50331991Sheppo ldckp->tx_no_desc.value.ul = statsp->tx_no_desc; 50342336Snarayan 50351991Sheppo ldckp->rx_allocb_fail.value.ul = statsp->rx_allocb_fail; 50362336Snarayan ldckp->rx_vio_allocb_fail.value.ul = statsp->rx_vio_allocb_fail; 50371991Sheppo ldckp->rx_lost_pkts.value.ul = statsp->rx_lost_pkts; 50381991Sheppo 50391991Sheppo ldckp->callbacks.value.ul = statsp->callbacks; 50401991Sheppo ldckp->dring_data_acks.value.ul = statsp->dring_data_acks; 50412336Snarayan ldckp->dring_stopped_acks.value.ul = statsp->dring_stopped_acks; 50422336Snarayan ldckp->dring_data_msgs.value.ul = statsp->dring_data_msgs; 50431991Sheppo } else { 50441991Sheppo statsp->ipackets = ldckp->ipackets64.value.ull; 50451991Sheppo statsp->ierrors = ldckp->ierrors.value.ul; 50461991Sheppo statsp->opackets = ldckp->opackets64.value.ull; 50471991Sheppo statsp->oerrors = ldckp->oerrors.value.ul; 50481991Sheppo 50491991Sheppo /* 50501991Sheppo * MIB II kstat variables 50511991Sheppo */ 50521991Sheppo statsp->rbytes = ldckp->rbytes64.value.ull; 50531991Sheppo statsp->obytes = ldckp->obytes64.value.ull; 50541991Sheppo statsp->multircv = ldckp->multircv.value.ul; 50551991Sheppo statsp->multixmt = ldckp->multixmt.value.ul; 50561991Sheppo statsp->brdcstrcv = ldckp->brdcstrcv.value.ul; 50571991Sheppo statsp->brdcstxmt = ldckp->brdcstxmt.value.ul; 50581991Sheppo statsp->norcvbuf = ldckp->norcvbuf.value.ul; 50591991Sheppo statsp->noxmtbuf = ldckp->noxmtbuf.value.ul; 50601991Sheppo 50611991Sheppo statsp->tx_no_desc = ldckp->tx_no_desc.value.ul; 50622336Snarayan 50631991Sheppo statsp->rx_allocb_fail = ldckp->rx_allocb_fail.value.ul; 50642336Snarayan statsp->rx_vio_allocb_fail = ldckp->rx_vio_allocb_fail.value.ul; 50651991Sheppo statsp->rx_lost_pkts = ldckp->rx_lost_pkts.value.ul; 50661991Sheppo 50671991Sheppo statsp->callbacks = ldckp->callbacks.value.ul; 50681991Sheppo statsp->dring_data_acks = ldckp->dring_data_acks.value.ul; 50692336Snarayan statsp->dring_stopped_acks = ldckp->dring_stopped_acks.value.ul; 50702336Snarayan statsp->dring_data_msgs = ldckp->dring_data_msgs.value.ul; 50711991Sheppo } 50721991Sheppo 50731991Sheppo return (VGEN_SUCCESS); 50741991Sheppo } 50751991Sheppo 50761991Sheppo /* handler for error messages received from the peer ldc end-point */ 50771991Sheppo static void 50781991Sheppo vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 50791991Sheppo { 50801991Sheppo _NOTE(ARGUNUSED(ldcp, tagp)) 50811991Sheppo } 50821991Sheppo 50831991Sheppo /* Check if the session id in the received message is valid */ 50841991Sheppo static int 50851991Sheppo vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 50861991Sheppo { 50871991Sheppo if (tagp->vio_sid != ldcp->peer_sid) { 50881991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 50891991Sheppo DWARN((vnetp, 50901991Sheppo "sid mismatch: expected(%x), rcvd(%x)\n", 50911991Sheppo ldcp->peer_sid, tagp->vio_sid)); 50921991Sheppo return (VGEN_FAILURE); 50931991Sheppo } 50941991Sheppo else 50951991Sheppo return (VGEN_SUCCESS); 50961991Sheppo } 50971991Sheppo 50981991Sheppo /* convert mac address from string to uint64_t */ 50991991Sheppo static uint64_t 51001991Sheppo vgen_macaddr_strtoul(const uint8_t *macaddr) 51011991Sheppo { 51021991Sheppo uint64_t val = 0; 51031991Sheppo int i; 51041991Sheppo 51051991Sheppo for (i = 0; i < ETHERADDRL; i++) { 51061991Sheppo val <<= 8; 51071991Sheppo val |= macaddr[i]; 51081991Sheppo } 51091991Sheppo 51101991Sheppo return (val); 51111991Sheppo } 51121991Sheppo 51131991Sheppo /* convert mac address from uint64_t to string */ 51141991Sheppo static int 51151991Sheppo vgen_macaddr_ultostr(uint64_t val, uint8_t *macaddr) 51161991Sheppo { 51171991Sheppo int i; 51181991Sheppo uint64_t value; 51191991Sheppo 51201991Sheppo value = val; 51211991Sheppo for (i = ETHERADDRL - 1; i >= 0; i--) { 51221991Sheppo macaddr[i] = value & 0xFF; 51231991Sheppo value >>= 8; 51241991Sheppo } 51251991Sheppo return (VGEN_SUCCESS); 51261991Sheppo } 51271991Sheppo 51281991Sheppo static caddr_t 51291991Sheppo vgen_print_ethaddr(uint8_t *a, char *ebuf) 51301991Sheppo { 51311991Sheppo (void) sprintf(ebuf, 51321991Sheppo "%x:%x:%x:%x:%x:%x", a[0], a[1], a[2], a[3], a[4], a[5]); 51331991Sheppo return (ebuf); 51341991Sheppo } 51351991Sheppo 51361991Sheppo /* Handshake watchdog timeout handler */ 51371991Sheppo static void 51381991Sheppo vgen_hwatchdog(void *arg) 51391991Sheppo { 51401991Sheppo vgen_ldc_t *ldcp = (vgen_ldc_t *)arg; 51411991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 51421991Sheppo 51431991Sheppo DWARN((vnetp, 51441991Sheppo "vgen_hwatchdog: handshake timeout ldc(%lx) phase(%x) state(%x)\n", 51451991Sheppo ldcp->ldc_id, ldcp->hphase, ldcp->hstate)); 51461991Sheppo 51471991Sheppo mutex_enter(&ldcp->cblock); 5148*3653Snarayan if (ldcp->cancel_htid) { 5149*3653Snarayan ldcp->cancel_htid = 0; 5150*3653Snarayan mutex_exit(&ldcp->cblock); 5151*3653Snarayan return; 5152*3653Snarayan } 51531991Sheppo ldcp->htid = 0; 51542841Snarayan ldcp->need_ldc_reset = B_TRUE; 51551991Sheppo vgen_handshake_retry(ldcp); 51561991Sheppo mutex_exit(&ldcp->cblock); 51571991Sheppo } 51581991Sheppo 51591991Sheppo static void 51601991Sheppo vgen_print_hparams(vgen_hparams_t *hp) 51611991Sheppo { 51621991Sheppo uint8_t addr[6]; 51631991Sheppo char ea[6]; 51641991Sheppo ldc_mem_cookie_t *dc; 51651991Sheppo 51661991Sheppo cmn_err(CE_CONT, "version_info:\n"); 51671991Sheppo cmn_err(CE_CONT, 51681991Sheppo "\tver_major: %d, ver_minor: %d, dev_class: %d\n", 51691991Sheppo hp->ver_major, hp->ver_minor, hp->dev_class); 51701991Sheppo 51711991Sheppo (void) vgen_macaddr_ultostr(hp->addr, addr); 51721991Sheppo cmn_err(CE_CONT, "attr_info:\n"); 51731991Sheppo cmn_err(CE_CONT, "\tMTU: %lx, addr: %s\n", hp->mtu, 51741991Sheppo vgen_print_ethaddr(addr, ea)); 51751991Sheppo cmn_err(CE_CONT, 51761991Sheppo "\taddr_type: %x, xfer_mode: %x, ack_freq: %x\n", 51771991Sheppo hp->addr_type, hp->xfer_mode, hp->ack_freq); 51781991Sheppo 51791991Sheppo dc = &hp->dring_cookie; 51801991Sheppo cmn_err(CE_CONT, "dring_info:\n"); 51811991Sheppo cmn_err(CE_CONT, 51821991Sheppo "\tlength: %d, dsize: %d\n", hp->num_desc, hp->desc_size); 51831991Sheppo cmn_err(CE_CONT, 51841991Sheppo "\tldc_addr: 0x%lx, ldc_size: %ld\n", 51851991Sheppo dc->addr, dc->size); 51861991Sheppo cmn_err(CE_CONT, "\tdring_ident: 0x%lx\n", hp->dring_ident); 51871991Sheppo } 51881991Sheppo 51891991Sheppo static void 51901991Sheppo vgen_print_ldcinfo(vgen_ldc_t *ldcp) 51911991Sheppo { 51921991Sheppo vgen_hparams_t *hp; 51931991Sheppo 51941991Sheppo cmn_err(CE_CONT, "Channel Information:\n"); 51951991Sheppo cmn_err(CE_CONT, 51961991Sheppo "\tldc_id: 0x%lx, ldc_status: 0x%x\n", 51971991Sheppo ldcp->ldc_id, ldcp->ldc_status); 51981991Sheppo cmn_err(CE_CONT, 51991991Sheppo "\tlocal_sid: 0x%x, peer_sid: 0x%x\n", 52001991Sheppo ldcp->local_sid, ldcp->peer_sid); 52011991Sheppo cmn_err(CE_CONT, 52021991Sheppo "\thphase: 0x%x, hstate: 0x%x\n", 52031991Sheppo ldcp->hphase, ldcp->hstate); 52041991Sheppo 52051991Sheppo cmn_err(CE_CONT, "Local handshake params:\n"); 52061991Sheppo hp = &ldcp->local_hparams; 52071991Sheppo vgen_print_hparams(hp); 52081991Sheppo 52091991Sheppo cmn_err(CE_CONT, "Peer handshake params:\n"); 52101991Sheppo hp = &ldcp->peer_hparams; 52111991Sheppo vgen_print_hparams(hp); 52121991Sheppo } 5213