1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/sysmacros.h> 28 #include <sys/open.h> 29 #include <sys/param.h> 30 #include <sys/machparam.h> 31 #include <sys/systm.h> 32 #include <sys/signal.h> 33 #include <sys/cred.h> 34 #include <sys/user.h> 35 #include <sys/proc.h> 36 #include <sys/vnode.h> 37 #include <sys/uio.h> 38 #include <sys/buf.h> 39 #include <sys/file.h> 40 #include <sys/kmem.h> 41 #include <sys/stat.h> 42 #include <sys/stream.h> 43 #include <sys/stropts.h> 44 #include <sys/strsubr.h> 45 #include <sys/strsun.h> 46 #include <inet/common.h> 47 #include <inet/mi.h> 48 #include <inet/nd.h> 49 #include <sys/poll.h> 50 #include <sys/utsname.h> 51 #include <sys/debug.h> 52 #include <sys/conf.h> 53 #include <sys/ddi.h> 54 #include <sys/sunddi.h> 55 #include <sys/errno.h> 56 #include <sys/modctl.h> 57 #include <sys/machsystm.h> 58 #include <sys/promif.h> 59 #include <sys/prom_plat.h> 60 #include <sys/obpdefs.h> 61 #include <vm/seg_kmem.h> 62 #include <vm/seg_kp.h> 63 #include <sys/kstat.h> 64 #include <sys/membar.h> 65 #include <sys/ivintr.h> 66 #include <sys/vm_machparam.h> 67 #include <sys/x_call.h> 68 #include <sys/cpuvar.h> 69 #include <sys/archsystm.h> 70 #include <sys/dmv.h> 71 72 #include <sys/idn.h> 73 #include <sys/idn_xf.h> 74 #include <sys/cpu_sgnblk_defs.h> 75 #include <sys/cpu_sgn.h> 76 77 struct idn_gkstat sg_kstat; 78 79 #define MBXTBL_PART_REPORT ((caddr_t)1) 80 #define MBXTBL_FULL_REPORT ((caddr_t)2) 81 82 idn_domain_t idn_domain[MAX_DOMAINS]; 83 idn_global_t idn; 84 int idn_debug; 85 int idn_snoop; 86 int idn_history; 87 88 typedef enum { 89 IDN_GPROPS_OKAY, 90 IDN_GPROPS_UNCHECKED, 91 IDN_GPROPS_ERROR 92 } idn_gprops_t; 93 94 struct idn_history idnhlog; 95 96 /* 97 * IDN "tunables". 98 */ 99 int idn_smr_size; 100 int idn_nwr_size; 101 int idn_lowat; 102 int idn_hiwat; 103 int idn_protocol_nservers; 104 int idn_awolmsg_interval; 105 int idn_smr_bufsize; 106 int idn_slab_bufcount; 107 int idn_slab_prealloc; 108 int idn_slab_maxperdomain; 109 int idn_slab_mintotal; 110 int idn_window_max; 111 int idn_window_incr; 112 int idn_window_emax; 113 int idn_reclaim_min; 114 int idn_reclaim_max; 115 int idn_mbox_per_net; 116 int idn_max_nets; 117 118 int idn_netsvr_spin_count; 119 int idn_netsvr_wait_min; 120 int idn_netsvr_wait_max; 121 int idn_netsvr_wait_shift; 122 123 int idn_checksum; 124 125 int idn_msgwait_nego; 126 int idn_msgwait_cfg; 127 int idn_msgwait_con; 128 int idn_msgwait_fin; 129 int idn_msgwait_cmd; 130 int idn_msgwait_data; 131 132 int idn_retryfreq_nego; 133 int idn_retryfreq_con; 134 int idn_retryfreq_fin; 135 136 int idn_window_emax; /* calculated */ 137 int idn_slab_maxperdomain; /* calculated */ 138 139 /* 140 * DMV interrupt support. 141 */ 142 int idn_pil; 143 int idn_dmv_pending_max; 144 idn_dmv_msg_t *idn_iv_queue[NCPU]; 145 int idn_intr_index[NCPU]; /* idn_handler ONLY */ 146 static idn_dmv_data_t *idn_dmv_data; 147 148 int idn_sigbpil; 149 150 idnparam_t idn_param_arr[] = { 151 { 0, 1, 0, /* 0 */ "idn_modunloadable" }, 152 }; 153 154 /* 155 * Parameters that are only accessible in a DEBUG driver. 156 */ 157 static char *idn_param_debug_only[] = { 158 #if 0 159 "idn_checksum", 160 #endif /* 0 */ 161 0 162 }; 163 164 /* 165 * Parameters that are READ-ONLY. 166 */ 167 static char *idn_param_read_only[] = { 168 #if 0 169 "idn_window_emax", 170 "idn_slab_maxperdomain", 171 #endif /* 0 */ 172 0 173 }; 174 175 static struct idn_global_props { 176 int p_min, p_max, p_def; 177 char *p_string; 178 int *p_var; 179 } idn_global_props[] = { 180 { 0, 0, 0, "idn_debug", &idn_debug }, 181 { 0, 1, 0, "idn_history", &idn_history }, 182 { 0, IDN_SMR_MAXSIZE, 183 0, "idn_smr_size", &idn_smr_size }, 184 { 0, IDN_SMR_MAXSIZE, 185 0, "idn_nwr_size", &idn_nwr_size }, 186 { 1, 512*1024, 187 1, "idn_lowat", &idn_lowat }, 188 { 1*1024, 189 1*1024*1024, 190 256*1024, 191 "idn_hiwat", &idn_hiwat }, 192 { IDN_SMR_BUFSIZE_MIN, 193 IDN_SMR_BUFSIZE_MAX, 194 IDN_SMR_BUFSIZE_DEF, 195 "idn_smr_bufsize", &idn_smr_bufsize }, 196 { 4, 1024, 32, "idn_slab_bufcount", &idn_slab_bufcount }, 197 { 0, 10, 0, "idn_slab_prealloc", &idn_slab_prealloc }, 198 { 2, MAX_DOMAINS, 199 8, "idn_slab_mintotal", &idn_slab_mintotal }, 200 { 8, 256, 64, "idn_window_max", &idn_window_max }, 201 { 0, 32, 8, "idn_window_incr", &idn_window_incr }, 202 { 1, 128, 5, "idn_reclaim_min", &idn_reclaim_min }, 203 { 0, 128, 0, "idn_reclaim_max", &idn_reclaim_max }, 204 { 1, IDN_MAXMAX_NETS, 205 8, "idn_max_nets", &idn_max_nets }, 206 { 31, 511, 127, "idn_mbox_per_net", &idn_mbox_per_net }, 207 { 0, 1, 1, "idn_checksum", &idn_checksum }, 208 { 0, 10000, 500, "idn_netsvr_spin_count", 209 &idn_netsvr_spin_count }, 210 { 0, 30*100, 40, "idn_netsvr_wait_min", &idn_netsvr_wait_min }, 211 { 0, 60*100, 16*100, "idn_netsvr_wait_max", &idn_netsvr_wait_max }, 212 { 1, 5, 1, "idn_netsvr_wait_shift", 213 &idn_netsvr_wait_shift }, 214 { 1, MAX_DOMAINS, 215 IDN_PROTOCOL_NSERVERS, 216 "idn_protocol_nservers", 217 &idn_protocol_nservers }, 218 { 0, 3600, IDN_AWOLMSG_INTERVAL, 219 "idn_awolmsg_interval", &idn_awolmsg_interval }, 220 { 10, 300, IDN_MSGWAIT_NEGO, 221 "idn_msgwait_nego", &idn_msgwait_nego }, 222 { 10, 300, IDN_MSGWAIT_CFG, 223 "idn_msgwait_cfg", &idn_msgwait_cfg }, 224 { 10, 300, IDN_MSGWAIT_CON, 225 "idn_msgwait_con", &idn_msgwait_con }, 226 { 10, 300, IDN_MSGWAIT_FIN, 227 "idn_msgwait_fin", &idn_msgwait_fin }, 228 { 10, 300, IDN_MSGWAIT_CMD, 229 "idn_msgwait_cmd", &idn_msgwait_cmd }, 230 { 10, 300, IDN_MSGWAIT_DATA, 231 "idn_msgwait_data", &idn_msgwait_data }, 232 { 1, 60, IDN_RETRYFREQ_NEGO, 233 "idn_retryfreq_nego", &idn_retryfreq_nego }, 234 { 1, 60, IDN_RETRYFREQ_CON, 235 "idn_retryfreq_con", &idn_retryfreq_con }, 236 { 1, 60, IDN_RETRYFREQ_FIN, 237 "idn_retryfreq_fin", &idn_retryfreq_fin }, 238 { 1, 9, IDN_PIL, 239 "idn_pil", &idn_pil }, 240 { 1, 9, IDN_SIGBPIL, 241 "idn_sigbpil", &idn_sigbpil }, 242 { 8, 512, IDN_DMV_PENDING_MAX, 243 "idn_dmv_pending_max", &idn_dmv_pending_max }, 244 { 0, 0, 0, NULL, NULL } 245 }; 246 247 struct idn *idn_i2s_table[IDN_MAXMAX_NETS << 1]; 248 clock_t idn_msg_waittime[IDN_NUM_MSGTYPES]; 249 clock_t idn_msg_retrytime[(int)IDN_NUM_RETRYTYPES]; 250 251 static caddr_t idn_ndlist; /* head of 'named dispatch' var list */ 252 253 static int idnattach(dev_info_t *, ddi_attach_cmd_t); 254 static int idndetach(dev_info_t *, ddi_detach_cmd_t); 255 static int idnopen(register queue_t *, dev_t *, int, int, cred_t *); 256 static int idnclose(queue_t *, int, cred_t *); 257 static int idnwput(queue_t *, mblk_t *); 258 static int idnwsrv(queue_t *); 259 static int idnrput(queue_t *, mblk_t *); 260 static void idnioctl(queue_t *, mblk_t *); 261 static idn_gprops_t idn_check_conf(dev_info_t *dip, processorid_t *cpuid); 262 static int idn_size_check(); 263 static void idn_xmit_monitor_init(); 264 static void idn_xmit_monitor_deinit(); 265 static void idn_init_msg_waittime(); 266 static void idn_init_msg_retrytime(); 267 static void idn_sigb_setup(cpu_sgnblk_t *sigbp, void *arg); 268 static int idn_init(dev_info_t *dip); 269 static int idn_deinit(); 270 static void idn_sigbhandler_create(); 271 static void idn_sigbhandler_kill(); 272 static uint_t idn_sigbhandler_wakeup(caddr_t arg1, caddr_t arg2); 273 static void idn_sigbhandler_thread(struct sigbintr **sbpp); 274 static void idn_sigbhandler(processorid_t cpuid, cpu_sgnblk_t *sgnblkp); 275 static int idn_info(idnsb_info_t *sfp); 276 static int idn_init_smr(); 277 static void idn_deinit_smr(); 278 static int idn_prom_getsmr(uint_t *smrsz, uint64_t *paddrp, 279 uint64_t *sizep); 280 static int idn_init_handler(); 281 static void idn_deinit_handler(); 282 static uint_t idn_handler(caddr_t unused, caddr_t unused2); 283 /* 284 * ioctl services 285 */ 286 static int idnioc_link(idnop_t *idnop); 287 static int idnioc_unlink(idnop_t *idnop); 288 static int idn_rw_mem(idnop_t *idnop); 289 static int idn_send_ping(idnop_t *idnop); 290 291 static void idn_domains_init(struct hwconfig *local_hw); 292 static void idn_domains_deinit(); 293 static void idn_retrytask_init(); 294 static void idn_retrytask_deinit(); 295 static void idn_gkstat_init(); 296 static void idn_gkstat_deinit(); 297 static int idn_gkstat_update(); 298 static void idn_timercache_init(); 299 static void idn_timercache_deinit(); 300 static void idn_dopers_init(); 301 static void idn_dopers_deinit(); 302 303 static void idn_param_cleanup(); 304 static int idn_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr); 305 static int idn_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, 306 cred_t *cr); 307 static int idn_param_register(register idnparam_t *idnpa, int count); 308 static int idn_slabpool_report(queue_t *wq, mblk_t *mp, caddr_t cp, 309 cred_t *cr); 310 static int idn_buffer_report(queue_t *wq, mblk_t *mp, caddr_t cp, 311 cred_t *cr); 312 static int idn_mboxtbl_report(queue_t *wq, mblk_t *mp, caddr_t cp, 313 cred_t *cr); 314 static int idn_mainmbox_report(queue_t *wq, mblk_t *mp, caddr_t cp, 315 cred_t *cr); 316 static void idn_mainmbox_domain_report(queue_t *wq, mblk_t *mp, int domid, 317 idn_mainmbox_t *mmp, char *mbxtype); 318 static int idn_global_report(queue_t *wq, mblk_t *mp, caddr_t cp, 319 cred_t *cr); 320 static int idn_domain_report(queue_t *wq, mblk_t *mp, caddr_t cp, 321 cred_t *cr); 322 static int idn_get_net_binding(queue_t *wq, mblk_t *mp, caddr_t cp, 323 cred_t *cr); 324 static int idn_set_net_binding(queue_t *wq, mblk_t *mp, char *value, 325 caddr_t cp, cred_t *cr); 326 327 /* 328 * String definitions used for DEBUG and non-DEBUG. 329 */ 330 const char *idnm_str[] = { 331 /* 0 */ "null", 332 /* 1 */ "nego", 333 /* 2 */ "con", 334 /* 3 */ "cfg", 335 /* 4 */ "fin", 336 /* 5 */ "cmd", 337 /* 6 */ "data", 338 }; 339 340 const char *idnds_str[] = { 341 /* 0 */ "CLOSED", 342 /* 1 */ "NEGO_PEND", 343 /* 2 */ "NEGO_SENT", 344 /* 3 */ "NEGO_RCVD", 345 /* 4 */ "CONFIG", 346 /* 5 */ "CON_PEND", 347 /* 6 */ "CON_SENT", 348 /* 7 */ "CON_RCVD", 349 /* 8 */ "CON_READY", 350 /* 9 */ "CONNECTED", 351 /* 10 */ "FIN_PEND", 352 /* 11 */ "FIN_SENT", 353 /* 12 */ "FIN_RCVD", 354 /* 13 */ "DMAP" 355 }; 356 357 const char *idnxs_str[] = { 358 /* 0 */ "PEND", 359 /* 1 */ "SENT", 360 /* 2 */ "RCVD", 361 /* 3 */ "FINAL", 362 /* 4 */ "NIL" 363 }; 364 365 const char *idngs_str[] = { 366 /* 0 */ "OFFLINE", 367 /* 1 */ "CONNECT", 368 /* 2 */ "ONLINE", 369 /* 3 */ "DISCONNECT", 370 /* 4 */ "RECONFIG", 371 /* 5 */ "unknown", 372 /* 6 */ "unknown", 373 /* 7 */ "unknown", 374 /* 8 */ "unknown", 375 /* 9 */ "unknown", 376 /* 10 */ "IGNORE" 377 }; 378 379 const char *idncmd_str[] = { 380 /* 0 */ "unknown", 381 /* 1 */ "SLABALLOC", 382 /* 2 */ "SLABFREE", 383 /* 3 */ "SLABREAP", 384 /* 4 */ "NODENAME" 385 }; 386 387 const char *idncon_str[] = { 388 /* 0 */ "OFF", 389 /* 1 */ "NORMAL", 390 /* 2 */ "QUERY" 391 }; 392 393 const char *idnfin_str[] = { 394 /* 0 */ "OFF", 395 /* 1 */ "NORMAL", 396 /* 2 */ "FORCE_SOFT", 397 /* 3 */ "FORCE_HARD", 398 /* 4 */ "QUERY" 399 }; 400 401 const char *idnfinopt_str[] = { 402 /* 0 */ "NONE", 403 /* 1 */ "UNLINK", 404 /* 2 */ "RELINK" 405 }; 406 407 const char *idnfinarg_str[] = { 408 /* 0 */ "NONE", 409 /* 1 */ "SMRBAD", 410 /* 2 */ "CPUCFG", 411 /* 3 */ "HWERR", 412 /* 4 */ "CFGERR_FATAL", 413 /* 5 */ "CFGERR_MTU", 414 /* 6 */ "CFGERR_BUF", 415 /* 7 */ "CFGERR_SLAB", 416 /* 8 */ "CFGERR_NWR", 417 /* 9 */ "CFGERR_NETS", 418 /* 10 */ "CFGERR_MBOX", 419 /* 11 */ "CFGERR_NMCADR", 420 /* 12 */ "CFGERR_MCADR", 421 /* 13 */ "CFGERR_CKSUM", 422 /* 14 */ "CFGERR_SMR", 423 }; 424 425 const char *idnsync_str[] = { 426 /* 0 */ "NIL", 427 /* 1 */ "CONNECT", 428 /* 2 */ "DISCONNECT" 429 }; 430 431 const char *idnreg_str[] = { 432 /* 0 */ "REG", 433 /* 1 */ "NEW", 434 /* 2 */ "QUERY" 435 }; 436 437 const char *idnnack_str[] = { 438 /* 0 */ "unknown", 439 /* 1 */ "NOCONN", 440 /* 2 */ "BADCHAN", 441 /* 3 */ "BADCFG", 442 /* 4 */ "BADCMD", 443 /* 5 */ "RETRY", 444 /* 6 */ "DUP", 445 /* 7 */ "EXIT", 446 /* 8 */ "--reserved1", 447 /* 9 */ "--reserved2", 448 /* 10 */ "--reserved3" 449 }; 450 451 const char *idnop_str[] = { 452 /* 0 */ "DISCONNECTED", 453 /* 1 */ "CONNECTED", 454 /* 2 */ "ERROR" 455 }; 456 457 const char *chanop_str[] = { 458 /* 0 */ "OPEN", 459 /* 1 */ "SOFT_CLOSE", 460 /* 2 */ "HARD_CLOSE", 461 /* 3 */ "OFFLINE", 462 /* 4 */ "ONLINE" 463 }; 464 465 const char *chanaction_str[] = { 466 /* 0 */ "DETACH", 467 /* 1 */ "STOP", 468 /* 2 */ "SUSPEND", 469 /* 3 */ "RESUME", 470 /* 4 */ "RESTART", 471 /* 5 */ "ATTACH" 472 }; 473 474 const char *timer_str[] = { 475 /* 0 */ "NIL", 476 /* 1 */ "MSG" 477 }; 478 479 static struct module_info idnrinfo = { 480 IDNIDNUM, /* mi_idnum */ 481 IDNNAME, /* mi_idname */ 482 IDNMINPSZ, /* mi_minpsz */ 483 IDNMAXPSZ, /* mi_maxpsz */ 484 0, /* mi_hiwat - see IDN_HIWAT */ 485 0 /* mi_lowat - see IDN_LOWAT */ 486 }; 487 488 static struct module_info idnwinfo = { 489 IDNIDNUM, /* mi_idnum */ 490 IDNNAME, /* mi_idname */ 491 IDNMINPSZ, /* mi_minpsz */ 492 IDNMAXPSZ, /* mi_maxpsz */ 493 0, /* mi_hiwat - see IDN_HIWAT */ 494 0 /* mi_lowat - see IDN_LOWAT */ 495 }; 496 497 static struct qinit idnrinit = { 498 idnrput, /* qi_putp */ 499 NULL, /* qi_srvp */ 500 idnopen, /* qi_qopen */ 501 idnclose, /* qi_qclose */ 502 NULL, /* qi_qadmin */ 503 &idnrinfo, /* qi_minfo */ 504 NULL, /* qi_mstat */ 505 NULL, /* qi_rwp */ 506 NULL, /* qi_infop */ 507 STRUIOT_DONTCARE /* qi_struiot */ 508 }; 509 510 static struct qinit idnwinit = { 511 idnwput, /* qi_putp */ 512 idnwsrv, /* qi_srvp */ 513 NULL, /* qi_qopen */ 514 NULL, /* qi_qclose */ 515 NULL, /* qi_qadmin */ 516 &idnwinfo, /* qi_minfo */ 517 NULL, /* qi_mstat */ 518 NULL, /* qi_rwp */ 519 NULL, /* qi_infop */ 520 STRUIOT_DONTCARE /* qi_struiot */ 521 }; 522 523 struct streamtab idninfo = { 524 &idnrinit, /* st_rdinit */ 525 &idnwinit, /* st_wrinit */ 526 NULL, /* st_muxrinit */ 527 NULL, /* st_muxwinit */ 528 }; 529 530 /* 531 * Module linkage information (cb_ops & dev_ops) for the kernel. 532 */ 533 534 static struct cb_ops cb_idnops = { 535 nulldev, /* cb_open */ 536 nulldev, /* cb_close */ 537 nodev, /* cb_strategy */ 538 nodev, /* cb_print */ 539 nodev, /* cb_dump */ 540 nodev, /* cb_read */ 541 nodev, /* cb_write */ 542 nodev, /* cb_ioctl */ 543 nodev, /* cb_devmap */ 544 nodev, /* cb_mmap */ 545 nodev, /* cb_segmap */ 546 nochpoll, /* cb_chpoll */ 547 ddi_prop_op, /* cb_prop_op */ 548 &idninfo, /* cb_stream */ 549 D_MP, /* cb_flag */ 550 CB_REV, /* cb_rev */ 551 nodev, /* cb_aread */ 552 nodev, /* cb_awrite */ 553 }; 554 555 static struct dev_ops idnops = { 556 DEVO_REV, /* devo_rev */ 557 0, /* devo_refcnt */ 558 ddi_no_info, /* devo_getinfo */ 559 nulldev, /* devo_identify */ 560 nulldev, /* devo_probe */ 561 idnattach, /* devo_attach */ 562 idndetach, /* devo_detach */ 563 nodev, /* devo_reset */ 564 &cb_idnops, /* devo_cb_ops */ 565 (struct bus_ops *)NULL, /* devo_bus_ops */ 566 NULL, /* devo_power */ 567 ddi_quiesce_not_needed, /* quiesce */ 568 }; 569 570 extern cpuset_t cpu_ready_set; 571 572 static struct modldrv modldrv = { 573 &mod_driverops, /* This module is a pseudo driver */ 574 IDNDESC " 1.58", 575 &idnops 576 }; 577 578 static struct modlinkage modlinkage = { 579 MODREV_1, 580 &modldrv, 581 NULL 582 }; 583 584 /* 585 * -------------------------------------------------- 586 */ 587 int 588 _init(void) 589 { 590 idn.version = IDN_VERSION; 591 592 return (mod_install(&modlinkage)); 593 } 594 595 int 596 _fini(void) 597 { 598 return (mod_remove(&modlinkage)); 599 } 600 601 int 602 _info(struct modinfo *modinfop) 603 { 604 return (mod_info(&modlinkage, modinfop)); 605 } 606 607 /* 608 * ---------------------------------------------- 609 */ 610 static int 611 idnattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 612 { 613 int instance; 614 int doinit = 0; 615 processorid_t bcpuid; 616 struct idn *sip; 617 struct idnstr *stp; 618 procname_t proc = "idnattach"; 619 620 621 #ifndef lint 622 ASSERT(sizeof (idnsb_t) == IDNSB_SIZE); 623 ASSERT((uint_t)&((struct idnsb *)0)->id_hwchkpt[0] == 0x40); 624 #endif /* lint */ 625 626 switch (cmd) { 627 case DDI_RESUME: 628 sip = ddi_get_driver_private(dip); 629 /* 630 * sip may have not yet been set if the 631 * OBP environment variable (idn-smr-size) 632 * was not set. 633 */ 634 if (sip == NULL) 635 return (DDI_FAILURE); 636 /* 637 * RESUME IDN services. 638 */ 639 IDN_GLOCK_SHARED(); 640 if (idn.state != IDNGS_OFFLINE) { 641 cmn_err(CE_WARN, 642 "IDN: 101: not in expected OFFLINE state " 643 "for DDI_RESUME"); 644 ASSERT(0); 645 } 646 IDN_GUNLOCK(); 647 648 /* 649 * RESUME DLPI services. 650 */ 651 sip->si_flags &= ~IDNSUSPENDED; 652 653 rw_enter(&idn.struprwlock, RW_READER); 654 for (stp = idn.strup; stp; stp = stp->ss_nextp) 655 if (stp->ss_sip == sip) { 656 doinit = 1; 657 break; 658 } 659 rw_exit(&idn.struprwlock); 660 if (doinit) 661 (void) idndl_init(sip); 662 663 return (DDI_SUCCESS); 664 665 case DDI_ATTACH: 666 break; 667 668 default: 669 return (DDI_FAILURE); 670 } 671 672 instance = ddi_get_instance(dip); 673 674 PR_DRV("%s: instance = %d\n", proc, instance); 675 676 if (idn_check_conf(dip, &bcpuid) == IDN_GPROPS_ERROR) 677 return (DDI_FAILURE); 678 679 mutex_enter(&idn.siplock); 680 681 if (ddi_create_minor_node(dip, IDNNAME, S_IFCHR, instance, 682 DDI_NT_NET, CLONE_DEV) == DDI_FAILURE) { 683 mutex_exit(&idn.siplock); 684 return (DDI_FAILURE); 685 } 686 687 if (idn.smr.ready == 0) { 688 if (idn_init_smr() == 0) { 689 idn.enabled = 1; 690 #ifdef DEBUG 691 cmn_err(CE_NOTE, "!IDN: Driver enabled"); 692 #endif /* DEBUG */ 693 } else { 694 cmn_err(CE_NOTE, 695 "!IDN: 102: driver disabled " 696 "- check OBP environment " 697 "(idn-smr-size)"); 698 mutex_exit(&idn.siplock); 699 return (DDI_SUCCESS); 700 } 701 } 702 703 ASSERT(idn.smr.ready || idn.enabled); 704 705 if (idn.dip == NULL) { 706 doinit = 1; 707 708 if (idn_size_check()) { 709 idn_deinit_smr(); 710 ddi_remove_minor_node(dip, NULL); 711 mutex_exit(&idn.siplock); 712 return (DDI_FAILURE); 713 } 714 715 if (idn_init(dip)) { 716 idn_deinit_smr(); 717 ddi_remove_minor_node(dip, NULL); 718 mutex_exit(&idn.siplock); 719 return (DDI_FAILURE); 720 } 721 } 722 723 ASSERT(idn.dip); 724 725 /* 726 * This must occur _after_ idn_init() since 727 * it assumes idn_chanservers_init() has been 728 * called. 729 */ 730 idn_chanserver_bind(ddi_get_instance(dip), bcpuid); 731 732 /* 733 * DLPI supporting stuff. 734 */ 735 sip = GETSTRUCT(struct idn, 1); 736 sip->si_dip = dip; 737 ddi_set_driver_private(dip, sip); 738 sip->si_nextp = idn.sip; 739 idn.sip = sip; 740 IDN_SET_INST2SIP(instance, sip); 741 mutex_exit(&idn.siplock); 742 743 if (doinit) 744 idndl_dlpi_init(); /* initializes idninfoack */ 745 /* 746 * Get our local IDN ethernet address. 747 */ 748 idndl_localetheraddr(sip, &sip->si_ouraddr); 749 idndl_statinit(sip); 750 751 if (doinit) { 752 idn_gkstat_init(); 753 /* 754 * Add our sigblock SSP interrupt handler. 755 */ 756 mutex_enter(&idn.sigbintr.sb_mutex); 757 idn_sigbhandler_create(); 758 mutex_exit(&idn.sigbintr.sb_mutex); 759 760 if (sgnblk_poll_register(idn_sigbhandler) == 0) { 761 mutex_enter(&idn.sigbintr.sb_mutex); 762 idn_sigbhandler_kill(); 763 idn.sigbintr.sb_cpuid = (uchar_t)-1; 764 idn.sigbintr.sb_busy = IDNSIGB_INACTIVE; 765 mutex_exit(&idn.sigbintr.sb_mutex); 766 767 idn_gkstat_deinit(); 768 769 mutex_enter(&idn.siplock); 770 (void) idn_deinit(); 771 IDN_SET_INST2SIP(instance, NULL); 772 idn.sip = sip->si_nextp; 773 mutex_exit(&idn.siplock); 774 775 ddi_remove_minor_node(dip, NULL); 776 777 return (DDI_FAILURE); 778 } 779 /* 780 * We require sigblkp[cpu0] to be mapped for hardware 781 * configuration determination and also auto-linking 782 * on bootup. 783 */ 784 if (sgnblk_poll_reference(idn_sigb_setup, NULL) != 0) { 785 sgnblk_poll_unregister(idn_sigbhandler); 786 mutex_enter(&idn.sigbintr.sb_mutex); 787 idn_sigbhandler_kill(); 788 idn.sigbintr.sb_cpuid = (uchar_t)-1; 789 idn.sigbintr.sb_busy = IDNSIGB_INACTIVE; 790 mutex_exit(&idn.sigbintr.sb_mutex); 791 792 idn_gkstat_deinit(); 793 794 mutex_enter(&idn.siplock); 795 (void) idn_deinit(); 796 IDN_SET_INST2SIP(instance, NULL); 797 idn.sip = sip->si_nextp; 798 mutex_exit(&idn.siplock); 799 800 ddi_remove_minor_node(dip, NULL); 801 802 cmn_err(CE_WARN, 803 "IDN: 103: unable to reference sigblock area"); 804 805 return (DDI_FAILURE); 806 } 807 808 idn_init_autolink(); 809 } 810 811 ddi_report_dev(dip); 812 813 return (DDI_SUCCESS); 814 } 815 816 /* 817 * ---------------------------------------------- 818 */ 819 static int 820 idndetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 821 { 822 int err = 0; 823 int instance; 824 struct idn *sip, *hsip, *tsip; 825 procname_t proc = "idndetach"; 826 827 sip = ddi_get_driver_private(dip); 828 instance = ddi_get_instance(dip); 829 830 switch (cmd) { 831 case DDI_SUSPEND: 832 if (sip == NULL) 833 return (DDI_FAILURE); 834 /* 835 * SUSPEND IDN services. 836 * - Actually don't suspend anything, we just 837 * make sure we're not connected per DR protocol. 838 * If we really wanted to suspend it should 839 * be done _after_ DLPI is suspended so that 840 * we're not competing with that traffic. 841 */ 842 IDN_GLOCK_SHARED(); 843 844 if (idn.state != IDNGS_OFFLINE) { 845 int d; 846 847 cmn_err(CE_WARN, 848 "IDN: 104: cannot suspend while active " 849 "(state = %s)", 850 idngs_str[idn.state]); 851 852 for (d = 0; d < MAX_DOMAINS; d++) { 853 idn_domain_t *dp; 854 855 dp = &idn_domain[d]; 856 if (dp->dcpu < 0) 857 continue; 858 859 cmn_err(CE_CONT, 860 "IDN: 121: domain %d (CPU %d, name " 861 "\"%s\", state %s)\n", 862 d, dp->dcpu, dp->dname, 863 idnds_str[dp->dstate]); 864 } 865 err = 1; 866 } 867 868 IDN_GUNLOCK(); 869 870 if (err) 871 return (DDI_FAILURE); 872 /* 873 * SUSPEND DLPI services. 874 */ 875 sip->si_flags |= IDNSUSPENDED; 876 877 idndl_uninit(sip); 878 879 return (DDI_FAILURE); 880 881 case DDI_DETACH: 882 if (idn.enabled == 0) { 883 ddi_remove_minor_node(dip, NULL); 884 ASSERT(idn.dip == NULL); 885 return (DDI_SUCCESS); 886 } 887 if (!IDN_MODUNLOADABLE) 888 return (DDI_FAILURE); 889 break; 890 891 default: 892 return (DDI_FAILURE); 893 } 894 895 PR_DRV("%s: instance = %d\n", proc, instance); 896 897 if (sip == NULL) { 898 /* 899 * No resources allocated. 900 */ 901 return (DDI_SUCCESS); 902 } 903 904 mutex_enter(&idn.siplock); 905 if (idn.sip && (idn.sip->si_nextp == NULL)) { 906 /* 907 * This is our last stream connection 908 * going away. Time to deinit and flag 909 * the SSP we're (IDN) DOWN. 910 */ 911 if (idn_deinit()) { 912 /* 913 * Must still be active. 914 */ 915 mutex_exit(&idn.siplock); 916 return (DDI_FAILURE); 917 } 918 idn_deinit_autolink(); 919 /* 920 * Remove our sigblock SSP interrupt handler. 921 */ 922 sgnblk_poll_unregister(idn_sigbhandler); 923 mutex_enter(&idn.sigbintr.sb_mutex); 924 idn_sigbhandler_kill(); 925 idn.sigbintr.sb_cpuid = (uchar_t)-1; 926 idn.sigbintr.sb_busy = IDNSIGB_NOTREADY; 927 mutex_exit(&idn.sigbintr.sb_mutex); 928 /* 929 * Remove our reference to the sigblock area. 930 */ 931 sgnblk_poll_unreference(idn_sigb_setup); 932 idn_gkstat_deinit(); 933 } 934 935 ddi_remove_minor_node(dip, NULL); 936 937 /* 938 * Remove this instance from our linked list. 939 */ 940 IDN_SET_INST2SIP(instance, NULL); 941 if ((hsip = tsip = idn.sip) == sip) { 942 idn.sip = sip->si_nextp; 943 } else { 944 for (; hsip && (sip != hsip); tsip = hsip, 945 hsip = hsip->si_nextp) 946 ; 947 if (hsip) 948 tsip->si_nextp = hsip->si_nextp; 949 } 950 mutex_exit(&idn.siplock); 951 if (sip->si_ksp) 952 kstat_delete(sip->si_ksp); 953 954 ddi_set_driver_private(dip, NULL); 955 956 FREESTRUCT(sip, struct idn, 1); 957 958 return (DDI_SUCCESS); 959 } 960 961 /* 962 * ---------------------------------------------- 963 */ 964 static idn_gprops_t 965 idn_check_conf(dev_info_t *dip, processorid_t *cpuid) 966 { 967 static idn_gprops_t global_props = IDN_GPROPS_UNCHECKED; 968 969 if (global_props == IDN_GPROPS_UNCHECKED) { 970 int p; 971 972 global_props = IDN_GPROPS_OKAY; 973 974 for (p = 0; idn_global_props[p].p_string; p++) { 975 char *str; 976 int *var; 977 int val, v_min, v_max, v_def; 978 979 str = idn_global_props[p].p_string; 980 var = (int *)idn_global_props[p].p_var; 981 v_min = idn_global_props[p].p_min; 982 v_max = idn_global_props[p].p_max; 983 v_def = idn_global_props[p].p_def; 984 ASSERT(str && var); 985 986 val = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 987 DDI_PROP_DONTPASS | 988 DDI_PROP_NOTPROM, 989 str, v_def); 990 if ((v_min != v_max) && 991 ((val < v_min) || (val > v_max))) { 992 cmn_err(CE_WARN, 993 "IDN: 105: driver parameter " 994 "(%s) specified (%d) out of " 995 "range [%d - %d]", 996 str, val, v_min, v_max); 997 global_props = IDN_GPROPS_ERROR; 998 } else { 999 *var = val; 1000 } 1001 } 1002 } 1003 1004 *cpuid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 1005 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 1006 "bind_cpu", -1); 1007 1008 return (global_props); 1009 } 1010 1011 static int 1012 idn_size_check() 1013 { 1014 int i, cnt; 1015 int rv = 0; 1016 ulong_t mboxareasize; 1017 int max_num_slabs; 1018 procname_t proc = "idn_size_check"; 1019 1020 if (IDN_NWR_SIZE == 0) 1021 IDN_NWR_SIZE = IDN_SMR_SIZE; 1022 1023 if (IDN_NWR_SIZE > IDN_SMR_SIZE) { 1024 cmn_err(CE_WARN, 1025 "IDN: 106: idn_nwr_size(%d) > idn_smr_size(%d)" 1026 " - Limiting to %d MB", 1027 IDN_NWR_SIZE, IDN_SMR_SIZE, IDN_SMR_SIZE); 1028 IDN_NWR_SIZE = IDN_SMR_SIZE; 1029 } 1030 1031 if (MB2B(IDN_NWR_SIZE) < IDN_SLAB_SIZE) { 1032 cmn_err(CE_WARN, 1033 "IDN: 107: memory region(%lu) < slab size(%u)", 1034 MB2B(IDN_NWR_SIZE), IDN_SLAB_SIZE); 1035 rv = -1; 1036 } 1037 1038 if (IDN_LOWAT >= IDN_HIWAT) { 1039 cmn_err(CE_WARN, 1040 "IDN: 108: idn_lowat(%d) >= idn_hiwat(%d)", 1041 IDN_LOWAT, IDN_HIWAT); 1042 rv = -1; 1043 } 1044 1045 mboxareasize = (ulong_t)(IDN_MBOXAREA_SIZE + (IDN_SMR_BUFSIZE - 1)); 1046 mboxareasize &= ~((ulong_t)IDN_SMR_BUFSIZE - 1); 1047 #ifdef DEBUG 1048 if ((ulong_t)IDN_SLAB_SIZE < mboxareasize) { 1049 PR_DRV("%s: slab size(%d) < mailbox area(%ld)", 1050 proc, IDN_SLAB_SIZE, mboxareasize); 1051 /* not fatal */ 1052 } 1053 #endif /* DEBUG */ 1054 1055 if ((mboxareasize + (ulong_t)IDN_SLAB_SIZE) > MB2B(IDN_NWR_SIZE)) { 1056 cmn_err(CE_WARN, 1057 "IDN: 109: mailbox area(%lu) + slab size(%u) " 1058 "> nwr region(%lu)", 1059 mboxareasize, IDN_SLAB_SIZE, 1060 MB2B(IDN_NWR_SIZE)); 1061 rv = -1; 1062 } 1063 1064 max_num_slabs = (int)((MB2B(IDN_NWR_SIZE) - mboxareasize) / 1065 (ulong_t)IDN_SLAB_SIZE); 1066 if (max_num_slabs < IDN_SLAB_MINTOTAL) { 1067 cmn_err(CE_WARN, 1068 "IDN: 110: maximum number of slabs(%d) < " 1069 "minimum required(%d)", 1070 max_num_slabs, IDN_SLAB_MINTOTAL); 1071 rv = -1; 1072 } else { 1073 IDN_SLAB_MAXPERDOMAIN = max_num_slabs / IDN_SLAB_MINTOTAL; 1074 } 1075 1076 #if 0 1077 if ((IDN_MTU + sizeof (struct ether_header)) > IDN_DATA_SIZE) { 1078 cmn_err(CE_WARN, 1079 "IDN: (IDN_MTU(%d) + ether_header(%d)) " 1080 "> IDN_DATA_SIZE(%lu)", 1081 IDN_MTU, sizeof (struct ether_header), 1082 IDN_DATA_SIZE); 1083 rv = -1; 1084 } 1085 #endif /* 0 */ 1086 1087 if (IDN_SMR_BUFSIZE & (IDN_ALIGNSIZE - 1)) { 1088 cmn_err(CE_WARN, 1089 "IDN: 111: idn_smr_bufsize(%d) not on a " 1090 "64 byte boundary", IDN_SMR_BUFSIZE); 1091 rv = -1; 1092 } 1093 1094 for (i = cnt = 0; 1095 (cnt <= 1) && (((ulong_t)1 << i) < MB2B(IDN_NWR_SIZE)); 1096 i++) 1097 if ((1 << i) & IDN_SMR_BUFSIZE) 1098 cnt++; 1099 if ((i > 0) && (!cnt || (cnt > 1))) { 1100 cmn_err(CE_WARN, 1101 "IDN: 112: idn_smr_bufsize(%d) not a power of 2", 1102 IDN_SMR_BUFSIZE); 1103 rv = -1; 1104 } 1105 1106 if ((IDN_MBOX_PER_NET & 1) == 0) { 1107 cmn_err(CE_WARN, 1108 "IDN: 113: idn_mbox_per_net(%d) must be an " 1109 "odd number", IDN_MBOX_PER_NET); 1110 rv = -1; 1111 } 1112 1113 if (idn.nchannels > 0) 1114 IDN_WINDOW_EMAX = IDN_WINDOW_MAX + 1115 ((idn.nchannels - 1) * IDN_WINDOW_INCR); 1116 1117 if (IDN_NETSVR_WAIT_MIN > IDN_NETSVR_WAIT_MAX) { 1118 cmn_err(CE_WARN, 1119 "IDN: 115: idn_netsvr_wait_min(%d) cannot be " 1120 "greater than idn_netsvr_wait_max(%d)", 1121 IDN_NETSVR_WAIT_MIN, 1122 IDN_NETSVR_WAIT_MAX); 1123 rv = -1; 1124 } 1125 1126 return (rv); 1127 } 1128 1129 static int 1130 idn_init_smr() 1131 { 1132 uint64_t obp_paddr; 1133 uint64_t obp_size; /* in Bytes */ 1134 uint_t smr_size; /* in MBytes */ 1135 pgcnt_t npages; 1136 procname_t proc = "idn_init_smr"; 1137 1138 if (idn.smr.ready) 1139 return (0); 1140 1141 if (idn_prom_getsmr(&smr_size, &obp_paddr, &obp_size) < 0) 1142 return (-1); 1143 1144 PR_PROTO("%s: smr_size = %d, obp_paddr = 0x%lx, obp_size = 0x%lx\n", 1145 proc, smr_size, obp_paddr, obp_size); 1146 1147 if (IDN_SMR_SIZE) 1148 smr_size = MIN(smr_size, IDN_SMR_SIZE); 1149 1150 npages = btopr(MB2B(smr_size)); 1151 1152 idn.smr.prom_paddr = obp_paddr; 1153 idn.smr.prom_size = obp_size; 1154 idn.smr.vaddr = vmem_alloc(heap_arena, ptob(npages), VM_SLEEP); 1155 ASSERT(((ulong_t)idn.smr.vaddr & MMU_PAGEOFFSET) == 0); 1156 idn.smr.locpfn = (pfn_t)(obp_paddr >> MMU_PAGESHIFT); 1157 idn.smr.rempfn = idn.smr.rempfnlim = PFN_INVALID; 1158 IDN_SMR_SIZE = smr_size; 1159 1160 PR_PROTO("%s: smr vaddr = %p\n", proc, idn.smr.vaddr); 1161 1162 smr_remap(&kas, idn.smr.vaddr, idn.smr.locpfn, IDN_SMR_SIZE); 1163 1164 idn.localid = PADDR_TO_DOMAINID(obp_paddr); 1165 1166 idn.smr.ready = 1; 1167 1168 return (0); 1169 } 1170 1171 static void 1172 idn_deinit_smr() 1173 { 1174 pgcnt_t npages; 1175 1176 if (idn.smr.ready == 0) 1177 return; 1178 1179 smr_remap(&kas, idn.smr.vaddr, PFN_INVALID, IDN_SMR_SIZE); 1180 1181 npages = btopr(MB2B(IDN_SMR_SIZE)); 1182 1183 vmem_free(heap_arena, idn.smr.vaddr, ptob(npages)); 1184 1185 idn.localid = IDN_NIL_DOMID; 1186 1187 IDN_SMR_SIZE = 0; 1188 1189 idn.smr.ready = 0; 1190 } 1191 1192 /*ARGSUSED1*/ 1193 static void 1194 idn_sigb_setup(cpu_sgnblk_t *sigbp, void *arg) 1195 { 1196 procname_t proc = "idn_sigb_setup"; 1197 1198 PR_PROTO("%s: Setting sigb to %p\n", proc, sigbp); 1199 1200 mutex_enter(&idn.idnsb_mutex); 1201 if (sigbp == NULL) { 1202 idn.idnsb = NULL; 1203 idn.idnsb_eventp = NULL; 1204 mutex_exit(&idn.idnsb_mutex); 1205 return; 1206 } 1207 idn.idnsb_eventp = (idnsb_event_t *)sigbp->sigb_idn; 1208 idn.idnsb = (idnsb_t *)&idn.idnsb_eventp->idn_reserved1; 1209 mutex_exit(&idn.idnsb_mutex); 1210 } 1211 1212 static int 1213 idn_init(dev_info_t *dip) 1214 { 1215 struct hwconfig local_hw; 1216 procname_t proc = "idn_init"; 1217 1218 1219 ASSERT(MUTEX_HELD(&idn.siplock)); 1220 1221 if (!idn.enabled) { 1222 cmn_err(CE_WARN, 1223 "IDN: 117: IDN not enabled"); 1224 return (-1); 1225 } 1226 1227 if (idn.dip != NULL) { 1228 PR_DRV("%s: already initialized (dip = 0x%p)\n", 1229 proc, idn.dip); 1230 return (0); 1231 } 1232 1233 /* 1234 * Determine our local domain's hardware configuration. 1235 */ 1236 if (get_hw_config(&local_hw)) { 1237 cmn_err(CE_WARN, 1238 "IDN: 118: hardware config not appropriate"); 1239 return (-1); 1240 } 1241 1242 PR_DRV("%s: locpfn = 0x%lx\n", proc, idn.smr.locpfn); 1243 PR_DRV("%s: rempfn = 0x%lx\n", proc, idn.smr.rempfn); 1244 PR_DRV("%s: smrsize = %d MB\n", proc, IDN_SMR_SIZE); 1245 1246 rw_init(&idn.grwlock, NULL, RW_DEFAULT, NULL); 1247 rw_init(&idn.struprwlock, NULL, RW_DEFAULT, NULL); 1248 mutex_init(&idn.sync.sz_mutex, NULL, MUTEX_DEFAULT, NULL); 1249 mutex_init(&idn.sipwenlock, NULL, MUTEX_DEFAULT, NULL); 1250 1251 /* 1252 * Calculate proper value for idn.bframe_shift. 1253 * Kind of hokey as it assume knowledge of the format 1254 * of the idnparam_t structure. 1255 */ 1256 { 1257 int s; 1258 1259 for (s = 0; (1 << s) < IDN_SMR_BUFSIZE_MIN; s++) 1260 ; 1261 idn.bframe_shift = s; 1262 PR_DRV("%s: idn.bframe_shift = %d, minbuf = %d\n", 1263 proc, idn.bframe_shift, IDN_SMR_BUFSIZE_MIN); 1264 1265 ASSERT((uint_t)IDN_OFFSET2BFRAME(MB2B(idn_smr_size)) < 1266 (1 << 24)); 1267 } 1268 1269 idn_xmit_monitor_init(); 1270 1271 /* 1272 * Initialize the domain op (dopers) stuff. 1273 */ 1274 idn_dopers_init(); 1275 1276 /* 1277 * Initialize the timer (kmem) cache used for timeout 1278 * structures. 1279 */ 1280 idn_timercache_init(); 1281 1282 /* 1283 * Initialize the slab waiting areas. 1284 */ 1285 (void) smr_slabwaiter_init(); 1286 1287 /* 1288 * Initialize retryjob kmem cache. 1289 */ 1290 idn_retrytask_init(); 1291 1292 idn_init_msg_waittime(); 1293 idn_init_msg_retrytime(); 1294 1295 /* 1296 * Initialize idn_domains[] and local domains information 1297 * include idn_global information. 1298 */ 1299 idn_domains_init(&local_hw); 1300 1301 /* 1302 * Start up IDN protocol servers. 1303 */ 1304 if (idn_protocol_init(idn_protocol_nservers) <= 0) { 1305 cmn_err(CE_WARN, 1306 "IDN: 119: failed to initialize %d protocol servers", 1307 idn_protocol_nservers); 1308 idn_domains_deinit(); 1309 idn_retrytask_deinit(); 1310 smr_slabwaiter_deinit(); 1311 idn_timercache_deinit(); 1312 idn_dopers_deinit(); 1313 idn_xmit_monitor_deinit(); 1314 mutex_destroy(&idn.sipwenlock); 1315 mutex_destroy(&idn.sync.sz_mutex); 1316 rw_destroy(&idn.grwlock); 1317 rw_destroy(&idn.struprwlock); 1318 return (-1); 1319 } 1320 1321 /* 1322 * Initialize chan_servers array. 1323 */ 1324 (void) idn_chanservers_init(); 1325 1326 /* 1327 * Need to register the IDN handler with the DMV subsystem. 1328 * 1329 * Need to prevent the IDN driver from being unloaded 1330 * once loaded since DMV's may come in at any time. 1331 * If the driver is not loaded and the idn_dmv_handler 1332 * has been registered with the DMV, system will crash. 1333 */ 1334 (void) idn_init_handler(); 1335 1336 idn.dip = dip; 1337 IDN_GLOCK_EXCL(); 1338 IDN_GSTATE_TRANSITION(IDNGS_OFFLINE); 1339 IDN_GUNLOCK(); 1340 1341 return (0); 1342 } 1343 1344 static int 1345 idn_deinit() 1346 { 1347 procname_t proc = "idn_deinit"; 1348 1349 ASSERT(MUTEX_HELD(&idn.siplock)); 1350 1351 IDN_GLOCK_EXCL(); 1352 1353 if (idn.state != IDNGS_OFFLINE) { 1354 int d; 1355 1356 cmn_err(CE_WARN, 1357 "IDN: 120: cannot deinit while active " 1358 "(state = %s)", idngs_str[idn.state]); 1359 1360 for (d = 0; d < MAX_DOMAINS; d++) { 1361 idn_domain_t *dp; 1362 1363 dp = &idn_domain[d]; 1364 if (dp->dcpu < 0) 1365 continue; 1366 1367 cmn_err(CE_CONT, 1368 "IDN: 121: domain %d (CPU %d, " 1369 "name \"%s\", state %s)\n", 1370 d, dp->dcpu, dp->dname, 1371 idnds_str[dp->dstate]); 1372 } 1373 IDN_GUNLOCK(); 1374 return (-1); 1375 } 1376 1377 if (idn.dip == NULL) { 1378 PR_DRV("%s: already deinitialized\n", proc); 1379 IDN_GUNLOCK(); 1380 return (0); 1381 } 1382 1383 IDN_GSTATE_TRANSITION(IDNGS_IGNORE); 1384 1385 IDN_GUNLOCK(); 1386 1387 idn_xmit_monitor_deinit(); 1388 1389 idn_deinit_handler(); 1390 1391 idn_chanservers_deinit(); 1392 1393 idn.nchannels = 0; 1394 ASSERT(idn.chan_servers == NULL); 1395 1396 smr_slabpool_deinit(); 1397 1398 idn_protocol_deinit(); 1399 1400 idn_domains_deinit(); 1401 1402 smr_slabwaiter_deinit(); 1403 1404 idn_retrytask_deinit(); 1405 1406 idn_timercache_deinit(); 1407 1408 idn_dopers_deinit(); 1409 1410 ASSERT(idn.localid == IDN_NIL_DOMID); 1411 1412 IDN_SET_MASTERID(IDN_NIL_DOMID); 1413 1414 idn_deinit_smr(); 1415 1416 mutex_destroy(&idn.sipwenlock); 1417 mutex_destroy(&idn.sync.sz_mutex); 1418 rw_destroy(&idn.grwlock); 1419 rw_destroy(&idn.struprwlock); 1420 1421 idn.dip = NULL; 1422 1423 return (0); 1424 } 1425 1426 static void 1427 idn_xmit_monitor_init() 1428 { 1429 mutex_init(&idn.xmit_lock, NULL, MUTEX_DEFAULT, NULL); 1430 idn.xmit_tid = (timeout_id_t)NULL; 1431 CHANSET_ZERO(idn.xmit_chanset_wanted); 1432 } 1433 1434 static void 1435 idn_xmit_monitor_deinit() 1436 { 1437 timeout_id_t tid; 1438 1439 mutex_enter(&idn.xmit_lock); 1440 CHANSET_ZERO(idn.xmit_chanset_wanted); 1441 if ((tid = idn.xmit_tid) != (timeout_id_t)NULL) { 1442 idn.xmit_tid = (timeout_id_t)NULL; 1443 mutex_exit(&idn.xmit_lock); 1444 (void) untimeout(tid); 1445 } else { 1446 mutex_exit(&idn.xmit_lock); 1447 } 1448 mutex_destroy(&idn.xmit_lock); 1449 } 1450 1451 static void 1452 idn_init_msg_waittime() 1453 { 1454 idn_msg_waittime[IDNP_NULL] = -1; 1455 idn_msg_waittime[IDNP_NEGO] = idn_msgwait_nego * hz; 1456 idn_msg_waittime[IDNP_CFG] = idn_msgwait_cfg * hz; 1457 idn_msg_waittime[IDNP_CON] = idn_msgwait_con * hz; 1458 idn_msg_waittime[IDNP_FIN] = idn_msgwait_fin * hz; 1459 idn_msg_waittime[IDNP_CMD] = idn_msgwait_cmd * hz; 1460 idn_msg_waittime[IDNP_DATA] = idn_msgwait_data * hz; 1461 } 1462 1463 static void 1464 idn_init_msg_retrytime() 1465 { 1466 idn_msg_retrytime[(int)IDNRETRY_NIL] = -1; 1467 idn_msg_retrytime[(int)IDNRETRY_NEGO] = idn_retryfreq_nego * hz; 1468 idn_msg_retrytime[(int)IDNRETRY_CON] = idn_retryfreq_con * hz; 1469 idn_msg_retrytime[(int)IDNRETRY_CONQ] = idn_retryfreq_con * hz; 1470 idn_msg_retrytime[(int)IDNRETRY_FIN] = idn_retryfreq_fin * hz; 1471 idn_msg_retrytime[(int)IDNRETRY_FINQ] = idn_retryfreq_fin * hz; 1472 } 1473 1474 /* 1475 * ---------------------------------------------- 1476 */ 1477 /*ARGSUSED*/ 1478 static int 1479 idnopen(register queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *crp) 1480 { 1481 register int err = 0; 1482 int minordev; 1483 struct idnstr *stp, **pstp; 1484 procname_t proc = "idnopen"; 1485 1486 ASSERT(sflag != MODOPEN); 1487 1488 IDN_GLOCK_EXCL(); 1489 1490 rw_enter(&idn.struprwlock, RW_WRITER); 1491 mutex_enter(&idn.sipwenlock); 1492 pstp = &idn.strup; 1493 1494 if (idn.enabled == 0) { 1495 PR_DRV("%s: Driver disabled (check OBP:idn-smr-size)\n", 1496 proc); 1497 mutex_exit(&idn.sipwenlock); 1498 rw_exit(&idn.struprwlock); 1499 IDN_GUNLOCK(); 1500 return (EACCES); 1501 } 1502 1503 if (!idn_ndlist && 1504 idn_param_register(idn_param_arr, A_CNT(idn_param_arr))) { 1505 PR_DRV("%s: failed to register ndd parameters\n", proc); 1506 mutex_exit(&idn.sipwenlock); 1507 rw_exit(&idn.struprwlock); 1508 IDN_GUNLOCK(); 1509 return (ENOMEM); 1510 } 1511 IDN_GUNLOCK(); 1512 1513 if (sflag == CLONEOPEN) { 1514 minordev = 0; 1515 for (stp = *pstp; stp; pstp = &stp->ss_nextp, stp = *pstp) { 1516 if (minordev < stp->ss_minor) 1517 break; 1518 minordev++; 1519 } 1520 *devp = makedevice(getmajor(*devp), minordev); 1521 } else { 1522 minordev = getminor(*devp); 1523 } 1524 if (rq->q_ptr) 1525 goto done; 1526 1527 stp = GETSTRUCT(struct idnstr, 1); 1528 stp->ss_rq = rq; 1529 stp->ss_minor = minordev; 1530 rw_init(&stp->ss_rwlock, NULL, RW_DEFAULT, NULL); 1531 /* 1532 * DLPI stuff 1533 */ 1534 stp->ss_sip = NULL; 1535 stp->ss_state = DL_UNATTACHED; 1536 stp->ss_sap = 0; 1537 stp->ss_flags = 0; 1538 stp->ss_mccount = 0; 1539 stp->ss_mctab = NULL; 1540 1541 /* 1542 * Link new entry into list of actives. 1543 */ 1544 stp->ss_nextp = *pstp; 1545 *pstp = stp; 1546 1547 WR(rq)->q_ptr = rq->q_ptr = (void *)stp; 1548 /* 1549 * Disable automatic enabling of our write service 1550 * procedure. We control this explicitly. 1551 */ 1552 noenable(WR(rq)); 1553 1554 /* 1555 * Set our STREAMs queue maximum packet size that 1556 * we'll accept and our high/low water marks. 1557 */ 1558 (void) strqset(WR(rq), QMAXPSZ, 0, IDN_DATA_SIZE); 1559 (void) strqset(WR(rq), QLOWAT, 0, IDN_LOWAT); 1560 (void) strqset(WR(rq), QHIWAT, 0, IDN_HIWAT); 1561 (void) strqset(rq, QMAXPSZ, 0, IDN_DATA_SIZE); 1562 (void) strqset(rq, QLOWAT, 0, IDN_LOWAT); 1563 (void) strqset(rq, QHIWAT, 0, IDN_HIWAT); 1564 1565 done: 1566 mutex_exit(&idn.sipwenlock); 1567 rw_exit(&idn.struprwlock); 1568 1569 (void) qassociate(rq, -1); 1570 qprocson(rq); 1571 1572 return (err); 1573 } 1574 1575 /* 1576 * ---------------------------------------------- 1577 */ 1578 /*ARGSUSED1*/ 1579 static int 1580 idnclose(queue_t *rq, int flag, cred_t *crp) 1581 { 1582 struct idnstr *stp, **pstp; 1583 1584 ASSERT(rq->q_ptr); 1585 1586 qprocsoff(rq); 1587 /* 1588 * Guaranteed to be single threaded with respect 1589 * to this stream at this point. 1590 */ 1591 1592 stp = (struct idnstr *)rq->q_ptr; 1593 1594 if (stp->ss_sip) 1595 idndl_dodetach(stp); 1596 1597 rw_enter(&idn.struprwlock, RW_WRITER); 1598 mutex_enter(&idn.sipwenlock); 1599 pstp = &idn.strup; 1600 for (stp = *pstp; stp; pstp = &stp->ss_nextp, stp = *pstp) 1601 if (stp == (struct idnstr *)rq->q_ptr) 1602 break; 1603 ASSERT(stp); 1604 ASSERT(stp->ss_rq == rq); 1605 *pstp = stp->ss_nextp; 1606 1607 rw_destroy(&stp->ss_rwlock); 1608 FREESTRUCT(stp, struct idnstr, 1); 1609 1610 WR(rq)->q_ptr = rq->q_ptr = NULL; 1611 mutex_exit(&idn.sipwenlock); 1612 rw_exit(&idn.struprwlock); 1613 1614 idn_param_cleanup(); 1615 (void) qassociate(rq, -1); 1616 1617 return (0); 1618 } 1619 1620 /* 1621 * ---------------------------------------------- 1622 */ 1623 static int 1624 idnwput(register queue_t *wq, register mblk_t *mp) 1625 { 1626 register struct idnstr *stp; 1627 struct idn *sip; 1628 procname_t proc = "idnwput"; 1629 1630 stp = (struct idnstr *)wq->q_ptr; 1631 sip = stp->ss_sip; 1632 1633 switch (DB_TYPE(mp)) { 1634 case M_IOCTL: 1635 idnioctl(wq, mp); 1636 break; 1637 1638 case M_DATA: 1639 if (((stp->ss_flags & (IDNSFAST|IDNSRAW)) == 0) || 1640 (stp->ss_state != DL_IDLE) || 1641 (sip == NULL)) { 1642 PR_DLPI("%s: fl=0x%x, st=0x%x, ret(EPROTO)\n", 1643 proc, stp->ss_flags, stp->ss_state); 1644 merror(wq, mp, EPROTO); 1645 1646 } else if (wq->q_first) { 1647 if (putq(wq, mp) == 0) 1648 freemsg(mp); 1649 /* 1650 * We're only holding the reader lock, 1651 * but that's okay since this field 1652 * is just a soft-flag. 1653 */ 1654 sip->si_wantw = 1; 1655 qenable(wq); 1656 1657 } else if (sip->si_flags & IDNPROMISC) { 1658 if (putq(wq, mp) == 0) { 1659 PR_DLPI("%s: putq failed\n", proc); 1660 freemsg(mp); 1661 } else { 1662 PR_DLPI("%s: putq succeeded\n", proc); 1663 } 1664 qenable(wq); 1665 1666 } else { 1667 PR_DLPI("%s: idndl_start(sip=0x%p)\n", 1668 proc, sip); 1669 rw_enter(&stp->ss_rwlock, RW_READER); 1670 (void) idndl_start(wq, mp, sip); 1671 rw_exit(&stp->ss_rwlock); 1672 } 1673 break; 1674 1675 case M_PROTO: 1676 case M_PCPROTO: 1677 /* 1678 * Break the association between the current thread 1679 * and the thread that calls idndl_proto() to resolve 1680 * the problem of idn_chan_server() threads which 1681 * loop back around to call idndl_proto and try to 1682 * recursively acquire internal locks. 1683 */ 1684 if (putq(wq, mp) == 0) 1685 freemsg(mp); 1686 qenable(wq); 1687 break; 1688 1689 case M_FLUSH: 1690 PR_STR("%s: M_FLUSH request (flush = %d)\n", 1691 proc, (int)*mp->b_rptr); 1692 if (*mp->b_rptr & FLUSHW) { 1693 flushq(wq, FLUSHALL); 1694 *mp->b_rptr &= ~FLUSHW; 1695 } 1696 if (*mp->b_rptr & FLUSHR) 1697 qreply(wq, mp); 1698 else 1699 freemsg(mp); 1700 break; 1701 1702 default: 1703 PR_STR("%s: unexpected DB_TYPE 0x%x\n", 1704 proc, DB_TYPE(mp)); 1705 freemsg(mp); 1706 break; 1707 } 1708 1709 return (0); 1710 } 1711 1712 /* 1713 * ---------------------------------------------- 1714 */ 1715 static int 1716 idnwsrv(queue_t *wq) 1717 { 1718 mblk_t *mp; 1719 int err = 0; 1720 struct idnstr *stp; 1721 struct idn *sip; 1722 procname_t proc = "idnwsrv"; 1723 1724 stp = (struct idnstr *)wq->q_ptr; 1725 sip = stp->ss_sip; 1726 1727 while (mp = getq(wq)) { 1728 switch (DB_TYPE(mp)) { 1729 case M_DATA: 1730 if (sip) { 1731 PR_DLPI("%s: idndl_start(sip=0x%p)\n", 1732 proc, sip); 1733 rw_enter(&stp->ss_rwlock, RW_READER); 1734 err = idndl_start(wq, mp, sip); 1735 rw_exit(&stp->ss_rwlock); 1736 if (err) 1737 goto done; 1738 } else { 1739 PR_DLPI("%s: NO sip to start msg\n", proc); 1740 freemsg(mp); 1741 } 1742 break; 1743 1744 case M_PROTO: 1745 case M_PCPROTO: 1746 idndl_proto(wq, mp); 1747 break; 1748 1749 default: 1750 ASSERT(0); 1751 PR_STR("%s: unexpected db_type (%d)\n", 1752 proc, DB_TYPE(mp)); 1753 freemsg(mp); 1754 break; 1755 } 1756 } 1757 done: 1758 return (0); 1759 } 1760 1761 /* 1762 * ---------------------------------------------- 1763 */ 1764 static int 1765 idnrput(register queue_t *rq, register mblk_t *mp) 1766 { 1767 register int err = 0; 1768 procname_t proc = "idnrput"; 1769 1770 switch (DB_TYPE(mp)) { 1771 case M_DATA: 1772 /* 1773 * Should not reach here with data packets 1774 * if running DLPI. 1775 */ 1776 cmn_err(CE_WARN, 1777 "IDN: 123: unexpected M_DATA packets for " 1778 "q_stream 0x%p", rq->q_stream); 1779 freemsg(mp); 1780 err = ENXIO; 1781 break; 1782 1783 case M_FLUSH: 1784 PR_STR("%s: M_FLUSH request (flush = %d)\n", 1785 proc, (int)*mp->b_rptr); 1786 if (*mp->b_rptr & FLUSHR) 1787 flushq(rq, FLUSHALL); 1788 (void) putnext(rq, mp); 1789 break; 1790 1791 case M_ERROR: 1792 PR_STR("%s: M_ERROR (error = %d) coming through\n", 1793 proc, (int)*mp->b_rptr); 1794 (void) putnext(rq, mp); 1795 break; 1796 default: 1797 PR_STR("%s: unexpected DB_TYPE 0x%x\n", 1798 proc, DB_TYPE(mp)); 1799 freemsg(mp); 1800 err = ENXIO; 1801 break; 1802 } 1803 1804 return (err); 1805 } 1806 1807 /* 1808 * ---------------------------------------------- 1809 * Not allowed to enqueue messages! Only M_DATA messages 1810 * can be enqueued on the write stream. 1811 * ---------------------------------------------- 1812 */ 1813 static void 1814 idnioctl(register queue_t *wq, register mblk_t *mp) 1815 { 1816 register struct iocblk *iocp; 1817 register int cmd; 1818 idnop_t *idnop = NULL; 1819 int error = 0; 1820 int argsize; 1821 procname_t proc = "idnioctl"; 1822 1823 iocp = (struct iocblk *)mp->b_rptr; 1824 cmd = iocp->ioc_cmd; 1825 1826 /* 1827 * Intercept DLPI ioctl's. 1828 */ 1829 if (VALID_DLPIOP(cmd)) { 1830 PR_STR("%s: DLPI ioctl(%d)\n", proc, cmd); 1831 error = idnioc_dlpi(wq, mp, &argsize); 1832 goto done; 1833 } 1834 1835 /* 1836 * Validate expected arguments. 1837 */ 1838 if (!VALID_IDNIOCTL(cmd)) { 1839 PR_STR("%s: invalid cmd (0x%x)\n", proc, cmd); 1840 error = EINVAL; 1841 goto done; 1842 1843 } else if (!VALID_NDOP(cmd)) { 1844 error = miocpullup(mp, sizeof (idnop_t)); 1845 if (error != 0) { 1846 PR_STR("%s: idnioc(cmd = 0x%x) miocpullup " 1847 "failed (%d)\n", proc, cmd, error); 1848 goto done; 1849 } 1850 } 1851 1852 argsize = mp->b_cont->b_wptr - mp->b_cont->b_rptr; 1853 idnop = (idnop_t *)mp->b_cont->b_rptr; 1854 1855 switch (cmd) { 1856 case IDNIOC_LINK: 1857 error = idnioc_link(idnop); 1858 break; 1859 1860 case IDNIOC_UNLINK: 1861 error = idnioc_unlink(idnop); 1862 break; 1863 1864 case IDNIOC_MEM_RW: 1865 error = idn_rw_mem(idnop); 1866 break; 1867 1868 case IDNIOC_PING: 1869 error = idn_send_ping(idnop); 1870 break; 1871 1872 case ND_SET: 1873 IDN_GLOCK_EXCL(); 1874 if (!nd_getset(wq, idn_ndlist, mp)) { 1875 IDN_GUNLOCK(); 1876 error = ENOENT; 1877 break; 1878 } 1879 IDN_GUNLOCK(); 1880 qreply(wq, mp); 1881 return; 1882 1883 case ND_GET: 1884 IDN_GLOCK_SHARED(); 1885 if (!nd_getset(wq, idn_ndlist, mp)) { 1886 IDN_GUNLOCK(); 1887 error = ENOENT; 1888 break; 1889 } 1890 IDN_GUNLOCK(); 1891 qreply(wq, mp); 1892 return; 1893 1894 default: 1895 PR_STR("%s: invalid cmd 0x%x\n", proc, cmd); 1896 error = EINVAL; 1897 break; 1898 } 1899 1900 done: 1901 if (error == 0) 1902 miocack(wq, mp, argsize, 0); 1903 else 1904 miocnak(wq, mp, 0, error); 1905 } 1906 1907 /* 1908 * This thread actually services the SSI_LINK/UNLINK calls 1909 * asynchronously that come via BBSRAM. This is necessary 1910 * since we can't process them from within the context of 1911 * the interrupt handler in which idn_sigbhandler() is 1912 * called. 1913 */ 1914 static void 1915 idn_sigbhandler_thread(struct sigbintr **sbpp) 1916 { 1917 int d, pri, rv; 1918 struct sigbintr *sbp; 1919 sigbmbox_t *mbp; 1920 idn_fin_t fintype; 1921 idnsb_data_t *sdp; 1922 idnsb_info_t *sfp; 1923 idnsb_error_t *sep; 1924 idn_domain_t *dp; 1925 procname_t proc = "idn_sigbhandler_thread"; 1926 1927 1928 sbp = *sbpp; 1929 1930 PR_PROTO("%s: KICKED OFF (sigbintr pointer = 0x%p)\n", 1931 proc, sbp); 1932 1933 ASSERT(sbp == &idn.sigbintr); 1934 1935 mutex_enter(&idn.sigbintr.sb_mutex); 1936 1937 while (sbp->sb_busy != IDNSIGB_DIE) { 1938 cpu_sgnblk_t *sigbp; 1939 1940 while ((sbp->sb_busy != IDNSIGB_ACTIVE) && 1941 (sbp->sb_busy != IDNSIGB_DIE)) { 1942 cv_wait(&sbp->sb_cv, &idn.sigbintr.sb_mutex); 1943 PR_PROTO("%s: AWAKENED (busy = %d)\n", 1944 proc, (int)sbp->sb_busy); 1945 } 1946 if (sbp->sb_busy == IDNSIGB_DIE) { 1947 PR_PROTO("%s: DIE REQUESTED\n", proc); 1948 break; 1949 } 1950 1951 if ((sigbp = cpu_sgnblkp[sbp->sb_cpuid]) == NULL) { 1952 cmn_err(CE_WARN, 1953 "IDN: 124: sigblk for CPU ID %d " 1954 "is NULL", sbp->sb_cpuid); 1955 sbp->sb_busy = IDNSIGB_INACTIVE; 1956 continue; 1957 } 1958 1959 mbp = &sigbp->sigb_host_mbox; 1960 1961 if (mbp->flag != SIGB_MBOX_BUSY) { 1962 PR_PROTO("%s: sigblk mbox flag (%d) != BUSY (%d)\n", 1963 proc, mbp->flag, SIGB_MBOX_BUSY); 1964 sbp->sb_busy = IDNSIGB_INACTIVE; 1965 continue; 1966 } 1967 /* 1968 * The sb_busy bit is set and the mailbox flag 1969 * indicates BUSY also, so we effectively have things locked. 1970 * So, we can drop the critical sb_mutex which we want to 1971 * do since it pushes us to PIL 14 while we hold it and we 1972 * don't want to run at PIL 14 across IDN code. 1973 */ 1974 mutex_exit(&idn.sigbintr.sb_mutex); 1975 1976 sdp = (idnsb_data_t *)mbp->data; 1977 sep = (idnsb_error_t *)&sdp->ssb_error; 1978 INIT_IDNKERR(sep); 1979 1980 if (mbp->len != sizeof (idnsb_data_t)) { 1981 PR_PROTO("%s: sigblk mbox length (%d) != " 1982 "expected (%lu)\n", proc, mbp->len, 1983 sizeof (idnsb_data_t)); 1984 SET_IDNKERR_ERRNO(sep, EINVAL); 1985 SET_IDNKERR_IDNERR(sep, IDNKERR_DATA_LEN); 1986 SET_IDNKERR_PARAM0(sep, sizeof (idnsb_data_t)); 1987 1988 goto sberr; 1989 1990 } 1991 if (idn.enabled == 0) { 1992 #ifdef DEBUG 1993 cmn_err(CE_NOTE, 1994 "IDN: 102: driver disabled " 1995 "- check OBP environment " 1996 "(idn-smr-size)"); 1997 #else /* DEBUG */ 1998 cmn_err(CE_NOTE, 1999 "!IDN: 102: driver disabled " 2000 "- check OBP environment " 2001 "(idn-smr-size)"); 2002 #endif /* DEBUG */ 2003 SET_IDNKERR_ERRNO(sep, EACCES); 2004 SET_IDNKERR_IDNERR(sep, IDNKERR_DRV_DISABLED); 2005 2006 goto sberr; 2007 2008 } 2009 2010 switch (mbp->cmd) { 2011 2012 case SSI_LINK: 2013 { 2014 idnsb_link_t slp; 2015 2016 bcopy(&sdp->ssb_link, &slp, sizeof (slp)); 2017 2018 if (slp.master_pri < 0) { 2019 pri = IDNVOTE_MINPRI; 2020 } else if (slp.master_pri > 0) { 2021 /* 2022 * If I'm already in a IDN network, 2023 * then my vote priority is set to 2024 * the max, otherwise it's one-less. 2025 */ 2026 pri = IDNVOTE_MAXPRI; 2027 IDN_GLOCK_SHARED(); 2028 if (idn.ndomains <= 1) 2029 pri--; 2030 IDN_GUNLOCK(); 2031 } else { 2032 pri = IDNVOTE_DEFPRI; 2033 } 2034 2035 PR_PROTO("%s: SSI_LINK(cpuid = %d, domid = %d, " 2036 "pri = %d (req = %d), t/o = %d)\n", 2037 proc, slp.cpuid, slp.domid, pri, 2038 slp.master_pri, slp.timeout); 2039 2040 rv = idn_link(slp.domid, slp.cpuid, pri, 2041 slp.timeout, sep); 2042 SET_IDNKERR_ERRNO(sep, rv); 2043 (void) idn_info(&sdp->ssb_info); 2044 break; 2045 } 2046 2047 case SSI_UNLINK: 2048 { 2049 idnsb_unlink_t sup; 2050 idn_domain_t *xdp; 2051 domainset_t domset; 2052 2053 bcopy(&sdp->ssb_unlink, &sup, sizeof (sup)); 2054 2055 PR_PROTO("%s: SSI_UNLINK(c = %d, d = %d, bs = 0x%x, " 2056 "f = %d, is = 0x%x, t/o = %d)\n", 2057 proc, sup.cpuid, sup.domid, sup.boardset, 2058 sup.force, sup.idnset, sup.timeout); 2059 2060 domset = idn.domset.ds_trans_on | 2061 idn.domset.ds_connected | 2062 idn.domset.ds_trans_off | 2063 idn.domset.ds_awol | 2064 idn.domset.ds_relink; 2065 2066 if (VALID_DOMAINID(sup.domid)) { 2067 dp = &idn_domain[sup.domid]; 2068 } else if (VALID_CPUID(sup.cpuid)) { 2069 for (d = 0; d < MAX_DOMAINS; d++) { 2070 xdp = &idn_domain[d]; 2071 2072 if ((xdp->dcpu == IDN_NIL_DCPU) && 2073 !DOMAIN_IN_SET(domset, d)) 2074 continue; 2075 2076 if (CPU_IN_SET(xdp->dcpuset, 2077 sup.cpuid)) 2078 break; 2079 } 2080 dp = (d == MAX_DOMAINS) ? NULL : xdp; 2081 } 2082 if ((dp == NULL) && sup.boardset) { 2083 for (d = 0; d < MAX_DOMAINS; d++) { 2084 xdp = &idn_domain[d]; 2085 2086 if ((xdp->dcpu == IDN_NIL_DCPU) && 2087 !DOMAIN_IN_SET(domset, d)) 2088 continue; 2089 2090 if (xdp->dhw.dh_boardset & 2091 sup.boardset) 2092 break; 2093 } 2094 dp = (d == MAX_DOMAINS) ? NULL : xdp; 2095 } 2096 if (dp == NULL) { 2097 SET_IDNKERR_ERRNO(sep, EINVAL); 2098 SET_IDNKERR_IDNERR(sep, IDNKERR_INVALID_DOMAIN); 2099 SET_IDNKERR_PARAM0(sep, sup.domid); 2100 SET_IDNKERR_PARAM1(sep, sup.cpuid); 2101 (void) idn_info(&sdp->ssb_info); 2102 goto sberr; 2103 } else { 2104 sup.domid = dp->domid; 2105 } 2106 2107 switch (sup.force) { 2108 case SSIFORCE_OFF: 2109 fintype = IDNFIN_NORMAL; 2110 break; 2111 2112 case SSIFORCE_SOFT: 2113 fintype = IDNFIN_FORCE_SOFT; 2114 break; 2115 2116 case SSIFORCE_HARD: 2117 fintype = IDNFIN_FORCE_HARD; 2118 break; 2119 default: 2120 SET_IDNKERR_ERRNO(sep, EINVAL); 2121 SET_IDNKERR_IDNERR(sep, IDNKERR_INVALID_FORCE); 2122 SET_IDNKERR_PARAM0(sep, sup.force); 2123 (void) idn_info(&sdp->ssb_info); 2124 goto sberr; 2125 } 2126 2127 rv = idn_unlink(sup.domid, sup.idnset, fintype, 2128 IDNFIN_OPT_UNLINK, sup.timeout, sep); 2129 SET_IDNKERR_ERRNO(sep, rv); 2130 (void) idn_info(&sdp->ssb_info); 2131 break; 2132 } 2133 2134 case SSI_INFO: 2135 sfp = &sdp->ssb_info; 2136 2137 PR_PROTO("%s: SSI_INFO\n", proc); 2138 2139 rv = idn_info(sfp); 2140 SET_IDNKERR_ERRNO(sep, rv); 2141 if (rv != 0) { 2142 SET_IDNKERR_IDNERR(sep, IDNKERR_INFO_FAILED); 2143 } 2144 break; 2145 2146 default: 2147 ASSERT(0); 2148 SET_IDNKERR_ERRNO(sep, EINVAL); 2149 SET_IDNKERR_IDNERR(sep, IDNKERR_INVALID_CMD); 2150 SET_IDNKERR_PARAM0(sep, mbp->cmd); 2151 break; 2152 } 2153 2154 sberr: 2155 2156 if (GET_IDNKERR_ERRNO(sep) != 0) { 2157 cmn_err(CE_WARN, 2158 #ifdef DEBUG 2159 "IDN: 125: op (%s) failed, returning " 2160 "(%d/0x%x [%d, %d, %d])", 2161 #else /* DEBUG */ 2162 "!IDN: 125: op (%s) failed, returning " 2163 "(%d/0x%x [%d, %d, %d])", 2164 #endif /* DEBUG */ 2165 (mbp->cmd == SSI_LINK) ? "LINK" : 2166 (mbp->cmd == SSI_UNLINK) ? "UNLINK" : 2167 (mbp->cmd == SSI_INFO) ? 2168 "INFO" : "UNKNOWN", 2169 GET_IDNKERR_ERRNO(sep), 2170 GET_IDNKERR_IDNERR(sep), 2171 GET_IDNKERR_PARAM0(sep), 2172 GET_IDNKERR_PARAM1(sep), 2173 GET_IDNKERR_PARAM2(sep)); 2174 } 2175 2176 PR_PROTO("%s: returning errno = %d, idnerr = %d, " 2177 "params = [%d, %d, %d]\n", 2178 proc, GET_IDNKERR_ERRNO(sep), GET_IDNKERR_IDNERR(sep), 2179 GET_IDNKERR_PARAM0(sep), GET_IDNKERR_PARAM1(sep), 2180 GET_IDNKERR_PARAM2(sep)); 2181 2182 mutex_enter(&idn.sigbintr.sb_mutex); 2183 ASSERT((sbp->sb_busy == IDNSIGB_ACTIVE) || 2184 (sbp->sb_busy == IDNSIGB_DIE)); 2185 mbp->cmd |= SSI_ACK; 2186 if (sbp->sb_busy == IDNSIGB_ACTIVE) 2187 sbp->sb_busy = IDNSIGB_INACTIVE; 2188 /* 2189 * Set flag which kicks off response to SSP. 2190 */ 2191 membar_stst_ldst(); 2192 mbp->flag = HOST_TO_CBS; 2193 } 2194 2195 /* 2196 * Wake up the dude that killed us! 2197 */ 2198 idn.sigb_threadp = NULL; 2199 cv_signal(&sbp->sb_cv); 2200 mutex_exit(&idn.sigbintr.sb_mutex); 2201 thread_exit(); 2202 } 2203 2204 /* 2205 * Create the thread that will service sigb interrupts. 2206 */ 2207 static void 2208 idn_sigbhandler_create() 2209 { 2210 struct sigbintr *sbp; 2211 2212 if (idn.sigb_threadp) { 2213 cmn_err(CE_WARN, 2214 "IDN: 126: sigbhandler thread already " 2215 "exists (0x%p)", idn.sigb_threadp); 2216 return; 2217 } 2218 cv_init(&idn.sigbintr.sb_cv, NULL, CV_DEFAULT, NULL); 2219 sbp = &idn.sigbintr; 2220 sbp->sb_busy = IDNSIGB_INACTIVE; 2221 idn.sigb_threadp = thread_create(NULL, 0, 2222 idn_sigbhandler_thread, &sbp, sizeof (sbp), &p0, 2223 TS_RUN, minclsyspri); 2224 sbp->sb_inum = add_softintr((uint_t)idn_sigbpil, 2225 idn_sigbhandler_wakeup, 0, SOFTINT_ST); 2226 } 2227 2228 static void 2229 idn_sigbhandler_kill() 2230 { 2231 if (idn.sigb_threadp) { 2232 struct sigbintr *sbp; 2233 2234 sbp = &idn.sigbintr; 2235 if (sbp->sb_inum != 0) 2236 (void) rem_softintr(sbp->sb_inum); 2237 sbp->sb_inum = 0; 2238 sbp->sb_busy = IDNSIGB_DIE; 2239 cv_signal(&sbp->sb_cv); 2240 while (idn.sigb_threadp != NULL) 2241 cv_wait(&sbp->sb_cv, &idn.sigbintr.sb_mutex); 2242 sbp->sb_busy = IDNSIGB_INACTIVE; 2243 cv_destroy(&sbp->sb_cv); 2244 } 2245 } 2246 2247 /*ARGSUSED0*/ 2248 static uint_t 2249 idn_sigbhandler_wakeup(caddr_t arg1, caddr_t arg2) 2250 { 2251 mutex_enter(&idn.sigbintr.sb_mutex); 2252 if (idn.sigbintr.sb_busy == IDNSIGB_STARTED) { 2253 idn.sigbintr.sb_busy = IDNSIGB_ACTIVE; 2254 cv_signal(&idn.sigbintr.sb_cv); 2255 } 2256 mutex_exit(&idn.sigbintr.sb_mutex); 2257 2258 return (DDI_INTR_CLAIMED); 2259 } 2260 2261 static void 2262 idn_sigbhandler(processorid_t cpuid, cpu_sgnblk_t *sgnblkp) 2263 { 2264 struct sigbintr *sbp = &idn.sigbintr; 2265 sigbmbox_t *mbp; 2266 idnsb_data_t *sdp; 2267 idnsb_error_t *sep; 2268 uint32_t cmd; 2269 int sigb_lock = 0; 2270 2271 ASSERT(sgnblkp); 2272 2273 mbp = &sgnblkp->sigb_host_mbox; 2274 sdp = (idnsb_data_t *)mbp->data; 2275 sep = &sdp->ssb_error; 2276 cmd = mbp->cmd; 2277 2278 if ((mbp->flag != CBS_TO_HOST) || !VALID_IDNSIGBCMD(cmd)) { 2279 /* 2280 * Not a valid IDN command. Just bail out. 2281 */ 2282 return; 2283 } 2284 2285 mbp->flag = SIGB_MBOX_BUSY; 2286 SET_IDNKERR_ERRNO(sep, 0); 2287 2288 if (cmd & SSI_ACK) { 2289 /* 2290 * Hmmm...weird, the ACK bit is set. 2291 */ 2292 SET_IDNKERR_ERRNO(sep, EPROTO); 2293 SET_IDNKERR_IDNERR(sep, IDNKERR_INVALID_CMD); 2294 SET_IDNKERR_PARAM0(sep, cmd); 2295 goto sigb_done; 2296 } 2297 2298 if (!mutex_tryenter(&idn.sigbintr.sb_mutex)) { 2299 /* 2300 * Couldn't get the lock. Driver is either 2301 * not quite all the way up or is shutting down 2302 * for some reason. Caller should spin again. 2303 */ 2304 cmd |= SSI_ACK; 2305 SET_IDNKERR_ERRNO(sep, EBUSY); 2306 SET_IDNKERR_IDNERR(sep, IDNKERR_SIGBINTR_LOCKED); 2307 goto sigb_done; 2308 } 2309 sigb_lock = 1; 2310 2311 if ((idn.sigb_threadp == NULL) || 2312 (sbp->sb_busy == IDNSIGB_NOTREADY)) { 2313 cmd |= SSI_ACK; 2314 SET_IDNKERR_ERRNO(sep, EAGAIN); 2315 SET_IDNKERR_IDNERR(sep, IDNKERR_SIGBINTR_NOTRDY); 2316 goto sigb_done; 2317 } 2318 2319 if (sbp->sb_busy != IDNSIGB_INACTIVE) { 2320 cmd |= SSI_ACK; 2321 SET_IDNKERR_ERRNO(sep, EBUSY); 2322 SET_IDNKERR_IDNERR(sep, IDNKERR_SIGBINTR_BUSY); 2323 goto sigb_done; 2324 } 2325 2326 sbp->sb_cpuid = (uchar_t)cpuid & 0xff; 2327 membar_stst_ldst(); 2328 sbp->sb_busy = IDNSIGB_STARTED; 2329 /* 2330 * The sb_busy bit is set and the mailbox flag 2331 * indicates BUSY also, so we effectively have things locked. 2332 * So, we can drop the critical sb_mutex which we want to 2333 * do since it pushes us to PIL 14 while we hold it and we 2334 * don't want to run at PIL 14 across IDN code. 2335 * 2336 * Send interrupt to cause idn_sigbhandler_thread to wakeup. 2337 * We cannot do wakeup (cv_signal) directly from here since 2338 * we're executing from a high-level (14) interrupt. 2339 */ 2340 setsoftint(sbp->sb_inum); 2341 2342 sigb_done: 2343 2344 if (GET_IDNKERR_ERRNO(sep) != 0) { 2345 mbp->len = sizeof (idnsb_data_t); 2346 mbp->cmd = cmd; 2347 membar_stst_ldst(); 2348 mbp->flag = HOST_TO_CBS; 2349 } 2350 2351 if (sigb_lock) 2352 mutex_exit(&idn.sigbintr.sb_mutex); 2353 } 2354 2355 static int 2356 idn_info(idnsb_info_t *sfp) 2357 { 2358 int count, d; 2359 idn_domain_t *dp; 2360 idnsb_info_t sinfo; 2361 int local_id, master_id; 2362 procname_t proc = "idn_info"; 2363 2364 bzero(&sinfo, sizeof (sinfo)); 2365 sinfo.master_index = (uchar_t)-1; 2366 sinfo.master_cpuid = (uchar_t)-1; 2367 sinfo.local_index = (uchar_t)-1; 2368 sinfo.local_cpuid = (uchar_t)-1; 2369 2370 IDN_GLOCK_SHARED(); 2371 2372 sinfo.idn_state = (uchar_t)idn.state; 2373 2374 switch (idn.state) { 2375 case IDNGS_OFFLINE: 2376 sinfo.idn_active = SSISTATE_INACTIVE; 2377 PR_PROTO("%s: idn_state (%s) = INACTIVE\n", 2378 proc, idngs_str[idn.state]); 2379 break; 2380 2381 case IDNGS_IGNORE: 2382 PR_PROTO("%s: IGNORING IDN_INFO call...\n", proc); 2383 IDN_GUNLOCK(); 2384 return (EIO); 2385 2386 default: 2387 sinfo.idn_active = SSISTATE_ACTIVE; 2388 PR_PROTO("%s: idn_state (%s) = ACTIVE\n", 2389 proc, idngs_str[idn.state]); 2390 break; 2391 } 2392 master_id = IDN_GET_MASTERID(); 2393 local_id = idn.localid; 2394 2395 /* 2396 * Need to drop idn.grwlock before acquiring domain locks. 2397 */ 2398 IDN_GUNLOCK(); 2399 2400 IDN_SYNC_LOCK(); 2401 2402 sinfo.awol_domset = (ushort_t)idn.domset.ds_awol; 2403 sinfo.conn_domset = (ushort_t)(idn.domset.ds_connected & 2404 ~idn.domset.ds_trans_on); 2405 DOMAINSET_ADD(sinfo.conn_domset, idn.localid); 2406 2407 count = 0; 2408 for (d = 0; d < MAX_DOMAINS; d++) { 2409 dp = &idn_domain[d]; 2410 2411 if (dp->dcpu == IDN_NIL_DCPU) 2412 continue; 2413 2414 IDN_DLOCK_SHARED(d); 2415 if ((dp->dcpu == IDN_NIL_DCPU) || 2416 (dp->dstate == IDNDS_CLOSED)) { 2417 IDN_DUNLOCK(d); 2418 continue; 2419 } 2420 2421 count++; 2422 if (d == local_id) { 2423 sinfo.local_index = (uchar_t)d; 2424 sinfo.local_cpuid = (uchar_t)dp->dcpu; 2425 PR_PROTO("%s: domid %d is LOCAL (cpuid = %d)\n", 2426 proc, d, dp->dcpu); 2427 } 2428 if (d == master_id) { 2429 sinfo.master_index = (uchar_t)d; 2430 sinfo.master_cpuid = (uchar_t)dp->dcpu; 2431 PR_PROTO("%s: domid %d is MASTER (cpuid = %d)\n", 2432 proc, d, dp->dcpu); 2433 } 2434 2435 sinfo.domain_boardset[d] = (ushort_t)dp->dhw.dh_boardset; 2436 2437 IDN_DUNLOCK(d); 2438 } 2439 2440 IDN_SYNC_UNLOCK(); 2441 2442 bcopy(&sinfo, sfp, sizeof (*sfp)); 2443 2444 PR_PROTO("%s: Found %d domains within IDNnet\n", proc, count); 2445 2446 return (0); 2447 } 2448 2449 /* 2450 * ---------------------------------------------- 2451 * ndd param support routines. 2452 * - Borrowed from tcp. 2453 * ---------------------------------------------- 2454 */ 2455 static void 2456 idn_param_cleanup() 2457 { 2458 IDN_GLOCK_EXCL(); 2459 if (!idn.strup && idn_ndlist) 2460 nd_free(&idn_ndlist); 2461 IDN_GUNLOCK(); 2462 } 2463 2464 /*ARGSUSED*/ 2465 static int 2466 idn_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr) 2467 { 2468 idnparam_t *idnpa = (idnparam_t *)cp; 2469 2470 /* 2471 * lock grabbed before calling nd_getset. 2472 */ 2473 ASSERT(IDN_GLOCK_IS_HELD()); 2474 2475 (void) mi_mpprintf(mp, "%ld", idnpa->sp_val); 2476 2477 return (0); 2478 } 2479 2480 /*ARGSUSED*/ 2481 static int 2482 idn_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *cr) 2483 { 2484 char *end; 2485 ulong_t new_value; 2486 idnparam_t *idnpa = (idnparam_t *)cp; 2487 2488 /* 2489 * lock grabbed before calling nd_getset. 2490 */ 2491 ASSERT(IDN_GLOCK_IS_EXCL()); 2492 2493 new_value = (ulong_t)mi_strtol(value, &end, 10); 2494 2495 if ((end == value) || 2496 (new_value < idnpa->sp_min) || 2497 (new_value > idnpa->sp_max)) 2498 return (EINVAL); 2499 2500 if (idn.enabled == 0) { 2501 #ifdef DEBUG 2502 cmn_err(CE_NOTE, 2503 "IDN: 102: driver disabled " 2504 "- check OBP environment " 2505 "(idn-smr-size)"); 2506 #else /* DEBUG */ 2507 cmn_err(CE_NOTE, 2508 "!IDN: 102: driver disabled " 2509 "- check OBP environment " 2510 "(idn-smr-size)"); 2511 #endif /* DEBUG */ 2512 return (EACCES); 2513 } 2514 2515 idnpa->sp_val = new_value; 2516 2517 return (0); 2518 } 2519 2520 static int 2521 idn_param_register(register idnparam_t *idnpa, int count) 2522 { 2523 ASSERT(IDN_GLOCK_IS_EXCL()); 2524 2525 for (; count > 0; count--, idnpa++) { 2526 if (idnpa->sp_name && idnpa->sp_name[0]) { 2527 register int i; 2528 ndsetf_t set_func; 2529 char *p; 2530 /* 2531 * Don't advertise in non-DEBUG parameters. 2532 */ 2533 for (i = 0; idn_param_debug_only[i]; i++) { 2534 p = idn_param_debug_only[i]; 2535 if (strcmp(idnpa->sp_name, p) == 0) 2536 break; 2537 } 2538 if (idn_param_debug_only[i]) 2539 continue; 2540 2541 /* 2542 * Do not register a "set" function for 2543 * read-only parameters. 2544 */ 2545 for (i = 0; idn_param_read_only[i]; i++) { 2546 p = idn_param_read_only[i]; 2547 if (strcmp(idnpa->sp_name, p) == 0) 2548 break; 2549 } 2550 if (idn_param_read_only[i]) 2551 set_func = NULL; 2552 else 2553 set_func = idn_param_set; 2554 2555 if (!nd_load(&idn_ndlist, idnpa->sp_name, 2556 idn_param_get, set_func, 2557 (caddr_t)idnpa)) { 2558 nd_free(&idn_ndlist); 2559 return (-1); 2560 } 2561 } 2562 } 2563 if (!nd_load(&idn_ndlist, "idn_slabpool", idn_slabpool_report, 2564 NULL, NULL)) { 2565 nd_free(&idn_ndlist); 2566 return (-1); 2567 } 2568 if (!nd_load(&idn_ndlist, "idn_buffers", idn_buffer_report, 2569 NULL, NULL)) { 2570 nd_free(&idn_ndlist); 2571 return (-1); 2572 } 2573 if (!nd_load(&idn_ndlist, "idn_mboxtbl", idn_mboxtbl_report, 2574 NULL, MBXTBL_PART_REPORT)) { 2575 nd_free(&idn_ndlist); 2576 return (-1); 2577 } 2578 if (!nd_load(&idn_ndlist, "idn_mboxtbl_all", idn_mboxtbl_report, 2579 NULL, MBXTBL_FULL_REPORT)) { 2580 nd_free(&idn_ndlist); 2581 return (-1); 2582 } 2583 if (!nd_load(&idn_ndlist, "idn_mainmbox", idn_mainmbox_report, 2584 NULL, NULL)) { 2585 nd_free(&idn_ndlist); 2586 return (-1); 2587 } 2588 if (!nd_load(&idn_ndlist, "idn_global", idn_global_report, 2589 NULL, NULL)) { 2590 nd_free(&idn_ndlist); 2591 return (-1); 2592 } 2593 if (!nd_load(&idn_ndlist, "idn_domain", idn_domain_report, 2594 NULL, (caddr_t)0)) { 2595 nd_free(&idn_ndlist); 2596 return (-1); 2597 } 2598 if (!nd_load(&idn_ndlist, "idn_domain_all", idn_domain_report, 2599 NULL, (caddr_t)1)) { 2600 nd_free(&idn_ndlist); 2601 return (-1); 2602 } 2603 if (!nd_load(&idn_ndlist, "idn_bind_net", idn_get_net_binding, 2604 idn_set_net_binding, NULL)) { 2605 nd_free(&idn_ndlist); 2606 return (-1); 2607 } 2608 2609 return (0); 2610 } 2611 2612 /*ARGSUSED*/ 2613 static int 2614 idn_set_net_binding(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *cr) 2615 { 2616 char *end, *cpup; 2617 long net; 2618 processorid_t cpuid; 2619 2620 /* 2621 * lock grabbed before calling nd_getset. 2622 */ 2623 ASSERT(IDN_GLOCK_IS_EXCL()); 2624 2625 if ((cpup = strchr(value, '=')) == NULL) 2626 return (EINVAL); 2627 2628 *cpup++ = '\0'; 2629 2630 net = mi_strtol(value, &end, 10); 2631 if ((end == value) || (net < 0) || (net >= IDN_MAX_NETS) || 2632 !CHAN_IN_SET(idn.chanset, net)) 2633 return (EINVAL); 2634 2635 cpuid = (processorid_t)mi_strtol(cpup, &end, 10); 2636 if ((end == cpup) || ((cpuid != -1) && 2637 (!VALID_CPUID(cpuid) || 2638 !CPU_IN_SET(cpu_ready_set, cpuid)))) 2639 return (EINVAL); 2640 2641 idn_chanserver_bind(net, cpuid); 2642 2643 return (0); 2644 } 2645 2646 /*ARGSUSED*/ 2647 static int 2648 idn_get_net_binding(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr) 2649 { 2650 int c; 2651 2652 /* 2653 * lock grabbed before calling nd_getset. 2654 */ 2655 ASSERT(IDN_GLOCK_IS_HELD()); 2656 2657 (void) mi_mpprintf(mp, 2658 "IDN network interfaces/channels active = %d", 2659 idn.nchannels); 2660 2661 if (idn.nchannels == 0) 2662 return (0); 2663 2664 mi_mpprintf(mp, "Net Cpu"); 2665 2666 for (c = 0; c < IDN_MAX_NETS; c++) { 2667 int bc; 2668 idn_chansvr_t *csp; 2669 2670 if (!CHAN_IN_SET(idn.chanset, c)) 2671 continue; 2672 2673 csp = &idn.chan_servers[c]; 2674 2675 if ((bc = csp->ch_bound_cpuid) == -1) 2676 bc = csp->ch_bound_cpuid_pending; 2677 2678 if (c < 10) 2679 mi_mpprintf(mp, " %d %d", c, bc); 2680 else 2681 mi_mpprintf(mp, " %d %d", c, bc); 2682 } 2683 2684 return (0); 2685 } 2686 2687 static int 2688 idnioc_link(idnop_t *idnop) 2689 { 2690 int rv; 2691 int pri; 2692 idnsb_error_t err; 2693 procname_t proc = "idnioc_link"; 2694 2695 if (idnop->link.master < 0) 2696 pri = IDNVOTE_MINPRI; 2697 else if (idnop->link.master > 0) 2698 pri = IDNVOTE_MAXPRI; 2699 else 2700 pri = IDNVOTE_DEFPRI; 2701 2702 PR_DRV("%s: domid = %d, cpuid = %d, pri = %d\n", 2703 proc, idnop->link.domid, idnop->link.cpuid, pri); 2704 2705 rv = idn_link(idnop->link.domid, idnop->link.cpuid, 2706 pri, idnop->link.wait, &err); 2707 2708 return (rv); 2709 } 2710 2711 static int 2712 idnioc_unlink(idnop_t *idnop) 2713 { 2714 int d, cpuid, domid, rv; 2715 boardset_t idnset; 2716 idn_fin_t fintype; 2717 idn_domain_t *dp, *xdp; 2718 idnsb_error_t err; 2719 procname_t proc = "idnioc_unlink"; 2720 2721 PR_DRV("%s: domid = %d, cpuid = %d, force = %d\n", 2722 proc, idnop->unlink.domid, idnop->unlink.cpuid, 2723 idnop->unlink.force); 2724 2725 idnset = BOARDSET_ALL; 2726 domid = idnop->unlink.domid; 2727 cpuid = idnop->unlink.cpuid; 2728 dp = NULL; 2729 2730 if (domid == IDN_NIL_DOMID) 2731 domid = idn.localid; 2732 2733 if (VALID_DOMAINID(domid)) { 2734 dp = &idn_domain[domid]; 2735 if (VALID_CPUID(cpuid) && (dp->dcpu != IDN_NIL_DCPU) && 2736 !CPU_IN_SET(dp->dcpuset, cpuid)) { 2737 dp = NULL; 2738 PR_PROTO("%s: ERROR: invalid cpuid " 2739 "(%d) for domain (%d) [cset = 0x%x.x%x]\n", 2740 proc, cpuid, domid, 2741 UPPER32_CPUMASK(dp->dcpuset), 2742 LOWER32_CPUMASK(dp->dcpuset)); 2743 } 2744 } else if (VALID_CPUID(cpuid)) { 2745 for (d = 0; d < MAX_DOMAINS; d++) { 2746 xdp = &idn_domain[d]; 2747 2748 if (xdp->dcpu == IDN_NIL_DCPU) 2749 continue; 2750 2751 if (CPU_IN_SET(xdp->dcpuset, cpuid)) 2752 break; 2753 } 2754 dp = (d == MAX_DOMAINS) ? NULL : xdp; 2755 } 2756 2757 if ((dp == NULL) || (dp->dcpu == IDN_NIL_DCPU)) 2758 return (0); 2759 2760 domid = dp->domid; 2761 2762 switch (idnop->unlink.force) { 2763 case SSIFORCE_OFF: 2764 fintype = IDNFIN_NORMAL; 2765 break; 2766 2767 case SSIFORCE_SOFT: 2768 fintype = IDNFIN_FORCE_SOFT; 2769 break; 2770 2771 case SSIFORCE_HARD: 2772 fintype = IDNFIN_FORCE_HARD; 2773 break; 2774 default: 2775 PR_PROTO("%s: invalid force parameter \"%d\"", 2776 proc, idnop->unlink.force); 2777 return (EINVAL); 2778 } 2779 2780 rv = idn_unlink(domid, idnset, fintype, IDNFIN_OPT_UNLINK, 2781 idnop->unlink.wait, &err); 2782 2783 return (rv); 2784 } 2785 2786 static int 2787 idn_send_ping(idnop_t *idnop) 2788 { 2789 int domid = idnop->ping.domid; 2790 int cpuid = idnop->ping.cpuid; 2791 int ocpuid; 2792 idn_domain_t *dp; 2793 idn_msgtype_t mt; 2794 procname_t proc = "idn_send_ping"; 2795 2796 if ((domid == IDN_NIL_DOMID) && (cpuid == IDN_NIL_DCPU)) { 2797 cmn_err(CE_WARN, 2798 "IDN: %s: no valid domain ID or CPU ID given", 2799 proc); 2800 return (EINVAL); 2801 } 2802 if (domid == IDN_NIL_DOMID) 2803 domid = MAX_DOMAINS - 1; 2804 2805 dp = &idn_domain[domid]; 2806 IDN_DLOCK_EXCL(domid); 2807 if ((dp->dcpu == IDN_NIL_DCPU) && (cpuid == IDN_NIL_DCPU)) { 2808 cmn_err(CE_WARN, 2809 "IDN: %s: no valid target CPU specified", 2810 proc); 2811 IDN_DUNLOCK(domid); 2812 return (EINVAL); 2813 } 2814 if (cpuid == IDN_NIL_DCPU) 2815 cpuid = dp->dcpu; 2816 2817 ocpuid = dp->dcpu; 2818 dp->dcpu = cpuid; 2819 2820 /* 2821 * XXX - Need a special PING IDN command. 2822 */ 2823 mt.mt_mtype = IDNP_DATA | IDNP_ACK; 2824 mt.mt_atype = 0; 2825 2826 (void) IDNXDC(domid, &mt, 0x100, 0x200, 0x300, 0x400); 2827 2828 dp->dcpu = ocpuid; 2829 IDN_DUNLOCK(domid); 2830 2831 return (0); 2832 } 2833 2834 /* 2835 * ---------------------------------------------- 2836 */ 2837 static void 2838 idn_dopers_init() 2839 { 2840 int i; 2841 dop_waitlist_t *dwl; 2842 2843 if (idn.dopers) 2844 return; 2845 2846 idn.dopers = GETSTRUCT(struct dopers, 1); 2847 2848 bzero(idn.dopers, sizeof (struct dopers)); 2849 2850 dwl = &idn.dopers->_dop_wcache[0]; 2851 for (i = 0; i < (IDNOP_CACHE_SIZE-1); i++) 2852 dwl[i].dw_next = &dwl[i+1]; 2853 dwl[i].dw_next = NULL; 2854 2855 idn.dopers->dop_freelist = &idn.dopers->_dop_wcache[0]; 2856 idn.dopers->dop_waitcount = 0; 2857 idn.dopers->dop_domset = 0; 2858 idn.dopers->dop_waitlist = NULL; 2859 2860 cv_init(&idn.dopers->dop_cv, NULL, CV_DEFAULT, NULL); 2861 mutex_init(&idn.dopers->dop_mutex, NULL, MUTEX_DEFAULT, NULL); 2862 } 2863 2864 static void 2865 idn_dopers_deinit() 2866 { 2867 dop_waitlist_t *dwl, *next_dwl; 2868 2869 2870 if (idn.dopers == NULL) 2871 return; 2872 2873 for (dwl = idn.dopers->dop_waitlist; dwl; dwl = next_dwl) { 2874 next_dwl = dwl->dw_next; 2875 if (!IDNOP_IN_CACHE(dwl)) 2876 FREESTRUCT(dwl, dop_waitlist_t, 1); 2877 } 2878 2879 cv_destroy(&idn.dopers->dop_cv); 2880 mutex_destroy(&idn.dopers->dop_mutex); 2881 2882 FREESTRUCT(idn.dopers, struct dopers, 1); 2883 idn.dopers = NULL; 2884 } 2885 2886 /* 2887 * Reset the dop_errset field in preparation for an 2888 * IDN operation attempt. This is only called from 2889 * idn_link() and idn_unlink(). 2890 */ 2891 void * 2892 idn_init_op(idn_opflag_t opflag, domainset_t domset, idnsb_error_t *sep) 2893 { 2894 dop_waitlist_t *dwl; 2895 /* 2896 * Clear any outstanding error ops in preparation 2897 * for an IDN (link/unlink) operation. 2898 */ 2899 mutex_enter(&idn.dopers->dop_mutex); 2900 if ((dwl = idn.dopers->dop_freelist) == NULL) { 2901 dwl = GETSTRUCT(dop_waitlist_t, 1); 2902 } else { 2903 idn.dopers->dop_freelist = dwl->dw_next; 2904 bzero(dwl, sizeof (*dwl)); 2905 } 2906 dwl->dw_op = opflag; 2907 dwl->dw_reqset = domset; 2908 dwl->dw_idnerr = sep; 2909 dwl->dw_next = idn.dopers->dop_waitlist; 2910 2911 idn.dopers->dop_waitlist = dwl; 2912 idn.dopers->dop_waitcount++; 2913 idn.dopers->dop_domset |= domset; 2914 mutex_exit(&idn.dopers->dop_mutex); 2915 2916 return (dwl); 2917 } 2918 2919 /* 2920 * Anybody waiting on a opflag operation for any one 2921 * of the domains in domset, needs to be updated to 2922 * additionally wait for new domains in domset. 2923 * This is used, for example, when needing to connect 2924 * to more domains than known at the time of the 2925 * original request. 2926 */ 2927 void 2928 idn_add_op(idn_opflag_t opflag, domainset_t domset) 2929 { 2930 dop_waitlist_t *dwl; 2931 2932 mutex_enter(&idn.dopers->dop_mutex); 2933 if ((idn.dopers->dop_waitcount == 0) || 2934 ((idn.dopers->dop_domset & domset) == 0)) { 2935 mutex_exit(&idn.dopers->dop_mutex); 2936 return; 2937 } 2938 for (dwl = idn.dopers->dop_waitlist; dwl; dwl = dwl->dw_next) 2939 if ((dwl->dw_op == opflag) && (dwl->dw_reqset & domset)) 2940 dwl->dw_reqset |= domset; 2941 mutex_exit(&idn.dopers->dop_mutex); 2942 } 2943 2944 /* 2945 * Mechanism to wakeup any potential users which may be waiting 2946 * for a link/unlink operation to complete. If an error occurred 2947 * don't update dop_errset unless there was no previous error. 2948 */ 2949 void 2950 idn_update_op(idn_opflag_t opflag, domainset_t domset, idnsb_error_t *sep) 2951 { 2952 int do_wakeup = 0; 2953 dop_waitlist_t *dw; 2954 procname_t proc = "idn_update_op"; 2955 2956 mutex_enter(&idn.dopers->dop_mutex); 2957 /* 2958 * If there are no waiters, or nobody is waiting for 2959 * the particular domainset in question, then 2960 * just bail. 2961 */ 2962 if ((idn.dopers->dop_waitcount == 0) || 2963 ((idn.dopers->dop_domset & domset) == 0)) { 2964 mutex_exit(&idn.dopers->dop_mutex); 2965 PR_PROTO("%s: NO waiters exist (domset=0x%x)\n", 2966 proc, domset); 2967 return; 2968 } 2969 2970 for (dw = idn.dopers->dop_waitlist; dw; dw = dw->dw_next) { 2971 int d; 2972 domainset_t dset, rset; 2973 2974 if ((dset = dw->dw_reqset & domset) == 0) 2975 continue; 2976 2977 if (opflag == IDNOP_ERROR) { 2978 dw->dw_errset |= dset; 2979 if (sep) { 2980 for (d = 0; d < MAX_DOMAINS; d++) { 2981 if (!DOMAIN_IN_SET(dset, d)) 2982 continue; 2983 2984 dw->dw_errors[d] = 2985 (short)GET_IDNKERR_ERRNO(sep); 2986 } 2987 bcopy(sep, dw->dw_idnerr, sizeof (*sep)); 2988 } 2989 } else if (opflag == dw->dw_op) { 2990 dw->dw_domset |= dset; 2991 } 2992 2993 /* 2994 * Check if all the domains are spoken for that 2995 * a particular waiter may have been waiting for. 2996 * If there's at least one, we'll need to broadcast. 2997 */ 2998 rset = (dw->dw_errset | dw->dw_domset) & dw->dw_reqset; 2999 if (rset == dw->dw_reqset) 3000 do_wakeup++; 3001 } 3002 3003 PR_PROTO("%s: found %d waiters ready for wakeup\n", proc, do_wakeup); 3004 3005 if (do_wakeup > 0) 3006 cv_broadcast(&idn.dopers->dop_cv); 3007 3008 mutex_exit(&idn.dopers->dop_mutex); 3009 } 3010 3011 void 3012 idn_deinit_op(void *cookie) 3013 { 3014 domainset_t domset; 3015 dop_waitlist_t *hw, *tw; 3016 dop_waitlist_t *dwl = (dop_waitlist_t *)cookie; 3017 3018 mutex_enter(&idn.dopers->dop_mutex); 3019 3020 ASSERT(idn.dopers->dop_waitlist); 3021 3022 if (dwl == idn.dopers->dop_waitlist) { 3023 idn.dopers->dop_waitlist = dwl->dw_next; 3024 if (IDNOP_IN_CACHE(dwl)) { 3025 dwl->dw_next = idn.dopers->dop_freelist; 3026 idn.dopers->dop_freelist = dwl; 3027 } else { 3028 FREESTRUCT(dwl, dop_waitlist_t, 1); 3029 } 3030 } else { 3031 for (tw = idn.dopers->dop_waitlist, hw = tw->dw_next; 3032 hw; 3033 tw = hw, hw = hw->dw_next) { 3034 if (dwl == hw) 3035 break; 3036 } 3037 ASSERT(hw); 3038 3039 tw->dw_next = hw->dw_next; 3040 } 3041 3042 /* 3043 * Recompute domainset for which waiters might be waiting. 3044 * It's possible there may be other waiters waiting for 3045 * the same domainset that the current waiter that's leaving 3046 * may have been waiting for, so we can't simply delete 3047 * the leaving waiter's domainset from dop_domset. 3048 */ 3049 for (hw = idn.dopers->dop_waitlist, domset = 0; hw; hw = hw->dw_next) 3050 domset |= hw->dw_reqset; 3051 3052 idn.dopers->dop_waitcount--; 3053 idn.dopers->dop_domset = domset; 3054 3055 mutex_exit(&idn.dopers->dop_mutex); 3056 } 3057 3058 /* 3059 * Wait until the specified operation succeeds or fails with 3060 * respect to the given domains. Note the function terminates 3061 * if at least one error occurs. 3062 * This process is necessary since link/unlink operations occur 3063 * asynchronously and we need some way of waiting to find out 3064 * if it indeed completed. 3065 * Timeout value is received indirectly from the SSP and 3066 * represents seconds. 3067 */ 3068 int 3069 idn_wait_op(void *cookie, domainset_t *domsetp, int wait_timeout) 3070 { 3071 int d, rv, err = 0; 3072 dop_waitlist_t *dwl; 3073 3074 3075 dwl = (dop_waitlist_t *)cookie; 3076 3077 ASSERT(wait_timeout > 0); 3078 ASSERT((dwl->dw_op == IDNOP_CONNECTED) || 3079 (dwl->dw_op == IDNOP_DISCONNECTED)); 3080 3081 mutex_enter(&idn.dopers->dop_mutex); 3082 3083 while (((dwl->dw_domset | dwl->dw_errset) != dwl->dw_reqset) && !err) { 3084 rv = cv_reltimedwait_sig(&idn.dopers->dop_cv, 3085 &idn.dopers->dop_mutex, (wait_timeout * hz), TR_CLOCK_TICK); 3086 3087 if ((dwl->dw_domset | dwl->dw_errset) == dwl->dw_reqset) 3088 break; 3089 3090 switch (rv) { 3091 case -1: 3092 /* 3093 * timed out 3094 */ 3095 cmn_err(CE_WARN, 3096 "!IDN: 129: %s operation timed out", 3097 (dwl->dw_op == IDNOP_CONNECTED) ? "LINK" : 3098 (dwl->dw_op == IDNOP_DISCONNECTED) ? "UNLINK" : 3099 "UNKNOWN"); 3100 /*FALLTHROUGH*/ 3101 case 0: 3102 /* 3103 * signal, e.g. kill(2) 3104 */ 3105 err = 1; 3106 break; 3107 3108 default: 3109 break; 3110 } 3111 } 3112 3113 if (dwl->dw_domset == dwl->dw_reqset) { 3114 rv = 0; 3115 } else { 3116 /* 3117 * Op failed for some domains or we were awakened. 3118 */ 3119 for (d = rv = 0; (d < MAX_DOMAINS) && !rv; d++) 3120 rv = dwl->dw_errors[d]; 3121 } 3122 *domsetp = dwl->dw_domset; 3123 3124 mutex_exit(&idn.dopers->dop_mutex); 3125 3126 idn_deinit_op(cookie); 3127 3128 return (rv); 3129 } 3130 3131 /* 3132 * -------------------------------------------------- 3133 * Return any valid (& ready) cpuid for the given board based on 3134 * the given cpuset. 3135 * -------------------------------------------------- 3136 */ 3137 int 3138 board_to_ready_cpu(int board, cpuset_t cpuset) 3139 { 3140 int base_cpuid; 3141 int ncpu_board = MAX_CPU_PER_BRD; 3142 3143 board *= ncpu_board; 3144 for (base_cpuid = board; 3145 base_cpuid < (board + ncpu_board); 3146 base_cpuid++) 3147 if (CPU_IN_SET(cpuset, base_cpuid)) 3148 return (base_cpuid); 3149 3150 return (-1); 3151 } 3152 3153 void 3154 idn_domain_resetentry(idn_domain_t *dp) 3155 { 3156 register int i; 3157 procname_t proc = "idn_domain_resetentry"; 3158 3159 ASSERT(dp); 3160 ASSERT(dp->dstate == IDNDS_CLOSED); 3161 ASSERT(IDN_DLOCK_IS_EXCL(dp->domid)); 3162 ASSERT(IDN_GLOCK_IS_EXCL()); 3163 3164 ASSERT(dp->domid == (dp - &idn_domain[0])); 3165 3166 IDN_FSTATE_TRANSITION(dp, IDNFIN_OFF); 3167 dp->dname[0] = '\0'; 3168 dp->dnetid = (ushort_t)-1; 3169 dp->dmtu = 0; 3170 dp->dbufsize = 0; 3171 dp->dslabsize = 0; 3172 dp->dnwrsize = 0; 3173 dp->dncpus = 0; 3174 dp->dcpuindex = 0; 3175 CPUSET_ZERO(dp->dcpuset); 3176 dp->dcpu = dp->dcpu_last = dp->dcpu_save = IDN_NIL_DCPU; 3177 dp->dvote.ticket = 0; 3178 dp->dslab = NULL; 3179 dp->dslab_state = DSLAB_STATE_UNKNOWN; 3180 dp->dnslabs = 0; 3181 dp->dio = 0; 3182 dp->dioerr = 0; 3183 lock_clear(&dp->diowanted); 3184 bzero(&dp->dhw, sizeof (dp->dhw)); 3185 dp->dxp = NULL; 3186 IDN_XSTATE_TRANSITION(dp, IDNXS_NIL); 3187 dp->dsync.s_cmd = IDNSYNC_NIL; 3188 dp->dfin_sync = IDNFIN_SYNC_OFF; 3189 IDN_RESET_COOKIES(dp->domid); 3190 dp->dcookie_err = 0; 3191 bzero(&dp->dawol, sizeof (dp->dawol)); 3192 dp->dtmp = -1; 3193 3194 if (dp->dtimerq.tq_queue != NULL) { 3195 PR_PROTO("%s: WARNING: MSG timerq not empty (count = %d)\n", 3196 proc, dp->dtimerq.tq_count); 3197 IDN_MSGTIMER_STOP(dp->domid, 0, 0); 3198 } 3199 3200 for (i = 0; i < NCPU; i++) 3201 dp->dcpumap[i] = (uchar_t)-1; 3202 } 3203 3204 int 3205 idn_open_domain(int domid, int cpuid, uint_t ticket) 3206 { 3207 int c, new_cpuid; 3208 idn_domain_t *dp, *ldp; 3209 procname_t proc = "idn_open_domain"; 3210 3211 ASSERT(IDN_SYNC_IS_LOCKED()); 3212 ASSERT(IDN_DLOCK_IS_EXCL(domid)); 3213 3214 if (!VALID_DOMAINID(domid)) { 3215 PR_PROTO("%s: INVALID domainid (%d) " 3216 "[cpuid = %d, ticket = 0x%x]\n", 3217 proc, domid, cpuid, ticket); 3218 return (-1); 3219 } 3220 3221 dp = &idn_domain[domid]; 3222 ldp = &idn_domain[idn.localid]; 3223 3224 if (dp->dcpu >= 0) { 3225 PR_PROTO("%s:%d: domain already OPEN (state = %s)\n", 3226 proc, domid, idnds_str[dp->dstate]); 3227 return (1); 3228 } 3229 3230 if (DOMAIN_IN_SET(idn.domset.ds_relink, domid)) { 3231 if (dp->dcpu_save == IDN_NIL_DCPU) 3232 new_cpuid = cpuid; 3233 else 3234 new_cpuid = dp->dcpu_save; 3235 } else { 3236 new_cpuid = cpuid; 3237 } 3238 3239 if (new_cpuid == IDN_NIL_DCPU) { 3240 PR_PROTO("%s:%d: WARNING: invalid cpuid (%d) specified\n", 3241 proc, domid, new_cpuid); 3242 return (-1); 3243 } 3244 3245 IDN_GLOCK_EXCL(); 3246 3247 idn_domain_resetentry(dp); 3248 3249 PR_STATE("%s:%d: requested cpuid %d, assigning cpuid %d\n", 3250 proc, domid, cpuid, new_cpuid); 3251 3252 idn_assign_cookie(domid); 3253 3254 dp->dcpu = dp->dcpu_save = new_cpuid; 3255 dp->dvote.ticket = ticket; 3256 CPUSET_ADD(dp->dcpuset, new_cpuid); 3257 dp->dncpus = 1; 3258 for (c = 0; c < NCPU; c++) 3259 dp->dcpumap[c] = (uchar_t)new_cpuid; 3260 dp->dhw.dh_nboards = 1; 3261 dp->dhw.dh_boardset = BOARDSET(CPUID_TO_BOARDID(new_cpuid)); 3262 3263 if (domid != idn.localid) 3264 IDN_DLOCK_EXCL(idn.localid); 3265 3266 if (idn.ndomains == 1) { 3267 struct hwconfig local_hw; 3268 3269 /* 3270 * We're attempting to connect to our first domain. 3271 * Recheck our local hardware configuration before 3272 * we go any further in case it changed due to a DR, 3273 * and update any structs dependent on this. 3274 * ASSUMPTION: 3275 * IDN is unlinked before performing any DRs. 3276 */ 3277 PR_PROTO("%s: RECHECKING local HW config.\n", proc); 3278 if (get_hw_config(&local_hw)) { 3279 dp->dcpu = IDN_NIL_DCPU; 3280 cmn_err(CE_WARN, 3281 "IDN: 118: hardware config not appropriate"); 3282 if (domid != idn.localid) 3283 IDN_DUNLOCK(idn.localid); 3284 IDN_GUNLOCK(); 3285 return (-1); 3286 } 3287 (void) update_local_hw_config(ldp, &local_hw); 3288 } 3289 3290 idn.ndomains++; 3291 3292 if (domid != idn.localid) 3293 IDN_DUNLOCK(idn.localid); 3294 IDN_GUNLOCK(); 3295 3296 IDN_MBOX_LOCK(domid); 3297 dp->dmbox.m_tbl = NULL; 3298 3299 if (domid != idn.localid) { 3300 dp->dmbox.m_send = idn_mainmbox_init(domid, 3301 IDNMMBOX_TYPE_SEND); 3302 dp->dmbox.m_recv = idn_mainmbox_init(domid, 3303 IDNMMBOX_TYPE_RECV); 3304 } else { 3305 /* 3306 * The local domain does not need send/recv 3307 * mailboxes in its idn_domain[] entry. 3308 */ 3309 dp->dmbox.m_send = NULL; 3310 dp->dmbox.m_recv = NULL; 3311 } 3312 IDN_MBOX_UNLOCK(domid); 3313 3314 PR_PROTO("%s:%d: new domain (cpu = %d, vote = 0x%x)\n", 3315 proc, domid, dp->dcpu, dp->dvote.ticket); 3316 3317 return (0); 3318 } 3319 3320 /* 3321 * The local domain never "closes" itself unless the driver 3322 * is doing a idndetach. It will be reopened during idnattach 3323 * when idn_domains_init is called. 3324 */ 3325 void 3326 idn_close_domain(int domid) 3327 { 3328 uint_t token; 3329 idn_domain_t *dp; 3330 procname_t proc = "idn_close_domain"; 3331 3332 ASSERT(IDN_SYNC_IS_LOCKED()); 3333 ASSERT(IDN_DLOCK_IS_EXCL(domid)); 3334 3335 dp = &idn_domain[domid]; 3336 3337 ASSERT(dp->dstate == IDNDS_CLOSED); 3338 3339 if (dp->dcpu == IDN_NIL_DCPU) { 3340 PR_PROTO("%s:%d: DOMAIN ALREADY CLOSED!\n", 3341 proc, domid); 3342 return; 3343 } 3344 3345 token = IDN_RETRY_TOKEN(domid, IDN_RETRY_TYPEALL); 3346 3347 (void) idn_retry_terminate(token); 3348 3349 DOMAINSET_DEL(idn.domset.ds_trans_on, domid); 3350 DOMAINSET_DEL(idn.domset.ds_ready_on, domid); 3351 DOMAINSET_DEL(idn.domset.ds_connected, domid); 3352 DOMAINSET_DEL(idn.domset.ds_trans_off, domid); 3353 DOMAINSET_DEL(idn.domset.ds_ready_off, domid); 3354 DOMAINSET_DEL(idn.domset.ds_hwlinked, domid); 3355 DOMAINSET_DEL(idn.domset.ds_flush, domid); 3356 3357 idn_sync_exit(domid, IDNSYNC_CONNECT); 3358 idn_sync_exit(domid, IDNSYNC_DISCONNECT); 3359 3360 IDN_GLOCK_EXCL(); 3361 3362 if (DOMAIN_IN_SET(idn.domset.ds_awol, domid)) 3363 idn_clear_awol(domid); 3364 3365 idn.ndomains--; 3366 3367 IDN_GUNLOCK(); 3368 3369 IDN_MBOX_LOCK(domid); 3370 dp->dmbox.m_tbl = NULL; 3371 3372 if (dp->dmbox.m_send) { 3373 idn_mainmbox_deinit(domid, dp->dmbox.m_send); 3374 dp->dmbox.m_send = NULL; 3375 } 3376 3377 if (dp->dmbox.m_recv) { 3378 idn_mainmbox_deinit(domid, dp->dmbox.m_recv); 3379 dp->dmbox.m_recv = NULL; 3380 } 3381 3382 IDN_MBOX_UNLOCK(domid); 3383 3384 cmn_err(CE_NOTE, 3385 "!IDN: 142: link (domain %d, CPU %d) disconnected", 3386 dp->domid, dp->dcpu); 3387 3388 dp->dcpu = IDN_NIL_DCPU; /* ultimate demise */ 3389 3390 IDN_RESET_COOKIES(domid); 3391 3392 ASSERT(dp->dio <= 0); 3393 ASSERT(dp->dioerr == 0); 3394 ASSERT(dp->dslab == NULL); 3395 ASSERT(dp->dnslabs == 0); 3396 3397 IDN_GKSTAT_GLOBAL_EVENT(gk_unlinks, gk_unlink_last); 3398 } 3399 3400 3401 /* 3402 * ----------------------------------------------------------------------- 3403 */ 3404 static void 3405 idn_domains_init(struct hwconfig *local_hw) 3406 { 3407 register int i, d; 3408 idn_domain_t *ldp; 3409 uchar_t *cpumap; 3410 3411 ASSERT(local_hw != NULL); 3412 3413 cpumap = GETSTRUCT(uchar_t, NCPU * MAX_DOMAINS); 3414 3415 for (d = 0; d < MAX_DOMAINS; d++) { 3416 register idn_domain_t *dp; 3417 3418 dp = &idn_domain[d]; 3419 3420 dp->domid = d; 3421 3422 rw_init(&dp->drwlock, NULL, RW_DEFAULT, NULL); 3423 3424 IDN_TIMERQ_INIT(&dp->dtimerq); 3425 3426 dp->dstate = IDNDS_CLOSED; 3427 3428 mutex_init(&dp->dmbox.m_mutex, NULL, MUTEX_DEFAULT, NULL); 3429 3430 dp->dcpumap = cpumap; 3431 3432 rw_init(&dp->dslab_rwlock, NULL, RW_DEFAULT, NULL); 3433 3434 IDN_DLOCK_EXCL(d); 3435 IDN_GLOCK_EXCL(); 3436 3437 idn_domain_resetentry(dp); 3438 3439 IDN_GUNLOCK(); 3440 3441 IDNSB_DOMAIN_UPDATE(dp); 3442 3443 IDN_DUNLOCK(d); 3444 3445 cpumap += NCPU; 3446 } 3447 3448 IDN_SYNC_LOCK(); 3449 3450 /* 3451 * Update local domain information. 3452 */ 3453 ASSERT(idn.smr.locpfn); 3454 ASSERT(local_hw->dh_nboards && local_hw->dh_boardset); 3455 3456 idn.ndomains = 0; /* note that open_domain will get us to 1 */ 3457 3458 IDN_DLOCK_EXCL(idn.localid); 3459 d = idn_open_domain(idn.localid, (int)CPU->cpu_id, 0); 3460 ASSERT(d == 0); 3461 IDN_GLOCK_EXCL(); 3462 IDN_SET_MASTERID(IDN_NIL_DOMID); 3463 IDN_SET_NEW_MASTERID(IDN_NIL_DOMID); 3464 3465 ldp = &idn_domain[idn.localid]; 3466 3467 strncpy(ldp->dname, utsname.nodename, MAXDNAME - 1); 3468 ldp->dname[MAXDNAME-1] = '\0'; 3469 bcopy(local_hw, &ldp->dhw, sizeof (ldp->dhw)); 3470 ASSERT(idn.ndomains == 1); 3471 ASSERT((ldp->dhw.dh_nboards > 0) && 3472 (ldp->dhw.dh_nboards <= MAX_BOARDS)); 3473 ldp->dnetid = IDN_DOMID2NETID(ldp->domid); 3474 ldp->dmtu = IDN_MTU; 3475 ldp->dbufsize = IDN_SMR_BUFSIZE; 3476 ldp->dslabsize = (short)IDN_SLAB_BUFCOUNT; 3477 ldp->dnwrsize = (short)IDN_NWR_SIZE; 3478 ldp->dcpuset = cpu_ready_set; 3479 ldp->dncpus = (short)ncpus; 3480 ldp->dvote.ticket = IDNVOTE_INITIAL_TICKET; 3481 ldp->dvote.v.master = 0; 3482 ldp->dvote.v.nmembrds = ldp->dhw.dh_nmcadr - 1; 3483 ldp->dvote.v.ncpus = (int)ldp->dncpus - 1; 3484 ldp->dvote.v.board = CPUID_TO_BOARDID(ldp->dcpu); 3485 i = -1; 3486 for (d = 0; d < NCPU; d++) { 3487 BUMP_INDEX(ldp->dcpuset, i); 3488 ldp->dcpumap[d] = (uchar_t)i; 3489 } 3490 3491 CPUSET_ZERO(idn.dc_cpuset); 3492 CPUSET_OR(idn.dc_cpuset, ldp->dcpuset); 3493 idn.dc_boardset = ldp->dhw.dh_boardset; 3494 3495 /* 3496 * Setting the state for ourselves is only relevant 3497 * for loopback performance testing. Anyway, it 3498 * makes sense that we always have an established 3499 * connection with ourself regardless of IDN :-o 3500 */ 3501 IDN_DSTATE_TRANSITION(ldp, IDNDS_CONNECTED); 3502 3503 IDN_GUNLOCK(); 3504 IDN_DUNLOCK(idn.localid); 3505 IDN_SYNC_UNLOCK(); 3506 } 3507 3508 static void 3509 idn_domains_deinit() 3510 { 3511 register int d; 3512 3513 IDN_SYNC_LOCK(); 3514 IDN_DLOCK_EXCL(idn.localid); 3515 IDN_DSTATE_TRANSITION(&idn_domain[idn.localid], IDNDS_CLOSED); 3516 idn_close_domain(idn.localid); 3517 IDN_DUNLOCK(idn.localid); 3518 IDN_SYNC_UNLOCK(); 3519 idn.localid = IDN_NIL_DOMID; 3520 3521 FREESTRUCT(idn_domain[0].dcpumap, uchar_t, NCPU * MAX_DOMAINS); 3522 3523 for (d = 0; d < MAX_DOMAINS; d++) { 3524 idn_domain_t *dp; 3525 3526 dp = &idn_domain[d]; 3527 3528 rw_destroy(&dp->dslab_rwlock); 3529 mutex_destroy(&dp->dmbox.m_mutex); 3530 rw_destroy(&dp->drwlock); 3531 IDN_TIMERQ_DEINIT(&dp->dtimerq); 3532 dp->dcpumap = NULL; 3533 } 3534 } 3535 3536 /* 3537 * ----------------------------------------------------------------------- 3538 */ 3539 static void 3540 idn_retrytask_init() 3541 { 3542 ASSERT(idn.retryqueue.rq_cache == NULL); 3543 3544 mutex_init(&idn.retryqueue.rq_mutex, NULL, MUTEX_DEFAULT, NULL); 3545 idn.retryqueue.rq_cache = kmem_cache_create("idn_retryjob_cache", 3546 sizeof (idn_retry_job_t), 3547 0, NULL, NULL, NULL, 3548 NULL, NULL, 0); 3549 } 3550 3551 static void 3552 idn_retrytask_deinit() 3553 { 3554 if (idn.retryqueue.rq_cache == NULL) 3555 return; 3556 3557 kmem_cache_destroy(idn.retryqueue.rq_cache); 3558 mutex_destroy(&idn.retryqueue.rq_mutex); 3559 3560 bzero(&idn.retryqueue, sizeof (idn.retryqueue)); 3561 } 3562 3563 /* 3564 * ----------------------------------------------------------------------- 3565 */ 3566 static void 3567 idn_timercache_init() 3568 { 3569 ASSERT(idn.timer_cache == NULL); 3570 3571 idn.timer_cache = kmem_cache_create("idn_timer_cache", 3572 sizeof (idn_timer_t), 3573 0, NULL, NULL, NULL, 3574 NULL, NULL, 0); 3575 } 3576 3577 static void 3578 idn_timercache_deinit() 3579 { 3580 if (idn.timer_cache == NULL) 3581 return; 3582 3583 kmem_cache_destroy(idn.timer_cache); 3584 idn.timer_cache = NULL; 3585 } 3586 3587 idn_timer_t * 3588 idn_timer_alloc() 3589 { 3590 idn_timer_t *tp; 3591 3592 tp = kmem_cache_alloc(idn.timer_cache, KM_SLEEP); 3593 bzero(tp, sizeof (*tp)); 3594 tp->t_forw = tp->t_back = tp; 3595 3596 return (tp); 3597 } 3598 3599 void 3600 idn_timer_free(idn_timer_t *tp) 3601 { 3602 if (tp == NULL) 3603 return; 3604 kmem_cache_free(idn.timer_cache, tp); 3605 } 3606 3607 void 3608 idn_timerq_init(idn_timerq_t *tq) 3609 { 3610 mutex_init(&tq->tq_mutex, NULL, MUTEX_DEFAULT, NULL); 3611 tq->tq_count = 0; 3612 tq->tq_queue = NULL; 3613 } 3614 3615 void 3616 idn_timerq_deinit(idn_timerq_t *tq) 3617 { 3618 ASSERT(tq->tq_queue == NULL); 3619 mutex_destroy(&tq->tq_mutex); 3620 } 3621 3622 /* 3623 * Dequeue all the timers of the given subtype from the 3624 * given timerQ. If subtype is 0, then dequeue all the 3625 * timers. 3626 */ 3627 idn_timer_t * 3628 idn_timer_get(idn_timerq_t *tq, int type, ushort_t tcookie) 3629 { 3630 register idn_timer_t *tp, *tphead; 3631 3632 ASSERT(IDN_TIMERQ_IS_LOCKED(tq)); 3633 3634 if ((tp = tq->tq_queue) == NULL) 3635 return (NULL); 3636 3637 if (!type) { 3638 tq->tq_queue = NULL; 3639 tq->tq_count = 0; 3640 tphead = tp; 3641 } else { 3642 int count; 3643 idn_timer_t *tpnext; 3644 3645 tphead = NULL; 3646 count = tq->tq_count; 3647 do { 3648 tpnext = tp->t_forw; 3649 if ((tp->t_type == type) && 3650 (!tcookie || (tp->t_cookie == tcookie))) { 3651 tp->t_forw->t_back = tp->t_back; 3652 tp->t_back->t_forw = tp->t_forw; 3653 if (tphead == NULL) { 3654 tp->t_forw = tp->t_back = tp; 3655 } else { 3656 tp->t_forw = tphead; 3657 tp->t_back = tphead->t_back; 3658 tp->t_back->t_forw = tp; 3659 tphead->t_back = tp; 3660 } 3661 tphead = tp; 3662 if (--(tq->tq_count) == 0) 3663 tq->tq_queue = NULL; 3664 else if (tq->tq_queue == tp) 3665 tq->tq_queue = tpnext; 3666 } 3667 tp = tpnext; 3668 } while (--count > 0); 3669 } 3670 3671 if (tphead) { 3672 tphead->t_back->t_forw = NULL; 3673 3674 for (tp = tphead; tp; tp = tp->t_forw) 3675 tp->t_onq = 0; 3676 } 3677 3678 return (tphead); 3679 } 3680 3681 ushort_t 3682 idn_timer_start(idn_timerq_t *tq, idn_timer_t *tp, clock_t tval) 3683 { 3684 idn_timer_t *otp; 3685 ushort_t tcookie; 3686 procname_t proc = "idn_timer_start"; 3687 STRING(str); 3688 3689 ASSERT(tq && tp && (tval > 0)); 3690 ASSERT((tp->t_forw == tp) && (tp->t_back == tp)); 3691 ASSERT(tp->t_type != 0); 3692 3693 IDN_TIMERQ_LOCK(tq); 3694 /* 3695 * Assign a unique non-zero 8-bit cookie to this timer 3696 * if the caller hasn't already preassigned one. 3697 */ 3698 while ((tcookie = tp->t_cookie) == 0) { 3699 tp->t_cookie = (tp->t_type & 0xf) | 3700 ((++tq->tq_cookie & 0xf) << 4); 3701 /* 3702 * Calculated cookie must never conflict 3703 * with the public timer cookie. 3704 */ 3705 ASSERT(tp->t_cookie != IDN_TIMER_PUBLIC_COOKIE); 3706 } 3707 3708 /* 3709 * First have to remove old timers of the 3710 * same type and cookie, and get rid of them. 3711 */ 3712 otp = idn_timer_get(tq, tp->t_type, tcookie); 3713 3714 tq->tq_count++; 3715 3716 if (tq->tq_queue == NULL) { 3717 tq->tq_queue = tp; 3718 ASSERT((tp->t_forw == tp) && (tp->t_back == tp)); 3719 } else { 3720 /* 3721 * Put me at the end of the list. 3722 */ 3723 tp->t_forw = tq->tq_queue; 3724 tp->t_back = tq->tq_queue->t_back; 3725 tp->t_back->t_forw = tp; 3726 tp->t_forw->t_back = tp; 3727 } 3728 3729 tp->t_onq = 1; 3730 tp->t_q = tq; 3731 tp->t_id = timeout(idn_timer_expired, (caddr_t)tp, tval); 3732 3733 3734 INUM2STR(tp->t_type, str); 3735 PR_TIMER("%s: started %s timer (domain = %d, cookie = 0x%x)\n", 3736 proc, str, tp->t_domid, tcookie); 3737 3738 IDN_TIMERQ_UNLOCK(tq); 3739 3740 if (otp) 3741 (void) idn_timer_stopall(otp); 3742 3743 return (tcookie); 3744 } 3745 3746 /* 3747 * Stop all timers of the given subtype. 3748 * If subtype is 0, then stop all timers 3749 * in this timerQ. 3750 */ 3751 void 3752 idn_timer_stop(idn_timerq_t *tq, int type, ushort_t tcookie) 3753 { 3754 idn_timer_t *tphead; 3755 procname_t proc = "idn_timer_stop"; 3756 STRING(str); 3757 3758 ASSERT(tq); 3759 3760 INUM2STR(type, str); 3761 3762 IDN_TIMERQ_LOCK(tq); 3763 3764 if (tq->tq_count == 0) { 3765 PR_TIMER("%s: found no %s timers (count=0)\n", proc, str); 3766 IDN_TIMERQ_UNLOCK(tq); 3767 return; 3768 } 3769 tphead = idn_timer_get(tq, type, tcookie); 3770 #ifdef DEBUG 3771 if (tphead == NULL) 3772 PR_TIMER("%s: found no %s (cookie = 0x%x) " 3773 "timers (count=%d)!!\n", 3774 proc, str, tcookie, tq->tq_count); 3775 #endif /* DEBUG */ 3776 IDN_TIMERQ_UNLOCK(tq); 3777 3778 if (tphead) 3779 (void) idn_timer_stopall(tphead); 3780 } 3781 3782 int 3783 idn_timer_stopall(idn_timer_t *tp) 3784 { 3785 int count = 0; 3786 int nonactive; 3787 uint_t type; 3788 idn_timer_t *ntp; 3789 procname_t proc = "idn_timer_stopall"; 3790 STRING(str); 3791 3792 nonactive = 0; 3793 3794 if (tp) { 3795 /* 3796 * Circle should have been broken. 3797 */ 3798 ASSERT(tp->t_back->t_forw == NULL); 3799 type = tp->t_type; 3800 INUM2STR(type, str); 3801 } 3802 3803 for (; tp; tp = ntp) { 3804 ntp = tp->t_forw; 3805 count++; 3806 ASSERT(tp->t_id != (timeout_id_t)0); 3807 if (untimeout(tp->t_id) < 0) { 3808 nonactive++; 3809 PR_TIMER("%s: bad %s untimeout (domain=%d)\n", 3810 proc, str, tp->t_domid); 3811 } else { 3812 PR_TIMER("%s: good %s untimeout (domain=%d)\n", 3813 proc, str, tp->t_domid); 3814 } 3815 /* 3816 * There are two possible outcomes from 3817 * the untimeout(). Each ultimately result 3818 * in us having to free the timeout structure. 3819 * 3820 * 1. We successfully aborted a timeout call. 3821 * 3822 * 2. We failed to find the given timer. He 3823 * probably just fired off. 3824 */ 3825 idn_timer_free(tp); 3826 } 3827 PR_TIMER("%s: stopped %d of %d %s timers\n", 3828 proc, count - nonactive, count, str); 3829 3830 return (count); 3831 } 3832 3833 void 3834 idn_timer_dequeue(idn_timerq_t *tq, idn_timer_t *tp) 3835 { 3836 ASSERT(tq && tp); 3837 ASSERT(IDN_TIMERQ_IS_LOCKED(tq)); 3838 3839 ASSERT(tp->t_q == tq); 3840 3841 if (tp->t_onq == 0) { 3842 /* 3843 * We've already been dequeued. 3844 */ 3845 ASSERT(tp == tp->t_forw); 3846 ASSERT(tp == tp->t_back); 3847 } else { 3848 /* 3849 * We're still in the queue, get out. 3850 */ 3851 if (tq->tq_queue == tp) 3852 tq->tq_queue = tp->t_forw; 3853 tp->t_forw->t_back = tp->t_back; 3854 tp->t_back->t_forw = tp->t_forw; 3855 tp->t_onq = 0; 3856 if (--(tq->tq_count) == 0) { 3857 ASSERT(tq->tq_queue == tp); 3858 tq->tq_queue = NULL; 3859 } 3860 tp->t_forw = tp->t_back = tp; 3861 } 3862 } 3863 3864 /* 3865 * ----------------------------------------------------------------------- 3866 */ 3867 /*ARGSUSED*/ 3868 static int 3869 idn_slabpool_report(queue_t *wq, mblk_t *mp, caddr_t cp, cred_t *cr) 3870 { 3871 register int p, nfree; 3872 char dsetstr[128]; 3873 3874 ASSERT(IDN_GLOCK_IS_HELD()); 3875 3876 if (idn.slabpool == NULL) { 3877 (void) mi_mpprintf(mp, 3878 "IDN slabpool not initialized (masterid = %d)", 3879 IDN_GET_MASTERID()); 3880 return (0); 3881 } 3882 3883 for (p = nfree = 0; p < idn.slabpool->npools; p++) 3884 nfree += idn.slabpool->pool[p].nfree; 3885 3886 (void) mi_mpprintf(mp, 3887 "IDN slabpool (ntotal_slabs = %d, nalloc = %d, " 3888 "npools = %d)", 3889 idn.slabpool->ntotslabs, 3890 idn.slabpool->ntotslabs - nfree, 3891 idn.slabpool->npools); 3892 3893 (void) mi_mpprintf(mp, "pool nslabs nfree domains"); 3894 3895 for (p = 0; p < idn.slabpool->npools; p++) { 3896 register int d, s; 3897 uint_t domset; 3898 3899 domset = 0; 3900 for (s = 0; s < idn.slabpool->pool[p].nslabs; s++) { 3901 short dd; 3902 3903 dd = idn.slabpool->pool[p].sarray[s].sl_domid; 3904 if (dd != (short)IDN_NIL_DOMID) 3905 DOMAINSET_ADD(domset, dd); 3906 } 3907 dsetstr[0] = '\0'; 3908 if (domset) { 3909 for (d = 0; d < MAX_DOMAINS; d++) { 3910 if (!DOMAIN_IN_SET(domset, d)) 3911 continue; 3912 3913 if (dsetstr[0] == '\0') 3914 (void) sprintf(dsetstr, "%d", d); 3915 else 3916 (void) sprintf(dsetstr, "%s %d", 3917 dsetstr, d); 3918 } 3919 } 3920 3921 if (p < 10) 3922 (void) mi_mpprintf(mp, " %d %d %d %s", 3923 p, idn.slabpool->pool[p].nslabs, 3924 idn.slabpool->pool[p].nfree, 3925 dsetstr); 3926 else 3927 (void) mi_mpprintf(mp, " %d %d %d %s", 3928 p, idn.slabpool->pool[p].nslabs, 3929 idn.slabpool->pool[p].nfree, 3930 dsetstr); 3931 } 3932 return (0); 3933 } 3934 3935 /*ARGSUSED*/ 3936 static int 3937 idn_buffer_report(queue_t *wq, mblk_t *mp, caddr_t cp, cred_t *cr) 3938 { 3939 smr_slab_t *sp; 3940 register int d, cnt; 3941 int bufcount[MAX_DOMAINS]; 3942 int spl; 3943 3944 ASSERT(IDN_GLOCK_IS_HELD()); 3945 3946 if (idn.localid == IDN_NIL_DOMID) { 3947 (void) mi_mpprintf(mp, "IDN not initialized (localid = %d)", 3948 idn.localid); 3949 return (0); 3950 } 3951 3952 (void) mi_mpprintf(mp, "Local domain has %d slabs allocated.", 3953 idn_domain[idn.localid].dnslabs); 3954 3955 DSLAB_LOCK_SHARED(idn.localid); 3956 if ((sp = idn_domain[idn.localid].dslab) == NULL) { 3957 DSLAB_UNLOCK(idn.localid); 3958 return (0); 3959 } 3960 3961 bzero(bufcount, sizeof (bufcount)); 3962 cnt = 0; 3963 3964 spl = splhi(); 3965 for (; sp; sp = sp->sl_next) { 3966 smr_slabbuf_t *bp; 3967 3968 while (!lock_try(&sp->sl_lock)) 3969 ; 3970 for (bp = sp->sl_inuse; bp; bp = bp->sb_next) { 3971 bufcount[bp->sb_domid]++; 3972 cnt++; 3973 } 3974 lock_clear(&sp->sl_lock); 3975 } 3976 splx(spl); 3977 3978 DSLAB_UNLOCK(idn.localid); 3979 3980 (void) mi_mpprintf(mp, "Local domain has %d buffers outstanding.", cnt); 3981 if (cnt == 0) 3982 return (0); 3983 3984 (void) mi_mpprintf(mp, "Domain nbufs"); 3985 for (d = 0; d < MAX_DOMAINS; d++) 3986 if (bufcount[d]) { 3987 if (d < 10) 3988 (void) mi_mpprintf(mp, " %d %d", 3989 d, bufcount[d]); 3990 else 3991 (void) mi_mpprintf(mp, " %d %d", 3992 d, bufcount[d]); 3993 } 3994 3995 return (0); 3996 } 3997 3998 static const char * 3999 _get_spaces(int w, int s, int W) 4000 { 4001 static const char *const _spaces[] = { 4002 "", /* 0 */ 4003 " ", /* 1 */ 4004 " ", /* 2 */ 4005 " ", /* 3 */ 4006 " ", /* 4 */ 4007 " ", /* 5 */ 4008 " ", /* 6 */ 4009 " ", /* 7 */ 4010 " ", /* 8 */ 4011 " ", /* 9 */ 4012 " ", /* 10 */ 4013 " ", /* 11 */ 4014 " ", /* 12 */ 4015 " ", /* 13 */ 4016 " ", /* 14 */ 4017 " ", /* 15 */ 4018 " ", /* 16 */ 4019 " ", /* 17 */ 4020 " ", /* 18 */ 4021 " ", /* 19 */ 4022 }; 4023 return (_spaces[w+s-W]); 4024 } 4025 4026 #define _SSS(X, W, w, s) \ 4027 (((w) >= (W)) && (X)) ? _get_spaces((w), (s), (W)) 4028 4029 static const char * 4030 _hexspace(uint64_t v, int sz, int width, int padding) 4031 { 4032 int maxnbl = 16; 4033 int diff; 4034 uchar_t *np; 4035 4036 diff = sizeof (uint64_t) - sz; 4037 np = (uchar_t *)&v + diff; 4038 maxnbl -= diff << 1; 4039 while (sz-- > 0) { 4040 if ((*np & 0xf0) && (width >= maxnbl)) 4041 return (_get_spaces(width, padding, maxnbl)); 4042 maxnbl--; 4043 if ((*np & 0x0f) && (width >= maxnbl)) 4044 return (_get_spaces(width, padding, maxnbl)); 4045 maxnbl--; 4046 np++; 4047 } 4048 return (_get_spaces(width, padding, 1)); 4049 } 4050 4051 #define HEXSPACE(v, t, w, s) _hexspace((uint64_t)(v), sizeof (t), (w), (s)) 4052 4053 #define DECSPACE(n, w, s) \ 4054 (_SSS((uint_t)(n) >= 10000000, 8, (w), (s)) : \ 4055 _SSS((uint_t)(n) >= 1000000, 7, (w), (s)) : \ 4056 _SSS((uint_t)(n) >= 100000, 6, (w), (s)) : \ 4057 _SSS((uint_t)(n) >= 10000, 5, (w), (s)) : \ 4058 _SSS((uint_t)(n) >= 1000, 4, (w), (s)) : \ 4059 _SSS((uint_t)(n) >= 100, 3, (w), (s)) : \ 4060 _SSS((uint_t)(n) >= 10, 2, (w), (s)) : \ 4061 _get_spaces((w), (s), 1)) 4062 4063 #define DECSPACE16(n, w, s) \ 4064 (_SSS((n) >= 10000, 5, (w), (s)) : \ 4065 _SSS((n) >= 1000, 4, (w), (s)) : \ 4066 _SSS((n) >= 100, 3, (w), (s)) : \ 4067 _SSS((n) >= 10, 2, (w), (s)) : \ 4068 _get_spaces((w), (s), 1)) 4069 4070 #define MBXINFO(mtp) \ 4071 &mtp->mt_header, \ 4072 HEXSPACE(&mtp->mt_header, &mtp->mt_header, 16, 2), \ 4073 mtp->mt_header.mh_svr_ready_ptr, \ 4074 HEXSPACE(mtp->mt_header.mh_svr_ready_ptr, \ 4075 mtp->mt_header.mh_svr_ready_ptr, 8, 1), \ 4076 mtp->mt_header.mh_svr_active_ptr, \ 4077 HEXSPACE(mtp->mt_header.mh_svr_active_ptr, \ 4078 mtp->mt_header.mh_svr_active_ptr, 8, 2), \ 4079 *(ushort_t *)(IDN_OFFSET2ADDR(mtp->mt_header.mh_svr_ready_ptr)), \ 4080 DECSPACE16(*(ushort_t *) \ 4081 (IDN_OFFSET2ADDR(mtp->mt_header.mh_svr_ready_ptr)), \ 4082 1, 1), \ 4083 *(ushort_t *)(IDN_OFFSET2ADDR(mtp->mt_header.mh_svr_active_ptr)), \ 4084 DECSPACE16(*(ushort_t *) \ 4085 (IDN_OFFSET2ADDR(mtp->mt_header.mh_svr_active_ptr)), \ 4086 1, 5), \ 4087 mtp->mt_header.mh_cookie, \ 4088 HEXSPACE(mtp->mt_header.mh_cookie, \ 4089 mtp->mt_header.mh_cookie, 8, 2), \ 4090 &mtp->mt_queue[0], \ 4091 HEXSPACE(&mtp->mt_queue[0], &mtp->mt_queue[0], 16, 2) 4092 4093 /*ARGSUSED*/ 4094 static int 4095 idn_mboxtbl_report(queue_t *wq, mblk_t *mp, caddr_t cp, cred_t *cr) 4096 { 4097 register int c, n, domid, subdomid; 4098 register idn_mboxtbl_t *mtp; 4099 register idn_mboxmsg_t *msp; 4100 idn_mboxtbl_t *map, *mtbasep; 4101 4102 4103 ASSERT((cp == MBXTBL_PART_REPORT) || (cp == MBXTBL_FULL_REPORT)); 4104 4105 if (IDN_GLOCK_TRY_SHARED() == 0) { 4106 (void) mi_mpprintf(mp, "Local domain busy, try again."); 4107 return (0); 4108 } 4109 4110 if ((map = idn.mboxarea) == NULL) { 4111 (void) mi_mpprintf(mp, 4112 "WARNING: Local domain is not master, " 4113 "ASSUMING idn.smr.vaddr."); 4114 map = (idn_mboxtbl_t *)idn.smr.vaddr; 4115 } 4116 4117 if (map) { 4118 (void) mi_mpprintf(mp, "Mailbox Area starts @ 0x%p", 4119 map); 4120 } else { 4121 (void) mi_mpprintf(mp, "Mailbox Area not found."); 4122 goto repdone; 4123 } 4124 4125 if (!idn.nchannels) { 4126 (void) mi_mpprintf(mp, "No OPEN channels found"); 4127 goto repdone; 4128 } 4129 4130 for (c = 0; c < IDN_MAX_NETS; c++) { 4131 4132 IDN_CHAN_LOCK_GLOBAL(&idn.chan_servers[c]); 4133 if (!IDN_CHANNEL_IS_ATTACHED(&idn.chan_servers[c])) { 4134 IDN_CHAN_UNLOCK_GLOBAL(&idn.chan_servers[c]); 4135 continue; 4136 } 4137 4138 (void) mi_mpprintf(mp, 4139 "Channel %d ---------------------------" 4140 "--------------------------" 4141 "-----------------------------", c); 4142 (void) mi_mpprintf(mp, 4143 " Domain Header " 4144 "Ready/Active Ptrs " 4145 "rdy/actv cookie Queue " 4146 "busy"); 4147 4148 for (domid = 0; domid < MAX_DOMAINS; domid++) { 4149 register int busy_count; 4150 4151 if ((cp == MBXTBL_PART_REPORT) && 4152 (idn_domain[domid].dcpu == IDN_NIL_DCPU)) 4153 continue; 4154 4155 mtbasep = IDN_MBOXAREA_BASE(map, domid); 4156 4157 for (subdomid = 0; subdomid < MAX_DOMAINS; 4158 subdomid++) { 4159 mtp = IDN_MBOXTBL_PTR(mtbasep, subdomid); 4160 mtp = IDN_MBOXTBL_PTR_CHAN(mtp, c); 4161 4162 if (subdomid == domid) { 4163 if (subdomid == 0) 4164 (void) mi_mpprintf(mp, 4165 " %x.%x-%d%s%s", 4166 domid, subdomid, c, 4167 /*CONSTCOND*/ 4168 DECSPACE(c, 2, 2), 4169 "-- unused --"); 4170 else 4171 (void) mi_mpprintf(mp, 4172 " .%x-%d%s%s", 4173 subdomid, c, 4174 /*CONSTCOND*/ 4175 DECSPACE(c, 2, 2), 4176 "-- unused --"); 4177 continue; 4178 } 4179 busy_count = 0; 4180 msp = &mtp->mt_queue[0]; 4181 for (n = 0; n < IDN_MMBOX_NUMENTRIES; n++) { 4182 if (msp[n].ms_owner) 4183 busy_count++; 4184 } 4185 if (subdomid == 0) { 4186 (void) mi_mpprintf(mp, 4187 " %x.%x-%d%s%p%s%x%s/ %x%s" 4188 "%d%s/ %d%s%x%s%p%s%d%s", 4189 domid, subdomid, c, 4190 /*CONSTCOND*/ 4191 DECSPACE(c, 2, 2), 4192 MBXINFO(mtp), busy_count, 4193 busy_count ? " <<<<<":""); 4194 } else { 4195 (void) mi_mpprintf(mp, 4196 " .%x-%d%s%p%s%x%s/ %x%s" 4197 "%d%s/ %d%s%x%s%p%s%d%s", 4198 subdomid, c, 4199 /*CONSTCOND*/ 4200 DECSPACE(c, 2, 2), 4201 MBXINFO(mtp), busy_count, 4202 busy_count ? " <<<<<":""); 4203 } 4204 } 4205 } 4206 IDN_CHAN_UNLOCK_GLOBAL(&idn.chan_servers[c]); 4207 } 4208 4209 repdone: 4210 IDN_GUNLOCK(); 4211 4212 return (0); 4213 } 4214 4215 /*ARGSUSED*/ 4216 static void 4217 idn_mainmbox_domain_report(queue_t *wq, mblk_t *mp, int domid, 4218 idn_mainmbox_t *mmp, char *mbxtype) 4219 { 4220 register int c; 4221 4222 if (mmp == NULL) { 4223 (void) mi_mpprintf(mp, " %x.%s -- none --", domid, mbxtype); 4224 return; 4225 } 4226 4227 for (c = 0; c < IDN_MAX_NETS; mmp++, c++) { 4228 int mm_count; 4229 4230 IDN_CHAN_LOCK_GLOBAL(&idn.chan_servers[c]); 4231 if (IDN_CHANNEL_IS_DETACHED(&idn.chan_servers[c])) { 4232 (void) mi_mpprintf(mp, " %x.%s %u -- not open --", 4233 domid, mbxtype, (int)mmp->mm_channel); 4234 IDN_CHAN_UNLOCK_GLOBAL(&idn.chan_servers[c]); 4235 continue; 4236 } 4237 4238 mm_count = ((mmp->mm_count < 0) ? 0 : mmp->mm_count) / 1000; 4239 4240 (void) mi_mpprintf(mp, " %x.%s %d%s%d%s%d%s%p%s%p%s%p%s%d/%d", 4241 domid, mbxtype, 4242 (int)mmp->mm_channel, 4243 /*CONSTCOND*/ 4244 DECSPACE((int)mmp->mm_channel, 5, 2), 4245 mm_count, DECSPACE(mm_count, 8, 2), 4246 mmp->mm_dropped, 4247 DECSPACE(mmp->mm_dropped, 8, 2), 4248 mmp->mm_smr_mboxp, 4249 HEXSPACE(mmp->mm_smr_mboxp, 4250 mmp->mm_smr_mboxp, 16, 2), 4251 mmp->mm_smr_readyp, 4252 HEXSPACE(mmp->mm_smr_readyp, 4253 mmp->mm_smr_readyp, 16, 2), 4254 mmp->mm_smr_activep, 4255 HEXSPACE(mmp->mm_smr_activep, 4256 mmp->mm_smr_activep, 16, 2), 4257 mmp->mm_qiget, mmp->mm_qiput); 4258 IDN_CHAN_UNLOCK_GLOBAL(&idn.chan_servers[c]); 4259 } 4260 } 4261 4262 /*ARGSUSED2*/ 4263 static int 4264 idn_mainmbox_report(queue_t *wq, mblk_t *mp, caddr_t cp, cred_t *cr) 4265 { 4266 int domid; 4267 int header = 0; 4268 4269 /* 4270 * Domain 0 never has a send/recv mainmbox so 4271 * don't bother printing him. 4272 */ 4273 for (domid = 1; domid < MAX_DOMAINS; domid++) { 4274 idn_domain_t *dp; 4275 4276 dp = &idn_domain[domid]; 4277 4278 if (dp->dcpu == IDN_NIL_DCPU) 4279 continue; 4280 IDN_DLOCK_SHARED(domid); 4281 if (dp->dcpu == IDN_NIL_DCPU) { 4282 IDN_DUNLOCK(domid); 4283 continue; 4284 } 4285 if (!header) { 4286 (void) mi_mpprintf(mp, 4287 "Domain Chan PktCntK " 4288 "PktDrop SMRMbox " 4289 "ReadyPtr " 4290 "ActvPtr Miget/Miput"); 4291 header = 1; 4292 } 4293 4294 mutex_enter(&dp->dmbox.m_mutex); 4295 idn_mainmbox_domain_report(wq, mp, domid, 4296 idn_domain[domid].dmbox.m_send, 4297 "snd"); 4298 idn_mainmbox_domain_report(wq, mp, domid, 4299 idn_domain[domid].dmbox.m_recv, 4300 "rcv"); 4301 mutex_exit(&dp->dmbox.m_mutex); 4302 4303 IDN_DUNLOCK(domid); 4304 4305 (void) mi_mpprintf(mp, 4306 " ---------------------------------------" 4307 "------------------------" 4308 "----------------------------"); 4309 } 4310 4311 if (!header) 4312 (void) mi_mpprintf(mp, "No ACTIVE domain connections exist"); 4313 4314 return (0); 4315 } 4316 4317 /*ARGSUSED*/ 4318 static int 4319 idn_global_report(queue_t *wq, mblk_t *mp, caddr_t cp, cred_t *cr) 4320 { 4321 int i, nactive, masterid, nretry; 4322 uint_t locpfn_upper, locpfn_lower, 4323 rempfn_upper, rempfn_lower; 4324 uint_t marea_upper, marea_lower, 4325 iarea_upper, iarea_lower; 4326 char alt_dbuffer[64]; 4327 idn_retry_job_t *rp; 4328 domainset_t retryset; 4329 domainset_t connected; 4330 idn_synczone_t *zp; 4331 idn_syncop_t *sp; 4332 idn_domain_t *dp; 4333 char *dbp, *dbuffer; 4334 4335 if (IDN_SYNC_TRYLOCK() == 0) { 4336 (void) mi_mpprintf(mp, "Sync lock busy, try again."); 4337 return (0); 4338 } 4339 4340 if (IDN_GLOCK_TRY_SHARED() == 0) { 4341 (void) mi_mpprintf(mp, "Local domain busy, try again."); 4342 IDN_SYNC_UNLOCK(); 4343 return (0); 4344 } 4345 if ((dbp = dbuffer = ALLOC_DISPSTRING()) == NULL) 4346 dbp = alt_dbuffer; 4347 4348 (void) mi_mpprintf(mp, "IDN\n Global State = %s (%d)", 4349 idngs_str[idn.state], idn.state); 4350 4351 (void) mi_mpprintf(mp, "SMR"); 4352 (void) mi_mpprintf(mp, " vaddr "); 4353 (void) mi_mpprintf(mp, " 0x%p", idn.smr.vaddr); 4354 4355 (void) mi_mpprintf(mp, " paddr-local paddr-remote"); 4356 masterid = IDN_GET_MASTERID(); 4357 locpfn_upper = (uint_t)(idn.smr.locpfn >> (32 - PAGESHIFT)); 4358 locpfn_lower = (uint_t)(idn.smr.locpfn << PAGESHIFT); 4359 if (idn.smr.rempfn == PFN_INVALID) { 4360 rempfn_upper = rempfn_lower = 0; 4361 } else { 4362 rempfn_upper = (uint_t)(idn.smr.rempfn >> (32 - PAGESHIFT)); 4363 rempfn_lower = (uint_t)(idn.smr.rempfn << PAGESHIFT); 4364 } 4365 (void) mi_mpprintf(mp, " 0x%x.%x%s0x%x.%x", 4366 locpfn_upper, locpfn_lower, 4367 HEXSPACE(locpfn_lower, locpfn_lower, 8, 4368 (locpfn_upper < 0x10) ? 4 : 3), 4369 rempfn_upper, rempfn_lower); 4370 4371 (void) mi_mpprintf(mp, " SMR length = %d MBytes", IDN_SMR_SIZE); 4372 (void) mi_mpprintf(mp, " SMR bufsize = %d Bytes", IDN_SMR_BUFSIZE); 4373 (void) mi_mpprintf(mp, " NWR length = %d MBytes", IDN_NWR_SIZE); 4374 marea_upper = (uint_t)((uint64_t)IDN_MBOXAREA_SIZE >> 32); 4375 marea_lower = (uint_t)((uint64_t)IDN_MBOXAREA_SIZE & 0xffffffff); 4376 iarea_upper = (uint_t)((uint64_t)(MB2B(IDN_NWR_SIZE) - 4377 (size_t)IDN_MBOXAREA_SIZE) >> 32); 4378 iarea_lower = (uint_t)((MB2B(IDN_NWR_SIZE) - 4379 (size_t)IDN_MBOXAREA_SIZE) & 0xffffffff); 4380 (void) mi_mpprintf(mp, 4381 " [ mbox area = 0x%x.%x Bytes, " 4382 "iobuf area = 0x%x.%x Bytes ]", 4383 marea_upper, marea_lower, iarea_upper, iarea_lower); 4384 4385 (void) mi_mpprintf(mp, 4386 "\nIDNnet (local domain [id:%d] [name:%s] is %s)", 4387 idn.localid, 4388 idn_domain[idn.localid].dname, 4389 (masterid == IDN_NIL_DOMID) ? "IDLE" : 4390 (idn.localid == masterid) ? "MASTER" : 4391 "SLAVE"); 4392 nactive = 0; 4393 for (i = 0; i < IDN_MAX_NETS; i++) { 4394 IDN_CHAN_LOCK_GLOBAL(&idn.chan_servers[i]); 4395 if (IDN_CHANNEL_IS_ACTIVE(&idn.chan_servers[i])) 4396 nactive++; 4397 IDN_CHAN_UNLOCK_GLOBAL(&idn.chan_servers[i]); 4398 } 4399 (void) mi_mpprintf(mp, " I/O Networks: (Open = %d, " 4400 "Active = %d, Max = %d)", 4401 idn.nchannels, nactive, IDN_MAX_NETS); 4402 (void) mi_mpprintf(mp, " Number of Domains = %d", idn.ndomains); 4403 (void) mi_mpprintf(mp, " Number of AWOLs = %d", idn.nawols); 4404 /* 4405 * During connect domains can possibly be in ds_connected 4406 * while still in ds_trans_on. Only once they leave ds_trans_on 4407 * are they really connected. 4408 */ 4409 connected = idn.domset.ds_connected & ~idn.domset.ds_trans_on; 4410 DOMAINSET_ADD(connected, idn.localid); 4411 boardset2str(connected, dbp); 4412 (void) mi_mpprintf(mp, " Connected Domains = %s", dbp); 4413 domainset2str(idn.domset.ds_trans_on, dbp); 4414 (void) mi_mpprintf(mp, " Pending Domain Links = %s", 4415 idn.domset.ds_trans_on ? dbp : "<>"); 4416 domainset2str(idn.domset.ds_trans_off, dbp); 4417 (void) mi_mpprintf(mp, " Pending Domain Unlinks = %s", 4418 idn.domset.ds_trans_off ? dbp : "<>"); 4419 mutex_enter(&idn.retryqueue.rq_mutex); 4420 nretry = idn.retryqueue.rq_count; 4421 retryset = 0; 4422 for (i = 0, rp = idn.retryqueue.rq_jobs; i < nretry; i++, 4423 rp = rp->rj_next) { 4424 int domid; 4425 4426 domid = IDN_RETRY_TOKEN2DOMID(rp->rj_token); 4427 if (VALID_DOMAINID(domid)) { 4428 DOMAINSET_ADD(retryset, domid); 4429 } 4430 } 4431 mutex_exit(&idn.retryqueue.rq_mutex); 4432 domainset2str(retryset, dbp); 4433 (void) mi_mpprintf(mp, " Retry Jobs:Domains = %d:%s", 4434 nretry, retryset ? dbp : "<>"); 4435 domainset2str(idn.domset.ds_hitlist, dbp); 4436 (void) mi_mpprintf(mp, " Hitlist Domains = %s", 4437 idn.domset.ds_hitlist ? dbp : "<>"); 4438 domainset2str(idn.domset.ds_relink, dbp); 4439 (void) mi_mpprintf(mp, " Reconfig Domains = %s", 4440 idn.domset.ds_relink ? dbp : "<>"); 4441 if (idn.domset.ds_relink) 4442 (void) mi_mpprintf(mp, " new master id = %d", 4443 IDN_GET_NEW_MASTERID()); 4444 if (masterid == IDN_NIL_DOMID) { 4445 (void) mi_mpprintf(mp, " Master Domain: no master"); 4446 } else { 4447 idn_domain_t *mdp; 4448 4449 mdp = &idn_domain[masterid]; 4450 4451 (void) mi_mpprintf(mp, 4452 " Master Domain (id:name/brds - state):"); 4453 4454 if (strlen(mdp->dname) > 0) 4455 strcpy(dbp, mdp->dname); 4456 else 4457 boardset2str(mdp->dhw.dh_boardset, dbp); 4458 if (masterid < 10) 4459 (void) mi_mpprintf(mp, " %d: %s - %s", 4460 masterid, dbp, 4461 idnds_str[mdp->dstate]); 4462 else 4463 (void) mi_mpprintf(mp, " %d: %s - %s", 4464 masterid, dbp, 4465 idnds_str[mdp->dstate]); 4466 } 4467 if (idn.ndomains <= 1) { 4468 (void) mi_mpprintf(mp, " Slave Domains: none"); 4469 } else { 4470 int d; 4471 4472 (void) mi_mpprintf(mp, 4473 " Slave Domains (id:name/brds - state):"); 4474 for (d = 0; d < MAX_DOMAINS; d++) { 4475 dp = &idn_domain[d]; 4476 4477 if ((dp->dcpu == IDN_NIL_DCPU) || (d == masterid)) 4478 continue; 4479 4480 if (strlen(dp->dname) > 0) 4481 strcpy(dbp, dp->dname); 4482 else 4483 boardset2str(dp->dhw.dh_boardset, dbp); 4484 if (d < 10) 4485 (void) mi_mpprintf(mp, " %d: %s - %s", 4486 d, dbp, 4487 idnds_str[dp->dstate]); 4488 else 4489 (void) mi_mpprintf(mp, " %d: %s - %s", 4490 d, dbp, 4491 idnds_str[dp->dstate]); 4492 } 4493 } 4494 4495 if (idn.nawols == 0) { 4496 (void) mi_mpprintf(mp, " AWOL Domains: none"); 4497 } else { 4498 int d; 4499 4500 (void) mi_mpprintf(mp, " AWOL Domains (id:name/brds):"); 4501 for (d = 0; d < MAX_DOMAINS; d++) { 4502 dp = &idn_domain[d]; 4503 4504 if (!DOMAIN_IN_SET(idn.domset.ds_awol, d) || 4505 (dp->dcpu == IDN_NIL_DCPU)) 4506 continue; 4507 4508 if (strlen(dp->dname) > 0) 4509 strcpy(dbp, dp->dname); 4510 else 4511 boardset2str(dp->dhw.dh_boardset, dbp); 4512 if (d < 10) 4513 (void) mi_mpprintf(mp, " %d: %s", 4514 d, dbp); 4515 else 4516 (void) mi_mpprintf(mp, " %d: %s", 4517 d, dbp); 4518 } 4519 } 4520 4521 /*CONSTCOND*/ 4522 i = IDN_SYNC_GETZONE(IDNSYNC_CONNECT); 4523 zp = &idn.sync.sz_zone[i]; 4524 if (zp->sc_cnt == 0) { 4525 (void) mi_mpprintf(mp, " Sync Zone (con): [empty]"); 4526 } else { 4527 (void) mi_mpprintf(mp, " Sync Zone (con): [%d domains]", 4528 zp->sc_cnt); 4529 sp = zp->sc_op; 4530 for (i = 0; (i < zp->sc_cnt) && sp; i++) { 4531 (void) mi_mpprintf(mp, 4532 " " 4533 "%x: x_set =%s0x%x, r_set =%s0x%x", 4534 sp->s_domid, 4535 HEXSPACE(sp->s_set_exp, 4536 sp->s_set_exp, 4, 1), 4537 sp->s_set_exp, 4538 HEXSPACE(sp->s_set_rdy, 4539 sp->s_set_rdy, 4, 1), 4540 sp->s_set_rdy); 4541 sp = sp->s_next; 4542 } 4543 } 4544 /*CONSTCOND*/ 4545 i = IDN_SYNC_GETZONE(IDNSYNC_DISCONNECT); 4546 zp = &idn.sync.sz_zone[i]; 4547 if (zp->sc_cnt == 0) { 4548 (void) mi_mpprintf(mp, " Sync Zone (dis): [empty]"); 4549 } else { 4550 (void) mi_mpprintf(mp, " Sync Zone (dis): [%d domains]", 4551 zp->sc_cnt); 4552 sp = zp->sc_op; 4553 for (i = 0; (i < zp->sc_cnt) && sp; i++) { 4554 (void) mi_mpprintf(mp, 4555 " " 4556 "%x: x_set =%s0x%x, r_set =%s0x%x", 4557 sp->s_domid, 4558 HEXSPACE(sp->s_set_exp, 4559 sp->s_set_exp, 4, 1), 4560 sp->s_set_exp, 4561 HEXSPACE(sp->s_set_rdy, 4562 sp->s_set_rdy, 4, 1), 4563 sp->s_set_rdy); 4564 sp = sp->s_next; 4565 } 4566 } 4567 4568 IDN_GUNLOCK(); 4569 IDN_SYNC_UNLOCK(); 4570 4571 if (dbuffer) { 4572 FREE_DISPSTRING(dbuffer); 4573 } 4574 4575 return (0); 4576 } 4577 4578 /*ARGSUSED*/ 4579 static int 4580 idn_domain_report(queue_t *wq, mblk_t *mp, caddr_t cp, cred_t *cr) 4581 { 4582 int d, nchan; 4583 uint_t domset; 4584 idn_chanset_t chanset; 4585 idn_domain_t *dp; 4586 uint_t pset_upper, pset_lower; 4587 char *dbuffer, *dbp; 4588 char alt_dbuffer[64]; 4589 4590 4591 if (IDN_SYNC_TRYLOCK() == 0) { 4592 (void) mi_mpprintf(mp, "Sync lock busy, try again."); 4593 return (0); 4594 } 4595 4596 if (IDN_GLOCK_TRY_SHARED() == 0) { 4597 (void) mi_mpprintf(mp, "Local domain busy, try again."); 4598 IDN_SYNC_UNLOCK(); 4599 return (0); 4600 } 4601 4602 if ((dbp = dbuffer = ALLOC_DISPSTRING()) == NULL) 4603 dbp = alt_dbuffer; 4604 4605 if (cp == NULL) 4606 domset = DOMAINSET(idn.localid); 4607 else 4608 domset = DOMAINSET_ALL; 4609 4610 for (d = 0; d < MAX_DOMAINS; d++) { 4611 4612 if (DOMAIN_IN_SET(domset, d) == 0) 4613 continue; 4614 4615 dp = &idn_domain[d]; 4616 4617 if (dp->dcpu == IDN_NIL_DCPU) 4618 continue; 4619 4620 if (IDN_DLOCK_TRY_SHARED(d) == 0) { 4621 if (d < 10) 4622 (void) mi_mpprintf(mp, 4623 "Domain %d (0x%p) busy...", 4624 d, dp); 4625 else 4626 (void) mi_mpprintf(mp, 4627 "Domain %d (0x%p) busy...", 4628 d, dp); 4629 continue; 4630 } 4631 if (dp->dcpu == IDN_NIL_DCPU) { 4632 IDN_DUNLOCK(d); 4633 continue; 4634 } 4635 if (d < 10) 4636 (void) mi_mpprintf(mp, "%sDomain %d (0x%p)", 4637 (d && (idn.ndomains > 1)) ? "\n" : "", 4638 d, dp); 4639 else 4640 (void) mi_mpprintf(mp, "%sDomain %d (0x%p)", 4641 (d && (idn.ndomains > 1)) ? "\n" : "", 4642 d, dp); 4643 4644 if (d == idn.localid) 4645 (void) mi_mpprintf(mp, " (local) State = %s (%d)", 4646 idnds_str[dp->dstate], dp->dstate); 4647 else 4648 (void) mi_mpprintf(mp, " State = %s (%d)", 4649 idnds_str[dp->dstate], dp->dstate); 4650 (void) mi_mpprintf(mp, " Name = %s, Netid = %d", 4651 (strlen(dp->dname) > 0) ? dp->dname : "<>", 4652 (int)dp->dnetid); 4653 4654 CHANSET_ZERO(chanset); 4655 nchan = idn_domain_is_registered(d, -1, &chanset); 4656 if (dbuffer) 4657 mask2str(chanset, dbp, 32); 4658 else 4659 (void) sprintf(dbp, "0x%x", chanset); 4660 (void) mi_mpprintf(mp, " Nchans = %d, Chanset = %s", 4661 nchan, nchan ? dbp : "<>"); 4662 pset_upper = UPPER32_CPUMASK(dp->dcpuset); 4663 pset_lower = LOWER32_CPUMASK(dp->dcpuset); 4664 if (dbuffer) 4665 boardset2str(dp->dhw.dh_boardset, dbp); 4666 else 4667 (void) sprintf(dbp, "0x%x", dp->dhw.dh_boardset); 4668 4669 (void) mi_mpprintf(mp, " Nboards = %d, Brdset = %s", 4670 dp->dhw.dh_nboards, 4671 dp->dhw.dh_nboards ? dbp : "<>"); 4672 (void) sprintf(dbp, "0x%x.%x", pset_upper, pset_lower); 4673 (void) mi_mpprintf(mp, " Ncpus = %d, Cpuset = %s", 4674 dp->dncpus, dp->dncpus ? dbp : "<>"); 4675 (void) mi_mpprintf(mp, " Nmcadr = %d", 4676 dp->dhw.dh_nmcadr); 4677 (void) mi_mpprintf(mp, 4678 " MsgTimer = %s (cnt = %d)", 4679 (dp->dtimerq.tq_count > 0) 4680 ? "active" : "idle", 4681 dp->dtimerq.tq_count); 4682 (void) mi_mpprintf(mp, " Dcpu = %d " 4683 "(lastcpu = %d, cpuindex = %d)", 4684 dp->dcpu, dp->dcpu_last, dp->dcpuindex); 4685 (void) mi_mpprintf(mp, " Dio = %d " 4686 "(ioerr = %d, iochk = %d, iowanted = %d)", 4687 dp->dio, dp->dioerr, dp->diocheck ? 1 : 0, 4688 dp->diowanted ? 1 : 0); 4689 if (dp->dsync.s_cmd == IDNSYNC_NIL) { 4690 (void) mi_mpprintf(mp, " Dsync = %s", 4691 idnsync_str[IDNSYNC_NIL]); 4692 } else { 4693 (void) mi_mpprintf(mp, 4694 " Dsync = %s " 4695 "(x_set = 0x%x, r_set = 0x%x)", 4696 idnsync_str[dp->dsync.s_cmd], 4697 (uint_t)dp->dsync.s_set_exp, 4698 (uint_t)dp->dsync.s_set_rdy); 4699 } 4700 (void) mi_mpprintf(mp, " Dvote = 0x%x", 4701 dp->dvote.ticket); 4702 (void) mi_mpprintf(mp, " Dfin = %s (Sync = %s)", 4703 idnfin_str[dp->dfin], 4704 (dp->dfin_sync == IDNFIN_SYNC_OFF) ? "OFF" : 4705 (dp->dfin_sync == IDNFIN_SYNC_YES) ? "YES" : 4706 "NO"); 4707 (void) mi_mpprintf(mp, " Dcookie_err = %s (cnt = %d)", 4708 dp->dcookie_err ? "YES" : "NO", 4709 dp->dcookie_errcnt); 4710 IDN_DUNLOCK(d); 4711 } 4712 4713 IDN_GUNLOCK(); 4714 4715 if (dbuffer) { 4716 FREE_DISPSTRING(dbuffer); 4717 } 4718 4719 IDN_SYNC_UNLOCK(); 4720 4721 return (0); 4722 } 4723 4724 #define SNOOP_ENTRIES 2048 /* power of 2 */ 4725 4726 struct snoop_buffer { 4727 /* 0 */ char io; 4728 /* 1 */ char board; 4729 /* 2 */ char trans[14]; 4730 4731 /* 10 */ uint_t xargs[4]; 4732 } *snoop_data, snoop_buffer[SNOOP_ENTRIES+1]; 4733 4734 4735 int snoop_index; 4736 kmutex_t snoop_mutex; 4737 static char _bd2hexascii[] = { 4738 '0', '1', '2', '3', '4', '5', '6', '7', 4739 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' 4740 }; 4741 4742 #define SNOOP_IDN(in, tr, bd, arg1, arg2, arg3, arg4) \ 4743 { \ 4744 if (idn_snoop) { \ 4745 mutex_enter(&snoop_mutex); \ 4746 if (snoop_data == NULL) { \ 4747 snoop_data = (struct snoop_buffer *) \ 4748 (((uint_t)snoop_buffer + 0xf) & ~0xf); \ 4749 } \ 4750 snoop_data[snoop_index].io = ((in) == 0) ? 'o' : 'i'; \ 4751 snoop_data[snoop_index].board = \ 4752 ((bd) == -1) ? 'X' : _bd2hexascii[bd]; \ 4753 (void) strncpy(snoop_data[snoop_index].trans, (tr), 14); \ 4754 snoop_data[snoop_index].xargs[0] = (arg1); \ 4755 snoop_data[snoop_index].xargs[1] = (arg2); \ 4756 snoop_data[snoop_index].xargs[2] = (arg3); \ 4757 snoop_data[snoop_index].xargs[3] = (arg4); \ 4758 snoop_index++; \ 4759 snoop_index &= SNOOP_ENTRIES - 1; \ 4760 mutex_exit(&snoop_mutex); \ 4761 } \ 4762 } 4763 4764 /* 4765 * Allocate the circular buffers to be used for 4766 * DMV interrupt processing. 4767 */ 4768 static int 4769 idn_init_handler() 4770 { 4771 int i, c; 4772 size_t len; 4773 idn_dmv_msg_t *basep, *ivp; 4774 uint32_t ivp_offset; 4775 procname_t proc = "idn_init_handler"; 4776 4777 if (idn.intr.dmv_data != NULL) { 4778 cmn_err(CE_WARN, 4779 "IDN: 130: IDN DMV handler already initialized"); 4780 return (-1); 4781 } 4782 4783 /* 4784 * This memory will be touched by the low-level 4785 * DMV trap handler for IDN. 4786 */ 4787 len = sizeof (idn_dmv_data_t); 4788 len = roundup(len, sizeof (uint64_t)); 4789 len += NCPU * idn_dmv_pending_max * sizeof (idn_dmv_msg_t); 4790 len = roundup(len, PAGESIZE); 4791 4792 PR_PROTO("%s: sizeof (idn_dmv_data_t) = %lu\n", 4793 proc, sizeof (idn_dmv_data_t)); 4794 PR_PROTO("%s: allocating %lu bytes for dmv data area\n", proc, len); 4795 4796 idn.intr.dmv_data_len = len; 4797 idn.intr.dmv_data = kmem_zalloc(len, KM_SLEEP); 4798 4799 PR_PROTO("%s: DMV data area = %p\n", proc, idn.intr.dmv_data); 4800 4801 idn_dmv_data = (idn_dmv_data_t *)idn.intr.dmv_data; 4802 basep = (idn_dmv_msg_t *)roundup((size_t)idn.intr.dmv_data + 4803 sizeof (idn_dmv_data_t), 4804 sizeof (uint64_t)); 4805 idn_dmv_data->idn_dmv_qbase = (uint64_t)basep; 4806 4807 ivp = basep; 4808 ivp_offset = 0; 4809 /* 4810 * The buffer queues are allocated per-cpu. 4811 */ 4812 for (c = 0, ivp = basep; c < NCPU; ivp++, c++) { 4813 idn_dmv_data->idn_dmv_cpu[c].idn_dmv_current = ivp_offset; 4814 idn_iv_queue[c] = ivp; 4815 ivp_offset += sizeof (idn_dmv_msg_t); 4816 for (i = 1; i < idn_dmv_pending_max; ivp++, i++) { 4817 ivp->iv_next = ivp_offset; 4818 ivp->iv_ready = 0; 4819 lock_set(&ivp->iv_ready); 4820 ivp_offset += sizeof (idn_dmv_msg_t); 4821 } 4822 ivp->iv_next = idn_dmv_data->idn_dmv_cpu[c].idn_dmv_current; 4823 ivp->iv_ready = 0; 4824 lock_set(&ivp->iv_ready); 4825 } 4826 4827 idn.intr.dmv_inum = STARFIRE_DMV_IDN_BASE; 4828 idn.intr.soft_inum = add_softintr((uint_t)idn_pil, idn_handler, 0, 4829 SOFTINT_ST); 4830 idn_dmv_data->idn_soft_inum = idn.intr.soft_inum; 4831 /* 4832 * Make sure everything is out there before 4833 * we effectively set it free for use. 4834 */ 4835 membar_stld_stst(); 4836 4837 if (dmv_add_intr(idn.intr.dmv_inum, idn_dmv_handler, 4838 (caddr_t)idn_dmv_data)) { 4839 idn_deinit_handler(); 4840 cmn_err(CE_WARN, "IDN: 132: failed to add IDN DMV handler"); 4841 return (-1); 4842 } 4843 4844 return (0); 4845 } 4846 4847 static void 4848 idn_deinit_handler() 4849 { 4850 if (idn.intr.dmv_data == NULL) 4851 return; 4852 4853 (void) dmv_rem_intr(idn.intr.dmv_inum); 4854 (void) rem_softintr(idn.intr.soft_inum); 4855 kmem_free(idn.intr.dmv_data, idn.intr.dmv_data_len); 4856 idn.intr.dmv_data = NULL; 4857 } 4858 4859 /* 4860 * High-level (soft interrupt) handler for DMV interrupts 4861 */ 4862 /*ARGSUSED0*/ 4863 static uint_t 4864 idn_handler(caddr_t unused, caddr_t unused2) 4865 { 4866 #ifdef DEBUG 4867 int count = 0; 4868 #endif /* DEBUG */ 4869 int cpuid = (int)CPU->cpu_id; 4870 ushort_t mtype, atype; 4871 idn_dmv_msg_t *xp, *xplimit; 4872 procname_t proc = "idn_handler"; 4873 4874 ASSERT(getpil() >= idn_pil); 4875 flush_windows(); 4876 4877 /* 4878 * Clear the synchronization flag to indicate that 4879 * processing has started. As long as idn_dmv_active 4880 * is non-zero, idn_dmv_handler will queue work without 4881 * initiating a soft interrupt. Since we clear it 4882 * first thing at most one pil-interrupt for IDN will 4883 * queue up behind the currently active one. We don't 4884 * want to clear this flag at the end because it leaves 4885 * a window where an interrupt could get lost (unless it's 4886 * pushed by a subsequent interrupt). The objective in 4887 * doing this is to prevent exhausting a cpu's intr_vec 4888 * structures with interrupts of the same pil level. 4889 */ 4890 lock_clear(&idn_dmv_data->idn_dmv_cpu[cpuid].idn_dmv_active); 4891 4892 xp = idn_iv_queue[cpuid]; 4893 xplimit = xp + idn_dmv_pending_max; 4894 xp += idn_intr_index[cpuid]; 4895 /* 4896 * As long as there's stuff that's READY in the 4897 * queue, keep processing. 4898 */ 4899 while (lock_try(&xp->iv_ready)) { 4900 4901 ASSERT(lock_try(&xp->iv_inuse) == 0); 4902 4903 mtype = (ushort_t)xp->iv_mtype; 4904 mtype &= IDNP_MSGTYPE_MASK | IDNP_ACKNACK_MASK; 4905 atype = (ushort_t)xp->iv_atype; 4906 4907 if (((int)xp->iv_ver == idn.version) && mtype) { 4908 idn_protojob_t *jp; 4909 #ifdef DEBUG 4910 STRING(mstr); 4911 STRING(astr); 4912 4913 INUM2STR(mtype, mstr); 4914 if ((mtype & IDNP_MSGTYPE_MASK) == 0) { 4915 INUM2STR(atype, astr); 4916 strcat(mstr, "/"); 4917 strcat(mstr, astr); 4918 } 4919 4920 count++; 4921 4922 PR_XDC("%s:%d:%d RECV: scpu = %d, msg = 0x%x(%s)\n", 4923 proc, (int)xp->iv_domid, count, 4924 (int)xp->iv_cpuid, mtype, mstr); 4925 PR_XDC("%s:%d:%d R-DATA: a0 = 0x%x, a1 = 0x%x\n", 4926 proc, (int)xp->iv_domid, count, 4927 xp->iv_xargs0, xp->iv_xargs1); 4928 PR_XDC("%s:%d:%d R-DATA: a2 = 0x%x, a3 = 0x%x\n", 4929 proc, (int)xp->iv_domid, count, 4930 xp->iv_xargs2, xp->iv_xargs3); 4931 #endif /* DEBUG */ 4932 4933 if (mtype == IDNP_DATA) { 4934 jp = NULL; 4935 /* 4936 * The only time we receive pure 4937 * data messages at this level is 4938 * to wake up the channel server. 4939 * Since this is often an urgent 4940 * request we'll do it from here 4941 * instead of waiting for a proto 4942 * server to do it. 4943 */ 4944 idn_signal_data_server((int)xp->iv_domid, 4945 (ushort_t)xp->iv_xargs0); 4946 } else { 4947 jp = idn_protojob_alloc(KM_NOSLEEP); 4948 /* 4949 * If the allocation fails, just drop 4950 * the message and get on with life. 4951 * If memory pressure is this great then 4952 * dropping this message is probably 4953 * the least of our worries! 4954 */ 4955 if (jp) { 4956 jp->j_msg.m_domid = (int)xp->iv_domid; 4957 jp->j_msg.m_cpuid = (int)xp->iv_cpuid; 4958 jp->j_msg.m_msgtype = mtype; 4959 jp->j_msg.m_acktype = atype; 4960 jp->j_msg.m_cookie = xp->iv_cookie; 4961 SET_XARGS(jp->j_msg.m_xargs, 4962 xp->iv_xargs0, xp->iv_xargs1, 4963 xp->iv_xargs2, xp->iv_xargs3); 4964 } 4965 4966 } 4967 membar_ldst_stst(); 4968 4969 lock_clear(&xp->iv_inuse); 4970 4971 if (jp) 4972 idn_protojob_submit(jp->j_msg.m_domid, jp); 4973 } else { 4974 membar_ldst_stst(); 4975 IDN_GKSTAT_INC(gk_dropped_intrs); 4976 lock_clear(&xp->iv_inuse); 4977 } 4978 4979 if (++xp == xplimit) 4980 xp = idn_iv_queue[cpuid]; 4981 } 4982 4983 idn_intr_index[cpuid] = xp - idn_iv_queue[cpuid]; 4984 4985 return (DDI_INTR_CLAIMED); 4986 } 4987 4988 void 4989 idn_awol_event_set(boardset_t boardset) 4990 { 4991 idnsb_event_t *sbp; 4992 procname_t proc = "idn_awol_event_set"; 4993 4994 ASSERT(IDN_GLOCK_IS_EXCL()); 4995 4996 mutex_enter(&idn.idnsb_mutex); 4997 sbp = idn.idnsb_eventp; 4998 if (sbp == NULL) { 4999 cmn_err(CE_WARN, "IDN: 133: sigblock event area missing"); 5000 cmn_err(CE_CONT, 5001 "IDN: 134: unable to mark boardset (0x%x) AWOL\n", 5002 boardset); 5003 mutex_exit(&idn.idnsb_mutex); 5004 return; 5005 } 5006 5007 if (boardset == 0) { 5008 PR_PROTO("%s: AWOL BOARDSET is 0, NO EVENT <<<<<<<<<<<<<<<\n", 5009 proc); 5010 mutex_exit(&idn.idnsb_mutex); 5011 return; 5012 } else { 5013 PR_PROTO("%s: MARKING BOARDSET (0x%x) AWOL\n", proc, boardset); 5014 } 5015 SSIEVENT_ADD(sbp, SSIEVENT_AWOL, boardset); 5016 mutex_exit(&idn.idnsb_mutex); 5017 } 5018 5019 void 5020 idn_awol_event_clear(boardset_t boardset) 5021 { 5022 idnsb_event_t *sbp; 5023 procname_t proc = "idn_awol_event_clear"; 5024 5025 ASSERT(IDN_GLOCK_IS_EXCL()); 5026 5027 mutex_enter(&idn.idnsb_mutex); 5028 sbp = idn.idnsb_eventp; 5029 if (sbp == NULL) { 5030 cmn_err(CE_WARN, "IDN: 133: sigblock event area missing"); 5031 cmn_err(CE_CONT, 5032 "IDN: 134: unable to mark boardset (0x%x) AWOL\n", 5033 boardset); 5034 mutex_exit(&idn.idnsb_mutex); 5035 return; 5036 } 5037 5038 if (boardset == 0) { 5039 PR_PROTO("%s: AWOL BOARDSET is 0, NO EVENT <<<<<<<<<<<<<<<\n", 5040 proc); 5041 mutex_exit(&idn.idnsb_mutex); 5042 return; 5043 } else { 5044 PR_PROTO("%s: CLEARING BOARDSET (0x%x) AWOL\n", proc, boardset); 5045 } 5046 SSIEVENT_DEL(sbp, SSIEVENT_AWOL, boardset); 5047 mutex_exit(&idn.idnsb_mutex); 5048 } 5049 5050 static void 5051 idn_gkstat_init() 5052 { 5053 struct kstat *ksp; 5054 struct idn_gkstat_named *sgkp; 5055 5056 #ifdef kstat 5057 if ((ksp = kstat_create(IDNNAME, ddi_get_instance(idn.dip), 5058 IDNNAME, "net", KSTAT_TYPE_NAMED, 5059 sizeof (struct idn_gkstat_named) / sizeof (kstat_named_t), 5060 KSTAT_FLAG_PERSISTENT)) == NULL) { 5061 #else 5062 if ((ksp = kstat_create(IDNNAME, ddi_get_instance(idn.dip), 5063 IDNNAME, "net", KSTAT_TYPE_NAMED, 5064 sizeof (struct idn_gkstat_named) / 5065 sizeof (kstat_named_t), 0)) == NULL) { 5066 #endif /* kstat */ 5067 cmn_err(CE_CONT, "IDN: 135: %s: %s\n", 5068 IDNNAME, "kstat_create failed"); 5069 return; 5070 } 5071 5072 idn.ksp = ksp; 5073 sgkp = (struct idn_gkstat_named *)(ksp->ks_data); 5074 kstat_named_init(&sgkp->sk_curtime, "curtime", 5075 KSTAT_DATA_ULONG); 5076 kstat_named_init(&sgkp->sk_reconfigs, "reconfigs", 5077 KSTAT_DATA_ULONG); 5078 kstat_named_init(&sgkp->sk_reconfig_last, "reconfig_last", 5079 KSTAT_DATA_ULONG); 5080 kstat_named_init(&sgkp->sk_reaps, "reaps", 5081 KSTAT_DATA_ULONG); 5082 kstat_named_init(&sgkp->sk_reap_last, "reap_last", 5083 KSTAT_DATA_ULONG); 5084 kstat_named_init(&sgkp->sk_links, "links", 5085 KSTAT_DATA_ULONG); 5086 kstat_named_init(&sgkp->sk_link_last, "link_last", 5087 KSTAT_DATA_ULONG); 5088 kstat_named_init(&sgkp->sk_unlinks, "unlinks", 5089 KSTAT_DATA_ULONG); 5090 kstat_named_init(&sgkp->sk_unlink_last, "unlink_last", 5091 KSTAT_DATA_ULONG); 5092 kstat_named_init(&sgkp->sk_buffail, "buf_fail", 5093 KSTAT_DATA_ULONG); 5094 kstat_named_init(&sgkp->sk_buffail_last, "buf_fail_last", 5095 KSTAT_DATA_ULONG); 5096 kstat_named_init(&sgkp->sk_slabfail, "slab_fail", 5097 KSTAT_DATA_ULONG); 5098 kstat_named_init(&sgkp->sk_slabfail_last, "slab_fail_last", 5099 KSTAT_DATA_ULONG); 5100 kstat_named_init(&sgkp->sk_slabfail_last, "slab_fail_last", 5101 KSTAT_DATA_ULONG); 5102 kstat_named_init(&sgkp->sk_reap_count, "reap_count", 5103 KSTAT_DATA_ULONG); 5104 kstat_named_init(&sgkp->sk_dropped_intrs, "dropped_intrs", 5105 KSTAT_DATA_ULONG); 5106 ksp->ks_update = idn_gkstat_update; 5107 ksp->ks_private = (void *)NULL; 5108 kstat_install(ksp); 5109 } 5110 5111 static void 5112 idn_gkstat_deinit() 5113 { 5114 if (idn.ksp) 5115 kstat_delete(idn.ksp); 5116 idn.ksp = NULL; 5117 } 5118 5119 static int 5120 idn_gkstat_update(kstat_t *ksp, int rw) 5121 { 5122 struct idn_gkstat_named *sgkp; 5123 5124 sgkp = (struct idn_gkstat_named *)ksp->ks_data; 5125 5126 if (rw == KSTAT_WRITE) { 5127 sg_kstat.gk_reconfigs = sgkp->sk_reconfigs.value.ul; 5128 sg_kstat.gk_reconfig_last = sgkp->sk_reconfig_last.value.ul; 5129 sg_kstat.gk_reaps = sgkp->sk_reaps.value.ul; 5130 sg_kstat.gk_reap_last = sgkp->sk_reap_last.value.ul; 5131 sg_kstat.gk_links = sgkp->sk_links.value.ul; 5132 sg_kstat.gk_link_last = sgkp->sk_link_last.value.ul; 5133 sg_kstat.gk_unlinks = sgkp->sk_unlinks.value.ul; 5134 sg_kstat.gk_unlink_last = sgkp->sk_unlink_last.value.ul; 5135 sg_kstat.gk_buffail = sgkp->sk_buffail.value.ul; 5136 sg_kstat.gk_buffail_last = sgkp->sk_buffail_last.value.ul; 5137 sg_kstat.gk_slabfail = sgkp->sk_slabfail.value.ul; 5138 sg_kstat.gk_slabfail_last = sgkp->sk_slabfail_last.value.ul; 5139 sg_kstat.gk_reap_count = sgkp->sk_reap_count.value.ul; 5140 sg_kstat.gk_dropped_intrs = sgkp->sk_dropped_intrs.value.ul; 5141 } else { 5142 sgkp->sk_curtime.value.ul = ddi_get_lbolt(); 5143 sgkp->sk_reconfigs.value.ul = sg_kstat.gk_reconfigs; 5144 sgkp->sk_reconfig_last.value.ul = sg_kstat.gk_reconfig_last; 5145 sgkp->sk_reaps.value.ul = sg_kstat.gk_reaps; 5146 sgkp->sk_reap_last.value.ul = sg_kstat.gk_reap_last; 5147 sgkp->sk_links.value.ul = sg_kstat.gk_links; 5148 sgkp->sk_link_last.value.ul = sg_kstat.gk_link_last; 5149 sgkp->sk_unlinks.value.ul = sg_kstat.gk_unlinks; 5150 sgkp->sk_unlink_last.value.ul = sg_kstat.gk_unlink_last; 5151 sgkp->sk_buffail.value.ul = sg_kstat.gk_buffail; 5152 sgkp->sk_buffail_last.value.ul = sg_kstat.gk_buffail_last; 5153 sgkp->sk_slabfail.value.ul = sg_kstat.gk_slabfail; 5154 sgkp->sk_slabfail_last.value.ul = sg_kstat.gk_slabfail_last; 5155 sgkp->sk_reap_count.value.ul = sg_kstat.gk_reap_count; 5156 sgkp->sk_dropped_intrs.value.ul = sg_kstat.gk_dropped_intrs; 5157 } 5158 5159 return (0); 5160 } 5161 5162 #ifdef DEBUG 5163 #define RW_HISTORY 100 5164 static uint_t rw_history[NCPU][RW_HISTORY]; 5165 static int rw_index[NCPU]; 5166 #endif /* DEBUG */ 5167 5168 static int 5169 idn_rw_mem(idnop_t *idnop) 5170 { 5171 uint_t lo_off, hi_off; 5172 int rw, blksize, num; 5173 int cpuid; 5174 register int n, idx; 5175 char *ibuf, *obuf; 5176 char *smraddr; 5177 struct seg *segp; 5178 ulong_t randx; 5179 kmutex_t slock; 5180 kcondvar_t scv; 5181 static int orig_gstate = IDNGS_IGNORE; 5182 extern struct seg ktextseg; 5183 5184 #define RANDOM_INIT() (randx = ddi_get_lbolt()) 5185 #define RANDOM(a, b) \ 5186 (((a) >= (b)) ? \ 5187 (a) : (((randx = randx * 1103515245L + 12345) % ((b)-(a))) + (a))) 5188 5189 RANDOM_INIT(); 5190 5191 lo_off = idnop->rwmem.lo_off; 5192 hi_off = idnop->rwmem.hi_off; 5193 blksize = idnop->rwmem.blksize; 5194 num = idnop->rwmem.num; 5195 rw = idnop->rwmem.rw; /* 0 = rd, 1 = wr, 2 = rd/wr */ 5196 5197 if (((hi_off > (uint_t)MB2B(IDN_SMR_SIZE)) || (lo_off >= hi_off) || 5198 (blksize <= 0) || (blksize > (hi_off - lo_off)) || (num <= 0)) && 5199 (idnop->rwmem.goawol == -1)) { 5200 return (EINVAL); 5201 } 5202 5203 if (idnop->rwmem.goawol && (orig_gstate == IDNGS_IGNORE)) { 5204 IDN_GLOCK_EXCL(); 5205 cmn_err(CE_WARN, "IDN: Local domain going into IGNORE MODE!!"); 5206 orig_gstate = idn.state; 5207 IDN_GSTATE_TRANSITION(IDNGS_IGNORE); 5208 IDN_GUNLOCK(); 5209 5210 } else if (!idnop->rwmem.goawol && (orig_gstate != IDNGS_IGNORE)) { 5211 IDN_GLOCK_EXCL(); 5212 cmn_err(CE_WARN, 5213 "IDN: Local domain restoring original state %s(%d)", 5214 idngs_str[orig_gstate], (int)orig_gstate); 5215 IDN_GSTATE_TRANSITION(orig_gstate); 5216 orig_gstate = IDNGS_IGNORE; 5217 IDN_GUNLOCK(); 5218 } 5219 /* 5220 * Just requested AWOL. 5221 */ 5222 if (num == 0) 5223 return (0); 5224 /* 5225 * Default READ only. 5226 */ 5227 ibuf = (char *)kmem_alloc(blksize, KM_SLEEP); 5228 if (rw == 1) { 5229 /* 5230 * WRITE only. 5231 */ 5232 obuf = ibuf; 5233 ibuf = NULL; 5234 } else if (rw == 2) { 5235 /* 5236 * READ/WRITE. 5237 */ 5238 obuf = (char *)kmem_alloc(blksize, KM_SLEEP); 5239 for (segp = &ktextseg; segp; segp = AS_SEGNEXT(&kas, segp)) { 5240 if (segp->s_size >= blksize) 5241 break; 5242 } 5243 if (segp == NULL) { 5244 cmn_err(CE_WARN, 5245 "IDN: blksize (%d) too large", blksize); 5246 return (EINVAL); 5247 } 5248 bcopy(segp->s_base, obuf, blksize); 5249 } 5250 5251 mutex_init(&slock, NULL, MUTEX_DEFAULT, NULL); 5252 cv_init(&scv, NULL, CV_DEFAULT, NULL); 5253 5254 cmn_err(CE_NOTE, 5255 "IDN: starting %s of %d blocks of %d bytes each...", 5256 (rw == 1) ? "W-ONLY" : (rw == 2) ? "RW" : "R-ONLY", 5257 num, blksize); 5258 5259 for (n = 0; n < num; n++) { 5260 uint_t rpos; 5261 5262 if ((hi_off - lo_off) > blksize) 5263 rpos = RANDOM(lo_off, (hi_off - blksize)); 5264 else 5265 rpos = lo_off; 5266 smraddr = IDN_OFFSET2ADDR(rpos); 5267 5268 cpuid = (int)CPU->cpu_id; 5269 #ifdef DEBUG 5270 idx = rw_index[cpuid]++ % RW_HISTORY; 5271 rw_history[cpuid][idx] = rpos; 5272 #endif /* DEBUG */ 5273 5274 switch (rw) { 5275 case 0: 5276 bcopy(smraddr, ibuf, blksize); 5277 break; 5278 case 1: 5279 bcopy(obuf, smraddr, blksize); 5280 break; 5281 case 2: 5282 if (n & 1) 5283 bcopy(obuf, smraddr, blksize); 5284 else 5285 bcopy(smraddr, ibuf, blksize); 5286 break; 5287 default: 5288 break; 5289 } 5290 if (!(n % 1000)) { 5291 int rv; 5292 5293 mutex_enter(&slock); 5294 rv = cv_reltimedwait_sig(&scv, &slock, hz, 5295 TR_CLOCK_TICK); 5296 mutex_exit(&slock); 5297 if (rv == 0) 5298 break; 5299 } 5300 } 5301 5302 cv_destroy(&scv); 5303 mutex_destroy(&slock); 5304 5305 if (ibuf) 5306 kmem_free(ibuf, blksize); 5307 if (obuf) 5308 kmem_free(obuf, blksize); 5309 5310 return (0); 5311 } 5312 5313 void 5314 inum2str(uint_t inum, char str[]) 5315 { 5316 uint_t acknack; 5317 5318 str[0] = '\0'; 5319 5320 acknack = (inum & IDNP_ACKNACK_MASK); 5321 inum &= ~IDNP_ACKNACK_MASK; 5322 5323 if (!inum && !acknack) { 5324 strcpy(str, idnm_str[0]); 5325 return; 5326 } 5327 5328 if (inum == 0) { 5329 strcpy(str, (acknack & IDNP_ACK) ? "ack" : "nack"); 5330 } else { 5331 if (inum < IDN_NUM_MSGTYPES) 5332 strcpy(str, idnm_str[inum]); 5333 else 5334 sprintf(str, "0x%x?", inum); 5335 if (acknack) { 5336 if (acknack & IDNP_ACK) 5337 strcat(str, "+ack"); 5338 else 5339 strcat(str, "+nack"); 5340 } 5341 } 5342 } 5343 5344 boardset_t 5345 cpuset2boardset(cpuset_t portset) 5346 { 5347 register int c; 5348 register boardset_t bset; 5349 5350 bset = 0; 5351 for (c = 0; c < NCPU; ) 5352 if (CPU_IN_SET(portset, c)) { 5353 BOARDSET_ADD(bset, CPUID_TO_BOARDID(c)); 5354 c = (c + 4) & ~3; 5355 } else { 5356 c++; 5357 } 5358 5359 return (bset); 5360 } 5361 5362 void 5363 cpuset2str(cpuset_t cset, char buffer[]) 5364 { 5365 register int c, n; 5366 5367 buffer[0] = '\0'; 5368 for (c = n = 0; c < NCPU; c++) { 5369 if (!CPU_IN_SET(cset, c)) 5370 continue; 5371 #ifdef DEBUG 5372 if (strlen(buffer) >= _DSTRLEN) { 5373 PR_PROTO("************* WARNING WARNING WARNING\n"); 5374 PR_PROTO("cpuset2str(cpu = %d) buffer " 5375 "OVERFLOW <<<<<<\n", c); 5376 PR_PROTO("*******************************\n"); 5377 (void) sprintf(&buffer[_DSTRLEN-6], "*OVER"); 5378 return; 5379 } 5380 #endif /* DEBUG */ 5381 if (n == 0) 5382 (void) sprintf(buffer, "%d", c); 5383 else 5384 (void) sprintf(buffer, "%s, %d", buffer, c); 5385 n++; 5386 } 5387 } 5388 5389 void 5390 domainset2str(domainset_t dset, char buffer[]) 5391 { 5392 /* 5393 * Since domainset_t and boardset_t are the 5394 * same (max = MAX_DOMAINS = MAX_BOARDS) we 5395 * can just overload boardset2str(). 5396 */ 5397 mask2str((uint_t)dset, buffer, MAX_DOMAINS); 5398 } 5399 5400 void 5401 boardset2str(boardset_t bset, char buffer[]) 5402 { 5403 mask2str((uint_t)bset, buffer, MAX_BOARDS); 5404 } 5405 5406 void 5407 mask2str(uint_t mask, char buffer[], int maxnum) 5408 { 5409 int n, i; 5410 5411 buffer[0] = '\0'; 5412 for (i = n = 0; i < maxnum; i++) { 5413 if ((mask & (1 << i)) == 0) 5414 continue; 5415 if (n == 0) 5416 (void) sprintf(buffer, "%d", i); 5417 else 5418 (void) sprintf(buffer, "%s, %d", buffer, i); 5419 n++; 5420 } 5421 } 5422 5423 int 5424 idnxdc(int domid, idn_msgtype_t *mtp, 5425 uint_t arg1, uint_t arg2, 5426 uint_t arg3, uint_t arg4) 5427 { 5428 int rv, cpuid, tcpuid; 5429 uint_t cookie; 5430 uint64_t pdata; 5431 uint64_t dmv_word0, dmv_word1, dmv_word2; 5432 idn_domain_t *dp = &idn_domain[domid]; 5433 extern kmutex_t xc_sys_mutex; 5434 extern int xc_spl_enter[]; 5435 procname_t proc = "idnxdc"; 5436 5437 5438 if (idn_snoop) { 5439 int bd; 5440 STRING(str); 5441 STRING(mstr); 5442 STRING(astr); 5443 5444 INUM2STR(mtp->mt_mtype, mstr); 5445 if ((mtp->mt_mtype & IDNP_MSGTYPE_MASK) == 0) { 5446 INUM2STR(arg1, astr); 5447 sprintf(str, "%s/%s", mstr, astr); 5448 } else { 5449 strcpy(str, mstr); 5450 } 5451 if (dp->dcpu == IDN_NIL_DCPU) 5452 bd = -1; 5453 else 5454 bd = CPUID_TO_BOARDID(dp->dcpu); 5455 SNOOP_IDN(0, str, bd, arg1, arg2, arg3, arg4); 5456 } 5457 5458 /* 5459 * For NEGO messages we send the remote domain the cookie we 5460 * expect it to use in subsequent messages that it sends 5461 * to us (dcookie_recv). 5462 * For other messages, we must use the cookie that the 5463 * remote domain assigned to us for sending (dcookie_send). 5464 */ 5465 if ((mtp->mt_mtype & IDNP_MSGTYPE_MASK) == IDNP_NEGO) 5466 cookie = IDN_MAKE_COOKIE(dp->dcookie_recv, mtp->mt_cookie); 5467 else 5468 cookie = IDN_MAKE_COOKIE(dp->dcookie_send, mtp->mt_cookie); 5469 5470 pdata = IDN_MAKE_PDATA(mtp->mt_mtype, mtp->mt_atype, cookie); 5471 5472 dmv_word0 = DMV_MAKE_DMV(idn.intr.dmv_inum, pdata); 5473 dmv_word1 = ((uint64_t)arg1 << 32) | (uint64_t)arg2; 5474 dmv_word2 = ((uint64_t)arg3 << 32) | (uint64_t)arg4; 5475 5476 ASSERT((dp->dcpu != IDN_NIL_DCPU) || 5477 (dp->dcpu_last != IDN_NIL_DCPU)); 5478 5479 tcpuid = (dp->dcpu == IDN_NIL_DCPU) ? 5480 dp->dcpu_last : dp->dcpu; 5481 5482 if (tcpuid == IDN_NIL_DCPU) { 5483 PR_PROTO("%s:%d: cpu/cpu_last == NIL_DCPU\n", 5484 proc, domid); 5485 return (-1); 5486 } 5487 5488 mutex_enter(&xc_sys_mutex); 5489 cpuid = (int)CPU->cpu_id; 5490 xc_spl_enter[cpuid] = 1; 5491 5492 idnxf_init_mondo(dmv_word0, dmv_word1, dmv_word2); 5493 5494 rv = idnxf_send_mondo(STARFIRE_UPAID2HWMID(tcpuid)); 5495 5496 xc_spl_enter[cpuid] = 0; 5497 mutex_exit(&xc_sys_mutex); 5498 5499 return (rv); 5500 } 5501 5502 void 5503 idnxdc_broadcast(domainset_t domset, idn_msgtype_t *mtp, 5504 uint_t arg1, uint_t arg2, 5505 uint_t arg3, uint_t arg4) 5506 { 5507 int d; 5508 5509 for (d = 0; d < MAX_DOMAINS; d++) { 5510 idn_domain_t *dp; 5511 5512 if (!DOMAIN_IN_SET(domset, d)) 5513 continue; 5514 5515 dp = &idn_domain[d]; 5516 if (dp->dcpu == IDN_NIL_DCPU) 5517 continue; 5518 5519 (void) IDNXDC(d, mtp, arg1, arg2, arg3, arg4); 5520 } 5521 } 5522 5523 #define PROM_SMRSIZE 0x1 5524 #define PROM_SMRADDR 0x2 5525 #define PROM_SMRPROPS (PROM_SMRSIZE | PROM_SMRADDR) 5526 /* 5527 * Locate the idn-smr-size property to determine the size of the SMR 5528 * region for the SSI. Value inherently enables/disables SSI capability. 5529 */ 5530 static int 5531 idn_prom_getsmr(uint_t *smrsz, uint64_t *paddrp, uint64_t *sizep) 5532 { 5533 pnode_t nodeid; 5534 int found = 0; 5535 int len; 5536 uint_t smrsize = 0; 5537 uint64_t obpaddr, obpsize; 5538 struct smraddr { 5539 uint32_t hi_addr; 5540 uint32_t lo_addr; 5541 uint32_t hi_size; 5542 uint32_t lo_size; 5543 } smraddr; 5544 procname_t proc = "idn_prom_getsmr"; 5545 5546 bzero(&smraddr, sizeof (smraddr)); 5547 /* 5548 * idn-smr-size is a property of the "memory" node and 5549 * is defined in megabytes. 5550 */ 5551 nodeid = prom_finddevice("/memory"); 5552 5553 if (nodeid != OBP_NONODE) { 5554 len = prom_getproplen(nodeid, IDN_PROP_SMRSIZE); 5555 if (len == sizeof (smrsize)) { 5556 (void) prom_getprop(nodeid, IDN_PROP_SMRSIZE, 5557 (caddr_t)&smrsize); 5558 found |= PROM_SMRSIZE; 5559 } 5560 len = prom_getproplen(nodeid, IDN_PROP_SMRADDR); 5561 if (len == sizeof (smraddr)) { 5562 (void) prom_getprop(nodeid, IDN_PROP_SMRADDR, 5563 (caddr_t)&smraddr); 5564 found |= PROM_SMRADDR; 5565 } 5566 } 5567 5568 if (found != PROM_SMRPROPS) { 5569 if ((found & PROM_SMRSIZE) == 0) 5570 cmn_err(CE_WARN, 5571 "IDN: 136: \"%s\" property not found, " 5572 "disabling IDN", 5573 IDN_PROP_SMRSIZE); 5574 if (smrsize && ((found & PROM_SMRADDR) == 0)) 5575 cmn_err(CE_WARN, 5576 "IDN: 136: \"%s\" property not found, " 5577 "disabling IDN", 5578 IDN_PROP_SMRADDR); 5579 return (-1); 5580 } 5581 5582 if (smrsize == 0) { 5583 PR_SMR("%s: IDN DISABLED (idn_smr_size = 0)\n", proc); 5584 cmn_err(CE_NOTE, "!IDN: 137: SMR size is 0, disabling IDN"); 5585 5586 } else if (smrsize > IDN_SMR_MAXSIZE) { 5587 PR_SMR("%s: IDN DISABLED (idn_smr_size too big %d > %d MB)\n", 5588 proc, smrsize, IDN_SMR_MAXSIZE); 5589 cmn_err(CE_WARN, 5590 "!IDN: 138: SMR size (%dMB) is too big (max = %dMB), " 5591 "disabling IDN", 5592 smrsize, IDN_SMR_MAXSIZE); 5593 smrsize = 0; 5594 } else { 5595 *smrsz = smrsize; 5596 found &= ~PROM_SMRSIZE; 5597 } 5598 5599 obpaddr = ((uint64_t)smraddr.hi_addr << 32) | 5600 (uint64_t)smraddr.lo_addr; 5601 obpsize = ((uint64_t)smraddr.hi_size << 32) | 5602 (uint64_t)smraddr.lo_size; 5603 5604 if (obpsize == 0) { 5605 if (smrsize > 0) { 5606 cmn_err(CE_WARN, "!IDN: 139: OBP region for " 5607 "SMR is 0 length"); 5608 } 5609 } else if (obpsize < (uint64_t)MB2B(smrsize)) { 5610 cmn_err(CE_WARN, 5611 "!IDN: 140: OBP region (%ld B) smaller " 5612 "than requested size (%ld B)", 5613 obpsize, MB2B(smrsize)); 5614 } else if ((obpaddr & ((uint64_t)IDN_SMR_ALIGN - 1)) != 0) { 5615 cmn_err(CE_WARN, 5616 "!IDN: 141: OBP region (0x%lx) not on (0x%x) " 5617 "boundary", obpaddr, IDN_SMR_ALIGN); 5618 } else { 5619 *sizep = obpsize; 5620 *paddrp = obpaddr; 5621 found &= ~PROM_SMRADDR; 5622 } 5623 5624 return (found ? -1 : 0); 5625 } 5626 5627 void 5628 idn_init_autolink() 5629 { 5630 idnsb_event_t *sbp; 5631 procname_t proc = "idn_init_autolink"; 5632 5633 mutex_enter(&idn.idnsb_mutex); 5634 if ((sbp = idn.idnsb_eventp) == NULL) { 5635 PR_PROTO("%s: IDN private sigb (event) area is NULL\n", proc); 5636 mutex_exit(&idn.idnsb_mutex); 5637 return; 5638 } 5639 5640 PR_PROTO("%s: marking domain IDN ready.\n", proc); 5641 5642 bzero(sbp, sizeof (*sbp)); 5643 5644 sbp->idn_version = (uchar_t)idn.version; 5645 SSIEVENT_SET(sbp, SSIEVENT_BOOT, 0); 5646 (void) strncpy(sbp->idn_cookie_str, SSIEVENT_COOKIE, 5647 SSIEVENT_COOKIE_LEN); 5648 mutex_exit(&idn.idnsb_mutex); 5649 } 5650 5651 void 5652 idn_deinit_autolink() 5653 { 5654 idnsb_event_t *sbp; 5655 procname_t proc = "idn_deinit_autolink"; 5656 5657 mutex_enter(&idn.idnsb_mutex); 5658 if ((sbp = idn.idnsb_eventp) == NULL) { 5659 PR_PROTO("%s: IDN private sigb (event) area is NULL\n", proc); 5660 mutex_exit(&idn.idnsb_mutex); 5661 return; 5662 } 5663 5664 PR_PROTO("%s: marking domain IDN unavailable.\n", proc); 5665 5666 sbp->idn_version = (uchar_t)idn.version; 5667 SSIEVENT_CLEAR(sbp, SSIEVENT_BOOT, 0); 5668 (void) strncpy(sbp->idn_cookie_str, SSIEVENT_COOKIE, 5669 SSIEVENT_COOKIE_LEN); 5670 mutex_exit(&idn.idnsb_mutex); 5671 } 5672 5673 void 5674 _make64cpumask(cpuset_t *csetp, uint_t upper, uint_t lower) 5675 { 5676 int c; 5677 5678 CPUSET_ZERO(*csetp); 5679 5680 for (c = 0; c < 32; c++) { 5681 if (lower & (1 << c)) { 5682 CPUSET_ADD(*csetp, c); 5683 } 5684 if (upper & (1 << (c + 32))) { 5685 CPUSET_ADD(*csetp, c + 32); 5686 } 5687 } 5688 } 5689 5690 uint_t 5691 _lower32cpumask(cpuset_t cset) 5692 { 5693 int c; 5694 uint_t set = 0; 5695 5696 for (c = 0; c < 32; c++) 5697 if (CPU_IN_SET(cset, c)) 5698 set |= 1 << c; 5699 5700 return (set); 5701 } 5702 5703 uint_t 5704 _upper32cpumask(cpuset_t cset) 5705 { 5706 int c; 5707 uint_t set = 0; 5708 5709 for (c = 32; c < NCPU; c++) 5710 if (CPU_IN_SET(cset, c)) 5711 set |= 1 << (c - 32); 5712 5713 return (set); 5714 } 5715 5716 #ifdef DEBUG 5717 int 5718 debug_idnxdc(char *f, int domid, idn_msgtype_t *mtp, 5719 uint_t a1, uint_t a2, uint_t a3, uint_t a4) 5720 { 5721 idn_domain_t *dp = &idn_domain[domid]; 5722 int rv, cpuid, bd; 5723 static int xx = 0; 5724 STRING(str); 5725 STRING(mstr); 5726 STRING(astr); 5727 5728 xx++; 5729 INUM2STR(mtp->mt_mtype, mstr); 5730 if ((mtp->mt_mtype & IDNP_MSGTYPE_MASK) == 0) { 5731 INUM2STR(a1, astr); 5732 sprintf(str, "%s/%s", mstr, astr); 5733 } else { 5734 strcpy(str, mstr); 5735 } 5736 5737 if ((cpuid = dp->dcpu) == IDN_NIL_DCPU) 5738 bd = -1; 5739 else 5740 bd = CPUID_TO_BOARDID(cpuid); 5741 5742 SNOOP_IDN(0, str, bd, a1, a2, a3, a4); 5743 5744 PR_XDC("%s:%d:%d SENT: scpu = %d, msg = 0x%x(%s)\n", 5745 f, domid, xx, cpuid, mtp->mt_mtype, str); 5746 PR_XDC("%s:%d:%d S-DATA: a1 = 0x%x, a2 = 0x%x\n", 5747 f, domid, xx, a1, a2); 5748 PR_XDC("%s:%d:%d S-DATA: a3 = 0x%x, a4 = 0x%x\n", 5749 f, domid, xx, a3, a4); 5750 5751 rv = idnxdc(domid, mtp, a1, a2, a3, a4); 5752 if (rv != 0) { 5753 PR_XDC("%s:%d:%d: WARNING: idnxdc(cpu %d) FAILED\n", 5754 f, domid, xx, cpuid); 5755 } 5756 5757 return (rv); 5758 } 5759 5760 caddr_t 5761 _idn_getstruct(char *structname, int size) 5762 { 5763 caddr_t ptr; 5764 procname_t proc = "GETSTRUCT"; 5765 5766 ptr = kmem_zalloc(size, KM_SLEEP); 5767 5768 PR_ALLOC("%s: ptr 0x%p, struct(%s), size = %d\n", 5769 proc, ptr, structname, size); 5770 5771 return (ptr); 5772 } 5773 5774 void 5775 _idn_freestruct(caddr_t ptr, char *structname, int size) 5776 { 5777 procname_t proc = "FREESTRUCT"; 5778 5779 PR_ALLOC("%s: ptr 0x%p, struct(%s), size = %d\n", 5780 proc, ptr, structname, size); 5781 5782 ASSERT(ptr != NULL); 5783 kmem_free(ptr, size); 5784 } 5785 #endif /* DEBUG */ 5786