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