11991Sheppo /* 21991Sheppo * CDDL HEADER START 31991Sheppo * 41991Sheppo * The contents of this file are subject to the terms of the 51991Sheppo * Common Development and Distribution License (the "License"). 61991Sheppo * You may not use this file except in compliance with the License. 71991Sheppo * 81991Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91991Sheppo * or http://www.opensolaris.org/os/licensing. 101991Sheppo * See the License for the specific language governing permissions 111991Sheppo * and limitations under the License. 121991Sheppo * 131991Sheppo * When distributing Covered Code, include this CDDL HEADER in each 141991Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151991Sheppo * If applicable, add the following below this CDDL HEADER, with the 161991Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 171991Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 181991Sheppo * 191991Sheppo * CDDL HEADER END 201991Sheppo */ 211991Sheppo 221991Sheppo /* 239217SWentao.Yang@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 241991Sheppo * Use is subject to license terms. 251991Sheppo */ 261991Sheppo 271991Sheppo #include <sys/types.h> 281991Sheppo #include <sys/errno.h> 291991Sheppo #include <sys/param.h> 301991Sheppo #include <sys/stream.h> 311991Sheppo #include <sys/kmem.h> 321991Sheppo #include <sys/conf.h> 331991Sheppo #include <sys/devops.h> 341991Sheppo #include <sys/ksynch.h> 351991Sheppo #include <sys/stat.h> 361991Sheppo #include <sys/modctl.h> 376419Ssb155480 #include <sys/modhash.h> 381991Sheppo #include <sys/debug.h> 391991Sheppo #include <sys/ethernet.h> 401991Sheppo #include <sys/dlpi.h> 411991Sheppo #include <net/if.h> 428275SEric Cheng #include <sys/mac_provider.h> 432311Sseb #include <sys/mac_ether.h> 441991Sheppo #include <sys/ddi.h> 451991Sheppo #include <sys/sunddi.h> 461991Sheppo #include <sys/strsun.h> 471991Sheppo #include <sys/note.h> 486419Ssb155480 #include <sys/atomic.h> 491991Sheppo #include <sys/vnet.h> 506419Ssb155480 #include <sys/vlan.h> 516495Sspeer #include <sys/vnet_mailbox.h> 526495Sspeer #include <sys/vnet_common.h> 536495Sspeer #include <sys/dds.h> 546495Sspeer #include <sys/strsubr.h> 556495Sspeer #include <sys/taskq.h> 561991Sheppo 571991Sheppo /* 581991Sheppo * Function prototypes. 591991Sheppo */ 601991Sheppo 611991Sheppo /* DDI entrypoints */ 621991Sheppo static int vnetdevinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 631991Sheppo static int vnetattach(dev_info_t *, ddi_attach_cmd_t); 641991Sheppo static int vnetdetach(dev_info_t *, ddi_detach_cmd_t); 651991Sheppo 661991Sheppo /* MAC entrypoints */ 672311Sseb static int vnet_m_stat(void *, uint_t, uint64_t *); 681991Sheppo static int vnet_m_start(void *); 691991Sheppo static void vnet_m_stop(void *); 701991Sheppo static int vnet_m_promisc(void *, boolean_t); 711991Sheppo static int vnet_m_multicst(void *, boolean_t, const uint8_t *); 721991Sheppo static int vnet_m_unicst(void *, const uint8_t *); 731991Sheppo mblk_t *vnet_m_tx(void *, mblk_t *); 749336SSriharsha.Basavapatna@Sun.COM static void vnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp); 759336SSriharsha.Basavapatna@Sun.COM #ifdef VNET_IOC_DEBUG 769336SSriharsha.Basavapatna@Sun.COM static void vnet_force_link_state(vnet_t *vnetp, queue_t *q, mblk_t *mp); 779336SSriharsha.Basavapatna@Sun.COM #endif 781991Sheppo 791991Sheppo /* vnet internal functions */ 809217SWentao.Yang@Sun.COM static int vnet_unattach(vnet_t *vnetp); 811991Sheppo static int vnet_mac_register(vnet_t *); 821991Sheppo static int vnet_read_mac_address(vnet_t *vnetp); 831991Sheppo 846419Ssb155480 /* Forwarding database (FDB) routines */ 856419Ssb155480 static void vnet_fdb_create(vnet_t *vnetp); 866419Ssb155480 static void vnet_fdb_destroy(vnet_t *vnetp); 876495Sspeer static vnet_res_t *vnet_fdbe_find(vnet_t *vnetp, struct ether_addr *addrp); 886419Ssb155480 static void vnet_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val); 896495Sspeer void vnet_fdbe_add(vnet_t *vnetp, vnet_res_t *vresp); 906495Sspeer static void vnet_fdbe_del(vnet_t *vnetp, vnet_res_t *vresp); 916495Sspeer 927896SSriharsha.Basavapatna@Sun.COM static void vnet_rx_frames_untag(uint16_t pvid, mblk_t **mp); 936495Sspeer static void vnet_rx(vio_net_handle_t vrh, mblk_t *mp); 946495Sspeer static void vnet_tx_update(vio_net_handle_t vrh); 956495Sspeer static void vnet_res_start_task(void *arg); 966495Sspeer static void vnet_start_resources(vnet_t *vnetp); 976495Sspeer static void vnet_stop_resources(vnet_t *vnetp); 986495Sspeer static void vnet_dispatch_res_task(vnet_t *vnetp); 996495Sspeer static void vnet_res_start_task(void *arg); 1006495Sspeer static void vnet_handle_res_err(vio_net_handle_t vrh, vio_net_err_val_t err); 1019336SSriharsha.Basavapatna@Sun.COM 1029336SSriharsha.Basavapatna@Sun.COM /* Exported to vnet_gen */ 1037529SSriharsha.Basavapatna@Sun.COM int vnet_mtu_update(vnet_t *vnetp, uint32_t mtu); 1049336SSriharsha.Basavapatna@Sun.COM void vnet_link_update(vnet_t *vnetp, link_state_t link_state); 1059647SWentao.Yang@Sun.COM void vnet_dds_cleanup_hio(vnet_t *vnetp); 1066419Ssb155480 1078160SWentao.Yang@Sun.COM static kstat_t *vnet_hio_setup_kstats(char *ks_mod, char *ks_name, 1088160SWentao.Yang@Sun.COM vnet_res_t *vresp); 1098160SWentao.Yang@Sun.COM static int vnet_hio_update_kstats(kstat_t *ksp, int rw); 1108160SWentao.Yang@Sun.COM static void vnet_hio_get_stats(vnet_res_t *vresp, vnet_hio_stats_t *statsp); 1118160SWentao.Yang@Sun.COM static void vnet_hio_destroy_kstats(kstat_t *ksp); 1128160SWentao.Yang@Sun.COM 1136495Sspeer /* Exported to to vnet_dds */ 1146495Sspeer int vnet_send_dds_msg(vnet_t *vnetp, void *dmsg); 1151991Sheppo 1166495Sspeer /* Externs that are imported from vnet_gen */ 1176495Sspeer extern int vgen_init(void *vnetp, uint64_t regprop, dev_info_t *vnetdip, 1186495Sspeer const uint8_t *macaddr, void **vgenhdl); 1199235SWentao.Yang@Sun.COM extern void vgen_uninit(void *arg); 1206495Sspeer extern int vgen_dds_tx(void *arg, void *dmsg); 1219217SWentao.Yang@Sun.COM extern void vgen_mod_init(void); 1229217SWentao.Yang@Sun.COM extern int vgen_mod_cleanup(void); 1239217SWentao.Yang@Sun.COM extern void vgen_mod_fini(void); 1246495Sspeer 1256495Sspeer /* Externs that are imported from vnet_dds */ 1266495Sspeer extern void vdds_mod_init(void); 1276495Sspeer extern void vdds_mod_fini(void); 1286495Sspeer extern int vdds_init(vnet_t *vnetp); 1296495Sspeer extern void vdds_cleanup(vnet_t *vnetp); 1306495Sspeer extern void vdds_process_dds_msg(vnet_t *vnetp, vio_dds_msg_t *dmsg); 1317819SRaghuram.Kothakota@Sun.COM extern void vdds_cleanup_hybrid_res(void *arg); 1329647SWentao.Yang@Sun.COM extern void vdds_cleanup_hio(vnet_t *vnetp); 1331991Sheppo 1348160SWentao.Yang@Sun.COM #define DRV_NAME "vnet" 1356419Ssb155480 #define VNET_FDBE_REFHOLD(p) \ 1366419Ssb155480 { \ 1376419Ssb155480 atomic_inc_32(&(p)->refcnt); \ 1386419Ssb155480 ASSERT((p)->refcnt != 0); \ 1396419Ssb155480 } 1406419Ssb155480 1416419Ssb155480 #define VNET_FDBE_REFRELE(p) \ 1426419Ssb155480 { \ 1436419Ssb155480 ASSERT((p)->refcnt != 0); \ 1446419Ssb155480 atomic_dec_32(&(p)->refcnt); \ 1456419Ssb155480 } 1466419Ssb155480 1479336SSriharsha.Basavapatna@Sun.COM #ifdef VNET_IOC_DEBUG 1489336SSriharsha.Basavapatna@Sun.COM #define VNET_M_CALLBACK_FLAGS (MC_IOCTL) 1499336SSriharsha.Basavapatna@Sun.COM #else 1509336SSriharsha.Basavapatna@Sun.COM #define VNET_M_CALLBACK_FLAGS (0) 1519336SSriharsha.Basavapatna@Sun.COM #endif 1529336SSriharsha.Basavapatna@Sun.COM 1532311Sseb static mac_callbacks_t vnet_m_callbacks = { 1549336SSriharsha.Basavapatna@Sun.COM VNET_M_CALLBACK_FLAGS, 1552311Sseb vnet_m_stat, 1562311Sseb vnet_m_start, 1572311Sseb vnet_m_stop, 1582311Sseb vnet_m_promisc, 1592311Sseb vnet_m_multicst, 1602311Sseb vnet_m_unicst, 1612311Sseb vnet_m_tx, 1629336SSriharsha.Basavapatna@Sun.COM vnet_m_ioctl, 1632311Sseb NULL, 1642311Sseb NULL 1652311Sseb }; 1662311Sseb 1671991Sheppo /* 1681991Sheppo * Linked list of "vnet_t" structures - one per instance. 1691991Sheppo */ 1701991Sheppo static vnet_t *vnet_headp = NULL; 1711991Sheppo static krwlock_t vnet_rw; 1721991Sheppo 1731991Sheppo /* Tunables */ 1741991Sheppo uint32_t vnet_ntxds = VNET_NTXDS; /* power of 2 transmit descriptors */ 1751991Sheppo uint32_t vnet_ldcwd_interval = VNET_LDCWD_INTERVAL; /* watchdog freq in msec */ 1761991Sheppo uint32_t vnet_ldcwd_txtimeout = VNET_LDCWD_TXTIMEOUT; /* tx timeout in msec */ 1772410Slm66018 uint32_t vnet_ldc_mtu = VNET_LDC_MTU; /* ldc mtu */ 1786419Ssb155480 1797529SSriharsha.Basavapatna@Sun.COM /* 1807529SSriharsha.Basavapatna@Sun.COM * Set this to non-zero to enable additional internal receive buffer pools 1817529SSriharsha.Basavapatna@Sun.COM * based on the MTU of the device for better performance at the cost of more 1827529SSriharsha.Basavapatna@Sun.COM * memory consumption. This is turned off by default, to use allocb(9F) for 1837529SSriharsha.Basavapatna@Sun.COM * receive buffer allocations of sizes > 2K. 1847529SSriharsha.Basavapatna@Sun.COM */ 1857529SSriharsha.Basavapatna@Sun.COM boolean_t vnet_jumbo_rxpools = B_FALSE; 1867529SSriharsha.Basavapatna@Sun.COM 1876419Ssb155480 /* # of chains in fdb hash table */ 1886419Ssb155480 uint32_t vnet_fdb_nchains = VNET_NFDB_HASH; 1896419Ssb155480 1906419Ssb155480 /* Internal tunables */ 1916419Ssb155480 uint32_t vnet_ethermtu = 1500; /* mtu of the device */ 1926419Ssb155480 1936419Ssb155480 /* 1946419Ssb155480 * Default vlan id. This is only used internally when the "default-vlan-id" 1956419Ssb155480 * property is not present in the MD device node. Therefore, this should not be 1966419Ssb155480 * used as a tunable; if this value is changed, the corresponding variable 1976419Ssb155480 * should be updated to the same value in vsw and also other vnets connected to 1986419Ssb155480 * the same vsw. 1996419Ssb155480 */ 2006419Ssb155480 uint16_t vnet_default_vlan_id = 1; 2016419Ssb155480 2026419Ssb155480 /* delay in usec to wait for all references on a fdb entry to be dropped */ 2036419Ssb155480 uint32_t vnet_fdbe_refcnt_delay = 10; 2041991Sheppo 2056495Sspeer static struct ether_addr etherbroadcastaddr = { 2066495Sspeer 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 2076495Sspeer }; 2086495Sspeer 2096495Sspeer 2101991Sheppo /* 2111991Sheppo * Property names 2121991Sheppo */ 2131991Sheppo static char macaddr_propname[] = "local-mac-address"; 2141991Sheppo 2151991Sheppo /* 2161991Sheppo * This is the string displayed by modinfo(1m). 2171991Sheppo */ 2187529SSriharsha.Basavapatna@Sun.COM static char vnet_ident[] = "vnet driver"; 2191991Sheppo extern struct mod_ops mod_driverops; 2201991Sheppo static struct cb_ops cb_vnetops = { 2211991Sheppo nulldev, /* cb_open */ 2221991Sheppo nulldev, /* cb_close */ 2231991Sheppo nodev, /* cb_strategy */ 2241991Sheppo nodev, /* cb_print */ 2251991Sheppo nodev, /* cb_dump */ 2261991Sheppo nodev, /* cb_read */ 2271991Sheppo nodev, /* cb_write */ 2281991Sheppo nodev, /* cb_ioctl */ 2291991Sheppo nodev, /* cb_devmap */ 2301991Sheppo nodev, /* cb_mmap */ 2311991Sheppo nodev, /* cb_segmap */ 2321991Sheppo nochpoll, /* cb_chpoll */ 2331991Sheppo ddi_prop_op, /* cb_prop_op */ 2341991Sheppo NULL, /* cb_stream */ 2351991Sheppo (int)(D_MP) /* cb_flag */ 2361991Sheppo }; 2371991Sheppo 2381991Sheppo static struct dev_ops vnetops = { 2391991Sheppo DEVO_REV, /* devo_rev */ 2401991Sheppo 0, /* devo_refcnt */ 2411991Sheppo NULL, /* devo_getinfo */ 2421991Sheppo nulldev, /* devo_identify */ 2431991Sheppo nulldev, /* devo_probe */ 2441991Sheppo vnetattach, /* devo_attach */ 2451991Sheppo vnetdetach, /* devo_detach */ 2461991Sheppo nodev, /* devo_reset */ 2471991Sheppo &cb_vnetops, /* devo_cb_ops */ 2487656SSherry.Moore@Sun.COM (struct bus_ops *)NULL, /* devo_bus_ops */ 2497656SSherry.Moore@Sun.COM NULL, /* devo_power */ 2507656SSherry.Moore@Sun.COM ddi_quiesce_not_supported, /* devo_quiesce */ 2511991Sheppo }; 2521991Sheppo 2531991Sheppo static struct modldrv modldrv = { 2541991Sheppo &mod_driverops, /* Type of module. This one is a driver */ 2551991Sheppo vnet_ident, /* ID string */ 2561991Sheppo &vnetops /* driver specific ops */ 2571991Sheppo }; 2581991Sheppo 2591991Sheppo static struct modlinkage modlinkage = { 2601991Sheppo MODREV_1, (void *)&modldrv, NULL 2611991Sheppo }; 2621991Sheppo 2634647Sraghuram #ifdef DEBUG 2641991Sheppo 2651991Sheppo /* 2661991Sheppo * Print debug messages - set to 0xf to enable all msgs 2671991Sheppo */ 2684647Sraghuram int vnet_dbglevel = 0x8; 2691991Sheppo 2704647Sraghuram static void 2714647Sraghuram debug_printf(const char *fname, void *arg, const char *fmt, ...) 2721991Sheppo { 2731991Sheppo char buf[512]; 2741991Sheppo va_list ap; 2751991Sheppo vnet_t *vnetp = (vnet_t *)arg; 2764647Sraghuram char *bufp = buf; 2771991Sheppo 2784647Sraghuram if (vnetp == NULL) { 2794647Sraghuram (void) sprintf(bufp, "%s: ", fname); 2804647Sraghuram bufp += strlen(bufp); 2814647Sraghuram } else { 2824647Sraghuram (void) sprintf(bufp, "vnet%d:%s: ", vnetp->instance, fname); 2834647Sraghuram bufp += strlen(bufp); 2844647Sraghuram } 2854647Sraghuram va_start(ap, fmt); 2864647Sraghuram (void) vsprintf(bufp, fmt, ap); 2874647Sraghuram va_end(ap); 2884647Sraghuram cmn_err(CE_CONT, "%s\n", buf); 2894647Sraghuram } 2901991Sheppo 2911991Sheppo #endif 2921991Sheppo 2931991Sheppo /* _init(9E): initialize the loadable module */ 2941991Sheppo int 2951991Sheppo _init(void) 2961991Sheppo { 2971991Sheppo int status; 2981991Sheppo 2994647Sraghuram DBG1(NULL, "enter\n"); 3001991Sheppo 3011991Sheppo mac_init_ops(&vnetops, "vnet"); 3021991Sheppo status = mod_install(&modlinkage); 3031991Sheppo if (status != 0) { 3041991Sheppo mac_fini_ops(&vnetops); 3051991Sheppo } 3066495Sspeer vdds_mod_init(); 3079217SWentao.Yang@Sun.COM vgen_mod_init(); 3084647Sraghuram DBG1(NULL, "exit(%d)\n", status); 3091991Sheppo return (status); 3101991Sheppo } 3111991Sheppo 3121991Sheppo /* _fini(9E): prepare the module for unloading. */ 3131991Sheppo int 3141991Sheppo _fini(void) 3151991Sheppo { 3169217SWentao.Yang@Sun.COM int status; 3171991Sheppo 3184647Sraghuram DBG1(NULL, "enter\n"); 3191991Sheppo 3209217SWentao.Yang@Sun.COM status = vgen_mod_cleanup(); 3219217SWentao.Yang@Sun.COM if (status != 0) 3229217SWentao.Yang@Sun.COM return (status); 3239217SWentao.Yang@Sun.COM 3241991Sheppo status = mod_remove(&modlinkage); 3251991Sheppo if (status != 0) 3261991Sheppo return (status); 3271991Sheppo mac_fini_ops(&vnetops); 3289217SWentao.Yang@Sun.COM vgen_mod_fini(); 3296495Sspeer vdds_mod_fini(); 3301991Sheppo 3314647Sraghuram DBG1(NULL, "exit(%d)\n", status); 3321991Sheppo return (status); 3331991Sheppo } 3341991Sheppo 3351991Sheppo /* _info(9E): return information about the loadable module */ 3361991Sheppo int 3371991Sheppo _info(struct modinfo *modinfop) 3381991Sheppo { 3391991Sheppo return (mod_info(&modlinkage, modinfop)); 3401991Sheppo } 3411991Sheppo 3421991Sheppo /* 3431991Sheppo * attach(9E): attach a device to the system. 3441991Sheppo * called once for each instance of the device on the system. 3451991Sheppo */ 3461991Sheppo static int 3471991Sheppo vnetattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 3481991Sheppo { 3499217SWentao.Yang@Sun.COM vnet_t *vnetp; 3509217SWentao.Yang@Sun.COM int status; 3519217SWentao.Yang@Sun.COM int instance; 3529217SWentao.Yang@Sun.COM uint64_t reg; 3539217SWentao.Yang@Sun.COM char qname[TASKQ_NAMELEN]; 3549217SWentao.Yang@Sun.COM vnet_attach_progress_t attach_progress; 3551991Sheppo 3569217SWentao.Yang@Sun.COM attach_progress = AST_init; 3571991Sheppo 3581991Sheppo switch (cmd) { 3591991Sheppo case DDI_ATTACH: 3601991Sheppo break; 3611991Sheppo case DDI_RESUME: 3621991Sheppo case DDI_PM_RESUME: 3631991Sheppo default: 3641991Sheppo goto vnet_attach_fail; 3651991Sheppo } 3661991Sheppo 3671991Sheppo instance = ddi_get_instance(dip); 3684647Sraghuram DBG1(NULL, "instance(%d) enter\n", instance); 3691991Sheppo 3701991Sheppo /* allocate vnet_t and mac_t structures */ 3711991Sheppo vnetp = kmem_zalloc(sizeof (vnet_t), KM_SLEEP); 3726495Sspeer vnetp->dip = dip; 3736495Sspeer vnetp->instance = instance; 3746495Sspeer rw_init(&vnetp->vrwlock, NULL, RW_DRIVER, NULL); 3756495Sspeer rw_init(&vnetp->vsw_fp_rw, NULL, RW_DRIVER, NULL); 3769217SWentao.Yang@Sun.COM attach_progress |= AST_vnet_alloc; 3771991Sheppo 3786495Sspeer status = vdds_init(vnetp); 3796495Sspeer if (status != 0) { 3806495Sspeer goto vnet_attach_fail; 3816495Sspeer } 3829217SWentao.Yang@Sun.COM attach_progress |= AST_vdds_init; 3836495Sspeer 3841991Sheppo /* setup links to vnet_t from both devinfo and mac_t */ 3851991Sheppo ddi_set_driver_private(dip, (caddr_t)vnetp); 3861991Sheppo 3871991Sheppo /* read the mac address */ 3881991Sheppo status = vnet_read_mac_address(vnetp); 3891991Sheppo if (status != DDI_SUCCESS) { 3901991Sheppo goto vnet_attach_fail; 3911991Sheppo } 3929217SWentao.Yang@Sun.COM attach_progress |= AST_read_macaddr; 3931991Sheppo 3946495Sspeer reg = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 3956495Sspeer DDI_PROP_DONTPASS, "reg", -1); 3966495Sspeer if (reg == -1) { 3976495Sspeer goto vnet_attach_fail; 3986495Sspeer } 3996495Sspeer vnetp->reg = reg; 4006495Sspeer 4016495Sspeer vnet_fdb_create(vnetp); 4029217SWentao.Yang@Sun.COM attach_progress |= AST_fdbh_alloc; 4036495Sspeer 4046495Sspeer (void) snprintf(qname, TASKQ_NAMELEN, "vnet_taskq%d", instance); 4056495Sspeer if ((vnetp->taskqp = ddi_taskq_create(dip, qname, 1, 4066495Sspeer TASKQ_DEFAULTPRI, 0)) == NULL) { 4076495Sspeer cmn_err(CE_WARN, "!vnet%d: Unable to create task queue", 4086495Sspeer instance); 4096495Sspeer goto vnet_attach_fail; 4106495Sspeer } 4119217SWentao.Yang@Sun.COM attach_progress |= AST_taskq_create; 4126495Sspeer 4136495Sspeer /* add to the list of vnet devices */ 4146495Sspeer WRITE_ENTER(&vnet_rw); 4156495Sspeer vnetp->nextp = vnet_headp; 4166495Sspeer vnet_headp = vnetp; 4176495Sspeer RW_EXIT(&vnet_rw); 4186495Sspeer 4199217SWentao.Yang@Sun.COM attach_progress |= AST_vnet_list; 4206495Sspeer 4211991Sheppo /* 4226495Sspeer * Initialize the generic vnet plugin which provides 4236495Sspeer * communication via sun4v LDC (logical domain channel) based 4246495Sspeer * resources. It will register the LDC resources as and when 4256495Sspeer * they become available. 4261991Sheppo */ 4276495Sspeer status = vgen_init(vnetp, reg, vnetp->dip, 4286495Sspeer (uint8_t *)vnetp->curr_macaddr, &vnetp->vgenhdl); 4291991Sheppo if (status != DDI_SUCCESS) { 4304647Sraghuram DERR(vnetp, "vgen_init() failed\n"); 4311991Sheppo goto vnet_attach_fail; 4321991Sheppo } 4339217SWentao.Yang@Sun.COM attach_progress |= AST_vgen_init; 4341991Sheppo 4351991Sheppo /* register with MAC layer */ 4361991Sheppo status = vnet_mac_register(vnetp); 4371991Sheppo if (status != DDI_SUCCESS) { 4381991Sheppo goto vnet_attach_fail; 4391991Sheppo } 4409336SSriharsha.Basavapatna@Sun.COM vnetp->link_state = LINK_STATE_UNKNOWN; 4411991Sheppo 4429217SWentao.Yang@Sun.COM attach_progress |= AST_macreg; 4439217SWentao.Yang@Sun.COM 4449217SWentao.Yang@Sun.COM vnetp->attach_progress = attach_progress; 4459217SWentao.Yang@Sun.COM 4464647Sraghuram DBG1(NULL, "instance(%d) exit\n", instance); 4471991Sheppo return (DDI_SUCCESS); 4481991Sheppo 4491991Sheppo vnet_attach_fail: 4509217SWentao.Yang@Sun.COM vnetp->attach_progress = attach_progress; 4519235SWentao.Yang@Sun.COM status = vnet_unattach(vnetp); 4529235SWentao.Yang@Sun.COM ASSERT(status == 0); 4531991Sheppo return (DDI_FAILURE); 4541991Sheppo } 4551991Sheppo 4561991Sheppo /* 4571991Sheppo * detach(9E): detach a device from the system. 4581991Sheppo */ 4591991Sheppo static int 4601991Sheppo vnetdetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4611991Sheppo { 4621991Sheppo vnet_t *vnetp; 4631991Sheppo int instance; 4641991Sheppo 4651991Sheppo instance = ddi_get_instance(dip); 4664647Sraghuram DBG1(NULL, "instance(%d) enter\n", instance); 4671991Sheppo 4681991Sheppo vnetp = ddi_get_driver_private(dip); 4691991Sheppo if (vnetp == NULL) { 4701991Sheppo goto vnet_detach_fail; 4711991Sheppo } 4721991Sheppo 4731991Sheppo switch (cmd) { 4741991Sheppo case DDI_DETACH: 4751991Sheppo break; 4761991Sheppo case DDI_SUSPEND: 4771991Sheppo case DDI_PM_SUSPEND: 4781991Sheppo default: 4791991Sheppo goto vnet_detach_fail; 4801991Sheppo } 4811991Sheppo 4829217SWentao.Yang@Sun.COM if (vnet_unattach(vnetp) != 0) { 4836495Sspeer goto vnet_detach_fail; 4842336Snarayan } 4852336Snarayan 4861991Sheppo return (DDI_SUCCESS); 4871991Sheppo 4881991Sheppo vnet_detach_fail: 4891991Sheppo return (DDI_FAILURE); 4901991Sheppo } 4911991Sheppo 4929217SWentao.Yang@Sun.COM /* 4939217SWentao.Yang@Sun.COM * Common routine to handle vnetattach() failure and vnetdetach(). Note that 4949217SWentao.Yang@Sun.COM * the only reason this function could fail is if mac_unregister() fails. 4959217SWentao.Yang@Sun.COM * Otherwise, this function must ensure that all resources are freed and return 4969217SWentao.Yang@Sun.COM * success. 4979217SWentao.Yang@Sun.COM */ 4989217SWentao.Yang@Sun.COM static int 4999217SWentao.Yang@Sun.COM vnet_unattach(vnet_t *vnetp) 5009217SWentao.Yang@Sun.COM { 5019217SWentao.Yang@Sun.COM vnet_attach_progress_t attach_progress; 5029217SWentao.Yang@Sun.COM 5039217SWentao.Yang@Sun.COM attach_progress = vnetp->attach_progress; 5049217SWentao.Yang@Sun.COM 5059217SWentao.Yang@Sun.COM /* 5069217SWentao.Yang@Sun.COM * Unregister from the gldv3 subsystem. This can fail, in particular 5079217SWentao.Yang@Sun.COM * if there are still any open references to this mac device; in which 5089217SWentao.Yang@Sun.COM * case we just return failure without continuing to detach further. 5099217SWentao.Yang@Sun.COM */ 5109217SWentao.Yang@Sun.COM if (attach_progress & AST_macreg) { 5119217SWentao.Yang@Sun.COM if (mac_unregister(vnetp->mh) != 0) { 5129217SWentao.Yang@Sun.COM return (1); 5139217SWentao.Yang@Sun.COM } 5149217SWentao.Yang@Sun.COM attach_progress &= ~AST_macreg; 5159217SWentao.Yang@Sun.COM } 5169217SWentao.Yang@Sun.COM 5179217SWentao.Yang@Sun.COM /* 5189217SWentao.Yang@Sun.COM * Now that we have unregistered from gldv3, we must finish all other 5199217SWentao.Yang@Sun.COM * steps and successfully return from this function; otherwise we will 5209217SWentao.Yang@Sun.COM * end up leaving the device in a broken/unusable state. 5219217SWentao.Yang@Sun.COM * 5229217SWentao.Yang@Sun.COM * First, release any hybrid resources assigned to this vnet device. 5239217SWentao.Yang@Sun.COM */ 5249217SWentao.Yang@Sun.COM if (attach_progress & AST_vdds_init) { 5259217SWentao.Yang@Sun.COM vdds_cleanup(vnetp); 5269217SWentao.Yang@Sun.COM attach_progress &= ~AST_vdds_init; 5279217SWentao.Yang@Sun.COM } 5289217SWentao.Yang@Sun.COM 5299217SWentao.Yang@Sun.COM /* 5309217SWentao.Yang@Sun.COM * Uninit vgen. This stops further mdeg callbacks to this vnet 5319217SWentao.Yang@Sun.COM * device and/or its ports; and detaches any existing ports. 5329217SWentao.Yang@Sun.COM */ 5339217SWentao.Yang@Sun.COM if (attach_progress & AST_vgen_init) { 5349217SWentao.Yang@Sun.COM vgen_uninit(vnetp->vgenhdl); 5359217SWentao.Yang@Sun.COM attach_progress &= ~AST_vgen_init; 5369217SWentao.Yang@Sun.COM } 5379217SWentao.Yang@Sun.COM 5389217SWentao.Yang@Sun.COM /* Destroy the taskq. */ 5399217SWentao.Yang@Sun.COM if (attach_progress & AST_taskq_create) { 5409217SWentao.Yang@Sun.COM ddi_taskq_destroy(vnetp->taskqp); 5419217SWentao.Yang@Sun.COM attach_progress &= ~AST_taskq_create; 5429217SWentao.Yang@Sun.COM } 5439217SWentao.Yang@Sun.COM 5449217SWentao.Yang@Sun.COM /* Destroy fdb. */ 5459217SWentao.Yang@Sun.COM if (attach_progress & AST_fdbh_alloc) { 5469217SWentao.Yang@Sun.COM vnet_fdb_destroy(vnetp); 5479217SWentao.Yang@Sun.COM attach_progress &= ~AST_fdbh_alloc; 5489217SWentao.Yang@Sun.COM } 5499217SWentao.Yang@Sun.COM 5509217SWentao.Yang@Sun.COM /* Remove from the device list */ 5519217SWentao.Yang@Sun.COM if (attach_progress & AST_vnet_list) { 5529217SWentao.Yang@Sun.COM vnet_t **vnetpp; 5539217SWentao.Yang@Sun.COM /* unlink from instance(vnet_t) list */ 5549217SWentao.Yang@Sun.COM WRITE_ENTER(&vnet_rw); 5559217SWentao.Yang@Sun.COM for (vnetpp = &vnet_headp; *vnetpp; 5569217SWentao.Yang@Sun.COM vnetpp = &(*vnetpp)->nextp) { 5579217SWentao.Yang@Sun.COM if (*vnetpp == vnetp) { 5589217SWentao.Yang@Sun.COM *vnetpp = vnetp->nextp; 5599217SWentao.Yang@Sun.COM break; 5609217SWentao.Yang@Sun.COM } 5619217SWentao.Yang@Sun.COM } 5629217SWentao.Yang@Sun.COM RW_EXIT(&vnet_rw); 5639217SWentao.Yang@Sun.COM attach_progress &= ~AST_vnet_list; 5649217SWentao.Yang@Sun.COM } 5659217SWentao.Yang@Sun.COM 5669217SWentao.Yang@Sun.COM if (attach_progress & AST_vnet_alloc) { 5679217SWentao.Yang@Sun.COM rw_destroy(&vnetp->vrwlock); 5689217SWentao.Yang@Sun.COM rw_destroy(&vnetp->vsw_fp_rw); 5699217SWentao.Yang@Sun.COM attach_progress &= ~AST_vnet_list; 5709217SWentao.Yang@Sun.COM KMEM_FREE(vnetp); 5719217SWentao.Yang@Sun.COM } 5729217SWentao.Yang@Sun.COM 5739217SWentao.Yang@Sun.COM return (0); 5749217SWentao.Yang@Sun.COM } 5759217SWentao.Yang@Sun.COM 5761991Sheppo /* enable the device for transmit/receive */ 5771991Sheppo static int 5781991Sheppo vnet_m_start(void *arg) 5791991Sheppo { 5801991Sheppo vnet_t *vnetp = arg; 5811991Sheppo 5824647Sraghuram DBG1(vnetp, "enter\n"); 5831991Sheppo 5846495Sspeer WRITE_ENTER(&vnetp->vrwlock); 5856495Sspeer vnetp->flags |= VNET_STARTED; 5866495Sspeer vnet_start_resources(vnetp); 5876495Sspeer RW_EXIT(&vnetp->vrwlock); 5881991Sheppo 5894647Sraghuram DBG1(vnetp, "exit\n"); 5901991Sheppo return (VNET_SUCCESS); 5911991Sheppo 5921991Sheppo } 5931991Sheppo 5941991Sheppo /* stop transmit/receive for the device */ 5951991Sheppo static void 5961991Sheppo vnet_m_stop(void *arg) 5971991Sheppo { 5981991Sheppo vnet_t *vnetp = arg; 5991991Sheppo 6004647Sraghuram DBG1(vnetp, "enter\n"); 6011991Sheppo 6026495Sspeer WRITE_ENTER(&vnetp->vrwlock); 6036495Sspeer if (vnetp->flags & VNET_STARTED) { 604*9805SSriharsha.Basavapatna@Sun.COM /* 605*9805SSriharsha.Basavapatna@Sun.COM * Set the flags appropriately; this should prevent starting of 606*9805SSriharsha.Basavapatna@Sun.COM * any new resources that are added(see vnet_res_start_task()), 607*9805SSriharsha.Basavapatna@Sun.COM * while we release the vrwlock in vnet_stop_resources() before 608*9805SSriharsha.Basavapatna@Sun.COM * stopping each resource. 609*9805SSriharsha.Basavapatna@Sun.COM */ 610*9805SSriharsha.Basavapatna@Sun.COM vnetp->flags &= ~VNET_STARTED; 611*9805SSriharsha.Basavapatna@Sun.COM vnetp->flags |= VNET_STOPPING; 6126495Sspeer vnet_stop_resources(vnetp); 613*9805SSriharsha.Basavapatna@Sun.COM vnetp->flags &= ~VNET_STOPPING; 6141991Sheppo } 6156495Sspeer RW_EXIT(&vnetp->vrwlock); 6161991Sheppo 6174647Sraghuram DBG1(vnetp, "exit\n"); 6181991Sheppo } 6191991Sheppo 6201991Sheppo /* set the unicast mac address of the device */ 6211991Sheppo static int 6221991Sheppo vnet_m_unicst(void *arg, const uint8_t *macaddr) 6231991Sheppo { 6241991Sheppo _NOTE(ARGUNUSED(macaddr)) 6251991Sheppo 6261991Sheppo vnet_t *vnetp = arg; 6271991Sheppo 6284647Sraghuram DBG1(vnetp, "enter\n"); 6291991Sheppo /* 6302793Slm66018 * NOTE: setting mac address dynamically is not supported. 6311991Sheppo */ 6324647Sraghuram DBG1(vnetp, "exit\n"); 6331991Sheppo 6342109Slm66018 return (VNET_FAILURE); 6351991Sheppo } 6361991Sheppo 6371991Sheppo /* enable/disable a multicast address */ 6381991Sheppo static int 6391991Sheppo vnet_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 6401991Sheppo { 6411991Sheppo _NOTE(ARGUNUSED(add, mca)) 6421991Sheppo 6431991Sheppo vnet_t *vnetp = arg; 6446495Sspeer vnet_res_t *vresp; 6456495Sspeer mac_register_t *macp; 6462311Sseb mac_callbacks_t *cbp; 6471991Sheppo int rv = VNET_SUCCESS; 6481991Sheppo 6494647Sraghuram DBG1(vnetp, "enter\n"); 6506495Sspeer 6516495Sspeer READ_ENTER(&vnetp->vrwlock); 6526495Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) { 6536495Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) { 6546495Sspeer macp = &vresp->macreg; 6556495Sspeer cbp = macp->m_callbacks; 6566495Sspeer rv = cbp->mc_multicst(macp->m_driver, add, mca); 6571991Sheppo } 6581991Sheppo } 6596495Sspeer RW_EXIT(&vnetp->vrwlock); 6606495Sspeer 6614647Sraghuram DBG1(vnetp, "exit(%d)\n", rv); 6621991Sheppo return (rv); 6631991Sheppo } 6641991Sheppo 6651991Sheppo /* set or clear promiscuous mode on the device */ 6661991Sheppo static int 6671991Sheppo vnet_m_promisc(void *arg, boolean_t on) 6681991Sheppo { 6691991Sheppo _NOTE(ARGUNUSED(on)) 6701991Sheppo 6711991Sheppo vnet_t *vnetp = arg; 6724647Sraghuram DBG1(vnetp, "enter\n"); 6731991Sheppo /* 6742793Slm66018 * NOTE: setting promiscuous mode is not supported, just return success. 6751991Sheppo */ 6764647Sraghuram DBG1(vnetp, "exit\n"); 6771991Sheppo return (VNET_SUCCESS); 6781991Sheppo } 6791991Sheppo 6801991Sheppo /* 6811991Sheppo * Transmit a chain of packets. This function provides switching functionality 6821991Sheppo * based on the destination mac address to reach other guests (within ldoms) or 6831991Sheppo * external hosts. 6841991Sheppo */ 6851991Sheppo mblk_t * 6861991Sheppo vnet_m_tx(void *arg, mblk_t *mp) 6871991Sheppo { 6886419Ssb155480 vnet_t *vnetp; 6896495Sspeer vnet_res_t *vresp; 6906419Ssb155480 mblk_t *next; 6916495Sspeer mblk_t *resid_mp; 6926495Sspeer mac_register_t *macp; 6936495Sspeer struct ether_header *ehp; 6946495Sspeer boolean_t is_unicast; 6957896SSriharsha.Basavapatna@Sun.COM boolean_t is_pvid; /* non-default pvid ? */ 6967896SSriharsha.Basavapatna@Sun.COM boolean_t hres; /* Hybrid resource ? */ 6971991Sheppo 6981991Sheppo vnetp = (vnet_t *)arg; 6994647Sraghuram DBG1(vnetp, "enter\n"); 7001991Sheppo ASSERT(mp != NULL); 7011991Sheppo 7027896SSriharsha.Basavapatna@Sun.COM is_pvid = (vnetp->pvid != vnetp->default_vlan_id) ? B_TRUE : B_FALSE; 7037896SSriharsha.Basavapatna@Sun.COM 7041991Sheppo while (mp != NULL) { 7056419Ssb155480 7061991Sheppo next = mp->b_next; 7071991Sheppo mp->b_next = NULL; 7081991Sheppo 7096419Ssb155480 /* 7106419Ssb155480 * Find fdb entry for the destination 7116419Ssb155480 * and hold a reference to it. 7126419Ssb155480 */ 7131991Sheppo ehp = (struct ether_header *)mp->b_rptr; 7146495Sspeer vresp = vnet_fdbe_find(vnetp, &ehp->ether_dhost); 7156495Sspeer if (vresp != NULL) { 7161991Sheppo 7171991Sheppo /* 7186419Ssb155480 * Destination found in FDB. 7196419Ssb155480 * The destination is a vnet device within ldoms 7206419Ssb155480 * and directly reachable, invoke the tx function 7216419Ssb155480 * in the fdb entry. 7221991Sheppo */ 7236495Sspeer macp = &vresp->macreg; 7246495Sspeer resid_mp = macp->m_callbacks->mc_tx(macp->m_driver, mp); 7256419Ssb155480 7266419Ssb155480 /* tx done; now release ref on fdb entry */ 7276495Sspeer VNET_FDBE_REFRELE(vresp); 7286419Ssb155480 7291991Sheppo if (resid_mp != NULL) { 7301991Sheppo /* m_tx failed */ 7311991Sheppo mp->b_next = next; 7321991Sheppo break; 7331991Sheppo } 7341991Sheppo } else { 7356495Sspeer is_unicast = !(IS_BROADCAST(ehp) || 7366495Sspeer (IS_MULTICAST(ehp))); 7371991Sheppo /* 7386419Ssb155480 * Destination is not in FDB. 7396495Sspeer * If the destination is broadcast or multicast, 7406495Sspeer * then forward the packet to vswitch. 7416495Sspeer * If a Hybrid resource avilable, then send the 7426495Sspeer * unicast packet via hybrid resource, otherwise 7436495Sspeer * forward it to vswitch. 7441991Sheppo */ 7456419Ssb155480 READ_ENTER(&vnetp->vsw_fp_rw); 7466419Ssb155480 7476495Sspeer if ((is_unicast) && (vnetp->hio_fp != NULL)) { 7486495Sspeer vresp = vnetp->hio_fp; 7497896SSriharsha.Basavapatna@Sun.COM hres = B_TRUE; 7506495Sspeer } else { 7516495Sspeer vresp = vnetp->vsw_fp; 7527896SSriharsha.Basavapatna@Sun.COM hres = B_FALSE; 7536495Sspeer } 7546495Sspeer if (vresp == NULL) { 7556419Ssb155480 /* 7566419Ssb155480 * no fdb entry to vsw? drop the packet. 7576419Ssb155480 */ 7586419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 7591991Sheppo freemsg(mp); 7606419Ssb155480 mp = next; 7616419Ssb155480 continue; 7621991Sheppo } 7636419Ssb155480 7646419Ssb155480 /* ref hold the fdb entry to vsw */ 7656495Sspeer VNET_FDBE_REFHOLD(vresp); 7666419Ssb155480 7676419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 7686419Ssb155480 7697896SSriharsha.Basavapatna@Sun.COM /* 7707896SSriharsha.Basavapatna@Sun.COM * In the case of a hybrid resource we need to insert 7717896SSriharsha.Basavapatna@Sun.COM * the tag for the pvid case here; unlike packets that 7727896SSriharsha.Basavapatna@Sun.COM * are destined to a vnet/vsw in which case the vgen 7737896SSriharsha.Basavapatna@Sun.COM * layer does the tagging before sending it over ldc. 7747896SSriharsha.Basavapatna@Sun.COM */ 7757896SSriharsha.Basavapatna@Sun.COM if (hres == B_TRUE) { 7767896SSriharsha.Basavapatna@Sun.COM /* 7777896SSriharsha.Basavapatna@Sun.COM * Determine if the frame being transmitted 7787896SSriharsha.Basavapatna@Sun.COM * over the hybrid resource is untagged. If so, 7797896SSriharsha.Basavapatna@Sun.COM * insert the tag before transmitting. 7807896SSriharsha.Basavapatna@Sun.COM */ 7817896SSriharsha.Basavapatna@Sun.COM if (is_pvid == B_TRUE && 7827896SSriharsha.Basavapatna@Sun.COM ehp->ether_type != htons(ETHERTYPE_VLAN)) { 7837896SSriharsha.Basavapatna@Sun.COM 7847896SSriharsha.Basavapatna@Sun.COM mp = vnet_vlan_insert_tag(mp, 7857896SSriharsha.Basavapatna@Sun.COM vnetp->pvid); 7867896SSriharsha.Basavapatna@Sun.COM if (mp == NULL) { 7877896SSriharsha.Basavapatna@Sun.COM VNET_FDBE_REFRELE(vresp); 7887896SSriharsha.Basavapatna@Sun.COM mp = next; 7897896SSriharsha.Basavapatna@Sun.COM continue; 7907896SSriharsha.Basavapatna@Sun.COM } 7917896SSriharsha.Basavapatna@Sun.COM 7927896SSriharsha.Basavapatna@Sun.COM } 7937896SSriharsha.Basavapatna@Sun.COM } 7947896SSriharsha.Basavapatna@Sun.COM 7956495Sspeer macp = &vresp->macreg; 7966495Sspeer resid_mp = macp->m_callbacks->mc_tx(macp->m_driver, mp); 7976419Ssb155480 7986419Ssb155480 /* tx done; now release ref on fdb entry */ 7996495Sspeer VNET_FDBE_REFRELE(vresp); 8006419Ssb155480 8016419Ssb155480 if (resid_mp != NULL) { 8026419Ssb155480 /* m_tx failed */ 8036419Ssb155480 mp->b_next = next; 8046419Ssb155480 break; 8056419Ssb155480 } 8061991Sheppo } 8071991Sheppo 8081991Sheppo mp = next; 8091991Sheppo } 8101991Sheppo 8114647Sraghuram DBG1(vnetp, "exit\n"); 8121991Sheppo return (mp); 8131991Sheppo } 8141991Sheppo 8152311Sseb /* get statistics from the device */ 8162311Sseb int 8172311Sseb vnet_m_stat(void *arg, uint_t stat, uint64_t *val) 8181991Sheppo { 8191991Sheppo vnet_t *vnetp = arg; 8206495Sspeer vnet_res_t *vresp; 8216495Sspeer mac_register_t *macp; 8222311Sseb mac_callbacks_t *cbp; 8232311Sseb uint64_t val_total = 0; 8241991Sheppo 8254647Sraghuram DBG1(vnetp, "enter\n"); 8261991Sheppo 8271991Sheppo /* 8282311Sseb * get the specified statistic from each transport and return the 8292311Sseb * aggregate val. This obviously only works for counters. 8301991Sheppo */ 8312311Sseb if ((IS_MAC_STAT(stat) && !MAC_STAT_ISACOUNTER(stat)) || 8322311Sseb (IS_MACTYPE_STAT(stat) && !ETHER_STAT_ISACOUNTER(stat))) { 8332311Sseb return (ENOTSUP); 8342311Sseb } 8356495Sspeer 8366495Sspeer READ_ENTER(&vnetp->vrwlock); 8376495Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) { 8386495Sspeer macp = &vresp->macreg; 8396495Sspeer cbp = macp->m_callbacks; 8406495Sspeer if (cbp->mc_getstat(macp->m_driver, stat, val) == 0) 8412311Sseb val_total += *val; 8421991Sheppo } 8436495Sspeer RW_EXIT(&vnetp->vrwlock); 8441991Sheppo 8452311Sseb *val = val_total; 8462311Sseb 8474647Sraghuram DBG1(vnetp, "exit\n"); 8482311Sseb return (0); 8491991Sheppo } 8501991Sheppo 8511991Sheppo /* wrapper function for mac_register() */ 8521991Sheppo static int 8531991Sheppo vnet_mac_register(vnet_t *vnetp) 8541991Sheppo { 8552311Sseb mac_register_t *macp; 8562311Sseb int err; 8571991Sheppo 8582311Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 8592311Sseb return (DDI_FAILURE); 8602311Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 8612311Sseb macp->m_driver = vnetp; 8621991Sheppo macp->m_dip = vnetp->dip; 8632311Sseb macp->m_src_addr = vnetp->curr_macaddr; 8642311Sseb macp->m_callbacks = &vnet_m_callbacks; 8652311Sseb macp->m_min_sdu = 0; 8667529SSriharsha.Basavapatna@Sun.COM macp->m_max_sdu = vnetp->mtu; 8676419Ssb155480 macp->m_margin = VLAN_TAGSZ; 8681991Sheppo 8691991Sheppo /* 8701991Sheppo * Finally, we're ready to register ourselves with the MAC layer 8711991Sheppo * interface; if this succeeds, we're all ready to start() 8721991Sheppo */ 8732311Sseb err = mac_register(macp, &vnetp->mh); 8742311Sseb mac_free(macp); 8752311Sseb return (err == 0 ? DDI_SUCCESS : DDI_FAILURE); 8761991Sheppo } 8771991Sheppo 8781991Sheppo /* read the mac address of the device */ 8791991Sheppo static int 8801991Sheppo vnet_read_mac_address(vnet_t *vnetp) 8811991Sheppo { 8821991Sheppo uchar_t *macaddr; 8831991Sheppo uint32_t size; 8841991Sheppo int rv; 8851991Sheppo 8861991Sheppo rv = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, vnetp->dip, 8874650Sraghuram DDI_PROP_DONTPASS, macaddr_propname, &macaddr, &size); 8881991Sheppo if ((rv != DDI_PROP_SUCCESS) || (size != ETHERADDRL)) { 8894647Sraghuram DWARN(vnetp, "prop_lookup failed(%s) err(%d)\n", 8904647Sraghuram macaddr_propname, rv); 8911991Sheppo return (DDI_FAILURE); 8921991Sheppo } 8931991Sheppo bcopy(macaddr, (caddr_t)vnetp->vendor_addr, ETHERADDRL); 8941991Sheppo bcopy(macaddr, (caddr_t)vnetp->curr_macaddr, ETHERADDRL); 8951991Sheppo ddi_prop_free(macaddr); 8961991Sheppo 8971991Sheppo return (DDI_SUCCESS); 8981991Sheppo } 8991991Sheppo 9006419Ssb155480 static void 9016419Ssb155480 vnet_fdb_create(vnet_t *vnetp) 9021991Sheppo { 9036419Ssb155480 char hashname[MAXNAMELEN]; 9041991Sheppo 9056419Ssb155480 (void) snprintf(hashname, MAXNAMELEN, "vnet%d-fdbhash", 9066419Ssb155480 vnetp->instance); 9076419Ssb155480 vnetp->fdb_nchains = vnet_fdb_nchains; 9086419Ssb155480 vnetp->fdb_hashp = mod_hash_create_ptrhash(hashname, vnetp->fdb_nchains, 9096419Ssb155480 mod_hash_null_valdtor, sizeof (void *)); 9106419Ssb155480 } 9111991Sheppo 9126419Ssb155480 static void 9136419Ssb155480 vnet_fdb_destroy(vnet_t *vnetp) 9146419Ssb155480 { 9156419Ssb155480 /* destroy fdb-hash-table */ 9166419Ssb155480 if (vnetp->fdb_hashp != NULL) { 9176419Ssb155480 mod_hash_destroy_hash(vnetp->fdb_hashp); 9186419Ssb155480 vnetp->fdb_hashp = NULL; 9196419Ssb155480 vnetp->fdb_nchains = 0; 9201991Sheppo } 9211991Sheppo } 9221991Sheppo 9236419Ssb155480 /* 9246419Ssb155480 * Add an entry into the fdb. 9256419Ssb155480 */ 9261991Sheppo void 9276495Sspeer vnet_fdbe_add(vnet_t *vnetp, vnet_res_t *vresp) 9281991Sheppo { 9296419Ssb155480 uint64_t addr = 0; 9306419Ssb155480 int rv; 9316419Ssb155480 9326495Sspeer KEY_HASH(addr, vresp->rem_macaddr); 9331991Sheppo 9346419Ssb155480 /* 9356495Sspeer * If the entry being added corresponds to LDC_SERVICE resource, 9366495Sspeer * that is, vswitch connection, it is added to the hash and also 9376495Sspeer * the entry is cached, an additional reference count reflects 9386495Sspeer * this. The HYBRID resource is not added to the hash, but only 9396495Sspeer * cached, as it is only used for sending out packets for unknown 9406495Sspeer * unicast destinations. 9416419Ssb155480 */ 9426495Sspeer (vresp->type == VIO_NET_RES_LDC_SERVICE) ? 9436495Sspeer (vresp->refcnt = 1) : (vresp->refcnt = 0); 9441991Sheppo 9456419Ssb155480 /* 9466419Ssb155480 * Note: duplicate keys will be rejected by mod_hash. 9476419Ssb155480 */ 9486495Sspeer if (vresp->type != VIO_NET_RES_HYBRID) { 9496495Sspeer rv = mod_hash_insert(vnetp->fdb_hashp, (mod_hash_key_t)addr, 9506495Sspeer (mod_hash_val_t)vresp); 9516495Sspeer if (rv != 0) { 9526495Sspeer DWARN(vnetp, "Duplicate macaddr key(%lx)\n", addr); 9536495Sspeer return; 9546495Sspeer } 9551991Sheppo } 9561991Sheppo 9576495Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) { 9586419Ssb155480 /* Cache the fdb entry to vsw-port */ 9596419Ssb155480 WRITE_ENTER(&vnetp->vsw_fp_rw); 9606419Ssb155480 if (vnetp->vsw_fp == NULL) 9616495Sspeer vnetp->vsw_fp = vresp; 9626495Sspeer RW_EXIT(&vnetp->vsw_fp_rw); 9636495Sspeer } else if (vresp->type == VIO_NET_RES_HYBRID) { 9646495Sspeer /* Cache the fdb entry to hybrid resource */ 9656495Sspeer WRITE_ENTER(&vnetp->vsw_fp_rw); 9666495Sspeer if (vnetp->hio_fp == NULL) 9676495Sspeer vnetp->hio_fp = vresp; 9686419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 9692793Slm66018 } 9701991Sheppo } 9711991Sheppo 9726419Ssb155480 /* 9736419Ssb155480 * Remove an entry from fdb. 9746419Ssb155480 */ 9756495Sspeer static void 9766495Sspeer vnet_fdbe_del(vnet_t *vnetp, vnet_res_t *vresp) 9775641Swentaoy { 9786419Ssb155480 uint64_t addr = 0; 9796419Ssb155480 int rv; 9806419Ssb155480 uint32_t refcnt; 9816495Sspeer vnet_res_t *tmp; 9825641Swentaoy 9836495Sspeer KEY_HASH(addr, vresp->rem_macaddr); 9845641Swentaoy 9856419Ssb155480 /* 9866419Ssb155480 * Remove the entry from fdb hash table. 9876419Ssb155480 * This prevents further references to this fdb entry. 9886419Ssb155480 */ 9896495Sspeer if (vresp->type != VIO_NET_RES_HYBRID) { 9906495Sspeer rv = mod_hash_remove(vnetp->fdb_hashp, (mod_hash_key_t)addr, 9916495Sspeer (mod_hash_val_t *)&tmp); 9926495Sspeer if (rv != 0) { 9936495Sspeer /* 9946495Sspeer * As the resources are added to the hash only 9956495Sspeer * after they are started, this can occur if 9966495Sspeer * a resource unregisters before it is ever started. 9976495Sspeer */ 9986495Sspeer return; 9996495Sspeer } 10006495Sspeer } 10015641Swentaoy 10026495Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) { 10036419Ssb155480 WRITE_ENTER(&vnetp->vsw_fp_rw); 10045641Swentaoy 10056495Sspeer ASSERT(tmp == vnetp->vsw_fp); 10066419Ssb155480 vnetp->vsw_fp = NULL; 10076419Ssb155480 10086419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 10096495Sspeer } else if (vresp->type == VIO_NET_RES_HYBRID) { 10106495Sspeer WRITE_ENTER(&vnetp->vsw_fp_rw); 10116495Sspeer 10126495Sspeer vnetp->hio_fp = NULL; 10136495Sspeer 10146495Sspeer RW_EXIT(&vnetp->vsw_fp_rw); 10155641Swentaoy } 10165641Swentaoy 10175641Swentaoy /* 10186419Ssb155480 * If there are threads already ref holding before the entry was 10196419Ssb155480 * removed from hash table, then wait for ref count to drop to zero. 10205641Swentaoy */ 10216495Sspeer (vresp->type == VIO_NET_RES_LDC_SERVICE) ? 10226495Sspeer (refcnt = 1) : (refcnt = 0); 10236495Sspeer while (vresp->refcnt > refcnt) { 10246419Ssb155480 delay(drv_usectohz(vnet_fdbe_refcnt_delay)); 10256419Ssb155480 } 10261991Sheppo } 10271991Sheppo 10286419Ssb155480 /* 10296419Ssb155480 * Search fdb for a given mac address. If an entry is found, hold 10306419Ssb155480 * a reference to it and return the entry; else returns NULL. 10316419Ssb155480 */ 10326495Sspeer static vnet_res_t * 10336419Ssb155480 vnet_fdbe_find(vnet_t *vnetp, struct ether_addr *addrp) 10341991Sheppo { 10356419Ssb155480 uint64_t key = 0; 10366495Sspeer vnet_res_t *vresp; 10376419Ssb155480 int rv; 10386419Ssb155480 10396495Sspeer KEY_HASH(key, addrp->ether_addr_octet); 10406419Ssb155480 10416419Ssb155480 rv = mod_hash_find_cb(vnetp->fdb_hashp, (mod_hash_key_t)key, 10426495Sspeer (mod_hash_val_t *)&vresp, vnet_fdbe_find_cb); 10431991Sheppo 10446419Ssb155480 if (rv != 0) 10456419Ssb155480 return (NULL); 10461991Sheppo 10476495Sspeer return (vresp); 10486419Ssb155480 } 10491991Sheppo 10506419Ssb155480 /* 10516419Ssb155480 * Callback function provided to mod_hash_find_cb(). After finding the fdb 10526419Ssb155480 * entry corresponding to the key (macaddr), this callback will be invoked by 10536419Ssb155480 * mod_hash_find_cb() to atomically increment the reference count on the fdb 10546419Ssb155480 * entry before returning the found entry. 10556419Ssb155480 */ 10566419Ssb155480 static void 10576419Ssb155480 vnet_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val) 10586419Ssb155480 { 10596419Ssb155480 _NOTE(ARGUNUSED(key)) 10606495Sspeer VNET_FDBE_REFHOLD((vnet_res_t *)val); 10616495Sspeer } 10626495Sspeer 10637896SSriharsha.Basavapatna@Sun.COM /* 10647896SSriharsha.Basavapatna@Sun.COM * Frames received that are tagged with the pvid of the vnet device must be 10657896SSriharsha.Basavapatna@Sun.COM * untagged before sending up the stack. This function walks the chain of rx 10667896SSriharsha.Basavapatna@Sun.COM * frames, untags any such frames and returns the updated chain. 10677896SSriharsha.Basavapatna@Sun.COM * 10687896SSriharsha.Basavapatna@Sun.COM * Arguments: 10697896SSriharsha.Basavapatna@Sun.COM * pvid: pvid of the vnet device for which packets are being received 10707896SSriharsha.Basavapatna@Sun.COM * mp: head of pkt chain to be validated and untagged 10717896SSriharsha.Basavapatna@Sun.COM * 10727896SSriharsha.Basavapatna@Sun.COM * Returns: 10737896SSriharsha.Basavapatna@Sun.COM * mp: head of updated chain of packets 10747896SSriharsha.Basavapatna@Sun.COM */ 10757896SSriharsha.Basavapatna@Sun.COM static void 10767896SSriharsha.Basavapatna@Sun.COM vnet_rx_frames_untag(uint16_t pvid, mblk_t **mp) 10777896SSriharsha.Basavapatna@Sun.COM { 10787896SSriharsha.Basavapatna@Sun.COM struct ether_vlan_header *evhp; 10797896SSriharsha.Basavapatna@Sun.COM mblk_t *bp; 10807896SSriharsha.Basavapatna@Sun.COM mblk_t *bpt; 10817896SSriharsha.Basavapatna@Sun.COM mblk_t *bph; 10827896SSriharsha.Basavapatna@Sun.COM mblk_t *bpn; 10837896SSriharsha.Basavapatna@Sun.COM 10847896SSriharsha.Basavapatna@Sun.COM bpn = bph = bpt = NULL; 10857896SSriharsha.Basavapatna@Sun.COM 10867896SSriharsha.Basavapatna@Sun.COM for (bp = *mp; bp != NULL; bp = bpn) { 10877896SSriharsha.Basavapatna@Sun.COM 10887896SSriharsha.Basavapatna@Sun.COM bpn = bp->b_next; 10897896SSriharsha.Basavapatna@Sun.COM bp->b_next = bp->b_prev = NULL; 10907896SSriharsha.Basavapatna@Sun.COM 10917896SSriharsha.Basavapatna@Sun.COM evhp = (struct ether_vlan_header *)bp->b_rptr; 10927896SSriharsha.Basavapatna@Sun.COM 10937896SSriharsha.Basavapatna@Sun.COM if (ntohs(evhp->ether_tpid) == ETHERTYPE_VLAN && 10947896SSriharsha.Basavapatna@Sun.COM VLAN_ID(ntohs(evhp->ether_tci)) == pvid) { 10957896SSriharsha.Basavapatna@Sun.COM 10967896SSriharsha.Basavapatna@Sun.COM bp = vnet_vlan_remove_tag(bp); 10977896SSriharsha.Basavapatna@Sun.COM if (bp == NULL) { 10987896SSriharsha.Basavapatna@Sun.COM continue; 10997896SSriharsha.Basavapatna@Sun.COM } 11007896SSriharsha.Basavapatna@Sun.COM 11017896SSriharsha.Basavapatna@Sun.COM } 11027896SSriharsha.Basavapatna@Sun.COM 11037896SSriharsha.Basavapatna@Sun.COM /* build a chain of processed packets */ 11047896SSriharsha.Basavapatna@Sun.COM if (bph == NULL) { 11057896SSriharsha.Basavapatna@Sun.COM bph = bpt = bp; 11067896SSriharsha.Basavapatna@Sun.COM } else { 11077896SSriharsha.Basavapatna@Sun.COM bpt->b_next = bp; 11087896SSriharsha.Basavapatna@Sun.COM bpt = bp; 11097896SSriharsha.Basavapatna@Sun.COM } 11107896SSriharsha.Basavapatna@Sun.COM 11117896SSriharsha.Basavapatna@Sun.COM } 11127896SSriharsha.Basavapatna@Sun.COM 11137896SSriharsha.Basavapatna@Sun.COM *mp = bph; 11147896SSriharsha.Basavapatna@Sun.COM } 11157896SSriharsha.Basavapatna@Sun.COM 11166495Sspeer static void 11176495Sspeer vnet_rx(vio_net_handle_t vrh, mblk_t *mp) 11186495Sspeer { 11197896SSriharsha.Basavapatna@Sun.COM vnet_res_t *vresp = (vnet_res_t *)vrh; 11207896SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp = vresp->vnetp; 11217896SSriharsha.Basavapatna@Sun.COM 11227896SSriharsha.Basavapatna@Sun.COM if ((vnetp == NULL) || (vnetp->mh == 0)) { 11237896SSriharsha.Basavapatna@Sun.COM freemsgchain(mp); 11247896SSriharsha.Basavapatna@Sun.COM return; 11257896SSriharsha.Basavapatna@Sun.COM } 11266495Sspeer 11277896SSriharsha.Basavapatna@Sun.COM /* 11287896SSriharsha.Basavapatna@Sun.COM * Packets received over a hybrid resource need additional processing 11297896SSriharsha.Basavapatna@Sun.COM * to remove the tag, for the pvid case. The underlying resource is 11307896SSriharsha.Basavapatna@Sun.COM * not aware of the vnet's pvid and thus packets are received with the 11317896SSriharsha.Basavapatna@Sun.COM * vlan tag in the header; unlike packets that are received over a ldc 11327896SSriharsha.Basavapatna@Sun.COM * channel in which case the peer vnet/vsw would have already removed 11337896SSriharsha.Basavapatna@Sun.COM * the tag. 11347896SSriharsha.Basavapatna@Sun.COM */ 11357896SSriharsha.Basavapatna@Sun.COM if (vresp->type == VIO_NET_RES_HYBRID && 11367896SSriharsha.Basavapatna@Sun.COM vnetp->pvid != vnetp->default_vlan_id) { 11377896SSriharsha.Basavapatna@Sun.COM 11387896SSriharsha.Basavapatna@Sun.COM vnet_rx_frames_untag(vnetp->pvid, &mp); 11397896SSriharsha.Basavapatna@Sun.COM if (mp == NULL) { 11407896SSriharsha.Basavapatna@Sun.COM return; 11417896SSriharsha.Basavapatna@Sun.COM } 11426495Sspeer } 11437896SSriharsha.Basavapatna@Sun.COM 11447896SSriharsha.Basavapatna@Sun.COM mac_rx(vnetp->mh, NULL, mp); 11451991Sheppo } 11462311Sseb 11472311Sseb void 11486495Sspeer vnet_tx_update(vio_net_handle_t vrh) 11496495Sspeer { 11506495Sspeer vnet_res_t *vresp = (vnet_res_t *)vrh; 11516495Sspeer vnet_t *vnetp = vresp->vnetp; 11526495Sspeer 11536495Sspeer if ((vnetp != NULL) && (vnetp->mh != NULL)) { 11546495Sspeer mac_tx_update(vnetp->mh); 11556495Sspeer } 11566495Sspeer } 11576495Sspeer 11586495Sspeer /* 11597529SSriharsha.Basavapatna@Sun.COM * Update the new mtu of vnet into the mac layer. First check if the device has 11607529SSriharsha.Basavapatna@Sun.COM * been plumbed and if so fail the mtu update. Returns 0 on success. 11617529SSriharsha.Basavapatna@Sun.COM */ 11627529SSriharsha.Basavapatna@Sun.COM int 11637529SSriharsha.Basavapatna@Sun.COM vnet_mtu_update(vnet_t *vnetp, uint32_t mtu) 11647529SSriharsha.Basavapatna@Sun.COM { 11657529SSriharsha.Basavapatna@Sun.COM int rv; 11667529SSriharsha.Basavapatna@Sun.COM 11677529SSriharsha.Basavapatna@Sun.COM if (vnetp == NULL || vnetp->mh == NULL) { 11687529SSriharsha.Basavapatna@Sun.COM return (EINVAL); 11697529SSriharsha.Basavapatna@Sun.COM } 11707529SSriharsha.Basavapatna@Sun.COM 11717529SSriharsha.Basavapatna@Sun.COM WRITE_ENTER(&vnetp->vrwlock); 11727529SSriharsha.Basavapatna@Sun.COM 11737529SSriharsha.Basavapatna@Sun.COM if (vnetp->flags & VNET_STARTED) { 11747529SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock); 11757529SSriharsha.Basavapatna@Sun.COM cmn_err(CE_NOTE, "!vnet%d: Unable to process mtu " 11767529SSriharsha.Basavapatna@Sun.COM "update as the device is plumbed\n", 11777529SSriharsha.Basavapatna@Sun.COM vnetp->instance); 11787529SSriharsha.Basavapatna@Sun.COM return (EBUSY); 11797529SSriharsha.Basavapatna@Sun.COM } 11807529SSriharsha.Basavapatna@Sun.COM 11817529SSriharsha.Basavapatna@Sun.COM /* update mtu in the mac layer */ 11827529SSriharsha.Basavapatna@Sun.COM rv = mac_maxsdu_update(vnetp->mh, mtu); 11837529SSriharsha.Basavapatna@Sun.COM if (rv != 0) { 11847529SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock); 11857529SSriharsha.Basavapatna@Sun.COM cmn_err(CE_NOTE, 11867529SSriharsha.Basavapatna@Sun.COM "!vnet%d: Unable to update mtu with mac layer\n", 11877529SSriharsha.Basavapatna@Sun.COM vnetp->instance); 11887529SSriharsha.Basavapatna@Sun.COM return (EIO); 11897529SSriharsha.Basavapatna@Sun.COM } 11907529SSriharsha.Basavapatna@Sun.COM 11917529SSriharsha.Basavapatna@Sun.COM vnetp->mtu = mtu; 11927529SSriharsha.Basavapatna@Sun.COM 11937529SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock); 11947529SSriharsha.Basavapatna@Sun.COM 11957529SSriharsha.Basavapatna@Sun.COM return (0); 11967529SSriharsha.Basavapatna@Sun.COM } 11977529SSriharsha.Basavapatna@Sun.COM 11987529SSriharsha.Basavapatna@Sun.COM /* 11999336SSriharsha.Basavapatna@Sun.COM * Update the link state of vnet to the mac layer. 12009336SSriharsha.Basavapatna@Sun.COM */ 12019336SSriharsha.Basavapatna@Sun.COM void 12029336SSriharsha.Basavapatna@Sun.COM vnet_link_update(vnet_t *vnetp, link_state_t link_state) 12039336SSriharsha.Basavapatna@Sun.COM { 12049336SSriharsha.Basavapatna@Sun.COM if (vnetp == NULL || vnetp->mh == NULL) { 12059336SSriharsha.Basavapatna@Sun.COM return; 12069336SSriharsha.Basavapatna@Sun.COM } 12079336SSriharsha.Basavapatna@Sun.COM 12089336SSriharsha.Basavapatna@Sun.COM WRITE_ENTER(&vnetp->vrwlock); 12099336SSriharsha.Basavapatna@Sun.COM if (vnetp->link_state == link_state) { 12109336SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock); 12119336SSriharsha.Basavapatna@Sun.COM return; 12129336SSriharsha.Basavapatna@Sun.COM } 12139336SSriharsha.Basavapatna@Sun.COM vnetp->link_state = link_state; 12149336SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock); 12159336SSriharsha.Basavapatna@Sun.COM 12169336SSriharsha.Basavapatna@Sun.COM mac_link_update(vnetp->mh, link_state); 12179336SSriharsha.Basavapatna@Sun.COM } 12189336SSriharsha.Basavapatna@Sun.COM 12199336SSriharsha.Basavapatna@Sun.COM /* 12206495Sspeer * vio_net_resource_reg -- An interface called to register a resource 12216495Sspeer * with vnet. 12226495Sspeer * macp -- a GLDv3 mac_register that has all the details of 12236495Sspeer * a resource and its callbacks etc. 12246495Sspeer * type -- resource type. 12256495Sspeer * local_macaddr -- resource's MAC address. This is used to 12266495Sspeer * associate a resource with a corresponding vnet. 12276495Sspeer * remote_macaddr -- remote side MAC address. This is ignored for 12286495Sspeer * the Hybrid resources. 12296495Sspeer * vhp -- A handle returned to the caller. 12306495Sspeer * vcb -- A set of callbacks provided to the callers. 12316495Sspeer */ 12326495Sspeer int vio_net_resource_reg(mac_register_t *macp, vio_net_res_type_t type, 12336495Sspeer ether_addr_t local_macaddr, ether_addr_t rem_macaddr, vio_net_handle_t *vhp, 12346495Sspeer vio_net_callbacks_t *vcb) 12356495Sspeer { 12366495Sspeer vnet_t *vnetp; 12376495Sspeer vnet_res_t *vresp; 12386495Sspeer 12396495Sspeer vresp = kmem_zalloc(sizeof (vnet_res_t), KM_SLEEP); 12406495Sspeer ether_copy(local_macaddr, vresp->local_macaddr); 12416495Sspeer ether_copy(rem_macaddr, vresp->rem_macaddr); 12426495Sspeer vresp->type = type; 12436495Sspeer bcopy(macp, &vresp->macreg, sizeof (mac_register_t)); 12446495Sspeer 12456495Sspeer DBG1(NULL, "Resource Registerig type=0%X\n", type); 12466495Sspeer 12476495Sspeer READ_ENTER(&vnet_rw); 12486495Sspeer vnetp = vnet_headp; 12496495Sspeer while (vnetp != NULL) { 12506495Sspeer if (VNET_MATCH_RES(vresp, vnetp)) { 12518332SWentao.Yang@Sun.COM vresp->vnetp = vnetp; 12528332SWentao.Yang@Sun.COM 12538332SWentao.Yang@Sun.COM /* Setup kstats for hio resource */ 12548332SWentao.Yang@Sun.COM if (vresp->type == VIO_NET_RES_HYBRID) { 12558332SWentao.Yang@Sun.COM vresp->ksp = vnet_hio_setup_kstats(DRV_NAME, 12568332SWentao.Yang@Sun.COM "hio", vresp); 12578332SWentao.Yang@Sun.COM if (vresp->ksp == NULL) { 12588332SWentao.Yang@Sun.COM cmn_err(CE_NOTE, "!vnet%d: Cannot " 12598332SWentao.Yang@Sun.COM "create kstats for hio resource", 12608332SWentao.Yang@Sun.COM vnetp->instance); 12618332SWentao.Yang@Sun.COM } 12628332SWentao.Yang@Sun.COM } 12638332SWentao.Yang@Sun.COM 12646495Sspeer WRITE_ENTER(&vnetp->vrwlock); 12656495Sspeer vresp->nextp = vnetp->vres_list; 12666495Sspeer vnetp->vres_list = vresp; 12676495Sspeer RW_EXIT(&vnetp->vrwlock); 12686495Sspeer break; 12696495Sspeer } 12706495Sspeer vnetp = vnetp->nextp; 12716495Sspeer } 12726495Sspeer RW_EXIT(&vnet_rw); 12736495Sspeer if (vresp->vnetp == NULL) { 12746495Sspeer DWARN(NULL, "No vnet instance"); 12756495Sspeer kmem_free(vresp, sizeof (vnet_res_t)); 12766495Sspeer return (ENXIO); 12776495Sspeer } 12786495Sspeer 12796495Sspeer *vhp = vresp; 12806495Sspeer vcb->vio_net_rx_cb = vnet_rx; 12816495Sspeer vcb->vio_net_tx_update = vnet_tx_update; 12826495Sspeer vcb->vio_net_report_err = vnet_handle_res_err; 12836495Sspeer 12846495Sspeer /* Dispatch a task to start resources */ 12856495Sspeer vnet_dispatch_res_task(vnetp); 12866495Sspeer return (0); 12876495Sspeer } 12886495Sspeer 12896495Sspeer /* 12906495Sspeer * vio_net_resource_unreg -- An interface to unregister a resource. 12916495Sspeer */ 12926495Sspeer void 12936495Sspeer vio_net_resource_unreg(vio_net_handle_t vhp) 12946495Sspeer { 1295*9805SSriharsha.Basavapatna@Sun.COM vnet_res_t *vresp = (vnet_res_t *)vhp; 1296*9805SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp = vresp->vnetp; 1297*9805SSriharsha.Basavapatna@Sun.COM vnet_res_t *vrp; 1298*9805SSriharsha.Basavapatna@Sun.COM kstat_t *ksp = NULL; 12996495Sspeer 13006495Sspeer DBG1(NULL, "Resource Registerig hdl=0x%p", vhp); 13016495Sspeer 13026495Sspeer ASSERT(vnetp != NULL); 1303*9805SSriharsha.Basavapatna@Sun.COM /* 1304*9805SSriharsha.Basavapatna@Sun.COM * Remove the resource from fdb; this ensures 1305*9805SSriharsha.Basavapatna@Sun.COM * there are no references to the resource. 1306*9805SSriharsha.Basavapatna@Sun.COM */ 13076495Sspeer vnet_fdbe_del(vnetp, vresp); 13086495Sspeer 1309*9805SSriharsha.Basavapatna@Sun.COM /* Now remove the resource from the list */ 13106495Sspeer WRITE_ENTER(&vnetp->vrwlock); 13116495Sspeer if (vresp == vnetp->vres_list) { 13126495Sspeer vnetp->vres_list = vresp->nextp; 13136495Sspeer } else { 13146495Sspeer vrp = vnetp->vres_list; 13156495Sspeer while (vrp->nextp != NULL) { 13166495Sspeer if (vrp->nextp == vresp) { 13176495Sspeer vrp->nextp = vresp->nextp; 13186495Sspeer break; 13196495Sspeer } 13206495Sspeer vrp = vrp->nextp; 13216495Sspeer } 13226495Sspeer } 13238160SWentao.Yang@Sun.COM 13248160SWentao.Yang@Sun.COM ksp = vresp->ksp; 13258160SWentao.Yang@Sun.COM vresp->ksp = NULL; 13268160SWentao.Yang@Sun.COM 13276495Sspeer vresp->vnetp = NULL; 13286495Sspeer vresp->nextp = NULL; 13296495Sspeer RW_EXIT(&vnetp->vrwlock); 13308160SWentao.Yang@Sun.COM vnet_hio_destroy_kstats(ksp); 13316495Sspeer KMEM_FREE(vresp); 13326495Sspeer } 13336495Sspeer 13346495Sspeer /* 13356495Sspeer * vnet_dds_rx -- an interface called by vgen to DDS messages. 13366495Sspeer */ 13376495Sspeer void 13386495Sspeer vnet_dds_rx(void *arg, void *dmsg) 13392311Sseb { 13402311Sseb vnet_t *vnetp = arg; 13416495Sspeer vdds_process_dds_msg(vnetp, dmsg); 13422311Sseb } 13432311Sseb 13446495Sspeer /* 13456495Sspeer * vnet_send_dds_msg -- An interface provided to DDS to send 13466495Sspeer * DDS messages. This simply sends meessages via vgen. 13476495Sspeer */ 13486495Sspeer int 13496495Sspeer vnet_send_dds_msg(vnet_t *vnetp, void *dmsg) 13506495Sspeer { 13516495Sspeer int rv; 13526495Sspeer 13536495Sspeer if (vnetp->vgenhdl != NULL) { 13546495Sspeer rv = vgen_dds_tx(vnetp->vgenhdl, dmsg); 13556495Sspeer } 13566495Sspeer return (rv); 13576495Sspeer } 13586495Sspeer 13596495Sspeer /* 13609647SWentao.Yang@Sun.COM * vnet_cleanup_hio -- an interface called by vgen to cleanup hio resources. 13619647SWentao.Yang@Sun.COM */ 13629647SWentao.Yang@Sun.COM void 13639647SWentao.Yang@Sun.COM vnet_dds_cleanup_hio(vnet_t *vnetp) 13649647SWentao.Yang@Sun.COM { 13659647SWentao.Yang@Sun.COM vdds_cleanup_hio(vnetp); 13669647SWentao.Yang@Sun.COM } 13679647SWentao.Yang@Sun.COM 13689647SWentao.Yang@Sun.COM /* 13696495Sspeer * vnet_handle_res_err -- A callback function called by a resource 13706495Sspeer * to report an error. For example, vgen can call to report 13716495Sspeer * an LDC down/reset event. This will trigger cleanup of associated 13726495Sspeer * Hybrid resource. 13736495Sspeer */ 13746495Sspeer /* ARGSUSED */ 13756495Sspeer static void 13766495Sspeer vnet_handle_res_err(vio_net_handle_t vrh, vio_net_err_val_t err) 13776495Sspeer { 13786495Sspeer vnet_res_t *vresp = (vnet_res_t *)vrh; 13796495Sspeer vnet_t *vnetp = vresp->vnetp; 13806495Sspeer 13816495Sspeer if (vnetp == NULL) { 13826495Sspeer return; 13836495Sspeer } 13846495Sspeer if ((vresp->type != VIO_NET_RES_LDC_SERVICE) && 13856495Sspeer (vresp->type != VIO_NET_RES_HYBRID)) { 13866495Sspeer return; 13876495Sspeer } 13889647SWentao.Yang@Sun.COM 13899647SWentao.Yang@Sun.COM vdds_cleanup_hio(vnetp); 13906495Sspeer } 13916495Sspeer 13926495Sspeer /* 13936495Sspeer * vnet_dispatch_res_task -- A function to dispatch tasks start resources. 13946495Sspeer */ 13956495Sspeer static void 13966495Sspeer vnet_dispatch_res_task(vnet_t *vnetp) 13976495Sspeer { 13986495Sspeer int rv; 13996495Sspeer 14009677SZachary.Kissel@Sun.COM /* 14019677SZachary.Kissel@Sun.COM * Dispatch the task. It could be the case that vnetp->flags does 14029677SZachary.Kissel@Sun.COM * not have VNET_STARTED set. This is ok as vnet_rest_start_task() 1403*9805SSriharsha.Basavapatna@Sun.COM * can abort the task when the task is started. See related comments 1404*9805SSriharsha.Basavapatna@Sun.COM * in vnet_m_stop() and vnet_stop_resources(). 14059677SZachary.Kissel@Sun.COM */ 14069677SZachary.Kissel@Sun.COM rv = ddi_taskq_dispatch(vnetp->taskqp, vnet_res_start_task, 14079677SZachary.Kissel@Sun.COM vnetp, DDI_NOSLEEP); 14089677SZachary.Kissel@Sun.COM if (rv != DDI_SUCCESS) { 14099677SZachary.Kissel@Sun.COM cmn_err(CE_WARN, 14109677SZachary.Kissel@Sun.COM "vnet%d:Can't dispatch start resource task", 14119677SZachary.Kissel@Sun.COM vnetp->instance); 14126495Sspeer } 14136495Sspeer } 14146495Sspeer 14156495Sspeer /* 14166495Sspeer * vnet_res_start_task -- A taskq callback function that starts a resource. 14176495Sspeer */ 14186495Sspeer static void 14196495Sspeer vnet_res_start_task(void *arg) 14202311Sseb { 14212311Sseb vnet_t *vnetp = arg; 14226495Sspeer 14236495Sspeer WRITE_ENTER(&vnetp->vrwlock); 14246495Sspeer if (vnetp->flags & VNET_STARTED) { 14256495Sspeer vnet_start_resources(vnetp); 14266495Sspeer } 14276495Sspeer RW_EXIT(&vnetp->vrwlock); 14282311Sseb } 14296495Sspeer 14306495Sspeer /* 14316495Sspeer * vnet_start_resources -- starts all resources associated with 14326495Sspeer * a vnet. 14336495Sspeer */ 14346495Sspeer static void 14356495Sspeer vnet_start_resources(vnet_t *vnetp) 14366495Sspeer { 14376495Sspeer mac_register_t *macp; 14386495Sspeer mac_callbacks_t *cbp; 14396495Sspeer vnet_res_t *vresp; 14406495Sspeer int rv; 14416495Sspeer 14426495Sspeer DBG1(vnetp, "enter\n"); 14436495Sspeer 1444*9805SSriharsha.Basavapatna@Sun.COM ASSERT(RW_WRITE_HELD(&vnetp->vrwlock)); 1445*9805SSriharsha.Basavapatna@Sun.COM 14466495Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) { 14476495Sspeer /* skip if it is already started */ 14486495Sspeer if (vresp->flags & VNET_STARTED) { 14496495Sspeer continue; 14506495Sspeer } 14516495Sspeer macp = &vresp->macreg; 14526495Sspeer cbp = macp->m_callbacks; 14536495Sspeer rv = cbp->mc_start(macp->m_driver); 14546495Sspeer if (rv == 0) { 14556495Sspeer /* 14566495Sspeer * Successfully started the resource, so now 14576495Sspeer * add it to the fdb. 14586495Sspeer */ 14596495Sspeer vresp->flags |= VNET_STARTED; 14606495Sspeer vnet_fdbe_add(vnetp, vresp); 14616495Sspeer } 14626495Sspeer } 14636495Sspeer 14646495Sspeer DBG1(vnetp, "exit\n"); 14656495Sspeer 14666495Sspeer } 14676495Sspeer 14686495Sspeer /* 14696495Sspeer * vnet_stop_resources -- stop all resources associated with a vnet. 14706495Sspeer */ 14716495Sspeer static void 14726495Sspeer vnet_stop_resources(vnet_t *vnetp) 14736495Sspeer { 14746495Sspeer vnet_res_t *vresp; 14756495Sspeer mac_register_t *macp; 14766495Sspeer mac_callbacks_t *cbp; 14776495Sspeer 14786495Sspeer DBG1(vnetp, "enter\n"); 14796495Sspeer 1480*9805SSriharsha.Basavapatna@Sun.COM ASSERT(RW_WRITE_HELD(&vnetp->vrwlock)); 1481*9805SSriharsha.Basavapatna@Sun.COM 14826495Sspeer for (vresp = vnetp->vres_list; vresp != NULL; ) { 14836495Sspeer if (vresp->flags & VNET_STARTED) { 1484*9805SSriharsha.Basavapatna@Sun.COM /* 1485*9805SSriharsha.Basavapatna@Sun.COM * Release the lock while invoking mc_stop() of the 1486*9805SSriharsha.Basavapatna@Sun.COM * underlying resource. We hold a reference to this 1487*9805SSriharsha.Basavapatna@Sun.COM * resource to prevent being removed from the list in 1488*9805SSriharsha.Basavapatna@Sun.COM * vio_net_resource_unreg(). Note that new resources 1489*9805SSriharsha.Basavapatna@Sun.COM * can be added to the head of the list while the lock 1490*9805SSriharsha.Basavapatna@Sun.COM * is released, but they won't be started, as 1491*9805SSriharsha.Basavapatna@Sun.COM * VNET_STARTED flag has been cleared for the vnet 1492*9805SSriharsha.Basavapatna@Sun.COM * device in vnet_m_stop(). Also, while the lock is 1493*9805SSriharsha.Basavapatna@Sun.COM * released a resource could be removed from the list 1494*9805SSriharsha.Basavapatna@Sun.COM * in vio_net_resource_unreg(); but that is ok, as we 1495*9805SSriharsha.Basavapatna@Sun.COM * re-acquire the lock and only then access the forward 1496*9805SSriharsha.Basavapatna@Sun.COM * link (vresp->nextp) to continue with the next 1497*9805SSriharsha.Basavapatna@Sun.COM * resource. 1498*9805SSriharsha.Basavapatna@Sun.COM */ 1499*9805SSriharsha.Basavapatna@Sun.COM vresp->flags &= ~VNET_STARTED; 1500*9805SSriharsha.Basavapatna@Sun.COM vresp->flags |= VNET_STOPPING; 15016495Sspeer macp = &vresp->macreg; 15026495Sspeer cbp = macp->m_callbacks; 1503*9805SSriharsha.Basavapatna@Sun.COM VNET_FDBE_REFHOLD(vresp); 1504*9805SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock); 1505*9805SSriharsha.Basavapatna@Sun.COM 15066495Sspeer cbp->mc_stop(macp->m_driver); 1507*9805SSriharsha.Basavapatna@Sun.COM 1508*9805SSriharsha.Basavapatna@Sun.COM WRITE_ENTER(&vnetp->vrwlock); 1509*9805SSriharsha.Basavapatna@Sun.COM vresp->flags &= ~VNET_STOPPING; 1510*9805SSriharsha.Basavapatna@Sun.COM VNET_FDBE_REFRELE(vresp); 15116495Sspeer } 1512*9805SSriharsha.Basavapatna@Sun.COM vresp = vresp->nextp; 15136495Sspeer } 15146495Sspeer DBG1(vnetp, "exit\n"); 15156495Sspeer } 15168160SWentao.Yang@Sun.COM 15178160SWentao.Yang@Sun.COM /* 15188160SWentao.Yang@Sun.COM * Setup kstats for the HIO statistics. 15198160SWentao.Yang@Sun.COM * NOTE: the synchronization for the statistics is the 15208160SWentao.Yang@Sun.COM * responsibility of the caller. 15218160SWentao.Yang@Sun.COM */ 15228160SWentao.Yang@Sun.COM kstat_t * 15238160SWentao.Yang@Sun.COM vnet_hio_setup_kstats(char *ks_mod, char *ks_name, vnet_res_t *vresp) 15248160SWentao.Yang@Sun.COM { 15258160SWentao.Yang@Sun.COM kstat_t *ksp; 15268160SWentao.Yang@Sun.COM vnet_t *vnetp = vresp->vnetp; 15278160SWentao.Yang@Sun.COM vnet_hio_kstats_t *hiokp; 15288160SWentao.Yang@Sun.COM size_t size; 15298160SWentao.Yang@Sun.COM 15308160SWentao.Yang@Sun.COM ASSERT(vnetp != NULL); 15318160SWentao.Yang@Sun.COM size = sizeof (vnet_hio_kstats_t) / sizeof (kstat_named_t); 15328160SWentao.Yang@Sun.COM ksp = kstat_create(ks_mod, vnetp->instance, ks_name, "net", 15338160SWentao.Yang@Sun.COM KSTAT_TYPE_NAMED, size, 0); 15348160SWentao.Yang@Sun.COM if (ksp == NULL) { 15358160SWentao.Yang@Sun.COM return (NULL); 15368160SWentao.Yang@Sun.COM } 15378160SWentao.Yang@Sun.COM 15388160SWentao.Yang@Sun.COM hiokp = (vnet_hio_kstats_t *)ksp->ks_data; 15398160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->ipackets, "ipackets", 15408160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 15418160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->ierrors, "ierrors", 15428160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 15438160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->opackets, "opackets", 15448160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 15458160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->oerrors, "oerrors", 15468160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 15478160SWentao.Yang@Sun.COM 15488160SWentao.Yang@Sun.COM 15498160SWentao.Yang@Sun.COM /* MIB II kstat variables */ 15508160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->rbytes, "rbytes", 15518160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 15528160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->obytes, "obytes", 15538160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 15548160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->multircv, "multircv", 15558160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 15568160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->multixmt, "multixmt", 15578160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 15588160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->brdcstrcv, "brdcstrcv", 15598160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 15608160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->brdcstxmt, "brdcstxmt", 15618160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 15628160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->norcvbuf, "norcvbuf", 15638160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 15648160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->noxmtbuf, "noxmtbuf", 15658160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 15668160SWentao.Yang@Sun.COM 15678160SWentao.Yang@Sun.COM ksp->ks_update = vnet_hio_update_kstats; 15688160SWentao.Yang@Sun.COM ksp->ks_private = (void *)vresp; 15698160SWentao.Yang@Sun.COM kstat_install(ksp); 15708160SWentao.Yang@Sun.COM return (ksp); 15718160SWentao.Yang@Sun.COM } 15728160SWentao.Yang@Sun.COM 15738160SWentao.Yang@Sun.COM /* 15748160SWentao.Yang@Sun.COM * Destroy kstats. 15758160SWentao.Yang@Sun.COM */ 15768160SWentao.Yang@Sun.COM static void 15778160SWentao.Yang@Sun.COM vnet_hio_destroy_kstats(kstat_t *ksp) 15788160SWentao.Yang@Sun.COM { 15798160SWentao.Yang@Sun.COM if (ksp != NULL) 15808160SWentao.Yang@Sun.COM kstat_delete(ksp); 15818160SWentao.Yang@Sun.COM } 15828160SWentao.Yang@Sun.COM 15838160SWentao.Yang@Sun.COM /* 15848160SWentao.Yang@Sun.COM * Update the kstats. 15858160SWentao.Yang@Sun.COM */ 15868160SWentao.Yang@Sun.COM static int 15878160SWentao.Yang@Sun.COM vnet_hio_update_kstats(kstat_t *ksp, int rw) 15888160SWentao.Yang@Sun.COM { 15898160SWentao.Yang@Sun.COM vnet_t *vnetp; 15908160SWentao.Yang@Sun.COM vnet_res_t *vresp; 15918160SWentao.Yang@Sun.COM vnet_hio_stats_t statsp; 15928160SWentao.Yang@Sun.COM vnet_hio_kstats_t *hiokp; 15938160SWentao.Yang@Sun.COM 15948160SWentao.Yang@Sun.COM vresp = (vnet_res_t *)ksp->ks_private; 15958160SWentao.Yang@Sun.COM vnetp = vresp->vnetp; 15968160SWentao.Yang@Sun.COM 15978160SWentao.Yang@Sun.COM bzero(&statsp, sizeof (vnet_hio_stats_t)); 15988160SWentao.Yang@Sun.COM 15998160SWentao.Yang@Sun.COM READ_ENTER(&vnetp->vsw_fp_rw); 16008160SWentao.Yang@Sun.COM if (vnetp->hio_fp == NULL) { 16018160SWentao.Yang@Sun.COM /* not using hio resources, just return */ 16028160SWentao.Yang@Sun.COM RW_EXIT(&vnetp->vsw_fp_rw); 16038160SWentao.Yang@Sun.COM return (0); 16048160SWentao.Yang@Sun.COM } 16058160SWentao.Yang@Sun.COM VNET_FDBE_REFHOLD(vnetp->hio_fp); 16068160SWentao.Yang@Sun.COM RW_EXIT(&vnetp->vsw_fp_rw); 16078160SWentao.Yang@Sun.COM vnet_hio_get_stats(vnetp->hio_fp, &statsp); 16088160SWentao.Yang@Sun.COM VNET_FDBE_REFRELE(vnetp->hio_fp); 16098160SWentao.Yang@Sun.COM 16108160SWentao.Yang@Sun.COM hiokp = (vnet_hio_kstats_t *)ksp->ks_data; 16118160SWentao.Yang@Sun.COM 16128160SWentao.Yang@Sun.COM if (rw == KSTAT_READ) { 16138160SWentao.Yang@Sun.COM /* Link Input/Output stats */ 16148160SWentao.Yang@Sun.COM hiokp->ipackets.value.ul = (uint32_t)statsp.ipackets; 16158160SWentao.Yang@Sun.COM hiokp->ipackets64.value.ull = statsp.ipackets; 16168160SWentao.Yang@Sun.COM hiokp->ierrors.value.ul = statsp.ierrors; 16178160SWentao.Yang@Sun.COM hiokp->opackets.value.ul = (uint32_t)statsp.opackets; 16188160SWentao.Yang@Sun.COM hiokp->opackets64.value.ull = statsp.opackets; 16198160SWentao.Yang@Sun.COM hiokp->oerrors.value.ul = statsp.oerrors; 16208160SWentao.Yang@Sun.COM 16218160SWentao.Yang@Sun.COM /* MIB II kstat variables */ 16228160SWentao.Yang@Sun.COM hiokp->rbytes.value.ul = (uint32_t)statsp.rbytes; 16238160SWentao.Yang@Sun.COM hiokp->rbytes64.value.ull = statsp.rbytes; 16248160SWentao.Yang@Sun.COM hiokp->obytes.value.ul = (uint32_t)statsp.obytes; 16258160SWentao.Yang@Sun.COM hiokp->obytes64.value.ull = statsp.obytes; 16268160SWentao.Yang@Sun.COM hiokp->multircv.value.ul = statsp.multircv; 16278160SWentao.Yang@Sun.COM hiokp->multixmt.value.ul = statsp.multixmt; 16288160SWentao.Yang@Sun.COM hiokp->brdcstrcv.value.ul = statsp.brdcstrcv; 16298160SWentao.Yang@Sun.COM hiokp->brdcstxmt.value.ul = statsp.brdcstxmt; 16308160SWentao.Yang@Sun.COM hiokp->norcvbuf.value.ul = statsp.norcvbuf; 16318160SWentao.Yang@Sun.COM hiokp->noxmtbuf.value.ul = statsp.noxmtbuf; 16328160SWentao.Yang@Sun.COM } else { 16338160SWentao.Yang@Sun.COM return (EACCES); 16348160SWentao.Yang@Sun.COM } 16358160SWentao.Yang@Sun.COM 16368160SWentao.Yang@Sun.COM return (0); 16378160SWentao.Yang@Sun.COM } 16388160SWentao.Yang@Sun.COM 16398160SWentao.Yang@Sun.COM static void 16408160SWentao.Yang@Sun.COM vnet_hio_get_stats(vnet_res_t *vresp, vnet_hio_stats_t *statsp) 16418160SWentao.Yang@Sun.COM { 16428160SWentao.Yang@Sun.COM mac_register_t *macp; 16438160SWentao.Yang@Sun.COM mac_callbacks_t *cbp; 16448160SWentao.Yang@Sun.COM uint64_t val; 16458160SWentao.Yang@Sun.COM int stat; 16468160SWentao.Yang@Sun.COM 16478160SWentao.Yang@Sun.COM /* 16488160SWentao.Yang@Sun.COM * get the specified statistics from the underlying nxge. 16498160SWentao.Yang@Sun.COM */ 16508160SWentao.Yang@Sun.COM macp = &vresp->macreg; 16518160SWentao.Yang@Sun.COM cbp = macp->m_callbacks; 16528160SWentao.Yang@Sun.COM for (stat = MAC_STAT_MIN; stat < MAC_STAT_OVERFLOWS; stat++) { 16538160SWentao.Yang@Sun.COM if (cbp->mc_getstat(macp->m_driver, stat, &val) == 0) { 16548160SWentao.Yang@Sun.COM switch (stat) { 16558160SWentao.Yang@Sun.COM case MAC_STAT_IPACKETS: 16568160SWentao.Yang@Sun.COM statsp->ipackets = val; 16578160SWentao.Yang@Sun.COM break; 16588160SWentao.Yang@Sun.COM 16598160SWentao.Yang@Sun.COM case MAC_STAT_IERRORS: 16608160SWentao.Yang@Sun.COM statsp->ierrors = val; 16618160SWentao.Yang@Sun.COM break; 16628160SWentao.Yang@Sun.COM 16638160SWentao.Yang@Sun.COM case MAC_STAT_OPACKETS: 16648160SWentao.Yang@Sun.COM statsp->opackets = val; 16658160SWentao.Yang@Sun.COM break; 16668160SWentao.Yang@Sun.COM 16678160SWentao.Yang@Sun.COM case MAC_STAT_OERRORS: 16688160SWentao.Yang@Sun.COM statsp->oerrors = val; 16698160SWentao.Yang@Sun.COM break; 16708160SWentao.Yang@Sun.COM 16718160SWentao.Yang@Sun.COM case MAC_STAT_RBYTES: 16728160SWentao.Yang@Sun.COM statsp->rbytes = val; 16738160SWentao.Yang@Sun.COM break; 16748160SWentao.Yang@Sun.COM 16758160SWentao.Yang@Sun.COM case MAC_STAT_OBYTES: 16768160SWentao.Yang@Sun.COM statsp->obytes = val; 16778160SWentao.Yang@Sun.COM break; 16788160SWentao.Yang@Sun.COM 16798160SWentao.Yang@Sun.COM case MAC_STAT_MULTIRCV: 16808160SWentao.Yang@Sun.COM statsp->multircv = val; 16818160SWentao.Yang@Sun.COM break; 16828160SWentao.Yang@Sun.COM 16838160SWentao.Yang@Sun.COM case MAC_STAT_MULTIXMT: 16848160SWentao.Yang@Sun.COM statsp->multixmt = val; 16858160SWentao.Yang@Sun.COM break; 16868160SWentao.Yang@Sun.COM 16878160SWentao.Yang@Sun.COM case MAC_STAT_BRDCSTRCV: 16888160SWentao.Yang@Sun.COM statsp->brdcstrcv = val; 16898160SWentao.Yang@Sun.COM break; 16908160SWentao.Yang@Sun.COM 16918160SWentao.Yang@Sun.COM case MAC_STAT_BRDCSTXMT: 16928160SWentao.Yang@Sun.COM statsp->brdcstxmt = val; 16938160SWentao.Yang@Sun.COM break; 16948160SWentao.Yang@Sun.COM 16958160SWentao.Yang@Sun.COM case MAC_STAT_NOXMTBUF: 16968160SWentao.Yang@Sun.COM statsp->noxmtbuf = val; 16978160SWentao.Yang@Sun.COM break; 16988160SWentao.Yang@Sun.COM 16998160SWentao.Yang@Sun.COM case MAC_STAT_NORCVBUF: 17008160SWentao.Yang@Sun.COM statsp->norcvbuf = val; 17018160SWentao.Yang@Sun.COM break; 17028160SWentao.Yang@Sun.COM 17038160SWentao.Yang@Sun.COM default: 17048160SWentao.Yang@Sun.COM /* 17058160SWentao.Yang@Sun.COM * parameters not interested. 17068160SWentao.Yang@Sun.COM */ 17078160SWentao.Yang@Sun.COM break; 17088160SWentao.Yang@Sun.COM } 17098160SWentao.Yang@Sun.COM } 17108160SWentao.Yang@Sun.COM } 17118160SWentao.Yang@Sun.COM } 17129336SSriharsha.Basavapatna@Sun.COM 17139336SSriharsha.Basavapatna@Sun.COM #ifdef VNET_IOC_DEBUG 17149336SSriharsha.Basavapatna@Sun.COM 17159336SSriharsha.Basavapatna@Sun.COM /* 17169336SSriharsha.Basavapatna@Sun.COM * The ioctl entry point is used only for debugging for now. The ioctl commands 17179336SSriharsha.Basavapatna@Sun.COM * can be used to force the link state of the channel connected to vsw. 17189336SSriharsha.Basavapatna@Sun.COM */ 17199336SSriharsha.Basavapatna@Sun.COM static void 17209336SSriharsha.Basavapatna@Sun.COM vnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp) 17219336SSriharsha.Basavapatna@Sun.COM { 17229336SSriharsha.Basavapatna@Sun.COM struct iocblk *iocp; 17239336SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp; 17249336SSriharsha.Basavapatna@Sun.COM 17259336SSriharsha.Basavapatna@Sun.COM iocp = (struct iocblk *)(uintptr_t)mp->b_rptr; 17269336SSriharsha.Basavapatna@Sun.COM iocp->ioc_error = 0; 17279336SSriharsha.Basavapatna@Sun.COM vnetp = (vnet_t *)arg; 17289336SSriharsha.Basavapatna@Sun.COM 17299336SSriharsha.Basavapatna@Sun.COM if (vnetp == NULL) { 17309336SSriharsha.Basavapatna@Sun.COM miocnak(q, mp, 0, EINVAL); 17319336SSriharsha.Basavapatna@Sun.COM return; 17329336SSriharsha.Basavapatna@Sun.COM } 17339336SSriharsha.Basavapatna@Sun.COM 17349336SSriharsha.Basavapatna@Sun.COM switch (iocp->ioc_cmd) { 17359336SSriharsha.Basavapatna@Sun.COM 17369336SSriharsha.Basavapatna@Sun.COM case VNET_FORCE_LINK_DOWN: 17379336SSriharsha.Basavapatna@Sun.COM case VNET_FORCE_LINK_UP: 17389336SSriharsha.Basavapatna@Sun.COM vnet_force_link_state(vnetp, q, mp); 17399336SSriharsha.Basavapatna@Sun.COM break; 17409336SSriharsha.Basavapatna@Sun.COM 17419336SSriharsha.Basavapatna@Sun.COM default: 17429336SSriharsha.Basavapatna@Sun.COM iocp->ioc_error = EINVAL; 17439336SSriharsha.Basavapatna@Sun.COM miocnak(q, mp, 0, iocp->ioc_error); 17449336SSriharsha.Basavapatna@Sun.COM break; 17459336SSriharsha.Basavapatna@Sun.COM 17469336SSriharsha.Basavapatna@Sun.COM } 17479336SSriharsha.Basavapatna@Sun.COM } 17489336SSriharsha.Basavapatna@Sun.COM 17499336SSriharsha.Basavapatna@Sun.COM static void 17509336SSriharsha.Basavapatna@Sun.COM vnet_force_link_state(vnet_t *vnetp, queue_t *q, mblk_t *mp) 17519336SSriharsha.Basavapatna@Sun.COM { 17529336SSriharsha.Basavapatna@Sun.COM mac_register_t *macp; 17539336SSriharsha.Basavapatna@Sun.COM mac_callbacks_t *cbp; 17549336SSriharsha.Basavapatna@Sun.COM vnet_res_t *vresp; 17559336SSriharsha.Basavapatna@Sun.COM 17569336SSriharsha.Basavapatna@Sun.COM READ_ENTER(&vnetp->vsw_fp_rw); 17579336SSriharsha.Basavapatna@Sun.COM 17589336SSriharsha.Basavapatna@Sun.COM vresp = vnetp->vsw_fp; 17599336SSriharsha.Basavapatna@Sun.COM if (vresp == NULL) { 17609336SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vsw_fp_rw); 17619336SSriharsha.Basavapatna@Sun.COM return; 17629336SSriharsha.Basavapatna@Sun.COM } 17639336SSriharsha.Basavapatna@Sun.COM 17649336SSriharsha.Basavapatna@Sun.COM macp = &vresp->macreg; 17659336SSriharsha.Basavapatna@Sun.COM cbp = macp->m_callbacks; 17669336SSriharsha.Basavapatna@Sun.COM cbp->mc_ioctl(macp->m_driver, q, mp); 17679336SSriharsha.Basavapatna@Sun.COM 17689336SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vsw_fp_rw); 17699336SSriharsha.Basavapatna@Sun.COM } 17709336SSriharsha.Basavapatna@Sun.COM 17719336SSriharsha.Basavapatna@Sun.COM #else 17729336SSriharsha.Basavapatna@Sun.COM 17739336SSriharsha.Basavapatna@Sun.COM static void 17749336SSriharsha.Basavapatna@Sun.COM vnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp) 17759336SSriharsha.Basavapatna@Sun.COM { 17769336SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp; 17779336SSriharsha.Basavapatna@Sun.COM 17789336SSriharsha.Basavapatna@Sun.COM vnetp = (vnet_t *)arg; 17799336SSriharsha.Basavapatna@Sun.COM 17809336SSriharsha.Basavapatna@Sun.COM if (vnetp == NULL) { 17819336SSriharsha.Basavapatna@Sun.COM miocnak(q, mp, 0, EINVAL); 17829336SSriharsha.Basavapatna@Sun.COM return; 17839336SSriharsha.Basavapatna@Sun.COM } 17849336SSriharsha.Basavapatna@Sun.COM 17859336SSriharsha.Basavapatna@Sun.COM /* ioctl support only for debugging */ 17869336SSriharsha.Basavapatna@Sun.COM miocnak(q, mp, 0, ENOTSUP); 17879336SSriharsha.Basavapatna@Sun.COM } 17889336SSriharsha.Basavapatna@Sun.COM 17899336SSriharsha.Basavapatna@Sun.COM #endif 1790