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