xref: /titanic_51/usr/src/uts/sun4u/starfire/io/idn_smr.c (revision 07d06da50d310a325b457d6330165aebab1e0064)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5d3d50737SRafael Vanoni  * Common Development and Distribution License (the "License").
6d3d50737SRafael Vanoni  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21*07d06da5SSurya Prakki 
227c478bd9Sstevel@tonic-gate /*
23d3d50737SRafael Vanoni  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  *
267c478bd9Sstevel@tonic-gate  * Inter-Domain Network
277c478bd9Sstevel@tonic-gate  *
287c478bd9Sstevel@tonic-gate  * Shared Memory Region (SMR) supporting code.
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <sys/types.h>
327c478bd9Sstevel@tonic-gate #include <sys/param.h>
337c478bd9Sstevel@tonic-gate #include <sys/machparam.h>
347c478bd9Sstevel@tonic-gate #include <sys/debug.h>
357c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
367c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
377c478bd9Sstevel@tonic-gate #include <sys/mutex.h>
387c478bd9Sstevel@tonic-gate #include <sys/rwlock.h>
397c478bd9Sstevel@tonic-gate #include <sys/systm.h>
407c478bd9Sstevel@tonic-gate #include <sys/machlock.h>
417c478bd9Sstevel@tonic-gate #include <sys/membar.h>
427c478bd9Sstevel@tonic-gate #include <sys/mman.h>
437c478bd9Sstevel@tonic-gate #include <vm/hat.h>
447c478bd9Sstevel@tonic-gate #include <vm/as.h>
457c478bd9Sstevel@tonic-gate #include <vm/hat_sfmmu.h>
467c478bd9Sstevel@tonic-gate #include <sys/vm_machparam.h>
477c478bd9Sstevel@tonic-gate #include <sys/x_call.h>
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate #include <sys/idn.h>
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate #ifdef DEBUG
527c478bd9Sstevel@tonic-gate #define	DIOCHECK(domid) \
537c478bd9Sstevel@tonic-gate { \
547c478bd9Sstevel@tonic-gate 	int	_dio; \
557c478bd9Sstevel@tonic-gate 	if ((_dio = idn_domain[domid].dio) < 0) { \
567c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, \
577c478bd9Sstevel@tonic-gate 			">>>>> file %s, line %d: domain %d, dio = %d", \
587c478bd9Sstevel@tonic-gate 			__FILE__, __LINE__, (domid), _dio); \
597c478bd9Sstevel@tonic-gate 	} \
607c478bd9Sstevel@tonic-gate }
617c478bd9Sstevel@tonic-gate #else
627c478bd9Sstevel@tonic-gate #define	DIOCHECK(domid)
637c478bd9Sstevel@tonic-gate #endif /* DEBUG */
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate static int	smr_slab_alloc_local(int domid, smr_slab_t **spp);
667c478bd9Sstevel@tonic-gate static int	smr_slab_alloc_remote(int domid, smr_slab_t **spp);
677c478bd9Sstevel@tonic-gate static void	smr_slab_free_local(int domid, smr_slab_t *sp);
687c478bd9Sstevel@tonic-gate static void	smr_slab_free_remote(int domid, smr_slab_t *sp);
697c478bd9Sstevel@tonic-gate static int 	smr_slabwaiter_register(int domid);
707c478bd9Sstevel@tonic-gate static int 	smr_slabwaiter_unregister(int domid, smr_slab_t **spp);
717c478bd9Sstevel@tonic-gate static int 	smr_slaballoc_wait(int domid, smr_slab_t **spp);
727c478bd9Sstevel@tonic-gate static smr_slab_t 	*smr_slab_reserve(int domid);
737c478bd9Sstevel@tonic-gate static void 	smr_slab_unreserve(int domid, smr_slab_t *sp);
747c478bd9Sstevel@tonic-gate static void	smr_slab_reap_global();
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate /*
777c478bd9Sstevel@tonic-gate  * Can only be called by the master.  Allocate a slab from the
787c478bd9Sstevel@tonic-gate  * local pool representing the SMR, on behalf of the given
797c478bd9Sstevel@tonic-gate  * domain.  Slab is either being requested for use by the
807c478bd9Sstevel@tonic-gate  * local domain (i.e. domid == idn.localid), or it's being
817c478bd9Sstevel@tonic-gate  * allocated to give to a remote domain which requested one.
827c478bd9Sstevel@tonic-gate  * In the base of allocating on behalf of a remote domain,
837c478bd9Sstevel@tonic-gate  * smr_slab_t structure is used simply to manage ownership.
847c478bd9Sstevel@tonic-gate  *
857c478bd9Sstevel@tonic-gate  * Returns:	smr_slaballoc_wait
867c478bd9Sstevel@tonic-gate  * 		(EINVAL, ETIMEDOUT)
877c478bd9Sstevel@tonic-gate  *		smr_slabwatier_unregister
887c478bd9Sstevel@tonic-gate  *		(0, EINVAL, EBUSY, ENOMEM)
897c478bd9Sstevel@tonic-gate  *		ENOLCK
907c478bd9Sstevel@tonic-gate  */
917c478bd9Sstevel@tonic-gate static int
927c478bd9Sstevel@tonic-gate smr_slab_alloc_local(int domid, smr_slab_t **spp)
937c478bd9Sstevel@tonic-gate {
947c478bd9Sstevel@tonic-gate 	int		serrno = 0;
957c478bd9Sstevel@tonic-gate 	int		nwait;
967c478bd9Sstevel@tonic-gate 	smr_slab_t	*sp;
977c478bd9Sstevel@tonic-gate 	idn_domain_t	*dp;
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 	/*
1017c478bd9Sstevel@tonic-gate 	 * Only the master can make local allocations.
1027c478bd9Sstevel@tonic-gate 	 */
1037c478bd9Sstevel@tonic-gate 	ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID);
1047c478bd9Sstevel@tonic-gate 	ASSERT(idn.localid == IDN_GET_MASTERID());
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	*spp = NULL;
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	dp = &idn_domain[domid];
1097c478bd9Sstevel@tonic-gate 	ASSERT(DSLAB_READ_HELD(domid));
1107c478bd9Sstevel@tonic-gate 	ASSERT(dp->dslab_state == DSLAB_STATE_LOCAL);
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 	/*
1137c478bd9Sstevel@tonic-gate 	 * Register myself with the waiting list.
1147c478bd9Sstevel@tonic-gate 	 */
1157c478bd9Sstevel@tonic-gate 	nwait = smr_slabwaiter_register(domid);
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 	if (nwait > 1) {
1187c478bd9Sstevel@tonic-gate 		/*
1197c478bd9Sstevel@tonic-gate 		 * XXX - old comment?
1207c478bd9Sstevel@tonic-gate 		 * Need to drop the read lock _after_ registering
1217c478bd9Sstevel@tonic-gate 		 * ourselves with the potential wait list for this allocation.
1227c478bd9Sstevel@tonic-gate 		 * Although this allocation is not a remote one, we could
1237c478bd9Sstevel@tonic-gate 		 * still have multiple threads on the master trying to
1247c478bd9Sstevel@tonic-gate 		 * satisfy (allocate) request on behalf of a remote domain.
1257c478bd9Sstevel@tonic-gate 		 */
1267c478bd9Sstevel@tonic-gate 		/*
1277c478bd9Sstevel@tonic-gate 		 * Somebody is already in the process of satisfying
1287c478bd9Sstevel@tonic-gate 		 * the allocation request for this respective
1297c478bd9Sstevel@tonic-gate 		 * domain.  All we need to do is wait and let
1307c478bd9Sstevel@tonic-gate 		 * it happen.
1317c478bd9Sstevel@tonic-gate 		 */
1327c478bd9Sstevel@tonic-gate 		serrno = smr_slaballoc_wait(domid, spp);
1337c478bd9Sstevel@tonic-gate 		return (serrno);
1347c478bd9Sstevel@tonic-gate 	}
1357c478bd9Sstevel@tonic-gate 	/*
1367c478bd9Sstevel@tonic-gate 	 * I'm the original slab requester for this domain.  It's local
1377c478bd9Sstevel@tonic-gate 	 * so go ahead and do the job.
1387c478bd9Sstevel@tonic-gate 	 */
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	if ((sp = smr_slab_reserve(domid)) == NULL)
1417c478bd9Sstevel@tonic-gate 		serrno = ENOMEM;
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 	/*
1447c478bd9Sstevel@tonic-gate 	 * Allocation may have failed.  In either case we've
1457c478bd9Sstevel@tonic-gate 	 * got to do the put to at least wake potential waiters up.
1467c478bd9Sstevel@tonic-gate 	 */
1477c478bd9Sstevel@tonic-gate 	if (!serrno) {
1487c478bd9Sstevel@tonic-gate 		if (DSLAB_LOCK_TRYUPGRADE(domid) == 0) {
1497c478bd9Sstevel@tonic-gate 			DSLAB_UNLOCK(domid);
1507c478bd9Sstevel@tonic-gate 			DSLAB_LOCK_EXCL(domid);
1517c478bd9Sstevel@tonic-gate 		}
1527c478bd9Sstevel@tonic-gate 	}
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	(void) smr_slaballoc_put(domid, sp, 0, serrno);
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	/*
1577c478bd9Sstevel@tonic-gate 	 * If serrno is ENOLCK here, then we must have failed
1587c478bd9Sstevel@tonic-gate 	 * on the upgrade above, so lock already dropped.
1597c478bd9Sstevel@tonic-gate 	 */
1607c478bd9Sstevel@tonic-gate 	if (serrno != ENOLCK) {
1617c478bd9Sstevel@tonic-gate 		/*
1627c478bd9Sstevel@tonic-gate 		 * Need to drop since reaping may be recursive?
1637c478bd9Sstevel@tonic-gate 		 */
1647c478bd9Sstevel@tonic-gate 		DSLAB_UNLOCK(domid);
1657c478bd9Sstevel@tonic-gate 	}
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	/*
1687c478bd9Sstevel@tonic-gate 	 * Since we were the original requester but never went
1697c478bd9Sstevel@tonic-gate 	 * to sleep, we need to directly unregister ourselves
1707c478bd9Sstevel@tonic-gate 	 * from the waiting list.
1717c478bd9Sstevel@tonic-gate 	 */
1727c478bd9Sstevel@tonic-gate 	serrno = smr_slabwaiter_unregister(domid, spp);
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	/*
1757c478bd9Sstevel@tonic-gate 	 * Now that we've satisfied the request, let's check if any
1767c478bd9Sstevel@tonic-gate 	 * reaping is necessary.  Only the master does this and only
1777c478bd9Sstevel@tonic-gate 	 * when allocating slabs, an infrequent event :-o
1787c478bd9Sstevel@tonic-gate 	 */
1797c478bd9Sstevel@tonic-gate 	smr_slab_reap_global();
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	ASSERT((serrno == 0) ? (*spp != NULL) : (*spp == NULL));
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	DSLAB_LOCK_SHARED(domid);
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	return (serrno);
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate /*
1897c478bd9Sstevel@tonic-gate  * Can only be called by a slave on behalf of himself.  Need to
1907c478bd9Sstevel@tonic-gate  * make a request to the master to allocate a slab of SMR buffers
1917c478bd9Sstevel@tonic-gate  * for the local domain.
1927c478bd9Sstevel@tonic-gate  *
1937c478bd9Sstevel@tonic-gate  * Returns:	smr_slaballoc_wait
1947c478bd9Sstevel@tonic-gate  *		(0, EINVAL, EBUSY, ENOMEM)
1957c478bd9Sstevel@tonic-gate  *		ENOLCK
1967c478bd9Sstevel@tonic-gate  *		ECANCELED
1977c478bd9Sstevel@tonic-gate  */
1987c478bd9Sstevel@tonic-gate static int
1997c478bd9Sstevel@tonic-gate smr_slab_alloc_remote(int domid, smr_slab_t **spp)
2007c478bd9Sstevel@tonic-gate {
2017c478bd9Sstevel@tonic-gate 	int		nwait;
2027c478bd9Sstevel@tonic-gate 	int		serrno = 0;
2037c478bd9Sstevel@tonic-gate 	int		bailout = 0;
2047c478bd9Sstevel@tonic-gate 	int		masterid;
2057c478bd9Sstevel@tonic-gate 	idn_domain_t	*dp, *mdp = NULL;
2067c478bd9Sstevel@tonic-gate 	procname_t	proc = "smr_slab_alloc_remote";
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	/*
2097c478bd9Sstevel@tonic-gate 	 * Only slaves make remote allocations.
2107c478bd9Sstevel@tonic-gate 	 */
2117c478bd9Sstevel@tonic-gate 	ASSERT(idn.localid != IDN_GET_MASTERID());
2127c478bd9Sstevel@tonic-gate 	ASSERT(domid == idn.localid);
2137c478bd9Sstevel@tonic-gate 	ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID);
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	*spp = NULL;
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	dp = &idn_domain[domid];
2187c478bd9Sstevel@tonic-gate 	ASSERT(DSLAB_READ_HELD(domid));
2197c478bd9Sstevel@tonic-gate 	ASSERT(dp->dslab_state == DSLAB_STATE_REMOTE);
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	/*
2227c478bd9Sstevel@tonic-gate 	 * Register myself with the slaballoc waiting list.
2237c478bd9Sstevel@tonic-gate 	 * Note that only allow one outstanding allocation
2247c478bd9Sstevel@tonic-gate 	 * request for the given domain.  Other callers which
2257c478bd9Sstevel@tonic-gate 	 * detect a slab is needed simply get stuck on the
2267c478bd9Sstevel@tonic-gate 	 * waiting list waiting for the original caller to
2277c478bd9Sstevel@tonic-gate 	 * get the job done.
2287c478bd9Sstevel@tonic-gate 	 * The waiter_register routine will allocate the necessary
2297c478bd9Sstevel@tonic-gate 	 * slab structure which will ultimately be inserted in
2307c478bd9Sstevel@tonic-gate 	 * the domain's slab list via smr_slaballoc_put().
2317c478bd9Sstevel@tonic-gate 	 */
2327c478bd9Sstevel@tonic-gate 	nwait = smr_slabwaiter_register(domid);
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 	/*
2357c478bd9Sstevel@tonic-gate 	 * Make sure we have a connection with the master
2367c478bd9Sstevel@tonic-gate 	 * before we wait around for nothing and send a
2377c478bd9Sstevel@tonic-gate 	 * command off to nowhere.
2387c478bd9Sstevel@tonic-gate 	 * First do a quick (no lock) check for global okayness.
2397c478bd9Sstevel@tonic-gate 	 */
2407c478bd9Sstevel@tonic-gate 	if ((idn.state != IDNGS_ONLINE) ||
2417c478bd9Sstevel@tonic-gate 	    ((masterid = IDN_GET_MASTERID()) == IDN_NIL_DOMID)) {
2427c478bd9Sstevel@tonic-gate 		bailout = 1;
2437c478bd9Sstevel@tonic-gate 		serrno = ECANCELED;
2447c478bd9Sstevel@tonic-gate 	}
2457c478bd9Sstevel@tonic-gate 	/*
2467c478bd9Sstevel@tonic-gate 	 * We need to drop our read lock _before_ acquiring the
2477c478bd9Sstevel@tonic-gate 	 * slaballoc waiter lock.  This is necessary because the
2487c478bd9Sstevel@tonic-gate 	 * thread that receives the slab alloc response and fills
2497c478bd9Sstevel@tonic-gate 	 * in the slab structure will need to grab the domain write
2507c478bd9Sstevel@tonic-gate 	 * lock while holding onto the slaballoc waiter lock.
2517c478bd9Sstevel@tonic-gate 	 * Potentially could deadlock if we didn't drop our domain
2527c478bd9Sstevel@tonic-gate 	 * lock before.  Plus, we've registered.
2537c478bd9Sstevel@tonic-gate 	 *
2547c478bd9Sstevel@tonic-gate 	 * 4093209 - Note also that we do this _after_ the check for
2557c478bd9Sstevel@tonic-gate 	 *	idn.masterid where we grab the READER global
2567c478bd9Sstevel@tonic-gate 	 *	lock.  This is to prevent somebody from
2577c478bd9Sstevel@tonic-gate 	 *	changing our state after we drop the drwlock.
2587c478bd9Sstevel@tonic-gate 	 *	A deadlock can occur when shutting down a
2597c478bd9Sstevel@tonic-gate 	 *	domain we're holding the
2607c478bd9Sstevel@tonic-gate 	 */
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	if (!bailout) {
2637c478bd9Sstevel@tonic-gate 		mdp = &idn_domain[masterid];
2647c478bd9Sstevel@tonic-gate 		/*
2657c478bd9Sstevel@tonic-gate 		 * Global state is okay.  Let's double check the
2667c478bd9Sstevel@tonic-gate 		 * state of our actual target domain.
2677c478bd9Sstevel@tonic-gate 		 */
2687c478bd9Sstevel@tonic-gate 		if (mdp->dstate != IDNDS_CONNECTED) {
2697c478bd9Sstevel@tonic-gate 			bailout = 1;
2707c478bd9Sstevel@tonic-gate 			serrno = ECANCELED;
2717c478bd9Sstevel@tonic-gate 		} else if (IDN_DLOCK_TRY_SHARED(masterid)) {
2727c478bd9Sstevel@tonic-gate 			if (mdp->dstate != IDNDS_CONNECTED) {
2737c478bd9Sstevel@tonic-gate 				bailout = 1;
2747c478bd9Sstevel@tonic-gate 				serrno = ECANCELED;
2757c478bd9Sstevel@tonic-gate 				IDN_DUNLOCK(masterid);
2767c478bd9Sstevel@tonic-gate 			} else if (nwait != 1) {
2777c478bd9Sstevel@tonic-gate 				IDN_DUNLOCK(masterid);
2787c478bd9Sstevel@tonic-gate 			}
2797c478bd9Sstevel@tonic-gate 			/*
2807c478bd9Sstevel@tonic-gate 			 * Note that keep the drwlock(read) for
2817c478bd9Sstevel@tonic-gate 			 * the target (master) domain if it appears
2827c478bd9Sstevel@tonic-gate 			 * we're the lucky one to send the command.
2837c478bd9Sstevel@tonic-gate 			 * We hold onto the lock until we've actually
2847c478bd9Sstevel@tonic-gate 			 * sent the command out.
2857c478bd9Sstevel@tonic-gate 			 * We don't reach this place unless it
2867c478bd9Sstevel@tonic-gate 			 * appears everything is kosher with
2877c478bd9Sstevel@tonic-gate 			 * the target (master) domain.
2887c478bd9Sstevel@tonic-gate 			 */
2897c478bd9Sstevel@tonic-gate 		} else {
2907c478bd9Sstevel@tonic-gate 			bailout = 1;
2917c478bd9Sstevel@tonic-gate 			serrno = ENOLCK;
2927c478bd9Sstevel@tonic-gate 		}
2937c478bd9Sstevel@tonic-gate 	}
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	if (bailout) {
2967c478bd9Sstevel@tonic-gate 		ASSERT(serrno);
2977c478bd9Sstevel@tonic-gate 		/*
2987c478bd9Sstevel@tonic-gate 		 * Gotta bail.  Abort operation.  Error result
2997c478bd9Sstevel@tonic-gate 		 * will be picked up when we attempt to wait.
3007c478bd9Sstevel@tonic-gate 		 */
3017c478bd9Sstevel@tonic-gate 		PR_SMR("%s: BAILING OUT on behalf domain %d "
3027c478bd9Sstevel@tonic-gate 		    "(err=%d, gs=%s, ms=%s)\n",
3037c478bd9Sstevel@tonic-gate 		    proc, domid, serrno, idngs_str[idn.state],
3047c478bd9Sstevel@tonic-gate 		    (masterid == IDN_NIL_DOMID)
3057c478bd9Sstevel@tonic-gate 		    ? "unknown" : idnds_str[idn_domain[masterid].dstate]);
3067c478bd9Sstevel@tonic-gate 		(void) smr_slabwaiter_abort(domid, serrno);
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	} else if (nwait == 1) {
3097c478bd9Sstevel@tonic-gate 		/*
3107c478bd9Sstevel@tonic-gate 		 * We are the original requester.  Initiate the
3117c478bd9Sstevel@tonic-gate 		 * actual request to the master.
3127c478bd9Sstevel@tonic-gate 		 */
313d3d50737SRafael Vanoni 		idn_send_cmd(masterid, IDNCMD_SLABALLOC, IDN_SLAB_SIZE, 0, 0);
3147c478bd9Sstevel@tonic-gate 		ASSERT(mdp);
3157c478bd9Sstevel@tonic-gate 		IDN_DUNLOCK(masterid);
3167c478bd9Sstevel@tonic-gate 	}
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	/*
3197c478bd9Sstevel@tonic-gate 	 * Wait here for response.  Once awakened func returns
3207c478bd9Sstevel@tonic-gate 	 * with slab structure possibly filled with gifts!
3217c478bd9Sstevel@tonic-gate 	 */
3227c478bd9Sstevel@tonic-gate 	serrno = smr_slaballoc_wait(domid, spp);
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	return (serrno);
3257c478bd9Sstevel@tonic-gate }
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate /*
3287c478bd9Sstevel@tonic-gate  * Allocate a slab from the Master on behalf
3297c478bd9Sstevel@tonic-gate  * of the given domain.  Note that master uses
3307c478bd9Sstevel@tonic-gate  * this function to allocate slabs on behalf of
3317c478bd9Sstevel@tonic-gate  * remote domains also.
3327c478bd9Sstevel@tonic-gate  * Entered with drwlock held.
3337c478bd9Sstevel@tonic-gate  * Leaves with drwlock dropped.
3347c478bd9Sstevel@tonic-gate  * Returns:	EDQUOT
3357c478bd9Sstevel@tonic-gate  *		EINVAL
3367c478bd9Sstevel@tonic-gate  *		ENOLCK
3377c478bd9Sstevel@tonic-gate  *		smr_slab_alloc_local
3387c478bd9Sstevel@tonic-gate  *		smr_slab_alloc_remote
3397c478bd9Sstevel@tonic-gate  *		(0, EINVAL, EBUSY, ENOMEM)
3407c478bd9Sstevel@tonic-gate  */
3417c478bd9Sstevel@tonic-gate int
3427c478bd9Sstevel@tonic-gate smr_slab_alloc(int domid, smr_slab_t **spp)
3437c478bd9Sstevel@tonic-gate {
3447c478bd9Sstevel@tonic-gate 	int		serrno = 0;
3457c478bd9Sstevel@tonic-gate 	idn_domain_t	*dp;
3467c478bd9Sstevel@tonic-gate 	procname_t	proc = "smr_slab_alloc";
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	dp = &idn_domain[domid];
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	ASSERT(DSLAB_READ_HELD(domid));
3527c478bd9Sstevel@tonic-gate 	ASSERT(dp->dslab_state != DSLAB_STATE_UNKNOWN);
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	*spp = NULL;
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 	switch (dp->dslab_state) {
3577c478bd9Sstevel@tonic-gate 	case DSLAB_STATE_UNKNOWN:
3587c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
3597c478bd9Sstevel@tonic-gate 		    "IDN: 300: no slab allocations without a master");
3607c478bd9Sstevel@tonic-gate 		serrno = EINVAL;
3617c478bd9Sstevel@tonic-gate 		break;
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	case DSLAB_STATE_LOCAL:
3647c478bd9Sstevel@tonic-gate 		/*
3657c478bd9Sstevel@tonic-gate 		 * If I'm the master, then get a slab
3667c478bd9Sstevel@tonic-gate 		 * from the local SMR pool, but only
3677c478bd9Sstevel@tonic-gate 		 * if the number of allocated slabs has
3687c478bd9Sstevel@tonic-gate 		 * not been exceeded.
3697c478bd9Sstevel@tonic-gate 		 */
3707c478bd9Sstevel@tonic-gate 		if (((int)dp->dnslabs < IDN_SLAB_MAXPERDOMAIN) ||
3717c478bd9Sstevel@tonic-gate 		    !IDN_SLAB_MAXPERDOMAIN)
3727c478bd9Sstevel@tonic-gate 			serrno = smr_slab_alloc_local(domid, spp);
3737c478bd9Sstevel@tonic-gate 		else
3747c478bd9Sstevel@tonic-gate 			serrno = EDQUOT;
3757c478bd9Sstevel@tonic-gate 		break;
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	case DSLAB_STATE_REMOTE:
3787c478bd9Sstevel@tonic-gate 		/*
3797c478bd9Sstevel@tonic-gate 		 * Have to make a remote request.
3807c478bd9Sstevel@tonic-gate 		 * In order to prevent overwhelming the master
3817c478bd9Sstevel@tonic-gate 		 * with a bunch of requests that he won't be able
3827c478bd9Sstevel@tonic-gate 		 * to handle we do a check to see if we're still
3837c478bd9Sstevel@tonic-gate 		 * under quota.  Note that the limit is known
3847c478bd9Sstevel@tonic-gate 		 * apriori based on the SMR/NWR size and
3857c478bd9Sstevel@tonic-gate 		 * IDN_SLAB_MINTOTAL.  Domains must have the same
3867c478bd9Sstevel@tonic-gate 		 * size SMR/NWR, however they can have different
3877c478bd9Sstevel@tonic-gate 		 * IDN_SLAB_MINTOTAL.  Thus a domain could throttle
3887c478bd9Sstevel@tonic-gate 		 * itself however it wishes.
3897c478bd9Sstevel@tonic-gate 		 */
3907c478bd9Sstevel@tonic-gate 		if (((int)dp->dnslabs < IDN_SLAB_MAXPERDOMAIN) ||
3917c478bd9Sstevel@tonic-gate 		    !IDN_SLAB_MAXPERDOMAIN)
3927c478bd9Sstevel@tonic-gate 			serrno = smr_slab_alloc_remote(domid, spp);
3937c478bd9Sstevel@tonic-gate 		else
3947c478bd9Sstevel@tonic-gate 			serrno = EDQUOT;
3957c478bd9Sstevel@tonic-gate 		break;
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	default:
3987c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
3997c478bd9Sstevel@tonic-gate 		    "IDN: 301: (ALLOC) unknown slab state (%d) "
4007c478bd9Sstevel@tonic-gate 		    "for domain %d", dp->dslab_state, domid);
4017c478bd9Sstevel@tonic-gate 		serrno = EINVAL;
4027c478bd9Sstevel@tonic-gate 		break;
4037c478bd9Sstevel@tonic-gate 	}
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	if (*spp == NULL) {
4067c478bd9Sstevel@tonic-gate 		PR_SMR("%s: failed to allocate %s slab [serrno = %d]\n",
4077c478bd9Sstevel@tonic-gate 		    proc, (idn.localid == IDN_GET_MASTERID()) ?
4087c478bd9Sstevel@tonic-gate 		    "local" : "remote", serrno);
4097c478bd9Sstevel@tonic-gate 	}
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	if (serrno) {
4127c478bd9Sstevel@tonic-gate 		IDN_GKSTAT_GLOBAL_EVENT(gk_slabfail, gk_slabfail_last);
4137c478bd9Sstevel@tonic-gate 	}
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	return (serrno);
4167c478bd9Sstevel@tonic-gate }
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate static void
4197c478bd9Sstevel@tonic-gate smr_slab_free_local(int domid, smr_slab_t *sp)
4207c478bd9Sstevel@tonic-gate {
4217c478bd9Sstevel@tonic-gate 	int	rv;
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	/*
4247c478bd9Sstevel@tonic-gate 	 * Do a slaballoc_put just in case there may have
4257c478bd9Sstevel@tonic-gate 	 * been waiters for slabs for this respective domain
4267c478bd9Sstevel@tonic-gate 	 * before we unreserve this slab.
4277c478bd9Sstevel@tonic-gate 	 */
4287c478bd9Sstevel@tonic-gate 	rv = smr_slaballoc_put(domid, sp, 0, 0);
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	if (rv == -1) {
4317c478bd9Sstevel@tonic-gate 		/*
4327c478bd9Sstevel@tonic-gate 		 * Put failed.  Must not have been any waiters.
4337c478bd9Sstevel@tonic-gate 		 * Go ahead and unreserve the space.
4347c478bd9Sstevel@tonic-gate 		 */
4357c478bd9Sstevel@tonic-gate 		smr_slab_unreserve(domid, sp);
4367c478bd9Sstevel@tonic-gate 	}
4377c478bd9Sstevel@tonic-gate }
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate static void
4407c478bd9Sstevel@tonic-gate smr_slab_free_remote(int domid, smr_slab_t *sp)
4417c478bd9Sstevel@tonic-gate {
4427c478bd9Sstevel@tonic-gate 	smr_offset_t	slab_offset;
4437c478bd9Sstevel@tonic-gate 	int		slab_size;
4447c478bd9Sstevel@tonic-gate 	int		rv;
4457c478bd9Sstevel@tonic-gate 	int		masterid;
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	ASSERT(domid == idn.localid);
4487c478bd9Sstevel@tonic-gate 	ASSERT(idn.localid != IDN_GET_MASTERID());
4497c478bd9Sstevel@tonic-gate 	ASSERT(DSLAB_WRITE_HELD(domid));
4507c478bd9Sstevel@tonic-gate 	ASSERT(idn_domain[domid].dslab_state == DSLAB_STATE_REMOTE);
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 	masterid = IDN_GET_MASTERID();
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	ASSERT(masterid != IDN_NIL_DOMID);
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	slab_offset = IDN_ADDR2OFFSET(sp->sl_start);
4577c478bd9Sstevel@tonic-gate 	slab_size   = (int)(sp->sl_end - sp->sl_start);
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	/*
4607c478bd9Sstevel@tonic-gate 	 * Do a slaballoc_put just in case there may have
4617c478bd9Sstevel@tonic-gate 	 * been waiters for slabs for this domain before
4627c478bd9Sstevel@tonic-gate 	 * returning back to the master.
4637c478bd9Sstevel@tonic-gate 	 */
4647c478bd9Sstevel@tonic-gate 	rv = smr_slaballoc_put(domid, sp, 0, 0);
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	if ((rv == -1) && (masterid != IDN_NIL_DOMID)) {
4677c478bd9Sstevel@tonic-gate 		/*
4687c478bd9Sstevel@tonic-gate 		 * Put failed.  No waiters so free the local data
4697c478bd9Sstevel@tonic-gate 		 * structure ship the SMR range off to the master.
4707c478bd9Sstevel@tonic-gate 		 */
4717c478bd9Sstevel@tonic-gate 		smr_free_buflist(sp);
4727c478bd9Sstevel@tonic-gate 		FREESTRUCT(sp, smr_slab_t, 1);
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 		IDN_DLOCK_SHARED(masterid);
475d3d50737SRafael Vanoni 		idn_send_cmd(masterid, IDNCMD_SLABFREE, slab_offset, slab_size,
476d3d50737SRafael Vanoni 		    0);
4777c478bd9Sstevel@tonic-gate 		IDN_DUNLOCK(masterid);
4787c478bd9Sstevel@tonic-gate 	}
4797c478bd9Sstevel@tonic-gate }
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate /*
4827c478bd9Sstevel@tonic-gate  * Free up the list of slabs passed
4837c478bd9Sstevel@tonic-gate  */
4847c478bd9Sstevel@tonic-gate void
4857c478bd9Sstevel@tonic-gate smr_slab_free(int domid, smr_slab_t *sp)
4867c478bd9Sstevel@tonic-gate {
4877c478bd9Sstevel@tonic-gate 	smr_slab_t	*nsp = NULL;
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 	ASSERT(DSLAB_WRITE_HELD(domid));
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	if (sp == NULL)
4927c478bd9Sstevel@tonic-gate 		return;
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 	ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID);
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 	switch (idn_domain[domid].dslab_state) {
4977c478bd9Sstevel@tonic-gate 	case DSLAB_STATE_UNKNOWN:
498d3d50737SRafael Vanoni 		cmn_err(CE_WARN, "IDN: 302: no slab free without a master");
4997c478bd9Sstevel@tonic-gate 		break;
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 	case DSLAB_STATE_LOCAL:
5027c478bd9Sstevel@tonic-gate 		/*
5037c478bd9Sstevel@tonic-gate 		 * If I'm the master then put the slabs
5047c478bd9Sstevel@tonic-gate 		 * back to the local SMR pool.
5057c478bd9Sstevel@tonic-gate 		 */
5067c478bd9Sstevel@tonic-gate 		for (; sp; sp = nsp) {
5077c478bd9Sstevel@tonic-gate 			nsp = sp->sl_next;
5087c478bd9Sstevel@tonic-gate 			smr_slab_free_local(domid, sp);
5097c478bd9Sstevel@tonic-gate 		}
5107c478bd9Sstevel@tonic-gate 		break;
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	case DSLAB_STATE_REMOTE:
5137c478bd9Sstevel@tonic-gate 		/*
5147c478bd9Sstevel@tonic-gate 		 * If the domid is my own then I'm freeing
5157c478bd9Sstevel@tonic-gate 		 * a slab back to the Master.
5167c478bd9Sstevel@tonic-gate 		 */
5177c478bd9Sstevel@tonic-gate 		for (; sp; sp = nsp) {
5187c478bd9Sstevel@tonic-gate 			nsp = sp->sl_next;
5197c478bd9Sstevel@tonic-gate 			smr_slab_free_remote(domid, sp);
5207c478bd9Sstevel@tonic-gate 		}
5217c478bd9Sstevel@tonic-gate 		break;
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 	default:
5247c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
525d3d50737SRafael Vanoni 		    "IDN: 301: (FREE) unknown slab state (%d) for domain %d",
5267c478bd9Sstevel@tonic-gate 		    idn_domain[domid].dslab_state, domid);
5277c478bd9Sstevel@tonic-gate 		break;
5287c478bd9Sstevel@tonic-gate 	}
5297c478bd9Sstevel@tonic-gate }
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate /*
5327c478bd9Sstevel@tonic-gate  * Free up the list of slab data structures ONLY.
5337c478bd9Sstevel@tonic-gate  * This is called during a fatal shutdown of the master
5347c478bd9Sstevel@tonic-gate  * where we need to garbage collect the locally allocated
5357c478bd9Sstevel@tonic-gate  * data structures used to manage slabs allocated to the
5367c478bd9Sstevel@tonic-gate  * local domain.  Should never be called by a master since
5377c478bd9Sstevel@tonic-gate  * the master can do a regular smr_slab_free.
5387c478bd9Sstevel@tonic-gate  */
5397c478bd9Sstevel@tonic-gate void
5407c478bd9Sstevel@tonic-gate smr_slab_garbage_collection(smr_slab_t *sp)
5417c478bd9Sstevel@tonic-gate {
5427c478bd9Sstevel@tonic-gate 	smr_slab_t	*nsp;
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 	ASSERT(idn_domain[idn.localid].dvote.v.master == 0);
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 	if (sp == NULL)
5477c478bd9Sstevel@tonic-gate 		return;
5487c478bd9Sstevel@tonic-gate 	/*
5497c478bd9Sstevel@tonic-gate 	 * Since this is only ever called by a slave,
5507c478bd9Sstevel@tonic-gate 	 * the slab structure size always contains a buflist.
5517c478bd9Sstevel@tonic-gate 	 */
5527c478bd9Sstevel@tonic-gate 	for (; sp; sp = nsp) {
5537c478bd9Sstevel@tonic-gate 		nsp = sp->sl_next;
5547c478bd9Sstevel@tonic-gate 		smr_free_buflist(sp);
5557c478bd9Sstevel@tonic-gate 		FREESTRUCT(sp, smr_slab_t, 1);
5567c478bd9Sstevel@tonic-gate 	}
5577c478bd9Sstevel@tonic-gate }
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate /*
5607c478bd9Sstevel@tonic-gate  * Allocate a SMR buffer on behalf of the local domain
5617c478bd9Sstevel@tonic-gate  * which is ultimately targeted for the given domain.
5627c478bd9Sstevel@tonic-gate  *
5637c478bd9Sstevel@tonic-gate  * IMPORTANT: This routine is going to drop the domain rwlock (drwlock)
5647c478bd9Sstevel@tonic-gate  *	      for the domain on whose behalf the request is being
5657c478bd9Sstevel@tonic-gate  *	      made.  This routine canNOT block on trying to
5667c478bd9Sstevel@tonic-gate  *	      reacquire the drwlock.  If he does block then somebody
5677c478bd9Sstevel@tonic-gate  *	      must have the write lock on the domain which most likely
5687c478bd9Sstevel@tonic-gate  *	      means the domain is going south anyway, so just bail on
5697c478bd9Sstevel@tonic-gate  *	      this buffer.  Higher levels will retry if needed.
5707c478bd9Sstevel@tonic-gate  *
5717c478bd9Sstevel@tonic-gate  * XXX - Support larger than IDN_SMR_BUFSIZE allocations?
5727c478bd9Sstevel@tonic-gate  *
5737c478bd9Sstevel@tonic-gate  * Returns:	A negative return value indicates lock lost on domid.
5747c478bd9Sstevel@tonic-gate  *		EINVAL, ENOLINK, ENOLCK(internal)
5757c478bd9Sstevel@tonic-gate  *		smr_slaballoc_wait
5767c478bd9Sstevel@tonic-gate  * 		(EINVAL, ETIMEDOUT)
5777c478bd9Sstevel@tonic-gate  *		smr_slabwatier_unregister
5787c478bd9Sstevel@tonic-gate  *		(0, EINVAL, EBUSY, ENOMEM)
5797c478bd9Sstevel@tonic-gate  */
5807c478bd9Sstevel@tonic-gate int
5817c478bd9Sstevel@tonic-gate smr_buf_alloc(int domid, uint_t len, caddr_t *bufpp)
5827c478bd9Sstevel@tonic-gate {
5837c478bd9Sstevel@tonic-gate 	register idn_domain_t	*dp, *ldp;
5847c478bd9Sstevel@tonic-gate 	smr_slab_t	*sp;
5857c478bd9Sstevel@tonic-gate 	caddr_t		bufp = NULL;
5867c478bd9Sstevel@tonic-gate 	int		serrno;
5877c478bd9Sstevel@tonic-gate 	procname_t	proc = "smr_buf_alloc";
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	dp = &idn_domain[domid];
5907c478bd9Sstevel@tonic-gate 	/*
5917c478bd9Sstevel@tonic-gate 	 * Local domain can only allocate on behalf of
5927c478bd9Sstevel@tonic-gate 	 * itself if this is a priviledged call and the
5937c478bd9Sstevel@tonic-gate 	 * caller is the master.
5947c478bd9Sstevel@tonic-gate 	 */
5957c478bd9Sstevel@tonic-gate 	ASSERT((domid != idn.localid) && (domid != IDN_NIL_DOMID));
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 	*bufpp = NULL;
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 	if (len > IDN_DATA_SIZE) {
6007c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
601bf30efa4Smathue 		    "IDN: 303: buffer len %d > IDN_DATA_SIZE (%lu)",
6027c478bd9Sstevel@tonic-gate 		    len, IDN_DATA_SIZE);
6037c478bd9Sstevel@tonic-gate 		IDN_GKSTAT_GLOBAL_EVENT(gk_buffail, gk_buffail_last);
6047c478bd9Sstevel@tonic-gate 		return (EINVAL);
6057c478bd9Sstevel@tonic-gate 	}
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	/*
6087c478bd9Sstevel@tonic-gate 	 * Need to go to my local slab list to find
6097c478bd9Sstevel@tonic-gate 	 * a buffer.
6107c478bd9Sstevel@tonic-gate 	 */
6117c478bd9Sstevel@tonic-gate 	ldp = &idn_domain[idn.localid];
6127c478bd9Sstevel@tonic-gate 	/*
6137c478bd9Sstevel@tonic-gate 	 * Now we loop trying to locate a buffer out of our
6147c478bd9Sstevel@tonic-gate 	 * slabs.  We continue this until either we find a
6157c478bd9Sstevel@tonic-gate 	 * buffer or we're unable to allocate a slab.  Note
6167c478bd9Sstevel@tonic-gate 	 * that new slabs are allocated to the front.
6177c478bd9Sstevel@tonic-gate 	 */
6187c478bd9Sstevel@tonic-gate 	DSLAB_LOCK_SHARED(idn.localid);
6197c478bd9Sstevel@tonic-gate 	sp = ldp->dslab;
6207c478bd9Sstevel@tonic-gate 	do {
6217c478bd9Sstevel@tonic-gate 		int	spl, all_empty;
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 		if (sp == NULL) {
6247c478bd9Sstevel@tonic-gate 			if ((serrno = smr_slab_alloc(idn.localid, &sp)) != 0) {
6257c478bd9Sstevel@tonic-gate 				PR_SMR("%s:%d: failed to allocate "
6267c478bd9Sstevel@tonic-gate 				    "slab [serrno = %d]",
6277c478bd9Sstevel@tonic-gate 				    proc, domid, serrno);
6287c478bd9Sstevel@tonic-gate 				DSLAB_UNLOCK(idn.localid);
6297c478bd9Sstevel@tonic-gate 				IDN_GKSTAT_GLOBAL_EVENT(gk_buffail,
6307c478bd9Sstevel@tonic-gate 				    gk_buffail_last);
6317c478bd9Sstevel@tonic-gate 				return (serrno);
6327c478bd9Sstevel@tonic-gate 			}
6337c478bd9Sstevel@tonic-gate 			/*
6347c478bd9Sstevel@tonic-gate 			 * Of course, the world may have changed while
6357c478bd9Sstevel@tonic-gate 			 * we dropped the lock.  Better make sure we're
6367c478bd9Sstevel@tonic-gate 			 * still established.
6377c478bd9Sstevel@tonic-gate 			 */
6387c478bd9Sstevel@tonic-gate 			if (dp->dstate != IDNDS_CONNECTED) {
6397c478bd9Sstevel@tonic-gate 				PR_SMR("%s:%d: state changed during slab "
6407c478bd9Sstevel@tonic-gate 				    "alloc (dstate = %s)\n",
6417c478bd9Sstevel@tonic-gate 				    proc, domid, idnds_str[dp->dstate]);
6427c478bd9Sstevel@tonic-gate 				DSLAB_UNLOCK(idn.localid);
6437c478bd9Sstevel@tonic-gate 				IDN_GKSTAT_GLOBAL_EVENT(gk_buffail,
6447c478bd9Sstevel@tonic-gate 				    gk_buffail_last);
6457c478bd9Sstevel@tonic-gate 				return (ENOLINK);
6467c478bd9Sstevel@tonic-gate 			}
6477c478bd9Sstevel@tonic-gate 			/*
6487c478bd9Sstevel@tonic-gate 			 * We were able to allocate a slab.  Should
6497c478bd9Sstevel@tonic-gate 			 * be at the front of the list, spin again.
6507c478bd9Sstevel@tonic-gate 			 */
6517c478bd9Sstevel@tonic-gate 			sp = ldp->dslab;
6527c478bd9Sstevel@tonic-gate 		}
6537c478bd9Sstevel@tonic-gate 		/*
6547c478bd9Sstevel@tonic-gate 		 * If we have reached here then we have a slab!
6557c478bd9Sstevel@tonic-gate 		 * Hopefully there are free bufs there :-o
6567c478bd9Sstevel@tonic-gate 		 */
6577c478bd9Sstevel@tonic-gate 		spl = splhi();
6587c478bd9Sstevel@tonic-gate 		all_empty = 1;
6597c478bd9Sstevel@tonic-gate 		for (; sp && !bufp; sp = sp->sl_next) {
6607c478bd9Sstevel@tonic-gate 			smr_slabbuf_t	*bp;
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 			if (sp->sl_free == NULL)
6637c478bd9Sstevel@tonic-gate 				continue;
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 			if (!lock_try(&sp->sl_lock)) {
6667c478bd9Sstevel@tonic-gate 				all_empty = 0;
6677c478bd9Sstevel@tonic-gate 				continue;
6687c478bd9Sstevel@tonic-gate 			}
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 			if ((bp = sp->sl_free) == NULL) {
6717c478bd9Sstevel@tonic-gate 				lock_clear(&sp->sl_lock);
6727c478bd9Sstevel@tonic-gate 				continue;
6737c478bd9Sstevel@tonic-gate 			}
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 			sp->sl_free = bp->sb_next;
6767c478bd9Sstevel@tonic-gate 			bp->sb_next = sp->sl_inuse;
6777c478bd9Sstevel@tonic-gate 			sp->sl_inuse = bp;
6787c478bd9Sstevel@tonic-gate 			/*
6797c478bd9Sstevel@tonic-gate 			 * Found a free buffer.
6807c478bd9Sstevel@tonic-gate 			 */
6817c478bd9Sstevel@tonic-gate 			bp->sb_domid = domid;
6827c478bd9Sstevel@tonic-gate 			bufp = bp->sb_bufp;
6837c478bd9Sstevel@tonic-gate 			lock_clear(&sp->sl_lock);
6847c478bd9Sstevel@tonic-gate 		}
6857c478bd9Sstevel@tonic-gate 		splx(spl);
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 		if (!all_empty && !bufp) {
6887c478bd9Sstevel@tonic-gate 			/*
6897c478bd9Sstevel@tonic-gate 			 * If we still haven't found a buffer, but
6907c478bd9Sstevel@tonic-gate 			 * there's still possibly a buffer available,
6917c478bd9Sstevel@tonic-gate 			 * then try again.  Only if we're absolutely
6927c478bd9Sstevel@tonic-gate 			 * sure all slabs are empty do we attempt
6937c478bd9Sstevel@tonic-gate 			 * to allocate a new one.
6947c478bd9Sstevel@tonic-gate 			 */
6957c478bd9Sstevel@tonic-gate 			sp = ldp->dslab;
6967c478bd9Sstevel@tonic-gate 		}
6977c478bd9Sstevel@tonic-gate 	} while (bufp == NULL);
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 	*bufpp = bufp;
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 	ATOMIC_INC(dp->dio);
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	DSLAB_UNLOCK(idn.localid);
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 	return (0);
7067c478bd9Sstevel@tonic-gate }
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate /*
7097c478bd9Sstevel@tonic-gate  * Free a buffer allocated to the local domain back to
7107c478bd9Sstevel@tonic-gate  * its respective slab.  Slabs are freed via the slab-reap command.
7117c478bd9Sstevel@tonic-gate  * XXX - Support larger than IDN_SMR_BUFSIZE allocations?
7127c478bd9Sstevel@tonic-gate  */
7137c478bd9Sstevel@tonic-gate int
7147c478bd9Sstevel@tonic-gate smr_buf_free(int domid, caddr_t bufp, uint_t len)
7157c478bd9Sstevel@tonic-gate {
7167c478bd9Sstevel@tonic-gate 	register smr_slab_t	*sp;
7177c478bd9Sstevel@tonic-gate 	smr_slabbuf_t		*bp, **bpp;
7187c478bd9Sstevel@tonic-gate 	idn_domain_t		*ldp;
7197c478bd9Sstevel@tonic-gate 	int		buffreed;
7207c478bd9Sstevel@tonic-gate 	int		lockheld = (len == (uint_t)-1);
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 	/*
7237c478bd9Sstevel@tonic-gate 	 * We should never be free'ing a buffer on
7247c478bd9Sstevel@tonic-gate 	 * behalf of ourselves as we are never the
7257c478bd9Sstevel@tonic-gate 	 * target for allocated SMR buffers.
7267c478bd9Sstevel@tonic-gate 	 */
7277c478bd9Sstevel@tonic-gate 	ASSERT(domid != idn.localid);
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 	sp = NULL;
7307c478bd9Sstevel@tonic-gate 	buffreed = 0;
7317c478bd9Sstevel@tonic-gate 	ldp = &idn_domain[idn.localid];
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 	DSLAB_LOCK_SHARED(idn.localid);
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 	if (((uintptr_t)bufp & (IDN_SMR_BUFSIZE-1)) &&
7367c478bd9Sstevel@tonic-gate 	    (IDN_ADDR2OFFSET(bufp) % IDN_SMR_BUFSIZE)) {
7377c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
738bf30efa4Smathue 		    "IDN: 304: buffer (0x%p) from domain %d not on a "
739*07d06da5SSurya Prakki 		    "%d boundary", (void *)bufp, domid, IDN_SMR_BUFSIZE);
7407c478bd9Sstevel@tonic-gate 		goto bfdone;
7417c478bd9Sstevel@tonic-gate 	}
7427c478bd9Sstevel@tonic-gate 	if (!lockheld && (len > IDN_DATA_SIZE)) {
7437c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
7447c478bd9Sstevel@tonic-gate 		    "IDN: 305: buffer length (%d) from domain %d greater "
745bf30efa4Smathue 		    "than IDN_DATA_SIZE (%lu)",
7467c478bd9Sstevel@tonic-gate 		    len, domid, IDN_DATA_SIZE);
7477c478bd9Sstevel@tonic-gate 		goto bfdone;
7487c478bd9Sstevel@tonic-gate 	}
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 	for (sp = ldp->dslab; sp; sp = sp->sl_next)
7517c478bd9Sstevel@tonic-gate 		if ((bufp >= sp->sl_start) && (bufp < sp->sl_end))
7527c478bd9Sstevel@tonic-gate 			break;
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 	if (sp) {
7557c478bd9Sstevel@tonic-gate 		int spl;
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 		spl = splhi();
7587c478bd9Sstevel@tonic-gate 		while (!lock_try(&sp->sl_lock))
7597c478bd9Sstevel@tonic-gate 			;
7607c478bd9Sstevel@tonic-gate 		bpp = &sp->sl_inuse;
7617c478bd9Sstevel@tonic-gate 		for (bp = *bpp; bp; bp = *bpp) {
7627c478bd9Sstevel@tonic-gate 			if (bp->sb_bufp == bufp)
7637c478bd9Sstevel@tonic-gate 				break;
7647c478bd9Sstevel@tonic-gate 			bpp = &bp->sb_next;
7657c478bd9Sstevel@tonic-gate 		}
7667c478bd9Sstevel@tonic-gate 		if (bp) {
7677c478bd9Sstevel@tonic-gate 			ASSERT(bp->sb_domid == domid);
7687c478bd9Sstevel@tonic-gate 			buffreed++;
7697c478bd9Sstevel@tonic-gate 			bp->sb_domid = IDN_NIL_DOMID;
7707c478bd9Sstevel@tonic-gate 			*bpp = bp->sb_next;
7717c478bd9Sstevel@tonic-gate 			bp->sb_next = sp->sl_free;
7727c478bd9Sstevel@tonic-gate 			sp->sl_free = bp;
7737c478bd9Sstevel@tonic-gate 		}
7747c478bd9Sstevel@tonic-gate 		lock_clear(&sp->sl_lock);
7757c478bd9Sstevel@tonic-gate 		splx(spl);
7767c478bd9Sstevel@tonic-gate 	}
7777c478bd9Sstevel@tonic-gate bfdone:
7787c478bd9Sstevel@tonic-gate 	if (buffreed) {
7797c478bd9Sstevel@tonic-gate 		ATOMIC_DEC(idn_domain[domid].dio);
7807c478bd9Sstevel@tonic-gate 		DIOCHECK(domid);
7817c478bd9Sstevel@tonic-gate 	} else {
7827c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
7837c478bd9Sstevel@tonic-gate 		    "IDN: 306: unknown buffer (0x%p) from domain %d",
784*07d06da5SSurya Prakki 		    (void *)bufp, domid);
7857c478bd9Sstevel@tonic-gate 		ATOMIC_INC(idn_domain[domid].dioerr);
7867c478bd9Sstevel@tonic-gate 	}
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 	DSLAB_UNLOCK(idn.localid);
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate 	return (sp ? 0 : -1);
7917c478bd9Sstevel@tonic-gate }
7927c478bd9Sstevel@tonic-gate 
7937c478bd9Sstevel@tonic-gate /*
7947c478bd9Sstevel@tonic-gate  * Alternative interface to smr_buf_free, but with local drwlock
7957c478bd9Sstevel@tonic-gate  * held.
7967c478bd9Sstevel@tonic-gate  */
7977c478bd9Sstevel@tonic-gate /* ARGSUSED2 */
7987c478bd9Sstevel@tonic-gate int
7997c478bd9Sstevel@tonic-gate smr_buf_free_locked(int domid, caddr_t bufp, uint_t len)
8007c478bd9Sstevel@tonic-gate {
8017c478bd9Sstevel@tonic-gate 	return (smr_buf_free(domid, bufp, (uint_t)-1));
8027c478bd9Sstevel@tonic-gate }
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate /*
8057c478bd9Sstevel@tonic-gate  * Free any and all buffers associated with the given domain.
8067c478bd9Sstevel@tonic-gate  * Assumption is that domain is dead and buffers are not in use.
8077c478bd9Sstevel@tonic-gate  * Returns:	Number of buffers freed.
8087c478bd9Sstevel@tonic-gate  *		-1 if error.
8097c478bd9Sstevel@tonic-gate  */
8107c478bd9Sstevel@tonic-gate int
8117c478bd9Sstevel@tonic-gate smr_buf_free_all(int domid)
8127c478bd9Sstevel@tonic-gate {
8137c478bd9Sstevel@tonic-gate 	register smr_slab_t	*sp;
8147c478bd9Sstevel@tonic-gate 	register smr_slabbuf_t	*bp, **bpp;
8157c478bd9Sstevel@tonic-gate 	idn_domain_t		*ldp;
8167c478bd9Sstevel@tonic-gate 	int			nbufsfreed = 0;
8177c478bd9Sstevel@tonic-gate 	procname_t	proc = "smr_buf_free_all";
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 	/*
8207c478bd9Sstevel@tonic-gate 	 * We should never be free'ing buffers on
8217c478bd9Sstevel@tonic-gate 	 * behalf of ourself
8227c478bd9Sstevel@tonic-gate 	 */
8237c478bd9Sstevel@tonic-gate 	ASSERT(domid != idn.localid);
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate 	if (!VALID_DOMAINID(domid)) {
826d3d50737SRafael Vanoni 		cmn_err(CE_WARN, "IDN: 307: domain ID (%d) invalid", domid);
8277c478bd9Sstevel@tonic-gate 		return (-1);
8287c478bd9Sstevel@tonic-gate 	}
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 	ldp = &idn_domain[idn.localid];
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 	/*
8337c478bd9Sstevel@tonic-gate 	 * We grab the writer lock so that we don't have any
8347c478bd9Sstevel@tonic-gate 	 * competition during a "free-all" call.
8357c478bd9Sstevel@tonic-gate 	 * No need to grab individual slab locks when holding
8367c478bd9Sstevel@tonic-gate 	 * dslab(writer).
8377c478bd9Sstevel@tonic-gate 	 */
8387c478bd9Sstevel@tonic-gate 	DSLAB_LOCK_EXCL(idn.localid);
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate 	for (sp = ldp->dslab; sp; sp = sp->sl_next) {
8417c478bd9Sstevel@tonic-gate 		bpp = &sp->sl_inuse;
8427c478bd9Sstevel@tonic-gate 		for (bp = *bpp; bp; bp = *bpp) {
8437c478bd9Sstevel@tonic-gate 			if (bp->sb_domid == domid) {
8447c478bd9Sstevel@tonic-gate 				bp->sb_domid = IDN_NIL_DOMID;
8457c478bd9Sstevel@tonic-gate 				*bpp = bp->sb_next;
8467c478bd9Sstevel@tonic-gate 				bp->sb_next = sp->sl_free;
8477c478bd9Sstevel@tonic-gate 				sp->sl_free = bp;
8487c478bd9Sstevel@tonic-gate 				nbufsfreed++;
8497c478bd9Sstevel@tonic-gate 			} else {
8507c478bd9Sstevel@tonic-gate 				bpp = &bp->sb_next;
8517c478bd9Sstevel@tonic-gate 			}
8527c478bd9Sstevel@tonic-gate 		}
8537c478bd9Sstevel@tonic-gate 	}
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate 	if (nbufsfreed > 0) {
8567c478bd9Sstevel@tonic-gate 		ATOMIC_SUB(idn_domain[domid].dio, nbufsfreed);
8577c478bd9Sstevel@tonic-gate 		idn_domain[domid].dioerr = 0;
8587c478bd9Sstevel@tonic-gate 		DIOCHECK(domid);
8597c478bd9Sstevel@tonic-gate 	}
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 	DSLAB_UNLOCK(idn.localid);
8627c478bd9Sstevel@tonic-gate 
863d3d50737SRafael Vanoni 	PR_SMR("%s: freed %d buffers for domain %d\n", proc, nbufsfreed, domid);
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate 	return (nbufsfreed);
8667c478bd9Sstevel@tonic-gate }
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate int
8697c478bd9Sstevel@tonic-gate smr_buf_reclaim(int domid, int nbufs)
8707c478bd9Sstevel@tonic-gate {
8717c478bd9Sstevel@tonic-gate 	int		num_reclaimed = 0;
8727c478bd9Sstevel@tonic-gate 	idn_domain_t	*ldp, *dp;
8737c478bd9Sstevel@tonic-gate 	procname_t	proc = "smr_buf_reclaim";
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	ldp = &idn_domain[idn.localid];
8767c478bd9Sstevel@tonic-gate 	dp  = &idn_domain[domid];
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 	ASSERT(domid != idn.localid);
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate 	if (ATOMIC_CAS(&dp->dreclaim_inprogress, 0, 1)) {
8817c478bd9Sstevel@tonic-gate 		/*
8827c478bd9Sstevel@tonic-gate 		 * Reclaim is already in progress, don't
8837c478bd9Sstevel@tonic-gate 		 * bother.
8847c478bd9Sstevel@tonic-gate 		 */
8857c478bd9Sstevel@tonic-gate 		PR_DATA("%s: reclaim already in progress\n", proc);
8867c478bd9Sstevel@tonic-gate 		return (0);
8877c478bd9Sstevel@tonic-gate 	}
8887c478bd9Sstevel@tonic-gate 
889d3d50737SRafael Vanoni 	PR_SMR("%s: requested %d buffers from domain %d\n", proc, nbufs, domid);
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate 	if (dp->dio && nbufs) {
8927c478bd9Sstevel@tonic-gate 		register smr_slab_t	*sp;
8937c478bd9Sstevel@tonic-gate 		int spl;
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 		DSLAB_LOCK_SHARED(idn.localid);
8967c478bd9Sstevel@tonic-gate 		spl = splhi();
8977c478bd9Sstevel@tonic-gate 		for (sp = ldp->dslab; sp && nbufs; sp = sp->sl_next) {
8987c478bd9Sstevel@tonic-gate 			register smr_slabbuf_t	*bp, **bpp;
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 			if (sp->sl_inuse == NULL)
9017c478bd9Sstevel@tonic-gate 				continue;
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 			if (!lock_try(&sp->sl_lock))
9047c478bd9Sstevel@tonic-gate 				continue;
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 			if (sp->sl_inuse == NULL) {
9077c478bd9Sstevel@tonic-gate 				lock_clear(&sp->sl_lock);
9087c478bd9Sstevel@tonic-gate 				continue;
9097c478bd9Sstevel@tonic-gate 			}
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 			bpp = &sp->sl_inuse;
9127c478bd9Sstevel@tonic-gate 			for (bp = *bpp; bp && nbufs; bp = *bpp) {
9137c478bd9Sstevel@tonic-gate 				if (bp->sb_domid == domid) {
9147c478bd9Sstevel@tonic-gate 					/*
9157c478bd9Sstevel@tonic-gate 					 * Buffer no longer in use,
9167c478bd9Sstevel@tonic-gate 					 * reclaim it.
9177c478bd9Sstevel@tonic-gate 					 */
9187c478bd9Sstevel@tonic-gate 					bp->sb_domid = IDN_NIL_DOMID;
9197c478bd9Sstevel@tonic-gate 					*bpp = bp->sb_next;
9207c478bd9Sstevel@tonic-gate 					bp->sb_next = sp->sl_free;
9217c478bd9Sstevel@tonic-gate 					sp->sl_free = bp;
9227c478bd9Sstevel@tonic-gate 					num_reclaimed++;
9237c478bd9Sstevel@tonic-gate 					nbufs--;
9247c478bd9Sstevel@tonic-gate 				} else {
9257c478bd9Sstevel@tonic-gate 					bpp = &bp->sb_next;
9267c478bd9Sstevel@tonic-gate 				}
9277c478bd9Sstevel@tonic-gate 			}
9287c478bd9Sstevel@tonic-gate 			lock_clear(&sp->sl_lock);
9297c478bd9Sstevel@tonic-gate 		}
9307c478bd9Sstevel@tonic-gate 		splx(spl);
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 		if (num_reclaimed > 0) {
9337c478bd9Sstevel@tonic-gate 			ATOMIC_SUB(dp->dio, num_reclaimed);
9347c478bd9Sstevel@tonic-gate 			DIOCHECK(domid);
9357c478bd9Sstevel@tonic-gate 		}
9367c478bd9Sstevel@tonic-gate 		DSLAB_UNLOCK(idn.localid);
9377c478bd9Sstevel@tonic-gate 	}
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 	PR_SMR("%s: reclaimed %d buffers from domain %d\n",
9407c478bd9Sstevel@tonic-gate 	    proc, num_reclaimed, domid);
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 	return (num_reclaimed);
9437c478bd9Sstevel@tonic-gate }
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate /*
9467c478bd9Sstevel@tonic-gate  * Returns 1	If any buffers are locked for the given slab.
9477c478bd9Sstevel@tonic-gate  *	   0	If all buffers are free for the given slab.
9487c478bd9Sstevel@tonic-gate  *
9497c478bd9Sstevel@tonic-gate  * The caller is assumed to have the slab protected so that no
9507c478bd9Sstevel@tonic-gate  * new allocations are attempted from it.  Also, this is only
9517c478bd9Sstevel@tonic-gate  * valid to be called with respect to slabs that were allocated
9527c478bd9Sstevel@tonic-gate  * on behalf of the local domain, i.e. the master is not expected
9537c478bd9Sstevel@tonic-gate  * to call this function with (slave) slab "representatives".
9547c478bd9Sstevel@tonic-gate  */
9557c478bd9Sstevel@tonic-gate int
9567c478bd9Sstevel@tonic-gate smr_slab_busy(smr_slab_t *sp)
9577c478bd9Sstevel@tonic-gate {
9587c478bd9Sstevel@tonic-gate 	return ((sp && sp->sl_inuse) ? 1 : 0);
9597c478bd9Sstevel@tonic-gate }
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate int
9627c478bd9Sstevel@tonic-gate smr_slabwaiter_init()
9637c478bd9Sstevel@tonic-gate {
9647c478bd9Sstevel@tonic-gate 	register int		i;
9657c478bd9Sstevel@tonic-gate 	struct slabwaiter	*wp;
9667c478bd9Sstevel@tonic-gate 
9677c478bd9Sstevel@tonic-gate 	if (idn.slabwaiter != NULL)
9687c478bd9Sstevel@tonic-gate 		return (0);
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate 	/*
9717c478bd9Sstevel@tonic-gate 	 * Initialize the slab waiting area for MAX_DOMAINS.
9727c478bd9Sstevel@tonic-gate 	 */
9737c478bd9Sstevel@tonic-gate 	idn.slabwaiter = GETSTRUCT(struct slabwaiter, MAX_DOMAINS);
9747c478bd9Sstevel@tonic-gate 	wp = idn.slabwaiter;
9757c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_DOMAINS; wp++, i++) {
9767c478bd9Sstevel@tonic-gate 		wp->w_closed = 0;
9777c478bd9Sstevel@tonic-gate 		mutex_init(&wp->w_mutex, NULL, MUTEX_DEFAULT, NULL);
9787c478bd9Sstevel@tonic-gate 		cv_init(&wp->w_cv, NULL, CV_DEFAULT, NULL);
9797c478bd9Sstevel@tonic-gate 	}
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate 	return (0);
9827c478bd9Sstevel@tonic-gate }
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate void
9857c478bd9Sstevel@tonic-gate smr_slabwaiter_deinit()
9867c478bd9Sstevel@tonic-gate {
9877c478bd9Sstevel@tonic-gate 	register int		i;
9887c478bd9Sstevel@tonic-gate 	struct slabwaiter	*wp;
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate 	if ((wp = idn.slabwaiter) == NULL)
9917c478bd9Sstevel@tonic-gate 		return;
9927c478bd9Sstevel@tonic-gate 
9937c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_DOMAINS; wp++, i++) {
9947c478bd9Sstevel@tonic-gate 		ASSERT(wp->w_nwaiters == 0);
9957c478bd9Sstevel@tonic-gate 		ASSERT(wp->w_sp == NULL);
9967c478bd9Sstevel@tonic-gate 		cv_destroy(&wp->w_cv);
9977c478bd9Sstevel@tonic-gate 		mutex_destroy(&wp->w_mutex);
9987c478bd9Sstevel@tonic-gate 	}
9997c478bd9Sstevel@tonic-gate 
10007c478bd9Sstevel@tonic-gate 	FREESTRUCT(idn.slabwaiter, struct slabwaiter, MAX_DOMAINS);
10017c478bd9Sstevel@tonic-gate 	idn.slabwaiter = NULL;
10027c478bd9Sstevel@tonic-gate }
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate void
10057c478bd9Sstevel@tonic-gate smr_slabwaiter_open(domainset_t domset)
10067c478bd9Sstevel@tonic-gate {
10077c478bd9Sstevel@tonic-gate 	int			d;
10087c478bd9Sstevel@tonic-gate 	struct slabwaiter	*wp;
10097c478bd9Sstevel@tonic-gate 
10107c478bd9Sstevel@tonic-gate 	if ((domset == 0) || !idn.slabwaiter)
10117c478bd9Sstevel@tonic-gate 		return;
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 	wp = idn.slabwaiter;
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 	for (d = 0; d < MAX_DOMAINS; wp++, d++) {
10167c478bd9Sstevel@tonic-gate 		if (!DOMAIN_IN_SET(domset, d))
10177c478bd9Sstevel@tonic-gate 			continue;
10187c478bd9Sstevel@tonic-gate 		mutex_enter(&wp->w_mutex);
10197c478bd9Sstevel@tonic-gate 		wp->w_closed = 0;
10207c478bd9Sstevel@tonic-gate 		mutex_exit(&wp->w_mutex);
10217c478bd9Sstevel@tonic-gate 	}
10227c478bd9Sstevel@tonic-gate }
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate void
10257c478bd9Sstevel@tonic-gate smr_slabwaiter_close(domainset_t domset)
10267c478bd9Sstevel@tonic-gate {
10277c478bd9Sstevel@tonic-gate 	int			d;
10287c478bd9Sstevel@tonic-gate 	struct slabwaiter	*wp;
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate 	if ((domset == 0) || !idn.slabwaiter)
10317c478bd9Sstevel@tonic-gate 		return;
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 	wp = idn.slabwaiter;
10347c478bd9Sstevel@tonic-gate 
10357c478bd9Sstevel@tonic-gate 	for (d = 0; d < MAX_DOMAINS; wp++, d++) {
10367c478bd9Sstevel@tonic-gate 		if (!DOMAIN_IN_SET(domset, d))
10377c478bd9Sstevel@tonic-gate 			continue;
10387c478bd9Sstevel@tonic-gate 		mutex_enter(&wp->w_mutex);
10397c478bd9Sstevel@tonic-gate 		wp->w_closed = 1;
10407c478bd9Sstevel@tonic-gate 		cv_broadcast(&wp->w_cv);
10417c478bd9Sstevel@tonic-gate 		mutex_exit(&wp->w_mutex);
10427c478bd9Sstevel@tonic-gate 	}
10437c478bd9Sstevel@tonic-gate }
10447c478bd9Sstevel@tonic-gate 
10457c478bd9Sstevel@tonic-gate /*
10467c478bd9Sstevel@tonic-gate  * Register the caller with the waiting list for the
10477c478bd9Sstevel@tonic-gate  * given domain.
10487c478bd9Sstevel@tonic-gate  *
10497c478bd9Sstevel@tonic-gate  * Protocol:
10507c478bd9Sstevel@tonic-gate  *	1st Local requester:	register -> alloc ->
10517c478bd9Sstevel@tonic-gate  *						put(wakeup|xdc) -> unregister
10527c478bd9Sstevel@tonic-gate  *	Nth Local requester:	register -> wait
10537c478bd9Sstevel@tonic-gate  *	1st Remote requester:	register -> xdc -> wait
10547c478bd9Sstevel@tonic-gate  *	Nth Remote requester:	register -> wait
10557c478bd9Sstevel@tonic-gate  *
10567c478bd9Sstevel@tonic-gate  *	Remote Responder:	local alloc -> put(xdc)
10577c478bd9Sstevel@tonic-gate  *	Local Handler:		xdc -> put(wakeup)
10587c478bd9Sstevel@tonic-gate  *
10597c478bd9Sstevel@tonic-gate  * E.g. A standard slave allocation request:
10607c478bd9Sstevel@tonic-gate  *	slave			master
10617c478bd9Sstevel@tonic-gate  *	-----			------
10627c478bd9Sstevel@tonic-gate  *	idn_slab_alloc(remote)
10637c478bd9Sstevel@tonic-gate  *	- register
10647c478bd9Sstevel@tonic-gate  *	- xdc		->	idn_handler
10657c478bd9Sstevel@tonic-gate  *	- wait			...
10667c478bd9Sstevel@tonic-gate  *				idn_slab_alloc(local)
10677c478bd9Sstevel@tonic-gate  *				- register
10687c478bd9Sstevel@tonic-gate  *				- alloc
10697c478bd9Sstevel@tonic-gate  *				- put
10707c478bd9Sstevel@tonic-gate  *				  . wakeup [local]
10717c478bd9Sstevel@tonic-gate  *				- unregister
10727c478bd9Sstevel@tonic-gate  *	idn_handler    	<-	- xdc
10737c478bd9Sstevel@tonic-gate  *	- put       		DONE
10747c478bd9Sstevel@tonic-gate  *	  . wakeup [local]
10757c478bd9Sstevel@tonic-gate  *	    |
10767c478bd9Sstevel@tonic-gate  *	    V
10777c478bd9Sstevel@tonic-gate  *      - wait
10787c478bd9Sstevel@tonic-gate  *	  . unregister
10797c478bd9Sstevel@tonic-gate  *	DONE
10807c478bd9Sstevel@tonic-gate  */
10817c478bd9Sstevel@tonic-gate static int
10827c478bd9Sstevel@tonic-gate smr_slabwaiter_register(int domid)
10837c478bd9Sstevel@tonic-gate {
10847c478bd9Sstevel@tonic-gate 	struct slabwaiter	*wp;
10857c478bd9Sstevel@tonic-gate 	int		nwait;
10867c478bd9Sstevel@tonic-gate 	procname_t	proc = "smr_slabwaiter_register";
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate 	ASSERT(domid != IDN_NIL_DOMID);
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate 	ASSERT(DSLAB_READ_HELD(domid));
10927c478bd9Sstevel@tonic-gate 
10937c478bd9Sstevel@tonic-gate 	wp = &idn.slabwaiter[domid];
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&wp->w_mutex));
10967c478bd9Sstevel@tonic-gate 
10977c478bd9Sstevel@tonic-gate 	mutex_enter(&wp->w_mutex);
10987c478bd9Sstevel@tonic-gate 
10997c478bd9Sstevel@tonic-gate 	nwait = ++(wp->w_nwaiters);
11007c478bd9Sstevel@tonic-gate 	ASSERT(nwait > 0);
11017c478bd9Sstevel@tonic-gate 
1102d3d50737SRafael Vanoni 	PR_SMR("%s: domain = %d, (new)nwaiters = %d\n", proc, domid, nwait);
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate 	if (nwait > 1) {
11057c478bd9Sstevel@tonic-gate 		/*
11067c478bd9Sstevel@tonic-gate 		 * There are already waiters for slab allocations
11077c478bd9Sstevel@tonic-gate 		 * with respect to this domain.
11087c478bd9Sstevel@tonic-gate 		 */
11097c478bd9Sstevel@tonic-gate 		PR_SMR("%s: existing waiters for slabs for domain %d\n",
11107c478bd9Sstevel@tonic-gate 		    proc, domid);
11117c478bd9Sstevel@tonic-gate 		mutex_exit(&wp->w_mutex);
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate 		return (nwait);
11147c478bd9Sstevel@tonic-gate 	}
11157c478bd9Sstevel@tonic-gate 	PR_SMR("%s: initial waiter for slabs for domain %d\n", proc, domid);
11167c478bd9Sstevel@tonic-gate 	/*
11177c478bd9Sstevel@tonic-gate 	 * We are the first requester of a slab allocation for this
11187c478bd9Sstevel@tonic-gate 	 * respective domain.  Need to prep waiting area for
11197c478bd9Sstevel@tonic-gate 	 * subsequent arrival of a slab.
11207c478bd9Sstevel@tonic-gate 	 */
11217c478bd9Sstevel@tonic-gate 	wp->w_sp = NULL;
11227c478bd9Sstevel@tonic-gate 	wp->w_done = 0;
11237c478bd9Sstevel@tonic-gate 	wp->w_serrno = 0;
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate 	mutex_exit(&wp->w_mutex);
11267c478bd9Sstevel@tonic-gate 
11277c478bd9Sstevel@tonic-gate 	return (nwait);
11287c478bd9Sstevel@tonic-gate }
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate /*
11317c478bd9Sstevel@tonic-gate  * It is assumed that the caller had previously registered,
11327c478bd9Sstevel@tonic-gate  * but wakeup did not occur due to caller never waiting.
11337c478bd9Sstevel@tonic-gate  * Thus, slaballoc mutex is still held by caller.
11347c478bd9Sstevel@tonic-gate  *
11357c478bd9Sstevel@tonic-gate  * Returns:	0
11367c478bd9Sstevel@tonic-gate  *		EINVAL
11377c478bd9Sstevel@tonic-gate  *		EBUSY
11387c478bd9Sstevel@tonic-gate  *		w_serrno (smr_slaballoc_put)
11397c478bd9Sstevel@tonic-gate  *		(0, ENOLCK, ENOMEM, EDQUOT, EBUSY, ECANCELED)
11407c478bd9Sstevel@tonic-gate  */
11417c478bd9Sstevel@tonic-gate static int
11427c478bd9Sstevel@tonic-gate smr_slabwaiter_unregister(int domid, smr_slab_t **spp)
11437c478bd9Sstevel@tonic-gate {
11447c478bd9Sstevel@tonic-gate 	struct slabwaiter	*wp;
11457c478bd9Sstevel@tonic-gate 	int		serrno = 0;
11467c478bd9Sstevel@tonic-gate 	procname_t	proc = "smr_slabwaiter_unregister";
11477c478bd9Sstevel@tonic-gate 
11487c478bd9Sstevel@tonic-gate 
11497c478bd9Sstevel@tonic-gate 	ASSERT(domid != IDN_NIL_DOMID);
11507c478bd9Sstevel@tonic-gate 
11517c478bd9Sstevel@tonic-gate 	wp = &idn.slabwaiter[domid];
11527c478bd9Sstevel@tonic-gate 
11537c478bd9Sstevel@tonic-gate 	mutex_enter(&wp->w_mutex);
11547c478bd9Sstevel@tonic-gate 
1155d3d50737SRafael Vanoni 	PR_SMR("%s: domain = %d, nwaiters = %d\n", proc, domid, wp->w_nwaiters);
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate 	if (wp->w_nwaiters <= 0) {
11587c478bd9Sstevel@tonic-gate 		/*
11597c478bd9Sstevel@tonic-gate 		 * Hmmm...nobody is registered!
11607c478bd9Sstevel@tonic-gate 		 */
11617c478bd9Sstevel@tonic-gate 		PR_SMR("%s: NO WAITERS (domid = %d)\n", proc, domid);
11627c478bd9Sstevel@tonic-gate 		mutex_exit(&wp->w_mutex);
11637c478bd9Sstevel@tonic-gate 		return (EINVAL);
11647c478bd9Sstevel@tonic-gate 	}
11657c478bd9Sstevel@tonic-gate 	(wp->w_nwaiters)--;
11667c478bd9Sstevel@tonic-gate 	/*
11677c478bd9Sstevel@tonic-gate 	 * Is our present under the tree?
11687c478bd9Sstevel@tonic-gate 	 */
11697c478bd9Sstevel@tonic-gate 	if (!wp->w_done) {
11707c478bd9Sstevel@tonic-gate 		/*
11717c478bd9Sstevel@tonic-gate 		 * Bummer...no presents.  Let the caller know
11727c478bd9Sstevel@tonic-gate 		 * via a null slab pointer.
11737c478bd9Sstevel@tonic-gate 		 * Note that we don't clean up immediately since
11747c478bd9Sstevel@tonic-gate 		 * message might still come in for other waiters.
11757c478bd9Sstevel@tonic-gate 		 * Thus, late sleepers may still get a chance.
11767c478bd9Sstevel@tonic-gate 		 */
11777c478bd9Sstevel@tonic-gate 		PR_SMR("%s: bummer no slab allocated for domain %d\n",
11787c478bd9Sstevel@tonic-gate 		    proc, domid);
11797c478bd9Sstevel@tonic-gate 		ASSERT(wp->w_sp == NULL);
11807c478bd9Sstevel@tonic-gate 		(*spp) = NULL;
11817c478bd9Sstevel@tonic-gate 		serrno = wp->w_closed ? ECANCELED : EBUSY;
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate 	} else {
11847c478bd9Sstevel@tonic-gate 		(*spp) = wp->w_sp;
11857c478bd9Sstevel@tonic-gate 		serrno = wp->w_serrno;
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate #ifdef DEBUG
11887c478bd9Sstevel@tonic-gate 		if (serrno == 0) {
11897c478bd9Sstevel@tonic-gate 			register smr_slab_t	*sp;
11907c478bd9Sstevel@tonic-gate 
11917c478bd9Sstevel@tonic-gate 			ASSERT(wp->w_sp);
11927c478bd9Sstevel@tonic-gate 			PR_SMR("%s: allocation succeeded (domain %d)\n",
11937c478bd9Sstevel@tonic-gate 			    proc, domid);
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate 			DSLAB_LOCK_SHARED(domid);
11967c478bd9Sstevel@tonic-gate 			for (sp = idn_domain[domid].dslab; sp; sp = sp->sl_next)
11977c478bd9Sstevel@tonic-gate 				if (sp == wp->w_sp)
11987c478bd9Sstevel@tonic-gate 					break;
11997c478bd9Sstevel@tonic-gate 			if (sp == NULL)
12007c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
12017c478bd9Sstevel@tonic-gate 				    "%s:%d: slab ptr = NULL",
12027c478bd9Sstevel@tonic-gate 				    proc, domid);
12037c478bd9Sstevel@tonic-gate 			DSLAB_UNLOCK(domid);
12047c478bd9Sstevel@tonic-gate 		} else {
12057c478bd9Sstevel@tonic-gate 			PR_SMR("%s: allocation failed (domain %d) "
12067c478bd9Sstevel@tonic-gate 			    "[serrno = %d]\n", proc, domid, serrno);
12077c478bd9Sstevel@tonic-gate 		}
12087c478bd9Sstevel@tonic-gate #endif /* DEBUG */
12097c478bd9Sstevel@tonic-gate 	}
12107c478bd9Sstevel@tonic-gate 	if (wp->w_nwaiters == 0) {
12117c478bd9Sstevel@tonic-gate 		/*
12127c478bd9Sstevel@tonic-gate 		 * Last one turns out the lights.
12137c478bd9Sstevel@tonic-gate 		 */
12147c478bd9Sstevel@tonic-gate 		PR_SMR("%s: domain %d last waiter, turning out lights\n",
12157c478bd9Sstevel@tonic-gate 		    proc, domid);
12167c478bd9Sstevel@tonic-gate 		wp->w_sp = NULL;
12177c478bd9Sstevel@tonic-gate 		wp->w_done = 0;
12187c478bd9Sstevel@tonic-gate 		wp->w_serrno = 0;
12197c478bd9Sstevel@tonic-gate 	}
12207c478bd9Sstevel@tonic-gate 	mutex_exit(&wp->w_mutex);
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate 	return (serrno);
12237c478bd9Sstevel@tonic-gate }
12247c478bd9Sstevel@tonic-gate 
12257c478bd9Sstevel@tonic-gate /*
12267c478bd9Sstevel@tonic-gate  * Called to abort any slaballoc requests on behalf of the
12277c478bd9Sstevel@tonic-gate  * given domain.
12287c478bd9Sstevel@tonic-gate  */
12297c478bd9Sstevel@tonic-gate int
12307c478bd9Sstevel@tonic-gate smr_slabwaiter_abort(int domid, int serrno)
12317c478bd9Sstevel@tonic-gate {
12327c478bd9Sstevel@tonic-gate 	ASSERT(serrno != 0);
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate 	return (smr_slaballoc_put(domid, NULL, 0, serrno));
12357c478bd9Sstevel@tonic-gate }
12367c478bd9Sstevel@tonic-gate 
12377c478bd9Sstevel@tonic-gate /*
12387c478bd9Sstevel@tonic-gate  * Put ourselves into a timedwait waiting for slab to be
12397c478bd9Sstevel@tonic-gate  * allocated.
12407c478bd9Sstevel@tonic-gate  * Returns with slaballoc mutex dropped.
12417c478bd9Sstevel@tonic-gate  *
12427c478bd9Sstevel@tonic-gate  * Returns:	EINVAL
12437c478bd9Sstevel@tonic-gate  *		ETIMEDOUT
12447c478bd9Sstevel@tonic-gate  *		smr_slabwatier_unregister
12457c478bd9Sstevel@tonic-gate  *		(0, EINVAL, EBUSY, ENOMEM)
12467c478bd9Sstevel@tonic-gate  */
12477c478bd9Sstevel@tonic-gate static int
12487c478bd9Sstevel@tonic-gate smr_slaballoc_wait(int domid, smr_slab_t **spp)
12497c478bd9Sstevel@tonic-gate {
12507c478bd9Sstevel@tonic-gate 	struct slabwaiter	*wp;
12517c478bd9Sstevel@tonic-gate 	int			serrno = 0, serrno_unreg;
12527c478bd9Sstevel@tonic-gate 	procname_t		proc = "smr_slaballoc_wait";
12537c478bd9Sstevel@tonic-gate 
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate 	wp = &idn.slabwaiter[domid];
12567c478bd9Sstevel@tonic-gate 
12577c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&wp->w_mutex));
12587c478bd9Sstevel@tonic-gate 
12597c478bd9Sstevel@tonic-gate 	mutex_enter(&wp->w_mutex);
12607c478bd9Sstevel@tonic-gate 
1261bf30efa4Smathue 	PR_SMR("%s: domain = %d, nwaiters = %d, wsp = 0x%p\n",
1262*07d06da5SSurya Prakki 	    proc, domid, wp->w_nwaiters, (void *)wp->w_sp);
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate 	if (wp->w_nwaiters <= 0) {
12657c478bd9Sstevel@tonic-gate 		/*
12667c478bd9Sstevel@tonic-gate 		 * Hmmm...no waiters registered.
12677c478bd9Sstevel@tonic-gate 		 */
1268d3d50737SRafael Vanoni 		PR_SMR("%s: domain %d, no waiters!\n", proc, domid);
12697c478bd9Sstevel@tonic-gate 		mutex_exit(&wp->w_mutex);
12707c478bd9Sstevel@tonic-gate 		return (EINVAL);
12717c478bd9Sstevel@tonic-gate 	}
12727c478bd9Sstevel@tonic-gate 	ASSERT(DSLAB_READ_HELD(domid));
12737c478bd9Sstevel@tonic-gate 	DSLAB_UNLOCK(domid);
12747c478bd9Sstevel@tonic-gate 
12757c478bd9Sstevel@tonic-gate 	if (!wp->w_done && !wp->w_closed) {
12767c478bd9Sstevel@tonic-gate 		int	rv;
12777c478bd9Sstevel@tonic-gate 
12787c478bd9Sstevel@tonic-gate 		/*
12797c478bd9Sstevel@tonic-gate 		 * Only wait if data hasn't arrived yet.
12807c478bd9Sstevel@tonic-gate 		 */
1281d3d50737SRafael Vanoni 		PR_SMR("%s: domain %d, going to sleep...\n", proc, domid);
12827c478bd9Sstevel@tonic-gate 
1283d3d50737SRafael Vanoni 		rv = cv_reltimedwait_sig(&wp->w_cv, &wp->w_mutex,
1284d3d50737SRafael Vanoni 		    IDN_SLABALLOC_WAITTIME, TR_CLOCK_TICK);
12857c478bd9Sstevel@tonic-gate 		if (rv == -1)
12867c478bd9Sstevel@tonic-gate 			serrno = ETIMEDOUT;
12877c478bd9Sstevel@tonic-gate 
12887c478bd9Sstevel@tonic-gate 		PR_SMR("%s: domain %d, awakened (reason = %s)\n",
12897c478bd9Sstevel@tonic-gate 		    proc, domid, (rv == -1) ? "TIMEOUT" : "SIGNALED");
12907c478bd9Sstevel@tonic-gate 	}
12917c478bd9Sstevel@tonic-gate 	/*
12927c478bd9Sstevel@tonic-gate 	 * We've awakened or request already filled!
12937c478bd9Sstevel@tonic-gate 	 * Unregister ourselves.
12947c478bd9Sstevel@tonic-gate 	 */
12957c478bd9Sstevel@tonic-gate 	mutex_exit(&wp->w_mutex);
12967c478bd9Sstevel@tonic-gate 
12977c478bd9Sstevel@tonic-gate 	/*
12987c478bd9Sstevel@tonic-gate 	 * Any gifts will be entered into spp.
12997c478bd9Sstevel@tonic-gate 	 */
13007c478bd9Sstevel@tonic-gate 	serrno_unreg = smr_slabwaiter_unregister(domid, spp);
13017c478bd9Sstevel@tonic-gate 
13027c478bd9Sstevel@tonic-gate 	/*
13037c478bd9Sstevel@tonic-gate 	 * Leave with reader lock on dslab_lock.
13047c478bd9Sstevel@tonic-gate 	 */
13057c478bd9Sstevel@tonic-gate 	DSLAB_LOCK_SHARED(domid);
13067c478bd9Sstevel@tonic-gate 
13077c478bd9Sstevel@tonic-gate 	if ((serrno_unreg == EBUSY) && (serrno == ETIMEDOUT))
13087c478bd9Sstevel@tonic-gate 		return (serrno);
13097c478bd9Sstevel@tonic-gate 	else
13107c478bd9Sstevel@tonic-gate 		return (serrno_unreg);
13117c478bd9Sstevel@tonic-gate }
13127c478bd9Sstevel@tonic-gate 
13137c478bd9Sstevel@tonic-gate /*
13147c478bd9Sstevel@tonic-gate  * A SMR slab was allocated on behalf of the given domain.
13157c478bd9Sstevel@tonic-gate  * Wakeup anybody that may have been waiting for the allocation.
13167c478bd9Sstevel@tonic-gate  * Note that if the domain is a remote one, i.e. master is allocating
13177c478bd9Sstevel@tonic-gate  * on behalf of a slave, it's up to the caller to transmit the
13187c478bd9Sstevel@tonic-gate  * allocation response to that domain.
13197c478bd9Sstevel@tonic-gate  * The force flag indicates that we want to install the slab for
13207c478bd9Sstevel@tonic-gate  * the given user regardless of whether there are waiters or not.
13217c478bd9Sstevel@tonic-gate  * This is used primarily in situations where a slave may have timed
13227c478bd9Sstevel@tonic-gate  * out before the response actually arrived.  In this situation we
13237c478bd9Sstevel@tonic-gate  * don't want to send slab back to the master after we went through
13247c478bd9Sstevel@tonic-gate  * the trouble of allocating one.  Master is _not_ allowed to do this
13257c478bd9Sstevel@tonic-gate  * for remote domains.
13267c478bd9Sstevel@tonic-gate  *
13277c478bd9Sstevel@tonic-gate  * Returns:	-1	Non-registered waiter or waiting area garbaged.
13287c478bd9Sstevel@tonic-gate  *		0	Successfully performed operation.
13297c478bd9Sstevel@tonic-gate  */
13307c478bd9Sstevel@tonic-gate int
13317c478bd9Sstevel@tonic-gate smr_slaballoc_put(int domid, smr_slab_t *sp, int forceflag, int serrno)
13327c478bd9Sstevel@tonic-gate {
13337c478bd9Sstevel@tonic-gate 	idn_domain_t		*dp;
13347c478bd9Sstevel@tonic-gate 	struct slabwaiter	*wp;
13357c478bd9Sstevel@tonic-gate 	procname_t		proc = "smr_slaballoc_put";
13367c478bd9Sstevel@tonic-gate 
13377c478bd9Sstevel@tonic-gate 
13387c478bd9Sstevel@tonic-gate 	dp = &idn_domain[domid];
13397c478bd9Sstevel@tonic-gate 
13407c478bd9Sstevel@tonic-gate 	ASSERT(!serrno ? DSLAB_WRITE_HELD(domid) : 1);
13417c478bd9Sstevel@tonic-gate 
13427c478bd9Sstevel@tonic-gate 	if (domid == IDN_NIL_DOMID)
13437c478bd9Sstevel@tonic-gate 		return (-1);
13447c478bd9Sstevel@tonic-gate 
13457c478bd9Sstevel@tonic-gate 	ASSERT(serrno ? (sp == NULL) : (sp != NULL));
13467c478bd9Sstevel@tonic-gate 
13477c478bd9Sstevel@tonic-gate 	wp = &idn.slabwaiter[domid];
13487c478bd9Sstevel@tonic-gate 
13497c478bd9Sstevel@tonic-gate 	mutex_enter(&wp->w_mutex);
13507c478bd9Sstevel@tonic-gate 
1351bf30efa4Smathue 	PR_SMR("%s: domain = %d, bufp = 0x%p, ebufp = 0x%p, "
1352bf30efa4Smathue 	    "(f = %d, se = %d)\n", proc, domid,
1353*07d06da5SSurya Prakki 	    (sp ? (void *)sp->sl_start : 0),
1354*07d06da5SSurya Prakki 	    (sp ? (void *)sp->sl_end : 0), forceflag, serrno);
13557c478bd9Sstevel@tonic-gate 
13567c478bd9Sstevel@tonic-gate 	if (wp->w_nwaiters <= 0) {
13577c478bd9Sstevel@tonic-gate 		/*
13587c478bd9Sstevel@tonic-gate 		 * There are no waiters!!  Must have timed out
13597c478bd9Sstevel@tonic-gate 		 * and left.  Oh well...
13607c478bd9Sstevel@tonic-gate 		 */
13617c478bd9Sstevel@tonic-gate 		PR_SMR("%s: no slaballoc waiters found for domain %d\n",
13627c478bd9Sstevel@tonic-gate 		    proc, domid);
13637c478bd9Sstevel@tonic-gate 		if (!forceflag || serrno || !sp) {
13647c478bd9Sstevel@tonic-gate 			/*
13657c478bd9Sstevel@tonic-gate 			 * No waiters and caller doesn't want to force it.
13667c478bd9Sstevel@tonic-gate 			 */
13677c478bd9Sstevel@tonic-gate 			mutex_exit(&wp->w_mutex);
13687c478bd9Sstevel@tonic-gate 			return (-1);
13697c478bd9Sstevel@tonic-gate 		}
13707c478bd9Sstevel@tonic-gate 		PR_SMR("%s: forcing slab onto domain %d\n", proc, domid);
13717c478bd9Sstevel@tonic-gate 		ASSERT(domid == idn.localid);
13727c478bd9Sstevel@tonic-gate 		ASSERT(wp->w_sp == NULL);
13737c478bd9Sstevel@tonic-gate 		wp->w_done = 0;
13747c478bd9Sstevel@tonic-gate 		/*
13757c478bd9Sstevel@tonic-gate 		 * Now we fall through and let it be added in the
13767c478bd9Sstevel@tonic-gate 		 * regular manor.
13777c478bd9Sstevel@tonic-gate 		 */
13787c478bd9Sstevel@tonic-gate 	}
13797c478bd9Sstevel@tonic-gate 	if (wp->w_done) {
13807c478bd9Sstevel@tonic-gate 		/*
13817c478bd9Sstevel@tonic-gate 		 * There's at least one waiter so there has
13827c478bd9Sstevel@tonic-gate 		 * to be a slab structure waiting for us.
13837c478bd9Sstevel@tonic-gate 		 * If everything is going smoothly, there should only
13847c478bd9Sstevel@tonic-gate 		 * be one guy coming through the path of inserting
13857c478bd9Sstevel@tonic-gate 		 * an error or good slab.  However, if a disconnect was
13867c478bd9Sstevel@tonic-gate 		 * detected, you may get several guys coming through
13877c478bd9Sstevel@tonic-gate 		 * trying to let everybody know.
13887c478bd9Sstevel@tonic-gate 		 */
13897c478bd9Sstevel@tonic-gate 		ASSERT(wp->w_serrno ?
13907c478bd9Sstevel@tonic-gate 		    (wp->w_sp == NULL) : (wp->w_sp != NULL));
13917c478bd9Sstevel@tonic-gate 
13927c478bd9Sstevel@tonic-gate 		cv_broadcast(&wp->w_cv);
13937c478bd9Sstevel@tonic-gate 		mutex_exit(&wp->w_mutex);
13947c478bd9Sstevel@tonic-gate 
13957c478bd9Sstevel@tonic-gate 		return (-1);
13967c478bd9Sstevel@tonic-gate 	}
13977c478bd9Sstevel@tonic-gate 	if (serrno != 0) {
13987c478bd9Sstevel@tonic-gate 		/*
13997c478bd9Sstevel@tonic-gate 		 * Bummer...allocation failed.  This call is simply
14007c478bd9Sstevel@tonic-gate 		 * to wake up the sleepers and let them know.
14017c478bd9Sstevel@tonic-gate 		 */
1402d3d50737SRafael Vanoni 		PR_SMR("%s: slaballoc failed for domain %d\n", proc, domid);
14037c478bd9Sstevel@tonic-gate 		wp->w_serrno = serrno;
14047c478bd9Sstevel@tonic-gate 		wp->w_done = 1;
14057c478bd9Sstevel@tonic-gate 		cv_broadcast(&wp->w_cv);
14067c478bd9Sstevel@tonic-gate 		mutex_exit(&wp->w_mutex);
14077c478bd9Sstevel@tonic-gate 
14087c478bd9Sstevel@tonic-gate 		return (0);
14097c478bd9Sstevel@tonic-gate 	}
14107c478bd9Sstevel@tonic-gate 	PR_SMR("%s: putting slab into struct (domid=%d, localid=%d)\n",
14117c478bd9Sstevel@tonic-gate 	    proc, domid, idn.localid);
14127c478bd9Sstevel@tonic-gate 	/*
14137c478bd9Sstevel@tonic-gate 	 * Prep the slab structure.
14147c478bd9Sstevel@tonic-gate 	 */
14157c478bd9Sstevel@tonic-gate 
14167c478bd9Sstevel@tonic-gate 	if (domid == idn.localid) {
14177c478bd9Sstevel@tonic-gate 		/*
14187c478bd9Sstevel@tonic-gate 		 * Allocation was indeed for me.
14197c478bd9Sstevel@tonic-gate 		 * Slab may or may not be locked when
14207c478bd9Sstevel@tonic-gate 		 * we reach.  Normally they will be locked
14217c478bd9Sstevel@tonic-gate 		 * if we're being called on behalf of a
14227c478bd9Sstevel@tonic-gate 		 * free, and not locked if on behalf of
14237c478bd9Sstevel@tonic-gate 		 * a new allocation request.
14247c478bd9Sstevel@tonic-gate 		 */
14257c478bd9Sstevel@tonic-gate 		lock_clear(&sp->sl_lock);
14267c478bd9Sstevel@tonic-gate 		smr_alloc_buflist(sp);
14277c478bd9Sstevel@tonic-gate #ifdef DEBUG
14287c478bd9Sstevel@tonic-gate 	} else {
14297c478bd9Sstevel@tonic-gate 		uint_t	rv;
14307c478bd9Sstevel@tonic-gate 		/*
14317c478bd9Sstevel@tonic-gate 		 * Slab was not allocated on my behalf.  Must be
14327c478bd9Sstevel@tonic-gate 		 * a master request on behalf of some other domain.
14337c478bd9Sstevel@tonic-gate 		 * Prep appropriately.  Slab should have been locked
14347c478bd9Sstevel@tonic-gate 		 * by smr_slab_reserve.
14357c478bd9Sstevel@tonic-gate 		 */
14367c478bd9Sstevel@tonic-gate 		rv = lock_try(&sp->sl_lock);
14377c478bd9Sstevel@tonic-gate 		ASSERT(!rv);
14387c478bd9Sstevel@tonic-gate 		ASSERT(sp->sl_domid == (short)domid);
14397c478bd9Sstevel@tonic-gate #endif /* DEBUG */
14407c478bd9Sstevel@tonic-gate 	}
14417c478bd9Sstevel@tonic-gate 
14427c478bd9Sstevel@tonic-gate 	/*
14437c478bd9Sstevel@tonic-gate 	 * Slab is ready to go.  Insert it into the domain's
14447c478bd9Sstevel@tonic-gate 	 * slab list so once we wake everybody up they'll find it.
14457c478bd9Sstevel@tonic-gate 	 * You better have write lock if you're putting treasures
14467c478bd9Sstevel@tonic-gate 	 * there.
14477c478bd9Sstevel@tonic-gate 	 */
14487c478bd9Sstevel@tonic-gate 	ASSERT(DSLAB_WRITE_HELD(domid));
14497c478bd9Sstevel@tonic-gate 
14507c478bd9Sstevel@tonic-gate 	sp->sl_next = dp->dslab;
14517c478bd9Sstevel@tonic-gate 	dp->dslab  = sp;
14527c478bd9Sstevel@tonic-gate 	dp->dnslabs++;
14537c478bd9Sstevel@tonic-gate 
14547c478bd9Sstevel@tonic-gate 	/*
14557c478bd9Sstevel@tonic-gate 	 * It's possible to fall through here without waiters.
14567c478bd9Sstevel@tonic-gate 	 * This is a case where forceflag was set.
14577c478bd9Sstevel@tonic-gate 	 */
14587c478bd9Sstevel@tonic-gate 	if (wp->w_nwaiters > 0) {
14597c478bd9Sstevel@tonic-gate 		wp->w_sp = sp;
14607c478bd9Sstevel@tonic-gate 		wp->w_serrno = serrno;
14617c478bd9Sstevel@tonic-gate 		wp->w_done = 1;
14627c478bd9Sstevel@tonic-gate 		cv_broadcast(&wp->w_cv);
14637c478bd9Sstevel@tonic-gate 	} else {
14647c478bd9Sstevel@tonic-gate 		ASSERT(forceflag);
14657c478bd9Sstevel@tonic-gate 		wp->w_sp = NULL;
14667c478bd9Sstevel@tonic-gate 		wp->w_serrno = 0;
14677c478bd9Sstevel@tonic-gate 		wp->w_done = 0;
14687c478bd9Sstevel@tonic-gate 	}
14697c478bd9Sstevel@tonic-gate 	mutex_exit(&wp->w_mutex);
14707c478bd9Sstevel@tonic-gate 
14717c478bd9Sstevel@tonic-gate 	return (0);
14727c478bd9Sstevel@tonic-gate }
14737c478bd9Sstevel@tonic-gate 
14747c478bd9Sstevel@tonic-gate /*
14757c478bd9Sstevel@tonic-gate  * Get the slab representing [bufp,ebufp] from the respective
14767c478bd9Sstevel@tonic-gate  * domain's pool if all the buffers are free.  Remove them from
14777c478bd9Sstevel@tonic-gate  * the domain's list and return it.
14787c478bd9Sstevel@tonic-gate  * If bufp == NULL, then return however many free ones you
14797c478bd9Sstevel@tonic-gate  * can find.
14807c478bd9Sstevel@tonic-gate  * List of slabs are returned locked (sl_lock).
14817c478bd9Sstevel@tonic-gate  * XXX - Need minimum limit to make sure we don't free up _all_
14827c478bd9Sstevel@tonic-gate  *	 of our slabs!  However, during a shutdown we will need
14837c478bd9Sstevel@tonic-gate  *	 method to free them all up regardless of locking.
14847c478bd9Sstevel@tonic-gate  */
14857c478bd9Sstevel@tonic-gate smr_slab_t *
14867c478bd9Sstevel@tonic-gate smr_slaballoc_get(int domid, caddr_t bufp, caddr_t ebufp)
14877c478bd9Sstevel@tonic-gate {
14887c478bd9Sstevel@tonic-gate 	idn_domain_t	*dp;
14897c478bd9Sstevel@tonic-gate 	smr_slab_t	*retsp, *sp, **psp;
14907c478bd9Sstevel@tonic-gate 	int		foundit, islocal = 0;
14917c478bd9Sstevel@tonic-gate 	int		nslabs;
14927c478bd9Sstevel@tonic-gate 	procname_t	proc = "smr_slaballoc_get";
14937c478bd9Sstevel@tonic-gate 
1494bf30efa4Smathue 	PR_SMR("%s: getting slab for domain %d [bufp=0x%p, ebufp=0x%p]\n",
1495*07d06da5SSurya Prakki 	    proc, domid, (void *)bufp, (void *)ebufp);
14967c478bd9Sstevel@tonic-gate 
14977c478bd9Sstevel@tonic-gate 	dp = &idn_domain[domid];
14987c478bd9Sstevel@tonic-gate 
14997c478bd9Sstevel@tonic-gate 	ASSERT(DSLAB_WRITE_HELD(domid));
15007c478bd9Sstevel@tonic-gate 
15017c478bd9Sstevel@tonic-gate 	if ((sp = dp->dslab) == NULL) {
1502d3d50737SRafael Vanoni 		PR_SMR("%s: oops, no slabs for domain %d\n", proc, domid);
15037c478bd9Sstevel@tonic-gate 		return (NULL);
15047c478bd9Sstevel@tonic-gate 	}
15057c478bd9Sstevel@tonic-gate 	/*
15067c478bd9Sstevel@tonic-gate 	 * If domid is myself then I'm trying to get a slab out
15077c478bd9Sstevel@tonic-gate 	 * of my local pool.  Otherwise, I'm the master and
15087c478bd9Sstevel@tonic-gate 	 * I'm trying to get the slab representative from the
15097c478bd9Sstevel@tonic-gate 	 * global pool.
15107c478bd9Sstevel@tonic-gate 	 */
15117c478bd9Sstevel@tonic-gate 	if (domid == idn.localid)
15127c478bd9Sstevel@tonic-gate 		islocal = 1;
15137c478bd9Sstevel@tonic-gate 
15147c478bd9Sstevel@tonic-gate 	if (bufp != NULL) {
15157c478bd9Sstevel@tonic-gate 		nslabs = -1;
15167c478bd9Sstevel@tonic-gate 	} else {
15177c478bd9Sstevel@tonic-gate 		nslabs = *(int *)ebufp;
15187c478bd9Sstevel@tonic-gate 		if (nslabs == 0) {
15197c478bd9Sstevel@tonic-gate 			PR_SMR("%s: requested nslabs (%d) <= 0\n",
15207c478bd9Sstevel@tonic-gate 			    proc, nslabs);
15217c478bd9Sstevel@tonic-gate 			return (NULL);
15227c478bd9Sstevel@tonic-gate 		} else if (nslabs < 0) {
15237c478bd9Sstevel@tonic-gate 			/*
15247c478bd9Sstevel@tonic-gate 			 * Caller wants them all!
15257c478bd9Sstevel@tonic-gate 			 */
15267c478bd9Sstevel@tonic-gate 			nslabs = (int)dp->dnslabs;
15277c478bd9Sstevel@tonic-gate 		}
15287c478bd9Sstevel@tonic-gate 	}
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate 	retsp = NULL;
15317c478bd9Sstevel@tonic-gate 	foundit = 0;
15327c478bd9Sstevel@tonic-gate 	for (psp = &dp->dslab; sp; sp = *psp) {
15337c478bd9Sstevel@tonic-gate 		int	isbusy;
15347c478bd9Sstevel@tonic-gate 
15357c478bd9Sstevel@tonic-gate 		if (bufp && (sp->sl_start != bufp)) {
15367c478bd9Sstevel@tonic-gate 			psp = &sp->sl_next;
15377c478bd9Sstevel@tonic-gate 			continue;
15387c478bd9Sstevel@tonic-gate 		}
15397c478bd9Sstevel@tonic-gate 
15407c478bd9Sstevel@tonic-gate 		if (bufp && (ebufp > sp->sl_end)) {
1541bf30efa4Smathue 			PR_SMR("%s: bufp/ebufp (0x%p/0x%p) "
1542*07d06da5SSurya Prakki 			    "expected (0x%p/0x%p)\n", proc, (void *)bufp,
1543*07d06da5SSurya Prakki 			    (void *)ebufp, (void *)sp->sl_start,
1544*07d06da5SSurya Prakki 			    (void *)sp->sl_end);
15457c478bd9Sstevel@tonic-gate 			ASSERT(0);
15467c478bd9Sstevel@tonic-gate 		}
15477c478bd9Sstevel@tonic-gate 		/*
15487c478bd9Sstevel@tonic-gate 		 * We found the desired slab.  Make sure
15497c478bd9Sstevel@tonic-gate 		 * it's free.
15507c478bd9Sstevel@tonic-gate 		 */
15517c478bd9Sstevel@tonic-gate 		foundit++;
15527c478bd9Sstevel@tonic-gate 		isbusy = 0;
15537c478bd9Sstevel@tonic-gate 		if (islocal) {
15547c478bd9Sstevel@tonic-gate 			int spl;
15557c478bd9Sstevel@tonic-gate 
15567c478bd9Sstevel@tonic-gate 			/*
15577c478bd9Sstevel@tonic-gate 			 * Some of the buffers in the slab
15587c478bd9Sstevel@tonic-gate 			 * are still in use.  Unlock the
15597c478bd9Sstevel@tonic-gate 			 * buffers we locked and bail out.
15607c478bd9Sstevel@tonic-gate 			 */
15617c478bd9Sstevel@tonic-gate 			spl = splhi();
15627c478bd9Sstevel@tonic-gate 			if (!lock_try(&sp->sl_lock)) {
15637c478bd9Sstevel@tonic-gate 				isbusy = 1;
15647c478bd9Sstevel@tonic-gate 				foundit--;
15657c478bd9Sstevel@tonic-gate 			} else if (sp->sl_inuse) {
15667c478bd9Sstevel@tonic-gate 				lock_clear(&sp->sl_lock);
15677c478bd9Sstevel@tonic-gate 				isbusy = 1;
15687c478bd9Sstevel@tonic-gate 				foundit--;
15697c478bd9Sstevel@tonic-gate 			}
15707c478bd9Sstevel@tonic-gate 			splx(spl);
15717c478bd9Sstevel@tonic-gate 		} else {
15727c478bd9Sstevel@tonic-gate 			/*
15737c478bd9Sstevel@tonic-gate 			 * If not local, then I'm the master getting
15747c478bd9Sstevel@tonic-gate 			 * a slab from one of the slaves.  In this case,
15757c478bd9Sstevel@tonic-gate 			 * their slab structs will always be locked.
15767c478bd9Sstevel@tonic-gate 			 */
15777c478bd9Sstevel@tonic-gate 			ASSERT(!lock_try(&sp->sl_lock));
15787c478bd9Sstevel@tonic-gate 		}
15797c478bd9Sstevel@tonic-gate 		if (!isbusy) {
15807c478bd9Sstevel@tonic-gate 			/*
15817c478bd9Sstevel@tonic-gate 			 * Delete the entry from the list and slap
15827c478bd9Sstevel@tonic-gate 			 * it onto our return list.
15837c478bd9Sstevel@tonic-gate 			 */
15847c478bd9Sstevel@tonic-gate 			*psp = sp->sl_next;
15857c478bd9Sstevel@tonic-gate 			sp->sl_next = retsp;
15867c478bd9Sstevel@tonic-gate 			retsp = sp;
15877c478bd9Sstevel@tonic-gate 		} else {
15887c478bd9Sstevel@tonic-gate 			psp = &sp->sl_next;
15897c478bd9Sstevel@tonic-gate 		}
15907c478bd9Sstevel@tonic-gate 		/*
15917c478bd9Sstevel@tonic-gate 		 * If bufp == NULL (alternate interface) and we haven't
15927c478bd9Sstevel@tonic-gate 		 * found the desired number of slabs yet, keep looking.
15937c478bd9Sstevel@tonic-gate 		 */
15947c478bd9Sstevel@tonic-gate 		if (bufp || (foundit == nslabs))
15957c478bd9Sstevel@tonic-gate 			break;
15967c478bd9Sstevel@tonic-gate 	}
15977c478bd9Sstevel@tonic-gate 	dp->dnslabs -= (short)foundit;
15987c478bd9Sstevel@tonic-gate 
15997c478bd9Sstevel@tonic-gate 	if (foundit) {
1600d3d50737SRafael Vanoni 		PR_SMR("%s: found %d free slabs (domid = %d)\n", proc, foundit,
1601d3d50737SRafael Vanoni 		    domid);
16027c478bd9Sstevel@tonic-gate 	} else {
1603d3d50737SRafael Vanoni 		PR_SMR("%s: no free slabs found (domid = %d)\n", proc, domid);
16047c478bd9Sstevel@tonic-gate 	}
16057c478bd9Sstevel@tonic-gate 
16067c478bd9Sstevel@tonic-gate 	/*
16077c478bd9Sstevel@tonic-gate 	 * If this is the alternate interface, need to return
16087c478bd9Sstevel@tonic-gate 	 * the number of slabs found in the ebufp parameter.
16097c478bd9Sstevel@tonic-gate 	 */
16107c478bd9Sstevel@tonic-gate 	if (bufp == NULL)
16117c478bd9Sstevel@tonic-gate 		*(int *)ebufp = foundit;
16127c478bd9Sstevel@tonic-gate 
16137c478bd9Sstevel@tonic-gate 	return (retsp);
16147c478bd9Sstevel@tonic-gate }
16157c478bd9Sstevel@tonic-gate 
16167c478bd9Sstevel@tonic-gate /*
16177c478bd9Sstevel@tonic-gate  * Wrapper to hide alternate interface to smr_slaballoc_get()
16187c478bd9Sstevel@tonic-gate  */
16197c478bd9Sstevel@tonic-gate smr_slab_t *
16207c478bd9Sstevel@tonic-gate smr_slaballoc_get_n(int domid, int *nslabs)
16217c478bd9Sstevel@tonic-gate {
16227c478bd9Sstevel@tonic-gate 	smr_slab_t	*sp;
16237c478bd9Sstevel@tonic-gate 
16247c478bd9Sstevel@tonic-gate 	ASSERT(DSLAB_WRITE_HELD(domid));
16257c478bd9Sstevel@tonic-gate 
16267c478bd9Sstevel@tonic-gate 	sp = smr_slaballoc_get(domid, NULL, (caddr_t)nslabs);
16277c478bd9Sstevel@tonic-gate 
16287c478bd9Sstevel@tonic-gate 	return (sp);
16297c478bd9Sstevel@tonic-gate }
16307c478bd9Sstevel@tonic-gate 
16317c478bd9Sstevel@tonic-gate /*
16327c478bd9Sstevel@tonic-gate  * Only called by master.  Initialize slab pool based on local SMR.
16337c478bd9Sstevel@tonic-gate  * Returns number of slabs initialized.
16347c478bd9Sstevel@tonic-gate  * reserved_size = Length of area at the front of the NWR portion
16357c478bd9Sstevel@tonic-gate  *		   of the SMR to reserve and not make available for
16367c478bd9Sstevel@tonic-gate  *		   slab allocations.  Must be a IDN_SMR_BUFSIZE multiple.
16377c478bd9Sstevel@tonic-gate  * reserved_area = Pointer to reserved area, if any.
16387c478bd9Sstevel@tonic-gate  */
16397c478bd9Sstevel@tonic-gate int
16407c478bd9Sstevel@tonic-gate smr_slabpool_init(size_t reserved_size, caddr_t *reserved_area)
16417c478bd9Sstevel@tonic-gate {
16427c478bd9Sstevel@tonic-gate 	size_t			nwr_available;
16437c478bd9Sstevel@tonic-gate 	int			minperpool, ntotslabs, nxslabs, nslabs;
16447c478bd9Sstevel@tonic-gate 	register int		p, pp;
16457c478bd9Sstevel@tonic-gate 	register caddr_t	bufp;
16467c478bd9Sstevel@tonic-gate 	register smr_slab_t	*sp;
16477c478bd9Sstevel@tonic-gate 
16487c478bd9Sstevel@tonic-gate 	ASSERT(IDN_GLOCK_IS_EXCL());
16497c478bd9Sstevel@tonic-gate 	ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID);
16507c478bd9Sstevel@tonic-gate 
16517c478bd9Sstevel@tonic-gate 	*reserved_area = NULL;
16527c478bd9Sstevel@tonic-gate 
16537c478bd9Sstevel@tonic-gate 	nwr_available = MB2B(IDN_NWR_SIZE) - reserved_size;
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate 	if ((idn.localid != IDN_GET_MASTERID()) ||
16567c478bd9Sstevel@tonic-gate 	    (nwr_available < IDN_SLAB_SIZE) ||
16577c478bd9Sstevel@tonic-gate 	    (idn.slabpool != NULL) ||
16587c478bd9Sstevel@tonic-gate 	    ((reserved_size != 0) && (reserved_size & (IDN_SMR_BUFSIZE-1)))) {
16597c478bd9Sstevel@tonic-gate 		return (-1);
16607c478bd9Sstevel@tonic-gate 	}
16617c478bd9Sstevel@tonic-gate 
16627c478bd9Sstevel@tonic-gate 	idn.slabpool = GETSTRUCT(struct slabpool, 1);
16637c478bd9Sstevel@tonic-gate 	idn.slabpool->ntotslabs = ntotslabs = nwr_available / IDN_SLAB_SIZE;
16647c478bd9Sstevel@tonic-gate 	ASSERT(ntotslabs > 0);
16657c478bd9Sstevel@tonic-gate 	minperpool = (ntotslabs < IDN_SLAB_MINPERPOOL) ?
16667c478bd9Sstevel@tonic-gate 	    1 : IDN_SLAB_MINPERPOOL;
16677c478bd9Sstevel@tonic-gate 	idn.slabpool->npools = (ntotslabs + (minperpool - 1)) / minperpool;
16687c478bd9Sstevel@tonic-gate 
16697c478bd9Sstevel@tonic-gate 	if ((idn.slabpool->npools & 1) == 0) {
16707c478bd9Sstevel@tonic-gate 		/*
16717c478bd9Sstevel@tonic-gate 		 * npools needs to be odd for hashing algorithm.
16727c478bd9Sstevel@tonic-gate 		 */
16737c478bd9Sstevel@tonic-gate 		idn.slabpool->npools++;
16747c478bd9Sstevel@tonic-gate 	}
16757c478bd9Sstevel@tonic-gate 	ASSERT(idn.slabpool->npools > 0);
16767c478bd9Sstevel@tonic-gate 	minperpool = (ntotslabs < idn.slabpool->npools) ?
16777c478bd9Sstevel@tonic-gate 	    1 : (ntotslabs / idn.slabpool->npools);
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate 	/*
16807c478bd9Sstevel@tonic-gate 	 * Calculate the number of extra slabs that will need to
16817c478bd9Sstevel@tonic-gate 	 * be alloted to the pools.  This number will be less than
16827c478bd9Sstevel@tonic-gate 	 * npools.  Only one extra slab is allocated to each pool
16837c478bd9Sstevel@tonic-gate 	 * until we have assigned all the extra slabs.
16847c478bd9Sstevel@tonic-gate 	 */
16857c478bd9Sstevel@tonic-gate 	if (ntotslabs > (idn.slabpool->npools * minperpool))
16867c478bd9Sstevel@tonic-gate 		nxslabs = ntotslabs - (idn.slabpool->npools * minperpool);
16877c478bd9Sstevel@tonic-gate 	else
16887c478bd9Sstevel@tonic-gate 		nxslabs = 0;
16897c478bd9Sstevel@tonic-gate 	ASSERT((nxslabs >= 0) && (nxslabs < idn.slabpool->npools));
16907c478bd9Sstevel@tonic-gate 
16917c478bd9Sstevel@tonic-gate 	idn.slabpool->pool = GETSTRUCT(struct smr_slabtbl,
16927c478bd9Sstevel@tonic-gate 	    idn.slabpool->npools);
16937c478bd9Sstevel@tonic-gate 	sp = GETSTRUCT(smr_slab_t, idn.slabpool->ntotslabs);
16947c478bd9Sstevel@tonic-gate 
16957c478bd9Sstevel@tonic-gate 	idn.slabpool->savep = sp;
16967c478bd9Sstevel@tonic-gate 	bufp = idn.smr.vaddr + reserved_size;
16977c478bd9Sstevel@tonic-gate 
16987c478bd9Sstevel@tonic-gate 	for (p = nslabs = 0;
16997c478bd9Sstevel@tonic-gate 	    (p < idn.slabpool->npools) && (ntotslabs > 0);
17007c478bd9Sstevel@tonic-gate 	    p++, ntotslabs -= nslabs) {
17017c478bd9Sstevel@tonic-gate 
17027c478bd9Sstevel@tonic-gate 		nslabs = (ntotslabs < minperpool) ? ntotslabs : minperpool;
17037c478bd9Sstevel@tonic-gate 		if (nxslabs > 0) {
17047c478bd9Sstevel@tonic-gate 			nslabs++;
17057c478bd9Sstevel@tonic-gate 			nxslabs--;
17067c478bd9Sstevel@tonic-gate 		}
17077c478bd9Sstevel@tonic-gate 		idn.slabpool->pool[p].sarray = sp;
17087c478bd9Sstevel@tonic-gate 		for (pp = 0; pp < nslabs; pp++) {
17097c478bd9Sstevel@tonic-gate 
17107c478bd9Sstevel@tonic-gate 			sp->sl_next  = NULL;
17117c478bd9Sstevel@tonic-gate 			sp->sl_start = bufp;
17127c478bd9Sstevel@tonic-gate 			sp->sl_end   = bufp = sp->sl_start + IDN_SLAB_SIZE;
17137c478bd9Sstevel@tonic-gate 			sp->sl_lock  = 0;
17147c478bd9Sstevel@tonic-gate 			sp->sl_domid = (short)IDN_NIL_DOMID;
17157c478bd9Sstevel@tonic-gate 
17167c478bd9Sstevel@tonic-gate 			sp++;
17177c478bd9Sstevel@tonic-gate 		}
17187c478bd9Sstevel@tonic-gate 		idn.slabpool->pool[p].nfree   = nslabs;
17197c478bd9Sstevel@tonic-gate 		idn.slabpool->pool[p].nslabs  = nslabs;
17207c478bd9Sstevel@tonic-gate 	}
17217c478bd9Sstevel@tonic-gate 	ASSERT((ntotslabs == 0) && (nxslabs == 0));
17227c478bd9Sstevel@tonic-gate 	/*
17237c478bd9Sstevel@tonic-gate 	 * We should be at the end of the SMR at this point.
17247c478bd9Sstevel@tonic-gate 	 */
1725d3d50737SRafael Vanoni 	ASSERT(bufp == (idn.smr.vaddr + reserved_size
17267c478bd9Sstevel@tonic-gate 	    + (idn.slabpool->ntotslabs * IDN_SLAB_SIZE)));
17277c478bd9Sstevel@tonic-gate 
17287c478bd9Sstevel@tonic-gate 	if (reserved_size != 0)
17297c478bd9Sstevel@tonic-gate 		*reserved_area = idn.smr.vaddr;
17307c478bd9Sstevel@tonic-gate 
17317c478bd9Sstevel@tonic-gate 	return (0);
17327c478bd9Sstevel@tonic-gate }
17337c478bd9Sstevel@tonic-gate 
17347c478bd9Sstevel@tonic-gate void
17357c478bd9Sstevel@tonic-gate smr_slabpool_deinit()
17367c478bd9Sstevel@tonic-gate {
17377c478bd9Sstevel@tonic-gate 	if (idn.slabpool == NULL)
17387c478bd9Sstevel@tonic-gate 		return;
17397c478bd9Sstevel@tonic-gate 
17407c478bd9Sstevel@tonic-gate 	FREESTRUCT(idn.slabpool->savep, smr_slab_t, idn.slabpool->ntotslabs);
17417c478bd9Sstevel@tonic-gate 	FREESTRUCT(idn.slabpool->pool, struct smr_slabtbl,
17427c478bd9Sstevel@tonic-gate 	    idn.slabpool->npools);
17437c478bd9Sstevel@tonic-gate 	FREESTRUCT(idn.slabpool, struct slabpool, 1);
17447c478bd9Sstevel@tonic-gate 
17457c478bd9Sstevel@tonic-gate 	idn.slabpool = NULL;
17467c478bd9Sstevel@tonic-gate }
17477c478bd9Sstevel@tonic-gate 
17487c478bd9Sstevel@tonic-gate void
17497c478bd9Sstevel@tonic-gate smr_alloc_buflist(smr_slab_t *sp)
17507c478bd9Sstevel@tonic-gate {
17517c478bd9Sstevel@tonic-gate 	int		n, nbufs;
17527c478bd9Sstevel@tonic-gate 	caddr_t		sbufp;
17537c478bd9Sstevel@tonic-gate 	smr_slabbuf_t	*hp, *bp;
17547c478bd9Sstevel@tonic-gate 
17557c478bd9Sstevel@tonic-gate 	if (sp->sl_head)
17567c478bd9Sstevel@tonic-gate 		return;
17577c478bd9Sstevel@tonic-gate 
17587c478bd9Sstevel@tonic-gate 	nbufs = (sp->sl_end - sp->sl_start) / IDN_SMR_BUFSIZE;
17597c478bd9Sstevel@tonic-gate 	ASSERT(nbufs > 0);
17607c478bd9Sstevel@tonic-gate 	if (nbufs <= 0) {
17617c478bd9Sstevel@tonic-gate 		sp->sl_head = sp->sl_free = sp->sl_inuse = NULL;
17627c478bd9Sstevel@tonic-gate 		return;
17637c478bd9Sstevel@tonic-gate 	}
17647c478bd9Sstevel@tonic-gate 
17657c478bd9Sstevel@tonic-gate 	hp = GETSTRUCT(smr_slabbuf_t, nbufs);
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate 	sbufp = sp->sl_start;
17687c478bd9Sstevel@tonic-gate 	for (n = 0, bp = hp; n < nbufs; bp++, n++) {
17697c478bd9Sstevel@tonic-gate 		bp->sb_bufp = sbufp;
17707c478bd9Sstevel@tonic-gate 		bp->sb_domid = IDN_NIL_DOMID;
17717c478bd9Sstevel@tonic-gate 		bp->sb_next = bp + 1;
17727c478bd9Sstevel@tonic-gate 		sbufp += IDN_SMR_BUFSIZE;
17737c478bd9Sstevel@tonic-gate 	}
17747c478bd9Sstevel@tonic-gate 	(--bp)->sb_next = NULL;
17757c478bd9Sstevel@tonic-gate 
17767c478bd9Sstevel@tonic-gate 	sp->sl_head = sp->sl_free = hp;
17777c478bd9Sstevel@tonic-gate 	sp->sl_inuse = NULL;
17787c478bd9Sstevel@tonic-gate }
17797c478bd9Sstevel@tonic-gate 
17807c478bd9Sstevel@tonic-gate void
17817c478bd9Sstevel@tonic-gate smr_free_buflist(smr_slab_t *sp)
17827c478bd9Sstevel@tonic-gate {
17837c478bd9Sstevel@tonic-gate 	int	nbufs;
17847c478bd9Sstevel@tonic-gate 
17857c478bd9Sstevel@tonic-gate 	if (sp->sl_head == NULL)
17867c478bd9Sstevel@tonic-gate 		return;
17877c478bd9Sstevel@tonic-gate 
17887c478bd9Sstevel@tonic-gate 	nbufs = (sp->sl_end - sp->sl_start) / IDN_SMR_BUFSIZE;
17897c478bd9Sstevel@tonic-gate 
17907c478bd9Sstevel@tonic-gate 	FREESTRUCT(sp->sl_head, smr_slabbuf_t, nbufs);
17917c478bd9Sstevel@tonic-gate 
17927c478bd9Sstevel@tonic-gate 	sp->sl_head = sp->sl_free = sp->sl_inuse = NULL;
17937c478bd9Sstevel@tonic-gate }
17947c478bd9Sstevel@tonic-gate 
17957c478bd9Sstevel@tonic-gate /*
17967c478bd9Sstevel@tonic-gate  * Returns:	0 Successfully located a slab.
17977c478bd9Sstevel@tonic-gate  *	       -1 Failure.
17987c478bd9Sstevel@tonic-gate  */
17997c478bd9Sstevel@tonic-gate static smr_slab_t *
18007c478bd9Sstevel@tonic-gate smr_slab_reserve(int domid)
18017c478bd9Sstevel@tonic-gate {
18027c478bd9Sstevel@tonic-gate 	register int		p, nextp, s, nexts;
18037c478bd9Sstevel@tonic-gate 	register smr_slab_t	*spa;
18047c478bd9Sstevel@tonic-gate 	int			startp, starts;
18057c478bd9Sstevel@tonic-gate 	int			foundone = 0;
18067c478bd9Sstevel@tonic-gate 	int			spl;
18077c478bd9Sstevel@tonic-gate 	procname_t		proc = "smr_slab_reserve";
18087c478bd9Sstevel@tonic-gate 
18097c478bd9Sstevel@tonic-gate 	p = startp = SMR_SLABPOOL_HASH(domid);
18107c478bd9Sstevel@tonic-gate 	nextp = -1;
18117c478bd9Sstevel@tonic-gate 
18127c478bd9Sstevel@tonic-gate 	spl = splhi();
18137c478bd9Sstevel@tonic-gate 	while ((nextp != startp) && !foundone) {
18147c478bd9Sstevel@tonic-gate 
18157c478bd9Sstevel@tonic-gate 		s = starts = SMR_SLAB_HASH(p, domid);
18167c478bd9Sstevel@tonic-gate 		nexts = -1;
18177c478bd9Sstevel@tonic-gate 		spa = &(idn.slabpool->pool[p].sarray[0]);
18187c478bd9Sstevel@tonic-gate 
18197c478bd9Sstevel@tonic-gate 		while ((nexts != starts) && !foundone) {
18207c478bd9Sstevel@tonic-gate 			if (lock_try(&spa[s].sl_lock)) {
18217c478bd9Sstevel@tonic-gate 				foundone = 1;
18227c478bd9Sstevel@tonic-gate 				break;
18237c478bd9Sstevel@tonic-gate 			}
18247c478bd9Sstevel@tonic-gate 			nexts = SMR_SLAB_HASHSTEP(p, s);
18257c478bd9Sstevel@tonic-gate 			s = nexts;
18267c478bd9Sstevel@tonic-gate 		}
18277c478bd9Sstevel@tonic-gate 		if (foundone)
18287c478bd9Sstevel@tonic-gate 			break;
18297c478bd9Sstevel@tonic-gate 		nextp = SMR_SLABPOOL_HASHSTEP(p);
18307c478bd9Sstevel@tonic-gate 		p = nextp;
18317c478bd9Sstevel@tonic-gate 	}
18327c478bd9Sstevel@tonic-gate 	splx(spl);
18337c478bd9Sstevel@tonic-gate 
18347c478bd9Sstevel@tonic-gate 	if (foundone) {
18357c478bd9Sstevel@tonic-gate 		ASSERT((&spa[s] >= idn.slabpool->savep) &&
18367c478bd9Sstevel@tonic-gate 		    (&spa[s] < (idn.slabpool->savep +
18377c478bd9Sstevel@tonic-gate 		    idn.slabpool->ntotslabs)));
18387c478bd9Sstevel@tonic-gate 
18397c478bd9Sstevel@tonic-gate 		spa[s].sl_domid = (short)domid;
18407c478bd9Sstevel@tonic-gate 
18417c478bd9Sstevel@tonic-gate 		ATOMIC_DEC(idn.slabpool->pool[p].nfree);
18427c478bd9Sstevel@tonic-gate 
18437c478bd9Sstevel@tonic-gate 		if (domid == idn.localid) {
18447c478bd9Sstevel@tonic-gate 			smr_slab_t	*nsp;
18457c478bd9Sstevel@tonic-gate 			/*
18467c478bd9Sstevel@tonic-gate 			 * Caller is actually reserving a slab for
18477c478bd9Sstevel@tonic-gate 			 * themself which means they'll need the full
18487c478bd9Sstevel@tonic-gate 			 * slab structure to represent all of the I/O
18497c478bd9Sstevel@tonic-gate 			 * buffers.  The "spa" is just a representative
18507c478bd9Sstevel@tonic-gate 			 * and doesn't contain the space to manage the
18517c478bd9Sstevel@tonic-gate 			 * individual buffers.  Need to alloc a full-size
18527c478bd9Sstevel@tonic-gate 			 * struct.
18537c478bd9Sstevel@tonic-gate 			 * Note that this results in the returning
18547c478bd9Sstevel@tonic-gate 			 * smr_slab_t structure being unlocked.
18557c478bd9Sstevel@tonic-gate 			 */
18567c478bd9Sstevel@tonic-gate 			ASSERT(idn.localid == IDN_GET_MASTERID());
18577c478bd9Sstevel@tonic-gate 			nsp = GETSTRUCT(smr_slab_t, 1);
18587c478bd9Sstevel@tonic-gate 			nsp->sl_start = spa[s].sl_start;
18597c478bd9Sstevel@tonic-gate 			nsp->sl_end   = spa[s].sl_end;
18607c478bd9Sstevel@tonic-gate 			smr_alloc_buflist(nsp);
18617c478bd9Sstevel@tonic-gate 			spa = nsp;
18627c478bd9Sstevel@tonic-gate 			PR_SMR("%s: allocated full slab struct for domain %d\n",
18637c478bd9Sstevel@tonic-gate 			    proc, domid);
18647c478bd9Sstevel@tonic-gate 		} else {
18657c478bd9Sstevel@tonic-gate 			/*
18667c478bd9Sstevel@tonic-gate 			 * Slab structure gets returned locked.
18677c478bd9Sstevel@tonic-gate 			 */
18687c478bd9Sstevel@tonic-gate 			spa += s;
18697c478bd9Sstevel@tonic-gate 		}
18707c478bd9Sstevel@tonic-gate 
1871bf30efa4Smathue 		PR_SMR("%s: allocated slab 0x%p (start=0x%p, size=%lu) for "
1872*07d06da5SSurya Prakki 		    "domain %d\n", proc, (void *)spa, (void *)spa->sl_start,
18737c478bd9Sstevel@tonic-gate 		    spa->sl_end - spa->sl_start, domid);
18747c478bd9Sstevel@tonic-gate 	} else {
18757c478bd9Sstevel@tonic-gate 		PR_SMR("%s: FAILED to allocate for domain %d\n",
18767c478bd9Sstevel@tonic-gate 		    proc, domid);
18777c478bd9Sstevel@tonic-gate 		spa = NULL;
18787c478bd9Sstevel@tonic-gate 	}
18797c478bd9Sstevel@tonic-gate 
18807c478bd9Sstevel@tonic-gate 	return (spa);
18817c478bd9Sstevel@tonic-gate }
18827c478bd9Sstevel@tonic-gate 
18837c478bd9Sstevel@tonic-gate static void
18847c478bd9Sstevel@tonic-gate smr_slab_unreserve(int domid, smr_slab_t *sp)
18857c478bd9Sstevel@tonic-gate {
18867c478bd9Sstevel@tonic-gate 	register int		p, nextp, s, nexts;
18877c478bd9Sstevel@tonic-gate 	register smr_slab_t	*spa;
18887c478bd9Sstevel@tonic-gate 	int			foundit = 0;
18897c478bd9Sstevel@tonic-gate 	int			startp, starts;
18907c478bd9Sstevel@tonic-gate 	caddr_t			bufp;
18917c478bd9Sstevel@tonic-gate 	procname_t		proc = "smr_slab_unreserve";
18927c478bd9Sstevel@tonic-gate 
18937c478bd9Sstevel@tonic-gate 	bufp = sp->sl_start;
18947c478bd9Sstevel@tonic-gate 	p = startp = SMR_SLABPOOL_HASH(domid);
18957c478bd9Sstevel@tonic-gate 	nextp = -1;
18967c478bd9Sstevel@tonic-gate 
18977c478bd9Sstevel@tonic-gate 	while ((nextp != startp) && !foundit) {
18987c478bd9Sstevel@tonic-gate 
18997c478bd9Sstevel@tonic-gate 		s = starts = SMR_SLAB_HASH(p, domid);
19007c478bd9Sstevel@tonic-gate 		nexts = -1;
19017c478bd9Sstevel@tonic-gate 		spa = &(idn.slabpool->pool[p].sarray[0]);
19027c478bd9Sstevel@tonic-gate 
19037c478bd9Sstevel@tonic-gate 		while ((nexts != starts) && !foundit) {
19047c478bd9Sstevel@tonic-gate 			if (spa[s].sl_start == bufp) {
19057c478bd9Sstevel@tonic-gate 				foundit = 1;
19067c478bd9Sstevel@tonic-gate 				break;
19077c478bd9Sstevel@tonic-gate 			}
19087c478bd9Sstevel@tonic-gate 			nexts = SMR_SLAB_HASHSTEP(p, s);
19097c478bd9Sstevel@tonic-gate 			s = nexts;
19107c478bd9Sstevel@tonic-gate 		}
19117c478bd9Sstevel@tonic-gate 		if (foundit)
19127c478bd9Sstevel@tonic-gate 			break;
19137c478bd9Sstevel@tonic-gate 		nextp = SMR_SLABPOOL_HASHSTEP(p);
19147c478bd9Sstevel@tonic-gate 		p = nextp;
19157c478bd9Sstevel@tonic-gate 	}
19167c478bd9Sstevel@tonic-gate 	if (foundit) {
19177c478bd9Sstevel@tonic-gate 		ASSERT((&spa[s] >= idn.slabpool->savep) &&
19187c478bd9Sstevel@tonic-gate 		    (&spa[s] < (idn.slabpool->savep +
19197c478bd9Sstevel@tonic-gate 		    idn.slabpool->ntotslabs)));
19207c478bd9Sstevel@tonic-gate 		ASSERT(!lock_try(&spa[s].sl_lock));
19217c478bd9Sstevel@tonic-gate 		ASSERT(spa[s].sl_domid == (short)domid);
19227c478bd9Sstevel@tonic-gate 
19237c478bd9Sstevel@tonic-gate 		spa[s].sl_next = NULL;
19247c478bd9Sstevel@tonic-gate 		spa[s].sl_domid = (short)IDN_NIL_DOMID;
19257c478bd9Sstevel@tonic-gate 		lock_clear(&spa[s].sl_lock);
19267c478bd9Sstevel@tonic-gate 
19277c478bd9Sstevel@tonic-gate 		ATOMIC_INC(idn.slabpool->pool[p].nfree);
19287c478bd9Sstevel@tonic-gate 
1929bf30efa4Smathue 		PR_SMR("%s: freed (bufp=0x%p) for domain %d\n",
1930*07d06da5SSurya Prakki 		    proc, (void *)bufp, domid);
19317c478bd9Sstevel@tonic-gate 
19327c478bd9Sstevel@tonic-gate 		if (domid == idn.localid) {
19337c478bd9Sstevel@tonic-gate 			/*
19347c478bd9Sstevel@tonic-gate 			 * Caller is actually unreserving a slab of their
19357c478bd9Sstevel@tonic-gate 			 * own.  Note that only the master calls this
19367c478bd9Sstevel@tonic-gate 			 * routine.  Since the master's local slab
19377c478bd9Sstevel@tonic-gate 			 * structures do not get entered into the global
19387c478bd9Sstevel@tonic-gate 			 * "representative" pool, we need to free up the
19397c478bd9Sstevel@tonic-gate 			 * data structure that was passed in.
19407c478bd9Sstevel@tonic-gate 			 */
19417c478bd9Sstevel@tonic-gate 			ASSERT(idn.localid == IDN_GET_MASTERID());
19427c478bd9Sstevel@tonic-gate 			ASSERT(sp != &spa[s]);
19437c478bd9Sstevel@tonic-gate 
19447c478bd9Sstevel@tonic-gate 			smr_free_buflist(sp);
19457c478bd9Sstevel@tonic-gate 			FREESTRUCT(sp, smr_slab_t, 1);
19467c478bd9Sstevel@tonic-gate 		} else {
19477c478bd9Sstevel@tonic-gate 			ASSERT(sp == &spa[s]);
19487c478bd9Sstevel@tonic-gate 		}
19497c478bd9Sstevel@tonic-gate 	} else {
19507c478bd9Sstevel@tonic-gate 		/*
19517c478bd9Sstevel@tonic-gate 		 * Couldn't find slab entry for given buf!
19527c478bd9Sstevel@tonic-gate 		 */
1953bf30efa4Smathue 		PR_SMR("%s: FAILED to free (bufp=0x%p) for domain %d\n",
1954*07d06da5SSurya Prakki 		    proc, (void *)bufp, domid);
19557c478bd9Sstevel@tonic-gate 	}
19567c478bd9Sstevel@tonic-gate }
19577c478bd9Sstevel@tonic-gate 
19587c478bd9Sstevel@tonic-gate /*
19597c478bd9Sstevel@tonic-gate  * The Reap Protocol:
19607c478bd9Sstevel@tonic-gate  *	master				   slave
19617c478bd9Sstevel@tonic-gate  *	------				   -----
19627c478bd9Sstevel@tonic-gate  *	smr_slab_reap_global
19637c478bd9Sstevel@tonic-gate  *	- idn_broadcast_cmd(SLABREAP) ->   idn_recv_cmd(SLABREAP)
19647c478bd9Sstevel@tonic-gate  *	  . idn_local_cmd(SLABREAP)        - idn_recv_slabreap_req
19657c478bd9Sstevel@tonic-gate  *	    - smr_slab_reap	             . smr_slab_reap
19667c478bd9Sstevel@tonic-gate  *	      . smr_slaballoc_get_n            - smr_slaballoc_get_n
19677c478bd9Sstevel@tonic-gate  *	      . smr_slab_free		       - smr_slab_free
19687c478bd9Sstevel@tonic-gate  *		- smr_slab_free_local		 . smr_slab_free_remote
19697c478bd9Sstevel@tonic-gate  *		  . smr_slab_unreserve
19707c478bd9Sstevel@tonic-gate  *				      <-	   - idn_send_cmd(SLABFREE)
19717c478bd9Sstevel@tonic-gate  *	idn_recv_cmd(SLABFREE)
19727c478bd9Sstevel@tonic-gate  *	- idn_recv_slabfree_req
19737c478bd9Sstevel@tonic-gate  *	  . smr_slaballoc_get
19747c478bd9Sstevel@tonic-gate  *	  . smr_slab_free
19757c478bd9Sstevel@tonic-gate  *	    - smr_slab_free_local
19767c478bd9Sstevel@tonic-gate  *	      . smr_slab_unreserve
19777c478bd9Sstevel@tonic-gate  *        . idn_send_slabfree_resp    ->   idn_recv_cmd(SLABFREE | ack)
19787c478bd9Sstevel@tonic-gate  *					   - idn_recv_slabfree_resp
19797c478bd9Sstevel@tonic-gate  *
19807c478bd9Sstevel@tonic-gate  *	idn_recv_cmd(SLABREAP | ack)  <-     . idn_send_slabreap_resp
19817c478bd9Sstevel@tonic-gate  *	- idn_recv_slabreap_resp	   DONE
19827c478bd9Sstevel@tonic-gate  *	DONE
19837c478bd9Sstevel@tonic-gate  *
19847c478bd9Sstevel@tonic-gate  * Check available slabs and if we're below the threshold, kick
19857c478bd9Sstevel@tonic-gate  * off reaping to all remote domains.  There is no guarantee remote
19867c478bd9Sstevel@tonic-gate  * domains will be able to free up any.
19877c478bd9Sstevel@tonic-gate  */
19887c478bd9Sstevel@tonic-gate static void
19897c478bd9Sstevel@tonic-gate smr_slab_reap_global()
19907c478bd9Sstevel@tonic-gate {
19917c478bd9Sstevel@tonic-gate 	register int	p, npools;
19927c478bd9Sstevel@tonic-gate 	register int	total_free = 0;
19937c478bd9Sstevel@tonic-gate 	register struct smr_slabtbl	*tblp;
19947c478bd9Sstevel@tonic-gate 	static clock_t	reap_last = 0;
19957c478bd9Sstevel@tonic-gate 	procname_t	proc = "smr_slab_reap_global";
1996d3d50737SRafael Vanoni 	clock_t		now;
19977c478bd9Sstevel@tonic-gate 
19987c478bd9Sstevel@tonic-gate 	ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID);
19997c478bd9Sstevel@tonic-gate 
20007c478bd9Sstevel@tonic-gate 	DSLAB_LOCK_SHARED(idn.localid);
20017c478bd9Sstevel@tonic-gate 	if (idn_domain[idn.localid].dslab_state != DSLAB_STATE_LOCAL) {
20027c478bd9Sstevel@tonic-gate 		PR_SMR("%s: only allowed by master (%d)\n",
20037c478bd9Sstevel@tonic-gate 		    proc, IDN_GET_MASTERID());
20047c478bd9Sstevel@tonic-gate 		DSLAB_UNLOCK(idn.localid);
20057c478bd9Sstevel@tonic-gate 		return;
20067c478bd9Sstevel@tonic-gate 	}
20077c478bd9Sstevel@tonic-gate 	DSLAB_UNLOCK(idn.localid);
20087c478bd9Sstevel@tonic-gate 
2009d3d50737SRafael Vanoni 	now = ddi_get_lbolt();
2010d3d50737SRafael Vanoni 	if ((now > 0) && (now > reap_last) &&
2011d3d50737SRafael Vanoni 	    ((now - reap_last) < IDN_REAP_INTERVAL))
20127c478bd9Sstevel@tonic-gate 		return;
20137c478bd9Sstevel@tonic-gate 
2014d3d50737SRafael Vanoni 	reap_last = now;
20157c478bd9Sstevel@tonic-gate 
20167c478bd9Sstevel@tonic-gate 	ASSERT(idn.slabpool);
20177c478bd9Sstevel@tonic-gate 
20187c478bd9Sstevel@tonic-gate 	npools = idn.slabpool->npools;
20197c478bd9Sstevel@tonic-gate 	tblp   = idn.slabpool->pool;
20207c478bd9Sstevel@tonic-gate 
20217c478bd9Sstevel@tonic-gate 	for (p = 0; p < npools; tblp++, p++)
20227c478bd9Sstevel@tonic-gate 		total_free += tblp->nfree;
20237c478bd9Sstevel@tonic-gate 
20247c478bd9Sstevel@tonic-gate 	if (total_free <= IDN_SLAB_THRESHOLD) {
20257c478bd9Sstevel@tonic-gate 		int	diff, reap_per_domain;
20267c478bd9Sstevel@tonic-gate 
20277c478bd9Sstevel@tonic-gate 		PR_SMR("%s: kicking off reaping "
2028bf30efa4Smathue 		    "(total_free = %d, min = %d)\n",
20297c478bd9Sstevel@tonic-gate 		    proc, total_free, IDN_SLAB_THRESHOLD);
20307c478bd9Sstevel@tonic-gate 
20317c478bd9Sstevel@tonic-gate 		diff = IDN_SLAB_THRESHOLD - total_free;
2032d3d50737SRafael Vanoni 		reap_per_domain = (diff < idn.ndomains) ?
2033d3d50737SRafael Vanoni 		    1 : (diff / idn.ndomains);
20347c478bd9Sstevel@tonic-gate 
20357c478bd9Sstevel@tonic-gate 		idn_broadcast_cmd(IDNCMD_SLABREAP, reap_per_domain, 0, 0);
20367c478bd9Sstevel@tonic-gate 	}
20377c478bd9Sstevel@tonic-gate }
20387c478bd9Sstevel@tonic-gate 
20397c478bd9Sstevel@tonic-gate void
20407c478bd9Sstevel@tonic-gate smr_slab_reap(int domid, int *nslabs)
20417c478bd9Sstevel@tonic-gate {
20427c478bd9Sstevel@tonic-gate 	register int	d;
20437c478bd9Sstevel@tonic-gate 	int		nreclaimed;
20447c478bd9Sstevel@tonic-gate 	smr_slab_t	*sp;
20457c478bd9Sstevel@tonic-gate 	domainset_t	reapset;
20467c478bd9Sstevel@tonic-gate 	procname_t	proc = "smr_slab_reap";
20477c478bd9Sstevel@tonic-gate 
20487c478bd9Sstevel@tonic-gate 	/*
20497c478bd9Sstevel@tonic-gate 	 * Should only be called on behalf of local
20507c478bd9Sstevel@tonic-gate 	 * domain.
20517c478bd9Sstevel@tonic-gate 	 */
20527c478bd9Sstevel@tonic-gate 	if (domid != idn.localid) {
20537c478bd9Sstevel@tonic-gate 		PR_SMR("%s: called by domain %d, should only be local (%d)\n",
20547c478bd9Sstevel@tonic-gate 		    proc, domid, idn.localid);
20557c478bd9Sstevel@tonic-gate 		ASSERT(0);
20567c478bd9Sstevel@tonic-gate 		return;
20577c478bd9Sstevel@tonic-gate 	}
20587c478bd9Sstevel@tonic-gate 	/*
20597c478bd9Sstevel@tonic-gate 	 * Try and reclaim some buffers so we can possibly
20607c478bd9Sstevel@tonic-gate 	 * free up some slabs.
20617c478bd9Sstevel@tonic-gate 	 */
20627c478bd9Sstevel@tonic-gate 	reapset = idn.domset.ds_connected;
20637c478bd9Sstevel@tonic-gate 
20647c478bd9Sstevel@tonic-gate 	IDN_GKSTAT_GLOBAL_EVENT(gk_reaps, gk_reap_last);
20657c478bd9Sstevel@tonic-gate 
20667c478bd9Sstevel@tonic-gate 	nreclaimed = 0;
20677c478bd9Sstevel@tonic-gate 	for (d = 0; d < MAX_DOMAINS; d++) {
20687c478bd9Sstevel@tonic-gate 		int		nr;
20697c478bd9Sstevel@tonic-gate 		idn_domain_t	*dp;
20707c478bd9Sstevel@tonic-gate 
20717c478bd9Sstevel@tonic-gate 		if (!DOMAIN_IN_SET(reapset, d))
20727c478bd9Sstevel@tonic-gate 			continue;
20737c478bd9Sstevel@tonic-gate 
20747c478bd9Sstevel@tonic-gate 		IDN_DLOCK_SHARED(d);
20757c478bd9Sstevel@tonic-gate 
20767c478bd9Sstevel@tonic-gate 		dp = &idn_domain[d];
20777c478bd9Sstevel@tonic-gate 		if ((d == idn.localid) || (dp->dcpu < 0)) {
20787c478bd9Sstevel@tonic-gate 			IDN_DUNLOCK(d);
20797c478bd9Sstevel@tonic-gate 			continue;
20807c478bd9Sstevel@tonic-gate 		}
20817c478bd9Sstevel@tonic-gate 		/*
20827c478bd9Sstevel@tonic-gate 		 * Clean up any dead I/O errors if possible.
20837c478bd9Sstevel@tonic-gate 		 */
20847c478bd9Sstevel@tonic-gate 		if (dp->dioerr > 0) {
20857c478bd9Sstevel@tonic-gate 			idn_domain_t	*ldp;
20867c478bd9Sstevel@tonic-gate 			register int	cnt;
20877c478bd9Sstevel@tonic-gate 			register smr_slabbuf_t	*bp;
20887c478bd9Sstevel@tonic-gate 			/*
20897c478bd9Sstevel@tonic-gate 			 * We need to grab the writer lock to prevent
20907c478bd9Sstevel@tonic-gate 			 * anybody from allocating buffers while we
20917c478bd9Sstevel@tonic-gate 			 * traverse the slabs outstanding.
20927c478bd9Sstevel@tonic-gate 			 */
20937c478bd9Sstevel@tonic-gate 			cnt = 0;
20947c478bd9Sstevel@tonic-gate 			ldp = &idn_domain[idn.localid];
20957c478bd9Sstevel@tonic-gate 			IDN_DLOCK_EXCL(idn.localid);
20967c478bd9Sstevel@tonic-gate 			DSLAB_LOCK_EXCL(idn.localid);
20977c478bd9Sstevel@tonic-gate 			for (sp = ldp->dslab; sp; sp = sp->sl_next)
20987c478bd9Sstevel@tonic-gate 				for (bp = sp->sl_inuse; bp; bp = bp->sb_next)
20997c478bd9Sstevel@tonic-gate 					if (bp->sb_domid == d)
21007c478bd9Sstevel@tonic-gate 						cnt++;
21017c478bd9Sstevel@tonic-gate 			DSLAB_UNLOCK(idn.localid);
21027c478bd9Sstevel@tonic-gate 			ASSERT((dp->dio + dp->dioerr) >= cnt);
21037c478bd9Sstevel@tonic-gate 			dp->dio = cnt;
21047c478bd9Sstevel@tonic-gate 			dp->dioerr = 0;
21057c478bd9Sstevel@tonic-gate 			IDN_DUNLOCK(idn.localid);
21067c478bd9Sstevel@tonic-gate 		}
21077c478bd9Sstevel@tonic-gate 		if ((dp->dstate == IDNDS_CONNECTED) &&
21087c478bd9Sstevel@tonic-gate 		    ((nr = idn_reclaim_mboxdata(d, 0, -1)) > 0))
21097c478bd9Sstevel@tonic-gate 			nreclaimed += nr;
21107c478bd9Sstevel@tonic-gate 
21117c478bd9Sstevel@tonic-gate 		IDN_DUNLOCK(d);
21127c478bd9Sstevel@tonic-gate 	}
21137c478bd9Sstevel@tonic-gate 
21147c478bd9Sstevel@tonic-gate 	DSLAB_LOCK_EXCL(domid);
21157c478bd9Sstevel@tonic-gate 	sp = smr_slaballoc_get_n(domid, nslabs);
21167c478bd9Sstevel@tonic-gate 	if (sp) {
21177c478bd9Sstevel@tonic-gate 		IDN_GKSTAT_ADD(gk_reap_count, (ulong_t)(*nslabs));
21187c478bd9Sstevel@tonic-gate 		smr_slab_free(domid, sp);
21197c478bd9Sstevel@tonic-gate 	}
21207c478bd9Sstevel@tonic-gate 	DSLAB_UNLOCK(domid);
21217c478bd9Sstevel@tonic-gate }
21227c478bd9Sstevel@tonic-gate 
21237c478bd9Sstevel@tonic-gate /*
21247c478bd9Sstevel@tonic-gate  * ---------------------------------------------------------------------
21257c478bd9Sstevel@tonic-gate  * Remap the (IDN) shared memory region to a new physical address.
21267c478bd9Sstevel@tonic-gate  * Caller is expected to have performed a ecache flush if needed.
21277c478bd9Sstevel@tonic-gate  * ---------------------------------------------------------------------
21287c478bd9Sstevel@tonic-gate  */
21297c478bd9Sstevel@tonic-gate void
21307c478bd9Sstevel@tonic-gate smr_remap(struct as *as, register caddr_t vaddr,
21317c478bd9Sstevel@tonic-gate 		register pfn_t new_pfn, uint_t mblen)
21327c478bd9Sstevel@tonic-gate {
21337c478bd9Sstevel@tonic-gate 	tte_t		tte;
21347c478bd9Sstevel@tonic-gate 	size_t		blen;
21357c478bd9Sstevel@tonic-gate 	pgcnt_t		p, npgs;
21367c478bd9Sstevel@tonic-gate 	procname_t	proc = "smr_remap";
21377c478bd9Sstevel@tonic-gate 
21387c478bd9Sstevel@tonic-gate 	if (va_to_pfn(vaddr) == new_pfn) {
2139bf30efa4Smathue 		PR_REMAP("%s: vaddr (0x%p) already mapped to pfn (0x%lx)\n",
2140*07d06da5SSurya Prakki 		    proc, (void *)vaddr, new_pfn);
21417c478bd9Sstevel@tonic-gate 		return;
21427c478bd9Sstevel@tonic-gate 	}
21437c478bd9Sstevel@tonic-gate 
21447c478bd9Sstevel@tonic-gate 	blen = MB2B(mblen);
21457c478bd9Sstevel@tonic-gate 	npgs = btopr(blen);
21467c478bd9Sstevel@tonic-gate 	ASSERT(npgs != 0);
21477c478bd9Sstevel@tonic-gate 
2148bf30efa4Smathue 	PR_REMAP("%s: va = 0x%p, pfn = 0x%lx, npgs = %ld, mb = %d MB (%ld)\n",
2149*07d06da5SSurya Prakki 	    proc, (void *)vaddr, new_pfn, npgs, mblen, blen);
21507c478bd9Sstevel@tonic-gate 
21517c478bd9Sstevel@tonic-gate 	/*
21527c478bd9Sstevel@tonic-gate 	 * Unmap the SMR virtual address from it's current
21537c478bd9Sstevel@tonic-gate 	 * mapping.
21547c478bd9Sstevel@tonic-gate 	 */
21557c478bd9Sstevel@tonic-gate 	hat_unload(as->a_hat, vaddr, blen, HAT_UNLOAD_UNLOCK);
21567c478bd9Sstevel@tonic-gate 
21577c478bd9Sstevel@tonic-gate 	if (new_pfn == PFN_INVALID)
21587c478bd9Sstevel@tonic-gate 		return;
21597c478bd9Sstevel@tonic-gate 
21607c478bd9Sstevel@tonic-gate 	/*
21617c478bd9Sstevel@tonic-gate 	 * Map the SMR to the new physical address space,
21627c478bd9Sstevel@tonic-gate 	 * presumably a remote pfn.  Cannot use hat_devload
21637c478bd9Sstevel@tonic-gate 	 * because it will think pfn represents non-memory,
21647c478bd9Sstevel@tonic-gate 	 * i.e. space since it may beyond his physmax.
21657c478bd9Sstevel@tonic-gate 	 */
21667c478bd9Sstevel@tonic-gate 	for (p = 0; p < npgs; p++) {
2167d3d50737SRafael Vanoni 		sfmmu_memtte(&tte, new_pfn, PROT_READ | PROT_WRITE | HAT_NOSYNC,
21687c478bd9Sstevel@tonic-gate 		    TTE8K);
21697c478bd9Sstevel@tonic-gate 		sfmmu_tteload(as->a_hat, &tte, vaddr, NULL, HAT_LOAD_LOCK);
21707c478bd9Sstevel@tonic-gate 
21717c478bd9Sstevel@tonic-gate 		vaddr += MMU_PAGESIZE;
21727c478bd9Sstevel@tonic-gate 		new_pfn++;
21737c478bd9Sstevel@tonic-gate 	}
21747c478bd9Sstevel@tonic-gate 
21757c478bd9Sstevel@tonic-gate 	PR_REMAP("%s: remapped %ld pages (expected %ld)\n",
21767c478bd9Sstevel@tonic-gate 	    proc, npgs, btopr(MB2B(mblen)));
21777c478bd9Sstevel@tonic-gate }
2178