1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * safari system board DR module. 31 */ 32 33 #include <sys/debug.h> 34 #include <sys/types.h> 35 #include <sys/errno.h> 36 #include <sys/cred.h> 37 #include <sys/dditypes.h> 38 #include <sys/devops.h> 39 #include <sys/modctl.h> 40 #include <sys/poll.h> 41 #include <sys/conf.h> 42 #include <sys/ddi.h> 43 #include <sys/sunddi.h> 44 #include <sys/sunndi.h> 45 #include <sys/ndi_impldefs.h> 46 #include <sys/stat.h> 47 #include <sys/kmem.h> 48 #include <sys/cpuvar.h> 49 #include <sys/mem_config.h> 50 #include <sys/mem_cage.h> 51 52 #include <sys/autoconf.h> 53 #include <sys/cmn_err.h> 54 55 #include <sys/ddi_impldefs.h> 56 #include <sys/machsystm.h> 57 #include <sys/param.h> 58 59 #include <sys/sbdpriv.h> 60 #include <sys/sbd_io.h> 61 62 /* start sbd includes */ 63 64 #include <sys/systm.h> 65 #include <sys/sysmacros.h> 66 #include <sys/x_call.h> 67 #include <sys/membar.h> 68 #include <vm/seg_kmem.h> 69 70 extern int nulldev(); 71 extern int nodev(); 72 73 typedef struct { /* arg to sbd_get_handle */ 74 dev_t dev; 75 int cmd; 76 int mode; 77 sbd_ioctl_arg_t *ioargp; 78 } sbd_init_arg_t; 79 80 81 /* 82 * sbd support operations. 83 */ 84 static void sbd_exec_op(sbd_handle_t *hp); 85 static void sbd_dev_configure(sbd_handle_t *hp); 86 static int sbd_dev_release(sbd_handle_t *hp); 87 static int sbd_dev_unconfigure(sbd_handle_t *hp); 88 static void sbd_attach_cpu(sbd_handle_t *hp, sbderror_t *ep, 89 dev_info_t *dip, int unit); 90 static void sbd_detach_cpu(sbd_handle_t *hp, sbderror_t *ep, 91 dev_info_t *dip, int unit); 92 static int sbd_detach_mem(sbd_handle_t *hp, sbderror_t *ep, int unit); 93 static void sbd_cancel(sbd_handle_t *hp); 94 void sbd_errno_decode(int err, sbderror_t *ep, dev_info_t *dip); 95 int sbd_dealloc_instance(sbd_board_t *sbp, int max_boards); 96 int sbd_errno2ecode(int error); 97 #pragma weak sbdp_cpu_get_impl 98 99 #ifdef DEBUG 100 uint_t sbd_debug = (uint_t)0x0; 101 102 #ifdef SBD_DEBUG_ERRS 103 /* controls which errors are injected */ 104 uint_t sbd_err_debug = (uint_t)0x0; 105 106 /* controls printing about error injection */ 107 uint_t sbd_print_errs = (uint_t)0x0; 108 109 #endif /* SBD_DEBUG_ERRS */ 110 111 #endif /* DEBUG */ 112 113 char *sbd_state_str[] = { 114 "EMPTY", "OCCUPIED", "CONNECTED", "UNCONFIGURED", 115 "PARTIAL", "CONFIGURED", "RELEASE", "UNREFERENCED", 116 "FATAL" 117 }; 118 119 /* Note: this must be changed in tandem with sbd_ioctl.h */ 120 char *sbd_ct_str[] = { 121 "NONE", "CPU", "MEM", "IO", "UNKNOWN" 122 }; 123 124 /* Note: this must also be changed in tandem with sbd_ioctl.h */ 125 #define SBD_CMD_STR(c) \ 126 (((c) == SBD_CMD_ASSIGN) ? "ASSIGN" : \ 127 ((c) == SBD_CMD_UNASSIGN) ? "UNASSIGN" : \ 128 ((c) == SBD_CMD_POWERON) ? "POWERON" : \ 129 ((c) == SBD_CMD_POWEROFF) ? "POWEROFF" : \ 130 ((c) == SBD_CMD_TEST) ? "TEST" : \ 131 ((c) == SBD_CMD_CONNECT) ? "CONNECT" : \ 132 ((c) == SBD_CMD_CONFIGURE) ? "CONFIGURE" : \ 133 ((c) == SBD_CMD_UNCONFIGURE) ? "UNCONFIGURE" : \ 134 ((c) == SBD_CMD_DISCONNECT) ? "DISCONNECT" : \ 135 ((c) == SBD_CMD_STATUS) ? "STATUS" : \ 136 ((c) == SBD_CMD_GETNCM) ? "GETNCM" : \ 137 ((c) == SBD_CMD_PASSTHRU) ? "PASSTHRU" : "unknown") 138 139 /* 140 * Defines and structures for device tree naming and mapping 141 * to node types 142 */ 143 144 sbd_devattr_t *sbd_devattr; 145 146 /* defines to access the attribute struct */ 147 #define SBD_DEVNAME(i) sbd_devattr[i].s_devname 148 #define SBD_OTYPE(i) sbd_devattr[(i)].s_obp_type 149 #define SBD_COMP(i) sbd_devattr[i].s_dnodetype 150 151 /* 152 * State transition table. States valid transitions for "board" state. 153 * Recall that non-zero return value terminates operation, however 154 * the herrno value is what really indicates an error , if any. 155 */ 156 static int 157 _cmd2index(int c) 158 { 159 /* 160 * Translate DR CMD to index into sbd_state_transition. 161 */ 162 switch (c) { 163 case SBD_CMD_CONNECT: return (0); 164 case SBD_CMD_DISCONNECT: return (1); 165 case SBD_CMD_CONFIGURE: return (2); 166 case SBD_CMD_UNCONFIGURE: return (3); 167 case SBD_CMD_POWEROFF: return (4); 168 case SBD_CMD_POWERON: return (5); 169 case SBD_CMD_UNASSIGN: return (6); 170 case SBD_CMD_ASSIGN: return (7); 171 case SBD_CMD_TEST: return (8); 172 default: return (-1); 173 } 174 } 175 176 #define CMD2INDEX(c) _cmd2index(c) 177 178 static struct sbd_state_trans { 179 int x_cmd; 180 struct { 181 int x_rv; /* return value of pre_op */ 182 int x_err; /* errno, if any */ 183 } x_op[SBD_NUM_STATES]; 184 } sbd_state_transition[] = { 185 { SBD_CMD_CONNECT, 186 { 187 { 0, 0 }, /* empty */ 188 { 0, 0 }, /* occupied */ 189 { 1, EIO }, /* connected */ 190 { 1, EIO }, /* unconfigured */ 191 { 1, EIO }, /* partial */ 192 { 1, EIO }, /* configured */ 193 { 1, EIO }, /* release */ 194 { 1, EIO }, /* unreferenced */ 195 { 1, EIO }, /* fatal */ 196 } 197 }, 198 { SBD_CMD_DISCONNECT, 199 { 200 { 1, EIO }, /* empty */ 201 { 0, 0 }, /* occupied */ 202 { 0, 0 }, /* connected */ 203 { 0, 0 }, /* unconfigured */ 204 { 1, EIO }, /* partial */ 205 { 1, EIO }, /* configured */ 206 { 1, EIO }, /* release */ 207 { 1, EIO }, /* unreferenced */ 208 { 1, EIO }, /* fatal */ 209 } 210 }, 211 { SBD_CMD_CONFIGURE, 212 { 213 { 1, EIO }, /* empty */ 214 { 1, EIO }, /* occupied */ 215 { 0, 0 }, /* connected */ 216 { 0, 0 }, /* unconfigured */ 217 { 0, 0 }, /* partial */ 218 { 1, 0 }, /* configured */ 219 { 0, 0 }, /* release */ 220 { 0, 0 }, /* unreferenced */ 221 { 1, EIO }, /* fatal */ 222 } 223 }, 224 { SBD_CMD_UNCONFIGURE, 225 { 226 { 1, EIO }, /* empty */ 227 { 1, EIO }, /* occupied */ 228 { 1, EIO }, /* connected */ 229 { 1, EIO }, /* unconfigured */ 230 { 1, EIO }, /* partial */ 231 { 0, 0 }, /* configured */ 232 { 0, 0 }, /* release */ 233 { 0, 0 }, /* unreferenced */ 234 { 1, EIO }, /* fatal */ 235 } 236 }, 237 { SBD_CMD_POWEROFF, 238 { 239 { 1, EIO }, /* empty */ 240 { 0, 0 }, /* occupied */ 241 { 1, EIO }, /* connected */ 242 { 1, EIO }, /* unconfigured */ 243 { 1, EIO }, /* partial */ 244 { 1, EIO }, /* configured */ 245 { 1, EIO }, /* release */ 246 { 1, EIO }, /* unreferenced */ 247 { 1, EIO }, /* fatal */ 248 } 249 }, 250 { SBD_CMD_POWERON, 251 { 252 { 1, EIO }, /* empty */ 253 { 0, 0 }, /* occupied */ 254 { 1, EIO }, /* connected */ 255 { 1, EIO }, /* unconfigured */ 256 { 1, EIO }, /* partial */ 257 { 1, EIO }, /* configured */ 258 { 1, EIO }, /* release */ 259 { 1, EIO }, /* unreferenced */ 260 { 1, EIO }, /* fatal */ 261 } 262 }, 263 { SBD_CMD_UNASSIGN, 264 { 265 { 1, EIO }, /* empty */ 266 { 0, 0 }, /* occupied */ 267 { 1, EIO }, /* connected */ 268 { 1, EIO }, /* unconfigured */ 269 { 1, EIO }, /* partial */ 270 { 1, EIO }, /* configured */ 271 { 1, EIO }, /* release */ 272 { 1, EIO }, /* unreferenced */ 273 { 1, EIO }, /* fatal */ 274 } 275 }, 276 { SBD_CMD_ASSIGN, 277 { 278 { 1, EIO }, /* empty */ 279 { 0, 0 }, /* occupied */ 280 { 1, EIO }, /* connected */ 281 { 1, EIO }, /* unconfigured */ 282 { 1, EIO }, /* partial */ 283 { 1, EIO }, /* configured */ 284 { 1, EIO }, /* release */ 285 { 1, EIO }, /* unreferenced */ 286 { 1, EIO }, /* fatal */ 287 } 288 }, 289 { SBD_CMD_TEST, 290 { 291 { 1, EIO }, /* empty */ 292 { 0, 0 }, /* occupied */ 293 { 1, EIO }, /* connected */ 294 { 1, EIO }, /* unconfigured */ 295 { 1, EIO }, /* partial */ 296 { 1, EIO }, /* configured */ 297 { 1, EIO }, /* release */ 298 { 1, EIO }, /* unreferenced */ 299 { 1, EIO }, /* fatal */ 300 } 301 }, 302 }; 303 304 /* 305 * Global R/W lock to synchronize access across 306 * multiple boards. Users wanting multi-board access 307 * must grab WRITE lock, others must grab READ lock. 308 */ 309 krwlock_t sbd_grwlock; 310 311 /* 312 * Global to determine if an event needs to be sent 313 */ 314 char send_event = 0; 315 316 /* 317 * Required/Expected functions. 318 */ 319 320 static sbd_handle_t *sbd_get_handle(dev_t dev, sbd_softstate_t *softsp, 321 intptr_t arg, sbd_init_arg_t *iap); 322 static void sbd_release_handle(sbd_handle_t *hp); 323 static int sbd_pre_op(sbd_handle_t *hp); 324 static void sbd_post_op(sbd_handle_t *hp); 325 static int sbd_probe_board(sbd_handle_t *hp); 326 static int sbd_deprobe_board(sbd_handle_t *hp); 327 static void sbd_connect(sbd_handle_t *hp); 328 static void sbd_assign_board(sbd_handle_t *hp); 329 static void sbd_unassign_board(sbd_handle_t *hp); 330 static void sbd_poweron_board(sbd_handle_t *hp); 331 static void sbd_poweroff_board(sbd_handle_t *hp); 332 static void sbd_test_board(sbd_handle_t *hp); 333 334 static int sbd_disconnect(sbd_handle_t *hp); 335 static sbd_devlist_t *sbd_get_attach_devlist(sbd_handle_t *hp, 336 int32_t *devnump, int32_t pass); 337 static int sbd_pre_attach_devlist(sbd_handle_t *hp, 338 sbd_devlist_t *devlist, int32_t devnum); 339 static int sbd_post_attach_devlist(sbd_handle_t *hp, 340 sbd_devlist_t *devlist, int32_t devnum); 341 static sbd_devlist_t *sbd_get_release_devlist(sbd_handle_t *hp, 342 int32_t *devnump, int32_t pass); 343 static int sbd_pre_release_devlist(sbd_handle_t *hp, 344 sbd_devlist_t *devlist, int32_t devnum); 345 static int sbd_post_release_devlist(sbd_handle_t *hp, 346 sbd_devlist_t *devlist, int32_t devnum); 347 static void sbd_release_done(sbd_handle_t *hp, 348 sbd_comp_type_t nodetype, 349 dev_info_t *dip); 350 static sbd_devlist_t *sbd_get_detach_devlist(sbd_handle_t *hp, 351 int32_t *devnump, int32_t pass); 352 static int sbd_pre_detach_devlist(sbd_handle_t *hp, 353 sbd_devlist_t *devlist, int32_t devnum); 354 static int sbd_post_detach_devlist(sbd_handle_t *hp, 355 sbd_devlist_t *devlist, int32_t devnum); 356 static void sbd_status(sbd_handle_t *hp); 357 static void sbd_get_ncm(sbd_handle_t *hp); 358 359 360 /* 361 * Support functions. 362 */ 363 static sbd_devset_t sbd_dev2devset(sbd_comp_id_t *cid); 364 static int sbd_copyin_ioarg(sbd_handle_t *hp, int mode, int cmd, 365 sbd_cmd_t *cmdp, sbd_ioctl_arg_t *iap); 366 static int sbd_copyout_errs(int mode, sbd_ioctl_arg_t *iap, 367 void *arg); 368 static int sbd_copyout_ioarg(int mode, int cmd, sbd_cmd_t *scp, 369 sbd_ioctl_arg_t *iap); 370 static int sbd_check_transition(sbd_board_t *sbp, 371 sbd_devset_t *devsetp, 372 struct sbd_state_trans *transp); 373 static sbd_devlist_t *sbd_get_devlist(sbd_handle_t *hp, 374 sbd_board_t *sbp, 375 sbd_comp_type_t nodetype, 376 int max_units, uint_t uset, 377 int *count, int present_only); 378 static int sbd_mem_status(sbd_handle_t *hp, sbd_devset_t devset, 379 sbd_dev_stat_t *dsp); 380 381 static int sbd_init_devlists(sbd_board_t *sbp); 382 static int sbd_name_to_idx(char *name); 383 static int sbd_otype_to_idx(char *otpye); 384 static int sbd_setup_devlists(dev_info_t *dip, void *arg); 385 static void sbd_init_mem_devlists(sbd_board_t *sbp); 386 static void sbd_init_cpu_unit(sbd_board_t *sbp, int unit); 387 static void sbd_board_discovery(sbd_board_t *sbp); 388 static void sbd_board_init(sbd_board_t *sbp, 389 sbd_softstate_t *softsp, 390 int bd, dev_info_t *dip, int wnode); 391 static void sbd_board_destroy(sbd_board_t *sbp); 392 static int sbd_check_unit_attached(sbd_board_t *sbp, 393 dev_info_t *dip, int unit, 394 sbd_comp_type_t nodetype, sbderror_t *ep); 395 396 static sbd_state_t rstate_cvt(sbd_istate_t state); 397 398 /* 399 * Autoconfiguration data structures 400 */ 401 402 extern struct mod_ops mod_miscops; 403 404 static struct modlmisc modlmisc = { 405 &mod_miscops, 406 "System Board DR v%I%" 407 }; 408 409 static struct modlinkage modlinkage = { 410 MODREV_1, 411 (void *)&modlmisc, 412 NULL 413 }; 414 415 static int sbd_instances = 0; 416 417 /* 418 * dr Global data elements 419 */ 420 sbd_global sbd_g; 421 422 /* 423 * We want to be able to unload the module when we wish to do so, but we don't 424 * want anything else to unload it. Unloading cannot occur until 425 * sbd_teardown_instance is called by an explicit IOCTL into the parent node. 426 * This support is for debugging purposes and should it be expected to work 427 * on the field, it should be enhanced: 428 * Currently, there is still a window where sbd_teardow_instance gets called, 429 * sbd_prevent_unloading now = 0, the driver doesn't get unloaded, and 430 * sbd_setup_instance gets called. This may cause a panic. 431 */ 432 int sbd_prevent_unloading = 1; 433 434 /* 435 * Driver entry points. 436 */ 437 int 438 _init(void) 439 { 440 int err; 441 442 /* 443 * If you need to support multiple nodes (instances), then 444 * whatever the maximum number of supported nodes is would 445 * need to passed as the third parameter to ddi_soft_state_init(). 446 * Alternative would be to dynamically fini and re-init the 447 * soft state structure each time a node is attached. 448 */ 449 err = ddi_soft_state_init((void **)&sbd_g.softsp, 450 sizeof (sbd_softstate_t), SBD_MAX_INSTANCES); 451 if (err) 452 return (err); 453 454 if ((err = mod_install(&modlinkage)) != 0) { 455 ddi_soft_state_fini((void **)&sbd_g.softsp); 456 return (err); 457 } 458 459 /* Get the array of names from platform helper routine */ 460 sbd_devattr = sbdp_get_devattr(); 461 462 return (err); 463 } 464 465 int 466 _fini(void) 467 { 468 int err; 469 470 if (sbd_prevent_unloading) 471 return (DDI_FAILURE); 472 473 ASSERT(sbd_instances == 0); 474 475 if ((err = mod_remove(&modlinkage)) != 0) 476 return (err); 477 478 ddi_soft_state_fini((void **)&sbd_g.softsp); 479 480 return (0); 481 } 482 483 int 484 _info(struct modinfo *modinfop) 485 { 486 return (mod_info(&modlinkage, modinfop)); 487 } 488 489 int 490 sbd_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, char *event) 491 { 492 int rv = 0, instance; 493 sbd_handle_t *hp; 494 sbd_softstate_t *softsp; 495 sbd_init_arg_t init_arg; 496 static fn_t f = "sbd_ioctl"; 497 int dr_avail; 498 499 PR_BYP("sbd_ioctl cmd=%x, arg=%lx\n", cmd, arg); 500 501 /* Note: this must also be changed in tandem with sbd_ioctl.h */ 502 switch (cmd) { 503 case SBD_CMD_ASSIGN: 504 case SBD_CMD_UNASSIGN: 505 case SBD_CMD_POWERON: 506 case SBD_CMD_POWEROFF: 507 case SBD_CMD_TEST: 508 case SBD_CMD_CONNECT: 509 case SBD_CMD_CONFIGURE: 510 case SBD_CMD_UNCONFIGURE: 511 case SBD_CMD_DISCONNECT: 512 case SBD_CMD_STATUS: 513 case SBD_CMD_GETNCM: 514 case SBD_CMD_PASSTHRU: 515 break; 516 default: 517 return (ENOTTY); 518 } 519 520 instance = SBD_GET_MINOR2INST(getminor(dev)); 521 if ((softsp = (sbd_softstate_t *)GET_SOFTC(instance)) == NULL) { 522 cmn_err(CE_WARN, 523 "sbd:%s:%d: module not yet attached", 524 f, instance); 525 return (ENXIO); 526 } 527 528 init_arg.dev = dev; 529 init_arg.cmd = cmd; 530 init_arg.mode = mode; 531 init_arg.ioargp = (sbd_ioctl_arg_t *)arg; 532 533 hp = sbd_get_handle(dev, softsp, arg, &init_arg); 534 /* Check to see if we support dr */ 535 dr_avail = sbdp_dr_avail(); 536 if (dr_avail != 1) { 537 switch (hp->h_cmd) { 538 case SBD_CMD_STATUS: 539 case SBD_CMD_GETNCM: 540 case SBD_CMD_PASSTHRU: 541 break; 542 default: 543 sbd_release_handle(hp); 544 return (ENOTSUP); 545 } 546 } 547 548 switch (hp->h_cmd) { 549 case SBD_CMD_STATUS: 550 case SBD_CMD_GETNCM: 551 case SBD_CMD_PASSTHRU: 552 /* no locks needed for these commands */ 553 break; 554 555 default: 556 rw_enter(&sbd_grwlock, RW_WRITER); 557 mutex_enter(&SBDH2BD(hp->h_sbd)->sb_mutex); 558 559 /* 560 * If we're dealing with memory at all, then we have 561 * to keep the "exclusive" global lock held. This is 562 * necessary since we will probably need to look at 563 * multiple board structs. Otherwise, we only have 564 * to deal with the board in question and so can drop 565 * the global lock to "shared". 566 */ 567 /* 568 * XXX This is incorrect. The sh_devset has not 569 * been set at this point - it is 0. 570 */ 571 rv = DEVSET_IN_SET(HD2MACHHD(hp)->sh_devset, 572 SBD_COMP_MEM, DEVSET_ANYUNIT); 573 if (rv == 0) 574 rw_downgrade(&sbd_grwlock); 575 break; 576 } 577 578 /* 579 * Before any operations happen, reset the event flag 580 */ 581 send_event = 0; 582 583 if (sbd_pre_op(hp) == 0) { 584 sbd_exec_op(hp); 585 sbd_post_op(hp); 586 } 587 588 rv = SBD_GET_ERRNO(SBD_HD2ERR(hp)); 589 *event = send_event; 590 591 /* undo locking, if any, done before sbd_pre_op */ 592 switch (hp->h_cmd) { 593 case SBD_CMD_STATUS: 594 case SBD_CMD_GETNCM: 595 case SBD_CMD_PASSTHRU: 596 break; 597 default: 598 mutex_exit(&SBDH2BD(hp->h_sbd)->sb_mutex); 599 rw_exit(&sbd_grwlock); 600 } 601 602 sbd_release_handle(hp); 603 604 return (rv); 605 } 606 607 int 608 sbd_setup_instance(int instance, dev_info_t *root, int max_boards, int wnode, 609 caddr_t sbdp_arg) 610 { 611 int b; 612 sbd_softstate_t *softsp; 613 sbd_board_t *sbd_boardlist; 614 static fn_t f = "sbd_setup_instance"; 615 616 sbd_instances++; 617 618 if (sbdp_setup_instance(sbdp_arg) != DDI_SUCCESS) { 619 sbd_instances--; 620 return (DDI_FAILURE); 621 } 622 623 if (ALLOC_SOFTC(instance) != DDI_SUCCESS) { 624 cmn_err(CE_WARN, 625 "sbd:%s:%d: failed to alloc soft-state", 626 f, instance); 627 sbdp_teardown_instance(sbdp_arg); 628 sbd_instances--; 629 return (DDI_FAILURE); 630 } 631 632 softsp = (sbd_softstate_t *)GET_SOFTC(instance); 633 634 if (softsp == NULL) { 635 cmn_err(CE_WARN, 636 "sbd:%s:%d: failed to get soft-state instance", 637 f, instance); 638 goto exit; 639 } 640 641 sbd_boardlist = GETSTRUCT(sbd_board_t, max_boards); 642 if (sbd_boardlist == NULL) { 643 cmn_err(CE_WARN, 644 "sbd:%s: failed to alloc board list %d", 645 f, instance); 646 goto exit; 647 } 648 649 650 softsp->sbd_boardlist = (void *)sbd_boardlist; 651 softsp->max_boards = max_boards; 652 softsp->wnode = wnode; 653 654 655 for (b = 0; b < max_boards; b++) { 656 sbd_board_init(sbd_boardlist++, softsp, b, root, wnode); 657 } 658 659 660 return (DDI_SUCCESS); 661 exit: 662 (void) sbdp_teardown_instance(sbdp_arg); 663 FREE_SOFTC(instance); 664 sbd_instances--; 665 return (DDI_FAILURE); 666 } 667 668 int 669 sbd_teardown_instance(int instance, caddr_t sbdp_arg) 670 { 671 sbd_softstate_t *softsp; 672 673 if (sbdp_teardown_instance(sbdp_arg) != DDI_SUCCESS) 674 return (DDI_FAILURE); 675 676 softsp = (sbd_softstate_t *)GET_SOFTC(instance); 677 if (softsp == NULL) { 678 return (DDI_FAILURE); 679 } 680 681 (void) sbd_dealloc_instance((sbd_board_t *)softsp->sbd_boardlist, 682 softsp->max_boards); 683 684 FREE_SOFTC(instance); 685 sbd_instances--; 686 sbd_prevent_unloading = 0; 687 688 return (DDI_SUCCESS); 689 } 690 691 static void 692 sbd_exec_op(sbd_handle_t *hp) 693 { 694 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 695 static fn_t f = "sbd_exec_op"; 696 697 switch (hp->h_cmd) { 698 int dev_canceled; 699 700 case SBD_CMD_CONNECT: 701 if (sbd_probe_board(hp)) 702 break; 703 704 sbd_connect(hp); 705 break; 706 707 case SBD_CMD_CONFIGURE: 708 sbd_dev_configure(hp); 709 break; 710 711 case SBD_CMD_UNCONFIGURE: 712 if (((dev_canceled = sbd_dev_release(hp)) == 0) && 713 (SBD_GET_ERRNO(SBD_HD2ERR(hp)) == 0 && 714 SBD_GET_ERR(SBD_HD2ERR(hp)) == 0)) 715 dev_canceled = sbd_dev_unconfigure(hp); 716 717 if (dev_canceled) 718 sbd_cancel(hp); 719 break; 720 721 case SBD_CMD_DISCONNECT: 722 mutex_enter(&sbp->sb_slock); 723 if (sbd_disconnect(hp) == 0) 724 (void) sbd_deprobe_board(hp); 725 mutex_exit(&sbp->sb_slock); 726 break; 727 728 case SBD_CMD_STATUS: 729 sbd_status(hp); 730 break; 731 732 case SBD_CMD_GETNCM: 733 sbd_get_ncm(hp); 734 break; 735 736 case SBD_CMD_ASSIGN: 737 sbd_assign_board(hp); 738 break; 739 740 case SBD_CMD_UNASSIGN: 741 sbd_unassign_board(hp); 742 break; 743 744 case SBD_CMD_POWEROFF: 745 sbd_poweroff_board(hp); 746 break; 747 748 case SBD_CMD_POWERON: 749 sbd_poweron_board(hp); 750 break; 751 752 case SBD_CMD_TEST: 753 sbd_test_board(hp); 754 break; 755 756 case SBD_CMD_PASSTHRU: 757 { 758 int rv; 759 sbdp_handle_t *hdp; 760 sbderror_t *ep = SBD_HD2ERR(hp); 761 sbdp_ioctl_arg_t ia, *iap; 762 763 iap = &ia; 764 765 iap->h_dev = hp->h_dev; 766 iap->h_cmd = hp->h_cmd; 767 iap->h_iap = (intptr_t)hp->h_iap; 768 iap->h_mode = hp->h_mode; 769 770 hdp = sbd_get_sbdp_handle(sbp, hp); 771 rv = sbdp_ioctl(hdp, iap); 772 if (rv != 0) { 773 SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 774 ep->e_errno = rv; 775 } 776 sbd_release_sbdp_handle(hdp); 777 break; 778 } 779 780 default: 781 SBD_SET_ERRNO(SBD_HD2ERR(hp), ENOTTY); 782 cmn_err(CE_WARN, 783 "sbd:%s: unknown command (%d)", 784 f, hp->h_cmd); 785 break; 786 787 } 788 789 if (SBD_GET_ERR(SBD_HD2ERR(hp))) 790 PR_BYP("XXX e_code=%d", SBD_GET_ERR(SBD_HD2ERR(hp))); 791 if (SBD_GET_ERRNO(SBD_HD2ERR(hp))) 792 PR_BYP("XXX errno=%d", SBD_GET_ERRNO(SBD_HD2ERR(hp))); 793 } 794 795 sbd_comp_type_t 796 sbd_get_devtype(sbd_handle_t *hp, dev_info_t *dip) 797 { 798 sbd_board_t *sbp = hp ? SBDH2BD(hp->h_sbd) : NULL; 799 sbd_istate_t bstate; 800 dev_info_t **devlist; 801 int i; 802 char device[OBP_MAXDRVNAME]; 803 int devicelen; 804 805 devicelen = sizeof (device); 806 807 bstate = sbp ? SBD_BOARD_STATE(sbp) : SBD_STATE_EMPTY; 808 /* 809 * if the board's connected or configured, search the 810 * devlists. Otherwise check the device tree 811 */ 812 switch (bstate) { 813 814 case SBD_STATE_CONNECTED: 815 case SBD_STATE_CONFIGURED: 816 case SBD_STATE_UNREFERENCED: 817 case SBD_STATE_UNCONFIGURED: 818 devlist = sbp->sb_devlist[NIX(SBD_COMP_MEM)]; 819 for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) 820 if (devlist[i] == dip) 821 return (SBD_COMP_MEM); 822 823 devlist = sbp->sb_devlist[NIX(SBD_COMP_CPU)]; 824 for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) 825 if (devlist[i] == dip) 826 return (SBD_COMP_CPU); 827 828 devlist = sbp->sb_devlist[NIX(SBD_COMP_IO)]; 829 for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) 830 if (devlist[i] == dip) 831 return (SBD_COMP_IO); 832 /*FALLTHROUGH*/ 833 834 default: 835 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 836 OBP_DEVICETYPE, (caddr_t)device, &devicelen)) 837 break; 838 839 for (i = 0; SBD_COMP(i) != SBD_COMP_UNKNOWN; i++) { 840 if (strcmp(device, SBD_OTYPE(i)) != 0) 841 continue; 842 return (SBD_COMP(i)); 843 } 844 845 break; 846 } 847 return (SBD_COMP_UNKNOWN); 848 } 849 850 static void 851 sbd_dev_configure(sbd_handle_t *hp) 852 { 853 int n, unit; 854 int32_t pass, devnum; 855 dev_info_t *dip; 856 sbd_devlist_t *devlist; 857 sbdp_handle_t *hdp; 858 sbd_comp_type_t nodetype; 859 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 860 861 pass = 1; 862 863 hdp = sbd_get_sbdp_handle(sbp, hp); 864 while ((devlist = sbd_get_attach_devlist(hp, &devnum, pass)) != NULL) { 865 int err; 866 867 err = sbd_pre_attach_devlist(hp, devlist, devnum); 868 if (err < 0) { 869 break; 870 } else if (err > 0) { 871 pass++; 872 continue; 873 } 874 875 for (n = 0; n < devnum; n++) { 876 sbderror_t *ep; 877 878 ep = &devlist[n].dv_error; 879 SBD_SET_ERRNO(ep, 0); 880 SBD_SET_ERR(ep, 0); 881 dip = devlist[n].dv_dip; 882 nodetype = sbd_get_devtype(hp, dip); 883 884 unit = sbdp_get_unit_num(hdp, dip); 885 if (unit < 0) { 886 SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 887 break; 888 } 889 890 switch (nodetype) { 891 case SBD_COMP_MEM: 892 sbd_attach_mem(hp, ep); 893 if (SBD_GET_ERR(ep) == ESBD_CPUONLINE) { 894 FREESTRUCT(devlist, sbd_devlist_t, 895 MAX_MEM_UNITS_PER_BOARD); 896 sbd_release_sbdp_handle(hdp); 897 return; 898 } 899 break; 900 901 case SBD_COMP_CPU: 902 sbd_attach_cpu(hp, ep, dip, unit); 903 break; 904 905 case SBD_COMP_IO: 906 sbd_attach_io(hp, ep, dip, unit); 907 break; 908 909 default: 910 SBD_SET_ERRNO(ep, ENOTTY); 911 break; 912 } 913 914 if (sbd_set_err_in_hdl(hp, ep) == 0) 915 continue; 916 } 917 918 err = sbd_post_attach_devlist(hp, devlist, devnum); 919 if (err < 0) 920 break; 921 922 pass++; 923 } 924 sbd_release_sbdp_handle(hdp); 925 } 926 927 static int 928 sbd_dev_release(sbd_handle_t *hp) 929 { 930 int n, unit; 931 int32_t pass, devnum; 932 dev_info_t *dip; 933 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 934 sbdp_handle_t *hdp; 935 sbd_devlist_t *devlist; 936 sbd_comp_type_t nodetype; 937 int err = 0; 938 int dev_canceled; 939 940 pass = 1; 941 hdp = sbd_get_sbdp_handle(sbp, hp); 942 943 sbp->sb_busy = 1; 944 while ((devlist = 945 sbd_get_release_devlist(hp, &devnum, pass)) != NULL) { 946 947 err = sbd_pre_release_devlist(hp, devlist, devnum); 948 if (err < 0) { 949 dev_canceled = 1; 950 break; 951 } else if (err > 0) { 952 pass++; 953 continue; 954 } 955 956 dev_canceled = 0; 957 for (n = 0; n < devnum; n++) { 958 dip = devlist[n].dv_dip; 959 nodetype = sbd_get_devtype(hp, dip); 960 961 unit = sbdp_get_unit_num(hdp, dip); 962 if (unit < 0) { 963 SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 964 break; 965 } 966 967 if ((nodetype == SBD_COMP_MEM) && 968 sbd_release_mem(hp, dip, unit)) { 969 970 dev_canceled++; 971 } 972 973 sbd_release_done(hp, nodetype, dip); 974 } 975 976 err = sbd_post_release_devlist(hp, devlist, devnum); 977 978 if (err < 0) 979 break; 980 981 if (dev_canceled) 982 break; 983 984 pass++; 985 } 986 sbp->sb_busy = 0; 987 988 sbd_release_sbdp_handle(hdp); 989 990 if (dev_canceled) 991 return (dev_canceled); 992 993 return (err); 994 } 995 996 static int 997 sbd_dev_unconfigure(sbd_handle_t *hp) 998 { 999 int n, unit; 1000 int32_t pass, devnum; 1001 dev_info_t *dip; 1002 sbd_devlist_t *devlist; 1003 sbdp_handle_t *hdp; 1004 sbd_comp_type_t nodetype; 1005 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 1006 int dev_canceled = 0; 1007 static fn_t f = "sbd_dev_unconfigure"; 1008 1009 PR_ALL("%s...\n", f); 1010 1011 pass = 1; 1012 hdp = sbd_get_sbdp_handle(sbp, hp); 1013 1014 while ((devlist = sbd_get_detach_devlist(hp, &devnum, pass)) != NULL) { 1015 int err, detach_err = 0; 1016 1017 err = sbd_pre_detach_devlist(hp, devlist, devnum); 1018 if (err) { 1019 /* 1020 * Only cancel the operation for memory in 1021 * case of failure. 1022 */ 1023 nodetype = sbd_get_devtype(hp, devlist->dv_dip); 1024 if (nodetype == SBD_COMP_MEM) 1025 dev_canceled = 1; 1026 (void) sbd_post_detach_devlist(hp, devlist, devnum); 1027 break; 1028 } 1029 1030 for (n = 0; n < devnum; n++) { 1031 sbderror_t *ep; 1032 1033 ep = &devlist[n].dv_error; 1034 SBD_SET_ERRNO(ep, 0); 1035 SBD_SET_ERR(ep, 0); 1036 dip = devlist[n].dv_dip; 1037 nodetype = sbd_get_devtype(hp, dip); 1038 1039 unit = sbdp_get_unit_num(hdp, dip); 1040 if (unit < 0) { 1041 SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 1042 break; 1043 } 1044 1045 switch (nodetype) { 1046 case SBD_COMP_MEM: 1047 dev_canceled = sbd_detach_mem(hp, ep, unit); 1048 break; 1049 1050 case SBD_COMP_CPU: 1051 sbd_detach_cpu(hp, ep, dip, unit); 1052 break; 1053 1054 case SBD_COMP_IO: 1055 sbd_detach_io(hp, ep, dip, unit); 1056 break; 1057 1058 default: 1059 SBD_SET_ERRNO(ep, ENOTTY); 1060 break; 1061 } 1062 1063 if (sbd_set_err_in_hdl(hp, ep) == 0) { 1064 detach_err = -1; 1065 break; 1066 } 1067 1068 } 1069 err = sbd_post_detach_devlist(hp, devlist, devnum); 1070 if ((err < 0) || (detach_err < 0)) 1071 break; 1072 1073 pass++; 1074 } 1075 1076 sbd_release_sbdp_handle(hdp); 1077 return (dev_canceled); 1078 } 1079 1080 int 1081 sbd_errno2ecode(int error) 1082 { 1083 int rv; 1084 1085 switch (error) { 1086 case EBUSY: 1087 rv = ESBD_BUSY; 1088 break; 1089 case EINVAL: 1090 rv = ESBD_INVAL; 1091 break; 1092 case EALREADY: 1093 rv = ESBD_ALREADY; 1094 break; 1095 case ENODEV: 1096 rv = ESBD_NODEV; 1097 break; 1098 case ENOMEM: 1099 rv = ESBD_NOMEM; 1100 break; 1101 default: 1102 rv = ESBD_INVAL; 1103 } 1104 1105 return (rv); 1106 } 1107 1108 static void 1109 sbd_attach_cpu(sbd_handle_t *hp, sbderror_t *ep, dev_info_t *dip, int unit) 1110 { 1111 int rv = 0; 1112 processorid_t cpuid; 1113 sbdp_handle_t *hdp; 1114 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 1115 static fn_t f = "sbd_attach_cpu"; 1116 char *pathname; 1117 1118 ASSERT(MUTEX_HELD(&cpu_lock)); 1119 1120 ASSERT(dip); 1121 1122 /* 1123 * With the introduction of CMP devices, the CPU nodes 1124 * are no longer directly under the top node. Since 1125 * there is no plan to support CPU attach in the near 1126 * future, a branch configure operation is not required. 1127 */ 1128 1129 hdp = sbd_get_sbdp_handle(sbp, hp); 1130 cpuid = sbdp_get_cpuid(hdp, dip); 1131 if (cpuid < 0) { 1132 rv = -1; 1133 SBD_GET_PERR(hdp->h_err, ep); 1134 } else if ((rv = cpu_configure(cpuid)) != 0) { 1135 cmn_err(CE_WARN, 1136 "sbd:%s: cpu_configure for cpuid %d failed", 1137 f, cpuid); 1138 SBD_SET_ERR(ep, sbd_errno2ecode(rv)); 1139 } 1140 sbd_release_sbdp_handle(hdp); 1141 1142 if (rv == 0) { 1143 ASSERT(sbp->sb_cpupath[unit] != NULL); 1144 pathname = sbp->sb_cpupath[unit]; 1145 (void) ddi_pathname(dip, pathname); 1146 } 1147 } 1148 1149 /* 1150 * translate errno 1151 */ 1152 void 1153 sbd_errno_decode(int err, sbderror_t *ep, dev_info_t *dip) 1154 { 1155 ASSERT(err != 0); 1156 1157 switch (err) { 1158 case ENOMEM: 1159 SBD_SET_ERR(ep, ESBD_NOMEM); 1160 break; 1161 1162 case EBUSY: 1163 SBD_SET_ERR(ep, ESBD_BUSY); 1164 break; 1165 1166 case EIO: 1167 SBD_SET_ERR(ep, ESBD_IO); 1168 break; 1169 1170 case ENXIO: 1171 SBD_SET_ERR(ep, ESBD_NODEV); 1172 break; 1173 1174 case EINVAL: 1175 SBD_SET_ERR(ep, ESBD_INVAL); 1176 break; 1177 1178 case EFAULT: 1179 default: 1180 SBD_SET_ERR(ep, ESBD_FAULT); 1181 break; 1182 } 1183 1184 (void) ddi_pathname(dip, SBD_GET_ERRSTR(ep)); 1185 } 1186 1187 static void 1188 sbd_detach_cpu(sbd_handle_t *hp, sbderror_t *ep, dev_info_t *dip, int unit) 1189 { 1190 processorid_t cpuid; 1191 int rv; 1192 sbdp_handle_t *hdp; 1193 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 1194 sbd_error_t *spe; 1195 static fn_t f = "sbd_detach_cpu"; 1196 1197 ASSERT(MUTEX_HELD(&cpu_lock)); 1198 1199 ASSERT(dip); 1200 hdp = sbd_get_sbdp_handle(sbp, hp); 1201 spe = hdp->h_err; 1202 cpuid = sbdp_get_cpuid(hdp, dip); 1203 if (cpuid < 0) { 1204 SBD_GET_PERR(spe, ep); 1205 sbd_release_sbdp_handle(hdp); 1206 return; 1207 } 1208 1209 if ((rv = cpu_unconfigure(cpuid)) != 0) { 1210 SBD_SET_ERR(ep, sbd_errno2ecode(rv)); 1211 SBD_SET_ERRSTR(ep, sbp->sb_cpupath[unit]); 1212 cmn_err(CE_WARN, 1213 "sbd:%s: cpu_unconfigure for cpu %d failed", 1214 f, cpuid); 1215 sbd_release_sbdp_handle(hdp); 1216 return; 1217 } 1218 sbd_release_sbdp_handle(hdp); 1219 1220 /* 1221 * Since CPU nodes are no longer configured in CPU 1222 * attach, the corresponding branch unconfigure 1223 * operation that would be performed here is also 1224 * no longer required. 1225 */ 1226 } 1227 1228 1229 int 1230 sbd_detach_mem(sbd_handle_t *hp, sbderror_t *ep, int unit) 1231 { 1232 sbd_mem_unit_t *mp; 1233 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 1234 int i, rv; 1235 static fn_t f = "sbd_detach_mem"; 1236 1237 mp = SBD_GET_BOARD_MEMUNIT(sbp, unit); 1238 1239 if (sbd_detach_memory(hp, ep, mp, unit)) { 1240 cmn_err(CE_WARN, "%s: detach fail", f); 1241 return (-1); 1242 } 1243 1244 /* 1245 * Now detach mem devinfo nodes with status lock held. 1246 */ 1247 for (i = 0; i < SBD_NUM_MC_PER_BOARD; i++) { 1248 dev_info_t *fdip = NULL; 1249 1250 if (mp->sbm_dip[i] == NULL) 1251 continue; 1252 ASSERT(e_ddi_branch_held(mp->sbm_dip[i])); 1253 mutex_enter(&sbp->sb_slock); 1254 rv = e_ddi_branch_unconfigure(mp->sbm_dip[i], &fdip, 1255 DEVI_BRANCH_EVENT); 1256 mutex_exit(&sbp->sb_slock); 1257 if (rv) { 1258 /* 1259 * If non-NULL, fdip is returned held and must be 1260 * released. 1261 */ 1262 if (fdip != NULL) { 1263 sbd_errno_decode(rv, ep, fdip); 1264 ddi_release_devi(fdip); 1265 } else { 1266 sbd_errno_decode(rv, ep, mp->sbm_dip[i]); 1267 } 1268 } 1269 } 1270 1271 return (0); 1272 } 1273 1274 /* start beginning of sbd.c */ 1275 1276 /* 1277 * MDR memory support - somewhat disabled for now. 1278 * UNSAFE unsafe driver code - I don't think we want this. 1279 * need to check. 1280 * DEVNODE This driver creates attachment points for individual 1281 * components as well as boards. We only need board 1282 * support. 1283 * DEV2DEVSET Put only present devices in devset. 1284 */ 1285 1286 1287 static sbd_state_t 1288 rstate_cvt(sbd_istate_t state) 1289 { 1290 sbd_state_t cs; 1291 1292 switch (state) { 1293 case SBD_STATE_EMPTY: 1294 cs = SBD_STAT_EMPTY; 1295 break; 1296 case SBD_STATE_OCCUPIED: 1297 case SBD_STATE_FATAL: 1298 cs = SBD_STAT_DISCONNECTED; 1299 break; 1300 case SBD_STATE_CONFIGURED: 1301 case SBD_STATE_CONNECTED: 1302 case SBD_STATE_UNCONFIGURED: 1303 case SBD_STATE_PARTIAL: 1304 case SBD_STATE_RELEASE: 1305 case SBD_STATE_UNREFERENCED: 1306 cs = SBD_STAT_CONNECTED; 1307 break; 1308 default: 1309 cs = SBD_STAT_NONE; 1310 break; 1311 } 1312 1313 return (cs); 1314 } 1315 1316 1317 sbd_state_t 1318 ostate_cvt(sbd_istate_t state) 1319 { 1320 sbd_state_t cs; 1321 1322 switch (state) { 1323 case SBD_STATE_EMPTY: 1324 case SBD_STATE_OCCUPIED: 1325 case SBD_STATE_UNCONFIGURED: 1326 case SBD_STATE_CONNECTED: 1327 case SBD_STATE_FATAL: 1328 cs = SBD_STAT_UNCONFIGURED; 1329 break; 1330 case SBD_STATE_PARTIAL: 1331 case SBD_STATE_CONFIGURED: 1332 case SBD_STATE_RELEASE: 1333 case SBD_STATE_UNREFERENCED: 1334 cs = SBD_STAT_CONFIGURED; 1335 break; 1336 default: 1337 cs = SBD_STAT_NONE; 1338 break; 1339 } 1340 1341 return (cs); 1342 } 1343 1344 int 1345 sbd_dealloc_instance(sbd_board_t *sbp, int max_boards) 1346 { 1347 int b; 1348 sbd_board_t *list = sbp; 1349 static fn_t f = "sbd_dealloc_instance"; 1350 1351 PR_ALL("%s...\n", f); 1352 1353 if (sbp == NULL) { 1354 return (-1); 1355 } 1356 1357 for (b = 0; b < max_boards; b++) { 1358 sbd_board_destroy(sbp++); 1359 } 1360 1361 FREESTRUCT(list, sbd_board_t, max_boards); 1362 1363 return (0); 1364 } 1365 1366 static sbd_devset_t 1367 sbd_dev2devset(sbd_comp_id_t *cid) 1368 { 1369 static fn_t f = "sbd_dev2devset"; 1370 1371 sbd_devset_t devset; 1372 int unit = cid->c_unit; 1373 1374 switch (cid->c_type) { 1375 case SBD_COMP_NONE: 1376 devset = DEVSET(SBD_COMP_CPU, DEVSET_ANYUNIT); 1377 devset |= DEVSET(SBD_COMP_MEM, DEVSET_ANYUNIT); 1378 devset |= DEVSET(SBD_COMP_IO, DEVSET_ANYUNIT); 1379 break; 1380 1381 case SBD_COMP_CPU: 1382 if ((unit > MAX_CPU_UNITS_PER_BOARD) || (unit < 0)) { 1383 PR_ALL("%s: invalid cpu unit# = %d", 1384 f, unit); 1385 devset = 0; 1386 } else 1387 /* 1388 * Generate a devset that includes all the 1389 * cores of a CMP device. If this is not a 1390 * CMP, the extra cores will be eliminated 1391 * later since they are not present. This is 1392 * also true for CMP devices that do not have 1393 * all cores active. 1394 */ 1395 devset = DEVSET(SBD_COMP_CMP, unit); 1396 1397 break; 1398 1399 case SBD_COMP_MEM: 1400 1401 if ((unit > MAX_MEM_UNITS_PER_BOARD) || (unit < 0)) { 1402 #ifdef XXX_jeffco 1403 PR_ALL("%s: invalid mem unit# = %d", 1404 f, unit); 1405 devset = 0; 1406 #endif 1407 devset = DEVSET(cid->c_type, 0); 1408 PR_ALL("%s: adjusted MEM devset = 0x%x\n", 1409 f, devset); 1410 } else 1411 devset = DEVSET(cid->c_type, unit); 1412 break; 1413 1414 case SBD_COMP_IO: 1415 if ((unit > MAX_IO_UNITS_PER_BOARD) || (unit < 0)) { 1416 PR_ALL("%s: invalid io unit# = %d", 1417 f, unit); 1418 devset = 0; 1419 } else 1420 devset = DEVSET(cid->c_type, unit); 1421 1422 break; 1423 1424 default: 1425 case SBD_COMP_UNKNOWN: 1426 devset = 0; 1427 break; 1428 } 1429 1430 return (devset); 1431 } 1432 1433 /* 1434 * Simple mutex for covering handle list ops as it is only 1435 * used "infrequently". No need to add another mutex to the sbd_board_t. 1436 */ 1437 static kmutex_t sbd_handle_list_mutex; 1438 1439 static sbd_handle_t * 1440 sbd_get_handle(dev_t dev, sbd_softstate_t *softsp, intptr_t arg, 1441 sbd_init_arg_t *iap) 1442 { 1443 sbd_handle_t *hp; 1444 sbderror_t *ep; 1445 sbd_priv_handle_t *shp; 1446 sbd_board_t *sbp = softsp->sbd_boardlist; 1447 int board; 1448 1449 board = SBDGETSLOT(dev); 1450 ASSERT(board < softsp->max_boards); 1451 sbp += board; 1452 1453 /* 1454 * Brand-new handle. 1455 */ 1456 shp = kmem_zalloc(sizeof (sbd_priv_handle_t), KM_SLEEP); 1457 shp->sh_arg = (void *)arg; 1458 1459 hp = MACHHD2HD(shp); 1460 1461 ep = &shp->sh_err; 1462 1463 hp->h_err = ep; 1464 hp->h_sbd = (void *) sbp; 1465 hp->h_dev = iap->dev; 1466 hp->h_cmd = iap->cmd; 1467 hp->h_mode = iap->mode; 1468 sbd_init_err(ep); 1469 1470 mutex_enter(&sbd_handle_list_mutex); 1471 shp->sh_next = sbp->sb_handle; 1472 sbp->sb_handle = shp; 1473 mutex_exit(&sbd_handle_list_mutex); 1474 1475 return (hp); 1476 } 1477 1478 void 1479 sbd_init_err(sbderror_t *ep) 1480 { 1481 ep->e_errno = 0; 1482 ep->e_code = 0; 1483 ep->e_rsc[0] = '\0'; 1484 } 1485 1486 int 1487 sbd_set_err_in_hdl(sbd_handle_t *hp, sbderror_t *ep) 1488 { 1489 sbderror_t *hep = SBD_HD2ERR(hp); 1490 1491 /* 1492 * If there is an error logged already, don't rewrite it 1493 */ 1494 if (SBD_GET_ERR(hep) || SBD_GET_ERRNO(hep)) { 1495 return (0); 1496 } 1497 1498 if (SBD_GET_ERR(ep) || SBD_GET_ERRNO(ep)) { 1499 SBD_SET_ERR(hep, SBD_GET_ERR(ep)); 1500 SBD_SET_ERRNO(hep, SBD_GET_ERRNO(ep)); 1501 SBD_SET_ERRSTR(hep, SBD_GET_ERRSTR(ep)); 1502 return (0); 1503 } 1504 1505 return (-1); 1506 } 1507 1508 static void 1509 sbd_release_handle(sbd_handle_t *hp) 1510 { 1511 sbd_priv_handle_t *shp, **shpp; 1512 sbd_board_t *sbp; 1513 static fn_t f = "sbd_release_handle"; 1514 1515 if (hp == NULL) 1516 return; 1517 1518 sbp = SBDH2BD(hp->h_sbd); 1519 1520 shp = HD2MACHHD(hp); 1521 1522 mutex_enter(&sbd_handle_list_mutex); 1523 /* 1524 * Locate the handle in the board's reference list. 1525 */ 1526 for (shpp = &sbp->sb_handle; (*shpp) && ((*shpp) != shp); 1527 shpp = &((*shpp)->sh_next)) 1528 /* empty */; 1529 1530 if (*shpp == NULL) { 1531 cmn_err(CE_PANIC, 1532 "sbd:%s: handle not found in board %d", 1533 f, sbp->sb_num); 1534 /*NOTREACHED*/ 1535 } else { 1536 *shpp = shp->sh_next; 1537 } 1538 mutex_exit(&sbd_handle_list_mutex); 1539 1540 if (hp->h_opts.copts != NULL) { 1541 FREESTRUCT(hp->h_opts.copts, char, hp->h_opts.size); 1542 } 1543 1544 FREESTRUCT(shp, sbd_priv_handle_t, 1); 1545 } 1546 1547 sbdp_handle_t * 1548 sbd_get_sbdp_handle(sbd_board_t *sbp, sbd_handle_t *hp) 1549 { 1550 sbdp_handle_t *hdp; 1551 1552 hdp = kmem_zalloc(sizeof (sbdp_handle_t), KM_SLEEP); 1553 hdp->h_err = kmem_zalloc(sizeof (sbd_error_t), KM_SLEEP); 1554 if (sbp == NULL) { 1555 hdp->h_board = -1; 1556 hdp->h_wnode = -1; 1557 } else { 1558 hdp->h_board = sbp->sb_num; 1559 hdp->h_wnode = sbp->sb_wnode; 1560 } 1561 1562 if (hp == NULL) { 1563 hdp->h_flags = 0; 1564 hdp->h_opts = NULL; 1565 } else { 1566 hdp->h_flags = SBD_2_SBDP_FLAGS(hp->h_flags); 1567 hdp->h_opts = &hp->h_opts; 1568 } 1569 1570 return (hdp); 1571 } 1572 1573 void 1574 sbd_release_sbdp_handle(sbdp_handle_t *hdp) 1575 { 1576 if (hdp == NULL) 1577 return; 1578 1579 kmem_free(hdp->h_err, sizeof (sbd_error_t)); 1580 kmem_free(hdp, sizeof (sbdp_handle_t)); 1581 } 1582 1583 void 1584 sbd_reset_error_sbdph(sbdp_handle_t *hdp) 1585 { 1586 if ((hdp != NULL) && (hdp->h_err != NULL)) { 1587 bzero(hdp->h_err, sizeof (sbd_error_t)); 1588 } 1589 } 1590 1591 static int 1592 sbd_copyin_ioarg(sbd_handle_t *hp, int mode, int cmd, sbd_cmd_t *cmdp, 1593 sbd_ioctl_arg_t *iap) 1594 { 1595 static fn_t f = "sbd_copyin_ioarg"; 1596 1597 if (iap == NULL) 1598 return (EINVAL); 1599 1600 bzero((caddr_t)cmdp, sizeof (sbd_cmd_t)); 1601 1602 #ifdef _MULTI_DATAMODEL 1603 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 1604 sbd_cmd32_t scmd32; 1605 1606 bzero((caddr_t)&scmd32, sizeof (sbd_cmd32_t)); 1607 1608 if (ddi_copyin((void *)iap, (void *)&scmd32, 1609 sizeof (sbd_cmd32_t), mode)) { 1610 cmn_err(CE_WARN, 1611 "sbd:%s: (32bit) failed to copyin " 1612 "sbdcmd-struct", f); 1613 return (EFAULT); 1614 } 1615 cmdp->cmd_cm.c_id.c_type = scmd32.cmd_cm.c_id.c_type; 1616 cmdp->cmd_cm.c_id.c_unit = scmd32.cmd_cm.c_id.c_unit; 1617 bcopy(&scmd32.cmd_cm.c_id.c_name[0], 1618 &cmdp->cmd_cm.c_id.c_name[0], OBP_MAXPROPNAME); 1619 cmdp->cmd_cm.c_flags = scmd32.cmd_cm.c_flags; 1620 cmdp->cmd_cm.c_len = scmd32.cmd_cm.c_len; 1621 cmdp->cmd_cm.c_opts = (caddr_t)(uintptr_t)scmd32.cmd_cm.c_opts; 1622 1623 if (cmd == SBD_CMD_PASSTHRU) { 1624 PR_BYP("passthru copyin: iap=%p, sz=%ld", iap, 1625 sizeof (sbd_cmd32_t)); 1626 PR_BYP("passthru copyin: c_opts=%x, c_len=%d", 1627 scmd32.cmd_cm.c_opts, 1628 scmd32.cmd_cm.c_len); 1629 } 1630 1631 switch (cmd) { 1632 case SBD_CMD_STATUS: 1633 cmdp->cmd_stat.s_nbytes = scmd32.cmd_stat.s_nbytes; 1634 cmdp->cmd_stat.s_statp = 1635 (caddr_t)(uintptr_t)scmd32.cmd_stat.s_statp; 1636 break; 1637 default: 1638 break; 1639 1640 } 1641 } else 1642 #endif /* _MULTI_DATAMODEL */ 1643 if (ddi_copyin((void *)iap, (void *)cmdp, 1644 sizeof (sbd_cmd_t), mode) != 0) { 1645 cmn_err(CE_WARN, 1646 "sbd:%s: failed to copyin sbd cmd_t struct", f); 1647 return (EFAULT); 1648 } 1649 /* 1650 * A user may set platform specific options so we need to 1651 * copy them in 1652 */ 1653 if ((cmd != SBD_CMD_STATUS) && ((hp->h_opts.size = cmdp->cmd_cm.c_len) 1654 > 0)) { 1655 hp->h_opts.size += 1; /* For null termination of string. */ 1656 hp->h_opts.copts = GETSTRUCT(char, hp->h_opts.size); 1657 if (ddi_copyin((void *)cmdp->cmd_cm.c_opts, 1658 (void *)hp->h_opts.copts, 1659 cmdp->cmd_cm.c_len, hp->h_mode) != 0) { 1660 /* copts is freed in sbd_release_handle(). */ 1661 cmn_err(CE_WARN, 1662 "sbd:%s: failed to copyin options", f); 1663 return (EFAULT); 1664 } 1665 } 1666 1667 return (0); 1668 } 1669 1670 static int 1671 sbd_copyout_ioarg(int mode, int cmd, sbd_cmd_t *scp, sbd_ioctl_arg_t *iap) 1672 { 1673 static fn_t f = "sbd_copyout_ioarg"; 1674 1675 if ((iap == NULL) || (scp == NULL)) 1676 return (EINVAL); 1677 1678 #ifdef _MULTI_DATAMODEL 1679 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 1680 sbd_cmd32_t scmd32; 1681 1682 scmd32.cmd_cm.c_id.c_type = scp->cmd_cm.c_id.c_type; 1683 scmd32.cmd_cm.c_id.c_unit = scp->cmd_cm.c_id.c_unit; 1684 bcopy(scp->cmd_cm.c_id.c_name, 1685 scmd32.cmd_cm.c_id.c_name, OBP_MAXPROPNAME); 1686 1687 scmd32.cmd_cm.c_flags = scp->cmd_cm.c_flags; 1688 1689 switch (cmd) { 1690 case SBD_CMD_GETNCM: 1691 scmd32.cmd_getncm.g_ncm = scp->cmd_getncm.g_ncm; 1692 break; 1693 default: 1694 break; 1695 } 1696 1697 if (ddi_copyout((void *)&scmd32, (void *)iap, 1698 sizeof (sbd_cmd32_t), mode)) { 1699 cmn_err(CE_WARN, 1700 "sbd:%s: (32bit) failed to copyout " 1701 "sbdcmd struct", f); 1702 return (EFAULT); 1703 } 1704 } else 1705 #endif /* _MULTI_DATAMODEL */ 1706 if (ddi_copyout((void *)scp, (void *)iap, 1707 sizeof (sbd_cmd_t), mode) != 0) { 1708 cmn_err(CE_WARN, 1709 "sbd:%s: failed to copyout sbdcmd struct", f); 1710 return (EFAULT); 1711 } 1712 1713 return (0); 1714 } 1715 1716 static int 1717 sbd_copyout_errs(int mode, sbd_ioctl_arg_t *iap, void *arg) 1718 { 1719 static fn_t f = "sbd_copyout_errs"; 1720 sbd_ioctl_arg_t *uap; 1721 1722 uap = (sbd_ioctl_arg_t *)arg; 1723 1724 #ifdef _MULTI_DATAMODEL 1725 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 1726 sbd_error32_t err32; 1727 sbd_ioctl_arg32_t *uap32; 1728 1729 uap32 = (sbd_ioctl_arg32_t *)arg; 1730 1731 err32.e_code = iap->ie_code; 1732 (void) strcpy(err32.e_rsc, iap->ie_rsc); 1733 1734 if (ddi_copyout((void *)&err32, (void *)&uap32->i_err, 1735 sizeof (sbd_error32_t), mode)) { 1736 cmn_err(CE_WARN, 1737 "sbd:%s: failed to copyout ioctl32 errs", 1738 f); 1739 return (EFAULT); 1740 } 1741 } else 1742 #endif /* _MULTI_DATAMODEL */ 1743 if (ddi_copyout((void *)&iap->i_err, (void *)&uap->i_err, 1744 sizeof (sbd_error_t), mode) != 0) { 1745 cmn_err(CE_WARN, 1746 "sbd:%s: failed to copyout ioctl errs", f); 1747 return (EFAULT); 1748 } 1749 1750 return (0); 1751 } 1752 1753 /* 1754 * State transition policy is that if at least one 1755 * device cannot make the transition, then none of 1756 * the requested devices are allowed to transition. 1757 * 1758 * Returns the state that is in error, if any. 1759 */ 1760 static int 1761 sbd_check_transition(sbd_board_t *sbp, sbd_devset_t *devsetp, 1762 struct sbd_state_trans *transp) 1763 { 1764 int s, ut; 1765 int state_err = 0; 1766 sbd_devset_t devset; 1767 static fn_t f = "sbd_check_transition"; 1768 1769 devset = *devsetp; 1770 1771 if (!devset) { 1772 /* 1773 * Transition does not deal with any components. 1774 * This is the case for addboard/deleteboard. 1775 */ 1776 PR_ALL("%s: no devs: requested devset = 0x%x," 1777 " final devset = 0x%x\n", 1778 f, (uint_t)*devsetp, (uint_t)devset); 1779 1780 return (0); 1781 } 1782 1783 if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT)) { 1784 for (ut = 0; ut < MAX_MEM_UNITS_PER_BOARD; ut++) { 1785 if (DEVSET_IN_SET(devset, SBD_COMP_MEM, ut) == 0) 1786 continue; 1787 s = (int)SBD_DEVICE_STATE(sbp, SBD_COMP_MEM, ut); 1788 if (transp->x_op[s].x_rv) { 1789 if (!state_err) 1790 state_err = s; 1791 DEVSET_DEL(devset, SBD_COMP_MEM, ut); 1792 } 1793 } 1794 } 1795 1796 if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT)) { 1797 for (ut = 0; ut < MAX_CPU_UNITS_PER_BOARD; ut++) { 1798 if (DEVSET_IN_SET(devset, SBD_COMP_CPU, ut) == 0) 1799 continue; 1800 s = (int)SBD_DEVICE_STATE(sbp, SBD_COMP_CPU, ut); 1801 if (transp->x_op[s].x_rv) { 1802 if (!state_err) 1803 state_err = s; 1804 DEVSET_DEL(devset, SBD_COMP_CPU, ut); 1805 } 1806 } 1807 } 1808 1809 if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT)) { 1810 for (ut = 0; ut < MAX_IO_UNITS_PER_BOARD; ut++) { 1811 if (DEVSET_IN_SET(devset, SBD_COMP_IO, ut) == 0) 1812 continue; 1813 s = (int)SBD_DEVICE_STATE(sbp, SBD_COMP_IO, ut); 1814 if (transp->x_op[s].x_rv) { 1815 if (!state_err) 1816 state_err = s; 1817 DEVSET_DEL(devset, SBD_COMP_IO, ut); 1818 } 1819 } 1820 } 1821 1822 PR_ALL("%s: requested devset = 0x%x, final devset = 0x%x\n", 1823 f, (uint_t)*devsetp, (uint_t)devset); 1824 1825 *devsetp = devset; 1826 /* 1827 * If there are some remaining components for which 1828 * this state transition is valid, then allow them 1829 * through, otherwise if none are left then return 1830 * the state error. 1831 */ 1832 return (devset ? 0 : state_err); 1833 } 1834 1835 /* 1836 * pre-op entry point must SET_ERRNO(), if needed. 1837 * Return value of non-zero indicates failure. 1838 */ 1839 static int 1840 sbd_pre_op(sbd_handle_t *hp) 1841 { 1842 int rv = 0, t; 1843 int cmd, serr = 0; 1844 sbd_devset_t devset; 1845 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 1846 sbd_priv_handle_t *shp = HD2MACHHD(hp); 1847 sbderror_t *ep = SBD_HD2ERR(hp); 1848 sbd_cmd_t *cmdp; 1849 static fn_t f = "sbd_pre_op"; 1850 1851 cmd = hp->h_cmd; 1852 devset = shp->sh_devset; 1853 1854 switch (cmd) { 1855 case SBD_CMD_CONNECT: 1856 case SBD_CMD_DISCONNECT: 1857 case SBD_CMD_UNCONFIGURE: 1858 case SBD_CMD_CONFIGURE: 1859 case SBD_CMD_ASSIGN: 1860 case SBD_CMD_UNASSIGN: 1861 case SBD_CMD_POWERON: 1862 case SBD_CMD_POWEROFF: 1863 case SBD_CMD_TEST: 1864 /* ioctls allowed if caller has write permission */ 1865 if (!(hp->h_mode & FWRITE)) { 1866 SBD_SET_ERRNO(ep, EPERM); 1867 return (-1); 1868 } 1869 1870 default: 1871 break; 1872 } 1873 1874 hp->h_iap = GETSTRUCT(sbd_ioctl_arg_t, 1); 1875 rv = sbd_copyin_ioarg(hp, hp->h_mode, cmd, 1876 (sbd_cmd_t *)hp->h_iap, shp->sh_arg); 1877 if (rv) { 1878 SBD_SET_ERRNO(ep, rv); 1879 FREESTRUCT(hp->h_iap, sbd_ioctl_arg_t, 1); 1880 hp->h_iap = NULL; 1881 cmn_err(CE_WARN, "%s: copyin fail", f); 1882 return (-1); 1883 } else { 1884 cmdp = (sbd_cmd_t *)hp->h_iap; 1885 if (cmdp->cmd_cm.c_id.c_name[0] != '\0') { 1886 1887 cmdp->cmd_cm.c_id.c_type = SBD_COMP(sbd_name_to_idx( 1888 cmdp->cmd_cm.c_id.c_name)); 1889 if (cmdp->cmd_cm.c_id.c_type == SBD_COMP_MEM) { 1890 if (cmdp->cmd_cm.c_id.c_unit == -1) 1891 cmdp->cmd_cm.c_id.c_unit = 0; 1892 } 1893 } 1894 devset = shp->sh_orig_devset = shp->sh_devset = 1895 sbd_dev2devset(&cmdp->cmd_cm.c_id); 1896 if (devset == 0) { 1897 SBD_SET_ERRNO(ep, EINVAL); 1898 FREESTRUCT(hp->h_iap, sbd_ioctl_arg_t, 1); 1899 hp->h_iap = NULL; 1900 return (-1); 1901 } 1902 } 1903 1904 /* 1905 * Always turn on these bits ala Sunfire DR. 1906 */ 1907 hp->h_flags |= SBD_FLAG_DEVI_FORCE; 1908 1909 if (cmdp->cmd_cm.c_flags & SBD_FLAG_FORCE) 1910 hp->h_flags |= SBD_IOCTL_FLAG_FORCE; 1911 1912 /* 1913 * Check for valid state transitions. 1914 */ 1915 if (!serr && ((t = CMD2INDEX(cmd)) != -1)) { 1916 struct sbd_state_trans *transp; 1917 int state_err; 1918 1919 transp = &sbd_state_transition[t]; 1920 ASSERT(transp->x_cmd == cmd); 1921 1922 state_err = sbd_check_transition(sbp, &devset, transp); 1923 1924 if (state_err < 0) { 1925 /* 1926 * Invalidate device. 1927 */ 1928 SBD_SET_ERRNO(ep, ENOTTY); 1929 serr = -1; 1930 PR_ALL("%s: invalid devset (0x%x)\n", 1931 f, (uint_t)devset); 1932 } else if (state_err != 0) { 1933 /* 1934 * State transition is not a valid one. 1935 */ 1936 SBD_SET_ERRNO(ep, transp->x_op[state_err].x_err); 1937 serr = transp->x_op[state_err].x_rv; 1938 PR_ALL("%s: invalid state %s(%d) for cmd %s(%d)\n", 1939 f, sbd_state_str[state_err], state_err, 1940 SBD_CMD_STR(cmd), cmd); 1941 } 1942 if (serr && SBD_GET_ERRNO(ep) != 0) { 1943 /* 1944 * A state transition error occurred. 1945 */ 1946 if (serr < 0) { 1947 SBD_SET_ERR(ep, ESBD_INVAL); 1948 } else { 1949 SBD_SET_ERR(ep, ESBD_STATE); 1950 } 1951 PR_ALL("%s: invalid state transition\n", f); 1952 } else { 1953 shp->sh_devset = devset; 1954 } 1955 } 1956 1957 if (serr && !rv && hp->h_iap) { 1958 1959 /* 1960 * There was a state error. We successfully copied 1961 * in the ioctl argument, so let's fill in the 1962 * error and copy it back out. 1963 */ 1964 1965 if (SBD_GET_ERR(ep) && SBD_GET_ERRNO(ep) == 0) 1966 SBD_SET_ERRNO(ep, EIO); 1967 1968 SBD_SET_IOCTL_ERR(&hp->h_iap->i_err, 1969 ep->e_code, 1970 ep->e_rsc); 1971 (void) sbd_copyout_errs(hp->h_mode, hp->h_iap, shp->sh_arg); 1972 FREESTRUCT(hp->h_iap, sbd_ioctl_arg_t, 1); 1973 hp->h_iap = NULL; 1974 rv = -1; 1975 } 1976 1977 return (rv); 1978 } 1979 1980 static void 1981 sbd_post_op(sbd_handle_t *hp) 1982 { 1983 int cmd; 1984 sbderror_t *ep = SBD_HD2ERR(hp); 1985 sbd_priv_handle_t *shp = HD2MACHHD(hp); 1986 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 1987 1988 cmd = hp->h_cmd; 1989 1990 switch (cmd) { 1991 case SBD_CMD_CONFIGURE: 1992 case SBD_CMD_UNCONFIGURE: 1993 case SBD_CMD_CONNECT: 1994 case SBD_CMD_DISCONNECT: 1995 sbp->sb_time = gethrestime_sec(); 1996 break; 1997 1998 default: 1999 break; 2000 } 2001 2002 if (SBD_GET_ERR(ep) && SBD_GET_ERRNO(ep) == 0) { 2003 SBD_SET_ERRNO(ep, EIO); 2004 } 2005 2006 if (shp->sh_arg != NULL) { 2007 2008 if (SBD_GET_ERR(ep) != ESBD_NOERROR) { 2009 2010 SBD_SET_IOCTL_ERR(&hp->h_iap->i_err, 2011 ep->e_code, 2012 ep->e_rsc); 2013 2014 (void) sbd_copyout_errs(hp->h_mode, hp->h_iap, 2015 shp->sh_arg); 2016 } 2017 2018 if (hp->h_iap != NULL) { 2019 FREESTRUCT(hp->h_iap, sbd_ioctl_arg_t, 1); 2020 hp->h_iap = NULL; 2021 } 2022 } 2023 } 2024 2025 static int 2026 sbd_probe_board(sbd_handle_t *hp) 2027 { 2028 int rv; 2029 sbd_board_t *sbp; 2030 sbdp_handle_t *hdp; 2031 static fn_t f = "sbd_probe_board"; 2032 2033 sbp = SBDH2BD(hp->h_sbd); 2034 2035 ASSERT(sbp != NULL); 2036 PR_ALL("%s for board %d", f, sbp->sb_num); 2037 2038 2039 hdp = sbd_get_sbdp_handle(sbp, hp); 2040 2041 if ((rv = sbdp_connect_board(hdp)) != 0) { 2042 sbderror_t *ep = SBD_HD2ERR(hp); 2043 2044 SBD_GET_PERR(hdp->h_err, ep); 2045 } 2046 2047 /* 2048 * We need to force a recache after the connect. The cached 2049 * info may be incorrect 2050 */ 2051 mutex_enter(&sbp->sb_flags_mutex); 2052 sbp->sb_flags &= ~SBD_BOARD_STATUS_CACHED; 2053 mutex_exit(&sbp->sb_flags_mutex); 2054 2055 SBD_INJECT_ERR(SBD_PROBE_BOARD_PSEUDO_ERR, hp->h_err, EIO, 2056 ESGT_PROBE, NULL); 2057 2058 sbd_release_sbdp_handle(hdp); 2059 2060 return (rv); 2061 } 2062 2063 static int 2064 sbd_deprobe_board(sbd_handle_t *hp) 2065 { 2066 int rv; 2067 sbdp_handle_t *hdp; 2068 sbd_board_t *sbp; 2069 static fn_t f = "sbd_deprobe_board"; 2070 2071 PR_ALL("%s...\n", f); 2072 2073 sbp = SBDH2BD(hp->h_sbd); 2074 2075 hdp = sbd_get_sbdp_handle(sbp, hp); 2076 2077 if ((rv = sbdp_disconnect_board(hdp)) != 0) { 2078 sbderror_t *ep = SBD_HD2ERR(hp); 2079 2080 SBD_GET_PERR(hdp->h_err, ep); 2081 } 2082 2083 mutex_enter(&sbp->sb_flags_mutex); 2084 sbp->sb_flags &= ~SBD_BOARD_STATUS_CACHED; 2085 mutex_exit(&sbp->sb_flags_mutex); 2086 2087 SBD_INJECT_ERR(SBD_DEPROBE_BOARD_PSEUDO_ERR, hp->h_err, EIO, 2088 ESGT_DEPROBE, NULL); 2089 2090 sbd_release_sbdp_handle(hdp); 2091 return (rv); 2092 } 2093 2094 /* 2095 * Check if a CPU node is part of a CMP. 2096 */ 2097 int 2098 sbd_is_cmp_child(dev_info_t *dip) 2099 { 2100 dev_info_t *pdip; 2101 2102 if (strcmp(ddi_node_name(dip), "cpu") != 0) { 2103 return (0); 2104 } 2105 2106 pdip = ddi_get_parent(dip); 2107 2108 ASSERT(pdip); 2109 2110 if (strcmp(ddi_node_name(pdip), "cmp") == 0) { 2111 return (1); 2112 } 2113 2114 return (0); 2115 } 2116 2117 /* 2118 * Returns the nodetype if dip is a top dip on the board of 2119 * interest or SBD_COMP_UNKNOWN otherwise 2120 */ 2121 static sbd_comp_type_t 2122 get_node_type(sbd_board_t *sbp, dev_info_t *dip, int *unitp) 2123 { 2124 int idx, unit; 2125 sbd_handle_t *hp; 2126 sbdp_handle_t *hdp; 2127 char otype[OBP_MAXDRVNAME]; 2128 int otypelen; 2129 2130 ASSERT(sbp); 2131 2132 if (unitp) 2133 *unitp = -1; 2134 2135 hp = MACHBD2HD(sbp); 2136 2137 hdp = sbd_get_sbdp_handle(sbp, hp); 2138 if (sbdp_get_board_num(hdp, dip) != sbp->sb_num) { 2139 sbd_release_sbdp_handle(hdp); 2140 return (SBD_COMP_UNKNOWN); 2141 } 2142 2143 /* 2144 * sbdp_get_unit_num will return (-1) for cmp as there 2145 * is no "device_type" property associated with cmp. 2146 * Therefore we will just skip getting unit number for 2147 * cmp. Callers of this function need to check the 2148 * value set in unitp before using it to dereference 2149 * an array. 2150 */ 2151 if (strcmp(ddi_node_name(dip), "cmp") == 0) { 2152 sbd_release_sbdp_handle(hdp); 2153 return (SBD_COMP_CMP); 2154 } 2155 2156 otypelen = sizeof (otype); 2157 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 2158 OBP_DEVICETYPE, (caddr_t)otype, &otypelen)) { 2159 sbd_release_sbdp_handle(hdp); 2160 return (SBD_COMP_UNKNOWN); 2161 } 2162 2163 idx = sbd_otype_to_idx(otype); 2164 2165 if (SBD_COMP(idx) == SBD_COMP_UNKNOWN) { 2166 sbd_release_sbdp_handle(hdp); 2167 return (SBD_COMP_UNKNOWN); 2168 } 2169 2170 unit = sbdp_get_unit_num(hdp, dip); 2171 if (unit == -1) { 2172 cmn_err(CE_WARN, 2173 "get_node_type: %s unit fail %p", otype, (void *)dip); 2174 sbd_release_sbdp_handle(hdp); 2175 return (SBD_COMP_UNKNOWN); 2176 } 2177 2178 sbd_release_sbdp_handle(hdp); 2179 2180 if (unitp) 2181 *unitp = unit; 2182 2183 return (SBD_COMP(idx)); 2184 } 2185 2186 typedef struct { 2187 sbd_board_t *sbp; 2188 int nmc; 2189 int hold; 2190 } walk_tree_t; 2191 2192 static int 2193 sbd_setup_devlists(dev_info_t *dip, void *arg) 2194 { 2195 walk_tree_t *wp; 2196 dev_info_t **devlist = NULL; 2197 char *pathname = NULL; 2198 sbd_mem_unit_t *mp; 2199 static fn_t f = "sbd_setup_devlists"; 2200 sbd_board_t *sbp; 2201 int unit; 2202 sbd_comp_type_t nodetype; 2203 2204 ASSERT(dip); 2205 2206 wp = (walk_tree_t *)arg; 2207 2208 if (wp == NULL) { 2209 PR_ALL("%s:bad arg\n", f); 2210 return (DDI_WALK_TERMINATE); 2211 } 2212 2213 sbp = wp->sbp; 2214 2215 nodetype = get_node_type(sbp, dip, &unit); 2216 2217 switch (nodetype) { 2218 2219 case SBD_COMP_CPU: 2220 pathname = sbp->sb_cpupath[unit]; 2221 break; 2222 2223 case SBD_COMP_MEM: 2224 pathname = sbp->sb_mempath[unit]; 2225 break; 2226 2227 case SBD_COMP_IO: 2228 pathname = sbp->sb_iopath[unit]; 2229 break; 2230 2231 case SBD_COMP_CMP: 2232 case SBD_COMP_UNKNOWN: 2233 /* 2234 * This dip is not of interest to us 2235 */ 2236 return (DDI_WALK_CONTINUE); 2237 2238 default: 2239 ASSERT(0); 2240 return (DDI_WALK_CONTINUE); 2241 } 2242 2243 /* 2244 * dip's parent is being held busy by ddi_walk_devs(), 2245 * so dip doesn't have to be held while calling ddi_pathname() 2246 */ 2247 if (pathname) { 2248 (void) ddi_pathname(dip, pathname); 2249 } 2250 2251 devlist = sbp->sb_devlist[NIX(nodetype)]; 2252 2253 /* 2254 * The branch rooted at dip should already be held, 2255 * unless we are dealing with a core of a CMP. 2256 */ 2257 ASSERT(sbd_is_cmp_child(dip) || e_ddi_branch_held(dip)); 2258 devlist[unit] = dip; 2259 2260 /* 2261 * This test is required if multiple devices are considered 2262 * as one. This is the case for memory-controller nodes. 2263 */ 2264 if (!SBD_DEV_IS_PRESENT(sbp, nodetype, unit)) { 2265 sbp->sb_ndev++; 2266 SBD_DEV_SET_PRESENT(sbp, nodetype, unit); 2267 } 2268 2269 if (nodetype == SBD_COMP_MEM) { 2270 mp = SBD_GET_BOARD_MEMUNIT(sbp, unit); 2271 ASSERT(wp->nmc < SBD_NUM_MC_PER_BOARD); 2272 mp->sbm_dip[wp->nmc++] = dip; 2273 } 2274 2275 return (DDI_WALK_CONTINUE); 2276 } 2277 2278 /* 2279 * This routine is used to construct the memory devlist. 2280 * In Starcat and Serengeti platforms, a system board can contain up to 2281 * four memory controllers (MC). The MCs have been programmed by POST for 2282 * optimum memory interleaving amongst their peers on the same board. 2283 * This DR driver does not support deinterleaving. Therefore, the smallest 2284 * unit of memory that can be manipulated by this driver is all of the 2285 * memory on a board. Because of this restriction, a board's memory devlist 2286 * is populated with only one of the four (possible) MC dnodes on that board. 2287 * Care must be taken to ensure that the selected MC dnode represents the 2288 * lowest physical address to which memory on the board will respond to. 2289 * This is required in order to preserve the semantics of 2290 * sbdp_get_base_physaddr() when applied to a MC dnode stored in the 2291 * memory devlist. 2292 */ 2293 static void 2294 sbd_init_mem_devlists(sbd_board_t *sbp) 2295 { 2296 dev_info_t **devlist; 2297 sbd_mem_unit_t *mp; 2298 dev_info_t *mc_dip; 2299 sbdp_handle_t *hdp; 2300 uint64_t mc_pa, lowest_pa; 2301 int i; 2302 sbd_handle_t *hp = MACHBD2HD(sbp); 2303 2304 devlist = sbp->sb_devlist[NIX(SBD_COMP_MEM)]; 2305 2306 mp = SBD_GET_BOARD_MEMUNIT(sbp, 0); 2307 2308 mc_dip = mp->sbm_dip[0]; 2309 if (mc_dip == NULL) 2310 return; /* No MC dips found for this board */ 2311 2312 hdp = sbd_get_sbdp_handle(sbp, hp); 2313 2314 if (sbdphw_get_base_physaddr(hdp, mc_dip, &mc_pa)) { 2315 /* TODO: log complaint about dnode */ 2316 2317 pretend_no_mem: 2318 /* 2319 * We are here because sbdphw_get_base_physaddr() failed. 2320 * Although it is very unlikely to happen, it did. Lucky us. 2321 * Since we can no longer examine _all_ of the MCs on this 2322 * board to determine which one is programmed to the lowest 2323 * physical address, we cannot involve any of the MCs on 2324 * this board in DR operations. To ensure this, we pretend 2325 * that this board does not contain any memory. 2326 * 2327 * Paranoia: clear the dev_present mask. 2328 */ 2329 if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_MEM, 0)) { 2330 ASSERT(sbp->sb_ndev != 0); 2331 SBD_DEV_CLR_PRESENT(sbp, SBD_COMP_MEM, 0); 2332 sbp->sb_ndev--; 2333 } 2334 2335 for (i = 0; i < SBD_NUM_MC_PER_BOARD; i++) { 2336 mp->sbm_dip[i] = NULL; 2337 } 2338 2339 sbd_release_sbdp_handle(hdp); 2340 return; 2341 } 2342 2343 /* assume this one will win. */ 2344 devlist[0] = mc_dip; 2345 mp->sbm_cm.sbdev_dip = mc_dip; 2346 lowest_pa = mc_pa; 2347 2348 /* 2349 * We know the base physical address of one of the MC devices. Now 2350 * we will enumerate through all of the remaining MC devices on 2351 * the board to find which of them is programmed to the lowest 2352 * physical address. 2353 */ 2354 for (i = 1; i < SBD_NUM_MC_PER_BOARD; i++) { 2355 mc_dip = mp->sbm_dip[i]; 2356 if (mc_dip == NULL) { 2357 break; 2358 } 2359 2360 if (sbdphw_get_base_physaddr(hdp, mc_dip, &mc_pa)) { 2361 cmn_err(CE_NOTE, "No mem on board %d unit %d", 2362 sbp->sb_num, i); 2363 break; 2364 } 2365 if (mc_pa < lowest_pa) { 2366 mp->sbm_cm.sbdev_dip = mc_dip; 2367 devlist[0] = mc_dip; 2368 lowest_pa = mc_pa; 2369 } 2370 } 2371 2372 sbd_release_sbdp_handle(hdp); 2373 } 2374 2375 static int 2376 sbd_name_to_idx(char *name) 2377 { 2378 int idx; 2379 2380 for (idx = 0; SBD_COMP(idx) != SBD_COMP_UNKNOWN; idx++) { 2381 if (strcmp(name, SBD_DEVNAME(idx)) == 0) { 2382 break; 2383 } 2384 } 2385 2386 return (idx); 2387 } 2388 2389 static int 2390 sbd_otype_to_idx(char *otype) 2391 { 2392 int idx; 2393 2394 for (idx = 0; SBD_COMP(idx) != SBD_COMP_UNKNOWN; idx++) { 2395 2396 if (strcmp(otype, SBD_OTYPE(idx)) == 0) { 2397 break; 2398 } 2399 } 2400 2401 return (idx); 2402 } 2403 2404 static int 2405 sbd_init_devlists(sbd_board_t *sbp) 2406 { 2407 int i; 2408 sbd_dev_unit_t *dp; 2409 sbd_mem_unit_t *mp; 2410 walk_tree_t *wp, walk = {0}; 2411 dev_info_t *pdip; 2412 static fn_t f = "sbd_init_devlists"; 2413 2414 PR_ALL("%s (board = %d)...\n", f, sbp->sb_num); 2415 2416 wp = &walk; 2417 2418 SBD_DEVS_DISCONNECT(sbp, (uint_t)-1); 2419 2420 /* 2421 * Clear out old entries, if any. 2422 */ 2423 2424 for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 2425 sbp->sb_devlist[NIX(SBD_COMP_MEM)][i] = NULL; 2426 dp = (sbd_dev_unit_t *)SBD_GET_BOARD_MEMUNIT(sbp, i); 2427 dp->u_common.sbdev_sbp = sbp; 2428 dp->u_common.sbdev_unum = i; 2429 dp->u_common.sbdev_type = SBD_COMP_MEM; 2430 } 2431 2432 mp = SBD_GET_BOARD_MEMUNIT(sbp, 0); 2433 ASSERT(mp != NULL); 2434 for (i = 0; i < SBD_NUM_MC_PER_BOARD; i++) { 2435 mp->sbm_dip[i] = NULL; 2436 } 2437 2438 for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) { 2439 sbp->sb_devlist[NIX(SBD_COMP_CPU)][i] = NULL; 2440 dp = (sbd_dev_unit_t *)SBD_GET_BOARD_CPUUNIT(sbp, i); 2441 dp->u_common.sbdev_sbp = sbp; 2442 dp->u_common.sbdev_unum = i; 2443 dp->u_common.sbdev_type = SBD_COMP_CPU; 2444 } 2445 for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) { 2446 sbp->sb_devlist[NIX(SBD_COMP_IO)][i] = NULL; 2447 dp = (sbd_dev_unit_t *)SBD_GET_BOARD_IOUNIT(sbp, i); 2448 dp->u_common.sbdev_sbp = sbp; 2449 dp->u_common.sbdev_unum = i; 2450 dp->u_common.sbdev_type = SBD_COMP_IO; 2451 } 2452 2453 wp->sbp = sbp; 2454 wp->nmc = 0; 2455 sbp->sb_ndev = 0; 2456 2457 /* 2458 * ddi_walk_devs() requires that topdip's parent be held. 2459 */ 2460 pdip = ddi_get_parent(sbp->sb_topdip); 2461 if (pdip) { 2462 ndi_hold_devi(pdip); 2463 ndi_devi_enter(pdip, &i); 2464 } 2465 ddi_walk_devs(sbp->sb_topdip, sbd_setup_devlists, (void *) wp); 2466 if (pdip) { 2467 ndi_devi_exit(pdip, i); 2468 ndi_rele_devi(pdip); 2469 } 2470 2471 /* 2472 * There is no point checking all the components if there 2473 * are no devices. 2474 */ 2475 if (sbp->sb_ndev == 0) { 2476 sbp->sb_memaccess_ok = 0; 2477 return (sbp->sb_ndev); 2478 } 2479 2480 /* 2481 * Initialize cpu sections before calling sbd_init_mem_devlists 2482 * which will access the mmus. 2483 */ 2484 sbp->sb_memaccess_ok = 1; 2485 for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) { 2486 if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_CPU, i)) { 2487 sbd_init_cpu_unit(sbp, i); 2488 if (sbd_connect_cpu(sbp, i)) { 2489 SBD_SET_ERR(HD2MACHERR(MACHBD2HD(sbp)), 2490 ESBD_CPUSTART); 2491 } 2492 2493 } 2494 } 2495 2496 if (sbp->sb_memaccess_ok) { 2497 sbd_init_mem_devlists(sbp); 2498 } else { 2499 cmn_err(CE_WARN, "unable to access memory on board %d", 2500 sbp->sb_num); 2501 } 2502 2503 return (sbp->sb_ndev); 2504 } 2505 2506 static void 2507 sbd_init_cpu_unit(sbd_board_t *sbp, int unit) 2508 { 2509 sbd_istate_t new_state; 2510 sbd_cpu_unit_t *cp; 2511 int cpuid; 2512 dev_info_t *dip; 2513 sbdp_handle_t *hdp; 2514 sbd_handle_t *hp = MACHBD2HD(sbp); 2515 extern kmutex_t cpu_lock; 2516 2517 if (SBD_DEV_IS_ATTACHED(sbp, SBD_COMP_CPU, unit)) { 2518 new_state = SBD_STATE_CONFIGURED; 2519 } else if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_CPU, unit)) { 2520 new_state = SBD_STATE_CONNECTED; 2521 } else { 2522 new_state = SBD_STATE_EMPTY; 2523 } 2524 2525 dip = sbp->sb_devlist[NIX(SBD_COMP_CPU)][unit]; 2526 2527 cp = SBD_GET_BOARD_CPUUNIT(sbp, unit); 2528 2529 hdp = sbd_get_sbdp_handle(sbp, hp); 2530 2531 cpuid = sbdp_get_cpuid(hdp, dip); 2532 2533 cp->sbc_cpu_id = cpuid; 2534 2535 if (&sbdp_cpu_get_impl) 2536 cp->sbc_cpu_impl = sbdp_cpu_get_impl(hdp, dip); 2537 else 2538 cp->sbc_cpu_impl = -1; 2539 2540 mutex_enter(&cpu_lock); 2541 if ((cpuid >= 0) && cpu[cpuid]) 2542 cp->sbc_cpu_flags = cpu[cpuid]->cpu_flags; 2543 else 2544 cp->sbc_cpu_flags = CPU_OFFLINE | CPU_POWEROFF; 2545 mutex_exit(&cpu_lock); 2546 2547 sbd_cpu_set_prop(cp, dip); 2548 2549 cp->sbc_cm.sbdev_cond = sbd_get_comp_cond(dip); 2550 sbd_release_sbdp_handle(hdp); 2551 2552 /* 2553 * Any changes to the cpu should be performed above 2554 * this call to ensure the cpu is fully initialized 2555 * before transitioning to the new state. 2556 */ 2557 SBD_DEVICE_TRANSITION(sbp, SBD_COMP_CPU, unit, new_state); 2558 } 2559 2560 /* 2561 * Only do work if called to operate on an entire board 2562 * which doesn't already have components present. 2563 */ 2564 static void 2565 sbd_connect(sbd_handle_t *hp) 2566 { 2567 sbd_board_t *sbp; 2568 sbderror_t *ep; 2569 static fn_t f = "sbd_connect"; 2570 2571 sbp = SBDH2BD(hp->h_sbd); 2572 2573 PR_ALL("%s board %d\n", f, sbp->sb_num); 2574 2575 ep = HD2MACHERR(hp); 2576 2577 if (SBD_DEVS_PRESENT(sbp)) { 2578 /* 2579 * Board already has devices present. 2580 */ 2581 PR_ALL("%s: devices already present (0x%x)\n", 2582 f, SBD_DEVS_PRESENT(sbp)); 2583 SBD_SET_ERRNO(ep, EINVAL); 2584 return; 2585 } 2586 2587 if (sbd_init_devlists(sbp) == 0) { 2588 cmn_err(CE_WARN, "%s: no devices present on board %d", 2589 f, sbp->sb_num); 2590 SBD_SET_ERR(ep, ESBD_NODEV); 2591 return; 2592 } else { 2593 int i; 2594 2595 /* 2596 * Initialize mem-unit section of board structure. 2597 */ 2598 for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) 2599 if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_MEM, i)) 2600 sbd_init_mem_unit(sbp, i, SBD_HD2ERR(hp)); 2601 2602 /* 2603 * Initialize sb_io sections. 2604 */ 2605 for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) 2606 if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_IO, i)) 2607 sbd_init_io_unit(sbp, i); 2608 2609 SBD_BOARD_TRANSITION(sbp, SBD_STATE_CONNECTED); 2610 sbp->sb_rstate = SBD_STAT_CONNECTED; 2611 sbp->sb_ostate = SBD_STAT_UNCONFIGURED; 2612 (void) drv_getparm(TIME, (void *)&sbp->sb_time); 2613 SBD_INJECT_ERR(SBD_CONNECT_BOARD_PSEUDO_ERR, hp->h_err, EIO, 2614 ESBD_INTERNAL, NULL); 2615 } 2616 } 2617 2618 static int 2619 sbd_disconnect(sbd_handle_t *hp) 2620 { 2621 int i; 2622 sbd_devset_t devset; 2623 sbd_board_t *sbp; 2624 static fn_t f = "sbd_disconnect it"; 2625 2626 PR_ALL("%s ...\n", f); 2627 2628 sbp = SBDH2BD(hp->h_sbd); 2629 2630 /* 2631 * Only devices which are present, but 2632 * unattached can be disconnected. 2633 */ 2634 devset = HD2MACHHD(hp)->sh_devset & SBD_DEVS_PRESENT(sbp) & 2635 SBD_DEVS_UNATTACHED(sbp); 2636 2637 ASSERT((SBD_DEVS_ATTACHED(sbp) & devset) == 0); 2638 2639 /* 2640 * Update per-device state transitions. 2641 */ 2642 2643 for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) 2644 if (DEVSET_IN_SET(devset, SBD_COMP_MEM, i)) { 2645 if (sbd_disconnect_mem(hp, i) == 0) { 2646 SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, i, 2647 SBD_STATE_EMPTY); 2648 SBD_DEV_CLR_PRESENT(sbp, SBD_COMP_MEM, i); 2649 } 2650 } 2651 2652 for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) 2653 if (DEVSET_IN_SET(devset, SBD_COMP_CPU, i)) { 2654 if (sbd_disconnect_cpu(hp, i) == 0) { 2655 SBD_DEVICE_TRANSITION(sbp, SBD_COMP_CPU, i, 2656 SBD_STATE_EMPTY); 2657 SBD_DEV_CLR_PRESENT(sbp, SBD_COMP_CPU, i); 2658 } 2659 } 2660 2661 for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) 2662 if (DEVSET_IN_SET(devset, SBD_COMP_IO, i)) { 2663 if (sbd_disconnect_io(hp, i) == 0) { 2664 SBD_DEVICE_TRANSITION(sbp, SBD_COMP_IO, i, 2665 SBD_STATE_EMPTY); 2666 SBD_DEV_CLR_PRESENT(sbp, SBD_COMP_IO, i); 2667 } 2668 } 2669 2670 /* 2671 * Once all the components on a board have been disconnect 2672 * the board's state can transition to disconnected and 2673 * we can allow the deprobe to take place. 2674 */ 2675 if (SBD_DEVS_PRESENT(sbp) == 0) { 2676 SBD_BOARD_TRANSITION(sbp, SBD_STATE_OCCUPIED); 2677 sbp->sb_rstate = SBD_STAT_DISCONNECTED; 2678 sbp->sb_ostate = SBD_STAT_UNCONFIGURED; 2679 (void) drv_getparm(TIME, (void *)&sbp->sb_time); 2680 SBD_INJECT_ERR(SBD_DISCONNECT_BOARD_PSEUDO_ERR, hp->h_err, EIO, 2681 ESBD_INTERNAL, NULL); 2682 return (0); 2683 } else { 2684 cmn_err(CE_WARN, "%s: could not disconnect devices on board %d", 2685 f, sbp->sb_num); 2686 return (-1); 2687 } 2688 } 2689 2690 static void 2691 sbd_test_board(sbd_handle_t *hp) 2692 { 2693 sbd_board_t *sbp; 2694 sbdp_handle_t *hdp; 2695 2696 sbp = SBDH2BD(hp->h_sbd); 2697 2698 PR_ALL("sbd_test_board: board %d\n", sbp->sb_num); 2699 2700 2701 hdp = sbd_get_sbdp_handle(sbp, hp); 2702 2703 if (sbdp_test_board(hdp, &hp->h_opts) != 0) { 2704 sbderror_t *ep = SBD_HD2ERR(hp); 2705 2706 SBD_GET_PERR(hdp->h_err, ep); 2707 } 2708 2709 SBD_INJECT_ERR(SBD_TEST_BOARD_PSEUDO_ERR, hp->h_err, EIO, 2710 ESBD_INTERNAL, NULL); 2711 2712 sbd_release_sbdp_handle(hdp); 2713 } 2714 2715 static void 2716 sbd_assign_board(sbd_handle_t *hp) 2717 { 2718 sbd_board_t *sbp; 2719 sbdp_handle_t *hdp; 2720 2721 sbp = SBDH2BD(hp->h_sbd); 2722 2723 PR_ALL("sbd_assign_board: board %d\n", sbp->sb_num); 2724 2725 hdp = sbd_get_sbdp_handle(sbp, hp); 2726 2727 if (sbdp_assign_board(hdp) != 0) { 2728 sbderror_t *ep = SBD_HD2ERR(hp); 2729 2730 SBD_GET_PERR(hdp->h_err, ep); 2731 } 2732 2733 SBD_INJECT_ERR(SBD_ASSIGN_BOARD_PSEUDO_ERR, hp->h_err, EIO, 2734 ESBD_INTERNAL, NULL); 2735 2736 sbd_release_sbdp_handle(hdp); 2737 } 2738 2739 static void 2740 sbd_unassign_board(sbd_handle_t *hp) 2741 { 2742 sbd_board_t *sbp; 2743 sbdp_handle_t *hdp; 2744 2745 sbp = SBDH2BD(hp->h_sbd); 2746 2747 PR_ALL("sbd_unassign_board: board %d\n", sbp->sb_num); 2748 2749 hdp = sbd_get_sbdp_handle(sbp, hp); 2750 2751 if (sbdp_unassign_board(hdp) != 0) { 2752 sbderror_t *ep = SBD_HD2ERR(hp); 2753 2754 SBD_GET_PERR(hdp->h_err, ep); 2755 } 2756 2757 SBD_INJECT_ERR(SBD_ASSIGN_BOARD_PSEUDO_ERR, hp->h_err, EIO, 2758 ESBD_INTERNAL, NULL); 2759 2760 sbd_release_sbdp_handle(hdp); 2761 } 2762 2763 static void 2764 sbd_poweron_board(sbd_handle_t *hp) 2765 { 2766 sbd_board_t *sbp; 2767 sbdp_handle_t *hdp; 2768 2769 sbp = SBDH2BD(hp->h_sbd); 2770 2771 PR_ALL("sbd_poweron_board: %d\n", sbp->sb_num); 2772 2773 hdp = sbd_get_sbdp_handle(sbp, hp); 2774 2775 if (sbdp_poweron_board(hdp) != 0) { 2776 sbderror_t *ep = SBD_HD2ERR(hp); 2777 2778 SBD_GET_PERR(hdp->h_err, ep); 2779 } 2780 2781 SBD_INJECT_ERR(SBD_POWERON_BOARD_PSEUDO_ERR, hp->h_err, EIO, 2782 ESBD_INTERNAL, NULL); 2783 2784 sbd_release_sbdp_handle(hdp); 2785 } 2786 2787 static void 2788 sbd_poweroff_board(sbd_handle_t *hp) 2789 { 2790 sbd_board_t *sbp; 2791 sbdp_handle_t *hdp; 2792 2793 sbp = SBDH2BD(hp->h_sbd); 2794 2795 PR_ALL("sbd_poweroff_board: %d\n", sbp->sb_num); 2796 2797 hdp = sbd_get_sbdp_handle(sbp, hp); 2798 2799 if (sbdp_poweroff_board(hdp) != 0) { 2800 sbderror_t *ep = SBD_HD2ERR(hp); 2801 2802 SBD_GET_PERR(hdp->h_err, ep); 2803 } 2804 2805 SBD_INJECT_ERR(SBD_POWEROFF_BOARD_PSEUDO_ERR, hp->h_err, EIO, 2806 ESBD_INTERNAL, NULL); 2807 2808 sbd_release_sbdp_handle(hdp); 2809 } 2810 2811 2812 /* 2813 * Return a list of the dip's of devices that are 2814 * either present and attached, or present only but 2815 * not yet attached for the given board. 2816 */ 2817 sbd_devlist_t * 2818 sbd_get_devlist(sbd_handle_t *hp, sbd_board_t *sbp, sbd_comp_type_t nodetype, 2819 int max_units, uint_t uset, int *count, int present_only) 2820 { 2821 int i, ix; 2822 sbd_devlist_t *ret_devlist; 2823 dev_info_t **devlist; 2824 sbdp_handle_t *hdp; 2825 2826 *count = 0; 2827 ret_devlist = GETSTRUCT(sbd_devlist_t, max_units); 2828 devlist = sbp->sb_devlist[NIX(nodetype)]; 2829 /* 2830 * Turn into binary value since we're going 2831 * to be using XOR for a comparison. 2832 * if (present_only) then 2833 * dev must be PRESENT, but NOT ATTACHED. 2834 * else 2835 * dev must be PRESENT AND ATTACHED. 2836 * endif 2837 */ 2838 if (present_only) 2839 present_only = 1; 2840 2841 hdp = sbd_get_sbdp_handle(sbp, hp); 2842 2843 for (i = ix = 0; (i < max_units) && uset; i++) { 2844 int ut, is_present, is_attached; 2845 dev_info_t *dip; 2846 sbderror_t *ep = SBD_HD2ERR(hp); 2847 int nunits, distance, j; 2848 2849 /* 2850 * For CMPs, we would like to perform DR operation on 2851 * all the cores before moving onto the next chip. 2852 * Therefore, when constructing the devlist, we process 2853 * all the cores together. 2854 */ 2855 if (nodetype == SBD_COMP_CPU) { 2856 /* 2857 * Number of units to process in the inner loop 2858 */ 2859 nunits = MAX_CORES_PER_CMP; 2860 /* 2861 * The distance between the units in the 2862 * board's sb_devlist structure. 2863 */ 2864 distance = MAX_CMP_UNITS_PER_BOARD; 2865 } else { 2866 nunits = 1; 2867 distance = 0; 2868 } 2869 2870 for (j = 0; j < nunits; j++) { 2871 if ((dip = devlist[i + j * distance]) == NULL) 2872 continue; 2873 2874 ut = sbdp_get_unit_num(hdp, dip); 2875 2876 if (ut == -1) { 2877 SBD_GET_PERR(hdp->h_err, ep); 2878 PR_ALL("sbd_get_devlist bad unit %d" 2879 " code %d errno %d", 2880 i, ep->e_code, ep->e_errno); 2881 } 2882 2883 if ((uset & (1 << ut)) == 0) 2884 continue; 2885 uset &= ~(1 << ut); 2886 is_present = SBD_DEV_IS_PRESENT(sbp, nodetype, ut) ? 2887 1 : 0; 2888 is_attached = SBD_DEV_IS_ATTACHED(sbp, nodetype, ut) ? 2889 1 : 0; 2890 2891 if (is_present && (present_only ^ is_attached)) { 2892 ret_devlist[ix].dv_dip = dip; 2893 sbd_init_err(&ret_devlist[ix].dv_error); 2894 ix++; 2895 } 2896 } 2897 } 2898 sbd_release_sbdp_handle(hdp); 2899 2900 if ((*count = ix) == 0) { 2901 FREESTRUCT(ret_devlist, sbd_devlist_t, max_units); 2902 ret_devlist = NULL; 2903 } 2904 2905 return (ret_devlist); 2906 } 2907 2908 static sbd_devlist_t * 2909 sbd_get_attach_devlist(sbd_handle_t *hp, int32_t *devnump, int32_t pass) 2910 { 2911 sbd_board_t *sbp; 2912 uint_t uset; 2913 sbd_devset_t devset; 2914 sbd_devlist_t *attach_devlist; 2915 static int next_pass = 1; 2916 static fn_t f = "sbd_get_attach_devlist"; 2917 2918 PR_ALL("%s (pass = %d)...\n", f, pass); 2919 2920 sbp = SBDH2BD(hp->h_sbd); 2921 devset = HD2MACHHD(hp)->sh_devset; 2922 2923 *devnump = 0; 2924 attach_devlist = NULL; 2925 2926 /* 2927 * We switch on next_pass for the cases where a board 2928 * does not contain a particular type of component. 2929 * In these situations we don't want to return NULL 2930 * prematurely. We need to check other devices and 2931 * we don't want to check the same type multiple times. 2932 * For example, if there were no cpus, then on pass 1 2933 * we would drop through and return the memory nodes. 2934 * However, on pass 2 we would switch back to the memory 2935 * nodes thereby returning them twice! Using next_pass 2936 * forces us down to the end (or next item). 2937 */ 2938 if (pass == 1) 2939 next_pass = 1; 2940 2941 switch (next_pass) { 2942 case 1: 2943 if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT)) { 2944 uset = DEVSET_GET_UNITSET(devset, SBD_COMP_CPU); 2945 2946 attach_devlist = sbd_get_devlist(hp, sbp, SBD_COMP_CPU, 2947 MAX_CPU_UNITS_PER_BOARD, 2948 uset, devnump, 1); 2949 2950 DEVSET_DEL(devset, SBD_COMP_CPU, DEVSET_ANYUNIT); 2951 if (!devset || attach_devlist) { 2952 next_pass = 2; 2953 return (attach_devlist); 2954 } 2955 /* 2956 * If the caller is interested in the entire 2957 * board, but there aren't any cpus, then just 2958 * fall through to check for the next component. 2959 */ 2960 } 2961 /*FALLTHROUGH*/ 2962 2963 case 2: 2964 if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT)) { 2965 uset = DEVSET_GET_UNITSET(devset, SBD_COMP_MEM); 2966 2967 attach_devlist = sbd_get_devlist(hp, sbp, SBD_COMP_MEM, 2968 MAX_MEM_UNITS_PER_BOARD, 2969 uset, devnump, 1); 2970 2971 DEVSET_DEL(devset, SBD_COMP_MEM, DEVSET_ANYUNIT); 2972 if (!devset || attach_devlist) { 2973 next_pass = 3; 2974 return (attach_devlist); 2975 } 2976 /* 2977 * If the caller is interested in the entire 2978 * board, but there isn't any memory, then 2979 * just fall through to next component. 2980 */ 2981 } 2982 /*FALLTHROUGH*/ 2983 2984 2985 case 3: 2986 next_pass = -1; 2987 if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT)) { 2988 uset = DEVSET_GET_UNITSET(devset, SBD_COMP_IO); 2989 2990 attach_devlist = sbd_get_devlist(hp, sbp, SBD_COMP_IO, 2991 MAX_IO_UNITS_PER_BOARD, 2992 uset, devnump, 1); 2993 2994 DEVSET_DEL(devset, SBD_COMP_IO, DEVSET_ANYUNIT); 2995 if (!devset || attach_devlist) { 2996 next_pass = 4; 2997 return (attach_devlist); 2998 } 2999 } 3000 /*FALLTHROUGH*/ 3001 3002 default: 3003 *devnump = 0; 3004 return (NULL); 3005 } 3006 /*NOTREACHED*/ 3007 } 3008 3009 static int 3010 sbd_pre_attach_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist, 3011 int32_t devnum) 3012 { 3013 int max_units = 0, rv = 0; 3014 sbd_comp_type_t nodetype; 3015 static fn_t f = "sbd_pre_attach_devlist"; 3016 3017 /* 3018 * In this driver, all entries in a devlist[] are 3019 * of the same nodetype. 3020 */ 3021 nodetype = sbd_get_devtype(hp, devlist->dv_dip); 3022 3023 PR_ALL("%s (nt = %s(%d), num = %d)...\n", 3024 f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum); 3025 3026 switch (nodetype) { 3027 3028 case SBD_COMP_MEM: 3029 max_units = MAX_MEM_UNITS_PER_BOARD; 3030 rv = sbd_pre_attach_mem(hp, devlist, devnum); 3031 break; 3032 3033 case SBD_COMP_CPU: 3034 max_units = MAX_CPU_UNITS_PER_BOARD; 3035 rv = sbd_pre_attach_cpu(hp, devlist, devnum); 3036 break; 3037 3038 case SBD_COMP_IO: 3039 max_units = MAX_IO_UNITS_PER_BOARD; 3040 break; 3041 3042 default: 3043 rv = -1; 3044 break; 3045 } 3046 3047 if (rv && max_units) { 3048 int i; 3049 /* 3050 * Need to clean up devlist 3051 * if pre-op is going to fail. 3052 */ 3053 for (i = 0; i < max_units; i++) { 3054 if (SBD_GET_ERRSTR(&devlist[i].dv_error)) { 3055 SBD_FREE_ERR(&devlist[i].dv_error); 3056 } else { 3057 break; 3058 } 3059 } 3060 FREESTRUCT(devlist, sbd_devlist_t, max_units); 3061 } 3062 3063 /* 3064 * If an error occurred, return "continue" 3065 * indication so that we can continue attaching 3066 * as much as possible. 3067 */ 3068 return (rv ? -1 : 0); 3069 } 3070 3071 static int 3072 sbd_post_attach_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist, 3073 int32_t devnum) 3074 { 3075 int i, max_units = 0, rv = 0; 3076 sbd_devset_t devs_unattached, devs_present; 3077 sbd_comp_type_t nodetype; 3078 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 3079 sbdp_handle_t *hdp; 3080 static fn_t f = "sbd_post_attach_devlist"; 3081 3082 sbp = SBDH2BD(hp->h_sbd); 3083 nodetype = sbd_get_devtype(hp, devlist->dv_dip); 3084 3085 PR_ALL("%s (nt = %s(%d), num = %d)...\n", 3086 f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum); 3087 3088 hdp = sbd_get_sbdp_handle(sbp, hp); 3089 3090 /* 3091 * Need to free up devlist[] created earlier in 3092 * sbd_get_attach_devlist(). 3093 */ 3094 switch (nodetype) { 3095 case SBD_COMP_CPU: 3096 max_units = MAX_CPU_UNITS_PER_BOARD; 3097 rv = sbd_post_attach_cpu(hp, devlist, devnum); 3098 break; 3099 3100 3101 case SBD_COMP_MEM: 3102 max_units = MAX_MEM_UNITS_PER_BOARD; 3103 3104 rv = sbd_post_attach_mem(hp, devlist, devnum); 3105 break; 3106 3107 case SBD_COMP_IO: 3108 max_units = MAX_IO_UNITS_PER_BOARD; 3109 break; 3110 3111 default: 3112 rv = -1; 3113 break; 3114 } 3115 3116 3117 for (i = 0; i < devnum; i++) { 3118 int unit; 3119 dev_info_t *dip; 3120 sbderror_t *ep; 3121 3122 ep = &devlist[i].dv_error; 3123 3124 if (sbd_set_err_in_hdl(hp, ep) == 0) 3125 continue; 3126 3127 dip = devlist[i].dv_dip; 3128 nodetype = sbd_get_devtype(hp, dip); 3129 unit = sbdp_get_unit_num(hdp, dip); 3130 3131 if (unit == -1) { 3132 SBD_GET_PERR(hdp->h_err, ep); 3133 continue; 3134 } 3135 3136 unit = sbd_check_unit_attached(sbp, dip, unit, nodetype, ep); 3137 3138 if (unit == -1) { 3139 PR_ALL("%s: ERROR (nt=%s, b=%d, u=%d) not attached\n", 3140 f, sbd_ct_str[(int)nodetype], sbp->sb_num, i); 3141 continue; 3142 } 3143 3144 SBD_DEV_SET_ATTACHED(sbp, nodetype, unit); 3145 SBD_DEVICE_TRANSITION(sbp, nodetype, unit, 3146 SBD_STATE_CONFIGURED); 3147 } 3148 sbd_release_sbdp_handle(hdp); 3149 3150 if (rv) { 3151 PR_ALL("%s: errno %d, ecode %d during attach\n", 3152 f, SBD_GET_ERRNO(SBD_HD2ERR(hp)), 3153 SBD_GET_ERR(HD2MACHERR(hp))); 3154 } 3155 3156 devs_present = SBD_DEVS_PRESENT(sbp); 3157 devs_unattached = SBD_DEVS_UNATTACHED(sbp); 3158 3159 switch (SBD_BOARD_STATE(sbp)) { 3160 case SBD_STATE_CONNECTED: 3161 case SBD_STATE_UNCONFIGURED: 3162 ASSERT(devs_present); 3163 3164 if (devs_unattached == 0) { 3165 /* 3166 * All devices finally attached. 3167 */ 3168 SBD_BOARD_TRANSITION(sbp, SBD_STATE_CONFIGURED); 3169 sbp->sb_rstate = SBD_STAT_CONNECTED; 3170 sbp->sb_ostate = SBD_STAT_CONFIGURED; 3171 } else if (devs_present != devs_unattached) { 3172 /* 3173 * Only some devices are fully attached. 3174 */ 3175 SBD_BOARD_TRANSITION(sbp, SBD_STATE_PARTIAL); 3176 sbp->sb_rstate = SBD_STAT_CONNECTED; 3177 sbp->sb_ostate = SBD_STAT_UNCONFIGURED; 3178 } 3179 (void) drv_getparm(TIME, (void *)&sbp->sb_time); 3180 break; 3181 3182 case SBD_STATE_PARTIAL: 3183 ASSERT(devs_present); 3184 /* 3185 * All devices finally attached. 3186 */ 3187 if (devs_unattached == 0) { 3188 SBD_BOARD_TRANSITION(sbp, SBD_STATE_CONFIGURED); 3189 sbp->sb_rstate = SBD_STAT_CONNECTED; 3190 sbp->sb_ostate = SBD_STAT_CONFIGURED; 3191 (void) drv_getparm(TIME, (void *)&sbp->sb_time); 3192 } 3193 break; 3194 3195 default: 3196 break; 3197 } 3198 3199 if (max_units && devlist) { 3200 int i; 3201 3202 for (i = 0; i < max_units; i++) { 3203 if (SBD_GET_ERRSTR(&devlist[i].dv_error)) { 3204 SBD_FREE_ERR(&devlist[i].dv_error); 3205 } else { 3206 break; 3207 } 3208 } 3209 FREESTRUCT(devlist, sbd_devlist_t, max_units); 3210 } 3211 3212 /* 3213 * Our policy is to attach all components that are 3214 * possible, thus we always return "success" on the 3215 * pre and post operations. 3216 */ 3217 return (0); 3218 } 3219 3220 /* 3221 * We only need to "release" cpu and memory devices. 3222 */ 3223 static sbd_devlist_t * 3224 sbd_get_release_devlist(sbd_handle_t *hp, int32_t *devnump, int32_t pass) 3225 { 3226 sbd_board_t *sbp; 3227 uint_t uset; 3228 sbd_devset_t devset; 3229 sbd_devlist_t *release_devlist; 3230 static int next_pass = 1; 3231 static fn_t f = "sbd_get_release_devlist"; 3232 3233 PR_ALL("%s (pass = %d)...\n", f, pass); 3234 3235 sbp = SBDH2BD(hp->h_sbd); 3236 devset = HD2MACHHD(hp)->sh_devset; 3237 3238 *devnump = 0; 3239 release_devlist = NULL; 3240 3241 /* 3242 * We switch on next_pass for the cases where a board 3243 * does not contain a particular type of component. 3244 * In these situations we don't want to return NULL 3245 * prematurely. We need to check other devices and 3246 * we don't want to check the same type multiple times. 3247 * For example, if there were no cpus, then on pass 1 3248 * we would drop through and return the memory nodes. 3249 * However, on pass 2 we would switch back to the memory 3250 * nodes thereby returning them twice! Using next_pass 3251 * forces us down to the end (or next item). 3252 */ 3253 if (pass == 1) 3254 next_pass = 1; 3255 3256 switch (next_pass) { 3257 case 1: 3258 if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT)) { 3259 uset = DEVSET_GET_UNITSET(devset, SBD_COMP_MEM); 3260 3261 release_devlist = sbd_get_devlist(hp, sbp, 3262 SBD_COMP_MEM, 3263 MAX_MEM_UNITS_PER_BOARD, 3264 uset, devnump, 0); 3265 3266 DEVSET_DEL(devset, SBD_COMP_MEM, DEVSET_ANYUNIT); 3267 if (!devset || release_devlist) { 3268 next_pass = 2; 3269 return (release_devlist); 3270 } 3271 /* 3272 * If the caller is interested in the entire 3273 * board, but there isn't any memory, then 3274 * just fall through to next component. 3275 */ 3276 } 3277 /*FALLTHROUGH*/ 3278 3279 3280 case 2: 3281 if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT)) { 3282 uset = DEVSET_GET_UNITSET(devset, SBD_COMP_CPU); 3283 3284 release_devlist = sbd_get_devlist(hp, sbp, 3285 SBD_COMP_CPU, 3286 MAX_CPU_UNITS_PER_BOARD, 3287 uset, devnump, 0); 3288 3289 DEVSET_DEL(devset, SBD_COMP_CPU, DEVSET_ANYUNIT); 3290 if (!devset || release_devlist) { 3291 next_pass = 3; 3292 return (release_devlist); 3293 } 3294 /* 3295 * If the caller is interested in the entire 3296 * board, but there aren't any cpus, then just 3297 * fall through to check for the next component. 3298 */ 3299 } 3300 /*FALLTHROUGH*/ 3301 3302 3303 case 3: 3304 next_pass = -1; 3305 if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT)) { 3306 uset = DEVSET_GET_UNITSET(devset, SBD_COMP_IO); 3307 3308 release_devlist = sbd_get_devlist(hp, sbp, 3309 SBD_COMP_IO, 3310 MAX_IO_UNITS_PER_BOARD, 3311 uset, devnump, 0); 3312 3313 DEVSET_DEL(devset, SBD_COMP_IO, DEVSET_ANYUNIT); 3314 if (!devset || release_devlist) { 3315 next_pass = 4; 3316 return (release_devlist); 3317 } 3318 } 3319 /*FALLTHROUGH*/ 3320 3321 default: 3322 *devnump = 0; 3323 return (NULL); 3324 } 3325 /*NOTREACHED*/ 3326 } 3327 3328 static int 3329 sbd_pre_release_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist, 3330 int32_t devnum) 3331 { 3332 int max_units = 0, rv = 0; 3333 sbd_comp_type_t nodetype; 3334 static fn_t f = "sbd_pre_release_devlist"; 3335 3336 nodetype = sbd_get_devtype(hp, devlist->dv_dip); 3337 3338 PR_ALL("%s (nt = %s(%d), num = %d)...\n", 3339 f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum); 3340 3341 switch (nodetype) { 3342 case SBD_COMP_CPU: { 3343 int i, mem_present = 0; 3344 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 3345 sbd_devset_t devset; 3346 sbd_priv_handle_t *shp = HD2MACHHD(hp); 3347 3348 max_units = MAX_CPU_UNITS_PER_BOARD; 3349 3350 devset = shp->sh_orig_devset; 3351 3352 for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 3353 /* 3354 * if client also requested to unconfigure memory 3355 * the we allow the operation. Therefore 3356 * we need to warranty that memory gets unconfig 3357 * before cpus 3358 */ 3359 3360 if (DEVSET_IN_SET(devset, SBD_COMP_MEM, i)) { 3361 continue; 3362 } 3363 if (SBD_DEV_IS_ATTACHED(sbp, SBD_COMP_MEM, i)) { 3364 mem_present = 1; 3365 break; 3366 } 3367 } 3368 if (mem_present) { 3369 sbderror_t *ep = SBD_HD2ERR(hp); 3370 SBD_SET_ERR(ep, ESBD_MEMONLINE); 3371 SBD_SET_ERRSTR(ep, sbp->sb_mempath[i]); 3372 rv = -1; 3373 } else { 3374 rv = sbd_pre_release_cpu(hp, devlist, devnum); 3375 } 3376 3377 break; 3378 3379 } 3380 case SBD_COMP_MEM: 3381 max_units = MAX_MEM_UNITS_PER_BOARD; 3382 rv = sbd_pre_release_mem(hp, devlist, devnum); 3383 break; 3384 3385 3386 case SBD_COMP_IO: 3387 max_units = MAX_IO_UNITS_PER_BOARD; 3388 rv = sbd_pre_release_io(hp, devlist, devnum); 3389 break; 3390 3391 default: 3392 rv = -1; 3393 break; 3394 } 3395 3396 if (rv && max_units) { 3397 int i; 3398 3399 /* 3400 * the individual pre_release component routines should 3401 * have set the error in the handle. No need to set it 3402 * here 3403 * 3404 * Need to clean up dynamically allocated devlist 3405 * if pre-op is going to fail. 3406 */ 3407 for (i = 0; i < max_units; i++) { 3408 if (SBD_GET_ERRSTR(&devlist[i].dv_error)) { 3409 SBD_FREE_ERR(&devlist[i].dv_error); 3410 } else { 3411 break; 3412 } 3413 } 3414 FREESTRUCT(devlist, sbd_devlist_t, max_units); 3415 } 3416 3417 return (rv ? -1 : 0); 3418 } 3419 3420 static int 3421 sbd_post_release_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist, 3422 int32_t devnum) 3423 { 3424 int i, max_units = 0; 3425 sbd_comp_type_t nodetype; 3426 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 3427 sbdp_handle_t *hdp; 3428 sbd_error_t *spe; 3429 static fn_t f = "sbd_post_release_devlist"; 3430 3431 nodetype = sbd_get_devtype(hp, devlist->dv_dip); 3432 ASSERT(nodetype >= SBD_COMP_CPU && nodetype <= SBD_COMP_IO); 3433 3434 PR_ALL("%s (nt = %s(%d), num = %d)...\n", 3435 f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum); 3436 3437 /* 3438 * Need to free up devlist[] created earlier in 3439 * sbd_get_release_devlist(). 3440 */ 3441 switch (nodetype) { 3442 case SBD_COMP_CPU: 3443 max_units = MAX_CPU_UNITS_PER_BOARD; 3444 break; 3445 3446 case SBD_COMP_MEM: 3447 max_units = MAX_MEM_UNITS_PER_BOARD; 3448 break; 3449 3450 case SBD_COMP_IO: 3451 /* 3452 * Need to check if specific I/O is referenced and 3453 * fail post-op. 3454 */ 3455 3456 if (sbd_check_io_refs(hp, devlist, devnum) > 0) { 3457 PR_IO("%s: error - I/O devices ref'd\n", f); 3458 } 3459 3460 max_units = MAX_IO_UNITS_PER_BOARD; 3461 break; 3462 3463 default: 3464 { 3465 cmn_err(CE_WARN, "%s: invalid nodetype (%d)", 3466 f, (int)nodetype); 3467 SBD_SET_ERR(HD2MACHERR(hp), ESBD_INVAL); 3468 } 3469 break; 3470 } 3471 hdp = sbd_get_sbdp_handle(sbp, hp); 3472 spe = hdp->h_err; 3473 3474 for (i = 0; i < devnum; i++) { 3475 int unit; 3476 sbderror_t *ep; 3477 3478 ep = &devlist[i].dv_error; 3479 3480 if (sbd_set_err_in_hdl(hp, ep) == 0) { 3481 continue; 3482 } 3483 3484 unit = sbdp_get_unit_num(hdp, devlist[i].dv_dip); 3485 if (unit == -1) { 3486 SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 3487 PR_ALL("%s bad unit num: %d code %d", 3488 f, unit, spe->e_code); 3489 continue; 3490 } 3491 } 3492 sbd_release_sbdp_handle(hdp); 3493 3494 if (SBD_GET_ERRNO(SBD_HD2ERR(hp))) { 3495 PR_ALL("%s: errno %d, ecode %d during release\n", 3496 f, SBD_GET_ERRNO(SBD_HD2ERR(hp)), 3497 SBD_GET_ERR(SBD_HD2ERR(hp))); 3498 } 3499 3500 if (max_units && devlist) { 3501 int i; 3502 3503 for (i = 0; i < max_units; i++) { 3504 if (SBD_GET_ERRSTR(&devlist[i].dv_error)) { 3505 SBD_FREE_ERR(&devlist[i].dv_error); 3506 } else { 3507 break; 3508 } 3509 } 3510 FREESTRUCT(devlist, sbd_devlist_t, max_units); 3511 } 3512 3513 return (SBD_GET_ERRNO(SBD_HD2ERR(hp)) ? -1 : 0); 3514 } 3515 3516 static void 3517 sbd_release_dev_done(sbd_board_t *sbp, sbd_comp_type_t nodetype, int unit) 3518 { 3519 SBD_DEV_SET_UNREFERENCED(sbp, nodetype, unit); 3520 SBD_DEVICE_TRANSITION(sbp, nodetype, unit, SBD_STATE_UNREFERENCED); 3521 } 3522 3523 static void 3524 sbd_release_done(sbd_handle_t *hp, sbd_comp_type_t nodetype, dev_info_t *dip) 3525 { 3526 int unit; 3527 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 3528 sbderror_t *ep; 3529 static fn_t f = "sbd_release_done"; 3530 sbdp_handle_t *hdp; 3531 3532 PR_ALL("%s...\n", f); 3533 3534 hdp = sbd_get_sbdp_handle(sbp, hp); 3535 ep = SBD_HD2ERR(hp); 3536 3537 if ((unit = sbdp_get_unit_num(hdp, dip)) < 0) { 3538 cmn_err(CE_WARN, 3539 "sbd:%s: unable to get unit for dip (0x%p)", 3540 f, (void *)dip); 3541 SBD_GET_PERR(hdp->h_err, ep); 3542 sbd_release_sbdp_handle(hdp); 3543 return; 3544 } 3545 sbd_release_sbdp_handle(hdp); 3546 3547 /* 3548 * Transfer the device which just completed its release 3549 * to the UNREFERENCED state. 3550 */ 3551 switch (nodetype) { 3552 3553 case SBD_COMP_MEM: 3554 sbd_release_mem_done((void *)hp, unit); 3555 break; 3556 3557 default: 3558 sbd_release_dev_done(sbp, nodetype, unit); 3559 break; 3560 } 3561 3562 /* 3563 * If the entire board was released and all components 3564 * unreferenced then transfer it to the UNREFERENCED state. 3565 */ 3566 if (SBD_DEVS_RELEASED(sbp) == SBD_DEVS_UNREFERENCED(sbp)) { 3567 SBD_BOARD_TRANSITION(sbp, SBD_STATE_UNREFERENCED); 3568 (void) drv_getparm(TIME, (void *)&sbp->sb_time); 3569 } 3570 } 3571 3572 static sbd_devlist_t * 3573 sbd_get_detach_devlist(sbd_handle_t *hp, int32_t *devnump, int32_t pass) 3574 { 3575 sbd_board_t *sbp; 3576 uint_t uset; 3577 sbd_devset_t devset; 3578 sbd_devlist_t *detach_devlist; 3579 static int next_pass = 1; 3580 static fn_t f = "sbd_get_detach_devlist"; 3581 3582 PR_ALL("%s (pass = %d)...\n", f, pass); 3583 3584 sbp = SBDH2BD(hp->h_sbd); 3585 devset = HD2MACHHD(hp)->sh_devset; 3586 3587 *devnump = 0; 3588 detach_devlist = NULL; 3589 3590 /* 3591 * We switch on next_pass for the cases where a board 3592 * does not contain a particular type of component. 3593 * In these situations we don't want to return NULL 3594 * prematurely. We need to check other devices and 3595 * we don't want to check the same type multiple times. 3596 * For example, if there were no cpus, then on pass 1 3597 * we would drop through and return the memory nodes. 3598 * However, on pass 2 we would switch back to the memory 3599 * nodes thereby returning them twice! Using next_pass 3600 * forces us down to the end (or next item). 3601 */ 3602 if (pass == 1) 3603 next_pass = 1; 3604 3605 switch (next_pass) { 3606 case 1: 3607 if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT)) { 3608 uset = DEVSET_GET_UNITSET(devset, SBD_COMP_MEM); 3609 3610 detach_devlist = sbd_get_devlist(hp, sbp, 3611 SBD_COMP_MEM, 3612 MAX_MEM_UNITS_PER_BOARD, 3613 uset, devnump, 0); 3614 3615 DEVSET_DEL(devset, SBD_COMP_MEM, DEVSET_ANYUNIT); 3616 if (!devset || detach_devlist) { 3617 next_pass = 2; 3618 return (detach_devlist); 3619 } 3620 /* 3621 * If the caller is interested in the entire 3622 * board, but there isn't any memory, then 3623 * just fall through to next component. 3624 */ 3625 } 3626 /*FALLTHROUGH*/ 3627 3628 case 2: 3629 if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT)) { 3630 uset = DEVSET_GET_UNITSET(devset, SBD_COMP_CPU); 3631 3632 detach_devlist = sbd_get_devlist(hp, sbp, 3633 SBD_COMP_CPU, 3634 MAX_CPU_UNITS_PER_BOARD, 3635 uset, devnump, 0); 3636 3637 DEVSET_DEL(devset, SBD_COMP_CPU, DEVSET_ANYUNIT); 3638 if (!devset || detach_devlist) { 3639 next_pass = 2; 3640 return (detach_devlist); 3641 } 3642 /* 3643 * If the caller is interested in the entire 3644 * board, but there aren't any cpus, then just 3645 * fall through to check for the next component. 3646 */ 3647 } 3648 /*FALLTHROUGH*/ 3649 3650 case 3: 3651 next_pass = -1; 3652 if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT)) { 3653 uset = DEVSET_GET_UNITSET(devset, SBD_COMP_IO); 3654 3655 detach_devlist = sbd_get_devlist(hp, sbp, 3656 SBD_COMP_IO, 3657 MAX_IO_UNITS_PER_BOARD, 3658 uset, devnump, 0); 3659 3660 DEVSET_DEL(devset, SBD_COMP_IO, DEVSET_ANYUNIT); 3661 if (!devset || detach_devlist) { 3662 next_pass = 4; 3663 return (detach_devlist); 3664 } 3665 } 3666 /*FALLTHROUGH*/ 3667 3668 default: 3669 *devnump = 0; 3670 return (NULL); 3671 } 3672 /*NOTREACHED*/ 3673 } 3674 3675 static int 3676 sbd_pre_detach_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist, 3677 int32_t devnum) 3678 { 3679 int rv = 0; 3680 sbd_comp_type_t nodetype; 3681 static fn_t f = "sbd_pre_detach_devlist"; 3682 3683 nodetype = sbd_get_devtype(hp, devlist->dv_dip); 3684 3685 PR_ALL("%s (nt = %s(%d), num = %d)...\n", 3686 f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum); 3687 3688 switch (nodetype) { 3689 case SBD_COMP_CPU: 3690 rv = sbd_pre_detach_cpu(hp, devlist, devnum); 3691 break; 3692 3693 case SBD_COMP_MEM: 3694 rv = sbd_pre_detach_mem(hp, devlist, devnum); 3695 break; 3696 3697 case SBD_COMP_IO: 3698 rv = sbd_pre_detach_io(hp, devlist, devnum); 3699 break; 3700 3701 default: 3702 rv = -1; 3703 break; 3704 } 3705 3706 /* 3707 * We want to continue attempting to detach 3708 * other components. 3709 */ 3710 return (rv); 3711 } 3712 3713 static int 3714 sbd_post_detach_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist, 3715 int32_t devnum) 3716 { 3717 int i, max_units = 0, rv = 0; 3718 sbd_comp_type_t nodetype; 3719 sbd_board_t *sbp; 3720 sbd_istate_t bstate; 3721 static fn_t f = "sbd_post_detach_devlist"; 3722 sbdp_handle_t *hdp; 3723 3724 sbp = SBDH2BD(hp->h_sbd); 3725 nodetype = sbd_get_devtype(hp, devlist->dv_dip); 3726 3727 hdp = sbd_get_sbdp_handle(sbp, hp); 3728 3729 PR_ALL("%s (nt = %s(%d), num = %d)...\n", 3730 f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum); 3731 3732 /* 3733 * Need to free up devlist[] created earlier in 3734 * sbd_get_detach_devlist(). 3735 */ 3736 switch (nodetype) { 3737 case SBD_COMP_CPU: 3738 max_units = MAX_CPU_UNITS_PER_BOARD; 3739 rv = sbd_post_detach_cpu(hp, devlist, devnum); 3740 break; 3741 3742 case SBD_COMP_MEM: 3743 max_units = MAX_MEM_UNITS_PER_BOARD; 3744 rv = sbd_post_detach_mem(hp, devlist, devnum); 3745 break; 3746 3747 case SBD_COMP_IO: 3748 max_units = MAX_IO_UNITS_PER_BOARD; 3749 rv = sbd_post_detach_io(hp, devlist, devnum); 3750 break; 3751 3752 default: 3753 rv = -1; 3754 break; 3755 } 3756 3757 3758 for (i = 0; i < devnum; i++) { 3759 int unit; 3760 sbderror_t *ep; 3761 dev_info_t *dip; 3762 3763 ep = &devlist[i].dv_error; 3764 3765 if (sbd_set_err_in_hdl(hp, ep) == 0) 3766 continue; 3767 3768 dip = devlist[i].dv_dip; 3769 unit = sbdp_get_unit_num(hdp, dip); 3770 if (unit == -1) { 3771 if (hp->h_flags & SBD_IOCTL_FLAG_FORCE) 3772 continue; 3773 else { 3774 SBD_GET_PERR(hdp->h_err, ep); 3775 break; 3776 } 3777 } 3778 nodetype = sbd_get_devtype(hp, dip); 3779 3780 if (sbd_check_unit_attached(sbp, dip, unit, nodetype, 3781 ep) >= 0) { 3782 /* 3783 * Device is still attached probably due 3784 * to an error. Need to keep track of it. 3785 */ 3786 PR_ALL("%s: ERROR (nt=%s, b=%d, u=%d) not detached\n", 3787 f, sbd_ct_str[(int)nodetype], sbp->sb_num, 3788 unit); 3789 continue; 3790 } 3791 3792 SBD_DEV_CLR_ATTACHED(sbp, nodetype, unit); 3793 SBD_DEV_CLR_RELEASED(sbp, nodetype, unit); 3794 SBD_DEV_CLR_UNREFERENCED(sbp, nodetype, unit); 3795 SBD_DEVICE_TRANSITION(sbp, nodetype, unit, 3796 SBD_STATE_UNCONFIGURED); 3797 } 3798 sbd_release_sbdp_handle(hdp); 3799 3800 bstate = SBD_BOARD_STATE(sbp); 3801 if (bstate != SBD_STATE_UNCONFIGURED) { 3802 if (SBD_DEVS_PRESENT(sbp) == SBD_DEVS_UNATTACHED(sbp)) { 3803 /* 3804 * All devices are finally detached. 3805 */ 3806 SBD_BOARD_TRANSITION(sbp, SBD_STATE_UNCONFIGURED); 3807 } else if ((SBD_BOARD_STATE(sbp) != SBD_STATE_PARTIAL) && 3808 SBD_DEVS_ATTACHED(sbp)) { 3809 /* 3810 * Some devices remain attached. 3811 */ 3812 SBD_BOARD_TRANSITION(sbp, SBD_STATE_PARTIAL); 3813 } 3814 } 3815 3816 if (rv) { 3817 PR_ALL("%s: errno %d, ecode %d during detach\n", 3818 f, SBD_GET_ERRNO(SBD_HD2ERR(hp)), 3819 SBD_GET_ERR(HD2MACHERR(hp))); 3820 } 3821 3822 if (max_units && devlist) { 3823 int i; 3824 3825 for (i = 0; i < max_units; i++) { 3826 if (SBD_GET_ERRSTR(&devlist[i].dv_error)) { 3827 SBD_FREE_ERR(&devlist[i].dv_error); 3828 } else { 3829 break; 3830 } 3831 } 3832 FREESTRUCT(devlist, sbd_devlist_t, max_units); 3833 } 3834 3835 return (SBD_GET_ERRNO(SBD_HD2ERR(hp)) ? -1 : 0); 3836 } 3837 3838 /* 3839 * Return the unit number of the respective dip if 3840 * it's found to be attached. 3841 */ 3842 static int 3843 sbd_check_unit_attached(sbd_board_t *sbp, dev_info_t *dip, int unit, 3844 sbd_comp_type_t nodetype, sbderror_t *ep) 3845 { 3846 int rv = -1; 3847 processorid_t cpuid; 3848 uint64_t basepa, endpa; 3849 struct memlist *ml; 3850 extern struct memlist *phys_install; 3851 sbdp_handle_t *hdp; 3852 sbd_handle_t *hp = MACHBD2HD(sbp); 3853 static fn_t f = "sbd_check_unit_attached"; 3854 3855 hdp = sbd_get_sbdp_handle(sbp, hp); 3856 3857 switch (nodetype) { 3858 3859 case SBD_COMP_CPU: 3860 cpuid = sbdp_get_cpuid(hdp, dip); 3861 if (cpuid < 0) { 3862 break; 3863 } 3864 mutex_enter(&cpu_lock); 3865 if (cpu_get(cpuid) != NULL) 3866 rv = unit; 3867 mutex_exit(&cpu_lock); 3868 break; 3869 3870 case SBD_COMP_MEM: 3871 if (sbdphw_get_base_physaddr(hdp, dip, &basepa)) { 3872 break; 3873 } 3874 if (sbdp_get_mem_alignment(hdp, dip, &endpa)) { 3875 cmn_err(CE_WARN, "%s sbdp_get_mem_alignment fail", f); 3876 break; 3877 } 3878 3879 basepa &= ~(endpa - 1); 3880 endpa += basepa; 3881 /* 3882 * Check if base address is in phys_install. 3883 */ 3884 memlist_read_lock(); 3885 for (ml = phys_install; ml; ml = ml->next) 3886 if ((endpa <= ml->address) || 3887 (basepa >= (ml->address + ml->size))) 3888 continue; 3889 else 3890 break; 3891 memlist_read_unlock(); 3892 if (ml != NULL) 3893 rv = unit; 3894 break; 3895 3896 case SBD_COMP_IO: 3897 { 3898 dev_info_t *tdip, *pdip; 3899 3900 tdip = dip; 3901 3902 /* 3903 * ddi_walk_devs() requires that topdip's parent be held. 3904 */ 3905 pdip = ddi_get_parent(sbp->sb_topdip); 3906 if (pdip) { 3907 ndi_hold_devi(pdip); 3908 ndi_devi_enter(pdip, &rv); 3909 } 3910 ddi_walk_devs(sbp->sb_topdip, sbd_check_io_attached, 3911 (void *)&tdip); 3912 if (pdip) { 3913 ndi_devi_exit(pdip, rv); 3914 ndi_rele_devi(pdip); 3915 } 3916 3917 if (tdip == NULL) 3918 rv = unit; 3919 else 3920 rv = -1; 3921 break; 3922 } 3923 3924 default: 3925 PR_ALL("%s: unexpected nodetype(%d) for dip 0x%p\n", 3926 f, nodetype, (void *)dip); 3927 rv = -1; 3928 break; 3929 } 3930 3931 /* 3932 * Save the error that sbdp sent us and report it 3933 */ 3934 if (rv == -1) 3935 SBD_GET_PERR(hdp->h_err, ep); 3936 3937 sbd_release_sbdp_handle(hdp); 3938 3939 return (rv); 3940 } 3941 3942 /* 3943 * Return memhandle, if in fact, this memunit is the owner of 3944 * a scheduled memory delete. 3945 */ 3946 int 3947 sbd_get_memhandle(sbd_handle_t *hp, dev_info_t *dip, memhandle_t *mhp) 3948 { 3949 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 3950 sbd_mem_unit_t *mp; 3951 sbdp_handle_t *hdp; 3952 int unit; 3953 static fn_t f = "sbd_get_memhandle"; 3954 3955 PR_MEM("%s...\n", f); 3956 3957 hdp = sbd_get_sbdp_handle(sbp, hp); 3958 3959 unit = sbdp_get_unit_num(hdp, dip); 3960 if (unit == -1) { 3961 SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 3962 sbd_release_sbdp_handle(hdp); 3963 return (-1); 3964 } 3965 sbd_release_sbdp_handle(hdp); 3966 3967 mp = SBD_GET_BOARD_MEMUNIT(sbp, unit); 3968 3969 if (mp->sbm_flags & SBD_MFLAG_RELOWNER) { 3970 *mhp = mp->sbm_memhandle; 3971 return (0); 3972 } else { 3973 SBD_SET_ERR(SBD_HD2ERR(hp), ESBD_INTERNAL); 3974 SBD_SET_ERRSTR(SBD_HD2ERR(hp), sbp->sb_mempath[unit]); 3975 return (-1); 3976 } 3977 /*NOTREACHED*/ 3978 } 3979 3980 3981 static int 3982 sbd_cpu_cnt(sbd_handle_t *hp, sbd_devset_t devset) 3983 { 3984 int c, cix; 3985 sbd_board_t *sbp; 3986 3987 sbp = SBDH2BD(hp->h_sbd); 3988 3989 /* 3990 * Only look for requested devices that are actually present. 3991 */ 3992 devset &= SBD_DEVS_PRESENT(sbp); 3993 3994 for (c = cix = 0; c < MAX_CMP_UNITS_PER_BOARD; c++) { 3995 /* 3996 * Index for core 1 , if exists. 3997 * With the current implementation it is 3998 * MAX_CMP_UNITS_PER_BOARD off from core 0. 3999 * The calculation will need to change if 4000 * the assumption is no longer true. 4001 */ 4002 int c1 = c + MAX_CMP_UNITS_PER_BOARD; 4003 4004 if (DEVSET_IN_SET(devset, SBD_COMP_CMP, c) == 0) { 4005 continue; 4006 } 4007 4008 /* 4009 * Check to see if the dip(s) exist for this chip 4010 */ 4011 if ((sbp->sb_devlist[NIX(SBD_COMP_CMP)][c] == NULL) && 4012 (sbp->sb_devlist[NIX(SBD_COMP_CMP)][c1] == NULL)) 4013 continue; 4014 4015 cix++; 4016 } 4017 4018 return (cix); 4019 } 4020 4021 static int 4022 sbd_mem_cnt(sbd_handle_t *hp, sbd_devset_t devset) 4023 { 4024 int i, ix; 4025 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 4026 4027 /* 4028 * Only look for requested devices that are actually present. 4029 */ 4030 devset &= SBD_DEVS_PRESENT(sbp); 4031 4032 for (i = ix = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 4033 dev_info_t *dip; 4034 4035 if (DEVSET_IN_SET(devset, SBD_COMP_MEM, i) == 0) { 4036 continue; 4037 } 4038 4039 dip = sbp->sb_devlist[NIX(SBD_COMP_MEM)][i]; 4040 if (dip == NULL) 4041 continue; 4042 4043 ix++; 4044 } 4045 4046 return (ix); 4047 } 4048 4049 /* 4050 * NOTE: This routine is only partially smart about multiple 4051 * mem-units. Need to make mem-status structure smart 4052 * about them also. 4053 */ 4054 static int 4055 sbd_mem_status(sbd_handle_t *hp, sbd_devset_t devset, sbd_dev_stat_t *dsp) 4056 { 4057 int m, mix, rv; 4058 memdelstat_t mdst; 4059 memquery_t mq; 4060 sbd_board_t *sbp; 4061 sbd_mem_unit_t *mp; 4062 sbd_mem_stat_t *msp; 4063 extern int kcage_on; 4064 int i; 4065 static fn_t f = "sbd_mem_status"; 4066 4067 sbp = SBDH2BD(hp->h_sbd); 4068 4069 /* 4070 * Check the present devset and access the dip with 4071 * status lock held to protect agains a concurrent 4072 * unconfigure or disconnect thread. 4073 */ 4074 mutex_enter(&sbp->sb_slock); 4075 4076 /* 4077 * Only look for requested devices that are actually present. 4078 */ 4079 devset &= SBD_DEVS_PRESENT(sbp); 4080 4081 for (m = mix = 0; m < MAX_MEM_UNITS_PER_BOARD; m++) { 4082 dev_info_t *dip; 4083 4084 4085 if (DEVSET_IN_SET(devset, SBD_COMP_MEM, m) == 0) 4086 continue; 4087 4088 /* 4089 * Check to make sure the memory unit is in a state 4090 * where its fully initialized. 4091 */ 4092 if (SBD_DEVICE_STATE(sbp, SBD_COMP_MEM, m) == SBD_STATE_EMPTY) 4093 continue; 4094 4095 dip = sbp->sb_devlist[NIX(SBD_COMP_MEM)][m]; 4096 if (dip == NULL) 4097 continue; 4098 4099 mp = SBD_GET_BOARD_MEMUNIT(sbp, m); 4100 4101 msp = &dsp->d_mem; 4102 4103 bzero((caddr_t)msp, sizeof (*msp)); 4104 msp->ms_type = SBD_COMP_MEM; 4105 4106 /* 4107 * The plugin expects -1 for the mem unit 4108 */ 4109 msp->ms_cm.c_id.c_unit = -1; 4110 4111 /* 4112 * Get the memory name from what sbdp gave us 4113 */ 4114 for (i = 0; SBD_COMP(i) != SBD_COMP_UNKNOWN; i++) { 4115 if (SBD_COMP(i) == SBD_COMP_MEM) { 4116 (void) strcpy(msp->ms_name, SBD_DEVNAME(i)); 4117 } 4118 } 4119 msp->ms_cm.c_cond = mp->sbm_cm.sbdev_cond; 4120 msp->ms_cm.c_busy = mp->sbm_cm.sbdev_busy; 4121 msp->ms_cm.c_time = mp->sbm_cm.sbdev_time; 4122 4123 /* XXX revisit this after memory conversion */ 4124 msp->ms_ostate = ostate_cvt(SBD_DEVICE_STATE( 4125 sbp, SBD_COMP_MEM, m)); 4126 4127 msp->ms_basepfn = mp->sbm_basepfn; 4128 msp->ms_pageslost = mp->sbm_pageslost; 4129 msp->ms_cage_enabled = kcage_on; 4130 msp->ms_interleave = mp->sbm_interleave; 4131 4132 if (mp->sbm_flags & SBD_MFLAG_RELOWNER) 4133 rv = kphysm_del_status(mp->sbm_memhandle, &mdst); 4134 else 4135 rv = KPHYSM_EHANDLE; /* force 'if' to fail */ 4136 4137 if (rv == KPHYSM_OK) { 4138 msp->ms_totpages += mdst.phys_pages; 4139 4140 /* 4141 * Any pages above managed is "free", 4142 * i.e. it's collected. 4143 */ 4144 msp->ms_detpages += (uint_t)(mdst.collected + 4145 mdst.phys_pages - 4146 mdst.managed); 4147 } else { 4148 msp->ms_totpages += (uint_t)mp->sbm_npages; 4149 4150 /* 4151 * If we're UNREFERENCED or UNCONFIGURED, 4152 * then the number of detached pages is 4153 * however many pages are on the board. 4154 * I.e. detached = not in use by OS. 4155 */ 4156 switch (msp->ms_cm.c_ostate) { 4157 /* 4158 * changed to use cfgadm states 4159 * 4160 * was: 4161 * case SFDR_STATE_UNREFERENCED: 4162 * case SFDR_STATE_UNCONFIGURED: 4163 */ 4164 case SBD_STAT_UNCONFIGURED: 4165 msp->ms_detpages = msp->ms_totpages; 4166 break; 4167 4168 default: 4169 break; 4170 } 4171 } 4172 4173 rv = kphysm_del_span_query(mp->sbm_basepfn, 4174 mp->sbm_npages, &mq); 4175 if (rv == KPHYSM_OK) { 4176 msp->ms_managed_pages = mq.managed; 4177 msp->ms_noreloc_pages = mq.nonrelocatable; 4178 msp->ms_noreloc_first = mq.first_nonrelocatable; 4179 msp->ms_noreloc_last = mq.last_nonrelocatable; 4180 msp->ms_cm.c_sflags = 0; 4181 if (mq.nonrelocatable) { 4182 SBD_SET_SUSPEND(SBD_CMD_UNCONFIGURE, 4183 dsp->ds_suspend); 4184 } 4185 } else { 4186 PR_MEM("%s: kphysm_del_span_query() = %d\n", f, rv); 4187 } 4188 4189 mix++; 4190 dsp++; 4191 } 4192 4193 mutex_exit(&sbp->sb_slock); 4194 4195 return (mix); 4196 } 4197 4198 static void 4199 sbd_cancel(sbd_handle_t *hp) 4200 { 4201 int i; 4202 sbd_devset_t devset; 4203 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 4204 static fn_t f = "sbd_cancel"; 4205 int rv; 4206 4207 PR_ALL("%s...\n", f); 4208 4209 /* 4210 * Only devices which have been "released" are 4211 * subject to cancellation. 4212 */ 4213 devset = HD2MACHHD(hp)->sh_devset & SBD_DEVS_UNREFERENCED(sbp); 4214 4215 /* 4216 * Nothing to do for CPUs or IO other than change back 4217 * their state. 4218 */ 4219 for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) { 4220 if (!DEVSET_IN_SET(devset, SBD_COMP_CPU, i)) 4221 continue; 4222 if (sbd_cancel_cpu(hp, i) != SBD_CPUERR_FATAL) { 4223 SBD_DEVICE_TRANSITION(sbp, SBD_COMP_CPU, i, 4224 SBD_STATE_CONFIGURED); 4225 } else { 4226 SBD_DEVICE_TRANSITION(sbp, SBD_COMP_CPU, i, 4227 SBD_STATE_FATAL); 4228 } 4229 } 4230 4231 for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) { 4232 if (!DEVSET_IN_SET(devset, SBD_COMP_IO, i)) 4233 continue; 4234 SBD_DEVICE_TRANSITION(sbp, SBD_COMP_IO, i, 4235 SBD_STATE_CONFIGURED); 4236 } 4237 4238 for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 4239 if (!DEVSET_IN_SET(devset, SBD_COMP_MEM, i)) 4240 continue; 4241 if ((rv = sbd_cancel_mem(hp, i)) == 0) { 4242 SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, i, 4243 SBD_STATE_CONFIGURED); 4244 } else if (rv == -1) { 4245 SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, i, 4246 SBD_STATE_FATAL); 4247 } 4248 } 4249 4250 PR_ALL("%s: unreleasing devset (0x%x)\n", f, (uint_t)devset); 4251 4252 SBD_DEVS_CANCEL(sbp, devset); 4253 4254 if (SBD_DEVS_UNREFERENCED(sbp) == 0) { 4255 sbd_istate_t new_state; 4256 /* 4257 * If the board no longer has any released devices 4258 * than transfer it back to the CONFIG/PARTIAL state. 4259 */ 4260 if (SBD_DEVS_ATTACHED(sbp) == SBD_DEVS_PRESENT(sbp)) 4261 new_state = SBD_STATE_CONFIGURED; 4262 else 4263 new_state = SBD_STATE_PARTIAL; 4264 if (SBD_BOARD_STATE(sbp) != new_state) { 4265 SBD_BOARD_TRANSITION(sbp, new_state); 4266 } 4267 sbp->sb_ostate = SBD_STAT_CONFIGURED; 4268 (void) drv_getparm(TIME, (void *)&sbp->sb_time); 4269 } 4270 } 4271 4272 static void 4273 sbd_get_ncm(sbd_handle_t *hp) 4274 { 4275 sbd_devset_t devset; 4276 sbd_priv_handle_t *shp = HD2MACHHD(hp); 4277 sbd_cmd_t *cmdp = (sbd_cmd_t *)hp->h_iap; 4278 int error; 4279 4280 /* pre_op restricted the devices to those selected by the ioctl */ 4281 devset = shp->sh_devset; 4282 4283 cmdp->cmd_getncm.g_ncm = sbd_cpu_cnt(hp, devset) 4284 + sbd_io_cnt(hp, devset) + sbd_mem_cnt(hp, devset); 4285 4286 error = sbd_copyout_ioarg(hp->h_mode, hp->h_cmd, cmdp, 4287 (sbd_ioctl_arg_t *)shp->sh_arg); 4288 4289 if (error != 0) 4290 SBD_SET_ERRNO(SBD_HD2ERR(hp), error); 4291 } 4292 4293 static void 4294 sbd_status(sbd_handle_t *hp) 4295 { 4296 int nstat, mode, ncm, sz, cksz; 4297 sbd_priv_handle_t *shp = HD2MACHHD(hp); 4298 sbd_devset_t devset; 4299 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 4300 sbd_stat_t *dstatp; 4301 sbd_cmd_t *cmdp = (sbd_cmd_t *)hp->h_iap; 4302 sbdp_handle_t *hdp; 4303 sbd_dev_stat_t *devstatp; 4304 4305 #ifdef _MULTI_DATAMODEL 4306 int sz32; 4307 sbd_stat32_t *dstat32p; 4308 #endif /* _MULTI_DATAMODEL */ 4309 4310 static fn_t f = "sbd_status"; 4311 4312 mode = hp->h_mode; 4313 devset = shp->sh_devset; 4314 4315 devset &= SBD_DEVS_PRESENT(sbp); 4316 4317 if (cmdp->cmd_cm.c_id.c_type == SBD_COMP_NONE) { 4318 if (cmdp->cmd_cm.c_flags & SBD_FLAG_ALLCMP) { 4319 /* 4320 * Get the number of components "ncm" on the board. 4321 * Calculate size of buffer required to store one 4322 * sbd_stat_t structure plus ncm-1 sbd_dev_stat_t 4323 * structures. Note that sbd_stat_t already contains 4324 * one sbd_dev_stat_t, so only an additional ncm-1 4325 * sbd_dev_stat_t structures need to be accounted for 4326 * in the calculation when more than one component 4327 * is present. 4328 */ 4329 ncm = sbd_cpu_cnt(hp, devset) + sbd_io_cnt(hp, devset) + 4330 sbd_mem_cnt(hp, devset); 4331 4332 } else { 4333 /* 4334 * In the case of c_type == SBD_COMP_NONE, and 4335 * SBD_FLAG_ALLCMP not specified, only the board 4336 * info is to be returned, no components. 4337 */ 4338 ncm = 0; 4339 devset = 0; 4340 } 4341 } else { 4342 /* Confirm that only one component is selected. */ 4343 ncm = sbd_cpu_cnt(hp, devset) + sbd_io_cnt(hp, devset) + 4344 sbd_mem_cnt(hp, devset); 4345 if (ncm != 1) { 4346 PR_ALL("%s: expected ncm of 1, got %d, devset 0x%x\n", 4347 f, ncm, devset); 4348 SBD_SET_ERRNO(SBD_HD2ERR(hp), EINVAL); 4349 return; 4350 } 4351 } 4352 4353 sz = sizeof (sbd_stat_t); 4354 if (ncm > 1) 4355 sz += sizeof (sbd_dev_stat_t) * (ncm - 1); 4356 4357 cksz = sz; 4358 4359 /* 4360 * s_nbytes describes the size of the preallocated user 4361 * buffer into which the application is executing to 4362 * receive the sbd_stat_t and sbd_dev_stat_t structures. 4363 * This buffer must be at least the required (sz) size. 4364 */ 4365 4366 #ifdef _MULTI_DATAMODEL 4367 4368 /* 4369 * More buffer space is required for the 64bit to 32bit 4370 * conversion of data structures. 4371 */ 4372 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 4373 sz32 = sizeof (sbd_stat32_t); 4374 if (ncm > 1) 4375 sz32 += sizeof (sbd_dev_stat32_t) * (ncm - 1); 4376 cksz = sz32; 4377 } else 4378 sz32 = 0; 4379 #endif 4380 4381 if ((int)cmdp->cmd_stat.s_nbytes < cksz) { 4382 PR_ALL("%s: ncm=%d s_nbytes = 0x%x\n", f, ncm, 4383 cmdp->cmd_stat.s_nbytes); 4384 PR_ALL("%s: expected size of 0x%x\n", f, cksz); 4385 SBD_SET_ERRNO(SBD_HD2ERR(hp), EINVAL); 4386 return; 4387 } 4388 4389 dstatp = kmem_zalloc(sz, KM_SLEEP); 4390 devstatp = &dstatp->s_stat[0]; 4391 4392 #ifdef _MULTI_DATAMODEL 4393 if (sz32 != 0) 4394 dstat32p = kmem_zalloc(sz32, KM_SLEEP); 4395 #endif 4396 4397 /* 4398 * if connected or better, provide cached status if available, 4399 * otherwise call sbdp for status 4400 */ 4401 mutex_enter(&sbp->sb_flags_mutex); 4402 switch (sbp->sb_state) { 4403 4404 case SBD_STATE_CONNECTED: 4405 case SBD_STATE_PARTIAL: 4406 case SBD_STATE_CONFIGURED: 4407 if (sbp->sb_flags & SBD_BOARD_STATUS_CACHED) { 4408 bcopy(&sbp->sb_stat, dstatp, sizeof (sbd_stat_t)); 4409 dstatp->s_rstate = rstate_cvt(sbp->sb_state); 4410 dstatp->s_ostate = ostate_cvt(sbp->sb_state); 4411 dstatp->s_busy = sbp->sb_busy; 4412 dstatp->s_time = sbp->sb_time; 4413 dstatp->s_cond = sbp->sb_cond; 4414 break; 4415 } 4416 /*FALLTHROUGH*/ 4417 4418 default: 4419 sbp->sb_flags &= ~SBD_BOARD_STATUS_CACHED; 4420 dstatp->s_board = sbp->sb_num; 4421 dstatp->s_ostate = ostate_cvt(sbp->sb_state); 4422 dstatp->s_time = sbp->sb_time; 4423 4424 hdp = sbd_get_sbdp_handle(sbp, hp); 4425 4426 if (sbdp_get_board_status(hdp, dstatp) != 0) { 4427 SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 4428 sbd_release_sbdp_handle(hdp); 4429 #ifdef _MULTI_DATAMODEL 4430 if (sz32 != 0) 4431 kmem_free(dstat32p, sz32); 4432 #endif 4433 kmem_free(dstatp, sz); 4434 mutex_exit(&sbp->sb_flags_mutex); 4435 return; 4436 } 4437 /* 4438 * Do not cache status if the busy flag has 4439 * been set by the call to sbdp_get_board_status(). 4440 */ 4441 if (!dstatp->s_busy) { 4442 /* Can get board busy flag now */ 4443 dstatp->s_busy = sbp->sb_busy; 4444 sbp->sb_cond = (sbd_cond_t)dstatp->s_cond; 4445 bcopy(dstatp, &sbp->sb_stat, 4446 sizeof (sbd_stat_t)); 4447 sbp->sb_flags |= SBD_BOARD_STATUS_CACHED; 4448 } 4449 sbd_release_sbdp_handle(hdp); 4450 break; 4451 } 4452 mutex_exit(&sbp->sb_flags_mutex); 4453 4454 if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT)) 4455 if ((nstat = sbd_cpu_flags(hp, devset, devstatp)) > 0) { 4456 dstatp->s_nstat += nstat; 4457 devstatp += nstat; 4458 } 4459 4460 if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT)) 4461 if ((nstat = sbd_mem_status(hp, devset, devstatp)) > 0) { 4462 dstatp->s_nstat += nstat; 4463 devstatp += nstat; 4464 } 4465 4466 if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT)) 4467 if ((nstat = sbd_io_status(hp, devset, devstatp)) > 0) { 4468 dstatp->s_nstat += nstat; 4469 devstatp += nstat; 4470 } 4471 4472 /* paranoia: detect buffer overrun */ 4473 if ((caddr_t)devstatp > ((caddr_t)dstatp) + sz) { 4474 PR_ALL("%s: buffer overrun\n", f); 4475 #ifdef _MULTI_DATAMODEL 4476 if (sz32 != 0) 4477 kmem_free(dstat32p, sz32); 4478 #endif 4479 kmem_free(dstatp, sz); 4480 SBD_SET_ERRNO(SBD_HD2ERR(hp), EINVAL); 4481 return; 4482 } 4483 4484 /* if necessary, move data into intermediate device status buffer */ 4485 #ifdef _MULTI_DATAMODEL 4486 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 4487 int i, j; 4488 4489 ASSERT(sz32 != 0); 4490 /* paranoia: detect buffer overrun */ 4491 if ((caddr_t)&dstat32p->s_stat[dstatp->s_nstat] > 4492 ((caddr_t)dstat32p) + sz32) { 4493 cmn_err(CE_WARN, 4494 "sbd:%s: buffer32 overrun", f); 4495 #ifdef _MULTI_DATAMODEL 4496 if (sz32 != 0) 4497 kmem_free(dstat32p, sz32); 4498 #endif 4499 kmem_free(dstatp, sz); 4500 SBD_SET_ERRNO(SBD_HD2ERR(hp), EINVAL); 4501 return; 4502 } 4503 4504 /* 4505 * initialize 32 bit sbd board status structure 4506 */ 4507 dstat32p->s_board = (int32_t)dstatp->s_board; 4508 dstat32p->s_nstat = (int32_t)dstatp->s_nstat; 4509 dstat32p->s_rstate = dstatp->s_rstate; 4510 dstat32p->s_ostate = dstatp->s_ostate; 4511 dstat32p->s_cond = dstatp->s_cond; 4512 dstat32p->s_busy = dstatp->s_busy; 4513 dstat32p->s_time = dstatp->s_time; 4514 dstat32p->s_assigned = dstatp->s_assigned; 4515 dstat32p->s_power = dstatp->s_power; 4516 dstat32p->s_platopts = (int32_t)dstatp->s_platopts; 4517 (void) strcpy(dstat32p->s_type, dstatp->s_type); 4518 4519 for (i = 0; i < dstatp->s_nstat; i++) { 4520 sbd_dev_stat_t *dsp = &dstatp->s_stat[i]; 4521 sbd_dev_stat32_t *ds32p = &dstat32p->s_stat[i]; 4522 4523 /* 4524 * copy common data for the device 4525 */ 4526 ds32p->d_cm.ci_type = (int32_t)dsp->d_cm.ci_type; 4527 ds32p->d_cm.ci_unit = (int32_t)dsp->d_cm.ci_unit; 4528 ds32p->d_cm.c_ostate = (int32_t)dsp->d_cm.c_ostate; 4529 ds32p->d_cm.c_cond = (int32_t)dsp->d_cm.c_cond; 4530 ds32p->d_cm.c_busy = (int32_t)dsp->d_cm.c_busy; 4531 ds32p->d_cm.c_time = (time32_t)dsp->d_cm.c_time; 4532 ds32p->d_cm.c_sflags = (int32_t)dsp->d_cm.c_sflags; 4533 (void) strcpy(ds32p->d_cm.ci_name, dsp->d_cm.ci_name); 4534 4535 /* copy type specific data for the device */ 4536 switch (dsp->d_cm.ci_type) { 4537 4538 case SBD_COMP_CPU: 4539 ds32p->d_cpu.cs_isbootproc = 4540 (int32_t)dsp->d_cpu.cs_isbootproc; 4541 ds32p->d_cpu.cs_cpuid = 4542 (int32_t)dsp->d_cpu.cs_cpuid; 4543 ds32p->d_cpu.cs_speed = 4544 (int32_t)dsp->d_cpu.cs_speed; 4545 ds32p->d_cpu.cs_ecache = 4546 (int32_t)dsp->d_cpu.cs_ecache; 4547 break; 4548 4549 case SBD_COMP_MEM: 4550 ds32p->d_mem.ms_type = 4551 (int32_t)dsp->d_mem.ms_type; 4552 ds32p->d_mem.ms_ostate = 4553 (int32_t)dsp->d_mem.ms_ostate; 4554 ds32p->d_mem.ms_cond = 4555 (int32_t)dsp->d_mem.ms_cond; 4556 ds32p->d_mem.ms_interleave = 4557 (uint32_t)dsp->d_mem.ms_interleave; 4558 ds32p->d_mem.ms_basepfn = 4559 (uint32_t)dsp->d_mem.ms_basepfn; 4560 ds32p->d_mem.ms_totpages = 4561 (uint32_t)dsp->d_mem.ms_totpages; 4562 ds32p->d_mem.ms_detpages = 4563 (uint32_t)dsp->d_mem.ms_detpages; 4564 ds32p->d_mem.ms_pageslost = 4565 (int32_t)dsp->d_mem.ms_pageslost; 4566 ds32p->d_mem.ms_managed_pages = 4567 (int32_t)dsp->d_mem.ms_managed_pages; 4568 ds32p->d_mem.ms_noreloc_pages = 4569 (int32_t)dsp->d_mem.ms_noreloc_pages; 4570 ds32p->d_mem.ms_noreloc_first = 4571 (int32_t)dsp->d_mem.ms_noreloc_first; 4572 ds32p->d_mem.ms_noreloc_last = 4573 (int32_t)dsp->d_mem.ms_noreloc_last; 4574 ds32p->d_mem.ms_cage_enabled = 4575 (int32_t)dsp->d_mem.ms_cage_enabled; 4576 ds32p->d_mem.ms_peer_is_target = 4577 (int32_t)dsp->d_mem.ms_peer_is_target; 4578 (void) strcpy(ds32p->d_mem.ms_peer_ap_id, 4579 dsp->d_mem.ms_peer_ap_id); 4580 break; 4581 4582 4583 case SBD_COMP_IO: 4584 4585 ds32p->d_io.is_type = 4586 (int32_t)dsp->d_io.is_type; 4587 ds32p->d_io.is_unsafe_count = 4588 (int32_t)dsp->d_io.is_unsafe_count; 4589 ds32p->d_io.is_referenced = 4590 (int32_t)dsp->d_io.is_referenced; 4591 for (j = 0; j < SBD_MAX_UNSAFE; j++) 4592 ds32p->d_io.is_unsafe_list[j] = 4593 (int32_t) 4594 ds32p->d_io.is_unsafe_list[j]; 4595 bcopy(dsp->d_io.is_pathname, 4596 ds32p->d_io.is_pathname, MAXPATHLEN); 4597 break; 4598 4599 case SBD_COMP_CMP: 4600 /* copy sbd_cmp_stat_t structure members */ 4601 bcopy(&dsp->d_cmp.ps_cpuid[0], 4602 &ds32p->d_cmp.ps_cpuid[0], 4603 sizeof (ds32p->d_cmp.ps_cpuid)); 4604 ds32p->d_cmp.ps_ncores = 4605 (int32_t)dsp->d_cmp.ps_ncores; 4606 ds32p->d_cmp.ps_speed = 4607 (int32_t)dsp->d_cmp.ps_speed; 4608 ds32p->d_cmp.ps_ecache = 4609 (int32_t)dsp->d_cmp.ps_ecache; 4610 break; 4611 4612 default: 4613 cmn_err(CE_WARN, 4614 "sbd:%s: unknown dev type (%d)", f, 4615 (int)dsp->d_cm.c_id.c_type); 4616 break; 4617 } 4618 } 4619 4620 if (ddi_copyout((void *)dstat32p, 4621 cmdp->cmd_stat.s_statp, sz32, mode) != 0) { 4622 cmn_err(CE_WARN, 4623 "sbd:%s: failed to copyout status " 4624 "for board %d", f, sbp->sb_num); 4625 SBD_SET_ERRNO(SBD_HD2ERR(hp), EFAULT); 4626 } 4627 } else 4628 #endif /* _MULTI_DATAMODEL */ 4629 if (ddi_copyout((void *)dstatp, cmdp->cmd_stat.s_statp, 4630 sz, mode) != 0) { 4631 cmn_err(CE_WARN, 4632 "sbd:%s: failed to copyout status for board %d", 4633 f, sbp->sb_num); 4634 SBD_SET_ERRNO(SBD_HD2ERR(hp), EFAULT); 4635 } 4636 4637 #ifdef _MULTI_DATAMODEL 4638 if (sz32 != 0) 4639 kmem_free(dstat32p, sz32); 4640 #endif 4641 kmem_free(dstatp, sz); 4642 } 4643 4644 /* 4645 * Called at driver load time to determine the state and condition 4646 * of an existing board in the system. 4647 */ 4648 static void 4649 sbd_board_discovery(sbd_board_t *sbp) 4650 { 4651 int i; 4652 dev_info_t *dip; 4653 sbd_devset_t devs_lost, devs_attached = 0; 4654 extern kmutex_t cpu_lock; 4655 sbdp_handle_t *hdp; 4656 static fn_t f = "sbd_board_discovery"; 4657 sbderror_t error, *ep; 4658 sbd_handle_t *hp = MACHBD2HD(sbp); 4659 4660 if (SBD_DEVS_PRESENT(sbp) == 0) { 4661 PR_ALL("%s: board %d has no devices present\n", 4662 f, sbp->sb_num); 4663 return; 4664 } 4665 4666 ep = &error; 4667 bzero(ep, sizeof (sbderror_t)); 4668 4669 /* 4670 * Check for existence of cpus. 4671 */ 4672 4673 hdp = sbd_get_sbdp_handle(sbp, hp); 4674 4675 for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) { 4676 processorid_t cpuid; 4677 4678 if (!SBD_DEV_IS_PRESENT(sbp, SBD_COMP_CPU, i)) 4679 continue; 4680 4681 dip = sbp->sb_devlist[NIX(SBD_COMP_CPU)][i]; 4682 4683 if (dip != NULL) { 4684 cpuid = sbdp_get_cpuid(hdp, dip); 4685 4686 if (cpuid < 0) { 4687 SBD_GET_PERR(hdp->h_err, 4688 ep); 4689 continue; 4690 } 4691 4692 mutex_enter(&cpu_lock); /* needed to call cpu_get() */ 4693 if (cpu_get(cpuid)) { 4694 SBD_DEV_SET_ATTACHED(sbp, SBD_COMP_CPU, i); 4695 DEVSET_ADD(devs_attached, SBD_COMP_CPU, i); 4696 PR_ALL("%s: board %d, cpuid %d - attached\n", 4697 f, sbp->sb_num, cpuid); 4698 } 4699 mutex_exit(&cpu_lock); 4700 sbd_init_cpu_unit(sbp, i); 4701 } 4702 } 4703 4704 /* 4705 * Check for existence of memory. 4706 */ 4707 for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 4708 uint64_t basepa, endpa; 4709 struct memlist *ml; 4710 extern struct memlist *phys_install; 4711 4712 if (!SBD_DEV_IS_PRESENT(sbp, SBD_COMP_MEM, i)) 4713 continue; 4714 4715 dip = sbp->sb_devlist[NIX(SBD_COMP_MEM)][i]; 4716 if (dip == NULL) 4717 continue; 4718 4719 if (sbdphw_get_base_physaddr(hdp, dip, &basepa)) { 4720 /* omit phantom memory controllers on I/O boards */ 4721 if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_MEM, i)) { 4722 ASSERT(sbp->sb_ndev != 0); 4723 SBD_DEV_CLR_PRESENT(sbp, SBD_COMP_MEM, i); 4724 sbp->sb_ndev--; 4725 } 4726 sbp->sb_devlist[NIX(SBD_COMP_MEM)][i] = NULL; 4727 continue; 4728 } 4729 4730 /* 4731 * basepa may not be on a alignment boundary, make it so. 4732 */ 4733 if (sbdp_get_mem_alignment(hdp, dip, &endpa)) { 4734 cmn_err(CE_WARN, "%s sbdp_get_mem_alignment fail", f); 4735 continue; 4736 } 4737 4738 basepa &= ~(endpa - 1); 4739 endpa += basepa; 4740 4741 /* 4742 * Check if base address is in phys_install. 4743 */ 4744 memlist_read_lock(); 4745 for (ml = phys_install; ml; ml = ml->next) 4746 if ((endpa <= ml->address) || 4747 (basepa >= (ml->address + ml->size))) 4748 continue; 4749 else 4750 break; 4751 memlist_read_unlock(); 4752 4753 if (ml) { 4754 SBD_DEV_SET_ATTACHED(sbp, SBD_COMP_MEM, i); 4755 DEVSET_ADD(devs_attached, SBD_COMP_MEM, i); 4756 PR_ALL("%s: board %d, mem-unit %d - attached\n", 4757 f, sbp->sb_num, i); 4758 } 4759 sbd_init_mem_unit(sbp, i, ep); 4760 } 4761 sbd_release_sbdp_handle(hdp); 4762 4763 /* 4764 * If so far we have found an error, we just log it but continue 4765 */ 4766 if (SBD_GET_ERRNO(ep) != 0) 4767 cmn_err(CE_WARN, "%s errno has occurred: errno %d", f, 4768 SBD_GET_ERRNO(ep)); 4769 4770 /* 4771 * Check for i/o state. 4772 */ 4773 for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) { 4774 4775 if (!SBD_DEV_IS_PRESENT(sbp, SBD_COMP_IO, i)) 4776 continue; 4777 4778 dip = sbp->sb_devlist[NIX(SBD_COMP_IO)][i]; 4779 if (dip == NULL) 4780 continue; 4781 4782 ASSERT(e_ddi_branch_held(dip)); 4783 4784 /* 4785 * XXX Is the devstate check needed ? 4786 */ 4787 if (i_ddi_devi_attached(dip) || 4788 ddi_get_devstate(dip) == DDI_DEVSTATE_UP) { 4789 4790 /* 4791 * Found it! 4792 */ 4793 SBD_DEV_SET_ATTACHED(sbp, SBD_COMP_IO, i); 4794 DEVSET_ADD(devs_attached, SBD_COMP_IO, i); 4795 PR_ALL("%s: board %d, io-unit %d - attached\n", 4796 f, sbp->sb_num, i); 4797 } 4798 sbd_init_io_unit(sbp, i); 4799 } 4800 4801 SBD_DEVS_CONFIGURE(sbp, devs_attached); 4802 if (devs_attached && ((devs_lost = SBD_DEVS_UNATTACHED(sbp)) != 0)) { 4803 int ut; 4804 /* 4805 * A prior comment stated that a partially configured 4806 * board was not permitted. The Serengeti architecture 4807 * makes this possible, so the SB_DEVS_DISCONNECT 4808 * at the end of this block has been removed. 4809 */ 4810 4811 PR_ALL("%s: some devices not configured (0x%x)...\n", 4812 f, devs_lost); 4813 4814 for (ut = 0; ut < MAX_CPU_UNITS_PER_BOARD; ut++) 4815 if (DEVSET_IN_SET(devs_lost, SBD_COMP_CPU, ut)) { 4816 SBD_DEVICE_TRANSITION(sbp, SBD_COMP_CPU, 4817 ut, SBD_STATE_UNCONFIGURED); 4818 } 4819 4820 for (ut = 0; ut < MAX_MEM_UNITS_PER_BOARD; ut++) 4821 if (DEVSET_IN_SET(devs_lost, SBD_COMP_MEM, ut)) { 4822 SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, 4823 ut, SBD_STATE_UNCONFIGURED); 4824 } 4825 4826 for (ut = 0; ut < MAX_IO_UNITS_PER_BOARD; ut++) 4827 if (DEVSET_IN_SET(devs_lost, SBD_COMP_IO, ut)) { 4828 SBD_DEVICE_TRANSITION(sbp, SBD_COMP_IO, 4829 ut, SBD_STATE_UNCONFIGURED); 4830 } 4831 } 4832 } 4833 4834 static int 4835 hold_rele_branch(dev_info_t *rdip, void *arg) 4836 { 4837 walk_tree_t *wp = (walk_tree_t *)arg; 4838 4839 ASSERT(wp && (wp->hold == 0 || wp->hold == 1)); 4840 4841 switch (get_node_type(wp->sbp, rdip, NULL)) { 4842 case SBD_COMP_CMP: 4843 case SBD_COMP_MEM: 4844 case SBD_COMP_IO: 4845 break; 4846 case SBD_COMP_CPU: 4847 4848 /* 4849 * All CPU nodes under CMP nodes should have 4850 * gotten pruned when the CMP node was first 4851 * encountered. 4852 */ 4853 ASSERT(!sbd_is_cmp_child(rdip)); 4854 4855 break; 4856 4857 case SBD_COMP_UNKNOWN: 4858 /* Not of interest to us */ 4859 return (DDI_WALK_CONTINUE); 4860 default: 4861 ASSERT(0); 4862 return (DDI_WALK_PRUNECHILD); 4863 } 4864 4865 if (wp->hold) { 4866 ASSERT(!e_ddi_branch_held(rdip)); 4867 e_ddi_branch_hold(rdip); 4868 } else { 4869 ASSERT(e_ddi_branch_held(rdip)); 4870 e_ddi_branch_rele(rdip); 4871 } 4872 4873 return (DDI_WALK_PRUNECHILD); 4874 } 4875 4876 static void 4877 sbd_board_init(sbd_board_t *sbp, sbd_softstate_t *softsp, 4878 int bd, dev_info_t *top_dip, int wnode) 4879 { 4880 int i; 4881 dev_info_t *pdip; 4882 int circ; 4883 walk_tree_t walk = {0}; 4884 4885 mutex_init(&sbp->sb_mutex, NULL, MUTEX_DRIVER, NULL); 4886 mutex_init(&sbp->sb_flags_mutex, NULL, MUTEX_DRIVER, NULL); 4887 mutex_init(&sbp->sb_slock, NULL, MUTEX_DRIVER, NULL); 4888 4889 sbp->sb_ref = 0; 4890 sbp->sb_num = bd; 4891 sbp->sb_time = gethrestime_sec(); 4892 /* 4893 * For serengeti, top_dip doesn't need to be held because 4894 * sbp i.e. sbd_board_t will be destroyed in sbd_teardown_instance() 4895 * before top_dip detaches. For Daktari, top_dip is the 4896 * root node which never has to be held. 4897 */ 4898 sbp->sb_topdip = top_dip; 4899 sbp->sb_cpuid = -1; 4900 sbp->sb_softsp = (void *) softsp; 4901 sbp->sb_cond = SBD_COND_UNKNOWN; 4902 sbp->sb_wnode = wnode; 4903 sbp->sb_memaccess_ok = 1; 4904 4905 ASSERT(MAX_IO_UNITS_PER_BOARD <= SBD_MAX_UNITS_PER_BOARD); 4906 ASSERT(MAX_CPU_UNITS_PER_BOARD <= SBD_MAX_UNITS_PER_BOARD); 4907 ASSERT(MAX_MEM_UNITS_PER_BOARD <= SBD_MAX_UNITS_PER_BOARD); 4908 4909 /* 4910 * Allocate the devlist for cpus. 4911 */ 4912 sbp->sb_devlist[NIX(SBD_COMP_CPU)] = GETSTRUCT(dev_info_t *, 4913 MAX_CPU_UNITS_PER_BOARD); 4914 4915 /* 4916 * Allocate the devlist for mem. 4917 */ 4918 sbp->sb_devlist[NIX(SBD_COMP_MEM)] = GETSTRUCT(dev_info_t *, 4919 MAX_MEM_UNITS_PER_BOARD); 4920 4921 /* 4922 * Allocate the devlist for io. 4923 */ 4924 sbp->sb_devlist[NIX(SBD_COMP_IO)] = GETSTRUCT(dev_info_t *, 4925 MAX_IO_UNITS_PER_BOARD); 4926 4927 4928 sbp->sb_dev[NIX(SBD_COMP_CPU)] = GETSTRUCT(sbd_dev_unit_t, 4929 MAX_CPU_UNITS_PER_BOARD); 4930 4931 sbp->sb_dev[NIX(SBD_COMP_MEM)] = GETSTRUCT(sbd_dev_unit_t, 4932 MAX_MEM_UNITS_PER_BOARD); 4933 4934 sbp->sb_dev[NIX(SBD_COMP_IO)] = GETSTRUCT(sbd_dev_unit_t, 4935 MAX_IO_UNITS_PER_BOARD); 4936 4937 for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) { 4938 sbp->sb_cpupath[i] = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 4939 } 4940 4941 for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 4942 sbp->sb_mempath[i] = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 4943 } 4944 4945 for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) { 4946 sbp->sb_iopath[i] = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 4947 } 4948 4949 /* 4950 * Walk the device tree, find all top dips on this board and 4951 * hold the branches rooted at them 4952 */ 4953 ASSERT(sbp->sb_topdip); 4954 pdip = ddi_get_parent(sbp->sb_topdip); 4955 if (pdip) 4956 ndi_devi_enter(pdip, &circ); 4957 walk.sbp = sbp; 4958 walk.hold = 1; 4959 ddi_walk_devs(sbp->sb_topdip, hold_rele_branch, (void *)&walk); 4960 if (pdip) 4961 ndi_devi_exit(pdip, circ); 4962 4963 /* 4964 * Initialize the devlists 4965 */ 4966 if (sbd_init_devlists(sbp) == 0) { 4967 SBD_BOARD_TRANSITION(sbp, SBD_STATE_EMPTY); 4968 } else { 4969 /* 4970 * Couldn't have made it down here without 4971 * having found at least one device. 4972 */ 4973 ASSERT(SBD_DEVS_PRESENT(sbp) != 0); 4974 /* 4975 * Check the state of any possible devices on the 4976 * board. 4977 */ 4978 sbd_board_discovery(sbp); 4979 4980 if (SBD_DEVS_UNATTACHED(sbp) == 0) { 4981 /* 4982 * The board has no unattached devices, therefore 4983 * by reason of insanity it must be configured! 4984 */ 4985 SBD_BOARD_TRANSITION(sbp, SBD_STATE_CONFIGURED); 4986 sbp->sb_cond = SBD_COND_OK; 4987 } else if (SBD_DEVS_ATTACHED(sbp)) { 4988 SBD_BOARD_TRANSITION(sbp, SBD_STATE_PARTIAL); 4989 } else { 4990 SBD_BOARD_TRANSITION(sbp, SBD_STATE_CONNECTED); 4991 } 4992 } 4993 } 4994 4995 static void 4996 sbd_board_destroy(sbd_board_t *sbp) 4997 { 4998 int i; 4999 dev_info_t *pdip; 5000 int circ; 5001 walk_tree_t walk = {0}; 5002 5003 SBD_BOARD_TRANSITION(sbp, SBD_STATE_EMPTY); 5004 5005 #ifdef DEBUG 5006 for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 5007 sbd_mem_unit_t *mp; 5008 5009 mp = SBD_GET_BOARD_MEMUNIT(sbp, i); 5010 ASSERT(mp->sbm_mlist == NULL); 5011 } 5012 #endif /* DEBUG */ 5013 5014 /* 5015 * Free up MEM unit structs. 5016 */ 5017 FREESTRUCT(sbp->sb_dev[NIX(SBD_COMP_MEM)], 5018 sbd_dev_unit_t, MAX_MEM_UNITS_PER_BOARD); 5019 sbp->sb_dev[NIX(SBD_COMP_MEM)] = NULL; 5020 5021 /* 5022 * Free up CPU unit structs. 5023 */ 5024 FREESTRUCT(sbp->sb_dev[NIX(SBD_COMP_CPU)], 5025 sbd_dev_unit_t, MAX_CPU_UNITS_PER_BOARD); 5026 sbp->sb_dev[NIX(SBD_COMP_CPU)] = NULL; 5027 5028 /* 5029 * Free up IO unit structs. 5030 */ 5031 FREESTRUCT(sbp->sb_dev[NIX(SBD_COMP_IO)], 5032 sbd_dev_unit_t, MAX_IO_UNITS_PER_BOARD); 5033 sbp->sb_dev[NIX(SBD_COMP_IO)] = NULL; 5034 5035 /* 5036 * free up CPU devlists. 5037 */ 5038 5039 for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) { 5040 kmem_free((caddr_t)sbp->sb_cpupath[i], MAXPATHLEN); 5041 } 5042 FREESTRUCT(sbp->sb_devlist[NIX(SBD_COMP_CPU)], dev_info_t *, 5043 MAX_CPU_UNITS_PER_BOARD); 5044 sbp->sb_devlist[NIX(SBD_COMP_CPU)] = NULL; 5045 5046 /* 5047 * free up MEM devlists. 5048 */ 5049 for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 5050 kmem_free((caddr_t)sbp->sb_mempath[i], MAXPATHLEN); 5051 } 5052 FREESTRUCT(sbp->sb_devlist[NIX(SBD_COMP_MEM)], dev_info_t *, 5053 MAX_MEM_UNITS_PER_BOARD); 5054 sbp->sb_devlist[NIX(SBD_COMP_MEM)] = NULL; 5055 5056 /* 5057 * free up IO devlists. 5058 */ 5059 for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) { 5060 kmem_free((caddr_t)sbp->sb_iopath[i], MAXPATHLEN); 5061 } 5062 FREESTRUCT(sbp->sb_devlist[NIX(SBD_COMP_IO)], dev_info_t *, 5063 MAX_IO_UNITS_PER_BOARD); 5064 sbp->sb_devlist[NIX(SBD_COMP_IO)] = NULL; 5065 5066 /* 5067 * Release all branches held earlier 5068 */ 5069 ASSERT(sbp->sb_topdip); 5070 pdip = ddi_get_parent(sbp->sb_topdip); 5071 if (pdip) 5072 ndi_devi_enter(pdip, &circ); 5073 walk.sbp = sbp; 5074 walk.hold = 0; 5075 ddi_walk_devs(sbp->sb_topdip, hold_rele_branch, (void *)&walk); 5076 if (pdip) 5077 ndi_devi_exit(pdip, circ); 5078 5079 mutex_destroy(&sbp->sb_slock); 5080 mutex_destroy(&sbp->sb_flags_mutex); 5081 mutex_destroy(&sbp->sb_mutex); 5082 } 5083 5084 sbd_comp_type_t 5085 sbd_cm_type(char *name) 5086 { 5087 sbd_comp_type_t type = SBD_COMP_UNKNOWN; 5088 int i; 5089 5090 /* look up type in table */ 5091 for (i = 0; SBD_COMP(i) != SBD_COMP_UNKNOWN; i++) { 5092 if (strcmp(name, SBD_OTYPE(i)) == 0) { 5093 type = SBD_COMP(i); 5094 break; 5095 } 5096 } 5097 5098 return (type); 5099 } 5100 5101 /* 5102 * There are certain cases where obp marks components as failed 5103 * If the status is ok the node won't have any status property. It 5104 * is only there if the status is other than ok. 5105 * 5106 * The translation is as follows: 5107 * If there is no status prop, the the cond is SBD_COND_OK 5108 * If we find a status prop but can't get to it then cond is SBD_COND_UNKNOWN 5109 * if we find a stat and it is failed the cond is SBD_COND_FAILED 5110 * If the stat is disabled, the cond is SBD_COND_UNUSABLE 5111 * Otherwise we return con as SBD_COND_OK 5112 */ 5113 sbd_cond_t 5114 sbd_get_comp_cond(dev_info_t *dip) 5115 { 5116 int len; 5117 char *status_buf; 5118 static const char *status = "status"; 5119 static const char *failed = "fail"; 5120 static const char *disabled = "disabled"; 5121 5122 if (dip == NULL) { 5123 PR_BYP("dip is NULL\n"); 5124 return (SBD_COND_UNKNOWN); 5125 } 5126 5127 if (ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 5128 (char *)status, &len) != DDI_PROP_SUCCESS) { 5129 PR_CPU("status in sbd is ok\n"); 5130 return (SBD_COND_OK); 5131 } 5132 5133 status_buf = kmem_zalloc(sizeof (char) * OBP_MAXPROPNAME, KM_SLEEP); 5134 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 5135 (char *)status, status_buf, &len) != DDI_PROP_SUCCESS) { 5136 PR_CPU("status in sbd is unknown\n"); 5137 return (SBD_COND_UNKNOWN); 5138 } 5139 5140 if (strncmp(status_buf, failed, strlen(failed)) == 0) { 5141 PR_CPU("status in sbd is failed\n"); 5142 kmem_free(status_buf, sizeof (char) * OBP_MAXPROPNAME); 5143 return (SBD_COND_FAILED); 5144 } 5145 5146 if (strcmp(status_buf, disabled) == 0) { 5147 PR_CPU("status in sbd is unusable\n"); 5148 kmem_free(status_buf, sizeof (char) * OBP_MAXPROPNAME); 5149 return (SBD_COND_UNUSABLE); 5150 } 5151 5152 kmem_free(status_buf, sizeof (char) * OBP_MAXPROPNAME); 5153 return (SBD_COND_OK); 5154 } 5155 5156 #ifdef SBD_DEBUG_ERRS 5157 5158 /* function to simulate errors throughout the sbd code */ 5159 void 5160 sbd_inject_err(int error, sbderror_t *ep, int Errno, int ecode, 5161 char *rsc) 5162 { 5163 static fn_t f = "sbd_inject_err"; 5164 5165 if (sbd_err_debug == 0) 5166 return; 5167 5168 if (ep == NULL) { 5169 cmn_err(CE_WARN, "%s ep is NULL", f); 5170 return; 5171 } 5172 5173 if (SBD_GET_ERRNO(ep) != 0) { 5174 cmn_err(CE_WARN, "%s errno already set to %d", f, 5175 SBD_GET_ERRNO(ep)); 5176 return; 5177 } 5178 5179 if (SBD_GET_ERR(ep) != 0) { 5180 cmn_err(CE_WARN, "%s code already set to %d", f, 5181 SBD_GET_ERR(ep)); 5182 return; 5183 } 5184 5185 if ((sbd_err_debug & (1 << error)) != 0) { 5186 ep->e_errno = Errno; 5187 ep->e_code = ecode; 5188 5189 if (rsc != NULL) 5190 bcopy((caddr_t)rsc, 5191 (caddr_t)ep->e_rsc, 5192 sizeof (ep->e_rsc)); 5193 5194 if (Errno != 0) 5195 PR_ERR_ERRNO("%s set errno to %d", f, ep->e_errno); 5196 5197 if (ecode != 0) 5198 PR_ERR_ECODE("%s set ecode to %d", f, ep->e_code); 5199 5200 if (rsc != NULL) 5201 PR_ERR_RSC("%s set rsc to %s", f, ep->e_rsc); 5202 } 5203 } 5204 #endif 5205