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/conf.h> 31 #include <sys/ddi.h> 32 #include <sys/sunddi.h> 33 #include <sys/ddi_impldefs.h> 34 #include <sys/obpdefs.h> 35 #include <sys/promif.h> 36 #include <sys/cmn_err.h> 37 #include <sys/errno.h> 38 #include <sys/kmem.h> 39 #include <sys/kstat.h> 40 #include <sys/debug.h> 41 #include <sys/fhc.h> 42 #include <sys/jtag.h> 43 #include <sys/sysctrl.h> 44 45 static fhc_bd_resizable_t boards; /* booted and hotplugged boards */ 46 static fhc_bd_resizable_t clocks; /* clocks under central. */ 47 48 static int fhc_bdmax; 49 /* 50 * !! IMPORTANT !! fhc_bdlist_rwlock is implemented as a single 51 * RW_WRITER lock with *no* RW_READERs -- and it should stay that 52 * way. The fhc_bdlist_rwlock should never be used with RW_READER. 53 * 54 * The lock was originally a mutex, but was changed to a 55 * single-writer, zero-reader rwlock to force requesting threads 56 * to block (sleep, not spin) when the RW_WRITER lock is already 57 * held by a thread currently running. 58 */ 59 static krwlock_t fhc_bdlist_rwlock; 60 static sysc_evt_handle_t fhc_bd_evt; 61 static sysc_evt_handle_t *fbe = &fhc_bd_evt; 62 63 #define fhc_bd_sc_evt(s, e) (*fbe->update)(fbe->soft, s, e) 64 #define FHC_INCREMENT 4 65 #define FHC_B_SEARCH(in_array, board) \ 66 fhc_b_search(in_array.boards, board, 0, in_array.last); 67 68 static int fhc_bd_disabled(int); 69 static void fhc_check_array(int); 70 static void fhc_shell_sort(fhc_bd_t **, int, int); 71 static int fhc_b_search(fhc_bd_t **, int, int, int); 72 static void fhc_check_size(fhc_bd_resizable_t *); 73 static void fhc_resize(fhc_bd_t ***, int, int); 74 75 76 /* 77 * fhc_bdmax gets set in fhc_bdlist_prime() and does not 78 * change thereafter. 79 */ 80 int 81 fhc_max_boards() 82 { 83 return (fhc_bdmax + 1); 84 } 85 86 static int 87 fhc_bd_disabled(int board) 88 { 89 int index; 90 91 ASSERT(boards.sorted); 92 index = FHC_B_SEARCH(boards, board); 93 ASSERT(index != -1); 94 return (boards.boards[index]->flags & BDF_DISABLED); 95 } 96 97 static void 98 fhc_check_array(int btype) 99 { 100 if (btype == FHC_BOARDS) { 101 ASSERT(fhc_bdlist_locked()); 102 if (!boards.sorted) { 103 fhc_shell_sort(boards.boards, 0, boards.last); 104 boards.sorted = TRUE; 105 } 106 } else { 107 ASSERT(fhc_bdlist_locked()); 108 if (!clocks.sorted) { 109 fhc_shell_sort(clocks.boards, 0, clocks.last); 110 clocks.sorted = TRUE; 111 } 112 } 113 } 114 115 static void 116 fhc_shell_sort(fhc_bd_t *a[], int lb, int ub) 117 { 118 int n, h, i, j; 119 fhc_bd_t *t; 120 121 /* sort array a[lb..ub] */ 122 123 /* compute largest increment */ 124 n = ub - lb + 1; 125 h = 1; 126 if (n < 14) 127 h = 1; 128 else { 129 while (h < n) 130 h = 3 * h + 1; 131 h /= 3; 132 h /= 3; 133 } 134 135 while (h > 0) { 136 /* sort-by-insertion in increments of h */ 137 for (i = lb + h; i <= ub; i++) { 138 t = a[i]; 139 for (j = i - h; 140 j >= lb && a[j]->sc.board > t->sc.board; 141 j -= h) { 142 a[j+h] = a[j]; 143 } 144 a[j+h] = t; 145 } 146 147 /* compute next increment */ 148 h /= 3; 149 } 150 } 151 152 static int 153 fhc_b_search(fhc_bd_t *in_array[], int board, int first, int last) 154 { 155 int mid; 156 157 /* Array of length 0 case. */ 158 if (in_array == NULL) 159 return (-1); 160 161 /* Array of length > 0 case. */ 162 while (first < last) { 163 mid = (first + last) / 2; 164 if (in_array[mid]->sc.board < board) 165 first = mid + 1; 166 else 167 last = mid; 168 } 169 170 if (in_array[first]->sc.board == board) { 171 return (first); 172 } else { 173 return (-1); 174 } 175 176 } 177 178 static void 179 fhc_check_size(fhc_bd_resizable_t *resizable) 180 { 181 int oldsize; 182 int newsize; 183 184 ASSERT(fhc_bdlist_locked()); 185 186 if (resizable->size == resizable->last + 1) { 187 oldsize = sizeof (fhc_bd_t *) * resizable->size; 188 resizable->size += FHC_INCREMENT; 189 newsize = sizeof (fhc_bd_t *) * resizable->size; 190 fhc_resize(&(resizable->boards), oldsize, newsize); 191 } 192 } 193 194 int 195 fhc_bdlist_locked() 196 { 197 if (panicstr) 198 return (1); 199 200 return (rw_owner(&fhc_bdlist_rwlock) == curthread); 201 } 202 203 int 204 fhc_bd_busy(int board) 205 { 206 int index; 207 208 ASSERT(boards.sorted); 209 index = FHC_B_SEARCH(boards, board); 210 ASSERT(index != -1); 211 return (boards.boards[index]->sc.in_transition); 212 } 213 214 int 215 fhc_bd_is_jtag_master(int board) 216 { 217 int index; 218 219 ASSERT(boards.sorted); 220 index = FHC_B_SEARCH(boards, board); 221 ASSERT(index != -1); 222 if (boards.boards[index]->softsp == NULL) 223 return (FALSE); 224 else 225 return ((boards.boards[index]->softsp)->jt_master.is_master); 226 } 227 228 int 229 fhc_bd_is_plus(int board) 230 { 231 int index; 232 233 ASSERT(boards.sorted); 234 index = FHC_B_SEARCH(boards, board); 235 ASSERT(index != -1); 236 if (boards.boards[index]->sc.plus_board) 237 return (boards.boards[index]->sc.plus_board); 238 else 239 return (FALSE); 240 } 241 242 void 243 fhc_bdlist_init() 244 { 245 ASSERT(!fhc_bdmax); 246 rw_init(&fhc_bdlist_rwlock, NULL, RW_DEFAULT, NULL); 247 boards.boards = NULL; 248 boards.size = 0; 249 boards.last = -1; 250 boards.sorted = TRUE; /* Array of 0 elements is sorted. */ 251 252 clocks.boards = NULL; 253 clocks.size = 0; 254 clocks.last = -1; 255 clocks.sorted = TRUE; /* Array of 0 elements is sorted. */ 256 } 257 258 void 259 fhc_bdlist_fini() 260 { 261 rw_destroy(&fhc_bdlist_rwlock); 262 } 263 264 fhc_bd_t * 265 fhc_bdlist_lock(int board) 266 { 267 int index; 268 269 ASSERT(!fhc_bdlist_locked()); 270 271 /* RW_WRITER *ONLY*. Never use RW_READER! */ 272 rw_enter(&fhc_bdlist_rwlock, RW_WRITER); 273 274 if (board == -1) 275 return (NULL); 276 else { 277 ASSERT(boards.sorted); 278 index = FHC_B_SEARCH(boards, board); 279 ASSERT(index != -1); 280 return (boards.boards[index]); 281 } 282 } 283 284 void 285 fhc_bdlist_unlock() 286 { 287 ASSERT(fhc_bdlist_locked()); 288 289 rw_exit(&fhc_bdlist_rwlock); 290 } 291 292 static void 293 fhc_resize(fhc_bd_t ***in_array, int oldsize, int newsize) 294 { 295 fhc_bd_t **temp; 296 297 /* This function only grows arrays. */ 298 ASSERT(newsize > oldsize); 299 300 /* Allocate new array. */ 301 temp = kmem_alloc(newsize, KM_SLEEP); 302 303 /* Bcopy old array and free it. */ 304 if (*in_array != NULL) { 305 ASSERT(oldsize > 0); 306 bcopy(*in_array, temp, oldsize); 307 kmem_free(*in_array, oldsize); 308 } 309 *in_array = temp; 310 } 311 312 void 313 fhc_bd_init(struct fhc_soft_state *softsp, int board, enum board_type type) 314 { 315 fhc_bd_t *bdp; 316 int index; 317 318 (void) fhc_bdlist_lock(-1); 319 320 /* See if board already exists. */ 321 ASSERT(boards.sorted); 322 ASSERT(clocks.sorted); 323 if (softsp->is_central) { 324 index = FHC_B_SEARCH(clocks, board); 325 } else { 326 index = FHC_B_SEARCH(boards, board); 327 } 328 329 /* If index == -1 board does not exist. */ 330 if (index != -1) { 331 if (softsp->is_central) { 332 bdp = clocks.boards[index]; 333 } else { 334 bdp = boards.boards[index]; 335 } 336 } else { 337 if (softsp->is_central) { 338 fhc_check_size(&clocks); 339 clocks.boards[clocks.last + 1] = 340 kmem_zalloc(sizeof (fhc_bd_t), KM_SLEEP); 341 bdp = clocks.boards[clocks.last + 1]; 342 clocks.last++; 343 clocks.sorted = FALSE; 344 } else { 345 fhc_check_size(&boards); 346 boards.boards[boards.last + 1] = 347 kmem_zalloc(sizeof (fhc_bd_t), KM_SLEEP); 348 bdp = boards.boards[boards.last + 1]; 349 boards.last++; 350 boards.sorted = FALSE; 351 } 352 } 353 354 softsp->list = bdp; 355 bdp->flags |= BDF_VALID; 356 bdp->softsp = softsp; 357 bdp->sc.type = type; 358 bdp->sc.board = board; 359 bdp->sc.plus_board = ISPLUSBRD(*softsp->bsr); 360 361 /* Keep arrays sorted. */ 362 fhc_check_array(FHC_BOARDS); 363 fhc_check_array(FHC_CLOCKS); 364 365 fhc_bdlist_unlock(); 366 } 367 368 fhc_bd_t * 369 fhc_bd(int board) 370 { 371 int index; 372 373 if (fhc_bdmax) { 374 ASSERT(fhc_bdlist_locked()); 375 } 376 ASSERT(boards.sorted); 377 index = FHC_B_SEARCH(boards, board); 378 ASSERT(index != -1); 379 return (boards.boards[index]); 380 } 381 382 fhc_bd_t * 383 fhc_bd_clock(void) 384 { 385 ASSERT(fhc_bdlist_locked()); 386 ASSERT(clocks.size != 0); 387 388 return (clocks.boards[0]); 389 } 390 391 fhc_bd_t * 392 fhc_bd_first() 393 { 394 ASSERT(fhc_bdlist_locked()); 395 if (boards.boards != NULL) 396 return (boards.boards[0]); 397 else 398 return (NULL); 399 } 400 401 fhc_bd_t * 402 fhc_bd_next(fhc_bd_t *bdp) 403 { 404 int index; 405 406 ASSERT(boards.sorted); 407 index = FHC_B_SEARCH(boards, bdp->sc.board); 408 ASSERT(index != -1); 409 if (index < boards.last) 410 return (boards.boards[index + 1]); 411 else 412 return (NULL); 413 } 414 415 int 416 fhc_bd_valid(int bd) 417 { 418 int index; 419 420 ASSERT(bd >= 0); 421 /* Untill fhc_bdlist_prime runs anything is valid. */ 422 if (!fhc_bdmax) 423 return (TRUE); 424 425 ASSERT(boards.sorted); 426 index = FHC_B_SEARCH(boards, bd); 427 if (index == -1) 428 return (FALSE); 429 else 430 return (TRUE); 431 } 432 433 enum board_type 434 fhc_bd_type(int board) 435 { 436 int index; 437 438 ASSERT(boards.sorted); 439 index = FHC_B_SEARCH(boards, board); 440 if (index == -1) 441 return (-1); 442 443 return (boards.boards[index]->sc.type); 444 } 445 446 char * 447 fhc_bd_typestr(enum board_type type) 448 { 449 char *type_str; 450 451 switch (type) { 452 case MEM_BOARD: 453 type_str = MEM_BD_NAME; 454 break; 455 456 case CPU_BOARD: 457 type_str = CPU_BD_NAME; 458 break; 459 460 case IO_2SBUS_BOARD: 461 type_str = IO_2SBUS_BD_NAME; 462 break; 463 464 case IO_SBUS_FFB_BOARD: 465 type_str = IO_SBUS_FFB_BD_NAME; 466 break; 467 468 case IO_2SBUS_SOCPLUS_BOARD: 469 type_str = IO_2SBUS_SOCPLUS_BD_NAME; 470 break; 471 472 case IO_SBUS_FFB_SOCPLUS_BOARD: 473 type_str = IO_SBUS_FFB_SOCPLUS_BD_NAME; 474 break; 475 476 case IO_PCI_BOARD: 477 type_str = IO_PCI_BD_NAME; 478 break; 479 480 case DISK_BOARD: 481 type_str = DISK_BD_NAME; 482 break; 483 484 case UNKNOWN_BOARD: 485 default: 486 type_str = "unknown"; 487 break; 488 } 489 490 return (type_str); 491 } 492 493 void 494 fhc_bd_env_set(int board, void *env) 495 { 496 fhc_bd_t *bdp; 497 498 bdp = fhc_bd(board); 499 bdp->dev_softsp = env; 500 } 501 502 static void 503 fhc_bd_dlist_init() 504 { 505 int i; 506 int len; 507 int board; 508 pnode_t node; 509 char *dlist; 510 int index; 511 512 /* 513 * Find the disabled board list property if present. 514 * 515 * The disabled board list is in the options node under root; 516 * it is a null terminated list of boards in a string. 517 * Each char represents a board. The driver must 518 * reject illegal chars in case a user places them in the 519 * property. 520 */ 521 if (((node = prom_finddevice("/options")) == OBP_BADNODE) || 522 ((len = prom_getproplen(node, "disabled-board-list")) == -1)) 523 return; 524 525 dlist = kmem_alloc(len, KM_SLEEP); 526 (void) prom_getprop(node, "disabled-board-list", dlist); 527 528 /* 529 * now loop thru the string, and create disabled board list 530 * entries for all legal boards in the list. 531 */ 532 for (i = 0; (i < len) && (dlist[i] != 0); i++) { 533 char ch = dlist[i]; 534 535 if (ch >= '0' && ch <= '9') 536 board = ch - '0'; 537 else if (ch >= 'A' && ch <= 'F') 538 board = ch - 'A' + 10; 539 else if (ch >= 'a' && ch <= 'f') 540 board = ch - 'a' + 10; 541 else 542 /* junk entry */ 543 continue; 544 545 index = FHC_B_SEARCH(boards, board); 546 if (index != -1) { 547 boards.boards[index]->flags |= BDF_DISABLED; 548 } 549 } 550 kmem_free(dlist, len); 551 } 552 553 static struct bd_info fhc_bd_info; 554 555 static int 556 fhc_bd_ks_update(kstat_t *ksp, int rw) 557 { 558 fhc_bd_t *bdp; 559 sysc_cfga_stat_t *sc; 560 struct bd_info *uip; 561 enum board_state state; 562 563 if (rw == KSTAT_WRITE) 564 return (EACCES); 565 566 bdp = (fhc_bd_t *)ksp->ks_private; 567 uip = &fhc_bd_info; 568 sc = &bdp->sc; 569 570 ASSERT(fhc_bd_valid(sc->board)); 571 572 uip->board = sc->board; 573 uip->type = sc->type; 574 uip->fhc_compid = sc->fhc_compid; 575 uip->ac_compid = sc->ac_compid; 576 bcopy((caddr_t)sc->prom_rev, uip->prom_rev, sizeof (uip->prom_rev)); 577 bcopy((caddr_t)&sc->bd, &uip->bd, sizeof (union bd_un)); 578 579 switch (sc->rstate) { 580 case SYSC_CFGA_RSTATE_DISCONNECTED: 581 switch (sc->condition) { 582 case SYSC_CFGA_COND_OK: 583 case SYSC_CFGA_COND_UNKNOWN: 584 state = DISABLED_STATE; 585 break; 586 case SYSC_CFGA_COND_FAILING: 587 case SYSC_CFGA_COND_FAILED: 588 case SYSC_CFGA_COND_UNUSABLE: 589 state = FAILED_STATE; 590 break; 591 default: 592 state = UNKNOWN_STATE; 593 break; 594 } 595 break; 596 default: 597 state = UNKNOWN_STATE; 598 break; 599 } 600 601 uip->state = state; 602 603 return (0); 604 } 605 606 void 607 fhc_bd_ks_alloc(fhc_bd_t *bdp) 608 { 609 ASSERT(!bdp->ksp); 610 611 bdp->ksp = kstat_create("unix", bdp->sc.board, 612 BDLIST_KSTAT_NAME, "misc", KSTAT_TYPE_RAW, 613 sizeof (struct bd_info), KSTAT_FLAG_VIRTUAL); 614 615 if (bdp->ksp != NULL) { 616 bdp->ksp->ks_data = &fhc_bd_info; 617 bdp->ksp->ks_update = fhc_bd_ks_update; 618 bdp->ksp->ks_private = (void *)bdp; 619 kstat_install(bdp->ksp); 620 } 621 } 622 623 static void 624 fhc_bdlist_dk_init() 625 { 626 dev_info_t *dnode; 627 628 /* 629 * Search the children of root to see if there are any 630 * disk boards in the tree. 631 */ 632 for (dnode = ddi_get_child(ddi_root_node()); 633 dnode != NULL; dnode = ddi_get_next_sibling(dnode)) { 634 if (strcmp(ddi_node_name(dnode), "disk-board") == 0) { 635 int id; 636 int board; 637 fhc_bd_t *bdp; 638 sysc_cfga_stat_t *sc; 639 640 /* 641 * Get the board number property. 642 */ 643 if ((board = (int)ddi_getprop(DDI_DEV_T_ANY, dnode, 644 DDI_PROP_DONTPASS, OBP_BOARDNUM, -1)) == -1) { 645 cmn_err(CE_WARN, 646 "Could not find board number"); 647 continue; 648 } 649 bdp = fhc_bd(board); 650 sc = &bdp->sc; 651 652 if ((id = (int)ddi_getprop(DDI_DEV_T_ANY, dnode, 653 DDI_PROP_DONTPASS, "disk0-scsi-id", -1)) != -1) { 654 sc->bd.dsk.disk_pres[0] = 1; 655 sc->bd.dsk.disk_id[0] = id; 656 } else { 657 sc->bd.dsk.disk_pres[0] = 0; 658 } 659 660 if ((id = (int)ddi_getprop(DDI_DEV_T_ANY, dnode, 661 DDI_PROP_DONTPASS, "disk1-scsi-id", -1)) != -1) { 662 sc->bd.dsk.disk_pres[1] = 1; 663 sc->bd.dsk.disk_id[1] = id; 664 } else { 665 sc->bd.dsk.disk_pres[1] = 0; 666 } 667 668 } 669 } 670 671 } 672 673 struct jt_mstr * 674 jtag_master_lock(void) 675 { 676 fhc_bd_t *bdp; 677 struct jt_mstr *master = NULL; 678 679 ASSERT(fhc_bdlist_locked()); 680 681 /* 682 * Now search for the JTAG master and place the addresses for 683 * command into the fhc soft state structure. 684 * Disk board do not have softsp set. 685 */ 686 for (bdp = fhc_bd_first(); bdp; bdp = fhc_bd_next(bdp)) 687 if (bdp->softsp && (bdp->softsp->jt_master.is_master == 1)) { 688 master = &bdp->softsp->jt_master; 689 mutex_enter(&master->lock); 690 break; 691 } 692 693 return (master); 694 } 695 696 void 697 jtag_master_unlock(struct jt_mstr *mstr) 698 { 699 ASSERT(fhc_bdlist_locked()); 700 ASSERT(mutex_owned(&mstr->lock)); 701 702 mutex_exit(&mstr->lock); 703 } 704 705 void 706 fhc_bdlist_prime(int first, int count, int incr) 707 { 708 int board; 709 fhc_bd_t *bdp; 710 sysc_evt_t se; 711 sysc_cfga_stat_t *sc; 712 struct jt_mstr *jtm; 713 int index; 714 int nadded; 715 716 ASSERT(fbe->update); 717 718 (void) fhc_bdlist_lock(-1); 719 nadded = 0; 720 for (board = first; board < count; board += incr) { 721 /* 722 * Search only subset of array. We hold mutex so 723 * noone can add new elements to it. 724 */ 725 index = fhc_b_search(boards.boards, board, 0, 726 boards.last - nadded); 727 if (index == -1) { 728 fhc_check_size(&boards); 729 boards.boards[boards.last + 1] = 730 kmem_zalloc(sizeof (fhc_bd_t), KM_SLEEP); 731 boards.boards[boards.last + 1]->sc.type = UNKNOWN_BOARD; 732 boards.boards[boards.last + 1]->sc.board = board; 733 boards.boards[boards.last + 1]->softsp = NULL; 734 boards.last++; 735 nadded++; 736 boards.sorted = FALSE; 737 } 738 } 739 fhc_check_array(FHC_BOARDS); 740 fhc_bdlist_unlock(); 741 742 fhc_bdmax = count - 1; 743 744 /* 745 * Initialize our copy of the disabled board list. 746 */ 747 fhc_bd_dlist_init(); 748 749 (void) fhc_bdlist_lock(-1); 750 751 if ((jtm = jtag_master_lock()) == NULL) 752 cmn_err(CE_PANIC, "fhc_bdlist_prime: no jtag master"); 753 754 /* 755 * Go through the board list, skipping illegal slots 756 * and initialize each slot. 757 */ 758 for (bdp = fhc_bd_first(); bdp; bdp = fhc_bd_next(bdp)) { 759 sc = &bdp->sc; 760 board = sc->board; 761 762 se = SYSC_EVT_BD_PRESENT; 763 764 if (sc->type == UNKNOWN_BOARD) { 765 uint_t fhc_csr; 766 uint_t fhc_bsr; 767 enum board_type type; 768 769 type = jtag_get_board_type(jtm->jtag_cmd, sc); 770 switch (type) { 771 case -1: 772 fhc_bd_sc_evt(sc, SYSC_EVT_BD_EMPTY); 773 continue; 774 case DISK_BOARD: 775 /* 776 * Disk boards are handled differently 777 * in that they don't fail POST and have 778 * no fhc attached. 779 */ 780 sc->type = DISK_BOARD; 781 (void) jtag_init_disk_board(jtm->jtag_cmd, 782 board, 783 &fhc_csr, &fhc_bsr); 784 fhc_bd_ks_alloc(bdp); 785 break; 786 default: 787 /* 788 * Set the condition to FAILED if POST has 789 * failed. A failed board is physically 790 * present, is not on the disabled list and 791 * is of type UNKNOWN. 792 * NOTE: a non-present board which is 793 * (potentially) on the disabled board 794 * list has been ignored in the empty 795 * slot case. 796 */ 797 if (fhc_bd_disabled(board)) { 798 fhc_bd_ks_alloc(bdp); 799 se = SYSC_EVT_BD_DISABLED; 800 } else 801 se = SYSC_EVT_BD_FAILED; 802 803 sc->type = type; 804 break; 805 } 806 } 807 808 fhc_bd_sc_evt(sc, se); 809 } 810 811 /* 812 * Do the disk specific initialization. This routine scans 813 * for all disk boards, so we call it only once. 814 */ 815 fhc_bdlist_dk_init(); 816 817 jtag_master_unlock(jtm); 818 819 fhc_bdlist_unlock(); 820 } 821 822 struct cpu_speed { 823 int cpu_freq; 824 int sram_mode; 825 int system_div; 826 int system_dvd; 827 }; 828 829 struct cpu_speed ultraI_speed_table[] = { 830 { 0, 0, 0, 0}, 831 { 143, 1, 2, 1}, 832 { 154, 1, 2, 1}, 833 { 168, 1, 2, 1}, 834 { 182, 1, 3, 1}, 835 { 200, 1, 3, 1}, 836 { 222, 1, 3, 1}, 837 { 250, 1, 3, 1} 838 }; 839 840 struct cpu_speed ultraII_speed_table[] = { 841 { 0, 0, 0, 0}, 842 { 360, 2, 2, 1}, 843 { 400, 2, 4, 1}, 844 { 400, 2, 5, 2}, 845 { 248, 2, 3, 2}, 846 { 496, 2, 5, 2}, 847 { 296, 2, 2, 1}, 848 { 336, 2, 2, 1} 849 }; 850 851 /* 852 * set_cpu_info 853 * 854 * This routine extracts CPU module information used later for 855 * determining hotplug compatibility. 856 */ 857 static void 858 set_cpu_info(sysc_cfga_stat_t *sc, uint_t fhc_bsr) 859 { 860 int i; 861 int speed_pins; 862 struct cpu_speed *table; 863 864 for (i = 0; i < 2; i++) { 865 sc->bd.cpu[i].cpu_speed = 0; 866 sc->bd.cpu[i].cpu_sram_mode = 0; 867 868 if (!sc->bd.cpu[i].cpu_detected) 869 continue; 870 871 speed_pins = (i == 0) ? CPU_0_PINS(fhc_bsr) : 872 CPU_1_PINS(fhc_bsr); 873 874 switch (sc->bd.cpu[i].cpu_compid & CID_REV_MASK) { 875 case ULTRAI_COMPID: 876 table = ultraI_speed_table; 877 break; 878 case ULTRAII_COMPID: 879 table = ultraII_speed_table; 880 break; 881 default: 882 cmn_err(CE_WARN, "board %d, cpu module %c " 883 "unknown type", sc->board, 884 (i == 0) ? 'A' : 'B'); 885 sc->bd.cpu[i].cpu_speed = -1; 886 continue; 887 } 888 889 sc->bd.cpu[i].cpu_speed = table[speed_pins].cpu_freq; 890 sc->bd.cpu[i].cpu_sram_mode = table[speed_pins].sram_mode; 891 } 892 } 893 894 int 895 fhc_bdlist_scan(sysc_cfga_rstate_t rstate, struct jt_mstr *jtm) 896 { 897 int board; 898 int error; 899 int found = 0; 900 uint_t fhc_csr; 901 uint_t fhc_bsr; 902 fhc_bd_t *bdp; 903 sysc_cfga_stat_t *sc; 904 enum board_type type; 905 906 for (bdp = fhc_bd_first(); bdp; bdp = fhc_bd_next(bdp)) { 907 908 sc = &bdp->sc; 909 board = sc->board; 910 911 /* 912 * Check the boards in EMPTY and DISCONNECTED 913 * states. We need to check a board in the 914 * DISCONNECTED state in case it had been replugged. 915 */ 916 if (sc->in_transition || sc->rstate != rstate) 917 continue; 918 else if (sc->rstate == SYSC_CFGA_RSTATE_EMPTY) { 919 type = jtag_get_board_type(jtm->jtag_cmd, sc); 920 if (type == -1) 921 continue; /* no board present */ 922 sc->type = type; 923 } else 924 type = sc->type; 925 926 if (type != UNKNOWN_BOARD) 927 (void) jtag_get_board_info(jtm->jtag_cmd, sc); 928 929 error = 0; 930 931 if (type == DISK_BOARD) 932 /* 933 * Scan the FHC to turn off the board insert 934 * interrupt and modify LEDs based on hotplug 935 * status. 936 */ 937 (void) jtag_init_disk_board(jtm->jtag_cmd, board, 938 &fhc_csr, &fhc_bsr); 939 else 940 error = jtag_powerdown_board(jtm->jtag_cmd, 941 board, type, &fhc_csr, &fhc_bsr, FALSE); 942 943 if (error) { 944 fhc_bd_sc_evt(sc, SYSC_EVT_BD_INS_FAILED); 945 continue; 946 } 947 948 if (fhc_csr & FHC_NOT_BRD_PRES) 949 continue; 950 951 if (type == CPU_BOARD) { 952 set_cpu_info(sc, fhc_bsr); 953 } 954 955 fhc_bd_sc_evt(sc, SYSC_EVT_BD_INSERTED); 956 957 /* 958 * A replugged board will still have its kstat info. 959 */ 960 if (!bdp->ksp) 961 fhc_bd_ks_alloc(bdp); 962 963 found++; 964 break; 965 } 966 967 return (found); 968 } 969 970 int 971 fhc_bd_insert_scan() 972 { 973 struct jt_mstr *jtm; 974 int found; 975 976 ASSERT(fhc_bdlist_locked()); 977 978 if ((jtm = jtag_master_lock()) == NULL) 979 cmn_err(CE_PANIC, "fhc_bd_insert_scan: no jtag master"); 980 981 /* first check empty then disconnected */ 982 found = fhc_bdlist_scan(SYSC_CFGA_RSTATE_EMPTY, jtm); 983 if (!found) 984 found |= fhc_bdlist_scan(SYSC_CFGA_RSTATE_DISCONNECTED, jtm); 985 if (!found) 986 cmn_err(CE_WARN, "Could not find hotplugged core system board"); 987 988 jtag_master_unlock(jtm); 989 990 return (found); 991 } 992 993 int 994 fhc_bd_remove_scan() 995 { 996 int poll = 0; 997 fhc_bd_t *bdp; 998 struct jt_mstr *jtm; 999 sysc_cfga_stat_t *sc; 1000 1001 ASSERT(fhc_bdlist_locked()); 1002 1003 if ((jtm = jtag_master_lock()) == NULL) 1004 cmn_err(CE_PANIC, "fhc_bd_remove_scan: no jtag master"); 1005 1006 for (bdp = fhc_bd_first(); bdp; bdp = fhc_bd_next(bdp)) { 1007 sc = &bdp->sc; 1008 1009 if (sc->rstate != SYSC_CFGA_RSTATE_DISCONNECTED) 1010 continue; 1011 /* 1012 * While there is a board in the disconnected state 1013 * continue polling. When the last board is removed, 1014 * we will get one last scan. 1015 */ 1016 poll++; 1017 1018 if (sc->in_transition) 1019 continue; 1020 1021 /* 1022 * Scan to see if the board is still in. 1023 */ 1024 if (jtag_get_board_type(jtm->jtag_cmd, sc) == -1) { 1025 if (bdp->ksp) { 1026 kstat_delete(bdp->ksp); 1027 bdp->ksp = NULL; 1028 } 1029 fhc_bd_sc_evt(sc, SYSC_EVT_BD_REMOVED); 1030 } 1031 } 1032 1033 jtag_master_unlock(jtm); 1034 1035 return (poll); 1036 } 1037 1038 int 1039 fhc_bd_detachable(int board) 1040 { 1041 fhc_bd_t *bdp = fhc_bd(board); 1042 1043 if (bdp->softsp != NULL) 1044 return (bdp->flags & BDF_DETACH); 1045 else 1046 return (FALSE); 1047 } 1048 1049 void 1050 fhc_bd_sc_register(void (*f)(void *, sysc_cfga_stat_t *, sysc_evt_t), void *sp) 1051 { 1052 fhc_bd_evt.update = f; 1053 fhc_bd_evt.soft = sp; 1054 } 1055 1056 void 1057 fhc_bd_update(int board, sysc_evt_t evt) 1058 { 1059 fhc_bd_t *bdp; 1060 1061 ASSERT(fhc_bd_valid(board)); 1062 1063 /* 1064 * There is a window where this routine might be called 1065 * as a result of the environ thread before sysctrl has 1066 * attached and registered the callback. 1067 */ 1068 if (!(fbe->update)) 1069 return; 1070 1071 bdp = fhc_bdlist_lock(board); 1072 1073 fhc_bd_sc_evt(&bdp->sc, evt); 1074 1075 fhc_bdlist_unlock(); 1076 } 1077 1078 /* ARGSUSED */ 1079 int 1080 fhc_bd_test(int board, sysc_cfga_pkt_t *pkt) 1081 { 1082 uint_t fhc_csr, fhc_bsr; 1083 fhc_bd_t *bdp; 1084 struct jt_mstr *jtm; 1085 sysc_cfga_stat_t *sc; 1086 1087 ASSERT(fhc_bdlist_locked()); 1088 ASSERT(fhc_bd_busy(board)); 1089 1090 bdp = fhc_bd(board); 1091 sc = &bdp->sc; 1092 1093 switch (sc->rstate) { 1094 case SYSC_CFGA_RSTATE_EMPTY: 1095 cmn_err(CE_NOTE, "fhc_bd_test: simulate board %d insertion", 1096 board); 1097 1098 jtm = jtag_master_lock(); 1099 ASSERT(jtm); 1100 jtag_master_unlock(jtm); 1101 1102 (void) jtag_powerdown_board(jtm->jtag_cmd, board, 1103 sc->type, &fhc_csr, &fhc_bsr, TRUE); 1104 break; 1105 case SYSC_CFGA_RSTATE_DISCONNECTED: 1106 cmn_err(CE_NOTE, "fhc_bd_test: simulate board %d removal", 1107 board); 1108 1109 if (bdp->ksp) { 1110 kstat_delete(bdp->ksp); 1111 bdp->ksp = NULL; 1112 } 1113 fhc_bd_sc_evt(sc, SYSC_EVT_BD_REMOVED); 1114 break; 1115 default: 1116 cmn_err(CE_NOTE, 1117 "fhc_bd_test: invalid board state: %d", board); 1118 break; 1119 } 1120 1121 return (0); 1122 } 1123 1124 /* 1125 * force a board condition for test purpose 1126 */ 1127 /* ARGSUSED */ 1128 int 1129 fhc_bd_test_set_cond(int board, sysc_cfga_pkt_t *sysc_pkt) 1130 { 1131 fhc_bd_t *bdp; 1132 sysc_cfga_stat_t *sc; 1133 sysc_cfga_cond_t cond; 1134 1135 ASSERT(fhc_bdlist_locked()); 1136 ASSERT(fhc_bd_busy(board)); 1137 1138 bdp = fhc_bd(board); 1139 sc = &bdp->sc; 1140 1141 cond = (sysc_cfga_cond_t)sysc_pkt->cmd_cfga.arg; 1142 1143 switch (cond) { 1144 case SYSC_CFGA_COND_UNKNOWN: 1145 case SYSC_CFGA_COND_OK: 1146 case SYSC_CFGA_COND_FAILING: 1147 case SYSC_CFGA_COND_FAILED: 1148 case SYSC_CFGA_COND_UNUSABLE: 1149 sc->condition = cond; 1150 return (0); 1151 default: 1152 return (EINVAL); 1153 } 1154 } 1155