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