xref: /titanic_52/usr/src/uts/sun4u/sunfire/io/fhc_bd.c (revision 29949e866e40b95795203f3ee46f44a197c946e4)
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