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