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