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