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 /* 236419Ssb155480 * Copyright 2008 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> 421991Sheppo #include <sys/mac.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 *); 741991Sheppo 751991Sheppo /* vnet internal functions */ 761991Sheppo static int vnet_mac_register(vnet_t *); 771991Sheppo static int vnet_read_mac_address(vnet_t *vnetp); 781991Sheppo 796419Ssb155480 /* Forwarding database (FDB) routines */ 806419Ssb155480 static void vnet_fdb_create(vnet_t *vnetp); 816419Ssb155480 static void vnet_fdb_destroy(vnet_t *vnetp); 826495Sspeer static vnet_res_t *vnet_fdbe_find(vnet_t *vnetp, struct ether_addr *addrp); 836419Ssb155480 static void vnet_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val); 846495Sspeer void vnet_fdbe_add(vnet_t *vnetp, vnet_res_t *vresp); 856495Sspeer static void vnet_fdbe_del(vnet_t *vnetp, vnet_res_t *vresp); 866495Sspeer 876495Sspeer static void vnet_rx(vio_net_handle_t vrh, mblk_t *mp); 886495Sspeer static void vnet_tx_update(vio_net_handle_t vrh); 896495Sspeer static void vnet_res_start_task(void *arg); 906495Sspeer static void vnet_start_resources(vnet_t *vnetp); 916495Sspeer static void vnet_stop_resources(vnet_t *vnetp); 926495Sspeer static void vnet_dispatch_res_task(vnet_t *vnetp); 936495Sspeer static void vnet_res_start_task(void *arg); 946495Sspeer static void vnet_handle_res_err(vio_net_handle_t vrh, vio_net_err_val_t err); 957529SSriharsha.Basavapatna@Sun.COM int vnet_mtu_update(vnet_t *vnetp, uint32_t mtu); 966419Ssb155480 976495Sspeer /* Exported to to vnet_dds */ 986495Sspeer int vnet_send_dds_msg(vnet_t *vnetp, void *dmsg); 991991Sheppo 1006495Sspeer /* Externs that are imported from vnet_gen */ 1016495Sspeer extern int vgen_init(void *vnetp, uint64_t regprop, dev_info_t *vnetdip, 1026495Sspeer const uint8_t *macaddr, void **vgenhdl); 1032336Snarayan extern int vgen_uninit(void *arg); 1046495Sspeer extern int vgen_dds_tx(void *arg, void *dmsg); 1056495Sspeer 1066495Sspeer /* Externs that are imported from vnet_dds */ 1076495Sspeer extern void vdds_mod_init(void); 1086495Sspeer extern void vdds_mod_fini(void); 1096495Sspeer extern int vdds_init(vnet_t *vnetp); 1106495Sspeer extern void vdds_cleanup(vnet_t *vnetp); 1116495Sspeer extern void vdds_process_dds_msg(vnet_t *vnetp, vio_dds_msg_t *dmsg); 112*7819SRaghuram.Kothakota@Sun.COM extern void vdds_cleanup_hybrid_res(void *arg); 1131991Sheppo 1146419Ssb155480 #define VNET_FDBE_REFHOLD(p) \ 1156419Ssb155480 { \ 1166419Ssb155480 atomic_inc_32(&(p)->refcnt); \ 1176419Ssb155480 ASSERT((p)->refcnt != 0); \ 1186419Ssb155480 } 1196419Ssb155480 1206419Ssb155480 #define VNET_FDBE_REFRELE(p) \ 1216419Ssb155480 { \ 1226419Ssb155480 ASSERT((p)->refcnt != 0); \ 1236419Ssb155480 atomic_dec_32(&(p)->refcnt); \ 1246419Ssb155480 } 1256419Ssb155480 1262311Sseb static mac_callbacks_t vnet_m_callbacks = { 1272311Sseb 0, 1282311Sseb vnet_m_stat, 1292311Sseb vnet_m_start, 1302311Sseb vnet_m_stop, 1312311Sseb vnet_m_promisc, 1322311Sseb vnet_m_multicst, 1332311Sseb vnet_m_unicst, 1342311Sseb vnet_m_tx, 1352311Sseb NULL, 1362311Sseb NULL, 1372311Sseb NULL 1382311Sseb }; 1392311Sseb 1401991Sheppo /* 1411991Sheppo * Linked list of "vnet_t" structures - one per instance. 1421991Sheppo */ 1431991Sheppo static vnet_t *vnet_headp = NULL; 1441991Sheppo static krwlock_t vnet_rw; 1451991Sheppo 1461991Sheppo /* Tunables */ 1471991Sheppo uint32_t vnet_ntxds = VNET_NTXDS; /* power of 2 transmit descriptors */ 1481991Sheppo uint32_t vnet_ldcwd_interval = VNET_LDCWD_INTERVAL; /* watchdog freq in msec */ 1491991Sheppo uint32_t vnet_ldcwd_txtimeout = VNET_LDCWD_TXTIMEOUT; /* tx timeout in msec */ 1502410Slm66018 uint32_t vnet_ldc_mtu = VNET_LDC_MTU; /* ldc mtu */ 1516419Ssb155480 1527529SSriharsha.Basavapatna@Sun.COM /* 1537529SSriharsha.Basavapatna@Sun.COM * Set this to non-zero to enable additional internal receive buffer pools 1547529SSriharsha.Basavapatna@Sun.COM * based on the MTU of the device for better performance at the cost of more 1557529SSriharsha.Basavapatna@Sun.COM * memory consumption. This is turned off by default, to use allocb(9F) for 1567529SSriharsha.Basavapatna@Sun.COM * receive buffer allocations of sizes > 2K. 1577529SSriharsha.Basavapatna@Sun.COM */ 1587529SSriharsha.Basavapatna@Sun.COM boolean_t vnet_jumbo_rxpools = B_FALSE; 1597529SSriharsha.Basavapatna@Sun.COM 1606419Ssb155480 /* # of chains in fdb hash table */ 1616419Ssb155480 uint32_t vnet_fdb_nchains = VNET_NFDB_HASH; 1626419Ssb155480 1636419Ssb155480 /* Internal tunables */ 1646419Ssb155480 uint32_t vnet_ethermtu = 1500; /* mtu of the device */ 1656419Ssb155480 1666419Ssb155480 /* 1676419Ssb155480 * Default vlan id. This is only used internally when the "default-vlan-id" 1686419Ssb155480 * property is not present in the MD device node. Therefore, this should not be 1696419Ssb155480 * used as a tunable; if this value is changed, the corresponding variable 1706419Ssb155480 * should be updated to the same value in vsw and also other vnets connected to 1716419Ssb155480 * the same vsw. 1726419Ssb155480 */ 1736419Ssb155480 uint16_t vnet_default_vlan_id = 1; 1746419Ssb155480 1756419Ssb155480 /* delay in usec to wait for all references on a fdb entry to be dropped */ 1766419Ssb155480 uint32_t vnet_fdbe_refcnt_delay = 10; 1771991Sheppo 1786495Sspeer static struct ether_addr etherbroadcastaddr = { 1796495Sspeer 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 1806495Sspeer }; 1816495Sspeer 1826495Sspeer 1831991Sheppo /* 1841991Sheppo * Property names 1851991Sheppo */ 1861991Sheppo static char macaddr_propname[] = "local-mac-address"; 1871991Sheppo 1881991Sheppo /* 1891991Sheppo * This is the string displayed by modinfo(1m). 1901991Sheppo */ 1917529SSriharsha.Basavapatna@Sun.COM static char vnet_ident[] = "vnet driver"; 1921991Sheppo extern struct mod_ops mod_driverops; 1931991Sheppo static struct cb_ops cb_vnetops = { 1941991Sheppo nulldev, /* cb_open */ 1951991Sheppo nulldev, /* cb_close */ 1961991Sheppo nodev, /* cb_strategy */ 1971991Sheppo nodev, /* cb_print */ 1981991Sheppo nodev, /* cb_dump */ 1991991Sheppo nodev, /* cb_read */ 2001991Sheppo nodev, /* cb_write */ 2011991Sheppo nodev, /* cb_ioctl */ 2021991Sheppo nodev, /* cb_devmap */ 2031991Sheppo nodev, /* cb_mmap */ 2041991Sheppo nodev, /* cb_segmap */ 2051991Sheppo nochpoll, /* cb_chpoll */ 2061991Sheppo ddi_prop_op, /* cb_prop_op */ 2071991Sheppo NULL, /* cb_stream */ 2081991Sheppo (int)(D_MP) /* cb_flag */ 2091991Sheppo }; 2101991Sheppo 2111991Sheppo static struct dev_ops vnetops = { 2121991Sheppo DEVO_REV, /* devo_rev */ 2131991Sheppo 0, /* devo_refcnt */ 2141991Sheppo NULL, /* devo_getinfo */ 2151991Sheppo nulldev, /* devo_identify */ 2161991Sheppo nulldev, /* devo_probe */ 2171991Sheppo vnetattach, /* devo_attach */ 2181991Sheppo vnetdetach, /* devo_detach */ 2191991Sheppo nodev, /* devo_reset */ 2201991Sheppo &cb_vnetops, /* devo_cb_ops */ 2217656SSherry.Moore@Sun.COM (struct bus_ops *)NULL, /* devo_bus_ops */ 2227656SSherry.Moore@Sun.COM NULL, /* devo_power */ 2237656SSherry.Moore@Sun.COM ddi_quiesce_not_supported, /* devo_quiesce */ 2241991Sheppo }; 2251991Sheppo 2261991Sheppo static struct modldrv modldrv = { 2271991Sheppo &mod_driverops, /* Type of module. This one is a driver */ 2281991Sheppo vnet_ident, /* ID string */ 2291991Sheppo &vnetops /* driver specific ops */ 2301991Sheppo }; 2311991Sheppo 2321991Sheppo static struct modlinkage modlinkage = { 2331991Sheppo MODREV_1, (void *)&modldrv, NULL 2341991Sheppo }; 2351991Sheppo 2364647Sraghuram #ifdef DEBUG 2371991Sheppo 2381991Sheppo /* 2391991Sheppo * Print debug messages - set to 0xf to enable all msgs 2401991Sheppo */ 2414647Sraghuram int vnet_dbglevel = 0x8; 2421991Sheppo 2434647Sraghuram static void 2444647Sraghuram debug_printf(const char *fname, void *arg, const char *fmt, ...) 2451991Sheppo { 2461991Sheppo char buf[512]; 2471991Sheppo va_list ap; 2481991Sheppo vnet_t *vnetp = (vnet_t *)arg; 2494647Sraghuram char *bufp = buf; 2501991Sheppo 2514647Sraghuram if (vnetp == NULL) { 2524647Sraghuram (void) sprintf(bufp, "%s: ", fname); 2534647Sraghuram bufp += strlen(bufp); 2544647Sraghuram } else { 2554647Sraghuram (void) sprintf(bufp, "vnet%d:%s: ", vnetp->instance, fname); 2564647Sraghuram bufp += strlen(bufp); 2574647Sraghuram } 2584647Sraghuram va_start(ap, fmt); 2594647Sraghuram (void) vsprintf(bufp, fmt, ap); 2604647Sraghuram va_end(ap); 2614647Sraghuram cmn_err(CE_CONT, "%s\n", buf); 2624647Sraghuram } 2631991Sheppo 2641991Sheppo #endif 2651991Sheppo 2661991Sheppo /* _init(9E): initialize the loadable module */ 2671991Sheppo int 2681991Sheppo _init(void) 2691991Sheppo { 2701991Sheppo int status; 2711991Sheppo 2724647Sraghuram DBG1(NULL, "enter\n"); 2731991Sheppo 2741991Sheppo mac_init_ops(&vnetops, "vnet"); 2751991Sheppo status = mod_install(&modlinkage); 2761991Sheppo if (status != 0) { 2771991Sheppo mac_fini_ops(&vnetops); 2781991Sheppo } 2796495Sspeer vdds_mod_init(); 2804647Sraghuram DBG1(NULL, "exit(%d)\n", status); 2811991Sheppo return (status); 2821991Sheppo } 2831991Sheppo 2841991Sheppo /* _fini(9E): prepare the module for unloading. */ 2851991Sheppo int 2861991Sheppo _fini(void) 2871991Sheppo { 2881991Sheppo int status; 2891991Sheppo 2904647Sraghuram DBG1(NULL, "enter\n"); 2911991Sheppo 2921991Sheppo status = mod_remove(&modlinkage); 2931991Sheppo if (status != 0) 2941991Sheppo return (status); 2951991Sheppo mac_fini_ops(&vnetops); 2966495Sspeer vdds_mod_fini(); 2971991Sheppo 2984647Sraghuram DBG1(NULL, "exit(%d)\n", status); 2991991Sheppo return (status); 3001991Sheppo } 3011991Sheppo 3021991Sheppo /* _info(9E): return information about the loadable module */ 3031991Sheppo int 3041991Sheppo _info(struct modinfo *modinfop) 3051991Sheppo { 3061991Sheppo return (mod_info(&modlinkage, modinfop)); 3071991Sheppo } 3081991Sheppo 3091991Sheppo /* 3101991Sheppo * attach(9E): attach a device to the system. 3111991Sheppo * called once for each instance of the device on the system. 3121991Sheppo */ 3131991Sheppo static int 3141991Sheppo vnetattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 3151991Sheppo { 3161991Sheppo vnet_t *vnetp; 3176495Sspeer int status; 3181991Sheppo int instance; 3196495Sspeer uint64_t reg; 3206495Sspeer char qname[TASKQ_NAMELEN]; 3214647Sraghuram enum { AST_init = 0x0, AST_vnet_alloc = 0x1, 3224647Sraghuram AST_mac_alloc = 0x2, AST_read_macaddr = 0x4, 3236495Sspeer AST_vgen_init = 0x8, AST_fdbh_alloc = 0x10, 3246495Sspeer AST_vdds_init = 0x20, AST_taskq_create = 0x40, 3256495Sspeer AST_vnet_list = 0x80 } attach_state; 3261991Sheppo 3271991Sheppo attach_state = AST_init; 3281991Sheppo 3291991Sheppo switch (cmd) { 3301991Sheppo case DDI_ATTACH: 3311991Sheppo break; 3321991Sheppo case DDI_RESUME: 3331991Sheppo case DDI_PM_RESUME: 3341991Sheppo default: 3351991Sheppo goto vnet_attach_fail; 3361991Sheppo } 3371991Sheppo 3381991Sheppo instance = ddi_get_instance(dip); 3394647Sraghuram DBG1(NULL, "instance(%d) enter\n", instance); 3401991Sheppo 3411991Sheppo /* allocate vnet_t and mac_t structures */ 3421991Sheppo vnetp = kmem_zalloc(sizeof (vnet_t), KM_SLEEP); 3436495Sspeer vnetp->dip = dip; 3446495Sspeer vnetp->instance = instance; 3456495Sspeer rw_init(&vnetp->vrwlock, NULL, RW_DRIVER, NULL); 3466495Sspeer rw_init(&vnetp->vsw_fp_rw, NULL, RW_DRIVER, NULL); 3471991Sheppo attach_state |= AST_vnet_alloc; 3481991Sheppo 3496495Sspeer status = vdds_init(vnetp); 3506495Sspeer if (status != 0) { 3516495Sspeer goto vnet_attach_fail; 3526495Sspeer } 3536495Sspeer attach_state |= AST_vdds_init; 3546495Sspeer 3551991Sheppo /* setup links to vnet_t from both devinfo and mac_t */ 3561991Sheppo ddi_set_driver_private(dip, (caddr_t)vnetp); 3571991Sheppo 3581991Sheppo /* read the mac address */ 3591991Sheppo status = vnet_read_mac_address(vnetp); 3601991Sheppo if (status != DDI_SUCCESS) { 3611991Sheppo goto vnet_attach_fail; 3621991Sheppo } 3631991Sheppo attach_state |= AST_read_macaddr; 3641991Sheppo 3656495Sspeer reg = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 3666495Sspeer DDI_PROP_DONTPASS, "reg", -1); 3676495Sspeer if (reg == -1) { 3686495Sspeer goto vnet_attach_fail; 3696495Sspeer } 3706495Sspeer vnetp->reg = reg; 3716495Sspeer 3726495Sspeer vnet_fdb_create(vnetp); 3736495Sspeer attach_state |= AST_fdbh_alloc; 3746495Sspeer 3756495Sspeer (void) snprintf(qname, TASKQ_NAMELEN, "vnet_taskq%d", instance); 3766495Sspeer if ((vnetp->taskqp = ddi_taskq_create(dip, qname, 1, 3776495Sspeer TASKQ_DEFAULTPRI, 0)) == NULL) { 3786495Sspeer cmn_err(CE_WARN, "!vnet%d: Unable to create task queue", 3796495Sspeer instance); 3806495Sspeer goto vnet_attach_fail; 3816495Sspeer } 3826495Sspeer attach_state |= AST_taskq_create; 3836495Sspeer 3846495Sspeer /* add to the list of vnet devices */ 3856495Sspeer WRITE_ENTER(&vnet_rw); 3866495Sspeer vnetp->nextp = vnet_headp; 3876495Sspeer vnet_headp = vnetp; 3886495Sspeer RW_EXIT(&vnet_rw); 3896495Sspeer 3906495Sspeer attach_state |= AST_vnet_list; 3916495Sspeer 3921991Sheppo /* 3936495Sspeer * Initialize the generic vnet plugin which provides 3946495Sspeer * communication via sun4v LDC (logical domain channel) based 3956495Sspeer * resources. It will register the LDC resources as and when 3966495Sspeer * they become available. 3971991Sheppo */ 3986495Sspeer status = vgen_init(vnetp, reg, vnetp->dip, 3996495Sspeer (uint8_t *)vnetp->curr_macaddr, &vnetp->vgenhdl); 4001991Sheppo if (status != DDI_SUCCESS) { 4014647Sraghuram DERR(vnetp, "vgen_init() failed\n"); 4021991Sheppo goto vnet_attach_fail; 4031991Sheppo } 4041991Sheppo attach_state |= AST_vgen_init; 4051991Sheppo 4061991Sheppo /* register with MAC layer */ 4071991Sheppo status = vnet_mac_register(vnetp); 4081991Sheppo if (status != DDI_SUCCESS) { 4091991Sheppo goto vnet_attach_fail; 4101991Sheppo } 4111991Sheppo 4124647Sraghuram DBG1(NULL, "instance(%d) exit\n", instance); 4131991Sheppo return (DDI_SUCCESS); 4141991Sheppo 4151991Sheppo vnet_attach_fail: 4166495Sspeer 4176495Sspeer if (attach_state & AST_vnet_list) { 4186495Sspeer vnet_t **vnetpp; 4196495Sspeer /* unlink from instance(vnet_t) list */ 4206495Sspeer WRITE_ENTER(&vnet_rw); 4216495Sspeer for (vnetpp = &vnet_headp; *vnetpp; 4226495Sspeer vnetpp = &(*vnetpp)->nextp) { 4236495Sspeer if (*vnetpp == vnetp) { 4246495Sspeer *vnetpp = vnetp->nextp; 4256495Sspeer break; 4266495Sspeer } 4276495Sspeer } 4286495Sspeer RW_EXIT(&vnet_rw); 4296495Sspeer } 4306495Sspeer 4316495Sspeer if (attach_state & AST_vdds_init) { 4326495Sspeer vdds_cleanup(vnetp); 4336495Sspeer } 4346495Sspeer if (attach_state & AST_taskq_create) { 4356495Sspeer ddi_taskq_destroy(vnetp->taskqp); 4366495Sspeer } 4371991Sheppo if (attach_state & AST_fdbh_alloc) { 4386419Ssb155480 vnet_fdb_destroy(vnetp); 4391991Sheppo } 4401991Sheppo if (attach_state & AST_vgen_init) { 4416495Sspeer (void) vgen_uninit(vnetp->vgenhdl); 4421991Sheppo } 4431991Sheppo if (attach_state & AST_vnet_alloc) { 4446495Sspeer rw_destroy(&vnetp->vrwlock); 4456495Sspeer rw_destroy(&vnetp->vsw_fp_rw); 4461991Sheppo KMEM_FREE(vnetp); 4471991Sheppo } 4481991Sheppo return (DDI_FAILURE); 4491991Sheppo } 4501991Sheppo 4511991Sheppo /* 4521991Sheppo * detach(9E): detach a device from the system. 4531991Sheppo */ 4541991Sheppo static int 4551991Sheppo vnetdetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4561991Sheppo { 4571991Sheppo vnet_t *vnetp; 4581991Sheppo vnet_t **vnetpp; 4591991Sheppo int instance; 4602336Snarayan int rv; 4611991Sheppo 4621991Sheppo instance = ddi_get_instance(dip); 4634647Sraghuram DBG1(NULL, "instance(%d) enter\n", instance); 4641991Sheppo 4651991Sheppo vnetp = ddi_get_driver_private(dip); 4661991Sheppo if (vnetp == NULL) { 4671991Sheppo goto vnet_detach_fail; 4681991Sheppo } 4691991Sheppo 4701991Sheppo switch (cmd) { 4711991Sheppo case DDI_DETACH: 4721991Sheppo break; 4731991Sheppo case DDI_SUSPEND: 4741991Sheppo case DDI_PM_SUSPEND: 4751991Sheppo default: 4761991Sheppo goto vnet_detach_fail; 4771991Sheppo } 4781991Sheppo 4796495Sspeer (void) vdds_cleanup(vnetp); 4806495Sspeer rv = vgen_uninit(vnetp->vgenhdl); 4816495Sspeer if (rv != DDI_SUCCESS) { 4826495Sspeer goto vnet_detach_fail; 4832336Snarayan } 4842336Snarayan 4851991Sheppo /* 4861991Sheppo * Unregister from the MAC subsystem. This can fail, in 4871991Sheppo * particular if there are DLPI style-2 streams still open - 4881991Sheppo * in which case we just return failure. 4891991Sheppo */ 4902311Sseb if (mac_unregister(vnetp->mh) != 0) 4911991Sheppo goto vnet_detach_fail; 4921991Sheppo 4931991Sheppo /* unlink from instance(vnet_t) list */ 4941991Sheppo WRITE_ENTER(&vnet_rw); 4951991Sheppo for (vnetpp = &vnet_headp; *vnetpp; vnetpp = &(*vnetpp)->nextp) { 4961991Sheppo if (*vnetpp == vnetp) { 4971991Sheppo *vnetpp = vnetp->nextp; 4981991Sheppo break; 4991991Sheppo } 5001991Sheppo } 5011991Sheppo RW_EXIT(&vnet_rw); 5021991Sheppo 5036495Sspeer ddi_taskq_destroy(vnetp->taskqp); 5046419Ssb155480 /* destroy fdb */ 5056419Ssb155480 vnet_fdb_destroy(vnetp); 5063297Ssb155480 5076495Sspeer rw_destroy(&vnetp->vrwlock); 5086495Sspeer rw_destroy(&vnetp->vsw_fp_rw); 5091991Sheppo KMEM_FREE(vnetp); 5101991Sheppo 5111991Sheppo return (DDI_SUCCESS); 5121991Sheppo 5131991Sheppo vnet_detach_fail: 5141991Sheppo return (DDI_FAILURE); 5151991Sheppo } 5161991Sheppo 5171991Sheppo /* enable the device for transmit/receive */ 5181991Sheppo static int 5191991Sheppo vnet_m_start(void *arg) 5201991Sheppo { 5211991Sheppo vnet_t *vnetp = arg; 5221991Sheppo 5234647Sraghuram DBG1(vnetp, "enter\n"); 5241991Sheppo 5256495Sspeer WRITE_ENTER(&vnetp->vrwlock); 5266495Sspeer vnetp->flags |= VNET_STARTED; 5276495Sspeer vnet_start_resources(vnetp); 5286495Sspeer RW_EXIT(&vnetp->vrwlock); 5291991Sheppo 5304647Sraghuram DBG1(vnetp, "exit\n"); 5311991Sheppo return (VNET_SUCCESS); 5321991Sheppo 5331991Sheppo } 5341991Sheppo 5351991Sheppo /* stop transmit/receive for the device */ 5361991Sheppo static void 5371991Sheppo vnet_m_stop(void *arg) 5381991Sheppo { 5391991Sheppo vnet_t *vnetp = arg; 5401991Sheppo 5414647Sraghuram DBG1(vnetp, "enter\n"); 5421991Sheppo 5436495Sspeer WRITE_ENTER(&vnetp->vrwlock); 5446495Sspeer if (vnetp->flags & VNET_STARTED) { 5456495Sspeer vnet_stop_resources(vnetp); 5466495Sspeer vnetp->flags &= ~VNET_STARTED; 5471991Sheppo } 5486495Sspeer RW_EXIT(&vnetp->vrwlock); 5491991Sheppo 5504647Sraghuram DBG1(vnetp, "exit\n"); 5511991Sheppo } 5521991Sheppo 5531991Sheppo /* set the unicast mac address of the device */ 5541991Sheppo static int 5551991Sheppo vnet_m_unicst(void *arg, const uint8_t *macaddr) 5561991Sheppo { 5571991Sheppo _NOTE(ARGUNUSED(macaddr)) 5581991Sheppo 5591991Sheppo vnet_t *vnetp = arg; 5601991Sheppo 5614647Sraghuram DBG1(vnetp, "enter\n"); 5621991Sheppo /* 5632793Slm66018 * NOTE: setting mac address dynamically is not supported. 5641991Sheppo */ 5654647Sraghuram DBG1(vnetp, "exit\n"); 5661991Sheppo 5672109Slm66018 return (VNET_FAILURE); 5681991Sheppo } 5691991Sheppo 5701991Sheppo /* enable/disable a multicast address */ 5711991Sheppo static int 5721991Sheppo vnet_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 5731991Sheppo { 5741991Sheppo _NOTE(ARGUNUSED(add, mca)) 5751991Sheppo 5761991Sheppo vnet_t *vnetp = arg; 5776495Sspeer vnet_res_t *vresp; 5786495Sspeer mac_register_t *macp; 5792311Sseb mac_callbacks_t *cbp; 5801991Sheppo int rv = VNET_SUCCESS; 5811991Sheppo 5824647Sraghuram DBG1(vnetp, "enter\n"); 5836495Sspeer 5846495Sspeer READ_ENTER(&vnetp->vrwlock); 5856495Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) { 5866495Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) { 5876495Sspeer macp = &vresp->macreg; 5886495Sspeer cbp = macp->m_callbacks; 5896495Sspeer rv = cbp->mc_multicst(macp->m_driver, add, mca); 5901991Sheppo } 5911991Sheppo } 5926495Sspeer RW_EXIT(&vnetp->vrwlock); 5936495Sspeer 5944647Sraghuram DBG1(vnetp, "exit(%d)\n", rv); 5951991Sheppo return (rv); 5961991Sheppo } 5971991Sheppo 5981991Sheppo /* set or clear promiscuous mode on the device */ 5991991Sheppo static int 6001991Sheppo vnet_m_promisc(void *arg, boolean_t on) 6011991Sheppo { 6021991Sheppo _NOTE(ARGUNUSED(on)) 6031991Sheppo 6041991Sheppo vnet_t *vnetp = arg; 6054647Sraghuram DBG1(vnetp, "enter\n"); 6061991Sheppo /* 6072793Slm66018 * NOTE: setting promiscuous mode is not supported, just return success. 6081991Sheppo */ 6094647Sraghuram DBG1(vnetp, "exit\n"); 6101991Sheppo return (VNET_SUCCESS); 6111991Sheppo } 6121991Sheppo 6131991Sheppo /* 6141991Sheppo * Transmit a chain of packets. This function provides switching functionality 6151991Sheppo * based on the destination mac address to reach other guests (within ldoms) or 6161991Sheppo * external hosts. 6171991Sheppo */ 6181991Sheppo mblk_t * 6191991Sheppo vnet_m_tx(void *arg, mblk_t *mp) 6201991Sheppo { 6216419Ssb155480 vnet_t *vnetp; 6226495Sspeer vnet_res_t *vresp; 6236419Ssb155480 mblk_t *next; 6246495Sspeer mblk_t *resid_mp; 6256495Sspeer mac_register_t *macp; 6266495Sspeer struct ether_header *ehp; 6276495Sspeer boolean_t is_unicast; 6281991Sheppo 6291991Sheppo vnetp = (vnet_t *)arg; 6304647Sraghuram DBG1(vnetp, "enter\n"); 6311991Sheppo ASSERT(mp != NULL); 6321991Sheppo 6331991Sheppo while (mp != NULL) { 6346419Ssb155480 6351991Sheppo next = mp->b_next; 6361991Sheppo mp->b_next = NULL; 6371991Sheppo 6386419Ssb155480 /* 6396419Ssb155480 * Find fdb entry for the destination 6406419Ssb155480 * and hold a reference to it. 6416419Ssb155480 */ 6421991Sheppo ehp = (struct ether_header *)mp->b_rptr; 6436495Sspeer vresp = vnet_fdbe_find(vnetp, &ehp->ether_dhost); 6446495Sspeer if (vresp != NULL) { 6451991Sheppo 6461991Sheppo /* 6476419Ssb155480 * Destination found in FDB. 6486419Ssb155480 * The destination is a vnet device within ldoms 6496419Ssb155480 * and directly reachable, invoke the tx function 6506419Ssb155480 * in the fdb entry. 6511991Sheppo */ 6526495Sspeer macp = &vresp->macreg; 6536495Sspeer resid_mp = macp->m_callbacks->mc_tx(macp->m_driver, mp); 6546419Ssb155480 6556419Ssb155480 /* tx done; now release ref on fdb entry */ 6566495Sspeer VNET_FDBE_REFRELE(vresp); 6576419Ssb155480 6581991Sheppo if (resid_mp != NULL) { 6591991Sheppo /* m_tx failed */ 6601991Sheppo mp->b_next = next; 6611991Sheppo break; 6621991Sheppo } 6631991Sheppo } else { 6646495Sspeer is_unicast = !(IS_BROADCAST(ehp) || 6656495Sspeer (IS_MULTICAST(ehp))); 6661991Sheppo /* 6676419Ssb155480 * Destination is not in FDB. 6686495Sspeer * If the destination is broadcast or multicast, 6696495Sspeer * then forward the packet to vswitch. 6706495Sspeer * If a Hybrid resource avilable, then send the 6716495Sspeer * unicast packet via hybrid resource, otherwise 6726495Sspeer * forward it to vswitch. 6731991Sheppo */ 6746419Ssb155480 READ_ENTER(&vnetp->vsw_fp_rw); 6756419Ssb155480 6766495Sspeer if ((is_unicast) && (vnetp->hio_fp != NULL)) { 6776495Sspeer vresp = vnetp->hio_fp; 6786495Sspeer } else { 6796495Sspeer vresp = vnetp->vsw_fp; 6806495Sspeer } 6816495Sspeer if (vresp == NULL) { 6826419Ssb155480 /* 6836419Ssb155480 * no fdb entry to vsw? drop the packet. 6846419Ssb155480 */ 6856419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 6861991Sheppo freemsg(mp); 6876419Ssb155480 mp = next; 6886419Ssb155480 continue; 6891991Sheppo } 6906419Ssb155480 6916419Ssb155480 /* ref hold the fdb entry to vsw */ 6926495Sspeer VNET_FDBE_REFHOLD(vresp); 6936419Ssb155480 6946419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 6956419Ssb155480 6966495Sspeer macp = &vresp->macreg; 6976495Sspeer resid_mp = macp->m_callbacks->mc_tx(macp->m_driver, mp); 6986419Ssb155480 6996419Ssb155480 /* tx done; now release ref on fdb entry */ 7006495Sspeer VNET_FDBE_REFRELE(vresp); 7016419Ssb155480 7026419Ssb155480 if (resid_mp != NULL) { 7036419Ssb155480 /* m_tx failed */ 7046419Ssb155480 mp->b_next = next; 7056419Ssb155480 break; 7066419Ssb155480 } 7071991Sheppo } 7081991Sheppo 7091991Sheppo mp = next; 7101991Sheppo } 7111991Sheppo 7124647Sraghuram DBG1(vnetp, "exit\n"); 7131991Sheppo return (mp); 7141991Sheppo } 7151991Sheppo 7162311Sseb /* get statistics from the device */ 7172311Sseb int 7182311Sseb vnet_m_stat(void *arg, uint_t stat, uint64_t *val) 7191991Sheppo { 7201991Sheppo vnet_t *vnetp = arg; 7216495Sspeer vnet_res_t *vresp; 7226495Sspeer mac_register_t *macp; 7232311Sseb mac_callbacks_t *cbp; 7242311Sseb uint64_t val_total = 0; 7251991Sheppo 7264647Sraghuram DBG1(vnetp, "enter\n"); 7271991Sheppo 7281991Sheppo /* 7292311Sseb * get the specified statistic from each transport and return the 7302311Sseb * aggregate val. This obviously only works for counters. 7311991Sheppo */ 7322311Sseb if ((IS_MAC_STAT(stat) && !MAC_STAT_ISACOUNTER(stat)) || 7332311Sseb (IS_MACTYPE_STAT(stat) && !ETHER_STAT_ISACOUNTER(stat))) { 7342311Sseb return (ENOTSUP); 7352311Sseb } 7366495Sspeer 7376495Sspeer READ_ENTER(&vnetp->vrwlock); 7386495Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) { 7396495Sspeer macp = &vresp->macreg; 7406495Sspeer cbp = macp->m_callbacks; 7416495Sspeer if (cbp->mc_getstat(macp->m_driver, stat, val) == 0) 7422311Sseb val_total += *val; 7431991Sheppo } 7446495Sspeer RW_EXIT(&vnetp->vrwlock); 7451991Sheppo 7462311Sseb *val = val_total; 7472311Sseb 7484647Sraghuram DBG1(vnetp, "exit\n"); 7492311Sseb return (0); 7501991Sheppo } 7511991Sheppo 7521991Sheppo /* wrapper function for mac_register() */ 7531991Sheppo static int 7541991Sheppo vnet_mac_register(vnet_t *vnetp) 7551991Sheppo { 7562311Sseb mac_register_t *macp; 7572311Sseb int err; 7581991Sheppo 7592311Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 7602311Sseb return (DDI_FAILURE); 7612311Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 7622311Sseb macp->m_driver = vnetp; 7631991Sheppo macp->m_dip = vnetp->dip; 7642311Sseb macp->m_src_addr = vnetp->curr_macaddr; 7652311Sseb macp->m_callbacks = &vnet_m_callbacks; 7662311Sseb macp->m_min_sdu = 0; 7677529SSriharsha.Basavapatna@Sun.COM macp->m_max_sdu = vnetp->mtu; 7686419Ssb155480 macp->m_margin = VLAN_TAGSZ; 7691991Sheppo 7701991Sheppo /* 7711991Sheppo * Finally, we're ready to register ourselves with the MAC layer 7721991Sheppo * interface; if this succeeds, we're all ready to start() 7731991Sheppo */ 7742311Sseb err = mac_register(macp, &vnetp->mh); 7752311Sseb mac_free(macp); 7762311Sseb return (err == 0 ? DDI_SUCCESS : DDI_FAILURE); 7771991Sheppo } 7781991Sheppo 7791991Sheppo /* read the mac address of the device */ 7801991Sheppo static int 7811991Sheppo vnet_read_mac_address(vnet_t *vnetp) 7821991Sheppo { 7831991Sheppo uchar_t *macaddr; 7841991Sheppo uint32_t size; 7851991Sheppo int rv; 7861991Sheppo 7871991Sheppo rv = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, vnetp->dip, 7884650Sraghuram DDI_PROP_DONTPASS, macaddr_propname, &macaddr, &size); 7891991Sheppo if ((rv != DDI_PROP_SUCCESS) || (size != ETHERADDRL)) { 7904647Sraghuram DWARN(vnetp, "prop_lookup failed(%s) err(%d)\n", 7914647Sraghuram macaddr_propname, rv); 7921991Sheppo return (DDI_FAILURE); 7931991Sheppo } 7941991Sheppo bcopy(macaddr, (caddr_t)vnetp->vendor_addr, ETHERADDRL); 7951991Sheppo bcopy(macaddr, (caddr_t)vnetp->curr_macaddr, ETHERADDRL); 7961991Sheppo ddi_prop_free(macaddr); 7971991Sheppo 7981991Sheppo return (DDI_SUCCESS); 7991991Sheppo } 8001991Sheppo 8016419Ssb155480 static void 8026419Ssb155480 vnet_fdb_create(vnet_t *vnetp) 8031991Sheppo { 8046419Ssb155480 char hashname[MAXNAMELEN]; 8051991Sheppo 8066419Ssb155480 (void) snprintf(hashname, MAXNAMELEN, "vnet%d-fdbhash", 8076419Ssb155480 vnetp->instance); 8086419Ssb155480 vnetp->fdb_nchains = vnet_fdb_nchains; 8096419Ssb155480 vnetp->fdb_hashp = mod_hash_create_ptrhash(hashname, vnetp->fdb_nchains, 8106419Ssb155480 mod_hash_null_valdtor, sizeof (void *)); 8116419Ssb155480 } 8121991Sheppo 8136419Ssb155480 static void 8146419Ssb155480 vnet_fdb_destroy(vnet_t *vnetp) 8156419Ssb155480 { 8166419Ssb155480 /* destroy fdb-hash-table */ 8176419Ssb155480 if (vnetp->fdb_hashp != NULL) { 8186419Ssb155480 mod_hash_destroy_hash(vnetp->fdb_hashp); 8196419Ssb155480 vnetp->fdb_hashp = NULL; 8206419Ssb155480 vnetp->fdb_nchains = 0; 8211991Sheppo } 8221991Sheppo } 8231991Sheppo 8246419Ssb155480 /* 8256419Ssb155480 * Add an entry into the fdb. 8266419Ssb155480 */ 8271991Sheppo void 8286495Sspeer vnet_fdbe_add(vnet_t *vnetp, vnet_res_t *vresp) 8291991Sheppo { 8306419Ssb155480 uint64_t addr = 0; 8316419Ssb155480 int rv; 8326419Ssb155480 8336495Sspeer KEY_HASH(addr, vresp->rem_macaddr); 8341991Sheppo 8356419Ssb155480 /* 8366495Sspeer * If the entry being added corresponds to LDC_SERVICE resource, 8376495Sspeer * that is, vswitch connection, it is added to the hash and also 8386495Sspeer * the entry is cached, an additional reference count reflects 8396495Sspeer * this. The HYBRID resource is not added to the hash, but only 8406495Sspeer * cached, as it is only used for sending out packets for unknown 8416495Sspeer * unicast destinations. 8426419Ssb155480 */ 8436495Sspeer (vresp->type == VIO_NET_RES_LDC_SERVICE) ? 8446495Sspeer (vresp->refcnt = 1) : (vresp->refcnt = 0); 8451991Sheppo 8466419Ssb155480 /* 8476419Ssb155480 * Note: duplicate keys will be rejected by mod_hash. 8486419Ssb155480 */ 8496495Sspeer if (vresp->type != VIO_NET_RES_HYBRID) { 8506495Sspeer rv = mod_hash_insert(vnetp->fdb_hashp, (mod_hash_key_t)addr, 8516495Sspeer (mod_hash_val_t)vresp); 8526495Sspeer if (rv != 0) { 8536495Sspeer DWARN(vnetp, "Duplicate macaddr key(%lx)\n", addr); 8546495Sspeer return; 8556495Sspeer } 8561991Sheppo } 8571991Sheppo 8586495Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) { 8596419Ssb155480 /* Cache the fdb entry to vsw-port */ 8606419Ssb155480 WRITE_ENTER(&vnetp->vsw_fp_rw); 8616419Ssb155480 if (vnetp->vsw_fp == NULL) 8626495Sspeer vnetp->vsw_fp = vresp; 8636495Sspeer RW_EXIT(&vnetp->vsw_fp_rw); 8646495Sspeer } else if (vresp->type == VIO_NET_RES_HYBRID) { 8656495Sspeer /* Cache the fdb entry to hybrid resource */ 8666495Sspeer WRITE_ENTER(&vnetp->vsw_fp_rw); 8676495Sspeer if (vnetp->hio_fp == NULL) 8686495Sspeer vnetp->hio_fp = vresp; 8696419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 8702793Slm66018 } 8711991Sheppo } 8721991Sheppo 8736419Ssb155480 /* 8746419Ssb155480 * Remove an entry from fdb. 8756419Ssb155480 */ 8766495Sspeer static void 8776495Sspeer vnet_fdbe_del(vnet_t *vnetp, vnet_res_t *vresp) 8785641Swentaoy { 8796419Ssb155480 uint64_t addr = 0; 8806419Ssb155480 int rv; 8816419Ssb155480 uint32_t refcnt; 8826495Sspeer vnet_res_t *tmp; 8835641Swentaoy 8846495Sspeer KEY_HASH(addr, vresp->rem_macaddr); 8855641Swentaoy 8866419Ssb155480 /* 8876419Ssb155480 * Remove the entry from fdb hash table. 8886419Ssb155480 * This prevents further references to this fdb entry. 8896419Ssb155480 */ 8906495Sspeer if (vresp->type != VIO_NET_RES_HYBRID) { 8916495Sspeer rv = mod_hash_remove(vnetp->fdb_hashp, (mod_hash_key_t)addr, 8926495Sspeer (mod_hash_val_t *)&tmp); 8936495Sspeer if (rv != 0) { 8946495Sspeer /* 8956495Sspeer * As the resources are added to the hash only 8966495Sspeer * after they are started, this can occur if 8976495Sspeer * a resource unregisters before it is ever started. 8986495Sspeer */ 8996495Sspeer return; 9006495Sspeer } 9016495Sspeer } 9025641Swentaoy 9036495Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) { 9046419Ssb155480 WRITE_ENTER(&vnetp->vsw_fp_rw); 9055641Swentaoy 9066495Sspeer ASSERT(tmp == vnetp->vsw_fp); 9076419Ssb155480 vnetp->vsw_fp = NULL; 9086419Ssb155480 9096419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 9106495Sspeer } else if (vresp->type == VIO_NET_RES_HYBRID) { 9116495Sspeer WRITE_ENTER(&vnetp->vsw_fp_rw); 9126495Sspeer 9136495Sspeer vnetp->hio_fp = NULL; 9146495Sspeer 9156495Sspeer RW_EXIT(&vnetp->vsw_fp_rw); 9165641Swentaoy } 9175641Swentaoy 9185641Swentaoy /* 9196419Ssb155480 * If there are threads already ref holding before the entry was 9206419Ssb155480 * removed from hash table, then wait for ref count to drop to zero. 9215641Swentaoy */ 9226495Sspeer (vresp->type == VIO_NET_RES_LDC_SERVICE) ? 9236495Sspeer (refcnt = 1) : (refcnt = 0); 9246495Sspeer while (vresp->refcnt > refcnt) { 9256419Ssb155480 delay(drv_usectohz(vnet_fdbe_refcnt_delay)); 9266419Ssb155480 } 9271991Sheppo } 9281991Sheppo 9296419Ssb155480 /* 9306419Ssb155480 * Search fdb for a given mac address. If an entry is found, hold 9316419Ssb155480 * a reference to it and return the entry; else returns NULL. 9326419Ssb155480 */ 9336495Sspeer static vnet_res_t * 9346419Ssb155480 vnet_fdbe_find(vnet_t *vnetp, struct ether_addr *addrp) 9351991Sheppo { 9366419Ssb155480 uint64_t key = 0; 9376495Sspeer vnet_res_t *vresp; 9386419Ssb155480 int rv; 9396419Ssb155480 9406495Sspeer KEY_HASH(key, addrp->ether_addr_octet); 9416419Ssb155480 9426419Ssb155480 rv = mod_hash_find_cb(vnetp->fdb_hashp, (mod_hash_key_t)key, 9436495Sspeer (mod_hash_val_t *)&vresp, vnet_fdbe_find_cb); 9441991Sheppo 9456419Ssb155480 if (rv != 0) 9466419Ssb155480 return (NULL); 9471991Sheppo 9486495Sspeer return (vresp); 9496419Ssb155480 } 9501991Sheppo 9516419Ssb155480 /* 9526419Ssb155480 * Callback function provided to mod_hash_find_cb(). After finding the fdb 9536419Ssb155480 * entry corresponding to the key (macaddr), this callback will be invoked by 9546419Ssb155480 * mod_hash_find_cb() to atomically increment the reference count on the fdb 9556419Ssb155480 * entry before returning the found entry. 9566419Ssb155480 */ 9576419Ssb155480 static void 9586419Ssb155480 vnet_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val) 9596419Ssb155480 { 9606419Ssb155480 _NOTE(ARGUNUSED(key)) 9616495Sspeer VNET_FDBE_REFHOLD((vnet_res_t *)val); 9626495Sspeer } 9636495Sspeer 9646495Sspeer static void 9656495Sspeer vnet_rx(vio_net_handle_t vrh, mblk_t *mp) 9666495Sspeer { 9676495Sspeer vnet_res_t *vresp = (vnet_res_t *)vrh; 9686495Sspeer vnet_t *vnetp = vresp->vnetp; 9696495Sspeer 9706495Sspeer if ((vnetp != NULL) && (vnetp->mh)) { 9716495Sspeer mac_rx(vnetp->mh, NULL, mp); 9726495Sspeer } else { 9736495Sspeer freemsgchain(mp); 9746495Sspeer } 9751991Sheppo } 9762311Sseb 9772311Sseb void 9786495Sspeer vnet_tx_update(vio_net_handle_t vrh) 9796495Sspeer { 9806495Sspeer vnet_res_t *vresp = (vnet_res_t *)vrh; 9816495Sspeer vnet_t *vnetp = vresp->vnetp; 9826495Sspeer 9836495Sspeer if ((vnetp != NULL) && (vnetp->mh != NULL)) { 9846495Sspeer mac_tx_update(vnetp->mh); 9856495Sspeer } 9866495Sspeer } 9876495Sspeer 9886495Sspeer /* 9897529SSriharsha.Basavapatna@Sun.COM * Update the new mtu of vnet into the mac layer. First check if the device has 9907529SSriharsha.Basavapatna@Sun.COM * been plumbed and if so fail the mtu update. Returns 0 on success. 9917529SSriharsha.Basavapatna@Sun.COM */ 9927529SSriharsha.Basavapatna@Sun.COM int 9937529SSriharsha.Basavapatna@Sun.COM vnet_mtu_update(vnet_t *vnetp, uint32_t mtu) 9947529SSriharsha.Basavapatna@Sun.COM { 9957529SSriharsha.Basavapatna@Sun.COM int rv; 9967529SSriharsha.Basavapatna@Sun.COM 9977529SSriharsha.Basavapatna@Sun.COM if (vnetp == NULL || vnetp->mh == NULL) { 9987529SSriharsha.Basavapatna@Sun.COM return (EINVAL); 9997529SSriharsha.Basavapatna@Sun.COM } 10007529SSriharsha.Basavapatna@Sun.COM 10017529SSriharsha.Basavapatna@Sun.COM WRITE_ENTER(&vnetp->vrwlock); 10027529SSriharsha.Basavapatna@Sun.COM 10037529SSriharsha.Basavapatna@Sun.COM if (vnetp->flags & VNET_STARTED) { 10047529SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock); 10057529SSriharsha.Basavapatna@Sun.COM cmn_err(CE_NOTE, "!vnet%d: Unable to process mtu " 10067529SSriharsha.Basavapatna@Sun.COM "update as the device is plumbed\n", 10077529SSriharsha.Basavapatna@Sun.COM vnetp->instance); 10087529SSriharsha.Basavapatna@Sun.COM return (EBUSY); 10097529SSriharsha.Basavapatna@Sun.COM } 10107529SSriharsha.Basavapatna@Sun.COM 10117529SSriharsha.Basavapatna@Sun.COM /* update mtu in the mac layer */ 10127529SSriharsha.Basavapatna@Sun.COM rv = mac_maxsdu_update(vnetp->mh, mtu); 10137529SSriharsha.Basavapatna@Sun.COM if (rv != 0) { 10147529SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock); 10157529SSriharsha.Basavapatna@Sun.COM cmn_err(CE_NOTE, 10167529SSriharsha.Basavapatna@Sun.COM "!vnet%d: Unable to update mtu with mac layer\n", 10177529SSriharsha.Basavapatna@Sun.COM vnetp->instance); 10187529SSriharsha.Basavapatna@Sun.COM return (EIO); 10197529SSriharsha.Basavapatna@Sun.COM } 10207529SSriharsha.Basavapatna@Sun.COM 10217529SSriharsha.Basavapatna@Sun.COM vnetp->mtu = mtu; 10227529SSriharsha.Basavapatna@Sun.COM 10237529SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock); 10247529SSriharsha.Basavapatna@Sun.COM 10257529SSriharsha.Basavapatna@Sun.COM return (0); 10267529SSriharsha.Basavapatna@Sun.COM } 10277529SSriharsha.Basavapatna@Sun.COM 10287529SSriharsha.Basavapatna@Sun.COM /* 10296495Sspeer * vio_net_resource_reg -- An interface called to register a resource 10306495Sspeer * with vnet. 10316495Sspeer * macp -- a GLDv3 mac_register that has all the details of 10326495Sspeer * a resource and its callbacks etc. 10336495Sspeer * type -- resource type. 10346495Sspeer * local_macaddr -- resource's MAC address. This is used to 10356495Sspeer * associate a resource with a corresponding vnet. 10366495Sspeer * remote_macaddr -- remote side MAC address. This is ignored for 10376495Sspeer * the Hybrid resources. 10386495Sspeer * vhp -- A handle returned to the caller. 10396495Sspeer * vcb -- A set of callbacks provided to the callers. 10406495Sspeer */ 10416495Sspeer int vio_net_resource_reg(mac_register_t *macp, vio_net_res_type_t type, 10426495Sspeer ether_addr_t local_macaddr, ether_addr_t rem_macaddr, vio_net_handle_t *vhp, 10436495Sspeer vio_net_callbacks_t *vcb) 10446495Sspeer { 10456495Sspeer vnet_t *vnetp; 10466495Sspeer vnet_res_t *vresp; 10476495Sspeer 10486495Sspeer vresp = kmem_zalloc(sizeof (vnet_res_t), KM_SLEEP); 10496495Sspeer ether_copy(local_macaddr, vresp->local_macaddr); 10506495Sspeer ether_copy(rem_macaddr, vresp->rem_macaddr); 10516495Sspeer vresp->type = type; 10526495Sspeer bcopy(macp, &vresp->macreg, sizeof (mac_register_t)); 10536495Sspeer 10546495Sspeer DBG1(NULL, "Resource Registerig type=0%X\n", type); 10556495Sspeer 10566495Sspeer READ_ENTER(&vnet_rw); 10576495Sspeer vnetp = vnet_headp; 10586495Sspeer while (vnetp != NULL) { 10596495Sspeer if (VNET_MATCH_RES(vresp, vnetp)) { 10606495Sspeer WRITE_ENTER(&vnetp->vrwlock); 10616495Sspeer vresp->vnetp = vnetp; 10626495Sspeer vresp->nextp = vnetp->vres_list; 10636495Sspeer vnetp->vres_list = vresp; 10646495Sspeer RW_EXIT(&vnetp->vrwlock); 10656495Sspeer break; 10666495Sspeer } 10676495Sspeer vnetp = vnetp->nextp; 10686495Sspeer } 10696495Sspeer RW_EXIT(&vnet_rw); 10706495Sspeer if (vresp->vnetp == NULL) { 10716495Sspeer DWARN(NULL, "No vnet instance"); 10726495Sspeer kmem_free(vresp, sizeof (vnet_res_t)); 10736495Sspeer return (ENXIO); 10746495Sspeer } 10756495Sspeer 10766495Sspeer *vhp = vresp; 10776495Sspeer vcb->vio_net_rx_cb = vnet_rx; 10786495Sspeer vcb->vio_net_tx_update = vnet_tx_update; 10796495Sspeer vcb->vio_net_report_err = vnet_handle_res_err; 10806495Sspeer 10816495Sspeer /* Dispatch a task to start resources */ 10826495Sspeer vnet_dispatch_res_task(vnetp); 10836495Sspeer return (0); 10846495Sspeer } 10856495Sspeer 10866495Sspeer /* 10876495Sspeer * vio_net_resource_unreg -- An interface to unregister a resource. 10886495Sspeer */ 10896495Sspeer void 10906495Sspeer vio_net_resource_unreg(vio_net_handle_t vhp) 10916495Sspeer { 10926495Sspeer vnet_res_t *vresp = (vnet_res_t *)vhp; 10936495Sspeer vnet_t *vnetp = vresp->vnetp; 10946495Sspeer vnet_res_t *vrp; 10956495Sspeer 10966495Sspeer DBG1(NULL, "Resource Registerig hdl=0x%p", vhp); 10976495Sspeer 10986495Sspeer ASSERT(vnetp != NULL); 10996495Sspeer vnet_fdbe_del(vnetp, vresp); 11006495Sspeer 11016495Sspeer WRITE_ENTER(&vnetp->vrwlock); 11026495Sspeer if (vresp == vnetp->vres_list) { 11036495Sspeer vnetp->vres_list = vresp->nextp; 11046495Sspeer } else { 11056495Sspeer vrp = vnetp->vres_list; 11066495Sspeer while (vrp->nextp != NULL) { 11076495Sspeer if (vrp->nextp == vresp) { 11086495Sspeer vrp->nextp = vresp->nextp; 11096495Sspeer break; 11106495Sspeer } 11116495Sspeer vrp = vrp->nextp; 11126495Sspeer } 11136495Sspeer } 11146495Sspeer vresp->vnetp = NULL; 11156495Sspeer vresp->nextp = NULL; 11166495Sspeer RW_EXIT(&vnetp->vrwlock); 11176495Sspeer KMEM_FREE(vresp); 11186495Sspeer } 11196495Sspeer 11206495Sspeer /* 11216495Sspeer * vnet_dds_rx -- an interface called by vgen to DDS messages. 11226495Sspeer */ 11236495Sspeer void 11246495Sspeer vnet_dds_rx(void *arg, void *dmsg) 11252311Sseb { 11262311Sseb vnet_t *vnetp = arg; 11276495Sspeer vdds_process_dds_msg(vnetp, dmsg); 11282311Sseb } 11292311Sseb 11306495Sspeer /* 11316495Sspeer * vnet_send_dds_msg -- An interface provided to DDS to send 11326495Sspeer * DDS messages. This simply sends meessages via vgen. 11336495Sspeer */ 11346495Sspeer int 11356495Sspeer vnet_send_dds_msg(vnet_t *vnetp, void *dmsg) 11366495Sspeer { 11376495Sspeer int rv; 11386495Sspeer 11396495Sspeer if (vnetp->vgenhdl != NULL) { 11406495Sspeer rv = vgen_dds_tx(vnetp->vgenhdl, dmsg); 11416495Sspeer } 11426495Sspeer return (rv); 11436495Sspeer } 11446495Sspeer 11456495Sspeer /* 11466495Sspeer * vnet_handle_res_err -- A callback function called by a resource 11476495Sspeer * to report an error. For example, vgen can call to report 11486495Sspeer * an LDC down/reset event. This will trigger cleanup of associated 11496495Sspeer * Hybrid resource. 11506495Sspeer */ 11516495Sspeer /* ARGSUSED */ 11526495Sspeer static void 11536495Sspeer vnet_handle_res_err(vio_net_handle_t vrh, vio_net_err_val_t err) 11546495Sspeer { 11556495Sspeer vnet_res_t *vresp = (vnet_res_t *)vrh; 11566495Sspeer vnet_t *vnetp = vresp->vnetp; 1157*7819SRaghuram.Kothakota@Sun.COM int rv; 11586495Sspeer 11596495Sspeer if (vnetp == NULL) { 11606495Sspeer return; 11616495Sspeer } 11626495Sspeer if ((vresp->type != VIO_NET_RES_LDC_SERVICE) && 11636495Sspeer (vresp->type != VIO_NET_RES_HYBRID)) { 11646495Sspeer return; 11656495Sspeer } 1166*7819SRaghuram.Kothakota@Sun.COM rv = ddi_taskq_dispatch(vnetp->taskqp, vdds_cleanup_hybrid_res, 1167*7819SRaghuram.Kothakota@Sun.COM vnetp, DDI_NOSLEEP); 1168*7819SRaghuram.Kothakota@Sun.COM if (rv != DDI_SUCCESS) { 1169*7819SRaghuram.Kothakota@Sun.COM cmn_err(CE_WARN, 1170*7819SRaghuram.Kothakota@Sun.COM "vnet%d:Failed to dispatch task to cleanup hybrid resource", 1171*7819SRaghuram.Kothakota@Sun.COM vnetp->instance); 1172*7819SRaghuram.Kothakota@Sun.COM } 11736495Sspeer } 11746495Sspeer 11756495Sspeer /* 11766495Sspeer * vnet_dispatch_res_task -- A function to dispatch tasks start resources. 11776495Sspeer */ 11786495Sspeer static void 11796495Sspeer vnet_dispatch_res_task(vnet_t *vnetp) 11806495Sspeer { 11816495Sspeer int rv; 11826495Sspeer 11836495Sspeer WRITE_ENTER(&vnetp->vrwlock); 11846495Sspeer if (vnetp->flags & VNET_STARTED) { 11856495Sspeer rv = ddi_taskq_dispatch(vnetp->taskqp, vnet_res_start_task, 11866495Sspeer vnetp, DDI_NOSLEEP); 11876495Sspeer if (rv != DDI_SUCCESS) { 11886495Sspeer cmn_err(CE_WARN, 11896495Sspeer "vnet%d:Can't dispatch start resource task", 11906495Sspeer vnetp->instance); 11916495Sspeer } 11926495Sspeer } 11936495Sspeer RW_EXIT(&vnetp->vrwlock); 11946495Sspeer } 11956495Sspeer 11966495Sspeer /* 11976495Sspeer * vnet_res_start_task -- A taskq callback function that starts a resource. 11986495Sspeer */ 11996495Sspeer static void 12006495Sspeer vnet_res_start_task(void *arg) 12012311Sseb { 12022311Sseb vnet_t *vnetp = arg; 12036495Sspeer 12046495Sspeer WRITE_ENTER(&vnetp->vrwlock); 12056495Sspeer if (vnetp->flags & VNET_STARTED) { 12066495Sspeer vnet_start_resources(vnetp); 12076495Sspeer } 12086495Sspeer RW_EXIT(&vnetp->vrwlock); 12092311Sseb } 12106495Sspeer 12116495Sspeer /* 12126495Sspeer * vnet_start_resources -- starts all resources associated with 12136495Sspeer * a vnet. 12146495Sspeer */ 12156495Sspeer static void 12166495Sspeer vnet_start_resources(vnet_t *vnetp) 12176495Sspeer { 12186495Sspeer mac_register_t *macp; 12196495Sspeer mac_callbacks_t *cbp; 12206495Sspeer vnet_res_t *vresp; 12216495Sspeer int rv; 12226495Sspeer 12236495Sspeer DBG1(vnetp, "enter\n"); 12246495Sspeer 12256495Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) { 12266495Sspeer /* skip if it is already started */ 12276495Sspeer if (vresp->flags & VNET_STARTED) { 12286495Sspeer continue; 12296495Sspeer } 12306495Sspeer macp = &vresp->macreg; 12316495Sspeer cbp = macp->m_callbacks; 12326495Sspeer rv = cbp->mc_start(macp->m_driver); 12336495Sspeer if (rv == 0) { 12346495Sspeer /* 12356495Sspeer * Successfully started the resource, so now 12366495Sspeer * add it to the fdb. 12376495Sspeer */ 12386495Sspeer vresp->flags |= VNET_STARTED; 12396495Sspeer vnet_fdbe_add(vnetp, vresp); 12406495Sspeer } 12416495Sspeer } 12426495Sspeer 12436495Sspeer DBG1(vnetp, "exit\n"); 12446495Sspeer 12456495Sspeer } 12466495Sspeer 12476495Sspeer /* 12486495Sspeer * vnet_stop_resources -- stop all resources associated with a vnet. 12496495Sspeer */ 12506495Sspeer static void 12516495Sspeer vnet_stop_resources(vnet_t *vnetp) 12526495Sspeer { 12536495Sspeer vnet_res_t *vresp; 12546495Sspeer vnet_res_t *nvresp; 12556495Sspeer mac_register_t *macp; 12566495Sspeer mac_callbacks_t *cbp; 12576495Sspeer 12586495Sspeer DBG1(vnetp, "enter\n"); 12596495Sspeer 12606495Sspeer for (vresp = vnetp->vres_list; vresp != NULL; ) { 12616495Sspeer nvresp = vresp->nextp; 12626495Sspeer if (vresp->flags & VNET_STARTED) { 12636495Sspeer macp = &vresp->macreg; 12646495Sspeer cbp = macp->m_callbacks; 12656495Sspeer cbp->mc_stop(macp->m_driver); 12666495Sspeer vresp->flags &= ~VNET_STARTED; 12676495Sspeer } 12686495Sspeer vresp = nvresp; 12696495Sspeer } 12706495Sspeer DBG1(vnetp, "exit\n"); 12716495Sspeer } 1272