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