xref: /titanic_44/usr/src/uts/sun4u/starfire/io/idn_proto.c (revision 4496171313bed39e96f21bc2f9faf2868e267ae3)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Inter-Domain Network
31  *
32  * IDN Protocol functions to support domain link/unlink/reconfig.
33  */
34 
35 #include <sys/types.h>
36 #include <sys/param.h>
37 #include <sys/machparam.h>
38 #include <sys/debug.h>
39 #include <sys/cpuvar.h>
40 #include <sys/kmem.h>
41 #include <sys/mutex.h>
42 #include <sys/rwlock.h>
43 #include <sys/systm.h>
44 #include <sys/stream.h>
45 #include <sys/strsun.h>
46 #include <sys/stropts.h>
47 #include <sys/sema_impl.h>
48 #include <sys/membar.h>
49 #include <sys/utsname.h>
50 #include <inet/common.h>
51 #include <inet/mi.h>
52 #include <netinet/ip6.h>
53 #include <inet/ip.h>
54 #include <netinet/in.h>
55 #include <sys/vm_machparam.h>
56 #include <sys/x_call.h>
57 #include <sys/ddi.h>
58 #include <sys/sunddi.h>
59 #include <sys/atomic.h>
60 #include <vm/as.h>		/* kas decl */
61 
62 #include <sys/idn.h>
63 #include <sys/idn_xf.h>
64 
65 #define	IDNBUG_CPUPERBOARD
66 
67 extern pri_t		maxclsyspri;
68 extern u_longlong_t	gettick();
69 
70 clock_t	idn_xmit_monitor_freq = 50;
71 
72 static int	idn_connect(int domid);
73 static int	idn_disconnect(int domid, idn_fin_t fintype,
74 				idn_finarg_t finarg, idn_finsync_t finsync);
75 static void	idn_deconfig(int domid);
76 static void	idn_unlink_domainset(domainset_t domset, idn_fin_t fintype,
77 				idn_finarg_t finarg, idn_finopt_t finopt,
78 				boardset_t idnset);
79 static void	idn_retry_execute(void *arg);
80 static void	idn_retry_submit(void (*func)(uint_t token, void *arg),
81 				void *arg, uint_t token, clock_t ticks);
82 static void	idn_shutdown_datapath(domainset_t domset, int force);
83 static mblk_t	*idn_fill_buffer(caddr_t bufp, int size, mblk_t *mp,
84 				uchar_t **data_rptrp);
85 static ushort_t	idn_cksum(register ushort_t *hdrp, register int count);
86 static int	idn_mark_awol(int domid, clock_t *atime);
87 
88 static void	idn_recv_proto(idn_protomsg_t *hp);
89 static void	idn_send_config(int domid, int phase);
90 static void	idn_recv_config(int domid, idn_msgtype_t *mtp,
91 				idn_xdcargs_t xargs);
92 static int	idn_send_master_config(int domid, int phase);
93 static int	idn_send_slave_config(int domid, int phase);
94 static uint_t	idn_check_master_config(int domid, uint_t *exp, uint_t *act);
95 static uint_t	idn_check_slave_config(int domid, uint_t *exp, uint_t *act);
96 static int	idn_recv_config_done(int domid);
97 static void	idn_nego_cleanup_check(int domid, int new_masterid,
98 				int new_cpuid);
99 static void	idn_recv_cmd(int domid, idn_msgtype_t *mtp,
100 				idn_xdcargs_t xargs);
101 static int	idn_recv_data(int domid, idn_msgtype_t *mtp,
102 				idn_xdcargs_t xargs);
103 static int	idn_send_data_loopback(idn_netaddr_t dst_netaddr,
104 				queue_t *wq, mblk_t *mp);
105 static void	idn_send_dataresp(int domid, idn_nack_t nacktype);
106 static int	idn_send_mboxdata(int domid, struct idn *sip, int channel,
107 				caddr_t bufp);
108 static int	idn_recv_mboxdata(int channel, caddr_t bufp);
109 static int	idn_program_hardware(int domid);
110 static int	idn_deprogram_hardware(int domid);
111 
112 static void	idn_send_cmd_nackresp(int domid, idn_msgtype_t *mtp,
113 			idn_cmd_t cmdtype, idn_nack_t nacktype);
114 static void	idn_local_cmd(idn_cmd_t cmdtype, uint_t arg1,
115 				uint_t arg2, uint_t arg3);
116 static void	idn_terminate_cmd(int domid, int serrno);
117 static void	idn_mboxarea_init(idn_mboxtbl_t *mtp, register int ntbls);
118 static void	idn_mainmbox_activate(int domid);
119 static void	idn_mainmbox_deactivate(ushort_t domset);
120 static void	idn_mainmbox_chan_register(int domid,
121 				idn_mainmbox_t *send_mmp,
122 				idn_mainmbox_t *recv_mmp, int channel);
123 static int	idn_mainmbox_chan_unregister(ushort_t domset, int channel);
124 static int	idn_mainmbox_flush(int domid, idn_mainmbox_t *mmp);
125 static void	idn_mainmbox_reset(int domid, idn_mainmbox_t *cmp);
126 static int	idn_activate_channel(idn_chanset_t chanset,
127 				idn_chanop_t chanop);
128 static void	idn_deactivate_channel(idn_chanset_t chanset,
129 				idn_chanop_t chanop);
130 static int	idn_deactivate_channel_services(int channel,
131 				idn_chanop_t chanop);
132 static int	idn_activate_channel_services(int channel);
133 static void	idn_chan_server(idn_chansvr_t **cspp);
134 #if 0
135 static void	idn_chan_flush(idn_chansvr_t *csp);
136 #endif /* 0 */
137 static void	idn_chan_action(int channel, idn_chanaction_t chanaction,
138 				int wait);
139 static void	idn_chan_addmbox(int channel, ushort_t domset);
140 static void	idn_chan_delmbox(int channel, ushort_t domset);
141 static void	idn_submit_chanactivate_job(int channel);
142 static void	idn_exec_chanactivate(void *chn);
143 
144 static void	idn_link_established(void *arg);
145 static void	idn_prealloc_slab(int nslabs);
146 static void	idn_recv_slaballoc_req(int domid, idn_msgtype_t *mtp,
147 				uint_t slab_size);
148 static void	idn_send_slaballoc_resp(int domid, idn_msgtype_t *mtp,
149 				uint_t slab_offset, uint_t slab_size,
150 				int serrno);
151 static void	idn_recv_slaballoc_resp(int domid, smr_offset_t slab_offset,
152 				uint_t slab_size, int serrno);
153 static void	idn_recv_slabreap_req(int domid, idn_msgtype_t *mtp,
154 				int nslabs);
155 static void	idn_recv_slabreap_resp(int domid, int nslabs, int serrno);
156 static void	idn_send_slabreap_resp(int domid, idn_msgtype_t *mtp,
157 				int nslabs, int serrno);
158 static void	idn_recv_slabfree_req(int domid, idn_msgtype_t *mtp,
159 				smr_offset_t slab_offset, uint_t slab_size);
160 static void	idn_recv_slabfree_resp(int domid, uint_t slab_offset,
161 				uint_t slab_size, int serrno);
162 static void	idn_send_slabfree_resp(int domid, idn_msgtype_t *mtp,
163 				uint_t slab_offset, uint_t slab_size,
164 				int serrno);
165 static void	idn_retry_nodename_req(void *arg);
166 static void	idn_send_nodename_req(int domid);
167 static void	idn_send_nodename_resp(int domid, idn_msgtype_t *mtp,
168 				uint_t bufoffset, int serrno);
169 static void	idn_recv_nodename_req(int domid, idn_msgtype_t *mtp,
170 				uint_t bufoffset);
171 static void	idn_recv_nodename_resp(int domid, uint_t bufoffset,
172 				int serrno);
173 
174 static void	idn_protocol_server(int *id);
175 static void	idn_protocol_server_killall();
176 static void	idn_protojob_free(idn_protojob_t *jp);
177 
178 static int	idn_xstate_transfunc(int domid, void *transarg);
179 static int	idn_xphase_transition(int domid, idn_msgtype_t *mtp,
180 				idn_xdcargs_t xargs);
181 static void	idn_sync_enter(int domid, idn_synccmd_t cmd,
182 				domainset_t xset, domainset_t rset,
183 				int (*transfunc)(), void *transarg);
184 static domainset_t
185 		idn_sync_register(int domid, idn_synccmd_t cmd,
186 				domainset_t ready_set, idn_syncreg_t regtype);
187 static void	idn_sync_register_awol(int domid);
188 static int	idn_verify_config_mbox(int domid);
189 static int	idn_select_master(int domid, int rmasterid, int rcpuid);
190 
191 static int	valid_mtu(uint_t mtu);
192 static int	valid_bufsize(uint_t bufsize);
193 static int	valid_slabsize(int slabsize);
194 static int	valid_nwrsize(int nwrsize);
195 
196 static int	idn_master_init();
197 static void	idn_master_deinit();
198 
199 static void	idn_send_acknack(int domid, idn_msgtype_t *mtp,
200 				idn_xdcargs_t xargs);
201 
202 static int	idn_send_nego(int domid, idn_msgtype_t *mtp,
203 				domainset_t conset);
204 static void	idn_retry_nego(uint_t token, void *arg);
205 static int	idn_check_nego(int domid, idn_msgtype_t *mtp,
206 				idn_xdcargs_t xargs);
207 static void	idn_action_nego_pend(int domid, idn_msgtype_t *mtp,
208 				idn_xdcargs_t xargs);
209 static void	idn_error_nego(int domid, idn_msgtype_t *mtp,
210 				idn_xdcargs_t xargs);
211 static void	idn_action_nego_sent(int domid, idn_msgtype_t *mtp,
212 				idn_xdcargs_t xargs);
213 static void	idn_action_nego_rcvd(int domid, idn_msgtype_t *mtp,
214 				idn_xdcargs_t xargs);
215 static void	idn_final_nego(int domid);
216 static void	idn_exit_nego(int domid, uint_t msgtype);
217 
218 static int	idn_send_con(int domid, idn_msgtype_t *mtp,
219 				idn_con_t contype, domainset_t conset);
220 static void	idn_retry_con(uint_t token, void *arg);
221 static int	idn_check_con(int domid, idn_msgtype_t *mtp,
222 				idn_xdcargs_t xargs);
223 static void	idn_action_con_pend(int domid, idn_msgtype_t *mtp,
224 				idn_xdcargs_t xargs);
225 static void	idn_error_con(int domid, idn_msgtype_t *mtp,
226 				idn_xdcargs_t xargs);
227 static void	idn_action_con_sent(int domid, idn_msgtype_t *mtp,
228 				idn_xdcargs_t xargs);
229 static void	idn_action_con_rcvd(int domid, idn_msgtype_t *mtp,
230 				idn_xdcargs_t xargs);
231 static void	idn_final_con(int domid);
232 static void	idn_exit_con(int domid, uint_t msgtype);
233 
234 static int	idn_send_fin(int domid, idn_msgtype_t *mtp, idn_fin_t fintype,
235 				idn_finarg_t finarg, idn_finopt_t finopt,
236 				domainset_t finset, uint_t finmaster);
237 static void	idn_retry_fin(uint_t token, void *arg);
238 static int	idn_check_fin_pend(int domid, idn_msgtype_t *mtp,
239 				idn_xdcargs_t xargs);
240 static void	idn_action_fin_pend(int domid, idn_msgtype_t *mtp,
241 				idn_xdcargs_t xargs);
242 static void	idn_error_fin_pend(int domid, idn_msgtype_t *mtp,
243 				idn_xdcargs_t xargs);
244 static int	idn_check_fin_sent(int domid, idn_msgtype_t *mtp,
245 				idn_xdcargs_t xargs);
246 static void	idn_action_fin_sent(int domid, idn_msgtype_t *mtp,
247 				idn_xdcargs_t xargs);
248 static void	idn_error_fin_sent(int domid, idn_msgtype_t *mtp,
249 				idn_xdcargs_t xargs);
250 static void	idn_action_fin_rcvd(int domid, idn_msgtype_t *mtp,
251 				idn_xdcargs_t xargs);
252 static void	idn_final_fin(int domid);
253 static void	idn_exit_fin(int domid, uint_t msgtype);
254 
255 /*
256  * We keep a small cache of protojob structures just
257  * in case allocation within idn_handler comes back
258  * with nothing from the land of kmem.
259  */
260 idn_protojob_t	idn_protojob_cache[IDN_DMV_PENDING_MAX];
261 idn_protojob_t	*idn_protojob_cache_list;
262 kmutex_t	idn_protojob_cache_lock;
263 
264 /*
265  *	- receive message.
266  *	- call check-function for current state.
267  *	- if (check-function == ok) then
268  *		call action-function for current state.
269  *	  else
270  *		call error-function for current state.
271  *	- transition state based on check results.
272  *	- if (next state == final state) then
273  *		call final-function.
274  */
275 static idn_xphase_t xphase_nego = {
276 	IDNP_NEGO,
277 	{
278 		{ IDNDS_NEGO_PEND,
279 			idn_check_nego,
280 			idn_action_nego_pend,
281 			idn_error_nego},
282 		{ IDNDS_NEGO_SENT,
283 			idn_check_nego,
284 			idn_action_nego_sent,
285 			idn_error_nego},
286 		{ IDNDS_NEGO_RCVD,
287 			NULL,
288 			idn_action_nego_rcvd,
289 			NULL },
290 		{ IDNDS_CONFIG, NULL, NULL, NULL },
291 	},
292 	idn_final_nego,
293 	idn_exit_nego
294 };
295 
296 static idn_xphase_t xphase_con = {
297 	IDNP_CON,
298 	{
299 		{ IDNDS_CON_PEND,
300 			idn_check_con,
301 			idn_action_con_pend,
302 			idn_error_con},
303 		{ IDNDS_CON_SENT,
304 			idn_check_con,
305 			idn_action_con_sent,
306 			idn_error_con},
307 		{ IDNDS_CON_RCVD,
308 			NULL,
309 			idn_action_con_rcvd,
310 			NULL },
311 		{ IDNDS_CON_READY, NULL, NULL, NULL },
312 	},
313 	idn_final_con,
314 	idn_exit_con
315 };
316 
317 static idn_xphase_t xphase_fin = {
318 	IDNP_FIN,
319 	{
320 		{ IDNDS_FIN_PEND,
321 			idn_check_fin_pend,
322 			idn_action_fin_pend,
323 			idn_error_fin_pend },
324 		{ IDNDS_FIN_SENT,
325 			idn_check_fin_sent,
326 			idn_action_fin_sent,
327 			idn_error_fin_sent },
328 		{ IDNDS_FIN_RCVD,
329 			NULL,
330 			idn_action_fin_rcvd,
331 			NULL },
332 		{ IDNDS_DMAP, NULL, NULL, NULL },
333 	},
334 	idn_final_fin,
335 	idn_exit_fin
336 };
337 
338 static int idnxs_state_table[4][5][2] = {
339 	{			/* IDNXS_PEND */
340 		{ IDNXS_SENT,	IDNXS_PEND },	/* 0 */
341 		{ IDNXS_RCVD,	IDNXS_PEND },	/* msg */
342 		{ IDNXS_NIL,	IDNXS_PEND },	/* msg+ack */
343 		{ IDNXS_PEND,	IDNXS_NIL },	/* ack */
344 		{ IDNXS_PEND,	IDNXS_NIL },	/* nack */
345 	},
346 	{			/* IDNXS_SENT */
347 		{ IDNXS_NIL,	IDNXS_NIL },	/* 0 */
348 		{ IDNXS_RCVD,	IDNXS_PEND },	/* msg */
349 		{ IDNXS_FINAL,	IDNXS_PEND },	/* msg+ack */
350 		{ IDNXS_NIL,	IDNXS_NIL },	/* ack */
351 		{ IDNXS_PEND,	IDNXS_NIL },	/* nack */
352 	},
353 	{			/* IDNXS_RCVD */
354 		{ IDNXS_NIL,	IDNXS_NIL },	/* 0 */
355 		{ IDNXS_NIL,	IDNXS_NIL },	/* msg */
356 		{ IDNXS_FINAL,	IDNXS_NIL },	/* msg+ack */
357 		{ IDNXS_FINAL,	IDNXS_NIL },	/* ack */
358 		{ IDNXS_PEND,	IDNXS_NIL },	/* nack */
359 	},
360 	{			/* IDNXS_FINAL */
361 		{ IDNXS_NIL,	IDNXS_NIL },	/* 0 */
362 		{ IDNXS_NIL,	IDNXS_NIL },	/* msg */
363 		{ IDNXS_NIL,	IDNXS_NIL },	/* msg+ack */
364 		{ IDNXS_NIL,	IDNXS_NIL },	/* ack */
365 		{ IDNXS_NIL,	IDNXS_NIL },	/* nack */
366 	}
367 };
368 
369 /*
370  * NONE		Respective domain does not have a master.
371  * OTHER	Respective domain has a master different
372  *		than either local or remote.
373  * LOCAL	Respective domain has chosen local as master.
374  * REMOTE	Respective domain has chosen remote as master.
375  *
376  * Actions:
377  *	VOTE		Compare votes and select one.
378  *	VOTE_RCFG	Compare votes and Reconfigure
379  *			if necessary, i.e. remote won.
380  *	CONNECT		Connect to remote's OTHER if different
381  *			than our local master.
382  *	LOCAL		Local domain is winner.
383  *	REMOTE		Remote domain is winner.
384  *	WAIT		Wait for remote to connect to our
385  *			master if his is different.
386  *	ERROR		An impossible condition.
387  *
388  * Index:
389  *	0 = Local
390  *	1 = Remote
391  */
392 static idn_master_select_t master_select_table[4][4] = {
393 	{				/* local	remote	*/
394 		MASTER_SELECT_VOTE,	/* NONE		NONE	*/
395 		MASTER_SELECT_CONNECT,	/* NONE		OTHER	*/
396 		MASTER_SELECT_LOCAL,	/* NONE		LOCAL	*/
397 		MASTER_SELECT_REMOTE	/* NONE		REMOTE	*/
398 	},
399 	{
400 		MASTER_SELECT_WAIT,	/* OTHER	NONE	*/
401 		MASTER_SELECT_CONNECT,	/* OTHER	OTHER	*/
402 		MASTER_SELECT_WAIT,	/* OTHER	LOCAL	*/
403 		MASTER_SELECT_WAIT	/* OTHER	REMOTE	*/
404 	},
405 	{
406 		MASTER_SELECT_LOCAL,	/* LOCAL	NONE	*/
407 		MASTER_SELECT_CONNECT,	/* LOCAL	OTHER	*/
408 		MASTER_SELECT_LOCAL,	/* LOCAL	LOCAL	*/
409 		MASTER_SELECT_VOTE_RCFG	/* LOCAL	REMOTE	*/
410 	},
411 	{
412 		MASTER_SELECT_REMOTE,	/* REMOTE	NONE	*/
413 		MASTER_SELECT_CONNECT,	/* REMOTE	OTHER	*/
414 		MASTER_SELECT_ERROR,	/* REMOTE	LOCAL	*/
415 		MASTER_SELECT_REMOTE	/* REMOTE	REMOTE	*/
416 	}
417 };
418 
419 void
420 idn_assign_cookie(int domid)
421 {
422 	static ushort_t	num = 0;
423 	ushort_t	cookie;
424 	procname_t	proc = "idn_assign_cookie";
425 
426 	if ((cookie = idn_domain[domid].dcookie_recv) != 0)
427 		return;
428 
429 	cookie = (ushort_t)(((uint64_t)&idn_domain[domid] >> 8) & 0xff);
430 	while ((cookie ^= num++ & 0xff) == 0)
431 		;
432 
433 	PR_PROTO("%s:%d: assigned RECV cookie 0x%x\n", proc, domid, cookie);
434 
435 	idn_domain[domid].dcookie_recv = cookie;
436 }
437 
438 void
439 idn_update_priority(int domid, int pri)
440 {
441 	idn_domain_t	*dp;
442 	procname_t	proc = "idn_update_priority";
443 
444 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
445 
446 	dp = &idn_domain[domid];
447 
448 	if (pri >= IDNVOTE_MINPRI) {
449 		dp->dvote.v.priority = pri & IDNVOTE_PRI_MASK;
450 
451 		PR_PROTO("%s:%d: SETTING PRIORITY to req(%d) "
452 			"(localpri = 0x%x)\n",
453 			proc, domid, pri, IDNVOTE_PRIVALUE(dp->dvote));
454 	} else {
455 		PR_PROTO("%s:%d: PRIORITIES UNCHANGED (pri = 0x%x)\n",
456 			proc, domid, IDNVOTE_PRIVALUE(dp->dvote));
457 	}
458 }
459 
460 /*
461  * Initiate a link between the local domain and the remote domain
462  * containing the given cpuid.
463  */
464 int
465 idn_link(int domid, int cpuid, int pri, int waittime, idnsb_error_t *sep)
466 {
467 	int		rv;
468 	idn_domain_t	*dp;
469 	void		*opcookie;
470 	procname_t	proc = "idn_link";
471 
472 	if ((cpuid < 0) || (cpuid >= NCPU)) {
473 		cmn_err(CE_WARN,
474 			"IDN: 201: (LINK) invalid CPU ID (%d)", cpuid);
475 		return (EINVAL);
476 	}
477 	if (waittime < 0) {
478 		cmn_err(CE_WARN,
479 			"IDN: 202: (LINK) invalid time-out value (%d)",
480 			waittime);
481 		return (EINVAL);
482 	}
483 	if (!VALID_DOMAINID(domid)) {
484 		cmn_err(CE_WARN,
485 			"IDN: 203: (LINK) invalid domain ID (%d)",
486 			domid);
487 		return (EINVAL);
488 	}
489 	if (domid == idn.localid)
490 		return (0);
491 
492 	IDN_SYNC_LOCK();
493 	IDN_DLOCK_EXCL(domid);
494 
495 	dp = &idn_domain[domid];
496 
497 	switch (dp->dstate) {
498 	case IDNDS_CLOSED:
499 		break;
500 
501 	case IDNDS_CONNECTED:
502 #ifdef DEBUG
503 		cmn_err(CE_NOTE,
504 			"!IDN: domain %d (CPU ID %d) already connected",
505 			domid, cpuid);
506 #endif /* DEBUG */
507 		IDN_DUNLOCK(domid);
508 		IDN_SYNC_UNLOCK();
509 		return (0);
510 
511 	default:
512 		cmn_err(CE_WARN,
513 			"IDN: 204: domain %d state (%s) inappropriate",
514 			domid, idnds_str[dp->dstate]);
515 		IDN_DUNLOCK(domid);
516 		IDN_SYNC_UNLOCK();
517 		return (EINVAL);
518 	}
519 
520 	rv = idn_open_domain(domid, cpuid, 0);
521 	if (rv != 0) {
522 		cmn_err(CE_WARN,
523 			"IDN: 205: (%s) failed to open-domain(%d,%d)",
524 			proc, domid, cpuid);
525 		IDN_DUNLOCK(domid);
526 		IDN_SYNC_UNLOCK();
527 		return (EIO);
528 	}
529 
530 
531 	IDN_DLOCK_EXCL(idn.localid);
532 	idn_update_priority(idn.localid, pri);
533 	IDN_DUNLOCK(idn.localid);
534 
535 	if (waittime > 0)
536 		opcookie = idn_init_op(IDNOP_CONNECTED, DOMAINSET(domid), sep);
537 
538 	idn_connect(domid);
539 
540 	IDN_DUNLOCK(domid);
541 	IDN_SYNC_UNLOCK();
542 
543 	PR_PROTO("%s:%d: ALLOCATED idn_link(%d)\n", proc, domid, cpuid);
544 
545 	if (waittime > 0) {
546 		boardset_t	domset = 0;
547 		/*
548 		 * Well we've successfully allocated a domain id,
549 		 * but the link may not be fully established yet.
550 		 * Need to wait since it happens asynchronously.
551 		 */
552 		PR_PROTO("%s:%d: WAITING for op(%s) for (domset 0%x)...\n",
553 			proc, domid, idnop_str[IDNOP_CONNECTED],
554 			DOMAINSET(domid));
555 
556 		rv = idn_wait_op(opcookie, &domset, waittime);
557 	}
558 
559 #ifdef DEBUG
560 	if (rv == 0) {
561 		if (waittime > 0) {
562 			PR_PROTO("%s:%d: connect SUCCEEDED (cpu %d)\n",
563 					proc, domid, cpuid);
564 		} else {
565 			PR_PROTO("%s:%d: connect KICKED OFF (cpu %d)\n",
566 					proc, domid, cpuid);
567 		}
568 	} else {
569 		PR_PROTO("%s:%d: connect FAILED (cpu %d)\n",
570 				proc, domid, cpuid);
571 	}
572 #endif /* DEBUG */
573 
574 	return (rv);
575 }
576 
577 /*
578  * Unlink the given domain from any domain cluster of
579  * which it might be a member.  Force indicates that domain
580  * should not go AWOL and if it's currently AWOL to close
581  * and remove it.
582  * IMPORTANT: If the (hard) force flag is set, the caller is
583  *	      assumed to GUARANTEE that the given domain will
584  *	      not attempt to communicate with the local domain
585  *	      in any manner.
586  */
587 int
588 idn_unlink(int domid, boardset_t idnset, idn_fin_t fintype,
589 		idn_finopt_t finopt, int waittime, idnsb_error_t *sep)
590 {
591 	int		rv = 0;
592 	domainset_t	domset;
593 	void		*opcookie;
594 	procname_t	proc = "idn_unlink";
595 
596 
597 	if (waittime < 0) {
598 		cmn_err(CE_WARN,
599 			"IDN: 202: (UNLINK) invalid time-out value (%d)",
600 			waittime);
601 		SET_IDNKERR_IDNERR(sep, IDNKERR_INVALID_WTIME);
602 		SET_IDNKERR_PARAM0(sep, waittime);
603 		return (EINVAL);
604 	}
605 	if (!VALID_DOMAINID(domid)) {
606 		cmn_err(CE_WARN,
607 			"IDN: 203: (UNLINK) invalid domain ID (%d)",
608 			domid);
609 		SET_IDNKERR_IDNERR(sep, IDNKERR_INVALID_DOMAIN);
610 		SET_IDNKERR_PARAM0(sep, domid);
611 		SET_IDNKERR_PARAM1(sep, -1);
612 		return (EINVAL);
613 	}
614 	if (idn.localid == IDN_NIL_DOMID) {
615 #ifdef DEBUG
616 		cmn_err(CE_NOTE,
617 			"!IDN: %s: local domain not connected to an IDNnet",
618 			proc);
619 #endif /* DEBUG */
620 		return (0);
621 	}
622 
623 	/*
624 	 * Lock ordering protocols requires that we grab the
625 	 * global lock _before_ the local domain's lock.
626 	 * However, non-local domains must have their lock
627 	 * grabbed _before_ the global lock.
628 	 */
629 	IDN_SYNC_LOCK();
630 	IDN_GLOCK_EXCL();
631 	domset = idn.domset.ds_trans_on | idn.domset.ds_trans_off;
632 	if ((idn.state == IDNGS_OFFLINE) && !domset) {
633 #ifdef DEBUG
634 		cmn_err(CE_WARN,
635 			"!IDN: %s: local domain not connected to an IDNnet",
636 			proc);
637 #endif /* DEBUG */
638 		IDN_GUNLOCK();
639 		IDN_SYNC_UNLOCK();
640 		return (0);
641 	}
642 
643 	if ((domid == IDN_NIL_DOMID) || (domid == idn.localid)) {
644 		domid = idn.localid;
645 		IDN_GSTATE_TRANSITION(IDNGS_DISCONNECT);
646 		IDN_SET_NEW_MASTERID(IDN_NIL_DOMID);
647 		domset = DOMAINSET_ALL;
648 		DOMAINSET_DEL(domset, idn.localid);
649 	} else {
650 		domset = DOMAINSET(domid);
651 	}
652 	IDN_GUNLOCK();
653 
654 	if (waittime > 0)
655 		opcookie = idn_init_op(IDNOP_DISCONNECTED, domset, sep);
656 
657 	idn_unlink_domainset(domset, fintype, IDNFIN_ARG_NONE, finopt, idnset);
658 
659 	IDN_SYNC_UNLOCK();
660 
661 	if (waittime > 0) {
662 		/*
663 		 * Well the unlink has successfully kicked off.
664 		 * Since process is asynchronous we need to wait
665 		 * for it to complete.
666 		 */
667 		PR_PROTO("%s:%d: WAITING for op(%s) for (domset 0%x)...\n",
668 			proc, domid, idnop_str[IDNOP_DISCONNECTED],
669 			domset);
670 
671 		rv = idn_wait_op(opcookie, &domset, waittime);
672 	}
673 
674 	if (rv == 0) {
675 		if (waittime > 0) {
676 			PR_PROTO("%s:%d: disconnect SUCCEEDED\n",
677 				proc, domid);
678 		} else {
679 			PR_PROTO("%s:%d: disconnect KICKED OFF\n",
680 				proc, domid);
681 		}
682 	} else {
683 		PR_PROTO("%s:%d: disconnect FAILED\n", proc, domid);
684 	}
685 
686 	return (rv);
687 }
688 
689 static void
690 idn_unlink_domainset(domainset_t domset, idn_fin_t fintype,
691 			idn_finarg_t finarg, idn_finopt_t finopt,
692 			boardset_t idnset)
693 {
694 	int		d;
695 	domainset_t	offset;
696 	procname_t	proc = "idn_unlink_domainset";
697 
698 	ASSERT(IDN_SYNC_IS_LOCKED());
699 
700 	/*
701 	 * Determine subset for which we have
702 	 * no active connections.
703 	 */
704 	offset = domset & ~(idn.domset.ds_trans_on |
705 				idn.domset.ds_connected |
706 				idn.domset.ds_trans_off |
707 				idn.domset.ds_relink);
708 	/*
709 	 * Determine subset that are really candidates.
710 	 * Note that we include those already down the path
711 	 * since it's possible a request came in to upgrade
712 	 * their fintype (e.g. NORMAL->FORCE_SOFT).
713 	 */
714 	domset &= ~offset;
715 
716 	if (offset)
717 		idn_update_op(IDNOP_DISCONNECTED, offset, NULL);
718 
719 	IDN_GLOCK_EXCL();
720 	if ((finopt == IDNFIN_OPT_RELINK) && (idn.state != IDNGS_DISCONNECT)) {
721 		/*
722 		 * Don't add domains already transitioning off.
723 		 * If they caught on an earlier Reconfig wave then
724 		 * they'll already be in ds_relink anyway.  Otherwise,
725 		 * once a domain is transition off we can't upgrade
726 		 * him to a RELINK.
727 		 */
728 #ifdef DEBUG
729 		if (idn.domset.ds_hitlist & domset) {
730 			PR_HITLIST("%s: domset=%x, hitlist=%x, trans_off=%x "
731 				"-> relink = %x -> %x\n",
732 				proc, domset, idn.domset.ds_hitlist,
733 				idn.domset.ds_relink, idn.domset.ds_trans_off,
734 				idn.domset.ds_relink |
735 					(domset & ~idn.domset.ds_trans_off));
736 		}
737 #endif /* DEBUG */
738 
739 		domset &= ~idn.domset.ds_trans_off;
740 		idn.domset.ds_relink |= domset;
741 	} else {
742 		idn.domset.ds_relink &= ~domset;
743 	}
744 	/*
745 	 * Update the ds_trans_on/off so we don't waste
746 	 * time talking to these folks.
747 	 */
748 	idn.domset.ds_trans_on  &= ~domset;
749 	idn.domset.ds_trans_off |= domset;
750 
751 	if (domset == 0) {
752 		if ((idn.domset.ds_trans_on |
753 				idn.domset.ds_connected |
754 				idn.domset.ds_trans_off |
755 				idn.domset.ds_relink) == 0) {
756 			PR_HITLIST("%s:%x: HITLIST %x -> 0\n",
757 				proc, domset, idn.domset.ds_hitlist);
758 			idn.domset.ds_hitlist = 0;
759 			IDN_GSTATE_TRANSITION(IDNGS_OFFLINE);
760 		}
761 		IDN_GUNLOCK();
762 		return;
763 	}
764 	IDN_GUNLOCK();
765 
766 	for (d = 0; d < MAX_DOMAINS; d++) {
767 		idn_domain_t	*dp;
768 		idn_fin_t	ftype;
769 
770 		if (!DOMAIN_IN_SET(domset, d))
771 			continue;
772 
773 		dp = &idn_domain[d];
774 		IDN_DLOCK_EXCL(d);
775 		IDN_HISTORY_LOG(IDNH_RELINK, d, dp->dstate,
776 					idn.domset.ds_relink);
777 		ftype = fintype;
778 		if ((dp->dcpu != IDN_NIL_DCPU) && dp->dhw.dh_boardset) {
779 			/*
780 			 * If domain is not in the IDNSET passed
781 			 * down then we need to upgrade this to
782 			 * hard-force in order to prevent possible
783 			 * system failures (arbstop).  This is simply
784 			 * extra protection beyond that checked by
785 			 * the SSP.  IDNSET contains the set of boards
786 			 * that have a "link" to the local domain,
787 			 * including the SMD regs.
788 			 */
789 			if ((idnset & dp->dhw.dh_boardset) == 0) {
790 				PR_PROTO("%s:%d: boardset 0x%x "
791 					"NOT in IDNSET 0x%x\n",
792 					proc, d, dp->dhw.dh_boardset,
793 					idnset);
794 				if (ftype != IDNFIN_FORCE_HARD)
795 					cmn_err(CE_NOTE,
796 						"!IDN: 222: no IDN linkage "
797 						"found (b=0x%x, i=0x%x) "
798 						"upgrading unlink %s to %s",
799 						dp->dhw.dh_boardset,
800 						idnset, idnfin_str[ftype],
801 						idnfin_str[IDNFIN_FORCE_HARD]);
802 
803 				ftype = IDNFIN_FORCE_HARD;
804 			} else {
805 				PR_PROTO("%s:%d: boardset 0x%x "
806 					"FOUND in IDNSET 0x%x\n",
807 					proc, d, dp->dhw.dh_boardset,
808 					idnset);
809 			}
810 		}
811 		idn_disconnect(d, ftype, finarg, IDNDS_SYNC_TYPE(dp));
812 		IDN_DUNLOCK(d);
813 	}
814 }
815 
816 /*
817  * Return w/locks held.
818  */
819 static int
820 idn_connect(int domid)
821 {
822 	idn_xdcargs_t	xargs;
823 	idn_domain_t	*dp = &idn_domain[domid];
824 	procname_t	proc = "idn_connect";
825 
826 	ASSERT(IDN_SYNC_IS_LOCKED());
827 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
828 
829 	ASSERT(dp->dcpu != IDN_NIL_DCPU);
830 
831 	if (dp->dstate != IDNDS_CLOSED) {
832 		if (DOMAIN_IN_SET(idn.domset.ds_trans_on |
833 				idn.domset.ds_connected, domid)) {
834 			PR_PROTO("%s:%d: already connected or "
835 				"in-progress\n", proc, domid);
836 		} else {
837 			PR_PROTO("%s:%d: current state (%s) != "
838 				"CLOSED\n", proc, domid,
839 				idnds_str[dp->dstate]);
840 		}
841 		return (-1);
842 	}
843 
844 	ASSERT(!DOMAIN_IN_SET(idn.domset.ds_connected, domid));
845 	ASSERT(!DOMAIN_IN_SET(idn.domset.ds_trans_off, domid));
846 
847 	dp->dxp = &xphase_nego;
848 	IDN_XSTATE_TRANSITION(dp, IDNXS_PEND);
849 
850 	idn_xphase_transition(domid, NULL, xargs);
851 
852 	return (0);
853 }
854 
855 /*
856  * Return w/locks held.
857  */
858 static int
859 idn_disconnect(int domid, idn_fin_t fintype, idn_finarg_t finarg,
860 		idn_finsync_t finsync)
861 {
862 	int		new_masterid, new_cpuid = IDN_NIL_DCPU;
863 	uint_t		token;
864 	uint_t		finmaster;
865 	idn_xdcargs_t	xargs;
866 	idn_finopt_t	finopt;
867 	idn_domain_t	*dp = &idn_domain[domid];
868 	procname_t	proc = "idn_disconnect";
869 
870 	ASSERT(IDN_SYNC_IS_LOCKED());
871 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
872 
873 	if (dp->dstate == IDNDS_CLOSED) {
874 		PR_PROTO("%s:%d: already CLOSED\n", proc, domid);
875 		idn_update_op(IDNOP_DISCONNECTED, DOMAINSET(domid), NULL);
876 		return (-1);
877 	}
878 
879 	/*
880 	 * Terminate any outstanding commands that were
881 	 * targeted towards this domain.
882 	 */
883 	idn_terminate_cmd(domid, ECANCELED);
884 
885 	/*
886 	 * Terminate any and all retries that may have
887 	 * outstanding for this domain.
888 	 */
889 	token = IDN_RETRY_TOKEN(domid, IDN_RETRY_TYPEALL);
890 	(void) idn_retry_terminate(token);
891 
892 	/*
893 	 * Stop all outstanding message timers for
894 	 * this guy.
895 	 */
896 	IDN_MSGTIMER_STOP(domid, 0, 0);
897 
898 	dp->dxp = &xphase_fin;
899 	IDN_XSTATE_TRANSITION(dp, IDNXS_PEND);
900 	if ((int)dp->dfin < (int)fintype) {
901 		/*
902 		 * You can only upgrade a fin type.
903 		 * We don't allow it to be downgraded
904 		 * as it's too dangerous since some
905 		 * state may have been blown away while
906 		 * we were fin'ing at a higher level.
907 		 */
908 		IDN_FSTATE_TRANSITION(dp, fintype);
909 	}
910 
911 	dp->dfin_sync = finsync;
912 	PR_PROTO("%s:%d: disconnect synchronously = %s\n",
913 		proc, domid, (finsync == IDNFIN_SYNC_OFF) ? "OFF" :
914 		(finsync == IDNFIN_SYNC_NO) ? "NO" : "YES");
915 
916 	IDN_GLOCK_SHARED();
917 	if (DOMAIN_IN_SET(idn.domset.ds_relink, domid) &&
918 			(idn.state != IDNGS_DISCONNECT)) {
919 		finopt = IDNFIN_OPT_RELINK;
920 	} else {
921 		finopt = IDNFIN_OPT_UNLINK;
922 		PR_HITLIST("%s:%d: HITLIST %x -> %x\n",
923 			proc, domid, idn.domset.ds_hitlist,
924 			idn.domset.ds_hitlist | DOMAINSET(domid));
925 		DOMAINSET_ADD(idn.domset.ds_hitlist, domid);
926 	}
927 
928 	CLR_XARGS(xargs);
929 	SET_XARGS_FIN_TYPE(xargs, dp->dfin);
930 	SET_XARGS_FIN_ARG(xargs, finarg);
931 	SET_XARGS_FIN_OPT(xargs, finopt);
932 	SET_XARGS_FIN_DOMSET(xargs, 0);		/* unused when msg = 0 */
933 	new_masterid = IDN_GET_NEW_MASTERID();
934 	IDN_GUNLOCK();
935 	if (new_masterid != IDN_NIL_DOMID)
936 		new_cpuid = idn_domain[new_masterid].dcpu;
937 	finmaster = MAKE_FIN_MASTER(new_masterid, new_cpuid);
938 	SET_XARGS_FIN_MASTER(xargs, finmaster);
939 
940 	idn_xphase_transition(domid, NULL, xargs);
941 
942 	return (0);
943 }
944 
945 static int
946 idn_next_xstate(idn_xstate_t o_xstate, int err, uint_t msg)
947 {
948 	int		index;
949 	procname_t	proc = "idn_next_xstate";
950 
951 	ASSERT(((int)o_xstate >= 0) && ((int)o_xstate <= 4));
952 
953 	if (!msg)
954 		index = 0;
955 	else if ((msg & IDNP_MSGTYPE_MASK) == 0)
956 		index = (msg & IDNP_ACK) ? 3 : (msg & IDNP_NACK) ? 4 : -1;
957 	else
958 		index = (msg & IDNP_ACK) ? 2 :
959 				!(msg & IDNP_ACKNACK_MASK) ? 1 : -1;
960 
961 	if (index == -1) {
962 		STRING(str);
963 
964 		INUM2STR(msg, str);
965 		PR_PROTO("%s: (msg = 0x%x(%s))\n", proc, msg, str);
966 		return (IDNXS_NIL);
967 	}
968 
969 	if (err == -1) {
970 		int	n_xstate;
971 		/*
972 		 * Caller is just interested in querying is this
973 		 * is a valid message to receive in the current
974 		 * xstate.  A return value of IDNXS_NIL indicates
975 		 * that it's not.  A return value of non-IDNXS_NIL
976 		 * indicates it's cool.  An invalid message is
977 		 * determined by both err & !err states being IDNXS_NIL.
978 		 */
979 		n_xstate = idnxs_state_table[(int)o_xstate][index][0];
980 		if (n_xstate != IDNXS_NIL)
981 			return (n_xstate);
982 		else
983 			return (idnxs_state_table[(int)o_xstate][index][1]);
984 	} else {
985 		return (idnxs_state_table[(int)o_xstate][index][err ? 1 : 0]);
986 	}
987 }
988 
989 static int
990 idn_select_candidate(domainset_t master_set)
991 {
992 	int		d, best_id = IDN_NIL_DOMID;
993 	uint_t		best_vote = 0;
994 	idn_domain_t	*dp;
995 	procname_t	proc = "idn_select_candidate";
996 
997 	ASSERT(IDN_SYNC_IS_LOCKED());
998 
999 	if (master_set == 0) {
1000 		PR_PROTO("%s: %x -> %d\n", proc, master_set, IDN_NIL_DOMID);
1001 		return (IDN_NIL_DOMID);
1002 	}
1003 
1004 	for (d = 0; d < MAX_DOMAINS; d++) {
1005 		uint_t		vote;
1006 		idn_vote_t	v;
1007 
1008 		if (!DOMAIN_IN_SET(master_set, d))
1009 			continue;
1010 
1011 		dp = &idn_domain[d];
1012 
1013 		if ((dp->domid == IDN_NIL_DOMID) ||
1014 			(dp->dcpu == IDN_NIL_DCPU) ||
1015 			((v.ticket = dp->dvote.ticket) == 0))
1016 			continue;
1017 
1018 		vote = IDNVOTE_ELECT(v);
1019 
1020 		if (vote > best_vote) {
1021 			best_vote = vote;
1022 			best_id = d;
1023 		}
1024 	}
1025 
1026 	PR_PROTO("%s: %x -> %d\n", proc, master_set, best_id);
1027 
1028 	return (best_id);
1029 }
1030 
1031 /*
1032  * If a non-zero value is returned then GLOCK will have been dropped.
1033  * Otherwise, routine returns with all incoming locks still held.
1034  */
1035 static int
1036 idn_select_master(int domid, int rmasterid, int rcpuid)
1037 {
1038 	char		*sel;
1039 	int		lmasterid, masterid;
1040 	int		do_reconfig = 0;
1041 	int		lindex, rindex;
1042 	idn_domain_t	*ldp, *rdp;
1043 	uint_t		rvote, lvote;
1044 	idn_master_select_t	select;
1045 	procname_t	proc = "idn_select_master";
1046 
1047 	ASSERT(IDN_SYNC_IS_LOCKED());
1048 	ASSERT(IDN_GLOCK_IS_EXCL());
1049 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
1050 
1051 	PR_PROTO("%s:%d: lmasterid = %d, rmasterid = %d, rcpuid = %d\n",
1052 		proc, domid, IDN_GET_MASTERID(), rmasterid, rcpuid);
1053 
1054 	IDN_DLOCK_EXCL(idn.localid);
1055 
1056 	ldp = &idn_domain[idn.localid];
1057 	rdp = &idn_domain[domid];
1058 
1059 	/*
1060 	 * Clear master bits since mastership is derived from
1061 	 * other information (local/remote idn.masterid/idn.new_masterid)
1062 	 * and we don't want the vote master bit to confuse matters.
1063 	 */
1064 	lvote = IDNVOTE_ELECT(ldp->dvote);
1065 	rvote = IDNVOTE_ELECT(rdp->dvote);
1066 
1067 	lmasterid = IDN_GET_MASTERID();
1068 
1069 	lindex = (lmasterid == IDN_NIL_DOMID) ? MASTER_IS_NONE :
1070 			(lmasterid == idn.localid) ? MASTER_IS_LOCAL :
1071 			(lmasterid == domid) ? MASTER_IS_REMOTE :
1072 			MASTER_IS_OTHER;
1073 
1074 	rindex = (rmasterid == IDN_NIL_DOMID) ? MASTER_IS_NONE :
1075 			(rmasterid == domid) ? MASTER_IS_REMOTE :
1076 			(rmasterid == idn.localid) ? MASTER_IS_LOCAL :
1077 			MASTER_IS_OTHER;
1078 
1079 	select = master_select_table[lindex][rindex];
1080 
1081 	masterid = IDN_NIL_DOMID;
1082 
1083 	/*
1084 	 * Each case is responsible for dropping DLOCK(localid)
1085 	 * and GLOCK if it doesn't select a master, unless a
1086 	 * reconfig is necessary.
1087 	 */
1088 	switch (select) {
1089 	case MASTER_SELECT_VOTE_RCFG:
1090 		sel = "VOTE_RECONFIG";
1091 		if (lvote > rvote) {
1092 			/*
1093 			 * If the local domain is the winner then remote
1094 			 * domain will have to Reconfig.  We'll continue
1095 			 * through the connection process anyway.  The
1096 			 * remote domains will tell us to back-off while
1097 			 * Reconfigs, but that's okay as we'll keep retrying.
1098 			 */
1099 			masterid = idn.localid;
1100 		} else if (lvote < rvote) {
1101 			do_reconfig = 1;
1102 			/*
1103 			 * GLOCK will get dropped once reconfig
1104 			 * is kicked off.
1105 			 */
1106 		} else {
1107 			cmn_err(CE_WARN,
1108 				"IDN: 206: cannot link domains "
1109 				"with equal votes (L(%d),R(%d),0x%x)",
1110 				idn.localid, domid, rvote);
1111 			IDN_GUNLOCK();
1112 		}
1113 		IDN_DUNLOCK(idn.localid);
1114 		break;
1115 
1116 	case MASTER_SELECT_VOTE:
1117 		sel = "VOTE";
1118 		if (lvote > rvote) {
1119 			masterid = idn.localid;
1120 			ldp->dvote.v.master = 1;
1121 			rdp->dvote.v.master = 0;
1122 		} else if (lvote < rvote) {
1123 			masterid = domid;
1124 			ldp->dvote.v.master = 0;
1125 			rdp->dvote.v.master = 1;
1126 		} else {
1127 			cmn_err(CE_WARN,
1128 				"IDN: 206: cannot link domains "
1129 				"with equal votes (L(%d),R(%d),0x%x)",
1130 				idn.localid, domid, rvote);
1131 		}
1132 		ASSERT(IDN_GET_MASTERID() == IDN_NIL_DOMID);
1133 		if (masterid != IDN_NIL_DOMID) {
1134 			IDN_SET_MASTERID(masterid);
1135 			IDN_SET_NEW_MASTERID(IDN_NIL_DOMID);
1136 		} else {
1137 			IDN_GUNLOCK();
1138 		}
1139 		IDN_DUNLOCK(idn.localid);
1140 		break;
1141 
1142 	case MASTER_SELECT_REMOTE:
1143 		sel = "REMOTE";
1144 		masterid = domid;
1145 		if (IDN_GET_MASTERID() == IDN_NIL_DOMID) {
1146 			IDN_SET_MASTERID(masterid);
1147 			IDN_SET_NEW_MASTERID(IDN_NIL_DOMID);
1148 			ldp->dvote.v.master = 0;
1149 			rdp->dvote.v.master = 1;
1150 		}
1151 		ASSERT(IDN_GET_MASTERID() == domid);
1152 		IDN_DUNLOCK(idn.localid);
1153 		break;
1154 
1155 	case MASTER_SELECT_LOCAL:
1156 		sel = "LOCAL";
1157 		masterid = idn.localid;
1158 		if (IDN_GET_MASTERID() == IDN_NIL_DOMID) {
1159 			IDN_SET_MASTERID(masterid);
1160 			IDN_SET_NEW_MASTERID(IDN_NIL_DOMID);
1161 			ldp->dvote.v.master = 1;
1162 			rdp->dvote.v.master = 0;
1163 		}
1164 		ASSERT(IDN_GET_MASTERID() == idn.localid);
1165 		IDN_DUNLOCK(idn.localid);
1166 		break;
1167 
1168 	case MASTER_SELECT_CONNECT:
1169 		sel = "CONNECT";
1170 		if (rmasterid == lmasterid) {
1171 			/*
1172 			 * Local and remote have same master,
1173 			 * let him come onboard.
1174 			 */
1175 			masterid = lmasterid;
1176 			IDN_DUNLOCK(idn.localid);
1177 
1178 		} else {
1179 			int	rv;
1180 
1181 			IDN_DUNLOCK(idn.localid);
1182 			IDN_GUNLOCK();
1183 			IDN_DLOCK_EXCL(rmasterid);
1184 			PR_PROTO("%s:%d: attempting connect w/remote "
1185 				"master %d\n",
1186 				proc, domid, rmasterid);
1187 			rv = idn_open_domain(rmasterid, rcpuid, 0);
1188 			if (rv == 0) {
1189 				idn_connect(rmasterid);
1190 			} else if (rv < 0) {
1191 				cmn_err(CE_WARN,
1192 					"IDN: 205: (%s) failed to "
1193 					"open-domain(%d,%d)",
1194 					proc, rmasterid, rcpuid);
1195 			} else {
1196 				/*
1197 				 * Must already have a connection going.
1198 				 */
1199 				PR_PROTO("%s:%d: failed "
1200 					"idn_open_domain(%d,%d,0) "
1201 					"(rv = %d)\n",
1202 					proc, domid, rmasterid,
1203 					rcpuid, rv);
1204 			}
1205 			IDN_DUNLOCK(rmasterid);
1206 		}
1207 		break;
1208 
1209 	case MASTER_SELECT_WAIT:
1210 		sel = "WAIT";
1211 		/*
1212 		 * If the remote domain has the same master as the local
1213 		 * domain then there's no need to wait.
1214 		 */
1215 		if (rmasterid == lmasterid) {
1216 			masterid = lmasterid;
1217 		} else {
1218 			IDN_GUNLOCK();
1219 		}
1220 		IDN_DUNLOCK(idn.localid);
1221 		break;
1222 
1223 	case MASTER_SELECT_ERROR:
1224 		sel = "ERROR";
1225 		/*
1226 		 * Hit impossible condition.
1227 		 */
1228 		cmn_err(CE_WARN,
1229 			"IDN: 207: local/remote master-id conflict "
1230 			"(%d.lmasterid = %d, %d.rmasterid = %d)",
1231 			idn.localid, lmasterid, domid, rmasterid);
1232 		IDN_GUNLOCK();
1233 		IDN_DUNLOCK(idn.localid);
1234 		break;
1235 
1236 	default:
1237 		cmn_err(CE_WARN,
1238 			"IDN: 208: %s: unknown case (%d)",
1239 			proc, (int)select);
1240 		IDN_GUNLOCK();
1241 		IDN_DUNLOCK(idn.localid);
1242 		ASSERT(0);
1243 		break;
1244 	}
1245 
1246 	if (masterid == IDN_NIL_DOMID) {
1247 		PR_PROTO("%s:%d: NO MASTER SELECTED (rmstr=%d) sel=%s\n",
1248 			proc, domid, rmasterid, sel);
1249 	} else {
1250 		PR_PROTO("%s:%d: MASTER SELECTED = %d (%s)\n",
1251 			proc, domid, masterid,
1252 			(masterid == idn.localid) ? "LOCAL" :
1253 			(masterid == domid) ? "REMOTE" : "OTHER");
1254 	}
1255 
1256 	if (do_reconfig) {
1257 		domainset_t	dis_set;
1258 
1259 		/*
1260 		 * Local domain already has a master.
1261 		 * Need to dismantle all connections
1262 		 * and reestablish one with new master.
1263 		 */
1264 		IDN_GKSTAT_GLOBAL_EVENT(gk_reconfigs, gk_reconfig_last);
1265 
1266 		PR_PROTO("%s:%d: RECONFIG new masterid = %d\n",
1267 				proc, domid, domid);
1268 
1269 		IDN_GSTATE_TRANSITION(IDNGS_RECONFIG);
1270 		IDN_SET_NEW_MASTERID(domid);
1271 		IDN_GUNLOCK();
1272 
1273 		dis_set = idn.domset.ds_trans_on | idn.domset.ds_connected;
1274 		DOMAINSET_DEL(dis_set, domid);
1275 
1276 		idn_unlink_domainset(dis_set, IDNFIN_NORMAL,
1277 					IDNFIN_ARG_NONE, IDNFIN_OPT_RELINK,
1278 					BOARDSET_ALL);
1279 	}
1280 
1281 	return ((masterid == IDN_NIL_DOMID) ? -1 : 0);
1282 }
1283 
1284 /*ARGSUSED1*/
1285 static void
1286 idn_retry_query(uint_t token, void *arg)
1287 {
1288 	idn_retry_t	rtype = IDN_RETRY_TOKEN2TYPE(token);
1289 	int		d, domid = IDN_RETRY_TOKEN2DOMID(token);
1290 	idn_domain_t	*dp = &idn_domain[domid];
1291 	idn_synccmd_t	sync_cmd;
1292 	domainset_t	query_set, my_ready_set;
1293 	procname_t	proc = "idn_retry_query";
1294 
1295 	IDN_SYNC_LOCK();
1296 	IDN_DLOCK_EXCL(domid);
1297 
1298 	switch (rtype) {
1299 	case IDNRETRY_CONQ:
1300 		sync_cmd = IDNSYNC_CONNECT;
1301 		my_ready_set = idn.domset.ds_ready_on |
1302 				idn.domset.ds_connected;
1303 		my_ready_set &= ~idn.domset.ds_trans_off;
1304 		DOMAINSET_ADD(my_ready_set, idn.localid);
1305 		break;
1306 
1307 	case IDNRETRY_FINQ:
1308 		sync_cmd = IDNSYNC_DISCONNECT;
1309 		my_ready_set = idn.domset.ds_ready_off |
1310 				~idn.domset.ds_connected;
1311 		break;
1312 
1313 	default:
1314 		IDN_DUNLOCK(domid);
1315 		IDN_SYNC_UNLOCK();
1316 		return;
1317 	}
1318 
1319 	if (dp->dsync.s_cmd == sync_cmd)
1320 		my_ready_set |= dp->dsync.s_set_rdy;
1321 
1322 	query_set = idn_sync_register(domid, sync_cmd, 0, IDNSYNC_REG_QUERY);
1323 
1324 	PR_PROTO("%s:%d: query_set = 0x%x\n", proc, domid, query_set);
1325 
1326 	if (query_set == 0) {
1327 		IDN_DUNLOCK(domid);
1328 		IDN_SYNC_UNLOCK();
1329 		return;
1330 	}
1331 
1332 	for (d = 0; d < MAX_DOMAINS; d++) {
1333 		if (!DOMAIN_IN_SET(query_set, d))
1334 			continue;
1335 
1336 		dp = &idn_domain[d];
1337 		if (d != domid)
1338 			IDN_DLOCK_EXCL(d);
1339 
1340 		if ((dp->dsync.s_cmd == sync_cmd) ||
1341 				(!dp->dcookie_send &&
1342 				(rtype == IDNRETRY_CONQ))) {
1343 			if (d != domid)
1344 				IDN_DUNLOCK(d);
1345 			continue;
1346 		}
1347 
1348 		IDN_SYNC_QUERY_UPDATE(domid, d);
1349 
1350 		if (rtype == IDNRETRY_CONQ)
1351 			idn_send_con(d, NULL, IDNCON_QUERY, my_ready_set);
1352 		else
1353 			idn_send_fin(d, NULL, IDNFIN_QUERY, IDNFIN_ARG_NONE,
1354 					IDNFIN_OPT_NONE, my_ready_set,
1355 					NIL_FIN_MASTER);
1356 		if (d != domid)
1357 			IDN_DUNLOCK(d);
1358 	}
1359 
1360 	IDN_DUNLOCK(domid);
1361 	IDN_SYNC_UNLOCK();
1362 }
1363 
1364 static int
1365 idn_send_nego(int domid, idn_msgtype_t *mtp, domainset_t conset)
1366 {
1367 	idn_domain_t	*ldp, *dp;
1368 	int		d, masterid;
1369 	uint_t		dmask;
1370 	uint_t		acknack;
1371 	uint_t		ticket;
1372 	idnneg_dset_t	dset;
1373 	idn_msgtype_t	mt;
1374 	procname_t	proc = "idn_send_nego";
1375 
1376 	ASSERT(IDN_SYNC_IS_LOCKED());
1377 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
1378 
1379 	if (mtp) {
1380 		acknack = mtp->mt_mtype & IDNP_ACKNACK_MASK;
1381 		mt.mt_mtype = mtp->mt_mtype;
1382 		mt.mt_atype = mtp->mt_atype;
1383 		mt.mt_cookie = mtp->mt_cookie;
1384 	} else {
1385 		acknack = 0;
1386 		mt.mt_mtype = IDNP_NEGO;
1387 		mt.mt_atype = 0;
1388 		mt.mt_cookie = IDN_TIMER_PUBLIC_COOKIE;
1389 	}
1390 
1391 	IDN_GLOCK_SHARED();
1392 
1393 	dp = &idn_domain[domid];
1394 	ldp = &idn_domain[idn.localid];
1395 
1396 	if ((idn.state == IDNGS_RECONFIG) ||
1397 			((masterid = IDN_GET_MASTERID()) == IDN_NIL_DOMID)) {
1398 		masterid = IDN_GET_NEW_MASTERID();
1399 		if ((masterid == idn.localid) || (masterid == domid)) {
1400 			/*
1401 			 * We only send the new-master "hint" to
1402 			 * "other" domains.  If the new-master is
1403 			 * ourself or we're talking to the new-master
1404 			 * then we need to be accurate about our
1405 			 * real master so that the correct master
1406 			 * is selected.
1407 			 */
1408 			masterid = IDN_NIL_DOMID;
1409 		}
1410 	}
1411 
1412 	DOMAINSET_DEL(conset, idn.localid);
1413 	DOMAINSET_DEL(conset, domid);
1414 	/*
1415 	 * Exclude domains from conset that are on
1416 	 * remote domain's hitlist.  He's not interested
1417 	 * in hearing about them.  SSP is probably requesting
1418 	 * such domains be unlinked - will eventually get to
1419 	 * local domain.
1420 	 */
1421 	conset &= ~idn.domset.ds_hitlist;
1422 	if ((masterid != IDN_NIL_DOMID) &&
1423 			DOMAIN_IN_SET(idn.domset.ds_hitlist, masterid)) {
1424 		PR_PROTO("%s:%d: masterid(%d) on hitlist(0x%x) -> -1\n",
1425 			proc, domid, masterid, idn.domset.ds_hitlist);
1426 		/*
1427 		 * Yikes, our chosen master is on the hitlist!
1428 		 */
1429 		masterid = IDN_NIL_DOMID;
1430 	}
1431 
1432 	dmask = IDNNEG_DSET_MYMASK();
1433 	IDNNEG_DSET_INIT(dset, dmask);
1434 	for (d = 0; d < MAX_DOMAINS; d++) {
1435 		int	cpuid;
1436 
1437 		if (!DOMAIN_IN_SET(conset, d))
1438 			continue;
1439 
1440 		if ((cpuid = idn_domain[d].dcpu) == IDN_NIL_DCPU) {
1441 			ASSERT(d != masterid);
1442 			continue;
1443 		}
1444 
1445 		IDNNEG_DSET_SET(dset, d, cpuid, dmask);
1446 	}
1447 	IDNNEG_DSET_SET_MASTER(dset, domid, masterid);
1448 	ASSERT((masterid != IDN_NIL_DOMID) ?
1449 		(idn_domain[masterid].dcpu != IDN_NIL_DCPU) : 1);
1450 	IDN_GUNLOCK();
1451 
1452 	IDN_DLOCK_SHARED(idn.localid);
1453 	ticket = IDNVOTE_BASICS(ldp->dvote);
1454 	/*
1455 	 * We just want to send basic vote components without an
1456 	 * indication of mastership (master bit) since that's primarily
1457 	 * for local domain's usage.  There is more correct master
1458 	 * indications in the DSET.  Recall that if we were in a
1459 	 * Reconfig we would have transmitted the "new_masterid"
1460 	 * which might conflict with the local domain's vote.v.master
1461 	 * bit if he was originally the master prior to the Reconfig.
1462 	 */
1463 
1464 	PR_PROTO("%s:%d: sending nego%sto (cpu %d) "
1465 		"[v=0x%x, cs=0x%x, mstr=%d]\n",
1466 		proc, domid,
1467 		(acknack & IDNP_ACK) ? "+ack " :
1468 		(acknack & IDNP_NACK) ? "+nack " : " ",
1469 		dp->dcpu, ticket, conset, masterid);
1470 
1471 	IDN_MSGTIMER_START(domid, IDNP_NEGO, 0,
1472 			idn_msg_waittime[IDNP_NEGO], &mt.mt_cookie);
1473 
1474 	IDNXDC(domid, &mt, ticket, dset[0], dset[1], dset[2]);
1475 
1476 	IDN_DUNLOCK(idn.localid);
1477 
1478 	return (0);
1479 }
1480 
1481 static int
1482 idn_recv_nego(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs,
1483 		ushort_t dcookie)
1484 {
1485 	uint_t		msg = mtp->mt_mtype;
1486 	idn_msgtype_t	mt;
1487 	idn_domain_t	*dp = &idn_domain[domid];
1488 	idn_xdcargs_t	nargs;
1489 	procname_t	proc = "idn_recv_nego";
1490 
1491 	ASSERT(IDN_SYNC_IS_LOCKED());
1492 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
1493 
1494 	mt.mt_cookie = mtp->mt_cookie;
1495 
1496 #ifdef DEBUG
1497 	if (DOMAIN_IN_SET(idn.domset.ds_hitlist, domid)) {
1498 		PR_HITLIST("%s:%d: dcpu=%d, dstate=%s, msg=%x, "
1499 			"hitlist=%x\n",
1500 			proc, domid, dp->dcpu, idnds_str[dp->dstate],
1501 			msg, idn.domset.ds_hitlist);
1502 	}
1503 #endif /* DEBUG */
1504 
1505 	if (dp->dcpu == IDN_NIL_DCPU) {
1506 		int		cpuid;
1507 		uint_t		ticket;
1508 		/*
1509 		 * Brandnew link.  Need to open a new domain entry.
1510 		 */
1511 		ticket = GET_XARGS_NEGO_TICKET(xargs);
1512 		cpuid = dp->dcpu_last;
1513 		ASSERT(VALID_CPUID(cpuid));
1514 
1515 		if (idn_open_domain(domid, cpuid, ticket) != 0) {
1516 			PR_PROTO("%s:%d: FAILED to open doamin "
1517 				"(ticket = 0x%x)\n",
1518 				proc, domid, ticket);
1519 			return (-1);
1520 		}
1521 	}
1522 
1523 	if ((msg & IDNP_MSGTYPE_MASK) == IDNP_NEGO) {
1524 		PR_PROTO("%s:%d: assigned SEND cookie 0x%x\n",
1525 			proc, domid, dcookie);
1526 		dp->dcookie_send = dcookie;
1527 	}
1528 
1529 	if ((dp->dxp == NULL) && IDNDS_IS_CLOSED(dp)) {
1530 		dp->dxp = &xphase_nego;
1531 		IDN_XSTATE_TRANSITION(dp, IDNXS_PEND);
1532 	} else if (dp->dxp != &xphase_nego) {
1533 		if (msg & IDNP_MSGTYPE_MASK) {
1534 			/*
1535 			 * If we already have a connection to somebody
1536 			 * trying to initiate a connection to us, then
1537 			 * possibly we've awaken from a coma or he did.
1538 			 * In any case, dismantle current connection
1539 			 * and attempt to establish a new one.
1540 			 */
1541 			if (dp->dstate == IDNDS_CONNECTED) {
1542 				DOMAINSET_ADD(idn.domset.ds_relink, domid);
1543 				IDN_HISTORY_LOG(IDNH_RELINK, domid,
1544 						dp->dstate,
1545 						idn.domset.ds_relink);
1546 				idn_disconnect(domid, IDNFIN_NORMAL,
1547 						IDNFIN_ARG_NONE,
1548 						IDNFIN_SYNC_YES);
1549 			} else {
1550 				mt.mt_mtype = IDNP_NACK;
1551 				mt.mt_atype = msg;
1552 
1553 				CLR_XARGS(nargs);
1554 
1555 				if (DOMAIN_IN_SET(idn.domset.ds_hitlist,
1556 							domid)) {
1557 					SET_XARGS_NACK_TYPE(nargs,
1558 							IDNNACK_EXIT);
1559 				} else {
1560 					int	new_masterid;
1561 					int	new_cpuid = IDN_NIL_DCPU;
1562 
1563 					SET_XARGS_NACK_TYPE(nargs,
1564 							IDNNACK_RETRY);
1565 					IDN_GLOCK_SHARED();
1566 					new_masterid = IDN_GET_NEW_MASTERID();
1567 					if (new_masterid == IDN_NIL_DOMID)
1568 						new_masterid =
1569 							IDN_GET_MASTERID();
1570 					if (new_masterid != IDN_NIL_DOMID) {
1571 						idn_domain_t	*mdp;
1572 
1573 						mdp = &idn_domain[new_masterid];
1574 						new_cpuid = mdp->dcpu;
1575 					}
1576 					SET_XARGS_NACK_ARG1(nargs,
1577 								new_masterid);
1578 					SET_XARGS_NACK_ARG2(nargs,
1579 								new_cpuid);
1580 					IDN_GUNLOCK();
1581 				}
1582 				idn_send_acknack(domid, &mt, nargs);
1583 			}
1584 		}
1585 		return (0);
1586 	}
1587 
1588 	idn_xphase_transition(domid, mtp, xargs);
1589 
1590 	return (0);
1591 }
1592 
1593 /*ARGSUSED1*/
1594 static void
1595 idn_retry_nego(uint_t token, void *arg)
1596 {
1597 	int		domid = IDN_RETRY_TOKEN2DOMID(token);
1598 	int		new_masterid;
1599 	idn_domain_t	*dp = &idn_domain[domid];
1600 	idn_xdcargs_t	xargs;
1601 	procname_t	proc = "idn_retry_nego";
1602 
1603 	ASSERT(IDN_RETRY_TOKEN2TYPE(token) == IDNRETRY_NEGO);
1604 
1605 	IDN_SYNC_LOCK();
1606 	IDN_DLOCK_EXCL(domid);
1607 
1608 	if (dp->dxp != &xphase_nego) {
1609 		STRING(str);
1610 
1611 #ifdef DEBUG
1612 		if (dp->dxp) {
1613 			INUM2STR(dp->dxp->xt_msgtype, str);
1614 		}
1615 #endif /* DEBUG */
1616 
1617 		PR_PROTO("%s:%d: dxp(%s) != NEGO...bailing...\n",
1618 			proc, domid, dp->dxp ? str : "NULL");
1619 		IDN_DUNLOCK(domid);
1620 		IDN_SYNC_UNLOCK();
1621 		return;
1622 	}
1623 
1624 	if (dp->dxstate != IDNXS_PEND) {
1625 		PR_PROTO("%s:%d: xstate(%s) != %s...bailing\n",
1626 			proc, domid, idnxs_str[dp->dxstate],
1627 			idnxs_str[IDNXS_PEND]);
1628 		IDN_DUNLOCK(domid);
1629 		IDN_SYNC_UNLOCK();
1630 		return;
1631 	}
1632 
1633 	IDN_GLOCK_SHARED();
1634 	if (idn.state == IDNGS_RECONFIG) {
1635 		/*
1636 		 * Have to try again later after
1637 		 * reconfig has completed.
1638 		 */
1639 		PR_PROTO("%s:%d: reconfig in-progress...try later\n",
1640 			proc, domid);
1641 		idn_retry_submit(idn_retry_nego, NULL, token,
1642 				idn_msg_retrytime[IDNP_NEGO]);
1643 		IDN_GUNLOCK();
1644 		IDN_DUNLOCK(domid);
1645 		IDN_SYNC_UNLOCK();
1646 		return;
1647 	}
1648 	new_masterid = IDN_GET_NEW_MASTERID();
1649 	if ((idn.state == IDNGS_CONNECT) &&
1650 			(new_masterid != IDN_NIL_DOMID) &&
1651 			(domid != new_masterid) &&
1652 			(idn.localid != new_masterid)) {
1653 		/*
1654 		 * We have a new master pending and this
1655 		 * guy isn't it.  Wait until the local domain
1656 		 * has a chance to connect with the new
1657 		 * master before going forward with this
1658 		 * guy.
1659 		 */
1660 		PR_PROTO("%s:%d: waiting for connect to new master %d\n",
1661 			proc, domid, IDN_GET_NEW_MASTERID());
1662 		idn_retry_submit(idn_retry_nego, NULL, token,
1663 				idn_msg_retrytime[IDNP_NEGO]);
1664 		IDN_GUNLOCK();
1665 		IDN_DUNLOCK(domid);
1666 		IDN_SYNC_UNLOCK();
1667 		return;
1668 	}
1669 	IDN_GUNLOCK();
1670 
1671 	idn_xphase_transition(domid, NULL, xargs);
1672 
1673 	IDN_DUNLOCK(domid);
1674 	IDN_SYNC_UNLOCK();
1675 }
1676 
1677 static int
1678 idn_check_nego(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs)
1679 {
1680 	int		d, new_masterid, masterid;
1681 	int		cpuid, m_cpuid = -1;
1682 	uint_t		dmask;
1683 	uint_t		msg = mtp ? mtp->mt_mtype : 0;
1684 	idn_domain_t	*dp, *ldp;
1685 	domainset_t	con_set, pending_set;
1686 	idnneg_dset_t	dset;
1687 	procname_t	proc = "idn_check_nego";
1688 
1689 	ASSERT(IDN_SYNC_IS_LOCKED());
1690 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
1691 
1692 	dp = &idn_domain[domid];
1693 	ldp = &idn_domain[idn.localid];
1694 
1695 	if (msg & IDNP_NACK) {
1696 		if (GET_XARGS_NACK_TYPE(xargs) == IDNNACK_EXIT) {
1697 			PR_HITLIST("%s:%d(%s): (msg=%x) EXIT received, "
1698 				"adding to hitlist %x -> %x\n",
1699 				proc, domid, idnds_str[dp->dstate], msg,
1700 				idn.domset.ds_hitlist,
1701 				idn.domset.ds_hitlist | DOMAINSET(domid));
1702 
1703 			DOMAINSET_ADD(idn.domset.ds_hitlist, domid);
1704 			return (-1);
1705 		} else {
1706 			return (0);
1707 		}
1708 	}
1709 
1710 	if (DOMAIN_IN_SET(idn.domset.ds_hitlist, domid)) {
1711 		PR_HITLIST("%s:%d(%s): (msg=%x) domain in hitlist (%x) - "
1712 			"exiting phase\n",
1713 			proc, domid, idnds_str[dp->dstate], msg,
1714 			idn.domset.ds_hitlist);
1715 		return (-1);
1716 	}
1717 
1718 	if ((dp->dstate == IDNDS_NEGO_PEND) &&
1719 			(msg & IDNP_MSGTYPE_MASK) &&
1720 			(msg & IDNP_ACK))		/* nego+ack */
1721 		return (1);
1722 
1723 	dmask = (uint_t)-1;
1724 
1725 	IDN_GLOCK_EXCL();
1726 	if (idn.state == IDNGS_DISCONNECT) {
1727 		PR_PROTO("%s:%d: DISCONNECT in-progress >>> EXIT\n",
1728 			proc, domid);
1729 		IDN_GUNLOCK();
1730 		return (-1);
1731 	} else if (idn.state == IDNGS_OFFLINE) {
1732 		IDN_GSTATE_TRANSITION(IDNGS_CONNECT);
1733 		IDN_PREP_HWINIT();
1734 		IDN_DLOCK_EXCL(idn.localid);
1735 		ldp->dvote.v.connected = 0;
1736 		IDN_DUNLOCK(idn.localid);
1737 	}
1738 
1739 	if (!DOMAIN_IN_SET(idn.domset.ds_trans_on, domid)) {
1740 		DOMAINSET_ADD(idn.domset.ds_trans_on, domid);
1741 		IDN_HISTORY_LOG(IDNH_NEGO, domid,
1742 				idn.domset.ds_trans_on,
1743 				idn.domset.ds_connected);
1744 	}
1745 
1746 	switch (idn.state) {
1747 	case IDNGS_RECONFIG:
1748 		PR_PROTO("%s:%d: RECONFIG in-progress >>> RETRY\n",
1749 			proc, domid);
1750 		IDN_GUNLOCK();
1751 		return (1);
1752 
1753 	case IDNGS_CONNECT:
1754 		new_masterid = IDN_GET_NEW_MASTERID();
1755 		if ((new_masterid != IDN_NIL_DOMID) &&
1756 				(domid != new_masterid) &&
1757 				(idn.localid != new_masterid)) {
1758 			PR_PROTO("%s:%d: waiting for connect to "
1759 				"new master %d\n",
1760 				proc, domid, IDN_GET_NEW_MASTERID());
1761 			IDN_GUNLOCK();
1762 			return (1);
1763 		}
1764 		break;
1765 
1766 	default:
1767 		break;
1768 	}
1769 
1770 	ASSERT((idn.state == IDNGS_CONNECT) || (idn.state == IDNGS_ONLINE));
1771 
1772 	con_set = 0;
1773 
1774 	if (msg) {
1775 		idn_domain_t	*mdp;
1776 		idn_vote_t	vote;
1777 
1778 		vote.ticket = GET_XARGS_NEGO_TICKET(xargs);
1779 		/*
1780 		 * Sender should note have set master bit,
1781 		 * but just in case clear it so local domain
1782 		 * doesn't get confused.
1783 		 */
1784 		vote.v.master = 0;
1785 		dp->dvote.ticket = vote.ticket;
1786 		GET_XARGS_NEGO_DSET(xargs, dset);
1787 		/*LINTED*/
1788 		IDNNEG_DSET_GET_MASK(dset, domid, dmask);
1789 		IDNNEG_DSET_GET_MASTER(dset, new_masterid);
1790 		if (new_masterid == IDNNEG_NO_MASTER) {
1791 			new_masterid = IDN_NIL_DOMID;
1792 		} else {
1793 			/*
1794 			 * Remote domain has a master.  Find
1795 			 * his cpuid in the dset.  We may need
1796 			 * it to initiate a connection.
1797 			 */
1798 			if (new_masterid == domid) {
1799 				m_cpuid = dp->dcpu;
1800 			} else {
1801 				IDNNEG_DSET_GET(dset, new_masterid, m_cpuid,
1802 						dmask);
1803 				if (m_cpuid == -1) {
1804 					/*
1805 					 * Something is bogus if remote domain
1806 					 * is reporting a valid masterid, but
1807 					 * doesn't have the cpuid for it.
1808 					 */
1809 					cmn_err(CE_WARN,
1810 						"IDN: 209: remote domain (ID "
1811 						"%d, CPU %d) reporting master "
1812 						"(ID %d) without CPU ID",
1813 						domid, dp->dcpu, new_masterid);
1814 					DOMAINSET_ADD(idn.domset.ds_hitlist,
1815 						domid);
1816 					IDN_GUNLOCK();
1817 					return (-1);
1818 				}
1819 			}
1820 		}
1821 
1822 		for (d = 0; d < MAX_DOMAINS; d++) {
1823 			if ((d == idn.localid) || (d == domid))
1824 				continue;
1825 			IDNNEG_DSET_GET(dset, d, cpuid, dmask);
1826 			if (cpuid != -1) {
1827 				DOMAINSET_ADD(con_set, d);
1828 			}
1829 		}
1830 
1831 #ifdef DEBUG
1832 		if (idn.domset.ds_hitlist) {
1833 			PR_HITLIST("%s:%d: con_set %x -> %x (hitlist = %x)\n",
1834 				proc, domid, con_set,
1835 				con_set & ~idn.domset.ds_hitlist,
1836 				idn.domset.ds_hitlist);
1837 		}
1838 #endif /* DEBUG */
1839 
1840 		con_set &= ~idn.domset.ds_hitlist;
1841 
1842 		ASSERT(!DOMAIN_IN_SET(con_set, idn.localid));
1843 		ASSERT(!DOMAIN_IN_SET(con_set, domid));
1844 
1845 		if ((new_masterid != IDN_NIL_DOMID) &&
1846 				DOMAIN_IN_SET(idn.domset.ds_hitlist,
1847 						new_masterid)) {
1848 			PR_HITLIST("%s:%d: new_mstr %d -> -1 (hitlist = %x)\n",
1849 				proc, domid, new_masterid,
1850 				idn.domset.ds_hitlist);
1851 			IDN_GUNLOCK();
1852 			return (1);
1853 		}
1854 
1855 		if (idn_select_master(domid, new_masterid, m_cpuid) < 0) {
1856 			/*
1857 			 * Returns w/GLOCK dropped if error.
1858 			 */
1859 			return (1);
1860 		}
1861 
1862 		masterid = IDN_GET_MASTERID();
1863 		ASSERT(masterid != IDN_NIL_DOMID);
1864 
1865 		if (idn.state == IDNGS_CONNECT) {
1866 			/*
1867 			 * This is the initial connection for
1868 			 * the local domain.
1869 			 */
1870 			IDN_DLOCK_EXCL(idn.localid);
1871 
1872 			if (masterid == idn.localid) {
1873 				if (idn_master_init() < 0) {
1874 					cmn_err(CE_WARN,
1875 						"IDN: 210: failed to init "
1876 						"MASTER context");
1877 					ldp->dvote.v.master = 0;
1878 					IDN_DUNLOCK(idn.localid);
1879 					IDN_GSTATE_TRANSITION(IDNGS_DISCONNECT);
1880 					IDN_SET_MASTERID(IDN_NIL_DOMID);
1881 					IDN_GUNLOCK();
1882 					return (-1);
1883 				}
1884 				DSLAB_LOCK_EXCL(idn.localid);
1885 				ldp->dslab_state = DSLAB_STATE_LOCAL;
1886 				DSLAB_UNLOCK(idn.localid);
1887 				ldp->dvote.v.connected = 1;
1888 			} else {
1889 				/*
1890 				 * Either the remote domain is the
1891 				 * master or its a new slave trying
1892 				 * to connect to us.  We can't allow
1893 				 * further progress until we've
1894 				 * sync'd up with the master.
1895 				 */
1896 				if (masterid != domid) {
1897 					IDN_DUNLOCK(idn.localid);
1898 					IDN_GUNLOCK();
1899 					return (1);
1900 				}
1901 				DSLAB_LOCK_EXCL(idn.localid);
1902 				ldp->dslab_state = DSLAB_STATE_REMOTE;
1903 				DSLAB_UNLOCK(idn.localid);
1904 			}
1905 			IDN_DUNLOCK(idn.localid);
1906 			/*
1907 			 * We've sync'd up with the new master.
1908 			 */
1909 			IDN_GSTATE_TRANSITION(IDNGS_ONLINE);
1910 		}
1911 
1912 		mdp = &idn_domain[masterid];
1913 
1914 		if ((masterid != domid) && !IDNDS_CONFIG_DONE(mdp)) {
1915 			/*
1916 			 * We can't progress any further with
1917 			 * other domains until we've exchanged all
1918 			 * the necessary CFG info with the master,
1919 			 * i.e. until we have a mailbox area from
1920 			 * which we can allocate mailboxes to
1921 			 * other domains.
1922 			 */
1923 			PR_PROTO("%s:%d: still exchanging CFG "
1924 				"w/master(%d)\n",
1925 				proc, domid, masterid);
1926 			IDN_GUNLOCK();
1927 			return (1);
1928 		}
1929 
1930 		DSLAB_LOCK_EXCL(domid);
1931 		dp->dslab_state = ldp->dslab_state;
1932 		DSLAB_UNLOCK(domid);
1933 		if (idn.state != IDNGS_ONLINE) {
1934 			IDN_GSTATE_TRANSITION(IDNGS_ONLINE);
1935 		}
1936 	}
1937 
1938 	IDN_GUNLOCK();
1939 
1940 	pending_set = con_set;
1941 	pending_set &= ~(idn.domset.ds_trans_on | idn.domset.ds_connected);
1942 	idn.domset.ds_trans_on |= pending_set;
1943 
1944 	con_set |= idn.domset.ds_trans_on | idn.domset.ds_connected;
1945 	con_set &= ~idn.domset.ds_trans_off;
1946 	DOMAINSET_ADD(con_set, idn.localid);
1947 
1948 	if (dp->dsync.s_cmd != IDNSYNC_CONNECT) {
1949 		idn_sync_exit(domid, IDNSYNC_DISCONNECT);
1950 		idn_sync_enter(domid, IDNSYNC_CONNECT,
1951 				con_set, DOMAINSET(idn.localid),
1952 				idn_xstate_transfunc,
1953 				(void *)IDNP_CON);
1954 	}
1955 
1956 	/*
1957 	 * Get this domain registered as an expected domain on
1958 	 * the remaining domains in the CONNECT synchronization.
1959 	 */
1960 	(void) idn_sync_register(domid, IDNSYNC_CONNECT, 0, IDNSYNC_REG_NEW);
1961 
1962 	/*
1963 	 * Note that if (msg == 0), i.e. then there will be
1964 	 * no dset and also pending_set will be 0.
1965 	 * So, the following loop will never attempt to
1966 	 * look at the dset unless (msg != 0), implying
1967 	 * that we've been through the initial code above
1968 	 * and have initialized dmask.
1969 	 */
1970 	ASSERT(pending_set ? (dmask != (uint_t)-1) : 1);
1971 
1972 	for (d = 0; d < MAX_DOMAINS; d++) {
1973 		int	rv;
1974 
1975 		if (!DOMAIN_IN_SET(pending_set, d))
1976 			continue;
1977 
1978 		ASSERT((d != idn.localid) && (d != domid));
1979 
1980 		dp = &idn_domain[d];
1981 
1982 		IDNNEG_DSET_GET(dset, d, cpuid, dmask);
1983 		if (cpuid == -1) {
1984 			PR_PROTO("%s:%d: failed to get cpuid from dset "
1985 				"for domain %d (pset = 0x%x)\n",
1986 				proc, domid, d, pending_set);
1987 			DOMAINSET_DEL(idn.domset.ds_trans_on, d);
1988 			continue;
1989 		}
1990 
1991 		IDN_DLOCK_EXCL(d);
1992 		if ((rv = idn_open_domain(d, cpuid, 0)) != 0) {
1993 			PR_PROTO("%s:%d: failed "
1994 				"idn_open_domain(%d,%d,0) (rv = %d)\n",
1995 				proc, domid, d, cpuid, rv);
1996 			if (rv < 0) {
1997 				cmn_err(CE_WARN,
1998 					"IDN: 205: (%s) failed to "
1999 					"open-domain(%d,%d)",
2000 					proc, d, cpuid);
2001 				DOMAINSET_DEL(idn.domset.ds_trans_on, d);
2002 			} else if (DOMAIN_IN_SET(idn.domset.ds_trans_off, d)) {
2003 				/*
2004 				 * We've requested to connect to a domain
2005 				 * from which we're disconnecting.  We
2006 				 * better mark this guy for relinking.
2007 				 */
2008 				DOMAINSET_ADD(idn.domset.ds_relink, d);
2009 				IDN_HISTORY_LOG(IDNH_RELINK, d, dp->dstate,
2010 						idn.domset.ds_relink);
2011 			}
2012 			IDN_DUNLOCK(d);
2013 			continue;
2014 		}
2015 
2016 		idn_connect(d);
2017 
2018 		IDN_DUNLOCK(d);
2019 	}
2020 
2021 	return (0);
2022 }
2023 
2024 /*ARGSUSED*/
2025 static void
2026 idn_action_nego_pend(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs)
2027 {
2028 	uint_t		msg = mtp ? mtp->mt_mtype : 0;
2029 	idn_msgtype_t	mt;
2030 	domainset_t	con_set;
2031 
2032 	ASSERT(IDN_SYNC_IS_LOCKED());
2033 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
2034 
2035 	con_set = idn.domset.ds_trans_on | idn.domset.ds_connected;
2036 	con_set &= ~idn.domset.ds_trans_off;
2037 
2038 	if (!msg) {
2039 		idn_send_nego(domid, NULL, con_set);
2040 	} else {
2041 		mt.mt_mtype = IDNP_NEGO | IDNP_ACK;
2042 		mt.mt_atype = 0;
2043 		mt.mt_cookie = mtp->mt_cookie;
2044 		idn_send_nego(domid, &mt, con_set);
2045 	}
2046 }
2047 
2048 /*ARGSUSED*/
2049 static void
2050 idn_error_nego(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs)
2051 {
2052 	int	new_masterid, new_cpuid;
2053 	int	retry = 1;
2054 	uint_t	msg = mtp ? mtp->mt_mtype : 0;
2055 	uint_t	token;
2056 
2057 	ASSERT(IDN_SYNC_IS_LOCKED());
2058 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
2059 
2060 	if (msg & IDNP_NACK) {
2061 		idn_nack_t	nack;
2062 
2063 		nack = GET_XARGS_NACK_TYPE(xargs);
2064 		switch (nack) {
2065 		case IDNNACK_RETRY:
2066 			new_masterid = (int)GET_XARGS_NACK_ARG1(xargs);
2067 			new_cpuid    = (int)GET_XARGS_NACK_ARG2(xargs);
2068 			break;
2069 
2070 		case IDNNACK_EXIT:
2071 			retry = 0;
2072 			/*FALLTHROUGH*/
2073 
2074 		default:
2075 			new_masterid = IDN_NIL_DOMID;
2076 			new_cpuid    = IDN_NIL_DCPU;
2077 			break;
2078 		}
2079 		idn_nego_cleanup_check(domid, new_masterid, new_cpuid);
2080 	}
2081 
2082 	if (msg & IDNP_MSGTYPE_MASK) {
2083 		idn_msgtype_t	mt;
2084 		idn_xdcargs_t	nargs;
2085 
2086 		mt.mt_mtype = IDNP_NACK;
2087 		mt.mt_atype = msg;
2088 		mt.mt_cookie = mtp->mt_cookie;
2089 		CLR_XARGS(nargs);
2090 		SET_XARGS_NACK_TYPE(nargs, IDNNACK_RETRY);
2091 		IDN_GLOCK_SHARED();
2092 		new_masterid = IDN_GET_NEW_MASTERID();
2093 		if (new_masterid == IDN_NIL_DOMID)
2094 			new_masterid = IDN_GET_MASTERID();
2095 		if (new_masterid != IDN_NIL_DOMID)
2096 			new_cpuid = idn_domain[new_masterid].dcpu;
2097 		else
2098 			new_cpuid = IDN_NIL_DCPU;
2099 		SET_XARGS_NACK_ARG1(nargs, new_masterid);
2100 		SET_XARGS_NACK_ARG2(nargs, new_cpuid);
2101 		IDN_GUNLOCK();
2102 		idn_send_acknack(domid, &mt, nargs);
2103 	}
2104 
2105 	if (retry) {
2106 		token = IDN_RETRY_TOKEN(domid, IDNRETRY_NEGO);
2107 		idn_retry_submit(idn_retry_nego, NULL, token,
2108 				idn_msg_retrytime[(int)IDNRETRY_NEGO]);
2109 	} else {
2110 		DOMAINSET_DEL(idn.domset.ds_relink, domid);
2111 		IDN_RESET_COOKIES(domid);
2112 		idn_disconnect(domid, IDNFIN_NORMAL, IDNFIN_ARG_NONE,
2113 				IDNDS_SYNC_TYPE(&idn_domain[domid]));
2114 	}
2115 }
2116 
2117 /*ARGSUSED*/
2118 static void
2119 idn_action_nego_sent(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs)
2120 {
2121 	uint_t		msg = mtp ? mtp->mt_mtype : 0;
2122 	domainset_t	conset;
2123 	idn_msgtype_t	mt;
2124 
2125 	ASSERT(IDN_SYNC_IS_LOCKED());
2126 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
2127 
2128 	mt.mt_cookie = mtp ? mtp->mt_cookie : 0;
2129 
2130 	conset = idn.domset.ds_trans_on | idn.domset.ds_connected;
2131 	conset &= ~idn.domset.ds_trans_off;
2132 
2133 	if ((msg & IDNP_ACKNACK_MASK) == 0) {
2134 		/*
2135 		 * nego
2136 		 */
2137 		mt.mt_mtype = IDNP_NEGO | IDNP_ACK;
2138 		mt.mt_atype = 0;
2139 		idn_send_nego(domid, &mt, conset);
2140 	} else if (msg & IDNP_MSGTYPE_MASK) {
2141 		int		d;
2142 		idn_xdcargs_t	nargs;
2143 		idnneg_dset_t	dset;
2144 		uint_t		dmask;
2145 		idn_vote_t	vote;
2146 
2147 		mt.mt_mtype = IDNP_ACK;
2148 		mt.mt_atype = msg;
2149 		DOMAINSET_DEL(conset, idn.localid);
2150 		DOMAINSET_DEL(conset, domid);
2151 
2152 		dmask = IDNNEG_DSET_MYMASK();
2153 		IDNNEG_DSET_INIT(dset, dmask);
2154 		for (d = 0; d < MAX_DOMAINS; d++) {
2155 			int	cpuid;
2156 
2157 			if (!DOMAIN_IN_SET(conset, d))
2158 				continue;
2159 
2160 			if ((cpuid = idn_domain[d].dcpu) == IDN_NIL_DCPU)
2161 				continue;
2162 
2163 			IDNNEG_DSET_SET(dset, d, cpuid, dmask);
2164 		}
2165 		IDNNEG_DSET_SET_MASTER(dset, domid, IDN_GET_MASTERID());
2166 		ASSERT((IDN_GET_MASTERID() != IDN_NIL_DOMID) ?
2167 			(idn_domain[IDN_GET_MASTERID()].dcpu != IDN_NIL_DCPU) :
2168 			1);
2169 		vote.ticket = idn_domain[idn.localid].dvote.ticket;
2170 		vote.v.master = 0;
2171 		CLR_XARGS(nargs);
2172 		SET_XARGS_NEGO_TICKET(nargs, vote.ticket);
2173 		SET_XARGS_NEGO_DSET(nargs, dset);
2174 		/*
2175 		 * nego+ack
2176 		 */
2177 		idn_send_acknack(domid, &mt, nargs);
2178 	} else {
2179 		uint_t		token;
2180 		int		new_masterid, new_cpuid;
2181 		int		retry = 1;
2182 		idn_nack_t	nack;
2183 		/*
2184 		 * nack - retry
2185 		 *
2186 		 * It's possible if we've made it this far that
2187 		 * we may have already chosen a master and this
2188 		 * dude might be it!  If it is we need to clean up.
2189 		 */
2190 		nack = GET_XARGS_NACK_TYPE(xargs);
2191 		switch (nack) {
2192 		case IDNNACK_RETRY:
2193 			new_masterid = (int)GET_XARGS_NACK_ARG1(xargs);
2194 			new_cpuid = (int)GET_XARGS_NACK_ARG2(xargs);
2195 			break;
2196 
2197 		case IDNNACK_EXIT:
2198 			retry = 0;
2199 			/*FALLTHROUGH*/
2200 
2201 		default:
2202 			new_masterid = IDN_NIL_DOMID;
2203 			new_cpuid = IDN_NIL_DCPU;
2204 			break;
2205 		}
2206 
2207 		idn_nego_cleanup_check(domid, new_masterid, new_cpuid);
2208 
2209 		if (retry) {
2210 			token = IDN_RETRY_TOKEN(domid, IDNRETRY_NEGO);
2211 			idn_retry_submit(idn_retry_nego, NULL, token,
2212 					idn_msg_retrytime[(int)IDNRETRY_NEGO]);
2213 		} else {
2214 			DOMAINSET_DEL(idn.domset.ds_relink, domid);
2215 			IDN_RESET_COOKIES(domid);
2216 			idn_disconnect(domid, IDNFIN_NORMAL, IDNFIN_ARG_NONE,
2217 					IDNDS_SYNC_TYPE(&idn_domain[domid]));
2218 		}
2219 	}
2220 }
2221 
2222 /*ARGSUSED*/
2223 static void
2224 idn_action_nego_rcvd(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs)
2225 {
2226 	uint_t	msg = mtp ? mtp->mt_mtype : 0;
2227 
2228 	ASSERT(IDN_SYNC_IS_LOCKED());
2229 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
2230 
2231 	if (msg & IDNP_NACK) {
2232 		uint_t		token;
2233 		int		new_masterid, new_cpuid;
2234 		int		retry = 1;
2235 		idn_nack_t	nack;
2236 		/*
2237 		 * nack - retry.
2238 		 *
2239 		 * At this stage of receiving a nack we need to
2240 		 * check whether we need to start over again with
2241 		 * selecting a new master.
2242 		 */
2243 		nack = GET_XARGS_NACK_TYPE(xargs);
2244 		switch (nack) {
2245 		case IDNNACK_RETRY:
2246 			new_masterid = (int)GET_XARGS_NACK_ARG1(xargs);
2247 			new_cpuid = (int)GET_XARGS_NACK_ARG2(xargs);
2248 			break;
2249 
2250 		case IDNNACK_EXIT:
2251 			retry = 0;
2252 			/*FALLTHROUGH*/
2253 
2254 		default:
2255 			new_masterid = IDN_NIL_DOMID;
2256 			new_cpuid = IDN_NIL_DCPU;
2257 			break;
2258 		}
2259 
2260 		idn_nego_cleanup_check(domid, new_masterid, new_cpuid);
2261 
2262 		if (retry) {
2263 			token = IDN_RETRY_TOKEN(domid, IDNRETRY_NEGO);
2264 			idn_retry_submit(idn_retry_nego, NULL, token,
2265 					idn_msg_retrytime[(int)IDNRETRY_NEGO]);
2266 		} else {
2267 			DOMAINSET_DEL(idn.domset.ds_relink, domid);
2268 			IDN_RESET_COOKIES(domid);
2269 			idn_disconnect(domid, IDNFIN_NORMAL, IDNFIN_ARG_NONE,
2270 					IDNDS_SYNC_TYPE(&idn_domain[domid]));
2271 		}
2272 	}
2273 }
2274 
2275 static void
2276 idn_final_nego(int domid)
2277 {
2278 	idn_domain_t	*dp = &idn_domain[domid];
2279 
2280 	ASSERT(IDN_SYNC_IS_LOCKED());
2281 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
2282 
2283 	(void) idn_retry_terminate(IDN_RETRY_TOKEN(domid, IDNRETRY_NEGO));
2284 
2285 	ASSERT(dp->dstate == IDNDS_CONFIG);
2286 
2287 	dp->dxp = NULL;
2288 	IDN_XSTATE_TRANSITION(dp, IDNXS_NIL);
2289 
2290 	idn_send_config(domid, 1);
2291 }
2292 
2293 /*
2294  */
2295 /*ARGSUSED1*/
2296 static void
2297 idn_exit_nego(int domid, uint_t msgtype)
2298 {
2299 	idn_domain_t	*dp;
2300 	idn_fin_t	fintype;
2301 
2302 	ASSERT(IDN_SYNC_IS_LOCKED());
2303 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
2304 
2305 	dp = &idn_domain[domid];
2306 
2307 	fintype = msgtype ? IDNFIN_NORMAL : IDNFIN_FORCE_HARD;
2308 
2309 	(void) idn_retry_terminate(IDN_RETRY_TOKEN(domid, IDNRETRY_NEGO));
2310 
2311 	ASSERT(!DOMAIN_IN_SET(idn.domset.ds_connected, domid));
2312 	ASSERT(!DOMAIN_IN_SET(idn.domset.ds_ready_on, domid));
2313 	ASSERT(dp->dxp == &xphase_nego);
2314 
2315 	idn_nego_cleanup_check(domid, IDN_NIL_DOMID, IDN_NIL_DCPU);
2316 
2317 	IDN_GLOCK_SHARED();
2318 	if ((idn.state != IDNGS_DISCONNECT) &&
2319 			!DOMAIN_IN_SET(idn.domset.ds_hitlist, domid)) {
2320 		DOMAINSET_ADD(idn.domset.ds_relink, domid);
2321 		IDN_HISTORY_LOG(IDNH_RELINK, domid, dp->dstate,
2322 				idn.domset.ds_relink);
2323 	} else {
2324 		idn_update_op(IDNOP_ERROR, DOMAINSET(domid), NULL);
2325 		DOMAINSET_DEL(idn.domset.ds_relink, domid);
2326 	}
2327 	IDN_GUNLOCK();
2328 	/*
2329 	 * Reset send cookie to 0 so that receiver does not validate
2330 	 * cookie.  This is necessary since at this early stage it's
2331 	 * possible we may not have exchanged appropriate cookies.
2332 	 */
2333 	IDN_RESET_COOKIES(domid);
2334 	idn_disconnect(domid, fintype, IDNFIN_ARG_NONE,
2335 			IDNDS_SYNC_TYPE(dp));
2336 }
2337 
2338 static void
2339 idn_nego_cleanup_check(int domid, int new_masterid, int new_cpuid)
2340 {
2341 	idn_domain_t	*ldp, *dp;
2342 	procname_t	proc = "idn_nego_cleanup_check";
2343 
2344 	ASSERT(IDN_SYNC_IS_LOCKED());
2345 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
2346 
2347 	dp = &idn_domain[domid];
2348 	ldp = &idn_domain[idn.localid];
2349 
2350 	IDN_GLOCK_EXCL();
2351 
2352 	if (((idn.state == IDNGS_ONLINE) && !idn.domset.ds_connected) ||
2353 			(idn.state == IDNGS_CONNECT)) {
2354 		domainset_t	trans_on;
2355 		int		masterid;
2356 		int		retry_domid = IDN_NIL_DOMID;
2357 		int		rv;
2358 
2359 		IDN_DLOCK_EXCL(idn.localid);
2360 		masterid = (idn.state == IDNGS_ONLINE) ?
2361 				IDN_GET_MASTERID() : IDN_GET_NEW_MASTERID();
2362 		trans_on = idn.domset.ds_trans_on;
2363 		DOMAINSET_DEL(trans_on, domid);
2364 		if (trans_on == 0) {
2365 			int		d;
2366 			domainset_t	relink = idn.domset.ds_relink;
2367 			/*
2368 			 * This was the only guy we were trying
2369 			 * to connect with.
2370 			 */
2371 			ASSERT((idn.state == IDNGS_ONLINE) ?
2372 				((idn.localid == masterid) ||
2373 					(domid == masterid)) : 1);
2374 			if (idn.localid == masterid)
2375 				idn_master_deinit();
2376 			ldp->dvote.v.connected = 0;
2377 			ldp->dvote.v.master = 0;
2378 			dp->dvote.v.master = 0;
2379 			IDN_SET_MASTERID(IDN_NIL_DOMID);
2380 			IDN_SET_NEW_MASTERID(new_masterid);
2381 			IDN_GSTATE_TRANSITION(IDNGS_CONNECT);
2382 			IDN_PREP_HWINIT();
2383 			IDN_DUNLOCK(idn.localid);
2384 			IDN_GUNLOCK();
2385 			/*
2386 			 * If there's a new master available then
2387 			 * just try and relink with him unless
2388 			 * it's ourself.
2389 			 */
2390 			if ((new_masterid != IDN_NIL_DOMID) &&
2391 					(new_masterid != idn.localid) &&
2392 					(new_masterid != domid)) {
2393 				IDN_DLOCK_EXCL(new_masterid);
2394 				rv = idn_open_domain(new_masterid,
2395 							new_cpuid, 0);
2396 				if (rv < 0) {
2397 					cmn_err(CE_WARN,
2398 						"IDN: 205: (%s) failed to "
2399 						"open-domain(%d,%d)",
2400 						proc, new_masterid, new_cpuid);
2401 					IDN_GLOCK_EXCL();
2402 					IDN_SET_NEW_MASTERID(IDN_NIL_DOMID);
2403 					IDN_GUNLOCK();
2404 				} else {
2405 					relink = DOMAINSET(new_masterid);
2406 				}
2407 				IDN_DUNLOCK(new_masterid);
2408 			}
2409 			DOMAINSET_DEL(relink, domid);
2410 			if (relink)
2411 				for (d = 0; d < MAX_DOMAINS; d++) {
2412 					if (!DOMAIN_IN_SET(relink, d))
2413 						continue;
2414 					retry_domid = d;
2415 					break;
2416 				}
2417 		} else if (domid == masterid) {
2418 			/*
2419 			 * There are other domains we were trying
2420 			 * to connect to.  As long as the chosen
2421 			 * master was somebody other then this
2422 			 * domain that nack'd us, life is cool, but
2423 			 * if it was this remote domain we'll need
2424 			 * to start over.
2425 			 */
2426 			IDN_DUNLOCK(idn.localid);
2427 			dp->dvote.v.master = 0;
2428 			IDN_SET_MASTERID(IDN_NIL_DOMID);
2429 			IDN_SET_NEW_MASTERID(new_masterid);
2430 
2431 			if (idn.state == IDNGS_ONLINE) {
2432 				IDN_GKSTAT_GLOBAL_EVENT(gk_reconfigs,
2433 							gk_reconfig_last);
2434 				IDN_GSTATE_TRANSITION(IDNGS_RECONFIG);
2435 				IDN_GUNLOCK();
2436 				idn_unlink_domainset(trans_on, IDNFIN_NORMAL,
2437 							IDNFIN_ARG_NONE,
2438 							IDNFIN_OPT_RELINK,
2439 							BOARDSET_ALL);
2440 			} else if ((new_masterid != IDN_NIL_DOMID) &&
2441 					(new_masterid != idn.localid) &&
2442 					(new_masterid != domid) &&
2443 					!DOMAIN_IN_SET(trans_on,
2444 							new_masterid)) {
2445 				IDN_GUNLOCK();
2446 				IDN_DLOCK_EXCL(new_masterid);
2447 				rv = idn_open_domain(new_masterid,
2448 							new_cpuid, 0);
2449 				IDN_GLOCK_EXCL();
2450 				IDN_DUNLOCK(new_masterid);
2451 				if (rv < 0) {
2452 					cmn_err(CE_WARN,
2453 						"IDN: 205: (%s) failed to "
2454 						"open-domain(%d,%d)",
2455 						proc, new_masterid,
2456 						new_cpuid);
2457 					IDN_SET_NEW_MASTERID(IDN_NIL_DOMID);
2458 					new_masterid = IDN_NIL_DOMID;
2459 				} else {
2460 					retry_domid = new_masterid;
2461 				}
2462 				IDN_GUNLOCK();
2463 			} else {
2464 				IDN_GUNLOCK();
2465 			}
2466 		} else {
2467 			IDN_DUNLOCK(idn.localid);
2468 			IDN_GUNLOCK();
2469 		}
2470 		if (retry_domid != IDN_NIL_DOMID) {
2471 			uint_t		token;
2472 			idn_domain_t	*rdp = &idn_domain[retry_domid];
2473 
2474 			IDN_DLOCK_EXCL(retry_domid);
2475 			rdp->dxp = &xphase_nego;
2476 			IDN_XSTATE_TRANSITION(rdp, IDNXS_PEND);
2477 			IDN_DUNLOCK(retry_domid);
2478 			token = IDN_RETRY_TOKEN(retry_domid, IDNRETRY_NEGO);
2479 			idn_retry_submit(idn_retry_nego, NULL, token,
2480 					idn_msg_retrytime[(int)IDNRETRY_NEGO]);
2481 		}
2482 	} else {
2483 		IDN_GUNLOCK();
2484 	}
2485 }
2486 
2487 static int
2488 idn_send_con(int domid, idn_msgtype_t *mtp,
2489 		idn_con_t contype, domainset_t conset)
2490 {
2491 	idn_msgtype_t	mt;
2492 	uint_t		acknack;
2493 	procname_t	proc = "idn_send_con";
2494 
2495 	ASSERT(IDN_SYNC_IS_LOCKED());
2496 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
2497 
2498 	if (mtp) {
2499 		acknack = mtp->mt_mtype & IDNP_ACKNACK_MASK;
2500 		mt.mt_mtype = mtp->mt_mtype;
2501 		mt.mt_atype = mtp->mt_atype;
2502 		mt.mt_cookie = mtp->mt_cookie;
2503 	} else {
2504 		acknack = 0;
2505 		mt.mt_mtype = IDNP_CON;
2506 		mt.mt_atype = 0;
2507 		/*
2508 		 * For simple CON queries we want a unique
2509 		 * timer assigned.  For others, they
2510 		 * effectively share one.
2511 		 */
2512 		if (contype == IDNCON_QUERY)
2513 			mt.mt_cookie = 0;
2514 		else
2515 			mt.mt_cookie = IDN_TIMER_PUBLIC_COOKIE;
2516 	}
2517 
2518 	ASSERT((contype == IDNCON_QUERY) ? idn_domain[domid].dcookie_send : 1);
2519 
2520 	PR_PROTO("%s:%d: sending con%sto (cpu %d) [ct=%s, cs=0x%x]\n",
2521 		proc, domid,
2522 		(acknack & IDNP_ACK) ? "+ack " :
2523 		(acknack & IDNP_NACK) ? "+nack " : " ",
2524 		idn_domain[domid].dcpu,
2525 		idncon_str[contype], conset);
2526 
2527 	IDN_MSGTIMER_START(domid, IDNP_CON, (ushort_t)contype,
2528 			idn_msg_waittime[IDNP_CON], &mt.mt_cookie);
2529 
2530 	IDNXDC(domid, &mt, (uint_t)contype, (uint_t)conset, 0, 0);
2531 
2532 	return (0);
2533 }
2534 
2535 /*
2536  * Must leave w/DLOCK dropped and SYNC_LOCK held.
2537  */
2538 static int
2539 idn_recv_con(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs)
2540 {
2541 	uint_t		msg = mtp ? mtp->mt_mtype : 0;
2542 	uint_t		msgarg = mtp ? mtp->mt_atype : 0;
2543 	idn_con_t	contype;
2544 	domainset_t	my_ready_set, ready_set;
2545 	idn_msgtype_t	mt;
2546 	idn_domain_t	*dp = &idn_domain[domid];
2547 	idn_xdcargs_t	aargs;
2548 	procname_t	proc = "idn_recv_con";
2549 
2550 	ASSERT(IDN_SYNC_IS_LOCKED());
2551 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
2552 
2553 	mt.mt_cookie = mtp ? mtp->mt_cookie : 0;
2554 
2555 	contype   = GET_XARGS_CON_TYPE(xargs);
2556 	ready_set = GET_XARGS_CON_DOMSET(xargs);
2557 
2558 	CLR_XARGS(aargs);
2559 
2560 	if (!(msg & IDNP_NACK) && (contype == IDNCON_QUERY)) {
2561 		domainset_t	query_set;
2562 
2563 		query_set = idn_sync_register(domid, IDNSYNC_CONNECT,
2564 						ready_set, IDNSYNC_REG_REG);
2565 
2566 		my_ready_set = idn.domset.ds_connected |
2567 				idn.domset.ds_ready_on;
2568 		my_ready_set &= ~idn.domset.ds_trans_off;
2569 		DOMAINSET_ADD(my_ready_set, idn.localid);
2570 
2571 		if (msg & IDNP_MSGTYPE_MASK) {
2572 			mt.mt_mtype = IDNP_ACK;
2573 			mt.mt_atype = IDNP_CON;
2574 			SET_XARGS_CON_TYPE(aargs, contype);
2575 			SET_XARGS_CON_DOMSET(aargs, my_ready_set);
2576 			idn_send_acknack(domid, &mt, aargs);
2577 		}
2578 
2579 		if (query_set) {
2580 			uint_t	token;
2581 
2582 			token = IDN_RETRY_TOKEN(domid, IDNRETRY_CONQ);
2583 			idn_retry_submit(idn_retry_query, NULL, token,
2584 					idn_msg_retrytime[(int)IDNRETRY_CONQ]);
2585 		}
2586 
2587 		return (0);
2588 	}
2589 
2590 	if (dp->dxp == NULL) {
2591 		STRING(mstr);
2592 		STRING(lstr);
2593 		/*
2594 		 * Must have received an inappropriate error
2595 		 * message as we should already be registered
2596 		 * by the time we reach here.
2597 		 */
2598 		INUM2STR(msg, mstr);
2599 		INUM2STR(msgarg, lstr);
2600 
2601 		PR_PROTO("%s:%d: ERROR: NOT YET REGISTERED (%s/%s)\n",
2602 			proc, domid, mstr, lstr);
2603 
2604 		if (msg & IDNP_MSGTYPE_MASK) {
2605 			mt.mt_mtype = IDNP_NACK;
2606 			mt.mt_atype = msg;
2607 			SET_XARGS_NACK_TYPE(aargs, IDNNACK_RETRY);
2608 			idn_send_acknack(domid, &mt, aargs);
2609 		}
2610 
2611 		return (-1);
2612 	}
2613 
2614 	idn_xphase_transition(domid, mtp, xargs);
2615 
2616 	return (0);
2617 }
2618 
2619 /*ARGSUSED1*/
2620 static void
2621 idn_retry_con(uint_t token, void *arg)
2622 {
2623 	int		domid = IDN_RETRY_TOKEN2DOMID(token);
2624 	idn_domain_t	*dp = &idn_domain[domid];
2625 	idn_xdcargs_t	xargs;
2626 	procname_t	proc = "idn_retry_con";
2627 
2628 	ASSERT(IDN_RETRY_TOKEN2TYPE(token) == IDNRETRY_CON);
2629 
2630 	IDN_SYNC_LOCK();
2631 	IDN_DLOCK_EXCL(domid);
2632 
2633 	if (dp->dxp != &xphase_con) {
2634 		STRING(str);
2635 
2636 #ifdef DEBUG
2637 		if (dp->dxp) {
2638 			INUM2STR(dp->dxp->xt_msgtype, str);
2639 		}
2640 #endif /* DEBUG */
2641 
2642 		PR_PROTO("%s:%d: dxp(%s) != CON...bailing...\n",
2643 			proc, domid, dp->dxp ? str : "NULL");
2644 		IDN_DUNLOCK(domid);
2645 		IDN_SYNC_UNLOCK();
2646 		return;
2647 	}
2648 
2649 	if ((dp->dsync.s_cmd != IDNSYNC_CONNECT) ||
2650 			(dp->dxstate != IDNXS_PEND)) {
2651 		PR_PROTO("%s:%d: cmd (%s) and/or xstate (%s) not "
2652 			"expected (%s/%s)\n",
2653 			proc, domid, idnsync_str[dp->dsync.s_cmd],
2654 			idnxs_str[dp->dxstate], idnsync_str[IDNSYNC_CONNECT],
2655 			idnxs_str[IDNXS_PEND]);
2656 		IDN_DUNLOCK(domid);
2657 		IDN_SYNC_UNLOCK();
2658 		return;
2659 	}
2660 
2661 	idn_xphase_transition(domid, NULL, xargs);
2662 
2663 	IDN_DUNLOCK(domid);
2664 	IDN_SYNC_UNLOCK();
2665 }
2666 
2667 static int
2668 idn_check_con(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs)
2669 {
2670 	int		ready;
2671 	uint_t		msg = mtp ? mtp->mt_mtype : 0;
2672 	idn_domain_t	*dp = &idn_domain[domid];
2673 	domainset_t	ready_set, my_ready_set, query_set;
2674 
2675 	ASSERT(IDN_SYNC_IS_LOCKED());
2676 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
2677 
2678 	if (msg & IDNP_NACK)
2679 		return (0);
2680 
2681 	if ((dp->dstate == IDNDS_CON_PEND) &&
2682 			(msg & IDNP_MSGTYPE_MASK) &&
2683 			(msg & IDNP_ACK))		/* con+ack */
2684 		return (1);
2685 
2686 	if (msg == 0) {
2687 		ready_set = idn.domset.ds_connected &
2688 				~idn.domset.ds_trans_off;
2689 	} else {
2690 		ready_set = GET_XARGS_CON_DOMSET(xargs);
2691 		DOMAINSET_ADD(idn.domset.ds_ready_on, domid);
2692 	}
2693 
2694 	DOMAINSET_ADD(ready_set, idn.localid);
2695 
2696 	query_set = idn_sync_register(domid, IDNSYNC_CONNECT,
2697 					ready_set, IDNSYNC_REG_REG);
2698 	/*
2699 	 * No need to query this domain as he's already
2700 	 * in the CON sequence.
2701 	 */
2702 	DOMAINSET_DEL(query_set, domid);
2703 
2704 	ready = (dp->dsync.s_set_exp == dp->dsync.s_set_rdy) ? 1 : 0;
2705 	if (ready) {
2706 		DOMAINSET_DEL(idn.domset.ds_ready_on, domid);
2707 		DOMAINSET_ADD(idn.domset.ds_connected, domid);
2708 	}
2709 
2710 	if (query_set) {
2711 		int	d;
2712 
2713 		my_ready_set = idn.domset.ds_ready_on |
2714 				idn.domset.ds_connected;
2715 		my_ready_set &= ~idn.domset.ds_trans_off;
2716 		DOMAINSET_ADD(my_ready_set, idn.localid);
2717 
2718 		for (d = 0; d < MAX_DOMAINS; d++) {
2719 			if (!DOMAIN_IN_SET(query_set, d))
2720 				continue;
2721 
2722 			dp = &idn_domain[d];
2723 
2724 			IDN_DLOCK_EXCL(d);
2725 			if ((dp->dsync.s_cmd == IDNSYNC_CONNECT) ||
2726 					!dp->dcookie_send) {
2727 				IDN_DUNLOCK(d);
2728 				continue;
2729 			}
2730 
2731 			IDN_SYNC_QUERY_UPDATE(domid, d);
2732 
2733 			idn_send_con(d, NULL, IDNCON_QUERY, my_ready_set);
2734 			IDN_DUNLOCK(d);
2735 		}
2736 	}
2737 
2738 	return (!msg ? 0 : (ready ? 0 : 1));
2739 }
2740 
2741 /*ARGSUSED2*/
2742 static void
2743 idn_error_con(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs)
2744 {
2745 	uint_t	token;
2746 	uint_t	msg = mtp ? mtp->mt_mtype : 0;
2747 
2748 	ASSERT(IDN_SYNC_IS_LOCKED());
2749 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
2750 
2751 	if (msg & IDNP_MSGTYPE_MASK) {
2752 		idn_msgtype_t	mt;
2753 		idn_xdcargs_t	nargs;
2754 
2755 		mt.mt_mtype = IDNP_NACK;
2756 		mt.mt_atype = msg;
2757 		mt.mt_cookie = mtp->mt_cookie;
2758 		CLR_XARGS(nargs);
2759 		SET_XARGS_NACK_TYPE(nargs, IDNNACK_RETRY);
2760 		idn_send_acknack(domid, &mt, nargs);
2761 	}
2762 
2763 	token = IDN_RETRY_TOKEN(domid, IDNRETRY_CON);
2764 	idn_retry_submit(idn_retry_con, NULL, token,
2765 			idn_msg_retrytime[(int)IDNRETRY_CON]);
2766 }
2767 
2768 /*ARGSUSED*/
2769 static void
2770 idn_action_con_pend(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs)
2771 {
2772 	uint_t		msg = mtp ? mtp->mt_mtype : 0;
2773 	idn_domain_t	*dp = &idn_domain[domid];
2774 	idn_msgtype_t	mt;
2775 	domainset_t	my_ready_set;
2776 
2777 	ASSERT(IDN_SYNC_IS_LOCKED());
2778 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
2779 
2780 	my_ready_set = dp->dsync.s_set_rdy |
2781 			idn.domset.ds_ready_on | idn.domset.ds_connected;
2782 	my_ready_set &= ~idn.domset.ds_trans_off;
2783 	DOMAINSET_ADD(my_ready_set, idn.localid);
2784 
2785 	if (!msg) {
2786 		idn_send_con(domid, NULL, IDNCON_NORMAL, my_ready_set);
2787 	} else {
2788 		mt.mt_mtype = IDNP_CON | IDNP_ACK;
2789 		mt.mt_atype = 0;
2790 		mt.mt_cookie = mtp->mt_cookie;
2791 		idn_send_con(domid, &mt, IDNCON_NORMAL, my_ready_set);
2792 	}
2793 }
2794 
2795 static void
2796 idn_action_con_sent(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs)
2797 {
2798 	uint_t		msg = mtp ? mtp->mt_mtype : 0;
2799 	idn_domain_t	*dp = &idn_domain[domid];
2800 	idn_con_t	contype;
2801 	domainset_t	my_ready_set;
2802 	idn_msgtype_t	mt;
2803 
2804 	ASSERT(IDN_SYNC_IS_LOCKED());
2805 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
2806 
2807 	mt.mt_cookie = mtp ? mtp->mt_cookie : 0;
2808 
2809 	my_ready_set = dp->dsync.s_set_rdy |
2810 				idn.domset.ds_ready_on |
2811 				idn.domset.ds_connected;
2812 	my_ready_set &= ~idn.domset.ds_trans_off;
2813 	DOMAINSET_ADD(my_ready_set, idn.localid);
2814 
2815 	contype = GET_XARGS_CON_TYPE(xargs);
2816 
2817 	if ((msg & IDNP_ACKNACK_MASK) == 0) {
2818 		/*
2819 		 * con
2820 		 */
2821 		mt.mt_mtype = IDNP_CON | IDNP_ACK;
2822 		mt.mt_atype = 0;
2823 		idn_send_con(domid, &mt, contype, my_ready_set);
2824 	} else if (msg & IDNP_MSGTYPE_MASK) {
2825 		idn_xdcargs_t	cargs;
2826 
2827 		mt.mt_mtype = IDNP_ACK;
2828 		mt.mt_atype = msg;
2829 		CLR_XARGS(cargs);
2830 		SET_XARGS_CON_TYPE(cargs, contype);
2831 		SET_XARGS_CON_DOMSET(cargs, my_ready_set);
2832 		/*
2833 		 * con+ack
2834 		 */
2835 		idn_send_acknack(domid, &mt, cargs);
2836 	} else {
2837 		uint_t	token;
2838 		/*
2839 		 * nack - retry
2840 		 */
2841 		token = IDN_RETRY_TOKEN(domid, IDNRETRY_CON);
2842 		idn_retry_submit(idn_retry_con, NULL, token,
2843 				idn_msg_retrytime[(int)IDNRETRY_CON]);
2844 	}
2845 }
2846 
2847 /*ARGSUSED*/
2848 static void
2849 idn_action_con_rcvd(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs)
2850 {
2851 	uint_t	msg = mtp ? mtp->mt_mtype : 0;
2852 
2853 	ASSERT(IDN_SYNC_IS_LOCKED());
2854 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
2855 
2856 	if (msg & IDNP_NACK) {
2857 		uint_t	token;
2858 		/*
2859 		 * nack - retry
2860 		 */
2861 		token = IDN_RETRY_TOKEN(domid, IDNRETRY_CON);
2862 		idn_retry_submit(idn_retry_con, NULL, token,
2863 				idn_msg_retrytime[(int)IDNRETRY_CON]);
2864 	}
2865 }
2866 
2867 static void
2868 idn_final_con(int domid)
2869 {
2870 	uint_t		targ;
2871 	uint_t		token = IDN_RETRY_TOKEN(domid, IDNRETRY_CON);
2872 	idn_domain_t	*dp = &idn_domain[domid];
2873 	procname_t	proc = "idn_final_con";
2874 
2875 	ASSERT(IDN_SYNC_IS_LOCKED());
2876 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
2877 
2878 	(void) idn_retry_terminate(token);
2879 
2880 	dp->dxp = NULL;
2881 	IDN_XSTATE_TRANSITION(dp, IDNXS_NIL);
2882 
2883 	idn_sync_exit(domid, IDNSYNC_CONNECT);
2884 
2885 	CHECKPOINT_OPENED(IDNSB_CHKPT_LINK, dp->dhw.dh_boardset, 1);
2886 
2887 	DOMAINSET_DEL(idn.domset.ds_trans_on, domid);
2888 	DOMAINSET_DEL(idn.domset.ds_relink, domid);
2889 	IDN_FSTATE_TRANSITION(dp, IDNFIN_OFF);
2890 
2891 	PR_PROTO("%s:%d: CONNECTED\n", proc, domid);
2892 
2893 	if (idn.domset.ds_trans_on == 0) {
2894 		if ((idn.domset.ds_trans_off | idn.domset.ds_relink) == 0) {
2895 			PR_HITLIST("%s:%d: HITLIST %x -> 0\n",
2896 				proc, domid, idn.domset.ds_hitlist);
2897 			idn.domset.ds_hitlist = 0;
2898 		}
2899 		PR_PROTO("%s:%d: ALL CONNECTED ************ "
2900 			"(0x%x + 0x%x) = 0x%x\n", proc, domid,
2901 			DOMAINSET(idn.localid), idn.domset.ds_connected,
2902 			DOMAINSET(idn.localid) | idn.domset.ds_connected);
2903 	} else {
2904 		PR_PROTO("%s:%d: >>> ds_trans_on = 0x%x, ds_ready_on = 0x%x\n",
2905 			proc, domid,
2906 			idn.domset.ds_trans_on, idn.domset.ds_ready_on);
2907 	}
2908 
2909 	if (idn_verify_config_mbox(domid)) {
2910 		idnsb_error_t	idnerr;
2911 		/*
2912 		 * Mailbox is not cool. Need to disconnect.
2913 		 */
2914 		INIT_IDNKERR(&idnerr);
2915 		SET_IDNKERR_ERRNO(&idnerr, EPROTO);
2916 		SET_IDNKERR_IDNERR(&idnerr, IDNKERR_SMR_CORRUPTED);
2917 		SET_IDNKERR_PARAM0(&idnerr, domid);
2918 		idn_update_op(IDNOP_ERROR, DOMAINSET(domid), &idnerr);
2919 		/*
2920 		 * We cannot disconnect from an individual domain
2921 		 * unless all domains are attempting to disconnect
2922 		 * from him also, especially now since we touched
2923 		 * the SMR and now we have a potential cache conflicts
2924 		 * with the other domains with respect to this
2925 		 * domain.  Disconnect attempt will effectively
2926 		 * shutdown connection with respective domain
2927 		 * which is the effect we really want anyway.
2928 		 */
2929 		idn_disconnect(domid, IDNFIN_NORMAL, IDNFIN_ARG_SMRBAD,
2930 				IDNFIN_SYNC_YES);
2931 
2932 		return;
2933 	}
2934 
2935 	if (lock_try(&idn.first_swlink)) {
2936 		/*
2937 		 * This is our first connection.  Need to
2938 		 * kick some stuff into gear.
2939 		 */
2940 		idndl_dlpi_init();
2941 		(void) idn_activate_channel(CHANSET_ALL, IDNCHAN_ONLINE);
2942 
2943 		targ = 0xf0;
2944 	} else {
2945 		targ = 0;
2946 	}
2947 
2948 	idn_mainmbox_activate(domid);
2949 
2950 	idn_update_op(IDNOP_CONNECTED, DOMAINSET(domid), NULL);
2951 
2952 	IDN_GKSTAT_GLOBAL_EVENT(gk_links, gk_link_last);
2953 
2954 	membar_stst_ldst();
2955 
2956 	IDN_DSTATE_TRANSITION(dp, IDNDS_CONNECTED);
2957 	/*
2958 	 * Need to kick off initial commands in background.
2959 	 * We do not want to do them within the context of
2960 	 * a protocol server because they may sleep and thus
2961 	 * cause the protocol server to incur a soft-deadlock,
2962 	 * i.e. he's sleeping waiting in the slab-waiting area
2963 	 * for a response that will arrive on his protojob
2964 	 * queue, but which he obviously can't process since
2965 	 * he's not waiting on his protojob queue.
2966 	 */
2967 	targ |= domid & 0x0f;
2968 	(void) timeout(idn_link_established, (void *)(uintptr_t)targ, 50);
2969 
2970 	cmn_err(CE_NOTE,
2971 		"!IDN: 200: link (domain %d, CPU %d) connected",
2972 		dp->domid, dp->dcpu);
2973 }
2974 
2975 static void
2976 idn_exit_con(int domid, uint_t msgtype)
2977 {
2978 	idn_domain_t	*dp = &idn_domain[domid];
2979 	idn_fin_t	fintype;
2980 	procname_t	proc = "idn_exit_con";
2981 	STRING(str);
2982 
2983 	ASSERT(IDN_SYNC_IS_LOCKED());
2984 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
2985 
2986 	INUM2STR(msgtype, str);
2987 	PR_PROTO("%s:%d: msgtype = 0x%x(%s)\n", proc, domid, msgtype, str);
2988 
2989 	fintype = msgtype ? IDNFIN_NORMAL : IDNFIN_FORCE_HARD;
2990 
2991 	IDN_GLOCK_SHARED();
2992 	if (idn.state != IDNGS_DISCONNECT) {
2993 		DOMAINSET_ADD(idn.domset.ds_relink, domid);
2994 		IDN_HISTORY_LOG(IDNH_RELINK, domid, dp->dstate,
2995 				idn.domset.ds_relink);
2996 	} else {
2997 		DOMAINSET_DEL(idn.domset.ds_relink, domid);
2998 	}
2999 	IDN_GUNLOCK();
3000 
3001 	idn_disconnect(domid, fintype, IDNFIN_ARG_NONE,
3002 			IDNDS_SYNC_TYPE(dp));
3003 }
3004 
3005 static int
3006 idn_send_fin(int domid, idn_msgtype_t *mtp, idn_fin_t fintype,
3007 		idn_finarg_t finarg, idn_finopt_t finopt,
3008 		domainset_t finset, uint_t finmaster)
3009 {
3010 	int		need_timer = 1;
3011 	uint_t		acknack;
3012 	uint_t		fintypearg = 0;
3013 	idn_msgtype_t	mt;
3014 	idn_domain_t	*dp = &idn_domain[domid];
3015 	procname_t	proc = "idn_send_fin";
3016 
3017 	ASSERT(IDN_SYNC_IS_LOCKED());
3018 	ASSERT(IDN_DLOCK_IS_HELD(domid));
3019 
3020 	ASSERT((fintype != IDNFIN_QUERY) ? (finopt != IDNFIN_OPT_NONE) : 1);
3021 
3022 	if (mtp) {
3023 		acknack = mtp->mt_mtype & IDNP_ACKNACK_MASK;
3024 		mt.mt_mtype = mtp->mt_mtype;
3025 		mt.mt_atype = mtp->mt_atype;
3026 		mt.mt_cookie = mtp->mt_cookie;
3027 	} else {
3028 		acknack = 0;
3029 		mt.mt_mtype = IDNP_FIN;
3030 		mt.mt_atype = 0;
3031 		/*
3032 		 * For simple FIN queries we want a unique
3033 		 * timer assigned.  For others, they
3034 		 * effectively share one.
3035 		 */
3036 		if (fintype == IDNFIN_QUERY)
3037 			mt.mt_cookie = 0;
3038 		else
3039 			mt.mt_cookie = IDN_TIMER_PUBLIC_COOKIE;
3040 	}
3041 
3042 	PR_PROTO("%s:%d: sending fin%sto (cpu %d) "
3043 		"[ft=%s, fa=%s, fs=0x%x, fo=%s, fm=(%d,%d)]\n",
3044 		proc, domid,
3045 		(acknack & IDNP_ACK) ? "+ack " :
3046 		(acknack & IDNP_NACK) ? "+nack " : " ",
3047 		dp->dcpu, idnfin_str[fintype], idnfinarg_str[finarg],
3048 		(int)finset, idnfinopt_str[finopt],
3049 		FIN_MASTER_DOMID(finmaster), FIN_MASTER_CPUID(finmaster));
3050 
3051 	if (need_timer) {
3052 		IDN_MSGTIMER_START(domid, IDNP_FIN, (ushort_t)fintype,
3053 				idn_msg_waittime[IDNP_FIN], &mt.mt_cookie);
3054 	}
3055 
3056 	SET_FIN_TYPE(fintypearg, fintype);
3057 	SET_FIN_ARG(fintypearg, finarg);
3058 
3059 	IDNXDC(domid, &mt, fintypearg, (uint_t)finset,
3060 		(uint_t)finopt, finmaster);
3061 
3062 	return (0);
3063 }
3064 
3065 /*
3066  * Must leave w/DLOCK dropped and SYNC_LOCK held.
3067  */
3068 static int
3069 idn_recv_fin(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs)
3070 {
3071 	uint_t		msg = mtp ? mtp->mt_mtype : 0;
3072 	idn_fin_t	fintype;
3073 	idn_finarg_t	finarg;
3074 	idn_finopt_t	finopt;
3075 	domainset_t	my_ready_set, ready_set;
3076 	idn_msgtype_t	mt;
3077 	idn_domain_t	*dp = &idn_domain[domid];
3078 	idn_xdcargs_t	aargs;
3079 	procname_t	proc = "idn_recv_fin";
3080 
3081 	ASSERT(IDN_SYNC_IS_LOCKED());
3082 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
3083 
3084 	mt.mt_cookie = mtp ? mtp->mt_cookie : 0;
3085 
3086 	fintype   = GET_XARGS_FIN_TYPE(xargs);
3087 	finarg    = GET_XARGS_FIN_ARG(xargs);
3088 	ready_set = GET_XARGS_FIN_DOMSET(xargs);
3089 	finopt    = GET_XARGS_FIN_OPT(xargs);
3090 
3091 	CLR_XARGS(aargs);
3092 
3093 	if (msg & IDNP_NACK) {
3094 		PR_PROTO("%s:%d: received NACK (type = %s)\n",
3095 			proc, domid, idnnack_str[xargs[0]]);
3096 	} else {
3097 		PR_PROTO("%s:%d: fintype = %s, finopt = %s, "
3098 			"finarg = %s, ready_set = 0x%x\n",
3099 			proc, domid, idnfin_str[fintype],
3100 			idnfinopt_str[finopt],
3101 			idnfinarg_str[finarg], ready_set);
3102 	}
3103 
3104 	if (!(msg & IDNP_NACK) && (fintype == IDNFIN_QUERY)) {
3105 		domainset_t	query_set;
3106 
3107 		query_set = idn_sync_register(domid, IDNSYNC_DISCONNECT,
3108 						ready_set, IDNSYNC_REG_REG);
3109 
3110 		my_ready_set = ~idn.domset.ds_connected |
3111 					idn.domset.ds_ready_off;
3112 
3113 		if (msg & IDNP_MSGTYPE_MASK) {
3114 			mt.mt_mtype = IDNP_ACK;
3115 			mt.mt_atype = IDNP_FIN;
3116 			SET_XARGS_FIN_TYPE(aargs, fintype);
3117 			SET_XARGS_FIN_ARG(aargs, finarg);
3118 			SET_XARGS_FIN_DOMSET(aargs, my_ready_set);
3119 			SET_XARGS_FIN_OPT(aargs, IDNFIN_OPT_NONE);
3120 			SET_XARGS_FIN_MASTER(aargs, NIL_FIN_MASTER);
3121 			idn_send_acknack(domid, &mt, aargs);
3122 		}
3123 
3124 		if (query_set) {
3125 			uint_t	token;
3126 
3127 			token = IDN_RETRY_TOKEN(domid, IDNRETRY_FINQ);
3128 			idn_retry_submit(idn_retry_query, NULL, token,
3129 					idn_msg_retrytime[(int)IDNRETRY_FINQ]);
3130 		}
3131 
3132 		return (0);
3133 	}
3134 
3135 	if (dp->dxp != &xphase_fin) {
3136 		uint_t	token;
3137 
3138 		if (IDNDS_IS_CLOSED(dp)) {
3139 			PR_PROTO("%s:%d: domain already closed (%s)\n",
3140 				proc, domid, idnds_str[dp->dstate]);
3141 			if (msg & IDNP_MSGTYPE_MASK) {
3142 				/*
3143 				 * fin or fin+ack.
3144 				 */
3145 				mt.mt_mtype = IDNP_NACK;
3146 				mt.mt_atype = msg;
3147 				SET_XARGS_NACK_TYPE(aargs, IDNNACK_NOCONN);
3148 				idn_send_acknack(domid, &mt, aargs);
3149 			}
3150 			return (0);
3151 		}
3152 		dp->dfin_sync = IDNDS_SYNC_TYPE(dp);
3153 
3154 		/*
3155 		 * Need to do some clean-up ala idn_disconnect().
3156 		 *
3157 		 * Terminate any outstanding commands that were
3158 		 * targeted towards this domain.
3159 		 */
3160 		idn_terminate_cmd(domid, ECANCELED);
3161 
3162 		/*
3163 		 * Terminate any and all retries that may have
3164 		 * outstanding for this domain.
3165 		 */
3166 		token = IDN_RETRY_TOKEN(domid, IDN_RETRY_TYPEALL);
3167 		(void) idn_retry_terminate(token);
3168 
3169 		/*
3170 		 * Stop all outstanding message timers for
3171 		 * this guy.
3172 		 */
3173 		IDN_MSGTIMER_STOP(domid, 0, 0);
3174 
3175 		dp->dxp = &xphase_fin;
3176 		IDN_XSTATE_TRANSITION(dp, IDNXS_PEND);
3177 	}
3178 
3179 	if (msg & IDNP_NACK) {
3180 		idn_nack_t	nack;
3181 
3182 		nack = GET_XARGS_NACK_TYPE(xargs);
3183 		if (nack == IDNNACK_NOCONN) {
3184 			/*
3185 			 * We're trying to FIN with somebody we're
3186 			 * already disconnected from.  Need to
3187 			 * speed this guy through.
3188 			 */
3189 			DOMAINSET_ADD(idn.domset.ds_ready_off, domid);
3190 			(void) idn_sync_register(domid, IDNSYNC_DISCONNECT,
3191 					DOMAINSET_ALL, IDNSYNC_REG_REG);
3192 			ready_set = (uint_t)DOMAINSET_ALL;
3193 			/*
3194 			 * Need to transform message to allow us to
3195 			 * pass this guy right through and not waste time
3196 			 * talking to him.
3197 			 */
3198 			IDN_FSTATE_TRANSITION(dp, IDNFIN_FORCE_HARD);
3199 
3200 			switch (dp->dstate) {
3201 			case IDNDS_FIN_PEND:
3202 				mtp->mt_mtype = 0;
3203 				mtp->mt_atype = 0;
3204 				break;
3205 
3206 			case IDNDS_FIN_SENT:
3207 				mtp->mt_mtype = IDNP_FIN | IDNP_ACK;
3208 				mtp->mt_atype = 0;
3209 				break;
3210 
3211 			case IDNDS_FIN_RCVD:
3212 				mtp->mt_mtype = IDNP_ACK;
3213 				mtp->mt_atype = IDNP_FIN | IDNP_ACK;
3214 				break;
3215 
3216 			default:
3217 #ifdef DEBUG
3218 				cmn_err(CE_PANIC,
3219 					"%s:%d: UNEXPECTED state = %s",
3220 					proc, domid,
3221 					idnds_str[dp->dstate]);
3222 #endif /* DEBUG */
3223 				break;
3224 			}
3225 		}
3226 		fintype = (uint_t)dp->dfin;
3227 		finopt = DOMAIN_IN_SET(idn.domset.ds_relink, domid) ?
3228 				IDNFIN_OPT_RELINK : IDNFIN_OPT_UNLINK;
3229 
3230 		CLR_XARGS(xargs);
3231 		SET_XARGS_FIN_TYPE(xargs, fintype);
3232 		SET_XARGS_FIN_ARG(xargs, finarg);
3233 		SET_XARGS_FIN_DOMSET(xargs, ready_set);
3234 		SET_XARGS_FIN_OPT(xargs, finopt);
3235 		SET_XARGS_FIN_MASTER(xargs, NIL_FIN_MASTER);
3236 	}
3237 
3238 	idn_xphase_transition(domid, mtp, xargs);
3239 
3240 	return (0);
3241 }
3242 
3243 /*ARGSUSED1*/
3244 static void
3245 idn_retry_fin(uint_t token, void *arg)
3246 {
3247 	int		domid = IDN_RETRY_TOKEN2DOMID(token);
3248 	int		new_masterid, new_cpuid = IDN_NIL_DCPU;
3249 	uint_t		finmaster;
3250 	idn_domain_t	*dp = &idn_domain[domid];
3251 	idn_xdcargs_t	xargs;
3252 	idn_finopt_t	finopt;
3253 	procname_t	proc = "idn_retry_fin";
3254 
3255 	ASSERT(IDN_RETRY_TOKEN2TYPE(token) == IDNRETRY_FIN);
3256 
3257 	IDN_SYNC_LOCK();
3258 	IDN_DLOCK_EXCL(domid);
3259 
3260 	if (dp->dxp != &xphase_fin) {
3261 		PR_PROTO("%s:%d: dxp(0x%p) != xstate_fin(0x%p)...bailing\n",
3262 			proc, domid, dp->dxp, &xphase_fin);
3263 		IDN_DUNLOCK(domid);
3264 		IDN_SYNC_UNLOCK();
3265 		return;
3266 	}
3267 
3268 	if (dp->dxstate != IDNXS_PEND) {
3269 		PR_PROTO("%s:%d: xstate(%s) != %s...bailing\n",
3270 			proc, domid, idnxs_str[dp->dxstate],
3271 			idnxs_str[IDNXS_PEND]);
3272 		IDN_DUNLOCK(domid);
3273 		IDN_SYNC_UNLOCK();
3274 		return;
3275 	}
3276 
3277 	finopt = DOMAIN_IN_SET(idn.domset.ds_relink, domid) ?
3278 			IDNFIN_OPT_RELINK : IDNFIN_OPT_UNLINK;
3279 
3280 	CLR_XARGS(xargs);
3281 	SET_XARGS_FIN_TYPE(xargs, dp->dfin);
3282 	/*LINTED*/
3283 	SET_XARGS_FIN_ARG(xargs, IDNFIN_ARG_NONE);
3284 	SET_XARGS_FIN_OPT(xargs, finopt);
3285 	SET_XARGS_FIN_DOMSET(xargs, 0);		/* unused when msg == 0 */
3286 	IDN_GLOCK_SHARED();
3287 	new_masterid = IDN_GET_NEW_MASTERID();
3288 	IDN_GUNLOCK();
3289 	if (new_masterid != IDN_NIL_DOMID)
3290 		new_cpuid = idn_domain[new_masterid].dcpu;
3291 	finmaster = MAKE_FIN_MASTER(new_masterid, new_cpuid);
3292 	SET_XARGS_FIN_MASTER(xargs, finmaster);
3293 
3294 	idn_xphase_transition(domid, NULL, xargs);
3295 
3296 	IDN_DUNLOCK(domid);
3297 	IDN_SYNC_UNLOCK();
3298 }
3299 
3300 static int
3301 idn_check_fin_pend(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs)
3302 {
3303 	idn_domain_t	*dp = &idn_domain[domid];
3304 	idn_fin_t	fintype;
3305 	idn_finopt_t	finopt;
3306 	idn_finarg_t	finarg;
3307 	int		ready;
3308 	int		finmasterid;
3309 	int		fincpuid;
3310 	uint_t		finmaster;
3311 	uint_t		msg = mtp ? mtp->mt_mtype : 0;
3312 	domainset_t	query_set, ready_set, conn_set;
3313 	domainset_t	my_ready_set, shutdown_set;
3314 	procname_t	proc = "idn_check_fin_pend";
3315 
3316 	ASSERT(IDN_SYNC_IS_LOCKED());
3317 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
3318 
3319 	if (msg & IDNP_NACK)
3320 		return (0);
3321 
3322 	if ((dp->dstate == IDNDS_FIN_PEND) &&
3323 			(msg & IDNP_MSGTYPE_MASK) &&
3324 			(msg & IDNP_ACK))		/* fin+ack */
3325 		return (1);
3326 
3327 	query_set = 0;
3328 
3329 	if (!DOMAIN_IN_SET(idn.domset.ds_trans_off, domid)) {
3330 		/*
3331 		 * Can't remove domain from ds_connected yet,
3332 		 * since he's still officially connected until
3333 		 * we get an ACK from him.
3334 		 */
3335 		DOMAINSET_DEL(idn.domset.ds_trans_on, domid);
3336 		DOMAINSET_ADD(idn.domset.ds_trans_off, domid);
3337 	}
3338 
3339 	IDN_GLOCK_SHARED();
3340 	conn_set = (idn.domset.ds_connected | idn.domset.ds_trans_on) &
3341 			~idn.domset.ds_trans_off;
3342 	if ((idn.state == IDNGS_DISCONNECT) ||
3343 		(idn.state == IDNGS_RECONFIG) ||
3344 		(domid == IDN_GET_MASTERID()) || !conn_set) {
3345 		/*
3346 		 * If we're disconnecting, reconfiguring,
3347 		 * unlinking from the master, or unlinking
3348 		 * the last of our connections, then we need
3349 		 * to shutdown all the channels.
3350 		 */
3351 		shutdown_set = DOMAINSET_ALL;
3352 	} else {
3353 		shutdown_set = DOMAINSET(domid);
3354 	}
3355 	IDN_GUNLOCK();
3356 
3357 	idn_shutdown_datapath(shutdown_set,
3358 				(dp->dfin == IDNFIN_FORCE_HARD));
3359 
3360 	IDN_GLOCK_EXCL();
3361 	/*
3362 	 * Remap the SMR back to our local space if the remote
3363 	 * domain going down is the master.  We do this now before
3364 	 * flushing caches.  This will help guarantee that any
3365 	 * accidental accesses to the SMR after the cache flush
3366 	 * will only go to local memory.
3367 	 */
3368 	if ((domid == IDN_GET_MASTERID()) && (idn.smr.rempfn != PFN_INVALID)) {
3369 		PR_PROTO("%s:%d: deconfiging CURRENT MASTER - SMR remap\n",
3370 			proc, domid);
3371 		IDN_DLOCK_EXCL(idn.localid);
3372 		/*
3373 		 * We're going to remap the SMR,
3374 		 * so gotta blow away our local
3375 		 * pointer to the mbox table.
3376 		 */
3377 		idn_domain[idn.localid].dmbox.m_tbl = NULL;
3378 		IDN_DUNLOCK(idn.localid);
3379 
3380 		idn.smr.rempfn = PFN_INVALID;
3381 		idn.smr.rempfnlim = PFN_INVALID;
3382 
3383 		smr_remap(&kas, idn.smr.vaddr, idn.smr.locpfn, IDN_SMR_SIZE);
3384 	}
3385 	IDN_GUNLOCK();
3386 
3387 	if (DOMAIN_IN_SET(idn.domset.ds_flush, domid)) {
3388 		idnxf_flushall_ecache();
3389 		CHECKPOINT_CLOSED(IDNSB_CHKPT_CACHE, dp->dhw.dh_boardset, 2);
3390 		DOMAINSET_DEL(idn.domset.ds_flush, domid);
3391 	}
3392 
3393 	fintype   = GET_XARGS_FIN_TYPE(xargs);
3394 	finarg    = GET_XARGS_FIN_ARG(xargs);
3395 	ready_set = GET_XARGS_FIN_DOMSET(xargs);
3396 	finopt    = GET_XARGS_FIN_OPT(xargs);
3397 
3398 	ASSERT(fintype != IDNFIN_QUERY);
3399 	if (!VALID_FIN(fintype)) {
3400 		/*
3401 		 * If for some reason remote domain
3402 		 * sent us an invalid FIN type,
3403 		 * override it to a  NORMAL fin.
3404 		 */
3405 		PR_PROTO("%s:%d: WARNING invalid fintype (%d) -> %s(%d)\n",
3406 			proc, domid, (int)fintype,
3407 			idnfin_str[IDNFIN_NORMAL], (int)IDNFIN_NORMAL);
3408 		fintype = IDNFIN_NORMAL;
3409 	}
3410 
3411 	if (!VALID_FINOPT(finopt)) {
3412 		PR_PROTO("%s:%d: WARNING invalid finopt (%d) -> %s(%d)\n",
3413 			proc, domid, (int)finopt,
3414 			idnfinopt_str[IDNFIN_OPT_UNLINK],
3415 			(int)IDNFIN_OPT_UNLINK);
3416 		finopt = IDNFIN_OPT_UNLINK;
3417 	}
3418 
3419 	finmaster = GET_XARGS_FIN_MASTER(xargs);
3420 	finmasterid = FIN_MASTER_DOMID(finmaster);
3421 	fincpuid = FIN_MASTER_CPUID(finmaster);
3422 
3423 	if ((finarg != IDNFIN_ARG_NONE) &&
3424 			!DOMAIN_IN_SET(idn.domset.ds_hitlist, domid)) {
3425 		idnsb_error_t	idnerr;
3426 
3427 		INIT_IDNKERR(&idnerr);
3428 		SET_IDNKERR_ERRNO(&idnerr, EPROTO);
3429 		SET_IDNKERR_IDNERR(&idnerr, FINARG2IDNKERR(finarg));
3430 		SET_IDNKERR_PARAM0(&idnerr, domid);
3431 
3432 		if (IDNFIN_ARG_IS_FATAL(finarg)) {
3433 			finopt = IDNFIN_OPT_UNLINK;
3434 			DOMAINSET_DEL(idn.domset.ds_relink, domid);
3435 			DOMAINSET_ADD(idn.domset.ds_hitlist, domid);
3436 
3437 			if (idn.domset.ds_connected == 0) {
3438 				domainset_t	domset;
3439 
3440 				IDN_GLOCK_EXCL();
3441 				domset = ~idn.domset.ds_relink;
3442 				if (idn.domset.ds_relink == 0) {
3443 					IDN_GSTATE_TRANSITION(IDNGS_DISCONNECT);
3444 				}
3445 				domset &= ~idn.domset.ds_hitlist;
3446 				/*
3447 				 * The primary domain we were trying to
3448 				 * connect to fin'd us with a fatal argument.
3449 				 * Something isn't cool in our IDN environment,
3450 				 * e.g. corrupted SMR or non-compatible CONFIG
3451 				 * parameters.  In any case we need to dismantle
3452 				 * ourselves completely.
3453 				 */
3454 				IDN_SET_NEW_MASTERID(IDN_NIL_DOMID);
3455 				IDN_GUNLOCK();
3456 				IDN_DUNLOCK(domid);
3457 
3458 				DOMAINSET_DEL(domset, idn.localid);
3459 				DOMAINSET_DEL(domset, domid);
3460 
3461 				idn_update_op(IDNOP_ERROR, DOMAINSET_ALL,
3462 						&idnerr);
3463 
3464 				PR_HITLIST("%s:%d: unlink_domainset(%x) "
3465 					"due to CFG error (relink=%x, "
3466 					"hitlist=%x)\n", proc, domid, domset,
3467 					idn.domset.ds_relink,
3468 					idn.domset.ds_hitlist);
3469 
3470 				idn_unlink_domainset(domset, IDNFIN_NORMAL,
3471 						finarg, IDNFIN_OPT_UNLINK,
3472 						BOARDSET_ALL);
3473 				IDN_DLOCK_EXCL(domid);
3474 			}
3475 			PR_HITLIST("%s:%d: CFG error, (conn=%x, relink=%x, "
3476 				"hitlist=%x)\n",
3477 				proc, domid, idn.domset.ds_connected,
3478 				idn.domset.ds_relink, idn.domset.ds_hitlist);
3479 		}
3480 		idn_update_op(IDNOP_ERROR, DOMAINSET(domid), &idnerr);
3481 	}
3482 
3483 	if ((finmasterid != IDN_NIL_DOMID) &&
3484 			(!VALID_DOMAINID(finmasterid) ||
3485 			DOMAIN_IN_SET(idn.domset.ds_hitlist, domid))) {
3486 		PR_HITLIST("%s:%d: finmasterid = %d -> -1, relink=%x, "
3487 			"hitlist=%x\n",
3488 			proc, domid, finmasterid, idn.domset.ds_relink,
3489 			idn.domset.ds_hitlist);
3490 		PR_PROTO("%s:%d: WARNING invalid finmasterid (%d) -> -1\n",
3491 			proc, domid, finmasterid);
3492 		finmasterid = IDN_NIL_DOMID;
3493 	}
3494 
3495 	IDN_GLOCK_EXCL();
3496 
3497 	if ((finopt == IDNFIN_OPT_RELINK) && (idn.state != IDNGS_DISCONNECT)) {
3498 		DOMAINSET_ADD(idn.domset.ds_relink, domid);
3499 		IDN_HISTORY_LOG(IDNH_RELINK, domid, dp->dstate,
3500 					idn.domset.ds_relink);
3501 	} else {
3502 		DOMAINSET_DEL(idn.domset.ds_relink, domid);
3503 		DOMAINSET_ADD(idn.domset.ds_hitlist, domid);
3504 	}
3505 
3506 	if ((domid == IDN_GET_NEW_MASTERID()) &&
3507 			!DOMAIN_IN_SET(idn.domset.ds_relink, domid)) {
3508 		IDN_SET_NEW_MASTERID(IDN_NIL_DOMID);
3509 	}
3510 
3511 	if ((idn.state != IDNGS_DISCONNECT) &&
3512 			(idn.state != IDNGS_RECONFIG) &&
3513 			(domid == IDN_GET_MASTERID())) {
3514 		domainset_t	dis_set, master_candidates;
3515 
3516 		IDN_GKSTAT_GLOBAL_EVENT(gk_reconfigs, gk_reconfig_last);
3517 
3518 		IDN_GSTATE_TRANSITION(IDNGS_RECONFIG);
3519 		IDN_GUNLOCK();
3520 
3521 		if ((finmasterid != IDN_NIL_DOMID) &&
3522 				(finmasterid != idn.localid)) {
3523 			if (finmasterid != domid)
3524 				IDN_DLOCK_EXCL(finmasterid);
3525 			if (idn_open_domain(finmasterid, fincpuid, 0) < 0) {
3526 				cmn_err(CE_WARN,
3527 					"IDN: 205: (%s) failed to "
3528 					"open-domain(%d,%d)",
3529 					proc, finmasterid, fincpuid);
3530 				if (finmasterid != domid)
3531 					IDN_DUNLOCK(finmasterid);
3532 				finmasterid = IDN_NIL_DOMID;
3533 			}
3534 			if (finmasterid != domid)
3535 				IDN_DUNLOCK(finmasterid);
3536 		}
3537 
3538 		IDN_GLOCK_EXCL();
3539 		if (finmasterid == IDN_NIL_DOMID) {
3540 			int	m;
3541 
3542 			master_candidates = idn.domset.ds_trans_on |
3543 						idn.domset.ds_connected |
3544 						idn.domset.ds_relink;
3545 			master_candidates &= ~(idn.domset.ds_trans_off &
3546 						~idn.domset.ds_relink);
3547 			DOMAINSET_DEL(master_candidates, domid);
3548 			/*
3549 			 * Local domain gets to participate also.
3550 			 */
3551 			DOMAINSET_ADD(master_candidates, idn.localid);
3552 
3553 			m = idn_select_candidate(master_candidates);
3554 			IDN_SET_NEW_MASTERID(m);
3555 		} else {
3556 			IDN_SET_NEW_MASTERID(finmasterid);
3557 		}
3558 		IDN_GUNLOCK();
3559 
3560 		dis_set = idn.domset.ds_trans_on | idn.domset.ds_connected;
3561 		DOMAINSET_DEL(dis_set, domid);
3562 
3563 		idn_unlink_domainset(dis_set, IDNFIN_NORMAL, IDNFIN_ARG_NONE,
3564 					IDNFIN_OPT_RELINK, BOARDSET_ALL);
3565 	} else {
3566 		IDN_GUNLOCK();
3567 	}
3568 
3569 	/*
3570 	 * My local ready-set are those domains from which I
3571 	 * have confirmed no datapaths exist.
3572 	 */
3573 	my_ready_set = ~idn.domset.ds_connected;
3574 
3575 	switch (dp->dfin) {
3576 	case IDNFIN_NORMAL:
3577 	case IDNFIN_FORCE_SOFT:
3578 	case IDNFIN_FORCE_HARD:
3579 		if (fintype < dp->dfin) {
3580 			/*
3581 			 * Remote domain has requested a
3582 			 * FIN of lower priority than what
3583 			 * we're currently running.  Just
3584 			 * leave the priority where it is.
3585 			 */
3586 			break;
3587 		}
3588 		/*FALLTHROUGH*/
3589 
3590 	default:
3591 		IDN_FSTATE_TRANSITION(dp, fintype);
3592 		break;
3593 	}
3594 
3595 	ASSERT(dp->dfin_sync != IDNFIN_SYNC_OFF);
3596 
3597 	if (msg == 0) {
3598 		/*
3599 		 * Local domain is initiating a FIN sequence
3600 		 * to remote domid.  Note that remote domain
3601 		 * remains in ds_connected even though he's
3602 		 * in thet ready-set from the local domain's
3603 		 * perspective.  We can't remove him from
3604 		 * ds_connected until we get a confirmed message
3605 		 * from him indicating he has ceased communication.
3606 		 */
3607 		ready_set = my_ready_set;
3608 	} else {
3609 		/*
3610 		 * Remote domain initiated a FIN sequence
3611 		 * to local domain.  This implies that he
3612 		 * has shutdown his datapath to us.  Since
3613 		 * we shutdown our datapath to him, we're
3614 		 * effectively now in his ready-set.
3615 		 */
3616 		DOMAINSET_ADD(ready_set, idn.localid);
3617 		/*
3618 		 * Since we know both sides of the connection
3619 		 * have ceased, this remote domain is effectively
3620 		 * considered disconnected.
3621 		 */
3622 		DOMAINSET_ADD(idn.domset.ds_ready_off, domid);
3623 	}
3624 
3625 	if (dp->dfin == IDNFIN_FORCE_HARD) {
3626 		/*
3627 		 * If we're doing a hard disconnect
3628 		 * of this domain then we want to
3629 		 * blow straight through and not
3630 		 * waste time trying to talk to the
3631 		 * remote domain nor to domains we
3632 		 * believe are AWOL.  Although we will
3633 		 * try and do it cleanly with
3634 		 * everybody else.
3635 		 */
3636 		DOMAINSET_ADD(my_ready_set, domid);
3637 		my_ready_set |= idn.domset.ds_awol;
3638 		ready_set = DOMAINSET_ALL;
3639 
3640 	} else if (dp->dfin_sync == IDNFIN_SYNC_NO) {
3641 		/*
3642 		 * If we're not fin'ing this domain
3643 		 * synchronously then the only
3644 		 * expected domain set is himself.
3645 		 */
3646 		ready_set |= ~DOMAINSET(domid);
3647 		my_ready_set |= ~DOMAINSET(domid);
3648 	}
3649 
3650 	if (dp->dsync.s_cmd != IDNSYNC_DISCONNECT) {
3651 		idn_sync_exit(domid, IDNSYNC_CONNECT);
3652 		idn_sync_enter(domid, IDNSYNC_DISCONNECT,
3653 					DOMAINSET_ALL, my_ready_set,
3654 					idn_xstate_transfunc,
3655 					(void *)IDNP_FIN);
3656 	}
3657 
3658 	query_set = idn_sync_register(domid, IDNSYNC_DISCONNECT,
3659 					ready_set, IDNSYNC_REG_REG);
3660 	/*
3661 	 * No need to query this domain as he's already
3662 	 * in the FIN sequence.
3663 	 */
3664 	DOMAINSET_DEL(query_set, domid);
3665 
3666 	ready = (dp->dsync.s_set_exp == dp->dsync.s_set_rdy) ? 1 : 0;
3667 	if (ready) {
3668 		DOMAINSET_DEL(idn.domset.ds_ready_off, domid);
3669 		DOMAINSET_DEL(idn.domset.ds_connected, domid);
3670 	}
3671 
3672 	if (query_set) {
3673 		int	d;
3674 
3675 		my_ready_set = idn.domset.ds_ready_off |
3676 				~idn.domset.ds_connected;
3677 
3678 		for (d = 0; d < MAX_DOMAINS; d++) {
3679 			if (!DOMAIN_IN_SET(query_set, d))
3680 				continue;
3681 
3682 			dp = &idn_domain[d];
3683 
3684 			IDN_DLOCK_EXCL(d);
3685 
3686 			if (dp->dsync.s_cmd == IDNSYNC_DISCONNECT) {
3687 				IDN_DUNLOCK(d);
3688 				continue;
3689 			}
3690 
3691 			IDN_SYNC_QUERY_UPDATE(domid, d);
3692 
3693 			idn_send_fin(d, NULL, IDNFIN_QUERY, IDNFIN_ARG_NONE,
3694 					IDNFIN_OPT_NONE, my_ready_set,
3695 					NIL_FIN_MASTER);
3696 			IDN_DUNLOCK(d);
3697 		}
3698 	}
3699 
3700 	return (!msg ? 0 : (ready ? 0 : 1));
3701 }
3702 
3703 /*ARGSUSED*/
3704 static void
3705 idn_error_fin_pend(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs)
3706 {
3707 	uint_t	msg = mtp ? mtp->mt_mtype : 0;
3708 	uint_t	token;
3709 
3710 	ASSERT(IDN_SYNC_IS_LOCKED());
3711 	ASSERT(IDN_DLOCK_IS_HELD(domid));
3712 
3713 	/*
3714 	 * Don't communicate with domains that
3715 	 * we're forcing a hard disconnect.
3716 	 */
3717 	if ((idn_domain[domid].dfin != IDNFIN_FORCE_HARD) &&
3718 			(msg & IDNP_MSGTYPE_MASK)) {
3719 		idn_msgtype_t	mt;
3720 		idn_xdcargs_t	nargs;
3721 
3722 		mt.mt_mtype = IDNP_NACK;
3723 		mt.mt_atype = msg;
3724 		mt.mt_cookie = mtp->mt_cookie;
3725 		CLR_XARGS(nargs);
3726 		SET_XARGS_NACK_TYPE(nargs, IDNNACK_RETRY);
3727 		idn_send_acknack(domid, &mt, nargs);
3728 	}
3729 
3730 	token = IDN_RETRY_TOKEN(domid, IDNRETRY_FIN);
3731 	idn_retry_submit(idn_retry_fin, NULL, token,
3732 			idn_msg_retrytime[(int)IDNRETRY_FIN]);
3733 }
3734 
3735 static void
3736 idn_action_fin_pend(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs)
3737 {
3738 	idn_domain_t	*dp = &idn_domain[domid];
3739 	domainset_t	my_ready_set;
3740 	idn_finopt_t	finopt;
3741 	idn_finarg_t	finarg;
3742 	uint_t		finmaster;
3743 	int		new_masterid, new_cpuid = IDN_NIL_DCPU;
3744 	uint_t		msg = mtp ? mtp->mt_mtype : 0;
3745 	idn_msgtype_t	mt;
3746 
3747 	ASSERT(IDN_SYNC_IS_LOCKED());
3748 	ASSERT(IDN_DLOCK_IS_HELD(domid));
3749 
3750 	my_ready_set = dp->dsync.s_set_rdy |
3751 			idn.domset.ds_ready_off |
3752 			~idn.domset.ds_connected;
3753 
3754 	ASSERT(xargs[0] != (uint_t)IDNFIN_QUERY);
3755 
3756 	finarg = GET_XARGS_FIN_ARG(xargs);
3757 	finopt = DOMAIN_IN_SET(idn.domset.ds_relink, domid) ?
3758 			IDNFIN_OPT_RELINK : IDNFIN_OPT_UNLINK;
3759 
3760 	mt.mt_cookie = mtp ? mtp->mt_cookie : 0;
3761 
3762 	IDN_GLOCK_SHARED();
3763 	new_masterid = IDN_GET_NEW_MASTERID();
3764 	IDN_GUNLOCK();
3765 	if (new_masterid != IDN_NIL_DOMID)
3766 		new_cpuid = idn_domain[new_masterid].dcpu;
3767 	finmaster = MAKE_FIN_MASTER(new_masterid, new_cpuid);
3768 
3769 	if (dp->dfin == IDNFIN_FORCE_HARD) {
3770 		ASSERT(IDN_DLOCK_IS_EXCL(domid));
3771 
3772 		if (!msg) {
3773 			mt.mt_mtype = IDNP_FIN | IDNP_ACK;
3774 			mt.mt_atype = 0;
3775 		} else {
3776 			mt.mt_mtype = IDNP_ACK;
3777 			mt.mt_atype = IDNP_FIN | IDNP_ACK;
3778 		}
3779 		idn_xphase_transition(domid, &mt, xargs);
3780 	} else if (!msg) {
3781 		idn_send_fin(domid, NULL, dp->dfin, finarg,
3782 				finopt, my_ready_set, finmaster);
3783 	} else if ((msg & IDNP_ACKNACK_MASK) == 0) {
3784 		/*
3785 		 * fin
3786 		 */
3787 		mt.mt_mtype = IDNP_FIN | IDNP_ACK;
3788 		mt.mt_atype = 0;
3789 		idn_send_fin(domid, &mt, dp->dfin, finarg,
3790 				finopt, my_ready_set, finmaster);
3791 	} else {
3792 		uint_t	token;
3793 		/*
3794 		 * nack - retry
3795 		 */
3796 		token = IDN_RETRY_TOKEN(domid, IDNRETRY_FIN);
3797 		idn_retry_submit(idn_retry_fin, NULL, token,
3798 				idn_msg_retrytime[(int)IDNRETRY_FIN]);
3799 	}
3800 }
3801 
3802 static int
3803 idn_check_fin_sent(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs)
3804 {
3805 	int		ready;
3806 	uint_t		msg = mtp ? mtp->mt_mtype : 0;
3807 	idn_fin_t	fintype;
3808 	idn_finopt_t	finopt;
3809 	idn_domain_t	*dp = &idn_domain[domid];
3810 	domainset_t	query_set, ready_set;
3811 
3812 	ASSERT(IDN_SYNC_IS_LOCKED());
3813 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
3814 
3815 	if (msg & IDNP_NACK)
3816 		return (0);
3817 
3818 	fintype   = GET_XARGS_FIN_TYPE(xargs);
3819 	ready_set = GET_XARGS_FIN_DOMSET(xargs);
3820 	finopt    = GET_XARGS_FIN_OPT(xargs);
3821 
3822 	ASSERT(fintype != IDNFIN_QUERY);
3823 	if (!VALID_FIN(fintype)) {
3824 		/*
3825 		 * If for some reason remote domain
3826 		 * sent us an invalid FIN type,
3827 		 * override it to a  NORMAL fin.
3828 		 */
3829 		fintype = IDNFIN_NORMAL;
3830 	}
3831 
3832 	if (!VALID_FINOPT(finopt)) {
3833 		finopt = IDNFIN_OPT_UNLINK;
3834 	}
3835 	IDN_GLOCK_SHARED();
3836 	if ((finopt == IDNFIN_OPT_RELINK) && (idn.state != IDNGS_DISCONNECT)) {
3837 		DOMAINSET_ADD(idn.domset.ds_relink, domid);
3838 		IDN_HISTORY_LOG(IDNH_RELINK, domid, dp->dstate,
3839 					idn.domset.ds_relink);
3840 	} else {
3841 		DOMAINSET_DEL(idn.domset.ds_relink, domid);
3842 	}
3843 	IDN_GUNLOCK();
3844 
3845 	switch (dp->dfin) {
3846 	case IDNFIN_NORMAL:
3847 	case IDNFIN_FORCE_SOFT:
3848 	case IDNFIN_FORCE_HARD:
3849 		if (fintype < dp->dfin) {
3850 			/*
3851 			 * Remote domain has requested a
3852 			 * FIN of lower priority than what
3853 			 * we're current running.  Just
3854 			 * leave the priority where it is.
3855 			 */
3856 			break;
3857 		}
3858 		/*FALLTHROUGH*/
3859 
3860 	default:
3861 		IDN_FSTATE_TRANSITION(dp, fintype);
3862 		break;
3863 	}
3864 
3865 	if (dp->dfin == IDNFIN_FORCE_HARD) {
3866 		/*
3867 		 * If we're doing a hard disconnect
3868 		 * of this domain then we want to
3869 		 * blow straight through and not
3870 		 * waste time trying to talk to the
3871 		 * remote domain.  By registering him
3872 		 * as ready with respect to all
3873 		 * possible domains he'll transition
3874 		 * immediately.  Note that we'll still
3875 		 * try and do it coherently with
3876 		 * other domains to which we're connected.
3877 		 */
3878 		ready_set = DOMAINSET_ALL;
3879 	} else {
3880 		DOMAINSET_ADD(ready_set, idn.localid);
3881 	}
3882 
3883 	DOMAINSET_ADD(idn.domset.ds_ready_off, domid);
3884 
3885 	query_set = idn_sync_register(domid, IDNSYNC_DISCONNECT,
3886 					ready_set, IDNSYNC_REG_REG);
3887 	/*
3888 	 * No need to query this domain as he's already
3889 	 * in the FIN sequence.
3890 	 */
3891 	DOMAINSET_DEL(query_set, domid);
3892 
3893 	ready = (dp->dsync.s_set_exp == dp->dsync.s_set_rdy) ? 1 : 0;
3894 	if (ready) {
3895 		DOMAINSET_DEL(idn.domset.ds_ready_off, domid);
3896 		DOMAINSET_DEL(idn.domset.ds_connected, domid);
3897 	}
3898 
3899 	if (query_set) {
3900 		int		d;
3901 		domainset_t	my_ready_set;
3902 
3903 		my_ready_set = idn.domset.ds_ready_off |
3904 				~idn.domset.ds_connected;
3905 
3906 		for (d = 0; d < MAX_DOMAINS; d++) {
3907 			if (!DOMAIN_IN_SET(query_set, d))
3908 				continue;
3909 
3910 			dp = &idn_domain[d];
3911 
3912 			IDN_DLOCK_EXCL(d);
3913 
3914 			if (dp->dsync.s_cmd == IDNSYNC_DISCONNECT) {
3915 				IDN_DUNLOCK(d);
3916 				continue;
3917 			}
3918 
3919 			IDN_SYNC_QUERY_UPDATE(domid, d);
3920 
3921 			idn_send_fin(d, NULL, IDNFIN_QUERY, IDNFIN_ARG_NONE,
3922 					IDNFIN_OPT_NONE, my_ready_set,
3923 					NIL_FIN_MASTER);
3924 			IDN_DUNLOCK(d);
3925 		}
3926 	}
3927 
3928 	return ((ready > 0) ? 0 : 1);
3929 }
3930 
3931 /*ARGSUSED*/
3932 static void
3933 idn_error_fin_sent(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs)
3934 {
3935 	uint_t	msg = mtp ? mtp->mt_mtype : 0;
3936 	uint_t	token;
3937 
3938 	ASSERT(IDN_SYNC_IS_LOCKED());
3939 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
3940 
3941 	/*
3942 	 * Don't communicate with domains that
3943 	 * we're forcing a hard disconnect.
3944 	 */
3945 	if ((idn_domain[domid].dfin != IDNFIN_FORCE_HARD) &&
3946 			(msg & IDNP_MSGTYPE_MASK)) {
3947 		idn_msgtype_t	mt;
3948 		idn_xdcargs_t	nargs;
3949 
3950 		mt.mt_mtype = IDNP_NACK;
3951 		mt.mt_atype = msg;
3952 		mt.mt_cookie = mtp->mt_cookie;
3953 		CLR_XARGS(nargs);
3954 		SET_XARGS_NACK_TYPE(nargs, IDNNACK_RETRY);
3955 		idn_send_acknack(domid, &mt, nargs);
3956 	}
3957 
3958 	token = IDN_RETRY_TOKEN(domid, IDNRETRY_FIN);
3959 	idn_retry_submit(idn_retry_fin, NULL, token,
3960 			idn_msg_retrytime[(int)IDNRETRY_FIN]);
3961 }
3962 
3963 static void
3964 idn_action_fin_sent(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs)
3965 {
3966 	uint_t		msg = mtp ? mtp->mt_mtype : 0;
3967 	int		new_masterid, new_cpuid = IDN_NIL_DCPU;
3968 	uint_t		finmaster;
3969 	idn_msgtype_t	mt;
3970 	idn_finopt_t	finopt;
3971 	idn_finarg_t	finarg;
3972 	domainset_t	my_ready_set;
3973 	idn_domain_t	*dp = &idn_domain[domid];
3974 
3975 	ASSERT(IDN_SYNC_IS_LOCKED());
3976 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
3977 
3978 	mt.mt_cookie = mtp ? mtp->mt_cookie : 0;
3979 
3980 	finopt = DOMAIN_IN_SET(idn.domset.ds_relink, domid) ?
3981 				IDNFIN_OPT_RELINK : IDNFIN_OPT_UNLINK;
3982 
3983 	finarg = GET_XARGS_FIN_ARG(xargs);
3984 
3985 	my_ready_set = dp->dsync.s_set_rdy |
3986 				idn.domset.ds_ready_off |
3987 				~idn.domset.ds_connected;
3988 
3989 	IDN_GLOCK_SHARED();
3990 	new_masterid = IDN_GET_NEW_MASTERID();
3991 	IDN_GUNLOCK();
3992 	if (new_masterid != IDN_NIL_DOMID)
3993 		new_cpuid = idn_domain[new_masterid].dcpu;
3994 	finmaster = MAKE_FIN_MASTER(new_masterid, new_cpuid);
3995 
3996 	if ((msg & IDNP_ACKNACK_MASK) == 0) {
3997 		/*
3998 		 * fin
3999 		 */
4000 		if (dp->dfin == IDNFIN_FORCE_HARD) {
4001 			mt.mt_mtype = IDNP_ACK;
4002 			mt.mt_atype = IDNP_FIN | IDNP_ACK;
4003 			idn_xphase_transition(domid, &mt, xargs);
4004 		} else {
4005 			mt.mt_mtype = IDNP_FIN | IDNP_ACK;
4006 			mt.mt_atype = 0;
4007 			idn_send_fin(domid, &mt, dp->dfin, finarg,
4008 					finopt, my_ready_set, finmaster);
4009 		}
4010 	} else if (msg & IDNP_MSGTYPE_MASK) {
4011 		/*
4012 		 * fin+ack
4013 		 */
4014 		if (dp->dfin != IDNFIN_FORCE_HARD) {
4015 			idn_xdcargs_t	fargs;
4016 
4017 			mt.mt_mtype = IDNP_ACK;
4018 			mt.mt_atype = msg;
4019 			CLR_XARGS(fargs);
4020 			SET_XARGS_FIN_TYPE(fargs, dp->dfin);
4021 			SET_XARGS_FIN_ARG(fargs, finarg);
4022 			SET_XARGS_FIN_DOMSET(fargs, my_ready_set);
4023 			SET_XARGS_FIN_OPT(fargs, finopt);
4024 			SET_XARGS_FIN_MASTER(fargs, finmaster);
4025 			idn_send_acknack(domid, &mt, fargs);
4026 		}
4027 	} else {
4028 		uint_t	token;
4029 		/*
4030 		 * nack - retry
4031 		 */
4032 		token = IDN_RETRY_TOKEN(domid, IDNRETRY_FIN);
4033 		idn_retry_submit(idn_retry_fin, NULL, token,
4034 				idn_msg_retrytime[(int)IDNRETRY_FIN]);
4035 	}
4036 }
4037 
4038 /*ARGSUSED*/
4039 static void
4040 idn_action_fin_rcvd(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs)
4041 {
4042 	uint_t	msg = mtp ? mtp->mt_mtype : 0;
4043 
4044 	ASSERT(IDN_SYNC_IS_LOCKED());
4045 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
4046 
4047 	if (msg & IDNP_NACK) {
4048 		uint_t	token;
4049 		/*
4050 		 * nack - retry.
4051 		 */
4052 		token = IDN_RETRY_TOKEN(domid, IDNRETRY_FIN);
4053 		idn_retry_submit(idn_retry_fin, NULL, token,
4054 				idn_msg_retrytime[(int)IDNRETRY_FIN]);
4055 	}
4056 }
4057 
4058 static void
4059 idn_final_fin(int domid)
4060 {
4061 	int		do_relink;
4062 	int		rv, d, new_masterid = IDN_NIL_DOMID;
4063 	idn_gstate_t	next_gstate;
4064 	domainset_t	relinkset;
4065 	uint_t		token = IDN_RETRY_TOKEN(domid, IDNRETRY_FIN);
4066 	idn_domain_t	*ldp, *dp = &idn_domain[domid];
4067 	procname_t	proc = "idn_final_fin";
4068 
4069 	ASSERT(IDN_SYNC_IS_LOCKED());
4070 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
4071 	ASSERT(dp->dstate == IDNDS_DMAP);
4072 
4073 	(void) idn_retry_terminate(token);
4074 
4075 	dp->dxp = NULL;
4076 	IDN_XSTATE_TRANSITION(dp, IDNXS_NIL);
4077 
4078 	idn_sync_exit(domid, IDNSYNC_DISCONNECT);
4079 
4080 	DOMAINSET_DEL(idn.domset.ds_trans_off, domid);
4081 
4082 	do_relink = DOMAIN_IN_SET(idn.domset.ds_relink, domid) ? 1 : 0;
4083 
4084 	/*
4085 	 * idn_deconfig will idn_close_domain.
4086 	 */
4087 	idn_deconfig(domid);
4088 
4089 	PR_PROTO("%s:%d: DISCONNECTED\n", proc, domid);
4090 
4091 	IDN_GLOCK_EXCL();
4092 	/*
4093 	 * It's important that this update-op occur within
4094 	 * the context of holding the glock(EXCL).  There is
4095 	 * still some additional state stuff to cleanup which
4096 	 * will be completed once the glock is dropped in
4097 	 * this flow.  Which means anybody that's doing a
4098 	 * SSI_INFO and waiting on glock will not actually
4099 	 * run until the clean-up is completed, which is what
4100 	 * we want.  Recall that a separate thread processes
4101 	 * the SSI_LINK/UNLINK calls and when they complete
4102 	 * (i.e. are awakened) they will immediately SSI_INFO
4103 	 * and we don't want them to prematurely pick up stale
4104 	 * information.
4105 	 */
4106 	idn_update_op(IDNOP_DISCONNECTED, DOMAINSET(domid), NULL);
4107 
4108 	ASSERT(idn.state != IDNGS_OFFLINE);
4109 	ASSERT(!DOMAIN_IN_SET(idn.domset.ds_trans_on, domid));
4110 
4111 	if (domid == IDN_GET_MASTERID()) {
4112 		IDN_SET_MASTERID(IDN_NIL_DOMID);
4113 		dp->dvote.v.master = 0;
4114 	}
4115 
4116 	if ((domid == IDN_GET_NEW_MASTERID()) && !do_relink) {
4117 		IDN_SET_NEW_MASTERID(IDN_NIL_DOMID);
4118 	}
4119 
4120 	if (idn.state == IDNGS_RECONFIG)
4121 		new_masterid = IDN_GET_NEW_MASTERID();
4122 
4123 	if ((idn.domset.ds_trans_on |
4124 			idn.domset.ds_trans_off |
4125 			idn.domset.ds_relink) == 0) {
4126 		PR_HITLIST("%s:%d: HITLIST %x -> 0\n",
4127 			proc, domid, idn.domset.ds_hitlist);
4128 		idn.domset.ds_hitlist = 0;
4129 	}
4130 
4131 	if (idn.domset.ds_connected || idn.domset.ds_trans_off) {
4132 		PR_PROTO("%s:%d: ds_connected = 0x%x, ds_trans_off = 0x%x\n",
4133 			proc, domid, idn.domset.ds_connected,
4134 			idn.domset.ds_trans_off);
4135 		IDN_GUNLOCK();
4136 		goto fin_done;
4137 	}
4138 
4139 	IDN_DLOCK_EXCL(idn.localid);
4140 	ldp = &idn_domain[idn.localid];
4141 
4142 	if (idn.domset.ds_trans_on != 0) {
4143 		ASSERT((idn.state != IDNGS_DISCONNECT) &&
4144 			(idn.state != IDNGS_OFFLINE));
4145 
4146 		switch (idn.state) {
4147 		case IDNGS_CONNECT:
4148 			if (idn.localid == IDN_GET_MASTERID()) {
4149 				idn_master_deinit();
4150 				IDN_SET_MASTERID(IDN_NIL_DOMID);
4151 				ldp->dvote.v.master = 0;
4152 			}
4153 			/*FALLTHROUGH*/
4154 		case IDNGS_ONLINE:
4155 			next_gstate = idn.state;
4156 			break;
4157 
4158 		case IDNGS_RECONFIG:
4159 			if (idn.localid == IDN_GET_MASTERID()) {
4160 				idn_master_deinit();
4161 				IDN_SET_MASTERID(IDN_NIL_DOMID);
4162 				ldp->dvote.v.master = 0;
4163 			}
4164 			ASSERT(IDN_GET_MASTERID() == IDN_NIL_DOMID);
4165 			next_gstate = IDNGS_CONNECT;
4166 			ldp->dvote.v.connected = 0;
4167 			/*
4168 			 * Need to do HWINIT since we won't
4169 			 * be transitioning through OFFLINE
4170 			 * which would normally be caught in
4171 			 * idn_check_nego() when we
4172 			 * initially go to CONNECT.
4173 			 */
4174 			IDN_PREP_HWINIT();
4175 			break;
4176 
4177 		case IDNGS_DISCONNECT:
4178 		case IDNGS_OFFLINE:
4179 			cmn_err(CE_WARN,
4180 				"IDN: 211: disconnect domain %d, "
4181 				"unexpected Gstate (%s)",
4182 				domid, idngs_str[idn.state]);
4183 			IDN_DUNLOCK(idn.localid);
4184 			IDN_GUNLOCK();
4185 			goto fin_done;
4186 
4187 		default:
4188 			/*
4189 			 * XXX
4190 			 * Go into FATAL state?
4191 			 */
4192 			cmn_err(CE_PANIC,
4193 				"IDN: 212: disconnect domain %d, "
4194 				"bad Gstate (%d)",
4195 				domid, idn.state);
4196 			/* not reached */
4197 			break;
4198 		}
4199 	} else {
4200 		if (idn.localid == IDN_GET_MASTERID()) {
4201 			idn_master_deinit();
4202 			IDN_SET_MASTERID(IDN_NIL_DOMID);
4203 			ldp->dvote.v.master = 0;
4204 		}
4205 		next_gstate = IDNGS_OFFLINE;
4206 		if (idn.domset.ds_relink == 0) {
4207 			IDN_SET_NEW_MASTERID(IDN_NIL_DOMID);
4208 		}
4209 	}
4210 	IDN_DUNLOCK(idn.localid);
4211 
4212 	/*
4213 	 * If we reach here we've effectively disconnected all
4214 	 * existing links, however new ones may be pending.
4215 	 */
4216 	PR_PROTO("%s:%d: ALL DISCONNECTED *****************\n", proc, domid);
4217 
4218 	IDN_GSTATE_TRANSITION(next_gstate);
4219 
4220 	ASSERT((idn.state == IDNGS_OFFLINE) ?
4221 		(IDN_GET_MASTERID() == IDN_NIL_DOMID) : 1);
4222 
4223 	IDN_GUNLOCK();
4224 
4225 	/*
4226 	 * If we have no new masterid and yet there are relinkers
4227 	 * out there, then force us to attempt to link with one
4228 	 * of them.
4229 	 */
4230 	if ((new_masterid == IDN_NIL_DOMID) && idn.domset.ds_relink)
4231 		new_masterid = idn.localid;
4232 
4233 	if (new_masterid != IDN_NIL_DOMID) {
4234 		/*
4235 		 * If the local domain is the selected
4236 		 * master then we'll want to initiate
4237 		 * a link with one of the other candidates.
4238 		 * If not, then we want to initiate a link
4239 		 * with the master only.
4240 		 */
4241 		relinkset = (new_masterid == idn.localid) ?
4242 				idn.domset.ds_relink : DOMAINSET(new_masterid);
4243 
4244 		DOMAINSET_DEL(relinkset, idn.localid);
4245 
4246 		for (d = 0; d < MAX_DOMAINS; d++) {
4247 			int	lock_held;
4248 
4249 			if (!DOMAIN_IN_SET(relinkset, d))
4250 				continue;
4251 
4252 			if (d == domid) {
4253 				do_relink = 0;
4254 				lock_held = 0;
4255 			} else {
4256 				IDN_DLOCK_EXCL(d);
4257 				lock_held = 1;
4258 			}
4259 
4260 			rv = idn_open_domain(d, -1, 0);
4261 			if (rv == 0) {
4262 				rv = idn_connect(d);
4263 				if (lock_held)
4264 					IDN_DUNLOCK(d);
4265 				/*
4266 				 * If we're able to kick off at
4267 				 * least one connect then that's
4268 				 * good enough for now.  The others
4269 				 * will fall into place normally.
4270 				 */
4271 				if (rv == 0)
4272 					break;
4273 			} else if (rv < 0) {
4274 				if (lock_held)
4275 					IDN_DUNLOCK(d);
4276 				cmn_err(CE_WARN,
4277 					"IDN: 205: (%s.1) failed to "
4278 					"open-domain(%d,%d)",
4279 					proc, domid, -1);
4280 				DOMAINSET_DEL(idn.domset.ds_relink, d);
4281 			} else {
4282 				if (lock_held)
4283 					IDN_DUNLOCK(d);
4284 				PR_PROTO("%s:%d: failed to "
4285 					"re-open domain %d "
4286 					"(cpu %d) [rv = %d]\n",
4287 					proc, domid, d, idn_domain[d].dcpu,
4288 					rv);
4289 			}
4290 		}
4291 	}
4292 
4293 fin_done:
4294 	if (do_relink) {
4295 		ASSERT(IDN_DLOCK_IS_EXCL(domid));
4296 
4297 		rv = idn_open_domain(domid, -1, 0);
4298 		if (rv == 0) {
4299 			(void) idn_connect(domid);
4300 		} else if (rv < 0) {
4301 			cmn_err(CE_WARN,
4302 				"IDN: 205: (%s.2) failed to "
4303 				"open-domain(%d,%d)",
4304 				proc, domid, -1);
4305 			DOMAINSET_DEL(idn.domset.ds_relink, domid);
4306 		}
4307 	}
4308 }
4309 
4310 static void
4311 idn_exit_fin(int domid, uint_t msgtype)
4312 {
4313 	idn_domain_t	*dp = &idn_domain[domid];
4314 	uint_t		token;
4315 	procname_t	proc = "idn_exit_fin";
4316 	STRING(str);
4317 
4318 	ASSERT(IDN_SYNC_IS_LOCKED());
4319 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
4320 
4321 	INUM2STR(msgtype, str);
4322 	PR_PROTO("%s:%d: msgtype = 0x%x(%s)\n", proc, domid, msgtype, str);
4323 
4324 	token = IDN_RETRY_TOKEN(domid, IDNRETRY_FIN);
4325 	(void) idn_retry_terminate(token);
4326 
4327 	DOMAINSET_DEL(idn.domset.ds_ready_off, domid);
4328 
4329 	dp->dxp = &xphase_fin;
4330 	IDN_XSTATE_TRANSITION(dp, IDNXS_PEND);
4331 
4332 	idn_retry_submit(idn_retry_fin, NULL, token,
4333 			idn_msg_retrytime[(int)IDNRETRY_FIN]);
4334 }
4335 
4336 /*
4337  * Must return w/locks held.
4338  */
4339 static int
4340 idn_xphase_transition(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs)
4341 {
4342 	uint_t		msg = mtp ? mtp->mt_mtype : 0;
4343 	uint_t		msgarg = mtp ? mtp->mt_atype : 0;
4344 	idn_xphase_t	*xp;
4345 	idn_domain_t	*dp;
4346 	int		(*cfunc)(int, idn_msgtype_t *, idn_xdcargs_t);
4347 	void		(*ffunc)(int);
4348 	void		(*afunc)(int, idn_msgtype_t *, idn_xdcargs_t);
4349 	void		(*efunc)(int, idn_msgtype_t *, idn_xdcargs_t);
4350 	void		(*xfunc)(int, uint_t);
4351 	int		err = 0;
4352 	uint_t		msgtype;
4353 	idn_xstate_t	o_xstate, n_xstate;
4354 	procname_t	proc = "idn_xphase_transition";
4355 	STRING(mstr);
4356 	STRING(astr);
4357 
4358 	ASSERT(IDN_SYNC_IS_LOCKED());
4359 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
4360 
4361 	INUM2STR(msg, mstr);
4362 	INUM2STR(msgarg, astr);
4363 
4364 	dp = &idn_domain[domid];
4365 	if ((xp = dp->dxp) == NULL) {
4366 		PR_PROTO("%s:%d: WARNING: domain xsp is NULL (msg = %s, "
4367 			"msgarg = %s) <<<<<<<<<<<<\n",
4368 			proc, domid, mstr, astr);
4369 		return (-1);
4370 	}
4371 	o_xstate = dp->dxstate;
4372 
4373 	xfunc = xp->xt_exit;
4374 
4375 	if ((msgtype = (msg & IDNP_MSGTYPE_MASK)) == 0)
4376 		msgtype = msgarg & IDNP_MSGTYPE_MASK;
4377 
4378 	if ((o_xstate == IDNXS_PEND) && msg &&
4379 			((msg & IDNP_ACKNACK_MASK) == msg)) {
4380 		PR_PROTO("%s:%d: unwanted acknack received (o_xstate = %s, "
4381 			"msg = %s/%s - dropping message\n",
4382 			proc, domid, idnxs_str[(int)o_xstate], mstr, astr);
4383 		return (0);
4384 	}
4385 
4386 	/*
4387 	 * Validate that message received is following
4388 	 * the expected protocol for the current state.
4389 	 */
4390 	if (idn_next_xstate(o_xstate, -1, msg) == IDNXS_NIL) {
4391 		PR_PROTO("%s:%d: WARNING: o_xstate = %s, msg = %s -> NIL "
4392 			"<<<<<<<<<\n",
4393 			proc, domid, idnxs_str[(int)o_xstate], mstr);
4394 		if (xfunc)
4395 			(*xfunc)(domid, msgtype);
4396 		return (-1);
4397 	}
4398 
4399 	if (msg || msgarg) {
4400 		/*
4401 		 * Verify that message type is correct for
4402 		 * the given xstate.
4403 		 */
4404 		if (msgtype != xp->xt_msgtype) {
4405 			STRING(xstr);
4406 			STRING(tstr);
4407 
4408 			INUM2STR(xp->xt_msgtype, xstr);
4409 			INUM2STR(msgtype, tstr);
4410 			PR_PROTO("%s:%d: WARNING: msg expected %s(0x%x), "
4411 				"actual %s(0x%x) [msg=%s(0x%x), "
4412 				"msgarg=%s(0x%x)]\n",
4413 				proc, domid, xstr, xp->xt_msgtype,
4414 				tstr, msgtype, mstr, msg, astr, msgarg);
4415 			if (xfunc)
4416 				(*xfunc)(domid, msgtype);
4417 			return (-1);
4418 		}
4419 	}
4420 
4421 	cfunc = xp->xt_trans[(int)o_xstate].t_check;
4422 
4423 	if (cfunc && ((err = (*cfunc)(domid, mtp, xargs)) < 0)) {
4424 		if (o_xstate != IDNXS_PEND) {
4425 			IDN_XSTATE_TRANSITION(dp, IDNXS_PEND);
4426 		}
4427 		if (xfunc)
4428 			(*xfunc)(domid, msgtype);
4429 		return (-1);
4430 	}
4431 
4432 	n_xstate = idn_next_xstate(o_xstate, err, msg);
4433 
4434 	if (n_xstate == IDNXS_NIL) {
4435 		PR_PROTO("%s:%d: WARNING: n_xstate = %s, msg = %s -> NIL "
4436 			"<<<<<<<<<\n",
4437 			proc, domid, idnxs_str[(int)n_xstate], mstr);
4438 		if (xfunc)
4439 			(*xfunc)(domid, msgtype);
4440 		return (-1);
4441 	}
4442 
4443 	if (n_xstate != o_xstate) {
4444 		IDN_XSTATE_TRANSITION(dp, n_xstate);
4445 	}
4446 
4447 	if (err) {
4448 		if ((efunc = xp->xt_trans[(int)o_xstate].t_error) != NULL)
4449 			(*efunc)(domid, mtp, xargs);
4450 	} else if ((afunc = xp->xt_trans[(int)o_xstate].t_action) != NULL) {
4451 		(*afunc)(domid, mtp, xargs);
4452 	}
4453 
4454 	if ((n_xstate == IDNXS_FINAL) && ((ffunc = xp->xt_final) != NULL))
4455 		(*ffunc)(domid);
4456 
4457 	return (0);
4458 }
4459 
4460 /*
4461  * Entered and returns w/DLOCK & SYNC_LOCK held.
4462  */
4463 static int
4464 idn_xstate_transfunc(int domid, void *transarg)
4465 {
4466 	uint_t		msg = (uint_t)(uintptr_t)transarg;
4467 	uint_t		token;
4468 	procname_t	proc = "idn_xstate_transfunc";
4469 
4470 	ASSERT(IDN_SYNC_IS_LOCKED());
4471 
4472 	switch (msg) {
4473 	case IDNP_CON:
4474 		DOMAINSET_ADD(idn.domset.ds_connected, domid);
4475 		break;
4476 
4477 	case IDNP_FIN:
4478 		DOMAINSET_DEL(idn.domset.ds_connected, domid);
4479 		break;
4480 
4481 	default:
4482 		PR_PROTO("%s:%d: ERROR: unknown msg (0x%x) <<<<<<<<\n",
4483 			proc, domid, msg);
4484 		return (0);
4485 	}
4486 
4487 	token = IDN_RETRY_TOKEN(domid, (msg == IDNP_CON) ?
4488 					IDNRETRY_CON : IDNRETRY_FIN);
4489 	if (msg == IDNP_CON)
4490 		idn_retry_submit(idn_retry_con, NULL, token,
4491 			idn_msg_retrytime[(int)IDNRETRY_CON]);
4492 	else
4493 		idn_retry_submit(idn_retry_fin, NULL, token,
4494 			idn_msg_retrytime[(int)IDNRETRY_FIN]);
4495 
4496 	return (1);
4497 }
4498 
4499 /*
4500  * Entered and returns w/DLOCK & SYNC_LOCK held.
4501  */
4502 static void
4503 idn_sync_enter(int domid, idn_synccmd_t cmd,
4504 	domainset_t xset, domainset_t rset,
4505 	int (*transfunc)(), void *transarg)
4506 {
4507 	int		z;
4508 	idn_syncop_t	*sp;
4509 	idn_synczone_t	*zp;
4510 	procname_t	proc = "idn_sync_enter";
4511 
4512 	ASSERT(IDN_SYNC_IS_LOCKED());
4513 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
4514 
4515 	z = IDN_SYNC_GETZONE(cmd);
4516 	ASSERT(z >= 0);
4517 	zp = &idn.sync.sz_zone[z];
4518 
4519 	PR_SYNC("%s:%d: cmd=%s(%d), z=%d, xs=0x%x, rx=0x%x, cnt=%d\n",
4520 		proc, domid, idnsync_str[cmd], cmd, z, xset, rset, zp->sc_cnt);
4521 
4522 	sp = &idn_domain[domid].dsync;
4523 
4524 	sp->s_domid = domid;
4525 	sp->s_cmd = cmd;
4526 	sp->s_msg = 0;
4527 	sp->s_set_exp = xset;
4528 	sp->s_set_rdy = rset;
4529 	sp->s_transfunc = transfunc;
4530 	sp->s_transarg = transarg;
4531 	IDN_SYNC_QUERY_INIT(domid);
4532 
4533 	sp->s_next = zp->sc_op;
4534 	zp->sc_op = sp;
4535 	zp->sc_cnt++;
4536 }
4537 
4538 /*
4539  * Entered and returns w/DLOCK & SYNC_LOCK held.
4540  */
4541 void
4542 idn_sync_exit(int domid, idn_synccmd_t cmd)
4543 {
4544 	int		d, z, zone, tot_queries, tot_domains;
4545 	idn_syncop_t	*sp;
4546 	idn_synczone_t	*zp = NULL;
4547 	procname_t	proc = "idn_sync_exit";
4548 
4549 	ASSERT(IDN_SYNC_IS_LOCKED());
4550 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
4551 
4552 	sp = &idn_domain[domid].dsync;
4553 
4554 	z = IDN_SYNC_GETZONE(sp->s_cmd);
4555 
4556 	zone = IDN_SYNC_GETZONE(cmd);
4557 
4558 	PR_SYNC("%s:%d: cmd=%s(%d) (z=%d, zone=%d)\n",
4559 		proc, domid, idnsync_str[cmd], cmd, z, zone);
4560 
4561 #ifdef DEBUG
4562 	if (z != -1) {
4563 		tot_queries = tot_domains = 0;
4564 
4565 		for (d = 0; d < MAX_DOMAINS; d++) {
4566 			int	qv;
4567 
4568 			if ((qv = sp->s_query[d]) > 0) {
4569 				tot_queries += qv;
4570 				tot_domains++;
4571 				PR_SYNC("%s:%d: query_count = %d\n",
4572 					proc, domid, qv);
4573 			}
4574 		}
4575 		PR_SYNC("%s:%d: tot_queries = %d, tot_domaines = %d\n",
4576 			proc, domid, tot_queries, tot_domains);
4577 	}
4578 #endif /* DEBUG */
4579 
4580 	zp = (z != -1) ? &idn.sync.sz_zone[z] : NULL;
4581 
4582 	if (zp) {
4583 		idn_syncop_t	**spp;
4584 
4585 		for (spp = &zp->sc_op; *spp; spp = &((*spp)->s_next)) {
4586 			if (*spp == sp) {
4587 				*spp = sp->s_next;
4588 				sp->s_next = NULL;
4589 				zp->sc_cnt--;
4590 				break;
4591 			}
4592 		}
4593 	}
4594 
4595 	sp->s_cmd = IDNSYNC_NIL;
4596 
4597 	for (z = 0; z < IDN_SYNC_NUMZONE; z++) {
4598 		idn_syncop_t	**spp, **nspp;
4599 
4600 		if ((zone != -1) && (z != zone))
4601 			continue;
4602 
4603 		zp = &idn.sync.sz_zone[z];
4604 
4605 		for (spp = &zp->sc_op; *spp; spp = nspp) {
4606 			sp = *spp;
4607 			nspp = &sp->s_next;
4608 
4609 			if (!DOMAIN_IN_SET(sp->s_set_exp, domid))
4610 				continue;
4611 
4612 			DOMAINSET_DEL(sp->s_set_exp, domid);
4613 			DOMAINSET_DEL(sp->s_set_rdy, domid);
4614 
4615 			if ((sp->s_set_exp == sp->s_set_rdy) &&
4616 					sp->s_transfunc) {
4617 				int	delok;
4618 
4619 				ASSERT(sp->s_domid != domid);
4620 
4621 				PR_SYNC("%s:%d invoking transfunc "
4622 					"for domain %d\n",
4623 					proc, domid, sp->s_domid);
4624 				delok = (*sp->s_transfunc)(sp->s_domid,
4625 							sp->s_transarg);
4626 				if (delok) {
4627 					*spp = sp->s_next;
4628 					sp->s_next = NULL;
4629 					zp->sc_cnt--;
4630 					nspp = spp;
4631 				}
4632 			}
4633 		}
4634 	}
4635 }
4636 
4637 /*
4638  * Entered and returns w/DLOCK & SYNC_LOCK held.
4639  */
4640 static domainset_t
4641 idn_sync_register(int domid, idn_synccmd_t cmd,
4642 		domainset_t ready_set, idn_syncreg_t regtype)
4643 {
4644 	int		z;
4645 	idn_synczone_t	*zp;
4646 	idn_syncop_t	*sp, **spp, **nspp;
4647 	domainset_t	query_set = 0, trans_set;
4648 	procname_t	proc = "idn_sync_register";
4649 
4650 	ASSERT(IDN_SYNC_IS_LOCKED());
4651 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
4652 
4653 	if ((z = IDN_SYNC_GETZONE(cmd)) == -1) {
4654 		PR_SYNC("%s:%d: ERROR: unexpected sync cmd(%d)\n",
4655 			proc, domid, cmd);
4656 		return (0);
4657 	}
4658 
4659 	/*
4660 	 * Find out what domains are in transition with respect
4661 	 * to given command.  There will be no need to query
4662 	 * these folks.
4663 	 */
4664 	trans_set = IDN_SYNC_GETTRANS(cmd);
4665 
4666 	zp = &idn.sync.sz_zone[z];
4667 
4668 	PR_SYNC("%s:%d: cmd=%s(%d), z=%d, rset=0x%x, "
4669 		"regtype=%s(%d), sc_op=%s\n",
4670 		proc, domid, idnsync_str[cmd], cmd, z, ready_set,
4671 		idnreg_str[regtype], regtype,
4672 		zp->sc_op ? idnsync_str[zp->sc_op->s_cmd] : "NULL");
4673 
4674 	for (spp = &zp->sc_op; *spp; spp = nspp) {
4675 		sp = *spp;
4676 		nspp = &sp->s_next;
4677 
4678 		if (regtype == IDNSYNC_REG_NEW) {
4679 			DOMAINSET_ADD(sp->s_set_exp, domid);
4680 			PR_SYNC("%s:%d: adding new to %d (exp=0x%x)\n",
4681 				proc, domid, sp->s_domid, sp->s_set_exp);
4682 		} else if (regtype == IDNSYNC_REG_QUERY) {
4683 			query_set |= ~sp->s_set_rdy & sp->s_set_exp;
4684 			continue;
4685 		}
4686 
4687 		if (!DOMAIN_IN_SET(sp->s_set_exp, domid))
4688 			continue;
4689 
4690 		if (!DOMAIN_IN_SET(ready_set, sp->s_domid)) {
4691 			/*
4692 			 * Given domid doesn't have a desired
4693 			 * domain in his ready-set.  We'll need
4694 			 * to query him again.
4695 			 */
4696 			DOMAINSET_ADD(query_set, domid);
4697 			continue;
4698 		}
4699 
4700 		/*
4701 		 * If we reach here, then an expected domain
4702 		 * has marked its respective datapath to
4703 		 * sp->s_domid as down (i.e. in his ready_set).
4704 		 */
4705 		DOMAINSET_ADD(sp->s_set_rdy, domid);
4706 
4707 		PR_SYNC("%s:%d: mark READY for domain %d "
4708 			"(r=0x%x, x=0x%x)\n",
4709 			proc, domid, sp->s_domid,
4710 			sp->s_set_rdy, sp->s_set_exp);
4711 
4712 		query_set |= ~sp->s_set_rdy & sp->s_set_exp;
4713 
4714 		if (sp->s_set_exp == sp->s_set_rdy) {
4715 #ifdef DEBUG
4716 			if (sp->s_msg == 0) {
4717 				sp->s_msg = 1;
4718 				PR_SYNC("%s:%d: >>>>>>>>>>> DOMAIN %d "
4719 					"ALL CHECKED IN (0x%x)\n",
4720 					proc, domid, sp->s_domid,
4721 					sp->s_set_exp);
4722 			}
4723 #endif /* DEBUG */
4724 
4725 			if ((sp->s_domid != domid) && sp->s_transfunc) {
4726 				int	delok;
4727 
4728 				PR_SYNC("%s:%d invoking transfunc "
4729 					"for domain %d\n",
4730 					proc, domid, sp->s_domid);
4731 				delok = (*sp->s_transfunc)(sp->s_domid,
4732 						sp->s_transarg);
4733 				if (delok) {
4734 					*spp = sp->s_next;
4735 					sp->s_next = NULL;
4736 					zp->sc_cnt--;
4737 					nspp = spp;
4738 				}
4739 			}
4740 		}
4741 	}
4742 
4743 	PR_SYNC("%s:%d: trans_set = 0x%x, query_set = 0x%x -> 0x%x\n",
4744 		proc, domid, trans_set, query_set, query_set & ~trans_set);
4745 
4746 	query_set &= ~trans_set;
4747 
4748 	return (query_set);
4749 }
4750 
4751 static void
4752 idn_sync_register_awol(int domid)
4753 {
4754 	int		z;
4755 	idn_synccmd_t	cmd = IDNSYNC_DISCONNECT;
4756 	idn_synczone_t	*zp;
4757 	idn_syncop_t	*sp;
4758 	procname_t	proc = "idn_sync_register_awol";
4759 
4760 	ASSERT(IDN_SYNC_IS_LOCKED());
4761 
4762 	if ((z = IDN_SYNC_GETZONE(cmd)) == -1) {
4763 		PR_SYNC("%s:%d: ERROR: unexpected sync cmd(%d)\n",
4764 			proc, domid, cmd);
4765 		return;
4766 	}
4767 
4768 	zp = &idn.sync.sz_zone[z];
4769 
4770 	PR_SYNC("%s:%d: cmd=%s(%d), z=%d (domain %d = AWOL)\n",
4771 		proc, domid, idnsync_str[cmd], cmd, z, domid);
4772 
4773 	for (sp = zp->sc_op; sp; sp = sp->s_next) {
4774 		idn_domain_t	*dp;
4775 
4776 		dp = &idn_domain[sp->s_domid];
4777 		if (dp->dfin == IDNFIN_FORCE_HARD) {
4778 			DOMAINSET_ADD(sp->s_set_rdy, domid);
4779 			PR_SYNC("%s:%d: adding new to %d (rdy=0x%x)\n",
4780 				proc, domid, sp->s_domid, sp->s_set_rdy);
4781 		}
4782 	}
4783 }
4784 
4785 static void
4786 idn_link_established(void *arg)
4787 {
4788 	int	first_link;
4789 	int	domid, masterid;
4790 	uint_t	info = (uint_t)(uintptr_t)arg;
4791 
4792 	first_link = (int)(info & 0xf0);
4793 	domid = (int)(info & 0x0f);
4794 
4795 	IDN_GLOCK_SHARED();
4796 	masterid = IDN_GET_MASTERID();
4797 	if ((masterid == IDN_NIL_DOMID) ||
4798 		(idn_domain[masterid].dstate != IDNDS_CONNECTED)) {
4799 		/*
4800 		 * No point in doing this unless we're connected
4801 		 * to the master.
4802 		 */
4803 		if ((masterid != IDN_NIL_DOMID) &&
4804 				(idn.state == IDNGS_ONLINE)) {
4805 			/*
4806 			 * As long as we're still online keep
4807 			 * trying.
4808 			 */
4809 			(void) timeout(idn_link_established, arg, 50);
4810 		}
4811 		IDN_GUNLOCK();
4812 		return;
4813 	}
4814 	IDN_GUNLOCK();
4815 
4816 	if (first_link && IDN_SLAB_PREALLOC)
4817 		idn_prealloc_slab(IDN_SLAB_PREALLOC);
4818 
4819 	/*
4820 	 * No guarantee, but it might save a little
4821 	 * time.
4822 	 */
4823 	if (idn_domain[domid].dstate == IDNDS_CONNECTED) {
4824 		/*
4825 		 * Get the remote domain's dname.
4826 		 */
4827 		idn_send_nodename_req(domid);
4828 	}
4829 
4830 	/*
4831 	 * May have had some streams backed up waiting for
4832 	 * this connection.  Prod them.
4833 	 */
4834 	rw_enter(&idn.struprwlock, RW_READER);
4835 	mutex_enter(&idn.sipwenlock);
4836 	idndl_wenable(NULL);
4837 	mutex_exit(&idn.sipwenlock);
4838 	rw_exit(&idn.struprwlock);
4839 }
4840 
4841 /*
4842  * Send the following chunk of data received from above onto
4843  * the IDN wire.  This is raw data as far as the IDN driver
4844  * is concerned.
4845  * Returns:
4846  *	IDNXMIT_LOOP	- Msg handled in loopback and thus
4847  *			  still active (i.e. don't free).
4848  *	IDNXMIT_OKAY	- Data handled (freemsg).
4849  *	IDNXMIT_DROP	- Packet should be dropped.
4850  *	IDNXMIT_RETRY	- Packet should be requeued and retried.
4851  *	IDNXMIT_REQUEUE	- Packet should be requeued, but not
4852  *			  immediatetly retried.
4853  */
4854 int
4855 idn_send_data(int dst_domid, idn_netaddr_t dst_netaddr,
4856 						queue_t *wq, mblk_t *mp)
4857 {
4858 	int		pktcnt = 0;
4859 	int		msglen;
4860 	int		rv = IDNXMIT_OKAY;
4861 	int		xfersize = 0;
4862 	caddr_t		iobufp, iodatap;
4863 	uchar_t		*data_rptr;
4864 	int		cpuindex;
4865 	int		serrno;
4866 	int		channel;
4867 	int		retry_reclaim;
4868 	idn_chansvr_t	*csp = NULL;
4869 	uint_t		netports = 0;
4870 	struct idnstr	*stp;
4871 	struct idn	*sip;
4872 	idn_domain_t	*dp;
4873 	struct ether_header	*ehp;
4874 	smr_pkthdr_t	*hdrp;
4875 	idn_msgtype_t	mt;
4876 	procname_t	proc = "idn_send_data";
4877 #ifdef DEBUG
4878 	size_t		orig_msglen = msgsize(mp);
4879 #endif /* DEBUG */
4880 
4881 	ASSERT(DB_TYPE(mp) == M_DATA);
4882 
4883 	mt.mt_mtype = IDNP_DATA;
4884 	mt.mt_atype = 0;
4885 	mt.mt_cookie = 0;
4886 
4887 	channel = (int)dst_netaddr.net.chan;
4888 
4889 	msglen = msgdsize(mp);
4890 	PR_DATA("%s:%d: (netaddr 0x%x) msgsize=%ld, msgdsize=%d\n",
4891 		proc, dst_domid, dst_netaddr.netaddr, msgsize(mp), msglen);
4892 
4893 	ASSERT(wq->q_ptr);
4894 
4895 	stp = (struct idnstr *)wq->q_ptr;
4896 	sip = stp->ss_sip;
4897 	ASSERT(sip);
4898 
4899 	if (msglen < 0) {
4900 		/*
4901 		 * No data to send.  That was easy!
4902 		 */
4903 		PR_DATA("%s:%d: BAD msg length (%d) (netaddr 0x%x)\n",
4904 			proc, dst_domid, msglen, dst_netaddr.netaddr);
4905 		return (IDNXMIT_DROP);
4906 	}
4907 
4908 	ASSERT(RW_READ_HELD(&stp->ss_rwlock));
4909 
4910 	if (dst_domid == IDN_NIL_DOMID) {
4911 		cmn_err(CE_WARN,
4912 			"IDN: 213: no destination specified "
4913 			"(d=%d, c=%d, n=0x%x)",
4914 			dst_domid, dst_netaddr.net.chan,
4915 			dst_netaddr.net.netid);
4916 		IDN_KSTAT_INC(sip, si_nolink);
4917 		IDN_KSTAT_INC(sip, si_macxmt_errors);
4918 		rv = IDNXMIT_DROP;
4919 		goto nocando;
4920 	}
4921 
4922 	ehp = (struct ether_header *)mp->b_rptr;
4923 	PR_DATA("%s:%d: destination channel = %d\n", proc, dst_domid, channel);
4924 
4925 #ifdef DEBUG
4926 	{
4927 		uchar_t	echn;
4928 
4929 		echn = (uchar_t)
4930 			ehp->ether_shost.ether_addr_octet[IDNETHER_CHANNEL];
4931 		ASSERT((uchar_t)channel == echn);
4932 	}
4933 #endif /* DEBUG */
4934 	ASSERT(msglen <= IDN_DATA_SIZE);
4935 
4936 	dp = &idn_domain[dst_domid];
4937 	/*
4938 	 * Get reader lock.  We hold for the duration
4939 	 * of the transfer so that our state doesn't
4940 	 * change during this activity.  Note that since
4941 	 * we grab the reader lock, we can still permit
4942 	 * simultaneous tranfers from different threads
4943 	 * to the same domain.
4944 	 * Before we waste a bunch of time gathering locks, etc.
4945 	 * do a an unprotected check to make sure things are
4946 	 * semi-copesetic.  If these values are in flux,
4947 	 * that's okay.
4948 	 */
4949 	if ((dp->dstate != IDNDS_CONNECTED) || (idn.state != IDNGS_ONLINE)) {
4950 		IDN_KSTAT_INC(sip, si_linkdown);
4951 		if (idn.state != IDNGS_ONLINE) {
4952 			rv = IDNXMIT_REQUEUE;
4953 		} else {
4954 			IDN_KSTAT_INC(sip, si_macxmt_errors);
4955 			rv = IDNXMIT_DROP;
4956 		}
4957 		goto nocando;
4958 	}
4959 
4960 	if (idn.chan_servers[channel].ch_send.c_checkin) {
4961 		/*
4962 		 * Gotta bail, somethin' s'up.
4963 		 */
4964 		rv = IDNXMIT_REQUEUE;
4965 		goto nocando;
4966 	}
4967 
4968 	csp = &idn.chan_servers[channel];
4969 	IDN_CHAN_LOCK_SEND(csp);
4970 
4971 	if (dst_netaddr.net.netid == IDN_BROADCAST_ALLNETID) {
4972 		/*
4973 		 * We're doing a broadcast.  Need to set
4974 		 * up IDN netaddr's one at a time.
4975 		 * We set the ethernet destination to the same
4976 		 * instance as the sending address.  The instance
4977 		 * numbers effectively represent subnets.
4978 		 */
4979 		dst_netaddr.net.netid = dp->dnetid;
4980 
4981 		(void) idndl_domain_etheraddr(dst_domid, channel,
4982 						&ehp->ether_dhost);
4983 
4984 		if (dst_domid == idn.localid) {
4985 			mblk_t	*nmp;
4986 			/*
4987 			 * If this is a broadcast and going to
4988 			 * the local domain, then we need to make
4989 			 * a private copy of the message since
4990 			 * the current one will be reused when
4991 			 * transmitting to other domains.
4992 			 */
4993 			PR_DATA("%s:%d: dup broadcast msg for local domain\n",
4994 				proc, dst_domid);
4995 			if ((nmp = copymsg(mp)) == NULL) {
4996 				/*
4997 				 * Couldn't get a duplicate copy.
4998 				 */
4999 				IDN_CHAN_UNLOCK_SEND(csp);
5000 				csp = NULL;
5001 				IDN_KSTAT_INC(sip, si_allocbfail);
5002 				IDN_KSTAT_INC(sip, si_noxmtbuf);
5003 				rv = IDNXMIT_DROP;
5004 				goto nocando;
5005 			}
5006 			mp = nmp;
5007 		}
5008 	}
5009 
5010 	if (dp->dnetid != dst_netaddr.net.netid) {
5011 		PR_DATA("%s:%d: dest netid (0x%x) != expected (0x%x)\n",
5012 			proc, dst_domid, (uint_t)dst_netaddr.net.netid,
5013 			(uint_t)dp->dnetid);
5014 		IDN_CHAN_UNLOCK_SEND(csp);
5015 		csp = NULL;
5016 		IDN_KSTAT_INC(sip, si_nolink);
5017 		IDN_KSTAT_INC(sip, si_macxmt_errors);
5018 		rv = IDNXMIT_DROP;
5019 		goto nocando;
5020 	}
5021 
5022 	if (dst_domid == idn.localid) {
5023 		int	lbrv;
5024 		/*
5025 		 * Sending to our local domain! Loopback.
5026 		 * Note that idn_send_data_loop returning 0
5027 		 * does not mean the message can now be freed.
5028 		 * We need to return (-1) so that caller doesn't
5029 		 * try to free mblk.
5030 		 */
5031 		IDN_CHAN_UNLOCK_SEND(csp);
5032 		rw_exit(&stp->ss_rwlock);
5033 		lbrv = idn_send_data_loopback(dst_netaddr, wq, mp);
5034 		rw_enter(&stp->ss_rwlock, RW_READER);
5035 		if (lbrv == 0) {
5036 			return (IDNXMIT_LOOP);
5037 		} else {
5038 			IDN_KSTAT_INC(sip, si_macxmt_errors);
5039 			return (IDNXMIT_DROP);
5040 		}
5041 	}
5042 
5043 	if (dp->dstate != IDNDS_CONNECTED) {
5044 		/*
5045 		 * Can't send data unless a link has already been
5046 		 * established with the target domain.  Normally,
5047 		 * a user cannot set the remote netaddr unless a
5048 		 * link has already been established, however it
5049 		 * is possible the connection may have become
5050 		 * disconnected since that time.
5051 		 */
5052 		IDN_CHAN_UNLOCK_SEND(csp);
5053 		csp = NULL;
5054 		IDN_KSTAT_INC(sip, si_linkdown);
5055 		IDN_KSTAT_INC(sip, si_macxmt_errors);
5056 		rv = IDNXMIT_DROP;
5057 		goto nocando;
5058 	}
5059 
5060 	/*
5061 	 * Need to make sure the channel is active and that the
5062 	 * domain to which we're sending is allowed to receive stuff.
5063 	 */
5064 	if (!IDN_CHANNEL_IS_SEND_ACTIVE(csp)) {
5065 		int	not_active;
5066 		/*
5067 		 * See if we can activate channel.
5068 		 */
5069 		IDN_CHAN_UNLOCK_SEND(csp);
5070 		not_active = idn_activate_channel(CHANSET(channel),
5071 							IDNCHAN_OPEN);
5072 		if (!not_active) {
5073 			/*
5074 			 * Only grab the lock for a recheck if we were
5075 			 * able to activate the channel.
5076 			 */
5077 			IDN_CHAN_LOCK_SEND(csp);
5078 		}
5079 		/*
5080 		 * Verify channel still active now that we have the lock.
5081 		 */
5082 		if (not_active || !IDN_CHANNEL_IS_SEND_ACTIVE(csp)) {
5083 			if (!not_active) {
5084 				/*
5085 				 * Only need to drop the lock if it was
5086 				 * acquired while we thought we had
5087 				 * activated the channel.
5088 				 */
5089 				IDN_CHAN_UNLOCK_SEND(csp);
5090 			}
5091 			ASSERT(!IDN_CHAN_SEND_IS_LOCKED(csp));
5092 			/*
5093 			 * Damn!   Must have went inactive during the window
5094 			 * before we regrabbed the send lock.  Oh well, can't
5095 			 * spend all day doing this, bail out.  Set csp to
5096 			 * NULL to prevent inprogress update at bottom.
5097 			 */
5098 			csp = NULL;
5099 			/*
5100 			 * Channel is not active, should not be used.
5101 			 */
5102 			PR_DATA("%s:%d: dest channel %d NOT ACTIVE\n",
5103 				proc, dst_domid, channel);
5104 			IDN_KSTAT_INC(sip, si_linkdown);
5105 			rv = IDNXMIT_REQUEUE;
5106 			goto nocando;
5107 		}
5108 		ASSERT(IDN_CHAN_SEND_IS_LOCKED(csp));
5109 	}
5110 	/*
5111 	 * If we made it here then the channel is active
5112 	 * Make sure the target domain is registered to receive stuff,
5113 	 * i.e. we're still linked.
5114 	 */
5115 	if (!IDN_CHAN_DOMAIN_IS_REGISTERED(csp, dst_domid)) {
5116 		/*
5117 		 * If domain is not even registered with this channel
5118 		 * then we have no business being here.  Doesn't matter
5119 		 * whether it's active or not.
5120 		 */
5121 		PR_DATA("%s:%d: domain not registered with channel %d\n",
5122 			proc, dst_domid, channel);
5123 		/*
5124 		 * Set csp to NULL to prevent in-progress update below.
5125 		 */
5126 		IDN_CHAN_UNLOCK_SEND(csp);
5127 		csp = NULL;
5128 		IDN_KSTAT_INC(sip, si_linkdown);
5129 		IDN_KSTAT_INC(sip, si_macxmt_errors);
5130 		rv = IDNXMIT_DROP;
5131 		goto nocando;
5132 	}
5133 
5134 	IDN_CHAN_SEND_INPROGRESS(csp);
5135 	IDN_CHAN_UNLOCK_SEND(csp);
5136 
5137 	/*
5138 	 * Find a target cpu to send interrupt to if
5139 	 * it becomes necessary (i.e. remote channel
5140 	 * server is idle).
5141 	 */
5142 	cpuindex = dp->dcpuindex;
5143 
5144 	/*
5145 	 * dcpuindex is atomically incremented, but other than
5146 	 * that is not well protected and that's okay.  The
5147 	 * intention is to simply spread around the interrupts
5148 	 * at the destination domain, however we don't have to
5149 	 * anal about it.  If we hit the same cpu multiple times
5150 	 * in a row that's okay, it will only be for a very short
5151 	 * period anyway before the cpuindex is incremented
5152 	 * to the next cpu.
5153 	 */
5154 	if (cpuindex < NCPU) {
5155 		ATOMIC_INC(dp->dcpuindex);
5156 	}
5157 	if (dp->dcpuindex >= NCPU)
5158 		dp->dcpuindex = 0;
5159 
5160 	IDN_ASSIGN_DCPU(dp, cpuindex);
5161 
5162 #ifdef XXX_DLPI_UNFRIENDLY
5163 	{
5164 		ushort_t	dstport = (ushort_t)dp->dcpu;
5165 
5166 		/*
5167 		 * XXX
5168 		 * This is not DLPI friendly, but we need some way
5169 		 * of distributing our XDC interrupts to the cpus
5170 		 * on the remote domain in a relatively random fashion
5171 		 * while trying to remain constant for an individual
5172 		 * network connection.  Don't want the target network
5173 		 * appl pinging around cpus thrashing the caches.
5174 		 * So, we'll pick target cpus based on the destination
5175 		 * TCP/IP port (socket).  The (simple) alternative to
5176 		 * this is to simply send all messages destined for
5177 		 * particular domain to the same cpu (dcpu), but
5178 		 * will lower our bandwidth and introduce a lot of
5179 		 * contention on that target cpu.
5180 		 */
5181 		if (ehp->ether_type == ETHERTYPE_IP) {
5182 			ipha_t	*ipha;
5183 			uchar_t	*dstporta;
5184 			int	hdr_length;
5185 			mblk_t	*nmp = mp;
5186 			uchar_t	*rptr = mp->b_rptr +
5187 					sizeof (struct ether_header);
5188 			if (nmp->b_wptr <= rptr) {
5189 				/*
5190 				 * Only the ethernet header was contained
5191 				 * in the first block.  Check for the
5192 				 * next packet.
5193 				 */
5194 				if ((nmp = mp->b_cont) != NULL)
5195 					rptr = nmp->b_rptr;
5196 			}
5197 			/*
5198 			 * If we still haven't found the IP header packet
5199 			 * then don't bother.  Can't search forever.
5200 			 */
5201 			if (nmp &&
5202 			    ((nmp->b_wptr - rptr) >= IP_SIMPLE_HDR_LENGTH)) {
5203 				ipha = (ipha_t *)ALIGN32(rptr);
5204 
5205 				ASSERT(DB_TYPE(mp) == M_DATA);
5206 				hdr_length = IPH_HDR_LENGTH(ipha);
5207 
5208 				switch (ipha->ipha_protocol) {
5209 				case IPPROTO_UDP:
5210 				case IPPROTO_TCP:
5211 					/*
5212 					 * TCP/UDP Protocol Header (1st word)
5213 					 * 0	    15,16	31
5214 					 * -----------------------
5215 					 * | src port | dst port |
5216 					 * -----------------------
5217 					 */
5218 					dstporta = (uchar_t *)ipha + hdr_length;
5219 					netports = *(uint_t *)dstporta;
5220 					dstporta += 2;
5221 					dstport  = *(ushort_t *)dstporta;
5222 					break;
5223 				default:
5224 					break;
5225 				}
5226 			}
5227 
5228 		}
5229 		IDN_ASSIGN_DCPU(dp, dstport);
5230 
5231 		PR_DATA("%s:%d: (dstport %d) assigned %d\n",
5232 			proc, dst_domid, (int)dstport, dp->dcpu);
5233 	}
5234 #endif /* XXX_DLPI_UNFRIENDLY */
5235 
5236 	data_rptr = mp->b_rptr;
5237 
5238 	ASSERT(dp->dcpu != IDN_NIL_DCPU);
5239 
5240 	ASSERT(idn_domain[dst_domid].dmbox.m_send);
5241 
5242 	retry_reclaim = 1;
5243 retry:
5244 	if ((dp->dio >= IDN_RECLAIM_MIN) || dp->diowanted) {
5245 		int	reclaim_req;
5246 		/*
5247 		 * Reclaim however many outstanding buffers
5248 		 * there are up to IDN_RECLAIM_MAX if it's set.
5249 		 */
5250 		reclaim_req = dp->diowanted ? -1 : IDN_RECLAIM_MAX ?
5251 					MIN(dp->dio, IDN_RECLAIM_MAX) :
5252 					dp->dio;
5253 		(void) idn_reclaim_mboxdata(dst_domid, channel,
5254 					reclaim_req);
5255 	}
5256 
5257 	if (dp->dio >= IDN_WINDOW_EMAX) {
5258 
5259 		if (lock_try(&dp->diocheck)) {
5260 			IDN_MSGTIMER_START(dst_domid, IDNP_DATA, 0,
5261 					idn_msg_waittime[IDNP_DATA],
5262 					&mt.mt_cookie);
5263 			/*
5264 			 * We have exceeded the minimum window for
5265 			 * outstanding I/O buffers to this domain.
5266 			 * Need to start the MSG timer to check for
5267 			 * possible response from remote domain.
5268 			 * The remote domain may be hung.  Send a
5269 			 * wakeup!  Specify all channels for given
5270 			 * domain since we don't know precisely which
5271 			 * is backed up (dio is global).
5272 			 */
5273 			IDNXDC(dst_domid, &mt,
5274 				(uint_t)dst_netaddr.net.chan, 0, 0, 0);
5275 		}
5276 
5277 		/*
5278 		 * Yikes!  We have exceeded the maximum window
5279 		 * which means no more packets going to remote
5280 		 * domain until he frees some up.
5281 		 */
5282 		IDN_KSTAT_INC(sip, si_txmax);
5283 		IDN_KSTAT_INC(sip, si_macxmt_errors);
5284 		rv = IDNXMIT_DROP;
5285 		goto nocando;
5286 	}
5287 	/*
5288 	 * Allocate a SMR I/O buffer and send it.
5289 	 */
5290 
5291 	if (msglen == 0) {
5292 		/*
5293 		 * A zero length messages is effectively a signal
5294 		 * to just send an interrupt to the remote domain.
5295 		 */
5296 		IDN_MSGTIMER_START(dst_domid, IDNP_DATA, 0,
5297 				idn_msg_waittime[IDNP_DATA],
5298 				&mt.mt_cookie);
5299 		IDNXDC(dst_domid, &mt,
5300 			(uint_t)dst_netaddr.net.chan, 0, 0, 0);
5301 	}
5302 	for (; (msglen > 0) && mp; msglen -= xfersize) {
5303 		int		xrv;
5304 		smr_offset_t	bufoffset;
5305 #ifdef DEBUG
5306 		int		n_xfersize;
5307 #endif /* DEBUG */
5308 
5309 		ASSERT(msglen <= IDN_DATA_SIZE);
5310 		xfersize = msglen;
5311 
5312 		serrno = smr_buf_alloc(dst_domid, xfersize, &iobufp);
5313 		if (serrno) {
5314 			PR_DATA("%s:%d: failed to alloc SMR I/O buffer "
5315 				"(serrno = %d)\n",
5316 				proc, dst_domid, serrno);
5317 			/*
5318 			 * Failure is either due to a timeout waiting
5319 			 * for the master to give us a slab, OR the
5320 			 * local domain exhausted its slab quota!
5321 			 * In either case we'll have to bail from
5322 			 * here and let higher layers decide what
5323 			 * to do.
5324 			 * We also could have had locking problems.
5325 			 * A negative serrno indicates we lost the lock
5326 			 * on dst_domid, so no need in dropping lock.
5327 			 */
5328 
5329 			if (lock_try(&dp->diowanted) && retry_reclaim) {
5330 				/*
5331 				 * We were the first to acquire the
5332 				 * lock indicating that it wasn't
5333 				 * set on entry to idn_send_data.
5334 				 * So, let's go back and see if we
5335 				 * can't reclaim some buffers and
5336 				 * try again.
5337 				 * It's very likely diowanted will be
5338 				 * enough to prevent us from looping
5339 				 * on retrying here, however to protect
5340 				 * against the small window where a
5341 				 * race condition might exist, we use
5342 				 * the retry_reclaim flag so that we
5343 				 * don't retry more than once.
5344 				 */
5345 				retry_reclaim = 0;
5346 				goto retry;
5347 			}
5348 
5349 			rv = (serrno > 0) ? serrno : -serrno;
5350 			IDN_KSTAT_INC(sip, si_notbufs);
5351 			IDN_KSTAT_INC(sip, si_noxmtbuf);	/* MIB II */
5352 			switch (rv) {
5353 			case ENOMEM:
5354 			case EBUSY:
5355 			case ENOLCK:
5356 			case ETIMEDOUT:
5357 			case EDQUOT:
5358 				/*
5359 				 * These are all transient conditions
5360 				 * which should be recoverable over
5361 				 * time.
5362 				 */
5363 				rv = IDNXMIT_REQUEUE;
5364 				break;
5365 
5366 			default:
5367 				rv = IDNXMIT_DROP;
5368 				break;
5369 			}
5370 			goto nocando;
5371 		}
5372 
5373 		lock_clear(&dp->diowanted);
5374 
5375 		hdrp = IDN_BUF2HDR(iobufp);
5376 		bufoffset = (smr_offset_t)IDN_ALIGNPTR(sizeof (smr_pkthdr_t),
5377 							data_rptr);
5378 		/*
5379 		 * If the alignment of bufoffset took us pass the
5380 		 * length of a smr_pkthdr_t then we need to possibly
5381 		 * lower xfersize since it was calulated based on
5382 		 * a perfect alignment.  However, if we're in DLPI
5383 		 * mode then shouldn't be necessary since the length
5384 		 * of the incoming packet (mblk) should have already
5385 		 * taken into consideration this possible adjustment.
5386 		 */
5387 #ifdef DEBUG
5388 		if (bufoffset != sizeof (smr_pkthdr_t))
5389 			PR_DATA("%s:%d: offset ALIGNMENT (%lu -> %u) "
5390 				"(data_rptr = %p)\n",
5391 				proc, dst_domid, sizeof (smr_pkthdr_t),
5392 				bufoffset, data_rptr);
5393 
5394 		n_xfersize = MIN(xfersize, (IDN_SMR_BUFSIZE - bufoffset));
5395 		if (xfersize != n_xfersize) {
5396 			PR_DATA("%s:%d: xfersize ADJUST (%d -> %d)\n",
5397 				proc, dst_domid, xfersize, n_xfersize);
5398 			cmn_err(CE_WARN, "%s: ERROR (xfersize = %d, > "
5399 					"bufsize(%d)-bufoffset(%d) = %d)",
5400 					proc, xfersize, IDN_SMR_BUFSIZE,
5401 					bufoffset,
5402 					IDN_SMR_BUFSIZE - bufoffset);
5403 		}
5404 #endif /* DEBUG */
5405 		xfersize = MIN(xfersize, (int)(IDN_SMR_BUFSIZE - bufoffset));
5406 
5407 		iodatap = IDN_BUF2DATA(iobufp, bufoffset);
5408 		mp = idn_fill_buffer(iodatap, xfersize, mp, &data_rptr);
5409 
5410 		hdrp->b_netaddr  = dst_netaddr.netaddr;
5411 		hdrp->b_netports = netports;
5412 		hdrp->b_offset   = bufoffset;
5413 		hdrp->b_length   = xfersize;
5414 		hdrp->b_next	 = IDN_NIL_SMROFFSET;
5415 		hdrp->b_rawio	 = 0;
5416 		hdrp->b_cksum    = IDN_CKSUM_PKT(hdrp);
5417 
5418 		xrv = idn_send_mboxdata(dst_domid, sip, channel, iobufp);
5419 		if (xrv) {
5420 			/*
5421 			 * Reclaim packet.
5422 			 * Return error on this packet so it can be retried
5423 			 * (putbq).  Note that it should be safe to assume
5424 			 * that this for-loop is only executed once when in
5425 			 * DLPI mode and so no need to worry about fractured
5426 			 * mblk packet.
5427 			 */
5428 			PR_DATA("%s:%d: DATA XFER to chan %d FAILED "
5429 				"(ret=%d)\n",
5430 				proc, dst_domid, channel, xrv);
5431 			smr_buf_free(dst_domid, iobufp, xfersize);
5432 
5433 			PR_DATA("%s:%d: (line %d) dec(dio) -> %d\n",
5434 				proc, dst_domid, __LINE__, dp->dio);
5435 
5436 			rv = IDNXMIT_DROP;
5437 			IDN_KSTAT_INC(sip, si_macxmt_errors);
5438 			goto nocando;
5439 		} else {
5440 			pktcnt++;
5441 			/*
5442 			 * Packet will get freed on a subsequent send
5443 			 * when we reclaim buffers that the receivers
5444 			 * has finished consuming.
5445 			 */
5446 		}
5447 	}
5448 
5449 #ifdef DEBUG
5450 	if (pktcnt > 1)
5451 		cmn_err(CE_WARN,
5452 			"%s: ERROR: sent multi-pkts (%d), len = %ld",
5453 			proc, pktcnt, orig_msglen);
5454 #endif /* DEBUG */
5455 
5456 	PR_DATA("%s:%d: SENT %d packets (%d @ 0x%x)\n",
5457 		proc, dst_domid, pktcnt, dst_netaddr.net.chan,
5458 		dst_netaddr.net.netid);
5459 
5460 	IDN_CHAN_LOCK_SEND(csp);
5461 	IDN_CHAN_SEND_DONE(csp);
5462 	IDN_CHAN_UNLOCK_SEND(csp);
5463 
5464 	return (IDNXMIT_OKAY);
5465 
5466 nocando:
5467 
5468 	if (csp) {
5469 		IDN_CHAN_LOCK_SEND(csp);
5470 		IDN_CHAN_SEND_DONE(csp);
5471 		IDN_CHAN_UNLOCK_SEND(csp);
5472 	}
5473 
5474 	if (rv == IDNXMIT_REQUEUE) {
5475 		/*
5476 		 * Better kick off monitor to check when
5477 		 * it's ready to reenable the queues for
5478 		 * this channel.
5479 		 */
5480 		idn_xmit_monitor_kickoff(channel);
5481 	}
5482 
5483 	return (rv);
5484 }
5485 
5486 /*
5487  * Function to support local loopback testing of IDN driver.
5488  * Primarily geared towards measuring stream-head and IDN driver
5489  * overhead with respect to data messages.  Setting idn_strhead_only
5490  * allows routine to focus on stream-head overhead by simply putting
5491  * the message straight to the 'next' queue of the destination
5492  * read-queue.  Current implementation puts the message directly to
5493  * the read-queue thus sending the message right back to the IDN driver
5494  * as though the data came in off the wire.  No need to worry about
5495  * any IDN layers attempting to ack data as that's normally handled
5496  * by idnh_recv_data.
5497  *
5498  * dst_netaddr = destination port-n-addr on local domain.
5499  * wq          = write queue from whence message came.
5500  * mp          = the (data-only) message.
5501  *
5502  * Returns 0		Indicates data handled.
5503  *	   errno	EAGAIN indicates data can be retried.
5504  *			Other errno's indicate failure to handle.
5505  */
5506 static int
5507 idn_send_data_loopback(idn_netaddr_t dst_netaddr, queue_t *wq, mblk_t *mp)
5508 {
5509 	register struct idnstr	*stp;
5510 	struct idn	*sip;
5511 	int		rv = 0;
5512 	procname_t	proc = "idn_send_data_loopback";
5513 
5514 	if (dst_netaddr.net.netid != idn_domain[idn.localid].dnetid) {
5515 		PR_DATA("%s: dst_netaddr.net.netid 0x%x != local 0x%x\n",
5516 			proc, dst_netaddr.net.netid,
5517 			idn_domain[idn.localid].dnetid);
5518 		rv = EADDRNOTAVAIL;
5519 		goto done;
5520 	}
5521 	stp = (struct idnstr *)wq->q_ptr;
5522 	if (!stp || !stp->ss_rq) {
5523 		rv = EDESTADDRREQ;
5524 		goto done;
5525 	}
5526 	sip = stp->ss_sip;
5527 
5528 	idndl_read(sip, mp);
5529 	rv = 0;
5530 
5531 done:
5532 	return (rv);
5533 }
5534 
5535 /*
5536  * Fill bufp with as much data as possible from the message pointed
5537  * to by mp up to size bytes.
5538  * Save our current read pointer in the variable parameter (data_rptrp)
5539  * so we know where to start on the next go around.  Don't want to
5540  * bump the actual b_rptr in the mblk because the mblk may need to
5541  * be reused, e.g. broadcast.
5542  * Return the mblk pointer to the position we had to stop.
5543  */
5544 static mblk_t *
5545 idn_fill_buffer(caddr_t bufp, int size, mblk_t *mp, uchar_t **data_rptrp)
5546 {
5547 	int	copysize;
5548 
5549 	ASSERT(bufp && size);
5550 
5551 	if (mp == NULL)
5552 		return (NULL);
5553 
5554 	while ((size > 0) && mp) {
5555 
5556 		copysize = MIN(mp->b_wptr - (*data_rptrp), size);
5557 
5558 		if (copysize > 0) {
5559 			/*
5560 			 * If there's data to copy, do it.
5561 			 */
5562 			bcopy((*data_rptrp), bufp, copysize);
5563 			(*data_rptrp) += copysize;
5564 			bufp += copysize;
5565 			size -= copysize;
5566 		}
5567 		if (mp->b_wptr <= (*data_rptrp)) {
5568 			/*
5569 			 * If we emptied the mblk, then
5570 			 * move on to the next one.
5571 			 */
5572 			for (mp = mp->b_cont;
5573 			    mp && (mp->b_datap->db_type != M_DATA);
5574 			    mp = mp->b_cont)
5575 				;
5576 			if (mp)
5577 				*data_rptrp = mp->b_rptr;
5578 		}
5579 	}
5580 	return (mp);
5581 }
5582 
5583 /*
5584  * Messages received here do NOT arrive on a stream, but are
5585  * instead handled via the idn_protocol_servers.  This routine
5586  * is effectively the job processor for the protocol servers.
5587  */
5588 static void
5589 idn_recv_proto(idn_protomsg_t *hp)
5590 {
5591 	int		domid, cpuid;
5592 	int		sync_lock = 0;
5593 	idn_domain_t	*dp;
5594 	register uint_t	mtype;
5595 	register uint_t	msgtype, acktype;
5596 	idn_msgtype_t	mt;
5597 	ushort_t	dcookie, tcookie;
5598 	procname_t	proc = "idn_recv_proto";
5599 
5600 
5601 	if (idn.state == IDNGS_IGNORE) {
5602 		/*
5603 		 * Fault injection to simulate non-responsive domain.
5604 		 */
5605 		return;
5606 	}
5607 
5608 	domid   = hp->m_domid;
5609 	cpuid   = hp->m_cpuid;
5610 	msgtype = hp->m_msgtype;
5611 	acktype = hp->m_acktype;
5612 	dcookie = IDN_DCOOKIE(hp->m_cookie);
5613 	tcookie = IDN_TCOOKIE(hp->m_cookie);
5614 	/*
5615 	 * msgtype =	Is the type of message we received,
5616 	 *		e.g. nego, ack, nego+ack, etc.
5617 	 *
5618 	 * acktype =	If we received a pure ack or nack
5619 	 *		then this variable is set to the
5620 	 *		type of message that was ack/nack'd.
5621 	 */
5622 	if ((mtype = msgtype & IDNP_MSGTYPE_MASK) == 0) {
5623 		/*
5624 		 * Received a pure ack/nack.
5625 		 */
5626 		mtype = acktype & IDNP_MSGTYPE_MASK;
5627 	}
5628 
5629 	if (!VALID_MSGTYPE(mtype)) {
5630 		PR_PROTO("%s:%d: ERROR: invalid message type (0x%x)\n",
5631 			proc, domid, mtype);
5632 		return;
5633 	}
5634 	if (!VALID_CPUID(cpuid)) {
5635 		PR_PROTO("%s:%d: ERROR: invalid cpuid (%d)\n",
5636 			proc, domid, cpuid);
5637 		return;
5638 	}
5639 
5640 	/*
5641 	 * No pure data packets should reach this level.
5642 	 * Data+ack messages will reach here, but only
5643 	 * for the purpose of stopping the timer which
5644 	 * happens by default when this routine is called.
5645 	 */
5646 	ASSERT(msgtype != IDNP_DATA);
5647 
5648 	/*
5649 	 * We should never receive a request from ourself,
5650 	 * except for commands in the case of broadcasts!
5651 	 */
5652 	if ((domid == idn.localid) && (mtype != IDNP_CMD)) {
5653 		char	str[15];
5654 
5655 		inum2str(hp->m_msgtype, str);
5656 
5657 		cmn_err(CE_WARN,
5658 			"IDN: 214: received message (%s[0x%x]) from self "
5659 			"(domid %d)",
5660 			str, hp->m_msgtype, domid);
5661 		return;
5662 	}
5663 
5664 	IDN_SYNC_LOCK();
5665 	/*
5666 	 * Set a flag indicating whether we really need
5667 	 * SYNC-LOCK.  We'll drop it in a little bit if
5668 	 * we really don't need it.
5669 	 */
5670 	switch (mtype) {
5671 	case IDNP_CON:
5672 	case IDNP_FIN:
5673 	case IDNP_NEGO:
5674 		sync_lock = 1;
5675 		break;
5676 
5677 	default:
5678 		break;
5679 	}
5680 
5681 	dp = &idn_domain[domid];
5682 	IDN_DLOCK_EXCL(domid);
5683 
5684 	/*
5685 	 * The only messages we do _not_ check the cookie are:
5686 	 *	nego
5687 	 *	nego+ack
5688 	 *	fin	 - if received cookie is 0.
5689 	 *	fin+ack	 - if received cookie is 0.
5690 	 *	ack/fin	 - if received cookie is 0.
5691 	 *	nack/fin - if received cookie is 0.
5692 	 */
5693 	if (((msgtype & IDNP_MSGTYPE_MASK) != IDNP_NEGO) &&
5694 			((mtype != IDNP_FIN) ||
5695 			(dcookie && dp->dcookie_recv))) {
5696 		if (dp->dcookie_recv != dcookie) {
5697 			dp->dcookie_errcnt++;
5698 			if (dp->dcookie_err == 0) {
5699 				/*
5700 				 * Set cookie error to prevent a
5701 				 * possible flood of bogus cookies
5702 				 * and thus error messages.
5703 				 */
5704 				dp->dcookie_err = 1;
5705 				cmn_err(CE_WARN,
5706 					"IDN: 215: invalid cookie (0x%x) "
5707 					"for message (0x%x) from domain %d",
5708 					dcookie, hp->m_msgtype, domid);
5709 
5710 				PR_PROTO("%s:%d: received cookie (0x%x), "
5711 					"expected (0x%x) [errcnt = %d]\n",
5712 					proc, domid, dcookie,
5713 					dp->dcookie_recv, dp->dcookie_errcnt);
5714 			}
5715 			IDN_DUNLOCK(domid);
5716 			IDN_SYNC_UNLOCK();
5717 			return;
5718 		}
5719 	}
5720 	dp->dcookie_err = 0;
5721 	IDN_GLOCK_EXCL();
5722 
5723 	idn_clear_awol(domid);
5724 
5725 	IDN_GUNLOCK();
5726 	if (!sync_lock)		/* really don't need SYNC-LOCK past here */
5727 		IDN_SYNC_UNLOCK();
5728 
5729 	/*
5730 	 * Stop any timers that may have been outstanding for
5731 	 * this domain, for this particular message type.
5732 	 * Note that CFG timers are directly managed by
5733 	 * config recv/send code.
5734 	 */
5735 	if ((mtype != IDNP_CFG) && (msgtype & IDNP_ACKNACK_MASK) && tcookie) {
5736 		IDN_MSGTIMER_STOP(domid, mtype, tcookie);
5737 	}
5738 
5739 	/*
5740 	 * Keep track of the last cpu to send us a message.
5741 	 * If the domain has not yet been assigned, we'll need
5742 	 * this cpuid in order to send back a respond.
5743 	 */
5744 	dp->dcpu_last = cpuid;
5745 
5746 	mt.mt_mtype = (ushort_t)msgtype;
5747 	mt.mt_atype = (ushort_t)acktype;
5748 	mt.mt_cookie = tcookie;
5749 
5750 	switch (mtype) {
5751 	case IDNP_NEGO:
5752 		idn_recv_nego(domid, &mt, hp->m_xargs, dcookie);
5753 		break;
5754 
5755 	case IDNP_CFG:
5756 		idn_recv_config(domid, &mt, hp->m_xargs);
5757 		break;
5758 
5759 	case IDNP_CON:
5760 		idn_recv_con(domid, &mt, hp->m_xargs);
5761 		break;
5762 
5763 	case IDNP_FIN:
5764 		idn_recv_fin(domid, &mt, hp->m_xargs);
5765 		break;
5766 
5767 	case IDNP_CMD:
5768 		idn_recv_cmd(domid, &mt, hp->m_xargs);
5769 		break;
5770 
5771 	case IDNP_DATA:
5772 		ASSERT(msgtype & IDNP_ACKNACK_MASK);
5773 		/*
5774 		 * When doing the fast track we simply process
5775 		 * possible nack error conditions.  The actual
5776 		 * processing of the SMR data buffer is taken
5777 		 * care of in idnh_recv_dataack.  When NOT doing
5778 		 * the fast track, we do all the processing here
5779 		 * in the protocol server.
5780 		 */
5781 		idn_recv_data(domid, &mt, hp->m_xargs);
5782 		break;
5783 
5784 	default:
5785 		/*
5786 		 * Should be receiving 0 inum and 0 acknack.
5787 		 */
5788 #ifdef DEBUG
5789 		cmn_err(CE_PANIC,
5790 #else /* DEBUG */
5791 		cmn_err(CE_WARN,
5792 #endif /* DEBUG */
5793 			"IDN: 216: (0x%x)msgtype/(0x%x)acktype rcvd from "
5794 			"domain %d", msgtype, acktype, domid);
5795 		break;
5796 	}
5797 
5798 	IDN_DUNLOCK(domid);
5799 	/*
5800 	 * All receiving routines are responsible for dropping drwlock.
5801 	 */
5802 
5803 	if (sync_lock)
5804 		IDN_SYNC_UNLOCK();
5805 }
5806 
5807 /*
5808  * Once the CONFIG state is hit we immediately blast out all
5809  * of our config info.  This guarantees that the CONFIG state
5810  * effectively signifies that the sender has sent _all_ of
5811  * their config info.
5812  */
5813 static void
5814 idn_send_config(int domid, int phase)
5815 {
5816 	idn_domain_t	*dp;
5817 	int		rv;
5818 	clock_t		cfg_waittime = idn_msg_waittime[IDNP_CFG];
5819 	procname_t	proc = "idn_send_config";
5820 
5821 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
5822 
5823 	dp = &idn_domain[domid];
5824 
5825 	ASSERT(dp->dstate == IDNDS_CONFIG);
5826 
5827 	if (phase == 1) {
5828 		/*
5829 		 * Reset stuff in dtmp to 0:
5830 		 *	dcfgphase
5831 		 *	dcksum
5832 		 *	dncfgitems
5833 		 *	dmaxnets
5834 		 *	dmboxpernet
5835 		 */
5836 		dp->dtmp = 0;
5837 	}
5838 
5839 	if (dp->dcfgsnddone) {
5840 		if (!dp->dcfgrcvdone) {
5841 			IDN_MSGTIMER_START(domid, IDNP_CFG, 0,
5842 					cfg_waittime, NULL);
5843 		}
5844 		return;
5845 	}
5846 
5847 	IDN_DLOCK_SHARED(idn.localid);
5848 
5849 	PR_PROTO("%s:%d: sending %s config (phase %d)\n",
5850 		proc, domid,
5851 		idn_domain[idn.localid].dvote.v.master ? "MASTER" : "SLAVE",
5852 		phase);
5853 
5854 	if (idn_domain[idn.localid].dvote.v.master)
5855 		rv = idn_send_master_config(domid, phase);
5856 	else
5857 		rv = idn_send_slave_config(domid, phase);
5858 
5859 	IDN_DUNLOCK(idn.localid);
5860 
5861 	if (rv >= 0) {
5862 
5863 		if (rv == 1) {
5864 			dp->dcfgsnddone = 1;
5865 			PR_PROTO("%s:%d: SEND config DONE\n", proc, domid);
5866 			if (!dp->dcfgrcvdone) {
5867 				IDN_MSGTIMER_START(domid, IDNP_CFG, 0,
5868 						cfg_waittime, NULL);
5869 			}
5870 		} else {
5871 			IDN_MSGTIMER_START(domid, IDNP_CFG, 0,
5872 						cfg_waittime, NULL);
5873 		}
5874 	}
5875 }
5876 
5877 /*
5878  * Clear out the mailbox table.
5879  * NOTE: This routine touches the SMR.
5880  */
5881 static void
5882 idn_reset_mboxtbl(idn_mboxtbl_t *mtp)
5883 {
5884 	int		qi;
5885 	idn_mboxmsg_t	*mp = &mtp->mt_queue[0];
5886 
5887 	qi = 0;
5888 	do {
5889 		mp[qi].ms_bframe = 0;
5890 		mp[qi].ms_owner = 0;
5891 		mp[qi].ms_flag = 0;
5892 		IDN_MMBOXINDEX_INC(qi);
5893 	} while (qi);
5894 }
5895 
5896 static int
5897 idn_get_mbox_config(int domid, int *mindex,
5898 		smr_offset_t *mtable, smr_offset_t *mdomain)
5899 {
5900 	idn_domain_t	*dp, *ldp;
5901 
5902 	dp = &idn_domain[domid];
5903 	ldp = &idn_domain[idn.localid];
5904 
5905 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
5906 	ASSERT(IDN_DLOCK_IS_SHARED(idn.localid));
5907 	ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID);
5908 
5909 	/*
5910 	 * Get SMR offset of receive mailbox assigned
5911 	 * to respective domain.  If I'm a slave then
5912 	 * my dmbox.m_tbl will not have been assigned yet.
5913 	 * Instead of sending the actual offset I send
5914 	 * the master his assigned index.  Since the
5915 	 * master knows what offset it will assign to
5916 	 * me he can determine his assigned (recv) mailbox
5917 	 * based on the offset and given index.  The local
5918 	 * domain can also use this information once the
5919 	 * dmbox.m_tbl is received to properly assign the
5920 	 * correct mbox offset to the master.
5921 	 */
5922 	if (ldp->dmbox.m_tbl == NULL) {
5923 		/*
5924 		 * Local domain has not yet been assigned a
5925 		 * (recv) mailbox table.  This must be the
5926 		 * initial connection of this domain.
5927 		 */
5928 		ASSERT(dp->dvote.v.master && !ldp->dvote.v.master);
5929 		ASSERT(mindex);
5930 		*mindex = domid;
5931 	} else {
5932 		idn_mboxtbl_t	*mtp;
5933 
5934 		mtp = IDN_MBOXTBL_PTR(ldp->dmbox.m_tbl, domid);
5935 
5936 		ASSERT(mdomain);
5937 		*mdomain = IDN_ADDR2OFFSET(mtp);
5938 
5939 		if (ldp->dvote.v.master) {
5940 			/*
5941 			 * Need to calculate mailbox table to
5942 			 * assign to the given domain.  Since
5943 			 * I'm the master his mailbox is in
5944 			 * the (all-domains) mailbox table.
5945 			 */
5946 			mtp = IDN_MBOXAREA_BASE(idn.mboxarea, domid);
5947 			ASSERT(mtable);
5948 			*mtable = IDN_ADDR2OFFSET(mtp);
5949 
5950 			dp->dmbox.m_tbl = mtp;
5951 		}
5952 	}
5953 
5954 	return (0);
5955 }
5956 
5957 /*
5958  * RETURNS:
5959  *	1	Unexpected/unnecessary phase.
5960  *	0	Successfully handled, timer needed.
5961  */
5962 static int
5963 idn_send_master_config(int domid, int phase)
5964 {
5965 	idn_cfgsubtype_t	cfg_subtype;
5966 	int		rv = 0;
5967 	idn_domain_t	*dp, *ldp;
5968 	idn_msgtype_t	mt;
5969 	int		nmcadr;
5970 	uint_t		barpfn, larpfn;
5971 	uint_t		cpus_u32, cpus_l32;
5972 	uint_t		mcadr[3];
5973 	smr_offset_t	mbox_table, mbox_domain;
5974 	register int	b, p, m;
5975 	procname_t	proc = "idn_send_master_config";
5976 
5977 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
5978 	ASSERT(IDN_DLOCK_IS_SHARED(idn.localid));
5979 
5980 	dp = &idn_domain[domid];
5981 	ldp = &idn_domain[idn.localid];
5982 
5983 	ASSERT(dp->dstate == IDNDS_CONFIG);
5984 	ASSERT(dp->dvote.v.master == 0);
5985 	ASSERT(ldp->dvote.v.master == 1);
5986 
5987 	mt.mt_mtype = IDNP_CFG;
5988 	mt.mt_atype = 0;
5989 	mt.mt_cookie = 0;
5990 	m = 0;
5991 	mcadr[0] = mcadr[1] = mcadr[2] = 0;
5992 	cfg_subtype.val = 0;
5993 
5994 	switch (phase) {
5995 
5996 	case 1:
5997 		mbox_table = mbox_domain = IDN_NIL_SMROFFSET;
5998 		idn_get_mbox_config(domid, NULL, &mbox_table,
5999 					&mbox_domain);
6000 		/*
6001 		 * ----------------------------------------------------
6002 		 * Send: SLABSIZE, DATAMBOX.DOMAIN, DATAMBOX.TABLE
6003 		 * ----------------------------------------------------
6004 		 */
6005 		cfg_subtype.param.p[0] = IDN_CFGPARAM(IDNCFG_SIZE,
6006 						IDNCFGARG_SIZE_SLAB);
6007 		cfg_subtype.param.p[1] = IDN_CFGPARAM(IDNCFG_DATAMBOX,
6008 						IDNCFGARG_DATAMBOX_DOMAIN);
6009 		cfg_subtype.param.p[2] = IDN_CFGPARAM(IDNCFG_DATAMBOX,
6010 						IDNCFGARG_DATAMBOX_TABLE);
6011 		cfg_subtype.info.num = 3;
6012 		cfg_subtype.info.phase = phase;
6013 		dp->dcfgphase = phase;
6014 
6015 		ASSERT(mbox_domain != IDN_NIL_SMROFFSET);
6016 		ASSERT(mbox_table != IDN_NIL_SMROFFSET);
6017 
6018 		PR_PROTO("%s:%d:%d: sending SLABSIZE (%d), "
6019 			"DATAMBOX.DOMAIN (0x%x), DATAMBOX.TABLE (0x%x)\n",
6020 			proc, domid, phase, IDN_SLAB_BUFCOUNT, mbox_domain,
6021 			mbox_table);
6022 
6023 		IDNXDC(domid, &mt, cfg_subtype.val, IDN_SLAB_BUFCOUNT,
6024 			mbox_domain, mbox_table);
6025 		break;
6026 
6027 	case 2:
6028 		barpfn = idn.smr.locpfn;
6029 		larpfn = barpfn + (uint_t)btop(MB2B(IDN_SMR_SIZE));
6030 		/*
6031 		 * ----------------------------------------------------
6032 		 * Send: NETID, BARLAR
6033 		 * ----------------------------------------------------
6034 		 */
6035 		cfg_subtype.param.p[0] = IDN_CFGPARAM(IDNCFG_NETID, 0);
6036 		cfg_subtype.param.p[1] = IDN_CFGPARAM(IDNCFG_BARLAR,
6037 						IDNCFGARG_BARLAR_BAR);
6038 		cfg_subtype.param.p[2] = IDN_CFGPARAM(IDNCFG_BARLAR,
6039 						IDNCFGARG_BARLAR_LAR);
6040 		cfg_subtype.info.num = 3;
6041 		cfg_subtype.info.phase = phase;
6042 		dp->dcfgphase = phase;
6043 
6044 		PR_PROTO("%s:%d:%d: sending NETID (%d), "
6045 			"BARPFN/LARPFN (0x%x/0x%x)\n",
6046 			proc, domid, phase, ldp->dnetid, barpfn, larpfn);
6047 
6048 		IDNXDC(domid, &mt, cfg_subtype.val,
6049 			(uint_t)ldp->dnetid, barpfn, larpfn);
6050 		break;
6051 
6052 	case 3:
6053 		nmcadr = ldp->dhw.dh_nmcadr;
6054 		cpus_u32 = UPPER32_CPUMASK(ldp->dcpuset);
6055 		cpus_l32 = LOWER32_CPUMASK(ldp->dcpuset);
6056 		/*
6057 		 * ----------------------------------------------------
6058 		 * Send: CPUSET, NMCADR
6059 		 * ----------------------------------------------------
6060 		 */
6061 		cfg_subtype.param.p[0] = IDN_CFGPARAM(IDNCFG_CPUSET,
6062 						IDNCFGARG_CPUSET_UPPER);
6063 		cfg_subtype.param.p[1] = IDN_CFGPARAM(IDNCFG_CPUSET,
6064 						IDNCFGARG_CPUSET_LOWER);
6065 		cfg_subtype.param.p[2] = IDN_CFGPARAM(IDNCFG_NMCADR, 0);
6066 		cfg_subtype.info.num = 3;
6067 		cfg_subtype.info.phase = phase;
6068 		dp->dcfgphase = phase;
6069 
6070 		PR_PROTO("%s:%d:%d: sending CPUSET (0x%x.%x), NMCADR (%d)\n",
6071 			proc, domid, phase, cpus_u32, cpus_l32, nmcadr);
6072 
6073 		IDNXDC(domid, &mt, cfg_subtype.val,
6074 			cpus_u32, cpus_l32, nmcadr);
6075 		break;
6076 
6077 	case 4:
6078 		/*
6079 		 * ----------------------------------------------------
6080 		 * Send: BOARDSET, MTU, BUFSIZE
6081 		 * ----------------------------------------------------
6082 		 */
6083 		cfg_subtype.param.p[0] = IDN_CFGPARAM(IDNCFG_BOARDSET, 0);
6084 		cfg_subtype.param.p[1] = IDN_CFGPARAM(IDNCFG_SIZE,
6085 						IDNCFGARG_SIZE_MTU);
6086 		cfg_subtype.param.p[2] = IDN_CFGPARAM(IDNCFG_SIZE,
6087 						IDNCFGARG_SIZE_BUF);
6088 		cfg_subtype.info.num = 3;
6089 		cfg_subtype.info.phase = phase;
6090 		dp->dcfgphase = phase;
6091 
6092 		PR_PROTO("%s:%d:%d: sending BOARDSET (0x%x), MTU (0x%lx), "
6093 			"BUFSIZE (0x%x)\n", proc, domid, phase,
6094 			ldp->dhw.dh_boardset, IDN_MTU, IDN_SMR_BUFSIZE);
6095 
6096 		IDNXDC(domid, &mt, cfg_subtype.val,
6097 			ldp->dhw.dh_boardset, IDN_MTU, IDN_SMR_BUFSIZE);
6098 		break;
6099 
6100 	case 5:
6101 		/*
6102 		 * ----------------------------------------------------
6103 		 * Send: MAXNETS, MBOXPERNET, CKSUM
6104 		 * ----------------------------------------------------
6105 		 */
6106 		cfg_subtype.param.p[0] = IDN_CFGPARAM(IDNCFG_DATASVR,
6107 						IDNCFGARG_DATASVR_MAXNETS);
6108 		cfg_subtype.param.p[1] = IDN_CFGPARAM(IDNCFG_DATASVR,
6109 						IDNCFGARG_DATASVR_MBXPERNET);
6110 		cfg_subtype.param.p[2] = IDN_CFGPARAM(IDNCFG_OPTIONS,
6111 						IDNCFGARG_CHECKSUM);
6112 		cfg_subtype.info.num = 3;
6113 		cfg_subtype.info.phase = phase;
6114 		dp->dcfgphase = phase;
6115 
6116 		PR_PROTO("%s:%d:%d: sending MAXNETS (%d), "
6117 			"MBOXPERNET (%d), CKSUM (%d)\n",
6118 			proc, domid, phase,
6119 			IDN_MAX_NETS, IDN_MBOX_PER_NET,
6120 			IDN_CHECKSUM);
6121 
6122 		IDNXDC(domid, &mt, cfg_subtype.val,
6123 			IDN_MAX_NETS, IDN_MBOX_PER_NET, IDN_CHECKSUM);
6124 		break;
6125 
6126 	case 6:
6127 		/*
6128 		 * ----------------------------------------------------
6129 		 * Send: NWRSIZE (piggyback on MCADRs)
6130 		 * ----------------------------------------------------
6131 		 */
6132 		cfg_subtype.param.p[0] = IDN_CFGPARAM(IDNCFG_SIZE,
6133 						IDNCFGARG_SIZE_NWR);
6134 		mcadr[0] = IDN_NWR_SIZE;
6135 		m = 1;
6136 
6137 		/*FALLTHROUGH*/
6138 
6139 	default:	/* case 7 and above */
6140 		/*
6141 		 * ----------------------------------------------------
6142 		 * Send: MCADR's
6143 		 * ----------------------------------------------------
6144 		 * First need to figure how many we've already sent
6145 		 * based on what phase of CONFIG we're in.
6146 		 * ----------------------------------------------------
6147 		 */
6148 		if (phase > 6) {
6149 			p = ((phase - 7) * 3) + 2;
6150 			for (b = 0; (b < MAX_BOARDS) && (p > 0); b++)
6151 				if (ldp->dhw.dh_mcadr[b])
6152 					p--;
6153 		} else {
6154 			b = 0;
6155 		}
6156 
6157 		for (; (b < MAX_BOARDS) && (m < 3); b++) {
6158 			if (ldp->dhw.dh_mcadr[b] == 0)
6159 				continue;
6160 			mcadr[m] = ldp->dhw.dh_mcadr[b];
6161 			cfg_subtype.param.p[m] = IDN_CFGPARAM(IDNCFG_MCADR, b);
6162 			m++;
6163 		}
6164 		if (m > 0) {
6165 			if (phase == 6) {
6166 				PR_PROTO("%s:%d:%d: sending NWRSIZE (%d), "
6167 					"MCADRs (0x%x, 0x%x)\n",
6168 					proc, domid, phase,
6169 					mcadr[0], mcadr[1], mcadr[2]);
6170 			} else {
6171 				PR_PROTO("%s:%d:%d: sending MCADRs "
6172 					"(0x%x, 0x%x, 0x%x)\n",
6173 					proc, domid, phase,
6174 					mcadr[0], mcadr[1], mcadr[2]);
6175 			}
6176 			cfg_subtype.info.num = m;
6177 			cfg_subtype.info.phase = phase;
6178 			dp->dcfgphase = phase;
6179 
6180 			IDNXDC(domid, &mt, cfg_subtype.val,
6181 				mcadr[0], mcadr[1], mcadr[2]);
6182 		} else {
6183 			rv = 1;
6184 		}
6185 		break;
6186 	}
6187 
6188 	return (rv);
6189 }
6190 
6191 /*
6192  * RETURNS:
6193  *	1	Unexpected/unnecessary phase.
6194  *	0	Successfully handled.
6195  */
6196 static int
6197 idn_send_slave_config(int domid, int phase)
6198 {
6199 	idn_cfgsubtype_t	cfg_subtype;
6200 	int		rv = 0;
6201 	idn_domain_t	*dp, *ldp;
6202 	smr_offset_t	mbox_domain;
6203 	idn_msgtype_t	mt;
6204 	int		mbox_index;
6205 	uint_t		cpus_u32, cpus_l32;
6206 	procname_t	proc = "idn_send_slave_config";
6207 
6208 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
6209 	ASSERT(IDN_DLOCK_IS_SHARED(idn.localid));
6210 
6211 	mt.mt_mtype = IDNP_CFG;
6212 	mt.mt_atype = 0;
6213 	dp = &idn_domain[domid];
6214 	ldp = &idn_domain[idn.localid];
6215 
6216 	ASSERT(dp->dstate == IDNDS_CONFIG);
6217 	ASSERT(ldp->dvote.v.master == 0);
6218 
6219 	switch (phase) {
6220 
6221 	case 1:
6222 		mbox_index = IDN_NIL_DOMID;
6223 		mbox_domain = IDN_NIL_SMROFFSET;
6224 		idn_get_mbox_config(domid, &mbox_index, NULL, &mbox_domain);
6225 		/*
6226 		 * ----------------------------------------------------
6227 		 * Send: DATAMBOX.DOMAIN or DATAMBOX.INDEX,
6228 		 *	 DATASVR.MAXNETS, DATASVR.MBXPERNET
6229 		 * ----------------------------------------------------
6230 		 */
6231 		cfg_subtype.val = 0;
6232 		if (mbox_index == IDN_NIL_DOMID) {
6233 			ASSERT(mbox_domain != IDN_NIL_SMROFFSET);
6234 			cfg_subtype.param.p[0] = IDN_CFGPARAM(IDNCFG_DATAMBOX,
6235 						    IDNCFGARG_DATAMBOX_DOMAIN);
6236 		} else {
6237 			/*
6238 			 * Should only be sending Index to
6239 			 * the master and not another slave.
6240 			 */
6241 			ASSERT(dp->dvote.v.master);
6242 			ASSERT(mbox_domain == IDN_NIL_SMROFFSET);
6243 			cfg_subtype.param.p[0] = IDN_CFGPARAM(IDNCFG_DATAMBOX,
6244 						    IDNCFGARG_DATAMBOX_INDEX);
6245 		}
6246 		cfg_subtype.param.p[1] = IDN_CFGPARAM(IDNCFG_DATASVR,
6247 						IDNCFGARG_DATASVR_MAXNETS);
6248 		cfg_subtype.param.p[2] = IDN_CFGPARAM(IDNCFG_DATASVR,
6249 						IDNCFGARG_DATASVR_MBXPERNET);
6250 		cfg_subtype.info.num = 3;
6251 		cfg_subtype.info.phase = phase;
6252 		dp->dcfgphase = phase;
6253 
6254 		PR_PROTO("%s:%d:%d: sending DATAMBOX.%s (0x%x), "
6255 			"MAXNETS (%d), MBXPERNET (%d)\n",
6256 			proc, domid, phase,
6257 			(IDN_CFGPARAM_ARG(cfg_subtype.param.p[0])
6258 			    == IDNCFGARG_DATAMBOX_INDEX)
6259 			    ? "INDEX" : "DOMAIN",
6260 			(mbox_index == IDN_NIL_DOMID)
6261 			    ? mbox_domain : mbox_index,
6262 			    IDN_MAX_NETS, IDN_MBOX_PER_NET);
6263 
6264 		IDNXDC(domid, &mt, cfg_subtype.val,
6265 			((mbox_index == IDN_NIL_DOMID)
6266 				? mbox_domain : mbox_index),
6267 			IDN_MAX_NETS, IDN_MBOX_PER_NET);
6268 		break;
6269 
6270 	case 2:
6271 		cpus_u32 = UPPER32_CPUMASK(ldp->dcpuset);
6272 		cpus_l32 = LOWER32_CPUMASK(ldp->dcpuset);
6273 		/*
6274 		 * ----------------------------------------------------
6275 		 * Send: NETID, CPUSET
6276 		 * ----------------------------------------------------
6277 		 */
6278 		cfg_subtype.val = 0;
6279 		cfg_subtype.param.p[0] = IDN_CFGPARAM(IDNCFG_NETID, 0);
6280 		cfg_subtype.param.p[1] = IDN_CFGPARAM(IDNCFG_CPUSET,
6281 						    IDNCFGARG_CPUSET_UPPER);
6282 		cfg_subtype.param.p[2] = IDN_CFGPARAM(IDNCFG_CPUSET,
6283 						    IDNCFGARG_CPUSET_LOWER);
6284 		cfg_subtype.info.num = 3;
6285 		cfg_subtype.info.phase = phase;
6286 		dp->dcfgphase = phase;
6287 
6288 		PR_PROTO("%s:%d:%d: sending NETID (%d), "
6289 			"CPUSET (0x%x.%x)\n", proc, domid, phase,
6290 			ldp->dnetid, cpus_u32, cpus_l32);
6291 
6292 		IDNXDC(domid, &mt, cfg_subtype.val,
6293 			(uint_t)ldp->dnetid, cpus_u32, cpus_l32);
6294 		break;
6295 
6296 	case 3:
6297 		/*
6298 		 * ----------------------------------------------------
6299 		 * Send: BOARDSET, MTU, BUFSIZE
6300 		 * ----------------------------------------------------
6301 		 */
6302 		cfg_subtype.val = 0;
6303 		cfg_subtype.param.p[0] = IDN_CFGPARAM(IDNCFG_BOARDSET, 0);
6304 		cfg_subtype.param.p[1] = IDN_CFGPARAM(IDNCFG_SIZE,
6305 							IDNCFGARG_SIZE_MTU);
6306 		cfg_subtype.param.p[2] = IDN_CFGPARAM(IDNCFG_SIZE,
6307 							IDNCFGARG_SIZE_BUF);
6308 		cfg_subtype.info.num = 3;
6309 		cfg_subtype.info.phase = phase;
6310 		dp->dcfgphase = phase;
6311 
6312 		PR_PROTO("%s:%d:%d: sending BOARDSET (0x%x), MTU (0x%lx), "
6313 			"BUFSIZE (0x%x)\n",
6314 			proc, domid, phase, ldp->dhw.dh_boardset, IDN_MTU,
6315 			IDN_SMR_BUFSIZE);
6316 
6317 		IDNXDC(domid, &mt, cfg_subtype.val,
6318 			ldp->dhw.dh_boardset, IDN_MTU, IDN_SMR_BUFSIZE);
6319 		break;
6320 
6321 	case 4:
6322 		/*
6323 		 * ----------------------------------------------------
6324 		 * Send: SLABSIZE, OPTIONS.CHECKSUM, NWR_SIZE
6325 		 * ----------------------------------------------------
6326 		 */
6327 		cfg_subtype.val = 0;
6328 		cfg_subtype.param.p[0] = IDN_CFGPARAM(IDNCFG_SIZE,
6329 						    IDNCFGARG_SIZE_SLAB);
6330 		cfg_subtype.param.p[1] = IDN_CFGPARAM(IDNCFG_OPTIONS,
6331 						    IDNCFGARG_CHECKSUM);
6332 		cfg_subtype.param.p[2] = IDN_CFGPARAM(IDNCFG_SIZE,
6333 						    IDNCFGARG_SIZE_NWR);
6334 		cfg_subtype.info.num = 3;
6335 		cfg_subtype.info.phase = phase;
6336 		dp->dcfgphase = phase;
6337 
6338 		PR_PROTO("%s:%d:%d: sending SLABSIZE (%d), CKSUM (%d), "
6339 			"NWRSIZE (%d)\n",
6340 			proc, domid, phase, IDN_SLAB_BUFCOUNT,
6341 			IDN_CHECKSUM, IDN_NWR_SIZE);
6342 
6343 		IDNXDC(domid, &mt, cfg_subtype.val,
6344 			IDN_SLAB_BUFCOUNT, IDN_CHECKSUM, IDN_NWR_SIZE);
6345 		break;
6346 
6347 	default:
6348 		rv = 1;
6349 		break;
6350 	}
6351 
6352 	return (rv);
6353 }
6354 
6355 #define	CFG_FATAL	((uint_t)-1)	/* reset link */
6356 #define	CFG_CONTINUE	0x0000		/* looking for more */
6357 #define	CFG_DONE	0x0001		/* got everything expected */
6358 #define	CFG_ERR_MTU	0x0002
6359 #define	CFG_ERR_BUF	0x0004
6360 #define	CFG_ERR_SLAB	0x0008
6361 #define	CFG_ERR_NWR	0x0010
6362 #define	CFG_ERR_NETS	0x0020
6363 #define	CFG_ERR_MBOX	0x0040
6364 #define	CFG_ERR_NMCADR	0x0080
6365 #define	CFG_ERR_MCADR	0x0100
6366 #define	CFG_ERR_CKSUM	0x0200
6367 #define	CFG_ERR_SMR	0x0400
6368 #define	CFG_MAX_ERRORS	16
6369 
6370 #define	CFGERR2IDNKERR(ce) \
6371 	(((ce) & CFG_ERR_MTU)	? IDNKERR_CONFIG_MTU 	: \
6372 	((ce) & CFG_ERR_BUF)	? IDNKERR_CONFIG_BUF 	: \
6373 	((ce) & CFG_ERR_SLAB)	? IDNKERR_CONFIG_SLAB 	: \
6374 	((ce) & CFG_ERR_NWR)	? IDNKERR_CONFIG_NWR 	: \
6375 	((ce) & CFG_ERR_NETS)	? IDNKERR_CONFIG_NETS 	: \
6376 	((ce) & CFG_ERR_MBOX)	? IDNKERR_CONFIG_MBOX 	: \
6377 	((ce) & CFG_ERR_NMCADR)	? IDNKERR_CONFIG_NMCADR	: \
6378 	((ce) & CFG_ERR_MCADR)	? IDNKERR_CONFIG_MCADR	: \
6379 	((ce) & CFG_ERR_CKSUM)	? IDNKERR_CONFIG_CKSUM	: \
6380 	((ce) & CFG_ERR_SMR)	? IDNKERR_CONFIG_SMR	: 0)
6381 
6382 #define	CFGERR2FINARG(ce) \
6383 	(((ce) & CFG_ERR_MTU)	? IDNFIN_ARG_CFGERR_MTU    : \
6384 	((ce) & CFG_ERR_BUF)	? IDNFIN_ARG_CFGERR_BUF    : \
6385 	((ce) & CFG_ERR_SLAB)	? IDNFIN_ARG_CFGERR_SLAB   : \
6386 	((ce) & CFG_ERR_NWR)	? IDNFIN_ARG_CFGERR_NWR    : \
6387 	((ce) & CFG_ERR_NETS)	? IDNFIN_ARG_CFGERR_NETS   : \
6388 	((ce) & CFG_ERR_MBOX)	? IDNFIN_ARG_CFGERR_MBOX   : \
6389 	((ce) & CFG_ERR_NMCADR)	? IDNFIN_ARG_CFGERR_NMCADR : \
6390 	((ce) & CFG_ERR_MCADR)	? IDNFIN_ARG_CFGERR_MCADR  : \
6391 	((ce) & CFG_ERR_CKSUM)	? IDNFIN_ARG_CFGERR_CKSUM  : \
6392 	((ce) & CFG_ERR_SMR)	? IDNFIN_ARG_CFGERR_SMR	   : IDNFIN_ARG_NONE)
6393 
6394 /*
6395  * Called when some CFG messages arrive.  We use dncfgitems to count the
6396  * total number of items received so far since we'll receive multiple CFG
6397  * messages during the CONFIG phase.  Note that dncfgitems is initialized
6398  * in idn_send_config.
6399  */
6400 static void
6401 idn_recv_config(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs)
6402 {
6403 	uint_t		msg = mtp->mt_mtype;
6404 	uint_t		rv, rv_expected, rv_actual;
6405 	int		pnum;
6406 	int		phase;
6407 	register int	p;
6408 	register int	c;
6409 	idn_mainmbox_t	*mmp;
6410 	register uint_t	subtype, subtype_arg;
6411 	idn_domain_t	*dp;
6412 	int		index;
6413 	idn_domain_t	*ldp = &idn_domain[idn.localid];
6414 	idn_mboxtbl_t	*mbtp;
6415 	idn_cfgsubtype_t	cfg_subtype;
6416 	idn_xdcargs_t	cfg_arg;
6417 	idn_msgtype_t	mt;
6418 	idnsb_error_t	idnerr;
6419 	procname_t	proc = "idn_recv_config";
6420 
6421 	ASSERT(domid != idn.localid);
6422 
6423 	GET_XARGS(xargs, &cfg_subtype.val, &cfg_arg[0], &cfg_arg[1],
6424 			&cfg_arg[2]);
6425 	cfg_arg[3] = 0;
6426 
6427 	dp = &idn_domain[domid];
6428 
6429 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
6430 
6431 	if (dp->dstate != IDNDS_CONFIG) {
6432 		/*
6433 		 * Not ready to receive config info.
6434 		 * Drop whatever he sent us.  Let the
6435 		 * timer continue and timeout if needed.
6436 		 */
6437 		PR_PROTO("%s:%d: WARNING state(%s) != CONFIG\n",
6438 			proc, domid, idnds_str[dp->dstate]);
6439 		return;
6440 	}
6441 
6442 	if ((msg & IDNP_ACKNACK_MASK) || dp->dcfgsnddone) {
6443 		IDN_MSGTIMER_STOP(domid, IDNP_CFG, 0);
6444 	}
6445 
6446 	if (msg & IDNP_ACKNACK_MASK) {
6447 		/*
6448 		 * ack/cfg
6449 		 */
6450 		phase = GET_XARGS_CFG_PHASE(xargs);
6451 
6452 		PR_PROTO("%s:%d: received ACK for CFG phase %d\n",
6453 			proc, domid, phase);
6454 		if (phase != (int)dp->dcfgphase) {
6455 			/*
6456 			 * Phase is not what we were
6457 			 * expecting.  Something got lost
6458 			 * in the shuffle.  Restart the
6459 			 * timer and let it timeout if necessary
6460 			 * and reestablish the connection.
6461 			 */
6462 			IDN_MSGTIMER_START(domid, IDNP_CFG, dp->dcfgphase,
6463 					idn_msg_waittime[IDNP_CFG], NULL);
6464 		} else {
6465 			idn_send_config(domid, phase + 1);
6466 
6467 			if (dp->dcfgsnddone && dp->dcfgrcvdone) {
6468 				IDN_DUNLOCK(domid);
6469 				IDN_SYNC_LOCK();
6470 				IDN_DLOCK_EXCL(domid);
6471 				if (dp->dstate == IDNDS_CONFIG) {
6472 					dp->dxp = &xphase_con;
6473 					IDN_XSTATE_TRANSITION(dp, IDNXS_PEND);
6474 					bzero(xargs, sizeof (xargs));
6475 
6476 					idn_xphase_transition(domid, NULL,
6477 								xargs);
6478 				}
6479 				IDN_SYNC_UNLOCK();
6480 			}
6481 		}
6482 		return;
6483 	}
6484 
6485 	pnum = (int)cfg_subtype.info.num;
6486 	phase = (int)cfg_subtype.info.phase;
6487 
6488 	for (p = 0; p < pnum; p++) {
6489 		int	board;
6490 #ifdef DEBUG
6491 		uint_t	val;
6492 		char	*str;
6493 
6494 		val = 0;
6495 		str = NULL;
6496 #define	RCVCFG(s, v)	{ str = (s); val = (v); }
6497 #else
6498 #define	RCVCFG(s, v)	{}
6499 #endif /* DEBUG */
6500 
6501 		subtype	    = IDN_CFGPARAM_TYPE(cfg_subtype.param.p[p]);
6502 		subtype_arg = IDN_CFGPARAM_ARG(cfg_subtype.param.p[p]);
6503 
6504 		switch (subtype) {
6505 
6506 		case IDNCFG_BARLAR:
6507 			IDN_GLOCK_EXCL();
6508 			switch (subtype_arg) {
6509 
6510 			case IDNCFGARG_BARLAR_BAR:
6511 				if (idn.smr.rempfn == PFN_INVALID) {
6512 					idn.smr.rempfn = (pfn_t)cfg_arg[p];
6513 					dp->dncfgitems++;
6514 					RCVCFG("BARLAR_BAR", cfg_arg[p]);
6515 				}
6516 				break;
6517 
6518 			case IDNCFGARG_BARLAR_LAR:
6519 				if (idn.smr.rempfnlim == PFN_INVALID) {
6520 					idn.smr.rempfnlim = (pfn_t)cfg_arg[p];
6521 					dp->dncfgitems++;
6522 					RCVCFG("BARLAR_LAR", cfg_arg[p]);
6523 				}
6524 				break;
6525 
6526 			default:
6527 				cmn_err(CE_WARN,
6528 					"IDN 217: unknown CFGARG type (%d) "
6529 					"from domain %d",
6530 					subtype_arg, domid);
6531 				break;
6532 			}
6533 			IDN_GUNLOCK();
6534 			break;
6535 
6536 		case IDNCFG_MCADR:
6537 			board = subtype_arg;
6538 			if ((board >= 0) && (board < MAX_BOARDS) &&
6539 			    (dp->dhw.dh_mcadr[board] == 0)) {
6540 				dp->dhw.dh_mcadr[board] = cfg_arg[p];
6541 				dp->dncfgitems++;
6542 				RCVCFG("MCADR", cfg_arg[p]);
6543 			}
6544 			break;
6545 
6546 		case IDNCFG_NMCADR:
6547 			if (dp->dhw.dh_nmcadr == 0) {
6548 				dp->dhw.dh_nmcadr = cfg_arg[p];
6549 				dp->dncfgitems++;
6550 				RCVCFG("NMCADR", cfg_arg[p]);
6551 			}
6552 			break;
6553 
6554 		case IDNCFG_CPUSET:
6555 			switch (subtype_arg) {
6556 
6557 			case IDNCFGARG_CPUSET_UPPER:
6558 			{
6559 				cpuset_t	tmpset;
6560 
6561 				MAKE64_CPUMASK(tmpset, cfg_arg[p], 0);
6562 				CPUSET_OR(dp->dcpuset, tmpset);
6563 				dp->dncfgitems++;
6564 				RCVCFG("CPUSET_UPPER", cfg_arg[p]);
6565 				break;
6566 			}
6567 			case IDNCFGARG_CPUSET_LOWER:
6568 			{
6569 				cpuset_t	tmpset;
6570 
6571 				MAKE64_CPUMASK(tmpset, 0, cfg_arg[p]);
6572 				CPUSET_OR(dp->dcpuset, tmpset);
6573 				dp->dncfgitems++;
6574 				RCVCFG("CPUSET_LOWER", cfg_arg[p]);
6575 				break;
6576 			}
6577 			default:
6578 				ASSERT(0);
6579 				break;
6580 			}
6581 			break;
6582 
6583 		case IDNCFG_NETID:
6584 			if (dp->dnetid == (ushort_t)-1) {
6585 				dp->dnetid = (ushort_t)cfg_arg[p];
6586 				dp->dncfgitems++;
6587 				RCVCFG("NETID", cfg_arg[p]);
6588 			}
6589 			break;
6590 
6591 		case IDNCFG_BOARDSET:
6592 			if ((dp->dhw.dh_boardset & cfg_arg[p])
6593 						== dp->dhw.dh_boardset) {
6594 				/*
6595 				 * Boardset better include what we
6596 				 * already know about.
6597 				 */
6598 				dp->dhw.dh_boardset = cfg_arg[p];
6599 				dp->dncfgitems++;
6600 				RCVCFG("BOARDSET", cfg_arg[p]);
6601 			}
6602 			break;
6603 
6604 		case IDNCFG_SIZE:
6605 			switch (subtype_arg) {
6606 
6607 			case IDNCFGARG_SIZE_MTU:
6608 				if (dp->dmtu == 0) {
6609 					dp->dmtu = cfg_arg[p];
6610 					dp->dncfgitems++;
6611 					RCVCFG("MTU", cfg_arg[p]);
6612 				}
6613 				break;
6614 
6615 			case IDNCFGARG_SIZE_BUF:
6616 				if (dp->dbufsize == 0) {
6617 					dp->dbufsize = cfg_arg[p];
6618 					dp->dncfgitems++;
6619 					RCVCFG("BUFSIZE", cfg_arg[p]);
6620 				}
6621 				break;
6622 
6623 			case IDNCFGARG_SIZE_SLAB:
6624 				if (dp->dslabsize == 0) {
6625 					dp->dslabsize = (short)cfg_arg[p];
6626 					dp->dncfgitems++;
6627 					RCVCFG("SLABSIZE", cfg_arg[p]);
6628 				}
6629 				break;
6630 
6631 			case IDNCFGARG_SIZE_NWR:
6632 				if (dp->dnwrsize == 0) {
6633 					dp->dnwrsize = (short)cfg_arg[p];
6634 					dp->dncfgitems++;
6635 					RCVCFG("NWRSIZE", cfg_arg[p]);
6636 				}
6637 				break;
6638 
6639 			default:
6640 				ASSERT(0);
6641 				break;
6642 			}
6643 			break;
6644 
6645 		case IDNCFG_DATAMBOX:
6646 			switch (subtype_arg) {
6647 
6648 			case IDNCFGARG_DATAMBOX_TABLE:
6649 				if (ldp->dmbox.m_tbl ||
6650 				    !dp->dvote.v.master ||
6651 				    !VALID_NWROFFSET(cfg_arg[p], 4)) {
6652 					/*
6653 					 * Only a master should be
6654 					 * sending us a datambox table.
6655 					 */
6656 					break;
6657 				}
6658 				IDN_DLOCK_EXCL(idn.localid);
6659 				ldp->dmbox.m_tbl = (idn_mboxtbl_t *)
6660 						    IDN_OFFSET2ADDR(cfg_arg[p]);
6661 				IDN_DUNLOCK(idn.localid);
6662 				dp->dncfgitems++;
6663 				RCVCFG("DATAMBOX.TABLE", cfg_arg[p]);
6664 				break;
6665 
6666 			case IDNCFGARG_DATAMBOX_DOMAIN:
6667 				if (dp->dmbox.m_send->mm_smr_mboxp ||
6668 				    !VALID_NWROFFSET(cfg_arg[p], 4))
6669 					break;
6670 				mbtp = (idn_mboxtbl_t *)
6671 						IDN_OFFSET2ADDR(cfg_arg[p]);
6672 				mmp = dp->dmbox.m_send;
6673 				for (c = 0; c < IDN_MAX_NETS; c++) {
6674 
6675 					mutex_enter(&mmp[c].mm_mutex);
6676 					mmp[c].mm_smr_mboxp = mbtp;
6677 					mutex_exit(&mmp[c].mm_mutex);
6678 
6679 					IDN_MBOXTBL_PTR_INC(mbtp);
6680 				}
6681 				if (c <= 0)
6682 					break;
6683 				dp->dncfgitems++;
6684 				RCVCFG("DATAMBOX.DOMAIN", cfg_arg[p]);
6685 				break;
6686 
6687 			case IDNCFGARG_DATAMBOX_INDEX:
6688 				if (!ldp->dvote.v.master ||
6689 				    dp->dmbox.m_send->mm_smr_mboxp) {
6690 					/*
6691 					 * If I'm not the master then
6692 					 * I can't handle processing a
6693 					 * mailbox index.
6694 					 * OR, if I already have the send
6695 					 * mailbox, I'm done with this
6696 					 * config item.
6697 					 */
6698 					break;
6699 				}
6700 				ASSERT(dp->dmbox.m_tbl);
6701 				index = (int)cfg_arg[p];
6702 				/*
6703 				 * The given index is the local domain's
6704 				 * index into the remote domain's mailbox
6705 				 * table that contains the mailbox that
6706 				 * remote domain wants the local domain to
6707 				 * use as the send mailbox for messages
6708 				 * destined for the remote domain.
6709 				 * I.e. from the remote domain's
6710 				 *	perspective, this is his receive
6711 				 *	mailbox.
6712 				 */
6713 				mbtp = IDN_MBOXTBL_PTR(dp->dmbox.m_tbl, index);
6714 				mmp = dp->dmbox.m_send;
6715 				for (c = 0; c < IDN_MAX_NETS; c++) {
6716 
6717 					mutex_enter(&mmp[c].mm_mutex);
6718 					mmp[c].mm_smr_mboxp = mbtp;
6719 					mutex_exit(&mmp[c].mm_mutex);
6720 
6721 					IDN_MBOXTBL_PTR_INC(mbtp);
6722 				}
6723 				if (c <= 0)
6724 					break;
6725 				dp->dncfgitems++;
6726 				RCVCFG("DATAMBOX.INDEX", cfg_arg[p]);
6727 				break;
6728 
6729 			default:
6730 				ASSERT(0);
6731 				break;
6732 			}
6733 			break;
6734 
6735 		case IDNCFG_DATASVR:
6736 			switch (subtype_arg) {
6737 
6738 			case IDNCFGARG_DATASVR_MAXNETS:
6739 				if (dp->dmaxnets)
6740 					break;
6741 				dp->dmaxnets = (uint_t)(cfg_arg[p] & 0x3f);
6742 				dp->dncfgitems++;
6743 				RCVCFG("DATASVR.MAXNETS", cfg_arg[p]);
6744 				break;
6745 
6746 			case IDNCFGARG_DATASVR_MBXPERNET:
6747 				if (dp->dmboxpernet)
6748 					break;
6749 				dp->dmboxpernet = (uint_t)(cfg_arg[p] & 0x1ff);
6750 				dp->dncfgitems++;
6751 				RCVCFG("DATASVR.MBXPERNET", cfg_arg[p]);
6752 				break;
6753 
6754 			default:
6755 				ASSERT(0);
6756 				break;
6757 			}
6758 			break;
6759 
6760 		case IDNCFG_OPTIONS:
6761 			switch (subtype_arg) {
6762 
6763 			case IDNCFGARG_CHECKSUM:
6764 				if (dp->dcksum)
6765 					break;
6766 				if ((cfg_arg[p] & 0xff) == 0)
6767 					dp->dcksum = 1;		/* off */
6768 				else
6769 					dp->dcksum = 2;		/* on */
6770 				dp->dncfgitems++;
6771 				RCVCFG("OPTIONS.CHECKSUM", cfg_arg[p]);
6772 				break;
6773 
6774 			default:
6775 				ASSERT(0);
6776 				break;
6777 			}
6778 
6779 		default:
6780 			break;
6781 		}
6782 #ifdef DEBUG
6783 		PR_PROTO("%s:%d: received %s (0x%x)\n",
6784 			proc, domid, str ? str : "<empty>", val);
6785 #endif /* DEBUG */
6786 	}
6787 
6788 	mt.mt_mtype = IDNP_ACK;
6789 	mt.mt_atype = IDNP_CFG;
6790 	mt.mt_cookie = mtp->mt_cookie;
6791 	CLR_XARGS(cfg_arg);
6792 	SET_XARGS_CFG_PHASE(cfg_arg, phase);
6793 	idn_send_acknack(domid, &mt, cfg_arg);
6794 
6795 	rv_expected = rv_actual = 0;
6796 
6797 	if (dp->dvote.v.master == 0) {
6798 		/*
6799 		 * Remote domain is a slave, check if we've received
6800 		 * all that we were expecting, and if so transition to
6801 		 * the next state.
6802 		 */
6803 		rv = idn_check_slave_config(domid, &rv_expected, &rv_actual);
6804 	} else {
6805 		/*
6806 		 * Remote domain is a master, check if this slave has
6807 		 * received all that it was expecting, and if so
6808 		 * transition to the next state.
6809 		 */
6810 		rv = idn_check_master_config(domid, &rv_expected, &rv_actual);
6811 	}
6812 
6813 	switch (rv) {
6814 	case CFG_DONE:
6815 		/*
6816 		 * All config info received that was expected, wrap up.
6817 		 */
6818 		if (!idn_recv_config_done(domid) && dp->dvote.v.master) {
6819 			IDN_DLOCK_EXCL(idn.localid);
6820 			ldp->dvote.v.connected = 1;
6821 			IDN_DUNLOCK(idn.localid);
6822 		}
6823 		break;
6824 
6825 	case CFG_CONTINUE:
6826 		/*
6827 		 * If we're not done sending our own config, then
6828 		 * there's no need to set a timer since one will
6829 		 * automatically be set when we send a config
6830 		 * message waiting for an acknowledgement.
6831 		 */
6832 		if (dp->dcfgsnddone) {
6833 			/*
6834 			 * We haven't yet received all the config
6835 			 * information we were expecting.  Need to
6836 			 * restart CFG timer if we've sent everything..
6837 			 */
6838 			IDN_MSGTIMER_START(domid, IDNP_CFG, 0,
6839 					idn_msg_waittime[IDNP_CFG], NULL);
6840 		}
6841 		break;
6842 
6843 	case CFG_FATAL:
6844 		/*
6845 		 * Fatal error occurred during config exchange.
6846 		 * We need to shutdown connection in this
6847 		 * case, so initiate a (non-relink) FIN.
6848 		 * so let's get the show on the road.
6849 		 */
6850 		IDN_DUNLOCK(domid);
6851 		IDN_SYNC_LOCK();
6852 		IDN_DLOCK_EXCL(domid);
6853 		/*
6854 		 * If the state has changed from CONFIG
6855 		 * then somebody else has taken over
6856 		 * control of this domain so we can just
6857 		 * bail out.
6858 		 */
6859 		if (dp->dstate == IDNDS_CONFIG) {
6860 			INIT_IDNKERR(&idnerr);
6861 			SET_IDNKERR_ERRNO(&idnerr, EPROTO);
6862 			SET_IDNKERR_IDNERR(&idnerr, IDNKERR_CONFIG_FATAL);
6863 			SET_IDNKERR_PARAM0(&idnerr, domid);
6864 			idn_update_op(IDNOP_ERROR, DOMAINSET(domid), &idnerr);
6865 			/*
6866 			 * Keep this guy around so we can try again.
6867 			 */
6868 			DOMAINSET_ADD(idn.domset.ds_relink, domid);
6869 			IDN_HISTORY_LOG(IDNH_RELINK, domid, dp->dstate,
6870 					idn.domset.ds_relink);
6871 			idn_disconnect(domid, IDNFIN_NORMAL,
6872 					IDNFIN_ARG_CFGERR_FATAL,
6873 					IDNFIN_SYNC_NO);
6874 		}
6875 		IDN_SYNC_UNLOCK();
6876 		break;
6877 
6878 	default:	/* parameter conflict */
6879 		IDN_DUNLOCK(domid);
6880 		IDN_SYNC_LOCK();
6881 		IDN_DLOCK_EXCL(domid);
6882 		if (dp->dstate != IDNDS_CONFIG) {
6883 			/*
6884 			 * Hmmm...changed in the short period
6885 			 * we had dropped the lock, oh well.
6886 			 */
6887 			IDN_SYNC_UNLOCK();
6888 			break;
6889 		}
6890 		c = 0;
6891 		for (p = 0; p < CFG_MAX_ERRORS; p++)
6892 			if (rv & (1 << p))
6893 				c++;
6894 		INIT_IDNKERR(&idnerr);
6895 		SET_IDNKERR_ERRNO(&idnerr, EINVAL);
6896 		SET_IDNKERR_PARAM0(&idnerr, domid);
6897 		if (c > 1) {
6898 			SET_IDNKERR_IDNERR(&idnerr, IDNKERR_CONFIG_MULTIPLE);
6899 			SET_IDNKERR_PARAM1(&idnerr, c);
6900 		} else {
6901 			SET_IDNKERR_IDNERR(&idnerr, CFGERR2IDNKERR(rv));
6902 			SET_IDNKERR_PARAM1(&idnerr, rv_expected);
6903 			SET_IDNKERR_PARAM2(&idnerr, rv_actual);
6904 		}
6905 		/*
6906 		 * Any parameter conflicts are grounds for dismissal.
6907 		 */
6908 		if (idn.domset.ds_connected == 0) {
6909 			domainset_t	domset;
6910 			/*
6911 			 * We have no other connections yet.
6912 			 * We must blow out of here completely
6913 			 * unless we have relinkers left from
6914 			 * a RECONFIG.
6915 			 */
6916 			IDN_GLOCK_EXCL();
6917 			domset = ~idn.domset.ds_relink;
6918 			if (idn.domset.ds_relink == 0) {
6919 				IDN_GSTATE_TRANSITION(IDNGS_DISCONNECT);
6920 			}
6921 			domset &= ~idn.domset.ds_hitlist;
6922 			IDN_SET_NEW_MASTERID(IDN_NIL_DOMID);
6923 			IDN_GUNLOCK();
6924 			IDN_DUNLOCK(domid);
6925 
6926 			DOMAINSET_DEL(domset, idn.localid);
6927 
6928 			idn_update_op(IDNOP_ERROR, DOMAINSET_ALL, &idnerr);
6929 
6930 			PR_HITLIST("%s:%d: unlink_domainset(%x) due to "
6931 				"CFG error (relink=%x, hitlist=%x)\n",
6932 				proc, domid, domset, idn.domset.ds_relink,
6933 				idn.domset.ds_hitlist);
6934 
6935 			idn_unlink_domainset(domset, IDNFIN_NORMAL,
6936 						CFGERR2FINARG(rv),
6937 						IDNFIN_OPT_UNLINK,
6938 						BOARDSET_ALL);
6939 			IDN_SYNC_UNLOCK();
6940 			IDN_DLOCK_EXCL(domid);
6941 		} else {
6942 			PR_HITLIST("%s:%d: idn_disconnect(%d) due to CFG "
6943 				"error (conn=%x, relink=%x, hitlist=%x)\n",
6944 				proc, domid, domid, idn.domset.ds_connected,
6945 				idn.domset.ds_relink, idn.domset.ds_hitlist);
6946 			/*
6947 			 * If we have other connections then
6948 			 * we're only going to blow away this
6949 			 * single connection.
6950 			 */
6951 			idn_update_op(IDNOP_ERROR, DOMAINSET(domid), &idnerr);
6952 
6953 			DOMAINSET_DEL(idn.domset.ds_relink, domid);
6954 			idn_disconnect(domid, IDNFIN_NORMAL,
6955 					CFGERR2FINARG(rv), IDNFIN_SYNC_NO);
6956 			IDN_SYNC_UNLOCK();
6957 		}
6958 		break;
6959 	}
6960 }
6961 
6962 /*
6963  * Called by master or slave which expects exactly the following
6964  * with respect to config info received from a SLAVE:
6965  * 	IDNCFG_CPUSET
6966  *	IDNCFG_NETID
6967  *	IDNCFG_BOARDSET
6968  *	IDNCFG_SIZE (MTU, BUF, SLAB, NWR)
6969  *	IDNCFG_DATAMBOX (DOMAIN or INDEX if caller is master)
6970  *	IDNCFG_DATASVR (MAXNETS, MBXPERNET)
6971  *	IDNCFG_OPTIONS (CHECKSUM)
6972  */
6973 static uint_t
6974 idn_check_slave_config(int domid, uint_t *exp, uint_t *act)
6975 {
6976 	uint_t		rv = 0;
6977 	idn_domain_t	*ldp, *dp;
6978 	procname_t	proc = "idn_check_slave_config";
6979 
6980 	dp = &idn_domain[domid];
6981 	ldp = &idn_domain[idn.localid];
6982 
6983 	ASSERT(domid != idn.localid);
6984 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
6985 	ASSERT(dp->dstate == IDNDS_CONFIG);
6986 
6987 	PR_PROTO("%s:%d: number received %d, number expected %d\n",
6988 		proc, domid, (int)dp->dncfgitems, IDN_SLAVE_NCFGITEMS);
6989 
6990 	if ((int)dp->dncfgitems < IDN_SLAVE_NCFGITEMS)
6991 		return (CFG_CONTINUE);
6992 
6993 	if ((dp->dnetid == (ushort_t)-1) ||
6994 	    CPUSET_ISNULL(dp->dcpuset) ||
6995 	    (dp->dhw.dh_boardset == 0) ||
6996 	    (dp->dmbox.m_send->mm_smr_mboxp == NULL) ||
6997 	    (dp->dmaxnets == 0) ||
6998 	    (dp->dmboxpernet == 0) ||
6999 	    (dp->dcksum == 0) ||
7000 	    (dp->dmtu == 0) ||
7001 	    (dp->dbufsize == 0) ||
7002 	    (dp->dslabsize == 0) ||
7003 	    (dp->dnwrsize == 0)) {
7004 		/*
7005 		 * We received our IDN_SLAVE_NCFGITEMS config items,
7006 		 * but not all what we were expecting!  Gotta nack and
7007 		 * close connection.
7008 		 */
7009 		cmn_err(CE_WARN,
7010 			"IDN: 218: missing some required config items from "
7011 			"domain %d", domid);
7012 
7013 		rv = CFG_FATAL;
7014 		goto done;
7015 	}
7016 
7017 	if (!valid_mtu(dp->dmtu)) {
7018 		cmn_err(CE_WARN,
7019 			"IDN: 219: remote domain %d MTU (%d) invalid "
7020 			"(local.mtu = %d)", dp->domid, dp->dmtu, ldp->dmtu);
7021 
7022 		*exp = (uint_t)ldp->dmtu;
7023 		*act = (uint_t)dp->dmtu;
7024 		rv |= CFG_ERR_MTU;
7025 	}
7026 	if (!valid_bufsize(dp->dbufsize)) {
7027 		cmn_err(CE_WARN,
7028 			"IDN: 220: remote domain %d BUFSIZE (%d) invalid "
7029 			"(local.bufsize = %d)", dp->domid, dp->dbufsize,
7030 			ldp->dbufsize);
7031 
7032 		*exp = (uint_t)ldp->dbufsize;
7033 		*act = (uint_t)dp->dbufsize;
7034 		rv |= CFG_ERR_BUF;
7035 	}
7036 	if (!valid_slabsize((int)dp->dslabsize)) {
7037 		cmn_err(CE_WARN,
7038 			"IDN: 221: remote domain %d SLABSIZE (%d) invalid "
7039 			"(local.slabsize = %d)",
7040 			dp->domid, dp->dslabsize, ldp->dslabsize);
7041 
7042 		*exp = (uint_t)ldp->dslabsize;
7043 		*act = (uint_t)dp->dslabsize;
7044 		rv |= CFG_ERR_SLAB;
7045 	}
7046 	if (!valid_nwrsize((int)dp->dnwrsize)) {
7047 		cmn_err(CE_WARN,
7048 			"IDN: 223: remote domain %d NWRSIZE (%d) invalid "
7049 			"(local.nwrsize = %d)",
7050 			dp->domid, dp->dnwrsize, ldp->dnwrsize);
7051 
7052 		*exp = (uint_t)ldp->dnwrsize;
7053 		*act = (uint_t)dp->dnwrsize;
7054 		rv |= CFG_ERR_NWR;
7055 	}
7056 	if ((int)dp->dmaxnets != IDN_MAX_NETS) {
7057 		cmn_err(CE_WARN,
7058 			"IDN: 224: remote domain %d MAX_NETS (%d) invalid "
7059 			"(local.maxnets = %d)",
7060 			dp->domid, (int)dp->dmaxnets, IDN_MAX_NETS);
7061 
7062 		*exp = (uint_t)IDN_MAX_NETS;
7063 		*act = (uint_t)dp->dmaxnets;
7064 		rv |= CFG_ERR_NETS;
7065 	}
7066 	if ((int)dp->dmboxpernet != IDN_MBOX_PER_NET) {
7067 		cmn_err(CE_WARN,
7068 			"IDN: 225: remote domain %d MBOX_PER_NET (%d) "
7069 			"invalid (local.mboxpernet = %d)",
7070 			dp->domid, (int)dp->dmboxpernet, IDN_MBOX_PER_NET);
7071 
7072 		*exp = (uint_t)IDN_MBOX_PER_NET;
7073 		*act = (uint_t)dp->dmboxpernet;
7074 		rv |= CFG_ERR_MBOX;
7075 	}
7076 	if ((dp->dcksum - 1) != (uchar_t)IDN_CHECKSUM) {
7077 		cmn_err(CE_WARN,
7078 			"IDN: 226: remote domain %d CHECKSUM flag (%d) "
7079 			"mismatches local domain's (%d)",
7080 			dp->domid, (int)dp->dcksum - 1, IDN_CHECKSUM);
7081 
7082 		*exp = (uint_t)IDN_CHECKSUM;
7083 		*act = (uint_t)(dp->dcksum - 1);
7084 		rv |= CFG_ERR_CKSUM;
7085 	}
7086 
7087 done:
7088 
7089 	return (rv ? rv : CFG_DONE);
7090 }
7091 
7092 /*
7093  * Called by slave ONLY which expects exactly the following
7094  * config info from the MASTER:
7095  *	IDNCFG_BARLAR
7096  *	IDNCFG_MCADR
7097  *	IDNCFG_NMCADR
7098  * 	IDNCFG_CPUSET
7099  *	IDNCFG_NETID
7100  *	IDNCFG_BOARDSET
7101  *	IDNCFG_SIZE (MTU, BUF, SLAB, NWR)
7102  *	IDNCFG_DATAMBOX (TABLE, DOMAIN)
7103  *	IDNCFG_DATASVR (MAXNETS, MBXPERNET)
7104  *	IDNCFG_OPTIONS (CHECKSUM)
7105  */
7106 static uint_t
7107 idn_check_master_config(int domid, uint_t *exp, uint_t *act)
7108 {
7109 	uint_t		rv = 0;
7110 	int		nmcadr;
7111 	int		total_expitems;
7112 	int		p, m, err;
7113 	idn_domain_t	*dp;
7114 	idn_domain_t	*ldp = &idn_domain[idn.localid];
7115 	procname_t	proc = "idn_check_master_config";
7116 
7117 	dp = &idn_domain[domid];
7118 
7119 	ASSERT(IDN_GET_MASTERID() != idn.localid);
7120 	ASSERT(domid != idn.localid);
7121 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
7122 	ASSERT(dp->dstate == IDNDS_CONFIG);
7123 
7124 	PR_PROTO("%s:%d: number received %d, minimum number expected %d\n",
7125 		proc, domid, (int)dp->dncfgitems, IDN_MASTER_NCFGITEMS);
7126 
7127 	if ((int)dp->dncfgitems < IDN_MASTER_NCFGITEMS)
7128 		return (CFG_CONTINUE);
7129 
7130 	/*
7131 	 * We have at least IDN_MASTER_NCFGITEMS items which
7132 	 * means we have at least one MCADR.  Need to make sure
7133 	 * we have all that we're expecting, NMCADR.
7134 	 */
7135 	total_expitems = IDN_MASTER_NCFGITEMS + dp->dhw.dh_nmcadr - 1;
7136 	if ((dp->dhw.dh_nmcadr == 0) ||
7137 	    ((int)dp->dncfgitems < total_expitems)) {
7138 		/*
7139 		 * We have not yet received all the MCADRs
7140 		 * we're expecting.
7141 		 */
7142 		PR_PROTO("%s:%d: haven't received all MCADRs yet.\n",
7143 			proc, domid);
7144 		return (CFG_CONTINUE);
7145 	}
7146 
7147 	nmcadr = 0;
7148 	for (p = 0; p < MAX_BOARDS; p++)
7149 		if (dp->dhw.dh_mcadr[p] != 0)
7150 			nmcadr++;
7151 
7152 	IDN_GLOCK_SHARED();
7153 	if ((idn.smr.rempfn == PFN_INVALID) ||
7154 	    (idn.smr.rempfnlim == PFN_INVALID) ||
7155 	    (dp->dnetid == (ushort_t)-1) ||
7156 	    CPUSET_ISNULL(dp->dcpuset) ||
7157 	    (dp->dhw.dh_boardset == 0) ||
7158 	    (nmcadr != dp->dhw.dh_nmcadr) ||
7159 	    (dp->dmbox.m_send->mm_smr_mboxp == NULL) ||
7160 	    (ldp->dmbox.m_tbl == NULL) ||
7161 	    (dp->dmaxnets == 0) ||
7162 	    (dp->dmboxpernet == 0) ||
7163 	    (dp->dcksum == 0) ||
7164 	    (dp->dmtu == 0) ||
7165 	    (dp->dbufsize == 0) ||
7166 	    (dp->dnwrsize == 0)) {
7167 
7168 		IDN_GUNLOCK();
7169 		/*
7170 		 * We received all of our config items, but not
7171 		 * all what we were expecting!  Gotta reset and
7172 		 * close connection.
7173 		 */
7174 		cmn_err(CE_WARN,
7175 			"IDN: 227: missing some required config items from "
7176 			"domain %d", domid);
7177 
7178 		rv = CFG_FATAL;
7179 		goto done;
7180 	}
7181 	if ((idn.smr.rempfnlim - idn.smr.rempfn) > btop(MB2B(IDN_SMR_SIZE))) {
7182 		/*
7183 		 * The master's SMR region is larger than
7184 		 * mine!  This means that this domain may
7185 		 * receive I/O buffers which are out of the
7186 		 * range of this local domain's SMR virtual
7187 		 * address space.  The master SMR has to be
7188 		 * no larger than the local SMR in order to
7189 		 * guarantee enough local virtual addresses
7190 		 * to see all of the SMR space.
7191 		 * XXX - Possibly add negotiating SMR size.
7192 		 *	 Try to create a new virtual mapping.
7193 		 *	 Could let domains negotiate SMR size.
7194 		 *	 Winning size would have to be smallest
7195 		 *	 in DC.  If so, how to handle incoming
7196 		 *	 domains with even smaller SMRs?
7197 		 *	 - Could either disallow connection
7198 		 *	 - Could reconfigure to use smaller SMR.
7199 		 */
7200 		cmn_err(CE_WARN,
7201 			"IDN: 228: master's SMR (%ld) larger than "
7202 			"local's SMR (%ld)",
7203 			idn.smr.rempfnlim - idn.smr.rempfn,
7204 			btop(MB2B(IDN_SMR_SIZE)));
7205 
7206 		*exp = (uint_t)IDN_SMR_SIZE;
7207 		*act = (uint_t)B2MB(ptob(idn.smr.rempfnlim - idn.smr.rempfn));
7208 		rv |= CFG_ERR_SMR;
7209 	}
7210 	IDN_GUNLOCK();
7211 
7212 	if (!valid_mtu(dp->dmtu)) {
7213 		cmn_err(CE_WARN,
7214 			"IDN: 219: remote domain %d MTU (%d) invalid "
7215 			"(local.mtu = %d)", dp->domid, dp->dmtu, ldp->dmtu);
7216 
7217 		*exp = (uint_t)ldp->dmtu;
7218 		*act = (uint_t)dp->dmtu;
7219 		rv |= CFG_ERR_MTU;
7220 	}
7221 	if (!valid_bufsize(dp->dbufsize)) {
7222 		cmn_err(CE_WARN,
7223 			"IDN: 220: remote domain %d BUFSIZE (%d) invalid "
7224 			"(local.bufsize = %d)", dp->domid, dp->dbufsize,
7225 			ldp->dbufsize);
7226 
7227 		*exp = (uint_t)ldp->dbufsize;
7228 		*act = (uint_t)dp->dbufsize;
7229 		rv |= CFG_ERR_BUF;
7230 	}
7231 	if (!valid_nwrsize((int)dp->dnwrsize)) {
7232 		cmn_err(CE_WARN,
7233 			"IDN: 223: remote domain %d NWRSIZE (%d) invalid "
7234 			"(local.nwrsize = %d)",
7235 			dp->domid, dp->dnwrsize, ldp->dnwrsize);
7236 
7237 		*exp = (uint_t)ldp->dnwrsize;
7238 		*act = (uint_t)dp->dnwrsize;
7239 		rv |= CFG_ERR_NWR;
7240 	}
7241 	if ((int)dp->dmaxnets != IDN_MAX_NETS) {
7242 		cmn_err(CE_WARN,
7243 			"IDN: 224: remote domain %d MAX_NETS (%d) invalid "
7244 			"(local.maxnets = %d)",
7245 			dp->domid, (int)dp->dmaxnets, IDN_MAX_NETS);
7246 
7247 		*exp = (uint_t)IDN_MAX_NETS;
7248 		*act = (uint_t)dp->dmaxnets;
7249 		rv |= CFG_ERR_NETS;
7250 	}
7251 	if ((int)dp->dmboxpernet != IDN_MBOX_PER_NET) {
7252 		cmn_err(CE_WARN,
7253 			"IDN: 225: remote domain %d MBOX_PER_NET (%d) "
7254 			"invalid (local.mboxpernet = %d)",
7255 			dp->domid, (int)dp->dmboxpernet, IDN_MBOX_PER_NET);
7256 
7257 		*exp = (uint_t)IDN_MBOX_PER_NET;
7258 		*act = (uint_t)dp->dmboxpernet;
7259 		rv |= CFG_ERR_MBOX;
7260 	}
7261 	if ((dp->dcksum - 1) != (uchar_t)IDN_CHECKSUM) {
7262 		cmn_err(CE_WARN,
7263 			"IDN: 226: remote domain %d CHECKSUM flag (%d) "
7264 			"mismatches local domain's (%d)",
7265 			dp->domid, (int)dp->dcksum - 1, IDN_CHECKSUM);
7266 
7267 		*exp = (uint_t)IDN_CHECKSUM;
7268 		*act = (uint_t)(dp->dcksum - 1);
7269 		rv |= CFG_ERR_CKSUM;
7270 	}
7271 	nmcadr = 0;
7272 	err = 0;
7273 	for (m = 0; m < MAX_BOARDS; m++) {
7274 		if (!BOARD_IN_SET(dp->dhw.dh_boardset, m) &&
7275 				dp->dhw.dh_mcadr[m]) {
7276 			cmn_err(CE_WARN,
7277 				"IDN: 229: remote domain %d boardset (0x%x) "
7278 				"conflicts with MCADR(board %d) [0x%x]",
7279 				dp->domid, (uint_t)dp->dhw.dh_boardset, m,
7280 				dp->dhw.dh_mcadr[m]);
7281 			err++;
7282 		}
7283 		if (dp->dhw.dh_mcadr[m])
7284 			nmcadr++;
7285 	}
7286 	if (err) {
7287 		*exp = 0;
7288 		*act = err;
7289 		rv |= CFG_ERR_MCADR;
7290 	} else if (nmcadr != dp->dhw.dh_nmcadr) {
7291 		cmn_err(CE_WARN,
7292 			"IDN: 230: remote domain %d reported number of "
7293 			"MCADRs (%d) mismatches received (%d)",
7294 			dp->domid, dp->dhw.dh_nmcadr, nmcadr);
7295 		*exp = (uint_t)dp->dhw.dh_nmcadr;
7296 		*act = (uint_t)nmcadr;
7297 		rv |= CFG_ERR_NMCADR;
7298 	}
7299 
7300 done:
7301 
7302 	return (rv ? rv : CFG_DONE);
7303 }
7304 
7305 static int
7306 idn_recv_config_done(int domid)
7307 {
7308 	boardset_t		b_conflicts;
7309 	cpuset_t		p_conflicts;
7310 	register int		p, i;
7311 	register idn_domain_t	*dp;
7312 	idnsb_error_t		idnerr;
7313 	procname_t		proc = "idn_recv_config_done";
7314 
7315 	ASSERT(domid != IDN_NIL_DOMID);
7316 	dp = &idn_domain[domid];
7317 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
7318 
7319 	/*
7320 	 * Well, we received all that we were expecting
7321 	 * so stop any CFG timers we had going.
7322 	 */
7323 	IDN_MSGTIMER_STOP(domid, IDNP_CFG, 0);
7324 
7325 	dp->dncpus = 0;
7326 	for (p = 0; p < NCPU; p++)
7327 		if (CPU_IN_SET(dp->dcpuset, p))
7328 			dp->dncpus++;
7329 	dp->dhw.dh_nboards = 0;
7330 	for (p = 0; p < MAX_BOARDS; p++)
7331 		if (BOARD_IN_SET(dp->dhw.dh_boardset, p))
7332 			dp->dhw.dh_nboards++;
7333 
7334 	IDN_GLOCK_EXCL();
7335 	/*
7336 	 * Verify dcpuset and dhw.dh_boardset don't
7337 	 * conflict with any existing DC member.
7338 	 */
7339 	b_conflicts = idn.dc_boardset & dp->dhw.dh_boardset;
7340 	CPUSET_ZERO(p_conflicts);
7341 	CPUSET_OR(p_conflicts, idn.dc_cpuset);
7342 	CPUSET_AND(p_conflicts, dp->dcpuset);
7343 
7344 	if (b_conflicts || !CPUSET_ISNULL(p_conflicts)) {
7345 		if (b_conflicts) {
7346 			cmn_err(CE_WARN,
7347 				"IDN: 231: domain %d boardset "
7348 				"(0x%x) conflicts with existing "
7349 				"IDN boardset (0x%x)",
7350 				domid, dp->dhw.dh_boardset,
7351 				b_conflicts);
7352 		}
7353 		if (!CPUSET_ISNULL(p_conflicts)) {
7354 			cmn_err(CE_WARN,
7355 				"IDN: 232: domain %d cpuset "
7356 				"(0x%x.%0x) conflicts with existing "
7357 				"IDN cpuset (0x%x.%0x)", domid,
7358 				UPPER32_CPUMASK(dp->dcpuset),
7359 				LOWER32_CPUMASK(dp->dcpuset),
7360 				UPPER32_CPUMASK(p_conflicts),
7361 				LOWER32_CPUMASK(p_conflicts));
7362 		}
7363 		IDN_GUNLOCK();
7364 		/*
7365 		 * Need to disconnect and not retry with this guy.
7366 		 */
7367 		IDN_DUNLOCK(domid);
7368 		IDN_SYNC_LOCK();
7369 		DOMAINSET_DEL(idn.domset.ds_relink, domid);
7370 		IDN_DLOCK_EXCL(domid);
7371 
7372 		INIT_IDNKERR(&idnerr);
7373 		SET_IDNKERR_ERRNO(&idnerr, EPROTO);
7374 		SET_IDNKERR_IDNERR(&idnerr, IDNKERR_CONFIG_FATAL);
7375 		SET_IDNKERR_PARAM0(&idnerr, domid);
7376 		idn_update_op(IDNOP_ERROR, DOMAINSET(domid), &idnerr);
7377 
7378 		idn_disconnect(domid, IDNFIN_FORCE_HARD,
7379 				IDNFIN_ARG_CFGERR_FATAL, IDNFIN_SYNC_NO);
7380 		IDN_SYNC_UNLOCK();
7381 
7382 		return (-1);
7383 	}
7384 
7385 	idn_mainmbox_reset(domid, dp->dmbox.m_send);
7386 	idn_mainmbox_reset(domid, dp->dmbox.m_recv);
7387 
7388 #ifdef IDNBUG_CPUPERBOARD
7389 	/*
7390 	 * We only allow connections to domains whose (mem) boards
7391 	 * all have at least one cpu.  This is necessary so that
7392 	 * we can program the CICs of that respective board.  This
7393 	 * is primarily only a requirement if the remote domain
7394 	 * is the master _and_ has the SMR in that particular board.
7395 	 * To simplify the checking we simply restrict connections to
7396 	 * domains that have at least one cpu on all boards that
7397 	 * contain memory.
7398 	 */
7399 	if (!idn_cpu_per_board((void *)NULL, dp->dcpuset, &dp->dhw)) {
7400 		cmn_err(CE_WARN,
7401 			"IDN: 233: domain %d missing CPU per "
7402 			"memory boardset (0x%x), CPU boardset (0x%x)",
7403 			domid, dp->dhw.dh_boardset,
7404 			cpuset2boardset(dp->dcpuset));
7405 
7406 		IDN_GUNLOCK();
7407 		/*
7408 		 * Need to disconnect and not retry with this guy.
7409 		 */
7410 		IDN_DUNLOCK(domid);
7411 		IDN_SYNC_LOCK();
7412 		DOMAINSET_DEL(idn.domset.ds_relink, domid);
7413 		IDN_DLOCK_EXCL(domid);
7414 
7415 		INIT_IDNKERR(&idnerr);
7416 		SET_IDNKERR_ERRNO(&idnerr, EINVAL);
7417 		SET_IDNKERR_IDNERR(&idnerr, IDNKERR_CPU_CONFIG);
7418 		SET_IDNKERR_PARAM0(&idnerr, domid);
7419 		idn_update_op(IDNOP_ERROR, DOMAINSET(domid), &idnerr);
7420 
7421 		idn_disconnect(domid, IDNFIN_FORCE_HARD,
7422 				IDNFIN_ARG_CPUCFG, IDNFIN_SYNC_NO);
7423 		IDN_SYNC_UNLOCK();
7424 
7425 		return (-1);
7426 	}
7427 #endif /* IDNBUG_CPUPERBOARD */
7428 
7429 	CPUSET_OR(idn.dc_cpuset, dp->dcpuset);
7430 	idn.dc_boardset |= dp->dhw.dh_boardset;
7431 
7432 	IDN_GUNLOCK();
7433 
7434 	/*
7435 	 * Set up the portmap for this domain.
7436 	 */
7437 	i = -1;
7438 	for (p = 0; p < NCPU; p++) {
7439 		BUMP_INDEX(dp->dcpuset, i);
7440 		dp->dcpumap[p] = (uchar_t)i;
7441 	}
7442 
7443 	/*
7444 	 * Got everything we need from the remote
7445 	 * domain, now we can program hardware as needed.
7446 	 */
7447 	if (idn_program_hardware(domid) != 0) {
7448 		domainset_t	domset;
7449 		/*
7450 		 * Yikes!  Failed to program hardware.
7451 		 * Gotta bail.
7452 		 */
7453 		cmn_err(CE_WARN,
7454 			"IDN: 234: failed to program hardware for domain %d "
7455 			"(boardset = 0x%x)",
7456 			domid, dp->dhw.dh_boardset);
7457 
7458 		IDN_DUNLOCK(domid);
7459 		/*
7460 		 * If we're having problems programming our
7461 		 * hardware we better unlink completely from
7462 		 * the IDN before things get really bad.
7463 		 */
7464 		IDN_SYNC_LOCK();
7465 		IDN_GLOCK_EXCL();
7466 		IDN_GSTATE_TRANSITION(IDNGS_DISCONNECT);
7467 		domset = DOMAINSET_ALL;
7468 		DOMAINSET_DEL(domset, idn.localid);
7469 		IDN_SET_NEW_MASTERID(IDN_NIL_DOMID);
7470 		IDN_GUNLOCK();
7471 
7472 		INIT_IDNKERR(&idnerr);
7473 		SET_IDNKERR_ERRNO(&idnerr, EINVAL);
7474 		SET_IDNKERR_IDNERR(&idnerr, IDNKERR_HW_ERROR);
7475 		SET_IDNKERR_PARAM0(&idnerr, domid);
7476 		idn_update_op(IDNOP_ERROR, DOMAINSET_ALL, &idnerr);
7477 
7478 		idn_unlink_domainset(domset, IDNFIN_NORMAL, IDNFIN_ARG_HWERR,
7479 					IDNFIN_OPT_UNLINK, BOARDSET_ALL);
7480 
7481 		IDN_SYNC_UNLOCK();
7482 		IDN_DLOCK_EXCL(domid);
7483 
7484 		return (-1);
7485 	}
7486 
7487 	/*
7488 	 * Now that hardware has been programmed we can
7489 	 * remap the SMR into our local space, if necessary.
7490 	 */
7491 	IDN_GLOCK_EXCL();
7492 	if (domid == IDN_GET_MASTERID()) {
7493 		/*
7494 		 * No need to worry about disabling the data
7495 		 * server since at this stage there is only
7496 		 * one and he doesn't go active until his
7497 		 * mailbox (dmbox.m_recv->mm_smr_mboxp) is set up.
7498 		 */
7499 		smr_remap(&kas, idn.smr.vaddr, idn.smr.rempfn, IDN_SMR_SIZE);
7500 	}
7501 	IDN_GUNLOCK();
7502 
7503 	/*
7504 	 * There is no need to ACK the CFG messages since remote
7505 	 * domain would not progress to the next state (CON_SENT)
7506 	 * unless he has received everything.
7507 	 */
7508 
7509 	dp->dcfgrcvdone = 1;
7510 	PR_PROTO("%s:%d: RECV config DONE\n", proc, domid);
7511 
7512 	if (dp->dcfgsnddone) {
7513 		idn_xdcargs_t	xargs;
7514 		/*
7515 		 * Well, we've received all that we were expecting,
7516 		 * but we don't know if the remote domain has
7517 		 * received all that it was expecting from us,
7518 		 * although we know we transferred everything
7519 		 * so let's get the show on the road.
7520 		 */
7521 		IDN_DUNLOCK(domid);
7522 		IDN_SYNC_LOCK();
7523 		IDN_DLOCK_EXCL(domid);
7524 		/*
7525 		 * If the state has changed from CONFIG
7526 		 * then somebody else has taken over
7527 		 * control of this domain so we can just
7528 		 * bail out.
7529 		 */
7530 		if (dp->dstate == IDNDS_CONFIG) {
7531 			dp->dxp = &xphase_con;
7532 			IDN_XSTATE_TRANSITION(dp, IDNXS_PEND);
7533 			bzero(xargs, sizeof (xargs));
7534 
7535 			idn_xphase_transition(domid, NULL, xargs);
7536 		}
7537 		IDN_SYNC_UNLOCK();
7538 	}
7539 
7540 	return (0);
7541 }
7542 
7543 static int
7544 idn_verify_config_mbox(int domid)
7545 {
7546 	idn_domain_t	*ldp, *dp;
7547 	idn_mainmbox_t	*mmp;
7548 	idn_mboxtbl_t	*mtp;
7549 	int		c, rv = 0;
7550 	uint_t		activeptr, readyptr;
7551 	ushort_t	mbox_csum;
7552 
7553 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
7554 
7555 	dp = &idn_domain[domid];
7556 	ldp = &idn_domain[idn.localid];
7557 
7558 	/*
7559 	 * The master will have assigned us the dmbox.m_tbl
7560 	 * from which we assign our receive mailboxes.
7561 	 * The first (0) entry contains the cookie used
7562 	 * for verification.
7563 	 */
7564 	IDN_DLOCK_SHARED(idn.localid);
7565 	/*
7566 	 * Now that we have an assigned mboxtbl from the
7567 	 * master, we can determine which receive mailbox
7568 	 * we indirectly assigned to him at the time we
7569 	 * sent him his MBOX_INDEX.  Prep it, however note
7570 	 * that the master will have not been able to
7571 	 * validate it because of the chicken 'n egg
7572 	 * problem between a master and slave.  Thus we
7573 	 * need to reset the cookie after the prep.
7574 	 */
7575 	mmp = dp->dmbox.m_recv;
7576 	mtp = IDN_MBOXTBL_PTR(ldp->dmbox.m_tbl, domid);
7577 	for (c = 0; c < IDN_MAX_NETS; c++) {
7578 		mutex_enter(&mmp[c].mm_mutex);
7579 		ASSERT(!mmp[c].mm_smr_mboxp);
7580 
7581 		mmp[c].mm_smr_mboxp = mtp;
7582 		mbox_csum = IDN_CKSUM_MBOX(&mtp->mt_header);
7583 		if (!VALID_MBOXHDR(&mtp->mt_header, c, mbox_csum)) {
7584 			cmn_err(CE_WARN,
7585 				"IDN: 235: [recv] mailbox (domain %d, "
7586 				"channel %d) SMR CORRUPTED - RELINK",
7587 				domid, c);
7588 			cmn_err(CE_CONT,
7589 				"IDN: 235: [recv] expected (cookie 0x%x, "
7590 				"cksum 0x%x) actual (cookie 0x%x, "
7591 				"cksum 0x%x)\n",
7592 				IDN_GET_MBOXHDR_COOKIE(&mtp->mt_header),
7593 				(int)mtp->mt_header.mh_cksum,
7594 				IDN_MAKE_MBOXHDR_COOKIE(0, 0, c),
7595 				(int)mbox_csum);
7596 			mutex_exit(&mmp[c].mm_mutex);
7597 			rv = -1;
7598 			break;
7599 		}
7600 		activeptr = mtp->mt_header.mh_svr_active_ptr;
7601 		readyptr = mtp->mt_header.mh_svr_ready_ptr;
7602 		/*
7603 		 * Verify pointers are valid.
7604 		 */
7605 		if (!activeptr || !VALID_NWROFFSET(activeptr, 2) ||
7606 			!readyptr || !VALID_NWROFFSET(readyptr, 2)) {
7607 			cmn_err(CE_WARN,
7608 				"IDN: 235: [recv] mailbox (domain %d, "
7609 				"channel %d) SMR CORRUPTED - RELINK",
7610 				domid, c);
7611 			cmn_err(CE_CONT,
7612 				"IDN: 235: [recv] activeptr (0x%x), "
7613 				"readyptr (0x%x)\n",
7614 				activeptr, readyptr);
7615 			mutex_exit(&mmp[c].mm_mutex);
7616 			rv = -1;
7617 			break;
7618 		}
7619 		mmp[c].mm_smr_activep =
7620 			(ushort_t *)IDN_OFFSET2ADDR(activeptr);
7621 		mmp[c].mm_smr_readyp =
7622 			(ushort_t *)IDN_OFFSET2ADDR(readyptr);
7623 		mutex_exit(&mmp[c].mm_mutex);
7624 		IDN_MBOXTBL_PTR_INC(mtp);
7625 	}
7626 
7627 	IDN_DUNLOCK(idn.localid);
7628 
7629 	if (rv)
7630 		return (rv);
7631 
7632 	/*
7633 	 * Now we need to translate SMR offsets for send mailboxes
7634 	 * to actual virtual addresses.
7635 	 */
7636 	mmp = dp->dmbox.m_send;
7637 	for (c = 0; c < IDN_MAX_NETS; mmp++, c++) {
7638 		mutex_enter(&mmp->mm_mutex);
7639 		if ((mtp = mmp->mm_smr_mboxp) == NULL) {
7640 			mutex_exit(&mmp->mm_mutex);
7641 			rv = -1;
7642 			break;
7643 		}
7644 
7645 		mbox_csum = IDN_CKSUM_MBOX(&mtp->mt_header);
7646 
7647 		if (!VALID_MBOXHDR(&mtp->mt_header, c, mbox_csum)) {
7648 			cmn_err(CE_WARN,
7649 				"IDN: 235: [send] mailbox (domain %d, "
7650 				"channel %d) SMR CORRUPTED - RELINK",
7651 				domid, c);
7652 			cmn_err(CE_CONT,
7653 				"IDN: 235: [send] expected (cookie 0x%x, "
7654 				"cksum 0x%x) actual (cookie 0x%x, "
7655 				"cksum 0x%x)\n",
7656 				IDN_GET_MBOXHDR_COOKIE(&mtp->mt_header),
7657 				(int)mtp->mt_header.mh_cksum,
7658 				IDN_MAKE_MBOXHDR_COOKIE(0, 0, c),
7659 				(int)mbox_csum);
7660 			mutex_exit(&mmp->mm_mutex);
7661 			rv = -1;
7662 			break;
7663 		}
7664 		activeptr = mtp->mt_header.mh_svr_active_ptr;
7665 		readyptr = mtp->mt_header.mh_svr_ready_ptr;
7666 		/*
7667 		 * Paranoid check.
7668 		 */
7669 		if (!activeptr || !VALID_NWROFFSET(activeptr, 2) ||
7670 			!readyptr || !VALID_NWROFFSET(readyptr, 2)) {
7671 			cmn_err(CE_WARN,
7672 				"IDN: 235: [send] mailbox (domain %d, "
7673 				"channel %d) SMR CORRUPTED - RELINK",
7674 				domid, c);
7675 			cmn_err(CE_CONT,
7676 				"IDN: 235: [send] activeptr (0x%x), "
7677 				"readyptr (0x%x)\n",
7678 				activeptr, readyptr);
7679 			mutex_exit(&mmp->mm_mutex);
7680 			rv = -1;
7681 			break;
7682 		}
7683 		mmp->mm_smr_activep = (ushort_t *)IDN_OFFSET2ADDR(activeptr);
7684 		mmp->mm_smr_readyp = (ushort_t *)IDN_OFFSET2ADDR(readyptr);
7685 		idn_reset_mboxtbl(mtp);
7686 		mutex_exit(&mmp->mm_mutex);
7687 		IDN_MBOXTBL_PTR_INC(mtp);
7688 	}
7689 
7690 	return (rv);
7691 }
7692 
7693 /*
7694  * The BUFSIZEs between domains have to be equal so that slave buffers
7695  * and the master's slabpool are consistent.
7696  * The MTUs between domains have to be equal so they can transfer
7697  * packets consistently without possible data truncation.
7698  *
7699  * ZZZ - Perhaps these could be negotiated?
7700  */
7701 static int
7702 valid_mtu(uint_t mtu)
7703 {
7704 	return ((mtu == idn_domain[idn.localid].dmtu) && mtu);
7705 }
7706 
7707 static int
7708 valid_bufsize(uint_t bufsize)
7709 {
7710 	return ((bufsize == idn_domain[idn.localid].dbufsize) && bufsize);
7711 }
7712 
7713 static int
7714 valid_slabsize(int slabsize)
7715 {
7716 	return ((slabsize == idn_domain[idn.localid].dslabsize) && slabsize);
7717 }
7718 
7719 static int
7720 valid_nwrsize(int nwrsize)
7721 {
7722 	return ((nwrsize == idn_domain[idn.localid].dnwrsize) && nwrsize);
7723 }
7724 
7725 static int
7726 idn_program_hardware(int domid)
7727 {
7728 	int		rv, is_master;
7729 	idn_domain_t	*dp;
7730 	uint_t		*mcadrp;
7731 	pfn_t		rem_pfn, rem_pfnlimit;
7732 	procname_t	proc = "idn_program_hardware";
7733 
7734 	PR_PROTO("%s:%d: program hw in domain %d w.r.t remote domain %d\n",
7735 		proc, domid, idn.localid, domid);
7736 
7737 	dp = &idn_domain[domid];
7738 
7739 	ASSERT(domid != idn.localid);
7740 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
7741 	ASSERT(dp->dstate == IDNDS_CONFIG);
7742 
7743 	IDN_GLOCK_EXCL();
7744 
7745 	if (DOMAIN_IN_SET(idn.domset.ds_hwlinked, domid)) {
7746 		IDN_GUNLOCK();
7747 		return (0);
7748 	}
7749 
7750 	DOMAINSET_ADD(idn.domset.ds_flush, domid);
7751 	CHECKPOINT_OPENED(IDNSB_CHKPT_CACHE, dp->dhw.dh_boardset, 1);
7752 
7753 	if (domid != IDN_GET_MASTERID()) {
7754 		/*
7755 		 * If the remote domain is a slave, then
7756 		 * all we have to program is the CIC sm_mask.
7757 		 */
7758 		is_master = 0;
7759 		if ((idn.localid == IDN_GET_MASTERID()) &&
7760 					lock_try(&idn.first_hwlink)) {
7761 			/*
7762 			 * This is our first HW link and I'm the
7763 			 * master, which means we need to program
7764 			 * our local bar/lar.
7765 			 */
7766 			ASSERT(idn.first_hwmasterid == (short)IDN_NIL_DOMID);
7767 			idn.first_hwmasterid = (short)idn.localid;
7768 			rem_pfn = idn.smr.locpfn;
7769 			rem_pfnlimit = idn.smr.locpfn +
7770 					btop(MB2B(IDN_SMR_SIZE));
7771 		} else {
7772 			/*
7773 			 * Otherwise, just a slave linking to
7774 			 * another slave.  No bar/lar updating
7775 			 * necessary.
7776 			 */
7777 			rem_pfn = rem_pfnlimit = PFN_INVALID;
7778 		}
7779 		mcadrp = NULL;
7780 	} else {
7781 		/*
7782 		 * If the remote domain is a master, then
7783 		 * we need to program the CIC sm_mask/sm_bar/sm_lar,
7784 		 * and PC's.
7785 		 */
7786 		is_master = 1;
7787 		rem_pfn = idn.smr.rempfn;
7788 		rem_pfnlimit = idn.smr.rempfnlim;
7789 		mcadrp = dp->dhw.dh_mcadr;
7790 		ASSERT(idn.first_hwmasterid == (short)IDN_NIL_DOMID);
7791 		idn.first_hwmasterid = (short)domid;
7792 	}
7793 
7794 	PR_PROTO("%s:%d: ADD bset (0x%x)\n",
7795 		proc, domid, dp->dhw.dh_boardset);
7796 
7797 	rv = idnxf_shmem_add(is_master, dp->dhw.dh_boardset,
7798 				rem_pfn, rem_pfnlimit, mcadrp);
7799 
7800 	if (rv == 0) {
7801 		DOMAINSET_ADD(idn.domset.ds_hwlinked, domid);
7802 	} else {
7803 		if (rem_pfn == idn.smr.locpfn)
7804 			lock_clear(&idn.first_hwlink);
7805 
7806 		if (idn.first_hwmasterid == (short)domid)
7807 			idn.first_hwmasterid = (short)IDN_NIL_DOMID;
7808 
7809 		(void) idnxf_shmem_sub(is_master, dp->dhw.dh_boardset);
7810 	}
7811 
7812 	IDN_GUNLOCK();
7813 
7814 	return (rv);
7815 }
7816 
7817 static int
7818 idn_deprogram_hardware(int domid)
7819 {
7820 	int		rv, is_master;
7821 	idn_domain_t	*dp;
7822 	procname_t	proc = "idn_deprogram_hardware";
7823 
7824 
7825 	dp = &idn_domain[domid];
7826 
7827 	ASSERT(domid != idn.localid);
7828 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
7829 
7830 	/*
7831 	 * Need to take into consideration what boards remote
7832 	 * domain was connected to.  If we don't have a connection to
7833 	 * them ourself, then we better remove them now , otherwise
7834 	 * they'll never be removed (unless we link to them at some point).
7835 	 */
7836 #if 0
7837 	DEBUG_USECDELAY(500000);
7838 #endif /* 0 */
7839 
7840 	IDN_GLOCK_EXCL();
7841 
7842 	if (!DOMAIN_IN_SET(idn.domset.ds_hwlinked, domid)) {
7843 		IDN_GUNLOCK();
7844 		return (0);
7845 	}
7846 
7847 	PR_PROTO("%s:%d: DEprogram hw in domain %d w.r.t remote domain %d\n",
7848 		proc, domid, idn.localid, domid);
7849 
7850 	/*
7851 	 * It's possible to come through this flow for domains that
7852 	 * have not been programmed, i.e. not in idn.hwlinked_domset,
7853 	 * so don't bother asserting that they might be in there.
7854 	 * This can occur if we lose a domain during the config/syn
7855 	 * sequence.  If this occurs we won't know whether the remote
7856 	 * domain has programmed its hardware or not.  If it has then
7857 	 * it will have to go through the DMAP sequence and thus we
7858 	 * have to go through it also.  So, if we reach at least the
7859 	 * CONFIG state, we need to go through the DMAP handshake.
7860 	 */
7861 
7862 	PR_PROTO("%s:%d: SUB bset (0x%x)\n",
7863 		proc, domid, dp->dhw.dh_boardset);
7864 
7865 	if (idn.first_hwmasterid == (short)domid) {
7866 		is_master = 1;
7867 		idn.first_hwmasterid = (short)IDN_NIL_DOMID;
7868 	} else {
7869 		is_master = 0;
7870 	}
7871 	rv = idnxf_shmem_sub(is_master, dp->dhw.dh_boardset);
7872 
7873 	if (rv == 0)
7874 		DOMAINSET_DEL(idn.domset.ds_hwlinked, domid);
7875 
7876 	IDN_GUNLOCK();
7877 
7878 	return (rv);
7879 }
7880 
7881 /*
7882  * Remember can't send slabs back to master at this point.
7883  * Entered with write-drwlock held.
7884  * Returns with drwlock dropped.
7885  */
7886 static void
7887 idn_deconfig(int domid)
7888 {
7889 	idn_domain_t	*dp, *ldp;
7890 	smr_slab_t	*sp;
7891 	int		c, masterid;
7892 	procname_t	proc = "idn_deconfig";
7893 
7894 	ASSERT(IDN_SYNC_IS_LOCKED());
7895 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
7896 	ASSERT(domid != idn.localid);
7897 
7898 	ldp = &idn_domain[idn.localid];
7899 	dp = &idn_domain[domid];
7900 
7901 	ASSERT(dp->dstate == IDNDS_DMAP);
7902 
7903 	PR_PROTO("%s:%d: (dio=%d, dioerr=%d, dnslabs=%d)\n",
7904 		proc, domid, dp->dio, dp->dioerr, dp->dnslabs);
7905 
7906 	IDN_GLOCK_EXCL();
7907 	masterid = IDN_GET_MASTERID();
7908 
7909 	idn.dc_boardset &= ~dp->dhw.dh_boardset;
7910 	for (c = 0; c < NCPU; c++) {
7911 		if (CPU_IN_SET(dp->dcpuset, c)) {
7912 			CPUSET_DEL(idn.dc_cpuset, c);
7913 		}
7914 	}
7915 
7916 	IDN_GUNLOCK();
7917 
7918 	(void) smr_buf_free_all(domid);
7919 
7920 	if (idn.localid == masterid) {
7921 		/*
7922 		 * Since I'm the master there may
7923 		 * have been slabs in this domain's
7924 		 * idn_domain[] entry.
7925 		 */
7926 		DSLAB_LOCK_EXCL(domid);
7927 		if ((sp = dp->dslab) != NULL) {
7928 			PR_PROTO("%s:%d: freeing up %d dead slabs\n",
7929 				proc, domid, dp->dnslabs);
7930 			smr_slab_free(domid, sp);
7931 			dp->dslab = NULL;
7932 			dp->dnslabs = 0;
7933 			dp->dslab_state = DSLAB_STATE_UNKNOWN;
7934 		}
7935 		DSLAB_UNLOCK(domid);
7936 	} else if (domid == masterid) {
7937 		/*
7938 		 * We're shutting down the master!
7939 		 * We need to blow away our local slab
7940 		 * data structures.
7941 		 * Since I'm not the master, there should
7942 		 * be no slab structures in the given
7943 		 * domain's idn_domain[] entry.  They should
7944 		 * only exist in the local domain's entry.
7945 		 */
7946 		DSLAB_LOCK_EXCL(idn.localid);
7947 		ASSERT(dp->dslab == NULL);
7948 #ifdef DEBUG
7949 		{
7950 			int	nbusy = 0;
7951 			uint_t	dommask = 0;
7952 			for (sp = ldp->dslab; sp; sp = sp->sl_next) {
7953 			    smr_slabbuf_t *bp;
7954 
7955 			    if (!smr_slab_busy(sp))
7956 				continue;
7957 			    nbusy++;
7958 			    for (bp = sp->sl_inuse; bp; bp = bp->sb_next)
7959 				if (bp->sb_domid != IDN_NIL_DOMID)
7960 				    DOMAINSET_ADD(dommask, bp->sb_domid);
7961 			}
7962 			if (nbusy)
7963 				PR_PROTO("%s:%d: found %d busy slabs "
7964 					"(dommask = 0x%x)\n",
7965 					proc, domid, nbusy, dommask);
7966 		}
7967 #endif /* DEBUG */
7968 		if ((sp = ldp->dslab) != NULL) {
7969 			PR_PROTO("%s:%d: freeing up %d local slab "
7970 				"structs\n", proc, domid, ldp->dnslabs);
7971 			smr_slab_garbage_collection(sp);
7972 			ldp->dslab = NULL;
7973 			ldp->dnslabs = 0;
7974 			ldp->dslab_state = DSLAB_STATE_UNKNOWN;
7975 		}
7976 		DSLAB_UNLOCK(idn.localid);
7977 	}
7978 	if (dp->dio) {
7979 		PR_PROTO("%s:%d: reset dio (%d) to 0\n",
7980 			proc, domid, dp->dio);
7981 		dp->dio = 0;
7982 	}
7983 	dp->dioerr = 0;
7984 
7985 	PR_PROTO("%s:%d: reset diocheck (%x) to 0\n",
7986 			proc, domid, dp->diocheck);
7987 	lock_clear(&dp->diocheck);
7988 
7989 	CHECKPOINT_CLOSED(IDNSB_CHKPT_LINK, dp->dhw.dh_boardset, 2);
7990 
7991 	/*
7992 	 * Should have already flush our memory before
7993 	 * reaching this stage.  The issue is that by the
7994 	 * time we reach here the remote domains may have
7995 	 * already reprogrammed their hardware and so flushing
7996 	 * out caches now could result in a arbstop/hang
7997 	 * if we have data that needs to go back to one
7998 	 * of the remote domains that has already reprogrammed
7999 	 * its hardware.
8000 	 */
8001 	ASSERT(!DOMAIN_IN_SET(idn.domset.ds_flush, domid));
8002 
8003 	(void) idn_deprogram_hardware(domid);
8004 	/*
8005 	 * XXX - what to do if we
8006 	 *	 fail to program hardware
8007 	 *	 probably should panic since
8008 	 *	 demise of system may be near?
8009 	 *	 Sufficient to just shutdown network?
8010 	 */
8011 
8012 	IDN_DSTATE_TRANSITION(dp, IDNDS_CLOSED);
8013 
8014 	idn_close_domain(domid);
8015 }
8016 
8017 /*
8018  * If we're sending a Reset we better make sure we don't have any
8019  * references or traffic headed in the direction of this guy, since
8020  * when he receives the reset, he'll start shutting down which means
8021  * we effectively have to shutdown _before_ sending the reset.
8022  * DO NOT HOLD ANY DOMAIN RWLOCKS ON ENTRY.  Could result in deadlock
8023  * due to channel server looping back through STREAMs and attempting
8024  * to acquire domain lock, i.e. channel server will never "stop".
8025  */
8026 static void
8027 idn_shutdown_datapath(domainset_t domset, int force)
8028 {
8029 	int		do_allchan;
8030 	idn_domain_t	*dp;
8031 	register int	d;
8032 	procname_t	proc = "idn_shutdown_datapath";
8033 
8034 
8035 	PR_CHAN("%s: domset = 0x%x\n", proc, (uint_t)domset);
8036 
8037 	do_allchan = (domset == DOMAINSET_ALL) ? 1 : 0;
8038 
8039 	DOMAINSET_DEL(domset, idn.localid);
8040 
8041 	if (do_allchan) {
8042 		/*
8043 		 * Need to stop all outgoing and
8044 		 * incoming SMR references.
8045 		 */
8046 		idn_deactivate_channel(CHANSET_ALL, IDNCHAN_OFFLINE);
8047 	}
8048 
8049 	/*
8050 	 * If force is set then we don't want to reference
8051 	 * the SMR at all, so deactivate the domains from
8052 	 * channels first.  This will result in the mainmbox-flush
8053 	 * routines to just clean up without referencing the
8054 	 * SMR space.
8055 	 */
8056 	if (force)
8057 		idn_mainmbox_deactivate(domset);
8058 
8059 	/*
8060 	 * Flush out mailboxes (clear smr reference).
8061 	 */
8062 	for (d = 0; d < MAX_DOMAINS; d++) {
8063 		if (!DOMAIN_IN_SET(domset, d))
8064 			continue;
8065 
8066 		dp = &idn_domain[d];
8067 		if ((dp->dmbox.m_send == NULL) && (dp->dmbox.m_recv == NULL))
8068 			continue;
8069 
8070 		IDN_MBOX_LOCK(d);
8071 		if (dp->dmbox.m_send)
8072 			(void) idn_mainmbox_flush(d, dp->dmbox.m_send);
8073 		if (dp->dmbox.m_recv)
8074 			(void) idn_mainmbox_flush(d, dp->dmbox.m_recv);
8075 		IDN_MBOX_UNLOCK(d);
8076 	}
8077 	/*
8078 	 * Deactivate all domain references also.
8079 	 * Only necessary if it wasn't already done above.
8080 	 */
8081 	if (!force)
8082 		idn_mainmbox_deactivate(domset);
8083 }
8084 
8085 void
8086 idn_send_cmd(int domid, idn_cmd_t cmdtype,
8087 		uint_t arg1, uint_t arg2, uint_t arg3)
8088 {
8089 	idn_msgtype_t	mt;
8090 	procname_t	proc = "idn_send_cmd";
8091 
8092 	mt.mt_mtype = IDNP_CMD;
8093 	mt.mt_atype = 0;
8094 	mt.mt_cookie = 0;
8095 
8096 	ASSERT(IDN_DLOCK_IS_HELD(domid));
8097 
8098 	PR_PROTO("%s:%d: sending command %s\n",
8099 		proc, domid,
8100 		VALID_IDNCMD(cmdtype) ? idncmd_str[cmdtype] : "unknown");
8101 
8102 	IDN_MSGTIMER_START(domid, IDNP_CMD, (ushort_t)cmdtype,
8103 				idn_msg_waittime[IDNP_CMD], &mt.mt_cookie);
8104 
8105 	IDNXDC(domid, &mt, (uint_t)cmdtype, arg1, arg2, arg3);
8106 }
8107 
8108 void
8109 idn_send_cmdresp(int domid, idn_msgtype_t *mtp, idn_cmd_t cmdtype,
8110 			uint_t arg1, uint_t arg2, uint_t cerrno)
8111 {
8112 	idn_msgtype_t	mt;
8113 
8114 	ASSERT(IDN_DLOCK_IS_HELD(domid));
8115 
8116 	if (domid == idn.localid) {
8117 		/*
8118 		 * It's possible local domain received a command
8119 		 * from itself.  However, we cannot send a normal
8120 		 * "ack" response (XDC) to ourself.
8121 		 */
8122 		return;
8123 	}
8124 
8125 	mt.mt_mtype = IDNP_CMD | IDNP_ACK;
8126 	mt.mt_atype = 0;
8127 	mt.mt_cookie = mtp->mt_cookie;
8128 
8129 	IDNXDC(domid, &mt, (uint_t)cmdtype, arg1, arg2, cerrno);
8130 }
8131 
8132 static void
8133 idn_send_cmd_nackresp(int domid, idn_msgtype_t *mtp, idn_cmd_t cmdtype,
8134 			idn_nack_t nacktype)
8135 {
8136 	idn_msgtype_t	mt;
8137 
8138 	if (domid == idn.localid)
8139 		return;
8140 
8141 	mt.mt_mtype = IDNP_CMD | IDNP_NACK;
8142 	mt.mt_atype = 0;
8143 	mt.mt_cookie = mtp->mt_cookie;
8144 
8145 	(void) IDNXDC(domid, &mt, (uint_t)cmdtype, (uint_t)nacktype, 0, 0);
8146 }
8147 
8148 void
8149 idn_broadcast_cmd(idn_cmd_t cmdtype, uint_t arg1, uint_t arg2, uint_t arg3)
8150 {
8151 	idn_msgtype_t	mt;
8152 	domainset_t	domset;
8153 	procname_t	proc = "idn_broadcast_cmd";
8154 
8155 	IDN_GLOCK_SHARED();
8156 
8157 	domset = idn.domset.ds_connected;
8158 	DOMAINSET_DEL(domset, idn.localid);
8159 
8160 	PR_PROTO("%s: broadcasting command (%s) to domainset 0x%x\n",
8161 		proc, VALID_IDNCMD(cmdtype) ? idncmd_str[cmdtype] : "unknown",
8162 		domset);
8163 
8164 	mt.mt_mtype = IDNP_CMD;
8165 	mt.mt_atype = 0;
8166 	mt.mt_cookie = 0;
8167 
8168 	IDNXDC_BROADCAST(domset, &mt, (uint_t)cmdtype, arg1, arg2, arg3);
8169 
8170 	IDN_GUNLOCK();
8171 	/*
8172 	 * This is a broadcast which means local domain needs
8173 	 * to process it also.  Since we can't XDC to ourselves
8174 	 * we simply call a local function.
8175 	 */
8176 	idn_local_cmd(cmdtype, arg1, arg2, arg3);
8177 }
8178 
8179 /*
8180  * Since xargs[0] contains the cmdtype, only xargs[1], xargs[2], xargs[3]
8181  * are valid possible response arguments.
8182  */
8183 static void
8184 idn_recv_cmd(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs)
8185 {
8186 	uint_t			msg = mtp->mt_mtype;
8187 	register idn_domain_t	*dp;
8188 	idn_cmd_t		cmdtype;
8189 	uint_t			acknack;
8190 	uint_t			cmdarg1, cmdarg2, cmdarg3;
8191 	int			islocal;
8192 	int			unsup_cmd_sent, unsup_cmd_recvd;
8193 	procname_t		proc = "idn_recv_cmd";
8194 
8195 	acknack = msg & IDNP_ACKNACK_MASK;
8196 	GET_XARGS(xargs, &cmdtype, &cmdarg1, &cmdarg2, &cmdarg3);
8197 
8198 	dp = &idn_domain[domid];
8199 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
8200 
8201 	IDN_GLOCK_SHARED();
8202 
8203 	islocal = (domid == idn.localid);
8204 
8205 	ASSERT(!acknack || (acknack & IDNP_ACKNACK_MASK));
8206 
8207 	PR_PROTO("%s:%d: (local=%d) acknack=0x%x, cmdtype=%s(%d), "
8208 		"a1=0x%x, a2=0x%x, a3=0x%x\n",
8209 		proc, domid, islocal, acknack,
8210 		VALID_IDNCMD(cmdtype) ? idncmd_str[cmdtype] : "unknown",
8211 		cmdtype, cmdarg1, cmdarg2, cmdarg3);
8212 
8213 	unsup_cmd_sent = unsup_cmd_recvd = 0;
8214 
8215 	if ((IDN_GET_MASTERID() == IDN_NIL_DOMID) ||
8216 			(dp->dstate != IDNDS_CONNECTED)) {
8217 		/*
8218 		 * Commands cannot be handled without a valid
8219 		 * master.  If this is a request then nack him.
8220 		 */
8221 		PR_PROTO("%s:%d: cannot process CMD w/o master (%d, %s)\n",
8222 			proc, domid, IDN_GET_MASTERID(),
8223 			idnds_str[dp->dstate]);
8224 
8225 		if (!islocal && !(acknack & IDNP_ACKNACK_MASK))
8226 			idn_send_cmd_nackresp(domid, mtp, cmdtype,
8227 						IDNNACK_NOCONN);
8228 		IDN_GUNLOCK();
8229 		return;
8230 	}
8231 	IDN_GUNLOCK();
8232 
8233 	if (acknack & IDNP_ACKNACK_MASK) {
8234 		idn_nack_t	nack;
8235 		/*
8236 		 * Receiving a cmd+ack or cmd+nack in response to some
8237 		 * earlier command we must have issued.
8238 		 * If the response is a nack, there are two possibilites:
8239 		 *
8240 		 *	1. Remote domain failed to allocate due
8241 		 *	   to limited resources.
8242 		 *
8243 		 *	2. Remote domain does not support this
8244 		 *	   particular command.
8245 		 *
8246 		 * In the case of #2, the argument immediately after
8247 		 * the cmdtype (xargs[1]) will be (-1).
8248 		 */
8249 		nack = (idn_nack_t)cmdarg1;
8250 		if ((acknack & IDNP_NACK) && (nack == IDNNACK_BADCMD))
8251 			unsup_cmd_sent++;
8252 
8253 		if (islocal) {
8254 			/*
8255 			 * Shouldn't be receiving local commands w/acks.
8256 			 */
8257 			cmdtype = (idn_cmd_t)0;
8258 		}
8259 
8260 		switch (cmdtype) {
8261 		case IDNCMD_SLABALLOC:
8262 			idn_recv_slaballoc_resp(domid, cmdarg1, cmdarg2,
8263 						cmdarg3);
8264 			break;
8265 
8266 		case IDNCMD_SLABFREE:
8267 			idn_recv_slabfree_resp(domid, cmdarg1, cmdarg2,
8268 						cmdarg3);
8269 			break;
8270 
8271 		case IDNCMD_SLABREAP:
8272 			/*
8273 			 * We only care if successful.
8274 			 */
8275 			if (acknack & IDNP_ACK)
8276 				idn_recv_slabreap_resp(domid, cmdarg1,
8277 							cmdarg3);
8278 			break;
8279 
8280 		case IDNCMD_NODENAME:
8281 			if ((acknack & IDNP_NACK) == 0) {
8282 				idn_recv_nodename_resp(domid, cmdarg1,
8283 							cmdarg3);
8284 				break;
8285 			}
8286 			switch (nack) {
8287 			case IDNNACK_NOCONN:
8288 			case IDNNACK_RETRY:
8289 				/*
8290 				 * Remote domain was not quite
8291 				 * ready, try again.
8292 				 */
8293 				PR_PROTO("%s:%d: remote not ready "
8294 					"for %s - retrying "
8295 					"[dstate=%s]\n",
8296 					proc, domid,
8297 					idncmd_str[IDNCMD_NODENAME],
8298 					idnds_str[dp->dstate]);
8299 
8300 				if (dp->dstate == IDNDS_CONNECTED)
8301 					(void) timeout(idn_retry_nodename_req,
8302 					    (void *)(uintptr_t)domid, hz);
8303 			default:
8304 				break;
8305 			}
8306 			break;
8307 
8308 		default:
8309 			/*
8310 			 * Unsupported command.
8311 			 */
8312 			unsup_cmd_recvd++;
8313 			break;
8314 		}
8315 		if (unsup_cmd_sent) {
8316 			PR_PROTO("%s:%d: unsupported command "
8317 				"requested (0x%x)\n",
8318 				proc, domid, cmdtype);
8319 		}
8320 		if (unsup_cmd_recvd) {
8321 			PR_PROTO("%s:%d: unsupported command "
8322 				"response (0x%x)\n",
8323 				proc, domid, cmdtype);
8324 		}
8325 	} else {
8326 		/*
8327 		 * Receiving a regular cmd from a remote domain.
8328 		 */
8329 		switch (cmdtype) {
8330 		case IDNCMD_SLABALLOC:
8331 			idn_recv_slaballoc_req(domid, mtp, cmdarg1);
8332 			break;
8333 
8334 		case IDNCMD_SLABFREE:
8335 			idn_recv_slabfree_req(domid, mtp, cmdarg1, cmdarg2);
8336 			break;
8337 
8338 		case IDNCMD_SLABREAP:
8339 			idn_recv_slabreap_req(domid, mtp, cmdarg1);
8340 			break;
8341 
8342 		case IDNCMD_NODENAME:
8343 			idn_recv_nodename_req(domid, mtp, cmdarg1);
8344 			break;
8345 
8346 		default:
8347 			/*
8348 			 * Unsupported command.
8349 			 */
8350 			unsup_cmd_recvd++;
8351 			break;
8352 		}
8353 		if (!islocal && unsup_cmd_recvd) {
8354 			/*
8355 			 * Received an unsupported IDN command.
8356 			 */
8357 			idn_send_cmd_nackresp(domid, mtp, cmdtype,
8358 					IDNNACK_BADCMD);
8359 		}
8360 	}
8361 }
8362 
8363 /*
8364  * This is a supporting routine for idn_broadcast_cmd() to
8365  * handle processing of the requested command for the local
8366  * domain.  Currently the only support broadcast command
8367  * supported is reaping.
8368  */
8369 /*ARGSUSED2*/
8370 static void
8371 idn_local_cmd(idn_cmd_t cmdtype, uint_t arg1, uint_t arg2, uint_t arg3)
8372 {
8373 	idn_protojob_t	*jp;
8374 	idn_domain_t	*ldp = &idn_domain[idn.localid];
8375 	procname_t	proc = "idn_local_cmd";
8376 
8377 	PR_PROTO("%s: submitting local command %s on domain %d\n",
8378 		proc, VALID_IDNCMD(cmdtype) ? idncmd_str[cmdtype] : "unknown",
8379 		idn.localid);
8380 
8381 
8382 	jp = idn_protojob_alloc(KM_SLEEP);
8383 
8384 	jp->j_msg.m_domid    = ldp->domid;
8385 	jp->j_msg.m_msgtype  = IDNP_CMD;
8386 	jp->j_msg.m_cookie   = ldp->dcookie_recv;
8387 	SET_XARGS(jp->j_msg.m_xargs, cmdtype, arg1, arg2, arg3);
8388 
8389 	idn_protojob_submit(ldp->domid, jp);
8390 }
8391 
8392 /*
8393  * Terminate any outstanding commands that may have
8394  * been targeted for the given domain.  A command is
8395  * designated as outstanding if it has an active timer.
8396  *
8397  * serrno = ECANCELED.
8398  */
8399 static void
8400 idn_terminate_cmd(int domid, int serrno)
8401 {
8402 	idn_domain_t	*dp;
8403 	idn_timer_t	*tplist = NULL, *tp;
8404 	procname_t	proc = "idn_terminate_cmd";
8405 
8406 	dp = &idn_domain[domid];
8407 
8408 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
8409 
8410 	IDN_MSGTIMER_GET(dp, IDNP_CMD, tplist, 0);
8411 	/*
8412 	 * At this point the timers are effectively terminated
8413 	 * since when they're t_onq indication is set false.
8414 	 */
8415 	if (tplist == NULL) {
8416 		PR_PROTO("%s:%d: no outstanding cmds found\n",
8417 			proc, domid);
8418 		/*
8419 		 * There is a window where we may have caught a
8420 		 * request just prior to issuing the actual
8421 		 * command (SLABALLOC).  We're guaranteed if there
8422 		 * was, then he will have at least registered.
8423 		 * So, if we abort the command now, he'll catch
8424 		 * it before going to sleep.
8425 		 * Drop through.
8426 		 */
8427 	}
8428 	ASSERT(tplist ? (tplist->t_back->t_forw == NULL) : 1);
8429 
8430 	for (tp = tplist; tp; tp = tp->t_forw) {
8431 		ASSERT(tp->t_type == IDNP_CMD);
8432 
8433 		PR_PROTO("%s:%d: found outstanding cmd: %s\n",
8434 			proc, domid, idncmd_str[tp->t_subtype]);
8435 
8436 		switch (tp->t_subtype) {
8437 		case IDNCMD_SLABALLOC:
8438 			/*
8439 			 * Outstanding slaballoc request may have
8440 			 * slab waiters hanging around.  Need to
8441 			 * tell them to bail out.  The given domain
8442 			 * must be the master if we have an outstanding
8443 			 * command to him.  This also presumes that
8444 			 * if there are any waiters they're only in
8445 			 * the local domain's waiting area (i.e. we're
8446 			 * a slave).
8447 			 */
8448 #ifdef DEBUG
8449 			IDN_GLOCK_SHARED();
8450 			ASSERT(domid == IDN_GET_MASTERID());
8451 			ASSERT(idn.localid != IDN_GET_MASTERID());
8452 			IDN_GUNLOCK();
8453 #endif /* DEBUG */
8454 			(void) smr_slabwaiter_abort(idn.localid, serrno);
8455 			break;
8456 
8457 		case IDNCMD_SLABFREE:
8458 		case IDNCMD_SLABREAP:
8459 		case IDNCMD_NODENAME:
8460 			/*
8461 			 * Nothing really waiting for these operations
8462 			 * so no biggy if we just drop.
8463 			 * Note that NODENAME may have an outstanding
8464 			 * buffer, however that will be reclaimed
8465 			 * when we actually unlink from domain.
8466 			 */
8467 			break;
8468 
8469 		default:
8470 			ASSERT(0);
8471 			break;
8472 		}
8473 	}
8474 	/*
8475 	 * As mentioned before the timers are effectively no-op'd
8476 	 * once they're dequeued, however let's cleanup house and
8477 	 * get rid of the useless entries in the timeout queue.
8478 	 */
8479 	if (tplist) {
8480 		IDN_TIMER_STOPALL(tplist);
8481 	}
8482 
8483 	if (idn_domain[idn.localid].dvote.v.master) {
8484 		/*
8485 		 * I'm the master so it's possible I had
8486 		 * outstanding commands (SLABALLOC) waiting
8487 		 * to be satisfied for the given domain.
8488 		 * Since we're forcing an error it's okay
8489 		 * to continue holding onto the drwlock.
8490 		 */
8491 		PR_PROTO("%s:%d: abort slaballoc waiters\n", proc, domid);
8492 		(void) smr_slabwaiter_abort(domid, serrno);
8493 
8494 	} else if (dp->dvote.v.master) {
8495 		PR_PROTO("%s:%d: abort (local domain) slaballoc waiters\n",
8496 			proc, domid);
8497 		(void) smr_slabwaiter_abort(idn.localid, serrno);
8498 	}
8499 }
8500 
8501 static void
8502 idn_send_acknack(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs)
8503 {
8504 	idn_domain_t	*dp = &idn_domain[domid];
8505 	procname_t	proc = "idn_send_acknack";
8506 
8507 	ASSERT(mtp ? (mtp->mt_mtype & IDNP_ACKNACK_MASK) : 1);
8508 	ASSERT(domid != IDN_NIL_DOMID);
8509 
8510 #ifdef DEBUG
8511 	{
8512 		STRING(mstr);
8513 		STRING(astr);
8514 
8515 		INUM2STR(mtp->mt_mtype, mstr);
8516 		INUM2STR(mtp->mt_atype, astr);
8517 
8518 		if (mtp->mt_mtype & IDNP_ACK) {
8519 			PR_PROTO("%s:%d: dstate=%s, msg=(%s/%s), "
8520 				"a1=0x%x, a2=0x%x, a3=0x%x, a4 = 0x%x\n",
8521 				proc, domid, idnds_str[dp->dstate],
8522 				astr, mstr, xargs[0], xargs[1],
8523 				xargs[2], xargs[3]);
8524 		} else {
8525 			idn_nack_t	nack;
8526 
8527 			nack = GET_XARGS_NACK_TYPE(xargs);
8528 			PR_PROTO("%s:%d: dstate=%s, msg=(%s/%s), "
8529 				"nack=%s(0x%x)\n",
8530 				proc, domid, idnds_str[dp->dstate],
8531 				astr, mstr, idnnack_str[nack],
8532 				(uint_t)nack);
8533 		}
8534 	}
8535 #endif /* DEBUG */
8536 
8537 	(void) IDNXDC(domid, mtp, xargs[0], xargs[1], xargs[2], xargs[3]);
8538 }
8539 
8540 /*ARGSUSED0*/
8541 static void
8542 idn_prealloc_slab(int nslabs)
8543 {
8544 	register int	s, serrno;
8545 	smr_slab_t	*sp;
8546 	idn_domain_t	*ldp = &idn_domain[idn.localid];
8547 	procname_t	proc = "idn_prealloc_slab";
8548 
8549 	IDN_GLOCK_SHARED();
8550 	DSLAB_LOCK_SHARED(idn.localid);
8551 	if ((idn.state != IDNGS_ONLINE) || (ldp->dnslabs > 0)) {
8552 		/*
8553 		 * Not in the proper state or slab already allocated.
8554 		 */
8555 		DSLAB_UNLOCK(idn.localid);
8556 		IDN_GUNLOCK();
8557 		return;
8558 	}
8559 	IDN_GUNLOCK();
8560 	ASSERT(!ldp->dslab);
8561 
8562 	serrno = 0;
8563 	for (s = 0; (s < nslabs) && ((int)ldp->dnslabs < nslabs); s++) {
8564 		/*
8565 		 * Returns with ldp->drwlock dropped.
8566 		 */
8567 		serrno = smr_slab_alloc(idn.localid, &sp);
8568 		if (serrno != 0) {
8569 			PR_PROTO("%s: FAILED to pre-alloc'd "
8570 				"slab (serrno = %d)\n", proc, serrno);
8571 			break;
8572 		}
8573 		/*
8574 		 * State may have changed since smr_slab_alloc
8575 		 * temporarily drops drwlock.  Make sure we're
8576 		 * still connected.
8577 		 */
8578 		PR_PROTO("%s: SUCCESSFULLY pre-alloc'd slab\n", proc);
8579 
8580 		if (idn.state != IDNGS_ONLINE) {
8581 			PR_PROTO("%s: Lost connection..leaving\n", proc);
8582 			break;
8583 		}
8584 	}
8585 
8586 	DSLAB_UNLOCK(idn.localid);
8587 }
8588 
8589 /*
8590  * Received a request from a remote domain to
8591  * allocate a slab from the master SMR for him.
8592  * Allocate slab and return the response.
8593  */
8594 static void
8595 idn_recv_slaballoc_req(int domid, idn_msgtype_t *mtp, uint_t slab_size)
8596 {
8597 	register idn_domain_t	*dp;
8598 	procname_t		proc = "idn_recv_slaballoc_req";
8599 
8600 	PR_PROTO("%s: slaballoc req from domain %d (size=0x%x)\n",
8601 		proc, domid, slab_size);
8602 
8603 	dp = &idn_domain[domid];
8604 
8605 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
8606 
8607 	IDN_GLOCK_SHARED();
8608 
8609 	if (idn.localid != IDN_GET_MASTERID()) {
8610 		IDN_GUNLOCK();
8611 		/*
8612 		 * It's a fatal error if the remote domain thinks
8613 		 * we're the master.
8614 		 */
8615 		idn_send_slaballoc_resp(domid, mtp, 0, 0, EACCES);
8616 
8617 	} else if (dp->dstate != IDNDS_CONNECTED) {
8618 
8619 		IDN_GUNLOCK();
8620 		/*
8621 		 * It's a fatal error if we don't yet have a
8622 		 * connection established with the requestor.
8623 		 */
8624 		idn_send_slaballoc_resp(domid, mtp, 0, 0, ENOLINK);
8625 	} else {
8626 		int		serrno;
8627 		smr_slab_t	*sp;
8628 		smr_offset_t	slab_offset;
8629 
8630 		IDN_GUNLOCK();
8631 		DSLAB_LOCK_SHARED(domid);
8632 		IDN_DUNLOCK(domid);
8633 		/*
8634 		 * We're connected and we're the master.
8635 		 * smr_slab_alloc() returns with dp->drwlock dropped.
8636 		 */
8637 		if ((serrno = smr_slab_alloc(domid, &sp)) == 0) {
8638 			/*
8639 			 * Successfully allocated slab for remote slave.
8640 			 */
8641 			slab_offset = IDN_ADDR2OFFSET(sp->sl_start);
8642 			slab_size   = sp->sl_end - sp->sl_start;
8643 			ASSERT((slab_offset != 0) && (slab_size != 0));
8644 		} else {
8645 			slab_offset = slab_size = 0;
8646 		}
8647 		DSLAB_UNLOCK(domid);
8648 		/*
8649 		 * The drwlock is dropped during smr_slab_alloc.
8650 		 * During that time our connection with the given
8651 		 * domain may have changed.  Better check again.
8652 		 */
8653 		IDN_DLOCK_SHARED(domid);
8654 		if ((dp->dstate != IDNDS_CONNECTED) && !serrno) {
8655 			/*
8656 			 * Connection broke.  Keep the slab here.
8657 			 */
8658 			DSLAB_LOCK_EXCL(domid);
8659 			IDN_DUNLOCK(domid);
8660 			smr_slab_free(domid, sp);
8661 			DSLAB_UNLOCK(domid);
8662 			slab_offset = slab_size = 0;
8663 			serrno = ECANCELED;
8664 			IDN_DLOCK_SHARED(domid);
8665 		}
8666 		/*
8667 		 * Send response.
8668 		 * Note that smr_slab_alloc automatically installs
8669 		 * slab into domains respective idn_domain entry
8670 		 * to be associated with that domain.
8671 		 */
8672 		idn_send_slaballoc_resp(domid, mtp,
8673 					slab_offset, slab_size, serrno);
8674 	}
8675 }
8676 
8677 static void
8678 idn_send_slaballoc_resp(int domid, idn_msgtype_t *mtp,
8679 			smr_offset_t slab_offset, uint_t slab_size, int serrno)
8680 {
8681 	procname_t	proc = "idn_send_slaballoc_resp";
8682 
8683 	PR_PROTO("%s: slaballoc resp to domain %d (off=0x%x, size=0x%x) "
8684 		"[serrno = %d]\n",
8685 		proc, domid, slab_offset, slab_size, serrno);
8686 
8687 	idn_send_cmdresp(domid, mtp, IDNCMD_SLABALLOC,
8688 				slab_offset, slab_size, serrno);
8689 }
8690 
8691 /*
8692  * Received the ack or nack to a previous allocation request
8693  * made by the local domain to the master for a slab.  Need
8694  * to "put" the response into the waiting area for any
8695  * waiters.
8696  */
8697 static void
8698 idn_recv_slaballoc_resp(int domid, smr_offset_t slab_offset,
8699 			uint_t slab_size, int serrno)
8700 {
8701 	smr_slab_t		*sp = NULL;
8702 	int			rv;
8703 	procname_t		proc = "idn_recv_slaballoc_resp";
8704 
8705 
8706 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
8707 
8708 	PR_PROTO("%s: slaballoc resp from domain %d (off=0x%x, size=0x%x) "
8709 		"[serrno = %d]\n",
8710 		proc, domid, slab_offset, slab_size, serrno);
8711 
8712 	if (!serrno) {
8713 		IDN_GLOCK_SHARED();
8714 		if (domid != IDN_GET_MASTERID()) {
8715 			/*
8716 			 * We should only be receiving responses from
8717 			 * our master.  This is either a bogus message
8718 			 * or an old response.  In either case dump it.
8719 			 */
8720 			PR_PROTO("%s: BOGUS slaballoc resp from domid %d "
8721 				"(master = %d)\n",
8722 				proc, domid, IDN_GET_MASTERID());
8723 			serrno = EPROTO;
8724 		}
8725 		IDN_GUNLOCK();
8726 
8727 		if (!serrno &&
8728 			!VALID_NWROFFSET(slab_offset, IDN_SMR_BUFSIZE)) {
8729 
8730 			PR_PROTO("%s: slab offset (0x%x) out of range "
8731 				"(0-0x%lx)\n",
8732 				proc, slab_offset, MB2B(IDN_NWR_SIZE));
8733 			serrno = EPROTO;
8734 		} else if (!serrno) {
8735 			sp = GETSTRUCT(smr_slab_t, 1);
8736 			sp->sl_start = IDN_OFFSET2ADDR(slab_offset);
8737 			sp->sl_end   = sp->sl_start + slab_size;
8738 			smr_alloc_buflist(sp);
8739 		}
8740 	}
8741 
8742 	/*
8743 	 * Always "put" slabs back to yourself since you're a slave.
8744 	 * Note that we set the forceflag so that even if there are
8745 	 * no waiters we still install the slab for the domain.
8746 	 */
8747 	if (!serrno) {
8748 		DSLAB_LOCK_EXCL(idn.localid);
8749 	}
8750 	rv = smr_slaballoc_put(idn.localid, sp, 1, serrno);
8751 	if (!serrno) {
8752 		DSLAB_UNLOCK(idn.localid);
8753 	}
8754 
8755 	if (rv < 0) {
8756 		/*
8757 		 * Some kind of error trying to install response.
8758 		 * If there was a valid slab sent to us, we'll
8759 		 * just have to send it back.
8760 		 */
8761 		PR_PROTO("%s: failed to install response in waiting area\n",
8762 			proc);
8763 		if (slab_size != 0) {
8764 			PR_PROTO("%s: sending slab back to domain %d "
8765 				"(master = %d)\n",
8766 				proc, domid, IDN_GET_MASTERID());
8767 			idn_send_cmd(domid, IDNCMD_SLABFREE,
8768 						slab_offset, slab_size, 0);
8769 		}
8770 		if (sp) {
8771 			smr_free_buflist(sp);
8772 			FREESTRUCT(sp, smr_slab_t, 1);
8773 		}
8774 	}
8775 }
8776 
8777 /*
8778  * Note that slab reaping is effectively performed asynchronously
8779  * since the request will be received a protocol server.
8780  */
8781 static void
8782 idn_recv_slabreap_req(int domid, idn_msgtype_t *mtp, int nslabs)
8783 {
8784 	procname_t	proc = "idn_recv_slabreap_req";
8785 
8786 	PR_PROTO("%s: slab reap request (nslabs = %d)\n", proc, nslabs);
8787 
8788 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
8789 
8790 	IDN_GLOCK_SHARED();
8791 	if (domid != IDN_GET_MASTERID()) {
8792 		/*
8793 		 * Only the master can request that slabs be reaped.
8794 		 */
8795 		IDN_GUNLOCK();
8796 		PR_PROTO("%s: only master can request slab reaping\n", proc);
8797 
8798 		idn_send_cmdresp(domid, mtp, IDNCMD_SLABREAP, 0, 0, EACCES);
8799 
8800 		return;
8801 	}
8802 	IDN_GUNLOCK();
8803 
8804 	if (nslabs != 0) {
8805 		IDN_DUNLOCK(domid);
8806 		smr_slab_reap(idn.localid, &nslabs);
8807 		IDN_DLOCK_SHARED(domid);
8808 	}
8809 
8810 	PR_PROTO("%s: slab reap result (nslabs = %d)\n", proc, nslabs);
8811 
8812 	/*
8813 	 * Go ahead and send the reap response back before we start
8814 	 * free'ing off the individual slabs.
8815 	 */
8816 	idn_send_slabreap_resp(domid, mtp, nslabs, 0);
8817 }
8818 
8819 static void
8820 idn_recv_slabreap_resp(int domid, int nslabs, int serrno)
8821 {
8822 	procname_t	proc = "idn_recv_slabreap_resp";
8823 
8824 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
8825 
8826 	if ((idn.localid != IDN_GET_MASTERID()) || (idn.localid == domid)) {
8827 		PR_PROTO("%s: unexpected slabreap resp received "
8828 			"(domid = %d)\n", proc, domid);
8829 		ASSERT(0);
8830 		return;
8831 	}
8832 	PR_PROTO("%s: recvd reap response from domain %d for %d slabs "
8833 		"[serrno = %d]\n", proc, domid, nslabs, serrno);
8834 }
8835 
8836 /*
8837  * Not really necessary to send slabreap response.
8838  * XXX - perhaps useful to master for accounting or
8839  *	 throttling of further reaping?
8840  */
8841 static void
8842 idn_send_slabreap_resp(int domid, idn_msgtype_t *mtp, int nslabs, int serrno)
8843 {
8844 	idn_send_cmdresp(domid, mtp, IDNCMD_SLABREAP, nslabs, 0, serrno);
8845 }
8846 
8847 /*
8848  * Slave -> Master ONLY
8849  * Master never sends slabfree request to itself.
8850  */
8851 static void
8852 idn_recv_slabfree_req(int domid, idn_msgtype_t *mtp,
8853 			smr_offset_t slab_offset, uint_t slab_size)
8854 {
8855 	smr_slab_t	*sp;
8856 	int		serrno;
8857 	caddr_t		s_start, s_end;
8858 	procname_t	proc = "idn_recv_slabfree_req";
8859 
8860 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
8861 
8862 	if (domid == IDN_GET_MASTERID()) {
8863 		PR_PROTO("%s: unexpected slabfree req received (domid = %d)\n",
8864 			proc, domid);
8865 		idn_send_slabfree_resp(domid, mtp,
8866 					slab_offset, slab_size, EACCES);
8867 		return;
8868 	}
8869 	if (slab_size > IDN_SLAB_SIZE) {
8870 		PR_PROTO("%s: unexpected slab size. exp %d, recvd %d\n",
8871 			proc, IDN_SLAB_SIZE, slab_size);
8872 		idn_send_slabfree_resp(domid, mtp,
8873 					slab_offset, slab_size, EINVAL);
8874 		return;
8875 	}
8876 	s_start = IDN_OFFSET2ADDR(slab_offset);
8877 	s_end   = s_start + slab_size;
8878 	/*
8879 	 * Master has received a SLABFREE request (effectively a response
8880 	 * to some earlier SLABREAP request.
8881 	 * Find the slab associated with this slab and free it up.
8882 	 */
8883 	DSLAB_LOCK_EXCL(domid);
8884 	if ((sp = smr_slaballoc_get(domid, s_start, s_end)) != NULL) {
8885 		smr_slab_free(domid, sp);
8886 		serrno = 0;
8887 	} else {
8888 		serrno = EINVAL;
8889 	}
8890 	DSLAB_UNLOCK(domid);
8891 
8892 	idn_send_slabfree_resp(domid, mtp, slab_offset, slab_size, serrno);
8893 }
8894 
8895 /*
8896  * Master -> Slave ONLY
8897  */
8898 static void
8899 idn_recv_slabfree_resp(int domid, uint_t slab_offset,
8900 			uint_t slab_size, int serrno)
8901 {
8902 	procname_t	proc = "idn_recv_slabfree_resp";
8903 
8904 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
8905 
8906 	if (domid != IDN_GET_MASTERID()) {
8907 		PR_PROTO("%s: unexpected slabfree resp received (domid = %d)\n",
8908 			proc, domid);
8909 		ASSERT(0);
8910 		return;
8911 	}
8912 	if (slab_size > IDN_SLAB_SIZE) {
8913 		PR_PROTO("%s: unexpected slab size. exp %d, recvd %d\n",
8914 			proc, IDN_SLAB_SIZE, slab_size);
8915 		ASSERT(0);
8916 		return;
8917 	}
8918 	PR_PROTO("%s: recvd free resp from dom %d "
8919 		"- slab (off/size) 0x%x/0x%x [serrno = %d]\n",
8920 		proc, domid, slab_offset, slab_size, serrno);
8921 }
8922 
8923 static void
8924 idn_send_slabfree_resp(int domid, idn_msgtype_t *mtp,
8925 			uint_t slab_offset, uint_t slab_size, int serrno)
8926 {
8927 	idn_send_cmdresp(domid, mtp, IDNCMD_SLABFREE,
8928 				slab_offset, slab_size, serrno);
8929 }
8930 
8931 static void
8932 idn_retry_nodename_req(void *arg)
8933 {
8934 	int	domid = (int)(uintptr_t)arg;
8935 
8936 	idn_send_nodename_req(domid);
8937 }
8938 
8939 static void
8940 idn_send_nodename_req(int domid)
8941 {
8942 	caddr_t		b_bufp;
8943 	smr_offset_t	bufoffset;
8944 	int		serrno;
8945 	idn_domain_t	*dp = &idn_domain[domid];
8946 	procname_t	proc = "idn_send_nodename_req";
8947 
8948 	/*
8949 	 * Need to drop domain lock across
8950 	 * SMR allocation.
8951 	 */
8952 	serrno = smr_buf_alloc(domid, MAXDNAME+1, &b_bufp);
8953 
8954 	IDN_DLOCK_SHARED(domid);
8955 	if (dp->dstate != IDNDS_CONNECTED) {
8956 		/*
8957 		 * Lost connection.
8958 		 */
8959 		PR_PROTO("%s:%d: connection lost [dstate = %s]\n",
8960 			proc, domid, idnds_str[dp->dstate]);
8961 		IDN_DUNLOCK(domid);
8962 		if (!serrno)
8963 			(void) smr_buf_free(domid, b_bufp, MAXDNAME+1);
8964 		return;
8965 	}
8966 	if (serrno) {
8967 		/*
8968 		 * Failed to allocate buffer, but still have
8969 		 * connection so keep trying.  We may have queried
8970 		 * the master a little too earlier.
8971 		 */
8972 		PR_PROTO("%s:%d: buffer alloc failed [dstate = %s]\n",
8973 			proc, domid, idnds_str[dp->dstate]);
8974 		(void) timeout(idn_retry_nodename_req, (void *)(uintptr_t)domid,
8975 		    hz);
8976 		IDN_DUNLOCK(domid);
8977 		return;
8978 	}
8979 
8980 	*b_bufp = (char)MAXDNAME;
8981 	bufoffset = IDN_ADDR2OFFSET(b_bufp);
8982 
8983 	idn_send_cmd(domid, IDNCMD_NODENAME, bufoffset, 0, 0);
8984 	IDN_DUNLOCK(domid);
8985 }
8986 
8987 static void
8988 idn_send_nodename_resp(int domid, idn_msgtype_t *mtp,
8989 			smr_offset_t bufoffset, int serrno)
8990 {
8991 	idn_send_cmdresp(domid, mtp, IDNCMD_NODENAME,
8992 			(uint_t)bufoffset, 0, serrno);
8993 }
8994 
8995 static void
8996 idn_recv_nodename_req(int domid, idn_msgtype_t *mtp, smr_offset_t bufoffset)
8997 {
8998 	caddr_t		b_bufp;
8999 	int		length;
9000 	idn_domain_t	*ldp = &idn_domain[idn.localid];
9001 	procname_t	proc = "idn_recv_nodename_req";
9002 
9003 	IDN_DLOCK_EXCL(idn.localid);
9004 	if (!strlen(ldp->dname)) {
9005 		if (!strlen(utsname.nodename)) {
9006 			/*
9007 			 * Local domain's nodename hasn't been
9008 			 * set yet.
9009 			 */
9010 			IDN_DUNLOCK(idn.localid);
9011 			idn_send_cmd_nackresp(domid, mtp, IDNCMD_NODENAME,
9012 						IDNNACK_RETRY);
9013 			return;
9014 		}
9015 		strncpy(ldp->dname, utsname.nodename, MAXDNAME - 1);
9016 	}
9017 	IDN_DLOCK_DOWNGRADE(idn.localid);
9018 
9019 	if (!VALID_NWROFFSET(bufoffset, IDN_SMR_BUFSIZE)) {
9020 		PR_PROTO("%s:%d: invalid SMR offset received (0x%x)\n",
9021 			proc, domid, bufoffset);
9022 		IDN_DUNLOCK(idn.localid);
9023 		idn_send_nodename_resp(domid, mtp, bufoffset, EINVAL);
9024 		return;
9025 	}
9026 
9027 	b_bufp = IDN_OFFSET2ADDR(bufoffset);
9028 	length = (int)(*b_bufp++ & 0xff);
9029 
9030 	if (length < strlen(ldp->dname)) {
9031 		PR_PROTO("%s:%d: buffer not big enough (req %lu, got %d)\n",
9032 			proc, domid, strlen(ldp->dname), length);
9033 		IDN_DUNLOCK(idn.localid);
9034 		idn_send_nodename_resp(domid, mtp, bufoffset, EINVAL);
9035 		return;
9036 	}
9037 
9038 	strncpy(b_bufp, ldp->dname, MAXDNAME);
9039 	b_bufp[MAXDNAME-1] = 0;
9040 	IDN_DUNLOCK(idn.localid);
9041 
9042 	idn_send_nodename_resp(domid, mtp, bufoffset, 0);
9043 }
9044 
9045 static void
9046 idn_recv_nodename_resp(int domid, smr_offset_t bufoffset, int serrno)
9047 {
9048 	caddr_t		b_bufp;
9049 	idn_domain_t	*dp = &idn_domain[domid];
9050 	procname_t	proc = "idn_recv_nodename_resp";
9051 
9052 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
9053 
9054 	if (!VALID_NWROFFSET(bufoffset, IDN_SMR_BUFSIZE)) {
9055 		PR_PROTO("%s:%d: invalid SMR offset received (0x%x)\n",
9056 			proc, domid, bufoffset);
9057 		return;
9058 	}
9059 
9060 	if (serrno == 0) {
9061 		b_bufp = IDN_OFFSET2ADDR(bufoffset) + 1;
9062 		b_bufp[MAXDNAME-1] = 0;
9063 
9064 		if (strlen(b_bufp) > 0) {
9065 			strncpy(dp->dname, b_bufp, MAXDNAME);
9066 			PR_PROTO("%s:%d: received nodename(%s)\n",
9067 				proc, domid, dp->dname);
9068 		}
9069 	}
9070 
9071 	(void) smr_buf_free(domid, b_bufp - 1, MAXDNAME + 1);
9072 }
9073 
9074 /*
9075  * The master allocations the SMR management structures.
9076  */
9077 static int
9078 idn_master_init()
9079 {
9080 	idn_domain_t	*ldp = &idn_domain[idn.localid];
9081 	size_t		reserved_size = 0;
9082 	caddr_t		reserved_area = NULL;
9083 	procname_t	proc = "idn_master_init";
9084 
9085 	ASSERT(IDN_GLOCK_IS_EXCL());
9086 	ASSERT(IDN_DLOCK_IS_EXCL(idn.localid));
9087 
9088 	if (idn.mboxarea != NULL) {
9089 		PR_PROTO("%s: master data already initialized\n", proc);
9090 		return (0);
9091 	}
9092 
9093 	PR_PROTO("%s: initializing master data (domid = %d)\n",
9094 		proc, idn.localid);
9095 
9096 	/*
9097 	 * Reserve an area of the SMR for mailbox usage.
9098 	 * This area is allocated to other domains via
9099 	 * the master.  Round it up to IDN_SMR_BUFSIZE multiple.
9100 	 */
9101 	reserved_size = IDNROUNDUP(IDN_MBOXAREA_SIZE, IDN_SMR_BUFSIZE);
9102 
9103 	PR_PROTO("%s: reserving %lu bytes for mailbox area\n",
9104 		proc, reserved_size);
9105 
9106 #ifdef DEBUG
9107 	if (reserved_size > (size_t)IDN_SLAB_SIZE) {
9108 		PR_PROTO("%s: WARNING mbox area (%ld) > slab size (%d)\n",
9109 			proc, reserved_size, IDN_SLAB_SIZE);
9110 	}
9111 #endif /* DEBUG */
9112 	/*
9113 	 * Initialize the pool of slabs and SMR I/O buffers.
9114 	 */
9115 	if (smr_slabpool_init(reserved_size, &reserved_area) != 0) {
9116 		idn_master_deinit();
9117 		return (-1);
9118 	}
9119 
9120 	ASSERT(idn.mboxarea == NULL);
9121 	ASSERT(reserved_area);
9122 
9123 	bzero(reserved_area, reserved_size);
9124 
9125 	idn.mboxarea = (idn_mboxtbl_t *)reserved_area;
9126 	ldp->dmbox.m_tbl = IDN_MBOXAREA_BASE(idn.mboxarea, idn.localid);
9127 	/*
9128 	 * Initialize the SMR pointers in the entire
9129 	 * mailbox table.
9130 	 */
9131 	idn_mboxarea_init(idn.mboxarea, IDN_MBOXAREA_SIZE / IDN_MBOXTBL_SIZE);
9132 
9133 	return (0);
9134 }
9135 
9136 static void
9137 idn_master_deinit()
9138 {
9139 	idn_domain_t	*ldp;
9140 	smr_slab_t	*sp;
9141 	procname_t	proc = "idn_master_deinit";
9142 
9143 	ASSERT(IDN_GLOCK_IS_EXCL());
9144 	ASSERT(IDN_DLOCK_IS_EXCL(idn.localid));
9145 
9146 	if (idn.mboxarea == NULL) {
9147 		PR_PROTO("%s: master data already deinitialized\n", proc);
9148 		return;
9149 	}
9150 
9151 	ldp = &idn_domain[idn.localid];
9152 
9153 	PR_PROTO("%s: deinitializing master data (domid = %d)\n",
9154 		proc, idn.localid);
9155 
9156 	ldp->dmbox.m_tbl = NULL;
9157 	idn.mboxarea = NULL;
9158 	/*
9159 	 * Master may still be holding onto slabs of his own.
9160 	 */
9161 	DSLAB_LOCK_EXCL(idn.localid);
9162 	sp = ldp->dslab;
9163 	ldp->dslab = NULL;
9164 	ldp->dnslabs = 0;
9165 	if (sp)
9166 		smr_slab_free(idn.localid, sp);
9167 	ldp->dslab_state = DSLAB_STATE_UNKNOWN;
9168 	DSLAB_UNLOCK(idn.localid);
9169 
9170 	smr_slabpool_deinit();
9171 }
9172 
9173 static int
9174 idn_mark_awol(int domid, clock_t *atime)
9175 {
9176 	clock_t		awol;
9177 	idn_domain_t	*dp = &idn_domain[domid];
9178 
9179 	ASSERT(IDN_SYNC_IS_LOCKED());
9180 	ASSERT(IDN_GLOCK_IS_EXCL());
9181 
9182 	if (!DOMAIN_IN_SET(idn.domset.ds_awol, domid)) {
9183 		DOMAINSET_ADD(idn.domset.ds_awol, domid);
9184 		idn.nawols++;
9185 	}
9186 	awol = lbolt;
9187 	if (dp->dawol.a_count++ == 0)
9188 		dp->dawol.a_time = awol;
9189 	dp->dawol.a_last = awol;
9190 	if ((awol - dp->dawol.a_msg) >= (clock_t)(idn_awolmsg_interval * hz))
9191 		dp->dawol.a_msg = awol;
9192 	else
9193 		awol = 0;
9194 
9195 	*atime = awol;
9196 
9197 	idn_awol_event_set(dp->dhw.dh_boardset);
9198 
9199 	return (dp->dawol.a_count);
9200 }
9201 
9202 void
9203 idn_clear_awol(int domid)
9204 {
9205 	idn_domain_t	*dp = &idn_domain[domid];
9206 
9207 	ASSERT(IDN_SYNC_IS_LOCKED());
9208 	ASSERT(IDN_GLOCK_IS_EXCL());
9209 	if (DOMAIN_IN_SET(idn.domset.ds_awol, domid)) {
9210 		DOMAINSET_DEL(idn.domset.ds_awol, domid);
9211 		idn.nawols--;
9212 	}
9213 	if (dp->dawol.a_count > 0) {
9214 		dp->dawol.a_count = 0;
9215 		dp->dawol.a_last = dp->dawol.a_time;
9216 		dp->dawol.a_time = 0;
9217 		dp->dawol.a_msg = 0;
9218 
9219 		idn_awol_event_clear(dp->dhw.dh_boardset);
9220 	}
9221 }
9222 
9223 /*
9224  * A timer expired.
9225  */
9226 void
9227 idn_timer_expired(void *arg)
9228 {
9229 	idn_domain_t	*dp;
9230 	char		*op = "UNKNOWN";
9231 	clock_t		awol = 0;
9232 	int		awolcount, dcpu, domid;
9233 	idn_timer_t	*tp = (idn_timer_t *)arg;
9234 	idn_timerq_t	*tq = NULL;
9235 	uint_t		token;
9236 	char		dname[MAXDNAME];
9237 	procname_t	proc = "idn_timer_expired";
9238 	STRING(str);
9239 
9240 	tq = tp->t_q;
9241 
9242 	ASSERT(tp->t_domid != IDN_NIL_DOMID);
9243 
9244 	IDN_TIMERQ_LOCK(tq);
9245 
9246 	INUM2STR(tp->t_type, str);
9247 
9248 	if (tp->t_onq == 0) {
9249 		PR_TIMER("%s: timer CAUGHT TERMINATION (type = %s)\n",
9250 			proc, str);
9251 		/*
9252 		 * Timer was dequeued.  Somebody is trying
9253 		 * to shut it down.
9254 		 */
9255 		IDN_TIMERQ_UNLOCK(tq);
9256 		return;
9257 	}
9258 
9259 	IDN_TIMER_DEQUEUE(tq, tp);
9260 
9261 	IDN_TIMERQ_UNLOCK(tq);
9262 
9263 	IDN_SYNC_LOCK();
9264 	IDN_DLOCK_EXCL(tp->t_domid);
9265 
9266 	domid = tp->t_domid;
9267 
9268 	dp = &idn_domain[domid];
9269 	strcpy(dname, dp->dname);
9270 	dcpu = dp->dcpu;
9271 
9272 	IDN_TIMER_EXEC(tp);
9273 
9274 #ifdef DEBUG
9275 	PR_TIMER("%s:%d: [%s] timer EXPIRED (C=0x%x, P=0x%llx, X=0x%llx)\n",
9276 		proc, tp->t_domid, str, tp->t_cookie,
9277 		tp->t_posttime, tp->t_exectime);
9278 #endif /* DEBUG */
9279 
9280 	/*
9281 	 * IMPORTANT:
9282 	 * Each case is responsible for dropping SYNC_LOCK & DLOCK.
9283 	 */
9284 	switch (tp->t_type) {
9285 	case IDNP_DATA:
9286 		IDN_SYNC_UNLOCK();
9287 		/*
9288 		 * Timed out waiting for a data packet response.
9289 		 * We can't close domain since he may just be
9290 		 * temporarily AWOL.
9291 		 * Note that dio and diocheck do not get cleared.
9292 		 * This is taken care of when the domain restarts
9293 		 * or is fatally closed.
9294 		 * We only need a reader lock for this.
9295 		 */
9296 		IDN_DLOCK_DOWNGRADE(domid);
9297 		if (dp->diocheck && dp->dmbox.m_send) {
9298 			(void) idn_reclaim_mboxdata(domid, 0, -1);
9299 			if (dp->dio >= IDN_WINDOW_EMAX) {
9300 				idn_msgtype_t	mt;
9301 				/*
9302 				 * Restart timer for another
9303 				 * go around.
9304 				 */
9305 				IDN_MSGTIMER_START(domid, IDNP_DATA, 0,
9306 						idn_msg_waittime[IDNP_DATA],
9307 						&mt.mt_cookie);
9308 			} else {
9309 				lock_clear(&dp->diocheck);
9310 			}
9311 		}
9312 		IDN_DUNLOCK(domid);
9313 		break;
9314 
9315 	case IDNP_NEGO:
9316 		/*
9317 		 * If we're not in a NEGO transition, then
9318 		 * just ignore this timeout.
9319 		 */
9320 		if (dp->dxp == &xphase_nego) {
9321 			uint_t		token;
9322 
9323 			IDN_GLOCK_EXCL();
9324 			op = "CONNECT";
9325 			awolcount = idn_mark_awol(domid, &awol);
9326 			IDN_GUNLOCK();
9327 
9328 			idn_nego_cleanup_check(domid, IDN_NIL_DOMID,
9329 						IDN_NIL_DCPU);
9330 
9331 			IDN_XSTATE_TRANSITION(dp, IDNXS_PEND);
9332 			token = IDN_RETRY_TOKEN(domid, IDNRETRY_NEGO);
9333 			idn_retry_submit(idn_retry_nego, NULL, token,
9334 					idn_msg_retrytime[(int)IDNRETRY_NEGO]);
9335 		}
9336 		IDN_DUNLOCK(domid);
9337 		IDN_SYNC_UNLOCK();
9338 		break;
9339 
9340 	case IDNP_CMD:
9341 		/*
9342 		 * Timeouts on commands typically mean that the
9343 		 * the master is not responding.  Furthermore, we
9344 		 * can't FORCE a FIN disconnect since at this stage
9345 		 * we are CONNECTED and thus other domains may
9346 		 * have cache entries that we're sharing with them.
9347 		 * Only choice is to completely disconnect from
9348 		 * IDN and try to reestablish connection.
9349 		 *
9350 		 * However, timeouts attempting to get nodename
9351 		 * are not fatal.  Although we don't want to retry
9352 		 * either since each timeout is a lost buffer to
9353 		 * the remote domain.
9354 		 */
9355 		if (tp->t_subtype == (ushort_t)IDNCMD_NODENAME) {
9356 			PR_PROTO("%s:%d: timedout waiting for nodename\n",
9357 				proc, domid);
9358 			IDN_DUNLOCK(domid);
9359 			IDN_SYNC_UNLOCK();
9360 			break;
9361 		}
9362 
9363 		IDN_GLOCK_EXCL();
9364 		if (idn.state == IDNGS_ONLINE) {
9365 			domainset_t	domset;
9366 			int		masterid = IDN_GET_MASTERID();
9367 
9368 			IDN_GKSTAT_GLOBAL_EVENT(gk_reconfigs,
9369 						gk_reconfig_last);
9370 
9371 			PR_PROTO("%s:%d: RECONFIG trying old masterid = %d\n",
9372 				proc, domid, masterid);
9373 
9374 			IDN_GSTATE_TRANSITION(IDNGS_RECONFIG);
9375 			IDN_SET_NEW_MASTERID(masterid);
9376 			IDN_GUNLOCK();
9377 			IDN_DUNLOCK(domid);
9378 
9379 			domset = idn.domset.ds_trans_on |
9380 					idn.domset.ds_connected;
9381 
9382 			idn_unlink_domainset(domset, IDNFIN_NORMAL,
9383 						IDNFIN_ARG_NONE,
9384 						IDNFIN_OPT_RELINK,
9385 						BOARDSET_ALL);
9386 		} else {
9387 			IDN_GUNLOCK();
9388 			IDN_DUNLOCK(domid);
9389 		}
9390 		IDN_SYNC_UNLOCK();
9391 		break;
9392 
9393 	case IDNP_CON:
9394 		if (tp->t_subtype == (ushort_t)IDNCON_QUERY) {
9395 			/*
9396 			 * Timed out sending a CON-query.  This is
9397 			 * non-fatal.  We simply need to retry.
9398 			 */
9399 			IDN_GLOCK_EXCL();
9400 			op = "CONNECT";
9401 			awolcount = idn_mark_awol(domid, &awol);
9402 			IDN_GUNLOCK();
9403 			token = IDN_RETRY_TOKEN(domid, IDNRETRY_CONQ);
9404 			idn_retry_submit(idn_retry_query, NULL, token,
9405 					idn_msg_retrytime[(int)IDNRETRY_CONQ]);
9406 			IDN_DUNLOCK(domid);
9407 			IDN_SYNC_UNLOCK();
9408 			break;
9409 		}
9410 		/*FALLTHROUGH*/
9411 	case IDNP_CFG:
9412 		/*
9413 		 * Any timeouts here we simply try to disconnect
9414 		 * and reestablish the link.  Since we haven't
9415 		 * reached the connected state w.r.t. this domain
9416 		 * we put his fin state to FORCE-HARD in order
9417 		 * to shoot right through without involving other
9418 		 * domains.  Recall that other domains may have
9419 		 * established connections with the given domain
9420 		 * which means any FIN queries to them will always
9421 		 * return connected to the given domain.  Since
9422 		 * neither the given domain nor the local domain
9423 		 * plan on disconnecting from the IDN the connection
9424 		 * to the other domains will remain thereby preventing
9425 		 * the local FIN from ever completing.  Recall that
9426 		 * a FIN depends on all member domains FIN'ing also.
9427 		 */
9428 		IDN_GLOCK_EXCL();
9429 		op = "CONNECT";
9430 		awolcount = idn_mark_awol(domid, &awol);
9431 		IDN_GUNLOCK();
9432 		DOMAINSET_ADD(idn.domset.ds_relink, domid);
9433 		IDN_HISTORY_LOG(IDNH_RELINK, domid, dp->dstate,
9434 				idn.domset.ds_relink);
9435 		idn_disconnect(domid, IDNFIN_FORCE_SOFT,
9436 				IDNFIN_ARG_NONE, IDNFIN_SYNC_NO);
9437 		IDN_DUNLOCK(domid);
9438 		IDN_SYNC_UNLOCK();
9439 		break;
9440 
9441 	case IDNP_FIN:
9442 		/*
9443 		 * Timeouts here simply try to retry.
9444 		 */
9445 		IDN_GLOCK_EXCL();
9446 		op = "DISCONNECT";
9447 		awolcount = idn_mark_awol(domid, &awol);
9448 		IDN_GUNLOCK();
9449 		if (tp->t_subtype == (ushort_t)IDNFIN_QUERY) {
9450 			int		d;
9451 			domainset_t	rdyset;
9452 			/*
9453 			 * Timed out sending a FIN-query.  This is
9454 			 * non-fatal.  We simply need to retry.
9455 			 * If we were doing a forced unlink of any
9456 			 * domains, we don't want this awol guy
9457 			 * to hold us up.  Looks for any forced
9458 			 * unlinks and make them "ready" with
9459 			 * respect to this awol domain.
9460 			 */
9461 			rdyset = 0;
9462 			for (d = 0; d < MAX_DOMAINS; d++) {
9463 				if (FIN_IS_FORCE(idn_domain[d].dfin)) {
9464 					DOMAINSET_ADD(rdyset, d);
9465 				}
9466 			}
9467 			if (rdyset)
9468 				(void) idn_sync_register(domid,
9469 						IDNSYNC_DISCONNECT,
9470 						rdyset, IDNSYNC_REG_REG);
9471 
9472 			token = IDN_RETRY_TOKEN(domid, IDNRETRY_FINQ);
9473 			idn_retry_submit(idn_retry_query, NULL, token,
9474 					idn_msg_retrytime[(int)IDNRETRY_FINQ]);
9475 			IDN_DUNLOCK(domid);
9476 			IDN_SYNC_UNLOCK();
9477 			break;
9478 		}
9479 
9480 		if (dp->dfin == IDNFIN_FORCE_SOFT) {
9481 			IDN_FSTATE_TRANSITION(dp, IDNFIN_FORCE_HARD);
9482 		}
9483 		/*
9484 		 * Anybody that was waiting on this domain and
9485 		 * had a hard-force in action gets this guy for
9486 		 * free in their base ready-set.
9487 		 */
9488 		idn_sync_register_awol(domid);
9489 
9490 		dp->dxp = &xphase_fin;
9491 		IDN_XSTATE_TRANSITION(dp, IDNXS_PEND);
9492 		token = IDN_RETRY_TOKEN(domid, IDNRETRY_FIN);
9493 		idn_retry_submit(idn_retry_fin, NULL, token,
9494 				idn_msg_retrytime[(int)IDNRETRY_FIN]);
9495 		IDN_DUNLOCK(domid);
9496 		IDN_SYNC_UNLOCK();
9497 		break;
9498 
9499 	default:
9500 
9501 		ASSERT(0);
9502 		IDN_DUNLOCK(domid);
9503 		IDN_SYNC_UNLOCK();
9504 		break;
9505 	}
9506 
9507 	IDN_TIMER_FREE(tp);
9508 
9509 	if (awol) {
9510 		if (strlen(dname) > 0) {
9511 			cmn_err(CE_WARN,
9512 				"IDN: 236: domain (%s) [ID %d] not "
9513 				"responding to %s [#%d]",
9514 				dname, domid, op, awolcount);
9515 		} else {
9516 			cmn_err(CE_WARN,
9517 				"IDN: 236: domain [ID %d, CPU %d] not "
9518 				"responding to %s [#%d]",
9519 				domid, dcpu, op, awolcount);
9520 		}
9521 	}
9522 }
9523 
9524 #if 0
9525 static int
9526 idn_retry_check(uint_t token)
9527 {
9528 	int			i, count = 0;
9529 	int			domid = IDN_RETRY_TOKEN2DOMID(token);
9530 	int			key = IDN_RETRY_TOKEN2TYPE(token);
9531 	idn_retry_job_t		*rp;
9532 	idn_retry_queue_t	*qp;
9533 
9534 	qp = &idn.retryqueue;
9535 
9536 	mutex_enter(&qp->rq_mutex);
9537 
9538 	for (i = 0, rp = qp->rq_jobs; i < qp->rq_count; i++, rp = rp->rj_next)
9539 		if ((domid == IDN_RETRY_TOKEN2DOMID(rp->rj_token)) &&
9540 				((key == IDN_RETRY_TYPEALL) ||
9541 				(rp->rj_token == token)))
9542 			count++;
9543 
9544 	mutex_exit(&qp->rq_mutex);
9545 
9546 	return (count);
9547 }
9548 #endif /* 0 */
9549 
9550 static void
9551 idn_retry_execute(void *arg)
9552 {
9553 	idn_retry_job_t		*rp = (idn_retry_job_t *)arg;
9554 	idn_retry_queue_t	*qp;
9555 
9556 	qp = &idn.retryqueue;
9557 
9558 	mutex_enter(&qp->rq_mutex);
9559 	if (rp->rj_onq == 0) {
9560 		/*
9561 		 * Job has already been claimed by
9562 		 * retry termination routine.
9563 		 * Bail out.
9564 		 */
9565 		mutex_exit(&qp->rq_mutex);
9566 		return;
9567 	}
9568 	rp->rj_next->rj_prev = rp->rj_prev;
9569 	rp->rj_prev->rj_next = rp->rj_next;
9570 	if (--(qp->rq_count) == 0)
9571 		qp->rq_jobs = NULL;
9572 	else if (qp->rq_jobs == rp)
9573 		qp->rq_jobs = rp->rj_next;
9574 	mutex_exit(&qp->rq_mutex);
9575 
9576 	(*rp->rj_func)(rp->rj_token, rp->rj_arg);
9577 
9578 	IDNRETRY_FREEJOB(rp);
9579 }
9580 
9581 /*
9582  *
9583  */
9584 static void
9585 idn_retry_submit(void (*func)(uint_t token, void *arg),
9586 		void *arg, uint_t token, clock_t ticks)
9587 {
9588 	idn_retry_job_t		*rp, *cp;
9589 	idn_retry_queue_t	*qp;
9590 	int			c;
9591 	procname_t		proc = "idn_retry_submit";
9592 
9593 	if (ticks < 0) {
9594 		PR_PROTO("%s: (token = 0x%x) WARNING ticks = %ld\n",
9595 			proc, token, ticks);
9596 		return;
9597 	}
9598 	if (ticks == 0)		/* At least one tick to get into background */
9599 		ticks++;
9600 
9601 	PR_PROTO("%s: token = 0x%x\n", proc, token);
9602 
9603 	qp = &idn.retryqueue;
9604 
9605 	mutex_enter(&qp->rq_mutex);
9606 	for (c = 0, cp = qp->rq_jobs;
9607 			c < qp->rq_count;
9608 			cp = cp->rj_next, c++) {
9609 		if (cp->rj_token == token) {
9610 			PR_PROTO("%s: token = (%d,0x%x) already present\n",
9611 				proc, IDN_RETRY_TOKEN2DOMID(token),
9612 				IDN_RETRY_TOKEN2TYPE(token));
9613 			break;
9614 		}
9615 	}
9616 
9617 	if (c < qp->rq_count) {
9618 		mutex_exit(&qp->rq_mutex);
9619 		return;
9620 	}
9621 
9622 	rp = IDNRETRY_ALLOCJOB();
9623 	rp->rj_func = func;
9624 	rp->rj_arg = arg;
9625 	rp->rj_token = token;
9626 	rp->rj_prev = rp->rj_next = rp;
9627 
9628 	if (qp->rq_jobs == NULL) {
9629 		qp->rq_jobs = rp;
9630 	} else {
9631 		rp->rj_next = qp->rq_jobs;
9632 		rp->rj_prev = qp->rq_jobs->rj_prev;
9633 		rp->rj_next->rj_prev = rp;
9634 		rp->rj_prev->rj_next = rp;
9635 	}
9636 	rp->rj_onq = 1;
9637 	qp->rq_count++;
9638 	rp->rj_id = timeout(idn_retry_execute, (caddr_t)rp, ticks);
9639 	mutex_exit(&qp->rq_mutex);
9640 }
9641 
9642 int
9643 idn_retry_terminate(uint_t token)
9644 {
9645 	int			i, domid;
9646 	uint_t			key, count;
9647 	idn_retry_job_t		*rp, *nrp, *fp;
9648 	idn_retry_queue_t	*qp;
9649 	procname_t		proc = "idn_retry_terminate";
9650 
9651 	key = IDN_RETRY_TOKEN2TYPE(token);
9652 	domid = IDN_RETRY_TOKEN2DOMID(token);
9653 	fp = NULL;
9654 	qp = &idn.retryqueue;
9655 
9656 	mutex_enter(&qp->rq_mutex);
9657 	for (i = count = 0, rp = qp->rq_jobs; i < qp->rq_count; i++) {
9658 		nrp = rp->rj_next;
9659 		if ((domid == IDN_RETRY_TOKEN2DOMID(rp->rj_token)) &&
9660 			((key == IDN_RETRY_TYPEALL) ||
9661 				(rp->rj_token == token))) {
9662 			/*
9663 			 * Turn off onq field as a signal to
9664 			 * the execution routine that this
9665 			 * retry has been terminated.  This
9666 			 * is necessary since we can't untimeout
9667 			 * while holding the rq_mutex otherwise
9668 			 * we'll deadlock with the execution
9669 			 * routine.  We'll untimeout these guys
9670 			 * _after_ we drop rq_mutex.
9671 			 */
9672 			rp->rj_onq = 0;
9673 			rp->rj_next->rj_prev = rp->rj_prev;
9674 			rp->rj_prev->rj_next = rp->rj_next;
9675 			if (qp->rq_jobs == rp)
9676 				qp->rq_jobs = rp->rj_next;
9677 			rp->rj_next = fp;
9678 			fp = rp;
9679 			count++;
9680 		}
9681 		rp = nrp;
9682 	}
9683 
9684 	if ((qp->rq_count -= count) == 0)
9685 		qp->rq_jobs = NULL;
9686 
9687 	mutex_exit(&qp->rq_mutex);
9688 
9689 	PR_PROTO("%s: token = (%d,0x%x), dequeued = %d\n",
9690 		proc, domid, key, count);
9691 
9692 	for (; fp; fp = nrp) {
9693 		(void) untimeout(fp->rj_id);
9694 
9695 		nrp = fp->rj_next;
9696 		IDNRETRY_FREEJOB(fp);
9697 	}
9698 
9699 	return (count);
9700 }
9701 
9702 /*
9703  * -----------------------------------------------------------------------
9704  * The sole purpose of the idn_protocol_server is to manage the IDN
9705  * protocols between the various domains.  These messages do _not_ go
9706  * through the regular streams queues since they are not dependent on
9707  * any user process or module necessarily having the IDN driver open.
9708  * There may be multiple instances of these servers to enhance performance
9709  * of domain management.  Each server is assigned a idn_protoqueue_t
9710  * from which to obtain the work they need to do.
9711  * -----------------------------------------------------------------------
9712  */
9713 int
9714 idn_protocol_init(int nservers)
9715 {
9716 	int		i;
9717 	idn_protojob_t	*jp;
9718 	register idn_protoqueue_t	*protoq;
9719 
9720 	if (nservers <= 0) {
9721 		cmn_err(CE_WARN,
9722 			"IDN: 237: invalid number (%d) of protocol servers",
9723 			nservers);
9724 		return (-1);
9725 	}
9726 
9727 	idn.protocol.p_jobpool = kmem_cache_create("idn_protocol_jobcache",
9728 						sizeof (idn_protojob_t),
9729 						0, NULL, NULL, NULL,
9730 						NULL, NULL, 0);
9731 	if (idn.protocol.p_jobpool == NULL) {
9732 		cmn_err(CE_WARN,
9733 			"IDN: 238: kmem_cache_create(jobcache) failed");
9734 		return (-1);
9735 	}
9736 
9737 	/*
9738 	 * Initialize static cache for protojob.
9739 	 */
9740 	mutex_init(&idn_protojob_cache_lock, NULL, MUTEX_DRIVER, NULL);
9741 	jp = &idn_protojob_cache[0];
9742 	for (i = 1; i < IDN_DMV_PENDING_MAX; jp = jp->j_next, i++) {
9743 		jp->j_cache = 1;
9744 		jp->j_next = &idn_protojob_cache[i];
9745 	}
9746 	jp->j_cache = 1;
9747 	jp->j_next = NULL;
9748 	idn_protojob_cache_list = &idn_protojob_cache[0];
9749 
9750 	/*
9751 	 * Init morgue semaphore.
9752 	 */
9753 	sema_init(&idn.protocol.p_morgue, 0, NULL, SEMA_DEFAULT, NULL);
9754 	/*
9755 	 * Alloc server queues.
9756 	 */
9757 	idn.protocol.p_serverq = GETSTRUCT(idn_protoqueue_t, nservers);
9758 
9759 	/*
9760 	 * Init server queues.
9761 	 */
9762 	protoq = idn.protocol.p_serverq;
9763 	for (i = 0; i < nservers; protoq++, i++) {
9764 		mutex_init(&protoq->q_mutex, NULL, MUTEX_DRIVER, NULL);
9765 		cv_init(&protoq->q_cv, NULL, CV_DEFAULT, NULL);
9766 		protoq->q_id	  = i;
9767 		protoq->q_joblist = NULL;
9768 		protoq->q_joblist_tail = NULL;
9769 		protoq->q_die	  = 0;
9770 		protoq->q_morgue  = &idn.protocol.p_morgue;
9771 		/*
9772 		 * Create protocol server thread.
9773 		 */
9774 		protoq->q_threadp = thread_create(NULL, 0,
9775 		    idn_protocol_server, (caddr_t)&i, sizeof (i), &p0,
9776 		    TS_RUN, maxclsyspri);
9777 	}
9778 	/*
9779 	 * The servers are kept in the p_server[] array, however
9780 	 * we'll build a linked list of them to facilitate debugging.
9781 	 */
9782 	protoq = idn.protocol.p_serverq;
9783 	for (i = 0; i < (nservers - 1); protoq++, i++)
9784 		protoq->q_next = (protoq + 1);
9785 	protoq->q_next = NULL;
9786 
9787 	idn.nservers = nservers;
9788 
9789 	return (idn.nservers);
9790 }
9791 
9792 void
9793 idn_protocol_deinit()
9794 {
9795 	register int	i;
9796 	int		nservers;
9797 	register idn_protoqueue_t	*protoq;
9798 
9799 	nservers = idn.nservers;
9800 
9801 	if (nservers <= 0)
9802 		return;
9803 
9804 	/*
9805 	 * Make sure the servers are dead.
9806 	 */
9807 	idn_protocol_server_killall();
9808 	ASSERT(idn.nservers == 0);
9809 	/*
9810 	 * Destroy the mutexes.
9811 	 */
9812 	protoq = idn.protocol.p_serverq;
9813 	for (i = 0; i < nservers; protoq++, i++) {
9814 		mutex_destroy(&protoq->q_mutex);
9815 		cv_destroy(&protoq->q_cv);
9816 	}
9817 	/*
9818 	 * Free up the protoqueue memory.
9819 	 */
9820 	FREESTRUCT(idn.protocol.p_serverq, idn_protoqueue_t, nservers);
9821 	idn.protocol.p_serverq = NULL;
9822 	/*
9823 	 * Destroy the morgue semaphore.
9824 	 */
9825 	sema_destroy(&idn.protocol.p_morgue);
9826 
9827 	if (idn.protocol.p_jobpool) {
9828 		kmem_cache_destroy(idn.protocol.p_jobpool);
9829 		idn.protocol.p_jobpool = NULL;
9830 	}
9831 }
9832 
9833 static void
9834 idn_protocol_server(int *id)
9835 {
9836 	idn_protoqueue_t	*pq;
9837 	idn_protojob_t		*jl;
9838 	register idn_protojob_t	*jp;
9839 	procname_t		proc = "idn_protocol_server";
9840 
9841 	if (id == NULL) {
9842 		PR_PROTO("%s: id == NULL, thread exiting\n",
9843 			proc);
9844 		return;
9845 	}
9846 	ASSERT((*id >= 0) && (*id < idn_protocol_nservers));
9847 
9848 	pq = &idn.protocol.p_serverq[*id];
9849 
9850 	ASSERT(pq->q_id == *id);
9851 
9852 	PR_PROTO("%s: id %d starting up (pq = 0x%p)\n",
9853 		proc, pq->q_id, pq);
9854 
9855 	/*CONSTCOND*/
9856 	while (1) {
9857 		mutex_enter(&pq->q_mutex);
9858 
9859 		while (((jl = pq->q_joblist) == NULL) && !pq->q_die)
9860 			cv_wait(&pq->q_cv, &pq->q_mutex);
9861 
9862 		pq->q_joblist = pq->q_joblist_tail = NULL;
9863 
9864 		if (pq->q_die) {
9865 			/*
9866 			 * We've been killed.  Need to check-in
9867 			 * at the morgue.
9868 			 */
9869 			pq->q_threadp = NULL;
9870 			mutex_exit(&pq->q_mutex);
9871 			PR_PROTO("%s: thread (%d) killed...bye bye\n",
9872 				proc, pq->q_id);
9873 			for (jp = jl; jp; jp = jl) {
9874 				jl = jp->j_next;
9875 				idn_protojob_free(jp);
9876 			}
9877 			sema_v(pq->q_morgue);
9878 			thread_exit();
9879 			/*NOTREACHED*/
9880 		}
9881 		mutex_exit(&pq->q_mutex);
9882 
9883 		/*
9884 		 * We can process the jobs asynchronously while more are
9885 		 * put on.
9886 		 */
9887 		for (jp = jl; jp; jp = jl) {
9888 			jl = jp->j_next;
9889 			idn_recv_proto(&(jp->j_msg));
9890 			idn_protojob_free(jp);
9891 		}
9892 	}
9893 }
9894 
9895 /*
9896  * Kill off all the protocol servers.
9897  */
9898 static void
9899 idn_protocol_server_killall()
9900 {
9901 	register idn_protoqueue_t	*pq;
9902 	int		i;
9903 	procname_t	proc = "idn_protocol_server_killall";
9904 
9905 	PR_PROTO("%s: killing off %d protocol servers\n",
9906 		proc, idn.nservers);
9907 
9908 	pq = idn.protocol.p_serverq;
9909 	for (i = 0; i < idn.nservers; pq++, i++) {
9910 		mutex_enter(&pq->q_mutex);
9911 		pq->q_die = 1;
9912 		cv_signal(&pq->q_cv);
9913 		mutex_exit(&pq->q_mutex);
9914 	}
9915 
9916 	while (idn.nservers > 0) {
9917 		sema_p(&idn.protocol.p_morgue);
9918 		idn.nservers--;
9919 	}
9920 }
9921 
9922 idn_protojob_t *
9923 idn_protojob_alloc(int kmflag)
9924 {
9925 	idn_protojob_t	*jp;
9926 
9927 	jp = kmem_cache_alloc(idn.protocol.p_jobpool, kmflag);
9928 	if (jp == NULL) {
9929 		mutex_enter(&idn_protojob_cache_lock);
9930 		if ((jp = idn_protojob_cache_list) != NULL)
9931 			idn_protojob_cache_list = jp->j_next;
9932 		mutex_exit(&idn_protojob_cache_lock);
9933 	} else {
9934 		jp->j_cache = 0;
9935 	}
9936 
9937 	return (jp);
9938 }
9939 
9940 static void
9941 idn_protojob_free(idn_protojob_t *jp)
9942 {
9943 	ASSERT(jp);
9944 
9945 	if (jp->j_cache) {
9946 		mutex_enter(&idn_protojob_cache_lock);
9947 		jp->j_next = idn_protojob_cache_list;
9948 		idn_protojob_cache_list = jp;
9949 		mutex_exit(&idn_protojob_cache_lock);
9950 	} else {
9951 		kmem_cache_free(idn.protocol.p_jobpool, (void *)jp);
9952 	}
9953 }
9954 
9955 void
9956 idn_protojob_submit(int cookie, idn_protojob_t *jp)
9957 {
9958 	idn_protoqueue_t	*pq;
9959 	int			serverid;
9960 	procname_t		proc = "idn_protojob_submit";
9961 	STRING(str);
9962 
9963 	if (jp == NULL)
9964 		return;
9965 
9966 	serverid = IDN_PROTOCOL_SERVER_HASH(cookie);
9967 
9968 	pq = &idn.protocol.p_serverq[serverid];
9969 
9970 	INUM2STR(jp->j_msg.m_msgtype, str);
9971 	PR_PROTO("%s: job (d=%d, m=0x%x, %s) submitted to "
9972 		"protocol server %d\n", proc, jp->j_msg.m_domid,
9973 		jp->j_msg.m_msgtype, str, serverid);
9974 
9975 	mutex_enter(&pq->q_mutex);
9976 	/*
9977 	 * Can't submit jobs to dying servers.
9978 	 */
9979 	if (!pq->q_die) {
9980 		if (pq->q_joblist_tail) {
9981 			pq->q_joblist_tail->j_next = jp;
9982 			pq->q_joblist_tail = jp;
9983 		} else {
9984 			pq->q_joblist = pq->q_joblist_tail = jp;
9985 		}
9986 		jp->j_next = NULL;
9987 		cv_signal(&pq->q_cv);
9988 	} else {
9989 		PR_PROTO("%s: protocol server dead.  freeing protojob\n",
9990 			proc);
9991 		idn_protojob_free(jp);
9992 	}
9993 	mutex_exit(&pq->q_mutex);
9994 }
9995 
9996 static void
9997 idn_mboxarea_init(idn_mboxtbl_t *mtp, register int ntbls)
9998 {
9999 	register int	d;
10000 	caddr_t		state_ptr = NULL, mtbasep = (caddr_t)mtp;
10001 	idn_mboxtbl_t	*amtp;
10002 	procname_t	proc = "idn_mboxarea_init";
10003 
10004 	ASSERT(mtp && (ntbls > 0));
10005 
10006 	PR_PROTO("%s: init mboxtbl (0x%p) ntbls = %d\n",
10007 		proc, mtp, ntbls);
10008 
10009 	for (d = 0; d < ntbls; d++) {
10010 		register int	pd, sd;
10011 		register int	ch;
10012 
10013 		mtp->mt_header.mh_svr_active = 0;
10014 		mtp->mt_header.mh_svr_ready = 0;
10015 		/*
10016 		 * Initialize the header of each mbox table
10017 		 * with a cookie for identity.
10018 		 */
10019 		/*
10020 		 * Format: 0xc0c0DSCC
10021 		 *	 D = primary domain
10022 		 *	 S = sub-domain of primary
10023 		 *	CC = channel of sub-domain.
10024 		 */
10025 		pd = (d / MAX_DOMAINS) / IDN_MAX_NETS;
10026 		sd = (d / IDN_MAX_NETS) % MAX_DOMAINS;
10027 		ch = d % IDN_MAX_NETS;
10028 
10029 		/*
10030 		 * We point all sub-domains in the same channel
10031 		 * to the same active sync flag since a single server
10032 		 * services all domains in the same channel.
10033 		 */
10034 		amtp = IDN_MBOXTBL_ABS_PTR(mtbasep, pd, 0, ch);
10035 
10036 		state_ptr = (caddr_t)&amtp->mt_header.mh_svr_active;
10037 		mtp->mt_header.mh_svr_active_ptr = IDN_ADDR2OFFSET(state_ptr);
10038 
10039 		state_ptr = (caddr_t)&amtp->mt_header.mh_svr_ready;
10040 		mtp->mt_header.mh_svr_ready_ptr = IDN_ADDR2OFFSET(state_ptr);
10041 
10042 		mtp->mt_header.mh_cookie = IDN_MAKE_MBOXHDR_COOKIE(pd, sd, ch);
10043 
10044 		mtp->mt_header.mh_cksum = IDN_CKSUM_MBOX(&mtp->mt_header);
10045 
10046 		IDN_MBOXTBL_PTR_INC(mtp);
10047 	}
10048 	/*
10049 	 * Now that the master has initialized the entire mailbox
10050 	 * region the referenced memory may not necessarily be up-to-date
10051 	 * with respect to the actual SMR memory due to caching.
10052 	 * In order to make sure future connecting domains get a
10053 	 * consistent picture of the mailbox region, it's necessary
10054 	 * for the master to flush its caches.
10055 	 */
10056 	PR_PROTO("%s: flushing ecache's of local (master) domain\n", proc);
10057 
10058 	idnxf_flushall_ecache();
10059 }
10060 
10061 idn_mainmbox_t *
10062 idn_mainmbox_init(int domid, int mbx)
10063 {
10064 	idn_mainmbox_t	*mmp;
10065 	int		c;
10066 	idn_mainmbox_t	*cmp;
10067 	procname_t	proc = "idn_mainmbox_init";
10068 
10069 	ASSERT(idn_domain[domid].dcpu != IDN_NIL_DCPU);
10070 	ASSERT(IDN_DLOCK_IS_HELD(domid));
10071 
10072 	PR_PROTO("%s: initializing main %s mailbox for domain %d\n",
10073 		proc, IDNMBOX_IS_RECV(mbx) ? "RECV" : "SEND", domid);
10074 
10075 	cmp = GETSTRUCT(idn_mainmbox_t, IDN_MAX_NETS);
10076 	for (c = 0; c < IDN_MAX_NETS; c++) {
10077 		mmp = &cmp[c];
10078 		mmp->mm_channel = (short)c;
10079 		mutex_init(&mmp->mm_mutex, NULL, MUTEX_DRIVER, NULL);
10080 		mmp->mm_domid = (short)domid;
10081 		mmp->mm_type = mbx;
10082 	}
10083 	mmp = cmp;
10084 	/*
10085 	 * The actual SMR mailbox (mmp->mm_smr_mboxp) gets setup
10086 	 * when the SMR is setup.
10087 	 */
10088 
10089 	return (mmp);
10090 }
10091 
10092 static void
10093 idn_mainmbox_reset(int domid, idn_mainmbox_t *cmp)
10094 {
10095 	idn_mainmbox_t	*mmp;
10096 	int		c;
10097 	procname_t	proc = "idn_mainmbox_reset";
10098 
10099 	ASSERT(IDN_DLOCK_IS_EXCL(domid));
10100 
10101 	PR_PROTO("%s: reseting main %s mailbox for domain %d\n",
10102 		proc, IDNMBOX_IS_RECV(cmp->mm_type) ? "RECV" : "SEND", domid);
10103 
10104 	for (c = 0; c < IDN_MAX_NETS; c++) {
10105 		mmp = &cmp[c];
10106 
10107 		mmp->mm_channel = (short)c;
10108 		mmp->mm_domid = (short)domid;
10109 		mmp->mm_count = 0;
10110 		mmp->mm_flags = 0;
10111 		mmp->mm_qiget = mmp->mm_qiput = 0;
10112 		mmp->mm_csp = NULL;
10113 		ASSERT(mmp->mm_type == cmp->mm_type);
10114 	}
10115 }
10116 
10117 void
10118 idn_mainmbox_deinit(int domid, idn_mainmbox_t *mmp)
10119 {
10120 	procname_t	proc = "idn_mainmbox_deinit";
10121 
10122 	ASSERT(IDN_DLOCK_IS_HELD(domid));
10123 
10124 	PR_PROTO("%s: deinitializing main %s mailbox for domain %d\n",
10125 		proc, IDNMBOX_IS_RECV(mmp->mm_type) ? "RECV" : "SEND", domid);
10126 
10127 	ASSERT(idn_domain_is_registered(domid, -1, NULL) == 0);
10128 
10129 	FREESTRUCT(mmp, idn_mainmbox_t, IDN_MAX_NETS);
10130 }
10131 
10132 static void
10133 idn_mainmbox_activate(int domid)
10134 {
10135 	register int	c;
10136 	idn_domain_t	*dp = &idn_domain[domid];
10137 	procname_t	proc = "idn_mainmbox_activate";
10138 
10139 	ASSERT(IDN_DLOCK_IS_HELD(domid));
10140 
10141 	PR_PROTO("%s:%d: activating main mailbox\n", proc, domid);
10142 
10143 	for (c = 0; c < IDN_MAX_NETS; c++)
10144 		idn_mainmbox_chan_register(domid, &dp->dmbox.m_send[c],
10145 						&dp->dmbox.m_recv[c], c);
10146 }
10147 
10148 /*
10149  * Called upon disabling the SMR to deactivate all the mailboxes
10150  * so that they no longer reference the SMR that's going away.
10151  *
10152  * stopall - Indicates to stop all channel services, across the board.
10153  */
10154 static void
10155 idn_mainmbox_deactivate(ushort_t domset)
10156 {
10157 	int		svr_count;
10158 	procname_t	proc = "idn_mainmbox_deactivate";
10159 
10160 
10161 	if (domset == 0)
10162 		return;
10163 
10164 	PR_PROTO("%s: %s deactivating main mailboxes for domset 0x%x\n",
10165 		proc, (domset == (ushort_t)-1) ? "STOP-ALL" : "NORMAL", domset);
10166 
10167 	svr_count = idn_mainmbox_chan_unregister(domset, -1);
10168 
10169 	PR_PROTO("%s: deactivated %d chansvrs (domset 0x%x)\n",
10170 		proc, svr_count, domset);
10171 }
10172 
10173 static void
10174 idn_mainmbox_chan_register(int domid, idn_mainmbox_t *send_mmp,
10175 					idn_mainmbox_t *recv_mmp, int channel)
10176 {
10177 	ASSERT(IDN_DLOCK_IS_HELD(domid));
10178 
10179 	/*
10180 	 * Obtain receive mailbox lock first.
10181 	 */
10182 	mutex_enter(&recv_mmp->mm_mutex);
10183 	mutex_enter(&send_mmp->mm_mutex);
10184 
10185 	ASSERT(recv_mmp->mm_channel == (short)channel);
10186 	ASSERT(send_mmp->mm_channel == (short)channel);
10187 
10188 	recv_mmp->mm_csp = &idn.chan_servers[channel];
10189 	recv_mmp->mm_count = 0;
10190 	recv_mmp->mm_dropped = 0;
10191 	recv_mmp->mm_flags = 0;
10192 
10193 	send_mmp->mm_csp = &idn.chan_servers[channel];
10194 	send_mmp->mm_count = 0;
10195 	send_mmp->mm_dropped = 0;
10196 	send_mmp->mm_flags = 0;
10197 
10198 	mutex_exit(&send_mmp->mm_mutex);
10199 	mutex_exit(&recv_mmp->mm_mutex);
10200 
10201 	/*
10202 	 * We have to add ourselves to the respective
10203 	 * channel server's service table.
10204 	 * Note that the channel may not necessarily be
10205 	 * active at this time.
10206 	 */
10207 	ASSERT(idn.chan_servers);
10208 	/*
10209 	 * Have to get the channel server under
10210 	 * control so we can add ourselves.
10211 	 * Returns w/c_mutex.
10212 	 */
10213 	IDN_CHAN_LOCK_GLOBAL(&idn.chan_servers[channel]);
10214 	/*
10215 	 * Add the following domain (mailbox) for monitoring
10216 	 * by the respective channel server.
10217 	 */
10218 	idn_chan_addmbox(channel, DOMAINSET(domid));
10219 
10220 	IDN_CHAN_UNLOCK_GLOBAL(&idn.chan_servers[channel]);
10221 }
10222 
10223 /*
10224  * Unregister the given domain from the specified channel(s) for monitoring.
10225  */
10226 static int
10227 idn_mainmbox_chan_unregister(ushort_t domset, int channel)
10228 {
10229 	int		c, dd_count;
10230 	int		min_chan, max_chan;
10231 	procname_t	proc = "idn_mainmbox_chan_unregister";
10232 
10233 
10234 	PR_CHAN("%s: deactivating main mailboxes (channel %d) "
10235 		"for domset 0x%x\n", proc, channel, domset);
10236 
10237 	if (channel == -1) {
10238 		min_chan = 0;
10239 		max_chan = IDN_MAX_NETS - 1;
10240 	} else {
10241 		min_chan = max_chan = channel;
10242 	}
10243 	/*
10244 	 * Point all the data dispatchers to the same morgue
10245 	 * so we can kill them all at once.
10246 	 */
10247 	dd_count = 0;
10248 	for (c = min_chan; c <= max_chan; c++) {
10249 
10250 		/*
10251 		 * Have to get the channel server under
10252 		 * control so we can remove ourselves.
10253 		 * Returns w/c_mutex held.
10254 		 */
10255 		IDN_CHAN_LOCK_GLOBAL(&idn.chan_servers[c]);
10256 		/*
10257 		 * Delete the following domain (mailbox) from
10258 		 * monitoring by the respective channel server.
10259 		 */
10260 		idn_chan_delmbox(c, (ushort_t)domset);
10261 
10262 		IDN_CHAN_UNLOCK_GLOBAL(&idn.chan_servers[c]);
10263 		dd_count++;
10264 	}
10265 	PR_CHAN("%s: deactivated %d channel mboxes for domset 0x%x, chan %d\n",
10266 		proc, dd_count, domset, channel);
10267 	return (dd_count);
10268 }
10269 
10270 /*
10271  * Check if the given domain is registered with the given channel(s).
10272  */
10273 int
10274 idn_domain_is_registered(int domid, int channel, idn_chanset_t *chansetp)
10275 {
10276 	int		regcount;
10277 	int		c, min_chan, max_chan;
10278 	idn_chanset_t	chanset;
10279 	procname_t	proc = "idn_domain_is_registered";
10280 
10281 
10282 	CHANSET_ZERO(chanset);
10283 
10284 	if (idn.chan_servers == NULL) {
10285 		PR_CHAN("%s: idn.chan_servers == NULL!!\n", proc);
10286 		return (0);
10287 	}
10288 
10289 	if (channel == -1) {
10290 		min_chan = 0;
10291 		max_chan = IDN_MAX_NETS - 1;
10292 	} else {
10293 		min_chan = max_chan = channel;
10294 	}
10295 
10296 	regcount = 0;
10297 
10298 	for (c = min_chan; c <= max_chan; c++) {
10299 		idn_chansvr_t	*csp;
10300 
10301 		csp = &idn.chan_servers[c];
10302 		IDN_CHAN_LOCK_SEND(csp);
10303 		/*
10304 		 * Don't really need recv side lock since registeration
10305 		 * can't change while we're holding send side.
10306 		 * No need to wait for send side to actually suspend
10307 		 * since all we want to do is prevent the registered
10308 		 * information from changing.
10309 		 */
10310 		if (IDN_CHAN_DOMAIN_IS_REGISTERED(csp, domid)) {
10311 			regcount++;
10312 			CHANSET_ADD(chanset, c);
10313 		}
10314 
10315 		IDN_CHAN_UNLOCK_SEND(csp);
10316 	}
10317 
10318 	PR_CHAN("%s: domid %d mbox reg'd with %d channels [0x%x] (req=%d)\n",
10319 		proc, domid, regcount, chanset, channel);
10320 
10321 	if (chansetp)
10322 		*chansetp = chanset;
10323 
10324 	return (regcount);
10325 }
10326 
10327 static int
10328 idn_mainmbox_flush(int domid, idn_mainmbox_t *mmp)
10329 {
10330 	register int		qi;
10331 	register idn_mboxmsg_t	*mqp;
10332 	int		total_count = 0;
10333 	int		c, count;
10334 	int		mbox_type;
10335 	char		*mbox_str;
10336 	int		lost_io, total_lost_io = 0;
10337 	idn_chanset_t	chanset;
10338 	procname_t	proc = "idn_mainmbox_flush";
10339 
10340 
10341 	if (mmp == NULL)
10342 		return (0);
10343 
10344 	CHANSET_ZERO(chanset);
10345 
10346 	mbox_type = mmp->mm_type;
10347 	ASSERT((mbox_type == IDNMMBOX_TYPE_SEND) ||
10348 			(mbox_type == IDNMMBOX_TYPE_RECV));
10349 
10350 	mbox_str = (mbox_type == IDNMMBOX_TYPE_SEND) ? "SEND" : "RECV";
10351 
10352 	/*
10353 	 * Determine which channels this domain is registered
10354 	 * with.  If he's not registered with any, then we
10355 	 * can't touch the SMR.
10356 	 */
10357 	(void) idn_domain_is_registered(domid, -1, &chanset);
10358 
10359 	for (c = 0; c < IDN_MAX_NETS; c++) {
10360 		ushort_t	mbox_csum;
10361 
10362 		if (mmp[c].mm_smr_mboxp == NULL)
10363 			continue;
10364 		mutex_enter(&mmp[c].mm_mutex);
10365 		ASSERT(mmp[c].mm_type == mbox_type);
10366 		if (CHAN_IN_SET(chanset, c) == 0) {
10367 			/*
10368 			 * Domain is no longer registered.
10369 			 * DON'T TOUCH THE SMR - IT'S POISON!
10370 			 */
10371 			if (mmp[c].mm_smr_mboxp) {
10372 				PR_CHAN("%s:%d:%s: domain unregistered "
10373 					"w/chan %d - DUMPING SMR reference\n",
10374 					proc, domid, mbox_str, c);
10375 				lost_io = IDN_MMBOXINDEX_DIFF(mmp[c].mm_qiput,
10376 							mmp[c].mm_qiget);
10377 #ifdef DEBUG
10378 				if (mbox_type == IDNMMBOX_TYPE_RECV) {
10379 					PR_CHAN("%s:%d:%s: blowing away %d "
10380 						"incoming pkts\n",
10381 						proc, domid, mbox_str, lost_io);
10382 				} else {
10383 					PR_CHAN("%s:%d:%s: blowing away %d/%d "
10384 						"outstanding pkts\n",
10385 						proc, domid, mbox_str, lost_io,
10386 						idn_domain[domid].dio);
10387 				}
10388 #endif /* DEBUG */
10389 			}
10390 			mmp[c].mm_qiput = mmp[c].mm_qiget = 0;
10391 			mmp[c].mm_smr_mboxp = NULL;
10392 			total_lost_io += lost_io;
10393 		}
10394 		if (mmp[c].mm_smr_mboxp) {
10395 			mbox_csum =
10396 				IDN_CKSUM_MBOX(&mmp[c].mm_smr_mboxp->mt_header);
10397 			if (!VALID_NWRADDR(mmp[c].mm_smr_mboxp, 4) ||
10398 			    !VALID_MBOXHDR(&mmp[c].mm_smr_mboxp->mt_header,
10399 							c, mbox_csum)) {
10400 				lost_io = IDN_MMBOXINDEX_DIFF(mmp[c].mm_qiput,
10401 							mmp[c].mm_qiget);
10402 #ifdef DEBUG
10403 				if (mbox_type == IDNMMBOX_TYPE_RECV) {
10404 					PR_CHAN("%s:%d:%s: bad mbox.  blowing "
10405 						"away %d incoming pkts\n",
10406 						proc, domid, mbox_str, lost_io);
10407 				} else {
10408 					PR_CHAN("%s:%d:%s: bad mbox.  blowing "
10409 						"away %d/%d outstanding pkts\n",
10410 						proc, domid, mbox_str, lost_io,
10411 						idn_domain[domid].dio);
10412 				}
10413 #endif /* DEBUG */
10414 				mmp[c].mm_smr_mboxp = NULL;
10415 				mmp[c].mm_qiput = mmp[c].mm_qiget = 0;
10416 				total_lost_io += lost_io;
10417 			}
10418 		}
10419 		if (mmp[c].mm_smr_mboxp == NULL) {
10420 			mutex_exit(&mmp[c].mm_mutex);
10421 			continue;
10422 		}
10423 		mqp = &mmp[c].mm_smr_mboxp->mt_queue[0];
10424 		qi = 0;
10425 		count = 0;
10426 		/*
10427 		 * It's quite possible the remote domain may be accessing
10428 		 * these mailbox entries at the exact same time we're
10429 		 * clearing the owner bit.  That's okay.  All we're trying
10430 		 * to do at this point is to minimize the number of packets
10431 		 * the remote domain might try to process unnecessarily.
10432 		 */
10433 		do {
10434 			if (mqp[qi].ms_owner)
10435 				count++;
10436 			mqp[qi].ms_owner = 0;
10437 			IDN_MMBOXINDEX_INC(qi);
10438 		} while (qi);
10439 
10440 		lost_io = IDN_MMBOXINDEX_DIFF(mmp[c].mm_qiput, mmp[c].mm_qiget);
10441 		total_lost_io += lost_io;
10442 
10443 		mmp[c].mm_qiput = mmp[c].mm_qiget = 0;
10444 		mmp[c].mm_smr_mboxp = NULL;
10445 		mutex_exit(&mmp[c].mm_mutex);
10446 
10447 		total_count += count;
10448 
10449 		PR_CHAN("%s:%d:%s: flushed out %d mbox entries for chan %d\n",
10450 			proc, domid, mbox_str, count, c);
10451 	}
10452 
10453 	if (total_lost_io && (mbox_type == IDNMMBOX_TYPE_SEND)) {
10454 		int	lost_bufs;
10455 		/*
10456 		 * If we lost all our outstanding I/O.  We could
10457 		 * possible could have slabs now with mistakenly
10458 		 * outstanding I/O buffers.  Need to clean them up.
10459 		 * Clean up of leftovers our self.
10460 		 */
10461 		lost_bufs = smr_buf_free_all(domid);
10462 
10463 		PR_CHAN("%s:%d:%s: flushed %d/%d buffers from slabs\n",
10464 			proc, domid, mbox_str, lost_bufs, total_lost_io);
10465 	}
10466 
10467 	PR_CHAN("%s:%d:%s: flushed total of %d mailbox entries (lost %d)\n",
10468 		proc, domid, mbox_str, total_count, total_lost_io);
10469 
10470 	return (total_count);
10471 }
10472 
10473 void
10474 idn_chanserver_bind(int net, int cpuid)
10475 {
10476 	int		ocpuid;
10477 	cpu_t		*cp;
10478 	idn_chansvr_t	*csp;
10479 	kthread_id_t	tp;
10480 	procname_t	proc = "idn_chanserver_bind";
10481 
10482 	csp = &idn.chan_servers[net];
10483 	IDN_CHAN_LOCK_GLOBAL(csp);
10484 
10485 	mutex_enter(&cpu_lock);		/* protect checking cpu_ready_set */
10486 	ocpuid = csp->ch_bound_cpuid;
10487 	cp = cpu_get(cpuid);
10488 	if ((cpuid != -1) && ((cp == NULL) || !cpu_is_online(cp))) {
10489 		mutex_exit(&cpu_lock);
10490 		cmn_err(CE_WARN,
10491 			"IDN: 239: invalid CPU ID (%d) specified for "
10492 			"IDN net %d",
10493 			cpuid, net);
10494 		IDN_CHAN_UNLOCK_GLOBAL(csp);
10495 		return;
10496 	}
10497 	if ((tp = csp->ch_recv_threadp) == NULL) {
10498 		/*
10499 		 * Thread is not yet active.  Set ch_bound_cpuid
10500 		 * so when thread activates it will automatically
10501 		 * bind itself.
10502 		 */
10503 		csp->ch_bound_cpuid = -1;
10504 		csp->ch_bound_cpuid_pending = cpuid;
10505 	} else {
10506 		if (ocpuid != -1) {
10507 			thread_affinity_clear(tp);
10508 			csp->ch_bound_cpuid = -1;
10509 		}
10510 		if (cpuid >= 0) {
10511 			thread_affinity_set(tp, cpuid);
10512 			csp->ch_bound_cpuid = cpuid;
10513 		}
10514 		csp->ch_bound_cpuid_pending = -1;
10515 	}
10516 	mutex_exit(&cpu_lock);
10517 
10518 	PR_CHAN("%s: bound net/channel (%d) from cpuid %d to%scpuid %d\n",
10519 		proc, net, ocpuid, tp ? " " : " (pending) ", cpuid);
10520 
10521 	IDN_CHAN_UNLOCK_GLOBAL(csp);
10522 }
10523 
10524 #ifdef DEBUG
10525 static idn_mboxhdr_t	*prev_mhp[IDN_MAXMAX_NETS];
10526 #endif /* DEBUG */
10527 /*
10528  * Get access to the respective channel server's synchronization
10529  * header which resides in SMR space.
10530  */
10531 static idn_mboxhdr_t *
10532 idn_chan_server_syncheader(int channel)
10533 {
10534 	idn_domain_t	*ldp = &idn_domain[idn.localid];
10535 	idn_mboxtbl_t	*mtp;
10536 	idn_mboxhdr_t	*mhp;
10537 	ushort_t		mbox_csum;
10538 	procname_t	proc = "idn_chan_server_syncheader";
10539 
10540 	ASSERT(IDN_CHAN_RECV_IS_LOCKED(&idn.chan_servers[channel]));
10541 
10542 	IDN_DLOCK_SHARED(idn.localid);
10543 
10544 	if (ldp->dmbox.m_tbl == NULL) {
10545 		PR_CHAN("%s: local dmbox.m_tbl == NULL\n", proc);
10546 		IDN_DUNLOCK(idn.localid);
10547 		return (NULL);
10548 	}
10549 
10550 	mtp = IDN_MBOXTBL_PTR_CHAN(ldp->dmbox.m_tbl, channel);
10551 	mhp = &mtp->mt_header;
10552 	mbox_csum = IDN_CKSUM_MBOX(&mtp->mt_header);
10553 
10554 #ifdef DEBUG
10555 	if (mhp != prev_mhp[channel]) {
10556 		prev_mhp[channel] = mhp;
10557 		PR_CHAN("%s: chan_server (%d) cookie = 0x%x (exp 0x%x)\n",
10558 			proc, channel, IDN_GET_MBOXHDR_COOKIE(mhp),
10559 			IDN_MAKE_MBOXHDR_COOKIE(0, 0, channel));
10560 		PR_CHAN("%s: chan_server (%d) actv_ptr = 0x%x (exp 0x%x)\n",
10561 			proc, channel, mhp->mh_svr_active_ptr,
10562 			IDN_ADDR2OFFSET(&mhp->mh_svr_active));
10563 		PR_CHAN("%s: chan_server (%d) ready_ptr = 0x%x (exp 0x%x)\n",
10564 			proc, channel, mhp->mh_svr_ready_ptr,
10565 			IDN_ADDR2OFFSET(&mhp->mh_svr_ready));
10566 		PR_CHAN("%s: chan_server (%d) mbox_cksum = 0x%x (exp 0x%x)\n",
10567 			proc, channel, (int)mhp->mh_cksum, (int)mbox_csum);
10568 	}
10569 #endif /* DEBUG */
10570 
10571 	if ((IDN_ADDR2OFFSET(&mhp->mh_svr_active) !=
10572 					mhp->mh_svr_active_ptr) ||
10573 			(IDN_ADDR2OFFSET(&mhp->mh_svr_ready) !=
10574 					mhp->mh_svr_ready_ptr) ||
10575 			!VALID_MBOXHDR(mhp, channel, mbox_csum)) {
10576 		idn_chansvr_t	*csp;
10577 
10578 		csp = &idn.chan_servers[channel];
10579 		if (IDN_CHANNEL_IS_RECV_CORRUPTED(csp) == 0) {
10580 			IDN_CHANSVC_MARK_RECV_CORRUPTED(csp);
10581 
10582 			cmn_err(CE_WARN,
10583 				"IDN: 240: (channel %d) SMR CORRUPTED "
10584 				"- RELINK", channel);
10585 			cmn_err(CE_CONT,
10586 				"IDN: 240: (channel %d) cookie "
10587 				"(expected 0x%x, actual 0x%x)\n",
10588 				channel,
10589 				IDN_MAKE_MBOXHDR_COOKIE(0, 0, channel),
10590 				mhp->mh_cookie);
10591 			cmn_err(CE_CONT,
10592 				"IDN: 240: (channel %d) actv_flg "
10593 				"(expected 0x%x, actual 0x%x)\n",
10594 				channel, mhp->mh_svr_active_ptr,
10595 				IDN_ADDR2OFFSET(&mhp->mh_svr_active));
10596 			cmn_err(CE_CONT,
10597 				"IDN: 240: (channel %d) ready_flg "
10598 				"(expected 0x%x, actual 0x%x)\n",
10599 				channel, mhp->mh_svr_ready_ptr,
10600 				IDN_ADDR2OFFSET(&mhp->mh_svr_ready));
10601 		}
10602 
10603 		mhp = NULL;
10604 	}
10605 	IDN_DUNLOCK(idn.localid);
10606 
10607 	PR_CHAN("%s: channel(%d) mainhp = 0x%p\n", proc, channel, mhp);
10608 
10609 	return (mhp);
10610 }
10611 
10612 #define	CHANSVR_SYNC_CACHE(csp, mmp, chan) \
10613 { \
10614 	ASSERT(IDN_CHAN_RECV_IS_LOCKED(csp)); \
10615 	if ((csp)->ch_recv_changed) { \
10616 		register int _d; \
10617 		(csp)->ch_recv_scanset = (csp)->ch_recv_scanset_pending; \
10618 		(csp)->ch_recv_domset = (csp)->ch_recv_domset_pending; \
10619 		for (_d = 0; _d < MAX_DOMAINS; _d++) { \
10620 			if (DOMAIN_IN_SET((csp)->ch_recv_domset, _d)) { \
10621 				(mmp)[_d] = \
10622 					&idn_domain[_d].dmbox.m_recv[chan]; \
10623 			} else { \
10624 				(mmp)[_d] = NULL; \
10625 			} \
10626 		} \
10627 		(csp)->ch_recv_changed = 0; \
10628 	} \
10629 }
10630 #define	CHANSVR_NEXT_DOMID(csp, i, d) \
10631 { \
10632 	(i) = ((i) + 1) & (MAX_DOMAINS - 1); \
10633 	(d) = (int)(((csp)->ch_recv_scanset >> ((i) << 2)) & 0xf); \
10634 }
10635 #define	CHANSVR_RESET_INDEX(i)	((i) = -1)
10636 
10637 #ifdef DEBUG
10638 static idn_mainmbox_t	*Mmp[IDN_MAXMAX_NETS][MAX_DOMAINS];
10639 #endif /* DEBUG */
10640 
10641 static void
10642 idn_chan_server(idn_chansvr_t **cspp)
10643 {
10644 	idn_mboxhdr_t	*mainhp;
10645 	register idn_chansvr_t		*csp;
10646 	register idn_mboxmsg_t		*mqp;
10647 #ifdef DEBUG
10648 	idn_mainmbox_t			**mmp;
10649 #else
10650 	idn_mainmbox_t			*mmp[MAX_DOMAINS];
10651 #endif /* DEBUG */
10652 	register int	qi;
10653 	struct idn	*sip;
10654 	int		channel;
10655 	int		cpuid;
10656 	int		empty;
10657 	int		tot_pktcount, tot_dropcount;
10658 	register int	index;
10659 	register int	domid;
10660 	register int	idleloops;
10661 	procname_t	proc = "idn_chan_server";
10662 
10663 
10664 #ifdef DEBUG
10665 	mmp = &Mmp[(*cspp)->ch_id][0];
10666 	bzero(mmp, MAX_DOMAINS * sizeof (idn_mainmbox_t *));
10667 #else /* DEBUG */
10668 	bzero(mmp, sizeof (mmp));
10669 #endif /* DEBUG */
10670 
10671 	tot_pktcount = tot_dropcount = 0;
10672 
10673 	ASSERT(cspp && *cspp);
10674 
10675 	csp = *cspp;
10676 	channel = csp->ch_id;
10677 	sip = IDN_INST2SIP(channel);
10678 	ASSERT(sip);
10679 
10680 	PR_CHAN("%s: CHANNEL SERVER (channel %d) GOING ACTIVE...\n",
10681 		proc, channel);
10682 
10683 	IDN_CHAN_LOCK_RECV(csp);
10684 	IDN_CHAN_RECV_INPROGRESS(csp);
10685 	ASSERT(csp->ch_recv_threadp == curthread);
10686 	mutex_enter(&cpu_lock);
10687 	if ((cpuid = csp->ch_bound_cpuid_pending) != -1) {
10688 		cpu_t	*cp = cpu_get(cpuid);
10689 		/*
10690 		 * We've been requested to bind to
10691 		 * a particular cpu.
10692 		 */
10693 		if ((cp == NULL) || !cpu_is_online(cp)) {
10694 			/*
10695 			 * Cpu seems to have gone away or gone offline
10696 			 * since originally requested.
10697 			 */
10698 			mutex_exit(&cpu_lock);
10699 			cmn_err(CE_WARN,
10700 				"IDN: 239: invalid CPU ID (%d) specified for "
10701 				"IDN net %d",
10702 				cpuid, channel);
10703 		} else {
10704 			csp->ch_bound_cpuid = cpuid;
10705 			affinity_set(csp->ch_bound_cpuid);
10706 			mutex_exit(&cpu_lock);
10707 		}
10708 		csp->ch_bound_cpuid_pending = -1;
10709 	} else {
10710 		mutex_exit(&cpu_lock);
10711 	}
10712 	if (csp->ch_bound_cpuid != -1) {
10713 		PR_CHAN("%s: thread bound to cpuid %d\n",
10714 			proc, csp->ch_bound_cpuid);
10715 	}
10716 	/*
10717 	 * Only the first (main) mbox header is used for
10718 	 * synchronization with data delivery since there is
10719 	 * only data server for all mailboxes for this
10720 	 * given channel.
10721 	 */
10722 	CHANSVR_SYNC_CACHE(csp, mmp, channel);
10723 
10724 	mainhp = ((csp->ch_recv_domcount > 0) &&
10725 		    IDN_CHANNEL_IS_RECV_ACTIVE(csp))
10726 			? idn_chan_server_syncheader(channel) : NULL;
10727 
10728 	if (mainhp && IDN_CHANNEL_IS_RECV_ACTIVE(csp))
10729 		mainhp->mh_svr_active = 1;
10730 
10731 	ASSERT(csp->ch_recv_domcount ?
10732 		(csp->ch_recv_scanset && csp->ch_recv_domset) : 1);
10733 
10734 	IDN_CHAN_UNLOCK_RECV(csp);
10735 
10736 	empty = 0;
10737 	idleloops = 0;
10738 	CHANSVR_RESET_INDEX(index);
10739 
10740 	/*
10741 	 * ---------------------------------------------
10742 	 */
10743 	/*CONSTCOND*/
10744 	while (1) {
10745 		register int	pktcount;
10746 		register int	dropcount;
10747 		ushort_t		mbox_csum;
10748 		idn_mboxtbl_t	*smr_mboxp;	/* points to SMR space */
10749 		register smr_offset_t	bufoffset;
10750 #ifdef DEBUG
10751 		register smr_pkthdr_t	*hdrp;
10752 		idn_netaddr_t		netaddr;
10753 #endif /* DEBUG */
10754 
10755 		/*
10756 		 * Speed through and find the next available domid.
10757 		 */
10758 		CHANSVR_NEXT_DOMID(csp, index, domid);
10759 
10760 		if (!index) {
10761 			/*
10762 			 * We only check state changes when
10763 			 * we wrap around.  Done for performance.
10764 			 */
10765 			if (!IDN_CHANNEL_IS_RECV_ACTIVE(csp) ||
10766 					csp->ch_recv.c_checkin ||
10767 					(idn.state != IDNGS_ONLINE)) {
10768 
10769 				PR_DATA("%s: (channel %d) %s\n",
10770 					proc, channel,
10771 					IDN_CHANNEL_IS_DETACHED(csp)
10772 					? "DEAD" :
10773 					IDN_CHANNEL_IS_PENDING(csp)
10774 					? "IDLED" :
10775 					IDN_CHANNEL_IS_ACTIVE(csp)
10776 					? "ACTIVE" : "DISABLED");
10777 				goto cc_sleep;
10778 			}
10779 		}
10780 		if (csp->ch_recv.c_checkin)
10781 			goto cc_sleep;
10782 
10783 		if (empty == csp->ch_recv_domcount) {
10784 			empty = 0;
10785 			goto cc_slowdown;
10786 		}
10787 
10788 		ASSERT(mmp[domid] != NULL);
10789 
10790 		mutex_enter(&mmp[domid]->mm_mutex);
10791 		if ((smr_mboxp = mmp[domid]->mm_smr_mboxp) == NULL) {
10792 			/*
10793 			 * Somebody is trying to shut things down.
10794 			 */
10795 			empty++;
10796 			mutex_exit(&mmp[domid]->mm_mutex);
10797 			continue;
10798 		}
10799 		ASSERT(mmp[domid]->mm_channel == (short)channel);
10800 		/*
10801 		 * We don't care if the mm_smr_mboxp is nullified
10802 		 * after this point.  The thread attempting to shut
10803 		 * us down has to formally pause this channel before
10804 		 * anything is official anyway.  So, we can continue
10805 		 * with our local SMR reference until the thread
10806 		 * shutting us down really stops us.
10807 		 *
10808 		 * Need to get the qiget index _before_ we drop the
10809 		 * lock since it might get flushed (idn_mainmbox_flush)
10810 		 * once we drop the mm_mutex.
10811 		 *
10812 		 * We prefer not to hold the mm_mutex across the
10813 		 * idn_recv_mboxdata() call since that may be time-
10814 		 * consuming.
10815 		 */
10816 		qi  = mmp[domid]->mm_qiget;
10817 
10818 		/*
10819 		 * Check the mailbox header if checksum is turned on.
10820 		 */
10821 		mbox_csum = IDN_CKSUM_MBOX(&smr_mboxp->mt_header);
10822 		if (!VALID_MBOXHDR(&smr_mboxp->mt_header, channel, mbox_csum)) {
10823 			IDN_KSTAT_INC(sip, si_mboxcrc);
10824 			IDN_KSTAT_INC(sip, si_ierrors);
10825 			if (!(mmp[domid]->mm_flags & IDNMMBOX_FLAG_CORRUPTED)) {
10826 				cmn_err(CE_WARN,
10827 					"IDN: 241: [recv] (domain %d, "
10828 					"channel %d) SMR CORRUPTED - RELINK",
10829 					domid, channel);
10830 				mmp[domid]->mm_flags |= IDNMMBOX_FLAG_CORRUPTED;
10831 			}
10832 			empty = 0;
10833 			mutex_exit(&mmp[domid]->mm_mutex);
10834 			goto cc_sleep;
10835 		}
10836 		mutex_exit(&mmp[domid]->mm_mutex);
10837 		mqp = &smr_mboxp->mt_queue[0];
10838 
10839 		pktcount = dropcount = 0;
10840 
10841 		if (mqp[qi].ms_owner == 0)
10842 			goto cc_next;
10843 
10844 		bufoffset = IDN_BFRAME2OFFSET(mqp[qi].ms_bframe);
10845 
10846 		if (!VALID_NWROFFSET(bufoffset, IDN_SMR_BUFSIZE)) {
10847 			/* ASSERT(0); */
10848 			mqp[qi].ms_flag |= IDN_MBOXMSG_FLAG_ERR_BADOFFSET;
10849 			mqp[qi].ms_owner = 0;
10850 			IDN_MMBOXINDEX_INC(qi);
10851 			dropcount++;
10852 
10853 			IDN_KSTAT_INC(sip, si_smraddr);
10854 			IDN_KSTAT_INC(sip, si_ierrors);
10855 
10856 		} else {
10857 			PR_DATA("%s: (channel %d) pkt (off 0x%x, "
10858 				"qiget %d) from domain %d\n",
10859 				proc, channel, bufoffset, qi, domid);
10860 #ifdef DEBUG
10861 
10862 			hdrp = IDN_BUF2HDR(IDN_OFFSET2ADDR(bufoffset));
10863 			netaddr.netaddr = hdrp->b_netaddr;
10864 			ASSERT(netaddr.net.chan == (ushort_t)channel);
10865 #endif /* DEBUG */
10866 
10867 			if (idn_recv_mboxdata(channel,
10868 					IDN_OFFSET2ADDR(bufoffset)) < 0) {
10869 				mutex_enter(&mmp[domid]->mm_mutex);
10870 				if (!(mmp[domid]->mm_flags &
10871 					IDNMMBOX_FLAG_CORRUPTED)) {
10872 					cmn_err(CE_WARN,
10873 						"IDN: 241: [recv] (domain "
10874 						"%d, channel %d) SMR "
10875 						"CORRUPTED - RELINK",
10876 						domid, channel);
10877 					mmp[domid]->mm_flags |=
10878 						IDNMMBOX_FLAG_CORRUPTED;
10879 				}
10880 				mutex_exit(&mmp[domid]->mm_mutex);
10881 			}
10882 
10883 			mqp[qi].ms_owner = 0;
10884 			IDN_MMBOXINDEX_INC(qi);
10885 			pktcount++;
10886 		}
10887 
10888 cc_next:
10889 
10890 		mutex_enter(&mmp[domid]->mm_mutex);
10891 		if (mmp[domid]->mm_smr_mboxp) {
10892 			if (dropcount)
10893 				mmp[domid]->mm_dropped += dropcount;
10894 			mmp[domid]->mm_qiget = qi;
10895 			mmp[domid]->mm_count += pktcount;
10896 		}
10897 		mutex_exit(&mmp[domid]->mm_mutex);
10898 
10899 		if (pktcount == 0) {
10900 			empty++;
10901 		} else {
10902 			csp->ch_recv_waittime = IDN_NETSVR_WAIT_MIN;
10903 			empty = 0;
10904 			idleloops = 0;
10905 
10906 			PR_DATA("%s: (channel %d) dom=%d, pktcnt=%d\n",
10907 				proc, channel, domid, pktcount);
10908 		}
10909 
10910 		continue;
10911 
10912 cc_slowdown:
10913 
10914 #ifdef DEBUG
10915 		if (idleloops == 0) {
10916 			PR_DATA("%s: (channel %d) going SOFT IDLE...\n",
10917 				proc, channel);
10918 		}
10919 #endif /* DEBUG */
10920 		if (idleloops++ < IDN_NETSVR_SPIN_COUNT) {
10921 			/*
10922 			 * At this level we only busy-wait.
10923 			 * Get back into action.
10924 			 */
10925 			continue;
10926 		}
10927 		idleloops = 0;
10928 
10929 cc_sleep:
10930 
10931 		if (mainhp)
10932 			mainhp->mh_svr_active = 0;
10933 
10934 		IDN_CHAN_LOCK_RECV(csp);
10935 
10936 cc_die:
10937 
10938 		ASSERT(IDN_CHAN_RECV_IS_LOCKED(csp));
10939 
10940 		if (!IDN_CHANNEL_IS_RECV_ACTIVE(csp) &&
10941 					IDN_CHANNEL_IS_DETACHED(csp)) {
10942 			/*
10943 			 * Time to die...
10944 			 */
10945 			PR_CHAN("%s: (channel %d) serviced %d "
10946 				"packets, drop = %d\n", proc, channel,
10947 				tot_pktcount, tot_dropcount);
10948 			PR_CHAN("%s: (channel %d) TERMINATING\n",
10949 				proc, channel);
10950 			PR_CHAN("%s: (channel %d) ch_morguep = %p\n",
10951 				proc, channel, csp->ch_recv_morguep);
10952 
10953 			csp->ch_recv_threadp = NULL;
10954 #ifdef DEBUG
10955 			for (index = 0; index < csp->ch_recv_domcount;
10956 							index++) {
10957 				if ((int)((csp->ch_recv_scanset >>
10958 							(index*4)) & 0xf)
10959 							== domid) {
10960 					PR_DATA("%s: WARNING (channel %d) "
10961 						"DROPPING domid %d...\n",
10962 						proc, channel, domid);
10963 				}
10964 			}
10965 #endif /* DEBUG */
10966 			IDN_CHAN_RECV_DONE(csp);
10967 
10968 			sema_v(csp->ch_recv_morguep);
10969 
10970 			IDN_CHAN_UNLOCK_RECV(csp);
10971 
10972 			thread_exit();
10973 			/* not reached */
10974 		}
10975 
10976 		do {
10977 			if (IDN_CHANNEL_IS_DETACHED(csp)) {
10978 				PR_CHAN("%s: (channel %d) going to DIE...\n",
10979 					proc, channel);
10980 				goto cc_die;
10981 			}
10982 #ifdef DEBUG
10983 			if (IDN_CHANNEL_IS_RECV_ACTIVE(csp) &&
10984 					(csp->ch_recv_waittime <=
10985 						IDN_NETSVR_WAIT_MAX)) {
10986 				PR_CHAN("%s: (channel %d) going SOFT IDLE "
10987 					"(waittime = %d ticks)...\n",
10988 					proc, channel,
10989 					csp->ch_recv_waittime);
10990 			} else {
10991 				PR_CHAN("%s: (channel %d) going "
10992 					"HARD IDLE...\n", proc, channel);
10993 			}
10994 #endif /* DEBUG */
10995 			IDN_CHAN_RECV_DONE(csp);
10996 
10997 			/*
10998 			 * If we're being asked to check-in then
10999 			 * go into a hard sleep.  Want to give the
11000 			 * thread requesting us to checkin a chance.
11001 			 */
11002 			while (csp->ch_recv.c_checkin)
11003 				cv_wait(&csp->ch_recv_cv,
11004 					&csp->ch_recv.c_mutex);
11005 
11006 			if (csp->ch_recv_waittime > IDN_NETSVR_WAIT_MAX)
11007 				cv_wait(&csp->ch_recv_cv,
11008 					&csp->ch_recv.c_mutex);
11009 			else
11010 				(void) cv_timedwait(&csp->ch_recv_cv,
11011 						&csp->ch_recv.c_mutex,
11012 						lbolt +
11013 						csp->ch_recv_waittime);
11014 
11015 			IDN_CHAN_RECV_INPROGRESS(csp);
11016 
11017 			IDN_KSTAT_INC(sip, si_sigsvr);
11018 
11019 			if (csp->ch_recv_waittime <= IDN_NETSVR_WAIT_MAX)
11020 				csp->ch_recv_waittime <<=
11021 						IDN_NETSVR_WAIT_SHIFT;
11022 
11023 		} while (!IDN_CHANNEL_IS_RECV_ACTIVE(csp));
11024 
11025 		/*
11026 		 * Before we see the world (and touch SMR space),
11027 		 * see if we've been told to die.
11028 		 */
11029 		mainhp = NULL;
11030 		/*
11031 		 * The world may have changed since we were
11032 		 * asleep.  Need to resync cache and check for a
11033 		 * new syncheader.
11034 		 *
11035 		 * Reset chansvr cache against any changes in
11036 		 * mbox fields we need (mm_qiget).
11037 		 */
11038 		CHANSVR_SYNC_CACHE(csp, mmp, channel);
11039 		if (csp->ch_recv_domcount <= 0) {
11040 			/*
11041 			 * Everybody disappeared on us.
11042 			 * Go back to sleep.
11043 			 */
11044 			goto cc_die;
11045 		}
11046 		ASSERT(csp->ch_recv_scanset && csp->ch_recv_domset);
11047 
11048 		mainhp = idn_chan_server_syncheader(channel);
11049 		if (mainhp == NULL) {
11050 			/*
11051 			 * Bummer...we're idling...
11052 			 */
11053 			goto cc_die;
11054 		}
11055 
11056 		mainhp->mh_svr_active = 1;
11057 
11058 		IDN_CHAN_UNLOCK_RECV(csp);
11059 		/*
11060 		 * Reset the domid index after sleeping.
11061 		 */
11062 		CHANSVR_RESET_INDEX(index);
11063 
11064 		empty = 0;
11065 		idleloops = 0;
11066 	}
11067 }
11068 
11069 #if 0
11070 /*
11071  * We maintain a separate function for flushing the STREAMs
11072  * queue of a channel because it must be done outside the
11073  * context of the idn_chan_action routine.  The streams flush
11074  * cannot occur inline with the idn_chan_action because
11075  * the act of flushing may cause IDN send functions to be called
11076  * directly and thus locks to be obtained which could result
11077  * in deadlocks.
11078  */
11079 static void
11080 idn_chan_flush(idn_chansvr_t *csp)
11081 {
11082 	queue_t		*rq;
11083 	struct idn	*sip;
11084 	int		flush_type = 0;
11085 	idn_chaninfo_t	*csend, *crecv;
11086 	procname_t	proc = "idn_chan_flush";
11087 
11088 	csend = &csp->ch_send;
11089 	crecv = &csp->ch_recv;
11090 
11091 	mutex_enter(&crecv->c_mutex);
11092 	mutex_enter(&csend->c_mutex);
11093 
11094 	if (crecv->c_state & IDN_CHANSVC_STATE_FLUSH)
11095 		flush_type |= FLUSHR;
11096 
11097 	if (csend->c_state & IDN_CHANSVC_STATE_FLUSH)
11098 		flush_type |= FLUSHW;
11099 
11100 	if (flush_type) {
11101 		rq = NULL;
11102 		rw_enter(&idn.struprwlock, RW_READER);
11103 		if ((sip = IDN_INST2SIP(csp->ch_id)) != NULL)
11104 			rq = sip->si_ipq;
11105 		rw_exit(&idn.struprwlock);
11106 		if (rq) {
11107 			/*
11108 			 * Flush the STREAM if possible
11109 			 * to get the channel server coherent
11110 			 * enough to respond to us.
11111 			 */
11112 			PR_CHAN("%s: sending FLUSH (%x) to channel %d\n",
11113 				proc, flush_type, csp->ch_id);
11114 
11115 			(void) putnextctl1(rq, M_FLUSH, flush_type);
11116 		}
11117 		crecv->c_state &= ~IDN_CHANSVC_STATE_FLUSH;
11118 		csend->c_state &= ~IDN_CHANSVC_STATE_FLUSH;
11119 
11120 		if (crecv->c_waiters)
11121 			cv_broadcast(&crecv->c_cv);
11122 	}
11123 
11124 	mutex_exit(&csend->c_mutex);
11125 	mutex_exit(&crecv->c_mutex);
11126 }
11127 #endif /* 0 */
11128 
11129 /*
11130  * Locks are with respect to SEND/RECV locks (c_mutex).
11131  *
11132  * STOP/SUSPEND/DETACH
11133  *	- Entered with locks dropped, leave with locks held.
11134  *	  DETACH - lock dropped manually.
11135  * RESTART/RESUME
11136  *	- Entered with locks held, leave with locks dropped.
11137  * ATTACH
11138  *	- both enter and leave with locks dropped.
11139  */
11140 static void
11141 idn_chan_action(int channel, idn_chanaction_t chanaction, int wait)
11142 {
11143 	uchar_t		clr_state, set_state;
11144 	uint_t		is_running;
11145 	domainset_t	closed_slabwaiters = 0;
11146 	struct idn	*sip;
11147 	idn_chansvr_t	*csp;
11148 	idn_chaninfo_t	*csend, *crecv;
11149 	procname_t	proc = "idn_chan_action";
11150 
11151 	ASSERT((channel >= 0) && (channel < IDN_MAX_NETS));
11152 	ASSERT(idn.chan_servers);
11153 
11154 	csp = &idn.chan_servers[channel];
11155 
11156 	PR_CHAN("%s: requesting %s for channel %d\n",
11157 		proc, chanaction_str[(int)chanaction], channel);
11158 
11159 	csend = &csp->ch_send;
11160 	crecv = &csp->ch_recv;
11161 
11162 	ASSERT(IDN_CHAN_GLOBAL_IS_LOCKED(csp));
11163 
11164 	clr_state = set_state = 0;
11165 
11166 	switch (chanaction) {
11167 	case IDNCHAN_ACTION_DETACH:
11168 		clr_state = IDN_CHANSVC_STATE_MASK;
11169 		/*FALLTHROUGH*/
11170 
11171 	case IDNCHAN_ACTION_STOP:
11172 		clr_state |= IDN_CHANSVC_STATE_ENABLED;
11173 		/*FALLTHROUGH*/
11174 
11175 	case IDNCHAN_ACTION_SUSPEND:
11176 		clr_state |= IDN_CHANSVC_STATE_ACTIVE;
11177 
11178 		/*
11179 		 * Must maintain this locking order.
11180 		 * Set asynchronous check-in flags.
11181 		 */
11182 		crecv->c_checkin = 1;
11183 		csend->c_checkin = 1;
11184 
11185 		is_running = 0;
11186 		if ((csend->c_inprogress || crecv->c_inprogress) &&
11187 			wait && (csp->ch_recv_threadp != curthread)) {
11188 
11189 			rw_enter(&idn.struprwlock, RW_READER);
11190 			if ((sip = IDN_INST2SIP(channel)) != NULL) {
11191 				/*
11192 				 * Temporarily turn off the STREAM
11193 				 * to give a chance to breath.
11194 				 */
11195 				is_running = sip->si_flags & IDNRUNNING;
11196 				if (is_running)
11197 					sip->si_flags &= ~IDNRUNNING;
11198 			}
11199 			rw_exit(&idn.struprwlock);
11200 		}
11201 
11202 		mutex_enter(&crecv->c_mutex);
11203 		crecv->c_state &= ~clr_state;
11204 
11205 		mutex_enter(&csend->c_mutex);
11206 		csend->c_state &= ~clr_state;
11207 
11208 		/*
11209 		 * It's possible the channel server could come
11210 		 * through this flow itself due to putting data upstream
11211 		 * that ultimately turned around and came back down for
11212 		 * sending.  If this is the case we certainly don't
11213 		 * want to cv_wait, otherwise we'll obviously deadlock
11214 		 * waiting for ourself.  So, only block if somebody
11215 		 * other than the channel server we're attempting to
11216 		 * suspend/stop.
11217 		 */
11218 		if (wait && (csp->ch_recv_threadp != curthread)) {
11219 			int	do_flush = 0;
11220 
11221 			if (csend->c_inprogress || crecv->c_inprogress)
11222 				do_flush++;
11223 
11224 			if (do_flush) {
11225 				rw_enter(&idn.struprwlock, RW_READER);
11226 				if ((sip = IDN_INST2SIP(channel)) != NULL) {
11227 					/*
11228 					 * Temporarily turn off the STREAM
11229 					 * to give a chance to breath.
11230 					 */
11231 					if (sip->si_flags & IDNRUNNING) {
11232 						is_running = 1;
11233 						sip->si_flags &= ~IDNRUNNING;
11234 					}
11235 				}
11236 				rw_exit(&idn.struprwlock);
11237 			}
11238 
11239 			/*
11240 			 * If we have any senders in-progress
11241 			 * it's possible they're stuck waiting
11242 			 * down in smr_buf_alloc which may never
11243 			 * arrive if we're in an unlink process.
11244 			 * Rather than wait for it to timeout
11245 			 * let's be proactive so we can disconnect
11246 			 * asap.
11247 			 */
11248 			closed_slabwaiters = csp->ch_reg_domset;
11249 			DOMAINSET_ADD(closed_slabwaiters, idn.localid);
11250 			if (closed_slabwaiters)
11251 				smr_slabwaiter_close(closed_slabwaiters);
11252 
11253 			do {
11254 				/*
11255 				 * It's possible due to a STREAMs
11256 				 * loopback from read queue to write queue
11257 				 * that receiver and sender may be same
11258 				 * thread, i.e. receiver's inprogress
11259 				 * flag will never clear until sender's
11260 				 * inprogress flag clears.  So, we wait
11261 				 * for sender's inprogress first.
11262 				 */
11263 				while (csend->c_inprogress) {
11264 					mutex_exit(&crecv->c_mutex);
11265 					while (csend->c_inprogress) {
11266 						csend->c_waiters++;
11267 						cv_wait(&csend->c_cv,
11268 							&csend->c_mutex);
11269 						csend->c_waiters--;
11270 					}
11271 					/*
11272 					 * Maintain lock ordering.
11273 					 * Eventually we will catch
11274 					 * him due to the flag settings.
11275 					 */
11276 					mutex_exit(&csend->c_mutex);
11277 					mutex_enter(&crecv->c_mutex);
11278 					mutex_enter(&csend->c_mutex);
11279 				}
11280 				if (crecv->c_inprogress) {
11281 					mutex_exit(&csend->c_mutex);
11282 					while (crecv->c_inprogress) {
11283 						crecv->c_waiters++;
11284 						cv_wait(&crecv->c_cv,
11285 							&crecv->c_mutex);
11286 						crecv->c_waiters--;
11287 					}
11288 					mutex_enter(&csend->c_mutex);
11289 				}
11290 			} while (csend->c_inprogress);
11291 		}
11292 
11293 		if (is_running) {
11294 			/*
11295 			 * Restore the IDNRUNNING bit in
11296 			 * the flags to let them know the
11297 			 * channel is still alive.
11298 			 */
11299 			rw_enter(&idn.struprwlock, RW_READER);
11300 			if ((sip = IDN_INST2SIP(channel)) != NULL)
11301 				sip->si_flags |= IDNRUNNING;
11302 			rw_exit(&idn.struprwlock);
11303 		}
11304 
11305 		if (closed_slabwaiters) {
11306 			/*
11307 			 * We can reopen now since at this point no new
11308 			 * slabwaiters will attempt to come in and wait.
11309 			 */
11310 			smr_slabwaiter_open(csp->ch_reg_domset);
11311 		}
11312 
11313 		crecv->c_checkin = 0;
11314 		csend->c_checkin = 0;
11315 
11316 		/*
11317 		 * ALL leave with locks held.
11318 		 */
11319 		PR_CHAN("%s: action (%s) for channel %d - COMPLETED\n",
11320 			proc, chanaction_str[(int)chanaction], channel);
11321 		break;
11322 
11323 	case IDNCHAN_ACTION_ATTACH:
11324 		mutex_enter(&crecv->c_mutex);
11325 		mutex_enter(&csend->c_mutex);
11326 		set_state |= csp->ch_state & IDN_CHANSVC_STATE_ATTACHED;
11327 		/*FALLTHROUGH*/
11328 
11329 	case IDNCHAN_ACTION_RESTART:
11330 		set_state |= csp->ch_state & IDN_CHANSVC_STATE_ENABLED;
11331 		/*FALLTHROUGH*/
11332 
11333 	case IDNCHAN_ACTION_RESUME:
11334 		ASSERT(IDN_CHAN_LOCAL_IS_LOCKED(csp));
11335 		set_state |= csp->ch_state & IDN_CHANSVC_STATE_ACTIVE;
11336 
11337 		crecv->c_state |= set_state;
11338 		csend->c_state |= set_state;
11339 
11340 		/*
11341 		 * The channel server itself could come through this
11342 		 * flow, so obviously no point in attempting to wake
11343 		 * ourself up!.
11344 		 */
11345 		if (csp->ch_recv_threadp &&
11346 				(csp->ch_recv_threadp != curthread))
11347 			cv_signal(&csp->ch_recv_cv);
11348 
11349 		PR_CHAN("%s: action (%s) for channel %d - COMPLETED\n",
11350 			proc, chanaction_str[(int)chanaction], channel);
11351 
11352 		/*
11353 		 * Leaves with lock released.
11354 		 */
11355 		mutex_exit(&csend->c_mutex);
11356 		mutex_exit(&crecv->c_mutex);
11357 		break;
11358 
11359 	default:
11360 		ASSERT(0);
11361 		break;
11362 	}
11363 }
11364 
11365 static void
11366 idn_chan_addmbox(int channel, ushort_t domset)
11367 {
11368 	idn_chansvr_t	*csp;
11369 	register int	d;
11370 	procname_t	proc = "idn_chan_addmbox";
11371 
11372 
11373 	PR_CHAN("%s: adding domset 0x%x main mailboxes to channel %d\n",
11374 		proc, domset, channel);
11375 
11376 	ASSERT(idn.chan_servers);
11377 
11378 	csp = &idn.chan_servers[channel];
11379 
11380 	/*
11381 	 * Adding domains to a channel can be
11382 	 * asynchonous, so we don't bother waiting.
11383 	 */
11384 	IDN_CHANNEL_SUSPEND(channel, 0);
11385 
11386 	/*
11387 	 * Now we have the sending and receiving sides blocked
11388 	 * for this channel.
11389 	 */
11390 	for (d = 0; d < MAX_DOMAINS; d++) {
11391 		if (!DOMAIN_IN_SET(domset, d))
11392 			continue;
11393 		if (IDN_CHAN_DOMAIN_IS_REGISTERED(csp, d)) {
11394 			DOMAINSET_DEL(domset, d);
11395 			continue;
11396 		}
11397 		IDN_CHANSVR_SCANSET_ADD_PENDING(csp, d);
11398 		DOMAINSET_ADD(csp->ch_recv_domset_pending, d);
11399 		IDN_CHAN_DOMAIN_REGISTER(csp, d);
11400 
11401 		PR_CHAN("%s: domain %d (channel %d) RECV (pending) "
11402 			"scanset = 0x%lx\n", proc, d, channel,
11403 			csp->ch_recv_scanset_pending);
11404 		PR_CHAN("%s: domain %d (channel %d) domset = 0x%x\n",
11405 			proc, d, channel, (uint_t)csp->ch_reg_domset);
11406 
11407 		CHECKPOINT_OPENED(IDNSB_CHKPT_CHAN,
11408 					idn_domain[d].dhw.dh_boardset, 1);
11409 	}
11410 	if (domset)
11411 		csp->ch_recv_changed = 1;
11412 
11413 	IDN_CHANNEL_RESUME(channel);
11414 }
11415 
11416 static void
11417 idn_chan_delmbox(int channel, ushort_t domset)
11418 {
11419 	idn_chansvr_t	*csp;
11420 	register int	d;
11421 	procname_t	proc = "idn_chan_delmbox";
11422 
11423 
11424 	PR_CHAN("%s: deleting domset 0x%x main mailboxes from channel %d\n",
11425 		proc, domset, channel);
11426 
11427 	ASSERT(idn.chan_servers);
11428 
11429 	csp = &idn.chan_servers[channel];
11430 
11431 	/*
11432 	 * Here we have to wait for the channel server
11433 	 * as it's vital that we don't return without guaranteeing
11434 	 * that the given domset is no longer registered.
11435 	 */
11436 	IDN_CHANNEL_SUSPEND(channel, 1);
11437 
11438 	/*
11439 	 * Now we have the sending and receiving sides blocked
11440 	 * for this channel.
11441 	 */
11442 	for (d = 0; d < MAX_DOMAINS; d++) {
11443 		if (!DOMAIN_IN_SET(domset, d))
11444 			continue;
11445 		if (!IDN_CHAN_DOMAIN_IS_REGISTERED(csp, d)) {
11446 			DOMAINSET_DEL(domset, d);
11447 			continue;
11448 		}
11449 		/*
11450 		 * This domain has a mailbox hanging on this channel.
11451 		 * Get him out.
11452 		 *
11453 		 * First remove him from the receive side.
11454 		 */
11455 		ASSERT(csp->ch_recv_domcount > 0);
11456 		IDN_CHANSVR_SCANSET_DEL_PENDING(csp, d);
11457 		DOMAINSET_DEL(csp->ch_recv_domset_pending, d);
11458 		IDN_CHAN_DOMAIN_UNREGISTER(csp, d);
11459 
11460 		PR_CHAN("%s: domain %d (channel %d) RECV (pending) "
11461 			"scanset = 0x%lx\n", proc, d, channel,
11462 			csp->ch_recv_scanset_pending);
11463 		PR_CHAN("%s: domain %d (channel %d) domset = 0x%x\n",
11464 			proc, d, channel, (uint_t)csp->ch_reg_domset);
11465 
11466 		CHECKPOINT_CLOSED(IDNSB_CHKPT_CHAN,
11467 					idn_domain[d].dhw.dh_boardset, 2);
11468 
11469 	}
11470 	if (domset)
11471 		csp->ch_recv_changed = 1;
11472 
11473 	IDN_CHANNEL_RESUME(channel);
11474 }
11475 
11476 static int
11477 idn_valid_etherheader(struct ether_header *ehp)
11478 {
11479 	uchar_t	*eap;
11480 
11481 	eap = &ehp->ether_dhost.ether_addr_octet[0];
11482 
11483 	if ((eap[IDNETHER_ZERO] != 0) && (eap[IDNETHER_ZERO] != 0xff))
11484 		return (0);
11485 
11486 	if ((eap[IDNETHER_COOKIE1] != IDNETHER_COOKIE1_VAL) &&
11487 		(eap[IDNETHER_COOKIE1] != 0xff))
11488 		return (0);
11489 
11490 	if ((eap[IDNETHER_COOKIE2] != IDNETHER_COOKIE2_VAL) &&
11491 		(eap[IDNETHER_COOKIE2] != 0xff))
11492 		return (0);
11493 
11494 	if ((eap[IDNETHER_RESERVED] != IDNETHER_RESERVED_VAL) &&
11495 		(eap[IDNETHER_RESERVED] != 0xff))
11496 		return (0);
11497 
11498 	if (!VALID_UCHANNEL(eap[IDNETHER_CHANNEL]) &&
11499 		(eap[IDNETHER_CHANNEL] != 0xff))
11500 		return (0);
11501 
11502 	if (!VALID_UDOMAINID(IDN_NETID2DOMID(eap[IDNETHER_NETID])) &&
11503 		(eap[IDNETHER_NETID] != 0xff))
11504 		return (0);
11505 
11506 	return (1);
11507 }
11508 
11509 /*
11510  * Packet header has already been filled in.
11511  * RETURNS:	0
11512  *		ENOLINK
11513  *		EPROTO
11514  *		ENOSPC
11515  */
11516 /*ARGSUSED*/
11517 static int
11518 idn_send_mboxdata(int domid, struct idn *sip, int channel, caddr_t bufp)
11519 {
11520 	idn_mainmbox_t	*mmp;
11521 	idn_mboxmsg_t	*mqp;
11522 	smr_pkthdr_t	*hdrp;
11523 	smr_offset_t	bufoffset;
11524 	idn_netaddr_t	dst;
11525 	ushort_t		mbox_csum;
11526 	int		rv = 0;
11527 	int		pktlen, qi;
11528 	procname_t	proc = "idn_send_mboxdata";
11529 
11530 	mmp = idn_domain[domid].dmbox.m_send;
11531 	if (mmp == NULL) {
11532 		PR_DATA("%s: dmbox.m_send == NULL\n", proc);
11533 		IDN_KSTAT_INC(sip, si_linkdown);
11534 		return (ENOLINK);
11535 	}
11536 
11537 	mmp += channel;
11538 	mutex_enter(&mmp->mm_mutex);
11539 
11540 	if (mmp->mm_smr_mboxp == NULL) {
11541 		PR_DATA("%s: (d %d, chn %d) mm_smr_mboxp == NULL\n",
11542 			proc, domid, channel);
11543 		IDN_KSTAT_INC(sip, si_linkdown);
11544 		rv = ENOLINK;
11545 		goto send_err;
11546 	}
11547 	mbox_csum = IDN_CKSUM_MBOX(&mmp->mm_smr_mboxp->mt_header);
11548 	if (mbox_csum != mmp->mm_smr_mboxp->mt_header.mh_cksum) {
11549 		PR_DATA("%s: (d %d, chn %d) mbox hdr cksum (%d) "
11550 			"!= actual (%d)\n",
11551 			proc, domid, channel, mbox_csum,
11552 			mmp->mm_smr_mboxp->mt_header.mh_cksum);
11553 		if ((mmp->mm_flags & IDNMMBOX_FLAG_CORRUPTED) == 0) {
11554 			cmn_err(CE_WARN,
11555 				"IDN: 241: [send] (domain %d, "
11556 				"channel %d) SMR CORRUPTED - RELINK",
11557 				domid, channel);
11558 			mmp->mm_flags |= IDNMMBOX_FLAG_CORRUPTED;
11559 		}
11560 		IDN_KSTAT_INC(sip, si_mboxcrc);
11561 		IDN_KSTAT_INC(sip, si_oerrors);
11562 		rv = EPROTO;
11563 		goto send_err;
11564 	}
11565 
11566 	bufoffset = IDN_ADDR2OFFSET(bufp);
11567 	hdrp	  = IDN_BUF2HDR(bufp);
11568 	pktlen    = hdrp->b_length;
11569 	dst.netaddr = hdrp->b_netaddr;
11570 	ASSERT(dst.net.chan == (ushort_t)channel);
11571 
11572 	mqp = &mmp->mm_smr_mboxp->mt_queue[0];
11573 	qi  = mmp->mm_qiput;
11574 
11575 	if (mqp[qi].ms_owner) {
11576 		PR_DATA("%s: mailbox FULL (qiput=%d, qiget=%d)\n",
11577 			proc, mmp->mm_qiput, mmp->mm_qiget);
11578 		IDN_KSTAT_INC(sip, si_txfull);
11579 		rv = ENOSPC;
11580 		goto send_err;
11581 	}
11582 	if (mqp[qi].ms_flag & IDN_MBOXMSG_FLAG_RECLAIM) {
11583 		smr_offset_t	recl_bufoffset;
11584 		/*
11585 		 * Remote domain finished with mailbox entry,
11586 		 * however it has not been reclaimed yet.  A reclaim
11587 		 * was done before coming into this routine, however
11588 		 * timing may have been such that the entry became
11589 		 * free just after the reclamation, but before
11590 		 * entry into here.  Go ahead and reclaim this entry.
11591 		 */
11592 		recl_bufoffset = IDN_BFRAME2OFFSET(mqp[qi].ms_bframe);
11593 
11594 		PR_DATA("%s: attempting reclaim (domain %d) "
11595 			"(qiput=%d, b_off=0x%x)\n",
11596 			proc, domid, qi, recl_bufoffset);
11597 
11598 		if (VALID_NWROFFSET(recl_bufoffset, IDN_SMR_BUFSIZE)) {
11599 			int		recl;
11600 			caddr_t		b_bufp;
11601 			smr_pkthdr_t	*b_hdrp;
11602 
11603 			b_bufp = IDN_OFFSET2ADDR(recl_bufoffset);
11604 			b_hdrp = IDN_BUF2HDR(b_bufp);
11605 
11606 			if (IDN_CKSUM_PKT(b_hdrp) != b_hdrp->b_cksum) {
11607 				IDN_KSTAT_INC(sip, si_crc);
11608 				IDN_KSTAT_INC(sip, si_fcs_errors);
11609 				IDN_KSTAT_INC(sip, si_reclaim);
11610 				IDN_KSTAT_INC(sip, si_oerrors);
11611 			}
11612 
11613 			recl = smr_buf_free(domid, b_bufp, b_hdrp->b_length);
11614 #ifdef DEBUG
11615 			if (recl == 0) {
11616 				PR_DATA("%s: SUCCESSFULLY reclaimed buf "
11617 					"(domain %d)\n", proc, domid);
11618 			} else {
11619 				PR_DATA("%s: WARNING: reclaim failed (FREE) "
11620 					"(domain %d)\n", proc, domid);
11621 			}
11622 #endif /* DEBUG */
11623 		} else {
11624 			IDN_KSTAT_INC(sip, si_smraddr);
11625 			IDN_KSTAT_INC(sip, si_reclaim);
11626 			PR_DATA("%s: WARNING: reclaim failed (BAD OFFSET) "
11627 				"(domain %d)\n", proc, domid);
11628 		}
11629 	}
11630 
11631 	if (*mmp->mm_smr_readyp == 0) {
11632 		mmp->mm_qiput = qi;
11633 		IDN_KSTAT_INC(sip, si_linkdown);
11634 		rv = ENOLINK;
11635 		goto send_err;
11636 	}
11637 
11638 	mqp[qi].ms_flag = IDN_MBOXMSG_FLAG_RECLAIM;
11639 	mqp[qi].ms_bframe = IDN_OFFSET2BFRAME(bufoffset);
11640 	/* membar_stst(); */
11641 	mqp[qi].ms_owner = 1;
11642 
11643 	IDN_MMBOXINDEX_INC(qi);
11644 
11645 	mmp->mm_qiput = qi;
11646 
11647 	mmp->mm_count++;
11648 
11649 	if ((*mmp->mm_smr_readyp) && !(*mmp->mm_smr_activep)) {
11650 		idn_msgtype_t	mt;
11651 
11652 		mt.mt_mtype = IDNP_DATA;
11653 		mt.mt_atype = 0;
11654 		IDN_KSTAT_INC(sip, si_xdcall);
11655 		(void) IDNXDC(domid, &mt, (uint_t)dst.net.chan,
11656 				0, 0, 0);
11657 	}
11658 	mutex_exit(&mmp->mm_mutex);
11659 	IDN_KSTAT_INC(sip, si_opackets);
11660 	IDN_KSTAT_INC(sip, si_opackets64);
11661 	IDN_KSTAT_ADD(sip, si_xmtbytes, pktlen);
11662 	IDN_KSTAT_ADD(sip, si_obytes64, (uint64_t)pktlen);
11663 
11664 	return (0);
11665 
11666 send_err:
11667 	mmp->mm_dropped++;
11668 
11669 	mutex_exit(&mmp->mm_mutex);
11670 
11671 	return (rv);
11672 }
11673 
11674 static int
11675 idn_recv_mboxdata(int channel, caddr_t bufp)
11676 {
11677 	smr_pkthdr_t	*hdrp;
11678 	struct idn	*sip;
11679 	mblk_t		*mp = nilp(mblk_t);
11680 	int		pktlen;
11681 	int		apktlen;
11682 	int		rv = 0;
11683 	smr_offset_t	bufoffset;
11684 	ushort_t	csum;
11685 	idn_netaddr_t	dst, daddr;
11686 	procname_t	proc = "idn_recv_mboxdata";
11687 
11688 	hdrp = IDN_BUF2HDR(bufp);
11689 
11690 	csum = IDN_CKSUM_PKT(hdrp);
11691 
11692 	sip = IDN_INST2SIP(channel);
11693 	if (sip == NULL) {
11694 		/*LINTED*/
11695 		sip = IDN_INST2SIP(0);
11696 	}
11697 	ASSERT(sip);
11698 
11699 	if (csum != hdrp->b_cksum) {
11700 		PR_DATA("%s: bad checksum(%x) != expected(%x)\n",
11701 			proc, (uint_t)csum, (uint_t)hdrp->b_cksum);
11702 		IDN_KSTAT_INC(sip, si_crc);
11703 		IDN_KSTAT_INC(sip, si_fcs_errors);
11704 		rv = -1;
11705 		goto recv_err;
11706 	}
11707 
11708 	daddr.net.chan = (ushort_t)channel;
11709 	daddr.net.netid = (ushort_t)idn.localid;
11710 
11711 	dst.netaddr = hdrp->b_netaddr;
11712 	bufoffset = hdrp->b_offset;
11713 
11714 	if (dst.netaddr != daddr.netaddr) {
11715 		PR_DATA("%s: wrong dest netaddr (0x%x), expected (0x%x)\n",
11716 			proc, dst.netaddr, daddr.netaddr);
11717 		IDN_KSTAT_INC(sip, si_nolink);
11718 		IDN_KSTAT_INC(sip, si_macrcv_errors);
11719 		goto recv_err;
11720 	}
11721 	pktlen  = hdrp->b_length;
11722 	apktlen = pktlen;
11723 
11724 	if ((pktlen <= 0) || (pktlen > IDN_DATA_SIZE)) {
11725 		PR_DATA("%s: invalid packet length (%d) <= 0 || > %lu\n",
11726 			proc, pktlen, IDN_DATA_SIZE);
11727 		IDN_KSTAT_INC(sip, si_buff);
11728 		IDN_KSTAT_INC(sip, si_toolong_errors);
11729 		goto recv_err;
11730 	}
11731 
11732 	mp = allocb(apktlen + IDN_ALIGNSIZE, BPRI_LO);
11733 	if (mp == nilp(mblk_t)) {
11734 		PR_DATA("%s: allocb(pkt) failed\n", proc);
11735 		IDN_KSTAT_INC(sip, si_allocbfail);
11736 		IDN_KSTAT_INC(sip, si_norcvbuf);	/* MIB II */
11737 		goto recv_err;
11738 	}
11739 	ASSERT(DB_TYPE(mp) == M_DATA);
11740 	/*
11741 	 * Copy data packet into its streams buffer.
11742 	 * Align pointers for maximum bcopy performance.
11743 	 */
11744 	mp->b_rptr = (uchar_t *)IDN_ALIGNPTR(mp->b_rptr, bufoffset);
11745 	bcopy(IDN_BUF2DATA(bufp, bufoffset), mp->b_rptr, apktlen);
11746 	mp->b_wptr = mp->b_rptr + pktlen;
11747 
11748 	if (IDN_CHECKSUM &&
11749 		!idn_valid_etherheader((struct ether_header *)mp->b_rptr)) {
11750 		freeb(mp);
11751 		mp = nilp(mblk_t);
11752 		PR_DATA("%s: etherheader CORRUPTED\n", proc);
11753 		IDN_KSTAT_INC(sip, si_crc);
11754 		IDN_KSTAT_INC(sip, si_fcs_errors);
11755 		rv = -1;
11756 		goto recv_err;
11757 	}
11758 
11759 	idndl_read(NULL, mp);
11760 
11761 recv_err:
11762 
11763 	if (mp == nilp(mblk_t)) {
11764 		IDN_KSTAT_INC(sip, si_ierrors);
11765 	}
11766 
11767 	return (rv);
11768 }
11769 
11770 /*
11771  * When on shutdown path (idn_active_resources) must call
11772  * idn_mainmbox_flush() _BEFORE_ calling idn_reclaim_mboxdata()
11773  * for any final data.  This is necessary incase the mailboxes
11774  * have been unregistered.  If they have then idn_mainmbox_flush()
11775  * will set mm_smr_mboxp to NULL which prevents us from touching
11776  * poison SMR space.
11777  */
11778 int
11779 idn_reclaim_mboxdata(int domid, int channel, int nbufs)
11780 {
11781 	idn_mainmbox_t	*mmp;
11782 	idn_mboxmsg_t	*mqp;
11783 	smr_pkthdr_t	*hdrp;
11784 	idn_domain_t	*dp;
11785 	int		qi;
11786 	int		mi;
11787 	int		reclaim_cnt = 0;
11788 	int		free_cnt;
11789 	ushort_t	csum;
11790 	struct idn	*sip;
11791 	smr_offset_t	reclaim_list, curr, prev;
11792 	procname_t	proc = "idn_reclaim_mboxdata";
11793 
11794 
11795 	sip = IDN_INST2SIP(channel);
11796 	if (sip == NULL) {
11797 		/*LINTED*/
11798 		sip = IDN_INST2SIP(0);
11799 	}
11800 	ASSERT(sip);
11801 
11802 	dp = &idn_domain[domid];
11803 
11804 	PR_DATA("%s: requested %d buffers from domain %d\n",
11805 		proc, nbufs, domid);
11806 
11807 	if (lock_try(&dp->dreclaim_inprogress) == 0) {
11808 		/*
11809 		 * Reclaim is already in progress, don't
11810 		 * bother.
11811 		 */
11812 		PR_DATA("%s: reclaim already in progress\n", proc);
11813 		return (0);
11814 	}
11815 
11816 	if (dp->dmbox.m_send == NULL)
11817 		return (0);
11818 
11819 	reclaim_list = curr = prev = IDN_NIL_SMROFFSET;
11820 
11821 	mi = (int)dp->dreclaim_index;
11822 	do {
11823 		ushort_t	mbox_csum;
11824 
11825 		mmp = &dp->dmbox.m_send[mi];
11826 		/* do-while continues down */
11827 		ASSERT(mmp);
11828 		if (mutex_tryenter(&mmp->mm_mutex) == 0) {
11829 			/*
11830 			 * This channel is busy, move on.
11831 			 */
11832 			IDN_MBOXCHAN_INC(mi);
11833 			continue;
11834 		}
11835 
11836 		if (mmp->mm_smr_mboxp == NULL) {
11837 			PR_DATA("%s: no smr pointer for domid %d, chan %d\n",
11838 				proc, domid, (int)mmp->mm_channel);
11839 			ASSERT(mmp->mm_qiget == mmp->mm_qiput);
11840 			mutex_exit(&mmp->mm_mutex);
11841 			IDN_MBOXCHAN_INC(mi);
11842 			continue;
11843 		}
11844 		mbox_csum = IDN_CKSUM_MBOX(&mmp->mm_smr_mboxp->mt_header);
11845 		if (mbox_csum != mmp->mm_smr_mboxp->mt_header.mh_cksum) {
11846 			PR_DATA("%s: (d %d, chn %d) mbox hdr "
11847 				"cksum (%d) != actual (%d)\n",
11848 				proc, domid, (int)mmp->mm_channel, mbox_csum,
11849 				mmp->mm_smr_mboxp->mt_header.mh_cksum);
11850 			IDN_KSTAT_INC(sip, si_mboxcrc);
11851 			IDN_KSTAT_INC(sip, si_oerrors);
11852 			mutex_exit(&mmp->mm_mutex);
11853 			IDN_MBOXCHAN_INC(mi);
11854 			continue;
11855 		}
11856 		mqp = &mmp->mm_smr_mboxp->mt_queue[0];
11857 		qi  = mmp->mm_qiget;
11858 
11859 		while (!mqp[qi].ms_owner &&
11860 			(mqp[qi].ms_flag & IDN_MBOXMSG_FLAG_RECLAIM) &&
11861 			nbufs) {
11862 			idn_mboxmsg_t	*msp;
11863 			int		badbuf;
11864 
11865 			badbuf = 0;
11866 			msp = &mqp[qi];
11867 
11868 			if (msp->ms_flag & IDN_MBOXMSG_FLAG_ERRMASK) {
11869 				PR_DATA("%s: msg.flag ERROR(0x%x) (off=0x%x, "
11870 					"domid=%d, qiget=%d)\n", proc,
11871 					(uint_t)(msp->ms_flag &
11872 						IDN_MBOXMSG_FLAG_ERRMASK),
11873 					IDN_BFRAME2OFFSET(msp->ms_bframe),
11874 					domid, qi);
11875 			}
11876 			prev = curr;
11877 			curr = IDN_BFRAME2OFFSET(mqp[qi].ms_bframe);
11878 
11879 			if (!VALID_NWROFFSET(curr, IDN_SMR_BUFSIZE)) {
11880 				badbuf = 1;
11881 				IDN_KSTAT_INC(sip, si_reclaim);
11882 			} else {
11883 				/*
11884 				 * Put the buffers onto a list that will be
11885 				 * formally reclaimed down below.  This allows
11886 				 * us to free up mboxq entries as fast as
11887 				 * possible.
11888 				 */
11889 				hdrp = IDN_BUF2HDR(IDN_OFFSET2ADDR(curr));
11890 				csum = IDN_CKSUM_PKT(hdrp);
11891 
11892 				if (csum != hdrp->b_cksum) {
11893 					badbuf = 1;
11894 					IDN_KSTAT_INC(sip, si_crc);
11895 					IDN_KSTAT_INC(sip, si_fcs_errors);
11896 					IDN_KSTAT_INC(sip, si_reclaim);
11897 					if (!(mmp->mm_flags &
11898 						IDNMMBOX_FLAG_CORRUPTED)) {
11899 						cmn_err(CE_WARN,
11900 							"IDN: 241: [send] "
11901 							"(domain %d, channel "
11902 							"%d) SMR CORRUPTED - "
11903 							"RELINK",
11904 							domid, channel);
11905 						mmp->mm_flags |=
11906 							IDNMMBOX_FLAG_CORRUPTED;
11907 					}
11908 
11909 				} else if (reclaim_list == IDN_NIL_SMROFFSET) {
11910 					reclaim_list = curr;
11911 				} else {
11912 					caddr_t	bufp;
11913 
11914 					bufp = IDN_OFFSET2ADDR(prev);
11915 					hdrp = IDN_BUF2HDR(bufp);
11916 					hdrp->b_next = curr;
11917 				}
11918 			}
11919 
11920 			mqp[qi].ms_flag = 0;
11921 
11922 			IDN_MMBOXINDEX_INC(qi);
11923 
11924 			if (!badbuf) {
11925 				nbufs--;
11926 				reclaim_cnt++;
11927 			}
11928 
11929 			if (qi == mmp->mm_qiget)
11930 				break;
11931 		}
11932 		mmp->mm_qiget = qi;
11933 
11934 		mutex_exit(&mmp->mm_mutex);
11935 
11936 		IDN_MBOXCHAN_INC(mi);
11937 
11938 	} while ((mi != (int)dp->dreclaim_index) && nbufs);
11939 
11940 	dp->dreclaim_index = (uchar_t)mi;
11941 
11942 	if (reclaim_list != IDN_NIL_SMROFFSET) {
11943 		hdrp = IDN_BUF2HDR(IDN_OFFSET2ADDR(curr));
11944 		hdrp->b_next = IDN_NIL_SMROFFSET;
11945 	}
11946 
11947 	PR_DATA("%s: reclaimed %d buffers from domain %d\n",
11948 		proc, reclaim_cnt, domid);
11949 
11950 	if (reclaim_cnt == 0) {
11951 		lock_clear(&dp->dreclaim_inprogress);
11952 		return (0);
11953 	}
11954 
11955 	/*
11956 	 * Now actually go and reclaim (free) the buffers.
11957 	 */
11958 	free_cnt = 0;
11959 
11960 	for (curr = reclaim_list; curr != IDN_NIL_SMROFFSET; ) {
11961 		caddr_t		bufp;
11962 
11963 		bufp = IDN_OFFSET2ADDR(curr);
11964 		hdrp = IDN_BUF2HDR(bufp);
11965 		csum = IDN_CKSUM_PKT(hdrp);
11966 		if (csum != hdrp->b_cksum) {
11967 			/*
11968 			 * Once corruption is detected we
11969 			 * can't trust our list any further.
11970 			 * These buffers are effectively lost.
11971 			 */
11972 			cmn_err(CE_WARN,
11973 				"IDN: 241: [send] (domain %d, channel %d) SMR "
11974 				"CORRUPTED - RELINK", domid, channel);
11975 			break;
11976 		}
11977 
11978 		curr = hdrp->b_next;
11979 
11980 		if (!smr_buf_free(domid, bufp, hdrp->b_length))
11981 			free_cnt++;
11982 	}
11983 
11984 	if ((dp->dio < IDN_WINDOW_EMAX) && dp->diocheck) {
11985 		lock_clear(&dp->diocheck);
11986 		IDN_MSGTIMER_STOP(domid, IDNP_DATA, 0);
11987 	}
11988 
11989 #ifdef DEBUG
11990 	if (free_cnt != reclaim_cnt) {
11991 		PR_DATA("%s: *** WARNING *** freecnt(%d) != reclaim_cnt (%d)\n",
11992 			proc, free_cnt, reclaim_cnt);
11993 	}
11994 #endif /* DEBUG */
11995 
11996 	lock_clear(&dp->dreclaim_inprogress);
11997 
11998 	return (reclaim_cnt);
11999 }
12000 
12001 void
12002 idn_signal_data_server(int domid, ushort_t channel)
12003 {
12004 	idn_nack_t	nacktype = 0;
12005 	idn_domain_t	*dp;
12006 	idn_chansvr_t	*csp;
12007 	int		c, min_chan, max_chan;
12008 	idn_mainmbox_t	*mmp;
12009 	procname_t	proc = "idn_signal_data_server";
12010 
12011 
12012 	if (domid == IDN_NIL_DOMID)
12013 		return;
12014 
12015 	dp = &idn_domain[domid];
12016 
12017 	if (dp->dawol.a_count > 0) {
12018 		/*
12019 		 * Domain was previously AWOL, but no longer.
12020 		 */
12021 		IDN_SYNC_LOCK();
12022 		IDN_GLOCK_EXCL();
12023 		idn_clear_awol(domid);
12024 		IDN_GUNLOCK();
12025 		IDN_SYNC_UNLOCK();
12026 	}
12027 	/*
12028 	 * Do a precheck before wasting time trying to acquire the lock.
12029 	 */
12030 	if ((dp->dstate != IDNDS_CONNECTED) || !IDN_DLOCK_TRY_SHARED(domid)) {
12031 		/*
12032 		 * Either we're not connected or somebody is busy working
12033 		 * on the domain.  Bail on the signal for now, we'll catch
12034 		 * it on the next go around.
12035 		 */
12036 		return;
12037 	}
12038 	/*
12039 	 * We didn't have the drwlock on the first check of dstate,
12040 	 * but now that we do, make sure the world hasn't changed!
12041 	 */
12042 	if (dp->dstate != IDNDS_CONNECTED) {
12043 		/*
12044 		 * If we reach here, then no connection.
12045 		 * Send no response if this is the case.
12046 		 */
12047 		nacktype = IDNNACK_NOCONN;
12048 		goto send_dresp;
12049 	}
12050 
12051 	/*
12052 	 * No need to worry about locking mainmbox
12053 	 * because we're already holding reader
12054 	 * lock on domain, plus we're just reading
12055 	 * fields in the mainmbox which only change
12056 	 * (or go away) when the writer lock is
12057 	 * held on the domain.
12058 	 */
12059 	if ((mmp = dp->dmbox.m_recv) == NULL) {
12060 		/*
12061 		 * No local mailbox.
12062 		 */
12063 		nacktype = IDNNACK_BADCFG;
12064 		goto send_dresp;
12065 	}
12066 	if ((channel != IDN_BROADCAST_ALLCHAN) && (channel >= IDN_MAX_NETS)) {
12067 		nacktype = IDNNACK_BADCHAN;
12068 		goto send_dresp;
12069 	}
12070 	if (channel == IDN_BROADCAST_ALLCHAN) {
12071 		PR_DATA("%s: requested signal to ALL channels on domain %d\n",
12072 			proc, domid);
12073 		min_chan = 0;
12074 		max_chan = IDN_MAX_NETS - 1;
12075 	} else {
12076 		PR_DATA("%s: requested signal to channel %d on domain %d\n",
12077 			proc, channel, domid);
12078 		min_chan = max_chan = (int)channel;
12079 	}
12080 	mmp += min_chan;
12081 	for (c = min_chan; c <= max_chan; mmp++, c++) {
12082 
12083 		/*
12084 		 * We do a quick check for a pending channel.
12085 		 * If pending it will need activation and we rather
12086 		 * do that through a separate (proto) thread.
12087 		 */
12088 		csp = &idn.chan_servers[c];
12089 
12090 		if (csp->ch_recv.c_checkin) {
12091 			PR_DATA("%s: chansvr (%d) for domid %d CHECK-IN\n",
12092 				proc, c, domid);
12093 			continue;
12094 		}
12095 
12096 		if (IDN_CHAN_TRYLOCK_RECV(csp) == 0) {
12097 			/*
12098 			 * Failed to grab lock, server must be active.
12099 			 */
12100 			PR_DATA("%s: chansvr (%d) for domid %d already actv\n",
12101 				proc, c, domid);
12102 			continue;
12103 		}
12104 
12105 		if (IDN_CHANNEL_IS_PENDING(csp)) {
12106 			/*
12107 			 * Lock is pending.  Submit asynchronous
12108 			 * job to activate and move-on.
12109 			 */
12110 			IDN_CHAN_UNLOCK_RECV(csp);
12111 			idn_submit_chanactivate_job(c);
12112 			continue;
12113 		}
12114 
12115 		/*
12116 		 * If he ain't active, we ain't talkin'.
12117 		 */
12118 		if (IDN_CHANNEL_IS_RECV_ACTIVE(csp) == 0) {
12119 			IDN_CHAN_UNLOCK_RECV(csp);
12120 			PR_DATA("%s: chansvr (%d) for domid %d inactive\n",
12121 				proc, c, domid);
12122 			continue;
12123 		}
12124 
12125 		if (mutex_tryenter(&mmp->mm_mutex) == 0) {
12126 			IDN_CHAN_UNLOCK_RECV(csp);
12127 			continue;
12128 		}
12129 
12130 		if (mmp->mm_csp != csp) {
12131 			/*
12132 			 * Not registered.
12133 			 */
12134 			mutex_exit(&mmp->mm_mutex);
12135 			IDN_CHAN_UNLOCK_RECV(csp);
12136 			continue;
12137 
12138 		}
12139 		if (mmp->mm_smr_mboxp == NULL) {
12140 			/*
12141 			 * No SMR mailbox.
12142 			 */
12143 			mutex_exit(&mmp->mm_mutex);
12144 			IDN_CHAN_UNLOCK_RECV(csp);
12145 			continue;
12146 		}
12147 		mutex_exit(&mmp->mm_mutex);
12148 
12149 		if (csp->ch_recv.c_inprogress) {
12150 			/*
12151 			 * Data server is already active.
12152 			 */
12153 			IDN_CHAN_UNLOCK_RECV(csp);
12154 			PR_DATA("%s: chansvr (%d) for domid %d already actv\n",
12155 				proc, c, domid);
12156 			continue;
12157 		}
12158 		ASSERT(csp == &idn.chan_servers[c]);
12159 
12160 
12161 		PR_DATA("%s: signaling data dispatcher for chan %d dom %d\n",
12162 			proc, c, domid);
12163 		ASSERT(csp);
12164 		cv_signal(&csp->ch_recv_cv);
12165 		IDN_CHAN_UNLOCK_RECV(csp);
12166 	}
12167 
12168 	if (!nacktype || (channel == IDN_BROADCAST_ALLCHAN)) {
12169 		/*
12170 		 * If there were no real errors or we were
12171 		 * handling multiple channels, then just
12172 		 * return.
12173 		 */
12174 		IDN_DUNLOCK(domid);
12175 		return;
12176 	}
12177 
12178 send_dresp:
12179 
12180 	PR_DATA("%s: sending NACK (%s) back to domain %d (cpu %d)\n",
12181 		proc, idnnack_str[nacktype], domid, idn_domain[domid].dcpu);
12182 
12183 	idn_send_dataresp(domid, nacktype);
12184 
12185 	IDN_DUNLOCK(domid);
12186 }
12187 
12188 /*ARGSUSED*/
12189 static int
12190 idn_recv_data(int domid, idn_msgtype_t *mtp, idn_xdcargs_t xargs)
12191 {
12192 #ifdef DEBUG
12193 	uint_t		msg = mtp ? mtp->mt_mtype : 0;
12194 	uint_t		msgarg = mtp ? mtp->mt_atype : 0;
12195 	procname_t	proc = "idn_recv_data";
12196 
12197 	PR_PROTO("%s:%d: DATA message received (msg = 0x%x, msgarg = 0x%x)\n",
12198 		proc, domid, msg, msgarg);
12199 	PR_PROTO("%s:%d: xargs = (0x%x, 0x%x, 0x%x, 0x%x)\n",
12200 		proc, domid, xargs[0], xargs[1], xargs[2], xargs[3]);
12201 #endif /* DEBUG */
12202 
12203 	return (0);
12204 }
12205 
12206 /*
12207  * Only used when sending a negative response.
12208  */
12209 static void
12210 idn_send_dataresp(int domid, idn_nack_t nacktype)
12211 {
12212 	idn_msgtype_t	mt;
12213 
12214 	ASSERT(IDN_DLOCK_IS_HELD(domid));
12215 
12216 	if (idn_domain[domid].dcpu == IDN_NIL_DCPU)
12217 		return;
12218 
12219 	mt.mt_mtype = IDNP_NACK;
12220 	mt.mt_atype = IDNP_DATA;
12221 
12222 	(void) IDNXDC(domid, &mt, (uint_t)nacktype, 0, 0, 0);
12223 }
12224 
12225 /*
12226  * Checksum routine used in checksum smr_pkthdr_t and idn_mboxhdr_t.
12227  */
12228 static ushort_t
12229 idn_cksum(register ushort_t *hdrp, register int count)
12230 {
12231 	register int		i;
12232 	register ushort_t	sum = 0;
12233 
12234 	for (i = 0; i < count; i++)
12235 		sum += hdrp[i];
12236 
12237 	sum = (sum >> 16) + (sum & 0xffff);
12238 	sum += (sum >> 16);
12239 
12240 	return (~sum);
12241 }
12242 
12243 /*
12244  * ------------------------------------------------
12245  */
12246 
12247 int
12248 idn_open_channel(int channel)
12249 {
12250 	int		masterid;
12251 	idn_chansvr_t	*csp;
12252 	struct idn	*sip;
12253 	procname_t	proc = "idn_open_channel";
12254 
12255 	if (channel >= IDN_MAX_NETS) {
12256 		cmn_err(CE_WARN,
12257 			"IDN: 242: maximum channels (%d) already open",
12258 			IDN_MAX_NETS);
12259 		return (-1);
12260 	}
12261 	IDN_GLOCK_EXCL();
12262 
12263 	ASSERT(idn.chan_servers != NULL);
12264 
12265 	csp = &idn.chan_servers[channel];
12266 
12267 	IDN_CHAN_LOCK_GLOBAL(csp);
12268 
12269 	if (IDN_CHANNEL_IS_ATTACHED(csp)) {
12270 		PR_CHAN("%s: channel %d already open\n", proc, channel);
12271 		IDN_CHAN_UNLOCK_GLOBAL(csp);
12272 		IDN_GUNLOCK();
12273 		return (0);
12274 	}
12275 
12276 	/*
12277 	 * Need to zero out the kstats now that we're activating
12278 	 * this channel.
12279 	 */
12280 	for (sip = idn.sip; sip; sip = sip->si_nextp) {
12281 		if (sip->si_dip && (ddi_get_instance(sip->si_dip) == channel)) {
12282 			bzero(&sip->si_kstat, sizeof (sip->si_kstat));
12283 			break;
12284 		}
12285 	}
12286 
12287 	IDN_CHANSVC_MARK_ATTACHED(csp);
12288 	idn.nchannels++;
12289 	CHANSET_ADD(idn.chanset, channel);
12290 	IDN_CHANNEL_ATTACH(channel);
12291 
12292 	IDN_CHAN_UNLOCK_GLOBAL(csp);
12293 
12294 	/*
12295 	 * We increase our window threshold each time a channel
12296 	 * is opened.
12297 	 */
12298 	ASSERT(idn.nchannels > 0);
12299 	IDN_WINDOW_EMAX = IDN_WINDOW_MAX +
12300 				((idn.nchannels - 1) * IDN_WINDOW_INCR);
12301 
12302 	PR_CHAN("%s: channel %d is OPEN (nchannels = %d)\n",
12303 		proc, channel, idn.nchannels);
12304 
12305 	masterid = IDN_GET_MASTERID();
12306 	IDN_GUNLOCK();
12307 
12308 	/*
12309 	 * Check if there is an active master to which
12310 	 * we're connected.  If so, then activate channel.
12311 	 */
12312 	if (masterid != IDN_NIL_DOMID) {
12313 		idn_domain_t	*dp;
12314 
12315 		dp = &idn_domain[masterid];
12316 		IDN_DLOCK_SHARED(masterid);
12317 		if (dp->dvote.v.master && (dp->dstate == IDNDS_CONNECTED))
12318 			(void) idn_activate_channel(CHANSET(channel),
12319 							IDNCHAN_ONLINE);
12320 		IDN_DUNLOCK(masterid);
12321 	}
12322 
12323 	return (0);
12324 }
12325 
12326 void
12327 idn_close_channel(int channel, idn_chanop_t chanop)
12328 {
12329 	idn_chansvr_t	*csp;
12330 	procname_t	proc = "idn_close_channel";
12331 
12332 
12333 	ASSERT(idn.chan_servers != NULL);
12334 
12335 	csp = &idn.chan_servers[channel];
12336 
12337 	IDN_GLOCK_EXCL();
12338 
12339 	IDN_CHAN_LOCK_GLOBAL(csp);
12340 	if (IDN_CHANNEL_IS_DETACHED(csp)) {
12341 		PR_CHAN("%s: channel %d already closed\n", proc, channel);
12342 		IDN_CHAN_UNLOCK_GLOBAL(csp);
12343 		IDN_GUNLOCK();
12344 		return;
12345 	}
12346 	IDN_CHAN_UNLOCK_GLOBAL(csp);
12347 
12348 	idn_deactivate_channel(CHANSET(channel), chanop);
12349 
12350 	IDN_CHAN_LOCK_GLOBAL(csp);
12351 
12352 	if (chanop == IDNCHAN_HARD_CLOSE) {
12353 		idn.nchannels--;
12354 		CHANSET_DEL(idn.chanset, channel);
12355 		/*
12356 		 * We increase our window threshold each time a channel
12357 		 * is opened.
12358 		 */
12359 		if (idn.nchannels <= 0)
12360 			IDN_WINDOW_EMAX = 0;
12361 		else
12362 			IDN_WINDOW_EMAX = IDN_WINDOW_MAX +
12363 					((idn.nchannels - 1) * IDN_WINDOW_INCR);
12364 	}
12365 
12366 	PR_CHAN("%s: channel %d is (%s) CLOSED (nchannels = %d)\n",
12367 		proc, channel,
12368 		(chanop == IDNCHAN_SOFT_CLOSE) ? "SOFT"
12369 		: (chanop == IDNCHAN_HARD_CLOSE) ? "HARD" : "OFFLINE",
12370 		idn.nchannels);
12371 
12372 	IDN_CHAN_UNLOCK_GLOBAL(csp);
12373 	IDN_GUNLOCK();
12374 }
12375 
12376 static int
12377 idn_activate_channel(idn_chanset_t chanset, idn_chanop_t chanop)
12378 {
12379 	int		c, rv = 0;
12380 	procname_t	proc = "idn_activate_channel";
12381 
12382 	PR_CHAN("%s: chanset = 0x%x, chanop = %s\n",
12383 		proc, chanset, chanop_str[chanop]);
12384 
12385 	if (idn.state != IDNGS_ONLINE) {
12386 		/*
12387 		 * Can't activate any channels unless local
12388 		 * domain is connected and thus has a master.
12389 		 */
12390 		PR_CHAN("%s: local domain not connected.  no data servers\n",
12391 			proc);
12392 		return (-1);
12393 	}
12394 
12395 	for (c = 0; c < IDN_MAX_NETS; c++) {
12396 		idn_chansvr_t	*csp;
12397 		idn_mboxhdr_t	*mainhp;
12398 		struct idn	*sip;
12399 
12400 		if (!CHAN_IN_SET(chanset, c))
12401 			continue;
12402 		csp = &idn.chan_servers[c];
12403 
12404 		if (chanop == IDNCHAN_ONLINE) {
12405 			IDN_CHAN_LOCK_GLOBAL(csp);
12406 		} else {
12407 			/*
12408 			 * We don't wait to grab the global lock
12409 			 * if IDNCHAN_OPEN since these occur along
12410 			 * critical data paths and will be retried
12411 			 * anyway if needed.
12412 			 */
12413 			if (IDN_CHAN_TRYLOCK_GLOBAL(csp) == 0) {
12414 				PR_CHAN("%s: failed to acquire global "
12415 					"lock for channel %d\n",
12416 					proc, c);
12417 				continue;
12418 			}
12419 		}
12420 
12421 		if (!IDN_CHANNEL_IS_ATTACHED(csp)) {
12422 			PR_CHAN("%s: channel %d NOT open\n", proc, c);
12423 			IDN_CHAN_UNLOCK_GLOBAL(csp);
12424 			continue;
12425 
12426 		}
12427 
12428 		if (IDN_CHANNEL_IS_ACTIVE(csp)) {
12429 
12430 			PR_CHAN("%s: channel %d already active\n", proc, c);
12431 			rv++;
12432 			IDN_CHAN_UNLOCK_GLOBAL(csp);
12433 			continue;
12434 
12435 		}
12436 		/*
12437 		 * Channel activation can happen asynchronously.
12438 		 */
12439 		IDN_CHANNEL_SUSPEND(c, 0);
12440 
12441 		if (IDN_CHANNEL_IS_PENDING(csp) && (chanop == IDNCHAN_OPEN)) {
12442 
12443 			PR_CHAN("%s: ACTIVATING channel %d\n", proc, c);
12444 
12445 			if (idn_activate_channel_services(c) >= 0) {
12446 				PR_CHAN("%s: Setting channel %d ACTIVE\n",
12447 					proc, c);
12448 				IDN_CHANSVC_MARK_ACTIVE(csp);
12449 				rv++;
12450 			}
12451 		} else if (!IDN_CHANNEL_IS_PENDING(csp) &&
12452 					(chanop == IDNCHAN_ONLINE)) {
12453 			PR_CHAN("%s: Setting channel %d PENDING\n", proc, c);
12454 
12455 			IDN_CHANSVC_MARK_PENDING(csp);
12456 		}
12457 		/*
12458 		 * Don't syncheader (i.e. touch SMR) unless
12459 		 * channel is at least ENABLED.  For a DISABLED
12460 		 * channel, the SMR may be invalid so do NOT
12461 		 * touch it.
12462 		 */
12463 		if (IDN_CHANNEL_IS_ENABLED(csp) &&
12464 			((mainhp = idn_chan_server_syncheader(c)) != NULL)) {
12465 			PR_CHAN("%s: marking chansvr (mhp=0x%p) %d READY\n",
12466 				proc, mainhp, c);
12467 			mainhp->mh_svr_ready = 1;
12468 		}
12469 
12470 		IDN_CHANNEL_RESUME(c);
12471 		sip = IDN_INST2SIP(c);
12472 		ASSERT(sip);
12473 		if (sip->si_wantw) {
12474 			mutex_enter(&idn.sipwenlock);
12475 			idndl_wenable(sip);
12476 			mutex_exit(&idn.sipwenlock);
12477 		}
12478 		IDN_CHAN_UNLOCK_GLOBAL(csp);
12479 
12480 	}
12481 	/*
12482 	 * Returns "not active", i.e. value of 0 indicates
12483 	 * no channels are activated.
12484 	 */
12485 	return (rv == 0);
12486 }
12487 
12488 static void
12489 idn_deactivate_channel(idn_chanset_t chanset, idn_chanop_t chanop)
12490 {
12491 	int		c;
12492 	procname_t	proc = "idn_deactivate_channel";
12493 
12494 
12495 	PR_CHAN("%s: chanset = 0x%x, chanop = %s\n",
12496 		proc, chanset, chanop_str[chanop]);
12497 
12498 	for (c = 0; c < IDN_MAX_NETS; c++) {
12499 		idn_chansvr_t	*csp;
12500 		idn_mboxhdr_t	*mainhp;
12501 
12502 		if (!CHAN_IN_SET(chanset, c))
12503 			continue;
12504 
12505 		csp = &idn.chan_servers[c];
12506 
12507 		IDN_CHAN_LOCK_GLOBAL(csp);
12508 
12509 		if (((chanop == IDNCHAN_SOFT_CLOSE) &&
12510 				!IDN_CHANNEL_IS_ACTIVE(csp)) ||
12511 			((chanop == IDNCHAN_HARD_CLOSE) &&
12512 				IDN_CHANNEL_IS_DETACHED(csp)) ||
12513 			((chanop == IDNCHAN_OFFLINE) &&
12514 				!IDN_CHANNEL_IS_ENABLED(csp))) {
12515 
12516 			ASSERT(!IDN_CHANNEL_IS_RECV_ACTIVE(csp));
12517 			ASSERT(!IDN_CHANNEL_IS_SEND_ACTIVE(csp));
12518 
12519 			PR_CHAN("%s: channel %d already deactivated\n",
12520 				proc, c);
12521 			IDN_CHAN_UNLOCK_GLOBAL(csp);
12522 			continue;
12523 		}
12524 
12525 		switch (chanop) {
12526 		case IDNCHAN_OFFLINE:
12527 			IDN_CHANSVC_MARK_IDLE(csp);
12528 			IDN_CHANSVC_MARK_DISABLED(csp);
12529 			IDN_CHANNEL_STOP(c, 1);
12530 			mainhp = idn_chan_server_syncheader(c);
12531 			if (mainhp != NULL)
12532 				mainhp->mh_svr_ready = 0;
12533 			break;
12534 
12535 		case IDNCHAN_HARD_CLOSE:
12536 			IDN_CHANSVC_MARK_DETACHED(csp);
12537 			IDN_CHANNEL_DETACH(c, 1);
12538 			mainhp = idn_chan_server_syncheader(c);
12539 			if (mainhp != NULL)
12540 				mainhp->mh_svr_ready = 0;
12541 			break;
12542 
12543 		default:
12544 			IDN_CHANSVC_MARK_IDLE(csp);
12545 			IDN_CHANNEL_SUSPEND(c, 1);
12546 			ASSERT(IDN_CHANNEL_IS_ATTACHED(csp));
12547 			break;
12548 		}
12549 
12550 		lock_clear(&csp->ch_actvlck);
12551 		lock_clear(&csp->ch_initlck);
12552 
12553 		PR_CHAN("%s: DEACTIVATING channel %d (%s)\n", proc, c,
12554 			chanop_str[chanop]);
12555 		PR_CHAN("%s: removing chanset 0x%x data svrs for "
12556 			"each domain link\n", proc, chanset);
12557 
12558 		(void) idn_deactivate_channel_services(c, chanop);
12559 	}
12560 	/*
12561 	 * Returns with channels unlocked.
12562 	 */
12563 }
12564 
12565 /*
12566  * The priority of the channel server must be less than that
12567  * of the protocol server since the protocol server tasks
12568  * are (can be) of more importance.
12569  *
12570  * Possible range: 60-99.
12571  */
12572 static pri_t	idn_chansvr_pri = (7 * MAXCLSYSPRI) / 8;
12573 
12574 static int
12575 idn_activate_channel_services(int channel)
12576 {
12577 	idn_chansvr_t	*csp;
12578 	procname_t	proc = "idn_activate_channel_services";
12579 
12580 
12581 	ASSERT((channel >= 0) && (channel < IDN_MAX_NETS));
12582 
12583 	csp = &idn.chan_servers[channel];
12584 
12585 	ASSERT(IDN_CHAN_GLOBAL_IS_LOCKED(csp));
12586 	ASSERT(IDN_CHAN_LOCAL_IS_LOCKED(csp));
12587 
12588 	if (csp->ch_recv_threadp) {
12589 		/*
12590 		 * There's an existing dispatcher!
12591 		 * Must have been idle'd during an earlier
12592 		 * stint.
12593 		 */
12594 		ASSERT(csp->ch_id == (uchar_t)channel);
12595 		PR_CHAN("%s: existing chansvr FOUND for (c=%d)\n",
12596 			proc, channel);
12597 
12598 		if (IDN_CHANNEL_IS_PENDING(csp) == 0)
12599 			return (-1);
12600 
12601 		PR_CHAN("%s: chansvr (c=%d) Rstate = 0x%x, Sstate = 0x%x\n",
12602 			proc, channel, csp->ch_recv.c_state,
12603 			csp->ch_send.c_state);
12604 
12605 		cv_signal(&csp->ch_recv_cv);
12606 
12607 		return (0);
12608 	}
12609 
12610 	if (IDN_CHANNEL_IS_PENDING(csp) == 0)
12611 		return (-1);
12612 
12613 	csp->ch_id = (uchar_t)channel;
12614 
12615 	PR_CHAN("%s: init channel %d server\n", proc, channel);
12616 
12617 	csp->ch_recv_morguep = GETSTRUCT(ksema_t, 1);
12618 	sema_init(csp->ch_recv_morguep, 0, NULL, SEMA_DRIVER, NULL);
12619 
12620 	csp->ch_recv.c_inprogress = 0;
12621 	csp->ch_recv.c_waiters = 0;
12622 	csp->ch_recv.c_checkin = 0;
12623 	csp->ch_recv_changed = 1;
12624 
12625 	csp->ch_recv_domset = csp->ch_reg_domset;
12626 
12627 	csp->ch_recv_waittime = IDN_NETSVR_WAIT_MIN;
12628 
12629 	csp->ch_recv_threadp = thread_create(NULL, 0,
12630 	    idn_chan_server, &csp, sizeof (csp), &p0, TS_RUN, idn_chansvr_pri);
12631 
12632 	csp->ch_send.c_inprogress = 0;
12633 	csp->ch_send.c_waiters = 0;
12634 	csp->ch_send.c_checkin = 0;
12635 
12636 	return (0);
12637 }
12638 
12639 /*
12640  * This routine can handle terminating a set of channel
12641  * servers all at once, however currently only used
12642  * for serial killing, i.e. one-at-a-time.
12643  *
12644  * Entered with RECV locks held on chanset.
12645  * Acquires SEND locks if needed.
12646  * Leaves with all RECV and SEND locks dropped.
12647  */
12648 static int
12649 idn_deactivate_channel_services(int channel, idn_chanop_t chanop)
12650 {
12651 	idn_chansvr_t	*csp;
12652 	int		cs_count;
12653 	int		c;
12654 	idn_chanset_t	chanset;
12655 	ksema_t		*central_morguep = NULL;
12656 	procname_t	proc = "idn_deactivate_channel_services";
12657 
12658 
12659 	ASSERT(idn.chan_servers);
12660 
12661 	PR_CHAN("%s: deactivating channel %d services\n", proc, channel);
12662 
12663 	/*
12664 	 * XXX
12665 	 * Old code allowed us to deactivate multiple channel
12666 	 * servers at once.  Keep for now just in case.
12667 	 */
12668 	chanset = CHANSET(channel);
12669 
12670 	/*
12671 	 * Point all the data dispatchers to the same morgue
12672 	 * so we can kill them all at once.
12673 	 */
12674 	cs_count = 0;
12675 	for (c = 0; c < IDN_MAX_NETS; c++) {
12676 		if (!CHAN_IN_SET(chanset, c))
12677 			continue;
12678 
12679 		csp = &idn.chan_servers[c];
12680 		ASSERT(IDN_CHAN_GLOBAL_IS_LOCKED(csp));
12681 		ASSERT(IDN_CHAN_LOCAL_IS_LOCKED(csp));
12682 
12683 		if (csp->ch_recv_threadp == NULL) {
12684 			/*
12685 			 * No channel server home.
12686 			 * But we're still holding the c_mutex.
12687 			 * At mark him idle incase we start him up.
12688 			 */
12689 			PR_CHAN("%s: no channel server found for chan %d\n",
12690 				proc, c);
12691 			IDN_CHAN_UNLOCK_LOCAL(csp);
12692 			IDN_CHAN_UNLOCK_GLOBAL(csp);
12693 			continue;
12694 		}
12695 		ASSERT(csp->ch_id == (uchar_t)c);
12696 
12697 		/*
12698 		 * Okay, now we've blocked the send and receive sides.
12699 		 */
12700 
12701 		if ((chanop == IDNCHAN_SOFT_CLOSE) ||
12702 		    (chanop == IDNCHAN_OFFLINE)) {
12703 			/*
12704 			 * We set turned off the ACTIVE flag, but there's
12705 			 * no guarantee he stopped because of it.  He may
12706 			 * have already been sleeping.  We need to be
12707 			 * sure he recognizes the IDLE, so we need to
12708 			 * signal him and give him a chance to see it.
12709 			 */
12710 			cv_signal(&csp->ch_recv_cv);
12711 			IDN_CHAN_UNLOCK_LOCAL(csp);
12712 			IDN_CHAN_UNLOCK_GLOBAL(csp);
12713 			cs_count++;
12714 			continue;
12715 		}
12716 
12717 		PR_CHAN("%s: pointing chansvr %d to morgue (0x%p)\n",
12718 			proc, c, central_morguep ? central_morguep
12719 						: csp->ch_recv_morguep);
12720 
12721 		if (central_morguep == NULL) {
12722 			central_morguep = csp->ch_recv_morguep;
12723 		} else {
12724 			sema_destroy(csp->ch_recv_morguep);
12725 			FREESTRUCT(csp->ch_recv_morguep, ksema_t, 1);
12726 
12727 			csp->ch_recv_morguep = central_morguep;
12728 		}
12729 		cv_signal(&csp->ch_recv_cv);
12730 		if (csp->ch_recv.c_waiters > 0)
12731 			cv_broadcast(&csp->ch_recv.c_cv);
12732 		/*
12733 		 * Save any existing binding for next reincarnation.
12734 		 * Note that we're holding the local and global
12735 		 * locks so we're protected against others touchers
12736 		 * of the ch_bound_cpuid fields.
12737 		 */
12738 		csp->ch_bound_cpuid_pending = csp->ch_bound_cpuid;
12739 		csp->ch_bound_cpuid = -1;
12740 		IDN_CHAN_UNLOCK_LOCAL(csp);
12741 		IDN_CHAN_UNLOCK_GLOBAL(csp);
12742 		cs_count++;
12743 	}
12744 	PR_CHAN("%s: signaled %d chansvrs for chanset 0x%x\n",
12745 		proc, cs_count, chanset);
12746 
12747 	if ((chanop == IDNCHAN_SOFT_CLOSE) || (chanop == IDNCHAN_OFFLINE))
12748 		return (cs_count);
12749 
12750 	PR_CHAN("%s: waiting for %d (chnset=0x%x) chan svrs to term\n",
12751 		proc, cs_count, chanset);
12752 	PR_CHAN("%s: morguep = 0x%p\n", proc, central_morguep);
12753 
12754 	ASSERT((cs_count > 0) ? (central_morguep != NULL) : 1);
12755 	while (cs_count-- > 0)
12756 		sema_p(central_morguep);
12757 
12758 	if (central_morguep) {
12759 		sema_destroy(central_morguep);
12760 		FREESTRUCT(central_morguep, ksema_t, 1);
12761 	}
12762 
12763 	return (cs_count);
12764 }
12765 
12766 int
12767 idn_chanservers_init()
12768 {
12769 	int		c;
12770 	idn_chansvr_t	*csp;
12771 
12772 
12773 	if (idn.chan_servers)
12774 		return (0);
12775 
12776 	idn.chan_servers = GETSTRUCT(idn_chansvr_t, IDN_MAXMAX_NETS);
12777 
12778 	for (c = 0; c < IDN_MAXMAX_NETS; c++) {
12779 		csp = &idn.chan_servers[c];
12780 		mutex_init(&csp->ch_send.c_mutex, NULL, MUTEX_DEFAULT, NULL);
12781 		mutex_init(&csp->ch_recv.c_mutex, NULL, MUTEX_DEFAULT, NULL);
12782 		cv_init(&csp->ch_send.c_cv, NULL, CV_DRIVER, NULL);
12783 		cv_init(&csp->ch_recv.c_cv, NULL, CV_DRIVER, NULL);
12784 		cv_init(&csp->ch_recv_cv, NULL, CV_DRIVER, NULL);
12785 		csp->ch_bound_cpuid = -1;
12786 		csp->ch_bound_cpuid_pending = -1;
12787 	}
12788 
12789 	return (c);
12790 }
12791 
12792 void
12793 idn_chanservers_deinit()
12794 {
12795 	int		c;
12796 	idn_chansvr_t	*csp;
12797 
12798 
12799 	if (idn.chan_servers == NULL)
12800 		return;
12801 
12802 	for (c = 0; c < IDN_MAXMAX_NETS; c++) {
12803 		csp = &idn.chan_servers[c];
12804 
12805 		mutex_destroy(&csp->ch_send.c_mutex);
12806 		mutex_destroy(&csp->ch_recv.c_mutex);
12807 		cv_destroy(&csp->ch_send.c_cv);
12808 		cv_destroy(&csp->ch_recv.c_cv);
12809 		cv_destroy(&csp->ch_recv_cv);
12810 	}
12811 
12812 	FREESTRUCT(idn.chan_servers, idn_chansvr_t, IDN_MAXMAX_NETS);
12813 	idn.chan_servers = NULL;
12814 }
12815 
12816 static void
12817 idn_exec_chanactivate(void *chn)
12818 {
12819 	int		not_active, channel;
12820 	idn_chansvr_t	*csp;
12821 
12822 	channel = (int)(uintptr_t)chn;
12823 
12824 	IDN_GLOCK_SHARED();
12825 	if (idn.chan_servers == NULL) {
12826 		IDN_GUNLOCK();
12827 		return;
12828 	}
12829 	csp = &idn.chan_servers[channel];
12830 
12831 	if (IDN_CHAN_TRYLOCK_GLOBAL(csp) == 0) {
12832 		/*
12833 		 * If we can't grab the global lock, then
12834 		 * something is up, skip out.
12835 		 */
12836 		IDN_GUNLOCK();
12837 		return;
12838 	}
12839 	IDN_GUNLOCK();
12840 
12841 	if (IDN_CHANNEL_IS_PENDING(csp) && lock_try(&csp->ch_actvlck)) {
12842 		IDN_CHAN_UNLOCK_GLOBAL(csp);
12843 		not_active = idn_activate_channel(CHANSET(channel),
12844 							IDNCHAN_OPEN);
12845 		if (not_active)
12846 			lock_clear(&csp->ch_actvlck);
12847 	} else {
12848 		IDN_CHAN_UNLOCK_GLOBAL(csp);
12849 	}
12850 }
12851 
12852 /*
12853  * Delayed activation of channel.  We don't want to do this within
12854  * idn_signal_data_server() since that's called within the context
12855  * of an XDC handler so we submit it as a timeout() call to be short
12856  * as soon as possible.
12857  * The ch_initlck & ch_actvlck are used to synchronize activation
12858  * of the channel so that we don't have multiple idn_activate_channel's
12859  * attempting to activate the same channel.
12860  */
12861 static void
12862 idn_submit_chanactivate_job(int channel)
12863 {
12864 	idn_chansvr_t	*csp;
12865 
12866 	if (idn.chan_servers == NULL)
12867 		return;
12868 	csp = &idn.chan_servers[channel];
12869 
12870 	if (lock_try(&csp->ch_initlck) == 0)
12871 		return;
12872 
12873 	(void) timeout(idn_exec_chanactivate, (caddr_t)(uintptr_t)channel, 1);
12874 }
12875 
12876 /*ARGSUSED0*/
12877 static void
12878 idn_xmit_monitor(void *unused)
12879 {
12880 	int		c, d;
12881 	idn_chansvr_t	*csp;
12882 	idn_chanset_t	wake_set;
12883 	domainset_t	conset;
12884 	smr_slab_t	*sp;
12885 	procname_t	proc = "idn_xmit_monitor";
12886 
12887 	CHANSET_ZERO(wake_set);
12888 
12889 	mutex_enter(&idn.xmit_lock);
12890 	if ((idn.xmit_tid == NULL) || !idn.xmit_chanset_wanted) {
12891 		idn.xmit_tid = NULL;
12892 		mutex_exit(&idn.xmit_lock);
12893 		PR_XMON("%s: bailing out\n", proc);
12894 		return;
12895 	}
12896 
12897 	/*
12898 	 * No point in transmitting unless state
12899 	 * is ONLINE.
12900 	 */
12901 	if (idn.state != IDNGS_ONLINE)
12902 		goto retry;
12903 
12904 	conset = idn.domset.ds_connected;
12905 
12906 	/*
12907 	 * Try and reclaim some buffers if possible.
12908 	 */
12909 	for (d = 0; d < MAX_DOMAINS; d++) {
12910 		if (!DOMAIN_IN_SET(conset, d))
12911 			continue;
12912 
12913 		if (!IDN_DLOCK_TRY_SHARED(d))
12914 			continue;
12915 
12916 		if (idn_domain[d].dcpu != IDN_NIL_DCPU)
12917 			(void) idn_reclaim_mboxdata(d, 0, -1);
12918 
12919 		IDN_DUNLOCK(d);
12920 	}
12921 
12922 	/*
12923 	 * Now check if we were successful in getting
12924 	 * any buffers.
12925 	 */
12926 	DSLAB_LOCK_SHARED(idn.localid);
12927 	sp = idn_domain[idn.localid].dslab;
12928 	for (; sp; sp = sp->sl_next)
12929 		if (sp->sl_free)
12930 			break;
12931 	DSLAB_UNLOCK(idn.localid);
12932 
12933 	/*
12934 	 * If there are no buffers available,
12935 	 * no point in reenabling the queues.
12936 	 */
12937 	if (sp == NULL)
12938 		goto retry;
12939 
12940 	CHANSET_ZERO(wake_set);
12941 	for (c = 0; c < IDN_MAX_NETS; c++) {
12942 		int		pending_bits;
12943 		struct idn	*sip;
12944 
12945 		if (!CHAN_IN_SET(idn.xmit_chanset_wanted, c))
12946 			continue;
12947 
12948 		csp = &idn.chan_servers[c];
12949 		if (!IDN_CHAN_TRYLOCK_GLOBAL(csp))
12950 			continue;
12951 
12952 		pending_bits = csp->ch_state &
12953 				IDN_CHANSVC_PENDING_BITS;
12954 
12955 		sip = IDN_INST2SIP(c);
12956 
12957 		if (!csp->ch_send.c_checkin &&
12958 			(pending_bits == IDN_CHANSVC_PENDING_BITS) &&
12959 			sip && (sip->si_flags & IDNRUNNING)) {
12960 
12961 			IDN_CHAN_UNLOCK_GLOBAL(csp);
12962 			CHANSET_ADD(wake_set, c);
12963 
12964 			PR_XMON("%s: QENABLE for channel %d\n",
12965 				proc, c);
12966 
12967 			rw_enter(&idn.struprwlock, RW_READER);
12968 			mutex_enter(&idn.sipwenlock);
12969 			idndl_wenable(sip);
12970 			mutex_exit(&idn.sipwenlock);
12971 			rw_exit(&idn.struprwlock);
12972 		} else {
12973 			IDN_CHAN_UNLOCK_GLOBAL(csp);
12974 		}
12975 	}
12976 
12977 	/*
12978 	 * Clear the channels we enabled.
12979 	 */
12980 	idn.xmit_chanset_wanted &= ~wake_set;
12981 
12982 retry:
12983 
12984 	if (idn.xmit_chanset_wanted == 0)
12985 		idn.xmit_tid = NULL;
12986 	else
12987 		idn.xmit_tid = timeout(idn_xmit_monitor, NULL,
12988 					idn_xmit_monitor_freq);
12989 
12990 	mutex_exit(&idn.xmit_lock);
12991 }
12992 
12993 void
12994 idn_xmit_monitor_kickoff(int chan_wanted)
12995 {
12996 	procname_t	proc = "idn_xmit_monitor_kickoff";
12997 
12998 	mutex_enter(&idn.xmit_lock);
12999 
13000 	if (chan_wanted < 0) {
13001 		/*
13002 		 * Wants all channels.
13003 		 */
13004 		idn.xmit_chanset_wanted = CHANSET_ALL;
13005 	} else {
13006 		CHANSET_ADD(idn.xmit_chanset_wanted, chan_wanted);
13007 	}
13008 
13009 	if (idn.xmit_tid != (timeout_id_t)NULL) {
13010 		/*
13011 		 * A monitor is already running, so
13012 		 * he will catch the new "wants" when
13013 		 * he comes around.
13014 		 */
13015 		mutex_exit(&idn.xmit_lock);
13016 		return;
13017 	}
13018 
13019 	PR_XMON("%s: xmit_mon kicked OFF (chanset = 0x%x)\n",
13020 		proc, idn.xmit_chanset_wanted);
13021 
13022 	idn.xmit_tid = timeout(idn_xmit_monitor, NULL, idn_xmit_monitor_freq);
13023 
13024 	mutex_exit(&idn.xmit_lock);
13025 }
13026