xref: /onnv-gate/usr/src/uts/sun4v/io/vsw_hio.c (revision 12011:2377022c7a2d)
16495Sspeer /*
26495Sspeer  * CDDL HEADER START
36495Sspeer  *
46495Sspeer  * The contents of this file are subject to the terms of the
56495Sspeer  * Common Development and Distribution License (the "License").
66495Sspeer  * You may not use this file except in compliance with the License.
76495Sspeer  *
86495Sspeer  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96495Sspeer  * or http://www.opensolaris.org/os/licensing.
106495Sspeer  * See the License for the specific language governing permissions
116495Sspeer  * and limitations under the License.
126495Sspeer  *
136495Sspeer  * When distributing Covered Code, include this CDDL HEADER in each
146495Sspeer  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156495Sspeer  * If applicable, add the following below this CDDL HEADER, with the
166495Sspeer  * fields enclosed by brackets "[]" replaced with your own identifying
176495Sspeer  * information: Portions Copyright [yyyy] [name of copyright owner]
186495Sspeer  *
196495Sspeer  * CDDL HEADER END
206495Sspeer  */
216495Sspeer 
226495Sspeer /*
23*12011SSriharsha.Basavapatna@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
246495Sspeer  * Use is subject to license terms.
256495Sspeer  */
266495Sspeer 
276495Sspeer #include <sys/types.h>
286495Sspeer #include <sys/errno.h>
296495Sspeer #include <sys/debug.h>
306495Sspeer #include <sys/time.h>
316495Sspeer #include <sys/sysmacros.h>
326495Sspeer #include <sys/systm.h>
336495Sspeer #include <sys/user.h>
346495Sspeer #include <sys/stropts.h>
356495Sspeer #include <sys/stream.h>
366495Sspeer #include <sys/strlog.h>
376495Sspeer #include <sys/strsubr.h>
386495Sspeer #include <sys/cmn_err.h>
396495Sspeer #include <sys/cpu.h>
406495Sspeer #include <sys/kmem.h>
416495Sspeer #include <sys/conf.h>
426495Sspeer #include <sys/ddi.h>
436495Sspeer #include <sys/sunddi.h>
446495Sspeer #include <sys/ksynch.h>
456495Sspeer #include <sys/stat.h>
466495Sspeer #include <sys/kstat.h>
476495Sspeer #include <sys/vtrace.h>
486495Sspeer #include <sys/strsun.h>
496495Sspeer #include <sys/dlpi.h>
506495Sspeer #include <sys/ethernet.h>
516495Sspeer #include <net/if.h>
526495Sspeer #include <sys/varargs.h>
536495Sspeer #include <sys/machsystm.h>
546495Sspeer #include <sys/modctl.h>
556495Sspeer #include <sys/modhash.h>
568275SEric Cheng #include <sys/mac_provider.h>
576495Sspeer #include <sys/mac_ether.h>
586495Sspeer #include <sys/taskq.h>
596495Sspeer #include <sys/note.h>
606495Sspeer #include <sys/mach_descrip.h>
616495Sspeer #include <sys/mac.h>
626495Sspeer #include <sys/mdeg.h>
636495Sspeer #include <sys/ldc.h>
646495Sspeer #include <sys/vsw_fdb.h>
656495Sspeer #include <sys/vsw.h>
666495Sspeer #include <sys/vio_mailbox.h>
676495Sspeer #include <sys/vnet_mailbox.h>
686495Sspeer #include <sys/vnet_common.h>
696495Sspeer #include <sys/vio_util.h>
706495Sspeer #include <sys/sdt.h>
716495Sspeer #include <sys/atomic.h>
726495Sspeer #include <sys/callb.h>
736495Sspeer 
746495Sspeer 
756495Sspeer #define	VSW_DDS_NEXT_REQID(vsharep)	(++vsharep->vs_req_id)
766495Sspeer 
776495Sspeer extern boolean_t vsw_hio_enabled;		/* HybridIO enabled? */
786495Sspeer extern int vsw_hio_max_cleanup_retries;
796495Sspeer extern int vsw_hio_cleanup_delay;
806495Sspeer 
816495Sspeer /* Functions imported from other files */
826495Sspeer extern int vsw_send_msg(vsw_ldc_t *, void *, int, boolean_t);
836724Sraghuram extern void vsw_hio_port_reset(vsw_port_t *portp, boolean_t immediate);
848275SEric Cheng extern void vsw_port_mac_reconfig(vsw_port_t *portp, boolean_t update_vlans,
858275SEric Cheng     uint16_t new_pvid, vsw_vlanid_t *new_vids, int new_nvids);
866495Sspeer 
876495Sspeer /* Functions exported to other files */
886495Sspeer void vsw_hio_init(vsw_t *vswp);
896495Sspeer void vsw_hio_cleanup(vsw_t *vswp);
906495Sspeer void vsw_hio_start(vsw_t *vswp, vsw_ldc_t *ldcp);
916495Sspeer void vsw_hio_stop(vsw_t *vswp, vsw_ldc_t *ldcp);
926495Sspeer void vsw_process_dds_msg(vsw_t *vswp, vsw_ldc_t *ldcp, void *msg);
936495Sspeer void vsw_hio_start_ports(vsw_t *vswp);
946495Sspeer void vsw_hio_stop_port(vsw_port_t *portp);
956495Sspeer 
966495Sspeer /* Support functions */
976724Sraghuram static void vsw_hio_free_all_shares(vsw_t *vswp, boolean_t reboot);
986495Sspeer static vsw_share_t *vsw_hio_alloc_share(vsw_t *vswp, vsw_ldc_t *ldcp);
996495Sspeer static void vsw_hio_free_share(vsw_share_t *vsharep);
1006495Sspeer static vsw_share_t *vsw_hio_find_free_share(vsw_t *vswp);
1016495Sspeer static vsw_share_t *vsw_hio_find_vshare_ldcid(vsw_t *vswp, uint64_t ldc_id);
1026495Sspeer static vsw_share_t *vsw_hio_find_vshare_port(vsw_t *vswp, vsw_port_t *portp);
1036495Sspeer static int vsw_send_dds_msg(vsw_ldc_t *ldcp, uint8_t dds_subclass,
1046495Sspeer     uint64_t cookie, uint64_t macaddr, uint32_t req_id);
1056495Sspeer static int vsw_send_dds_resp_msg(vsw_ldc_t *ldcp, vio_dds_msg_t *dmsg, int ack);
1066495Sspeer static int vsw_hio_send_delshare_msg(vsw_share_t *vsharep);
1076724Sraghuram static boolean_t vsw_hio_reboot_callb(void *arg, int code);
1086724Sraghuram static boolean_t vsw_hio_panic_callb(void *arg, int code);
1096495Sspeer 
1108275SEric Cheng /*
1118275SEric Cheng  * Locking strategy for HybridIO is followed as below:
1128275SEric Cheng  *
1138275SEric Cheng  *	- As the Shares are associated with a network device, the
1148275SEric Cheng  *	  the global lock('vswp>mac_lock') is used for all Shares
1158275SEric Cheng  *	  related operations.
1168275SEric Cheng  *	- The 'port->maccl_rwlock' is used to synchronize only the
1178275SEric Cheng  *	  the operations that operate on that port's mac client. That
1188275SEric Cheng  *	  is, the share_bind and unbind operations only.
1198275SEric Cheng  *
1208275SEric Cheng  *	- The locking hierarchy follows that the global mac_lock is
1218275SEric Cheng  *	  acquired first and then the ports mac client lock(maccl_rwlock)
1228275SEric Cheng  */
1238275SEric Cheng 
1248275SEric Cheng 
1258160SWentao.Yang@Sun.COM static kstat_t *vsw_hio_setup_kstats(char *ks_mod, char *ks_name, vsw_t *vswp);
1268160SWentao.Yang@Sun.COM static void vsw_hio_destroy_kstats(vsw_t *vswp);
1278160SWentao.Yang@Sun.COM static int vsw_hio_kstats_update(kstat_t *ksp, int rw);
1286495Sspeer 
1296495Sspeer /*
1306495Sspeer  * vsw_hio_init -- Initialize the HybridIO related info.
1316495Sspeer  *	- Query SHARES and RINGS capability. Both capabilities
1326495Sspeer  *	  need to be supported by the physical-device.
1336495Sspeer  */
1346495Sspeer void
vsw_hio_init(vsw_t * vswp)1356495Sspeer vsw_hio_init(vsw_t *vswp)
1366495Sspeer {
1376495Sspeer 	vsw_hio_t	*hiop = &vswp->vhio;
1388275SEric Cheng 	int		num_shares;
1396495Sspeer 	int		i;
1406495Sspeer 
1418275SEric Cheng 	ASSERT(MUTEX_HELD(&vswp->mac_lock));
1426495Sspeer 	D1(vswp, "%s:enter\n", __func__);
1436495Sspeer 	if (vsw_hio_enabled == B_FALSE) {
1446495Sspeer 		return;
1456495Sspeer 	}
1466495Sspeer 
1476495Sspeer 	vswp->hio_capable = B_FALSE;
1488275SEric Cheng 	num_shares = mac_share_capable(vswp->mh);
1498275SEric Cheng 	if (num_shares == 0) {
1506495Sspeer 		D2(vswp, "%s: %s is not HybridIO capable\n", __func__,
1516495Sspeer 		    vswp->physname);
1526495Sspeer 		return;
1536495Sspeer 	}
1548275SEric Cheng 	hiop->vh_num_shares = num_shares;
1556495Sspeer 	hiop->vh_shares = kmem_zalloc((sizeof (vsw_share_t) *
1566495Sspeer 	    hiop->vh_num_shares), KM_SLEEP);
1576495Sspeer 	for (i = 0; i < hiop->vh_num_shares; i++) {
1586495Sspeer 		hiop->vh_shares[i].vs_state = VSW_SHARE_FREE;
1596495Sspeer 		hiop->vh_shares[i].vs_index = i;
1606495Sspeer 		hiop->vh_shares[i].vs_vswp = vswp;
1616495Sspeer 	}
1626495Sspeer 	vswp->hio_capable = B_TRUE;
1636724Sraghuram 
1646724Sraghuram 	/*
1656724Sraghuram 	 * Register to get reboot and panic events so that
1666724Sraghuram 	 * we can cleanup HybridIO resources gracefully.
1676724Sraghuram 	 */
1686724Sraghuram 	vswp->hio_reboot_cb_id = callb_add(vsw_hio_reboot_callb,
1696724Sraghuram 	    (void *)vswp, CB_CL_MDBOOT, "vsw_hio");
1706724Sraghuram 
1716724Sraghuram 	vswp->hio_panic_cb_id = callb_add(vsw_hio_panic_callb,
1726724Sraghuram 	    (void *)vswp, CB_CL_PANIC, "vsw_hio");
1736724Sraghuram 
1748160SWentao.Yang@Sun.COM 	/* setup kstats for hybrid resources */
1758160SWentao.Yang@Sun.COM 	hiop->vh_ksp = vsw_hio_setup_kstats(DRV_NAME, "hio", vswp);
1768160SWentao.Yang@Sun.COM 	if (hiop->vh_ksp == NULL) {
1778160SWentao.Yang@Sun.COM 		DERR(vswp, "%s: kstats setup failed", __func__);
1788160SWentao.Yang@Sun.COM 	}
1798160SWentao.Yang@Sun.COM 
1806495Sspeer 	D2(vswp, "%s: %s is HybridIO capable num_shares=%d\n", __func__,
1816495Sspeer 	    vswp->physname, hiop->vh_num_shares);
1826495Sspeer 	D1(vswp, "%s:exit\n", __func__);
1836495Sspeer }
1846495Sspeer 
1856495Sspeer /*
1866495Sspeer  * vsw_hio_alloc_share -- Allocate and setup the share for a guest domain.
1876495Sspeer  *	- Allocate a free share.
1886495Sspeer  *	- Bind the Guest's MAC address.
1896495Sspeer  */
1906495Sspeer static vsw_share_t *
vsw_hio_alloc_share(vsw_t * vswp,vsw_ldc_t * ldcp)1916495Sspeer vsw_hio_alloc_share(vsw_t *vswp, vsw_ldc_t *ldcp)
1926495Sspeer {
1936495Sspeer 	vsw_share_t	*vsharep;
1946495Sspeer 	vsw_port_t	*portp = ldcp->ldc_port;
1956495Sspeer 	uint64_t	ldc_id = ldcp->ldc_id;
1966495Sspeer 	int		rv;
1976495Sspeer 
1986495Sspeer 	D1(vswp, "%s:enter\n", __func__);
1996495Sspeer 	vsharep = vsw_hio_find_free_share(vswp);
2006495Sspeer 	if (vsharep == NULL) {
2016495Sspeer 		/* No free shares available */
2026495Sspeer 		return (NULL);
2036495Sspeer 	}
2048275SEric Cheng 
2058275SEric Cheng 	WRITE_ENTER(&portp->maccl_rwlock);
2068275SEric Cheng 	rv = mac_share_bind(portp->p_mch, ldc_id, &vsharep->vs_cookie);
2078275SEric Cheng 	RW_EXIT(&portp->maccl_rwlock);
2086495Sspeer 	if (rv != 0) {
2096495Sspeer 		return (NULL);
2106495Sspeer 	}
2116495Sspeer 
2126495Sspeer 	/* Cache some useful info */
2136495Sspeer 	vsharep->vs_ldcid = ldcp->ldc_id;
2146495Sspeer 	vsharep->vs_macaddr = vnet_macaddr_strtoul(
2156495Sspeer 	    portp->p_macaddr.ether_addr_octet);
2166495Sspeer 	vsharep->vs_portp = ldcp->ldc_port;
2176495Sspeer 	vsharep->vs_state |= VSW_SHARE_ASSIGNED;
2186495Sspeer 
2196495Sspeer 	D1(vswp, "%s:exit\n", __func__);
2206495Sspeer 	return (vsharep);
2216495Sspeer }
2226495Sspeer 
2236495Sspeer /*
2246495Sspeer  * vsw_hio_find_free_share -- Find a free Share.
2256495Sspeer  */
2266495Sspeer static vsw_share_t *
vsw_hio_find_free_share(vsw_t * vswp)2276495Sspeer vsw_hio_find_free_share(vsw_t *vswp)
2286495Sspeer {
2296495Sspeer 	vsw_hio_t *hiop = &vswp->vhio;
2306495Sspeer 	vsw_share_t *vsharep;
2316495Sspeer 	int i;
2326495Sspeer 
2336495Sspeer 	D1(vswp, "%s:enter\n", __func__);
2346495Sspeer 	for (i = 0; i < hiop->vh_num_shares; i++) {
2356495Sspeer 		vsharep = &hiop->vh_shares[i];
2366495Sspeer 		if (vsharep->vs_state == VSW_SHARE_FREE) {
2376495Sspeer 			D1(vswp, "%s:Returning free share(%d)\n",
2386495Sspeer 			    __func__, vsharep->vs_index);
2396495Sspeer 			return (vsharep);
2406495Sspeer 		}
2416495Sspeer 	}
2426495Sspeer 	D1(vswp, "%s:no free share\n", __func__);
2436495Sspeer 	return (NULL);
2446495Sspeer }
2456495Sspeer 
2466495Sspeer /*
2476495Sspeer  * vsw_hio_find_vshare_ldcid -- Given ldc_id, find the corresponding
2486495Sspeer  *	share structure.
2496495Sspeer  */
2506495Sspeer static vsw_share_t *
vsw_hio_find_vshare_ldcid(vsw_t * vswp,uint64_t ldc_id)2516495Sspeer vsw_hio_find_vshare_ldcid(vsw_t *vswp, uint64_t ldc_id)
2526495Sspeer {
2536495Sspeer 	vsw_hio_t *hiop = &vswp->vhio;
2546495Sspeer 	vsw_share_t *vsharep;
2556495Sspeer 	int i;
2566495Sspeer 
2576495Sspeer 	D1(vswp, "%s:enter, ldc=0x%lx", __func__, ldc_id);
2586495Sspeer 	for (i = 0; i < hiop->vh_num_shares; i++) {
2596495Sspeer 		vsharep = &hiop->vh_shares[i];
2606495Sspeer 		if (vsharep->vs_state == VSW_SHARE_FREE) {
2616495Sspeer 			continue;
2626495Sspeer 		}
2636495Sspeer 		if (vsharep->vs_ldcid == ldc_id) {
2646495Sspeer 			D1(vswp, "%s:returning share(%d)",
2656495Sspeer 			    __func__, vsharep->vs_index);
2666495Sspeer 			return (vsharep);
2676495Sspeer 		}
2686495Sspeer 	}
2696495Sspeer 	D1(vswp, "%s:returning NULL", __func__);
2706495Sspeer 	return (NULL);
2716495Sspeer }
2726495Sspeer 
2736495Sspeer /*
2746495Sspeer  * vsw_hio_find_vshare_port -- Given portp, find the corresponding
2756495Sspeer  *	share structure.
2766495Sspeer  */
2776495Sspeer static vsw_share_t *
vsw_hio_find_vshare_port(vsw_t * vswp,vsw_port_t * portp)2786495Sspeer vsw_hio_find_vshare_port(vsw_t *vswp, vsw_port_t *portp)
2796495Sspeer {
2806495Sspeer 	vsw_hio_t *hiop = &vswp->vhio;
2816495Sspeer 	vsw_share_t *vsharep;
2826495Sspeer 	int i;
2836495Sspeer 
2846495Sspeer 	D1(vswp, "%s:enter, portp=0x%p", __func__, portp);
2856495Sspeer 	for (i = 0; i < hiop->vh_num_shares; i++) {
2866495Sspeer 		vsharep = &hiop->vh_shares[i];
2876495Sspeer 		if (vsharep->vs_state == VSW_SHARE_FREE) {
2886495Sspeer 			continue;
2896495Sspeer 		}
2906495Sspeer 		if (vsharep->vs_portp == portp) {
2916495Sspeer 			D1(vswp, "%s:returning share(%d)",
2926495Sspeer 			    __func__, vsharep->vs_index);
2936495Sspeer 			return (vsharep);
2946495Sspeer 		}
2956495Sspeer 	}
2966495Sspeer 	D1(vswp, "%s:returning NULL", __func__);
2976495Sspeer 	return (NULL);
2986495Sspeer }
2996495Sspeer 
3006495Sspeer /*
3016495Sspeer  * vsw_hio_free_share -- Unbind the MAC address and free share.
3026495Sspeer  */
3036495Sspeer static void
vsw_hio_free_share(vsw_share_t * vsharep)3046495Sspeer vsw_hio_free_share(vsw_share_t *vsharep)
3056495Sspeer {
3066495Sspeer 	vsw_t		*vswp = vsharep->vs_vswp;
3078275SEric Cheng 	vsw_port_t	*portp = vsharep->vs_portp;
3086495Sspeer 
3096495Sspeer 	D1(vswp, "%s:enter\n", __func__);
3106495Sspeer 
3118275SEric Cheng 	WRITE_ENTER(&portp->maccl_rwlock);
3128275SEric Cheng 	mac_share_unbind(portp->p_mch);
3138275SEric Cheng 	RW_EXIT(&portp->maccl_rwlock);
3146495Sspeer 	vsharep->vs_state = VSW_SHARE_FREE;
3158160SWentao.Yang@Sun.COM 	vsharep->vs_macaddr = 0;
3169217SWentao.Yang@Sun.COM 	vsharep->vs_portp = NULL;
3176495Sspeer 
3186495Sspeer 	/* DERR only for printing by default */
3196495Sspeer 	DERR(vswp, "Share freed for ldc_id=0x%lx Cookie=0x%lX",
3206495Sspeer 	    vsharep->vs_ldcid, vsharep->vs_cookie);
3216495Sspeer 	D1(vswp, "%s:exit\n", __func__);
3226495Sspeer }
3236495Sspeer 
3246495Sspeer 
3256495Sspeer /*
3266724Sraghuram  * vsw_hio_cleanup -- Cleanup the HybridIO. It unregisters the callbs
3276724Sraghuram  *	and frees all shares.
3286724Sraghuram  */
3296724Sraghuram void
vsw_hio_cleanup(vsw_t * vswp)3306724Sraghuram vsw_hio_cleanup(vsw_t *vswp)
3316724Sraghuram {
3326724Sraghuram 	D1(vswp, "%s:enter\n", __func__);
3336724Sraghuram 
3346724Sraghuram 	/* Unregister reboot and panic callbs. */
3356724Sraghuram 	if (vswp->hio_reboot_cb_id) {
3366724Sraghuram 		(void) callb_delete(vswp->hio_reboot_cb_id);
3376724Sraghuram 		vswp->hio_reboot_cb_id = 0;
3386724Sraghuram 	}
3396724Sraghuram 	if (vswp->hio_panic_cb_id) {
3406724Sraghuram 		(void) callb_delete(vswp->hio_panic_cb_id);
3416724Sraghuram 		vswp->hio_panic_cb_id = 0;
3426724Sraghuram 	}
3436724Sraghuram 	vsw_hio_free_all_shares(vswp, B_FALSE);
3448160SWentao.Yang@Sun.COM 	vsw_hio_destroy_kstats(vswp);
3456724Sraghuram 	D1(vswp, "%s:exit\n", __func__);
3466724Sraghuram }
3476724Sraghuram 
3486724Sraghuram /*
3496724Sraghuram  * vsw_hio_free_all_shares -- A routine to free all shares gracefully.
3506495Sspeer  *	The following are the steps followed to accomplish this:
3516495Sspeer  *
3526495Sspeer  *	- First clear 'hio_capable' to avoid further share allocations.
3536495Sspeer  *	- If a share is in accepted(ACKD) state, that means the guest
3546495Sspeer  *	  has HybridIO setup etc. If so, send a DEL_SHARE message and
3556495Sspeer  *	  give some time(delay) for the guest to ACK.
3566495Sspeer  *	- If the Share is another state, give some time to transition to
3576495Sspeer  *	  ACKD state, then try the above.
3586495Sspeer  *	- After max retries, reset the ports to brute force the shares
3596495Sspeer  *	  to be freed. Give a little delay for the LDC reset code to
3606495Sspeer  *	  free the Share.
3616495Sspeer  */
3626724Sraghuram static void
vsw_hio_free_all_shares(vsw_t * vswp,boolean_t reboot)3636724Sraghuram vsw_hio_free_all_shares(vsw_t *vswp, boolean_t reboot)
3646495Sspeer {
3656495Sspeer 	vsw_hio_t	*hiop = &vswp->vhio;
3666495Sspeer 	vsw_port_list_t	*plist = &vswp->plist;
3676495Sspeer 	vsw_share_t	*vsharep;
3686495Sspeer 	int		free_shares = 0;
3696495Sspeer 	int		max_retries = vsw_hio_max_cleanup_retries;
3706495Sspeer 	int		i;
3716495Sspeer 
3726495Sspeer 	D1(vswp, "%s:enter\n", __func__);
3736495Sspeer 
3746495Sspeer 	/*
3756495Sspeer 	 * Acquire plist->lockrw to make the locking a bit easier
3766495Sspeer 	 * and keep the ports in a stable state while we are cleaningup
3776495Sspeer 	 * HybridIO.
3786495Sspeer 	 */
3796495Sspeer 	READ_ENTER(&plist->lockrw);
3808275SEric Cheng 	mutex_enter(&vswp->mac_lock);
3816495Sspeer 	/*
3826495Sspeer 	 * first clear the hio_capable flag so that no more
3836495Sspeer 	 * HybridIO operations are initiated.
3846495Sspeer 	 */
3856495Sspeer 	vswp->hio_capable = B_FALSE;
3866495Sspeer 
3876495Sspeer 	do {
3886495Sspeer 		free_shares = 0;
3896495Sspeer 		for (i = 0; i < hiop->vh_num_shares; i++) {
3906495Sspeer 			vsharep = &hiop->vh_shares[i];
3916495Sspeer 			if (vsharep->vs_state == VSW_SHARE_FREE) {
3926495Sspeer 				free_shares++;
3936495Sspeer 				continue;
3946495Sspeer 			}
3956495Sspeer 			/*
3966495Sspeer 			 * If the share is in DDS_ACKD state, then
3976495Sspeer 			 * send DEL_SHARE message so that guest can
3986495Sspeer 			 * release its Hybrid resource.
3996495Sspeer 			 */
4006495Sspeer 			if (vsharep->vs_state & VSW_SHARE_DDS_ACKD) {
4016495Sspeer 				int rv;
4026495Sspeer 
4036495Sspeer 				/* send DDS_DEL_SHARE */
4046495Sspeer 				D1(vswp, "%s:sending DEL_SHARE msg for "
4056495Sspeer 				    "share(%d)", __func__, vsharep->vs_index);
4066495Sspeer 				rv = vsw_hio_send_delshare_msg(vsharep);
4076495Sspeer 				if (rv != 0) {
4086495Sspeer 					/*
4096495Sspeer 					 * No alternative, reset the port
4106495Sspeer 					 * to force the release of Hybrid
4116495Sspeer 					 * resources.
4126495Sspeer 					 */
4136724Sraghuram 					vsw_hio_port_reset(vsharep->vs_portp,
4146724Sraghuram 					    B_FALSE);
4156495Sspeer 				}
4166495Sspeer 			}
4176495Sspeer 			if (max_retries == 1) {
4186724Sraghuram 				/*
4196724Sraghuram 				 * Last retry,  reset the port.
4206724Sraghuram 				 * If it is reboot case, issue an immediate
4216724Sraghuram 				 * reset.
4226724Sraghuram 				 */
4236495Sspeer 				DWARN(vswp, "%s:All retries failed, "
4246495Sspeer 				    " cause a reset to trigger cleanup for "
4256495Sspeer 				    "share(%d)", __func__, vsharep->vs_index);
4266724Sraghuram 				vsw_hio_port_reset(vsharep->vs_portp, reboot);
4276495Sspeer 			}
4286495Sspeer 		}
4296495Sspeer 		if (free_shares == hiop->vh_num_shares) {
4306495Sspeer 			/* Clean up is done */
4316495Sspeer 			break;
4326495Sspeer 		}
4336495Sspeer 		/*
4346495Sspeer 		 * Release the lock so that reply for DEL_SHARE
4356495Sspeer 		 * messages come and get processed, that is, shares
4366495Sspeer 		 * get freed.
4376495Sspeer 		 * This delay is also needed for the port reset to
4386495Sspeer 		 * release the Hybrid resource.
4396495Sspeer 		 */
4408275SEric Cheng 		mutex_exit(&vswp->mac_lock);
4417819SRaghuram.Kothakota@Sun.COM 		drv_usecwait(vsw_hio_cleanup_delay);
4428275SEric Cheng 		mutex_enter(&vswp->mac_lock);
4436495Sspeer 		max_retries--;
4446495Sspeer 	} while ((free_shares < hiop->vh_num_shares) && (max_retries > 0));
4456495Sspeer 
4466495Sspeer 	/* By now, all shares should be freed */
4476495Sspeer 	if (free_shares != hiop->vh_num_shares) {
4486724Sraghuram 		if (reboot == B_FALSE) {
4496724Sraghuram 			cmn_err(CE_NOTE, "vsw%d: All physical resources "
4506724Sraghuram 			    "could not be freed", vswp->instance);
4516724Sraghuram 		}
4526495Sspeer 	}
4536495Sspeer 
4546495Sspeer 	kmem_free(hiop->vh_shares, sizeof (vsw_share_t) * hiop->vh_num_shares);
4556495Sspeer 	hiop->vh_shares = NULL;
4566495Sspeer 	hiop->vh_num_shares = 0;
4578275SEric Cheng 	mutex_exit(&vswp->mac_lock);
4586495Sspeer 	RW_EXIT(&plist->lockrw);
4596495Sspeer 	D1(vswp, "%s:exit\n", __func__);
4606495Sspeer }
4616495Sspeer 
4626495Sspeer /*
4636495Sspeer  * vsw_hio_start_ports -- Start HybridIO for ports that have
4646495Sspeer  *	already established connection before HybridIO is intialized.
4656495Sspeer  */
4666495Sspeer void
vsw_hio_start_ports(vsw_t * vswp)4676495Sspeer vsw_hio_start_ports(vsw_t *vswp)
4686495Sspeer {
4696495Sspeer 	vsw_port_list_t	*plist = &vswp->plist;
4706495Sspeer 	vsw_port_t	*portp;
4716495Sspeer 	vsw_share_t	*vsharep;
4726495Sspeer 	boolean_t	reset;
4736495Sspeer 
4746495Sspeer 	if (vswp->hio_capable == B_FALSE) {
4756495Sspeer 		return;
4766495Sspeer 	}
4776495Sspeer 	READ_ENTER(&plist->lockrw);
4786495Sspeer 	for (portp = plist->head; portp != NULL; portp = portp->p_next) {
4796495Sspeer 		if ((portp->p_hio_enabled == B_FALSE) ||
4806495Sspeer 		    (portp->p_hio_capable == B_FALSE)) {
4816495Sspeer 			continue;
4826495Sspeer 		}
4836495Sspeer 
4846495Sspeer 		reset = B_FALSE;
4858275SEric Cheng 		mutex_enter(&vswp->mac_lock);
4866495Sspeer 		vsharep = vsw_hio_find_vshare_port(vswp, portp);
4876495Sspeer 		if (vsharep == NULL) {
4886495Sspeer 			reset = B_TRUE;
4896495Sspeer 		}
4908275SEric Cheng 		mutex_exit(&vswp->mac_lock);
4916495Sspeer 
4926495Sspeer 		if (reset == B_TRUE) {
4936495Sspeer 			/* Cause a rest to trigger HybridIO setup */
4946724Sraghuram 			vsw_hio_port_reset(portp, B_FALSE);
4956495Sspeer 		}
4966495Sspeer 	}
4976495Sspeer 	RW_EXIT(&plist->lockrw);
4986495Sspeer }
4996495Sspeer 
5006495Sspeer /*
5016495Sspeer  * vsw_hio_start -- Start HybridIO for a guest(given LDC)
5026495Sspeer  */
5036495Sspeer void
vsw_hio_start(vsw_t * vswp,vsw_ldc_t * ldcp)5046495Sspeer vsw_hio_start(vsw_t *vswp, vsw_ldc_t *ldcp)
5056495Sspeer {
5066495Sspeer 	vsw_share_t	*vsharep;
5076495Sspeer 	uint32_t	req_id;
5086495Sspeer 	int		rv;
5096495Sspeer 
5106495Sspeer 	D1(vswp, "%s:enter ldc=0x%lx", __func__, ldcp->ldc_id);
5118275SEric Cheng 	mutex_enter(&vswp->mac_lock);
5126495Sspeer 	if (vswp->hio_capable == B_FALSE) {
5138275SEric Cheng 		mutex_exit(&vswp->mac_lock);
5146495Sspeer 		D2(vswp, "%s:not HIO capable", __func__);
5156495Sspeer 		return;
5166495Sspeer 	}
5176495Sspeer 
5186495Sspeer 	/* Verify if a share was already allocated */
5196495Sspeer 	vsharep = vsw_hio_find_vshare_ldcid(vswp, ldcp->ldc_id);
5206495Sspeer 	if (vsharep != NULL) {
5218275SEric Cheng 		mutex_exit(&vswp->mac_lock);
5226495Sspeer 		D2(vswp, "%s:Share already allocated to ldc=0x%lx",
5236495Sspeer 		    __func__, ldcp->ldc_id);
5246495Sspeer 		return;
5256495Sspeer 	}
5266495Sspeer 	vsharep = vsw_hio_alloc_share(vswp, ldcp);
5276495Sspeer 	if (vsharep == NULL) {
5288275SEric Cheng 		mutex_exit(&vswp->mac_lock);
5296495Sspeer 		D2(vswp, "%s: no Share available for ldc=0x%lx",
5306495Sspeer 		    __func__, ldcp->ldc_id);
5316495Sspeer 		return;
5326495Sspeer 	}
5336495Sspeer 	req_id = VSW_DDS_NEXT_REQID(vsharep);
5346495Sspeer 	rv = vsw_send_dds_msg(ldcp, DDS_VNET_ADD_SHARE, vsharep->vs_cookie,
5356495Sspeer 	    vsharep->vs_macaddr, req_id);
5366495Sspeer 	if (rv != 0) {
5376495Sspeer 		/*
5386495Sspeer 		 * Failed to send a DDS message, so cleanup now.
5396495Sspeer 		 */
5406495Sspeer 		vsw_hio_free_share(vsharep);
5418275SEric Cheng 		mutex_exit(&vswp->mac_lock);
5426495Sspeer 		return;
5436495Sspeer 	}
5446724Sraghuram 	vsharep->vs_state &= ~VSW_SHARE_DDS_ACKD;
5456495Sspeer 	vsharep->vs_state |= VSW_SHARE_DDS_SENT;
5468275SEric Cheng 	mutex_exit(&vswp->mac_lock);
5476495Sspeer 
5486495Sspeer 	/* DERR only to print by default */
5496495Sspeer 	DERR(vswp, "Share allocated for ldc_id=0x%lx Cookie=0x%lX",
5506495Sspeer 	    ldcp->ldc_id, vsharep->vs_cookie);
5516495Sspeer 
5526495Sspeer 	D1(vswp, "%s:exit ldc=0x%lx", __func__, ldcp->ldc_id);
5536495Sspeer }
5546495Sspeer 
5556495Sspeer /*
5566495Sspeer  * vsw_hio_stop -- Stop/clean the HybridIO config for a guest(given ldc).
5576495Sspeer  */
5586495Sspeer void
vsw_hio_stop(vsw_t * vswp,vsw_ldc_t * ldcp)5596495Sspeer vsw_hio_stop(vsw_t *vswp, vsw_ldc_t *ldcp)
5606495Sspeer {
5616495Sspeer 	vsw_share_t *vsharep;
5626495Sspeer 
5636495Sspeer 	D1(vswp, "%s:enter ldc=0x%lx", __func__, ldcp->ldc_id);
5646495Sspeer 
5658275SEric Cheng 	mutex_enter(&vswp->mac_lock);
5666495Sspeer 	vsharep = vsw_hio_find_vshare_ldcid(vswp, ldcp->ldc_id);
5676495Sspeer 	if (vsharep == NULL) {
5686495Sspeer 		D1(vswp, "%s:no share found for ldc=0x%lx",
5696495Sspeer 		    __func__, ldcp->ldc_id);
5708275SEric Cheng 		mutex_exit(&vswp->mac_lock);
5716495Sspeer 		return;
5726495Sspeer 	}
5736495Sspeer 	vsw_hio_free_share(vsharep);
5748275SEric Cheng 	mutex_exit(&vswp->mac_lock);
5756495Sspeer 
5766495Sspeer 	D1(vswp, "%s:exit ldc=0x%lx", __func__, ldcp->ldc_id);
5776495Sspeer }
5786495Sspeer 
5796495Sspeer /*
5806495Sspeer  * vsw_hio_send_delshare_msg -- Send a DEL_SHARE message to the	guest.
5816495Sspeer  */
5826495Sspeer static int
vsw_hio_send_delshare_msg(vsw_share_t * vsharep)5836495Sspeer vsw_hio_send_delshare_msg(vsw_share_t *vsharep)
5846495Sspeer {
5856495Sspeer 	vsw_t *vswp = vsharep->vs_vswp;
5866495Sspeer 	vsw_port_t *portp;
5876495Sspeer 	vsw_ldc_t	*ldcp;
5886495Sspeer 	uint32_t	req_id;
5896495Sspeer 	uint64_t	cookie = vsharep->vs_cookie;
5906495Sspeer 	uint64_t	macaddr = vsharep->vs_macaddr;
5916495Sspeer 	int		rv;
5926495Sspeer 
5938275SEric Cheng 	ASSERT(MUTEX_HELD(&vswp->mac_lock));
5948275SEric Cheng 	mutex_exit(&vswp->mac_lock);
5956495Sspeer 
5966495Sspeer 	portp = vsharep->vs_portp;
5976495Sspeer 	if (portp == NULL) {
5988275SEric Cheng 		mutex_enter(&vswp->mac_lock);
5996495Sspeer 		return (0);
6006495Sspeer 	}
6016495Sspeer 
602*12011SSriharsha.Basavapatna@Sun.COM 	ldcp = portp->ldcp;
6036495Sspeer 	if ((ldcp == NULL) || (ldcp->ldc_id != vsharep->vs_ldcid)) {
6048275SEric Cheng 		mutex_enter(&vswp->mac_lock);
6056495Sspeer 		return (0);
6066495Sspeer 	}
6076495Sspeer 	req_id = VSW_DDS_NEXT_REQID(vsharep);
6086495Sspeer 	rv = vsw_send_dds_msg(ldcp, DDS_VNET_DEL_SHARE,
6096495Sspeer 	    cookie, macaddr, req_id);
6106724Sraghuram 
6118275SEric Cheng 	mutex_enter(&vswp->mac_lock);
6126724Sraghuram 	if (rv == 0) {
6136724Sraghuram 		vsharep->vs_state &= ~VSW_SHARE_DDS_ACKD;
6146724Sraghuram 		vsharep->vs_state |= VSW_SHARE_DDS_SENT;
6156724Sraghuram 	}
6166495Sspeer 	return (rv);
6176495Sspeer }
6186495Sspeer 
6196495Sspeer /*
6206495Sspeer  * vsw_send_dds_msg -- Send a DDS message.
6216495Sspeer  */
6226495Sspeer static int
vsw_send_dds_msg(vsw_ldc_t * ldcp,uint8_t dds_subclass,uint64_t cookie,uint64_t macaddr,uint32_t req_id)6236495Sspeer vsw_send_dds_msg(vsw_ldc_t *ldcp, uint8_t dds_subclass, uint64_t
6246495Sspeer     cookie, uint64_t macaddr, uint32_t req_id)
6256495Sspeer {
6266495Sspeer 	vsw_t *vswp = ldcp->ldc_port->p_vswp;
6276495Sspeer 	vio_dds_msg_t	vmsg;
6286495Sspeer 	dds_share_msg_t	*smsg = &vmsg.msg.share_msg;
6296495Sspeer 	int rv;
6306495Sspeer 
6316495Sspeer 	D1(vswp, "%s:enter\n", __func__);
6326495Sspeer 	vmsg.tag.vio_msgtype = VIO_TYPE_CTRL;
6336495Sspeer 	vmsg.tag.vio_subtype = VIO_SUBTYPE_INFO;
6346495Sspeer 	vmsg.tag.vio_subtype_env = VIO_DDS_INFO;
6356495Sspeer 	vmsg.tag.vio_sid = ldcp->local_session;
6366495Sspeer 	vmsg.dds_class = DDS_VNET_NIU;
6376495Sspeer 	vmsg.dds_subclass = dds_subclass;
6386495Sspeer 	vmsg.dds_req_id = req_id;
6396495Sspeer 	smsg->macaddr = macaddr;
6406495Sspeer 	smsg->cookie = cookie;
6416495Sspeer 	rv = vsw_send_msg(ldcp, &vmsg, sizeof (vmsg), B_FALSE);
6426495Sspeer 	D1(vswp, "%s:exit rv=%d\n", __func__, rv);
6436495Sspeer 	return (rv);
6446495Sspeer }
6456495Sspeer 
6466495Sspeer /*
6476495Sspeer  * vsw_process_dds_msg -- Process a DDS message received from a guest.
6486495Sspeer  */
6496495Sspeer void
vsw_process_dds_msg(vsw_t * vswp,vsw_ldc_t * ldcp,void * msg)6506495Sspeer vsw_process_dds_msg(vsw_t *vswp, vsw_ldc_t *ldcp, void *msg)
6516495Sspeer {
6526495Sspeer 	vsw_share_t	*vsharep;
6536495Sspeer 	vio_dds_msg_t	*dmsg = msg;
6546495Sspeer 
6556495Sspeer 	D1(vswp, "%s:enter ldc=0x%lx\n", __func__, ldcp->ldc_id);
6566495Sspeer 	if (dmsg->dds_class != DDS_VNET_NIU) {
6576495Sspeer 		/* discard */
6586495Sspeer 		return;
6596495Sspeer 	}
6608275SEric Cheng 	mutex_enter(&vswp->mac_lock);
6616495Sspeer 	/*
6626495Sspeer 	 * We expect to receive DDS messages only from guests that
6636495Sspeer 	 * have HybridIO started.
6646495Sspeer 	 */
6656495Sspeer 	vsharep = vsw_hio_find_vshare_ldcid(vswp, ldcp->ldc_id);
6666495Sspeer 	if (vsharep == NULL) {
6678275SEric Cheng 		mutex_exit(&vswp->mac_lock);
6686495Sspeer 		return;
6696495Sspeer 	}
6706495Sspeer 
6716495Sspeer 	switch (dmsg->dds_subclass) {
6726495Sspeer 	case DDS_VNET_ADD_SHARE:
6736495Sspeer 		/* A response for ADD_SHARE message. */
6746495Sspeer 		D1(vswp, "%s:DDS_VNET_ADD_SHARE\n", __func__);
6756495Sspeer 		if (!(vsharep->vs_state & VSW_SHARE_DDS_SENT)) {
6766495Sspeer 			DWARN(vswp, "%s: invalid ADD_SHARE response  message "
6776495Sspeer 			    " share state=0x%X", __func__, vsharep->vs_state);
6786495Sspeer 			break;
6796495Sspeer 		}
6806495Sspeer 
6816495Sspeer 		if (dmsg->dds_req_id != vsharep->vs_req_id) {
6826495Sspeer 			DWARN(vswp, "%s: invalid req_id in ADD_SHARE response"
6836495Sspeer 			    " message req_id=0x%X share's req_id=0x%X",
6846495Sspeer 			    __func__, dmsg->dds_req_id, vsharep->vs_req_id);
6856495Sspeer 			break;
6866495Sspeer 		}
6876495Sspeer 
6886495Sspeer 		if (dmsg->tag.vio_subtype == VIO_SUBTYPE_NACK) {
6896495Sspeer 			DWARN(vswp, "%s: NACK received for ADD_SHARE"
6906495Sspeer 			    " message ldcid=0x%lx", __func__, ldcp->ldc_id);
6916495Sspeer 			/* cleanup for NACK */
6926495Sspeer 			vsw_hio_free_share(vsharep);
6936495Sspeer 		} else {
6946495Sspeer 			D2(vswp, "%s: ACK received for ADD_SHARE", __func__);
6956495Sspeer 			vsharep->vs_state &= ~VSW_SHARE_DDS_SENT;
6966495Sspeer 			vsharep->vs_state |= VSW_SHARE_DDS_ACKD;
6976495Sspeer 		}
6986495Sspeer 		break;
6996495Sspeer 
7006495Sspeer 	case DDS_VNET_DEL_SHARE:
7016495Sspeer 		/* A response for DEL_SHARE message */
7026495Sspeer 		D1(vswp, "%s:DDS_VNET_DEL_SHARE\n", __func__);
7036495Sspeer 		if (!(vsharep->vs_state & VSW_SHARE_DDS_SENT)) {
7046724Sraghuram 			DWARN(vswp, "%s: invalid DEL_SHARE response message "
7056495Sspeer 			    " share state=0x%X", __func__, vsharep->vs_state);
7066495Sspeer 			break;
7076495Sspeer 		}
7086495Sspeer 
7096495Sspeer 		if (dmsg->dds_req_id != vsharep->vs_req_id) {
7106724Sraghuram 			DWARN(vswp, "%s: invalid req_id in DEL_SHARE response"
7116495Sspeer 			    " message share req_id=0x%X share's req_id=0x%X",
7126495Sspeer 			    __func__, dmsg->dds_req_id, vsharep->vs_req_id);
7136495Sspeer 			break;
7146495Sspeer 		}
7156495Sspeer 		if (dmsg->tag.vio_subtype == VIO_SUBTYPE_NACK) {
7166724Sraghuram 			DWARN(vswp, "%s: NACK received for DEL_SHARE",
7176495Sspeer 			    __func__);
7186495Sspeer 		}
7196724Sraghuram 
7206495Sspeer 		/* There is nothing we can do, free share now */
7216495Sspeer 		vsw_hio_free_share(vsharep);
7226495Sspeer 		break;
7236495Sspeer 
7246495Sspeer 	case DDS_VNET_REL_SHARE:
7256495Sspeer 		/* Guest has released Share voluntarily, so free it now */
7266495Sspeer 		D1(vswp, "%s:DDS_VNET_REL_SHARE\n", __func__);
7276495Sspeer 		/* send ACK */
7286495Sspeer 		(void) vsw_send_dds_resp_msg(ldcp, dmsg, B_FALSE);
7296495Sspeer 		vsw_hio_free_share(vsharep);
7306495Sspeer 		break;
7316495Sspeer 	default:
7326495Sspeer 		DERR(vswp, "%s: Invalid DDS message type=0x%X",
7336495Sspeer 		    __func__, dmsg->dds_subclass);
7346495Sspeer 		break;
7356495Sspeer 	}
7368275SEric Cheng 	mutex_exit(&vswp->mac_lock);
7376495Sspeer 	D1(vswp, "%s:exit ldc=0x%lx\n", __func__, ldcp->ldc_id);
7386495Sspeer }
7396495Sspeer 
7406495Sspeer /*
7416495Sspeer  * vsw_send_dds_resp_msg -- Send a DDS response message.
7426495Sspeer  */
7436495Sspeer static int
vsw_send_dds_resp_msg(vsw_ldc_t * ldcp,vio_dds_msg_t * dmsg,int ack)7446495Sspeer vsw_send_dds_resp_msg(vsw_ldc_t *ldcp, vio_dds_msg_t *dmsg, int ack)
7456495Sspeer {
7466495Sspeer 	vsw_t	*vswp = ldcp->ldc_port->p_vswp;
7476495Sspeer 	int	rv;
7486495Sspeer 
7496495Sspeer 	D1(vswp, "%s:enter\n", __func__);
7506495Sspeer 	if (ack == B_TRUE) {
7516495Sspeer 		dmsg->tag.vio_subtype = VIO_SUBTYPE_ACK;
7526495Sspeer 		dmsg->msg.share_resp_msg.status = DDS_VNET_SUCCESS;
7536495Sspeer 	} else {
7546495Sspeer 		dmsg->tag.vio_subtype = VIO_SUBTYPE_NACK;
7556495Sspeer 		dmsg->msg.share_resp_msg.status = DDS_VNET_FAIL;
7566495Sspeer 	}
7576495Sspeer 	rv = vsw_send_msg(ldcp, dmsg, sizeof (vio_dds_msg_t), B_FALSE);
7586495Sspeer 	D1(vswp, "%s:exit rv=%d\n", __func__, rv);
7596495Sspeer 	return (rv);
7606495Sspeer }
7616495Sspeer 
7626495Sspeer /*
7636495Sspeer  * vsw_hio_port_update -- update Hybrid mode change for a port.
7646495Sspeer  */
7656495Sspeer void
vsw_hio_port_update(vsw_port_t * portp,boolean_t hio_enabled)7666495Sspeer vsw_hio_port_update(vsw_port_t *portp, boolean_t hio_enabled)
7676495Sspeer {
7686495Sspeer 	/* Verify if the mode really changed */
7696495Sspeer 	if (portp->p_hio_enabled == hio_enabled) {
7706495Sspeer 		return;
7716495Sspeer 	}
7726495Sspeer 
7736495Sspeer 	if (hio_enabled == B_FALSE) {
7746495Sspeer 		/* Hybrid Mode is disabled, so stop HybridIO */
7756495Sspeer 		vsw_hio_stop_port(portp);
7766495Sspeer 		portp->p_hio_enabled = B_FALSE;
7778275SEric Cheng 
7788275SEric Cheng 		vsw_port_mac_reconfig(portp, B_FALSE, 0, NULL, 0);
7796495Sspeer 	} else {
7806495Sspeer 		portp->p_hio_enabled =  B_TRUE;
7818275SEric Cheng 		vsw_port_mac_reconfig(portp, B_FALSE, 0, NULL, 0);
7828275SEric Cheng 
7836495Sspeer 		/* reset the port to initiate HybridIO setup */
7846724Sraghuram 		vsw_hio_port_reset(portp, B_FALSE);
7856495Sspeer 	}
7866495Sspeer }
7876495Sspeer 
7886495Sspeer /*
7896495Sspeer  * vsw_hio_stop_port -- Stop HybridIO for a given port. Sequence
7906724Sraghuram  *	followed is similar to vsw_hio_free_all_shares().
7916495Sspeer  *
7926495Sspeer  */
7936495Sspeer void
vsw_hio_stop_port(vsw_port_t * portp)7946495Sspeer vsw_hio_stop_port(vsw_port_t *portp)
7956495Sspeer {
7966495Sspeer 	vsw_t *vswp = portp->p_vswp;
7976495Sspeer 	vsw_share_t *vsharep;
7986495Sspeer 	int max_retries = vsw_hio_max_cleanup_retries;
7996495Sspeer 
8006495Sspeer 	D1(vswp, "%s:enter\n", __func__);
8018275SEric Cheng 	mutex_enter(&vswp->mac_lock);
8026495Sspeer 
8036495Sspeer 	if (vswp->hio_capable == B_FALSE) {
8048275SEric Cheng 		mutex_exit(&vswp->mac_lock);
8056495Sspeer 		return;
8066495Sspeer 	}
8076495Sspeer 
8086495Sspeer 	vsharep = vsw_hio_find_vshare_port(vswp, portp);
8096495Sspeer 	if (vsharep == NULL) {
8108275SEric Cheng 		mutex_exit(&vswp->mac_lock);
8116495Sspeer 		return;
8126495Sspeer 	}
8136495Sspeer 
8146495Sspeer 	do {
8156495Sspeer 		if (vsharep->vs_state & VSW_SHARE_DDS_ACKD) {
8166495Sspeer 			int rv;
8176495Sspeer 
8186495Sspeer 			/* send DDS_DEL_SHARE */
8196495Sspeer 			D1(vswp, "%s:sending DEL_SHARE msg for "
8206495Sspeer 			    "share(%d)", __func__, vsharep->vs_index);
8216495Sspeer 			rv = vsw_hio_send_delshare_msg(vsharep);
8226495Sspeer 			if (rv != 0) {
8236495Sspeer 				/*
8246495Sspeer 				 * Cause a port reset to trigger
8256495Sspeer 				 * cleanup.
8266495Sspeer 				 */
8276724Sraghuram 				vsw_hio_port_reset(vsharep->vs_portp, B_FALSE);
8286495Sspeer 			}
8296495Sspeer 		}
8306495Sspeer 		if (max_retries == 1) {
8316495Sspeer 			/* last retry */
8326495Sspeer 			DWARN(vswp, "%s:All retries failed, "
8336495Sspeer 			    " cause a reset to trigger cleanup for "
8346495Sspeer 			    "share(%d)", __func__, vsharep->vs_index);
8356724Sraghuram 			vsw_hio_port_reset(vsharep->vs_portp, B_FALSE);
8366495Sspeer 		}
8376495Sspeer 
8386495Sspeer 		/* Check if the share still assigned to this port */
8396495Sspeer 		if ((vsharep->vs_portp != portp) ||
8406495Sspeer 		    (vsharep->vs_state == VSW_SHARE_FREE)) {
8416495Sspeer 			break;
8426495Sspeer 		}
8436495Sspeer 
8446495Sspeer 		/*
8456495Sspeer 		 * Release the lock so that reply for DEL_SHARE
8466495Sspeer 		 * messages come and get processed, that is, shares
8476495Sspeer 		 * get freed.
8486495Sspeer 		 */
8498275SEric Cheng 		mutex_exit(&vswp->mac_lock);
8507819SRaghuram.Kothakota@Sun.COM 		drv_usecwait(vsw_hio_cleanup_delay);
8518275SEric Cheng 		mutex_enter(&vswp->mac_lock);
8526495Sspeer 
8536495Sspeer 		/* Check if the share still assigned to this port */
8546495Sspeer 		if ((vsharep->vs_portp != portp) ||
8556495Sspeer 		    (vsharep->vs_state == VSW_SHARE_FREE)) {
8566495Sspeer 			break;
8576495Sspeer 		}
8586495Sspeer 		max_retries--;
8596495Sspeer 	} while ((vsharep->vs_state != VSW_SHARE_FREE) && (max_retries > 0));
8606495Sspeer 
8618275SEric Cheng 	mutex_exit(&vswp->mac_lock);
8626495Sspeer 	D1(vswp, "%s:exit\n", __func__);
8636495Sspeer }
8646724Sraghuram 
8656724Sraghuram /*
8666724Sraghuram  * vsw_hio_rest_all -- Resets all ports that have shares allocated.
8676724Sraghuram  *	It is called only in the panic code path, so the LDC channels
8686724Sraghuram  *	are reset immediately.
8696724Sraghuram  */
8706724Sraghuram static void
vsw_hio_reset_all(vsw_t * vswp)8716724Sraghuram vsw_hio_reset_all(vsw_t *vswp)
8726724Sraghuram {
8736724Sraghuram 	vsw_hio_t	*hiop = &vswp->vhio;
8746724Sraghuram 	vsw_share_t	*vsharep;
8756724Sraghuram 	int		i;
8766724Sraghuram 
8776724Sraghuram 	D1(vswp, "%s:enter\n", __func__);
8786724Sraghuram 
8796724Sraghuram 	if (vswp->hio_capable != B_TRUE)
8806724Sraghuram 		return;
8816724Sraghuram 
8826724Sraghuram 	for (i = 0; i < hiop->vh_num_shares; i++) {
8836724Sraghuram 		vsharep = &hiop->vh_shares[i];
8846724Sraghuram 		if (vsharep->vs_state == VSW_SHARE_FREE) {
8856724Sraghuram 			continue;
8866724Sraghuram 		}
8876724Sraghuram 		/*
8886724Sraghuram 		 * Reset the port with immediate flag enabled,
8896724Sraghuram 		 * to cause LDC reset immediately.
8906724Sraghuram 		 */
8916724Sraghuram 		vsw_hio_port_reset(vsharep->vs_portp, B_TRUE);
8926724Sraghuram 	}
8936724Sraghuram 	D1(vswp, "%s:exit\n", __func__);
8946724Sraghuram }
8956724Sraghuram 
8966724Sraghuram /*
8976724Sraghuram  * vsw_hio_reboot_callb -- Called for reboot event. It tries to
8986724Sraghuram  *	free all currently allocated shares.
8996724Sraghuram  */
9006724Sraghuram /* ARGSUSED */
9016724Sraghuram static boolean_t
vsw_hio_reboot_callb(void * arg,int code)9026724Sraghuram vsw_hio_reboot_callb(void *arg, int code)
9036724Sraghuram {
9046724Sraghuram 	vsw_t *vswp = arg;
9056724Sraghuram 
9066724Sraghuram 	D1(vswp, "%s:enter\n", __func__);
9076724Sraghuram 	vsw_hio_free_all_shares(vswp, B_TRUE);
9086724Sraghuram 	D1(vswp, "%s:exit\n", __func__);
9096724Sraghuram 	return (B_TRUE);
9106724Sraghuram }
9116724Sraghuram 
9126724Sraghuram /*
9136724Sraghuram  * vsw_hio_panic_callb -- Called from panic event. It resets all
9146724Sraghuram  *	the ports that have shares allocated. This is done to
9156724Sraghuram  *	trigger the cleanup in the guest ahead of HV reset.
9166724Sraghuram  */
9176724Sraghuram /* ARGSUSED */
9186724Sraghuram static boolean_t
vsw_hio_panic_callb(void * arg,int code)9196724Sraghuram vsw_hio_panic_callb(void *arg, int code)
9206724Sraghuram {
9216724Sraghuram 	vsw_t *vswp = arg;
9226724Sraghuram 
9236724Sraghuram 	D1(vswp, "%s:enter\n", __func__);
9246724Sraghuram 	vsw_hio_reset_all(vswp);
9256724Sraghuram 	D1(vswp, "%s:exit\n", __func__);
9266724Sraghuram 	return (B_TRUE);
9276724Sraghuram }
9288160SWentao.Yang@Sun.COM 
9298160SWentao.Yang@Sun.COM /*
9308160SWentao.Yang@Sun.COM  * Setup kstats for hio statistics.
9318160SWentao.Yang@Sun.COM  */
9328160SWentao.Yang@Sun.COM static kstat_t *
vsw_hio_setup_kstats(char * ks_mod,char * ks_name,vsw_t * vswp)9338160SWentao.Yang@Sun.COM vsw_hio_setup_kstats(char *ks_mod, char *ks_name, vsw_t *vswp)
9348160SWentao.Yang@Sun.COM {
9358160SWentao.Yang@Sun.COM 	kstat_t			*ksp;
9368160SWentao.Yang@Sun.COM 	vsw_hio_kstats_t	*hiokp;
9378160SWentao.Yang@Sun.COM 	vsw_hio_t		*hiop;
9388160SWentao.Yang@Sun.COM 	char			share_assigned_info[MAXNAMELEN];
9398160SWentao.Yang@Sun.COM 	size_t			size;
9408160SWentao.Yang@Sun.COM 	int			i;
9418160SWentao.Yang@Sun.COM 
9428160SWentao.Yang@Sun.COM 	hiop = &vswp->vhio;
9438160SWentao.Yang@Sun.COM 	/*
9448160SWentao.Yang@Sun.COM 	 * vsw_hio_stats_t structure is variable size structure
9458160SWentao.Yang@Sun.COM 	 * having fields defined only for one share. So, we need
9468160SWentao.Yang@Sun.COM 	 * allocate additional space for the rest of the shares.
9478160SWentao.Yang@Sun.COM 	 */
9488160SWentao.Yang@Sun.COM 	size = sizeof (vsw_hio_kstats_t) / sizeof (kstat_named_t);
9498160SWentao.Yang@Sun.COM 	ASSERT(hiop->vh_num_shares >= 1);
9508160SWentao.Yang@Sun.COM 	size += ((hiop->vh_num_shares - 1) * 2);
9518160SWentao.Yang@Sun.COM 
9528160SWentao.Yang@Sun.COM 	ksp = kstat_create(ks_mod, vswp->instance, ks_name, "misc",
9538160SWentao.Yang@Sun.COM 	    KSTAT_TYPE_NAMED, size, KSTAT_FLAG_VIRTUAL);
9548160SWentao.Yang@Sun.COM 
9558160SWentao.Yang@Sun.COM 	if (ksp == NULL) {
9568160SWentao.Yang@Sun.COM 		return (NULL);
9578160SWentao.Yang@Sun.COM 	}
9588160SWentao.Yang@Sun.COM 	hiokp = (vsw_hio_kstats_t *)kmem_zalloc(sizeof (kstat_named_t) *
9598160SWentao.Yang@Sun.COM 	    size, KM_SLEEP);
9608160SWentao.Yang@Sun.COM 	ksp->ks_data = hiokp;
9618160SWentao.Yang@Sun.COM 
9628160SWentao.Yang@Sun.COM 	hiop->vh_ksp = ksp;
9638160SWentao.Yang@Sun.COM 	hiop->vh_kstatsp = hiokp;
9648160SWentao.Yang@Sun.COM 	hiop->vh_kstat_size =  size;
9658160SWentao.Yang@Sun.COM 
9668160SWentao.Yang@Sun.COM 	kstat_named_init(&hiokp->hio_capable, "hio_capable", KSTAT_DATA_CHAR);
9678160SWentao.Yang@Sun.COM 	kstat_named_init(&hiokp->hio_num_shares, "hio_num_shares",
9688160SWentao.Yang@Sun.COM 	    KSTAT_DATA_ULONG);
9698160SWentao.Yang@Sun.COM 
9708160SWentao.Yang@Sun.COM 	for (i = 0; i < hiop->vh_num_shares; i++) {
9718160SWentao.Yang@Sun.COM 		(void) sprintf(share_assigned_info, "%s%d", "hio_share_", i);
9728160SWentao.Yang@Sun.COM 		kstat_named_init(&(hiokp->share[i].assigned),
9738160SWentao.Yang@Sun.COM 		    share_assigned_info, KSTAT_DATA_ULONG);
9748160SWentao.Yang@Sun.COM 
9758160SWentao.Yang@Sun.COM 		(void) sprintf(share_assigned_info, "%s%d%s",
9768160SWentao.Yang@Sun.COM 		    "hio_share_", i, "_state");
9778160SWentao.Yang@Sun.COM 		kstat_named_init(&(hiokp->share[i].state),
9788160SWentao.Yang@Sun.COM 		    share_assigned_info, KSTAT_DATA_ULONG);
9798160SWentao.Yang@Sun.COM 	}
9808160SWentao.Yang@Sun.COM 
9818160SWentao.Yang@Sun.COM 	ksp->ks_update = vsw_hio_kstats_update;
9828160SWentao.Yang@Sun.COM 	ksp->ks_private = (void *)vswp;
9838160SWentao.Yang@Sun.COM 	kstat_install(ksp);
9848160SWentao.Yang@Sun.COM 	return (ksp);
9858160SWentao.Yang@Sun.COM }
9868160SWentao.Yang@Sun.COM 
9878160SWentao.Yang@Sun.COM /*
9888160SWentao.Yang@Sun.COM  * Destroy hio kstats.
9898160SWentao.Yang@Sun.COM  */
9908160SWentao.Yang@Sun.COM static void
vsw_hio_destroy_kstats(vsw_t * vswp)9918160SWentao.Yang@Sun.COM vsw_hio_destroy_kstats(vsw_t *vswp)
9928160SWentao.Yang@Sun.COM {
9938160SWentao.Yang@Sun.COM 	kstat_t			*ksp;
9948160SWentao.Yang@Sun.COM 	vsw_hio_t		*hiop;
9958160SWentao.Yang@Sun.COM 
9968160SWentao.Yang@Sun.COM 	ASSERT(vswp != NULL);
9978160SWentao.Yang@Sun.COM 
9988160SWentao.Yang@Sun.COM 	ksp = vswp->vhio.vh_ksp;
9998160SWentao.Yang@Sun.COM 	hiop = &vswp->vhio;
10008160SWentao.Yang@Sun.COM 	if (ksp != NULL) {
10018160SWentao.Yang@Sun.COM 		kmem_free(hiop->vh_kstatsp, sizeof (kstat_named_t) *
10028160SWentao.Yang@Sun.COM 		    hiop->vh_kstat_size);
10038160SWentao.Yang@Sun.COM 		kstat_delete(ksp);
10048160SWentao.Yang@Sun.COM 		hiop->vh_kstatsp = NULL;
10058160SWentao.Yang@Sun.COM 		hiop->vh_ksp = NULL;
10068160SWentao.Yang@Sun.COM 	}
10078160SWentao.Yang@Sun.COM }
10088160SWentao.Yang@Sun.COM 
10098160SWentao.Yang@Sun.COM /*
10108160SWentao.Yang@Sun.COM  * Update hio kstats.
10118160SWentao.Yang@Sun.COM  */
10128160SWentao.Yang@Sun.COM static int
vsw_hio_kstats_update(kstat_t * ksp,int rw)10138160SWentao.Yang@Sun.COM vsw_hio_kstats_update(kstat_t *ksp, int rw)
10148160SWentao.Yang@Sun.COM {
10158160SWentao.Yang@Sun.COM 	vsw_t			*vswp;
10168160SWentao.Yang@Sun.COM 	vsw_hio_t		*hiop;
10178160SWentao.Yang@Sun.COM 	vsw_hio_kstats_t	*hiokp;
10188160SWentao.Yang@Sun.COM 	int			i;
10198160SWentao.Yang@Sun.COM 
10208160SWentao.Yang@Sun.COM 	vswp = (vsw_t *)ksp->ks_private;
10218160SWentao.Yang@Sun.COM 	ASSERT(vswp != NULL);
10228160SWentao.Yang@Sun.COM 
10238160SWentao.Yang@Sun.COM 	hiop = &vswp->vhio;
10248160SWentao.Yang@Sun.COM 	hiokp = hiop->vh_kstatsp;
10258160SWentao.Yang@Sun.COM 
10268160SWentao.Yang@Sun.COM 	if (rw == KSTAT_READ) {
10278160SWentao.Yang@Sun.COM 		if (vswp->hio_capable) {
10288160SWentao.Yang@Sun.COM 			(void) strcpy(hiokp->hio_capable.value.c, "Yes");
10298160SWentao.Yang@Sun.COM 		} else {
10308160SWentao.Yang@Sun.COM 			/* not hio capable, just return */
10318160SWentao.Yang@Sun.COM 			(void) strcpy(hiokp->hio_capable.value.c, "No");
10328160SWentao.Yang@Sun.COM 			return (0);
10338160SWentao.Yang@Sun.COM 		}
10348160SWentao.Yang@Sun.COM 
10358275SEric Cheng 		mutex_enter(&vswp->mac_lock);
10368160SWentao.Yang@Sun.COM 		hiokp->hio_num_shares.value.ul = (uint32_t)hiop->vh_num_shares;
10378160SWentao.Yang@Sun.COM 		for (i = 0; i < hiop->vh_num_shares; i++) {
10388160SWentao.Yang@Sun.COM 			hiokp->share[i].assigned.value.ul =
10398160SWentao.Yang@Sun.COM 			    hiop->vh_shares[i].vs_macaddr;
10408160SWentao.Yang@Sun.COM 			hiokp->share[i].state.value.ul =
10418160SWentao.Yang@Sun.COM 			    hiop->vh_shares[i].vs_state;
10428160SWentao.Yang@Sun.COM 		}
10438275SEric Cheng 		mutex_exit(&vswp->mac_lock);
10448160SWentao.Yang@Sun.COM 	} else {
10458160SWentao.Yang@Sun.COM 		return (EACCES);
10468160SWentao.Yang@Sun.COM 	}
10478160SWentao.Yang@Sun.COM 
10488160SWentao.Yang@Sun.COM 	return (0);
10498160SWentao.Yang@Sun.COM }
1050