xref: /onnv-gate/usr/src/uts/sun4u/starfire/io/idn_smr.c (revision 931:92fdf4004904)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*931Smathue  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  *
260Sstevel@tonic-gate  * Inter-Domain Network
270Sstevel@tonic-gate  *
280Sstevel@tonic-gate  * Shared Memory Region (SMR) supporting code.
290Sstevel@tonic-gate  */
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include <sys/types.h>
340Sstevel@tonic-gate #include <sys/param.h>
350Sstevel@tonic-gate #include <sys/machparam.h>
360Sstevel@tonic-gate #include <sys/debug.h>
370Sstevel@tonic-gate #include <sys/cpuvar.h>
380Sstevel@tonic-gate #include <sys/kmem.h>
390Sstevel@tonic-gate #include <sys/mutex.h>
400Sstevel@tonic-gate #include <sys/rwlock.h>
410Sstevel@tonic-gate #include <sys/systm.h>
420Sstevel@tonic-gate #include <sys/machlock.h>
430Sstevel@tonic-gate #include <sys/membar.h>
440Sstevel@tonic-gate #include <sys/mman.h>
450Sstevel@tonic-gate #include <vm/hat.h>
460Sstevel@tonic-gate #include <vm/as.h>
470Sstevel@tonic-gate #include <vm/hat_sfmmu.h>
480Sstevel@tonic-gate #include <sys/vm_machparam.h>
490Sstevel@tonic-gate #include <sys/x_call.h>
500Sstevel@tonic-gate 
510Sstevel@tonic-gate #include <sys/idn.h>
520Sstevel@tonic-gate 
530Sstevel@tonic-gate #ifdef DEBUG
540Sstevel@tonic-gate #define	DIOCHECK(domid) \
550Sstevel@tonic-gate { \
560Sstevel@tonic-gate 	int	_dio; \
570Sstevel@tonic-gate 	if ((_dio = idn_domain[domid].dio) < 0) { \
580Sstevel@tonic-gate 		cmn_err(CE_WARN, \
590Sstevel@tonic-gate 			">>>>> file %s, line %d: domain %d, dio = %d", \
600Sstevel@tonic-gate 			__FILE__, __LINE__, (domid), _dio); \
610Sstevel@tonic-gate 	} \
620Sstevel@tonic-gate }
630Sstevel@tonic-gate #else
640Sstevel@tonic-gate #define	DIOCHECK(domid)
650Sstevel@tonic-gate #endif /* DEBUG */
660Sstevel@tonic-gate 
670Sstevel@tonic-gate static int	smr_slab_alloc_local(int domid, smr_slab_t **spp);
680Sstevel@tonic-gate static int	smr_slab_alloc_remote(int domid, smr_slab_t **spp);
690Sstevel@tonic-gate static void	smr_slab_free_local(int domid, smr_slab_t *sp);
700Sstevel@tonic-gate static void	smr_slab_free_remote(int domid, smr_slab_t *sp);
710Sstevel@tonic-gate static int 	smr_slabwaiter_register(int domid);
720Sstevel@tonic-gate static int 	smr_slabwaiter_unregister(int domid, smr_slab_t **spp);
730Sstevel@tonic-gate static int 	smr_slaballoc_wait(int domid, smr_slab_t **spp);
740Sstevel@tonic-gate static smr_slab_t 	*smr_slab_reserve(int domid);
750Sstevel@tonic-gate static void 	smr_slab_unreserve(int domid, smr_slab_t *sp);
760Sstevel@tonic-gate static void	smr_slab_reap_global();
770Sstevel@tonic-gate 
780Sstevel@tonic-gate /*
790Sstevel@tonic-gate  * Can only be called by the master.  Allocate a slab from the
800Sstevel@tonic-gate  * local pool representing the SMR, on behalf of the given
810Sstevel@tonic-gate  * domain.  Slab is either being requested for use by the
820Sstevel@tonic-gate  * local domain (i.e. domid == idn.localid), or it's being
830Sstevel@tonic-gate  * allocated to give to a remote domain which requested one.
840Sstevel@tonic-gate  * In the base of allocating on behalf of a remote domain,
850Sstevel@tonic-gate  * smr_slab_t structure is used simply to manage ownership.
860Sstevel@tonic-gate  *
870Sstevel@tonic-gate  * Returns:	smr_slaballoc_wait
880Sstevel@tonic-gate  * 		(EINVAL, ETIMEDOUT)
890Sstevel@tonic-gate  *		smr_slabwatier_unregister
900Sstevel@tonic-gate  *		(0, EINVAL, EBUSY, ENOMEM)
910Sstevel@tonic-gate  *		ENOLCK
920Sstevel@tonic-gate  */
930Sstevel@tonic-gate static int
940Sstevel@tonic-gate smr_slab_alloc_local(int domid, smr_slab_t **spp)
950Sstevel@tonic-gate {
960Sstevel@tonic-gate 	int		serrno = 0;
970Sstevel@tonic-gate 	int		nwait;
980Sstevel@tonic-gate 	smr_slab_t	*sp;
990Sstevel@tonic-gate 	idn_domain_t	*dp;
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate 	/*
1030Sstevel@tonic-gate 	 * Only the master can make local allocations.
1040Sstevel@tonic-gate 	 */
1050Sstevel@tonic-gate 	ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID);
1060Sstevel@tonic-gate 	ASSERT(idn.localid == IDN_GET_MASTERID());
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate 	*spp = NULL;
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 	dp = &idn_domain[domid];
1110Sstevel@tonic-gate 	ASSERT(DSLAB_READ_HELD(domid));
1120Sstevel@tonic-gate 	ASSERT(dp->dslab_state == DSLAB_STATE_LOCAL);
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate 	/*
1150Sstevel@tonic-gate 	 * Register myself with the waiting list.
1160Sstevel@tonic-gate 	 */
1170Sstevel@tonic-gate 	nwait = smr_slabwaiter_register(domid);
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 	if (nwait > 1) {
1200Sstevel@tonic-gate 		/*
1210Sstevel@tonic-gate 		 * XXX - old comment?
1220Sstevel@tonic-gate 		 * Need to drop the read lock _after_ registering
1230Sstevel@tonic-gate 		 * ourselves with the potential wait list for this allocation.
1240Sstevel@tonic-gate 		 * Although this allocation is not a remote one, we could
1250Sstevel@tonic-gate 		 * still have multiple threads on the master trying to
1260Sstevel@tonic-gate 		 * satisfy (allocate) request on behalf of a remote domain.
1270Sstevel@tonic-gate 		 */
1280Sstevel@tonic-gate 		/*
1290Sstevel@tonic-gate 		 * Somebody is already in the process of satisfying
1300Sstevel@tonic-gate 		 * the allocation request for this respective
1310Sstevel@tonic-gate 		 * domain.  All we need to do is wait and let
1320Sstevel@tonic-gate 		 * it happen.
1330Sstevel@tonic-gate 		 */
1340Sstevel@tonic-gate 		serrno = smr_slaballoc_wait(domid, spp);
1350Sstevel@tonic-gate 		return (serrno);
1360Sstevel@tonic-gate 	}
1370Sstevel@tonic-gate 	/*
1380Sstevel@tonic-gate 	 * I'm the original slab requester for this domain.  It's local
1390Sstevel@tonic-gate 	 * so go ahead and do the job.
1400Sstevel@tonic-gate 	 */
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 	if ((sp = smr_slab_reserve(domid)) == NULL)
1430Sstevel@tonic-gate 		serrno = ENOMEM;
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 	/*
1460Sstevel@tonic-gate 	 * Allocation may have failed.  In either case we've
1470Sstevel@tonic-gate 	 * got to do the put to at least wake potential waiters up.
1480Sstevel@tonic-gate 	 */
1490Sstevel@tonic-gate 	if (!serrno) {
1500Sstevel@tonic-gate 		if (DSLAB_LOCK_TRYUPGRADE(domid) == 0) {
1510Sstevel@tonic-gate 			DSLAB_UNLOCK(domid);
1520Sstevel@tonic-gate 			DSLAB_LOCK_EXCL(domid);
1530Sstevel@tonic-gate 		}
1540Sstevel@tonic-gate 	}
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 	(void) smr_slaballoc_put(domid, sp, 0, serrno);
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 	/*
1590Sstevel@tonic-gate 	 * If serrno is ENOLCK here, then we must have failed
1600Sstevel@tonic-gate 	 * on the upgrade above, so lock already dropped.
1610Sstevel@tonic-gate 	 */
1620Sstevel@tonic-gate 	if (serrno != ENOLCK) {
1630Sstevel@tonic-gate 		/*
1640Sstevel@tonic-gate 		 * Need to drop since reaping may be recursive?
1650Sstevel@tonic-gate 		 */
1660Sstevel@tonic-gate 		DSLAB_UNLOCK(domid);
1670Sstevel@tonic-gate 	}
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 	/*
1700Sstevel@tonic-gate 	 * Since we were the original requester but never went
1710Sstevel@tonic-gate 	 * to sleep, we need to directly unregister ourselves
1720Sstevel@tonic-gate 	 * from the waiting list.
1730Sstevel@tonic-gate 	 */
1740Sstevel@tonic-gate 	serrno = smr_slabwaiter_unregister(domid, spp);
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	/*
1770Sstevel@tonic-gate 	 * Now that we've satisfied the request, let's check if any
1780Sstevel@tonic-gate 	 * reaping is necessary.  Only the master does this and only
1790Sstevel@tonic-gate 	 * when allocating slabs, an infrequent event :-o
1800Sstevel@tonic-gate 	 */
1810Sstevel@tonic-gate 	smr_slab_reap_global();
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 	ASSERT((serrno == 0) ? (*spp != NULL) : (*spp == NULL));
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate 	DSLAB_LOCK_SHARED(domid);
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate 	return (serrno);
1880Sstevel@tonic-gate }
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate /*
1910Sstevel@tonic-gate  * Can only be called by a slave on behalf of himself.  Need to
1920Sstevel@tonic-gate  * make a request to the master to allocate a slab of SMR buffers
1930Sstevel@tonic-gate  * for the local domain.
1940Sstevel@tonic-gate  *
1950Sstevel@tonic-gate  * Returns:	smr_slaballoc_wait
1960Sstevel@tonic-gate  *		(0, EINVAL, EBUSY, ENOMEM)
1970Sstevel@tonic-gate  *		ENOLCK
1980Sstevel@tonic-gate  *		ECANCELED
1990Sstevel@tonic-gate  */
2000Sstevel@tonic-gate static int
2010Sstevel@tonic-gate smr_slab_alloc_remote(int domid, smr_slab_t **spp)
2020Sstevel@tonic-gate {
2030Sstevel@tonic-gate 	int		nwait;
2040Sstevel@tonic-gate 	int		serrno = 0;
2050Sstevel@tonic-gate 	int		bailout = 0;
2060Sstevel@tonic-gate 	int		masterid;
2070Sstevel@tonic-gate 	idn_domain_t	*dp, *mdp = NULL;
2080Sstevel@tonic-gate 	procname_t	proc = "smr_slab_alloc_remote";
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	/*
2110Sstevel@tonic-gate 	 * Only slaves make remote allocations.
2120Sstevel@tonic-gate 	 */
2130Sstevel@tonic-gate 	ASSERT(idn.localid != IDN_GET_MASTERID());
2140Sstevel@tonic-gate 	ASSERT(domid == idn.localid);
2150Sstevel@tonic-gate 	ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID);
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	*spp = NULL;
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	dp = &idn_domain[domid];
2200Sstevel@tonic-gate 	ASSERT(DSLAB_READ_HELD(domid));
2210Sstevel@tonic-gate 	ASSERT(dp->dslab_state == DSLAB_STATE_REMOTE);
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate 	/*
2240Sstevel@tonic-gate 	 * Register myself with the slaballoc waiting list.
2250Sstevel@tonic-gate 	 * Note that only allow one outstanding allocation
2260Sstevel@tonic-gate 	 * request for the given domain.  Other callers which
2270Sstevel@tonic-gate 	 * detect a slab is needed simply get stuck on the
2280Sstevel@tonic-gate 	 * waiting list waiting for the original caller to
2290Sstevel@tonic-gate 	 * get the job done.
2300Sstevel@tonic-gate 	 * The waiter_register routine will allocate the necessary
2310Sstevel@tonic-gate 	 * slab structure which will ultimately be inserted in
2320Sstevel@tonic-gate 	 * the domain's slab list via smr_slaballoc_put().
2330Sstevel@tonic-gate 	 */
2340Sstevel@tonic-gate 	nwait = smr_slabwaiter_register(domid);
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 	/*
2370Sstevel@tonic-gate 	 * Make sure we have a connection with the master
2380Sstevel@tonic-gate 	 * before we wait around for nothing and send a
2390Sstevel@tonic-gate 	 * command off to nowhere.
2400Sstevel@tonic-gate 	 * First do a quick (no lock) check for global okayness.
2410Sstevel@tonic-gate 	 */
2420Sstevel@tonic-gate 	if ((idn.state != IDNGS_ONLINE) ||
2430Sstevel@tonic-gate 			((masterid = IDN_GET_MASTERID()) == IDN_NIL_DOMID)) {
2440Sstevel@tonic-gate 		bailout = 1;
2450Sstevel@tonic-gate 		serrno = ECANCELED;
2460Sstevel@tonic-gate 	}
2470Sstevel@tonic-gate 	/*
2480Sstevel@tonic-gate 	 * We need to drop our read lock _before_ acquiring the
2490Sstevel@tonic-gate 	 * slaballoc waiter lock.  This is necessary because the
2500Sstevel@tonic-gate 	 * thread that receives the slab alloc response and fills
2510Sstevel@tonic-gate 	 * in the slab structure will need to grab the domain write
2520Sstevel@tonic-gate 	 * lock while holding onto the slaballoc waiter lock.
2530Sstevel@tonic-gate 	 * Potentially could deadlock if we didn't drop our domain
2540Sstevel@tonic-gate 	 * lock before.  Plus, we've registered.
2550Sstevel@tonic-gate 	 *
2560Sstevel@tonic-gate 	 * 4093209 - Note also that we do this _after_ the check for
2570Sstevel@tonic-gate 	 *	idn.masterid where we grab the READER global
2580Sstevel@tonic-gate 	 *	lock.  This is to prevent somebody from
2590Sstevel@tonic-gate 	 *	changing our state after we drop the drwlock.
2600Sstevel@tonic-gate 	 *	A deadlock can occur when shutting down a
2610Sstevel@tonic-gate 	 *	domain we're holding the
2620Sstevel@tonic-gate 	 */
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 	if (!bailout) {
2650Sstevel@tonic-gate 		mdp = &idn_domain[masterid];
2660Sstevel@tonic-gate 		/*
2670Sstevel@tonic-gate 		 * Global state is okay.  Let's double check the
2680Sstevel@tonic-gate 		 * state of our actual target domain.
2690Sstevel@tonic-gate 		 */
2700Sstevel@tonic-gate 		if (mdp->dstate != IDNDS_CONNECTED) {
2710Sstevel@tonic-gate 			bailout = 1;
2720Sstevel@tonic-gate 			serrno = ECANCELED;
2730Sstevel@tonic-gate 		} else if (IDN_DLOCK_TRY_SHARED(masterid)) {
2740Sstevel@tonic-gate 			if (mdp->dstate != IDNDS_CONNECTED) {
2750Sstevel@tonic-gate 				bailout = 1;
2760Sstevel@tonic-gate 				serrno = ECANCELED;
2770Sstevel@tonic-gate 				IDN_DUNLOCK(masterid);
2780Sstevel@tonic-gate 			} else if (nwait != 1) {
2790Sstevel@tonic-gate 				IDN_DUNLOCK(masterid);
2800Sstevel@tonic-gate 			}
2810Sstevel@tonic-gate 			/*
2820Sstevel@tonic-gate 			 * Note that keep the drwlock(read) for
2830Sstevel@tonic-gate 			 * the target (master) domain if it appears
2840Sstevel@tonic-gate 			 * we're the lucky one to send the command.
2850Sstevel@tonic-gate 			 * We hold onto the lock until we've actually
2860Sstevel@tonic-gate 			 * sent the command out.
2870Sstevel@tonic-gate 			 * We don't reach this place unless it
2880Sstevel@tonic-gate 			 * appears everything is kosher with
2890Sstevel@tonic-gate 			 * the target (master) domain.
2900Sstevel@tonic-gate 			 */
2910Sstevel@tonic-gate 		} else {
2920Sstevel@tonic-gate 			bailout = 1;
2930Sstevel@tonic-gate 			serrno = ENOLCK;
2940Sstevel@tonic-gate 		}
2950Sstevel@tonic-gate 	}
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	if (bailout) {
2980Sstevel@tonic-gate 		ASSERT(serrno);
2990Sstevel@tonic-gate 		/*
3000Sstevel@tonic-gate 		 * Gotta bail.  Abort operation.  Error result
3010Sstevel@tonic-gate 		 * will be picked up when we attempt to wait.
3020Sstevel@tonic-gate 		 */
3030Sstevel@tonic-gate 		PR_SMR("%s: BAILING OUT on behalf domain %d "
3040Sstevel@tonic-gate 			"(err=%d, gs=%s, ms=%s)\n",
3050Sstevel@tonic-gate 			proc, domid, serrno, idngs_str[idn.state],
3060Sstevel@tonic-gate 			(masterid == IDN_NIL_DOMID)
3070Sstevel@tonic-gate 			? "unknown" : idnds_str[idn_domain[masterid].dstate]);
3080Sstevel@tonic-gate 		(void) smr_slabwaiter_abort(domid, serrno);
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	} else if (nwait == 1) {
3110Sstevel@tonic-gate 		/*
3120Sstevel@tonic-gate 		 * We are the original requester.  Initiate the
3130Sstevel@tonic-gate 		 * actual request to the master.
3140Sstevel@tonic-gate 		 */
3150Sstevel@tonic-gate 		idn_send_cmd(masterid, IDNCMD_SLABALLOC,
3160Sstevel@tonic-gate 				IDN_SLAB_SIZE, 0, 0);
3170Sstevel@tonic-gate 		ASSERT(mdp);
3180Sstevel@tonic-gate 		IDN_DUNLOCK(masterid);
3190Sstevel@tonic-gate 	}
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	/*
3220Sstevel@tonic-gate 	 * Wait here for response.  Once awakened func returns
3230Sstevel@tonic-gate 	 * with slab structure possibly filled with gifts!
3240Sstevel@tonic-gate 	 */
3250Sstevel@tonic-gate 	serrno = smr_slaballoc_wait(domid, spp);
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 	return (serrno);
3280Sstevel@tonic-gate }
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate /*
3310Sstevel@tonic-gate  * Allocate a slab from the Master on behalf
3320Sstevel@tonic-gate  * of the given domain.  Note that master uses
3330Sstevel@tonic-gate  * this function to allocate slabs on behalf of
3340Sstevel@tonic-gate  * remote domains also.
3350Sstevel@tonic-gate  * Entered with drwlock held.
3360Sstevel@tonic-gate  * Leaves with drwlock dropped.
3370Sstevel@tonic-gate  * Returns:	EDQUOT
3380Sstevel@tonic-gate  *		EINVAL
3390Sstevel@tonic-gate  *		ENOLCK
3400Sstevel@tonic-gate  *		smr_slab_alloc_local
3410Sstevel@tonic-gate  *		smr_slab_alloc_remote
3420Sstevel@tonic-gate  *		(0, EINVAL, EBUSY, ENOMEM)
3430Sstevel@tonic-gate  */
3440Sstevel@tonic-gate int
3450Sstevel@tonic-gate smr_slab_alloc(int domid, smr_slab_t **spp)
3460Sstevel@tonic-gate {
3470Sstevel@tonic-gate 	int		serrno = 0;
3480Sstevel@tonic-gate 	idn_domain_t	*dp;
3490Sstevel@tonic-gate 	procname_t	proc = "smr_slab_alloc";
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	dp = &idn_domain[domid];
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 	ASSERT(DSLAB_READ_HELD(domid));
3550Sstevel@tonic-gate 	ASSERT(dp->dslab_state != DSLAB_STATE_UNKNOWN);
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	*spp = NULL;
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 	switch (dp->dslab_state) {
3600Sstevel@tonic-gate 	case DSLAB_STATE_UNKNOWN:
3610Sstevel@tonic-gate 		cmn_err(CE_WARN,
3620Sstevel@tonic-gate 			"IDN: 300: no slab allocations without a master");
3630Sstevel@tonic-gate 		serrno = EINVAL;
3640Sstevel@tonic-gate 		break;
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 	case DSLAB_STATE_LOCAL:
3670Sstevel@tonic-gate 		/*
3680Sstevel@tonic-gate 		 * If I'm the master, then get a slab
3690Sstevel@tonic-gate 		 * from the local SMR pool, but only
3700Sstevel@tonic-gate 		 * if the number of allocated slabs has
3710Sstevel@tonic-gate 		 * not been exceeded.
3720Sstevel@tonic-gate 		 */
3730Sstevel@tonic-gate 		if (((int)dp->dnslabs < IDN_SLAB_MAXPERDOMAIN) ||
3740Sstevel@tonic-gate 						!IDN_SLAB_MAXPERDOMAIN)
3750Sstevel@tonic-gate 			serrno = smr_slab_alloc_local(domid, spp);
3760Sstevel@tonic-gate 		else
3770Sstevel@tonic-gate 			serrno = EDQUOT;
3780Sstevel@tonic-gate 		break;
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	case DSLAB_STATE_REMOTE:
3810Sstevel@tonic-gate 		/*
3820Sstevel@tonic-gate 		 * Have to make a remote request.
3830Sstevel@tonic-gate 		 * In order to prevent overwhelming the master
3840Sstevel@tonic-gate 		 * with a bunch of requests that he won't be able
3850Sstevel@tonic-gate 		 * to handle we do a check to see if we're still
3860Sstevel@tonic-gate 		 * under quota.  Note that the limit is known
3870Sstevel@tonic-gate 		 * apriori based on the SMR/NWR size and
3880Sstevel@tonic-gate 		 * IDN_SLAB_MINTOTAL.  Domains must have the same
3890Sstevel@tonic-gate 		 * size SMR/NWR, however they can have different
3900Sstevel@tonic-gate 		 * IDN_SLAB_MINTOTAL.  Thus a domain could throttle
3910Sstevel@tonic-gate 		 * itself however it wishes.
3920Sstevel@tonic-gate 		 */
3930Sstevel@tonic-gate 		if (((int)dp->dnslabs < IDN_SLAB_MAXPERDOMAIN) ||
3940Sstevel@tonic-gate 						!IDN_SLAB_MAXPERDOMAIN)
3950Sstevel@tonic-gate 			serrno = smr_slab_alloc_remote(domid, spp);
3960Sstevel@tonic-gate 		else
3970Sstevel@tonic-gate 			serrno = EDQUOT;
3980Sstevel@tonic-gate 		break;
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 	default:
4010Sstevel@tonic-gate 		cmn_err(CE_WARN,
4020Sstevel@tonic-gate 			"IDN: 301: (ALLOC) unknown slab state (%d) "
4030Sstevel@tonic-gate 			"for domain %d", dp->dslab_state, domid);
4040Sstevel@tonic-gate 		serrno = EINVAL;
4050Sstevel@tonic-gate 		break;
4060Sstevel@tonic-gate 	}
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	if (*spp == NULL) {
4090Sstevel@tonic-gate 		PR_SMR("%s: failed to allocate %s slab [serrno = %d]\n",
4100Sstevel@tonic-gate 			proc, (idn.localid == IDN_GET_MASTERID()) ?
4110Sstevel@tonic-gate 			"local" : "remote", serrno);
4120Sstevel@tonic-gate 	}
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	if (serrno) {
4150Sstevel@tonic-gate 		IDN_GKSTAT_GLOBAL_EVENT(gk_slabfail, gk_slabfail_last);
4160Sstevel@tonic-gate 	}
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 	return (serrno);
4190Sstevel@tonic-gate }
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate static void
4220Sstevel@tonic-gate smr_slab_free_local(int domid, smr_slab_t *sp)
4230Sstevel@tonic-gate {
4240Sstevel@tonic-gate 	int	rv;
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 	/*
4270Sstevel@tonic-gate 	 * Do a slaballoc_put just in case there may have
4280Sstevel@tonic-gate 	 * been waiters for slabs for this respective domain
4290Sstevel@tonic-gate 	 * before we unreserve this slab.
4300Sstevel@tonic-gate 	 */
4310Sstevel@tonic-gate 	rv = smr_slaballoc_put(domid, sp, 0, 0);
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	if (rv == -1) {
4340Sstevel@tonic-gate 		/*
4350Sstevel@tonic-gate 		 * Put failed.  Must not have been any waiters.
4360Sstevel@tonic-gate 		 * Go ahead and unreserve the space.
4370Sstevel@tonic-gate 		 */
4380Sstevel@tonic-gate 		smr_slab_unreserve(domid, sp);
4390Sstevel@tonic-gate 	}
4400Sstevel@tonic-gate }
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate static void
4430Sstevel@tonic-gate smr_slab_free_remote(int domid, smr_slab_t *sp)
4440Sstevel@tonic-gate {
4450Sstevel@tonic-gate 	smr_offset_t	slab_offset;
4460Sstevel@tonic-gate 	int		slab_size;
4470Sstevel@tonic-gate 	int		rv;
4480Sstevel@tonic-gate 	int		masterid;
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	ASSERT(domid == idn.localid);
4510Sstevel@tonic-gate 	ASSERT(idn.localid != IDN_GET_MASTERID());
4520Sstevel@tonic-gate 	ASSERT(DSLAB_WRITE_HELD(domid));
4530Sstevel@tonic-gate 	ASSERT(idn_domain[domid].dslab_state == DSLAB_STATE_REMOTE);
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 	masterid = IDN_GET_MASTERID();
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 	ASSERT(masterid != IDN_NIL_DOMID);
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 	slab_offset = IDN_ADDR2OFFSET(sp->sl_start);
4600Sstevel@tonic-gate 	slab_size   = (int)(sp->sl_end - sp->sl_start);
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 	/*
4630Sstevel@tonic-gate 	 * Do a slaballoc_put just in case there may have
4640Sstevel@tonic-gate 	 * been waiters for slabs for this domain before
4650Sstevel@tonic-gate 	 * returning back to the master.
4660Sstevel@tonic-gate 	 */
4670Sstevel@tonic-gate 	rv = smr_slaballoc_put(domid, sp, 0, 0);
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 	if ((rv == -1) && (masterid != IDN_NIL_DOMID)) {
4700Sstevel@tonic-gate 		/*
4710Sstevel@tonic-gate 		 * Put failed.  No waiters so free the local data
4720Sstevel@tonic-gate 		 * structure ship the SMR range off to the master.
4730Sstevel@tonic-gate 		 */
4740Sstevel@tonic-gate 		smr_free_buflist(sp);
4750Sstevel@tonic-gate 		FREESTRUCT(sp, smr_slab_t, 1);
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 		IDN_DLOCK_SHARED(masterid);
4780Sstevel@tonic-gate 		idn_send_cmd(masterid, IDNCMD_SLABFREE,
4790Sstevel@tonic-gate 				slab_offset, slab_size, 0);
4800Sstevel@tonic-gate 		IDN_DUNLOCK(masterid);
4810Sstevel@tonic-gate 	}
4820Sstevel@tonic-gate }
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate /*
4850Sstevel@tonic-gate  * Free up the list of slabs passed
4860Sstevel@tonic-gate  */
4870Sstevel@tonic-gate void
4880Sstevel@tonic-gate smr_slab_free(int domid, smr_slab_t *sp)
4890Sstevel@tonic-gate {
4900Sstevel@tonic-gate 	smr_slab_t	*nsp = NULL;
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 	ASSERT(DSLAB_WRITE_HELD(domid));
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 	if (sp == NULL)
4950Sstevel@tonic-gate 		return;
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 	ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID);
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 	switch (idn_domain[domid].dslab_state) {
5000Sstevel@tonic-gate 	case DSLAB_STATE_UNKNOWN:
5010Sstevel@tonic-gate 		cmn_err(CE_WARN,
5020Sstevel@tonic-gate 			"IDN: 302: no slab free without a master");
5030Sstevel@tonic-gate 		break;
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	case DSLAB_STATE_LOCAL:
5060Sstevel@tonic-gate 		/*
5070Sstevel@tonic-gate 		 * If I'm the master then put the slabs
5080Sstevel@tonic-gate 		 * back to the local SMR pool.
5090Sstevel@tonic-gate 		 */
5100Sstevel@tonic-gate 		for (; sp; sp = nsp) {
5110Sstevel@tonic-gate 			nsp = sp->sl_next;
5120Sstevel@tonic-gate 			smr_slab_free_local(domid, sp);
5130Sstevel@tonic-gate 		}
5140Sstevel@tonic-gate 		break;
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 	case DSLAB_STATE_REMOTE:
5170Sstevel@tonic-gate 		/*
5180Sstevel@tonic-gate 		 * If the domid is my own then I'm freeing
5190Sstevel@tonic-gate 		 * a slab back to the Master.
5200Sstevel@tonic-gate 		 */
5210Sstevel@tonic-gate 		for (; sp; sp = nsp) {
5220Sstevel@tonic-gate 			nsp = sp->sl_next;
5230Sstevel@tonic-gate 			smr_slab_free_remote(domid, sp);
5240Sstevel@tonic-gate 		}
5250Sstevel@tonic-gate 		break;
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 	default:
5280Sstevel@tonic-gate 		cmn_err(CE_WARN,
5290Sstevel@tonic-gate 			"IDN: 301: (FREE) unknown slab state "
5300Sstevel@tonic-gate 			"(%d) for domain %d",
5310Sstevel@tonic-gate 			idn_domain[domid].dslab_state, domid);
5320Sstevel@tonic-gate 		break;
5330Sstevel@tonic-gate 	}
5340Sstevel@tonic-gate }
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate /*
5370Sstevel@tonic-gate  * Free up the list of slab data structures ONLY.
5380Sstevel@tonic-gate  * This is called during a fatal shutdown of the master
5390Sstevel@tonic-gate  * where we need to garbage collect the locally allocated
5400Sstevel@tonic-gate  * data structures used to manage slabs allocated to the
5410Sstevel@tonic-gate  * local domain.  Should never be called by a master since
5420Sstevel@tonic-gate  * the master can do a regular smr_slab_free.
5430Sstevel@tonic-gate  */
5440Sstevel@tonic-gate void
5450Sstevel@tonic-gate smr_slab_garbage_collection(smr_slab_t *sp)
5460Sstevel@tonic-gate {
5470Sstevel@tonic-gate 	smr_slab_t	*nsp;
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 	ASSERT(idn_domain[idn.localid].dvote.v.master == 0);
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 	if (sp == NULL)
5520Sstevel@tonic-gate 		return;
5530Sstevel@tonic-gate 	/*
5540Sstevel@tonic-gate 	 * Since this is only ever called by a slave,
5550Sstevel@tonic-gate 	 * the slab structure size always contains a buflist.
5560Sstevel@tonic-gate 	 */
5570Sstevel@tonic-gate 	for (; sp; sp = nsp) {
5580Sstevel@tonic-gate 		nsp = sp->sl_next;
5590Sstevel@tonic-gate 		smr_free_buflist(sp);
5600Sstevel@tonic-gate 		FREESTRUCT(sp, smr_slab_t, 1);
5610Sstevel@tonic-gate 	}
5620Sstevel@tonic-gate }
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate /*
5650Sstevel@tonic-gate  * Allocate a SMR buffer on behalf of the local domain
5660Sstevel@tonic-gate  * which is ultimately targeted for the given domain.
5670Sstevel@tonic-gate  *
5680Sstevel@tonic-gate  * IMPORTANT: This routine is going to drop the domain rwlock (drwlock)
5690Sstevel@tonic-gate  *	      for the domain on whose behalf the request is being
5700Sstevel@tonic-gate  *	      made.  This routine canNOT block on trying to
5710Sstevel@tonic-gate  *	      reacquire the drwlock.  If he does block then somebody
5720Sstevel@tonic-gate  *	      must have the write lock on the domain which most likely
5730Sstevel@tonic-gate  *	      means the domain is going south anyway, so just bail on
5740Sstevel@tonic-gate  *	      this buffer.  Higher levels will retry if needed.
5750Sstevel@tonic-gate  *
5760Sstevel@tonic-gate  * XXX - Support larger than IDN_SMR_BUFSIZE allocations?
5770Sstevel@tonic-gate  *
5780Sstevel@tonic-gate  * Returns:	A negative return value indicates lock lost on domid.
5790Sstevel@tonic-gate  *		EINVAL, ENOLINK, ENOLCK(internal)
5800Sstevel@tonic-gate  *		smr_slaballoc_wait
5810Sstevel@tonic-gate  * 		(EINVAL, ETIMEDOUT)
5820Sstevel@tonic-gate  *		smr_slabwatier_unregister
5830Sstevel@tonic-gate  *		(0, EINVAL, EBUSY, ENOMEM)
5840Sstevel@tonic-gate  */
5850Sstevel@tonic-gate int
5860Sstevel@tonic-gate smr_buf_alloc(int domid, uint_t len, caddr_t *bufpp)
5870Sstevel@tonic-gate {
5880Sstevel@tonic-gate 	register idn_domain_t	*dp, *ldp;
5890Sstevel@tonic-gate 	smr_slab_t	*sp;
5900Sstevel@tonic-gate 	caddr_t		bufp = NULL;
5910Sstevel@tonic-gate 	int		serrno;
5920Sstevel@tonic-gate 	procname_t	proc = "smr_buf_alloc";
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	dp = &idn_domain[domid];
5950Sstevel@tonic-gate 	/*
5960Sstevel@tonic-gate 	 * Local domain can only allocate on behalf of
5970Sstevel@tonic-gate 	 * itself if this is a priviledged call and the
5980Sstevel@tonic-gate 	 * caller is the master.
5990Sstevel@tonic-gate 	 */
6000Sstevel@tonic-gate 	ASSERT((domid != idn.localid) && (domid != IDN_NIL_DOMID));
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 	*bufpp = NULL;
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 	if (len > IDN_DATA_SIZE) {
6050Sstevel@tonic-gate 		cmn_err(CE_WARN,
606*931Smathue 			"IDN: 303: buffer len %d > IDN_DATA_SIZE (%lu)",
6070Sstevel@tonic-gate 			len, IDN_DATA_SIZE);
6080Sstevel@tonic-gate 		IDN_GKSTAT_GLOBAL_EVENT(gk_buffail, gk_buffail_last);
6090Sstevel@tonic-gate 		return (EINVAL);
6100Sstevel@tonic-gate 	}
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate 	/*
6130Sstevel@tonic-gate 	 * Need to go to my local slab list to find
6140Sstevel@tonic-gate 	 * a buffer.
6150Sstevel@tonic-gate 	 */
6160Sstevel@tonic-gate 	ldp = &idn_domain[idn.localid];
6170Sstevel@tonic-gate 	/*
6180Sstevel@tonic-gate 	 * Now we loop trying to locate a buffer out of our
6190Sstevel@tonic-gate 	 * slabs.  We continue this until either we find a
6200Sstevel@tonic-gate 	 * buffer or we're unable to allocate a slab.  Note
6210Sstevel@tonic-gate 	 * that new slabs are allocated to the front.
6220Sstevel@tonic-gate 	 */
6230Sstevel@tonic-gate 	DSLAB_LOCK_SHARED(idn.localid);
6240Sstevel@tonic-gate 	sp = ldp->dslab;
6250Sstevel@tonic-gate 	do {
6260Sstevel@tonic-gate 		int	spl, all_empty;
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 		if (sp == NULL) {
6290Sstevel@tonic-gate 			if ((serrno = smr_slab_alloc(idn.localid, &sp)) != 0) {
6300Sstevel@tonic-gate 				PR_SMR("%s:%d: failed to allocate "
6310Sstevel@tonic-gate 					"slab [serrno = %d]",
6320Sstevel@tonic-gate 					proc, domid, serrno);
6330Sstevel@tonic-gate 				DSLAB_UNLOCK(idn.localid);
6340Sstevel@tonic-gate 				IDN_GKSTAT_GLOBAL_EVENT(gk_buffail,
6350Sstevel@tonic-gate 							gk_buffail_last);
6360Sstevel@tonic-gate 				return (serrno);
6370Sstevel@tonic-gate 			}
6380Sstevel@tonic-gate 			/*
6390Sstevel@tonic-gate 			 * Of course, the world may have changed while
6400Sstevel@tonic-gate 			 * we dropped the lock.  Better make sure we're
6410Sstevel@tonic-gate 			 * still established.
6420Sstevel@tonic-gate 			 */
6430Sstevel@tonic-gate 			if (dp->dstate != IDNDS_CONNECTED) {
6440Sstevel@tonic-gate 				PR_SMR("%s:%d: state changed during slab "
6450Sstevel@tonic-gate 					"alloc (dstate = %s)\n",
6460Sstevel@tonic-gate 					proc, domid, idnds_str[dp->dstate]);
6470Sstevel@tonic-gate 				DSLAB_UNLOCK(idn.localid);
6480Sstevel@tonic-gate 				IDN_GKSTAT_GLOBAL_EVENT(gk_buffail,
6490Sstevel@tonic-gate 							gk_buffail_last);
6500Sstevel@tonic-gate 				return (ENOLINK);
6510Sstevel@tonic-gate 			}
6520Sstevel@tonic-gate 			/*
6530Sstevel@tonic-gate 			 * We were able to allocate a slab.  Should
6540Sstevel@tonic-gate 			 * be at the front of the list, spin again.
6550Sstevel@tonic-gate 			 */
6560Sstevel@tonic-gate 			sp = ldp->dslab;
6570Sstevel@tonic-gate 		}
6580Sstevel@tonic-gate 		/*
6590Sstevel@tonic-gate 		 * If we have reached here then we have a slab!
6600Sstevel@tonic-gate 		 * Hopefully there are free bufs there :-o
6610Sstevel@tonic-gate 		 */
6620Sstevel@tonic-gate 		spl = splhi();
6630Sstevel@tonic-gate 		all_empty = 1;
6640Sstevel@tonic-gate 		for (; sp && !bufp; sp = sp->sl_next) {
6650Sstevel@tonic-gate 			smr_slabbuf_t	*bp;
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 			if (sp->sl_free == NULL)
6680Sstevel@tonic-gate 				continue;
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 			if (!lock_try(&sp->sl_lock)) {
6710Sstevel@tonic-gate 				all_empty = 0;
6720Sstevel@tonic-gate 				continue;
6730Sstevel@tonic-gate 			}
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 			if ((bp = sp->sl_free) == NULL) {
6760Sstevel@tonic-gate 				lock_clear(&sp->sl_lock);
6770Sstevel@tonic-gate 				continue;
6780Sstevel@tonic-gate 			}
6790Sstevel@tonic-gate 
6800Sstevel@tonic-gate 			sp->sl_free = bp->sb_next;
6810Sstevel@tonic-gate 			bp->sb_next = sp->sl_inuse;
6820Sstevel@tonic-gate 			sp->sl_inuse = bp;
6830Sstevel@tonic-gate 			/*
6840Sstevel@tonic-gate 			 * Found a free buffer.
6850Sstevel@tonic-gate 			 */
6860Sstevel@tonic-gate 			bp->sb_domid = domid;
6870Sstevel@tonic-gate 			bufp = bp->sb_bufp;
6880Sstevel@tonic-gate 			lock_clear(&sp->sl_lock);
6890Sstevel@tonic-gate 		}
6900Sstevel@tonic-gate 		splx(spl);
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 		if (!all_empty && !bufp) {
6930Sstevel@tonic-gate 			/*
6940Sstevel@tonic-gate 			 * If we still haven't found a buffer, but
6950Sstevel@tonic-gate 			 * there's still possibly a buffer available,
6960Sstevel@tonic-gate 			 * then try again.  Only if we're absolutely
6970Sstevel@tonic-gate 			 * sure all slabs are empty do we attempt
6980Sstevel@tonic-gate 			 * to allocate a new one.
6990Sstevel@tonic-gate 			 */
7000Sstevel@tonic-gate 			sp = ldp->dslab;
7010Sstevel@tonic-gate 		}
7020Sstevel@tonic-gate 	} while (bufp == NULL);
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 	*bufpp = bufp;
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	ATOMIC_INC(dp->dio);
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	DSLAB_UNLOCK(idn.localid);
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 	return (0);
7110Sstevel@tonic-gate }
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate /*
7140Sstevel@tonic-gate  * Free a buffer allocated to the local domain back to
7150Sstevel@tonic-gate  * its respective slab.  Slabs are freed via the slab-reap command.
7160Sstevel@tonic-gate  * XXX - Support larger than IDN_SMR_BUFSIZE allocations?
7170Sstevel@tonic-gate  */
7180Sstevel@tonic-gate int
7190Sstevel@tonic-gate smr_buf_free(int domid, caddr_t bufp, uint_t len)
7200Sstevel@tonic-gate {
7210Sstevel@tonic-gate 	register smr_slab_t	*sp;
7220Sstevel@tonic-gate 	smr_slabbuf_t		*bp, **bpp;
7230Sstevel@tonic-gate 	idn_domain_t		*ldp;
7240Sstevel@tonic-gate 	int		buffreed;
7250Sstevel@tonic-gate 	int		lockheld = (len == (uint_t)-1);
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 	/*
7280Sstevel@tonic-gate 	 * We should never be free'ing a buffer on
7290Sstevel@tonic-gate 	 * behalf of ourselves as we are never the
7300Sstevel@tonic-gate 	 * target for allocated SMR buffers.
7310Sstevel@tonic-gate 	 */
7320Sstevel@tonic-gate 	ASSERT(domid != idn.localid);
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 	sp = NULL;
7350Sstevel@tonic-gate 	buffreed = 0;
7360Sstevel@tonic-gate 	ldp = &idn_domain[idn.localid];
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate 	DSLAB_LOCK_SHARED(idn.localid);
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 	if (((uintptr_t)bufp & (IDN_SMR_BUFSIZE-1)) &&
7410Sstevel@tonic-gate 	    (IDN_ADDR2OFFSET(bufp) % IDN_SMR_BUFSIZE)) {
7420Sstevel@tonic-gate 		cmn_err(CE_WARN,
743*931Smathue 			"IDN: 304: buffer (0x%p) from domain %d not on a "
744*931Smathue 			"%d boundary", bufp, domid, IDN_SMR_BUFSIZE);
7450Sstevel@tonic-gate 		goto bfdone;
7460Sstevel@tonic-gate 	}
7470Sstevel@tonic-gate 	if (!lockheld && (len > IDN_DATA_SIZE)) {
7480Sstevel@tonic-gate 		cmn_err(CE_WARN,
7490Sstevel@tonic-gate 			"IDN: 305: buffer length (%d) from domain %d greater "
750*931Smathue 			"than IDN_DATA_SIZE (%lu)",
7510Sstevel@tonic-gate 			len, domid, IDN_DATA_SIZE);
7520Sstevel@tonic-gate 		goto bfdone;
7530Sstevel@tonic-gate 	}
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate 	for (sp = ldp->dslab; sp; sp = sp->sl_next)
7560Sstevel@tonic-gate 		if ((bufp >= sp->sl_start) && (bufp < sp->sl_end))
7570Sstevel@tonic-gate 			break;
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate 	if (sp) {
7600Sstevel@tonic-gate 		int spl;
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 		spl = splhi();
7630Sstevel@tonic-gate 		while (!lock_try(&sp->sl_lock))
7640Sstevel@tonic-gate 			;
7650Sstevel@tonic-gate 		bpp = &sp->sl_inuse;
7660Sstevel@tonic-gate 		for (bp = *bpp; bp; bp = *bpp) {
7670Sstevel@tonic-gate 			if (bp->sb_bufp == bufp)
7680Sstevel@tonic-gate 				break;
7690Sstevel@tonic-gate 			bpp = &bp->sb_next;
7700Sstevel@tonic-gate 		}
7710Sstevel@tonic-gate 		if (bp) {
7720Sstevel@tonic-gate 			ASSERT(bp->sb_domid == domid);
7730Sstevel@tonic-gate 			buffreed++;
7740Sstevel@tonic-gate 			bp->sb_domid = IDN_NIL_DOMID;
7750Sstevel@tonic-gate 			*bpp = bp->sb_next;
7760Sstevel@tonic-gate 			bp->sb_next = sp->sl_free;
7770Sstevel@tonic-gate 			sp->sl_free = bp;
7780Sstevel@tonic-gate 		}
7790Sstevel@tonic-gate 		lock_clear(&sp->sl_lock);
7800Sstevel@tonic-gate 		splx(spl);
7810Sstevel@tonic-gate 	}
7820Sstevel@tonic-gate bfdone:
7830Sstevel@tonic-gate 	if (buffreed) {
7840Sstevel@tonic-gate 		ATOMIC_DEC(idn_domain[domid].dio);
7850Sstevel@tonic-gate 		DIOCHECK(domid);
7860Sstevel@tonic-gate 	} else {
7870Sstevel@tonic-gate 		cmn_err(CE_WARN,
7880Sstevel@tonic-gate 			"IDN: 306: unknown buffer (0x%p) from domain %d",
7890Sstevel@tonic-gate 			bufp, domid);
7900Sstevel@tonic-gate 		ATOMIC_INC(idn_domain[domid].dioerr);
7910Sstevel@tonic-gate 	}
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 	DSLAB_UNLOCK(idn.localid);
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 	return (sp ? 0 : -1);
7960Sstevel@tonic-gate }
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate /*
7990Sstevel@tonic-gate  * Alternative interface to smr_buf_free, but with local drwlock
8000Sstevel@tonic-gate  * held.
8010Sstevel@tonic-gate  */
8020Sstevel@tonic-gate /* ARGSUSED2 */
8030Sstevel@tonic-gate int
8040Sstevel@tonic-gate smr_buf_free_locked(int domid, caddr_t bufp, uint_t len)
8050Sstevel@tonic-gate {
8060Sstevel@tonic-gate 	return (smr_buf_free(domid, bufp, (uint_t)-1));
8070Sstevel@tonic-gate }
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate /*
8100Sstevel@tonic-gate  * Free any and all buffers associated with the given domain.
8110Sstevel@tonic-gate  * Assumption is that domain is dead and buffers are not in use.
8120Sstevel@tonic-gate  * Returns:	Number of buffers freed.
8130Sstevel@tonic-gate  *		-1 if error.
8140Sstevel@tonic-gate  */
8150Sstevel@tonic-gate int
8160Sstevel@tonic-gate smr_buf_free_all(int domid)
8170Sstevel@tonic-gate {
8180Sstevel@tonic-gate 	register smr_slab_t	*sp;
8190Sstevel@tonic-gate 	register smr_slabbuf_t	*bp, **bpp;
8200Sstevel@tonic-gate 	idn_domain_t		*ldp;
8210Sstevel@tonic-gate 	int			nbufsfreed = 0;
8220Sstevel@tonic-gate 	procname_t	proc = "smr_buf_free_all";
8230Sstevel@tonic-gate 
8240Sstevel@tonic-gate 	/*
8250Sstevel@tonic-gate 	 * We should never be free'ing buffers on
8260Sstevel@tonic-gate 	 * behalf of ourself
8270Sstevel@tonic-gate 	 */
8280Sstevel@tonic-gate 	ASSERT(domid != idn.localid);
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 	if (!VALID_DOMAINID(domid)) {
8310Sstevel@tonic-gate 		cmn_err(CE_WARN,
832*931Smathue 			"IDN: 307: domain ID (%d) invalid", domid);
8330Sstevel@tonic-gate 		return (-1);
8340Sstevel@tonic-gate 	}
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 	ldp = &idn_domain[idn.localid];
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 	/*
8390Sstevel@tonic-gate 	 * We grab the writer lock so that we don't have any
8400Sstevel@tonic-gate 	 * competition during a "free-all" call.
8410Sstevel@tonic-gate 	 * No need to grab individual slab locks when holding
8420Sstevel@tonic-gate 	 * dslab(writer).
8430Sstevel@tonic-gate 	 */
8440Sstevel@tonic-gate 	DSLAB_LOCK_EXCL(idn.localid);
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate 	for (sp = ldp->dslab; sp; sp = sp->sl_next) {
8470Sstevel@tonic-gate 		bpp = &sp->sl_inuse;
8480Sstevel@tonic-gate 		for (bp = *bpp; bp; bp = *bpp) {
8490Sstevel@tonic-gate 			if (bp->sb_domid == domid) {
8500Sstevel@tonic-gate 				bp->sb_domid = IDN_NIL_DOMID;
8510Sstevel@tonic-gate 				*bpp = bp->sb_next;
8520Sstevel@tonic-gate 				bp->sb_next = sp->sl_free;
8530Sstevel@tonic-gate 				sp->sl_free = bp;
8540Sstevel@tonic-gate 				nbufsfreed++;
8550Sstevel@tonic-gate 			} else {
8560Sstevel@tonic-gate 				bpp = &bp->sb_next;
8570Sstevel@tonic-gate 			}
8580Sstevel@tonic-gate 		}
8590Sstevel@tonic-gate 	}
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 	if (nbufsfreed > 0) {
8620Sstevel@tonic-gate 		ATOMIC_SUB(idn_domain[domid].dio, nbufsfreed);
8630Sstevel@tonic-gate 		idn_domain[domid].dioerr = 0;
8640Sstevel@tonic-gate 		DIOCHECK(domid);
8650Sstevel@tonic-gate 	}
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate 	DSLAB_UNLOCK(idn.localid);
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate 	PR_SMR("%s: freed %d buffers for domain %d\n",
8700Sstevel@tonic-gate 		proc, nbufsfreed, domid);
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate 	return (nbufsfreed);
8730Sstevel@tonic-gate }
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate int
8760Sstevel@tonic-gate smr_buf_reclaim(int domid, int nbufs)
8770Sstevel@tonic-gate {
8780Sstevel@tonic-gate 	int		num_reclaimed = 0;
8790Sstevel@tonic-gate 	idn_domain_t	*ldp, *dp;
8800Sstevel@tonic-gate 	procname_t	proc = "smr_buf_reclaim";
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	ldp = &idn_domain[idn.localid];
8830Sstevel@tonic-gate 	dp  = &idn_domain[domid];
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 	ASSERT(domid != idn.localid);
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 	if (ATOMIC_CAS(&dp->dreclaim_inprogress, 0, 1)) {
8880Sstevel@tonic-gate 		/*
8890Sstevel@tonic-gate 		 * Reclaim is already in progress, don't
8900Sstevel@tonic-gate 		 * bother.
8910Sstevel@tonic-gate 		 */
8920Sstevel@tonic-gate 		PR_DATA("%s: reclaim already in progress\n", proc);
8930Sstevel@tonic-gate 		return (0);
8940Sstevel@tonic-gate 	}
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate 	PR_SMR("%s: requested %d buffers from domain %d\n",
8970Sstevel@tonic-gate 		proc, nbufs, domid);
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 	if (dp->dio && nbufs) {
9000Sstevel@tonic-gate 		register smr_slab_t	*sp;
9010Sstevel@tonic-gate 		int spl;
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 		DSLAB_LOCK_SHARED(idn.localid);
9040Sstevel@tonic-gate 		spl = splhi();
9050Sstevel@tonic-gate 		for (sp = ldp->dslab; sp && nbufs; sp = sp->sl_next) {
9060Sstevel@tonic-gate 			register smr_slabbuf_t	*bp, **bpp;
9070Sstevel@tonic-gate 
9080Sstevel@tonic-gate 			if (sp->sl_inuse == NULL)
9090Sstevel@tonic-gate 				continue;
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 			if (!lock_try(&sp->sl_lock))
9120Sstevel@tonic-gate 				continue;
9130Sstevel@tonic-gate 
9140Sstevel@tonic-gate 			if (sp->sl_inuse == NULL) {
9150Sstevel@tonic-gate 				lock_clear(&sp->sl_lock);
9160Sstevel@tonic-gate 				continue;
9170Sstevel@tonic-gate 			}
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate 			bpp = &sp->sl_inuse;
9200Sstevel@tonic-gate 			for (bp = *bpp; bp && nbufs; bp = *bpp) {
9210Sstevel@tonic-gate 				if (bp->sb_domid == domid) {
9220Sstevel@tonic-gate 					/*
9230Sstevel@tonic-gate 					 * Buffer no longer in use,
9240Sstevel@tonic-gate 					 * reclaim it.
9250Sstevel@tonic-gate 					 */
9260Sstevel@tonic-gate 					bp->sb_domid = IDN_NIL_DOMID;
9270Sstevel@tonic-gate 					*bpp = bp->sb_next;
9280Sstevel@tonic-gate 					bp->sb_next = sp->sl_free;
9290Sstevel@tonic-gate 					sp->sl_free = bp;
9300Sstevel@tonic-gate 					num_reclaimed++;
9310Sstevel@tonic-gate 					nbufs--;
9320Sstevel@tonic-gate 				} else {
9330Sstevel@tonic-gate 					bpp = &bp->sb_next;
9340Sstevel@tonic-gate 				}
9350Sstevel@tonic-gate 			}
9360Sstevel@tonic-gate 			lock_clear(&sp->sl_lock);
9370Sstevel@tonic-gate 		}
9380Sstevel@tonic-gate 		splx(spl);
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 		if (num_reclaimed > 0) {
9410Sstevel@tonic-gate 			ATOMIC_SUB(dp->dio, num_reclaimed);
9420Sstevel@tonic-gate 			DIOCHECK(domid);
9430Sstevel@tonic-gate 		}
9440Sstevel@tonic-gate 		DSLAB_UNLOCK(idn.localid);
9450Sstevel@tonic-gate 	}
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate 	PR_SMR("%s: reclaimed %d buffers from domain %d\n",
9480Sstevel@tonic-gate 		proc, num_reclaimed, domid);
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 	return (num_reclaimed);
9510Sstevel@tonic-gate }
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate /*
9540Sstevel@tonic-gate  * Returns 1	If any buffers are locked for the given slab.
9550Sstevel@tonic-gate  *	   0	If all buffers are free for the given slab.
9560Sstevel@tonic-gate  *
9570Sstevel@tonic-gate  * The caller is assumed to have the slab protected so that no
9580Sstevel@tonic-gate  * new allocations are attempted from it.  Also, this is only
9590Sstevel@tonic-gate  * valid to be called with respect to slabs that were allocated
9600Sstevel@tonic-gate  * on behalf of the local domain, i.e. the master is not expected
9610Sstevel@tonic-gate  * to call this function with (slave) slab "representatives".
9620Sstevel@tonic-gate  */
9630Sstevel@tonic-gate int
9640Sstevel@tonic-gate smr_slab_busy(smr_slab_t *sp)
9650Sstevel@tonic-gate {
9660Sstevel@tonic-gate 	return ((sp && sp->sl_inuse) ? 1 : 0);
9670Sstevel@tonic-gate }
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate int
9700Sstevel@tonic-gate smr_slabwaiter_init()
9710Sstevel@tonic-gate {
9720Sstevel@tonic-gate 	register int		i;
9730Sstevel@tonic-gate 	struct slabwaiter	*wp;
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 	if (idn.slabwaiter != NULL)
9760Sstevel@tonic-gate 		return (0);
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	/*
9790Sstevel@tonic-gate 	 * Initialize the slab waiting area for MAX_DOMAINS.
9800Sstevel@tonic-gate 	 */
9810Sstevel@tonic-gate 	idn.slabwaiter = GETSTRUCT(struct slabwaiter, MAX_DOMAINS);
9820Sstevel@tonic-gate 	wp = idn.slabwaiter;
9830Sstevel@tonic-gate 	for (i = 0; i < MAX_DOMAINS; wp++, i++) {
9840Sstevel@tonic-gate 		wp->w_closed = 0;
9850Sstevel@tonic-gate 		mutex_init(&wp->w_mutex, NULL, MUTEX_DEFAULT, NULL);
9860Sstevel@tonic-gate 		cv_init(&wp->w_cv, NULL, CV_DEFAULT, NULL);
9870Sstevel@tonic-gate 	}
9880Sstevel@tonic-gate 
9890Sstevel@tonic-gate 	return (0);
9900Sstevel@tonic-gate }
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate void
9930Sstevel@tonic-gate smr_slabwaiter_deinit()
9940Sstevel@tonic-gate {
9950Sstevel@tonic-gate 	register int		i;
9960Sstevel@tonic-gate 	struct slabwaiter	*wp;
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate 	if ((wp = idn.slabwaiter) == NULL)
9990Sstevel@tonic-gate 		return;
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate 	for (i = 0; i < MAX_DOMAINS; wp++, i++) {
10020Sstevel@tonic-gate 		ASSERT(wp->w_nwaiters == 0);
10030Sstevel@tonic-gate 		ASSERT(wp->w_sp == NULL);
10040Sstevel@tonic-gate 		cv_destroy(&wp->w_cv);
10050Sstevel@tonic-gate 		mutex_destroy(&wp->w_mutex);
10060Sstevel@tonic-gate 	}
10070Sstevel@tonic-gate 
10080Sstevel@tonic-gate 	FREESTRUCT(idn.slabwaiter, struct slabwaiter, MAX_DOMAINS);
10090Sstevel@tonic-gate 	idn.slabwaiter = NULL;
10100Sstevel@tonic-gate }
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate void
10130Sstevel@tonic-gate smr_slabwaiter_open(domainset_t domset)
10140Sstevel@tonic-gate {
10150Sstevel@tonic-gate 	int			d;
10160Sstevel@tonic-gate 	struct slabwaiter	*wp;
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 	if ((domset == 0) || !idn.slabwaiter)
10190Sstevel@tonic-gate 		return;
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate 	wp = idn.slabwaiter;
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 	for (d = 0; d < MAX_DOMAINS; wp++, d++) {
10240Sstevel@tonic-gate 		if (!DOMAIN_IN_SET(domset, d))
10250Sstevel@tonic-gate 			continue;
10260Sstevel@tonic-gate 		mutex_enter(&wp->w_mutex);
10270Sstevel@tonic-gate 		wp->w_closed = 0;
10280Sstevel@tonic-gate 		mutex_exit(&wp->w_mutex);
10290Sstevel@tonic-gate 	}
10300Sstevel@tonic-gate }
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate void
10330Sstevel@tonic-gate smr_slabwaiter_close(domainset_t domset)
10340Sstevel@tonic-gate {
10350Sstevel@tonic-gate 	int			d;
10360Sstevel@tonic-gate 	struct slabwaiter	*wp;
10370Sstevel@tonic-gate 
10380Sstevel@tonic-gate 	if ((domset == 0) || !idn.slabwaiter)
10390Sstevel@tonic-gate 		return;
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate 	wp = idn.slabwaiter;
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 	for (d = 0; d < MAX_DOMAINS; wp++, d++) {
10440Sstevel@tonic-gate 		if (!DOMAIN_IN_SET(domset, d))
10450Sstevel@tonic-gate 			continue;
10460Sstevel@tonic-gate 		mutex_enter(&wp->w_mutex);
10470Sstevel@tonic-gate 		wp->w_closed = 1;
10480Sstevel@tonic-gate 		cv_broadcast(&wp->w_cv);
10490Sstevel@tonic-gate 		mutex_exit(&wp->w_mutex);
10500Sstevel@tonic-gate 	}
10510Sstevel@tonic-gate }
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate /*
10540Sstevel@tonic-gate  * Register the caller with the waiting list for the
10550Sstevel@tonic-gate  * given domain.
10560Sstevel@tonic-gate  *
10570Sstevel@tonic-gate  * Protocol:
10580Sstevel@tonic-gate  *	1st Local requester:	register -> alloc ->
10590Sstevel@tonic-gate  *						put(wakeup|xdc) -> unregister
10600Sstevel@tonic-gate  *	Nth Local requester:	register -> wait
10610Sstevel@tonic-gate  *	1st Remote requester:	register -> xdc -> wait
10620Sstevel@tonic-gate  *	Nth Remote requester:	register -> wait
10630Sstevel@tonic-gate  *
10640Sstevel@tonic-gate  *	Remote Responder:	local alloc -> put(xdc)
10650Sstevel@tonic-gate  *	Local Handler:		xdc -> put(wakeup)
10660Sstevel@tonic-gate  *
10670Sstevel@tonic-gate  * E.g. A standard slave allocation request:
10680Sstevel@tonic-gate  *	slave			master
10690Sstevel@tonic-gate  *	-----			------
10700Sstevel@tonic-gate  *	idn_slab_alloc(remote)
10710Sstevel@tonic-gate  *	- register
10720Sstevel@tonic-gate  *	- xdc		->	idn_handler
10730Sstevel@tonic-gate  *	- wait			...
10740Sstevel@tonic-gate  *				idn_slab_alloc(local)
10750Sstevel@tonic-gate  *				- register
10760Sstevel@tonic-gate  *				- alloc
10770Sstevel@tonic-gate  *				- put
10780Sstevel@tonic-gate  *				  . wakeup [local]
10790Sstevel@tonic-gate  *				- unregister
10800Sstevel@tonic-gate  *	idn_handler    	<-	- xdc
10810Sstevel@tonic-gate  *	- put       		DONE
10820Sstevel@tonic-gate  *	  . wakeup [local]
10830Sstevel@tonic-gate  *	    |
10840Sstevel@tonic-gate  *	    V
10850Sstevel@tonic-gate  *      - wait
10860Sstevel@tonic-gate  *	  . unregister
10870Sstevel@tonic-gate  *	DONE
10880Sstevel@tonic-gate  */
10890Sstevel@tonic-gate static int
10900Sstevel@tonic-gate smr_slabwaiter_register(int domid)
10910Sstevel@tonic-gate {
10920Sstevel@tonic-gate 	struct slabwaiter	*wp;
10930Sstevel@tonic-gate 	int		nwait;
10940Sstevel@tonic-gate 	procname_t	proc = "smr_slabwaiter_register";
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 	ASSERT(domid != IDN_NIL_DOMID);
10980Sstevel@tonic-gate 
10990Sstevel@tonic-gate 	ASSERT(DSLAB_READ_HELD(domid));
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate 	wp = &idn.slabwaiter[domid];
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&wp->w_mutex));
11040Sstevel@tonic-gate 
11050Sstevel@tonic-gate 	mutex_enter(&wp->w_mutex);
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate 	nwait = ++(wp->w_nwaiters);
11080Sstevel@tonic-gate 	ASSERT(nwait > 0);
11090Sstevel@tonic-gate 
11100Sstevel@tonic-gate 	PR_SMR("%s: domain = %d, (new)nwaiters = %d\n",
11110Sstevel@tonic-gate 		proc, domid, nwait);
11120Sstevel@tonic-gate 
11130Sstevel@tonic-gate 	if (nwait > 1) {
11140Sstevel@tonic-gate 		/*
11150Sstevel@tonic-gate 		 * There are already waiters for slab allocations
11160Sstevel@tonic-gate 		 * with respect to this domain.
11170Sstevel@tonic-gate 		 */
11180Sstevel@tonic-gate 		PR_SMR("%s: existing waiters for slabs for domain %d\n",
11190Sstevel@tonic-gate 			proc, domid);
11200Sstevel@tonic-gate 		mutex_exit(&wp->w_mutex);
11210Sstevel@tonic-gate 
11220Sstevel@tonic-gate 		return (nwait);
11230Sstevel@tonic-gate 	}
11240Sstevel@tonic-gate 	PR_SMR("%s: initial waiter for slabs for domain %d\n", proc, domid);
11250Sstevel@tonic-gate 	/*
11260Sstevel@tonic-gate 	 * We are the first requester of a slab allocation for this
11270Sstevel@tonic-gate 	 * respective domain.  Need to prep waiting area for
11280Sstevel@tonic-gate 	 * subsequent arrival of a slab.
11290Sstevel@tonic-gate 	 */
11300Sstevel@tonic-gate 	wp->w_sp = NULL;
11310Sstevel@tonic-gate 	wp->w_done = 0;
11320Sstevel@tonic-gate 	wp->w_serrno = 0;
11330Sstevel@tonic-gate 
11340Sstevel@tonic-gate 	mutex_exit(&wp->w_mutex);
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate 	return (nwait);
11370Sstevel@tonic-gate }
11380Sstevel@tonic-gate 
11390Sstevel@tonic-gate /*
11400Sstevel@tonic-gate  * It is assumed that the caller had previously registered,
11410Sstevel@tonic-gate  * but wakeup did not occur due to caller never waiting.
11420Sstevel@tonic-gate  * Thus, slaballoc mutex is still held by caller.
11430Sstevel@tonic-gate  *
11440Sstevel@tonic-gate  * Returns:	0
11450Sstevel@tonic-gate  *		EINVAL
11460Sstevel@tonic-gate  *		EBUSY
11470Sstevel@tonic-gate  *		w_serrno (smr_slaballoc_put)
11480Sstevel@tonic-gate  *		(0, ENOLCK, ENOMEM, EDQUOT, EBUSY, ECANCELED)
11490Sstevel@tonic-gate  */
11500Sstevel@tonic-gate static int
11510Sstevel@tonic-gate smr_slabwaiter_unregister(int domid, smr_slab_t **spp)
11520Sstevel@tonic-gate {
11530Sstevel@tonic-gate 	struct slabwaiter	*wp;
11540Sstevel@tonic-gate 	int		serrno = 0;
11550Sstevel@tonic-gate 	procname_t	proc = "smr_slabwaiter_unregister";
11560Sstevel@tonic-gate 
11570Sstevel@tonic-gate 
11580Sstevel@tonic-gate 	ASSERT(domid != IDN_NIL_DOMID);
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate 	wp = &idn.slabwaiter[domid];
11610Sstevel@tonic-gate 
11620Sstevel@tonic-gate 	mutex_enter(&wp->w_mutex);
11630Sstevel@tonic-gate 
11640Sstevel@tonic-gate 	PR_SMR("%s: domain = %d, nwaiters = %d\n",
11650Sstevel@tonic-gate 		proc, domid, wp->w_nwaiters);
11660Sstevel@tonic-gate 
11670Sstevel@tonic-gate 	if (wp->w_nwaiters <= 0) {
11680Sstevel@tonic-gate 		/*
11690Sstevel@tonic-gate 		 * Hmmm...nobody is registered!
11700Sstevel@tonic-gate 		 */
11710Sstevel@tonic-gate 		PR_SMR("%s: NO WAITERS (domid = %d)\n", proc, domid);
11720Sstevel@tonic-gate 		mutex_exit(&wp->w_mutex);
11730Sstevel@tonic-gate 		return (EINVAL);
11740Sstevel@tonic-gate 	}
11750Sstevel@tonic-gate 	(wp->w_nwaiters)--;
11760Sstevel@tonic-gate 	/*
11770Sstevel@tonic-gate 	 * Is our present under the tree?
11780Sstevel@tonic-gate 	 */
11790Sstevel@tonic-gate 	if (!wp->w_done) {
11800Sstevel@tonic-gate 		/*
11810Sstevel@tonic-gate 		 * Bummer...no presents.  Let the caller know
11820Sstevel@tonic-gate 		 * via a null slab pointer.
11830Sstevel@tonic-gate 		 * Note that we don't clean up immediately since
11840Sstevel@tonic-gate 		 * message might still come in for other waiters.
11850Sstevel@tonic-gate 		 * Thus, late sleepers may still get a chance.
11860Sstevel@tonic-gate 		 */
11870Sstevel@tonic-gate 		PR_SMR("%s: bummer no slab allocated for domain %d\n",
11880Sstevel@tonic-gate 			proc, domid);
11890Sstevel@tonic-gate 		ASSERT(wp->w_sp == NULL);
11900Sstevel@tonic-gate 		(*spp) = NULL;
11910Sstevel@tonic-gate 		serrno = wp->w_closed ? ECANCELED : EBUSY;
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate 	} else {
11940Sstevel@tonic-gate 		(*spp) = wp->w_sp;
11950Sstevel@tonic-gate 		serrno = wp->w_serrno;
11960Sstevel@tonic-gate 
11970Sstevel@tonic-gate #ifdef DEBUG
11980Sstevel@tonic-gate 		if (serrno == 0) {
11990Sstevel@tonic-gate 			register smr_slab_t	*sp;
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate 			ASSERT(wp->w_sp);
12020Sstevel@tonic-gate 			PR_SMR("%s: allocation succeeded (domain %d)\n",
12030Sstevel@tonic-gate 				proc, domid);
12040Sstevel@tonic-gate 
12050Sstevel@tonic-gate 			DSLAB_LOCK_SHARED(domid);
12060Sstevel@tonic-gate 			for (sp = idn_domain[domid].dslab; sp; sp = sp->sl_next)
12070Sstevel@tonic-gate 				if (sp == wp->w_sp)
12080Sstevel@tonic-gate 					break;
12090Sstevel@tonic-gate 			if (sp == NULL)
12100Sstevel@tonic-gate 				cmn_err(CE_WARN,
12110Sstevel@tonic-gate 					"%s:%d: slab ptr = NULL",
12120Sstevel@tonic-gate 					proc, domid);
12130Sstevel@tonic-gate 			DSLAB_UNLOCK(domid);
12140Sstevel@tonic-gate 		} else {
12150Sstevel@tonic-gate 			PR_SMR("%s: allocation failed (domain %d) "
12160Sstevel@tonic-gate 				"[serrno = %d]\n", proc, domid, serrno);
12170Sstevel@tonic-gate 		}
12180Sstevel@tonic-gate #endif /* DEBUG */
12190Sstevel@tonic-gate 	}
12200Sstevel@tonic-gate 	if (wp->w_nwaiters == 0) {
12210Sstevel@tonic-gate 		/*
12220Sstevel@tonic-gate 		 * Last one turns out the lights.
12230Sstevel@tonic-gate 		 */
12240Sstevel@tonic-gate 		PR_SMR("%s: domain %d last waiter, turning out lights\n",
12250Sstevel@tonic-gate 			proc, domid);
12260Sstevel@tonic-gate 		wp->w_sp = NULL;
12270Sstevel@tonic-gate 		wp->w_done = 0;
12280Sstevel@tonic-gate 		wp->w_serrno = 0;
12290Sstevel@tonic-gate 	}
12300Sstevel@tonic-gate 	mutex_exit(&wp->w_mutex);
12310Sstevel@tonic-gate 
12320Sstevel@tonic-gate 	return (serrno);
12330Sstevel@tonic-gate }
12340Sstevel@tonic-gate 
12350Sstevel@tonic-gate /*
12360Sstevel@tonic-gate  * Called to abort any slaballoc requests on behalf of the
12370Sstevel@tonic-gate  * given domain.
12380Sstevel@tonic-gate  */
12390Sstevel@tonic-gate int
12400Sstevel@tonic-gate smr_slabwaiter_abort(int domid, int serrno)
12410Sstevel@tonic-gate {
12420Sstevel@tonic-gate 	ASSERT(serrno != 0);
12430Sstevel@tonic-gate 
12440Sstevel@tonic-gate 	return (smr_slaballoc_put(domid, NULL, 0, serrno));
12450Sstevel@tonic-gate }
12460Sstevel@tonic-gate 
12470Sstevel@tonic-gate /*
12480Sstevel@tonic-gate  * Put ourselves into a timedwait waiting for slab to be
12490Sstevel@tonic-gate  * allocated.
12500Sstevel@tonic-gate  * Returns with slaballoc mutex dropped.
12510Sstevel@tonic-gate  *
12520Sstevel@tonic-gate  * Returns:	EINVAL
12530Sstevel@tonic-gate  *		ETIMEDOUT
12540Sstevel@tonic-gate  *		smr_slabwatier_unregister
12550Sstevel@tonic-gate  *		(0, EINVAL, EBUSY, ENOMEM)
12560Sstevel@tonic-gate  */
12570Sstevel@tonic-gate static int
12580Sstevel@tonic-gate smr_slaballoc_wait(int domid, smr_slab_t **spp)
12590Sstevel@tonic-gate {
12600Sstevel@tonic-gate 	struct slabwaiter	*wp;
12610Sstevel@tonic-gate 	int			serrno = 0, serrno_unreg;
12620Sstevel@tonic-gate 	procname_t		proc = "smr_slaballoc_wait";
12630Sstevel@tonic-gate 
12640Sstevel@tonic-gate 
12650Sstevel@tonic-gate 	wp = &idn.slabwaiter[domid];
12660Sstevel@tonic-gate 
12670Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&wp->w_mutex));
12680Sstevel@tonic-gate 
12690Sstevel@tonic-gate 	mutex_enter(&wp->w_mutex);
12700Sstevel@tonic-gate 
1271*931Smathue 	PR_SMR("%s: domain = %d, nwaiters = %d, wsp = 0x%p\n",
1272*931Smathue 		proc, domid, wp->w_nwaiters, wp->w_sp);
12730Sstevel@tonic-gate 
12740Sstevel@tonic-gate 	if (wp->w_nwaiters <= 0) {
12750Sstevel@tonic-gate 		/*
12760Sstevel@tonic-gate 		 * Hmmm...no waiters registered.
12770Sstevel@tonic-gate 		 */
12780Sstevel@tonic-gate 		PR_SMR("%s: domain %d, no waiters!\n",
12790Sstevel@tonic-gate 			proc, domid);
12800Sstevel@tonic-gate 		mutex_exit(&wp->w_mutex);
12810Sstevel@tonic-gate 		return (EINVAL);
12820Sstevel@tonic-gate 	}
12830Sstevel@tonic-gate 	ASSERT(DSLAB_READ_HELD(domid));
12840Sstevel@tonic-gate 	DSLAB_UNLOCK(domid);
12850Sstevel@tonic-gate 
12860Sstevel@tonic-gate 	if (!wp->w_done && !wp->w_closed) {
12870Sstevel@tonic-gate 		int	rv;
12880Sstevel@tonic-gate 
12890Sstevel@tonic-gate 		/*
12900Sstevel@tonic-gate 		 * Only wait if data hasn't arrived yet.
12910Sstevel@tonic-gate 		 */
12920Sstevel@tonic-gate 		PR_SMR("%s: domain %d, going to sleep...\n",
12930Sstevel@tonic-gate 			proc, domid);
12940Sstevel@tonic-gate 
12950Sstevel@tonic-gate 
12960Sstevel@tonic-gate 		rv = cv_timedwait_sig(&wp->w_cv, &wp->w_mutex,
12970Sstevel@tonic-gate 				lbolt + IDN_SLABALLOC_WAITTIME);
12980Sstevel@tonic-gate 		if (rv == -1)
12990Sstevel@tonic-gate 			serrno = ETIMEDOUT;
13000Sstevel@tonic-gate 
13010Sstevel@tonic-gate 		PR_SMR("%s: domain %d, awakened (reason = %s)\n",
13020Sstevel@tonic-gate 			proc, domid, (rv == -1) ? "TIMEOUT" : "SIGNALED");
13030Sstevel@tonic-gate 	}
13040Sstevel@tonic-gate 	/*
13050Sstevel@tonic-gate 	 * We've awakened or request already filled!
13060Sstevel@tonic-gate 	 * Unregister ourselves.
13070Sstevel@tonic-gate 	 */
13080Sstevel@tonic-gate 	mutex_exit(&wp->w_mutex);
13090Sstevel@tonic-gate 
13100Sstevel@tonic-gate 	/*
13110Sstevel@tonic-gate 	 * Any gifts will be entered into spp.
13120Sstevel@tonic-gate 	 */
13130Sstevel@tonic-gate 	serrno_unreg = smr_slabwaiter_unregister(domid, spp);
13140Sstevel@tonic-gate 
13150Sstevel@tonic-gate 	/*
13160Sstevel@tonic-gate 	 * Leave with reader lock on dslab_lock.
13170Sstevel@tonic-gate 	 */
13180Sstevel@tonic-gate 	DSLAB_LOCK_SHARED(domid);
13190Sstevel@tonic-gate 
13200Sstevel@tonic-gate 	if ((serrno_unreg == EBUSY) && (serrno == ETIMEDOUT))
13210Sstevel@tonic-gate 		return (serrno);
13220Sstevel@tonic-gate 	else
13230Sstevel@tonic-gate 		return (serrno_unreg);
13240Sstevel@tonic-gate }
13250Sstevel@tonic-gate 
13260Sstevel@tonic-gate /*
13270Sstevel@tonic-gate  * A SMR slab was allocated on behalf of the given domain.
13280Sstevel@tonic-gate  * Wakeup anybody that may have been waiting for the allocation.
13290Sstevel@tonic-gate  * Note that if the domain is a remote one, i.e. master is allocating
13300Sstevel@tonic-gate  * on behalf of a slave, it's up to the caller to transmit the
13310Sstevel@tonic-gate  * allocation response to that domain.
13320Sstevel@tonic-gate  * The force flag indicates that we want to install the slab for
13330Sstevel@tonic-gate  * the given user regardless of whether there are waiters or not.
13340Sstevel@tonic-gate  * This is used primarily in situations where a slave may have timed
13350Sstevel@tonic-gate  * out before the response actually arrived.  In this situation we
13360Sstevel@tonic-gate  * don't want to send slab back to the master after we went through
13370Sstevel@tonic-gate  * the trouble of allocating one.  Master is _not_ allowed to do this
13380Sstevel@tonic-gate  * for remote domains.
13390Sstevel@tonic-gate  *
13400Sstevel@tonic-gate  * Returns:	-1	Non-registered waiter or waiting area garbaged.
13410Sstevel@tonic-gate  *		0	Successfully performed operation.
13420Sstevel@tonic-gate  */
13430Sstevel@tonic-gate int
13440Sstevel@tonic-gate smr_slaballoc_put(int domid, smr_slab_t *sp, int forceflag, int serrno)
13450Sstevel@tonic-gate {
13460Sstevel@tonic-gate 	idn_domain_t		*dp;
13470Sstevel@tonic-gate 	struct slabwaiter	*wp;
13480Sstevel@tonic-gate 	procname_t		proc = "smr_slaballoc_put";
13490Sstevel@tonic-gate 
13500Sstevel@tonic-gate 
13510Sstevel@tonic-gate 	dp = &idn_domain[domid];
13520Sstevel@tonic-gate 
13530Sstevel@tonic-gate 	ASSERT(!serrno ? DSLAB_WRITE_HELD(domid) : 1);
13540Sstevel@tonic-gate 
13550Sstevel@tonic-gate 	if (domid == IDN_NIL_DOMID)
13560Sstevel@tonic-gate 		return (-1);
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate 	ASSERT(serrno ? (sp == NULL) : (sp != NULL));
13590Sstevel@tonic-gate 
13600Sstevel@tonic-gate 	wp = &idn.slabwaiter[domid];
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate 	mutex_enter(&wp->w_mutex);
13630Sstevel@tonic-gate 
1364*931Smathue 	PR_SMR("%s: domain = %d, bufp = 0x%p, ebufp = 0x%p, "
1365*931Smathue 		"(f = %d, se = %d)\n", proc, domid,
1366*931Smathue 		(sp ? sp->sl_start : 0),
1367*931Smathue 		(sp ? sp->sl_end : 0), forceflag, serrno);
13680Sstevel@tonic-gate 
13690Sstevel@tonic-gate 	if (wp->w_nwaiters <= 0) {
13700Sstevel@tonic-gate 		/*
13710Sstevel@tonic-gate 		 * There are no waiters!!  Must have timed out
13720Sstevel@tonic-gate 		 * and left.  Oh well...
13730Sstevel@tonic-gate 		 */
13740Sstevel@tonic-gate 		PR_SMR("%s: no slaballoc waiters found for domain %d\n",
13750Sstevel@tonic-gate 			proc, domid);
13760Sstevel@tonic-gate 		if (!forceflag || serrno || !sp) {
13770Sstevel@tonic-gate 			/*
13780Sstevel@tonic-gate 			 * No waiters and caller doesn't want to force it.
13790Sstevel@tonic-gate 			 */
13800Sstevel@tonic-gate 			mutex_exit(&wp->w_mutex);
13810Sstevel@tonic-gate 			return (-1);
13820Sstevel@tonic-gate 		}
13830Sstevel@tonic-gate 		PR_SMR("%s: forcing slab onto domain %d\n", proc, domid);
13840Sstevel@tonic-gate 		ASSERT(domid == idn.localid);
13850Sstevel@tonic-gate 		ASSERT(wp->w_sp == NULL);
13860Sstevel@tonic-gate 		wp->w_done = 0;
13870Sstevel@tonic-gate 		/*
13880Sstevel@tonic-gate 		 * Now we fall through and let it be added in the
13890Sstevel@tonic-gate 		 * regular manor.
13900Sstevel@tonic-gate 		 */
13910Sstevel@tonic-gate 	}
13920Sstevel@tonic-gate 	if (wp->w_done) {
13930Sstevel@tonic-gate 		/*
13940Sstevel@tonic-gate 		 * There's at least one waiter so there has
13950Sstevel@tonic-gate 		 * to be a slab structure waiting for us.
13960Sstevel@tonic-gate 		 * If everything is going smoothly, there should only
13970Sstevel@tonic-gate 		 * be one guy coming through the path of inserting
13980Sstevel@tonic-gate 		 * an error or good slab.  However, if a disconnect was
13990Sstevel@tonic-gate 		 * detected, you may get several guys coming through
14000Sstevel@tonic-gate 		 * trying to let everybody know.
14010Sstevel@tonic-gate 		 */
14020Sstevel@tonic-gate 		ASSERT(wp->w_serrno ?
14030Sstevel@tonic-gate 			(wp->w_sp == NULL) : (wp->w_sp != NULL));
14040Sstevel@tonic-gate 
14050Sstevel@tonic-gate 		cv_broadcast(&wp->w_cv);
14060Sstevel@tonic-gate 		mutex_exit(&wp->w_mutex);
14070Sstevel@tonic-gate 
14080Sstevel@tonic-gate 		return (-1);
14090Sstevel@tonic-gate 	}
14100Sstevel@tonic-gate 	if (serrno != 0) {
14110Sstevel@tonic-gate 		/*
14120Sstevel@tonic-gate 		 * Bummer...allocation failed.  This call is simply
14130Sstevel@tonic-gate 		 * to wake up the sleepers and let them know.
14140Sstevel@tonic-gate 		 */
14150Sstevel@tonic-gate 		PR_SMR("%s: slaballoc failed for domain %d\n",
14160Sstevel@tonic-gate 			proc, domid);
14170Sstevel@tonic-gate 		wp->w_serrno = serrno;
14180Sstevel@tonic-gate 		wp->w_done = 1;
14190Sstevel@tonic-gate 		cv_broadcast(&wp->w_cv);
14200Sstevel@tonic-gate 		mutex_exit(&wp->w_mutex);
14210Sstevel@tonic-gate 
14220Sstevel@tonic-gate 		return (0);
14230Sstevel@tonic-gate 	}
14240Sstevel@tonic-gate 	PR_SMR("%s: putting slab into struct (domid=%d, localid=%d)\n",
14250Sstevel@tonic-gate 		proc, domid, idn.localid);
14260Sstevel@tonic-gate 	/*
14270Sstevel@tonic-gate 	 * Prep the slab structure.
14280Sstevel@tonic-gate 	 */
14290Sstevel@tonic-gate 
14300Sstevel@tonic-gate 	if (domid == idn.localid) {
14310Sstevel@tonic-gate 		/*
14320Sstevel@tonic-gate 		 * Allocation was indeed for me.
14330Sstevel@tonic-gate 		 * Slab may or may not be locked when
14340Sstevel@tonic-gate 		 * we reach.  Normally they will be locked
14350Sstevel@tonic-gate 		 * if we're being called on behalf of a
14360Sstevel@tonic-gate 		 * free, and not locked if on behalf of
14370Sstevel@tonic-gate 		 * a new allocation request.
14380Sstevel@tonic-gate 		 */
14390Sstevel@tonic-gate 		lock_clear(&sp->sl_lock);
14400Sstevel@tonic-gate 		smr_alloc_buflist(sp);
14410Sstevel@tonic-gate #ifdef DEBUG
14420Sstevel@tonic-gate 	} else {
14430Sstevel@tonic-gate 		uint_t	rv;
14440Sstevel@tonic-gate 		/*
14450Sstevel@tonic-gate 		 * Slab was not allocated on my behalf.  Must be
14460Sstevel@tonic-gate 		 * a master request on behalf of some other domain.
14470Sstevel@tonic-gate 		 * Prep appropriately.  Slab should have been locked
14480Sstevel@tonic-gate 		 * by smr_slab_reserve.
14490Sstevel@tonic-gate 		 */
14500Sstevel@tonic-gate 		rv = lock_try(&sp->sl_lock);
14510Sstevel@tonic-gate 		ASSERT(!rv);
14520Sstevel@tonic-gate 		ASSERT(sp->sl_domid == (short)domid);
14530Sstevel@tonic-gate #endif /* DEBUG */
14540Sstevel@tonic-gate 	}
14550Sstevel@tonic-gate 
14560Sstevel@tonic-gate 	/*
14570Sstevel@tonic-gate 	 * Slab is ready to go.  Insert it into the domain's
14580Sstevel@tonic-gate 	 * slab list so once we wake everybody up they'll find it.
14590Sstevel@tonic-gate 	 * You better have write lock if you're putting treasures
14600Sstevel@tonic-gate 	 * there.
14610Sstevel@tonic-gate 	 */
14620Sstevel@tonic-gate 	ASSERT(DSLAB_WRITE_HELD(domid));
14630Sstevel@tonic-gate 
14640Sstevel@tonic-gate 	sp->sl_next = dp->dslab;
14650Sstevel@tonic-gate 	dp->dslab  = sp;
14660Sstevel@tonic-gate 	dp->dnslabs++;
14670Sstevel@tonic-gate 
14680Sstevel@tonic-gate 	/*
14690Sstevel@tonic-gate 	 * It's possible to fall through here without waiters.
14700Sstevel@tonic-gate 	 * This is a case where forceflag was set.
14710Sstevel@tonic-gate 	 */
14720Sstevel@tonic-gate 	if (wp->w_nwaiters > 0) {
14730Sstevel@tonic-gate 		wp->w_sp = sp;
14740Sstevel@tonic-gate 		wp->w_serrno = serrno;
14750Sstevel@tonic-gate 		wp->w_done = 1;
14760Sstevel@tonic-gate 		cv_broadcast(&wp->w_cv);
14770Sstevel@tonic-gate 	} else {
14780Sstevel@tonic-gate 		ASSERT(forceflag);
14790Sstevel@tonic-gate 		wp->w_sp = NULL;
14800Sstevel@tonic-gate 		wp->w_serrno = 0;
14810Sstevel@tonic-gate 		wp->w_done = 0;
14820Sstevel@tonic-gate 	}
14830Sstevel@tonic-gate 	mutex_exit(&wp->w_mutex);
14840Sstevel@tonic-gate 
14850Sstevel@tonic-gate 	return (0);
14860Sstevel@tonic-gate }
14870Sstevel@tonic-gate 
14880Sstevel@tonic-gate /*
14890Sstevel@tonic-gate  * Get the slab representing [bufp,ebufp] from the respective
14900Sstevel@tonic-gate  * domain's pool if all the buffers are free.  Remove them from
14910Sstevel@tonic-gate  * the domain's list and return it.
14920Sstevel@tonic-gate  * If bufp == NULL, then return however many free ones you
14930Sstevel@tonic-gate  * can find.
14940Sstevel@tonic-gate  * List of slabs are returned locked (sl_lock).
14950Sstevel@tonic-gate  * XXX - Need minimum limit to make sure we don't free up _all_
14960Sstevel@tonic-gate  *	 of our slabs!  However, during a shutdown we will need
14970Sstevel@tonic-gate  *	 method to free them all up regardless of locking.
14980Sstevel@tonic-gate  */
14990Sstevel@tonic-gate smr_slab_t *
15000Sstevel@tonic-gate smr_slaballoc_get(int domid, caddr_t bufp, caddr_t ebufp)
15010Sstevel@tonic-gate {
15020Sstevel@tonic-gate 	idn_domain_t	*dp;
15030Sstevel@tonic-gate 	smr_slab_t	*retsp, *sp, **psp;
15040Sstevel@tonic-gate 	int		foundit, islocal = 0;
15050Sstevel@tonic-gate 	int		nslabs;
15060Sstevel@tonic-gate 	procname_t	proc = "smr_slaballoc_get";
15070Sstevel@tonic-gate 
1508*931Smathue 	PR_SMR("%s: getting slab for domain %d [bufp=0x%p, ebufp=0x%p]\n",
1509*931Smathue 		proc, domid, bufp, ebufp);
15100Sstevel@tonic-gate 
15110Sstevel@tonic-gate 	dp = &idn_domain[domid];
15120Sstevel@tonic-gate 
15130Sstevel@tonic-gate 	ASSERT(DSLAB_WRITE_HELD(domid));
15140Sstevel@tonic-gate 
15150Sstevel@tonic-gate 	if ((sp = dp->dslab) == NULL) {
15160Sstevel@tonic-gate 		PR_SMR("%s: oops, no slabs for domain %d\n",
15170Sstevel@tonic-gate 			proc, domid);
15180Sstevel@tonic-gate 		return (NULL);
15190Sstevel@tonic-gate 	}
15200Sstevel@tonic-gate 	/*
15210Sstevel@tonic-gate 	 * If domid is myself then I'm trying to get a slab out
15220Sstevel@tonic-gate 	 * of my local pool.  Otherwise, I'm the master and
15230Sstevel@tonic-gate 	 * I'm trying to get the slab representative from the
15240Sstevel@tonic-gate 	 * global pool.
15250Sstevel@tonic-gate 	 */
15260Sstevel@tonic-gate 	if (domid == idn.localid)
15270Sstevel@tonic-gate 		islocal = 1;
15280Sstevel@tonic-gate 
15290Sstevel@tonic-gate 	if (bufp != NULL) {
15300Sstevel@tonic-gate 		nslabs = -1;
15310Sstevel@tonic-gate 	} else {
15320Sstevel@tonic-gate 		nslabs = *(int *)ebufp;
15330Sstevel@tonic-gate 		if (nslabs == 0) {
15340Sstevel@tonic-gate 			PR_SMR("%s: requested nslabs (%d) <= 0\n",
15350Sstevel@tonic-gate 				proc, nslabs);
15360Sstevel@tonic-gate 			return (NULL);
15370Sstevel@tonic-gate 		} else if (nslabs < 0) {
15380Sstevel@tonic-gate 			/*
15390Sstevel@tonic-gate 			 * Caller wants them all!
15400Sstevel@tonic-gate 			 */
15410Sstevel@tonic-gate 			nslabs = (int)dp->dnslabs;
15420Sstevel@tonic-gate 		}
15430Sstevel@tonic-gate 	}
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate 	retsp = NULL;
15460Sstevel@tonic-gate 	foundit = 0;
15470Sstevel@tonic-gate 	for (psp = &dp->dslab; sp; sp = *psp) {
15480Sstevel@tonic-gate 		int	isbusy;
15490Sstevel@tonic-gate 
15500Sstevel@tonic-gate 		if (bufp && (sp->sl_start != bufp)) {
15510Sstevel@tonic-gate 			psp = &sp->sl_next;
15520Sstevel@tonic-gate 			continue;
15530Sstevel@tonic-gate 		}
15540Sstevel@tonic-gate 
15550Sstevel@tonic-gate 		if (bufp && (ebufp > sp->sl_end)) {
1556*931Smathue 			PR_SMR("%s: bufp/ebufp (0x%p/0x%p) "
1557*931Smathue 				"expected (0x%p/0x%p)\n", proc, bufp, ebufp,
1558*931Smathue 				sp->sl_start, sp->sl_end);
15590Sstevel@tonic-gate 			ASSERT(0);
15600Sstevel@tonic-gate 		}
15610Sstevel@tonic-gate 		/*
15620Sstevel@tonic-gate 		 * We found the desired slab.  Make sure
15630Sstevel@tonic-gate 		 * it's free.
15640Sstevel@tonic-gate 		 */
15650Sstevel@tonic-gate 		foundit++;
15660Sstevel@tonic-gate 		isbusy = 0;
15670Sstevel@tonic-gate 		if (islocal) {
15680Sstevel@tonic-gate 			int spl;
15690Sstevel@tonic-gate 
15700Sstevel@tonic-gate 			/*
15710Sstevel@tonic-gate 			 * Some of the buffers in the slab
15720Sstevel@tonic-gate 			 * are still in use.  Unlock the
15730Sstevel@tonic-gate 			 * buffers we locked and bail out.
15740Sstevel@tonic-gate 			 */
15750Sstevel@tonic-gate 			spl = splhi();
15760Sstevel@tonic-gate 			if (!lock_try(&sp->sl_lock)) {
15770Sstevel@tonic-gate 				isbusy = 1;
15780Sstevel@tonic-gate 				foundit--;
15790Sstevel@tonic-gate 			} else if (sp->sl_inuse) {
15800Sstevel@tonic-gate 				lock_clear(&sp->sl_lock);
15810Sstevel@tonic-gate 				isbusy = 1;
15820Sstevel@tonic-gate 				foundit--;
15830Sstevel@tonic-gate 			}
15840Sstevel@tonic-gate 			splx(spl);
15850Sstevel@tonic-gate 		} else {
15860Sstevel@tonic-gate 			/*
15870Sstevel@tonic-gate 			 * If not local, then I'm the master getting
15880Sstevel@tonic-gate 			 * a slab from one of the slaves.  In this case,
15890Sstevel@tonic-gate 			 * their slab structs will always be locked.
15900Sstevel@tonic-gate 			 */
15910Sstevel@tonic-gate 			ASSERT(!lock_try(&sp->sl_lock));
15920Sstevel@tonic-gate 		}
15930Sstevel@tonic-gate 		if (!isbusy) {
15940Sstevel@tonic-gate 			/*
15950Sstevel@tonic-gate 			 * Delete the entry from the list and slap
15960Sstevel@tonic-gate 			 * it onto our return list.
15970Sstevel@tonic-gate 			 */
15980Sstevel@tonic-gate 			*psp = sp->sl_next;
15990Sstevel@tonic-gate 			sp->sl_next = retsp;
16000Sstevel@tonic-gate 			retsp = sp;
16010Sstevel@tonic-gate 		} else {
16020Sstevel@tonic-gate 			psp = &sp->sl_next;
16030Sstevel@tonic-gate 		}
16040Sstevel@tonic-gate 		/*
16050Sstevel@tonic-gate 		 * If bufp == NULL (alternate interface) and we haven't
16060Sstevel@tonic-gate 		 * found the desired number of slabs yet, keep looking.
16070Sstevel@tonic-gate 		 */
16080Sstevel@tonic-gate 		if (bufp || (foundit == nslabs))
16090Sstevel@tonic-gate 			break;
16100Sstevel@tonic-gate 	}
16110Sstevel@tonic-gate 	dp->dnslabs -= (short)foundit;
16120Sstevel@tonic-gate 
16130Sstevel@tonic-gate 	if (foundit) {
16140Sstevel@tonic-gate 		PR_SMR("%s: found %d free slabs (domid = %d)\n",
16150Sstevel@tonic-gate 			proc, foundit, domid);
16160Sstevel@tonic-gate 	} else {
16170Sstevel@tonic-gate 		PR_SMR("%s: no free slabs found (domid = %d)\n",
16180Sstevel@tonic-gate 			proc, domid);
16190Sstevel@tonic-gate 	}
16200Sstevel@tonic-gate 
16210Sstevel@tonic-gate 	/*
16220Sstevel@tonic-gate 	 * If this is the alternate interface, need to return
16230Sstevel@tonic-gate 	 * the number of slabs found in the ebufp parameter.
16240Sstevel@tonic-gate 	 */
16250Sstevel@tonic-gate 	if (bufp == NULL)
16260Sstevel@tonic-gate 		*(int *)ebufp = foundit;
16270Sstevel@tonic-gate 
16280Sstevel@tonic-gate 	return (retsp);
16290Sstevel@tonic-gate }
16300Sstevel@tonic-gate 
16310Sstevel@tonic-gate /*
16320Sstevel@tonic-gate  * Wrapper to hide alternate interface to smr_slaballoc_get()
16330Sstevel@tonic-gate  */
16340Sstevel@tonic-gate smr_slab_t *
16350Sstevel@tonic-gate smr_slaballoc_get_n(int domid, int *nslabs)
16360Sstevel@tonic-gate {
16370Sstevel@tonic-gate 	smr_slab_t	*sp;
16380Sstevel@tonic-gate 
16390Sstevel@tonic-gate 	ASSERT(DSLAB_WRITE_HELD(domid));
16400Sstevel@tonic-gate 
16410Sstevel@tonic-gate 	sp = smr_slaballoc_get(domid, NULL, (caddr_t)nslabs);
16420Sstevel@tonic-gate 
16430Sstevel@tonic-gate 	return (sp);
16440Sstevel@tonic-gate }
16450Sstevel@tonic-gate 
16460Sstevel@tonic-gate /*
16470Sstevel@tonic-gate  * Only called by master.  Initialize slab pool based on local SMR.
16480Sstevel@tonic-gate  * Returns number of slabs initialized.
16490Sstevel@tonic-gate  * reserved_size = Length of area at the front of the NWR portion
16500Sstevel@tonic-gate  *		   of the SMR to reserve and not make available for
16510Sstevel@tonic-gate  *		   slab allocations.  Must be a IDN_SMR_BUFSIZE multiple.
16520Sstevel@tonic-gate  * reserved_area = Pointer to reserved area, if any.
16530Sstevel@tonic-gate  */
16540Sstevel@tonic-gate int
16550Sstevel@tonic-gate smr_slabpool_init(size_t reserved_size, caddr_t *reserved_area)
16560Sstevel@tonic-gate {
16570Sstevel@tonic-gate 	size_t			nwr_available;
16580Sstevel@tonic-gate 	int			minperpool, ntotslabs, nxslabs, nslabs;
16590Sstevel@tonic-gate 	register int		p, pp;
16600Sstevel@tonic-gate 	register caddr_t	bufp;
16610Sstevel@tonic-gate 	register smr_slab_t	*sp;
16620Sstevel@tonic-gate 
16630Sstevel@tonic-gate 	ASSERT(IDN_GLOCK_IS_EXCL());
16640Sstevel@tonic-gate 	ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID);
16650Sstevel@tonic-gate 
16660Sstevel@tonic-gate 	*reserved_area = NULL;
16670Sstevel@tonic-gate 
16680Sstevel@tonic-gate 	nwr_available = MB2B(IDN_NWR_SIZE) - reserved_size;
16690Sstevel@tonic-gate 
16700Sstevel@tonic-gate 	if ((idn.localid != IDN_GET_MASTERID()) ||
16710Sstevel@tonic-gate 	    (nwr_available < IDN_SLAB_SIZE) ||
16720Sstevel@tonic-gate 	    (idn.slabpool != NULL) ||
16730Sstevel@tonic-gate 	    ((reserved_size != 0) && (reserved_size & (IDN_SMR_BUFSIZE-1)))) {
16740Sstevel@tonic-gate 		return (-1);
16750Sstevel@tonic-gate 	}
16760Sstevel@tonic-gate 
16770Sstevel@tonic-gate 	idn.slabpool = GETSTRUCT(struct slabpool, 1);
16780Sstevel@tonic-gate 	idn.slabpool->ntotslabs = ntotslabs = nwr_available / IDN_SLAB_SIZE;
16790Sstevel@tonic-gate 	ASSERT(ntotslabs > 0);
16800Sstevel@tonic-gate 	minperpool = (ntotslabs < IDN_SLAB_MINPERPOOL) ?
16810Sstevel@tonic-gate 						1 : IDN_SLAB_MINPERPOOL;
16820Sstevel@tonic-gate 	idn.slabpool->npools = (ntotslabs + (minperpool - 1)) / minperpool;
16830Sstevel@tonic-gate 
16840Sstevel@tonic-gate 	if ((idn.slabpool->npools & 1) == 0) {
16850Sstevel@tonic-gate 		/*
16860Sstevel@tonic-gate 		 * npools needs to be odd for hashing algorithm.
16870Sstevel@tonic-gate 		 */
16880Sstevel@tonic-gate 		idn.slabpool->npools++;
16890Sstevel@tonic-gate 	}
16900Sstevel@tonic-gate 	ASSERT(idn.slabpool->npools > 0);
16910Sstevel@tonic-gate 	minperpool = (ntotslabs < idn.slabpool->npools) ?
16920Sstevel@tonic-gate 				1 : (ntotslabs / idn.slabpool->npools);
16930Sstevel@tonic-gate 
16940Sstevel@tonic-gate 	/*
16950Sstevel@tonic-gate 	 * Calculate the number of extra slabs that will need to
16960Sstevel@tonic-gate 	 * be alloted to the pools.  This number will be less than
16970Sstevel@tonic-gate 	 * npools.  Only one extra slab is allocated to each pool
16980Sstevel@tonic-gate 	 * until we have assigned all the extra slabs.
16990Sstevel@tonic-gate 	 */
17000Sstevel@tonic-gate 	if (ntotslabs > (idn.slabpool->npools * minperpool))
17010Sstevel@tonic-gate 		nxslabs = ntotslabs - (idn.slabpool->npools * minperpool);
17020Sstevel@tonic-gate 	else
17030Sstevel@tonic-gate 		nxslabs = 0;
17040Sstevel@tonic-gate 	ASSERT((nxslabs >= 0) && (nxslabs < idn.slabpool->npools));
17050Sstevel@tonic-gate 
17060Sstevel@tonic-gate 	idn.slabpool->pool = GETSTRUCT(struct smr_slabtbl,
17070Sstevel@tonic-gate 					idn.slabpool->npools);
17080Sstevel@tonic-gate 	sp = GETSTRUCT(smr_slab_t, idn.slabpool->ntotslabs);
17090Sstevel@tonic-gate 
17100Sstevel@tonic-gate 	idn.slabpool->savep = sp;
17110Sstevel@tonic-gate 	bufp = idn.smr.vaddr + reserved_size;
17120Sstevel@tonic-gate 
17130Sstevel@tonic-gate 	for (p = nslabs = 0;
17140Sstevel@tonic-gate 	    (p < idn.slabpool->npools) && (ntotslabs > 0);
17150Sstevel@tonic-gate 	    p++, ntotslabs -= nslabs) {
17160Sstevel@tonic-gate 
17170Sstevel@tonic-gate 		nslabs = (ntotslabs < minperpool) ? ntotslabs : minperpool;
17180Sstevel@tonic-gate 		if (nxslabs > 0) {
17190Sstevel@tonic-gate 			nslabs++;
17200Sstevel@tonic-gate 			nxslabs--;
17210Sstevel@tonic-gate 		}
17220Sstevel@tonic-gate 		idn.slabpool->pool[p].sarray = sp;
17230Sstevel@tonic-gate 		for (pp = 0; pp < nslabs; pp++) {
17240Sstevel@tonic-gate 
17250Sstevel@tonic-gate 			sp->sl_next  = NULL;
17260Sstevel@tonic-gate 			sp->sl_start = bufp;
17270Sstevel@tonic-gate 			sp->sl_end   = bufp = sp->sl_start + IDN_SLAB_SIZE;
17280Sstevel@tonic-gate 			sp->sl_lock  = 0;
17290Sstevel@tonic-gate 			sp->sl_domid = (short)IDN_NIL_DOMID;
17300Sstevel@tonic-gate 
17310Sstevel@tonic-gate 			sp++;
17320Sstevel@tonic-gate 		}
17330Sstevel@tonic-gate 		idn.slabpool->pool[p].nfree   = nslabs;
17340Sstevel@tonic-gate 		idn.slabpool->pool[p].nslabs  = nslabs;
17350Sstevel@tonic-gate 	}
17360Sstevel@tonic-gate 	ASSERT((ntotslabs == 0) && (nxslabs == 0));
17370Sstevel@tonic-gate 	/*
17380Sstevel@tonic-gate 	 * We should be at the end of the SMR at this point.
17390Sstevel@tonic-gate 	 */
17400Sstevel@tonic-gate 	ASSERT(bufp == (idn.smr.vaddr
17410Sstevel@tonic-gate 			+ reserved_size
17420Sstevel@tonic-gate 			+ (idn.slabpool->ntotslabs * IDN_SLAB_SIZE)));
17430Sstevel@tonic-gate 
17440Sstevel@tonic-gate 	if (reserved_size != 0)
17450Sstevel@tonic-gate 		*reserved_area = idn.smr.vaddr;
17460Sstevel@tonic-gate 
17470Sstevel@tonic-gate 	return (0);
17480Sstevel@tonic-gate }
17490Sstevel@tonic-gate 
17500Sstevel@tonic-gate void
17510Sstevel@tonic-gate smr_slabpool_deinit()
17520Sstevel@tonic-gate {
17530Sstevel@tonic-gate 	if (idn.slabpool == NULL)
17540Sstevel@tonic-gate 		return;
17550Sstevel@tonic-gate 
17560Sstevel@tonic-gate 	FREESTRUCT(idn.slabpool->savep, smr_slab_t, idn.slabpool->ntotslabs);
17570Sstevel@tonic-gate 	FREESTRUCT(idn.slabpool->pool, struct smr_slabtbl,
17580Sstevel@tonic-gate 			idn.slabpool->npools);
17590Sstevel@tonic-gate 	FREESTRUCT(idn.slabpool, struct slabpool, 1);
17600Sstevel@tonic-gate 
17610Sstevel@tonic-gate 	idn.slabpool = NULL;
17620Sstevel@tonic-gate }
17630Sstevel@tonic-gate 
17640Sstevel@tonic-gate void
17650Sstevel@tonic-gate smr_alloc_buflist(smr_slab_t *sp)
17660Sstevel@tonic-gate {
17670Sstevel@tonic-gate 	int		n, nbufs;
17680Sstevel@tonic-gate 	caddr_t		sbufp;
17690Sstevel@tonic-gate 	smr_slabbuf_t	*hp, *bp;
17700Sstevel@tonic-gate 
17710Sstevel@tonic-gate 	if (sp->sl_head)
17720Sstevel@tonic-gate 		return;
17730Sstevel@tonic-gate 
17740Sstevel@tonic-gate 	nbufs = (sp->sl_end - sp->sl_start) / IDN_SMR_BUFSIZE;
17750Sstevel@tonic-gate 	ASSERT(nbufs > 0);
17760Sstevel@tonic-gate 	if (nbufs <= 0) {
17770Sstevel@tonic-gate 		sp->sl_head = sp->sl_free = sp->sl_inuse = NULL;
17780Sstevel@tonic-gate 		return;
17790Sstevel@tonic-gate 	}
17800Sstevel@tonic-gate 
17810Sstevel@tonic-gate 	hp = GETSTRUCT(smr_slabbuf_t, nbufs);
17820Sstevel@tonic-gate 
17830Sstevel@tonic-gate 	sbufp = sp->sl_start;
17840Sstevel@tonic-gate 	for (n = 0, bp = hp; n < nbufs; bp++, n++) {
17850Sstevel@tonic-gate 		bp->sb_bufp = sbufp;
17860Sstevel@tonic-gate 		bp->sb_domid = IDN_NIL_DOMID;
17870Sstevel@tonic-gate 		bp->sb_next = bp + 1;
17880Sstevel@tonic-gate 		sbufp += IDN_SMR_BUFSIZE;
17890Sstevel@tonic-gate 	}
17900Sstevel@tonic-gate 	(--bp)->sb_next = NULL;
17910Sstevel@tonic-gate 
17920Sstevel@tonic-gate 	sp->sl_head = sp->sl_free = hp;
17930Sstevel@tonic-gate 	sp->sl_inuse = NULL;
17940Sstevel@tonic-gate }
17950Sstevel@tonic-gate 
17960Sstevel@tonic-gate void
17970Sstevel@tonic-gate smr_free_buflist(smr_slab_t *sp)
17980Sstevel@tonic-gate {
17990Sstevel@tonic-gate 	int	nbufs;
18000Sstevel@tonic-gate 
18010Sstevel@tonic-gate 	if (sp->sl_head == NULL)
18020Sstevel@tonic-gate 		return;
18030Sstevel@tonic-gate 
18040Sstevel@tonic-gate 	nbufs = (sp->sl_end - sp->sl_start) / IDN_SMR_BUFSIZE;
18050Sstevel@tonic-gate 
18060Sstevel@tonic-gate 	FREESTRUCT(sp->sl_head, smr_slabbuf_t, nbufs);
18070Sstevel@tonic-gate 
18080Sstevel@tonic-gate 	sp->sl_head = sp->sl_free = sp->sl_inuse = NULL;
18090Sstevel@tonic-gate }
18100Sstevel@tonic-gate 
18110Sstevel@tonic-gate /*
18120Sstevel@tonic-gate  * Returns:	0 Successfully located a slab.
18130Sstevel@tonic-gate  *	       -1 Failure.
18140Sstevel@tonic-gate  */
18150Sstevel@tonic-gate static smr_slab_t *
18160Sstevel@tonic-gate smr_slab_reserve(int domid)
18170Sstevel@tonic-gate {
18180Sstevel@tonic-gate 	register int		p, nextp, s, nexts;
18190Sstevel@tonic-gate 	register smr_slab_t	*spa;
18200Sstevel@tonic-gate 	int			startp, starts;
18210Sstevel@tonic-gate 	int			foundone = 0;
18220Sstevel@tonic-gate 	int			spl;
18230Sstevel@tonic-gate 	procname_t		proc = "smr_slab_reserve";
18240Sstevel@tonic-gate 
18250Sstevel@tonic-gate 	p = startp = SMR_SLABPOOL_HASH(domid);
18260Sstevel@tonic-gate 	nextp = -1;
18270Sstevel@tonic-gate 
18280Sstevel@tonic-gate 	spl = splhi();
18290Sstevel@tonic-gate 	while ((nextp != startp) && !foundone) {
18300Sstevel@tonic-gate 
18310Sstevel@tonic-gate 		s = starts = SMR_SLAB_HASH(p, domid);
18320Sstevel@tonic-gate 		nexts = -1;
18330Sstevel@tonic-gate 		spa = &(idn.slabpool->pool[p].sarray[0]);
18340Sstevel@tonic-gate 
18350Sstevel@tonic-gate 		while ((nexts != starts) && !foundone) {
18360Sstevel@tonic-gate 			if (lock_try(&spa[s].sl_lock)) {
18370Sstevel@tonic-gate 				foundone = 1;
18380Sstevel@tonic-gate 				break;
18390Sstevel@tonic-gate 			}
18400Sstevel@tonic-gate 			nexts = SMR_SLAB_HASHSTEP(p, s);
18410Sstevel@tonic-gate 			s = nexts;
18420Sstevel@tonic-gate 		}
18430Sstevel@tonic-gate 		if (foundone)
18440Sstevel@tonic-gate 			break;
18450Sstevel@tonic-gate 		nextp = SMR_SLABPOOL_HASHSTEP(p);
18460Sstevel@tonic-gate 		p = nextp;
18470Sstevel@tonic-gate 	}
18480Sstevel@tonic-gate 	splx(spl);
18490Sstevel@tonic-gate 
18500Sstevel@tonic-gate 	if (foundone) {
18510Sstevel@tonic-gate 		ASSERT((&spa[s] >= idn.slabpool->savep) &&
18520Sstevel@tonic-gate 			(&spa[s] < (idn.slabpool->savep +
18530Sstevel@tonic-gate 					idn.slabpool->ntotslabs)));
18540Sstevel@tonic-gate 
18550Sstevel@tonic-gate 		spa[s].sl_domid = (short)domid;
18560Sstevel@tonic-gate 
18570Sstevel@tonic-gate 		ATOMIC_DEC(idn.slabpool->pool[p].nfree);
18580Sstevel@tonic-gate 
18590Sstevel@tonic-gate 		if (domid == idn.localid) {
18600Sstevel@tonic-gate 			smr_slab_t	*nsp;
18610Sstevel@tonic-gate 			/*
18620Sstevel@tonic-gate 			 * Caller is actually reserving a slab for
18630Sstevel@tonic-gate 			 * themself which means they'll need the full
18640Sstevel@tonic-gate 			 * slab structure to represent all of the I/O
18650Sstevel@tonic-gate 			 * buffers.  The "spa" is just a representative
18660Sstevel@tonic-gate 			 * and doesn't contain the space to manage the
18670Sstevel@tonic-gate 			 * individual buffers.  Need to alloc a full-size
18680Sstevel@tonic-gate 			 * struct.
18690Sstevel@tonic-gate 			 * Note that this results in the returning
18700Sstevel@tonic-gate 			 * smr_slab_t structure being unlocked.
18710Sstevel@tonic-gate 			 */
18720Sstevel@tonic-gate 			ASSERT(idn.localid == IDN_GET_MASTERID());
18730Sstevel@tonic-gate 			nsp = GETSTRUCT(smr_slab_t, 1);
18740Sstevel@tonic-gate 			nsp->sl_start = spa[s].sl_start;
18750Sstevel@tonic-gate 			nsp->sl_end   = spa[s].sl_end;
18760Sstevel@tonic-gate 			smr_alloc_buflist(nsp);
18770Sstevel@tonic-gate 			spa = nsp;
18780Sstevel@tonic-gate 			PR_SMR("%s: allocated full slab struct for domain %d\n",
18790Sstevel@tonic-gate 				proc, domid);
18800Sstevel@tonic-gate 		} else {
18810Sstevel@tonic-gate 			/*
18820Sstevel@tonic-gate 			 * Slab structure gets returned locked.
18830Sstevel@tonic-gate 			 */
18840Sstevel@tonic-gate 			spa += s;
18850Sstevel@tonic-gate 		}
18860Sstevel@tonic-gate 
1887*931Smathue 		PR_SMR("%s: allocated slab 0x%p (start=0x%p, size=%lu) for "
1888*931Smathue 			"domain %d\n", proc, spa, spa->sl_start,
18890Sstevel@tonic-gate 			spa->sl_end - spa->sl_start, domid);
18900Sstevel@tonic-gate 	} else {
18910Sstevel@tonic-gate 		PR_SMR("%s: FAILED to allocate for domain %d\n",
18920Sstevel@tonic-gate 			proc, domid);
18930Sstevel@tonic-gate 		spa = NULL;
18940Sstevel@tonic-gate 	}
18950Sstevel@tonic-gate 
18960Sstevel@tonic-gate 	return (spa);
18970Sstevel@tonic-gate }
18980Sstevel@tonic-gate 
18990Sstevel@tonic-gate static void
19000Sstevel@tonic-gate smr_slab_unreserve(int domid, smr_slab_t *sp)
19010Sstevel@tonic-gate {
19020Sstevel@tonic-gate 	register int		p, nextp, s, nexts;
19030Sstevel@tonic-gate 	register smr_slab_t	*spa;
19040Sstevel@tonic-gate 	int			foundit = 0;
19050Sstevel@tonic-gate 	int			startp, starts;
19060Sstevel@tonic-gate 	caddr_t			bufp;
19070Sstevel@tonic-gate 	procname_t		proc = "smr_slab_unreserve";
19080Sstevel@tonic-gate 
19090Sstevel@tonic-gate 	bufp = sp->sl_start;
19100Sstevel@tonic-gate 	p = startp = SMR_SLABPOOL_HASH(domid);
19110Sstevel@tonic-gate 	nextp = -1;
19120Sstevel@tonic-gate 
19130Sstevel@tonic-gate 	while ((nextp != startp) && !foundit) {
19140Sstevel@tonic-gate 
19150Sstevel@tonic-gate 		s = starts = SMR_SLAB_HASH(p, domid);
19160Sstevel@tonic-gate 		nexts = -1;
19170Sstevel@tonic-gate 		spa = &(idn.slabpool->pool[p].sarray[0]);
19180Sstevel@tonic-gate 
19190Sstevel@tonic-gate 		while ((nexts != starts) && !foundit) {
19200Sstevel@tonic-gate 			if (spa[s].sl_start == bufp) {
19210Sstevel@tonic-gate 				foundit = 1;
19220Sstevel@tonic-gate 				break;
19230Sstevel@tonic-gate 			}
19240Sstevel@tonic-gate 			nexts = SMR_SLAB_HASHSTEP(p, s);
19250Sstevel@tonic-gate 			s = nexts;
19260Sstevel@tonic-gate 		}
19270Sstevel@tonic-gate 		if (foundit)
19280Sstevel@tonic-gate 			break;
19290Sstevel@tonic-gate 		nextp = SMR_SLABPOOL_HASHSTEP(p);
19300Sstevel@tonic-gate 		p = nextp;
19310Sstevel@tonic-gate 	}
19320Sstevel@tonic-gate 	if (foundit) {
19330Sstevel@tonic-gate 		ASSERT((&spa[s] >= idn.slabpool->savep) &&
19340Sstevel@tonic-gate 			(&spa[s] < (idn.slabpool->savep +
19350Sstevel@tonic-gate 					idn.slabpool->ntotslabs)));
19360Sstevel@tonic-gate 		ASSERT(!lock_try(&spa[s].sl_lock));
19370Sstevel@tonic-gate 		ASSERT(spa[s].sl_domid == (short)domid);
19380Sstevel@tonic-gate 
19390Sstevel@tonic-gate 		spa[s].sl_next = NULL;
19400Sstevel@tonic-gate 		spa[s].sl_domid = (short)IDN_NIL_DOMID;
19410Sstevel@tonic-gate 		lock_clear(&spa[s].sl_lock);
19420Sstevel@tonic-gate 
19430Sstevel@tonic-gate 		ATOMIC_INC(idn.slabpool->pool[p].nfree);
19440Sstevel@tonic-gate 
1945*931Smathue 		PR_SMR("%s: freed (bufp=0x%p) for domain %d\n",
1946*931Smathue 			proc, bufp, domid);
19470Sstevel@tonic-gate 
19480Sstevel@tonic-gate 		if (domid == idn.localid) {
19490Sstevel@tonic-gate 			/*
19500Sstevel@tonic-gate 			 * Caller is actually unreserving a slab of their
19510Sstevel@tonic-gate 			 * own.  Note that only the master calls this
19520Sstevel@tonic-gate 			 * routine.  Since the master's local slab
19530Sstevel@tonic-gate 			 * structures do not get entered into the global
19540Sstevel@tonic-gate 			 * "representative" pool, we need to free up the
19550Sstevel@tonic-gate 			 * data structure that was passed in.
19560Sstevel@tonic-gate 			 */
19570Sstevel@tonic-gate 			ASSERT(idn.localid == IDN_GET_MASTERID());
19580Sstevel@tonic-gate 			ASSERT(sp != &spa[s]);
19590Sstevel@tonic-gate 
19600Sstevel@tonic-gate 			smr_free_buflist(sp);
19610Sstevel@tonic-gate 			FREESTRUCT(sp, smr_slab_t, 1);
19620Sstevel@tonic-gate 		} else {
19630Sstevel@tonic-gate 			ASSERT(sp == &spa[s]);
19640Sstevel@tonic-gate 		}
19650Sstevel@tonic-gate 	} else {
19660Sstevel@tonic-gate 		/*
19670Sstevel@tonic-gate 		 * Couldn't find slab entry for given buf!
19680Sstevel@tonic-gate 		 */
1969*931Smathue 		PR_SMR("%s: FAILED to free (bufp=0x%p) for domain %d\n",
1970*931Smathue 			proc, bufp, domid);
19710Sstevel@tonic-gate 	}
19720Sstevel@tonic-gate }
19730Sstevel@tonic-gate 
19740Sstevel@tonic-gate /*
19750Sstevel@tonic-gate  * The Reap Protocol:
19760Sstevel@tonic-gate  *	master				   slave
19770Sstevel@tonic-gate  *	------				   -----
19780Sstevel@tonic-gate  *	smr_slab_reap_global
19790Sstevel@tonic-gate  *	- idn_broadcast_cmd(SLABREAP) ->   idn_recv_cmd(SLABREAP)
19800Sstevel@tonic-gate  *	  . idn_local_cmd(SLABREAP)        - idn_recv_slabreap_req
19810Sstevel@tonic-gate  *	    - smr_slab_reap	             . smr_slab_reap
19820Sstevel@tonic-gate  *	      . smr_slaballoc_get_n            - smr_slaballoc_get_n
19830Sstevel@tonic-gate  *	      . smr_slab_free		       - smr_slab_free
19840Sstevel@tonic-gate  *		- smr_slab_free_local		 . smr_slab_free_remote
19850Sstevel@tonic-gate  *		  . smr_slab_unreserve
19860Sstevel@tonic-gate  *				      <-	   - idn_send_cmd(SLABFREE)
19870Sstevel@tonic-gate  *	idn_recv_cmd(SLABFREE)
19880Sstevel@tonic-gate  *	- idn_recv_slabfree_req
19890Sstevel@tonic-gate  *	  . smr_slaballoc_get
19900Sstevel@tonic-gate  *	  . smr_slab_free
19910Sstevel@tonic-gate  *	    - smr_slab_free_local
19920Sstevel@tonic-gate  *	      . smr_slab_unreserve
19930Sstevel@tonic-gate  *        . idn_send_slabfree_resp    ->   idn_recv_cmd(SLABFREE | ack)
19940Sstevel@tonic-gate  *					   - idn_recv_slabfree_resp
19950Sstevel@tonic-gate  *
19960Sstevel@tonic-gate  *	idn_recv_cmd(SLABREAP | ack)  <-     . idn_send_slabreap_resp
19970Sstevel@tonic-gate  *	- idn_recv_slabreap_resp	   DONE
19980Sstevel@tonic-gate  *	DONE
19990Sstevel@tonic-gate  *
20000Sstevel@tonic-gate  * Check available slabs and if we're below the threshold, kick
20010Sstevel@tonic-gate  * off reaping to all remote domains.  There is no guarantee remote
20020Sstevel@tonic-gate  * domains will be able to free up any.
20030Sstevel@tonic-gate  */
20040Sstevel@tonic-gate static void
20050Sstevel@tonic-gate smr_slab_reap_global()
20060Sstevel@tonic-gate {
20070Sstevel@tonic-gate 	register int	p, npools;
20080Sstevel@tonic-gate 	register int	total_free = 0;
20090Sstevel@tonic-gate 	register struct smr_slabtbl	*tblp;
20100Sstevel@tonic-gate 	static clock_t	reap_last = 0;
20110Sstevel@tonic-gate 	procname_t	proc = "smr_slab_reap_global";
20120Sstevel@tonic-gate 
20130Sstevel@tonic-gate 	ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID);
20140Sstevel@tonic-gate 
20150Sstevel@tonic-gate 	DSLAB_LOCK_SHARED(idn.localid);
20160Sstevel@tonic-gate 	if (idn_domain[idn.localid].dslab_state != DSLAB_STATE_LOCAL) {
20170Sstevel@tonic-gate 		PR_SMR("%s: only allowed by master (%d)\n",
20180Sstevel@tonic-gate 			proc, IDN_GET_MASTERID());
20190Sstevel@tonic-gate 		DSLAB_UNLOCK(idn.localid);
20200Sstevel@tonic-gate 		return;
20210Sstevel@tonic-gate 	}
20220Sstevel@tonic-gate 	DSLAB_UNLOCK(idn.localid);
20230Sstevel@tonic-gate 
20240Sstevel@tonic-gate 	if ((lbolt > 0) && (lbolt > reap_last) &&
20250Sstevel@tonic-gate 			((lbolt - reap_last) < IDN_REAP_INTERVAL))
20260Sstevel@tonic-gate 		return;
20270Sstevel@tonic-gate 
20280Sstevel@tonic-gate 	reap_last = lbolt;
20290Sstevel@tonic-gate 
20300Sstevel@tonic-gate 	ASSERT(idn.slabpool);
20310Sstevel@tonic-gate 
20320Sstevel@tonic-gate 	npools = idn.slabpool->npools;
20330Sstevel@tonic-gate 	tblp   = idn.slabpool->pool;
20340Sstevel@tonic-gate 
20350Sstevel@tonic-gate 	for (p = 0; p < npools; tblp++, p++)
20360Sstevel@tonic-gate 		total_free += tblp->nfree;
20370Sstevel@tonic-gate 
20380Sstevel@tonic-gate 	if (total_free <= IDN_SLAB_THRESHOLD) {
20390Sstevel@tonic-gate 		int	diff, reap_per_domain;
20400Sstevel@tonic-gate 
20410Sstevel@tonic-gate 		PR_SMR("%s: kicking off reaping "
2042*931Smathue 			"(total_free = %d, min = %d)\n",
20430Sstevel@tonic-gate 			proc, total_free, IDN_SLAB_THRESHOLD);
20440Sstevel@tonic-gate 
20450Sstevel@tonic-gate 		diff = IDN_SLAB_THRESHOLD - total_free;
20460Sstevel@tonic-gate 		reap_per_domain = (diff < idn.ndomains)
20470Sstevel@tonic-gate 					? 1 : (diff / idn.ndomains);
20480Sstevel@tonic-gate 
20490Sstevel@tonic-gate 		idn_broadcast_cmd(IDNCMD_SLABREAP, reap_per_domain, 0, 0);
20500Sstevel@tonic-gate 	}
20510Sstevel@tonic-gate }
20520Sstevel@tonic-gate 
20530Sstevel@tonic-gate void
20540Sstevel@tonic-gate smr_slab_reap(int domid, int *nslabs)
20550Sstevel@tonic-gate {
20560Sstevel@tonic-gate 	register int	d;
20570Sstevel@tonic-gate 	int		nreclaimed;
20580Sstevel@tonic-gate 	smr_slab_t	*sp;
20590Sstevel@tonic-gate 	domainset_t	reapset;
20600Sstevel@tonic-gate 	procname_t	proc = "smr_slab_reap";
20610Sstevel@tonic-gate 
20620Sstevel@tonic-gate 	/*
20630Sstevel@tonic-gate 	 * Should only be called on behalf of local
20640Sstevel@tonic-gate 	 * domain.
20650Sstevel@tonic-gate 	 */
20660Sstevel@tonic-gate 	if (domid != idn.localid) {
20670Sstevel@tonic-gate 		PR_SMR("%s: called by domain %d, should only be local (%d)\n",
20680Sstevel@tonic-gate 			proc, domid, idn.localid);
20690Sstevel@tonic-gate 		ASSERT(0);
20700Sstevel@tonic-gate 		return;
20710Sstevel@tonic-gate 	}
20720Sstevel@tonic-gate 	/*
20730Sstevel@tonic-gate 	 * Try and reclaim some buffers so we can possibly
20740Sstevel@tonic-gate 	 * free up some slabs.
20750Sstevel@tonic-gate 	 */
20760Sstevel@tonic-gate 	reapset = idn.domset.ds_connected;
20770Sstevel@tonic-gate 
20780Sstevel@tonic-gate 	IDN_GKSTAT_GLOBAL_EVENT(gk_reaps, gk_reap_last);
20790Sstevel@tonic-gate 
20800Sstevel@tonic-gate 	nreclaimed = 0;
20810Sstevel@tonic-gate 	for (d = 0; d < MAX_DOMAINS; d++) {
20820Sstevel@tonic-gate 		int		nr;
20830Sstevel@tonic-gate 		idn_domain_t	*dp;
20840Sstevel@tonic-gate 
20850Sstevel@tonic-gate 		if (!DOMAIN_IN_SET(reapset, d))
20860Sstevel@tonic-gate 			continue;
20870Sstevel@tonic-gate 
20880Sstevel@tonic-gate 		IDN_DLOCK_SHARED(d);
20890Sstevel@tonic-gate 
20900Sstevel@tonic-gate 		dp = &idn_domain[d];
20910Sstevel@tonic-gate 		if ((d == idn.localid) || (dp->dcpu < 0)) {
20920Sstevel@tonic-gate 			IDN_DUNLOCK(d);
20930Sstevel@tonic-gate 			continue;
20940Sstevel@tonic-gate 		}
20950Sstevel@tonic-gate 		/*
20960Sstevel@tonic-gate 		 * Clean up any dead I/O errors if possible.
20970Sstevel@tonic-gate 		 */
20980Sstevel@tonic-gate 		if (dp->dioerr > 0) {
20990Sstevel@tonic-gate 			idn_domain_t	*ldp;
21000Sstevel@tonic-gate 			register int	cnt;
21010Sstevel@tonic-gate 			register smr_slabbuf_t	*bp;
21020Sstevel@tonic-gate 			/*
21030Sstevel@tonic-gate 			 * We need to grab the writer lock to prevent
21040Sstevel@tonic-gate 			 * anybody from allocating buffers while we
21050Sstevel@tonic-gate 			 * traverse the slabs outstanding.
21060Sstevel@tonic-gate 			 */
21070Sstevel@tonic-gate 			cnt = 0;
21080Sstevel@tonic-gate 			ldp = &idn_domain[idn.localid];
21090Sstevel@tonic-gate 			IDN_DLOCK_EXCL(idn.localid);
21100Sstevel@tonic-gate 			DSLAB_LOCK_EXCL(idn.localid);
21110Sstevel@tonic-gate 			for (sp = ldp->dslab; sp; sp = sp->sl_next)
21120Sstevel@tonic-gate 				for (bp = sp->sl_inuse; bp; bp = bp->sb_next)
21130Sstevel@tonic-gate 					if (bp->sb_domid == d)
21140Sstevel@tonic-gate 						cnt++;
21150Sstevel@tonic-gate 			DSLAB_UNLOCK(idn.localid);
21160Sstevel@tonic-gate 			ASSERT((dp->dio + dp->dioerr) >= cnt);
21170Sstevel@tonic-gate 			dp->dio = cnt;
21180Sstevel@tonic-gate 			dp->dioerr = 0;
21190Sstevel@tonic-gate 			IDN_DUNLOCK(idn.localid);
21200Sstevel@tonic-gate 		}
21210Sstevel@tonic-gate 		if ((dp->dstate == IDNDS_CONNECTED) &&
21220Sstevel@tonic-gate 				((nr = idn_reclaim_mboxdata(d, 0, -1)) > 0))
21230Sstevel@tonic-gate 			nreclaimed += nr;
21240Sstevel@tonic-gate 
21250Sstevel@tonic-gate 		IDN_DUNLOCK(d);
21260Sstevel@tonic-gate 	}
21270Sstevel@tonic-gate 
21280Sstevel@tonic-gate 	DSLAB_LOCK_EXCL(domid);
21290Sstevel@tonic-gate 	sp = smr_slaballoc_get_n(domid, nslabs);
21300Sstevel@tonic-gate 	if (sp) {
21310Sstevel@tonic-gate 		IDN_GKSTAT_ADD(gk_reap_count, (ulong_t)(*nslabs));
21320Sstevel@tonic-gate 		smr_slab_free(domid, sp);
21330Sstevel@tonic-gate 	}
21340Sstevel@tonic-gate 	DSLAB_UNLOCK(domid);
21350Sstevel@tonic-gate }
21360Sstevel@tonic-gate 
21370Sstevel@tonic-gate /*
21380Sstevel@tonic-gate  * ---------------------------------------------------------------------
21390Sstevel@tonic-gate  * Remap the (IDN) shared memory region to a new physical address.
21400Sstevel@tonic-gate  * Caller is expected to have performed a ecache flush if needed.
21410Sstevel@tonic-gate  * ---------------------------------------------------------------------
21420Sstevel@tonic-gate  */
21430Sstevel@tonic-gate void
21440Sstevel@tonic-gate smr_remap(struct as *as, register caddr_t vaddr,
21450Sstevel@tonic-gate 		register pfn_t new_pfn, uint_t mblen)
21460Sstevel@tonic-gate {
21470Sstevel@tonic-gate 	tte_t		tte;
21480Sstevel@tonic-gate 	size_t		blen;
21490Sstevel@tonic-gate 	pgcnt_t		p, npgs;
21500Sstevel@tonic-gate 	procname_t	proc = "smr_remap";
21510Sstevel@tonic-gate 
21520Sstevel@tonic-gate 	if (va_to_pfn(vaddr) == new_pfn) {
2153*931Smathue 		PR_REMAP("%s: vaddr (0x%p) already mapped to pfn (0x%lx)\n",
2154*931Smathue 			proc, vaddr, new_pfn);
21550Sstevel@tonic-gate 		return;
21560Sstevel@tonic-gate 	}
21570Sstevel@tonic-gate 
21580Sstevel@tonic-gate 	blen = MB2B(mblen);
21590Sstevel@tonic-gate 	npgs = btopr(blen);
21600Sstevel@tonic-gate 	ASSERT(npgs != 0);
21610Sstevel@tonic-gate 
2162*931Smathue 	PR_REMAP("%s: va = 0x%p, pfn = 0x%lx, npgs = %ld, mb = %d MB (%ld)\n",
2163*931Smathue 		proc, vaddr, new_pfn, npgs, mblen, blen);
21640Sstevel@tonic-gate 
21650Sstevel@tonic-gate 	/*
21660Sstevel@tonic-gate 	 * Unmap the SMR virtual address from it's current
21670Sstevel@tonic-gate 	 * mapping.
21680Sstevel@tonic-gate 	 */
21690Sstevel@tonic-gate 	hat_unload(as->a_hat, vaddr, blen, HAT_UNLOAD_UNLOCK);
21700Sstevel@tonic-gate 
21710Sstevel@tonic-gate 	if (new_pfn == PFN_INVALID)
21720Sstevel@tonic-gate 		return;
21730Sstevel@tonic-gate 
21740Sstevel@tonic-gate 	/*
21750Sstevel@tonic-gate 	 * Map the SMR to the new physical address space,
21760Sstevel@tonic-gate 	 * presumably a remote pfn.  Cannot use hat_devload
21770Sstevel@tonic-gate 	 * because it will think pfn represents non-memory,
21780Sstevel@tonic-gate 	 * i.e. space since it may beyond his physmax.
21790Sstevel@tonic-gate 	 */
21800Sstevel@tonic-gate 	for (p = 0; p < npgs; p++) {
21810Sstevel@tonic-gate 		sfmmu_memtte(&tte, new_pfn,
21820Sstevel@tonic-gate 				PROT_READ | PROT_WRITE | HAT_NOSYNC,
21830Sstevel@tonic-gate 				TTE8K);
21840Sstevel@tonic-gate 		sfmmu_tteload(as->a_hat, &tte, vaddr, NULL, HAT_LOAD_LOCK);
21850Sstevel@tonic-gate 
21860Sstevel@tonic-gate 		vaddr += MMU_PAGESIZE;
21870Sstevel@tonic-gate 		new_pfn++;
21880Sstevel@tonic-gate 	}
21890Sstevel@tonic-gate 
21900Sstevel@tonic-gate 	PR_REMAP("%s: remapped %ld pages (expected %ld)\n",
21910Sstevel@tonic-gate 		proc, npgs, btopr(MB2B(mblen)));
21920Sstevel@tonic-gate }
2193