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) { 6046495Sspeer vnet_stop_resources(vnetp); 6056495Sspeer vnetp->flags &= ~VNET_STARTED; 6061991Sheppo } 6076495Sspeer RW_EXIT(&vnetp->vrwlock); 6081991Sheppo 6094647Sraghuram DBG1(vnetp, "exit\n"); 6101991Sheppo } 6111991Sheppo 6121991Sheppo /* set the unicast mac address of the device */ 6131991Sheppo static int 6141991Sheppo vnet_m_unicst(void *arg, const uint8_t *macaddr) 6151991Sheppo { 6161991Sheppo _NOTE(ARGUNUSED(macaddr)) 6171991Sheppo 6181991Sheppo vnet_t *vnetp = arg; 6191991Sheppo 6204647Sraghuram DBG1(vnetp, "enter\n"); 6211991Sheppo /* 6222793Slm66018 * NOTE: setting mac address dynamically is not supported. 6231991Sheppo */ 6244647Sraghuram DBG1(vnetp, "exit\n"); 6251991Sheppo 6262109Slm66018 return (VNET_FAILURE); 6271991Sheppo } 6281991Sheppo 6291991Sheppo /* enable/disable a multicast address */ 6301991Sheppo static int 6311991Sheppo vnet_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 6321991Sheppo { 6331991Sheppo _NOTE(ARGUNUSED(add, mca)) 6341991Sheppo 6351991Sheppo vnet_t *vnetp = arg; 6366495Sspeer vnet_res_t *vresp; 6376495Sspeer mac_register_t *macp; 6382311Sseb mac_callbacks_t *cbp; 6391991Sheppo int rv = VNET_SUCCESS; 6401991Sheppo 6414647Sraghuram DBG1(vnetp, "enter\n"); 6426495Sspeer 6436495Sspeer READ_ENTER(&vnetp->vrwlock); 6446495Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) { 6456495Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) { 6466495Sspeer macp = &vresp->macreg; 6476495Sspeer cbp = macp->m_callbacks; 6486495Sspeer rv = cbp->mc_multicst(macp->m_driver, add, mca); 6491991Sheppo } 6501991Sheppo } 6516495Sspeer RW_EXIT(&vnetp->vrwlock); 6526495Sspeer 6534647Sraghuram DBG1(vnetp, "exit(%d)\n", rv); 6541991Sheppo return (rv); 6551991Sheppo } 6561991Sheppo 6571991Sheppo /* set or clear promiscuous mode on the device */ 6581991Sheppo static int 6591991Sheppo vnet_m_promisc(void *arg, boolean_t on) 6601991Sheppo { 6611991Sheppo _NOTE(ARGUNUSED(on)) 6621991Sheppo 6631991Sheppo vnet_t *vnetp = arg; 6644647Sraghuram DBG1(vnetp, "enter\n"); 6651991Sheppo /* 6662793Slm66018 * NOTE: setting promiscuous mode is not supported, just return success. 6671991Sheppo */ 6684647Sraghuram DBG1(vnetp, "exit\n"); 6691991Sheppo return (VNET_SUCCESS); 6701991Sheppo } 6711991Sheppo 6721991Sheppo /* 6731991Sheppo * Transmit a chain of packets. This function provides switching functionality 6741991Sheppo * based on the destination mac address to reach other guests (within ldoms) or 6751991Sheppo * external hosts. 6761991Sheppo */ 6771991Sheppo mblk_t * 6781991Sheppo vnet_m_tx(void *arg, mblk_t *mp) 6791991Sheppo { 6806419Ssb155480 vnet_t *vnetp; 6816495Sspeer vnet_res_t *vresp; 6826419Ssb155480 mblk_t *next; 6836495Sspeer mblk_t *resid_mp; 6846495Sspeer mac_register_t *macp; 6856495Sspeer struct ether_header *ehp; 6866495Sspeer boolean_t is_unicast; 6877896SSriharsha.Basavapatna@Sun.COM boolean_t is_pvid; /* non-default pvid ? */ 6887896SSriharsha.Basavapatna@Sun.COM boolean_t hres; /* Hybrid resource ? */ 6891991Sheppo 6901991Sheppo vnetp = (vnet_t *)arg; 6914647Sraghuram DBG1(vnetp, "enter\n"); 6921991Sheppo ASSERT(mp != NULL); 6931991Sheppo 6947896SSriharsha.Basavapatna@Sun.COM is_pvid = (vnetp->pvid != vnetp->default_vlan_id) ? B_TRUE : B_FALSE; 6957896SSriharsha.Basavapatna@Sun.COM 6961991Sheppo while (mp != NULL) { 6976419Ssb155480 6981991Sheppo next = mp->b_next; 6991991Sheppo mp->b_next = NULL; 7001991Sheppo 7016419Ssb155480 /* 7026419Ssb155480 * Find fdb entry for the destination 7036419Ssb155480 * and hold a reference to it. 7046419Ssb155480 */ 7051991Sheppo ehp = (struct ether_header *)mp->b_rptr; 7066495Sspeer vresp = vnet_fdbe_find(vnetp, &ehp->ether_dhost); 7076495Sspeer if (vresp != NULL) { 7081991Sheppo 7091991Sheppo /* 7106419Ssb155480 * Destination found in FDB. 7116419Ssb155480 * The destination is a vnet device within ldoms 7126419Ssb155480 * and directly reachable, invoke the tx function 7136419Ssb155480 * in the fdb entry. 7141991Sheppo */ 7156495Sspeer macp = &vresp->macreg; 7166495Sspeer resid_mp = macp->m_callbacks->mc_tx(macp->m_driver, mp); 7176419Ssb155480 7186419Ssb155480 /* tx done; now release ref on fdb entry */ 7196495Sspeer VNET_FDBE_REFRELE(vresp); 7206419Ssb155480 7211991Sheppo if (resid_mp != NULL) { 7221991Sheppo /* m_tx failed */ 7231991Sheppo mp->b_next = next; 7241991Sheppo break; 7251991Sheppo } 7261991Sheppo } else { 7276495Sspeer is_unicast = !(IS_BROADCAST(ehp) || 7286495Sspeer (IS_MULTICAST(ehp))); 7291991Sheppo /* 7306419Ssb155480 * Destination is not in FDB. 7316495Sspeer * If the destination is broadcast or multicast, 7326495Sspeer * then forward the packet to vswitch. 7336495Sspeer * If a Hybrid resource avilable, then send the 7346495Sspeer * unicast packet via hybrid resource, otherwise 7356495Sspeer * forward it to vswitch. 7361991Sheppo */ 7376419Ssb155480 READ_ENTER(&vnetp->vsw_fp_rw); 7386419Ssb155480 7396495Sspeer if ((is_unicast) && (vnetp->hio_fp != NULL)) { 7406495Sspeer vresp = vnetp->hio_fp; 7417896SSriharsha.Basavapatna@Sun.COM hres = B_TRUE; 7426495Sspeer } else { 7436495Sspeer vresp = vnetp->vsw_fp; 7447896SSriharsha.Basavapatna@Sun.COM hres = B_FALSE; 7456495Sspeer } 7466495Sspeer if (vresp == NULL) { 7476419Ssb155480 /* 7486419Ssb155480 * no fdb entry to vsw? drop the packet. 7496419Ssb155480 */ 7506419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 7511991Sheppo freemsg(mp); 7526419Ssb155480 mp = next; 7536419Ssb155480 continue; 7541991Sheppo } 7556419Ssb155480 7566419Ssb155480 /* ref hold the fdb entry to vsw */ 7576495Sspeer VNET_FDBE_REFHOLD(vresp); 7586419Ssb155480 7596419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 7606419Ssb155480 7617896SSriharsha.Basavapatna@Sun.COM /* 7627896SSriharsha.Basavapatna@Sun.COM * In the case of a hybrid resource we need to insert 7637896SSriharsha.Basavapatna@Sun.COM * the tag for the pvid case here; unlike packets that 7647896SSriharsha.Basavapatna@Sun.COM * are destined to a vnet/vsw in which case the vgen 7657896SSriharsha.Basavapatna@Sun.COM * layer does the tagging before sending it over ldc. 7667896SSriharsha.Basavapatna@Sun.COM */ 7677896SSriharsha.Basavapatna@Sun.COM if (hres == B_TRUE) { 7687896SSriharsha.Basavapatna@Sun.COM /* 7697896SSriharsha.Basavapatna@Sun.COM * Determine if the frame being transmitted 7707896SSriharsha.Basavapatna@Sun.COM * over the hybrid resource is untagged. If so, 7717896SSriharsha.Basavapatna@Sun.COM * insert the tag before transmitting. 7727896SSriharsha.Basavapatna@Sun.COM */ 7737896SSriharsha.Basavapatna@Sun.COM if (is_pvid == B_TRUE && 7747896SSriharsha.Basavapatna@Sun.COM ehp->ether_type != htons(ETHERTYPE_VLAN)) { 7757896SSriharsha.Basavapatna@Sun.COM 7767896SSriharsha.Basavapatna@Sun.COM mp = vnet_vlan_insert_tag(mp, 7777896SSriharsha.Basavapatna@Sun.COM vnetp->pvid); 7787896SSriharsha.Basavapatna@Sun.COM if (mp == NULL) { 7797896SSriharsha.Basavapatna@Sun.COM VNET_FDBE_REFRELE(vresp); 7807896SSriharsha.Basavapatna@Sun.COM mp = next; 7817896SSriharsha.Basavapatna@Sun.COM continue; 7827896SSriharsha.Basavapatna@Sun.COM } 7837896SSriharsha.Basavapatna@Sun.COM 7847896SSriharsha.Basavapatna@Sun.COM } 7857896SSriharsha.Basavapatna@Sun.COM } 7867896SSriharsha.Basavapatna@Sun.COM 7876495Sspeer macp = &vresp->macreg; 7886495Sspeer resid_mp = macp->m_callbacks->mc_tx(macp->m_driver, mp); 7896419Ssb155480 7906419Ssb155480 /* tx done; now release ref on fdb entry */ 7916495Sspeer VNET_FDBE_REFRELE(vresp); 7926419Ssb155480 7936419Ssb155480 if (resid_mp != NULL) { 7946419Ssb155480 /* m_tx failed */ 7956419Ssb155480 mp->b_next = next; 7966419Ssb155480 break; 7976419Ssb155480 } 7981991Sheppo } 7991991Sheppo 8001991Sheppo mp = next; 8011991Sheppo } 8021991Sheppo 8034647Sraghuram DBG1(vnetp, "exit\n"); 8041991Sheppo return (mp); 8051991Sheppo } 8061991Sheppo 8072311Sseb /* get statistics from the device */ 8082311Sseb int 8092311Sseb vnet_m_stat(void *arg, uint_t stat, uint64_t *val) 8101991Sheppo { 8111991Sheppo vnet_t *vnetp = arg; 8126495Sspeer vnet_res_t *vresp; 8136495Sspeer mac_register_t *macp; 8142311Sseb mac_callbacks_t *cbp; 8152311Sseb uint64_t val_total = 0; 8161991Sheppo 8174647Sraghuram DBG1(vnetp, "enter\n"); 8181991Sheppo 8191991Sheppo /* 8202311Sseb * get the specified statistic from each transport and return the 8212311Sseb * aggregate val. This obviously only works for counters. 8221991Sheppo */ 8232311Sseb if ((IS_MAC_STAT(stat) && !MAC_STAT_ISACOUNTER(stat)) || 8242311Sseb (IS_MACTYPE_STAT(stat) && !ETHER_STAT_ISACOUNTER(stat))) { 8252311Sseb return (ENOTSUP); 8262311Sseb } 8276495Sspeer 8286495Sspeer READ_ENTER(&vnetp->vrwlock); 8296495Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) { 8306495Sspeer macp = &vresp->macreg; 8316495Sspeer cbp = macp->m_callbacks; 8326495Sspeer if (cbp->mc_getstat(macp->m_driver, stat, val) == 0) 8332311Sseb val_total += *val; 8341991Sheppo } 8356495Sspeer RW_EXIT(&vnetp->vrwlock); 8361991Sheppo 8372311Sseb *val = val_total; 8382311Sseb 8394647Sraghuram DBG1(vnetp, "exit\n"); 8402311Sseb return (0); 8411991Sheppo } 8421991Sheppo 8431991Sheppo /* wrapper function for mac_register() */ 8441991Sheppo static int 8451991Sheppo vnet_mac_register(vnet_t *vnetp) 8461991Sheppo { 8472311Sseb mac_register_t *macp; 8482311Sseb int err; 8491991Sheppo 8502311Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 8512311Sseb return (DDI_FAILURE); 8522311Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 8532311Sseb macp->m_driver = vnetp; 8541991Sheppo macp->m_dip = vnetp->dip; 8552311Sseb macp->m_src_addr = vnetp->curr_macaddr; 8562311Sseb macp->m_callbacks = &vnet_m_callbacks; 8572311Sseb macp->m_min_sdu = 0; 8587529SSriharsha.Basavapatna@Sun.COM macp->m_max_sdu = vnetp->mtu; 8596419Ssb155480 macp->m_margin = VLAN_TAGSZ; 8601991Sheppo 8611991Sheppo /* 8621991Sheppo * Finally, we're ready to register ourselves with the MAC layer 8631991Sheppo * interface; if this succeeds, we're all ready to start() 8641991Sheppo */ 8652311Sseb err = mac_register(macp, &vnetp->mh); 8662311Sseb mac_free(macp); 8672311Sseb return (err == 0 ? DDI_SUCCESS : DDI_FAILURE); 8681991Sheppo } 8691991Sheppo 8701991Sheppo /* read the mac address of the device */ 8711991Sheppo static int 8721991Sheppo vnet_read_mac_address(vnet_t *vnetp) 8731991Sheppo { 8741991Sheppo uchar_t *macaddr; 8751991Sheppo uint32_t size; 8761991Sheppo int rv; 8771991Sheppo 8781991Sheppo rv = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, vnetp->dip, 8794650Sraghuram DDI_PROP_DONTPASS, macaddr_propname, &macaddr, &size); 8801991Sheppo if ((rv != DDI_PROP_SUCCESS) || (size != ETHERADDRL)) { 8814647Sraghuram DWARN(vnetp, "prop_lookup failed(%s) err(%d)\n", 8824647Sraghuram macaddr_propname, rv); 8831991Sheppo return (DDI_FAILURE); 8841991Sheppo } 8851991Sheppo bcopy(macaddr, (caddr_t)vnetp->vendor_addr, ETHERADDRL); 8861991Sheppo bcopy(macaddr, (caddr_t)vnetp->curr_macaddr, ETHERADDRL); 8871991Sheppo ddi_prop_free(macaddr); 8881991Sheppo 8891991Sheppo return (DDI_SUCCESS); 8901991Sheppo } 8911991Sheppo 8926419Ssb155480 static void 8936419Ssb155480 vnet_fdb_create(vnet_t *vnetp) 8941991Sheppo { 8956419Ssb155480 char hashname[MAXNAMELEN]; 8961991Sheppo 8976419Ssb155480 (void) snprintf(hashname, MAXNAMELEN, "vnet%d-fdbhash", 8986419Ssb155480 vnetp->instance); 8996419Ssb155480 vnetp->fdb_nchains = vnet_fdb_nchains; 9006419Ssb155480 vnetp->fdb_hashp = mod_hash_create_ptrhash(hashname, vnetp->fdb_nchains, 9016419Ssb155480 mod_hash_null_valdtor, sizeof (void *)); 9026419Ssb155480 } 9031991Sheppo 9046419Ssb155480 static void 9056419Ssb155480 vnet_fdb_destroy(vnet_t *vnetp) 9066419Ssb155480 { 9076419Ssb155480 /* destroy fdb-hash-table */ 9086419Ssb155480 if (vnetp->fdb_hashp != NULL) { 9096419Ssb155480 mod_hash_destroy_hash(vnetp->fdb_hashp); 9106419Ssb155480 vnetp->fdb_hashp = NULL; 9116419Ssb155480 vnetp->fdb_nchains = 0; 9121991Sheppo } 9131991Sheppo } 9141991Sheppo 9156419Ssb155480 /* 9166419Ssb155480 * Add an entry into the fdb. 9176419Ssb155480 */ 9181991Sheppo void 9196495Sspeer vnet_fdbe_add(vnet_t *vnetp, vnet_res_t *vresp) 9201991Sheppo { 9216419Ssb155480 uint64_t addr = 0; 9226419Ssb155480 int rv; 9236419Ssb155480 9246495Sspeer KEY_HASH(addr, vresp->rem_macaddr); 9251991Sheppo 9266419Ssb155480 /* 9276495Sspeer * If the entry being added corresponds to LDC_SERVICE resource, 9286495Sspeer * that is, vswitch connection, it is added to the hash and also 9296495Sspeer * the entry is cached, an additional reference count reflects 9306495Sspeer * this. The HYBRID resource is not added to the hash, but only 9316495Sspeer * cached, as it is only used for sending out packets for unknown 9326495Sspeer * unicast destinations. 9336419Ssb155480 */ 9346495Sspeer (vresp->type == VIO_NET_RES_LDC_SERVICE) ? 9356495Sspeer (vresp->refcnt = 1) : (vresp->refcnt = 0); 9361991Sheppo 9376419Ssb155480 /* 9386419Ssb155480 * Note: duplicate keys will be rejected by mod_hash. 9396419Ssb155480 */ 9406495Sspeer if (vresp->type != VIO_NET_RES_HYBRID) { 9416495Sspeer rv = mod_hash_insert(vnetp->fdb_hashp, (mod_hash_key_t)addr, 9426495Sspeer (mod_hash_val_t)vresp); 9436495Sspeer if (rv != 0) { 9446495Sspeer DWARN(vnetp, "Duplicate macaddr key(%lx)\n", addr); 9456495Sspeer return; 9466495Sspeer } 9471991Sheppo } 9481991Sheppo 9496495Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) { 9506419Ssb155480 /* Cache the fdb entry to vsw-port */ 9516419Ssb155480 WRITE_ENTER(&vnetp->vsw_fp_rw); 9526419Ssb155480 if (vnetp->vsw_fp == NULL) 9536495Sspeer vnetp->vsw_fp = vresp; 9546495Sspeer RW_EXIT(&vnetp->vsw_fp_rw); 9556495Sspeer } else if (vresp->type == VIO_NET_RES_HYBRID) { 9566495Sspeer /* Cache the fdb entry to hybrid resource */ 9576495Sspeer WRITE_ENTER(&vnetp->vsw_fp_rw); 9586495Sspeer if (vnetp->hio_fp == NULL) 9596495Sspeer vnetp->hio_fp = vresp; 9606419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 9612793Slm66018 } 9621991Sheppo } 9631991Sheppo 9646419Ssb155480 /* 9656419Ssb155480 * Remove an entry from fdb. 9666419Ssb155480 */ 9676495Sspeer static void 9686495Sspeer vnet_fdbe_del(vnet_t *vnetp, vnet_res_t *vresp) 9695641Swentaoy { 9706419Ssb155480 uint64_t addr = 0; 9716419Ssb155480 int rv; 9726419Ssb155480 uint32_t refcnt; 9736495Sspeer vnet_res_t *tmp; 9745641Swentaoy 9756495Sspeer KEY_HASH(addr, vresp->rem_macaddr); 9765641Swentaoy 9776419Ssb155480 /* 9786419Ssb155480 * Remove the entry from fdb hash table. 9796419Ssb155480 * This prevents further references to this fdb entry. 9806419Ssb155480 */ 9816495Sspeer if (vresp->type != VIO_NET_RES_HYBRID) { 9826495Sspeer rv = mod_hash_remove(vnetp->fdb_hashp, (mod_hash_key_t)addr, 9836495Sspeer (mod_hash_val_t *)&tmp); 9846495Sspeer if (rv != 0) { 9856495Sspeer /* 9866495Sspeer * As the resources are added to the hash only 9876495Sspeer * after they are started, this can occur if 9886495Sspeer * a resource unregisters before it is ever started. 9896495Sspeer */ 9906495Sspeer return; 9916495Sspeer } 9926495Sspeer } 9935641Swentaoy 9946495Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) { 9956419Ssb155480 WRITE_ENTER(&vnetp->vsw_fp_rw); 9965641Swentaoy 9976495Sspeer ASSERT(tmp == vnetp->vsw_fp); 9986419Ssb155480 vnetp->vsw_fp = NULL; 9996419Ssb155480 10006419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 10016495Sspeer } else if (vresp->type == VIO_NET_RES_HYBRID) { 10026495Sspeer WRITE_ENTER(&vnetp->vsw_fp_rw); 10036495Sspeer 10046495Sspeer vnetp->hio_fp = NULL; 10056495Sspeer 10066495Sspeer RW_EXIT(&vnetp->vsw_fp_rw); 10075641Swentaoy } 10085641Swentaoy 10095641Swentaoy /* 10106419Ssb155480 * If there are threads already ref holding before the entry was 10116419Ssb155480 * removed from hash table, then wait for ref count to drop to zero. 10125641Swentaoy */ 10136495Sspeer (vresp->type == VIO_NET_RES_LDC_SERVICE) ? 10146495Sspeer (refcnt = 1) : (refcnt = 0); 10156495Sspeer while (vresp->refcnt > refcnt) { 10166419Ssb155480 delay(drv_usectohz(vnet_fdbe_refcnt_delay)); 10176419Ssb155480 } 10181991Sheppo } 10191991Sheppo 10206419Ssb155480 /* 10216419Ssb155480 * Search fdb for a given mac address. If an entry is found, hold 10226419Ssb155480 * a reference to it and return the entry; else returns NULL. 10236419Ssb155480 */ 10246495Sspeer static vnet_res_t * 10256419Ssb155480 vnet_fdbe_find(vnet_t *vnetp, struct ether_addr *addrp) 10261991Sheppo { 10276419Ssb155480 uint64_t key = 0; 10286495Sspeer vnet_res_t *vresp; 10296419Ssb155480 int rv; 10306419Ssb155480 10316495Sspeer KEY_HASH(key, addrp->ether_addr_octet); 10326419Ssb155480 10336419Ssb155480 rv = mod_hash_find_cb(vnetp->fdb_hashp, (mod_hash_key_t)key, 10346495Sspeer (mod_hash_val_t *)&vresp, vnet_fdbe_find_cb); 10351991Sheppo 10366419Ssb155480 if (rv != 0) 10376419Ssb155480 return (NULL); 10381991Sheppo 10396495Sspeer return (vresp); 10406419Ssb155480 } 10411991Sheppo 10426419Ssb155480 /* 10436419Ssb155480 * Callback function provided to mod_hash_find_cb(). After finding the fdb 10446419Ssb155480 * entry corresponding to the key (macaddr), this callback will be invoked by 10456419Ssb155480 * mod_hash_find_cb() to atomically increment the reference count on the fdb 10466419Ssb155480 * entry before returning the found entry. 10476419Ssb155480 */ 10486419Ssb155480 static void 10496419Ssb155480 vnet_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val) 10506419Ssb155480 { 10516419Ssb155480 _NOTE(ARGUNUSED(key)) 10526495Sspeer VNET_FDBE_REFHOLD((vnet_res_t *)val); 10536495Sspeer } 10546495Sspeer 10557896SSriharsha.Basavapatna@Sun.COM /* 10567896SSriharsha.Basavapatna@Sun.COM * Frames received that are tagged with the pvid of the vnet device must be 10577896SSriharsha.Basavapatna@Sun.COM * untagged before sending up the stack. This function walks the chain of rx 10587896SSriharsha.Basavapatna@Sun.COM * frames, untags any such frames and returns the updated chain. 10597896SSriharsha.Basavapatna@Sun.COM * 10607896SSriharsha.Basavapatna@Sun.COM * Arguments: 10617896SSriharsha.Basavapatna@Sun.COM * pvid: pvid of the vnet device for which packets are being received 10627896SSriharsha.Basavapatna@Sun.COM * mp: head of pkt chain to be validated and untagged 10637896SSriharsha.Basavapatna@Sun.COM * 10647896SSriharsha.Basavapatna@Sun.COM * Returns: 10657896SSriharsha.Basavapatna@Sun.COM * mp: head of updated chain of packets 10667896SSriharsha.Basavapatna@Sun.COM */ 10677896SSriharsha.Basavapatna@Sun.COM static void 10687896SSriharsha.Basavapatna@Sun.COM vnet_rx_frames_untag(uint16_t pvid, mblk_t **mp) 10697896SSriharsha.Basavapatna@Sun.COM { 10707896SSriharsha.Basavapatna@Sun.COM struct ether_vlan_header *evhp; 10717896SSriharsha.Basavapatna@Sun.COM mblk_t *bp; 10727896SSriharsha.Basavapatna@Sun.COM mblk_t *bpt; 10737896SSriharsha.Basavapatna@Sun.COM mblk_t *bph; 10747896SSriharsha.Basavapatna@Sun.COM mblk_t *bpn; 10757896SSriharsha.Basavapatna@Sun.COM 10767896SSriharsha.Basavapatna@Sun.COM bpn = bph = bpt = NULL; 10777896SSriharsha.Basavapatna@Sun.COM 10787896SSriharsha.Basavapatna@Sun.COM for (bp = *mp; bp != NULL; bp = bpn) { 10797896SSriharsha.Basavapatna@Sun.COM 10807896SSriharsha.Basavapatna@Sun.COM bpn = bp->b_next; 10817896SSriharsha.Basavapatna@Sun.COM bp->b_next = bp->b_prev = NULL; 10827896SSriharsha.Basavapatna@Sun.COM 10837896SSriharsha.Basavapatna@Sun.COM evhp = (struct ether_vlan_header *)bp->b_rptr; 10847896SSriharsha.Basavapatna@Sun.COM 10857896SSriharsha.Basavapatna@Sun.COM if (ntohs(evhp->ether_tpid) == ETHERTYPE_VLAN && 10867896SSriharsha.Basavapatna@Sun.COM VLAN_ID(ntohs(evhp->ether_tci)) == pvid) { 10877896SSriharsha.Basavapatna@Sun.COM 10887896SSriharsha.Basavapatna@Sun.COM bp = vnet_vlan_remove_tag(bp); 10897896SSriharsha.Basavapatna@Sun.COM if (bp == NULL) { 10907896SSriharsha.Basavapatna@Sun.COM continue; 10917896SSriharsha.Basavapatna@Sun.COM } 10927896SSriharsha.Basavapatna@Sun.COM 10937896SSriharsha.Basavapatna@Sun.COM } 10947896SSriharsha.Basavapatna@Sun.COM 10957896SSriharsha.Basavapatna@Sun.COM /* build a chain of processed packets */ 10967896SSriharsha.Basavapatna@Sun.COM if (bph == NULL) { 10977896SSriharsha.Basavapatna@Sun.COM bph = bpt = bp; 10987896SSriharsha.Basavapatna@Sun.COM } else { 10997896SSriharsha.Basavapatna@Sun.COM bpt->b_next = bp; 11007896SSriharsha.Basavapatna@Sun.COM bpt = bp; 11017896SSriharsha.Basavapatna@Sun.COM } 11027896SSriharsha.Basavapatna@Sun.COM 11037896SSriharsha.Basavapatna@Sun.COM } 11047896SSriharsha.Basavapatna@Sun.COM 11057896SSriharsha.Basavapatna@Sun.COM *mp = bph; 11067896SSriharsha.Basavapatna@Sun.COM } 11077896SSriharsha.Basavapatna@Sun.COM 11086495Sspeer static void 11096495Sspeer vnet_rx(vio_net_handle_t vrh, mblk_t *mp) 11106495Sspeer { 11117896SSriharsha.Basavapatna@Sun.COM vnet_res_t *vresp = (vnet_res_t *)vrh; 11127896SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp = vresp->vnetp; 11137896SSriharsha.Basavapatna@Sun.COM 11147896SSriharsha.Basavapatna@Sun.COM if ((vnetp == NULL) || (vnetp->mh == 0)) { 11157896SSriharsha.Basavapatna@Sun.COM freemsgchain(mp); 11167896SSriharsha.Basavapatna@Sun.COM return; 11177896SSriharsha.Basavapatna@Sun.COM } 11186495Sspeer 11197896SSriharsha.Basavapatna@Sun.COM /* 11207896SSriharsha.Basavapatna@Sun.COM * Packets received over a hybrid resource need additional processing 11217896SSriharsha.Basavapatna@Sun.COM * to remove the tag, for the pvid case. The underlying resource is 11227896SSriharsha.Basavapatna@Sun.COM * not aware of the vnet's pvid and thus packets are received with the 11237896SSriharsha.Basavapatna@Sun.COM * vlan tag in the header; unlike packets that are received over a ldc 11247896SSriharsha.Basavapatna@Sun.COM * channel in which case the peer vnet/vsw would have already removed 11257896SSriharsha.Basavapatna@Sun.COM * the tag. 11267896SSriharsha.Basavapatna@Sun.COM */ 11277896SSriharsha.Basavapatna@Sun.COM if (vresp->type == VIO_NET_RES_HYBRID && 11287896SSriharsha.Basavapatna@Sun.COM vnetp->pvid != vnetp->default_vlan_id) { 11297896SSriharsha.Basavapatna@Sun.COM 11307896SSriharsha.Basavapatna@Sun.COM vnet_rx_frames_untag(vnetp->pvid, &mp); 11317896SSriharsha.Basavapatna@Sun.COM if (mp == NULL) { 11327896SSriharsha.Basavapatna@Sun.COM return; 11337896SSriharsha.Basavapatna@Sun.COM } 11346495Sspeer } 11357896SSriharsha.Basavapatna@Sun.COM 11367896SSriharsha.Basavapatna@Sun.COM mac_rx(vnetp->mh, NULL, mp); 11371991Sheppo } 11382311Sseb 11392311Sseb void 11406495Sspeer vnet_tx_update(vio_net_handle_t vrh) 11416495Sspeer { 11426495Sspeer vnet_res_t *vresp = (vnet_res_t *)vrh; 11436495Sspeer vnet_t *vnetp = vresp->vnetp; 11446495Sspeer 11456495Sspeer if ((vnetp != NULL) && (vnetp->mh != NULL)) { 11466495Sspeer mac_tx_update(vnetp->mh); 11476495Sspeer } 11486495Sspeer } 11496495Sspeer 11506495Sspeer /* 11517529SSriharsha.Basavapatna@Sun.COM * Update the new mtu of vnet into the mac layer. First check if the device has 11527529SSriharsha.Basavapatna@Sun.COM * been plumbed and if so fail the mtu update. Returns 0 on success. 11537529SSriharsha.Basavapatna@Sun.COM */ 11547529SSriharsha.Basavapatna@Sun.COM int 11557529SSriharsha.Basavapatna@Sun.COM vnet_mtu_update(vnet_t *vnetp, uint32_t mtu) 11567529SSriharsha.Basavapatna@Sun.COM { 11577529SSriharsha.Basavapatna@Sun.COM int rv; 11587529SSriharsha.Basavapatna@Sun.COM 11597529SSriharsha.Basavapatna@Sun.COM if (vnetp == NULL || vnetp->mh == NULL) { 11607529SSriharsha.Basavapatna@Sun.COM return (EINVAL); 11617529SSriharsha.Basavapatna@Sun.COM } 11627529SSriharsha.Basavapatna@Sun.COM 11637529SSriharsha.Basavapatna@Sun.COM WRITE_ENTER(&vnetp->vrwlock); 11647529SSriharsha.Basavapatna@Sun.COM 11657529SSriharsha.Basavapatna@Sun.COM if (vnetp->flags & VNET_STARTED) { 11667529SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock); 11677529SSriharsha.Basavapatna@Sun.COM cmn_err(CE_NOTE, "!vnet%d: Unable to process mtu " 11687529SSriharsha.Basavapatna@Sun.COM "update as the device is plumbed\n", 11697529SSriharsha.Basavapatna@Sun.COM vnetp->instance); 11707529SSriharsha.Basavapatna@Sun.COM return (EBUSY); 11717529SSriharsha.Basavapatna@Sun.COM } 11727529SSriharsha.Basavapatna@Sun.COM 11737529SSriharsha.Basavapatna@Sun.COM /* update mtu in the mac layer */ 11747529SSriharsha.Basavapatna@Sun.COM rv = mac_maxsdu_update(vnetp->mh, mtu); 11757529SSriharsha.Basavapatna@Sun.COM if (rv != 0) { 11767529SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock); 11777529SSriharsha.Basavapatna@Sun.COM cmn_err(CE_NOTE, 11787529SSriharsha.Basavapatna@Sun.COM "!vnet%d: Unable to update mtu with mac layer\n", 11797529SSriharsha.Basavapatna@Sun.COM vnetp->instance); 11807529SSriharsha.Basavapatna@Sun.COM return (EIO); 11817529SSriharsha.Basavapatna@Sun.COM } 11827529SSriharsha.Basavapatna@Sun.COM 11837529SSriharsha.Basavapatna@Sun.COM vnetp->mtu = mtu; 11847529SSriharsha.Basavapatna@Sun.COM 11857529SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock); 11867529SSriharsha.Basavapatna@Sun.COM 11877529SSriharsha.Basavapatna@Sun.COM return (0); 11887529SSriharsha.Basavapatna@Sun.COM } 11897529SSriharsha.Basavapatna@Sun.COM 11907529SSriharsha.Basavapatna@Sun.COM /* 11919336SSriharsha.Basavapatna@Sun.COM * Update the link state of vnet to the mac layer. 11929336SSriharsha.Basavapatna@Sun.COM */ 11939336SSriharsha.Basavapatna@Sun.COM void 11949336SSriharsha.Basavapatna@Sun.COM vnet_link_update(vnet_t *vnetp, link_state_t link_state) 11959336SSriharsha.Basavapatna@Sun.COM { 11969336SSriharsha.Basavapatna@Sun.COM if (vnetp == NULL || vnetp->mh == NULL) { 11979336SSriharsha.Basavapatna@Sun.COM return; 11989336SSriharsha.Basavapatna@Sun.COM } 11999336SSriharsha.Basavapatna@Sun.COM 12009336SSriharsha.Basavapatna@Sun.COM WRITE_ENTER(&vnetp->vrwlock); 12019336SSriharsha.Basavapatna@Sun.COM if (vnetp->link_state == link_state) { 12029336SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock); 12039336SSriharsha.Basavapatna@Sun.COM return; 12049336SSriharsha.Basavapatna@Sun.COM } 12059336SSriharsha.Basavapatna@Sun.COM vnetp->link_state = link_state; 12069336SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock); 12079336SSriharsha.Basavapatna@Sun.COM 12089336SSriharsha.Basavapatna@Sun.COM mac_link_update(vnetp->mh, link_state); 12099336SSriharsha.Basavapatna@Sun.COM } 12109336SSriharsha.Basavapatna@Sun.COM 12119336SSriharsha.Basavapatna@Sun.COM /* 12126495Sspeer * vio_net_resource_reg -- An interface called to register a resource 12136495Sspeer * with vnet. 12146495Sspeer * macp -- a GLDv3 mac_register that has all the details of 12156495Sspeer * a resource and its callbacks etc. 12166495Sspeer * type -- resource type. 12176495Sspeer * local_macaddr -- resource's MAC address. This is used to 12186495Sspeer * associate a resource with a corresponding vnet. 12196495Sspeer * remote_macaddr -- remote side MAC address. This is ignored for 12206495Sspeer * the Hybrid resources. 12216495Sspeer * vhp -- A handle returned to the caller. 12226495Sspeer * vcb -- A set of callbacks provided to the callers. 12236495Sspeer */ 12246495Sspeer int vio_net_resource_reg(mac_register_t *macp, vio_net_res_type_t type, 12256495Sspeer ether_addr_t local_macaddr, ether_addr_t rem_macaddr, vio_net_handle_t *vhp, 12266495Sspeer vio_net_callbacks_t *vcb) 12276495Sspeer { 12286495Sspeer vnet_t *vnetp; 12296495Sspeer vnet_res_t *vresp; 12306495Sspeer 12316495Sspeer vresp = kmem_zalloc(sizeof (vnet_res_t), KM_SLEEP); 12326495Sspeer ether_copy(local_macaddr, vresp->local_macaddr); 12336495Sspeer ether_copy(rem_macaddr, vresp->rem_macaddr); 12346495Sspeer vresp->type = type; 12356495Sspeer bcopy(macp, &vresp->macreg, sizeof (mac_register_t)); 12366495Sspeer 12376495Sspeer DBG1(NULL, "Resource Registerig type=0%X\n", type); 12386495Sspeer 12396495Sspeer READ_ENTER(&vnet_rw); 12406495Sspeer vnetp = vnet_headp; 12416495Sspeer while (vnetp != NULL) { 12426495Sspeer if (VNET_MATCH_RES(vresp, vnetp)) { 12438332SWentao.Yang@Sun.COM vresp->vnetp = vnetp; 12448332SWentao.Yang@Sun.COM 12458332SWentao.Yang@Sun.COM /* Setup kstats for hio resource */ 12468332SWentao.Yang@Sun.COM if (vresp->type == VIO_NET_RES_HYBRID) { 12478332SWentao.Yang@Sun.COM vresp->ksp = vnet_hio_setup_kstats(DRV_NAME, 12488332SWentao.Yang@Sun.COM "hio", vresp); 12498332SWentao.Yang@Sun.COM if (vresp->ksp == NULL) { 12508332SWentao.Yang@Sun.COM cmn_err(CE_NOTE, "!vnet%d: Cannot " 12518332SWentao.Yang@Sun.COM "create kstats for hio resource", 12528332SWentao.Yang@Sun.COM vnetp->instance); 12538332SWentao.Yang@Sun.COM } 12548332SWentao.Yang@Sun.COM } 12558332SWentao.Yang@Sun.COM 12566495Sspeer WRITE_ENTER(&vnetp->vrwlock); 12576495Sspeer vresp->nextp = vnetp->vres_list; 12586495Sspeer vnetp->vres_list = vresp; 12596495Sspeer RW_EXIT(&vnetp->vrwlock); 12606495Sspeer break; 12616495Sspeer } 12626495Sspeer vnetp = vnetp->nextp; 12636495Sspeer } 12646495Sspeer RW_EXIT(&vnet_rw); 12656495Sspeer if (vresp->vnetp == NULL) { 12666495Sspeer DWARN(NULL, "No vnet instance"); 12676495Sspeer kmem_free(vresp, sizeof (vnet_res_t)); 12686495Sspeer return (ENXIO); 12696495Sspeer } 12706495Sspeer 12716495Sspeer *vhp = vresp; 12726495Sspeer vcb->vio_net_rx_cb = vnet_rx; 12736495Sspeer vcb->vio_net_tx_update = vnet_tx_update; 12746495Sspeer vcb->vio_net_report_err = vnet_handle_res_err; 12756495Sspeer 12766495Sspeer /* Dispatch a task to start resources */ 12776495Sspeer vnet_dispatch_res_task(vnetp); 12786495Sspeer return (0); 12796495Sspeer } 12806495Sspeer 12816495Sspeer /* 12826495Sspeer * vio_net_resource_unreg -- An interface to unregister a resource. 12836495Sspeer */ 12846495Sspeer void 12856495Sspeer vio_net_resource_unreg(vio_net_handle_t vhp) 12866495Sspeer { 12876495Sspeer vnet_res_t *vresp = (vnet_res_t *)vhp; 12886495Sspeer vnet_t *vnetp = vresp->vnetp; 12896495Sspeer vnet_res_t *vrp; 12908160SWentao.Yang@Sun.COM kstat_t *ksp = NULL; 12916495Sspeer 12926495Sspeer DBG1(NULL, "Resource Registerig hdl=0x%p", vhp); 12936495Sspeer 12946495Sspeer ASSERT(vnetp != NULL); 12956495Sspeer vnet_fdbe_del(vnetp, vresp); 12966495Sspeer 12976495Sspeer WRITE_ENTER(&vnetp->vrwlock); 12986495Sspeer if (vresp == vnetp->vres_list) { 12996495Sspeer vnetp->vres_list = vresp->nextp; 13006495Sspeer } else { 13016495Sspeer vrp = vnetp->vres_list; 13026495Sspeer while (vrp->nextp != NULL) { 13036495Sspeer if (vrp->nextp == vresp) { 13046495Sspeer vrp->nextp = vresp->nextp; 13056495Sspeer break; 13066495Sspeer } 13076495Sspeer vrp = vrp->nextp; 13086495Sspeer } 13096495Sspeer } 13108160SWentao.Yang@Sun.COM 13118160SWentao.Yang@Sun.COM ksp = vresp->ksp; 13128160SWentao.Yang@Sun.COM vresp->ksp = NULL; 13138160SWentao.Yang@Sun.COM 13146495Sspeer vresp->vnetp = NULL; 13156495Sspeer vresp->nextp = NULL; 13166495Sspeer RW_EXIT(&vnetp->vrwlock); 13178160SWentao.Yang@Sun.COM vnet_hio_destroy_kstats(ksp); 13186495Sspeer KMEM_FREE(vresp); 13196495Sspeer } 13206495Sspeer 13216495Sspeer /* 13226495Sspeer * vnet_dds_rx -- an interface called by vgen to DDS messages. 13236495Sspeer */ 13246495Sspeer void 13256495Sspeer vnet_dds_rx(void *arg, void *dmsg) 13262311Sseb { 13272311Sseb vnet_t *vnetp = arg; 13286495Sspeer vdds_process_dds_msg(vnetp, dmsg); 13292311Sseb } 13302311Sseb 13316495Sspeer /* 13326495Sspeer * vnet_send_dds_msg -- An interface provided to DDS to send 13336495Sspeer * DDS messages. This simply sends meessages via vgen. 13346495Sspeer */ 13356495Sspeer int 13366495Sspeer vnet_send_dds_msg(vnet_t *vnetp, void *dmsg) 13376495Sspeer { 13386495Sspeer int rv; 13396495Sspeer 13406495Sspeer if (vnetp->vgenhdl != NULL) { 13416495Sspeer rv = vgen_dds_tx(vnetp->vgenhdl, dmsg); 13426495Sspeer } 13436495Sspeer return (rv); 13446495Sspeer } 13456495Sspeer 13466495Sspeer /* 13479647SWentao.Yang@Sun.COM * vnet_cleanup_hio -- an interface called by vgen to cleanup hio resources. 13489647SWentao.Yang@Sun.COM */ 13499647SWentao.Yang@Sun.COM void 13509647SWentao.Yang@Sun.COM vnet_dds_cleanup_hio(vnet_t *vnetp) 13519647SWentao.Yang@Sun.COM { 13529647SWentao.Yang@Sun.COM vdds_cleanup_hio(vnetp); 13539647SWentao.Yang@Sun.COM } 13549647SWentao.Yang@Sun.COM 13559647SWentao.Yang@Sun.COM /* 13566495Sspeer * vnet_handle_res_err -- A callback function called by a resource 13576495Sspeer * to report an error. For example, vgen can call to report 13586495Sspeer * an LDC down/reset event. This will trigger cleanup of associated 13596495Sspeer * Hybrid resource. 13606495Sspeer */ 13616495Sspeer /* ARGSUSED */ 13626495Sspeer static void 13636495Sspeer vnet_handle_res_err(vio_net_handle_t vrh, vio_net_err_val_t err) 13646495Sspeer { 13656495Sspeer vnet_res_t *vresp = (vnet_res_t *)vrh; 13666495Sspeer vnet_t *vnetp = vresp->vnetp; 13676495Sspeer 13686495Sspeer if (vnetp == NULL) { 13696495Sspeer return; 13706495Sspeer } 13716495Sspeer if ((vresp->type != VIO_NET_RES_LDC_SERVICE) && 13726495Sspeer (vresp->type != VIO_NET_RES_HYBRID)) { 13736495Sspeer return; 13746495Sspeer } 13759647SWentao.Yang@Sun.COM 13769647SWentao.Yang@Sun.COM vdds_cleanup_hio(vnetp); 13776495Sspeer } 13786495Sspeer 13796495Sspeer /* 13806495Sspeer * vnet_dispatch_res_task -- A function to dispatch tasks start resources. 13816495Sspeer */ 13826495Sspeer static void 13836495Sspeer vnet_dispatch_res_task(vnet_t *vnetp) 13846495Sspeer { 13856495Sspeer int rv; 13866495Sspeer 1387*9677SZachary.Kissel@Sun.COM /* 1388*9677SZachary.Kissel@Sun.COM * Dispatch the task. It could be the case that vnetp->flags does 1389*9677SZachary.Kissel@Sun.COM * not have VNET_STARTED set. This is ok as vnet_rest_start_task() 1390*9677SZachary.Kissel@Sun.COM * can abort the task when the task is started. 1391*9677SZachary.Kissel@Sun.COM */ 1392*9677SZachary.Kissel@Sun.COM rv = ddi_taskq_dispatch(vnetp->taskqp, vnet_res_start_task, 1393*9677SZachary.Kissel@Sun.COM vnetp, DDI_NOSLEEP); 1394*9677SZachary.Kissel@Sun.COM if (rv != DDI_SUCCESS) { 1395*9677SZachary.Kissel@Sun.COM cmn_err(CE_WARN, 1396*9677SZachary.Kissel@Sun.COM "vnet%d:Can't dispatch start resource task", 1397*9677SZachary.Kissel@Sun.COM vnetp->instance); 13986495Sspeer } 13996495Sspeer } 14006495Sspeer 14016495Sspeer /* 14026495Sspeer * vnet_res_start_task -- A taskq callback function that starts a resource. 14036495Sspeer */ 14046495Sspeer static void 14056495Sspeer vnet_res_start_task(void *arg) 14062311Sseb { 14072311Sseb vnet_t *vnetp = arg; 14086495Sspeer 14096495Sspeer WRITE_ENTER(&vnetp->vrwlock); 14106495Sspeer if (vnetp->flags & VNET_STARTED) { 14116495Sspeer vnet_start_resources(vnetp); 14126495Sspeer } 14136495Sspeer RW_EXIT(&vnetp->vrwlock); 14142311Sseb } 14156495Sspeer 14166495Sspeer /* 14176495Sspeer * vnet_start_resources -- starts all resources associated with 14186495Sspeer * a vnet. 14196495Sspeer */ 14206495Sspeer static void 14216495Sspeer vnet_start_resources(vnet_t *vnetp) 14226495Sspeer { 14236495Sspeer mac_register_t *macp; 14246495Sspeer mac_callbacks_t *cbp; 14256495Sspeer vnet_res_t *vresp; 14266495Sspeer int rv; 14276495Sspeer 14286495Sspeer DBG1(vnetp, "enter\n"); 14296495Sspeer 14306495Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) { 14316495Sspeer /* skip if it is already started */ 14326495Sspeer if (vresp->flags & VNET_STARTED) { 14336495Sspeer continue; 14346495Sspeer } 14356495Sspeer macp = &vresp->macreg; 14366495Sspeer cbp = macp->m_callbacks; 14376495Sspeer rv = cbp->mc_start(macp->m_driver); 14386495Sspeer if (rv == 0) { 14396495Sspeer /* 14406495Sspeer * Successfully started the resource, so now 14416495Sspeer * add it to the fdb. 14426495Sspeer */ 14436495Sspeer vresp->flags |= VNET_STARTED; 14446495Sspeer vnet_fdbe_add(vnetp, vresp); 14456495Sspeer } 14466495Sspeer } 14476495Sspeer 14486495Sspeer DBG1(vnetp, "exit\n"); 14496495Sspeer 14506495Sspeer } 14516495Sspeer 14526495Sspeer /* 14536495Sspeer * vnet_stop_resources -- stop all resources associated with a vnet. 14546495Sspeer */ 14556495Sspeer static void 14566495Sspeer vnet_stop_resources(vnet_t *vnetp) 14576495Sspeer { 14586495Sspeer vnet_res_t *vresp; 14596495Sspeer vnet_res_t *nvresp; 14606495Sspeer mac_register_t *macp; 14616495Sspeer mac_callbacks_t *cbp; 14626495Sspeer 14636495Sspeer DBG1(vnetp, "enter\n"); 14646495Sspeer 14656495Sspeer for (vresp = vnetp->vres_list; vresp != NULL; ) { 14666495Sspeer nvresp = vresp->nextp; 14676495Sspeer if (vresp->flags & VNET_STARTED) { 14686495Sspeer macp = &vresp->macreg; 14696495Sspeer cbp = macp->m_callbacks; 14706495Sspeer cbp->mc_stop(macp->m_driver); 14716495Sspeer vresp->flags &= ~VNET_STARTED; 14726495Sspeer } 14736495Sspeer vresp = nvresp; 14746495Sspeer } 14756495Sspeer DBG1(vnetp, "exit\n"); 14766495Sspeer } 14778160SWentao.Yang@Sun.COM 14788160SWentao.Yang@Sun.COM /* 14798160SWentao.Yang@Sun.COM * Setup kstats for the HIO statistics. 14808160SWentao.Yang@Sun.COM * NOTE: the synchronization for the statistics is the 14818160SWentao.Yang@Sun.COM * responsibility of the caller. 14828160SWentao.Yang@Sun.COM */ 14838160SWentao.Yang@Sun.COM kstat_t * 14848160SWentao.Yang@Sun.COM vnet_hio_setup_kstats(char *ks_mod, char *ks_name, vnet_res_t *vresp) 14858160SWentao.Yang@Sun.COM { 14868160SWentao.Yang@Sun.COM kstat_t *ksp; 14878160SWentao.Yang@Sun.COM vnet_t *vnetp = vresp->vnetp; 14888160SWentao.Yang@Sun.COM vnet_hio_kstats_t *hiokp; 14898160SWentao.Yang@Sun.COM size_t size; 14908160SWentao.Yang@Sun.COM 14918160SWentao.Yang@Sun.COM ASSERT(vnetp != NULL); 14928160SWentao.Yang@Sun.COM size = sizeof (vnet_hio_kstats_t) / sizeof (kstat_named_t); 14938160SWentao.Yang@Sun.COM ksp = kstat_create(ks_mod, vnetp->instance, ks_name, "net", 14948160SWentao.Yang@Sun.COM KSTAT_TYPE_NAMED, size, 0); 14958160SWentao.Yang@Sun.COM if (ksp == NULL) { 14968160SWentao.Yang@Sun.COM return (NULL); 14978160SWentao.Yang@Sun.COM } 14988160SWentao.Yang@Sun.COM 14998160SWentao.Yang@Sun.COM hiokp = (vnet_hio_kstats_t *)ksp->ks_data; 15008160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->ipackets, "ipackets", 15018160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 15028160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->ierrors, "ierrors", 15038160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 15048160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->opackets, "opackets", 15058160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 15068160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->oerrors, "oerrors", 15078160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 15088160SWentao.Yang@Sun.COM 15098160SWentao.Yang@Sun.COM 15108160SWentao.Yang@Sun.COM /* MIB II kstat variables */ 15118160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->rbytes, "rbytes", 15128160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 15138160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->obytes, "obytes", 15148160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 15158160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->multircv, "multircv", 15168160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 15178160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->multixmt, "multixmt", 15188160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 15198160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->brdcstrcv, "brdcstrcv", 15208160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 15218160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->brdcstxmt, "brdcstxmt", 15228160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 15238160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->norcvbuf, "norcvbuf", 15248160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 15258160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->noxmtbuf, "noxmtbuf", 15268160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 15278160SWentao.Yang@Sun.COM 15288160SWentao.Yang@Sun.COM ksp->ks_update = vnet_hio_update_kstats; 15298160SWentao.Yang@Sun.COM ksp->ks_private = (void *)vresp; 15308160SWentao.Yang@Sun.COM kstat_install(ksp); 15318160SWentao.Yang@Sun.COM return (ksp); 15328160SWentao.Yang@Sun.COM } 15338160SWentao.Yang@Sun.COM 15348160SWentao.Yang@Sun.COM /* 15358160SWentao.Yang@Sun.COM * Destroy kstats. 15368160SWentao.Yang@Sun.COM */ 15378160SWentao.Yang@Sun.COM static void 15388160SWentao.Yang@Sun.COM vnet_hio_destroy_kstats(kstat_t *ksp) 15398160SWentao.Yang@Sun.COM { 15408160SWentao.Yang@Sun.COM if (ksp != NULL) 15418160SWentao.Yang@Sun.COM kstat_delete(ksp); 15428160SWentao.Yang@Sun.COM } 15438160SWentao.Yang@Sun.COM 15448160SWentao.Yang@Sun.COM /* 15458160SWentao.Yang@Sun.COM * Update the kstats. 15468160SWentao.Yang@Sun.COM */ 15478160SWentao.Yang@Sun.COM static int 15488160SWentao.Yang@Sun.COM vnet_hio_update_kstats(kstat_t *ksp, int rw) 15498160SWentao.Yang@Sun.COM { 15508160SWentao.Yang@Sun.COM vnet_t *vnetp; 15518160SWentao.Yang@Sun.COM vnet_res_t *vresp; 15528160SWentao.Yang@Sun.COM vnet_hio_stats_t statsp; 15538160SWentao.Yang@Sun.COM vnet_hio_kstats_t *hiokp; 15548160SWentao.Yang@Sun.COM 15558160SWentao.Yang@Sun.COM vresp = (vnet_res_t *)ksp->ks_private; 15568160SWentao.Yang@Sun.COM vnetp = vresp->vnetp; 15578160SWentao.Yang@Sun.COM 15588160SWentao.Yang@Sun.COM bzero(&statsp, sizeof (vnet_hio_stats_t)); 15598160SWentao.Yang@Sun.COM 15608160SWentao.Yang@Sun.COM READ_ENTER(&vnetp->vsw_fp_rw); 15618160SWentao.Yang@Sun.COM if (vnetp->hio_fp == NULL) { 15628160SWentao.Yang@Sun.COM /* not using hio resources, just return */ 15638160SWentao.Yang@Sun.COM RW_EXIT(&vnetp->vsw_fp_rw); 15648160SWentao.Yang@Sun.COM return (0); 15658160SWentao.Yang@Sun.COM } 15668160SWentao.Yang@Sun.COM VNET_FDBE_REFHOLD(vnetp->hio_fp); 15678160SWentao.Yang@Sun.COM RW_EXIT(&vnetp->vsw_fp_rw); 15688160SWentao.Yang@Sun.COM vnet_hio_get_stats(vnetp->hio_fp, &statsp); 15698160SWentao.Yang@Sun.COM VNET_FDBE_REFRELE(vnetp->hio_fp); 15708160SWentao.Yang@Sun.COM 15718160SWentao.Yang@Sun.COM hiokp = (vnet_hio_kstats_t *)ksp->ks_data; 15728160SWentao.Yang@Sun.COM 15738160SWentao.Yang@Sun.COM if (rw == KSTAT_READ) { 15748160SWentao.Yang@Sun.COM /* Link Input/Output stats */ 15758160SWentao.Yang@Sun.COM hiokp->ipackets.value.ul = (uint32_t)statsp.ipackets; 15768160SWentao.Yang@Sun.COM hiokp->ipackets64.value.ull = statsp.ipackets; 15778160SWentao.Yang@Sun.COM hiokp->ierrors.value.ul = statsp.ierrors; 15788160SWentao.Yang@Sun.COM hiokp->opackets.value.ul = (uint32_t)statsp.opackets; 15798160SWentao.Yang@Sun.COM hiokp->opackets64.value.ull = statsp.opackets; 15808160SWentao.Yang@Sun.COM hiokp->oerrors.value.ul = statsp.oerrors; 15818160SWentao.Yang@Sun.COM 15828160SWentao.Yang@Sun.COM /* MIB II kstat variables */ 15838160SWentao.Yang@Sun.COM hiokp->rbytes.value.ul = (uint32_t)statsp.rbytes; 15848160SWentao.Yang@Sun.COM hiokp->rbytes64.value.ull = statsp.rbytes; 15858160SWentao.Yang@Sun.COM hiokp->obytes.value.ul = (uint32_t)statsp.obytes; 15868160SWentao.Yang@Sun.COM hiokp->obytes64.value.ull = statsp.obytes; 15878160SWentao.Yang@Sun.COM hiokp->multircv.value.ul = statsp.multircv; 15888160SWentao.Yang@Sun.COM hiokp->multixmt.value.ul = statsp.multixmt; 15898160SWentao.Yang@Sun.COM hiokp->brdcstrcv.value.ul = statsp.brdcstrcv; 15908160SWentao.Yang@Sun.COM hiokp->brdcstxmt.value.ul = statsp.brdcstxmt; 15918160SWentao.Yang@Sun.COM hiokp->norcvbuf.value.ul = statsp.norcvbuf; 15928160SWentao.Yang@Sun.COM hiokp->noxmtbuf.value.ul = statsp.noxmtbuf; 15938160SWentao.Yang@Sun.COM } else { 15948160SWentao.Yang@Sun.COM return (EACCES); 15958160SWentao.Yang@Sun.COM } 15968160SWentao.Yang@Sun.COM 15978160SWentao.Yang@Sun.COM return (0); 15988160SWentao.Yang@Sun.COM } 15998160SWentao.Yang@Sun.COM 16008160SWentao.Yang@Sun.COM static void 16018160SWentao.Yang@Sun.COM vnet_hio_get_stats(vnet_res_t *vresp, vnet_hio_stats_t *statsp) 16028160SWentao.Yang@Sun.COM { 16038160SWentao.Yang@Sun.COM mac_register_t *macp; 16048160SWentao.Yang@Sun.COM mac_callbacks_t *cbp; 16058160SWentao.Yang@Sun.COM uint64_t val; 16068160SWentao.Yang@Sun.COM int stat; 16078160SWentao.Yang@Sun.COM 16088160SWentao.Yang@Sun.COM /* 16098160SWentao.Yang@Sun.COM * get the specified statistics from the underlying nxge. 16108160SWentao.Yang@Sun.COM */ 16118160SWentao.Yang@Sun.COM macp = &vresp->macreg; 16128160SWentao.Yang@Sun.COM cbp = macp->m_callbacks; 16138160SWentao.Yang@Sun.COM for (stat = MAC_STAT_MIN; stat < MAC_STAT_OVERFLOWS; stat++) { 16148160SWentao.Yang@Sun.COM if (cbp->mc_getstat(macp->m_driver, stat, &val) == 0) { 16158160SWentao.Yang@Sun.COM switch (stat) { 16168160SWentao.Yang@Sun.COM case MAC_STAT_IPACKETS: 16178160SWentao.Yang@Sun.COM statsp->ipackets = val; 16188160SWentao.Yang@Sun.COM break; 16198160SWentao.Yang@Sun.COM 16208160SWentao.Yang@Sun.COM case MAC_STAT_IERRORS: 16218160SWentao.Yang@Sun.COM statsp->ierrors = val; 16228160SWentao.Yang@Sun.COM break; 16238160SWentao.Yang@Sun.COM 16248160SWentao.Yang@Sun.COM case MAC_STAT_OPACKETS: 16258160SWentao.Yang@Sun.COM statsp->opackets = val; 16268160SWentao.Yang@Sun.COM break; 16278160SWentao.Yang@Sun.COM 16288160SWentao.Yang@Sun.COM case MAC_STAT_OERRORS: 16298160SWentao.Yang@Sun.COM statsp->oerrors = val; 16308160SWentao.Yang@Sun.COM break; 16318160SWentao.Yang@Sun.COM 16328160SWentao.Yang@Sun.COM case MAC_STAT_RBYTES: 16338160SWentao.Yang@Sun.COM statsp->rbytes = val; 16348160SWentao.Yang@Sun.COM break; 16358160SWentao.Yang@Sun.COM 16368160SWentao.Yang@Sun.COM case MAC_STAT_OBYTES: 16378160SWentao.Yang@Sun.COM statsp->obytes = val; 16388160SWentao.Yang@Sun.COM break; 16398160SWentao.Yang@Sun.COM 16408160SWentao.Yang@Sun.COM case MAC_STAT_MULTIRCV: 16418160SWentao.Yang@Sun.COM statsp->multircv = val; 16428160SWentao.Yang@Sun.COM break; 16438160SWentao.Yang@Sun.COM 16448160SWentao.Yang@Sun.COM case MAC_STAT_MULTIXMT: 16458160SWentao.Yang@Sun.COM statsp->multixmt = val; 16468160SWentao.Yang@Sun.COM break; 16478160SWentao.Yang@Sun.COM 16488160SWentao.Yang@Sun.COM case MAC_STAT_BRDCSTRCV: 16498160SWentao.Yang@Sun.COM statsp->brdcstrcv = val; 16508160SWentao.Yang@Sun.COM break; 16518160SWentao.Yang@Sun.COM 16528160SWentao.Yang@Sun.COM case MAC_STAT_BRDCSTXMT: 16538160SWentao.Yang@Sun.COM statsp->brdcstxmt = val; 16548160SWentao.Yang@Sun.COM break; 16558160SWentao.Yang@Sun.COM 16568160SWentao.Yang@Sun.COM case MAC_STAT_NOXMTBUF: 16578160SWentao.Yang@Sun.COM statsp->noxmtbuf = val; 16588160SWentao.Yang@Sun.COM break; 16598160SWentao.Yang@Sun.COM 16608160SWentao.Yang@Sun.COM case MAC_STAT_NORCVBUF: 16618160SWentao.Yang@Sun.COM statsp->norcvbuf = val; 16628160SWentao.Yang@Sun.COM break; 16638160SWentao.Yang@Sun.COM 16648160SWentao.Yang@Sun.COM default: 16658160SWentao.Yang@Sun.COM /* 16668160SWentao.Yang@Sun.COM * parameters not interested. 16678160SWentao.Yang@Sun.COM */ 16688160SWentao.Yang@Sun.COM break; 16698160SWentao.Yang@Sun.COM } 16708160SWentao.Yang@Sun.COM } 16718160SWentao.Yang@Sun.COM } 16728160SWentao.Yang@Sun.COM } 16739336SSriharsha.Basavapatna@Sun.COM 16749336SSriharsha.Basavapatna@Sun.COM #ifdef VNET_IOC_DEBUG 16759336SSriharsha.Basavapatna@Sun.COM 16769336SSriharsha.Basavapatna@Sun.COM /* 16779336SSriharsha.Basavapatna@Sun.COM * The ioctl entry point is used only for debugging for now. The ioctl commands 16789336SSriharsha.Basavapatna@Sun.COM * can be used to force the link state of the channel connected to vsw. 16799336SSriharsha.Basavapatna@Sun.COM */ 16809336SSriharsha.Basavapatna@Sun.COM static void 16819336SSriharsha.Basavapatna@Sun.COM vnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp) 16829336SSriharsha.Basavapatna@Sun.COM { 16839336SSriharsha.Basavapatna@Sun.COM struct iocblk *iocp; 16849336SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp; 16859336SSriharsha.Basavapatna@Sun.COM 16869336SSriharsha.Basavapatna@Sun.COM iocp = (struct iocblk *)(uintptr_t)mp->b_rptr; 16879336SSriharsha.Basavapatna@Sun.COM iocp->ioc_error = 0; 16889336SSriharsha.Basavapatna@Sun.COM vnetp = (vnet_t *)arg; 16899336SSriharsha.Basavapatna@Sun.COM 16909336SSriharsha.Basavapatna@Sun.COM if (vnetp == NULL) { 16919336SSriharsha.Basavapatna@Sun.COM miocnak(q, mp, 0, EINVAL); 16929336SSriharsha.Basavapatna@Sun.COM return; 16939336SSriharsha.Basavapatna@Sun.COM } 16949336SSriharsha.Basavapatna@Sun.COM 16959336SSriharsha.Basavapatna@Sun.COM switch (iocp->ioc_cmd) { 16969336SSriharsha.Basavapatna@Sun.COM 16979336SSriharsha.Basavapatna@Sun.COM case VNET_FORCE_LINK_DOWN: 16989336SSriharsha.Basavapatna@Sun.COM case VNET_FORCE_LINK_UP: 16999336SSriharsha.Basavapatna@Sun.COM vnet_force_link_state(vnetp, q, mp); 17009336SSriharsha.Basavapatna@Sun.COM break; 17019336SSriharsha.Basavapatna@Sun.COM 17029336SSriharsha.Basavapatna@Sun.COM default: 17039336SSriharsha.Basavapatna@Sun.COM iocp->ioc_error = EINVAL; 17049336SSriharsha.Basavapatna@Sun.COM miocnak(q, mp, 0, iocp->ioc_error); 17059336SSriharsha.Basavapatna@Sun.COM break; 17069336SSriharsha.Basavapatna@Sun.COM 17079336SSriharsha.Basavapatna@Sun.COM } 17089336SSriharsha.Basavapatna@Sun.COM } 17099336SSriharsha.Basavapatna@Sun.COM 17109336SSriharsha.Basavapatna@Sun.COM static void 17119336SSriharsha.Basavapatna@Sun.COM vnet_force_link_state(vnet_t *vnetp, queue_t *q, mblk_t *mp) 17129336SSriharsha.Basavapatna@Sun.COM { 17139336SSriharsha.Basavapatna@Sun.COM mac_register_t *macp; 17149336SSriharsha.Basavapatna@Sun.COM mac_callbacks_t *cbp; 17159336SSriharsha.Basavapatna@Sun.COM vnet_res_t *vresp; 17169336SSriharsha.Basavapatna@Sun.COM 17179336SSriharsha.Basavapatna@Sun.COM READ_ENTER(&vnetp->vsw_fp_rw); 17189336SSriharsha.Basavapatna@Sun.COM 17199336SSriharsha.Basavapatna@Sun.COM vresp = vnetp->vsw_fp; 17209336SSriharsha.Basavapatna@Sun.COM if (vresp == NULL) { 17219336SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vsw_fp_rw); 17229336SSriharsha.Basavapatna@Sun.COM return; 17239336SSriharsha.Basavapatna@Sun.COM } 17249336SSriharsha.Basavapatna@Sun.COM 17259336SSriharsha.Basavapatna@Sun.COM macp = &vresp->macreg; 17269336SSriharsha.Basavapatna@Sun.COM cbp = macp->m_callbacks; 17279336SSriharsha.Basavapatna@Sun.COM cbp->mc_ioctl(macp->m_driver, q, mp); 17289336SSriharsha.Basavapatna@Sun.COM 17299336SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vsw_fp_rw); 17309336SSriharsha.Basavapatna@Sun.COM } 17319336SSriharsha.Basavapatna@Sun.COM 17329336SSriharsha.Basavapatna@Sun.COM #else 17339336SSriharsha.Basavapatna@Sun.COM 17349336SSriharsha.Basavapatna@Sun.COM static void 17359336SSriharsha.Basavapatna@Sun.COM vnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp) 17369336SSriharsha.Basavapatna@Sun.COM { 17379336SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp; 17389336SSriharsha.Basavapatna@Sun.COM 17399336SSriharsha.Basavapatna@Sun.COM vnetp = (vnet_t *)arg; 17409336SSriharsha.Basavapatna@Sun.COM 17419336SSriharsha.Basavapatna@Sun.COM if (vnetp == NULL) { 17429336SSriharsha.Basavapatna@Sun.COM miocnak(q, mp, 0, EINVAL); 17439336SSriharsha.Basavapatna@Sun.COM return; 17449336SSriharsha.Basavapatna@Sun.COM } 17459336SSriharsha.Basavapatna@Sun.COM 17469336SSriharsha.Basavapatna@Sun.COM /* ioctl support only for debugging */ 17479336SSriharsha.Basavapatna@Sun.COM miocnak(q, mp, 0, ENOTSUP); 17489336SSriharsha.Basavapatna@Sun.COM } 17499336SSriharsha.Basavapatna@Sun.COM 17509336SSriharsha.Basavapatna@Sun.COM #endif 1751