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