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 #pragma ident "%Z%%M% %I% %E% SMI" 281ae08745Sheppo 291ae08745Sheppo #include <sys/types.h> 301ae08745Sheppo #include <sys/errno.h> 311ae08745Sheppo #include <sys/debug.h> 321ae08745Sheppo #include <sys/time.h> 331ae08745Sheppo #include <sys/sysmacros.h> 341ae08745Sheppo #include <sys/systm.h> 351ae08745Sheppo #include <sys/user.h> 361ae08745Sheppo #include <sys/stropts.h> 371ae08745Sheppo #include <sys/stream.h> 381ae08745Sheppo #include <sys/strlog.h> 391ae08745Sheppo #include <sys/strsubr.h> 401ae08745Sheppo #include <sys/cmn_err.h> 411ae08745Sheppo #include <sys/cpu.h> 421ae08745Sheppo #include <sys/kmem.h> 431ae08745Sheppo #include <sys/conf.h> 441ae08745Sheppo #include <sys/ddi.h> 451ae08745Sheppo #include <sys/sunddi.h> 461ae08745Sheppo #include <sys/ksynch.h> 471ae08745Sheppo #include <sys/stat.h> 481ae08745Sheppo #include <sys/kstat.h> 491ae08745Sheppo #include <sys/vtrace.h> 501ae08745Sheppo #include <sys/strsun.h> 511ae08745Sheppo #include <sys/dlpi.h> 521ae08745Sheppo #include <sys/ethernet.h> 531ae08745Sheppo #include <net/if.h> 541ae08745Sheppo #include <sys/varargs.h> 551ae08745Sheppo #include <sys/machsystm.h> 561ae08745Sheppo #include <sys/modctl.h> 571ae08745Sheppo #include <sys/modhash.h> 581ae08745Sheppo #include <sys/mac.h> 59ba2e4443Sseb #include <sys/mac_ether.h> 601ae08745Sheppo #include <sys/taskq.h> 611ae08745Sheppo #include <sys/note.h> 621ae08745Sheppo #include <sys/mach_descrip.h> 631ae08745Sheppo #include <sys/mac.h> 641ae08745Sheppo #include <sys/mdeg.h> 651ae08745Sheppo #include <sys/ldc.h> 661ae08745Sheppo #include <sys/vsw_fdb.h> 671ae08745Sheppo #include <sys/vsw.h> 681ae08745Sheppo #include <sys/vio_mailbox.h> 691ae08745Sheppo #include <sys/vnet_mailbox.h> 701ae08745Sheppo #include <sys/vnet_common.h> 71d10e4ef2Snarayan #include <sys/vio_util.h> 72d10e4ef2Snarayan #include <sys/sdt.h> 7319b65a69Ssb155480 #include <sys/atomic.h> 7406db247cSraghuram #include <sys/callb.h> 751ae08745Sheppo 761ae08745Sheppo /* 771ae08745Sheppo * Function prototypes. 781ae08745Sheppo */ 791ae08745Sheppo static int vsw_attach(dev_info_t *, ddi_attach_cmd_t); 801ae08745Sheppo static int vsw_detach(dev_info_t *, ddi_detach_cmd_t); 811ae08745Sheppo static int vsw_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 8234683adeSsg70180 static int vsw_get_md_physname(vsw_t *, md_t *, mde_cookie_t, char *); 8334683adeSsg70180 static int vsw_get_md_smodes(vsw_t *, md_t *, mde_cookie_t, uint8_t *, int *); 841ae08745Sheppo 851ae08745Sheppo /* MDEG routines */ 8634683adeSsg70180 static int vsw_mdeg_register(vsw_t *vswp); 871ae08745Sheppo static void vsw_mdeg_unregister(vsw_t *vswp); 881ae08745Sheppo static int vsw_mdeg_cb(void *cb_argp, mdeg_result_t *); 8934683adeSsg70180 static int vsw_port_mdeg_cb(void *cb_argp, mdeg_result_t *); 9019b65a69Ssb155480 static int vsw_get_initial_md_properties(vsw_t *vswp, md_t *, mde_cookie_t); 91f0ca1d9aSsb155480 static void vsw_read_pri_eth_types(vsw_t *vswp, md_t *mdp, 92f0ca1d9aSsb155480 mde_cookie_t node); 9334683adeSsg70180 static void vsw_update_md_prop(vsw_t *, md_t *, mde_cookie_t); 9419b65a69Ssb155480 static int vsw_read_mdprops(vsw_t *vswp); 9519b65a69Ssb155480 static void vsw_save_lmacaddr(vsw_t *vswp, uint64_t macaddr); 961ae08745Sheppo 9706db247cSraghuram /* Mac driver related routines */ 9806db247cSraghuram static int vsw_mac_register(vsw_t *); 9906db247cSraghuram static int vsw_mac_unregister(vsw_t *); 10006db247cSraghuram static int vsw_m_stat(void *, uint_t, uint64_t *); 10106db247cSraghuram static void vsw_m_stop(void *arg); 10206db247cSraghuram static int vsw_m_start(void *arg); 10306db247cSraghuram static int vsw_m_unicst(void *arg, const uint8_t *); 10406db247cSraghuram static int vsw_m_multicst(void *arg, boolean_t, const uint8_t *); 10506db247cSraghuram static int vsw_m_promisc(void *arg, boolean_t); 10606db247cSraghuram static mblk_t *vsw_m_tx(void *arg, mblk_t *); 107f0ca1d9aSsb155480 void vsw_mac_rx(vsw_t *vswp, mac_resource_handle_t mrh, 108f0ca1d9aSsb155480 mblk_t *mp, vsw_macrx_flags_t flags); 1091ae08745Sheppo 11006db247cSraghuram /* 11106db247cSraghuram * Functions imported from other files. 11206db247cSraghuram */ 11306db247cSraghuram extern void vsw_setup_switching_timeout(void *arg); 11406db247cSraghuram extern void vsw_stop_switching_timeout(vsw_t *vswp); 11506db247cSraghuram extern int vsw_setup_switching(vsw_t *); 11606db247cSraghuram extern int vsw_add_mcst(vsw_t *, uint8_t, uint64_t, void *); 11706db247cSraghuram extern int vsw_del_mcst(vsw_t *, uint8_t, uint64_t, void *); 11806db247cSraghuram extern void vsw_del_mcst_vsw(vsw_t *); 11906db247cSraghuram extern mcst_addr_t *vsw_del_addr(uint8_t devtype, void *arg, uint64_t addr); 12006db247cSraghuram extern int vsw_detach_ports(vsw_t *vswp); 12106db247cSraghuram extern int vsw_port_add(vsw_t *vswp, md_t *mdp, mde_cookie_t *node); 12206db247cSraghuram extern int vsw_port_detach(vsw_t *vswp, int p_instance); 12306db247cSraghuram extern int vsw_port_attach(vsw_t *vswp, int p_instance, 12406db247cSraghuram uint64_t *ldcids, int nids, struct ether_addr *macaddr); 12506db247cSraghuram extern vsw_port_t *vsw_lookup_port(vsw_t *vswp, int p_instance); 12606db247cSraghuram extern int vsw_mac_attach(vsw_t *vswp); 12706db247cSraghuram extern void vsw_mac_detach(vsw_t *vswp); 12806db247cSraghuram extern int vsw_mac_open(vsw_t *vswp); 12906db247cSraghuram extern void vsw_mac_close(vsw_t *vswp); 13006db247cSraghuram extern int vsw_set_hw(vsw_t *, vsw_port_t *, int); 13106db247cSraghuram extern int vsw_unset_hw(vsw_t *, vsw_port_t *, int); 13206db247cSraghuram extern void vsw_reconfig_hw(vsw_t *); 13306db247cSraghuram extern void vsw_unset_addrs(vsw_t *vswp); 13406db247cSraghuram extern void vsw_set_addrs(vsw_t *vswp); 13506db247cSraghuram 13606db247cSraghuram 13706db247cSraghuram /* 13806db247cSraghuram * Internal tunables. 13906db247cSraghuram */ 140445b4c2eSsb155480 int vsw_num_handshakes = VNET_NUM_HANDSHAKES; /* # of handshake attempts */ 1411ae08745Sheppo int vsw_wretries = 100; /* # of write attempts */ 142d10e4ef2Snarayan int vsw_desc_delay = 0; /* delay in us */ 143d10e4ef2Snarayan int vsw_read_attempts = 5; /* # of reads of descriptor */ 14419b65a69Ssb155480 int vsw_mac_open_retries = 20; /* max # of mac_open() retries */ 14519b65a69Ssb155480 int vsw_setup_switching_delay = 3; /* setup sw timeout interval in sec */ 14606db247cSraghuram int vsw_ldc_tx_delay = 5; /* delay(ticks) for tx retries */ 14706db247cSraghuram int vsw_ldc_tx_retries = 10; /* # of ldc tx retries */ 14806db247cSraghuram boolean_t vsw_ldc_rxthr_enabled = B_TRUE; /* LDC Rx thread enabled */ 14906db247cSraghuram boolean_t vsw_ldc_txthr_enabled = B_TRUE; /* LDC Tx thread enabled */ 150d10e4ef2Snarayan 151f0ca1d9aSsb155480 /* 152f0ca1d9aSsb155480 * Workaround for a version handshake bug in obp's vnet. 153f0ca1d9aSsb155480 * If vsw initiates version negotiation starting from the highest version, 154f0ca1d9aSsb155480 * obp sends a nack and terminates version handshake. To workaround 155f0ca1d9aSsb155480 * this, we do not initiate version handshake when the channel comes up. 156f0ca1d9aSsb155480 * Instead, we wait for the peer to send its version info msg and go through 157f0ca1d9aSsb155480 * the version protocol exchange. If we successfully negotiate a version, 158f0ca1d9aSsb155480 * before sending the ack, we send our version info msg to the peer 159f0ca1d9aSsb155480 * using the <major,minor> version that we are about to ack. 160f0ca1d9aSsb155480 */ 161f0ca1d9aSsb155480 boolean_t vsw_obp_ver_proto_workaround = B_TRUE; 162f0ca1d9aSsb155480 163f0ca1d9aSsb155480 /* 164f0ca1d9aSsb155480 * In the absence of "priority-ether-types" property in MD, the following 165f0ca1d9aSsb155480 * internal tunable can be set to specify a single priority ethertype. 166f0ca1d9aSsb155480 */ 167f0ca1d9aSsb155480 uint64_t vsw_pri_eth_type = 0; 168f0ca1d9aSsb155480 169f0ca1d9aSsb155480 /* 170f0ca1d9aSsb155480 * Number of transmit priority buffers that are preallocated per device. 171f0ca1d9aSsb155480 * This number is chosen to be a small value to throttle transmission 172f0ca1d9aSsb155480 * of priority packets. Note: Must be a power of 2 for vio_create_mblks(). 173f0ca1d9aSsb155480 */ 174f0ca1d9aSsb155480 uint32_t vsw_pri_tx_nmblks = 64; 175d10e4ef2Snarayan 17606db247cSraghuram /* 17706db247cSraghuram * External tunables. 17806db247cSraghuram */ 17906db247cSraghuram /* 18006db247cSraghuram * Enable/disable thread per ring. This is a mode selection 18106db247cSraghuram * that is done a vsw driver attach time. 18206db247cSraghuram */ 18306db247cSraghuram boolean_t vsw_multi_ring_enable = B_FALSE; 18406db247cSraghuram int vsw_mac_rx_rings = VSW_MAC_RX_RINGS; 18506db247cSraghuram 186f0ca1d9aSsb155480 /* Number of transmit descriptors - must be power of 2 */ 187f0ca1d9aSsb155480 uint32_t vsw_ntxds = VSW_RING_NUM_EL; 188f0ca1d9aSsb155480 18906db247cSraghuram /* 19006db247cSraghuram * Max number of mblks received in one receive operation. 19106db247cSraghuram */ 19206db247cSraghuram uint32_t vsw_chain_len = (VSW_NUM_MBLKS * 0.6); 19306db247cSraghuram 19406db247cSraghuram /* 19506db247cSraghuram * Tunables for three different pools, that is, the size and 19606db247cSraghuram * number of mblks for each pool. 19706db247cSraghuram */ 19806db247cSraghuram uint32_t vsw_mblk_size1 = VSW_MBLK_SZ_128; /* size=128 for pool1 */ 19906db247cSraghuram uint32_t vsw_mblk_size2 = VSW_MBLK_SZ_256; /* size=256 for pool2 */ 20006db247cSraghuram uint32_t vsw_mblk_size3 = VSW_MBLK_SZ_2048; /* size=2048 for pool3 */ 20106db247cSraghuram uint32_t vsw_num_mblks1 = VSW_NUM_MBLKS; /* number of mblks for pool1 */ 20206db247cSraghuram uint32_t vsw_num_mblks2 = VSW_NUM_MBLKS; /* number of mblks for pool2 */ 20306db247cSraghuram uint32_t vsw_num_mblks3 = VSW_NUM_MBLKS; /* number of mblks for pool3 */ 20406db247cSraghuram 20506db247cSraghuram /* 206f0ca1d9aSsb155480 * vsw_max_tx_qcount is the maximum # of packets that can be queued 207f0ca1d9aSsb155480 * before the tx worker thread begins processing the queue. Its value 208f0ca1d9aSsb155480 * is chosen to be 4x the default length of tx descriptor ring. 209f0ca1d9aSsb155480 */ 210f0ca1d9aSsb155480 uint32_t vsw_max_tx_qcount = 4 * VSW_RING_NUM_EL; 211f0ca1d9aSsb155480 212f0ca1d9aSsb155480 /* 21306db247cSraghuram * MAC callbacks 21406db247cSraghuram */ 215ba2e4443Sseb static mac_callbacks_t vsw_m_callbacks = { 216ba2e4443Sseb 0, 217ba2e4443Sseb vsw_m_stat, 218ba2e4443Sseb vsw_m_start, 219ba2e4443Sseb vsw_m_stop, 220ba2e4443Sseb vsw_m_promisc, 221ba2e4443Sseb vsw_m_multicst, 222ba2e4443Sseb vsw_m_unicst, 223ba2e4443Sseb vsw_m_tx, 224ba2e4443Sseb NULL, 225ba2e4443Sseb NULL, 226ba2e4443Sseb NULL 227ba2e4443Sseb }; 228ba2e4443Sseb 2291ae08745Sheppo static struct cb_ops vsw_cb_ops = { 2301ae08745Sheppo nulldev, /* cb_open */ 2311ae08745Sheppo nulldev, /* cb_close */ 2321ae08745Sheppo nodev, /* cb_strategy */ 2331ae08745Sheppo nodev, /* cb_print */ 2341ae08745Sheppo nodev, /* cb_dump */ 2351ae08745Sheppo nodev, /* cb_read */ 2361ae08745Sheppo nodev, /* cb_write */ 2371ae08745Sheppo nodev, /* cb_ioctl */ 2381ae08745Sheppo nodev, /* cb_devmap */ 2391ae08745Sheppo nodev, /* cb_mmap */ 2401ae08745Sheppo nodev, /* cb_segmap */ 2411ae08745Sheppo nochpoll, /* cb_chpoll */ 2421ae08745Sheppo ddi_prop_op, /* cb_prop_op */ 2431ae08745Sheppo NULL, /* cb_stream */ 2441ae08745Sheppo D_MP, /* cb_flag */ 2451ae08745Sheppo CB_REV, /* rev */ 2461ae08745Sheppo nodev, /* int (*cb_aread)() */ 2471ae08745Sheppo nodev /* int (*cb_awrite)() */ 2481ae08745Sheppo }; 2491ae08745Sheppo 2501ae08745Sheppo static struct dev_ops vsw_ops = { 2511ae08745Sheppo DEVO_REV, /* devo_rev */ 2521ae08745Sheppo 0, /* devo_refcnt */ 2531ae08745Sheppo vsw_getinfo, /* devo_getinfo */ 2541ae08745Sheppo nulldev, /* devo_identify */ 2551ae08745Sheppo nulldev, /* devo_probe */ 2561ae08745Sheppo vsw_attach, /* devo_attach */ 2571ae08745Sheppo vsw_detach, /* devo_detach */ 2581ae08745Sheppo nodev, /* devo_reset */ 2591ae08745Sheppo &vsw_cb_ops, /* devo_cb_ops */ 2601ae08745Sheppo (struct bus_ops *)NULL, /* devo_bus_ops */ 2611ae08745Sheppo ddi_power /* devo_power */ 2621ae08745Sheppo }; 2631ae08745Sheppo 2641ae08745Sheppo extern struct mod_ops mod_driverops; 2651ae08745Sheppo static struct modldrv vswmodldrv = { 2661ae08745Sheppo &mod_driverops, 267205eeb1aSlm66018 "sun4v Virtual Switch", 2681ae08745Sheppo &vsw_ops, 2691ae08745Sheppo }; 2701ae08745Sheppo 2711ae08745Sheppo #define LDC_ENTER_LOCK(ldcp) \ 2721ae08745Sheppo mutex_enter(&((ldcp)->ldc_cblock));\ 27306db247cSraghuram mutex_enter(&((ldcp)->ldc_rxlock));\ 2741ae08745Sheppo mutex_enter(&((ldcp)->ldc_txlock)); 2751ae08745Sheppo #define LDC_EXIT_LOCK(ldcp) \ 2761ae08745Sheppo mutex_exit(&((ldcp)->ldc_txlock));\ 27706db247cSraghuram mutex_exit(&((ldcp)->ldc_rxlock));\ 2781ae08745Sheppo mutex_exit(&((ldcp)->ldc_cblock)); 2791ae08745Sheppo 2801ae08745Sheppo /* Driver soft state ptr */ 2811ae08745Sheppo static void *vsw_state; 2821ae08745Sheppo 2831ae08745Sheppo /* 2841ae08745Sheppo * Linked list of "vsw_t" structures - one per instance. 2851ae08745Sheppo */ 2861ae08745Sheppo vsw_t *vsw_head = NULL; 2871ae08745Sheppo krwlock_t vsw_rw; 2881ae08745Sheppo 2891ae08745Sheppo /* 2901ae08745Sheppo * Property names 2911ae08745Sheppo */ 2921ae08745Sheppo static char vdev_propname[] = "virtual-device"; 2931ae08745Sheppo static char vsw_propname[] = "virtual-network-switch"; 2941ae08745Sheppo static char physdev_propname[] = "vsw-phys-dev"; 2951ae08745Sheppo static char smode_propname[] = "vsw-switch-mode"; 2961ae08745Sheppo static char macaddr_propname[] = "local-mac-address"; 2971ae08745Sheppo static char remaddr_propname[] = "remote-mac-address"; 2981ae08745Sheppo static char ldcids_propname[] = "ldc-ids"; 2991ae08745Sheppo static char chan_propname[] = "channel-endpoint"; 3001ae08745Sheppo static char id_propname[] = "id"; 3011ae08745Sheppo static char reg_propname[] = "reg"; 302f0ca1d9aSsb155480 static char pri_types_propname[] = "priority-ether-types"; 3031ae08745Sheppo 3041ae08745Sheppo /* 3051ae08745Sheppo * Matching criteria passed to the MDEG to register interest 3061ae08745Sheppo * in changes to 'virtual-device-port' nodes identified by their 3071ae08745Sheppo * 'id' property. 3081ae08745Sheppo */ 3091ae08745Sheppo static md_prop_match_t vport_prop_match[] = { 3101ae08745Sheppo { MDET_PROP_VAL, "id" }, 3111ae08745Sheppo { MDET_LIST_END, NULL } 3121ae08745Sheppo }; 3131ae08745Sheppo 3141ae08745Sheppo static mdeg_node_match_t vport_match = { "virtual-device-port", 3151ae08745Sheppo vport_prop_match }; 3161ae08745Sheppo 3171ae08745Sheppo /* 31834683adeSsg70180 * Matching criteria passed to the MDEG to register interest 31934683adeSsg70180 * in changes to 'virtual-device' nodes (i.e. vsw nodes) identified 32034683adeSsg70180 * by their 'name' and 'cfg-handle' properties. 32134683adeSsg70180 */ 32234683adeSsg70180 static md_prop_match_t vdev_prop_match[] = { 32334683adeSsg70180 { MDET_PROP_STR, "name" }, 32434683adeSsg70180 { MDET_PROP_VAL, "cfg-handle" }, 32534683adeSsg70180 { MDET_LIST_END, NULL } 32634683adeSsg70180 }; 32734683adeSsg70180 32834683adeSsg70180 static mdeg_node_match_t vdev_match = { "virtual-device", 32934683adeSsg70180 vdev_prop_match }; 33034683adeSsg70180 33134683adeSsg70180 33234683adeSsg70180 /* 3331ae08745Sheppo * Specification of an MD node passed to the MDEG to filter any 3341ae08745Sheppo * 'vport' nodes that do not belong to the specified node. This 3351ae08745Sheppo * template is copied for each vsw instance and filled in with 3361ae08745Sheppo * the appropriate 'cfg-handle' value before being passed to the MDEG. 3371ae08745Sheppo */ 3381ae08745Sheppo static mdeg_prop_spec_t vsw_prop_template[] = { 3391ae08745Sheppo { MDET_PROP_STR, "name", vsw_propname }, 3401ae08745Sheppo { MDET_PROP_VAL, "cfg-handle", NULL }, 3411ae08745Sheppo { MDET_LIST_END, NULL, NULL } 3421ae08745Sheppo }; 3431ae08745Sheppo 3441ae08745Sheppo #define VSW_SET_MDEG_PROP_INST(specp, val) (specp)[1].ps_val = (val); 3451ae08745Sheppo 34606db247cSraghuram #ifdef DEBUG 3477636cb21Slm66018 /* 3481ae08745Sheppo * Print debug messages - set to 0x1f to enable all msgs 3491ae08745Sheppo * or 0x0 to turn all off. 3501ae08745Sheppo */ 3511ae08745Sheppo int vswdbg = 0x0; 3521ae08745Sheppo 3531ae08745Sheppo /* 3541ae08745Sheppo * debug levels: 3551ae08745Sheppo * 0x01: Function entry/exit tracing 3561ae08745Sheppo * 0x02: Internal function messages 3571ae08745Sheppo * 0x04: Verbose internal messages 3581ae08745Sheppo * 0x08: Warning messages 3591ae08745Sheppo * 0x10: Error messages 3601ae08745Sheppo */ 3611ae08745Sheppo 36206db247cSraghuram void 3631ae08745Sheppo vswdebug(vsw_t *vswp, const char *fmt, ...) 3641ae08745Sheppo { 3651ae08745Sheppo char buf[512]; 3661ae08745Sheppo va_list ap; 3671ae08745Sheppo 3681ae08745Sheppo va_start(ap, fmt); 3691ae08745Sheppo (void) vsprintf(buf, fmt, ap); 3701ae08745Sheppo va_end(ap); 3711ae08745Sheppo 3721ae08745Sheppo if (vswp == NULL) 3731ae08745Sheppo cmn_err(CE_CONT, "%s\n", buf); 3741ae08745Sheppo else 3751ae08745Sheppo cmn_err(CE_CONT, "vsw%d: %s\n", vswp->instance, buf); 3761ae08745Sheppo } 3771ae08745Sheppo 3781ae08745Sheppo #endif /* DEBUG */ 3791ae08745Sheppo 3801ae08745Sheppo static struct modlinkage modlinkage = { 3811ae08745Sheppo MODREV_1, 3821ae08745Sheppo &vswmodldrv, 3831ae08745Sheppo NULL 3841ae08745Sheppo }; 3851ae08745Sheppo 3861ae08745Sheppo int 3871ae08745Sheppo _init(void) 3881ae08745Sheppo { 3891ae08745Sheppo int status; 3901ae08745Sheppo 3911ae08745Sheppo rw_init(&vsw_rw, NULL, RW_DRIVER, NULL); 3921ae08745Sheppo 3931ae08745Sheppo status = ddi_soft_state_init(&vsw_state, sizeof (vsw_t), 1); 3941ae08745Sheppo if (status != 0) { 3951ae08745Sheppo return (status); 3961ae08745Sheppo } 3971ae08745Sheppo 39806db247cSraghuram mac_init_ops(&vsw_ops, DRV_NAME); 3991ae08745Sheppo status = mod_install(&modlinkage); 4001ae08745Sheppo if (status != 0) { 4011ae08745Sheppo ddi_soft_state_fini(&vsw_state); 4021ae08745Sheppo } 4031ae08745Sheppo return (status); 4041ae08745Sheppo } 4051ae08745Sheppo 4061ae08745Sheppo int 4071ae08745Sheppo _fini(void) 4081ae08745Sheppo { 4091ae08745Sheppo int status; 4101ae08745Sheppo 4111ae08745Sheppo status = mod_remove(&modlinkage); 4121ae08745Sheppo if (status != 0) 4131ae08745Sheppo return (status); 4141ae08745Sheppo mac_fini_ops(&vsw_ops); 4151ae08745Sheppo ddi_soft_state_fini(&vsw_state); 4161ae08745Sheppo 4171ae08745Sheppo rw_destroy(&vsw_rw); 4181ae08745Sheppo 4191ae08745Sheppo return (status); 4201ae08745Sheppo } 4211ae08745Sheppo 4221ae08745Sheppo int 4231ae08745Sheppo _info(struct modinfo *modinfop) 4241ae08745Sheppo { 4251ae08745Sheppo return (mod_info(&modlinkage, modinfop)); 4261ae08745Sheppo } 4271ae08745Sheppo 4281ae08745Sheppo static int 4291ae08745Sheppo vsw_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 4301ae08745Sheppo { 4311ae08745Sheppo vsw_t *vswp; 43234683adeSsg70180 int instance; 4331ae08745Sheppo char hashname[MAXNAMELEN]; 4341ae08745Sheppo char qname[TASKQ_NAMELEN]; 4357636cb21Slm66018 enum { PROG_init = 0x00, 43619b65a69Ssb155480 PROG_locks = 0x01, 43719b65a69Ssb155480 PROG_readmd = 0x02, 43819b65a69Ssb155480 PROG_fdb = 0x04, 43919b65a69Ssb155480 PROG_mfdb = 0x08, 44019b65a69Ssb155480 PROG_taskq = 0x10, 441f0ca1d9aSsb155480 PROG_swmode = 0x20, 442f0ca1d9aSsb155480 PROG_macreg = 0x40, 443f0ca1d9aSsb155480 PROG_mdreg = 0x80} 4441ae08745Sheppo progress; 4451ae08745Sheppo 4461ae08745Sheppo progress = PROG_init; 44719b65a69Ssb155480 int rv; 4481ae08745Sheppo 4491ae08745Sheppo switch (cmd) { 4501ae08745Sheppo case DDI_ATTACH: 4511ae08745Sheppo break; 4521ae08745Sheppo case DDI_RESUME: 4531ae08745Sheppo /* nothing to do for this non-device */ 4541ae08745Sheppo return (DDI_SUCCESS); 4551ae08745Sheppo case DDI_PM_RESUME: 4561ae08745Sheppo default: 4571ae08745Sheppo return (DDI_FAILURE); 4581ae08745Sheppo } 4591ae08745Sheppo 4601ae08745Sheppo instance = ddi_get_instance(dip); 4611ae08745Sheppo if (ddi_soft_state_zalloc(vsw_state, instance) != DDI_SUCCESS) { 4621ae08745Sheppo DERR(NULL, "vsw%d: ddi_soft_state_zalloc failed", instance); 4631ae08745Sheppo return (DDI_FAILURE); 4641ae08745Sheppo } 4651ae08745Sheppo vswp = ddi_get_soft_state(vsw_state, instance); 4661ae08745Sheppo 4671ae08745Sheppo if (vswp == NULL) { 4681ae08745Sheppo DERR(NULL, "vsw%d: ddi_get_soft_state failed", instance); 4691ae08745Sheppo goto vsw_attach_fail; 4701ae08745Sheppo } 4711ae08745Sheppo 4721ae08745Sheppo vswp->dip = dip; 4731ae08745Sheppo vswp->instance = instance; 4741ae08745Sheppo ddi_set_driver_private(dip, (caddr_t)vswp); 4751ae08745Sheppo 4765f94e909Ssg70180 mutex_init(&vswp->hw_lock, NULL, MUTEX_DRIVER, NULL); 47734683adeSsg70180 mutex_init(&vswp->mac_lock, NULL, MUTEX_DRIVER, NULL); 47819b65a69Ssb155480 mutex_init(&vswp->mca_lock, NULL, MUTEX_DRIVER, NULL); 47919b65a69Ssb155480 mutex_init(&vswp->swtmout_lock, NULL, MUTEX_DRIVER, NULL); 4801ae08745Sheppo rw_init(&vswp->if_lockrw, NULL, RW_DRIVER, NULL); 48119b65a69Ssb155480 rw_init(&vswp->mfdbrw, NULL, RW_DRIVER, NULL); 48219b65a69Ssb155480 rw_init(&vswp->plist.lockrw, NULL, RW_DRIVER, NULL); 48319b65a69Ssb155480 48419b65a69Ssb155480 progress |= PROG_locks; 48519b65a69Ssb155480 48619b65a69Ssb155480 rv = vsw_read_mdprops(vswp); 48719b65a69Ssb155480 if (rv != 0) 48819b65a69Ssb155480 goto vsw_attach_fail; 48919b65a69Ssb155480 49019b65a69Ssb155480 progress |= PROG_readmd; 4911ae08745Sheppo 4921ae08745Sheppo /* setup the unicast forwarding database */ 4931ae08745Sheppo (void) snprintf(hashname, MAXNAMELEN, "vsw_unicst_table-%d", 4941ae08745Sheppo vswp->instance); 4951ae08745Sheppo D2(vswp, "creating unicast hash table (%s)...", hashname); 4961ae08745Sheppo vswp->fdb = mod_hash_create_ptrhash(hashname, VSW_NCHAINS, 4971ae08745Sheppo mod_hash_null_valdtor, sizeof (void *)); 4981ae08745Sheppo 4991ae08745Sheppo progress |= PROG_fdb; 5001ae08745Sheppo 5011ae08745Sheppo /* setup the multicast fowarding database */ 5021ae08745Sheppo (void) snprintf(hashname, MAXNAMELEN, "vsw_mcst_table-%d", 5031ae08745Sheppo vswp->instance); 5041ae08745Sheppo D2(vswp, "creating multicast hash table %s)...", hashname); 5051ae08745Sheppo vswp->mfdb = mod_hash_create_ptrhash(hashname, VSW_NCHAINS, 5061ae08745Sheppo mod_hash_null_valdtor, sizeof (void *)); 5071ae08745Sheppo 5081ae08745Sheppo progress |= PROG_mfdb; 5091ae08745Sheppo 5101ae08745Sheppo /* 5111ae08745Sheppo * Create the taskq which will process all the VIO 5121ae08745Sheppo * control messages. 5131ae08745Sheppo */ 5141ae08745Sheppo (void) snprintf(qname, TASKQ_NAMELEN, "vsw_taskq%d", vswp->instance); 5151ae08745Sheppo if ((vswp->taskq_p = ddi_taskq_create(vswp->dip, qname, 1, 5161ae08745Sheppo TASKQ_DEFAULTPRI, 0)) == NULL) { 51734683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to create task queue", 51834683adeSsg70180 vswp->instance); 5191ae08745Sheppo goto vsw_attach_fail; 5201ae08745Sheppo } 5211ae08745Sheppo 5221ae08745Sheppo progress |= PROG_taskq; 5231ae08745Sheppo 524d10e4ef2Snarayan /* prevent auto-detaching */ 525d10e4ef2Snarayan if (ddi_prop_update_int(DDI_DEV_T_NONE, vswp->dip, 526d10e4ef2Snarayan DDI_NO_AUTODETACH, 1) != DDI_SUCCESS) { 52734683adeSsg70180 cmn_err(CE_NOTE, "!Unable to set \"%s\" property for " 528d10e4ef2Snarayan "instance %u", DDI_NO_AUTODETACH, instance); 529d10e4ef2Snarayan } 530d10e4ef2Snarayan 5311ae08745Sheppo /* 53219b65a69Ssb155480 * Setup the required switching mode, 53319b65a69Ssb155480 * based on the mdprops that we read earlier. 53419b65a69Ssb155480 */ 53519b65a69Ssb155480 rv = vsw_setup_switching(vswp); 53619b65a69Ssb155480 if (rv == EAGAIN) { 53719b65a69Ssb155480 /* 53819b65a69Ssb155480 * Unable to setup switching mode; 53919b65a69Ssb155480 * as the error is EAGAIN, schedule a timeout to retry. 54019b65a69Ssb155480 */ 54119b65a69Ssb155480 mutex_enter(&vswp->swtmout_lock); 54219b65a69Ssb155480 54319b65a69Ssb155480 vswp->swtmout_enabled = B_TRUE; 54419b65a69Ssb155480 vswp->swtmout_id = 54519b65a69Ssb155480 timeout(vsw_setup_switching_timeout, vswp, 54619b65a69Ssb155480 (vsw_setup_switching_delay * drv_usectohz(MICROSEC))); 54719b65a69Ssb155480 54819b65a69Ssb155480 mutex_exit(&vswp->swtmout_lock); 54919b65a69Ssb155480 } else if (rv != 0) { 55019b65a69Ssb155480 goto vsw_attach_fail; 55119b65a69Ssb155480 } 55219b65a69Ssb155480 55319b65a69Ssb155480 progress |= PROG_swmode; 55419b65a69Ssb155480 55519b65a69Ssb155480 /* Register with mac layer as a provider */ 55619b65a69Ssb155480 rv = vsw_mac_register(vswp); 55719b65a69Ssb155480 if (rv != 0) 55819b65a69Ssb155480 goto vsw_attach_fail; 55919b65a69Ssb155480 56019b65a69Ssb155480 progress |= PROG_macreg; 56119b65a69Ssb155480 56219b65a69Ssb155480 /* 56334683adeSsg70180 * Now we have everything setup, register an interest in 56434683adeSsg70180 * specific MD nodes. 56534683adeSsg70180 * 56634683adeSsg70180 * The callback is invoked in 2 cases, firstly if upon mdeg 56734683adeSsg70180 * registration there are existing nodes which match our specified 56834683adeSsg70180 * criteria, and secondly if the MD is changed (and again, there 56934683adeSsg70180 * are nodes which we are interested in present within it. Note 57034683adeSsg70180 * that our callback will be invoked even if our specified nodes 57134683adeSsg70180 * have not actually changed). 57234683adeSsg70180 * 5731ae08745Sheppo */ 57419b65a69Ssb155480 rv = vsw_mdeg_register(vswp); 57519b65a69Ssb155480 if (rv != 0) 57634683adeSsg70180 goto vsw_attach_fail; 5771ae08745Sheppo 57819b65a69Ssb155480 progress |= PROG_mdreg; 57919b65a69Ssb155480 58019b65a69Ssb155480 WRITE_ENTER(&vsw_rw); 58119b65a69Ssb155480 vswp->next = vsw_head; 58219b65a69Ssb155480 vsw_head = vswp; 58319b65a69Ssb155480 RW_EXIT(&vsw_rw); 58419b65a69Ssb155480 58519b65a69Ssb155480 ddi_report_dev(vswp->dip); 5861ae08745Sheppo return (DDI_SUCCESS); 5871ae08745Sheppo 5881ae08745Sheppo vsw_attach_fail: 5891ae08745Sheppo DERR(NULL, "vsw_attach: failed"); 5901ae08745Sheppo 59119b65a69Ssb155480 if (progress & PROG_mdreg) { 59219b65a69Ssb155480 vsw_mdeg_unregister(vswp); 59319b65a69Ssb155480 (void) vsw_detach_ports(vswp); 59419b65a69Ssb155480 } 59519b65a69Ssb155480 59619b65a69Ssb155480 if (progress & PROG_macreg) 59719b65a69Ssb155480 (void) vsw_mac_unregister(vswp); 59819b65a69Ssb155480 59919b65a69Ssb155480 if (progress & PROG_swmode) { 60019b65a69Ssb155480 vsw_stop_switching_timeout(vswp); 60119b65a69Ssb155480 mutex_enter(&vswp->mac_lock); 60219b65a69Ssb155480 vsw_mac_detach(vswp); 60319b65a69Ssb155480 vsw_mac_close(vswp); 60419b65a69Ssb155480 mutex_exit(&vswp->mac_lock); 60519b65a69Ssb155480 } 60619b65a69Ssb155480 6071ae08745Sheppo if (progress & PROG_taskq) 6081ae08745Sheppo ddi_taskq_destroy(vswp->taskq_p); 6091ae08745Sheppo 61019b65a69Ssb155480 if (progress & PROG_mfdb) 6111ae08745Sheppo mod_hash_destroy_hash(vswp->mfdb); 6121ae08745Sheppo 61319b65a69Ssb155480 if (progress & PROG_fdb) 6141ae08745Sheppo mod_hash_destroy_hash(vswp->fdb); 6151ae08745Sheppo 616f0ca1d9aSsb155480 if (progress & PROG_readmd) { 617f0ca1d9aSsb155480 if (VSW_PRI_ETH_DEFINED(vswp)) { 618f0ca1d9aSsb155480 kmem_free(vswp->pri_types, 619f0ca1d9aSsb155480 sizeof (uint16_t) * vswp->pri_num_types); 620f0ca1d9aSsb155480 } 621f0ca1d9aSsb155480 (void) vio_destroy_mblks(vswp->pri_tx_vmp); 622f0ca1d9aSsb155480 } 623f0ca1d9aSsb155480 62419b65a69Ssb155480 if (progress & PROG_locks) { 62519b65a69Ssb155480 rw_destroy(&vswp->plist.lockrw); 62619b65a69Ssb155480 rw_destroy(&vswp->mfdbrw); 6271ae08745Sheppo rw_destroy(&vswp->if_lockrw); 62819b65a69Ssb155480 mutex_destroy(&vswp->swtmout_lock); 62919b65a69Ssb155480 mutex_destroy(&vswp->mca_lock); 63034683adeSsg70180 mutex_destroy(&vswp->mac_lock); 6315f94e909Ssg70180 mutex_destroy(&vswp->hw_lock); 63234683adeSsg70180 } 6331ae08745Sheppo 6341ae08745Sheppo ddi_soft_state_free(vsw_state, instance); 6351ae08745Sheppo return (DDI_FAILURE); 6361ae08745Sheppo } 6371ae08745Sheppo 6381ae08745Sheppo static int 6391ae08745Sheppo vsw_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 6401ae08745Sheppo { 641d10e4ef2Snarayan vio_mblk_pool_t *poolp, *npoolp; 6421ae08745Sheppo vsw_t **vswpp, *vswp; 6431ae08745Sheppo int instance; 6441ae08745Sheppo 6451ae08745Sheppo instance = ddi_get_instance(dip); 6461ae08745Sheppo vswp = ddi_get_soft_state(vsw_state, instance); 6471ae08745Sheppo 6481ae08745Sheppo if (vswp == NULL) { 6491ae08745Sheppo return (DDI_FAILURE); 6501ae08745Sheppo } 6511ae08745Sheppo 6521ae08745Sheppo switch (cmd) { 6531ae08745Sheppo case DDI_DETACH: 6541ae08745Sheppo break; 6551ae08745Sheppo case DDI_SUSPEND: 6561ae08745Sheppo case DDI_PM_SUSPEND: 6571ae08745Sheppo default: 6581ae08745Sheppo return (DDI_FAILURE); 6591ae08745Sheppo } 6601ae08745Sheppo 6611ae08745Sheppo D2(vswp, "detaching instance %d", instance); 6621ae08745Sheppo 66319b65a69Ssb155480 /* Stop any pending timeout to setup switching mode. */ 66419b65a69Ssb155480 vsw_stop_switching_timeout(vswp); 66519b65a69Ssb155480 66634683adeSsg70180 if (vswp->if_state & VSW_IF_REG) { 6671ae08745Sheppo if (vsw_mac_unregister(vswp) != 0) { 66834683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to detach from " 66934683adeSsg70180 "MAC layer", vswp->instance); 6701ae08745Sheppo return (DDI_FAILURE); 6711ae08745Sheppo } 672d10e4ef2Snarayan } 6731ae08745Sheppo 6741ae08745Sheppo vsw_mdeg_unregister(vswp); 6751ae08745Sheppo 676e1ebb9ecSlm66018 /* remove mac layer callback */ 67734683adeSsg70180 mutex_enter(&vswp->mac_lock); 678e1ebb9ecSlm66018 if ((vswp->mh != NULL) && (vswp->mrh != NULL)) { 6791f8aaf0dSethindra mac_rx_remove(vswp->mh, vswp->mrh, B_TRUE); 680e1ebb9ecSlm66018 vswp->mrh = NULL; 6811ae08745Sheppo } 68234683adeSsg70180 mutex_exit(&vswp->mac_lock); 6831ae08745Sheppo 6841ae08745Sheppo if (vsw_detach_ports(vswp) != 0) { 685*1ef0bbb5Snarayan cmn_err(CE_WARN, "!vsw%d: Unable to unconfigure ports", 68634683adeSsg70180 vswp->instance); 6871ae08745Sheppo return (DDI_FAILURE); 6881ae08745Sheppo } 6891ae08745Sheppo 69034683adeSsg70180 rw_destroy(&vswp->if_lockrw); 69134683adeSsg70180 6925f94e909Ssg70180 mutex_destroy(&vswp->hw_lock); 6935f94e909Ssg70180 6941ae08745Sheppo /* 695e1ebb9ecSlm66018 * Now that the ports have been deleted, stop and close 696e1ebb9ecSlm66018 * the physical device. 697e1ebb9ecSlm66018 */ 69834683adeSsg70180 mutex_enter(&vswp->mac_lock); 699e1ebb9ecSlm66018 70019b65a69Ssb155480 vsw_mac_detach(vswp); 70119b65a69Ssb155480 vsw_mac_close(vswp); 70219b65a69Ssb155480 70334683adeSsg70180 mutex_exit(&vswp->mac_lock); 70419b65a69Ssb155480 70534683adeSsg70180 mutex_destroy(&vswp->mac_lock); 70619b65a69Ssb155480 mutex_destroy(&vswp->swtmout_lock); 707e1ebb9ecSlm66018 708e1ebb9ecSlm66018 /* 709d10e4ef2Snarayan * Destroy any free pools that may still exist. 710d10e4ef2Snarayan */ 711d10e4ef2Snarayan poolp = vswp->rxh; 712d10e4ef2Snarayan while (poolp != NULL) { 713d10e4ef2Snarayan npoolp = vswp->rxh = poolp->nextp; 714d10e4ef2Snarayan if (vio_destroy_mblks(poolp) != 0) { 715d10e4ef2Snarayan vswp->rxh = poolp; 716d10e4ef2Snarayan return (DDI_FAILURE); 717d10e4ef2Snarayan } 718d10e4ef2Snarayan poolp = npoolp; 719d10e4ef2Snarayan } 720d10e4ef2Snarayan 721d10e4ef2Snarayan /* 7221ae08745Sheppo * Remove this instance from any entries it may be on in 7231ae08745Sheppo * the hash table by using the list of addresses maintained 7241ae08745Sheppo * in the vsw_t structure. 7251ae08745Sheppo */ 7261ae08745Sheppo vsw_del_mcst_vsw(vswp); 7271ae08745Sheppo 7281ae08745Sheppo vswp->mcap = NULL; 7291ae08745Sheppo mutex_destroy(&vswp->mca_lock); 7301ae08745Sheppo 7311ae08745Sheppo /* 7321ae08745Sheppo * By now any pending tasks have finished and the underlying 7331ae08745Sheppo * ldc's have been destroyed, so its safe to delete the control 7341ae08745Sheppo * message taskq. 7351ae08745Sheppo */ 7361ae08745Sheppo if (vswp->taskq_p != NULL) 7371ae08745Sheppo ddi_taskq_destroy(vswp->taskq_p); 7381ae08745Sheppo 7391ae08745Sheppo /* 7401ae08745Sheppo * At this stage all the data pointers in the hash table 7411ae08745Sheppo * should be NULL, as all the ports have been removed and will 7421ae08745Sheppo * have deleted themselves from the port lists which the data 7431ae08745Sheppo * pointers point to. Hence we can destroy the table using the 7441ae08745Sheppo * default destructors. 7451ae08745Sheppo */ 7461ae08745Sheppo D2(vswp, "vsw_detach: destroying hash tables.."); 7471ae08745Sheppo mod_hash_destroy_hash(vswp->fdb); 7481ae08745Sheppo vswp->fdb = NULL; 7491ae08745Sheppo 7501ae08745Sheppo WRITE_ENTER(&vswp->mfdbrw); 7511ae08745Sheppo mod_hash_destroy_hash(vswp->mfdb); 7521ae08745Sheppo vswp->mfdb = NULL; 7531ae08745Sheppo RW_EXIT(&vswp->mfdbrw); 7541ae08745Sheppo rw_destroy(&vswp->mfdbrw); 7551ae08745Sheppo 756f0ca1d9aSsb155480 /* free pri_types table */ 757f0ca1d9aSsb155480 if (VSW_PRI_ETH_DEFINED(vswp)) { 758f0ca1d9aSsb155480 kmem_free(vswp->pri_types, 759f0ca1d9aSsb155480 sizeof (uint16_t) * vswp->pri_num_types); 760f0ca1d9aSsb155480 (void) vio_destroy_mblks(vswp->pri_tx_vmp); 761f0ca1d9aSsb155480 } 762f0ca1d9aSsb155480 7631ae08745Sheppo ddi_remove_minor_node(dip, NULL); 7641ae08745Sheppo 7651ae08745Sheppo rw_destroy(&vswp->plist.lockrw); 7661ae08745Sheppo WRITE_ENTER(&vsw_rw); 7671ae08745Sheppo for (vswpp = &vsw_head; *vswpp; vswpp = &(*vswpp)->next) { 7681ae08745Sheppo if (*vswpp == vswp) { 7691ae08745Sheppo *vswpp = vswp->next; 7701ae08745Sheppo break; 7711ae08745Sheppo } 7721ae08745Sheppo } 7731ae08745Sheppo RW_EXIT(&vsw_rw); 7741ae08745Sheppo ddi_soft_state_free(vsw_state, instance); 7751ae08745Sheppo 7761ae08745Sheppo return (DDI_SUCCESS); 7771ae08745Sheppo } 7781ae08745Sheppo 7791ae08745Sheppo static int 7801ae08745Sheppo vsw_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 7811ae08745Sheppo { 7821ae08745Sheppo _NOTE(ARGUNUSED(dip)) 7831ae08745Sheppo 7841ae08745Sheppo vsw_t *vswp = NULL; 7851ae08745Sheppo dev_t dev = (dev_t)arg; 7861ae08745Sheppo int instance; 7871ae08745Sheppo 7881ae08745Sheppo instance = getminor(dev); 7891ae08745Sheppo 7901ae08745Sheppo switch (infocmd) { 7911ae08745Sheppo case DDI_INFO_DEVT2DEVINFO: 7921ae08745Sheppo if ((vswp = ddi_get_soft_state(vsw_state, instance)) == NULL) { 7931ae08745Sheppo *result = NULL; 7941ae08745Sheppo return (DDI_FAILURE); 7951ae08745Sheppo } 7961ae08745Sheppo *result = vswp->dip; 7971ae08745Sheppo return (DDI_SUCCESS); 7981ae08745Sheppo 7991ae08745Sheppo case DDI_INFO_DEVT2INSTANCE: 8001ae08745Sheppo *result = (void *)(uintptr_t)instance; 8011ae08745Sheppo return (DDI_SUCCESS); 8021ae08745Sheppo 8031ae08745Sheppo default: 8041ae08745Sheppo *result = NULL; 8051ae08745Sheppo return (DDI_FAILURE); 8061ae08745Sheppo } 8071ae08745Sheppo } 8081ae08745Sheppo 8091ae08745Sheppo /* 81034683adeSsg70180 * Get the value of the "vsw-phys-dev" property in the specified 81134683adeSsg70180 * node. This property is the name of the physical device that 81234683adeSsg70180 * the virtual switch will use to talk to the outside world. 81334683adeSsg70180 * 81434683adeSsg70180 * Note it is valid for this property to be NULL (but the property 81534683adeSsg70180 * itself must exist). Callers of this routine should verify that 81634683adeSsg70180 * the value returned is what they expected (i.e. either NULL or non NULL). 81734683adeSsg70180 * 81834683adeSsg70180 * On success returns value of the property in region pointed to by 81934683adeSsg70180 * the 'name' argument, and with return value of 0. Otherwise returns 1. 8201ae08745Sheppo */ 82134683adeSsg70180 static int 82234683adeSsg70180 vsw_get_md_physname(vsw_t *vswp, md_t *mdp, mde_cookie_t node, char *name) 8231ae08745Sheppo { 82434683adeSsg70180 int len = 0; 825f2b610cfSwentaoy int instance; 8261ae08745Sheppo char *physname = NULL; 8271ae08745Sheppo char *dev; 828f2b610cfSwentaoy const char *dev_name; 829f2b610cfSwentaoy char myname[MAXNAMELEN]; 830f2b610cfSwentaoy 831f2b610cfSwentaoy dev_name = ddi_driver_name(vswp->dip); 832f2b610cfSwentaoy instance = ddi_get_instance(vswp->dip); 833f2b610cfSwentaoy (void) snprintf(myname, MAXNAMELEN, "%s%d", dev_name, instance); 8341ae08745Sheppo 83534683adeSsg70180 if (md_get_prop_data(mdp, node, physdev_propname, 8361ae08745Sheppo (uint8_t **)(&physname), &len) != 0) { 83734683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to get name(s) of physical " 83834683adeSsg70180 "device(s) from MD", vswp->instance); 83934683adeSsg70180 return (1); 8401ae08745Sheppo } else if ((strlen(physname) + 1) > LIFNAMSIZ) { 84134683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: %s is too long a device name", 84234683adeSsg70180 vswp->instance, physname); 84334683adeSsg70180 return (1); 844f2b610cfSwentaoy } else if (strcmp(myname, physname) == 0) { 845f2b610cfSwentaoy /* 846f2b610cfSwentaoy * Prevent the vswitch from opening itself as the 847f2b610cfSwentaoy * network device. 848f2b610cfSwentaoy */ 849f2b610cfSwentaoy cmn_err(CE_WARN, "!vsw%d: %s is an invalid device name", 850f2b610cfSwentaoy vswp->instance, physname); 851f2b610cfSwentaoy return (1); 8521ae08745Sheppo } else { 85334683adeSsg70180 (void) strncpy(name, physname, strlen(physname) + 1); 8541ae08745Sheppo D2(vswp, "%s: using first device specified (%s)", 85534683adeSsg70180 __func__, physname); 8561ae08745Sheppo } 8571ae08745Sheppo 8581ae08745Sheppo #ifdef DEBUG 8591ae08745Sheppo /* 8601ae08745Sheppo * As a temporary measure to aid testing we check to see if there 8611ae08745Sheppo * is a vsw.conf file present. If there is we use the value of the 8621ae08745Sheppo * vsw_physname property in the file as the name of the physical 8631ae08745Sheppo * device, overriding the value from the MD. 8641ae08745Sheppo * 8651ae08745Sheppo * There may be multiple devices listed, but for the moment 8661ae08745Sheppo * we just use the first one. 8671ae08745Sheppo */ 8681ae08745Sheppo if (ddi_prop_lookup_string(DDI_DEV_T_ANY, vswp->dip, 0, 8691ae08745Sheppo "vsw_physname", &dev) == DDI_PROP_SUCCESS) { 8701ae08745Sheppo if ((strlen(dev) + 1) > LIFNAMSIZ) { 87134683adeSsg70180 cmn_err(CE_WARN, "vsw%d: %s is too long a device name", 87234683adeSsg70180 vswp->instance, dev); 87334683adeSsg70180 ddi_prop_free(dev); 87434683adeSsg70180 return (1); 8751ae08745Sheppo } else { 87634683adeSsg70180 cmn_err(CE_NOTE, "vsw%d: Using device name (%s) from " 87734683adeSsg70180 "config file", vswp->instance, dev); 8781ae08745Sheppo 87934683adeSsg70180 (void) strncpy(name, dev, strlen(dev) + 1); 8801ae08745Sheppo } 8811ae08745Sheppo 8821ae08745Sheppo ddi_prop_free(dev); 8831ae08745Sheppo } 8841ae08745Sheppo #endif 8851ae08745Sheppo 88634683adeSsg70180 return (0); 88734683adeSsg70180 } 888e1ebb9ecSlm66018 889e1ebb9ecSlm66018 /* 89034683adeSsg70180 * Read the 'vsw-switch-mode' property from the specified MD node. 89134683adeSsg70180 * 89234683adeSsg70180 * Returns 0 on success and the number of modes found in 'found', 89334683adeSsg70180 * otherwise returns 1. 894e1ebb9ecSlm66018 */ 89534683adeSsg70180 static int 89634683adeSsg70180 vsw_get_md_smodes(vsw_t *vswp, md_t *mdp, mde_cookie_t node, 89734683adeSsg70180 uint8_t *modes, int *found) 89834683adeSsg70180 { 89934683adeSsg70180 int len = 0; 90034683adeSsg70180 int smode_num = 0; 90134683adeSsg70180 char *smode = NULL; 90234683adeSsg70180 char *curr_mode = NULL; 90334683adeSsg70180 90434683adeSsg70180 D1(vswp, "%s: enter", __func__); 9051ae08745Sheppo 9061ae08745Sheppo /* 9071ae08745Sheppo * Get the switch-mode property. The modes are listed in 9081ae08745Sheppo * decreasing order of preference, i.e. prefered mode is 9091ae08745Sheppo * first item in list. 9101ae08745Sheppo */ 9111ae08745Sheppo len = 0; 91234683adeSsg70180 smode_num = 0; 91334683adeSsg70180 if (md_get_prop_data(mdp, node, smode_propname, 9141ae08745Sheppo (uint8_t **)(&smode), &len) != 0) { 9151ae08745Sheppo /* 916e1ebb9ecSlm66018 * Unable to get switch-mode property from MD, nothing 917e1ebb9ecSlm66018 * more we can do. 9181ae08745Sheppo */ 91934683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to get switch mode property" 92034683adeSsg70180 " from the MD", vswp->instance); 92134683adeSsg70180 *found = 0; 92234683adeSsg70180 return (1); 923e1ebb9ecSlm66018 } 924e1ebb9ecSlm66018 9251ae08745Sheppo curr_mode = smode; 9261ae08745Sheppo /* 9271ae08745Sheppo * Modes of operation: 9281ae08745Sheppo * 'switched' - layer 2 switching, underlying HW in 929e1ebb9ecSlm66018 * programmed mode. 9301ae08745Sheppo * 'promiscuous' - layer 2 switching, underlying HW in 9311ae08745Sheppo * promiscuous mode. 9321ae08745Sheppo * 'routed' - layer 3 (i.e. IP) routing, underlying HW 9331ae08745Sheppo * in non-promiscuous mode. 9341ae08745Sheppo */ 93534683adeSsg70180 while ((curr_mode < (smode + len)) && (smode_num < NUM_SMODES)) { 9361ae08745Sheppo D2(vswp, "%s: curr_mode = [%s]", __func__, curr_mode); 937e1ebb9ecSlm66018 if (strcmp(curr_mode, "switched") == 0) { 93834683adeSsg70180 modes[smode_num++] = VSW_LAYER2; 939e1ebb9ecSlm66018 } else if (strcmp(curr_mode, "promiscuous") == 0) { 94034683adeSsg70180 modes[smode_num++] = VSW_LAYER2_PROMISC; 941e1ebb9ecSlm66018 } else if (strcmp(curr_mode, "routed") == 0) { 94234683adeSsg70180 modes[smode_num++] = VSW_LAYER3; 943e1ebb9ecSlm66018 } else { 944*1ef0bbb5Snarayan DWARN(vswp, "%s: Unknown switch mode %s, " 945*1ef0bbb5Snarayan "setting to default 'switched' mode", 946*1ef0bbb5Snarayan __func__, curr_mode); 94734683adeSsg70180 modes[smode_num++] = VSW_LAYER2; 9481ae08745Sheppo } 9491ae08745Sheppo curr_mode += strlen(curr_mode) + 1; 9501ae08745Sheppo } 95134683adeSsg70180 *found = smode_num; 9521ae08745Sheppo 95334683adeSsg70180 D2(vswp, "%s: %d modes found", __func__, smode_num); 9541ae08745Sheppo 9551ae08745Sheppo D1(vswp, "%s: exit", __func__); 95634683adeSsg70180 95734683adeSsg70180 return (0); 9581ae08745Sheppo } 9591ae08745Sheppo 960e1ebb9ecSlm66018 /* 9611ae08745Sheppo * Register with the MAC layer as a network device, so we 9621ae08745Sheppo * can be plumbed if necessary. 9631ae08745Sheppo */ 9641ae08745Sheppo static int 9651ae08745Sheppo vsw_mac_register(vsw_t *vswp) 9661ae08745Sheppo { 967ba2e4443Sseb mac_register_t *macp; 968ba2e4443Sseb int rv; 9691ae08745Sheppo 9701ae08745Sheppo D1(vswp, "%s: enter", __func__); 9711ae08745Sheppo 972ba2e4443Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 973ba2e4443Sseb return (EINVAL); 974ba2e4443Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 9751ae08745Sheppo macp->m_driver = vswp; 976ba2e4443Sseb macp->m_dip = vswp->dip; 977ba2e4443Sseb macp->m_src_addr = (uint8_t *)&vswp->if_addr; 978ba2e4443Sseb macp->m_callbacks = &vsw_m_callbacks; 979ba2e4443Sseb macp->m_min_sdu = 0; 980ba2e4443Sseb macp->m_max_sdu = ETHERMTU; 981ba2e4443Sseb rv = mac_register(macp, &vswp->if_mh); 982ba2e4443Sseb mac_free(macp); 98319b65a69Ssb155480 if (rv != 0) { 98419b65a69Ssb155480 /* 98519b65a69Ssb155480 * Treat this as a non-fatal error as we may be 98619b65a69Ssb155480 * able to operate in some other mode. 98719b65a69Ssb155480 */ 98819b65a69Ssb155480 cmn_err(CE_NOTE, "!vsw%d: Unable to register as " 98919b65a69Ssb155480 "a provider with MAC layer", vswp->instance); 99019b65a69Ssb155480 return (rv); 99119b65a69Ssb155480 } 99219b65a69Ssb155480 993ba2e4443Sseb vswp->if_state |= VSW_IF_REG; 9941ae08745Sheppo 9951ae08745Sheppo D1(vswp, "%s: exit", __func__); 9961ae08745Sheppo 9971ae08745Sheppo return (rv); 9981ae08745Sheppo } 9991ae08745Sheppo 10001ae08745Sheppo static int 10011ae08745Sheppo vsw_mac_unregister(vsw_t *vswp) 10021ae08745Sheppo { 10031ae08745Sheppo int rv = 0; 10041ae08745Sheppo 10051ae08745Sheppo D1(vswp, "%s: enter", __func__); 10061ae08745Sheppo 10071ae08745Sheppo WRITE_ENTER(&vswp->if_lockrw); 10081ae08745Sheppo 1009ba2e4443Sseb if (vswp->if_state & VSW_IF_REG) { 1010ba2e4443Sseb rv = mac_unregister(vswp->if_mh); 10111ae08745Sheppo if (rv != 0) { 10121ae08745Sheppo DWARN(vswp, "%s: unable to unregister from MAC " 10131ae08745Sheppo "framework", __func__); 10141ae08745Sheppo 10151ae08745Sheppo RW_EXIT(&vswp->if_lockrw); 10161ae08745Sheppo D1(vswp, "%s: fail exit", __func__); 10171ae08745Sheppo return (rv); 10181ae08745Sheppo } 10191ae08745Sheppo 1020ba2e4443Sseb /* mark i/f as down and unregistered */ 1021ba2e4443Sseb vswp->if_state &= ~(VSW_IF_UP | VSW_IF_REG); 10221ae08745Sheppo } 10231ae08745Sheppo RW_EXIT(&vswp->if_lockrw); 10241ae08745Sheppo 10251ae08745Sheppo D1(vswp, "%s: exit", __func__); 10261ae08745Sheppo 10271ae08745Sheppo return (rv); 10281ae08745Sheppo } 10291ae08745Sheppo 1030ba2e4443Sseb static int 1031ba2e4443Sseb vsw_m_stat(void *arg, uint_t stat, uint64_t *val) 10321ae08745Sheppo { 10331ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 10341ae08745Sheppo 10351ae08745Sheppo D1(vswp, "%s: enter", __func__); 10361ae08745Sheppo 103734683adeSsg70180 mutex_enter(&vswp->mac_lock); 103834683adeSsg70180 if (vswp->mh == NULL) { 103934683adeSsg70180 mutex_exit(&vswp->mac_lock); 1040ba2e4443Sseb return (EINVAL); 104134683adeSsg70180 } 10421ae08745Sheppo 10431ae08745Sheppo /* return stats from underlying device */ 1044ba2e4443Sseb *val = mac_stat_get(vswp->mh, stat); 104534683adeSsg70180 104634683adeSsg70180 mutex_exit(&vswp->mac_lock); 104734683adeSsg70180 1048ba2e4443Sseb return (0); 10491ae08745Sheppo } 10501ae08745Sheppo 10511ae08745Sheppo static void 10521ae08745Sheppo vsw_m_stop(void *arg) 10531ae08745Sheppo { 10541ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 10551ae08745Sheppo 10561ae08745Sheppo D1(vswp, "%s: enter", __func__); 10571ae08745Sheppo 10581ae08745Sheppo WRITE_ENTER(&vswp->if_lockrw); 10591ae08745Sheppo vswp->if_state &= ~VSW_IF_UP; 10601ae08745Sheppo RW_EXIT(&vswp->if_lockrw); 10611ae08745Sheppo 10625f94e909Ssg70180 mutex_enter(&vswp->hw_lock); 10635f94e909Ssg70180 10645f94e909Ssg70180 (void) vsw_unset_hw(vswp, NULL, VSW_LOCALDEV); 10655f94e909Ssg70180 10665f94e909Ssg70180 if (vswp->recfg_reqd) 10675f94e909Ssg70180 vsw_reconfig_hw(vswp); 10685f94e909Ssg70180 10695f94e909Ssg70180 mutex_exit(&vswp->hw_lock); 10705f94e909Ssg70180 10711ae08745Sheppo D1(vswp, "%s: exit (state = %d)", __func__, vswp->if_state); 10721ae08745Sheppo } 10731ae08745Sheppo 10741ae08745Sheppo static int 10751ae08745Sheppo vsw_m_start(void *arg) 10761ae08745Sheppo { 10771ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 10781ae08745Sheppo 10791ae08745Sheppo D1(vswp, "%s: enter", __func__); 10801ae08745Sheppo 10811ae08745Sheppo WRITE_ENTER(&vswp->if_lockrw); 10821ae08745Sheppo 108319b65a69Ssb155480 vswp->if_state |= VSW_IF_UP; 108419b65a69Ssb155480 108519b65a69Ssb155480 if (vswp->switching_setup_done == B_FALSE) { 108619b65a69Ssb155480 /* 108719b65a69Ssb155480 * If the switching mode has not been setup yet, just 108819b65a69Ssb155480 * return. The unicast address will be programmed 108919b65a69Ssb155480 * after the physical device is successfully setup by the 109019b65a69Ssb155480 * timeout handler. 109119b65a69Ssb155480 */ 109219b65a69Ssb155480 RW_EXIT(&vswp->if_lockrw); 109319b65a69Ssb155480 return (0); 109419b65a69Ssb155480 } 109519b65a69Ssb155480 109619b65a69Ssb155480 /* if in layer2 mode, program unicast address. */ 109719b65a69Ssb155480 if (vswp->mh != NULL) { 10985f94e909Ssg70180 mutex_enter(&vswp->hw_lock); 10995f94e909Ssg70180 (void) vsw_set_hw(vswp, NULL, VSW_LOCALDEV); 11005f94e909Ssg70180 mutex_exit(&vswp->hw_lock); 110119b65a69Ssb155480 } 110219b65a69Ssb155480 110319b65a69Ssb155480 RW_EXIT(&vswp->if_lockrw); 11045f94e909Ssg70180 11051ae08745Sheppo D1(vswp, "%s: exit (state = %d)", __func__, vswp->if_state); 11061ae08745Sheppo return (0); 11071ae08745Sheppo } 11081ae08745Sheppo 11091ae08745Sheppo /* 11101ae08745Sheppo * Change the local interface address. 11115f94e909Ssg70180 * 11125f94e909Ssg70180 * Note: we don't support this entry point. The local 11135f94e909Ssg70180 * mac address of the switch can only be changed via its 11145f94e909Ssg70180 * MD node properties. 11151ae08745Sheppo */ 11161ae08745Sheppo static int 11171ae08745Sheppo vsw_m_unicst(void *arg, const uint8_t *macaddr) 11181ae08745Sheppo { 11195f94e909Ssg70180 _NOTE(ARGUNUSED(arg, macaddr)) 11201ae08745Sheppo 11215f94e909Ssg70180 return (DDI_FAILURE); 11221ae08745Sheppo } 11231ae08745Sheppo 11241ae08745Sheppo static int 11251ae08745Sheppo vsw_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 11261ae08745Sheppo { 11271ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 11281ae08745Sheppo mcst_addr_t *mcst_p = NULL; 11291ae08745Sheppo uint64_t addr = 0x0; 1130e1ebb9ecSlm66018 int i, ret = 0; 11311ae08745Sheppo 11321ae08745Sheppo D1(vswp, "%s: enter", __func__); 11331ae08745Sheppo 11341ae08745Sheppo /* 11351ae08745Sheppo * Convert address into form that can be used 11361ae08745Sheppo * as hash table key. 11371ae08745Sheppo */ 11381ae08745Sheppo for (i = 0; i < ETHERADDRL; i++) { 11391ae08745Sheppo addr = (addr << 8) | mca[i]; 11401ae08745Sheppo } 11411ae08745Sheppo 11421ae08745Sheppo D2(vswp, "%s: addr = 0x%llx", __func__, addr); 11431ae08745Sheppo 11441ae08745Sheppo if (add) { 11451ae08745Sheppo D2(vswp, "%s: adding multicast", __func__); 11461ae08745Sheppo if (vsw_add_mcst(vswp, VSW_LOCALDEV, addr, NULL) == 0) { 11471ae08745Sheppo /* 11481ae08745Sheppo * Update the list of multicast addresses 11491ae08745Sheppo * contained within the vsw_t structure to 11501ae08745Sheppo * include this new one. 11511ae08745Sheppo */ 11521ae08745Sheppo mcst_p = kmem_zalloc(sizeof (mcst_addr_t), KM_NOSLEEP); 11531ae08745Sheppo if (mcst_p == NULL) { 11541ae08745Sheppo DERR(vswp, "%s unable to alloc mem", __func__); 115519b65a69Ssb155480 (void) vsw_del_mcst(vswp, 115619b65a69Ssb155480 VSW_LOCALDEV, addr, NULL); 11571ae08745Sheppo return (1); 11581ae08745Sheppo } 11591ae08745Sheppo mcst_p->addr = addr; 116019b65a69Ssb155480 ether_copy(mca, &mcst_p->mca); 11611ae08745Sheppo 11621ae08745Sheppo /* 11631ae08745Sheppo * Call into the underlying driver to program the 11641ae08745Sheppo * address into HW. 11651ae08745Sheppo */ 116634683adeSsg70180 mutex_enter(&vswp->mac_lock); 1167e1ebb9ecSlm66018 if (vswp->mh != NULL) { 1168e1ebb9ecSlm66018 ret = mac_multicst_add(vswp->mh, mca); 1169e1ebb9ecSlm66018 if (ret != 0) { 1170*1ef0bbb5Snarayan cmn_err(CE_NOTE, "!vsw%d: unable to " 117134683adeSsg70180 "add multicast address", 117234683adeSsg70180 vswp->instance); 117334683adeSsg70180 mutex_exit(&vswp->mac_lock); 117419b65a69Ssb155480 (void) vsw_del_mcst(vswp, 117519b65a69Ssb155480 VSW_LOCALDEV, addr, NULL); 117619b65a69Ssb155480 kmem_free(mcst_p, sizeof (*mcst_p)); 117719b65a69Ssb155480 return (ret); 1178e1ebb9ecSlm66018 } 117919b65a69Ssb155480 mcst_p->mac_added = B_TRUE; 11801ae08745Sheppo } 118134683adeSsg70180 mutex_exit(&vswp->mac_lock); 118219b65a69Ssb155480 118319b65a69Ssb155480 mutex_enter(&vswp->mca_lock); 118419b65a69Ssb155480 mcst_p->nextp = vswp->mcap; 118519b65a69Ssb155480 vswp->mcap = mcst_p; 118619b65a69Ssb155480 mutex_exit(&vswp->mca_lock); 11871ae08745Sheppo } else { 1188*1ef0bbb5Snarayan cmn_err(CE_NOTE, "!vsw%d: unable to add multicast " 118934683adeSsg70180 "address", vswp->instance); 1190e1ebb9ecSlm66018 } 1191e1ebb9ecSlm66018 return (ret); 1192e1ebb9ecSlm66018 } 1193e1ebb9ecSlm66018 11941ae08745Sheppo D2(vswp, "%s: removing multicast", __func__); 11951ae08745Sheppo /* 11961ae08745Sheppo * Remove the address from the hash table.. 11971ae08745Sheppo */ 11981ae08745Sheppo if (vsw_del_mcst(vswp, VSW_LOCALDEV, addr, NULL) == 0) { 11991ae08745Sheppo 12001ae08745Sheppo /* 12011ae08745Sheppo * ..and then from the list maintained in the 12021ae08745Sheppo * vsw_t structure. 12031ae08745Sheppo */ 120419b65a69Ssb155480 mcst_p = vsw_del_addr(VSW_LOCALDEV, vswp, addr); 120519b65a69Ssb155480 ASSERT(mcst_p != NULL); 12061ae08745Sheppo 120734683adeSsg70180 mutex_enter(&vswp->mac_lock); 120819b65a69Ssb155480 if (vswp->mh != NULL && mcst_p->mac_added) { 12091ae08745Sheppo (void) mac_multicst_remove(vswp->mh, mca); 121019b65a69Ssb155480 mcst_p->mac_added = B_FALSE; 121119b65a69Ssb155480 } 121234683adeSsg70180 mutex_exit(&vswp->mac_lock); 121319b65a69Ssb155480 kmem_free(mcst_p, sizeof (*mcst_p)); 12141ae08745Sheppo } 12151ae08745Sheppo 12161ae08745Sheppo D1(vswp, "%s: exit", __func__); 12171ae08745Sheppo 12181ae08745Sheppo return (0); 12191ae08745Sheppo } 12201ae08745Sheppo 12211ae08745Sheppo static int 12221ae08745Sheppo vsw_m_promisc(void *arg, boolean_t on) 12231ae08745Sheppo { 12241ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 12251ae08745Sheppo 12261ae08745Sheppo D1(vswp, "%s: enter", __func__); 12271ae08745Sheppo 12281ae08745Sheppo WRITE_ENTER(&vswp->if_lockrw); 12291ae08745Sheppo if (on) 12301ae08745Sheppo vswp->if_state |= VSW_IF_PROMISC; 12311ae08745Sheppo else 12321ae08745Sheppo vswp->if_state &= ~VSW_IF_PROMISC; 12331ae08745Sheppo RW_EXIT(&vswp->if_lockrw); 12341ae08745Sheppo 12351ae08745Sheppo D1(vswp, "%s: exit", __func__); 12361ae08745Sheppo 12371ae08745Sheppo return (0); 12381ae08745Sheppo } 12391ae08745Sheppo 12401ae08745Sheppo static mblk_t * 12411ae08745Sheppo vsw_m_tx(void *arg, mblk_t *mp) 12421ae08745Sheppo { 12431ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 12441ae08745Sheppo 12451ae08745Sheppo D1(vswp, "%s: enter", __func__); 12461ae08745Sheppo 124734683adeSsg70180 vswp->vsw_switch_frame(vswp, mp, VSW_LOCALDEV, NULL, NULL); 12481ae08745Sheppo 12491ae08745Sheppo D1(vswp, "%s: exit", __func__); 12501ae08745Sheppo 12511ae08745Sheppo return (NULL); 12521ae08745Sheppo } 12531ae08745Sheppo 12541ae08745Sheppo /* 12551ae08745Sheppo * Register for machine description (MD) updates. 125634683adeSsg70180 * 125734683adeSsg70180 * Returns 0 on success, 1 on failure. 12581ae08745Sheppo */ 125934683adeSsg70180 static int 12601ae08745Sheppo vsw_mdeg_register(vsw_t *vswp) 12611ae08745Sheppo { 12621ae08745Sheppo mdeg_prop_spec_t *pspecp; 12631ae08745Sheppo mdeg_node_spec_t *inst_specp; 126434683adeSsg70180 mdeg_handle_t mdeg_hdl, mdeg_port_hdl; 12651ae08745Sheppo size_t templatesz; 126619b65a69Ssb155480 int rv; 12671ae08745Sheppo 12681ae08745Sheppo D1(vswp, "%s: enter", __func__); 12691ae08745Sheppo 127034683adeSsg70180 /* 12711ae08745Sheppo * Allocate and initialize a per-instance copy 12721ae08745Sheppo * of the global property spec array that will 12731ae08745Sheppo * uniquely identify this vsw instance. 12741ae08745Sheppo */ 12751ae08745Sheppo templatesz = sizeof (vsw_prop_template); 12761ae08745Sheppo pspecp = kmem_zalloc(templatesz, KM_SLEEP); 12771ae08745Sheppo 12781ae08745Sheppo bcopy(vsw_prop_template, pspecp, templatesz); 12791ae08745Sheppo 128019b65a69Ssb155480 VSW_SET_MDEG_PROP_INST(pspecp, vswp->regprop); 12811ae08745Sheppo 12821ae08745Sheppo /* initialize the complete prop spec structure */ 12831ae08745Sheppo inst_specp = kmem_zalloc(sizeof (mdeg_node_spec_t), KM_SLEEP); 12841ae08745Sheppo inst_specp->namep = "virtual-device"; 12851ae08745Sheppo inst_specp->specp = pspecp; 12861ae08745Sheppo 128719b65a69Ssb155480 D2(vswp, "%s: instance %d registering with mdeg", __func__, 128819b65a69Ssb155480 vswp->regprop); 128934683adeSsg70180 /* 129034683adeSsg70180 * Register an interest in 'virtual-device' nodes with a 129134683adeSsg70180 * 'name' property of 'virtual-network-switch' 129234683adeSsg70180 */ 129334683adeSsg70180 rv = mdeg_register(inst_specp, &vdev_match, vsw_mdeg_cb, 12941ae08745Sheppo (void *)vswp, &mdeg_hdl); 129534683adeSsg70180 if (rv != MDEG_SUCCESS) { 129634683adeSsg70180 DERR(vswp, "%s: mdeg_register failed (%d) for vsw node", 129734683adeSsg70180 __func__, rv); 129834683adeSsg70180 goto mdeg_reg_fail; 129934683adeSsg70180 } 13001ae08745Sheppo 130134683adeSsg70180 /* 130234683adeSsg70180 * Register an interest in 'vsw-port' nodes. 130334683adeSsg70180 */ 130434683adeSsg70180 rv = mdeg_register(inst_specp, &vport_match, vsw_port_mdeg_cb, 130534683adeSsg70180 (void *)vswp, &mdeg_port_hdl); 13061ae08745Sheppo if (rv != MDEG_SUCCESS) { 13071ae08745Sheppo DERR(vswp, "%s: mdeg_register failed (%d)\n", __func__, rv); 130834683adeSsg70180 (void) mdeg_unregister(mdeg_hdl); 130934683adeSsg70180 goto mdeg_reg_fail; 13101ae08745Sheppo } 13111ae08745Sheppo 13121ae08745Sheppo /* save off data that will be needed later */ 13131ae08745Sheppo vswp->inst_spec = inst_specp; 13141ae08745Sheppo vswp->mdeg_hdl = mdeg_hdl; 131534683adeSsg70180 vswp->mdeg_port_hdl = mdeg_port_hdl; 13161ae08745Sheppo 13171ae08745Sheppo D1(vswp, "%s: exit", __func__); 131834683adeSsg70180 return (0); 131934683adeSsg70180 132034683adeSsg70180 mdeg_reg_fail: 132134683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to register MDEG callbacks", 132234683adeSsg70180 vswp->instance); 132334683adeSsg70180 kmem_free(pspecp, templatesz); 132434683adeSsg70180 kmem_free(inst_specp, sizeof (mdeg_node_spec_t)); 132534683adeSsg70180 132634683adeSsg70180 vswp->mdeg_hdl = NULL; 132734683adeSsg70180 vswp->mdeg_port_hdl = NULL; 132834683adeSsg70180 132934683adeSsg70180 return (1); 13301ae08745Sheppo } 13311ae08745Sheppo 13321ae08745Sheppo static void 13331ae08745Sheppo vsw_mdeg_unregister(vsw_t *vswp) 13341ae08745Sheppo { 13351ae08745Sheppo D1(vswp, "vsw_mdeg_unregister: enter"); 13361ae08745Sheppo 133734683adeSsg70180 if (vswp->mdeg_hdl != NULL) 13381ae08745Sheppo (void) mdeg_unregister(vswp->mdeg_hdl); 13391ae08745Sheppo 134034683adeSsg70180 if (vswp->mdeg_port_hdl != NULL) 134134683adeSsg70180 (void) mdeg_unregister(vswp->mdeg_port_hdl); 134234683adeSsg70180 134334683adeSsg70180 if (vswp->inst_spec != NULL) { 13441ae08745Sheppo if (vswp->inst_spec->specp != NULL) { 13451ae08745Sheppo (void) kmem_free(vswp->inst_spec->specp, 13461ae08745Sheppo sizeof (vsw_prop_template)); 13471ae08745Sheppo vswp->inst_spec->specp = NULL; 13481ae08745Sheppo } 13491ae08745Sheppo 1350205eeb1aSlm66018 (void) kmem_free(vswp->inst_spec, sizeof (mdeg_node_spec_t)); 13511ae08745Sheppo vswp->inst_spec = NULL; 13521ae08745Sheppo } 13531ae08745Sheppo 13541ae08745Sheppo D1(vswp, "vsw_mdeg_unregister: exit"); 13551ae08745Sheppo } 13561ae08745Sheppo 135734683adeSsg70180 /* 135834683adeSsg70180 * Mdeg callback invoked for the vsw node itself. 135934683adeSsg70180 */ 13601ae08745Sheppo static int 13611ae08745Sheppo vsw_mdeg_cb(void *cb_argp, mdeg_result_t *resp) 13621ae08745Sheppo { 13631ae08745Sheppo vsw_t *vswp; 13641ae08745Sheppo md_t *mdp; 13651ae08745Sheppo mde_cookie_t node; 13661ae08745Sheppo uint64_t inst; 136734683adeSsg70180 char *node_name = NULL; 13681ae08745Sheppo 13691ae08745Sheppo if (resp == NULL) 13701ae08745Sheppo return (MDEG_FAILURE); 13711ae08745Sheppo 13721ae08745Sheppo vswp = (vsw_t *)cb_argp; 13731ae08745Sheppo 137434683adeSsg70180 D1(vswp, "%s: added %d : removed %d : curr matched %d" 137534683adeSsg70180 " : prev matched %d", __func__, resp->added.nelem, 137634683adeSsg70180 resp->removed.nelem, resp->match_curr.nelem, 137734683adeSsg70180 resp->match_prev.nelem); 137834683adeSsg70180 137934683adeSsg70180 /* 138019b65a69Ssb155480 * We get an initial callback for this node as 'added' 138119b65a69Ssb155480 * after registering with mdeg. Note that we would have 138219b65a69Ssb155480 * already gathered information about this vsw node by 138319b65a69Ssb155480 * walking MD earlier during attach (in vsw_read_mdprops()). 138419b65a69Ssb155480 * So, there is a window where the properties of this 138519b65a69Ssb155480 * node might have changed when we get this initial 'added' 138619b65a69Ssb155480 * callback. We handle this as if an update occured 138719b65a69Ssb155480 * and invoke the same function which handles updates to 138819b65a69Ssb155480 * the properties of this vsw-node if any. 138919b65a69Ssb155480 * 139034683adeSsg70180 * A non-zero 'match' value indicates that the MD has been 139119b65a69Ssb155480 * updated and that a virtual-network-switch node is 139219b65a69Ssb155480 * present which may or may not have been updated. It is 139319b65a69Ssb155480 * up to the clients to examine their own nodes and 139419b65a69Ssb155480 * determine if they have changed. 139534683adeSsg70180 */ 139619b65a69Ssb155480 if (resp->added.nelem != 0) { 139734683adeSsg70180 139819b65a69Ssb155480 if (resp->added.nelem != 1) { 139919b65a69Ssb155480 cmn_err(CE_NOTE, "!vsw%d: number of nodes added " 140019b65a69Ssb155480 "invalid: %d\n", vswp->instance, resp->added.nelem); 140119b65a69Ssb155480 return (MDEG_FAILURE); 140219b65a69Ssb155480 } 140319b65a69Ssb155480 140419b65a69Ssb155480 mdp = resp->added.mdp; 140519b65a69Ssb155480 node = resp->added.mdep[0]; 140619b65a69Ssb155480 140719b65a69Ssb155480 } else if (resp->match_curr.nelem != 0) { 140819b65a69Ssb155480 140919b65a69Ssb155480 if (resp->match_curr.nelem != 1) { 141019b65a69Ssb155480 cmn_err(CE_NOTE, "!vsw%d: number of nodes updated " 141119b65a69Ssb155480 "invalid: %d\n", vswp->instance, 141219b65a69Ssb155480 resp->match_curr.nelem); 141319b65a69Ssb155480 return (MDEG_FAILURE); 141419b65a69Ssb155480 } 141519b65a69Ssb155480 141619b65a69Ssb155480 mdp = resp->match_curr.mdp; 141719b65a69Ssb155480 node = resp->match_curr.mdep[0]; 141819b65a69Ssb155480 141919b65a69Ssb155480 } else { 142019b65a69Ssb155480 return (MDEG_FAILURE); 142119b65a69Ssb155480 } 142219b65a69Ssb155480 142319b65a69Ssb155480 /* Validate name and instance */ 142434683adeSsg70180 if (md_get_prop_str(mdp, node, "name", &node_name) != 0) { 142519b65a69Ssb155480 DERR(vswp, "%s: unable to get node name\n", __func__); 142619b65a69Ssb155480 return (MDEG_FAILURE); 142719b65a69Ssb155480 } 142819b65a69Ssb155480 142919b65a69Ssb155480 /* is this a virtual-network-switch? */ 143019b65a69Ssb155480 if (strcmp(node_name, vsw_propname) != 0) { 143119b65a69Ssb155480 DERR(vswp, "%s: Invalid node name: %s\n", 143219b65a69Ssb155480 __func__, node_name); 143319b65a69Ssb155480 return (MDEG_FAILURE); 143434683adeSsg70180 } 143534683adeSsg70180 143634683adeSsg70180 if (md_get_prop_val(mdp, node, "cfg-handle", &inst)) { 143719b65a69Ssb155480 DERR(vswp, "%s: prop(cfg-handle) not found\n", 143819b65a69Ssb155480 __func__); 143919b65a69Ssb155480 return (MDEG_FAILURE); 144034683adeSsg70180 } 144134683adeSsg70180 144219b65a69Ssb155480 /* is this the right instance of vsw? */ 144319b65a69Ssb155480 if (inst != vswp->regprop) { 144419b65a69Ssb155480 DERR(vswp, "%s: Invalid cfg-handle: %lx\n", 144519b65a69Ssb155480 __func__, inst); 144619b65a69Ssb155480 return (MDEG_FAILURE); 144719b65a69Ssb155480 } 144834683adeSsg70180 144934683adeSsg70180 vsw_update_md_prop(vswp, mdp, node); 145034683adeSsg70180 145134683adeSsg70180 return (MDEG_SUCCESS); 145234683adeSsg70180 } 145334683adeSsg70180 145434683adeSsg70180 /* 145534683adeSsg70180 * Mdeg callback invoked for changes to the vsw-port nodes 145634683adeSsg70180 * under the vsw node. 145734683adeSsg70180 */ 145834683adeSsg70180 static int 145934683adeSsg70180 vsw_port_mdeg_cb(void *cb_argp, mdeg_result_t *resp) 146034683adeSsg70180 { 146134683adeSsg70180 vsw_t *vswp; 146234683adeSsg70180 int idx; 146334683adeSsg70180 md_t *mdp; 146434683adeSsg70180 mde_cookie_t node; 146534683adeSsg70180 uint64_t inst; 1466*1ef0bbb5Snarayan int rv; 146734683adeSsg70180 146834683adeSsg70180 if ((resp == NULL) || (cb_argp == NULL)) 146934683adeSsg70180 return (MDEG_FAILURE); 147034683adeSsg70180 147134683adeSsg70180 vswp = (vsw_t *)cb_argp; 147234683adeSsg70180 147334683adeSsg70180 D2(vswp, "%s: added %d : removed %d : curr matched %d" 147434683adeSsg70180 " : prev matched %d", __func__, resp->added.nelem, 147534683adeSsg70180 resp->removed.nelem, resp->match_curr.nelem, 14761ae08745Sheppo resp->match_prev.nelem); 14771ae08745Sheppo 14781ae08745Sheppo /* process added ports */ 14791ae08745Sheppo for (idx = 0; idx < resp->added.nelem; idx++) { 14801ae08745Sheppo mdp = resp->added.mdp; 14811ae08745Sheppo node = resp->added.mdep[idx]; 14821ae08745Sheppo 14831ae08745Sheppo D2(vswp, "%s: adding node(%d) 0x%lx", __func__, idx, node); 14841ae08745Sheppo 1485*1ef0bbb5Snarayan if ((rv = vsw_port_add(vswp, mdp, &node)) != 0) { 148634683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to add new port " 1487*1ef0bbb5Snarayan "(0x%lx), err=%d", vswp->instance, node, rv); 14881ae08745Sheppo } 14891ae08745Sheppo } 14901ae08745Sheppo 14911ae08745Sheppo /* process removed ports */ 14921ae08745Sheppo for (idx = 0; idx < resp->removed.nelem; idx++) { 14931ae08745Sheppo mdp = resp->removed.mdp; 14941ae08745Sheppo node = resp->removed.mdep[idx]; 14951ae08745Sheppo 14961ae08745Sheppo if (md_get_prop_val(mdp, node, id_propname, &inst)) { 149734683adeSsg70180 DERR(vswp, "%s: prop(%s) not found in port(%d)", 14981ae08745Sheppo __func__, id_propname, idx); 14991ae08745Sheppo continue; 15001ae08745Sheppo } 15011ae08745Sheppo 15021ae08745Sheppo D2(vswp, "%s: removing node(%d) 0x%lx", __func__, idx, node); 15031ae08745Sheppo 15041ae08745Sheppo if (vsw_port_detach(vswp, inst) != 0) { 150534683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to remove port %ld", 150634683adeSsg70180 vswp->instance, inst); 15071ae08745Sheppo } 15081ae08745Sheppo } 15091ae08745Sheppo 15101ae08745Sheppo /* 15111ae08745Sheppo * Currently no support for updating already active ports. 15121ae08745Sheppo * So, ignore the match_curr and match_priv arrays for now. 15131ae08745Sheppo */ 15141ae08745Sheppo 15151ae08745Sheppo D1(vswp, "%s: exit", __func__); 15161ae08745Sheppo 15171ae08745Sheppo return (MDEG_SUCCESS); 15181ae08745Sheppo } 15191ae08745Sheppo 15201ae08745Sheppo /* 152119b65a69Ssb155480 * Scan the machine description for this instance of vsw 152219b65a69Ssb155480 * and read its properties. Called only from vsw_attach(). 152319b65a69Ssb155480 * Returns: 0 on success, 1 on failure. 152419b65a69Ssb155480 */ 152519b65a69Ssb155480 static int 152619b65a69Ssb155480 vsw_read_mdprops(vsw_t *vswp) 152719b65a69Ssb155480 { 152819b65a69Ssb155480 md_t *mdp = NULL; 152919b65a69Ssb155480 mde_cookie_t rootnode; 153019b65a69Ssb155480 mde_cookie_t *listp = NULL; 153119b65a69Ssb155480 uint64_t inst; 153219b65a69Ssb155480 uint64_t cfgh; 153319b65a69Ssb155480 char *name; 153419b65a69Ssb155480 int rv = 1; 153519b65a69Ssb155480 int num_nodes = 0; 153619b65a69Ssb155480 int num_devs = 0; 153719b65a69Ssb155480 int listsz = 0; 153819b65a69Ssb155480 int i; 153919b65a69Ssb155480 154019b65a69Ssb155480 /* 154119b65a69Ssb155480 * In each 'virtual-device' node in the MD there is a 154219b65a69Ssb155480 * 'cfg-handle' property which is the MD's concept of 154319b65a69Ssb155480 * an instance number (this may be completely different from 154419b65a69Ssb155480 * the device drivers instance #). OBP reads that value and 154519b65a69Ssb155480 * stores it in the 'reg' property of the appropriate node in 154619b65a69Ssb155480 * the device tree. We first read this reg property and use this 154719b65a69Ssb155480 * to compare against the 'cfg-handle' property of vsw nodes 154819b65a69Ssb155480 * in MD to get to this specific vsw instance and then read 154919b65a69Ssb155480 * other properties that we are interested in. 155019b65a69Ssb155480 * We also cache the value of 'reg' property and use it later 155119b65a69Ssb155480 * to register callbacks with mdeg (see vsw_mdeg_register()) 155219b65a69Ssb155480 */ 155319b65a69Ssb155480 inst = ddi_prop_get_int(DDI_DEV_T_ANY, vswp->dip, 155419b65a69Ssb155480 DDI_PROP_DONTPASS, reg_propname, -1); 155519b65a69Ssb155480 if (inst == -1) { 155619b65a69Ssb155480 cmn_err(CE_NOTE, "!vsw%d: Unable to read %s property from " 155719b65a69Ssb155480 "OBP device tree", vswp->instance, reg_propname); 155819b65a69Ssb155480 return (rv); 155919b65a69Ssb155480 } 156019b65a69Ssb155480 156119b65a69Ssb155480 vswp->regprop = inst; 156219b65a69Ssb155480 156319b65a69Ssb155480 if ((mdp = md_get_handle()) == NULL) { 156419b65a69Ssb155480 DWARN(vswp, "%s: cannot init MD\n", __func__); 156519b65a69Ssb155480 return (rv); 156619b65a69Ssb155480 } 156719b65a69Ssb155480 156819b65a69Ssb155480 num_nodes = md_node_count(mdp); 156919b65a69Ssb155480 ASSERT(num_nodes > 0); 157019b65a69Ssb155480 157119b65a69Ssb155480 listsz = num_nodes * sizeof (mde_cookie_t); 157219b65a69Ssb155480 listp = (mde_cookie_t *)kmem_zalloc(listsz, KM_SLEEP); 157319b65a69Ssb155480 157419b65a69Ssb155480 rootnode = md_root_node(mdp); 157519b65a69Ssb155480 157619b65a69Ssb155480 /* search for all "virtual_device" nodes */ 157719b65a69Ssb155480 num_devs = md_scan_dag(mdp, rootnode, 157819b65a69Ssb155480 md_find_name(mdp, vdev_propname), 157919b65a69Ssb155480 md_find_name(mdp, "fwd"), listp); 158019b65a69Ssb155480 if (num_devs <= 0) { 158119b65a69Ssb155480 DWARN(vswp, "%s: invalid num_devs:%d\n", __func__, num_devs); 158219b65a69Ssb155480 goto vsw_readmd_exit; 158319b65a69Ssb155480 } 158419b65a69Ssb155480 158519b65a69Ssb155480 /* 158619b65a69Ssb155480 * Now loop through the list of virtual-devices looking for 158719b65a69Ssb155480 * devices with name "virtual-network-switch" and for each 158819b65a69Ssb155480 * such device compare its instance with what we have from 158919b65a69Ssb155480 * the 'reg' property to find the right node in MD and then 159019b65a69Ssb155480 * read all its properties. 159119b65a69Ssb155480 */ 159219b65a69Ssb155480 for (i = 0; i < num_devs; i++) { 159319b65a69Ssb155480 159419b65a69Ssb155480 if (md_get_prop_str(mdp, listp[i], "name", &name) != 0) { 159519b65a69Ssb155480 DWARN(vswp, "%s: name property not found\n", 159619b65a69Ssb155480 __func__); 159719b65a69Ssb155480 goto vsw_readmd_exit; 159819b65a69Ssb155480 } 159919b65a69Ssb155480 160019b65a69Ssb155480 /* is this a virtual-network-switch? */ 160119b65a69Ssb155480 if (strcmp(name, vsw_propname) != 0) 160219b65a69Ssb155480 continue; 160319b65a69Ssb155480 160419b65a69Ssb155480 if (md_get_prop_val(mdp, listp[i], "cfg-handle", &cfgh) != 0) { 160519b65a69Ssb155480 DWARN(vswp, "%s: cfg-handle property not found\n", 160619b65a69Ssb155480 __func__); 160719b65a69Ssb155480 goto vsw_readmd_exit; 160819b65a69Ssb155480 } 160919b65a69Ssb155480 161019b65a69Ssb155480 /* is this the required instance of vsw? */ 161119b65a69Ssb155480 if (inst != cfgh) 161219b65a69Ssb155480 continue; 161319b65a69Ssb155480 161419b65a69Ssb155480 /* now read all properties of this vsw instance */ 161519b65a69Ssb155480 rv = vsw_get_initial_md_properties(vswp, mdp, listp[i]); 161619b65a69Ssb155480 break; 161719b65a69Ssb155480 } 161819b65a69Ssb155480 161919b65a69Ssb155480 vsw_readmd_exit: 162019b65a69Ssb155480 162119b65a69Ssb155480 kmem_free(listp, listsz); 162219b65a69Ssb155480 (void) md_fini_handle(mdp); 162319b65a69Ssb155480 return (rv); 162419b65a69Ssb155480 } 162519b65a69Ssb155480 162619b65a69Ssb155480 /* 162734683adeSsg70180 * Read the initial start-of-day values from the specified MD node. 162834683adeSsg70180 */ 162919b65a69Ssb155480 static int 163034683adeSsg70180 vsw_get_initial_md_properties(vsw_t *vswp, md_t *mdp, mde_cookie_t node) 163134683adeSsg70180 { 163234683adeSsg70180 int i; 163334683adeSsg70180 uint64_t macaddr = 0; 163434683adeSsg70180 163534683adeSsg70180 D1(vswp, "%s: enter", __func__); 163634683adeSsg70180 163719b65a69Ssb155480 if (vsw_get_md_physname(vswp, mdp, node, vswp->physname) != 0) { 163819b65a69Ssb155480 return (1); 163934683adeSsg70180 } 164034683adeSsg70180 164134683adeSsg70180 /* mac address for vswitch device itself */ 164234683adeSsg70180 if (md_get_prop_val(mdp, node, macaddr_propname, &macaddr) != 0) { 164334683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to get MAC address from MD", 164434683adeSsg70180 vswp->instance); 164519b65a69Ssb155480 return (1); 164619b65a69Ssb155480 } 164734683adeSsg70180 164819b65a69Ssb155480 vsw_save_lmacaddr(vswp, macaddr); 164934683adeSsg70180 1650205eeb1aSlm66018 if (vsw_get_md_smodes(vswp, mdp, node, vswp->smode, &vswp->smode_num)) { 1651*1ef0bbb5Snarayan DWARN(vswp, "%s: Unable to read %s property from MD, " 1652*1ef0bbb5Snarayan "defaulting to 'switched' mode", 1653*1ef0bbb5Snarayan __func__, smode_propname); 165434683adeSsg70180 165534683adeSsg70180 for (i = 0; i < NUM_SMODES; i++) 165634683adeSsg70180 vswp->smode[i] = VSW_LAYER2; 165734683adeSsg70180 165834683adeSsg70180 vswp->smode_num = NUM_SMODES; 165934683adeSsg70180 } else { 166034683adeSsg70180 ASSERT(vswp->smode_num != 0); 166134683adeSsg70180 } 166234683adeSsg70180 1663f0ca1d9aSsb155480 vsw_read_pri_eth_types(vswp, mdp, node); 1664f0ca1d9aSsb155480 166534683adeSsg70180 D1(vswp, "%s: exit", __func__); 166619b65a69Ssb155480 return (0); 166734683adeSsg70180 } 166834683adeSsg70180 166934683adeSsg70180 /* 1670f0ca1d9aSsb155480 * This function reads "priority-ether-types" property from md. This property 1671f0ca1d9aSsb155480 * is used to enable support for priority frames. Applications which need 1672f0ca1d9aSsb155480 * guaranteed and timely delivery of certain high priority frames to/from 1673f0ca1d9aSsb155480 * a vnet or vsw within ldoms, should configure this property by providing 1674f0ca1d9aSsb155480 * the ether type(s) for which the priority facility is needed. 1675f0ca1d9aSsb155480 * Normal data frames are delivered over a ldc channel using the descriptor 1676f0ca1d9aSsb155480 * ring mechanism which is constrained by factors such as descriptor ring size, 1677f0ca1d9aSsb155480 * the rate at which the ring is processed at the peer ldc end point, etc. 1678f0ca1d9aSsb155480 * The priority mechanism provides an Out-Of-Band path to send/receive frames 1679f0ca1d9aSsb155480 * as raw pkt data (VIO_PKT_DATA) messages over the channel, avoiding the 1680f0ca1d9aSsb155480 * descriptor ring path and enables a more reliable and timely delivery of 1681f0ca1d9aSsb155480 * frames to the peer. 1682f0ca1d9aSsb155480 */ 1683f0ca1d9aSsb155480 static void 1684f0ca1d9aSsb155480 vsw_read_pri_eth_types(vsw_t *vswp, md_t *mdp, mde_cookie_t node) 1685f0ca1d9aSsb155480 { 1686f0ca1d9aSsb155480 int rv; 1687f0ca1d9aSsb155480 uint16_t *types; 1688f0ca1d9aSsb155480 uint64_t *data; 1689f0ca1d9aSsb155480 int size; 1690f0ca1d9aSsb155480 int i; 1691f0ca1d9aSsb155480 size_t mblk_sz; 1692f0ca1d9aSsb155480 1693f0ca1d9aSsb155480 rv = md_get_prop_data(mdp, node, pri_types_propname, 1694f0ca1d9aSsb155480 (uint8_t **)&data, &size); 1695f0ca1d9aSsb155480 if (rv != 0) { 1696f0ca1d9aSsb155480 /* 1697f0ca1d9aSsb155480 * Property may not exist if we are running pre-ldoms1.1 f/w. 1698f0ca1d9aSsb155480 * Check if 'vsw_pri_eth_type' has been set in that case. 1699f0ca1d9aSsb155480 */ 1700f0ca1d9aSsb155480 if (vsw_pri_eth_type != 0) { 1701f0ca1d9aSsb155480 size = sizeof (vsw_pri_eth_type); 1702f0ca1d9aSsb155480 data = &vsw_pri_eth_type; 1703f0ca1d9aSsb155480 } else { 1704f0ca1d9aSsb155480 D3(vswp, "%s: prop(%s) not found", __func__, 1705f0ca1d9aSsb155480 pri_types_propname); 1706f0ca1d9aSsb155480 size = 0; 1707f0ca1d9aSsb155480 } 1708f0ca1d9aSsb155480 } 1709f0ca1d9aSsb155480 1710f0ca1d9aSsb155480 if (size == 0) { 1711f0ca1d9aSsb155480 vswp->pri_num_types = 0; 1712f0ca1d9aSsb155480 return; 1713f0ca1d9aSsb155480 } 1714f0ca1d9aSsb155480 1715f0ca1d9aSsb155480 /* 1716f0ca1d9aSsb155480 * we have some priority-ether-types defined; 1717f0ca1d9aSsb155480 * allocate a table of these types and also 1718f0ca1d9aSsb155480 * allocate a pool of mblks to transmit these 1719f0ca1d9aSsb155480 * priority packets. 1720f0ca1d9aSsb155480 */ 1721f0ca1d9aSsb155480 size /= sizeof (uint64_t); 1722f0ca1d9aSsb155480 vswp->pri_num_types = size; 1723f0ca1d9aSsb155480 vswp->pri_types = kmem_zalloc(size * sizeof (uint16_t), KM_SLEEP); 1724f0ca1d9aSsb155480 for (i = 0, types = vswp->pri_types; i < size; i++) { 1725f0ca1d9aSsb155480 types[i] = data[i] & 0xFFFF; 1726f0ca1d9aSsb155480 } 1727f0ca1d9aSsb155480 mblk_sz = (VIO_PKT_DATA_HDRSIZE + ETHERMAX + 7) & ~7; 1728f0ca1d9aSsb155480 (void) vio_create_mblks(vsw_pri_tx_nmblks, mblk_sz, &vswp->pri_tx_vmp); 1729f0ca1d9aSsb155480 } 1730f0ca1d9aSsb155480 1731f0ca1d9aSsb155480 /* 173234683adeSsg70180 * Check to see if the relevant properties in the specified node have 173334683adeSsg70180 * changed, and if so take the appropriate action. 173434683adeSsg70180 * 173534683adeSsg70180 * If any of the properties are missing or invalid we don't take 173634683adeSsg70180 * any action, as this function should only be invoked when modifications 173734683adeSsg70180 * have been made to what we assume is a working configuration, which 173834683adeSsg70180 * we leave active. 173934683adeSsg70180 * 174034683adeSsg70180 * Note it is legal for this routine to be invoked even if none of the 174134683adeSsg70180 * properties in the port node within the MD have actually changed. 174234683adeSsg70180 */ 174334683adeSsg70180 static void 174434683adeSsg70180 vsw_update_md_prop(vsw_t *vswp, md_t *mdp, mde_cookie_t node) 174534683adeSsg70180 { 174634683adeSsg70180 char physname[LIFNAMSIZ]; 174734683adeSsg70180 char drv[LIFNAMSIZ]; 174834683adeSsg70180 uint_t ddi_instance; 174934683adeSsg70180 uint8_t new_smode[NUM_SMODES]; 175034683adeSsg70180 int i, smode_num = 0; 175134683adeSsg70180 uint64_t macaddr = 0; 175234683adeSsg70180 enum {MD_init = 0x1, 175334683adeSsg70180 MD_physname = 0x2, 175434683adeSsg70180 MD_macaddr = 0x4, 175534683adeSsg70180 MD_smode = 0x8} updated; 175619b65a69Ssb155480 int rv; 175734683adeSsg70180 175834683adeSsg70180 updated = MD_init; 175934683adeSsg70180 176034683adeSsg70180 D1(vswp, "%s: enter", __func__); 176134683adeSsg70180 176234683adeSsg70180 /* 176334683adeSsg70180 * Check if name of physical device in MD has changed. 176434683adeSsg70180 */ 176534683adeSsg70180 if (vsw_get_md_physname(vswp, mdp, node, (char *)&physname) == 0) { 176634683adeSsg70180 /* 176734683adeSsg70180 * Do basic sanity check on new device name/instance, 176834683adeSsg70180 * if its non NULL. It is valid for the device name to 176934683adeSsg70180 * have changed from a non NULL to a NULL value, i.e. 177034683adeSsg70180 * the vsw is being changed to 'routed' mode. 177134683adeSsg70180 */ 177234683adeSsg70180 if ((strlen(physname) != 0) && 177319b65a69Ssb155480 (ddi_parse(physname, drv, 177419b65a69Ssb155480 &ddi_instance) != DDI_SUCCESS)) { 1775*1ef0bbb5Snarayan cmn_err(CE_WARN, "!vsw%d: physical device %s is not" 177634683adeSsg70180 " a valid device name/instance", 177734683adeSsg70180 vswp->instance, physname); 177834683adeSsg70180 goto fail_reconf; 177934683adeSsg70180 } 178034683adeSsg70180 178134683adeSsg70180 if (strcmp(physname, vswp->physname)) { 178234683adeSsg70180 D2(vswp, "%s: device name changed from %s to %s", 178334683adeSsg70180 __func__, vswp->physname, physname); 178434683adeSsg70180 178534683adeSsg70180 updated |= MD_physname; 178634683adeSsg70180 } else { 178734683adeSsg70180 D2(vswp, "%s: device name unchanged at %s", 178834683adeSsg70180 __func__, vswp->physname); 178934683adeSsg70180 } 179034683adeSsg70180 } else { 179134683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to read name of physical " 179234683adeSsg70180 "device from updated MD.", vswp->instance); 179334683adeSsg70180 goto fail_reconf; 179434683adeSsg70180 } 179534683adeSsg70180 179634683adeSsg70180 /* 179734683adeSsg70180 * Check if MAC address has changed. 179834683adeSsg70180 */ 179934683adeSsg70180 if (md_get_prop_val(mdp, node, macaddr_propname, &macaddr) != 0) { 180034683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to get MAC address from MD", 180134683adeSsg70180 vswp->instance); 180234683adeSsg70180 goto fail_reconf; 180334683adeSsg70180 } else { 180419b65a69Ssb155480 uint64_t maddr = macaddr; 180534683adeSsg70180 READ_ENTER(&vswp->if_lockrw); 180634683adeSsg70180 for (i = ETHERADDRL - 1; i >= 0; i--) { 180719b65a69Ssb155480 if (vswp->if_addr.ether_addr_octet[i] 180819b65a69Ssb155480 != (macaddr & 0xFF)) { 180934683adeSsg70180 D2(vswp, "%s: octet[%d] 0x%x != 0x%x", 181034683adeSsg70180 __func__, i, 181134683adeSsg70180 vswp->if_addr.ether_addr_octet[i], 181234683adeSsg70180 (macaddr & 0xFF)); 181334683adeSsg70180 updated |= MD_macaddr; 181419b65a69Ssb155480 macaddr = maddr; 181534683adeSsg70180 break; 181634683adeSsg70180 } 181734683adeSsg70180 macaddr >>= 8; 181834683adeSsg70180 } 181934683adeSsg70180 RW_EXIT(&vswp->if_lockrw); 182019b65a69Ssb155480 if (updated & MD_macaddr) { 182119b65a69Ssb155480 vsw_save_lmacaddr(vswp, macaddr); 182219b65a69Ssb155480 } 182334683adeSsg70180 } 182434683adeSsg70180 182534683adeSsg70180 /* 182634683adeSsg70180 * Check if switching modes have changed. 182734683adeSsg70180 */ 182819b65a69Ssb155480 if (vsw_get_md_smodes(vswp, mdp, node, 182919b65a69Ssb155480 new_smode, &smode_num)) { 183034683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to read %s property from MD", 183134683adeSsg70180 vswp->instance, smode_propname); 183234683adeSsg70180 goto fail_reconf; 183334683adeSsg70180 } else { 183434683adeSsg70180 ASSERT(smode_num != 0); 183534683adeSsg70180 if (smode_num != vswp->smode_num) { 183634683adeSsg70180 D2(vswp, "%s: number of modes changed from %d to %d", 183734683adeSsg70180 __func__, vswp->smode_num, smode_num); 183834683adeSsg70180 } 183934683adeSsg70180 184034683adeSsg70180 for (i = 0; i < smode_num; i++) { 184134683adeSsg70180 if (new_smode[i] != vswp->smode[i]) { 184234683adeSsg70180 D2(vswp, "%s: mode changed from %d to %d", 184334683adeSsg70180 __func__, vswp->smode[i], new_smode[i]); 184434683adeSsg70180 updated |= MD_smode; 184534683adeSsg70180 break; 184634683adeSsg70180 } 184734683adeSsg70180 } 184834683adeSsg70180 } 184934683adeSsg70180 185034683adeSsg70180 /* 185134683adeSsg70180 * Now make any changes which are needed... 185234683adeSsg70180 */ 185334683adeSsg70180 185434683adeSsg70180 if (updated & (MD_physname | MD_smode)) { 185534683adeSsg70180 185634683adeSsg70180 /* 185719b65a69Ssb155480 * Stop any pending timeout to setup switching mode. 185834683adeSsg70180 */ 185919b65a69Ssb155480 vsw_stop_switching_timeout(vswp); 186019b65a69Ssb155480 186119b65a69Ssb155480 /* 186219b65a69Ssb155480 * Remove unicst, mcst addrs of vsw interface 186319b65a69Ssb155480 * and ports from the physdev. 186419b65a69Ssb155480 */ 186519b65a69Ssb155480 vsw_unset_addrs(vswp); 186619b65a69Ssb155480 186719b65a69Ssb155480 /* 186819b65a69Ssb155480 * Stop, detach and close the old device.. 186919b65a69Ssb155480 */ 187019b65a69Ssb155480 mutex_enter(&vswp->mac_lock); 187119b65a69Ssb155480 187234683adeSsg70180 vsw_mac_detach(vswp); 187319b65a69Ssb155480 vsw_mac_close(vswp); 187419b65a69Ssb155480 187519b65a69Ssb155480 mutex_exit(&vswp->mac_lock); 187634683adeSsg70180 187734683adeSsg70180 /* 187834683adeSsg70180 * Update phys name. 187934683adeSsg70180 */ 188034683adeSsg70180 if (updated & MD_physname) { 188134683adeSsg70180 cmn_err(CE_NOTE, "!vsw%d: changing from %s to %s", 188234683adeSsg70180 vswp->instance, vswp->physname, physname); 188334683adeSsg70180 (void) strncpy(vswp->physname, 188434683adeSsg70180 physname, strlen(physname) + 1); 188534683adeSsg70180 } 188634683adeSsg70180 188734683adeSsg70180 /* 188834683adeSsg70180 * Update array with the new switch mode values. 188934683adeSsg70180 */ 189034683adeSsg70180 if (updated & MD_smode) { 189134683adeSsg70180 for (i = 0; i < smode_num; i++) 189234683adeSsg70180 vswp->smode[i] = new_smode[i]; 189334683adeSsg70180 189434683adeSsg70180 vswp->smode_num = smode_num; 189534683adeSsg70180 vswp->smode_idx = 0; 189634683adeSsg70180 } 189734683adeSsg70180 189834683adeSsg70180 /* 189934683adeSsg70180 * ..and attach, start the new device. 190034683adeSsg70180 */ 190119b65a69Ssb155480 rv = vsw_setup_switching(vswp); 190219b65a69Ssb155480 if (rv == EAGAIN) { 190319b65a69Ssb155480 /* 190419b65a69Ssb155480 * Unable to setup switching mode. 190519b65a69Ssb155480 * As the error is EAGAIN, schedule a timeout to retry 190619b65a69Ssb155480 * and return. Programming addresses of ports and 190719b65a69Ssb155480 * vsw interface will be done when the timeout handler 190819b65a69Ssb155480 * completes successfully. 190919b65a69Ssb155480 */ 191019b65a69Ssb155480 mutex_enter(&vswp->swtmout_lock); 191119b65a69Ssb155480 191219b65a69Ssb155480 vswp->swtmout_enabled = B_TRUE; 191319b65a69Ssb155480 vswp->swtmout_id = 191419b65a69Ssb155480 timeout(vsw_setup_switching_timeout, vswp, 191519b65a69Ssb155480 (vsw_setup_switching_delay * 191619b65a69Ssb155480 drv_usectohz(MICROSEC))); 191719b65a69Ssb155480 191819b65a69Ssb155480 mutex_exit(&vswp->swtmout_lock); 191919b65a69Ssb155480 192019b65a69Ssb155480 return; 192119b65a69Ssb155480 192219b65a69Ssb155480 } else if (rv) { 192334683adeSsg70180 goto fail_update; 192419b65a69Ssb155480 } 192534683adeSsg70180 192634683adeSsg70180 /* 192719b65a69Ssb155480 * program unicst, mcst addrs of vsw interface 192819b65a69Ssb155480 * and ports in the physdev. 192934683adeSsg70180 */ 193019b65a69Ssb155480 vsw_set_addrs(vswp); 193134683adeSsg70180 193219b65a69Ssb155480 } else if (updated & MD_macaddr) { 193319b65a69Ssb155480 /* 193419b65a69Ssb155480 * We enter here if only MD_macaddr is exclusively updated. 193519b65a69Ssb155480 * If MD_physname and/or MD_smode are also updated, then 193619b65a69Ssb155480 * as part of that, we would have implicitly processed 193719b65a69Ssb155480 * MD_macaddr update (above). 193819b65a69Ssb155480 */ 193934683adeSsg70180 cmn_err(CE_NOTE, "!vsw%d: changing mac address to 0x%lx", 194034683adeSsg70180 vswp->instance, macaddr); 194134683adeSsg70180 194219b65a69Ssb155480 READ_ENTER(&vswp->if_lockrw); 194319b65a69Ssb155480 if (vswp->if_state & VSW_IF_UP) { 194434683adeSsg70180 19455f94e909Ssg70180 mutex_enter(&vswp->hw_lock); 194619b65a69Ssb155480 /* 194719b65a69Ssb155480 * Remove old mac address of vsw interface 194819b65a69Ssb155480 * from the physdev 194919b65a69Ssb155480 */ 19505f94e909Ssg70180 (void) vsw_unset_hw(vswp, NULL, VSW_LOCALDEV); 195119b65a69Ssb155480 /* 195219b65a69Ssb155480 * Program new mac address of vsw interface 195319b65a69Ssb155480 * in the physdev 195419b65a69Ssb155480 */ 195519b65a69Ssb155480 rv = vsw_set_hw(vswp, NULL, VSW_LOCALDEV); 19565f94e909Ssg70180 mutex_exit(&vswp->hw_lock); 195719b65a69Ssb155480 if (rv != 0) { 195819b65a69Ssb155480 cmn_err(CE_NOTE, 195919b65a69Ssb155480 "!vsw%d: failed to program interface " 196019b65a69Ssb155480 "unicast address\n", vswp->instance); 196119b65a69Ssb155480 } 19625f94e909Ssg70180 /* 196334683adeSsg70180 * Notify the MAC layer of the changed address. 196434683adeSsg70180 */ 196519b65a69Ssb155480 mac_unicst_update(vswp->if_mh, 196619b65a69Ssb155480 (uint8_t *)&vswp->if_addr); 196719b65a69Ssb155480 196819b65a69Ssb155480 } 196919b65a69Ssb155480 RW_EXIT(&vswp->if_lockrw); 197019b65a69Ssb155480 197134683adeSsg70180 } 197234683adeSsg70180 197334683adeSsg70180 return; 197434683adeSsg70180 197534683adeSsg70180 fail_reconf: 197634683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: configuration unchanged", vswp->instance); 197734683adeSsg70180 return; 197834683adeSsg70180 197934683adeSsg70180 fail_update: 1980*1ef0bbb5Snarayan cmn_err(CE_WARN, "!vsw%d: re-configuration failed", 198134683adeSsg70180 vswp->instance); 198234683adeSsg70180 } 198334683adeSsg70180 198434683adeSsg70180 /* 19851ae08745Sheppo * Add a new port to the system. 19861ae08745Sheppo * 19871ae08745Sheppo * Returns 0 on success, 1 on failure. 19881ae08745Sheppo */ 19891ae08745Sheppo int 19901ae08745Sheppo vsw_port_add(vsw_t *vswp, md_t *mdp, mde_cookie_t *node) 19911ae08745Sheppo { 19921ae08745Sheppo uint64_t ldc_id; 19931ae08745Sheppo uint8_t *addrp; 19941ae08745Sheppo int i, addrsz; 19951ae08745Sheppo int num_nodes = 0, nchan = 0; 19961ae08745Sheppo int listsz = 0; 19971ae08745Sheppo mde_cookie_t *listp = NULL; 19981ae08745Sheppo struct ether_addr ea; 19991ae08745Sheppo uint64_t macaddr; 20001ae08745Sheppo uint64_t inst = 0; 20011ae08745Sheppo vsw_port_t *port; 20021ae08745Sheppo 20031ae08745Sheppo if (md_get_prop_val(mdp, *node, id_propname, &inst)) { 20041ae08745Sheppo DWARN(vswp, "%s: prop(%s) not found", __func__, 20051ae08745Sheppo id_propname); 20061ae08745Sheppo return (1); 20071ae08745Sheppo } 20081ae08745Sheppo 20091ae08745Sheppo /* 20101ae08745Sheppo * Find the channel endpoint node(s) (which should be under this 20111ae08745Sheppo * port node) which contain the channel id(s). 20121ae08745Sheppo */ 20131ae08745Sheppo if ((num_nodes = md_node_count(mdp)) <= 0) { 20141ae08745Sheppo DERR(vswp, "%s: invalid number of nodes found (%d)", 20151ae08745Sheppo __func__, num_nodes); 20161ae08745Sheppo return (1); 20171ae08745Sheppo } 20181ae08745Sheppo 201934683adeSsg70180 D2(vswp, "%s: %d nodes found", __func__, num_nodes); 202034683adeSsg70180 20211ae08745Sheppo /* allocate enough space for node list */ 20221ae08745Sheppo listsz = num_nodes * sizeof (mde_cookie_t); 20231ae08745Sheppo listp = kmem_zalloc(listsz, KM_SLEEP); 20241ae08745Sheppo 2025205eeb1aSlm66018 nchan = md_scan_dag(mdp, *node, md_find_name(mdp, chan_propname), 20261ae08745Sheppo md_find_name(mdp, "fwd"), listp); 20271ae08745Sheppo 20281ae08745Sheppo if (nchan <= 0) { 20291ae08745Sheppo DWARN(vswp, "%s: no %s nodes found", __func__, chan_propname); 20301ae08745Sheppo kmem_free(listp, listsz); 20311ae08745Sheppo return (1); 20321ae08745Sheppo } 20331ae08745Sheppo 20341ae08745Sheppo D2(vswp, "%s: %d %s nodes found", __func__, nchan, chan_propname); 20351ae08745Sheppo 20361ae08745Sheppo /* use property from first node found */ 20371ae08745Sheppo if (md_get_prop_val(mdp, listp[0], id_propname, &ldc_id)) { 20381ae08745Sheppo DWARN(vswp, "%s: prop(%s) not found\n", __func__, 20391ae08745Sheppo id_propname); 20401ae08745Sheppo kmem_free(listp, listsz); 20411ae08745Sheppo return (1); 20421ae08745Sheppo } 20431ae08745Sheppo 20441ae08745Sheppo /* don't need list any more */ 20451ae08745Sheppo kmem_free(listp, listsz); 20461ae08745Sheppo 20471ae08745Sheppo D2(vswp, "%s: ldc_id 0x%llx", __func__, ldc_id); 20481ae08745Sheppo 20491ae08745Sheppo /* read mac-address property */ 20501ae08745Sheppo if (md_get_prop_data(mdp, *node, remaddr_propname, 20511ae08745Sheppo &addrp, &addrsz)) { 20521ae08745Sheppo DWARN(vswp, "%s: prop(%s) not found", 20531ae08745Sheppo __func__, remaddr_propname); 20541ae08745Sheppo return (1); 20551ae08745Sheppo } 20561ae08745Sheppo 20571ae08745Sheppo if (addrsz < ETHERADDRL) { 20581ae08745Sheppo DWARN(vswp, "%s: invalid address size", __func__); 20591ae08745Sheppo return (1); 20601ae08745Sheppo } 20611ae08745Sheppo 20621ae08745Sheppo macaddr = *((uint64_t *)addrp); 20631ae08745Sheppo D2(vswp, "%s: remote mac address 0x%llx", __func__, macaddr); 20641ae08745Sheppo 20651ae08745Sheppo for (i = ETHERADDRL - 1; i >= 0; i--) { 20661ae08745Sheppo ea.ether_addr_octet[i] = macaddr & 0xFF; 20671ae08745Sheppo macaddr >>= 8; 20681ae08745Sheppo } 20691ae08745Sheppo 20701ae08745Sheppo if (vsw_port_attach(vswp, (int)inst, &ldc_id, 1, &ea) != 0) { 20711ae08745Sheppo DERR(vswp, "%s: failed to attach port", __func__); 20721ae08745Sheppo return (1); 20731ae08745Sheppo } 20741ae08745Sheppo 20751ae08745Sheppo port = vsw_lookup_port(vswp, (int)inst); 20761ae08745Sheppo 20771ae08745Sheppo /* just successfuly created the port, so it should exist */ 20781ae08745Sheppo ASSERT(port != NULL); 20791ae08745Sheppo 20801ae08745Sheppo return (0); 20811ae08745Sheppo } 20821ae08745Sheppo 20831ae08745Sheppo /* 208406db247cSraghuram * vsw_mac_rx -- A common function to send packets to the interface. 208506db247cSraghuram * By default this function check if the interface is UP or not, the 208606db247cSraghuram * rest of the behaviour depends on the flags as below: 20871ae08745Sheppo * 208806db247cSraghuram * VSW_MACRX_PROMISC -- Check if the promisc mode set or not. 208906db247cSraghuram * VSW_MACRX_COPYMSG -- Make a copy of the message(s). 209006db247cSraghuram * VSW_MACRX_FREEMSG -- Free if the messages cannot be sent up the stack. 20911ae08745Sheppo */ 20921ae08745Sheppo void 2093f0ca1d9aSsb155480 vsw_mac_rx(vsw_t *vswp, mac_resource_handle_t mrh, 2094f0ca1d9aSsb155480 mblk_t *mp, vsw_macrx_flags_t flags) 20951ae08745Sheppo { 209606db247cSraghuram D1(vswp, "%s:enter\n", __func__); 20971ae08745Sheppo READ_ENTER(&vswp->if_lockrw); 209806db247cSraghuram /* Check if the interface is up */ 209906db247cSraghuram if (!(vswp->if_state & VSW_IF_UP)) { 21001ae08745Sheppo RW_EXIT(&vswp->if_lockrw); 210106db247cSraghuram /* Free messages only if FREEMSG flag specified */ 210206db247cSraghuram if (flags & VSW_MACRX_FREEMSG) { 210306db247cSraghuram freemsgchain(mp); 210406db247cSraghuram } 210506db247cSraghuram D1(vswp, "%s:exit\n", __func__); 210606db247cSraghuram return; 210706db247cSraghuram } 210806db247cSraghuram /* 210906db247cSraghuram * If PROMISC flag is passed, then check if 211006db247cSraghuram * the interface is in the PROMISC mode. 211106db247cSraghuram * If not, drop the messages. 211206db247cSraghuram */ 211306db247cSraghuram if (flags & VSW_MACRX_PROMISC) { 211406db247cSraghuram if (!(vswp->if_state & VSW_IF_PROMISC)) { 211506db247cSraghuram RW_EXIT(&vswp->if_lockrw); 211606db247cSraghuram /* Free messages only if FREEMSG flag specified */ 211706db247cSraghuram if (flags & VSW_MACRX_FREEMSG) { 211806db247cSraghuram freemsgchain(mp); 211906db247cSraghuram } 212006db247cSraghuram D1(vswp, "%s:exit\n", __func__); 212106db247cSraghuram return; 212206db247cSraghuram } 212306db247cSraghuram } 212406db247cSraghuram RW_EXIT(&vswp->if_lockrw); 212506db247cSraghuram /* 212606db247cSraghuram * If COPYMSG flag is passed, then make a copy 212706db247cSraghuram * of the message chain and send up the copy. 212806db247cSraghuram */ 212906db247cSraghuram if (flags & VSW_MACRX_COPYMSG) { 213006db247cSraghuram mp = copymsgchain(mp); 2131f0ca1d9aSsb155480 if (mp == NULL) { 213206db247cSraghuram D1(vswp, "%s:exit\n", __func__); 213306db247cSraghuram return; 213406db247cSraghuram } 213506db247cSraghuram } 213606db247cSraghuram 2137f0ca1d9aSsb155480 D2(vswp, "%s: sending up stack", __func__); 2138ba2e4443Sseb mac_rx(vswp->if_mh, mrh, mp); 213906db247cSraghuram D1(vswp, "%s:exit\n", __func__); 21401ae08745Sheppo } 21411ae08745Sheppo 214206db247cSraghuram /* copy mac address of vsw into soft state structure */ 21431ae08745Sheppo static void 214406db247cSraghuram vsw_save_lmacaddr(vsw_t *vswp, uint64_t macaddr) 21451ae08745Sheppo { 21461ae08745Sheppo int i; 21471ae08745Sheppo 214806db247cSraghuram WRITE_ENTER(&vswp->if_lockrw); 214906db247cSraghuram for (i = ETHERADDRL - 1; i >= 0; i--) { 215006db247cSraghuram vswp->if_addr.ether_addr_octet[i] = macaddr & 0xFF; 215106db247cSraghuram macaddr >>= 8; 21521ae08745Sheppo } 215306db247cSraghuram RW_EXIT(&vswp->if_lockrw); 21541ae08745Sheppo } 2155