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