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 #include <sys/types.h> 28 #include <sys/cmn_err.h> 29 #include <sys/conf.h> 30 #include <sys/ddi_impldefs.h> 31 #include <sys/autoconf.h> 32 #include <sys/systm.h> 33 #include <sys/modctl.h> 34 #include <sys/ddi.h> 35 #include <sys/sunddi.h> 36 #include <sys/sunndi.h> 37 #include <sys/ndi_impldefs.h> 38 #include <sys/promif.h> 39 #include <sys/stat.h> 40 #include <sys/kmem.h> 41 #include <sys/promif.h> 42 #include <sys/conf.h> 43 #include <sys/obpdefs.h> 44 #include <sys/cpuvar.h> 45 #include <vm/seg_kmem.h> 46 #include <sys/prom_plat.h> 47 #include <sys/machsystm.h> 48 #include <sys/note.h> 49 #include <sys/memlist.h> 50 #include <sys/ssm.h> 51 52 #include <sys/sbd_ioctl.h> 53 #include <sys/sbd.h> 54 #include <sys/sbdp_priv.h> 55 #include <sys/sbdp_mem.h> 56 #include <sys/sbdp_error.h> 57 #include <sys/serengeti.h> 58 59 #include <sys/sgsbbc.h> /* To get fn_t type definition */ 60 61 /* 62 * Config information 63 */ 64 #ifdef DEBUG 65 uint_t sbdp_debug = 0x0; 66 #endif /* DEBUG */ 67 68 /* 69 * Enable or disable dr 70 */ 71 int sbdp_dr_available = 1; 72 73 /* name properties for some Serengeti device nodes */ 74 #define CMP_DEVNAME "cmp" 75 #define MEM_DEVNAME "memory" 76 #define CPU_DEVNAME "cpu" 77 #define IO_PCI_DEVNAME "pci" 78 #define IO_SGHSC_DEVNAME "sghsc" 79 #define IO_WCI_DEVNAME "wci" 80 81 static sbd_devattr_t sbdp_devattr[] = { 82 { CMP_DEVNAME, "cmp", SBD_COMP_CMP }, 83 { MEM_DEVNAME, "memory-controller", SBD_COMP_MEM }, 84 { CPU_DEVNAME, "cpu", SBD_COMP_CPU }, 85 { IO_PCI_DEVNAME, "pci", SBD_COMP_IO }, 86 { IO_SGHSC_DEVNAME, "sghsc", SBD_COMP_IO }, 87 { IO_WCI_DEVNAME, "wci", SBD_COMP_IO }, 88 /* last item must be blank */ 89 { NULL, NULL, SBD_COMP_UNKNOWN } 90 }; 91 92 /* 93 * In the case of a busy mbox, if a status cmd comes in we return a cached 94 * copy. This cache is a link list of wnodes that contains bd structs with 95 * the appropriate info. When a new wnode is created a whole entry is added 96 * to the list. 97 */ 98 sbdp_wnode_t *first_node = NULL; /* first wnode. Entry to the link list */ 99 int cur_num_wnodes = 0; /* how many nodes are currently running */ 100 101 /* Macros to access fields in the previous array */ 102 #define SBDP_CT(i) sbdp_devattr[i].s_dnodetype 103 #define SBDP_DEVNAME(i) sbdp_devattr[(i)].s_devname 104 #define SBDP_OTYPE(i) sbdp_devattr[(i)].s_obp_type 105 106 /* 107 * Prototypes 108 */ 109 sbdp_wnode_t *sbdp_get_wnodep(int); 110 111 /* 112 * Module linkage information for the kernel. 113 */ 114 115 static struct modlmisc modlmisc = { 116 &mod_miscops, 117 "Serengeti sbdp", 118 }; 119 120 static struct modlinkage modlinkage = { 121 MODREV_1, 122 (void *)&modlmisc, 123 NULL 124 }; 125 126 /* 127 * VA area used during CPU shutdown. 128 */ 129 caddr_t sbdp_shutdown_va; 130 131 /* 132 * Mutex to protect our inventory 133 */ 134 kmutex_t sbdp_wnode_mutex; 135 136 int 137 _init(void) 138 { 139 int e; 140 141 e = mod_install(&modlinkage); 142 if (e != 0) 143 return (e); 144 145 sbdp_shutdown_va = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP); 146 ASSERT(sbdp_shutdown_va != NULL); 147 sbdp_valp = (uint64_t *)vmem_alloc(static_alloc_arena, 148 sizeof (uint64_t), VM_SLEEP); 149 150 mutex_init(&sbdp_wnode_mutex, NULL, MUTEX_DRIVER, NULL); 151 return (e); 152 } 153 154 int 155 _fini(void) 156 { 157 int e; 158 159 /* 160 * Remove the module. 161 */ 162 e = mod_remove(&modlinkage); 163 if (e != 0) 164 return (e); 165 166 vmem_free(heap_arena, sbdp_shutdown_va, PAGESIZE); 167 sbdp_shutdown_va = NULL; 168 vmem_free(static_alloc_arena, (void *)sbdp_valp, sizeof (uint64_t)); 169 sbdp_valp = NULL; 170 171 mutex_destroy(&sbdp_wnode_mutex); 172 return (e); 173 } 174 175 int 176 _info(struct modinfo *modinfop) 177 { 178 return (mod_info(&modlinkage, modinfop)); 179 } 180 181 int 182 sbdp_get_bd_and_wnode_num(pnode_t nodeid, int *bd, int *wnode) 183 { 184 int portid; 185 static fn_t f = "sbdp_get_bd_and_wnode_num"; 186 extern int get_portid(pnode_t node, pnode_t *cmpp); 187 188 SBDP_DBG_FUNC("%s\n", f); 189 190 if (sbdp_is_node_bad(nodeid)) 191 return (-1); 192 193 if ((portid = get_portid(nodeid, NULL)) == -1) 194 return (-1); 195 196 /* 197 * decode the board number 198 */ 199 *bd = SG_PORTID_TO_BOARD_NUM(portid); 200 *wnode = SG_PORTID_TO_NODEID(portid); 201 202 return (0); 203 } 204 205 int 206 sbdp_get_board_num(sbdp_handle_t *hp, dev_info_t *dip) 207 { 208 _NOTE(ARGUNUSED(hp)) 209 210 pnode_t nodeid; 211 int bd, wnode; 212 static fn_t f = "sbdp_get_board_num"; 213 214 SBDP_DBG_FUNC("%s\n", f); 215 216 if (dip == NULL) 217 return (-1); 218 219 nodeid = ddi_get_nodeid(dip); 220 221 /* 222 * Portid has encoded the nodeid and the agent id. The top 223 * 4 bits are correspond to the wcnodeid and the lower 5 are the 224 * agent id. 225 * Each agent id represents a physical location hence we can 226 * obtain the board number 227 */ 228 if (sbdp_get_bd_and_wnode_num(nodeid, &bd, &wnode) < 0) 229 return (-1); 230 231 return (bd); 232 } 233 234 235 sbd_devattr_t * 236 sbdp_get_devattr(void) 237 { 238 return (&sbdp_devattr[0]); 239 } 240 241 int 242 sbdp_portid_to_cpu_unit(int cmp, int core) 243 { 244 return (SG_PORTID_TO_CPU_UNIT(cmp, core)); 245 } 246 247 int 248 sbdp_get_unit_num(sbdp_handle_t *hp, dev_info_t *dip) 249 { 250 int unit = -1; 251 int portid; 252 processorid_t cpuid; 253 sbd_comp_type_t type; 254 char dev_type[OBP_MAXPROPNAME]; 255 int i; 256 pnode_t nodeid; 257 static fn_t f = "sbdp_get_unit_num"; 258 259 SBDP_DBG_FUNC("%s\n", f); 260 261 if (dip == NULL) 262 return (-1); 263 264 nodeid = ddi_get_nodeid(dip); 265 266 if (sbdp_is_node_bad(nodeid)) 267 return (-1); 268 269 if (prom_getprop(nodeid, "device_type", (caddr_t)dev_type) < 0) { 270 SBDP_DBG_MISC("%s: couldn't get device_type\n", f); 271 return (-1); 272 } 273 274 for (i = 0; SBDP_CT(i) != SBD_COMP_UNKNOWN; i++) { 275 if (strcmp(dev_type, SBDP_OTYPE(i)) != 0) 276 continue; 277 type = SBDP_CT(i); 278 } 279 280 switch (type) { 281 case SBD_COMP_CPU: 282 if ((cpuid = sbdp_get_cpuid(hp, dip)) != -1) { 283 unit = SG_CPUID_TO_CPU_UNIT(cpuid); 284 } 285 break; 286 case SBD_COMP_MEM: 287 unit = 0; 288 break; 289 case SBD_COMP_IO: { 290 regspace_t regs[3]; 291 int len = 0; 292 293 /* 294 * Check to see if this is a cpci node 295 * cpci nodes are assign unit nums of 5 for now 296 * So they don't conflict with the pci unit nums 297 */ 298 299 if (strcmp(dev_type, "sghsc") == 0) { 300 SBDP_DBG_MISC("it is a sghsc\n"); 301 return (4); 302 } 303 304 if (prom_getprop(nodeid, "portid", (caddr_t)&portid) <= 0) { 305 SBDP_DBG_MISC("%s: couldn't get portid\n", f); 306 return (-1); 307 } 308 309 len = prom_getproplen(nodeid, "reg"); 310 if (len <= 0) { 311 SBDP_DBG_MISC("%s: couldn't get length\n", f); 312 return (-1); 313 } 314 315 if (prom_getprop(nodeid, "reg", (caddr_t)regs) < 0) { 316 SBDP_DBG_MISC("%s: couldn't get registers\n", f); 317 return (-1); 318 } 319 320 if ((portid % 2) != 0) 321 if ((regs[0].regspec_addr_lo & 0x700000) == 322 0x700000) 323 unit = 0; 324 else 325 unit = 1; 326 else 327 if ((regs[0].regspec_addr_lo & 0x700000) == 328 0x700000) 329 unit = 2; 330 else 331 unit = 3; 332 333 SBDP_DBG_MISC("unit is %d\n", unit); 334 break; 335 } 336 default: 337 break; 338 339 } 340 341 return (unit); 342 } 343 344 struct sbdp_mem_dip { 345 sbdp_bd_t *bdp; 346 dev_info_t *dip; 347 }; 348 349 static int 350 sbdp_get_mem_dip(pnode_t node, void *arg, uint_t flags) 351 { 352 _NOTE(ARGUNUSED(flags)) 353 354 struct sbdp_mem_dip *smdp = (struct sbdp_mem_dip *)arg; 355 mem_op_t mem = {0}; 356 357 if (node == OBP_NONODE || node == OBP_BADNODE) 358 return (DDI_FAILURE); 359 360 mem.nodes = smdp->bdp->nodes; 361 mem.board = smdp->bdp->bd; 362 mem.nmem = smdp->bdp->nnum; 363 364 (void) sbdp_is_mem(node, &mem); 365 366 /* 367 * We need to find the dip only for the first nodeid 368 */ 369 if (smdp->bdp->nnum == 0 && mem.nmem == 1) { 370 ASSERT(smdp->dip == NULL); 371 smdp->dip = e_ddi_nodeid_to_dip(node); 372 } 373 374 smdp->bdp->nnum = mem.nmem; 375 376 return (DDI_SUCCESS); 377 } 378 379 380 /* 381 * Update the board info. Required after a copy rename 382 */ 383 void 384 sbdp_update_bd_info(sbdp_bd_t *bdp) 385 { 386 attach_pkt_t apkt, *apktp = &apkt; 387 struct sbdp_mem_dip smd = {0}; 388 static fn_t f = "sbdp_update_bd_info"; 389 390 SBDP_DBG_FUNC("%s\n", f); 391 392 if (bdp == NULL) { 393 return; 394 } 395 /* 396 * Grab the lock 397 */ 398 mutex_enter(&bdp->bd_mutex); 399 400 /* 401 * we get the top nodes here. This will have a side effect of 402 * updating the present bit for cpus 403 */ 404 apktp->node = bdp->wnode; 405 apktp->board = bdp->bd; 406 apktp->num_of_nodes = 0; 407 apktp->flags = 0; 408 sbdp_walk_prom_tree(prom_rootnode(), sbdp_select_top_nodes, 409 (void *) apktp); 410 411 /* 412 * We need to clear nnum since we are looking again for the 413 * nodes 414 */ 415 bdp->nnum = 0; 416 smd.bdp = bdp; 417 418 /* 419 * If a dip is found by sbdp_get_mem_dip(), it will be 420 * returned held 421 */ 422 sbdp_walk_prom_tree(prom_rootnode(), sbdp_get_mem_dip, &smd); 423 if (smd.dip != NULL) { 424 sbdp_handle_t *hp; 425 426 hp = kmem_zalloc(sizeof (sbdp_handle_t), KM_SLEEP); 427 hp->h_board = bdp->bd; 428 hp->h_wnode = bdp->wnode; 429 hp->h_err = kmem_zalloc(sizeof (*hp->h_err), KM_SLEEP); 430 if (bdp->ml != NULL) { 431 (void) sbdp_del_memlist(hp, bdp->ml); 432 } 433 bdp->ml = sbdp_get_memlist(hp, (dev_info_t *)NULL); 434 /* 435 * if the board doesn't have banks initialize them, 436 * otherwise we assume they have been updated if 437 * necessary 438 */ 439 if (bdp->banks == NULL) { 440 sbdp_init_bd_banks(bdp); 441 } 442 #ifdef DEBUG 443 sbdp_print_bd_banks(bdp); 444 #endif 445 446 if (sbdphw_get_base_physaddr(hp, smd.dip, &bdp->bpa)) 447 bdp->bpa = -1; 448 ddi_release_devi(smd.dip); 449 kmem_free(hp->h_err, sizeof (*hp->h_err)); 450 kmem_free(hp, sizeof (sbdp_handle_t)); 451 } 452 mutex_exit(&bdp->bd_mutex); 453 } 454 455 /* 456 * Initialize the board struct. This remains cached. We update it 457 * every time we have a successful show_board and after a copy-rename 458 */ 459 void 460 sbdp_bd_init(sbdp_bd_t *bdp, int bd, int wnode) 461 { 462 static fn_t f = "sbdp_bd_init"; 463 464 SBDP_DBG_FUNC("%s\n", f); 465 466 bdp->bd = bd; 467 bdp->wnode = wnode; 468 469 SBDP_UNSET_ALL_CPUS_IN_RESET(bdp); 470 471 bdp->cpus_present = 0; 472 473 sbdp_update_bd_info(bdp); 474 475 mutex_init(&bdp->bd_mutex, NULL, MUTEX_DRIVER, NULL); 476 bdp->bd_sc = (show_board_t *)kmem_zalloc(sizeof (show_board_t), 477 KM_SLEEP); 478 bdp->valid_cp = -1; 479 } 480 481 /* 482 * This entry is going away. Clean up 483 */ 484 void 485 sbdp_bd_fini(sbdp_bd_t *bdp) 486 { 487 static fn_t f = "sbdp_bd_fini"; 488 489 SBDP_DBG_FUNC("%s\n", f); 490 491 sbdp_cleanup_bd(bdp->wnode, bdp->bd); 492 kmem_free(bdp->bd_sc, sizeof (show_board_t)); 493 bdp->bd_sc = NULL; 494 mutex_destroy(&bdp->bd_mutex); 495 #ifdef DEBUG 496 sbdp_print_all_segs(); 497 #endif 498 } 499 500 /* 501 * A new wnode has arrived. Initialize the struct and create 502 * the board structures. 503 */ 504 void 505 sbdp_wnode_init(sbdp_wnode_t *wnodep, int wnode, int boards) 506 { 507 int i; 508 static fn_t f = "sbdp_wnode_init"; 509 510 SBDP_DBG_FUNC("%s\n", f); 511 512 wnodep->wnode = wnode; 513 wnodep->nbds = boards; 514 wnodep->bds = kmem_zalloc(sizeof (sbdp_bd_t) * boards, KM_SLEEP); 515 wnodep->next = wnodep->prev = NULL; 516 517 for (i = 0; i < boards; i++) 518 sbdp_bd_init(&wnodep->bds[i], i, wnode); 519 } 520 521 /* 522 * Wnode got DRed out. Clean up all the node stuff including the boards 523 */ 524 void 525 sbdp_wnode_fini(sbdp_wnode_t *wnodep) 526 { 527 int boards; 528 int i; 529 static fn_t f = "sbdp_wnode_fini"; 530 531 SBDP_DBG_FUNC("%s\n", f); 532 533 boards = wnodep->nbds; 534 535 for (i = 0; i < boards; i++) 536 sbdp_bd_fini(&wnodep->bds[i]); 537 538 kmem_free(wnodep->bds, sizeof (sbdp_bd_t) * boards); 539 wnodep->next = wnodep->prev = NULL; 540 kmem_free(wnodep, sizeof (sbdp_wnode_t)); 541 } 542 543 /* 544 * Add all the necessary fields to this board's struct 545 */ 546 void 547 sbdp_add_new_bd_info(int wnode, int board) 548 { 549 sbdp_wnode_t *cur; 550 static fn_t f = "sbdp_add_new_bd_info"; 551 552 SBDP_DBG_FUNC("%s\n", f); 553 554 cur = sbdp_get_wnodep(wnode); 555 556 SBDP_DBG_MISC("adding new board info %d\n", board); 557 558 sbdp_update_bd_info(&cur->bds[board]); 559 560 } 561 562 /* 563 * This board has gone away. Clean the necessary fields 564 */ 565 void 566 sbdp_cleanup_bd(int wnode, int board) 567 { 568 sbdp_wnode_t *cur; 569 sbdp_handle_t handle, *hp; 570 sbdp_bd_t *bdp; 571 int i; 572 static fn_t f = "sbdp_cleanup_bd"; 573 574 SBDP_DBG_FUNC("%s\n", f); 575 576 cur = sbdp_get_wnodep(wnode); 577 578 SBDP_DBG_MISC("cleaning up bd info for bd %d\n", board); 579 if (cur == NULL) { 580 SBDP_DBG_MISC("cur is null\n"); 581 return; 582 } 583 584 bdp = &cur->bds[board]; 585 586 /* 587 * Grab the lock 588 */ 589 mutex_enter(&bdp->bd_mutex); 590 591 for (i = 0; i < bdp->nnum; i++) 592 bdp->nodes[i] = (pnode_t)0; 593 bdp->nnum = 0; 594 595 sbdp_fini_bd_banks(bdp); 596 597 hp = &handle; 598 hp->h_board = bdp->bd; 599 hp->h_wnode = bdp->wnode; 600 if (bdp->ml) { 601 (void) sbdp_del_memlist(hp, bdp->ml); 602 } 603 604 bdp->ml = NULL; 605 606 bdp->bpa = -1; 607 608 sbdp_cpu_in_reset(wnode, bdp->bd, SBDP_ALL_CPUS, 0); 609 610 bdp->cpus_present = 0; 611 612 mutex_exit(&bdp->bd_mutex); 613 } 614 615 /* 616 * Traverse the list looking for wnode. Return it when found 617 */ 618 sbdp_wnode_t * 619 sbdp_get_wnodep(int wnode) 620 { 621 sbdp_wnode_t *cur; 622 int i; 623 static fn_t f = "sbdp_get_wnodep"; 624 625 SBDP_DBG_FUNC("%s\n", f); 626 627 mutex_enter(&sbdp_wnode_mutex); 628 for (i = 0, cur = first_node; i < cur_num_wnodes; i++, 629 cur = cur->next) { 630 if (cur->wnode == wnode) { 631 mutex_exit(&sbdp_wnode_mutex); 632 return (cur); 633 } 634 } 635 mutex_exit(&sbdp_wnode_mutex); 636 637 return (NULL); 638 } 639 640 /* 641 * Insert this brand new node into our master list. It leaves it all 642 * initialized 643 */ 644 void 645 sbdp_insert_wnode(int wnode, int max_boards) 646 { 647 sbdp_wnode_t *wnodep; 648 sbdp_wnode_t *cur; 649 static fn_t f = "sbdp_insert_wnode"; 650 651 SBDP_DBG_FUNC("%s\n", f); 652 653 wnodep = kmem_zalloc(sizeof (sbdp_wnode_t), KM_SLEEP); 654 655 mutex_enter(&sbdp_wnode_mutex); 656 if (first_node == NULL) { 657 first_node = wnodep; 658 cur_num_wnodes++; 659 } else { 660 cur = first_node + cur_num_wnodes++; 661 cur->next = wnodep; 662 wnodep->prev = cur; 663 } 664 mutex_exit(&sbdp_wnode_mutex); 665 sbdp_wnode_init(wnodep, wnode, max_boards); 666 } 667 668 /* 669 * This node is gone. Remove it from the list and also clean up 670 */ 671 void 672 sbdp_remove_wnode(sbdp_wnode_t *wnodep) 673 { 674 sbdp_wnode_t *cur; 675 static fn_t f = "sbdp_remove_wnode"; 676 677 SBDP_DBG_FUNC("%s\n", f); 678 679 if (wnodep != NULL) { 680 sbdp_wnode_fini(wnodep); 681 mutex_enter(&sbdp_wnode_mutex); 682 683 if (first_node == wnodep) 684 first_node = NULL; 685 else { 686 cur = wnodep->prev; 687 if (cur != NULL) 688 cur->next = wnodep->next; 689 if (wnodep->next != NULL) 690 wnodep->next->prev = cur; 691 } 692 693 cur_num_wnodes--; 694 mutex_exit(&sbdp_wnode_mutex); 695 } 696 } 697 698 /* 699 * Entry point from sbd. This is called when a new node is added. We 700 * create an entry in our inventory and initialize all the stuff that will be 701 * needed 702 */ 703 int 704 sbdp_setup_instance(caddr_t arg) 705 { 706 ssm_sbdp_info_t *sbdp_info; 707 int instance; 708 int wnode; 709 int max_boards; 710 static fn_t f = "sbdp_setup_instance"; 711 712 SBDP_DBG_FUNC("%s\n", f); 713 714 /* 715 * We get this directly from ssm 716 */ 717 sbdp_info = (ssm_sbdp_info_t *)arg; 718 719 instance = sbdp_info->instance; 720 wnode = sbdp_info->wnode; 721 max_boards = plat_max_boards(); 722 723 SBDP_DBG_MISC("sbdp_setup_instance: instance %d wnode %d\n", instance, 724 sbdp_info->wnode); 725 726 if (sbdp_get_wnodep(wnode) == NULL) { 727 /* 728 * This node has not been instanstiated 729 * create one 730 */ 731 sbdp_insert_wnode(wnode, max_boards); 732 } 733 734 return (DDI_SUCCESS); 735 } 736 737 /* 738 * Entry point from sbd. This is called when a node has been removed (or is 739 * going away. We do all the necessary cleanup 740 */ 741 int 742 sbdp_teardown_instance(caddr_t arg) 743 { 744 ssm_sbdp_info_t *sbdp_info; 745 int instance; 746 int wnode; 747 sbdp_wnode_t *wnodep; 748 static fn_t f = "sbdp_teardown_instance"; 749 750 SBDP_DBG_FUNC("%s\n", f); 751 752 /* 753 * ssm should have set this up 754 */ 755 sbdp_info = (ssm_sbdp_info_t *)arg; 756 757 instance = sbdp_info->instance; 758 wnode = sbdp_info->wnode; 759 760 SBDP_DBG_MISC("sbdp_teardown_instance: instance %d wnode %d\n", 761 instance, wnode); 762 763 /* 764 * Find this node and then remove it 765 */ 766 if ((wnodep = sbdp_get_wnodep(wnode)) != NULL) { 767 sbdp_remove_wnode(wnodep); 768 } 769 return (DDI_SUCCESS); 770 } 771 772 int 773 sbdp_disabled_component(sbdp_handle_t *hp) 774 { 775 #ifdef lint 776 hp = hp; 777 #endif 778 return (0); 779 } 780 781 /* ARGSUSED */ 782 int 783 sbdp_release_component(sbdp_handle_t *hp, dev_info_t *dip) 784 { 785 return (0); 786 } 787 788 void 789 sbdp_set_err(sbd_error_t *ep, int ecode, char *rsc) 790 { 791 static fn_t f = "sbdp_set_err"; 792 793 SBDP_DBG_FUNC("%s\n", f); 794 ASSERT(ep != NULL); 795 ep->e_code = ecode; 796 797 if (rsc != NULL) { 798 (void) strcpy((caddr_t)(ep->e_rsc), (caddr_t)rsc); 799 } 800 } 801 802 /* 803 * Serengeti DR passthrus are for debugging purposes only. 804 */ 805 static struct { 806 const char *name; 807 int (*handler)(sbdp_handle_t *, void *); 808 } sbdp_passthrus[] = { 809 #ifdef DEBUG 810 { "readmem", sbdp_passthru_readmem }, 811 { "prep-script", sbdp_passthru_prep_script }, 812 { "test-quiesce", sbdp_passthru_test_quiesce }, 813 { "inject-error", sbdp_passthru_inject_error }, 814 { "reset-error", sbdp_passthru_reset_error }, 815 #endif 816 817 /* the following line must always be last */ 818 { NULL, NULL } 819 }; 820 821 822 /*ARGSUSED*/ 823 int 824 sbdp_ioctl(sbdp_handle_t *hp, sbdp_ioctl_arg_t *sbdpi) 825 { 826 #ifdef DEBUG 827 char buf[512]; 828 int rv; 829 sbd_ioctl_arg_t *sbdi = (sbd_ioctl_arg_t *)sbdpi->h_iap; 830 int i; 831 static fn_t f = "sbdp_ioctl"; 832 833 SBDP_DBG_FUNC("%s\n", f); 834 835 if (sbdi->i_len >= sizeof (buf) || 836 ddi_copyin(sbdi->i_opts, buf, sbdi->i_len, sbdpi->h_mode)) { 837 sbdp_set_err(hp->h_err, ESBD_FAULT, NULL); 838 return (-1); 839 } 840 841 i = 0; 842 while (sbdp_passthrus[i].name != NULL) { 843 int len; 844 845 len = strlen(sbdp_passthrus[i].name); 846 if (strncmp(sbdp_passthrus[i].name, buf, len) == 0) 847 break; 848 i++; 849 } 850 851 if (sbdp_passthrus[i].name == NULL) { 852 sbdp_set_err(hp->h_err, ESBD_INVAL, NULL); 853 rv = EIO; 854 } else { 855 rv = (*sbdp_passthrus[i].handler)(hp, buf); 856 if (rv != ESBD_NOERROR) { 857 sbdp_set_err(hp->h_err, rv, NULL); 858 rv = EIO; 859 } 860 861 } 862 863 return (rv); 864 #else 865 return (0); 866 #endif 867 } 868 869 /* 870 * Check the dnode we obtained. Need to find a better way to determine 871 * if the node has the correct starting address 872 */ 873 int 874 sbdp_is_node_bad(pnode_t node) 875 { 876 static fn_t f = "sbdp_is_node_bad"; 877 878 SBDP_DBG_FUNC("%s\n", f); 879 880 return ((node == OBP_NONODE) || (node == OBP_BADNODE) || 881 ((node & 0x80000000u) != 0x80000000u)); 882 } 883 884 /* 885 * Retrieve the information we have on this board from 886 * the inventory 887 */ 888 sbdp_bd_t * 889 sbdp_get_bd_info(int wnode, int board) 890 { 891 sbdp_wnode_t *wnodep; 892 sbdp_bd_t *bdp; 893 int max_bds; 894 static fn_t f = "sbdp_get_bd_info"; 895 896 SBDP_DBG_FUNC("%s\n", f); 897 898 wnodep = sbdp_get_wnodep(wnode); 899 max_bds = plat_max_boards(); 900 901 if ((wnodep == NULL) || ((board < 0) && (board > max_bds))) { 902 return (NULL); 903 } 904 905 bdp = &wnodep->bds[board]; 906 907 /* 908 * We might not have the complete bd info. With cheetah we 909 * cannot access the memory decode registers when then cpu is 910 * in reset. If the mem info is incomplete, then we try to gather it 911 * here 912 */ 913 sbdp_update_bd_info(bdp); 914 915 return (bdp); 916 } 917 918 /* 919 * There are certain cases where obp marks components as failed 920 * If the status is ok the node won't have any status property. It 921 * is only there if the status is other than ok. 922 */ 923 sbd_cond_t 924 sbdp_get_comp_status(pnode_t nodeid) 925 { 926 char status_buf[OBP_MAXPROPNAME]; 927 static const char *status = "status"; 928 static const char *failed = "fail"; 929 static const char *disabled = "disabled"; 930 static fn_t f = "sbdp_get_comp_status"; 931 932 SBDP_DBG_FUNC("%s\n", f); 933 934 if (sbdp_is_node_bad(nodeid)) { 935 SBDP_DBG_STATE("node is not ok\n"); 936 return (SBD_COND_UNKNOWN); 937 } 938 939 if (prom_getproplen(nodeid, (char *)status) <= 0) { 940 SBDP_DBG_STATE("status is ok\n"); 941 return (SBD_COND_OK); 942 } 943 944 if (prom_getprop(nodeid, (char *)status, status_buf) < 0) { 945 SBDP_DBG_STATE("status is unknown\n"); 946 return (SBD_COND_UNKNOWN); 947 } 948 949 if (strncmp(status_buf, failed, strlen(failed)) == 0) { 950 SBDP_DBG_STATE("status of failed\n"); 951 return (SBD_COND_FAILED); 952 } 953 954 if (strcmp(status_buf, disabled) == 0) { 955 SBDP_DBG_STATE("status of unusable\n"); 956 return (SBD_COND_UNUSABLE); 957 } 958 959 return (SBD_COND_OK); 960 } 961 962 void 963 sbdp_cpu_in_reset(int node, int bd, int unit, int reset) 964 { 965 sbdp_wnode_t *cur; 966 sbdp_bd_t *bdp; 967 static fn_t f = "sbdp_cpu_in_reset"; 968 969 SBDP_DBG_FUNC("%s\n", f); 970 971 if ((unit < -1) || (bd < 0) || (node < 0)) { 972 return; 973 } 974 975 cur = sbdp_get_wnodep(node); 976 977 SBDP_DBG_MISC("marking cpu %d %s for board %d\n", unit, 978 (reset) ? "in reset" : "out of reset", bd); 979 980 if (cur == NULL) { 981 return; 982 } 983 984 bdp = &cur->bds[bd]; 985 986 if (unit == SBDP_ALL_CPUS) 987 if (reset == 1) 988 SBDP_SET_ALL_CPUS_IN_RESET(bdp); 989 else 990 SBDP_UNSET_ALL_CPUS_IN_RESET(bdp); 991 else 992 if (reset == 1) 993 SBDP_SET_CPU_IN_RESET(bdp, unit); 994 else 995 SBDP_UNSET_CPU_IN_RESET(bdp, unit); 996 } 997 998 int 999 sbdp_set_cpu_present(int node, int bd, int unit) 1000 { 1001 sbdp_wnode_t *cur; 1002 sbdp_bd_t *bdp; 1003 static fn_t f = "sbdp_set_cpu_present"; 1004 1005 SBDP_DBG_FUNC("%s\n", f); 1006 1007 if ((unit < 0) || (bd < 0) || (node < 0)) { 1008 return (-1); 1009 } 1010 1011 cur = sbdp_get_wnodep(node); 1012 if (cur == NULL) { 1013 return (-1); 1014 } 1015 1016 bdp = &cur->bds[bd]; 1017 1018 SBDP_SET_CPU_PRESENT(bdp, unit); 1019 1020 return (0); 1021 } 1022 1023 int 1024 sbdp_is_cpu_present(int node, int bd, int unit) 1025 { 1026 sbdp_wnode_t *cur; 1027 sbdp_bd_t *bdp; 1028 static fn_t f = "sbdp_is_cpu_present"; 1029 1030 SBDP_DBG_FUNC("%s\n", f); 1031 1032 if ((unit < 0) || (bd < 0) || (node < 0)) { 1033 return (-1); 1034 } 1035 1036 cur = sbdp_get_wnodep(node); 1037 if (cur == NULL) { 1038 return (-1); 1039 } 1040 1041 bdp = &cur->bds[bd]; 1042 1043 return (SBDP_IS_CPU_PRESENT(bdp, unit)); 1044 } 1045 1046 int 1047 sbdp_is_cpu_in_reset(int node, int bd, int unit) 1048 { 1049 sbdp_wnode_t *cur; 1050 sbdp_bd_t *bdp; 1051 static fn_t f = "sbdp_is_cpu_in_reset"; 1052 1053 SBDP_DBG_FUNC("%s\n", f); 1054 1055 if ((unit < 0) || (bd < 0) || (node < 0)) { 1056 return (-1); 1057 } 1058 1059 cur = sbdp_get_wnodep(node); 1060 1061 if (cur == NULL) { 1062 return (-1); 1063 } 1064 1065 bdp = &cur->bds[bd]; 1066 1067 return (SBDP_IS_CPU_IN_RESET(bdp, unit)); 1068 } 1069 1070 int 1071 sbdp_dr_avail(void) 1072 { 1073 static fn_t f = "sbdp_dr_avail"; 1074 1075 SBDP_DBG_FUNC("%s\n", f); 1076 1077 if (sbdp_dr_available) 1078 if (sg_prom_sb_dr_check() == 0) 1079 return (1); 1080 return (0); 1081 } 1082