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