11991Sheppo /* 21991Sheppo * CDDL HEADER START 31991Sheppo * 41991Sheppo * The contents of this file are subject to the terms of the 51991Sheppo * Common Development and Distribution License (the "License"). 61991Sheppo * You may not use this file except in compliance with the License. 71991Sheppo * 81991Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91991Sheppo * or http://www.opensolaris.org/os/licensing. 101991Sheppo * See the License for the specific language governing permissions 111991Sheppo * and limitations under the License. 121991Sheppo * 131991Sheppo * When distributing Covered Code, include this CDDL HEADER in each 141991Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151991Sheppo * If applicable, add the following below this CDDL HEADER, with the 161991Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 171991Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 181991Sheppo * 191991Sheppo * CDDL HEADER END 201991Sheppo */ 211991Sheppo 221991Sheppo /* 231991Sheppo * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 241991Sheppo * Use is subject to license terms. 251991Sheppo */ 261991Sheppo 271991Sheppo #pragma ident "%Z%%M% %I% %E% SMI" 281991Sheppo 291991Sheppo #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> 53*2336Snarayan #include <sys/vnet_mailbox.h> 54*2336Snarayan #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); 68*2336Snarayan 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); 821991Sheppo void vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg); 831991Sheppo void vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg); 841991Sheppo void vnet_del_def_rte(void *arg); 852311Sseb void vnet_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp); 862311Sseb void vnet_tx_update(void *arg); 871991Sheppo 881991Sheppo /* vgen internal functions */ 891991Sheppo static void vgen_detach_ports(vgen_t *vgenp); 901991Sheppo static void vgen_port_detach(vgen_port_t *portp); 911991Sheppo static void vgen_port_list_insert(vgen_port_t *portp); 921991Sheppo static void vgen_port_list_remove(vgen_port_t *portp); 931991Sheppo static vgen_port_t *vgen_port_lookup(vgen_portlist_t *plistp, 941991Sheppo int port_num); 951991Sheppo static int vgen_mdeg_reg(vgen_t *vgenp); 961991Sheppo static void vgen_mdeg_unreg(vgen_t *vgenp); 971991Sheppo static int vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp); 981991Sheppo static int vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex); 991991Sheppo static int vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex); 1001991Sheppo static int vgen_port_attach_mdeg(vgen_t *vgenp, int port_num, uint64_t *ldcids, 1011991Sheppo int num_ids, struct ether_addr *macaddr, boolean_t vsw_port); 1021991Sheppo static void vgen_port_detach_mdeg(vgen_port_t *portp); 1031991Sheppo static int vgen_update_port(vgen_t *vgenp, md_t *curr_mdp, 1041991Sheppo mde_cookie_t curr_mdex, md_t *prev_mdp, mde_cookie_t prev_mdex); 1052311Sseb static uint64_t vgen_port_stat(vgen_port_t *portp, uint_t stat); 1061991Sheppo 1071991Sheppo static int vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id); 1081991Sheppo static void vgen_ldc_detach(vgen_ldc_t *ldcp); 1091991Sheppo static int vgen_alloc_tx_ring(vgen_ldc_t *ldcp); 1101991Sheppo static void vgen_free_tx_ring(vgen_ldc_t *ldcp); 1111991Sheppo static void vgen_init_ports(vgen_t *vgenp); 1121991Sheppo static void vgen_port_init(vgen_port_t *portp); 1131991Sheppo static void vgen_uninit_ports(vgen_t *vgenp); 1141991Sheppo static void vgen_port_uninit(vgen_port_t *portp); 1151991Sheppo static void vgen_init_ldcs(vgen_port_t *portp); 1161991Sheppo static void vgen_uninit_ldcs(vgen_port_t *portp); 1171991Sheppo static int vgen_ldc_init(vgen_ldc_t *ldcp); 1181991Sheppo static void vgen_ldc_uninit(vgen_ldc_t *ldcp); 1191991Sheppo static int vgen_init_tbufs(vgen_ldc_t *ldcp); 1201991Sheppo static void vgen_uninit_tbufs(vgen_ldc_t *ldcp); 1211991Sheppo static void vgen_clobber_tbufs(vgen_ldc_t *ldcp); 1221991Sheppo static void vgen_clobber_rxds(vgen_ldc_t *ldcp); 1232311Sseb static uint64_t vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat); 1241991Sheppo static uint_t vgen_ldc_cb(uint64_t event, caddr_t arg); 1251991Sheppo static int vgen_portsend(vgen_port_t *portp, mblk_t *mp); 1261991Sheppo static int vgen_ldcsend(vgen_ldc_t *ldcp, mblk_t *mp); 1271991Sheppo static void vgen_reclaim(vgen_ldc_t *ldcp); 1281991Sheppo static void vgen_reclaim_dring(vgen_ldc_t *ldcp); 1291991Sheppo static int vgen_num_txpending(vgen_ldc_t *ldcp); 1301991Sheppo static int vgen_tx_dring_full(vgen_ldc_t *ldcp); 1311991Sheppo static int vgen_ldc_txtimeout(vgen_ldc_t *ldcp); 1321991Sheppo static void vgen_ldc_watchdog(void *arg); 1331991Sheppo static int vgen_setup_kstats(vgen_ldc_t *ldcp); 1341991Sheppo static void vgen_destroy_kstats(vgen_ldc_t *ldcp); 1351991Sheppo static int vgen_kstat_update(kstat_t *ksp, int rw); 1361991Sheppo 1371991Sheppo /* vgen handshake functions */ 1381991Sheppo static vgen_ldc_t *vh_nextphase(vgen_ldc_t *ldcp); 1391991Sheppo static int vgen_supported_version(vgen_ldc_t *ldcp, uint16_t ver_major, 1401991Sheppo uint16_t ver_minor); 1411991Sheppo static int vgen_next_version(vgen_ldc_t *ldcp, vgen_ver_t *verp); 1421991Sheppo static int vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg, size_t msglen, 1431991Sheppo boolean_t caller_holds_lock); 1441991Sheppo static int vgen_send_version_negotiate(vgen_ldc_t *ldcp); 1451991Sheppo static int vgen_send_attr_info(vgen_ldc_t *ldcp); 1461991Sheppo static int vgen_send_dring_reg(vgen_ldc_t *ldcp); 1471991Sheppo static int vgen_send_rdx_info(vgen_ldc_t *ldcp); 148*2336Snarayan static int vgen_send_dring_data(vgen_ldc_t *ldcp, uint32_t start, int32_t end); 1491991Sheppo static int vgen_send_mcast_info(vgen_ldc_t *ldcp); 1501991Sheppo static int vgen_handshake_phase2(vgen_ldc_t *ldcp); 1511991Sheppo static void vgen_handshake_reset(vgen_ldc_t *ldcp); 1521991Sheppo static void vgen_reset_hphase(vgen_ldc_t *ldcp); 1531991Sheppo static void vgen_handshake(vgen_ldc_t *ldcp); 1541991Sheppo static int vgen_handshake_done(vgen_ldc_t *ldcp); 1551991Sheppo static void vgen_handshake_retry(vgen_ldc_t *ldcp); 1561991Sheppo static void vgen_handle_version_negotiate(vgen_ldc_t *ldcp, 1571991Sheppo vio_msg_tag_t *tagp); 1581991Sheppo static void vgen_handle_attr_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1591991Sheppo static void vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1601991Sheppo static void vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1611991Sheppo static void vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1621991Sheppo static void vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1631991Sheppo static void vgen_handle_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, 1641991Sheppo mblk_t **headp, mblk_t **tailp); 165*2336Snarayan static void vgen_send_dring_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, 166*2336Snarayan uint32_t start, int32_t end, uint8_t pstate); 1671991Sheppo static void vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, 1681991Sheppo mblk_t **headp, mblk_t **tailp); 1691991Sheppo static void vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1701991Sheppo static int vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1711991Sheppo static uint64_t vgen_macaddr_strtoul(const uint8_t *macaddr); 1721991Sheppo static int vgen_macaddr_ultostr(uint64_t value, uint8_t *macaddr); 1731991Sheppo static caddr_t vgen_print_ethaddr(uint8_t *a, char *ebuf); 1741991Sheppo static void vgen_hwatchdog(void *arg); 1751991Sheppo static void vgen_print_attr_info(vgen_ldc_t *ldcp, int endpoint); 1761991Sheppo static void vgen_print_hparams(vgen_hparams_t *hp); 1771991Sheppo static void vgen_print_ldcinfo(vgen_ldc_t *ldcp); 1781991Sheppo 1791991Sheppo /* 1801991Sheppo * The handshake process consists of 5 phases defined below, with VH_PHASE0 1811991Sheppo * being the pre-handshake phase and VH_DONE is the phase to indicate 1821991Sheppo * successful completion of all phases. 1831991Sheppo * Each phase may have one to several handshake states which are required 1841991Sheppo * to complete successfully to move to the next phase. 1851991Sheppo * Refer to the functions vgen_handshake() and vgen_handshake_done() for 1861991Sheppo * more details. 1871991Sheppo */ 1881991Sheppo /* handshake phases */ 1891991Sheppo enum { VH_PHASE0, VH_PHASE1, VH_PHASE2, VH_PHASE3, VH_DONE = 0x80 }; 1901991Sheppo 1911991Sheppo /* handshake states */ 1921991Sheppo enum { 1931991Sheppo 1941991Sheppo VER_INFO_SENT = 0x1, 1951991Sheppo VER_ACK_RCVD = 0x2, 1961991Sheppo VER_INFO_RCVD = 0x4, 1971991Sheppo VER_ACK_SENT = 0x8, 1981991Sheppo VER_NEGOTIATED = (VER_ACK_RCVD | VER_ACK_SENT), 1991991Sheppo 2001991Sheppo ATTR_INFO_SENT = 0x10, 2011991Sheppo ATTR_ACK_RCVD = 0x20, 2021991Sheppo ATTR_INFO_RCVD = 0x40, 2031991Sheppo ATTR_ACK_SENT = 0x80, 2041991Sheppo ATTR_INFO_EXCHANGED = (ATTR_ACK_RCVD | ATTR_ACK_SENT), 2051991Sheppo 2061991Sheppo DRING_INFO_SENT = 0x100, 2071991Sheppo DRING_ACK_RCVD = 0x200, 2081991Sheppo DRING_INFO_RCVD = 0x400, 2091991Sheppo DRING_ACK_SENT = 0x800, 2101991Sheppo DRING_INFO_EXCHANGED = (DRING_ACK_RCVD | DRING_ACK_SENT), 2111991Sheppo 2121991Sheppo RDX_INFO_SENT = 0x1000, 2131991Sheppo RDX_ACK_RCVD = 0x2000, 2141991Sheppo RDX_INFO_RCVD = 0x4000, 2151991Sheppo RDX_ACK_SENT = 0x8000, 2161991Sheppo RDX_EXCHANGED = (RDX_ACK_RCVD | RDX_ACK_SENT) 2171991Sheppo 2181991Sheppo }; 2191991Sheppo 2201991Sheppo #define LDC_LOCK(ldcp) \ 2211991Sheppo mutex_enter(&((ldcp)->cblock));\ 2221991Sheppo mutex_enter(&((ldcp)->txlock));\ 2231991Sheppo mutex_enter(&((ldcp)->tclock)); 2241991Sheppo #define LDC_UNLOCK(ldcp) \ 2251991Sheppo mutex_exit(&((ldcp)->tclock));\ 2261991Sheppo mutex_exit(&((ldcp)->txlock));\ 2271991Sheppo mutex_exit(&((ldcp)->cblock)); 2281991Sheppo 2291991Sheppo static struct ether_addr etherbroadcastaddr = { 2301991Sheppo 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 2311991Sheppo }; 2321991Sheppo /* 2331991Sheppo * MIB II broadcast/multicast packets 2341991Sheppo */ 2351991Sheppo #define IS_BROADCAST(ehp) \ 2361991Sheppo (ether_cmp(&ehp->ether_dhost, ðerbroadcastaddr) == 0) 2371991Sheppo #define IS_MULTICAST(ehp) \ 2381991Sheppo ((ehp->ether_dhost.ether_addr_octet[0] & 01) == 1) 2391991Sheppo 2401991Sheppo /* 2411991Sheppo * Property names 2421991Sheppo */ 2431991Sheppo static char macaddr_propname[] = "mac-address"; 2441991Sheppo static char rmacaddr_propname[] = "remote-mac-address"; 2451991Sheppo static char channel_propname[] = "channel-endpoint"; 2461991Sheppo static char reg_propname[] = "reg"; 2471991Sheppo static char port_propname[] = "port"; 2481991Sheppo static char swport_propname[] = "switch-port"; 2491991Sheppo static char id_propname[] = "id"; 2501991Sheppo 2511991Sheppo /* versions supported - in decreasing order */ 2521991Sheppo static vgen_ver_t vgen_versions[VGEN_NUM_VER] = { {1, 0} }; 2531991Sheppo 2541991Sheppo /* Tunables */ 2551991Sheppo uint32_t vgen_hwd_interval = 1000; /* handshake watchdog freq in msec */ 2561991Sheppo uint32_t vgen_max_hretries = 1; /* max # of handshake retries */ 2571991Sheppo uint32_t vgen_ldcwr_retries = 10; /* max # of ldc_write() retries */ 2582109Slm66018 uint32_t vgen_ldcup_retries = 5; /* max # of ldc_up() retries */ 259*2336Snarayan uint32_t vgen_recv_delay = 1; /* delay when rx descr not ready */ 260*2336Snarayan uint32_t vgen_recv_retries = 10; /* retry when rx descr not ready */ 2611991Sheppo 2621991Sheppo #ifdef DEBUG 2631991Sheppo /* flags to simulate error conditions for debugging */ 2641991Sheppo int vgen_trigger_txtimeout = 0; 2651991Sheppo int vgen_trigger_rxlost = 0; 2661991Sheppo #endif 2671991Sheppo 2681991Sheppo /* MD update matching structure */ 2691991Sheppo static md_prop_match_t vport_prop_match[] = { 2701991Sheppo { MDET_PROP_VAL, "id" }, 2711991Sheppo { MDET_LIST_END, NULL } 2721991Sheppo }; 2731991Sheppo 2741991Sheppo static mdeg_node_match_t vport_match = { "virtual-device-port", 2751991Sheppo vport_prop_match }; 2761991Sheppo 2771991Sheppo /* template for matching a particular vnet instance */ 2781991Sheppo static mdeg_prop_spec_t vgen_prop_template[] = { 2791991Sheppo { MDET_PROP_STR, "name", "network" }, 2801991Sheppo { MDET_PROP_VAL, "cfg-handle", NULL }, 2811991Sheppo { MDET_LIST_END, NULL, NULL } 2821991Sheppo }; 2831991Sheppo 2841991Sheppo #define VGEN_SET_MDEG_PROP_INST(specp, val) (specp)[1].ps_val = (val) 2851991Sheppo 2861991Sheppo static int vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp); 2871991Sheppo 2882311Sseb static mac_callbacks_t vgen_m_callbacks = { 2892311Sseb 0, 2902311Sseb vgen_stat, 2912311Sseb vgen_start, 2922311Sseb vgen_stop, 2932311Sseb vgen_promisc, 2942311Sseb vgen_multicst, 2952311Sseb vgen_unicst, 2962311Sseb vgen_tx, 2972311Sseb NULL, 2982311Sseb NULL, 2992311Sseb NULL 3002311Sseb }; 3012311Sseb 3021991Sheppo /* externs */ 3031991Sheppo extern uint32_t vnet_ntxds; 3041991Sheppo extern uint32_t vnet_reclaim_lowat; 3051991Sheppo extern uint32_t vnet_reclaim_hiwat; 3061991Sheppo extern uint32_t vnet_ldcwd_interval; 3071991Sheppo extern uint32_t vnet_ldcwd_txtimeout; 3081991Sheppo extern uint32_t vnet_ldc_qlen; 309*2336Snarayan extern uint32_t vnet_nrbufs; 3101991Sheppo extern int _vnet_dbglevel; 3111991Sheppo extern void _vnetdebug_printf(void *vnetp, const char *fmt, ...); 3121991Sheppo 3131991Sheppo #ifdef DEBUG 3141991Sheppo 3151991Sheppo /* 3161991Sheppo * XXX: definitions below need to be in sync with those in vnet.c 3171991Sheppo */ 3181991Sheppo 3191991Sheppo /* 3201991Sheppo * debug levels: 3211991Sheppo * DBG_LEVEL1: Function entry/exit tracing 3221991Sheppo * DBG_LEVEL2: Info messages 3231991Sheppo * DBG_LEVEL3: Warning messages 3241991Sheppo * DBG_LEVEL4: Error messages 3251991Sheppo */ 3261991Sheppo 3271991Sheppo enum { DBG_LEVEL1 = 0x01, DBG_LEVEL2 = 0x02, DBG_LEVEL3 = 0x04, 3281991Sheppo DBG_LEVEL4 = 0x08 }; 3291991Sheppo 3301991Sheppo #define DBG1(_s) do { \ 3311991Sheppo if ((_vnet_dbglevel & DBG_LEVEL1) != 0) { \ 3321991Sheppo _vnetdebug_printf _s; \ 3331991Sheppo } \ 3341991Sheppo _NOTE(CONSTCOND) } while (0) 3351991Sheppo 3361991Sheppo #define DBG2(_s) do { \ 3371991Sheppo if ((_vnet_dbglevel & DBG_LEVEL2) != 0) { \ 3381991Sheppo _vnetdebug_printf _s; \ 3391991Sheppo } \ 3401991Sheppo _NOTE(CONSTCOND) } while (0) 3411991Sheppo 3421991Sheppo #define DWARN(_s) do { \ 3431991Sheppo if ((_vnet_dbglevel & DBG_LEVEL3) != 0) { \ 3441991Sheppo _vnetdebug_printf _s; \ 3451991Sheppo } \ 3461991Sheppo _NOTE(CONSTCOND) } while (0) 3471991Sheppo 3481991Sheppo #define DERR(_s) do { \ 3491991Sheppo if ((_vnet_dbglevel & DBG_LEVEL4) != 0) { \ 3501991Sheppo _vnetdebug_printf _s; \ 3511991Sheppo } \ 3521991Sheppo _NOTE(CONSTCOND) } while (0) 3531991Sheppo 3541991Sheppo #else 3551991Sheppo 3561991Sheppo #define DBG1(_s) if (0) _vnetdebug_printf _s 3571991Sheppo #define DBG2(_s) if (0) _vnetdebug_printf _s 3581991Sheppo #define DWARN(_s) if (0) _vnetdebug_printf _s 3591991Sheppo #define DERR(_s) if (0) _vnetdebug_printf _s 3601991Sheppo 3611991Sheppo #endif 3621991Sheppo 3631991Sheppo #ifdef DEBUG 3641991Sheppo 3651991Sheppo /* simulate handshake error conditions for debug */ 3661991Sheppo uint32_t vgen_hdbg; 3671991Sheppo #define HDBG_VERSION 0x1 3681991Sheppo #define HDBG_TIMEOUT 0x2 3691991Sheppo #define HDBG_BAD_SID 0x4 3701991Sheppo #define HDBG_OUT_STATE 0x8 3711991Sheppo 3721991Sheppo #endif 3731991Sheppo 374*2336Snarayan 3751991Sheppo 3761991Sheppo /* 3771991Sheppo * vgen_init() is called by an instance of vnet driver to initialize the 3781991Sheppo * corresponding generic proxy transport layer. The arguments passed by vnet 3791991Sheppo * are - an opaque pointer to the vnet instance, pointers to dev_info_t and 3802311Sseb * the mac address of the vnet device, and a pointer to mac_register_t of 3812311Sseb * the generic transport is returned in the last argument. 3821991Sheppo */ 3831991Sheppo int 3842311Sseb vgen_init(void *vnetp, dev_info_t *vnetdip, const uint8_t *macaddr, 3852311Sseb mac_register_t **vgenmacp) 3861991Sheppo { 3871991Sheppo vgen_t *vgenp; 3882311Sseb mac_register_t *macp; 3891991Sheppo int instance; 3901991Sheppo 3912311Sseb if ((vnetp == NULL) || (vnetdip == NULL)) 3921991Sheppo return (DDI_FAILURE); 3931991Sheppo 3941991Sheppo instance = ddi_get_instance(vnetdip); 3951991Sheppo 3961991Sheppo DBG1((vnetp, "vgen_init: enter vnet_instance(%d)\n", instance)); 3971991Sheppo 3981991Sheppo vgenp = kmem_zalloc(sizeof (vgen_t), KM_SLEEP); 3991991Sheppo 4001991Sheppo vgenp->vnetp = vnetp; 4011991Sheppo vgenp->vnetdip = vnetdip; 4021991Sheppo bcopy(macaddr, &(vgenp->macaddr), ETHERADDRL); 4031991Sheppo 4042311Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 4052311Sseb KMEM_FREE(vgenp); 4062311Sseb return (DDI_FAILURE); 4072311Sseb } 4082311Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 4092311Sseb macp->m_driver = vgenp; 4102311Sseb macp->m_dip = vnetdip; 4112311Sseb macp->m_src_addr = (uint8_t *)&(vgenp->macaddr); 4122311Sseb macp->m_callbacks = &vgen_m_callbacks; 4132311Sseb macp->m_min_sdu = 0; 4142311Sseb macp->m_max_sdu = ETHERMTU; 4152311Sseb vgenp->macp = macp; 4162311Sseb 4171991Sheppo /* allocate multicast table */ 4181991Sheppo vgenp->mctab = kmem_zalloc(VGEN_INIT_MCTAB_SIZE * 4191991Sheppo sizeof (struct ether_addr), KM_SLEEP); 4201991Sheppo vgenp->mccount = 0; 4211991Sheppo vgenp->mcsize = VGEN_INIT_MCTAB_SIZE; 4221991Sheppo 4231991Sheppo mutex_init(&vgenp->lock, NULL, MUTEX_DRIVER, NULL); 4241991Sheppo 4251991Sheppo /* register with MD event generator */ 4261991Sheppo if (vgen_mdeg_reg(vgenp) != DDI_SUCCESS) { 4271991Sheppo mutex_destroy(&vgenp->lock); 4281991Sheppo kmem_free(vgenp->mctab, VGEN_INIT_MCTAB_SIZE * 4291991Sheppo sizeof (struct ether_addr)); 4302311Sseb mac_free(vgenp->macp); 4311991Sheppo KMEM_FREE(vgenp); 4321991Sheppo return (DDI_FAILURE); 4331991Sheppo } 4341991Sheppo 4352311Sseb /* register macp of this vgen_t with vnet */ 4362311Sseb *vgenmacp = vgenp->macp; 4371991Sheppo 4381991Sheppo DBG1((vnetp, "vgen_init: exit vnet_instance(%d)\n", instance)); 4391991Sheppo return (DDI_SUCCESS); 4401991Sheppo } 4411991Sheppo 4421991Sheppo /* 4431991Sheppo * Called by vnet to undo the initializations done by vgen_init(). 4441991Sheppo * The handle provided by generic transport during vgen_init() is the argument. 4451991Sheppo */ 446*2336Snarayan int 4471991Sheppo vgen_uninit(void *arg) 4481991Sheppo { 4491991Sheppo vgen_t *vgenp = (vgen_t *)arg; 4501991Sheppo void *vnetp; 4511991Sheppo int instance; 452*2336Snarayan vio_mblk_pool_t *rp, *nrp; 453*2336Snarayan 454*2336Snarayan if (vgenp == NULL) { 455*2336Snarayan return (DDI_FAILURE); 456*2336Snarayan } 4571991Sheppo 4581991Sheppo instance = ddi_get_instance(vgenp->vnetdip); 4591991Sheppo vnetp = vgenp->vnetp; 4601991Sheppo 4611991Sheppo DBG1((vnetp, "vgen_uninit: enter vnet_instance(%d)\n", instance)); 4621991Sheppo 4631991Sheppo /* unregister with MD event generator */ 4641991Sheppo vgen_mdeg_unreg(vgenp); 4651991Sheppo 4661991Sheppo mutex_enter(&vgenp->lock); 4671991Sheppo 4681991Sheppo /* detach all ports from the device */ 4691991Sheppo vgen_detach_ports(vgenp); 4701991Sheppo 471*2336Snarayan /* 472*2336Snarayan * free any pending rx mblk pools, 473*2336Snarayan * that couldn't be freed previously during channel detach. 474*2336Snarayan */ 475*2336Snarayan rp = vgenp->rmp; 476*2336Snarayan while (rp != NULL) { 477*2336Snarayan nrp = vgenp->rmp = rp->nextp; 478*2336Snarayan if (vio_destroy_mblks(rp)) { 479*2336Snarayan vgenp->rmp = rp; 480*2336Snarayan mutex_exit(&vgenp->lock); 481*2336Snarayan return (DDI_FAILURE); 482*2336Snarayan } 483*2336Snarayan rp = nrp; 484*2336Snarayan } 485*2336Snarayan 4861991Sheppo /* free multicast table */ 4871991Sheppo kmem_free(vgenp->mctab, vgenp->mcsize * sizeof (struct ether_addr)); 4881991Sheppo 4892311Sseb mac_free(vgenp->macp); 4902311Sseb 4911991Sheppo mutex_exit(&vgenp->lock); 4921991Sheppo 4931991Sheppo mutex_destroy(&vgenp->lock); 4941991Sheppo 4951991Sheppo KMEM_FREE(vgenp); 4961991Sheppo 4971991Sheppo DBG1((vnetp, "vgen_uninit: exit vnet_instance(%d)\n", instance)); 498*2336Snarayan 499*2336Snarayan return (DDI_SUCCESS); 5001991Sheppo } 5011991Sheppo 5021991Sheppo /* enable transmit/receive for the device */ 5032311Sseb int 5041991Sheppo vgen_start(void *arg) 5051991Sheppo { 5061991Sheppo vgen_t *vgenp = (vgen_t *)arg; 5071991Sheppo 5081991Sheppo DBG1((vgenp->vnetp, "vgen_start: enter\n")); 5091991Sheppo 5101991Sheppo mutex_enter(&vgenp->lock); 5111991Sheppo vgen_init_ports(vgenp); 5121991Sheppo vgenp->flags |= VGEN_STARTED; 5131991Sheppo mutex_exit(&vgenp->lock); 5141991Sheppo 5151991Sheppo DBG1((vgenp->vnetp, "vgen_start: exit\n")); 5161991Sheppo return (DDI_SUCCESS); 5171991Sheppo } 5181991Sheppo 5191991Sheppo /* stop transmit/receive */ 5202311Sseb void 5211991Sheppo vgen_stop(void *arg) 5221991Sheppo { 5231991Sheppo vgen_t *vgenp = (vgen_t *)arg; 5241991Sheppo 5251991Sheppo DBG1((vgenp->vnetp, "vgen_stop: enter\n")); 5261991Sheppo 5271991Sheppo mutex_enter(&vgenp->lock); 5281991Sheppo vgen_uninit_ports(vgenp); 5291991Sheppo vgenp->flags &= ~(VGEN_STARTED); 5301991Sheppo mutex_exit(&vgenp->lock); 5311991Sheppo 5321991Sheppo DBG1((vgenp->vnetp, "vgen_stop: exit\n")); 5331991Sheppo } 5341991Sheppo 5351991Sheppo /* vgen transmit function */ 5361991Sheppo static mblk_t * 5371991Sheppo vgen_tx(void *arg, mblk_t *mp) 5381991Sheppo { 5391991Sheppo vgen_port_t *portp; 5401991Sheppo int status; 5411991Sheppo 5421991Sheppo portp = (vgen_port_t *)arg; 5431991Sheppo status = vgen_portsend(portp, mp); 5441991Sheppo if (status != VGEN_SUCCESS) { 5451991Sheppo /* failure */ 5461991Sheppo return (mp); 5471991Sheppo } 5481991Sheppo /* success */ 5491991Sheppo return (NULL); 5501991Sheppo } 5511991Sheppo 5521991Sheppo /* transmit packets over the given port */ 5531991Sheppo static int 5541991Sheppo vgen_portsend(vgen_port_t *portp, mblk_t *mp) 5551991Sheppo { 5561991Sheppo vgen_ldclist_t *ldclp; 5571991Sheppo vgen_ldc_t *ldcp; 5581991Sheppo int status; 5591991Sheppo 5601991Sheppo ldclp = &portp->ldclist; 5611991Sheppo READ_ENTER(&ldclp->rwlock); 5621991Sheppo /* 563*2336Snarayan * NOTE: for now, we will assume we have a single channel. 5641991Sheppo */ 5651991Sheppo if (ldclp->headp == NULL) { 5661991Sheppo RW_EXIT(&ldclp->rwlock); 5671991Sheppo return (VGEN_FAILURE); 5681991Sheppo } 5691991Sheppo ldcp = ldclp->headp; 5701991Sheppo 5711991Sheppo if (ldcp->need_resched) { 5721991Sheppo /* out of tx resources, see vgen_ldcsend() for details. */ 5731991Sheppo mutex_enter(&ldcp->txlock); 5741991Sheppo ldcp->statsp->tx_no_desc++; 5751991Sheppo mutex_exit(&ldcp->txlock); 5761991Sheppo 5771991Sheppo RW_EXIT(&ldclp->rwlock); 578*2336Snarayan return (VGEN_FAILURE); 5791991Sheppo } 5801991Sheppo 5811991Sheppo status = vgen_ldcsend(ldcp, mp); 5821991Sheppo RW_EXIT(&ldclp->rwlock); 5831991Sheppo 5841991Sheppo if (status != VGEN_TX_SUCCESS) 5851991Sheppo return (VGEN_FAILURE); 5861991Sheppo 5871991Sheppo return (VGEN_SUCCESS); 5881991Sheppo } 5891991Sheppo 5901991Sheppo /* channel transmit function */ 5911991Sheppo static int 5921991Sheppo vgen_ldcsend(vgen_ldc_t *ldcp, mblk_t *mp) 5931991Sheppo { 5941991Sheppo void *vnetp; 5951991Sheppo size_t size; 5961991Sheppo int rv; 597*2336Snarayan uint64_t tbuf_ix; 5981991Sheppo vgen_private_desc_t *tbufp; 5991991Sheppo vgen_private_desc_t *ntbufp; 6001991Sheppo vnet_public_desc_t *txdp; 6011991Sheppo vio_dring_entry_hdr_t *hdrp; 6021991Sheppo vgen_stats_t *statsp; 6031991Sheppo struct ether_header *ehp; 6041991Sheppo boolean_t is_bcast = B_FALSE; 6051991Sheppo boolean_t is_mcast = B_FALSE; 6061991Sheppo boolean_t need_intr = B_FALSE; 607*2336Snarayan size_t mblksz; 608*2336Snarayan caddr_t dst; 609*2336Snarayan mblk_t *bp; 6101991Sheppo 6111991Sheppo vnetp = LDC_TO_VNET(ldcp); 6121991Sheppo statsp = ldcp->statsp; 6132109Slm66018 size = msgsize(mp); 6142109Slm66018 6151991Sheppo DBG1((vnetp, "vgen_ldcsend: enter ldcid(%lx)\n", ldcp->ldc_id)); 6161991Sheppo 6172109Slm66018 mutex_enter(&ldcp->txlock); 6182109Slm66018 6192109Slm66018 /* drop the packet if ldc is not up or handshake is not done */ 6202109Slm66018 if (ldcp->ldc_status != LDC_UP) { 6211991Sheppo DWARN((vnetp, 6221991Sheppo "vgen_ldcsend: id(%lx) status(%d), dropping packet\n", 6231991Sheppo ldcp->ldc_id, ldcp->ldc_status)); 6242109Slm66018 /* retry ldc_up() if needed */ 6252109Slm66018 if (ldcp->flags & CHANNEL_STARTED) 6262109Slm66018 (void) ldc_up(ldcp->ldc_handle); 6272109Slm66018 goto vgen_tx_exit; 6281991Sheppo } 6291991Sheppo 6302109Slm66018 if (ldcp->hphase != VH_DONE) { 6312109Slm66018 DWARN((vnetp, 6322109Slm66018 "vgen_ldcsend: id(%lx) hphase(%x), dropping packet\n", 6332109Slm66018 ldcp->ldc_id, ldcp->hphase)); 6342109Slm66018 goto vgen_tx_exit; 6352109Slm66018 } 6362109Slm66018 6371991Sheppo if (size > (size_t)ETHERMAX) { 6381991Sheppo DWARN((vnetp, "vgen_ldcsend: id(%lx) invalid size(%d)\n", 6391991Sheppo ldcp->ldc_id, size)); 6401991Sheppo goto vgen_tx_exit; 6411991Sheppo } 6421991Sheppo 6431991Sheppo /* 6441991Sheppo * allocate a descriptor 6451991Sheppo */ 6461991Sheppo tbufp = ldcp->next_tbufp; 6471991Sheppo ntbufp = NEXTTBUF(ldcp, tbufp); 648*2336Snarayan if (ntbufp == ldcp->cur_tbufp) { /* out of tbufs/txds */ 6491991Sheppo 6501991Sheppo mutex_enter(&ldcp->tclock); 651*2336Snarayan if (ntbufp == ldcp->cur_tbufp) { 6521991Sheppo ldcp->need_resched = B_TRUE; 653*2336Snarayan mutex_exit(&ldcp->tclock); 654*2336Snarayan 655*2336Snarayan statsp->tx_no_desc++; 656*2336Snarayan mutex_exit(&ldcp->txlock); 657*2336Snarayan 658*2336Snarayan return (VGEN_TX_NORESOURCES); 659*2336Snarayan } 6601991Sheppo mutex_exit(&ldcp->tclock); 6611991Sheppo } 6621991Sheppo 6632109Slm66018 if (size < ETHERMIN) 6642109Slm66018 size = ETHERMIN; 6652109Slm66018 6662109Slm66018 /* copy data into pre-allocated transmit buffer */ 667*2336Snarayan dst = tbufp->datap + VNET_IPALIGN; 668*2336Snarayan for (bp = mp; bp != NULL; bp = bp->b_cont) { 669*2336Snarayan mblksz = MBLKL(bp); 670*2336Snarayan bcopy(bp->b_rptr, dst, mblksz); 671*2336Snarayan dst += mblksz; 6721991Sheppo } 6731991Sheppo 674*2336Snarayan tbuf_ix = tbufp - ldcp->tbufp; 6751991Sheppo 6762109Slm66018 ehp = (struct ether_header *)tbufp->datap; 6771991Sheppo is_bcast = IS_BROADCAST(ehp); 6781991Sheppo is_mcast = IS_MULTICAST(ehp); 6792109Slm66018 6801991Sheppo tbufp->flags = VGEN_PRIV_DESC_BUSY; 6812109Slm66018 tbufp->datalen = size; 6821991Sheppo 6831991Sheppo /* initialize the corresponding public descriptor (txd) */ 6841991Sheppo txdp = tbufp->descp; 6851991Sheppo hdrp = &txdp->hdr; 6861991Sheppo if (need_intr) 6871991Sheppo hdrp->ack = B_TRUE; 6882109Slm66018 txdp->nbytes = size; 6892109Slm66018 txdp->ncookies = tbufp->ncookies; 6901991Sheppo bcopy((tbufp->memcookie), (txdp->memcookie), 691*2336Snarayan tbufp->ncookies * sizeof (ldc_mem_cookie_t)); 692*2336Snarayan hdrp->dstate = VIO_DESC_READY; 6931991Sheppo 6941991Sheppo /* send dring datamsg to the peer */ 695*2336Snarayan if (ldcp->resched_peer) { 696*2336Snarayan rv = vgen_send_dring_data(ldcp, (uint32_t)tbuf_ix, -1); 697*2336Snarayan if (rv != 0) { 698*2336Snarayan /* vgen_send_dring_data() error: drop the packet */ 699*2336Snarayan DWARN((vnetp, 700*2336Snarayan "vgen_ldcsend: vgen_send_dring_data(): failed: " 701*2336Snarayan "id(%lx) rv(%d) len (%d)\n", 702*2336Snarayan ldcp->ldc_id, rv, size)); 703*2336Snarayan tbufp->flags = VGEN_PRIV_DESC_FREE; /* free tbuf */ 704*2336Snarayan hdrp->dstate = VIO_DESC_FREE; /* free txd */ 705*2336Snarayan hdrp->ack = B_FALSE; 706*2336Snarayan statsp->oerrors++; 707*2336Snarayan goto vgen_tx_exit; 708*2336Snarayan } 709*2336Snarayan ldcp->resched_peer = B_FALSE; 7101991Sheppo } 7111991Sheppo 7121991Sheppo /* update next available tbuf in the ring */ 7131991Sheppo ldcp->next_tbufp = ntbufp; 714*2336Snarayan 715*2336Snarayan /* update tx index */ 7161991Sheppo INCR_TXI(ldcp->next_txi, ldcp); 7171991Sheppo 7181991Sheppo /* update stats */ 7191991Sheppo statsp->opackets++; 7202109Slm66018 statsp->obytes += size; 7211991Sheppo if (is_bcast) 7221991Sheppo statsp->brdcstxmt++; 7231991Sheppo else if (is_mcast) 7241991Sheppo statsp->multixmt++; 7251991Sheppo 7261991Sheppo vgen_tx_exit: 7271991Sheppo mutex_exit(&ldcp->txlock); 7281991Sheppo 7291991Sheppo DBG1((vnetp, "vgen_ldcsend: exit: ldcid (%lx)\n", ldcp->ldc_id)); 7301991Sheppo 7312109Slm66018 freemsg(mp); 7322109Slm66018 return (VGEN_TX_SUCCESS); 7331991Sheppo } 7341991Sheppo 7351991Sheppo /* enable/disable a multicast address */ 7362311Sseb int 7371991Sheppo vgen_multicst(void *arg, boolean_t add, const uint8_t *mca) 7381991Sheppo { 7391991Sheppo vgen_t *vgenp; 7401991Sheppo vnet_mcast_msg_t mcastmsg; 7411991Sheppo vio_msg_tag_t *tagp; 7421991Sheppo vgen_port_t *portp; 7431991Sheppo vgen_portlist_t *plistp; 7441991Sheppo vgen_ldc_t *ldcp; 7451991Sheppo vgen_ldclist_t *ldclp; 7461991Sheppo void *vnetp; 7471991Sheppo struct ether_addr *addrp; 7481991Sheppo int rv; 7491991Sheppo uint32_t i; 7501991Sheppo 7511991Sheppo vgenp = (vgen_t *)arg; 7521991Sheppo vnetp = vgenp->vnetp; 7531991Sheppo addrp = (struct ether_addr *)mca; 7541991Sheppo tagp = &mcastmsg.tag; 7551991Sheppo bzero(&mcastmsg, sizeof (mcastmsg)); 7561991Sheppo 7571991Sheppo mutex_enter(&vgenp->lock); 7581991Sheppo 7591991Sheppo plistp = &(vgenp->vgenports); 7601991Sheppo 7611991Sheppo READ_ENTER(&plistp->rwlock); 7621991Sheppo 7631991Sheppo portp = vgenp->vsw_portp; 7641991Sheppo if (portp == NULL) { 7651991Sheppo RW_EXIT(&plistp->rwlock); 7661991Sheppo goto vgen_mcast_exit; 7671991Sheppo } 7681991Sheppo ldclp = &portp->ldclist; 7691991Sheppo 7701991Sheppo READ_ENTER(&ldclp->rwlock); 7711991Sheppo 7721991Sheppo ldcp = ldclp->headp; 7731991Sheppo if (ldcp == NULL) { 7741991Sheppo RW_EXIT(&ldclp->rwlock); 7751991Sheppo RW_EXIT(&plistp->rwlock); 7761991Sheppo goto vgen_mcast_exit; 7771991Sheppo } 7781991Sheppo 7791991Sheppo mutex_enter(&ldcp->cblock); 7801991Sheppo 7811991Sheppo if (ldcp->hphase == VH_DONE) { 7821991Sheppo /* 7831991Sheppo * If handshake is done, send a msg to vsw to add/remove 7841991Sheppo * the multicast address. 7851991Sheppo */ 7861991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 7871991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 7881991Sheppo tagp->vio_subtype_env = VNET_MCAST_INFO; 7891991Sheppo tagp->vio_sid = ldcp->local_sid; 7901991Sheppo bcopy(mca, &(mcastmsg.mca), ETHERADDRL); 7911991Sheppo mcastmsg.set = add; 7921991Sheppo mcastmsg.count = 1; 7931991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (mcastmsg), 7941991Sheppo B_FALSE); 7951991Sheppo if (rv != VGEN_SUCCESS) { 7961991Sheppo DWARN((vnetp, "vgen_mutlicst: vgen_sendmsg failed" 7971991Sheppo "id (%lx)\n", ldcp->ldc_id)); 7981991Sheppo } 7991991Sheppo } else { 8001991Sheppo /* set the flag to send a msg to vsw after handshake is done */ 8011991Sheppo ldcp->need_mcast_sync = B_TRUE; 8021991Sheppo } 8031991Sheppo 8041991Sheppo mutex_exit(&ldcp->cblock); 8051991Sheppo 8061991Sheppo if (add) { 8071991Sheppo 8081991Sheppo /* expand multicast table if necessary */ 8091991Sheppo if (vgenp->mccount >= vgenp->mcsize) { 8101991Sheppo struct ether_addr *newtab; 8111991Sheppo uint32_t newsize; 8121991Sheppo 8131991Sheppo 8141991Sheppo newsize = vgenp->mcsize * 2; 8151991Sheppo 8161991Sheppo newtab = kmem_zalloc(newsize * 8171991Sheppo sizeof (struct ether_addr), KM_NOSLEEP); 8181991Sheppo 8191991Sheppo bcopy(vgenp->mctab, newtab, vgenp->mcsize * 8201991Sheppo sizeof (struct ether_addr)); 8211991Sheppo kmem_free(vgenp->mctab, 8221991Sheppo vgenp->mcsize * sizeof (struct ether_addr)); 8231991Sheppo 8241991Sheppo vgenp->mctab = newtab; 8251991Sheppo vgenp->mcsize = newsize; 8261991Sheppo } 8271991Sheppo 8281991Sheppo /* add address to the table */ 8291991Sheppo vgenp->mctab[vgenp->mccount++] = *addrp; 8301991Sheppo 8311991Sheppo } else { 8321991Sheppo 8331991Sheppo /* delete address from the table */ 8341991Sheppo for (i = 0; i < vgenp->mccount; i++) { 8351991Sheppo if (ether_cmp(addrp, &(vgenp->mctab[i])) == 0) { 8361991Sheppo 8371991Sheppo /* 8381991Sheppo * If there's more than one address in this 8391991Sheppo * table, delete the unwanted one by moving 8401991Sheppo * the last one in the list over top of it; 8411991Sheppo * otherwise, just remove it. 8421991Sheppo */ 8431991Sheppo if (vgenp->mccount > 1) { 8441991Sheppo vgenp->mctab[i] = 8451991Sheppo vgenp->mctab[vgenp->mccount-1]; 8461991Sheppo } 8471991Sheppo vgenp->mccount--; 8481991Sheppo break; 8491991Sheppo } 8501991Sheppo } 8511991Sheppo } 8521991Sheppo 8531991Sheppo RW_EXIT(&ldclp->rwlock); 8541991Sheppo RW_EXIT(&plistp->rwlock); 8551991Sheppo 8561991Sheppo vgen_mcast_exit: 8571991Sheppo mutex_exit(&vgenp->lock); 8581991Sheppo return (DDI_SUCCESS); 8591991Sheppo } 8601991Sheppo 8611991Sheppo /* set or clear promiscuous mode on the device */ 8621991Sheppo static int 8631991Sheppo vgen_promisc(void *arg, boolean_t on) 8641991Sheppo { 8651991Sheppo _NOTE(ARGUNUSED(arg, on)) 8661991Sheppo return (DDI_SUCCESS); 8671991Sheppo } 8681991Sheppo 8691991Sheppo /* set the unicast mac address of the device */ 8701991Sheppo static int 8711991Sheppo vgen_unicst(void *arg, const uint8_t *mca) 8721991Sheppo { 8731991Sheppo _NOTE(ARGUNUSED(arg, mca)) 8741991Sheppo return (DDI_SUCCESS); 8751991Sheppo } 8761991Sheppo 8771991Sheppo /* get device statistics */ 8782311Sseb int 8792311Sseb vgen_stat(void *arg, uint_t stat, uint64_t *val) 8801991Sheppo { 8811991Sheppo vgen_t *vgenp = (vgen_t *)arg; 8821991Sheppo vgen_port_t *portp; 8831991Sheppo vgen_portlist_t *plistp; 8842311Sseb 8852311Sseb *val = 0; 8861991Sheppo 8871991Sheppo plistp = &(vgenp->vgenports); 8881991Sheppo READ_ENTER(&plistp->rwlock); 8891991Sheppo 8901991Sheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) { 8912311Sseb *val += vgen_port_stat(portp, stat); 8921991Sheppo } 8931991Sheppo 8941991Sheppo RW_EXIT(&plistp->rwlock); 8951991Sheppo 8962311Sseb return (0); 8971991Sheppo } 8981991Sheppo 8991991Sheppo static void 9001991Sheppo vgen_ioctl(void *arg, queue_t *wq, mblk_t *mp) 9011991Sheppo { 9021991Sheppo _NOTE(ARGUNUSED(arg, wq, mp)) 9031991Sheppo } 9041991Sheppo 9051991Sheppo /* vgen internal functions */ 9061991Sheppo /* detach all ports from the device */ 9071991Sheppo static void 9081991Sheppo vgen_detach_ports(vgen_t *vgenp) 9091991Sheppo { 9101991Sheppo vgen_port_t *portp; 9111991Sheppo vgen_portlist_t *plistp; 9121991Sheppo 9131991Sheppo plistp = &(vgenp->vgenports); 9141991Sheppo WRITE_ENTER(&plistp->rwlock); 9151991Sheppo 9161991Sheppo while ((portp = plistp->headp) != NULL) { 9171991Sheppo vgen_port_detach(portp); 9181991Sheppo } 9191991Sheppo 9201991Sheppo RW_EXIT(&plistp->rwlock); 9211991Sheppo } 9221991Sheppo 9231991Sheppo /* 9241991Sheppo * detach the given port. 9251991Sheppo */ 9261991Sheppo static void 9271991Sheppo vgen_port_detach(vgen_port_t *portp) 9281991Sheppo { 9291991Sheppo vgen_t *vgenp; 9301991Sheppo vgen_ldclist_t *ldclp; 9311991Sheppo int port_num; 9321991Sheppo 9331991Sheppo vgenp = portp->vgenp; 9341991Sheppo port_num = portp->port_num; 9351991Sheppo 9361991Sheppo DBG1((vgenp->vnetp, 9371991Sheppo "vgen_port_detach: enter: port_num(%d)\n", port_num)); 9381991Sheppo 9391991Sheppo /* remove it from port list */ 9401991Sheppo vgen_port_list_remove(portp); 9411991Sheppo 9421991Sheppo /* detach channels from this port */ 9431991Sheppo ldclp = &portp->ldclist; 9441991Sheppo WRITE_ENTER(&ldclp->rwlock); 9451991Sheppo while (ldclp->headp) { 9461991Sheppo vgen_ldc_detach(ldclp->headp); 9471991Sheppo } 9481991Sheppo RW_EXIT(&ldclp->rwlock); 9491991Sheppo 9501991Sheppo if (vgenp->vsw_portp == portp) { 9511991Sheppo vgenp->vsw_portp = NULL; 9521991Sheppo } 9531991Sheppo KMEM_FREE(portp); 9541991Sheppo 9551991Sheppo DBG1((vgenp->vnetp, 9561991Sheppo "vgen_port_detach: exit: port_num(%d)\n", port_num)); 9571991Sheppo } 9581991Sheppo 9591991Sheppo /* add a port to port list */ 9601991Sheppo static void 9611991Sheppo vgen_port_list_insert(vgen_port_t *portp) 9621991Sheppo { 9631991Sheppo vgen_portlist_t *plistp; 9641991Sheppo vgen_t *vgenp; 9651991Sheppo 9661991Sheppo vgenp = portp->vgenp; 9671991Sheppo plistp = &(vgenp->vgenports); 9681991Sheppo 9691991Sheppo if (plistp->headp == NULL) { 9701991Sheppo plistp->headp = portp; 9711991Sheppo } else { 9721991Sheppo plistp->tailp->nextp = portp; 9731991Sheppo } 9741991Sheppo plistp->tailp = portp; 9751991Sheppo portp->nextp = NULL; 9761991Sheppo } 9771991Sheppo 9781991Sheppo /* remove a port from port list */ 9791991Sheppo static void 9801991Sheppo vgen_port_list_remove(vgen_port_t *portp) 9811991Sheppo { 9821991Sheppo vgen_port_t *prevp; 9831991Sheppo vgen_port_t *nextp; 9841991Sheppo vgen_portlist_t *plistp; 9851991Sheppo vgen_t *vgenp; 9861991Sheppo 9871991Sheppo vgenp = portp->vgenp; 9881991Sheppo 9891991Sheppo plistp = &(vgenp->vgenports); 9901991Sheppo 9911991Sheppo if (plistp->headp == NULL) 9921991Sheppo return; 9931991Sheppo 9941991Sheppo if (portp == plistp->headp) { 9951991Sheppo plistp->headp = portp->nextp; 9961991Sheppo if (portp == plistp->tailp) 9971991Sheppo plistp->tailp = plistp->headp; 9981991Sheppo } else { 9991991Sheppo for (prevp = plistp->headp; ((nextp = prevp->nextp) != NULL) && 10001991Sheppo (nextp != portp); prevp = nextp); 10011991Sheppo if (nextp == portp) { 10021991Sheppo prevp->nextp = portp->nextp; 10031991Sheppo } 10041991Sheppo if (portp == plistp->tailp) 10051991Sheppo plistp->tailp = prevp; 10061991Sheppo } 10071991Sheppo } 10081991Sheppo 10091991Sheppo /* lookup a port in the list based on port_num */ 10101991Sheppo static vgen_port_t * 10111991Sheppo vgen_port_lookup(vgen_portlist_t *plistp, int port_num) 10121991Sheppo { 10131991Sheppo vgen_port_t *portp = NULL; 10141991Sheppo 10151991Sheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) { 10161991Sheppo if (portp->port_num == port_num) { 10171991Sheppo break; 10181991Sheppo } 10191991Sheppo } 10201991Sheppo 10211991Sheppo return (portp); 10221991Sheppo } 10231991Sheppo 10241991Sheppo /* enable ports for transmit/receive */ 10251991Sheppo static void 10261991Sheppo vgen_init_ports(vgen_t *vgenp) 10271991Sheppo { 10281991Sheppo vgen_port_t *portp; 10291991Sheppo vgen_portlist_t *plistp; 10301991Sheppo 10311991Sheppo plistp = &(vgenp->vgenports); 10321991Sheppo READ_ENTER(&plistp->rwlock); 10331991Sheppo 10341991Sheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) { 10351991Sheppo vgen_port_init(portp); 10361991Sheppo } 10371991Sheppo 10381991Sheppo RW_EXIT(&plistp->rwlock); 10391991Sheppo } 10401991Sheppo 10411991Sheppo static void 10421991Sheppo vgen_port_init(vgen_port_t *portp) 10431991Sheppo { 10441991Sheppo vgen_t *vgenp; 10451991Sheppo 10461991Sheppo vgenp = portp->vgenp; 10471991Sheppo /* 10481991Sheppo * Create fdb entry in vnet, corresponding to the mac 10491991Sheppo * address of this port. Note that the port specified 10501991Sheppo * is vsw-port. This is done so that vsw-port acts 10511991Sheppo * as the route to reach this macaddr, until the 10521991Sheppo * channel for this port comes up (LDC_UP) and 10531991Sheppo * handshake is done successfully. 10541991Sheppo * eg, if the peer is OBP-vnet, it may not bring the 10551991Sheppo * channel up for this port and may communicate via 10561991Sheppo * vsw to reach this port. 10571991Sheppo * Later, when Solaris-vnet comes up at the other end 10581991Sheppo * of the channel for this port and brings up the channel, 10591991Sheppo * it is an indication that peer vnet is capable of 10601991Sheppo * distributed switching, so the direct route through this 10611991Sheppo * port is specified in fdb, using vnet_modify_fdb(macaddr); 10621991Sheppo */ 10631991Sheppo vnet_add_fdb(vgenp->vnetp, (uint8_t *)&portp->macaddr, 10641991Sheppo vgen_tx, vgenp->vsw_portp); 10651991Sheppo 10661991Sheppo if (portp == vgenp->vsw_portp) { 10671991Sheppo /* 10681991Sheppo * create the default route entry in vnet's fdb. 10691991Sheppo * This is the entry used by vnet to reach 10701991Sheppo * unknown destinations, which basically goes 10711991Sheppo * through vsw on domain0 and out through the 10721991Sheppo * physical device bound to vsw. 10731991Sheppo */ 10741991Sheppo vnet_add_def_rte(vgenp->vnetp, vgen_tx, portp); 10751991Sheppo } 10761991Sheppo 10771991Sheppo /* Bring up the channels of this port */ 10781991Sheppo vgen_init_ldcs(portp); 10791991Sheppo } 10801991Sheppo 10811991Sheppo /* disable transmit/receive on ports */ 10821991Sheppo static void 10831991Sheppo vgen_uninit_ports(vgen_t *vgenp) 10841991Sheppo { 10851991Sheppo vgen_port_t *portp; 10861991Sheppo vgen_portlist_t *plistp; 10871991Sheppo 10881991Sheppo plistp = &(vgenp->vgenports); 10891991Sheppo READ_ENTER(&plistp->rwlock); 10901991Sheppo 10911991Sheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) { 10921991Sheppo vgen_port_uninit(portp); 10931991Sheppo } 10941991Sheppo 10951991Sheppo RW_EXIT(&plistp->rwlock); 10961991Sheppo } 10971991Sheppo 10981991Sheppo static void 10991991Sheppo vgen_port_uninit(vgen_port_t *portp) 11001991Sheppo { 11011991Sheppo vgen_t *vgenp; 11021991Sheppo 11031991Sheppo vgenp = portp->vgenp; 11041991Sheppo 11051991Sheppo vgen_uninit_ldcs(portp); 11061991Sheppo /* delete the entry in vnet's fdb for this port */ 11071991Sheppo vnet_del_fdb(vgenp->vnetp, (uint8_t *)&portp->macaddr); 11081991Sheppo if (portp == vgenp->vsw_portp) { 11091991Sheppo /* 11101991Sheppo * if this is vsw-port, then delete the default 11111991Sheppo * route entry in vnet's fdb. 11121991Sheppo */ 11131991Sheppo vnet_del_def_rte(vgenp->vnetp); 11141991Sheppo } 11151991Sheppo } 11161991Sheppo 11171991Sheppo /* register with MD event generator */ 11181991Sheppo static int 11191991Sheppo vgen_mdeg_reg(vgen_t *vgenp) 11201991Sheppo { 11211991Sheppo mdeg_prop_spec_t *pspecp; 11221991Sheppo mdeg_node_spec_t *parentp; 11231991Sheppo uint_t templatesz; 11241991Sheppo int rv; 11251991Sheppo mdeg_handle_t hdl; 11261991Sheppo int i; 11271991Sheppo void *vnetp = vgenp->vnetp; 11281991Sheppo 11291991Sheppo i = ddi_prop_get_int(DDI_DEV_T_ANY, vgenp->vnetdip, 11301991Sheppo DDI_PROP_DONTPASS, reg_propname, -1); 11311991Sheppo if (i == -1) { 11321991Sheppo return (DDI_FAILURE); 11331991Sheppo } 11341991Sheppo templatesz = sizeof (vgen_prop_template); 11351991Sheppo pspecp = kmem_zalloc(templatesz, KM_NOSLEEP); 11361991Sheppo if (pspecp == NULL) { 11371991Sheppo return (DDI_FAILURE); 11381991Sheppo } 11391991Sheppo parentp = kmem_zalloc(sizeof (mdeg_node_spec_t), KM_NOSLEEP); 11401991Sheppo if (parentp == NULL) { 11411991Sheppo kmem_free(pspecp, templatesz); 11421991Sheppo return (DDI_FAILURE); 11431991Sheppo } 11441991Sheppo 11451991Sheppo bcopy(vgen_prop_template, pspecp, templatesz); 11461991Sheppo 11471991Sheppo /* 11481991Sheppo * NOTE: The instance here refers to the value of "reg" property and 11491991Sheppo * not the dev_info instance (ddi_get_instance()) of vnet. 11501991Sheppo */ 11511991Sheppo VGEN_SET_MDEG_PROP_INST(pspecp, i); 11521991Sheppo 11531991Sheppo parentp->namep = "virtual-device"; 11541991Sheppo parentp->specp = pspecp; 11551991Sheppo 11561991Sheppo /* save parentp in vgen_t */ 11571991Sheppo vgenp->mdeg_parentp = parentp; 11581991Sheppo 11591991Sheppo rv = mdeg_register(parentp, &vport_match, vgen_mdeg_cb, vgenp, &hdl); 11601991Sheppo if (rv != MDEG_SUCCESS) { 11611991Sheppo DERR((vnetp, "vgen_mdeg_reg: mdeg_register failed\n")); 11621991Sheppo KMEM_FREE(parentp); 11631991Sheppo kmem_free(pspecp, templatesz); 11641991Sheppo vgenp->mdeg_parentp = NULL; 11651991Sheppo return (DDI_FAILURE); 11661991Sheppo } 11671991Sheppo 11681991Sheppo /* save mdeg handle in vgen_t */ 11691991Sheppo vgenp->mdeg_hdl = hdl; 11701991Sheppo 11711991Sheppo return (DDI_SUCCESS); 11721991Sheppo } 11731991Sheppo 11741991Sheppo /* unregister with MD event generator */ 11751991Sheppo static void 11761991Sheppo vgen_mdeg_unreg(vgen_t *vgenp) 11771991Sheppo { 11781991Sheppo (void) mdeg_unregister(vgenp->mdeg_hdl); 11791991Sheppo KMEM_FREE(vgenp->mdeg_parentp); 11801991Sheppo vgenp->mdeg_parentp = NULL; 11811991Sheppo vgenp->mdeg_hdl = NULL; 11821991Sheppo } 11831991Sheppo 11841991Sheppo /* callback function registered with MD event generator */ 11851991Sheppo static int 11861991Sheppo vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp) 11871991Sheppo { 11881991Sheppo int idx; 11891991Sheppo int vsw_idx = -1; 11901991Sheppo uint64_t val; 11911991Sheppo vgen_t *vgenp; 11921991Sheppo 11931991Sheppo if ((resp == NULL) || (cb_argp == NULL)) { 11941991Sheppo return (MDEG_FAILURE); 11951991Sheppo } 11961991Sheppo 11971991Sheppo vgenp = (vgen_t *)cb_argp; 11981991Sheppo DBG1((vgenp->vnetp, "vgen_mdeg_cb: enter\n")); 11991991Sheppo 12001991Sheppo mutex_enter(&vgenp->lock); 12011991Sheppo 12021991Sheppo DBG1((vgenp->vnetp, 12031991Sheppo "vgen_mdeg_cb: ports: removed(%x), added(%x), updated(%x)\n", 12041991Sheppo resp->removed.nelem, resp->added.nelem, resp->match_curr.nelem)); 12051991Sheppo 12061991Sheppo for (idx = 0; idx < resp->removed.nelem; idx++) { 12071991Sheppo (void) vgen_remove_port(vgenp, resp->removed.mdp, 12081991Sheppo resp->removed.mdep[idx]); 12091991Sheppo } 12101991Sheppo 12111991Sheppo if (vgenp->vsw_portp == NULL) { 12121991Sheppo /* 12131991Sheppo * find vsw_port and add it first, because other ports need 12141991Sheppo * this when adding fdb entry (see vgen_port_init()). 12151991Sheppo */ 12161991Sheppo for (idx = 0; idx < resp->added.nelem; idx++) { 12171991Sheppo if (!(md_get_prop_val(resp->added.mdp, 12181991Sheppo resp->added.mdep[idx], swport_propname, &val))) { 12191991Sheppo if (val == 0) { 12201991Sheppo /* 12211991Sheppo * This port is connected to the 12221991Sheppo * vsw on dom0. 12231991Sheppo */ 12241991Sheppo vsw_idx = idx; 12251991Sheppo (void) vgen_add_port(vgenp, 12261991Sheppo resp->added.mdp, 12271991Sheppo resp->added.mdep[idx]); 12281991Sheppo break; 12291991Sheppo } 12301991Sheppo } 12311991Sheppo } 12321991Sheppo if (vsw_idx == -1) { 12331991Sheppo DWARN((vgenp->vnetp, "vgen_mdeg_cb: " 12341991Sheppo "can't find vsw_port\n")); 12351991Sheppo return (MDEG_FAILURE); 12361991Sheppo } 12371991Sheppo } 12381991Sheppo 12391991Sheppo for (idx = 0; idx < resp->added.nelem; idx++) { 12401991Sheppo if ((vsw_idx != -1) && (vsw_idx == idx)) /* skip vsw_port */ 12411991Sheppo continue; 12421991Sheppo (void) vgen_add_port(vgenp, resp->added.mdp, 12431991Sheppo resp->added.mdep[idx]); 12441991Sheppo } 12451991Sheppo 12461991Sheppo for (idx = 0; idx < resp->match_curr.nelem; idx++) { 12471991Sheppo (void) vgen_update_port(vgenp, resp->match_curr.mdp, 12481991Sheppo resp->match_curr.mdep[idx], 12491991Sheppo resp->match_prev.mdp, 12501991Sheppo resp->match_prev.mdep[idx]); 12511991Sheppo } 12521991Sheppo 12531991Sheppo mutex_exit(&vgenp->lock); 12541991Sheppo DBG1((vgenp->vnetp, "vgen_mdeg_cb: exit\n")); 12551991Sheppo return (MDEG_SUCCESS); 12561991Sheppo } 12571991Sheppo 12581991Sheppo /* add a new port to the device */ 12591991Sheppo static int 12601991Sheppo vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex) 12611991Sheppo { 12621991Sheppo uint64_t port_num; 12631991Sheppo uint64_t *ldc_ids; 12641991Sheppo uint64_t macaddr; 12651991Sheppo uint64_t val; 12661991Sheppo int num_ldcs; 12671991Sheppo int vsw_port = B_FALSE; 12681991Sheppo int i; 12691991Sheppo int addrsz; 12701991Sheppo int num_nodes = 0; 12711991Sheppo int listsz = 0; 12721991Sheppo mde_cookie_t *listp = NULL; 12731991Sheppo uint8_t *addrp; 12741991Sheppo struct ether_addr ea; 12751991Sheppo 12761991Sheppo /* read "id" property to get the port number */ 12771991Sheppo if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) { 12781991Sheppo DWARN((vgenp->vnetp, 12791991Sheppo "vgen_add_port: prop(%s) not found\n", id_propname)); 12801991Sheppo return (DDI_FAILURE); 12811991Sheppo } 12821991Sheppo 12831991Sheppo /* 12841991Sheppo * Find the channel endpoint node(s) under this port node. 12851991Sheppo */ 12861991Sheppo if ((num_nodes = md_node_count(mdp)) <= 0) { 12871991Sheppo DWARN((vgenp->vnetp, 12881991Sheppo "vgen_add_port: invalid number of nodes found (%d)", 12891991Sheppo num_nodes)); 12901991Sheppo return (DDI_FAILURE); 12911991Sheppo } 12921991Sheppo 12931991Sheppo /* allocate space for node list */ 12941991Sheppo listsz = num_nodes * sizeof (mde_cookie_t); 12951991Sheppo listp = kmem_zalloc(listsz, KM_NOSLEEP); 12961991Sheppo if (listp == NULL) 12971991Sheppo return (DDI_FAILURE); 12981991Sheppo 12991991Sheppo num_ldcs = md_scan_dag(mdp, mdex, 13001991Sheppo md_find_name(mdp, channel_propname), 13011991Sheppo md_find_name(mdp, "fwd"), listp); 13021991Sheppo 13031991Sheppo if (num_ldcs <= 0) { 13041991Sheppo DWARN((vgenp->vnetp, 13051991Sheppo "vgen_add_port: can't find %s nodes", channel_propname)); 13061991Sheppo kmem_free(listp, listsz); 13071991Sheppo return (DDI_FAILURE); 13081991Sheppo } 13091991Sheppo 13101991Sheppo DBG2((vgenp->vnetp, "vgen_add_port: num_ldcs %d", num_ldcs)); 13111991Sheppo 13121991Sheppo ldc_ids = kmem_zalloc(num_ldcs * sizeof (uint64_t), KM_NOSLEEP); 13131991Sheppo if (ldc_ids == NULL) { 13141991Sheppo kmem_free(listp, listsz); 13151991Sheppo return (DDI_FAILURE); 13161991Sheppo } 13171991Sheppo 13181991Sheppo for (i = 0; i < num_ldcs; i++) { 13191991Sheppo /* read channel ids */ 13201991Sheppo if (md_get_prop_val(mdp, listp[i], id_propname, &ldc_ids[i])) { 13211991Sheppo DWARN((vgenp->vnetp, 13221991Sheppo "vgen_add_port: prop(%s) not found\n", 13231991Sheppo id_propname)); 13241991Sheppo kmem_free(listp, listsz); 13251991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 13261991Sheppo return (DDI_FAILURE); 13271991Sheppo } 13281991Sheppo DBG2((vgenp->vnetp, "vgen_add_port: ldc_id 0x%llx", 13291991Sheppo ldc_ids[i])); 13301991Sheppo } 13311991Sheppo 13321991Sheppo kmem_free(listp, listsz); 13331991Sheppo 13341991Sheppo if (md_get_prop_data(mdp, mdex, rmacaddr_propname, &addrp, 13351991Sheppo &addrsz)) { 13361991Sheppo DWARN((vgenp->vnetp, 13371991Sheppo "vgen_add_port: prop(%s) not found\n", rmacaddr_propname)); 13381991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 13391991Sheppo return (DDI_FAILURE); 13401991Sheppo } 13411991Sheppo 13421991Sheppo if (addrsz < ETHERADDRL) { 13431991Sheppo DWARN((vgenp->vnetp, 13441991Sheppo "vgen_add_port: invalid address size (%d)\n", addrsz)); 13451991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 13461991Sheppo return (DDI_FAILURE); 13471991Sheppo } 13481991Sheppo 13491991Sheppo macaddr = *((uint64_t *)addrp); 13501991Sheppo 13511991Sheppo DBG2((vgenp->vnetp, "vgen_add_port: remote mac address 0x%llx\n", 13521991Sheppo macaddr)); 13531991Sheppo 13541991Sheppo for (i = ETHERADDRL - 1; i >= 0; i--) { 13551991Sheppo ea.ether_addr_octet[i] = macaddr & 0xFF; 13561991Sheppo macaddr >>= 8; 13571991Sheppo } 13581991Sheppo 13591991Sheppo if (vgenp->vsw_portp == NULL) { 13601991Sheppo if (!(md_get_prop_val(mdp, mdex, swport_propname, &val))) { 13611991Sheppo if (val == 0) { 13621991Sheppo /* This port is connected to the vsw on dom0 */ 13631991Sheppo vsw_port = B_TRUE; 13641991Sheppo } 13651991Sheppo } 13661991Sheppo } 13671991Sheppo (void) vgen_port_attach_mdeg(vgenp, (int)port_num, ldc_ids, num_ldcs, 13681991Sheppo &ea, vsw_port); 13691991Sheppo 13701991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 13711991Sheppo 13721991Sheppo return (DDI_SUCCESS); 13731991Sheppo } 13741991Sheppo 13751991Sheppo /* remove a port from the device */ 13761991Sheppo static int 13771991Sheppo vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex) 13781991Sheppo { 13791991Sheppo uint64_t port_num; 13801991Sheppo vgen_port_t *portp; 13811991Sheppo vgen_portlist_t *plistp; 13821991Sheppo 13831991Sheppo /* read "id" property to get the port number */ 13841991Sheppo if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) { 13851991Sheppo DWARN((vgenp->vnetp, 13861991Sheppo "vgen_remove_port: prop(%s) not found\n", id_propname)); 13871991Sheppo return (DDI_FAILURE); 13881991Sheppo } 13891991Sheppo 13901991Sheppo plistp = &(vgenp->vgenports); 13911991Sheppo 13921991Sheppo WRITE_ENTER(&plistp->rwlock); 13931991Sheppo portp = vgen_port_lookup(plistp, (int)port_num); 13941991Sheppo if (portp == NULL) { 13951991Sheppo DWARN((vgenp->vnetp, "vgen_remove_port: can't find port(%lx)\n", 13961991Sheppo port_num)); 13971991Sheppo RW_EXIT(&plistp->rwlock); 13981991Sheppo return (DDI_FAILURE); 13991991Sheppo } 14001991Sheppo 14011991Sheppo vgen_port_detach_mdeg(portp); 14021991Sheppo RW_EXIT(&plistp->rwlock); 14031991Sheppo 14041991Sheppo return (DDI_SUCCESS); 14051991Sheppo } 14061991Sheppo 14071991Sheppo /* attach a port to the device based on mdeg data */ 14081991Sheppo static int 14091991Sheppo vgen_port_attach_mdeg(vgen_t *vgenp, int port_num, uint64_t *ldcids, 14101991Sheppo int num_ids, struct ether_addr *macaddr, boolean_t vsw_port) 14111991Sheppo { 14121991Sheppo vgen_port_t *portp; 14131991Sheppo vgen_portlist_t *plistp; 14141991Sheppo int i; 14151991Sheppo 14161991Sheppo portp = kmem_zalloc(sizeof (vgen_port_t), KM_NOSLEEP); 14171991Sheppo if (portp == NULL) { 14181991Sheppo return (DDI_FAILURE); 14191991Sheppo } 14201991Sheppo portp->vgenp = vgenp; 14211991Sheppo portp->port_num = port_num; 14221991Sheppo 14231991Sheppo DBG1((vgenp->vnetp, 14241991Sheppo "vgen_port_attach_mdeg: port_num(%d)\n", portp->port_num)); 14251991Sheppo 14261991Sheppo portp->ldclist.num_ldcs = 0; 14271991Sheppo portp->ldclist.headp = NULL; 14281991Sheppo rw_init(&portp->ldclist.rwlock, NULL, RW_DRIVER, NULL); 14291991Sheppo 14301991Sheppo ether_copy(macaddr, &portp->macaddr); 14311991Sheppo for (i = 0; i < num_ids; i++) { 14321991Sheppo DBG2((vgenp->vnetp, "vgen_port_attach_mdeg: ldcid (%lx)\n", 14331991Sheppo ldcids[i])); 14341991Sheppo (void) vgen_ldc_attach(portp, ldcids[i]); 14351991Sheppo } 14361991Sheppo 14371991Sheppo /* link it into the list of ports */ 14381991Sheppo plistp = &(vgenp->vgenports); 14391991Sheppo WRITE_ENTER(&plistp->rwlock); 14401991Sheppo vgen_port_list_insert(portp); 14411991Sheppo RW_EXIT(&plistp->rwlock); 14421991Sheppo 14431991Sheppo /* This port is connected to the vsw on domain0 */ 14441991Sheppo if (vsw_port) 14451991Sheppo vgenp->vsw_portp = portp; 14461991Sheppo 14471991Sheppo if (vgenp->flags & VGEN_STARTED) { /* interface is configured */ 14481991Sheppo vgen_port_init(portp); 14491991Sheppo } 14501991Sheppo 14511991Sheppo DBG1((vgenp->vnetp, 14521991Sheppo "vgen_port_attach_mdeg: exit: port_num(%d)\n", portp->port_num)); 14531991Sheppo return (DDI_SUCCESS); 14541991Sheppo } 14551991Sheppo 14561991Sheppo /* detach a port from the device based on mdeg data */ 14571991Sheppo static void 14581991Sheppo vgen_port_detach_mdeg(vgen_port_t *portp) 14591991Sheppo { 14601991Sheppo vgen_t *vgenp = portp->vgenp; 14611991Sheppo 14621991Sheppo DBG1((vgenp->vnetp, 14631991Sheppo "vgen_port_detach_mdeg: enter: port_num(%d)\n", portp->port_num)); 14641991Sheppo /* stop the port if needed */ 14651991Sheppo if (vgenp->flags & VGEN_STARTED) { 14661991Sheppo vgen_port_uninit(portp); 14671991Sheppo } 14681991Sheppo vgen_port_detach(portp); 14691991Sheppo 14701991Sheppo DBG1((vgenp->vnetp, 14711991Sheppo "vgen_port_detach_mdeg: exit: port_num(%d)\n", portp->port_num)); 14721991Sheppo } 14731991Sheppo 14741991Sheppo static int 14751991Sheppo vgen_update_port(vgen_t *vgenp, md_t *curr_mdp, mde_cookie_t curr_mdex, 14761991Sheppo md_t *prev_mdp, mde_cookie_t prev_mdex) 14771991Sheppo { 14781991Sheppo _NOTE(ARGUNUSED(vgenp, curr_mdp, curr_mdex, prev_mdp, prev_mdex)) 14791991Sheppo 14801991Sheppo /* XXX: TBD */ 14811991Sheppo return (DDI_SUCCESS); 14821991Sheppo } 14831991Sheppo 14841991Sheppo static uint64_t 14852311Sseb vgen_port_stat(vgen_port_t *portp, uint_t stat) 14861991Sheppo { 14871991Sheppo vgen_ldclist_t *ldclp; 14881991Sheppo vgen_ldc_t *ldcp; 14891991Sheppo uint64_t val; 14901991Sheppo 14911991Sheppo val = 0; 14921991Sheppo ldclp = &portp->ldclist; 14931991Sheppo 14941991Sheppo READ_ENTER(&ldclp->rwlock); 14951991Sheppo for (ldcp = ldclp->headp; ldcp != NULL; ldcp = ldcp->nextp) { 14961991Sheppo val += vgen_ldc_stat(ldcp, stat); 14971991Sheppo } 14981991Sheppo RW_EXIT(&ldclp->rwlock); 14991991Sheppo 15001991Sheppo return (val); 15011991Sheppo } 15021991Sheppo 15031991Sheppo /* attach the channel corresponding to the given ldc_id to the port */ 15041991Sheppo static int 15051991Sheppo vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id) 15061991Sheppo { 15071991Sheppo vgen_t *vgenp; 15081991Sheppo vgen_ldclist_t *ldclp; 15091991Sheppo vgen_ldc_t *ldcp, **prev_ldcp; 15101991Sheppo ldc_attr_t attr; 15111991Sheppo int status; 15121991Sheppo ldc_status_t istatus; 15131991Sheppo enum {AST_init = 0x0, AST_ldc_alloc = 0x1, 15141991Sheppo AST_mutex_init = 0x2, AST_ldc_init = 0x4, 1515*2336Snarayan AST_ldc_reg_cb = 0x8, AST_alloc_tx_ring = 0x10, 1516*2336Snarayan AST_create_rxmblks = 0x20} 15171991Sheppo attach_state; 15181991Sheppo 15191991Sheppo attach_state = AST_init; 15201991Sheppo vgenp = portp->vgenp; 15211991Sheppo ldclp = &portp->ldclist; 15221991Sheppo 15231991Sheppo ldcp = kmem_zalloc(sizeof (vgen_ldc_t), KM_NOSLEEP); 15241991Sheppo if (ldcp == NULL) { 15251991Sheppo goto ldc_attach_failed; 15261991Sheppo } 15271991Sheppo ldcp->ldc_id = ldc_id; 15281991Sheppo ldcp->portp = portp; 15291991Sheppo ldcp->reclaim_lowat = vnet_reclaim_lowat; 15301991Sheppo ldcp->reclaim_hiwat = vnet_reclaim_hiwat; 15311991Sheppo 15321991Sheppo attach_state |= AST_ldc_alloc; 15331991Sheppo 15341991Sheppo mutex_init(&ldcp->txlock, NULL, MUTEX_DRIVER, NULL); 15351991Sheppo mutex_init(&ldcp->cblock, NULL, MUTEX_DRIVER, NULL); 15361991Sheppo mutex_init(&ldcp->tclock, NULL, MUTEX_DRIVER, NULL); 15371991Sheppo 15381991Sheppo attach_state |= AST_mutex_init; 15391991Sheppo 15401991Sheppo attr.devclass = LDC_DEV_NT; 15411991Sheppo attr.instance = ddi_get_instance(vgenp->vnetdip); 15421991Sheppo attr.mode = LDC_MODE_UNRELIABLE; 15431991Sheppo attr.qlen = vnet_ldc_qlen; 15441991Sheppo status = ldc_init(ldc_id, &attr, &ldcp->ldc_handle); 15451991Sheppo if (status != 0) { 15461991Sheppo DWARN((vgenp->vnetp, "ldc_init failed, id (%lx) rv (%d)\n", 15471991Sheppo ldc_id, status)); 15481991Sheppo goto ldc_attach_failed; 15491991Sheppo } 15501991Sheppo attach_state |= AST_ldc_init; 15511991Sheppo 15521991Sheppo status = ldc_reg_callback(ldcp->ldc_handle, vgen_ldc_cb, (caddr_t)ldcp); 15531991Sheppo if (status != 0) { 15541991Sheppo DWARN((vgenp->vnetp, 15551991Sheppo "ldc_reg_callback failed, id (%lx) rv (%d)\n", 15561991Sheppo ldc_id, status)); 15571991Sheppo goto ldc_attach_failed; 15581991Sheppo } 15591991Sheppo attach_state |= AST_ldc_reg_cb; 15601991Sheppo 15611991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 15621991Sheppo ASSERT(istatus == LDC_INIT); 15631991Sheppo ldcp->ldc_status = istatus; 15641991Sheppo 15651991Sheppo /* allocate transmit resources */ 15661991Sheppo status = vgen_alloc_tx_ring(ldcp); 15671991Sheppo if (status != 0) { 15681991Sheppo goto ldc_attach_failed; 15691991Sheppo } 15701991Sheppo attach_state |= AST_alloc_tx_ring; 15711991Sheppo 1572*2336Snarayan /* allocate receive resources */ 1573*2336Snarayan ldcp->num_rbufs = vnet_nrbufs; 1574*2336Snarayan ldcp->rmp = NULL; 1575*2336Snarayan status = vio_create_mblks(ldcp->num_rbufs, VGEN_DBLK_SZ, 1576*2336Snarayan &(ldcp->rmp)); 1577*2336Snarayan if (status != 0) { 1578*2336Snarayan goto ldc_attach_failed; 1579*2336Snarayan } 1580*2336Snarayan attach_state |= AST_create_rxmblks; 1581*2336Snarayan 15821991Sheppo /* Setup kstats for the channel */ 15831991Sheppo status = vgen_setup_kstats(ldcp); 15841991Sheppo if (status != VGEN_SUCCESS) { 15851991Sheppo goto ldc_attach_failed; 15861991Sheppo } 15871991Sheppo 15881991Sheppo /* initialize vgen_versions supported */ 15891991Sheppo bcopy(vgen_versions, ldcp->vgen_versions, sizeof (ldcp->vgen_versions)); 15901991Sheppo 15911991Sheppo /* link it into the list of channels for this port */ 15921991Sheppo WRITE_ENTER(&ldclp->rwlock); 15931991Sheppo prev_ldcp = (vgen_ldc_t **)(&ldclp->headp); 15941991Sheppo ldcp->nextp = *prev_ldcp; 15951991Sheppo *prev_ldcp = ldcp; 15961991Sheppo ldclp->num_ldcs++; 15971991Sheppo RW_EXIT(&ldclp->rwlock); 15981991Sheppo 15991991Sheppo ldcp->flags |= CHANNEL_ATTACHED; 16001991Sheppo return (DDI_SUCCESS); 16011991Sheppo 16021991Sheppo ldc_attach_failed: 1603*2336Snarayan if (attach_state & AST_create_rxmblks) { 1604*2336Snarayan (void) vio_destroy_mblks(ldcp->rmp); 1605*2336Snarayan } 16061991Sheppo if (attach_state & AST_alloc_tx_ring) { 16071991Sheppo vgen_free_tx_ring(ldcp); 16081991Sheppo } 16091991Sheppo if (attach_state & AST_ldc_reg_cb) { 16101991Sheppo (void) ldc_unreg_callback(ldcp->ldc_handle); 16111991Sheppo } 16121991Sheppo if (attach_state & AST_ldc_init) { 16131991Sheppo (void) ldc_fini(ldcp->ldc_handle); 16141991Sheppo } 16151991Sheppo if (attach_state & AST_mutex_init) { 16161991Sheppo mutex_destroy(&ldcp->tclock); 16171991Sheppo mutex_destroy(&ldcp->txlock); 16181991Sheppo mutex_destroy(&ldcp->cblock); 16191991Sheppo } 16201991Sheppo if (attach_state & AST_ldc_alloc) { 16211991Sheppo KMEM_FREE(ldcp); 16221991Sheppo } 16231991Sheppo return (DDI_FAILURE); 16241991Sheppo } 16251991Sheppo 16261991Sheppo /* detach a channel from the port */ 16271991Sheppo static void 16281991Sheppo vgen_ldc_detach(vgen_ldc_t *ldcp) 16291991Sheppo { 16301991Sheppo vgen_port_t *portp; 16311991Sheppo vgen_t *vgenp; 16321991Sheppo vgen_ldc_t *pldcp; 16331991Sheppo vgen_ldc_t **prev_ldcp; 16341991Sheppo vgen_ldclist_t *ldclp; 16351991Sheppo 16361991Sheppo portp = ldcp->portp; 16371991Sheppo vgenp = portp->vgenp; 16381991Sheppo ldclp = &portp->ldclist; 16391991Sheppo 16401991Sheppo prev_ldcp = (vgen_ldc_t **)&ldclp->headp; 16411991Sheppo for (; (pldcp = *prev_ldcp) != NULL; prev_ldcp = &pldcp->nextp) { 16421991Sheppo if (pldcp == ldcp) { 16431991Sheppo break; 16441991Sheppo } 16451991Sheppo } 16461991Sheppo 16471991Sheppo if (pldcp == NULL) { 16481991Sheppo /* invalid ldcp? */ 16491991Sheppo return; 16501991Sheppo } 16511991Sheppo 16521991Sheppo if (ldcp->ldc_status != LDC_INIT) { 16531991Sheppo DWARN((vgenp->vnetp, 16541991Sheppo "vgen_ldc_detach: ldc_status is not INIT id(%lx)\n", 16551991Sheppo ldcp->ldc_id)); 16561991Sheppo } 16571991Sheppo 16581991Sheppo if (ldcp->flags & CHANNEL_ATTACHED) { 16591991Sheppo ldcp->flags &= ~(CHANNEL_ATTACHED); 16601991Sheppo 16611991Sheppo vgen_destroy_kstats(ldcp); 1662*2336Snarayan 1663*2336Snarayan /* free receive resources */ 1664*2336Snarayan if (vio_destroy_mblks(ldcp->rmp)) { 1665*2336Snarayan /* 1666*2336Snarayan * if we cannot reclaim all mblks, put this 1667*2336Snarayan * on the list of pools to be reclaimed when the 1668*2336Snarayan * device gets detached (see vgen_uninit()). 1669*2336Snarayan */ 1670*2336Snarayan ldcp->rmp->nextp = vgenp->rmp; 1671*2336Snarayan vgenp->rmp = ldcp->rmp; 1672*2336Snarayan } 1673*2336Snarayan 16741991Sheppo /* free transmit resources */ 16751991Sheppo vgen_free_tx_ring(ldcp); 1676*2336Snarayan 16771991Sheppo (void) ldc_unreg_callback(ldcp->ldc_handle); 16781991Sheppo (void) ldc_fini(ldcp->ldc_handle); 16791991Sheppo mutex_destroy(&ldcp->tclock); 16801991Sheppo mutex_destroy(&ldcp->txlock); 16811991Sheppo mutex_destroy(&ldcp->cblock); 16821991Sheppo 16831991Sheppo /* unlink it from the list */ 16841991Sheppo *prev_ldcp = ldcp->nextp; 16851991Sheppo ldclp->num_ldcs--; 16861991Sheppo KMEM_FREE(ldcp); 16871991Sheppo } 16881991Sheppo } 16891991Sheppo 16901991Sheppo /* 16911991Sheppo * This function allocates transmit resources for the channel. 16921991Sheppo * The resources consist of a transmit descriptor ring and an associated 16931991Sheppo * transmit buffer ring. 16941991Sheppo */ 16951991Sheppo static int 16961991Sheppo vgen_alloc_tx_ring(vgen_ldc_t *ldcp) 16971991Sheppo { 16981991Sheppo void *tbufp; 16991991Sheppo ldc_mem_info_t minfo; 17001991Sheppo uint32_t txdsize; 17011991Sheppo uint32_t tbufsize; 17021991Sheppo int status; 17031991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 17041991Sheppo 17051991Sheppo ldcp->num_txds = vnet_ntxds; 17061991Sheppo txdsize = sizeof (vnet_public_desc_t); 17071991Sheppo tbufsize = sizeof (vgen_private_desc_t); 17081991Sheppo 17091991Sheppo /* allocate transmit buffer ring */ 17101991Sheppo tbufp = kmem_zalloc(ldcp->num_txds * tbufsize, KM_NOSLEEP); 17111991Sheppo if (tbufp == NULL) { 17121991Sheppo return (DDI_FAILURE); 17131991Sheppo } 17141991Sheppo 17151991Sheppo /* create transmit descriptor ring */ 17161991Sheppo status = ldc_mem_dring_create(ldcp->num_txds, txdsize, 17171991Sheppo &ldcp->tx_dhandle); 17181991Sheppo if (status) { 17191991Sheppo DWARN((vnetp, "vgen_alloc_tx_ring: ldc_mem_dring_create() " 17201991Sheppo "failed, id(%lx)\n", ldcp->ldc_id)); 17211991Sheppo kmem_free(tbufp, ldcp->num_txds * tbufsize); 17221991Sheppo return (DDI_FAILURE); 17231991Sheppo } 17241991Sheppo 17251991Sheppo /* get the addr of descripror ring */ 17261991Sheppo status = ldc_mem_dring_info(ldcp->tx_dhandle, &minfo); 17271991Sheppo if (status) { 17281991Sheppo DWARN((vnetp, "vgen_alloc_tx_ring: ldc_mem_dring_info() " 17291991Sheppo "failed, id(%lx)\n", ldcp->ldc_id)); 17301991Sheppo kmem_free(tbufp, ldcp->num_txds * tbufsize); 17311991Sheppo (void) ldc_mem_dring_destroy(ldcp->tx_dhandle); 17321991Sheppo ldcp->tbufp = NULL; 17331991Sheppo return (DDI_FAILURE); 17341991Sheppo } 17351991Sheppo ldcp->txdp = (vnet_public_desc_t *)(minfo.vaddr); 17361991Sheppo ldcp->tbufp = tbufp; 17371991Sheppo 17381991Sheppo ldcp->txdendp = &((ldcp->txdp)[ldcp->num_txds]); 17391991Sheppo ldcp->tbufendp = &((ldcp->tbufp)[ldcp->num_txds]); 17401991Sheppo 17411991Sheppo return (DDI_SUCCESS); 17421991Sheppo } 17431991Sheppo 17441991Sheppo /* Free transmit resources for the channel */ 17451991Sheppo static void 17461991Sheppo vgen_free_tx_ring(vgen_ldc_t *ldcp) 17471991Sheppo { 17481991Sheppo int tbufsize = sizeof (vgen_private_desc_t); 17491991Sheppo 17501991Sheppo /* free transmit descriptor ring */ 17511991Sheppo (void) ldc_mem_dring_destroy(ldcp->tx_dhandle); 17521991Sheppo 17531991Sheppo /* free transmit buffer ring */ 17541991Sheppo kmem_free(ldcp->tbufp, ldcp->num_txds * tbufsize); 17551991Sheppo ldcp->txdp = ldcp->txdendp = NULL; 17561991Sheppo ldcp->tbufp = ldcp->tbufendp = NULL; 17571991Sheppo } 17581991Sheppo 17591991Sheppo /* enable transmit/receive on the channels for the port */ 17601991Sheppo static void 17611991Sheppo vgen_init_ldcs(vgen_port_t *portp) 17621991Sheppo { 17631991Sheppo vgen_ldclist_t *ldclp = &portp->ldclist; 17641991Sheppo vgen_ldc_t *ldcp; 17651991Sheppo 17661991Sheppo READ_ENTER(&ldclp->rwlock); 17671991Sheppo ldcp = ldclp->headp; 17681991Sheppo for (; ldcp != NULL; ldcp = ldcp->nextp) { 17691991Sheppo (void) vgen_ldc_init(ldcp); 17701991Sheppo } 17711991Sheppo RW_EXIT(&ldclp->rwlock); 17721991Sheppo } 17731991Sheppo 17741991Sheppo /* stop transmit/receive on the channels for the port */ 17751991Sheppo static void 17761991Sheppo vgen_uninit_ldcs(vgen_port_t *portp) 17771991Sheppo { 17781991Sheppo vgen_ldclist_t *ldclp = &portp->ldclist; 17791991Sheppo vgen_ldc_t *ldcp; 17801991Sheppo 17811991Sheppo READ_ENTER(&ldclp->rwlock); 17821991Sheppo ldcp = ldclp->headp; 17831991Sheppo for (; ldcp != NULL; ldcp = ldcp->nextp) { 17841991Sheppo vgen_ldc_uninit(ldcp); 17851991Sheppo } 17861991Sheppo RW_EXIT(&ldclp->rwlock); 17871991Sheppo } 17881991Sheppo 17891991Sheppo /* enable transmit/receive on the channel */ 17901991Sheppo static int 17911991Sheppo vgen_ldc_init(vgen_ldc_t *ldcp) 17921991Sheppo { 17931991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 17941991Sheppo ldc_status_t istatus; 17951991Sheppo int rv; 17961991Sheppo enum { ST_init = 0x0, ST_init_tbufs = 0x1, 17971991Sheppo ST_ldc_open = 0x2, ST_dring_bind = 0x4 17981991Sheppo } 17991991Sheppo init_state; 18001991Sheppo uint32_t ncookies = 0; 18012109Slm66018 uint32_t retries = 0; 18021991Sheppo 18031991Sheppo init_state = ST_init; 18041991Sheppo 18051991Sheppo LDC_LOCK(ldcp); 18061991Sheppo 18071991Sheppo rv = ldc_open(ldcp->ldc_handle); 18081991Sheppo if (rv != 0) { 18091991Sheppo DWARN((vnetp, 18101991Sheppo "vgen_ldcinit: ldc_open failed: id<%lx> rv(%d)\n", 18111991Sheppo ldcp->ldc_id, rv)); 18121991Sheppo goto ldcinit_failed; 18131991Sheppo } 18141991Sheppo init_state |= ST_ldc_open; 18151991Sheppo 18161991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 18171991Sheppo if (istatus != LDC_OPEN && istatus != LDC_READY) { 18181991Sheppo DWARN((vnetp, 18191991Sheppo "vgen_ldcinit: id (%lx) status(%d) is not OPEN/READY\n", 18201991Sheppo ldcp->ldc_id, istatus)); 18211991Sheppo goto ldcinit_failed; 18221991Sheppo } 18231991Sheppo ldcp->ldc_status = istatus; 18241991Sheppo 18251991Sheppo rv = vgen_init_tbufs(ldcp); 18261991Sheppo if (rv != 0) { 18271991Sheppo DWARN((vnetp, 18281991Sheppo "vgen_ldcinit: vgen_init_tbufs() failed: id(%lx)\n", 18291991Sheppo ldcp->ldc_id)); 18301991Sheppo goto ldcinit_failed; 18311991Sheppo } 18321991Sheppo init_state |= ST_init_tbufs; 18331991Sheppo 18341991Sheppo /* Bind descriptor ring to the channel */ 18351991Sheppo rv = ldc_mem_dring_bind(ldcp->ldc_handle, ldcp->tx_dhandle, 18361991Sheppo LDC_SHADOW_MAP, LDC_MEM_RW, &ldcp->tx_dcookie, &ncookies); 18371991Sheppo if (rv != 0) { 18381991Sheppo DWARN((vnetp, "vgen_ldcinit: id (%lx) " 1839*2336Snarayan "ldc_mem_dring_bind failed rv(%x)\n", ldcp->ldc_id, rv)); 18401991Sheppo goto ldcinit_failed; 18411991Sheppo } 18421991Sheppo 18431991Sheppo ASSERT(ncookies == 1); 18441991Sheppo ldcp->num_txdcookies = ncookies; 18451991Sheppo 18461991Sheppo init_state |= ST_dring_bind; 18471991Sheppo 18482109Slm66018 do { 18492109Slm66018 rv = ldc_up(ldcp->ldc_handle); 18502109Slm66018 if ((rv != 0) && (rv == EWOULDBLOCK)) { 18512109Slm66018 DBG2((vnetp, 18522109Slm66018 "vgen_ldcinit: ldc_up err id(%lx) rv(%d)\n", 18532109Slm66018 ldcp->ldc_id, rv)); 18542109Slm66018 drv_usecwait(VGEN_LDC_UP_DELAY); 18552109Slm66018 } 18562109Slm66018 if (retries++ >= vgen_ldcup_retries) 18572109Slm66018 break; 18582109Slm66018 } while (rv == EWOULDBLOCK); 18591991Sheppo 18601991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 18611991Sheppo if (istatus != LDC_UP) { 18621991Sheppo DBG2((vnetp, "vgen_ldcinit: id(%lx) status(%d) is not UP\n", 18631991Sheppo ldcp->ldc_id, istatus)); 18641991Sheppo } 18651991Sheppo ldcp->ldc_status = istatus; 18661991Sheppo 18671991Sheppo /* initialize transmit watchdog timeout */ 18681991Sheppo ldcp->wd_tid = timeout(vgen_ldc_watchdog, (caddr_t)ldcp, 18691991Sheppo drv_usectohz(vnet_ldcwd_interval * 1000)); 18701991Sheppo 18711991Sheppo ldcp->flags |= CHANNEL_STARTED; 18721991Sheppo 18731991Sheppo LDC_UNLOCK(ldcp); 18741991Sheppo return (DDI_SUCCESS); 18751991Sheppo 18761991Sheppo ldcinit_failed: 18771991Sheppo if (init_state & ST_dring_bind) { 18781991Sheppo (void) ldc_mem_dring_unbind(ldcp->tx_dhandle); 18791991Sheppo } 18801991Sheppo if (init_state & ST_init_tbufs) { 18811991Sheppo vgen_uninit_tbufs(ldcp); 18821991Sheppo } 18831991Sheppo if (init_state & ST_ldc_open) { 18841991Sheppo (void) ldc_close(ldcp->ldc_handle); 18851991Sheppo } 18861991Sheppo LDC_UNLOCK(ldcp); 18871991Sheppo return (DDI_FAILURE); 18881991Sheppo } 18891991Sheppo 18901991Sheppo /* stop transmit/receive on the channel */ 18911991Sheppo static void 18921991Sheppo vgen_ldc_uninit(vgen_ldc_t *ldcp) 18931991Sheppo { 18941991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 18951991Sheppo int rv; 18961991Sheppo 18971991Sheppo DBG1((vnetp, "vgen_ldc_uninit: enter: id(%lx)\n", ldcp->ldc_id)); 18981991Sheppo LDC_LOCK(ldcp); 18991991Sheppo 19001991Sheppo if ((ldcp->flags & CHANNEL_STARTED) == 0) { 19011991Sheppo LDC_UNLOCK(ldcp); 19021991Sheppo DWARN((vnetp, "vgen_ldc_uninit: id(%lx) CHANNEL_STARTED" 19031991Sheppo " flag is not set\n", ldcp->ldc_id)); 19041991Sheppo return; 19051991Sheppo } 19061991Sheppo 19071991Sheppo /* disable further callbacks */ 19081991Sheppo rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE); 19091991Sheppo if (rv != 0) { 19101991Sheppo DWARN((vnetp, "vgen_ldc_uninit: id (%lx) " 19111991Sheppo "ldc_set_cb_mode failed\n", ldcp->ldc_id)); 19121991Sheppo } 19131991Sheppo 19141991Sheppo /* clear handshake done bit and wait for pending tx and cb to finish */ 19151991Sheppo ldcp->hphase &= ~(VH_DONE); 19161991Sheppo LDC_UNLOCK(ldcp); 19171991Sheppo drv_usecwait(1000); 19181991Sheppo LDC_LOCK(ldcp); 19191991Sheppo 19201991Sheppo vgen_reset_hphase(ldcp); 19211991Sheppo 19221991Sheppo /* reset transmit watchdog timeout */ 19231991Sheppo if (ldcp->wd_tid) { 19241991Sheppo (void) untimeout(ldcp->wd_tid); 19251991Sheppo ldcp->wd_tid = 0; 19261991Sheppo } 19271991Sheppo 19281991Sheppo /* unbind tx descriptor ring from the channel */ 19291991Sheppo rv = ldc_mem_dring_unbind(ldcp->tx_dhandle); 19301991Sheppo if (rv != 0) { 19311991Sheppo DWARN((vnetp, "vgen_ldcuninit: ldc_mem_dring_unbind " 19321991Sheppo "failed id(%lx)\n", ldcp->ldc_id)); 19331991Sheppo } 19341991Sheppo 19351991Sheppo vgen_uninit_tbufs(ldcp); 19361991Sheppo 19371991Sheppo rv = ldc_close(ldcp->ldc_handle); 19381991Sheppo if (rv != 0) { 19391991Sheppo DWARN((vnetp, "vgen_ldcuninit: ldc_close err id(%lx)\n", 19401991Sheppo ldcp->ldc_id)); 19411991Sheppo } 19421991Sheppo ldcp->ldc_status = LDC_INIT; 19431991Sheppo ldcp->flags &= ~(CHANNEL_STARTED); 19441991Sheppo 19451991Sheppo LDC_UNLOCK(ldcp); 19461991Sheppo 19471991Sheppo DBG1((vnetp, "vgen_ldc_uninit: exit: id(%lx)\n", ldcp->ldc_id)); 19481991Sheppo } 19491991Sheppo 19501991Sheppo /* Initialize the transmit buffer ring for the channel */ 19511991Sheppo static int 19521991Sheppo vgen_init_tbufs(vgen_ldc_t *ldcp) 19531991Sheppo { 19541991Sheppo vgen_private_desc_t *tbufp; 19551991Sheppo vnet_public_desc_t *txdp; 19561991Sheppo vio_dring_entry_hdr_t *hdrp; 19571991Sheppo int i; 19581991Sheppo int rv; 19592109Slm66018 caddr_t datap = NULL; 19602109Slm66018 int ci; 19612109Slm66018 uint32_t ncookies; 19621991Sheppo 19631991Sheppo bzero(ldcp->tbufp, sizeof (*tbufp) * (ldcp->num_txds)); 19641991Sheppo bzero(ldcp->txdp, sizeof (*txdp) * (ldcp->num_txds)); 19651991Sheppo 1966*2336Snarayan datap = kmem_zalloc(ldcp->num_txds * VGEN_DBLK_SZ, KM_SLEEP); 19672109Slm66018 ldcp->tx_datap = datap; 19682109Slm66018 19691991Sheppo /* 19702109Slm66018 * for each private descriptor, allocate a ldc mem_handle which is 19711991Sheppo * required to map the data during transmit, set the flags 19721991Sheppo * to free (available for use by transmit routine). 19731991Sheppo */ 19741991Sheppo 19751991Sheppo for (i = 0; i < ldcp->num_txds; i++) { 19762109Slm66018 19771991Sheppo tbufp = &(ldcp->tbufp[i]); 19781991Sheppo rv = ldc_mem_alloc_handle(ldcp->ldc_handle, 19791991Sheppo &(tbufp->memhandle)); 19801991Sheppo if (rv) { 19811991Sheppo tbufp->memhandle = 0; 19821991Sheppo goto init_tbufs_failed; 19831991Sheppo } 19842109Slm66018 19852109Slm66018 /* 19862109Slm66018 * bind ldc memhandle to the corresponding transmit buffer. 19872109Slm66018 */ 19882109Slm66018 ci = ncookies = 0; 19892109Slm66018 rv = ldc_mem_bind_handle(tbufp->memhandle, 1990*2336Snarayan (caddr_t)datap, VGEN_DBLK_SZ, LDC_SHADOW_MAP, 19912109Slm66018 LDC_MEM_R, &(tbufp->memcookie[ci]), &ncookies); 19922109Slm66018 if (rv != 0) { 19932109Slm66018 goto init_tbufs_failed; 19942109Slm66018 } 19952109Slm66018 19962109Slm66018 /* 19972109Slm66018 * successful in binding the handle to tx data buffer. 19982109Slm66018 * set datap in the private descr to this buffer. 19992109Slm66018 */ 20002109Slm66018 tbufp->datap = datap; 20012109Slm66018 20022109Slm66018 if ((ncookies == 0) || 2003*2336Snarayan (ncookies > MAX_COOKIES)) { 20042109Slm66018 goto init_tbufs_failed; 20052109Slm66018 } 20062109Slm66018 20072109Slm66018 for (ci = 1; ci < ncookies; ci++) { 20082109Slm66018 rv = ldc_mem_nextcookie(tbufp->memhandle, 2009*2336Snarayan &(tbufp->memcookie[ci])); 20102109Slm66018 if (rv != 0) { 20112109Slm66018 goto init_tbufs_failed; 20122109Slm66018 } 20132109Slm66018 } 20142109Slm66018 20152109Slm66018 tbufp->ncookies = ncookies; 2016*2336Snarayan datap += VGEN_DBLK_SZ; 20172109Slm66018 20181991Sheppo tbufp->flags = VGEN_PRIV_DESC_FREE; 20191991Sheppo txdp = &(ldcp->txdp[i]); 20201991Sheppo hdrp = &txdp->hdr; 20211991Sheppo hdrp->dstate = VIO_DESC_FREE; 20221991Sheppo hdrp->ack = B_FALSE; 20231991Sheppo tbufp->descp = txdp; 20242109Slm66018 20251991Sheppo } 20261991Sheppo 20271991Sheppo /* reset tbuf walking pointers */ 20281991Sheppo ldcp->next_tbufp = ldcp->tbufp; 20291991Sheppo ldcp->cur_tbufp = ldcp->tbufp; 20301991Sheppo 20311991Sheppo /* initialize tx seqnum and index */ 20321991Sheppo ldcp->next_txseq = VNET_ISS; 20331991Sheppo ldcp->next_txi = 0; 20341991Sheppo 2035*2336Snarayan ldcp->resched_peer = B_TRUE; 2036*2336Snarayan 20371991Sheppo return (DDI_SUCCESS); 20381991Sheppo 20391991Sheppo init_tbufs_failed:; 20401991Sheppo vgen_uninit_tbufs(ldcp); 20411991Sheppo return (DDI_FAILURE); 20421991Sheppo } 20431991Sheppo 20441991Sheppo /* Uninitialize transmit buffer ring for the channel */ 20451991Sheppo static void 20461991Sheppo vgen_uninit_tbufs(vgen_ldc_t *ldcp) 20471991Sheppo { 20481991Sheppo vgen_private_desc_t *tbufp = ldcp->tbufp; 20491991Sheppo vnet_public_desc_t *txdp; 20501991Sheppo vio_dring_entry_hdr_t *hdrp; 20511991Sheppo int i; 20521991Sheppo 20531991Sheppo /* for each tbuf (priv_desc), free ldc mem_handle */ 20541991Sheppo for (i = 0; i < ldcp->num_txds; i++) { 20551991Sheppo 20561991Sheppo tbufp = &(ldcp->tbufp[i]); 20571991Sheppo txdp = tbufp->descp; 20581991Sheppo hdrp = &txdp->hdr; 20591991Sheppo 20602109Slm66018 if (tbufp->datap) { /* if bound to a ldc memhandle */ 20611991Sheppo (void) ldc_mem_unbind_handle(tbufp->memhandle); 20622109Slm66018 tbufp->datap = NULL; 20631991Sheppo } 20642109Slm66018 tbufp->flags = VGEN_PRIV_DESC_FREE; 20652109Slm66018 hdrp->dstate = VIO_DESC_FREE; 20662109Slm66018 hdrp->ack = B_FALSE; 20671991Sheppo if (tbufp->memhandle) { 20681991Sheppo (void) ldc_mem_free_handle(tbufp->memhandle); 20691991Sheppo tbufp->memhandle = 0; 20701991Sheppo } 20711991Sheppo tbufp->descp = NULL; 20721991Sheppo } 20731991Sheppo 20742109Slm66018 if (ldcp->tx_datap) { 20752109Slm66018 /* prealloc'd tx data buffer */ 2076*2336Snarayan kmem_free(ldcp->tx_datap, ldcp->num_txds * VGEN_DBLK_SZ); 20772109Slm66018 ldcp->tx_datap = NULL; 20782109Slm66018 } 20792109Slm66018 20801991Sheppo bzero(ldcp->tbufp, sizeof (*tbufp) * (ldcp->num_txds)); 20811991Sheppo bzero(ldcp->txdp, sizeof (*txdp) * (ldcp->num_txds)); 20821991Sheppo } 20831991Sheppo 20841991Sheppo /* clobber tx descriptor ring */ 20851991Sheppo static void 20861991Sheppo vgen_clobber_tbufs(vgen_ldc_t *ldcp) 20871991Sheppo { 20881991Sheppo vnet_public_desc_t *txdp; 20891991Sheppo vgen_private_desc_t *tbufp; 20901991Sheppo vio_dring_entry_hdr_t *hdrp; 20911991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 20921991Sheppo int i; 20931991Sheppo #ifdef DEBUG 20941991Sheppo int ndone = 0; 20951991Sheppo #endif 20961991Sheppo 20971991Sheppo for (i = 0; i < ldcp->num_txds; i++) { 20981991Sheppo 20991991Sheppo tbufp = &(ldcp->tbufp[i]); 21001991Sheppo txdp = tbufp->descp; 21011991Sheppo hdrp = &txdp->hdr; 21021991Sheppo 21031991Sheppo if (tbufp->flags & VGEN_PRIV_DESC_BUSY) { 21041991Sheppo tbufp->flags = VGEN_PRIV_DESC_FREE; 21051991Sheppo #ifdef DEBUG 21061991Sheppo if (hdrp->dstate == VIO_DESC_DONE) 21071991Sheppo ndone++; 21081991Sheppo #endif 21091991Sheppo hdrp->dstate = VIO_DESC_FREE; 21101991Sheppo hdrp->ack = B_FALSE; 21111991Sheppo } 21121991Sheppo } 21131991Sheppo /* reset tbuf walking pointers */ 21141991Sheppo ldcp->next_tbufp = ldcp->tbufp; 21151991Sheppo ldcp->cur_tbufp = ldcp->tbufp; 21161991Sheppo 21171991Sheppo /* reset tx seqnum and index */ 21181991Sheppo ldcp->next_txseq = VNET_ISS; 21191991Sheppo ldcp->next_txi = 0; 2120*2336Snarayan 2121*2336Snarayan ldcp->resched_peer = B_TRUE; 2122*2336Snarayan 21231991Sheppo #ifdef DEBUG 21241991Sheppo DBG2((vnetp, 21251991Sheppo "vgen_clobber_tbufs: id(0x%lx) num descrs done (%d)\n", 21261991Sheppo ldcp->ldc_id, ndone)); 21271991Sheppo #endif 21281991Sheppo } 21291991Sheppo 21301991Sheppo /* clobber receive descriptor ring */ 21311991Sheppo static void 21321991Sheppo vgen_clobber_rxds(vgen_ldc_t *ldcp) 21331991Sheppo { 21341991Sheppo ldcp->rx_dhandle = 0; 21351991Sheppo bzero(&ldcp->rx_dcookie, sizeof (ldcp->rx_dcookie)); 21361991Sheppo ldcp->rxdp = NULL; 21371991Sheppo ldcp->next_rxi = 0; 21381991Sheppo ldcp->num_rxds = 0; 21391991Sheppo ldcp->next_rxseq = VNET_ISS; 21401991Sheppo } 21411991Sheppo 21421991Sheppo /* initialize receive descriptor ring */ 21431991Sheppo static int 21441991Sheppo vgen_init_rxds(vgen_ldc_t *ldcp, uint32_t num_desc, uint32_t desc_size, 21451991Sheppo ldc_mem_cookie_t *dcookie, uint32_t ncookies) 21461991Sheppo { 21471991Sheppo int rv; 21481991Sheppo ldc_mem_info_t minfo; 21491991Sheppo 21501991Sheppo rv = ldc_mem_dring_map(ldcp->ldc_handle, dcookie, ncookies, num_desc, 21511991Sheppo desc_size, LDC_SHADOW_MAP, &(ldcp->rx_dhandle)); 21521991Sheppo if (rv != 0) { 21531991Sheppo return (DDI_FAILURE); 21541991Sheppo } 21551991Sheppo 21561991Sheppo /* 21571991Sheppo * sucessfully mapped, now try to 21581991Sheppo * get info about the mapped dring 21591991Sheppo */ 21601991Sheppo rv = ldc_mem_dring_info(ldcp->rx_dhandle, &minfo); 21611991Sheppo if (rv != 0) { 21621991Sheppo (void) ldc_mem_dring_unmap(ldcp->rx_dhandle); 21631991Sheppo return (DDI_FAILURE); 21641991Sheppo } 21651991Sheppo 21661991Sheppo /* 21671991Sheppo * save ring address, number of descriptors. 21681991Sheppo */ 21691991Sheppo ldcp->rxdp = (vnet_public_desc_t *)(minfo.vaddr); 21701991Sheppo bcopy(dcookie, &(ldcp->rx_dcookie), sizeof (*dcookie)); 21711991Sheppo ldcp->num_rxdcookies = ncookies; 21721991Sheppo ldcp->num_rxds = num_desc; 21731991Sheppo ldcp->next_rxi = 0; 21741991Sheppo ldcp->next_rxseq = VNET_ISS; 21751991Sheppo 21761991Sheppo return (DDI_SUCCESS); 21771991Sheppo } 21781991Sheppo 21791991Sheppo /* get channel statistics */ 21801991Sheppo static uint64_t 21812311Sseb vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat) 21821991Sheppo { 21831991Sheppo vgen_stats_t *statsp; 21841991Sheppo uint64_t val; 21851991Sheppo 21861991Sheppo val = 0; 21871991Sheppo statsp = ldcp->statsp; 21881991Sheppo switch (stat) { 21891991Sheppo 21901991Sheppo case MAC_STAT_MULTIRCV: 21911991Sheppo val = statsp->multircv; 21921991Sheppo break; 21931991Sheppo 21941991Sheppo case MAC_STAT_BRDCSTRCV: 21951991Sheppo val = statsp->brdcstrcv; 21961991Sheppo break; 21971991Sheppo 21981991Sheppo case MAC_STAT_MULTIXMT: 21991991Sheppo val = statsp->multixmt; 22001991Sheppo break; 22011991Sheppo 22021991Sheppo case MAC_STAT_BRDCSTXMT: 22031991Sheppo val = statsp->brdcstxmt; 22041991Sheppo break; 22051991Sheppo 22061991Sheppo case MAC_STAT_NORCVBUF: 22071991Sheppo val = statsp->norcvbuf; 22081991Sheppo break; 22091991Sheppo 22101991Sheppo case MAC_STAT_IERRORS: 22111991Sheppo val = statsp->ierrors; 22121991Sheppo break; 22131991Sheppo 22141991Sheppo case MAC_STAT_NOXMTBUF: 22151991Sheppo val = statsp->noxmtbuf; 22161991Sheppo break; 22171991Sheppo 22181991Sheppo case MAC_STAT_OERRORS: 22191991Sheppo val = statsp->oerrors; 22201991Sheppo break; 22211991Sheppo 22221991Sheppo case MAC_STAT_COLLISIONS: 22231991Sheppo break; 22241991Sheppo 22251991Sheppo case MAC_STAT_RBYTES: 22261991Sheppo val = statsp->rbytes; 22271991Sheppo break; 22281991Sheppo 22291991Sheppo case MAC_STAT_IPACKETS: 22301991Sheppo val = statsp->ipackets; 22311991Sheppo break; 22321991Sheppo 22331991Sheppo case MAC_STAT_OBYTES: 22341991Sheppo val = statsp->obytes; 22351991Sheppo break; 22361991Sheppo 22371991Sheppo case MAC_STAT_OPACKETS: 22381991Sheppo val = statsp->opackets; 22391991Sheppo break; 22401991Sheppo 22411991Sheppo /* stats not relevant to ldc, return 0 */ 22421991Sheppo case MAC_STAT_IFSPEED: 22432311Sseb case ETHER_STAT_ALIGN_ERRORS: 22442311Sseb case ETHER_STAT_FCS_ERRORS: 22452311Sseb case ETHER_STAT_FIRST_COLLISIONS: 22462311Sseb case ETHER_STAT_MULTI_COLLISIONS: 22472311Sseb case ETHER_STAT_DEFER_XMTS: 22482311Sseb case ETHER_STAT_TX_LATE_COLLISIONS: 22492311Sseb case ETHER_STAT_EX_COLLISIONS: 22502311Sseb case ETHER_STAT_MACXMT_ERRORS: 22512311Sseb case ETHER_STAT_CARRIER_ERRORS: 22522311Sseb case ETHER_STAT_TOOLONG_ERRORS: 22532311Sseb case ETHER_STAT_XCVR_ADDR: 22542311Sseb case ETHER_STAT_XCVR_ID: 22552311Sseb case ETHER_STAT_XCVR_INUSE: 22562311Sseb case ETHER_STAT_CAP_1000FDX: 22572311Sseb case ETHER_STAT_CAP_1000HDX: 22582311Sseb case ETHER_STAT_CAP_100FDX: 22592311Sseb case ETHER_STAT_CAP_100HDX: 22602311Sseb case ETHER_STAT_CAP_10FDX: 22612311Sseb case ETHER_STAT_CAP_10HDX: 22622311Sseb case ETHER_STAT_CAP_ASMPAUSE: 22632311Sseb case ETHER_STAT_CAP_PAUSE: 22642311Sseb case ETHER_STAT_CAP_AUTONEG: 22652311Sseb case ETHER_STAT_ADV_CAP_1000FDX: 22662311Sseb case ETHER_STAT_ADV_CAP_1000HDX: 22672311Sseb case ETHER_STAT_ADV_CAP_100FDX: 22682311Sseb case ETHER_STAT_ADV_CAP_100HDX: 22692311Sseb case ETHER_STAT_ADV_CAP_10FDX: 22702311Sseb case ETHER_STAT_ADV_CAP_10HDX: 22712311Sseb case ETHER_STAT_ADV_CAP_ASMPAUSE: 22722311Sseb case ETHER_STAT_ADV_CAP_PAUSE: 22732311Sseb case ETHER_STAT_ADV_CAP_AUTONEG: 22742311Sseb case ETHER_STAT_LP_CAP_1000FDX: 22752311Sseb case ETHER_STAT_LP_CAP_1000HDX: 22762311Sseb case ETHER_STAT_LP_CAP_100FDX: 22772311Sseb case ETHER_STAT_LP_CAP_100HDX: 22782311Sseb case ETHER_STAT_LP_CAP_10FDX: 22792311Sseb case ETHER_STAT_LP_CAP_10HDX: 22802311Sseb case ETHER_STAT_LP_CAP_ASMPAUSE: 22812311Sseb case ETHER_STAT_LP_CAP_PAUSE: 22822311Sseb case ETHER_STAT_LP_CAP_AUTONEG: 22832311Sseb case ETHER_STAT_LINK_ASMPAUSE: 22842311Sseb case ETHER_STAT_LINK_PAUSE: 22852311Sseb case ETHER_STAT_LINK_AUTONEG: 22862311Sseb case ETHER_STAT_LINK_DUPLEX: 22871991Sheppo default: 22881991Sheppo val = 0; 22891991Sheppo break; 22901991Sheppo 22911991Sheppo } 22921991Sheppo return (val); 22931991Sheppo } 22941991Sheppo 22951991Sheppo /* Interrupt handler for the channel */ 22961991Sheppo static uint_t 22971991Sheppo vgen_ldc_cb(uint64_t event, caddr_t arg) 22981991Sheppo { 22991991Sheppo _NOTE(ARGUNUSED(event)) 23001991Sheppo vgen_ldc_t *ldcp; 23011991Sheppo void *vnetp; 23021991Sheppo vgen_t *vgenp; 23031991Sheppo size_t msglen; 23041991Sheppo ldc_status_t istatus; 23051991Sheppo uint64_t ldcmsg[7]; 23061991Sheppo int rv; 23071991Sheppo vio_msg_tag_t *tagp; 23081991Sheppo mblk_t *mp = NULL; 23091991Sheppo mblk_t *bp = NULL; 23101991Sheppo mblk_t *bpt = NULL; 23111991Sheppo mblk_t *headp = NULL; 23121991Sheppo mblk_t *tailp = NULL; 23131991Sheppo vgen_stats_t *statsp; 23141991Sheppo 23151991Sheppo ldcp = (vgen_ldc_t *)arg; 23161991Sheppo vgenp = LDC_TO_VGEN(ldcp); 23171991Sheppo vnetp = LDC_TO_VNET(ldcp); 23181991Sheppo statsp = ldcp->statsp; 23191991Sheppo 23201991Sheppo DBG1((vnetp, "vgen_ldc_cb enter: ldcid (%lx)\n", ldcp->ldc_id)); 23211991Sheppo 23221991Sheppo mutex_enter(&ldcp->cblock); 23231991Sheppo statsp->callbacks++; 23241991Sheppo if ((ldcp->ldc_status == LDC_INIT) || (ldcp->ldc_handle == NULL)) { 23251991Sheppo DWARN((vnetp, "vgen_ldc_cb: id(%lx), status(%d) is LDC_INIT\n", 23261991Sheppo ldcp->ldc_id, ldcp->ldc_status)); 23271991Sheppo mutex_exit(&ldcp->cblock); 23281991Sheppo return (LDC_SUCCESS); 23291991Sheppo } 23301991Sheppo 23311991Sheppo /* check ldc status change events first */ 23321991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 23331991Sheppo 23341991Sheppo if (istatus != ldcp->ldc_status) { 23351991Sheppo switch (istatus) { 23361991Sheppo case LDC_UP: 23371991Sheppo ldcp->ldc_status = istatus; 23381991Sheppo DBG1((vnetp, 23391991Sheppo "vgen_ldc_cb: id(%lx) status(%d) is LDC_UP\n", 23401991Sheppo ldcp->ldc_id, ldcp->ldc_status)); 23411991Sheppo 23421991Sheppo if (ldcp->portp != vgenp->vsw_portp) { 23431991Sheppo /* 23441991Sheppo * modify fdb entry to use this port as the 23451991Sheppo * channel is up, instead of going through the 23461991Sheppo * vsw-port (see comments in vgen_port_init()) 23471991Sheppo */ 23481991Sheppo vnet_modify_fdb(vnetp, 23491991Sheppo (uint8_t *)&ldcp->portp->macaddr, 23501991Sheppo vgen_tx, ldcp->portp); 23511991Sheppo } 23521991Sheppo /* Initialize local session id */ 23531991Sheppo ldcp->local_sid = ddi_get_lbolt(); 23541991Sheppo /* clear peer session id */ 23551991Sheppo ldcp->peer_sid = 0; 23561991Sheppo ldcp->hretries = 0; 23571991Sheppo /* Initiate Handshake process with peer ldc endpoint */ 23581991Sheppo vgen_handshake_reset(ldcp); 23591991Sheppo vgen_handshake(vh_nextphase(ldcp)); 23601991Sheppo break; 23611991Sheppo 23621991Sheppo case LDC_OPEN: 23631991Sheppo case LDC_READY: 23641991Sheppo ldcp->ldc_status = istatus; 23651991Sheppo if ((ldcp->portp != vgenp->vsw_portp) && 23661991Sheppo (vgenp->vsw_portp != NULL)) { 23671991Sheppo /* 23681991Sheppo * modify fdb entry to use vsw-port as the 23691991Sheppo * channel is reset and we don't have a direct 23701991Sheppo * link to the destination (see comments 23711991Sheppo * in vgen_port_init()). 23721991Sheppo */ 23731991Sheppo vnet_modify_fdb(vnetp, 23741991Sheppo (uint8_t *)&ldcp->portp->macaddr, 23751991Sheppo vgen_tx, vgenp->vsw_portp); 23761991Sheppo } 23771991Sheppo /* clear sids */ 23781991Sheppo ldcp->local_sid = 0; 23791991Sheppo ldcp->peer_sid = 0; 23801991Sheppo if (ldcp->hphase != VH_PHASE0) { 23811991Sheppo vgen_handshake_reset(ldcp); 23821991Sheppo } 23831991Sheppo DBG1((vnetp, 23841991Sheppo "vgen_ldc_cb: id(%lx) status is (%d)\n", 23851991Sheppo ldcp->ldc_id, ldcp->ldc_status)); 23861991Sheppo break; 23871991Sheppo 23881991Sheppo default: 23891991Sheppo DWARN((vnetp, 23901991Sheppo "vgen_ldc_cb: id(%lx) istatus=(%d) status(%d) is" 23911991Sheppo " *UNKNOWN*\n", 23921991Sheppo ldcp->ldc_id, istatus, ldcp->ldc_status)); 23931991Sheppo break; 23941991Sheppo } 23951991Sheppo } 23961991Sheppo 23971991Sheppo if (istatus != LDC_UP) { 23981991Sheppo DBG1((vnetp, "vgen_ldc_cb: id(%lx) status(%d) is NOT LDC_UP\n", 23991991Sheppo ldcp->ldc_id, ldcp->ldc_status)); 24001991Sheppo mutex_exit(&ldcp->cblock); 24011991Sheppo return (LDC_SUCCESS); 24021991Sheppo } 24031991Sheppo 24041991Sheppo /* if ldc_status is UP, receive all packets */ 24051991Sheppo do { 24061991Sheppo msglen = sizeof (ldcmsg); 24071991Sheppo rv = ldc_read(ldcp->ldc_handle, (caddr_t)&ldcmsg, &msglen); 24081991Sheppo 24091991Sheppo if (rv != 0) { 24101991Sheppo DWARN((vnetp, 24111991Sheppo "vgen_ldc_cb:ldc_read err id(%lx) rv(%d) " 24121991Sheppo "len(%d)\n", ldcp->ldc_id, rv, msglen)); 24131991Sheppo break; 24141991Sheppo } 24151991Sheppo if (msglen == 0) { 24161991Sheppo DBG2((vnetp, "vgen_ldc_cb: ldc_read id(%lx) NODATA", 24171991Sheppo ldcp->ldc_id)); 24181991Sheppo break; 24191991Sheppo } 24201991Sheppo DBG2((vnetp, "vgen_ldc_cb: ldc_read id(%lx): msglen(%d)", 24211991Sheppo ldcp->ldc_id, msglen)); 24221991Sheppo 24231991Sheppo tagp = (vio_msg_tag_t *)ldcmsg; 24241991Sheppo 24251991Sheppo if (ldcp->peer_sid) { 24261991Sheppo /* 24271991Sheppo * check sid only after we have received peer's sid 24281991Sheppo * in the version negotiate msg. 24291991Sheppo */ 24301991Sheppo #ifdef DEBUG 24311991Sheppo if (vgen_hdbg & HDBG_BAD_SID) { 24321991Sheppo /* simulate bad sid condition */ 24331991Sheppo tagp->vio_sid = 0; 24341991Sheppo vgen_hdbg &= ~(HDBG_BAD_SID); 24351991Sheppo } 24361991Sheppo #endif 24371991Sheppo if (vgen_check_sid(ldcp, tagp) == VGEN_FAILURE) { 24381991Sheppo /* 24391991Sheppo * If sid mismatch is detected, 24401991Sheppo * reset the channel. 24411991Sheppo */ 24421991Sheppo ldcp->need_ldc_reset = B_TRUE; 24431991Sheppo vgen_handshake_reset(ldcp); 24441991Sheppo mutex_exit(&ldcp->cblock); 24451991Sheppo return (LDC_SUCCESS); 24461991Sheppo } 24471991Sheppo } 24481991Sheppo 24491991Sheppo switch (tagp->vio_msgtype) { 24501991Sheppo case VIO_TYPE_CTRL: 24511991Sheppo vgen_handle_ctrlmsg(ldcp, tagp); 24521991Sheppo break; 24531991Sheppo 24541991Sheppo case VIO_TYPE_DATA: 24551991Sheppo headp = tailp = NULL; 24561991Sheppo vgen_handle_datamsg(ldcp, tagp, &headp, &tailp); 24571991Sheppo /* build a chain of received packets */ 24581991Sheppo if (headp != NULL) { 24591991Sheppo if (bp == NULL) { 24601991Sheppo bp = headp; 24611991Sheppo bpt = tailp; 24621991Sheppo } else { 24631991Sheppo bpt->b_next = headp; 24641991Sheppo bpt = tailp; 24651991Sheppo } 24661991Sheppo } 24671991Sheppo break; 24681991Sheppo 24691991Sheppo case VIO_TYPE_ERR: 24701991Sheppo vgen_handle_errmsg(ldcp, tagp); 24711991Sheppo break; 24721991Sheppo 24731991Sheppo default: 24741991Sheppo DWARN((vnetp, 24751991Sheppo "vgen_ldc_cb: Unknown VIO_TYPE(%x)\n", 24761991Sheppo tagp->vio_msgtype)); 24771991Sheppo break; 24781991Sheppo } 24791991Sheppo 24801991Sheppo } while (msglen); 24811991Sheppo 24821991Sheppo mutex_exit(&ldcp->cblock); 24831991Sheppo /* send up the received packets to MAC layer */ 24841991Sheppo while (bp != NULL) { 24851991Sheppo mp = bp; 24861991Sheppo bp = bp->b_next; 24871991Sheppo mp->b_next = mp->b_prev = NULL; 24881991Sheppo DBG2((vnetp, "vgen_ldc_cb: id(%lx) rx pkt len (%lx)\n", 24891991Sheppo ldcp->ldc_id, MBLKL(mp))); 24902311Sseb vnet_rx(vgenp->vnetp, NULL, mp); 24911991Sheppo } 24921991Sheppo DBG1((vnetp, "vgen_ldc_cb exit: ldcid (%lx)\n", ldcp->ldc_id)); 24931991Sheppo 24941991Sheppo return (LDC_SUCCESS); 24951991Sheppo } 24961991Sheppo 24971991Sheppo /* vgen handshake functions */ 24981991Sheppo 24991991Sheppo /* change the hphase for the channel to the next phase */ 25001991Sheppo static vgen_ldc_t * 25011991Sheppo vh_nextphase(vgen_ldc_t *ldcp) 25021991Sheppo { 25031991Sheppo if (ldcp->hphase == VH_PHASE3) { 25041991Sheppo ldcp->hphase = VH_DONE; 25051991Sheppo } else { 25061991Sheppo ldcp->hphase++; 25071991Sheppo } 25081991Sheppo return (ldcp); 25091991Sheppo } 25101991Sheppo 25111991Sheppo /* 25121991Sheppo * Check whether the given version is supported or not and 25131991Sheppo * return VGEN_SUCCESS if supported. 25141991Sheppo */ 25151991Sheppo static int 25161991Sheppo vgen_supported_version(vgen_ldc_t *ldcp, uint16_t ver_major, 25171991Sheppo uint16_t ver_minor) 25181991Sheppo { 25191991Sheppo vgen_ver_t *versions = ldcp->vgen_versions; 25201991Sheppo int i = 0; 25211991Sheppo 25221991Sheppo while (i < VGEN_NUM_VER) { 25231991Sheppo if ((versions[i].ver_major == 0) && 25241991Sheppo (versions[i].ver_minor == 0)) { 25251991Sheppo break; 25261991Sheppo } 25271991Sheppo if ((versions[i].ver_major == ver_major) && 25281991Sheppo (versions[i].ver_minor == ver_minor)) { 25291991Sheppo return (VGEN_SUCCESS); 25301991Sheppo } 25311991Sheppo i++; 25321991Sheppo } 25331991Sheppo return (VGEN_FAILURE); 25341991Sheppo } 25351991Sheppo 25361991Sheppo /* 25371991Sheppo * Given a version, return VGEN_SUCCESS if a lower version is supported. 25381991Sheppo */ 25391991Sheppo static int 25401991Sheppo vgen_next_version(vgen_ldc_t *ldcp, vgen_ver_t *verp) 25411991Sheppo { 25421991Sheppo vgen_ver_t *versions = ldcp->vgen_versions; 25431991Sheppo int i = 0; 25441991Sheppo 25451991Sheppo while (i < VGEN_NUM_VER) { 25461991Sheppo if ((versions[i].ver_major == 0) && 25471991Sheppo (versions[i].ver_minor == 0)) { 25481991Sheppo break; 25491991Sheppo } 25501991Sheppo /* 25511991Sheppo * if we support a lower minor version within the same major 25521991Sheppo * version, or if we support a lower major version, 25531991Sheppo * update the verp parameter with this lower version and 25541991Sheppo * return success. 25551991Sheppo */ 25561991Sheppo if (((versions[i].ver_major == verp->ver_major) && 25571991Sheppo (versions[i].ver_minor < verp->ver_minor)) || 25581991Sheppo (versions[i].ver_major < verp->ver_major)) { 25591991Sheppo verp->ver_major = versions[i].ver_major; 25601991Sheppo verp->ver_minor = versions[i].ver_minor; 25611991Sheppo return (VGEN_SUCCESS); 25621991Sheppo } 25631991Sheppo i++; 25641991Sheppo } 25651991Sheppo 25661991Sheppo return (VGEN_FAILURE); 25671991Sheppo } 25681991Sheppo 25691991Sheppo /* 25701991Sheppo * wrapper routine to send the given message over ldc using ldc_write(). 25711991Sheppo */ 25721991Sheppo static int 25731991Sheppo vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg, size_t msglen, 25741991Sheppo boolean_t caller_holds_lock) 25751991Sheppo { 25761991Sheppo int rv; 25771991Sheppo size_t len; 25781991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 25791991Sheppo uint32_t retries = 0; 25801991Sheppo 25811991Sheppo len = msglen; 25821991Sheppo if ((len == 0) || (msg == NULL)) 25831991Sheppo return (VGEN_FAILURE); 25841991Sheppo 25851991Sheppo if (!caller_holds_lock) { 25861991Sheppo mutex_enter(&ldcp->txlock); 25871991Sheppo } 25881991Sheppo 25891991Sheppo do { 25901991Sheppo len = msglen; 25911991Sheppo rv = ldc_write(ldcp->ldc_handle, (caddr_t)msg, &len); 25921991Sheppo if (retries++ >= vgen_ldcwr_retries) 25931991Sheppo break; 25941991Sheppo } while (rv == EWOULDBLOCK); 25951991Sheppo 25961991Sheppo if (!caller_holds_lock) { 25971991Sheppo mutex_exit(&ldcp->txlock); 25981991Sheppo } 25991991Sheppo 26001991Sheppo if ((rv != 0) || (len != msglen)) { 26011991Sheppo DWARN((vnetp, 26021991Sheppo "vgen_sendmsg: ldc_write failed: id(%lx) rv(%d)" 26031991Sheppo " msglen (%d)\n", ldcp->ldc_id, rv, msglen)); 26041991Sheppo return (VGEN_FAILURE); 26051991Sheppo } 26061991Sheppo return (VGEN_SUCCESS); 26071991Sheppo } 26081991Sheppo 26091991Sheppo /* send version negotiate message to the peer over ldc */ 26101991Sheppo static int 26111991Sheppo vgen_send_version_negotiate(vgen_ldc_t *ldcp) 26121991Sheppo { 26131991Sheppo vio_ver_msg_t vermsg; 26141991Sheppo vio_msg_tag_t *tagp = &vermsg.tag; 26151991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 26161991Sheppo int rv; 26171991Sheppo 26181991Sheppo bzero(&vermsg, sizeof (vermsg)); 26191991Sheppo 26201991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 26211991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 26221991Sheppo tagp->vio_subtype_env = VIO_VER_INFO; 26231991Sheppo tagp->vio_sid = ldcp->local_sid; 26241991Sheppo 26251991Sheppo /* get version msg payload from ldcp->local */ 26261991Sheppo vermsg.ver_major = ldcp->local_hparams.ver_major; 26271991Sheppo vermsg.ver_minor = ldcp->local_hparams.ver_minor; 26281991Sheppo vermsg.dev_class = ldcp->local_hparams.dev_class; 26291991Sheppo 26301991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vermsg), B_FALSE); 26311991Sheppo if (rv != VGEN_SUCCESS) { 26321991Sheppo DWARN((vnetp, "vgen_send_version_negotiate: vgen_sendmsg failed" 26331991Sheppo "id (%lx)\n", ldcp->ldc_id)); 26341991Sheppo return (VGEN_FAILURE); 26351991Sheppo } 26361991Sheppo 26371991Sheppo ldcp->hstate |= VER_INFO_SENT; 26381991Sheppo DBG2((vnetp, 26391991Sheppo "vgen_send_version_negotiate: VER_INFO_SENT id (%lx) ver(%d,%d)\n", 26401991Sheppo ldcp->ldc_id, vermsg.ver_major, vermsg.ver_minor)); 26411991Sheppo 26421991Sheppo return (VGEN_SUCCESS); 26431991Sheppo } 26441991Sheppo 26451991Sheppo /* send attr info message to the peer over ldc */ 26461991Sheppo static int 26471991Sheppo vgen_send_attr_info(vgen_ldc_t *ldcp) 26481991Sheppo { 26491991Sheppo vnet_attr_msg_t attrmsg; 26501991Sheppo vio_msg_tag_t *tagp = &attrmsg.tag; 26511991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 26521991Sheppo int rv; 26531991Sheppo 26541991Sheppo bzero(&attrmsg, sizeof (attrmsg)); 26551991Sheppo 26561991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 26571991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 26581991Sheppo tagp->vio_subtype_env = VIO_ATTR_INFO; 26591991Sheppo tagp->vio_sid = ldcp->local_sid; 26601991Sheppo 26611991Sheppo /* get attr msg payload from ldcp->local */ 26621991Sheppo attrmsg.mtu = ldcp->local_hparams.mtu; 26631991Sheppo attrmsg.addr = ldcp->local_hparams.addr; 26641991Sheppo attrmsg.addr_type = ldcp->local_hparams.addr_type; 26651991Sheppo attrmsg.xfer_mode = ldcp->local_hparams.xfer_mode; 26661991Sheppo attrmsg.ack_freq = ldcp->local_hparams.ack_freq; 26671991Sheppo 26681991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (attrmsg), B_FALSE); 26691991Sheppo if (rv != VGEN_SUCCESS) { 26701991Sheppo DWARN((vnetp, "vgen_send_attr_info: vgen_sendmsg failed" 26711991Sheppo "id (%lx)\n", ldcp->ldc_id)); 26721991Sheppo return (VGEN_FAILURE); 26731991Sheppo } 26741991Sheppo 26751991Sheppo ldcp->hstate |= ATTR_INFO_SENT; 26761991Sheppo DBG2((vnetp, "vgen_send_attr_info: ATTR_INFO_SENT id (%lx)\n", 26771991Sheppo ldcp->ldc_id)); 26781991Sheppo 26791991Sheppo return (VGEN_SUCCESS); 26801991Sheppo } 26811991Sheppo 26821991Sheppo /* send descriptor ring register message to the peer over ldc */ 26831991Sheppo static int 26841991Sheppo vgen_send_dring_reg(vgen_ldc_t *ldcp) 26851991Sheppo { 26861991Sheppo vio_dring_reg_msg_t msg; 26871991Sheppo vio_msg_tag_t *tagp = &msg.tag; 26881991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 26891991Sheppo int rv; 26901991Sheppo 26911991Sheppo bzero(&msg, sizeof (msg)); 26921991Sheppo 26931991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 26941991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 26951991Sheppo tagp->vio_subtype_env = VIO_DRING_REG; 26961991Sheppo tagp->vio_sid = ldcp->local_sid; 26971991Sheppo 26981991Sheppo /* get dring info msg payload from ldcp->local */ 26991991Sheppo bcopy(&(ldcp->local_hparams.dring_cookie), (msg.cookie), 27001991Sheppo sizeof (ldc_mem_cookie_t)); 27011991Sheppo msg.ncookies = ldcp->local_hparams.num_dcookies; 27021991Sheppo msg.num_descriptors = ldcp->local_hparams.num_desc; 27031991Sheppo msg.descriptor_size = ldcp->local_hparams.desc_size; 27041991Sheppo 27051991Sheppo /* 27061991Sheppo * dring_ident is set to 0. After mapping the dring, peer sets this 27071991Sheppo * value and sends it in the ack, which is saved in 27081991Sheppo * vgen_handle_dring_reg(). 27091991Sheppo */ 27101991Sheppo msg.dring_ident = 0; 27111991Sheppo 27121991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (msg), B_FALSE); 27131991Sheppo if (rv != VGEN_SUCCESS) { 27141991Sheppo DWARN((vnetp, "vgen_send_dring_reg: vgen_sendmsg failed" 27151991Sheppo "id (%lx)\n", ldcp->ldc_id)); 27161991Sheppo return (VGEN_FAILURE); 27171991Sheppo } 27181991Sheppo 27191991Sheppo ldcp->hstate |= DRING_INFO_SENT; 27201991Sheppo DBG2((vnetp, "vgen_send_dring_reg: DRING_INFO_SENT id (%lx)\n", 27211991Sheppo ldcp->ldc_id)); 27221991Sheppo 27231991Sheppo return (VGEN_SUCCESS); 27241991Sheppo } 27251991Sheppo 27261991Sheppo static int 27271991Sheppo vgen_send_rdx_info(vgen_ldc_t *ldcp) 27281991Sheppo { 27291991Sheppo vio_rdx_msg_t rdxmsg; 27301991Sheppo vio_msg_tag_t *tagp = &rdxmsg.tag; 27311991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 27321991Sheppo int rv; 27331991Sheppo 27341991Sheppo bzero(&rdxmsg, sizeof (rdxmsg)); 27351991Sheppo 27361991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 27371991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 27381991Sheppo tagp->vio_subtype_env = VIO_RDX; 27391991Sheppo tagp->vio_sid = ldcp->local_sid; 27401991Sheppo 27411991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (rdxmsg), B_FALSE); 27421991Sheppo if (rv != VGEN_SUCCESS) { 27431991Sheppo DWARN((vnetp, "vgen_send_rdx_info: vgen_sendmsg failed" 27441991Sheppo "id (%lx)\n", ldcp->ldc_id)); 27451991Sheppo return (VGEN_FAILURE); 27461991Sheppo } 27471991Sheppo 27481991Sheppo ldcp->hstate |= RDX_INFO_SENT; 27491991Sheppo DBG2((vnetp, "vgen_send_rdx_info: RDX_INFO_SENT id (%lx)\n", 27501991Sheppo ldcp->ldc_id)); 27511991Sheppo 27521991Sheppo return (VGEN_SUCCESS); 27531991Sheppo } 27541991Sheppo 27551991Sheppo /* send descriptor ring data message to the peer over ldc */ 27561991Sheppo static int 2757*2336Snarayan vgen_send_dring_data(vgen_ldc_t *ldcp, uint32_t start, int32_t end) 27581991Sheppo { 27591991Sheppo vio_dring_msg_t dringmsg, *msgp = &dringmsg; 27601991Sheppo vio_msg_tag_t *tagp = &msgp->tag; 27611991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 27621991Sheppo int rv; 27631991Sheppo 27641991Sheppo bzero(msgp, sizeof (*msgp)); 27651991Sheppo 27661991Sheppo tagp->vio_msgtype = VIO_TYPE_DATA; 27671991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 27681991Sheppo tagp->vio_subtype_env = VIO_DRING_DATA; 27691991Sheppo tagp->vio_sid = ldcp->local_sid; 27701991Sheppo 2771*2336Snarayan msgp->seq_num = ldcp->next_txseq; 27721991Sheppo msgp->dring_ident = ldcp->local_hparams.dring_ident; 27731991Sheppo msgp->start_idx = start; 27741991Sheppo msgp->end_idx = end; 27751991Sheppo 27761991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (dringmsg), B_TRUE); 27771991Sheppo if (rv != VGEN_SUCCESS) { 27781991Sheppo DWARN((vnetp, "vgen_send_dring_data: vgen_sendmsg failed" 27791991Sheppo "id (%lx)\n", ldcp->ldc_id)); 27801991Sheppo return (VGEN_FAILURE); 27811991Sheppo } 27821991Sheppo 2783*2336Snarayan ldcp->next_txseq++; 2784*2336Snarayan ldcp->statsp->dring_data_msgs++; 2785*2336Snarayan 27861991Sheppo DBG2((vnetp, "vgen_send_dring_data: DRING_DATA_SENT id (%lx)\n", 27871991Sheppo ldcp->ldc_id)); 27881991Sheppo 27891991Sheppo return (VGEN_SUCCESS); 27901991Sheppo } 27911991Sheppo 27921991Sheppo /* send multicast addr info message to vsw */ 27931991Sheppo static int 27941991Sheppo vgen_send_mcast_info(vgen_ldc_t *ldcp) 27951991Sheppo { 27961991Sheppo vnet_mcast_msg_t mcastmsg; 27971991Sheppo vnet_mcast_msg_t *msgp; 27981991Sheppo vio_msg_tag_t *tagp; 27991991Sheppo vgen_t *vgenp; 28001991Sheppo void *vnetp; 28011991Sheppo struct ether_addr *mca; 28021991Sheppo int rv; 28031991Sheppo int i; 28041991Sheppo uint32_t size; 28051991Sheppo uint32_t mccount; 28061991Sheppo uint32_t n; 28071991Sheppo 28081991Sheppo msgp = &mcastmsg; 28091991Sheppo tagp = &msgp->tag; 28101991Sheppo vgenp = LDC_TO_VGEN(ldcp); 28111991Sheppo vnetp = LDC_TO_VNET(ldcp); 28121991Sheppo 28131991Sheppo mccount = vgenp->mccount; 28141991Sheppo i = 0; 28151991Sheppo 28161991Sheppo do { 28171991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 28181991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 28191991Sheppo tagp->vio_subtype_env = VNET_MCAST_INFO; 28201991Sheppo tagp->vio_sid = ldcp->local_sid; 28211991Sheppo 28221991Sheppo n = ((mccount >= VNET_NUM_MCAST) ? VNET_NUM_MCAST : mccount); 28231991Sheppo size = n * sizeof (struct ether_addr); 28241991Sheppo 28251991Sheppo mca = &(vgenp->mctab[i]); 28261991Sheppo bcopy(mca, (msgp->mca), size); 28271991Sheppo msgp->set = B_TRUE; 28281991Sheppo msgp->count = n; 28291991Sheppo 28301991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp), 28311991Sheppo B_FALSE); 28321991Sheppo if (rv != VGEN_SUCCESS) { 28331991Sheppo DWARN((vnetp, "vgen_send_mcast_info: vgen_sendmsg err" 28341991Sheppo "id (%lx)\n", ldcp->ldc_id)); 28351991Sheppo return (VGEN_FAILURE); 28361991Sheppo } 28371991Sheppo 28381991Sheppo mccount -= n; 28391991Sheppo i += n; 28401991Sheppo 28411991Sheppo } while (mccount); 28421991Sheppo 28431991Sheppo return (VGEN_SUCCESS); 28441991Sheppo } 28451991Sheppo 28461991Sheppo /* Initiate Phase 2 of handshake */ 28471991Sheppo static int 28481991Sheppo vgen_handshake_phase2(vgen_ldc_t *ldcp) 28491991Sheppo { 28501991Sheppo int rv; 28511991Sheppo #ifdef DEBUG 28521991Sheppo if (vgen_hdbg & HDBG_OUT_STATE) { 28531991Sheppo /* simulate out of state condition */ 28541991Sheppo vgen_hdbg &= ~(HDBG_OUT_STATE); 28551991Sheppo rv = vgen_send_rdx_info(ldcp); 28561991Sheppo return (rv); 28571991Sheppo } 28581991Sheppo if (vgen_hdbg & HDBG_TIMEOUT) { 28591991Sheppo /* simulate timeout condition */ 28601991Sheppo vgen_hdbg &= ~(HDBG_TIMEOUT); 28611991Sheppo return (VGEN_SUCCESS); 28621991Sheppo } 28631991Sheppo #endif 28641991Sheppo if ((rv = vgen_send_attr_info(ldcp)) != VGEN_SUCCESS) { 28651991Sheppo return (rv); 28661991Sheppo } 28671991Sheppo if ((rv = vgen_send_dring_reg(ldcp)) != VGEN_SUCCESS) { 28681991Sheppo return (rv); 28691991Sheppo } 28701991Sheppo 28711991Sheppo return (VGEN_SUCCESS); 28721991Sheppo } 28731991Sheppo 28741991Sheppo /* 28751991Sheppo * This function resets the handshake phase to VH_PHASE0(pre-handshake phase). 28761991Sheppo * This can happen after a channel comes up (status: LDC_UP) or 28771991Sheppo * when handshake gets terminated due to various conditions. 28781991Sheppo */ 28791991Sheppo static void 28801991Sheppo vgen_reset_hphase(vgen_ldc_t *ldcp) 28811991Sheppo { 28821991Sheppo vgen_t *vgenp = LDC_TO_VGEN(ldcp); 28831991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 28841991Sheppo ldc_status_t istatus; 28851991Sheppo 28861991Sheppo DBG2((vnetp, "vgen_reset_hphase: id(0x%lx)\n", ldcp->ldc_id)); 28871991Sheppo /* reset hstate and hphase */ 28881991Sheppo ldcp->hstate = 0; 28891991Sheppo ldcp->hphase = VH_PHASE0; 28901991Sheppo 28911991Sheppo /* reset handshake watchdog timeout */ 28921991Sheppo if (ldcp->htid) { 28931991Sheppo (void) untimeout(ldcp->htid); 28941991Sheppo ldcp->htid = 0; 28951991Sheppo } 28961991Sheppo 28971991Sheppo /* 28981991Sheppo * Unmap drings, if dring_ready is set. 28991991Sheppo */ 29001991Sheppo if (ldcp->local_hparams.dring_ready) { 29011991Sheppo ldcp->local_hparams.dring_ready = B_FALSE; 29021991Sheppo /* do not unbind our dring */ 29031991Sheppo } 29041991Sheppo 29051991Sheppo if (ldcp->peer_hparams.dring_ready) { 29061991Sheppo ldcp->peer_hparams.dring_ready = B_FALSE; 29071991Sheppo /* Unmap peer's dring */ 29081991Sheppo (void) ldc_mem_dring_unmap(ldcp->rx_dhandle); 29091991Sheppo vgen_clobber_rxds(ldcp); 29101991Sheppo } 29111991Sheppo 29121991Sheppo vgen_clobber_tbufs(ldcp); 29131991Sheppo 29141991Sheppo /* 29151991Sheppo * clear local handshake params and initialize. 29161991Sheppo */ 29171991Sheppo bzero(&(ldcp->local_hparams), sizeof (ldcp->local_hparams)); 29181991Sheppo 29191991Sheppo /* set version to the highest version supported */ 29201991Sheppo ldcp->local_hparams.ver_major = 29211991Sheppo ldcp->vgen_versions[0].ver_major; 29221991Sheppo ldcp->local_hparams.ver_minor = 29231991Sheppo ldcp->vgen_versions[0].ver_minor; 29241991Sheppo ldcp->local_hparams.dev_class = VDEV_NETWORK; 29251991Sheppo 29261991Sheppo /* set attr_info params */ 29271991Sheppo ldcp->local_hparams.mtu = ETHERMAX; 29281991Sheppo ldcp->local_hparams.addr = 29291991Sheppo vgen_macaddr_strtoul(vgenp->macaddr); 29301991Sheppo ldcp->local_hparams.addr_type = ADDR_TYPE_MAC; 29311991Sheppo ldcp->local_hparams.xfer_mode = VIO_DRING_MODE; 29321991Sheppo ldcp->local_hparams.ack_freq = 0; /* don't need acks */ 29331991Sheppo 29341991Sheppo /* 29351991Sheppo * set dring_info params. 29361991Sheppo * Note: dring is already created and bound. 29371991Sheppo */ 29381991Sheppo bcopy(&(ldcp->tx_dcookie), &(ldcp->local_hparams.dring_cookie), 29391991Sheppo sizeof (ldc_mem_cookie_t)); 29401991Sheppo ldcp->local_hparams.num_dcookies = ldcp->num_txdcookies; 29411991Sheppo ldcp->local_hparams.num_desc = ldcp->num_txds; 29421991Sheppo ldcp->local_hparams.desc_size = sizeof (vnet_public_desc_t); 29431991Sheppo 29441991Sheppo /* 29451991Sheppo * dring_ident is set to 0. After mapping the dring, peer sets this 29461991Sheppo * value and sends it in the ack, which is saved in 29471991Sheppo * vgen_handle_dring_reg(). 29481991Sheppo */ 29491991Sheppo ldcp->local_hparams.dring_ident = 0; 29501991Sheppo 29511991Sheppo /* clear peer_hparams */ 29521991Sheppo bzero(&(ldcp->peer_hparams), sizeof (ldcp->peer_hparams)); 29531991Sheppo 29541991Sheppo /* reset the channel if required */ 29551991Sheppo if (ldcp->need_ldc_reset) { 29561991Sheppo DWARN((vnetp, 29571991Sheppo "vgen_reset_hphase: id (%lx), Doing Channel Reset...\n", 29581991Sheppo ldcp->ldc_id)); 29591991Sheppo ldcp->need_ldc_reset = B_FALSE; 29601991Sheppo (void) ldc_reset(ldcp->ldc_handle); 29611991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 29621991Sheppo DBG2((vnetp, 29631991Sheppo "vgen_reset_hphase: id (%lx), RESET Done,ldc_status(%x)\n", 29641991Sheppo ldcp->ldc_id, istatus)); 29651991Sheppo ldcp->ldc_status = istatus; 29661991Sheppo /* clear sids */ 29671991Sheppo ldcp->local_sid = 0; 29681991Sheppo ldcp->peer_sid = 0; 29691991Sheppo (void) ldc_up(ldcp->ldc_handle); 29701991Sheppo } 29711991Sheppo } 29721991Sheppo 29731991Sheppo /* wrapper function for vgen_reset_hphase */ 29741991Sheppo static void 29751991Sheppo vgen_handshake_reset(vgen_ldc_t *ldcp) 29761991Sheppo { 29771991Sheppo ASSERT(MUTEX_HELD(&ldcp->cblock)); 29781991Sheppo mutex_enter(&ldcp->txlock); 29791991Sheppo mutex_enter(&ldcp->tclock); 29801991Sheppo 29811991Sheppo vgen_reset_hphase(ldcp); 29821991Sheppo 29831991Sheppo mutex_exit(&ldcp->tclock); 29841991Sheppo mutex_exit(&ldcp->txlock); 29851991Sheppo } 29861991Sheppo 29871991Sheppo /* 29881991Sheppo * Initiate handshake with the peer by sending various messages 29891991Sheppo * based on the handshake-phase that the channel is currently in. 29901991Sheppo */ 29911991Sheppo static void 29921991Sheppo vgen_handshake(vgen_ldc_t *ldcp) 29931991Sheppo { 29941991Sheppo uint32_t hphase = ldcp->hphase; 29951991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 29961991Sheppo vgen_t *vgenp = LDC_TO_VGEN(ldcp); 29971991Sheppo 29981991Sheppo switch (hphase) { 29991991Sheppo 30001991Sheppo case VH_PHASE1: 30011991Sheppo 30021991Sheppo /* 30031991Sheppo * start timer, for entire handshake process, turn this timer 30041991Sheppo * off if all phases of handshake complete successfully and 30051991Sheppo * hphase goes to VH_DONE(below) or 30061991Sheppo * vgen_reset_hphase() gets called or 30071991Sheppo * channel is reset due to errors or 30081991Sheppo * vgen_ldc_uninit() is invoked(vgen_stop). 30091991Sheppo */ 30101991Sheppo ldcp->htid = timeout(vgen_hwatchdog, (caddr_t)ldcp, 30111991Sheppo drv_usectohz(vgen_hwd_interval * 1000)); 30121991Sheppo 30131991Sheppo /* Phase 1 involves negotiating the version */ 30141991Sheppo if (vgen_send_version_negotiate(ldcp) != VGEN_SUCCESS) { 30151991Sheppo vgen_handshake_reset(ldcp); 30161991Sheppo } 30171991Sheppo break; 30181991Sheppo 30191991Sheppo case VH_PHASE2: 30201991Sheppo if (vgen_handshake_phase2(ldcp) != VGEN_SUCCESS) { 30211991Sheppo vgen_handshake_reset(ldcp); 30221991Sheppo } 30231991Sheppo break; 30241991Sheppo 30251991Sheppo case VH_PHASE3: 30261991Sheppo if (vgen_send_rdx_info(ldcp) != VGEN_SUCCESS) { 30271991Sheppo vgen_handshake_reset(ldcp); 30281991Sheppo } 30291991Sheppo break; 30301991Sheppo 30311991Sheppo case VH_DONE: 30321991Sheppo /* reset handshake watchdog timeout */ 30331991Sheppo if (ldcp->htid) { 30341991Sheppo (void) untimeout(ldcp->htid); 30351991Sheppo ldcp->htid = 0; 30361991Sheppo } 30371991Sheppo ldcp->hretries = 0; 30381991Sheppo #if 0 30391991Sheppo vgen_print_ldcinfo(ldcp); 30401991Sheppo #endif 30411991Sheppo DBG1((vnetp, "vgen_handshake: id(0x%lx) Handshake Done\n", 30421991Sheppo ldcp->ldc_id)); 30431991Sheppo 30441991Sheppo if (ldcp->need_mcast_sync) { 30451991Sheppo /* need to sync multicast table with vsw */ 30461991Sheppo 30471991Sheppo ldcp->need_mcast_sync = B_FALSE; 30481991Sheppo mutex_exit(&ldcp->cblock); 30491991Sheppo 30501991Sheppo mutex_enter(&vgenp->lock); 30511991Sheppo (void) vgen_send_mcast_info(ldcp); 30521991Sheppo mutex_exit(&vgenp->lock); 30531991Sheppo 30541991Sheppo mutex_enter(&ldcp->cblock); 30551991Sheppo 30561991Sheppo } 30571991Sheppo break; 30581991Sheppo 30591991Sheppo default: 30601991Sheppo break; 30611991Sheppo } 30621991Sheppo } 30631991Sheppo 30641991Sheppo /* 30651991Sheppo * Check if the current handshake phase has completed successfully and 30661991Sheppo * return the status. 30671991Sheppo */ 30681991Sheppo static int 30691991Sheppo vgen_handshake_done(vgen_ldc_t *ldcp) 30701991Sheppo { 30711991Sheppo uint32_t hphase = ldcp->hphase; 30721991Sheppo int status = 0; 30731991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 30741991Sheppo 30751991Sheppo switch (hphase) { 30761991Sheppo 30771991Sheppo case VH_PHASE1: 30781991Sheppo /* 30791991Sheppo * Phase1 is done, if version negotiation 30801991Sheppo * completed successfully. 30811991Sheppo */ 30821991Sheppo status = ((ldcp->hstate & VER_NEGOTIATED) == 30831991Sheppo VER_NEGOTIATED); 30841991Sheppo break; 30851991Sheppo 30861991Sheppo case VH_PHASE2: 30871991Sheppo /* 30881991Sheppo * Phase 2 is done, if attr info and dring info 30891991Sheppo * have been exchanged successfully. 30901991Sheppo */ 30911991Sheppo status = (((ldcp->hstate & ATTR_INFO_EXCHANGED) == 30921991Sheppo ATTR_INFO_EXCHANGED) && 30931991Sheppo ((ldcp->hstate & DRING_INFO_EXCHANGED) == 30941991Sheppo DRING_INFO_EXCHANGED)); 30951991Sheppo break; 30961991Sheppo 30971991Sheppo case VH_PHASE3: 30981991Sheppo /* Phase 3 is done, if rdx msg has been exchanged */ 30991991Sheppo status = ((ldcp->hstate & RDX_EXCHANGED) == 31001991Sheppo RDX_EXCHANGED); 31011991Sheppo break; 31021991Sheppo 31031991Sheppo default: 31041991Sheppo break; 31051991Sheppo } 31061991Sheppo 31071991Sheppo if (status == 0) { 31081991Sheppo return (VGEN_FAILURE); 31091991Sheppo } 31101991Sheppo DBG2((vnetp, "VNET_HANDSHAKE_DONE: PHASE(%d)\n", hphase)); 31111991Sheppo return (VGEN_SUCCESS); 31121991Sheppo } 31131991Sheppo 31141991Sheppo /* retry handshake on failure */ 31151991Sheppo static void 31161991Sheppo vgen_handshake_retry(vgen_ldc_t *ldcp) 31171991Sheppo { 31181991Sheppo /* reset handshake phase */ 31191991Sheppo vgen_handshake_reset(ldcp); 31201991Sheppo if (vgen_max_hretries) { /* handshake retry is specified */ 31211991Sheppo if (ldcp->hretries++ < vgen_max_hretries) 31221991Sheppo vgen_handshake(vh_nextphase(ldcp)); 31231991Sheppo } 31241991Sheppo } 31251991Sheppo 31261991Sheppo /* 31271991Sheppo * Handle a version info msg from the peer or an ACK/NACK from the peer 31281991Sheppo * to a version info msg that we sent. 31291991Sheppo */ 31301991Sheppo static void 31311991Sheppo vgen_handle_version_negotiate(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 31321991Sheppo { 31331991Sheppo vio_ver_msg_t *vermsg = (vio_ver_msg_t *)tagp; 31341991Sheppo int ack = 0; 31351991Sheppo int failed = 0; 31361991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 31371991Sheppo int idx; 31381991Sheppo vgen_ver_t *versions = ldcp->vgen_versions; 31391991Sheppo 31401991Sheppo DBG1((vnetp, "vgen_handle_version_negotiate: enter\n")); 31411991Sheppo switch (tagp->vio_subtype) { 31421991Sheppo case VIO_SUBTYPE_INFO: 31431991Sheppo 31441991Sheppo /* Cache sid of peer if this is the first time */ 31451991Sheppo if (ldcp->peer_sid == 0) { 31461991Sheppo DBG2((vnetp, 31471991Sheppo "vgen_handle_version_negotiate: id (%lx) Caching" 31481991Sheppo " peer_sid(%x)\n", ldcp->ldc_id, tagp->vio_sid)); 31491991Sheppo ldcp->peer_sid = tagp->vio_sid; 31501991Sheppo } 31511991Sheppo 31521991Sheppo if (ldcp->hphase != VH_PHASE1) { 31531991Sheppo /* 31541991Sheppo * If we are not already in VH_PHASE1, reset to 31551991Sheppo * pre-handshake state, and initiate handshake 31561991Sheppo * to the peer too. 31571991Sheppo */ 31581991Sheppo vgen_handshake_reset(ldcp); 31591991Sheppo vgen_handshake(vh_nextphase(ldcp)); 31601991Sheppo } 31611991Sheppo ldcp->hstate |= VER_INFO_RCVD; 31621991Sheppo 31631991Sheppo /* save peer's requested values */ 31641991Sheppo ldcp->peer_hparams.ver_major = vermsg->ver_major; 31651991Sheppo ldcp->peer_hparams.ver_minor = vermsg->ver_minor; 31661991Sheppo ldcp->peer_hparams.dev_class = vermsg->dev_class; 31671991Sheppo 31681991Sheppo if ((vermsg->dev_class != VDEV_NETWORK) && 31691991Sheppo (vermsg->dev_class != VDEV_NETWORK_SWITCH)) { 31701991Sheppo /* unsupported dev_class, send NACK */ 31711991Sheppo 31721991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 31731991Sheppo tagp->vio_sid = ldcp->local_sid; 31741991Sheppo /* send reply msg back to peer */ 31751991Sheppo (void) vgen_sendmsg(ldcp, (caddr_t)tagp, 31761991Sheppo sizeof (*vermsg), B_FALSE); 31771991Sheppo DWARN((vnetp, 31781991Sheppo "vgen_handle_version_negotiate: Version" 31791991Sheppo " Negotiation Failed id (%lx)\n", ldcp->ldc_id)); 31801991Sheppo vgen_handshake_reset(ldcp); 31811991Sheppo return; 31821991Sheppo } 31831991Sheppo 31841991Sheppo DBG2((vnetp, "vgen_handle_version_negotiate: VER_INFO_RCVD," 31851991Sheppo " id (%lx), ver(%d,%d)\n", ldcp->ldc_id, 31861991Sheppo vermsg->ver_major, vermsg->ver_minor)); 31871991Sheppo 31881991Sheppo idx = 0; 31891991Sheppo 31901991Sheppo for (;;) { 31911991Sheppo 31921991Sheppo if (vermsg->ver_major > versions[idx].ver_major) { 31931991Sheppo 31941991Sheppo /* nack with next lower version */ 31951991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 31961991Sheppo vermsg->ver_major = versions[idx].ver_major; 31971991Sheppo vermsg->ver_minor = versions[idx].ver_minor; 31981991Sheppo break; 31991991Sheppo } 32001991Sheppo 32011991Sheppo if (vermsg->ver_major == versions[idx].ver_major) { 32021991Sheppo 32031991Sheppo /* major version match - ACK version */ 32041991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 32051991Sheppo ack = 1; 32061991Sheppo 32071991Sheppo /* 32081991Sheppo * lower minor version to the one this endpt 32091991Sheppo * supports, if necessary 32101991Sheppo */ 32111991Sheppo if (vermsg->ver_minor > 32121991Sheppo versions[idx].ver_minor) { 32131991Sheppo vermsg->ver_minor = 32141991Sheppo versions[idx].ver_minor; 32151991Sheppo ldcp->peer_hparams.ver_minor = 32161991Sheppo versions[idx].ver_minor; 32171991Sheppo } 32181991Sheppo break; 32191991Sheppo } 32201991Sheppo 32211991Sheppo idx++; 32221991Sheppo 32231991Sheppo if (idx == VGEN_NUM_VER) { 32241991Sheppo 32251991Sheppo /* no version match - send NACK */ 32261991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 32271991Sheppo vermsg->ver_major = 0; 32281991Sheppo vermsg->ver_minor = 0; 32291991Sheppo failed = 1; 32301991Sheppo break; 32311991Sheppo } 32321991Sheppo 32331991Sheppo } 32341991Sheppo 32351991Sheppo tagp->vio_sid = ldcp->local_sid; 32361991Sheppo 32371991Sheppo /* send reply msg back to peer */ 32381991Sheppo if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*vermsg), 32391991Sheppo B_FALSE) != VGEN_SUCCESS) { 32401991Sheppo vgen_handshake_reset(ldcp); 32411991Sheppo return; 32421991Sheppo } 32431991Sheppo 32441991Sheppo if (ack) { 32451991Sheppo ldcp->hstate |= VER_ACK_SENT; 32461991Sheppo DBG2((vnetp, "vgen_handle_version_negotiate:" 32471991Sheppo " VER_ACK_SENT, id (%lx) ver(%d,%d) \n", 32481991Sheppo ldcp->ldc_id, vermsg->ver_major, 32491991Sheppo vermsg->ver_minor)); 32501991Sheppo } 32511991Sheppo if (failed) { 32521991Sheppo DWARN((vnetp, "vgen_handle_version_negotiate:" 32531991Sheppo " Version Negotiation Failed id (%lx)\n", 32541991Sheppo ldcp->ldc_id)); 32551991Sheppo vgen_handshake_reset(ldcp); 32561991Sheppo return; 32571991Sheppo } 32581991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 32591991Sheppo 32601991Sheppo /* VER_ACK_SENT and VER_ACK_RCVD */ 32611991Sheppo 32621991Sheppo /* local and peer versions match? */ 32631991Sheppo ASSERT((ldcp->local_hparams.ver_major == 32641991Sheppo ldcp->peer_hparams.ver_major) && 32651991Sheppo (ldcp->local_hparams.ver_minor == 32661991Sheppo ldcp->peer_hparams.ver_minor)); 32671991Sheppo 32681991Sheppo /* move to the next phase */ 32691991Sheppo vgen_handshake(vh_nextphase(ldcp)); 32701991Sheppo } 32711991Sheppo 32721991Sheppo break; 32731991Sheppo 32741991Sheppo case VIO_SUBTYPE_ACK: 32751991Sheppo 32761991Sheppo if (ldcp->hphase != VH_PHASE1) { 32771991Sheppo /* This should not happen. */ 32781991Sheppo DWARN((vnetp, 32791991Sheppo "vgen_handle_version_negotiate:" 32801991Sheppo " VER_ACK_RCVD id (%lx) Invalid Phase(%u)\n", 32811991Sheppo ldcp->ldc_id, ldcp->hphase)); 32821991Sheppo vgen_handshake_reset(ldcp); 32831991Sheppo return; 32841991Sheppo } 32851991Sheppo 32861991Sheppo /* SUCCESS - we have agreed on a version */ 32871991Sheppo ldcp->local_hparams.ver_major = vermsg->ver_major; 32881991Sheppo ldcp->local_hparams.ver_minor = vermsg->ver_minor; 32891991Sheppo ldcp->hstate |= VER_ACK_RCVD; 32901991Sheppo 32911991Sheppo DBG2((vnetp, "vgen_handle_version_negotiate:" 32921991Sheppo " VER_ACK_RCVD, id (%lx) ver(%d,%d) \n", 32931991Sheppo ldcp->ldc_id, vermsg->ver_major, vermsg->ver_minor)); 32941991Sheppo 32951991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 32961991Sheppo 32971991Sheppo /* VER_ACK_SENT and VER_ACK_RCVD */ 32981991Sheppo 32991991Sheppo /* local and peer versions match? */ 33001991Sheppo ASSERT((ldcp->local_hparams.ver_major == 33011991Sheppo ldcp->peer_hparams.ver_major) && 33021991Sheppo (ldcp->local_hparams.ver_minor == 33031991Sheppo ldcp->peer_hparams.ver_minor)); 33041991Sheppo 33051991Sheppo /* move to the next phase */ 33061991Sheppo vgen_handshake(vh_nextphase(ldcp)); 33071991Sheppo } 33081991Sheppo break; 33091991Sheppo 33101991Sheppo case VIO_SUBTYPE_NACK: 33111991Sheppo 33121991Sheppo if (ldcp->hphase != VH_PHASE1) { 33131991Sheppo /* This should not happen. */ 33141991Sheppo DWARN((vnetp, 33151991Sheppo "vgen_handle_version_negotiate:" 33161991Sheppo " VER_NACK_RCVD id (%lx) Invalid Phase(%u)\n", 33171991Sheppo ldcp->ldc_id, ldcp->hphase)); 33181991Sheppo vgen_handshake_reset(ldcp); 33191991Sheppo return; 33201991Sheppo } 33211991Sheppo 33221991Sheppo DBG2((vnetp, "vgen_handle_version_negotiate:" 33231991Sheppo " VER_NACK_RCVD id(%lx) next ver(%d,%d)\n", 33241991Sheppo ldcp->ldc_id, vermsg->ver_major, vermsg->ver_minor)); 33251991Sheppo 33261991Sheppo /* check if version in NACK is zero */ 33271991Sheppo if (vermsg->ver_major == 0 && vermsg->ver_minor == 0) { 33281991Sheppo /* 33291991Sheppo * Version Negotiation has failed. 33301991Sheppo */ 33311991Sheppo DWARN((vnetp, "vgen_handle_version_negotiate:" 33321991Sheppo " Version Negotiation Failed id (%lx)\n", 33331991Sheppo ldcp->ldc_id)); 33341991Sheppo vgen_handshake_reset(ldcp); 33351991Sheppo return; 33361991Sheppo } 33371991Sheppo 33381991Sheppo idx = 0; 33391991Sheppo 33401991Sheppo for (;;) { 33411991Sheppo 33421991Sheppo if (vermsg->ver_major > versions[idx].ver_major) { 33431991Sheppo /* select next lower version */ 33441991Sheppo 33451991Sheppo ldcp->local_hparams.ver_major = 33461991Sheppo versions[idx].ver_major; 33471991Sheppo ldcp->local_hparams.ver_minor = 33481991Sheppo versions[idx].ver_minor; 33491991Sheppo break; 33501991Sheppo } 33511991Sheppo 33521991Sheppo if (vermsg->ver_major == versions[idx].ver_major) { 33531991Sheppo /* major version match */ 33541991Sheppo 33551991Sheppo ldcp->local_hparams.ver_major = 33561991Sheppo versions[idx].ver_major; 33571991Sheppo 33581991Sheppo ldcp->local_hparams.ver_minor = 33591991Sheppo versions[idx].ver_minor; 33601991Sheppo break; 33611991Sheppo } 33621991Sheppo 33631991Sheppo idx++; 33641991Sheppo 33651991Sheppo if (idx == VGEN_NUM_VER) { 33661991Sheppo /* 33671991Sheppo * no version match. 33681991Sheppo * Version Negotiation has failed. 33691991Sheppo */ 33701991Sheppo DWARN((vnetp, "vgen_handle_version_negotiate:" 33711991Sheppo " Version Negotiation Failed id (%lx)\n", 33721991Sheppo ldcp->ldc_id)); 33731991Sheppo vgen_handshake_reset(ldcp); 33741991Sheppo return; 33751991Sheppo } 33761991Sheppo 33771991Sheppo } 33781991Sheppo 33791991Sheppo if (vgen_send_version_negotiate(ldcp) != VGEN_SUCCESS) { 33801991Sheppo vgen_handshake_reset(ldcp); 33811991Sheppo return; 33821991Sheppo } 33831991Sheppo 33841991Sheppo break; 33851991Sheppo } 33861991Sheppo DBG1((vnetp, "vgen_handle_version_negotiate: exit\n")); 33871991Sheppo } 33881991Sheppo 33891991Sheppo /* Check if the attributes are supported */ 33901991Sheppo static int 33911991Sheppo vgen_check_attr_info(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg) 33921991Sheppo { 33931991Sheppo _NOTE(ARGUNUSED(ldcp)) 33941991Sheppo 33951991Sheppo #if 0 33961991Sheppo uint64_t port_macaddr; 33971991Sheppo port_macaddr = vgen_macaddr_strtoul((uint8_t *) 33981991Sheppo &(ldcp->portp->macaddr)); 33991991Sheppo #endif 34001991Sheppo /* 34011991Sheppo * currently, we support these attr values: 34021991Sheppo * mtu of ethernet, addr_type of mac, xfer_mode of 34031991Sheppo * ldc shared memory, ack_freq of 0 (data is acked if 34041991Sheppo * the ack bit is set in the descriptor) and the address should 34051991Sheppo * match the address in the port node. 34061991Sheppo */ 34071991Sheppo if ((msg->mtu != ETHERMAX) || 34081991Sheppo (msg->addr_type != ADDR_TYPE_MAC) || 34091991Sheppo (msg->xfer_mode != VIO_DRING_MODE) || 34101991Sheppo (msg->ack_freq > 64)) { 34111991Sheppo #if 0 34121991Sheppo (msg->addr != port_macaddr)) 34131991Sheppo cmn_err(CE_CONT, "vgen_check_attr_info: msg->addr(%lx), port_macaddr(%lx)\n", 34141991Sheppo msg->addr, port_macaddr); 34151991Sheppo #endif 34161991Sheppo return (VGEN_FAILURE); 34171991Sheppo } 34181991Sheppo 34191991Sheppo return (VGEN_SUCCESS); 34201991Sheppo } 34211991Sheppo 34221991Sheppo /* 34231991Sheppo * Handle an attribute info msg from the peer or an ACK/NACK from the peer 34241991Sheppo * to an attr info msg that we sent. 34251991Sheppo */ 34261991Sheppo static void 34271991Sheppo vgen_handle_attr_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 34281991Sheppo { 34291991Sheppo vnet_attr_msg_t *attrmsg = (vnet_attr_msg_t *)tagp; 34301991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 34311991Sheppo int ack = 0; 34321991Sheppo 34331991Sheppo DBG1((vnetp, "vgen_handle_attr_info: enter\n")); 34341991Sheppo if (ldcp->hphase != VH_PHASE2) { 34351991Sheppo DWARN((vnetp, 34361991Sheppo "vgen_handle_attr_info: Rcvd ATTR_INFO id(%lx)" 34371991Sheppo " subtype (%d), Invalid Phase(%u)\n", ldcp->ldc_id, 34381991Sheppo tagp->vio_subtype, ldcp->hphase)); 34391991Sheppo vgen_handshake_reset(ldcp); 34401991Sheppo return; 34411991Sheppo } 34421991Sheppo switch (tagp->vio_subtype) { 34431991Sheppo case VIO_SUBTYPE_INFO: 34441991Sheppo 34451991Sheppo DBG2((vnetp, "vgen_handle_attr_info: ATTR_INFO_RCVD id(%lx)\n", 34461991Sheppo ldcp->ldc_id)); 34471991Sheppo ldcp->hstate |= ATTR_INFO_RCVD; 34481991Sheppo 34491991Sheppo /* save peer's values */ 34501991Sheppo ldcp->peer_hparams.mtu = attrmsg->mtu; 34511991Sheppo ldcp->peer_hparams.addr = attrmsg->addr; 34521991Sheppo ldcp->peer_hparams.addr_type = attrmsg->addr_type; 34531991Sheppo ldcp->peer_hparams.xfer_mode = attrmsg->xfer_mode; 34541991Sheppo ldcp->peer_hparams.ack_freq = attrmsg->ack_freq; 34551991Sheppo 34561991Sheppo if (vgen_check_attr_info(ldcp, attrmsg) == VGEN_FAILURE) { 34571991Sheppo /* unsupported attr, send NACK */ 34581991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 34591991Sheppo } else { 34601991Sheppo ack = 1; 34611991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 34621991Sheppo } 34631991Sheppo tagp->vio_sid = ldcp->local_sid; 34641991Sheppo 34651991Sheppo /* send reply msg back to peer */ 34661991Sheppo if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*attrmsg), 34671991Sheppo B_FALSE) != VGEN_SUCCESS) { 34681991Sheppo vgen_handshake_reset(ldcp); 34691991Sheppo return; 34701991Sheppo } 34711991Sheppo 34721991Sheppo if (ack) { 34731991Sheppo ldcp->hstate |= ATTR_ACK_SENT; 34741991Sheppo DBG2((vnetp, "vgen_handle_attr_info:" 34751991Sheppo " ATTR_ACK_SENT id(%lx)\n", ldcp->ldc_id)); 34761991Sheppo } else { 34771991Sheppo /* failed */ 34781991Sheppo DWARN((vnetp, "vgen_handle_attr_info:" 34791991Sheppo " ATTR_NACK_SENT id(%lx)\n", ldcp->ldc_id)); 34801991Sheppo vgen_handshake_reset(ldcp); 34811991Sheppo return; 34821991Sheppo } 34831991Sheppo 34841991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 34851991Sheppo vgen_handshake(vh_nextphase(ldcp)); 34861991Sheppo } 34871991Sheppo 34881991Sheppo break; 34891991Sheppo 34901991Sheppo case VIO_SUBTYPE_ACK: 34911991Sheppo 34921991Sheppo ldcp->hstate |= ATTR_ACK_RCVD; 34931991Sheppo 34941991Sheppo DBG2((vnetp, "vgen_handle_attr_info: ATTR_ACK_RCVD id(%lx)\n", 34951991Sheppo ldcp->ldc_id)); 34961991Sheppo 34971991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 34981991Sheppo vgen_handshake(vh_nextphase(ldcp)); 34991991Sheppo } 35001991Sheppo break; 35011991Sheppo 35021991Sheppo case VIO_SUBTYPE_NACK: 35031991Sheppo 35041991Sheppo DBG2((vnetp, "vgen_handle_attr_info: ATTR_NACK_RCVD id(%lx)\n", 35051991Sheppo ldcp->ldc_id)); 35061991Sheppo vgen_handshake_reset(ldcp); 35071991Sheppo break; 35081991Sheppo } 35091991Sheppo DBG1((vnetp, "vgen_handle_attr_info: exit\n")); 35101991Sheppo } 35111991Sheppo 35121991Sheppo /* Check if the dring info msg is ok */ 35131991Sheppo static int 35141991Sheppo vgen_check_dring_reg(vio_dring_reg_msg_t *msg) 35151991Sheppo { 35161991Sheppo /* check if msg contents are ok */ 35171991Sheppo if ((msg->num_descriptors < 128) || (msg->descriptor_size < 35181991Sheppo sizeof (vnet_public_desc_t))) { 35191991Sheppo return (VGEN_FAILURE); 35201991Sheppo } 35211991Sheppo return (VGEN_SUCCESS); 35221991Sheppo } 35231991Sheppo 35241991Sheppo /* 35251991Sheppo * Handle a descriptor ring register msg from the peer or an ACK/NACK from 35261991Sheppo * the peer to a dring register msg that we sent. 35271991Sheppo */ 35281991Sheppo static void 35291991Sheppo vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 35301991Sheppo { 35311991Sheppo vio_dring_reg_msg_t *msg = (vio_dring_reg_msg_t *)tagp; 35321991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 35331991Sheppo ldc_mem_cookie_t dcookie; 35341991Sheppo int ack = 0; 35351991Sheppo int rv = 0; 35361991Sheppo 35371991Sheppo DBG1((vnetp, "vgen_handle_dring_reg: enter\n")); 35381991Sheppo if (ldcp->hphase < VH_PHASE2) { 35391991Sheppo /* dring_info can be rcvd in any of the phases after Phase1 */ 35401991Sheppo DWARN((vnetp, 35411991Sheppo "vgen_handle_dring_reg: Rcvd DRING_INFO, id (%lx)" 35421991Sheppo " Subtype (%d), Invalid Phase(%u)\n", ldcp->ldc_id, 35431991Sheppo tagp->vio_subtype, ldcp->hphase)); 35441991Sheppo vgen_handshake_reset(ldcp); 35451991Sheppo return; 35461991Sheppo } 35471991Sheppo switch (tagp->vio_subtype) { 35481991Sheppo case VIO_SUBTYPE_INFO: 35491991Sheppo 35501991Sheppo DBG2((vnetp, "vgen_handle_dring_reg: DRING_INFO_RCVD id(%lx)\n", 35511991Sheppo ldcp->ldc_id)); 35521991Sheppo ldcp->hstate |= DRING_INFO_RCVD; 35531991Sheppo bcopy((msg->cookie), &dcookie, sizeof (dcookie)); 35541991Sheppo 35551991Sheppo ASSERT(msg->ncookies == 1); 35561991Sheppo 35571991Sheppo if (vgen_check_dring_reg(msg) == VGEN_SUCCESS) { 35581991Sheppo /* 35591991Sheppo * verified dring info msg to be ok, 35601991Sheppo * now try to map the remote dring. 35611991Sheppo */ 35621991Sheppo rv = vgen_init_rxds(ldcp, msg->num_descriptors, 35631991Sheppo msg->descriptor_size, &dcookie, 35641991Sheppo msg->ncookies); 35651991Sheppo if (rv == DDI_SUCCESS) { 35661991Sheppo /* now we can ack the peer */ 35671991Sheppo ack = 1; 35681991Sheppo } 35691991Sheppo } 35701991Sheppo if (ack == 0) { 35711991Sheppo /* failed, send NACK */ 35721991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 35731991Sheppo } else { 35741991Sheppo if (!(ldcp->peer_hparams.dring_ready)) { 35751991Sheppo 35761991Sheppo /* save peer's dring_info values */ 35771991Sheppo bcopy(&dcookie, 35781991Sheppo &(ldcp->peer_hparams.dring_cookie), 35791991Sheppo sizeof (dcookie)); 35801991Sheppo ldcp->peer_hparams.num_desc = 35811991Sheppo msg->num_descriptors; 35821991Sheppo ldcp->peer_hparams.desc_size = 35831991Sheppo msg->descriptor_size; 35841991Sheppo ldcp->peer_hparams.num_dcookies = 35851991Sheppo msg->ncookies; 35861991Sheppo 35871991Sheppo /* set dring_ident for the peer */ 35881991Sheppo ldcp->peer_hparams.dring_ident = 35891991Sheppo (uint64_t)ldcp->rxdp; 35901991Sheppo /* return the dring_ident in ack msg */ 35911991Sheppo msg->dring_ident = 35921991Sheppo (uint64_t)ldcp->rxdp; 35931991Sheppo 35941991Sheppo ldcp->peer_hparams.dring_ready = B_TRUE; 35951991Sheppo } 35961991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 35971991Sheppo } 35981991Sheppo tagp->vio_sid = ldcp->local_sid; 35991991Sheppo /* send reply msg back to peer */ 36001991Sheppo if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msg), 36011991Sheppo B_FALSE) != VGEN_SUCCESS) { 36021991Sheppo vgen_handshake_reset(ldcp); 36031991Sheppo return; 36041991Sheppo } 36051991Sheppo 36061991Sheppo if (ack) { 36071991Sheppo ldcp->hstate |= DRING_ACK_SENT; 36081991Sheppo DBG2((vnetp, "vgen_handle_dring_reg: DRING_ACK_SENT" 36091991Sheppo " id (%lx)\n", ldcp->ldc_id)); 36101991Sheppo } else { 36111991Sheppo DWARN((vnetp, "vgen_handle_dring_reg: DRING_NACK_SENT" 36121991Sheppo " id (%lx)\n", ldcp->ldc_id)); 36131991Sheppo vgen_handshake_reset(ldcp); 36141991Sheppo return; 36151991Sheppo } 36161991Sheppo 36171991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 36181991Sheppo vgen_handshake(vh_nextphase(ldcp)); 36191991Sheppo } 36201991Sheppo 36211991Sheppo break; 36221991Sheppo 36231991Sheppo case VIO_SUBTYPE_ACK: 36241991Sheppo 36251991Sheppo ldcp->hstate |= DRING_ACK_RCVD; 36261991Sheppo 36271991Sheppo DBG2((vnetp, "vgen_handle_dring_reg: DRING_ACK_RCVD" 36281991Sheppo " id (%lx)\n", ldcp->ldc_id)); 36291991Sheppo 36301991Sheppo if (!(ldcp->local_hparams.dring_ready)) { 36311991Sheppo /* local dring is now ready */ 36321991Sheppo ldcp->local_hparams.dring_ready = B_TRUE; 36331991Sheppo 36341991Sheppo /* save dring_ident acked by peer */ 36351991Sheppo ldcp->local_hparams.dring_ident = 36361991Sheppo msg->dring_ident; 36371991Sheppo } 36381991Sheppo 36391991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 36401991Sheppo vgen_handshake(vh_nextphase(ldcp)); 36411991Sheppo } 36421991Sheppo 36431991Sheppo break; 36441991Sheppo 36451991Sheppo case VIO_SUBTYPE_NACK: 36461991Sheppo 36471991Sheppo DBG2((vnetp, "vgen_handle_dring_reg: DRING_NACK_RCVD" 36481991Sheppo " id (%lx)\n", ldcp->ldc_id)); 36491991Sheppo vgen_handshake_reset(ldcp); 36501991Sheppo break; 36511991Sheppo } 36521991Sheppo DBG1((vnetp, "vgen_handle_dring_reg: exit\n")); 36531991Sheppo } 36541991Sheppo 36551991Sheppo /* 36561991Sheppo * Handle a rdx info msg from the peer or an ACK/NACK 36571991Sheppo * from the peer to a rdx info msg that we sent. 36581991Sheppo */ 36591991Sheppo static void 36601991Sheppo vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 36611991Sheppo { 36621991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 36631991Sheppo 36641991Sheppo DBG1((vnetp, "vgen_handle_rdx_info: enter\n")); 36651991Sheppo if (ldcp->hphase != VH_PHASE3) { 36661991Sheppo DWARN((vnetp, 36671991Sheppo "vgen_handle_rdx_info: Rcvd RDX_INFO, id (%lx)" 36681991Sheppo " Subtype (%d), Invalid Phase(%u)\n", ldcp->ldc_id, 36691991Sheppo tagp->vio_subtype, ldcp->hphase)); 36701991Sheppo vgen_handshake_reset(ldcp); 36711991Sheppo return; 36721991Sheppo } 36731991Sheppo switch (tagp->vio_subtype) { 36741991Sheppo case VIO_SUBTYPE_INFO: 36751991Sheppo 36761991Sheppo DBG2((vnetp, "vgen_handle_rdx_info: RDX_INFO_RCVD id (%lx)\n", 36771991Sheppo ldcp->ldc_id)); 36781991Sheppo ldcp->hstate |= RDX_INFO_RCVD; 36791991Sheppo 36801991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 36811991Sheppo tagp->vio_sid = ldcp->local_sid; 36821991Sheppo /* send reply msg back to peer */ 36831991Sheppo if (vgen_sendmsg(ldcp, (caddr_t)tagp, 36841991Sheppo sizeof (vio_rdx_msg_t), B_FALSE) != VGEN_SUCCESS) { 36851991Sheppo vgen_handshake_reset(ldcp); 36861991Sheppo return; 36871991Sheppo } 36881991Sheppo 36891991Sheppo ldcp->hstate |= RDX_ACK_SENT; 36901991Sheppo DBG2((vnetp, "vgen_handle_rdx_info: RDX_ACK_SENT id (%lx)\n", 36911991Sheppo ldcp->ldc_id)); 36921991Sheppo 36931991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 36941991Sheppo vgen_handshake(vh_nextphase(ldcp)); 36951991Sheppo } 36961991Sheppo 36971991Sheppo break; 36981991Sheppo 36991991Sheppo case VIO_SUBTYPE_ACK: 37001991Sheppo 37011991Sheppo ldcp->hstate |= RDX_ACK_RCVD; 37021991Sheppo 37031991Sheppo DBG2((vnetp, "vgen_handle_rdx_info: RDX_ACK_RCVD id (%lx)\n", 37041991Sheppo ldcp->ldc_id)); 37051991Sheppo 37061991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 37071991Sheppo vgen_handshake(vh_nextphase(ldcp)); 37081991Sheppo } 37091991Sheppo break; 37101991Sheppo 37111991Sheppo case VIO_SUBTYPE_NACK: 37121991Sheppo 37131991Sheppo DBG2((vnetp, "vgen_handle_rdx_info: RDX_NACK_RCVD id (%lx)\n", 37141991Sheppo ldcp->ldc_id)); 37151991Sheppo vgen_handshake_reset(ldcp); 37161991Sheppo break; 37171991Sheppo } 37181991Sheppo DBG1((vnetp, "vgen_handle_rdx_info: exit\n")); 37191991Sheppo } 37201991Sheppo 37211991Sheppo /* Handle ACK/NACK from vsw to a set multicast msg that we sent */ 37221991Sheppo static void 37231991Sheppo vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 37241991Sheppo { 37251991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 37261991Sheppo vgen_t *vgenp = LDC_TO_VGEN(ldcp); 37271991Sheppo vnet_mcast_msg_t *msgp = (vnet_mcast_msg_t *)tagp; 37281991Sheppo struct ether_addr *addrp; 37291991Sheppo int count; 37301991Sheppo int i; 37311991Sheppo 37321991Sheppo DBG1((vnetp, "vgen_handle_mcast_info: enter\n")); 37331991Sheppo switch (tagp->vio_subtype) { 37341991Sheppo 37351991Sheppo case VIO_SUBTYPE_INFO: 37361991Sheppo 37371991Sheppo /* vnet shouldn't recv set mcast msg, only vsw handles it */ 37381991Sheppo DWARN((vnetp, 37391991Sheppo "vgen_handle_mcast_info: rcvd SET_MCAST_INFO id (%lx)\n", 37401991Sheppo ldcp->ldc_id)); 37411991Sheppo break; 37421991Sheppo 37431991Sheppo case VIO_SUBTYPE_ACK: 37441991Sheppo 37451991Sheppo /* success adding/removing multicast addr */ 37461991Sheppo DBG2((vnetp, 37471991Sheppo "vgen_handle_mcast_info: rcvd SET_MCAST_ACK id (%lx)\n", 37481991Sheppo ldcp->ldc_id)); 37491991Sheppo break; 37501991Sheppo 37511991Sheppo case VIO_SUBTYPE_NACK: 37521991Sheppo 37531991Sheppo DWARN((vnetp, 37541991Sheppo "vgen_handle_mcast_info: rcvd SET_MCAST_NACK id (%lx)\n", 37551991Sheppo ldcp->ldc_id)); 37561991Sheppo if (!(msgp->set)) { 37571991Sheppo /* multicast remove request failed */ 37581991Sheppo break; 37591991Sheppo } 37601991Sheppo 37611991Sheppo /* multicast add request failed */ 37621991Sheppo for (count = 0; count < msgp->count; count++) { 37631991Sheppo addrp = &(msgp->mca[count]); 37641991Sheppo 37651991Sheppo /* delete address from the table */ 37661991Sheppo for (i = 0; i < vgenp->mccount; i++) { 37671991Sheppo if (ether_cmp(addrp, 37681991Sheppo &(vgenp->mctab[i])) == 0) { 37691991Sheppo if (vgenp->mccount > 1) { 37701991Sheppo vgenp->mctab[i] = 37711991Sheppo vgenp->mctab[vgenp->mccount-1]; 37721991Sheppo } 37731991Sheppo vgenp->mccount--; 37741991Sheppo break; 37751991Sheppo } 37761991Sheppo } 37771991Sheppo } 37781991Sheppo break; 37791991Sheppo 37801991Sheppo } 37811991Sheppo DBG1((vnetp, "vgen_handle_mcast_info: exit\n")); 37821991Sheppo } 37831991Sheppo 37841991Sheppo /* handler for control messages received from the peer ldc end-point */ 37851991Sheppo static void 37861991Sheppo vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 37871991Sheppo { 37881991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 37891991Sheppo 37901991Sheppo DBG1((vnetp, "vgen_handle_ctrlmsg: enter\n")); 37911991Sheppo switch (tagp->vio_subtype_env) { 37921991Sheppo 37931991Sheppo case VIO_VER_INFO: 37941991Sheppo vgen_handle_version_negotiate(ldcp, tagp); 37951991Sheppo break; 37961991Sheppo 37971991Sheppo case VIO_ATTR_INFO: 37981991Sheppo vgen_handle_attr_info(ldcp, tagp); 37991991Sheppo break; 38001991Sheppo 38011991Sheppo case VIO_DRING_REG: 38021991Sheppo vgen_handle_dring_reg(ldcp, tagp); 38031991Sheppo break; 38041991Sheppo 38051991Sheppo case VIO_RDX: 38061991Sheppo vgen_handle_rdx_info(ldcp, tagp); 38071991Sheppo break; 38081991Sheppo 38091991Sheppo case VNET_MCAST_INFO: 38101991Sheppo vgen_handle_mcast_info(ldcp, tagp); 38111991Sheppo break; 38121991Sheppo 38131991Sheppo } 38141991Sheppo DBG1((vnetp, "vgen_handle_ctrlmsg: exit\n")); 38151991Sheppo } 38161991Sheppo 38171991Sheppo /* handler for data messages received from the peer ldc end-point */ 38181991Sheppo static void 38191991Sheppo vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, 38201991Sheppo mblk_t **headp, mblk_t **tailp) 38211991Sheppo { 38221991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 38231991Sheppo 38241991Sheppo DBG1((vnetp, "vgen_handle_datamsg: enter\n")); 38251991Sheppo 38261991Sheppo if (ldcp->hphase != VH_DONE) 38271991Sheppo return; 38281991Sheppo switch (tagp->vio_subtype_env) { 38291991Sheppo case VIO_DRING_DATA: 38301991Sheppo vgen_handle_dring_data(ldcp, tagp, headp, tailp); 38311991Sheppo break; 38321991Sheppo default: 38331991Sheppo break; 38341991Sheppo } 38351991Sheppo 38361991Sheppo DBG1((vnetp, "vgen_handle_datamsg: exit\n")); 38371991Sheppo } 38381991Sheppo 38391991Sheppo static void 3840*2336Snarayan vgen_send_dring_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, uint32_t start, 3841*2336Snarayan int32_t end, uint8_t pstate) 3842*2336Snarayan { 3843*2336Snarayan vio_dring_msg_t *msgp = (vio_dring_msg_t *)tagp; 3844*2336Snarayan void *vnetp = LDC_TO_VNET(ldcp); 3845*2336Snarayan 3846*2336Snarayan tagp->vio_subtype = VIO_SUBTYPE_ACK; 3847*2336Snarayan tagp->vio_sid = ldcp->local_sid; 3848*2336Snarayan msgp->start_idx = start; 3849*2336Snarayan msgp->end_idx = end; 3850*2336Snarayan msgp->dring_process_state = pstate; 3851*2336Snarayan if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp), B_FALSE)) { 3852*2336Snarayan DWARN((vnetp, "vgen_send_dring_ack: id(%lx) vgen_sendmsg " 3853*2336Snarayan "failed\n", (ldcp)->ldc_id)); 3854*2336Snarayan } 3855*2336Snarayan } 3856*2336Snarayan 3857*2336Snarayan static void 38581991Sheppo vgen_handle_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, 38591991Sheppo mblk_t **headp, mblk_t **tailp) 38601991Sheppo { 38611991Sheppo vio_dring_msg_t *dringmsg; 38621991Sheppo vnet_public_desc_t *rxdp; 38631991Sheppo vnet_public_desc_t *txdp; 38641991Sheppo vio_dring_entry_hdr_t *hdrp; 38651991Sheppo vgen_stats_t *statsp; 38661991Sheppo struct ether_header *ehp; 38671991Sheppo mblk_t *mp = NULL; 38681991Sheppo mblk_t *bp = NULL; 38691991Sheppo mblk_t *bpt = NULL; 38701991Sheppo size_t nbytes; 38711991Sheppo size_t nread; 38721991Sheppo uint64_t off = 0; 38731991Sheppo uint32_t start; 3874*2336Snarayan int32_t end; 38751991Sheppo uint32_t datalen; 38761991Sheppo uint32_t ncookies; 3877*2336Snarayan uint32_t ack_start; 3878*2336Snarayan uint32_t ack_end; 38791991Sheppo uint32_t rxi; 38801991Sheppo uint32_t txi; 38811991Sheppo int rv; 38821991Sheppo boolean_t rxd_err = B_FALSE; 3883*2336Snarayan boolean_t set_ack_start = B_FALSE; 3884*2336Snarayan vgen_private_desc_t *tbufp; 3885*2336Snarayan uint32_t next_rxi; 3886*2336Snarayan boolean_t ready_txd = B_FALSE; 3887*2336Snarayan uint32_t retries = 0; 38881991Sheppo #ifdef VGEN_HANDLE_LOST_PKTS 38891991Sheppo int n; 38901991Sheppo #endif 38911991Sheppo #ifdef VGEN_REXMIT 38921991Sheppo uint64_t seqnum; 38931991Sheppo #endif 38941991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 38951991Sheppo 38961991Sheppo dringmsg = (vio_dring_msg_t *)tagp; 38971991Sheppo start = dringmsg->start_idx; 38981991Sheppo end = dringmsg->end_idx; 38991991Sheppo statsp = ldcp->statsp; 39001991Sheppo 39011991Sheppo DBG1((vnetp, "vgen_handle_dring_data: enter\n")); 39021991Sheppo switch (tagp->vio_subtype) { 39031991Sheppo 39041991Sheppo case VIO_SUBTYPE_INFO: 39051991Sheppo /* 39061991Sheppo * received a data msg, which contains the start and end 39071991Sheppo * indeces of the descriptors within the rx ring holding data, 39081991Sheppo * the seq_num of data packet corresponding to the start index, 39091991Sheppo * and the dring_ident. 39101991Sheppo * We can now read the contents of each of these descriptors 39111991Sheppo * and gather data from it. 39121991Sheppo */ 39131991Sheppo DBG2((vnetp, 39141991Sheppo "vgen_handle_dring_data: INFO: start(%d), end(%d)\n", 39151991Sheppo start, end)); 39161991Sheppo 39171991Sheppo /* validate rx start and end indeces */ 3918*2336Snarayan if (!(CHECK_RXI(start, ldcp)) || ((end != -1) && 3919*2336Snarayan !(CHECK_RXI(end, ldcp)))) { 39201991Sheppo /* drop the message if invalid index */ 39211991Sheppo break; 39221991Sheppo } 39231991Sheppo 39241991Sheppo /* validate dring_ident */ 39251991Sheppo if (dringmsg->dring_ident != ldcp->peer_hparams.dring_ident) { 39261991Sheppo /* invalid dring_ident, drop the msg */ 39271991Sheppo break; 39281991Sheppo } 39291991Sheppo #ifdef DEBUG 39301991Sheppo if (vgen_trigger_rxlost) { 39311991Sheppo /* drop this msg to simulate lost pkts for debugging */ 39321991Sheppo vgen_trigger_rxlost = 0; 39331991Sheppo break; 39341991Sheppo } 39351991Sheppo #endif 39361991Sheppo 39371991Sheppo #ifdef VGEN_HANDLE_LOST_PKTS 39381991Sheppo 39391991Sheppo /* receive start index doesn't match expected index */ 39401991Sheppo if (ldcp->next_rxi != start) { 39411991Sheppo 39421991Sheppo DWARN((vnetp, "vgen_handle_dring_data: id(%lx) " 39431991Sheppo "next_rxi(%d) != start(%d)\n", 39441991Sheppo ldcp->ldc_id, ldcp->next_rxi, start)); 39451991Sheppo 39461991Sheppo /* calculate the number of pkts lost */ 39471991Sheppo if (start >= ldcp->next_rxi) { 39481991Sheppo n = start - ldcp->next_rxi; 39491991Sheppo } else { 39501991Sheppo n = ldcp->num_rxds - (ldcp->next_rxi - start); 39511991Sheppo } 39521991Sheppo 39531991Sheppo /* 3954*2336Snarayan * sequence number of dring data message 39551991Sheppo * is less than the next sequence number that 39561991Sheppo * is expected: 39571991Sheppo * 39581991Sheppo * drop the message and the corresponding packets. 39591991Sheppo */ 39601991Sheppo if (ldcp->next_rxseq > dringmsg->seq_num) { 39611991Sheppo DWARN((vnetp, "vgen_handle_dring_data: id(%lx) " 39621991Sheppo "dropping pkts, expected rxseq(0x%lx) " 39631991Sheppo "> recvd(0x%lx)\n", 39641991Sheppo ldcp->ldc_id, ldcp->next_rxseq, 39651991Sheppo dringmsg->seq_num)); 39661991Sheppo /* 39671991Sheppo * duplicate/multiple retransmissions from 39681991Sheppo * sender?? drop this msg. 39691991Sheppo */ 39701991Sheppo break; 39711991Sheppo } 39721991Sheppo 39731991Sheppo /* 3974*2336Snarayan * sequence number of dring data message 39751991Sheppo * is greater than the next expected sequence number 39761991Sheppo * 39771991Sheppo * send a NACK back to the peer to indicate lost 39781991Sheppo * packets. 39791991Sheppo */ 39801991Sheppo if (dringmsg->seq_num > ldcp->next_rxseq) { 39811991Sheppo statsp->rx_lost_pkts += n; 39821991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 39831991Sheppo tagp->vio_sid = ldcp->local_sid; 39841991Sheppo /* indicate the range of lost descriptors */ 39851991Sheppo dringmsg->start_idx = ldcp->next_rxi; 39861991Sheppo rxi = start; 39871991Sheppo DECR_RXI(rxi, ldcp); 39881991Sheppo dringmsg->end_idx = rxi; 39891991Sheppo /* dring ident is left unchanged */ 39901991Sheppo if (vgen_sendmsg(ldcp, (caddr_t)tagp, 39911991Sheppo sizeof (*dringmsg), B_FALSE)) { 39921991Sheppo DWARN((vnetp, 39931991Sheppo "vgen_handle_dring_data: id(%lx) " 39941991Sheppo "vgen_sendmsg failed, " 39951991Sheppo "stype: NACK\n", ldcp->ldc_id)); 39961991Sheppo } 39971991Sheppo #ifdef VGEN_REXMIT 39981991Sheppo /* 39991991Sheppo * stop further processing until peer 4000*2336Snarayan * retransmits with the right index. 4001*2336Snarayan * update next_rxseq expected. 40021991Sheppo */ 4003*2336Snarayan ldcp->next_rxseq += 1; 40041991Sheppo break; 40051991Sheppo #else /* VGEN_REXMIT */ 40061991Sheppo /* 40071991Sheppo * treat this range of descrs/pkts as dropped 40081991Sheppo * and set the new expected values for next_rxi 40091991Sheppo * and next_rxseq. continue(below) to process 40101991Sheppo * from the new start index. 40111991Sheppo */ 40121991Sheppo ldcp->next_rxi = start; 4013*2336Snarayan ldcp->next_rxseq += 1; 40141991Sheppo #endif /* VGEN_REXMIT */ 40151991Sheppo 40161991Sheppo } else if (dringmsg->seq_num == ldcp->next_rxseq) { 40171991Sheppo /* 4018*2336Snarayan * expected and received seqnums match, but 40191991Sheppo * the descriptor indeces don't? 40201991Sheppo * 40211991Sheppo * restart handshake with peer. 40221991Sheppo */ 40231991Sheppo DWARN((vnetp, 40241991Sheppo "vgen_handle_dring_data: id(%lx) " 40251991Sheppo "next_rxseq(0x%lx) == seq_num(0x%lx)\n", 40261991Sheppo ldcp->ldc_id, ldcp->next_rxseq, 40271991Sheppo dringmsg->seq_num)); 40281991Sheppo 40291991Sheppo } 40301991Sheppo 40311991Sheppo } else { 40321991Sheppo /* expected and start dring indeces match */ 40331991Sheppo 40341991Sheppo if (dringmsg->seq_num != ldcp->next_rxseq) { 40351991Sheppo 40361991Sheppo /* seqnums don't match */ 40371991Sheppo 40381991Sheppo DWARN((vnetp, 40391991Sheppo "vgen_handle_dring_data: id(%lx) " 40401991Sheppo "next_rxseq(0x%lx) != seq_num(0x%lx)\n", 40411991Sheppo ldcp->ldc_id, ldcp->next_rxseq, 40421991Sheppo dringmsg->seq_num)); 40431991Sheppo } 40441991Sheppo } 40451991Sheppo 40461991Sheppo #endif /* VGEN_HANDLE_LOST_PKTS */ 40471991Sheppo 40481991Sheppo /* 4049*2336Snarayan * start processing the descriptors from the specified 4050*2336Snarayan * start index, up to the index a descriptor is not ready 4051*2336Snarayan * to be processed or we process the entire descriptor ring 4052*2336Snarayan * and wrap around upto the start index. 40531991Sheppo */ 4054*2336Snarayan 4055*2336Snarayan /* need to set the start index of descriptors to be ack'd */ 4056*2336Snarayan set_ack_start = B_TRUE; 4057*2336Snarayan 4058*2336Snarayan /* index upto which we have ack'd */ 4059*2336Snarayan ack_end = start; 4060*2336Snarayan DECR_RXI(ack_end, ldcp); 4061*2336Snarayan 4062*2336Snarayan next_rxi = rxi = start; 40631991Sheppo do { 4064*2336Snarayan 4065*2336Snarayan vgen_recv_retry: if (ldc_mem_dring_acquire(ldcp->rx_dhandle, 4066*2336Snarayan rxi, rxi)) { 4067*2336Snarayan DWARN((vnetp, "vgen_handle_dring_data: " 4068*2336Snarayan "id(%lx), ldc_mem_dring_acquire() failed\n", 4069*2336Snarayan ldcp->ldc_id)); 4070*2336Snarayan statsp->ierrors++; 4071*2336Snarayan break; 4072*2336Snarayan } 40731991Sheppo 40741991Sheppo rxdp = &(ldcp->rxdp[rxi]); 40751991Sheppo hdrp = &rxdp->hdr; 40761991Sheppo 4077*2336Snarayan if (hdrp->dstate != VIO_DESC_READY) { 4078*2336Snarayan /* 4079*2336Snarayan * descriptor is not ready. 4080*2336Snarayan * retry descriptor acquire, stop processing 4081*2336Snarayan * after max # retries. 4082*2336Snarayan */ 4083*2336Snarayan if (retries == vgen_recv_retries) 4084*2336Snarayan break; 4085*2336Snarayan retries++; 4086*2336Snarayan drv_usecwait(vgen_recv_delay); 4087*2336Snarayan goto vgen_recv_retry; 4088*2336Snarayan } 4089*2336Snarayan retries = 0; 4090*2336Snarayan 4091*2336Snarayan if (set_ack_start) { 4092*2336Snarayan /* 4093*2336Snarayan * initialize the start index of the range 4094*2336Snarayan * of descriptors to be ack'd. 4095*2336Snarayan */ 4096*2336Snarayan ack_start = rxi; 4097*2336Snarayan set_ack_start = B_FALSE; 4098*2336Snarayan } 4099*2336Snarayan 41001991Sheppo datalen = rxdp->nbytes; 41011991Sheppo ncookies = rxdp->ncookies; 41021991Sheppo if ((datalen < ETHERMIN) || 41031991Sheppo (ncookies == 0) || 4104*2336Snarayan (ncookies > MAX_COOKIES)) { 41051991Sheppo rxd_err = B_TRUE; 41061991Sheppo } else { 41071991Sheppo /* 4108*2336Snarayan * Try to allocate an mblk from the free pool 4109*2336Snarayan * of recv mblks for the channel. 4110*2336Snarayan * If this fails, use allocb(). 41111991Sheppo */ 4112*2336Snarayan mp = vio_allocb(ldcp->rmp); 4113*2336Snarayan if (!mp) { 4114*2336Snarayan /* 4115*2336Snarayan * The data buffer returned by 4116*2336Snarayan * allocb(9F) is 8byte aligned. We 4117*2336Snarayan * allocate extra 8 bytes to ensure 4118*2336Snarayan * size is multiple of 8 bytes for 4119*2336Snarayan * ldc_mem_copy(). 4120*2336Snarayan */ 4121*2336Snarayan statsp->rx_vio_allocb_fail++; 4122*2336Snarayan mp = allocb(VNET_IPALIGN + datalen + 8, 4123*2336Snarayan BPRI_MED); 4124*2336Snarayan } 4125*2336Snarayan nbytes = (VNET_IPALIGN + datalen + 7) & ~7; 41261991Sheppo } 41271991Sheppo if ((rxd_err) || (mp == NULL)) { 41281991Sheppo /* 41291991Sheppo * rxd_err or allocb() failure, 41301991Sheppo * drop this packet, get next. 41311991Sheppo */ 41321991Sheppo if (rxd_err) { 41331991Sheppo statsp->ierrors++; 41341991Sheppo rxd_err = B_FALSE; 41351991Sheppo } else { 41361991Sheppo statsp->rx_allocb_fail++; 41371991Sheppo } 41381991Sheppo 41391991Sheppo /* set descriptor done bit */ 41401991Sheppo hdrp->dstate = VIO_DESC_DONE; 41411991Sheppo 4142*2336Snarayan (void) ldc_mem_dring_release(ldcp->rx_dhandle, 4143*2336Snarayan rxi, rxi); 4144*2336Snarayan 41451991Sheppo if (hdrp->ack) { 41461991Sheppo /* 4147*2336Snarayan * sender needs ack for this packet, 4148*2336Snarayan * ack pkts upto this index. 41491991Sheppo */ 4150*2336Snarayan ack_end = rxi; 4151*2336Snarayan 4152*2336Snarayan vgen_send_dring_ack(ldcp, tagp, 4153*2336Snarayan ack_start, ack_end, 4154*2336Snarayan VIO_DP_ACTIVE); 4155*2336Snarayan 4156*2336Snarayan /* need to set new ack start index */ 4157*2336Snarayan set_ack_start = B_TRUE; 41581991Sheppo } 41591991Sheppo goto vgen_next_rxi; 41601991Sheppo } 41611991Sheppo 41621991Sheppo nread = nbytes; 41631991Sheppo rv = ldc_mem_copy(ldcp->ldc_handle, 41641991Sheppo (caddr_t)mp->b_rptr, off, &nread, 41651991Sheppo rxdp->memcookie, ncookies, LDC_COPY_IN); 41661991Sheppo 41671991Sheppo /* set done bit irrespective of rv of ldc_mem_copy() */ 41681991Sheppo hdrp->dstate = VIO_DESC_DONE; 41691991Sheppo 4170*2336Snarayan (void) ldc_mem_dring_release(ldcp->rx_dhandle, 4171*2336Snarayan rxi, rxi); 4172*2336Snarayan 4173*2336Snarayan mp->b_rptr += VNET_IPALIGN; 4174*2336Snarayan 41751991Sheppo if (hdrp->ack) { 41761991Sheppo /* 4177*2336Snarayan * sender needs ack for this packet, 4178*2336Snarayan * ack pkts upto this index. 41791991Sheppo */ 4180*2336Snarayan ack_end = rxi; 4181*2336Snarayan 4182*2336Snarayan vgen_send_dring_ack(ldcp, tagp, 4183*2336Snarayan ack_start, ack_end, VIO_DP_ACTIVE); 4184*2336Snarayan 4185*2336Snarayan /* need to set new ack start index */ 4186*2336Snarayan set_ack_start = B_TRUE; 41871991Sheppo } 4188*2336Snarayan 41891991Sheppo /* if ldc_mem_copy() failed */ 41901991Sheppo if (rv) { 41911991Sheppo DWARN((vnetp, 41921991Sheppo "vgen_handle_dring_data: id(%lx) " 41931991Sheppo "ldc_mem_copy failed\n", ldcp->ldc_id)); 41941991Sheppo statsp->ierrors++; 41951991Sheppo freemsg(mp); 41961991Sheppo goto vgen_next_rxi; 41971991Sheppo } 41981991Sheppo if (nread != nbytes) { 41991991Sheppo DWARN((vnetp, 42001991Sheppo "vgen_handle_dring_data: id(%lx) " 42011991Sheppo "ldc_mem_copy nread(%lx), nbytes(%lx)\n", 42021991Sheppo ldcp->ldc_id, nread, nbytes)); 42031991Sheppo statsp->ierrors++; 42041991Sheppo freemsg(mp); 42051991Sheppo goto vgen_next_rxi; 42061991Sheppo } 42071991Sheppo 42081991Sheppo /* point to the actual end of data */ 42091991Sheppo mp->b_wptr = mp->b_rptr + datalen; 42101991Sheppo 42111991Sheppo /* update stats */ 42121991Sheppo statsp->ipackets++; 42131991Sheppo statsp->rbytes += datalen; 42141991Sheppo ehp = (struct ether_header *)mp->b_rptr; 42151991Sheppo if (IS_BROADCAST(ehp)) 42161991Sheppo statsp->brdcstrcv++; 42171991Sheppo else if (IS_MULTICAST(ehp)) 42181991Sheppo statsp->multircv++; 42191991Sheppo 42201991Sheppo /* build a chain of received packets */ 42211991Sheppo if (bp == NULL) { 42221991Sheppo /* first pkt */ 42231991Sheppo bp = mp; 42241991Sheppo bpt = bp; 42251991Sheppo bpt->b_next = NULL; 42261991Sheppo } else { 42271991Sheppo mp->b_next = NULL; 42281991Sheppo bpt->b_next = mp; 42291991Sheppo bpt = mp; 42301991Sheppo } 42311991Sheppo 4232*2336Snarayan 4233*2336Snarayan vgen_next_rxi: 4234*2336Snarayan /* update end index of range of descrs to be ack'd */ 4235*2336Snarayan ack_end = rxi; 4236*2336Snarayan 4237*2336Snarayan /* update the next index to be processed */ 4238*2336Snarayan INCR_RXI(next_rxi, ldcp); 4239*2336Snarayan if (next_rxi == start) { 4240*2336Snarayan /* 4241*2336Snarayan * processed the entire descriptor ring upto 4242*2336Snarayan * the index at which we started. 4243*2336Snarayan */ 42441991Sheppo break; 42451991Sheppo } 4246*2336Snarayan 4247*2336Snarayan rxi = next_rxi; 42481991Sheppo 42491991Sheppo _NOTE(CONSTCOND) 42501991Sheppo } while (1); 42511991Sheppo 4252*2336Snarayan /* 4253*2336Snarayan * send an ack message to peer indicating that we have stopped 4254*2336Snarayan * processing descriptors. 4255*2336Snarayan */ 4256*2336Snarayan if (set_ack_start) { 4257*2336Snarayan /* 4258*2336Snarayan * We have ack'd upto some index and we have not 4259*2336Snarayan * processed any descriptors beyond that index. 4260*2336Snarayan * Use the last ack'd index as both the start and 4261*2336Snarayan * end of range of descrs being ack'd. 4262*2336Snarayan * Note: This results in acking the last index twice 4263*2336Snarayan * and should be harmless. 4264*2336Snarayan */ 4265*2336Snarayan ack_start = ack_end; 42661991Sheppo } 42671991Sheppo 4268*2336Snarayan vgen_send_dring_ack(ldcp, tagp, ack_start, ack_end, 4269*2336Snarayan VIO_DP_STOPPED); 4270*2336Snarayan 4271*2336Snarayan /* save new recv index and expected seqnum of next dring msg */ 4272*2336Snarayan ldcp->next_rxi = next_rxi; 4273*2336Snarayan ldcp->next_rxseq += 1; 4274*2336Snarayan 42751991Sheppo break; 42761991Sheppo 42771991Sheppo case VIO_SUBTYPE_ACK: 42781991Sheppo /* 42791991Sheppo * received an ack corresponding to a specific descriptor for 42801991Sheppo * which we had set the ACK bit in the descriptor (during 42811991Sheppo * transmit). This enables us to reclaim descriptors. 42821991Sheppo */ 4283*2336Snarayan 42841991Sheppo DBG2((vnetp, 42851991Sheppo "vgen_handle_dring_data: ACK: start(%d), end(%d)\n", 42861991Sheppo start, end)); 42871991Sheppo 42881991Sheppo /* validate start and end indeces in the tx ack msg */ 42891991Sheppo if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) { 42901991Sheppo /* drop the message if invalid index */ 42911991Sheppo break; 42921991Sheppo } 42931991Sheppo /* validate dring_ident */ 42941991Sheppo if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) { 42951991Sheppo /* invalid dring_ident, drop the msg */ 42961991Sheppo break; 42971991Sheppo } 42981991Sheppo statsp->dring_data_acks++; 4299*2336Snarayan 4300*2336Snarayan /* reclaim descriptors that are done */ 43011991Sheppo vgen_reclaim(ldcp); 4302*2336Snarayan 4303*2336Snarayan if (dringmsg->dring_process_state != VIO_DP_STOPPED) { 4304*2336Snarayan /* 4305*2336Snarayan * receiver continued processing descriptors after 4306*2336Snarayan * sending us the ack. 4307*2336Snarayan */ 4308*2336Snarayan break; 4309*2336Snarayan } 4310*2336Snarayan 4311*2336Snarayan statsp->dring_stopped_acks++; 4312*2336Snarayan 4313*2336Snarayan /* receiver stopped processing descriptors */ 4314*2336Snarayan mutex_enter(&ldcp->txlock); 4315*2336Snarayan mutex_enter(&ldcp->tclock); 4316*2336Snarayan 4317*2336Snarayan /* 4318*2336Snarayan * determine if there are any pending tx descriptors 4319*2336Snarayan * ready to be processed by the receiver(peer) and if so, 4320*2336Snarayan * send a message to the peer to restart receiving. 4321*2336Snarayan */ 4322*2336Snarayan ready_txd = B_FALSE; 4323*2336Snarayan 4324*2336Snarayan /* 4325*2336Snarayan * using the end index of the descriptor range for which 4326*2336Snarayan * we received the ack, check if the next descriptor is 4327*2336Snarayan * ready. 4328*2336Snarayan */ 4329*2336Snarayan txi = end; 4330*2336Snarayan INCR_TXI(txi, ldcp); 4331*2336Snarayan tbufp = &ldcp->tbufp[txi]; 4332*2336Snarayan txdp = tbufp->descp; 4333*2336Snarayan hdrp = &txdp->hdr; 4334*2336Snarayan if (hdrp->dstate == VIO_DESC_READY) { 4335*2336Snarayan ready_txd = B_TRUE; 4336*2336Snarayan } else { 4337*2336Snarayan /* 4338*2336Snarayan * descr next to the end of ack'd descr range is not 4339*2336Snarayan * ready. 4340*2336Snarayan * starting from the current reclaim index, check 4341*2336Snarayan * if any descriptor is ready. 4342*2336Snarayan */ 4343*2336Snarayan 4344*2336Snarayan txi = ldcp->cur_tbufp - ldcp->tbufp; 4345*2336Snarayan tbufp = &ldcp->tbufp[txi]; 4346*2336Snarayan 4347*2336Snarayan while (tbufp != ldcp->next_tbufp) { 4348*2336Snarayan 4349*2336Snarayan txdp = tbufp->descp; 4350*2336Snarayan hdrp = &txdp->hdr; 4351*2336Snarayan if (hdrp->dstate == VIO_DESC_READY) { 4352*2336Snarayan break; 4353*2336Snarayan } 4354*2336Snarayan 4355*2336Snarayan INCR_TXI(txi, ldcp); 4356*2336Snarayan tbufp = &ldcp->tbufp[txi]; 4357*2336Snarayan 4358*2336Snarayan } 4359*2336Snarayan 4360*2336Snarayan if (tbufp != ldcp->next_tbufp) 4361*2336Snarayan ready_txd = B_TRUE; 4362*2336Snarayan } 4363*2336Snarayan 4364*2336Snarayan if (ready_txd) { 4365*2336Snarayan /* 4366*2336Snarayan * we have tx descriptor(s) ready to be 4367*2336Snarayan * processed by the receiver. 4368*2336Snarayan * send a message to the peer with the start index 4369*2336Snarayan * of ready descriptors. 4370*2336Snarayan */ 4371*2336Snarayan rv = vgen_send_dring_data(ldcp, txi, -1); 4372*2336Snarayan if (rv != 0) { 4373*2336Snarayan ldcp->resched_peer = B_TRUE; 4374*2336Snarayan } 4375*2336Snarayan } else { 4376*2336Snarayan /* 4377*2336Snarayan * no ready tx descriptors. set the flag to send a 4378*2336Snarayan * message to peer when tx descriptors are ready in 4379*2336Snarayan * transmit routine. 4380*2336Snarayan */ 4381*2336Snarayan ldcp->resched_peer = B_TRUE; 4382*2336Snarayan } 4383*2336Snarayan 4384*2336Snarayan mutex_exit(&ldcp->tclock); 4385*2336Snarayan mutex_exit(&ldcp->txlock); 4386*2336Snarayan 43871991Sheppo break; 43881991Sheppo 43891991Sheppo case VIO_SUBTYPE_NACK: 43901991Sheppo /* 43911991Sheppo * peer sent a NACK msg to indicate lost packets. 43921991Sheppo * The start and end correspond to the range of descriptors 43931991Sheppo * for which the peer didn't receive a dring data msg and so 43941991Sheppo * didn't receive the corresponding data. 43951991Sheppo */ 43961991Sheppo DWARN((vnetp, 43971991Sheppo "vgen_handle_dring_data: NACK: start(%d), end(%d)\n", 43981991Sheppo start, end)); 43991991Sheppo 44001991Sheppo /* validate start and end indeces in the tx nack msg */ 44011991Sheppo if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) { 44021991Sheppo /* drop the message if invalid index */ 44031991Sheppo break; 44041991Sheppo } 44051991Sheppo /* validate dring_ident */ 44061991Sheppo if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) { 44071991Sheppo /* invalid dring_ident, drop the msg */ 44081991Sheppo break; 44091991Sheppo } 44101991Sheppo mutex_enter(&ldcp->txlock); 44111991Sheppo mutex_enter(&ldcp->tclock); 44121991Sheppo 44131991Sheppo if (ldcp->next_tbufp == ldcp->cur_tbufp) { 44141991Sheppo /* no busy descriptors, bogus nack ? */ 44151991Sheppo mutex_exit(&ldcp->tclock); 44161991Sheppo mutex_exit(&ldcp->txlock); 44171991Sheppo break; 44181991Sheppo } 44191991Sheppo 44201991Sheppo #ifdef VGEN_REXMIT 44211991Sheppo /* send a new dring data msg including the lost descrs */ 44221991Sheppo end = ldcp->next_tbufp - ldcp->tbufp; 44231991Sheppo DECR_TXI(end, ldcp); 4424*2336Snarayan rv = vgen_send_dring_data(ldcp, start, end); 44251991Sheppo if (rv != 0) { 44261991Sheppo /* 44271991Sheppo * vgen_send_dring_data() error: drop all packets 44281991Sheppo * in this descr range 44291991Sheppo */ 44301991Sheppo DWARN((vnetp, 44311991Sheppo "vgen_handle_dring_data: " 44321991Sheppo "vgen_send_dring_data failed :" 44331991Sheppo "id(%lx) rv(%d)\n", ldcp->ldc_id, rv)); 44341991Sheppo for (txi = start; txi <= end; ) { 44351991Sheppo tbufp = &(ldcp->tbufp[txi]); 44361991Sheppo txdp = tbufp->descp; 44371991Sheppo hdrp = &txdp->hdr; 44381991Sheppo tbufp->flags = VGEN_PRIV_DESC_FREE; 44391991Sheppo hdrp->dstate = VIO_DESC_FREE; 44401991Sheppo hdrp->ack = B_FALSE; 44411991Sheppo statsp->oerrors++; 44421991Sheppo } 44431991Sheppo 44441991Sheppo /* update next pointer */ 44451991Sheppo ldcp->next_tbufp = &(ldcp->tbufp[start]); 44461991Sheppo ldcp->next_txi = start; 44471991Sheppo } 44481991Sheppo DBG2((vnetp, 44491991Sheppo "vgen_handle_dring_data: rexmit: start(%d) end(%d)\n", 44501991Sheppo start, end)); 44511991Sheppo #else /* VGEN_REXMIT */ 44521991Sheppo /* we just mark the descrs as done so they can be reclaimed */ 44531991Sheppo for (txi = start; txi <= end; ) { 44541991Sheppo txdp = &(ldcp->txdp[txi]); 44551991Sheppo hdrp = &txdp->hdr; 44561991Sheppo if (hdrp->dstate == VIO_DESC_READY) 44571991Sheppo hdrp->dstate = VIO_DESC_DONE; 44581991Sheppo INCR_TXI(txi, ldcp); 44591991Sheppo } 44601991Sheppo #endif /* VGEN_REXMIT */ 44611991Sheppo mutex_exit(&ldcp->tclock); 44621991Sheppo mutex_exit(&ldcp->txlock); 44631991Sheppo 44641991Sheppo break; 44651991Sheppo } 44661991Sheppo 44671991Sheppo DBG1((vnetp, "vgen_handle_dring_data: exit\n")); 44681991Sheppo *headp = bp; 44691991Sheppo *tailp = bpt; 4470*2336Snarayan 44711991Sheppo } 44721991Sheppo 44731991Sheppo static void 44741991Sheppo vgen_reclaim(vgen_ldc_t *ldcp) 44751991Sheppo { 4476*2336Snarayan mutex_enter(&ldcp->tclock); 4477*2336Snarayan 44781991Sheppo vgen_reclaim_dring(ldcp); 44791991Sheppo ldcp->reclaim_lbolt = ddi_get_lbolt(); 4480*2336Snarayan 44811991Sheppo mutex_exit(&ldcp->tclock); 44821991Sheppo } 44831991Sheppo 44841991Sheppo /* 44851991Sheppo * transmit reclaim function. starting from the current reclaim index 44861991Sheppo * look for descriptors marked DONE and reclaim the descriptor and the 44871991Sheppo * corresponding buffers (tbuf). 44881991Sheppo */ 44891991Sheppo static void 44901991Sheppo vgen_reclaim_dring(vgen_ldc_t *ldcp) 44911991Sheppo { 44921991Sheppo vnet_public_desc_t *txdp; 44931991Sheppo vgen_private_desc_t *tbufp; 44941991Sheppo vio_dring_entry_hdr_t *hdrp; 4495*2336Snarayan vgen_t *vgenp = LDC_TO_VGEN(ldcp); 44961991Sheppo 44971991Sheppo #ifdef DEBUG 44981991Sheppo if (vgen_trigger_txtimeout) 44991991Sheppo return; 45001991Sheppo #endif 45011991Sheppo 45021991Sheppo tbufp = ldcp->cur_tbufp; 45031991Sheppo txdp = tbufp->descp; 45041991Sheppo hdrp = &txdp->hdr; 45051991Sheppo 45061991Sheppo while ((hdrp->dstate == VIO_DESC_DONE) && 45071991Sheppo (tbufp != ldcp->next_tbufp)) { 45081991Sheppo tbufp->flags = VGEN_PRIV_DESC_FREE; 45091991Sheppo hdrp->dstate = VIO_DESC_FREE; 45101991Sheppo hdrp->ack = B_FALSE; 45111991Sheppo 45121991Sheppo tbufp = NEXTTBUF(ldcp, tbufp); 45131991Sheppo txdp = tbufp->descp; 45141991Sheppo hdrp = &txdp->hdr; 45151991Sheppo } 45161991Sheppo 45171991Sheppo ldcp->cur_tbufp = tbufp; 45181991Sheppo 45191991Sheppo /* 45201991Sheppo * Check if mac layer should be notified to restart transmissions 45211991Sheppo */ 45221991Sheppo if (ldcp->need_resched) { 45231991Sheppo ldcp->need_resched = B_FALSE; 45242311Sseb vnet_tx_update(vgenp->vnetp); 45251991Sheppo } 45261991Sheppo } 45271991Sheppo 45281991Sheppo /* return the number of pending transmits for the channel */ 45291991Sheppo static int 45301991Sheppo vgen_num_txpending(vgen_ldc_t *ldcp) 45311991Sheppo { 45321991Sheppo int n; 45331991Sheppo 45341991Sheppo if (ldcp->next_tbufp >= ldcp->cur_tbufp) { 45351991Sheppo n = ldcp->next_tbufp - ldcp->cur_tbufp; 45361991Sheppo } else { 45371991Sheppo /* cur_tbufp > next_tbufp */ 45381991Sheppo n = ldcp->num_txds - (ldcp->cur_tbufp - ldcp->next_tbufp); 45391991Sheppo } 45401991Sheppo 45411991Sheppo return (n); 45421991Sheppo } 45431991Sheppo 45441991Sheppo /* determine if the transmit descriptor ring is full */ 45451991Sheppo static int 45461991Sheppo vgen_tx_dring_full(vgen_ldc_t *ldcp) 45471991Sheppo { 45481991Sheppo vgen_private_desc_t *tbufp; 45491991Sheppo vgen_private_desc_t *ntbufp; 45501991Sheppo 45511991Sheppo tbufp = ldcp->next_tbufp; 45521991Sheppo ntbufp = NEXTTBUF(ldcp, tbufp); 45531991Sheppo if (ntbufp == ldcp->cur_tbufp) { /* out of tbufs/txds */ 45541991Sheppo return (VGEN_SUCCESS); 45551991Sheppo } 45561991Sheppo return (VGEN_FAILURE); 45571991Sheppo } 45581991Sheppo 45591991Sheppo /* determine if timeout condition has occured */ 45601991Sheppo static int 45611991Sheppo vgen_ldc_txtimeout(vgen_ldc_t *ldcp) 45621991Sheppo { 45631991Sheppo if (((ddi_get_lbolt() - ldcp->reclaim_lbolt) > 45641991Sheppo drv_usectohz(vnet_ldcwd_txtimeout * 1000)) && 45651991Sheppo (vnet_ldcwd_txtimeout) && 45661991Sheppo (vgen_tx_dring_full(ldcp) == VGEN_SUCCESS)) { 45671991Sheppo return (VGEN_SUCCESS); 45681991Sheppo } else { 45691991Sheppo return (VGEN_FAILURE); 45701991Sheppo } 45711991Sheppo } 45721991Sheppo 45731991Sheppo /* transmit watchdog timeout handler */ 45741991Sheppo static void 45751991Sheppo vgen_ldc_watchdog(void *arg) 45761991Sheppo { 45771991Sheppo vgen_ldc_t *ldcp; 4578*2336Snarayan vgen_t *vgenp; 45791991Sheppo void *vnetp; 45801991Sheppo int rv; 45811991Sheppo 45821991Sheppo ldcp = (vgen_ldc_t *)arg; 4583*2336Snarayan vgenp = LDC_TO_VGEN(ldcp); 45841991Sheppo vnetp = LDC_TO_VNET(ldcp); 45851991Sheppo 45861991Sheppo rv = vgen_ldc_txtimeout(ldcp); 45871991Sheppo if (rv == VGEN_SUCCESS) { 45881991Sheppo DWARN((vnetp, 45891991Sheppo "vgen_ldc_watchdog: transmit timeout ldcid(%lx)\n", 45901991Sheppo ldcp->ldc_id)); 45911991Sheppo #ifdef DEBUG 45921991Sheppo if (vgen_trigger_txtimeout) { 45931991Sheppo /* tx timeout triggered for debugging */ 45941991Sheppo vgen_trigger_txtimeout = 0; 45951991Sheppo } 45961991Sheppo #endif 45971991Sheppo mutex_enter(&ldcp->cblock); 45981991Sheppo vgen_handshake_retry(ldcp); 45991991Sheppo mutex_exit(&ldcp->cblock); 46001991Sheppo if (ldcp->need_resched) { 46011991Sheppo ldcp->need_resched = B_FALSE; 4602*2336Snarayan vnet_tx_update(vgenp->vnetp); 46031991Sheppo } 46041991Sheppo } 46051991Sheppo 46061991Sheppo ldcp->wd_tid = timeout(vgen_ldc_watchdog, (caddr_t)ldcp, 46071991Sheppo drv_usectohz(vnet_ldcwd_interval * 1000)); 46081991Sheppo } 46091991Sheppo 46101991Sheppo static int 46111991Sheppo vgen_setup_kstats(vgen_ldc_t *ldcp) 46121991Sheppo { 46131991Sheppo vgen_t *vgenp; 46141991Sheppo struct kstat *ksp; 46151991Sheppo vgen_stats_t *statsp; 46161991Sheppo vgen_kstats_t *ldckp; 46171991Sheppo int instance; 46181991Sheppo size_t size; 46191991Sheppo char name[MAXNAMELEN]; 46201991Sheppo 46211991Sheppo vgenp = LDC_TO_VGEN(ldcp); 46221991Sheppo instance = ddi_get_instance(vgenp->vnetdip); 46231991Sheppo (void) sprintf(name, "vnetldc0x%lx", ldcp->ldc_id); 46241991Sheppo statsp = kmem_zalloc(sizeof (vgen_stats_t), KM_SLEEP); 46251991Sheppo if (statsp == NULL) { 46261991Sheppo return (VGEN_FAILURE); 46271991Sheppo } 46281991Sheppo size = sizeof (vgen_kstats_t) / sizeof (kstat_named_t); 46291991Sheppo ksp = kstat_create("vnet", instance, name, "net", KSTAT_TYPE_NAMED, 46301991Sheppo size, 0); 46311991Sheppo if (ksp == NULL) { 46321991Sheppo KMEM_FREE(statsp); 46331991Sheppo return (VGEN_FAILURE); 46341991Sheppo } 46351991Sheppo 46361991Sheppo ldckp = (vgen_kstats_t *)ksp->ks_data; 46371991Sheppo kstat_named_init(&ldckp->ipackets, "ipackets", 46381991Sheppo KSTAT_DATA_ULONG); 46391991Sheppo kstat_named_init(&ldckp->ipackets64, "ipackets64", 46401991Sheppo KSTAT_DATA_ULONGLONG); 46411991Sheppo kstat_named_init(&ldckp->ierrors, "ierrors", 46421991Sheppo KSTAT_DATA_ULONG); 46431991Sheppo kstat_named_init(&ldckp->opackets, "opackets", 46441991Sheppo KSTAT_DATA_ULONG); 46451991Sheppo kstat_named_init(&ldckp->opackets64, "opackets64", 46461991Sheppo KSTAT_DATA_ULONGLONG); 46471991Sheppo kstat_named_init(&ldckp->oerrors, "oerrors", 46481991Sheppo KSTAT_DATA_ULONG); 46491991Sheppo 46501991Sheppo 46511991Sheppo /* MIB II kstat variables */ 46521991Sheppo kstat_named_init(&ldckp->rbytes, "rbytes", 46531991Sheppo KSTAT_DATA_ULONG); 46541991Sheppo kstat_named_init(&ldckp->rbytes64, "rbytes64", 46551991Sheppo KSTAT_DATA_ULONGLONG); 46561991Sheppo kstat_named_init(&ldckp->obytes, "obytes", 46571991Sheppo KSTAT_DATA_ULONG); 46581991Sheppo kstat_named_init(&ldckp->obytes64, "obytes64", 46591991Sheppo KSTAT_DATA_ULONGLONG); 46601991Sheppo kstat_named_init(&ldckp->multircv, "multircv", 46611991Sheppo KSTAT_DATA_ULONG); 46621991Sheppo kstat_named_init(&ldckp->multixmt, "multixmt", 46631991Sheppo KSTAT_DATA_ULONG); 46641991Sheppo kstat_named_init(&ldckp->brdcstrcv, "brdcstrcv", 46651991Sheppo KSTAT_DATA_ULONG); 46661991Sheppo kstat_named_init(&ldckp->brdcstxmt, "brdcstxmt", 46671991Sheppo KSTAT_DATA_ULONG); 46681991Sheppo kstat_named_init(&ldckp->norcvbuf, "norcvbuf", 46691991Sheppo KSTAT_DATA_ULONG); 46701991Sheppo kstat_named_init(&ldckp->noxmtbuf, "noxmtbuf", 46711991Sheppo KSTAT_DATA_ULONG); 46721991Sheppo 46731991Sheppo /* Tx stats */ 46741991Sheppo kstat_named_init(&ldckp->tx_no_desc, "tx_no_desc", 46751991Sheppo KSTAT_DATA_ULONG); 46761991Sheppo 46771991Sheppo /* Rx stats */ 4678*2336Snarayan kstat_named_init(&ldckp->rx_allocb_fail, "rx_allocb_fail", 46791991Sheppo KSTAT_DATA_ULONG); 4680*2336Snarayan kstat_named_init(&ldckp->rx_vio_allocb_fail, "rx_vio_allocb_fail", 46811991Sheppo KSTAT_DATA_ULONG); 46821991Sheppo kstat_named_init(&ldckp->rx_lost_pkts, "rx_lost_pkts", 46831991Sheppo KSTAT_DATA_ULONG); 46841991Sheppo 46851991Sheppo /* Interrupt stats */ 46861991Sheppo kstat_named_init(&ldckp->callbacks, "callbacks", 46871991Sheppo KSTAT_DATA_ULONG); 46881991Sheppo kstat_named_init(&ldckp->dring_data_acks, "dring_data_acks", 46891991Sheppo KSTAT_DATA_ULONG); 4690*2336Snarayan kstat_named_init(&ldckp->dring_stopped_acks, "dring_stopped_acks", 4691*2336Snarayan KSTAT_DATA_ULONG); 4692*2336Snarayan kstat_named_init(&ldckp->dring_data_msgs, "dring_data_msgs", 4693*2336Snarayan KSTAT_DATA_ULONG); 46941991Sheppo 46951991Sheppo ksp->ks_update = vgen_kstat_update; 46961991Sheppo ksp->ks_private = (void *)ldcp; 46971991Sheppo kstat_install(ksp); 46981991Sheppo 46991991Sheppo ldcp->ksp = ksp; 47001991Sheppo ldcp->statsp = statsp; 47011991Sheppo return (VGEN_SUCCESS); 47021991Sheppo } 47031991Sheppo 47041991Sheppo static void 47051991Sheppo vgen_destroy_kstats(vgen_ldc_t *ldcp) 47061991Sheppo { 47071991Sheppo if (ldcp->ksp) 47081991Sheppo kstat_delete(ldcp->ksp); 47091991Sheppo KMEM_FREE(ldcp->statsp); 47101991Sheppo } 47111991Sheppo 47121991Sheppo static int 47131991Sheppo vgen_kstat_update(kstat_t *ksp, int rw) 47141991Sheppo { 47151991Sheppo vgen_ldc_t *ldcp; 47161991Sheppo vgen_stats_t *statsp; 47171991Sheppo vgen_kstats_t *ldckp; 47181991Sheppo 47191991Sheppo ldcp = (vgen_ldc_t *)ksp->ks_private; 47201991Sheppo statsp = ldcp->statsp; 47211991Sheppo ldckp = (vgen_kstats_t *)ksp->ks_data; 47221991Sheppo 47231991Sheppo if (rw == KSTAT_READ) { 47241991Sheppo ldckp->ipackets.value.ul = (uint32_t)statsp->ipackets; 47251991Sheppo ldckp->ipackets64.value.ull = statsp->ipackets; 47261991Sheppo ldckp->ierrors.value.ul = statsp->ierrors; 47271991Sheppo ldckp->opackets.value.ul = (uint32_t)statsp->opackets; 47281991Sheppo ldckp->opackets64.value.ull = statsp->opackets; 47291991Sheppo ldckp->oerrors.value.ul = statsp->oerrors; 47301991Sheppo 47311991Sheppo /* 47321991Sheppo * MIB II kstat variables 47331991Sheppo */ 47341991Sheppo ldckp->rbytes.value.ul = (uint32_t)statsp->rbytes; 47351991Sheppo ldckp->rbytes64.value.ull = statsp->rbytes; 47361991Sheppo ldckp->obytes.value.ul = (uint32_t)statsp->obytes; 47371991Sheppo ldckp->obytes64.value.ull = statsp->obytes; 47381991Sheppo ldckp->multircv.value.ul = statsp->multircv; 47391991Sheppo ldckp->multixmt.value.ul = statsp->multixmt; 47401991Sheppo ldckp->brdcstrcv.value.ul = statsp->brdcstrcv; 47411991Sheppo ldckp->brdcstxmt.value.ul = statsp->brdcstxmt; 47421991Sheppo ldckp->norcvbuf.value.ul = statsp->norcvbuf; 47431991Sheppo ldckp->noxmtbuf.value.ul = statsp->noxmtbuf; 47441991Sheppo 47451991Sheppo ldckp->tx_no_desc.value.ul = statsp->tx_no_desc; 4746*2336Snarayan 47471991Sheppo ldckp->rx_allocb_fail.value.ul = statsp->rx_allocb_fail; 4748*2336Snarayan ldckp->rx_vio_allocb_fail.value.ul = statsp->rx_vio_allocb_fail; 47491991Sheppo ldckp->rx_lost_pkts.value.ul = statsp->rx_lost_pkts; 47501991Sheppo 47511991Sheppo ldckp->callbacks.value.ul = statsp->callbacks; 47521991Sheppo ldckp->dring_data_acks.value.ul = statsp->dring_data_acks; 4753*2336Snarayan ldckp->dring_stopped_acks.value.ul = statsp->dring_stopped_acks; 4754*2336Snarayan ldckp->dring_data_msgs.value.ul = statsp->dring_data_msgs; 47551991Sheppo } else { 47561991Sheppo statsp->ipackets = ldckp->ipackets64.value.ull; 47571991Sheppo statsp->ierrors = ldckp->ierrors.value.ul; 47581991Sheppo statsp->opackets = ldckp->opackets64.value.ull; 47591991Sheppo statsp->oerrors = ldckp->oerrors.value.ul; 47601991Sheppo 47611991Sheppo /* 47621991Sheppo * MIB II kstat variables 47631991Sheppo */ 47641991Sheppo statsp->rbytes = ldckp->rbytes64.value.ull; 47651991Sheppo statsp->obytes = ldckp->obytes64.value.ull; 47661991Sheppo statsp->multircv = ldckp->multircv.value.ul; 47671991Sheppo statsp->multixmt = ldckp->multixmt.value.ul; 47681991Sheppo statsp->brdcstrcv = ldckp->brdcstrcv.value.ul; 47691991Sheppo statsp->brdcstxmt = ldckp->brdcstxmt.value.ul; 47701991Sheppo statsp->norcvbuf = ldckp->norcvbuf.value.ul; 47711991Sheppo statsp->noxmtbuf = ldckp->noxmtbuf.value.ul; 47721991Sheppo 47731991Sheppo statsp->tx_no_desc = ldckp->tx_no_desc.value.ul; 4774*2336Snarayan 47751991Sheppo statsp->rx_allocb_fail = ldckp->rx_allocb_fail.value.ul; 4776*2336Snarayan statsp->rx_vio_allocb_fail = ldckp->rx_vio_allocb_fail.value.ul; 47771991Sheppo statsp->rx_lost_pkts = ldckp->rx_lost_pkts.value.ul; 47781991Sheppo 47791991Sheppo statsp->callbacks = ldckp->callbacks.value.ul; 47801991Sheppo statsp->dring_data_acks = ldckp->dring_data_acks.value.ul; 4781*2336Snarayan statsp->dring_stopped_acks = ldckp->dring_stopped_acks.value.ul; 4782*2336Snarayan statsp->dring_data_msgs = ldckp->dring_data_msgs.value.ul; 47831991Sheppo } 47841991Sheppo 47851991Sheppo return (VGEN_SUCCESS); 47861991Sheppo } 47871991Sheppo 47881991Sheppo /* handler for error messages received from the peer ldc end-point */ 47891991Sheppo static void 47901991Sheppo vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 47911991Sheppo { 47921991Sheppo _NOTE(ARGUNUSED(ldcp, tagp)) 47931991Sheppo } 47941991Sheppo 47951991Sheppo /* Check if the session id in the received message is valid */ 47961991Sheppo static int 47971991Sheppo vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 47981991Sheppo { 47991991Sheppo if (tagp->vio_sid != ldcp->peer_sid) { 48001991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 48011991Sheppo DWARN((vnetp, 48021991Sheppo "sid mismatch: expected(%x), rcvd(%x)\n", 48031991Sheppo ldcp->peer_sid, tagp->vio_sid)); 48041991Sheppo return (VGEN_FAILURE); 48051991Sheppo } 48061991Sheppo else 48071991Sheppo return (VGEN_SUCCESS); 48081991Sheppo } 48091991Sheppo 48101991Sheppo /* convert mac address from string to uint64_t */ 48111991Sheppo static uint64_t 48121991Sheppo vgen_macaddr_strtoul(const uint8_t *macaddr) 48131991Sheppo { 48141991Sheppo uint64_t val = 0; 48151991Sheppo int i; 48161991Sheppo 48171991Sheppo for (i = 0; i < ETHERADDRL; i++) { 48181991Sheppo val <<= 8; 48191991Sheppo val |= macaddr[i]; 48201991Sheppo } 48211991Sheppo 48221991Sheppo return (val); 48231991Sheppo } 48241991Sheppo 48251991Sheppo /* convert mac address from uint64_t to string */ 48261991Sheppo static int 48271991Sheppo vgen_macaddr_ultostr(uint64_t val, uint8_t *macaddr) 48281991Sheppo { 48291991Sheppo int i; 48301991Sheppo uint64_t value; 48311991Sheppo 48321991Sheppo value = val; 48331991Sheppo for (i = ETHERADDRL - 1; i >= 0; i--) { 48341991Sheppo macaddr[i] = value & 0xFF; 48351991Sheppo value >>= 8; 48361991Sheppo } 48371991Sheppo return (VGEN_SUCCESS); 48381991Sheppo } 48391991Sheppo 48401991Sheppo static caddr_t 48411991Sheppo vgen_print_ethaddr(uint8_t *a, char *ebuf) 48421991Sheppo { 48431991Sheppo (void) sprintf(ebuf, 48441991Sheppo "%x:%x:%x:%x:%x:%x", a[0], a[1], a[2], a[3], a[4], a[5]); 48451991Sheppo return (ebuf); 48461991Sheppo } 48471991Sheppo 48481991Sheppo /* Handshake watchdog timeout handler */ 48491991Sheppo static void 48501991Sheppo vgen_hwatchdog(void *arg) 48511991Sheppo { 48521991Sheppo vgen_ldc_t *ldcp = (vgen_ldc_t *)arg; 48531991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 48541991Sheppo 48551991Sheppo DWARN((vnetp, 48561991Sheppo "vgen_hwatchdog: handshake timeout ldc(%lx) phase(%x) state(%x)\n", 48571991Sheppo ldcp->ldc_id, ldcp->hphase, ldcp->hstate)); 48581991Sheppo 48591991Sheppo mutex_enter(&ldcp->cblock); 48601991Sheppo ldcp->htid = 0; 48611991Sheppo vgen_handshake_retry(ldcp); 48621991Sheppo mutex_exit(&ldcp->cblock); 48631991Sheppo } 48641991Sheppo 48651991Sheppo static void 48661991Sheppo vgen_print_hparams(vgen_hparams_t *hp) 48671991Sheppo { 48681991Sheppo uint8_t addr[6]; 48691991Sheppo char ea[6]; 48701991Sheppo ldc_mem_cookie_t *dc; 48711991Sheppo 48721991Sheppo cmn_err(CE_CONT, "version_info:\n"); 48731991Sheppo cmn_err(CE_CONT, 48741991Sheppo "\tver_major: %d, ver_minor: %d, dev_class: %d\n", 48751991Sheppo hp->ver_major, hp->ver_minor, hp->dev_class); 48761991Sheppo 48771991Sheppo (void) vgen_macaddr_ultostr(hp->addr, addr); 48781991Sheppo cmn_err(CE_CONT, "attr_info:\n"); 48791991Sheppo cmn_err(CE_CONT, "\tMTU: %lx, addr: %s\n", hp->mtu, 48801991Sheppo vgen_print_ethaddr(addr, ea)); 48811991Sheppo cmn_err(CE_CONT, 48821991Sheppo "\taddr_type: %x, xfer_mode: %x, ack_freq: %x\n", 48831991Sheppo hp->addr_type, hp->xfer_mode, hp->ack_freq); 48841991Sheppo 48851991Sheppo dc = &hp->dring_cookie; 48861991Sheppo cmn_err(CE_CONT, "dring_info:\n"); 48871991Sheppo cmn_err(CE_CONT, 48881991Sheppo "\tlength: %d, dsize: %d\n", hp->num_desc, hp->desc_size); 48891991Sheppo cmn_err(CE_CONT, 48901991Sheppo "\tldc_addr: 0x%lx, ldc_size: %ld\n", 48911991Sheppo dc->addr, dc->size); 48921991Sheppo cmn_err(CE_CONT, "\tdring_ident: 0x%lx\n", hp->dring_ident); 48931991Sheppo } 48941991Sheppo 48951991Sheppo static void 48961991Sheppo vgen_print_ldcinfo(vgen_ldc_t *ldcp) 48971991Sheppo { 48981991Sheppo vgen_hparams_t *hp; 48991991Sheppo 49001991Sheppo cmn_err(CE_CONT, "Channel Information:\n"); 49011991Sheppo cmn_err(CE_CONT, 49021991Sheppo "\tldc_id: 0x%lx, ldc_status: 0x%x\n", 49031991Sheppo ldcp->ldc_id, ldcp->ldc_status); 49041991Sheppo cmn_err(CE_CONT, 49051991Sheppo "\tlocal_sid: 0x%x, peer_sid: 0x%x\n", 49061991Sheppo ldcp->local_sid, ldcp->peer_sid); 49071991Sheppo cmn_err(CE_CONT, 49081991Sheppo "\thphase: 0x%x, hstate: 0x%x\n", 49091991Sheppo ldcp->hphase, ldcp->hstate); 49101991Sheppo 49111991Sheppo cmn_err(CE_CONT, "Local handshake params:\n"); 49121991Sheppo hp = &ldcp->local_hparams; 49131991Sheppo vgen_print_hparams(hp); 49141991Sheppo 49151991Sheppo cmn_err(CE_CONT, "Peer handshake params:\n"); 49161991Sheppo hp = &ldcp->peer_hparams; 49171991Sheppo vgen_print_hparams(hp); 49181991Sheppo } 4919