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