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 /* 236f09f0feSWENTAO YANG * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 241ae08745Sheppo * Use is subject to license terms. 251ae08745Sheppo */ 261ae08745Sheppo 271ae08745Sheppo #include <sys/types.h> 281ae08745Sheppo #include <sys/errno.h> 291ae08745Sheppo #include <sys/param.h> 301ae08745Sheppo #include <sys/stream.h> 311ae08745Sheppo #include <sys/kmem.h> 321ae08745Sheppo #include <sys/conf.h> 331ae08745Sheppo #include <sys/devops.h> 341ae08745Sheppo #include <sys/ksynch.h> 351ae08745Sheppo #include <sys/stat.h> 361ae08745Sheppo #include <sys/modctl.h> 37c1c61f44Ssb155480 #include <sys/modhash.h> 381ae08745Sheppo #include <sys/debug.h> 391ae08745Sheppo #include <sys/ethernet.h> 401ae08745Sheppo #include <sys/dlpi.h> 411ae08745Sheppo #include <net/if.h> 42da14cebeSEric Cheng #include <sys/mac_provider.h> 43ba2e4443Sseb #include <sys/mac_ether.h> 441ae08745Sheppo #include <sys/ddi.h> 451ae08745Sheppo #include <sys/sunddi.h> 461ae08745Sheppo #include <sys/strsun.h> 471ae08745Sheppo #include <sys/note.h> 48c1c61f44Ssb155480 #include <sys/atomic.h> 491ae08745Sheppo #include <sys/vnet.h> 50c1c61f44Ssb155480 #include <sys/vlan.h> 51678453a8Sspeer #include <sys/vnet_mailbox.h> 52678453a8Sspeer #include <sys/vnet_common.h> 53678453a8Sspeer #include <sys/dds.h> 54678453a8Sspeer #include <sys/strsubr.h> 55678453a8Sspeer #include <sys/taskq.h> 561ae08745Sheppo 571ae08745Sheppo /* 581ae08745Sheppo * Function prototypes. 591ae08745Sheppo */ 601ae08745Sheppo 611ae08745Sheppo /* DDI entrypoints */ 621ae08745Sheppo static int vnetdevinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 631ae08745Sheppo static int vnetattach(dev_info_t *, ddi_attach_cmd_t); 641ae08745Sheppo static int vnetdetach(dev_info_t *, ddi_detach_cmd_t); 651ae08745Sheppo 661ae08745Sheppo /* MAC entrypoints */ 67ba2e4443Sseb static int vnet_m_stat(void *, uint_t, uint64_t *); 681ae08745Sheppo static int vnet_m_start(void *); 691ae08745Sheppo static void vnet_m_stop(void *); 701ae08745Sheppo static int vnet_m_promisc(void *, boolean_t); 711ae08745Sheppo static int vnet_m_multicst(void *, boolean_t, const uint8_t *); 721ae08745Sheppo static int vnet_m_unicst(void *, const uint8_t *); 731ae08745Sheppo mblk_t *vnet_m_tx(void *, mblk_t *); 741107ea93SSriharsha Basavapatna static void vnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp); 751107ea93SSriharsha Basavapatna #ifdef VNET_IOC_DEBUG 761107ea93SSriharsha Basavapatna static void vnet_force_link_state(vnet_t *vnetp, queue_t *q, mblk_t *mp); 771107ea93SSriharsha Basavapatna #endif 781ae08745Sheppo 791ae08745Sheppo /* vnet internal functions */ 806f09f0feSWENTAO YANG static int vnet_unattach(vnet_t *vnetp); 811ae08745Sheppo static int vnet_mac_register(vnet_t *); 821ae08745Sheppo static int vnet_read_mac_address(vnet_t *vnetp); 831ae08745Sheppo 84c1c61f44Ssb155480 /* Forwarding database (FDB) routines */ 85c1c61f44Ssb155480 static void vnet_fdb_create(vnet_t *vnetp); 86c1c61f44Ssb155480 static void vnet_fdb_destroy(vnet_t *vnetp); 87678453a8Sspeer static vnet_res_t *vnet_fdbe_find(vnet_t *vnetp, struct ether_addr *addrp); 88c1c61f44Ssb155480 static void vnet_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val); 89678453a8Sspeer void vnet_fdbe_add(vnet_t *vnetp, vnet_res_t *vresp); 90678453a8Sspeer static void vnet_fdbe_del(vnet_t *vnetp, vnet_res_t *vresp); 91c1c61f44Ssb155480 928c242ab0SSriharsha Basavapatna static void vnet_rx_frames_untag(uint16_t pvid, mblk_t **mp); 93678453a8Sspeer static void vnet_rx(vio_net_handle_t vrh, mblk_t *mp); 94678453a8Sspeer static void vnet_tx_update(vio_net_handle_t vrh); 95678453a8Sspeer static void vnet_res_start_task(void *arg); 96678453a8Sspeer static void vnet_start_resources(vnet_t *vnetp); 97678453a8Sspeer static void vnet_stop_resources(vnet_t *vnetp); 98678453a8Sspeer static void vnet_dispatch_res_task(vnet_t *vnetp); 99678453a8Sspeer static void vnet_res_start_task(void *arg); 100678453a8Sspeer static void vnet_handle_res_err(vio_net_handle_t vrh, vio_net_err_val_t err); 1011107ea93SSriharsha Basavapatna 1021107ea93SSriharsha Basavapatna /* Exported to vnet_gen */ 1037b1f684aSSriharsha Basavapatna int vnet_mtu_update(vnet_t *vnetp, uint32_t mtu); 1041107ea93SSriharsha Basavapatna void vnet_link_update(vnet_t *vnetp, link_state_t link_state); 105*6d6de4eeSWENTAO YANG void vnet_dds_cleanup_hio(vnet_t *vnetp); 106678453a8Sspeer 1076ab6cb20SWENTAO YANG static kstat_t *vnet_hio_setup_kstats(char *ks_mod, char *ks_name, 1086ab6cb20SWENTAO YANG vnet_res_t *vresp); 1096ab6cb20SWENTAO YANG static int vnet_hio_update_kstats(kstat_t *ksp, int rw); 1106ab6cb20SWENTAO YANG static void vnet_hio_get_stats(vnet_res_t *vresp, vnet_hio_stats_t *statsp); 1116ab6cb20SWENTAO YANG static void vnet_hio_destroy_kstats(kstat_t *ksp); 1126ab6cb20SWENTAO YANG 113678453a8Sspeer /* Exported to to vnet_dds */ 114678453a8Sspeer int vnet_send_dds_msg(vnet_t *vnetp, void *dmsg); 115678453a8Sspeer 116678453a8Sspeer /* Externs that are imported from vnet_gen */ 117678453a8Sspeer extern int vgen_init(void *vnetp, uint64_t regprop, dev_info_t *vnetdip, 118678453a8Sspeer const uint8_t *macaddr, void **vgenhdl); 1193ab636deSWENTAO YANG extern void vgen_uninit(void *arg); 120678453a8Sspeer extern int vgen_dds_tx(void *arg, void *dmsg); 1216f09f0feSWENTAO YANG extern void vgen_mod_init(void); 1226f09f0feSWENTAO YANG extern int vgen_mod_cleanup(void); 1236f09f0feSWENTAO YANG extern void vgen_mod_fini(void); 124678453a8Sspeer 125678453a8Sspeer /* Externs that are imported from vnet_dds */ 126678453a8Sspeer extern void vdds_mod_init(void); 127678453a8Sspeer extern void vdds_mod_fini(void); 128678453a8Sspeer extern int vdds_init(vnet_t *vnetp); 129678453a8Sspeer extern void vdds_cleanup(vnet_t *vnetp); 130678453a8Sspeer extern void vdds_process_dds_msg(vnet_t *vnetp, vio_dds_msg_t *dmsg); 131d0288fccSRaghuram Kothakota extern void vdds_cleanup_hybrid_res(void *arg); 132*6d6de4eeSWENTAO YANG extern void vdds_cleanup_hio(vnet_t *vnetp); 1331ae08745Sheppo 1346ab6cb20SWENTAO YANG #define DRV_NAME "vnet" 135c1c61f44Ssb155480 #define VNET_FDBE_REFHOLD(p) \ 136c1c61f44Ssb155480 { \ 137c1c61f44Ssb155480 atomic_inc_32(&(p)->refcnt); \ 138c1c61f44Ssb155480 ASSERT((p)->refcnt != 0); \ 139c1c61f44Ssb155480 } 140c1c61f44Ssb155480 141c1c61f44Ssb155480 #define VNET_FDBE_REFRELE(p) \ 142c1c61f44Ssb155480 { \ 143c1c61f44Ssb155480 ASSERT((p)->refcnt != 0); \ 144c1c61f44Ssb155480 atomic_dec_32(&(p)->refcnt); \ 145c1c61f44Ssb155480 } 146c1c61f44Ssb155480 1471107ea93SSriharsha Basavapatna #ifdef VNET_IOC_DEBUG 1481107ea93SSriharsha Basavapatna #define VNET_M_CALLBACK_FLAGS (MC_IOCTL) 1491107ea93SSriharsha Basavapatna #else 1501107ea93SSriharsha Basavapatna #define VNET_M_CALLBACK_FLAGS (0) 1511107ea93SSriharsha Basavapatna #endif 1521107ea93SSriharsha Basavapatna 153ba2e4443Sseb static mac_callbacks_t vnet_m_callbacks = { 1541107ea93SSriharsha Basavapatna VNET_M_CALLBACK_FLAGS, 155ba2e4443Sseb vnet_m_stat, 156ba2e4443Sseb vnet_m_start, 157ba2e4443Sseb vnet_m_stop, 158ba2e4443Sseb vnet_m_promisc, 159ba2e4443Sseb vnet_m_multicst, 160ba2e4443Sseb vnet_m_unicst, 161ba2e4443Sseb vnet_m_tx, 1621107ea93SSriharsha Basavapatna vnet_m_ioctl, 163ba2e4443Sseb NULL, 164ba2e4443Sseb NULL 165ba2e4443Sseb }; 166ba2e4443Sseb 1671ae08745Sheppo /* 1681ae08745Sheppo * Linked list of "vnet_t" structures - one per instance. 1691ae08745Sheppo */ 1701ae08745Sheppo static vnet_t *vnet_headp = NULL; 1711ae08745Sheppo static krwlock_t vnet_rw; 1721ae08745Sheppo 1731ae08745Sheppo /* Tunables */ 1741ae08745Sheppo uint32_t vnet_ntxds = VNET_NTXDS; /* power of 2 transmit descriptors */ 1751ae08745Sheppo uint32_t vnet_ldcwd_interval = VNET_LDCWD_INTERVAL; /* watchdog freq in msec */ 1761ae08745Sheppo uint32_t vnet_ldcwd_txtimeout = VNET_LDCWD_TXTIMEOUT; /* tx timeout in msec */ 177e1ebb9ecSlm66018 uint32_t vnet_ldc_mtu = VNET_LDC_MTU; /* ldc mtu */ 178c1c61f44Ssb155480 1797b1f684aSSriharsha Basavapatna /* 1807b1f684aSSriharsha Basavapatna * Set this to non-zero to enable additional internal receive buffer pools 1817b1f684aSSriharsha Basavapatna * based on the MTU of the device for better performance at the cost of more 1827b1f684aSSriharsha Basavapatna * memory consumption. This is turned off by default, to use allocb(9F) for 1837b1f684aSSriharsha Basavapatna * receive buffer allocations of sizes > 2K. 1847b1f684aSSriharsha Basavapatna */ 1857b1f684aSSriharsha Basavapatna boolean_t vnet_jumbo_rxpools = B_FALSE; 1867b1f684aSSriharsha Basavapatna 187c1c61f44Ssb155480 /* # of chains in fdb hash table */ 188c1c61f44Ssb155480 uint32_t vnet_fdb_nchains = VNET_NFDB_HASH; 189c1c61f44Ssb155480 190c1c61f44Ssb155480 /* Internal tunables */ 191c1c61f44Ssb155480 uint32_t vnet_ethermtu = 1500; /* mtu of the device */ 192c1c61f44Ssb155480 193c1c61f44Ssb155480 /* 194c1c61f44Ssb155480 * Default vlan id. This is only used internally when the "default-vlan-id" 195c1c61f44Ssb155480 * property is not present in the MD device node. Therefore, this should not be 196c1c61f44Ssb155480 * used as a tunable; if this value is changed, the corresponding variable 197c1c61f44Ssb155480 * should be updated to the same value in vsw and also other vnets connected to 198c1c61f44Ssb155480 * the same vsw. 199c1c61f44Ssb155480 */ 200c1c61f44Ssb155480 uint16_t vnet_default_vlan_id = 1; 201c1c61f44Ssb155480 202c1c61f44Ssb155480 /* delay in usec to wait for all references on a fdb entry to be dropped */ 203c1c61f44Ssb155480 uint32_t vnet_fdbe_refcnt_delay = 10; 2041ae08745Sheppo 205678453a8Sspeer static struct ether_addr etherbroadcastaddr = { 206678453a8Sspeer 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 207678453a8Sspeer }; 208678453a8Sspeer 209678453a8Sspeer 2101ae08745Sheppo /* 2111ae08745Sheppo * Property names 2121ae08745Sheppo */ 2131ae08745Sheppo static char macaddr_propname[] = "local-mac-address"; 2141ae08745Sheppo 2151ae08745Sheppo /* 2161ae08745Sheppo * This is the string displayed by modinfo(1m). 2171ae08745Sheppo */ 2187b1f684aSSriharsha Basavapatna static char vnet_ident[] = "vnet driver"; 2191ae08745Sheppo extern struct mod_ops mod_driverops; 2201ae08745Sheppo static struct cb_ops cb_vnetops = { 2211ae08745Sheppo nulldev, /* cb_open */ 2221ae08745Sheppo nulldev, /* cb_close */ 2231ae08745Sheppo nodev, /* cb_strategy */ 2241ae08745Sheppo nodev, /* cb_print */ 2251ae08745Sheppo nodev, /* cb_dump */ 2261ae08745Sheppo nodev, /* cb_read */ 2271ae08745Sheppo nodev, /* cb_write */ 2281ae08745Sheppo nodev, /* cb_ioctl */ 2291ae08745Sheppo nodev, /* cb_devmap */ 2301ae08745Sheppo nodev, /* cb_mmap */ 2311ae08745Sheppo nodev, /* cb_segmap */ 2321ae08745Sheppo nochpoll, /* cb_chpoll */ 2331ae08745Sheppo ddi_prop_op, /* cb_prop_op */ 2341ae08745Sheppo NULL, /* cb_stream */ 2351ae08745Sheppo (int)(D_MP) /* cb_flag */ 2361ae08745Sheppo }; 2371ae08745Sheppo 2381ae08745Sheppo static struct dev_ops vnetops = { 2391ae08745Sheppo DEVO_REV, /* devo_rev */ 2401ae08745Sheppo 0, /* devo_refcnt */ 2411ae08745Sheppo NULL, /* devo_getinfo */ 2421ae08745Sheppo nulldev, /* devo_identify */ 2431ae08745Sheppo nulldev, /* devo_probe */ 2441ae08745Sheppo vnetattach, /* devo_attach */ 2451ae08745Sheppo vnetdetach, /* devo_detach */ 2461ae08745Sheppo nodev, /* devo_reset */ 2471ae08745Sheppo &cb_vnetops, /* devo_cb_ops */ 24819397407SSherry Moore (struct bus_ops *)NULL, /* devo_bus_ops */ 24919397407SSherry Moore NULL, /* devo_power */ 25019397407SSherry Moore ddi_quiesce_not_supported, /* devo_quiesce */ 2511ae08745Sheppo }; 2521ae08745Sheppo 2531ae08745Sheppo static struct modldrv modldrv = { 2541ae08745Sheppo &mod_driverops, /* Type of module. This one is a driver */ 2551ae08745Sheppo vnet_ident, /* ID string */ 2561ae08745Sheppo &vnetops /* driver specific ops */ 2571ae08745Sheppo }; 2581ae08745Sheppo 2591ae08745Sheppo static struct modlinkage modlinkage = { 2601ae08745Sheppo MODREV_1, (void *)&modldrv, NULL 2611ae08745Sheppo }; 2621ae08745Sheppo 263844e62a3Sraghuram #ifdef DEBUG 2641ae08745Sheppo 2651ae08745Sheppo /* 2661ae08745Sheppo * Print debug messages - set to 0xf to enable all msgs 2671ae08745Sheppo */ 268844e62a3Sraghuram int vnet_dbglevel = 0x8; 2691ae08745Sheppo 270844e62a3Sraghuram static void 271844e62a3Sraghuram debug_printf(const char *fname, void *arg, const char *fmt, ...) 2721ae08745Sheppo { 2731ae08745Sheppo char buf[512]; 2741ae08745Sheppo va_list ap; 2751ae08745Sheppo vnet_t *vnetp = (vnet_t *)arg; 276844e62a3Sraghuram char *bufp = buf; 2771ae08745Sheppo 278844e62a3Sraghuram if (vnetp == NULL) { 279844e62a3Sraghuram (void) sprintf(bufp, "%s: ", fname); 280844e62a3Sraghuram bufp += strlen(bufp); 281844e62a3Sraghuram } else { 282844e62a3Sraghuram (void) sprintf(bufp, "vnet%d:%s: ", vnetp->instance, fname); 283844e62a3Sraghuram bufp += strlen(bufp); 2841ae08745Sheppo } 285844e62a3Sraghuram va_start(ap, fmt); 286844e62a3Sraghuram (void) vsprintf(bufp, fmt, ap); 287844e62a3Sraghuram va_end(ap); 288844e62a3Sraghuram cmn_err(CE_CONT, "%s\n", buf); 289844e62a3Sraghuram } 2901ae08745Sheppo 2911ae08745Sheppo #endif 2921ae08745Sheppo 2931ae08745Sheppo /* _init(9E): initialize the loadable module */ 2941ae08745Sheppo int 2951ae08745Sheppo _init(void) 2961ae08745Sheppo { 2971ae08745Sheppo int status; 2981ae08745Sheppo 299844e62a3Sraghuram DBG1(NULL, "enter\n"); 3001ae08745Sheppo 3011ae08745Sheppo mac_init_ops(&vnetops, "vnet"); 3021ae08745Sheppo status = mod_install(&modlinkage); 3031ae08745Sheppo if (status != 0) { 3041ae08745Sheppo mac_fini_ops(&vnetops); 3051ae08745Sheppo } 306678453a8Sspeer vdds_mod_init(); 3076f09f0feSWENTAO YANG vgen_mod_init(); 308844e62a3Sraghuram DBG1(NULL, "exit(%d)\n", status); 3091ae08745Sheppo return (status); 3101ae08745Sheppo } 3111ae08745Sheppo 3121ae08745Sheppo /* _fini(9E): prepare the module for unloading. */ 3131ae08745Sheppo int 3141ae08745Sheppo _fini(void) 3151ae08745Sheppo { 3161ae08745Sheppo int status; 3171ae08745Sheppo 318844e62a3Sraghuram DBG1(NULL, "enter\n"); 3191ae08745Sheppo 3206f09f0feSWENTAO YANG status = vgen_mod_cleanup(); 3216f09f0feSWENTAO YANG if (status != 0) 3226f09f0feSWENTAO YANG return (status); 3236f09f0feSWENTAO YANG 3241ae08745Sheppo status = mod_remove(&modlinkage); 3251ae08745Sheppo if (status != 0) 3261ae08745Sheppo return (status); 3271ae08745Sheppo mac_fini_ops(&vnetops); 3286f09f0feSWENTAO YANG vgen_mod_fini(); 329678453a8Sspeer vdds_mod_fini(); 3301ae08745Sheppo 331844e62a3Sraghuram DBG1(NULL, "exit(%d)\n", status); 3321ae08745Sheppo return (status); 3331ae08745Sheppo } 3341ae08745Sheppo 3351ae08745Sheppo /* _info(9E): return information about the loadable module */ 3361ae08745Sheppo int 3371ae08745Sheppo _info(struct modinfo *modinfop) 3381ae08745Sheppo { 3391ae08745Sheppo return (mod_info(&modlinkage, modinfop)); 3401ae08745Sheppo } 3411ae08745Sheppo 3421ae08745Sheppo /* 3431ae08745Sheppo * attach(9E): attach a device to the system. 3441ae08745Sheppo * called once for each instance of the device on the system. 3451ae08745Sheppo */ 3461ae08745Sheppo static int 3471ae08745Sheppo vnetattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 3481ae08745Sheppo { 3491ae08745Sheppo vnet_t *vnetp; 3501ae08745Sheppo int status; 351678453a8Sspeer int instance; 352678453a8Sspeer uint64_t reg; 353678453a8Sspeer char qname[TASKQ_NAMELEN]; 3546f09f0feSWENTAO YANG vnet_attach_progress_t attach_progress; 3551ae08745Sheppo 3566f09f0feSWENTAO YANG attach_progress = AST_init; 3571ae08745Sheppo 3581ae08745Sheppo switch (cmd) { 3591ae08745Sheppo case DDI_ATTACH: 3601ae08745Sheppo break; 3611ae08745Sheppo case DDI_RESUME: 3621ae08745Sheppo case DDI_PM_RESUME: 3631ae08745Sheppo default: 3641ae08745Sheppo goto vnet_attach_fail; 3651ae08745Sheppo } 3661ae08745Sheppo 3671ae08745Sheppo instance = ddi_get_instance(dip); 368844e62a3Sraghuram DBG1(NULL, "instance(%d) enter\n", instance); 3691ae08745Sheppo 3701ae08745Sheppo /* allocate vnet_t and mac_t structures */ 3711ae08745Sheppo vnetp = kmem_zalloc(sizeof (vnet_t), KM_SLEEP); 372678453a8Sspeer vnetp->dip = dip; 373678453a8Sspeer vnetp->instance = instance; 374678453a8Sspeer rw_init(&vnetp->vrwlock, NULL, RW_DRIVER, NULL); 375678453a8Sspeer rw_init(&vnetp->vsw_fp_rw, NULL, RW_DRIVER, NULL); 3766f09f0feSWENTAO YANG attach_progress |= AST_vnet_alloc; 3771ae08745Sheppo 378678453a8Sspeer status = vdds_init(vnetp); 379678453a8Sspeer if (status != 0) { 380678453a8Sspeer goto vnet_attach_fail; 381678453a8Sspeer } 3826f09f0feSWENTAO YANG attach_progress |= AST_vdds_init; 383678453a8Sspeer 3841ae08745Sheppo /* setup links to vnet_t from both devinfo and mac_t */ 3851ae08745Sheppo ddi_set_driver_private(dip, (caddr_t)vnetp); 3861ae08745Sheppo 3871ae08745Sheppo /* read the mac address */ 3881ae08745Sheppo status = vnet_read_mac_address(vnetp); 3891ae08745Sheppo if (status != DDI_SUCCESS) { 3901ae08745Sheppo goto vnet_attach_fail; 3911ae08745Sheppo } 3926f09f0feSWENTAO YANG attach_progress |= AST_read_macaddr; 3931ae08745Sheppo 394678453a8Sspeer reg = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 395678453a8Sspeer DDI_PROP_DONTPASS, "reg", -1); 396678453a8Sspeer if (reg == -1) { 3971ae08745Sheppo goto vnet_attach_fail; 3981ae08745Sheppo } 399678453a8Sspeer vnetp->reg = reg; 4001ae08745Sheppo 401c1c61f44Ssb155480 vnet_fdb_create(vnetp); 4026f09f0feSWENTAO YANG attach_progress |= AST_fdbh_alloc; 4031ae08745Sheppo 404678453a8Sspeer (void) snprintf(qname, TASKQ_NAMELEN, "vnet_taskq%d", instance); 405678453a8Sspeer if ((vnetp->taskqp = ddi_taskq_create(dip, qname, 1, 406678453a8Sspeer TASKQ_DEFAULTPRI, 0)) == NULL) { 407678453a8Sspeer cmn_err(CE_WARN, "!vnet%d: Unable to create task queue", 408678453a8Sspeer instance); 4091ae08745Sheppo goto vnet_attach_fail; 4101ae08745Sheppo } 4116f09f0feSWENTAO YANG attach_progress |= AST_taskq_create; 4121ae08745Sheppo 4131ae08745Sheppo /* add to the list of vnet devices */ 4141ae08745Sheppo WRITE_ENTER(&vnet_rw); 4151ae08745Sheppo vnetp->nextp = vnet_headp; 4161ae08745Sheppo vnet_headp = vnetp; 4171ae08745Sheppo RW_EXIT(&vnet_rw); 4181ae08745Sheppo 4196f09f0feSWENTAO YANG attach_progress |= AST_vnet_list; 420678453a8Sspeer 421678453a8Sspeer /* 422678453a8Sspeer * Initialize the generic vnet plugin which provides 423678453a8Sspeer * communication via sun4v LDC (logical domain channel) based 424678453a8Sspeer * resources. It will register the LDC resources as and when 425678453a8Sspeer * they become available. 426678453a8Sspeer */ 427678453a8Sspeer status = vgen_init(vnetp, reg, vnetp->dip, 428678453a8Sspeer (uint8_t *)vnetp->curr_macaddr, &vnetp->vgenhdl); 429678453a8Sspeer if (status != DDI_SUCCESS) { 430678453a8Sspeer DERR(vnetp, "vgen_init() failed\n"); 431678453a8Sspeer goto vnet_attach_fail; 432678453a8Sspeer } 4336f09f0feSWENTAO YANG attach_progress |= AST_vgen_init; 434678453a8Sspeer 435678453a8Sspeer /* register with MAC layer */ 436678453a8Sspeer status = vnet_mac_register(vnetp); 437678453a8Sspeer if (status != DDI_SUCCESS) { 438678453a8Sspeer goto vnet_attach_fail; 439678453a8Sspeer } 4401107ea93SSriharsha Basavapatna vnetp->link_state = LINK_STATE_UNKNOWN; 441678453a8Sspeer 4426f09f0feSWENTAO YANG attach_progress |= AST_macreg; 4436f09f0feSWENTAO YANG 4446f09f0feSWENTAO YANG vnetp->attach_progress = attach_progress; 4456f09f0feSWENTAO YANG 446844e62a3Sraghuram DBG1(NULL, "instance(%d) exit\n", instance); 4471ae08745Sheppo return (DDI_SUCCESS); 4481ae08745Sheppo 4491ae08745Sheppo vnet_attach_fail: 4506f09f0feSWENTAO YANG vnetp->attach_progress = attach_progress; 4513ab636deSWENTAO YANG status = vnet_unattach(vnetp); 4523ab636deSWENTAO YANG ASSERT(status == 0); 4531ae08745Sheppo return (DDI_FAILURE); 4541ae08745Sheppo } 4551ae08745Sheppo 4561ae08745Sheppo /* 4571ae08745Sheppo * detach(9E): detach a device from the system. 4581ae08745Sheppo */ 4591ae08745Sheppo static int 4601ae08745Sheppo vnetdetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4611ae08745Sheppo { 4621ae08745Sheppo vnet_t *vnetp; 4631ae08745Sheppo int instance; 4641ae08745Sheppo 4651ae08745Sheppo instance = ddi_get_instance(dip); 466844e62a3Sraghuram DBG1(NULL, "instance(%d) enter\n", instance); 4671ae08745Sheppo 4681ae08745Sheppo vnetp = ddi_get_driver_private(dip); 4691ae08745Sheppo if (vnetp == NULL) { 4701ae08745Sheppo goto vnet_detach_fail; 4711ae08745Sheppo } 4721ae08745Sheppo 4731ae08745Sheppo switch (cmd) { 4741ae08745Sheppo case DDI_DETACH: 4751ae08745Sheppo break; 4761ae08745Sheppo case DDI_SUSPEND: 4771ae08745Sheppo case DDI_PM_SUSPEND: 4781ae08745Sheppo default: 4791ae08745Sheppo goto vnet_detach_fail; 4801ae08745Sheppo } 4811ae08745Sheppo 4826f09f0feSWENTAO YANG if (vnet_unattach(vnetp) != 0) { 483d10e4ef2Snarayan goto vnet_detach_fail; 484d10e4ef2Snarayan } 485d10e4ef2Snarayan 4866f09f0feSWENTAO YANG return (DDI_SUCCESS); 4871ae08745Sheppo 4886f09f0feSWENTAO YANG vnet_detach_fail: 4896f09f0feSWENTAO YANG return (DDI_FAILURE); 4906f09f0feSWENTAO YANG } 4916f09f0feSWENTAO YANG 4926f09f0feSWENTAO YANG /* 4936f09f0feSWENTAO YANG * Common routine to handle vnetattach() failure and vnetdetach(). Note that 4946f09f0feSWENTAO YANG * the only reason this function could fail is if mac_unregister() fails. 4956f09f0feSWENTAO YANG * Otherwise, this function must ensure that all resources are freed and return 4966f09f0feSWENTAO YANG * success. 4976f09f0feSWENTAO YANG */ 4986f09f0feSWENTAO YANG static int 4996f09f0feSWENTAO YANG vnet_unattach(vnet_t *vnetp) 5006f09f0feSWENTAO YANG { 5016f09f0feSWENTAO YANG vnet_attach_progress_t attach_progress; 5026f09f0feSWENTAO YANG 5036f09f0feSWENTAO YANG attach_progress = vnetp->attach_progress; 5046f09f0feSWENTAO YANG 5056f09f0feSWENTAO YANG /* 5066f09f0feSWENTAO YANG * Unregister from the gldv3 subsystem. This can fail, in particular 5076f09f0feSWENTAO YANG * if there are still any open references to this mac device; in which 5086f09f0feSWENTAO YANG * case we just return failure without continuing to detach further. 5096f09f0feSWENTAO YANG */ 5106f09f0feSWENTAO YANG if (attach_progress & AST_macreg) { 5116f09f0feSWENTAO YANG if (mac_unregister(vnetp->mh) != 0) { 5126f09f0feSWENTAO YANG return (1); 5136f09f0feSWENTAO YANG } 5146f09f0feSWENTAO YANG attach_progress &= ~AST_macreg; 5156f09f0feSWENTAO YANG } 5166f09f0feSWENTAO YANG 5176f09f0feSWENTAO YANG /* 5186f09f0feSWENTAO YANG * Now that we have unregistered from gldv3, we must finish all other 5196f09f0feSWENTAO YANG * steps and successfully return from this function; otherwise we will 5206f09f0feSWENTAO YANG * end up leaving the device in a broken/unusable state. 5216f09f0feSWENTAO YANG * 5226f09f0feSWENTAO YANG * First, release any hybrid resources assigned to this vnet device. 5236f09f0feSWENTAO YANG */ 5246f09f0feSWENTAO YANG if (attach_progress & AST_vdds_init) { 5256f09f0feSWENTAO YANG vdds_cleanup(vnetp); 5266f09f0feSWENTAO YANG attach_progress &= ~AST_vdds_init; 5276f09f0feSWENTAO YANG } 5286f09f0feSWENTAO YANG 5296f09f0feSWENTAO YANG /* 5306f09f0feSWENTAO YANG * Uninit vgen. This stops further mdeg callbacks to this vnet 5316f09f0feSWENTAO YANG * device and/or its ports; and detaches any existing ports. 5326f09f0feSWENTAO YANG */ 5336f09f0feSWENTAO YANG if (attach_progress & AST_vgen_init) { 5346f09f0feSWENTAO YANG vgen_uninit(vnetp->vgenhdl); 5356f09f0feSWENTAO YANG attach_progress &= ~AST_vgen_init; 5366f09f0feSWENTAO YANG } 5376f09f0feSWENTAO YANG 5386f09f0feSWENTAO YANG /* Destroy the taskq. */ 5396f09f0feSWENTAO YANG if (attach_progress & AST_taskq_create) { 5406f09f0feSWENTAO YANG ddi_taskq_destroy(vnetp->taskqp); 5416f09f0feSWENTAO YANG attach_progress &= ~AST_taskq_create; 5426f09f0feSWENTAO YANG } 5436f09f0feSWENTAO YANG 5446f09f0feSWENTAO YANG /* Destroy fdb. */ 5456f09f0feSWENTAO YANG if (attach_progress & AST_fdbh_alloc) { 5466f09f0feSWENTAO YANG vnet_fdb_destroy(vnetp); 5476f09f0feSWENTAO YANG attach_progress &= ~AST_fdbh_alloc; 5486f09f0feSWENTAO YANG } 5496f09f0feSWENTAO YANG 5506f09f0feSWENTAO YANG /* Remove from the device list */ 5516f09f0feSWENTAO YANG if (attach_progress & AST_vnet_list) { 5526f09f0feSWENTAO YANG vnet_t **vnetpp; 5531ae08745Sheppo /* unlink from instance(vnet_t) list */ 5541ae08745Sheppo WRITE_ENTER(&vnet_rw); 5556f09f0feSWENTAO YANG for (vnetpp = &vnet_headp; *vnetpp; 5566f09f0feSWENTAO YANG vnetpp = &(*vnetpp)->nextp) { 5571ae08745Sheppo if (*vnetpp == vnetp) { 5581ae08745Sheppo *vnetpp = vnetp->nextp; 5591ae08745Sheppo break; 5601ae08745Sheppo } 5611ae08745Sheppo } 5621ae08745Sheppo RW_EXIT(&vnet_rw); 5636f09f0feSWENTAO YANG attach_progress &= ~AST_vnet_list; 5646f09f0feSWENTAO YANG } 5651ae08745Sheppo 5666f09f0feSWENTAO YANG if (attach_progress & AST_vnet_alloc) { 567678453a8Sspeer rw_destroy(&vnetp->vrwlock); 568678453a8Sspeer rw_destroy(&vnetp->vsw_fp_rw); 5696f09f0feSWENTAO YANG attach_progress &= ~AST_vnet_list; 5701ae08745Sheppo KMEM_FREE(vnetp); 5716f09f0feSWENTAO YANG } 5721ae08745Sheppo 5736f09f0feSWENTAO YANG return (0); 5741ae08745Sheppo } 5751ae08745Sheppo 5761ae08745Sheppo /* enable the device for transmit/receive */ 5771ae08745Sheppo static int 5781ae08745Sheppo vnet_m_start(void *arg) 5791ae08745Sheppo { 5801ae08745Sheppo vnet_t *vnetp = arg; 5811ae08745Sheppo 582844e62a3Sraghuram DBG1(vnetp, "enter\n"); 5831ae08745Sheppo 584678453a8Sspeer WRITE_ENTER(&vnetp->vrwlock); 585678453a8Sspeer vnetp->flags |= VNET_STARTED; 586678453a8Sspeer vnet_start_resources(vnetp); 587678453a8Sspeer RW_EXIT(&vnetp->vrwlock); 5881ae08745Sheppo 589844e62a3Sraghuram DBG1(vnetp, "exit\n"); 5901ae08745Sheppo return (VNET_SUCCESS); 5911ae08745Sheppo 5921ae08745Sheppo } 5931ae08745Sheppo 5941ae08745Sheppo /* stop transmit/receive for the device */ 5951ae08745Sheppo static void 5961ae08745Sheppo vnet_m_stop(void *arg) 5971ae08745Sheppo { 5981ae08745Sheppo vnet_t *vnetp = arg; 5991ae08745Sheppo 600844e62a3Sraghuram DBG1(vnetp, "enter\n"); 6011ae08745Sheppo 602678453a8Sspeer WRITE_ENTER(&vnetp->vrwlock); 603678453a8Sspeer if (vnetp->flags & VNET_STARTED) { 604678453a8Sspeer vnet_stop_resources(vnetp); 605678453a8Sspeer vnetp->flags &= ~VNET_STARTED; 6061ae08745Sheppo } 607678453a8Sspeer RW_EXIT(&vnetp->vrwlock); 6081ae08745Sheppo 609844e62a3Sraghuram DBG1(vnetp, "exit\n"); 6101ae08745Sheppo } 6111ae08745Sheppo 6121ae08745Sheppo /* set the unicast mac address of the device */ 6131ae08745Sheppo static int 6141ae08745Sheppo vnet_m_unicst(void *arg, const uint8_t *macaddr) 6151ae08745Sheppo { 6161ae08745Sheppo _NOTE(ARGUNUSED(macaddr)) 6171ae08745Sheppo 6181ae08745Sheppo vnet_t *vnetp = arg; 6191ae08745Sheppo 620844e62a3Sraghuram DBG1(vnetp, "enter\n"); 6211ae08745Sheppo /* 6223af08d82Slm66018 * NOTE: setting mac address dynamically is not supported. 6231ae08745Sheppo */ 624844e62a3Sraghuram DBG1(vnetp, "exit\n"); 6251ae08745Sheppo 6268e6a2a04Slm66018 return (VNET_FAILURE); 6271ae08745Sheppo } 6281ae08745Sheppo 6291ae08745Sheppo /* enable/disable a multicast address */ 6301ae08745Sheppo static int 6311ae08745Sheppo vnet_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 6321ae08745Sheppo { 6331ae08745Sheppo _NOTE(ARGUNUSED(add, mca)) 6341ae08745Sheppo 6351ae08745Sheppo vnet_t *vnetp = arg; 636678453a8Sspeer vnet_res_t *vresp; 637678453a8Sspeer mac_register_t *macp; 638ba2e4443Sseb mac_callbacks_t *cbp; 6391ae08745Sheppo int rv = VNET_SUCCESS; 6401ae08745Sheppo 641844e62a3Sraghuram DBG1(vnetp, "enter\n"); 642678453a8Sspeer 643678453a8Sspeer READ_ENTER(&vnetp->vrwlock); 644678453a8Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) { 645678453a8Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) { 646678453a8Sspeer macp = &vresp->macreg; 647678453a8Sspeer cbp = macp->m_callbacks; 648678453a8Sspeer rv = cbp->mc_multicst(macp->m_driver, add, mca); 6491ae08745Sheppo } 6501ae08745Sheppo } 651678453a8Sspeer RW_EXIT(&vnetp->vrwlock); 652678453a8Sspeer 653844e62a3Sraghuram DBG1(vnetp, "exit(%d)\n", rv); 6541ae08745Sheppo return (rv); 6551ae08745Sheppo } 6561ae08745Sheppo 6571ae08745Sheppo /* set or clear promiscuous mode on the device */ 6581ae08745Sheppo static int 6591ae08745Sheppo vnet_m_promisc(void *arg, boolean_t on) 6601ae08745Sheppo { 6611ae08745Sheppo _NOTE(ARGUNUSED(on)) 6621ae08745Sheppo 6631ae08745Sheppo vnet_t *vnetp = arg; 664844e62a3Sraghuram DBG1(vnetp, "enter\n"); 6651ae08745Sheppo /* 6663af08d82Slm66018 * NOTE: setting promiscuous mode is not supported, just return success. 6671ae08745Sheppo */ 668844e62a3Sraghuram DBG1(vnetp, "exit\n"); 6691ae08745Sheppo return (VNET_SUCCESS); 6701ae08745Sheppo } 6711ae08745Sheppo 6721ae08745Sheppo /* 6731ae08745Sheppo * Transmit a chain of packets. This function provides switching functionality 6741ae08745Sheppo * based on the destination mac address to reach other guests (within ldoms) or 6751ae08745Sheppo * external hosts. 6761ae08745Sheppo */ 6771ae08745Sheppo mblk_t * 6781ae08745Sheppo vnet_m_tx(void *arg, mblk_t *mp) 6791ae08745Sheppo { 6801ae08745Sheppo vnet_t *vnetp; 681678453a8Sspeer vnet_res_t *vresp; 6821ae08745Sheppo mblk_t *next; 6831ae08745Sheppo mblk_t *resid_mp; 684678453a8Sspeer mac_register_t *macp; 685c1c61f44Ssb155480 struct ether_header *ehp; 686678453a8Sspeer boolean_t is_unicast; 6878c242ab0SSriharsha Basavapatna boolean_t is_pvid; /* non-default pvid ? */ 6888c242ab0SSriharsha Basavapatna boolean_t hres; /* Hybrid resource ? */ 6891ae08745Sheppo 6901ae08745Sheppo vnetp = (vnet_t *)arg; 691844e62a3Sraghuram DBG1(vnetp, "enter\n"); 6921ae08745Sheppo ASSERT(mp != NULL); 6931ae08745Sheppo 6948c242ab0SSriharsha Basavapatna is_pvid = (vnetp->pvid != vnetp->default_vlan_id) ? B_TRUE : B_FALSE; 6958c242ab0SSriharsha Basavapatna 6961ae08745Sheppo while (mp != NULL) { 697c1c61f44Ssb155480 6981ae08745Sheppo next = mp->b_next; 6991ae08745Sheppo mp->b_next = NULL; 7001ae08745Sheppo 7011ae08745Sheppo /* 702c1c61f44Ssb155480 * Find fdb entry for the destination 703c1c61f44Ssb155480 * and hold a reference to it. 7041ae08745Sheppo */ 705c1c61f44Ssb155480 ehp = (struct ether_header *)mp->b_rptr; 706678453a8Sspeer vresp = vnet_fdbe_find(vnetp, &ehp->ether_dhost); 707678453a8Sspeer if (vresp != NULL) { 708c1c61f44Ssb155480 709c1c61f44Ssb155480 /* 710c1c61f44Ssb155480 * Destination found in FDB. 711c1c61f44Ssb155480 * The destination is a vnet device within ldoms 712c1c61f44Ssb155480 * and directly reachable, invoke the tx function 713c1c61f44Ssb155480 * in the fdb entry. 714c1c61f44Ssb155480 */ 715678453a8Sspeer macp = &vresp->macreg; 716678453a8Sspeer resid_mp = macp->m_callbacks->mc_tx(macp->m_driver, mp); 717c1c61f44Ssb155480 718c1c61f44Ssb155480 /* tx done; now release ref on fdb entry */ 719678453a8Sspeer VNET_FDBE_REFRELE(vresp); 720c1c61f44Ssb155480 7211ae08745Sheppo if (resid_mp != NULL) { 7221ae08745Sheppo /* m_tx failed */ 7231ae08745Sheppo mp->b_next = next; 7241ae08745Sheppo break; 7251ae08745Sheppo } 7261ae08745Sheppo } else { 727678453a8Sspeer is_unicast = !(IS_BROADCAST(ehp) || 728678453a8Sspeer (IS_MULTICAST(ehp))); 7291ae08745Sheppo /* 730c1c61f44Ssb155480 * Destination is not in FDB. 731678453a8Sspeer * If the destination is broadcast or multicast, 732678453a8Sspeer * then forward the packet to vswitch. 733678453a8Sspeer * If a Hybrid resource avilable, then send the 734678453a8Sspeer * unicast packet via hybrid resource, otherwise 735678453a8Sspeer * forward it to vswitch. 7361ae08745Sheppo */ 737c1c61f44Ssb155480 READ_ENTER(&vnetp->vsw_fp_rw); 738c1c61f44Ssb155480 739678453a8Sspeer if ((is_unicast) && (vnetp->hio_fp != NULL)) { 740678453a8Sspeer vresp = vnetp->hio_fp; 7418c242ab0SSriharsha Basavapatna hres = B_TRUE; 742678453a8Sspeer } else { 743678453a8Sspeer vresp = vnetp->vsw_fp; 7448c242ab0SSriharsha Basavapatna hres = B_FALSE; 745678453a8Sspeer } 746678453a8Sspeer if (vresp == NULL) { 747c1c61f44Ssb155480 /* 748c1c61f44Ssb155480 * no fdb entry to vsw? drop the packet. 749c1c61f44Ssb155480 */ 750c1c61f44Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 751c1c61f44Ssb155480 freemsg(mp); 752c1c61f44Ssb155480 mp = next; 753c1c61f44Ssb155480 continue; 754c1c61f44Ssb155480 } 755c1c61f44Ssb155480 756c1c61f44Ssb155480 /* ref hold the fdb entry to vsw */ 757678453a8Sspeer VNET_FDBE_REFHOLD(vresp); 758c1c61f44Ssb155480 759c1c61f44Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 760c1c61f44Ssb155480 7618c242ab0SSriharsha Basavapatna /* 7628c242ab0SSriharsha Basavapatna * In the case of a hybrid resource we need to insert 7638c242ab0SSriharsha Basavapatna * the tag for the pvid case here; unlike packets that 7648c242ab0SSriharsha Basavapatna * are destined to a vnet/vsw in which case the vgen 7658c242ab0SSriharsha Basavapatna * layer does the tagging before sending it over ldc. 7668c242ab0SSriharsha Basavapatna */ 7678c242ab0SSriharsha Basavapatna if (hres == B_TRUE) { 7688c242ab0SSriharsha Basavapatna /* 7698c242ab0SSriharsha Basavapatna * Determine if the frame being transmitted 7708c242ab0SSriharsha Basavapatna * over the hybrid resource is untagged. If so, 7718c242ab0SSriharsha Basavapatna * insert the tag before transmitting. 7728c242ab0SSriharsha Basavapatna */ 7738c242ab0SSriharsha Basavapatna if (is_pvid == B_TRUE && 7748c242ab0SSriharsha Basavapatna ehp->ether_type != htons(ETHERTYPE_VLAN)) { 7758c242ab0SSriharsha Basavapatna 7768c242ab0SSriharsha Basavapatna mp = vnet_vlan_insert_tag(mp, 7778c242ab0SSriharsha Basavapatna vnetp->pvid); 7788c242ab0SSriharsha Basavapatna if (mp == NULL) { 7798c242ab0SSriharsha Basavapatna VNET_FDBE_REFRELE(vresp); 7808c242ab0SSriharsha Basavapatna mp = next; 7818c242ab0SSriharsha Basavapatna continue; 7828c242ab0SSriharsha Basavapatna } 7838c242ab0SSriharsha Basavapatna 7848c242ab0SSriharsha Basavapatna } 7858c242ab0SSriharsha Basavapatna } 7868c242ab0SSriharsha Basavapatna 787678453a8Sspeer macp = &vresp->macreg; 788678453a8Sspeer resid_mp = macp->m_callbacks->mc_tx(macp->m_driver, mp); 789c1c61f44Ssb155480 790c1c61f44Ssb155480 /* tx done; now release ref on fdb entry */ 791678453a8Sspeer VNET_FDBE_REFRELE(vresp); 792c1c61f44Ssb155480 7931ae08745Sheppo if (resid_mp != NULL) { 7941ae08745Sheppo /* m_tx failed */ 7951ae08745Sheppo mp->b_next = next; 7961ae08745Sheppo break; 7971ae08745Sheppo } 7981ae08745Sheppo } 7991ae08745Sheppo 8001ae08745Sheppo mp = next; 8011ae08745Sheppo } 8021ae08745Sheppo 803844e62a3Sraghuram DBG1(vnetp, "exit\n"); 8041ae08745Sheppo return (mp); 8051ae08745Sheppo } 8061ae08745Sheppo 8071ae08745Sheppo /* get statistics from the device */ 808ba2e4443Sseb int 809ba2e4443Sseb vnet_m_stat(void *arg, uint_t stat, uint64_t *val) 8101ae08745Sheppo { 8111ae08745Sheppo vnet_t *vnetp = arg; 812678453a8Sspeer vnet_res_t *vresp; 813678453a8Sspeer mac_register_t *macp; 814ba2e4443Sseb mac_callbacks_t *cbp; 815ba2e4443Sseb uint64_t val_total = 0; 8161ae08745Sheppo 817844e62a3Sraghuram DBG1(vnetp, "enter\n"); 8181ae08745Sheppo 8191ae08745Sheppo /* 820ba2e4443Sseb * get the specified statistic from each transport and return the 821ba2e4443Sseb * aggregate val. This obviously only works for counters. 8221ae08745Sheppo */ 823ba2e4443Sseb if ((IS_MAC_STAT(stat) && !MAC_STAT_ISACOUNTER(stat)) || 824ba2e4443Sseb (IS_MACTYPE_STAT(stat) && !ETHER_STAT_ISACOUNTER(stat))) { 825ba2e4443Sseb return (ENOTSUP); 826ba2e4443Sseb } 827678453a8Sspeer 828678453a8Sspeer READ_ENTER(&vnetp->vrwlock); 829678453a8Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) { 830678453a8Sspeer macp = &vresp->macreg; 831678453a8Sspeer cbp = macp->m_callbacks; 832678453a8Sspeer if (cbp->mc_getstat(macp->m_driver, stat, val) == 0) 833ba2e4443Sseb val_total += *val; 8341ae08745Sheppo } 835678453a8Sspeer RW_EXIT(&vnetp->vrwlock); 8361ae08745Sheppo 837ba2e4443Sseb *val = val_total; 838ba2e4443Sseb 839844e62a3Sraghuram DBG1(vnetp, "exit\n"); 840ba2e4443Sseb return (0); 8411ae08745Sheppo } 8421ae08745Sheppo 8431ae08745Sheppo /* wrapper function for mac_register() */ 8441ae08745Sheppo static int 8451ae08745Sheppo vnet_mac_register(vnet_t *vnetp) 8461ae08745Sheppo { 847ba2e4443Sseb mac_register_t *macp; 848ba2e4443Sseb int err; 8491ae08745Sheppo 850ba2e4443Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 851ba2e4443Sseb return (DDI_FAILURE); 852ba2e4443Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 853ba2e4443Sseb macp->m_driver = vnetp; 8541ae08745Sheppo macp->m_dip = vnetp->dip; 855ba2e4443Sseb macp->m_src_addr = vnetp->curr_macaddr; 856ba2e4443Sseb macp->m_callbacks = &vnet_m_callbacks; 857ba2e4443Sseb macp->m_min_sdu = 0; 8587b1f684aSSriharsha Basavapatna macp->m_max_sdu = vnetp->mtu; 859c1c61f44Ssb155480 macp->m_margin = VLAN_TAGSZ; 8601ae08745Sheppo 8611ae08745Sheppo /* 8621ae08745Sheppo * Finally, we're ready to register ourselves with the MAC layer 8631ae08745Sheppo * interface; if this succeeds, we're all ready to start() 8641ae08745Sheppo */ 865ba2e4443Sseb err = mac_register(macp, &vnetp->mh); 866ba2e4443Sseb mac_free(macp); 867ba2e4443Sseb return (err == 0 ? DDI_SUCCESS : DDI_FAILURE); 8681ae08745Sheppo } 8691ae08745Sheppo 8701ae08745Sheppo /* read the mac address of the device */ 8711ae08745Sheppo static int 8721ae08745Sheppo vnet_read_mac_address(vnet_t *vnetp) 8731ae08745Sheppo { 8741ae08745Sheppo uchar_t *macaddr; 8751ae08745Sheppo uint32_t size; 8761ae08745Sheppo int rv; 8771ae08745Sheppo 8781ae08745Sheppo rv = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, vnetp->dip, 8791ae08745Sheppo DDI_PROP_DONTPASS, macaddr_propname, &macaddr, &size); 8801ae08745Sheppo if ((rv != DDI_PROP_SUCCESS) || (size != ETHERADDRL)) { 881844e62a3Sraghuram DWARN(vnetp, "prop_lookup failed(%s) err(%d)\n", 882844e62a3Sraghuram macaddr_propname, rv); 8831ae08745Sheppo return (DDI_FAILURE); 8841ae08745Sheppo } 8851ae08745Sheppo bcopy(macaddr, (caddr_t)vnetp->vendor_addr, ETHERADDRL); 8861ae08745Sheppo bcopy(macaddr, (caddr_t)vnetp->curr_macaddr, ETHERADDRL); 8871ae08745Sheppo ddi_prop_free(macaddr); 8881ae08745Sheppo 8891ae08745Sheppo return (DDI_SUCCESS); 8901ae08745Sheppo } 8911ae08745Sheppo 89293b13a42Swentaoy static void 893c1c61f44Ssb155480 vnet_fdb_create(vnet_t *vnetp) 89493b13a42Swentaoy { 895c1c61f44Ssb155480 char hashname[MAXNAMELEN]; 89693b13a42Swentaoy 897c1c61f44Ssb155480 (void) snprintf(hashname, MAXNAMELEN, "vnet%d-fdbhash", 898c1c61f44Ssb155480 vnetp->instance); 899c1c61f44Ssb155480 vnetp->fdb_nchains = vnet_fdb_nchains; 900c1c61f44Ssb155480 vnetp->fdb_hashp = mod_hash_create_ptrhash(hashname, vnetp->fdb_nchains, 901c1c61f44Ssb155480 mod_hash_null_valdtor, sizeof (void *)); 90293b13a42Swentaoy } 90393b13a42Swentaoy 90493b13a42Swentaoy static void 905c1c61f44Ssb155480 vnet_fdb_destroy(vnet_t *vnetp) 90693b13a42Swentaoy { 907c1c61f44Ssb155480 /* destroy fdb-hash-table */ 908c1c61f44Ssb155480 if (vnetp->fdb_hashp != NULL) { 909c1c61f44Ssb155480 mod_hash_destroy_hash(vnetp->fdb_hashp); 910c1c61f44Ssb155480 vnetp->fdb_hashp = NULL; 911c1c61f44Ssb155480 vnetp->fdb_nchains = 0; 912c1c61f44Ssb155480 } 91393b13a42Swentaoy } 91493b13a42Swentaoy 91593b13a42Swentaoy /* 916c1c61f44Ssb155480 * Add an entry into the fdb. 91793b13a42Swentaoy */ 9181ae08745Sheppo void 919678453a8Sspeer vnet_fdbe_add(vnet_t *vnetp, vnet_res_t *vresp) 9201ae08745Sheppo { 921c1c61f44Ssb155480 uint64_t addr = 0; 922c1c61f44Ssb155480 int rv; 923c1c61f44Ssb155480 924678453a8Sspeer KEY_HASH(addr, vresp->rem_macaddr); 9251ae08745Sheppo 9261ae08745Sheppo /* 927678453a8Sspeer * If the entry being added corresponds to LDC_SERVICE resource, 928678453a8Sspeer * that is, vswitch connection, it is added to the hash and also 929678453a8Sspeer * the entry is cached, an additional reference count reflects 930678453a8Sspeer * this. The HYBRID resource is not added to the hash, but only 931678453a8Sspeer * cached, as it is only used for sending out packets for unknown 932678453a8Sspeer * unicast destinations. 9331ae08745Sheppo */ 934678453a8Sspeer (vresp->type == VIO_NET_RES_LDC_SERVICE) ? 935678453a8Sspeer (vresp->refcnt = 1) : (vresp->refcnt = 0); 9361ae08745Sheppo 937c1c61f44Ssb155480 /* 938c1c61f44Ssb155480 * Note: duplicate keys will be rejected by mod_hash. 939c1c61f44Ssb155480 */ 940678453a8Sspeer if (vresp->type != VIO_NET_RES_HYBRID) { 941c1c61f44Ssb155480 rv = mod_hash_insert(vnetp->fdb_hashp, (mod_hash_key_t)addr, 942678453a8Sspeer (mod_hash_val_t)vresp); 943c1c61f44Ssb155480 if (rv != 0) { 944c1c61f44Ssb155480 DWARN(vnetp, "Duplicate macaddr key(%lx)\n", addr); 9451ae08745Sheppo return; 9461ae08745Sheppo } 947678453a8Sspeer } 9481ae08745Sheppo 949678453a8Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) { 950c1c61f44Ssb155480 /* Cache the fdb entry to vsw-port */ 951c1c61f44Ssb155480 WRITE_ENTER(&vnetp->vsw_fp_rw); 952c1c61f44Ssb155480 if (vnetp->vsw_fp == NULL) 953678453a8Sspeer vnetp->vsw_fp = vresp; 954678453a8Sspeer RW_EXIT(&vnetp->vsw_fp_rw); 955678453a8Sspeer } else if (vresp->type == VIO_NET_RES_HYBRID) { 956678453a8Sspeer /* Cache the fdb entry to hybrid resource */ 957678453a8Sspeer WRITE_ENTER(&vnetp->vsw_fp_rw); 958678453a8Sspeer if (vnetp->hio_fp == NULL) 959678453a8Sspeer vnetp->hio_fp = vresp; 960c1c61f44Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 961c1c61f44Ssb155480 } 9621ae08745Sheppo } 9631ae08745Sheppo 964c1c61f44Ssb155480 /* 965c1c61f44Ssb155480 * Remove an entry from fdb. 966c1c61f44Ssb155480 */ 967678453a8Sspeer static void 968678453a8Sspeer vnet_fdbe_del(vnet_t *vnetp, vnet_res_t *vresp) 9691ae08745Sheppo { 970c1c61f44Ssb155480 uint64_t addr = 0; 971c1c61f44Ssb155480 int rv; 972c1c61f44Ssb155480 uint32_t refcnt; 973678453a8Sspeer vnet_res_t *tmp; 974c1c61f44Ssb155480 975678453a8Sspeer KEY_HASH(addr, vresp->rem_macaddr); 9761ae08745Sheppo 9771ae08745Sheppo /* 978c1c61f44Ssb155480 * Remove the entry from fdb hash table. 979c1c61f44Ssb155480 * This prevents further references to this fdb entry. 9801ae08745Sheppo */ 981678453a8Sspeer if (vresp->type != VIO_NET_RES_HYBRID) { 982c1c61f44Ssb155480 rv = mod_hash_remove(vnetp->fdb_hashp, (mod_hash_key_t)addr, 983678453a8Sspeer (mod_hash_val_t *)&tmp); 984678453a8Sspeer if (rv != 0) { 985678453a8Sspeer /* 986678453a8Sspeer * As the resources are added to the hash only 987678453a8Sspeer * after they are started, this can occur if 988678453a8Sspeer * a resource unregisters before it is ever started. 989678453a8Sspeer */ 990678453a8Sspeer return; 991678453a8Sspeer } 992678453a8Sspeer } 9931ae08745Sheppo 994678453a8Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) { 995c1c61f44Ssb155480 WRITE_ENTER(&vnetp->vsw_fp_rw); 9961ae08745Sheppo 997678453a8Sspeer ASSERT(tmp == vnetp->vsw_fp); 998c1c61f44Ssb155480 vnetp->vsw_fp = NULL; 999c1c61f44Ssb155480 1000c1c61f44Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 1001678453a8Sspeer } else if (vresp->type == VIO_NET_RES_HYBRID) { 1002678453a8Sspeer WRITE_ENTER(&vnetp->vsw_fp_rw); 1003678453a8Sspeer 1004678453a8Sspeer vnetp->hio_fp = NULL; 1005678453a8Sspeer 1006678453a8Sspeer RW_EXIT(&vnetp->vsw_fp_rw); 10071ae08745Sheppo } 10081ae08745Sheppo 1009c1c61f44Ssb155480 /* 1010c1c61f44Ssb155480 * If there are threads already ref holding before the entry was 1011c1c61f44Ssb155480 * removed from hash table, then wait for ref count to drop to zero. 1012c1c61f44Ssb155480 */ 1013678453a8Sspeer (vresp->type == VIO_NET_RES_LDC_SERVICE) ? 1014678453a8Sspeer (refcnt = 1) : (refcnt = 0); 1015678453a8Sspeer while (vresp->refcnt > refcnt) { 1016c1c61f44Ssb155480 delay(drv_usectohz(vnet_fdbe_refcnt_delay)); 1017c1c61f44Ssb155480 } 1018c1c61f44Ssb155480 } 1019c1c61f44Ssb155480 1020c1c61f44Ssb155480 /* 1021c1c61f44Ssb155480 * Search fdb for a given mac address. If an entry is found, hold 1022c1c61f44Ssb155480 * a reference to it and return the entry; else returns NULL. 1023c1c61f44Ssb155480 */ 1024678453a8Sspeer static vnet_res_t * 1025c1c61f44Ssb155480 vnet_fdbe_find(vnet_t *vnetp, struct ether_addr *addrp) 1026c1c61f44Ssb155480 { 1027c1c61f44Ssb155480 uint64_t key = 0; 1028678453a8Sspeer vnet_res_t *vresp; 1029c1c61f44Ssb155480 int rv; 1030c1c61f44Ssb155480 1031678453a8Sspeer KEY_HASH(key, addrp->ether_addr_octet); 1032c1c61f44Ssb155480 1033c1c61f44Ssb155480 rv = mod_hash_find_cb(vnetp->fdb_hashp, (mod_hash_key_t)key, 1034678453a8Sspeer (mod_hash_val_t *)&vresp, vnet_fdbe_find_cb); 1035c1c61f44Ssb155480 1036c1c61f44Ssb155480 if (rv != 0) 1037c1c61f44Ssb155480 return (NULL); 1038c1c61f44Ssb155480 1039678453a8Sspeer return (vresp); 1040c1c61f44Ssb155480 } 1041c1c61f44Ssb155480 1042c1c61f44Ssb155480 /* 1043c1c61f44Ssb155480 * Callback function provided to mod_hash_find_cb(). After finding the fdb 1044c1c61f44Ssb155480 * entry corresponding to the key (macaddr), this callback will be invoked by 1045c1c61f44Ssb155480 * mod_hash_find_cb() to atomically increment the reference count on the fdb 1046c1c61f44Ssb155480 * entry before returning the found entry. 1047c1c61f44Ssb155480 */ 1048c1c61f44Ssb155480 static void 1049c1c61f44Ssb155480 vnet_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val) 1050c1c61f44Ssb155480 { 1051c1c61f44Ssb155480 _NOTE(ARGUNUSED(key)) 1052678453a8Sspeer VNET_FDBE_REFHOLD((vnet_res_t *)val); 1053678453a8Sspeer } 1054678453a8Sspeer 10558c242ab0SSriharsha Basavapatna /* 10568c242ab0SSriharsha Basavapatna * Frames received that are tagged with the pvid of the vnet device must be 10578c242ab0SSriharsha Basavapatna * untagged before sending up the stack. This function walks the chain of rx 10588c242ab0SSriharsha Basavapatna * frames, untags any such frames and returns the updated chain. 10598c242ab0SSriharsha Basavapatna * 10608c242ab0SSriharsha Basavapatna * Arguments: 10618c242ab0SSriharsha Basavapatna * pvid: pvid of the vnet device for which packets are being received 10628c242ab0SSriharsha Basavapatna * mp: head of pkt chain to be validated and untagged 10638c242ab0SSriharsha Basavapatna * 10648c242ab0SSriharsha Basavapatna * Returns: 10658c242ab0SSriharsha Basavapatna * mp: head of updated chain of packets 10668c242ab0SSriharsha Basavapatna */ 10678c242ab0SSriharsha Basavapatna static void 10688c242ab0SSriharsha Basavapatna vnet_rx_frames_untag(uint16_t pvid, mblk_t **mp) 10698c242ab0SSriharsha Basavapatna { 10708c242ab0SSriharsha Basavapatna struct ether_vlan_header *evhp; 10718c242ab0SSriharsha Basavapatna mblk_t *bp; 10728c242ab0SSriharsha Basavapatna mblk_t *bpt; 10738c242ab0SSriharsha Basavapatna mblk_t *bph; 10748c242ab0SSriharsha Basavapatna mblk_t *bpn; 10758c242ab0SSriharsha Basavapatna 10768c242ab0SSriharsha Basavapatna bpn = bph = bpt = NULL; 10778c242ab0SSriharsha Basavapatna 10788c242ab0SSriharsha Basavapatna for (bp = *mp; bp != NULL; bp = bpn) { 10798c242ab0SSriharsha Basavapatna 10808c242ab0SSriharsha Basavapatna bpn = bp->b_next; 10818c242ab0SSriharsha Basavapatna bp->b_next = bp->b_prev = NULL; 10828c242ab0SSriharsha Basavapatna 10838c242ab0SSriharsha Basavapatna evhp = (struct ether_vlan_header *)bp->b_rptr; 10848c242ab0SSriharsha Basavapatna 10858c242ab0SSriharsha Basavapatna if (ntohs(evhp->ether_tpid) == ETHERTYPE_VLAN && 10868c242ab0SSriharsha Basavapatna VLAN_ID(ntohs(evhp->ether_tci)) == pvid) { 10878c242ab0SSriharsha Basavapatna 10888c242ab0SSriharsha Basavapatna bp = vnet_vlan_remove_tag(bp); 10898c242ab0SSriharsha Basavapatna if (bp == NULL) { 10908c242ab0SSriharsha Basavapatna continue; 10918c242ab0SSriharsha Basavapatna } 10928c242ab0SSriharsha Basavapatna 10938c242ab0SSriharsha Basavapatna } 10948c242ab0SSriharsha Basavapatna 10958c242ab0SSriharsha Basavapatna /* build a chain of processed packets */ 10968c242ab0SSriharsha Basavapatna if (bph == NULL) { 10978c242ab0SSriharsha Basavapatna bph = bpt = bp; 10988c242ab0SSriharsha Basavapatna } else { 10998c242ab0SSriharsha Basavapatna bpt->b_next = bp; 11008c242ab0SSriharsha Basavapatna bpt = bp; 11018c242ab0SSriharsha Basavapatna } 11028c242ab0SSriharsha Basavapatna 11038c242ab0SSriharsha Basavapatna } 11048c242ab0SSriharsha Basavapatna 11058c242ab0SSriharsha Basavapatna *mp = bph; 11068c242ab0SSriharsha Basavapatna } 11078c242ab0SSriharsha Basavapatna 1108678453a8Sspeer static void 1109678453a8Sspeer vnet_rx(vio_net_handle_t vrh, mblk_t *mp) 1110678453a8Sspeer { 1111678453a8Sspeer vnet_res_t *vresp = (vnet_res_t *)vrh; 1112678453a8Sspeer vnet_t *vnetp = vresp->vnetp; 1113678453a8Sspeer 11148c242ab0SSriharsha Basavapatna if ((vnetp == NULL) || (vnetp->mh == 0)) { 1115678453a8Sspeer freemsgchain(mp); 11168c242ab0SSriharsha Basavapatna return; 1117678453a8Sspeer } 11188c242ab0SSriharsha Basavapatna 11198c242ab0SSriharsha Basavapatna /* 11208c242ab0SSriharsha Basavapatna * Packets received over a hybrid resource need additional processing 11218c242ab0SSriharsha Basavapatna * to remove the tag, for the pvid case. The underlying resource is 11228c242ab0SSriharsha Basavapatna * not aware of the vnet's pvid and thus packets are received with the 11238c242ab0SSriharsha Basavapatna * vlan tag in the header; unlike packets that are received over a ldc 11248c242ab0SSriharsha Basavapatna * channel in which case the peer vnet/vsw would have already removed 11258c242ab0SSriharsha Basavapatna * the tag. 11268c242ab0SSriharsha Basavapatna */ 11278c242ab0SSriharsha Basavapatna if (vresp->type == VIO_NET_RES_HYBRID && 11288c242ab0SSriharsha Basavapatna vnetp->pvid != vnetp->default_vlan_id) { 11298c242ab0SSriharsha Basavapatna 11308c242ab0SSriharsha Basavapatna vnet_rx_frames_untag(vnetp->pvid, &mp); 11318c242ab0SSriharsha Basavapatna if (mp == NULL) { 11328c242ab0SSriharsha Basavapatna return; 11338c242ab0SSriharsha Basavapatna } 11348c242ab0SSriharsha Basavapatna } 11358c242ab0SSriharsha Basavapatna 11368c242ab0SSriharsha Basavapatna mac_rx(vnetp->mh, NULL, mp); 11371ae08745Sheppo } 1138ba2e4443Sseb 1139ba2e4443Sseb void 1140678453a8Sspeer vnet_tx_update(vio_net_handle_t vrh) 1141ba2e4443Sseb { 1142678453a8Sspeer vnet_res_t *vresp = (vnet_res_t *)vrh; 1143678453a8Sspeer vnet_t *vnetp = vresp->vnetp; 1144ba2e4443Sseb 1145678453a8Sspeer if ((vnetp != NULL) && (vnetp->mh != NULL)) { 1146ba2e4443Sseb mac_tx_update(vnetp->mh); 1147ba2e4443Sseb } 1148678453a8Sspeer } 1149678453a8Sspeer 1150678453a8Sspeer /* 11517b1f684aSSriharsha Basavapatna * Update the new mtu of vnet into the mac layer. First check if the device has 11527b1f684aSSriharsha Basavapatna * been plumbed and if so fail the mtu update. Returns 0 on success. 11537b1f684aSSriharsha Basavapatna */ 11547b1f684aSSriharsha Basavapatna int 11557b1f684aSSriharsha Basavapatna vnet_mtu_update(vnet_t *vnetp, uint32_t mtu) 11567b1f684aSSriharsha Basavapatna { 11577b1f684aSSriharsha Basavapatna int rv; 11587b1f684aSSriharsha Basavapatna 11597b1f684aSSriharsha Basavapatna if (vnetp == NULL || vnetp->mh == NULL) { 11607b1f684aSSriharsha Basavapatna return (EINVAL); 11617b1f684aSSriharsha Basavapatna } 11627b1f684aSSriharsha Basavapatna 11637b1f684aSSriharsha Basavapatna WRITE_ENTER(&vnetp->vrwlock); 11647b1f684aSSriharsha Basavapatna 11657b1f684aSSriharsha Basavapatna if (vnetp->flags & VNET_STARTED) { 11667b1f684aSSriharsha Basavapatna RW_EXIT(&vnetp->vrwlock); 11677b1f684aSSriharsha Basavapatna cmn_err(CE_NOTE, "!vnet%d: Unable to process mtu " 11687b1f684aSSriharsha Basavapatna "update as the device is plumbed\n", 11697b1f684aSSriharsha Basavapatna vnetp->instance); 11707b1f684aSSriharsha Basavapatna return (EBUSY); 11717b1f684aSSriharsha Basavapatna } 11727b1f684aSSriharsha Basavapatna 11737b1f684aSSriharsha Basavapatna /* update mtu in the mac layer */ 11747b1f684aSSriharsha Basavapatna rv = mac_maxsdu_update(vnetp->mh, mtu); 11757b1f684aSSriharsha Basavapatna if (rv != 0) { 11767b1f684aSSriharsha Basavapatna RW_EXIT(&vnetp->vrwlock); 11777b1f684aSSriharsha Basavapatna cmn_err(CE_NOTE, 11787b1f684aSSriharsha Basavapatna "!vnet%d: Unable to update mtu with mac layer\n", 11797b1f684aSSriharsha Basavapatna vnetp->instance); 11807b1f684aSSriharsha Basavapatna return (EIO); 11817b1f684aSSriharsha Basavapatna } 11827b1f684aSSriharsha Basavapatna 11837b1f684aSSriharsha Basavapatna vnetp->mtu = mtu; 11847b1f684aSSriharsha Basavapatna 11857b1f684aSSriharsha Basavapatna RW_EXIT(&vnetp->vrwlock); 11867b1f684aSSriharsha Basavapatna 11877b1f684aSSriharsha Basavapatna return (0); 11887b1f684aSSriharsha Basavapatna } 11897b1f684aSSriharsha Basavapatna 11907b1f684aSSriharsha Basavapatna /* 11911107ea93SSriharsha Basavapatna * Update the link state of vnet to the mac layer. 11921107ea93SSriharsha Basavapatna */ 11931107ea93SSriharsha Basavapatna void 11941107ea93SSriharsha Basavapatna vnet_link_update(vnet_t *vnetp, link_state_t link_state) 11951107ea93SSriharsha Basavapatna { 11961107ea93SSriharsha Basavapatna if (vnetp == NULL || vnetp->mh == NULL) { 11971107ea93SSriharsha Basavapatna return; 11981107ea93SSriharsha Basavapatna } 11991107ea93SSriharsha Basavapatna 12001107ea93SSriharsha Basavapatna WRITE_ENTER(&vnetp->vrwlock); 12011107ea93SSriharsha Basavapatna if (vnetp->link_state == link_state) { 12021107ea93SSriharsha Basavapatna RW_EXIT(&vnetp->vrwlock); 12031107ea93SSriharsha Basavapatna return; 12041107ea93SSriharsha Basavapatna } 12051107ea93SSriharsha Basavapatna vnetp->link_state = link_state; 12061107ea93SSriharsha Basavapatna RW_EXIT(&vnetp->vrwlock); 12071107ea93SSriharsha Basavapatna 12081107ea93SSriharsha Basavapatna mac_link_update(vnetp->mh, link_state); 12091107ea93SSriharsha Basavapatna } 12101107ea93SSriharsha Basavapatna 12111107ea93SSriharsha Basavapatna /* 1212678453a8Sspeer * vio_net_resource_reg -- An interface called to register a resource 1213678453a8Sspeer * with vnet. 1214678453a8Sspeer * macp -- a GLDv3 mac_register that has all the details of 1215678453a8Sspeer * a resource and its callbacks etc. 1216678453a8Sspeer * type -- resource type. 1217678453a8Sspeer * local_macaddr -- resource's MAC address. This is used to 1218678453a8Sspeer * associate a resource with a corresponding vnet. 1219678453a8Sspeer * remote_macaddr -- remote side MAC address. This is ignored for 1220678453a8Sspeer * the Hybrid resources. 1221678453a8Sspeer * vhp -- A handle returned to the caller. 1222678453a8Sspeer * vcb -- A set of callbacks provided to the callers. 1223678453a8Sspeer */ 1224678453a8Sspeer int vio_net_resource_reg(mac_register_t *macp, vio_net_res_type_t type, 1225678453a8Sspeer ether_addr_t local_macaddr, ether_addr_t rem_macaddr, vio_net_handle_t *vhp, 1226678453a8Sspeer vio_net_callbacks_t *vcb) 1227678453a8Sspeer { 1228678453a8Sspeer vnet_t *vnetp; 1229678453a8Sspeer vnet_res_t *vresp; 1230678453a8Sspeer 1231678453a8Sspeer vresp = kmem_zalloc(sizeof (vnet_res_t), KM_SLEEP); 1232678453a8Sspeer ether_copy(local_macaddr, vresp->local_macaddr); 1233678453a8Sspeer ether_copy(rem_macaddr, vresp->rem_macaddr); 1234678453a8Sspeer vresp->type = type; 1235678453a8Sspeer bcopy(macp, &vresp->macreg, sizeof (mac_register_t)); 1236678453a8Sspeer 1237678453a8Sspeer DBG1(NULL, "Resource Registerig type=0%X\n", type); 1238678453a8Sspeer 1239678453a8Sspeer READ_ENTER(&vnet_rw); 1240678453a8Sspeer vnetp = vnet_headp; 1241678453a8Sspeer while (vnetp != NULL) { 1242678453a8Sspeer if (VNET_MATCH_RES(vresp, vnetp)) { 1243678453a8Sspeer vresp->vnetp = vnetp; 12446b8fc343SWENTAO YANG 12456b8fc343SWENTAO YANG /* Setup kstats for hio resource */ 12466b8fc343SWENTAO YANG if (vresp->type == VIO_NET_RES_HYBRID) { 12476b8fc343SWENTAO YANG vresp->ksp = vnet_hio_setup_kstats(DRV_NAME, 12486b8fc343SWENTAO YANG "hio", vresp); 12496b8fc343SWENTAO YANG if (vresp->ksp == NULL) { 12506b8fc343SWENTAO YANG cmn_err(CE_NOTE, "!vnet%d: Cannot " 12516b8fc343SWENTAO YANG "create kstats for hio resource", 12526b8fc343SWENTAO YANG vnetp->instance); 12536b8fc343SWENTAO YANG } 12546b8fc343SWENTAO YANG } 12556b8fc343SWENTAO YANG 12566b8fc343SWENTAO YANG WRITE_ENTER(&vnetp->vrwlock); 1257678453a8Sspeer vresp->nextp = vnetp->vres_list; 1258678453a8Sspeer vnetp->vres_list = vresp; 1259678453a8Sspeer RW_EXIT(&vnetp->vrwlock); 1260678453a8Sspeer break; 1261678453a8Sspeer } 1262678453a8Sspeer vnetp = vnetp->nextp; 1263678453a8Sspeer } 1264678453a8Sspeer RW_EXIT(&vnet_rw); 1265678453a8Sspeer if (vresp->vnetp == NULL) { 1266678453a8Sspeer DWARN(NULL, "No vnet instance"); 1267678453a8Sspeer kmem_free(vresp, sizeof (vnet_res_t)); 1268678453a8Sspeer return (ENXIO); 1269678453a8Sspeer } 1270678453a8Sspeer 1271678453a8Sspeer *vhp = vresp; 1272678453a8Sspeer vcb->vio_net_rx_cb = vnet_rx; 1273678453a8Sspeer vcb->vio_net_tx_update = vnet_tx_update; 1274678453a8Sspeer vcb->vio_net_report_err = vnet_handle_res_err; 1275678453a8Sspeer 1276678453a8Sspeer /* Dispatch a task to start resources */ 1277678453a8Sspeer vnet_dispatch_res_task(vnetp); 1278678453a8Sspeer return (0); 1279678453a8Sspeer } 1280678453a8Sspeer 1281678453a8Sspeer /* 1282678453a8Sspeer * vio_net_resource_unreg -- An interface to unregister a resource. 1283678453a8Sspeer */ 1284678453a8Sspeer void 1285678453a8Sspeer vio_net_resource_unreg(vio_net_handle_t vhp) 1286678453a8Sspeer { 1287678453a8Sspeer vnet_res_t *vresp = (vnet_res_t *)vhp; 1288678453a8Sspeer vnet_t *vnetp = vresp->vnetp; 1289678453a8Sspeer vnet_res_t *vrp; 12906ab6cb20SWENTAO YANG kstat_t *ksp = NULL; 1291678453a8Sspeer 1292678453a8Sspeer DBG1(NULL, "Resource Registerig hdl=0x%p", vhp); 1293678453a8Sspeer 1294678453a8Sspeer ASSERT(vnetp != NULL); 1295678453a8Sspeer vnet_fdbe_del(vnetp, vresp); 1296678453a8Sspeer 1297678453a8Sspeer WRITE_ENTER(&vnetp->vrwlock); 1298678453a8Sspeer if (vresp == vnetp->vres_list) { 1299678453a8Sspeer vnetp->vres_list = vresp->nextp; 1300678453a8Sspeer } else { 1301678453a8Sspeer vrp = vnetp->vres_list; 1302678453a8Sspeer while (vrp->nextp != NULL) { 1303678453a8Sspeer if (vrp->nextp == vresp) { 1304678453a8Sspeer vrp->nextp = vresp->nextp; 1305678453a8Sspeer break; 1306678453a8Sspeer } 1307678453a8Sspeer vrp = vrp->nextp; 1308678453a8Sspeer } 1309678453a8Sspeer } 13106ab6cb20SWENTAO YANG 13116ab6cb20SWENTAO YANG ksp = vresp->ksp; 13126ab6cb20SWENTAO YANG vresp->ksp = NULL; 13136ab6cb20SWENTAO YANG 1314678453a8Sspeer vresp->vnetp = NULL; 1315678453a8Sspeer vresp->nextp = NULL; 1316678453a8Sspeer RW_EXIT(&vnetp->vrwlock); 13176ab6cb20SWENTAO YANG vnet_hio_destroy_kstats(ksp); 1318678453a8Sspeer KMEM_FREE(vresp); 1319678453a8Sspeer } 1320678453a8Sspeer 1321678453a8Sspeer /* 1322678453a8Sspeer * vnet_dds_rx -- an interface called by vgen to DDS messages. 1323678453a8Sspeer */ 1324678453a8Sspeer void 1325678453a8Sspeer vnet_dds_rx(void *arg, void *dmsg) 1326678453a8Sspeer { 1327678453a8Sspeer vnet_t *vnetp = arg; 1328678453a8Sspeer vdds_process_dds_msg(vnetp, dmsg); 1329678453a8Sspeer } 1330678453a8Sspeer 1331678453a8Sspeer /* 1332678453a8Sspeer * vnet_send_dds_msg -- An interface provided to DDS to send 1333678453a8Sspeer * DDS messages. This simply sends meessages via vgen. 1334678453a8Sspeer */ 1335678453a8Sspeer int 1336678453a8Sspeer vnet_send_dds_msg(vnet_t *vnetp, void *dmsg) 1337678453a8Sspeer { 1338678453a8Sspeer int rv; 1339678453a8Sspeer 1340678453a8Sspeer if (vnetp->vgenhdl != NULL) { 1341678453a8Sspeer rv = vgen_dds_tx(vnetp->vgenhdl, dmsg); 1342678453a8Sspeer } 1343678453a8Sspeer return (rv); 1344678453a8Sspeer } 1345678453a8Sspeer 1346678453a8Sspeer /* 1347*6d6de4eeSWENTAO YANG * vnet_cleanup_hio -- an interface called by vgen to cleanup hio resources. 1348*6d6de4eeSWENTAO YANG */ 1349*6d6de4eeSWENTAO YANG void 1350*6d6de4eeSWENTAO YANG vnet_dds_cleanup_hio(vnet_t *vnetp) 1351*6d6de4eeSWENTAO YANG { 1352*6d6de4eeSWENTAO YANG vdds_cleanup_hio(vnetp); 1353*6d6de4eeSWENTAO YANG } 1354*6d6de4eeSWENTAO YANG 1355*6d6de4eeSWENTAO YANG /* 1356678453a8Sspeer * vnet_handle_res_err -- A callback function called by a resource 1357678453a8Sspeer * to report an error. For example, vgen can call to report 1358678453a8Sspeer * an LDC down/reset event. This will trigger cleanup of associated 1359678453a8Sspeer * Hybrid resource. 1360678453a8Sspeer */ 1361678453a8Sspeer /* ARGSUSED */ 1362678453a8Sspeer static void 1363678453a8Sspeer vnet_handle_res_err(vio_net_handle_t vrh, vio_net_err_val_t err) 1364678453a8Sspeer { 1365678453a8Sspeer vnet_res_t *vresp = (vnet_res_t *)vrh; 1366678453a8Sspeer vnet_t *vnetp = vresp->vnetp; 1367678453a8Sspeer 1368678453a8Sspeer if (vnetp == NULL) { 1369678453a8Sspeer return; 1370678453a8Sspeer } 1371678453a8Sspeer if ((vresp->type != VIO_NET_RES_LDC_SERVICE) && 1372678453a8Sspeer (vresp->type != VIO_NET_RES_HYBRID)) { 1373678453a8Sspeer return; 1374678453a8Sspeer } 1375*6d6de4eeSWENTAO YANG 1376*6d6de4eeSWENTAO YANG vdds_cleanup_hio(vnetp); 1377678453a8Sspeer } 1378678453a8Sspeer 1379678453a8Sspeer /* 1380678453a8Sspeer * vnet_dispatch_res_task -- A function to dispatch tasks start resources. 1381678453a8Sspeer */ 1382678453a8Sspeer static void 1383678453a8Sspeer vnet_dispatch_res_task(vnet_t *vnetp) 1384678453a8Sspeer { 1385678453a8Sspeer int rv; 1386678453a8Sspeer 1387678453a8Sspeer WRITE_ENTER(&vnetp->vrwlock); 1388678453a8Sspeer if (vnetp->flags & VNET_STARTED) { 1389678453a8Sspeer rv = ddi_taskq_dispatch(vnetp->taskqp, vnet_res_start_task, 1390678453a8Sspeer vnetp, DDI_NOSLEEP); 1391678453a8Sspeer if (rv != DDI_SUCCESS) { 1392678453a8Sspeer cmn_err(CE_WARN, 1393678453a8Sspeer "vnet%d:Can't dispatch start resource task", 1394678453a8Sspeer vnetp->instance); 1395678453a8Sspeer } 1396678453a8Sspeer } 1397678453a8Sspeer RW_EXIT(&vnetp->vrwlock); 1398678453a8Sspeer } 1399678453a8Sspeer 1400678453a8Sspeer /* 1401678453a8Sspeer * vnet_res_start_task -- A taskq callback function that starts a resource. 1402678453a8Sspeer */ 1403678453a8Sspeer static void 1404678453a8Sspeer vnet_res_start_task(void *arg) 1405678453a8Sspeer { 1406678453a8Sspeer vnet_t *vnetp = arg; 1407678453a8Sspeer 1408678453a8Sspeer WRITE_ENTER(&vnetp->vrwlock); 1409678453a8Sspeer if (vnetp->flags & VNET_STARTED) { 1410678453a8Sspeer vnet_start_resources(vnetp); 1411678453a8Sspeer } 1412678453a8Sspeer RW_EXIT(&vnetp->vrwlock); 1413678453a8Sspeer } 1414678453a8Sspeer 1415678453a8Sspeer /* 1416678453a8Sspeer * vnet_start_resources -- starts all resources associated with 1417678453a8Sspeer * a vnet. 1418678453a8Sspeer */ 1419678453a8Sspeer static void 1420678453a8Sspeer vnet_start_resources(vnet_t *vnetp) 1421678453a8Sspeer { 1422678453a8Sspeer mac_register_t *macp; 1423678453a8Sspeer mac_callbacks_t *cbp; 1424678453a8Sspeer vnet_res_t *vresp; 1425678453a8Sspeer int rv; 1426678453a8Sspeer 1427678453a8Sspeer DBG1(vnetp, "enter\n"); 1428678453a8Sspeer 1429678453a8Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) { 1430678453a8Sspeer /* skip if it is already started */ 1431678453a8Sspeer if (vresp->flags & VNET_STARTED) { 1432678453a8Sspeer continue; 1433678453a8Sspeer } 1434678453a8Sspeer macp = &vresp->macreg; 1435678453a8Sspeer cbp = macp->m_callbacks; 1436678453a8Sspeer rv = cbp->mc_start(macp->m_driver); 1437678453a8Sspeer if (rv == 0) { 1438678453a8Sspeer /* 1439678453a8Sspeer * Successfully started the resource, so now 1440678453a8Sspeer * add it to the fdb. 1441678453a8Sspeer */ 1442678453a8Sspeer vresp->flags |= VNET_STARTED; 1443678453a8Sspeer vnet_fdbe_add(vnetp, vresp); 1444678453a8Sspeer } 1445678453a8Sspeer } 1446678453a8Sspeer 1447678453a8Sspeer DBG1(vnetp, "exit\n"); 1448678453a8Sspeer 1449678453a8Sspeer } 1450678453a8Sspeer 1451678453a8Sspeer /* 1452678453a8Sspeer * vnet_stop_resources -- stop all resources associated with a vnet. 1453678453a8Sspeer */ 1454678453a8Sspeer static void 1455678453a8Sspeer vnet_stop_resources(vnet_t *vnetp) 1456678453a8Sspeer { 1457678453a8Sspeer vnet_res_t *vresp; 1458678453a8Sspeer vnet_res_t *nvresp; 1459678453a8Sspeer mac_register_t *macp; 1460678453a8Sspeer mac_callbacks_t *cbp; 1461678453a8Sspeer 1462678453a8Sspeer DBG1(vnetp, "enter\n"); 1463678453a8Sspeer 1464678453a8Sspeer for (vresp = vnetp->vres_list; vresp != NULL; ) { 1465678453a8Sspeer nvresp = vresp->nextp; 1466678453a8Sspeer if (vresp->flags & VNET_STARTED) { 1467678453a8Sspeer macp = &vresp->macreg; 1468678453a8Sspeer cbp = macp->m_callbacks; 1469678453a8Sspeer cbp->mc_stop(macp->m_driver); 1470678453a8Sspeer vresp->flags &= ~VNET_STARTED; 1471678453a8Sspeer } 1472678453a8Sspeer vresp = nvresp; 1473678453a8Sspeer } 1474678453a8Sspeer DBG1(vnetp, "exit\n"); 1475678453a8Sspeer } 14766ab6cb20SWENTAO YANG 14776ab6cb20SWENTAO YANG /* 14786ab6cb20SWENTAO YANG * Setup kstats for the HIO statistics. 14796ab6cb20SWENTAO YANG * NOTE: the synchronization for the statistics is the 14806ab6cb20SWENTAO YANG * responsibility of the caller. 14816ab6cb20SWENTAO YANG */ 14826ab6cb20SWENTAO YANG kstat_t * 14836ab6cb20SWENTAO YANG vnet_hio_setup_kstats(char *ks_mod, char *ks_name, vnet_res_t *vresp) 14846ab6cb20SWENTAO YANG { 14856ab6cb20SWENTAO YANG kstat_t *ksp; 14866ab6cb20SWENTAO YANG vnet_t *vnetp = vresp->vnetp; 14876ab6cb20SWENTAO YANG vnet_hio_kstats_t *hiokp; 14886ab6cb20SWENTAO YANG size_t size; 14896ab6cb20SWENTAO YANG 14906ab6cb20SWENTAO YANG ASSERT(vnetp != NULL); 14916ab6cb20SWENTAO YANG size = sizeof (vnet_hio_kstats_t) / sizeof (kstat_named_t); 14926ab6cb20SWENTAO YANG ksp = kstat_create(ks_mod, vnetp->instance, ks_name, "net", 14936ab6cb20SWENTAO YANG KSTAT_TYPE_NAMED, size, 0); 14946ab6cb20SWENTAO YANG if (ksp == NULL) { 14956ab6cb20SWENTAO YANG return (NULL); 14966ab6cb20SWENTAO YANG } 14976ab6cb20SWENTAO YANG 14986ab6cb20SWENTAO YANG hiokp = (vnet_hio_kstats_t *)ksp->ks_data; 14996ab6cb20SWENTAO YANG kstat_named_init(&hiokp->ipackets, "ipackets", 15006ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 15016ab6cb20SWENTAO YANG kstat_named_init(&hiokp->ierrors, "ierrors", 15026ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 15036ab6cb20SWENTAO YANG kstat_named_init(&hiokp->opackets, "opackets", 15046ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 15056ab6cb20SWENTAO YANG kstat_named_init(&hiokp->oerrors, "oerrors", 15066ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 15076ab6cb20SWENTAO YANG 15086ab6cb20SWENTAO YANG 15096ab6cb20SWENTAO YANG /* MIB II kstat variables */ 15106ab6cb20SWENTAO YANG kstat_named_init(&hiokp->rbytes, "rbytes", 15116ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 15126ab6cb20SWENTAO YANG kstat_named_init(&hiokp->obytes, "obytes", 15136ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 15146ab6cb20SWENTAO YANG kstat_named_init(&hiokp->multircv, "multircv", 15156ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 15166ab6cb20SWENTAO YANG kstat_named_init(&hiokp->multixmt, "multixmt", 15176ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 15186ab6cb20SWENTAO YANG kstat_named_init(&hiokp->brdcstrcv, "brdcstrcv", 15196ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 15206ab6cb20SWENTAO YANG kstat_named_init(&hiokp->brdcstxmt, "brdcstxmt", 15216ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 15226ab6cb20SWENTAO YANG kstat_named_init(&hiokp->norcvbuf, "norcvbuf", 15236ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 15246ab6cb20SWENTAO YANG kstat_named_init(&hiokp->noxmtbuf, "noxmtbuf", 15256ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 15266ab6cb20SWENTAO YANG 15276ab6cb20SWENTAO YANG ksp->ks_update = vnet_hio_update_kstats; 15286ab6cb20SWENTAO YANG ksp->ks_private = (void *)vresp; 15296ab6cb20SWENTAO YANG kstat_install(ksp); 15306ab6cb20SWENTAO YANG return (ksp); 15316ab6cb20SWENTAO YANG } 15326ab6cb20SWENTAO YANG 15336ab6cb20SWENTAO YANG /* 15346ab6cb20SWENTAO YANG * Destroy kstats. 15356ab6cb20SWENTAO YANG */ 15366ab6cb20SWENTAO YANG static void 15376ab6cb20SWENTAO YANG vnet_hio_destroy_kstats(kstat_t *ksp) 15386ab6cb20SWENTAO YANG { 15396ab6cb20SWENTAO YANG if (ksp != NULL) 15406ab6cb20SWENTAO YANG kstat_delete(ksp); 15416ab6cb20SWENTAO YANG } 15426ab6cb20SWENTAO YANG 15436ab6cb20SWENTAO YANG /* 15446ab6cb20SWENTAO YANG * Update the kstats. 15456ab6cb20SWENTAO YANG */ 15466ab6cb20SWENTAO YANG static int 15476ab6cb20SWENTAO YANG vnet_hio_update_kstats(kstat_t *ksp, int rw) 15486ab6cb20SWENTAO YANG { 15496ab6cb20SWENTAO YANG vnet_t *vnetp; 15506ab6cb20SWENTAO YANG vnet_res_t *vresp; 15516ab6cb20SWENTAO YANG vnet_hio_stats_t statsp; 15526ab6cb20SWENTAO YANG vnet_hio_kstats_t *hiokp; 15536ab6cb20SWENTAO YANG 15546ab6cb20SWENTAO YANG vresp = (vnet_res_t *)ksp->ks_private; 15556ab6cb20SWENTAO YANG vnetp = vresp->vnetp; 15566ab6cb20SWENTAO YANG 15576ab6cb20SWENTAO YANG bzero(&statsp, sizeof (vnet_hio_stats_t)); 15586ab6cb20SWENTAO YANG 15596ab6cb20SWENTAO YANG READ_ENTER(&vnetp->vsw_fp_rw); 15606ab6cb20SWENTAO YANG if (vnetp->hio_fp == NULL) { 15616ab6cb20SWENTAO YANG /* not using hio resources, just return */ 15626ab6cb20SWENTAO YANG RW_EXIT(&vnetp->vsw_fp_rw); 15636ab6cb20SWENTAO YANG return (0); 15646ab6cb20SWENTAO YANG } 15656ab6cb20SWENTAO YANG VNET_FDBE_REFHOLD(vnetp->hio_fp); 15666ab6cb20SWENTAO YANG RW_EXIT(&vnetp->vsw_fp_rw); 15676ab6cb20SWENTAO YANG vnet_hio_get_stats(vnetp->hio_fp, &statsp); 15686ab6cb20SWENTAO YANG VNET_FDBE_REFRELE(vnetp->hio_fp); 15696ab6cb20SWENTAO YANG 15706ab6cb20SWENTAO YANG hiokp = (vnet_hio_kstats_t *)ksp->ks_data; 15716ab6cb20SWENTAO YANG 15726ab6cb20SWENTAO YANG if (rw == KSTAT_READ) { 15736ab6cb20SWENTAO YANG /* Link Input/Output stats */ 15746ab6cb20SWENTAO YANG hiokp->ipackets.value.ul = (uint32_t)statsp.ipackets; 15756ab6cb20SWENTAO YANG hiokp->ipackets64.value.ull = statsp.ipackets; 15766ab6cb20SWENTAO YANG hiokp->ierrors.value.ul = statsp.ierrors; 15776ab6cb20SWENTAO YANG hiokp->opackets.value.ul = (uint32_t)statsp.opackets; 15786ab6cb20SWENTAO YANG hiokp->opackets64.value.ull = statsp.opackets; 15796ab6cb20SWENTAO YANG hiokp->oerrors.value.ul = statsp.oerrors; 15806ab6cb20SWENTAO YANG 15816ab6cb20SWENTAO YANG /* MIB II kstat variables */ 15826ab6cb20SWENTAO YANG hiokp->rbytes.value.ul = (uint32_t)statsp.rbytes; 15836ab6cb20SWENTAO YANG hiokp->rbytes64.value.ull = statsp.rbytes; 15846ab6cb20SWENTAO YANG hiokp->obytes.value.ul = (uint32_t)statsp.obytes; 15856ab6cb20SWENTAO YANG hiokp->obytes64.value.ull = statsp.obytes; 15866ab6cb20SWENTAO YANG hiokp->multircv.value.ul = statsp.multircv; 15876ab6cb20SWENTAO YANG hiokp->multixmt.value.ul = statsp.multixmt; 15886ab6cb20SWENTAO YANG hiokp->brdcstrcv.value.ul = statsp.brdcstrcv; 15896ab6cb20SWENTAO YANG hiokp->brdcstxmt.value.ul = statsp.brdcstxmt; 15906ab6cb20SWENTAO YANG hiokp->norcvbuf.value.ul = statsp.norcvbuf; 15916ab6cb20SWENTAO YANG hiokp->noxmtbuf.value.ul = statsp.noxmtbuf; 15926ab6cb20SWENTAO YANG } else { 15936ab6cb20SWENTAO YANG return (EACCES); 15946ab6cb20SWENTAO YANG } 15956ab6cb20SWENTAO YANG 15966ab6cb20SWENTAO YANG return (0); 15976ab6cb20SWENTAO YANG } 15986ab6cb20SWENTAO YANG 15996ab6cb20SWENTAO YANG static void 16006ab6cb20SWENTAO YANG vnet_hio_get_stats(vnet_res_t *vresp, vnet_hio_stats_t *statsp) 16016ab6cb20SWENTAO YANG { 16026ab6cb20SWENTAO YANG mac_register_t *macp; 16036ab6cb20SWENTAO YANG mac_callbacks_t *cbp; 16046ab6cb20SWENTAO YANG uint64_t val; 16056ab6cb20SWENTAO YANG int stat; 16066ab6cb20SWENTAO YANG 16076ab6cb20SWENTAO YANG /* 16086ab6cb20SWENTAO YANG * get the specified statistics from the underlying nxge. 16096ab6cb20SWENTAO YANG */ 16106ab6cb20SWENTAO YANG macp = &vresp->macreg; 16116ab6cb20SWENTAO YANG cbp = macp->m_callbacks; 16126ab6cb20SWENTAO YANG for (stat = MAC_STAT_MIN; stat < MAC_STAT_OVERFLOWS; stat++) { 16136ab6cb20SWENTAO YANG if (cbp->mc_getstat(macp->m_driver, stat, &val) == 0) { 16146ab6cb20SWENTAO YANG switch (stat) { 16156ab6cb20SWENTAO YANG case MAC_STAT_IPACKETS: 16166ab6cb20SWENTAO YANG statsp->ipackets = val; 16176ab6cb20SWENTAO YANG break; 16186ab6cb20SWENTAO YANG 16196ab6cb20SWENTAO YANG case MAC_STAT_IERRORS: 16206ab6cb20SWENTAO YANG statsp->ierrors = val; 16216ab6cb20SWENTAO YANG break; 16226ab6cb20SWENTAO YANG 16236ab6cb20SWENTAO YANG case MAC_STAT_OPACKETS: 16246ab6cb20SWENTAO YANG statsp->opackets = val; 16256ab6cb20SWENTAO YANG break; 16266ab6cb20SWENTAO YANG 16276ab6cb20SWENTAO YANG case MAC_STAT_OERRORS: 16286ab6cb20SWENTAO YANG statsp->oerrors = val; 16296ab6cb20SWENTAO YANG break; 16306ab6cb20SWENTAO YANG 16316ab6cb20SWENTAO YANG case MAC_STAT_RBYTES: 16326ab6cb20SWENTAO YANG statsp->rbytes = val; 16336ab6cb20SWENTAO YANG break; 16346ab6cb20SWENTAO YANG 16356ab6cb20SWENTAO YANG case MAC_STAT_OBYTES: 16366ab6cb20SWENTAO YANG statsp->obytes = val; 16376ab6cb20SWENTAO YANG break; 16386ab6cb20SWENTAO YANG 16396ab6cb20SWENTAO YANG case MAC_STAT_MULTIRCV: 16406ab6cb20SWENTAO YANG statsp->multircv = val; 16416ab6cb20SWENTAO YANG break; 16426ab6cb20SWENTAO YANG 16436ab6cb20SWENTAO YANG case MAC_STAT_MULTIXMT: 16446ab6cb20SWENTAO YANG statsp->multixmt = val; 16456ab6cb20SWENTAO YANG break; 16466ab6cb20SWENTAO YANG 16476ab6cb20SWENTAO YANG case MAC_STAT_BRDCSTRCV: 16486ab6cb20SWENTAO YANG statsp->brdcstrcv = val; 16496ab6cb20SWENTAO YANG break; 16506ab6cb20SWENTAO YANG 16516ab6cb20SWENTAO YANG case MAC_STAT_BRDCSTXMT: 16526ab6cb20SWENTAO YANG statsp->brdcstxmt = val; 16536ab6cb20SWENTAO YANG break; 16546ab6cb20SWENTAO YANG 16556ab6cb20SWENTAO YANG case MAC_STAT_NOXMTBUF: 16566ab6cb20SWENTAO YANG statsp->noxmtbuf = val; 16576ab6cb20SWENTAO YANG break; 16586ab6cb20SWENTAO YANG 16596ab6cb20SWENTAO YANG case MAC_STAT_NORCVBUF: 16606ab6cb20SWENTAO YANG statsp->norcvbuf = val; 16616ab6cb20SWENTAO YANG break; 16626ab6cb20SWENTAO YANG 16636ab6cb20SWENTAO YANG default: 16646ab6cb20SWENTAO YANG /* 16656ab6cb20SWENTAO YANG * parameters not interested. 16666ab6cb20SWENTAO YANG */ 16676ab6cb20SWENTAO YANG break; 16686ab6cb20SWENTAO YANG } 16696ab6cb20SWENTAO YANG } 16706ab6cb20SWENTAO YANG } 16716ab6cb20SWENTAO YANG } 16721107ea93SSriharsha Basavapatna 16731107ea93SSriharsha Basavapatna #ifdef VNET_IOC_DEBUG 16741107ea93SSriharsha Basavapatna 16751107ea93SSriharsha Basavapatna /* 16761107ea93SSriharsha Basavapatna * The ioctl entry point is used only for debugging for now. The ioctl commands 16771107ea93SSriharsha Basavapatna * can be used to force the link state of the channel connected to vsw. 16781107ea93SSriharsha Basavapatna */ 16791107ea93SSriharsha Basavapatna static void 16801107ea93SSriharsha Basavapatna vnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp) 16811107ea93SSriharsha Basavapatna { 16821107ea93SSriharsha Basavapatna struct iocblk *iocp; 16831107ea93SSriharsha Basavapatna vnet_t *vnetp; 16841107ea93SSriharsha Basavapatna 16851107ea93SSriharsha Basavapatna iocp = (struct iocblk *)(uintptr_t)mp->b_rptr; 16861107ea93SSriharsha Basavapatna iocp->ioc_error = 0; 16871107ea93SSriharsha Basavapatna vnetp = (vnet_t *)arg; 16881107ea93SSriharsha Basavapatna 16891107ea93SSriharsha Basavapatna if (vnetp == NULL) { 16901107ea93SSriharsha Basavapatna miocnak(q, mp, 0, EINVAL); 16911107ea93SSriharsha Basavapatna return; 16921107ea93SSriharsha Basavapatna } 16931107ea93SSriharsha Basavapatna 16941107ea93SSriharsha Basavapatna switch (iocp->ioc_cmd) { 16951107ea93SSriharsha Basavapatna 16961107ea93SSriharsha Basavapatna case VNET_FORCE_LINK_DOWN: 16971107ea93SSriharsha Basavapatna case VNET_FORCE_LINK_UP: 16981107ea93SSriharsha Basavapatna vnet_force_link_state(vnetp, q, mp); 16991107ea93SSriharsha Basavapatna break; 17001107ea93SSriharsha Basavapatna 17011107ea93SSriharsha Basavapatna default: 17021107ea93SSriharsha Basavapatna iocp->ioc_error = EINVAL; 17031107ea93SSriharsha Basavapatna miocnak(q, mp, 0, iocp->ioc_error); 17041107ea93SSriharsha Basavapatna break; 17051107ea93SSriharsha Basavapatna 17061107ea93SSriharsha Basavapatna } 17071107ea93SSriharsha Basavapatna } 17081107ea93SSriharsha Basavapatna 17091107ea93SSriharsha Basavapatna static void 17101107ea93SSriharsha Basavapatna vnet_force_link_state(vnet_t *vnetp, queue_t *q, mblk_t *mp) 17111107ea93SSriharsha Basavapatna { 17121107ea93SSriharsha Basavapatna mac_register_t *macp; 17131107ea93SSriharsha Basavapatna mac_callbacks_t *cbp; 17141107ea93SSriharsha Basavapatna vnet_res_t *vresp; 17151107ea93SSriharsha Basavapatna 17161107ea93SSriharsha Basavapatna READ_ENTER(&vnetp->vsw_fp_rw); 17171107ea93SSriharsha Basavapatna 17181107ea93SSriharsha Basavapatna vresp = vnetp->vsw_fp; 17191107ea93SSriharsha Basavapatna if (vresp == NULL) { 17201107ea93SSriharsha Basavapatna RW_EXIT(&vnetp->vsw_fp_rw); 17211107ea93SSriharsha Basavapatna return; 17221107ea93SSriharsha Basavapatna } 17231107ea93SSriharsha Basavapatna 17241107ea93SSriharsha Basavapatna macp = &vresp->macreg; 17251107ea93SSriharsha Basavapatna cbp = macp->m_callbacks; 17261107ea93SSriharsha Basavapatna cbp->mc_ioctl(macp->m_driver, q, mp); 17271107ea93SSriharsha Basavapatna 17281107ea93SSriharsha Basavapatna RW_EXIT(&vnetp->vsw_fp_rw); 17291107ea93SSriharsha Basavapatna } 17301107ea93SSriharsha Basavapatna 17311107ea93SSriharsha Basavapatna #else 17321107ea93SSriharsha Basavapatna 17331107ea93SSriharsha Basavapatna static void 17341107ea93SSriharsha Basavapatna vnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp) 17351107ea93SSriharsha Basavapatna { 17361107ea93SSriharsha Basavapatna vnet_t *vnetp; 17371107ea93SSriharsha Basavapatna 17381107ea93SSriharsha Basavapatna vnetp = (vnet_t *)arg; 17391107ea93SSriharsha Basavapatna 17401107ea93SSriharsha Basavapatna if (vnetp == NULL) { 17411107ea93SSriharsha Basavapatna miocnak(q, mp, 0, EINVAL); 17421107ea93SSriharsha Basavapatna return; 17431107ea93SSriharsha Basavapatna } 17441107ea93SSriharsha Basavapatna 17451107ea93SSriharsha Basavapatna /* ioctl support only for debugging */ 17461107ea93SSriharsha Basavapatna miocnak(q, mp, 0, ENOTSUP); 17471107ea93SSriharsha Basavapatna } 17481107ea93SSriharsha Basavapatna 17491107ea93SSriharsha Basavapatna #endif 1750