11ae08745Sheppo /* 21ae08745Sheppo * CDDL HEADER START 31ae08745Sheppo * 41ae08745Sheppo * The contents of this file are subject to the terms of the 51ae08745Sheppo * Common Development and Distribution License (the "License"). 61ae08745Sheppo * You may not use this file except in compliance with the License. 71ae08745Sheppo * 81ae08745Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91ae08745Sheppo * or http://www.opensolaris.org/os/licensing. 101ae08745Sheppo * See the License for the specific language governing permissions 111ae08745Sheppo * and limitations under the License. 121ae08745Sheppo * 131ae08745Sheppo * When distributing Covered Code, include this CDDL HEADER in each 141ae08745Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151ae08745Sheppo * If applicable, add the following below this CDDL HEADER, with the 161ae08745Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 171ae08745Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 181ae08745Sheppo * 191ae08745Sheppo * CDDL HEADER END 201ae08745Sheppo */ 211ae08745Sheppo 221ae08745Sheppo /* 23a862df29SSriharsha Basavapatna * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 241ae08745Sheppo */ 251ae08745Sheppo 261ae08745Sheppo #include <sys/types.h> 271ae08745Sheppo #include <sys/errno.h> 287b1f684aSSriharsha Basavapatna #include <sys/sysmacros.h> 291ae08745Sheppo #include <sys/param.h> 307bd3a2e2SSriharsha Basavapatna #include <sys/machsystm.h> 311ae08745Sheppo #include <sys/stream.h> 32844e62a3Sraghuram #include <sys/strsubr.h> 331ae08745Sheppo #include <sys/kmem.h> 341ae08745Sheppo #include <sys/conf.h> 351ae08745Sheppo #include <sys/devops.h> 361ae08745Sheppo #include <sys/ksynch.h> 371ae08745Sheppo #include <sys/stat.h> 381ae08745Sheppo #include <sys/modctl.h> 391ae08745Sheppo #include <sys/debug.h> 401ae08745Sheppo #include <sys/ethernet.h> 411ae08745Sheppo #include <sys/ddi.h> 421ae08745Sheppo #include <sys/sunddi.h> 431ae08745Sheppo #include <sys/strsun.h> 441ae08745Sheppo #include <sys/note.h> 45da14cebeSEric Cheng #include <sys/mac_provider.h> 46ba2e4443Sseb #include <sys/mac_ether.h> 471ae08745Sheppo #include <sys/ldc.h> 481ae08745Sheppo #include <sys/mach_descrip.h> 491ae08745Sheppo #include <sys/mdeg.h> 50844e62a3Sraghuram #include <net/if.h> 51844e62a3Sraghuram #include <sys/vnet.h> 521ae08745Sheppo #include <sys/vio_mailbox.h> 531ae08745Sheppo #include <sys/vio_common.h> 541ae08745Sheppo #include <sys/vnet_common.h> 551ae08745Sheppo #include <sys/vnet_mailbox.h> 56d10e4ef2Snarayan #include <sys/vio_util.h> 57d10e4ef2Snarayan #include <sys/vnet_gen.h> 58f0ca1d9aSsb155480 #include <sys/atomic.h> 59844e62a3Sraghuram #include <sys/callb.h> 60844e62a3Sraghuram #include <sys/sdt.h> 61844e62a3Sraghuram #include <sys/intr.h> 62844e62a3Sraghuram #include <sys/pattr.h> 63c1c61f44Ssb155480 #include <sys/vlan.h> 641ae08745Sheppo 651ae08745Sheppo /* 667bd3a2e2SSriharsha Basavapatna * Implementation of the mac provider functionality for vnet using the 671ae08745Sheppo * generic(default) transport layer of sun4v Logical Domain Channels(LDC). 681ae08745Sheppo */ 691ae08745Sheppo 707bd3a2e2SSriharsha Basavapatna /* Entry Points */ 71678453a8Sspeer int vgen_init(void *vnetp, uint64_t regprop, dev_info_t *vnetdip, 72678453a8Sspeer const uint8_t *macaddr, void **vgenhdl); 7363f531d1SSriharsha Basavapatna int vgen_init_mdeg(void *arg); 743ab636deSWENTAO YANG void vgen_uninit(void *arg); 75678453a8Sspeer int vgen_dds_tx(void *arg, void *dmsg); 7663f531d1SSriharsha Basavapatna int vgen_enable_intr(void *arg); 7763f531d1SSriharsha Basavapatna int vgen_disable_intr(void *arg); 787bd3a2e2SSriharsha Basavapatna mblk_t *vgen_rx_poll(void *arg, int bytes_to_pickup); 791ae08745Sheppo static int vgen_start(void *arg); 801ae08745Sheppo static void vgen_stop(void *arg); 811ae08745Sheppo static mblk_t *vgen_tx(void *arg, mblk_t *mp); 821ae08745Sheppo static int vgen_multicst(void *arg, boolean_t add, 831ae08745Sheppo const uint8_t *mca); 841ae08745Sheppo static int vgen_promisc(void *arg, boolean_t on); 851ae08745Sheppo static int vgen_unicst(void *arg, const uint8_t *mca); 86ba2e4443Sseb static int vgen_stat(void *arg, uint_t stat, uint64_t *val); 871107ea93SSriharsha Basavapatna static void vgen_ioctl(void *arg, queue_t *q, mblk_t *mp); 881107ea93SSriharsha Basavapatna #ifdef VNET_IOC_DEBUG 891107ea93SSriharsha Basavapatna static int vgen_force_link_state(vgen_port_t *portp, int link_state); 901107ea93SSriharsha Basavapatna #endif 911ae08745Sheppo 927bd3a2e2SSriharsha Basavapatna /* Port/LDC Configuration */ 93c1c61f44Ssb155480 static int vgen_read_mdprops(vgen_t *vgenp); 94c1c61f44Ssb155480 static void vgen_update_md_prop(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex); 95c1c61f44Ssb155480 static void vgen_read_pri_eth_types(vgen_t *vgenp, md_t *mdp, 96c1c61f44Ssb155480 mde_cookie_t node); 977b1f684aSSriharsha Basavapatna static void vgen_mtu_read(vgen_t *vgenp, md_t *mdp, mde_cookie_t node, 987b1f684aSSriharsha Basavapatna uint32_t *mtu); 991107ea93SSriharsha Basavapatna static void vgen_linkprop_read(vgen_t *vgenp, md_t *mdp, mde_cookie_t node, 1001107ea93SSriharsha Basavapatna boolean_t *pls); 1011ae08745Sheppo static void vgen_detach_ports(vgen_t *vgenp); 1021ae08745Sheppo static void vgen_port_detach(vgen_port_t *portp); 1031ae08745Sheppo static void vgen_port_list_insert(vgen_port_t *portp); 1041ae08745Sheppo static void vgen_port_list_remove(vgen_port_t *portp); 1051ae08745Sheppo static vgen_port_t *vgen_port_lookup(vgen_portlist_t *plistp, 1061ae08745Sheppo int port_num); 1071ae08745Sheppo static int vgen_mdeg_reg(vgen_t *vgenp); 1081ae08745Sheppo static void vgen_mdeg_unreg(vgen_t *vgenp); 1091ae08745Sheppo static int vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp); 110c1c61f44Ssb155480 static int vgen_mdeg_port_cb(void *cb_argp, mdeg_result_t *resp); 1111ae08745Sheppo static int vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex); 112c1c61f44Ssb155480 static int vgen_port_read_props(vgen_port_t *portp, vgen_t *vgenp, md_t *mdp, 113c1c61f44Ssb155480 mde_cookie_t mdex); 1141ae08745Sheppo static int vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex); 115c1c61f44Ssb155480 static int vgen_port_attach(vgen_port_t *portp); 116c1c61f44Ssb155480 static void vgen_port_detach_mdeg(vgen_port_t *portp); 1171ae08745Sheppo static int vgen_update_port(vgen_t *vgenp, md_t *curr_mdp, 1181ae08745Sheppo mde_cookie_t curr_mdex, md_t *prev_mdp, mde_cookie_t prev_mdex); 119ba2e4443Sseb static uint64_t vgen_port_stat(vgen_port_t *portp, uint_t stat); 1201107ea93SSriharsha Basavapatna static void vgen_port_reset(vgen_port_t *portp); 1211107ea93SSriharsha Basavapatna static void vgen_reset_vsw_port(vgen_t *vgenp); 1227bd3a2e2SSriharsha Basavapatna static int vgen_ldc_reset(vgen_ldc_t *ldcp, vgen_caller_t caller); 1237bd3a2e2SSriharsha Basavapatna static void vgen_ldc_up(vgen_ldc_t *ldcp); 1241ae08745Sheppo static int vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id); 1251ae08745Sheppo static void vgen_ldc_detach(vgen_ldc_t *ldcp); 1261ae08745Sheppo static void vgen_port_init(vgen_port_t *portp); 1271ae08745Sheppo static void vgen_port_uninit(vgen_port_t *portp); 1281ae08745Sheppo static int vgen_ldc_init(vgen_ldc_t *ldcp); 1291ae08745Sheppo static void vgen_ldc_uninit(vgen_ldc_t *ldcp); 130ba2e4443Sseb static uint64_t vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat); 1317bd3a2e2SSriharsha Basavapatna 1327bd3a2e2SSriharsha Basavapatna /* I/O Processing */ 1331ae08745Sheppo static int vgen_portsend(vgen_port_t *portp, mblk_t *mp); 134f0ca1d9aSsb155480 static int vgen_ldcsend(void *arg, mblk_t *mp); 135f0ca1d9aSsb155480 static void vgen_ldcsend_pkt(void *arg, mblk_t *mp); 1367bd3a2e2SSriharsha Basavapatna static uint_t vgen_ldc_cb(uint64_t event, caddr_t arg); 1377bd3a2e2SSriharsha Basavapatna static void vgen_tx_watchdog(void *arg); 1381ae08745Sheppo 1397bd3a2e2SSriharsha Basavapatna /* Dring Configuration */ 1407bd3a2e2SSriharsha Basavapatna static int vgen_create_dring(vgen_ldc_t *ldcp); 1417bd3a2e2SSriharsha Basavapatna static void vgen_destroy_dring(vgen_ldc_t *ldcp); 1427bd3a2e2SSriharsha Basavapatna static int vgen_map_dring(vgen_ldc_t *ldcp, void *pkt); 1437bd3a2e2SSriharsha Basavapatna static void vgen_unmap_dring(vgen_ldc_t *ldcp); 144*34f94fbcSWENTAO YANG static int vgen_mapin_avail(vgen_ldc_t *ldcp); 1457bd3a2e2SSriharsha Basavapatna 1467bd3a2e2SSriharsha Basavapatna /* VIO Message Processing */ 1477bd3a2e2SSriharsha Basavapatna static int vgen_handshake(vgen_ldc_t *ldcp); 1487bd3a2e2SSriharsha Basavapatna static int vgen_handshake_done(vgen_ldc_t *ldcp); 1491ae08745Sheppo static vgen_ldc_t *vh_nextphase(vgen_ldc_t *ldcp); 1507bd3a2e2SSriharsha Basavapatna static int vgen_handshake_phase2(vgen_ldc_t *ldcp); 1517bd3a2e2SSriharsha Basavapatna static int vgen_handshake_phase3(vgen_ldc_t *ldcp); 1527bd3a2e2SSriharsha Basavapatna static void vgen_setup_handshake_params(vgen_ldc_t *ldcp); 1531ae08745Sheppo static int vgen_send_version_negotiate(vgen_ldc_t *ldcp); 1541ae08745Sheppo static int vgen_send_attr_info(vgen_ldc_t *ldcp); 1557bd3a2e2SSriharsha Basavapatna static int vgen_send_rx_dring_reg(vgen_ldc_t *ldcp); 1567bd3a2e2SSriharsha Basavapatna static int vgen_send_tx_dring_reg(vgen_ldc_t *ldcp); 1577bd3a2e2SSriharsha Basavapatna static void vgen_init_dring_reg_msg(vgen_ldc_t *ldcp, vio_dring_reg_msg_t *msg, 1587bd3a2e2SSriharsha Basavapatna uint8_t option); 1591ae08745Sheppo static int vgen_send_rdx_info(vgen_ldc_t *ldcp); 1607bd3a2e2SSriharsha Basavapatna static int vgen_send_dringdata(vgen_ldc_t *ldcp, uint32_t start, int32_t end); 1611ae08745Sheppo static int vgen_send_mcast_info(vgen_ldc_t *ldcp); 1623af08d82Slm66018 static int vgen_handle_version_negotiate(vgen_ldc_t *ldcp, 1631ae08745Sheppo vio_msg_tag_t *tagp); 1647bd3a2e2SSriharsha Basavapatna static int vgen_handle_attr_msg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1657bd3a2e2SSriharsha Basavapatna static int vgen_handle_attr_info(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg); 1667bd3a2e2SSriharsha Basavapatna static int vgen_handle_attr_ack(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg); 1673af08d82Slm66018 static int vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1687bd3a2e2SSriharsha Basavapatna static int vgen_handle_dring_reg_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1697bd3a2e2SSriharsha Basavapatna static int vgen_handle_dring_reg_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1703af08d82Slm66018 static int vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1713af08d82Slm66018 static int vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1723af08d82Slm66018 static int vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 173f0ca1d9aSsb155480 static void vgen_handle_pkt_data_nop(void *arg1, void *arg2, uint32_t msglen); 174f0ca1d9aSsb155480 static int vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, 175f0ca1d9aSsb155480 uint32_t msglen); 1761ae08745Sheppo static void vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1777bd3a2e2SSriharsha Basavapatna static int vgen_dds_rx(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 178678453a8Sspeer static void vgen_handle_evt_up(vgen_ldc_t *ldcp); 1797bd3a2e2SSriharsha Basavapatna static int vgen_process_reset(vgen_ldc_t *ldcp, int flags); 1801ae08745Sheppo static int vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1811ae08745Sheppo static void vgen_hwatchdog(void *arg); 182f0ca1d9aSsb155480 static void vgen_set_vnet_proto_ops(vgen_ldc_t *ldcp); 183f0ca1d9aSsb155480 static void vgen_reset_vnet_proto_ops(vgen_ldc_t *ldcp); 1841107ea93SSriharsha Basavapatna static void vgen_link_update(vgen_t *vgenp, link_state_t link_state); 1851ae08745Sheppo 1867bd3a2e2SSriharsha Basavapatna /* VLANs */ 187c1c61f44Ssb155480 static void vgen_vlan_read_ids(void *arg, int type, md_t *mdp, 188c1c61f44Ssb155480 mde_cookie_t node, uint16_t *pvidp, uint16_t **vidspp, 189c1c61f44Ssb155480 uint16_t *nvidsp, uint16_t *default_idp); 190c1c61f44Ssb155480 static void vgen_vlan_create_hash(vgen_port_t *portp); 191c1c61f44Ssb155480 static void vgen_vlan_destroy_hash(vgen_port_t *portp); 192c1c61f44Ssb155480 static void vgen_vlan_add_ids(vgen_port_t *portp); 193c1c61f44Ssb155480 static void vgen_vlan_remove_ids(vgen_port_t *portp); 194c1c61f44Ssb155480 static boolean_t vgen_vlan_lookup(mod_hash_t *vlan_hashp, uint16_t vid); 195c1c61f44Ssb155480 static boolean_t vgen_frame_lookup_vid(vnet_t *vnetp, struct ether_header *ehp, 196c1c61f44Ssb155480 uint16_t *vidp); 197c1c61f44Ssb155480 static mblk_t *vgen_vlan_frame_fixtag(vgen_port_t *portp, mblk_t *mp, 198c1c61f44Ssb155480 boolean_t is_tagged, uint16_t vid); 199c1c61f44Ssb155480 static void vgen_vlan_unaware_port_reset(vgen_port_t *portp); 200c1c61f44Ssb155480 static void vgen_reset_vlan_unaware_ports(vgen_t *vgenp); 201678453a8Sspeer 2027bd3a2e2SSriharsha Basavapatna /* Exported functions */ 2037bd3a2e2SSriharsha Basavapatna int vgen_handle_evt_read(vgen_ldc_t *ldcp, vgen_caller_t caller); 2047bd3a2e2SSriharsha Basavapatna int vgen_handle_evt_reset(vgen_ldc_t *ldcp, vgen_caller_t caller); 2057bd3a2e2SSriharsha Basavapatna void vgen_handle_pkt_data(void *arg1, void *arg2, uint32_t msglen); 2067bd3a2e2SSriharsha Basavapatna void vgen_destroy_rxpools(void *arg); 2077bd3a2e2SSriharsha Basavapatna 2087bd3a2e2SSriharsha Basavapatna /* Externs */ 209678453a8Sspeer extern void vnet_dds_rx(void *arg, void *dmsg); 2106d6de4eeSWENTAO YANG extern void vnet_dds_cleanup_hio(vnet_t *vnetp); 2117b1f684aSSriharsha Basavapatna extern int vnet_mtu_update(vnet_t *vnetp, uint32_t mtu); 2121107ea93SSriharsha Basavapatna extern void vnet_link_update(vnet_t *vnetp, link_state_t link_state); 2137bd3a2e2SSriharsha Basavapatna extern int vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg, size_t msglen, 2147bd3a2e2SSriharsha Basavapatna boolean_t caller_holds_lock); 2157bd3a2e2SSriharsha Basavapatna extern void vgen_stop_msg_thread(vgen_ldc_t *ldcp); 2167bd3a2e2SSriharsha Basavapatna extern int vgen_create_tx_dring(vgen_ldc_t *ldcp); 2177bd3a2e2SSriharsha Basavapatna extern void vgen_destroy_tx_dring(vgen_ldc_t *ldcp); 2187bd3a2e2SSriharsha Basavapatna extern int vgen_map_rx_dring(vgen_ldc_t *ldcp, void *pkt); 2197bd3a2e2SSriharsha Basavapatna extern void vgen_unmap_rx_dring(vgen_ldc_t *ldcp); 2207bd3a2e2SSriharsha Basavapatna extern int vgen_create_rx_dring(vgen_ldc_t *ldcp); 2217bd3a2e2SSriharsha Basavapatna extern void vgen_destroy_rx_dring(vgen_ldc_t *ldcp); 2227bd3a2e2SSriharsha Basavapatna extern int vgen_map_tx_dring(vgen_ldc_t *ldcp, void *pkt); 2237bd3a2e2SSriharsha Basavapatna extern void vgen_unmap_tx_dring(vgen_ldc_t *ldcp); 2247bd3a2e2SSriharsha Basavapatna extern int vgen_map_data(vgen_ldc_t *ldcp, void *pkt); 2257bd3a2e2SSriharsha Basavapatna extern int vgen_handle_dringdata_shm(void *arg1, void *arg2); 2267bd3a2e2SSriharsha Basavapatna extern int vgen_handle_dringdata(void *arg1, void *arg2); 2277bd3a2e2SSriharsha Basavapatna extern int vgen_dringsend_shm(void *arg, mblk_t *mp); 2287bd3a2e2SSriharsha Basavapatna extern int vgen_dringsend(void *arg, mblk_t *mp); 2297bd3a2e2SSriharsha Basavapatna extern void vgen_ldc_msg_worker(void *arg); 2307bd3a2e2SSriharsha Basavapatna extern int vgen_send_dringack_shm(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, 2317bd3a2e2SSriharsha Basavapatna uint32_t start, int32_t end, uint8_t pstate); 2327bd3a2e2SSriharsha Basavapatna extern mblk_t *vgen_poll_rcv_shm(vgen_ldc_t *ldcp, int bytes_to_pickup); 2337bd3a2e2SSriharsha Basavapatna extern mblk_t *vgen_poll_rcv(vgen_ldc_t *ldcp, int bytes_to_pickup); 2347bd3a2e2SSriharsha Basavapatna extern int vgen_check_datamsg_seq(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 2351ae08745Sheppo 236f0ca1d9aSsb155480 #define VGEN_PRI_ETH_DEFINED(vgenp) ((vgenp)->pri_num_types != 0) 237f0ca1d9aSsb155480 2381ae08745Sheppo #define LDC_LOCK(ldcp) \ 2391ae08745Sheppo mutex_enter(&((ldcp)->cblock));\ 240844e62a3Sraghuram mutex_enter(&((ldcp)->rxlock));\ 241844e62a3Sraghuram mutex_enter(&((ldcp)->wrlock));\ 2421ae08745Sheppo mutex_enter(&((ldcp)->txlock));\ 2431ae08745Sheppo mutex_enter(&((ldcp)->tclock)); 2441ae08745Sheppo #define LDC_UNLOCK(ldcp) \ 2451ae08745Sheppo mutex_exit(&((ldcp)->tclock));\ 2461ae08745Sheppo mutex_exit(&((ldcp)->txlock));\ 247844e62a3Sraghuram mutex_exit(&((ldcp)->wrlock));\ 248844e62a3Sraghuram mutex_exit(&((ldcp)->rxlock));\ 2491ae08745Sheppo mutex_exit(&((ldcp)->cblock)); 2501ae08745Sheppo 251c1c61f44Ssb155480 #define VGEN_VER_EQ(ldcp, major, minor) \ 252c1c61f44Ssb155480 ((ldcp)->local_hparams.ver_major == (major) && \ 253c1c61f44Ssb155480 (ldcp)->local_hparams.ver_minor == (minor)) 254c1c61f44Ssb155480 255c1c61f44Ssb155480 #define VGEN_VER_LT(ldcp, major, minor) \ 256c1c61f44Ssb155480 (((ldcp)->local_hparams.ver_major < (major)) || \ 257c1c61f44Ssb155480 ((ldcp)->local_hparams.ver_major == (major) && \ 258c1c61f44Ssb155480 (ldcp)->local_hparams.ver_minor < (minor))) 259c1c61f44Ssb155480 260c1c61f44Ssb155480 #define VGEN_VER_GTEQ(ldcp, major, minor) \ 261c1c61f44Ssb155480 (((ldcp)->local_hparams.ver_major > (major)) || \ 262c1c61f44Ssb155480 ((ldcp)->local_hparams.ver_major == (major) && \ 263c1c61f44Ssb155480 (ldcp)->local_hparams.ver_minor >= (minor))) 264c1c61f44Ssb155480 2651ae08745Sheppo /* 2661ae08745Sheppo * Property names 2671ae08745Sheppo */ 2681ae08745Sheppo static char macaddr_propname[] = "mac-address"; 2691ae08745Sheppo static char rmacaddr_propname[] = "remote-mac-address"; 2701ae08745Sheppo static char channel_propname[] = "channel-endpoint"; 2711ae08745Sheppo static char reg_propname[] = "reg"; 2721ae08745Sheppo static char port_propname[] = "port"; 2731ae08745Sheppo static char swport_propname[] = "switch-port"; 2741ae08745Sheppo static char id_propname[] = "id"; 275f0ca1d9aSsb155480 static char vdev_propname[] = "virtual-device"; 276f0ca1d9aSsb155480 static char vnet_propname[] = "network"; 277f0ca1d9aSsb155480 static char pri_types_propname[] = "priority-ether-types"; 278c1c61f44Ssb155480 static char vgen_pvid_propname[] = "port-vlan-id"; 279c1c61f44Ssb155480 static char vgen_vid_propname[] = "vlan-id"; 280c1c61f44Ssb155480 static char vgen_dvid_propname[] = "default-vlan-id"; 281c1c61f44Ssb155480 static char port_pvid_propname[] = "remote-port-vlan-id"; 282c1c61f44Ssb155480 static char port_vid_propname[] = "remote-vlan-id"; 2837b1f684aSSriharsha Basavapatna static char vgen_mtu_propname[] = "mtu"; 2841107ea93SSriharsha Basavapatna static char vgen_linkprop_propname[] = "linkprop"; 2851ae08745Sheppo 2861107ea93SSriharsha Basavapatna /* 2871107ea93SSriharsha Basavapatna * VIO Protocol Version Info: 2881107ea93SSriharsha Basavapatna * 2891107ea93SSriharsha Basavapatna * The version specified below represents the version of protocol currently 2901107ea93SSriharsha Basavapatna * supported in the driver. It means the driver can negotiate with peers with 2911107ea93SSriharsha Basavapatna * versions <= this version. Here is a summary of the feature(s) that are 2921107ea93SSriharsha Basavapatna * supported at each version of the protocol: 2931107ea93SSriharsha Basavapatna * 2941107ea93SSriharsha Basavapatna * 1.0 Basic VIO protocol. 2951107ea93SSriharsha Basavapatna * 1.1 vDisk protocol update (no virtual network update). 2961107ea93SSriharsha Basavapatna * 1.2 Support for priority frames (priority-ether-types). 2971107ea93SSriharsha Basavapatna * 1.3 VLAN and HybridIO support. 2981107ea93SSriharsha Basavapatna * 1.4 Jumbo Frame support. 2991107ea93SSriharsha Basavapatna * 1.5 Link State Notification support with optional support 3001107ea93SSriharsha Basavapatna * for Physical Link information. 3017bd3a2e2SSriharsha Basavapatna * 1.6 Support for RxDringData mode. 3021107ea93SSriharsha Basavapatna */ 3037bd3a2e2SSriharsha Basavapatna static vgen_ver_t vgen_versions[VGEN_NUM_VER] = { {1, 6} }; 3041ae08745Sheppo 3051ae08745Sheppo /* Tunables */ 30619b65a69Ssb155480 uint32_t vgen_hwd_interval = 5; /* handshake watchdog freq in sec */ 3071ae08745Sheppo uint32_t vgen_ldcwr_retries = 10; /* max # of ldc_write() retries */ 3088e6a2a04Slm66018 uint32_t vgen_ldcup_retries = 5; /* max # of ldc_up() retries */ 309195ce4e5SSriharsha Basavapatna uint32_t vgen_ldccl_retries = 5; /* max # of ldc_close() retries */ 31061a70d81Sraghuram uint32_t vgen_tx_delay = 0x30; /* delay when tx descr not available */ 3117bd3a2e2SSriharsha Basavapatna uint32_t vgen_ldc_mtu = VGEN_LDC_MTU; /* ldc mtu */ 3127bd3a2e2SSriharsha Basavapatna uint32_t vgen_txwd_interval = VGEN_TXWD_INTERVAL; /* watchdog freq in msec */ 3137bd3a2e2SSriharsha Basavapatna uint32_t vgen_txwd_timeout = VGEN_TXWD_TIMEOUT; /* tx timeout in msec */ 3146f09f0feSWENTAO YANG 315844e62a3Sraghuram /* 3167bd3a2e2SSriharsha Basavapatna * Max # of channel resets allowed during handshake. 3177bd3a2e2SSriharsha Basavapatna */ 3187bd3a2e2SSriharsha Basavapatna uint32_t vgen_ldc_max_resets = 5; 3197bd3a2e2SSriharsha Basavapatna 3207bd3a2e2SSriharsha Basavapatna /* 3217bd3a2e2SSriharsha Basavapatna * See comments in vsw.c for details on the dring modes supported. 3227bd3a2e2SSriharsha Basavapatna * In RxDringData mode, # of buffers is determined by multiplying the # of 3237bd3a2e2SSriharsha Basavapatna * descriptors with the factor below. Note that the factor must be > 1; i.e, 3247bd3a2e2SSriharsha Basavapatna * the # of buffers must always be > # of descriptors. This is needed because, 3257bd3a2e2SSriharsha Basavapatna * while the shared memory buffers are sent up the stack on the receiver, the 3267bd3a2e2SSriharsha Basavapatna * sender needs additional buffers that can be used for further transmits. 3277bd3a2e2SSriharsha Basavapatna * See vgen_create_rx_dring() for details. 3287bd3a2e2SSriharsha Basavapatna */ 3297bd3a2e2SSriharsha Basavapatna uint32_t vgen_nrbufs_factor = 2; 3307bd3a2e2SSriharsha Basavapatna 3317bd3a2e2SSriharsha Basavapatna /* 3327bd3a2e2SSriharsha Basavapatna * Retry delay used while destroying rx mblk pools. Used in both Dring modes. 3337bd3a2e2SSriharsha Basavapatna */ 3347bd3a2e2SSriharsha Basavapatna int vgen_rxpool_cleanup_delay = 100000; /* 100ms */ 3357bd3a2e2SSriharsha Basavapatna 3367bd3a2e2SSriharsha Basavapatna /* 3377bd3a2e2SSriharsha Basavapatna * Delay when rx descr not ready; used in TxDring mode only. 3387bd3a2e2SSriharsha Basavapatna */ 3397bd3a2e2SSriharsha Basavapatna uint32_t vgen_recv_delay = 1; 3407bd3a2e2SSriharsha Basavapatna 3417bd3a2e2SSriharsha Basavapatna /* 3427bd3a2e2SSriharsha Basavapatna * Retry when rx descr not ready; used in TxDring mode only. 3437bd3a2e2SSriharsha Basavapatna */ 3447bd3a2e2SSriharsha Basavapatna uint32_t vgen_recv_retries = 10; 3457bd3a2e2SSriharsha Basavapatna 3467bd3a2e2SSriharsha Basavapatna /* 3477bd3a2e2SSriharsha Basavapatna * Max # of packets accumulated prior to sending them up. It is best 3487bd3a2e2SSriharsha Basavapatna * to keep this at 60% of the number of receive buffers. Used in TxDring mode 3497bd3a2e2SSriharsha Basavapatna * by the msg worker thread. Used in RxDringData mode while in interrupt mode 3507bd3a2e2SSriharsha Basavapatna * (not used in polled mode). 351844e62a3Sraghuram */ 352844e62a3Sraghuram uint32_t vgen_chain_len = (VGEN_NRBUFS * 0.6); 353844e62a3Sraghuram 354844e62a3Sraghuram /* 3557b1f684aSSriharsha Basavapatna * Internal tunables for receive buffer pools, that is, the size and number of 3567b1f684aSSriharsha Basavapatna * mblks for each pool. At least 3 sizes must be specified if these are used. 3577b1f684aSSriharsha Basavapatna * The sizes must be specified in increasing order. Non-zero value of the first 3587b1f684aSSriharsha Basavapatna * size will be used as a hint to use these values instead of the algorithm 3597bd3a2e2SSriharsha Basavapatna * that determines the sizes based on MTU. Used in TxDring mode only. 360844e62a3Sraghuram */ 3617b1f684aSSriharsha Basavapatna uint32_t vgen_rbufsz1 = 0; 3627b1f684aSSriharsha Basavapatna uint32_t vgen_rbufsz2 = 0; 3637b1f684aSSriharsha Basavapatna uint32_t vgen_rbufsz3 = 0; 3647b1f684aSSriharsha Basavapatna uint32_t vgen_rbufsz4 = 0; 365844e62a3Sraghuram 366844e62a3Sraghuram uint32_t vgen_nrbufs1 = VGEN_NRBUFS; 367844e62a3Sraghuram uint32_t vgen_nrbufs2 = VGEN_NRBUFS; 368844e62a3Sraghuram uint32_t vgen_nrbufs3 = VGEN_NRBUFS; 3697b1f684aSSriharsha Basavapatna uint32_t vgen_nrbufs4 = VGEN_NRBUFS; 370844e62a3Sraghuram 371f0ca1d9aSsb155480 /* 372f0ca1d9aSsb155480 * In the absence of "priority-ether-types" property in MD, the following 373f0ca1d9aSsb155480 * internal tunable can be set to specify a single priority ethertype. 374f0ca1d9aSsb155480 */ 375f0ca1d9aSsb155480 uint64_t vgen_pri_eth_type = 0; 376f0ca1d9aSsb155480 377f0ca1d9aSsb155480 /* 378f0ca1d9aSsb155480 * Number of transmit priority buffers that are preallocated per device. 379f0ca1d9aSsb155480 * This number is chosen to be a small value to throttle transmission 380f0ca1d9aSsb155480 * of priority packets. Note: Must be a power of 2 for vio_create_mblks(). 381f0ca1d9aSsb155480 */ 382f0ca1d9aSsb155480 uint32_t vgen_pri_tx_nmblks = 64; 383f0ca1d9aSsb155480 384c1c61f44Ssb155480 uint32_t vgen_vlan_nchains = 4; /* # of chains in vlan id hash table */ 385c1c61f44Ssb155480 386c1c61f44Ssb155480 /* 387c1c61f44Ssb155480 * Matching criteria passed to the MDEG to register interest 388c1c61f44Ssb155480 * in changes to 'virtual-device' nodes (i.e. vnet nodes) identified 389c1c61f44Ssb155480 * by their 'name' and 'cfg-handle' properties. 390c1c61f44Ssb155480 */ 391c1c61f44Ssb155480 static md_prop_match_t vdev_prop_match[] = { 392c1c61f44Ssb155480 { MDET_PROP_STR, "name" }, 393c1c61f44Ssb155480 { MDET_PROP_VAL, "cfg-handle" }, 394c1c61f44Ssb155480 { MDET_LIST_END, NULL } 395c1c61f44Ssb155480 }; 396c1c61f44Ssb155480 397c1c61f44Ssb155480 static mdeg_node_match_t vdev_match = { "virtual-device", 398c1c61f44Ssb155480 vdev_prop_match }; 399c1c61f44Ssb155480 4001ae08745Sheppo /* MD update matching structure */ 4011ae08745Sheppo static md_prop_match_t vport_prop_match[] = { 4021ae08745Sheppo { MDET_PROP_VAL, "id" }, 4031ae08745Sheppo { MDET_LIST_END, NULL } 4041ae08745Sheppo }; 4051ae08745Sheppo 4061ae08745Sheppo static mdeg_node_match_t vport_match = { "virtual-device-port", 4071ae08745Sheppo vport_prop_match }; 4081ae08745Sheppo 4097bd3a2e2SSriharsha Basavapatna /* Template for matching a particular vnet instance */ 4101ae08745Sheppo static mdeg_prop_spec_t vgen_prop_template[] = { 4111ae08745Sheppo { MDET_PROP_STR, "name", "network" }, 4121ae08745Sheppo { MDET_PROP_VAL, "cfg-handle", NULL }, 4131ae08745Sheppo { MDET_LIST_END, NULL, NULL } 4141ae08745Sheppo }; 4151ae08745Sheppo 4161ae08745Sheppo #define VGEN_SET_MDEG_PROP_INST(specp, val) (specp)[1].ps_val = (val) 4171ae08745Sheppo 418c1c61f44Ssb155480 static int vgen_mdeg_port_cb(void *cb_argp, mdeg_result_t *resp); 4191ae08745Sheppo 4201107ea93SSriharsha Basavapatna #ifdef VNET_IOC_DEBUG 4211107ea93SSriharsha Basavapatna #define VGEN_M_CALLBACK_FLAGS (MC_IOCTL) 4221107ea93SSriharsha Basavapatna #else 4231107ea93SSriharsha Basavapatna #define VGEN_M_CALLBACK_FLAGS (0) 4241107ea93SSriharsha Basavapatna #endif 4251107ea93SSriharsha Basavapatna 426ba2e4443Sseb static mac_callbacks_t vgen_m_callbacks = { 4271107ea93SSriharsha Basavapatna VGEN_M_CALLBACK_FLAGS, 428ba2e4443Sseb vgen_stat, 429ba2e4443Sseb vgen_start, 430ba2e4443Sseb vgen_stop, 431ba2e4443Sseb vgen_promisc, 432ba2e4443Sseb vgen_multicst, 433ba2e4443Sseb vgen_unicst, 434ba2e4443Sseb vgen_tx, 4350dc2366fSVenugopal Iyer NULL, 4361107ea93SSriharsha Basavapatna vgen_ioctl, 437ba2e4443Sseb NULL, 438ba2e4443Sseb NULL 439ba2e4443Sseb }; 440ba2e4443Sseb 4417bd3a2e2SSriharsha Basavapatna /* Externs */ 442844e62a3Sraghuram extern pri_t maxclsyspri; 443844e62a3Sraghuram extern proc_t p0; 444c1c61f44Ssb155480 extern uint32_t vnet_ethermtu; 445c1c61f44Ssb155480 extern uint16_t vnet_default_vlan_id; 446*34f94fbcSWENTAO YANG extern uint32_t vnet_num_descriptors; 4471ae08745Sheppo 4481ae08745Sheppo #ifdef DEBUG 4491ae08745Sheppo 4507bd3a2e2SSriharsha Basavapatna #define DEBUG_PRINTF vgen_debug_printf 4517bd3a2e2SSriharsha Basavapatna 452844e62a3Sraghuram extern int vnet_dbglevel; 4537bd3a2e2SSriharsha Basavapatna 4547bd3a2e2SSriharsha Basavapatna void vgen_debug_printf(const char *fname, vgen_t *vgenp, 455844e62a3Sraghuram vgen_ldc_t *ldcp, const char *fmt, ...); 4561ae08745Sheppo 457844e62a3Sraghuram /* -1 for all LDCs info, or ldc_id for a specific LDC info */ 458844e62a3Sraghuram int vgendbg_ldcid = -1; 4591ae08745Sheppo 4607bd3a2e2SSriharsha Basavapatna /* Flags to simulate error conditions for debugging */ 4617bd3a2e2SSriharsha Basavapatna int vgen_inject_err_flag = 0; 4627bd3a2e2SSriharsha Basavapatna 4637bd3a2e2SSriharsha Basavapatna 4647bd3a2e2SSriharsha Basavapatna boolean_t 4657bd3a2e2SSriharsha Basavapatna vgen_inject_error(vgen_ldc_t *ldcp, int error) 4667bd3a2e2SSriharsha Basavapatna { 4677bd3a2e2SSriharsha Basavapatna if ((vgendbg_ldcid == ldcp->ldc_id) && 4687bd3a2e2SSriharsha Basavapatna (vgen_inject_err_flag & error)) { 4697bd3a2e2SSriharsha Basavapatna return (B_TRUE); 4707bd3a2e2SSriharsha Basavapatna } 4717bd3a2e2SSriharsha Basavapatna return (B_FALSE); 4727bd3a2e2SSriharsha Basavapatna } 4731ae08745Sheppo 4741ae08745Sheppo #endif 4751ae08745Sheppo 4761ae08745Sheppo /* 4771ae08745Sheppo * vgen_init() is called by an instance of vnet driver to initialize the 4787bd3a2e2SSriharsha Basavapatna * corresponding generic transport layer. This layer uses Logical Domain 4797bd3a2e2SSriharsha Basavapatna * Channels (LDCs) to communicate with the virtual switch in the service domain 4807bd3a2e2SSriharsha Basavapatna * and also with peer vnets in other guest domains in the system. 4817bd3a2e2SSriharsha Basavapatna * 4827bd3a2e2SSriharsha Basavapatna * Arguments: 4837bd3a2e2SSriharsha Basavapatna * vnetp: an opaque pointer to the vnet instance 4847bd3a2e2SSriharsha Basavapatna * regprop: frame to be transmitted 4857bd3a2e2SSriharsha Basavapatna * vnetdip: dip of the vnet device 4867bd3a2e2SSriharsha Basavapatna * macaddr: mac address of the vnet device 4877bd3a2e2SSriharsha Basavapatna * 4887bd3a2e2SSriharsha Basavapatna * Returns: 4897bd3a2e2SSriharsha Basavapatna * Sucess: a handle to the vgen instance (vgen_t) 4907bd3a2e2SSriharsha Basavapatna * Failure: NULL 4911ae08745Sheppo */ 4921ae08745Sheppo int 493678453a8Sspeer vgen_init(void *vnetp, uint64_t regprop, dev_info_t *vnetdip, 494678453a8Sspeer const uint8_t *macaddr, void **vgenhdl) 4951ae08745Sheppo { 4961ae08745Sheppo vgen_t *vgenp; 4971ae08745Sheppo int instance; 498f0ca1d9aSsb155480 int rv; 4997bd3a2e2SSriharsha Basavapatna char qname[TASKQ_NAMELEN]; 5001ae08745Sheppo 501ba2e4443Sseb if ((vnetp == NULL) || (vnetdip == NULL)) 5021ae08745Sheppo return (DDI_FAILURE); 5031ae08745Sheppo 5041ae08745Sheppo instance = ddi_get_instance(vnetdip); 5051ae08745Sheppo 50606db247cSraghuram DBG1(NULL, NULL, "vnet(%d): enter\n", instance); 5071ae08745Sheppo 5081ae08745Sheppo vgenp = kmem_zalloc(sizeof (vgen_t), KM_SLEEP); 5091ae08745Sheppo 5101ae08745Sheppo vgenp->vnetp = vnetp; 511678453a8Sspeer vgenp->instance = instance; 512678453a8Sspeer vgenp->regprop = regprop; 5131ae08745Sheppo vgenp->vnetdip = vnetdip; 5141ae08745Sheppo bcopy(macaddr, &(vgenp->macaddr), ETHERADDRL); 5151107ea93SSriharsha Basavapatna vgenp->phys_link_state = LINK_STATE_UNKNOWN; 5161ae08745Sheppo 5171ae08745Sheppo /* allocate multicast table */ 5181ae08745Sheppo vgenp->mctab = kmem_zalloc(VGEN_INIT_MCTAB_SIZE * 5191ae08745Sheppo sizeof (struct ether_addr), KM_SLEEP); 5201ae08745Sheppo vgenp->mccount = 0; 5211ae08745Sheppo vgenp->mcsize = VGEN_INIT_MCTAB_SIZE; 5221ae08745Sheppo 5231ae08745Sheppo mutex_init(&vgenp->lock, NULL, MUTEX_DRIVER, NULL); 52493b13a42Swentaoy rw_init(&vgenp->vgenports.rwlock, NULL, RW_DRIVER, NULL); 5251ae08745Sheppo 5267bd3a2e2SSriharsha Basavapatna (void) snprintf(qname, TASKQ_NAMELEN, "rxpool_taskq%d", 5277bd3a2e2SSriharsha Basavapatna instance); 5287bd3a2e2SSriharsha Basavapatna if ((vgenp->rxp_taskq = ddi_taskq_create(vnetdip, qname, 1, 5297bd3a2e2SSriharsha Basavapatna TASKQ_DEFAULTPRI, 0)) == NULL) { 5307bd3a2e2SSriharsha Basavapatna cmn_err(CE_WARN, "!vnet%d: Unable to create rx pool task queue", 5317bd3a2e2SSriharsha Basavapatna instance); 5327bd3a2e2SSriharsha Basavapatna goto vgen_init_fail; 5337bd3a2e2SSriharsha Basavapatna } 5347bd3a2e2SSriharsha Basavapatna 535f0ca1d9aSsb155480 rv = vgen_read_mdprops(vgenp); 536f0ca1d9aSsb155480 if (rv != 0) { 537f0ca1d9aSsb155480 goto vgen_init_fail; 538f0ca1d9aSsb155480 } 539678453a8Sspeer *vgenhdl = (void *)vgenp; 5401ae08745Sheppo 54106db247cSraghuram DBG1(NULL, NULL, "vnet(%d): exit\n", instance); 5421ae08745Sheppo return (DDI_SUCCESS); 543f0ca1d9aSsb155480 544f0ca1d9aSsb155480 vgen_init_fail: 545f0ca1d9aSsb155480 rw_destroy(&vgenp->vgenports.rwlock); 546f0ca1d9aSsb155480 mutex_destroy(&vgenp->lock); 547f0ca1d9aSsb155480 kmem_free(vgenp->mctab, VGEN_INIT_MCTAB_SIZE * 548f0ca1d9aSsb155480 sizeof (struct ether_addr)); 549f0ca1d9aSsb155480 if (VGEN_PRI_ETH_DEFINED(vgenp)) { 550f0ca1d9aSsb155480 kmem_free(vgenp->pri_types, 551f0ca1d9aSsb155480 sizeof (uint16_t) * vgenp->pri_num_types); 552f0ca1d9aSsb155480 (void) vio_destroy_mblks(vgenp->pri_tx_vmp); 553f0ca1d9aSsb155480 } 5547bd3a2e2SSriharsha Basavapatna if (vgenp->rxp_taskq != NULL) { 5557bd3a2e2SSriharsha Basavapatna ddi_taskq_destroy(vgenp->rxp_taskq); 5567bd3a2e2SSriharsha Basavapatna vgenp->rxp_taskq = NULL; 5577bd3a2e2SSriharsha Basavapatna } 558f0ca1d9aSsb155480 KMEM_FREE(vgenp); 559f0ca1d9aSsb155480 return (DDI_FAILURE); 5601ae08745Sheppo } 5611ae08745Sheppo 56263f531d1SSriharsha Basavapatna int 56363f531d1SSriharsha Basavapatna vgen_init_mdeg(void *arg) 56463f531d1SSriharsha Basavapatna { 56563f531d1SSriharsha Basavapatna vgen_t *vgenp = (vgen_t *)arg; 56663f531d1SSriharsha Basavapatna 56763f531d1SSriharsha Basavapatna /* register with MD event generator */ 56863f531d1SSriharsha Basavapatna return (vgen_mdeg_reg(vgenp)); 56963f531d1SSriharsha Basavapatna } 57063f531d1SSriharsha Basavapatna 5711ae08745Sheppo /* 5721ae08745Sheppo * Called by vnet to undo the initializations done by vgen_init(). 5731ae08745Sheppo * The handle provided by generic transport during vgen_init() is the argument. 5741ae08745Sheppo */ 5753ab636deSWENTAO YANG void 5761ae08745Sheppo vgen_uninit(void *arg) 5771ae08745Sheppo { 5781ae08745Sheppo vgen_t *vgenp = (vgen_t *)arg; 5791ae08745Sheppo 580d10e4ef2Snarayan if (vgenp == NULL) { 5813ab636deSWENTAO YANG return; 582d10e4ef2Snarayan } 5831ae08745Sheppo 584844e62a3Sraghuram DBG1(vgenp, NULL, "enter\n"); 5851ae08745Sheppo 5867bd3a2e2SSriharsha Basavapatna /* Unregister with MD event generator */ 5871ae08745Sheppo vgen_mdeg_unreg(vgenp); 5881ae08745Sheppo 5891ae08745Sheppo mutex_enter(&vgenp->lock); 5901ae08745Sheppo 5917bd3a2e2SSriharsha Basavapatna /* 5927bd3a2e2SSriharsha Basavapatna * Detach all ports from the device; note that the device should have 5937bd3a2e2SSriharsha Basavapatna * been unplumbed by this time (See vnet_unattach() for the sequence) 5947bd3a2e2SSriharsha Basavapatna * and thus vgen_stop() has already been invoked on all the ports. 5957bd3a2e2SSriharsha Basavapatna */ 5961ae08745Sheppo vgen_detach_ports(vgenp); 5971ae08745Sheppo 598d10e4ef2Snarayan /* 5997bd3a2e2SSriharsha Basavapatna * We now destroy the taskq used to clean up rx mblk pools that 6007bd3a2e2SSriharsha Basavapatna * couldn't be destroyed when the ports/channels were detached. 6017bd3a2e2SSriharsha Basavapatna * We implicitly wait for those tasks to complete in 6027bd3a2e2SSriharsha Basavapatna * ddi_taskq_destroy(). 603d10e4ef2Snarayan */ 6047bd3a2e2SSriharsha Basavapatna if (vgenp->rxp_taskq != NULL) { 6057bd3a2e2SSriharsha Basavapatna ddi_taskq_destroy(vgenp->rxp_taskq); 6067bd3a2e2SSriharsha Basavapatna vgenp->rxp_taskq = NULL; 607d10e4ef2Snarayan } 608d10e4ef2Snarayan 6097bd3a2e2SSriharsha Basavapatna /* Free multicast table */ 6101ae08745Sheppo kmem_free(vgenp->mctab, vgenp->mcsize * sizeof (struct ether_addr)); 6111ae08745Sheppo 6127bd3a2e2SSriharsha Basavapatna /* Free pri_types table */ 613f0ca1d9aSsb155480 if (VGEN_PRI_ETH_DEFINED(vgenp)) { 614f0ca1d9aSsb155480 kmem_free(vgenp->pri_types, 615f0ca1d9aSsb155480 sizeof (uint16_t) * vgenp->pri_num_types); 616f0ca1d9aSsb155480 (void) vio_destroy_mblks(vgenp->pri_tx_vmp); 617f0ca1d9aSsb155480 } 618f0ca1d9aSsb155480 6191ae08745Sheppo mutex_exit(&vgenp->lock); 62093b13a42Swentaoy rw_destroy(&vgenp->vgenports.rwlock); 6211ae08745Sheppo mutex_destroy(&vgenp->lock); 6221ae08745Sheppo 623844e62a3Sraghuram DBG1(vgenp, NULL, "exit\n"); 62452bca946SWENTAO YANG KMEM_FREE(vgenp); 6251ae08745Sheppo } 6261ae08745Sheppo 6271ae08745Sheppo /* enable transmit/receive for the device */ 628ba2e4443Sseb int 6291ae08745Sheppo vgen_start(void *arg) 6301ae08745Sheppo { 631678453a8Sspeer vgen_port_t *portp = (vgen_port_t *)arg; 632678453a8Sspeer vgen_t *vgenp = portp->vgenp; 6331ae08745Sheppo 634844e62a3Sraghuram DBG1(vgenp, NULL, "enter\n"); 635678453a8Sspeer mutex_enter(&portp->lock); 636678453a8Sspeer vgen_port_init(portp); 637678453a8Sspeer portp->flags |= VGEN_STARTED; 638678453a8Sspeer mutex_exit(&portp->lock); 639844e62a3Sraghuram DBG1(vgenp, NULL, "exit\n"); 640678453a8Sspeer 6411ae08745Sheppo return (DDI_SUCCESS); 6421ae08745Sheppo } 6431ae08745Sheppo 6441ae08745Sheppo /* stop transmit/receive */ 645ba2e4443Sseb void 6461ae08745Sheppo vgen_stop(void *arg) 6471ae08745Sheppo { 648678453a8Sspeer vgen_port_t *portp = (vgen_port_t *)arg; 649678453a8Sspeer vgen_t *vgenp = portp->vgenp; 6501ae08745Sheppo 651844e62a3Sraghuram DBG1(vgenp, NULL, "enter\n"); 6521ae08745Sheppo 653678453a8Sspeer mutex_enter(&portp->lock); 6540c4606f0SWENTAO YANG if (portp->flags & VGEN_STARTED) { 655678453a8Sspeer vgen_port_uninit(portp); 656678453a8Sspeer portp->flags &= ~(VGEN_STARTED); 6570c4606f0SWENTAO YANG } 658678453a8Sspeer mutex_exit(&portp->lock); 659844e62a3Sraghuram DBG1(vgenp, NULL, "exit\n"); 660678453a8Sspeer 6611ae08745Sheppo } 6621ae08745Sheppo 6631ae08745Sheppo /* vgen transmit function */ 6641ae08745Sheppo static mblk_t * 6651ae08745Sheppo vgen_tx(void *arg, mblk_t *mp) 6661ae08745Sheppo { 6671ae08745Sheppo vgen_port_t *portp; 6687bd3a2e2SSriharsha Basavapatna int status; 6691ae08745Sheppo 6701ae08745Sheppo portp = (vgen_port_t *)arg; 6711ae08745Sheppo status = vgen_portsend(portp, mp); 6721ae08745Sheppo if (status != VGEN_SUCCESS) { 6731ae08745Sheppo /* failure */ 6741ae08745Sheppo return (mp); 6751ae08745Sheppo } 6761ae08745Sheppo /* success */ 6771ae08745Sheppo return (NULL); 6781ae08745Sheppo } 6791ae08745Sheppo 680c1c61f44Ssb155480 /* 681c1c61f44Ssb155480 * This function provides any necessary tagging/untagging of the frames 682c1c61f44Ssb155480 * that are being transmitted over the port. It first verifies the vlan 683c1c61f44Ssb155480 * membership of the destination(port) and drops the packet if the 684c1c61f44Ssb155480 * destination doesn't belong to the given vlan. 685c1c61f44Ssb155480 * 686c1c61f44Ssb155480 * Arguments: 687c1c61f44Ssb155480 * portp: port over which the frames should be transmitted 688c1c61f44Ssb155480 * mp: frame to be transmitted 689c1c61f44Ssb155480 * is_tagged: 690c1c61f44Ssb155480 * B_TRUE: indicates frame header contains the vlan tag already. 691c1c61f44Ssb155480 * B_FALSE: indicates frame is untagged. 692c1c61f44Ssb155480 * vid: vlan in which the frame should be transmitted. 693c1c61f44Ssb155480 * 694c1c61f44Ssb155480 * Returns: 695c1c61f44Ssb155480 * Sucess: frame(mblk_t *) after doing the necessary tag/untag. 696c1c61f44Ssb155480 * Failure: NULL 697c1c61f44Ssb155480 */ 698c1c61f44Ssb155480 static mblk_t * 699c1c61f44Ssb155480 vgen_vlan_frame_fixtag(vgen_port_t *portp, mblk_t *mp, boolean_t is_tagged, 700c1c61f44Ssb155480 uint16_t vid) 701c1c61f44Ssb155480 { 702c1c61f44Ssb155480 vgen_t *vgenp; 703c1c61f44Ssb155480 boolean_t dst_tagged; 704c1c61f44Ssb155480 int rv; 705c1c61f44Ssb155480 706c1c61f44Ssb155480 vgenp = portp->vgenp; 707c1c61f44Ssb155480 708c1c61f44Ssb155480 /* 709c1c61f44Ssb155480 * If the packet is going to a vnet: 710c1c61f44Ssb155480 * Check if the destination vnet is in the same vlan. 711c1c61f44Ssb155480 * Check the frame header if tag or untag is needed. 712c1c61f44Ssb155480 * 713c1c61f44Ssb155480 * We do not check the above conditions if the packet is going to vsw: 714c1c61f44Ssb155480 * vsw must be present implicitly in all the vlans that a vnet device 715c1c61f44Ssb155480 * is configured into; even if vsw itself is not assigned to those 716c1c61f44Ssb155480 * vlans as an interface. For instance, the packet might be destined 717c1c61f44Ssb155480 * to another vnet(indirectly through vsw) or to an external host 718c1c61f44Ssb155480 * which is in the same vlan as this vnet and vsw itself may not be 719c1c61f44Ssb155480 * present in that vlan. Similarly packets going to vsw must be 720c1c61f44Ssb155480 * always tagged(unless in the default-vlan) if not already tagged, 721c1c61f44Ssb155480 * as we do not know the final destination. This is needed because 722c1c61f44Ssb155480 * vsw must always invoke its switching function only after tagging 723c1c61f44Ssb155480 * the packet; otherwise after switching function determines the 724c1c61f44Ssb155480 * destination we cannot figure out if the destination belongs to the 725c1c61f44Ssb155480 * the same vlan that the frame originated from and if it needs tag/ 726c1c61f44Ssb155480 * untag. Note that vsw will tag the packet itself when it receives 727c1c61f44Ssb155480 * it over the channel from a client if needed. However, that is 728c1c61f44Ssb155480 * needed only in the case of vlan unaware clients such as obp or 729c1c61f44Ssb155480 * earlier versions of vnet. 730c1c61f44Ssb155480 * 731c1c61f44Ssb155480 */ 732c1c61f44Ssb155480 if (portp != vgenp->vsw_portp) { 733c1c61f44Ssb155480 /* 734c1c61f44Ssb155480 * Packet going to a vnet. Check if the destination vnet is in 735c1c61f44Ssb155480 * the same vlan. Then check the frame header if tag/untag is 736c1c61f44Ssb155480 * needed. 737c1c61f44Ssb155480 */ 738c1c61f44Ssb155480 rv = vgen_vlan_lookup(portp->vlan_hashp, vid); 739c1c61f44Ssb155480 if (rv == B_FALSE) { 740c1c61f44Ssb155480 /* drop the packet */ 741c1c61f44Ssb155480 freemsg(mp); 742c1c61f44Ssb155480 return (NULL); 743c1c61f44Ssb155480 } 744c1c61f44Ssb155480 745c1c61f44Ssb155480 /* is the destination tagged or untagged in this vlan? */ 746c1c61f44Ssb155480 (vid == portp->pvid) ? (dst_tagged = B_FALSE) : 747c1c61f44Ssb155480 (dst_tagged = B_TRUE); 748c1c61f44Ssb155480 749c1c61f44Ssb155480 if (is_tagged == dst_tagged) { 750c1c61f44Ssb155480 /* no tagging/untagging needed */ 751c1c61f44Ssb155480 return (mp); 752c1c61f44Ssb155480 } 753c1c61f44Ssb155480 754c1c61f44Ssb155480 if (is_tagged == B_TRUE) { 755c1c61f44Ssb155480 /* frame is tagged; destination needs untagged */ 756c1c61f44Ssb155480 mp = vnet_vlan_remove_tag(mp); 757c1c61f44Ssb155480 return (mp); 758c1c61f44Ssb155480 } 759c1c61f44Ssb155480 760c1c61f44Ssb155480 /* (is_tagged == B_FALSE): fallthru to tag tx packet: */ 761c1c61f44Ssb155480 } 762c1c61f44Ssb155480 763c1c61f44Ssb155480 /* 764c1c61f44Ssb155480 * Packet going to a vnet needs tagging. 765c1c61f44Ssb155480 * OR 766c1c61f44Ssb155480 * If the packet is going to vsw, then it must be tagged in all cases: 767c1c61f44Ssb155480 * unknown unicast, broadcast/multicast or to vsw interface. 768c1c61f44Ssb155480 */ 769c1c61f44Ssb155480 770c1c61f44Ssb155480 if (is_tagged == B_FALSE) { 771c1c61f44Ssb155480 mp = vnet_vlan_insert_tag(mp, vid); 772c1c61f44Ssb155480 } 773c1c61f44Ssb155480 774c1c61f44Ssb155480 return (mp); 775c1c61f44Ssb155480 } 776c1c61f44Ssb155480 7771ae08745Sheppo /* transmit packets over the given port */ 7781ae08745Sheppo static int 7791ae08745Sheppo vgen_portsend(vgen_port_t *portp, mblk_t *mp) 7801ae08745Sheppo { 7811ae08745Sheppo vgen_ldc_t *ldcp; 7821ae08745Sheppo int status; 78361a70d81Sraghuram int rv = VGEN_SUCCESS; 784678453a8Sspeer vgen_t *vgenp = portp->vgenp; 785678453a8Sspeer vnet_t *vnetp = vgenp->vnetp; 786c1c61f44Ssb155480 boolean_t is_tagged; 787678453a8Sspeer boolean_t dec_refcnt = B_FALSE; 788c1c61f44Ssb155480 uint16_t vlan_id; 789c1c61f44Ssb155480 struct ether_header *ehp; 790c1c61f44Ssb155480 7917bd3a2e2SSriharsha Basavapatna if (portp == NULL) { 7927bd3a2e2SSriharsha Basavapatna return (VGEN_FAILURE); 7937bd3a2e2SSriharsha Basavapatna } 7947bd3a2e2SSriharsha Basavapatna 795678453a8Sspeer if (portp->use_vsw_port) { 796678453a8Sspeer (void) atomic_inc_32(&vgenp->vsw_port_refcnt); 797678453a8Sspeer portp = portp->vgenp->vsw_portp; 7987bd3a2e2SSriharsha Basavapatna ASSERT(portp != NULL); 799678453a8Sspeer dec_refcnt = B_TRUE; 800678453a8Sspeer } 801c1c61f44Ssb155480 802c1c61f44Ssb155480 /* 803c1c61f44Ssb155480 * Determine the vlan id that the frame belongs to. 804c1c61f44Ssb155480 */ 805c1c61f44Ssb155480 ehp = (struct ether_header *)mp->b_rptr; 806c1c61f44Ssb155480 is_tagged = vgen_frame_lookup_vid(vnetp, ehp, &vlan_id); 807c1c61f44Ssb155480 808c1c61f44Ssb155480 if (vlan_id == vnetp->default_vlan_id) { 809c1c61f44Ssb155480 810c1c61f44Ssb155480 /* Frames in default vlan must be untagged */ 811c1c61f44Ssb155480 ASSERT(is_tagged == B_FALSE); 812c1c61f44Ssb155480 813c1c61f44Ssb155480 /* 814c1c61f44Ssb155480 * If the destination is a vnet-port verify it belongs to the 815c1c61f44Ssb155480 * default vlan; otherwise drop the packet. We do not need 816c1c61f44Ssb155480 * this check for vsw-port, as it should implicitly belong to 817c1c61f44Ssb155480 * this vlan; see comments in vgen_vlan_frame_fixtag(). 818c1c61f44Ssb155480 */ 819c1c61f44Ssb155480 if (portp != vgenp->vsw_portp && 820c1c61f44Ssb155480 portp->pvid != vnetp->default_vlan_id) { 821c1c61f44Ssb155480 freemsg(mp); 822678453a8Sspeer goto portsend_ret; 823c1c61f44Ssb155480 } 824c1c61f44Ssb155480 825c1c61f44Ssb155480 } else { /* frame not in default-vlan */ 826c1c61f44Ssb155480 827c1c61f44Ssb155480 mp = vgen_vlan_frame_fixtag(portp, mp, is_tagged, vlan_id); 828c1c61f44Ssb155480 if (mp == NULL) { 829678453a8Sspeer goto portsend_ret; 830c1c61f44Ssb155480 } 831c1c61f44Ssb155480 832c1c61f44Ssb155480 } 8331ae08745Sheppo 8347bd3a2e2SSriharsha Basavapatna ldcp = portp->ldcp; 835f0ca1d9aSsb155480 status = ldcp->tx(ldcp, mp); 83661a70d81Sraghuram 83761a70d81Sraghuram if (status != VGEN_TX_SUCCESS) { 83861a70d81Sraghuram rv = VGEN_FAILURE; 83961a70d81Sraghuram } 840678453a8Sspeer 841678453a8Sspeer portsend_ret: 842678453a8Sspeer if (dec_refcnt == B_TRUE) { 843678453a8Sspeer (void) atomic_dec_32(&vgenp->vsw_port_refcnt); 844678453a8Sspeer } 84561a70d81Sraghuram return (rv); 8461ae08745Sheppo } 8471ae08745Sheppo 848f0ca1d9aSsb155480 /* 849f0ca1d9aSsb155480 * Wrapper function to transmit normal and/or priority frames over the channel. 850f0ca1d9aSsb155480 */ 8511ae08745Sheppo static int 852f0ca1d9aSsb155480 vgen_ldcsend(void *arg, mblk_t *mp) 8531ae08745Sheppo { 854f0ca1d9aSsb155480 vgen_ldc_t *ldcp = (vgen_ldc_t *)arg; 855f0ca1d9aSsb155480 int status; 856f0ca1d9aSsb155480 struct ether_header *ehp; 857f0ca1d9aSsb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 858f0ca1d9aSsb155480 uint32_t num_types; 859f0ca1d9aSsb155480 uint16_t *types; 860f0ca1d9aSsb155480 int i; 861f0ca1d9aSsb155480 862f0ca1d9aSsb155480 ASSERT(VGEN_PRI_ETH_DEFINED(vgenp)); 863f0ca1d9aSsb155480 864f0ca1d9aSsb155480 num_types = vgenp->pri_num_types; 865f0ca1d9aSsb155480 types = vgenp->pri_types; 866f0ca1d9aSsb155480 ehp = (struct ether_header *)mp->b_rptr; 867f0ca1d9aSsb155480 868f0ca1d9aSsb155480 for (i = 0; i < num_types; i++) { 869f0ca1d9aSsb155480 870f0ca1d9aSsb155480 if (ehp->ether_type == types[i]) { 871f0ca1d9aSsb155480 /* priority frame, use pri tx function */ 872f0ca1d9aSsb155480 vgen_ldcsend_pkt(ldcp, mp); 873f0ca1d9aSsb155480 return (VGEN_SUCCESS); 874f0ca1d9aSsb155480 } 875f0ca1d9aSsb155480 876f0ca1d9aSsb155480 } 877f0ca1d9aSsb155480 8787bd3a2e2SSriharsha Basavapatna if (ldcp->tx_dringdata == NULL) { 8797bd3a2e2SSriharsha Basavapatna freemsg(mp); 8807bd3a2e2SSriharsha Basavapatna return (VGEN_SUCCESS); 8817bd3a2e2SSriharsha Basavapatna } 882f0ca1d9aSsb155480 8837bd3a2e2SSriharsha Basavapatna status = ldcp->tx_dringdata(ldcp, mp); 884f0ca1d9aSsb155480 return (status); 885f0ca1d9aSsb155480 } 886f0ca1d9aSsb155480 887f0ca1d9aSsb155480 /* 888f0ca1d9aSsb155480 * This function transmits the frame in the payload of a raw data 889f0ca1d9aSsb155480 * (VIO_PKT_DATA) message. Thus, it provides an Out-Of-Band path to 890f0ca1d9aSsb155480 * send special frames with high priorities, without going through 891f0ca1d9aSsb155480 * the normal data path which uses descriptor ring mechanism. 892f0ca1d9aSsb155480 */ 893f0ca1d9aSsb155480 static void 894f0ca1d9aSsb155480 vgen_ldcsend_pkt(void *arg, mblk_t *mp) 895f0ca1d9aSsb155480 { 896f0ca1d9aSsb155480 vgen_ldc_t *ldcp = (vgen_ldc_t *)arg; 897f0ca1d9aSsb155480 vio_raw_data_msg_t *pkt; 898f0ca1d9aSsb155480 mblk_t *bp; 899f0ca1d9aSsb155480 mblk_t *nmp = NULL; 9007bd3a2e2SSriharsha Basavapatna vio_mblk_t *vmp; 901f0ca1d9aSsb155480 caddr_t dst; 902f0ca1d9aSsb155480 uint32_t mblksz; 903f0ca1d9aSsb155480 uint32_t size; 904f0ca1d9aSsb155480 uint32_t nbytes; 905f0ca1d9aSsb155480 int rv; 906f0ca1d9aSsb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 907f0ca1d9aSsb155480 vgen_stats_t *statsp = &ldcp->stats; 908f0ca1d9aSsb155480 909f0ca1d9aSsb155480 /* drop the packet if ldc is not up or handshake is not done */ 910f0ca1d9aSsb155480 if (ldcp->ldc_status != LDC_UP) { 911f0ca1d9aSsb155480 (void) atomic_inc_32(&statsp->tx_pri_fail); 912f0ca1d9aSsb155480 DWARN(vgenp, ldcp, "status(%d), dropping packet\n", 913f0ca1d9aSsb155480 ldcp->ldc_status); 914f0ca1d9aSsb155480 goto send_pkt_exit; 915f0ca1d9aSsb155480 } 916f0ca1d9aSsb155480 917f0ca1d9aSsb155480 if (ldcp->hphase != VH_DONE) { 918f0ca1d9aSsb155480 (void) atomic_inc_32(&statsp->tx_pri_fail); 919f0ca1d9aSsb155480 DWARN(vgenp, ldcp, "hphase(%x), dropping packet\n", 920f0ca1d9aSsb155480 ldcp->hphase); 921f0ca1d9aSsb155480 goto send_pkt_exit; 922f0ca1d9aSsb155480 } 923f0ca1d9aSsb155480 924f0ca1d9aSsb155480 size = msgsize(mp); 925f0ca1d9aSsb155480 926f0ca1d9aSsb155480 /* frame size bigger than available payload len of raw data msg ? */ 927f0ca1d9aSsb155480 if (size > (size_t)(ldcp->msglen - VIO_PKT_DATA_HDRSIZE)) { 928f0ca1d9aSsb155480 (void) atomic_inc_32(&statsp->tx_pri_fail); 929f0ca1d9aSsb155480 DWARN(vgenp, ldcp, "invalid size(%d)\n", size); 930f0ca1d9aSsb155480 goto send_pkt_exit; 931f0ca1d9aSsb155480 } 932f0ca1d9aSsb155480 933f0ca1d9aSsb155480 if (size < ETHERMIN) 934f0ca1d9aSsb155480 size = ETHERMIN; 935f0ca1d9aSsb155480 936f0ca1d9aSsb155480 /* alloc space for a raw data message */ 9377bd3a2e2SSriharsha Basavapatna vmp = vio_allocb(vgenp->pri_tx_vmp); 9387bd3a2e2SSriharsha Basavapatna if (vmp == NULL) { 939f0ca1d9aSsb155480 (void) atomic_inc_32(&statsp->tx_pri_fail); 940f0ca1d9aSsb155480 DWARN(vgenp, ldcp, "vio_allocb failed\n"); 941f0ca1d9aSsb155480 goto send_pkt_exit; 9427bd3a2e2SSriharsha Basavapatna } else { 9437bd3a2e2SSriharsha Basavapatna nmp = vmp->mp; 944f0ca1d9aSsb155480 } 945f0ca1d9aSsb155480 pkt = (vio_raw_data_msg_t *)nmp->b_rptr; 946f0ca1d9aSsb155480 947f0ca1d9aSsb155480 /* copy frame into the payload of raw data message */ 948f0ca1d9aSsb155480 dst = (caddr_t)pkt->data; 949f0ca1d9aSsb155480 for (bp = mp; bp != NULL; bp = bp->b_cont) { 950f0ca1d9aSsb155480 mblksz = MBLKL(bp); 951f0ca1d9aSsb155480 bcopy(bp->b_rptr, dst, mblksz); 952f0ca1d9aSsb155480 dst += mblksz; 953f0ca1d9aSsb155480 } 954f0ca1d9aSsb155480 9557bd3a2e2SSriharsha Basavapatna vmp->state = VIO_MBLK_HAS_DATA; 9567bd3a2e2SSriharsha Basavapatna 957f0ca1d9aSsb155480 /* setup the raw data msg */ 958f0ca1d9aSsb155480 pkt->tag.vio_msgtype = VIO_TYPE_DATA; 959f0ca1d9aSsb155480 pkt->tag.vio_subtype = VIO_SUBTYPE_INFO; 960f0ca1d9aSsb155480 pkt->tag.vio_subtype_env = VIO_PKT_DATA; 961f0ca1d9aSsb155480 pkt->tag.vio_sid = ldcp->local_sid; 962f0ca1d9aSsb155480 nbytes = VIO_PKT_DATA_HDRSIZE + size; 963f0ca1d9aSsb155480 964f0ca1d9aSsb155480 /* send the msg over ldc */ 965f0ca1d9aSsb155480 rv = vgen_sendmsg(ldcp, (caddr_t)pkt, nbytes, B_FALSE); 966f0ca1d9aSsb155480 if (rv != VGEN_SUCCESS) { 967f0ca1d9aSsb155480 (void) atomic_inc_32(&statsp->tx_pri_fail); 968f0ca1d9aSsb155480 DWARN(vgenp, ldcp, "Error sending priority frame\n"); 969f0ca1d9aSsb155480 if (rv == ECONNRESET) { 9707bd3a2e2SSriharsha Basavapatna (void) vgen_handle_evt_reset(ldcp, VGEN_OTHER); 971f0ca1d9aSsb155480 } 972f0ca1d9aSsb155480 goto send_pkt_exit; 973f0ca1d9aSsb155480 } 974f0ca1d9aSsb155480 975f0ca1d9aSsb155480 /* update stats */ 976f0ca1d9aSsb155480 (void) atomic_inc_64(&statsp->tx_pri_packets); 977f0ca1d9aSsb155480 (void) atomic_add_64(&statsp->tx_pri_bytes, size); 978f0ca1d9aSsb155480 979f0ca1d9aSsb155480 send_pkt_exit: 980f0ca1d9aSsb155480 if (nmp != NULL) 981f0ca1d9aSsb155480 freemsg(nmp); 982f0ca1d9aSsb155480 freemsg(mp); 983f0ca1d9aSsb155480 } 984f0ca1d9aSsb155480 985f0ca1d9aSsb155480 /* 9860c4606f0SWENTAO YANG * enable/disable a multicast address 9870c4606f0SWENTAO YANG * note that the cblock of the ldc channel connected to the vsw is used for 9880c4606f0SWENTAO YANG * synchronization of the mctab. 9890c4606f0SWENTAO YANG */ 990ba2e4443Sseb int 9911ae08745Sheppo vgen_multicst(void *arg, boolean_t add, const uint8_t *mca) 9921ae08745Sheppo { 9931ae08745Sheppo vgen_t *vgenp; 9941ae08745Sheppo vnet_mcast_msg_t mcastmsg; 9951ae08745Sheppo vio_msg_tag_t *tagp; 9961ae08745Sheppo vgen_port_t *portp; 9971ae08745Sheppo vgen_ldc_t *ldcp; 9981ae08745Sheppo struct ether_addr *addrp; 999bd8f0338Snarayan int rv = DDI_FAILURE; 10001ae08745Sheppo uint32_t i; 10011ae08745Sheppo 1002678453a8Sspeer portp = (vgen_port_t *)arg; 1003678453a8Sspeer vgenp = portp->vgenp; 1004678453a8Sspeer 10050c4606f0SWENTAO YANG if (portp->is_vsw_port != B_TRUE) { 1006678453a8Sspeer return (DDI_SUCCESS); 1007678453a8Sspeer } 1008678453a8Sspeer 10091ae08745Sheppo addrp = (struct ether_addr *)mca; 10101ae08745Sheppo tagp = &mcastmsg.tag; 10111ae08745Sheppo bzero(&mcastmsg, sizeof (mcastmsg)); 10121ae08745Sheppo 10137bd3a2e2SSriharsha Basavapatna ldcp = portp->ldcp; 10140c4606f0SWENTAO YANG if (ldcp == NULL) { 10150c4606f0SWENTAO YANG return (DDI_FAILURE); 10160c4606f0SWENTAO YANG } 10171ae08745Sheppo 10181ae08745Sheppo mutex_enter(&ldcp->cblock); 10191ae08745Sheppo 10201ae08745Sheppo if (ldcp->hphase == VH_DONE) { 10211ae08745Sheppo /* 10221ae08745Sheppo * If handshake is done, send a msg to vsw to add/remove 102319b65a69Ssb155480 * the multicast address. Otherwise, we just update this 102419b65a69Ssb155480 * mcast address in our table and the table will be sync'd 102519b65a69Ssb155480 * with vsw when handshake completes. 10261ae08745Sheppo */ 10271ae08745Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 10281ae08745Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 10291ae08745Sheppo tagp->vio_subtype_env = VNET_MCAST_INFO; 10301ae08745Sheppo tagp->vio_sid = ldcp->local_sid; 10311ae08745Sheppo bcopy(mca, &(mcastmsg.mca), ETHERADDRL); 10321ae08745Sheppo mcastmsg.set = add; 10331ae08745Sheppo mcastmsg.count = 1; 1034bd8f0338Snarayan if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (mcastmsg), 1035bd8f0338Snarayan B_FALSE) != VGEN_SUCCESS) { 1036844e62a3Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n"); 10370c4606f0SWENTAO YANG rv = DDI_FAILURE; 1038bd8f0338Snarayan goto vgen_mcast_exit; 10391ae08745Sheppo } 10401ae08745Sheppo } 10411ae08745Sheppo 10421ae08745Sheppo if (add) { 10431ae08745Sheppo 10441ae08745Sheppo /* expand multicast table if necessary */ 10451ae08745Sheppo if (vgenp->mccount >= vgenp->mcsize) { 10461ae08745Sheppo struct ether_addr *newtab; 10471ae08745Sheppo uint32_t newsize; 10481ae08745Sheppo 10491ae08745Sheppo 10501ae08745Sheppo newsize = vgenp->mcsize * 2; 10511ae08745Sheppo 10521ae08745Sheppo newtab = kmem_zalloc(newsize * 10531ae08745Sheppo sizeof (struct ether_addr), KM_NOSLEEP); 1054bd8f0338Snarayan if (newtab == NULL) 1055bd8f0338Snarayan goto vgen_mcast_exit; 10561ae08745Sheppo bcopy(vgenp->mctab, newtab, vgenp->mcsize * 10571ae08745Sheppo sizeof (struct ether_addr)); 10581ae08745Sheppo kmem_free(vgenp->mctab, 10591ae08745Sheppo vgenp->mcsize * sizeof (struct ether_addr)); 10601ae08745Sheppo 10611ae08745Sheppo vgenp->mctab = newtab; 10621ae08745Sheppo vgenp->mcsize = newsize; 10631ae08745Sheppo } 10641ae08745Sheppo 10651ae08745Sheppo /* add address to the table */ 10661ae08745Sheppo vgenp->mctab[vgenp->mccount++] = *addrp; 10671ae08745Sheppo 10681ae08745Sheppo } else { 10691ae08745Sheppo 10701ae08745Sheppo /* delete address from the table */ 10711ae08745Sheppo for (i = 0; i < vgenp->mccount; i++) { 10721ae08745Sheppo if (ether_cmp(addrp, &(vgenp->mctab[i])) == 0) { 10731ae08745Sheppo 10741ae08745Sheppo /* 10751ae08745Sheppo * If there's more than one address in this 10761ae08745Sheppo * table, delete the unwanted one by moving 10771ae08745Sheppo * the last one in the list over top of it; 10781ae08745Sheppo * otherwise, just remove it. 10791ae08745Sheppo */ 10801ae08745Sheppo if (vgenp->mccount > 1) { 10811ae08745Sheppo vgenp->mctab[i] = 10821ae08745Sheppo vgenp->mctab[vgenp->mccount-1]; 10831ae08745Sheppo } 10841ae08745Sheppo vgenp->mccount--; 10851ae08745Sheppo break; 10861ae08745Sheppo } 10871ae08745Sheppo } 10881ae08745Sheppo } 10891ae08745Sheppo 1090bd8f0338Snarayan rv = DDI_SUCCESS; 1091bd8f0338Snarayan 1092bd8f0338Snarayan vgen_mcast_exit: 10931ae08745Sheppo 10947bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->cblock); 1095bd8f0338Snarayan return (rv); 10961ae08745Sheppo } 10971ae08745Sheppo 10981ae08745Sheppo /* set or clear promiscuous mode on the device */ 10991ae08745Sheppo static int 11001ae08745Sheppo vgen_promisc(void *arg, boolean_t on) 11011ae08745Sheppo { 11021ae08745Sheppo _NOTE(ARGUNUSED(arg, on)) 11031ae08745Sheppo return (DDI_SUCCESS); 11041ae08745Sheppo } 11051ae08745Sheppo 11061ae08745Sheppo /* set the unicast mac address of the device */ 11071ae08745Sheppo static int 11081ae08745Sheppo vgen_unicst(void *arg, const uint8_t *mca) 11091ae08745Sheppo { 11101ae08745Sheppo _NOTE(ARGUNUSED(arg, mca)) 11111ae08745Sheppo return (DDI_SUCCESS); 11121ae08745Sheppo } 11131ae08745Sheppo 11141ae08745Sheppo /* get device statistics */ 1115ba2e4443Sseb int 1116ba2e4443Sseb vgen_stat(void *arg, uint_t stat, uint64_t *val) 11171ae08745Sheppo { 1118678453a8Sspeer vgen_port_t *portp = (vgen_port_t *)arg; 11191ae08745Sheppo 1120678453a8Sspeer *val = vgen_port_stat(portp, stat); 1121ba2e4443Sseb return (0); 11221ae08745Sheppo } 11231ae08745Sheppo 11241ae08745Sheppo /* vgen internal functions */ 11251ae08745Sheppo /* detach all ports from the device */ 11261ae08745Sheppo static void 11271ae08745Sheppo vgen_detach_ports(vgen_t *vgenp) 11281ae08745Sheppo { 11291ae08745Sheppo vgen_port_t *portp; 11301ae08745Sheppo vgen_portlist_t *plistp; 11311ae08745Sheppo 11321ae08745Sheppo plistp = &(vgenp->vgenports); 11331ae08745Sheppo WRITE_ENTER(&plistp->rwlock); 11341ae08745Sheppo while ((portp = plistp->headp) != NULL) { 11351ae08745Sheppo vgen_port_detach(portp); 11361ae08745Sheppo } 11371ae08745Sheppo RW_EXIT(&plistp->rwlock); 11381ae08745Sheppo } 11391ae08745Sheppo 11401ae08745Sheppo /* 11411ae08745Sheppo * detach the given port. 11421ae08745Sheppo */ 11431ae08745Sheppo static void 11441ae08745Sheppo vgen_port_detach(vgen_port_t *portp) 11451ae08745Sheppo { 11461ae08745Sheppo vgen_t *vgenp; 11471ae08745Sheppo int port_num; 11481ae08745Sheppo 11491ae08745Sheppo vgenp = portp->vgenp; 11501ae08745Sheppo port_num = portp->port_num; 11511ae08745Sheppo 1152844e62a3Sraghuram DBG1(vgenp, NULL, "port(%d):enter\n", port_num); 11531ae08745Sheppo 1154678453a8Sspeer /* 1155678453a8Sspeer * If this port is connected to the vswitch, then 1156678453a8Sspeer * potentially there could be ports that may be using 1157678453a8Sspeer * this port to transmit packets. To address this do 1158678453a8Sspeer * the following: 1159678453a8Sspeer * - First set vgenp->vsw_portp to NULL, so that 1160678453a8Sspeer * its not used after that. 1161678453a8Sspeer * - Then wait for the refcnt to go down to 0. 1162678453a8Sspeer * - Now we can safely detach this port. 1163678453a8Sspeer */ 1164678453a8Sspeer if (vgenp->vsw_portp == portp) { 1165678453a8Sspeer vgenp->vsw_portp = NULL; 1166678453a8Sspeer while (vgenp->vsw_port_refcnt > 0) { 1167678453a8Sspeer delay(drv_usectohz(vgen_tx_delay)); 1168678453a8Sspeer } 1169678453a8Sspeer (void) atomic_swap_32(&vgenp->vsw_port_refcnt, 0); 1170678453a8Sspeer } 1171678453a8Sspeer 1172678453a8Sspeer if (portp->vhp != NULL) { 1173678453a8Sspeer vio_net_resource_unreg(portp->vhp); 1174678453a8Sspeer portp->vhp = NULL; 1175678453a8Sspeer } 1176678453a8Sspeer 1177c1c61f44Ssb155480 vgen_vlan_destroy_hash(portp); 1178c1c61f44Ssb155480 11791ae08745Sheppo /* remove it from port list */ 11801ae08745Sheppo vgen_port_list_remove(portp); 11811ae08745Sheppo 11821ae08745Sheppo /* detach channels from this port */ 11837bd3a2e2SSriharsha Basavapatna vgen_ldc_detach(portp->ldcp); 11841ae08745Sheppo 1185c1c61f44Ssb155480 if (portp->num_ldcs != 0) { 1186c1c61f44Ssb155480 kmem_free(portp->ldc_ids, portp->num_ldcs * sizeof (uint64_t)); 1187c1c61f44Ssb155480 portp->num_ldcs = 0; 1188c1c61f44Ssb155480 } 1189c1c61f44Ssb155480 1190678453a8Sspeer mutex_destroy(&portp->lock); 11911ae08745Sheppo KMEM_FREE(portp); 11921ae08745Sheppo 1193844e62a3Sraghuram DBG1(vgenp, NULL, "port(%d):exit\n", port_num); 11941ae08745Sheppo } 11951ae08745Sheppo 11961ae08745Sheppo /* add a port to port list */ 11971ae08745Sheppo static void 11981ae08745Sheppo vgen_port_list_insert(vgen_port_t *portp) 11991ae08745Sheppo { 12001ae08745Sheppo vgen_portlist_t *plistp; 12011ae08745Sheppo vgen_t *vgenp; 12021ae08745Sheppo 12031ae08745Sheppo vgenp = portp->vgenp; 12041ae08745Sheppo plistp = &(vgenp->vgenports); 12051ae08745Sheppo 12061ae08745Sheppo if (plistp->headp == NULL) { 12071ae08745Sheppo plistp->headp = portp; 12081ae08745Sheppo } else { 12091ae08745Sheppo plistp->tailp->nextp = portp; 12101ae08745Sheppo } 12111ae08745Sheppo plistp->tailp = portp; 12121ae08745Sheppo portp->nextp = NULL; 12131ae08745Sheppo } 12141ae08745Sheppo 12151ae08745Sheppo /* remove a port from port list */ 12161ae08745Sheppo static void 12171ae08745Sheppo vgen_port_list_remove(vgen_port_t *portp) 12181ae08745Sheppo { 12191ae08745Sheppo vgen_port_t *prevp; 12201ae08745Sheppo vgen_port_t *nextp; 12211ae08745Sheppo vgen_portlist_t *plistp; 12221ae08745Sheppo vgen_t *vgenp; 12231ae08745Sheppo 12241ae08745Sheppo vgenp = portp->vgenp; 12251ae08745Sheppo 12261ae08745Sheppo plistp = &(vgenp->vgenports); 12271ae08745Sheppo 12281ae08745Sheppo if (plistp->headp == NULL) 12291ae08745Sheppo return; 12301ae08745Sheppo 12311ae08745Sheppo if (portp == plistp->headp) { 12321ae08745Sheppo plistp->headp = portp->nextp; 12331ae08745Sheppo if (portp == plistp->tailp) 12341ae08745Sheppo plistp->tailp = plistp->headp; 12351ae08745Sheppo } else { 1236b4d0458eSraghuram for (prevp = plistp->headp; 1237b4d0458eSraghuram ((nextp = prevp->nextp) != NULL) && (nextp != portp); 1238b4d0458eSraghuram prevp = nextp) 1239b4d0458eSraghuram ; 12401ae08745Sheppo if (nextp == portp) { 12411ae08745Sheppo prevp->nextp = portp->nextp; 12421ae08745Sheppo } 12431ae08745Sheppo if (portp == plistp->tailp) 12441ae08745Sheppo plistp->tailp = prevp; 12451ae08745Sheppo } 12461ae08745Sheppo } 12471ae08745Sheppo 12481ae08745Sheppo /* lookup a port in the list based on port_num */ 12491ae08745Sheppo static vgen_port_t * 12501ae08745Sheppo vgen_port_lookup(vgen_portlist_t *plistp, int port_num) 12511ae08745Sheppo { 12521ae08745Sheppo vgen_port_t *portp = NULL; 12531ae08745Sheppo 12541ae08745Sheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) { 12551ae08745Sheppo if (portp->port_num == port_num) { 12561ae08745Sheppo break; 12571ae08745Sheppo } 12581ae08745Sheppo } 12591ae08745Sheppo 12601ae08745Sheppo return (portp); 12611ae08745Sheppo } 12621ae08745Sheppo 12631ae08745Sheppo static void 12641ae08745Sheppo vgen_port_init(vgen_port_t *portp) 12651ae08745Sheppo { 1266c1c61f44Ssb155480 /* Add the port to the specified vlans */ 1267c1c61f44Ssb155480 vgen_vlan_add_ids(portp); 12681ae08745Sheppo 12697bd3a2e2SSriharsha Basavapatna /* Bring up the channel */ 12707bd3a2e2SSriharsha Basavapatna (void) vgen_ldc_init(portp->ldcp); 12711ae08745Sheppo } 12721ae08745Sheppo 12731ae08745Sheppo static void 12741ae08745Sheppo vgen_port_uninit(vgen_port_t *portp) 12751ae08745Sheppo { 12767bd3a2e2SSriharsha Basavapatna vgen_ldc_uninit(portp->ldcp); 1277c1c61f44Ssb155480 1278c1c61f44Ssb155480 /* remove the port from vlans it has been assigned to */ 1279c1c61f44Ssb155480 vgen_vlan_remove_ids(portp); 12801ae08745Sheppo } 12811ae08745Sheppo 1282f0ca1d9aSsb155480 /* 1283f0ca1d9aSsb155480 * Scan the machine description for this instance of vnet 1284f0ca1d9aSsb155480 * and read its properties. Called only from vgen_init(). 1285f0ca1d9aSsb155480 * Returns: 0 on success, 1 on failure. 1286f0ca1d9aSsb155480 */ 1287f0ca1d9aSsb155480 static int 1288f0ca1d9aSsb155480 vgen_read_mdprops(vgen_t *vgenp) 1289f0ca1d9aSsb155480 { 1290c1c61f44Ssb155480 vnet_t *vnetp = vgenp->vnetp; 1291f0ca1d9aSsb155480 md_t *mdp = NULL; 1292f0ca1d9aSsb155480 mde_cookie_t rootnode; 1293f0ca1d9aSsb155480 mde_cookie_t *listp = NULL; 1294f0ca1d9aSsb155480 uint64_t cfgh; 1295f0ca1d9aSsb155480 char *name; 1296f0ca1d9aSsb155480 int rv = 1; 1297f0ca1d9aSsb155480 int num_nodes = 0; 1298f0ca1d9aSsb155480 int num_devs = 0; 1299f0ca1d9aSsb155480 int listsz = 0; 1300f0ca1d9aSsb155480 int i; 1301f0ca1d9aSsb155480 1302f0ca1d9aSsb155480 if ((mdp = md_get_handle()) == NULL) { 1303f0ca1d9aSsb155480 return (rv); 1304f0ca1d9aSsb155480 } 1305f0ca1d9aSsb155480 1306f0ca1d9aSsb155480 num_nodes = md_node_count(mdp); 1307f0ca1d9aSsb155480 ASSERT(num_nodes > 0); 1308f0ca1d9aSsb155480 1309f0ca1d9aSsb155480 listsz = num_nodes * sizeof (mde_cookie_t); 1310f0ca1d9aSsb155480 listp = (mde_cookie_t *)kmem_zalloc(listsz, KM_SLEEP); 1311f0ca1d9aSsb155480 1312f0ca1d9aSsb155480 rootnode = md_root_node(mdp); 1313f0ca1d9aSsb155480 1314f0ca1d9aSsb155480 /* search for all "virtual_device" nodes */ 1315f0ca1d9aSsb155480 num_devs = md_scan_dag(mdp, rootnode, 1316f0ca1d9aSsb155480 md_find_name(mdp, vdev_propname), 1317f0ca1d9aSsb155480 md_find_name(mdp, "fwd"), listp); 1318f0ca1d9aSsb155480 if (num_devs <= 0) { 1319f0ca1d9aSsb155480 goto vgen_readmd_exit; 1320f0ca1d9aSsb155480 } 1321f0ca1d9aSsb155480 1322f0ca1d9aSsb155480 /* 1323f0ca1d9aSsb155480 * Now loop through the list of virtual-devices looking for 1324f0ca1d9aSsb155480 * devices with name "network" and for each such device compare 1325f0ca1d9aSsb155480 * its instance with what we have from the 'reg' property to 1326f0ca1d9aSsb155480 * find the right node in MD and then read all its properties. 1327f0ca1d9aSsb155480 */ 1328f0ca1d9aSsb155480 for (i = 0; i < num_devs; i++) { 1329f0ca1d9aSsb155480 1330f0ca1d9aSsb155480 if (md_get_prop_str(mdp, listp[i], "name", &name) != 0) { 1331f0ca1d9aSsb155480 goto vgen_readmd_exit; 1332f0ca1d9aSsb155480 } 1333f0ca1d9aSsb155480 1334f0ca1d9aSsb155480 /* is this a "network" device? */ 1335f0ca1d9aSsb155480 if (strcmp(name, vnet_propname) != 0) 1336f0ca1d9aSsb155480 continue; 1337f0ca1d9aSsb155480 1338f0ca1d9aSsb155480 if (md_get_prop_val(mdp, listp[i], "cfg-handle", &cfgh) != 0) { 1339f0ca1d9aSsb155480 goto vgen_readmd_exit; 1340f0ca1d9aSsb155480 } 1341f0ca1d9aSsb155480 1342f0ca1d9aSsb155480 /* is this the required instance of vnet? */ 1343678453a8Sspeer if (vgenp->regprop != cfgh) 1344f0ca1d9aSsb155480 continue; 1345f0ca1d9aSsb155480 13467b1f684aSSriharsha Basavapatna /* 13471107ea93SSriharsha Basavapatna * Read the 'linkprop' property to know if this vnet 13481107ea93SSriharsha Basavapatna * device should get physical link updates from vswitch. 13491107ea93SSriharsha Basavapatna */ 13501107ea93SSriharsha Basavapatna vgen_linkprop_read(vgenp, mdp, listp[i], 13511107ea93SSriharsha Basavapatna &vnetp->pls_update); 13521107ea93SSriharsha Basavapatna 13531107ea93SSriharsha Basavapatna /* 13547b1f684aSSriharsha Basavapatna * Read the mtu. Note that we set the mtu of vnet device within 13557b1f684aSSriharsha Basavapatna * this routine itself, after validating the range. 13567b1f684aSSriharsha Basavapatna */ 13577b1f684aSSriharsha Basavapatna vgen_mtu_read(vgenp, mdp, listp[i], &vnetp->mtu); 13587b1f684aSSriharsha Basavapatna if (vnetp->mtu < ETHERMTU || vnetp->mtu > VNET_MAX_MTU) { 13597b1f684aSSriharsha Basavapatna vnetp->mtu = ETHERMTU; 13607b1f684aSSriharsha Basavapatna } 13617b1f684aSSriharsha Basavapatna vgenp->max_frame_size = vnetp->mtu + 13627b1f684aSSriharsha Basavapatna sizeof (struct ether_header) + VLAN_TAGSZ; 13637b1f684aSSriharsha Basavapatna 13647b1f684aSSriharsha Basavapatna /* read priority ether types */ 1365f0ca1d9aSsb155480 vgen_read_pri_eth_types(vgenp, mdp, listp[i]); 1366c1c61f44Ssb155480 1367c1c61f44Ssb155480 /* read vlan id properties of this vnet instance */ 1368c1c61f44Ssb155480 vgen_vlan_read_ids(vgenp, VGEN_LOCAL, mdp, listp[i], 1369c1c61f44Ssb155480 &vnetp->pvid, &vnetp->vids, &vnetp->nvids, 1370c1c61f44Ssb155480 &vnetp->default_vlan_id); 1371c1c61f44Ssb155480 1372f0ca1d9aSsb155480 rv = 0; 1373f0ca1d9aSsb155480 break; 1374f0ca1d9aSsb155480 } 1375f0ca1d9aSsb155480 1376f0ca1d9aSsb155480 vgen_readmd_exit: 1377f0ca1d9aSsb155480 1378f0ca1d9aSsb155480 kmem_free(listp, listsz); 1379f0ca1d9aSsb155480 (void) md_fini_handle(mdp); 1380f0ca1d9aSsb155480 return (rv); 1381f0ca1d9aSsb155480 } 1382f0ca1d9aSsb155480 1383f0ca1d9aSsb155480 /* 1384c1c61f44Ssb155480 * Read vlan id properties of the given MD node. 1385c1c61f44Ssb155480 * Arguments: 1386c1c61f44Ssb155480 * arg: device argument(vnet device or a port) 1387c1c61f44Ssb155480 * type: type of arg; VGEN_LOCAL(vnet device) or VGEN_PEER(port) 1388c1c61f44Ssb155480 * mdp: machine description 1389c1c61f44Ssb155480 * node: md node cookie 1390c1c61f44Ssb155480 * 1391c1c61f44Ssb155480 * Returns: 1392c1c61f44Ssb155480 * pvidp: port-vlan-id of the node 1393c1c61f44Ssb155480 * vidspp: list of vlan-ids of the node 1394c1c61f44Ssb155480 * nvidsp: # of vlan-ids in the list 1395c1c61f44Ssb155480 * default_idp: default-vlan-id of the node(if node is vnet device) 1396c1c61f44Ssb155480 */ 1397c1c61f44Ssb155480 static void 1398c1c61f44Ssb155480 vgen_vlan_read_ids(void *arg, int type, md_t *mdp, mde_cookie_t node, 1399c1c61f44Ssb155480 uint16_t *pvidp, uint16_t **vidspp, uint16_t *nvidsp, 1400c1c61f44Ssb155480 uint16_t *default_idp) 1401c1c61f44Ssb155480 { 1402c1c61f44Ssb155480 vgen_t *vgenp; 1403c1c61f44Ssb155480 vnet_t *vnetp; 1404c1c61f44Ssb155480 vgen_port_t *portp; 1405c1c61f44Ssb155480 char *pvid_propname; 1406c1c61f44Ssb155480 char *vid_propname; 1407c1c61f44Ssb155480 uint_t nvids; 1408c1c61f44Ssb155480 uint32_t vids_size; 1409c1c61f44Ssb155480 int rv; 1410c1c61f44Ssb155480 int i; 1411c1c61f44Ssb155480 uint64_t *data; 1412c1c61f44Ssb155480 uint64_t val; 1413c1c61f44Ssb155480 int size; 1414c1c61f44Ssb155480 int inst; 1415c1c61f44Ssb155480 1416c1c61f44Ssb155480 if (type == VGEN_LOCAL) { 1417c1c61f44Ssb155480 1418c1c61f44Ssb155480 vgenp = (vgen_t *)arg; 1419c1c61f44Ssb155480 vnetp = vgenp->vnetp; 1420c1c61f44Ssb155480 pvid_propname = vgen_pvid_propname; 1421c1c61f44Ssb155480 vid_propname = vgen_vid_propname; 1422c1c61f44Ssb155480 inst = vnetp->instance; 1423c1c61f44Ssb155480 1424c1c61f44Ssb155480 } else if (type == VGEN_PEER) { 1425c1c61f44Ssb155480 1426c1c61f44Ssb155480 portp = (vgen_port_t *)arg; 1427c1c61f44Ssb155480 vgenp = portp->vgenp; 1428c1c61f44Ssb155480 vnetp = vgenp->vnetp; 1429c1c61f44Ssb155480 pvid_propname = port_pvid_propname; 1430c1c61f44Ssb155480 vid_propname = port_vid_propname; 1431c1c61f44Ssb155480 inst = portp->port_num; 1432c1c61f44Ssb155480 1433c1c61f44Ssb155480 } else { 1434c1c61f44Ssb155480 return; 1435c1c61f44Ssb155480 } 1436c1c61f44Ssb155480 1437c1c61f44Ssb155480 if (type == VGEN_LOCAL && default_idp != NULL) { 1438c1c61f44Ssb155480 rv = md_get_prop_val(mdp, node, vgen_dvid_propname, &val); 1439c1c61f44Ssb155480 if (rv != 0) { 1440c1c61f44Ssb155480 DWARN(vgenp, NULL, "prop(%s) not found", 1441c1c61f44Ssb155480 vgen_dvid_propname); 1442c1c61f44Ssb155480 1443c1c61f44Ssb155480 *default_idp = vnet_default_vlan_id; 1444c1c61f44Ssb155480 } else { 1445c1c61f44Ssb155480 *default_idp = val & 0xFFF; 1446c1c61f44Ssb155480 DBG2(vgenp, NULL, "%s(%d): (%d)\n", vgen_dvid_propname, 1447c1c61f44Ssb155480 inst, *default_idp); 1448c1c61f44Ssb155480 } 1449c1c61f44Ssb155480 } 1450c1c61f44Ssb155480 1451c1c61f44Ssb155480 rv = md_get_prop_val(mdp, node, pvid_propname, &val); 1452c1c61f44Ssb155480 if (rv != 0) { 1453c1c61f44Ssb155480 DWARN(vgenp, NULL, "prop(%s) not found", pvid_propname); 1454c1c61f44Ssb155480 *pvidp = vnet_default_vlan_id; 1455c1c61f44Ssb155480 } else { 1456c1c61f44Ssb155480 1457c1c61f44Ssb155480 *pvidp = val & 0xFFF; 1458c1c61f44Ssb155480 DBG2(vgenp, NULL, "%s(%d): (%d)\n", 1459c1c61f44Ssb155480 pvid_propname, inst, *pvidp); 1460c1c61f44Ssb155480 } 1461c1c61f44Ssb155480 1462c1c61f44Ssb155480 rv = md_get_prop_data(mdp, node, vid_propname, (uint8_t **)&data, 1463c1c61f44Ssb155480 &size); 1464c1c61f44Ssb155480 if (rv != 0) { 1465c1c61f44Ssb155480 DBG2(vgenp, NULL, "prop(%s) not found", vid_propname); 1466c1c61f44Ssb155480 size = 0; 1467c1c61f44Ssb155480 } else { 1468c1c61f44Ssb155480 size /= sizeof (uint64_t); 1469c1c61f44Ssb155480 } 1470c1c61f44Ssb155480 nvids = size; 1471c1c61f44Ssb155480 1472c1c61f44Ssb155480 if (nvids != 0) { 1473c1c61f44Ssb155480 DBG2(vgenp, NULL, "%s(%d): ", vid_propname, inst); 1474c1c61f44Ssb155480 vids_size = sizeof (uint16_t) * nvids; 1475c1c61f44Ssb155480 *vidspp = kmem_zalloc(vids_size, KM_SLEEP); 1476c1c61f44Ssb155480 for (i = 0; i < nvids; i++) { 1477c1c61f44Ssb155480 (*vidspp)[i] = data[i] & 0xFFFF; 1478c1c61f44Ssb155480 DBG2(vgenp, NULL, " %d ", (*vidspp)[i]); 1479c1c61f44Ssb155480 } 1480c1c61f44Ssb155480 DBG2(vgenp, NULL, "\n"); 1481c1c61f44Ssb155480 } 1482c1c61f44Ssb155480 1483c1c61f44Ssb155480 *nvidsp = nvids; 1484c1c61f44Ssb155480 } 1485c1c61f44Ssb155480 1486c1c61f44Ssb155480 /* 1487c1c61f44Ssb155480 * Create a vlan id hash table for the given port. 1488c1c61f44Ssb155480 */ 1489c1c61f44Ssb155480 static void 1490c1c61f44Ssb155480 vgen_vlan_create_hash(vgen_port_t *portp) 1491c1c61f44Ssb155480 { 1492c1c61f44Ssb155480 char hashname[MAXNAMELEN]; 1493c1c61f44Ssb155480 1494c1c61f44Ssb155480 (void) snprintf(hashname, MAXNAMELEN, "port%d-vlan-hash", 1495c1c61f44Ssb155480 portp->port_num); 1496c1c61f44Ssb155480 1497c1c61f44Ssb155480 portp->vlan_nchains = vgen_vlan_nchains; 1498c1c61f44Ssb155480 portp->vlan_hashp = mod_hash_create_idhash(hashname, 1499c1c61f44Ssb155480 portp->vlan_nchains, mod_hash_null_valdtor); 1500c1c61f44Ssb155480 } 1501c1c61f44Ssb155480 1502c1c61f44Ssb155480 /* 1503c1c61f44Ssb155480 * Destroy the vlan id hash table in the given port. 1504c1c61f44Ssb155480 */ 1505c1c61f44Ssb155480 static void 1506c1c61f44Ssb155480 vgen_vlan_destroy_hash(vgen_port_t *portp) 1507c1c61f44Ssb155480 { 1508c1c61f44Ssb155480 if (portp->vlan_hashp != NULL) { 1509c1c61f44Ssb155480 mod_hash_destroy_hash(portp->vlan_hashp); 1510c1c61f44Ssb155480 portp->vlan_hashp = NULL; 1511c1c61f44Ssb155480 portp->vlan_nchains = 0; 1512c1c61f44Ssb155480 } 1513c1c61f44Ssb155480 } 1514c1c61f44Ssb155480 1515c1c61f44Ssb155480 /* 1516c1c61f44Ssb155480 * Add a port to the vlans specified in its port properites. 1517c1c61f44Ssb155480 */ 1518c1c61f44Ssb155480 static void 1519c1c61f44Ssb155480 vgen_vlan_add_ids(vgen_port_t *portp) 1520c1c61f44Ssb155480 { 1521c1c61f44Ssb155480 int rv; 1522c1c61f44Ssb155480 int i; 1523c1c61f44Ssb155480 1524c1c61f44Ssb155480 rv = mod_hash_insert(portp->vlan_hashp, 1525c1c61f44Ssb155480 (mod_hash_key_t)VLAN_ID_KEY(portp->pvid), 1526c1c61f44Ssb155480 (mod_hash_val_t)B_TRUE); 1527c1c61f44Ssb155480 ASSERT(rv == 0); 1528c1c61f44Ssb155480 1529c1c61f44Ssb155480 for (i = 0; i < portp->nvids; i++) { 1530c1c61f44Ssb155480 rv = mod_hash_insert(portp->vlan_hashp, 1531c1c61f44Ssb155480 (mod_hash_key_t)VLAN_ID_KEY(portp->vids[i]), 1532c1c61f44Ssb155480 (mod_hash_val_t)B_TRUE); 1533c1c61f44Ssb155480 ASSERT(rv == 0); 1534c1c61f44Ssb155480 } 1535c1c61f44Ssb155480 } 1536c1c61f44Ssb155480 1537c1c61f44Ssb155480 /* 1538c1c61f44Ssb155480 * Remove a port from the vlans it has been assigned to. 1539c1c61f44Ssb155480 */ 1540c1c61f44Ssb155480 static void 1541c1c61f44Ssb155480 vgen_vlan_remove_ids(vgen_port_t *portp) 1542c1c61f44Ssb155480 { 1543c1c61f44Ssb155480 int rv; 1544c1c61f44Ssb155480 int i; 1545c1c61f44Ssb155480 mod_hash_val_t vp; 1546c1c61f44Ssb155480 1547c1c61f44Ssb155480 rv = mod_hash_remove(portp->vlan_hashp, 1548c1c61f44Ssb155480 (mod_hash_key_t)VLAN_ID_KEY(portp->pvid), 1549c1c61f44Ssb155480 (mod_hash_val_t *)&vp); 1550c1c61f44Ssb155480 ASSERT(rv == 0); 1551c1c61f44Ssb155480 1552c1c61f44Ssb155480 for (i = 0; i < portp->nvids; i++) { 1553c1c61f44Ssb155480 rv = mod_hash_remove(portp->vlan_hashp, 1554c1c61f44Ssb155480 (mod_hash_key_t)VLAN_ID_KEY(portp->vids[i]), 1555c1c61f44Ssb155480 (mod_hash_val_t *)&vp); 1556c1c61f44Ssb155480 ASSERT(rv == 0); 1557c1c61f44Ssb155480 } 1558c1c61f44Ssb155480 } 1559c1c61f44Ssb155480 1560c1c61f44Ssb155480 /* 1561c1c61f44Ssb155480 * Lookup the vlan id of the given tx frame. If it is a vlan-tagged frame, 1562c1c61f44Ssb155480 * then the vlan-id is available in the tag; otherwise, its vlan id is 1563c1c61f44Ssb155480 * implicitly obtained from the port-vlan-id of the vnet device. 1564c1c61f44Ssb155480 * The vlan id determined is returned in vidp. 1565c1c61f44Ssb155480 * Returns: B_TRUE if it is a tagged frame; B_FALSE if it is untagged. 1566c1c61f44Ssb155480 */ 1567c1c61f44Ssb155480 static boolean_t 1568c1c61f44Ssb155480 vgen_frame_lookup_vid(vnet_t *vnetp, struct ether_header *ehp, uint16_t *vidp) 1569c1c61f44Ssb155480 { 1570c1c61f44Ssb155480 struct ether_vlan_header *evhp; 1571c1c61f44Ssb155480 1572c1c61f44Ssb155480 /* If it's a tagged frame, get the vlan id from vlan header */ 1573c1c61f44Ssb155480 if (ehp->ether_type == ETHERTYPE_VLAN) { 1574c1c61f44Ssb155480 1575c1c61f44Ssb155480 evhp = (struct ether_vlan_header *)ehp; 1576c1c61f44Ssb155480 *vidp = VLAN_ID(ntohs(evhp->ether_tci)); 1577c1c61f44Ssb155480 return (B_TRUE); 1578c1c61f44Ssb155480 } 1579c1c61f44Ssb155480 1580c1c61f44Ssb155480 /* Untagged frame, vlan-id is the pvid of vnet device */ 1581c1c61f44Ssb155480 *vidp = vnetp->pvid; 1582c1c61f44Ssb155480 return (B_FALSE); 1583c1c61f44Ssb155480 } 1584c1c61f44Ssb155480 1585c1c61f44Ssb155480 /* 1586c1c61f44Ssb155480 * Find the given vlan id in the hash table. 1587c1c61f44Ssb155480 * Return: B_TRUE if the id is found; B_FALSE if not found. 1588c1c61f44Ssb155480 */ 1589c1c61f44Ssb155480 static boolean_t 1590c1c61f44Ssb155480 vgen_vlan_lookup(mod_hash_t *vlan_hashp, uint16_t vid) 1591c1c61f44Ssb155480 { 1592c1c61f44Ssb155480 int rv; 1593c1c61f44Ssb155480 mod_hash_val_t vp; 1594c1c61f44Ssb155480 1595c1c61f44Ssb155480 rv = mod_hash_find(vlan_hashp, VLAN_ID_KEY(vid), (mod_hash_val_t *)&vp); 1596c1c61f44Ssb155480 1597c1c61f44Ssb155480 if (rv != 0) 1598c1c61f44Ssb155480 return (B_FALSE); 1599c1c61f44Ssb155480 1600c1c61f44Ssb155480 return (B_TRUE); 1601c1c61f44Ssb155480 } 1602c1c61f44Ssb155480 1603c1c61f44Ssb155480 /* 1604f0ca1d9aSsb155480 * This function reads "priority-ether-types" property from md. This property 1605f0ca1d9aSsb155480 * is used to enable support for priority frames. Applications which need 1606f0ca1d9aSsb155480 * guaranteed and timely delivery of certain high priority frames to/from 1607f0ca1d9aSsb155480 * a vnet or vsw within ldoms, should configure this property by providing 1608f0ca1d9aSsb155480 * the ether type(s) for which the priority facility is needed. 1609f0ca1d9aSsb155480 * Normal data frames are delivered over a ldc channel using the descriptor 1610f0ca1d9aSsb155480 * ring mechanism which is constrained by factors such as descriptor ring size, 1611f0ca1d9aSsb155480 * the rate at which the ring is processed at the peer ldc end point, etc. 1612f0ca1d9aSsb155480 * The priority mechanism provides an Out-Of-Band path to send/receive frames 1613f0ca1d9aSsb155480 * as raw pkt data (VIO_PKT_DATA) messages over the channel, avoiding the 1614f0ca1d9aSsb155480 * descriptor ring path and enables a more reliable and timely delivery of 1615f0ca1d9aSsb155480 * frames to the peer. 1616f0ca1d9aSsb155480 */ 1617f0ca1d9aSsb155480 static void 1618f0ca1d9aSsb155480 vgen_read_pri_eth_types(vgen_t *vgenp, md_t *mdp, mde_cookie_t node) 1619f0ca1d9aSsb155480 { 1620f0ca1d9aSsb155480 int rv; 1621f0ca1d9aSsb155480 uint16_t *types; 1622f0ca1d9aSsb155480 uint64_t *data; 1623f0ca1d9aSsb155480 int size; 1624f0ca1d9aSsb155480 int i; 1625f0ca1d9aSsb155480 size_t mblk_sz; 1626f0ca1d9aSsb155480 1627f0ca1d9aSsb155480 rv = md_get_prop_data(mdp, node, pri_types_propname, 1628f0ca1d9aSsb155480 (uint8_t **)&data, &size); 1629f0ca1d9aSsb155480 if (rv != 0) { 1630f0ca1d9aSsb155480 /* 1631f0ca1d9aSsb155480 * Property may not exist if we are running pre-ldoms1.1 f/w. 1632f0ca1d9aSsb155480 * Check if 'vgen_pri_eth_type' has been set in that case. 1633f0ca1d9aSsb155480 */ 1634f0ca1d9aSsb155480 if (vgen_pri_eth_type != 0) { 1635f0ca1d9aSsb155480 size = sizeof (vgen_pri_eth_type); 1636f0ca1d9aSsb155480 data = &vgen_pri_eth_type; 1637f0ca1d9aSsb155480 } else { 1638678453a8Sspeer DBG2(vgenp, NULL, 1639f0ca1d9aSsb155480 "prop(%s) not found", pri_types_propname); 1640f0ca1d9aSsb155480 size = 0; 1641f0ca1d9aSsb155480 } 1642f0ca1d9aSsb155480 } 1643f0ca1d9aSsb155480 1644f0ca1d9aSsb155480 if (size == 0) { 1645f0ca1d9aSsb155480 vgenp->pri_num_types = 0; 1646f0ca1d9aSsb155480 return; 1647f0ca1d9aSsb155480 } 1648f0ca1d9aSsb155480 1649f0ca1d9aSsb155480 /* 1650f0ca1d9aSsb155480 * we have some priority-ether-types defined; 1651f0ca1d9aSsb155480 * allocate a table of these types and also 1652f0ca1d9aSsb155480 * allocate a pool of mblks to transmit these 1653f0ca1d9aSsb155480 * priority packets. 1654f0ca1d9aSsb155480 */ 1655f0ca1d9aSsb155480 size /= sizeof (uint64_t); 1656f0ca1d9aSsb155480 vgenp->pri_num_types = size; 1657f0ca1d9aSsb155480 vgenp->pri_types = kmem_zalloc(size * sizeof (uint16_t), KM_SLEEP); 1658f0ca1d9aSsb155480 for (i = 0, types = vgenp->pri_types; i < size; i++) { 1659f0ca1d9aSsb155480 types[i] = data[i] & 0xFFFF; 1660f0ca1d9aSsb155480 } 1661c1c61f44Ssb155480 mblk_sz = (VIO_PKT_DATA_HDRSIZE + vgenp->max_frame_size + 7) & ~7; 16627bd3a2e2SSriharsha Basavapatna (void) vio_create_mblks(vgen_pri_tx_nmblks, mblk_sz, NULL, 1663f0ca1d9aSsb155480 &vgenp->pri_tx_vmp); 1664f0ca1d9aSsb155480 } 1665f0ca1d9aSsb155480 16667b1f684aSSriharsha Basavapatna static void 16677b1f684aSSriharsha Basavapatna vgen_mtu_read(vgen_t *vgenp, md_t *mdp, mde_cookie_t node, uint32_t *mtu) 16687b1f684aSSriharsha Basavapatna { 16697b1f684aSSriharsha Basavapatna int rv; 16707b1f684aSSriharsha Basavapatna uint64_t val; 16717b1f684aSSriharsha Basavapatna char *mtu_propname; 16727b1f684aSSriharsha Basavapatna 16737b1f684aSSriharsha Basavapatna mtu_propname = vgen_mtu_propname; 16747b1f684aSSriharsha Basavapatna 16757b1f684aSSriharsha Basavapatna rv = md_get_prop_val(mdp, node, mtu_propname, &val); 16767b1f684aSSriharsha Basavapatna if (rv != 0) { 16777b1f684aSSriharsha Basavapatna DWARN(vgenp, NULL, "prop(%s) not found", mtu_propname); 16787b1f684aSSriharsha Basavapatna *mtu = vnet_ethermtu; 16797b1f684aSSriharsha Basavapatna } else { 16807b1f684aSSriharsha Basavapatna 16817b1f684aSSriharsha Basavapatna *mtu = val & 0xFFFF; 16827b1f684aSSriharsha Basavapatna DBG2(vgenp, NULL, "%s(%d): (%d)\n", mtu_propname, 16837b1f684aSSriharsha Basavapatna vgenp->instance, *mtu); 16847b1f684aSSriharsha Basavapatna } 16857b1f684aSSriharsha Basavapatna } 16867b1f684aSSriharsha Basavapatna 16871107ea93SSriharsha Basavapatna static void 16881107ea93SSriharsha Basavapatna vgen_linkprop_read(vgen_t *vgenp, md_t *mdp, mde_cookie_t node, 16891107ea93SSriharsha Basavapatna boolean_t *pls) 16901107ea93SSriharsha Basavapatna { 16911107ea93SSriharsha Basavapatna int rv; 16921107ea93SSriharsha Basavapatna uint64_t val; 16931107ea93SSriharsha Basavapatna char *linkpropname; 16941107ea93SSriharsha Basavapatna 16951107ea93SSriharsha Basavapatna linkpropname = vgen_linkprop_propname; 16961107ea93SSriharsha Basavapatna 16971107ea93SSriharsha Basavapatna rv = md_get_prop_val(mdp, node, linkpropname, &val); 16981107ea93SSriharsha Basavapatna if (rv != 0) { 16991107ea93SSriharsha Basavapatna DWARN(vgenp, NULL, "prop(%s) not found", linkpropname); 17001107ea93SSriharsha Basavapatna *pls = B_FALSE; 17011107ea93SSriharsha Basavapatna } else { 17021107ea93SSriharsha Basavapatna 17031107ea93SSriharsha Basavapatna *pls = (val & 0x1) ? B_TRUE : B_FALSE; 17041107ea93SSriharsha Basavapatna DBG2(vgenp, NULL, "%s(%d): (%d)\n", linkpropname, 17051107ea93SSriharsha Basavapatna vgenp->instance, *pls); 17061107ea93SSriharsha Basavapatna } 17071107ea93SSriharsha Basavapatna } 17081107ea93SSriharsha Basavapatna 17091ae08745Sheppo /* register with MD event generator */ 17101ae08745Sheppo static int 17111ae08745Sheppo vgen_mdeg_reg(vgen_t *vgenp) 17121ae08745Sheppo { 17131ae08745Sheppo mdeg_prop_spec_t *pspecp; 17141ae08745Sheppo mdeg_node_spec_t *parentp; 17151ae08745Sheppo uint_t templatesz; 17161ae08745Sheppo int rv; 1717c1c61f44Ssb155480 mdeg_handle_t dev_hdl = NULL; 1718c1c61f44Ssb155480 mdeg_handle_t port_hdl = NULL; 17191ae08745Sheppo 17201ae08745Sheppo templatesz = sizeof (vgen_prop_template); 17211ae08745Sheppo pspecp = kmem_zalloc(templatesz, KM_NOSLEEP); 17221ae08745Sheppo if (pspecp == NULL) { 17231ae08745Sheppo return (DDI_FAILURE); 17241ae08745Sheppo } 17251ae08745Sheppo parentp = kmem_zalloc(sizeof (mdeg_node_spec_t), KM_NOSLEEP); 17261ae08745Sheppo if (parentp == NULL) { 17271ae08745Sheppo kmem_free(pspecp, templatesz); 17281ae08745Sheppo return (DDI_FAILURE); 17291ae08745Sheppo } 17301ae08745Sheppo 17311ae08745Sheppo bcopy(vgen_prop_template, pspecp, templatesz); 17321ae08745Sheppo 17331ae08745Sheppo /* 17341ae08745Sheppo * NOTE: The instance here refers to the value of "reg" property and 17351ae08745Sheppo * not the dev_info instance (ddi_get_instance()) of vnet. 17361ae08745Sheppo */ 1737c1c61f44Ssb155480 VGEN_SET_MDEG_PROP_INST(pspecp, vgenp->regprop); 17381ae08745Sheppo 17391ae08745Sheppo parentp->namep = "virtual-device"; 17401ae08745Sheppo parentp->specp = pspecp; 17411ae08745Sheppo 17421ae08745Sheppo /* save parentp in vgen_t */ 17431ae08745Sheppo vgenp->mdeg_parentp = parentp; 17441ae08745Sheppo 1745c1c61f44Ssb155480 /* 1746c1c61f44Ssb155480 * Register an interest in 'virtual-device' nodes with a 1747c1c61f44Ssb155480 * 'name' property of 'network' 1748c1c61f44Ssb155480 */ 1749c1c61f44Ssb155480 rv = mdeg_register(parentp, &vdev_match, vgen_mdeg_cb, vgenp, &dev_hdl); 17501ae08745Sheppo if (rv != MDEG_SUCCESS) { 1751844e62a3Sraghuram DERR(vgenp, NULL, "mdeg_register failed\n"); 1752c1c61f44Ssb155480 goto mdeg_reg_fail; 1753c1c61f44Ssb155480 } 1754c1c61f44Ssb155480 1755c1c61f44Ssb155480 /* Register an interest in 'port' nodes */ 1756c1c61f44Ssb155480 rv = mdeg_register(parentp, &vport_match, vgen_mdeg_port_cb, vgenp, 1757c1c61f44Ssb155480 &port_hdl); 1758c1c61f44Ssb155480 if (rv != MDEG_SUCCESS) { 1759c1c61f44Ssb155480 DERR(vgenp, NULL, "mdeg_register failed\n"); 1760c1c61f44Ssb155480 goto mdeg_reg_fail; 1761c1c61f44Ssb155480 } 1762c1c61f44Ssb155480 1763c1c61f44Ssb155480 /* save mdeg handle in vgen_t */ 1764c1c61f44Ssb155480 vgenp->mdeg_dev_hdl = dev_hdl; 1765c1c61f44Ssb155480 vgenp->mdeg_port_hdl = port_hdl; 1766c1c61f44Ssb155480 1767c1c61f44Ssb155480 return (DDI_SUCCESS); 1768c1c61f44Ssb155480 1769c1c61f44Ssb155480 mdeg_reg_fail: 1770c1c61f44Ssb155480 if (dev_hdl != NULL) { 1771c1c61f44Ssb155480 (void) mdeg_unregister(dev_hdl); 1772c1c61f44Ssb155480 } 17731ae08745Sheppo KMEM_FREE(parentp); 17741ae08745Sheppo kmem_free(pspecp, templatesz); 17751ae08745Sheppo vgenp->mdeg_parentp = NULL; 17761ae08745Sheppo return (DDI_FAILURE); 17771ae08745Sheppo } 17781ae08745Sheppo 17791ae08745Sheppo /* unregister with MD event generator */ 17801ae08745Sheppo static void 17811ae08745Sheppo vgen_mdeg_unreg(vgen_t *vgenp) 17821ae08745Sheppo { 178363f531d1SSriharsha Basavapatna if (vgenp->mdeg_dev_hdl != NULL) { 1784c1c61f44Ssb155480 (void) mdeg_unregister(vgenp->mdeg_dev_hdl); 178563f531d1SSriharsha Basavapatna vgenp->mdeg_dev_hdl = NULL; 178663f531d1SSriharsha Basavapatna } 178763f531d1SSriharsha Basavapatna if (vgenp->mdeg_port_hdl != NULL) { 1788c1c61f44Ssb155480 (void) mdeg_unregister(vgenp->mdeg_port_hdl); 178963f531d1SSriharsha Basavapatna vgenp->mdeg_port_hdl = NULL; 179063f531d1SSriharsha Basavapatna } 179163f531d1SSriharsha Basavapatna 179263f531d1SSriharsha Basavapatna if (vgenp->mdeg_parentp != NULL) { 179363f531d1SSriharsha Basavapatna kmem_free(vgenp->mdeg_parentp->specp, 179463f531d1SSriharsha Basavapatna sizeof (vgen_prop_template)); 17951ae08745Sheppo KMEM_FREE(vgenp->mdeg_parentp); 17961ae08745Sheppo vgenp->mdeg_parentp = NULL; 179763f531d1SSriharsha Basavapatna } 17981ae08745Sheppo } 17991ae08745Sheppo 1800c1c61f44Ssb155480 /* mdeg callback function for the port node */ 18011ae08745Sheppo static int 1802c1c61f44Ssb155480 vgen_mdeg_port_cb(void *cb_argp, mdeg_result_t *resp) 18031ae08745Sheppo { 18041ae08745Sheppo int idx; 18051ae08745Sheppo int vsw_idx = -1; 18061ae08745Sheppo uint64_t val; 18071ae08745Sheppo vgen_t *vgenp; 18081ae08745Sheppo 18091ae08745Sheppo if ((resp == NULL) || (cb_argp == NULL)) { 18101ae08745Sheppo return (MDEG_FAILURE); 18111ae08745Sheppo } 18121ae08745Sheppo 18131ae08745Sheppo vgenp = (vgen_t *)cb_argp; 1814844e62a3Sraghuram DBG1(vgenp, NULL, "enter\n"); 18151ae08745Sheppo 18161ae08745Sheppo mutex_enter(&vgenp->lock); 18171ae08745Sheppo 1818844e62a3Sraghuram DBG1(vgenp, NULL, "ports: removed(%x), " 1819844e62a3Sraghuram "added(%x), updated(%x)\n", resp->removed.nelem, 1820844e62a3Sraghuram resp->added.nelem, resp->match_curr.nelem); 18211ae08745Sheppo 18221ae08745Sheppo for (idx = 0; idx < resp->removed.nelem; idx++) { 18231ae08745Sheppo (void) vgen_remove_port(vgenp, resp->removed.mdp, 18241ae08745Sheppo resp->removed.mdep[idx]); 18251ae08745Sheppo } 18261ae08745Sheppo 18271ae08745Sheppo if (vgenp->vsw_portp == NULL) { 18281ae08745Sheppo /* 18291ae08745Sheppo * find vsw_port and add it first, because other ports need 18301ae08745Sheppo * this when adding fdb entry (see vgen_port_init()). 18311ae08745Sheppo */ 18321ae08745Sheppo for (idx = 0; idx < resp->added.nelem; idx++) { 18331ae08745Sheppo if (!(md_get_prop_val(resp->added.mdp, 18341ae08745Sheppo resp->added.mdep[idx], swport_propname, &val))) { 18351ae08745Sheppo if (val == 0) { 18361ae08745Sheppo /* 18371ae08745Sheppo * This port is connected to the 1838c1c61f44Ssb155480 * vsw on service domain. 18391ae08745Sheppo */ 18401ae08745Sheppo vsw_idx = idx; 1841ca7ee4f9Szk194757 if (vgen_add_port(vgenp, 18421ae08745Sheppo resp->added.mdp, 1843ca7ee4f9Szk194757 resp->added.mdep[idx]) != 1844ca7ee4f9Szk194757 DDI_SUCCESS) { 1845ca7ee4f9Szk194757 cmn_err(CE_NOTE, "vnet%d Could " 1846ca7ee4f9Szk194757 "not initialize virtual " 1847ca7ee4f9Szk194757 "switch port.", 1848678453a8Sspeer vgenp->instance); 1849ca7ee4f9Szk194757 mutex_exit(&vgenp->lock); 1850ca7ee4f9Szk194757 return (MDEG_FAILURE); 1851ca7ee4f9Szk194757 } 18521ae08745Sheppo break; 18531ae08745Sheppo } 18541ae08745Sheppo } 18551ae08745Sheppo } 1856c198d18eSzk194757 if (vsw_idx == -1) { 1857844e62a3Sraghuram DWARN(vgenp, NULL, "can't find vsw_port\n"); 1858ca7ee4f9Szk194757 mutex_exit(&vgenp->lock); 18591ae08745Sheppo return (MDEG_FAILURE); 18601ae08745Sheppo } 18611ae08745Sheppo } 18621ae08745Sheppo 18631ae08745Sheppo for (idx = 0; idx < resp->added.nelem; idx++) { 18641ae08745Sheppo if ((vsw_idx != -1) && (vsw_idx == idx)) /* skip vsw_port */ 18651ae08745Sheppo continue; 1866ca7ee4f9Szk194757 1867ca7ee4f9Szk194757 /* If this port can't be added just skip it. */ 18681ae08745Sheppo (void) vgen_add_port(vgenp, resp->added.mdp, 18691ae08745Sheppo resp->added.mdep[idx]); 18701ae08745Sheppo } 18711ae08745Sheppo 18721ae08745Sheppo for (idx = 0; idx < resp->match_curr.nelem; idx++) { 18731ae08745Sheppo (void) vgen_update_port(vgenp, resp->match_curr.mdp, 18741ae08745Sheppo resp->match_curr.mdep[idx], 18751ae08745Sheppo resp->match_prev.mdp, 18761ae08745Sheppo resp->match_prev.mdep[idx]); 18771ae08745Sheppo } 18781ae08745Sheppo 18791ae08745Sheppo mutex_exit(&vgenp->lock); 1880844e62a3Sraghuram DBG1(vgenp, NULL, "exit\n"); 18811ae08745Sheppo return (MDEG_SUCCESS); 18821ae08745Sheppo } 18831ae08745Sheppo 1884c1c61f44Ssb155480 /* mdeg callback function for the vnet node */ 1885c1c61f44Ssb155480 static int 1886c1c61f44Ssb155480 vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp) 1887c1c61f44Ssb155480 { 1888c1c61f44Ssb155480 vgen_t *vgenp; 1889c1c61f44Ssb155480 vnet_t *vnetp; 1890c1c61f44Ssb155480 md_t *mdp; 1891c1c61f44Ssb155480 mde_cookie_t node; 1892c1c61f44Ssb155480 uint64_t inst; 1893c1c61f44Ssb155480 char *node_name = NULL; 1894c1c61f44Ssb155480 1895c1c61f44Ssb155480 if ((resp == NULL) || (cb_argp == NULL)) { 1896c1c61f44Ssb155480 return (MDEG_FAILURE); 1897c1c61f44Ssb155480 } 1898c1c61f44Ssb155480 1899c1c61f44Ssb155480 vgenp = (vgen_t *)cb_argp; 1900c1c61f44Ssb155480 vnetp = vgenp->vnetp; 1901c1c61f44Ssb155480 190252bca946SWENTAO YANG DBG1(vgenp, NULL, "added %d : removed %d : curr matched %d" 1903c1c61f44Ssb155480 " : prev matched %d", resp->added.nelem, resp->removed.nelem, 1904c1c61f44Ssb155480 resp->match_curr.nelem, resp->match_prev.nelem); 1905c1c61f44Ssb155480 1906c1c61f44Ssb155480 mutex_enter(&vgenp->lock); 1907c1c61f44Ssb155480 1908c1c61f44Ssb155480 /* 1909c1c61f44Ssb155480 * We get an initial callback for this node as 'added' after 1910c1c61f44Ssb155480 * registering with mdeg. Note that we would have already gathered 1911c1c61f44Ssb155480 * information about this vnet node by walking MD earlier during attach 1912c1c61f44Ssb155480 * (in vgen_read_mdprops()). So, there is a window where the properties 1913c1c61f44Ssb155480 * of this node might have changed when we get this initial 'added' 1914c1c61f44Ssb155480 * callback. We handle this as if an update occured and invoke the same 1915c1c61f44Ssb155480 * function which handles updates to the properties of this vnet-node 1916c1c61f44Ssb155480 * if any. A non-zero 'match' value indicates that the MD has been 1917c1c61f44Ssb155480 * updated and that a 'network' node is present which may or may not 1918c1c61f44Ssb155480 * have been updated. It is up to the clients to examine their own 1919c1c61f44Ssb155480 * nodes and determine if they have changed. 1920c1c61f44Ssb155480 */ 1921c1c61f44Ssb155480 if (resp->added.nelem != 0) { 1922c1c61f44Ssb155480 1923c1c61f44Ssb155480 if (resp->added.nelem != 1) { 1924c1c61f44Ssb155480 cmn_err(CE_NOTE, "!vnet%d: number of nodes added " 1925c1c61f44Ssb155480 "invalid: %d\n", vnetp->instance, 1926c1c61f44Ssb155480 resp->added.nelem); 1927c1c61f44Ssb155480 goto vgen_mdeg_cb_err; 1928c1c61f44Ssb155480 } 1929c1c61f44Ssb155480 1930c1c61f44Ssb155480 mdp = resp->added.mdp; 1931c1c61f44Ssb155480 node = resp->added.mdep[0]; 1932c1c61f44Ssb155480 1933c1c61f44Ssb155480 } else if (resp->match_curr.nelem != 0) { 1934c1c61f44Ssb155480 1935c1c61f44Ssb155480 if (resp->match_curr.nelem != 1) { 1936c1c61f44Ssb155480 cmn_err(CE_NOTE, "!vnet%d: number of nodes updated " 1937c1c61f44Ssb155480 "invalid: %d\n", vnetp->instance, 1938c1c61f44Ssb155480 resp->match_curr.nelem); 1939c1c61f44Ssb155480 goto vgen_mdeg_cb_err; 1940c1c61f44Ssb155480 } 1941c1c61f44Ssb155480 1942c1c61f44Ssb155480 mdp = resp->match_curr.mdp; 1943c1c61f44Ssb155480 node = resp->match_curr.mdep[0]; 1944c1c61f44Ssb155480 1945c1c61f44Ssb155480 } else { 1946c1c61f44Ssb155480 goto vgen_mdeg_cb_err; 1947c1c61f44Ssb155480 } 1948c1c61f44Ssb155480 1949c1c61f44Ssb155480 /* Validate name and instance */ 1950c1c61f44Ssb155480 if (md_get_prop_str(mdp, node, "name", &node_name) != 0) { 1951c1c61f44Ssb155480 DERR(vgenp, NULL, "unable to get node name\n"); 1952c1c61f44Ssb155480 goto vgen_mdeg_cb_err; 1953c1c61f44Ssb155480 } 1954c1c61f44Ssb155480 1955c1c61f44Ssb155480 /* is this a virtual-network device? */ 1956c1c61f44Ssb155480 if (strcmp(node_name, vnet_propname) != 0) { 1957c1c61f44Ssb155480 DERR(vgenp, NULL, "%s: Invalid node name: %s\n", node_name); 1958c1c61f44Ssb155480 goto vgen_mdeg_cb_err; 1959c1c61f44Ssb155480 } 1960c1c61f44Ssb155480 1961c1c61f44Ssb155480 if (md_get_prop_val(mdp, node, "cfg-handle", &inst)) { 1962c1c61f44Ssb155480 DERR(vgenp, NULL, "prop(cfg-handle) not found\n"); 1963c1c61f44Ssb155480 goto vgen_mdeg_cb_err; 1964c1c61f44Ssb155480 } 1965c1c61f44Ssb155480 1966678453a8Sspeer /* is this the right instance of vnet? */ 1967c1c61f44Ssb155480 if (inst != vgenp->regprop) { 1968c1c61f44Ssb155480 DERR(vgenp, NULL, "Invalid cfg-handle: %lx\n", inst); 1969c1c61f44Ssb155480 goto vgen_mdeg_cb_err; 1970c1c61f44Ssb155480 } 1971c1c61f44Ssb155480 1972c1c61f44Ssb155480 vgen_update_md_prop(vgenp, mdp, node); 1973c1c61f44Ssb155480 1974c1c61f44Ssb155480 mutex_exit(&vgenp->lock); 1975c1c61f44Ssb155480 return (MDEG_SUCCESS); 1976c1c61f44Ssb155480 1977c1c61f44Ssb155480 vgen_mdeg_cb_err: 1978c1c61f44Ssb155480 mutex_exit(&vgenp->lock); 1979c1c61f44Ssb155480 return (MDEG_FAILURE); 1980c1c61f44Ssb155480 } 1981c1c61f44Ssb155480 1982c1c61f44Ssb155480 /* 1983c1c61f44Ssb155480 * Check to see if the relevant properties in the specified node have 1984c1c61f44Ssb155480 * changed, and if so take the appropriate action. 1985c1c61f44Ssb155480 */ 1986c1c61f44Ssb155480 static void 1987c1c61f44Ssb155480 vgen_update_md_prop(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex) 1988c1c61f44Ssb155480 { 1989c1c61f44Ssb155480 uint16_t pvid; 1990c1c61f44Ssb155480 uint16_t *vids; 1991c1c61f44Ssb155480 uint16_t nvids; 1992c1c61f44Ssb155480 vnet_t *vnetp = vgenp->vnetp; 19937b1f684aSSriharsha Basavapatna uint32_t mtu; 19941107ea93SSriharsha Basavapatna boolean_t pls_update; 19957b1f684aSSriharsha Basavapatna enum { MD_init = 0x1, 19967b1f684aSSriharsha Basavapatna MD_vlans = 0x2, 19971107ea93SSriharsha Basavapatna MD_mtu = 0x4, 19981107ea93SSriharsha Basavapatna MD_pls = 0x8 } updated; 19997b1f684aSSriharsha Basavapatna int rv; 20007b1f684aSSriharsha Basavapatna 20017b1f684aSSriharsha Basavapatna updated = MD_init; 2002c1c61f44Ssb155480 2003c1c61f44Ssb155480 /* Read the vlan ids */ 2004c1c61f44Ssb155480 vgen_vlan_read_ids(vgenp, VGEN_LOCAL, mdp, mdex, &pvid, &vids, 2005c1c61f44Ssb155480 &nvids, NULL); 2006c1c61f44Ssb155480 2007c1c61f44Ssb155480 /* Determine if there are any vlan id updates */ 2008c1c61f44Ssb155480 if ((pvid != vnetp->pvid) || /* pvid changed? */ 2009c1c61f44Ssb155480 (nvids != vnetp->nvids) || /* # of vids changed? */ 2010c1c61f44Ssb155480 ((nvids != 0) && (vnetp->nvids != 0) && /* vids changed? */ 2011c1c61f44Ssb155480 bcmp(vids, vnetp->vids, sizeof (uint16_t) * nvids))) { 20127b1f684aSSriharsha Basavapatna updated |= MD_vlans; 2013c1c61f44Ssb155480 } 2014c1c61f44Ssb155480 20157b1f684aSSriharsha Basavapatna /* Read mtu */ 20167b1f684aSSriharsha Basavapatna vgen_mtu_read(vgenp, mdp, mdex, &mtu); 20177b1f684aSSriharsha Basavapatna if (mtu != vnetp->mtu) { 20187b1f684aSSriharsha Basavapatna if (mtu >= ETHERMTU && mtu <= VNET_MAX_MTU) { 20197b1f684aSSriharsha Basavapatna updated |= MD_mtu; 20207b1f684aSSriharsha Basavapatna } else { 20217b1f684aSSriharsha Basavapatna cmn_err(CE_NOTE, "!vnet%d: Unable to process mtu update" 20227b1f684aSSriharsha Basavapatna " as the specified value:%d is invalid\n", 20237b1f684aSSriharsha Basavapatna vnetp->instance, mtu); 2024c1c61f44Ssb155480 } 2025c1c61f44Ssb155480 } 2026c1c61f44Ssb155480 20271107ea93SSriharsha Basavapatna /* 20281107ea93SSriharsha Basavapatna * Read the 'linkprop' property. 20291107ea93SSriharsha Basavapatna */ 20301107ea93SSriharsha Basavapatna vgen_linkprop_read(vgenp, mdp, mdex, &pls_update); 20311107ea93SSriharsha Basavapatna if (pls_update != vnetp->pls_update) { 20321107ea93SSriharsha Basavapatna updated |= MD_pls; 20331107ea93SSriharsha Basavapatna } 20341107ea93SSriharsha Basavapatna 20357b1f684aSSriharsha Basavapatna /* Now process the updated props */ 20367b1f684aSSriharsha Basavapatna 20377b1f684aSSriharsha Basavapatna if (updated & MD_vlans) { 20387b1f684aSSriharsha Basavapatna 2039c1c61f44Ssb155480 /* save the new vlan ids */ 2040c1c61f44Ssb155480 vnetp->pvid = pvid; 2041c1c61f44Ssb155480 if (vnetp->nvids != 0) { 20427b1f684aSSriharsha Basavapatna kmem_free(vnetp->vids, 20437b1f684aSSriharsha Basavapatna sizeof (uint16_t) * vnetp->nvids); 2044c1c61f44Ssb155480 vnetp->nvids = 0; 2045c1c61f44Ssb155480 } 2046c1c61f44Ssb155480 if (nvids != 0) { 2047c1c61f44Ssb155480 vnetp->nvids = nvids; 2048c1c61f44Ssb155480 vnetp->vids = vids; 2049c1c61f44Ssb155480 } 2050c1c61f44Ssb155480 2051c1c61f44Ssb155480 /* reset vlan-unaware peers (ver < 1.3) and restart handshake */ 2052c1c61f44Ssb155480 vgen_reset_vlan_unaware_ports(vgenp); 20537b1f684aSSriharsha Basavapatna 20547b1f684aSSriharsha Basavapatna } else { 20557b1f684aSSriharsha Basavapatna 20567b1f684aSSriharsha Basavapatna if (nvids != 0) { 20577b1f684aSSriharsha Basavapatna kmem_free(vids, sizeof (uint16_t) * nvids); 20587b1f684aSSriharsha Basavapatna } 20597b1f684aSSriharsha Basavapatna } 20607b1f684aSSriharsha Basavapatna 20617b1f684aSSriharsha Basavapatna if (updated & MD_mtu) { 20627b1f684aSSriharsha Basavapatna 20637b1f684aSSriharsha Basavapatna DBG2(vgenp, NULL, "curr_mtu(%d) new_mtu(%d)\n", 20647b1f684aSSriharsha Basavapatna vnetp->mtu, mtu); 20657b1f684aSSriharsha Basavapatna 20667b1f684aSSriharsha Basavapatna rv = vnet_mtu_update(vnetp, mtu); 20677b1f684aSSriharsha Basavapatna if (rv == 0) { 20687b1f684aSSriharsha Basavapatna vgenp->max_frame_size = mtu + 20697b1f684aSSriharsha Basavapatna sizeof (struct ether_header) + VLAN_TAGSZ; 20707b1f684aSSriharsha Basavapatna } 20717b1f684aSSriharsha Basavapatna } 20721107ea93SSriharsha Basavapatna 20731107ea93SSriharsha Basavapatna if (updated & MD_pls) { 20741107ea93SSriharsha Basavapatna /* enable/disable physical link state updates */ 20751107ea93SSriharsha Basavapatna vnetp->pls_update = pls_update; 20766d6de4eeSWENTAO YANG mutex_exit(&vgenp->lock); 20771107ea93SSriharsha Basavapatna 20781107ea93SSriharsha Basavapatna /* reset vsw-port to re-negotiate with the updated prop. */ 20791107ea93SSriharsha Basavapatna vgen_reset_vsw_port(vgenp); 20806d6de4eeSWENTAO YANG 20816d6de4eeSWENTAO YANG mutex_enter(&vgenp->lock); 20821107ea93SSriharsha Basavapatna } 2083c1c61f44Ssb155480 } 2084c1c61f44Ssb155480 20851ae08745Sheppo /* add a new port to the device */ 20861ae08745Sheppo static int 20871ae08745Sheppo vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex) 20881ae08745Sheppo { 2089c1c61f44Ssb155480 vgen_port_t *portp; 2090c1c61f44Ssb155480 int rv; 2091c1c61f44Ssb155480 2092c1c61f44Ssb155480 portp = kmem_zalloc(sizeof (vgen_port_t), KM_SLEEP); 2093c1c61f44Ssb155480 2094c1c61f44Ssb155480 rv = vgen_port_read_props(portp, vgenp, mdp, mdex); 2095c1c61f44Ssb155480 if (rv != DDI_SUCCESS) { 2096c1c61f44Ssb155480 KMEM_FREE(portp); 2097c1c61f44Ssb155480 return (DDI_FAILURE); 2098c1c61f44Ssb155480 } 2099c1c61f44Ssb155480 2100c1c61f44Ssb155480 rv = vgen_port_attach(portp); 2101c1c61f44Ssb155480 if (rv != DDI_SUCCESS) { 2102c1c61f44Ssb155480 return (DDI_FAILURE); 2103c1c61f44Ssb155480 } 2104c1c61f44Ssb155480 2105c1c61f44Ssb155480 return (DDI_SUCCESS); 2106c1c61f44Ssb155480 } 2107c1c61f44Ssb155480 2108c1c61f44Ssb155480 /* read properties of the port from its md node */ 2109c1c61f44Ssb155480 static int 2110c1c61f44Ssb155480 vgen_port_read_props(vgen_port_t *portp, vgen_t *vgenp, md_t *mdp, 2111c1c61f44Ssb155480 mde_cookie_t mdex) 2112c1c61f44Ssb155480 { 21131ae08745Sheppo uint64_t port_num; 21141ae08745Sheppo uint64_t *ldc_ids; 21151ae08745Sheppo uint64_t macaddr; 21161ae08745Sheppo uint64_t val; 21171ae08745Sheppo int num_ldcs; 21181ae08745Sheppo int i; 21191ae08745Sheppo int addrsz; 21201ae08745Sheppo int num_nodes = 0; 21211ae08745Sheppo int listsz = 0; 21221ae08745Sheppo mde_cookie_t *listp = NULL; 21231ae08745Sheppo uint8_t *addrp; 21241ae08745Sheppo struct ether_addr ea; 21251ae08745Sheppo 21261ae08745Sheppo /* read "id" property to get the port number */ 21271ae08745Sheppo if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) { 2128844e62a3Sraghuram DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname); 21291ae08745Sheppo return (DDI_FAILURE); 21301ae08745Sheppo } 21311ae08745Sheppo 21321ae08745Sheppo /* 21331ae08745Sheppo * Find the channel endpoint node(s) under this port node. 21341ae08745Sheppo */ 21351ae08745Sheppo if ((num_nodes = md_node_count(mdp)) <= 0) { 2136844e62a3Sraghuram DWARN(vgenp, NULL, "invalid number of nodes found (%d)", 2137844e62a3Sraghuram num_nodes); 21381ae08745Sheppo return (DDI_FAILURE); 21391ae08745Sheppo } 21401ae08745Sheppo 21411ae08745Sheppo /* allocate space for node list */ 21421ae08745Sheppo listsz = num_nodes * sizeof (mde_cookie_t); 21431ae08745Sheppo listp = kmem_zalloc(listsz, KM_NOSLEEP); 21441ae08745Sheppo if (listp == NULL) 21451ae08745Sheppo return (DDI_FAILURE); 21461ae08745Sheppo 21471ae08745Sheppo num_ldcs = md_scan_dag(mdp, mdex, 21481ae08745Sheppo md_find_name(mdp, channel_propname), 21491ae08745Sheppo md_find_name(mdp, "fwd"), listp); 21501ae08745Sheppo 21511ae08745Sheppo if (num_ldcs <= 0) { 2152844e62a3Sraghuram DWARN(vgenp, NULL, "can't find %s nodes", channel_propname); 21531ae08745Sheppo kmem_free(listp, listsz); 21541ae08745Sheppo return (DDI_FAILURE); 21551ae08745Sheppo } 21561ae08745Sheppo 21577bd3a2e2SSriharsha Basavapatna if (num_ldcs > 1) { 21587bd3a2e2SSriharsha Basavapatna DWARN(vgenp, NULL, "Port %d: Number of channels %d > 1\n", 21597bd3a2e2SSriharsha Basavapatna port_num, num_ldcs); 21607bd3a2e2SSriharsha Basavapatna } 21611ae08745Sheppo 21621ae08745Sheppo ldc_ids = kmem_zalloc(num_ldcs * sizeof (uint64_t), KM_NOSLEEP); 21631ae08745Sheppo if (ldc_ids == NULL) { 21641ae08745Sheppo kmem_free(listp, listsz); 21651ae08745Sheppo return (DDI_FAILURE); 21661ae08745Sheppo } 21671ae08745Sheppo 21681ae08745Sheppo for (i = 0; i < num_ldcs; i++) { 21691ae08745Sheppo /* read channel ids */ 21701ae08745Sheppo if (md_get_prop_val(mdp, listp[i], id_propname, &ldc_ids[i])) { 2171844e62a3Sraghuram DWARN(vgenp, NULL, "prop(%s) not found\n", 2172844e62a3Sraghuram id_propname); 21731ae08745Sheppo kmem_free(listp, listsz); 21741ae08745Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 21751ae08745Sheppo return (DDI_FAILURE); 21761ae08745Sheppo } 2177844e62a3Sraghuram DBG2(vgenp, NULL, "ldc_id 0x%llx", ldc_ids[i]); 21781ae08745Sheppo } 21791ae08745Sheppo 21801ae08745Sheppo kmem_free(listp, listsz); 21811ae08745Sheppo 21821ae08745Sheppo if (md_get_prop_data(mdp, mdex, rmacaddr_propname, &addrp, 21831ae08745Sheppo &addrsz)) { 2184844e62a3Sraghuram DWARN(vgenp, NULL, "prop(%s) not found\n", rmacaddr_propname); 21851ae08745Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 21861ae08745Sheppo return (DDI_FAILURE); 21871ae08745Sheppo } 21881ae08745Sheppo 21891ae08745Sheppo if (addrsz < ETHERADDRL) { 2190844e62a3Sraghuram DWARN(vgenp, NULL, "invalid address size (%d)\n", addrsz); 21911ae08745Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 21921ae08745Sheppo return (DDI_FAILURE); 21931ae08745Sheppo } 21941ae08745Sheppo 21951ae08745Sheppo macaddr = *((uint64_t *)addrp); 21961ae08745Sheppo 2197844e62a3Sraghuram DBG2(vgenp, NULL, "remote mac address 0x%llx\n", macaddr); 21981ae08745Sheppo 21991ae08745Sheppo for (i = ETHERADDRL - 1; i >= 0; i--) { 22001ae08745Sheppo ea.ether_addr_octet[i] = macaddr & 0xFF; 22011ae08745Sheppo macaddr >>= 8; 22021ae08745Sheppo } 22031ae08745Sheppo 22041ae08745Sheppo if (!(md_get_prop_val(mdp, mdex, swport_propname, &val))) { 22051ae08745Sheppo if (val == 0) { 22061107ea93SSriharsha Basavapatna /* This port is connected to the vswitch */ 22071107ea93SSriharsha Basavapatna portp->is_vsw_port = B_TRUE; 22081107ea93SSriharsha Basavapatna } else { 22091107ea93SSriharsha Basavapatna portp->is_vsw_port = B_FALSE; 22101ae08745Sheppo } 22111ae08745Sheppo } 2212c1c61f44Ssb155480 2213c1c61f44Ssb155480 /* now update all properties into the port */ 2214c1c61f44Ssb155480 portp->vgenp = vgenp; 2215c1c61f44Ssb155480 portp->port_num = port_num; 2216c1c61f44Ssb155480 ether_copy(&ea, &portp->macaddr); 2217c1c61f44Ssb155480 portp->ldc_ids = kmem_zalloc(sizeof (uint64_t) * num_ldcs, KM_SLEEP); 2218c1c61f44Ssb155480 bcopy(ldc_ids, portp->ldc_ids, sizeof (uint64_t) * num_ldcs); 2219c1c61f44Ssb155480 portp->num_ldcs = num_ldcs; 2220c1c61f44Ssb155480 2221c1c61f44Ssb155480 /* read vlan id properties of this port node */ 2222c1c61f44Ssb155480 vgen_vlan_read_ids(portp, VGEN_PEER, mdp, mdex, &portp->pvid, 2223c1c61f44Ssb155480 &portp->vids, &portp->nvids, NULL); 22241ae08745Sheppo 22251ae08745Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 22261ae08745Sheppo 2227c1c61f44Ssb155480 return (DDI_SUCCESS); 22281ae08745Sheppo } 22291ae08745Sheppo 22301ae08745Sheppo /* remove a port from the device */ 22311ae08745Sheppo static int 22321ae08745Sheppo vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex) 22331ae08745Sheppo { 22341ae08745Sheppo uint64_t port_num; 22351ae08745Sheppo vgen_port_t *portp; 22361ae08745Sheppo vgen_portlist_t *plistp; 22371ae08745Sheppo 22381ae08745Sheppo /* read "id" property to get the port number */ 22391ae08745Sheppo if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) { 2240844e62a3Sraghuram DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname); 22411ae08745Sheppo return (DDI_FAILURE); 22421ae08745Sheppo } 22431ae08745Sheppo 22441ae08745Sheppo plistp = &(vgenp->vgenports); 22451ae08745Sheppo 22461ae08745Sheppo WRITE_ENTER(&plistp->rwlock); 22471ae08745Sheppo portp = vgen_port_lookup(plistp, (int)port_num); 22481ae08745Sheppo if (portp == NULL) { 2249844e62a3Sraghuram DWARN(vgenp, NULL, "can't find port(%lx)\n", port_num); 22501ae08745Sheppo RW_EXIT(&plistp->rwlock); 22511ae08745Sheppo return (DDI_FAILURE); 22521ae08745Sheppo } 22531ae08745Sheppo 22541ae08745Sheppo vgen_port_detach_mdeg(portp); 22551ae08745Sheppo RW_EXIT(&plistp->rwlock); 22561ae08745Sheppo 22571ae08745Sheppo return (DDI_SUCCESS); 22581ae08745Sheppo } 22591ae08745Sheppo 22601ae08745Sheppo /* attach a port to the device based on mdeg data */ 22611ae08745Sheppo static int 2262c1c61f44Ssb155480 vgen_port_attach(vgen_port_t *portp) 22631ae08745Sheppo { 2264c1c61f44Ssb155480 vgen_portlist_t *plistp; 2265c1c61f44Ssb155480 vgen_t *vgenp; 2266c1c61f44Ssb155480 uint64_t *ldcids; 2267678453a8Sspeer mac_register_t *macp; 2268678453a8Sspeer vio_net_res_type_t type; 2269678453a8Sspeer int rv; 22701ae08745Sheppo 2271c1c61f44Ssb155480 ASSERT(portp != NULL); 2272c1c61f44Ssb155480 vgenp = portp->vgenp; 2273c1c61f44Ssb155480 ldcids = portp->ldc_ids; 22741ae08745Sheppo 22757bd3a2e2SSriharsha Basavapatna DBG2(vgenp, NULL, "port_num(%d), ldcid(%lx)\n", 22767bd3a2e2SSriharsha Basavapatna portp->port_num, ldcids[0]); 22771ae08745Sheppo 2278678453a8Sspeer mutex_init(&portp->lock, NULL, MUTEX_DRIVER, NULL); 22791ae08745Sheppo 22807bd3a2e2SSriharsha Basavapatna /* 22817bd3a2e2SSriharsha Basavapatna * attach the channel under the port using its channel id; 22827bd3a2e2SSriharsha Basavapatna * note that we only support one channel per port for now. 22837bd3a2e2SSriharsha Basavapatna */ 22847bd3a2e2SSriharsha Basavapatna if (vgen_ldc_attach(portp, ldcids[0]) == DDI_FAILURE) { 2285ca7ee4f9Szk194757 vgen_port_detach(portp); 2286ca7ee4f9Szk194757 return (DDI_FAILURE); 2287ca7ee4f9Szk194757 } 22881ae08745Sheppo 2289c1c61f44Ssb155480 /* create vlan id hash table */ 2290c1c61f44Ssb155480 vgen_vlan_create_hash(portp); 2291c1c61f44Ssb155480 22921107ea93SSriharsha Basavapatna if (portp->is_vsw_port == B_TRUE) { 2293678453a8Sspeer /* This port is connected to the switch port */ 2294678453a8Sspeer (void) atomic_swap_32(&portp->use_vsw_port, B_FALSE); 2295678453a8Sspeer type = VIO_NET_RES_LDC_SERVICE; 2296678453a8Sspeer } else { 2297678453a8Sspeer (void) atomic_swap_32(&portp->use_vsw_port, B_TRUE); 2298678453a8Sspeer type = VIO_NET_RES_LDC_GUEST; 2299678453a8Sspeer } 2300678453a8Sspeer 2301678453a8Sspeer if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 2302678453a8Sspeer vgen_port_detach(portp); 2303678453a8Sspeer return (DDI_FAILURE); 2304678453a8Sspeer } 2305678453a8Sspeer macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 2306678453a8Sspeer macp->m_driver = portp; 2307678453a8Sspeer macp->m_dip = vgenp->vnetdip; 2308678453a8Sspeer macp->m_src_addr = (uint8_t *)&(vgenp->macaddr); 2309678453a8Sspeer macp->m_callbacks = &vgen_m_callbacks; 2310678453a8Sspeer macp->m_min_sdu = 0; 2311678453a8Sspeer macp->m_max_sdu = ETHERMTU; 2312678453a8Sspeer 2313678453a8Sspeer mutex_enter(&portp->lock); 2314678453a8Sspeer rv = vio_net_resource_reg(macp, type, vgenp->macaddr, 2315678453a8Sspeer portp->macaddr, &portp->vhp, &portp->vcb); 2316678453a8Sspeer mutex_exit(&portp->lock); 2317678453a8Sspeer mac_free(macp); 2318678453a8Sspeer 2319678453a8Sspeer if (rv == 0) { 23201ae08745Sheppo /* link it into the list of ports */ 23211ae08745Sheppo plistp = &(vgenp->vgenports); 23221ae08745Sheppo WRITE_ENTER(&plistp->rwlock); 23231ae08745Sheppo vgen_port_list_insert(portp); 23241ae08745Sheppo RW_EXIT(&plistp->rwlock); 23251107ea93SSriharsha Basavapatna 23261107ea93SSriharsha Basavapatna if (portp->is_vsw_port == B_TRUE) { 23271107ea93SSriharsha Basavapatna /* We now have the vswitch port attached */ 23281107ea93SSriharsha Basavapatna vgenp->vsw_portp = portp; 23291107ea93SSriharsha Basavapatna (void) atomic_swap_32(&vgenp->vsw_port_refcnt, 0); 23301107ea93SSriharsha Basavapatna } 2331678453a8Sspeer } else { 2332678453a8Sspeer DERR(vgenp, NULL, "vio_net_resource_reg failed for portp=0x%p", 2333678453a8Sspeer portp); 2334678453a8Sspeer vgen_port_detach(portp); 23351ae08745Sheppo } 23361ae08745Sheppo 2337844e62a3Sraghuram DBG1(vgenp, NULL, "exit: port_num(%d)\n", portp->port_num); 23381ae08745Sheppo return (DDI_SUCCESS); 23391ae08745Sheppo } 23401ae08745Sheppo 23411ae08745Sheppo /* detach a port from the device based on mdeg data */ 23421ae08745Sheppo static void 23431ae08745Sheppo vgen_port_detach_mdeg(vgen_port_t *portp) 23441ae08745Sheppo { 23451ae08745Sheppo vgen_t *vgenp = portp->vgenp; 23461ae08745Sheppo 2347844e62a3Sraghuram DBG1(vgenp, NULL, "enter: port_num(%d)\n", portp->port_num); 2348678453a8Sspeer 2349678453a8Sspeer mutex_enter(&portp->lock); 2350678453a8Sspeer 23511ae08745Sheppo /* stop the port if needed */ 2352678453a8Sspeer if (portp->flags & VGEN_STARTED) { 23531ae08745Sheppo vgen_port_uninit(portp); 23540c4606f0SWENTAO YANG portp->flags &= ~(VGEN_STARTED); 23551ae08745Sheppo } 2356678453a8Sspeer 2357678453a8Sspeer mutex_exit(&portp->lock); 23581ae08745Sheppo vgen_port_detach(portp); 23591ae08745Sheppo 2360844e62a3Sraghuram DBG1(vgenp, NULL, "exit: port_num(%d)\n", portp->port_num); 23611ae08745Sheppo } 23621ae08745Sheppo 23631ae08745Sheppo static int 23641ae08745Sheppo vgen_update_port(vgen_t *vgenp, md_t *curr_mdp, mde_cookie_t curr_mdex, 23651ae08745Sheppo md_t *prev_mdp, mde_cookie_t prev_mdex) 23661ae08745Sheppo { 2367c1c61f44Ssb155480 uint64_t cport_num; 2368c1c61f44Ssb155480 uint64_t pport_num; 2369c1c61f44Ssb155480 vgen_portlist_t *plistp; 2370c1c61f44Ssb155480 vgen_port_t *portp; 2371c1c61f44Ssb155480 boolean_t updated_vlans = B_FALSE; 2372c1c61f44Ssb155480 uint16_t pvid; 2373c1c61f44Ssb155480 uint16_t *vids; 2374c1c61f44Ssb155480 uint16_t nvids; 23751ae08745Sheppo 2376c1c61f44Ssb155480 /* 2377c1c61f44Ssb155480 * For now, we get port updates only if vlan ids changed. 2378c1c61f44Ssb155480 * We read the port num and do some sanity check. 2379c1c61f44Ssb155480 */ 2380c1c61f44Ssb155480 if (md_get_prop_val(curr_mdp, curr_mdex, id_propname, &cport_num)) { 2381c1c61f44Ssb155480 DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname); 2382c1c61f44Ssb155480 return (DDI_FAILURE); 2383c1c61f44Ssb155480 } 2384c1c61f44Ssb155480 2385c1c61f44Ssb155480 if (md_get_prop_val(prev_mdp, prev_mdex, id_propname, &pport_num)) { 2386c1c61f44Ssb155480 DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname); 2387c1c61f44Ssb155480 return (DDI_FAILURE); 2388c1c61f44Ssb155480 } 2389c1c61f44Ssb155480 if (cport_num != pport_num) 2390c1c61f44Ssb155480 return (DDI_FAILURE); 2391c1c61f44Ssb155480 2392c1c61f44Ssb155480 plistp = &(vgenp->vgenports); 2393c1c61f44Ssb155480 2394c1c61f44Ssb155480 READ_ENTER(&plistp->rwlock); 2395c1c61f44Ssb155480 2396c1c61f44Ssb155480 portp = vgen_port_lookup(plistp, (int)cport_num); 2397c1c61f44Ssb155480 if (portp == NULL) { 2398c1c61f44Ssb155480 DWARN(vgenp, NULL, "can't find port(%lx)\n", cport_num); 2399c1c61f44Ssb155480 RW_EXIT(&plistp->rwlock); 2400c1c61f44Ssb155480 return (DDI_FAILURE); 2401c1c61f44Ssb155480 } 2402c1c61f44Ssb155480 2403c1c61f44Ssb155480 /* Read the vlan ids */ 2404c1c61f44Ssb155480 vgen_vlan_read_ids(portp, VGEN_PEER, curr_mdp, curr_mdex, &pvid, &vids, 2405c1c61f44Ssb155480 &nvids, NULL); 2406c1c61f44Ssb155480 2407c1c61f44Ssb155480 /* Determine if there are any vlan id updates */ 2408c1c61f44Ssb155480 if ((pvid != portp->pvid) || /* pvid changed? */ 2409c1c61f44Ssb155480 (nvids != portp->nvids) || /* # of vids changed? */ 2410c1c61f44Ssb155480 ((nvids != 0) && (portp->nvids != 0) && /* vids changed? */ 2411c1c61f44Ssb155480 bcmp(vids, portp->vids, sizeof (uint16_t) * nvids))) { 2412c1c61f44Ssb155480 updated_vlans = B_TRUE; 2413c1c61f44Ssb155480 } 2414c1c61f44Ssb155480 2415c1c61f44Ssb155480 if (updated_vlans == B_FALSE) { 2416c1c61f44Ssb155480 RW_EXIT(&plistp->rwlock); 2417c1c61f44Ssb155480 return (DDI_FAILURE); 2418c1c61f44Ssb155480 } 2419c1c61f44Ssb155480 2420c1c61f44Ssb155480 /* remove the port from vlans it has been assigned to */ 2421c1c61f44Ssb155480 vgen_vlan_remove_ids(portp); 2422c1c61f44Ssb155480 2423c1c61f44Ssb155480 /* save the new vlan ids */ 2424c1c61f44Ssb155480 portp->pvid = pvid; 2425c1c61f44Ssb155480 if (portp->nvids != 0) { 2426c1c61f44Ssb155480 kmem_free(portp->vids, sizeof (uint16_t) * portp->nvids); 2427c1c61f44Ssb155480 portp->nvids = 0; 2428c1c61f44Ssb155480 } 2429c1c61f44Ssb155480 if (nvids != 0) { 2430c1c61f44Ssb155480 portp->vids = kmem_zalloc(sizeof (uint16_t) * nvids, KM_SLEEP); 2431c1c61f44Ssb155480 bcopy(vids, portp->vids, sizeof (uint16_t) * nvids); 2432c1c61f44Ssb155480 portp->nvids = nvids; 2433c1c61f44Ssb155480 kmem_free(vids, sizeof (uint16_t) * nvids); 2434c1c61f44Ssb155480 } 2435c1c61f44Ssb155480 2436c1c61f44Ssb155480 /* add port to the new vlans */ 2437c1c61f44Ssb155480 vgen_vlan_add_ids(portp); 2438c1c61f44Ssb155480 2439c1c61f44Ssb155480 /* reset the port if it is vlan unaware (ver < 1.3) */ 2440c1c61f44Ssb155480 vgen_vlan_unaware_port_reset(portp); 2441c1c61f44Ssb155480 2442c1c61f44Ssb155480 RW_EXIT(&plistp->rwlock); 2443c1c61f44Ssb155480 24441ae08745Sheppo return (DDI_SUCCESS); 24451ae08745Sheppo } 24461ae08745Sheppo 24471ae08745Sheppo static uint64_t 2448ba2e4443Sseb vgen_port_stat(vgen_port_t *portp, uint_t stat) 24491ae08745Sheppo { 24507bd3a2e2SSriharsha Basavapatna return (vgen_ldc_stat(portp->ldcp, stat)); 24517b1f684aSSriharsha Basavapatna } 24527b1f684aSSriharsha Basavapatna 24531ae08745Sheppo /* attach the channel corresponding to the given ldc_id to the port */ 24541ae08745Sheppo static int 24551ae08745Sheppo vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id) 24561ae08745Sheppo { 24571ae08745Sheppo vgen_t *vgenp; 24587bd3a2e2SSriharsha Basavapatna vgen_ldc_t *ldcp; 24591ae08745Sheppo ldc_attr_t attr; 24601ae08745Sheppo int status; 24611ae08745Sheppo ldc_status_t istatus; 246206db247cSraghuram char kname[MAXNAMELEN]; 246306db247cSraghuram int instance; 24641ae08745Sheppo enum {AST_init = 0x0, AST_ldc_alloc = 0x1, 24651ae08745Sheppo AST_mutex_init = 0x2, AST_ldc_init = 0x4, 24667bd3a2e2SSriharsha Basavapatna AST_ldc_reg_cb = 0x8 } attach_state; 24671ae08745Sheppo 24681ae08745Sheppo attach_state = AST_init; 24691ae08745Sheppo vgenp = portp->vgenp; 24701ae08745Sheppo 24711ae08745Sheppo ldcp = kmem_zalloc(sizeof (vgen_ldc_t), KM_NOSLEEP); 24721ae08745Sheppo if (ldcp == NULL) { 24731ae08745Sheppo goto ldc_attach_failed; 24741ae08745Sheppo } 24751ae08745Sheppo ldcp->ldc_id = ldc_id; 24761ae08745Sheppo ldcp->portp = portp; 24771ae08745Sheppo 24781ae08745Sheppo attach_state |= AST_ldc_alloc; 24791ae08745Sheppo 24801ae08745Sheppo mutex_init(&ldcp->txlock, NULL, MUTEX_DRIVER, NULL); 24811ae08745Sheppo mutex_init(&ldcp->cblock, NULL, MUTEX_DRIVER, NULL); 24821ae08745Sheppo mutex_init(&ldcp->tclock, NULL, MUTEX_DRIVER, NULL); 2483844e62a3Sraghuram mutex_init(&ldcp->wrlock, NULL, MUTEX_DRIVER, NULL); 2484844e62a3Sraghuram mutex_init(&ldcp->rxlock, NULL, MUTEX_DRIVER, NULL); 248563f531d1SSriharsha Basavapatna mutex_init(&ldcp->pollq_lock, NULL, MUTEX_DRIVER, NULL); 24867bd3a2e2SSriharsha Basavapatna mutex_init(&ldcp->msg_thr_lock, NULL, MUTEX_DRIVER, NULL); 24877bd3a2e2SSriharsha Basavapatna cv_init(&ldcp->msg_thr_cv, NULL, CV_DRIVER, NULL); 24881ae08745Sheppo 24891ae08745Sheppo attach_state |= AST_mutex_init; 24901ae08745Sheppo 24911ae08745Sheppo attr.devclass = LDC_DEV_NT; 2492678453a8Sspeer attr.instance = vgenp->instance; 24931ae08745Sheppo attr.mode = LDC_MODE_UNRELIABLE; 24947bd3a2e2SSriharsha Basavapatna attr.mtu = vgen_ldc_mtu; 24951ae08745Sheppo status = ldc_init(ldc_id, &attr, &ldcp->ldc_handle); 24961ae08745Sheppo if (status != 0) { 2497844e62a3Sraghuram DWARN(vgenp, ldcp, "ldc_init failed,rv (%d)\n", status); 24981ae08745Sheppo goto ldc_attach_failed; 24991ae08745Sheppo } 25001ae08745Sheppo attach_state |= AST_ldc_init; 25011ae08745Sheppo 25021ae08745Sheppo status = ldc_reg_callback(ldcp->ldc_handle, vgen_ldc_cb, (caddr_t)ldcp); 25031ae08745Sheppo if (status != 0) { 2504844e62a3Sraghuram DWARN(vgenp, ldcp, "ldc_reg_callback failed, rv (%d)\n", 2505844e62a3Sraghuram status); 25061ae08745Sheppo goto ldc_attach_failed; 25071ae08745Sheppo } 2508f0ca1d9aSsb155480 /* 2509f0ca1d9aSsb155480 * allocate a message for ldc_read()s, big enough to hold ctrl and 2510f0ca1d9aSsb155480 * data msgs, including raw data msgs used to recv priority frames. 2511f0ca1d9aSsb155480 */ 2512c1c61f44Ssb155480 ldcp->msglen = VIO_PKT_DATA_HDRSIZE + vgenp->max_frame_size; 2513f0ca1d9aSsb155480 ldcp->ldcmsg = kmem_alloc(ldcp->msglen, KM_SLEEP); 25141ae08745Sheppo attach_state |= AST_ldc_reg_cb; 25151ae08745Sheppo 25161ae08745Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 25171ae08745Sheppo ASSERT(istatus == LDC_INIT); 25181ae08745Sheppo ldcp->ldc_status = istatus; 25191ae08745Sheppo 25201ae08745Sheppo /* Setup kstats for the channel */ 2521678453a8Sspeer instance = vgenp->instance; 252206db247cSraghuram (void) sprintf(kname, "vnetldc0x%lx", ldcp->ldc_id); 252306db247cSraghuram ldcp->ksp = vgen_setup_kstats("vnet", instance, kname, &ldcp->stats); 252406db247cSraghuram if (ldcp->ksp == NULL) { 25251ae08745Sheppo goto ldc_attach_failed; 25261ae08745Sheppo } 25271ae08745Sheppo 25281ae08745Sheppo /* initialize vgen_versions supported */ 25291ae08745Sheppo bcopy(vgen_versions, ldcp->vgen_versions, sizeof (ldcp->vgen_versions)); 2530f0ca1d9aSsb155480 vgen_reset_vnet_proto_ops(ldcp); 25311ae08745Sheppo 25327bd3a2e2SSriharsha Basavapatna /* Link this channel to the port */ 25337bd3a2e2SSriharsha Basavapatna portp->ldcp = ldcp; 25341ae08745Sheppo 25351107ea93SSriharsha Basavapatna ldcp->link_state = LINK_STATE_UNKNOWN; 25361107ea93SSriharsha Basavapatna #ifdef VNET_IOC_DEBUG 25371107ea93SSriharsha Basavapatna ldcp->link_down_forced = B_FALSE; 25381107ea93SSriharsha Basavapatna #endif 25391ae08745Sheppo ldcp->flags |= CHANNEL_ATTACHED; 25401ae08745Sheppo return (DDI_SUCCESS); 25411ae08745Sheppo 25421ae08745Sheppo ldc_attach_failed: 2543844e62a3Sraghuram if (attach_state & AST_ldc_reg_cb) { 2544844e62a3Sraghuram (void) ldc_unreg_callback(ldcp->ldc_handle); 2545f0ca1d9aSsb155480 kmem_free(ldcp->ldcmsg, ldcp->msglen); 2546844e62a3Sraghuram } 25477bd3a2e2SSriharsha Basavapatna 25481ae08745Sheppo if (attach_state & AST_ldc_init) { 25491ae08745Sheppo (void) ldc_fini(ldcp->ldc_handle); 25501ae08745Sheppo } 25511ae08745Sheppo if (attach_state & AST_mutex_init) { 25521ae08745Sheppo mutex_destroy(&ldcp->tclock); 25531ae08745Sheppo mutex_destroy(&ldcp->txlock); 25541ae08745Sheppo mutex_destroy(&ldcp->cblock); 2555844e62a3Sraghuram mutex_destroy(&ldcp->wrlock); 2556844e62a3Sraghuram mutex_destroy(&ldcp->rxlock); 255763f531d1SSriharsha Basavapatna mutex_destroy(&ldcp->pollq_lock); 25581ae08745Sheppo } 25591ae08745Sheppo if (attach_state & AST_ldc_alloc) { 25601ae08745Sheppo KMEM_FREE(ldcp); 25611ae08745Sheppo } 25621ae08745Sheppo return (DDI_FAILURE); 25631ae08745Sheppo } 25641ae08745Sheppo 25651ae08745Sheppo /* detach a channel from the port */ 25661ae08745Sheppo static void 25671ae08745Sheppo vgen_ldc_detach(vgen_ldc_t *ldcp) 25681ae08745Sheppo { 25691ae08745Sheppo vgen_port_t *portp; 25701ae08745Sheppo vgen_t *vgenp; 25717bd3a2e2SSriharsha Basavapatna 25727bd3a2e2SSriharsha Basavapatna ASSERT(ldcp != NULL); 25731ae08745Sheppo 25741ae08745Sheppo portp = ldcp->portp; 25751ae08745Sheppo vgenp = portp->vgenp; 25761ae08745Sheppo 25771ae08745Sheppo if (ldcp->ldc_status != LDC_INIT) { 2578844e62a3Sraghuram DWARN(vgenp, ldcp, "ldc_status is not INIT\n"); 25791ae08745Sheppo } 25801ae08745Sheppo 25811ae08745Sheppo if (ldcp->flags & CHANNEL_ATTACHED) { 25821ae08745Sheppo ldcp->flags &= ~(CHANNEL_ATTACHED); 25831ae08745Sheppo 2584844e62a3Sraghuram (void) ldc_unreg_callback(ldcp->ldc_handle); 25857bd3a2e2SSriharsha Basavapatna (void) ldc_fini(ldcp->ldc_handle); 2586d10e4ef2Snarayan 25877bd3a2e2SSriharsha Basavapatna kmem_free(ldcp->ldcmsg, ldcp->msglen); 258806db247cSraghuram vgen_destroy_kstats(ldcp->ksp); 258906db247cSraghuram ldcp->ksp = NULL; 25901ae08745Sheppo mutex_destroy(&ldcp->tclock); 25911ae08745Sheppo mutex_destroy(&ldcp->txlock); 25921ae08745Sheppo mutex_destroy(&ldcp->cblock); 2593844e62a3Sraghuram mutex_destroy(&ldcp->wrlock); 2594844e62a3Sraghuram mutex_destroy(&ldcp->rxlock); 259563f531d1SSriharsha Basavapatna mutex_destroy(&ldcp->pollq_lock); 25967bd3a2e2SSriharsha Basavapatna mutex_destroy(&ldcp->msg_thr_lock); 25977bd3a2e2SSriharsha Basavapatna cv_destroy(&ldcp->msg_thr_cv); 25981ae08745Sheppo 25991ae08745Sheppo KMEM_FREE(ldcp); 26001ae08745Sheppo } 26011ae08745Sheppo } 26021ae08745Sheppo 26031ae08745Sheppo /* enable transmit/receive on the channel */ 26041ae08745Sheppo static int 26051ae08745Sheppo vgen_ldc_init(vgen_ldc_t *ldcp) 26061ae08745Sheppo { 2607844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 26081ae08745Sheppo ldc_status_t istatus; 26091ae08745Sheppo int rv; 2610844e62a3Sraghuram enum { ST_init = 0x0, ST_ldc_open = 0x1, 26117bd3a2e2SSriharsha Basavapatna ST_cb_enable = 0x2} init_state; 26127bd3a2e2SSriharsha Basavapatna int flag = 0; 26137bd3a2e2SSriharsha Basavapatna 26141ae08745Sheppo init_state = ST_init; 26151ae08745Sheppo 2616844e62a3Sraghuram DBG1(vgenp, ldcp, "enter\n"); 26171ae08745Sheppo LDC_LOCK(ldcp); 26181ae08745Sheppo 26191ae08745Sheppo rv = ldc_open(ldcp->ldc_handle); 26201ae08745Sheppo if (rv != 0) { 2621844e62a3Sraghuram DWARN(vgenp, ldcp, "ldc_open failed: rv(%d)\n", rv); 26221ae08745Sheppo goto ldcinit_failed; 26231ae08745Sheppo } 26241ae08745Sheppo init_state |= ST_ldc_open; 26251ae08745Sheppo 26261ae08745Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 26271ae08745Sheppo if (istatus != LDC_OPEN && istatus != LDC_READY) { 2628844e62a3Sraghuram DWARN(vgenp, ldcp, "status(%d) is not OPEN/READY\n", istatus); 26291ae08745Sheppo goto ldcinit_failed; 26301ae08745Sheppo } 26311ae08745Sheppo ldcp->ldc_status = istatus; 26321ae08745Sheppo 26337636cb21Slm66018 rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_ENABLE); 26347636cb21Slm66018 if (rv != 0) { 2635844e62a3Sraghuram DWARN(vgenp, ldcp, "ldc_set_cb_mode failed: rv(%d)\n", rv); 26367636cb21Slm66018 goto ldcinit_failed; 26377636cb21Slm66018 } 26387636cb21Slm66018 26397636cb21Slm66018 init_state |= ST_cb_enable; 26407636cb21Slm66018 26417bd3a2e2SSriharsha Basavapatna vgen_ldc_up(ldcp); 26421ae08745Sheppo 26431ae08745Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 26443af08d82Slm66018 if (istatus == LDC_UP) { 2645844e62a3Sraghuram DWARN(vgenp, ldcp, "status(%d) is UP\n", istatus); 26461ae08745Sheppo } 26473af08d82Slm66018 26481ae08745Sheppo ldcp->ldc_status = istatus; 26491ae08745Sheppo 26507bd3a2e2SSriharsha Basavapatna ldcp->hphase = VH_PHASE0; 26517bd3a2e2SSriharsha Basavapatna ldcp->hstate = 0; 26521ae08745Sheppo ldcp->flags |= CHANNEL_STARTED; 26531ae08745Sheppo 26547bd3a2e2SSriharsha Basavapatna vgen_setup_handshake_params(ldcp); 26557bd3a2e2SSriharsha Basavapatna 26563af08d82Slm66018 /* if channel is already UP - start handshake */ 26573af08d82Slm66018 if (istatus == LDC_UP) { 26583af08d82Slm66018 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 26593af08d82Slm66018 if (ldcp->portp != vgenp->vsw_portp) { 26603af08d82Slm66018 /* 2661678453a8Sspeer * As the channel is up, use this port from now on. 26623af08d82Slm66018 */ 2663678453a8Sspeer (void) atomic_swap_32( 2664678453a8Sspeer &ldcp->portp->use_vsw_port, B_FALSE); 26653af08d82Slm66018 } 26663af08d82Slm66018 26673af08d82Slm66018 /* Initialize local session id */ 26683af08d82Slm66018 ldcp->local_sid = ddi_get_lbolt(); 26693af08d82Slm66018 26703af08d82Slm66018 /* clear peer session id */ 26713af08d82Slm66018 ldcp->peer_sid = 0; 26723af08d82Slm66018 26733af08d82Slm66018 mutex_exit(&ldcp->tclock); 26743af08d82Slm66018 mutex_exit(&ldcp->txlock); 2675844e62a3Sraghuram mutex_exit(&ldcp->wrlock); 2676844e62a3Sraghuram mutex_exit(&ldcp->rxlock); 26777bd3a2e2SSriharsha Basavapatna rv = vgen_handshake(vh_nextphase(ldcp)); 26783af08d82Slm66018 mutex_exit(&ldcp->cblock); 26797bd3a2e2SSriharsha Basavapatna if (rv != 0) { 26807bd3a2e2SSriharsha Basavapatna flag = (rv == ECONNRESET) ? VGEN_FLAG_EVT_RESET : 26817bd3a2e2SSriharsha Basavapatna VGEN_FLAG_NEED_LDCRESET; 26827bd3a2e2SSriharsha Basavapatna (void) vgen_process_reset(ldcp, flag); 26837bd3a2e2SSriharsha Basavapatna } 26843af08d82Slm66018 } else { 26851ae08745Sheppo LDC_UNLOCK(ldcp); 26863af08d82Slm66018 } 26873af08d82Slm66018 26881ae08745Sheppo return (DDI_SUCCESS); 26891ae08745Sheppo 26901ae08745Sheppo ldcinit_failed: 26917636cb21Slm66018 if (init_state & ST_cb_enable) { 26927636cb21Slm66018 (void) ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE); 26937636cb21Slm66018 } 26941ae08745Sheppo if (init_state & ST_ldc_open) { 26951ae08745Sheppo (void) ldc_close(ldcp->ldc_handle); 26961ae08745Sheppo } 26971ae08745Sheppo LDC_UNLOCK(ldcp); 2698844e62a3Sraghuram DBG1(vgenp, ldcp, "exit\n"); 26991ae08745Sheppo return (DDI_FAILURE); 27001ae08745Sheppo } 27011ae08745Sheppo 27021ae08745Sheppo /* stop transmit/receive on the channel */ 27031ae08745Sheppo static void 27041ae08745Sheppo vgen_ldc_uninit(vgen_ldc_t *ldcp) 27051ae08745Sheppo { 2706844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 27071ae08745Sheppo 2708844e62a3Sraghuram DBG1(vgenp, ldcp, "enter\n"); 27097bd3a2e2SSriharsha Basavapatna 27101ae08745Sheppo LDC_LOCK(ldcp); 27111ae08745Sheppo 27121ae08745Sheppo if ((ldcp->flags & CHANNEL_STARTED) == 0) { 27131ae08745Sheppo LDC_UNLOCK(ldcp); 2714844e62a3Sraghuram DWARN(vgenp, ldcp, "CHANNEL_STARTED flag is not set\n"); 27151ae08745Sheppo return; 27161ae08745Sheppo } 27171ae08745Sheppo 27181ae08745Sheppo LDC_UNLOCK(ldcp); 27191ae08745Sheppo 27207bd3a2e2SSriharsha Basavapatna while (atomic_cas_uint(&ldcp->reset_in_progress, 0, 1) != 0) { 27217bd3a2e2SSriharsha Basavapatna delay(drv_usectohz(VGEN_LDC_UNINIT_DELAY)); 27225460ddbdSSriharsha Basavapatna } 27235460ddbdSSriharsha Basavapatna 27247bd3a2e2SSriharsha Basavapatna (void) vgen_process_reset(ldcp, VGEN_FLAG_UNINIT); 27251ae08745Sheppo 2726844e62a3Sraghuram DBG1(vgenp, ldcp, "exit\n"); 27271ae08745Sheppo } 27281ae08745Sheppo 27297b1f684aSSriharsha Basavapatna /* 27307bd3a2e2SSriharsha Basavapatna * Create a descriptor ring, that will be exported to the peer for mapping. 27317b1f684aSSriharsha Basavapatna */ 27327bd3a2e2SSriharsha Basavapatna static int 27337bd3a2e2SSriharsha Basavapatna vgen_create_dring(vgen_ldc_t *ldcp) 27347bd3a2e2SSriharsha Basavapatna { 27357bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams; 27367bd3a2e2SSriharsha Basavapatna int rv; 27377bd3a2e2SSriharsha Basavapatna 27387bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_RX_DRING_DATA) { 27397bd3a2e2SSriharsha Basavapatna rv = vgen_create_rx_dring(ldcp); 27407b1f684aSSriharsha Basavapatna } else { 27417bd3a2e2SSriharsha Basavapatna rv = vgen_create_tx_dring(ldcp); 27427b1f684aSSriharsha Basavapatna } 27437b1f684aSSriharsha Basavapatna 27447bd3a2e2SSriharsha Basavapatna return (rv); 27451ae08745Sheppo } 27468e6a2a04Slm66018 27478e6a2a04Slm66018 /* 27487bd3a2e2SSriharsha Basavapatna * Destroy the descriptor ring. 27498e6a2a04Slm66018 */ 27507bd3a2e2SSriharsha Basavapatna static void 27517bd3a2e2SSriharsha Basavapatna vgen_destroy_dring(vgen_ldc_t *ldcp) 27527bd3a2e2SSriharsha Basavapatna { 27537bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams; 27547bd3a2e2SSriharsha Basavapatna 27557bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_RX_DRING_DATA) { 27567bd3a2e2SSriharsha Basavapatna vgen_destroy_rx_dring(ldcp); 27577bd3a2e2SSriharsha Basavapatna } else { 27587bd3a2e2SSriharsha Basavapatna vgen_destroy_tx_dring(ldcp); 27597bd3a2e2SSriharsha Basavapatna } 27608e6a2a04Slm66018 } 27618e6a2a04Slm66018 27628e6a2a04Slm66018 /* 27637bd3a2e2SSriharsha Basavapatna * Map the descriptor ring exported by the peer. 27648e6a2a04Slm66018 */ 27651ae08745Sheppo static int 27667bd3a2e2SSriharsha Basavapatna vgen_map_dring(vgen_ldc_t *ldcp, void *pkt) 27671ae08745Sheppo { 27681ae08745Sheppo int rv; 27697bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams; 27701ae08745Sheppo 27717bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_RX_DRING_DATA) { 27727bd3a2e2SSriharsha Basavapatna /* 27737bd3a2e2SSriharsha Basavapatna * In RxDringData mode, dring that we map in 27747bd3a2e2SSriharsha Basavapatna * becomes our transmit descriptor ring. 27757bd3a2e2SSriharsha Basavapatna */ 27767bd3a2e2SSriharsha Basavapatna rv = vgen_map_tx_dring(ldcp, pkt); 27777bd3a2e2SSriharsha Basavapatna } else { 27787bd3a2e2SSriharsha Basavapatna 27797bd3a2e2SSriharsha Basavapatna /* 27807bd3a2e2SSriharsha Basavapatna * In TxDring mode, dring that we map in 27817bd3a2e2SSriharsha Basavapatna * becomes our receive descriptor ring. 27827bd3a2e2SSriharsha Basavapatna */ 27837bd3a2e2SSriharsha Basavapatna rv = vgen_map_rx_dring(ldcp, pkt); 27847bd3a2e2SSriharsha Basavapatna } 27857bd3a2e2SSriharsha Basavapatna 27867bd3a2e2SSriharsha Basavapatna return (rv); 27871ae08745Sheppo } 27881ae08745Sheppo 27891ae08745Sheppo /* 27907bd3a2e2SSriharsha Basavapatna * Unmap the descriptor ring exported by the peer. 27911ae08745Sheppo */ 27927bd3a2e2SSriharsha Basavapatna static void 27937bd3a2e2SSriharsha Basavapatna vgen_unmap_dring(vgen_ldc_t *ldcp) 27947bd3a2e2SSriharsha Basavapatna { 27957bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams; 27967bd3a2e2SSriharsha Basavapatna 27977bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_RX_DRING_DATA) { 27987bd3a2e2SSriharsha Basavapatna vgen_unmap_tx_dring(ldcp); 27997bd3a2e2SSriharsha Basavapatna } else { 28007bd3a2e2SSriharsha Basavapatna vgen_unmap_rx_dring(ldcp); 28017bd3a2e2SSriharsha Basavapatna } 28021ae08745Sheppo } 28031ae08745Sheppo 28047bd3a2e2SSriharsha Basavapatna void 28057bd3a2e2SSriharsha Basavapatna vgen_destroy_rxpools(void *arg) 28067bd3a2e2SSriharsha Basavapatna { 28077bd3a2e2SSriharsha Basavapatna vio_mblk_pool_t *poolp = (vio_mblk_pool_t *)arg; 28087bd3a2e2SSriharsha Basavapatna vio_mblk_pool_t *npoolp; 28091ae08745Sheppo 28107bd3a2e2SSriharsha Basavapatna while (poolp != NULL) { 28117bd3a2e2SSriharsha Basavapatna npoolp = poolp->nextp; 28127bd3a2e2SSriharsha Basavapatna while (vio_destroy_mblks(poolp) != 0) { 2813a862df29SSriharsha Basavapatna delay(drv_usectohz(vgen_rxpool_cleanup_delay)); 28147bd3a2e2SSriharsha Basavapatna } 28157bd3a2e2SSriharsha Basavapatna poolp = npoolp; 28167bd3a2e2SSriharsha Basavapatna } 28171ae08745Sheppo } 28181ae08745Sheppo 28191ae08745Sheppo /* get channel statistics */ 28201ae08745Sheppo static uint64_t 2821ba2e4443Sseb vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat) 28221ae08745Sheppo { 28231ae08745Sheppo vgen_stats_t *statsp; 28241ae08745Sheppo uint64_t val; 28251ae08745Sheppo 28261ae08745Sheppo val = 0; 282706db247cSraghuram statsp = &ldcp->stats; 28281ae08745Sheppo switch (stat) { 28291ae08745Sheppo 28301ae08745Sheppo case MAC_STAT_MULTIRCV: 28311ae08745Sheppo val = statsp->multircv; 28321ae08745Sheppo break; 28331ae08745Sheppo 28341ae08745Sheppo case MAC_STAT_BRDCSTRCV: 28351ae08745Sheppo val = statsp->brdcstrcv; 28361ae08745Sheppo break; 28371ae08745Sheppo 28381ae08745Sheppo case MAC_STAT_MULTIXMT: 28391ae08745Sheppo val = statsp->multixmt; 28401ae08745Sheppo break; 28411ae08745Sheppo 28421ae08745Sheppo case MAC_STAT_BRDCSTXMT: 28431ae08745Sheppo val = statsp->brdcstxmt; 28441ae08745Sheppo break; 28451ae08745Sheppo 28461ae08745Sheppo case MAC_STAT_NORCVBUF: 28471ae08745Sheppo val = statsp->norcvbuf; 28481ae08745Sheppo break; 28491ae08745Sheppo 28501ae08745Sheppo case MAC_STAT_IERRORS: 28511ae08745Sheppo val = statsp->ierrors; 28521ae08745Sheppo break; 28531ae08745Sheppo 28541ae08745Sheppo case MAC_STAT_NOXMTBUF: 28551ae08745Sheppo val = statsp->noxmtbuf; 28561ae08745Sheppo break; 28571ae08745Sheppo 28581ae08745Sheppo case MAC_STAT_OERRORS: 28591ae08745Sheppo val = statsp->oerrors; 28601ae08745Sheppo break; 28611ae08745Sheppo 28621ae08745Sheppo case MAC_STAT_COLLISIONS: 28631ae08745Sheppo break; 28641ae08745Sheppo 28651ae08745Sheppo case MAC_STAT_RBYTES: 28661ae08745Sheppo val = statsp->rbytes; 28671ae08745Sheppo break; 28681ae08745Sheppo 28691ae08745Sheppo case MAC_STAT_IPACKETS: 28701ae08745Sheppo val = statsp->ipackets; 28711ae08745Sheppo break; 28721ae08745Sheppo 28731ae08745Sheppo case MAC_STAT_OBYTES: 28741ae08745Sheppo val = statsp->obytes; 28751ae08745Sheppo break; 28761ae08745Sheppo 28771ae08745Sheppo case MAC_STAT_OPACKETS: 28781ae08745Sheppo val = statsp->opackets; 28791ae08745Sheppo break; 28801ae08745Sheppo 28811ae08745Sheppo /* stats not relevant to ldc, return 0 */ 28821ae08745Sheppo case MAC_STAT_IFSPEED: 2883ba2e4443Sseb case ETHER_STAT_ALIGN_ERRORS: 2884ba2e4443Sseb case ETHER_STAT_FCS_ERRORS: 2885ba2e4443Sseb case ETHER_STAT_FIRST_COLLISIONS: 2886ba2e4443Sseb case ETHER_STAT_MULTI_COLLISIONS: 2887ba2e4443Sseb case ETHER_STAT_DEFER_XMTS: 2888ba2e4443Sseb case ETHER_STAT_TX_LATE_COLLISIONS: 2889ba2e4443Sseb case ETHER_STAT_EX_COLLISIONS: 2890ba2e4443Sseb case ETHER_STAT_MACXMT_ERRORS: 2891ba2e4443Sseb case ETHER_STAT_CARRIER_ERRORS: 2892ba2e4443Sseb case ETHER_STAT_TOOLONG_ERRORS: 2893ba2e4443Sseb case ETHER_STAT_XCVR_ADDR: 2894ba2e4443Sseb case ETHER_STAT_XCVR_ID: 2895ba2e4443Sseb case ETHER_STAT_XCVR_INUSE: 2896ba2e4443Sseb case ETHER_STAT_CAP_1000FDX: 2897ba2e4443Sseb case ETHER_STAT_CAP_1000HDX: 2898ba2e4443Sseb case ETHER_STAT_CAP_100FDX: 2899ba2e4443Sseb case ETHER_STAT_CAP_100HDX: 2900ba2e4443Sseb case ETHER_STAT_CAP_10FDX: 2901ba2e4443Sseb case ETHER_STAT_CAP_10HDX: 2902ba2e4443Sseb case ETHER_STAT_CAP_ASMPAUSE: 2903ba2e4443Sseb case ETHER_STAT_CAP_PAUSE: 2904ba2e4443Sseb case ETHER_STAT_CAP_AUTONEG: 2905ba2e4443Sseb case ETHER_STAT_ADV_CAP_1000FDX: 2906ba2e4443Sseb case ETHER_STAT_ADV_CAP_1000HDX: 2907ba2e4443Sseb case ETHER_STAT_ADV_CAP_100FDX: 2908ba2e4443Sseb case ETHER_STAT_ADV_CAP_100HDX: 2909ba2e4443Sseb case ETHER_STAT_ADV_CAP_10FDX: 2910ba2e4443Sseb case ETHER_STAT_ADV_CAP_10HDX: 2911ba2e4443Sseb case ETHER_STAT_ADV_CAP_ASMPAUSE: 2912ba2e4443Sseb case ETHER_STAT_ADV_CAP_PAUSE: 2913ba2e4443Sseb case ETHER_STAT_ADV_CAP_AUTONEG: 2914ba2e4443Sseb case ETHER_STAT_LP_CAP_1000FDX: 2915ba2e4443Sseb case ETHER_STAT_LP_CAP_1000HDX: 2916ba2e4443Sseb case ETHER_STAT_LP_CAP_100FDX: 2917ba2e4443Sseb case ETHER_STAT_LP_CAP_100HDX: 2918ba2e4443Sseb case ETHER_STAT_LP_CAP_10FDX: 2919ba2e4443Sseb case ETHER_STAT_LP_CAP_10HDX: 2920ba2e4443Sseb case ETHER_STAT_LP_CAP_ASMPAUSE: 2921ba2e4443Sseb case ETHER_STAT_LP_CAP_PAUSE: 2922ba2e4443Sseb case ETHER_STAT_LP_CAP_AUTONEG: 2923ba2e4443Sseb case ETHER_STAT_LINK_ASMPAUSE: 2924ba2e4443Sseb case ETHER_STAT_LINK_PAUSE: 2925ba2e4443Sseb case ETHER_STAT_LINK_AUTONEG: 2926ba2e4443Sseb case ETHER_STAT_LINK_DUPLEX: 29271ae08745Sheppo default: 29281ae08745Sheppo val = 0; 29291ae08745Sheppo break; 29301ae08745Sheppo 29311ae08745Sheppo } 29321ae08745Sheppo return (val); 29331ae08745Sheppo } 29341ae08745Sheppo 29353af08d82Slm66018 /* 2936678453a8Sspeer * LDC channel is UP, start handshake process with peer. 29373af08d82Slm66018 */ 29383af08d82Slm66018 static void 2939678453a8Sspeer vgen_handle_evt_up(vgen_ldc_t *ldcp) 29403af08d82Slm66018 { 29413af08d82Slm66018 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 29423af08d82Slm66018 2943844e62a3Sraghuram DBG1(vgenp, ldcp, "enter\n"); 29443af08d82Slm66018 29453af08d82Slm66018 ASSERT(MUTEX_HELD(&ldcp->cblock)); 29463af08d82Slm66018 29473af08d82Slm66018 if (ldcp->portp != vgenp->vsw_portp) { 29483af08d82Slm66018 /* 2949678453a8Sspeer * As the channel is up, use this port from now on. 29503af08d82Slm66018 */ 2951678453a8Sspeer (void) atomic_swap_32(&ldcp->portp->use_vsw_port, B_FALSE); 29523af08d82Slm66018 } 29533af08d82Slm66018 29543af08d82Slm66018 /* Initialize local session id */ 29553af08d82Slm66018 ldcp->local_sid = ddi_get_lbolt(); 29563af08d82Slm66018 29573af08d82Slm66018 /* clear peer session id */ 29583af08d82Slm66018 ldcp->peer_sid = 0; 29593af08d82Slm66018 29603af08d82Slm66018 /* Initiate Handshake process with peer ldc endpoint */ 29617bd3a2e2SSriharsha Basavapatna (void) vgen_handshake(vh_nextphase(ldcp)); 29623af08d82Slm66018 2963844e62a3Sraghuram DBG1(vgenp, ldcp, "exit\n"); 29643af08d82Slm66018 } 29653af08d82Slm66018 29663af08d82Slm66018 /* 29673af08d82Slm66018 * LDC channel is Reset, terminate connection with peer and try to 29683af08d82Slm66018 * bring the channel up again. 29693af08d82Slm66018 */ 29707bd3a2e2SSriharsha Basavapatna int 29717bd3a2e2SSriharsha Basavapatna vgen_handle_evt_reset(vgen_ldc_t *ldcp, vgen_caller_t caller) 29723af08d82Slm66018 { 29737bd3a2e2SSriharsha Basavapatna if (caller == VGEN_LDC_CB || caller == VGEN_MSG_THR) { 29743af08d82Slm66018 ASSERT(MUTEX_HELD(&ldcp->cblock)); 2975678453a8Sspeer } 2976678453a8Sspeer 29777bd3a2e2SSriharsha Basavapatna /* Set the flag to indicate reset is in progress */ 29787bd3a2e2SSriharsha Basavapatna if (atomic_cas_uint(&ldcp->reset_in_progress, 0, 1) != 0) { 29797bd3a2e2SSriharsha Basavapatna /* another thread is already in the process of resetting */ 29807bd3a2e2SSriharsha Basavapatna return (EBUSY); 29813af08d82Slm66018 } 29823af08d82Slm66018 29837bd3a2e2SSriharsha Basavapatna if (caller == VGEN_LDC_CB || caller == VGEN_MSG_THR) { 29847bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->cblock); 29853af08d82Slm66018 } 29863af08d82Slm66018 29877bd3a2e2SSriharsha Basavapatna (void) vgen_process_reset(ldcp, VGEN_FLAG_EVT_RESET); 29883af08d82Slm66018 29897bd3a2e2SSriharsha Basavapatna if (caller == VGEN_LDC_CB || caller == VGEN_MSG_THR) { 29907bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->cblock); 29913af08d82Slm66018 } 29923af08d82Slm66018 29937bd3a2e2SSriharsha Basavapatna return (0); 29943af08d82Slm66018 } 29953af08d82Slm66018 29961ae08745Sheppo /* Interrupt handler for the channel */ 29971ae08745Sheppo static uint_t 29981ae08745Sheppo vgen_ldc_cb(uint64_t event, caddr_t arg) 29991ae08745Sheppo { 30001ae08745Sheppo _NOTE(ARGUNUSED(event)) 30011ae08745Sheppo vgen_ldc_t *ldcp; 30021ae08745Sheppo vgen_t *vgenp; 30031ae08745Sheppo ldc_status_t istatus; 30041ae08745Sheppo vgen_stats_t *statsp; 300552bca946SWENTAO YANG uint_t ret = LDC_SUCCESS; 30061ae08745Sheppo 30071ae08745Sheppo ldcp = (vgen_ldc_t *)arg; 30081ae08745Sheppo vgenp = LDC_TO_VGEN(ldcp); 300906db247cSraghuram statsp = &ldcp->stats; 30101ae08745Sheppo 3011844e62a3Sraghuram DBG1(vgenp, ldcp, "enter\n"); 30121ae08745Sheppo 30131ae08745Sheppo mutex_enter(&ldcp->cblock); 30141ae08745Sheppo statsp->callbacks++; 30151ae08745Sheppo if ((ldcp->ldc_status == LDC_INIT) || (ldcp->ldc_handle == NULL)) { 3016844e62a3Sraghuram DWARN(vgenp, ldcp, "status(%d) is LDC_INIT\n", 3017844e62a3Sraghuram ldcp->ldc_status); 30181ae08745Sheppo mutex_exit(&ldcp->cblock); 30191ae08745Sheppo return (LDC_SUCCESS); 30201ae08745Sheppo } 30211ae08745Sheppo 30221ae08745Sheppo /* 30233af08d82Slm66018 * NOTE: not using switch() as event could be triggered by 30243af08d82Slm66018 * a state change and a read request. Also the ordering of the 30253af08d82Slm66018 * check for the event types is deliberate. 30261ae08745Sheppo */ 30273af08d82Slm66018 if (event & LDC_EVT_UP) { 30283af08d82Slm66018 if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 3029844e62a3Sraghuram DWARN(vgenp, ldcp, "ldc_status err\n"); 30307062b44aSraghuram /* status couldn't be determined */ 303152bca946SWENTAO YANG ret = LDC_FAILURE; 303252bca946SWENTAO YANG goto ldc_cb_ret; 30331ae08745Sheppo } 30347062b44aSraghuram ldcp->ldc_status = istatus; 30357062b44aSraghuram if (ldcp->ldc_status != LDC_UP) { 30367062b44aSraghuram DWARN(vgenp, ldcp, "LDC_EVT_UP received " 30377062b44aSraghuram " but ldc status is not UP(0x%x)\n", 30387062b44aSraghuram ldcp->ldc_status); 30397062b44aSraghuram /* spurious interrupt, return success */ 304052bca946SWENTAO YANG goto ldc_cb_ret; 30417062b44aSraghuram } 3042844e62a3Sraghuram DWARN(vgenp, ldcp, "event(%lx) UP, status(%d)\n", 3043844e62a3Sraghuram event, ldcp->ldc_status); 30443af08d82Slm66018 3045678453a8Sspeer vgen_handle_evt_up(ldcp); 30463af08d82Slm66018 30473af08d82Slm66018 ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0); 30481ae08745Sheppo } 30491ae08745Sheppo 30507062b44aSraghuram /* Handle RESET/DOWN before READ event */ 30517062b44aSraghuram if (event & (LDC_EVT_RESET | LDC_EVT_DOWN)) { 30527062b44aSraghuram if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 30537062b44aSraghuram DWARN(vgenp, ldcp, "ldc_status error\n"); 30547062b44aSraghuram /* status couldn't be determined */ 305552bca946SWENTAO YANG ret = LDC_FAILURE; 305652bca946SWENTAO YANG goto ldc_cb_ret; 30577062b44aSraghuram } 30587062b44aSraghuram ldcp->ldc_status = istatus; 30597062b44aSraghuram DWARN(vgenp, ldcp, "event(%lx) RESET/DOWN, status(%d)\n", 30607062b44aSraghuram event, ldcp->ldc_status); 30617062b44aSraghuram 30627bd3a2e2SSriharsha Basavapatna (void) vgen_handle_evt_reset(ldcp, VGEN_LDC_CB); 30637062b44aSraghuram 30647062b44aSraghuram /* 30657062b44aSraghuram * As the channel is down/reset, ignore READ event 30667062b44aSraghuram * but print a debug warning message. 30677062b44aSraghuram */ 30687062b44aSraghuram if (event & LDC_EVT_READ) { 30697062b44aSraghuram DWARN(vgenp, ldcp, 30707062b44aSraghuram "LDC_EVT_READ set along with RESET/DOWN\n"); 30717062b44aSraghuram event &= ~LDC_EVT_READ; 30727062b44aSraghuram } 30737062b44aSraghuram } 30747062b44aSraghuram 30753af08d82Slm66018 if (event & LDC_EVT_READ) { 3076844e62a3Sraghuram DBG2(vgenp, ldcp, "event(%lx) READ, status(%d)\n", 3077844e62a3Sraghuram event, ldcp->ldc_status); 30783af08d82Slm66018 30793af08d82Slm66018 ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0); 3080844e62a3Sraghuram 30817bd3a2e2SSriharsha Basavapatna if (ldcp->msg_thread != NULL) { 3082844e62a3Sraghuram /* 3083844e62a3Sraghuram * If the receive thread is enabled, then 3084844e62a3Sraghuram * wakeup the receive thread to process the 3085844e62a3Sraghuram * LDC messages. 3086844e62a3Sraghuram */ 3087844e62a3Sraghuram mutex_exit(&ldcp->cblock); 30887bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->msg_thr_lock); 30897bd3a2e2SSriharsha Basavapatna if (!(ldcp->msg_thr_flags & VGEN_WTHR_DATARCVD)) { 30907bd3a2e2SSriharsha Basavapatna ldcp->msg_thr_flags |= VGEN_WTHR_DATARCVD; 30917bd3a2e2SSriharsha Basavapatna cv_signal(&ldcp->msg_thr_cv); 3092844e62a3Sraghuram } 30937bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->msg_thr_lock); 3094844e62a3Sraghuram mutex_enter(&ldcp->cblock); 3095844e62a3Sraghuram } else { 30967bd3a2e2SSriharsha Basavapatna (void) vgen_handle_evt_read(ldcp, VGEN_LDC_CB); 3097844e62a3Sraghuram } 30983af08d82Slm66018 } 309952bca946SWENTAO YANG 310052bca946SWENTAO YANG ldc_cb_ret: 31011ae08745Sheppo mutex_exit(&ldcp->cblock); 3102844e62a3Sraghuram DBG1(vgenp, ldcp, "exit\n"); 310352bca946SWENTAO YANG return (ret); 3104844e62a3Sraghuram } 3105844e62a3Sraghuram 31067bd3a2e2SSriharsha Basavapatna int 31077bd3a2e2SSriharsha Basavapatna vgen_handle_evt_read(vgen_ldc_t *ldcp, vgen_caller_t caller) 3108844e62a3Sraghuram { 3109844e62a3Sraghuram int rv; 3110f0ca1d9aSsb155480 uint64_t *ldcmsg; 3111844e62a3Sraghuram size_t msglen; 3112844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 3113844e62a3Sraghuram vio_msg_tag_t *tagp; 3114844e62a3Sraghuram ldc_status_t istatus; 3115844e62a3Sraghuram boolean_t has_data; 3116844e62a3Sraghuram 3117844e62a3Sraghuram DBG1(vgenp, ldcp, "enter\n"); 3118844e62a3Sraghuram 31197bd3a2e2SSriharsha Basavapatna if (caller == VGEN_LDC_CB) { 31207bd3a2e2SSriharsha Basavapatna ASSERT(MUTEX_HELD(&ldcp->cblock)); 31217bd3a2e2SSriharsha Basavapatna } else if (caller == VGEN_MSG_THR) { 3122844e62a3Sraghuram mutex_enter(&ldcp->cblock); 3123844e62a3Sraghuram } else { 31247bd3a2e2SSriharsha Basavapatna return (EINVAL); 3125844e62a3Sraghuram } 3126844e62a3Sraghuram 31277bd3a2e2SSriharsha Basavapatna ldcmsg = ldcp->ldcmsg; 31287bd3a2e2SSriharsha Basavapatna 31297bd3a2e2SSriharsha Basavapatna vgen_evtread: 31301ae08745Sheppo do { 3131f0ca1d9aSsb155480 msglen = ldcp->msglen; 3132f0ca1d9aSsb155480 rv = ldc_read(ldcp->ldc_handle, (caddr_t)ldcmsg, &msglen); 31331ae08745Sheppo 31341ae08745Sheppo if (rv != 0) { 31357bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "ldc_read() failed " 31367bd3a2e2SSriharsha Basavapatna "rv(%d) len(%d)\n", rv, msglen); 31373af08d82Slm66018 if (rv == ECONNRESET) 3138844e62a3Sraghuram goto vgen_evtread_error; 31391ae08745Sheppo break; 31401ae08745Sheppo } 31411ae08745Sheppo if (msglen == 0) { 3142844e62a3Sraghuram DBG2(vgenp, ldcp, "ldc_read NODATA"); 31431ae08745Sheppo break; 31441ae08745Sheppo } 3145844e62a3Sraghuram DBG2(vgenp, ldcp, "ldc_read msglen(%d)", msglen); 31461ae08745Sheppo 31471ae08745Sheppo tagp = (vio_msg_tag_t *)ldcmsg; 31481ae08745Sheppo 31491ae08745Sheppo if (ldcp->peer_sid) { 31501ae08745Sheppo /* 31511ae08745Sheppo * check sid only after we have received peer's sid 31521ae08745Sheppo * in the version negotiate msg. 31531ae08745Sheppo */ 31541ae08745Sheppo #ifdef DEBUG 31557bd3a2e2SSriharsha Basavapatna if (vgen_inject_error(ldcp, VGEN_ERR_HSID)) { 31561ae08745Sheppo /* simulate bad sid condition */ 31571ae08745Sheppo tagp->vio_sid = 0; 31587bd3a2e2SSriharsha Basavapatna vgen_inject_err_flag &= ~(VGEN_ERR_HSID); 31591ae08745Sheppo } 31601ae08745Sheppo #endif 31613af08d82Slm66018 rv = vgen_check_sid(ldcp, tagp); 31623af08d82Slm66018 if (rv != VGEN_SUCCESS) { 31631ae08745Sheppo /* 31641ae08745Sheppo * If sid mismatch is detected, 31651ae08745Sheppo * reset the channel. 31661ae08745Sheppo */ 31677bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "vgen_check_sid() failed\n"); 3168844e62a3Sraghuram goto vgen_evtread_error; 31691ae08745Sheppo } 31701ae08745Sheppo } 31711ae08745Sheppo 31721ae08745Sheppo switch (tagp->vio_msgtype) { 31731ae08745Sheppo case VIO_TYPE_CTRL: 31743af08d82Slm66018 rv = vgen_handle_ctrlmsg(ldcp, tagp); 31757bd3a2e2SSriharsha Basavapatna if (rv != 0) { 31767bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "vgen_handle_ctrlmsg()" 31777bd3a2e2SSriharsha Basavapatna " failed rv(%d)\n", rv); 31787bd3a2e2SSriharsha Basavapatna } 31791ae08745Sheppo break; 31801ae08745Sheppo 31811ae08745Sheppo case VIO_TYPE_DATA: 3182f0ca1d9aSsb155480 rv = vgen_handle_datamsg(ldcp, tagp, msglen); 31837bd3a2e2SSriharsha Basavapatna if (rv != 0) { 31847bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "vgen_handle_datamsg()" 31857bd3a2e2SSriharsha Basavapatna " failed rv(%d)\n", rv); 31867bd3a2e2SSriharsha Basavapatna } 31871ae08745Sheppo break; 31881ae08745Sheppo 31891ae08745Sheppo case VIO_TYPE_ERR: 31901ae08745Sheppo vgen_handle_errmsg(ldcp, tagp); 31911ae08745Sheppo break; 31921ae08745Sheppo 31931ae08745Sheppo default: 3194844e62a3Sraghuram DWARN(vgenp, ldcp, "Unknown VIO_TYPE(%x)\n", 3195844e62a3Sraghuram tagp->vio_msgtype); 31961ae08745Sheppo break; 31971ae08745Sheppo } 31981ae08745Sheppo 3199844e62a3Sraghuram /* 3200844e62a3Sraghuram * If an error is encountered, stop processing and 3201844e62a3Sraghuram * handle the error. 3202844e62a3Sraghuram */ 3203844e62a3Sraghuram if (rv != 0) { 3204844e62a3Sraghuram goto vgen_evtread_error; 32053af08d82Slm66018 } 32063af08d82Slm66018 32071ae08745Sheppo } while (msglen); 32081ae08745Sheppo 3209844e62a3Sraghuram /* check once more before exiting */ 3210844e62a3Sraghuram rv = ldc_chkq(ldcp->ldc_handle, &has_data); 3211844e62a3Sraghuram if ((rv == 0) && (has_data == B_TRUE)) { 32127bd3a2e2SSriharsha Basavapatna DTRACE_PROBE1(vgen_chkq, vgen_ldc_t *, ldcp); 32137bd3a2e2SSriharsha Basavapatna goto vgen_evtread; 32141ae08745Sheppo } 3215bd8f0338Snarayan 3216844e62a3Sraghuram vgen_evtread_error: 32177bd3a2e2SSriharsha Basavapatna if (rv != 0) { 32187bd3a2e2SSriharsha Basavapatna /* 32197bd3a2e2SSriharsha Basavapatna * We handle the error and then return the error value. If we 32207bd3a2e2SSriharsha Basavapatna * are running in the context of the msg worker, the error 32217bd3a2e2SSriharsha Basavapatna * tells the worker thread to exit, as the channel would have 32227bd3a2e2SSriharsha Basavapatna * been reset. 32237bd3a2e2SSriharsha Basavapatna */ 3224844e62a3Sraghuram if (rv == ECONNRESET) { 3225844e62a3Sraghuram if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 3226844e62a3Sraghuram DWARN(vgenp, ldcp, "ldc_status err\n"); 3227844e62a3Sraghuram } else { 3228844e62a3Sraghuram ldcp->ldc_status = istatus; 3229844e62a3Sraghuram } 32307bd3a2e2SSriharsha Basavapatna (void) vgen_handle_evt_reset(ldcp, caller); 32317bd3a2e2SSriharsha Basavapatna } else { 32327bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "Calling vgen_ldc_reset()...\n"); 32337bd3a2e2SSriharsha Basavapatna (void) vgen_ldc_reset(ldcp, caller); 32347bd3a2e2SSriharsha Basavapatna } 3235844e62a3Sraghuram } 3236844e62a3Sraghuram 32377bd3a2e2SSriharsha Basavapatna if (caller == VGEN_MSG_THR) { 3238844e62a3Sraghuram mutex_exit(&ldcp->cblock); 3239844e62a3Sraghuram } 32401ae08745Sheppo 3241844e62a3Sraghuram DBG1(vgenp, ldcp, "exit\n"); 32427bd3a2e2SSriharsha Basavapatna return (rv); 32431ae08745Sheppo } 32441ae08745Sheppo 32451ae08745Sheppo /* vgen handshake functions */ 32461ae08745Sheppo 32471ae08745Sheppo /* change the hphase for the channel to the next phase */ 32481ae08745Sheppo static vgen_ldc_t * 32491ae08745Sheppo vh_nextphase(vgen_ldc_t *ldcp) 32501ae08745Sheppo { 32517bd3a2e2SSriharsha Basavapatna if (ldcp->hphase == VH_PHASE4) { 32521ae08745Sheppo ldcp->hphase = VH_DONE; 32531ae08745Sheppo } else { 32541ae08745Sheppo ldcp->hphase++; 32551ae08745Sheppo } 32561ae08745Sheppo return (ldcp); 32571ae08745Sheppo } 32581ae08745Sheppo 32591ae08745Sheppo /* send version negotiate message to the peer over ldc */ 32601ae08745Sheppo static int 32611ae08745Sheppo vgen_send_version_negotiate(vgen_ldc_t *ldcp) 32621ae08745Sheppo { 3263844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 32641ae08745Sheppo vio_ver_msg_t vermsg; 32651ae08745Sheppo vio_msg_tag_t *tagp = &vermsg.tag; 32661ae08745Sheppo int rv; 32671ae08745Sheppo 32681ae08745Sheppo bzero(&vermsg, sizeof (vermsg)); 32691ae08745Sheppo 32701ae08745Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 32711ae08745Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 32721ae08745Sheppo tagp->vio_subtype_env = VIO_VER_INFO; 32731ae08745Sheppo tagp->vio_sid = ldcp->local_sid; 32741ae08745Sheppo 32751ae08745Sheppo /* get version msg payload from ldcp->local */ 32761ae08745Sheppo vermsg.ver_major = ldcp->local_hparams.ver_major; 32771ae08745Sheppo vermsg.ver_minor = ldcp->local_hparams.ver_minor; 32781ae08745Sheppo vermsg.dev_class = ldcp->local_hparams.dev_class; 32791ae08745Sheppo 32801ae08745Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vermsg), B_FALSE); 32811ae08745Sheppo if (rv != VGEN_SUCCESS) { 3282844e62a3Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n"); 32833af08d82Slm66018 return (rv); 32841ae08745Sheppo } 32851ae08745Sheppo 32861ae08745Sheppo ldcp->hstate |= VER_INFO_SENT; 3287844e62a3Sraghuram DBG2(vgenp, ldcp, "VER_INFO_SENT ver(%d,%d)\n", 3288844e62a3Sraghuram vermsg.ver_major, vermsg.ver_minor); 32891ae08745Sheppo 32901ae08745Sheppo return (VGEN_SUCCESS); 32911ae08745Sheppo } 32921ae08745Sheppo 32931ae08745Sheppo /* send attr info message to the peer over ldc */ 32941ae08745Sheppo static int 32951ae08745Sheppo vgen_send_attr_info(vgen_ldc_t *ldcp) 32961ae08745Sheppo { 3297844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 32981ae08745Sheppo vnet_attr_msg_t attrmsg; 32991ae08745Sheppo vio_msg_tag_t *tagp = &attrmsg.tag; 33001ae08745Sheppo int rv; 33011ae08745Sheppo 33021ae08745Sheppo bzero(&attrmsg, sizeof (attrmsg)); 33031ae08745Sheppo 33041ae08745Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 33051ae08745Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 33061ae08745Sheppo tagp->vio_subtype_env = VIO_ATTR_INFO; 33071ae08745Sheppo tagp->vio_sid = ldcp->local_sid; 33081ae08745Sheppo 33091ae08745Sheppo /* get attr msg payload from ldcp->local */ 33101ae08745Sheppo attrmsg.mtu = ldcp->local_hparams.mtu; 33111ae08745Sheppo attrmsg.addr = ldcp->local_hparams.addr; 33121ae08745Sheppo attrmsg.addr_type = ldcp->local_hparams.addr_type; 33131ae08745Sheppo attrmsg.xfer_mode = ldcp->local_hparams.xfer_mode; 33141ae08745Sheppo attrmsg.ack_freq = ldcp->local_hparams.ack_freq; 33151107ea93SSriharsha Basavapatna attrmsg.physlink_update = ldcp->local_hparams.physlink_update; 33167bd3a2e2SSriharsha Basavapatna attrmsg.options = ldcp->local_hparams.dring_mode; 33171ae08745Sheppo 33181ae08745Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (attrmsg), B_FALSE); 33191ae08745Sheppo if (rv != VGEN_SUCCESS) { 3320844e62a3Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n"); 33213af08d82Slm66018 return (rv); 33221ae08745Sheppo } 33231ae08745Sheppo 33241ae08745Sheppo ldcp->hstate |= ATTR_INFO_SENT; 3325844e62a3Sraghuram DBG2(vgenp, ldcp, "ATTR_INFO_SENT\n"); 33261ae08745Sheppo 33271ae08745Sheppo return (VGEN_SUCCESS); 33281ae08745Sheppo } 33291ae08745Sheppo 33307bd3a2e2SSriharsha Basavapatna /* 33317bd3a2e2SSriharsha Basavapatna * Send descriptor ring register message to the peer over ldc. 33327bd3a2e2SSriharsha Basavapatna * Invoked in RxDringData mode. 33337bd3a2e2SSriharsha Basavapatna */ 33341ae08745Sheppo static int 33357bd3a2e2SSriharsha Basavapatna vgen_send_rx_dring_reg(vgen_ldc_t *ldcp) 33367bd3a2e2SSriharsha Basavapatna { 33377bd3a2e2SSriharsha Basavapatna vgen_t *vgenp = LDC_TO_VGEN(ldcp); 33387bd3a2e2SSriharsha Basavapatna vio_dring_reg_msg_t *msg; 33397bd3a2e2SSriharsha Basavapatna vio_dring_reg_ext_msg_t *emsg; 33407bd3a2e2SSriharsha Basavapatna int rv; 33417bd3a2e2SSriharsha Basavapatna uint8_t *buf; 33427bd3a2e2SSriharsha Basavapatna uint_t msgsize; 33437bd3a2e2SSriharsha Basavapatna 33447bd3a2e2SSriharsha Basavapatna msgsize = VNET_DRING_REG_EXT_MSG_SIZE(ldcp->rx_data_ncookies); 33457bd3a2e2SSriharsha Basavapatna msg = kmem_zalloc(msgsize, KM_SLEEP); 33467bd3a2e2SSriharsha Basavapatna 33477bd3a2e2SSriharsha Basavapatna /* Initialize the common part of dring reg msg */ 33487bd3a2e2SSriharsha Basavapatna vgen_init_dring_reg_msg(ldcp, msg, VIO_RX_DRING_DATA); 33497bd3a2e2SSriharsha Basavapatna 33507bd3a2e2SSriharsha Basavapatna /* skip over dring cookies at the tail of common section */ 33517bd3a2e2SSriharsha Basavapatna buf = (uint8_t *)msg->cookie; 33527bd3a2e2SSriharsha Basavapatna ASSERT(msg->ncookies == 1); 33537bd3a2e2SSriharsha Basavapatna buf += (msg->ncookies * sizeof (ldc_mem_cookie_t)); 33547bd3a2e2SSriharsha Basavapatna 33557bd3a2e2SSriharsha Basavapatna /* Now setup the extended part, specific to RxDringData mode */ 33567bd3a2e2SSriharsha Basavapatna emsg = (vio_dring_reg_ext_msg_t *)buf; 33577bd3a2e2SSriharsha Basavapatna 33587bd3a2e2SSriharsha Basavapatna /* copy data_ncookies in the msg */ 33597bd3a2e2SSriharsha Basavapatna emsg->data_ncookies = ldcp->rx_data_ncookies; 33607bd3a2e2SSriharsha Basavapatna 33617bd3a2e2SSriharsha Basavapatna /* copy data area size in the msg */ 33627bd3a2e2SSriharsha Basavapatna emsg->data_area_size = ldcp->rx_data_sz; 33637bd3a2e2SSriharsha Basavapatna 33647bd3a2e2SSriharsha Basavapatna /* copy data area cookies in the msg */ 33657bd3a2e2SSriharsha Basavapatna bcopy(ldcp->rx_data_cookie, (ldc_mem_cookie_t *)emsg->data_cookie, 33667bd3a2e2SSriharsha Basavapatna sizeof (ldc_mem_cookie_t) * ldcp->rx_data_ncookies); 33677bd3a2e2SSriharsha Basavapatna 33687bd3a2e2SSriharsha Basavapatna rv = vgen_sendmsg(ldcp, (caddr_t)msg, msgsize, B_FALSE); 33697bd3a2e2SSriharsha Basavapatna if (rv != VGEN_SUCCESS) { 33707bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "vgen_sendmsg failed\n"); 33717bd3a2e2SSriharsha Basavapatna kmem_free(msg, msgsize); 33727bd3a2e2SSriharsha Basavapatna return (rv); 33737bd3a2e2SSriharsha Basavapatna } 33747bd3a2e2SSriharsha Basavapatna 33757bd3a2e2SSriharsha Basavapatna ldcp->hstate |= DRING_INFO_SENT; 33767bd3a2e2SSriharsha Basavapatna DBG2(vgenp, ldcp, "DRING_INFO_SENT \n"); 33777bd3a2e2SSriharsha Basavapatna 33787bd3a2e2SSriharsha Basavapatna kmem_free(msg, msgsize); 33797bd3a2e2SSriharsha Basavapatna return (VGEN_SUCCESS); 33807bd3a2e2SSriharsha Basavapatna } 33817bd3a2e2SSriharsha Basavapatna 33827bd3a2e2SSriharsha Basavapatna /* 33837bd3a2e2SSriharsha Basavapatna * Send descriptor ring register message to the peer over ldc. 33847bd3a2e2SSriharsha Basavapatna * Invoked in TxDring mode. 33857bd3a2e2SSriharsha Basavapatna */ 33867bd3a2e2SSriharsha Basavapatna static int 33877bd3a2e2SSriharsha Basavapatna vgen_send_tx_dring_reg(vgen_ldc_t *ldcp) 33881ae08745Sheppo { 3389844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 33901ae08745Sheppo vio_dring_reg_msg_t msg; 33911ae08745Sheppo int rv; 33921ae08745Sheppo 33931ae08745Sheppo bzero(&msg, sizeof (msg)); 33941ae08745Sheppo 33951ae08745Sheppo /* 33967bd3a2e2SSriharsha Basavapatna * Initialize only the common part of dring reg msg in TxDring mode. 33971ae08745Sheppo */ 33987bd3a2e2SSriharsha Basavapatna vgen_init_dring_reg_msg(ldcp, &msg, VIO_TX_DRING); 33991ae08745Sheppo 34007bd3a2e2SSriharsha Basavapatna rv = vgen_sendmsg(ldcp, (caddr_t)&msg, sizeof (msg), B_FALSE); 34011ae08745Sheppo if (rv != VGEN_SUCCESS) { 3402844e62a3Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n"); 34033af08d82Slm66018 return (rv); 34041ae08745Sheppo } 34051ae08745Sheppo 34061ae08745Sheppo ldcp->hstate |= DRING_INFO_SENT; 3407844e62a3Sraghuram DBG2(vgenp, ldcp, "DRING_INFO_SENT \n"); 34081ae08745Sheppo 34091ae08745Sheppo return (VGEN_SUCCESS); 34101ae08745Sheppo } 34111ae08745Sheppo 34121ae08745Sheppo static int 34131ae08745Sheppo vgen_send_rdx_info(vgen_ldc_t *ldcp) 34141ae08745Sheppo { 3415844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 34161ae08745Sheppo vio_rdx_msg_t rdxmsg; 34171ae08745Sheppo vio_msg_tag_t *tagp = &rdxmsg.tag; 34181ae08745Sheppo int rv; 34191ae08745Sheppo 34201ae08745Sheppo bzero(&rdxmsg, sizeof (rdxmsg)); 34211ae08745Sheppo 34221ae08745Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 34231ae08745Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 34241ae08745Sheppo tagp->vio_subtype_env = VIO_RDX; 34251ae08745Sheppo tagp->vio_sid = ldcp->local_sid; 34261ae08745Sheppo 34271ae08745Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (rdxmsg), B_FALSE); 34281ae08745Sheppo if (rv != VGEN_SUCCESS) { 3429844e62a3Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n"); 34303af08d82Slm66018 return (rv); 34311ae08745Sheppo } 34321ae08745Sheppo 34331ae08745Sheppo ldcp->hstate |= RDX_INFO_SENT; 3434844e62a3Sraghuram DBG2(vgenp, ldcp, "RDX_INFO_SENT\n"); 34351ae08745Sheppo 34361ae08745Sheppo return (VGEN_SUCCESS); 34371ae08745Sheppo } 34381ae08745Sheppo 34391ae08745Sheppo /* send multicast addr info message to vsw */ 34401ae08745Sheppo static int 34411ae08745Sheppo vgen_send_mcast_info(vgen_ldc_t *ldcp) 34421ae08745Sheppo { 34431ae08745Sheppo vnet_mcast_msg_t mcastmsg; 34441ae08745Sheppo vnet_mcast_msg_t *msgp; 34451ae08745Sheppo vio_msg_tag_t *tagp; 34461ae08745Sheppo vgen_t *vgenp; 34471ae08745Sheppo struct ether_addr *mca; 34481ae08745Sheppo int rv; 34491ae08745Sheppo int i; 34501ae08745Sheppo uint32_t size; 34511ae08745Sheppo uint32_t mccount; 34521ae08745Sheppo uint32_t n; 34531ae08745Sheppo 34541ae08745Sheppo msgp = &mcastmsg; 34551ae08745Sheppo tagp = &msgp->tag; 34561ae08745Sheppo vgenp = LDC_TO_VGEN(ldcp); 34571ae08745Sheppo 34581ae08745Sheppo mccount = vgenp->mccount; 34591ae08745Sheppo i = 0; 34601ae08745Sheppo 34611ae08745Sheppo do { 34621ae08745Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 34631ae08745Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 34641ae08745Sheppo tagp->vio_subtype_env = VNET_MCAST_INFO; 34651ae08745Sheppo tagp->vio_sid = ldcp->local_sid; 34661ae08745Sheppo 34671ae08745Sheppo n = ((mccount >= VNET_NUM_MCAST) ? VNET_NUM_MCAST : mccount); 34681ae08745Sheppo size = n * sizeof (struct ether_addr); 34691ae08745Sheppo 34701ae08745Sheppo mca = &(vgenp->mctab[i]); 34711ae08745Sheppo bcopy(mca, (msgp->mca), size); 34721ae08745Sheppo msgp->set = B_TRUE; 34731ae08745Sheppo msgp->count = n; 34741ae08745Sheppo 34751ae08745Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp), 34761ae08745Sheppo B_FALSE); 34771ae08745Sheppo if (rv != VGEN_SUCCESS) { 3478844e62a3Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg err(%d)\n", rv); 34793af08d82Slm66018 return (rv); 34801ae08745Sheppo } 34811ae08745Sheppo 34821ae08745Sheppo mccount -= n; 34831ae08745Sheppo i += n; 34841ae08745Sheppo 34851ae08745Sheppo } while (mccount); 34861ae08745Sheppo 34871ae08745Sheppo return (VGEN_SUCCESS); 34881ae08745Sheppo } 34891ae08745Sheppo 34907bd3a2e2SSriharsha Basavapatna /* 34917bd3a2e2SSriharsha Basavapatna * vgen_dds_rx -- post DDS messages to vnet. 34927bd3a2e2SSriharsha Basavapatna */ 34937bd3a2e2SSriharsha Basavapatna static int 34947bd3a2e2SSriharsha Basavapatna vgen_dds_rx(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 34957bd3a2e2SSriharsha Basavapatna { 34967bd3a2e2SSriharsha Basavapatna vio_dds_msg_t *dmsg = (vio_dds_msg_t *)tagp; 34977bd3a2e2SSriharsha Basavapatna vgen_t *vgenp = LDC_TO_VGEN(ldcp); 34987bd3a2e2SSriharsha Basavapatna 34997bd3a2e2SSriharsha Basavapatna if (dmsg->dds_class != DDS_VNET_NIU) { 35007bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "Unknown DDS class, dropping"); 35017bd3a2e2SSriharsha Basavapatna return (EBADMSG); 35027bd3a2e2SSriharsha Basavapatna } 35037bd3a2e2SSriharsha Basavapatna vnet_dds_rx(vgenp->vnetp, dmsg); 35047bd3a2e2SSriharsha Basavapatna return (0); 35057bd3a2e2SSriharsha Basavapatna } 35067bd3a2e2SSriharsha Basavapatna 35077bd3a2e2SSriharsha Basavapatna /* 35087bd3a2e2SSriharsha Basavapatna * vgen_dds_tx -- an interface called by vnet to send DDS messages. 35097bd3a2e2SSriharsha Basavapatna */ 35107bd3a2e2SSriharsha Basavapatna int 35117bd3a2e2SSriharsha Basavapatna vgen_dds_tx(void *arg, void *msg) 35127bd3a2e2SSriharsha Basavapatna { 35137bd3a2e2SSriharsha Basavapatna vgen_t *vgenp = arg; 35147bd3a2e2SSriharsha Basavapatna vio_dds_msg_t *dmsg = msg; 35157bd3a2e2SSriharsha Basavapatna vgen_portlist_t *plistp = &vgenp->vgenports; 35167bd3a2e2SSriharsha Basavapatna vgen_ldc_t *ldcp; 35177bd3a2e2SSriharsha Basavapatna int rv = EIO; 35187bd3a2e2SSriharsha Basavapatna 35197bd3a2e2SSriharsha Basavapatna READ_ENTER(&plistp->rwlock); 35207bd3a2e2SSriharsha Basavapatna ldcp = vgenp->vsw_portp->ldcp; 35217bd3a2e2SSriharsha Basavapatna if ((ldcp == NULL) || (ldcp->hphase != VH_DONE)) { 35227bd3a2e2SSriharsha Basavapatna goto vgen_dsend_exit; 35237bd3a2e2SSriharsha Basavapatna } 35247bd3a2e2SSriharsha Basavapatna 35257bd3a2e2SSriharsha Basavapatna dmsg->tag.vio_sid = ldcp->local_sid; 35267bd3a2e2SSriharsha Basavapatna rv = vgen_sendmsg(ldcp, (caddr_t)dmsg, sizeof (vio_dds_msg_t), B_FALSE); 35277bd3a2e2SSriharsha Basavapatna if (rv != VGEN_SUCCESS) { 35287bd3a2e2SSriharsha Basavapatna rv = EIO; 35297bd3a2e2SSriharsha Basavapatna } else { 35307bd3a2e2SSriharsha Basavapatna rv = 0; 35317bd3a2e2SSriharsha Basavapatna } 35327bd3a2e2SSriharsha Basavapatna 35337bd3a2e2SSriharsha Basavapatna vgen_dsend_exit: 35347bd3a2e2SSriharsha Basavapatna RW_EXIT(&plistp->rwlock); 35357bd3a2e2SSriharsha Basavapatna return (rv); 35367bd3a2e2SSriharsha Basavapatna 35377bd3a2e2SSriharsha Basavapatna } 35387bd3a2e2SSriharsha Basavapatna 35391ae08745Sheppo /* Initiate Phase 2 of handshake */ 35401ae08745Sheppo static int 35411ae08745Sheppo vgen_handshake_phase2(vgen_ldc_t *ldcp) 35421ae08745Sheppo { 35431ae08745Sheppo int rv; 3544844e62a3Sraghuram 35451ae08745Sheppo #ifdef DEBUG 35467bd3a2e2SSriharsha Basavapatna if (vgen_inject_error(ldcp, VGEN_ERR_HSTATE)) { 35471ae08745Sheppo /* simulate out of state condition */ 35487bd3a2e2SSriharsha Basavapatna vgen_inject_err_flag &= ~(VGEN_ERR_HSTATE); 35491ae08745Sheppo rv = vgen_send_rdx_info(ldcp); 35501ae08745Sheppo return (rv); 35511ae08745Sheppo } 35527bd3a2e2SSriharsha Basavapatna if (vgen_inject_error(ldcp, VGEN_ERR_HTIMEOUT)) { 35531ae08745Sheppo /* simulate timeout condition */ 35547bd3a2e2SSriharsha Basavapatna vgen_inject_err_flag &= ~(VGEN_ERR_HTIMEOUT); 35551ae08745Sheppo return (VGEN_SUCCESS); 35561ae08745Sheppo } 35571ae08745Sheppo #endif 35583af08d82Slm66018 rv = vgen_send_attr_info(ldcp); 35593af08d82Slm66018 if (rv != VGEN_SUCCESS) { 35601ae08745Sheppo return (rv); 35611ae08745Sheppo } 35623af08d82Slm66018 35637bd3a2e2SSriharsha Basavapatna return (VGEN_SUCCESS); 35643af08d82Slm66018 } 35657bd3a2e2SSriharsha Basavapatna 35667bd3a2e2SSriharsha Basavapatna static int 35677bd3a2e2SSriharsha Basavapatna vgen_handshake_phase3(vgen_ldc_t *ldcp) 35687bd3a2e2SSriharsha Basavapatna { 35697bd3a2e2SSriharsha Basavapatna int rv; 35707bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams; 35717bd3a2e2SSriharsha Basavapatna vgen_t *vgenp = LDC_TO_VGEN(ldcp); 35727bd3a2e2SSriharsha Basavapatna vgen_stats_t *statsp = &ldcp->stats; 35737bd3a2e2SSriharsha Basavapatna 35747bd3a2e2SSriharsha Basavapatna /* dring mode has been negotiated in attr phase; save in stats */ 35757bd3a2e2SSriharsha Basavapatna statsp->dring_mode = lp->dring_mode; 35767bd3a2e2SSriharsha Basavapatna 35777bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_RX_DRING_DATA) { /* RxDringData mode */ 35787bd3a2e2SSriharsha Basavapatna ldcp->rx_dringdata = vgen_handle_dringdata_shm; 35797bd3a2e2SSriharsha Basavapatna ldcp->tx_dringdata = vgen_dringsend_shm; 35807bd3a2e2SSriharsha Basavapatna if (!VGEN_PRI_ETH_DEFINED(vgenp)) { 35817bd3a2e2SSriharsha Basavapatna /* 35827bd3a2e2SSriharsha Basavapatna * If priority frames are not in use, we don't need a 35837bd3a2e2SSriharsha Basavapatna * separate wrapper function for 'tx', so we set it to 35847bd3a2e2SSriharsha Basavapatna * 'tx_dringdata'. If priority frames are configured, 35857bd3a2e2SSriharsha Basavapatna * we leave the 'tx' pointer as is (initialized in 35867bd3a2e2SSriharsha Basavapatna * vgen_set_vnet_proto_ops()). 35877bd3a2e2SSriharsha Basavapatna */ 35887bd3a2e2SSriharsha Basavapatna ldcp->tx = ldcp->tx_dringdata; 35897bd3a2e2SSriharsha Basavapatna } 35907bd3a2e2SSriharsha Basavapatna } else { /* TxDring mode */ 35917bd3a2e2SSriharsha Basavapatna ldcp->msg_thread = thread_create(NULL, 35927bd3a2e2SSriharsha Basavapatna 2 * DEFAULTSTKSZ, vgen_ldc_msg_worker, ldcp, 0, 35937bd3a2e2SSriharsha Basavapatna &p0, TS_RUN, maxclsyspri); 35947bd3a2e2SSriharsha Basavapatna } 35957bd3a2e2SSriharsha Basavapatna 35967bd3a2e2SSriharsha Basavapatna rv = vgen_create_dring(ldcp); 35977bd3a2e2SSriharsha Basavapatna if (rv != VGEN_SUCCESS) { 35987bd3a2e2SSriharsha Basavapatna return (rv); 35993af08d82Slm66018 } 36003af08d82Slm66018 36013af08d82Slm66018 /* update local dring_info params */ 36027bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_RX_DRING_DATA) { 36037bd3a2e2SSriharsha Basavapatna bcopy(&(ldcp->rx_dring_cookie), 36047bd3a2e2SSriharsha Basavapatna &(ldcp->local_hparams.dring_cookie), 36053af08d82Slm66018 sizeof (ldc_mem_cookie_t)); 36067bd3a2e2SSriharsha Basavapatna ldcp->local_hparams.dring_ncookies = ldcp->rx_dring_ncookies; 36077bd3a2e2SSriharsha Basavapatna ldcp->local_hparams.num_desc = ldcp->num_rxds; 36087bd3a2e2SSriharsha Basavapatna ldcp->local_hparams.desc_size = 36097bd3a2e2SSriharsha Basavapatna sizeof (vnet_rx_dringdata_desc_t); 36107bd3a2e2SSriharsha Basavapatna rv = vgen_send_rx_dring_reg(ldcp); 36117bd3a2e2SSriharsha Basavapatna } else { 36127bd3a2e2SSriharsha Basavapatna bcopy(&(ldcp->tx_dring_cookie), 36137bd3a2e2SSriharsha Basavapatna &(ldcp->local_hparams.dring_cookie), 36147bd3a2e2SSriharsha Basavapatna sizeof (ldc_mem_cookie_t)); 36157bd3a2e2SSriharsha Basavapatna ldcp->local_hparams.dring_ncookies = ldcp->tx_dring_ncookies; 36163af08d82Slm66018 ldcp->local_hparams.num_desc = ldcp->num_txds; 36173af08d82Slm66018 ldcp->local_hparams.desc_size = sizeof (vnet_public_desc_t); 36187bd3a2e2SSriharsha Basavapatna rv = vgen_send_tx_dring_reg(ldcp); 36197bd3a2e2SSriharsha Basavapatna } 36203af08d82Slm66018 36213af08d82Slm66018 if (rv != VGEN_SUCCESS) { 36221ae08745Sheppo return (rv); 36231ae08745Sheppo } 36241ae08745Sheppo 36251ae08745Sheppo return (VGEN_SUCCESS); 36261ae08745Sheppo } 36271ae08745Sheppo 36281ae08745Sheppo /* 3629f0ca1d9aSsb155480 * Set vnet-protocol-version dependent functions based on version. 3630f0ca1d9aSsb155480 */ 3631f0ca1d9aSsb155480 static void 3632f0ca1d9aSsb155480 vgen_set_vnet_proto_ops(vgen_ldc_t *ldcp) 3633f0ca1d9aSsb155480 { 3634f0ca1d9aSsb155480 vgen_hparams_t *lp = &ldcp->local_hparams; 3635f0ca1d9aSsb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 3636f0ca1d9aSsb155480 36377bd3a2e2SSriharsha Basavapatna /* 36387bd3a2e2SSriharsha Basavapatna * Setup the appropriate dring data processing routine and any 36397bd3a2e2SSriharsha Basavapatna * associated thread based on the version. 36407bd3a2e2SSriharsha Basavapatna * 36417bd3a2e2SSriharsha Basavapatna * In versions < 1.6, we only support TxDring mode. In this mode, the 36427bd3a2e2SSriharsha Basavapatna * msg worker thread processes all types of VIO msgs (ctrl and data). 36437bd3a2e2SSriharsha Basavapatna * 36447bd3a2e2SSriharsha Basavapatna * In versions >= 1.6, we also support RxDringData mode. In this mode, 36457bd3a2e2SSriharsha Basavapatna * all msgs including dring data messages are handled directly by the 36467bd3a2e2SSriharsha Basavapatna * callback (intr) thread. The dring data msgs (msgtype: VIO_TYPE_DATA, 36477bd3a2e2SSriharsha Basavapatna * subtype: VIO_SUBTYPE_INFO, subtype_env: VIO_DRING_DATA) can also be 36487bd3a2e2SSriharsha Basavapatna * disabled while the polling thread is active, in which case the 36497bd3a2e2SSriharsha Basavapatna * polling thread processes the rcv descriptor ring. 36507bd3a2e2SSriharsha Basavapatna * 36517bd3a2e2SSriharsha Basavapatna * However, for versions >= 1.6, we can force to only use TxDring mode. 36527bd3a2e2SSriharsha Basavapatna * This could happen if RxDringData mode has been disabled (see 3653*34f94fbcSWENTAO YANG * below) on this guest or on the peer guest. This info is determined 3654*34f94fbcSWENTAO YANG * as part of attr exchange phase of handshake. Hence, we setup these 3655*34f94fbcSWENTAO YANG * pointers for v1.6 after attr msg phase completes during handshake. 36567bd3a2e2SSriharsha Basavapatna */ 36577bd3a2e2SSriharsha Basavapatna if (VGEN_VER_GTEQ(ldcp, 1, 6)) { /* Ver >= 1.6 */ 36587bd3a2e2SSriharsha Basavapatna /* 36597bd3a2e2SSriharsha Basavapatna * Set data dring mode for vgen_send_attr_info(). 36607bd3a2e2SSriharsha Basavapatna */ 3661*34f94fbcSWENTAO YANG if (vgen_mapin_avail(ldcp) == B_TRUE) { 36627bd3a2e2SSriharsha Basavapatna lp->dring_mode = (VIO_RX_DRING_DATA | VIO_TX_DRING); 36637bd3a2e2SSriharsha Basavapatna } else { 36647bd3a2e2SSriharsha Basavapatna lp->dring_mode = VIO_TX_DRING; 36657bd3a2e2SSriharsha Basavapatna } 36667bd3a2e2SSriharsha Basavapatna } else { /* Ver <= 1.5 */ 36677bd3a2e2SSriharsha Basavapatna lp->dring_mode = VIO_TX_DRING; 36687bd3a2e2SSriharsha Basavapatna } 36697bd3a2e2SSriharsha Basavapatna 36701107ea93SSriharsha Basavapatna if (VGEN_VER_GTEQ(ldcp, 1, 5)) { 36711107ea93SSriharsha Basavapatna vgen_port_t *portp = ldcp->portp; 36721107ea93SSriharsha Basavapatna vnet_t *vnetp = vgenp->vnetp; 36731107ea93SSriharsha Basavapatna /* 36741107ea93SSriharsha Basavapatna * If the version negotiated with vswitch is >= 1.5 (link 36751107ea93SSriharsha Basavapatna * status update support), set the required bits in our 36761107ea93SSriharsha Basavapatna * attributes if this vnet device has been configured to get 36771107ea93SSriharsha Basavapatna * physical link state updates. 36781107ea93SSriharsha Basavapatna */ 36791107ea93SSriharsha Basavapatna if (portp == vgenp->vsw_portp && vnetp->pls_update == B_TRUE) { 36801107ea93SSriharsha Basavapatna lp->physlink_update = PHYSLINK_UPDATE_STATE; 36811107ea93SSriharsha Basavapatna } else { 36821107ea93SSriharsha Basavapatna lp->physlink_update = PHYSLINK_UPDATE_NONE; 36831107ea93SSriharsha Basavapatna } 36841107ea93SSriharsha Basavapatna } 36851107ea93SSriharsha Basavapatna 36867b1f684aSSriharsha Basavapatna if (VGEN_VER_GTEQ(ldcp, 1, 4)) { 3687c1c61f44Ssb155480 /* 36887b1f684aSSriharsha Basavapatna * If the version negotiated with peer is >= 1.4(Jumbo Frame 36897b1f684aSSriharsha Basavapatna * Support), set the mtu in our attributes to max_frame_size. 3690c1c61f44Ssb155480 */ 3691c1c61f44Ssb155480 lp->mtu = vgenp->max_frame_size; 36927b1f684aSSriharsha Basavapatna } else if (VGEN_VER_EQ(ldcp, 1, 3)) { 36937b1f684aSSriharsha Basavapatna /* 36947b1f684aSSriharsha Basavapatna * If the version negotiated with peer is == 1.3 (Vlan Tag 36957b1f684aSSriharsha Basavapatna * Support) set the attr.mtu to ETHERMAX + VLAN_TAGSZ. 36967b1f684aSSriharsha Basavapatna */ 36977b1f684aSSriharsha Basavapatna lp->mtu = ETHERMAX + VLAN_TAGSZ; 3698c1c61f44Ssb155480 } else { 3699c1c61f44Ssb155480 vgen_port_t *portp = ldcp->portp; 3700c1c61f44Ssb155480 vnet_t *vnetp = vgenp->vnetp; 3701c1c61f44Ssb155480 /* 3702c1c61f44Ssb155480 * Pre-1.3 peers expect max frame size of ETHERMAX. 3703c1c61f44Ssb155480 * We can negotiate that size with those peers provided the 3704c1c61f44Ssb155480 * following conditions are true: 3705c1c61f44Ssb155480 * - Only pvid is defined for our peer and there are no vids. 3706c1c61f44Ssb155480 * - pvids are equal. 3707c1c61f44Ssb155480 * If the above conditions are true, then we can send/recv only 3708c1c61f44Ssb155480 * untagged frames of max size ETHERMAX. 3709c1c61f44Ssb155480 */ 37107b1f684aSSriharsha Basavapatna if (portp->nvids == 0 && portp->pvid == vnetp->pvid) { 3711c1c61f44Ssb155480 lp->mtu = ETHERMAX; 3712c1c61f44Ssb155480 } 3713c1c61f44Ssb155480 } 3714c1c61f44Ssb155480 37157bd3a2e2SSriharsha Basavapatna if (VGEN_VER_GTEQ(ldcp, 1, 2)) { /* Versions >= 1.2 */ 37167bd3a2e2SSriharsha Basavapatna /* 37177bd3a2e2SSriharsha Basavapatna * Starting v1.2 we support priority frames; so set the 37187bd3a2e2SSriharsha Basavapatna * dring processing routines and xfer modes based on the 37197bd3a2e2SSriharsha Basavapatna * version. Note that the dring routines could be changed after 37207bd3a2e2SSriharsha Basavapatna * attribute handshake phase for versions >= 1.6 (See 37217bd3a2e2SSriharsha Basavapatna * vgen_handshake_phase3()) 37227bd3a2e2SSriharsha Basavapatna */ 37237bd3a2e2SSriharsha Basavapatna ldcp->tx_dringdata = vgen_dringsend; 37247bd3a2e2SSriharsha Basavapatna ldcp->rx_dringdata = vgen_handle_dringdata; 3725f0ca1d9aSsb155480 3726f0ca1d9aSsb155480 if (VGEN_PRI_ETH_DEFINED(vgenp)) { 3727f0ca1d9aSsb155480 /* 37287bd3a2e2SSriharsha Basavapatna * Enable priority routines and pkt mode only if 3729f0ca1d9aSsb155480 * at least one pri-eth-type is specified in MD. 3730f0ca1d9aSsb155480 */ 3731f0ca1d9aSsb155480 ldcp->tx = vgen_ldcsend; 3732f0ca1d9aSsb155480 ldcp->rx_pktdata = vgen_handle_pkt_data; 3733f0ca1d9aSsb155480 3734f0ca1d9aSsb155480 /* set xfer mode for vgen_send_attr_info() */ 3735f0ca1d9aSsb155480 lp->xfer_mode = VIO_PKT_MODE | VIO_DRING_MODE_V1_2; 3736f0ca1d9aSsb155480 } else { 37377bd3a2e2SSriharsha Basavapatna /* No priority eth types defined in MD */ 37387bd3a2e2SSriharsha Basavapatna ldcp->tx = ldcp->tx_dringdata; 3739f0ca1d9aSsb155480 ldcp->rx_pktdata = vgen_handle_pkt_data_nop; 3740f0ca1d9aSsb155480 37417bd3a2e2SSriharsha Basavapatna /* Set xfer mode for vgen_send_attr_info() */ 3742f0ca1d9aSsb155480 lp->xfer_mode = VIO_DRING_MODE_V1_2; 3743f0ca1d9aSsb155480 } 37447bd3a2e2SSriharsha Basavapatna } else { /* Versions prior to 1.2 */ 3745f0ca1d9aSsb155480 vgen_reset_vnet_proto_ops(ldcp); 3746f0ca1d9aSsb155480 } 3747f0ca1d9aSsb155480 } 3748f0ca1d9aSsb155480 3749f0ca1d9aSsb155480 /* 3750f0ca1d9aSsb155480 * Reset vnet-protocol-version dependent functions to pre-v1.2. 3751f0ca1d9aSsb155480 */ 3752f0ca1d9aSsb155480 static void 3753f0ca1d9aSsb155480 vgen_reset_vnet_proto_ops(vgen_ldc_t *ldcp) 3754f0ca1d9aSsb155480 { 3755f0ca1d9aSsb155480 vgen_hparams_t *lp = &ldcp->local_hparams; 3756f0ca1d9aSsb155480 37577bd3a2e2SSriharsha Basavapatna ldcp->tx = ldcp->tx_dringdata = vgen_dringsend; 37587bd3a2e2SSriharsha Basavapatna ldcp->rx_dringdata = vgen_handle_dringdata; 3759f0ca1d9aSsb155480 ldcp->rx_pktdata = vgen_handle_pkt_data_nop; 3760f0ca1d9aSsb155480 3761f0ca1d9aSsb155480 /* set xfer mode for vgen_send_attr_info() */ 3762f0ca1d9aSsb155480 lp->xfer_mode = VIO_DRING_MODE_V1_0; 3763f0ca1d9aSsb155480 } 3764f0ca1d9aSsb155480 3765c1c61f44Ssb155480 static void 3766c1c61f44Ssb155480 vgen_vlan_unaware_port_reset(vgen_port_t *portp) 3767c1c61f44Ssb155480 { 37687bd3a2e2SSriharsha Basavapatna vgen_ldc_t *ldcp = portp->ldcp; 3769c1c61f44Ssb155480 vgen_t *vgenp = portp->vgenp; 3770c1c61f44Ssb155480 vnet_t *vnetp = vgenp->vnetp; 37717bd3a2e2SSriharsha Basavapatna boolean_t need_reset = B_FALSE; 3772c1c61f44Ssb155480 3773c1c61f44Ssb155480 mutex_enter(&ldcp->cblock); 3774c1c61f44Ssb155480 3775c1c61f44Ssb155480 /* 3776c1c61f44Ssb155480 * If the peer is vlan_unaware(ver < 1.3), reset channel and terminate 3777c1c61f44Ssb155480 * the connection. See comments in vgen_set_vnet_proto_ops(). 3778c1c61f44Ssb155480 */ 3779c1c61f44Ssb155480 if (ldcp->hphase == VH_DONE && VGEN_VER_LT(ldcp, 1, 3) && 3780c1c61f44Ssb155480 (portp->nvids != 0 || portp->pvid != vnetp->pvid)) { 37817bd3a2e2SSriharsha Basavapatna need_reset = B_TRUE; 3782c1c61f44Ssb155480 } 3783c1c61f44Ssb155480 mutex_exit(&ldcp->cblock); 3784c1c61f44Ssb155480 37857bd3a2e2SSriharsha Basavapatna if (need_reset == B_TRUE) { 37867bd3a2e2SSriharsha Basavapatna (void) vgen_ldc_reset(ldcp, VGEN_OTHER); 37877bd3a2e2SSriharsha Basavapatna } 3788c1c61f44Ssb155480 } 3789c1c61f44Ssb155480 3790c1c61f44Ssb155480 static void 37911107ea93SSriharsha Basavapatna vgen_port_reset(vgen_port_t *portp) 37921107ea93SSriharsha Basavapatna { 37937bd3a2e2SSriharsha Basavapatna (void) vgen_ldc_reset(portp->ldcp, VGEN_OTHER); 37941107ea93SSriharsha Basavapatna } 37951107ea93SSriharsha Basavapatna 37961107ea93SSriharsha Basavapatna static void 3797c1c61f44Ssb155480 vgen_reset_vlan_unaware_ports(vgen_t *vgenp) 3798c1c61f44Ssb155480 { 3799c1c61f44Ssb155480 vgen_port_t *portp; 3800c1c61f44Ssb155480 vgen_portlist_t *plistp; 3801c1c61f44Ssb155480 3802c1c61f44Ssb155480 plistp = &(vgenp->vgenports); 3803c1c61f44Ssb155480 READ_ENTER(&plistp->rwlock); 3804c1c61f44Ssb155480 3805c1c61f44Ssb155480 for (portp = plistp->headp; portp != NULL; portp = portp->nextp) { 3806c1c61f44Ssb155480 3807c1c61f44Ssb155480 vgen_vlan_unaware_port_reset(portp); 3808c1c61f44Ssb155480 3809c1c61f44Ssb155480 } 3810c1c61f44Ssb155480 3811c1c61f44Ssb155480 RW_EXIT(&plistp->rwlock); 3812c1c61f44Ssb155480 } 3813c1c61f44Ssb155480 38141107ea93SSriharsha Basavapatna static void 38151107ea93SSriharsha Basavapatna vgen_reset_vsw_port(vgen_t *vgenp) 38161107ea93SSriharsha Basavapatna { 38171107ea93SSriharsha Basavapatna vgen_port_t *portp; 38181107ea93SSriharsha Basavapatna 38191107ea93SSriharsha Basavapatna if ((portp = vgenp->vsw_portp) != NULL) { 38201107ea93SSriharsha Basavapatna vgen_port_reset(portp); 38211107ea93SSriharsha Basavapatna } 38221107ea93SSriharsha Basavapatna } 38231107ea93SSriharsha Basavapatna 38241ae08745Sheppo static void 38257bd3a2e2SSriharsha Basavapatna vgen_setup_handshake_params(vgen_ldc_t *ldcp) 38261ae08745Sheppo { 38271ae08745Sheppo vgen_t *vgenp = LDC_TO_VGEN(ldcp); 38281ae08745Sheppo 38291ae08745Sheppo /* 38301ae08745Sheppo * clear local handshake params and initialize. 38311ae08745Sheppo */ 38321ae08745Sheppo bzero(&(ldcp->local_hparams), sizeof (ldcp->local_hparams)); 38331ae08745Sheppo 38341ae08745Sheppo /* set version to the highest version supported */ 38351ae08745Sheppo ldcp->local_hparams.ver_major = 38361ae08745Sheppo ldcp->vgen_versions[0].ver_major; 38371ae08745Sheppo ldcp->local_hparams.ver_minor = 38381ae08745Sheppo ldcp->vgen_versions[0].ver_minor; 38391ae08745Sheppo ldcp->local_hparams.dev_class = VDEV_NETWORK; 38401ae08745Sheppo 38411ae08745Sheppo /* set attr_info params */ 3842c1c61f44Ssb155480 ldcp->local_hparams.mtu = vgenp->max_frame_size; 38431ae08745Sheppo ldcp->local_hparams.addr = 3844f2b610cfSwentaoy vnet_macaddr_strtoul(vgenp->macaddr); 38451ae08745Sheppo ldcp->local_hparams.addr_type = ADDR_TYPE_MAC; 3846f0ca1d9aSsb155480 ldcp->local_hparams.xfer_mode = VIO_DRING_MODE_V1_0; 38471ae08745Sheppo ldcp->local_hparams.ack_freq = 0; /* don't need acks */ 38481107ea93SSriharsha Basavapatna ldcp->local_hparams.physlink_update = PHYSLINK_UPDATE_NONE; 38491ae08745Sheppo 38507bd3a2e2SSriharsha Basavapatna /* reset protocol version specific function pointers */ 38517bd3a2e2SSriharsha Basavapatna vgen_reset_vnet_proto_ops(ldcp); 38521ae08745Sheppo ldcp->local_hparams.dring_ident = 0; 38537bd3a2e2SSriharsha Basavapatna ldcp->local_hparams.dring_ready = B_FALSE; 38541ae08745Sheppo 38551ae08745Sheppo /* clear peer_hparams */ 38561ae08745Sheppo bzero(&(ldcp->peer_hparams), sizeof (ldcp->peer_hparams)); 38577bd3a2e2SSriharsha Basavapatna ldcp->peer_hparams.dring_ready = B_FALSE; 38583af08d82Slm66018 } 38593af08d82Slm66018 38607bd3a2e2SSriharsha Basavapatna /* 38617bd3a2e2SSriharsha Basavapatna * Process Channel Reset. We tear down the resources (timers, threads, 38627bd3a2e2SSriharsha Basavapatna * descriptor rings etc) associated with the channel and reinitialize the 38637bd3a2e2SSriharsha Basavapatna * channel based on the flags. 38647bd3a2e2SSriharsha Basavapatna * 38657bd3a2e2SSriharsha Basavapatna * Arguments: 38667bd3a2e2SSriharsha Basavapatna * ldcp: The channel being processed. 38677bd3a2e2SSriharsha Basavapatna * 38687bd3a2e2SSriharsha Basavapatna * flags: 38697bd3a2e2SSriharsha Basavapatna * VGEN_FLAG_EVT_RESET: 38707bd3a2e2SSriharsha Basavapatna * A ECONNRESET error occured while doing ldc operations such as 38717bd3a2e2SSriharsha Basavapatna * ldc_read() or ldc_write(); the channel is already reset and it 38727bd3a2e2SSriharsha Basavapatna * needs to be handled. 38737bd3a2e2SSriharsha Basavapatna * VGEN_FLAG_NEED_LDCRESET: 38747bd3a2e2SSriharsha Basavapatna * Some other errors occured and the error handling code needs to 38757bd3a2e2SSriharsha Basavapatna * explicitly reset the channel and restart handshake with the 38767bd3a2e2SSriharsha Basavapatna * peer. The error could be either in ldc operations or other 38777bd3a2e2SSriharsha Basavapatna * parts of the code such as timeouts or mdeg events etc. 38787bd3a2e2SSriharsha Basavapatna * VGEN_FLAG_UNINIT: 38797bd3a2e2SSriharsha Basavapatna * The channel is being torn down; no need to bring up the channel 38807bd3a2e2SSriharsha Basavapatna * after resetting. 38817bd3a2e2SSriharsha Basavapatna */ 38827bd3a2e2SSriharsha Basavapatna static int 38837bd3a2e2SSriharsha Basavapatna vgen_process_reset(vgen_ldc_t *ldcp, int flags) 38841ae08745Sheppo { 38851107ea93SSriharsha Basavapatna vgen_t *vgenp = LDC_TO_VGEN(ldcp); 38867bd3a2e2SSriharsha Basavapatna vgen_port_t *portp = ldcp->portp; 38877bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams; 38887bd3a2e2SSriharsha Basavapatna boolean_t is_vsw_port = B_FALSE; 38897bd3a2e2SSriharsha Basavapatna boolean_t link_update = B_FALSE; 38907bd3a2e2SSriharsha Basavapatna ldc_status_t istatus; 38917bd3a2e2SSriharsha Basavapatna int rv; 38927bd3a2e2SSriharsha Basavapatna uint_t retries = 0; 38937bd3a2e2SSriharsha Basavapatna timeout_id_t htid = 0; 38947bd3a2e2SSriharsha Basavapatna timeout_id_t wd_tid = 0; 38951107ea93SSriharsha Basavapatna 38967bd3a2e2SSriharsha Basavapatna if (portp == vgenp->vsw_portp) { /* vswitch port ? */ 38977bd3a2e2SSriharsha Basavapatna is_vsw_port = B_TRUE; 38987bd3a2e2SSriharsha Basavapatna } 38991ae08745Sheppo 39007bd3a2e2SSriharsha Basavapatna /* 39017bd3a2e2SSriharsha Basavapatna * Report that the channel is being reset; it ensures that any HybridIO 39027bd3a2e2SSriharsha Basavapatna * configuration is torn down before we reset the channel if it is not 39037bd3a2e2SSriharsha Basavapatna * already reset (flags == VGEN_FLAG_NEED_LDCRESET). 39047bd3a2e2SSriharsha Basavapatna */ 39057bd3a2e2SSriharsha Basavapatna if (is_vsw_port == B_TRUE) { 39067bd3a2e2SSriharsha Basavapatna vio_net_report_err_t rep_err = portp->vcb.vio_net_report_err; 39077bd3a2e2SSriharsha Basavapatna rep_err(portp->vhp, VIO_NET_RES_DOWN); 39087bd3a2e2SSriharsha Basavapatna } 39091ae08745Sheppo 39107bd3a2e2SSriharsha Basavapatna again: 39117bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->cblock); 39127bd3a2e2SSriharsha Basavapatna 39137bd3a2e2SSriharsha Basavapatna /* Clear hstate and hphase */ 39147bd3a2e2SSriharsha Basavapatna ldcp->hstate = 0; 39157bd3a2e2SSriharsha Basavapatna ldcp->hphase = VH_PHASE0; 39167bd3a2e2SSriharsha Basavapatna if (flags == VGEN_FLAG_NEED_LDCRESET || flags == VGEN_FLAG_UNINIT) { 39177bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "Doing Channel Reset...\n"); 39187bd3a2e2SSriharsha Basavapatna (void) ldc_down(ldcp->ldc_handle); 39197bd3a2e2SSriharsha Basavapatna (void) ldc_status(ldcp->ldc_handle, &istatus); 39207bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "Reset Done, ldc_status(%d)\n", istatus); 39217bd3a2e2SSriharsha Basavapatna ldcp->ldc_status = istatus; 39227bd3a2e2SSriharsha Basavapatna 39237bd3a2e2SSriharsha Basavapatna if (flags == VGEN_FLAG_UNINIT) { 39247bd3a2e2SSriharsha Basavapatna /* disable further callbacks */ 39257bd3a2e2SSriharsha Basavapatna rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE); 39267bd3a2e2SSriharsha Basavapatna if (rv != 0) { 39277bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "ldc_set_cb_mode failed\n"); 39287bd3a2e2SSriharsha Basavapatna } 39297bd3a2e2SSriharsha Basavapatna } 39307bd3a2e2SSriharsha Basavapatna 39317bd3a2e2SSriharsha Basavapatna } else { 39327bd3a2e2SSriharsha Basavapatna /* flags == VGEN_FLAG_EVT_RESET */ 39337bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "ldc status(%d)\n", ldcp->ldc_status); 39347bd3a2e2SSriharsha Basavapatna } 39351107ea93SSriharsha Basavapatna 39361107ea93SSriharsha Basavapatna /* 39371107ea93SSriharsha Basavapatna * As the connection is now reset, mark the channel 39381107ea93SSriharsha Basavapatna * link_state as 'down' and notify the stack if needed. 39391107ea93SSriharsha Basavapatna */ 39401107ea93SSriharsha Basavapatna if (ldcp->link_state != LINK_STATE_DOWN) { 39411107ea93SSriharsha Basavapatna ldcp->link_state = LINK_STATE_DOWN; 39421107ea93SSriharsha Basavapatna 39437bd3a2e2SSriharsha Basavapatna if (is_vsw_port == B_TRUE) { /* vswitch port ? */ 39441107ea93SSriharsha Basavapatna /* 39451107ea93SSriharsha Basavapatna * As the channel link is down, mark physical link also 39461107ea93SSriharsha Basavapatna * as down. After the channel comes back up and 39471107ea93SSriharsha Basavapatna * handshake completes, we will get an update on the 39481107ea93SSriharsha Basavapatna * physlink state from vswitch (if this device has been 39491107ea93SSriharsha Basavapatna * configured to get phys link updates). 39501107ea93SSriharsha Basavapatna */ 39511107ea93SSriharsha Basavapatna vgenp->phys_link_state = LINK_STATE_DOWN; 39527bd3a2e2SSriharsha Basavapatna link_update = B_TRUE; 39531107ea93SSriharsha Basavapatna 39547bd3a2e2SSriharsha Basavapatna } 39557bd3a2e2SSriharsha Basavapatna } 39567bd3a2e2SSriharsha Basavapatna 39577bd3a2e2SSriharsha Basavapatna if (ldcp->htid != 0) { 39587bd3a2e2SSriharsha Basavapatna htid = ldcp->htid; 39597bd3a2e2SSriharsha Basavapatna ldcp->htid = 0; 39607bd3a2e2SSriharsha Basavapatna } 39617bd3a2e2SSriharsha Basavapatna 39627bd3a2e2SSriharsha Basavapatna if (ldcp->wd_tid != 0) { 39637bd3a2e2SSriharsha Basavapatna wd_tid = ldcp->wd_tid; 39647bd3a2e2SSriharsha Basavapatna ldcp->wd_tid = 0; 39657bd3a2e2SSriharsha Basavapatna } 39667bd3a2e2SSriharsha Basavapatna 39671107ea93SSriharsha Basavapatna mutex_exit(&ldcp->cblock); 39687bd3a2e2SSriharsha Basavapatna 39697bd3a2e2SSriharsha Basavapatna /* Update link state to the stack */ 39707bd3a2e2SSriharsha Basavapatna if (link_update == B_TRUE) { 39711107ea93SSriharsha Basavapatna vgen_link_update(vgenp, ldcp->link_state); 39721107ea93SSriharsha Basavapatna } 39737bd3a2e2SSriharsha Basavapatna 39747bd3a2e2SSriharsha Basavapatna /* 39757bd3a2e2SSriharsha Basavapatna * As the channel is being reset, redirect traffic to the peer through 39767bd3a2e2SSriharsha Basavapatna * vswitch, until the channel becomes ready to be used again. 39777bd3a2e2SSriharsha Basavapatna */ 39787bd3a2e2SSriharsha Basavapatna if (is_vsw_port == B_FALSE && vgenp->vsw_portp != NULL) { 39797bd3a2e2SSriharsha Basavapatna (void) atomic_swap_32(&portp->use_vsw_port, B_TRUE); 39801107ea93SSriharsha Basavapatna } 39817bd3a2e2SSriharsha Basavapatna 39827bd3a2e2SSriharsha Basavapatna /* Cancel handshake watchdog timeout */ 39837bd3a2e2SSriharsha Basavapatna if (htid) { 39847bd3a2e2SSriharsha Basavapatna (void) untimeout(htid); 39857bd3a2e2SSriharsha Basavapatna } 39867bd3a2e2SSriharsha Basavapatna 39877bd3a2e2SSriharsha Basavapatna /* Cancel transmit watchdog timeout */ 39887bd3a2e2SSriharsha Basavapatna if (wd_tid) { 39897bd3a2e2SSriharsha Basavapatna (void) untimeout(wd_tid); 39907bd3a2e2SSriharsha Basavapatna } 39917bd3a2e2SSriharsha Basavapatna 39927bd3a2e2SSriharsha Basavapatna /* Stop the msg worker thread */ 39937bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_TX_DRING && curthread != ldcp->msg_thread) { 39947bd3a2e2SSriharsha Basavapatna vgen_stop_msg_thread(ldcp); 39957bd3a2e2SSriharsha Basavapatna } 39967bd3a2e2SSriharsha Basavapatna 39977bd3a2e2SSriharsha Basavapatna /* Grab all locks while we tear down tx/rx resources */ 39987bd3a2e2SSriharsha Basavapatna LDC_LOCK(ldcp); 39997bd3a2e2SSriharsha Basavapatna 40007bd3a2e2SSriharsha Basavapatna /* Destroy the local dring which is exported to the peer */ 40017bd3a2e2SSriharsha Basavapatna vgen_destroy_dring(ldcp); 40027bd3a2e2SSriharsha Basavapatna 40037bd3a2e2SSriharsha Basavapatna /* Unmap the remote dring which is imported from the peer */ 40047bd3a2e2SSriharsha Basavapatna vgen_unmap_dring(ldcp); 40057bd3a2e2SSriharsha Basavapatna 40067bd3a2e2SSriharsha Basavapatna /* 40077bd3a2e2SSriharsha Basavapatna * Bring up the channel and restart handshake 40087bd3a2e2SSriharsha Basavapatna * only if the channel is not being torn down. 40097bd3a2e2SSriharsha Basavapatna */ 40107bd3a2e2SSriharsha Basavapatna if (flags != VGEN_FLAG_UNINIT) { 40117bd3a2e2SSriharsha Basavapatna 40127bd3a2e2SSriharsha Basavapatna /* Setup handshake parameters to restart a new handshake */ 40137bd3a2e2SSriharsha Basavapatna vgen_setup_handshake_params(ldcp); 40147bd3a2e2SSriharsha Basavapatna 40157bd3a2e2SSriharsha Basavapatna /* Bring the channel up */ 40167bd3a2e2SSriharsha Basavapatna vgen_ldc_up(ldcp); 40177bd3a2e2SSriharsha Basavapatna 40187bd3a2e2SSriharsha Basavapatna if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 40197bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "ldc_status err\n"); 40207bd3a2e2SSriharsha Basavapatna } else { 40217bd3a2e2SSriharsha Basavapatna ldcp->ldc_status = istatus; 40227bd3a2e2SSriharsha Basavapatna } 40237bd3a2e2SSriharsha Basavapatna 40247bd3a2e2SSriharsha Basavapatna /* If the channel is UP, start handshake */ 40257bd3a2e2SSriharsha Basavapatna if (ldcp->ldc_status == LDC_UP) { 40267bd3a2e2SSriharsha Basavapatna 40277bd3a2e2SSriharsha Basavapatna if (is_vsw_port == B_FALSE) { 40287bd3a2e2SSriharsha Basavapatna /* 40297bd3a2e2SSriharsha Basavapatna * Channel is up; use this port from now on. 40307bd3a2e2SSriharsha Basavapatna */ 40317bd3a2e2SSriharsha Basavapatna (void) atomic_swap_32(&portp->use_vsw_port, 40327bd3a2e2SSriharsha Basavapatna B_FALSE); 40337bd3a2e2SSriharsha Basavapatna } 40347bd3a2e2SSriharsha Basavapatna 40357bd3a2e2SSriharsha Basavapatna /* Initialize local session id */ 40367bd3a2e2SSriharsha Basavapatna ldcp->local_sid = ddi_get_lbolt(); 40377bd3a2e2SSriharsha Basavapatna 40387bd3a2e2SSriharsha Basavapatna /* clear peer session id */ 40397bd3a2e2SSriharsha Basavapatna ldcp->peer_sid = 0; 40407bd3a2e2SSriharsha Basavapatna 40417bd3a2e2SSriharsha Basavapatna /* 40427bd3a2e2SSriharsha Basavapatna * Initiate Handshake process with peer ldc endpoint by 40437bd3a2e2SSriharsha Basavapatna * sending version info vio message. If that fails we 40447bd3a2e2SSriharsha Basavapatna * go back to the top of this function to process the 40457bd3a2e2SSriharsha Basavapatna * error again. Note that we can be in this loop for 40467bd3a2e2SSriharsha Basavapatna * 'vgen_ldc_max_resets' times, after which the channel 40477bd3a2e2SSriharsha Basavapatna * is not brought up. 40487bd3a2e2SSriharsha Basavapatna */ 40497bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->tclock); 40507bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->txlock); 40517bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->wrlock); 40527bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->rxlock); 40537bd3a2e2SSriharsha Basavapatna rv = vgen_handshake(vh_nextphase(ldcp)); 40547bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->cblock); 40557bd3a2e2SSriharsha Basavapatna if (rv != 0) { 40567bd3a2e2SSriharsha Basavapatna if (rv == ECONNRESET) { 40577bd3a2e2SSriharsha Basavapatna flags = VGEN_FLAG_EVT_RESET; 40587bd3a2e2SSriharsha Basavapatna } else { 40597bd3a2e2SSriharsha Basavapatna flags = VGEN_FLAG_NEED_LDCRESET; 40607bd3a2e2SSriharsha Basavapatna } 40617bd3a2e2SSriharsha Basavapatna 40627bd3a2e2SSriharsha Basavapatna /* 40637bd3a2e2SSriharsha Basavapatna * We still hold 'reset_in_progress'; so we can 40647bd3a2e2SSriharsha Basavapatna * just loop back to the top to restart error 40657bd3a2e2SSriharsha Basavapatna * processing. 40667bd3a2e2SSriharsha Basavapatna */ 40677bd3a2e2SSriharsha Basavapatna goto again; 40687bd3a2e2SSriharsha Basavapatna } 40697bd3a2e2SSriharsha Basavapatna } else { 40707bd3a2e2SSriharsha Basavapatna LDC_UNLOCK(ldcp); 40717bd3a2e2SSriharsha Basavapatna } 40727bd3a2e2SSriharsha Basavapatna 40737bd3a2e2SSriharsha Basavapatna } else { /* flags == VGEN_FLAG_UNINIT */ 40747bd3a2e2SSriharsha Basavapatna 40757bd3a2e2SSriharsha Basavapatna /* Close the channel - retry on EAGAIN */ 40767bd3a2e2SSriharsha Basavapatna while ((rv = ldc_close(ldcp->ldc_handle)) == EAGAIN) { 40777bd3a2e2SSriharsha Basavapatna if (++retries > vgen_ldccl_retries) { 40787bd3a2e2SSriharsha Basavapatna break; 40797bd3a2e2SSriharsha Basavapatna } 40807bd3a2e2SSriharsha Basavapatna drv_usecwait(VGEN_LDC_CLOSE_DELAY); 40817bd3a2e2SSriharsha Basavapatna } 40827bd3a2e2SSriharsha Basavapatna if (rv != 0) { 40837bd3a2e2SSriharsha Basavapatna cmn_err(CE_NOTE, 40847bd3a2e2SSriharsha Basavapatna "!vnet%d: Error(%d) closing the channel(0x%lx)\n", 40857bd3a2e2SSriharsha Basavapatna vgenp->instance, rv, ldcp->ldc_id); 40867bd3a2e2SSriharsha Basavapatna } 40877bd3a2e2SSriharsha Basavapatna 40887bd3a2e2SSriharsha Basavapatna ldcp->ldc_reset_count = 0; 40897bd3a2e2SSriharsha Basavapatna ldcp->ldc_status = LDC_INIT; 40907bd3a2e2SSriharsha Basavapatna ldcp->flags &= ~(CHANNEL_STARTED); 40917bd3a2e2SSriharsha Basavapatna 40927bd3a2e2SSriharsha Basavapatna LDC_UNLOCK(ldcp); 40937bd3a2e2SSriharsha Basavapatna } 40947bd3a2e2SSriharsha Basavapatna 40957bd3a2e2SSriharsha Basavapatna /* Done processing channel reset; clear the atomic flag */ 40967bd3a2e2SSriharsha Basavapatna ldcp->reset_in_progress = 0; 40977bd3a2e2SSriharsha Basavapatna return (0); 40981ae08745Sheppo } 40991ae08745Sheppo 41001ae08745Sheppo /* 41011ae08745Sheppo * Initiate handshake with the peer by sending various messages 41021ae08745Sheppo * based on the handshake-phase that the channel is currently in. 41031ae08745Sheppo */ 41047bd3a2e2SSriharsha Basavapatna static int 41051ae08745Sheppo vgen_handshake(vgen_ldc_t *ldcp) 41061ae08745Sheppo { 41071ae08745Sheppo uint32_t hphase = ldcp->hphase; 41081ae08745Sheppo vgen_t *vgenp = LDC_TO_VGEN(ldcp); 41093af08d82Slm66018 int rv = 0; 41107bd3a2e2SSriharsha Basavapatna timeout_id_t htid; 41111ae08745Sheppo 41121ae08745Sheppo switch (hphase) { 41131ae08745Sheppo 41141ae08745Sheppo case VH_PHASE1: 41151ae08745Sheppo 41161ae08745Sheppo /* 41171ae08745Sheppo * start timer, for entire handshake process, turn this timer 41181ae08745Sheppo * off if all phases of handshake complete successfully and 41197bd3a2e2SSriharsha Basavapatna * hphase goes to VH_DONE(below) or channel is reset due to 41207bd3a2e2SSriharsha Basavapatna * errors or vgen_ldc_uninit() is invoked(vgen_stop). 41211ae08745Sheppo */ 412252bca946SWENTAO YANG ASSERT(ldcp->htid == 0); 41231ae08745Sheppo ldcp->htid = timeout(vgen_hwatchdog, (caddr_t)ldcp, 412419b65a69Ssb155480 drv_usectohz(vgen_hwd_interval * MICROSEC)); 41251ae08745Sheppo 41261ae08745Sheppo /* Phase 1 involves negotiating the version */ 41273af08d82Slm66018 rv = vgen_send_version_negotiate(ldcp); 41281ae08745Sheppo break; 41291ae08745Sheppo 41301ae08745Sheppo case VH_PHASE2: 41313af08d82Slm66018 rv = vgen_handshake_phase2(ldcp); 41321ae08745Sheppo break; 41331ae08745Sheppo 41341ae08745Sheppo case VH_PHASE3: 41357bd3a2e2SSriharsha Basavapatna rv = vgen_handshake_phase3(ldcp); 41367bd3a2e2SSriharsha Basavapatna break; 41377bd3a2e2SSriharsha Basavapatna 41387bd3a2e2SSriharsha Basavapatna case VH_PHASE4: 41393af08d82Slm66018 rv = vgen_send_rdx_info(ldcp); 41401ae08745Sheppo break; 41411ae08745Sheppo 41421ae08745Sheppo case VH_DONE: 41437bd3a2e2SSriharsha Basavapatna 41447bd3a2e2SSriharsha Basavapatna ldcp->ldc_reset_count = 0; 41457bd3a2e2SSriharsha Basavapatna 4146844e62a3Sraghuram DBG1(vgenp, ldcp, "Handshake Done\n"); 41471ae08745Sheppo 41481107ea93SSriharsha Basavapatna /* 41491107ea93SSriharsha Basavapatna * The channel is up and handshake is done successfully. Now we 41501107ea93SSriharsha Basavapatna * can mark the channel link_state as 'up'. We also notify the 41511107ea93SSriharsha Basavapatna * stack if the channel is connected to vswitch. 41521107ea93SSriharsha Basavapatna */ 41531107ea93SSriharsha Basavapatna ldcp->link_state = LINK_STATE_UP; 41541107ea93SSriharsha Basavapatna 415519b65a69Ssb155480 if (ldcp->portp == vgenp->vsw_portp) { 415619b65a69Ssb155480 /* 415719b65a69Ssb155480 * If this channel(port) is connected to vsw, 415819b65a69Ssb155480 * need to sync multicast table with vsw. 415919b65a69Ssb155480 */ 41603af08d82Slm66018 rv = vgen_send_mcast_info(ldcp); 41617bd3a2e2SSriharsha Basavapatna if (rv != VGEN_SUCCESS) 41620c4606f0SWENTAO YANG break; 41631ae08745Sheppo 41641107ea93SSriharsha Basavapatna if (vgenp->pls_negotiated == B_FALSE) { 41651107ea93SSriharsha Basavapatna /* 41661107ea93SSriharsha Basavapatna * We haven't negotiated with vswitch to get 41671107ea93SSriharsha Basavapatna * physical link state updates. We can update 41681107ea93SSriharsha Basavapatna * update the stack at this point as the 41691107ea93SSriharsha Basavapatna * channel to vswitch is up and the handshake 41701107ea93SSriharsha Basavapatna * is done successfully. 41711107ea93SSriharsha Basavapatna * 41721107ea93SSriharsha Basavapatna * If we have negotiated to get physical link 41731107ea93SSriharsha Basavapatna * state updates, then we won't notify the 41741107ea93SSriharsha Basavapatna * the stack here; we do that as soon as 41751107ea93SSriharsha Basavapatna * vswitch sends us the initial phys link state 41761107ea93SSriharsha Basavapatna * (see vgen_handle_physlink_info()). 41771107ea93SSriharsha Basavapatna */ 41780c4606f0SWENTAO YANG mutex_exit(&ldcp->cblock); 41791107ea93SSriharsha Basavapatna vgen_link_update(vgenp, ldcp->link_state); 41800c4606f0SWENTAO YANG mutex_enter(&ldcp->cblock); 41811107ea93SSriharsha Basavapatna } 41827bd3a2e2SSriharsha Basavapatna } 41831107ea93SSriharsha Basavapatna 41847bd3a2e2SSriharsha Basavapatna if (ldcp->htid != 0) { 41857bd3a2e2SSriharsha Basavapatna htid = ldcp->htid; 41867bd3a2e2SSriharsha Basavapatna ldcp->htid = 0; 41877bd3a2e2SSriharsha Basavapatna 41887bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->cblock); 41897bd3a2e2SSriharsha Basavapatna (void) untimeout(htid); 41907bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->cblock); 41911ae08745Sheppo } 41923af08d82Slm66018 41933af08d82Slm66018 /* 41943af08d82Slm66018 * Check if mac layer should be notified to restart 41953af08d82Slm66018 * transmissions. This can happen if the channel got 41967bd3a2e2SSriharsha Basavapatna * reset and while tx_blocked is set. 41973af08d82Slm66018 */ 41983af08d82Slm66018 mutex_enter(&ldcp->tclock); 41997bd3a2e2SSriharsha Basavapatna if (ldcp->tx_blocked) { 4200678453a8Sspeer vio_net_tx_update_t vtx_update = 4201678453a8Sspeer ldcp->portp->vcb.vio_net_tx_update; 4202678453a8Sspeer 42037bd3a2e2SSriharsha Basavapatna ldcp->tx_blocked = B_FALSE; 4204678453a8Sspeer vtx_update(ldcp->portp->vhp); 42053af08d82Slm66018 } 42063af08d82Slm66018 mutex_exit(&ldcp->tclock); 42073af08d82Slm66018 42087bd3a2e2SSriharsha Basavapatna /* start transmit watchdog timer */ 42097bd3a2e2SSriharsha Basavapatna ldcp->wd_tid = timeout(vgen_tx_watchdog, (caddr_t)ldcp, 42107bd3a2e2SSriharsha Basavapatna drv_usectohz(vgen_txwd_interval * 1000)); 42117bd3a2e2SSriharsha Basavapatna 42121ae08745Sheppo break; 42131ae08745Sheppo 42141ae08745Sheppo default: 42151ae08745Sheppo break; 42161ae08745Sheppo } 42173af08d82Slm66018 42187bd3a2e2SSriharsha Basavapatna return (rv); 42191ae08745Sheppo } 42201ae08745Sheppo 42211ae08745Sheppo /* 42221ae08745Sheppo * Check if the current handshake phase has completed successfully and 42231ae08745Sheppo * return the status. 42241ae08745Sheppo */ 42251ae08745Sheppo static int 42261ae08745Sheppo vgen_handshake_done(vgen_ldc_t *ldcp) 42271ae08745Sheppo { 4228844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 42291ae08745Sheppo uint32_t hphase = ldcp->hphase; 42301ae08745Sheppo int status = 0; 42311ae08745Sheppo 42321ae08745Sheppo switch (hphase) { 42331ae08745Sheppo 42341ae08745Sheppo case VH_PHASE1: 42351ae08745Sheppo /* 42361ae08745Sheppo * Phase1 is done, if version negotiation 42371ae08745Sheppo * completed successfully. 42381ae08745Sheppo */ 42391ae08745Sheppo status = ((ldcp->hstate & VER_NEGOTIATED) == 42401ae08745Sheppo VER_NEGOTIATED); 42411ae08745Sheppo break; 42421ae08745Sheppo 42431ae08745Sheppo case VH_PHASE2: 42441ae08745Sheppo /* 42457bd3a2e2SSriharsha Basavapatna * Phase 2 is done, if attr info 42467bd3a2e2SSriharsha Basavapatna * has been exchanged successfully. 42471ae08745Sheppo */ 42487bd3a2e2SSriharsha Basavapatna status = ((ldcp->hstate & ATTR_INFO_EXCHANGED) == 42497bd3a2e2SSriharsha Basavapatna ATTR_INFO_EXCHANGED); 42501ae08745Sheppo break; 42511ae08745Sheppo 42521ae08745Sheppo case VH_PHASE3: 42537bd3a2e2SSriharsha Basavapatna /* 42547bd3a2e2SSriharsha Basavapatna * Phase 3 is done, if dring registration 42557bd3a2e2SSriharsha Basavapatna * has been exchanged successfully. 42567bd3a2e2SSriharsha Basavapatna */ 42577bd3a2e2SSriharsha Basavapatna status = ((ldcp->hstate & DRING_INFO_EXCHANGED) == 42587bd3a2e2SSriharsha Basavapatna DRING_INFO_EXCHANGED); 42597bd3a2e2SSriharsha Basavapatna break; 42607bd3a2e2SSriharsha Basavapatna 42617bd3a2e2SSriharsha Basavapatna case VH_PHASE4: 42627bd3a2e2SSriharsha Basavapatna /* Phase 4 is done, if rdx msg has been exchanged */ 42631ae08745Sheppo status = ((ldcp->hstate & RDX_EXCHANGED) == 42641ae08745Sheppo RDX_EXCHANGED); 42651ae08745Sheppo break; 42661ae08745Sheppo 42671ae08745Sheppo default: 42681ae08745Sheppo break; 42691ae08745Sheppo } 42701ae08745Sheppo 42711ae08745Sheppo if (status == 0) { 42721ae08745Sheppo return (VGEN_FAILURE); 42731ae08745Sheppo } 4274844e62a3Sraghuram DBG2(vgenp, ldcp, "PHASE(%d)\n", hphase); 42751ae08745Sheppo return (VGEN_SUCCESS); 42761ae08745Sheppo } 42771ae08745Sheppo 42781107ea93SSriharsha Basavapatna /* 42791107ea93SSriharsha Basavapatna * Link State Update Notes: 42801107ea93SSriharsha Basavapatna * The link state of the channel connected to vswitch is reported as the link 42811107ea93SSriharsha Basavapatna * state of the vnet device, by default. If the channel is down or reset, then 42821107ea93SSriharsha Basavapatna * the link state is marked 'down'. If the channel is 'up' *and* handshake 42831107ea93SSriharsha Basavapatna * between the vnet and vswitch is successful, then the link state is marked 42841107ea93SSriharsha Basavapatna * 'up'. If physical network link state is desired, then the vnet device must 42851107ea93SSriharsha Basavapatna * be configured to get physical link updates and the 'linkprop' property 42861107ea93SSriharsha Basavapatna * in the virtual-device MD node indicates this. As part of attribute exchange 42871107ea93SSriharsha Basavapatna * the vnet device negotiates with the vswitch to obtain physical link state 42881107ea93SSriharsha Basavapatna * updates. If it successfully negotiates, vswitch sends an initial physlink 42891107ea93SSriharsha Basavapatna * msg once the handshake is done and further whenever the physical link state 42901107ea93SSriharsha Basavapatna * changes. Currently we don't have mac layer interfaces to report two distinct 42911107ea93SSriharsha Basavapatna * link states - virtual and physical. Thus, if the vnet has been configured to 42921107ea93SSriharsha Basavapatna * get physical link updates, then the link status will be reported as 'up' 42931107ea93SSriharsha Basavapatna * only when both the virtual and physical links are up. 42941107ea93SSriharsha Basavapatna */ 42951107ea93SSriharsha Basavapatna static void 42961107ea93SSriharsha Basavapatna vgen_link_update(vgen_t *vgenp, link_state_t link_state) 42971107ea93SSriharsha Basavapatna { 42981107ea93SSriharsha Basavapatna vnet_link_update(vgenp->vnetp, link_state); 42991107ea93SSriharsha Basavapatna } 43001107ea93SSriharsha Basavapatna 43011ae08745Sheppo /* 43021ae08745Sheppo * Handle a version info msg from the peer or an ACK/NACK from the peer 43031ae08745Sheppo * to a version info msg that we sent. 43041ae08745Sheppo */ 43053af08d82Slm66018 static int 43061ae08745Sheppo vgen_handle_version_negotiate(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 43071ae08745Sheppo { 4308844e62a3Sraghuram vgen_t *vgenp; 43091ae08745Sheppo vio_ver_msg_t *vermsg = (vio_ver_msg_t *)tagp; 43101ae08745Sheppo int ack = 0; 43111ae08745Sheppo int failed = 0; 43121ae08745Sheppo int idx; 43131ae08745Sheppo vgen_ver_t *versions = ldcp->vgen_versions; 43143af08d82Slm66018 int rv = 0; 43151ae08745Sheppo 4316844e62a3Sraghuram vgenp = LDC_TO_VGEN(ldcp); 4317844e62a3Sraghuram DBG1(vgenp, ldcp, "enter\n"); 43181ae08745Sheppo switch (tagp->vio_subtype) { 43191ae08745Sheppo case VIO_SUBTYPE_INFO: 43201ae08745Sheppo 43211ae08745Sheppo /* Cache sid of peer if this is the first time */ 43221ae08745Sheppo if (ldcp->peer_sid == 0) { 4323844e62a3Sraghuram DBG2(vgenp, ldcp, "Caching peer_sid(%x)\n", 4324844e62a3Sraghuram tagp->vio_sid); 43251ae08745Sheppo ldcp->peer_sid = tagp->vio_sid; 43261ae08745Sheppo } 43271ae08745Sheppo 43281ae08745Sheppo if (ldcp->hphase != VH_PHASE1) { 43291ae08745Sheppo /* 43301ae08745Sheppo * If we are not already in VH_PHASE1, reset to 43311ae08745Sheppo * pre-handshake state, and initiate handshake 43321ae08745Sheppo * to the peer too. 43331ae08745Sheppo */ 43347bd3a2e2SSriharsha Basavapatna return (EINVAL); 43351ae08745Sheppo } 43367bd3a2e2SSriharsha Basavapatna 43371ae08745Sheppo ldcp->hstate |= VER_INFO_RCVD; 43381ae08745Sheppo 43391ae08745Sheppo /* save peer's requested values */ 43401ae08745Sheppo ldcp->peer_hparams.ver_major = vermsg->ver_major; 43411ae08745Sheppo ldcp->peer_hparams.ver_minor = vermsg->ver_minor; 43421ae08745Sheppo ldcp->peer_hparams.dev_class = vermsg->dev_class; 43431ae08745Sheppo 43441ae08745Sheppo if ((vermsg->dev_class != VDEV_NETWORK) && 43451ae08745Sheppo (vermsg->dev_class != VDEV_NETWORK_SWITCH)) { 43461ae08745Sheppo /* unsupported dev_class, send NACK */ 43471ae08745Sheppo 4348844e62a3Sraghuram DWARN(vgenp, ldcp, "Version Negotiation Failed\n"); 43493af08d82Slm66018 43503af08d82Slm66018 tagp->vio_subtype = VIO_SUBTYPE_NACK; 43513af08d82Slm66018 tagp->vio_sid = ldcp->local_sid; 43523af08d82Slm66018 /* send reply msg back to peer */ 43533af08d82Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, 43543af08d82Slm66018 sizeof (*vermsg), B_FALSE); 43553af08d82Slm66018 if (rv != VGEN_SUCCESS) { 43563af08d82Slm66018 return (rv); 43573af08d82Slm66018 } 43583af08d82Slm66018 return (VGEN_FAILURE); 43591ae08745Sheppo } 43601ae08745Sheppo 4361844e62a3Sraghuram DBG2(vgenp, ldcp, "VER_INFO_RCVD, ver(%d,%d)\n", 4362844e62a3Sraghuram vermsg->ver_major, vermsg->ver_minor); 43631ae08745Sheppo 43641ae08745Sheppo idx = 0; 43651ae08745Sheppo 43661ae08745Sheppo for (;;) { 43671ae08745Sheppo 43681ae08745Sheppo if (vermsg->ver_major > versions[idx].ver_major) { 43691ae08745Sheppo 43701ae08745Sheppo /* nack with next lower version */ 43711ae08745Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 43721ae08745Sheppo vermsg->ver_major = versions[idx].ver_major; 43731ae08745Sheppo vermsg->ver_minor = versions[idx].ver_minor; 43741ae08745Sheppo break; 43751ae08745Sheppo } 43761ae08745Sheppo 43771ae08745Sheppo if (vermsg->ver_major == versions[idx].ver_major) { 43781ae08745Sheppo 43791ae08745Sheppo /* major version match - ACK version */ 43801ae08745Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 43811ae08745Sheppo ack = 1; 43821ae08745Sheppo 43831ae08745Sheppo /* 43841ae08745Sheppo * lower minor version to the one this endpt 43851ae08745Sheppo * supports, if necessary 43861ae08745Sheppo */ 43871ae08745Sheppo if (vermsg->ver_minor > 43881ae08745Sheppo versions[idx].ver_minor) { 43891ae08745Sheppo vermsg->ver_minor = 43901ae08745Sheppo versions[idx].ver_minor; 43911ae08745Sheppo ldcp->peer_hparams.ver_minor = 43921ae08745Sheppo versions[idx].ver_minor; 43931ae08745Sheppo } 43941ae08745Sheppo break; 43951ae08745Sheppo } 43961ae08745Sheppo 43971ae08745Sheppo idx++; 43981ae08745Sheppo 43991ae08745Sheppo if (idx == VGEN_NUM_VER) { 44001ae08745Sheppo 44011ae08745Sheppo /* no version match - send NACK */ 44021ae08745Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 44031ae08745Sheppo vermsg->ver_major = 0; 44041ae08745Sheppo vermsg->ver_minor = 0; 44051ae08745Sheppo failed = 1; 44061ae08745Sheppo break; 44071ae08745Sheppo } 44081ae08745Sheppo 44091ae08745Sheppo } 44101ae08745Sheppo 44111ae08745Sheppo tagp->vio_sid = ldcp->local_sid; 44121ae08745Sheppo 44131ae08745Sheppo /* send reply msg back to peer */ 44143af08d82Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*vermsg), 44153af08d82Slm66018 B_FALSE); 44163af08d82Slm66018 if (rv != VGEN_SUCCESS) { 44173af08d82Slm66018 return (rv); 44181ae08745Sheppo } 44191ae08745Sheppo 44201ae08745Sheppo if (ack) { 44211ae08745Sheppo ldcp->hstate |= VER_ACK_SENT; 4422844e62a3Sraghuram DBG2(vgenp, ldcp, "VER_ACK_SENT, ver(%d,%d) \n", 4423844e62a3Sraghuram vermsg->ver_major, vermsg->ver_minor); 44241ae08745Sheppo } 44251ae08745Sheppo if (failed) { 4426844e62a3Sraghuram DWARN(vgenp, ldcp, "Negotiation Failed\n"); 44273af08d82Slm66018 return (VGEN_FAILURE); 44281ae08745Sheppo } 44291ae08745Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 44301ae08745Sheppo 44311ae08745Sheppo /* VER_ACK_SENT and VER_ACK_RCVD */ 44321ae08745Sheppo 44331ae08745Sheppo /* local and peer versions match? */ 44341ae08745Sheppo ASSERT((ldcp->local_hparams.ver_major == 44351ae08745Sheppo ldcp->peer_hparams.ver_major) && 44361ae08745Sheppo (ldcp->local_hparams.ver_minor == 44371ae08745Sheppo ldcp->peer_hparams.ver_minor)); 44381ae08745Sheppo 4439f0ca1d9aSsb155480 vgen_set_vnet_proto_ops(ldcp); 4440f0ca1d9aSsb155480 44411ae08745Sheppo /* move to the next phase */ 44427bd3a2e2SSriharsha Basavapatna rv = vgen_handshake(vh_nextphase(ldcp)); 44437bd3a2e2SSriharsha Basavapatna if (rv != 0) { 44447bd3a2e2SSriharsha Basavapatna return (rv); 44457bd3a2e2SSriharsha Basavapatna } 44461ae08745Sheppo } 44471ae08745Sheppo 44481ae08745Sheppo break; 44491ae08745Sheppo 44501ae08745Sheppo case VIO_SUBTYPE_ACK: 44511ae08745Sheppo 44521ae08745Sheppo if (ldcp->hphase != VH_PHASE1) { 44531ae08745Sheppo /* This should not happen. */ 4454844e62a3Sraghuram DWARN(vgenp, ldcp, "Invalid Phase(%u)\n", ldcp->hphase); 44553af08d82Slm66018 return (VGEN_FAILURE); 44561ae08745Sheppo } 44571ae08745Sheppo 44581ae08745Sheppo /* SUCCESS - we have agreed on a version */ 44591ae08745Sheppo ldcp->local_hparams.ver_major = vermsg->ver_major; 44601ae08745Sheppo ldcp->local_hparams.ver_minor = vermsg->ver_minor; 44611ae08745Sheppo ldcp->hstate |= VER_ACK_RCVD; 44621ae08745Sheppo 4463844e62a3Sraghuram DBG2(vgenp, ldcp, "VER_ACK_RCVD, ver(%d,%d) \n", 4464844e62a3Sraghuram vermsg->ver_major, vermsg->ver_minor); 44651ae08745Sheppo 44661ae08745Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 44671ae08745Sheppo 44681ae08745Sheppo /* VER_ACK_SENT and VER_ACK_RCVD */ 44691ae08745Sheppo 44701ae08745Sheppo /* local and peer versions match? */ 44711ae08745Sheppo ASSERT((ldcp->local_hparams.ver_major == 44721ae08745Sheppo ldcp->peer_hparams.ver_major) && 44731ae08745Sheppo (ldcp->local_hparams.ver_minor == 44741ae08745Sheppo ldcp->peer_hparams.ver_minor)); 44751ae08745Sheppo 4476f0ca1d9aSsb155480 vgen_set_vnet_proto_ops(ldcp); 4477f0ca1d9aSsb155480 44781ae08745Sheppo /* move to the next phase */ 44797bd3a2e2SSriharsha Basavapatna rv = vgen_handshake(vh_nextphase(ldcp)); 44807bd3a2e2SSriharsha Basavapatna if (rv != 0) { 44817bd3a2e2SSriharsha Basavapatna return (rv); 44827bd3a2e2SSriharsha Basavapatna } 44831ae08745Sheppo } 44841ae08745Sheppo break; 44851ae08745Sheppo 44861ae08745Sheppo case VIO_SUBTYPE_NACK: 44871ae08745Sheppo 44881ae08745Sheppo if (ldcp->hphase != VH_PHASE1) { 44891ae08745Sheppo /* This should not happen. */ 4490844e62a3Sraghuram DWARN(vgenp, ldcp, "VER_NACK_RCVD Invalid " 4491844e62a3Sraghuram "Phase(%u)\n", ldcp->hphase); 44923af08d82Slm66018 return (VGEN_FAILURE); 44931ae08745Sheppo } 44941ae08745Sheppo 4495844e62a3Sraghuram DBG2(vgenp, ldcp, "VER_NACK_RCVD next ver(%d,%d)\n", 4496844e62a3Sraghuram vermsg->ver_major, vermsg->ver_minor); 44971ae08745Sheppo 44981ae08745Sheppo /* check if version in NACK is zero */ 44991ae08745Sheppo if (vermsg->ver_major == 0 && vermsg->ver_minor == 0) { 45001ae08745Sheppo /* 45011ae08745Sheppo * Version Negotiation has failed. 45021ae08745Sheppo */ 4503844e62a3Sraghuram DWARN(vgenp, ldcp, "Version Negotiation Failed\n"); 45043af08d82Slm66018 return (VGEN_FAILURE); 45051ae08745Sheppo } 45061ae08745Sheppo 45071ae08745Sheppo idx = 0; 45081ae08745Sheppo 45091ae08745Sheppo for (;;) { 45101ae08745Sheppo 45111ae08745Sheppo if (vermsg->ver_major > versions[idx].ver_major) { 45121ae08745Sheppo /* select next lower version */ 45131ae08745Sheppo 45141ae08745Sheppo ldcp->local_hparams.ver_major = 45151ae08745Sheppo versions[idx].ver_major; 45161ae08745Sheppo ldcp->local_hparams.ver_minor = 45171ae08745Sheppo versions[idx].ver_minor; 45181ae08745Sheppo break; 45191ae08745Sheppo } 45201ae08745Sheppo 45211ae08745Sheppo if (vermsg->ver_major == versions[idx].ver_major) { 45221ae08745Sheppo /* major version match */ 45231ae08745Sheppo 45241ae08745Sheppo ldcp->local_hparams.ver_major = 45251ae08745Sheppo versions[idx].ver_major; 45261ae08745Sheppo 45271ae08745Sheppo ldcp->local_hparams.ver_minor = 45281ae08745Sheppo versions[idx].ver_minor; 45291ae08745Sheppo break; 45301ae08745Sheppo } 45311ae08745Sheppo 45321ae08745Sheppo idx++; 45331ae08745Sheppo 45341ae08745Sheppo if (idx == VGEN_NUM_VER) { 45351ae08745Sheppo /* 45361ae08745Sheppo * no version match. 45371ae08745Sheppo * Version Negotiation has failed. 45381ae08745Sheppo */ 4539844e62a3Sraghuram DWARN(vgenp, ldcp, 4540844e62a3Sraghuram "Version Negotiation Failed\n"); 45413af08d82Slm66018 return (VGEN_FAILURE); 45421ae08745Sheppo } 45431ae08745Sheppo 45441ae08745Sheppo } 45451ae08745Sheppo 45463af08d82Slm66018 rv = vgen_send_version_negotiate(ldcp); 45473af08d82Slm66018 if (rv != VGEN_SUCCESS) { 45483af08d82Slm66018 return (rv); 45491ae08745Sheppo } 45501ae08745Sheppo 45511ae08745Sheppo break; 45521ae08745Sheppo } 45533af08d82Slm66018 4554844e62a3Sraghuram DBG1(vgenp, ldcp, "exit\n"); 45553af08d82Slm66018 return (VGEN_SUCCESS); 45561ae08745Sheppo } 45571ae08745Sheppo 45581ae08745Sheppo static int 45597bd3a2e2SSriharsha Basavapatna vgen_handle_attr_info(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg) 45601ae08745Sheppo { 4561844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 45627b1f684aSSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams; 45637b1f684aSSriharsha Basavapatna vgen_hparams_t *rp = &ldcp->peer_hparams; 45647b1f684aSSriharsha Basavapatna uint32_t mtu; 45657bd3a2e2SSriharsha Basavapatna uint8_t dring_mode; 45661ae08745Sheppo 45671ae08745Sheppo ldcp->hstate |= ATTR_INFO_RCVD; 45681ae08745Sheppo 45691ae08745Sheppo /* save peer's values */ 45707b1f684aSSriharsha Basavapatna rp->mtu = msg->mtu; 45717b1f684aSSriharsha Basavapatna rp->addr = msg->addr; 45727b1f684aSSriharsha Basavapatna rp->addr_type = msg->addr_type; 45737b1f684aSSriharsha Basavapatna rp->xfer_mode = msg->xfer_mode; 45747b1f684aSSriharsha Basavapatna rp->ack_freq = msg->ack_freq; 45757bd3a2e2SSriharsha Basavapatna rp->dring_mode = msg->options; 45767b1f684aSSriharsha Basavapatna 45777b1f684aSSriharsha Basavapatna /* 45787bd3a2e2SSriharsha Basavapatna * Process address type, ack frequency and transfer mode attributes. 45797b1f684aSSriharsha Basavapatna */ 45807bd3a2e2SSriharsha Basavapatna if ((msg->addr_type != ADDR_TYPE_MAC) || 45817bd3a2e2SSriharsha Basavapatna (msg->ack_freq > 64) || 45827bd3a2e2SSriharsha Basavapatna (msg->xfer_mode != lp->xfer_mode)) { 45837bd3a2e2SSriharsha Basavapatna return (VGEN_FAILURE); 45847bd3a2e2SSriharsha Basavapatna } 45857bd3a2e2SSriharsha Basavapatna 45867bd3a2e2SSriharsha Basavapatna /* 45877bd3a2e2SSriharsha Basavapatna * Process dring mode attribute. 45887bd3a2e2SSriharsha Basavapatna */ 45897bd3a2e2SSriharsha Basavapatna if (VGEN_VER_GTEQ(ldcp, 1, 6)) { 45907bd3a2e2SSriharsha Basavapatna /* 45917bd3a2e2SSriharsha Basavapatna * Versions >= 1.6: 45927bd3a2e2SSriharsha Basavapatna * Though we are operating in v1.6 mode, it is possible that 45937bd3a2e2SSriharsha Basavapatna * RxDringData mode has been disabled either on this guest or 45947bd3a2e2SSriharsha Basavapatna * on the peer guest. If so, we revert to pre v1.6 behavior of 45957bd3a2e2SSriharsha Basavapatna * TxDring mode. But this must be agreed upon in both 45967bd3a2e2SSriharsha Basavapatna * directions of attr exchange. We first determine the mode 45977bd3a2e2SSriharsha Basavapatna * that can be negotiated. 45987bd3a2e2SSriharsha Basavapatna */ 45997bd3a2e2SSriharsha Basavapatna if ((msg->options & VIO_RX_DRING_DATA) != 0 && 4600*34f94fbcSWENTAO YANG vgen_mapin_avail(ldcp) == B_TRUE) { 46017bd3a2e2SSriharsha Basavapatna /* 46027bd3a2e2SSriharsha Basavapatna * We are capable of handling RxDringData AND the peer 46037bd3a2e2SSriharsha Basavapatna * is also capable of it; we enable RxDringData mode on 46047bd3a2e2SSriharsha Basavapatna * this channel. 46057bd3a2e2SSriharsha Basavapatna */ 46067bd3a2e2SSriharsha Basavapatna dring_mode = VIO_RX_DRING_DATA; 46077bd3a2e2SSriharsha Basavapatna } else if ((msg->options & VIO_TX_DRING) != 0) { 46087bd3a2e2SSriharsha Basavapatna /* 46097bd3a2e2SSriharsha Basavapatna * If the peer is capable of TxDring mode, we 46107bd3a2e2SSriharsha Basavapatna * negotiate TxDring mode on this channel. 46117bd3a2e2SSriharsha Basavapatna */ 46127bd3a2e2SSriharsha Basavapatna dring_mode = VIO_TX_DRING; 46137bd3a2e2SSriharsha Basavapatna } else { 46147bd3a2e2SSriharsha Basavapatna /* 46157bd3a2e2SSriharsha Basavapatna * We support only VIO_TX_DRING and VIO_RX_DRING_DATA 46167bd3a2e2SSriharsha Basavapatna * modes. We don't support VIO_RX_DRING mode. 46177bd3a2e2SSriharsha Basavapatna */ 46187bd3a2e2SSriharsha Basavapatna return (VGEN_FAILURE); 46197bd3a2e2SSriharsha Basavapatna } 46207bd3a2e2SSriharsha Basavapatna 46217bd3a2e2SSriharsha Basavapatna /* 46227bd3a2e2SSriharsha Basavapatna * If we have received an ack for the attr info that we sent, 46237bd3a2e2SSriharsha Basavapatna * then check if the dring mode matches what the peer had ack'd 46247bd3a2e2SSriharsha Basavapatna * (saved in local hparams). If they don't match, we fail the 46257bd3a2e2SSriharsha Basavapatna * handshake. 46267bd3a2e2SSriharsha Basavapatna */ 46277bd3a2e2SSriharsha Basavapatna if (ldcp->hstate & ATTR_ACK_RCVD) { 46287bd3a2e2SSriharsha Basavapatna if (msg->options != lp->dring_mode) { 46297bd3a2e2SSriharsha Basavapatna /* send NACK */ 46307bd3a2e2SSriharsha Basavapatna return (VGEN_FAILURE); 46317bd3a2e2SSriharsha Basavapatna } 46327bd3a2e2SSriharsha Basavapatna } else { 46337bd3a2e2SSriharsha Basavapatna /* 46347bd3a2e2SSriharsha Basavapatna * Save the negotiated dring mode in our attr 46357bd3a2e2SSriharsha Basavapatna * parameters, so it gets sent in the attr info from us 46367bd3a2e2SSriharsha Basavapatna * to the peer. 46377bd3a2e2SSriharsha Basavapatna */ 46387bd3a2e2SSriharsha Basavapatna lp->dring_mode = dring_mode; 46397bd3a2e2SSriharsha Basavapatna } 46407bd3a2e2SSriharsha Basavapatna 46417bd3a2e2SSriharsha Basavapatna /* save the negotiated dring mode in the msg to be replied */ 46427bd3a2e2SSriharsha Basavapatna msg->options = dring_mode; 46437bd3a2e2SSriharsha Basavapatna } 46447bd3a2e2SSriharsha Basavapatna 46457bd3a2e2SSriharsha Basavapatna /* 46467bd3a2e2SSriharsha Basavapatna * Process MTU attribute. 46477bd3a2e2SSriharsha Basavapatna */ 46487bd3a2e2SSriharsha Basavapatna if (VGEN_VER_GTEQ(ldcp, 1, 4)) { 46497bd3a2e2SSriharsha Basavapatna /* 46507bd3a2e2SSriharsha Basavapatna * Versions >= 1.4: 46517bd3a2e2SSriharsha Basavapatna * Validate mtu of the peer is at least ETHERMAX. Then, the mtu 46527bd3a2e2SSriharsha Basavapatna * is negotiated down to the minimum of our mtu and peer's mtu. 46537bd3a2e2SSriharsha Basavapatna */ 46547bd3a2e2SSriharsha Basavapatna if (msg->mtu < ETHERMAX) { 46557bd3a2e2SSriharsha Basavapatna return (VGEN_FAILURE); 46567bd3a2e2SSriharsha Basavapatna } 46577bd3a2e2SSriharsha Basavapatna 46587b1f684aSSriharsha Basavapatna mtu = MIN(msg->mtu, vgenp->max_frame_size); 46597b1f684aSSriharsha Basavapatna 46607b1f684aSSriharsha Basavapatna /* 46617b1f684aSSriharsha Basavapatna * If we have received an ack for the attr info 46627b1f684aSSriharsha Basavapatna * that we sent, then check if the mtu computed 46637b1f684aSSriharsha Basavapatna * above matches the mtu that the peer had ack'd 46647b1f684aSSriharsha Basavapatna * (saved in local hparams). If they don't 46657b1f684aSSriharsha Basavapatna * match, we fail the handshake. 46667b1f684aSSriharsha Basavapatna */ 46677b1f684aSSriharsha Basavapatna if (ldcp->hstate & ATTR_ACK_RCVD) { 46687b1f684aSSriharsha Basavapatna if (mtu != lp->mtu) { 46697b1f684aSSriharsha Basavapatna /* send NACK */ 46707bd3a2e2SSriharsha Basavapatna return (VGEN_FAILURE); 46717b1f684aSSriharsha Basavapatna } 46727b1f684aSSriharsha Basavapatna } else { 46737b1f684aSSriharsha Basavapatna /* 46747b1f684aSSriharsha Basavapatna * Save the mtu computed above in our 46757b1f684aSSriharsha Basavapatna * attr parameters, so it gets sent in 46767b1f684aSSriharsha Basavapatna * the attr info from us to the peer. 46777b1f684aSSriharsha Basavapatna */ 46787b1f684aSSriharsha Basavapatna lp->mtu = mtu; 46797b1f684aSSriharsha Basavapatna } 46807b1f684aSSriharsha Basavapatna 46817b1f684aSSriharsha Basavapatna /* save the MIN mtu in the msg to be replied */ 46827b1f684aSSriharsha Basavapatna msg->mtu = mtu; 46837b1f684aSSriharsha Basavapatna 46847b1f684aSSriharsha Basavapatna } else { 46857bd3a2e2SSriharsha Basavapatna /* versions < 1.4, mtu must match */ 46867bd3a2e2SSriharsha Basavapatna if (msg->mtu != lp->mtu) { 46877bd3a2e2SSriharsha Basavapatna return (VGEN_FAILURE); 46881ae08745Sheppo } 46891ae08745Sheppo } 46901ae08745Sheppo 46917bd3a2e2SSriharsha Basavapatna return (VGEN_SUCCESS); 46927bd3a2e2SSriharsha Basavapatna } 46937bd3a2e2SSriharsha Basavapatna 46947bd3a2e2SSriharsha Basavapatna static int 46957bd3a2e2SSriharsha Basavapatna vgen_handle_attr_ack(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg) 46967bd3a2e2SSriharsha Basavapatna { 46977bd3a2e2SSriharsha Basavapatna vgen_t *vgenp = LDC_TO_VGEN(ldcp); 46987bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams; 46997bd3a2e2SSriharsha Basavapatna 47007bd3a2e2SSriharsha Basavapatna /* 47017bd3a2e2SSriharsha Basavapatna * Process dring mode attribute. 47027bd3a2e2SSriharsha Basavapatna */ 47037bd3a2e2SSriharsha Basavapatna if (VGEN_VER_GTEQ(ldcp, 1, 6)) { 47047bd3a2e2SSriharsha Basavapatna /* 47057bd3a2e2SSriharsha Basavapatna * Versions >= 1.6: 47067bd3a2e2SSriharsha Basavapatna * The ack msg sent by the peer contains the negotiated dring 47077bd3a2e2SSriharsha Basavapatna * mode between our capability (that we had sent in our attr 47087bd3a2e2SSriharsha Basavapatna * info) and the peer's capability. 47097bd3a2e2SSriharsha Basavapatna */ 47107bd3a2e2SSriharsha Basavapatna if (ldcp->hstate & ATTR_ACK_SENT) { 47117bd3a2e2SSriharsha Basavapatna /* 47127bd3a2e2SSriharsha Basavapatna * If we have sent an ack for the attr info msg from 47137bd3a2e2SSriharsha Basavapatna * the peer, check if the dring mode that was 47147bd3a2e2SSriharsha Basavapatna * negotiated then (saved in local hparams) matches the 47157bd3a2e2SSriharsha Basavapatna * mode that the peer has ack'd. If they don't match, 47167bd3a2e2SSriharsha Basavapatna * we fail the handshake. 47177bd3a2e2SSriharsha Basavapatna */ 47187bd3a2e2SSriharsha Basavapatna if (lp->dring_mode != msg->options) { 47197bd3a2e2SSriharsha Basavapatna return (VGEN_FAILURE); 47207bd3a2e2SSriharsha Basavapatna } 47211ae08745Sheppo } else { 47227bd3a2e2SSriharsha Basavapatna if ((msg->options & lp->dring_mode) == 0) { 47237bd3a2e2SSriharsha Basavapatna /* 47247bd3a2e2SSriharsha Basavapatna * Peer ack'd with a mode that we don't 47257bd3a2e2SSriharsha Basavapatna * support; we fail the handshake. 47267bd3a2e2SSriharsha Basavapatna */ 47277bd3a2e2SSriharsha Basavapatna return (VGEN_FAILURE); 47287bd3a2e2SSriharsha Basavapatna } 47297bd3a2e2SSriharsha Basavapatna if ((msg->options & (VIO_TX_DRING|VIO_RX_DRING_DATA)) 47307bd3a2e2SSriharsha Basavapatna == (VIO_TX_DRING|VIO_RX_DRING_DATA)) { 47317bd3a2e2SSriharsha Basavapatna /* 47327bd3a2e2SSriharsha Basavapatna * Peer must ack with only one negotiated mode. 47337bd3a2e2SSriharsha Basavapatna * Otherwise fail handshake. 47347bd3a2e2SSriharsha Basavapatna */ 47353af08d82Slm66018 return (VGEN_FAILURE); 47361ae08745Sheppo } 47371ae08745Sheppo 47387bd3a2e2SSriharsha Basavapatna /* 47397bd3a2e2SSriharsha Basavapatna * Save the negotiated mode, so we can validate it when 47407bd3a2e2SSriharsha Basavapatna * we receive attr info from the peer. 47417bd3a2e2SSriharsha Basavapatna */ 47427bd3a2e2SSriharsha Basavapatna lp->dring_mode = msg->options; 47437bd3a2e2SSriharsha Basavapatna } 47441ae08745Sheppo } 47451ae08745Sheppo 47467bd3a2e2SSriharsha Basavapatna /* 47477bd3a2e2SSriharsha Basavapatna * Process Physical Link Update attribute. 47487bd3a2e2SSriharsha Basavapatna */ 47491107ea93SSriharsha Basavapatna if (VGEN_VER_GTEQ(ldcp, 1, 5) && 47501107ea93SSriharsha Basavapatna ldcp->portp == vgenp->vsw_portp) { 47511107ea93SSriharsha Basavapatna /* 47521107ea93SSriharsha Basavapatna * Versions >= 1.5: 47531107ea93SSriharsha Basavapatna * If the vnet device has been configured to get 47541107ea93SSriharsha Basavapatna * physical link state updates, check the corresponding 47551107ea93SSriharsha Basavapatna * bits in the ack msg, if the peer is vswitch. 47561107ea93SSriharsha Basavapatna */ 47577bd3a2e2SSriharsha Basavapatna if (((lp->physlink_update & PHYSLINK_UPDATE_STATE_MASK) == 47581107ea93SSriharsha Basavapatna PHYSLINK_UPDATE_STATE) && 47597bd3a2e2SSriharsha Basavapatna ((msg->physlink_update & PHYSLINK_UPDATE_STATE_MASK) == 47601107ea93SSriharsha Basavapatna PHYSLINK_UPDATE_STATE_ACK)) { 47611107ea93SSriharsha Basavapatna vgenp->pls_negotiated = B_TRUE; 47621107ea93SSriharsha Basavapatna } else { 47631107ea93SSriharsha Basavapatna vgenp->pls_negotiated = B_FALSE; 47641107ea93SSriharsha Basavapatna } 47651107ea93SSriharsha Basavapatna } 47661107ea93SSriharsha Basavapatna 47677bd3a2e2SSriharsha Basavapatna /* 47687bd3a2e2SSriharsha Basavapatna * Process MTU attribute. 47697bd3a2e2SSriharsha Basavapatna */ 47707b1f684aSSriharsha Basavapatna if (VGEN_VER_GTEQ(ldcp, 1, 4)) { 47717b1f684aSSriharsha Basavapatna /* 47727b1f684aSSriharsha Basavapatna * Versions >= 1.4: 47737b1f684aSSriharsha Basavapatna * The ack msg sent by the peer contains the minimum of 47747b1f684aSSriharsha Basavapatna * our mtu (that we had sent in our attr info) and the 47757b1f684aSSriharsha Basavapatna * peer's mtu. 47767b1f684aSSriharsha Basavapatna * 47777b1f684aSSriharsha Basavapatna * If we have sent an ack for the attr info msg from 47787b1f684aSSriharsha Basavapatna * the peer, check if the mtu that was computed then 47797b1f684aSSriharsha Basavapatna * (saved in local hparams) matches the mtu that the 47807b1f684aSSriharsha Basavapatna * peer has ack'd. If they don't match, we fail the 47817b1f684aSSriharsha Basavapatna * handshake. 47827b1f684aSSriharsha Basavapatna */ 47837b1f684aSSriharsha Basavapatna if (ldcp->hstate & ATTR_ACK_SENT) { 47847b1f684aSSriharsha Basavapatna if (lp->mtu != msg->mtu) { 47857b1f684aSSriharsha Basavapatna return (VGEN_FAILURE); 47867b1f684aSSriharsha Basavapatna } 47877b1f684aSSriharsha Basavapatna } else { 47887b1f684aSSriharsha Basavapatna /* 47897b1f684aSSriharsha Basavapatna * If the mtu ack'd by the peer is > our mtu 47907b1f684aSSriharsha Basavapatna * fail handshake. Otherwise, save the mtu, so 47917b1f684aSSriharsha Basavapatna * we can validate it when we receive attr info 47927b1f684aSSriharsha Basavapatna * from our peer. 47937b1f684aSSriharsha Basavapatna */ 47947b1f684aSSriharsha Basavapatna if (msg->mtu > lp->mtu) { 47957b1f684aSSriharsha Basavapatna return (VGEN_FAILURE); 47967b1f684aSSriharsha Basavapatna } 47977b1f684aSSriharsha Basavapatna if (msg->mtu <= lp->mtu) { 47987b1f684aSSriharsha Basavapatna lp->mtu = msg->mtu; 47997b1f684aSSriharsha Basavapatna } 48007b1f684aSSriharsha Basavapatna } 48017b1f684aSSriharsha Basavapatna } 48027b1f684aSSriharsha Basavapatna 48037bd3a2e2SSriharsha Basavapatna return (VGEN_SUCCESS); 48047bd3a2e2SSriharsha Basavapatna } 48051ae08745Sheppo 48067bd3a2e2SSriharsha Basavapatna 48077bd3a2e2SSriharsha Basavapatna /* 48087bd3a2e2SSriharsha Basavapatna * Handle an attribute info msg from the peer or an ACK/NACK from the peer 48097bd3a2e2SSriharsha Basavapatna * to an attr info msg that we sent. 48107bd3a2e2SSriharsha Basavapatna */ 48117bd3a2e2SSriharsha Basavapatna static int 48127bd3a2e2SSriharsha Basavapatna vgen_handle_attr_msg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 48137bd3a2e2SSriharsha Basavapatna { 48147bd3a2e2SSriharsha Basavapatna vgen_t *vgenp = LDC_TO_VGEN(ldcp); 48157bd3a2e2SSriharsha Basavapatna vnet_attr_msg_t *msg = (vnet_attr_msg_t *)tagp; 48167bd3a2e2SSriharsha Basavapatna int rv = 0; 48177bd3a2e2SSriharsha Basavapatna 48187bd3a2e2SSriharsha Basavapatna DBG1(vgenp, ldcp, "enter\n"); 48197bd3a2e2SSriharsha Basavapatna if (ldcp->hphase != VH_PHASE2) { 48207bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "Rcvd ATTR_INFO subtype(%d)," 48217bd3a2e2SSriharsha Basavapatna " Invalid Phase(%u)\n", 48227bd3a2e2SSriharsha Basavapatna tagp->vio_subtype, ldcp->hphase); 48237bd3a2e2SSriharsha Basavapatna return (VGEN_FAILURE); 48247bd3a2e2SSriharsha Basavapatna } 48257bd3a2e2SSriharsha Basavapatna switch (tagp->vio_subtype) { 48267bd3a2e2SSriharsha Basavapatna case VIO_SUBTYPE_INFO: 48277bd3a2e2SSriharsha Basavapatna 48287bd3a2e2SSriharsha Basavapatna rv = vgen_handle_attr_info(ldcp, msg); 48297bd3a2e2SSriharsha Basavapatna if (rv == VGEN_SUCCESS) { 48307bd3a2e2SSriharsha Basavapatna tagp->vio_subtype = VIO_SUBTYPE_ACK; 48317bd3a2e2SSriharsha Basavapatna } else { 48327bd3a2e2SSriharsha Basavapatna tagp->vio_subtype = VIO_SUBTYPE_NACK; 48337bd3a2e2SSriharsha Basavapatna } 48347bd3a2e2SSriharsha Basavapatna tagp->vio_sid = ldcp->local_sid; 48357bd3a2e2SSriharsha Basavapatna 48367bd3a2e2SSriharsha Basavapatna /* send reply msg back to peer */ 48377bd3a2e2SSriharsha Basavapatna rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msg), 48387bd3a2e2SSriharsha Basavapatna B_FALSE); 48397bd3a2e2SSriharsha Basavapatna if (rv != VGEN_SUCCESS) { 48407bd3a2e2SSriharsha Basavapatna return (rv); 48417bd3a2e2SSriharsha Basavapatna } 48427bd3a2e2SSriharsha Basavapatna 48437bd3a2e2SSriharsha Basavapatna if (tagp->vio_subtype == VIO_SUBTYPE_NACK) { 48447bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "ATTR_NACK_SENT"); 48457bd3a2e2SSriharsha Basavapatna break; 48467bd3a2e2SSriharsha Basavapatna } 48477bd3a2e2SSriharsha Basavapatna 48487bd3a2e2SSriharsha Basavapatna ldcp->hstate |= ATTR_ACK_SENT; 48497bd3a2e2SSriharsha Basavapatna DBG2(vgenp, ldcp, "ATTR_ACK_SENT \n"); 48507bd3a2e2SSriharsha Basavapatna if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 48517bd3a2e2SSriharsha Basavapatna rv = vgen_handshake(vh_nextphase(ldcp)); 48527bd3a2e2SSriharsha Basavapatna if (rv != 0) { 48537bd3a2e2SSriharsha Basavapatna return (rv); 48547bd3a2e2SSriharsha Basavapatna } 48557bd3a2e2SSriharsha Basavapatna } 48567bd3a2e2SSriharsha Basavapatna 48577bd3a2e2SSriharsha Basavapatna break; 48587bd3a2e2SSriharsha Basavapatna 48597bd3a2e2SSriharsha Basavapatna case VIO_SUBTYPE_ACK: 48607bd3a2e2SSriharsha Basavapatna 48617bd3a2e2SSriharsha Basavapatna rv = vgen_handle_attr_ack(ldcp, msg); 48627bd3a2e2SSriharsha Basavapatna if (rv == VGEN_FAILURE) { 48637bd3a2e2SSriharsha Basavapatna break; 48647bd3a2e2SSriharsha Basavapatna } 48657bd3a2e2SSriharsha Basavapatna 48667bd3a2e2SSriharsha Basavapatna ldcp->hstate |= ATTR_ACK_RCVD; 4867844e62a3Sraghuram DBG2(vgenp, ldcp, "ATTR_ACK_RCVD \n"); 48681ae08745Sheppo 48691ae08745Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 48707bd3a2e2SSriharsha Basavapatna rv = vgen_handshake(vh_nextphase(ldcp)); 48717bd3a2e2SSriharsha Basavapatna if (rv != 0) { 48727bd3a2e2SSriharsha Basavapatna return (rv); 48737bd3a2e2SSriharsha Basavapatna } 48741ae08745Sheppo } 48751ae08745Sheppo break; 48761ae08745Sheppo 48771ae08745Sheppo case VIO_SUBTYPE_NACK: 48781ae08745Sheppo 4879844e62a3Sraghuram DBG2(vgenp, ldcp, "ATTR_NACK_RCVD \n"); 48803af08d82Slm66018 return (VGEN_FAILURE); 48811ae08745Sheppo } 4882844e62a3Sraghuram DBG1(vgenp, ldcp, "exit\n"); 48833af08d82Slm66018 return (VGEN_SUCCESS); 48841ae08745Sheppo } 48851ae08745Sheppo 48861ae08745Sheppo static int 48877bd3a2e2SSriharsha Basavapatna vgen_handle_dring_reg_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 48881ae08745Sheppo { 48897bd3a2e2SSriharsha Basavapatna int rv = 0; 48907bd3a2e2SSriharsha Basavapatna vgen_t *vgenp = LDC_TO_VGEN(ldcp); 48917bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams; 48927bd3a2e2SSriharsha Basavapatna 48937bd3a2e2SSriharsha Basavapatna DBG2(vgenp, ldcp, "DRING_INFO_RCVD"); 48947bd3a2e2SSriharsha Basavapatna ldcp->hstate |= DRING_INFO_RCVD; 48957bd3a2e2SSriharsha Basavapatna 48967bd3a2e2SSriharsha Basavapatna if (VGEN_VER_GTEQ(ldcp, 1, 6) && 48977bd3a2e2SSriharsha Basavapatna (lp->dring_mode != ((vio_dring_reg_msg_t *)tagp)->options)) { 48987bd3a2e2SSriharsha Basavapatna /* 48997bd3a2e2SSriharsha Basavapatna * The earlier version of Solaris vnet driver doesn't set the 49007bd3a2e2SSriharsha Basavapatna * option (VIO_TX_DRING in its case) correctly in its dring reg 49017bd3a2e2SSriharsha Basavapatna * message. We workaround that here by doing the check only 49027bd3a2e2SSriharsha Basavapatna * for versions >= v1.6. 49037bd3a2e2SSriharsha Basavapatna */ 49047bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, 49057bd3a2e2SSriharsha Basavapatna "Rcvd dring reg option (%d), negotiated mode (%d)\n", 49067bd3a2e2SSriharsha Basavapatna ((vio_dring_reg_msg_t *)tagp)->options, lp->dring_mode); 49071ae08745Sheppo return (VGEN_FAILURE); 49081ae08745Sheppo } 49097bd3a2e2SSriharsha Basavapatna 49107bd3a2e2SSriharsha Basavapatna /* 49117bd3a2e2SSriharsha Basavapatna * Map dring exported by the peer. 49127bd3a2e2SSriharsha Basavapatna */ 49137bd3a2e2SSriharsha Basavapatna rv = vgen_map_dring(ldcp, (void *)tagp); 49147bd3a2e2SSriharsha Basavapatna if (rv != VGEN_SUCCESS) { 49157bd3a2e2SSriharsha Basavapatna return (rv); 49167bd3a2e2SSriharsha Basavapatna } 49177bd3a2e2SSriharsha Basavapatna 49187bd3a2e2SSriharsha Basavapatna /* 49197bd3a2e2SSriharsha Basavapatna * Map data buffers exported by the peer if we are in RxDringData mode. 49207bd3a2e2SSriharsha Basavapatna */ 49217bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_RX_DRING_DATA) { 49227bd3a2e2SSriharsha Basavapatna rv = vgen_map_data(ldcp, (void *)tagp); 49237bd3a2e2SSriharsha Basavapatna if (rv != VGEN_SUCCESS) { 49247bd3a2e2SSriharsha Basavapatna vgen_unmap_dring(ldcp); 49257bd3a2e2SSriharsha Basavapatna return (rv); 49267bd3a2e2SSriharsha Basavapatna } 49277bd3a2e2SSriharsha Basavapatna } 49287bd3a2e2SSriharsha Basavapatna 49297bd3a2e2SSriharsha Basavapatna if (ldcp->peer_hparams.dring_ready == B_FALSE) { 49307bd3a2e2SSriharsha Basavapatna ldcp->peer_hparams.dring_ready = B_TRUE; 49317bd3a2e2SSriharsha Basavapatna } 49327bd3a2e2SSriharsha Basavapatna 49337bd3a2e2SSriharsha Basavapatna return (VGEN_SUCCESS); 49347bd3a2e2SSriharsha Basavapatna } 49357bd3a2e2SSriharsha Basavapatna 49367bd3a2e2SSriharsha Basavapatna static int 49377bd3a2e2SSriharsha Basavapatna vgen_handle_dring_reg_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 49387bd3a2e2SSriharsha Basavapatna { 49397bd3a2e2SSriharsha Basavapatna vgen_t *vgenp = LDC_TO_VGEN(ldcp); 49407bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams; 49417bd3a2e2SSriharsha Basavapatna 49427bd3a2e2SSriharsha Basavapatna DBG2(vgenp, ldcp, "DRING_ACK_RCVD"); 49437bd3a2e2SSriharsha Basavapatna ldcp->hstate |= DRING_ACK_RCVD; 49447bd3a2e2SSriharsha Basavapatna 49457bd3a2e2SSriharsha Basavapatna if (lp->dring_ready) { 49467bd3a2e2SSriharsha Basavapatna return (VGEN_SUCCESS); 49477bd3a2e2SSriharsha Basavapatna } 49487bd3a2e2SSriharsha Basavapatna 49497bd3a2e2SSriharsha Basavapatna /* save dring_ident acked by peer */ 49507bd3a2e2SSriharsha Basavapatna lp->dring_ident = ((vio_dring_reg_msg_t *)tagp)->dring_ident; 49517bd3a2e2SSriharsha Basavapatna 49527bd3a2e2SSriharsha Basavapatna /* local dring is now ready */ 49537bd3a2e2SSriharsha Basavapatna lp->dring_ready = B_TRUE; 49547bd3a2e2SSriharsha Basavapatna 49551ae08745Sheppo return (VGEN_SUCCESS); 49561ae08745Sheppo } 49571ae08745Sheppo 49581ae08745Sheppo /* 49591ae08745Sheppo * Handle a descriptor ring register msg from the peer or an ACK/NACK from 49601ae08745Sheppo * the peer to a dring register msg that we sent. 49611ae08745Sheppo */ 49623af08d82Slm66018 static int 49631ae08745Sheppo vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 49641ae08745Sheppo { 4965844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 49661ae08745Sheppo int rv = 0; 49677bd3a2e2SSriharsha Basavapatna int msgsize; 49687bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams; 49691ae08745Sheppo 4970844e62a3Sraghuram DBG1(vgenp, ldcp, "enter\n"); 49711ae08745Sheppo if (ldcp->hphase < VH_PHASE2) { 49721ae08745Sheppo /* dring_info can be rcvd in any of the phases after Phase1 */ 4973844e62a3Sraghuram DWARN(vgenp, ldcp, 4974844e62a3Sraghuram "Rcvd DRING_INFO Subtype (%d), Invalid Phase(%u)\n", 4975844e62a3Sraghuram tagp->vio_subtype, ldcp->hphase); 49763af08d82Slm66018 return (VGEN_FAILURE); 49771ae08745Sheppo } 49787bd3a2e2SSriharsha Basavapatna 49791ae08745Sheppo switch (tagp->vio_subtype) { 49801ae08745Sheppo case VIO_SUBTYPE_INFO: 49811ae08745Sheppo 49827bd3a2e2SSriharsha Basavapatna rv = vgen_handle_dring_reg_info(ldcp, tagp); 49837bd3a2e2SSriharsha Basavapatna if (rv == VGEN_SUCCESS) { 49841ae08745Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 49857bd3a2e2SSriharsha Basavapatna } else { 49867bd3a2e2SSriharsha Basavapatna tagp->vio_subtype = VIO_SUBTYPE_NACK; 49871ae08745Sheppo } 49887bd3a2e2SSriharsha Basavapatna 49891ae08745Sheppo tagp->vio_sid = ldcp->local_sid; 49907bd3a2e2SSriharsha Basavapatna 49917bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_RX_DRING_DATA) { 49927bd3a2e2SSriharsha Basavapatna msgsize = 49937bd3a2e2SSriharsha Basavapatna VNET_DRING_REG_EXT_MSG_SIZE(ldcp->tx_data_ncookies); 49947bd3a2e2SSriharsha Basavapatna } else { 49957bd3a2e2SSriharsha Basavapatna msgsize = sizeof (vio_dring_reg_msg_t); 49967bd3a2e2SSriharsha Basavapatna } 49977bd3a2e2SSriharsha Basavapatna 49981ae08745Sheppo /* send reply msg back to peer */ 49997bd3a2e2SSriharsha Basavapatna rv = vgen_sendmsg(ldcp, (caddr_t)tagp, msgsize, 50003af08d82Slm66018 B_FALSE); 50013af08d82Slm66018 if (rv != VGEN_SUCCESS) { 50023af08d82Slm66018 return (rv); 50031ae08745Sheppo } 50041ae08745Sheppo 50057bd3a2e2SSriharsha Basavapatna if (tagp->vio_subtype == VIO_SUBTYPE_NACK) { 5006844e62a3Sraghuram DWARN(vgenp, ldcp, "DRING_NACK_SENT"); 50073af08d82Slm66018 return (VGEN_FAILURE); 50081ae08745Sheppo } 50091ae08745Sheppo 50107bd3a2e2SSriharsha Basavapatna ldcp->hstate |= DRING_ACK_SENT; 50117bd3a2e2SSriharsha Basavapatna DBG2(vgenp, ldcp, "DRING_ACK_SENT"); 50121ae08745Sheppo 50137bd3a2e2SSriharsha Basavapatna if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 50147bd3a2e2SSriharsha Basavapatna rv = vgen_handshake(vh_nextphase(ldcp)); 50157bd3a2e2SSriharsha Basavapatna if (rv != 0) { 50167bd3a2e2SSriharsha Basavapatna return (rv); 50177bd3a2e2SSriharsha Basavapatna } 50187bd3a2e2SSriharsha Basavapatna } 50191ae08745Sheppo break; 50201ae08745Sheppo 50211ae08745Sheppo case VIO_SUBTYPE_ACK: 50221ae08745Sheppo 50237bd3a2e2SSriharsha Basavapatna rv = vgen_handle_dring_reg_ack(ldcp, tagp); 50247bd3a2e2SSriharsha Basavapatna if (rv == VGEN_FAILURE) { 50257bd3a2e2SSriharsha Basavapatna return (rv); 50261ae08745Sheppo } 50271ae08745Sheppo 50281ae08745Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 50297bd3a2e2SSriharsha Basavapatna rv = vgen_handshake(vh_nextphase(ldcp)); 50307bd3a2e2SSriharsha Basavapatna if (rv != 0) { 50317bd3a2e2SSriharsha Basavapatna return (rv); 50327bd3a2e2SSriharsha Basavapatna } 50331ae08745Sheppo } 50341ae08745Sheppo 50351ae08745Sheppo break; 50361ae08745Sheppo 50371ae08745Sheppo case VIO_SUBTYPE_NACK: 50381ae08745Sheppo 50397bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "DRING_NACK_RCVD"); 50403af08d82Slm66018 return (VGEN_FAILURE); 50411ae08745Sheppo } 5042844e62a3Sraghuram DBG1(vgenp, ldcp, "exit\n"); 50433af08d82Slm66018 return (VGEN_SUCCESS); 50441ae08745Sheppo } 50451ae08745Sheppo 50461ae08745Sheppo /* 50471ae08745Sheppo * Handle a rdx info msg from the peer or an ACK/NACK 50481ae08745Sheppo * from the peer to a rdx info msg that we sent. 50491ae08745Sheppo */ 50503af08d82Slm66018 static int 50511ae08745Sheppo vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 50521ae08745Sheppo { 50533af08d82Slm66018 int rv = 0; 5054844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 50551ae08745Sheppo 5056844e62a3Sraghuram DBG1(vgenp, ldcp, "enter\n"); 50577bd3a2e2SSriharsha Basavapatna if (ldcp->hphase != VH_PHASE4) { 5058844e62a3Sraghuram DWARN(vgenp, ldcp, 5059844e62a3Sraghuram "Rcvd RDX_INFO Subtype (%d), Invalid Phase(%u)\n", 5060844e62a3Sraghuram tagp->vio_subtype, ldcp->hphase); 50613af08d82Slm66018 return (VGEN_FAILURE); 50621ae08745Sheppo } 50631ae08745Sheppo switch (tagp->vio_subtype) { 50641ae08745Sheppo case VIO_SUBTYPE_INFO: 50651ae08745Sheppo 5066844e62a3Sraghuram DBG2(vgenp, ldcp, "RDX_INFO_RCVD \n"); 50671ae08745Sheppo ldcp->hstate |= RDX_INFO_RCVD; 50681ae08745Sheppo 50691ae08745Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 50701ae08745Sheppo tagp->vio_sid = ldcp->local_sid; 50711ae08745Sheppo /* send reply msg back to peer */ 50723af08d82Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vio_rdx_msg_t), 50733af08d82Slm66018 B_FALSE); 50743af08d82Slm66018 if (rv != VGEN_SUCCESS) { 50753af08d82Slm66018 return (rv); 50761ae08745Sheppo } 50771ae08745Sheppo 50781ae08745Sheppo ldcp->hstate |= RDX_ACK_SENT; 5079844e62a3Sraghuram DBG2(vgenp, ldcp, "RDX_ACK_SENT \n"); 50801ae08745Sheppo 50811ae08745Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 50827bd3a2e2SSriharsha Basavapatna rv = vgen_handshake(vh_nextphase(ldcp)); 50837bd3a2e2SSriharsha Basavapatna if (rv != 0) { 50847bd3a2e2SSriharsha Basavapatna return (rv); 50857bd3a2e2SSriharsha Basavapatna } 50861ae08745Sheppo } 50871ae08745Sheppo 50881ae08745Sheppo break; 50891ae08745Sheppo 50901ae08745Sheppo case VIO_SUBTYPE_ACK: 50911ae08745Sheppo 50921ae08745Sheppo ldcp->hstate |= RDX_ACK_RCVD; 50931ae08745Sheppo 5094844e62a3Sraghuram DBG2(vgenp, ldcp, "RDX_ACK_RCVD \n"); 50951ae08745Sheppo 50961ae08745Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 50977bd3a2e2SSriharsha Basavapatna rv = vgen_handshake(vh_nextphase(ldcp)); 50987bd3a2e2SSriharsha Basavapatna if (rv != 0) { 50997bd3a2e2SSriharsha Basavapatna return (rv); 51007bd3a2e2SSriharsha Basavapatna } 51011ae08745Sheppo } 51021ae08745Sheppo break; 51031ae08745Sheppo 51041ae08745Sheppo case VIO_SUBTYPE_NACK: 51051ae08745Sheppo 5106844e62a3Sraghuram DBG2(vgenp, ldcp, "RDX_NACK_RCVD \n"); 51073af08d82Slm66018 return (VGEN_FAILURE); 51081ae08745Sheppo } 5109844e62a3Sraghuram DBG1(vgenp, ldcp, "exit\n"); 51103af08d82Slm66018 return (VGEN_SUCCESS); 51111ae08745Sheppo } 51121ae08745Sheppo 51131ae08745Sheppo /* Handle ACK/NACK from vsw to a set multicast msg that we sent */ 51143af08d82Slm66018 static int 51151ae08745Sheppo vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 51161ae08745Sheppo { 51171ae08745Sheppo vgen_t *vgenp = LDC_TO_VGEN(ldcp); 51181ae08745Sheppo vnet_mcast_msg_t *msgp = (vnet_mcast_msg_t *)tagp; 51191ae08745Sheppo struct ether_addr *addrp; 51201ae08745Sheppo int count; 51211ae08745Sheppo int i; 51221ae08745Sheppo 5123844e62a3Sraghuram DBG1(vgenp, ldcp, "enter\n"); 51241ae08745Sheppo switch (tagp->vio_subtype) { 51251ae08745Sheppo 51261ae08745Sheppo case VIO_SUBTYPE_INFO: 51271ae08745Sheppo 51281ae08745Sheppo /* vnet shouldn't recv set mcast msg, only vsw handles it */ 5129844e62a3Sraghuram DWARN(vgenp, ldcp, "rcvd SET_MCAST_INFO \n"); 51301ae08745Sheppo break; 51311ae08745Sheppo 51321ae08745Sheppo case VIO_SUBTYPE_ACK: 51331ae08745Sheppo 51341ae08745Sheppo /* success adding/removing multicast addr */ 5135844e62a3Sraghuram DBG1(vgenp, ldcp, "rcvd SET_MCAST_ACK \n"); 51361ae08745Sheppo break; 51371ae08745Sheppo 51381ae08745Sheppo case VIO_SUBTYPE_NACK: 51391ae08745Sheppo 5140844e62a3Sraghuram DWARN(vgenp, ldcp, "rcvd SET_MCAST_NACK \n"); 51411ae08745Sheppo if (!(msgp->set)) { 51421ae08745Sheppo /* multicast remove request failed */ 51431ae08745Sheppo break; 51441ae08745Sheppo } 51451ae08745Sheppo 51461ae08745Sheppo /* multicast add request failed */ 51471ae08745Sheppo for (count = 0; count < msgp->count; count++) { 51481ae08745Sheppo addrp = &(msgp->mca[count]); 51491ae08745Sheppo 51501ae08745Sheppo /* delete address from the table */ 51511ae08745Sheppo for (i = 0; i < vgenp->mccount; i++) { 51521ae08745Sheppo if (ether_cmp(addrp, 51531ae08745Sheppo &(vgenp->mctab[i])) == 0) { 51541ae08745Sheppo if (vgenp->mccount > 1) { 5155844e62a3Sraghuram int t = vgenp->mccount - 1; 51561ae08745Sheppo vgenp->mctab[i] = 5157844e62a3Sraghuram vgenp->mctab[t]; 51581ae08745Sheppo } 51591ae08745Sheppo vgenp->mccount--; 51601ae08745Sheppo break; 51611ae08745Sheppo } 51621ae08745Sheppo } 51631ae08745Sheppo } 51641ae08745Sheppo break; 51651ae08745Sheppo 51661ae08745Sheppo } 5167844e62a3Sraghuram DBG1(vgenp, ldcp, "exit\n"); 51683af08d82Slm66018 51693af08d82Slm66018 return (VGEN_SUCCESS); 51701ae08745Sheppo } 51711ae08745Sheppo 51721107ea93SSriharsha Basavapatna /* 51731107ea93SSriharsha Basavapatna * Physical link information message from the peer. Only vswitch should send 51741107ea93SSriharsha Basavapatna * us this message; if the vnet device has been configured to get physical link 51751107ea93SSriharsha Basavapatna * state updates. Note that we must have already negotiated this with the 51761107ea93SSriharsha Basavapatna * vswitch during attribute exchange phase of handshake. 51771107ea93SSriharsha Basavapatna */ 51781107ea93SSriharsha Basavapatna static int 51791107ea93SSriharsha Basavapatna vgen_handle_physlink_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 51801107ea93SSriharsha Basavapatna { 51811107ea93SSriharsha Basavapatna vgen_t *vgenp = LDC_TO_VGEN(ldcp); 51821107ea93SSriharsha Basavapatna vnet_physlink_msg_t *msgp = (vnet_physlink_msg_t *)tagp; 51831107ea93SSriharsha Basavapatna link_state_t link_state; 51841107ea93SSriharsha Basavapatna int rv; 51851107ea93SSriharsha Basavapatna 51861107ea93SSriharsha Basavapatna if (ldcp->portp != vgenp->vsw_portp) { 51871107ea93SSriharsha Basavapatna /* 51881107ea93SSriharsha Basavapatna * drop the message and don't process; as we should 51891107ea93SSriharsha Basavapatna * receive physlink_info message from only vswitch. 51901107ea93SSriharsha Basavapatna */ 51911107ea93SSriharsha Basavapatna return (VGEN_SUCCESS); 51921107ea93SSriharsha Basavapatna } 51931107ea93SSriharsha Basavapatna 51941107ea93SSriharsha Basavapatna if (vgenp->pls_negotiated == B_FALSE) { 51951107ea93SSriharsha Basavapatna /* 51961107ea93SSriharsha Basavapatna * drop the message and don't process; as we should receive 51971107ea93SSriharsha Basavapatna * physlink_info message only if physlink update is enabled for 51981107ea93SSriharsha Basavapatna * the device and negotiated with vswitch. 51991107ea93SSriharsha Basavapatna */ 52001107ea93SSriharsha Basavapatna return (VGEN_SUCCESS); 52011107ea93SSriharsha Basavapatna } 52021107ea93SSriharsha Basavapatna 52031107ea93SSriharsha Basavapatna switch (tagp->vio_subtype) { 52041107ea93SSriharsha Basavapatna 52051107ea93SSriharsha Basavapatna case VIO_SUBTYPE_INFO: 52061107ea93SSriharsha Basavapatna 52071107ea93SSriharsha Basavapatna if ((msgp->physlink_info & VNET_PHYSLINK_STATE_MASK) == 52081107ea93SSriharsha Basavapatna VNET_PHYSLINK_STATE_UP) { 52091107ea93SSriharsha Basavapatna link_state = LINK_STATE_UP; 52101107ea93SSriharsha Basavapatna } else { 52111107ea93SSriharsha Basavapatna link_state = LINK_STATE_DOWN; 52121107ea93SSriharsha Basavapatna } 52131107ea93SSriharsha Basavapatna 52141107ea93SSriharsha Basavapatna if (vgenp->phys_link_state != link_state) { 52151107ea93SSriharsha Basavapatna vgenp->phys_link_state = link_state; 52161107ea93SSriharsha Basavapatna mutex_exit(&ldcp->cblock); 52171107ea93SSriharsha Basavapatna 52181107ea93SSriharsha Basavapatna /* Now update the stack */ 52191107ea93SSriharsha Basavapatna vgen_link_update(vgenp, link_state); 52201107ea93SSriharsha Basavapatna 52211107ea93SSriharsha Basavapatna mutex_enter(&ldcp->cblock); 52221107ea93SSriharsha Basavapatna } 52231107ea93SSriharsha Basavapatna 52241107ea93SSriharsha Basavapatna tagp->vio_subtype = VIO_SUBTYPE_ACK; 52251107ea93SSriharsha Basavapatna tagp->vio_sid = ldcp->local_sid; 52261107ea93SSriharsha Basavapatna 52271107ea93SSriharsha Basavapatna /* send reply msg back to peer */ 52281107ea93SSriharsha Basavapatna rv = vgen_sendmsg(ldcp, (caddr_t)tagp, 52291107ea93SSriharsha Basavapatna sizeof (vnet_physlink_msg_t), B_FALSE); 52301107ea93SSriharsha Basavapatna if (rv != VGEN_SUCCESS) { 52311107ea93SSriharsha Basavapatna return (rv); 52321107ea93SSriharsha Basavapatna } 52331107ea93SSriharsha Basavapatna break; 52341107ea93SSriharsha Basavapatna 52351107ea93SSriharsha Basavapatna case VIO_SUBTYPE_ACK: 52361107ea93SSriharsha Basavapatna 52371107ea93SSriharsha Basavapatna /* vnet shouldn't recv physlink acks */ 52381107ea93SSriharsha Basavapatna DWARN(vgenp, ldcp, "rcvd PHYSLINK_ACK \n"); 52391107ea93SSriharsha Basavapatna break; 52401107ea93SSriharsha Basavapatna 52411107ea93SSriharsha Basavapatna case VIO_SUBTYPE_NACK: 52421107ea93SSriharsha Basavapatna 52431107ea93SSriharsha Basavapatna /* vnet shouldn't recv physlink nacks */ 52441107ea93SSriharsha Basavapatna DWARN(vgenp, ldcp, "rcvd PHYSLINK_NACK \n"); 52451107ea93SSriharsha Basavapatna break; 52461107ea93SSriharsha Basavapatna 52471107ea93SSriharsha Basavapatna } 52481107ea93SSriharsha Basavapatna DBG1(vgenp, ldcp, "exit\n"); 52491107ea93SSriharsha Basavapatna 52501107ea93SSriharsha Basavapatna return (VGEN_SUCCESS); 52511107ea93SSriharsha Basavapatna } 52521107ea93SSriharsha Basavapatna 52531ae08745Sheppo /* handler for control messages received from the peer ldc end-point */ 52543af08d82Slm66018 static int 52551ae08745Sheppo vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 52561ae08745Sheppo { 52573af08d82Slm66018 int rv = 0; 5258844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 52591ae08745Sheppo 5260844e62a3Sraghuram DBG1(vgenp, ldcp, "enter\n"); 52611ae08745Sheppo switch (tagp->vio_subtype_env) { 52621ae08745Sheppo 52631ae08745Sheppo case VIO_VER_INFO: 52643af08d82Slm66018 rv = vgen_handle_version_negotiate(ldcp, tagp); 52651ae08745Sheppo break; 52661ae08745Sheppo 52671ae08745Sheppo case VIO_ATTR_INFO: 52687bd3a2e2SSriharsha Basavapatna rv = vgen_handle_attr_msg(ldcp, tagp); 52691ae08745Sheppo break; 52701ae08745Sheppo 52711ae08745Sheppo case VIO_DRING_REG: 52723af08d82Slm66018 rv = vgen_handle_dring_reg(ldcp, tagp); 52731ae08745Sheppo break; 52741ae08745Sheppo 52751ae08745Sheppo case VIO_RDX: 52763af08d82Slm66018 rv = vgen_handle_rdx_info(ldcp, tagp); 52771ae08745Sheppo break; 52781ae08745Sheppo 52791ae08745Sheppo case VNET_MCAST_INFO: 52803af08d82Slm66018 rv = vgen_handle_mcast_info(ldcp, tagp); 52811ae08745Sheppo break; 52821ae08745Sheppo 5283678453a8Sspeer case VIO_DDS_INFO: 52846d6de4eeSWENTAO YANG /* 52856d6de4eeSWENTAO YANG * If we are in the process of resetting the vswitch channel, 52866d6de4eeSWENTAO YANG * drop the dds message. A new handshake will be initiated 52876d6de4eeSWENTAO YANG * when the channel comes back up after the reset and dds 52886d6de4eeSWENTAO YANG * negotiation can then continue. 52896d6de4eeSWENTAO YANG */ 52907bd3a2e2SSriharsha Basavapatna if (ldcp->reset_in_progress == 1) { 52916d6de4eeSWENTAO YANG break; 52926d6de4eeSWENTAO YANG } 5293678453a8Sspeer rv = vgen_dds_rx(ldcp, tagp); 5294678453a8Sspeer break; 52951107ea93SSriharsha Basavapatna 52961107ea93SSriharsha Basavapatna case VNET_PHYSLINK_INFO: 52971107ea93SSriharsha Basavapatna rv = vgen_handle_physlink_info(ldcp, tagp); 52981107ea93SSriharsha Basavapatna break; 52991ae08745Sheppo } 53003af08d82Slm66018 5301844e62a3Sraghuram DBG1(vgenp, ldcp, "exit rv(%d)\n", rv); 53023af08d82Slm66018 return (rv); 53031ae08745Sheppo } 53041ae08745Sheppo 53057bd3a2e2SSriharsha Basavapatna /* handler for error messages received from the peer ldc end-point */ 53067bd3a2e2SSriharsha Basavapatna static void 53077bd3a2e2SSriharsha Basavapatna vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 53087bd3a2e2SSriharsha Basavapatna { 53097bd3a2e2SSriharsha Basavapatna _NOTE(ARGUNUSED(ldcp, tagp)) 53107bd3a2e2SSriharsha Basavapatna } 53117bd3a2e2SSriharsha Basavapatna 53127bd3a2e2SSriharsha Basavapatna /* 53137bd3a2e2SSriharsha Basavapatna * This function handles raw pkt data messages received over the channel. 53147bd3a2e2SSriharsha Basavapatna * Currently, only priority-eth-type frames are received through this mechanism. 53157bd3a2e2SSriharsha Basavapatna * In this case, the frame(data) is present within the message itself which 53167bd3a2e2SSriharsha Basavapatna * is copied into an mblk before sending it up the stack. 53177bd3a2e2SSriharsha Basavapatna */ 53187bd3a2e2SSriharsha Basavapatna void 53197bd3a2e2SSriharsha Basavapatna vgen_handle_pkt_data(void *arg1, void *arg2, uint32_t msglen) 53207bd3a2e2SSriharsha Basavapatna { 53217bd3a2e2SSriharsha Basavapatna vgen_ldc_t *ldcp = (vgen_ldc_t *)arg1; 53227bd3a2e2SSriharsha Basavapatna vio_raw_data_msg_t *pkt = (vio_raw_data_msg_t *)arg2; 53237bd3a2e2SSriharsha Basavapatna uint32_t size; 53247bd3a2e2SSriharsha Basavapatna mblk_t *mp; 53257bd3a2e2SSriharsha Basavapatna vio_mblk_t *vmp; 53267bd3a2e2SSriharsha Basavapatna vio_net_rx_cb_t vrx_cb = NULL; 53277bd3a2e2SSriharsha Basavapatna vgen_t *vgenp = LDC_TO_VGEN(ldcp); 53287bd3a2e2SSriharsha Basavapatna vgen_stats_t *statsp = &ldcp->stats; 53297bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams; 53307bd3a2e2SSriharsha Basavapatna uint_t dring_mode = lp->dring_mode; 53317bd3a2e2SSriharsha Basavapatna 53327bd3a2e2SSriharsha Basavapatna ASSERT(MUTEX_HELD(&ldcp->cblock)); 53337bd3a2e2SSriharsha Basavapatna 53347bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->cblock); 53357bd3a2e2SSriharsha Basavapatna 53367bd3a2e2SSriharsha Basavapatna size = msglen - VIO_PKT_DATA_HDRSIZE; 53377bd3a2e2SSriharsha Basavapatna if (size < ETHERMIN || size > lp->mtu) { 53387bd3a2e2SSriharsha Basavapatna (void) atomic_inc_32(&statsp->rx_pri_fail); 53397bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->cblock); 53407bd3a2e2SSriharsha Basavapatna return; 53417bd3a2e2SSriharsha Basavapatna } 53427bd3a2e2SSriharsha Basavapatna 53437bd3a2e2SSriharsha Basavapatna vmp = vio_multipool_allocb(&ldcp->vmp, size); 53447bd3a2e2SSriharsha Basavapatna if (vmp == NULL) { 53457bd3a2e2SSriharsha Basavapatna mp = allocb(size, BPRI_MED); 53467bd3a2e2SSriharsha Basavapatna if (mp == NULL) { 53477bd3a2e2SSriharsha Basavapatna (void) atomic_inc_32(&statsp->rx_pri_fail); 53487bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "allocb failure, " 53497bd3a2e2SSriharsha Basavapatna "unable to process priority frame\n"); 53507bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->cblock); 53517bd3a2e2SSriharsha Basavapatna return; 53527bd3a2e2SSriharsha Basavapatna } 53537bd3a2e2SSriharsha Basavapatna } else { 53547bd3a2e2SSriharsha Basavapatna mp = vmp->mp; 53557bd3a2e2SSriharsha Basavapatna } 53567bd3a2e2SSriharsha Basavapatna 53577bd3a2e2SSriharsha Basavapatna /* copy the frame from the payload of raw data msg into the mblk */ 53587bd3a2e2SSriharsha Basavapatna bcopy(pkt->data, mp->b_rptr, size); 53597bd3a2e2SSriharsha Basavapatna mp->b_wptr = mp->b_rptr + size; 53607bd3a2e2SSriharsha Basavapatna 53617bd3a2e2SSriharsha Basavapatna if (vmp != NULL) { 53627bd3a2e2SSriharsha Basavapatna vmp->state = VIO_MBLK_HAS_DATA; 53637bd3a2e2SSriharsha Basavapatna } 53647bd3a2e2SSriharsha Basavapatna 53657bd3a2e2SSriharsha Basavapatna /* update stats */ 53667bd3a2e2SSriharsha Basavapatna (void) atomic_inc_64(&statsp->rx_pri_packets); 53677bd3a2e2SSriharsha Basavapatna (void) atomic_add_64(&statsp->rx_pri_bytes, size); 53687bd3a2e2SSriharsha Basavapatna 53697bd3a2e2SSriharsha Basavapatna /* 53707bd3a2e2SSriharsha Basavapatna * If polling is currently enabled, add the packet to the priority 53717bd3a2e2SSriharsha Basavapatna * packets list and return. It will be picked up by the polling thread. 53727bd3a2e2SSriharsha Basavapatna */ 53737bd3a2e2SSriharsha Basavapatna if (dring_mode == VIO_RX_DRING_DATA) { 53747bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->rxlock); 53757bd3a2e2SSriharsha Basavapatna } else { 53767bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->pollq_lock); 53777bd3a2e2SSriharsha Basavapatna } 53787bd3a2e2SSriharsha Basavapatna 53797bd3a2e2SSriharsha Basavapatna if (ldcp->polling_on == B_TRUE) { 53807bd3a2e2SSriharsha Basavapatna if (ldcp->rx_pri_tail != NULL) { 53817bd3a2e2SSriharsha Basavapatna ldcp->rx_pri_tail->b_next = mp; 53827bd3a2e2SSriharsha Basavapatna } else { 53837bd3a2e2SSriharsha Basavapatna ldcp->rx_pri_head = ldcp->rx_pri_tail = mp; 53847bd3a2e2SSriharsha Basavapatna } 53857bd3a2e2SSriharsha Basavapatna } else { 53867bd3a2e2SSriharsha Basavapatna vrx_cb = ldcp->portp->vcb.vio_net_rx_cb; 53877bd3a2e2SSriharsha Basavapatna } 53887bd3a2e2SSriharsha Basavapatna 53897bd3a2e2SSriharsha Basavapatna if (dring_mode == VIO_RX_DRING_DATA) { 53907bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->rxlock); 53917bd3a2e2SSriharsha Basavapatna } else { 53927bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->pollq_lock); 53937bd3a2e2SSriharsha Basavapatna } 53947bd3a2e2SSriharsha Basavapatna 53957bd3a2e2SSriharsha Basavapatna if (vrx_cb != NULL) { 53967bd3a2e2SSriharsha Basavapatna vrx_cb(ldcp->portp->vhp, mp); 53977bd3a2e2SSriharsha Basavapatna } 53987bd3a2e2SSriharsha Basavapatna 53997bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->cblock); 54007bd3a2e2SSriharsha Basavapatna } 54017bd3a2e2SSriharsha Basavapatna 54027bd3a2e2SSriharsha Basavapatna /* 54037bd3a2e2SSriharsha Basavapatna * dummy pkt data handler function for vnet protocol version 1.0 54047bd3a2e2SSriharsha Basavapatna */ 54057bd3a2e2SSriharsha Basavapatna static void 54067bd3a2e2SSriharsha Basavapatna vgen_handle_pkt_data_nop(void *arg1, void *arg2, uint32_t msglen) 54077bd3a2e2SSriharsha Basavapatna { 54087bd3a2e2SSriharsha Basavapatna _NOTE(ARGUNUSED(arg1, arg2, msglen)) 54097bd3a2e2SSriharsha Basavapatna } 54107bd3a2e2SSriharsha Basavapatna 54111ae08745Sheppo /* handler for data messages received from the peer ldc end-point */ 54123af08d82Slm66018 static int 5413f0ca1d9aSsb155480 vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, uint32_t msglen) 54141ae08745Sheppo { 54153af08d82Slm66018 int rv = 0; 5416844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 54177bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams; 54181ae08745Sheppo 5419844e62a3Sraghuram DBG1(vgenp, ldcp, "enter\n"); 54201ae08745Sheppo 54217bd3a2e2SSriharsha Basavapatna if (ldcp->hphase != VH_DONE) { 54227bd3a2e2SSriharsha Basavapatna return (0); 54237bd3a2e2SSriharsha Basavapatna } 5424f0ca1d9aSsb155480 54257bd3a2e2SSriharsha Basavapatna /* 54267bd3a2e2SSriharsha Basavapatna * We check the data msg seqnum. This is needed only in TxDring mode. 54277bd3a2e2SSriharsha Basavapatna */ 54287bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_TX_DRING && 54297bd3a2e2SSriharsha Basavapatna tagp->vio_subtype == VIO_SUBTYPE_INFO) { 5430f0ca1d9aSsb155480 rv = vgen_check_datamsg_seq(ldcp, tagp); 5431f0ca1d9aSsb155480 if (rv != 0) { 5432f0ca1d9aSsb155480 return (rv); 5433f0ca1d9aSsb155480 } 5434f0ca1d9aSsb155480 } 5435f0ca1d9aSsb155480 54361ae08745Sheppo switch (tagp->vio_subtype_env) { 54371ae08745Sheppo case VIO_DRING_DATA: 54387bd3a2e2SSriharsha Basavapatna rv = ldcp->rx_dringdata((void *)ldcp, (void *)tagp); 54391ae08745Sheppo break; 5440f0ca1d9aSsb155480 5441f0ca1d9aSsb155480 case VIO_PKT_DATA: 5442f0ca1d9aSsb155480 ldcp->rx_pktdata((void *)ldcp, (void *)tagp, msglen); 5443f0ca1d9aSsb155480 break; 54441ae08745Sheppo default: 54451ae08745Sheppo break; 54461ae08745Sheppo } 54471ae08745Sheppo 5448844e62a3Sraghuram DBG1(vgenp, ldcp, "exit rv(%d)\n", rv); 54493af08d82Slm66018 return (rv); 54501ae08745Sheppo } 54511ae08745Sheppo 54527bd3a2e2SSriharsha Basavapatna 54537bd3a2e2SSriharsha Basavapatna static int 54547bd3a2e2SSriharsha Basavapatna vgen_ldc_reset(vgen_ldc_t *ldcp, vgen_caller_t caller) 5455f0ca1d9aSsb155480 { 54567bd3a2e2SSriharsha Basavapatna int rv; 54577bd3a2e2SSriharsha Basavapatna 54587bd3a2e2SSriharsha Basavapatna if (caller == VGEN_LDC_CB || caller == VGEN_MSG_THR) { 54597bd3a2e2SSriharsha Basavapatna ASSERT(MUTEX_HELD(&ldcp->cblock)); 5460f0ca1d9aSsb155480 } 5461f0ca1d9aSsb155480 54627bd3a2e2SSriharsha Basavapatna /* Set the flag to indicate reset is in progress */ 54637bd3a2e2SSriharsha Basavapatna if (atomic_cas_uint(&ldcp->reset_in_progress, 0, 1) != 0) { 54647bd3a2e2SSriharsha Basavapatna /* another thread is already in the process of resetting */ 54657bd3a2e2SSriharsha Basavapatna return (EBUSY); 54667bd3a2e2SSriharsha Basavapatna } 54677bd3a2e2SSriharsha Basavapatna 54687bd3a2e2SSriharsha Basavapatna if (caller == VGEN_LDC_CB || caller == VGEN_MSG_THR) { 54697bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->cblock); 54707bd3a2e2SSriharsha Basavapatna } 54717bd3a2e2SSriharsha Basavapatna 54727bd3a2e2SSriharsha Basavapatna rv = vgen_process_reset(ldcp, VGEN_FLAG_NEED_LDCRESET); 54737bd3a2e2SSriharsha Basavapatna 54747bd3a2e2SSriharsha Basavapatna if (caller == VGEN_LDC_CB || caller == VGEN_MSG_THR) { 54757bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->cblock); 54767bd3a2e2SSriharsha Basavapatna } 54777bd3a2e2SSriharsha Basavapatna 54787bd3a2e2SSriharsha Basavapatna return (rv); 54797bd3a2e2SSriharsha Basavapatna } 54807bd3a2e2SSriharsha Basavapatna 5481f0ca1d9aSsb155480 static void 54827bd3a2e2SSriharsha Basavapatna vgen_ldc_up(vgen_ldc_t *ldcp) 5483f0ca1d9aSsb155480 { 54847bd3a2e2SSriharsha Basavapatna int rv; 54857bd3a2e2SSriharsha Basavapatna uint32_t retries = 0; 5486f0ca1d9aSsb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 5487f0ca1d9aSsb155480 5488f0ca1d9aSsb155480 ASSERT(MUTEX_HELD(&ldcp->cblock)); 5489f0ca1d9aSsb155480 54901ae08745Sheppo /* 54917bd3a2e2SSriharsha Basavapatna * If the channel has been reset max # of times, without successfully 54927bd3a2e2SSriharsha Basavapatna * completing handshake, stop and do not bring the channel up. 5493844e62a3Sraghuram */ 54947bd3a2e2SSriharsha Basavapatna if (ldcp->ldc_reset_count == vgen_ldc_max_resets) { 54957bd3a2e2SSriharsha Basavapatna cmn_err(CE_WARN, "!vnet%d: exceeded number of permitted" 54967bd3a2e2SSriharsha Basavapatna " handshake attempts (%d) on channel %ld", 54977bd3a2e2SSriharsha Basavapatna vgenp->instance, vgen_ldc_max_resets, ldcp->ldc_id); 54987bd3a2e2SSriharsha Basavapatna return; 5499844e62a3Sraghuram } 55007bd3a2e2SSriharsha Basavapatna ldcp->ldc_reset_count++; 55017bd3a2e2SSriharsha Basavapatna 55027bd3a2e2SSriharsha Basavapatna do { 55037bd3a2e2SSriharsha Basavapatna rv = ldc_up(ldcp->ldc_handle); 55047bd3a2e2SSriharsha Basavapatna if ((rv != 0) && (rv == EWOULDBLOCK)) { 55057bd3a2e2SSriharsha Basavapatna drv_usecwait(VGEN_LDC_UP_DELAY); 55067bd3a2e2SSriharsha Basavapatna } 55077bd3a2e2SSriharsha Basavapatna if (retries++ >= vgen_ldcup_retries) 55087bd3a2e2SSriharsha Basavapatna break; 55097bd3a2e2SSriharsha Basavapatna } while (rv == EWOULDBLOCK); 55107bd3a2e2SSriharsha Basavapatna 55117bd3a2e2SSriharsha Basavapatna if (rv != 0) { 55127bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "ldc_up err rv(%d)\n", rv); 55137bd3a2e2SSriharsha Basavapatna } 5514844e62a3Sraghuram } 5515844e62a3Sraghuram 55167bd3a2e2SSriharsha Basavapatna int 55177bd3a2e2SSriharsha Basavapatna vgen_enable_intr(void *arg) 5518844e62a3Sraghuram { 55197bd3a2e2SSriharsha Basavapatna uint32_t end_ix; 55207bd3a2e2SSriharsha Basavapatna vio_dring_msg_t msg; 55217bd3a2e2SSriharsha Basavapatna vgen_port_t *portp = (vgen_port_t *)arg; 55227bd3a2e2SSriharsha Basavapatna vgen_ldc_t *ldcp = portp->ldcp; 55237b1f684aSSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams; 5524844e62a3Sraghuram 55257bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_RX_DRING_DATA) { 55267bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->rxlock); 5527844e62a3Sraghuram 55287bd3a2e2SSriharsha Basavapatna ldcp->polling_on = B_FALSE; 55291ae08745Sheppo /* 55307bd3a2e2SSriharsha Basavapatna * We send a stopped message to peer (sender) as we are turning 55317bd3a2e2SSriharsha Basavapatna * off polled mode. This effectively restarts data interrupts 55327bd3a2e2SSriharsha Basavapatna * by allowing the peer to send further dring data msgs to us. 55331ae08745Sheppo */ 55347bd3a2e2SSriharsha Basavapatna end_ix = ldcp->next_rxi; 55357bd3a2e2SSriharsha Basavapatna DECR_RXI(end_ix, ldcp); 55367bd3a2e2SSriharsha Basavapatna msg.dring_ident = ldcp->peer_hparams.dring_ident; 55377bd3a2e2SSriharsha Basavapatna (void) vgen_send_dringack_shm(ldcp, (vio_msg_tag_t *)&msg, 55387bd3a2e2SSriharsha Basavapatna VNET_START_IDX_UNSPEC, end_ix, VIO_DP_STOPPED); 5539d10e4ef2Snarayan 55407bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->rxlock); 55411ae08745Sheppo } else { 55427bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->pollq_lock); 55437bd3a2e2SSriharsha Basavapatna ldcp->polling_on = B_FALSE; 55447bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->pollq_lock); 55451ae08745Sheppo } 55461ae08745Sheppo 55477bd3a2e2SSriharsha Basavapatna return (0); 55483af08d82Slm66018 } 5549d10e4ef2Snarayan 55507bd3a2e2SSriharsha Basavapatna int 55517bd3a2e2SSriharsha Basavapatna vgen_disable_intr(void *arg) 5552844e62a3Sraghuram { 55537bd3a2e2SSriharsha Basavapatna vgen_port_t *portp = (vgen_port_t *)arg; 55547bd3a2e2SSriharsha Basavapatna vgen_ldc_t *ldcp = portp->ldcp; 55557bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams; 5556844e62a3Sraghuram 55577bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_RX_DRING_DATA) { 55587bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->rxlock); 55597bd3a2e2SSriharsha Basavapatna ldcp->polling_on = B_TRUE; 55607bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->rxlock); 5561d10e4ef2Snarayan } else { 55627bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->pollq_lock); 55637bd3a2e2SSriharsha Basavapatna ldcp->polling_on = B_TRUE; 55647bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->pollq_lock); 5565d10e4ef2Snarayan } 5566d10e4ef2Snarayan 55677bd3a2e2SSriharsha Basavapatna return (0); 5568844e62a3Sraghuram } 5569844e62a3Sraghuram 55707bd3a2e2SSriharsha Basavapatna mblk_t * 55717bd3a2e2SSriharsha Basavapatna vgen_rx_poll(void *arg, int bytes_to_pickup) 55727bd3a2e2SSriharsha Basavapatna { 55737bd3a2e2SSriharsha Basavapatna vgen_port_t *portp = (vgen_port_t *)arg; 55747bd3a2e2SSriharsha Basavapatna vgen_ldc_t *ldcp = portp->ldcp; 55757bd3a2e2SSriharsha Basavapatna vgen_hparams_t *lp = &ldcp->local_hparams; 55767bd3a2e2SSriharsha Basavapatna mblk_t *mp = NULL; 55777bd3a2e2SSriharsha Basavapatna 55787bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_RX_DRING_DATA) { 55797bd3a2e2SSriharsha Basavapatna mp = vgen_poll_rcv_shm(ldcp, bytes_to_pickup); 5580d10e4ef2Snarayan } else { 55817bd3a2e2SSriharsha Basavapatna mp = vgen_poll_rcv(ldcp, bytes_to_pickup); 5582d10e4ef2Snarayan } 5583d10e4ef2Snarayan 55847bd3a2e2SSriharsha Basavapatna return (mp); 55851ae08745Sheppo } 55861ae08745Sheppo 55871ae08745Sheppo /* transmit watchdog timeout handler */ 55881ae08745Sheppo static void 55897bd3a2e2SSriharsha Basavapatna vgen_tx_watchdog(void *arg) 55901ae08745Sheppo { 55911ae08745Sheppo vgen_ldc_t *ldcp; 5592d10e4ef2Snarayan vgen_t *vgenp; 55931ae08745Sheppo int rv; 55947bd3a2e2SSriharsha Basavapatna boolean_t tx_blocked; 55957bd3a2e2SSriharsha Basavapatna clock_t tx_blocked_lbolt; 55961ae08745Sheppo 55971ae08745Sheppo ldcp = (vgen_ldc_t *)arg; 5598d10e4ef2Snarayan vgenp = LDC_TO_VGEN(ldcp); 55991ae08745Sheppo 56007bd3a2e2SSriharsha Basavapatna tx_blocked = ldcp->tx_blocked; 56017bd3a2e2SSriharsha Basavapatna tx_blocked_lbolt = ldcp->tx_blocked_lbolt; 56027bd3a2e2SSriharsha Basavapatna 56037bd3a2e2SSriharsha Basavapatna if (vgen_txwd_timeout && 56047bd3a2e2SSriharsha Basavapatna (tx_blocked == B_TRUE) && 56057bd3a2e2SSriharsha Basavapatna ((ddi_get_lbolt() - tx_blocked_lbolt) > 56067bd3a2e2SSriharsha Basavapatna drv_usectohz(vgen_txwd_timeout * 1000))) { 56077bd3a2e2SSriharsha Basavapatna /* 56087bd3a2e2SSriharsha Basavapatna * Something is wrong; the peer is not picking up the packets 56097bd3a2e2SSriharsha Basavapatna * in the transmit dring. We now go ahead and reset the channel 56107bd3a2e2SSriharsha Basavapatna * to break out of this condition. 56117bd3a2e2SSriharsha Basavapatna */ 56127bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "transmit timeout lbolt(%lx), " 56137bd3a2e2SSriharsha Basavapatna "tx_blocked_lbolt(%lx)\n", 56147bd3a2e2SSriharsha Basavapatna ddi_get_lbolt(), tx_blocked_lbolt); 56157bd3a2e2SSriharsha Basavapatna 56161ae08745Sheppo #ifdef DEBUG 56177bd3a2e2SSriharsha Basavapatna if (vgen_inject_error(ldcp, VGEN_ERR_TXTIMEOUT)) { 56181ae08745Sheppo /* tx timeout triggered for debugging */ 56197bd3a2e2SSriharsha Basavapatna vgen_inject_err_flag &= ~(VGEN_ERR_TXTIMEOUT); 56201ae08745Sheppo } 56211ae08745Sheppo #endif 56227bd3a2e2SSriharsha Basavapatna 56237bd3a2e2SSriharsha Basavapatna /* 56247bd3a2e2SSriharsha Basavapatna * Clear tid before invoking vgen_ldc_reset(). Otherwise, 56257bd3a2e2SSriharsha Basavapatna * it will result in a deadlock when vgen_process_reset() tries 56267bd3a2e2SSriharsha Basavapatna * to untimeout() on seeing a non-zero tid, but it is being 56277bd3a2e2SSriharsha Basavapatna * invoked by the timer itself in this case. 56287bd3a2e2SSriharsha Basavapatna */ 56291ae08745Sheppo mutex_enter(&ldcp->cblock); 56307bd3a2e2SSriharsha Basavapatna if (ldcp->wd_tid == 0) { 56317bd3a2e2SSriharsha Basavapatna /* Cancelled by vgen_process_reset() */ 56321ae08745Sheppo mutex_exit(&ldcp->cblock); 56337bd3a2e2SSriharsha Basavapatna return; 56347bd3a2e2SSriharsha Basavapatna } 56357bd3a2e2SSriharsha Basavapatna ldcp->wd_tid = 0; 56367bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->cblock); 56377bd3a2e2SSriharsha Basavapatna 56387bd3a2e2SSriharsha Basavapatna /* 56397bd3a2e2SSriharsha Basavapatna * Now reset the channel. 56407bd3a2e2SSriharsha Basavapatna */ 56417bd3a2e2SSriharsha Basavapatna rv = vgen_ldc_reset(ldcp, VGEN_OTHER); 56427bd3a2e2SSriharsha Basavapatna if (rv == 0) { 56437bd3a2e2SSriharsha Basavapatna /* 56447bd3a2e2SSriharsha Basavapatna * We have successfully reset the channel. If we are 56457bd3a2e2SSriharsha Basavapatna * in tx flow controlled state, clear it now and enable 56467bd3a2e2SSriharsha Basavapatna * transmit in the upper layer. 56477bd3a2e2SSriharsha Basavapatna */ 56487bd3a2e2SSriharsha Basavapatna if (ldcp->tx_blocked) { 5649678453a8Sspeer vio_net_tx_update_t vtx_update = 5650678453a8Sspeer ldcp->portp->vcb.vio_net_tx_update; 5651678453a8Sspeer 56527bd3a2e2SSriharsha Basavapatna ldcp->tx_blocked = B_FALSE; 5653678453a8Sspeer vtx_update(ldcp->portp->vhp); 56541ae08745Sheppo } 56551ae08745Sheppo } 56561ae08745Sheppo 56577bd3a2e2SSriharsha Basavapatna /* 56587bd3a2e2SSriharsha Basavapatna * Channel has been reset by us or some other thread is already 56597bd3a2e2SSriharsha Basavapatna * in the process of resetting. In either case, we return 56607bd3a2e2SSriharsha Basavapatna * without restarting the timer. When handshake completes and 56617bd3a2e2SSriharsha Basavapatna * the channel is ready for data transmit/receive we start a 56627bd3a2e2SSriharsha Basavapatna * new watchdog timer. 56637bd3a2e2SSriharsha Basavapatna */ 56647bd3a2e2SSriharsha Basavapatna return; 56651ae08745Sheppo } 56661ae08745Sheppo 56677bd3a2e2SSriharsha Basavapatna restart_timer: 56687bd3a2e2SSriharsha Basavapatna /* Restart the timer */ 56697bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->cblock); 56707bd3a2e2SSriharsha Basavapatna if (ldcp->wd_tid == 0) { 56717bd3a2e2SSriharsha Basavapatna /* Cancelled by vgen_process_reset() */ 56727bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->cblock); 56737bd3a2e2SSriharsha Basavapatna return; 56747bd3a2e2SSriharsha Basavapatna } 56757bd3a2e2SSriharsha Basavapatna ldcp->wd_tid = timeout(vgen_tx_watchdog, (caddr_t)ldcp, 56767bd3a2e2SSriharsha Basavapatna drv_usectohz(vgen_txwd_interval * 1000)); 56777bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->cblock); 56787bd3a2e2SSriharsha Basavapatna } 56797bd3a2e2SSriharsha Basavapatna 56807bd3a2e2SSriharsha Basavapatna /* Handshake watchdog timeout handler */ 56811ae08745Sheppo static void 56827bd3a2e2SSriharsha Basavapatna vgen_hwatchdog(void *arg) 56831ae08745Sheppo { 56847bd3a2e2SSriharsha Basavapatna vgen_ldc_t *ldcp = (vgen_ldc_t *)arg; 5685f0ca1d9aSsb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 5686f0ca1d9aSsb155480 56877bd3a2e2SSriharsha Basavapatna DWARN(vgenp, ldcp, "handshake timeout phase(%x) state(%x)\n", 56887bd3a2e2SSriharsha Basavapatna ldcp->hphase, ldcp->hstate); 56897bd3a2e2SSriharsha Basavapatna 56907bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->cblock); 56917bd3a2e2SSriharsha Basavapatna if (ldcp->htid == 0) { 56927bd3a2e2SSriharsha Basavapatna /* Cancelled by vgen_process_reset() */ 56937bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->cblock); 56947bd3a2e2SSriharsha Basavapatna return; 5695f0ca1d9aSsb155480 } 56967bd3a2e2SSriharsha Basavapatna ldcp->htid = 0; 56977bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->cblock); 5698f0ca1d9aSsb155480 56997bd3a2e2SSriharsha Basavapatna /* 57007bd3a2e2SSriharsha Basavapatna * Something is wrong; handshake with the peer seems to be hung. We now 57017bd3a2e2SSriharsha Basavapatna * go ahead and reset the channel to break out of this condition. 57027bd3a2e2SSriharsha Basavapatna */ 57037bd3a2e2SSriharsha Basavapatna (void) vgen_ldc_reset(ldcp, VGEN_OTHER); 5704f0ca1d9aSsb155480 } 5705f0ca1d9aSsb155480 57061ae08745Sheppo /* Check if the session id in the received message is valid */ 57071ae08745Sheppo static int 57081ae08745Sheppo vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 57091ae08745Sheppo { 5710844e62a3Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 5711844e62a3Sraghuram 57121ae08745Sheppo if (tagp->vio_sid != ldcp->peer_sid) { 5713844e62a3Sraghuram DWARN(vgenp, ldcp, "sid mismatch: expected(%x), rcvd(%x)\n", 5714844e62a3Sraghuram ldcp->peer_sid, tagp->vio_sid); 57151ae08745Sheppo return (VGEN_FAILURE); 57161ae08745Sheppo } 57171ae08745Sheppo else 57181ae08745Sheppo return (VGEN_SUCCESS); 57191ae08745Sheppo } 57201ae08745Sheppo 5721844e62a3Sraghuram /* 57227bd3a2e2SSriharsha Basavapatna * Initialize the common part of dring registration 57237bd3a2e2SSriharsha Basavapatna * message; used in both TxDring and RxDringData modes. 5724844e62a3Sraghuram */ 5725844e62a3Sraghuram static void 57267bd3a2e2SSriharsha Basavapatna vgen_init_dring_reg_msg(vgen_ldc_t *ldcp, vio_dring_reg_msg_t *msg, 57277bd3a2e2SSriharsha Basavapatna uint8_t option) 5728844e62a3Sraghuram { 57297bd3a2e2SSriharsha Basavapatna vio_msg_tag_t *tagp; 5730844e62a3Sraghuram 57317bd3a2e2SSriharsha Basavapatna tagp = &msg->tag; 57327bd3a2e2SSriharsha Basavapatna tagp->vio_msgtype = VIO_TYPE_CTRL; 57337bd3a2e2SSriharsha Basavapatna tagp->vio_subtype = VIO_SUBTYPE_INFO; 57347bd3a2e2SSriharsha Basavapatna tagp->vio_subtype_env = VIO_DRING_REG; 57357bd3a2e2SSriharsha Basavapatna tagp->vio_sid = ldcp->local_sid; 573663f531d1SSriharsha Basavapatna 57377bd3a2e2SSriharsha Basavapatna /* get dring info msg payload from ldcp->local */ 57387bd3a2e2SSriharsha Basavapatna bcopy(&(ldcp->local_hparams.dring_cookie), &(msg->cookie[0]), 57397bd3a2e2SSriharsha Basavapatna sizeof (ldc_mem_cookie_t)); 57407bd3a2e2SSriharsha Basavapatna msg->ncookies = ldcp->local_hparams.dring_ncookies; 57417bd3a2e2SSriharsha Basavapatna msg->num_descriptors = ldcp->local_hparams.num_desc; 57427bd3a2e2SSriharsha Basavapatna msg->descriptor_size = ldcp->local_hparams.desc_size; 574363f531d1SSriharsha Basavapatna 57447bd3a2e2SSriharsha Basavapatna msg->options = option; 574563f531d1SSriharsha Basavapatna 574663f531d1SSriharsha Basavapatna /* 57477bd3a2e2SSriharsha Basavapatna * dring_ident is set to 0. After mapping the dring, peer sets this 57487bd3a2e2SSriharsha Basavapatna * value and sends it in the ack, which is saved in 57497bd3a2e2SSriharsha Basavapatna * vgen_handle_dring_reg(). 575063f531d1SSriharsha Basavapatna */ 57517bd3a2e2SSriharsha Basavapatna msg->dring_ident = 0; 575263f531d1SSriharsha Basavapatna } 575363f531d1SSriharsha Basavapatna 5754*34f94fbcSWENTAO YANG static int 5755*34f94fbcSWENTAO YANG vgen_mapin_avail(vgen_ldc_t *ldcp) 5756*34f94fbcSWENTAO YANG { 5757*34f94fbcSWENTAO YANG int rv; 5758*34f94fbcSWENTAO YANG ldc_info_t info; 5759*34f94fbcSWENTAO YANG uint64_t mapin_sz_req; 5760*34f94fbcSWENTAO YANG uint64_t dblk_sz; 5761*34f94fbcSWENTAO YANG vgen_t *vgenp = LDC_TO_VGEN(ldcp); 5762*34f94fbcSWENTAO YANG 5763*34f94fbcSWENTAO YANG rv = ldc_info(ldcp->ldc_handle, &info); 5764*34f94fbcSWENTAO YANG if (rv != 0) { 5765*34f94fbcSWENTAO YANG return (B_FALSE); 5766*34f94fbcSWENTAO YANG } 5767*34f94fbcSWENTAO YANG 5768*34f94fbcSWENTAO YANG dblk_sz = RXDRING_DBLK_SZ(vgenp->max_frame_size); 5769*34f94fbcSWENTAO YANG mapin_sz_req = (VGEN_RXDRING_NRBUFS * dblk_sz); 5770*34f94fbcSWENTAO YANG 5771*34f94fbcSWENTAO YANG if (info.direct_map_size_max >= mapin_sz_req) { 5772*34f94fbcSWENTAO YANG return (B_TRUE); 5773*34f94fbcSWENTAO YANG } 5774*34f94fbcSWENTAO YANG 5775*34f94fbcSWENTAO YANG return (B_FALSE); 5776*34f94fbcSWENTAO YANG } 5777*34f94fbcSWENTAO YANG 5778844e62a3Sraghuram #if DEBUG 5779844e62a3Sraghuram 5780844e62a3Sraghuram /* 5781844e62a3Sraghuram * Print debug messages - set to 0xf to enable all msgs 5782844e62a3Sraghuram */ 57837bd3a2e2SSriharsha Basavapatna void 57847bd3a2e2SSriharsha Basavapatna vgen_debug_printf(const char *fname, vgen_t *vgenp, 5785844e62a3Sraghuram vgen_ldc_t *ldcp, const char *fmt, ...) 5786844e62a3Sraghuram { 5787844e62a3Sraghuram char buf[256]; 5788844e62a3Sraghuram char *bufp = buf; 5789844e62a3Sraghuram va_list ap; 5790844e62a3Sraghuram 5791844e62a3Sraghuram if ((vgenp != NULL) && (vgenp->vnetp != NULL)) { 5792844e62a3Sraghuram (void) sprintf(bufp, "vnet%d:", 5793844e62a3Sraghuram ((vnet_t *)(vgenp->vnetp))->instance); 5794844e62a3Sraghuram bufp += strlen(bufp); 5795844e62a3Sraghuram } 5796844e62a3Sraghuram if (ldcp != NULL) { 5797844e62a3Sraghuram (void) sprintf(bufp, "ldc(%ld):", ldcp->ldc_id); 5798844e62a3Sraghuram bufp += strlen(bufp); 5799844e62a3Sraghuram } 5800844e62a3Sraghuram (void) sprintf(bufp, "%s: ", fname); 5801844e62a3Sraghuram bufp += strlen(bufp); 5802844e62a3Sraghuram 5803844e62a3Sraghuram va_start(ap, fmt); 5804844e62a3Sraghuram (void) vsprintf(bufp, fmt, ap); 5805844e62a3Sraghuram va_end(ap); 5806844e62a3Sraghuram 5807844e62a3Sraghuram if ((ldcp == NULL) ||(vgendbg_ldcid == -1) || 5808844e62a3Sraghuram (vgendbg_ldcid == ldcp->ldc_id)) { 5809844e62a3Sraghuram cmn_err(CE_CONT, "%s\n", buf); 5810844e62a3Sraghuram } 5811844e62a3Sraghuram } 5812844e62a3Sraghuram #endif 58131107ea93SSriharsha Basavapatna 58141107ea93SSriharsha Basavapatna #ifdef VNET_IOC_DEBUG 58151107ea93SSriharsha Basavapatna 58161107ea93SSriharsha Basavapatna static void 58171107ea93SSriharsha Basavapatna vgen_ioctl(void *arg, queue_t *q, mblk_t *mp) 58181107ea93SSriharsha Basavapatna { 58191107ea93SSriharsha Basavapatna struct iocblk *iocp; 58201107ea93SSriharsha Basavapatna vgen_port_t *portp; 58211107ea93SSriharsha Basavapatna enum ioc_reply { 58221107ea93SSriharsha Basavapatna IOC_INVAL = -1, /* bad, NAK with EINVAL */ 58231107ea93SSriharsha Basavapatna IOC_ACK /* OK, just send ACK */ 58241107ea93SSriharsha Basavapatna } status; 58251107ea93SSriharsha Basavapatna int rv; 58261107ea93SSriharsha Basavapatna 58271107ea93SSriharsha Basavapatna iocp = (struct iocblk *)(uintptr_t)mp->b_rptr; 58281107ea93SSriharsha Basavapatna iocp->ioc_error = 0; 58291107ea93SSriharsha Basavapatna portp = (vgen_port_t *)arg; 58301107ea93SSriharsha Basavapatna 58311107ea93SSriharsha Basavapatna if (portp == NULL) { 58321107ea93SSriharsha Basavapatna status = IOC_INVAL; 58331107ea93SSriharsha Basavapatna goto vgen_ioc_exit; 58341107ea93SSriharsha Basavapatna } 58351107ea93SSriharsha Basavapatna 58361107ea93SSriharsha Basavapatna mutex_enter(&portp->lock); 58371107ea93SSriharsha Basavapatna 58381107ea93SSriharsha Basavapatna switch (iocp->ioc_cmd) { 58391107ea93SSriharsha Basavapatna 58401107ea93SSriharsha Basavapatna case VNET_FORCE_LINK_DOWN: 58411107ea93SSriharsha Basavapatna case VNET_FORCE_LINK_UP: 58421107ea93SSriharsha Basavapatna rv = vgen_force_link_state(portp, iocp->ioc_cmd); 58431107ea93SSriharsha Basavapatna (rv == 0) ? (status = IOC_ACK) : (status = IOC_INVAL); 58441107ea93SSriharsha Basavapatna break; 58451107ea93SSriharsha Basavapatna 58461107ea93SSriharsha Basavapatna default: 58471107ea93SSriharsha Basavapatna status = IOC_INVAL; 58481107ea93SSriharsha Basavapatna break; 58491107ea93SSriharsha Basavapatna 58501107ea93SSriharsha Basavapatna } 58511107ea93SSriharsha Basavapatna 58521107ea93SSriharsha Basavapatna mutex_exit(&portp->lock); 58531107ea93SSriharsha Basavapatna 58541107ea93SSriharsha Basavapatna vgen_ioc_exit: 58551107ea93SSriharsha Basavapatna 58561107ea93SSriharsha Basavapatna switch (status) { 58571107ea93SSriharsha Basavapatna default: 58581107ea93SSriharsha Basavapatna case IOC_INVAL: 58591107ea93SSriharsha Basavapatna /* Error, reply with a NAK and EINVAL error */ 58601107ea93SSriharsha Basavapatna miocnak(q, mp, 0, EINVAL); 58611107ea93SSriharsha Basavapatna break; 58621107ea93SSriharsha Basavapatna case IOC_ACK: 58631107ea93SSriharsha Basavapatna /* OK, reply with an ACK */ 58641107ea93SSriharsha Basavapatna miocack(q, mp, 0, 0); 58651107ea93SSriharsha Basavapatna break; 58661107ea93SSriharsha Basavapatna } 58671107ea93SSriharsha Basavapatna } 58681107ea93SSriharsha Basavapatna 58691107ea93SSriharsha Basavapatna static int 58701107ea93SSriharsha Basavapatna vgen_force_link_state(vgen_port_t *portp, int cmd) 58711107ea93SSriharsha Basavapatna { 58721107ea93SSriharsha Basavapatna ldc_status_t istatus; 58731107ea93SSriharsha Basavapatna int rv; 58747bd3a2e2SSriharsha Basavapatna vgen_ldc_t *ldcp = portp->ldcp; 58757bd3a2e2SSriharsha Basavapatna vgen_t *vgenp = portp->vgenp; 58761107ea93SSriharsha Basavapatna 58771107ea93SSriharsha Basavapatna mutex_enter(&ldcp->cblock); 58781107ea93SSriharsha Basavapatna 58791107ea93SSriharsha Basavapatna switch (cmd) { 58801107ea93SSriharsha Basavapatna 58811107ea93SSriharsha Basavapatna case VNET_FORCE_LINK_DOWN: 58821107ea93SSriharsha Basavapatna (void) ldc_down(ldcp->ldc_handle); 58831107ea93SSriharsha Basavapatna ldcp->link_down_forced = B_TRUE; 58841107ea93SSriharsha Basavapatna break; 58851107ea93SSriharsha Basavapatna 58861107ea93SSriharsha Basavapatna case VNET_FORCE_LINK_UP: 58877bd3a2e2SSriharsha Basavapatna vgen_ldc_up(ldcp); 58881107ea93SSriharsha Basavapatna ldcp->link_down_forced = B_FALSE; 58891107ea93SSriharsha Basavapatna 58901107ea93SSriharsha Basavapatna if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 58911107ea93SSriharsha Basavapatna DWARN(vgenp, ldcp, "ldc_status err\n"); 58921107ea93SSriharsha Basavapatna } else { 58931107ea93SSriharsha Basavapatna ldcp->ldc_status = istatus; 58941107ea93SSriharsha Basavapatna } 58951107ea93SSriharsha Basavapatna 58961107ea93SSriharsha Basavapatna /* if channel is already UP - restart handshake */ 58971107ea93SSriharsha Basavapatna if (ldcp->ldc_status == LDC_UP) { 58981107ea93SSriharsha Basavapatna vgen_handle_evt_up(ldcp); 58991107ea93SSriharsha Basavapatna } 59001107ea93SSriharsha Basavapatna break; 59011107ea93SSriharsha Basavapatna 59021107ea93SSriharsha Basavapatna } 59031107ea93SSriharsha Basavapatna 59041107ea93SSriharsha Basavapatna mutex_exit(&ldcp->cblock); 59051107ea93SSriharsha Basavapatna 59061107ea93SSriharsha Basavapatna return (0); 59071107ea93SSriharsha Basavapatna } 59081107ea93SSriharsha Basavapatna 59091107ea93SSriharsha Basavapatna #else 59101107ea93SSriharsha Basavapatna 59111107ea93SSriharsha Basavapatna static void 59121107ea93SSriharsha Basavapatna vgen_ioctl(void *arg, queue_t *q, mblk_t *mp) 59131107ea93SSriharsha Basavapatna { 59141107ea93SSriharsha Basavapatna vgen_port_t *portp; 59151107ea93SSriharsha Basavapatna 59161107ea93SSriharsha Basavapatna portp = (vgen_port_t *)arg; 59171107ea93SSriharsha Basavapatna 59181107ea93SSriharsha Basavapatna if (portp == NULL) { 59191107ea93SSriharsha Basavapatna miocnak(q, mp, 0, EINVAL); 59201107ea93SSriharsha Basavapatna return; 59211107ea93SSriharsha Basavapatna } 59221107ea93SSriharsha Basavapatna 59231107ea93SSriharsha Basavapatna miocnak(q, mp, 0, ENOTSUP); 59241107ea93SSriharsha Basavapatna } 59251107ea93SSriharsha Basavapatna 59261107ea93SSriharsha Basavapatna #endif 5927