xref: /titanic_44/usr/src/uts/sun4u/starfire/io/idn_smr.c (revision 07d06da50d310a325b457d6330165aebab1e0064)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Inter-Domain Network
27  *
28  * Shared Memory Region (SMR) supporting code.
29  */
30 
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/machparam.h>
34 #include <sys/debug.h>
35 #include <sys/cpuvar.h>
36 #include <sys/kmem.h>
37 #include <sys/mutex.h>
38 #include <sys/rwlock.h>
39 #include <sys/systm.h>
40 #include <sys/machlock.h>
41 #include <sys/membar.h>
42 #include <sys/mman.h>
43 #include <vm/hat.h>
44 #include <vm/as.h>
45 #include <vm/hat_sfmmu.h>
46 #include <sys/vm_machparam.h>
47 #include <sys/x_call.h>
48 
49 #include <sys/idn.h>
50 
51 #ifdef DEBUG
52 #define	DIOCHECK(domid) \
53 { \
54 	int	_dio; \
55 	if ((_dio = idn_domain[domid].dio) < 0) { \
56 		cmn_err(CE_WARN, \
57 			">>>>> file %s, line %d: domain %d, dio = %d", \
58 			__FILE__, __LINE__, (domid), _dio); \
59 	} \
60 }
61 #else
62 #define	DIOCHECK(domid)
63 #endif /* DEBUG */
64 
65 static int	smr_slab_alloc_local(int domid, smr_slab_t **spp);
66 static int	smr_slab_alloc_remote(int domid, smr_slab_t **spp);
67 static void	smr_slab_free_local(int domid, smr_slab_t *sp);
68 static void	smr_slab_free_remote(int domid, smr_slab_t *sp);
69 static int 	smr_slabwaiter_register(int domid);
70 static int 	smr_slabwaiter_unregister(int domid, smr_slab_t **spp);
71 static int 	smr_slaballoc_wait(int domid, smr_slab_t **spp);
72 static smr_slab_t 	*smr_slab_reserve(int domid);
73 static void 	smr_slab_unreserve(int domid, smr_slab_t *sp);
74 static void	smr_slab_reap_global();
75 
76 /*
77  * Can only be called by the master.  Allocate a slab from the
78  * local pool representing the SMR, on behalf of the given
79  * domain.  Slab is either being requested for use by the
80  * local domain (i.e. domid == idn.localid), or it's being
81  * allocated to give to a remote domain which requested one.
82  * In the base of allocating on behalf of a remote domain,
83  * smr_slab_t structure is used simply to manage ownership.
84  *
85  * Returns:	smr_slaballoc_wait
86  * 		(EINVAL, ETIMEDOUT)
87  *		smr_slabwatier_unregister
88  *		(0, EINVAL, EBUSY, ENOMEM)
89  *		ENOLCK
90  */
91 static int
smr_slab_alloc_local(int domid,smr_slab_t ** spp)92 smr_slab_alloc_local(int domid, smr_slab_t **spp)
93 {
94 	int		serrno = 0;
95 	int		nwait;
96 	smr_slab_t	*sp;
97 	idn_domain_t	*dp;
98 
99 
100 	/*
101 	 * Only the master can make local allocations.
102 	 */
103 	ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID);
104 	ASSERT(idn.localid == IDN_GET_MASTERID());
105 
106 	*spp = NULL;
107 
108 	dp = &idn_domain[domid];
109 	ASSERT(DSLAB_READ_HELD(domid));
110 	ASSERT(dp->dslab_state == DSLAB_STATE_LOCAL);
111 
112 	/*
113 	 * Register myself with the waiting list.
114 	 */
115 	nwait = smr_slabwaiter_register(domid);
116 
117 	if (nwait > 1) {
118 		/*
119 		 * XXX - old comment?
120 		 * Need to drop the read lock _after_ registering
121 		 * ourselves with the potential wait list for this allocation.
122 		 * Although this allocation is not a remote one, we could
123 		 * still have multiple threads on the master trying to
124 		 * satisfy (allocate) request on behalf of a remote domain.
125 		 */
126 		/*
127 		 * Somebody is already in the process of satisfying
128 		 * the allocation request for this respective
129 		 * domain.  All we need to do is wait and let
130 		 * it happen.
131 		 */
132 		serrno = smr_slaballoc_wait(domid, spp);
133 		return (serrno);
134 	}
135 	/*
136 	 * I'm the original slab requester for this domain.  It's local
137 	 * so go ahead and do the job.
138 	 */
139 
140 	if ((sp = smr_slab_reserve(domid)) == NULL)
141 		serrno = ENOMEM;
142 
143 	/*
144 	 * Allocation may have failed.  In either case we've
145 	 * got to do the put to at least wake potential waiters up.
146 	 */
147 	if (!serrno) {
148 		if (DSLAB_LOCK_TRYUPGRADE(domid) == 0) {
149 			DSLAB_UNLOCK(domid);
150 			DSLAB_LOCK_EXCL(domid);
151 		}
152 	}
153 
154 	(void) smr_slaballoc_put(domid, sp, 0, serrno);
155 
156 	/*
157 	 * If serrno is ENOLCK here, then we must have failed
158 	 * on the upgrade above, so lock already dropped.
159 	 */
160 	if (serrno != ENOLCK) {
161 		/*
162 		 * Need to drop since reaping may be recursive?
163 		 */
164 		DSLAB_UNLOCK(domid);
165 	}
166 
167 	/*
168 	 * Since we were the original requester but never went
169 	 * to sleep, we need to directly unregister ourselves
170 	 * from the waiting list.
171 	 */
172 	serrno = smr_slabwaiter_unregister(domid, spp);
173 
174 	/*
175 	 * Now that we've satisfied the request, let's check if any
176 	 * reaping is necessary.  Only the master does this and only
177 	 * when allocating slabs, an infrequent event :-o
178 	 */
179 	smr_slab_reap_global();
180 
181 	ASSERT((serrno == 0) ? (*spp != NULL) : (*spp == NULL));
182 
183 	DSLAB_LOCK_SHARED(domid);
184 
185 	return (serrno);
186 }
187 
188 /*
189  * Can only be called by a slave on behalf of himself.  Need to
190  * make a request to the master to allocate a slab of SMR buffers
191  * for the local domain.
192  *
193  * Returns:	smr_slaballoc_wait
194  *		(0, EINVAL, EBUSY, ENOMEM)
195  *		ENOLCK
196  *		ECANCELED
197  */
198 static int
smr_slab_alloc_remote(int domid,smr_slab_t ** spp)199 smr_slab_alloc_remote(int domid, smr_slab_t **spp)
200 {
201 	int		nwait;
202 	int		serrno = 0;
203 	int		bailout = 0;
204 	int		masterid;
205 	idn_domain_t	*dp, *mdp = NULL;
206 	procname_t	proc = "smr_slab_alloc_remote";
207 
208 	/*
209 	 * Only slaves make remote allocations.
210 	 */
211 	ASSERT(idn.localid != IDN_GET_MASTERID());
212 	ASSERT(domid == idn.localid);
213 	ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID);
214 
215 	*spp = NULL;
216 
217 	dp = &idn_domain[domid];
218 	ASSERT(DSLAB_READ_HELD(domid));
219 	ASSERT(dp->dslab_state == DSLAB_STATE_REMOTE);
220 
221 	/*
222 	 * Register myself with the slaballoc waiting list.
223 	 * Note that only allow one outstanding allocation
224 	 * request for the given domain.  Other callers which
225 	 * detect a slab is needed simply get stuck on the
226 	 * waiting list waiting for the original caller to
227 	 * get the job done.
228 	 * The waiter_register routine will allocate the necessary
229 	 * slab structure which will ultimately be inserted in
230 	 * the domain's slab list via smr_slaballoc_put().
231 	 */
232 	nwait = smr_slabwaiter_register(domid);
233 
234 	/*
235 	 * Make sure we have a connection with the master
236 	 * before we wait around for nothing and send a
237 	 * command off to nowhere.
238 	 * First do a quick (no lock) check for global okayness.
239 	 */
240 	if ((idn.state != IDNGS_ONLINE) ||
241 	    ((masterid = IDN_GET_MASTERID()) == IDN_NIL_DOMID)) {
242 		bailout = 1;
243 		serrno = ECANCELED;
244 	}
245 	/*
246 	 * We need to drop our read lock _before_ acquiring the
247 	 * slaballoc waiter lock.  This is necessary because the
248 	 * thread that receives the slab alloc response and fills
249 	 * in the slab structure will need to grab the domain write
250 	 * lock while holding onto the slaballoc waiter lock.
251 	 * Potentially could deadlock if we didn't drop our domain
252 	 * lock before.  Plus, we've registered.
253 	 *
254 	 * 4093209 - Note also that we do this _after_ the check for
255 	 *	idn.masterid where we grab the READER global
256 	 *	lock.  This is to prevent somebody from
257 	 *	changing our state after we drop the drwlock.
258 	 *	A deadlock can occur when shutting down a
259 	 *	domain we're holding the
260 	 */
261 
262 	if (!bailout) {
263 		mdp = &idn_domain[masterid];
264 		/*
265 		 * Global state is okay.  Let's double check the
266 		 * state of our actual target domain.
267 		 */
268 		if (mdp->dstate != IDNDS_CONNECTED) {
269 			bailout = 1;
270 			serrno = ECANCELED;
271 		} else if (IDN_DLOCK_TRY_SHARED(masterid)) {
272 			if (mdp->dstate != IDNDS_CONNECTED) {
273 				bailout = 1;
274 				serrno = ECANCELED;
275 				IDN_DUNLOCK(masterid);
276 			} else if (nwait != 1) {
277 				IDN_DUNLOCK(masterid);
278 			}
279 			/*
280 			 * Note that keep the drwlock(read) for
281 			 * the target (master) domain if it appears
282 			 * we're the lucky one to send the command.
283 			 * We hold onto the lock until we've actually
284 			 * sent the command out.
285 			 * We don't reach this place unless it
286 			 * appears everything is kosher with
287 			 * the target (master) domain.
288 			 */
289 		} else {
290 			bailout = 1;
291 			serrno = ENOLCK;
292 		}
293 	}
294 
295 	if (bailout) {
296 		ASSERT(serrno);
297 		/*
298 		 * Gotta bail.  Abort operation.  Error result
299 		 * will be picked up when we attempt to wait.
300 		 */
301 		PR_SMR("%s: BAILING OUT on behalf domain %d "
302 		    "(err=%d, gs=%s, ms=%s)\n",
303 		    proc, domid, serrno, idngs_str[idn.state],
304 		    (masterid == IDN_NIL_DOMID)
305 		    ? "unknown" : idnds_str[idn_domain[masterid].dstate]);
306 		(void) smr_slabwaiter_abort(domid, serrno);
307 
308 	} else if (nwait == 1) {
309 		/*
310 		 * We are the original requester.  Initiate the
311 		 * actual request to the master.
312 		 */
313 		idn_send_cmd(masterid, IDNCMD_SLABALLOC, IDN_SLAB_SIZE, 0, 0);
314 		ASSERT(mdp);
315 		IDN_DUNLOCK(masterid);
316 	}
317 
318 	/*
319 	 * Wait here for response.  Once awakened func returns
320 	 * with slab structure possibly filled with gifts!
321 	 */
322 	serrno = smr_slaballoc_wait(domid, spp);
323 
324 	return (serrno);
325 }
326 
327 /*
328  * Allocate a slab from the Master on behalf
329  * of the given domain.  Note that master uses
330  * this function to allocate slabs on behalf of
331  * remote domains also.
332  * Entered with drwlock held.
333  * Leaves with drwlock dropped.
334  * Returns:	EDQUOT
335  *		EINVAL
336  *		ENOLCK
337  *		smr_slab_alloc_local
338  *		smr_slab_alloc_remote
339  *		(0, EINVAL, EBUSY, ENOMEM)
340  */
341 int
smr_slab_alloc(int domid,smr_slab_t ** spp)342 smr_slab_alloc(int domid, smr_slab_t **spp)
343 {
344 	int		serrno = 0;
345 	idn_domain_t	*dp;
346 	procname_t	proc = "smr_slab_alloc";
347 
348 
349 	dp = &idn_domain[domid];
350 
351 	ASSERT(DSLAB_READ_HELD(domid));
352 	ASSERT(dp->dslab_state != DSLAB_STATE_UNKNOWN);
353 
354 	*spp = NULL;
355 
356 	switch (dp->dslab_state) {
357 	case DSLAB_STATE_UNKNOWN:
358 		cmn_err(CE_WARN,
359 		    "IDN: 300: no slab allocations without a master");
360 		serrno = EINVAL;
361 		break;
362 
363 	case DSLAB_STATE_LOCAL:
364 		/*
365 		 * If I'm the master, then get a slab
366 		 * from the local SMR pool, but only
367 		 * if the number of allocated slabs has
368 		 * not been exceeded.
369 		 */
370 		if (((int)dp->dnslabs < IDN_SLAB_MAXPERDOMAIN) ||
371 		    !IDN_SLAB_MAXPERDOMAIN)
372 			serrno = smr_slab_alloc_local(domid, spp);
373 		else
374 			serrno = EDQUOT;
375 		break;
376 
377 	case DSLAB_STATE_REMOTE:
378 		/*
379 		 * Have to make a remote request.
380 		 * In order to prevent overwhelming the master
381 		 * with a bunch of requests that he won't be able
382 		 * to handle we do a check to see if we're still
383 		 * under quota.  Note that the limit is known
384 		 * apriori based on the SMR/NWR size and
385 		 * IDN_SLAB_MINTOTAL.  Domains must have the same
386 		 * size SMR/NWR, however they can have different
387 		 * IDN_SLAB_MINTOTAL.  Thus a domain could throttle
388 		 * itself however it wishes.
389 		 */
390 		if (((int)dp->dnslabs < IDN_SLAB_MAXPERDOMAIN) ||
391 		    !IDN_SLAB_MAXPERDOMAIN)
392 			serrno = smr_slab_alloc_remote(domid, spp);
393 		else
394 			serrno = EDQUOT;
395 		break;
396 
397 	default:
398 		cmn_err(CE_WARN,
399 		    "IDN: 301: (ALLOC) unknown slab state (%d) "
400 		    "for domain %d", dp->dslab_state, domid);
401 		serrno = EINVAL;
402 		break;
403 	}
404 
405 	if (*spp == NULL) {
406 		PR_SMR("%s: failed to allocate %s slab [serrno = %d]\n",
407 		    proc, (idn.localid == IDN_GET_MASTERID()) ?
408 		    "local" : "remote", serrno);
409 	}
410 
411 	if (serrno) {
412 		IDN_GKSTAT_GLOBAL_EVENT(gk_slabfail, gk_slabfail_last);
413 	}
414 
415 	return (serrno);
416 }
417 
418 static void
smr_slab_free_local(int domid,smr_slab_t * sp)419 smr_slab_free_local(int domid, smr_slab_t *sp)
420 {
421 	int	rv;
422 
423 	/*
424 	 * Do a slaballoc_put just in case there may have
425 	 * been waiters for slabs for this respective domain
426 	 * before we unreserve this slab.
427 	 */
428 	rv = smr_slaballoc_put(domid, sp, 0, 0);
429 
430 	if (rv == -1) {
431 		/*
432 		 * Put failed.  Must not have been any waiters.
433 		 * Go ahead and unreserve the space.
434 		 */
435 		smr_slab_unreserve(domid, sp);
436 	}
437 }
438 
439 static void
smr_slab_free_remote(int domid,smr_slab_t * sp)440 smr_slab_free_remote(int domid, smr_slab_t *sp)
441 {
442 	smr_offset_t	slab_offset;
443 	int		slab_size;
444 	int		rv;
445 	int		masterid;
446 
447 	ASSERT(domid == idn.localid);
448 	ASSERT(idn.localid != IDN_GET_MASTERID());
449 	ASSERT(DSLAB_WRITE_HELD(domid));
450 	ASSERT(idn_domain[domid].dslab_state == DSLAB_STATE_REMOTE);
451 
452 	masterid = IDN_GET_MASTERID();
453 
454 	ASSERT(masterid != IDN_NIL_DOMID);
455 
456 	slab_offset = IDN_ADDR2OFFSET(sp->sl_start);
457 	slab_size   = (int)(sp->sl_end - sp->sl_start);
458 
459 	/*
460 	 * Do a slaballoc_put just in case there may have
461 	 * been waiters for slabs for this domain before
462 	 * returning back to the master.
463 	 */
464 	rv = smr_slaballoc_put(domid, sp, 0, 0);
465 
466 	if ((rv == -1) && (masterid != IDN_NIL_DOMID)) {
467 		/*
468 		 * Put failed.  No waiters so free the local data
469 		 * structure ship the SMR range off to the master.
470 		 */
471 		smr_free_buflist(sp);
472 		FREESTRUCT(sp, smr_slab_t, 1);
473 
474 		IDN_DLOCK_SHARED(masterid);
475 		idn_send_cmd(masterid, IDNCMD_SLABFREE, slab_offset, slab_size,
476 		    0);
477 		IDN_DUNLOCK(masterid);
478 	}
479 }
480 
481 /*
482  * Free up the list of slabs passed
483  */
484 void
smr_slab_free(int domid,smr_slab_t * sp)485 smr_slab_free(int domid, smr_slab_t *sp)
486 {
487 	smr_slab_t	*nsp = NULL;
488 
489 	ASSERT(DSLAB_WRITE_HELD(domid));
490 
491 	if (sp == NULL)
492 		return;
493 
494 	ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID);
495 
496 	switch (idn_domain[domid].dslab_state) {
497 	case DSLAB_STATE_UNKNOWN:
498 		cmn_err(CE_WARN, "IDN: 302: no slab free without a master");
499 		break;
500 
501 	case DSLAB_STATE_LOCAL:
502 		/*
503 		 * If I'm the master then put the slabs
504 		 * back to the local SMR pool.
505 		 */
506 		for (; sp; sp = nsp) {
507 			nsp = sp->sl_next;
508 			smr_slab_free_local(domid, sp);
509 		}
510 		break;
511 
512 	case DSLAB_STATE_REMOTE:
513 		/*
514 		 * If the domid is my own then I'm freeing
515 		 * a slab back to the Master.
516 		 */
517 		for (; sp; sp = nsp) {
518 			nsp = sp->sl_next;
519 			smr_slab_free_remote(domid, sp);
520 		}
521 		break;
522 
523 	default:
524 		cmn_err(CE_WARN,
525 		    "IDN: 301: (FREE) unknown slab state (%d) for domain %d",
526 		    idn_domain[domid].dslab_state, domid);
527 		break;
528 	}
529 }
530 
531 /*
532  * Free up the list of slab data structures ONLY.
533  * This is called during a fatal shutdown of the master
534  * where we need to garbage collect the locally allocated
535  * data structures used to manage slabs allocated to the
536  * local domain.  Should never be called by a master since
537  * the master can do a regular smr_slab_free.
538  */
539 void
smr_slab_garbage_collection(smr_slab_t * sp)540 smr_slab_garbage_collection(smr_slab_t *sp)
541 {
542 	smr_slab_t	*nsp;
543 
544 	ASSERT(idn_domain[idn.localid].dvote.v.master == 0);
545 
546 	if (sp == NULL)
547 		return;
548 	/*
549 	 * Since this is only ever called by a slave,
550 	 * the slab structure size always contains a buflist.
551 	 */
552 	for (; sp; sp = nsp) {
553 		nsp = sp->sl_next;
554 		smr_free_buflist(sp);
555 		FREESTRUCT(sp, smr_slab_t, 1);
556 	}
557 }
558 
559 /*
560  * Allocate a SMR buffer on behalf of the local domain
561  * which is ultimately targeted for the given domain.
562  *
563  * IMPORTANT: This routine is going to drop the domain rwlock (drwlock)
564  *	      for the domain on whose behalf the request is being
565  *	      made.  This routine canNOT block on trying to
566  *	      reacquire the drwlock.  If he does block then somebody
567  *	      must have the write lock on the domain which most likely
568  *	      means the domain is going south anyway, so just bail on
569  *	      this buffer.  Higher levels will retry if needed.
570  *
571  * XXX - Support larger than IDN_SMR_BUFSIZE allocations?
572  *
573  * Returns:	A negative return value indicates lock lost on domid.
574  *		EINVAL, ENOLINK, ENOLCK(internal)
575  *		smr_slaballoc_wait
576  * 		(EINVAL, ETIMEDOUT)
577  *		smr_slabwatier_unregister
578  *		(0, EINVAL, EBUSY, ENOMEM)
579  */
580 int
smr_buf_alloc(int domid,uint_t len,caddr_t * bufpp)581 smr_buf_alloc(int domid, uint_t len, caddr_t *bufpp)
582 {
583 	register idn_domain_t	*dp, *ldp;
584 	smr_slab_t	*sp;
585 	caddr_t		bufp = NULL;
586 	int		serrno;
587 	procname_t	proc = "smr_buf_alloc";
588 
589 	dp = &idn_domain[domid];
590 	/*
591 	 * Local domain can only allocate on behalf of
592 	 * itself if this is a priviledged call and the
593 	 * caller is the master.
594 	 */
595 	ASSERT((domid != idn.localid) && (domid != IDN_NIL_DOMID));
596 
597 	*bufpp = NULL;
598 
599 	if (len > IDN_DATA_SIZE) {
600 		cmn_err(CE_WARN,
601 		    "IDN: 303: buffer len %d > IDN_DATA_SIZE (%lu)",
602 		    len, IDN_DATA_SIZE);
603 		IDN_GKSTAT_GLOBAL_EVENT(gk_buffail, gk_buffail_last);
604 		return (EINVAL);
605 	}
606 
607 	/*
608 	 * Need to go to my local slab list to find
609 	 * a buffer.
610 	 */
611 	ldp = &idn_domain[idn.localid];
612 	/*
613 	 * Now we loop trying to locate a buffer out of our
614 	 * slabs.  We continue this until either we find a
615 	 * buffer or we're unable to allocate a slab.  Note
616 	 * that new slabs are allocated to the front.
617 	 */
618 	DSLAB_LOCK_SHARED(idn.localid);
619 	sp = ldp->dslab;
620 	do {
621 		int	spl, all_empty;
622 
623 		if (sp == NULL) {
624 			if ((serrno = smr_slab_alloc(idn.localid, &sp)) != 0) {
625 				PR_SMR("%s:%d: failed to allocate "
626 				    "slab [serrno = %d]",
627 				    proc, domid, serrno);
628 				DSLAB_UNLOCK(idn.localid);
629 				IDN_GKSTAT_GLOBAL_EVENT(gk_buffail,
630 				    gk_buffail_last);
631 				return (serrno);
632 			}
633 			/*
634 			 * Of course, the world may have changed while
635 			 * we dropped the lock.  Better make sure we're
636 			 * still established.
637 			 */
638 			if (dp->dstate != IDNDS_CONNECTED) {
639 				PR_SMR("%s:%d: state changed during slab "
640 				    "alloc (dstate = %s)\n",
641 				    proc, domid, idnds_str[dp->dstate]);
642 				DSLAB_UNLOCK(idn.localid);
643 				IDN_GKSTAT_GLOBAL_EVENT(gk_buffail,
644 				    gk_buffail_last);
645 				return (ENOLINK);
646 			}
647 			/*
648 			 * We were able to allocate a slab.  Should
649 			 * be at the front of the list, spin again.
650 			 */
651 			sp = ldp->dslab;
652 		}
653 		/*
654 		 * If we have reached here then we have a slab!
655 		 * Hopefully there are free bufs there :-o
656 		 */
657 		spl = splhi();
658 		all_empty = 1;
659 		for (; sp && !bufp; sp = sp->sl_next) {
660 			smr_slabbuf_t	*bp;
661 
662 			if (sp->sl_free == NULL)
663 				continue;
664 
665 			if (!lock_try(&sp->sl_lock)) {
666 				all_empty = 0;
667 				continue;
668 			}
669 
670 			if ((bp = sp->sl_free) == NULL) {
671 				lock_clear(&sp->sl_lock);
672 				continue;
673 			}
674 
675 			sp->sl_free = bp->sb_next;
676 			bp->sb_next = sp->sl_inuse;
677 			sp->sl_inuse = bp;
678 			/*
679 			 * Found a free buffer.
680 			 */
681 			bp->sb_domid = domid;
682 			bufp = bp->sb_bufp;
683 			lock_clear(&sp->sl_lock);
684 		}
685 		splx(spl);
686 
687 		if (!all_empty && !bufp) {
688 			/*
689 			 * If we still haven't found a buffer, but
690 			 * there's still possibly a buffer available,
691 			 * then try again.  Only if we're absolutely
692 			 * sure all slabs are empty do we attempt
693 			 * to allocate a new one.
694 			 */
695 			sp = ldp->dslab;
696 		}
697 	} while (bufp == NULL);
698 
699 	*bufpp = bufp;
700 
701 	ATOMIC_INC(dp->dio);
702 
703 	DSLAB_UNLOCK(idn.localid);
704 
705 	return (0);
706 }
707 
708 /*
709  * Free a buffer allocated to the local domain back to
710  * its respective slab.  Slabs are freed via the slab-reap command.
711  * XXX - Support larger than IDN_SMR_BUFSIZE allocations?
712  */
713 int
smr_buf_free(int domid,caddr_t bufp,uint_t len)714 smr_buf_free(int domid, caddr_t bufp, uint_t len)
715 {
716 	register smr_slab_t	*sp;
717 	smr_slabbuf_t		*bp, **bpp;
718 	idn_domain_t		*ldp;
719 	int		buffreed;
720 	int		lockheld = (len == (uint_t)-1);
721 
722 	/*
723 	 * We should never be free'ing a buffer on
724 	 * behalf of ourselves as we are never the
725 	 * target for allocated SMR buffers.
726 	 */
727 	ASSERT(domid != idn.localid);
728 
729 	sp = NULL;
730 	buffreed = 0;
731 	ldp = &idn_domain[idn.localid];
732 
733 	DSLAB_LOCK_SHARED(idn.localid);
734 
735 	if (((uintptr_t)bufp & (IDN_SMR_BUFSIZE-1)) &&
736 	    (IDN_ADDR2OFFSET(bufp) % IDN_SMR_BUFSIZE)) {
737 		cmn_err(CE_WARN,
738 		    "IDN: 304: buffer (0x%p) from domain %d not on a "
739 		    "%d boundary", (void *)bufp, domid, IDN_SMR_BUFSIZE);
740 		goto bfdone;
741 	}
742 	if (!lockheld && (len > IDN_DATA_SIZE)) {
743 		cmn_err(CE_WARN,
744 		    "IDN: 305: buffer length (%d) from domain %d greater "
745 		    "than IDN_DATA_SIZE (%lu)",
746 		    len, domid, IDN_DATA_SIZE);
747 		goto bfdone;
748 	}
749 
750 	for (sp = ldp->dslab; sp; sp = sp->sl_next)
751 		if ((bufp >= sp->sl_start) && (bufp < sp->sl_end))
752 			break;
753 
754 	if (sp) {
755 		int spl;
756 
757 		spl = splhi();
758 		while (!lock_try(&sp->sl_lock))
759 			;
760 		bpp = &sp->sl_inuse;
761 		for (bp = *bpp; bp; bp = *bpp) {
762 			if (bp->sb_bufp == bufp)
763 				break;
764 			bpp = &bp->sb_next;
765 		}
766 		if (bp) {
767 			ASSERT(bp->sb_domid == domid);
768 			buffreed++;
769 			bp->sb_domid = IDN_NIL_DOMID;
770 			*bpp = bp->sb_next;
771 			bp->sb_next = sp->sl_free;
772 			sp->sl_free = bp;
773 		}
774 		lock_clear(&sp->sl_lock);
775 		splx(spl);
776 	}
777 bfdone:
778 	if (buffreed) {
779 		ATOMIC_DEC(idn_domain[domid].dio);
780 		DIOCHECK(domid);
781 	} else {
782 		cmn_err(CE_WARN,
783 		    "IDN: 306: unknown buffer (0x%p) from domain %d",
784 		    (void *)bufp, domid);
785 		ATOMIC_INC(idn_domain[domid].dioerr);
786 	}
787 
788 	DSLAB_UNLOCK(idn.localid);
789 
790 	return (sp ? 0 : -1);
791 }
792 
793 /*
794  * Alternative interface to smr_buf_free, but with local drwlock
795  * held.
796  */
797 /* ARGSUSED2 */
798 int
smr_buf_free_locked(int domid,caddr_t bufp,uint_t len)799 smr_buf_free_locked(int domid, caddr_t bufp, uint_t len)
800 {
801 	return (smr_buf_free(domid, bufp, (uint_t)-1));
802 }
803 
804 /*
805  * Free any and all buffers associated with the given domain.
806  * Assumption is that domain is dead and buffers are not in use.
807  * Returns:	Number of buffers freed.
808  *		-1 if error.
809  */
810 int
smr_buf_free_all(int domid)811 smr_buf_free_all(int domid)
812 {
813 	register smr_slab_t	*sp;
814 	register smr_slabbuf_t	*bp, **bpp;
815 	idn_domain_t		*ldp;
816 	int			nbufsfreed = 0;
817 	procname_t	proc = "smr_buf_free_all";
818 
819 	/*
820 	 * We should never be free'ing buffers on
821 	 * behalf of ourself
822 	 */
823 	ASSERT(domid != idn.localid);
824 
825 	if (!VALID_DOMAINID(domid)) {
826 		cmn_err(CE_WARN, "IDN: 307: domain ID (%d) invalid", domid);
827 		return (-1);
828 	}
829 
830 	ldp = &idn_domain[idn.localid];
831 
832 	/*
833 	 * We grab the writer lock so that we don't have any
834 	 * competition during a "free-all" call.
835 	 * No need to grab individual slab locks when holding
836 	 * dslab(writer).
837 	 */
838 	DSLAB_LOCK_EXCL(idn.localid);
839 
840 	for (sp = ldp->dslab; sp; sp = sp->sl_next) {
841 		bpp = &sp->sl_inuse;
842 		for (bp = *bpp; bp; bp = *bpp) {
843 			if (bp->sb_domid == domid) {
844 				bp->sb_domid = IDN_NIL_DOMID;
845 				*bpp = bp->sb_next;
846 				bp->sb_next = sp->sl_free;
847 				sp->sl_free = bp;
848 				nbufsfreed++;
849 			} else {
850 				bpp = &bp->sb_next;
851 			}
852 		}
853 	}
854 
855 	if (nbufsfreed > 0) {
856 		ATOMIC_SUB(idn_domain[domid].dio, nbufsfreed);
857 		idn_domain[domid].dioerr = 0;
858 		DIOCHECK(domid);
859 	}
860 
861 	DSLAB_UNLOCK(idn.localid);
862 
863 	PR_SMR("%s: freed %d buffers for domain %d\n", proc, nbufsfreed, domid);
864 
865 	return (nbufsfreed);
866 }
867 
868 int
smr_buf_reclaim(int domid,int nbufs)869 smr_buf_reclaim(int domid, int nbufs)
870 {
871 	int		num_reclaimed = 0;
872 	idn_domain_t	*ldp, *dp;
873 	procname_t	proc = "smr_buf_reclaim";
874 
875 	ldp = &idn_domain[idn.localid];
876 	dp  = &idn_domain[domid];
877 
878 	ASSERT(domid != idn.localid);
879 
880 	if (ATOMIC_CAS(&dp->dreclaim_inprogress, 0, 1)) {
881 		/*
882 		 * Reclaim is already in progress, don't
883 		 * bother.
884 		 */
885 		PR_DATA("%s: reclaim already in progress\n", proc);
886 		return (0);
887 	}
888 
889 	PR_SMR("%s: requested %d buffers from domain %d\n", proc, nbufs, domid);
890 
891 	if (dp->dio && nbufs) {
892 		register smr_slab_t	*sp;
893 		int spl;
894 
895 		DSLAB_LOCK_SHARED(idn.localid);
896 		spl = splhi();
897 		for (sp = ldp->dslab; sp && nbufs; sp = sp->sl_next) {
898 			register smr_slabbuf_t	*bp, **bpp;
899 
900 			if (sp->sl_inuse == NULL)
901 				continue;
902 
903 			if (!lock_try(&sp->sl_lock))
904 				continue;
905 
906 			if (sp->sl_inuse == NULL) {
907 				lock_clear(&sp->sl_lock);
908 				continue;
909 			}
910 
911 			bpp = &sp->sl_inuse;
912 			for (bp = *bpp; bp && nbufs; bp = *bpp) {
913 				if (bp->sb_domid == domid) {
914 					/*
915 					 * Buffer no longer in use,
916 					 * reclaim it.
917 					 */
918 					bp->sb_domid = IDN_NIL_DOMID;
919 					*bpp = bp->sb_next;
920 					bp->sb_next = sp->sl_free;
921 					sp->sl_free = bp;
922 					num_reclaimed++;
923 					nbufs--;
924 				} else {
925 					bpp = &bp->sb_next;
926 				}
927 			}
928 			lock_clear(&sp->sl_lock);
929 		}
930 		splx(spl);
931 
932 		if (num_reclaimed > 0) {
933 			ATOMIC_SUB(dp->dio, num_reclaimed);
934 			DIOCHECK(domid);
935 		}
936 		DSLAB_UNLOCK(idn.localid);
937 	}
938 
939 	PR_SMR("%s: reclaimed %d buffers from domain %d\n",
940 	    proc, num_reclaimed, domid);
941 
942 	return (num_reclaimed);
943 }
944 
945 /*
946  * Returns 1	If any buffers are locked for the given slab.
947  *	   0	If all buffers are free for the given slab.
948  *
949  * The caller is assumed to have the slab protected so that no
950  * new allocations are attempted from it.  Also, this is only
951  * valid to be called with respect to slabs that were allocated
952  * on behalf of the local domain, i.e. the master is not expected
953  * to call this function with (slave) slab "representatives".
954  */
955 int
smr_slab_busy(smr_slab_t * sp)956 smr_slab_busy(smr_slab_t *sp)
957 {
958 	return ((sp && sp->sl_inuse) ? 1 : 0);
959 }
960 
961 int
smr_slabwaiter_init()962 smr_slabwaiter_init()
963 {
964 	register int		i;
965 	struct slabwaiter	*wp;
966 
967 	if (idn.slabwaiter != NULL)
968 		return (0);
969 
970 	/*
971 	 * Initialize the slab waiting area for MAX_DOMAINS.
972 	 */
973 	idn.slabwaiter = GETSTRUCT(struct slabwaiter, MAX_DOMAINS);
974 	wp = idn.slabwaiter;
975 	for (i = 0; i < MAX_DOMAINS; wp++, i++) {
976 		wp->w_closed = 0;
977 		mutex_init(&wp->w_mutex, NULL, MUTEX_DEFAULT, NULL);
978 		cv_init(&wp->w_cv, NULL, CV_DEFAULT, NULL);
979 	}
980 
981 	return (0);
982 }
983 
984 void
smr_slabwaiter_deinit()985 smr_slabwaiter_deinit()
986 {
987 	register int		i;
988 	struct slabwaiter	*wp;
989 
990 	if ((wp = idn.slabwaiter) == NULL)
991 		return;
992 
993 	for (i = 0; i < MAX_DOMAINS; wp++, i++) {
994 		ASSERT(wp->w_nwaiters == 0);
995 		ASSERT(wp->w_sp == NULL);
996 		cv_destroy(&wp->w_cv);
997 		mutex_destroy(&wp->w_mutex);
998 	}
999 
1000 	FREESTRUCT(idn.slabwaiter, struct slabwaiter, MAX_DOMAINS);
1001 	idn.slabwaiter = NULL;
1002 }
1003 
1004 void
smr_slabwaiter_open(domainset_t domset)1005 smr_slabwaiter_open(domainset_t domset)
1006 {
1007 	int			d;
1008 	struct slabwaiter	*wp;
1009 
1010 	if ((domset == 0) || !idn.slabwaiter)
1011 		return;
1012 
1013 	wp = idn.slabwaiter;
1014 
1015 	for (d = 0; d < MAX_DOMAINS; wp++, d++) {
1016 		if (!DOMAIN_IN_SET(domset, d))
1017 			continue;
1018 		mutex_enter(&wp->w_mutex);
1019 		wp->w_closed = 0;
1020 		mutex_exit(&wp->w_mutex);
1021 	}
1022 }
1023 
1024 void
smr_slabwaiter_close(domainset_t domset)1025 smr_slabwaiter_close(domainset_t domset)
1026 {
1027 	int			d;
1028 	struct slabwaiter	*wp;
1029 
1030 	if ((domset == 0) || !idn.slabwaiter)
1031 		return;
1032 
1033 	wp = idn.slabwaiter;
1034 
1035 	for (d = 0; d < MAX_DOMAINS; wp++, d++) {
1036 		if (!DOMAIN_IN_SET(domset, d))
1037 			continue;
1038 		mutex_enter(&wp->w_mutex);
1039 		wp->w_closed = 1;
1040 		cv_broadcast(&wp->w_cv);
1041 		mutex_exit(&wp->w_mutex);
1042 	}
1043 }
1044 
1045 /*
1046  * Register the caller with the waiting list for the
1047  * given domain.
1048  *
1049  * Protocol:
1050  *	1st Local requester:	register -> alloc ->
1051  *						put(wakeup|xdc) -> unregister
1052  *	Nth Local requester:	register -> wait
1053  *	1st Remote requester:	register -> xdc -> wait
1054  *	Nth Remote requester:	register -> wait
1055  *
1056  *	Remote Responder:	local alloc -> put(xdc)
1057  *	Local Handler:		xdc -> put(wakeup)
1058  *
1059  * E.g. A standard slave allocation request:
1060  *	slave			master
1061  *	-----			------
1062  *	idn_slab_alloc(remote)
1063  *	- register
1064  *	- xdc		->	idn_handler
1065  *	- wait			...
1066  *				idn_slab_alloc(local)
1067  *				- register
1068  *				- alloc
1069  *				- put
1070  *				  . wakeup [local]
1071  *				- unregister
1072  *	idn_handler    	<-	- xdc
1073  *	- put       		DONE
1074  *	  . wakeup [local]
1075  *	    |
1076  *	    V
1077  *      - wait
1078  *	  . unregister
1079  *	DONE
1080  */
1081 static int
smr_slabwaiter_register(int domid)1082 smr_slabwaiter_register(int domid)
1083 {
1084 	struct slabwaiter	*wp;
1085 	int		nwait;
1086 	procname_t	proc = "smr_slabwaiter_register";
1087 
1088 
1089 	ASSERT(domid != IDN_NIL_DOMID);
1090 
1091 	ASSERT(DSLAB_READ_HELD(domid));
1092 
1093 	wp = &idn.slabwaiter[domid];
1094 
1095 	ASSERT(MUTEX_NOT_HELD(&wp->w_mutex));
1096 
1097 	mutex_enter(&wp->w_mutex);
1098 
1099 	nwait = ++(wp->w_nwaiters);
1100 	ASSERT(nwait > 0);
1101 
1102 	PR_SMR("%s: domain = %d, (new)nwaiters = %d\n", proc, domid, nwait);
1103 
1104 	if (nwait > 1) {
1105 		/*
1106 		 * There are already waiters for slab allocations
1107 		 * with respect to this domain.
1108 		 */
1109 		PR_SMR("%s: existing waiters for slabs for domain %d\n",
1110 		    proc, domid);
1111 		mutex_exit(&wp->w_mutex);
1112 
1113 		return (nwait);
1114 	}
1115 	PR_SMR("%s: initial waiter for slabs for domain %d\n", proc, domid);
1116 	/*
1117 	 * We are the first requester of a slab allocation for this
1118 	 * respective domain.  Need to prep waiting area for
1119 	 * subsequent arrival of a slab.
1120 	 */
1121 	wp->w_sp = NULL;
1122 	wp->w_done = 0;
1123 	wp->w_serrno = 0;
1124 
1125 	mutex_exit(&wp->w_mutex);
1126 
1127 	return (nwait);
1128 }
1129 
1130 /*
1131  * It is assumed that the caller had previously registered,
1132  * but wakeup did not occur due to caller never waiting.
1133  * Thus, slaballoc mutex is still held by caller.
1134  *
1135  * Returns:	0
1136  *		EINVAL
1137  *		EBUSY
1138  *		w_serrno (smr_slaballoc_put)
1139  *		(0, ENOLCK, ENOMEM, EDQUOT, EBUSY, ECANCELED)
1140  */
1141 static int
smr_slabwaiter_unregister(int domid,smr_slab_t ** spp)1142 smr_slabwaiter_unregister(int domid, smr_slab_t **spp)
1143 {
1144 	struct slabwaiter	*wp;
1145 	int		serrno = 0;
1146 	procname_t	proc = "smr_slabwaiter_unregister";
1147 
1148 
1149 	ASSERT(domid != IDN_NIL_DOMID);
1150 
1151 	wp = &idn.slabwaiter[domid];
1152 
1153 	mutex_enter(&wp->w_mutex);
1154 
1155 	PR_SMR("%s: domain = %d, nwaiters = %d\n", proc, domid, wp->w_nwaiters);
1156 
1157 	if (wp->w_nwaiters <= 0) {
1158 		/*
1159 		 * Hmmm...nobody is registered!
1160 		 */
1161 		PR_SMR("%s: NO WAITERS (domid = %d)\n", proc, domid);
1162 		mutex_exit(&wp->w_mutex);
1163 		return (EINVAL);
1164 	}
1165 	(wp->w_nwaiters)--;
1166 	/*
1167 	 * Is our present under the tree?
1168 	 */
1169 	if (!wp->w_done) {
1170 		/*
1171 		 * Bummer...no presents.  Let the caller know
1172 		 * via a null slab pointer.
1173 		 * Note that we don't clean up immediately since
1174 		 * message might still come in for other waiters.
1175 		 * Thus, late sleepers may still get a chance.
1176 		 */
1177 		PR_SMR("%s: bummer no slab allocated for domain %d\n",
1178 		    proc, domid);
1179 		ASSERT(wp->w_sp == NULL);
1180 		(*spp) = NULL;
1181 		serrno = wp->w_closed ? ECANCELED : EBUSY;
1182 
1183 	} else {
1184 		(*spp) = wp->w_sp;
1185 		serrno = wp->w_serrno;
1186 
1187 #ifdef DEBUG
1188 		if (serrno == 0) {
1189 			register smr_slab_t	*sp;
1190 
1191 			ASSERT(wp->w_sp);
1192 			PR_SMR("%s: allocation succeeded (domain %d)\n",
1193 			    proc, domid);
1194 
1195 			DSLAB_LOCK_SHARED(domid);
1196 			for (sp = idn_domain[domid].dslab; sp; sp = sp->sl_next)
1197 				if (sp == wp->w_sp)
1198 					break;
1199 			if (sp == NULL)
1200 				cmn_err(CE_WARN,
1201 				    "%s:%d: slab ptr = NULL",
1202 				    proc, domid);
1203 			DSLAB_UNLOCK(domid);
1204 		} else {
1205 			PR_SMR("%s: allocation failed (domain %d) "
1206 			    "[serrno = %d]\n", proc, domid, serrno);
1207 		}
1208 #endif /* DEBUG */
1209 	}
1210 	if (wp->w_nwaiters == 0) {
1211 		/*
1212 		 * Last one turns out the lights.
1213 		 */
1214 		PR_SMR("%s: domain %d last waiter, turning out lights\n",
1215 		    proc, domid);
1216 		wp->w_sp = NULL;
1217 		wp->w_done = 0;
1218 		wp->w_serrno = 0;
1219 	}
1220 	mutex_exit(&wp->w_mutex);
1221 
1222 	return (serrno);
1223 }
1224 
1225 /*
1226  * Called to abort any slaballoc requests on behalf of the
1227  * given domain.
1228  */
1229 int
smr_slabwaiter_abort(int domid,int serrno)1230 smr_slabwaiter_abort(int domid, int serrno)
1231 {
1232 	ASSERT(serrno != 0);
1233 
1234 	return (smr_slaballoc_put(domid, NULL, 0, serrno));
1235 }
1236 
1237 /*
1238  * Put ourselves into a timedwait waiting for slab to be
1239  * allocated.
1240  * Returns with slaballoc mutex dropped.
1241  *
1242  * Returns:	EINVAL
1243  *		ETIMEDOUT
1244  *		smr_slabwatier_unregister
1245  *		(0, EINVAL, EBUSY, ENOMEM)
1246  */
1247 static int
smr_slaballoc_wait(int domid,smr_slab_t ** spp)1248 smr_slaballoc_wait(int domid, smr_slab_t **spp)
1249 {
1250 	struct slabwaiter	*wp;
1251 	int			serrno = 0, serrno_unreg;
1252 	procname_t		proc = "smr_slaballoc_wait";
1253 
1254 
1255 	wp = &idn.slabwaiter[domid];
1256 
1257 	ASSERT(MUTEX_NOT_HELD(&wp->w_mutex));
1258 
1259 	mutex_enter(&wp->w_mutex);
1260 
1261 	PR_SMR("%s: domain = %d, nwaiters = %d, wsp = 0x%p\n",
1262 	    proc, domid, wp->w_nwaiters, (void *)wp->w_sp);
1263 
1264 	if (wp->w_nwaiters <= 0) {
1265 		/*
1266 		 * Hmmm...no waiters registered.
1267 		 */
1268 		PR_SMR("%s: domain %d, no waiters!\n", proc, domid);
1269 		mutex_exit(&wp->w_mutex);
1270 		return (EINVAL);
1271 	}
1272 	ASSERT(DSLAB_READ_HELD(domid));
1273 	DSLAB_UNLOCK(domid);
1274 
1275 	if (!wp->w_done && !wp->w_closed) {
1276 		int	rv;
1277 
1278 		/*
1279 		 * Only wait if data hasn't arrived yet.
1280 		 */
1281 		PR_SMR("%s: domain %d, going to sleep...\n", proc, domid);
1282 
1283 		rv = cv_reltimedwait_sig(&wp->w_cv, &wp->w_mutex,
1284 		    IDN_SLABALLOC_WAITTIME, TR_CLOCK_TICK);
1285 		if (rv == -1)
1286 			serrno = ETIMEDOUT;
1287 
1288 		PR_SMR("%s: domain %d, awakened (reason = %s)\n",
1289 		    proc, domid, (rv == -1) ? "TIMEOUT" : "SIGNALED");
1290 	}
1291 	/*
1292 	 * We've awakened or request already filled!
1293 	 * Unregister ourselves.
1294 	 */
1295 	mutex_exit(&wp->w_mutex);
1296 
1297 	/*
1298 	 * Any gifts will be entered into spp.
1299 	 */
1300 	serrno_unreg = smr_slabwaiter_unregister(domid, spp);
1301 
1302 	/*
1303 	 * Leave with reader lock on dslab_lock.
1304 	 */
1305 	DSLAB_LOCK_SHARED(domid);
1306 
1307 	if ((serrno_unreg == EBUSY) && (serrno == ETIMEDOUT))
1308 		return (serrno);
1309 	else
1310 		return (serrno_unreg);
1311 }
1312 
1313 /*
1314  * A SMR slab was allocated on behalf of the given domain.
1315  * Wakeup anybody that may have been waiting for the allocation.
1316  * Note that if the domain is a remote one, i.e. master is allocating
1317  * on behalf of a slave, it's up to the caller to transmit the
1318  * allocation response to that domain.
1319  * The force flag indicates that we want to install the slab for
1320  * the given user regardless of whether there are waiters or not.
1321  * This is used primarily in situations where a slave may have timed
1322  * out before the response actually arrived.  In this situation we
1323  * don't want to send slab back to the master after we went through
1324  * the trouble of allocating one.  Master is _not_ allowed to do this
1325  * for remote domains.
1326  *
1327  * Returns:	-1	Non-registered waiter or waiting area garbaged.
1328  *		0	Successfully performed operation.
1329  */
1330 int
smr_slaballoc_put(int domid,smr_slab_t * sp,int forceflag,int serrno)1331 smr_slaballoc_put(int domid, smr_slab_t *sp, int forceflag, int serrno)
1332 {
1333 	idn_domain_t		*dp;
1334 	struct slabwaiter	*wp;
1335 	procname_t		proc = "smr_slaballoc_put";
1336 
1337 
1338 	dp = &idn_domain[domid];
1339 
1340 	ASSERT(!serrno ? DSLAB_WRITE_HELD(domid) : 1);
1341 
1342 	if (domid == IDN_NIL_DOMID)
1343 		return (-1);
1344 
1345 	ASSERT(serrno ? (sp == NULL) : (sp != NULL));
1346 
1347 	wp = &idn.slabwaiter[domid];
1348 
1349 	mutex_enter(&wp->w_mutex);
1350 
1351 	PR_SMR("%s: domain = %d, bufp = 0x%p, ebufp = 0x%p, "
1352 	    "(f = %d, se = %d)\n", proc, domid,
1353 	    (sp ? (void *)sp->sl_start : 0),
1354 	    (sp ? (void *)sp->sl_end : 0), forceflag, serrno);
1355 
1356 	if (wp->w_nwaiters <= 0) {
1357 		/*
1358 		 * There are no waiters!!  Must have timed out
1359 		 * and left.  Oh well...
1360 		 */
1361 		PR_SMR("%s: no slaballoc waiters found for domain %d\n",
1362 		    proc, domid);
1363 		if (!forceflag || serrno || !sp) {
1364 			/*
1365 			 * No waiters and caller doesn't want to force it.
1366 			 */
1367 			mutex_exit(&wp->w_mutex);
1368 			return (-1);
1369 		}
1370 		PR_SMR("%s: forcing slab onto domain %d\n", proc, domid);
1371 		ASSERT(domid == idn.localid);
1372 		ASSERT(wp->w_sp == NULL);
1373 		wp->w_done = 0;
1374 		/*
1375 		 * Now we fall through and let it be added in the
1376 		 * regular manor.
1377 		 */
1378 	}
1379 	if (wp->w_done) {
1380 		/*
1381 		 * There's at least one waiter so there has
1382 		 * to be a slab structure waiting for us.
1383 		 * If everything is going smoothly, there should only
1384 		 * be one guy coming through the path of inserting
1385 		 * an error or good slab.  However, if a disconnect was
1386 		 * detected, you may get several guys coming through
1387 		 * trying to let everybody know.
1388 		 */
1389 		ASSERT(wp->w_serrno ?
1390 		    (wp->w_sp == NULL) : (wp->w_sp != NULL));
1391 
1392 		cv_broadcast(&wp->w_cv);
1393 		mutex_exit(&wp->w_mutex);
1394 
1395 		return (-1);
1396 	}
1397 	if (serrno != 0) {
1398 		/*
1399 		 * Bummer...allocation failed.  This call is simply
1400 		 * to wake up the sleepers and let them know.
1401 		 */
1402 		PR_SMR("%s: slaballoc failed for domain %d\n", proc, domid);
1403 		wp->w_serrno = serrno;
1404 		wp->w_done = 1;
1405 		cv_broadcast(&wp->w_cv);
1406 		mutex_exit(&wp->w_mutex);
1407 
1408 		return (0);
1409 	}
1410 	PR_SMR("%s: putting slab into struct (domid=%d, localid=%d)\n",
1411 	    proc, domid, idn.localid);
1412 	/*
1413 	 * Prep the slab structure.
1414 	 */
1415 
1416 	if (domid == idn.localid) {
1417 		/*
1418 		 * Allocation was indeed for me.
1419 		 * Slab may or may not be locked when
1420 		 * we reach.  Normally they will be locked
1421 		 * if we're being called on behalf of a
1422 		 * free, and not locked if on behalf of
1423 		 * a new allocation request.
1424 		 */
1425 		lock_clear(&sp->sl_lock);
1426 		smr_alloc_buflist(sp);
1427 #ifdef DEBUG
1428 	} else {
1429 		uint_t	rv;
1430 		/*
1431 		 * Slab was not allocated on my behalf.  Must be
1432 		 * a master request on behalf of some other domain.
1433 		 * Prep appropriately.  Slab should have been locked
1434 		 * by smr_slab_reserve.
1435 		 */
1436 		rv = lock_try(&sp->sl_lock);
1437 		ASSERT(!rv);
1438 		ASSERT(sp->sl_domid == (short)domid);
1439 #endif /* DEBUG */
1440 	}
1441 
1442 	/*
1443 	 * Slab is ready to go.  Insert it into the domain's
1444 	 * slab list so once we wake everybody up they'll find it.
1445 	 * You better have write lock if you're putting treasures
1446 	 * there.
1447 	 */
1448 	ASSERT(DSLAB_WRITE_HELD(domid));
1449 
1450 	sp->sl_next = dp->dslab;
1451 	dp->dslab  = sp;
1452 	dp->dnslabs++;
1453 
1454 	/*
1455 	 * It's possible to fall through here without waiters.
1456 	 * This is a case where forceflag was set.
1457 	 */
1458 	if (wp->w_nwaiters > 0) {
1459 		wp->w_sp = sp;
1460 		wp->w_serrno = serrno;
1461 		wp->w_done = 1;
1462 		cv_broadcast(&wp->w_cv);
1463 	} else {
1464 		ASSERT(forceflag);
1465 		wp->w_sp = NULL;
1466 		wp->w_serrno = 0;
1467 		wp->w_done = 0;
1468 	}
1469 	mutex_exit(&wp->w_mutex);
1470 
1471 	return (0);
1472 }
1473 
1474 /*
1475  * Get the slab representing [bufp,ebufp] from the respective
1476  * domain's pool if all the buffers are free.  Remove them from
1477  * the domain's list and return it.
1478  * If bufp == NULL, then return however many free ones you
1479  * can find.
1480  * List of slabs are returned locked (sl_lock).
1481  * XXX - Need minimum limit to make sure we don't free up _all_
1482  *	 of our slabs!  However, during a shutdown we will need
1483  *	 method to free them all up regardless of locking.
1484  */
1485 smr_slab_t *
smr_slaballoc_get(int domid,caddr_t bufp,caddr_t ebufp)1486 smr_slaballoc_get(int domid, caddr_t bufp, caddr_t ebufp)
1487 {
1488 	idn_domain_t	*dp;
1489 	smr_slab_t	*retsp, *sp, **psp;
1490 	int		foundit, islocal = 0;
1491 	int		nslabs;
1492 	procname_t	proc = "smr_slaballoc_get";
1493 
1494 	PR_SMR("%s: getting slab for domain %d [bufp=0x%p, ebufp=0x%p]\n",
1495 	    proc, domid, (void *)bufp, (void *)ebufp);
1496 
1497 	dp = &idn_domain[domid];
1498 
1499 	ASSERT(DSLAB_WRITE_HELD(domid));
1500 
1501 	if ((sp = dp->dslab) == NULL) {
1502 		PR_SMR("%s: oops, no slabs for domain %d\n", proc, domid);
1503 		return (NULL);
1504 	}
1505 	/*
1506 	 * If domid is myself then I'm trying to get a slab out
1507 	 * of my local pool.  Otherwise, I'm the master and
1508 	 * I'm trying to get the slab representative from the
1509 	 * global pool.
1510 	 */
1511 	if (domid == idn.localid)
1512 		islocal = 1;
1513 
1514 	if (bufp != NULL) {
1515 		nslabs = -1;
1516 	} else {
1517 		nslabs = *(int *)ebufp;
1518 		if (nslabs == 0) {
1519 			PR_SMR("%s: requested nslabs (%d) <= 0\n",
1520 			    proc, nslabs);
1521 			return (NULL);
1522 		} else if (nslabs < 0) {
1523 			/*
1524 			 * Caller wants them all!
1525 			 */
1526 			nslabs = (int)dp->dnslabs;
1527 		}
1528 	}
1529 
1530 	retsp = NULL;
1531 	foundit = 0;
1532 	for (psp = &dp->dslab; sp; sp = *psp) {
1533 		int	isbusy;
1534 
1535 		if (bufp && (sp->sl_start != bufp)) {
1536 			psp = &sp->sl_next;
1537 			continue;
1538 		}
1539 
1540 		if (bufp && (ebufp > sp->sl_end)) {
1541 			PR_SMR("%s: bufp/ebufp (0x%p/0x%p) "
1542 			    "expected (0x%p/0x%p)\n", proc, (void *)bufp,
1543 			    (void *)ebufp, (void *)sp->sl_start,
1544 			    (void *)sp->sl_end);
1545 			ASSERT(0);
1546 		}
1547 		/*
1548 		 * We found the desired slab.  Make sure
1549 		 * it's free.
1550 		 */
1551 		foundit++;
1552 		isbusy = 0;
1553 		if (islocal) {
1554 			int spl;
1555 
1556 			/*
1557 			 * Some of the buffers in the slab
1558 			 * are still in use.  Unlock the
1559 			 * buffers we locked and bail out.
1560 			 */
1561 			spl = splhi();
1562 			if (!lock_try(&sp->sl_lock)) {
1563 				isbusy = 1;
1564 				foundit--;
1565 			} else if (sp->sl_inuse) {
1566 				lock_clear(&sp->sl_lock);
1567 				isbusy = 1;
1568 				foundit--;
1569 			}
1570 			splx(spl);
1571 		} else {
1572 			/*
1573 			 * If not local, then I'm the master getting
1574 			 * a slab from one of the slaves.  In this case,
1575 			 * their slab structs will always be locked.
1576 			 */
1577 			ASSERT(!lock_try(&sp->sl_lock));
1578 		}
1579 		if (!isbusy) {
1580 			/*
1581 			 * Delete the entry from the list and slap
1582 			 * it onto our return list.
1583 			 */
1584 			*psp = sp->sl_next;
1585 			sp->sl_next = retsp;
1586 			retsp = sp;
1587 		} else {
1588 			psp = &sp->sl_next;
1589 		}
1590 		/*
1591 		 * If bufp == NULL (alternate interface) and we haven't
1592 		 * found the desired number of slabs yet, keep looking.
1593 		 */
1594 		if (bufp || (foundit == nslabs))
1595 			break;
1596 	}
1597 	dp->dnslabs -= (short)foundit;
1598 
1599 	if (foundit) {
1600 		PR_SMR("%s: found %d free slabs (domid = %d)\n", proc, foundit,
1601 		    domid);
1602 	} else {
1603 		PR_SMR("%s: no free slabs found (domid = %d)\n", proc, domid);
1604 	}
1605 
1606 	/*
1607 	 * If this is the alternate interface, need to return
1608 	 * the number of slabs found in the ebufp parameter.
1609 	 */
1610 	if (bufp == NULL)
1611 		*(int *)ebufp = foundit;
1612 
1613 	return (retsp);
1614 }
1615 
1616 /*
1617  * Wrapper to hide alternate interface to smr_slaballoc_get()
1618  */
1619 smr_slab_t *
smr_slaballoc_get_n(int domid,int * nslabs)1620 smr_slaballoc_get_n(int domid, int *nslabs)
1621 {
1622 	smr_slab_t	*sp;
1623 
1624 	ASSERT(DSLAB_WRITE_HELD(domid));
1625 
1626 	sp = smr_slaballoc_get(domid, NULL, (caddr_t)nslabs);
1627 
1628 	return (sp);
1629 }
1630 
1631 /*
1632  * Only called by master.  Initialize slab pool based on local SMR.
1633  * Returns number of slabs initialized.
1634  * reserved_size = Length of area at the front of the NWR portion
1635  *		   of the SMR to reserve and not make available for
1636  *		   slab allocations.  Must be a IDN_SMR_BUFSIZE multiple.
1637  * reserved_area = Pointer to reserved area, if any.
1638  */
1639 int
smr_slabpool_init(size_t reserved_size,caddr_t * reserved_area)1640 smr_slabpool_init(size_t reserved_size, caddr_t *reserved_area)
1641 {
1642 	size_t			nwr_available;
1643 	int			minperpool, ntotslabs, nxslabs, nslabs;
1644 	register int		p, pp;
1645 	register caddr_t	bufp;
1646 	register smr_slab_t	*sp;
1647 
1648 	ASSERT(IDN_GLOCK_IS_EXCL());
1649 	ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID);
1650 
1651 	*reserved_area = NULL;
1652 
1653 	nwr_available = MB2B(IDN_NWR_SIZE) - reserved_size;
1654 
1655 	if ((idn.localid != IDN_GET_MASTERID()) ||
1656 	    (nwr_available < IDN_SLAB_SIZE) ||
1657 	    (idn.slabpool != NULL) ||
1658 	    ((reserved_size != 0) && (reserved_size & (IDN_SMR_BUFSIZE-1)))) {
1659 		return (-1);
1660 	}
1661 
1662 	idn.slabpool = GETSTRUCT(struct slabpool, 1);
1663 	idn.slabpool->ntotslabs = ntotslabs = nwr_available / IDN_SLAB_SIZE;
1664 	ASSERT(ntotslabs > 0);
1665 	minperpool = (ntotslabs < IDN_SLAB_MINPERPOOL) ?
1666 	    1 : IDN_SLAB_MINPERPOOL;
1667 	idn.slabpool->npools = (ntotslabs + (minperpool - 1)) / minperpool;
1668 
1669 	if ((idn.slabpool->npools & 1) == 0) {
1670 		/*
1671 		 * npools needs to be odd for hashing algorithm.
1672 		 */
1673 		idn.slabpool->npools++;
1674 	}
1675 	ASSERT(idn.slabpool->npools > 0);
1676 	minperpool = (ntotslabs < idn.slabpool->npools) ?
1677 	    1 : (ntotslabs / idn.slabpool->npools);
1678 
1679 	/*
1680 	 * Calculate the number of extra slabs that will need to
1681 	 * be alloted to the pools.  This number will be less than
1682 	 * npools.  Only one extra slab is allocated to each pool
1683 	 * until we have assigned all the extra slabs.
1684 	 */
1685 	if (ntotslabs > (idn.slabpool->npools * minperpool))
1686 		nxslabs = ntotslabs - (idn.slabpool->npools * minperpool);
1687 	else
1688 		nxslabs = 0;
1689 	ASSERT((nxslabs >= 0) && (nxslabs < idn.slabpool->npools));
1690 
1691 	idn.slabpool->pool = GETSTRUCT(struct smr_slabtbl,
1692 	    idn.slabpool->npools);
1693 	sp = GETSTRUCT(smr_slab_t, idn.slabpool->ntotslabs);
1694 
1695 	idn.slabpool->savep = sp;
1696 	bufp = idn.smr.vaddr + reserved_size;
1697 
1698 	for (p = nslabs = 0;
1699 	    (p < idn.slabpool->npools) && (ntotslabs > 0);
1700 	    p++, ntotslabs -= nslabs) {
1701 
1702 		nslabs = (ntotslabs < minperpool) ? ntotslabs : minperpool;
1703 		if (nxslabs > 0) {
1704 			nslabs++;
1705 			nxslabs--;
1706 		}
1707 		idn.slabpool->pool[p].sarray = sp;
1708 		for (pp = 0; pp < nslabs; pp++) {
1709 
1710 			sp->sl_next  = NULL;
1711 			sp->sl_start = bufp;
1712 			sp->sl_end   = bufp = sp->sl_start + IDN_SLAB_SIZE;
1713 			sp->sl_lock  = 0;
1714 			sp->sl_domid = (short)IDN_NIL_DOMID;
1715 
1716 			sp++;
1717 		}
1718 		idn.slabpool->pool[p].nfree   = nslabs;
1719 		idn.slabpool->pool[p].nslabs  = nslabs;
1720 	}
1721 	ASSERT((ntotslabs == 0) && (nxslabs == 0));
1722 	/*
1723 	 * We should be at the end of the SMR at this point.
1724 	 */
1725 	ASSERT(bufp == (idn.smr.vaddr + reserved_size
1726 	    + (idn.slabpool->ntotslabs * IDN_SLAB_SIZE)));
1727 
1728 	if (reserved_size != 0)
1729 		*reserved_area = idn.smr.vaddr;
1730 
1731 	return (0);
1732 }
1733 
1734 void
smr_slabpool_deinit()1735 smr_slabpool_deinit()
1736 {
1737 	if (idn.slabpool == NULL)
1738 		return;
1739 
1740 	FREESTRUCT(idn.slabpool->savep, smr_slab_t, idn.slabpool->ntotslabs);
1741 	FREESTRUCT(idn.slabpool->pool, struct smr_slabtbl,
1742 	    idn.slabpool->npools);
1743 	FREESTRUCT(idn.slabpool, struct slabpool, 1);
1744 
1745 	idn.slabpool = NULL;
1746 }
1747 
1748 void
smr_alloc_buflist(smr_slab_t * sp)1749 smr_alloc_buflist(smr_slab_t *sp)
1750 {
1751 	int		n, nbufs;
1752 	caddr_t		sbufp;
1753 	smr_slabbuf_t	*hp, *bp;
1754 
1755 	if (sp->sl_head)
1756 		return;
1757 
1758 	nbufs = (sp->sl_end - sp->sl_start) / IDN_SMR_BUFSIZE;
1759 	ASSERT(nbufs > 0);
1760 	if (nbufs <= 0) {
1761 		sp->sl_head = sp->sl_free = sp->sl_inuse = NULL;
1762 		return;
1763 	}
1764 
1765 	hp = GETSTRUCT(smr_slabbuf_t, nbufs);
1766 
1767 	sbufp = sp->sl_start;
1768 	for (n = 0, bp = hp; n < nbufs; bp++, n++) {
1769 		bp->sb_bufp = sbufp;
1770 		bp->sb_domid = IDN_NIL_DOMID;
1771 		bp->sb_next = bp + 1;
1772 		sbufp += IDN_SMR_BUFSIZE;
1773 	}
1774 	(--bp)->sb_next = NULL;
1775 
1776 	sp->sl_head = sp->sl_free = hp;
1777 	sp->sl_inuse = NULL;
1778 }
1779 
1780 void
smr_free_buflist(smr_slab_t * sp)1781 smr_free_buflist(smr_slab_t *sp)
1782 {
1783 	int	nbufs;
1784 
1785 	if (sp->sl_head == NULL)
1786 		return;
1787 
1788 	nbufs = (sp->sl_end - sp->sl_start) / IDN_SMR_BUFSIZE;
1789 
1790 	FREESTRUCT(sp->sl_head, smr_slabbuf_t, nbufs);
1791 
1792 	sp->sl_head = sp->sl_free = sp->sl_inuse = NULL;
1793 }
1794 
1795 /*
1796  * Returns:	0 Successfully located a slab.
1797  *	       -1 Failure.
1798  */
1799 static smr_slab_t *
smr_slab_reserve(int domid)1800 smr_slab_reserve(int domid)
1801 {
1802 	register int		p, nextp, s, nexts;
1803 	register smr_slab_t	*spa;
1804 	int			startp, starts;
1805 	int			foundone = 0;
1806 	int			spl;
1807 	procname_t		proc = "smr_slab_reserve";
1808 
1809 	p = startp = SMR_SLABPOOL_HASH(domid);
1810 	nextp = -1;
1811 
1812 	spl = splhi();
1813 	while ((nextp != startp) && !foundone) {
1814 
1815 		s = starts = SMR_SLAB_HASH(p, domid);
1816 		nexts = -1;
1817 		spa = &(idn.slabpool->pool[p].sarray[0]);
1818 
1819 		while ((nexts != starts) && !foundone) {
1820 			if (lock_try(&spa[s].sl_lock)) {
1821 				foundone = 1;
1822 				break;
1823 			}
1824 			nexts = SMR_SLAB_HASHSTEP(p, s);
1825 			s = nexts;
1826 		}
1827 		if (foundone)
1828 			break;
1829 		nextp = SMR_SLABPOOL_HASHSTEP(p);
1830 		p = nextp;
1831 	}
1832 	splx(spl);
1833 
1834 	if (foundone) {
1835 		ASSERT((&spa[s] >= idn.slabpool->savep) &&
1836 		    (&spa[s] < (idn.slabpool->savep +
1837 		    idn.slabpool->ntotslabs)));
1838 
1839 		spa[s].sl_domid = (short)domid;
1840 
1841 		ATOMIC_DEC(idn.slabpool->pool[p].nfree);
1842 
1843 		if (domid == idn.localid) {
1844 			smr_slab_t	*nsp;
1845 			/*
1846 			 * Caller is actually reserving a slab for
1847 			 * themself which means they'll need the full
1848 			 * slab structure to represent all of the I/O
1849 			 * buffers.  The "spa" is just a representative
1850 			 * and doesn't contain the space to manage the
1851 			 * individual buffers.  Need to alloc a full-size
1852 			 * struct.
1853 			 * Note that this results in the returning
1854 			 * smr_slab_t structure being unlocked.
1855 			 */
1856 			ASSERT(idn.localid == IDN_GET_MASTERID());
1857 			nsp = GETSTRUCT(smr_slab_t, 1);
1858 			nsp->sl_start = spa[s].sl_start;
1859 			nsp->sl_end   = spa[s].sl_end;
1860 			smr_alloc_buflist(nsp);
1861 			spa = nsp;
1862 			PR_SMR("%s: allocated full slab struct for domain %d\n",
1863 			    proc, domid);
1864 		} else {
1865 			/*
1866 			 * Slab structure gets returned locked.
1867 			 */
1868 			spa += s;
1869 		}
1870 
1871 		PR_SMR("%s: allocated slab 0x%p (start=0x%p, size=%lu) for "
1872 		    "domain %d\n", proc, (void *)spa, (void *)spa->sl_start,
1873 		    spa->sl_end - spa->sl_start, domid);
1874 	} else {
1875 		PR_SMR("%s: FAILED to allocate for domain %d\n",
1876 		    proc, domid);
1877 		spa = NULL;
1878 	}
1879 
1880 	return (spa);
1881 }
1882 
1883 static void
smr_slab_unreserve(int domid,smr_slab_t * sp)1884 smr_slab_unreserve(int domid, smr_slab_t *sp)
1885 {
1886 	register int		p, nextp, s, nexts;
1887 	register smr_slab_t	*spa;
1888 	int			foundit = 0;
1889 	int			startp, starts;
1890 	caddr_t			bufp;
1891 	procname_t		proc = "smr_slab_unreserve";
1892 
1893 	bufp = sp->sl_start;
1894 	p = startp = SMR_SLABPOOL_HASH(domid);
1895 	nextp = -1;
1896 
1897 	while ((nextp != startp) && !foundit) {
1898 
1899 		s = starts = SMR_SLAB_HASH(p, domid);
1900 		nexts = -1;
1901 		spa = &(idn.slabpool->pool[p].sarray[0]);
1902 
1903 		while ((nexts != starts) && !foundit) {
1904 			if (spa[s].sl_start == bufp) {
1905 				foundit = 1;
1906 				break;
1907 			}
1908 			nexts = SMR_SLAB_HASHSTEP(p, s);
1909 			s = nexts;
1910 		}
1911 		if (foundit)
1912 			break;
1913 		nextp = SMR_SLABPOOL_HASHSTEP(p);
1914 		p = nextp;
1915 	}
1916 	if (foundit) {
1917 		ASSERT((&spa[s] >= idn.slabpool->savep) &&
1918 		    (&spa[s] < (idn.slabpool->savep +
1919 		    idn.slabpool->ntotslabs)));
1920 		ASSERT(!lock_try(&spa[s].sl_lock));
1921 		ASSERT(spa[s].sl_domid == (short)domid);
1922 
1923 		spa[s].sl_next = NULL;
1924 		spa[s].sl_domid = (short)IDN_NIL_DOMID;
1925 		lock_clear(&spa[s].sl_lock);
1926 
1927 		ATOMIC_INC(idn.slabpool->pool[p].nfree);
1928 
1929 		PR_SMR("%s: freed (bufp=0x%p) for domain %d\n",
1930 		    proc, (void *)bufp, domid);
1931 
1932 		if (domid == idn.localid) {
1933 			/*
1934 			 * Caller is actually unreserving a slab of their
1935 			 * own.  Note that only the master calls this
1936 			 * routine.  Since the master's local slab
1937 			 * structures do not get entered into the global
1938 			 * "representative" pool, we need to free up the
1939 			 * data structure that was passed in.
1940 			 */
1941 			ASSERT(idn.localid == IDN_GET_MASTERID());
1942 			ASSERT(sp != &spa[s]);
1943 
1944 			smr_free_buflist(sp);
1945 			FREESTRUCT(sp, smr_slab_t, 1);
1946 		} else {
1947 			ASSERT(sp == &spa[s]);
1948 		}
1949 	} else {
1950 		/*
1951 		 * Couldn't find slab entry for given buf!
1952 		 */
1953 		PR_SMR("%s: FAILED to free (bufp=0x%p) for domain %d\n",
1954 		    proc, (void *)bufp, domid);
1955 	}
1956 }
1957 
1958 /*
1959  * The Reap Protocol:
1960  *	master				   slave
1961  *	------				   -----
1962  *	smr_slab_reap_global
1963  *	- idn_broadcast_cmd(SLABREAP) ->   idn_recv_cmd(SLABREAP)
1964  *	  . idn_local_cmd(SLABREAP)        - idn_recv_slabreap_req
1965  *	    - smr_slab_reap	             . smr_slab_reap
1966  *	      . smr_slaballoc_get_n            - smr_slaballoc_get_n
1967  *	      . smr_slab_free		       - smr_slab_free
1968  *		- smr_slab_free_local		 . smr_slab_free_remote
1969  *		  . smr_slab_unreserve
1970  *				      <-	   - idn_send_cmd(SLABFREE)
1971  *	idn_recv_cmd(SLABFREE)
1972  *	- idn_recv_slabfree_req
1973  *	  . smr_slaballoc_get
1974  *	  . smr_slab_free
1975  *	    - smr_slab_free_local
1976  *	      . smr_slab_unreserve
1977  *        . idn_send_slabfree_resp    ->   idn_recv_cmd(SLABFREE | ack)
1978  *					   - idn_recv_slabfree_resp
1979  *
1980  *	idn_recv_cmd(SLABREAP | ack)  <-     . idn_send_slabreap_resp
1981  *	- idn_recv_slabreap_resp	   DONE
1982  *	DONE
1983  *
1984  * Check available slabs and if we're below the threshold, kick
1985  * off reaping to all remote domains.  There is no guarantee remote
1986  * domains will be able to free up any.
1987  */
1988 static void
smr_slab_reap_global()1989 smr_slab_reap_global()
1990 {
1991 	register int	p, npools;
1992 	register int	total_free = 0;
1993 	register struct smr_slabtbl	*tblp;
1994 	static clock_t	reap_last = 0;
1995 	procname_t	proc = "smr_slab_reap_global";
1996 	clock_t		now;
1997 
1998 	ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID);
1999 
2000 	DSLAB_LOCK_SHARED(idn.localid);
2001 	if (idn_domain[idn.localid].dslab_state != DSLAB_STATE_LOCAL) {
2002 		PR_SMR("%s: only allowed by master (%d)\n",
2003 		    proc, IDN_GET_MASTERID());
2004 		DSLAB_UNLOCK(idn.localid);
2005 		return;
2006 	}
2007 	DSLAB_UNLOCK(idn.localid);
2008 
2009 	now = ddi_get_lbolt();
2010 	if ((now > 0) && (now > reap_last) &&
2011 	    ((now - reap_last) < IDN_REAP_INTERVAL))
2012 		return;
2013 
2014 	reap_last = now;
2015 
2016 	ASSERT(idn.slabpool);
2017 
2018 	npools = idn.slabpool->npools;
2019 	tblp   = idn.slabpool->pool;
2020 
2021 	for (p = 0; p < npools; tblp++, p++)
2022 		total_free += tblp->nfree;
2023 
2024 	if (total_free <= IDN_SLAB_THRESHOLD) {
2025 		int	diff, reap_per_domain;
2026 
2027 		PR_SMR("%s: kicking off reaping "
2028 		    "(total_free = %d, min = %d)\n",
2029 		    proc, total_free, IDN_SLAB_THRESHOLD);
2030 
2031 		diff = IDN_SLAB_THRESHOLD - total_free;
2032 		reap_per_domain = (diff < idn.ndomains) ?
2033 		    1 : (diff / idn.ndomains);
2034 
2035 		idn_broadcast_cmd(IDNCMD_SLABREAP, reap_per_domain, 0, 0);
2036 	}
2037 }
2038 
2039 void
smr_slab_reap(int domid,int * nslabs)2040 smr_slab_reap(int domid, int *nslabs)
2041 {
2042 	register int	d;
2043 	int		nreclaimed;
2044 	smr_slab_t	*sp;
2045 	domainset_t	reapset;
2046 	procname_t	proc = "smr_slab_reap";
2047 
2048 	/*
2049 	 * Should only be called on behalf of local
2050 	 * domain.
2051 	 */
2052 	if (domid != idn.localid) {
2053 		PR_SMR("%s: called by domain %d, should only be local (%d)\n",
2054 		    proc, domid, idn.localid);
2055 		ASSERT(0);
2056 		return;
2057 	}
2058 	/*
2059 	 * Try and reclaim some buffers so we can possibly
2060 	 * free up some slabs.
2061 	 */
2062 	reapset = idn.domset.ds_connected;
2063 
2064 	IDN_GKSTAT_GLOBAL_EVENT(gk_reaps, gk_reap_last);
2065 
2066 	nreclaimed = 0;
2067 	for (d = 0; d < MAX_DOMAINS; d++) {
2068 		int		nr;
2069 		idn_domain_t	*dp;
2070 
2071 		if (!DOMAIN_IN_SET(reapset, d))
2072 			continue;
2073 
2074 		IDN_DLOCK_SHARED(d);
2075 
2076 		dp = &idn_domain[d];
2077 		if ((d == idn.localid) || (dp->dcpu < 0)) {
2078 			IDN_DUNLOCK(d);
2079 			continue;
2080 		}
2081 		/*
2082 		 * Clean up any dead I/O errors if possible.
2083 		 */
2084 		if (dp->dioerr > 0) {
2085 			idn_domain_t	*ldp;
2086 			register int	cnt;
2087 			register smr_slabbuf_t	*bp;
2088 			/*
2089 			 * We need to grab the writer lock to prevent
2090 			 * anybody from allocating buffers while we
2091 			 * traverse the slabs outstanding.
2092 			 */
2093 			cnt = 0;
2094 			ldp = &idn_domain[idn.localid];
2095 			IDN_DLOCK_EXCL(idn.localid);
2096 			DSLAB_LOCK_EXCL(idn.localid);
2097 			for (sp = ldp->dslab; sp; sp = sp->sl_next)
2098 				for (bp = sp->sl_inuse; bp; bp = bp->sb_next)
2099 					if (bp->sb_domid == d)
2100 						cnt++;
2101 			DSLAB_UNLOCK(idn.localid);
2102 			ASSERT((dp->dio + dp->dioerr) >= cnt);
2103 			dp->dio = cnt;
2104 			dp->dioerr = 0;
2105 			IDN_DUNLOCK(idn.localid);
2106 		}
2107 		if ((dp->dstate == IDNDS_CONNECTED) &&
2108 		    ((nr = idn_reclaim_mboxdata(d, 0, -1)) > 0))
2109 			nreclaimed += nr;
2110 
2111 		IDN_DUNLOCK(d);
2112 	}
2113 
2114 	DSLAB_LOCK_EXCL(domid);
2115 	sp = smr_slaballoc_get_n(domid, nslabs);
2116 	if (sp) {
2117 		IDN_GKSTAT_ADD(gk_reap_count, (ulong_t)(*nslabs));
2118 		smr_slab_free(domid, sp);
2119 	}
2120 	DSLAB_UNLOCK(domid);
2121 }
2122 
2123 /*
2124  * ---------------------------------------------------------------------
2125  * Remap the (IDN) shared memory region to a new physical address.
2126  * Caller is expected to have performed a ecache flush if needed.
2127  * ---------------------------------------------------------------------
2128  */
2129 void
smr_remap(struct as * as,register caddr_t vaddr,register pfn_t new_pfn,uint_t mblen)2130 smr_remap(struct as *as, register caddr_t vaddr,
2131 		register pfn_t new_pfn, uint_t mblen)
2132 {
2133 	tte_t		tte;
2134 	size_t		blen;
2135 	pgcnt_t		p, npgs;
2136 	procname_t	proc = "smr_remap";
2137 
2138 	if (va_to_pfn(vaddr) == new_pfn) {
2139 		PR_REMAP("%s: vaddr (0x%p) already mapped to pfn (0x%lx)\n",
2140 		    proc, (void *)vaddr, new_pfn);
2141 		return;
2142 	}
2143 
2144 	blen = MB2B(mblen);
2145 	npgs = btopr(blen);
2146 	ASSERT(npgs != 0);
2147 
2148 	PR_REMAP("%s: va = 0x%p, pfn = 0x%lx, npgs = %ld, mb = %d MB (%ld)\n",
2149 	    proc, (void *)vaddr, new_pfn, npgs, mblen, blen);
2150 
2151 	/*
2152 	 * Unmap the SMR virtual address from it's current
2153 	 * mapping.
2154 	 */
2155 	hat_unload(as->a_hat, vaddr, blen, HAT_UNLOAD_UNLOCK);
2156 
2157 	if (new_pfn == PFN_INVALID)
2158 		return;
2159 
2160 	/*
2161 	 * Map the SMR to the new physical address space,
2162 	 * presumably a remote pfn.  Cannot use hat_devload
2163 	 * because it will think pfn represents non-memory,
2164 	 * i.e. space since it may beyond his physmax.
2165 	 */
2166 	for (p = 0; p < npgs; p++) {
2167 		sfmmu_memtte(&tte, new_pfn, PROT_READ | PROT_WRITE | HAT_NOSYNC,
2168 		    TTE8K);
2169 		sfmmu_tteload(as->a_hat, &tte, vaddr, NULL, HAT_LOAD_LOCK);
2170 
2171 		vaddr += MMU_PAGESIZE;
2172 		new_pfn++;
2173 	}
2174 
2175 	PR_REMAP("%s: remapped %ld pages (expected %ld)\n",
2176 	    proc, npgs, btopr(MB2B(mblen)));
2177 }
2178