xref: /onnv-gate/usr/src/uts/sun4v/io/vnet.c (revision 11881:df4f5330faaa)
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 /*
2311543SWentao.Yang@Sun.COM  * Copyright 2010 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>
3011878SVenu.Iyer@Sun.COM #include <sys/callb.h>
311991Sheppo #include <sys/stream.h>
321991Sheppo #include <sys/kmem.h>
331991Sheppo #include <sys/conf.h>
341991Sheppo #include <sys/devops.h>
351991Sheppo #include <sys/ksynch.h>
361991Sheppo #include <sys/stat.h>
371991Sheppo #include <sys/modctl.h>
386419Ssb155480 #include <sys/modhash.h>
391991Sheppo #include <sys/debug.h>
401991Sheppo #include <sys/ethernet.h>
411991Sheppo #include <sys/dlpi.h>
421991Sheppo #include <net/if.h>
438275SEric Cheng #include <sys/mac_provider.h>
4410309SSriharsha.Basavapatna@Sun.COM #include <sys/mac_client.h>
4510309SSriharsha.Basavapatna@Sun.COM #include <sys/mac_client_priv.h>
462311Sseb #include <sys/mac_ether.h>
471991Sheppo #include <sys/ddi.h>
481991Sheppo #include <sys/sunddi.h>
491991Sheppo #include <sys/strsun.h>
501991Sheppo #include <sys/note.h>
516419Ssb155480 #include <sys/atomic.h>
521991Sheppo #include <sys/vnet.h>
536419Ssb155480 #include <sys/vlan.h>
546495Sspeer #include <sys/vnet_mailbox.h>
556495Sspeer #include <sys/vnet_common.h>
566495Sspeer #include <sys/dds.h>
576495Sspeer #include <sys/strsubr.h>
586495Sspeer #include <sys/taskq.h>
591991Sheppo 
601991Sheppo /*
611991Sheppo  * Function prototypes.
621991Sheppo  */
631991Sheppo 
641991Sheppo /* DDI entrypoints */
651991Sheppo static int vnetdevinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
661991Sheppo static int vnetattach(dev_info_t *, ddi_attach_cmd_t);
671991Sheppo static int vnetdetach(dev_info_t *, ddi_detach_cmd_t);
681991Sheppo 
691991Sheppo /* MAC entrypoints  */
702311Sseb static int vnet_m_stat(void *, uint_t, uint64_t *);
711991Sheppo static int vnet_m_start(void *);
721991Sheppo static void vnet_m_stop(void *);
731991Sheppo static int vnet_m_promisc(void *, boolean_t);
741991Sheppo static int vnet_m_multicst(void *, boolean_t, const uint8_t *);
751991Sheppo static int vnet_m_unicst(void *, const uint8_t *);
761991Sheppo mblk_t *vnet_m_tx(void *, mblk_t *);
779336SSriharsha.Basavapatna@Sun.COM static void vnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp);
789336SSriharsha.Basavapatna@Sun.COM #ifdef	VNET_IOC_DEBUG
799336SSriharsha.Basavapatna@Sun.COM static void vnet_force_link_state(vnet_t *vnetp, queue_t *q, mblk_t *mp);
809336SSriharsha.Basavapatna@Sun.COM #endif
8110309SSriharsha.Basavapatna@Sun.COM static boolean_t vnet_m_capab(void *arg, mac_capab_t cap, void *cap_data);
8210309SSriharsha.Basavapatna@Sun.COM static void vnet_get_ring(void *arg, mac_ring_type_t rtype, const int g_index,
8310309SSriharsha.Basavapatna@Sun.COM 	const int r_index, mac_ring_info_t *infop, mac_ring_handle_t r_handle);
8410309SSriharsha.Basavapatna@Sun.COM static void vnet_get_group(void *arg, mac_ring_type_t type, const int index,
8510309SSriharsha.Basavapatna@Sun.COM 	mac_group_info_t *infop, mac_group_handle_t handle);
8610309SSriharsha.Basavapatna@Sun.COM static int vnet_rx_ring_start(mac_ring_driver_t rdriver, uint64_t mr_gen_num);
8710309SSriharsha.Basavapatna@Sun.COM static void vnet_rx_ring_stop(mac_ring_driver_t rdriver);
8811878SVenu.Iyer@Sun.COM static int vnet_rx_ring_stat(mac_ring_driver_t rdriver, uint_t stat,
8911878SVenu.Iyer@Sun.COM 	uint64_t *val);
9010309SSriharsha.Basavapatna@Sun.COM static int vnet_tx_ring_start(mac_ring_driver_t rdriver, uint64_t mr_gen_num);
9110309SSriharsha.Basavapatna@Sun.COM static void vnet_tx_ring_stop(mac_ring_driver_t rdriver);
9211878SVenu.Iyer@Sun.COM static int vnet_tx_ring_stat(mac_ring_driver_t rdriver, uint_t stat,
9311878SVenu.Iyer@Sun.COM 	uint64_t *val);
9410309SSriharsha.Basavapatna@Sun.COM static int vnet_ring_enable_intr(void *arg);
9510309SSriharsha.Basavapatna@Sun.COM static int vnet_ring_disable_intr(void *arg);
9610309SSriharsha.Basavapatna@Sun.COM static mblk_t *vnet_rx_poll(void *arg, int bytes_to_pickup);
9710309SSriharsha.Basavapatna@Sun.COM static int vnet_addmac(void *arg, const uint8_t *mac_addr);
9810309SSriharsha.Basavapatna@Sun.COM static int vnet_remmac(void *arg, const uint8_t *mac_addr);
991991Sheppo 
1001991Sheppo /* vnet internal functions */
1019217SWentao.Yang@Sun.COM static int vnet_unattach(vnet_t *vnetp);
10210309SSriharsha.Basavapatna@Sun.COM static void vnet_ring_grp_init(vnet_t *vnetp);
10310309SSriharsha.Basavapatna@Sun.COM static void vnet_ring_grp_uninit(vnet_t *vnetp);
1041991Sheppo static int vnet_mac_register(vnet_t *);
1051991Sheppo static int vnet_read_mac_address(vnet_t *vnetp);
10610309SSriharsha.Basavapatna@Sun.COM static int vnet_bind_vgenring(vnet_res_t *vresp);
10710309SSriharsha.Basavapatna@Sun.COM static void vnet_unbind_vgenring(vnet_res_t *vresp);
10810309SSriharsha.Basavapatna@Sun.COM static int vnet_bind_hwrings(vnet_t *vnetp);
10910309SSriharsha.Basavapatna@Sun.COM static void vnet_unbind_hwrings(vnet_t *vnetp);
11010309SSriharsha.Basavapatna@Sun.COM static int vnet_bind_rings(vnet_res_t *vresp);
11110309SSriharsha.Basavapatna@Sun.COM static void vnet_unbind_rings(vnet_res_t *vresp);
11210309SSriharsha.Basavapatna@Sun.COM static int vnet_hio_stat(void *, uint_t, uint64_t *);
11310309SSriharsha.Basavapatna@Sun.COM static int vnet_hio_start(void *);
11410309SSriharsha.Basavapatna@Sun.COM static void vnet_hio_stop(void *);
11510309SSriharsha.Basavapatna@Sun.COM mblk_t *vnet_hio_tx(void *, mblk_t *);
1161991Sheppo 
1176419Ssb155480 /* Forwarding database (FDB) routines */
1186419Ssb155480 static void vnet_fdb_create(vnet_t *vnetp);
1196419Ssb155480 static void vnet_fdb_destroy(vnet_t *vnetp);
1206495Sspeer static vnet_res_t *vnet_fdbe_find(vnet_t *vnetp, struct ether_addr *addrp);
1216419Ssb155480 static void vnet_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val);
1226495Sspeer void vnet_fdbe_add(vnet_t *vnetp, vnet_res_t *vresp);
1236495Sspeer static void vnet_fdbe_del(vnet_t *vnetp, vnet_res_t *vresp);
1246495Sspeer 
1257896SSriharsha.Basavapatna@Sun.COM static void vnet_rx_frames_untag(uint16_t pvid, mblk_t **mp);
1266495Sspeer static void vnet_rx(vio_net_handle_t vrh, mblk_t *mp);
1276495Sspeer static void vnet_tx_update(vio_net_handle_t vrh);
1286495Sspeer static void vnet_res_start_task(void *arg);
1296495Sspeer static void vnet_start_resources(vnet_t *vnetp);
1306495Sspeer static void vnet_stop_resources(vnet_t *vnetp);
1316495Sspeer static void vnet_dispatch_res_task(vnet_t *vnetp);
1326495Sspeer static void vnet_res_start_task(void *arg);
1336495Sspeer static void vnet_handle_res_err(vio_net_handle_t vrh, vio_net_err_val_t err);
13410309SSriharsha.Basavapatna@Sun.COM static void vnet_add_resource(vnet_t *vnetp, vnet_res_t *vresp);
13510309SSriharsha.Basavapatna@Sun.COM static vnet_res_t *vnet_rem_resource(vnet_t *vnetp, vnet_res_t *vresp);
13611878SVenu.Iyer@Sun.COM static void vnet_tx_notify_thread(void *);
1379336SSriharsha.Basavapatna@Sun.COM 
1389336SSriharsha.Basavapatna@Sun.COM /* Exported to vnet_gen */
1397529SSriharsha.Basavapatna@Sun.COM int vnet_mtu_update(vnet_t *vnetp, uint32_t mtu);
1409336SSriharsha.Basavapatna@Sun.COM void vnet_link_update(vnet_t *vnetp, link_state_t link_state);
1419647SWentao.Yang@Sun.COM void vnet_dds_cleanup_hio(vnet_t *vnetp);
1426419Ssb155480 
1438160SWentao.Yang@Sun.COM static kstat_t *vnet_hio_setup_kstats(char *ks_mod, char *ks_name,
1448160SWentao.Yang@Sun.COM     vnet_res_t *vresp);
1458160SWentao.Yang@Sun.COM static int vnet_hio_update_kstats(kstat_t *ksp, int rw);
1468160SWentao.Yang@Sun.COM static void vnet_hio_get_stats(vnet_res_t *vresp, vnet_hio_stats_t *statsp);
1478160SWentao.Yang@Sun.COM static void vnet_hio_destroy_kstats(kstat_t *ksp);
1488160SWentao.Yang@Sun.COM 
1496495Sspeer /* Exported to to vnet_dds */
1506495Sspeer int vnet_send_dds_msg(vnet_t *vnetp, void *dmsg);
15110309SSriharsha.Basavapatna@Sun.COM int vnet_hio_mac_init(vnet_t *vnetp, char *ifname);
15210309SSriharsha.Basavapatna@Sun.COM void vnet_hio_mac_cleanup(vnet_t *vnetp);
1531991Sheppo 
1546495Sspeer /* Externs that are imported from vnet_gen */
1556495Sspeer extern int vgen_init(void *vnetp, uint64_t regprop, dev_info_t *vnetdip,
1566495Sspeer     const uint8_t *macaddr, void **vgenhdl);
15710309SSriharsha.Basavapatna@Sun.COM extern int vgen_init_mdeg(void *arg);
1589235SWentao.Yang@Sun.COM extern void vgen_uninit(void *arg);
1596495Sspeer extern int vgen_dds_tx(void *arg, void *dmsg);
1609217SWentao.Yang@Sun.COM extern void vgen_mod_init(void);
1619217SWentao.Yang@Sun.COM extern int vgen_mod_cleanup(void);
1629217SWentao.Yang@Sun.COM extern void vgen_mod_fini(void);
16310309SSriharsha.Basavapatna@Sun.COM extern int vgen_enable_intr(void *arg);
16410309SSriharsha.Basavapatna@Sun.COM extern int vgen_disable_intr(void *arg);
16510309SSriharsha.Basavapatna@Sun.COM extern mblk_t *vgen_poll(void *arg, int bytes_to_pickup);
1666495Sspeer 
1676495Sspeer /* Externs that are imported from vnet_dds */
1686495Sspeer extern void vdds_mod_init(void);
1696495Sspeer extern void vdds_mod_fini(void);
1706495Sspeer extern int vdds_init(vnet_t *vnetp);
1716495Sspeer extern void vdds_cleanup(vnet_t *vnetp);
1726495Sspeer extern void vdds_process_dds_msg(vnet_t *vnetp, vio_dds_msg_t *dmsg);
1737819SRaghuram.Kothakota@Sun.COM extern void vdds_cleanup_hybrid_res(void *arg);
1749647SWentao.Yang@Sun.COM extern void vdds_cleanup_hio(vnet_t *vnetp);
1751991Sheppo 
17611878SVenu.Iyer@Sun.COM extern pri_t	minclsyspri;
17710309SSriharsha.Basavapatna@Sun.COM 
1788160SWentao.Yang@Sun.COM #define	DRV_NAME	"vnet"
1796419Ssb155480 #define	VNET_FDBE_REFHOLD(p)						\
1806419Ssb155480 {									\
1816419Ssb155480 	atomic_inc_32(&(p)->refcnt);					\
1826419Ssb155480 	ASSERT((p)->refcnt != 0);					\
1836419Ssb155480 }
1846419Ssb155480 
1856419Ssb155480 #define	VNET_FDBE_REFRELE(p)						\
1866419Ssb155480 {									\
1876419Ssb155480 	ASSERT((p)->refcnt != 0);					\
1886419Ssb155480 	atomic_dec_32(&(p)->refcnt);					\
1896419Ssb155480 }
1906419Ssb155480 
1919336SSriharsha.Basavapatna@Sun.COM #ifdef	VNET_IOC_DEBUG
19210309SSriharsha.Basavapatna@Sun.COM #define	VNET_M_CALLBACK_FLAGS	(MC_IOCTL | MC_GETCAPAB)
1939336SSriharsha.Basavapatna@Sun.COM #else
19410309SSriharsha.Basavapatna@Sun.COM #define	VNET_M_CALLBACK_FLAGS	(MC_GETCAPAB)
1959336SSriharsha.Basavapatna@Sun.COM #endif
1969336SSriharsha.Basavapatna@Sun.COM 
1972311Sseb static mac_callbacks_t vnet_m_callbacks = {
1989336SSriharsha.Basavapatna@Sun.COM 	VNET_M_CALLBACK_FLAGS,
1992311Sseb 	vnet_m_stat,
2002311Sseb 	vnet_m_start,
2012311Sseb 	vnet_m_stop,
2022311Sseb 	vnet_m_promisc,
2032311Sseb 	vnet_m_multicst,
20410309SSriharsha.Basavapatna@Sun.COM 	NULL,	/* m_unicst entry must be NULL while rx rings are exposed */
20510309SSriharsha.Basavapatna@Sun.COM 	NULL,	/* m_tx entry must be NULL while tx rings are exposed */
20611878SVenu.Iyer@Sun.COM 	NULL,
2079336SSriharsha.Basavapatna@Sun.COM 	vnet_m_ioctl,
20810309SSriharsha.Basavapatna@Sun.COM 	vnet_m_capab,
20910309SSriharsha.Basavapatna@Sun.COM 	NULL
21010309SSriharsha.Basavapatna@Sun.COM };
21110309SSriharsha.Basavapatna@Sun.COM 
21210309SSriharsha.Basavapatna@Sun.COM static mac_callbacks_t vnet_hio_res_callbacks = {
21310309SSriharsha.Basavapatna@Sun.COM 	0,
21410309SSriharsha.Basavapatna@Sun.COM 	vnet_hio_stat,
21510309SSriharsha.Basavapatna@Sun.COM 	vnet_hio_start,
21610309SSriharsha.Basavapatna@Sun.COM 	vnet_hio_stop,
21710309SSriharsha.Basavapatna@Sun.COM 	NULL,
21810309SSriharsha.Basavapatna@Sun.COM 	NULL,
21910309SSriharsha.Basavapatna@Sun.COM 	NULL,
22010309SSriharsha.Basavapatna@Sun.COM 	vnet_hio_tx,
22110309SSriharsha.Basavapatna@Sun.COM 	NULL,
2222311Sseb 	NULL,
2232311Sseb 	NULL
2242311Sseb };
2252311Sseb 
2261991Sheppo /*
2271991Sheppo  * Linked list of "vnet_t" structures - one per instance.
2281991Sheppo  */
2291991Sheppo static vnet_t	*vnet_headp = NULL;
2301991Sheppo static krwlock_t vnet_rw;
2311991Sheppo 
2321991Sheppo /* Tunables */
2331991Sheppo uint32_t vnet_ntxds = VNET_NTXDS;	/* power of 2 transmit descriptors */
2341991Sheppo uint32_t vnet_ldcwd_interval = VNET_LDCWD_INTERVAL; /* watchdog freq in msec */
2351991Sheppo uint32_t vnet_ldcwd_txtimeout = VNET_LDCWD_TXTIMEOUT;  /* tx timeout in msec */
2362410Slm66018 uint32_t vnet_ldc_mtu = VNET_LDC_MTU;		/* ldc mtu */
2376419Ssb155480 
23810309SSriharsha.Basavapatna@Sun.COM /* Configure tx serialization in mac layer for the vnet device */
23910309SSriharsha.Basavapatna@Sun.COM boolean_t vnet_mac_tx_serialize = B_TRUE;
24011878SVenu.Iyer@Sun.COM /* Configure enqueing at Rx soft rings in mac layer for the vnet device */
24111878SVenu.Iyer@Sun.COM boolean_t vnet_mac_rx_queuing = B_TRUE;
24210309SSriharsha.Basavapatna@Sun.COM 
2437529SSriharsha.Basavapatna@Sun.COM /*
2447529SSriharsha.Basavapatna@Sun.COM  * Set this to non-zero to enable additional internal receive buffer pools
2457529SSriharsha.Basavapatna@Sun.COM  * based on the MTU of the device for better performance at the cost of more
2467529SSriharsha.Basavapatna@Sun.COM  * memory consumption. This is turned off by default, to use allocb(9F) for
2477529SSriharsha.Basavapatna@Sun.COM  * receive buffer allocations of sizes > 2K.
2487529SSriharsha.Basavapatna@Sun.COM  */
2497529SSriharsha.Basavapatna@Sun.COM boolean_t vnet_jumbo_rxpools = B_FALSE;
2507529SSriharsha.Basavapatna@Sun.COM 
2516419Ssb155480 /* # of chains in fdb hash table */
2526419Ssb155480 uint32_t	vnet_fdb_nchains = VNET_NFDB_HASH;
2536419Ssb155480 
2546419Ssb155480 /* Internal tunables */
2556419Ssb155480 uint32_t	vnet_ethermtu = 1500;	/* mtu of the device */
2566419Ssb155480 
2576419Ssb155480 /*
2586419Ssb155480  * Default vlan id. This is only used internally when the "default-vlan-id"
2596419Ssb155480  * property is not present in the MD device node. Therefore, this should not be
2606419Ssb155480  * used as a tunable; if this value is changed, the corresponding variable
2616419Ssb155480  * should be updated to the same value in vsw and also other vnets connected to
2626419Ssb155480  * the same vsw.
2636419Ssb155480  */
2646419Ssb155480 uint16_t	vnet_default_vlan_id = 1;
2656419Ssb155480 
2666419Ssb155480 /* delay in usec to wait for all references on a fdb entry to be dropped */
2676419Ssb155480 uint32_t vnet_fdbe_refcnt_delay = 10;
2681991Sheppo 
2696495Sspeer static struct ether_addr etherbroadcastaddr = {
2706495Sspeer 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2716495Sspeer };
2726495Sspeer 
27310309SSriharsha.Basavapatna@Sun.COM /* mac_open() retry delay in usec */
27410309SSriharsha.Basavapatna@Sun.COM uint32_t vnet_mac_open_delay = 100;	/* 0.1 ms */
27510309SSriharsha.Basavapatna@Sun.COM 
27610309SSriharsha.Basavapatna@Sun.COM /* max # of mac_open() retries */
27710309SSriharsha.Basavapatna@Sun.COM uint32_t vnet_mac_open_retries = 100;
2786495Sspeer 
2791991Sheppo /*
2801991Sheppo  * Property names
2811991Sheppo  */
2821991Sheppo static char macaddr_propname[] = "local-mac-address";
2831991Sheppo 
2841991Sheppo /*
2851991Sheppo  * This is the string displayed by modinfo(1m).
2861991Sheppo  */
2877529SSriharsha.Basavapatna@Sun.COM static char vnet_ident[] = "vnet driver";
2881991Sheppo extern struct mod_ops mod_driverops;
2891991Sheppo static struct cb_ops cb_vnetops = {
2901991Sheppo 	nulldev,		/* cb_open */
2911991Sheppo 	nulldev,		/* cb_close */
2921991Sheppo 	nodev,			/* cb_strategy */
2931991Sheppo 	nodev,			/* cb_print */
2941991Sheppo 	nodev,			/* cb_dump */
2951991Sheppo 	nodev,			/* cb_read */
2961991Sheppo 	nodev,			/* cb_write */
2971991Sheppo 	nodev,			/* cb_ioctl */
2981991Sheppo 	nodev,			/* cb_devmap */
2991991Sheppo 	nodev,			/* cb_mmap */
3001991Sheppo 	nodev,			/* cb_segmap */
3011991Sheppo 	nochpoll,		/* cb_chpoll */
3021991Sheppo 	ddi_prop_op,		/* cb_prop_op */
3031991Sheppo 	NULL,			/* cb_stream */
3041991Sheppo 	(int)(D_MP)		/* cb_flag */
3051991Sheppo };
3061991Sheppo 
3071991Sheppo static struct dev_ops vnetops = {
3081991Sheppo 	DEVO_REV,		/* devo_rev */
3091991Sheppo 	0,			/* devo_refcnt */
3101991Sheppo 	NULL,			/* devo_getinfo */
3111991Sheppo 	nulldev,		/* devo_identify */
3121991Sheppo 	nulldev,		/* devo_probe */
3131991Sheppo 	vnetattach,		/* devo_attach */
3141991Sheppo 	vnetdetach,		/* devo_detach */
3151991Sheppo 	nodev,			/* devo_reset */
3161991Sheppo 	&cb_vnetops,		/* devo_cb_ops */
3177656SSherry.Moore@Sun.COM 	(struct bus_ops *)NULL,	/* devo_bus_ops */
3187656SSherry.Moore@Sun.COM 	NULL,			/* devo_power */
3197656SSherry.Moore@Sun.COM 	ddi_quiesce_not_supported,	/* devo_quiesce */
3201991Sheppo };
3211991Sheppo 
3221991Sheppo static struct modldrv modldrv = {
3231991Sheppo 	&mod_driverops,		/* Type of module.  This one is a driver */
3241991Sheppo 	vnet_ident,		/* ID string */
3251991Sheppo 	&vnetops		/* driver specific ops */
3261991Sheppo };
3271991Sheppo 
3281991Sheppo static struct modlinkage modlinkage = {
3291991Sheppo 	MODREV_1, (void *)&modldrv, NULL
3301991Sheppo };
3311991Sheppo 
3324647Sraghuram #ifdef DEBUG
3331991Sheppo 
3341991Sheppo /*
3351991Sheppo  * Print debug messages - set to 0xf to enable all msgs
3361991Sheppo  */
3374647Sraghuram int vnet_dbglevel = 0x8;
3381991Sheppo 
3394647Sraghuram static void
3404647Sraghuram debug_printf(const char *fname, void *arg, const char *fmt, ...)
3411991Sheppo {
3421991Sheppo 	char    buf[512];
3431991Sheppo 	va_list ap;
3441991Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
3454647Sraghuram 	char    *bufp = buf;
3461991Sheppo 
3474647Sraghuram 	if (vnetp == NULL) {
3484647Sraghuram 		(void) sprintf(bufp, "%s: ", fname);
3494647Sraghuram 		bufp += strlen(bufp);
3504647Sraghuram 	} else {
3514647Sraghuram 		(void) sprintf(bufp, "vnet%d:%s: ", vnetp->instance, fname);
3524647Sraghuram 		bufp += strlen(bufp);
3534647Sraghuram 	}
3544647Sraghuram 	va_start(ap, fmt);
3554647Sraghuram 	(void) vsprintf(bufp, fmt, ap);
3564647Sraghuram 	va_end(ap);
3574647Sraghuram 	cmn_err(CE_CONT, "%s\n", buf);
3584647Sraghuram }
3591991Sheppo 
3601991Sheppo #endif
3611991Sheppo 
3621991Sheppo /* _init(9E): initialize the loadable module */
3631991Sheppo int
3641991Sheppo _init(void)
3651991Sheppo {
3661991Sheppo 	int status;
3671991Sheppo 
3684647Sraghuram 	DBG1(NULL, "enter\n");
3691991Sheppo 
3701991Sheppo 	mac_init_ops(&vnetops, "vnet");
3711991Sheppo 	status = mod_install(&modlinkage);
3721991Sheppo 	if (status != 0) {
3731991Sheppo 		mac_fini_ops(&vnetops);
3741991Sheppo 	}
3756495Sspeer 	vdds_mod_init();
3769217SWentao.Yang@Sun.COM 	vgen_mod_init();
3774647Sraghuram 	DBG1(NULL, "exit(%d)\n", status);
3781991Sheppo 	return (status);
3791991Sheppo }
3801991Sheppo 
3811991Sheppo /* _fini(9E): prepare the module for unloading. */
3821991Sheppo int
3831991Sheppo _fini(void)
3841991Sheppo {
3859217SWentao.Yang@Sun.COM 	int		status;
3861991Sheppo 
3874647Sraghuram 	DBG1(NULL, "enter\n");
3881991Sheppo 
3899217SWentao.Yang@Sun.COM 	status = vgen_mod_cleanup();
3909217SWentao.Yang@Sun.COM 	if (status != 0)
3919217SWentao.Yang@Sun.COM 		return (status);
3929217SWentao.Yang@Sun.COM 
3931991Sheppo 	status = mod_remove(&modlinkage);
3941991Sheppo 	if (status != 0)
3951991Sheppo 		return (status);
3961991Sheppo 	mac_fini_ops(&vnetops);
3979217SWentao.Yang@Sun.COM 	vgen_mod_fini();
3986495Sspeer 	vdds_mod_fini();
3991991Sheppo 
4004647Sraghuram 	DBG1(NULL, "exit(%d)\n", status);
4011991Sheppo 	return (status);
4021991Sheppo }
4031991Sheppo 
4041991Sheppo /* _info(9E): return information about the loadable module */
4051991Sheppo int
4061991Sheppo _info(struct modinfo *modinfop)
4071991Sheppo {
4081991Sheppo 	return (mod_info(&modlinkage, modinfop));
4091991Sheppo }
4101991Sheppo 
4111991Sheppo /*
4121991Sheppo  * attach(9E): attach a device to the system.
4131991Sheppo  * called once for each instance of the device on the system.
4141991Sheppo  */
4151991Sheppo static int
4161991Sheppo vnetattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
4171991Sheppo {
4189217SWentao.Yang@Sun.COM 	vnet_t			*vnetp;
4199217SWentao.Yang@Sun.COM 	int			status;
4209217SWentao.Yang@Sun.COM 	int			instance;
4219217SWentao.Yang@Sun.COM 	uint64_t		reg;
4229217SWentao.Yang@Sun.COM 	char			qname[TASKQ_NAMELEN];
4239217SWentao.Yang@Sun.COM 	vnet_attach_progress_t	attach_progress;
4241991Sheppo 
4259217SWentao.Yang@Sun.COM 	attach_progress = AST_init;
4261991Sheppo 
4271991Sheppo 	switch (cmd) {
4281991Sheppo 	case DDI_ATTACH:
4291991Sheppo 		break;
4301991Sheppo 	case DDI_RESUME:
4311991Sheppo 	case DDI_PM_RESUME:
4321991Sheppo 	default:
4331991Sheppo 		goto vnet_attach_fail;
4341991Sheppo 	}
4351991Sheppo 
4361991Sheppo 	instance = ddi_get_instance(dip);
4374647Sraghuram 	DBG1(NULL, "instance(%d) enter\n", instance);
4381991Sheppo 
4391991Sheppo 	/* allocate vnet_t and mac_t structures */
4401991Sheppo 	vnetp = kmem_zalloc(sizeof (vnet_t), KM_SLEEP);
4416495Sspeer 	vnetp->dip = dip;
4426495Sspeer 	vnetp->instance = instance;
4436495Sspeer 	rw_init(&vnetp->vrwlock, NULL, RW_DRIVER, NULL);
4446495Sspeer 	rw_init(&vnetp->vsw_fp_rw, NULL, RW_DRIVER, NULL);
4459217SWentao.Yang@Sun.COM 	attach_progress |= AST_vnet_alloc;
4461991Sheppo 
44710309SSriharsha.Basavapatna@Sun.COM 	vnet_ring_grp_init(vnetp);
44810309SSriharsha.Basavapatna@Sun.COM 	attach_progress |= AST_ring_init;
44910309SSriharsha.Basavapatna@Sun.COM 
4506495Sspeer 	status = vdds_init(vnetp);
4516495Sspeer 	if (status != 0) {
4526495Sspeer 		goto vnet_attach_fail;
4536495Sspeer 	}
4549217SWentao.Yang@Sun.COM 	attach_progress |= AST_vdds_init;
4556495Sspeer 
4561991Sheppo 	/* setup links to vnet_t from both devinfo and mac_t */
4571991Sheppo 	ddi_set_driver_private(dip, (caddr_t)vnetp);
4581991Sheppo 
4591991Sheppo 	/* read the mac address */
4601991Sheppo 	status = vnet_read_mac_address(vnetp);
4611991Sheppo 	if (status != DDI_SUCCESS) {
4621991Sheppo 		goto vnet_attach_fail;
4631991Sheppo 	}
4649217SWentao.Yang@Sun.COM 	attach_progress |= AST_read_macaddr;
4651991Sheppo 
4666495Sspeer 	reg = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
4676495Sspeer 	    DDI_PROP_DONTPASS, "reg", -1);
4686495Sspeer 	if (reg == -1) {
4696495Sspeer 		goto vnet_attach_fail;
4706495Sspeer 	}
4716495Sspeer 	vnetp->reg = reg;
4726495Sspeer 
4736495Sspeer 	vnet_fdb_create(vnetp);
4749217SWentao.Yang@Sun.COM 	attach_progress |= AST_fdbh_alloc;
4756495Sspeer 
4766495Sspeer 	(void) snprintf(qname, TASKQ_NAMELEN, "vnet_taskq%d", instance);
4776495Sspeer 	if ((vnetp->taskqp = ddi_taskq_create(dip, qname, 1,
4786495Sspeer 	    TASKQ_DEFAULTPRI, 0)) == NULL) {
4796495Sspeer 		cmn_err(CE_WARN, "!vnet%d: Unable to create task queue",
4806495Sspeer 		    instance);
4816495Sspeer 		goto vnet_attach_fail;
4826495Sspeer 	}
4839217SWentao.Yang@Sun.COM 	attach_progress |= AST_taskq_create;
4846495Sspeer 
4856495Sspeer 	/* add to the list of vnet devices */
4866495Sspeer 	WRITE_ENTER(&vnet_rw);
4876495Sspeer 	vnetp->nextp = vnet_headp;
4886495Sspeer 	vnet_headp = vnetp;
4896495Sspeer 	RW_EXIT(&vnet_rw);
4906495Sspeer 
4919217SWentao.Yang@Sun.COM 	attach_progress |= AST_vnet_list;
4926495Sspeer 
4931991Sheppo 	/*
49410309SSriharsha.Basavapatna@Sun.COM 	 * Initialize the generic vnet plugin which provides communication via
49510309SSriharsha.Basavapatna@Sun.COM 	 * sun4v LDC (logical domain channel) based resources. This involves 2
49610309SSriharsha.Basavapatna@Sun.COM 	 * steps; first, vgen_init() is invoked to read the various properties
49710309SSriharsha.Basavapatna@Sun.COM 	 * of the vnet device from its MD node (including its mtu which is
49810309SSriharsha.Basavapatna@Sun.COM 	 * needed to mac_register()) and obtain a handle to the vgen layer.
49910309SSriharsha.Basavapatna@Sun.COM 	 * After mac_register() is done and we have a mac handle, we then
50010309SSriharsha.Basavapatna@Sun.COM 	 * invoke vgen_init_mdeg() which registers with the the MD event
50110309SSriharsha.Basavapatna@Sun.COM 	 * generator (mdeg) framework to allow LDC resource notifications.
50210309SSriharsha.Basavapatna@Sun.COM 	 * Note: this sequence also allows us to report the correct default #
50310309SSriharsha.Basavapatna@Sun.COM 	 * of pseudo rings (2TX and 3RX) in vnet_m_capab() which gets invoked
50410309SSriharsha.Basavapatna@Sun.COM 	 * in the context of mac_register(); and avoids conflicting with
50510309SSriharsha.Basavapatna@Sun.COM 	 * dynamic pseudo rx rings which get added/removed as a result of mdeg
50610309SSriharsha.Basavapatna@Sun.COM 	 * events in vgen.
5071991Sheppo 	 */
5086495Sspeer 	status = vgen_init(vnetp, reg, vnetp->dip,
5096495Sspeer 	    (uint8_t *)vnetp->curr_macaddr, &vnetp->vgenhdl);
5101991Sheppo 	if (status != DDI_SUCCESS) {
5114647Sraghuram 		DERR(vnetp, "vgen_init() failed\n");
5121991Sheppo 		goto vnet_attach_fail;
5131991Sheppo 	}
5149217SWentao.Yang@Sun.COM 	attach_progress |= AST_vgen_init;
5151991Sheppo 
5161991Sheppo 	status = vnet_mac_register(vnetp);
5171991Sheppo 	if (status != DDI_SUCCESS) {
5181991Sheppo 		goto vnet_attach_fail;
5191991Sheppo 	}
5209336SSriharsha.Basavapatna@Sun.COM 	vnetp->link_state = LINK_STATE_UNKNOWN;
5219217SWentao.Yang@Sun.COM 	attach_progress |= AST_macreg;
5229217SWentao.Yang@Sun.COM 
52310309SSriharsha.Basavapatna@Sun.COM 	status = vgen_init_mdeg(vnetp->vgenhdl);
52410309SSriharsha.Basavapatna@Sun.COM 	if (status != DDI_SUCCESS) {
52510309SSriharsha.Basavapatna@Sun.COM 		goto vnet_attach_fail;
52610309SSriharsha.Basavapatna@Sun.COM 	}
52710309SSriharsha.Basavapatna@Sun.COM 	attach_progress |= AST_init_mdeg;
52810309SSriharsha.Basavapatna@Sun.COM 
5299217SWentao.Yang@Sun.COM 	vnetp->attach_progress = attach_progress;
5309217SWentao.Yang@Sun.COM 
5314647Sraghuram 	DBG1(NULL, "instance(%d) exit\n", instance);
5321991Sheppo 	return (DDI_SUCCESS);
5331991Sheppo 
5341991Sheppo vnet_attach_fail:
5359217SWentao.Yang@Sun.COM 	vnetp->attach_progress = attach_progress;
5369235SWentao.Yang@Sun.COM 	status = vnet_unattach(vnetp);
5379235SWentao.Yang@Sun.COM 	ASSERT(status == 0);
5381991Sheppo 	return (DDI_FAILURE);
5391991Sheppo }
5401991Sheppo 
5411991Sheppo /*
5421991Sheppo  * detach(9E): detach a device from the system.
5431991Sheppo  */
5441991Sheppo static int
5451991Sheppo vnetdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
5461991Sheppo {
5471991Sheppo 	vnet_t		*vnetp;
5481991Sheppo 	int		instance;
5491991Sheppo 
5501991Sheppo 	instance = ddi_get_instance(dip);
5514647Sraghuram 	DBG1(NULL, "instance(%d) enter\n", instance);
5521991Sheppo 
5531991Sheppo 	vnetp = ddi_get_driver_private(dip);
5541991Sheppo 	if (vnetp == NULL) {
5551991Sheppo 		goto vnet_detach_fail;
5561991Sheppo 	}
5571991Sheppo 
5581991Sheppo 	switch (cmd) {
5591991Sheppo 	case DDI_DETACH:
5601991Sheppo 		break;
5611991Sheppo 	case DDI_SUSPEND:
5621991Sheppo 	case DDI_PM_SUSPEND:
5631991Sheppo 	default:
5641991Sheppo 		goto vnet_detach_fail;
5651991Sheppo 	}
5661991Sheppo 
5679217SWentao.Yang@Sun.COM 	if (vnet_unattach(vnetp) != 0) {
5686495Sspeer 		goto vnet_detach_fail;
5692336Snarayan 	}
5702336Snarayan 
5711991Sheppo 	return (DDI_SUCCESS);
5721991Sheppo 
5731991Sheppo vnet_detach_fail:
5741991Sheppo 	return (DDI_FAILURE);
5751991Sheppo }
5761991Sheppo 
5779217SWentao.Yang@Sun.COM /*
5789217SWentao.Yang@Sun.COM  * Common routine to handle vnetattach() failure and vnetdetach(). Note that
5799217SWentao.Yang@Sun.COM  * the only reason this function could fail is if mac_unregister() fails.
5809217SWentao.Yang@Sun.COM  * Otherwise, this function must ensure that all resources are freed and return
5819217SWentao.Yang@Sun.COM  * success.
5829217SWentao.Yang@Sun.COM  */
5839217SWentao.Yang@Sun.COM static int
5849217SWentao.Yang@Sun.COM vnet_unattach(vnet_t *vnetp)
5859217SWentao.Yang@Sun.COM {
5869217SWentao.Yang@Sun.COM 	vnet_attach_progress_t	attach_progress;
5879217SWentao.Yang@Sun.COM 
5889217SWentao.Yang@Sun.COM 	attach_progress = vnetp->attach_progress;
5899217SWentao.Yang@Sun.COM 
5909217SWentao.Yang@Sun.COM 	/*
59110309SSriharsha.Basavapatna@Sun.COM 	 * Disable the mac device in the gldv3 subsystem. This can fail, in
59210309SSriharsha.Basavapatna@Sun.COM 	 * particular if there are still any open references to this mac
59310309SSriharsha.Basavapatna@Sun.COM 	 * device; in which case we just return failure without continuing to
59410309SSriharsha.Basavapatna@Sun.COM 	 * detach further.
59510309SSriharsha.Basavapatna@Sun.COM 	 * If it succeeds, we then invoke vgen_uninit() which should unregister
59610309SSriharsha.Basavapatna@Sun.COM 	 * any pseudo rings registered with the mac layer. Note we keep the
59710309SSriharsha.Basavapatna@Sun.COM 	 * AST_macreg flag on, so we can unregister with the mac layer at
59810309SSriharsha.Basavapatna@Sun.COM 	 * the end of this routine.
5999217SWentao.Yang@Sun.COM 	 */
6009217SWentao.Yang@Sun.COM 	if (attach_progress & AST_macreg) {
60110309SSriharsha.Basavapatna@Sun.COM 		if (mac_disable(vnetp->mh) != 0) {
6029217SWentao.Yang@Sun.COM 			return (1);
6039217SWentao.Yang@Sun.COM 		}
6049217SWentao.Yang@Sun.COM 	}
6059217SWentao.Yang@Sun.COM 
6069217SWentao.Yang@Sun.COM 	/*
60710309SSriharsha.Basavapatna@Sun.COM 	 * Now that we have disabled the device, we must finish all other steps
60810309SSriharsha.Basavapatna@Sun.COM 	 * and successfully return from this function; otherwise we will end up
60910309SSriharsha.Basavapatna@Sun.COM 	 * leaving the device in a broken/unusable state.
6109217SWentao.Yang@Sun.COM 	 *
6119217SWentao.Yang@Sun.COM 	 * First, release any hybrid resources assigned to this vnet device.
6129217SWentao.Yang@Sun.COM 	 */
6139217SWentao.Yang@Sun.COM 	if (attach_progress & AST_vdds_init) {
6149217SWentao.Yang@Sun.COM 		vdds_cleanup(vnetp);
6159217SWentao.Yang@Sun.COM 		attach_progress &= ~AST_vdds_init;
6169217SWentao.Yang@Sun.COM 	}
6179217SWentao.Yang@Sun.COM 
6189217SWentao.Yang@Sun.COM 	/*
6199217SWentao.Yang@Sun.COM 	 * Uninit vgen. This stops further mdeg callbacks to this vnet
6209217SWentao.Yang@Sun.COM 	 * device and/or its ports; and detaches any existing ports.
6219217SWentao.Yang@Sun.COM 	 */
62210309SSriharsha.Basavapatna@Sun.COM 	if (attach_progress & (AST_vgen_init|AST_init_mdeg)) {
6239217SWentao.Yang@Sun.COM 		vgen_uninit(vnetp->vgenhdl);
6249217SWentao.Yang@Sun.COM 		attach_progress &= ~AST_vgen_init;
62510309SSriharsha.Basavapatna@Sun.COM 		attach_progress &= ~AST_init_mdeg;
6269217SWentao.Yang@Sun.COM 	}
6279217SWentao.Yang@Sun.COM 
6289217SWentao.Yang@Sun.COM 	/* Destroy the taskq. */
6299217SWentao.Yang@Sun.COM 	if (attach_progress & AST_taskq_create) {
6309217SWentao.Yang@Sun.COM 		ddi_taskq_destroy(vnetp->taskqp);
6319217SWentao.Yang@Sun.COM 		attach_progress &= ~AST_taskq_create;
6329217SWentao.Yang@Sun.COM 	}
6339217SWentao.Yang@Sun.COM 
6349217SWentao.Yang@Sun.COM 	/* Destroy fdb. */
6359217SWentao.Yang@Sun.COM 	if (attach_progress & AST_fdbh_alloc) {
6369217SWentao.Yang@Sun.COM 		vnet_fdb_destroy(vnetp);
6379217SWentao.Yang@Sun.COM 		attach_progress &= ~AST_fdbh_alloc;
6389217SWentao.Yang@Sun.COM 	}
6399217SWentao.Yang@Sun.COM 
6409217SWentao.Yang@Sun.COM 	/* Remove from the device list */
6419217SWentao.Yang@Sun.COM 	if (attach_progress & AST_vnet_list) {
6429217SWentao.Yang@Sun.COM 		vnet_t		**vnetpp;
6439217SWentao.Yang@Sun.COM 		/* unlink from instance(vnet_t) list */
6449217SWentao.Yang@Sun.COM 		WRITE_ENTER(&vnet_rw);
6459217SWentao.Yang@Sun.COM 		for (vnetpp = &vnet_headp; *vnetpp;
6469217SWentao.Yang@Sun.COM 		    vnetpp = &(*vnetpp)->nextp) {
6479217SWentao.Yang@Sun.COM 			if (*vnetpp == vnetp) {
6489217SWentao.Yang@Sun.COM 				*vnetpp = vnetp->nextp;
6499217SWentao.Yang@Sun.COM 				break;
6509217SWentao.Yang@Sun.COM 			}
6519217SWentao.Yang@Sun.COM 		}
6529217SWentao.Yang@Sun.COM 		RW_EXIT(&vnet_rw);
6539217SWentao.Yang@Sun.COM 		attach_progress &= ~AST_vnet_list;
6549217SWentao.Yang@Sun.COM 	}
6559217SWentao.Yang@Sun.COM 
65610309SSriharsha.Basavapatna@Sun.COM 	if (attach_progress & AST_ring_init) {
65710309SSriharsha.Basavapatna@Sun.COM 		vnet_ring_grp_uninit(vnetp);
65810309SSriharsha.Basavapatna@Sun.COM 		attach_progress &= ~AST_ring_init;
65910309SSriharsha.Basavapatna@Sun.COM 	}
66010309SSriharsha.Basavapatna@Sun.COM 
66110309SSriharsha.Basavapatna@Sun.COM 	if (attach_progress & AST_macreg) {
66210309SSriharsha.Basavapatna@Sun.COM 		VERIFY(mac_unregister(vnetp->mh) == 0);
66310309SSriharsha.Basavapatna@Sun.COM 		vnetp->mh = NULL;
66410309SSriharsha.Basavapatna@Sun.COM 		attach_progress &= ~AST_macreg;
66510309SSriharsha.Basavapatna@Sun.COM 	}
66610309SSriharsha.Basavapatna@Sun.COM 
6679217SWentao.Yang@Sun.COM 	if (attach_progress & AST_vnet_alloc) {
6689217SWentao.Yang@Sun.COM 		rw_destroy(&vnetp->vrwlock);
6699217SWentao.Yang@Sun.COM 		rw_destroy(&vnetp->vsw_fp_rw);
6709217SWentao.Yang@Sun.COM 		attach_progress &= ~AST_vnet_list;
6719217SWentao.Yang@Sun.COM 		KMEM_FREE(vnetp);
6729217SWentao.Yang@Sun.COM 	}
6739217SWentao.Yang@Sun.COM 
6749217SWentao.Yang@Sun.COM 	return (0);
6759217SWentao.Yang@Sun.COM }
6769217SWentao.Yang@Sun.COM 
6771991Sheppo /* enable the device for transmit/receive */
6781991Sheppo static int
6791991Sheppo vnet_m_start(void *arg)
6801991Sheppo {
6811991Sheppo 	vnet_t		*vnetp = arg;
6821991Sheppo 
6834647Sraghuram 	DBG1(vnetp, "enter\n");
6841991Sheppo 
6856495Sspeer 	WRITE_ENTER(&vnetp->vrwlock);
6866495Sspeer 	vnetp->flags |= VNET_STARTED;
6876495Sspeer 	vnet_start_resources(vnetp);
6886495Sspeer 	RW_EXIT(&vnetp->vrwlock);
6891991Sheppo 
6904647Sraghuram 	DBG1(vnetp, "exit\n");
6911991Sheppo 	return (VNET_SUCCESS);
6921991Sheppo 
6931991Sheppo }
6941991Sheppo 
6951991Sheppo /* stop transmit/receive for the device */
6961991Sheppo static void
6971991Sheppo vnet_m_stop(void *arg)
6981991Sheppo {
6991991Sheppo 	vnet_t		*vnetp = arg;
7001991Sheppo 
7014647Sraghuram 	DBG1(vnetp, "enter\n");
7021991Sheppo 
7036495Sspeer 	WRITE_ENTER(&vnetp->vrwlock);
7046495Sspeer 	if (vnetp->flags & VNET_STARTED) {
7059805SSriharsha.Basavapatna@Sun.COM 		/*
7069805SSriharsha.Basavapatna@Sun.COM 		 * Set the flags appropriately; this should prevent starting of
7079805SSriharsha.Basavapatna@Sun.COM 		 * any new resources that are added(see vnet_res_start_task()),
7089805SSriharsha.Basavapatna@Sun.COM 		 * while we release the vrwlock in vnet_stop_resources() before
7099805SSriharsha.Basavapatna@Sun.COM 		 * stopping each resource.
7109805SSriharsha.Basavapatna@Sun.COM 		 */
7119805SSriharsha.Basavapatna@Sun.COM 		vnetp->flags &= ~VNET_STARTED;
7129805SSriharsha.Basavapatna@Sun.COM 		vnetp->flags |= VNET_STOPPING;
7136495Sspeer 		vnet_stop_resources(vnetp);
7149805SSriharsha.Basavapatna@Sun.COM 		vnetp->flags &= ~VNET_STOPPING;
7151991Sheppo 	}
7166495Sspeer 	RW_EXIT(&vnetp->vrwlock);
7171991Sheppo 
7184647Sraghuram 	DBG1(vnetp, "exit\n");
7191991Sheppo }
7201991Sheppo 
7211991Sheppo /* set the unicast mac address of the device */
7221991Sheppo static int
7231991Sheppo vnet_m_unicst(void *arg, const uint8_t *macaddr)
7241991Sheppo {
7251991Sheppo 	_NOTE(ARGUNUSED(macaddr))
7261991Sheppo 
7271991Sheppo 	vnet_t *vnetp = arg;
7281991Sheppo 
7294647Sraghuram 	DBG1(vnetp, "enter\n");
7301991Sheppo 	/*
7312793Slm66018 	 * NOTE: setting mac address dynamically is not supported.
7321991Sheppo 	 */
7334647Sraghuram 	DBG1(vnetp, "exit\n");
7341991Sheppo 
7352109Slm66018 	return (VNET_FAILURE);
7361991Sheppo }
7371991Sheppo 
7381991Sheppo /* enable/disable a multicast address */
7391991Sheppo static int
7401991Sheppo vnet_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
7411991Sheppo {
7421991Sheppo 	_NOTE(ARGUNUSED(add, mca))
7431991Sheppo 
74411543SWentao.Yang@Sun.COM 	vnet_t		*vnetp = arg;
7456495Sspeer 	vnet_res_t	*vresp;
7466495Sspeer 	mac_register_t	*macp;
7472311Sseb 	mac_callbacks_t	*cbp;
74811543SWentao.Yang@Sun.COM 	int		rv = VNET_SUCCESS;
7491991Sheppo 
7504647Sraghuram 	DBG1(vnetp, "enter\n");
7516495Sspeer 
75211543SWentao.Yang@Sun.COM 	READ_ENTER(&vnetp->vsw_fp_rw);
75311543SWentao.Yang@Sun.COM 	if (vnetp->vsw_fp == NULL) {
75411543SWentao.Yang@Sun.COM 		RW_EXIT(&vnetp->vsw_fp_rw);
75511543SWentao.Yang@Sun.COM 		return (EAGAIN);
7561991Sheppo 	}
75711543SWentao.Yang@Sun.COM 	VNET_FDBE_REFHOLD(vnetp->vsw_fp);
75811543SWentao.Yang@Sun.COM 	RW_EXIT(&vnetp->vsw_fp_rw);
75911543SWentao.Yang@Sun.COM 
76011543SWentao.Yang@Sun.COM 	vresp = vnetp->vsw_fp;
76111543SWentao.Yang@Sun.COM 	macp = &vresp->macreg;
76211543SWentao.Yang@Sun.COM 	cbp = macp->m_callbacks;
76311543SWentao.Yang@Sun.COM 	rv = cbp->mc_multicst(macp->m_driver, add, mca);
76411543SWentao.Yang@Sun.COM 
76511543SWentao.Yang@Sun.COM 	VNET_FDBE_REFRELE(vnetp->vsw_fp);
7666495Sspeer 
7674647Sraghuram 	DBG1(vnetp, "exit(%d)\n", rv);
7681991Sheppo 	return (rv);
7691991Sheppo }
7701991Sheppo 
7711991Sheppo /* set or clear promiscuous mode on the device */
7721991Sheppo static int
7731991Sheppo vnet_m_promisc(void *arg, boolean_t on)
7741991Sheppo {
7751991Sheppo 	_NOTE(ARGUNUSED(on))
7761991Sheppo 
7771991Sheppo 	vnet_t *vnetp = arg;
7784647Sraghuram 	DBG1(vnetp, "enter\n");
7791991Sheppo 	/*
7802793Slm66018 	 * NOTE: setting promiscuous mode is not supported, just return success.
7811991Sheppo 	 */
7824647Sraghuram 	DBG1(vnetp, "exit\n");
7831991Sheppo 	return (VNET_SUCCESS);
7841991Sheppo }
7851991Sheppo 
7861991Sheppo /*
7871991Sheppo  * Transmit a chain of packets. This function provides switching functionality
7881991Sheppo  * based on the destination mac address to reach other guests (within ldoms) or
7891991Sheppo  * external hosts.
7901991Sheppo  */
7911991Sheppo mblk_t *
79210309SSriharsha.Basavapatna@Sun.COM vnet_tx_ring_send(void *arg, mblk_t *mp)
7931991Sheppo {
79410309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_tx_ring_t	*tx_ringp;
79511878SVenu.Iyer@Sun.COM 	vnet_tx_ring_stats_t	*statsp;
7966419Ssb155480 	vnet_t			*vnetp;
7976495Sspeer 	vnet_res_t		*vresp;
7986419Ssb155480 	mblk_t			*next;
7996495Sspeer 	mblk_t			*resid_mp;
8006495Sspeer 	mac_register_t		*macp;
8016495Sspeer 	struct ether_header	*ehp;
8026495Sspeer 	boolean_t		is_unicast;
8037896SSriharsha.Basavapatna@Sun.COM 	boolean_t		is_pvid;	/* non-default pvid ? */
8047896SSriharsha.Basavapatna@Sun.COM 	boolean_t		hres;		/* Hybrid resource ? */
80510309SSriharsha.Basavapatna@Sun.COM 	void			*tx_arg;
80611878SVenu.Iyer@Sun.COM 	size_t			size;
80710309SSriharsha.Basavapatna@Sun.COM 
80810309SSriharsha.Basavapatna@Sun.COM 	tx_ringp = (vnet_pseudo_tx_ring_t *)arg;
80911878SVenu.Iyer@Sun.COM 	statsp = &tx_ringp->tx_ring_stats;
81010309SSriharsha.Basavapatna@Sun.COM 	vnetp = (vnet_t *)tx_ringp->vnetp;
8114647Sraghuram 	DBG1(vnetp, "enter\n");
8121991Sheppo 	ASSERT(mp != NULL);
8131991Sheppo 
8147896SSriharsha.Basavapatna@Sun.COM 	is_pvid = (vnetp->pvid != vnetp->default_vlan_id) ? B_TRUE : B_FALSE;
8157896SSriharsha.Basavapatna@Sun.COM 
8161991Sheppo 	while (mp != NULL) {
8176419Ssb155480 
8181991Sheppo 		next = mp->b_next;
8191991Sheppo 		mp->b_next = NULL;
8201991Sheppo 
82111878SVenu.Iyer@Sun.COM 		/* update stats */
82211878SVenu.Iyer@Sun.COM 		size = msgsize(mp);
82311878SVenu.Iyer@Sun.COM 
8246419Ssb155480 		/*
8256419Ssb155480 		 * Find fdb entry for the destination
8266419Ssb155480 		 * and hold a reference to it.
8276419Ssb155480 		 */
8281991Sheppo 		ehp = (struct ether_header *)mp->b_rptr;
8296495Sspeer 		vresp = vnet_fdbe_find(vnetp, &ehp->ether_dhost);
8306495Sspeer 		if (vresp != NULL) {
8311991Sheppo 
8321991Sheppo 			/*
8336419Ssb155480 			 * Destination found in FDB.
8346419Ssb155480 			 * The destination is a vnet device within ldoms
8356419Ssb155480 			 * and directly reachable, invoke the tx function
8366419Ssb155480 			 * in the fdb entry.
8371991Sheppo 			 */
8386495Sspeer 			macp = &vresp->macreg;
8396495Sspeer 			resid_mp = macp->m_callbacks->mc_tx(macp->m_driver, mp);
8406419Ssb155480 
8416419Ssb155480 			/* tx done; now release ref on fdb entry */
8426495Sspeer 			VNET_FDBE_REFRELE(vresp);
8436419Ssb155480 
8441991Sheppo 			if (resid_mp != NULL) {
8451991Sheppo 				/* m_tx failed */
8461991Sheppo 				mp->b_next = next;
8471991Sheppo 				break;
8481991Sheppo 			}
8491991Sheppo 		} else {
8506495Sspeer 			is_unicast = !(IS_BROADCAST(ehp) ||
8516495Sspeer 			    (IS_MULTICAST(ehp)));
8521991Sheppo 			/*
8536419Ssb155480 			 * Destination is not in FDB.
8546495Sspeer 			 * If the destination is broadcast or multicast,
8556495Sspeer 			 * then forward the packet to vswitch.
8566495Sspeer 			 * If a Hybrid resource avilable, then send the
8576495Sspeer 			 * unicast packet via hybrid resource, otherwise
8586495Sspeer 			 * forward it to vswitch.
8591991Sheppo 			 */
8606419Ssb155480 			READ_ENTER(&vnetp->vsw_fp_rw);
8616419Ssb155480 
8626495Sspeer 			if ((is_unicast) && (vnetp->hio_fp != NULL)) {
8636495Sspeer 				vresp = vnetp->hio_fp;
8647896SSriharsha.Basavapatna@Sun.COM 				hres = B_TRUE;
8656495Sspeer 			} else {
8666495Sspeer 				vresp = vnetp->vsw_fp;
8677896SSriharsha.Basavapatna@Sun.COM 				hres = B_FALSE;
8686495Sspeer 			}
8696495Sspeer 			if (vresp == NULL) {
8706419Ssb155480 				/*
8716419Ssb155480 				 * no fdb entry to vsw? drop the packet.
8726419Ssb155480 				 */
8736419Ssb155480 				RW_EXIT(&vnetp->vsw_fp_rw);
8741991Sheppo 				freemsg(mp);
8756419Ssb155480 				mp = next;
8766419Ssb155480 				continue;
8771991Sheppo 			}
8786419Ssb155480 
8796419Ssb155480 			/* ref hold the fdb entry to vsw */
8806495Sspeer 			VNET_FDBE_REFHOLD(vresp);
8816419Ssb155480 
8826419Ssb155480 			RW_EXIT(&vnetp->vsw_fp_rw);
8836419Ssb155480 
8847896SSriharsha.Basavapatna@Sun.COM 			/*
8857896SSriharsha.Basavapatna@Sun.COM 			 * In the case of a hybrid resource we need to insert
8867896SSriharsha.Basavapatna@Sun.COM 			 * the tag for the pvid case here; unlike packets that
8877896SSriharsha.Basavapatna@Sun.COM 			 * are destined to a vnet/vsw in which case the vgen
8887896SSriharsha.Basavapatna@Sun.COM 			 * layer does the tagging before sending it over ldc.
8897896SSriharsha.Basavapatna@Sun.COM 			 */
8907896SSriharsha.Basavapatna@Sun.COM 			if (hres == B_TRUE) {
8917896SSriharsha.Basavapatna@Sun.COM 				/*
8927896SSriharsha.Basavapatna@Sun.COM 				 * Determine if the frame being transmitted
8937896SSriharsha.Basavapatna@Sun.COM 				 * over the hybrid resource is untagged. If so,
8947896SSriharsha.Basavapatna@Sun.COM 				 * insert the tag before transmitting.
8957896SSriharsha.Basavapatna@Sun.COM 				 */
8967896SSriharsha.Basavapatna@Sun.COM 				if (is_pvid == B_TRUE &&
8977896SSriharsha.Basavapatna@Sun.COM 				    ehp->ether_type != htons(ETHERTYPE_VLAN)) {
8987896SSriharsha.Basavapatna@Sun.COM 
8997896SSriharsha.Basavapatna@Sun.COM 					mp = vnet_vlan_insert_tag(mp,
9007896SSriharsha.Basavapatna@Sun.COM 					    vnetp->pvid);
9017896SSriharsha.Basavapatna@Sun.COM 					if (mp == NULL) {
9027896SSriharsha.Basavapatna@Sun.COM 						VNET_FDBE_REFRELE(vresp);
9037896SSriharsha.Basavapatna@Sun.COM 						mp = next;
9047896SSriharsha.Basavapatna@Sun.COM 						continue;
9057896SSriharsha.Basavapatna@Sun.COM 					}
9067896SSriharsha.Basavapatna@Sun.COM 
9077896SSriharsha.Basavapatna@Sun.COM 				}
90810309SSriharsha.Basavapatna@Sun.COM 
90910309SSriharsha.Basavapatna@Sun.COM 				macp = &vresp->macreg;
91010309SSriharsha.Basavapatna@Sun.COM 				tx_arg = tx_ringp;
91110309SSriharsha.Basavapatna@Sun.COM 			} else {
91210309SSriharsha.Basavapatna@Sun.COM 				macp = &vresp->macreg;
91310309SSriharsha.Basavapatna@Sun.COM 				tx_arg = macp->m_driver;
9147896SSriharsha.Basavapatna@Sun.COM 			}
91510309SSriharsha.Basavapatna@Sun.COM 			resid_mp = macp->m_callbacks->mc_tx(tx_arg, mp);
9166419Ssb155480 
9176419Ssb155480 			/* tx done; now release ref on fdb entry */
9186495Sspeer 			VNET_FDBE_REFRELE(vresp);
9196419Ssb155480 
9206419Ssb155480 			if (resid_mp != NULL) {
9216419Ssb155480 				/* m_tx failed */
9226419Ssb155480 				mp->b_next = next;
9236419Ssb155480 				break;
9246419Ssb155480 			}
9251991Sheppo 		}
9261991Sheppo 
92711878SVenu.Iyer@Sun.COM 		statsp->obytes += size;
92811878SVenu.Iyer@Sun.COM 		statsp->opackets++;
9291991Sheppo 		mp = next;
9301991Sheppo 	}
9311991Sheppo 
9324647Sraghuram 	DBG1(vnetp, "exit\n");
9331991Sheppo 	return (mp);
9341991Sheppo }
9351991Sheppo 
9362311Sseb /* get statistics from the device */
9372311Sseb int
9382311Sseb vnet_m_stat(void *arg, uint_t stat, uint64_t *val)
9391991Sheppo {
9401991Sheppo 	vnet_t *vnetp = arg;
9416495Sspeer 	vnet_res_t	*vresp;
9426495Sspeer 	mac_register_t	*macp;
9432311Sseb 	mac_callbacks_t	*cbp;
9442311Sseb 	uint64_t val_total = 0;
9451991Sheppo 
9464647Sraghuram 	DBG1(vnetp, "enter\n");
9471991Sheppo 
9481991Sheppo 	/*
9492311Sseb 	 * get the specified statistic from each transport and return the
9502311Sseb 	 * aggregate val.  This obviously only works for counters.
9511991Sheppo 	 */
9522311Sseb 	if ((IS_MAC_STAT(stat) && !MAC_STAT_ISACOUNTER(stat)) ||
9532311Sseb 	    (IS_MACTYPE_STAT(stat) && !ETHER_STAT_ISACOUNTER(stat))) {
9542311Sseb 		return (ENOTSUP);
9552311Sseb 	}
9566495Sspeer 
9576495Sspeer 	READ_ENTER(&vnetp->vrwlock);
9586495Sspeer 	for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) {
9596495Sspeer 		macp = &vresp->macreg;
9606495Sspeer 		cbp = macp->m_callbacks;
9616495Sspeer 		if (cbp->mc_getstat(macp->m_driver, stat, val) == 0)
9622311Sseb 			val_total += *val;
9631991Sheppo 	}
9646495Sspeer 	RW_EXIT(&vnetp->vrwlock);
9651991Sheppo 
9662311Sseb 	*val = val_total;
9672311Sseb 
9684647Sraghuram 	DBG1(vnetp, "exit\n");
9692311Sseb 	return (0);
9701991Sheppo }
9711991Sheppo 
97210309SSriharsha.Basavapatna@Sun.COM static void
97310309SSriharsha.Basavapatna@Sun.COM vnet_ring_grp_init(vnet_t *vnetp)
97410309SSriharsha.Basavapatna@Sun.COM {
97510309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_rx_group_t	*rx_grp;
97610309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_rx_ring_t	*rx_ringp;
97710309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_tx_group_t	*tx_grp;
97810309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_tx_ring_t	*tx_ringp;
97910309SSriharsha.Basavapatna@Sun.COM 	int			i;
98010309SSriharsha.Basavapatna@Sun.COM 
98110309SSriharsha.Basavapatna@Sun.COM 	tx_grp = &vnetp->tx_grp[0];
98210309SSriharsha.Basavapatna@Sun.COM 	tx_ringp = kmem_zalloc(sizeof (vnet_pseudo_tx_ring_t) *
98310309SSriharsha.Basavapatna@Sun.COM 	    VNET_NUM_PSEUDO_TXRINGS, KM_SLEEP);
98410309SSriharsha.Basavapatna@Sun.COM 	for (i = 0; i < VNET_NUM_PSEUDO_TXRINGS; i++) {
98510309SSriharsha.Basavapatna@Sun.COM 		tx_ringp[i].state |= VNET_TXRING_SHARED;
98610309SSriharsha.Basavapatna@Sun.COM 	}
98710309SSriharsha.Basavapatna@Sun.COM 	tx_grp->rings = tx_ringp;
98810309SSriharsha.Basavapatna@Sun.COM 	tx_grp->ring_cnt = VNET_NUM_PSEUDO_TXRINGS;
98911878SVenu.Iyer@Sun.COM 	mutex_init(&tx_grp->flowctl_lock, NULL, MUTEX_DRIVER, NULL);
99011878SVenu.Iyer@Sun.COM 	cv_init(&tx_grp->flowctl_cv, NULL, CV_DRIVER, NULL);
99111878SVenu.Iyer@Sun.COM 	tx_grp->flowctl_thread = thread_create(NULL, 0,
99211878SVenu.Iyer@Sun.COM 	    vnet_tx_notify_thread, tx_grp, 0, &p0, TS_RUN, minclsyspri);
99310309SSriharsha.Basavapatna@Sun.COM 
99410309SSriharsha.Basavapatna@Sun.COM 	rx_grp = &vnetp->rx_grp[0];
99510309SSriharsha.Basavapatna@Sun.COM 	rx_grp->max_ring_cnt = MAX_RINGS_PER_GROUP;
99610309SSriharsha.Basavapatna@Sun.COM 	rw_init(&rx_grp->lock, NULL, RW_DRIVER, NULL);
99710309SSriharsha.Basavapatna@Sun.COM 	rx_ringp = kmem_zalloc(sizeof (vnet_pseudo_rx_ring_t) *
99810309SSriharsha.Basavapatna@Sun.COM 	    rx_grp->max_ring_cnt, KM_SLEEP);
99910309SSriharsha.Basavapatna@Sun.COM 
100010309SSriharsha.Basavapatna@Sun.COM 	/*
100110309SSriharsha.Basavapatna@Sun.COM 	 * Setup the first 3 Pseudo RX Rings that are reserved;
100210309SSriharsha.Basavapatna@Sun.COM 	 * 1 for LDC resource to vswitch + 2 for RX rings of Hybrid resource.
100310309SSriharsha.Basavapatna@Sun.COM 	 */
100410309SSriharsha.Basavapatna@Sun.COM 	rx_ringp[0].state |= VNET_RXRING_INUSE|VNET_RXRING_LDC_SERVICE;
100510309SSriharsha.Basavapatna@Sun.COM 	rx_ringp[0].index = 0;
100610309SSriharsha.Basavapatna@Sun.COM 	rx_ringp[1].state |= VNET_RXRING_INUSE|VNET_RXRING_HYBRID;
100710309SSriharsha.Basavapatna@Sun.COM 	rx_ringp[1].index = 1;
100810309SSriharsha.Basavapatna@Sun.COM 	rx_ringp[2].state |= VNET_RXRING_INUSE|VNET_RXRING_HYBRID;
100910309SSriharsha.Basavapatna@Sun.COM 	rx_ringp[2].index = 2;
101010309SSriharsha.Basavapatna@Sun.COM 
101110309SSriharsha.Basavapatna@Sun.COM 	rx_grp->ring_cnt = VNET_NUM_PSEUDO_RXRINGS_DEFAULT;
101210309SSriharsha.Basavapatna@Sun.COM 	rx_grp->rings = rx_ringp;
101310309SSriharsha.Basavapatna@Sun.COM 
101410309SSriharsha.Basavapatna@Sun.COM 	for (i = VNET_NUM_PSEUDO_RXRINGS_DEFAULT;
101510309SSriharsha.Basavapatna@Sun.COM 	    i < rx_grp->max_ring_cnt; i++) {
101610309SSriharsha.Basavapatna@Sun.COM 		rx_ringp = &rx_grp->rings[i];
101710309SSriharsha.Basavapatna@Sun.COM 		rx_ringp->state = VNET_RXRING_FREE;
101810309SSriharsha.Basavapatna@Sun.COM 		rx_ringp->index = i;
101910309SSriharsha.Basavapatna@Sun.COM 	}
102010309SSriharsha.Basavapatna@Sun.COM }
102110309SSriharsha.Basavapatna@Sun.COM 
102210309SSriharsha.Basavapatna@Sun.COM static void
102310309SSriharsha.Basavapatna@Sun.COM vnet_ring_grp_uninit(vnet_t *vnetp)
102410309SSriharsha.Basavapatna@Sun.COM {
102510309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_rx_group_t	*rx_grp;
102610309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_tx_group_t	*tx_grp;
102711878SVenu.Iyer@Sun.COM 	kt_did_t		tid = 0;
102810309SSriharsha.Basavapatna@Sun.COM 
102910309SSriharsha.Basavapatna@Sun.COM 	tx_grp = &vnetp->tx_grp[0];
103011878SVenu.Iyer@Sun.COM 
103111878SVenu.Iyer@Sun.COM 	/* Inform tx_notify_thread to exit */
103211878SVenu.Iyer@Sun.COM 	mutex_enter(&tx_grp->flowctl_lock);
103311878SVenu.Iyer@Sun.COM 	if (tx_grp->flowctl_thread != NULL) {
103411878SVenu.Iyer@Sun.COM 		tid = tx_grp->flowctl_thread->t_did;
103511878SVenu.Iyer@Sun.COM 		tx_grp->flowctl_done = B_TRUE;
103611878SVenu.Iyer@Sun.COM 		cv_signal(&tx_grp->flowctl_cv);
103711878SVenu.Iyer@Sun.COM 	}
103811878SVenu.Iyer@Sun.COM 	mutex_exit(&tx_grp->flowctl_lock);
103911878SVenu.Iyer@Sun.COM 	if (tid != 0)
104011878SVenu.Iyer@Sun.COM 		thread_join(tid);
104111878SVenu.Iyer@Sun.COM 
104210309SSriharsha.Basavapatna@Sun.COM 	if (tx_grp->rings != NULL) {
104310309SSriharsha.Basavapatna@Sun.COM 		ASSERT(tx_grp->ring_cnt == VNET_NUM_PSEUDO_TXRINGS);
104410309SSriharsha.Basavapatna@Sun.COM 		kmem_free(tx_grp->rings, sizeof (vnet_pseudo_tx_ring_t) *
104510309SSriharsha.Basavapatna@Sun.COM 		    tx_grp->ring_cnt);
104610309SSriharsha.Basavapatna@Sun.COM 		tx_grp->rings = NULL;
104710309SSriharsha.Basavapatna@Sun.COM 	}
104810309SSriharsha.Basavapatna@Sun.COM 
104910309SSriharsha.Basavapatna@Sun.COM 	rx_grp = &vnetp->rx_grp[0];
105010309SSriharsha.Basavapatna@Sun.COM 	if (rx_grp->rings != NULL) {
105110309SSriharsha.Basavapatna@Sun.COM 		ASSERT(rx_grp->max_ring_cnt == MAX_RINGS_PER_GROUP);
105210309SSriharsha.Basavapatna@Sun.COM 		ASSERT(rx_grp->ring_cnt == VNET_NUM_PSEUDO_RXRINGS_DEFAULT);
105310309SSriharsha.Basavapatna@Sun.COM 		kmem_free(rx_grp->rings, sizeof (vnet_pseudo_rx_ring_t) *
105410309SSriharsha.Basavapatna@Sun.COM 		    rx_grp->max_ring_cnt);
105510309SSriharsha.Basavapatna@Sun.COM 		rx_grp->rings = NULL;
105610309SSriharsha.Basavapatna@Sun.COM 	}
105710309SSriharsha.Basavapatna@Sun.COM }
105810309SSriharsha.Basavapatna@Sun.COM 
105910309SSriharsha.Basavapatna@Sun.COM static vnet_pseudo_rx_ring_t *
106010309SSriharsha.Basavapatna@Sun.COM vnet_alloc_pseudo_rx_ring(vnet_t *vnetp)
106110309SSriharsha.Basavapatna@Sun.COM {
106210309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_rx_group_t  *rx_grp;
106310309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_rx_ring_t	*rx_ringp;
106410309SSriharsha.Basavapatna@Sun.COM 	int			index;
106510309SSriharsha.Basavapatna@Sun.COM 
106610309SSriharsha.Basavapatna@Sun.COM 	rx_grp = &vnetp->rx_grp[0];
106710309SSriharsha.Basavapatna@Sun.COM 	WRITE_ENTER(&rx_grp->lock);
106810309SSriharsha.Basavapatna@Sun.COM 
106910309SSriharsha.Basavapatna@Sun.COM 	if (rx_grp->ring_cnt == rx_grp->max_ring_cnt) {
107010309SSriharsha.Basavapatna@Sun.COM 		/* no rings available */
107110309SSriharsha.Basavapatna@Sun.COM 		RW_EXIT(&rx_grp->lock);
107210309SSriharsha.Basavapatna@Sun.COM 		return (NULL);
107310309SSriharsha.Basavapatna@Sun.COM 	}
107410309SSriharsha.Basavapatna@Sun.COM 
107510309SSriharsha.Basavapatna@Sun.COM 	for (index = VNET_NUM_PSEUDO_RXRINGS_DEFAULT;
107610309SSriharsha.Basavapatna@Sun.COM 	    index < rx_grp->max_ring_cnt; index++) {
107710309SSriharsha.Basavapatna@Sun.COM 		rx_ringp = &rx_grp->rings[index];
107810309SSriharsha.Basavapatna@Sun.COM 		if (rx_ringp->state == VNET_RXRING_FREE) {
107910309SSriharsha.Basavapatna@Sun.COM 			rx_ringp->state |= VNET_RXRING_INUSE;
108010309SSriharsha.Basavapatna@Sun.COM 			rx_grp->ring_cnt++;
108110309SSriharsha.Basavapatna@Sun.COM 			break;
108210309SSriharsha.Basavapatna@Sun.COM 		}
108310309SSriharsha.Basavapatna@Sun.COM 	}
108410309SSriharsha.Basavapatna@Sun.COM 
108510309SSriharsha.Basavapatna@Sun.COM 	RW_EXIT(&rx_grp->lock);
108610309SSriharsha.Basavapatna@Sun.COM 	return (rx_ringp);
108710309SSriharsha.Basavapatna@Sun.COM }
108810309SSriharsha.Basavapatna@Sun.COM 
108910309SSriharsha.Basavapatna@Sun.COM static void
109010309SSriharsha.Basavapatna@Sun.COM vnet_free_pseudo_rx_ring(vnet_t *vnetp, vnet_pseudo_rx_ring_t *ringp)
109110309SSriharsha.Basavapatna@Sun.COM {
109210309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_rx_group_t  *rx_grp;
109310309SSriharsha.Basavapatna@Sun.COM 
109410309SSriharsha.Basavapatna@Sun.COM 	ASSERT(ringp->index >= VNET_NUM_PSEUDO_RXRINGS_DEFAULT);
109510309SSriharsha.Basavapatna@Sun.COM 	rx_grp = &vnetp->rx_grp[0];
109610309SSriharsha.Basavapatna@Sun.COM 	WRITE_ENTER(&rx_grp->lock);
109710309SSriharsha.Basavapatna@Sun.COM 
109810309SSriharsha.Basavapatna@Sun.COM 	if (ringp->state != VNET_RXRING_FREE) {
109910309SSriharsha.Basavapatna@Sun.COM 		ringp->state = VNET_RXRING_FREE;
110010309SSriharsha.Basavapatna@Sun.COM 		ringp->handle = NULL;
110110309SSriharsha.Basavapatna@Sun.COM 		rx_grp->ring_cnt--;
110210309SSriharsha.Basavapatna@Sun.COM 	}
110310309SSriharsha.Basavapatna@Sun.COM 
110410309SSriharsha.Basavapatna@Sun.COM 	RW_EXIT(&rx_grp->lock);
110510309SSriharsha.Basavapatna@Sun.COM }
110610309SSriharsha.Basavapatna@Sun.COM 
11071991Sheppo /* wrapper function for mac_register() */
11081991Sheppo static int
11091991Sheppo vnet_mac_register(vnet_t *vnetp)
11101991Sheppo {
11112311Sseb 	mac_register_t	*macp;
11122311Sseb 	int		err;
11131991Sheppo 
11142311Sseb 	if ((macp = mac_alloc(MAC_VERSION)) == NULL)
11152311Sseb 		return (DDI_FAILURE);
11162311Sseb 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
11172311Sseb 	macp->m_driver = vnetp;
11181991Sheppo 	macp->m_dip = vnetp->dip;
11192311Sseb 	macp->m_src_addr = vnetp->curr_macaddr;
11202311Sseb 	macp->m_callbacks = &vnet_m_callbacks;
11212311Sseb 	macp->m_min_sdu = 0;
11227529SSriharsha.Basavapatna@Sun.COM 	macp->m_max_sdu = vnetp->mtu;
11236419Ssb155480 	macp->m_margin = VLAN_TAGSZ;
11241991Sheppo 
112510309SSriharsha.Basavapatna@Sun.COM 	macp->m_v12n = MAC_VIRT_LEVEL1;
112610309SSriharsha.Basavapatna@Sun.COM 
112710309SSriharsha.Basavapatna@Sun.COM 	/*
11281991Sheppo 	 * Finally, we're ready to register ourselves with the MAC layer
11291991Sheppo 	 * interface; if this succeeds, we're all ready to start()
11301991Sheppo 	 */
11312311Sseb 	err = mac_register(macp, &vnetp->mh);
11322311Sseb 	mac_free(macp);
11332311Sseb 	return (err == 0 ? DDI_SUCCESS : DDI_FAILURE);
11341991Sheppo }
11351991Sheppo 
11361991Sheppo /* read the mac address of the device */
11371991Sheppo static int
11381991Sheppo vnet_read_mac_address(vnet_t *vnetp)
11391991Sheppo {
11401991Sheppo 	uchar_t 	*macaddr;
11411991Sheppo 	uint32_t 	size;
11421991Sheppo 	int 		rv;
11431991Sheppo 
11441991Sheppo 	rv = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, vnetp->dip,
11454650Sraghuram 	    DDI_PROP_DONTPASS, macaddr_propname, &macaddr, &size);
11461991Sheppo 	if ((rv != DDI_PROP_SUCCESS) || (size != ETHERADDRL)) {
11474647Sraghuram 		DWARN(vnetp, "prop_lookup failed(%s) err(%d)\n",
11484647Sraghuram 		    macaddr_propname, rv);
11491991Sheppo 		return (DDI_FAILURE);
11501991Sheppo 	}
11511991Sheppo 	bcopy(macaddr, (caddr_t)vnetp->vendor_addr, ETHERADDRL);
11521991Sheppo 	bcopy(macaddr, (caddr_t)vnetp->curr_macaddr, ETHERADDRL);
11531991Sheppo 	ddi_prop_free(macaddr);
11541991Sheppo 
11551991Sheppo 	return (DDI_SUCCESS);
11561991Sheppo }
11571991Sheppo 
11586419Ssb155480 static void
11596419Ssb155480 vnet_fdb_create(vnet_t *vnetp)
11601991Sheppo {
11616419Ssb155480 	char		hashname[MAXNAMELEN];
11621991Sheppo 
11636419Ssb155480 	(void) snprintf(hashname, MAXNAMELEN, "vnet%d-fdbhash",
11646419Ssb155480 	    vnetp->instance);
11656419Ssb155480 	vnetp->fdb_nchains = vnet_fdb_nchains;
11666419Ssb155480 	vnetp->fdb_hashp = mod_hash_create_ptrhash(hashname, vnetp->fdb_nchains,
11676419Ssb155480 	    mod_hash_null_valdtor, sizeof (void *));
11686419Ssb155480 }
11691991Sheppo 
11706419Ssb155480 static void
11716419Ssb155480 vnet_fdb_destroy(vnet_t *vnetp)
11726419Ssb155480 {
11736419Ssb155480 	/* destroy fdb-hash-table */
11746419Ssb155480 	if (vnetp->fdb_hashp != NULL) {
11756419Ssb155480 		mod_hash_destroy_hash(vnetp->fdb_hashp);
11766419Ssb155480 		vnetp->fdb_hashp = NULL;
11776419Ssb155480 		vnetp->fdb_nchains = 0;
11781991Sheppo 	}
11791991Sheppo }
11801991Sheppo 
11816419Ssb155480 /*
11826419Ssb155480  * Add an entry into the fdb.
11836419Ssb155480  */
11841991Sheppo void
11856495Sspeer vnet_fdbe_add(vnet_t *vnetp, vnet_res_t *vresp)
11861991Sheppo {
11876419Ssb155480 	uint64_t	addr = 0;
11886419Ssb155480 	int		rv;
11896419Ssb155480 
11906495Sspeer 	KEY_HASH(addr, vresp->rem_macaddr);
11911991Sheppo 
11926419Ssb155480 	/*
11936495Sspeer 	 * If the entry being added corresponds to LDC_SERVICE resource,
11946495Sspeer 	 * that is, vswitch connection, it is added to the hash and also
11956495Sspeer 	 * the entry is cached, an additional reference count reflects
11966495Sspeer 	 * this. The HYBRID resource is not added to the hash, but only
11976495Sspeer 	 * cached, as it is only used for sending out packets for unknown
11986495Sspeer 	 * unicast destinations.
11996419Ssb155480 	 */
12006495Sspeer 	(vresp->type == VIO_NET_RES_LDC_SERVICE) ?
12016495Sspeer 	    (vresp->refcnt = 1) : (vresp->refcnt = 0);
12021991Sheppo 
12036419Ssb155480 	/*
12046419Ssb155480 	 * Note: duplicate keys will be rejected by mod_hash.
12056419Ssb155480 	 */
12066495Sspeer 	if (vresp->type != VIO_NET_RES_HYBRID) {
12076495Sspeer 		rv = mod_hash_insert(vnetp->fdb_hashp, (mod_hash_key_t)addr,
12086495Sspeer 		    (mod_hash_val_t)vresp);
12096495Sspeer 		if (rv != 0) {
12106495Sspeer 			DWARN(vnetp, "Duplicate macaddr key(%lx)\n", addr);
12116495Sspeer 			return;
12126495Sspeer 		}
12131991Sheppo 	}
12141991Sheppo 
12156495Sspeer 	if (vresp->type == VIO_NET_RES_LDC_SERVICE) {
12166419Ssb155480 		/* Cache the fdb entry to vsw-port */
12176419Ssb155480 		WRITE_ENTER(&vnetp->vsw_fp_rw);
12186419Ssb155480 		if (vnetp->vsw_fp == NULL)
12196495Sspeer 			vnetp->vsw_fp = vresp;
12206495Sspeer 		RW_EXIT(&vnetp->vsw_fp_rw);
12216495Sspeer 	} else if (vresp->type == VIO_NET_RES_HYBRID) {
12226495Sspeer 		/* Cache the fdb entry to hybrid resource */
12236495Sspeer 		WRITE_ENTER(&vnetp->vsw_fp_rw);
12246495Sspeer 		if (vnetp->hio_fp == NULL)
12256495Sspeer 			vnetp->hio_fp = vresp;
12266419Ssb155480 		RW_EXIT(&vnetp->vsw_fp_rw);
12272793Slm66018 	}
12281991Sheppo }
12291991Sheppo 
12306419Ssb155480 /*
12316419Ssb155480  * Remove an entry from fdb.
12326419Ssb155480  */
12336495Sspeer static void
12346495Sspeer vnet_fdbe_del(vnet_t *vnetp, vnet_res_t *vresp)
12355641Swentaoy {
12366419Ssb155480 	uint64_t	addr = 0;
12376419Ssb155480 	int		rv;
12386419Ssb155480 	uint32_t	refcnt;
12396495Sspeer 	vnet_res_t	*tmp;
12405641Swentaoy 
12416495Sspeer 	KEY_HASH(addr, vresp->rem_macaddr);
12425641Swentaoy 
12436419Ssb155480 	/*
12446419Ssb155480 	 * Remove the entry from fdb hash table.
12456419Ssb155480 	 * This prevents further references to this fdb entry.
12466419Ssb155480 	 */
12476495Sspeer 	if (vresp->type != VIO_NET_RES_HYBRID) {
12486495Sspeer 		rv = mod_hash_remove(vnetp->fdb_hashp, (mod_hash_key_t)addr,
12496495Sspeer 		    (mod_hash_val_t *)&tmp);
12506495Sspeer 		if (rv != 0) {
12516495Sspeer 			/*
12526495Sspeer 			 * As the resources are added to the hash only
12536495Sspeer 			 * after they are started, this can occur if
12546495Sspeer 			 * a resource unregisters before it is ever started.
12556495Sspeer 			 */
12566495Sspeer 			return;
12576495Sspeer 		}
12586495Sspeer 	}
12595641Swentaoy 
12606495Sspeer 	if (vresp->type == VIO_NET_RES_LDC_SERVICE) {
12616419Ssb155480 		WRITE_ENTER(&vnetp->vsw_fp_rw);
12625641Swentaoy 
12636495Sspeer 		ASSERT(tmp == vnetp->vsw_fp);
12646419Ssb155480 		vnetp->vsw_fp = NULL;
12656419Ssb155480 
12666419Ssb155480 		RW_EXIT(&vnetp->vsw_fp_rw);
12676495Sspeer 	} else if (vresp->type == VIO_NET_RES_HYBRID) {
12686495Sspeer 		WRITE_ENTER(&vnetp->vsw_fp_rw);
12696495Sspeer 
12706495Sspeer 		vnetp->hio_fp = NULL;
12716495Sspeer 
12726495Sspeer 		RW_EXIT(&vnetp->vsw_fp_rw);
12735641Swentaoy 	}
12745641Swentaoy 
12755641Swentaoy 	/*
12766419Ssb155480 	 * If there are threads already ref holding before the entry was
12776419Ssb155480 	 * removed from hash table, then wait for ref count to drop to zero.
12785641Swentaoy 	 */
12796495Sspeer 	(vresp->type == VIO_NET_RES_LDC_SERVICE) ?
12806495Sspeer 	    (refcnt = 1) : (refcnt = 0);
12816495Sspeer 	while (vresp->refcnt > refcnt) {
12826419Ssb155480 		delay(drv_usectohz(vnet_fdbe_refcnt_delay));
12836419Ssb155480 	}
12841991Sheppo }
12851991Sheppo 
12866419Ssb155480 /*
12876419Ssb155480  * Search fdb for a given mac address. If an entry is found, hold
12886419Ssb155480  * a reference to it and return the entry; else returns NULL.
12896419Ssb155480  */
12906495Sspeer static vnet_res_t *
12916419Ssb155480 vnet_fdbe_find(vnet_t *vnetp, struct ether_addr *addrp)
12921991Sheppo {
12936419Ssb155480 	uint64_t	key = 0;
12946495Sspeer 	vnet_res_t	*vresp;
12956419Ssb155480 	int		rv;
12966419Ssb155480 
12976495Sspeer 	KEY_HASH(key, addrp->ether_addr_octet);
12986419Ssb155480 
12996419Ssb155480 	rv = mod_hash_find_cb(vnetp->fdb_hashp, (mod_hash_key_t)key,
13006495Sspeer 	    (mod_hash_val_t *)&vresp, vnet_fdbe_find_cb);
13011991Sheppo 
13026419Ssb155480 	if (rv != 0)
13036419Ssb155480 		return (NULL);
13041991Sheppo 
13056495Sspeer 	return (vresp);
13066419Ssb155480 }
13071991Sheppo 
13086419Ssb155480 /*
13096419Ssb155480  * Callback function provided to mod_hash_find_cb(). After finding the fdb
13106419Ssb155480  * entry corresponding to the key (macaddr), this callback will be invoked by
13116419Ssb155480  * mod_hash_find_cb() to atomically increment the reference count on the fdb
13126419Ssb155480  * entry before returning the found entry.
13136419Ssb155480  */
13146419Ssb155480 static void
13156419Ssb155480 vnet_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val)
13166419Ssb155480 {
13176419Ssb155480 	_NOTE(ARGUNUSED(key))
13186495Sspeer 	VNET_FDBE_REFHOLD((vnet_res_t *)val);
13196495Sspeer }
13206495Sspeer 
13217896SSriharsha.Basavapatna@Sun.COM /*
13227896SSriharsha.Basavapatna@Sun.COM  * Frames received that are tagged with the pvid of the vnet device must be
13237896SSriharsha.Basavapatna@Sun.COM  * untagged before sending up the stack. This function walks the chain of rx
13247896SSriharsha.Basavapatna@Sun.COM  * frames, untags any such frames and returns the updated chain.
13257896SSriharsha.Basavapatna@Sun.COM  *
13267896SSriharsha.Basavapatna@Sun.COM  * Arguments:
13277896SSriharsha.Basavapatna@Sun.COM  *    pvid:  pvid of the vnet device for which packets are being received
13287896SSriharsha.Basavapatna@Sun.COM  *    mp:    head of pkt chain to be validated and untagged
13297896SSriharsha.Basavapatna@Sun.COM  *
13307896SSriharsha.Basavapatna@Sun.COM  * Returns:
13317896SSriharsha.Basavapatna@Sun.COM  *    mp:    head of updated chain of packets
13327896SSriharsha.Basavapatna@Sun.COM  */
13337896SSriharsha.Basavapatna@Sun.COM static void
13347896SSriharsha.Basavapatna@Sun.COM vnet_rx_frames_untag(uint16_t pvid, mblk_t **mp)
13357896SSriharsha.Basavapatna@Sun.COM {
13367896SSriharsha.Basavapatna@Sun.COM 	struct ether_vlan_header	*evhp;
13377896SSriharsha.Basavapatna@Sun.COM 	mblk_t				*bp;
13387896SSriharsha.Basavapatna@Sun.COM 	mblk_t				*bpt;
13397896SSriharsha.Basavapatna@Sun.COM 	mblk_t				*bph;
13407896SSriharsha.Basavapatna@Sun.COM 	mblk_t				*bpn;
13417896SSriharsha.Basavapatna@Sun.COM 
13427896SSriharsha.Basavapatna@Sun.COM 	bpn = bph = bpt = NULL;
13437896SSriharsha.Basavapatna@Sun.COM 
13447896SSriharsha.Basavapatna@Sun.COM 	for (bp = *mp; bp != NULL; bp = bpn) {
13457896SSriharsha.Basavapatna@Sun.COM 
13467896SSriharsha.Basavapatna@Sun.COM 		bpn = bp->b_next;
13477896SSriharsha.Basavapatna@Sun.COM 		bp->b_next = bp->b_prev = NULL;
13487896SSriharsha.Basavapatna@Sun.COM 
13497896SSriharsha.Basavapatna@Sun.COM 		evhp = (struct ether_vlan_header *)bp->b_rptr;
13507896SSriharsha.Basavapatna@Sun.COM 
13517896SSriharsha.Basavapatna@Sun.COM 		if (ntohs(evhp->ether_tpid) == ETHERTYPE_VLAN &&
13527896SSriharsha.Basavapatna@Sun.COM 		    VLAN_ID(ntohs(evhp->ether_tci)) == pvid) {
13537896SSriharsha.Basavapatna@Sun.COM 
13547896SSriharsha.Basavapatna@Sun.COM 			bp = vnet_vlan_remove_tag(bp);
13557896SSriharsha.Basavapatna@Sun.COM 			if (bp == NULL) {
13567896SSriharsha.Basavapatna@Sun.COM 				continue;
13577896SSriharsha.Basavapatna@Sun.COM 			}
13587896SSriharsha.Basavapatna@Sun.COM 
13597896SSriharsha.Basavapatna@Sun.COM 		}
13607896SSriharsha.Basavapatna@Sun.COM 
13617896SSriharsha.Basavapatna@Sun.COM 		/* build a chain of processed packets */
13627896SSriharsha.Basavapatna@Sun.COM 		if (bph == NULL) {
13637896SSriharsha.Basavapatna@Sun.COM 			bph = bpt = bp;
13647896SSriharsha.Basavapatna@Sun.COM 		} else {
13657896SSriharsha.Basavapatna@Sun.COM 			bpt->b_next = bp;
13667896SSriharsha.Basavapatna@Sun.COM 			bpt = bp;
13677896SSriharsha.Basavapatna@Sun.COM 		}
13687896SSriharsha.Basavapatna@Sun.COM 
13697896SSriharsha.Basavapatna@Sun.COM 	}
13707896SSriharsha.Basavapatna@Sun.COM 
13717896SSriharsha.Basavapatna@Sun.COM 	*mp = bph;
13727896SSriharsha.Basavapatna@Sun.COM }
13737896SSriharsha.Basavapatna@Sun.COM 
13746495Sspeer static void
13756495Sspeer vnet_rx(vio_net_handle_t vrh, mblk_t *mp)
13766495Sspeer {
137710309SSriharsha.Basavapatna@Sun.COM 	vnet_res_t		*vresp = (vnet_res_t *)vrh;
137810309SSriharsha.Basavapatna@Sun.COM 	vnet_t			*vnetp = vresp->vnetp;
137910309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_rx_ring_t	*ringp;
13807896SSriharsha.Basavapatna@Sun.COM 
13817896SSriharsha.Basavapatna@Sun.COM 	if ((vnetp == NULL) || (vnetp->mh == 0)) {
13827896SSriharsha.Basavapatna@Sun.COM 		freemsgchain(mp);
13837896SSriharsha.Basavapatna@Sun.COM 		return;
13847896SSriharsha.Basavapatna@Sun.COM 	}
13856495Sspeer 
138610309SSriharsha.Basavapatna@Sun.COM 	ringp = vresp->rx_ringp;
138710309SSriharsha.Basavapatna@Sun.COM 	mac_rx_ring(vnetp->mh, ringp->handle, mp, ringp->gen_num);
13881991Sheppo }
13892311Sseb 
13902311Sseb void
13916495Sspeer vnet_tx_update(vio_net_handle_t vrh)
13926495Sspeer {
139310309SSriharsha.Basavapatna@Sun.COM 	vnet_res_t		*vresp = (vnet_res_t *)vrh;
139410309SSriharsha.Basavapatna@Sun.COM 	vnet_t			*vnetp = vresp->vnetp;
139510309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_tx_ring_t	*tx_ringp;
139610309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_tx_group_t	*tx_grp;
139710309SSriharsha.Basavapatna@Sun.COM 	int			i;
139810309SSriharsha.Basavapatna@Sun.COM 
139910309SSriharsha.Basavapatna@Sun.COM 	if (vnetp == NULL || vnetp->mh == NULL) {
140010309SSriharsha.Basavapatna@Sun.COM 		return;
140110309SSriharsha.Basavapatna@Sun.COM 	}
140210309SSriharsha.Basavapatna@Sun.COM 
140310309SSriharsha.Basavapatna@Sun.COM 	/*
140410309SSriharsha.Basavapatna@Sun.COM 	 * Currently, the tx hwring API (used to access rings that belong to
140510309SSriharsha.Basavapatna@Sun.COM 	 * a Hybrid IO resource) does not provide us a per ring flow ctrl
140610309SSriharsha.Basavapatna@Sun.COM 	 * update; also the pseudo rings are shared by the ports/ldcs in the
140710309SSriharsha.Basavapatna@Sun.COM 	 * vgen layer. Thus we can't figure out which pseudo ring is being
140810309SSriharsha.Basavapatna@Sun.COM 	 * re-enabled for transmits. To work around this, when we get a tx
140910309SSriharsha.Basavapatna@Sun.COM 	 * restart notification from below, we simply propagate that to all
141010309SSriharsha.Basavapatna@Sun.COM 	 * the tx pseudo rings registered with the mac layer above.
141110309SSriharsha.Basavapatna@Sun.COM 	 *
141210309SSriharsha.Basavapatna@Sun.COM 	 * There are a couple of side effects with this approach, but they are
141310309SSriharsha.Basavapatna@Sun.COM 	 * not harmful, as outlined below:
141410309SSriharsha.Basavapatna@Sun.COM 	 *
141510309SSriharsha.Basavapatna@Sun.COM 	 * A) We might send an invalid ring_update() for a ring that is not
141610309SSriharsha.Basavapatna@Sun.COM 	 * really flow controlled. This will not have any effect in the mac
141710309SSriharsha.Basavapatna@Sun.COM 	 * layer and packets will continue to be transmitted on that ring.
141810309SSriharsha.Basavapatna@Sun.COM 	 *
141910309SSriharsha.Basavapatna@Sun.COM 	 * B) We might end up clearing the flow control in the mac layer for
142010309SSriharsha.Basavapatna@Sun.COM 	 * a ring that is still flow controlled in the underlying resource.
142110309SSriharsha.Basavapatna@Sun.COM 	 * This will result in the mac layer restarting	transmit, only to be
142210309SSriharsha.Basavapatna@Sun.COM 	 * flow controlled again on that ring.
142310309SSriharsha.Basavapatna@Sun.COM 	 */
142410309SSriharsha.Basavapatna@Sun.COM 	tx_grp = &vnetp->tx_grp[0];
142510309SSriharsha.Basavapatna@Sun.COM 	for (i = 0; i < tx_grp->ring_cnt; i++) {
142610309SSriharsha.Basavapatna@Sun.COM 		tx_ringp = &tx_grp->rings[i];
142710309SSriharsha.Basavapatna@Sun.COM 		mac_tx_ring_update(vnetp->mh, tx_ringp->handle);
14286495Sspeer 	}
14296495Sspeer }
14306495Sspeer 
14316495Sspeer /*
143211878SVenu.Iyer@Sun.COM  * vnet_tx_notify_thread:
143311878SVenu.Iyer@Sun.COM  *
143411878SVenu.Iyer@Sun.COM  * vnet_tx_ring_update() callback function wakes up this thread when
143511878SVenu.Iyer@Sun.COM  * it gets called. This thread will call mac_tx_ring_update() to
143611878SVenu.Iyer@Sun.COM  * notify upper mac of flow control getting relieved. Note that
143711878SVenu.Iyer@Sun.COM  * vnet_tx_ring_update() cannot call mac_tx_ring_update() directly
143811878SVenu.Iyer@Sun.COM  * because vnet_tx_ring_update() is called from lower mac with
143911878SVenu.Iyer@Sun.COM  * mi_rw_lock held and mac_tx_ring_update() would also try to grab
144011878SVenu.Iyer@Sun.COM  * the same lock.
144111878SVenu.Iyer@Sun.COM  */
144211878SVenu.Iyer@Sun.COM static void
144311878SVenu.Iyer@Sun.COM vnet_tx_notify_thread(void *arg)
144411878SVenu.Iyer@Sun.COM {
144511878SVenu.Iyer@Sun.COM 	callb_cpr_t		cprinfo;
144611878SVenu.Iyer@Sun.COM 	vnet_pseudo_tx_group_t	*tx_grp = (vnet_pseudo_tx_group_t *)arg;
144711878SVenu.Iyer@Sun.COM 	vnet_pseudo_tx_ring_t	*tx_ringp;
144811878SVenu.Iyer@Sun.COM 	vnet_t			*vnetp;
144911878SVenu.Iyer@Sun.COM 	int			i;
145011878SVenu.Iyer@Sun.COM 
145111878SVenu.Iyer@Sun.COM 	CALLB_CPR_INIT(&cprinfo, &tx_grp->flowctl_lock, callb_generic_cpr,
145211878SVenu.Iyer@Sun.COM 	    "vnet_tx_notify_thread");
145311878SVenu.Iyer@Sun.COM 
145411878SVenu.Iyer@Sun.COM 	mutex_enter(&tx_grp->flowctl_lock);
145511878SVenu.Iyer@Sun.COM 	while (!tx_grp->flowctl_done) {
145611878SVenu.Iyer@Sun.COM 		CALLB_CPR_SAFE_BEGIN(&cprinfo);
145711878SVenu.Iyer@Sun.COM 		cv_wait(&tx_grp->flowctl_cv, &tx_grp->flowctl_lock);
145811878SVenu.Iyer@Sun.COM 		CALLB_CPR_SAFE_END(&cprinfo, &tx_grp->flowctl_lock);
145911878SVenu.Iyer@Sun.COM 
146011878SVenu.Iyer@Sun.COM 		for (i = 0; i < tx_grp->ring_cnt; i++) {
146111878SVenu.Iyer@Sun.COM 			tx_ringp = &tx_grp->rings[i];
146211878SVenu.Iyer@Sun.COM 			if (tx_ringp->woken_up) {
146311878SVenu.Iyer@Sun.COM 				tx_ringp->woken_up = B_FALSE;
146411878SVenu.Iyer@Sun.COM 				vnetp = tx_ringp->vnetp;
146511878SVenu.Iyer@Sun.COM 				mac_tx_ring_update(vnetp->mh, tx_ringp->handle);
146611878SVenu.Iyer@Sun.COM 			}
146711878SVenu.Iyer@Sun.COM 		}
146811878SVenu.Iyer@Sun.COM 	}
146911878SVenu.Iyer@Sun.COM 	/*
147011878SVenu.Iyer@Sun.COM 	 * The tx_grp is being destroyed, exit the thread.
147111878SVenu.Iyer@Sun.COM 	 */
147211878SVenu.Iyer@Sun.COM 	tx_grp->flowctl_thread = NULL;
147311878SVenu.Iyer@Sun.COM 	CALLB_CPR_EXIT(&cprinfo);
147411878SVenu.Iyer@Sun.COM 	thread_exit();
147511878SVenu.Iyer@Sun.COM }
147611878SVenu.Iyer@Sun.COM 
147711878SVenu.Iyer@Sun.COM void
147811878SVenu.Iyer@Sun.COM vnet_tx_ring_update(void *arg1, uintptr_t arg2)
147911878SVenu.Iyer@Sun.COM {
148011878SVenu.Iyer@Sun.COM 	vnet_t			*vnetp = (vnet_t *)arg1;
148111878SVenu.Iyer@Sun.COM 	vnet_pseudo_tx_group_t	*tx_grp;
148211878SVenu.Iyer@Sun.COM 	vnet_pseudo_tx_ring_t	*tx_ringp;
148311878SVenu.Iyer@Sun.COM 	int			i;
148411878SVenu.Iyer@Sun.COM 
148511878SVenu.Iyer@Sun.COM 	tx_grp = &vnetp->tx_grp[0];
148611878SVenu.Iyer@Sun.COM 	for (i = 0; i < tx_grp->ring_cnt; i++) {
148711878SVenu.Iyer@Sun.COM 		tx_ringp = &tx_grp->rings[i];
148811878SVenu.Iyer@Sun.COM 		if (tx_ringp->hw_rh == (mac_ring_handle_t)arg2) {
148911878SVenu.Iyer@Sun.COM 			mutex_enter(&tx_grp->flowctl_lock);
149011878SVenu.Iyer@Sun.COM 			tx_ringp->woken_up = B_TRUE;
149111878SVenu.Iyer@Sun.COM 			cv_signal(&tx_grp->flowctl_cv);
149211878SVenu.Iyer@Sun.COM 			mutex_exit(&tx_grp->flowctl_lock);
149311878SVenu.Iyer@Sun.COM 			break;
149411878SVenu.Iyer@Sun.COM 		}
149511878SVenu.Iyer@Sun.COM 	}
149611878SVenu.Iyer@Sun.COM }
149711878SVenu.Iyer@Sun.COM 
149811878SVenu.Iyer@Sun.COM /*
14997529SSriharsha.Basavapatna@Sun.COM  * Update the new mtu of vnet into the mac layer. First check if the device has
15007529SSriharsha.Basavapatna@Sun.COM  * been plumbed and if so fail the mtu update. Returns 0 on success.
15017529SSriharsha.Basavapatna@Sun.COM  */
15027529SSriharsha.Basavapatna@Sun.COM int
15037529SSriharsha.Basavapatna@Sun.COM vnet_mtu_update(vnet_t *vnetp, uint32_t mtu)
15047529SSriharsha.Basavapatna@Sun.COM {
15057529SSriharsha.Basavapatna@Sun.COM 	int	rv;
15067529SSriharsha.Basavapatna@Sun.COM 
15077529SSriharsha.Basavapatna@Sun.COM 	if (vnetp == NULL || vnetp->mh == NULL) {
15087529SSriharsha.Basavapatna@Sun.COM 		return (EINVAL);
15097529SSriharsha.Basavapatna@Sun.COM 	}
15107529SSriharsha.Basavapatna@Sun.COM 
15117529SSriharsha.Basavapatna@Sun.COM 	WRITE_ENTER(&vnetp->vrwlock);
15127529SSriharsha.Basavapatna@Sun.COM 
15137529SSriharsha.Basavapatna@Sun.COM 	if (vnetp->flags & VNET_STARTED) {
15147529SSriharsha.Basavapatna@Sun.COM 		RW_EXIT(&vnetp->vrwlock);
15157529SSriharsha.Basavapatna@Sun.COM 		cmn_err(CE_NOTE, "!vnet%d: Unable to process mtu "
15167529SSriharsha.Basavapatna@Sun.COM 		    "update as the device is plumbed\n",
15177529SSriharsha.Basavapatna@Sun.COM 		    vnetp->instance);
15187529SSriharsha.Basavapatna@Sun.COM 		return (EBUSY);
15197529SSriharsha.Basavapatna@Sun.COM 	}
15207529SSriharsha.Basavapatna@Sun.COM 
15217529SSriharsha.Basavapatna@Sun.COM 	/* update mtu in the mac layer */
15227529SSriharsha.Basavapatna@Sun.COM 	rv = mac_maxsdu_update(vnetp->mh, mtu);
15237529SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
15247529SSriharsha.Basavapatna@Sun.COM 		RW_EXIT(&vnetp->vrwlock);
15257529SSriharsha.Basavapatna@Sun.COM 		cmn_err(CE_NOTE,
15267529SSriharsha.Basavapatna@Sun.COM 		    "!vnet%d: Unable to update mtu with mac layer\n",
15277529SSriharsha.Basavapatna@Sun.COM 		    vnetp->instance);
15287529SSriharsha.Basavapatna@Sun.COM 		return (EIO);
15297529SSriharsha.Basavapatna@Sun.COM 	}
15307529SSriharsha.Basavapatna@Sun.COM 
15317529SSriharsha.Basavapatna@Sun.COM 	vnetp->mtu = mtu;
15327529SSriharsha.Basavapatna@Sun.COM 
15337529SSriharsha.Basavapatna@Sun.COM 	RW_EXIT(&vnetp->vrwlock);
15347529SSriharsha.Basavapatna@Sun.COM 
15357529SSriharsha.Basavapatna@Sun.COM 	return (0);
15367529SSriharsha.Basavapatna@Sun.COM }
15377529SSriharsha.Basavapatna@Sun.COM 
15387529SSriharsha.Basavapatna@Sun.COM /*
15399336SSriharsha.Basavapatna@Sun.COM  * Update the link state of vnet to the mac layer.
15409336SSriharsha.Basavapatna@Sun.COM  */
15419336SSriharsha.Basavapatna@Sun.COM void
15429336SSriharsha.Basavapatna@Sun.COM vnet_link_update(vnet_t *vnetp, link_state_t link_state)
15439336SSriharsha.Basavapatna@Sun.COM {
15449336SSriharsha.Basavapatna@Sun.COM 	if (vnetp == NULL || vnetp->mh == NULL) {
15459336SSriharsha.Basavapatna@Sun.COM 		return;
15469336SSriharsha.Basavapatna@Sun.COM 	}
15479336SSriharsha.Basavapatna@Sun.COM 
15489336SSriharsha.Basavapatna@Sun.COM 	WRITE_ENTER(&vnetp->vrwlock);
15499336SSriharsha.Basavapatna@Sun.COM 	if (vnetp->link_state == link_state) {
15509336SSriharsha.Basavapatna@Sun.COM 		RW_EXIT(&vnetp->vrwlock);
15519336SSriharsha.Basavapatna@Sun.COM 		return;
15529336SSriharsha.Basavapatna@Sun.COM 	}
15539336SSriharsha.Basavapatna@Sun.COM 	vnetp->link_state = link_state;
15549336SSriharsha.Basavapatna@Sun.COM 	RW_EXIT(&vnetp->vrwlock);
15559336SSriharsha.Basavapatna@Sun.COM 
15569336SSriharsha.Basavapatna@Sun.COM 	mac_link_update(vnetp->mh, link_state);
15579336SSriharsha.Basavapatna@Sun.COM }
15589336SSriharsha.Basavapatna@Sun.COM 
15599336SSriharsha.Basavapatna@Sun.COM /*
15606495Sspeer  * vio_net_resource_reg -- An interface called to register a resource
15616495Sspeer  *	with vnet.
15626495Sspeer  *	macp -- a GLDv3 mac_register that has all the details of
15636495Sspeer  *		a resource and its callbacks etc.
15646495Sspeer  *	type -- resource type.
15656495Sspeer  *	local_macaddr -- resource's MAC address. This is used to
15666495Sspeer  *			 associate a resource with a corresponding vnet.
15676495Sspeer  *	remote_macaddr -- remote side MAC address. This is ignored for
15686495Sspeer  *			  the Hybrid resources.
15696495Sspeer  *	vhp -- A handle returned to the caller.
15706495Sspeer  *	vcb -- A set of callbacks provided to the callers.
15716495Sspeer  */
15726495Sspeer int vio_net_resource_reg(mac_register_t *macp, vio_net_res_type_t type,
15736495Sspeer     ether_addr_t local_macaddr, ether_addr_t rem_macaddr, vio_net_handle_t *vhp,
15746495Sspeer     vio_net_callbacks_t *vcb)
15756495Sspeer {
157610309SSriharsha.Basavapatna@Sun.COM 	vnet_t		*vnetp;
157710309SSriharsha.Basavapatna@Sun.COM 	vnet_res_t	*vresp;
15786495Sspeer 
15796495Sspeer 	vresp = kmem_zalloc(sizeof (vnet_res_t), KM_SLEEP);
15806495Sspeer 	ether_copy(local_macaddr, vresp->local_macaddr);
15816495Sspeer 	ether_copy(rem_macaddr, vresp->rem_macaddr);
15826495Sspeer 	vresp->type = type;
15836495Sspeer 	bcopy(macp, &vresp->macreg, sizeof (mac_register_t));
15846495Sspeer 
15856495Sspeer 	DBG1(NULL, "Resource Registerig type=0%X\n", type);
15866495Sspeer 
15876495Sspeer 	READ_ENTER(&vnet_rw);
15886495Sspeer 	vnetp = vnet_headp;
15896495Sspeer 	while (vnetp != NULL) {
15906495Sspeer 		if (VNET_MATCH_RES(vresp, vnetp)) {
15918332SWentao.Yang@Sun.COM 			vresp->vnetp = vnetp;
15928332SWentao.Yang@Sun.COM 
15938332SWentao.Yang@Sun.COM 			/* Setup kstats for hio resource */
15948332SWentao.Yang@Sun.COM 			if (vresp->type == VIO_NET_RES_HYBRID) {
15958332SWentao.Yang@Sun.COM 				vresp->ksp = vnet_hio_setup_kstats(DRV_NAME,
15968332SWentao.Yang@Sun.COM 				    "hio", vresp);
15978332SWentao.Yang@Sun.COM 				if (vresp->ksp == NULL) {
15988332SWentao.Yang@Sun.COM 					cmn_err(CE_NOTE, "!vnet%d: Cannot "
15998332SWentao.Yang@Sun.COM 					    "create kstats for hio resource",
16008332SWentao.Yang@Sun.COM 					    vnetp->instance);
16018332SWentao.Yang@Sun.COM 				}
16028332SWentao.Yang@Sun.COM 			}
160310309SSriharsha.Basavapatna@Sun.COM 			vnet_add_resource(vnetp, vresp);
16046495Sspeer 			break;
16056495Sspeer 		}
16066495Sspeer 		vnetp = vnetp->nextp;
16076495Sspeer 	}
16086495Sspeer 	RW_EXIT(&vnet_rw);
16096495Sspeer 	if (vresp->vnetp == NULL) {
16106495Sspeer 		DWARN(NULL, "No vnet instance");
16116495Sspeer 		kmem_free(vresp, sizeof (vnet_res_t));
16126495Sspeer 		return (ENXIO);
16136495Sspeer 	}
16146495Sspeer 
16156495Sspeer 	*vhp = vresp;
16166495Sspeer 	vcb->vio_net_rx_cb = vnet_rx;
16176495Sspeer 	vcb->vio_net_tx_update = vnet_tx_update;
16186495Sspeer 	vcb->vio_net_report_err = vnet_handle_res_err;
16196495Sspeer 
162010309SSriharsha.Basavapatna@Sun.COM 	/* Bind the resource to pseudo ring(s) */
162110309SSriharsha.Basavapatna@Sun.COM 	if (vnet_bind_rings(vresp) != 0) {
162210309SSriharsha.Basavapatna@Sun.COM 		(void) vnet_rem_resource(vnetp, vresp);
162310309SSriharsha.Basavapatna@Sun.COM 		vnet_hio_destroy_kstats(vresp->ksp);
162410309SSriharsha.Basavapatna@Sun.COM 		KMEM_FREE(vresp);
162510309SSriharsha.Basavapatna@Sun.COM 		return (1);
162610309SSriharsha.Basavapatna@Sun.COM 	}
162710309SSriharsha.Basavapatna@Sun.COM 
16286495Sspeer 	/* Dispatch a task to start resources */
16296495Sspeer 	vnet_dispatch_res_task(vnetp);
16306495Sspeer 	return (0);
16316495Sspeer }
16326495Sspeer 
16336495Sspeer /*
16346495Sspeer  * vio_net_resource_unreg -- An interface to unregister a resource.
16356495Sspeer  */
16366495Sspeer void
16376495Sspeer vio_net_resource_unreg(vio_net_handle_t vhp)
16386495Sspeer {
16399805SSriharsha.Basavapatna@Sun.COM 	vnet_res_t	*vresp = (vnet_res_t *)vhp;
16409805SSriharsha.Basavapatna@Sun.COM 	vnet_t		*vnetp = vresp->vnetp;
16416495Sspeer 
16426495Sspeer 	DBG1(NULL, "Resource Registerig hdl=0x%p", vhp);
16436495Sspeer 
16446495Sspeer 	ASSERT(vnetp != NULL);
16459805SSriharsha.Basavapatna@Sun.COM 	/*
16469805SSriharsha.Basavapatna@Sun.COM 	 * Remove the resource from fdb; this ensures
16479805SSriharsha.Basavapatna@Sun.COM 	 * there are no references to the resource.
16489805SSriharsha.Basavapatna@Sun.COM 	 */
16496495Sspeer 	vnet_fdbe_del(vnetp, vresp);
16506495Sspeer 
165110309SSriharsha.Basavapatna@Sun.COM 	vnet_unbind_rings(vresp);
165210309SSriharsha.Basavapatna@Sun.COM 
16539805SSriharsha.Basavapatna@Sun.COM 	/* Now remove the resource from the list */
165410309SSriharsha.Basavapatna@Sun.COM 	(void) vnet_rem_resource(vnetp, vresp);
165510309SSriharsha.Basavapatna@Sun.COM 
165610309SSriharsha.Basavapatna@Sun.COM 	vnet_hio_destroy_kstats(vresp->ksp);
165710309SSriharsha.Basavapatna@Sun.COM 	KMEM_FREE(vresp);
165810309SSriharsha.Basavapatna@Sun.COM }
165910309SSriharsha.Basavapatna@Sun.COM 
166010309SSriharsha.Basavapatna@Sun.COM static void
166110309SSriharsha.Basavapatna@Sun.COM vnet_add_resource(vnet_t *vnetp, vnet_res_t *vresp)
166210309SSriharsha.Basavapatna@Sun.COM {
166310309SSriharsha.Basavapatna@Sun.COM 	WRITE_ENTER(&vnetp->vrwlock);
166410309SSriharsha.Basavapatna@Sun.COM 	vresp->nextp = vnetp->vres_list;
166510309SSriharsha.Basavapatna@Sun.COM 	vnetp->vres_list = vresp;
166610309SSriharsha.Basavapatna@Sun.COM 	RW_EXIT(&vnetp->vrwlock);
166710309SSriharsha.Basavapatna@Sun.COM }
166810309SSriharsha.Basavapatna@Sun.COM 
166910309SSriharsha.Basavapatna@Sun.COM static vnet_res_t *
167010309SSriharsha.Basavapatna@Sun.COM vnet_rem_resource(vnet_t *vnetp, vnet_res_t *vresp)
167110309SSriharsha.Basavapatna@Sun.COM {
167210309SSriharsha.Basavapatna@Sun.COM 	vnet_res_t	*vrp;
167310309SSriharsha.Basavapatna@Sun.COM 
16746495Sspeer 	WRITE_ENTER(&vnetp->vrwlock);
16756495Sspeer 	if (vresp == vnetp->vres_list) {
16766495Sspeer 		vnetp->vres_list = vresp->nextp;
16776495Sspeer 	} else {
16786495Sspeer 		vrp = vnetp->vres_list;
16796495Sspeer 		while (vrp->nextp != NULL) {
16806495Sspeer 			if (vrp->nextp == vresp) {
16816495Sspeer 				vrp->nextp = vresp->nextp;
16826495Sspeer 				break;
16836495Sspeer 			}
16846495Sspeer 			vrp = vrp->nextp;
16856495Sspeer 		}
16866495Sspeer 	}
16876495Sspeer 	vresp->vnetp = NULL;
16886495Sspeer 	vresp->nextp = NULL;
168910309SSriharsha.Basavapatna@Sun.COM 
16906495Sspeer 	RW_EXIT(&vnetp->vrwlock);
169110309SSriharsha.Basavapatna@Sun.COM 
169210309SSriharsha.Basavapatna@Sun.COM 	return (vresp);
16936495Sspeer }
16946495Sspeer 
16956495Sspeer /*
16966495Sspeer  * vnet_dds_rx -- an interface called by vgen to DDS messages.
16976495Sspeer  */
16986495Sspeer void
16996495Sspeer vnet_dds_rx(void *arg, void *dmsg)
17002311Sseb {
17012311Sseb 	vnet_t *vnetp = arg;
17026495Sspeer 	vdds_process_dds_msg(vnetp, dmsg);
17032311Sseb }
17042311Sseb 
17056495Sspeer /*
17066495Sspeer  * vnet_send_dds_msg -- An interface provided to DDS to send
17076495Sspeer  *	DDS messages. This simply sends meessages via vgen.
17086495Sspeer  */
17096495Sspeer int
17106495Sspeer vnet_send_dds_msg(vnet_t *vnetp, void *dmsg)
17116495Sspeer {
17126495Sspeer 	int rv;
17136495Sspeer 
17146495Sspeer 	if (vnetp->vgenhdl != NULL) {
17156495Sspeer 		rv = vgen_dds_tx(vnetp->vgenhdl, dmsg);
17166495Sspeer 	}
17176495Sspeer 	return (rv);
17186495Sspeer }
17196495Sspeer 
17206495Sspeer /*
17219647SWentao.Yang@Sun.COM  * vnet_cleanup_hio -- an interface called by vgen to cleanup hio resources.
17229647SWentao.Yang@Sun.COM  */
17239647SWentao.Yang@Sun.COM void
17249647SWentao.Yang@Sun.COM vnet_dds_cleanup_hio(vnet_t *vnetp)
17259647SWentao.Yang@Sun.COM {
17269647SWentao.Yang@Sun.COM 	vdds_cleanup_hio(vnetp);
17279647SWentao.Yang@Sun.COM }
17289647SWentao.Yang@Sun.COM 
17299647SWentao.Yang@Sun.COM /*
17306495Sspeer  * vnet_handle_res_err -- A callback function called by a resource
17316495Sspeer  *	to report an error. For example, vgen can call to report
17326495Sspeer  *	an LDC down/reset event. This will trigger cleanup of associated
17336495Sspeer  *	Hybrid resource.
17346495Sspeer  */
17356495Sspeer /* ARGSUSED */
17366495Sspeer static void
17376495Sspeer vnet_handle_res_err(vio_net_handle_t vrh, vio_net_err_val_t err)
17386495Sspeer {
17396495Sspeer 	vnet_res_t *vresp = (vnet_res_t *)vrh;
17406495Sspeer 	vnet_t *vnetp = vresp->vnetp;
17416495Sspeer 
17426495Sspeer 	if (vnetp == NULL) {
17436495Sspeer 		return;
17446495Sspeer 	}
17456495Sspeer 	if ((vresp->type != VIO_NET_RES_LDC_SERVICE) &&
17466495Sspeer 	    (vresp->type != VIO_NET_RES_HYBRID)) {
17476495Sspeer 		return;
17486495Sspeer 	}
17499647SWentao.Yang@Sun.COM 
17509647SWentao.Yang@Sun.COM 	vdds_cleanup_hio(vnetp);
17516495Sspeer }
17526495Sspeer 
17536495Sspeer /*
17546495Sspeer  * vnet_dispatch_res_task -- A function to dispatch tasks start resources.
17556495Sspeer  */
17566495Sspeer static void
17576495Sspeer vnet_dispatch_res_task(vnet_t *vnetp)
17586495Sspeer {
17596495Sspeer 	int rv;
17606495Sspeer 
17619677SZachary.Kissel@Sun.COM 	/*
17629677SZachary.Kissel@Sun.COM 	 * Dispatch the task. It could be the case that vnetp->flags does
17639677SZachary.Kissel@Sun.COM 	 * not have VNET_STARTED set. This is ok as vnet_rest_start_task()
17649805SSriharsha.Basavapatna@Sun.COM 	 * can abort the task when the task is started. See related comments
17659805SSriharsha.Basavapatna@Sun.COM 	 * in vnet_m_stop() and vnet_stop_resources().
17669677SZachary.Kissel@Sun.COM 	 */
17679677SZachary.Kissel@Sun.COM 	rv = ddi_taskq_dispatch(vnetp->taskqp, vnet_res_start_task,
17689677SZachary.Kissel@Sun.COM 	    vnetp, DDI_NOSLEEP);
17699677SZachary.Kissel@Sun.COM 	if (rv != DDI_SUCCESS) {
17709677SZachary.Kissel@Sun.COM 		cmn_err(CE_WARN,
17719677SZachary.Kissel@Sun.COM 		    "vnet%d:Can't dispatch start resource task",
17729677SZachary.Kissel@Sun.COM 		    vnetp->instance);
17736495Sspeer 	}
17746495Sspeer }
17756495Sspeer 
17766495Sspeer /*
17776495Sspeer  * vnet_res_start_task -- A taskq callback function that starts a resource.
17786495Sspeer  */
17796495Sspeer static void
17806495Sspeer vnet_res_start_task(void *arg)
17812311Sseb {
17822311Sseb 	vnet_t *vnetp = arg;
17836495Sspeer 
17846495Sspeer 	WRITE_ENTER(&vnetp->vrwlock);
17856495Sspeer 	if (vnetp->flags & VNET_STARTED) {
17866495Sspeer 		vnet_start_resources(vnetp);
17876495Sspeer 	}
17886495Sspeer 	RW_EXIT(&vnetp->vrwlock);
17892311Sseb }
17906495Sspeer 
17916495Sspeer /*
17926495Sspeer  * vnet_start_resources -- starts all resources associated with
17936495Sspeer  *	a vnet.
17946495Sspeer  */
17956495Sspeer static void
17966495Sspeer vnet_start_resources(vnet_t *vnetp)
17976495Sspeer {
17986495Sspeer 	mac_register_t	*macp;
17996495Sspeer 	mac_callbacks_t	*cbp;
18006495Sspeer 	vnet_res_t	*vresp;
18016495Sspeer 	int rv;
18026495Sspeer 
18036495Sspeer 	DBG1(vnetp, "enter\n");
18046495Sspeer 
18059805SSriharsha.Basavapatna@Sun.COM 	ASSERT(RW_WRITE_HELD(&vnetp->vrwlock));
18069805SSriharsha.Basavapatna@Sun.COM 
18076495Sspeer 	for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) {
18086495Sspeer 		/* skip if it is already started */
18096495Sspeer 		if (vresp->flags & VNET_STARTED) {
18106495Sspeer 			continue;
18116495Sspeer 		}
18126495Sspeer 		macp = &vresp->macreg;
18136495Sspeer 		cbp = macp->m_callbacks;
18146495Sspeer 		rv = cbp->mc_start(macp->m_driver);
18156495Sspeer 		if (rv == 0) {
18166495Sspeer 			/*
18176495Sspeer 			 * Successfully started the resource, so now
18186495Sspeer 			 * add it to the fdb.
18196495Sspeer 			 */
18206495Sspeer 			vresp->flags |= VNET_STARTED;
18216495Sspeer 			vnet_fdbe_add(vnetp, vresp);
18226495Sspeer 		}
18236495Sspeer 	}
18246495Sspeer 
18256495Sspeer 	DBG1(vnetp, "exit\n");
18266495Sspeer 
18276495Sspeer }
18286495Sspeer 
18296495Sspeer /*
18306495Sspeer  * vnet_stop_resources -- stop all resources associated with a vnet.
18316495Sspeer  */
18326495Sspeer static void
18336495Sspeer vnet_stop_resources(vnet_t *vnetp)
18346495Sspeer {
18356495Sspeer 	vnet_res_t	*vresp;
18366495Sspeer 	mac_register_t	*macp;
18376495Sspeer 	mac_callbacks_t	*cbp;
18386495Sspeer 
18396495Sspeer 	DBG1(vnetp, "enter\n");
18406495Sspeer 
18419805SSriharsha.Basavapatna@Sun.COM 	ASSERT(RW_WRITE_HELD(&vnetp->vrwlock));
18429805SSriharsha.Basavapatna@Sun.COM 
18436495Sspeer 	for (vresp = vnetp->vres_list; vresp != NULL; ) {
18446495Sspeer 		if (vresp->flags & VNET_STARTED) {
18459805SSriharsha.Basavapatna@Sun.COM 			/*
18469805SSriharsha.Basavapatna@Sun.COM 			 * Release the lock while invoking mc_stop() of the
18479805SSriharsha.Basavapatna@Sun.COM 			 * underlying resource. We hold a reference to this
18489805SSriharsha.Basavapatna@Sun.COM 			 * resource to prevent being removed from the list in
18499805SSriharsha.Basavapatna@Sun.COM 			 * vio_net_resource_unreg(). Note that new resources
18509805SSriharsha.Basavapatna@Sun.COM 			 * can be added to the head of the list while the lock
18519805SSriharsha.Basavapatna@Sun.COM 			 * is released, but they won't be started, as
18529805SSriharsha.Basavapatna@Sun.COM 			 * VNET_STARTED flag has been cleared for the vnet
18539805SSriharsha.Basavapatna@Sun.COM 			 * device in vnet_m_stop(). Also, while the lock is
18549805SSriharsha.Basavapatna@Sun.COM 			 * released a resource could be removed from the list
18559805SSriharsha.Basavapatna@Sun.COM 			 * in vio_net_resource_unreg(); but that is ok, as we
18569805SSriharsha.Basavapatna@Sun.COM 			 * re-acquire the lock and only then access the forward
18579805SSriharsha.Basavapatna@Sun.COM 			 * link (vresp->nextp) to continue with the next
18589805SSriharsha.Basavapatna@Sun.COM 			 * resource.
18599805SSriharsha.Basavapatna@Sun.COM 			 */
18609805SSriharsha.Basavapatna@Sun.COM 			vresp->flags &= ~VNET_STARTED;
18619805SSriharsha.Basavapatna@Sun.COM 			vresp->flags |= VNET_STOPPING;
18626495Sspeer 			macp = &vresp->macreg;
18636495Sspeer 			cbp = macp->m_callbacks;
18649805SSriharsha.Basavapatna@Sun.COM 			VNET_FDBE_REFHOLD(vresp);
18659805SSriharsha.Basavapatna@Sun.COM 			RW_EXIT(&vnetp->vrwlock);
18669805SSriharsha.Basavapatna@Sun.COM 
18676495Sspeer 			cbp->mc_stop(macp->m_driver);
18689805SSriharsha.Basavapatna@Sun.COM 
18699805SSriharsha.Basavapatna@Sun.COM 			WRITE_ENTER(&vnetp->vrwlock);
18709805SSriharsha.Basavapatna@Sun.COM 			vresp->flags &= ~VNET_STOPPING;
18719805SSriharsha.Basavapatna@Sun.COM 			VNET_FDBE_REFRELE(vresp);
18726495Sspeer 		}
18739805SSriharsha.Basavapatna@Sun.COM 		vresp = vresp->nextp;
18746495Sspeer 	}
18756495Sspeer 	DBG1(vnetp, "exit\n");
18766495Sspeer }
18778160SWentao.Yang@Sun.COM 
18788160SWentao.Yang@Sun.COM /*
18798160SWentao.Yang@Sun.COM  * Setup kstats for the HIO statistics.
18808160SWentao.Yang@Sun.COM  * NOTE: the synchronization for the statistics is the
18818160SWentao.Yang@Sun.COM  * responsibility of the caller.
18828160SWentao.Yang@Sun.COM  */
18838160SWentao.Yang@Sun.COM kstat_t *
18848160SWentao.Yang@Sun.COM vnet_hio_setup_kstats(char *ks_mod, char *ks_name, vnet_res_t *vresp)
18858160SWentao.Yang@Sun.COM {
18868160SWentao.Yang@Sun.COM 	kstat_t *ksp;
18878160SWentao.Yang@Sun.COM 	vnet_t *vnetp = vresp->vnetp;
18888160SWentao.Yang@Sun.COM 	vnet_hio_kstats_t *hiokp;
18898160SWentao.Yang@Sun.COM 	size_t size;
18908160SWentao.Yang@Sun.COM 
18918160SWentao.Yang@Sun.COM 	ASSERT(vnetp != NULL);
18928160SWentao.Yang@Sun.COM 	size = sizeof (vnet_hio_kstats_t) / sizeof (kstat_named_t);
18938160SWentao.Yang@Sun.COM 	ksp = kstat_create(ks_mod, vnetp->instance, ks_name, "net",
18948160SWentao.Yang@Sun.COM 	    KSTAT_TYPE_NAMED, size, 0);
18958160SWentao.Yang@Sun.COM 	if (ksp == NULL) {
18968160SWentao.Yang@Sun.COM 		return (NULL);
18978160SWentao.Yang@Sun.COM 	}
18988160SWentao.Yang@Sun.COM 
18998160SWentao.Yang@Sun.COM 	hiokp = (vnet_hio_kstats_t *)ksp->ks_data;
19008160SWentao.Yang@Sun.COM 	kstat_named_init(&hiokp->ipackets,		"ipackets",
19018160SWentao.Yang@Sun.COM 	    KSTAT_DATA_ULONG);
19028160SWentao.Yang@Sun.COM 	kstat_named_init(&hiokp->ierrors,		"ierrors",
19038160SWentao.Yang@Sun.COM 	    KSTAT_DATA_ULONG);
19048160SWentao.Yang@Sun.COM 	kstat_named_init(&hiokp->opackets,		"opackets",
19058160SWentao.Yang@Sun.COM 	    KSTAT_DATA_ULONG);
19068160SWentao.Yang@Sun.COM 	kstat_named_init(&hiokp->oerrors,		"oerrors",
19078160SWentao.Yang@Sun.COM 	    KSTAT_DATA_ULONG);
19088160SWentao.Yang@Sun.COM 
19098160SWentao.Yang@Sun.COM 
19108160SWentao.Yang@Sun.COM 	/* MIB II kstat variables */
19118160SWentao.Yang@Sun.COM 	kstat_named_init(&hiokp->rbytes,		"rbytes",
19128160SWentao.Yang@Sun.COM 	    KSTAT_DATA_ULONG);
19138160SWentao.Yang@Sun.COM 	kstat_named_init(&hiokp->obytes,		"obytes",
19148160SWentao.Yang@Sun.COM 	    KSTAT_DATA_ULONG);
19158160SWentao.Yang@Sun.COM 	kstat_named_init(&hiokp->multircv,		"multircv",
19168160SWentao.Yang@Sun.COM 	    KSTAT_DATA_ULONG);
19178160SWentao.Yang@Sun.COM 	kstat_named_init(&hiokp->multixmt,		"multixmt",
19188160SWentao.Yang@Sun.COM 	    KSTAT_DATA_ULONG);
19198160SWentao.Yang@Sun.COM 	kstat_named_init(&hiokp->brdcstrcv,		"brdcstrcv",
19208160SWentao.Yang@Sun.COM 	    KSTAT_DATA_ULONG);
19218160SWentao.Yang@Sun.COM 	kstat_named_init(&hiokp->brdcstxmt,		"brdcstxmt",
19228160SWentao.Yang@Sun.COM 	    KSTAT_DATA_ULONG);
19238160SWentao.Yang@Sun.COM 	kstat_named_init(&hiokp->norcvbuf,		"norcvbuf",
19248160SWentao.Yang@Sun.COM 	    KSTAT_DATA_ULONG);
19258160SWentao.Yang@Sun.COM 	kstat_named_init(&hiokp->noxmtbuf,		"noxmtbuf",
19268160SWentao.Yang@Sun.COM 	    KSTAT_DATA_ULONG);
19278160SWentao.Yang@Sun.COM 
19288160SWentao.Yang@Sun.COM 	ksp->ks_update = vnet_hio_update_kstats;
19298160SWentao.Yang@Sun.COM 	ksp->ks_private = (void *)vresp;
19308160SWentao.Yang@Sun.COM 	kstat_install(ksp);
19318160SWentao.Yang@Sun.COM 	return (ksp);
19328160SWentao.Yang@Sun.COM }
19338160SWentao.Yang@Sun.COM 
19348160SWentao.Yang@Sun.COM /*
19358160SWentao.Yang@Sun.COM  * Destroy kstats.
19368160SWentao.Yang@Sun.COM  */
19378160SWentao.Yang@Sun.COM static void
19388160SWentao.Yang@Sun.COM vnet_hio_destroy_kstats(kstat_t *ksp)
19398160SWentao.Yang@Sun.COM {
19408160SWentao.Yang@Sun.COM 	if (ksp != NULL)
19418160SWentao.Yang@Sun.COM 		kstat_delete(ksp);
19428160SWentao.Yang@Sun.COM }
19438160SWentao.Yang@Sun.COM 
19448160SWentao.Yang@Sun.COM /*
19458160SWentao.Yang@Sun.COM  * Update the kstats.
19468160SWentao.Yang@Sun.COM  */
19478160SWentao.Yang@Sun.COM static int
19488160SWentao.Yang@Sun.COM vnet_hio_update_kstats(kstat_t *ksp, int rw)
19498160SWentao.Yang@Sun.COM {
19508160SWentao.Yang@Sun.COM 	vnet_t *vnetp;
19518160SWentao.Yang@Sun.COM 	vnet_res_t *vresp;
19528160SWentao.Yang@Sun.COM 	vnet_hio_stats_t statsp;
19538160SWentao.Yang@Sun.COM 	vnet_hio_kstats_t *hiokp;
19548160SWentao.Yang@Sun.COM 
19558160SWentao.Yang@Sun.COM 	vresp = (vnet_res_t *)ksp->ks_private;
19568160SWentao.Yang@Sun.COM 	vnetp = vresp->vnetp;
19578160SWentao.Yang@Sun.COM 
19588160SWentao.Yang@Sun.COM 	bzero(&statsp, sizeof (vnet_hio_stats_t));
19598160SWentao.Yang@Sun.COM 
19608160SWentao.Yang@Sun.COM 	READ_ENTER(&vnetp->vsw_fp_rw);
19618160SWentao.Yang@Sun.COM 	if (vnetp->hio_fp == NULL) {
19628160SWentao.Yang@Sun.COM 		/* not using hio resources, just return */
19638160SWentao.Yang@Sun.COM 		RW_EXIT(&vnetp->vsw_fp_rw);
19648160SWentao.Yang@Sun.COM 		return (0);
19658160SWentao.Yang@Sun.COM 	}
19668160SWentao.Yang@Sun.COM 	VNET_FDBE_REFHOLD(vnetp->hio_fp);
19678160SWentao.Yang@Sun.COM 	RW_EXIT(&vnetp->vsw_fp_rw);
19688160SWentao.Yang@Sun.COM 	vnet_hio_get_stats(vnetp->hio_fp, &statsp);
19698160SWentao.Yang@Sun.COM 	VNET_FDBE_REFRELE(vnetp->hio_fp);
19708160SWentao.Yang@Sun.COM 
19718160SWentao.Yang@Sun.COM 	hiokp = (vnet_hio_kstats_t *)ksp->ks_data;
19728160SWentao.Yang@Sun.COM 
19738160SWentao.Yang@Sun.COM 	if (rw == KSTAT_READ) {
19748160SWentao.Yang@Sun.COM 		/* Link Input/Output stats */
19758160SWentao.Yang@Sun.COM 		hiokp->ipackets.value.ul	= (uint32_t)statsp.ipackets;
19768160SWentao.Yang@Sun.COM 		hiokp->ipackets64.value.ull	= statsp.ipackets;
19778160SWentao.Yang@Sun.COM 		hiokp->ierrors.value.ul		= statsp.ierrors;
19788160SWentao.Yang@Sun.COM 		hiokp->opackets.value.ul	= (uint32_t)statsp.opackets;
19798160SWentao.Yang@Sun.COM 		hiokp->opackets64.value.ull	= statsp.opackets;
19808160SWentao.Yang@Sun.COM 		hiokp->oerrors.value.ul		= statsp.oerrors;
19818160SWentao.Yang@Sun.COM 
19828160SWentao.Yang@Sun.COM 		/* MIB II kstat variables */
19838160SWentao.Yang@Sun.COM 		hiokp->rbytes.value.ul		= (uint32_t)statsp.rbytes;
19848160SWentao.Yang@Sun.COM 		hiokp->rbytes64.value.ull	= statsp.rbytes;
19858160SWentao.Yang@Sun.COM 		hiokp->obytes.value.ul		= (uint32_t)statsp.obytes;
19868160SWentao.Yang@Sun.COM 		hiokp->obytes64.value.ull	= statsp.obytes;
19878160SWentao.Yang@Sun.COM 		hiokp->multircv.value.ul	= statsp.multircv;
19888160SWentao.Yang@Sun.COM 		hiokp->multixmt.value.ul	= statsp.multixmt;
19898160SWentao.Yang@Sun.COM 		hiokp->brdcstrcv.value.ul	= statsp.brdcstrcv;
19908160SWentao.Yang@Sun.COM 		hiokp->brdcstxmt.value.ul	= statsp.brdcstxmt;
19918160SWentao.Yang@Sun.COM 		hiokp->norcvbuf.value.ul	= statsp.norcvbuf;
19928160SWentao.Yang@Sun.COM 		hiokp->noxmtbuf.value.ul	= statsp.noxmtbuf;
19938160SWentao.Yang@Sun.COM 	} else {
19948160SWentao.Yang@Sun.COM 		return (EACCES);
19958160SWentao.Yang@Sun.COM 	}
19968160SWentao.Yang@Sun.COM 
19978160SWentao.Yang@Sun.COM 	return (0);
19988160SWentao.Yang@Sun.COM }
19998160SWentao.Yang@Sun.COM 
20008160SWentao.Yang@Sun.COM static void
20018160SWentao.Yang@Sun.COM vnet_hio_get_stats(vnet_res_t *vresp, vnet_hio_stats_t *statsp)
20028160SWentao.Yang@Sun.COM {
20038160SWentao.Yang@Sun.COM 	mac_register_t		*macp;
20048160SWentao.Yang@Sun.COM 	mac_callbacks_t		*cbp;
20058160SWentao.Yang@Sun.COM 	uint64_t		val;
20068160SWentao.Yang@Sun.COM 	int			stat;
20078160SWentao.Yang@Sun.COM 
20088160SWentao.Yang@Sun.COM 	/*
20098160SWentao.Yang@Sun.COM 	 * get the specified statistics from the underlying nxge.
20108160SWentao.Yang@Sun.COM 	 */
20118160SWentao.Yang@Sun.COM 	macp = &vresp->macreg;
20128160SWentao.Yang@Sun.COM 	cbp = macp->m_callbacks;
20138160SWentao.Yang@Sun.COM 	for (stat = MAC_STAT_MIN; stat < MAC_STAT_OVERFLOWS; stat++) {
20148160SWentao.Yang@Sun.COM 		if (cbp->mc_getstat(macp->m_driver, stat, &val) == 0) {
20158160SWentao.Yang@Sun.COM 			switch (stat) {
20168160SWentao.Yang@Sun.COM 			case MAC_STAT_IPACKETS:
20178160SWentao.Yang@Sun.COM 				statsp->ipackets = val;
20188160SWentao.Yang@Sun.COM 				break;
20198160SWentao.Yang@Sun.COM 
20208160SWentao.Yang@Sun.COM 			case MAC_STAT_IERRORS:
20218160SWentao.Yang@Sun.COM 				statsp->ierrors = val;
20228160SWentao.Yang@Sun.COM 				break;
20238160SWentao.Yang@Sun.COM 
20248160SWentao.Yang@Sun.COM 			case MAC_STAT_OPACKETS:
20258160SWentao.Yang@Sun.COM 				statsp->opackets = val;
20268160SWentao.Yang@Sun.COM 				break;
20278160SWentao.Yang@Sun.COM 
20288160SWentao.Yang@Sun.COM 			case MAC_STAT_OERRORS:
20298160SWentao.Yang@Sun.COM 				statsp->oerrors = val;
20308160SWentao.Yang@Sun.COM 				break;
20318160SWentao.Yang@Sun.COM 
20328160SWentao.Yang@Sun.COM 			case MAC_STAT_RBYTES:
20338160SWentao.Yang@Sun.COM 				statsp->rbytes = val;
20348160SWentao.Yang@Sun.COM 				break;
20358160SWentao.Yang@Sun.COM 
20368160SWentao.Yang@Sun.COM 			case MAC_STAT_OBYTES:
20378160SWentao.Yang@Sun.COM 				statsp->obytes = val;
20388160SWentao.Yang@Sun.COM 				break;
20398160SWentao.Yang@Sun.COM 
20408160SWentao.Yang@Sun.COM 			case MAC_STAT_MULTIRCV:
20418160SWentao.Yang@Sun.COM 				statsp->multircv = val;
20428160SWentao.Yang@Sun.COM 				break;
20438160SWentao.Yang@Sun.COM 
20448160SWentao.Yang@Sun.COM 			case MAC_STAT_MULTIXMT:
20458160SWentao.Yang@Sun.COM 				statsp->multixmt = val;
20468160SWentao.Yang@Sun.COM 				break;
20478160SWentao.Yang@Sun.COM 
20488160SWentao.Yang@Sun.COM 			case MAC_STAT_BRDCSTRCV:
20498160SWentao.Yang@Sun.COM 				statsp->brdcstrcv = val;
20508160SWentao.Yang@Sun.COM 				break;
20518160SWentao.Yang@Sun.COM 
20528160SWentao.Yang@Sun.COM 			case MAC_STAT_BRDCSTXMT:
20538160SWentao.Yang@Sun.COM 				statsp->brdcstxmt = val;
20548160SWentao.Yang@Sun.COM 				break;
20558160SWentao.Yang@Sun.COM 
20568160SWentao.Yang@Sun.COM 			case MAC_STAT_NOXMTBUF:
20578160SWentao.Yang@Sun.COM 				statsp->noxmtbuf = val;
20588160SWentao.Yang@Sun.COM 				break;
20598160SWentao.Yang@Sun.COM 
20608160SWentao.Yang@Sun.COM 			case MAC_STAT_NORCVBUF:
20618160SWentao.Yang@Sun.COM 				statsp->norcvbuf = val;
20628160SWentao.Yang@Sun.COM 				break;
20638160SWentao.Yang@Sun.COM 
20648160SWentao.Yang@Sun.COM 			default:
20658160SWentao.Yang@Sun.COM 				/*
20668160SWentao.Yang@Sun.COM 				 * parameters not interested.
20678160SWentao.Yang@Sun.COM 				 */
20688160SWentao.Yang@Sun.COM 				break;
20698160SWentao.Yang@Sun.COM 			}
20708160SWentao.Yang@Sun.COM 		}
20718160SWentao.Yang@Sun.COM 	}
20728160SWentao.Yang@Sun.COM }
20739336SSriharsha.Basavapatna@Sun.COM 
207410309SSriharsha.Basavapatna@Sun.COM static boolean_t
207510309SSriharsha.Basavapatna@Sun.COM vnet_m_capab(void *arg, mac_capab_t cap, void *cap_data)
207610309SSriharsha.Basavapatna@Sun.COM {
207710309SSriharsha.Basavapatna@Sun.COM 	vnet_t	*vnetp = (vnet_t *)arg;
207810309SSriharsha.Basavapatna@Sun.COM 
207910309SSriharsha.Basavapatna@Sun.COM 	if (vnetp == NULL) {
208010309SSriharsha.Basavapatna@Sun.COM 		return (0);
208110309SSriharsha.Basavapatna@Sun.COM 	}
208210309SSriharsha.Basavapatna@Sun.COM 
208310309SSriharsha.Basavapatna@Sun.COM 	switch (cap) {
208410309SSriharsha.Basavapatna@Sun.COM 
208510309SSriharsha.Basavapatna@Sun.COM 	case MAC_CAPAB_RINGS: {
208610309SSriharsha.Basavapatna@Sun.COM 
208710309SSriharsha.Basavapatna@Sun.COM 		mac_capab_rings_t *cap_rings = cap_data;
208810309SSriharsha.Basavapatna@Sun.COM 		/*
208910309SSriharsha.Basavapatna@Sun.COM 		 * Rings Capability Notes:
209010309SSriharsha.Basavapatna@Sun.COM 		 * We advertise rings to make use of the rings framework in
209110309SSriharsha.Basavapatna@Sun.COM 		 * gldv3 mac layer, to improve the performance. This is
209210309SSriharsha.Basavapatna@Sun.COM 		 * specifically needed when a Hybrid resource (with multiple
209310309SSriharsha.Basavapatna@Sun.COM 		 * tx/rx hardware rings) is assigned to a vnet device. We also
209410309SSriharsha.Basavapatna@Sun.COM 		 * leverage this for the normal case when no Hybrid resource is
209510309SSriharsha.Basavapatna@Sun.COM 		 * assigned.
209610309SSriharsha.Basavapatna@Sun.COM 		 *
209710309SSriharsha.Basavapatna@Sun.COM 		 * Ring Allocation:
209810309SSriharsha.Basavapatna@Sun.COM 		 * - TX path:
209910309SSriharsha.Basavapatna@Sun.COM 		 * We expose a pseudo ring group with 2 pseudo tx rings (as
210010309SSriharsha.Basavapatna@Sun.COM 		 * currently HybridIO exports only 2 rings) In the normal case,
210110309SSriharsha.Basavapatna@Sun.COM 		 * transmit traffic that comes down to the driver through the
210210309SSriharsha.Basavapatna@Sun.COM 		 * mri_tx (vnet_tx_ring_send()) entry point goes through the
210310309SSriharsha.Basavapatna@Sun.COM 		 * distributed switching algorithm in vnet and gets transmitted
210410309SSriharsha.Basavapatna@Sun.COM 		 * over a port/LDC in the vgen layer to either the vswitch or a
210510309SSriharsha.Basavapatna@Sun.COM 		 * peer vnet. If and when a Hybrid resource is assigned to the
210610309SSriharsha.Basavapatna@Sun.COM 		 * vnet, we obtain the tx ring information of the Hybrid device
210710309SSriharsha.Basavapatna@Sun.COM 		 * (nxge) and map the pseudo rings 1:1 to the 2 hw tx rings.
210810309SSriharsha.Basavapatna@Sun.COM 		 * Traffic being sent over the Hybrid resource by the mac layer
210910309SSriharsha.Basavapatna@Sun.COM 		 * gets spread across both hw rings, as they are mapped to the
211010309SSriharsha.Basavapatna@Sun.COM 		 * 2 pseudo tx rings in vnet.
211110309SSriharsha.Basavapatna@Sun.COM 		 *
211210309SSriharsha.Basavapatna@Sun.COM 		 * - RX path:
211310309SSriharsha.Basavapatna@Sun.COM 		 * We expose a pseudo ring group with 3 pseudo rx rings (static
211410309SSriharsha.Basavapatna@Sun.COM 		 * rings) initially. The first (default) pseudo rx ring is
211510309SSriharsha.Basavapatna@Sun.COM 		 * reserved for the resource that connects to the vswitch
211610309SSriharsha.Basavapatna@Sun.COM 		 * service. The next 2 rings are reserved for a Hybrid resource
211710309SSriharsha.Basavapatna@Sun.COM 		 * that may be assigned to the vnet device. If and when a
211810309SSriharsha.Basavapatna@Sun.COM 		 * Hybrid resource is assigned to the vnet, we obtain the rx
211910309SSriharsha.Basavapatna@Sun.COM 		 * ring information of the Hybrid device (nxge) and map these
212010309SSriharsha.Basavapatna@Sun.COM 		 * pseudo rings 1:1 to the 2 hw rx rings. For each additional
212110309SSriharsha.Basavapatna@Sun.COM 		 * resource that connects to a peer vnet, we dynamically
212210309SSriharsha.Basavapatna@Sun.COM 		 * allocate a pseudo rx ring and map it to that resource, when
212310309SSriharsha.Basavapatna@Sun.COM 		 * the resource gets added; and the pseudo rx ring is
212410309SSriharsha.Basavapatna@Sun.COM 		 * dynamically registered with the upper mac layer. We do the
212510309SSriharsha.Basavapatna@Sun.COM 		 * reverse and unregister the ring with the mac layer when
212610309SSriharsha.Basavapatna@Sun.COM 		 * the resource gets removed.
212710309SSriharsha.Basavapatna@Sun.COM 		 *
212810309SSriharsha.Basavapatna@Sun.COM 		 * Synchronization notes:
212910309SSriharsha.Basavapatna@Sun.COM 		 * We don't need any lock to protect members of ring structure,
213010309SSriharsha.Basavapatna@Sun.COM 		 * specifically ringp->hw_rh, in either the TX or the RX ring,
213110309SSriharsha.Basavapatna@Sun.COM 		 * as explained below.
213210309SSriharsha.Basavapatna@Sun.COM 		 * - TX ring:
213310309SSriharsha.Basavapatna@Sun.COM 		 * ring->hw_rh is initialized only when a Hybrid resource is
213410309SSriharsha.Basavapatna@Sun.COM 		 * associated; and gets referenced only in vnet_hio_tx(). The
213510309SSriharsha.Basavapatna@Sun.COM 		 * Hybrid resource itself is available in fdb only after tx
213610309SSriharsha.Basavapatna@Sun.COM 		 * hwrings are found and mapped; i.e, in vio_net_resource_reg()
213710309SSriharsha.Basavapatna@Sun.COM 		 * we call vnet_bind_rings() first and then call
213810309SSriharsha.Basavapatna@Sun.COM 		 * vnet_start_resources() which adds an entry to fdb. For
213910309SSriharsha.Basavapatna@Sun.COM 		 * traffic going over LDC resources, we don't reference
214010309SSriharsha.Basavapatna@Sun.COM 		 * ring->hw_rh at all.
214110309SSriharsha.Basavapatna@Sun.COM 		 * - RX ring:
214210309SSriharsha.Basavapatna@Sun.COM 		 * For rings mapped to Hybrid resource ring->hw_rh is
214310309SSriharsha.Basavapatna@Sun.COM 		 * initialized and only then do we add the rx callback for
214410309SSriharsha.Basavapatna@Sun.COM 		 * the underlying Hybrid resource; we disable callbacks before
214510309SSriharsha.Basavapatna@Sun.COM 		 * we unmap ring->hw_rh. For rings mapped to LDC resources, we
214610309SSriharsha.Basavapatna@Sun.COM 		 * stop the rx callbacks (in vgen) before we remove ring->hw_rh
214710309SSriharsha.Basavapatna@Sun.COM 		 * (vio_net_resource_unreg()).
214811878SVenu.Iyer@Sun.COM 		 * Also, we access ring->hw_rh in vnet_rx_ring_stat().
214911878SVenu.Iyer@Sun.COM 		 * Note that for rings mapped to Hybrid resource, though the
215011878SVenu.Iyer@Sun.COM 		 * rings are statically registered with the mac layer, its
215111878SVenu.Iyer@Sun.COM 		 * hardware ring mapping (ringp->hw_rh) can be torn down in
215211878SVenu.Iyer@Sun.COM 		 * vnet_unbind_hwrings() while the kstat operation is in
215311878SVenu.Iyer@Sun.COM 		 * progress. To protect against this, we hold a reference to
215411878SVenu.Iyer@Sun.COM 		 * the resource in FDB; this ensures that the thread in
215511878SVenu.Iyer@Sun.COM 		 * vio_net_resource_unreg() waits for the reference to be
215611878SVenu.Iyer@Sun.COM 		 * dropped before unbinding the ring.
215711878SVenu.Iyer@Sun.COM 		 *
215811878SVenu.Iyer@Sun.COM 		 * We don't need to do this for rings mapped to LDC resources.
215911878SVenu.Iyer@Sun.COM 		 * These rings are registered/unregistered dynamically with
216011878SVenu.Iyer@Sun.COM 		 * the mac layer and so any attempt to unregister the ring
216111878SVenu.Iyer@Sun.COM 		 * while kstat operation is in progress will block in
216211878SVenu.Iyer@Sun.COM 		 * mac_group_rem_ring(). Thus implicitly protects the
216311878SVenu.Iyer@Sun.COM 		 * resource (ringp->hw_rh) from disappearing.
216410309SSriharsha.Basavapatna@Sun.COM 		 */
216510309SSriharsha.Basavapatna@Sun.COM 
216610309SSriharsha.Basavapatna@Sun.COM 		if (cap_rings->mr_type == MAC_RING_TYPE_RX) {
216710309SSriharsha.Basavapatna@Sun.COM 			cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
216810309SSriharsha.Basavapatna@Sun.COM 
216910309SSriharsha.Basavapatna@Sun.COM 			/*
217010309SSriharsha.Basavapatna@Sun.COM 			 * The ring_cnt for rx grp is initialized in
217110309SSriharsha.Basavapatna@Sun.COM 			 * vnet_ring_grp_init(). Later, the ring_cnt gets
217210309SSriharsha.Basavapatna@Sun.COM 			 * updated dynamically whenever LDC resources are added
217310309SSriharsha.Basavapatna@Sun.COM 			 * or removed.
217410309SSriharsha.Basavapatna@Sun.COM 			 */
217510309SSriharsha.Basavapatna@Sun.COM 			cap_rings->mr_rnum = vnetp->rx_grp[0].ring_cnt;
217610309SSriharsha.Basavapatna@Sun.COM 			cap_rings->mr_rget = vnet_get_ring;
217710309SSriharsha.Basavapatna@Sun.COM 
217810309SSriharsha.Basavapatna@Sun.COM 			cap_rings->mr_gnum = VNET_NUM_PSEUDO_GROUPS;
217910309SSriharsha.Basavapatna@Sun.COM 			cap_rings->mr_gget = vnet_get_group;
218010309SSriharsha.Basavapatna@Sun.COM 			cap_rings->mr_gaddring = NULL;
218110309SSriharsha.Basavapatna@Sun.COM 			cap_rings->mr_gremring = NULL;
218210309SSriharsha.Basavapatna@Sun.COM 		} else {
218310309SSriharsha.Basavapatna@Sun.COM 			cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
218410309SSriharsha.Basavapatna@Sun.COM 
218510309SSriharsha.Basavapatna@Sun.COM 			/*
218610309SSriharsha.Basavapatna@Sun.COM 			 * The ring_cnt for tx grp is initialized in
218710309SSriharsha.Basavapatna@Sun.COM 			 * vnet_ring_grp_init() and remains constant, as we
218810309SSriharsha.Basavapatna@Sun.COM 			 * do not support dymanic tx rings for now.
218910309SSriharsha.Basavapatna@Sun.COM 			 */
219010309SSriharsha.Basavapatna@Sun.COM 			cap_rings->mr_rnum = vnetp->tx_grp[0].ring_cnt;
219110309SSriharsha.Basavapatna@Sun.COM 			cap_rings->mr_rget = vnet_get_ring;
219210309SSriharsha.Basavapatna@Sun.COM 
219310309SSriharsha.Basavapatna@Sun.COM 			/*
219410309SSriharsha.Basavapatna@Sun.COM 			 * Transmit rings are not grouped; i.e, the number of
219510309SSriharsha.Basavapatna@Sun.COM 			 * transmit ring groups advertised should be set to 0.
219610309SSriharsha.Basavapatna@Sun.COM 			 */
219710309SSriharsha.Basavapatna@Sun.COM 			cap_rings->mr_gnum = 0;
219810309SSriharsha.Basavapatna@Sun.COM 
219910309SSriharsha.Basavapatna@Sun.COM 			cap_rings->mr_gget = vnet_get_group;
220010309SSriharsha.Basavapatna@Sun.COM 			cap_rings->mr_gaddring = NULL;
220110309SSriharsha.Basavapatna@Sun.COM 			cap_rings->mr_gremring = NULL;
220210309SSriharsha.Basavapatna@Sun.COM 		}
220310309SSriharsha.Basavapatna@Sun.COM 		return (B_TRUE);
220410309SSriharsha.Basavapatna@Sun.COM 
220510309SSriharsha.Basavapatna@Sun.COM 	}
220610309SSriharsha.Basavapatna@Sun.COM 
220710309SSriharsha.Basavapatna@Sun.COM 	default:
220810309SSriharsha.Basavapatna@Sun.COM 		break;
220910309SSriharsha.Basavapatna@Sun.COM 
221010309SSriharsha.Basavapatna@Sun.COM 	}
221110309SSriharsha.Basavapatna@Sun.COM 
221210309SSriharsha.Basavapatna@Sun.COM 	return (B_FALSE);
221310309SSriharsha.Basavapatna@Sun.COM }
221410309SSriharsha.Basavapatna@Sun.COM 
221510309SSriharsha.Basavapatna@Sun.COM /*
221610309SSriharsha.Basavapatna@Sun.COM  * Callback funtion for MAC layer to get ring information.
221710309SSriharsha.Basavapatna@Sun.COM  */
221810309SSriharsha.Basavapatna@Sun.COM static void
221910309SSriharsha.Basavapatna@Sun.COM vnet_get_ring(void *arg, mac_ring_type_t rtype, const int g_index,
222010309SSriharsha.Basavapatna@Sun.COM     const int r_index, mac_ring_info_t *infop, mac_ring_handle_t r_handle)
222110309SSriharsha.Basavapatna@Sun.COM {
222210309SSriharsha.Basavapatna@Sun.COM 	vnet_t	*vnetp = arg;
222310309SSriharsha.Basavapatna@Sun.COM 
222410309SSriharsha.Basavapatna@Sun.COM 	switch (rtype) {
222510309SSriharsha.Basavapatna@Sun.COM 
222610309SSriharsha.Basavapatna@Sun.COM 	case MAC_RING_TYPE_RX: {
222710309SSriharsha.Basavapatna@Sun.COM 
222810309SSriharsha.Basavapatna@Sun.COM 		vnet_pseudo_rx_group_t	*rx_grp;
222910309SSriharsha.Basavapatna@Sun.COM 		vnet_pseudo_rx_ring_t	*rx_ringp;
223010309SSriharsha.Basavapatna@Sun.COM 		mac_intr_t		*mintr;
223110309SSriharsha.Basavapatna@Sun.COM 
223210309SSriharsha.Basavapatna@Sun.COM 		/* We advertised only one RX group */
223310309SSriharsha.Basavapatna@Sun.COM 		ASSERT(g_index == 0);
223410309SSriharsha.Basavapatna@Sun.COM 		rx_grp = &vnetp->rx_grp[g_index];
223510309SSriharsha.Basavapatna@Sun.COM 
223610309SSriharsha.Basavapatna@Sun.COM 		/* Check the current # of rings in the rx group */
223710309SSriharsha.Basavapatna@Sun.COM 		ASSERT((r_index >= 0) && (r_index < rx_grp->max_ring_cnt));
223810309SSriharsha.Basavapatna@Sun.COM 
223910309SSriharsha.Basavapatna@Sun.COM 		/* Get the ring based on the index */
224010309SSriharsha.Basavapatna@Sun.COM 		rx_ringp = &rx_grp->rings[r_index];
224110309SSriharsha.Basavapatna@Sun.COM 
224210309SSriharsha.Basavapatna@Sun.COM 		rx_ringp->handle = r_handle;
224310309SSriharsha.Basavapatna@Sun.COM 		/*
224410309SSriharsha.Basavapatna@Sun.COM 		 * Note: we don't need to save the incoming r_index in rx_ring,
224510309SSriharsha.Basavapatna@Sun.COM 		 * as vnet_ring_grp_init() would have initialized the index for
224610309SSriharsha.Basavapatna@Sun.COM 		 * each ring in the array.
224710309SSriharsha.Basavapatna@Sun.COM 		 */
224810309SSriharsha.Basavapatna@Sun.COM 		rx_ringp->grp = rx_grp;
224910309SSriharsha.Basavapatna@Sun.COM 		rx_ringp->vnetp = vnetp;
225010309SSriharsha.Basavapatna@Sun.COM 
225110309SSriharsha.Basavapatna@Sun.COM 		mintr = &infop->mri_intr;
225210309SSriharsha.Basavapatna@Sun.COM 		mintr->mi_handle = (mac_intr_handle_t)rx_ringp;
225310309SSriharsha.Basavapatna@Sun.COM 		mintr->mi_enable = (mac_intr_enable_t)vnet_ring_enable_intr;
225410309SSriharsha.Basavapatna@Sun.COM 		mintr->mi_disable = (mac_intr_disable_t)vnet_ring_disable_intr;
225510309SSriharsha.Basavapatna@Sun.COM 
225610309SSriharsha.Basavapatna@Sun.COM 		infop->mri_driver = (mac_ring_driver_t)rx_ringp;
225710309SSriharsha.Basavapatna@Sun.COM 		infop->mri_start = vnet_rx_ring_start;
225810309SSriharsha.Basavapatna@Sun.COM 		infop->mri_stop = vnet_rx_ring_stop;
225911878SVenu.Iyer@Sun.COM 		infop->mri_stat = vnet_rx_ring_stat;
226010309SSriharsha.Basavapatna@Sun.COM 
226110309SSriharsha.Basavapatna@Sun.COM 		/* Set the poll function, as this is an rx ring */
226210309SSriharsha.Basavapatna@Sun.COM 		infop->mri_poll = vnet_rx_poll;
226311878SVenu.Iyer@Sun.COM 		/*
226411878SVenu.Iyer@Sun.COM 		 * MAC_RING_RX_ENQUEUE bit needed to be set for nxge
226511878SVenu.Iyer@Sun.COM 		 * which was not sending packet chains in interrupt
226611878SVenu.Iyer@Sun.COM 		 * context. For such drivers, packets are queued in
226711878SVenu.Iyer@Sun.COM 		 * Rx soft rings so that we get a chance to switch
226811878SVenu.Iyer@Sun.COM 		 * into a polling mode under backlog. This bug (not
226911878SVenu.Iyer@Sun.COM 		 * sending packet chains) has now been fixed. Once
227011878SVenu.Iyer@Sun.COM 		 * the performance impact is measured, this change
227111878SVenu.Iyer@Sun.COM 		 * will be removed.
227211878SVenu.Iyer@Sun.COM 		 */
227311878SVenu.Iyer@Sun.COM 		infop->mri_flags = (vnet_mac_rx_queuing ?
227411878SVenu.Iyer@Sun.COM 		    MAC_RING_RX_ENQUEUE : 0);
227510309SSriharsha.Basavapatna@Sun.COM 		break;
227610309SSriharsha.Basavapatna@Sun.COM 	}
227710309SSriharsha.Basavapatna@Sun.COM 
227810309SSriharsha.Basavapatna@Sun.COM 	case MAC_RING_TYPE_TX: {
227910309SSriharsha.Basavapatna@Sun.COM 		vnet_pseudo_tx_group_t	*tx_grp;
228010309SSriharsha.Basavapatna@Sun.COM 		vnet_pseudo_tx_ring_t	*tx_ringp;
228110309SSriharsha.Basavapatna@Sun.COM 
228210309SSriharsha.Basavapatna@Sun.COM 		/*
228310309SSriharsha.Basavapatna@Sun.COM 		 * No need to check grp index; mac layer passes -1 for it.
228410309SSriharsha.Basavapatna@Sun.COM 		 */
228510309SSriharsha.Basavapatna@Sun.COM 		tx_grp = &vnetp->tx_grp[0];
228610309SSriharsha.Basavapatna@Sun.COM 
228710309SSriharsha.Basavapatna@Sun.COM 		/* Check the # of rings in the tx group */
228810309SSriharsha.Basavapatna@Sun.COM 		ASSERT((r_index >= 0) && (r_index < tx_grp->ring_cnt));
228910309SSriharsha.Basavapatna@Sun.COM 
229010309SSriharsha.Basavapatna@Sun.COM 		/* Get the ring based on the index */
229110309SSriharsha.Basavapatna@Sun.COM 		tx_ringp = &tx_grp->rings[r_index];
229210309SSriharsha.Basavapatna@Sun.COM 
229310309SSriharsha.Basavapatna@Sun.COM 		tx_ringp->handle = r_handle;
229410309SSriharsha.Basavapatna@Sun.COM 		tx_ringp->index = r_index;
229510309SSriharsha.Basavapatna@Sun.COM 		tx_ringp->grp = tx_grp;
229610309SSriharsha.Basavapatna@Sun.COM 		tx_ringp->vnetp = vnetp;
229710309SSriharsha.Basavapatna@Sun.COM 
229810309SSriharsha.Basavapatna@Sun.COM 		infop->mri_driver = (mac_ring_driver_t)tx_ringp;
229910309SSriharsha.Basavapatna@Sun.COM 		infop->mri_start = vnet_tx_ring_start;
230010309SSriharsha.Basavapatna@Sun.COM 		infop->mri_stop = vnet_tx_ring_stop;
230111878SVenu.Iyer@Sun.COM 		infop->mri_stat = vnet_tx_ring_stat;
230210309SSriharsha.Basavapatna@Sun.COM 
230310309SSriharsha.Basavapatna@Sun.COM 		/* Set the transmit function, as this is a tx ring */
230410309SSriharsha.Basavapatna@Sun.COM 		infop->mri_tx = vnet_tx_ring_send;
230511878SVenu.Iyer@Sun.COM 		/*
230611878SVenu.Iyer@Sun.COM 		 * MAC_RING_TX_SERIALIZE bit needs to be set while
230711878SVenu.Iyer@Sun.COM 		 * hybridIO is enabled to workaround tx lock
230811878SVenu.Iyer@Sun.COM 		 * contention issues in nxge.
230911878SVenu.Iyer@Sun.COM 		 */
231011878SVenu.Iyer@Sun.COM 		infop->mri_flags = (vnet_mac_tx_serialize ?
231111878SVenu.Iyer@Sun.COM 		    MAC_RING_TX_SERIALIZE : 0);
231210309SSriharsha.Basavapatna@Sun.COM 		break;
231310309SSriharsha.Basavapatna@Sun.COM 	}
231410309SSriharsha.Basavapatna@Sun.COM 
231510309SSriharsha.Basavapatna@Sun.COM 	default:
231610309SSriharsha.Basavapatna@Sun.COM 		break;
231710309SSriharsha.Basavapatna@Sun.COM 	}
231810309SSriharsha.Basavapatna@Sun.COM }
231910309SSriharsha.Basavapatna@Sun.COM 
232010309SSriharsha.Basavapatna@Sun.COM /*
232110309SSriharsha.Basavapatna@Sun.COM  * Callback funtion for MAC layer to get group information.
232210309SSriharsha.Basavapatna@Sun.COM  */
232310309SSriharsha.Basavapatna@Sun.COM static void
232410309SSriharsha.Basavapatna@Sun.COM vnet_get_group(void *arg, mac_ring_type_t type, const int index,
232510309SSriharsha.Basavapatna@Sun.COM 	mac_group_info_t *infop, mac_group_handle_t handle)
232610309SSriharsha.Basavapatna@Sun.COM {
232710309SSriharsha.Basavapatna@Sun.COM 	vnet_t	*vnetp = (vnet_t *)arg;
232810309SSriharsha.Basavapatna@Sun.COM 
232910309SSriharsha.Basavapatna@Sun.COM 	switch (type) {
233010309SSriharsha.Basavapatna@Sun.COM 
233110309SSriharsha.Basavapatna@Sun.COM 	case MAC_RING_TYPE_RX:
233210309SSriharsha.Basavapatna@Sun.COM 	{
233310309SSriharsha.Basavapatna@Sun.COM 		vnet_pseudo_rx_group_t	*rx_grp;
233410309SSriharsha.Basavapatna@Sun.COM 
233510309SSriharsha.Basavapatna@Sun.COM 		/* We advertised only one RX group */
233610309SSriharsha.Basavapatna@Sun.COM 		ASSERT(index == 0);
233710309SSriharsha.Basavapatna@Sun.COM 
233810309SSriharsha.Basavapatna@Sun.COM 		rx_grp = &vnetp->rx_grp[index];
233910309SSriharsha.Basavapatna@Sun.COM 		rx_grp->handle = handle;
234010309SSriharsha.Basavapatna@Sun.COM 		rx_grp->index = index;
234110309SSriharsha.Basavapatna@Sun.COM 		rx_grp->vnetp = vnetp;
234210309SSriharsha.Basavapatna@Sun.COM 
234310309SSriharsha.Basavapatna@Sun.COM 		infop->mgi_driver = (mac_group_driver_t)rx_grp;
234410309SSriharsha.Basavapatna@Sun.COM 		infop->mgi_start = NULL;
234510309SSriharsha.Basavapatna@Sun.COM 		infop->mgi_stop = NULL;
234610309SSriharsha.Basavapatna@Sun.COM 		infop->mgi_addmac = vnet_addmac;
234710309SSriharsha.Basavapatna@Sun.COM 		infop->mgi_remmac = vnet_remmac;
234810309SSriharsha.Basavapatna@Sun.COM 		infop->mgi_count = rx_grp->ring_cnt;
234910309SSriharsha.Basavapatna@Sun.COM 
235010309SSriharsha.Basavapatna@Sun.COM 		break;
235110309SSriharsha.Basavapatna@Sun.COM 	}
235210309SSriharsha.Basavapatna@Sun.COM 
235310309SSriharsha.Basavapatna@Sun.COM 	case MAC_RING_TYPE_TX:
235410309SSriharsha.Basavapatna@Sun.COM 	{
235510309SSriharsha.Basavapatna@Sun.COM 		vnet_pseudo_tx_group_t	*tx_grp;
235610309SSriharsha.Basavapatna@Sun.COM 
235710309SSriharsha.Basavapatna@Sun.COM 		/* We advertised only one TX group */
235810309SSriharsha.Basavapatna@Sun.COM 		ASSERT(index == 0);
235910309SSriharsha.Basavapatna@Sun.COM 
236010309SSriharsha.Basavapatna@Sun.COM 		tx_grp = &vnetp->tx_grp[index];
236110309SSriharsha.Basavapatna@Sun.COM 		tx_grp->handle = handle;
236210309SSriharsha.Basavapatna@Sun.COM 		tx_grp->index = index;
236310309SSriharsha.Basavapatna@Sun.COM 		tx_grp->vnetp = vnetp;
236410309SSriharsha.Basavapatna@Sun.COM 
236510309SSriharsha.Basavapatna@Sun.COM 		infop->mgi_driver = (mac_group_driver_t)tx_grp;
236610309SSriharsha.Basavapatna@Sun.COM 		infop->mgi_start = NULL;
236710309SSriharsha.Basavapatna@Sun.COM 		infop->mgi_stop = NULL;
236810309SSriharsha.Basavapatna@Sun.COM 		infop->mgi_addmac = NULL;
236910309SSriharsha.Basavapatna@Sun.COM 		infop->mgi_remmac = NULL;
237010309SSriharsha.Basavapatna@Sun.COM 		infop->mgi_count = VNET_NUM_PSEUDO_TXRINGS;
237110309SSriharsha.Basavapatna@Sun.COM 
237210309SSriharsha.Basavapatna@Sun.COM 		break;
237310309SSriharsha.Basavapatna@Sun.COM 	}
237410309SSriharsha.Basavapatna@Sun.COM 
237510309SSriharsha.Basavapatna@Sun.COM 	default:
237610309SSriharsha.Basavapatna@Sun.COM 		break;
237710309SSriharsha.Basavapatna@Sun.COM 
237810309SSriharsha.Basavapatna@Sun.COM 	}
237910309SSriharsha.Basavapatna@Sun.COM }
238010309SSriharsha.Basavapatna@Sun.COM 
238110309SSriharsha.Basavapatna@Sun.COM static int
238210309SSriharsha.Basavapatna@Sun.COM vnet_rx_ring_start(mac_ring_driver_t arg, uint64_t mr_gen_num)
238310309SSriharsha.Basavapatna@Sun.COM {
238410309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_rx_ring_t	*rx_ringp = (vnet_pseudo_rx_ring_t *)arg;
238510309SSriharsha.Basavapatna@Sun.COM 	int			err;
238610309SSriharsha.Basavapatna@Sun.COM 
238710309SSriharsha.Basavapatna@Sun.COM 	/*
238810309SSriharsha.Basavapatna@Sun.COM 	 * If this ring is mapped to a LDC resource, simply mark the state to
238910309SSriharsha.Basavapatna@Sun.COM 	 * indicate the ring is started and return.
239010309SSriharsha.Basavapatna@Sun.COM 	 */
239110309SSriharsha.Basavapatna@Sun.COM 	if ((rx_ringp->state &
239210309SSriharsha.Basavapatna@Sun.COM 	    (VNET_RXRING_LDC_SERVICE|VNET_RXRING_LDC_GUEST)) != 0) {
239310309SSriharsha.Basavapatna@Sun.COM 		rx_ringp->gen_num = mr_gen_num;
239410309SSriharsha.Basavapatna@Sun.COM 		rx_ringp->state |= VNET_RXRING_STARTED;
239510309SSriharsha.Basavapatna@Sun.COM 		return (0);
239610309SSriharsha.Basavapatna@Sun.COM 	}
239710309SSriharsha.Basavapatna@Sun.COM 
239810309SSriharsha.Basavapatna@Sun.COM 	ASSERT((rx_ringp->state & VNET_RXRING_HYBRID) != 0);
239910309SSriharsha.Basavapatna@Sun.COM 
240010309SSriharsha.Basavapatna@Sun.COM 	/*
240110309SSriharsha.Basavapatna@Sun.COM 	 * This must be a ring reserved for a hwring. If the hwring is not
240210309SSriharsha.Basavapatna@Sun.COM 	 * bound yet, simply mark the state to indicate the ring is started and
240310309SSriharsha.Basavapatna@Sun.COM 	 * return. If and when a hybrid resource is activated for this vnet
240410309SSriharsha.Basavapatna@Sun.COM 	 * device, we will bind the hwring and start it then. If a hwring is
240510309SSriharsha.Basavapatna@Sun.COM 	 * already bound, start it now.
240610309SSriharsha.Basavapatna@Sun.COM 	 */
240710309SSriharsha.Basavapatna@Sun.COM 	if (rx_ringp->hw_rh == NULL) {
240810309SSriharsha.Basavapatna@Sun.COM 		rx_ringp->gen_num = mr_gen_num;
240910309SSriharsha.Basavapatna@Sun.COM 		rx_ringp->state |= VNET_RXRING_STARTED;
241010309SSriharsha.Basavapatna@Sun.COM 		return (0);
241110309SSriharsha.Basavapatna@Sun.COM 	}
241210309SSriharsha.Basavapatna@Sun.COM 
241310309SSriharsha.Basavapatna@Sun.COM 	err = mac_hwring_start(rx_ringp->hw_rh);
241410309SSriharsha.Basavapatna@Sun.COM 	if (err == 0) {
241510309SSriharsha.Basavapatna@Sun.COM 		rx_ringp->gen_num = mr_gen_num;
241610309SSriharsha.Basavapatna@Sun.COM 		rx_ringp->state |= VNET_RXRING_STARTED;
241710309SSriharsha.Basavapatna@Sun.COM 	} else {
241810309SSriharsha.Basavapatna@Sun.COM 		err = ENXIO;
241910309SSriharsha.Basavapatna@Sun.COM 	}
242010309SSriharsha.Basavapatna@Sun.COM 
242110309SSriharsha.Basavapatna@Sun.COM 	return (err);
242210309SSriharsha.Basavapatna@Sun.COM }
242310309SSriharsha.Basavapatna@Sun.COM 
242410309SSriharsha.Basavapatna@Sun.COM static void
242510309SSriharsha.Basavapatna@Sun.COM vnet_rx_ring_stop(mac_ring_driver_t arg)
242610309SSriharsha.Basavapatna@Sun.COM {
242710309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_rx_ring_t	*rx_ringp = (vnet_pseudo_rx_ring_t *)arg;
242810309SSriharsha.Basavapatna@Sun.COM 
242910309SSriharsha.Basavapatna@Sun.COM 	/*
243010309SSriharsha.Basavapatna@Sun.COM 	 * If this ring is mapped to a LDC resource, simply mark the state to
243110309SSriharsha.Basavapatna@Sun.COM 	 * indicate the ring is now stopped and return.
243210309SSriharsha.Basavapatna@Sun.COM 	 */
243310309SSriharsha.Basavapatna@Sun.COM 	if ((rx_ringp->state &
243410309SSriharsha.Basavapatna@Sun.COM 	    (VNET_RXRING_LDC_SERVICE|VNET_RXRING_LDC_GUEST)) != 0) {
243510309SSriharsha.Basavapatna@Sun.COM 		rx_ringp->state &= ~VNET_RXRING_STARTED;
243610439SWentao.Yang@Sun.COM 		return;
243710309SSriharsha.Basavapatna@Sun.COM 	}
243810309SSriharsha.Basavapatna@Sun.COM 
243910309SSriharsha.Basavapatna@Sun.COM 	ASSERT((rx_ringp->state & VNET_RXRING_HYBRID) != 0);
244010309SSriharsha.Basavapatna@Sun.COM 
244110309SSriharsha.Basavapatna@Sun.COM 	/*
244210309SSriharsha.Basavapatna@Sun.COM 	 * This must be a ring reserved for a hwring. If the hwring is not
244310309SSriharsha.Basavapatna@Sun.COM 	 * bound yet, simply mark the state to indicate the ring is stopped and
244410309SSriharsha.Basavapatna@Sun.COM 	 * return. If a hwring is already bound, stop it now.
244510309SSriharsha.Basavapatna@Sun.COM 	 */
244610309SSriharsha.Basavapatna@Sun.COM 	if (rx_ringp->hw_rh == NULL) {
244710309SSriharsha.Basavapatna@Sun.COM 		rx_ringp->state &= ~VNET_RXRING_STARTED;
244810309SSriharsha.Basavapatna@Sun.COM 		return;
244910309SSriharsha.Basavapatna@Sun.COM 	}
245010309SSriharsha.Basavapatna@Sun.COM 
245110309SSriharsha.Basavapatna@Sun.COM 	mac_hwring_stop(rx_ringp->hw_rh);
245210309SSriharsha.Basavapatna@Sun.COM 	rx_ringp->state &= ~VNET_RXRING_STARTED;
245310309SSriharsha.Basavapatna@Sun.COM }
245410309SSriharsha.Basavapatna@Sun.COM 
245511878SVenu.Iyer@Sun.COM static int
245611878SVenu.Iyer@Sun.COM vnet_rx_ring_stat(mac_ring_driver_t rdriver, uint_t stat, uint64_t *val)
245711878SVenu.Iyer@Sun.COM {
245811878SVenu.Iyer@Sun.COM 	vnet_pseudo_rx_ring_t	*rx_ringp = (vnet_pseudo_rx_ring_t *)rdriver;
245911878SVenu.Iyer@Sun.COM 	vnet_t			*vnetp = (vnet_t *)rx_ringp->vnetp;
246011878SVenu.Iyer@Sun.COM 	vnet_res_t		*vresp;
246111878SVenu.Iyer@Sun.COM 	mac_register_t		*macp;
246211878SVenu.Iyer@Sun.COM 	mac_callbacks_t		*cbp;
246311878SVenu.Iyer@Sun.COM 
246411878SVenu.Iyer@Sun.COM 	/*
246511878SVenu.Iyer@Sun.COM 	 * Refer to vnet_m_capab() function for detailed comments on ring
246611878SVenu.Iyer@Sun.COM 	 * synchronization.
246711878SVenu.Iyer@Sun.COM 	 */
246811878SVenu.Iyer@Sun.COM 	if ((rx_ringp->state & VNET_RXRING_HYBRID) != 0) {
246911878SVenu.Iyer@Sun.COM 		READ_ENTER(&vnetp->vsw_fp_rw);
247011878SVenu.Iyer@Sun.COM 		if (vnetp->hio_fp == NULL) {
247111878SVenu.Iyer@Sun.COM 			RW_EXIT(&vnetp->vsw_fp_rw);
247211878SVenu.Iyer@Sun.COM 			return (0);
247311878SVenu.Iyer@Sun.COM 		}
247411878SVenu.Iyer@Sun.COM 
247511878SVenu.Iyer@Sun.COM 		VNET_FDBE_REFHOLD(vnetp->hio_fp);
247611878SVenu.Iyer@Sun.COM 		RW_EXIT(&vnetp->vsw_fp_rw);
2477*11881SVenu.Iyer@Sun.COM 		(void) mac_hwring_getstat(rx_ringp->hw_rh, stat, val);
247811878SVenu.Iyer@Sun.COM 		VNET_FDBE_REFRELE(vnetp->hio_fp);
247911878SVenu.Iyer@Sun.COM 		return (0);
248011878SVenu.Iyer@Sun.COM 	}
248111878SVenu.Iyer@Sun.COM 
248211878SVenu.Iyer@Sun.COM 	ASSERT((rx_ringp->state &
248311878SVenu.Iyer@Sun.COM 	    (VNET_RXRING_LDC_SERVICE|VNET_RXRING_LDC_GUEST)) != 0);
248411878SVenu.Iyer@Sun.COM 	vresp = (vnet_res_t *)rx_ringp->hw_rh;
248511878SVenu.Iyer@Sun.COM 	macp = &vresp->macreg;
248611878SVenu.Iyer@Sun.COM 	cbp = macp->m_callbacks;
248711878SVenu.Iyer@Sun.COM 
248811878SVenu.Iyer@Sun.COM 	cbp->mc_getstat(macp->m_driver, stat, val);
248911878SVenu.Iyer@Sun.COM 
249011878SVenu.Iyer@Sun.COM 	return (0);
249111878SVenu.Iyer@Sun.COM }
249211878SVenu.Iyer@Sun.COM 
249310309SSriharsha.Basavapatna@Sun.COM /* ARGSUSED */
249410309SSriharsha.Basavapatna@Sun.COM static int
249510309SSriharsha.Basavapatna@Sun.COM vnet_tx_ring_start(mac_ring_driver_t arg, uint64_t mr_gen_num)
249610309SSriharsha.Basavapatna@Sun.COM {
249710309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_tx_ring_t	*tx_ringp = (vnet_pseudo_tx_ring_t *)arg;
249810309SSriharsha.Basavapatna@Sun.COM 
249910309SSriharsha.Basavapatna@Sun.COM 	tx_ringp->state |= VNET_TXRING_STARTED;
250010309SSriharsha.Basavapatna@Sun.COM 	return (0);
250110309SSriharsha.Basavapatna@Sun.COM }
250210309SSriharsha.Basavapatna@Sun.COM 
250310309SSriharsha.Basavapatna@Sun.COM static void
250410309SSriharsha.Basavapatna@Sun.COM vnet_tx_ring_stop(mac_ring_driver_t arg)
250510309SSriharsha.Basavapatna@Sun.COM {
250610309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_tx_ring_t	*tx_ringp = (vnet_pseudo_tx_ring_t *)arg;
250710309SSriharsha.Basavapatna@Sun.COM 
250810309SSriharsha.Basavapatna@Sun.COM 	tx_ringp->state &= ~VNET_TXRING_STARTED;
250910309SSriharsha.Basavapatna@Sun.COM }
251010309SSriharsha.Basavapatna@Sun.COM 
251111878SVenu.Iyer@Sun.COM static int
251211878SVenu.Iyer@Sun.COM vnet_tx_ring_stat(mac_ring_driver_t rdriver, uint_t stat, uint64_t *val)
251311878SVenu.Iyer@Sun.COM {
251411878SVenu.Iyer@Sun.COM 	vnet_pseudo_tx_ring_t	*tx_ringp = (vnet_pseudo_tx_ring_t *)rdriver;
251511878SVenu.Iyer@Sun.COM 	vnet_tx_ring_stats_t	*statsp;
251611878SVenu.Iyer@Sun.COM 
251711878SVenu.Iyer@Sun.COM 	statsp = &tx_ringp->tx_ring_stats;
251811878SVenu.Iyer@Sun.COM 
251911878SVenu.Iyer@Sun.COM 	switch (stat) {
252011878SVenu.Iyer@Sun.COM 	case MAC_STAT_OPACKETS:
252111878SVenu.Iyer@Sun.COM 		*val = statsp->opackets;
252211878SVenu.Iyer@Sun.COM 		break;
252311878SVenu.Iyer@Sun.COM 
252411878SVenu.Iyer@Sun.COM 	case MAC_STAT_OBYTES:
252511878SVenu.Iyer@Sun.COM 		*val = statsp->obytes;
252611878SVenu.Iyer@Sun.COM 		break;
252711878SVenu.Iyer@Sun.COM 
252811878SVenu.Iyer@Sun.COM 	default:
252911878SVenu.Iyer@Sun.COM 		*val = 0;
253011878SVenu.Iyer@Sun.COM 		return (ENOTSUP);
253111878SVenu.Iyer@Sun.COM 	}
253211878SVenu.Iyer@Sun.COM 
253311878SVenu.Iyer@Sun.COM 	return (0);
253411878SVenu.Iyer@Sun.COM }
253511878SVenu.Iyer@Sun.COM 
253610309SSriharsha.Basavapatna@Sun.COM /*
253710309SSriharsha.Basavapatna@Sun.COM  * Disable polling for a ring and enable its interrupt.
253810309SSriharsha.Basavapatna@Sun.COM  */
253910309SSriharsha.Basavapatna@Sun.COM static int
254010309SSriharsha.Basavapatna@Sun.COM vnet_ring_enable_intr(void *arg)
254110309SSriharsha.Basavapatna@Sun.COM {
254210309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_rx_ring_t	*rx_ringp = (vnet_pseudo_rx_ring_t *)arg;
254310309SSriharsha.Basavapatna@Sun.COM 	vnet_res_t		*vresp;
254410309SSriharsha.Basavapatna@Sun.COM 
254510309SSriharsha.Basavapatna@Sun.COM 	if (rx_ringp->hw_rh == NULL) {
254610309SSriharsha.Basavapatna@Sun.COM 		/*
254710309SSriharsha.Basavapatna@Sun.COM 		 * Ring enable intr func is being invoked, but the ring is
254810309SSriharsha.Basavapatna@Sun.COM 		 * not bound to any underlying resource ? This must be a ring
254910309SSriharsha.Basavapatna@Sun.COM 		 * reserved for Hybrid resource and no such resource has been
255010309SSriharsha.Basavapatna@Sun.COM 		 * assigned to this vnet device yet. We simply return success.
255110309SSriharsha.Basavapatna@Sun.COM 		 */
255210309SSriharsha.Basavapatna@Sun.COM 		ASSERT((rx_ringp->state & VNET_RXRING_HYBRID) != 0);
255310309SSriharsha.Basavapatna@Sun.COM 		return (0);
255410309SSriharsha.Basavapatna@Sun.COM 	}
255510309SSriharsha.Basavapatna@Sun.COM 
255610309SSriharsha.Basavapatna@Sun.COM 	/*
255710309SSriharsha.Basavapatna@Sun.COM 	 * The rx ring has been bound to either a LDC or a Hybrid resource.
255810309SSriharsha.Basavapatna@Sun.COM 	 * Call the appropriate function to enable interrupts for the ring.
255910309SSriharsha.Basavapatna@Sun.COM 	 */
256010309SSriharsha.Basavapatna@Sun.COM 	if (rx_ringp->state & VNET_RXRING_HYBRID) {
256110309SSriharsha.Basavapatna@Sun.COM 		return (mac_hwring_enable_intr(rx_ringp->hw_rh));
256210309SSriharsha.Basavapatna@Sun.COM 	} else {
256310309SSriharsha.Basavapatna@Sun.COM 		vresp = (vnet_res_t *)rx_ringp->hw_rh;
256410309SSriharsha.Basavapatna@Sun.COM 		return (vgen_enable_intr(vresp->macreg.m_driver));
256510309SSriharsha.Basavapatna@Sun.COM 	}
256610309SSriharsha.Basavapatna@Sun.COM }
256710309SSriharsha.Basavapatna@Sun.COM 
256810309SSriharsha.Basavapatna@Sun.COM /*
256910309SSriharsha.Basavapatna@Sun.COM  * Enable polling for a ring and disable its interrupt.
257010309SSriharsha.Basavapatna@Sun.COM  */
257110309SSriharsha.Basavapatna@Sun.COM static int
257210309SSriharsha.Basavapatna@Sun.COM vnet_ring_disable_intr(void *arg)
257310309SSriharsha.Basavapatna@Sun.COM {
257410309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_rx_ring_t	*rx_ringp = (vnet_pseudo_rx_ring_t *)arg;
257510309SSriharsha.Basavapatna@Sun.COM 	vnet_res_t		*vresp;
257610309SSriharsha.Basavapatna@Sun.COM 
257710309SSriharsha.Basavapatna@Sun.COM 	if (rx_ringp->hw_rh == NULL) {
257810309SSriharsha.Basavapatna@Sun.COM 		/*
257910309SSriharsha.Basavapatna@Sun.COM 		 * Ring disable intr func is being invoked, but the ring is
258010309SSriharsha.Basavapatna@Sun.COM 		 * not bound to any underlying resource ? This must be a ring
258110309SSriharsha.Basavapatna@Sun.COM 		 * reserved for Hybrid resource and no such resource has been
258210309SSriharsha.Basavapatna@Sun.COM 		 * assigned to this vnet device yet. We simply return success.
258310309SSriharsha.Basavapatna@Sun.COM 		 */
258410309SSriharsha.Basavapatna@Sun.COM 		ASSERT((rx_ringp->state & VNET_RXRING_HYBRID) != 0);
258510309SSriharsha.Basavapatna@Sun.COM 		return (0);
258610309SSriharsha.Basavapatna@Sun.COM 	}
258710309SSriharsha.Basavapatna@Sun.COM 
258810309SSriharsha.Basavapatna@Sun.COM 	/*
258910309SSriharsha.Basavapatna@Sun.COM 	 * The rx ring has been bound to either a LDC or a Hybrid resource.
259010309SSriharsha.Basavapatna@Sun.COM 	 * Call the appropriate function to disable interrupts for the ring.
259110309SSriharsha.Basavapatna@Sun.COM 	 */
259210309SSriharsha.Basavapatna@Sun.COM 	if (rx_ringp->state & VNET_RXRING_HYBRID) {
259310309SSriharsha.Basavapatna@Sun.COM 		return (mac_hwring_disable_intr(rx_ringp->hw_rh));
259410309SSriharsha.Basavapatna@Sun.COM 	} else {
259510309SSriharsha.Basavapatna@Sun.COM 		vresp = (vnet_res_t *)rx_ringp->hw_rh;
259610309SSriharsha.Basavapatna@Sun.COM 		return (vgen_disable_intr(vresp->macreg.m_driver));
259710309SSriharsha.Basavapatna@Sun.COM 	}
259810309SSriharsha.Basavapatna@Sun.COM }
259910309SSriharsha.Basavapatna@Sun.COM 
260010309SSriharsha.Basavapatna@Sun.COM /*
260110309SSriharsha.Basavapatna@Sun.COM  * Poll 'bytes_to_pickup' bytes of message from the rx ring.
260210309SSriharsha.Basavapatna@Sun.COM  */
260310309SSriharsha.Basavapatna@Sun.COM static mblk_t *
260410309SSriharsha.Basavapatna@Sun.COM vnet_rx_poll(void *arg, int bytes_to_pickup)
260510309SSriharsha.Basavapatna@Sun.COM {
260610309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_rx_ring_t	*rx_ringp = (vnet_pseudo_rx_ring_t *)arg;
260710309SSriharsha.Basavapatna@Sun.COM 	mblk_t			*mp = NULL;
260810309SSriharsha.Basavapatna@Sun.COM 	vnet_res_t		*vresp;
260910309SSriharsha.Basavapatna@Sun.COM 	vnet_t			*vnetp = rx_ringp->vnetp;
261010309SSriharsha.Basavapatna@Sun.COM 
261110309SSriharsha.Basavapatna@Sun.COM 	if (rx_ringp->hw_rh == NULL) {
261210309SSriharsha.Basavapatna@Sun.COM 		return (NULL);
261310309SSriharsha.Basavapatna@Sun.COM 	}
261410309SSriharsha.Basavapatna@Sun.COM 
261510309SSriharsha.Basavapatna@Sun.COM 	if (rx_ringp->state & VNET_RXRING_HYBRID) {
261610309SSriharsha.Basavapatna@Sun.COM 		mp = mac_hwring_poll(rx_ringp->hw_rh, bytes_to_pickup);
261710309SSriharsha.Basavapatna@Sun.COM 		/*
261810309SSriharsha.Basavapatna@Sun.COM 		 * Packets received over a hybrid resource need additional
261910309SSriharsha.Basavapatna@Sun.COM 		 * processing to remove the tag, for the pvid case. The
262010309SSriharsha.Basavapatna@Sun.COM 		 * underlying resource is not aware of the vnet's pvid and thus
262110309SSriharsha.Basavapatna@Sun.COM 		 * packets are received with the vlan tag in the header; unlike
262210309SSriharsha.Basavapatna@Sun.COM 		 * packets that are received over a ldc channel in which case
262310309SSriharsha.Basavapatna@Sun.COM 		 * the peer vnet/vsw would have already removed the tag.
262410309SSriharsha.Basavapatna@Sun.COM 		 */
262510309SSriharsha.Basavapatna@Sun.COM 		if (vnetp->pvid != vnetp->default_vlan_id) {
262610309SSriharsha.Basavapatna@Sun.COM 			vnet_rx_frames_untag(vnetp->pvid, &mp);
262710309SSriharsha.Basavapatna@Sun.COM 		}
262810309SSriharsha.Basavapatna@Sun.COM 	} else {
262910309SSriharsha.Basavapatna@Sun.COM 		vresp = (vnet_res_t *)rx_ringp->hw_rh;
263010309SSriharsha.Basavapatna@Sun.COM 		mp = vgen_poll(vresp->macreg.m_driver, bytes_to_pickup);
263110309SSriharsha.Basavapatna@Sun.COM 	}
263210309SSriharsha.Basavapatna@Sun.COM 	return (mp);
263310309SSriharsha.Basavapatna@Sun.COM }
263410309SSriharsha.Basavapatna@Sun.COM 
263510309SSriharsha.Basavapatna@Sun.COM /* ARGSUSED */
263610309SSriharsha.Basavapatna@Sun.COM void
263710309SSriharsha.Basavapatna@Sun.COM vnet_hio_rx_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
263810309SSriharsha.Basavapatna@Sun.COM 	boolean_t loopback)
263910309SSriharsha.Basavapatna@Sun.COM {
264010309SSriharsha.Basavapatna@Sun.COM 	vnet_t			*vnetp = (vnet_t *)arg;
264110309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_rx_ring_t	*ringp = (vnet_pseudo_rx_ring_t *)mrh;
264210309SSriharsha.Basavapatna@Sun.COM 
264310309SSriharsha.Basavapatna@Sun.COM 	/*
264410309SSriharsha.Basavapatna@Sun.COM 	 * Packets received over a hybrid resource need additional processing
264510309SSriharsha.Basavapatna@Sun.COM 	 * to remove the tag, for the pvid case. The underlying resource is
264610309SSriharsha.Basavapatna@Sun.COM 	 * not aware of the vnet's pvid and thus packets are received with the
264710309SSriharsha.Basavapatna@Sun.COM 	 * vlan tag in the header; unlike packets that are received over a ldc
264810309SSriharsha.Basavapatna@Sun.COM 	 * channel in which case the peer vnet/vsw would have already removed
264910309SSriharsha.Basavapatna@Sun.COM 	 * the tag.
265010309SSriharsha.Basavapatna@Sun.COM 	 */
265110309SSriharsha.Basavapatna@Sun.COM 	if (vnetp->pvid != vnetp->default_vlan_id) {
265210309SSriharsha.Basavapatna@Sun.COM 		vnet_rx_frames_untag(vnetp->pvid, &mp);
265310309SSriharsha.Basavapatna@Sun.COM 		if (mp == NULL) {
265410309SSriharsha.Basavapatna@Sun.COM 			return;
265510309SSriharsha.Basavapatna@Sun.COM 		}
265610309SSriharsha.Basavapatna@Sun.COM 	}
265710309SSriharsha.Basavapatna@Sun.COM 	mac_rx_ring(vnetp->mh, ringp->handle, mp, ringp->gen_num);
265810309SSriharsha.Basavapatna@Sun.COM }
265910309SSriharsha.Basavapatna@Sun.COM 
266010309SSriharsha.Basavapatna@Sun.COM static int
266110309SSriharsha.Basavapatna@Sun.COM vnet_addmac(void *arg, const uint8_t *mac_addr)
266210309SSriharsha.Basavapatna@Sun.COM {
266310309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_rx_group_t  *rx_grp = (vnet_pseudo_rx_group_t *)arg;
266410309SSriharsha.Basavapatna@Sun.COM 	vnet_t			*vnetp;
266510309SSriharsha.Basavapatna@Sun.COM 
266610309SSriharsha.Basavapatna@Sun.COM 	vnetp = rx_grp->vnetp;
266710309SSriharsha.Basavapatna@Sun.COM 
266810309SSriharsha.Basavapatna@Sun.COM 	if (bcmp(mac_addr, vnetp->curr_macaddr, ETHERADDRL) == 0) {
266910309SSriharsha.Basavapatna@Sun.COM 		return (0);
267010309SSriharsha.Basavapatna@Sun.COM 	}
267110309SSriharsha.Basavapatna@Sun.COM 
267210309SSriharsha.Basavapatna@Sun.COM 	cmn_err(CE_CONT, "!vnet%d: %s: Multiple macaddr unsupported\n",
267310309SSriharsha.Basavapatna@Sun.COM 	    vnetp->instance, __func__);
267410309SSriharsha.Basavapatna@Sun.COM 	return (EINVAL);
267510309SSriharsha.Basavapatna@Sun.COM }
267610309SSriharsha.Basavapatna@Sun.COM 
267710309SSriharsha.Basavapatna@Sun.COM static int
267810309SSriharsha.Basavapatna@Sun.COM vnet_remmac(void *arg, const uint8_t *mac_addr)
267910309SSriharsha.Basavapatna@Sun.COM {
268010309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_rx_group_t  *rx_grp = (vnet_pseudo_rx_group_t *)arg;
268110309SSriharsha.Basavapatna@Sun.COM 	vnet_t			*vnetp;
268210309SSriharsha.Basavapatna@Sun.COM 
268310309SSriharsha.Basavapatna@Sun.COM 	vnetp = rx_grp->vnetp;
268410309SSriharsha.Basavapatna@Sun.COM 
268510309SSriharsha.Basavapatna@Sun.COM 	if (bcmp(mac_addr, vnetp->curr_macaddr, ETHERADDRL) == 0) {
268610309SSriharsha.Basavapatna@Sun.COM 		return (0);
268710309SSriharsha.Basavapatna@Sun.COM 	}
268810309SSriharsha.Basavapatna@Sun.COM 
268910309SSriharsha.Basavapatna@Sun.COM 	cmn_err(CE_CONT, "!vnet%d: %s: Invalid macaddr: %s\n",
269010309SSriharsha.Basavapatna@Sun.COM 	    vnetp->instance, __func__, ether_sprintf((void *)mac_addr));
269110309SSriharsha.Basavapatna@Sun.COM 	return (EINVAL);
269210309SSriharsha.Basavapatna@Sun.COM }
269310309SSriharsha.Basavapatna@Sun.COM 
269410309SSriharsha.Basavapatna@Sun.COM int
269510309SSriharsha.Basavapatna@Sun.COM vnet_hio_mac_init(vnet_t *vnetp, char *ifname)
269610309SSriharsha.Basavapatna@Sun.COM {
269710309SSriharsha.Basavapatna@Sun.COM 	mac_handle_t		mh;
269810309SSriharsha.Basavapatna@Sun.COM 	mac_client_handle_t	mch = NULL;
269910309SSriharsha.Basavapatna@Sun.COM 	mac_unicast_handle_t	muh = NULL;
270010309SSriharsha.Basavapatna@Sun.COM 	mac_diag_t		diag;
270110309SSriharsha.Basavapatna@Sun.COM 	mac_register_t		*macp;
270210309SSriharsha.Basavapatna@Sun.COM 	char			client_name[MAXNAMELEN];
270310309SSriharsha.Basavapatna@Sun.COM 	int			rv;
270410309SSriharsha.Basavapatna@Sun.COM 	uint16_t		mac_flags = MAC_UNICAST_TAG_DISABLE |
270510309SSriharsha.Basavapatna@Sun.COM 	    MAC_UNICAST_STRIP_DISABLE | MAC_UNICAST_PRIMARY;
270610309SSriharsha.Basavapatna@Sun.COM 	vio_net_callbacks_t	vcb;
270710309SSriharsha.Basavapatna@Sun.COM 	ether_addr_t		rem_addr =
270810309SSriharsha.Basavapatna@Sun.COM 		{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
270910309SSriharsha.Basavapatna@Sun.COM 	uint32_t		retries = 0;
271010309SSriharsha.Basavapatna@Sun.COM 
271110309SSriharsha.Basavapatna@Sun.COM 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
271210309SSriharsha.Basavapatna@Sun.COM 		return (EAGAIN);
271310309SSriharsha.Basavapatna@Sun.COM 	}
271410309SSriharsha.Basavapatna@Sun.COM 
271510309SSriharsha.Basavapatna@Sun.COM 	do {
271610309SSriharsha.Basavapatna@Sun.COM 		rv = mac_open_by_linkname(ifname, &mh);
271710309SSriharsha.Basavapatna@Sun.COM 		if (rv == 0) {
271810309SSriharsha.Basavapatna@Sun.COM 			break;
271910309SSriharsha.Basavapatna@Sun.COM 		}
272010309SSriharsha.Basavapatna@Sun.COM 		if (rv != ENOENT || (retries++ >= vnet_mac_open_retries)) {
272110309SSriharsha.Basavapatna@Sun.COM 			mac_free(macp);
272210309SSriharsha.Basavapatna@Sun.COM 			return (rv);
272310309SSriharsha.Basavapatna@Sun.COM 		}
272410309SSriharsha.Basavapatna@Sun.COM 		drv_usecwait(vnet_mac_open_delay);
272510309SSriharsha.Basavapatna@Sun.COM 	} while (rv == ENOENT);
272610309SSriharsha.Basavapatna@Sun.COM 
272710309SSriharsha.Basavapatna@Sun.COM 	vnetp->hio_mh = mh;
272810309SSriharsha.Basavapatna@Sun.COM 
272910309SSriharsha.Basavapatna@Sun.COM 	(void) snprintf(client_name, MAXNAMELEN, "vnet%d-%s", vnetp->instance,
273010309SSriharsha.Basavapatna@Sun.COM 	    ifname);
273110309SSriharsha.Basavapatna@Sun.COM 	rv = mac_client_open(mh, &mch, client_name, MAC_OPEN_FLAGS_EXCLUSIVE);
273210309SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
273310309SSriharsha.Basavapatna@Sun.COM 		goto fail;
273410309SSriharsha.Basavapatna@Sun.COM 	}
273510309SSriharsha.Basavapatna@Sun.COM 	vnetp->hio_mch = mch;
273610309SSriharsha.Basavapatna@Sun.COM 
273710309SSriharsha.Basavapatna@Sun.COM 	rv = mac_unicast_add(mch, vnetp->curr_macaddr, mac_flags, &muh, 0,
273810309SSriharsha.Basavapatna@Sun.COM 	    &diag);
273910309SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
274010309SSriharsha.Basavapatna@Sun.COM 		goto fail;
274110309SSriharsha.Basavapatna@Sun.COM 	}
274210309SSriharsha.Basavapatna@Sun.COM 	vnetp->hio_muh = muh;
274310309SSriharsha.Basavapatna@Sun.COM 
274410309SSriharsha.Basavapatna@Sun.COM 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
274510309SSriharsha.Basavapatna@Sun.COM 	macp->m_driver = vnetp;
274610309SSriharsha.Basavapatna@Sun.COM 	macp->m_dip = NULL;
274710309SSriharsha.Basavapatna@Sun.COM 	macp->m_src_addr = NULL;
274810309SSriharsha.Basavapatna@Sun.COM 	macp->m_callbacks = &vnet_hio_res_callbacks;
274910309SSriharsha.Basavapatna@Sun.COM 	macp->m_min_sdu = 0;
275010309SSriharsha.Basavapatna@Sun.COM 	macp->m_max_sdu = ETHERMTU;
275110309SSriharsha.Basavapatna@Sun.COM 
275210309SSriharsha.Basavapatna@Sun.COM 	rv = vio_net_resource_reg(macp, VIO_NET_RES_HYBRID,
275310309SSriharsha.Basavapatna@Sun.COM 	    vnetp->curr_macaddr, rem_addr, &vnetp->hio_vhp, &vcb);
275410309SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
275510309SSriharsha.Basavapatna@Sun.COM 		goto fail;
275610309SSriharsha.Basavapatna@Sun.COM 	}
275710309SSriharsha.Basavapatna@Sun.COM 	mac_free(macp);
275810309SSriharsha.Basavapatna@Sun.COM 
275910309SSriharsha.Basavapatna@Sun.COM 	/* add the recv callback */
276010309SSriharsha.Basavapatna@Sun.COM 	mac_rx_set(vnetp->hio_mch, vnet_hio_rx_cb, vnetp);
276110309SSriharsha.Basavapatna@Sun.COM 
276210309SSriharsha.Basavapatna@Sun.COM 	return (0);
276310309SSriharsha.Basavapatna@Sun.COM 
276410309SSriharsha.Basavapatna@Sun.COM fail:
276510309SSriharsha.Basavapatna@Sun.COM 	mac_free(macp);
276610309SSriharsha.Basavapatna@Sun.COM 	vnet_hio_mac_cleanup(vnetp);
276710309SSriharsha.Basavapatna@Sun.COM 	return (1);
276810309SSriharsha.Basavapatna@Sun.COM }
276910309SSriharsha.Basavapatna@Sun.COM 
277010309SSriharsha.Basavapatna@Sun.COM void
277110309SSriharsha.Basavapatna@Sun.COM vnet_hio_mac_cleanup(vnet_t *vnetp)
277210309SSriharsha.Basavapatna@Sun.COM {
277310309SSriharsha.Basavapatna@Sun.COM 	if (vnetp->hio_vhp != NULL) {
277410309SSriharsha.Basavapatna@Sun.COM 		vio_net_resource_unreg(vnetp->hio_vhp);
277510309SSriharsha.Basavapatna@Sun.COM 		vnetp->hio_vhp = NULL;
277610309SSriharsha.Basavapatna@Sun.COM 	}
277710309SSriharsha.Basavapatna@Sun.COM 
277810309SSriharsha.Basavapatna@Sun.COM 	if (vnetp->hio_muh != NULL) {
277911311SSurya.Prakki@Sun.COM 		(void) mac_unicast_remove(vnetp->hio_mch, vnetp->hio_muh);
278010309SSriharsha.Basavapatna@Sun.COM 		vnetp->hio_muh = NULL;
278110309SSriharsha.Basavapatna@Sun.COM 	}
278210309SSriharsha.Basavapatna@Sun.COM 
278310309SSriharsha.Basavapatna@Sun.COM 	if (vnetp->hio_mch != NULL) {
278410309SSriharsha.Basavapatna@Sun.COM 		mac_client_close(vnetp->hio_mch, 0);
278510309SSriharsha.Basavapatna@Sun.COM 		vnetp->hio_mch = NULL;
278610309SSriharsha.Basavapatna@Sun.COM 	}
278710309SSriharsha.Basavapatna@Sun.COM 
278810309SSriharsha.Basavapatna@Sun.COM 	if (vnetp->hio_mh != NULL) {
278910309SSriharsha.Basavapatna@Sun.COM 		mac_close(vnetp->hio_mh);
279010309SSriharsha.Basavapatna@Sun.COM 		vnetp->hio_mh = NULL;
279110309SSriharsha.Basavapatna@Sun.COM 	}
279210309SSriharsha.Basavapatna@Sun.COM }
279310309SSriharsha.Basavapatna@Sun.COM 
279410309SSriharsha.Basavapatna@Sun.COM /* Bind pseudo rings to hwrings */
279510309SSriharsha.Basavapatna@Sun.COM static int
279610309SSriharsha.Basavapatna@Sun.COM vnet_bind_hwrings(vnet_t *vnetp)
279710309SSriharsha.Basavapatna@Sun.COM {
279810309SSriharsha.Basavapatna@Sun.COM 	mac_ring_handle_t	hw_rh[VNET_NUM_HYBRID_RINGS];
279910309SSriharsha.Basavapatna@Sun.COM 	mac_perim_handle_t	mph1;
280010309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_rx_group_t	*rx_grp;
280110309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_rx_ring_t	*rx_ringp;
280210309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_tx_group_t	*tx_grp;
280310309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_tx_ring_t	*tx_ringp;
280410309SSriharsha.Basavapatna@Sun.COM 	int			hw_ring_cnt;
280510309SSriharsha.Basavapatna@Sun.COM 	int			i;
280610309SSriharsha.Basavapatna@Sun.COM 	int			rv;
280710309SSriharsha.Basavapatna@Sun.COM 
280810309SSriharsha.Basavapatna@Sun.COM 	mac_perim_enter_by_mh(vnetp->hio_mh, &mph1);
280910309SSriharsha.Basavapatna@Sun.COM 
281010309SSriharsha.Basavapatna@Sun.COM 	/* Get the list of the underlying RX rings. */
281110309SSriharsha.Basavapatna@Sun.COM 	hw_ring_cnt = mac_hwrings_get(vnetp->hio_mch, &vnetp->rx_hwgh, hw_rh,
281210309SSriharsha.Basavapatna@Sun.COM 	    MAC_RING_TYPE_RX);
281310309SSriharsha.Basavapatna@Sun.COM 
281410309SSriharsha.Basavapatna@Sun.COM 	/* We expect the the # of hw rx rings to match VNET_NUM_HYBRID_RINGS */
281510309SSriharsha.Basavapatna@Sun.COM 	if (hw_ring_cnt != VNET_NUM_HYBRID_RINGS) {
281610309SSriharsha.Basavapatna@Sun.COM 		cmn_err(CE_WARN,
281710309SSriharsha.Basavapatna@Sun.COM 		    "!vnet%d: vnet_bind_hwrings: bad rx hw_ring_cnt(%d)\n",
281810309SSriharsha.Basavapatna@Sun.COM 		    vnetp->instance, hw_ring_cnt);
281910309SSriharsha.Basavapatna@Sun.COM 		goto fail;
282010309SSriharsha.Basavapatna@Sun.COM 	}
282110309SSriharsha.Basavapatna@Sun.COM 
282210309SSriharsha.Basavapatna@Sun.COM 	if (vnetp->rx_hwgh != NULL) {
282310309SSriharsha.Basavapatna@Sun.COM 		/*
282410309SSriharsha.Basavapatna@Sun.COM 		 * Quiesce the HW ring and the mac srs on the ring. Note
282510309SSriharsha.Basavapatna@Sun.COM 		 * that the HW ring will be restarted when the pseudo ring
282610309SSriharsha.Basavapatna@Sun.COM 		 * is started. At that time all the packets will be
282710309SSriharsha.Basavapatna@Sun.COM 		 * directly passed up to the pseudo RX ring and handled
282810309SSriharsha.Basavapatna@Sun.COM 		 * by mac srs created over the pseudo RX ring.
282910309SSriharsha.Basavapatna@Sun.COM 		 */
283010309SSriharsha.Basavapatna@Sun.COM 		mac_rx_client_quiesce(vnetp->hio_mch);
283110309SSriharsha.Basavapatna@Sun.COM 		mac_srs_perm_quiesce(vnetp->hio_mch, B_TRUE);
283210309SSriharsha.Basavapatna@Sun.COM 	}
283310309SSriharsha.Basavapatna@Sun.COM 
283410309SSriharsha.Basavapatna@Sun.COM 	/*
283510309SSriharsha.Basavapatna@Sun.COM 	 * Bind the pseudo rings to the hwrings and start the hwrings.
283610309SSriharsha.Basavapatna@Sun.COM 	 * Note we don't need to register these with the upper mac, as we have
283710309SSriharsha.Basavapatna@Sun.COM 	 * statically exported these pseudo rxrings which are reserved for
283810309SSriharsha.Basavapatna@Sun.COM 	 * rxrings of Hybrid resource.
283910309SSriharsha.Basavapatna@Sun.COM 	 */
284010309SSriharsha.Basavapatna@Sun.COM 	rx_grp = &vnetp->rx_grp[0];
284110309SSriharsha.Basavapatna@Sun.COM 	for (i = 0; i < VNET_NUM_HYBRID_RINGS; i++) {
284210309SSriharsha.Basavapatna@Sun.COM 		/* Pick the rxrings reserved for Hybrid resource */
284310309SSriharsha.Basavapatna@Sun.COM 		rx_ringp = &rx_grp->rings[i + VNET_HYBRID_RXRING_INDEX];
284410309SSriharsha.Basavapatna@Sun.COM 
284510309SSriharsha.Basavapatna@Sun.COM 		/* Store the hw ring handle */
284610309SSriharsha.Basavapatna@Sun.COM 		rx_ringp->hw_rh = hw_rh[i];
284710309SSriharsha.Basavapatna@Sun.COM 
284810309SSriharsha.Basavapatna@Sun.COM 		/* Bind the pseudo ring to the underlying hwring */
284910309SSriharsha.Basavapatna@Sun.COM 		mac_hwring_setup(rx_ringp->hw_rh,
285011878SVenu.Iyer@Sun.COM 		    (mac_resource_handle_t)rx_ringp, NULL);
285110309SSriharsha.Basavapatna@Sun.COM 
285210309SSriharsha.Basavapatna@Sun.COM 		/* Start the hwring if needed */
285310309SSriharsha.Basavapatna@Sun.COM 		if (rx_ringp->state & VNET_RXRING_STARTED) {
285410309SSriharsha.Basavapatna@Sun.COM 			rv = mac_hwring_start(rx_ringp->hw_rh);
285510309SSriharsha.Basavapatna@Sun.COM 			if (rv != 0) {
285610309SSriharsha.Basavapatna@Sun.COM 				mac_hwring_teardown(rx_ringp->hw_rh);
285710309SSriharsha.Basavapatna@Sun.COM 				rx_ringp->hw_rh = NULL;
285810309SSriharsha.Basavapatna@Sun.COM 				goto fail;
285910309SSriharsha.Basavapatna@Sun.COM 			}
286010309SSriharsha.Basavapatna@Sun.COM 		}
286110309SSriharsha.Basavapatna@Sun.COM 	}
286210309SSriharsha.Basavapatna@Sun.COM 
286310309SSriharsha.Basavapatna@Sun.COM 	/* Get the list of the underlying TX rings. */
286410309SSriharsha.Basavapatna@Sun.COM 	hw_ring_cnt = mac_hwrings_get(vnetp->hio_mch, &vnetp->tx_hwgh, hw_rh,
286510309SSriharsha.Basavapatna@Sun.COM 	    MAC_RING_TYPE_TX);
286610309SSriharsha.Basavapatna@Sun.COM 
286710309SSriharsha.Basavapatna@Sun.COM 	/* We expect the # of hw tx rings to match VNET_NUM_HYBRID_RINGS */
286810309SSriharsha.Basavapatna@Sun.COM 	if (hw_ring_cnt != VNET_NUM_HYBRID_RINGS) {
286910309SSriharsha.Basavapatna@Sun.COM 		cmn_err(CE_WARN,
287010309SSriharsha.Basavapatna@Sun.COM 		    "!vnet%d: vnet_bind_hwrings: bad tx hw_ring_cnt(%d)\n",
287110309SSriharsha.Basavapatna@Sun.COM 		    vnetp->instance, hw_ring_cnt);
287210309SSriharsha.Basavapatna@Sun.COM 		goto fail;
287310309SSriharsha.Basavapatna@Sun.COM 	}
287410309SSriharsha.Basavapatna@Sun.COM 
287510309SSriharsha.Basavapatna@Sun.COM 	/*
287610309SSriharsha.Basavapatna@Sun.COM 	 * Now map the pseudo txrings to the hw txrings. Note we don't need
287710309SSriharsha.Basavapatna@Sun.COM 	 * to register these with the upper mac, as we have statically exported
287810309SSriharsha.Basavapatna@Sun.COM 	 * these rings. Note that these rings will continue to be used for LDC
287910309SSriharsha.Basavapatna@Sun.COM 	 * resources to peer vnets and vswitch (shared ring).
288010309SSriharsha.Basavapatna@Sun.COM 	 */
288110309SSriharsha.Basavapatna@Sun.COM 	tx_grp = &vnetp->tx_grp[0];
288210309SSriharsha.Basavapatna@Sun.COM 	for (i = 0; i < tx_grp->ring_cnt; i++) {
288310309SSriharsha.Basavapatna@Sun.COM 		tx_ringp = &tx_grp->rings[i];
288410309SSriharsha.Basavapatna@Sun.COM 		tx_ringp->hw_rh = hw_rh[i];
288510309SSriharsha.Basavapatna@Sun.COM 		tx_ringp->state |= VNET_TXRING_HYBRID;
288610309SSriharsha.Basavapatna@Sun.COM 	}
288711878SVenu.Iyer@Sun.COM 	tx_grp->tx_notify_handle =
288811878SVenu.Iyer@Sun.COM 	    mac_client_tx_notify(vnetp->hio_mch, vnet_tx_ring_update, vnetp);
288910309SSriharsha.Basavapatna@Sun.COM 
289010309SSriharsha.Basavapatna@Sun.COM 	mac_perim_exit(mph1);
289110309SSriharsha.Basavapatna@Sun.COM 	return (0);
289210309SSriharsha.Basavapatna@Sun.COM 
289310309SSriharsha.Basavapatna@Sun.COM fail:
289410309SSriharsha.Basavapatna@Sun.COM 	mac_perim_exit(mph1);
289510309SSriharsha.Basavapatna@Sun.COM 	vnet_unbind_hwrings(vnetp);
289610309SSriharsha.Basavapatna@Sun.COM 	return (1);
289710309SSriharsha.Basavapatna@Sun.COM }
289810309SSriharsha.Basavapatna@Sun.COM 
289910309SSriharsha.Basavapatna@Sun.COM /* Unbind pseudo rings from hwrings */
290010309SSriharsha.Basavapatna@Sun.COM static void
290110309SSriharsha.Basavapatna@Sun.COM vnet_unbind_hwrings(vnet_t *vnetp)
290210309SSriharsha.Basavapatna@Sun.COM {
290310309SSriharsha.Basavapatna@Sun.COM 	mac_perim_handle_t	mph1;
290410309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_rx_ring_t	*rx_ringp;
290510309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_rx_group_t	*rx_grp;
290610309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_tx_group_t	*tx_grp;
290710309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_tx_ring_t	*tx_ringp;
290810309SSriharsha.Basavapatna@Sun.COM 	int			i;
290910309SSriharsha.Basavapatna@Sun.COM 
291010309SSriharsha.Basavapatna@Sun.COM 	mac_perim_enter_by_mh(vnetp->hio_mh, &mph1);
291110309SSriharsha.Basavapatna@Sun.COM 
291210309SSriharsha.Basavapatna@Sun.COM 	tx_grp = &vnetp->tx_grp[0];
291310309SSriharsha.Basavapatna@Sun.COM 	for (i = 0; i < VNET_NUM_HYBRID_RINGS; i++) {
291410309SSriharsha.Basavapatna@Sun.COM 		tx_ringp = &tx_grp->rings[i];
291510309SSriharsha.Basavapatna@Sun.COM 		if (tx_ringp->state & VNET_TXRING_HYBRID) {
291610309SSriharsha.Basavapatna@Sun.COM 			tx_ringp->state &= ~VNET_TXRING_HYBRID;
291710309SSriharsha.Basavapatna@Sun.COM 			tx_ringp->hw_rh = NULL;
291810309SSriharsha.Basavapatna@Sun.COM 		}
291910309SSriharsha.Basavapatna@Sun.COM 	}
292011878SVenu.Iyer@Sun.COM 	(void) mac_client_tx_notify(vnetp->hio_mch, NULL,
292111878SVenu.Iyer@Sun.COM 	    tx_grp->tx_notify_handle);
292210309SSriharsha.Basavapatna@Sun.COM 
292310309SSriharsha.Basavapatna@Sun.COM 	rx_grp = &vnetp->rx_grp[0];
292410309SSriharsha.Basavapatna@Sun.COM 	for (i = 0; i < VNET_NUM_HYBRID_RINGS; i++) {
292510309SSriharsha.Basavapatna@Sun.COM 		rx_ringp = &rx_grp->rings[i + VNET_HYBRID_RXRING_INDEX];
292610309SSriharsha.Basavapatna@Sun.COM 		if (rx_ringp->hw_rh != NULL) {
292710309SSriharsha.Basavapatna@Sun.COM 			/* Stop the hwring */
292810309SSriharsha.Basavapatna@Sun.COM 			mac_hwring_stop(rx_ringp->hw_rh);
292910309SSriharsha.Basavapatna@Sun.COM 
293010309SSriharsha.Basavapatna@Sun.COM 			/* Teardown the hwring */
293110309SSriharsha.Basavapatna@Sun.COM 			mac_hwring_teardown(rx_ringp->hw_rh);
293210309SSriharsha.Basavapatna@Sun.COM 			rx_ringp->hw_rh = NULL;
293310309SSriharsha.Basavapatna@Sun.COM 		}
293410309SSriharsha.Basavapatna@Sun.COM 	}
293510309SSriharsha.Basavapatna@Sun.COM 
293610309SSriharsha.Basavapatna@Sun.COM 	if (vnetp->rx_hwgh != NULL) {
293710309SSriharsha.Basavapatna@Sun.COM 		vnetp->rx_hwgh = NULL;
293810309SSriharsha.Basavapatna@Sun.COM 		/*
293910309SSriharsha.Basavapatna@Sun.COM 		 * First clear the permanent-quiesced flag of the RX srs then
294010309SSriharsha.Basavapatna@Sun.COM 		 * restart the HW ring and the mac srs on the ring.
294110309SSriharsha.Basavapatna@Sun.COM 		 */
294210309SSriharsha.Basavapatna@Sun.COM 		mac_srs_perm_quiesce(vnetp->hio_mch, B_FALSE);
294310309SSriharsha.Basavapatna@Sun.COM 		mac_rx_client_restart(vnetp->hio_mch);
294410309SSriharsha.Basavapatna@Sun.COM 	}
294510309SSriharsha.Basavapatna@Sun.COM 
294610309SSriharsha.Basavapatna@Sun.COM 	mac_perim_exit(mph1);
294710309SSriharsha.Basavapatna@Sun.COM }
294810309SSriharsha.Basavapatna@Sun.COM 
294910309SSriharsha.Basavapatna@Sun.COM /* Bind pseudo ring to a LDC resource */
295010309SSriharsha.Basavapatna@Sun.COM static int
295110309SSriharsha.Basavapatna@Sun.COM vnet_bind_vgenring(vnet_res_t *vresp)
295210309SSriharsha.Basavapatna@Sun.COM {
295310309SSriharsha.Basavapatna@Sun.COM 	vnet_t			*vnetp;
295410309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_rx_group_t	*rx_grp;
295510309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_rx_ring_t	*rx_ringp;
295610309SSriharsha.Basavapatna@Sun.COM 	mac_perim_handle_t	mph1;
295710309SSriharsha.Basavapatna@Sun.COM 	int			rv;
295810309SSriharsha.Basavapatna@Sun.COM 	int			type;
295910309SSriharsha.Basavapatna@Sun.COM 
296010309SSriharsha.Basavapatna@Sun.COM 	vnetp = vresp->vnetp;
296110309SSriharsha.Basavapatna@Sun.COM 	type = vresp->type;
296210309SSriharsha.Basavapatna@Sun.COM 	rx_grp = &vnetp->rx_grp[0];
296310309SSriharsha.Basavapatna@Sun.COM 
296410309SSriharsha.Basavapatna@Sun.COM 	if (type == VIO_NET_RES_LDC_SERVICE) {
296510309SSriharsha.Basavapatna@Sun.COM 		/*
296610309SSriharsha.Basavapatna@Sun.COM 		 * Ring Index 0 is the default ring in the group and is
296710309SSriharsha.Basavapatna@Sun.COM 		 * reserved for LDC_SERVICE in vnet_ring_grp_init(). This ring
296810309SSriharsha.Basavapatna@Sun.COM 		 * is allocated statically and is reported to the mac layer
296910309SSriharsha.Basavapatna@Sun.COM 		 * in vnet_m_capab(). So, all we need to do here, is save a
297010309SSriharsha.Basavapatna@Sun.COM 		 * reference to the associated vresp.
297110309SSriharsha.Basavapatna@Sun.COM 		 */
297210309SSriharsha.Basavapatna@Sun.COM 		rx_ringp = &rx_grp->rings[0];
297310309SSriharsha.Basavapatna@Sun.COM 		rx_ringp->hw_rh = (mac_ring_handle_t)vresp;
297410309SSriharsha.Basavapatna@Sun.COM 		vresp->rx_ringp = (void *)rx_ringp;
297510309SSriharsha.Basavapatna@Sun.COM 		return (0);
297610309SSriharsha.Basavapatna@Sun.COM 	}
297710309SSriharsha.Basavapatna@Sun.COM 	ASSERT(type == VIO_NET_RES_LDC_GUEST);
297810309SSriharsha.Basavapatna@Sun.COM 
297910309SSriharsha.Basavapatna@Sun.COM 	mac_perim_enter_by_mh(vnetp->mh, &mph1);
298010309SSriharsha.Basavapatna@Sun.COM 
298110309SSriharsha.Basavapatna@Sun.COM 	rx_ringp = vnet_alloc_pseudo_rx_ring(vnetp);
298210309SSriharsha.Basavapatna@Sun.COM 	if (rx_ringp == NULL) {
298310309SSriharsha.Basavapatna@Sun.COM 		cmn_err(CE_WARN, "!vnet%d: Failed to allocate pseudo rx ring",
298410309SSriharsha.Basavapatna@Sun.COM 		    vnetp->instance);
298510309SSriharsha.Basavapatna@Sun.COM 		goto fail;
298610309SSriharsha.Basavapatna@Sun.COM 	}
298710309SSriharsha.Basavapatna@Sun.COM 
298810309SSriharsha.Basavapatna@Sun.COM 	/* Store the LDC resource itself as the ring handle */
298910309SSriharsha.Basavapatna@Sun.COM 	rx_ringp->hw_rh = (mac_ring_handle_t)vresp;
299010309SSriharsha.Basavapatna@Sun.COM 
299110309SSriharsha.Basavapatna@Sun.COM 	/*
299210309SSriharsha.Basavapatna@Sun.COM 	 * Save a reference to the ring in the resource for lookup during
299310309SSriharsha.Basavapatna@Sun.COM 	 * unbind. Note this is only done for LDC resources. We don't need this
299410309SSriharsha.Basavapatna@Sun.COM 	 * in the case of a Hybrid resource (see vnet_bind_hwrings()), as its
299510309SSriharsha.Basavapatna@Sun.COM 	 * rx rings are mapped to reserved pseudo rx rings (index 1 and 2).
299610309SSriharsha.Basavapatna@Sun.COM 	 */
299710309SSriharsha.Basavapatna@Sun.COM 	vresp->rx_ringp = (void *)rx_ringp;
299810309SSriharsha.Basavapatna@Sun.COM 	rx_ringp->state |= VNET_RXRING_LDC_GUEST;
299910309SSriharsha.Basavapatna@Sun.COM 
300010309SSriharsha.Basavapatna@Sun.COM 	/* Register the pseudo ring with upper-mac */
300110309SSriharsha.Basavapatna@Sun.COM 	rv = mac_group_add_ring(rx_grp->handle, rx_ringp->index);
300210309SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
300310309SSriharsha.Basavapatna@Sun.COM 		rx_ringp->state &= ~VNET_RXRING_LDC_GUEST;
300410309SSriharsha.Basavapatna@Sun.COM 		rx_ringp->hw_rh = NULL;
300510309SSriharsha.Basavapatna@Sun.COM 		vnet_free_pseudo_rx_ring(vnetp, rx_ringp);
300610309SSriharsha.Basavapatna@Sun.COM 		goto fail;
300710309SSriharsha.Basavapatna@Sun.COM 	}
300810309SSriharsha.Basavapatna@Sun.COM 
300910309SSriharsha.Basavapatna@Sun.COM 	mac_perim_exit(mph1);
301010309SSriharsha.Basavapatna@Sun.COM 	return (0);
301110309SSriharsha.Basavapatna@Sun.COM fail:
301210309SSriharsha.Basavapatna@Sun.COM 	mac_perim_exit(mph1);
301310309SSriharsha.Basavapatna@Sun.COM 	return (1);
301410309SSriharsha.Basavapatna@Sun.COM }
301510309SSriharsha.Basavapatna@Sun.COM 
301610309SSriharsha.Basavapatna@Sun.COM /* Unbind pseudo ring from a LDC resource */
301710309SSriharsha.Basavapatna@Sun.COM static void
301810309SSriharsha.Basavapatna@Sun.COM vnet_unbind_vgenring(vnet_res_t *vresp)
301910309SSriharsha.Basavapatna@Sun.COM {
302010309SSriharsha.Basavapatna@Sun.COM 	vnet_t			*vnetp;
302110309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_rx_group_t	*rx_grp;
302210309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_rx_ring_t	*rx_ringp;
302310309SSriharsha.Basavapatna@Sun.COM 	mac_perim_handle_t	mph1;
302410309SSriharsha.Basavapatna@Sun.COM 	int			type;
302510309SSriharsha.Basavapatna@Sun.COM 
302610309SSriharsha.Basavapatna@Sun.COM 	vnetp = vresp->vnetp;
302710309SSriharsha.Basavapatna@Sun.COM 	type = vresp->type;
302810309SSriharsha.Basavapatna@Sun.COM 	rx_grp = &vnetp->rx_grp[0];
302910309SSriharsha.Basavapatna@Sun.COM 
303010309SSriharsha.Basavapatna@Sun.COM 	if (vresp->rx_ringp == NULL) {
303110309SSriharsha.Basavapatna@Sun.COM 		return;
303210309SSriharsha.Basavapatna@Sun.COM 	}
303310309SSriharsha.Basavapatna@Sun.COM 
303410309SSriharsha.Basavapatna@Sun.COM 	if (type == VIO_NET_RES_LDC_SERVICE) {
303510309SSriharsha.Basavapatna@Sun.COM 		/*
303610309SSriharsha.Basavapatna@Sun.COM 		 * Ring Index 0 is the default ring in the group and is
303710309SSriharsha.Basavapatna@Sun.COM 		 * reserved for LDC_SERVICE in vnet_ring_grp_init(). This ring
303810309SSriharsha.Basavapatna@Sun.COM 		 * is allocated statically and is reported to the mac layer
303910309SSriharsha.Basavapatna@Sun.COM 		 * in vnet_m_capab(). So, all we need to do here, is remove its
304010309SSriharsha.Basavapatna@Sun.COM 		 * reference to the associated vresp.
304110309SSriharsha.Basavapatna@Sun.COM 		 */
304210309SSriharsha.Basavapatna@Sun.COM 		rx_ringp = &rx_grp->rings[0];
304310309SSriharsha.Basavapatna@Sun.COM 		rx_ringp->hw_rh = NULL;
304410309SSriharsha.Basavapatna@Sun.COM 		vresp->rx_ringp = NULL;
304510309SSriharsha.Basavapatna@Sun.COM 		return;
304610309SSriharsha.Basavapatna@Sun.COM 	}
304710309SSriharsha.Basavapatna@Sun.COM 	ASSERT(type == VIO_NET_RES_LDC_GUEST);
304810309SSriharsha.Basavapatna@Sun.COM 
304910309SSriharsha.Basavapatna@Sun.COM 	mac_perim_enter_by_mh(vnetp->mh, &mph1);
305010309SSriharsha.Basavapatna@Sun.COM 
305110309SSriharsha.Basavapatna@Sun.COM 	rx_ringp = (vnet_pseudo_rx_ring_t *)vresp->rx_ringp;
305210309SSriharsha.Basavapatna@Sun.COM 	vresp->rx_ringp = NULL;
305310309SSriharsha.Basavapatna@Sun.COM 
305410309SSriharsha.Basavapatna@Sun.COM 	if (rx_ringp != NULL && (rx_ringp->state & VNET_RXRING_LDC_GUEST)) {
305510309SSriharsha.Basavapatna@Sun.COM 		/* Unregister the pseudo ring with upper-mac */
305610309SSriharsha.Basavapatna@Sun.COM 		mac_group_rem_ring(rx_grp->handle, rx_ringp->handle);
305710309SSriharsha.Basavapatna@Sun.COM 
305810309SSriharsha.Basavapatna@Sun.COM 		rx_ringp->hw_rh = NULL;
305910309SSriharsha.Basavapatna@Sun.COM 		rx_ringp->state &= ~VNET_RXRING_LDC_GUEST;
306010309SSriharsha.Basavapatna@Sun.COM 
306110309SSriharsha.Basavapatna@Sun.COM 		/* Free the pseudo rx ring */
306210309SSriharsha.Basavapatna@Sun.COM 		vnet_free_pseudo_rx_ring(vnetp, rx_ringp);
306310309SSriharsha.Basavapatna@Sun.COM 	}
306410309SSriharsha.Basavapatna@Sun.COM 
306510309SSriharsha.Basavapatna@Sun.COM 	mac_perim_exit(mph1);
306610309SSriharsha.Basavapatna@Sun.COM }
306710309SSriharsha.Basavapatna@Sun.COM 
306810309SSriharsha.Basavapatna@Sun.COM static void
306910309SSriharsha.Basavapatna@Sun.COM vnet_unbind_rings(vnet_res_t *vresp)
307010309SSriharsha.Basavapatna@Sun.COM {
307110309SSriharsha.Basavapatna@Sun.COM 	switch (vresp->type) {
307210309SSriharsha.Basavapatna@Sun.COM 
307310309SSriharsha.Basavapatna@Sun.COM 	case VIO_NET_RES_LDC_SERVICE:
307410309SSriharsha.Basavapatna@Sun.COM 	case VIO_NET_RES_LDC_GUEST:
307510309SSriharsha.Basavapatna@Sun.COM 		vnet_unbind_vgenring(vresp);
307610309SSriharsha.Basavapatna@Sun.COM 		break;
307710309SSriharsha.Basavapatna@Sun.COM 
307810309SSriharsha.Basavapatna@Sun.COM 	case VIO_NET_RES_HYBRID:
307910309SSriharsha.Basavapatna@Sun.COM 		vnet_unbind_hwrings(vresp->vnetp);
308010309SSriharsha.Basavapatna@Sun.COM 		break;
308110309SSriharsha.Basavapatna@Sun.COM 
308210309SSriharsha.Basavapatna@Sun.COM 	default:
308310309SSriharsha.Basavapatna@Sun.COM 		break;
308410309SSriharsha.Basavapatna@Sun.COM 
308510309SSriharsha.Basavapatna@Sun.COM 	}
308610309SSriharsha.Basavapatna@Sun.COM }
308710309SSriharsha.Basavapatna@Sun.COM 
308810309SSriharsha.Basavapatna@Sun.COM static int
308910309SSriharsha.Basavapatna@Sun.COM vnet_bind_rings(vnet_res_t *vresp)
309010309SSriharsha.Basavapatna@Sun.COM {
309110309SSriharsha.Basavapatna@Sun.COM 	int	rv;
309210309SSriharsha.Basavapatna@Sun.COM 
309310309SSriharsha.Basavapatna@Sun.COM 	switch (vresp->type) {
309410309SSriharsha.Basavapatna@Sun.COM 
309510309SSriharsha.Basavapatna@Sun.COM 	case VIO_NET_RES_LDC_SERVICE:
309610309SSriharsha.Basavapatna@Sun.COM 	case VIO_NET_RES_LDC_GUEST:
309710309SSriharsha.Basavapatna@Sun.COM 		rv = vnet_bind_vgenring(vresp);
309810309SSriharsha.Basavapatna@Sun.COM 		break;
309910309SSriharsha.Basavapatna@Sun.COM 
310010309SSriharsha.Basavapatna@Sun.COM 	case VIO_NET_RES_HYBRID:
310110309SSriharsha.Basavapatna@Sun.COM 		rv = vnet_bind_hwrings(vresp->vnetp);
310210309SSriharsha.Basavapatna@Sun.COM 		break;
310310309SSriharsha.Basavapatna@Sun.COM 
310410309SSriharsha.Basavapatna@Sun.COM 	default:
310510309SSriharsha.Basavapatna@Sun.COM 		rv = 1;
310610309SSriharsha.Basavapatna@Sun.COM 		break;
310710309SSriharsha.Basavapatna@Sun.COM 
310810309SSriharsha.Basavapatna@Sun.COM 	}
310910309SSriharsha.Basavapatna@Sun.COM 
311010309SSriharsha.Basavapatna@Sun.COM 	return (rv);
311110309SSriharsha.Basavapatna@Sun.COM }
311210309SSriharsha.Basavapatna@Sun.COM 
311310309SSriharsha.Basavapatna@Sun.COM /* ARGSUSED */
311410309SSriharsha.Basavapatna@Sun.COM int
311510309SSriharsha.Basavapatna@Sun.COM vnet_hio_stat(void *arg, uint_t stat, uint64_t *val)
311610309SSriharsha.Basavapatna@Sun.COM {
311710309SSriharsha.Basavapatna@Sun.COM 	vnet_t	*vnetp = (vnet_t *)arg;
311810309SSriharsha.Basavapatna@Sun.COM 
311910309SSriharsha.Basavapatna@Sun.COM 	*val = mac_stat_get(vnetp->hio_mh, stat);
312010309SSriharsha.Basavapatna@Sun.COM 	return (0);
312110309SSriharsha.Basavapatna@Sun.COM }
312210309SSriharsha.Basavapatna@Sun.COM 
312310309SSriharsha.Basavapatna@Sun.COM /*
312410309SSriharsha.Basavapatna@Sun.COM  * The start() and stop() routines for the Hybrid resource below, are just
312510309SSriharsha.Basavapatna@Sun.COM  * dummy functions. This is provided to avoid resource type specific code in
312610309SSriharsha.Basavapatna@Sun.COM  * vnet_start_resources() and vnet_stop_resources(). The starting and stopping
312710309SSriharsha.Basavapatna@Sun.COM  * of the Hybrid resource happens in the context of the mac_client interfaces
312810309SSriharsha.Basavapatna@Sun.COM  * that are invoked in vnet_hio_mac_init() and vnet_hio_mac_cleanup().
312910309SSriharsha.Basavapatna@Sun.COM  */
313010309SSriharsha.Basavapatna@Sun.COM /* ARGSUSED */
313110309SSriharsha.Basavapatna@Sun.COM static int
313210309SSriharsha.Basavapatna@Sun.COM vnet_hio_start(void *arg)
313310309SSriharsha.Basavapatna@Sun.COM {
313410309SSriharsha.Basavapatna@Sun.COM 	return (0);
313510309SSriharsha.Basavapatna@Sun.COM }
313610309SSriharsha.Basavapatna@Sun.COM 
313710309SSriharsha.Basavapatna@Sun.COM /* ARGSUSED */
313810309SSriharsha.Basavapatna@Sun.COM static void
313910309SSriharsha.Basavapatna@Sun.COM vnet_hio_stop(void *arg)
314010309SSriharsha.Basavapatna@Sun.COM {
314110309SSriharsha.Basavapatna@Sun.COM }
314210309SSriharsha.Basavapatna@Sun.COM 
314310309SSriharsha.Basavapatna@Sun.COM mblk_t *
314410309SSriharsha.Basavapatna@Sun.COM vnet_hio_tx(void *arg, mblk_t *mp)
314510309SSriharsha.Basavapatna@Sun.COM {
314610309SSriharsha.Basavapatna@Sun.COM 	vnet_pseudo_tx_ring_t	*tx_ringp;
314710309SSriharsha.Basavapatna@Sun.COM 	mblk_t			*nextp;
314810309SSriharsha.Basavapatna@Sun.COM 	mblk_t			*ret_mp;
314910309SSriharsha.Basavapatna@Sun.COM 
315010309SSriharsha.Basavapatna@Sun.COM 	tx_ringp = (vnet_pseudo_tx_ring_t *)arg;
315110309SSriharsha.Basavapatna@Sun.COM 	for (;;) {
315210309SSriharsha.Basavapatna@Sun.COM 		nextp = mp->b_next;
315310309SSriharsha.Basavapatna@Sun.COM 		mp->b_next = NULL;
315410309SSriharsha.Basavapatna@Sun.COM 
315510309SSriharsha.Basavapatna@Sun.COM 		ret_mp = mac_hwring_tx(tx_ringp->hw_rh, mp);
315610309SSriharsha.Basavapatna@Sun.COM 		if (ret_mp != NULL) {
315710309SSriharsha.Basavapatna@Sun.COM 			ret_mp->b_next = nextp;
315810309SSriharsha.Basavapatna@Sun.COM 			mp = ret_mp;
315910309SSriharsha.Basavapatna@Sun.COM 			break;
316010309SSriharsha.Basavapatna@Sun.COM 		}
316110309SSriharsha.Basavapatna@Sun.COM 
316210309SSriharsha.Basavapatna@Sun.COM 		if ((mp = nextp) == NULL)
316310309SSriharsha.Basavapatna@Sun.COM 			break;
316410309SSriharsha.Basavapatna@Sun.COM 	}
316510309SSriharsha.Basavapatna@Sun.COM 	return (mp);
316610309SSriharsha.Basavapatna@Sun.COM }
316710309SSriharsha.Basavapatna@Sun.COM 
31689336SSriharsha.Basavapatna@Sun.COM #ifdef	VNET_IOC_DEBUG
31699336SSriharsha.Basavapatna@Sun.COM 
31709336SSriharsha.Basavapatna@Sun.COM /*
31719336SSriharsha.Basavapatna@Sun.COM  * The ioctl entry point is used only for debugging for now. The ioctl commands
31729336SSriharsha.Basavapatna@Sun.COM  * can be used to force the link state of the channel connected to vsw.
31739336SSriharsha.Basavapatna@Sun.COM  */
31749336SSriharsha.Basavapatna@Sun.COM static void
31759336SSriharsha.Basavapatna@Sun.COM vnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
31769336SSriharsha.Basavapatna@Sun.COM {
31779336SSriharsha.Basavapatna@Sun.COM 	struct iocblk	*iocp;
31789336SSriharsha.Basavapatna@Sun.COM 	vnet_t		*vnetp;
31799336SSriharsha.Basavapatna@Sun.COM 
31809336SSriharsha.Basavapatna@Sun.COM 	iocp = (struct iocblk *)(uintptr_t)mp->b_rptr;
31819336SSriharsha.Basavapatna@Sun.COM 	iocp->ioc_error = 0;
31829336SSriharsha.Basavapatna@Sun.COM 	vnetp = (vnet_t *)arg;
31839336SSriharsha.Basavapatna@Sun.COM 
31849336SSriharsha.Basavapatna@Sun.COM 	if (vnetp == NULL) {
31859336SSriharsha.Basavapatna@Sun.COM 		miocnak(q, mp, 0, EINVAL);
31869336SSriharsha.Basavapatna@Sun.COM 		return;
31879336SSriharsha.Basavapatna@Sun.COM 	}
31889336SSriharsha.Basavapatna@Sun.COM 
31899336SSriharsha.Basavapatna@Sun.COM 	switch (iocp->ioc_cmd) {
31909336SSriharsha.Basavapatna@Sun.COM 
31919336SSriharsha.Basavapatna@Sun.COM 	case VNET_FORCE_LINK_DOWN:
31929336SSriharsha.Basavapatna@Sun.COM 	case VNET_FORCE_LINK_UP:
31939336SSriharsha.Basavapatna@Sun.COM 		vnet_force_link_state(vnetp, q, mp);
31949336SSriharsha.Basavapatna@Sun.COM 		break;
31959336SSriharsha.Basavapatna@Sun.COM 
31969336SSriharsha.Basavapatna@Sun.COM 	default:
31979336SSriharsha.Basavapatna@Sun.COM 		iocp->ioc_error = EINVAL;
31989336SSriharsha.Basavapatna@Sun.COM 		miocnak(q, mp, 0, iocp->ioc_error);
31999336SSriharsha.Basavapatna@Sun.COM 		break;
32009336SSriharsha.Basavapatna@Sun.COM 
32019336SSriharsha.Basavapatna@Sun.COM 	}
32029336SSriharsha.Basavapatna@Sun.COM }
32039336SSriharsha.Basavapatna@Sun.COM 
32049336SSriharsha.Basavapatna@Sun.COM static void
32059336SSriharsha.Basavapatna@Sun.COM vnet_force_link_state(vnet_t *vnetp, queue_t *q, mblk_t *mp)
32069336SSriharsha.Basavapatna@Sun.COM {
32079336SSriharsha.Basavapatna@Sun.COM 	mac_register_t	*macp;
32089336SSriharsha.Basavapatna@Sun.COM 	mac_callbacks_t	*cbp;
32099336SSriharsha.Basavapatna@Sun.COM 	vnet_res_t	*vresp;
32109336SSriharsha.Basavapatna@Sun.COM 
32119336SSriharsha.Basavapatna@Sun.COM 	READ_ENTER(&vnetp->vsw_fp_rw);
32129336SSriharsha.Basavapatna@Sun.COM 
32139336SSriharsha.Basavapatna@Sun.COM 	vresp = vnetp->vsw_fp;
32149336SSriharsha.Basavapatna@Sun.COM 	if (vresp == NULL) {
32159336SSriharsha.Basavapatna@Sun.COM 		RW_EXIT(&vnetp->vsw_fp_rw);
32169336SSriharsha.Basavapatna@Sun.COM 		return;
32179336SSriharsha.Basavapatna@Sun.COM 	}
32189336SSriharsha.Basavapatna@Sun.COM 
32199336SSriharsha.Basavapatna@Sun.COM 	macp = &vresp->macreg;
32209336SSriharsha.Basavapatna@Sun.COM 	cbp = macp->m_callbacks;
32219336SSriharsha.Basavapatna@Sun.COM 	cbp->mc_ioctl(macp->m_driver, q, mp);
32229336SSriharsha.Basavapatna@Sun.COM 
32239336SSriharsha.Basavapatna@Sun.COM 	RW_EXIT(&vnetp->vsw_fp_rw);
32249336SSriharsha.Basavapatna@Sun.COM }
32259336SSriharsha.Basavapatna@Sun.COM 
32269336SSriharsha.Basavapatna@Sun.COM #else
32279336SSriharsha.Basavapatna@Sun.COM 
32289336SSriharsha.Basavapatna@Sun.COM static void
32299336SSriharsha.Basavapatna@Sun.COM vnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
32309336SSriharsha.Basavapatna@Sun.COM {
32319336SSriharsha.Basavapatna@Sun.COM 	vnet_t		*vnetp;
32329336SSriharsha.Basavapatna@Sun.COM 
32339336SSriharsha.Basavapatna@Sun.COM 	vnetp = (vnet_t *)arg;
32349336SSriharsha.Basavapatna@Sun.COM 
32359336SSriharsha.Basavapatna@Sun.COM 	if (vnetp == NULL) {
32369336SSriharsha.Basavapatna@Sun.COM 		miocnak(q, mp, 0, EINVAL);
32379336SSriharsha.Basavapatna@Sun.COM 		return;
32389336SSriharsha.Basavapatna@Sun.COM 	}
32399336SSriharsha.Basavapatna@Sun.COM 
32409336SSriharsha.Basavapatna@Sun.COM 	/* ioctl support only for debugging */
32419336SSriharsha.Basavapatna@Sun.COM 	miocnak(q, mp, 0, ENOTSUP);
32429336SSriharsha.Basavapatna@Sun.COM }
32439336SSriharsha.Basavapatna@Sun.COM 
32449336SSriharsha.Basavapatna@Sun.COM #endif
3245