xref: /titanic_44/usr/src/uts/sun4u/sunfire/io/fhc.c (revision 4088bb40326b75ef60834a6c2a92e29e25474b68)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/conf.h>
31 #include <sys/ddi.h>
32 #include <sys/sunddi.h>
33 #include <sys/ddi_impldefs.h>
34 #include <sys/obpdefs.h>
35 #include <sys/promif.h>
36 #include <sys/cmn_err.h>
37 #include <sys/errno.h>
38 #include <sys/kmem.h>
39 #include <sys/vmem.h>
40 #include <sys/debug.h>
41 #include <sys/sysmacros.h>
42 #include <sys/intreg.h>
43 #include <sys/autoconf.h>
44 #include <sys/modctl.h>
45 #include <sys/spl.h>
46 #include <sys/time.h>
47 #include <sys/systm.h>
48 #include <sys/machsystm.h>
49 #include <sys/cpu.h>
50 #include <sys/cpuvar.h>
51 #include <sys/x_call.h>		/* xt_one() */
52 #include <sys/membar.h>
53 #include <sys/vm.h>
54 #include <vm/seg_kmem.h>
55 #include <vm/hat_sfmmu.h>
56 #include <sys/promimpl.h>
57 #include <sys/prom_plat.h>
58 #include <sys/cpu_module.h>	/* flush_instr_mem() */
59 #include <sys/procset.h>
60 #include <sys/fhc.h>
61 #include <sys/ac.h>
62 #include <sys/environ.h>
63 #include <sys/jtag.h>
64 #include <sys/nexusdebug.h>
65 #include <sys/ac.h>
66 #include <sys/ddi_subrdefs.h>
67 #include <sys/eeprom.h>
68 #include <sys/sdt.h>
69 #include <sys/ddi_implfuncs.h>
70 #include <sys/ontrap.h>
71 
72 #ifndef TRUE
73 #define	TRUE (1)
74 #endif
75 #ifndef FALSE
76 #define	FALSE (0)
77 #endif
78 
79 /*
80  * Function to register and deregister callbacks, for sunfire only.
81  */
82 extern void plat_register_tod_fault(void (*func)(enum tod_fault_type));
83 
84 /*
85  * This table represents the FHC interrupt priorities.  They range from
86  * 1-15, and have been modeled after the sun4d interrupts. The mondo
87  * number anded with 0x7 is used to index into this table. This was
88  * done to save table space.
89  */
90 static int fhc_int_priorities[] = {
91 	PIL_15,			/* System interrupt priority */
92 	PIL_12,			/* zs interrupt priority */
93 	PIL_15,			/* TOD interrupt priority */
94 	PIL_15			/* Fan Fail priority */
95 };
96 
97 static void fhc_tod_fault(enum tod_fault_type tod_bad);
98 
99 /*
100  * The dont_calibrate variable is meant to be set to one in /etc/system
101  * or by boot -h so that the calibration tables are not used. This
102  * is useful for checking thermistors whose output seems to be incorrect.
103  */
104 static int dont_calibrate = 0;
105 
106 /* Only one processor should powerdown the system. */
107 static int powerdown_started = 0;
108 
109 /* Let user disable overtemp powerdown. */
110 int enable_overtemp_powerdown = 1;
111 
112 /*
113  * The following tables correspond to the degress Celcius for each count
114  * value possible from the 8-bit A/C convertors on each type of system
115  * board for the UltraSPARC Server systems. To access a temperature,
116  * just index into the correct table using the count from the A/D convertor
117  * register, and that is the correct temperature in degress Celsius. These
118  * values can be negative.
119  */
120 static short cpu_table[] = {
121 -16,	-14,	-12,	-10,	-8,	-6,	-4,	-2,	/* 0-7 */
122 1,	4,	6,	8,	10,	12,	13,	15,	/* 8-15 */
123 16,	18,	19,	20,	22,	23,	24,	25,	/* 16-23 */
124 26,	27,	28,	29,	30,	31,	32,	33,	/* 24-31 */
125 34,	35,	35,	36,	37,	38,	39,	39,	/* 32-39 */
126 40,	41,	41,	42,	43,	44,	44,	45,	/* 40-47 */
127 46,	46,	47,	47,	48,	49,	49,	50,	/* 48-55 */
128 51,	51,	52,	53,	53,	54,	54,	55,	/* 56-63 */
129 55,	56,	56,	57,	57,	58,	58,	59,	/* 64-71 */
130 60,	60,	61,	61,	62,	62,	63,	63,	/* 72-79 */
131 64,	64,	65,	65,	66,	66,	67,	67,	/* 80-87 */
132 68,	68,	69,	69,	70,	70,	71,	71,	/* 88-95 */
133 72,	72,	73,	73,	74,	74,	75,	75,	/* 96-103 */
134 76,	76,	77,	77,	78,	78,	79,	79,	/* 104-111 */
135 80,	80,	81,	81,	82,	82,	83,	83,	/* 112-119 */
136 84,	84,	85,	85,	86,	86,	87,	87,	/* 120-127 */
137 88,	88,	89,	89,	90,	90,	91,	91,	/* 128-135 */
138 92,	92,	93,	93,	94,	94,	95,	95,	/* 136-143 */
139 96,	96,	97,	98,	98,	99,	99,	100,	/* 144-151 */
140 100,	101,	101,	102,	103,	103,	104,	104,	/* 152-159 */
141 105,	106,	106,	107,	107,	108,	109,	109,	/* 160-167 */
142 110,								/* 168 */
143 };
144 
145 #define	CPU_MX_CNT	(sizeof (cpu_table)/sizeof (short))
146 
147 static short cpu2_table[] = {
148 -17,	-16,	-15,	-14,	-13,	-12,	-11,	-10,	/* 0-7 */
149 -9,	-8,	-7,	-6,	-5,	-4,	-3,	-2,	/* 8-15 */
150 -1,	0,	1,	2,	3,	4,	5,	6,	/* 16-23 */
151 7,	8,	9,	10,	11,	12,	13,	13,	/* 24-31 */
152 14,	15,	16,	16,	17,	18,	18,	19,	/* 32-39 */
153 20,	20,	21,	22,	22,	23,	24,	24,	/* 40-47 */
154 25,	25,	26,	26,	27,	27,	28,	28,	/* 48-55 */
155 29,	30,	30,	31,	31,	32,	32,	33,	/* 56-63 */
156 33,	34,	34,	35,	35,	36,	36,	37,	/* 64-71 */
157 37,	37,	38,	38,	39,	39,	40,	40,	/* 72-79 */
158 41,	41,	42,	42,	43,	43,	43,	44,	/* 80-87 */
159 44,	45,	45,	46,	46,	46,	47,	47,	/* 88-95 */
160 48,	48,	49,	49,	50,	50,	50,	51,	/* 96-103 */
161 51,	52,	52,	53,	53,	53,	54,	54,	/* 104-111 */
162 55,	55,	56,	56,	56,	57,	57,	58,	/* 112-119 */
163 58,	59,	59,	59,	60,	60,	61,	61,	/* 120-127 */
164 62,	62,	63,	63,	63,	64,	64,	65,	/* 128-135 */
165 65,	66,	66,	67,	67,	68,	68,	68,	/* 136-143 */
166 69,	69,	70,	70,	71,	71,	72,	72,	/* 144-151 */
167 73,	73,	74,	74,	75,	75,	76,	76,	/* 152-159 */
168 77,	77,	78,	78,	79,	79,	80,	80,	/* 160-167 */
169 81,	81,	82,	83,	83,	84,	84,	85,	/* 168-175 */
170 85,	86,	87,	87,	88,	88,	89,	90,	/* 176-183 */
171 90,	91,	92,	92,	93,	94,	94,	95,	/* 184-191 */
172 96,	96,	97,	98,	99,	99,	100,	101,	/* 192-199 */
173 102,	103,	103,	104,	105,	106,	107,	108,	/* 200-207 */
174 109,	110,							/* 208-209 */
175 };
176 
177 #define	CPU2_MX_CNT	(sizeof (cpu2_table)/sizeof (short))
178 
179 static short io_table[] = {
180 0,	0,	0,	0,	0,	0,	0,	0,	/* 0-7 */
181 0,	0,	0,	0,	0,	0,	0,	0,	/* 8-15 */
182 0,	0,	0,	0,	0,	0,	0,	0,	/* 16-23 */
183 0,	0,	0,	0,	0,	0,	0,	0,	/* 24-31 */
184 0,	0,	0,	0,	0,	0,	0,	0,	/* 32-39 */
185 0,	3,	7,	10,	13,	15,	17,	19,	/* 40-47 */
186 21,	23,	25,	27,	28,	30,	31,	32,	/* 48-55 */
187 34,	35,	36,	37,	38,	39,	41,	42,	/* 56-63 */
188 43,	44,	45,	46,	46,	47,	48,	49,	/* 64-71 */
189 50,	51,	52,	53,	53,	54,	55,	56,	/* 72-79 */
190 57,	57,	58,	59,	60,	60,	61,	62,	/* 80-87 */
191 62,	63,	64,	64,	65,	66,	66,	67,	/* 88-95 */
192 68,	68,	69,	70,	70,	71,	72,	72,	/* 96-103 */
193 73,	73,	74,	75,	75,	76,	77,	77,	/* 104-111 */
194 78,	78,	79,	80,	80,	81,	81,	82,	/* 112-119 */
195 };
196 
197 #define	IO_MN_CNT	40
198 #define	IO_MX_CNT	(sizeof (io_table)/sizeof (short))
199 
200 static short clock_table[] = {
201 0,	0,	0,	0,	0,	0,	0,	0,	/* 0-7 */
202 0,	0,	0,	0,	1,	2,	4,	5,	/* 8-15 */
203 7,	8,	10,	11,	12,	13,	14,	15,	/* 16-23 */
204 17,	18,	19,	20,	21,	22,	23,	24,	/* 24-31 */
205 24,	25,	26,	27,	28,	29,	29,	30,	/* 32-39 */
206 31,	32,	32,	33,	34,	35,	35,	36,	/* 40-47 */
207 37,	38,	38,	39,	40,	40,	41,	42,	/* 48-55 */
208 42,	43,	44,	44,	45,	46,	46,	47,	/* 56-63 */
209 48,	48,	49,	50,	50,	51,	52,	52,	/* 64-71 */
210 53,	54,	54,	55,	56,	57,	57,	58,	/* 72-79 */
211 59,	59,	60,	60,	61,	62,	63,	63,	/* 80-87 */
212 64,	65,	65,	66,	67,	68,	68,	69,	/* 88-95 */
213 70,	70,	71,	72,	73,	74,	74,	75,	/* 96-103 */
214 76,	77,	78,	78,	79,	80,	81,	82,	/* 104-111 */
215 };
216 
217 #define	CLK_MN_CNT	11
218 #define	CLK_MX_CNT	(sizeof (clock_table)/sizeof (short))
219 
220 /*
221  * System temperature limits.
222  *
223  * The following variables are the warning and danger limits for the
224  * different types of system boards. The limits are different because
225  * the various boards reach different nominal temperatures because
226  * of the different components that they contain.
227  *
228  * The warning limit is the temperature at which the user is warned.
229  * The danger limit is the temperature at which the system is shutdown.
230  * In the case of CPU/Memory system boards, the system will attempt
231  * to offline and power down processors on a board in an attempt to
232  * bring the board back into the nominal temperature range before
233  * shutting down the system.
234  *
235  * These values can be tuned via /etc/system or boot -h.
236  */
237 short cpu_warn_temp = 73;	/* CPU/Memory Warning Temperature */
238 short cpu_danger_temp = 83;	/* CPU/Memory Danger Temperature */
239 short io_warn_temp = 60;	/* IO Board Warning Temperature */
240 short io_danger_temp = 68;	/* IO Board Danger Temperature */
241 short clk_warn_temp = 60;	/* Clock Board Warning Temperature */
242 short clk_danger_temp = 68;	/* Clock Board Danger Temperature */
243 
244 short dft_warn_temp = 60;	/* default warning temp value */
245 short dft_danger_temp = 68;	/* default danger temp value */
246 
247 short cpu_warn_temp_4x = 60; 	/* CPU/Memory warning temp for 400 MHZ */
248 short cpu_danger_temp_4x = 68;	/* CPU/Memory danger temp for 400 MHZ */
249 
250 /*
251  * This variable tells us if we are in a heat chamber. It is set
252  * early on in boot, after we check the OBP 'mfg-mode' property in
253  * the options node.
254  */
255 static int temperature_chamber = -1;
256 
257 /*
258  * The fhc memloc structure is protected under the bdlist lock
259  */
260 static struct fhc_memloc *fhc_base_memloc = NULL;
261 
262 /*
263  * Driver global fault list mutex and list head pointer. The list is
264  * protected by the mutex and contains a record of all known faults.
265  * Faults can be inherited from the PROM or detected by the kernel.
266  */
267 static kmutex_t ftlist_mutex;
268 static struct ft_link_list *ft_list = NULL;
269 static int ft_nfaults = 0;
270 
271 /*
272  * Table of all known fault strings. This table is indexed by the fault
273  * type. Do not change the ordering of the table without redefining the
274  * fault type enum list on fhc.h.
275  */
276 char *ft_str_table[] = {
277 	"Core Power Supply",		/* FT_CORE_PS */
278 	"Overtemp",			/* FT_OVERTEMP */
279 	"AC Power",			/* FT_AC_PWR */
280 	"Peripheral Power Supply",	/* FT_PPS */
281 	"System 3.3 Volt Power",	/* FT_CLK_33 */
282 	"System 5.0 Volt Power",	/* FT_CLK_50 */
283 	"Peripheral 5.0 Volt Power",	/* FT_V5_P */
284 	"Peripheral 12 Volt Power",	/* FT_V12_P */
285 	"Auxiliary 5.0 Volt Power",	/* FT_V5_AUX */
286 	"Peripheral 5.0 Volt Precharge", /* FT_V5_P_PCH */
287 	"Peripheral 12 Volt Precharge",	/* FT_V12_P_PCH */
288 	"System 3.3 Volt Precharge",	/* FT_V3_PCH */
289 	"System 5.0 Volt Precharge",	/* FT_V5_PCH */
290 	"Peripheral Power Supply Fans",	/* FT_PPS_FAN */
291 	"Rack Exhaust Fan",		/* FT_RACK_EXH */
292 	"Disk Drive Fan",		/* FT_DSK_FAN */
293 	"AC Box Fan",			/* FT_AC_FAN */
294 	"Key Switch Fan",		/* FT_KEYSW_FAN */
295 	"Minimum Power",		/* FT_INSUFFICIENT_POWER */
296 	"PROM detected",		/* FT_PROM */
297 	"Hot Plug Support System",	/* FT_HOT_PLUG */
298 	"TOD"				/* FT_TODFAULT */
299 };
300 
301 static int ft_max_index = (sizeof (ft_str_table) / sizeof (char *));
302 
303 /*
304  * Function prototypes
305  */
306 static int fhc_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t,
307 	void *, void *);
308 static int fhc_intr_ops(dev_info_t *dip, dev_info_t *rdip,
309 	ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result);
310 
311 static int fhc_add_intr_impl(dev_info_t *dip, dev_info_t *rdip,
312 	ddi_intr_handle_impl_t *hdlp);
313 static void fhc_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip,
314 	ddi_intr_handle_impl_t *hdlp);
315 
316 static int fhc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
317 static int fhc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
318 static int fhc_init(struct fhc_soft_state *softsp);
319 static void fhc_unmap_regs(struct fhc_soft_state *softsp);
320 static enum board_type fhc_board_type(struct fhc_soft_state *, int);
321 
322 static void
323 fhc_xlate_intrs(ddi_intr_handle_impl_t *hdlp, uint32_t ign);
324 
325 static int
326 fhc_ctlops_peekpoke(ddi_ctl_enum_t, peekpoke_ctlops_t *, void *result);
327 
328 static void fhc_add_kstats(struct fhc_soft_state *);
329 static int fhc_kstat_update(kstat_t *, int);
330 static int check_for_chamber(void);
331 static int ft_ks_snapshot(struct kstat *, void *, int);
332 static int ft_ks_update(struct kstat *, int);
333 static int check_central(int board);
334 
335 /*
336  * board type and A/D convertor output passed in and real temperature
337  * is returned.
338  */
339 static short calibrate_temp(enum board_type, uchar_t, uint_t);
340 static enum temp_state get_temp_state(enum board_type, short, int);
341 
342 /* Routine to determine if there are CPUs on this board. */
343 static int cpu_on_board(int);
344 
345 static void build_bd_display_str(char *, enum board_type, int);
346 
347 /* Interrupt distribution callback function. */
348 static void fhc_intrdist(void *);
349 
350 /* CPU power control */
351 int fhc_cpu_poweroff(struct cpu *);	/* cpu_poweroff()->platform */
352 int fhc_cpu_poweron(struct cpu *);	/* cpu_poweron()->platform */
353 
354 extern struct cpu_node cpunodes[];
355 extern void halt(char *);
356 
357 /*
358  * Configuration data structures
359  */
360 static struct bus_ops fhc_bus_ops = {
361 	BUSO_REV,
362 	ddi_bus_map,		/* map */
363 	0,			/* get_intrspec */
364 	0,			/* add_intrspec */
365 	0,			/* remove_intrspec */
366 	i_ddi_map_fault,	/* map_fault */
367 	ddi_no_dma_map,		/* dma_map */
368 	ddi_no_dma_allochdl,
369 	ddi_no_dma_freehdl,
370 	ddi_no_dma_bindhdl,
371 	ddi_no_dma_unbindhdl,
372 	ddi_no_dma_flush,
373 	ddi_no_dma_win,
374 	ddi_dma_mctl,		/* dma_ctl */
375 	fhc_ctlops,		/* ctl */
376 	ddi_bus_prop_op,	/* prop_op */
377 	0,			/* (*bus_get_eventcookie)();	*/
378 	0,			/* (*bus_add_eventcall)();	*/
379 	0,			/* (*bus_remove_eventcall)();	*/
380 	0,			/* (*bus_post_event)();		*/
381 	0,			/* (*bus_intr_control)();	*/
382 	0,			/* (*bus_config)();		*/
383 	0,			/* (*bus_unconfig)();		*/
384 	0,			/* (*bus_fm_init)();		*/
385 	0,			/* (*bus_fm_fini)();		*/
386 	0,			/* (*bus_fm_access_enter)();	*/
387 	0,			/* (*bus_fm_access_exit)();	*/
388 	0,			/* (*bus_power)();		*/
389 	fhc_intr_ops		/* (*bus_intr_op)();		*/
390 };
391 
392 static struct cb_ops fhc_cb_ops = {
393 	nulldev,		/* open */
394 	nulldev,		/* close */
395 	nulldev,		/* strategy */
396 	nulldev,		/* print */
397 	nulldev,		/* dump */
398 	nulldev,		/* read */
399 	nulldev,		/* write */
400 	nulldev, 		/* ioctl */
401 	nodev,			/* devmap */
402 	nodev,			/* mmap */
403 	nodev,			/* segmap */
404 	nochpoll,		/* poll */
405 	ddi_prop_op,		/* cb_prop_op */
406 	0,			/* streamtab */
407 	D_MP|D_NEW|D_HOTPLUG,	/* Driver compatibility flag */
408 	CB_REV,			/* rev */
409 	nodev,			/* cb_aread */
410 	nodev			/* cb_awrite */
411 };
412 
413 static struct dev_ops fhc_ops = {
414 	DEVO_REV,		/* rev */
415 	0,			/* refcnt  */
416 	ddi_no_info,		/* getinfo */
417 	nulldev,		/* identify */
418 	nulldev,		/* probe */
419 	fhc_attach,		/* attach */
420 	fhc_detach,		/* detach */
421 	nulldev,		/* reset */
422 	&fhc_cb_ops,		/* cb_ops */
423 	&fhc_bus_ops,		/* bus_ops */
424 	nulldev			/* power */
425 };
426 
427 /*
428  * Driver globals
429  * TODO - We need to investigate what locking needs to be done here.
430  */
431 void *fhcp;				/* fhc soft state hook */
432 
433 extern struct mod_ops mod_driverops;
434 
435 static struct modldrv modldrv = {
436 	&mod_driverops,		/* Type of module.  This one is a driver */
437 	"FHC Nexus v%I%",	/* Name of module. */
438 	&fhc_ops,		/* driver ops */
439 };
440 
441 static struct modlinkage modlinkage = {
442 	MODREV_1,		/* rev */
443 	(void *)&modldrv,
444 	NULL
445 };
446 
447 
448 /*
449  * These are the module initialization routines.
450  */
451 
452 static caddr_t shutdown_va;
453 
454 int
455 _init(void)
456 {
457 	int error;
458 
459 	if ((error = ddi_soft_state_init(&fhcp,
460 	    sizeof (struct fhc_soft_state), 1)) != 0)
461 		return (error);
462 
463 	fhc_bdlist_init();
464 	mutex_init(&ftlist_mutex, NULL, MUTEX_DEFAULT, NULL);
465 
466 	shutdown_va = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP);
467 	ASSERT(shutdown_va != NULL);
468 
469 	plat_register_tod_fault(fhc_tod_fault);
470 
471 	return (mod_install(&modlinkage));
472 }
473 
474 int
475 _fini(void)
476 {
477 	int error;
478 
479 	if ((error = mod_remove(&modlinkage)) != 0)
480 		return (error);
481 
482 	plat_register_tod_fault(NULL);
483 
484 	mutex_destroy(&ftlist_mutex);
485 
486 	fhc_bdlist_fini();
487 
488 	ddi_soft_state_fini(&fhcp);
489 
490 	return (0);
491 }
492 
493 int
494 _info(struct modinfo *modinfop)
495 {
496 	return (mod_info(&modlinkage, modinfop));
497 }
498 
499 /*
500  * Reset the interrupt mapping registers.
501  * This function resets the values during DDI_RESUME.
502  *
503  * NOTE: This function will not work for a full CPR cycle
504  * and is currently designed to handle the RESUME after a connect.
505  *
506  * Note about the PROM handling of moving CENTRAL to another board:
507  * The PROM moves the IGN identity (igr register) from the
508  * original CENTRAL to the new one. This means that we do not
509  * duplicate the fhc_attach code that sets it to (board number * 2).
510  * We rely on only using FHC interrupts from one board only
511  * (the UART and SYS interrupts) so that the values of the other IGNs
512  * are irrelevant. The benefit of this approach is that we don't
513  * have to have to tear down and rebuild the interrupt records
514  * for UART and SYS. It is also why we don't try to change the
515  * board number in the fhc instance for the clock board.
516  */
517 static void
518 fhc_handle_imr(struct fhc_soft_state *softsp)
519 {
520 	int i;
521 	int cent;
522 	uint_t tmp_reg;
523 
524 
525 	if (softsp->is_central) {
526 		uint_t want_igr, act_igr;
527 
528 		want_igr = softsp->list->sc.board << 1;
529 		act_igr = *softsp->igr & 0x1f;
530 		if (want_igr != act_igr) {
531 			*softsp->igr = want_igr;
532 			tmp_reg = *softsp->igr;
533 #ifdef lint
534 			tmp_reg = tmp_reg;
535 #endif
536 			/* We must now re-issue any pending interrupts. */
537 			for (i = 0; i < FHC_MAX_INO; i++) {
538 				if (*(softsp->intr_regs[i].clear_reg) == 3) {
539 					*(softsp->intr_regs[i].clear_reg) =
540 					    ISM_IDLE;
541 
542 					tmp_reg =
543 					    *(softsp->intr_regs[i].clear_reg);
544 #ifdef lint
545 					tmp_reg = tmp_reg;
546 #endif
547 				}
548 			}
549 			cmn_err(CE_NOTE, "central IGN corruption fixed: "
550 				"got %x wanted %x", act_igr, want_igr);
551 		}
552 		return;
553 	}
554 
555 	ASSERT(softsp->list->sc.board == FHC_BSR_TO_BD(*(softsp->bsr)));
556 	cent = check_central(softsp->list->sc.board);
557 
558 	/* Loop through all 4 FHC interrupt mapping registers */
559 	for (i = 0; i < FHC_MAX_INO; i++) {
560 
561 		if (i == FHC_SYS_INO &&
562 		    *(softsp->intr_regs[i].clear_reg) == 3) {
563 			cmn_err(CE_NOTE,
564 			    "found lost system interrupt, resetting..");
565 
566 			*(softsp->intr_regs[i].clear_reg) = ISM_IDLE;
567 
568 			/*
569 			 * ensure atomic write with this read.
570 			 */
571 			tmp_reg = *(softsp->intr_regs[i].clear_reg);
572 #ifdef lint
573 			tmp_reg = tmp_reg;
574 #endif
575 		}
576 
577 		/*
578 		 * The mapping registers on the board with the "central" bit
579 		 * set should not be touched as it has been taken care by POST.
580 		 */
581 
582 		if (cent)
583 			continue;
584 
585 		*(softsp->intr_regs[i].mapping_reg) = 0;
586 
587 		/*
588 		 * ensure atomic write with this read.
589 		 */
590 		tmp_reg = *(softsp->intr_regs[i].mapping_reg);
591 #ifdef lint
592 		tmp_reg = tmp_reg;
593 #endif
594 
595 	}
596 }
597 
598 static int
599 check_central(int board)
600 {
601 	uint_t cs_value;
602 
603 	/*
604 	 * This is the value of AC configuration and status reg
605 	 * in the Local Devices space. We access it as a physical
606 	 * address.
607 	 */
608 	cs_value = ldphysio(AC_BCSR(board));
609 	if (cs_value & AC_CENTRAL)
610 		return (TRUE);
611 	else
612 		return (FALSE);
613 }
614 
615 static int
616 fhc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
617 {
618 	struct fhc_soft_state *softsp;
619 	int instance;
620 
621 	instance = ddi_get_instance(devi);
622 
623 	switch (cmd) {
624 	case DDI_ATTACH:
625 		break;
626 
627 	case DDI_RESUME:
628 		softsp = ddi_get_soft_state(fhcp, instance);
629 		/* IGR, NOT_BRD_PRES handled by prom */
630 		/* reset interrupt mapping registers */
631 		fhc_handle_imr(softsp);
632 
633 		return (DDI_SUCCESS);
634 
635 	default:
636 		return (DDI_FAILURE);
637 	}
638 
639 
640 	if (ddi_soft_state_zalloc(fhcp, instance) != DDI_SUCCESS)
641 		return (DDI_FAILURE);
642 
643 	softsp = ddi_get_soft_state(fhcp, instance);
644 
645 	/* Set the dip in the soft state */
646 	softsp->dip = devi;
647 
648 	if (fhc_init(softsp) != DDI_SUCCESS)
649 		goto bad;
650 
651 	ddi_report_dev(devi);
652 
653 	return (DDI_SUCCESS);
654 
655 bad:
656 	ddi_soft_state_free(fhcp, instance);
657 	return (DDI_FAILURE);
658 }
659 
660 static int
661 fhc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
662 {
663 	int board;
664 	int instance;
665 	struct fhc_soft_state *softsp;
666 	fhc_bd_t *list = NULL;
667 
668 	/* get the instance of this devi */
669 	instance = ddi_get_instance(devi);
670 
671 	/* get the soft state pointer for this device node */
672 	softsp = ddi_get_soft_state(fhcp, instance);
673 
674 	board = softsp->list->sc.board;
675 
676 	switch (cmd) {
677 	case DDI_SUSPEND:
678 
679 		return (DDI_SUCCESS);
680 
681 	case DDI_DETACH:
682 		/* grab the lock on the board list */
683 		list = fhc_bdlist_lock(board);
684 
685 		if (fhc_bd_detachable(board) &&
686 		    !fhc_bd_is_jtag_master(board))
687 			break;
688 		else
689 			fhc_bdlist_unlock();
690 		/* FALLTHROUGH */
691 
692 	default:
693 		return (DDI_FAILURE);
694 	}
695 
696 	/* Remove the interrupt redistribution callback. */
697 	intr_dist_rem(fhc_intrdist, (void *)devi);
698 
699 	/* remove the soft state pointer from the board list */
700 	list->softsp = NULL;
701 
702 	/* clear inherited faults from the PROM. */
703 	clear_fault(list->sc.board, FT_PROM, FT_BOARD);
704 
705 	/* remove the kstat for this board */
706 	kstat_delete(softsp->fhc_ksp);
707 
708 	/* destroy the mutexes in this soft state structure */
709 	mutex_destroy(&softsp->poll_list_lock);
710 	mutex_destroy(&softsp->ctrl_lock);
711 
712 	/* unmap all the register sets */
713 	fhc_unmap_regs(softsp);
714 
715 	/* release the board list lock now */
716 	fhc_bdlist_unlock();
717 
718 	/* free the soft state structure */
719 	ddi_soft_state_free(fhcp, instance);
720 
721 	return (DDI_SUCCESS);
722 }
723 
724 static enum board_type
725 fhc_board_type(struct fhc_soft_state *softsp, int board)
726 {
727 	int proplen;
728 	char *board_type;
729 	enum board_type type;
730 
731 	if (softsp->is_central)
732 		type = CLOCK_BOARD;
733 	else if (ddi_getlongprop(DDI_DEV_T_ANY, softsp->dip,
734 	    DDI_PROP_DONTPASS, "board-type", (caddr_t)&board_type,
735 	    &proplen) == DDI_PROP_SUCCESS) {
736 		/* match the board-type string */
737 		if (strcmp(CPU_BD_NAME, board_type) == 0) {
738 			type = CPU_BOARD;
739 		} else if (strcmp(MEM_BD_NAME, board_type) == 0) {
740 			type = MEM_BOARD;
741 		} else if (strcmp(IO_2SBUS_BD_NAME, board_type) == 0) {
742 			type = IO_2SBUS_BOARD;
743 		} else if (strcmp(IO_SBUS_FFB_BD_NAME, board_type) == 0) {
744 			type = IO_SBUS_FFB_BOARD;
745 		} else if (strcmp(IO_2SBUS_SOCPLUS_BD_NAME, board_type) == 0) {
746 			type = IO_2SBUS_SOCPLUS_BOARD;
747 		} else if (strcmp(IO_SBUS_FFB_SOCPLUS_BD_NAME, board_type)
748 		    == 0) {
749 			type = IO_SBUS_FFB_SOCPLUS_BOARD;
750 		} else if (strcmp(IO_PCI_BD_NAME, board_type) == 0) {
751 			type = IO_PCI_BOARD;
752 		} else {
753 			type = UNKNOWN_BOARD;
754 		}
755 		kmem_free(board_type, proplen);
756 	} else
757 		type = UNKNOWN_BOARD;
758 
759 	/*
760 	 * if the board type is indeterminate, it must be determined.
761 	 */
762 	if (type == UNKNOWN_BOARD) {
763 		/*
764 		 * Use the UPA64 bits from the FHC.
765 		 * This is not the best solution since we
766 		 * cannot fully type the IO boards.
767 		 */
768 		if (cpu_on_board(board))
769 			type = CPU_BOARD;
770 		else if ((*(softsp->bsr) & FHC_UPADATA64A) ||
771 			(*(softsp->bsr) & FHC_UPADATA64B))
772 			type = IO_2SBUS_BOARD;
773 		else
774 			type = MEM_BOARD;
775 	}
776 
777 	return (type);
778 }
779 
780 static void
781 fhc_unmap_regs(struct fhc_soft_state *softsp)
782 {
783 	dev_info_t *dip = softsp->dip;
784 
785 	if (softsp->id) {
786 		ddi_unmap_regs(dip, 0, (caddr_t *)&softsp->id, 0, 0);
787 		softsp->id = NULL;
788 	}
789 	if (softsp->igr) {
790 		ddi_unmap_regs(dip, 1, (caddr_t *)&softsp->igr, 0, 0);
791 		softsp->igr = NULL;
792 	}
793 	if (softsp->intr_regs[FHC_FANFAIL_INO].mapping_reg) {
794 		ddi_unmap_regs(dip, 2,
795 		(caddr_t *)&softsp->intr_regs[FHC_FANFAIL_INO].mapping_reg,
796 		0, 0);
797 		softsp->intr_regs[FHC_FANFAIL_INO].mapping_reg = NULL;
798 	}
799 	if (softsp->intr_regs[FHC_SYS_INO].mapping_reg) {
800 		ddi_unmap_regs(dip, 3,
801 		(caddr_t *)&softsp->intr_regs[FHC_SYS_INO].mapping_reg,
802 		0, 0);
803 		softsp->intr_regs[FHC_SYS_INO].mapping_reg = NULL;
804 	}
805 	if (softsp->intr_regs[FHC_UART_INO].mapping_reg) {
806 		ddi_unmap_regs(dip, 4,
807 		(caddr_t *)&softsp->intr_regs[FHC_UART_INO].mapping_reg,
808 		0, 0);
809 		softsp->intr_regs[FHC_UART_INO].mapping_reg = NULL;
810 	}
811 	if (softsp->intr_regs[FHC_TOD_INO].mapping_reg) {
812 		ddi_unmap_regs(dip, 5,
813 		(caddr_t *)&softsp->intr_regs[FHC_TOD_INO].mapping_reg,
814 		0, 0);
815 		softsp->intr_regs[FHC_TOD_INO].mapping_reg = NULL;
816 	}
817 }
818 
819 static int
820 fhc_init(struct fhc_soft_state *softsp)
821 {
822 	int i;
823 	uint_t tmp_reg;
824 	int board;
825 
826 	/*
827 	 * Map in the FHC registers. Specifying length and offset of
828 	 * zero maps in the entire OBP register set.
829 	 */
830 
831 	/* map in register set 0 */
832 	if (ddi_map_regs(softsp->dip, 0,
833 	    (caddr_t *)&softsp->id, 0, 0)) {
834 		cmn_err(CE_WARN, "fhc%d: unable to map internal "
835 			"registers", ddi_get_instance(softsp->dip));
836 		goto bad;
837 	}
838 
839 	/*
840 	 * Fill in the virtual addresses of the registers in the
841 	 * fhc_soft_state structure.
842 	 */
843 	softsp->rctrl = (uint_t *)((char *)(softsp->id) +
844 		FHC_OFF_RCTRL);
845 	softsp->ctrl = (uint_t *)((char *)(softsp->id) +
846 		FHC_OFF_CTRL);
847 	softsp->bsr = (uint_t *)((char *)(softsp->id) +
848 		FHC_OFF_BSR);
849 	softsp->jtag_ctrl = (uint_t *)((char *)(softsp->id) +
850 		FHC_OFF_JTAG_CTRL);
851 	softsp->jt_master.jtag_cmd = (uint_t *)((char *)(softsp->id) +
852 		FHC_OFF_JTAG_CMD);
853 
854 	/* map in register set 1 */
855 	if (ddi_map_regs(softsp->dip, 1,
856 	    (caddr_t *)&softsp->igr, 0, 0)) {
857 		cmn_err(CE_WARN, "fhc%d: unable to map IGR "
858 			"register", ddi_get_instance(softsp->dip));
859 		goto bad;
860 	}
861 
862 	/*
863 	 * map in register set 2
864 	 * XXX this can never be used as an interrupt generator
865 	 * (hardware queue overflow in fhc)
866 	 */
867 	if (ddi_map_regs(softsp->dip, 2,
868 	    (caddr_t *)&softsp->intr_regs[FHC_FANFAIL_INO].mapping_reg,
869 	    0, 0)) {
870 		cmn_err(CE_WARN, "fhc%d: unable to map Fan Fail "
871 			"IMR register", ddi_get_instance(softsp->dip));
872 		goto bad;
873 	}
874 
875 	/* map in register set 3 */
876 	if (ddi_map_regs(softsp->dip, 3,
877 	    (caddr_t *)&softsp->intr_regs[FHC_SYS_INO].mapping_reg,
878 	    0, 0)) {
879 		cmn_err(CE_WARN, "fhc%d: unable to map System "
880 			"IMR register\n", ddi_get_instance(softsp->dip));
881 		goto bad;
882 	}
883 
884 	/* map in register set 4 */
885 	if (ddi_map_regs(softsp->dip, 4,
886 	    (caddr_t *)&softsp->intr_regs[FHC_UART_INO].mapping_reg,
887 	    0, 0)) {
888 		cmn_err(CE_WARN, "fhc%d: unable to map UART "
889 			"IMR register\n", ddi_get_instance(softsp->dip));
890 		goto bad;
891 	}
892 
893 	/* map in register set 5 */
894 	if (ddi_map_regs(softsp->dip, 5,
895 	    (caddr_t *)&softsp->intr_regs[FHC_TOD_INO].mapping_reg,
896 	    0, 0)) {
897 		cmn_err(CE_WARN, "fhc%d: unable to map FHC TOD "
898 			"IMR register", ddi_get_instance(softsp->dip));
899 		goto bad;
900 	}
901 
902 	/* Loop over all intr sets and setup the VAs for the ISMR */
903 	/* TODO - Make sure we are calculating the ISMR correctly. */
904 	for (i = 0; i < FHC_MAX_INO; i++) {
905 		softsp->intr_regs[i].clear_reg =
906 			(uint_t *)((char *)(softsp->intr_regs[i].mapping_reg) +
907 			FHC_OFF_ISMR);
908 
909 		/* Now clear the state machines to idle */
910 		*(softsp->intr_regs[i].clear_reg) = ISM_IDLE;
911 	}
912 
913 	/*
914 	 * It is OK to not have a OBP_BOARDNUM property. This happens for
915 	 * the board which is a child of central. However this FHC
916 	 * still needs a proper Interrupt Group Number programmed
917 	 * into the Interrupt Group register, because the other
918 	 * instance of FHC, which is not under central, will properly
919 	 * program the IGR. The numbers from the two settings of the
920 	 * IGR need to be the same. One driver cannot wait for the
921 	 * other to program the IGR, because there is no guarantee
922 	 * which instance of FHC will get attached first.
923 	 */
924 	if ((board = (int)ddi_getprop(DDI_DEV_T_ANY, softsp->dip,
925 	    DDI_PROP_DONTPASS, OBP_BOARDNUM, -1)) == -1) {
926 		/*
927 		 * Now determine the board number by reading the
928 		 * hardware register.
929 		 */
930 		board = FHC_BSR_TO_BD(*(softsp->bsr));
931 		softsp->is_central = 1;
932 	}
933 
934 	/*
935 	 * If this fhc holds JTAG master line, and is not the central fhc,
936 	 * (this avoids two JTAG master nodes) then initialize the
937 	 * mutex and set the flag in the structure.
938 	 */
939 	if ((*(softsp->jtag_ctrl) & JTAG_MASTER_EN) && !softsp->is_central) {
940 		mutex_init(&(softsp->jt_master.lock), NULL, MUTEX_DEFAULT,
941 		    NULL);
942 		softsp->jt_master.is_master = 1;
943 	} else {
944 		softsp->jt_master.is_master = 0;
945 	}
946 
947 	fhc_bd_init(softsp, board, fhc_board_type(softsp, board));
948 
949 	/* Initialize the mutex guarding the poll_list. */
950 	mutex_init(&softsp->poll_list_lock, NULL, MUTEX_DRIVER, NULL);
951 
952 	/* Initialize the mutex guarding the FHC CSR */
953 	mutex_init(&softsp->ctrl_lock, NULL, MUTEX_DRIVER, NULL);
954 
955 	/* Initialize the poll_list to be empty */
956 	for (i = 0; i < MAX_ZS_CNT; i++) {
957 		softsp->poll_list[i].funcp = NULL;
958 	}
959 
960 	/* Modify the various registers in the FHC now */
961 
962 	/*
963 	 * We know this board to be present now, record that state and
964 	 * remove the NOT_BRD_PRES condition
965 	 */
966 	if (!(softsp->is_central)) {
967 		mutex_enter(&softsp->ctrl_lock);
968 		*(softsp->ctrl) |= FHC_NOT_BRD_PRES;
969 		/* Now flush the hardware store buffers. */
970 		tmp_reg = *(softsp->ctrl);
971 #ifdef lint
972 		tmp_reg = tmp_reg;
973 #endif
974 		/* XXX record the board state in global space */
975 		mutex_exit(&softsp->ctrl_lock);
976 
977 		/* Add kstats for all non-central instances of the FHC. */
978 		fhc_add_kstats(softsp);
979 	}
980 
981 	/*
982 	 * Read the device tree to see if this system is in an environmental
983 	 * chamber.
984 	 */
985 	if (temperature_chamber == -1) {
986 		temperature_chamber = check_for_chamber();
987 	}
988 
989 	/* Check for inherited faults from the PROM. */
990 	if (*softsp->ctrl & FHC_LED_MID) {
991 		reg_fault(softsp->list->sc.board, FT_PROM, FT_BOARD);
992 	}
993 
994 	/*
995 	 * setup the IGR. Shift the board number over by one to get
996 	 * the UPA MID.
997 	 */
998 	*(softsp->igr) = (softsp->list->sc.board) << 1;
999 
1000 	/* Now flush the hardware store buffers. */
1001 	tmp_reg = *(softsp->id);
1002 #ifdef lint
1003 	tmp_reg = tmp_reg;
1004 #endif
1005 
1006 	/* Add the interrupt redistribution callback. */
1007 	intr_dist_add(fhc_intrdist, (void *)softsp->dip);
1008 
1009 	return (DDI_SUCCESS);
1010 bad:
1011 	fhc_unmap_regs(softsp);
1012 	return (DDI_FAILURE);
1013 }
1014 
1015 static uint_t
1016 fhc_intr_wrapper(caddr_t arg)
1017 {
1018 	uint_t intr_return;
1019 	uint_t tmpreg;
1020 	struct fhc_wrapper_arg *intr_info = (struct fhc_wrapper_arg *)arg;
1021 	uint_t (*funcp)(caddr_t, caddr_t) = intr_info->funcp;
1022 	caddr_t iarg1 = intr_info->arg1;
1023 	caddr_t iarg2 = intr_info->arg2;
1024 	dev_info_t *dip = intr_info->child;
1025 
1026 	tmpreg = ISM_IDLE;
1027 
1028 	DTRACE_PROBE4(interrupt__start, dev_info_t, dip,
1029 	    void *, funcp, caddr_t, iarg1, caddr_t, iarg2);
1030 
1031 	intr_return = (*funcp)(iarg1, iarg2);
1032 
1033 	DTRACE_PROBE4(interrupt__complete, dev_info_t, dip,
1034 	    void *, funcp, caddr_t, iarg1, int, intr_return);
1035 
1036 	/* Idle the state machine. */
1037 	*(intr_info->clear_reg) = tmpreg;
1038 
1039 	/* Flush the hardware store buffers. */
1040 	tmpreg = *(intr_info->clear_reg);
1041 #ifdef lint
1042 	tmpreg = tmpreg;
1043 #endif	/* lint */
1044 
1045 	return (intr_return);
1046 }
1047 
1048 /*
1049  * fhc_zs_intr_wrapper
1050  *
1051  * This function handles intrerrupts where more than one device may interupt
1052  * the fhc with the same mondo.
1053  */
1054 
1055 #define	MAX_INTR_CNT 10
1056 
1057 static uint_t
1058 fhc_zs_intr_wrapper(caddr_t arg)
1059 {
1060 	struct fhc_soft_state *softsp = (struct fhc_soft_state *)arg;
1061 	uint_t (*funcp0)(caddr_t, caddr_t);
1062 	uint_t (*funcp1)(caddr_t, caddr_t);
1063 	caddr_t funcp0_arg1, funcp0_arg2, funcp1_arg1, funcp1_arg2;
1064 	uint_t tmp_reg;
1065 	uint_t result = DDI_INTR_UNCLAIMED;
1066 	volatile uint_t *clear_reg;
1067 	uchar_t *spurious_cntr = &softsp->spurious_zs_cntr;
1068 
1069 	funcp0 = softsp->poll_list[0].funcp;
1070 	funcp1 = softsp->poll_list[1].funcp;
1071 	funcp0_arg1 = softsp->poll_list[0].arg1;
1072 	funcp0_arg2 = softsp->poll_list[0].arg2;
1073 	funcp1_arg1 = softsp->poll_list[1].arg1;
1074 	funcp1_arg2 = softsp->poll_list[1].arg2;
1075 	clear_reg = softsp->intr_regs[FHC_UART_INO].clear_reg;
1076 
1077 	if (funcp0 != NULL) {
1078 		if ((funcp0)(funcp0_arg1, funcp0_arg2) == DDI_INTR_CLAIMED) {
1079 			result = DDI_INTR_CLAIMED;
1080 		}
1081 	}
1082 
1083 	if (funcp1 != NULL) {
1084 		if ((funcp1)(funcp1_arg1, funcp1_arg2) == DDI_INTR_CLAIMED) {
1085 			result = DDI_INTR_CLAIMED;
1086 		}
1087 	}
1088 
1089 	if (result == DDI_INTR_UNCLAIMED) {
1090 		(*spurious_cntr)++;
1091 
1092 		if (*spurious_cntr < MAX_INTR_CNT) {
1093 			result = DDI_INTR_CLAIMED;
1094 		} else {
1095 			*spurious_cntr = (uchar_t)0;
1096 		}
1097 	} else {
1098 		*spurious_cntr = (uchar_t)0;
1099 	}
1100 
1101 	/* Idle the state machine. */
1102 	*(clear_reg) = ISM_IDLE;
1103 
1104 	/* flush the store buffers. */
1105 	tmp_reg = *(clear_reg);
1106 #ifdef lint
1107 	tmp_reg = tmp_reg;
1108 #endif
1109 
1110 	return (result);
1111 }
1112 
1113 
1114 /*
1115  * add_intrspec - Add an interrupt specification.
1116  */
1117 static int
1118 fhc_add_intr_impl(dev_info_t *dip, dev_info_t *rdip,
1119     ddi_intr_handle_impl_t *hdlp)
1120 {
1121 	int ino;
1122 	struct fhc_wrapper_arg *fhc_arg;
1123 	struct fhc_soft_state *softsp = (struct fhc_soft_state *)
1124 	    ddi_get_soft_state(fhcp, ddi_get_instance(dip));
1125 	volatile uint_t *mondo_vec_reg;
1126 	uint_t tmp_mondo_vec;
1127 	uint_t tmpreg; /* HW flush reg */
1128 	uint_t cpu_id;
1129 	int ret = DDI_SUCCESS;
1130 
1131 	/* Xlate the interrupt */
1132 	fhc_xlate_intrs(hdlp,
1133 	    (softsp->list->sc.board << BD_IVINTR_SHFT));
1134 
1135 	/* get the mondo number */
1136 	ino = FHC_INO(hdlp->ih_vector);
1137 	mondo_vec_reg = softsp->intr_regs[ino].mapping_reg;
1138 
1139 	ASSERT(ino < FHC_MAX_INO);
1140 
1141 	/* We don't use the two spare interrupts. */
1142 	if (ino >= FHC_MAX_INO) {
1143 		cmn_err(CE_WARN, "fhc%d: Spare interrupt %d not usable",
1144 		    ddi_get_instance(dip), ino);
1145 		return (DDI_FAILURE);
1146 	}
1147 
1148 	/* TOD and Fan Fail interrupts are not usable */
1149 	if (ino == FHC_TOD_INO) {
1150 		cmn_err(CE_WARN, "fhc%d: TOD interrupt not usable",
1151 		    ddi_get_instance(dip));
1152 		return (DDI_FAILURE);
1153 	}
1154 	if (ino == FHC_FANFAIL_INO) {
1155 		cmn_err(CE_WARN, "fhc%d: Fan fail interrupt not usable",
1156 		    ddi_get_instance(dip));
1157 		return (DDI_FAILURE);
1158 	}
1159 
1160 	/*
1161 	 * If the interrupt is for the zs chips, use the vector
1162 	 * polling lists. Otherwise use a straight handler.
1163 	 */
1164 	if (ino == FHC_UART_INO) {
1165 		int32_t zs_inst;
1166 		/* First lock the mutex for this poll_list */
1167 		mutex_enter(&softsp->poll_list_lock);
1168 
1169 		/*
1170 		 * Add this interrupt to the polling list.
1171 		 */
1172 
1173 		/* figure out where to add this item in the list */
1174 		for (zs_inst = 0; zs_inst < MAX_ZS_CNT; zs_inst++) {
1175 			if (softsp->poll_list[zs_inst].funcp == NULL) {
1176 				softsp->poll_list[zs_inst].arg1 =
1177 				    hdlp->ih_cb_arg1;
1178 				softsp->poll_list[zs_inst].arg2 =
1179 				    hdlp->ih_cb_arg2;
1180 				softsp->poll_list[zs_inst].funcp =
1181 				    (ddi_intr_handler_t *)
1182 				    hdlp->ih_cb_func;
1183 				softsp->poll_list[zs_inst].inum =
1184 				    hdlp->ih_inum;
1185 				softsp->poll_list[zs_inst].child = rdip;
1186 
1187 				break;
1188 			}
1189 		}
1190 
1191 		if (zs_inst >= MAX_ZS_CNT) {
1192 			cmn_err(CE_WARN,
1193 			    "fhc%d: poll list overflow",
1194 			    ddi_get_instance(dip));
1195 			mutex_exit(&softsp->poll_list_lock);
1196 			ret = DDI_FAILURE;
1197 			goto done;
1198 		}
1199 
1200 		/*
1201 		 * If polling list is empty, then install handler
1202 		 * and enable interrupts for this ino.
1203 		 */
1204 		if (zs_inst == 0) {
1205 			DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp,
1206 			    (ddi_intr_handler_t *)fhc_zs_intr_wrapper,
1207 			    (caddr_t)softsp, NULL);
1208 
1209 			ret = i_ddi_add_ivintr(hdlp);
1210 
1211 			DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp,
1212 			    softsp->poll_list[zs_inst].funcp,
1213 			    softsp->poll_list[zs_inst].arg1,
1214 			    softsp->poll_list[zs_inst].arg2);
1215 
1216 			if (ret != DDI_SUCCESS)
1217 				goto done;
1218 		}
1219 
1220 		/*
1221 		 * If both zs handlers are active, then this is the
1222 		 * second add_intrspec called, so do not enable
1223 		 * the IMR_VALID bit, it is already on.
1224 		 */
1225 		if (zs_inst > 0) {
1226 				/* now release the mutex and return */
1227 			mutex_exit(&softsp->poll_list_lock);
1228 
1229 			goto done;
1230 		} else {
1231 			/* just release the mutex */
1232 			mutex_exit(&softsp->poll_list_lock);
1233 		}
1234 	} else {	/* normal interrupt installation */
1235 		int32_t i;
1236 
1237 		/* Allocate a nexus interrupt data structure */
1238 		fhc_arg = kmem_alloc(sizeof (struct fhc_wrapper_arg), KM_SLEEP);
1239 		fhc_arg->child = rdip;
1240 		fhc_arg->mapping_reg = mondo_vec_reg;
1241 		fhc_arg->clear_reg = (softsp->intr_regs[ino].clear_reg);
1242 		fhc_arg->softsp = softsp;
1243 		fhc_arg->funcp =
1244 		    (ddi_intr_handler_t *)hdlp->ih_cb_func;
1245 		fhc_arg->arg1 = hdlp->ih_cb_arg1;
1246 		fhc_arg->arg2 = hdlp->ih_cb_arg2;
1247 		fhc_arg->inum = hdlp->ih_inum;
1248 
1249 		for (i = 0; i < FHC_MAX_INO; i++) {
1250 			if (softsp->intr_list[i] == 0) {
1251 				softsp->intr_list[i] = fhc_arg;
1252 				break;
1253 			}
1254 		}
1255 
1256 		/*
1257 		 * Save the fhc_arg in the ispec so we can use this info
1258 		 * later to uninstall this interrupt spec.
1259 		 */
1260 		DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp,
1261 		    (ddi_intr_handler_t *)fhc_intr_wrapper,
1262 		    (caddr_t)fhc_arg, NULL);
1263 
1264 		ret = i_ddi_add_ivintr(hdlp);
1265 
1266 		DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, fhc_arg->funcp,
1267 		    fhc_arg->arg1, fhc_arg->arg2);
1268 
1269 		if (ret != DDI_SUCCESS)
1270 			goto done;
1271 	}
1272 
1273 	/*
1274 	 * Clear out a stale 'pending' or 'transmit' state in
1275 	 * this device's ISM that might have been left from a
1276 	 * previous session.
1277 	 *
1278 	 * Since all FHC interrupts are level interrupts, any
1279 	 * real interrupting condition will immediately transition
1280 	 * the ISM back to pending.
1281 	 */
1282 	*(softsp->intr_regs[ino].clear_reg) = ISM_IDLE;
1283 
1284 	/*
1285 	 * Program the mondo vector accordingly.  This MUST be the
1286 	 * last thing we do.  Once we program the ino, the device
1287 	 * may begin to interrupt.
1288 	 */
1289 	cpu_id = intr_dist_cpuid();
1290 
1291 	tmp_mondo_vec = cpu_id << INR_PID_SHIFT;
1292 
1293 	/* don't do this for fan because fan has a special control */
1294 	if (ino == FHC_FANFAIL_INO)
1295 		panic("fhc%d: enabling fanfail interrupt",
1296 		    ddi_get_instance(dip));
1297 	else
1298 		tmp_mondo_vec |= IMR_VALID;
1299 
1300 	DPRINTF(FHC_INTERRUPT_DEBUG,
1301 	    ("Mondo 0x%x mapping reg: 0x%p", hdlp->ih_vector, mondo_vec_reg));
1302 
1303 	/* Store it in the hardware reg. */
1304 	*mondo_vec_reg = tmp_mondo_vec;
1305 
1306 	/* Read a FHC register to flush store buffers */
1307 	tmpreg = *(softsp->id);
1308 #ifdef lint
1309 	tmpreg = tmpreg;
1310 #endif
1311 
1312 done:
1313 	return (ret);
1314 }
1315 
1316 /*
1317  * remove_intrspec - Remove an interrupt specification.
1318  */
1319 static void
1320 fhc_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip,
1321 	ddi_intr_handle_impl_t *hdlp)
1322 {
1323 	volatile uint_t *mondo_vec_reg;
1324 	volatile uint_t tmpreg;
1325 	int i;
1326 	struct fhc_soft_state *softsp = (struct fhc_soft_state *)
1327 		ddi_get_soft_state(fhcp, ddi_get_instance(dip));
1328 	int ino;
1329 
1330 	/* Xlate the interrupt */
1331 	fhc_xlate_intrs(hdlp,
1332 	    (softsp->list->sc.board << BD_IVINTR_SHFT));
1333 
1334 	/* get the mondo number */
1335 	ino = FHC_INO(hdlp->ih_vector);
1336 
1337 	if (ino == FHC_UART_INO) {
1338 		int intr_found = 0;
1339 
1340 		/* Lock the poll_list first */
1341 		mutex_enter(&softsp->poll_list_lock);
1342 
1343 		/*
1344 		 * Find which entry in the poll list belongs to this
1345 		 * intrspec.
1346 		 */
1347 		for (i = 0; i < MAX_ZS_CNT; i++) {
1348 			if (softsp->poll_list[i].child == rdip &&
1349 			    softsp->poll_list[i].inum == hdlp->ih_inum) {
1350 				softsp->poll_list[i].funcp = NULL;
1351 				intr_found++;
1352 			}
1353 		}
1354 
1355 		/* If we did not find an entry, then we have a problem */
1356 		if (!intr_found) {
1357 			cmn_err(CE_WARN, "fhc%d: Intrspec not found in"
1358 				" poll list", ddi_get_instance(dip));
1359 			mutex_exit(&softsp->poll_list_lock);
1360 			goto done;
1361 		}
1362 
1363 		/*
1364 		 * If we have removed all active entries for the poll
1365 		 * list, then we have to disable interupts at this point.
1366 		 */
1367 		if ((softsp->poll_list[0].funcp == NULL) &&
1368 		    (softsp->poll_list[1].funcp == NULL)) {
1369 			mondo_vec_reg =
1370 			    softsp->intr_regs[FHC_UART_INO].mapping_reg;
1371 			*mondo_vec_reg &= ~IMR_VALID;
1372 
1373 			/* flush the hardware buffers */
1374 			tmpreg = *(softsp->ctrl);
1375 
1376 			/* Eliminate the particular handler from the system. */
1377 			i_ddi_rem_ivintr(hdlp);
1378 		}
1379 
1380 		mutex_exit(&softsp->poll_list_lock);
1381 	} else {
1382 		int32_t i;
1383 
1384 
1385 		for (i = 0; i < FHC_MAX_INO; i++)
1386 			if (softsp->intr_list[i]->child == rdip &&
1387 			    softsp->intr_list[i]->inum == hdlp->ih_inum)
1388 				break;
1389 
1390 		if (i >= FHC_MAX_INO)
1391 			goto done;
1392 
1393 		mondo_vec_reg = softsp->intr_list[i]->mapping_reg;
1394 
1395 		/* Turn off the valid bit in the mapping register. */
1396 		/* XXX what about FHC_FANFAIL owned imr? */
1397 		*mondo_vec_reg &= ~IMR_VALID;
1398 
1399 		/* flush the hardware store buffers */
1400 		tmpreg = *(softsp->id);
1401 #ifdef lint
1402 		tmpreg = tmpreg;
1403 #endif
1404 
1405 		/* Eliminate the particular handler from the system. */
1406 		i_ddi_rem_ivintr(hdlp);
1407 
1408 		kmem_free(softsp->intr_list[i],
1409 		    sizeof (struct fhc_wrapper_arg));
1410 		softsp->intr_list[i] = 0;
1411 	}
1412 
1413 done:
1414 	;
1415 }
1416 
1417 /* new intr_ops structure */
1418 static int
1419 fhc_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
1420     ddi_intr_handle_impl_t *hdlp, void *result)
1421 {
1422 	int	ret = DDI_SUCCESS;
1423 
1424 	switch (intr_op) {
1425 	case DDI_INTROP_GETCAP:
1426 		*(int *)result = DDI_INTR_FLAG_LEVEL;
1427 		break;
1428 	case DDI_INTROP_ALLOC:
1429 		*(int *)result = hdlp->ih_scratch1;
1430 		break;
1431 	case DDI_INTROP_FREE:
1432 		break;
1433 	case DDI_INTROP_GETPRI:
1434 		if (hdlp->ih_pri == 0) {
1435 			struct fhc_soft_state *softsp =
1436 			    (struct fhc_soft_state *)ddi_get_soft_state(fhcp,
1437 			    ddi_get_instance(dip));
1438 
1439 			/* Xlate the interrupt */
1440 			fhc_xlate_intrs(hdlp,
1441 			    (softsp->list->sc.board << BD_IVINTR_SHFT));
1442 		}
1443 
1444 		*(int *)result = hdlp->ih_pri;
1445 		break;
1446 	case DDI_INTROP_SETPRI:
1447 		break;
1448 	case DDI_INTROP_ADDISR:
1449 		ret = fhc_add_intr_impl(dip, rdip, hdlp);
1450 		break;
1451 	case DDI_INTROP_REMISR:
1452 		fhc_remove_intr_impl(dip, rdip, hdlp);
1453 		break;
1454 	case DDI_INTROP_ENABLE:
1455 	case DDI_INTROP_DISABLE:
1456 		break;
1457 	case DDI_INTROP_NINTRS:
1458 	case DDI_INTROP_NAVAIL:
1459 		*(int *)result = i_ddi_get_intx_nintrs(rdip);
1460 		break;
1461 	case DDI_INTROP_SETCAP:
1462 	case DDI_INTROP_SETMASK:
1463 	case DDI_INTROP_CLRMASK:
1464 	case DDI_INTROP_GETPENDING:
1465 		ret = DDI_ENOTSUP;
1466 		break;
1467 	case DDI_INTROP_SUPPORTED_TYPES:
1468 		/* only support fixed interrupts */
1469 		*(int *)result = i_ddi_get_intx_nintrs(rdip) ?
1470 		    DDI_INTR_TYPE_FIXED : 0;
1471 		break;
1472 	default:
1473 		ret = i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result);
1474 		break;
1475 	}
1476 
1477 	return (ret);
1478 }
1479 
1480 /*
1481  * FHC Control Ops routine
1482  *
1483  * Requests handled here:
1484  *	DDI_CTLOPS_INITCHILD	see impl_ddi_sunbus_initchild() for details
1485  *	DDI_CTLOPS_UNINITCHILD	see fhc_uninit_child() for details
1486  *	DDI_CTLOPS_REPORTDEV	TODO - need to implement this.
1487  */
1488 static int
1489 fhc_ctlops(dev_info_t *dip, dev_info_t *rdip,
1490 	ddi_ctl_enum_t op, void *arg, void *result)
1491 {
1492 
1493 	switch (op) {
1494 	case DDI_CTLOPS_INITCHILD:
1495 		DPRINTF(FHC_CTLOPS_DEBUG, ("DDI_CTLOPS_INITCHILD\n"));
1496 		return (impl_ddi_sunbus_initchild((dev_info_t *)arg));
1497 
1498 	case DDI_CTLOPS_UNINITCHILD:
1499 		impl_ddi_sunbus_removechild((dev_info_t *)arg);
1500 		return (DDI_SUCCESS);
1501 
1502 	case DDI_CTLOPS_REPORTDEV:
1503 		/*
1504 		 * TODO - Figure out what makes sense to report here.
1505 		 */
1506 		return (DDI_SUCCESS);
1507 
1508 	case DDI_CTLOPS_POKE:
1509 	case DDI_CTLOPS_PEEK:
1510 		return (fhc_ctlops_peekpoke(op, (peekpoke_ctlops_t *)arg,
1511 		    result));
1512 
1513 	default:
1514 		return (ddi_ctlops(dip, rdip, op, arg, result));
1515 	}
1516 }
1517 
1518 
1519 /*
1520  * We're prepared to claim that the interrupt string is in
1521  * the form of a list of <FHCintr> specifications, or we're dealing
1522  * with on-board devices and we have an interrupt_number property which
1523  * gives us our mondo number.
1524  * Translate the mondos into fhcintrspecs.
1525  */
1526 /* ARGSUSED */
1527 static void
1528 fhc_xlate_intrs(ddi_intr_handle_impl_t *hdlp, uint32_t ign)
1529 
1530 {
1531 	uint32_t mondo;
1532 
1533 	mondo = hdlp->ih_vector;
1534 
1535 	hdlp->ih_vector = (mondo | ign);
1536 	if (hdlp->ih_pri == 0)
1537 		hdlp->ih_pri = fhc_int_priorities[FHC_INO(mondo)];
1538 }
1539 
1540 static int
1541 fhc_ctlops_peekpoke(ddi_ctl_enum_t cmd, peekpoke_ctlops_t *in_args,
1542     void *result)
1543 {
1544 	int err = DDI_SUCCESS;
1545 	on_trap_data_t otd;
1546 
1547 	/* No safe access except for peek/poke is supported. */
1548 	if (in_args->handle != NULL)
1549 		return (DDI_FAILURE);
1550 
1551 	/* Set up protected environment. */
1552 	if (!on_trap(&otd, OT_DATA_ACCESS)) {
1553 		uintptr_t tramp = otd.ot_trampoline;
1554 
1555 		if (cmd == DDI_CTLOPS_POKE) {
1556 			otd.ot_trampoline = (uintptr_t)&poke_fault;
1557 			err = do_poke(in_args->size, (void *)in_args->dev_addr,
1558 			    (void *)in_args->host_addr);
1559 		} else {
1560 			otd.ot_trampoline = (uintptr_t)&peek_fault;
1561 			err = do_peek(in_args->size, (void *)in_args->dev_addr,
1562 			    (void *)in_args->host_addr);
1563 			result = (void *)in_args->host_addr;
1564 		}
1565 		otd.ot_trampoline = tramp;
1566 	} else
1567 		err = DDI_FAILURE;
1568 
1569 	/* Take down protected environment. */
1570 	no_trap();
1571 
1572 	return (err);
1573 }
1574 
1575 /*
1576  * This function initializes the temperature arrays for use. All
1577  * temperatures are set in to invalid value to start.
1578  */
1579 void
1580 init_temp_arrays(struct temp_stats *envstat)
1581 {
1582 	int i;
1583 
1584 	envstat->index = 0;
1585 
1586 	for (i = 0; i < L1_SZ; i++) {
1587 		envstat->l1[i] = NA_TEMP;
1588 	}
1589 
1590 	for (i = 0; i < L2_SZ; i++) {
1591 		envstat->l2[i] = NA_TEMP;
1592 	}
1593 
1594 	for (i = 0; i < L3_SZ; i++) {
1595 		envstat->l3[i] = NA_TEMP;
1596 	}
1597 
1598 	for (i = 0; i < L4_SZ; i++) {
1599 		envstat->l4[i] = NA_TEMP;
1600 	}
1601 
1602 	for (i = 0; i < L5_SZ; i++) {
1603 		envstat->l5[i] = NA_TEMP;
1604 	}
1605 
1606 	envstat->max = NA_TEMP;
1607 	envstat->min = NA_TEMP;
1608 	envstat->trend = TREND_UNKNOWN;
1609 	envstat->version = TEMP_KSTAT_VERSION;
1610 	envstat->override = NA_TEMP;
1611 }
1612 
1613 /* Inhibit warning messages below this temperature, eg for CPU poweron. */
1614 static uint_t fhc_cpu_warning_temp_threshold = FHC_CPU_WARNING_TEMP_THRESHOLD;
1615 
1616 /*
1617  * This function manages the temperature history in the temperature
1618  * statistics buffer passed in. It calls the temperature calibration
1619  * routines and maintains the time averaged temperature data.
1620  */
1621 void
1622 update_temp(dev_info_t *pdip, struct temp_stats *envstat, uchar_t value)
1623 {
1624 	uint_t index;		    /* The absolute temperature counter */
1625 	uint_t tmp_index;	    /* temp index into upper level array */
1626 	int count;		    /* Count of non-zero values in array */
1627 	int total;		    /* sum total of non-zero values in array */
1628 	short real_temp;	    /* calibrated temperature */
1629 	int i;
1630 	struct fhc_soft_state *softsp;
1631 	char buffer[256];	    /* buffer for warning of overtemp */
1632 	enum temp_state temp_state; /* Temperature state */
1633 
1634 	/*
1635 	 * NOTE: This global counter is not protected since we're called
1636 	 * serially for each board.
1637 	 */
1638 	static int shutdown_msg = 0; /* Flag if shutdown warning issued */
1639 
1640 	/* determine soft state pointer of parent */
1641 	softsp = ddi_get_soft_state(fhcp, ddi_get_instance(pdip));
1642 
1643 	envstat->index++;
1644 	index = envstat->index;
1645 
1646 	/*
1647 	 * You need to update the level 5 intervals first, since
1648 	 * they are based on the data from the level 4 intervals,
1649 	 * and so on, down to the level 1 intervals.
1650 	 */
1651 
1652 	/* update the level 5 intervals if it is time */
1653 	if (((tmp_index = L5_INDEX(index)) > 0) && (L5_REM(index) == 0)) {
1654 		/* Generate the index within the level 5 array */
1655 		tmp_index -= 1;		/* decrement by 1 for indexing */
1656 		tmp_index = tmp_index % L5_SZ;
1657 
1658 		/* take an average of the level 4 array */
1659 		for (i = 0, count = 0, total = 0; i < L4_SZ; i++) {
1660 			/* Do not include zero values in average */
1661 			if (envstat->l4[i] != NA_TEMP) {
1662 				total += (int)envstat->l4[i];
1663 				count++;
1664 			}
1665 		}
1666 
1667 		/*
1668 		 * If there were any level 4 data points to average,
1669 		 * do so.
1670 		 */
1671 		if (count != 0) {
1672 			envstat->l5[tmp_index] = total/count;
1673 		} else {
1674 			envstat->l5[tmp_index] = NA_TEMP;
1675 		}
1676 	}
1677 
1678 	/* update the level 4 intervals if it is time */
1679 	if (((tmp_index = L4_INDEX(index)) > 0) && (L4_REM(index) == 0)) {
1680 		/* Generate the index within the level 4 array */
1681 		tmp_index -= 1;		/* decrement by 1 for indexing */
1682 		tmp_index = tmp_index % L4_SZ;
1683 
1684 		/* take an average of the level 3 array */
1685 		for (i = 0, count = 0, total = 0; i < L3_SZ; i++) {
1686 			/* Do not include zero values in average */
1687 			if (envstat->l3[i] != NA_TEMP) {
1688 				total += (int)envstat->l3[i];
1689 				count++;
1690 			}
1691 		}
1692 
1693 		/*
1694 		 * If there were any level 3 data points to average,
1695 		 * do so.
1696 		 */
1697 		if (count != 0) {
1698 			envstat->l4[tmp_index] = total/count;
1699 		} else {
1700 			envstat->l4[tmp_index] = NA_TEMP;
1701 		}
1702 	}
1703 
1704 	/* update the level 3 intervals if it is time */
1705 	if (((tmp_index = L3_INDEX(index)) > 0) && (L3_REM(index) == 0)) {
1706 		/* Generate the index within the level 3 array */
1707 		tmp_index -= 1;		/* decrement by 1 for indexing */
1708 		tmp_index = tmp_index % L3_SZ;
1709 
1710 		/* take an average of the level 2 array */
1711 		for (i = 0, count = 0, total = 0; i < L2_SZ; i++) {
1712 			/* Do not include zero values in average */
1713 			if (envstat->l2[i] != NA_TEMP) {
1714 				total += (int)envstat->l2[i];
1715 				count++;
1716 			}
1717 		}
1718 
1719 		/*
1720 		 * If there were any level 2 data points to average,
1721 		 * do so.
1722 		 */
1723 		if (count != 0) {
1724 			envstat->l3[tmp_index] = total/count;
1725 		} else {
1726 			envstat->l3[tmp_index] = NA_TEMP;
1727 		}
1728 	}
1729 
1730 	/* update the level 2 intervals if it is time */
1731 	if (((tmp_index = L2_INDEX(index)) > 0) && (L2_REM(index) == 0)) {
1732 		/* Generate the index within the level 2 array */
1733 		tmp_index -= 1;		/* decrement by 1 for indexing */
1734 		tmp_index = tmp_index % L2_SZ;
1735 
1736 		/* take an average of the level 1 array */
1737 		for (i = 0, count = 0, total = 0; i < L1_SZ; i++) {
1738 			/* Do not include zero values in average */
1739 			if (envstat->l1[i] != NA_TEMP) {
1740 				total += (int)envstat->l1[i];
1741 				count++;
1742 			}
1743 		}
1744 
1745 		/*
1746 		 * If there were any level 1 data points to average,
1747 		 * do so.
1748 		 */
1749 		if (count != 0) {
1750 			envstat->l2[tmp_index] = total/count;
1751 		} else {
1752 			envstat->l2[tmp_index] = NA_TEMP;
1753 		}
1754 	}
1755 
1756 	/* determine the current temperature in degrees Celcius */
1757 	if (envstat->override != NA_TEMP) {
1758 		/* use override temperature for this board */
1759 		real_temp = envstat->override;
1760 	} else {
1761 		/* Run the calibration function using this board type */
1762 		real_temp = calibrate_temp(softsp->list->sc.type, value,
1763 			softsp->list->sc.ac_compid);
1764 	}
1765 
1766 	envstat->l1[index % L1_SZ] = real_temp;
1767 
1768 	/* check if the temperature state for this device needs to change */
1769 	temp_state = get_temp_state(softsp->list->sc.type, real_temp,
1770 					softsp->list->sc.board);
1771 
1772 	/* has the state changed? Then get the board string ready */
1773 	if (temp_state != envstat->state) {
1774 		int board = softsp->list->sc.board;
1775 		enum board_type type = softsp->list->sc.type;
1776 
1777 		build_bd_display_str(buffer, type, board);
1778 
1779 		if (temp_state > envstat->state) {
1780 			if (envstat->state == TEMP_OK) {
1781 				if (type == CLOCK_BOARD) {
1782 					reg_fault(0, FT_OVERTEMP, FT_SYSTEM);
1783 				} else {
1784 					reg_fault(board, FT_OVERTEMP,
1785 						FT_BOARD);
1786 				}
1787 			}
1788 
1789 			/* heating up, change state now */
1790 			envstat->temp_cnt = 0;
1791 			envstat->state = temp_state;
1792 
1793 			if (temp_state == TEMP_WARN) {
1794 				/* now warn the user of the problem */
1795 				cmn_err(CE_WARN,
1796 					"%s is warm (temperature: %dC). "
1797 					"Please check system cooling", buffer,
1798 					real_temp);
1799 				fhc_bd_update(board, SYSC_EVT_BD_OVERTEMP);
1800 				if (temperature_chamber == -1)
1801 					temperature_chamber =
1802 					    check_for_chamber();
1803 			} else if (temp_state == TEMP_DANGER) {
1804 				cmn_err(CE_WARN,
1805 					"%s is very hot (temperature: %dC)",
1806 					buffer, real_temp);
1807 
1808 				envstat->shutdown_cnt = 1;
1809 				if (temperature_chamber == -1)
1810 					temperature_chamber =
1811 						check_for_chamber();
1812 				if ((temperature_chamber == 0) &&
1813 				    enable_overtemp_powerdown) {
1814 					/*
1815 					 * NOTE: The "%d seconds" is not
1816 					 * necessarily accurate in the case
1817 					 * where we have multiple boards
1818 					 * overheating and subsequently cooling
1819 					 * down.
1820 					 */
1821 					if (shutdown_msg == 0) {
1822 						cmn_err(CE_WARN, "System "
1823 							"shutdown scheduled "
1824 							"in %d seconds due to "
1825 							"over-temperature "
1826 							"condition on %s",
1827 							SHUTDOWN_TIMEOUT_SEC,
1828 							buffer);
1829 					}
1830 					shutdown_msg++;
1831 				}
1832 			}
1833 
1834 			/*
1835 			 * If this is a cpu board, power them off.
1836 			 */
1837 			if (temperature_chamber == 0) {
1838 				mutex_enter(&cpu_lock);
1839 				(void) fhc_board_poweroffcpus(board, NULL,
1840 				    CPU_FORCED);
1841 				mutex_exit(&cpu_lock);
1842 			}
1843 		} else if (temp_state < envstat->state) {
1844 			/*
1845 			 * Avert the sigpower that would
1846 			 * otherwise be sent to init.
1847 			 */
1848 			envstat->shutdown_cnt = 0;
1849 
1850 			/* cooling down, use state counter */
1851 			if (envstat->temp_cnt == 0) {
1852 				envstat->temp_cnt = TEMP_STATE_COUNT;
1853 			} else if (--envstat->temp_cnt == 0) {
1854 				if (temp_state == TEMP_WARN) {
1855 					cmn_err(CE_NOTE,
1856 						"%s is cooling "
1857 						"(temperature: %dC)", buffer,
1858 						real_temp);
1859 
1860 				} else if (temp_state == TEMP_OK) {
1861 					cmn_err(CE_NOTE,
1862 						"%s has cooled down "
1863 						"(temperature: %dC), system OK",
1864 						buffer, real_temp);
1865 
1866 					if (type == CLOCK_BOARD) {
1867 						clear_fault(0, FT_OVERTEMP,
1868 							FT_SYSTEM);
1869 					} else {
1870 						clear_fault(board, FT_OVERTEMP,
1871 							FT_BOARD);
1872 					}
1873 				}
1874 
1875 				/*
1876 				 * If we just came out of TEMP_DANGER, and
1877 				 * a warning was issued about shutting down,
1878 				 * let the user know it's been cancelled
1879 				 */
1880 				if (envstat->state == TEMP_DANGER &&
1881 				    (temperature_chamber == 0) &&
1882 				    enable_overtemp_powerdown &&
1883 				    (powerdown_started == 0) &&
1884 				    (--shutdown_msg == 0)) {
1885 					cmn_err(CE_NOTE, "System "
1886 						"shutdown due to over-"
1887 						"temperature "
1888 						"condition cancelled");
1889 				}
1890 				envstat->state = temp_state;
1891 
1892 				fhc_bd_update(board, SYSC_EVT_BD_TEMP_OK);
1893 			}
1894 		}
1895 	} else {
1896 		envstat->temp_cnt = 0;
1897 
1898 		if (temp_state == TEMP_DANGER) {
1899 			if (temperature_chamber == -1) {
1900 				temperature_chamber = check_for_chamber();
1901 			}
1902 
1903 			if ((envstat->shutdown_cnt++ >= SHUTDOWN_COUNT) &&
1904 			    (temperature_chamber == 0) &&
1905 			    enable_overtemp_powerdown &&
1906 			    (powerdown_started == 0)) {
1907 				powerdown_started = 1;
1908 
1909 				/* the system is still too hot */
1910 				build_bd_display_str(buffer,
1911 					softsp->list->sc.type,
1912 					softsp->list->sc.board);
1913 
1914 				cmn_err(CE_WARN, "%s still too hot "
1915 					"(temperature: %dC)."
1916 					" Overtemp shutdown started", buffer,
1917 					real_temp);
1918 
1919 				fhc_reboot();
1920 			}
1921 		}
1922 	}
1923 
1924 	/* update the maximum and minimum temperatures if necessary */
1925 	if ((envstat->max == NA_TEMP) || (real_temp > envstat->max)) {
1926 		envstat->max = real_temp;
1927 	}
1928 
1929 	if ((envstat->min == NA_TEMP) || (real_temp < envstat->min)) {
1930 		envstat->min = real_temp;
1931 	}
1932 
1933 	/*
1934 	 * Update the temperature trend.  Currently, the temperature
1935 	 * trend algorithm is based on the level 2 stats.  So, we
1936 	 * only need to run every time the level 2 stats get updated.
1937 	 */
1938 	if (((tmp_index = L2_INDEX(index)) > 0) && (L2_REM(index) == 0))  {
1939 		enum board_type type = softsp->list->sc.type;
1940 
1941 		envstat->trend = temp_trend(envstat);
1942 
1943 		/* Issue a warning if the temperature is rising rapidly. */
1944 		/* For CPU boards, don't warn if CPUs just powered on. */
1945 		if (envstat->trend == TREND_RAPID_RISE &&
1946 		    (type != CPU_BOARD || real_temp >
1947 		    fhc_cpu_warning_temp_threshold))  {
1948 			int board = softsp->list->sc.board;
1949 
1950 			build_bd_display_str(buffer, type, board);
1951 			cmn_err(CE_WARN, "%s temperature is rising rapidly!  "
1952 				"Current temperature is %dC", buffer,
1953 				real_temp);
1954 		}
1955 	}
1956 }
1957 
1958 #define	PREV_L2_INDEX(x)    ((x) ? ((x) - 1) : (L2_SZ - 1))
1959 
1960 /*
1961  * This routine determines if the temp of the device passed in is heating
1962  * up, cooling down, or staying stable.
1963  */
1964 enum temp_trend
1965 temp_trend(struct temp_stats *tempstat)
1966 {
1967 	int		ii;
1968 	uint_t		curr_index;
1969 	int		curr_temp;
1970 	uint_t		prev_index;
1971 	int		prev_temp;
1972 	int		trail_temp;
1973 	int		delta;
1974 	int		read_cnt;
1975 	enum temp_trend	result = TREND_STABLE;
1976 
1977 	if (tempstat == NULL)
1978 		return (TREND_UNKNOWN);
1979 
1980 	curr_index = (L2_INDEX(tempstat->index) - 1) % L2_SZ;
1981 	curr_temp = tempstat->l2[curr_index];
1982 
1983 	/* Count how many temperature readings are available */
1984 	prev_index = curr_index;
1985 	for (read_cnt = 0; read_cnt < L2_SZ - 1; read_cnt++) {
1986 		if (tempstat->l2[prev_index] == NA_TEMP)
1987 			break;
1988 		prev_index = PREV_L2_INDEX(prev_index);
1989 	}
1990 
1991 	switch (read_cnt) {
1992 	case 0:
1993 	case 1:
1994 		result = TREND_UNKNOWN;
1995 		break;
1996 
1997 	default:
1998 		delta = curr_temp - tempstat->l2[PREV_L2_INDEX(curr_index)];
1999 		prev_index = curr_index;
2000 		trail_temp = prev_temp = curr_temp;
2001 		if (delta >= RAPID_RISE_THRESH) {	    /* rapid rise? */
2002 			result = TREND_RAPID_RISE;
2003 		} else if (delta > 0) {			    /* rise? */
2004 			for (ii = 1; ii < read_cnt; ii++) {
2005 				prev_index = PREV_L2_INDEX(prev_index);
2006 				prev_temp = tempstat->l2[prev_index];
2007 				if (prev_temp > trail_temp) {
2008 					break;
2009 				}
2010 				trail_temp = prev_temp;
2011 				if (prev_temp <= curr_temp - NOISE_THRESH) {
2012 					result = TREND_RISE;
2013 					break;
2014 				}
2015 			}
2016 		} else if (delta <= -RAPID_FALL_THRESH) {   /* rapid fall? */
2017 			result = TREND_RAPID_FALL;
2018 		} else if (delta < 0) {			    /* fall? */
2019 			for (ii = 1; ii < read_cnt; ii++) {
2020 				prev_index = PREV_L2_INDEX(prev_index);
2021 				prev_temp = tempstat->l2[prev_index];
2022 				if (prev_temp < trail_temp) {
2023 					break;
2024 				}
2025 				trail_temp = prev_temp;
2026 				if (prev_temp >= curr_temp + NOISE_THRESH) {
2027 					result = TREND_FALL;
2028 					break;
2029 				}
2030 			}
2031 		}
2032 	}
2033 	return (result);
2034 }
2035 
2036 /*
2037  * Reboot the system if we can, otherwise attempt a power down
2038  */
2039 void
2040 fhc_reboot(void)
2041 {
2042 	proc_t *initpp;
2043 
2044 	/* send a SIGPWR to init process */
2045 	mutex_enter(&pidlock);
2046 	initpp = prfind(P_INITPID);
2047 	mutex_exit(&pidlock);
2048 
2049 	/*
2050 	 * If we're still booting and init(1) isn't
2051 	 * set up yet, simply halt.
2052 	 */
2053 	if (initpp != NULL) {
2054 		psignal(initpp, SIGFPE);	/* init 6 */
2055 	} else {
2056 		power_down("Environmental Shutdown");
2057 		halt("Power off the System");
2058 	}
2059 }
2060 
2061 int
2062 overtemp_kstat_update(kstat_t *ksp, int rw)
2063 {
2064 	struct temp_stats *tempstat;
2065 	char *kstatp;
2066 	int i;
2067 
2068 	kstatp = (char *)ksp->ks_data;
2069 	tempstat = (struct temp_stats *)ksp->ks_private;
2070 
2071 	/*
2072 	 * Kstat reads are used to retrieve the current system temperature
2073 	 * history. Kstat writes are used to reset the max and min
2074 	 * temperatures.
2075 	 */
2076 	if (rw == KSTAT_WRITE) {
2077 		short max;	/* temporary copy of max temperature */
2078 		short min;	/* temporary copy of min temperature */
2079 
2080 		/*
2081 		 * search for and reset the max and min to the current
2082 		 * array contents. Old max and min values will get
2083 		 * averaged out as they move into the higher level arrays.
2084 		 */
2085 		max = tempstat->l1[0];
2086 		min = tempstat->l1[0];
2087 
2088 		/* Pull the max and min from Level 1 array */
2089 		for (i = 0; i < L1_SZ; i++) {
2090 			if ((tempstat->l1[i] != NA_TEMP) &&
2091 			    (tempstat->l1[i] > max)) {
2092 				max = tempstat->l1[i];
2093 			}
2094 
2095 			if ((tempstat->l1[i] != NA_TEMP) &&
2096 			    (tempstat->l1[i] < min)) {
2097 				min = tempstat->l1[i];
2098 			}
2099 		}
2100 
2101 		/* Pull the max and min from Level 2 array */
2102 		for (i = 0; i < L2_SZ; i++) {
2103 			if ((tempstat->l2[i] != NA_TEMP) &&
2104 			    (tempstat->l2[i] > max)) {
2105 				max = tempstat->l2[i];
2106 			}
2107 
2108 			if ((tempstat->l2[i] != NA_TEMP) &&
2109 			    (tempstat->l2[i] < min)) {
2110 				min = tempstat->l2[i];
2111 			}
2112 		}
2113 
2114 		/* Pull the max and min from Level 3 array */
2115 		for (i = 0; i < L3_SZ; i++) {
2116 			if ((tempstat->l3[i] != NA_TEMP) &&
2117 			    (tempstat->l3[i] > max)) {
2118 				max = tempstat->l3[i];
2119 			}
2120 
2121 			if ((tempstat->l3[i] != NA_TEMP) &&
2122 			    (tempstat->l3[i] < min)) {
2123 				min = tempstat->l3[i];
2124 			}
2125 		}
2126 
2127 		/* Pull the max and min from Level 4 array */
2128 		for (i = 0; i < L4_SZ; i++) {
2129 			if ((tempstat->l4[i] != NA_TEMP) &&
2130 			    (tempstat->l4[i] > max)) {
2131 				max = tempstat->l4[i];
2132 			}
2133 
2134 			if ((tempstat->l4[i] != NA_TEMP) &&
2135 			    (tempstat->l4[i] < min)) {
2136 				min = tempstat->l4[i];
2137 			}
2138 		}
2139 
2140 		/* Pull the max and min from Level 5 array */
2141 		for (i = 0; i < L5_SZ; i++) {
2142 			if ((tempstat->l5[i] != NA_TEMP) &&
2143 			    (tempstat->l5[i] > max)) {
2144 				max = tempstat->l5[i];
2145 			}
2146 
2147 			if ((tempstat->l5[i] != NA_TEMP) &&
2148 			    (tempstat->l5[i] < min)) {
2149 				min = tempstat->l5[i];
2150 			}
2151 		}
2152 	} else {
2153 		/*
2154 		 * copy the temperature history buffer into the
2155 		 * kstat structure.
2156 		 */
2157 		bcopy(tempstat, kstatp, sizeof (struct temp_stats));
2158 	}
2159 	return (0);
2160 }
2161 
2162 int
2163 temp_override_kstat_update(kstat_t *ksp, int rw)
2164 {
2165 	short *over;
2166 	short *kstatp;
2167 
2168 	kstatp = (short *)ksp->ks_data;
2169 	over = (short *)ksp->ks_private;
2170 
2171 	/*
2172 	 * Kstat reads are used to get the temperature override setting.
2173 	 * Kstat writes are used to set the temperature override setting.
2174 	 */
2175 	if (rw == KSTAT_WRITE) {
2176 		*over = *kstatp;
2177 	} else {
2178 		*kstatp = *over;
2179 	}
2180 	return (0);
2181 }
2182 
2183 /*
2184  * This function uses the calibration tables at the beginning of this file
2185  * to lookup the actual temperature of the thermistor in degrees Celcius.
2186  * If the measurement is out of the bounds of the acceptable values, the
2187  * closest boundary value is used instead.
2188  */
2189 static short
2190 calibrate_temp(enum board_type type, uchar_t temp, uint_t ac_comp)
2191 {
2192 	short result = NA_TEMP;
2193 
2194 	if (dont_calibrate == 1) {
2195 		return ((short)temp);
2196 	}
2197 
2198 	switch (type) {
2199 	case CPU_BOARD:
2200 		/*
2201 		 * If AC chip revision is >= 4 or if it is unitialized,
2202 		 * then use the new calibration tables.
2203 		 */
2204 		if ((CHIP_REV(ac_comp) >= 4) || (CHIP_REV(ac_comp) == 0)) {
2205 			if (temp >= CPU2_MX_CNT) {
2206 				result = cpu2_table[CPU2_MX_CNT-1];
2207 			} else {
2208 				result = cpu2_table[temp];
2209 			}
2210 		} else {
2211 			if (temp >= CPU_MX_CNT) {
2212 				result = cpu_table[CPU_MX_CNT-1];
2213 			} else {
2214 				result = cpu_table[temp];
2215 			}
2216 		}
2217 		break;
2218 
2219 	case IO_2SBUS_BOARD:
2220 	case IO_SBUS_FFB_BOARD:
2221 	case IO_PCI_BOARD:
2222 	case IO_2SBUS_SOCPLUS_BOARD:
2223 	case IO_SBUS_FFB_SOCPLUS_BOARD:
2224 		if (temp < IO_MN_CNT) {
2225 			result = io_table[IO_MN_CNT];
2226 		} else if (temp >= IO_MX_CNT) {
2227 			result = io_table[IO_MX_CNT-1];
2228 		} else {
2229 			result = io_table[temp];
2230 		}
2231 		break;
2232 
2233 	case CLOCK_BOARD:
2234 		if (temp < CLK_MN_CNT) {
2235 			result = clock_table[CLK_MN_CNT];
2236 		} else if (temp >= CLK_MX_CNT) {
2237 			result = clock_table[CLK_MX_CNT-1];
2238 		} else {
2239 			result = clock_table[temp];
2240 		}
2241 		break;
2242 
2243 	default:
2244 		break;
2245 	}
2246 
2247 	return (result);
2248 }
2249 
2250 /*
2251  * Determine the temperature state of this board based on its type and
2252  * the actual temperature in degrees Celcius.
2253  */
2254 static enum temp_state
2255 get_temp_state(enum board_type type, short temp, int board)
2256 {
2257 	enum temp_state state = TEMP_OK;
2258 	short warn_limit;
2259 	short danger_limit;
2260 	struct cpu *cpa, *cpb;
2261 
2262 	switch (type) {
2263 	case CPU_BOARD:
2264 		warn_limit = cpu_warn_temp;
2265 		danger_limit = cpu_danger_temp;
2266 
2267 		/*
2268 		 * For CPU boards with frequency >= 400 MHZ,
2269 		 * temperature zones are different.
2270 		 */
2271 
2272 		mutex_enter(&cpu_lock);
2273 
2274 		if ((cpa = cpu_get(FHC_BOARD2CPU_A(board))) != NULL) {
2275 			if ((cpa->cpu_type_info.pi_clock) >= 400) {
2276 				warn_limit = cpu_warn_temp_4x;
2277 				danger_limit = cpu_danger_temp_4x;
2278 			}
2279 		}
2280 		if ((cpb = cpu_get(FHC_BOARD2CPU_B(board))) != NULL) {
2281 			if ((cpb->cpu_type_info.pi_clock) >= 400) {
2282 				warn_limit = cpu_warn_temp_4x;
2283 				danger_limit = cpu_danger_temp_4x;
2284 			}
2285 		}
2286 
2287 		mutex_exit(&cpu_lock);
2288 
2289 		break;
2290 
2291 	case IO_2SBUS_BOARD:
2292 	case IO_SBUS_FFB_BOARD:
2293 	case IO_PCI_BOARD:
2294 	case IO_2SBUS_SOCPLUS_BOARD:
2295 	case IO_SBUS_FFB_SOCPLUS_BOARD:
2296 		warn_limit = io_warn_temp;
2297 		danger_limit = io_danger_temp;
2298 		break;
2299 
2300 	case CLOCK_BOARD:
2301 		warn_limit = clk_warn_temp;
2302 		danger_limit = clk_danger_temp;
2303 		break;
2304 
2305 	case UNINIT_BOARD:
2306 	case UNKNOWN_BOARD:
2307 	case MEM_BOARD:
2308 	default:
2309 		warn_limit = dft_warn_temp;
2310 		danger_limit = dft_danger_temp;
2311 		break;
2312 	}
2313 
2314 	if (temp >= danger_limit) {
2315 		state = TEMP_DANGER;
2316 	} else if (temp >= warn_limit) {
2317 		state = TEMP_WARN;
2318 	}
2319 
2320 	return (state);
2321 }
2322 
2323 static void
2324 fhc_add_kstats(struct fhc_soft_state *softsp)
2325 {
2326 	struct kstat *fhc_ksp;
2327 	struct fhc_kstat *fhc_named_ksp;
2328 
2329 	if ((fhc_ksp = kstat_create("unix", softsp->list->sc.board,
2330 	    FHC_KSTAT_NAME, "misc", KSTAT_TYPE_NAMED,
2331 	    sizeof (struct fhc_kstat) / sizeof (kstat_named_t),
2332 	    KSTAT_FLAG_PERSISTENT)) == NULL) {
2333 		cmn_err(CE_WARN, "fhc%d kstat_create failed",
2334 			ddi_get_instance(softsp->dip));
2335 		return;
2336 	}
2337 
2338 	fhc_named_ksp = (struct fhc_kstat *)(fhc_ksp->ks_data);
2339 
2340 	/* initialize the named kstats */
2341 	kstat_named_init(&fhc_named_ksp->csr,
2342 		CSR_KSTAT_NAMED,
2343 		KSTAT_DATA_UINT32);
2344 
2345 	kstat_named_init(&fhc_named_ksp->bsr,
2346 		BSR_KSTAT_NAMED,
2347 		KSTAT_DATA_UINT32);
2348 
2349 	fhc_ksp->ks_update = fhc_kstat_update;
2350 	fhc_ksp->ks_private = (void *)softsp;
2351 	softsp->fhc_ksp = fhc_ksp;
2352 	kstat_install(fhc_ksp);
2353 }
2354 
2355 static int
2356 fhc_kstat_update(kstat_t *ksp, int rw)
2357 {
2358 	struct fhc_kstat *fhcksp;
2359 	struct fhc_soft_state *softsp;
2360 
2361 	fhcksp = (struct fhc_kstat *)ksp->ks_data;
2362 	softsp = (struct fhc_soft_state *)ksp->ks_private;
2363 
2364 	/* this is a read-only kstat. Bail out on a write */
2365 	if (rw == KSTAT_WRITE) {
2366 		return (EACCES);
2367 	} else {
2368 		/*
2369 		 * copy the current state of the hardware into the
2370 		 * kstat structure.
2371 		 */
2372 		fhcksp->csr.value.ui32 = *softsp->ctrl;
2373 		fhcksp->bsr.value.ui32 = *softsp->bsr;
2374 	}
2375 	return (0);
2376 }
2377 
2378 static int
2379 cpu_on_board(int board)
2380 {
2381 	int upa_a = board << 1;
2382 	int upa_b = (board << 1) + 1;
2383 
2384 	if ((cpunodes[upa_a].nodeid != NULL) ||
2385 	    (cpunodes[upa_b].nodeid != NULL)) {
2386 		return (1);
2387 	} else {
2388 		return (0);
2389 	}
2390 }
2391 
2392 /*
2393  * This function uses the board list and toggles the OS green board
2394  * LED. The mask input tells which bit fields are being modified,
2395  * and the value input tells the states of the bits.
2396  */
2397 void
2398 update_board_leds(fhc_bd_t *board, uint_t mask, uint_t value)
2399 {
2400 	volatile uint_t temp;
2401 
2402 	ASSERT(fhc_bdlist_locked());
2403 
2404 	/* mask off mask and value for only the LED bits */
2405 	mask &= (FHC_LED_LEFT|FHC_LED_MID|FHC_LED_RIGHT);
2406 	value &= (FHC_LED_LEFT|FHC_LED_MID|FHC_LED_RIGHT);
2407 
2408 	if (board != NULL) {
2409 		mutex_enter(&board->softsp->ctrl_lock);
2410 
2411 		/* read the current register state */
2412 		temp = *board->softsp->ctrl;
2413 
2414 		/*
2415 		 * The EPDA bits are special since the register is
2416 		 * special.  We don't want to set them, since setting
2417 		 * the bits on a shutdown cpu keeps the cpu permanently
2418 		 * powered off.  Also, the CSR_SYNC bit must always be
2419 		 * set to 0 as it is an OBP semaphore that is expected to
2420 		 * be clear for cpu restart.
2421 		 */
2422 		temp &= ~(FHC_CSR_SYNC | FHC_EPDA_OFF | FHC_EPDB_OFF);
2423 
2424 		/* mask off the bits to change */
2425 		temp &= ~mask;
2426 
2427 		/* or in the new values of the bits. */
2428 		temp |= value;
2429 
2430 		/* update the register */
2431 		*board->softsp->ctrl = temp;
2432 
2433 		/* flush the hardware registers */
2434 		temp = *board->softsp->ctrl;
2435 #ifdef lint
2436 		temp = temp;
2437 #endif
2438 
2439 		mutex_exit(&board->softsp->ctrl_lock);
2440 	}
2441 }
2442 
2443 static int
2444 check_for_chamber(void)
2445 {
2446 	int chamber = 0;
2447 	dev_info_t *options_dip;
2448 	pnode_t options_node_id;
2449 	int mfgmode_len;
2450 	int retval;
2451 	char *mfgmode;
2452 
2453 	/*
2454 	 * The operator can disable overtemp powerdown from /etc/system or
2455 	 * boot -h.
2456 	 */
2457 	if (!enable_overtemp_powerdown) {
2458 		cmn_err(CE_WARN, "Operator has disabled overtemp powerdown");
2459 		return (1);
2460 	}
2461 
2462 	/*
2463 	 * An OBP option, 'mfg-mode' is being used to inform us as to
2464 	 * whether we are in an enviromental chamber. It exists in
2465 	 * the 'options' node. This is where all OBP 'setenv' (eeprom)
2466 	 * parameters live.
2467 	 */
2468 	if ((options_dip = ddi_find_devinfo("options", -1, 0)) != NULL) {
2469 		options_node_id = (pnode_t)ddi_get_nodeid(options_dip);
2470 		mfgmode_len = prom_getproplen(options_node_id, "mfg-mode");
2471 		if (mfgmode_len == -1) {
2472 			return (chamber);
2473 		}
2474 		mfgmode = kmem_alloc(mfgmode_len+1, KM_SLEEP);
2475 
2476 		retval = prom_getprop(options_node_id, "mfg-mode", mfgmode);
2477 		if (retval != -1) {
2478 			mfgmode[retval] = 0;
2479 			if (strcmp(mfgmode, CHAMBER_VALUE) == 0) {
2480 				chamber = 1;
2481 				cmn_err(CE_WARN, "System in Temperature"
2482 					" Chamber Mode. Overtemperature"
2483 					" Shutdown disabled");
2484 			}
2485 		}
2486 		kmem_free(mfgmode, mfgmode_len+1);
2487 	}
2488 	return (chamber);
2489 }
2490 
2491 static void
2492 build_bd_display_str(char *buffer, enum board_type type, int board)
2493 {
2494 	if (buffer == NULL) {
2495 		return;
2496 	}
2497 
2498 	/* fill in board type to display */
2499 	switch (type) {
2500 	case UNINIT_BOARD:
2501 		(void) sprintf(buffer, "Uninitialized Board type board %d",
2502 									board);
2503 		break;
2504 
2505 	case UNKNOWN_BOARD:
2506 		(void) sprintf(buffer, "Unknown Board type board %d", board);
2507 		break;
2508 
2509 	case CPU_BOARD:
2510 	case MEM_BOARD:
2511 		(void) sprintf(buffer, "CPU/Memory board %d", board);
2512 		break;
2513 
2514 	case IO_2SBUS_BOARD:
2515 		(void) sprintf(buffer, "2 SBus IO board %d", board);
2516 		break;
2517 
2518 	case IO_SBUS_FFB_BOARD:
2519 		(void) sprintf(buffer, "SBus FFB IO board %d", board);
2520 		break;
2521 
2522 	case IO_PCI_BOARD:
2523 		(void) sprintf(buffer, "PCI IO board %d", board);
2524 		break;
2525 
2526 	case CLOCK_BOARD:
2527 		(void) sprintf(buffer, "Clock board");
2528 		break;
2529 
2530 	case IO_2SBUS_SOCPLUS_BOARD:
2531 		(void) sprintf(buffer, "2 SBus SOC+ IO board %d", board);
2532 		break;
2533 
2534 	case IO_SBUS_FFB_SOCPLUS_BOARD:
2535 		(void) sprintf(buffer, "SBus FFB SOC+ IO board %d", board);
2536 		break;
2537 
2538 	default:
2539 		(void) sprintf(buffer, "Unrecognized board type board %d",
2540 									board);
2541 		break;
2542 	}
2543 }
2544 
2545 void
2546 fhc_intrdist(void *arg)
2547 {
2548 	struct fhc_soft_state *softsp;
2549 	dev_info_t *dip = (dev_info_t *)arg;
2550 	volatile uint_t *mondo_vec_reg;
2551 	volatile uint_t *intr_state_reg;
2552 	uint_t mondo_vec;
2553 	uint_t tmp_reg;
2554 	uint_t cpu_id;
2555 	uint_t i;
2556 
2557 	/* extract the soft state pointer */
2558 	softsp = ddi_get_soft_state(fhcp, ddi_get_instance(dip));
2559 
2560 	/*
2561 	 * Loop through all the interrupt mapping registers and reprogram
2562 	 * the target CPU for all valid registers.
2563 	 */
2564 	for (i = 0; i < FHC_MAX_INO; i++) {
2565 		mondo_vec_reg = softsp->intr_regs[i].mapping_reg;
2566 		intr_state_reg = softsp->intr_regs[i].clear_reg;
2567 
2568 		if ((*mondo_vec_reg & IMR_VALID) == 0)
2569 			continue;
2570 
2571 		cpu_id = intr_dist_cpuid();
2572 
2573 		/* Check the current target of the mondo */
2574 		if (((*mondo_vec_reg & INR_PID_MASK) >> INR_PID_SHIFT) ==
2575 		    cpu_id) {
2576 			/* It is the same, don't reprogram */
2577 			return;
2578 		}
2579 
2580 		/* So it's OK to reprogram the CPU target */
2581 
2582 		/* turn off the valid bit */
2583 		*mondo_vec_reg &= ~IMR_VALID;
2584 
2585 		/* flush the hardware registers */
2586 		tmp_reg = *softsp->id;
2587 
2588 		/*
2589 		 * wait for the state machine to idle. Do not loop on panic, so
2590 		 * that system does not hang.
2591 		 */
2592 		while (((*intr_state_reg & INT_PENDING) == INT_PENDING) &&
2593 		    !panicstr)
2594 			;
2595 
2596 		/* re-target the mondo and turn it on */
2597 		mondo_vec = (cpu_id << INR_PID_SHIFT) | IMR_VALID;
2598 
2599 		/* write it back to the hardware. */
2600 		*mondo_vec_reg = mondo_vec;
2601 
2602 		/* flush the hardware buffers. */
2603 		tmp_reg = *(softsp->id);
2604 
2605 #ifdef	lint
2606 		tmp_reg = tmp_reg;
2607 #endif	/* lint */
2608 	}
2609 }
2610 
2611 /*
2612  * reg_fault
2613  *
2614  * This routine registers a fault in the fault list. If the fault
2615  * is unique (does not exist in fault list) then a new fault is
2616  * added to the fault list, with the appropriate structure elements
2617  * filled in.
2618  */
2619 void
2620 reg_fault(int unit, enum ft_type type, enum ft_class fclass)
2621 {
2622 	struct ft_link_list *list;	/* temporary list pointer */
2623 
2624 	if (type >= ft_max_index) {
2625 		cmn_err(CE_WARN, "Illegal Fault type %x", type);
2626 		return;
2627 	}
2628 
2629 	mutex_enter(&ftlist_mutex);
2630 
2631 	/* Search for the requested fault. If it already exists, return. */
2632 	for (list = ft_list; list != NULL; list = list->next) {
2633 		if ((list->f.unit == unit) && (list->f.type == type) &&
2634 		    (list->f.fclass == fclass)) {
2635 			mutex_exit(&ftlist_mutex);
2636 			return;
2637 		}
2638 	}
2639 
2640 	/* Allocate a new fault structure. */
2641 	list = kmem_zalloc(sizeof (struct ft_link_list), KM_SLEEP);
2642 
2643 	/* fill in the fault list elements */
2644 	list->f.unit = unit;
2645 	list->f.type = type;
2646 	list->f.fclass = fclass;
2647 	list->f.create_time = (time32_t)gethrestime_sec(); /* XX64 */
2648 	(void) strncpy(list->f.msg, ft_str_table[type], MAX_FT_DESC);
2649 
2650 	/* link it into the list. */
2651 	list->next = ft_list;
2652 	ft_list = list;
2653 
2654 	/* Update the total fault count */
2655 	ft_nfaults++;
2656 
2657 	mutex_exit(&ftlist_mutex);
2658 }
2659 
2660 /*
2661  * clear_fault
2662  *
2663  * This routine finds the fault list entry specified by the caller,
2664  * deletes it from the fault list, and frees up the memory used for
2665  * the entry. If the requested fault is not found, it exits silently.
2666  */
2667 void
2668 clear_fault(int unit, enum ft_type type, enum ft_class fclass)
2669 {
2670 	struct ft_link_list *list;		/* temporary list pointer */
2671 	struct ft_link_list **vect;
2672 
2673 	mutex_enter(&ftlist_mutex);
2674 
2675 	list = ft_list;
2676 	vect = &ft_list;
2677 
2678 	/*
2679 	 * Search for the requested fault. If it exists, delete it
2680 	 * and relink the fault list.
2681 	 */
2682 	for (; list != NULL; vect = &list->next, list = list->next) {
2683 		if ((list->f.unit == unit) && (list->f.type == type) &&
2684 		    (list->f.fclass == fclass)) {
2685 			/* remove the item from the list */
2686 			*vect = list->next;
2687 
2688 			/* free the memory allocated */
2689 			kmem_free(list, sizeof (struct ft_link_list));
2690 
2691 			/* Update the total fault count */
2692 			ft_nfaults--;
2693 			break;
2694 		}
2695 	}
2696 	mutex_exit(&ftlist_mutex);
2697 }
2698 
2699 /*
2700  * process_fault_list
2701  *
2702  * This routine walks the global fault list and updates the board list
2703  * with the current status of each Yellow LED. If any faults are found
2704  * in the system, then a non-zero value is returned. Else zero is returned.
2705  */
2706 int
2707 process_fault_list(void)
2708 {
2709 	int fault = 0;
2710 	struct ft_link_list *ftlist;	/* fault list pointer */
2711 	fhc_bd_t *bdlist;		/* board list pointer */
2712 
2713 	/*
2714 	 * Note on locking. The bdlist mutex is always acquired and
2715 	 * held around the ftlist mutex when both are needed for an
2716 	 * operation. This is to avoid deadlock.
2717 	 */
2718 
2719 	/* First lock the board list */
2720 	(void) fhc_bdlist_lock(-1);
2721 
2722 	/* Grab the fault list lock first */
2723 	mutex_enter(&ftlist_mutex);
2724 
2725 	/* clear the board list of all faults first */
2726 	for (bdlist = fhc_bd_first(); bdlist; bdlist = fhc_bd_next(bdlist))
2727 		bdlist->fault = 0;
2728 
2729 	/* walk the fault list here */
2730 	for (ftlist = ft_list; ftlist != NULL; ftlist = ftlist->next) {
2731 		fault++;
2732 
2733 		/*
2734 		 * If this is a board level fault, find the board, The
2735 		 * unit number for all board class faults must be the
2736 		 * actual board number. The caller of reg_fault must
2737 		 * ensure this for FT_BOARD class faults.
2738 		 */
2739 		if (ftlist->f.fclass == FT_BOARD) {
2740 			/* Sanity check the board first */
2741 			if (fhc_bd_valid(ftlist->f.unit)) {
2742 				bdlist = fhc_bd(ftlist->f.unit);
2743 				bdlist->fault = 1;
2744 			} else {
2745 				cmn_err(CE_WARN, "No board %d list entry found",
2746 					ftlist->f.unit);
2747 			}
2748 		}
2749 	}
2750 
2751 	/* now unlock the fault list */
2752 	mutex_exit(&ftlist_mutex);
2753 
2754 	/* unlock the board list before leaving */
2755 	fhc_bdlist_unlock();
2756 
2757 	return (fault);
2758 }
2759 
2760 /*
2761  * Add a new memloc to the database (and keep 'em sorted by PA)
2762  */
2763 void
2764 fhc_add_memloc(int board, uint64_t pa, uint_t size)
2765 {
2766 	struct fhc_memloc *p, **pp;
2767 	uint_t ipa = pa >> FHC_MEMLOC_SHIFT;
2768 
2769 	ASSERT(fhc_bdlist_locked());
2770 	ASSERT((size & (size-1)) == 0);		/* size must be power of 2 */
2771 
2772 	/* look for a comparable memloc (as long as new PA smaller) */
2773 	for (p = fhc_base_memloc, pp = &fhc_base_memloc;
2774 	    p != NULL; pp = &p->next, p = p->next) {
2775 		/* have we passed our place in the sort? */
2776 		if (ipa < p->pa) {
2777 			break;
2778 		}
2779 	}
2780 	p = kmem_alloc(sizeof (struct fhc_memloc), KM_SLEEP);
2781 	p->next = *pp;
2782 	p->board = board;
2783 	p->pa = ipa;
2784 	p->size = size;
2785 #ifdef DEBUG_MEMDEC
2786 	cmn_err(CE_NOTE, "fhc_add_memloc: adding %d 0x%x 0x%x",
2787 		p->board, p->pa, p->size);
2788 #endif /* DEBUG_MEMDEC */
2789 	*pp = p;
2790 }
2791 
2792 /*
2793  * Delete all memloc records for a board from the database
2794  */
2795 void
2796 fhc_del_memloc(int board)
2797 {
2798 	struct fhc_memloc *p, **pp;
2799 
2800 	ASSERT(fhc_bdlist_locked());
2801 
2802 	/* delete all entries that match board */
2803 	pp = &fhc_base_memloc;
2804 	while ((p = *pp) != NULL) {
2805 		if (p->board == board) {
2806 #ifdef DEBUG_MEMDEC
2807 			cmn_err(CE_NOTE, "fhc_del_memloc: removing %d "
2808 			    "0x%x 0x%x", board, p->pa, p->size);
2809 #endif /* DEBUG_MEMDEC */
2810 			*pp = p->next;
2811 			kmem_free(p, sizeof (struct fhc_memloc));
2812 		} else {
2813 			pp = &(p->next);
2814 		}
2815 	}
2816 }
2817 
2818 /*
2819  * Find a physical address range of sufficient size and return a starting PA
2820  */
2821 uint64_t
2822 fhc_find_memloc_gap(uint_t size)
2823 {
2824 	struct fhc_memloc *p;
2825 	uint_t base_pa = 0;
2826 	uint_t mask = ~(size-1);
2827 
2828 	ASSERT(fhc_bdlist_locked());
2829 	ASSERT((size & (size-1)) == 0);		/* size must be power of 2 */
2830 
2831 	/*
2832 	 * walk the list of known memlocs and measure the 'gaps'.
2833 	 * we will need a hole that can align the 'size' requested.
2834 	 * (e.g. a 256mb bank needs to be on a 256mb boundary).
2835 	 */
2836 	for (p = fhc_base_memloc; p != NULL; p = p->next) {
2837 		if (base_pa != (base_pa & mask))
2838 			base_pa = (base_pa + size) & mask;
2839 		if (base_pa + size <= p->pa)
2840 			break;
2841 		base_pa = p->pa + p->size;
2842 	}
2843 
2844 	/*
2845 	 * At this point, we assume that base_pa is good enough.
2846 	 */
2847 	ASSERT((base_pa + size) <= FHC_MEMLOC_MAX);
2848 	if (base_pa != (base_pa & mask))
2849 		base_pa = (base_pa + size) & mask;	/* align */
2850 	return ((uint64_t)base_pa << FHC_MEMLOC_SHIFT);
2851 }
2852 
2853 /*
2854  * This simple function to write the MCRs can only be used when
2855  * the contents of memory are not valid as there is a bug in the AC
2856  * ASIC concerning refresh.
2857  */
2858 static void
2859 fhc_write_mcrs(
2860 	uint64_t cpa,
2861 	uint64_t dpa0,
2862 	uint64_t dpa1,
2863 	uint64_t c,
2864 	uint64_t d0,
2865 	uint64_t d1)
2866 {
2867 	stdphysio(cpa, c & ~AC_CSR_REFEN);
2868 	(void) lddphysio(cpa);
2869 	if (GRP_SIZE_IS_SET(d0)) {
2870 		stdphysio(dpa0, d0);
2871 		(void) lddphysio(dpa0);
2872 	}
2873 	if (GRP_SIZE_IS_SET(d1)) {
2874 		stdphysio(dpa1, d1);
2875 		(void) lddphysio(dpa1);
2876 	}
2877 	stdphysio(cpa, c);
2878 	(void) lddphysio(cpa);
2879 }
2880 
2881 /* compute the appropriate RASIZE for bank size */
2882 static uint_t
2883 fhc_cvt_size(uint64_t bsz)
2884 {
2885 	uint_t csz;
2886 
2887 	csz = 0;
2888 	bsz /= 64;
2889 	while (bsz) {
2890 		csz++;
2891 		bsz /= 2;
2892 	}
2893 	csz /= 2;
2894 
2895 	return (csz);
2896 }
2897 
2898 void
2899 fhc_program_memory(int board, uint64_t pa)
2900 {
2901 	uint64_t cpa, dpa0, dpa1;
2902 	uint64_t c, d0, d1;
2903 	uint64_t b0_pa, b1_pa;
2904 	uint64_t memdec0, memdec1;
2905 	uint_t b0_size, b1_size;
2906 
2907 	/* XXX gross hack to get to board via board number */
2908 	cpa = 0x1c0f9000060ull + (board * 0x400000000ull);
2909 #ifdef DEBUG_MEMDEC
2910 	prom_printf("cpa = 0x%llx\n", cpa);
2911 #endif /* DEBUG_MEMDEC */
2912 	dpa0 = cpa + 0x10;
2913 	dpa1 = cpa + 0x20;
2914 
2915 /* assume size is set by connect */
2916 	memdec0 = lddphysio(dpa0);
2917 #ifdef DEBUG_MEMDEC
2918 	prom_printf("memdec0 = 0x%llx\n", memdec0);
2919 #endif /* DEBUG_MEMDEC */
2920 	memdec1 = lddphysio(dpa1);
2921 #ifdef DEBUG_MEMDEC
2922 	prom_printf("memdec1 = 0x%llx\n", memdec1);
2923 #endif /* DEBUG_MEMDEC */
2924 	if (GRP_SIZE_IS_SET(memdec0)) {
2925 		b0_size = GRP_SPANMB(memdec0);
2926 	} else {
2927 		b0_size = 0;
2928 	}
2929 	if (GRP_SIZE_IS_SET(memdec1)) {
2930 		b1_size = GRP_SPANMB(memdec1);
2931 	} else {
2932 		b1_size = 0;
2933 	}
2934 
2935 	c = lddphysio(cpa);
2936 #ifdef DEBUG_MEMDEC
2937 	prom_printf("c = 0x%llx\n", c);
2938 #endif /* DEBUG_MEMDEC */
2939 	if (b0_size) {
2940 		b0_pa = pa;
2941 		d0 = SETUP_DECODE(b0_pa, b0_size, 0, 0);
2942 		d0 |= AC_MEM_VALID;
2943 
2944 		c &= ~0x7;
2945 		c |= 0;
2946 		c &= ~(0x7 << 8);
2947 		c |= (fhc_cvt_size(b0_size) << 8);  /* match row size */
2948 	} else {
2949 		d0 = memdec0;
2950 	}
2951 	if (b1_size) {
2952 		b1_pa = pa + 0x80000000ull; /* XXX 2gb */
2953 		d1 = SETUP_DECODE(b1_pa, b1_size, 0, 0);
2954 		d1 |= AC_MEM_VALID;
2955 
2956 		c &= ~(0x7 << 3);
2957 		c |= (0 << 3);
2958 		c &= ~(0x7 << 11);
2959 		c |= (fhc_cvt_size(b1_size) << 11); /* match row size */
2960 	} else {
2961 		d1 = memdec1;
2962 	}
2963 #ifdef DEBUG_MEMDEC
2964 	prom_printf("c 0x%llx, d0 0x%llx, d1 0x%llx\n", c, d0, d1);
2965 #endif /* DEBUG_MEMDEC */
2966 	fhc_write_mcrs(cpa, dpa0, dpa1, c, d0, d1);
2967 }
2968 
2969 /*
2970  * Creates a variable sized virtual kstat with a snapshot routine in order
2971  * to pass the linked list fault list up to userland. Also creates a
2972  * virtual kstat to pass up the string table for faults.
2973  */
2974 void
2975 create_ft_kstats(int instance)
2976 {
2977 	struct kstat *ksp;
2978 
2979 	ksp = kstat_create("unix", instance, FT_LIST_KSTAT_NAME, "misc",
2980 		KSTAT_TYPE_RAW, 1, KSTAT_FLAG_VIRTUAL|KSTAT_FLAG_VAR_SIZE);
2981 
2982 	if (ksp != NULL) {
2983 		ksp->ks_data = NULL;
2984 		ksp->ks_update = ft_ks_update;
2985 		ksp->ks_snapshot = ft_ks_snapshot;
2986 		ksp->ks_data_size = 1;
2987 		ksp->ks_lock = &ftlist_mutex;
2988 		kstat_install(ksp);
2989 	}
2990 }
2991 
2992 /*
2993  * This routine creates a snapshot of all the fault list data. It is
2994  * called by the kstat framework when a kstat read is done.
2995  */
2996 static int
2997 ft_ks_snapshot(struct kstat *ksp, void *buf, int rw)
2998 {
2999 	struct ft_link_list *ftlist;
3000 
3001 	if (rw == KSTAT_WRITE) {
3002 		return (EACCES);
3003 	}
3004 
3005 	ksp->ks_snaptime = gethrtime();
3006 
3007 	for (ftlist = ft_list; ftlist != NULL; ftlist = ftlist->next) {
3008 		bcopy(&ftlist->f, buf, sizeof (struct ft_list));
3009 		buf = ((struct ft_list *)buf) + 1;
3010 	}
3011 	return (0);
3012 }
3013 
3014 /*
3015  * Setup the kstat data size for the kstat framework. This is used in
3016  * conjunction with the ks_snapshot routine. This routine sets the size,
3017  * the kstat framework allocates the memory, and ks_shapshot does the
3018  * data transfer.
3019  */
3020 static int
3021 ft_ks_update(struct kstat *ksp, int rw)
3022 {
3023 	if (rw == KSTAT_WRITE) {
3024 		return (EACCES);
3025 	} else {
3026 		if (ft_nfaults) {
3027 			ksp->ks_data_size = ft_nfaults *
3028 				sizeof (struct ft_list);
3029 		} else {
3030 			ksp->ks_data_size = 1;
3031 		}
3032 	}
3033 
3034 	return (0);
3035 }
3036 
3037 /*
3038  * Power off any cpus on the board.
3039  */
3040 int
3041 fhc_board_poweroffcpus(int board, char *errbuf, int cpu_flags)
3042 {
3043 	cpu_t *cpa, *cpb;
3044 	enum board_type type;
3045 	int error = 0;
3046 
3047 	ASSERT(MUTEX_HELD(&cpu_lock));
3048 
3049 	/*
3050 	 * what type of board are we dealing with?
3051 	 */
3052 	type = fhc_bd_type(board);
3053 
3054 	switch (type) {
3055 	case CPU_BOARD:
3056 
3057 		/*
3058 		 * the shutdown sequence will be:
3059 		 *
3060 		 * idle both cpus then shut them off.
3061 		 * it looks like the hardware gets corrupted if one
3062 		 * cpu is busy while the other is shutting down...
3063 		 */
3064 
3065 		if ((cpa = cpu_get(FHC_BOARD2CPU_A(board))) != NULL &&
3066 		    cpu_is_active(cpa)) {
3067 			if (!cpu_intr_on(cpa)) {
3068 				cpu_intr_enable(cpa);
3069 			}
3070 			if ((error = cpu_offline(cpa, cpu_flags)) != 0) {
3071 				cmn_err(CE_WARN,
3072 				    "Processor %d failed to offline.",
3073 				    cpa->cpu_id);
3074 				if (errbuf != NULL) {
3075 					(void) snprintf(errbuf, SYSC_OUTPUT_LEN,
3076 					    "processor %d failed to offline",
3077 					    cpa->cpu_id);
3078 				}
3079 			}
3080 		}
3081 
3082 		if (error == 0 &&
3083 		    (cpb = cpu_get(FHC_BOARD2CPU_B(board))) != NULL &&
3084 		    cpu_is_active(cpb)) {
3085 			if (!cpu_intr_on(cpb)) {
3086 				cpu_intr_enable(cpb);
3087 			}
3088 			if ((error = cpu_offline(cpb, cpu_flags)) != 0) {
3089 				cmn_err(CE_WARN,
3090 				    "Processor %d failed to offline.",
3091 				    cpb->cpu_id);
3092 
3093 				if (errbuf != NULL) {
3094 					(void) snprintf(errbuf, SYSC_OUTPUT_LEN,
3095 					    "processor %d failed to offline",
3096 					    cpb->cpu_id);
3097 				}
3098 			}
3099 		}
3100 
3101 		if (error == 0 && cpa != NULL && cpu_is_offline(cpa)) {
3102 			if ((error = cpu_poweroff(cpa)) != 0) {
3103 				cmn_err(CE_WARN,
3104 				    "Processor %d failed to power off.",
3105 				    cpa->cpu_id);
3106 				if (errbuf != NULL) {
3107 					(void) snprintf(errbuf, SYSC_OUTPUT_LEN,
3108 					    "processor %d failed to power off",
3109 					    cpa->cpu_id);
3110 				}
3111 			} else {
3112 				cmn_err(CE_NOTE, "Processor %d powered off.",
3113 				    cpa->cpu_id);
3114 			}
3115 		}
3116 
3117 		if (error == 0 && cpb != NULL && cpu_is_offline(cpb)) {
3118 			if ((error = cpu_poweroff(cpb)) != 0) {
3119 				cmn_err(CE_WARN,
3120 				    "Processor %d failed to power off.",
3121 				    cpb->cpu_id);
3122 
3123 				if (errbuf != NULL) {
3124 					(void) snprintf(errbuf, SYSC_OUTPUT_LEN,
3125 					    "processor %d failed to power off",
3126 					    cpb->cpu_id);
3127 				}
3128 			} else {
3129 				cmn_err(CE_NOTE, "Processor %d powered off.",
3130 				    cpb->cpu_id);
3131 			}
3132 		}
3133 
3134 		/*
3135 		 * If all the shutdowns completed, ONLY THEN, clear the
3136 		 * incorrectly valid dtags...
3137 		 *
3138 		 * IMPORTANT: it is an error to read or write dtags while
3139 		 * they are 'active'
3140 		 */
3141 		if (error == 0 && (cpa != NULL || cpb != NULL)) {
3142 			u_longlong_t base = 0;
3143 			int i;
3144 #ifdef DEBUG
3145 			int nonz0 = 0;
3146 			int nonz1 = 0;
3147 #endif
3148 			if (cpa != NULL)
3149 				base = FHC_DTAG_BASE(cpa->cpu_id);
3150 			if (cpb != NULL)
3151 				base = FHC_DTAG_BASE(cpb->cpu_id);
3152 			ASSERT(base != 0);
3153 
3154 			for (i = 0; i < FHC_DTAG_SIZE; i += FHC_DTAG_SKIP) {
3155 				u_longlong_t value = lddphysio(base+i);
3156 #ifdef lint
3157 				value = value;
3158 #endif
3159 #ifdef DEBUG
3160 				if (cpa != NULL && (value & FHC_DTAG_LOW))
3161 					nonz0++;
3162 				if (cpb != NULL && (value & FHC_DTAG_HIGH))
3163 					nonz1++;
3164 #endif
3165 				/* always clear the dtags */
3166 				stdphysio(base + i, 0ull);
3167 			}
3168 #ifdef DEBUG
3169 			if (nonz0 || nonz1) {
3170 				cmn_err(CE_NOTE, "!dtag results: "
3171 				    "cpua valid %d, cpub valid %d",
3172 				    nonz0, nonz1);
3173 			}
3174 #endif
3175 		}
3176 
3177 		break;
3178 
3179 	default:
3180 		break;
3181 	}
3182 
3183 	return (error);
3184 }
3185 
3186 /*
3187  * platform code for shutting down cpus.
3188  */
3189 int
3190 fhc_cpu_poweroff(struct cpu *cp)
3191 {
3192 	int board;
3193 	fhc_bd_t *bd_list;
3194 	int delays;
3195 	extern void idle_stop_xcall(void);
3196 	static void fhc_cpu_shutdown_self(void);
3197 
3198 	ASSERT(MUTEX_HELD(&cpu_lock));
3199 	ASSERT((cp->cpu_flags & (CPU_EXISTS | CPU_OFFLINE | CPU_QUIESCED)) ==
3200 		(CPU_EXISTS | CPU_OFFLINE | CPU_QUIESCED));
3201 
3202 	/*
3203 	 * Lock the board so that we can safely access the
3204 	 * registers. This cannot be done inside the pause_cpus().
3205 	 */
3206 	board = FHC_CPU2BOARD(cp->cpu_id);
3207 	bd_list = fhc_bdlist_lock(board);
3208 	ASSERT(fhc_bd_valid(board) && (bd_list->sc.type == CPU_BOARD));
3209 
3210 	/*
3211 	 * Capture all CPUs (except for detaching proc) to prevent
3212 	 * crosscalls to the detaching proc until it has cleared its
3213 	 * bit in cpu_ready_set.
3214 	 *
3215 	 * The CPU's remain paused and the prom_mutex is known to be free.
3216 	 * This prevents the x-trap victim from blocking when doing prom
3217 	 * IEEE-1275 calls at a high PIL level.
3218 	 */
3219 	promsafe_pause_cpus();
3220 
3221 	/*
3222 	 * Quiesce interrupts on the target CPU. We do this by setting
3223 	 * the CPU 'not ready'- (i.e. removing the CPU from cpu_ready_set) to
3224 	 * prevent it from receiving cross calls and cross traps.
3225 	 * This prevents the processor from receiving any new soft interrupts.
3226 	 */
3227 	mp_cpu_quiesce(cp);
3228 
3229 	xt_one_unchecked(cp->cpu_id, (xcfunc_t *)idle_stop_xcall,
3230 		(uint64_t)fhc_cpu_shutdown_self, (uint64_t)NULL);
3231 
3232 	/*
3233 	 * Wait for slave cpu to shutdown.
3234 	 * Sense this by watching the hardware EPDx bit.
3235 	 */
3236 	for (delays = FHC_SHUTDOWN_WAIT_MSEC; delays != 0; delays--) {
3237 		uint_t temp;
3238 
3239 		DELAY(1000);
3240 
3241 		/* get the current cpu power status */
3242 		temp = *bd_list->softsp->ctrl;
3243 
3244 		/* has the cpu actually signalled shutdown? */
3245 		if (FHC_CPU_IS_A(cp->cpu_id)) {
3246 			if (temp & FHC_EPDA_OFF)
3247 				break;
3248 		} else {
3249 			if (temp & FHC_EPDB_OFF)
3250 				break;
3251 		}
3252 	}
3253 
3254 	start_cpus();
3255 
3256 	fhc_bdlist_unlock();
3257 
3258 	/* A timeout means we've lost control of the cpu. */
3259 	if (delays == 0)
3260 		panic("Processor %d failed during shutdown", cp->cpu_id);
3261 
3262 	return (0);
3263 }
3264 
3265 /*
3266  * shutdown_self
3267  * slave side shutdown.  clean up and execute the shutdown sequence.
3268  */
3269 static void
3270 fhc_cpu_shutdown_self(void)
3271 {
3272 	extern void flush_windows(void);
3273 	static void os_completes_shutdown(void);
3274 
3275 	flush_windows();
3276 
3277 	ASSERT(CPU->cpu_intr_actv == 0);
3278 	ASSERT(CPU->cpu_thread == CPU->cpu_idle_thread ||
3279 	    CPU->cpu_thread == CPU->cpu_startup_thread);
3280 
3281 	CPU->cpu_flags = CPU_POWEROFF | CPU_OFFLINE | CPU_QUIESCED;
3282 
3283 	(void) prom_sunfire_cpu_off();	/* inform Ultra Enterprise prom */
3284 
3285 	os_completes_shutdown();
3286 
3287 	panic("fhc_cpu_shutdown_self: cannot return");
3288 	/*NOTREACHED*/
3289 }
3290 
3291 /*
3292  * Warm start CPU.
3293  */
3294 static int
3295 fhc_cpu_start(struct cpu *cp)
3296 {
3297 	int rv;
3298 	int cpuid = cp->cpu_id;
3299 	pnode_t nodeid;
3300 	extern void restart_other_cpu(int);
3301 
3302 	ASSERT(MUTEX_HELD(&cpu_lock));
3303 
3304 	/* power on cpu */
3305 	nodeid = cpunodes[cpuid].nodeid;
3306 	ASSERT(nodeid != (pnode_t)0);
3307 	rv = prom_wakeupcpu(nodeid);
3308 	if (rv != 0) {
3309 		cmn_err(CE_WARN, "Processor %d failed to power on.", cpuid);
3310 		return (EBUSY);
3311 	}
3312 
3313 	cp->cpu_flags &= ~CPU_POWEROFF;
3314 
3315 	/*
3316 	 * NOTE: restart_other_cpu pauses cpus during the slave cpu start.
3317 	 * This helps to quiesce the bus traffic a bit which makes
3318 	 * the tick sync routine in the prom more robust.
3319 	 */
3320 	restart_other_cpu(cpuid);
3321 
3322 	return (0);
3323 }
3324 
3325 /*
3326  * Power on CPU.
3327  */
3328 int
3329 fhc_cpu_poweron(struct cpu *cp)
3330 {
3331 	fhc_bd_t *bd_list;
3332 	enum temp_state state;
3333 	int board;
3334 	int status;
3335 	int status_other;
3336 	struct cpu *cp_other;
3337 
3338 	ASSERT(MUTEX_HELD(&cpu_lock));
3339 	ASSERT(cpu_is_poweredoff(cp));
3340 
3341 	/* do not power on overtemperature cpu */
3342 	board = FHC_CPU2BOARD(cp->cpu_id);
3343 	bd_list = fhc_bdlist_lock(board);
3344 
3345 	ASSERT(bd_list != NULL);
3346 	ASSERT(bd_list->sc.type == CPU_BOARD);
3347 	ASSERT(bd_list->dev_softsp != NULL);
3348 
3349 	state = ((struct environ_soft_state *)
3350 		bd_list->dev_softsp)->tempstat.state;
3351 
3352 	fhc_bdlist_unlock();
3353 	if ((state == TEMP_WARN) || (state == TEMP_DANGER))
3354 		return (EBUSY);
3355 
3356 	status = fhc_cpu_start(cp);
3357 
3358 	/* policy for dual cpu boards */
3359 
3360 	if ((status == 0) &&
3361 	    ((cp_other = cpu_get(FHC_OTHER_CPU_ID(cp->cpu_id))) != NULL)) {
3362 		/*
3363 		 * Do not leave board's other cpu idling in the prom.
3364 		 * Start the other cpu and set its state to P_OFFLINE.
3365 		 */
3366 		status_other = fhc_cpu_start(cp_other);
3367 		if (status_other != 0) {
3368 			panic("fhc: failed to start second CPU"
3369 			    " in pair %d & %d, error %d",
3370 			    cp->cpu_id, cp_other->cpu_id, status_other);
3371 		}
3372 	}
3373 
3374 	return (status);
3375 }
3376 
3377 /*
3378  * complete the shutdown sequence in case the firmware doesn't.
3379  *
3380  * If the firmware returns, then complete the shutdown code.
3381  * (sunfire firmware presently only updates its status.  the
3382  * OS must flush the D-tags and execute the shutdown instruction.)
3383  */
3384 static void
3385 os_completes_shutdown(void)
3386 {
3387 	pfn_t 			pfn;
3388 	tte_t			tte;
3389 	volatile uint_t		*src;
3390 	volatile uint_t		*dst;
3391 	caddr_t			copy_addr;
3392 	extern void fhc_shutdown_asm(u_longlong_t, int);
3393 	extern void fhc_shutdown_asm_end(void);
3394 
3395 	copy_addr = shutdown_va + FHC_SRAM_OS_OFFSET;
3396 
3397 	/* compute sram global address for this operation */
3398 	pfn = FHC_LOCAL_OS_PAGEBASE >> MMU_PAGESHIFT;
3399 
3400 	/* force load i and d translations */
3401 	tte.tte_inthi = TTE_VALID_INT | TTE_SZ_INT(TTE8K) |
3402 		TTE_PFN_INTHI(pfn);
3403 	tte.tte_intlo = TTE_PFN_INTLO(pfn) |
3404 		TTE_HWWR_INT | TTE_PRIV_INT | TTE_LCK_INT; /* un$ */
3405 	sfmmu_dtlb_ld_kva(shutdown_va, &tte);	/* load dtlb */
3406 	sfmmu_itlb_ld_kva(shutdown_va, &tte);	/* load itlb */
3407 
3408 	/*
3409 	 * copy the special shutdown function to sram
3410 	 * (this is a special integer copy that synchronizes with localspace
3411 	 * accesses.  we need special throttling to ensure copy integrity)
3412 	 */
3413 	for (src = (uint_t *)fhc_shutdown_asm, dst = (uint_t *)copy_addr;
3414 	    src < (uint_t *)fhc_shutdown_asm_end;
3415 	    src++, dst++) {
3416 		volatile uint_t dummy;
3417 
3418 		*dst = *src;
3419 		/*
3420 		 * ensure non corrupting single write operations to
3421 		 * localspace sram by interleaving reads with writes.
3422 		 */
3423 		dummy = *dst;
3424 #ifdef lint
3425 		dummy = dummy;
3426 #endif
3427 	}
3428 
3429 	/*
3430 	 * Call the shutdown sequencer.
3431 	 * NOTE: the base flush address must be unique for each MID.
3432 	 */
3433 	((void (*)(u_longlong_t, int))copy_addr)(
3434 		FHC_BASE_NOMEM + CPU->cpu_id * FHC_MAX_ECACHE_SIZE,
3435 		cpunodes[CPU->cpu_id].ecache_size);
3436 }
3437 
3438 enum temp_state
3439 fhc_env_temp_state(int board)
3440 {
3441 	fhc_bd_t *bdp;
3442 	struct environ_soft_state *envp;
3443 
3444 	ASSERT(fhc_bd_valid(board));
3445 
3446 	bdp = fhc_bd(board);
3447 
3448 	/*
3449 	 * Due to asynchronous attach of environ, environ may
3450 	 * not be attached by the time we start calling this routine
3451 	 * to check the temperature state.  Environ not attaching is
3452 	 * pathological so this will only cover the time between
3453 	 * board connect and environ attach.
3454 	 */
3455 	if (!bdp->dev_softsp) {
3456 		return (TEMP_OK);
3457 	}
3458 	envp = (struct environ_soft_state *)bdp->dev_softsp;
3459 
3460 	return (envp->tempstat.state);
3461 }
3462 
3463 static void
3464 fhc_tod_fault(enum tod_fault_type tod_bad)
3465 {
3466 	int board_num = 0;
3467 	enum ft_class class = FT_SYSTEM;
3468 	uint64_t addr;
3469 
3470 	addr = (va_to_pa((void *)v_eeprom_addr)) >> BOARD_PHYADDR_SHIFT;
3471 
3472 	if ((addr & CLOCKBOARD_PHYADDR_BITS) != CLOCKBOARD_PHYADDR_BITS) {
3473 		/* if tod is not on clock board, */
3474 		/* it'd be on one of io boards */
3475 		board_num = (addr >> IO_BOARD_NUMBER_SHIFT)
3476 				& IO_BOARD_NUMBER_MASK;
3477 		class = FT_BOARD;
3478 	}
3479 
3480 	switch (tod_bad) {
3481 	case TOD_NOFAULT:
3482 		clear_fault(board_num, FT_TODFAULT, class);
3483 		break;
3484 	case TOD_REVERSED:
3485 	case TOD_STALLED:
3486 	case TOD_JUMPED:
3487 	case TOD_RATECHANGED:
3488 		reg_fault(board_num, FT_TODFAULT, class);
3489 		break;
3490 	default:
3491 		break;
3492 	}
3493 }
3494