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 /* 23f0ca1d9aSsb155480 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 241ae08745Sheppo * Use is subject to license terms. 251ae08745Sheppo */ 261ae08745Sheppo 271ae08745Sheppo #include <sys/types.h> 281ae08745Sheppo #include <sys/errno.h> 291ae08745Sheppo #include <sys/debug.h> 301ae08745Sheppo #include <sys/time.h> 311ae08745Sheppo #include <sys/sysmacros.h> 321ae08745Sheppo #include <sys/systm.h> 331ae08745Sheppo #include <sys/user.h> 341ae08745Sheppo #include <sys/stropts.h> 351ae08745Sheppo #include <sys/stream.h> 361ae08745Sheppo #include <sys/strlog.h> 371ae08745Sheppo #include <sys/strsubr.h> 381ae08745Sheppo #include <sys/cmn_err.h> 391ae08745Sheppo #include <sys/cpu.h> 401ae08745Sheppo #include <sys/kmem.h> 411ae08745Sheppo #include <sys/conf.h> 421ae08745Sheppo #include <sys/ddi.h> 431ae08745Sheppo #include <sys/sunddi.h> 441ae08745Sheppo #include <sys/ksynch.h> 451ae08745Sheppo #include <sys/stat.h> 461ae08745Sheppo #include <sys/kstat.h> 471ae08745Sheppo #include <sys/vtrace.h> 481ae08745Sheppo #include <sys/strsun.h> 491ae08745Sheppo #include <sys/dlpi.h> 501ae08745Sheppo #include <sys/ethernet.h> 511ae08745Sheppo #include <net/if.h> 521ae08745Sheppo #include <sys/varargs.h> 531ae08745Sheppo #include <sys/machsystm.h> 541ae08745Sheppo #include <sys/modctl.h> 551ae08745Sheppo #include <sys/modhash.h> 561ae08745Sheppo #include <sys/mac.h> 57ba2e4443Sseb #include <sys/mac_ether.h> 581ae08745Sheppo #include <sys/taskq.h> 591ae08745Sheppo #include <sys/note.h> 601ae08745Sheppo #include <sys/mach_descrip.h> 611ae08745Sheppo #include <sys/mac.h> 621ae08745Sheppo #include <sys/mdeg.h> 631ae08745Sheppo #include <sys/ldc.h> 641ae08745Sheppo #include <sys/vsw_fdb.h> 651ae08745Sheppo #include <sys/vsw.h> 661ae08745Sheppo #include <sys/vio_mailbox.h> 671ae08745Sheppo #include <sys/vnet_mailbox.h> 681ae08745Sheppo #include <sys/vnet_common.h> 69d10e4ef2Snarayan #include <sys/vio_util.h> 70d10e4ef2Snarayan #include <sys/sdt.h> 7119b65a69Ssb155480 #include <sys/atomic.h> 7206db247cSraghuram #include <sys/callb.h> 73c1c61f44Ssb155480 #include <sys/vlan.h> 741ae08745Sheppo 751ae08745Sheppo /* 761ae08745Sheppo * Function prototypes. 771ae08745Sheppo */ 781ae08745Sheppo static int vsw_attach(dev_info_t *, ddi_attach_cmd_t); 791ae08745Sheppo static int vsw_detach(dev_info_t *, ddi_detach_cmd_t); 801ae08745Sheppo static int vsw_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 8134683adeSsg70180 static int vsw_get_md_physname(vsw_t *, md_t *, mde_cookie_t, char *); 8234683adeSsg70180 static int vsw_get_md_smodes(vsw_t *, md_t *, mde_cookie_t, uint8_t *, int *); 831ae08745Sheppo 841ae08745Sheppo /* MDEG routines */ 8534683adeSsg70180 static int vsw_mdeg_register(vsw_t *vswp); 861ae08745Sheppo static void vsw_mdeg_unregister(vsw_t *vswp); 871ae08745Sheppo static int vsw_mdeg_cb(void *cb_argp, mdeg_result_t *); 8834683adeSsg70180 static int vsw_port_mdeg_cb(void *cb_argp, mdeg_result_t *); 8919b65a69Ssb155480 static int vsw_get_initial_md_properties(vsw_t *vswp, md_t *, mde_cookie_t); 90c1c61f44Ssb155480 static int vsw_read_mdprops(vsw_t *vswp); 91c1c61f44Ssb155480 static void vsw_vlan_read_ids(void *arg, int type, md_t *mdp, 92c1c61f44Ssb155480 mde_cookie_t node, uint16_t *pvidp, uint16_t **vidspp, 93c1c61f44Ssb155480 uint16_t *nvidsp, uint16_t *default_idp); 94c1c61f44Ssb155480 static int vsw_port_read_props(vsw_port_t *portp, vsw_t *vswp, 95c1c61f44Ssb155480 md_t *mdp, mde_cookie_t *node); 96f0ca1d9aSsb155480 static void vsw_read_pri_eth_types(vsw_t *vswp, md_t *mdp, 97f0ca1d9aSsb155480 mde_cookie_t node); 98*7b1f684aSSriharsha Basavapatna static void vsw_mtu_read(vsw_t *vswp, md_t *mdp, mde_cookie_t node, 99*7b1f684aSSriharsha Basavapatna uint32_t *mtu); 100*7b1f684aSSriharsha Basavapatna static int vsw_mtu_update(vsw_t *vswp, uint32_t mtu); 10134683adeSsg70180 static void vsw_update_md_prop(vsw_t *, md_t *, mde_cookie_t); 10219b65a69Ssb155480 static void vsw_save_lmacaddr(vsw_t *vswp, uint64_t macaddr); 1031ae08745Sheppo 10406db247cSraghuram /* Mac driver related routines */ 10506db247cSraghuram static int vsw_mac_register(vsw_t *); 10606db247cSraghuram static int vsw_mac_unregister(vsw_t *); 10706db247cSraghuram static int vsw_m_stat(void *, uint_t, uint64_t *); 10806db247cSraghuram static void vsw_m_stop(void *arg); 10906db247cSraghuram static int vsw_m_start(void *arg); 11006db247cSraghuram static int vsw_m_unicst(void *arg, const uint8_t *); 11106db247cSraghuram static int vsw_m_multicst(void *arg, boolean_t, const uint8_t *); 11206db247cSraghuram static int vsw_m_promisc(void *arg, boolean_t); 11306db247cSraghuram static mblk_t *vsw_m_tx(void *arg, mblk_t *); 114f0ca1d9aSsb155480 void vsw_mac_rx(vsw_t *vswp, mac_resource_handle_t mrh, 115f0ca1d9aSsb155480 mblk_t *mp, vsw_macrx_flags_t flags); 1161ae08745Sheppo 11706db247cSraghuram /* 11806db247cSraghuram * Functions imported from other files. 11906db247cSraghuram */ 12006db247cSraghuram extern void vsw_setup_switching_timeout(void *arg); 12106db247cSraghuram extern void vsw_stop_switching_timeout(vsw_t *vswp); 12206db247cSraghuram extern int vsw_setup_switching(vsw_t *); 1237a327842Swentaoy extern void vsw_switch_frame_nop(vsw_t *vswp, mblk_t *mp, int caller, 1247a327842Swentaoy vsw_port_t *port, mac_resource_handle_t mrh); 12506db247cSraghuram extern int vsw_add_mcst(vsw_t *, uint8_t, uint64_t, void *); 12606db247cSraghuram extern int vsw_del_mcst(vsw_t *, uint8_t, uint64_t, void *); 12706db247cSraghuram extern void vsw_del_mcst_vsw(vsw_t *); 12806db247cSraghuram extern mcst_addr_t *vsw_del_addr(uint8_t devtype, void *arg, uint64_t addr); 12906db247cSraghuram extern int vsw_detach_ports(vsw_t *vswp); 13006db247cSraghuram extern int vsw_port_add(vsw_t *vswp, md_t *mdp, mde_cookie_t *node); 13106db247cSraghuram extern int vsw_port_detach(vsw_t *vswp, int p_instance); 132c1c61f44Ssb155480 static int vsw_port_update(vsw_t *vswp, md_t *curr_mdp, mde_cookie_t curr_mdex, 133c1c61f44Ssb155480 md_t *prev_mdp, mde_cookie_t prev_mdex); 134c1c61f44Ssb155480 extern int vsw_port_attach(vsw_port_t *port); 13506db247cSraghuram extern vsw_port_t *vsw_lookup_port(vsw_t *vswp, int p_instance); 13606db247cSraghuram extern int vsw_mac_attach(vsw_t *vswp); 13706db247cSraghuram extern void vsw_mac_detach(vsw_t *vswp); 13806db247cSraghuram extern int vsw_mac_open(vsw_t *vswp); 13906db247cSraghuram extern void vsw_mac_close(vsw_t *vswp); 14006db247cSraghuram extern int vsw_set_hw(vsw_t *, vsw_port_t *, int); 14106db247cSraghuram extern int vsw_unset_hw(vsw_t *, vsw_port_t *, int); 14206db247cSraghuram extern void vsw_reconfig_hw(vsw_t *); 14306db247cSraghuram extern void vsw_unset_addrs(vsw_t *vswp); 14406db247cSraghuram extern void vsw_set_addrs(vsw_t *vswp); 145c1c61f44Ssb155480 extern void vsw_create_vlans(void *arg, int type); 146c1c61f44Ssb155480 extern void vsw_destroy_vlans(void *arg, int type); 147c1c61f44Ssb155480 extern void vsw_vlan_add_ids(void *arg, int type); 148c1c61f44Ssb155480 extern void vsw_vlan_remove_ids(void *arg, int type); 149c1c61f44Ssb155480 extern void vsw_vlan_unaware_port_reset(vsw_port_t *portp); 150c1c61f44Ssb155480 extern uint32_t vsw_vlan_frame_untag(void *arg, int type, mblk_t **np, 151c1c61f44Ssb155480 mblk_t **npt); 152c1c61f44Ssb155480 extern mblk_t *vsw_vlan_frame_pretag(void *arg, int type, mblk_t *mp); 153678453a8Sspeer extern void vsw_hio_cleanup(vsw_t *vswp); 154678453a8Sspeer extern void vsw_hio_start_ports(vsw_t *vswp); 155*7b1f684aSSriharsha Basavapatna extern void vsw_reset_ports(vsw_t *vswp); 156*7b1f684aSSriharsha Basavapatna extern void vsw_port_reset(vsw_port_t *portp); 157678453a8Sspeer void vsw_hio_port_update(vsw_port_t *portp, boolean_t hio_enabled); 15806db247cSraghuram 15906db247cSraghuram /* 16006db247cSraghuram * Internal tunables. 16106db247cSraghuram */ 162445b4c2eSsb155480 int vsw_num_handshakes = VNET_NUM_HANDSHAKES; /* # of handshake attempts */ 1631ae08745Sheppo int vsw_wretries = 100; /* # of write attempts */ 164d10e4ef2Snarayan int vsw_desc_delay = 0; /* delay in us */ 165d10e4ef2Snarayan int vsw_read_attempts = 5; /* # of reads of descriptor */ 16619b65a69Ssb155480 int vsw_setup_switching_delay = 3; /* setup sw timeout interval in sec */ 1670e8b4070Ssb155480 int vsw_mac_open_retries = 300; /* max # of mac_open() retries */ 1680e8b4070Ssb155480 /* 300*3 = 900sec(15min) of max tmout */ 16906db247cSraghuram int vsw_ldc_tx_delay = 5; /* delay(ticks) for tx retries */ 17006db247cSraghuram int vsw_ldc_tx_retries = 10; /* # of ldc tx retries */ 17106db247cSraghuram boolean_t vsw_ldc_rxthr_enabled = B_TRUE; /* LDC Rx thread enabled */ 17206db247cSraghuram boolean_t vsw_ldc_txthr_enabled = B_TRUE; /* LDC Tx thread enabled */ 173d10e4ef2Snarayan 174c1c61f44Ssb155480 uint32_t vsw_fdb_nchains = 8; /* # of chains in fdb hash table */ 175c1c61f44Ssb155480 uint32_t vsw_vlan_nchains = 4; /* # of chains in vlan id hash table */ 176c1c61f44Ssb155480 uint32_t vsw_ethermtu = 1500; /* mtu of the device */ 177c1c61f44Ssb155480 1787a327842Swentaoy /* sw timeout for boot delay only, in milliseconds */ 1797a327842Swentaoy int vsw_setup_switching_boot_delay = 100 * MILLISEC; 1807a327842Swentaoy 181c1c61f44Ssb155480 /* delay in usec to wait for all references on a fdb entry to be dropped */ 182c1c61f44Ssb155480 uint32_t vsw_fdbe_refcnt_delay = 10; 183c1c61f44Ssb155480 184c1c61f44Ssb155480 /* 185c1c61f44Ssb155480 * Default vlan id. This is only used internally when the "default-vlan-id" 186c1c61f44Ssb155480 * property is not present in the MD device node. Therefore, this should not be 187c1c61f44Ssb155480 * used as a tunable; if this value is changed, the corresponding variable 188c1c61f44Ssb155480 * should be updated to the same value in all vnets connected to this vsw. 189c1c61f44Ssb155480 */ 190c1c61f44Ssb155480 uint16_t vsw_default_vlan_id = 1; 191c1c61f44Ssb155480 192f0ca1d9aSsb155480 /* 193f0ca1d9aSsb155480 * Workaround for a version handshake bug in obp's vnet. 194f0ca1d9aSsb155480 * If vsw initiates version negotiation starting from the highest version, 195f0ca1d9aSsb155480 * obp sends a nack and terminates version handshake. To workaround 196f0ca1d9aSsb155480 * this, we do not initiate version handshake when the channel comes up. 197f0ca1d9aSsb155480 * Instead, we wait for the peer to send its version info msg and go through 198f0ca1d9aSsb155480 * the version protocol exchange. If we successfully negotiate a version, 199f0ca1d9aSsb155480 * before sending the ack, we send our version info msg to the peer 200f0ca1d9aSsb155480 * using the <major,minor> version that we are about to ack. 201f0ca1d9aSsb155480 */ 202f0ca1d9aSsb155480 boolean_t vsw_obp_ver_proto_workaround = B_TRUE; 203f0ca1d9aSsb155480 204f0ca1d9aSsb155480 /* 205f0ca1d9aSsb155480 * In the absence of "priority-ether-types" property in MD, the following 206f0ca1d9aSsb155480 * internal tunable can be set to specify a single priority ethertype. 207f0ca1d9aSsb155480 */ 208f0ca1d9aSsb155480 uint64_t vsw_pri_eth_type = 0; 209f0ca1d9aSsb155480 210f0ca1d9aSsb155480 /* 211f0ca1d9aSsb155480 * Number of transmit priority buffers that are preallocated per device. 212f0ca1d9aSsb155480 * This number is chosen to be a small value to throttle transmission 213f0ca1d9aSsb155480 * of priority packets. Note: Must be a power of 2 for vio_create_mblks(). 214f0ca1d9aSsb155480 */ 215f0ca1d9aSsb155480 uint32_t vsw_pri_tx_nmblks = 64; 216d10e4ef2Snarayan 21751aa9d07Ssb155480 /* 21851aa9d07Ssb155480 * Number of RARP packets sent to announce macaddr to the physical switch, 21951aa9d07Ssb155480 * after vsw's physical device is changed dynamically or after a guest (client 22051aa9d07Ssb155480 * vnet) is live migrated in. 22151aa9d07Ssb155480 */ 22251aa9d07Ssb155480 uint32_t vsw_publish_macaddr_count = 3; 22351aa9d07Ssb155480 224678453a8Sspeer boolean_t vsw_hio_enabled = B_TRUE; /* Enable/disable HybridIO */ 225678453a8Sspeer int vsw_hio_max_cleanup_retries = 10; /* Max retries for HybridIO cleanp */ 226678453a8Sspeer int vsw_hio_cleanup_delay = 10000; /* 10ms */ 227678453a8Sspeer 22806db247cSraghuram /* 22906db247cSraghuram * External tunables. 23006db247cSraghuram */ 23106db247cSraghuram /* 23206db247cSraghuram * Enable/disable thread per ring. This is a mode selection 23306db247cSraghuram * that is done a vsw driver attach time. 23406db247cSraghuram */ 23506db247cSraghuram boolean_t vsw_multi_ring_enable = B_FALSE; 23606db247cSraghuram int vsw_mac_rx_rings = VSW_MAC_RX_RINGS; 23706db247cSraghuram 238f0ca1d9aSsb155480 /* Number of transmit descriptors - must be power of 2 */ 239f0ca1d9aSsb155480 uint32_t vsw_ntxds = VSW_RING_NUM_EL; 240f0ca1d9aSsb155480 24106db247cSraghuram /* 24206db247cSraghuram * Max number of mblks received in one receive operation. 24306db247cSraghuram */ 24406db247cSraghuram uint32_t vsw_chain_len = (VSW_NUM_MBLKS * 0.6); 24506db247cSraghuram 24606db247cSraghuram /* 247*7b1f684aSSriharsha Basavapatna * Internal tunables for receive buffer pools, that is, the size and number of 248*7b1f684aSSriharsha Basavapatna * mblks for each pool. At least 3 sizes must be specified if these are used. 249*7b1f684aSSriharsha Basavapatna * The sizes must be specified in increasing order. Non-zero value of the first 250*7b1f684aSSriharsha Basavapatna * size will be used as a hint to use these values instead of the algorithm 251*7b1f684aSSriharsha Basavapatna * that determines the sizes based on MTU. 25206db247cSraghuram */ 253*7b1f684aSSriharsha Basavapatna uint32_t vsw_mblk_size1 = 0; 254*7b1f684aSSriharsha Basavapatna uint32_t vsw_mblk_size2 = 0; 255*7b1f684aSSriharsha Basavapatna uint32_t vsw_mblk_size3 = 0; 256*7b1f684aSSriharsha Basavapatna uint32_t vsw_mblk_size4 = 0; 25706db247cSraghuram uint32_t vsw_num_mblks1 = VSW_NUM_MBLKS; /* number of mblks for pool1 */ 25806db247cSraghuram uint32_t vsw_num_mblks2 = VSW_NUM_MBLKS; /* number of mblks for pool2 */ 25906db247cSraghuram uint32_t vsw_num_mblks3 = VSW_NUM_MBLKS; /* number of mblks for pool3 */ 260*7b1f684aSSriharsha Basavapatna uint32_t vsw_num_mblks4 = VSW_NUM_MBLKS; /* number of mblks for pool4 */ 261*7b1f684aSSriharsha Basavapatna 262*7b1f684aSSriharsha Basavapatna /* 263*7b1f684aSSriharsha Basavapatna * Set this to non-zero to enable additional internal receive buffer pools 264*7b1f684aSSriharsha Basavapatna * based on the MTU of the device for better performance at the cost of more 265*7b1f684aSSriharsha Basavapatna * memory consumption. This is turned off by default, to use allocb(9F) for 266*7b1f684aSSriharsha Basavapatna * receive buffer allocations of sizes > 2K. 267*7b1f684aSSriharsha Basavapatna */ 268*7b1f684aSSriharsha Basavapatna boolean_t vsw_jumbo_rxpools = B_FALSE; 26906db247cSraghuram 27006db247cSraghuram /* 271f0ca1d9aSsb155480 * vsw_max_tx_qcount is the maximum # of packets that can be queued 272f0ca1d9aSsb155480 * before the tx worker thread begins processing the queue. Its value 273f0ca1d9aSsb155480 * is chosen to be 4x the default length of tx descriptor ring. 274f0ca1d9aSsb155480 */ 275f0ca1d9aSsb155480 uint32_t vsw_max_tx_qcount = 4 * VSW_RING_NUM_EL; 276f0ca1d9aSsb155480 277f0ca1d9aSsb155480 /* 27806db247cSraghuram * MAC callbacks 27906db247cSraghuram */ 280ba2e4443Sseb static mac_callbacks_t vsw_m_callbacks = { 281ba2e4443Sseb 0, 282ba2e4443Sseb vsw_m_stat, 283ba2e4443Sseb vsw_m_start, 284ba2e4443Sseb vsw_m_stop, 285ba2e4443Sseb vsw_m_promisc, 286ba2e4443Sseb vsw_m_multicst, 287ba2e4443Sseb vsw_m_unicst, 288ba2e4443Sseb vsw_m_tx, 289ba2e4443Sseb NULL, 290ba2e4443Sseb NULL, 291ba2e4443Sseb NULL 292ba2e4443Sseb }; 293ba2e4443Sseb 2941ae08745Sheppo static struct cb_ops vsw_cb_ops = { 2951ae08745Sheppo nulldev, /* cb_open */ 2961ae08745Sheppo nulldev, /* cb_close */ 2971ae08745Sheppo nodev, /* cb_strategy */ 2981ae08745Sheppo nodev, /* cb_print */ 2991ae08745Sheppo nodev, /* cb_dump */ 3001ae08745Sheppo nodev, /* cb_read */ 3011ae08745Sheppo nodev, /* cb_write */ 3021ae08745Sheppo nodev, /* cb_ioctl */ 3031ae08745Sheppo nodev, /* cb_devmap */ 3041ae08745Sheppo nodev, /* cb_mmap */ 3051ae08745Sheppo nodev, /* cb_segmap */ 3061ae08745Sheppo nochpoll, /* cb_chpoll */ 3071ae08745Sheppo ddi_prop_op, /* cb_prop_op */ 3081ae08745Sheppo NULL, /* cb_stream */ 3091ae08745Sheppo D_MP, /* cb_flag */ 3101ae08745Sheppo CB_REV, /* rev */ 3111ae08745Sheppo nodev, /* int (*cb_aread)() */ 3121ae08745Sheppo nodev /* int (*cb_awrite)() */ 3131ae08745Sheppo }; 3141ae08745Sheppo 3151ae08745Sheppo static struct dev_ops vsw_ops = { 3161ae08745Sheppo DEVO_REV, /* devo_rev */ 3171ae08745Sheppo 0, /* devo_refcnt */ 3181ae08745Sheppo vsw_getinfo, /* devo_getinfo */ 3191ae08745Sheppo nulldev, /* devo_identify */ 3201ae08745Sheppo nulldev, /* devo_probe */ 3211ae08745Sheppo vsw_attach, /* devo_attach */ 3221ae08745Sheppo vsw_detach, /* devo_detach */ 3231ae08745Sheppo nodev, /* devo_reset */ 3241ae08745Sheppo &vsw_cb_ops, /* devo_cb_ops */ 3251ae08745Sheppo (struct bus_ops *)NULL, /* devo_bus_ops */ 3261ae08745Sheppo ddi_power /* devo_power */ 3271ae08745Sheppo }; 3281ae08745Sheppo 3291ae08745Sheppo extern struct mod_ops mod_driverops; 3301ae08745Sheppo static struct modldrv vswmodldrv = { 3311ae08745Sheppo &mod_driverops, 332205eeb1aSlm66018 "sun4v Virtual Switch", 3331ae08745Sheppo &vsw_ops, 3341ae08745Sheppo }; 3351ae08745Sheppo 3361ae08745Sheppo #define LDC_ENTER_LOCK(ldcp) \ 3371ae08745Sheppo mutex_enter(&((ldcp)->ldc_cblock));\ 33806db247cSraghuram mutex_enter(&((ldcp)->ldc_rxlock));\ 3391ae08745Sheppo mutex_enter(&((ldcp)->ldc_txlock)); 3401ae08745Sheppo #define LDC_EXIT_LOCK(ldcp) \ 3411ae08745Sheppo mutex_exit(&((ldcp)->ldc_txlock));\ 34206db247cSraghuram mutex_exit(&((ldcp)->ldc_rxlock));\ 3431ae08745Sheppo mutex_exit(&((ldcp)->ldc_cblock)); 3441ae08745Sheppo 3451ae08745Sheppo /* Driver soft state ptr */ 3461ae08745Sheppo static void *vsw_state; 3471ae08745Sheppo 3481ae08745Sheppo /* 3491ae08745Sheppo * Linked list of "vsw_t" structures - one per instance. 3501ae08745Sheppo */ 3511ae08745Sheppo vsw_t *vsw_head = NULL; 3521ae08745Sheppo krwlock_t vsw_rw; 3531ae08745Sheppo 3541ae08745Sheppo /* 3551ae08745Sheppo * Property names 3561ae08745Sheppo */ 3571ae08745Sheppo static char vdev_propname[] = "virtual-device"; 3581ae08745Sheppo static char vsw_propname[] = "virtual-network-switch"; 3591ae08745Sheppo static char physdev_propname[] = "vsw-phys-dev"; 3601ae08745Sheppo static char smode_propname[] = "vsw-switch-mode"; 3611ae08745Sheppo static char macaddr_propname[] = "local-mac-address"; 3621ae08745Sheppo static char remaddr_propname[] = "remote-mac-address"; 3631ae08745Sheppo static char ldcids_propname[] = "ldc-ids"; 3641ae08745Sheppo static char chan_propname[] = "channel-endpoint"; 3651ae08745Sheppo static char id_propname[] = "id"; 3661ae08745Sheppo static char reg_propname[] = "reg"; 367f0ca1d9aSsb155480 static char pri_types_propname[] = "priority-ether-types"; 368c1c61f44Ssb155480 static char vsw_pvid_propname[] = "port-vlan-id"; 369c1c61f44Ssb155480 static char vsw_vid_propname[] = "vlan-id"; 370c1c61f44Ssb155480 static char vsw_dvid_propname[] = "default-vlan-id"; 371c1c61f44Ssb155480 static char port_pvid_propname[] = "remote-port-vlan-id"; 372c1c61f44Ssb155480 static char port_vid_propname[] = "remote-vlan-id"; 373678453a8Sspeer static char hybrid_propname[] = "hybrid"; 374*7b1f684aSSriharsha Basavapatna static char vsw_mtu_propname[] = "mtu"; 3751ae08745Sheppo 3761ae08745Sheppo /* 3771ae08745Sheppo * Matching criteria passed to the MDEG to register interest 3781ae08745Sheppo * in changes to 'virtual-device-port' nodes identified by their 3791ae08745Sheppo * 'id' property. 3801ae08745Sheppo */ 3811ae08745Sheppo static md_prop_match_t vport_prop_match[] = { 3821ae08745Sheppo { MDET_PROP_VAL, "id" }, 3831ae08745Sheppo { MDET_LIST_END, NULL } 3841ae08745Sheppo }; 3851ae08745Sheppo 3861ae08745Sheppo static mdeg_node_match_t vport_match = { "virtual-device-port", 3871ae08745Sheppo vport_prop_match }; 3881ae08745Sheppo 3891ae08745Sheppo /* 39034683adeSsg70180 * Matching criteria passed to the MDEG to register interest 39134683adeSsg70180 * in changes to 'virtual-device' nodes (i.e. vsw nodes) identified 39234683adeSsg70180 * by their 'name' and 'cfg-handle' properties. 39334683adeSsg70180 */ 39434683adeSsg70180 static md_prop_match_t vdev_prop_match[] = { 39534683adeSsg70180 { MDET_PROP_STR, "name" }, 39634683adeSsg70180 { MDET_PROP_VAL, "cfg-handle" }, 39734683adeSsg70180 { MDET_LIST_END, NULL } 39834683adeSsg70180 }; 39934683adeSsg70180 40034683adeSsg70180 static mdeg_node_match_t vdev_match = { "virtual-device", 40134683adeSsg70180 vdev_prop_match }; 40234683adeSsg70180 40334683adeSsg70180 40434683adeSsg70180 /* 4051ae08745Sheppo * Specification of an MD node passed to the MDEG to filter any 4061ae08745Sheppo * 'vport' nodes that do not belong to the specified node. This 4071ae08745Sheppo * template is copied for each vsw instance and filled in with 4081ae08745Sheppo * the appropriate 'cfg-handle' value before being passed to the MDEG. 4091ae08745Sheppo */ 4101ae08745Sheppo static mdeg_prop_spec_t vsw_prop_template[] = { 4111ae08745Sheppo { MDET_PROP_STR, "name", vsw_propname }, 4121ae08745Sheppo { MDET_PROP_VAL, "cfg-handle", NULL }, 4131ae08745Sheppo { MDET_LIST_END, NULL, NULL } 4141ae08745Sheppo }; 4151ae08745Sheppo 4161ae08745Sheppo #define VSW_SET_MDEG_PROP_INST(specp, val) (specp)[1].ps_val = (val); 4171ae08745Sheppo 41806db247cSraghuram #ifdef DEBUG 4197636cb21Slm66018 /* 4201ae08745Sheppo * Print debug messages - set to 0x1f to enable all msgs 4211ae08745Sheppo * or 0x0 to turn all off. 4221ae08745Sheppo */ 4231ae08745Sheppo int vswdbg = 0x0; 4241ae08745Sheppo 4251ae08745Sheppo /* 4261ae08745Sheppo * debug levels: 4271ae08745Sheppo * 0x01: Function entry/exit tracing 4281ae08745Sheppo * 0x02: Internal function messages 4291ae08745Sheppo * 0x04: Verbose internal messages 4301ae08745Sheppo * 0x08: Warning messages 4311ae08745Sheppo * 0x10: Error messages 4321ae08745Sheppo */ 4331ae08745Sheppo 43406db247cSraghuram void 4351ae08745Sheppo vswdebug(vsw_t *vswp, const char *fmt, ...) 4361ae08745Sheppo { 4371ae08745Sheppo char buf[512]; 4381ae08745Sheppo va_list ap; 4391ae08745Sheppo 4401ae08745Sheppo va_start(ap, fmt); 4411ae08745Sheppo (void) vsprintf(buf, fmt, ap); 4421ae08745Sheppo va_end(ap); 4431ae08745Sheppo 4441ae08745Sheppo if (vswp == NULL) 4451ae08745Sheppo cmn_err(CE_CONT, "%s\n", buf); 4461ae08745Sheppo else 4471ae08745Sheppo cmn_err(CE_CONT, "vsw%d: %s\n", vswp->instance, buf); 4481ae08745Sheppo } 4491ae08745Sheppo 4501ae08745Sheppo #endif /* DEBUG */ 4511ae08745Sheppo 4521ae08745Sheppo static struct modlinkage modlinkage = { 4531ae08745Sheppo MODREV_1, 4541ae08745Sheppo &vswmodldrv, 4551ae08745Sheppo NULL 4561ae08745Sheppo }; 4571ae08745Sheppo 4581ae08745Sheppo int 4591ae08745Sheppo _init(void) 4601ae08745Sheppo { 4611ae08745Sheppo int status; 4621ae08745Sheppo 4631ae08745Sheppo rw_init(&vsw_rw, NULL, RW_DRIVER, NULL); 4641ae08745Sheppo 4651ae08745Sheppo status = ddi_soft_state_init(&vsw_state, sizeof (vsw_t), 1); 4661ae08745Sheppo if (status != 0) { 4671ae08745Sheppo return (status); 4681ae08745Sheppo } 4691ae08745Sheppo 47006db247cSraghuram mac_init_ops(&vsw_ops, DRV_NAME); 4711ae08745Sheppo status = mod_install(&modlinkage); 4721ae08745Sheppo if (status != 0) { 4731ae08745Sheppo ddi_soft_state_fini(&vsw_state); 4741ae08745Sheppo } 4751ae08745Sheppo return (status); 4761ae08745Sheppo } 4771ae08745Sheppo 4781ae08745Sheppo int 4791ae08745Sheppo _fini(void) 4801ae08745Sheppo { 4811ae08745Sheppo int status; 4821ae08745Sheppo 4831ae08745Sheppo status = mod_remove(&modlinkage); 4841ae08745Sheppo if (status != 0) 4851ae08745Sheppo return (status); 4861ae08745Sheppo mac_fini_ops(&vsw_ops); 4871ae08745Sheppo ddi_soft_state_fini(&vsw_state); 4881ae08745Sheppo 4891ae08745Sheppo rw_destroy(&vsw_rw); 4901ae08745Sheppo 4911ae08745Sheppo return (status); 4921ae08745Sheppo } 4931ae08745Sheppo 4941ae08745Sheppo int 4951ae08745Sheppo _info(struct modinfo *modinfop) 4961ae08745Sheppo { 4971ae08745Sheppo return (mod_info(&modlinkage, modinfop)); 4981ae08745Sheppo } 4991ae08745Sheppo 5001ae08745Sheppo static int 5011ae08745Sheppo vsw_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 5021ae08745Sheppo { 5031ae08745Sheppo vsw_t *vswp; 50434683adeSsg70180 int instance; 5051ae08745Sheppo char hashname[MAXNAMELEN]; 5061ae08745Sheppo char qname[TASKQ_NAMELEN]; 5077636cb21Slm66018 enum { PROG_init = 0x00, 50819b65a69Ssb155480 PROG_locks = 0x01, 50919b65a69Ssb155480 PROG_readmd = 0x02, 51019b65a69Ssb155480 PROG_fdb = 0x04, 51119b65a69Ssb155480 PROG_mfdb = 0x08, 51219b65a69Ssb155480 PROG_taskq = 0x10, 513f0ca1d9aSsb155480 PROG_swmode = 0x20, 514f0ca1d9aSsb155480 PROG_macreg = 0x40, 515f0ca1d9aSsb155480 PROG_mdreg = 0x80} 5161ae08745Sheppo progress; 5171ae08745Sheppo 5181ae08745Sheppo progress = PROG_init; 51919b65a69Ssb155480 int rv; 5201ae08745Sheppo 5211ae08745Sheppo switch (cmd) { 5221ae08745Sheppo case DDI_ATTACH: 5231ae08745Sheppo break; 5241ae08745Sheppo case DDI_RESUME: 5251ae08745Sheppo /* nothing to do for this non-device */ 5261ae08745Sheppo return (DDI_SUCCESS); 5271ae08745Sheppo case DDI_PM_RESUME: 5281ae08745Sheppo default: 5291ae08745Sheppo return (DDI_FAILURE); 5301ae08745Sheppo } 5311ae08745Sheppo 5321ae08745Sheppo instance = ddi_get_instance(dip); 5331ae08745Sheppo if (ddi_soft_state_zalloc(vsw_state, instance) != DDI_SUCCESS) { 5341ae08745Sheppo DERR(NULL, "vsw%d: ddi_soft_state_zalloc failed", instance); 5351ae08745Sheppo return (DDI_FAILURE); 5361ae08745Sheppo } 5371ae08745Sheppo vswp = ddi_get_soft_state(vsw_state, instance); 5381ae08745Sheppo 5391ae08745Sheppo if (vswp == NULL) { 5401ae08745Sheppo DERR(NULL, "vsw%d: ddi_get_soft_state failed", instance); 5411ae08745Sheppo goto vsw_attach_fail; 5421ae08745Sheppo } 5431ae08745Sheppo 5441ae08745Sheppo vswp->dip = dip; 5451ae08745Sheppo vswp->instance = instance; 5461ae08745Sheppo ddi_set_driver_private(dip, (caddr_t)vswp); 5471ae08745Sheppo 5485f94e909Ssg70180 mutex_init(&vswp->hw_lock, NULL, MUTEX_DRIVER, NULL); 54919b65a69Ssb155480 mutex_init(&vswp->mca_lock, NULL, MUTEX_DRIVER, NULL); 55019b65a69Ssb155480 mutex_init(&vswp->swtmout_lock, NULL, MUTEX_DRIVER, NULL); 5511ae08745Sheppo rw_init(&vswp->if_lockrw, NULL, RW_DRIVER, NULL); 5523c1bce15Swentaoy rw_init(&vswp->mac_rwlock, NULL, RW_DRIVER, NULL); 55319b65a69Ssb155480 rw_init(&vswp->mfdbrw, NULL, RW_DRIVER, NULL); 55419b65a69Ssb155480 rw_init(&vswp->plist.lockrw, NULL, RW_DRIVER, NULL); 55519b65a69Ssb155480 55619b65a69Ssb155480 progress |= PROG_locks; 55719b65a69Ssb155480 55819b65a69Ssb155480 rv = vsw_read_mdprops(vswp); 55919b65a69Ssb155480 if (rv != 0) 56019b65a69Ssb155480 goto vsw_attach_fail; 56119b65a69Ssb155480 56219b65a69Ssb155480 progress |= PROG_readmd; 5631ae08745Sheppo 5641ae08745Sheppo /* setup the unicast forwarding database */ 5651ae08745Sheppo (void) snprintf(hashname, MAXNAMELEN, "vsw_unicst_table-%d", 5661ae08745Sheppo vswp->instance); 5671ae08745Sheppo D2(vswp, "creating unicast hash table (%s)...", hashname); 568c1c61f44Ssb155480 vswp->fdb_nchains = vsw_fdb_nchains; 569c1c61f44Ssb155480 vswp->fdb_hashp = mod_hash_create_ptrhash(hashname, vswp->fdb_nchains, 5701ae08745Sheppo mod_hash_null_valdtor, sizeof (void *)); 571c1c61f44Ssb155480 vsw_create_vlans((void *)vswp, VSW_LOCALDEV); 5721ae08745Sheppo progress |= PROG_fdb; 5731ae08745Sheppo 5741ae08745Sheppo /* setup the multicast fowarding database */ 5751ae08745Sheppo (void) snprintf(hashname, MAXNAMELEN, "vsw_mcst_table-%d", 5761ae08745Sheppo vswp->instance); 5771ae08745Sheppo D2(vswp, "creating multicast hash table %s)...", hashname); 578c1c61f44Ssb155480 vswp->mfdb = mod_hash_create_ptrhash(hashname, vsw_fdb_nchains, 5791ae08745Sheppo mod_hash_null_valdtor, sizeof (void *)); 5801ae08745Sheppo 5811ae08745Sheppo progress |= PROG_mfdb; 5821ae08745Sheppo 5831ae08745Sheppo /* 5841ae08745Sheppo * Create the taskq which will process all the VIO 5851ae08745Sheppo * control messages. 5861ae08745Sheppo */ 5871ae08745Sheppo (void) snprintf(qname, TASKQ_NAMELEN, "vsw_taskq%d", vswp->instance); 5881ae08745Sheppo if ((vswp->taskq_p = ddi_taskq_create(vswp->dip, qname, 1, 5891ae08745Sheppo TASKQ_DEFAULTPRI, 0)) == NULL) { 59034683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to create task queue", 59134683adeSsg70180 vswp->instance); 5921ae08745Sheppo goto vsw_attach_fail; 5931ae08745Sheppo } 5941ae08745Sheppo 5951ae08745Sheppo progress |= PROG_taskq; 5961ae08745Sheppo 597d10e4ef2Snarayan /* prevent auto-detaching */ 598d10e4ef2Snarayan if (ddi_prop_update_int(DDI_DEV_T_NONE, vswp->dip, 599d10e4ef2Snarayan DDI_NO_AUTODETACH, 1) != DDI_SUCCESS) { 60034683adeSsg70180 cmn_err(CE_NOTE, "!Unable to set \"%s\" property for " 601d10e4ef2Snarayan "instance %u", DDI_NO_AUTODETACH, instance); 602d10e4ef2Snarayan } 603d10e4ef2Snarayan 6041ae08745Sheppo /* 6057a327842Swentaoy * The null switching function is set to avoid panic until 6067a327842Swentaoy * switch mode is setup. 6077a327842Swentaoy */ 6087a327842Swentaoy vswp->vsw_switch_frame = vsw_switch_frame_nop; 6097a327842Swentaoy 6107a327842Swentaoy /* 61119b65a69Ssb155480 * Setup the required switching mode, 61219b65a69Ssb155480 * based on the mdprops that we read earlier. 6137a327842Swentaoy * schedule a short timeout (0.1 sec) for the first time 6147a327842Swentaoy * setup and avoid calling mac_open() directly here, 6157a327842Swentaoy * others are regular timeout 3 secs. 61619b65a69Ssb155480 */ 61719b65a69Ssb155480 mutex_enter(&vswp->swtmout_lock); 61819b65a69Ssb155480 61919b65a69Ssb155480 vswp->swtmout_enabled = B_TRUE; 6207a327842Swentaoy vswp->swtmout_id = timeout(vsw_setup_switching_timeout, vswp, 6217a327842Swentaoy drv_usectohz(vsw_setup_switching_boot_delay)); 62219b65a69Ssb155480 62319b65a69Ssb155480 mutex_exit(&vswp->swtmout_lock); 62419b65a69Ssb155480 62519b65a69Ssb155480 progress |= PROG_swmode; 62619b65a69Ssb155480 62719b65a69Ssb155480 /* Register with mac layer as a provider */ 62819b65a69Ssb155480 rv = vsw_mac_register(vswp); 62919b65a69Ssb155480 if (rv != 0) 63019b65a69Ssb155480 goto vsw_attach_fail; 63119b65a69Ssb155480 63219b65a69Ssb155480 progress |= PROG_macreg; 63319b65a69Ssb155480 63419b65a69Ssb155480 /* 63534683adeSsg70180 * Now we have everything setup, register an interest in 63634683adeSsg70180 * specific MD nodes. 63734683adeSsg70180 * 63834683adeSsg70180 * The callback is invoked in 2 cases, firstly if upon mdeg 63934683adeSsg70180 * registration there are existing nodes which match our specified 64034683adeSsg70180 * criteria, and secondly if the MD is changed (and again, there 64134683adeSsg70180 * are nodes which we are interested in present within it. Note 64234683adeSsg70180 * that our callback will be invoked even if our specified nodes 64334683adeSsg70180 * have not actually changed). 64434683adeSsg70180 * 6451ae08745Sheppo */ 64619b65a69Ssb155480 rv = vsw_mdeg_register(vswp); 64719b65a69Ssb155480 if (rv != 0) 64834683adeSsg70180 goto vsw_attach_fail; 6491ae08745Sheppo 65019b65a69Ssb155480 progress |= PROG_mdreg; 65119b65a69Ssb155480 65219b65a69Ssb155480 WRITE_ENTER(&vsw_rw); 65319b65a69Ssb155480 vswp->next = vsw_head; 65419b65a69Ssb155480 vsw_head = vswp; 65519b65a69Ssb155480 RW_EXIT(&vsw_rw); 65619b65a69Ssb155480 65719b65a69Ssb155480 ddi_report_dev(vswp->dip); 6581ae08745Sheppo return (DDI_SUCCESS); 6591ae08745Sheppo 6601ae08745Sheppo vsw_attach_fail: 6611ae08745Sheppo DERR(NULL, "vsw_attach: failed"); 6621ae08745Sheppo 66319b65a69Ssb155480 if (progress & PROG_mdreg) { 66419b65a69Ssb155480 vsw_mdeg_unregister(vswp); 66519b65a69Ssb155480 (void) vsw_detach_ports(vswp); 66619b65a69Ssb155480 } 66719b65a69Ssb155480 66819b65a69Ssb155480 if (progress & PROG_macreg) 66919b65a69Ssb155480 (void) vsw_mac_unregister(vswp); 67019b65a69Ssb155480 67119b65a69Ssb155480 if (progress & PROG_swmode) { 67219b65a69Ssb155480 vsw_stop_switching_timeout(vswp); 673678453a8Sspeer vsw_hio_cleanup(vswp); 6743c1bce15Swentaoy WRITE_ENTER(&vswp->mac_rwlock); 67519b65a69Ssb155480 vsw_mac_detach(vswp); 67619b65a69Ssb155480 vsw_mac_close(vswp); 6773c1bce15Swentaoy RW_EXIT(&vswp->mac_rwlock); 67819b65a69Ssb155480 } 67919b65a69Ssb155480 6801ae08745Sheppo if (progress & PROG_taskq) 6811ae08745Sheppo ddi_taskq_destroy(vswp->taskq_p); 6821ae08745Sheppo 68319b65a69Ssb155480 if (progress & PROG_mfdb) 6841ae08745Sheppo mod_hash_destroy_hash(vswp->mfdb); 6851ae08745Sheppo 686c1c61f44Ssb155480 if (progress & PROG_fdb) { 687c1c61f44Ssb155480 vsw_destroy_vlans(vswp, VSW_LOCALDEV); 688c1c61f44Ssb155480 mod_hash_destroy_hash(vswp->fdb_hashp); 689c1c61f44Ssb155480 } 6901ae08745Sheppo 691f0ca1d9aSsb155480 if (progress & PROG_readmd) { 692f0ca1d9aSsb155480 if (VSW_PRI_ETH_DEFINED(vswp)) { 693f0ca1d9aSsb155480 kmem_free(vswp->pri_types, 694f0ca1d9aSsb155480 sizeof (uint16_t) * vswp->pri_num_types); 695f0ca1d9aSsb155480 } 696f0ca1d9aSsb155480 (void) vio_destroy_mblks(vswp->pri_tx_vmp); 697f0ca1d9aSsb155480 } 698f0ca1d9aSsb155480 69919b65a69Ssb155480 if (progress & PROG_locks) { 70019b65a69Ssb155480 rw_destroy(&vswp->plist.lockrw); 70119b65a69Ssb155480 rw_destroy(&vswp->mfdbrw); 7023c1bce15Swentaoy rw_destroy(&vswp->mac_rwlock); 7031ae08745Sheppo rw_destroy(&vswp->if_lockrw); 70419b65a69Ssb155480 mutex_destroy(&vswp->swtmout_lock); 70519b65a69Ssb155480 mutex_destroy(&vswp->mca_lock); 7065f94e909Ssg70180 mutex_destroy(&vswp->hw_lock); 70734683adeSsg70180 } 7081ae08745Sheppo 7091ae08745Sheppo ddi_soft_state_free(vsw_state, instance); 7101ae08745Sheppo return (DDI_FAILURE); 7111ae08745Sheppo } 7121ae08745Sheppo 7131ae08745Sheppo static int 7141ae08745Sheppo vsw_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 7151ae08745Sheppo { 716d10e4ef2Snarayan vio_mblk_pool_t *poolp, *npoolp; 7171ae08745Sheppo vsw_t **vswpp, *vswp; 7181ae08745Sheppo int instance; 7191ae08745Sheppo 7201ae08745Sheppo instance = ddi_get_instance(dip); 7211ae08745Sheppo vswp = ddi_get_soft_state(vsw_state, instance); 7221ae08745Sheppo 7231ae08745Sheppo if (vswp == NULL) { 7241ae08745Sheppo return (DDI_FAILURE); 7251ae08745Sheppo } 7261ae08745Sheppo 7271ae08745Sheppo switch (cmd) { 7281ae08745Sheppo case DDI_DETACH: 7291ae08745Sheppo break; 7301ae08745Sheppo case DDI_SUSPEND: 7311ae08745Sheppo case DDI_PM_SUSPEND: 7321ae08745Sheppo default: 7331ae08745Sheppo return (DDI_FAILURE); 7341ae08745Sheppo } 7351ae08745Sheppo 7361ae08745Sheppo D2(vswp, "detaching instance %d", instance); 7371ae08745Sheppo 73819b65a69Ssb155480 /* Stop any pending timeout to setup switching mode. */ 73919b65a69Ssb155480 vsw_stop_switching_timeout(vswp); 74019b65a69Ssb155480 74134683adeSsg70180 if (vswp->if_state & VSW_IF_REG) { 7421ae08745Sheppo if (vsw_mac_unregister(vswp) != 0) { 74334683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to detach from " 74434683adeSsg70180 "MAC layer", vswp->instance); 7451ae08745Sheppo return (DDI_FAILURE); 7461ae08745Sheppo } 747d10e4ef2Snarayan } 7481ae08745Sheppo 7491ae08745Sheppo vsw_mdeg_unregister(vswp); 7501ae08745Sheppo 751e1ebb9ecSlm66018 /* remove mac layer callback */ 7523c1bce15Swentaoy WRITE_ENTER(&vswp->mac_rwlock); 753e1ebb9ecSlm66018 if ((vswp->mh != NULL) && (vswp->mrh != NULL)) { 7541f8aaf0dSethindra mac_rx_remove(vswp->mh, vswp->mrh, B_TRUE); 755e1ebb9ecSlm66018 vswp->mrh = NULL; 7561ae08745Sheppo } 7573c1bce15Swentaoy RW_EXIT(&vswp->mac_rwlock); 7581ae08745Sheppo 7591ae08745Sheppo if (vsw_detach_ports(vswp) != 0) { 7601ef0bbb5Snarayan cmn_err(CE_WARN, "!vsw%d: Unable to unconfigure ports", 76134683adeSsg70180 vswp->instance); 7621ae08745Sheppo return (DDI_FAILURE); 7631ae08745Sheppo } 7641ae08745Sheppo 76534683adeSsg70180 rw_destroy(&vswp->if_lockrw); 76634683adeSsg70180 767678453a8Sspeer /* cleanup HybridIO */ 768678453a8Sspeer vsw_hio_cleanup(vswp); 769678453a8Sspeer 7705f94e909Ssg70180 mutex_destroy(&vswp->hw_lock); 7715f94e909Ssg70180 7721ae08745Sheppo /* 773e1ebb9ecSlm66018 * Now that the ports have been deleted, stop and close 774e1ebb9ecSlm66018 * the physical device. 775e1ebb9ecSlm66018 */ 7763c1bce15Swentaoy WRITE_ENTER(&vswp->mac_rwlock); 777e1ebb9ecSlm66018 77819b65a69Ssb155480 vsw_mac_detach(vswp); 77919b65a69Ssb155480 vsw_mac_close(vswp); 78019b65a69Ssb155480 7813c1bce15Swentaoy RW_EXIT(&vswp->mac_rwlock); 78219b65a69Ssb155480 7833c1bce15Swentaoy rw_destroy(&vswp->mac_rwlock); 78419b65a69Ssb155480 mutex_destroy(&vswp->swtmout_lock); 785e1ebb9ecSlm66018 786e1ebb9ecSlm66018 /* 787d10e4ef2Snarayan * Destroy any free pools that may still exist. 788d10e4ef2Snarayan */ 789d10e4ef2Snarayan poolp = vswp->rxh; 790d10e4ef2Snarayan while (poolp != NULL) { 791d10e4ef2Snarayan npoolp = vswp->rxh = poolp->nextp; 792d10e4ef2Snarayan if (vio_destroy_mblks(poolp) != 0) { 793d10e4ef2Snarayan vswp->rxh = poolp; 794d10e4ef2Snarayan return (DDI_FAILURE); 795d10e4ef2Snarayan } 796d10e4ef2Snarayan poolp = npoolp; 797d10e4ef2Snarayan } 798d10e4ef2Snarayan 799d10e4ef2Snarayan /* 8001ae08745Sheppo * Remove this instance from any entries it may be on in 8011ae08745Sheppo * the hash table by using the list of addresses maintained 8021ae08745Sheppo * in the vsw_t structure. 8031ae08745Sheppo */ 8041ae08745Sheppo vsw_del_mcst_vsw(vswp); 8051ae08745Sheppo 8061ae08745Sheppo vswp->mcap = NULL; 8071ae08745Sheppo mutex_destroy(&vswp->mca_lock); 8081ae08745Sheppo 8091ae08745Sheppo /* 8101ae08745Sheppo * By now any pending tasks have finished and the underlying 8111ae08745Sheppo * ldc's have been destroyed, so its safe to delete the control 8121ae08745Sheppo * message taskq. 8131ae08745Sheppo */ 8141ae08745Sheppo if (vswp->taskq_p != NULL) 8151ae08745Sheppo ddi_taskq_destroy(vswp->taskq_p); 8161ae08745Sheppo 8171ae08745Sheppo /* 8181ae08745Sheppo * At this stage all the data pointers in the hash table 8191ae08745Sheppo * should be NULL, as all the ports have been removed and will 8201ae08745Sheppo * have deleted themselves from the port lists which the data 8211ae08745Sheppo * pointers point to. Hence we can destroy the table using the 8221ae08745Sheppo * default destructors. 8231ae08745Sheppo */ 8241ae08745Sheppo D2(vswp, "vsw_detach: destroying hash tables.."); 825c1c61f44Ssb155480 vsw_destroy_vlans(vswp, VSW_LOCALDEV); 826c1c61f44Ssb155480 mod_hash_destroy_hash(vswp->fdb_hashp); 827c1c61f44Ssb155480 vswp->fdb_hashp = NULL; 8281ae08745Sheppo 8291ae08745Sheppo WRITE_ENTER(&vswp->mfdbrw); 8301ae08745Sheppo mod_hash_destroy_hash(vswp->mfdb); 8311ae08745Sheppo vswp->mfdb = NULL; 8321ae08745Sheppo RW_EXIT(&vswp->mfdbrw); 8331ae08745Sheppo rw_destroy(&vswp->mfdbrw); 8341ae08745Sheppo 835f0ca1d9aSsb155480 /* free pri_types table */ 836f0ca1d9aSsb155480 if (VSW_PRI_ETH_DEFINED(vswp)) { 837f0ca1d9aSsb155480 kmem_free(vswp->pri_types, 838f0ca1d9aSsb155480 sizeof (uint16_t) * vswp->pri_num_types); 839f0ca1d9aSsb155480 (void) vio_destroy_mblks(vswp->pri_tx_vmp); 840f0ca1d9aSsb155480 } 841f0ca1d9aSsb155480 8421ae08745Sheppo ddi_remove_minor_node(dip, NULL); 8431ae08745Sheppo 8441ae08745Sheppo rw_destroy(&vswp->plist.lockrw); 8451ae08745Sheppo WRITE_ENTER(&vsw_rw); 8461ae08745Sheppo for (vswpp = &vsw_head; *vswpp; vswpp = &(*vswpp)->next) { 8471ae08745Sheppo if (*vswpp == vswp) { 8481ae08745Sheppo *vswpp = vswp->next; 8491ae08745Sheppo break; 8501ae08745Sheppo } 8511ae08745Sheppo } 8521ae08745Sheppo RW_EXIT(&vsw_rw); 8531ae08745Sheppo ddi_soft_state_free(vsw_state, instance); 8541ae08745Sheppo 8551ae08745Sheppo return (DDI_SUCCESS); 8561ae08745Sheppo } 8571ae08745Sheppo 8581ae08745Sheppo static int 8591ae08745Sheppo vsw_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 8601ae08745Sheppo { 8611ae08745Sheppo _NOTE(ARGUNUSED(dip)) 8621ae08745Sheppo 8631ae08745Sheppo vsw_t *vswp = NULL; 8641ae08745Sheppo dev_t dev = (dev_t)arg; 8651ae08745Sheppo int instance; 8661ae08745Sheppo 8671ae08745Sheppo instance = getminor(dev); 8681ae08745Sheppo 8691ae08745Sheppo switch (infocmd) { 8701ae08745Sheppo case DDI_INFO_DEVT2DEVINFO: 8711ae08745Sheppo if ((vswp = ddi_get_soft_state(vsw_state, instance)) == NULL) { 8721ae08745Sheppo *result = NULL; 8731ae08745Sheppo return (DDI_FAILURE); 8741ae08745Sheppo } 8751ae08745Sheppo *result = vswp->dip; 8761ae08745Sheppo return (DDI_SUCCESS); 8771ae08745Sheppo 8781ae08745Sheppo case DDI_INFO_DEVT2INSTANCE: 8791ae08745Sheppo *result = (void *)(uintptr_t)instance; 8801ae08745Sheppo return (DDI_SUCCESS); 8811ae08745Sheppo 8821ae08745Sheppo default: 8831ae08745Sheppo *result = NULL; 8841ae08745Sheppo return (DDI_FAILURE); 8851ae08745Sheppo } 8861ae08745Sheppo } 8871ae08745Sheppo 8881ae08745Sheppo /* 88934683adeSsg70180 * Get the value of the "vsw-phys-dev" property in the specified 89034683adeSsg70180 * node. This property is the name of the physical device that 89134683adeSsg70180 * the virtual switch will use to talk to the outside world. 89234683adeSsg70180 * 89334683adeSsg70180 * Note it is valid for this property to be NULL (but the property 89434683adeSsg70180 * itself must exist). Callers of this routine should verify that 89534683adeSsg70180 * the value returned is what they expected (i.e. either NULL or non NULL). 89634683adeSsg70180 * 89734683adeSsg70180 * On success returns value of the property in region pointed to by 89834683adeSsg70180 * the 'name' argument, and with return value of 0. Otherwise returns 1. 8991ae08745Sheppo */ 90034683adeSsg70180 static int 90134683adeSsg70180 vsw_get_md_physname(vsw_t *vswp, md_t *mdp, mde_cookie_t node, char *name) 9021ae08745Sheppo { 90334683adeSsg70180 int len = 0; 904f2b610cfSwentaoy int instance; 9051ae08745Sheppo char *physname = NULL; 9061ae08745Sheppo char *dev; 907f2b610cfSwentaoy const char *dev_name; 908f2b610cfSwentaoy char myname[MAXNAMELEN]; 909f2b610cfSwentaoy 910f2b610cfSwentaoy dev_name = ddi_driver_name(vswp->dip); 911f2b610cfSwentaoy instance = ddi_get_instance(vswp->dip); 912f2b610cfSwentaoy (void) snprintf(myname, MAXNAMELEN, "%s%d", dev_name, instance); 9131ae08745Sheppo 91434683adeSsg70180 if (md_get_prop_data(mdp, node, physdev_propname, 9151ae08745Sheppo (uint8_t **)(&physname), &len) != 0) { 91634683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to get name(s) of physical " 91734683adeSsg70180 "device(s) from MD", vswp->instance); 91834683adeSsg70180 return (1); 9191ae08745Sheppo } else if ((strlen(physname) + 1) > LIFNAMSIZ) { 92034683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: %s is too long a device name", 92134683adeSsg70180 vswp->instance, physname); 92234683adeSsg70180 return (1); 923f2b610cfSwentaoy } else if (strcmp(myname, physname) == 0) { 924f2b610cfSwentaoy /* 925f2b610cfSwentaoy * Prevent the vswitch from opening itself as the 926f2b610cfSwentaoy * network device. 927f2b610cfSwentaoy */ 928f2b610cfSwentaoy cmn_err(CE_WARN, "!vsw%d: %s is an invalid device name", 929f2b610cfSwentaoy vswp->instance, physname); 930f2b610cfSwentaoy return (1); 9311ae08745Sheppo } else { 93234683adeSsg70180 (void) strncpy(name, physname, strlen(physname) + 1); 9331ae08745Sheppo D2(vswp, "%s: using first device specified (%s)", 93434683adeSsg70180 __func__, physname); 9351ae08745Sheppo } 9361ae08745Sheppo 9371ae08745Sheppo #ifdef DEBUG 9381ae08745Sheppo /* 9391ae08745Sheppo * As a temporary measure to aid testing we check to see if there 9401ae08745Sheppo * is a vsw.conf file present. If there is we use the value of the 9411ae08745Sheppo * vsw_physname property in the file as the name of the physical 9421ae08745Sheppo * device, overriding the value from the MD. 9431ae08745Sheppo * 9441ae08745Sheppo * There may be multiple devices listed, but for the moment 9451ae08745Sheppo * we just use the first one. 9461ae08745Sheppo */ 9471ae08745Sheppo if (ddi_prop_lookup_string(DDI_DEV_T_ANY, vswp->dip, 0, 9481ae08745Sheppo "vsw_physname", &dev) == DDI_PROP_SUCCESS) { 9491ae08745Sheppo if ((strlen(dev) + 1) > LIFNAMSIZ) { 95034683adeSsg70180 cmn_err(CE_WARN, "vsw%d: %s is too long a device name", 95134683adeSsg70180 vswp->instance, dev); 95234683adeSsg70180 ddi_prop_free(dev); 95334683adeSsg70180 return (1); 9541ae08745Sheppo } else { 95534683adeSsg70180 cmn_err(CE_NOTE, "vsw%d: Using device name (%s) from " 95634683adeSsg70180 "config file", vswp->instance, dev); 9571ae08745Sheppo 95834683adeSsg70180 (void) strncpy(name, dev, strlen(dev) + 1); 9591ae08745Sheppo } 9601ae08745Sheppo 9611ae08745Sheppo ddi_prop_free(dev); 9621ae08745Sheppo } 9631ae08745Sheppo #endif 9641ae08745Sheppo 96534683adeSsg70180 return (0); 96634683adeSsg70180 } 967e1ebb9ecSlm66018 968e1ebb9ecSlm66018 /* 96934683adeSsg70180 * Read the 'vsw-switch-mode' property from the specified MD node. 97034683adeSsg70180 * 97134683adeSsg70180 * Returns 0 on success and the number of modes found in 'found', 97234683adeSsg70180 * otherwise returns 1. 973e1ebb9ecSlm66018 */ 97434683adeSsg70180 static int 97534683adeSsg70180 vsw_get_md_smodes(vsw_t *vswp, md_t *mdp, mde_cookie_t node, 97634683adeSsg70180 uint8_t *modes, int *found) 97734683adeSsg70180 { 97834683adeSsg70180 int len = 0; 97934683adeSsg70180 int smode_num = 0; 98034683adeSsg70180 char *smode = NULL; 98134683adeSsg70180 char *curr_mode = NULL; 98234683adeSsg70180 98334683adeSsg70180 D1(vswp, "%s: enter", __func__); 9841ae08745Sheppo 9851ae08745Sheppo /* 9861ae08745Sheppo * Get the switch-mode property. The modes are listed in 9871ae08745Sheppo * decreasing order of preference, i.e. prefered mode is 9881ae08745Sheppo * first item in list. 9891ae08745Sheppo */ 9901ae08745Sheppo len = 0; 99134683adeSsg70180 smode_num = 0; 99234683adeSsg70180 if (md_get_prop_data(mdp, node, smode_propname, 9931ae08745Sheppo (uint8_t **)(&smode), &len) != 0) { 9941ae08745Sheppo /* 995e1ebb9ecSlm66018 * Unable to get switch-mode property from MD, nothing 996e1ebb9ecSlm66018 * more we can do. 9971ae08745Sheppo */ 99834683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to get switch mode property" 99934683adeSsg70180 " from the MD", vswp->instance); 100034683adeSsg70180 *found = 0; 100134683adeSsg70180 return (1); 1002e1ebb9ecSlm66018 } 1003e1ebb9ecSlm66018 10041ae08745Sheppo curr_mode = smode; 10051ae08745Sheppo /* 10061ae08745Sheppo * Modes of operation: 10071ae08745Sheppo * 'switched' - layer 2 switching, underlying HW in 1008e1ebb9ecSlm66018 * programmed mode. 10091ae08745Sheppo * 'promiscuous' - layer 2 switching, underlying HW in 10101ae08745Sheppo * promiscuous mode. 10111ae08745Sheppo * 'routed' - layer 3 (i.e. IP) routing, underlying HW 10121ae08745Sheppo * in non-promiscuous mode. 10131ae08745Sheppo */ 101434683adeSsg70180 while ((curr_mode < (smode + len)) && (smode_num < NUM_SMODES)) { 10151ae08745Sheppo D2(vswp, "%s: curr_mode = [%s]", __func__, curr_mode); 1016e1ebb9ecSlm66018 if (strcmp(curr_mode, "switched") == 0) { 101734683adeSsg70180 modes[smode_num++] = VSW_LAYER2; 1018e1ebb9ecSlm66018 } else if (strcmp(curr_mode, "promiscuous") == 0) { 101934683adeSsg70180 modes[smode_num++] = VSW_LAYER2_PROMISC; 1020e1ebb9ecSlm66018 } else if (strcmp(curr_mode, "routed") == 0) { 102134683adeSsg70180 modes[smode_num++] = VSW_LAYER3; 1022e1ebb9ecSlm66018 } else { 10231ef0bbb5Snarayan DWARN(vswp, "%s: Unknown switch mode %s, " 10241ef0bbb5Snarayan "setting to default 'switched' mode", 10251ef0bbb5Snarayan __func__, curr_mode); 102634683adeSsg70180 modes[smode_num++] = VSW_LAYER2; 10271ae08745Sheppo } 10281ae08745Sheppo curr_mode += strlen(curr_mode) + 1; 10291ae08745Sheppo } 103034683adeSsg70180 *found = smode_num; 10311ae08745Sheppo 103234683adeSsg70180 D2(vswp, "%s: %d modes found", __func__, smode_num); 10331ae08745Sheppo 10341ae08745Sheppo D1(vswp, "%s: exit", __func__); 103534683adeSsg70180 103634683adeSsg70180 return (0); 10371ae08745Sheppo } 10381ae08745Sheppo 1039e1ebb9ecSlm66018 /* 10401ae08745Sheppo * Register with the MAC layer as a network device, so we 10411ae08745Sheppo * can be plumbed if necessary. 10421ae08745Sheppo */ 10431ae08745Sheppo static int 10441ae08745Sheppo vsw_mac_register(vsw_t *vswp) 10451ae08745Sheppo { 1046ba2e4443Sseb mac_register_t *macp; 1047ba2e4443Sseb int rv; 10481ae08745Sheppo 10491ae08745Sheppo D1(vswp, "%s: enter", __func__); 10501ae08745Sheppo 1051ba2e4443Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 1052ba2e4443Sseb return (EINVAL); 1053ba2e4443Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 10541ae08745Sheppo macp->m_driver = vswp; 1055ba2e4443Sseb macp->m_dip = vswp->dip; 1056ba2e4443Sseb macp->m_src_addr = (uint8_t *)&vswp->if_addr; 1057ba2e4443Sseb macp->m_callbacks = &vsw_m_callbacks; 1058ba2e4443Sseb macp->m_min_sdu = 0; 1059*7b1f684aSSriharsha Basavapatna macp->m_max_sdu = vswp->mtu; 1060c1c61f44Ssb155480 macp->m_margin = VLAN_TAGSZ; 1061ba2e4443Sseb rv = mac_register(macp, &vswp->if_mh); 1062ba2e4443Sseb mac_free(macp); 106319b65a69Ssb155480 if (rv != 0) { 106419b65a69Ssb155480 /* 106519b65a69Ssb155480 * Treat this as a non-fatal error as we may be 106619b65a69Ssb155480 * able to operate in some other mode. 106719b65a69Ssb155480 */ 106819b65a69Ssb155480 cmn_err(CE_NOTE, "!vsw%d: Unable to register as " 106919b65a69Ssb155480 "a provider with MAC layer", vswp->instance); 107019b65a69Ssb155480 return (rv); 107119b65a69Ssb155480 } 107219b65a69Ssb155480 1073ba2e4443Sseb vswp->if_state |= VSW_IF_REG; 10741ae08745Sheppo 10751ae08745Sheppo D1(vswp, "%s: exit", __func__); 10761ae08745Sheppo 10771ae08745Sheppo return (rv); 10781ae08745Sheppo } 10791ae08745Sheppo 10801ae08745Sheppo static int 10811ae08745Sheppo vsw_mac_unregister(vsw_t *vswp) 10821ae08745Sheppo { 10831ae08745Sheppo int rv = 0; 10841ae08745Sheppo 10851ae08745Sheppo D1(vswp, "%s: enter", __func__); 10861ae08745Sheppo 10871ae08745Sheppo WRITE_ENTER(&vswp->if_lockrw); 10881ae08745Sheppo 1089ba2e4443Sseb if (vswp->if_state & VSW_IF_REG) { 1090ba2e4443Sseb rv = mac_unregister(vswp->if_mh); 10911ae08745Sheppo if (rv != 0) { 10921ae08745Sheppo DWARN(vswp, "%s: unable to unregister from MAC " 10931ae08745Sheppo "framework", __func__); 10941ae08745Sheppo 10951ae08745Sheppo RW_EXIT(&vswp->if_lockrw); 10961ae08745Sheppo D1(vswp, "%s: fail exit", __func__); 10971ae08745Sheppo return (rv); 10981ae08745Sheppo } 10991ae08745Sheppo 1100ba2e4443Sseb /* mark i/f as down and unregistered */ 1101ba2e4443Sseb vswp->if_state &= ~(VSW_IF_UP | VSW_IF_REG); 11021ae08745Sheppo } 11031ae08745Sheppo RW_EXIT(&vswp->if_lockrw); 11041ae08745Sheppo 11051ae08745Sheppo D1(vswp, "%s: exit", __func__); 11061ae08745Sheppo 11071ae08745Sheppo return (rv); 11081ae08745Sheppo } 11091ae08745Sheppo 1110ba2e4443Sseb static int 1111ba2e4443Sseb vsw_m_stat(void *arg, uint_t stat, uint64_t *val) 11121ae08745Sheppo { 11131ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 11141ae08745Sheppo 11151ae08745Sheppo D1(vswp, "%s: enter", __func__); 11161ae08745Sheppo 11173c1bce15Swentaoy WRITE_ENTER(&vswp->mac_rwlock); 111834683adeSsg70180 if (vswp->mh == NULL) { 11193c1bce15Swentaoy RW_EXIT(&vswp->mac_rwlock); 1120ba2e4443Sseb return (EINVAL); 112134683adeSsg70180 } 11221ae08745Sheppo 11231ae08745Sheppo /* return stats from underlying device */ 1124ba2e4443Sseb *val = mac_stat_get(vswp->mh, stat); 112534683adeSsg70180 11263c1bce15Swentaoy RW_EXIT(&vswp->mac_rwlock); 112734683adeSsg70180 1128ba2e4443Sseb return (0); 11291ae08745Sheppo } 11301ae08745Sheppo 11311ae08745Sheppo static void 11321ae08745Sheppo vsw_m_stop(void *arg) 11331ae08745Sheppo { 11341ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 11351ae08745Sheppo 11361ae08745Sheppo D1(vswp, "%s: enter", __func__); 11371ae08745Sheppo 11381ae08745Sheppo WRITE_ENTER(&vswp->if_lockrw); 11391ae08745Sheppo vswp->if_state &= ~VSW_IF_UP; 11401ae08745Sheppo RW_EXIT(&vswp->if_lockrw); 11411ae08745Sheppo 11425f94e909Ssg70180 mutex_enter(&vswp->hw_lock); 11435f94e909Ssg70180 11445f94e909Ssg70180 (void) vsw_unset_hw(vswp, NULL, VSW_LOCALDEV); 11455f94e909Ssg70180 11465f94e909Ssg70180 if (vswp->recfg_reqd) 11475f94e909Ssg70180 vsw_reconfig_hw(vswp); 11485f94e909Ssg70180 11495f94e909Ssg70180 mutex_exit(&vswp->hw_lock); 11505f94e909Ssg70180 11511ae08745Sheppo D1(vswp, "%s: exit (state = %d)", __func__, vswp->if_state); 11521ae08745Sheppo } 11531ae08745Sheppo 11541ae08745Sheppo static int 11551ae08745Sheppo vsw_m_start(void *arg) 11561ae08745Sheppo { 11571ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 11581ae08745Sheppo 11591ae08745Sheppo D1(vswp, "%s: enter", __func__); 11601ae08745Sheppo 11611ae08745Sheppo WRITE_ENTER(&vswp->if_lockrw); 11621ae08745Sheppo 116319b65a69Ssb155480 vswp->if_state |= VSW_IF_UP; 116419b65a69Ssb155480 116519b65a69Ssb155480 if (vswp->switching_setup_done == B_FALSE) { 116619b65a69Ssb155480 /* 116719b65a69Ssb155480 * If the switching mode has not been setup yet, just 116819b65a69Ssb155480 * return. The unicast address will be programmed 116919b65a69Ssb155480 * after the physical device is successfully setup by the 117019b65a69Ssb155480 * timeout handler. 117119b65a69Ssb155480 */ 117219b65a69Ssb155480 RW_EXIT(&vswp->if_lockrw); 117319b65a69Ssb155480 return (0); 117419b65a69Ssb155480 } 117519b65a69Ssb155480 117619b65a69Ssb155480 /* if in layer2 mode, program unicast address. */ 117719b65a69Ssb155480 if (vswp->mh != NULL) { 11785f94e909Ssg70180 mutex_enter(&vswp->hw_lock); 11795f94e909Ssg70180 (void) vsw_set_hw(vswp, NULL, VSW_LOCALDEV); 11805f94e909Ssg70180 mutex_exit(&vswp->hw_lock); 118119b65a69Ssb155480 } 118219b65a69Ssb155480 118319b65a69Ssb155480 RW_EXIT(&vswp->if_lockrw); 11845f94e909Ssg70180 11851ae08745Sheppo D1(vswp, "%s: exit (state = %d)", __func__, vswp->if_state); 11861ae08745Sheppo return (0); 11871ae08745Sheppo } 11881ae08745Sheppo 11891ae08745Sheppo /* 11901ae08745Sheppo * Change the local interface address. 11915f94e909Ssg70180 * 11925f94e909Ssg70180 * Note: we don't support this entry point. The local 11935f94e909Ssg70180 * mac address of the switch can only be changed via its 11945f94e909Ssg70180 * MD node properties. 11951ae08745Sheppo */ 11961ae08745Sheppo static int 11971ae08745Sheppo vsw_m_unicst(void *arg, const uint8_t *macaddr) 11981ae08745Sheppo { 11995f94e909Ssg70180 _NOTE(ARGUNUSED(arg, macaddr)) 12001ae08745Sheppo 12015f94e909Ssg70180 return (DDI_FAILURE); 12021ae08745Sheppo } 12031ae08745Sheppo 12041ae08745Sheppo static int 12051ae08745Sheppo vsw_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 12061ae08745Sheppo { 12071ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 12081ae08745Sheppo mcst_addr_t *mcst_p = NULL; 12091ae08745Sheppo uint64_t addr = 0x0; 1210e1ebb9ecSlm66018 int i, ret = 0; 12111ae08745Sheppo 12121ae08745Sheppo D1(vswp, "%s: enter", __func__); 12131ae08745Sheppo 12141ae08745Sheppo /* 12151ae08745Sheppo * Convert address into form that can be used 12161ae08745Sheppo * as hash table key. 12171ae08745Sheppo */ 12181ae08745Sheppo for (i = 0; i < ETHERADDRL; i++) { 12191ae08745Sheppo addr = (addr << 8) | mca[i]; 12201ae08745Sheppo } 12211ae08745Sheppo 12221ae08745Sheppo D2(vswp, "%s: addr = 0x%llx", __func__, addr); 12231ae08745Sheppo 12241ae08745Sheppo if (add) { 12251ae08745Sheppo D2(vswp, "%s: adding multicast", __func__); 12261ae08745Sheppo if (vsw_add_mcst(vswp, VSW_LOCALDEV, addr, NULL) == 0) { 12271ae08745Sheppo /* 12281ae08745Sheppo * Update the list of multicast addresses 12291ae08745Sheppo * contained within the vsw_t structure to 12301ae08745Sheppo * include this new one. 12311ae08745Sheppo */ 12321ae08745Sheppo mcst_p = kmem_zalloc(sizeof (mcst_addr_t), KM_NOSLEEP); 12331ae08745Sheppo if (mcst_p == NULL) { 12341ae08745Sheppo DERR(vswp, "%s unable to alloc mem", __func__); 123519b65a69Ssb155480 (void) vsw_del_mcst(vswp, 123619b65a69Ssb155480 VSW_LOCALDEV, addr, NULL); 12371ae08745Sheppo return (1); 12381ae08745Sheppo } 12391ae08745Sheppo mcst_p->addr = addr; 124019b65a69Ssb155480 ether_copy(mca, &mcst_p->mca); 12411ae08745Sheppo 12421ae08745Sheppo /* 12431ae08745Sheppo * Call into the underlying driver to program the 12441ae08745Sheppo * address into HW. 12451ae08745Sheppo */ 12463c1bce15Swentaoy WRITE_ENTER(&vswp->mac_rwlock); 1247e1ebb9ecSlm66018 if (vswp->mh != NULL) { 1248e1ebb9ecSlm66018 ret = mac_multicst_add(vswp->mh, mca); 1249e1ebb9ecSlm66018 if (ret != 0) { 12501ef0bbb5Snarayan cmn_err(CE_NOTE, "!vsw%d: unable to " 125134683adeSsg70180 "add multicast address", 125234683adeSsg70180 vswp->instance); 12533c1bce15Swentaoy RW_EXIT(&vswp->mac_rwlock); 125419b65a69Ssb155480 (void) vsw_del_mcst(vswp, 125519b65a69Ssb155480 VSW_LOCALDEV, addr, NULL); 125619b65a69Ssb155480 kmem_free(mcst_p, sizeof (*mcst_p)); 125719b65a69Ssb155480 return (ret); 1258e1ebb9ecSlm66018 } 125919b65a69Ssb155480 mcst_p->mac_added = B_TRUE; 12601ae08745Sheppo } 12613c1bce15Swentaoy RW_EXIT(&vswp->mac_rwlock); 126219b65a69Ssb155480 126319b65a69Ssb155480 mutex_enter(&vswp->mca_lock); 126419b65a69Ssb155480 mcst_p->nextp = vswp->mcap; 126519b65a69Ssb155480 vswp->mcap = mcst_p; 126619b65a69Ssb155480 mutex_exit(&vswp->mca_lock); 12671ae08745Sheppo } else { 12681ef0bbb5Snarayan cmn_err(CE_NOTE, "!vsw%d: unable to add multicast " 126934683adeSsg70180 "address", vswp->instance); 1270e1ebb9ecSlm66018 } 1271e1ebb9ecSlm66018 return (ret); 1272e1ebb9ecSlm66018 } 1273e1ebb9ecSlm66018 12741ae08745Sheppo D2(vswp, "%s: removing multicast", __func__); 12751ae08745Sheppo /* 12761ae08745Sheppo * Remove the address from the hash table.. 12771ae08745Sheppo */ 12781ae08745Sheppo if (vsw_del_mcst(vswp, VSW_LOCALDEV, addr, NULL) == 0) { 12791ae08745Sheppo 12801ae08745Sheppo /* 12811ae08745Sheppo * ..and then from the list maintained in the 12821ae08745Sheppo * vsw_t structure. 12831ae08745Sheppo */ 128419b65a69Ssb155480 mcst_p = vsw_del_addr(VSW_LOCALDEV, vswp, addr); 128519b65a69Ssb155480 ASSERT(mcst_p != NULL); 12861ae08745Sheppo 12873c1bce15Swentaoy WRITE_ENTER(&vswp->mac_rwlock); 128819b65a69Ssb155480 if (vswp->mh != NULL && mcst_p->mac_added) { 12891ae08745Sheppo (void) mac_multicst_remove(vswp->mh, mca); 129019b65a69Ssb155480 mcst_p->mac_added = B_FALSE; 129119b65a69Ssb155480 } 12923c1bce15Swentaoy RW_EXIT(&vswp->mac_rwlock); 129319b65a69Ssb155480 kmem_free(mcst_p, sizeof (*mcst_p)); 12941ae08745Sheppo } 12951ae08745Sheppo 12961ae08745Sheppo D1(vswp, "%s: exit", __func__); 12971ae08745Sheppo 12981ae08745Sheppo return (0); 12991ae08745Sheppo } 13001ae08745Sheppo 13011ae08745Sheppo static int 13021ae08745Sheppo vsw_m_promisc(void *arg, boolean_t on) 13031ae08745Sheppo { 13041ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 13051ae08745Sheppo 13061ae08745Sheppo D1(vswp, "%s: enter", __func__); 13071ae08745Sheppo 13081ae08745Sheppo WRITE_ENTER(&vswp->if_lockrw); 13091ae08745Sheppo if (on) 13101ae08745Sheppo vswp->if_state |= VSW_IF_PROMISC; 13111ae08745Sheppo else 13121ae08745Sheppo vswp->if_state &= ~VSW_IF_PROMISC; 13131ae08745Sheppo RW_EXIT(&vswp->if_lockrw); 13141ae08745Sheppo 13151ae08745Sheppo D1(vswp, "%s: exit", __func__); 13161ae08745Sheppo 13171ae08745Sheppo return (0); 13181ae08745Sheppo } 13191ae08745Sheppo 13201ae08745Sheppo static mblk_t * 13211ae08745Sheppo vsw_m_tx(void *arg, mblk_t *mp) 13221ae08745Sheppo { 13231ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 13241ae08745Sheppo 13251ae08745Sheppo D1(vswp, "%s: enter", __func__); 13261ae08745Sheppo 1327c1c61f44Ssb155480 mp = vsw_vlan_frame_pretag(vswp, VSW_LOCALDEV, mp); 1328c1c61f44Ssb155480 1329c1c61f44Ssb155480 if (mp == NULL) { 1330c1c61f44Ssb155480 return (NULL); 1331c1c61f44Ssb155480 } 1332c1c61f44Ssb155480 133334683adeSsg70180 vswp->vsw_switch_frame(vswp, mp, VSW_LOCALDEV, NULL, NULL); 13341ae08745Sheppo 13351ae08745Sheppo D1(vswp, "%s: exit", __func__); 13361ae08745Sheppo 13371ae08745Sheppo return (NULL); 13381ae08745Sheppo } 13391ae08745Sheppo 13401ae08745Sheppo /* 13411ae08745Sheppo * Register for machine description (MD) updates. 134234683adeSsg70180 * 134334683adeSsg70180 * Returns 0 on success, 1 on failure. 13441ae08745Sheppo */ 134534683adeSsg70180 static int 13461ae08745Sheppo vsw_mdeg_register(vsw_t *vswp) 13471ae08745Sheppo { 13481ae08745Sheppo mdeg_prop_spec_t *pspecp; 13491ae08745Sheppo mdeg_node_spec_t *inst_specp; 135034683adeSsg70180 mdeg_handle_t mdeg_hdl, mdeg_port_hdl; 13511ae08745Sheppo size_t templatesz; 135219b65a69Ssb155480 int rv; 13531ae08745Sheppo 13541ae08745Sheppo D1(vswp, "%s: enter", __func__); 13551ae08745Sheppo 135634683adeSsg70180 /* 13571ae08745Sheppo * Allocate and initialize a per-instance copy 13581ae08745Sheppo * of the global property spec array that will 13591ae08745Sheppo * uniquely identify this vsw instance. 13601ae08745Sheppo */ 13611ae08745Sheppo templatesz = sizeof (vsw_prop_template); 13621ae08745Sheppo pspecp = kmem_zalloc(templatesz, KM_SLEEP); 13631ae08745Sheppo 13641ae08745Sheppo bcopy(vsw_prop_template, pspecp, templatesz); 13651ae08745Sheppo 136619b65a69Ssb155480 VSW_SET_MDEG_PROP_INST(pspecp, vswp->regprop); 13671ae08745Sheppo 13681ae08745Sheppo /* initialize the complete prop spec structure */ 13691ae08745Sheppo inst_specp = kmem_zalloc(sizeof (mdeg_node_spec_t), KM_SLEEP); 13701ae08745Sheppo inst_specp->namep = "virtual-device"; 13711ae08745Sheppo inst_specp->specp = pspecp; 13721ae08745Sheppo 137319b65a69Ssb155480 D2(vswp, "%s: instance %d registering with mdeg", __func__, 137419b65a69Ssb155480 vswp->regprop); 137534683adeSsg70180 /* 137634683adeSsg70180 * Register an interest in 'virtual-device' nodes with a 137734683adeSsg70180 * 'name' property of 'virtual-network-switch' 137834683adeSsg70180 */ 137934683adeSsg70180 rv = mdeg_register(inst_specp, &vdev_match, vsw_mdeg_cb, 13801ae08745Sheppo (void *)vswp, &mdeg_hdl); 138134683adeSsg70180 if (rv != MDEG_SUCCESS) { 138234683adeSsg70180 DERR(vswp, "%s: mdeg_register failed (%d) for vsw node", 138334683adeSsg70180 __func__, rv); 138434683adeSsg70180 goto mdeg_reg_fail; 138534683adeSsg70180 } 13861ae08745Sheppo 138734683adeSsg70180 /* 138834683adeSsg70180 * Register an interest in 'vsw-port' nodes. 138934683adeSsg70180 */ 139034683adeSsg70180 rv = mdeg_register(inst_specp, &vport_match, vsw_port_mdeg_cb, 139134683adeSsg70180 (void *)vswp, &mdeg_port_hdl); 13921ae08745Sheppo if (rv != MDEG_SUCCESS) { 13931ae08745Sheppo DERR(vswp, "%s: mdeg_register failed (%d)\n", __func__, rv); 139434683adeSsg70180 (void) mdeg_unregister(mdeg_hdl); 139534683adeSsg70180 goto mdeg_reg_fail; 13961ae08745Sheppo } 13971ae08745Sheppo 13981ae08745Sheppo /* save off data that will be needed later */ 13991ae08745Sheppo vswp->inst_spec = inst_specp; 14001ae08745Sheppo vswp->mdeg_hdl = mdeg_hdl; 140134683adeSsg70180 vswp->mdeg_port_hdl = mdeg_port_hdl; 14021ae08745Sheppo 14031ae08745Sheppo D1(vswp, "%s: exit", __func__); 140434683adeSsg70180 return (0); 140534683adeSsg70180 140634683adeSsg70180 mdeg_reg_fail: 140734683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to register MDEG callbacks", 140834683adeSsg70180 vswp->instance); 140934683adeSsg70180 kmem_free(pspecp, templatesz); 141034683adeSsg70180 kmem_free(inst_specp, sizeof (mdeg_node_spec_t)); 141134683adeSsg70180 141234683adeSsg70180 vswp->mdeg_hdl = NULL; 141334683adeSsg70180 vswp->mdeg_port_hdl = NULL; 141434683adeSsg70180 141534683adeSsg70180 return (1); 14161ae08745Sheppo } 14171ae08745Sheppo 14181ae08745Sheppo static void 14191ae08745Sheppo vsw_mdeg_unregister(vsw_t *vswp) 14201ae08745Sheppo { 14211ae08745Sheppo D1(vswp, "vsw_mdeg_unregister: enter"); 14221ae08745Sheppo 142334683adeSsg70180 if (vswp->mdeg_hdl != NULL) 14241ae08745Sheppo (void) mdeg_unregister(vswp->mdeg_hdl); 14251ae08745Sheppo 142634683adeSsg70180 if (vswp->mdeg_port_hdl != NULL) 142734683adeSsg70180 (void) mdeg_unregister(vswp->mdeg_port_hdl); 142834683adeSsg70180 142934683adeSsg70180 if (vswp->inst_spec != NULL) { 14301ae08745Sheppo if (vswp->inst_spec->specp != NULL) { 14311ae08745Sheppo (void) kmem_free(vswp->inst_spec->specp, 14321ae08745Sheppo sizeof (vsw_prop_template)); 14331ae08745Sheppo vswp->inst_spec->specp = NULL; 14341ae08745Sheppo } 14351ae08745Sheppo 1436205eeb1aSlm66018 (void) kmem_free(vswp->inst_spec, sizeof (mdeg_node_spec_t)); 14371ae08745Sheppo vswp->inst_spec = NULL; 14381ae08745Sheppo } 14391ae08745Sheppo 14401ae08745Sheppo D1(vswp, "vsw_mdeg_unregister: exit"); 14411ae08745Sheppo } 14421ae08745Sheppo 144334683adeSsg70180 /* 144434683adeSsg70180 * Mdeg callback invoked for the vsw node itself. 144534683adeSsg70180 */ 14461ae08745Sheppo static int 14471ae08745Sheppo vsw_mdeg_cb(void *cb_argp, mdeg_result_t *resp) 14481ae08745Sheppo { 14491ae08745Sheppo vsw_t *vswp; 14501ae08745Sheppo md_t *mdp; 14511ae08745Sheppo mde_cookie_t node; 14521ae08745Sheppo uint64_t inst; 145334683adeSsg70180 char *node_name = NULL; 14541ae08745Sheppo 14551ae08745Sheppo if (resp == NULL) 14561ae08745Sheppo return (MDEG_FAILURE); 14571ae08745Sheppo 14581ae08745Sheppo vswp = (vsw_t *)cb_argp; 14591ae08745Sheppo 146034683adeSsg70180 D1(vswp, "%s: added %d : removed %d : curr matched %d" 146134683adeSsg70180 " : prev matched %d", __func__, resp->added.nelem, 146234683adeSsg70180 resp->removed.nelem, resp->match_curr.nelem, 146334683adeSsg70180 resp->match_prev.nelem); 146434683adeSsg70180 146534683adeSsg70180 /* 146619b65a69Ssb155480 * We get an initial callback for this node as 'added' 146719b65a69Ssb155480 * after registering with mdeg. Note that we would have 146819b65a69Ssb155480 * already gathered information about this vsw node by 146919b65a69Ssb155480 * walking MD earlier during attach (in vsw_read_mdprops()). 147019b65a69Ssb155480 * So, there is a window where the properties of this 147119b65a69Ssb155480 * node might have changed when we get this initial 'added' 147219b65a69Ssb155480 * callback. We handle this as if an update occured 147319b65a69Ssb155480 * and invoke the same function which handles updates to 147419b65a69Ssb155480 * the properties of this vsw-node if any. 147519b65a69Ssb155480 * 147634683adeSsg70180 * A non-zero 'match' value indicates that the MD has been 147719b65a69Ssb155480 * updated and that a virtual-network-switch node is 147819b65a69Ssb155480 * present which may or may not have been updated. It is 147919b65a69Ssb155480 * up to the clients to examine their own nodes and 148019b65a69Ssb155480 * determine if they have changed. 148134683adeSsg70180 */ 148219b65a69Ssb155480 if (resp->added.nelem != 0) { 148334683adeSsg70180 148419b65a69Ssb155480 if (resp->added.nelem != 1) { 148519b65a69Ssb155480 cmn_err(CE_NOTE, "!vsw%d: number of nodes added " 148619b65a69Ssb155480 "invalid: %d\n", vswp->instance, resp->added.nelem); 148719b65a69Ssb155480 return (MDEG_FAILURE); 148819b65a69Ssb155480 } 148919b65a69Ssb155480 149019b65a69Ssb155480 mdp = resp->added.mdp; 149119b65a69Ssb155480 node = resp->added.mdep[0]; 149219b65a69Ssb155480 149319b65a69Ssb155480 } else if (resp->match_curr.nelem != 0) { 149419b65a69Ssb155480 149519b65a69Ssb155480 if (resp->match_curr.nelem != 1) { 149619b65a69Ssb155480 cmn_err(CE_NOTE, "!vsw%d: number of nodes updated " 149719b65a69Ssb155480 "invalid: %d\n", vswp->instance, 149819b65a69Ssb155480 resp->match_curr.nelem); 149919b65a69Ssb155480 return (MDEG_FAILURE); 150019b65a69Ssb155480 } 150119b65a69Ssb155480 150219b65a69Ssb155480 mdp = resp->match_curr.mdp; 150319b65a69Ssb155480 node = resp->match_curr.mdep[0]; 150419b65a69Ssb155480 150519b65a69Ssb155480 } else { 150619b65a69Ssb155480 return (MDEG_FAILURE); 150719b65a69Ssb155480 } 150819b65a69Ssb155480 150919b65a69Ssb155480 /* Validate name and instance */ 151034683adeSsg70180 if (md_get_prop_str(mdp, node, "name", &node_name) != 0) { 151119b65a69Ssb155480 DERR(vswp, "%s: unable to get node name\n", __func__); 151219b65a69Ssb155480 return (MDEG_FAILURE); 151319b65a69Ssb155480 } 151419b65a69Ssb155480 151519b65a69Ssb155480 /* is this a virtual-network-switch? */ 151619b65a69Ssb155480 if (strcmp(node_name, vsw_propname) != 0) { 151719b65a69Ssb155480 DERR(vswp, "%s: Invalid node name: %s\n", 151819b65a69Ssb155480 __func__, node_name); 151919b65a69Ssb155480 return (MDEG_FAILURE); 152034683adeSsg70180 } 152134683adeSsg70180 152234683adeSsg70180 if (md_get_prop_val(mdp, node, "cfg-handle", &inst)) { 152319b65a69Ssb155480 DERR(vswp, "%s: prop(cfg-handle) not found\n", 152419b65a69Ssb155480 __func__); 152519b65a69Ssb155480 return (MDEG_FAILURE); 152634683adeSsg70180 } 152734683adeSsg70180 152819b65a69Ssb155480 /* is this the right instance of vsw? */ 152919b65a69Ssb155480 if (inst != vswp->regprop) { 153019b65a69Ssb155480 DERR(vswp, "%s: Invalid cfg-handle: %lx\n", 153119b65a69Ssb155480 __func__, inst); 153219b65a69Ssb155480 return (MDEG_FAILURE); 153319b65a69Ssb155480 } 153434683adeSsg70180 153534683adeSsg70180 vsw_update_md_prop(vswp, mdp, node); 153634683adeSsg70180 153734683adeSsg70180 return (MDEG_SUCCESS); 153834683adeSsg70180 } 153934683adeSsg70180 154034683adeSsg70180 /* 154134683adeSsg70180 * Mdeg callback invoked for changes to the vsw-port nodes 154234683adeSsg70180 * under the vsw node. 154334683adeSsg70180 */ 154434683adeSsg70180 static int 154534683adeSsg70180 vsw_port_mdeg_cb(void *cb_argp, mdeg_result_t *resp) 154634683adeSsg70180 { 154734683adeSsg70180 vsw_t *vswp; 154834683adeSsg70180 int idx; 154934683adeSsg70180 md_t *mdp; 155034683adeSsg70180 mde_cookie_t node; 155134683adeSsg70180 uint64_t inst; 15521ef0bbb5Snarayan int rv; 155334683adeSsg70180 155434683adeSsg70180 if ((resp == NULL) || (cb_argp == NULL)) 155534683adeSsg70180 return (MDEG_FAILURE); 155634683adeSsg70180 155734683adeSsg70180 vswp = (vsw_t *)cb_argp; 155834683adeSsg70180 155934683adeSsg70180 D2(vswp, "%s: added %d : removed %d : curr matched %d" 156034683adeSsg70180 " : prev matched %d", __func__, resp->added.nelem, 156134683adeSsg70180 resp->removed.nelem, resp->match_curr.nelem, 15621ae08745Sheppo resp->match_prev.nelem); 15631ae08745Sheppo 15641ae08745Sheppo /* process added ports */ 15651ae08745Sheppo for (idx = 0; idx < resp->added.nelem; idx++) { 15661ae08745Sheppo mdp = resp->added.mdp; 15671ae08745Sheppo node = resp->added.mdep[idx]; 15681ae08745Sheppo 15691ae08745Sheppo D2(vswp, "%s: adding node(%d) 0x%lx", __func__, idx, node); 15701ae08745Sheppo 15711ef0bbb5Snarayan if ((rv = vsw_port_add(vswp, mdp, &node)) != 0) { 157234683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to add new port " 15731ef0bbb5Snarayan "(0x%lx), err=%d", vswp->instance, node, rv); 15741ae08745Sheppo } 15751ae08745Sheppo } 15761ae08745Sheppo 15771ae08745Sheppo /* process removed ports */ 15781ae08745Sheppo for (idx = 0; idx < resp->removed.nelem; idx++) { 15791ae08745Sheppo mdp = resp->removed.mdp; 15801ae08745Sheppo node = resp->removed.mdep[idx]; 15811ae08745Sheppo 15821ae08745Sheppo if (md_get_prop_val(mdp, node, id_propname, &inst)) { 158334683adeSsg70180 DERR(vswp, "%s: prop(%s) not found in port(%d)", 15841ae08745Sheppo __func__, id_propname, idx); 15851ae08745Sheppo continue; 15861ae08745Sheppo } 15871ae08745Sheppo 15881ae08745Sheppo D2(vswp, "%s: removing node(%d) 0x%lx", __func__, idx, node); 15891ae08745Sheppo 15901ae08745Sheppo if (vsw_port_detach(vswp, inst) != 0) { 159134683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to remove port %ld", 159234683adeSsg70180 vswp->instance, inst); 15931ae08745Sheppo } 15941ae08745Sheppo } 15951ae08745Sheppo 1596c1c61f44Ssb155480 for (idx = 0; idx < resp->match_curr.nelem; idx++) { 1597c1c61f44Ssb155480 (void) vsw_port_update(vswp, resp->match_curr.mdp, 1598c1c61f44Ssb155480 resp->match_curr.mdep[idx], 1599c1c61f44Ssb155480 resp->match_prev.mdp, 1600c1c61f44Ssb155480 resp->match_prev.mdep[idx]); 1601c1c61f44Ssb155480 } 16021ae08745Sheppo 16031ae08745Sheppo D1(vswp, "%s: exit", __func__); 16041ae08745Sheppo 16051ae08745Sheppo return (MDEG_SUCCESS); 16061ae08745Sheppo } 16071ae08745Sheppo 16081ae08745Sheppo /* 160919b65a69Ssb155480 * Scan the machine description for this instance of vsw 161019b65a69Ssb155480 * and read its properties. Called only from vsw_attach(). 161119b65a69Ssb155480 * Returns: 0 on success, 1 on failure. 161219b65a69Ssb155480 */ 161319b65a69Ssb155480 static int 161419b65a69Ssb155480 vsw_read_mdprops(vsw_t *vswp) 161519b65a69Ssb155480 { 161619b65a69Ssb155480 md_t *mdp = NULL; 161719b65a69Ssb155480 mde_cookie_t rootnode; 161819b65a69Ssb155480 mde_cookie_t *listp = NULL; 161919b65a69Ssb155480 uint64_t inst; 162019b65a69Ssb155480 uint64_t cfgh; 162119b65a69Ssb155480 char *name; 162219b65a69Ssb155480 int rv = 1; 162319b65a69Ssb155480 int num_nodes = 0; 162419b65a69Ssb155480 int num_devs = 0; 162519b65a69Ssb155480 int listsz = 0; 162619b65a69Ssb155480 int i; 162719b65a69Ssb155480 162819b65a69Ssb155480 /* 162919b65a69Ssb155480 * In each 'virtual-device' node in the MD there is a 163019b65a69Ssb155480 * 'cfg-handle' property which is the MD's concept of 163119b65a69Ssb155480 * an instance number (this may be completely different from 163219b65a69Ssb155480 * the device drivers instance #). OBP reads that value and 163319b65a69Ssb155480 * stores it in the 'reg' property of the appropriate node in 163419b65a69Ssb155480 * the device tree. We first read this reg property and use this 163519b65a69Ssb155480 * to compare against the 'cfg-handle' property of vsw nodes 163619b65a69Ssb155480 * in MD to get to this specific vsw instance and then read 163719b65a69Ssb155480 * other properties that we are interested in. 163819b65a69Ssb155480 * We also cache the value of 'reg' property and use it later 163919b65a69Ssb155480 * to register callbacks with mdeg (see vsw_mdeg_register()) 164019b65a69Ssb155480 */ 164119b65a69Ssb155480 inst = ddi_prop_get_int(DDI_DEV_T_ANY, vswp->dip, 164219b65a69Ssb155480 DDI_PROP_DONTPASS, reg_propname, -1); 164319b65a69Ssb155480 if (inst == -1) { 164419b65a69Ssb155480 cmn_err(CE_NOTE, "!vsw%d: Unable to read %s property from " 164519b65a69Ssb155480 "OBP device tree", vswp->instance, reg_propname); 164619b65a69Ssb155480 return (rv); 164719b65a69Ssb155480 } 164819b65a69Ssb155480 164919b65a69Ssb155480 vswp->regprop = inst; 165019b65a69Ssb155480 165119b65a69Ssb155480 if ((mdp = md_get_handle()) == NULL) { 165219b65a69Ssb155480 DWARN(vswp, "%s: cannot init MD\n", __func__); 165319b65a69Ssb155480 return (rv); 165419b65a69Ssb155480 } 165519b65a69Ssb155480 165619b65a69Ssb155480 num_nodes = md_node_count(mdp); 165719b65a69Ssb155480 ASSERT(num_nodes > 0); 165819b65a69Ssb155480 165919b65a69Ssb155480 listsz = num_nodes * sizeof (mde_cookie_t); 166019b65a69Ssb155480 listp = (mde_cookie_t *)kmem_zalloc(listsz, KM_SLEEP); 166119b65a69Ssb155480 166219b65a69Ssb155480 rootnode = md_root_node(mdp); 166319b65a69Ssb155480 166419b65a69Ssb155480 /* search for all "virtual_device" nodes */ 166519b65a69Ssb155480 num_devs = md_scan_dag(mdp, rootnode, 166619b65a69Ssb155480 md_find_name(mdp, vdev_propname), 166719b65a69Ssb155480 md_find_name(mdp, "fwd"), listp); 166819b65a69Ssb155480 if (num_devs <= 0) { 166919b65a69Ssb155480 DWARN(vswp, "%s: invalid num_devs:%d\n", __func__, num_devs); 167019b65a69Ssb155480 goto vsw_readmd_exit; 167119b65a69Ssb155480 } 167219b65a69Ssb155480 167319b65a69Ssb155480 /* 167419b65a69Ssb155480 * Now loop through the list of virtual-devices looking for 167519b65a69Ssb155480 * devices with name "virtual-network-switch" and for each 167619b65a69Ssb155480 * such device compare its instance with what we have from 167719b65a69Ssb155480 * the 'reg' property to find the right node in MD and then 167819b65a69Ssb155480 * read all its properties. 167919b65a69Ssb155480 */ 168019b65a69Ssb155480 for (i = 0; i < num_devs; i++) { 168119b65a69Ssb155480 168219b65a69Ssb155480 if (md_get_prop_str(mdp, listp[i], "name", &name) != 0) { 168319b65a69Ssb155480 DWARN(vswp, "%s: name property not found\n", 168419b65a69Ssb155480 __func__); 168519b65a69Ssb155480 goto vsw_readmd_exit; 168619b65a69Ssb155480 } 168719b65a69Ssb155480 168819b65a69Ssb155480 /* is this a virtual-network-switch? */ 168919b65a69Ssb155480 if (strcmp(name, vsw_propname) != 0) 169019b65a69Ssb155480 continue; 169119b65a69Ssb155480 169219b65a69Ssb155480 if (md_get_prop_val(mdp, listp[i], "cfg-handle", &cfgh) != 0) { 169319b65a69Ssb155480 DWARN(vswp, "%s: cfg-handle property not found\n", 169419b65a69Ssb155480 __func__); 169519b65a69Ssb155480 goto vsw_readmd_exit; 169619b65a69Ssb155480 } 169719b65a69Ssb155480 169819b65a69Ssb155480 /* is this the required instance of vsw? */ 169919b65a69Ssb155480 if (inst != cfgh) 170019b65a69Ssb155480 continue; 170119b65a69Ssb155480 170219b65a69Ssb155480 /* now read all properties of this vsw instance */ 170319b65a69Ssb155480 rv = vsw_get_initial_md_properties(vswp, mdp, listp[i]); 170419b65a69Ssb155480 break; 170519b65a69Ssb155480 } 170619b65a69Ssb155480 170719b65a69Ssb155480 vsw_readmd_exit: 170819b65a69Ssb155480 170919b65a69Ssb155480 kmem_free(listp, listsz); 171019b65a69Ssb155480 (void) md_fini_handle(mdp); 171119b65a69Ssb155480 return (rv); 171219b65a69Ssb155480 } 171319b65a69Ssb155480 171419b65a69Ssb155480 /* 171534683adeSsg70180 * Read the initial start-of-day values from the specified MD node. 171634683adeSsg70180 */ 171719b65a69Ssb155480 static int 171834683adeSsg70180 vsw_get_initial_md_properties(vsw_t *vswp, md_t *mdp, mde_cookie_t node) 171934683adeSsg70180 { 172034683adeSsg70180 int i; 172134683adeSsg70180 uint64_t macaddr = 0; 172234683adeSsg70180 172334683adeSsg70180 D1(vswp, "%s: enter", __func__); 172434683adeSsg70180 172519b65a69Ssb155480 if (vsw_get_md_physname(vswp, mdp, node, vswp->physname) != 0) { 172619b65a69Ssb155480 return (1); 172734683adeSsg70180 } 172834683adeSsg70180 172934683adeSsg70180 /* mac address for vswitch device itself */ 173034683adeSsg70180 if (md_get_prop_val(mdp, node, macaddr_propname, &macaddr) != 0) { 173134683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to get MAC address from MD", 173234683adeSsg70180 vswp->instance); 173319b65a69Ssb155480 return (1); 173419b65a69Ssb155480 } 173534683adeSsg70180 173619b65a69Ssb155480 vsw_save_lmacaddr(vswp, macaddr); 173734683adeSsg70180 1738205eeb1aSlm66018 if (vsw_get_md_smodes(vswp, mdp, node, vswp->smode, &vswp->smode_num)) { 17391ef0bbb5Snarayan DWARN(vswp, "%s: Unable to read %s property from MD, " 17401ef0bbb5Snarayan "defaulting to 'switched' mode", 17411ef0bbb5Snarayan __func__, smode_propname); 174234683adeSsg70180 174334683adeSsg70180 for (i = 0; i < NUM_SMODES; i++) 174434683adeSsg70180 vswp->smode[i] = VSW_LAYER2; 174534683adeSsg70180 174634683adeSsg70180 vswp->smode_num = NUM_SMODES; 174734683adeSsg70180 } else { 174834683adeSsg70180 ASSERT(vswp->smode_num != 0); 174934683adeSsg70180 } 175034683adeSsg70180 1751*7b1f684aSSriharsha Basavapatna /* read mtu */ 1752*7b1f684aSSriharsha Basavapatna vsw_mtu_read(vswp, mdp, node, &vswp->mtu); 1753*7b1f684aSSriharsha Basavapatna if (vswp->mtu < ETHERMTU || vswp->mtu > VNET_MAX_MTU) { 1754*7b1f684aSSriharsha Basavapatna vswp->mtu = ETHERMTU; 1755*7b1f684aSSriharsha Basavapatna } 1756*7b1f684aSSriharsha Basavapatna vswp->max_frame_size = vswp->mtu + sizeof (struct ether_header) + 1757*7b1f684aSSriharsha Basavapatna VLAN_TAGSZ; 1758*7b1f684aSSriharsha Basavapatna 1759c1c61f44Ssb155480 /* read vlan id properties of this vsw instance */ 1760c1c61f44Ssb155480 vsw_vlan_read_ids(vswp, VSW_LOCALDEV, mdp, node, &vswp->pvid, 1761c1c61f44Ssb155480 &vswp->vids, &vswp->nvids, &vswp->default_vlan_id); 1762c1c61f44Ssb155480 1763c1c61f44Ssb155480 /* read priority-ether-types */ 1764f0ca1d9aSsb155480 vsw_read_pri_eth_types(vswp, mdp, node); 1765f0ca1d9aSsb155480 176634683adeSsg70180 D1(vswp, "%s: exit", __func__); 176719b65a69Ssb155480 return (0); 176834683adeSsg70180 } 176934683adeSsg70180 177034683adeSsg70180 /* 1771c1c61f44Ssb155480 * Read vlan id properties of the given MD node. 1772c1c61f44Ssb155480 * Arguments: 1773c1c61f44Ssb155480 * arg: device argument(vsw device or a port) 1774c1c61f44Ssb155480 * type: type of arg; VSW_LOCALDEV(vsw device) or VSW_VNETPORT(port) 1775c1c61f44Ssb155480 * mdp: machine description 1776c1c61f44Ssb155480 * node: md node cookie 1777c1c61f44Ssb155480 * 1778c1c61f44Ssb155480 * Returns: 1779c1c61f44Ssb155480 * pvidp: port-vlan-id of the node 1780c1c61f44Ssb155480 * vidspp: list of vlan-ids of the node 1781c1c61f44Ssb155480 * nvidsp: # of vlan-ids in the list 1782c1c61f44Ssb155480 * default_idp: default-vlan-id of the node(if node is vsw device) 1783c1c61f44Ssb155480 */ 1784c1c61f44Ssb155480 static void 1785c1c61f44Ssb155480 vsw_vlan_read_ids(void *arg, int type, md_t *mdp, mde_cookie_t node, 1786c1c61f44Ssb155480 uint16_t *pvidp, uint16_t **vidspp, uint16_t *nvidsp, 1787c1c61f44Ssb155480 uint16_t *default_idp) 1788c1c61f44Ssb155480 { 1789c1c61f44Ssb155480 vsw_t *vswp; 1790c1c61f44Ssb155480 vsw_port_t *portp; 1791c1c61f44Ssb155480 char *pvid_propname; 1792c1c61f44Ssb155480 char *vid_propname; 1793c1c61f44Ssb155480 uint_t nvids = 0; 1794c1c61f44Ssb155480 uint32_t vids_size; 1795c1c61f44Ssb155480 int rv; 1796c1c61f44Ssb155480 int i; 1797c1c61f44Ssb155480 uint64_t *data; 1798c1c61f44Ssb155480 uint64_t val; 1799c1c61f44Ssb155480 int size; 1800c1c61f44Ssb155480 int inst; 1801c1c61f44Ssb155480 1802c1c61f44Ssb155480 if (type == VSW_LOCALDEV) { 1803c1c61f44Ssb155480 1804c1c61f44Ssb155480 vswp = (vsw_t *)arg; 1805c1c61f44Ssb155480 pvid_propname = vsw_pvid_propname; 1806c1c61f44Ssb155480 vid_propname = vsw_vid_propname; 1807c1c61f44Ssb155480 inst = vswp->instance; 1808c1c61f44Ssb155480 1809c1c61f44Ssb155480 } else if (type == VSW_VNETPORT) { 1810c1c61f44Ssb155480 1811c1c61f44Ssb155480 portp = (vsw_port_t *)arg; 1812c1c61f44Ssb155480 vswp = portp->p_vswp; 1813c1c61f44Ssb155480 pvid_propname = port_pvid_propname; 1814c1c61f44Ssb155480 vid_propname = port_vid_propname; 1815c1c61f44Ssb155480 inst = portp->p_instance; 1816c1c61f44Ssb155480 1817c1c61f44Ssb155480 } else { 1818c1c61f44Ssb155480 return; 1819c1c61f44Ssb155480 } 1820c1c61f44Ssb155480 1821c1c61f44Ssb155480 if (type == VSW_LOCALDEV && default_idp != NULL) { 1822c1c61f44Ssb155480 rv = md_get_prop_val(mdp, node, vsw_dvid_propname, &val); 1823c1c61f44Ssb155480 if (rv != 0) { 1824c1c61f44Ssb155480 DWARN(vswp, "%s: prop(%s) not found", __func__, 1825c1c61f44Ssb155480 vsw_dvid_propname); 1826c1c61f44Ssb155480 1827c1c61f44Ssb155480 *default_idp = vsw_default_vlan_id; 1828c1c61f44Ssb155480 } else { 1829c1c61f44Ssb155480 *default_idp = val & 0xFFF; 1830c1c61f44Ssb155480 D2(vswp, "%s: %s(%d): (%d)\n", __func__, 1831c1c61f44Ssb155480 vsw_dvid_propname, inst, *default_idp); 1832c1c61f44Ssb155480 } 1833c1c61f44Ssb155480 } 1834c1c61f44Ssb155480 1835c1c61f44Ssb155480 rv = md_get_prop_val(mdp, node, pvid_propname, &val); 1836c1c61f44Ssb155480 if (rv != 0) { 1837c1c61f44Ssb155480 DWARN(vswp, "%s: prop(%s) not found", __func__, pvid_propname); 1838c1c61f44Ssb155480 *pvidp = vsw_default_vlan_id; 1839c1c61f44Ssb155480 } else { 1840c1c61f44Ssb155480 1841c1c61f44Ssb155480 *pvidp = val & 0xFFF; 1842c1c61f44Ssb155480 D2(vswp, "%s: %s(%d): (%d)\n", __func__, 1843c1c61f44Ssb155480 pvid_propname, inst, *pvidp); 1844c1c61f44Ssb155480 } 1845c1c61f44Ssb155480 1846c1c61f44Ssb155480 rv = md_get_prop_data(mdp, node, vid_propname, (uint8_t **)&data, 1847c1c61f44Ssb155480 &size); 1848c1c61f44Ssb155480 if (rv != 0) { 1849c1c61f44Ssb155480 D2(vswp, "%s: prop(%s) not found", __func__, vid_propname); 1850c1c61f44Ssb155480 size = 0; 1851c1c61f44Ssb155480 } else { 1852c1c61f44Ssb155480 size /= sizeof (uint64_t); 1853c1c61f44Ssb155480 } 1854c1c61f44Ssb155480 nvids = size; 1855c1c61f44Ssb155480 1856c1c61f44Ssb155480 if (nvids != 0) { 1857c1c61f44Ssb155480 D2(vswp, "%s: %s(%d): ", __func__, vid_propname, inst); 1858c1c61f44Ssb155480 vids_size = sizeof (uint16_t) * nvids; 1859c1c61f44Ssb155480 *vidspp = kmem_zalloc(vids_size, KM_SLEEP); 1860c1c61f44Ssb155480 for (i = 0; i < nvids; i++) { 1861c1c61f44Ssb155480 (*vidspp)[i] = data[i] & 0xFFFF; 1862c1c61f44Ssb155480 D2(vswp, " %d ", (*vidspp)[i]); 1863c1c61f44Ssb155480 } 1864c1c61f44Ssb155480 D2(vswp, "\n"); 1865c1c61f44Ssb155480 } 1866c1c61f44Ssb155480 1867c1c61f44Ssb155480 *nvidsp = nvids; 1868c1c61f44Ssb155480 } 1869c1c61f44Ssb155480 1870c1c61f44Ssb155480 /* 1871f0ca1d9aSsb155480 * This function reads "priority-ether-types" property from md. This property 1872f0ca1d9aSsb155480 * is used to enable support for priority frames. Applications which need 1873f0ca1d9aSsb155480 * guaranteed and timely delivery of certain high priority frames to/from 1874f0ca1d9aSsb155480 * a vnet or vsw within ldoms, should configure this property by providing 1875f0ca1d9aSsb155480 * the ether type(s) for which the priority facility is needed. 1876f0ca1d9aSsb155480 * Normal data frames are delivered over a ldc channel using the descriptor 1877f0ca1d9aSsb155480 * ring mechanism which is constrained by factors such as descriptor ring size, 1878f0ca1d9aSsb155480 * the rate at which the ring is processed at the peer ldc end point, etc. 1879f0ca1d9aSsb155480 * The priority mechanism provides an Out-Of-Band path to send/receive frames 1880f0ca1d9aSsb155480 * as raw pkt data (VIO_PKT_DATA) messages over the channel, avoiding the 1881f0ca1d9aSsb155480 * descriptor ring path and enables a more reliable and timely delivery of 1882f0ca1d9aSsb155480 * frames to the peer. 1883f0ca1d9aSsb155480 */ 1884f0ca1d9aSsb155480 static void 1885f0ca1d9aSsb155480 vsw_read_pri_eth_types(vsw_t *vswp, md_t *mdp, mde_cookie_t node) 1886f0ca1d9aSsb155480 { 1887f0ca1d9aSsb155480 int rv; 1888f0ca1d9aSsb155480 uint16_t *types; 1889f0ca1d9aSsb155480 uint64_t *data; 1890f0ca1d9aSsb155480 int size; 1891f0ca1d9aSsb155480 int i; 1892f0ca1d9aSsb155480 size_t mblk_sz; 1893f0ca1d9aSsb155480 1894f0ca1d9aSsb155480 rv = md_get_prop_data(mdp, node, pri_types_propname, 1895f0ca1d9aSsb155480 (uint8_t **)&data, &size); 1896f0ca1d9aSsb155480 if (rv != 0) { 1897f0ca1d9aSsb155480 /* 1898f0ca1d9aSsb155480 * Property may not exist if we are running pre-ldoms1.1 f/w. 1899f0ca1d9aSsb155480 * Check if 'vsw_pri_eth_type' has been set in that case. 1900f0ca1d9aSsb155480 */ 1901f0ca1d9aSsb155480 if (vsw_pri_eth_type != 0) { 1902f0ca1d9aSsb155480 size = sizeof (vsw_pri_eth_type); 1903f0ca1d9aSsb155480 data = &vsw_pri_eth_type; 1904f0ca1d9aSsb155480 } else { 1905f0ca1d9aSsb155480 D3(vswp, "%s: prop(%s) not found", __func__, 1906f0ca1d9aSsb155480 pri_types_propname); 1907f0ca1d9aSsb155480 size = 0; 1908f0ca1d9aSsb155480 } 1909f0ca1d9aSsb155480 } 1910f0ca1d9aSsb155480 1911f0ca1d9aSsb155480 if (size == 0) { 1912f0ca1d9aSsb155480 vswp->pri_num_types = 0; 1913f0ca1d9aSsb155480 return; 1914f0ca1d9aSsb155480 } 1915f0ca1d9aSsb155480 1916f0ca1d9aSsb155480 /* 1917f0ca1d9aSsb155480 * we have some priority-ether-types defined; 1918f0ca1d9aSsb155480 * allocate a table of these types and also 1919f0ca1d9aSsb155480 * allocate a pool of mblks to transmit these 1920f0ca1d9aSsb155480 * priority packets. 1921f0ca1d9aSsb155480 */ 1922f0ca1d9aSsb155480 size /= sizeof (uint64_t); 1923f0ca1d9aSsb155480 vswp->pri_num_types = size; 1924f0ca1d9aSsb155480 vswp->pri_types = kmem_zalloc(size * sizeof (uint16_t), KM_SLEEP); 1925f0ca1d9aSsb155480 for (i = 0, types = vswp->pri_types; i < size; i++) { 1926f0ca1d9aSsb155480 types[i] = data[i] & 0xFFFF; 1927f0ca1d9aSsb155480 } 1928f0ca1d9aSsb155480 mblk_sz = (VIO_PKT_DATA_HDRSIZE + ETHERMAX + 7) & ~7; 1929f0ca1d9aSsb155480 (void) vio_create_mblks(vsw_pri_tx_nmblks, mblk_sz, &vswp->pri_tx_vmp); 1930f0ca1d9aSsb155480 } 1931f0ca1d9aSsb155480 1932*7b1f684aSSriharsha Basavapatna static void 1933*7b1f684aSSriharsha Basavapatna vsw_mtu_read(vsw_t *vswp, md_t *mdp, mde_cookie_t node, uint32_t *mtu) 1934*7b1f684aSSriharsha Basavapatna { 1935*7b1f684aSSriharsha Basavapatna int rv; 1936*7b1f684aSSriharsha Basavapatna int inst; 1937*7b1f684aSSriharsha Basavapatna uint64_t val; 1938*7b1f684aSSriharsha Basavapatna char *mtu_propname; 1939*7b1f684aSSriharsha Basavapatna 1940*7b1f684aSSriharsha Basavapatna mtu_propname = vsw_mtu_propname; 1941*7b1f684aSSriharsha Basavapatna inst = vswp->instance; 1942*7b1f684aSSriharsha Basavapatna 1943*7b1f684aSSriharsha Basavapatna rv = md_get_prop_val(mdp, node, mtu_propname, &val); 1944*7b1f684aSSriharsha Basavapatna if (rv != 0) { 1945*7b1f684aSSriharsha Basavapatna D3(vswp, "%s: prop(%s) not found", __func__, mtu_propname); 1946*7b1f684aSSriharsha Basavapatna *mtu = vsw_ethermtu; 1947*7b1f684aSSriharsha Basavapatna } else { 1948*7b1f684aSSriharsha Basavapatna 1949*7b1f684aSSriharsha Basavapatna *mtu = val & 0xFFFF; 1950*7b1f684aSSriharsha Basavapatna D2(vswp, "%s: %s(%d): (%d)\n", __func__, 1951*7b1f684aSSriharsha Basavapatna mtu_propname, inst, *mtu); 1952*7b1f684aSSriharsha Basavapatna } 1953*7b1f684aSSriharsha Basavapatna } 1954*7b1f684aSSriharsha Basavapatna 1955*7b1f684aSSriharsha Basavapatna /* 1956*7b1f684aSSriharsha Basavapatna * Update the mtu of the vsw device. We first check if the device has been 1957*7b1f684aSSriharsha Basavapatna * plumbed and if so fail the mtu update. Otherwise, we continue to update the 1958*7b1f684aSSriharsha Basavapatna * new mtu and reset all ports to initiate handshake re-negotiation with peers 1959*7b1f684aSSriharsha Basavapatna * using the new mtu. 1960*7b1f684aSSriharsha Basavapatna */ 1961*7b1f684aSSriharsha Basavapatna static int 1962*7b1f684aSSriharsha Basavapatna vsw_mtu_update(vsw_t *vswp, uint32_t mtu) 1963*7b1f684aSSriharsha Basavapatna { 1964*7b1f684aSSriharsha Basavapatna int rv; 1965*7b1f684aSSriharsha Basavapatna 1966*7b1f684aSSriharsha Basavapatna WRITE_ENTER(&vswp->if_lockrw); 1967*7b1f684aSSriharsha Basavapatna 1968*7b1f684aSSriharsha Basavapatna if (vswp->if_state & VSW_IF_UP) { 1969*7b1f684aSSriharsha Basavapatna 1970*7b1f684aSSriharsha Basavapatna RW_EXIT(&vswp->if_lockrw); 1971*7b1f684aSSriharsha Basavapatna 1972*7b1f684aSSriharsha Basavapatna cmn_err(CE_NOTE, "!vsw%d: Unable to process mtu update" 1973*7b1f684aSSriharsha Basavapatna " as the device is plumbed\n", vswp->instance); 1974*7b1f684aSSriharsha Basavapatna return (EBUSY); 1975*7b1f684aSSriharsha Basavapatna 1976*7b1f684aSSriharsha Basavapatna } else { 1977*7b1f684aSSriharsha Basavapatna 1978*7b1f684aSSriharsha Basavapatna D2(vswp, "%s: curr_mtu(%d) new_mtu(%d)\n", 1979*7b1f684aSSriharsha Basavapatna __func__, vswp->mtu, mtu); 1980*7b1f684aSSriharsha Basavapatna 1981*7b1f684aSSriharsha Basavapatna vswp->mtu = mtu; 1982*7b1f684aSSriharsha Basavapatna vswp->max_frame_size = vswp->mtu + 1983*7b1f684aSSriharsha Basavapatna sizeof (struct ether_header) + VLAN_TAGSZ; 1984*7b1f684aSSriharsha Basavapatna 1985*7b1f684aSSriharsha Basavapatna rv = mac_maxsdu_update(vswp->if_mh, mtu); 1986*7b1f684aSSriharsha Basavapatna if (rv != 0) { 1987*7b1f684aSSriharsha Basavapatna cmn_err(CE_NOTE, 1988*7b1f684aSSriharsha Basavapatna "!vsw%d: Unable to update mtu with mac" 1989*7b1f684aSSriharsha Basavapatna " layer\n", vswp->instance); 1990*7b1f684aSSriharsha Basavapatna } 1991*7b1f684aSSriharsha Basavapatna 1992*7b1f684aSSriharsha Basavapatna RW_EXIT(&vswp->if_lockrw); 1993*7b1f684aSSriharsha Basavapatna 1994*7b1f684aSSriharsha Basavapatna WRITE_ENTER(&vswp->mac_rwlock); 1995*7b1f684aSSriharsha Basavapatna 1996*7b1f684aSSriharsha Basavapatna if (vswp->mh == 0) { 1997*7b1f684aSSriharsha Basavapatna /* 1998*7b1f684aSSriharsha Basavapatna * Physical device is not available yet; mtu will be 1999*7b1f684aSSriharsha Basavapatna * updated after we open it successfully, as we have 2000*7b1f684aSSriharsha Basavapatna * saved the new mtu. 2001*7b1f684aSSriharsha Basavapatna */ 2002*7b1f684aSSriharsha Basavapatna D2(vswp, "%s: Physical device:%s is not " 2003*7b1f684aSSriharsha Basavapatna "available yet; can't update its mtu\n", 2004*7b1f684aSSriharsha Basavapatna __func__, vswp->physname); 2005*7b1f684aSSriharsha Basavapatna 2006*7b1f684aSSriharsha Basavapatna } else { 2007*7b1f684aSSriharsha Basavapatna 2008*7b1f684aSSriharsha Basavapatna /* 2009*7b1f684aSSriharsha Basavapatna * Stop and restart to enable the 2010*7b1f684aSSriharsha Basavapatna * new mtu in the physical device. 2011*7b1f684aSSriharsha Basavapatna */ 2012*7b1f684aSSriharsha Basavapatna vsw_mac_detach(vswp); 2013*7b1f684aSSriharsha Basavapatna rv = vsw_mac_attach(vswp); 2014*7b1f684aSSriharsha Basavapatna if (rv != 0) { 2015*7b1f684aSSriharsha Basavapatna RW_EXIT(&vswp->mac_rwlock); 2016*7b1f684aSSriharsha Basavapatna return (EIO); 2017*7b1f684aSSriharsha Basavapatna } 2018*7b1f684aSSriharsha Basavapatna 2019*7b1f684aSSriharsha Basavapatna } 2020*7b1f684aSSriharsha Basavapatna 2021*7b1f684aSSriharsha Basavapatna RW_EXIT(&vswp->mac_rwlock); 2022*7b1f684aSSriharsha Basavapatna 2023*7b1f684aSSriharsha Basavapatna /* Reset ports to renegotiate with the new mtu */ 2024*7b1f684aSSriharsha Basavapatna vsw_reset_ports(vswp); 2025*7b1f684aSSriharsha Basavapatna 2026*7b1f684aSSriharsha Basavapatna } 2027*7b1f684aSSriharsha Basavapatna 2028*7b1f684aSSriharsha Basavapatna return (0); 2029*7b1f684aSSriharsha Basavapatna } 2030*7b1f684aSSriharsha Basavapatna 2031f0ca1d9aSsb155480 /* 203234683adeSsg70180 * Check to see if the relevant properties in the specified node have 203334683adeSsg70180 * changed, and if so take the appropriate action. 203434683adeSsg70180 * 203534683adeSsg70180 * If any of the properties are missing or invalid we don't take 203634683adeSsg70180 * any action, as this function should only be invoked when modifications 203734683adeSsg70180 * have been made to what we assume is a working configuration, which 203834683adeSsg70180 * we leave active. 203934683adeSsg70180 * 204034683adeSsg70180 * Note it is legal for this routine to be invoked even if none of the 204134683adeSsg70180 * properties in the port node within the MD have actually changed. 204234683adeSsg70180 */ 204334683adeSsg70180 static void 204434683adeSsg70180 vsw_update_md_prop(vsw_t *vswp, md_t *mdp, mde_cookie_t node) 204534683adeSsg70180 { 204634683adeSsg70180 char physname[LIFNAMSIZ]; 204734683adeSsg70180 char drv[LIFNAMSIZ]; 204834683adeSsg70180 uint_t ddi_instance; 204934683adeSsg70180 uint8_t new_smode[NUM_SMODES]; 205034683adeSsg70180 int i, smode_num = 0; 205134683adeSsg70180 uint64_t macaddr = 0; 205234683adeSsg70180 enum {MD_init = 0x1, 205334683adeSsg70180 MD_physname = 0x2, 205434683adeSsg70180 MD_macaddr = 0x4, 2055c1c61f44Ssb155480 MD_smode = 0x8, 2056*7b1f684aSSriharsha Basavapatna MD_vlans = 0x10, 2057*7b1f684aSSriharsha Basavapatna MD_mtu = 0x20} updated; 205819b65a69Ssb155480 int rv; 2059c1c61f44Ssb155480 uint16_t pvid; 2060c1c61f44Ssb155480 uint16_t *vids; 2061c1c61f44Ssb155480 uint16_t nvids; 2062*7b1f684aSSriharsha Basavapatna uint32_t mtu; 206334683adeSsg70180 206434683adeSsg70180 updated = MD_init; 206534683adeSsg70180 206634683adeSsg70180 D1(vswp, "%s: enter", __func__); 206734683adeSsg70180 206834683adeSsg70180 /* 206934683adeSsg70180 * Check if name of physical device in MD has changed. 207034683adeSsg70180 */ 207134683adeSsg70180 if (vsw_get_md_physname(vswp, mdp, node, (char *)&physname) == 0) { 207234683adeSsg70180 /* 207334683adeSsg70180 * Do basic sanity check on new device name/instance, 207434683adeSsg70180 * if its non NULL. It is valid for the device name to 207534683adeSsg70180 * have changed from a non NULL to a NULL value, i.e. 207634683adeSsg70180 * the vsw is being changed to 'routed' mode. 207734683adeSsg70180 */ 207834683adeSsg70180 if ((strlen(physname) != 0) && 207919b65a69Ssb155480 (ddi_parse(physname, drv, 208019b65a69Ssb155480 &ddi_instance) != DDI_SUCCESS)) { 20811ef0bbb5Snarayan cmn_err(CE_WARN, "!vsw%d: physical device %s is not" 208234683adeSsg70180 " a valid device name/instance", 208334683adeSsg70180 vswp->instance, physname); 208434683adeSsg70180 goto fail_reconf; 208534683adeSsg70180 } 208634683adeSsg70180 208734683adeSsg70180 if (strcmp(physname, vswp->physname)) { 208834683adeSsg70180 D2(vswp, "%s: device name changed from %s to %s", 208934683adeSsg70180 __func__, vswp->physname, physname); 209034683adeSsg70180 209134683adeSsg70180 updated |= MD_physname; 209234683adeSsg70180 } else { 209334683adeSsg70180 D2(vswp, "%s: device name unchanged at %s", 209434683adeSsg70180 __func__, vswp->physname); 209534683adeSsg70180 } 209634683adeSsg70180 } else { 209734683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to read name of physical " 209834683adeSsg70180 "device from updated MD.", vswp->instance); 209934683adeSsg70180 goto fail_reconf; 210034683adeSsg70180 } 210134683adeSsg70180 210234683adeSsg70180 /* 210334683adeSsg70180 * Check if MAC address has changed. 210434683adeSsg70180 */ 210534683adeSsg70180 if (md_get_prop_val(mdp, node, macaddr_propname, &macaddr) != 0) { 210634683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to get MAC address from MD", 210734683adeSsg70180 vswp->instance); 210834683adeSsg70180 goto fail_reconf; 210934683adeSsg70180 } else { 211019b65a69Ssb155480 uint64_t maddr = macaddr; 211134683adeSsg70180 READ_ENTER(&vswp->if_lockrw); 211234683adeSsg70180 for (i = ETHERADDRL - 1; i >= 0; i--) { 211319b65a69Ssb155480 if (vswp->if_addr.ether_addr_octet[i] 211419b65a69Ssb155480 != (macaddr & 0xFF)) { 211534683adeSsg70180 D2(vswp, "%s: octet[%d] 0x%x != 0x%x", 211634683adeSsg70180 __func__, i, 211734683adeSsg70180 vswp->if_addr.ether_addr_octet[i], 211834683adeSsg70180 (macaddr & 0xFF)); 211934683adeSsg70180 updated |= MD_macaddr; 212019b65a69Ssb155480 macaddr = maddr; 212134683adeSsg70180 break; 212234683adeSsg70180 } 212334683adeSsg70180 macaddr >>= 8; 212434683adeSsg70180 } 212534683adeSsg70180 RW_EXIT(&vswp->if_lockrw); 212619b65a69Ssb155480 if (updated & MD_macaddr) { 212719b65a69Ssb155480 vsw_save_lmacaddr(vswp, macaddr); 212819b65a69Ssb155480 } 212934683adeSsg70180 } 213034683adeSsg70180 213134683adeSsg70180 /* 213234683adeSsg70180 * Check if switching modes have changed. 213334683adeSsg70180 */ 213419b65a69Ssb155480 if (vsw_get_md_smodes(vswp, mdp, node, 213519b65a69Ssb155480 new_smode, &smode_num)) { 213634683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to read %s property from MD", 213734683adeSsg70180 vswp->instance, smode_propname); 213834683adeSsg70180 goto fail_reconf; 213934683adeSsg70180 } else { 214034683adeSsg70180 ASSERT(smode_num != 0); 214134683adeSsg70180 if (smode_num != vswp->smode_num) { 214234683adeSsg70180 D2(vswp, "%s: number of modes changed from %d to %d", 214334683adeSsg70180 __func__, vswp->smode_num, smode_num); 214434683adeSsg70180 } 214534683adeSsg70180 214634683adeSsg70180 for (i = 0; i < smode_num; i++) { 214734683adeSsg70180 if (new_smode[i] != vswp->smode[i]) { 214834683adeSsg70180 D2(vswp, "%s: mode changed from %d to %d", 214934683adeSsg70180 __func__, vswp->smode[i], new_smode[i]); 215034683adeSsg70180 updated |= MD_smode; 215134683adeSsg70180 break; 215234683adeSsg70180 } 215334683adeSsg70180 } 215434683adeSsg70180 } 215534683adeSsg70180 2156c1c61f44Ssb155480 /* Read the vlan ids */ 2157c1c61f44Ssb155480 vsw_vlan_read_ids(vswp, VSW_LOCALDEV, mdp, node, &pvid, &vids, 2158c1c61f44Ssb155480 &nvids, NULL); 2159c1c61f44Ssb155480 2160c1c61f44Ssb155480 /* Determine if there are any vlan id updates */ 2161c1c61f44Ssb155480 if ((pvid != vswp->pvid) || /* pvid changed? */ 2162c1c61f44Ssb155480 (nvids != vswp->nvids) || /* # of vids changed? */ 2163c1c61f44Ssb155480 ((nvids != 0) && (vswp->nvids != 0) && /* vids changed? */ 2164c1c61f44Ssb155480 bcmp(vids, vswp->vids, sizeof (uint16_t) * nvids))) { 2165c1c61f44Ssb155480 updated |= MD_vlans; 2166c1c61f44Ssb155480 } 2167c1c61f44Ssb155480 2168*7b1f684aSSriharsha Basavapatna /* Read mtu */ 2169*7b1f684aSSriharsha Basavapatna vsw_mtu_read(vswp, mdp, node, &mtu); 2170*7b1f684aSSriharsha Basavapatna if (mtu != vswp->mtu) { 2171*7b1f684aSSriharsha Basavapatna if (mtu >= ETHERMTU && mtu <= VNET_MAX_MTU) { 2172*7b1f684aSSriharsha Basavapatna updated |= MD_mtu; 2173*7b1f684aSSriharsha Basavapatna } else { 2174*7b1f684aSSriharsha Basavapatna cmn_err(CE_NOTE, "!vsw%d: Unable to process mtu update" 2175*7b1f684aSSriharsha Basavapatna " as the specified value:%d is invalid\n", 2176*7b1f684aSSriharsha Basavapatna vswp->instance, mtu); 2177*7b1f684aSSriharsha Basavapatna } 2178*7b1f684aSSriharsha Basavapatna } 2179*7b1f684aSSriharsha Basavapatna 218034683adeSsg70180 /* 218134683adeSsg70180 * Now make any changes which are needed... 218234683adeSsg70180 */ 218334683adeSsg70180 218434683adeSsg70180 if (updated & (MD_physname | MD_smode)) { 218534683adeSsg70180 218634683adeSsg70180 /* 218719b65a69Ssb155480 * Stop any pending timeout to setup switching mode. 218834683adeSsg70180 */ 218919b65a69Ssb155480 vsw_stop_switching_timeout(vswp); 219019b65a69Ssb155480 2191678453a8Sspeer /* Cleanup HybridIO */ 2192678453a8Sspeer vsw_hio_cleanup(vswp); 2193678453a8Sspeer 219419b65a69Ssb155480 /* 219519b65a69Ssb155480 * Remove unicst, mcst addrs of vsw interface 219619b65a69Ssb155480 * and ports from the physdev. 219719b65a69Ssb155480 */ 219819b65a69Ssb155480 vsw_unset_addrs(vswp); 219919b65a69Ssb155480 220019b65a69Ssb155480 /* 220119b65a69Ssb155480 * Stop, detach and close the old device.. 220219b65a69Ssb155480 */ 22033c1bce15Swentaoy WRITE_ENTER(&vswp->mac_rwlock); 220419b65a69Ssb155480 220534683adeSsg70180 vsw_mac_detach(vswp); 220619b65a69Ssb155480 vsw_mac_close(vswp); 220719b65a69Ssb155480 22083c1bce15Swentaoy RW_EXIT(&vswp->mac_rwlock); 220934683adeSsg70180 221034683adeSsg70180 /* 221134683adeSsg70180 * Update phys name. 221234683adeSsg70180 */ 221334683adeSsg70180 if (updated & MD_physname) { 221434683adeSsg70180 cmn_err(CE_NOTE, "!vsw%d: changing from %s to %s", 221534683adeSsg70180 vswp->instance, vswp->physname, physname); 221634683adeSsg70180 (void) strncpy(vswp->physname, 221734683adeSsg70180 physname, strlen(physname) + 1); 221834683adeSsg70180 } 221934683adeSsg70180 222034683adeSsg70180 /* 222134683adeSsg70180 * Update array with the new switch mode values. 222234683adeSsg70180 */ 222334683adeSsg70180 if (updated & MD_smode) { 222434683adeSsg70180 for (i = 0; i < smode_num; i++) 222534683adeSsg70180 vswp->smode[i] = new_smode[i]; 222634683adeSsg70180 222734683adeSsg70180 vswp->smode_num = smode_num; 222834683adeSsg70180 vswp->smode_idx = 0; 222934683adeSsg70180 } 223034683adeSsg70180 223134683adeSsg70180 /* 223234683adeSsg70180 * ..and attach, start the new device. 223334683adeSsg70180 */ 223419b65a69Ssb155480 rv = vsw_setup_switching(vswp); 223519b65a69Ssb155480 if (rv == EAGAIN) { 223619b65a69Ssb155480 /* 223719b65a69Ssb155480 * Unable to setup switching mode. 223819b65a69Ssb155480 * As the error is EAGAIN, schedule a timeout to retry 223919b65a69Ssb155480 * and return. Programming addresses of ports and 224019b65a69Ssb155480 * vsw interface will be done when the timeout handler 224119b65a69Ssb155480 * completes successfully. 224219b65a69Ssb155480 */ 224319b65a69Ssb155480 mutex_enter(&vswp->swtmout_lock); 224419b65a69Ssb155480 224519b65a69Ssb155480 vswp->swtmout_enabled = B_TRUE; 224619b65a69Ssb155480 vswp->swtmout_id = 224719b65a69Ssb155480 timeout(vsw_setup_switching_timeout, vswp, 224819b65a69Ssb155480 (vsw_setup_switching_delay * 224919b65a69Ssb155480 drv_usectohz(MICROSEC))); 225019b65a69Ssb155480 225119b65a69Ssb155480 mutex_exit(&vswp->swtmout_lock); 225219b65a69Ssb155480 225319b65a69Ssb155480 return; 225419b65a69Ssb155480 225519b65a69Ssb155480 } else if (rv) { 225634683adeSsg70180 goto fail_update; 225719b65a69Ssb155480 } 225834683adeSsg70180 225934683adeSsg70180 /* 226019b65a69Ssb155480 * program unicst, mcst addrs of vsw interface 226119b65a69Ssb155480 * and ports in the physdev. 226234683adeSsg70180 */ 226319b65a69Ssb155480 vsw_set_addrs(vswp); 226434683adeSsg70180 2265678453a8Sspeer /* Start HIO for ports that have already connected */ 2266678453a8Sspeer vsw_hio_start_ports(vswp); 2267678453a8Sspeer 226819b65a69Ssb155480 } else if (updated & MD_macaddr) { 226919b65a69Ssb155480 /* 227019b65a69Ssb155480 * We enter here if only MD_macaddr is exclusively updated. 227119b65a69Ssb155480 * If MD_physname and/or MD_smode are also updated, then 227219b65a69Ssb155480 * as part of that, we would have implicitly processed 227319b65a69Ssb155480 * MD_macaddr update (above). 227419b65a69Ssb155480 */ 227534683adeSsg70180 cmn_err(CE_NOTE, "!vsw%d: changing mac address to 0x%lx", 227634683adeSsg70180 vswp->instance, macaddr); 227734683adeSsg70180 227819b65a69Ssb155480 READ_ENTER(&vswp->if_lockrw); 227919b65a69Ssb155480 if (vswp->if_state & VSW_IF_UP) { 228034683adeSsg70180 22815f94e909Ssg70180 mutex_enter(&vswp->hw_lock); 228219b65a69Ssb155480 /* 228319b65a69Ssb155480 * Remove old mac address of vsw interface 228419b65a69Ssb155480 * from the physdev 228519b65a69Ssb155480 */ 22865f94e909Ssg70180 (void) vsw_unset_hw(vswp, NULL, VSW_LOCALDEV); 228719b65a69Ssb155480 /* 228819b65a69Ssb155480 * Program new mac address of vsw interface 228919b65a69Ssb155480 * in the physdev 229019b65a69Ssb155480 */ 229119b65a69Ssb155480 rv = vsw_set_hw(vswp, NULL, VSW_LOCALDEV); 22925f94e909Ssg70180 mutex_exit(&vswp->hw_lock); 229319b65a69Ssb155480 if (rv != 0) { 229419b65a69Ssb155480 cmn_err(CE_NOTE, 229519b65a69Ssb155480 "!vsw%d: failed to program interface " 229619b65a69Ssb155480 "unicast address\n", vswp->instance); 229719b65a69Ssb155480 } 22985f94e909Ssg70180 /* 229934683adeSsg70180 * Notify the MAC layer of the changed address. 230034683adeSsg70180 */ 230119b65a69Ssb155480 mac_unicst_update(vswp->if_mh, 230219b65a69Ssb155480 (uint8_t *)&vswp->if_addr); 230319b65a69Ssb155480 230419b65a69Ssb155480 } 230519b65a69Ssb155480 RW_EXIT(&vswp->if_lockrw); 230619b65a69Ssb155480 230734683adeSsg70180 } 230834683adeSsg70180 2309c1c61f44Ssb155480 if (updated & MD_vlans) { 2310c1c61f44Ssb155480 /* Remove existing vlan ids from the hash table. */ 2311c1c61f44Ssb155480 vsw_vlan_remove_ids(vswp, VSW_LOCALDEV); 2312c1c61f44Ssb155480 2313c1c61f44Ssb155480 /* save the new vlan ids */ 2314c1c61f44Ssb155480 vswp->pvid = pvid; 2315c1c61f44Ssb155480 if (vswp->nvids != 0) { 2316c1c61f44Ssb155480 kmem_free(vswp->vids, sizeof (uint16_t) * vswp->nvids); 2317c1c61f44Ssb155480 vswp->nvids = 0; 2318c1c61f44Ssb155480 } 2319c1c61f44Ssb155480 if (nvids != 0) { 2320c1c61f44Ssb155480 vswp->nvids = nvids; 2321c1c61f44Ssb155480 vswp->vids = vids; 2322c1c61f44Ssb155480 } 2323c1c61f44Ssb155480 2324c1c61f44Ssb155480 /* add these new vlan ids into hash table */ 2325c1c61f44Ssb155480 vsw_vlan_add_ids(vswp, VSW_LOCALDEV); 2326c1c61f44Ssb155480 } else { 2327c1c61f44Ssb155480 if (nvids != 0) { 2328c1c61f44Ssb155480 kmem_free(vids, sizeof (uint16_t) * nvids); 2329c1c61f44Ssb155480 } 2330c1c61f44Ssb155480 } 2331c1c61f44Ssb155480 2332*7b1f684aSSriharsha Basavapatna if (updated & MD_mtu) { 2333*7b1f684aSSriharsha Basavapatna 2334*7b1f684aSSriharsha Basavapatna rv = vsw_mtu_update(vswp, mtu); 2335*7b1f684aSSriharsha Basavapatna if (rv != 0) { 2336*7b1f684aSSriharsha Basavapatna goto fail_update; 2337*7b1f684aSSriharsha Basavapatna } 2338*7b1f684aSSriharsha Basavapatna 2339*7b1f684aSSriharsha Basavapatna } 2340*7b1f684aSSriharsha Basavapatna 234134683adeSsg70180 return; 234234683adeSsg70180 234334683adeSsg70180 fail_reconf: 234434683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: configuration unchanged", vswp->instance); 234534683adeSsg70180 return; 234634683adeSsg70180 234734683adeSsg70180 fail_update: 23481ef0bbb5Snarayan cmn_err(CE_WARN, "!vsw%d: re-configuration failed", 234934683adeSsg70180 vswp->instance); 235034683adeSsg70180 } 235134683adeSsg70180 235234683adeSsg70180 /* 2353c1c61f44Ssb155480 * Read the port's md properties. 23541ae08745Sheppo */ 2355c1c61f44Ssb155480 static int 2356c1c61f44Ssb155480 vsw_port_read_props(vsw_port_t *portp, vsw_t *vswp, 2357c1c61f44Ssb155480 md_t *mdp, mde_cookie_t *node) 23581ae08745Sheppo { 23591ae08745Sheppo uint64_t ldc_id; 23601ae08745Sheppo uint8_t *addrp; 23611ae08745Sheppo int i, addrsz; 23621ae08745Sheppo int num_nodes = 0, nchan = 0; 23631ae08745Sheppo int listsz = 0; 23641ae08745Sheppo mde_cookie_t *listp = NULL; 23651ae08745Sheppo struct ether_addr ea; 23661ae08745Sheppo uint64_t macaddr; 23671ae08745Sheppo uint64_t inst = 0; 2368678453a8Sspeer uint64_t val; 23691ae08745Sheppo 23701ae08745Sheppo if (md_get_prop_val(mdp, *node, id_propname, &inst)) { 23711ae08745Sheppo DWARN(vswp, "%s: prop(%s) not found", __func__, 23721ae08745Sheppo id_propname); 23731ae08745Sheppo return (1); 23741ae08745Sheppo } 23751ae08745Sheppo 23761ae08745Sheppo /* 23771ae08745Sheppo * Find the channel endpoint node(s) (which should be under this 23781ae08745Sheppo * port node) which contain the channel id(s). 23791ae08745Sheppo */ 23801ae08745Sheppo if ((num_nodes = md_node_count(mdp)) <= 0) { 23811ae08745Sheppo DERR(vswp, "%s: invalid number of nodes found (%d)", 23821ae08745Sheppo __func__, num_nodes); 23831ae08745Sheppo return (1); 23841ae08745Sheppo } 23851ae08745Sheppo 238634683adeSsg70180 D2(vswp, "%s: %d nodes found", __func__, num_nodes); 238734683adeSsg70180 23881ae08745Sheppo /* allocate enough space for node list */ 23891ae08745Sheppo listsz = num_nodes * sizeof (mde_cookie_t); 23901ae08745Sheppo listp = kmem_zalloc(listsz, KM_SLEEP); 23911ae08745Sheppo 2392205eeb1aSlm66018 nchan = md_scan_dag(mdp, *node, md_find_name(mdp, chan_propname), 23931ae08745Sheppo md_find_name(mdp, "fwd"), listp); 23941ae08745Sheppo 23951ae08745Sheppo if (nchan <= 0) { 23961ae08745Sheppo DWARN(vswp, "%s: no %s nodes found", __func__, chan_propname); 23971ae08745Sheppo kmem_free(listp, listsz); 23981ae08745Sheppo return (1); 23991ae08745Sheppo } 24001ae08745Sheppo 24011ae08745Sheppo D2(vswp, "%s: %d %s nodes found", __func__, nchan, chan_propname); 24021ae08745Sheppo 24031ae08745Sheppo /* use property from first node found */ 24041ae08745Sheppo if (md_get_prop_val(mdp, listp[0], id_propname, &ldc_id)) { 24051ae08745Sheppo DWARN(vswp, "%s: prop(%s) not found\n", __func__, 24061ae08745Sheppo id_propname); 24071ae08745Sheppo kmem_free(listp, listsz); 24081ae08745Sheppo return (1); 24091ae08745Sheppo } 24101ae08745Sheppo 24111ae08745Sheppo /* don't need list any more */ 24121ae08745Sheppo kmem_free(listp, listsz); 24131ae08745Sheppo 24141ae08745Sheppo D2(vswp, "%s: ldc_id 0x%llx", __func__, ldc_id); 24151ae08745Sheppo 24161ae08745Sheppo /* read mac-address property */ 24171ae08745Sheppo if (md_get_prop_data(mdp, *node, remaddr_propname, 24181ae08745Sheppo &addrp, &addrsz)) { 24191ae08745Sheppo DWARN(vswp, "%s: prop(%s) not found", 24201ae08745Sheppo __func__, remaddr_propname); 24211ae08745Sheppo return (1); 24221ae08745Sheppo } 24231ae08745Sheppo 24241ae08745Sheppo if (addrsz < ETHERADDRL) { 24251ae08745Sheppo DWARN(vswp, "%s: invalid address size", __func__); 24261ae08745Sheppo return (1); 24271ae08745Sheppo } 24281ae08745Sheppo 24291ae08745Sheppo macaddr = *((uint64_t *)addrp); 24301ae08745Sheppo D2(vswp, "%s: remote mac address 0x%llx", __func__, macaddr); 24311ae08745Sheppo 24321ae08745Sheppo for (i = ETHERADDRL - 1; i >= 0; i--) { 24331ae08745Sheppo ea.ether_addr_octet[i] = macaddr & 0xFF; 24341ae08745Sheppo macaddr >>= 8; 24351ae08745Sheppo } 24361ae08745Sheppo 2437c1c61f44Ssb155480 /* now update all properties into the port */ 2438c1c61f44Ssb155480 portp->p_vswp = vswp; 2439c1c61f44Ssb155480 portp->p_instance = inst; 2440c1c61f44Ssb155480 portp->addr_set = VSW_ADDR_UNSET; 2441c1c61f44Ssb155480 ether_copy(&ea, &portp->p_macaddr); 2442c1c61f44Ssb155480 if (nchan > VSW_PORT_MAX_LDCS) { 2443c1c61f44Ssb155480 D2(vswp, "%s: using first of %d ldc ids", 2444c1c61f44Ssb155480 __func__, nchan); 2445c1c61f44Ssb155480 nchan = VSW_PORT_MAX_LDCS; 2446c1c61f44Ssb155480 } 2447c1c61f44Ssb155480 portp->num_ldcs = nchan; 2448c1c61f44Ssb155480 portp->ldc_ids = 2449c1c61f44Ssb155480 kmem_zalloc(sizeof (uint64_t) * nchan, KM_SLEEP); 2450c1c61f44Ssb155480 bcopy(&ldc_id, (portp->ldc_ids), sizeof (uint64_t) * nchan); 2451c1c61f44Ssb155480 2452c1c61f44Ssb155480 /* read vlan id properties of this port node */ 2453c1c61f44Ssb155480 vsw_vlan_read_ids(portp, VSW_VNETPORT, mdp, *node, &portp->pvid, 2454c1c61f44Ssb155480 &portp->vids, &portp->nvids, NULL); 2455c1c61f44Ssb155480 2456678453a8Sspeer /* Check if hybrid property is present */ 2457678453a8Sspeer if (md_get_prop_val(mdp, *node, hybrid_propname, &val) == 0) { 2458678453a8Sspeer D1(vswp, "%s: prop(%s) found\n", __func__, hybrid_propname); 2459678453a8Sspeer portp->p_hio_enabled = B_TRUE; 2460678453a8Sspeer } else { 2461678453a8Sspeer portp->p_hio_enabled = B_FALSE; 2462678453a8Sspeer } 2463678453a8Sspeer /* 2464678453a8Sspeer * Port hio capability determined after version 2465678453a8Sspeer * negotiation, i.e., when we know the peer is HybridIO capable. 2466678453a8Sspeer */ 2467678453a8Sspeer portp->p_hio_capable = B_FALSE; 2468c1c61f44Ssb155480 return (0); 2469c1c61f44Ssb155480 } 2470c1c61f44Ssb155480 2471c1c61f44Ssb155480 /* 2472c1c61f44Ssb155480 * Add a new port to the system. 2473c1c61f44Ssb155480 * 2474c1c61f44Ssb155480 * Returns 0 on success, 1 on failure. 2475c1c61f44Ssb155480 */ 2476c1c61f44Ssb155480 int 2477c1c61f44Ssb155480 vsw_port_add(vsw_t *vswp, md_t *mdp, mde_cookie_t *node) 2478c1c61f44Ssb155480 { 2479c1c61f44Ssb155480 vsw_port_t *portp; 2480c1c61f44Ssb155480 int rv; 2481c1c61f44Ssb155480 2482c1c61f44Ssb155480 portp = kmem_zalloc(sizeof (vsw_port_t), KM_SLEEP); 2483c1c61f44Ssb155480 2484c1c61f44Ssb155480 rv = vsw_port_read_props(portp, vswp, mdp, node); 2485c1c61f44Ssb155480 if (rv != 0) { 2486c1c61f44Ssb155480 kmem_free(portp, sizeof (*portp)); 2487c1c61f44Ssb155480 return (1); 2488c1c61f44Ssb155480 } 2489c1c61f44Ssb155480 2490c1c61f44Ssb155480 rv = vsw_port_attach(portp); 2491c1c61f44Ssb155480 if (rv != 0) { 24921ae08745Sheppo DERR(vswp, "%s: failed to attach port", __func__); 24931ae08745Sheppo return (1); 24941ae08745Sheppo } 24951ae08745Sheppo 2496c1c61f44Ssb155480 return (0); 2497c1c61f44Ssb155480 } 24981ae08745Sheppo 2499c1c61f44Ssb155480 static int 2500c1c61f44Ssb155480 vsw_port_update(vsw_t *vswp, md_t *curr_mdp, mde_cookie_t curr_mdex, 2501c1c61f44Ssb155480 md_t *prev_mdp, mde_cookie_t prev_mdex) 2502c1c61f44Ssb155480 { 2503c1c61f44Ssb155480 uint64_t cport_num; 2504c1c61f44Ssb155480 uint64_t pport_num; 2505c1c61f44Ssb155480 vsw_port_list_t *plistp; 2506c1c61f44Ssb155480 vsw_port_t *portp; 2507c1c61f44Ssb155480 boolean_t updated_vlans = B_FALSE; 2508c1c61f44Ssb155480 uint16_t pvid; 2509c1c61f44Ssb155480 uint16_t *vids; 2510c1c61f44Ssb155480 uint16_t nvids; 2511678453a8Sspeer uint64_t val; 2512678453a8Sspeer boolean_t hio_enabled = B_FALSE; 2513c1c61f44Ssb155480 2514c1c61f44Ssb155480 /* 2515c1c61f44Ssb155480 * For now, we get port updates only if vlan ids changed. 2516c1c61f44Ssb155480 * We read the port num and do some sanity check. 2517c1c61f44Ssb155480 */ 2518c1c61f44Ssb155480 if (md_get_prop_val(curr_mdp, curr_mdex, id_propname, &cport_num)) { 2519c1c61f44Ssb155480 return (1); 2520c1c61f44Ssb155480 } 2521c1c61f44Ssb155480 2522c1c61f44Ssb155480 if (md_get_prop_val(prev_mdp, prev_mdex, id_propname, &pport_num)) { 2523c1c61f44Ssb155480 return (1); 2524c1c61f44Ssb155480 } 2525c1c61f44Ssb155480 if (cport_num != pport_num) 2526c1c61f44Ssb155480 return (1); 2527c1c61f44Ssb155480 2528c1c61f44Ssb155480 plistp = &(vswp->plist); 2529c1c61f44Ssb155480 2530c1c61f44Ssb155480 READ_ENTER(&plistp->lockrw); 2531c1c61f44Ssb155480 2532c1c61f44Ssb155480 portp = vsw_lookup_port(vswp, cport_num); 2533c1c61f44Ssb155480 if (portp == NULL) { 2534c1c61f44Ssb155480 RW_EXIT(&plistp->lockrw); 2535c1c61f44Ssb155480 return (1); 2536c1c61f44Ssb155480 } 2537c1c61f44Ssb155480 2538c1c61f44Ssb155480 /* Read the vlan ids */ 2539c1c61f44Ssb155480 vsw_vlan_read_ids(portp, VSW_VNETPORT, curr_mdp, curr_mdex, &pvid, 2540c1c61f44Ssb155480 &vids, &nvids, NULL); 2541c1c61f44Ssb155480 2542c1c61f44Ssb155480 /* Determine if there are any vlan id updates */ 2543c1c61f44Ssb155480 if ((pvid != portp->pvid) || /* pvid changed? */ 2544c1c61f44Ssb155480 (nvids != portp->nvids) || /* # of vids changed? */ 2545c1c61f44Ssb155480 ((nvids != 0) && (portp->nvids != 0) && /* vids changed? */ 2546c1c61f44Ssb155480 bcmp(vids, portp->vids, sizeof (uint16_t) * nvids))) { 2547c1c61f44Ssb155480 updated_vlans = B_TRUE; 2548c1c61f44Ssb155480 } 2549c1c61f44Ssb155480 2550678453a8Sspeer if (updated_vlans == B_TRUE) { 2551c1c61f44Ssb155480 2552c1c61f44Ssb155480 /* Remove existing vlan ids from the hash table. */ 2553c1c61f44Ssb155480 vsw_vlan_remove_ids(portp, VSW_VNETPORT); 2554c1c61f44Ssb155480 2555c1c61f44Ssb155480 /* save the new vlan ids */ 2556c1c61f44Ssb155480 portp->pvid = pvid; 2557c1c61f44Ssb155480 if (portp->nvids != 0) { 2558678453a8Sspeer kmem_free(portp->vids, 2559678453a8Sspeer sizeof (uint16_t) * portp->nvids); 2560c1c61f44Ssb155480 portp->nvids = 0; 2561c1c61f44Ssb155480 } 2562c1c61f44Ssb155480 if (nvids != 0) { 2563678453a8Sspeer portp->vids = kmem_zalloc(sizeof (uint16_t) * 2564678453a8Sspeer nvids, KM_SLEEP); 2565c1c61f44Ssb155480 bcopy(vids, portp->vids, sizeof (uint16_t) * nvids); 2566c1c61f44Ssb155480 portp->nvids = nvids; 2567c1c61f44Ssb155480 kmem_free(vids, sizeof (uint16_t) * nvids); 2568c1c61f44Ssb155480 } 2569c1c61f44Ssb155480 2570c1c61f44Ssb155480 /* add these new vlan ids into hash table */ 2571c1c61f44Ssb155480 vsw_vlan_add_ids(portp, VSW_VNETPORT); 2572c1c61f44Ssb155480 2573c1c61f44Ssb155480 /* reset the port if it is vlan unaware (ver < 1.3) */ 2574c1c61f44Ssb155480 vsw_vlan_unaware_port_reset(portp); 2575678453a8Sspeer } 2576678453a8Sspeer 2577678453a8Sspeer /* Check if hybrid property is present */ 2578678453a8Sspeer if (md_get_prop_val(curr_mdp, curr_mdex, hybrid_propname, &val) == 0) { 2579678453a8Sspeer D1(vswp, "%s: prop(%s) found\n", __func__, hybrid_propname); 2580678453a8Sspeer hio_enabled = B_TRUE; 2581678453a8Sspeer } 2582678453a8Sspeer 2583678453a8Sspeer if (portp->p_hio_enabled != hio_enabled) { 2584678453a8Sspeer vsw_hio_port_update(portp, hio_enabled); 2585678453a8Sspeer } 2586c1c61f44Ssb155480 2587c1c61f44Ssb155480 RW_EXIT(&plistp->lockrw); 25881ae08745Sheppo 25891ae08745Sheppo return (0); 25901ae08745Sheppo } 25911ae08745Sheppo 25921ae08745Sheppo /* 259306db247cSraghuram * vsw_mac_rx -- A common function to send packets to the interface. 259406db247cSraghuram * By default this function check if the interface is UP or not, the 259506db247cSraghuram * rest of the behaviour depends on the flags as below: 25961ae08745Sheppo * 259706db247cSraghuram * VSW_MACRX_PROMISC -- Check if the promisc mode set or not. 259806db247cSraghuram * VSW_MACRX_COPYMSG -- Make a copy of the message(s). 259906db247cSraghuram * VSW_MACRX_FREEMSG -- Free if the messages cannot be sent up the stack. 26001ae08745Sheppo */ 26011ae08745Sheppo void 2602f0ca1d9aSsb155480 vsw_mac_rx(vsw_t *vswp, mac_resource_handle_t mrh, 2603f0ca1d9aSsb155480 mblk_t *mp, vsw_macrx_flags_t flags) 26041ae08745Sheppo { 2605c1c61f44Ssb155480 mblk_t *mpt; 2606c1c61f44Ssb155480 260706db247cSraghuram D1(vswp, "%s:enter\n", __func__); 26081ae08745Sheppo READ_ENTER(&vswp->if_lockrw); 260906db247cSraghuram /* Check if the interface is up */ 261006db247cSraghuram if (!(vswp->if_state & VSW_IF_UP)) { 26111ae08745Sheppo RW_EXIT(&vswp->if_lockrw); 261206db247cSraghuram /* Free messages only if FREEMSG flag specified */ 261306db247cSraghuram if (flags & VSW_MACRX_FREEMSG) { 261406db247cSraghuram freemsgchain(mp); 261506db247cSraghuram } 261606db247cSraghuram D1(vswp, "%s:exit\n", __func__); 261706db247cSraghuram return; 261806db247cSraghuram } 261906db247cSraghuram /* 262006db247cSraghuram * If PROMISC flag is passed, then check if 262106db247cSraghuram * the interface is in the PROMISC mode. 262206db247cSraghuram * If not, drop the messages. 262306db247cSraghuram */ 262406db247cSraghuram if (flags & VSW_MACRX_PROMISC) { 262506db247cSraghuram if (!(vswp->if_state & VSW_IF_PROMISC)) { 262606db247cSraghuram RW_EXIT(&vswp->if_lockrw); 262706db247cSraghuram /* Free messages only if FREEMSG flag specified */ 262806db247cSraghuram if (flags & VSW_MACRX_FREEMSG) { 262906db247cSraghuram freemsgchain(mp); 263006db247cSraghuram } 263106db247cSraghuram D1(vswp, "%s:exit\n", __func__); 263206db247cSraghuram return; 263306db247cSraghuram } 263406db247cSraghuram } 263506db247cSraghuram RW_EXIT(&vswp->if_lockrw); 263606db247cSraghuram /* 263706db247cSraghuram * If COPYMSG flag is passed, then make a copy 263806db247cSraghuram * of the message chain and send up the copy. 263906db247cSraghuram */ 264006db247cSraghuram if (flags & VSW_MACRX_COPYMSG) { 264106db247cSraghuram mp = copymsgchain(mp); 2642f0ca1d9aSsb155480 if (mp == NULL) { 264306db247cSraghuram D1(vswp, "%s:exit\n", __func__); 264406db247cSraghuram return; 264506db247cSraghuram } 264606db247cSraghuram } 264706db247cSraghuram 2648f0ca1d9aSsb155480 D2(vswp, "%s: sending up stack", __func__); 2649c1c61f44Ssb155480 2650c1c61f44Ssb155480 mpt = NULL; 2651c1c61f44Ssb155480 (void) vsw_vlan_frame_untag(vswp, VSW_LOCALDEV, &mp, &mpt); 2652c1c61f44Ssb155480 if (mp != NULL) { 2653ba2e4443Sseb mac_rx(vswp->if_mh, mrh, mp); 2654c1c61f44Ssb155480 } 265506db247cSraghuram D1(vswp, "%s:exit\n", __func__); 26561ae08745Sheppo } 26571ae08745Sheppo 265806db247cSraghuram /* copy mac address of vsw into soft state structure */ 26591ae08745Sheppo static void 266006db247cSraghuram vsw_save_lmacaddr(vsw_t *vswp, uint64_t macaddr) 26611ae08745Sheppo { 26621ae08745Sheppo int i; 26631ae08745Sheppo 266406db247cSraghuram WRITE_ENTER(&vswp->if_lockrw); 266506db247cSraghuram for (i = ETHERADDRL - 1; i >= 0; i--) { 266606db247cSraghuram vswp->if_addr.ether_addr_octet[i] = macaddr & 0xFF; 266706db247cSraghuram macaddr >>= 8; 26681ae08745Sheppo } 266906db247cSraghuram RW_EXIT(&vswp->if_lockrw); 26701ae08745Sheppo } 2671