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
fhc_max_boards()81 fhc_max_boards()
82 {
83 return (fhc_bdmax + 1);
84 }
85
86 static int
fhc_bd_disabled(int board)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
fhc_check_array(int btype)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
fhc_shell_sort(fhc_bd_t * a[],int lb,int ub)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
fhc_b_search(fhc_bd_t * in_array[],int board,int first,int last)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
fhc_check_size(fhc_bd_resizable_t * resizable)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
fhc_bdlist_locked()195 fhc_bdlist_locked()
196 {
197 if (panicstr)
198 return (1);
199
200 return (rw_owner(&fhc_bdlist_rwlock) == curthread);
201 }
202
203 int
fhc_bd_busy(int board)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
fhc_bd_is_jtag_master(int board)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
fhc_bd_is_plus(int board)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
fhc_bdlist_init()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
fhc_bdlist_fini()259 fhc_bdlist_fini()
260 {
261 rw_destroy(&fhc_bdlist_rwlock);
262 }
263
264 fhc_bd_t *
fhc_bdlist_lock(int board)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
fhc_bdlist_unlock()285 fhc_bdlist_unlock()
286 {
287 ASSERT(fhc_bdlist_locked());
288
289 rw_exit(&fhc_bdlist_rwlock);
290 }
291
292 static void
fhc_resize(fhc_bd_t *** in_array,int oldsize,int newsize)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
fhc_bd_init(struct fhc_soft_state * softsp,int board,enum board_type type)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 *
fhc_bd(int board)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 *
fhc_bd_clock(void)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 *
fhc_bd_first()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 *
fhc_bd_next(fhc_bd_t * bdp)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
fhc_bd_valid(int bd)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
fhc_bd_type(int board)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 *
fhc_bd_typestr(enum board_type type)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
fhc_bd_env_set(int board,void * env)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
fhc_bd_dlist_init()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
fhc_bd_ks_update(kstat_t * ksp,int rw)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
fhc_bd_ks_alloc(fhc_bd_t * bdp)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
fhc_bdlist_dk_init()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 *
jtag_master_lock(void)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
jtag_master_unlock(struct jt_mstr * mstr)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
fhc_bdlist_prime(int first,int count,int incr)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
set_cpu_info(sysc_cfga_stat_t * sc,uint_t fhc_bsr)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
fhc_bdlist_scan(sysc_cfga_rstate_t rstate,struct jt_mstr * jtm)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
fhc_bd_insert_scan()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
fhc_bd_remove_scan()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
fhc_bd_detachable(int board)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
fhc_bd_sc_register(void (* f)(void *,sysc_cfga_stat_t *,sysc_evt_t),void * sp)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
fhc_bd_update(int board,sysc_evt_t evt)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
fhc_bd_test(int board,sysc_cfga_pkt_t * pkt)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
fhc_bd_test_set_cond(int board,sysc_cfga_pkt_t * sysc_pkt)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