sysctrl.c revision 1341:6d7c4f090a72
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include <sys/types.h>
30#include <sys/conf.h>
31#include <sys/ddi.h>
32#include <sys/sunddi.h>
33#include <sys/ddi_impldefs.h>
34#include <sys/sunndi.h>
35#include <sys/ndi_impldefs.h>
36#include <sys/obpdefs.h>
37#include <sys/cmn_err.h>
38#include <sys/errno.h>
39#include <sys/kmem.h>
40#include <sys/debug.h>
41#include <sys/sysmacros.h>
42#include <sys/ivintr.h>
43#include <sys/autoconf.h>
44#include <sys/intreg.h>
45#include <sys/proc.h>
46#include <sys/modctl.h>
47#include <sys/callb.h>
48#include <sys/file.h>
49#include <sys/open.h>
50#include <sys/stat.h>
51#include <sys/fhc.h>
52#include <sys/sysctrl.h>
53#include <sys/jtag.h>
54#include <sys/ac.h>
55#include <sys/simmstat.h>
56#include <sys/clock.h>
57#include <sys/promif.h>
58#include <sys/promimpl.h>
59#include <sys/sunndi.h>
60#include <sys/machsystm.h>
61
62/* Useful debugging Stuff */
63#ifdef DEBUG
64int sysc_debug_info = 1;
65int sysc_debug_print_level = 0;
66#endif
67
68/*
69 * Function prototypes
70 */
71static int sysctrl_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
72		void **result);
73
74static int sysctrl_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
75
76static int sysctrl_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
77
78static int sysctrl_open(dev_t *, int, int, cred_t *);
79
80static int sysctrl_close(dev_t, int, int, cred_t *);
81
82static int sysctrl_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
83
84static uint_t system_high_handler(caddr_t arg);
85
86static uint_t spur_delay(caddr_t arg);
87
88static void spur_retry(void *);
89
90static uint_t spur_reenable(caddr_t arg);
91
92static void spur_long_timeout(void *);
93
94static uint_t spur_clear_count(caddr_t arg);
95
96static uint_t ac_fail_handler(caddr_t arg);
97
98static void ac_fail_retry(void *);
99
100static uint_t ac_fail_reenable(caddr_t arg);
101
102static uint_t ps_fail_int_handler(caddr_t arg);
103
104static uint_t ps_fail_poll_handler(caddr_t arg);
105
106static uint_t ps_fail_handler(struct sysctrl_soft_state *softsp, int fromint);
107
108enum power_state compute_power_state(struct sysctrl_soft_state *softsp,
109					int plus_load);
110
111static void ps_log_state_change(struct sysctrl_soft_state *softsp,
112					int index, int present);
113
114static void ps_log_pres_change(struct sysctrl_soft_state *softsp,
115					int index, int present);
116
117static void ps_fail_retry(void *);
118
119static uint_t pps_fanfail_handler(caddr_t arg);
120
121static void pps_fanfail_retry(void *);
122
123static uint_t pps_fanfail_reenable(caddr_t arg);
124
125static void pps_fan_poll(void *);
126
127static void pps_fan_state_change(struct sysctrl_soft_state *softsp,
128					int index, int fan_ok);
129
130static uint_t bd_insert_handler(caddr_t arg);
131
132static void bd_insert_timeout(void *);
133
134static void bd_remove_timeout(void *);
135
136static uint_t bd_insert_normal(caddr_t arg);
137
138static void sysctrl_add_kstats(struct sysctrl_soft_state *softsp);
139
140static int sysctrl_kstat_update(kstat_t *ksp, int rw);
141
142static int psstat_kstat_update(kstat_t *, int);
143
144static void init_remote_console_uart(struct sysctrl_soft_state *);
145
146static void blink_led_timeout(void *);
147
148static uint_t blink_led_handler(caddr_t arg);
149
150static void sysctrl_thread_wakeup(void *type);
151
152static void sysctrl_overtemp_poll(void);
153
154static void sysctrl_keyswitch_poll(void);
155
156static void update_key_state(struct sysctrl_soft_state *);
157
158static void sysctrl_abort_seq_handler(char *msg);
159
160static void nvram_update_powerfail(struct sysctrl_soft_state *softsp);
161
162static void toggle_board_green_leds(int);
163
164void bd_remove_poll(struct sysctrl_soft_state *);
165
166static void sysc_slot_info(int nslots, int *start, int *limit, int *incr);
167
168extern void sysc_board_connect_supported_init(void);
169
170static void rcons_reinit(struct sysctrl_soft_state *softsp);
171
172/*
173 * Configuration data structures
174 */
175static struct cb_ops sysctrl_cb_ops = {
176	sysctrl_open,		/* open */
177	sysctrl_close,		/* close */
178	nulldev,		/* strategy */
179	nulldev,		/* print */
180	nulldev,		/* dump */
181	nulldev,		/* read */
182	nulldev,		/* write */
183	sysctrl_ioctl,		/* ioctl */
184	nodev,			/* devmap */
185	nodev,			/* mmap */
186	nodev,			/* segmap */
187	nochpoll,		/* poll */
188	ddi_prop_op,		/* cb_prop_op */
189	0,			/* streamtab */
190	D_MP|D_NEW,		/* Driver compatibility flag */
191	CB_REV,			/* rev */
192	nodev,			/* cb_aread */
193	nodev			/* cb_awrite */
194};
195
196static struct dev_ops sysctrl_ops = {
197	DEVO_REV,		/* devo_rev */
198	0,			/* refcnt */
199	sysctrl_info,		/* getinfo */
200	nulldev,		/* identify */
201	nulldev,		/* probe */
202	sysctrl_attach,		/* attach */
203	sysctrl_detach,		/* detach */
204	nulldev,		/* reset */
205	&sysctrl_cb_ops,	/* cb_ops */
206	(struct bus_ops *)0,	/* bus_ops */
207	nulldev			/* power */
208};
209
210void *sysctrlp;				/* sysctrl soft state hook */
211
212/* # of ticks to silence spurious interrupts */
213static clock_t spur_timeout_hz;
214
215/* # of ticks to count spurious interrupts to print message */
216static clock_t spur_long_timeout_hz;
217
218/* # of ticks between AC failure polling */
219static clock_t ac_timeout_hz;
220
221/* # of ticks between Power Supply Failure polling */
222static clock_t ps_fail_timeout_hz;
223
224/*
225 * # of ticks between Peripheral Power Supply failure polling
226 * (used both for interrupt retry timeout and polling function)
227 */
228static clock_t pps_fan_timeout_hz;
229
230/* # of ticks delay after board insert interrupt */
231static clock_t bd_insert_delay_hz;
232
233/* # of secs to wait before restarting poll if we cannot clear interrupts */
234static clock_t bd_insert_retry_hz;
235
236/* # of secs between Board Removal polling */
237static clock_t bd_remove_timeout_hz;
238
239/* # of secs between toggle of OS LED */
240static clock_t blink_led_timeout_hz;
241
242/* overtemp polling routine timeout delay */
243static clock_t overtemp_timeout_hz;
244
245/* key switch polling routine timeout delay */
246static clock_t keyswitch_timeout_hz;
247
248/* Specify which system interrupt condition to monitor */
249int enable_sys_interrupt = SYS_AC_PWR_FAIL_EN | SYS_PPS_FAN_FAIL_EN |
250			SYS_PS_FAIL_EN | SYS_SBRD_PRES_EN;
251
252/* Should the overtemp_poll thread be running? */
253static int sysctrl_do_overtemp_thread = 1;
254
255/* Should the keyswitch_poll thread be running? */
256static int sysctrl_do_keyswitch_thread = 1;
257
258/*
259 * This timeout ID is for board remove polling routine. It is
260 * protected by the fhc_bdlist mutex.
261 * XXX - This will not work for wildfire. A different scheme must be
262 * used since there will be multiple sysctrl nodes, each with its
263 * own list of hotplugged boards to scan.
264 */
265static timeout_id_t bd_remove_to_id = 0;
266
267/*
268 * If this is set, the system will not shutdown when insufficient power
269 * condition persists.
270 */
271int disable_insufficient_power_reboot = 0;
272
273/*
274 * Set this to enable suspend/resume
275 */
276int sysctrl_enable_detach_suspend = 0;
277
278/*
279 * Set this to reflect the OBP initialized HOTPLUG_DISABLED_PROPERTY and
280 * during dynamic detection
281 */
282int sysctrl_hotplug_disabled = FALSE;
283
284/* Indicates whether or not the overtemp thread has been started */
285static int sysctrl_overtemp_thread_started = 0;
286
287/* Indicates whether or not the key switch thread has been started */
288static int sysctrl_keyswitch_thread_started = 0;
289
290/* *Mutex used to protect the soft state list */
291static kmutex_t sslist_mutex;
292
293/* The CV is used to wakeup the overtemp thread when needed. */
294static kcondvar_t overtemp_cv;
295
296/* The CV is used to wakeup the key switch thread when needed. */
297static kcondvar_t keyswitch_cv;
298
299/* This mutex is used to protect the sysctrl_ddi_branch_init variable */
300static kmutex_t sysctrl_branch_mutex;
301
302/*
303 * This variable is set after all existing branches in the system have
304 * been discovered and held via e_ddi_branch_hold(). This happens on
305 * first open() of any sysctrl minor node.
306 */
307static int sysctrl_ddi_branch_init;
308
309/*
310 * Linked list of all syctrl soft state structures.
311 * Used for polling sysctrl state changes, i.e. temperature.
312 */
313struct sysctrl_soft_state *sys_list = NULL;
314
315extern struct mod_ops mod_driverops;
316
317static struct modldrv modldrv = {
318	&mod_driverops,		/* Type of module.  This one is a driver */
319	"Clock Board %I%",	/* name of module */
320	&sysctrl_ops,		/* driver ops */
321};
322
323static struct modlinkage modlinkage = {
324	MODREV_1,		/* rev */
325	(void *)&modldrv,
326	NULL
327};
328
329#ifndef lint
330static char _depends_on[] = "drv/fhc";
331#endif /* lint */
332
333/*
334 * These are the module initialization routines.
335 */
336
337int
338_init(void)
339{
340	int error;
341
342	if ((error = ddi_soft_state_init(&sysctrlp,
343	    sizeof (struct sysctrl_soft_state), 1)) != 0)
344		return (error);
345
346	error = mod_install(&modlinkage);
347	if (error != 0) {
348		ddi_soft_state_fini(&sysctrlp);
349		return (error);
350	}
351
352	mutex_init(&sysctrl_branch_mutex, NULL, MUTEX_DRIVER, NULL);
353
354	return (0);
355}
356
357int
358_fini(void)
359{
360	int error;
361
362	if ((error = mod_remove(&modlinkage)) != 0)
363		return (error);
364
365	ddi_soft_state_fini(&sysctrlp);
366
367	mutex_destroy(&sysctrl_branch_mutex);
368
369	return (0);
370}
371
372int
373_info(struct modinfo *modinfop)
374{
375	return (mod_info(&modlinkage, modinfop));
376}
377
378/* ARGSUSED */
379static int
380sysctrl_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
381{
382	dev_t	dev;
383	int	instance;
384
385	if (infocmd == DDI_INFO_DEVT2INSTANCE) {
386		dev = (dev_t)arg;
387		instance = GETINSTANCE(dev);
388		*result = (void *)(uintptr_t)instance;
389		return (DDI_SUCCESS);
390	}
391	return (DDI_FAILURE);
392}
393
394static int
395sysctrl_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
396{
397	struct sysctrl_soft_state *softsp;
398	int instance;
399	uchar_t tmp_reg;
400	dev_info_t *dip;
401	char *propval;
402	int proplen;
403	int slot_num;
404	int start;		/* start index for scan loop */
405	int limit;		/* board number limit for scan loop */
406	int incr;		/* amount to incr each pass thru loop */
407	void set_clockbrd_info(void);
408
409
410	switch (cmd) {
411	case DDI_ATTACH:
412		break;
413
414	case DDI_RESUME:
415		/* XXX see sysctrl:DDI_SUSPEND for special h/w treatment */
416		return (DDI_SUCCESS);
417
418	default:
419		return (DDI_FAILURE);
420	}
421
422	instance = ddi_get_instance(devi);
423
424	if (ddi_soft_state_zalloc(sysctrlp, instance) != DDI_SUCCESS)
425		return (DDI_FAILURE);
426
427	softsp = GETSOFTC(instance);
428
429	/* Set the dip in the soft state */
430	softsp->dip = devi;
431
432	/* Set up the parent dip */
433	softsp->pdip = ddi_get_parent(softsp->dip);
434
435	DPRINTF(SYSCTRL_ATTACH_DEBUG, ("sysctrl: devi= 0x%p\n, softsp=0x%p\n",
436		devi, softsp));
437
438	/* First set all of the timeout values */
439	spur_timeout_hz = drv_usectohz(SPUR_TIMEOUT_USEC);
440	spur_long_timeout_hz = drv_usectohz(SPUR_LONG_TIMEOUT_USEC);
441	ac_timeout_hz = drv_usectohz(AC_TIMEOUT_USEC);
442	ps_fail_timeout_hz = drv_usectohz(PS_FAIL_TIMEOUT_USEC);
443	pps_fan_timeout_hz = drv_usectohz(PPS_FAN_TIMEOUT_USEC);
444	bd_insert_delay_hz = drv_usectohz(BRD_INSERT_DELAY_USEC);
445	bd_insert_retry_hz = drv_usectohz(BRD_INSERT_RETRY_USEC);
446	bd_remove_timeout_hz = drv_usectohz(BRD_REMOVE_TIMEOUT_USEC);
447	blink_led_timeout_hz = drv_usectohz(BLINK_LED_TIMEOUT_USEC);
448	overtemp_timeout_hz = drv_usectohz(OVERTEMP_TIMEOUT_SEC * MICROSEC);
449	keyswitch_timeout_hz = drv_usectohz(KEYSWITCH_TIMEOUT_USEC);
450
451	/*
452	 * Map in the registers sets that OBP hands us. According
453	 * to the sun4u device tree spec., the register sets are as
454	 * follows:
455	 *
456	 *	0	Clock Frequency Registers (contains the bit
457	 *		for enabling the remote console reset)
458	 *	1	Misc (has all the registers that we need
459	 *	2	Clock Version Register
460	 */
461	if (ddi_map_regs(softsp->dip, 0,
462	    (caddr_t *)&softsp->clk_freq1, 0, 0)) {
463		cmn_err(CE_WARN, "sysctrl%d: unable to map clock frequency "
464			"registers", instance);
465		goto bad0;
466	}
467
468	if (ddi_map_regs(softsp->dip, 1,
469	    (caddr_t *)&softsp->csr, 0, 0)) {
470		cmn_err(CE_WARN, "sysctrl%d: unable to map internal"
471			"registers", instance);
472		goto bad1;
473	}
474
475	/*
476	 * There is a new register for newer vintage clock board nodes,
477	 * OBP register set 2 in the clock board node.
478	 *
479	 */
480	(void) ddi_map_regs(softsp->dip, 2, (caddr_t *)&softsp->clk_ver, 0, 0);
481
482	/*
483	 * Fill in the virtual addresses of the registers in the
484	 * sysctrl_soft_state structure. We do not want to calculate
485	 * them on the fly. This way we waste a little memory, but
486	 * avoid bugs down the road.
487	 */
488	softsp->clk_freq2 = (uchar_t *)((caddr_t)softsp->clk_freq1 +
489		SYS_OFF_CLK_FREQ2);
490
491	softsp->status1 = (uchar_t *)((caddr_t)softsp->csr +
492		SYS_OFF_STAT1);
493
494	softsp->status2 = (uchar_t *)((caddr_t)softsp->csr +
495		SYS_OFF_STAT2);
496
497	softsp->ps_stat = (uchar_t *)((caddr_t)softsp->csr +
498		SYS_OFF_PSSTAT);
499
500	softsp->ps_pres = (uchar_t *)((caddr_t)softsp->csr +
501		SYS_OFF_PSPRES);
502
503	softsp->pppsr = (uchar_t *)((caddr_t)softsp->csr +
504		SYS_OFF_PPPSR);
505
506	softsp->temp_reg = (uchar_t *)((caddr_t)softsp->csr +
507		SYS_OFF_TEMP);
508
509	set_clockbrd_info();
510
511	/*
512	 * Enable the hardware watchdog gate on the clock board if
513	 * map_wellknown has detected that watchdog timer is available
514	 * and user wants it to be enabled.
515	 */
516	if (watchdog_available && watchdog_enable)
517		*(softsp->clk_freq2) |= TOD_RESET_EN;
518	else
519		*(softsp->clk_freq2) &= ~TOD_RESET_EN;
520
521	/* Check for inherited faults from the PROM. */
522	if (*softsp->csr & SYS_LED_MID) {
523		reg_fault(0, FT_PROM, FT_SYSTEM);
524	}
525
526	/*
527	 * calculate and cache the number of slots on this system
528	 */
529	switch (SYS_TYPE(*softsp->status1)) {
530	case SYS_16_SLOT:
531		softsp->nslots = 16;
532		break;
533
534	case SYS_8_SLOT:
535		softsp->nslots = 8;
536		break;
537
538	case SYS_4_SLOT:
539		/* check the clk_version register - if the ptr is valid */
540		if ((softsp->clk_ver != NULL) &&
541		    (SYS_TYPE2(*softsp->clk_ver) == SYS_PLUS_SYSTEM)) {
542			softsp->nslots = 5;
543		} else {
544			softsp->nslots = 4;
545		}
546		break;
547
548	case SYS_TESTBED:
549	default:
550		softsp->nslots = 0;
551		break;
552	}
553
554
555	/* create the fault list kstat */
556	create_ft_kstats(instance);
557
558	/*
559	 * Do a priming read on the ADC, and throw away the first value
560	 * read. This is a feature of the ADC hardware. After a power cycle
561	 * it does not contains valid data until a read occurs.
562	 */
563	tmp_reg = *(softsp->temp_reg);
564
565	/* Wait 30 usec for ADC hardware to stabilize. */
566	DELAY(30);
567
568	/* shut off all interrupt sources */
569	*(softsp->csr) &= ~(SYS_PPS_FAN_FAIL_EN | SYS_PS_FAIL_EN |
570				SYS_AC_PWR_FAIL_EN | SYS_SBRD_PRES_EN);
571	tmp_reg = *(softsp->csr);
572#ifdef lint
573	tmp_reg = tmp_reg;
574#endif
575
576	/*
577	 * Now register our high interrupt with the system.
578	 */
579	if (ddi_add_intr(devi, 0, &softsp->iblock,
580	    &softsp->idevice, (uint_t (*)(caddr_t))nulldev, NULL) !=
581	    DDI_SUCCESS)
582		goto bad2;
583
584	mutex_init(&softsp->csr_mutex, NULL, MUTEX_DRIVER,
585	    (void *)softsp->iblock);
586
587	ddi_remove_intr(devi, 0, softsp->iblock);
588
589	if (ddi_add_intr(devi, 0, &softsp->iblock,
590	    &softsp->idevice, system_high_handler, (caddr_t)softsp) !=
591	    DDI_SUCCESS)
592		goto bad3;
593
594	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->spur_id,
595	    &softsp->spur_int_c, NULL, spur_delay, (caddr_t)softsp) !=
596	    DDI_SUCCESS)
597		goto bad4;
598
599	mutex_init(&softsp->spur_int_lock, NULL, MUTEX_DRIVER,
600		(void *)softsp->spur_int_c);
601
602
603	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->spur_high_id,
604	    NULL, NULL, spur_reenable, (caddr_t)softsp) != DDI_SUCCESS)
605		goto bad5;
606
607	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->spur_long_to_id,
608	    NULL, NULL, spur_clear_count, (caddr_t)softsp) != DDI_SUCCESS)
609		goto bad6;
610
611	/*
612	 * Now register low-level ac fail handler
613	 */
614	if (ddi_add_softintr(devi, DDI_SOFTINT_HIGH, &softsp->ac_fail_id,
615	    NULL, NULL, ac_fail_handler, (caddr_t)softsp) != DDI_SUCCESS)
616		goto bad7;
617
618	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->ac_fail_high_id,
619	    NULL, NULL, ac_fail_reenable, (caddr_t)softsp) != DDI_SUCCESS)
620		goto bad8;
621
622	/*
623	 * Now register low-level ps fail handler
624	 */
625
626	if (ddi_add_softintr(devi, DDI_SOFTINT_HIGH, &softsp->ps_fail_int_id,
627	    &softsp->ps_fail_c, NULL, ps_fail_int_handler, (caddr_t)softsp) !=
628	    DDI_SUCCESS)
629		goto bad9;
630
631	mutex_init(&softsp->ps_fail_lock, NULL, MUTEX_DRIVER,
632		(void *)softsp->ps_fail_c);
633
634	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->ps_fail_poll_id,
635	    NULL, NULL, ps_fail_poll_handler, (caddr_t)softsp) !=
636	    DDI_SUCCESS)
637		goto bad10;
638
639	/*
640	 * Now register low-level pps fan fail handler
641	 */
642	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->pps_fan_id,
643	    NULL, NULL, pps_fanfail_handler, (caddr_t)softsp) !=
644	    DDI_SUCCESS)
645		goto bad11;
646
647	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->pps_fan_high_id,
648	    NULL, NULL, pps_fanfail_reenable, (caddr_t)softsp) !=
649	    DDI_SUCCESS)
650		goto bad12;
651
652	/*
653	 * Based upon a check for a current share backplane, advise
654	 * that system does not support hot plug
655	 *
656	 */
657	if ((*(softsp->pppsr) & SYS_NOT_CURRENT_S) != 0) {
658		cmn_err(CE_NOTE, "Hot Plug not supported in this system");
659		sysctrl_hotplug_disabled = TRUE;
660	}
661
662	/*
663	 * If the trigger circuit is busted or the NOT_BRD_PRES line
664	 * is stuck then OBP will publish this property stating that
665	 * hot plug is not available.  If this happens we will complain
666	 * to the console and register a system fault.  We will also
667	 * not enable the board insert interrupt for this session.
668	 */
669	if (ddi_prop_op(DDI_DEV_T_ANY, softsp->dip, PROP_LEN_AND_VAL_ALLOC,
670	    DDI_PROP_DONTPASS, HOTPLUG_DISABLED_PROPERTY,
671	    (caddr_t)&propval, &proplen) == DDI_PROP_SUCCESS) {
672		cmn_err(CE_WARN, "Hot Plug Unavailable [%s]", propval);
673		reg_fault(0, FT_HOT_PLUG, FT_SYSTEM);
674		sysctrl_hotplug_disabled = TRUE;
675		enable_sys_interrupt &= ~SYS_SBRD_PRES_EN;
676		kmem_free(propval, proplen);
677	}
678
679	sysc_board_connect_supported_init();
680
681	fhc_bd_sc_register(sysc_policy_update, softsp);
682
683	sysc_slot_info(softsp->nslots, &start, &limit, &incr);
684
685	/* Prime the board list. */
686	fhc_bdlist_prime(start, limit, incr);
687
688	/*
689	 * Set up a board remove timeout call.
690	 */
691	(void) fhc_bdlist_lock(-1);
692
693	DPRINTF(SYSCTRL_ATTACH_DEBUG,
694		("attach: start bd_remove_poll()..."));
695
696	bd_remove_poll(softsp);
697	fhc_bdlist_unlock();
698
699	/*
700	 * Now register low-level board insert handler
701	 */
702	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->sbrd_pres_id,
703	    NULL, NULL, bd_insert_handler, (caddr_t)softsp) != DDI_SUCCESS)
704		goto bad13;
705
706	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->sbrd_gone_id,
707	    NULL, NULL, bd_insert_normal, (caddr_t)softsp) != DDI_SUCCESS)
708		goto bad14;
709
710	/*
711	 * Now register led blink handler (interrupt level)
712	 */
713	if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &softsp->blink_led_id,
714	    &softsp->sys_led_c, NULL, blink_led_handler, (caddr_t)softsp) !=
715	    DDI_SUCCESS)
716		goto bad15;
717	mutex_init(&softsp->sys_led_lock, NULL, MUTEX_DRIVER,
718		(void *)softsp->sys_led_c);
719
720	/* initialize the bit field for all pps fans to assumed good */
721	softsp->pps_fan_saved = softsp->pps_fan_external_state =
722		SYS_AC_FAN_OK | SYS_KEYSW_FAN_OK;
723
724	/* prime the power supply state machines */
725	if (enable_sys_interrupt & SYS_PS_FAIL_EN)
726		ddi_trigger_softintr(softsp->ps_fail_poll_id);
727
728
729	/* kick off the OS led blinker */
730	softsp->sys_led = FALSE;
731	ddi_trigger_softintr(softsp->blink_led_id);
732
733	/* Now enable selected interrupt sources */
734	mutex_enter(&softsp->csr_mutex);
735	*(softsp->csr) |= enable_sys_interrupt &
736		(SYS_AC_PWR_FAIL_EN | SYS_PS_FAIL_EN |
737		SYS_PPS_FAN_FAIL_EN | SYS_SBRD_PRES_EN);
738	tmp_reg = *(softsp->csr);
739#ifdef lint
740	tmp_reg = tmp_reg;
741#endif
742	mutex_exit(&softsp->csr_mutex);
743
744	/* Initialize the temperature */
745	init_temp_arrays(&softsp->tempstat);
746
747	/*
748	 * initialize key switch shadow state
749	 */
750	softsp->key_shadow = KEY_BOOT;
751
752	/*
753	 * Now add this soft state structure to the front of the linked list
754	 * of soft state structures.
755	 */
756	if (sys_list == (struct sysctrl_soft_state *)NULL) {
757		mutex_init(&sslist_mutex, NULL, MUTEX_DEFAULT, NULL);
758	}
759	mutex_enter(&sslist_mutex);
760	softsp->next = sys_list;
761	sys_list = softsp;
762	mutex_exit(&sslist_mutex);
763
764	/* Setup the kstats for this device */
765	sysctrl_add_kstats(softsp);
766
767	/* kick off the PPS fan poll routine */
768	pps_fan_poll(softsp);
769
770	if (sysctrl_overtemp_thread_started == 0) {
771		/*
772		 * set up the overtemp condition variable before
773		 * starting the thread.
774		 */
775		cv_init(&overtemp_cv, NULL, CV_DRIVER, NULL);
776
777		/*
778		 * start up the overtemp polling thread
779		 */
780		(void) thread_create(NULL, 0, (void (*)())sysctrl_overtemp_poll,
781		    NULL, 0, &p0, TS_RUN, minclsyspri);
782		sysctrl_overtemp_thread_started++;
783	}
784
785	if (sysctrl_keyswitch_thread_started == 0) {
786		extern void (*abort_seq_handler)();
787
788		/*
789		 * interpose sysctrl's abort sequence handler
790		 */
791		abort_seq_handler = sysctrl_abort_seq_handler;
792
793		/*
794		 * set up the key switch condition variable before
795		 * starting the thread
796		 */
797		cv_init(&keyswitch_cv, NULL, CV_DRIVER, NULL);
798
799		/*
800		 * start up the key switch polling thread
801		 */
802		(void) thread_create(NULL, 0,
803		    (void (*)())sysctrl_keyswitch_poll, NULL, 0, &p0,
804		    TS_RUN, minclsyspri);
805		sysctrl_keyswitch_thread_started++;
806	}
807
808	/*
809	 * perform initialization to allow setting of powerfail-time
810	 */
811	if ((dip = ddi_find_devinfo("options", -1, 0)) == NULL)
812		softsp->options_nodeid = (pnode_t)NULL;
813	else
814		softsp->options_nodeid = (pnode_t)ddi_get_nodeid(dip);
815
816	DPRINTF(SYSCTRL_ATTACH_DEBUG,
817		("sysctrl: Creating devices start:%d, limit:%d, incr:%d\n",
818		start, limit, incr));
819
820	/*
821	 * Create minor node for each system attachment points
822	 */
823	for (slot_num = start; slot_num < limit; slot_num = slot_num + incr) {
824		char name[30];
825		(void) sprintf(name, "slot%d", slot_num);
826		if (ddi_create_minor_node(devi, name, S_IFCHR,
827		    (PUTINSTANCE(instance) | slot_num),
828		    DDI_NT_ATTACHMENT_POINT, 0) == DDI_FAILURE) {
829			cmn_err(CE_WARN, "sysctrl%d: \"%s\" "
830				"ddi_create_minor_node failed",
831				instance, name);
832			goto bad16;
833		}
834	}
835
836	ddi_report_dev(devi);
837
838	/*
839	 * Remote console is inherited from POST
840	 */
841	if ((*(softsp->clk_freq2) & RCONS_UART_EN) == 0) {
842		softsp->enable_rcons_atboot = FALSE;
843		cmn_err(CE_WARN, "Remote console not active");
844	} else
845		softsp->enable_rcons_atboot = TRUE;
846
847	return (DDI_SUCCESS);
848
849bad16:
850	cv_destroy(&keyswitch_cv);
851	cv_destroy(&overtemp_cv);
852	mutex_destroy(&sslist_mutex);
853	mutex_destroy(&softsp->sys_led_lock);
854	ddi_remove_softintr(softsp->blink_led_id);
855bad15:
856	ddi_remove_softintr(softsp->sbrd_gone_id);
857bad14:
858	ddi_remove_softintr(softsp->sbrd_pres_id);
859bad13:
860	ddi_remove_softintr(softsp->pps_fan_high_id);
861bad12:
862	ddi_remove_softintr(softsp->pps_fan_id);
863bad11:
864	ddi_remove_softintr(softsp->ps_fail_poll_id);
865bad10:
866	mutex_destroy(&softsp->ps_fail_lock);
867	ddi_remove_softintr(softsp->ps_fail_int_id);
868bad9:
869	ddi_remove_softintr(softsp->ac_fail_high_id);
870bad8:
871	ddi_remove_softintr(softsp->ac_fail_id);
872bad7:
873	ddi_remove_softintr(softsp->spur_long_to_id);
874bad6:
875	ddi_remove_softintr(softsp->spur_high_id);
876bad5:
877	mutex_destroy(&softsp->spur_int_lock);
878	ddi_remove_softintr(softsp->spur_id);
879bad4:
880	ddi_remove_intr(devi, 0, softsp->iblock);
881bad3:
882	mutex_destroy(&softsp->csr_mutex);
883bad2:
884	ddi_unmap_regs(softsp->dip, 1, (caddr_t *)&softsp->csr, 0, 0);
885	if (softsp->clk_ver != NULL)
886		ddi_unmap_regs(softsp->dip, 2, (caddr_t *)&softsp->clk_ver,
887		    0, 0);
888bad1:
889	ddi_unmap_regs(softsp->dip, 0, (caddr_t *)&softsp->clk_freq1, 0, 0);
890
891bad0:
892	ddi_soft_state_free(sysctrlp, instance);
893	ddi_remove_minor_node(dip, NULL);
894	cmn_err(CE_WARN,
895	    "sysctrl%d: Initialization failure. Some system level events,"
896	    " {AC Fail, Fan Failure, PS Failure} not detected", instance);
897	return (DDI_FAILURE);
898}
899
900struct sysc_hold {
901	int start;
902	int limit;
903	int incr;
904	int hold;
905};
906
907static int
908sysctrl_hold_rele_branches(dev_info_t *dip, void *arg)
909{
910	int *rp, len, slot, i;
911	struct sysc_hold *ap = (struct sysc_hold *)arg;
912
913	/*
914	 * For Sunfire, top nodes on board are always children of root dip
915	 */
916	ASSERT(ddi_get_parent(dip) == ddi_root_node());
917
918	/*
919	 * Skip non-PROM and "central" nodes
920	 */
921	if (!ndi_dev_is_prom_node(dip) ||
922	    strcmp(ddi_node_name(dip), "central") == 0)
923		return (DDI_WALK_PRUNECHILD);
924
925	/*
926	 * Extract board # from reg property.
927	 */
928	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
929	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "reg", (caddr_t)&rp, &len)
930	    != DDI_SUCCESS) {
931		DPRINTF(SYSC_DEBUG, ("devinfo node %s(%p) has no reg"
932		    " property\n", ddi_node_name(dip), (void *)dip));
933		return (DDI_WALK_PRUNECHILD);
934	}
935
936	slot = (*rp - 0x1c0) >> 2;
937	kmem_free(rp, len);
938
939	ASSERT(ap->start >= 0 && ap->start < ap->limit);
940
941	for (i = ap->start; i < ap->limit; i = i + ap->incr) {
942		if (i == slot)
943			break;
944	}
945
946	if (i >= ap->limit) {
947		DPRINTF(SYSC_DEBUG, ("sysctrl_hold_rele: Invalid board # (%d)"
948		    " for node %s(%p)\n", slot, ddi_node_name(dip),
949		    (void *)dip));
950		return (DDI_WALK_PRUNECHILD);
951	}
952
953	if (ap->hold) {
954		ASSERT(!e_ddi_branch_held(dip));
955		e_ddi_branch_hold(dip);
956	} else {
957		ASSERT(e_ddi_branch_held(dip));
958		e_ddi_branch_rele(dip);
959	}
960
961	return (DDI_WALK_PRUNECHILD);
962}
963
964/* ARGSUSED */
965static int
966sysctrl_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
967{
968#ifdef	SYSCTRL_SUPPORTS_DETACH
969	dev_info_t			*rdip;
970	struct sysc_hold		arg = {0};
971	struct sysctrl_soft_state	*softsp;
972#endif	/* SYSCTRL_SUPPORTS_DETACH */
973
974	if (sysctrl_enable_detach_suspend == FALSE)
975		return (DDI_FAILURE);
976
977	switch (cmd) {
978	case DDI_SUSPEND:
979		/*
980		 * XXX we don't presently save the state of the remote
981		 * console because it is a constant function of POST.
982		 * XXX we don't deal with the hardware watchdog here
983		 * either.  It should be handled in hardclk.
984		 */
985		return (DDI_SUCCESS);
986
987	case DDI_DETACH:
988		break;
989	default:
990		return (DDI_FAILURE);
991	}
992
993#ifdef	SYSCTRL_SUPPORTS_DETACH
994
995	/*
996	 * XXX If sysctrl ever supports detach, this code should be enabled
997	 * This is only the portion of the detach code dealing with
998	 * the DDI branch routines. Other parts of detach will need
999	 * to be added.
1000	 */
1001
1002	/*
1003	 * Walk immediate children of root devinfo node, releasing holds
1004	 * on branches acquired in first sysctrl_open().
1005	 */
1006
1007	instance = ddi_get_instance(dip);
1008	softsp = GETSOFTC(instance);
1009
1010	if (softsp == NULL) {
1011		cmn_err(CE_WARN, "sysctrl%d device not attached", instance);
1012		return (DDI_FAILURE);
1013	}
1014
1015	sysc_slot_info(softsp->nslots, &arg.start, &arg.limit, &arg.incr);
1016
1017	arg.hold = 0;
1018
1019	rdip = ddi_root_node();
1020
1021	ndi_devi_enter(rdip, &circ);
1022	ddi_walk_devs(ddi_get_child(rdip), sysctrl_hold_rele_branches, &arg);
1023	ndi_devi_exit(rdip, circ);
1024
1025	sysctrl_ddi_branch_init = 0;
1026
1027	return (DDI_SUCCESS);
1028#endif	/* SYSCTRL_SUPPORTS_DETACH */
1029
1030	return (DDI_FAILURE);
1031}
1032
1033/* ARGSUSED */
1034static int
1035sysctrl_open(dev_t *devp, int flag, int otyp, cred_t *credp)
1036{
1037	int		instance;
1038	int		slot;
1039	dev_t		dev;
1040	int		circ;
1041	dev_info_t	*rdip;
1042	struct sysc_hold arg = {0};
1043	struct sysctrl_soft_state *softsp;
1044
1045	dev = *devp;
1046
1047	/*
1048	 * We checked against the instance softstate structure since there
1049	 * will only be one instance of sysctrl (clock board) in UEXX00
1050	 *
1051	 * Since we only create minor devices for existing slots on a
1052	 * particular system, we don't need to worry about non-exist slot.
1053	 */
1054
1055	instance = GETINSTANCE(dev);
1056	slot = GETSLOT(dev);
1057
1058	/* Is the instance attached? */
1059	if ((softsp = GETSOFTC(instance)) == NULL) {
1060		cmn_err(CE_WARN, "sysctrl%d device not attached", instance);
1061		return (ENXIO);
1062	}
1063
1064	/* verify that otyp is appropriate */
1065	if (otyp != OTYP_CHR) {
1066		return (EINVAL);
1067	}
1068
1069	if (!fhc_bd_valid(slot))
1070		return (ENXIO);
1071
1072	/*
1073	 * On first open of a sysctrl minor walk immediate children of the
1074	 * devinfo root node and hold all branches of interest.
1075	 */
1076	mutex_enter(&sysctrl_branch_mutex);
1077	if (!sysctrl_ddi_branch_init) {
1078
1079		sysctrl_ddi_branch_init = 1;
1080
1081		sysc_slot_info(softsp->nslots, &arg.start, &arg.limit,
1082		    &arg.incr);
1083		arg.hold = 1;
1084
1085		rdip = ddi_root_node();
1086
1087		ndi_devi_enter(rdip, &circ);
1088		ddi_walk_devs(ddi_get_child(rdip), sysctrl_hold_rele_branches,
1089		    &arg);
1090		ndi_devi_exit(rdip, circ);
1091	}
1092	mutex_exit(&sysctrl_branch_mutex);
1093
1094	return (DDI_SUCCESS);
1095}
1096
1097/* ARGSUSED */
1098static int
1099sysctrl_close(dev_t devp, int flag, int otyp, cred_t *credp)
1100{
1101	return (DDI_SUCCESS);
1102}
1103
1104/*
1105 * This function will acquire the lock and set the in_transition
1106 * bit for the specified slot.  If the slot is being used,
1107 * we return FALSE; else set in_transition and return TRUE.
1108 */
1109static int
1110sysc_enter_transition(int slot)
1111{
1112	fhc_bd_t	*list;
1113	sysc_cfga_stat_t *sysc_stat_lk;
1114	fhc_bd_t	*glist;
1115	sysc_cfga_stat_t *sysc_stat_gk;
1116
1117	/* mutex lock the structure */
1118	list = fhc_bdlist_lock(slot);
1119	if ((slot != -1) && (list == NULL)) {
1120		fhc_bdlist_unlock();
1121		return (FALSE);
1122	}
1123
1124	glist = fhc_bd_clock();
1125	if (slot == -1)
1126		list = glist;
1127
1128	/* change the in_transition bit */
1129	sysc_stat_lk = &list->sc;
1130	sysc_stat_gk = &glist->sc;
1131	if ((sysc_stat_lk->in_transition == TRUE) ||
1132	    (sysc_stat_gk->in_transition == TRUE)) {
1133		fhc_bdlist_unlock();
1134		return (FALSE);
1135	} else {
1136		sysc_stat_lk->in_transition = TRUE;
1137		return (TRUE);
1138	}
1139}
1140
1141/*
1142 * This function will release the lock and clear the in_transition
1143 * bit for the specified slot.
1144 */
1145static void
1146sysc_exit_transition(int slot)
1147{
1148	fhc_bd_t	*list;
1149	sysc_cfga_stat_t *sysc_stat_lk;
1150
1151	ASSERT(fhc_bdlist_locked());
1152
1153	if (slot == -1)
1154		list = fhc_bd_clock();
1155	else
1156		list = fhc_bd(slot);
1157	sysc_stat_lk = &list->sc;
1158	ASSERT(sysc_stat_lk->in_transition == TRUE);
1159	sysc_stat_lk->in_transition = FALSE;
1160	fhc_bdlist_unlock();
1161}
1162
1163static int
1164sysc_pkt_init(sysc_cfga_pkt_t *pkt, intptr_t arg, int flag)
1165{
1166#ifdef _MULTI_DATAMODEL
1167	if (ddi_model_convert_from(flag & FMODELS) == DDI_MODEL_ILP32) {
1168		sysc_cfga_cmd32_t sysc_cmd32;
1169
1170		if (ddi_copyin((void *)arg, &sysc_cmd32,
1171			sizeof (sysc_cfga_cmd32_t), flag) != 0) {
1172			return (EFAULT);
1173		}
1174		pkt->cmd_cfga.force = sysc_cmd32.force;
1175		pkt->cmd_cfga.test = sysc_cmd32.test;
1176		pkt->cmd_cfga.arg = sysc_cmd32.arg;
1177		pkt->cmd_cfga.errtype = sysc_cmd32.errtype;
1178		pkt->cmd_cfga.outputstr =
1179			(char *)(uintptr_t)sysc_cmd32.outputstr;
1180	} else
1181#endif /* _MULTI_DATAMODEL */
1182	if (ddi_copyin((void *)arg, &(pkt->cmd_cfga),
1183		sizeof (sysc_cfga_cmd_t), flag) != 0) {
1184		return (EFAULT);
1185	}
1186	pkt->errbuf = kmem_zalloc(SYSC_OUTPUT_LEN, KM_SLEEP);
1187	return (0);
1188}
1189
1190static int
1191sysc_pkt_fini(sysc_cfga_pkt_t *pkt, intptr_t arg, int flag)
1192{
1193	int ret = TRUE;
1194
1195#ifdef _MULTI_DATAMODEL
1196	if (ddi_model_convert_from(flag & FMODELS) == DDI_MODEL_ILP32) {
1197
1198		if (ddi_copyout(&(pkt->cmd_cfga.errtype),
1199			(void *)&(((sysc_cfga_cmd32_t *)arg)->errtype),
1200			sizeof (sysc_err_t), flag) != 0) {
1201			ret = FALSE;
1202		}
1203	} else
1204#endif
1205	if (ddi_copyout(&(pkt->cmd_cfga.errtype),
1206		(void *)&(((sysc_cfga_cmd_t *)arg)->errtype),
1207		sizeof (sysc_err_t), flag) != 0) {
1208		ret = FALSE;
1209	}
1210
1211	if ((ret != FALSE) && ((pkt->cmd_cfga.outputstr != NULL) &&
1212		(ddi_copyout(pkt->errbuf, pkt->cmd_cfga.outputstr,
1213			SYSC_OUTPUT_LEN, flag) != 0))) {
1214			ret = FALSE;
1215	}
1216
1217	kmem_free(pkt->errbuf, SYSC_OUTPUT_LEN);
1218	return (ret);
1219}
1220
1221/* ARGSUSED */
1222static int
1223sysctrl_ioctl(dev_t devt, int cmd, intptr_t arg, int flag, cred_t *cred_p,
1224		int *rval_p)
1225{
1226	struct sysctrl_soft_state *softsp;
1227	sysc_cfga_pkt_t sysc_pkt;
1228	fhc_bd_t *fhc_list = NULL;
1229	sysc_cfga_stat_t *sc_list = NULL;
1230	fhc_bd_t *bdp;
1231	sysc_cfga_stat_t *sc = NULL;
1232	int instance;
1233	int slot;
1234	int retval = 0;
1235	int i;
1236
1237	instance = GETINSTANCE(devt);
1238	softsp = GETSOFTC(instance);
1239	if (softsp == NULL) {
1240		cmn_err(CE_CONT,
1241			"sysctrl_ioctl(%d): NULL softstate ptr!\n",
1242			(int)GETSLOT(devt));
1243		return (ENXIO);
1244	}
1245
1246	slot = GETSLOT(devt);
1247
1248	/*
1249	 * First switch is to do correct locking and do ddi_copyin()
1250	 */
1251	switch (cmd) {
1252	case SYSC_CFGA_CMD_GETSTATUS:
1253		/* mutex lock the whole list */
1254		if (sysc_enter_transition(-1) != TRUE) {
1255			retval = EBUSY;
1256			goto cleanup_exit;
1257		}
1258
1259		/* allocate the memory before acquiring mutex */
1260		fhc_list = kmem_zalloc(sizeof (fhc_bd_t) * fhc_max_boards(),
1261		    KM_SLEEP);
1262
1263		sc_list = kmem_zalloc(sizeof (sysc_cfga_stat_t) *
1264		    fhc_max_boards(), KM_SLEEP);
1265
1266		break;
1267
1268	case SYSC_CFGA_CMD_EJECT:
1269	case SYSC_CFGA_CMD_INSERT:
1270		retval = ENOTSUP;
1271		goto cleanup_exit;
1272
1273	case SYSC_CFGA_CMD_CONNECT:
1274	case SYSC_CFGA_CMD_DISCONNECT:
1275	case SYSC_CFGA_CMD_UNCONFIGURE:
1276	case SYSC_CFGA_CMD_CONFIGURE:
1277	case SYSC_CFGA_CMD_TEST:
1278	case SYSC_CFGA_CMD_TEST_SET_COND:
1279	case SYSC_CFGA_CMD_QUIESCE_TEST:
1280
1281		/* ioctls allowed if caller has write permission */
1282		if (!(flag & FWRITE)) {
1283			retval = EPERM;
1284			goto cleanup_exit;
1285		}
1286
1287		retval = sysc_pkt_init(&sysc_pkt, arg, flag);
1288		if (retval != 0)
1289			goto cleanup_exit;
1290
1291		/* grasp lock and set in_transition bit */
1292		if (sysc_enter_transition(cmd == SYSC_CFGA_CMD_QUIESCE_TEST
1293				? -1 : slot) != TRUE) {
1294			retval = EBUSY;
1295			SYSC_ERR_SET(&sysc_pkt, SYSC_ERR_INTRANS);
1296			goto cleanup_copyout;
1297		}
1298
1299		/* get the status structure for the slot */
1300		bdp = fhc_bd(slot);
1301		sc = &bdp->sc;
1302		break;
1303
1304	/* POSIX definition: return ENOTTY if unsupported command */
1305	default:
1306		retval = ENOTTY;
1307		goto cleanup_exit;
1308	}
1309
1310	/*
1311	 * Second switch is to call the underlayer workhorse.
1312	 */
1313	switch (cmd) {
1314	case SYSC_CFGA_CMD_GETSTATUS:
1315		for (i = 0; i < fhc_max_boards(); i++) {
1316			if (fhc_bd_valid(i)) {
1317				bdp = fhc_bd(i);
1318				if (fhc_bd_is_jtag_master(i))
1319					bdp->sc.no_detach = 1;
1320				else
1321					bdp->sc.no_detach = 0;
1322				bcopy((caddr_t)&bdp->sc,
1323					&sc_list[i], sizeof (sysc_cfga_stat_t));
1324			} else {
1325				sc_list[i].board = -1;
1326				sc_list[i].rstate = SYSC_CFGA_RSTATE_EMPTY;
1327			}
1328		}
1329
1330		sysc_exit_transition(-1);
1331
1332		break;
1333
1334	case SYSC_CFGA_CMD_EJECT:
1335	case SYSC_CFGA_CMD_INSERT:
1336		retval = ENOTSUP;
1337		goto cleanup_exit;
1338
1339	case SYSC_CFGA_CMD_CONNECT:
1340		retval = sysc_policy_connect(softsp, &sysc_pkt, sc);
1341		sysc_exit_transition(slot);
1342		break;
1343
1344	case SYSC_CFGA_CMD_DISCONNECT:
1345		retval = sysc_policy_disconnect(softsp, &sysc_pkt, sc);
1346		sysc_exit_transition(slot);
1347		break;
1348
1349	case SYSC_CFGA_CMD_UNCONFIGURE:
1350		retval = sysc_policy_unconfigure(softsp, &sysc_pkt, sc);
1351		sysc_exit_transition(slot);
1352		break;
1353
1354	case SYSC_CFGA_CMD_CONFIGURE:
1355		retval = sysc_policy_configure(softsp, &sysc_pkt, sc);
1356		sysc_exit_transition(slot);
1357		break;
1358
1359	case SYSC_CFGA_CMD_TEST:
1360		retval = fhc_bd_test(slot, &sysc_pkt);
1361		sysc_exit_transition(slot);
1362		break;
1363
1364	case SYSC_CFGA_CMD_TEST_SET_COND:
1365		retval = fhc_bd_test_set_cond(slot, &sysc_pkt);
1366		sysc_exit_transition(slot);
1367		break;
1368
1369	case SYSC_CFGA_CMD_QUIESCE_TEST:
1370		sysctrl_suspend_prepare();
1371		fhc_bdlist_unlock();
1372
1373		if (sysctrl_suspend(&sysc_pkt) == DDI_SUCCESS) {
1374			sysctrl_resume(&sysc_pkt);
1375		} else {
1376			retval = EBUSY;
1377		}
1378
1379		(void) fhc_bdlist_lock(-1);
1380		sysc_exit_transition(-1);
1381		break;
1382
1383	default:
1384		retval = ENOTTY;
1385		goto cleanup_exit;
1386	}
1387
1388cleanup_copyout:
1389	/*
1390	 * 3rd switch is to do appropriate copyout and reset locks
1391	 */
1392	switch (cmd) {
1393	case SYSC_CFGA_CMD_GETSTATUS:
1394		if (ddi_copyout(sc_list, (void *)arg,
1395			sizeof (sysc_cfga_stat_t) * fhc_max_boards(),
1396			    flag) != 0) {
1397			retval = EFAULT;
1398		}
1399
1400		/* cleanup memory */
1401		kmem_free(fhc_list, sizeof (fhc_bd_t) * fhc_max_boards());
1402		kmem_free(sc_list, sizeof (sysc_cfga_stat_t) *
1403		    fhc_max_boards());
1404		break;
1405
1406	case SYSC_CFGA_CMD_EJECT:
1407	case SYSC_CFGA_CMD_INSERT:
1408		retval = ENOTSUP;
1409		break;
1410
1411	case SYSC_CFGA_CMD_CONNECT:
1412	case SYSC_CFGA_CMD_DISCONNECT:
1413	case SYSC_CFGA_CMD_UNCONFIGURE:
1414	case SYSC_CFGA_CMD_CONFIGURE:
1415	case SYSC_CFGA_CMD_TEST:
1416	case SYSC_CFGA_CMD_TEST_SET_COND:
1417	case SYSC_CFGA_CMD_QUIESCE_TEST:
1418		if (sysc_pkt_fini(&sysc_pkt, arg, flag) != TRUE)
1419			return (EFAULT);
1420		break;
1421
1422	default:
1423		retval = ENOTTY;
1424		break;
1425	}
1426
1427cleanup_exit:
1428	return (retval);
1429}
1430
1431/*
1432 * system_high_handler()
1433 * This routine handles system interrupts.
1434 *
1435 * This routine goes through all the interrupt sources and masks
1436 * off the enable bit if interrupting.  Because of the special
1437 * nature of the pps fan source bits, we also cache the state
1438 * of the fan bits for that special case.
1439 *
1440 * The rest of the work is done in the low level handlers
1441 */
1442static uint_t
1443system_high_handler(caddr_t arg)
1444{
1445	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
1446	uchar_t csr;
1447	uchar_t status2;
1448	uchar_t tmp_reg;
1449	int serviced = 0;
1450
1451	ASSERT(softsp);
1452
1453	mutex_enter(&softsp->csr_mutex);
1454
1455	/* read in the hardware registers */
1456	csr = *(softsp->csr);
1457	status2 = *(softsp->status2);
1458
1459	if (csr & SYS_AC_PWR_FAIL_EN) {
1460		if (status2 & SYS_AC_FAIL) {
1461
1462			/* save the powerfail state in nvram */
1463			nvram_update_powerfail(softsp);
1464
1465			/* disable this interrupt source */
1466			csr &= ~SYS_AC_PWR_FAIL_EN;
1467
1468			ddi_trigger_softintr(softsp->ac_fail_id);
1469			serviced++;
1470		}
1471	}
1472
1473	if (csr & SYS_PS_FAIL_EN) {
1474		if ((*(softsp->ps_stat) != 0xff) ||
1475		    ((~status2) & (SYS_PPS0_OK | SYS_CLK_33_OK |
1476			SYS_CLK_50_OK)) ||
1477		    (~(*(softsp->pppsr)) & SYS_PPPSR_BITS)) {
1478
1479			/* disable this interrupt source */
1480			csr &= ~SYS_PS_FAIL_EN;
1481
1482			ddi_trigger_softintr(softsp->ps_fail_int_id);
1483			serviced++;
1484		}
1485	}
1486
1487	if (csr & SYS_PPS_FAN_FAIL_EN) {
1488		if (status2 & SYS_RACK_FANFAIL ||
1489		    !(status2 & SYS_AC_FAN_OK) ||
1490		    !(status2 & SYS_KEYSW_FAN_OK)) {
1491
1492			/*
1493			 * we must cache the fan status because it goes
1494			 * away when we disable interrupts !?!?!
1495			 */
1496			softsp->pps_fan_saved = status2;
1497
1498			/* disable this interrupt source */
1499			csr &= ~SYS_PPS_FAN_FAIL_EN;
1500
1501			ddi_trigger_softintr(softsp->pps_fan_id);
1502			serviced++;
1503		}
1504	}
1505
1506	if (csr & SYS_SBRD_PRES_EN) {
1507		if (!(*(softsp->status1) & SYS_NOT_BRD_PRES)) {
1508
1509			/* disable this interrupt source */
1510			csr &= ~SYS_SBRD_PRES_EN;
1511
1512			ddi_trigger_softintr(softsp->sbrd_pres_id);
1513			serviced++;
1514		}
1515	}
1516
1517	if (!serviced) {
1518
1519		/*
1520		 * if we get here than it is likely that contact bounce
1521		 * is messing with us.  so, we need to shut this interrupt
1522		 * up for a while to let the contacts settle down.
1523		 * Then we will re-enable the interrupts that are enabled
1524		 * right now.  The trick is to disable the appropriate
1525		 * interrupts and then to re-enable them correctly, even
1526		 * though intervening handlers might have been working.
1527		 */
1528
1529		/* remember all interrupts that could have caused it */
1530		softsp->saved_en_state |= csr &
1531		    (SYS_AC_PWR_FAIL_EN | SYS_PS_FAIL_EN |
1532		    SYS_PPS_FAN_FAIL_EN | SYS_SBRD_PRES_EN);
1533
1534		/* and then turn them off */
1535		csr &= ~(SYS_AC_PWR_FAIL_EN | SYS_PS_FAIL_EN |
1536			SYS_PPS_FAN_FAIL_EN | SYS_SBRD_PRES_EN);
1537
1538		/* and then bump the counter */
1539		softsp->spur_count++;
1540
1541		/* and kick off the timeout */
1542		ddi_trigger_softintr(softsp->spur_id);
1543	}
1544
1545	/* update the real csr */
1546	*(softsp->csr) = csr;
1547	tmp_reg = *(softsp->csr);
1548#ifdef lint
1549	tmp_reg = tmp_reg;
1550#endif
1551	mutex_exit(&softsp->csr_mutex);
1552
1553	return (DDI_INTR_CLAIMED);
1554}
1555
1556/*
1557 * we've detected a spurious interrupt.
1558 * determine if we should log a message and if we need another timeout
1559 */
1560static uint_t
1561spur_delay(caddr_t arg)
1562{
1563	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
1564
1565	ASSERT(softsp);
1566
1567	/* do we need to complain? */
1568	mutex_enter(&softsp->csr_mutex);
1569
1570	/* NOTE: this is == because we want one message per long timeout */
1571	if (softsp->spur_count == MAX_SPUR_COUNT) {
1572		char buf[128];
1573
1574		/* print out the candidates known at this time */
1575		/* XXX not perfect because of re-entrant nature but close */
1576		buf[0] = '\0';
1577		if (softsp->saved_en_state & SYS_AC_PWR_FAIL_EN)
1578			(void) strcat(buf, "AC FAIL");
1579		if (softsp->saved_en_state & SYS_PPS_FAN_FAIL_EN)
1580			(void) strcat(buf, buf[0] ? "|PPS FANS" : "PPS FANS");
1581		if (softsp->saved_en_state & SYS_PS_FAIL_EN)
1582			(void) strcat(buf, buf[0] ? "|PS FAIL" : "PS FAIL");
1583		if (softsp->saved_en_state & SYS_SBRD_PRES_EN)
1584			(void) strcat(buf,
1585				buf[0] ? "|BOARD INSERT" : "BOARD INSERT");
1586
1587		/*
1588		 * This is a high level mutex, therefore it needs to be
1589		 * dropped before calling cmn_err.
1590		 */
1591		mutex_exit(&softsp->csr_mutex);
1592
1593		cmn_err(CE_WARN, "sysctrl%d: unserviced interrupt."
1594				" possible sources [%s].",
1595				ddi_get_instance(softsp->dip), buf);
1596	} else
1597		mutex_exit(&softsp->csr_mutex);
1598
1599	mutex_enter(&softsp->spur_int_lock);
1600
1601	/* do we need to start the short timeout? */
1602	if (softsp->spur_timeout_id == 0) {
1603		softsp->spur_timeout_id = timeout(spur_retry, softsp,
1604		    spur_timeout_hz);
1605	}
1606
1607	/* do we need to start the long timeout? */
1608	if (softsp->spur_long_timeout_id == 0) {
1609		softsp->spur_long_timeout_id = timeout(spur_long_timeout,
1610		    softsp, spur_long_timeout_hz);
1611	}
1612
1613	mutex_exit(&softsp->spur_int_lock);
1614
1615	return (DDI_INTR_CLAIMED);
1616}
1617
1618/*
1619 * spur_retry
1620 *
1621 * this routine simply triggers the interrupt which will re-enable
1622 * the interrupts disabled by the spurious int detection.
1623 */
1624static void
1625spur_retry(void *arg)
1626{
1627	struct sysctrl_soft_state *softsp = arg;
1628
1629	ASSERT(softsp);
1630
1631	ddi_trigger_softintr(softsp->spur_high_id);
1632
1633	mutex_enter(&softsp->spur_int_lock);
1634	softsp->spur_timeout_id = 0;
1635	mutex_exit(&softsp->spur_int_lock);
1636}
1637
1638/*
1639 * spur_reenable
1640 *
1641 * OK, we've been slient for a while.   Go ahead and re-enable the
1642 * interrupts that were enabled at the time of the spurious detection.
1643 */
1644static uint_t
1645spur_reenable(caddr_t arg)
1646{
1647	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
1648	uchar_t tmp_reg;
1649
1650	ASSERT(softsp);
1651
1652	mutex_enter(&softsp->csr_mutex);
1653
1654	/* reenable those who were spurious candidates */
1655	*(softsp->csr) |= softsp->saved_en_state &
1656		(SYS_AC_PWR_FAIL_EN | SYS_PS_FAIL_EN |
1657		SYS_PPS_FAN_FAIL_EN | SYS_SBRD_PRES_EN);
1658	tmp_reg = *(softsp->csr);
1659#ifdef lint
1660	tmp_reg = tmp_reg;
1661#endif
1662
1663	/* clear out the saved state */
1664	softsp->saved_en_state = 0;
1665
1666	mutex_exit(&softsp->csr_mutex);
1667
1668	return (DDI_INTR_CLAIMED);
1669}
1670
1671/*
1672 * spur_long_timeout
1673 *
1674 * this routine merely resets the spurious interrupt counter thus ending
1675 * the interval of interest.  of course this is done by triggering a
1676 * softint because the counter is protected by an interrupt mutex.
1677 */
1678static void
1679spur_long_timeout(void *arg)
1680{
1681	struct sysctrl_soft_state *softsp = arg;
1682
1683	ASSERT(softsp);
1684
1685	ddi_trigger_softintr(softsp->spur_long_to_id);
1686
1687	mutex_enter(&softsp->spur_int_lock);
1688	softsp->spur_long_timeout_id = 0;
1689	mutex_exit(&softsp->spur_int_lock);
1690}
1691
1692/*
1693 * spur_clear_count
1694 *
1695 * simply clear out the spurious interrupt counter.
1696 *
1697 * softint level only
1698 */
1699static uint_t
1700spur_clear_count(caddr_t arg)
1701{
1702	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
1703
1704	ASSERT(softsp);
1705
1706	mutex_enter(&softsp->csr_mutex);
1707	softsp->spur_count = 0;
1708	mutex_exit(&softsp->csr_mutex);
1709
1710	return (DDI_INTR_CLAIMED);
1711}
1712
1713/*
1714 * ac_fail_handler
1715 *
1716 * This routine polls the AC power failure bit in the system status2
1717 * register.  If we get to this routine, then we sensed an ac fail
1718 * condition.  Note the fact and check again in a few.
1719 *
1720 * Called as softint from high interrupt.
1721 */
1722static uint_t
1723ac_fail_handler(caddr_t arg)
1724{
1725	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
1726
1727	ASSERT(softsp);
1728
1729	cmn_err(CE_WARN, "%s failure detected", ft_str_table[FT_AC_PWR]);
1730	reg_fault(0, FT_AC_PWR, FT_SYSTEM);
1731	(void) timeout(ac_fail_retry, softsp, ac_timeout_hz);
1732
1733	return (DDI_INTR_CLAIMED);
1734}
1735
1736/*
1737 * The timeout from ac_fail_handler() that checks to see if the
1738 * condition persists.
1739 */
1740static void
1741ac_fail_retry(void *arg)
1742{
1743	struct sysctrl_soft_state *softsp = arg;
1744
1745	ASSERT(softsp);
1746
1747	if (*softsp->status2 & SYS_AC_FAIL) {	/* still bad? */
1748		(void) timeout(ac_fail_retry, softsp, ac_timeout_hz);
1749	} else {
1750		cmn_err(CE_NOTE, "%s failure no longer detected",
1751			ft_str_table[FT_AC_PWR]);
1752		clear_fault(0, FT_AC_PWR, FT_SYSTEM);
1753		ddi_trigger_softintr(softsp->ac_fail_high_id);
1754	}
1755}
1756
1757/*
1758 * The interrupt routine that we use to re-enable the interrupt.
1759 * Called from ddi_trigger_softint() in the ac_fail_retry() when
1760 * the AC is better.
1761 */
1762static uint_t
1763ac_fail_reenable(caddr_t arg)
1764{
1765	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
1766	uchar_t tmp_reg;
1767
1768	ASSERT(softsp);
1769
1770	mutex_enter(&softsp->csr_mutex);
1771	*(softsp->csr) |= SYS_AC_PWR_FAIL_EN;
1772	tmp_reg = *(softsp->csr);
1773#ifdef lint
1774	tmp_reg = tmp_reg;
1775#endif
1776	mutex_exit(&softsp->csr_mutex);
1777
1778	return (DDI_INTR_CLAIMED);
1779}
1780
1781/*
1782 * ps_fail_int_handler
1783 *
1784 * Handle power supply failure interrupt.
1785 *
1786 * This wrapper is called as softint from hardware interrupt routine.
1787 */
1788static uint_t
1789ps_fail_int_handler(caddr_t arg)
1790{
1791	return (ps_fail_handler((struct sysctrl_soft_state *)arg, 1));
1792}
1793
1794/*
1795 * ps_fail_poll_handler
1796 *
1797 * Handle power supply failure interrupt.
1798 *
1799 * This wrapper is called as softint from power supply poll routine.
1800 */
1801static uint_t
1802ps_fail_poll_handler(caddr_t arg)
1803{
1804	return (ps_fail_handler((struct sysctrl_soft_state *)arg, 0));
1805}
1806
1807/*
1808 * ps_fail_handler
1809 *
1810 * This routine checks all eight of the board power supplies that are
1811 * installed plus the Peripheral power supply and the two DC OK. Since the
1812 * hardware bits are not enough to indicate Power Supply failure
1813 * vs. being turned off via software, the driver must maintain a
1814 * shadow state for the Power Supply status and monitor all changes.
1815 *
1816 * Called as a softint only.
1817 */
1818static uint_t
1819ps_fail_handler(struct sysctrl_soft_state *softsp, int fromint)
1820{
1821	int i;
1822	struct ps_state *pstatp;
1823	int poll_needed = 0;
1824	uchar_t ps_stat, ps_pres, status1, status2, pppsr;
1825	uchar_t tmp_reg;
1826	enum power_state current_power_state;
1827
1828	ASSERT(softsp);
1829
1830	/* pre-read the hardware state */
1831	ps_stat = *softsp->ps_stat;
1832	ps_pres = *softsp->ps_pres;
1833	status1 = *softsp->status1;
1834	status2 = *softsp->status2;
1835	pppsr	= *softsp->pppsr;
1836
1837	(void) fhc_bdlist_lock(-1);
1838
1839	mutex_enter(&softsp->ps_fail_lock);
1840
1841	for (i = 0, pstatp = &softsp->ps_stats[0]; i < SYS_PS_COUNT;
1842	    i++, pstatp++) {
1843		int	temp_psok;
1844		int	temp_pres;
1845		int	is_precharge = FALSE;
1846		int	is_fan_assy = FALSE;
1847
1848		/*
1849		 * pre-compute the presence and ok bits for this
1850		 * power supply from the hardware registers.
1851		 * NOTE: 4-slot pps1 is the same as core ps 7...
1852		 */
1853		switch (i) {
1854		/* the core power supplies */
1855		case 0: case 1: case 2: case 3:
1856		case 4: case 5: case 6: case 7:
1857			temp_pres = !((ps_pres >> i) & 0x1);
1858			temp_psok = (ps_stat >> i) & 0x1;
1859			break;
1860
1861		/* the first peripheral power supply */
1862		case SYS_PPS0_INDEX:
1863			temp_pres = !(status1 & SYS_NOT_PPS0_PRES);
1864			temp_psok = status2 & SYS_PPS0_OK;
1865			break;
1866
1867		/* shared 3.3v clock power */
1868		case SYS_CLK_33_INDEX:
1869			temp_pres = TRUE;
1870			temp_psok = status2 & SYS_CLK_33_OK;
1871			break;
1872
1873		/* shared 5.0v clock power */
1874		case SYS_CLK_50_INDEX:
1875			temp_pres = TRUE;
1876			temp_psok = status2 & SYS_CLK_50_OK;
1877			break;
1878
1879		/* peripheral 5v */
1880		case SYS_V5_P_INDEX:
1881			temp_pres = !(status1 & SYS_NOT_PPS0_PRES) ||
1882				((IS4SLOT(softsp->nslots) ||
1883				IS5SLOT(softsp->nslots)) &&
1884				!(ps_pres & SYS_NOT_PPS1_PRES));
1885			temp_psok = pppsr & SYS_V5_P_OK;
1886			break;
1887
1888		/* peripheral 12v */
1889		case SYS_V12_P_INDEX:
1890			temp_pres = !(status1 & SYS_NOT_PPS0_PRES) ||
1891				((IS4SLOT(softsp->nslots) ||
1892				IS5SLOT(softsp->nslots)) &&
1893				!(ps_pres & SYS_NOT_PPS1_PRES));
1894			temp_psok = pppsr & SYS_V12_P_OK;
1895			break;
1896
1897		/* aux 5v */
1898		case SYS_V5_AUX_INDEX:
1899			temp_pres = !(status1 & SYS_NOT_PPS0_PRES);
1900			temp_psok = pppsr & SYS_V5_AUX_OK;
1901			break;
1902
1903		/* peripheral 5v precharge */
1904		case SYS_V5_P_PCH_INDEX:
1905			temp_pres = !(status1 & SYS_NOT_PPS0_PRES);
1906			temp_psok = pppsr & SYS_V5_P_PCH_OK;
1907			is_precharge = TRUE;
1908			break;
1909
1910		/* peripheral 12v precharge */
1911		case SYS_V12_P_PCH_INDEX:
1912			temp_pres = !(status1 & SYS_NOT_PPS0_PRES);
1913			temp_psok = pppsr & SYS_V12_P_PCH_OK;
1914			is_precharge = TRUE;
1915			break;
1916
1917		/* 3.3v precharge */
1918		case SYS_V3_PCH_INDEX:
1919			temp_pres = !(status1 & SYS_NOT_PPS0_PRES);
1920			temp_psok = pppsr & SYS_V3_PCH_OK;
1921			is_precharge = TRUE;
1922			break;
1923
1924		/* 5v precharge */
1925		case SYS_V5_PCH_INDEX:
1926			temp_pres = !(status1 & SYS_NOT_PPS0_PRES);
1927			temp_psok = pppsr & SYS_V5_PCH_OK;
1928			is_precharge = TRUE;
1929			break;
1930
1931		/* peripheral fan assy */
1932		case SYS_P_FAN_INDEX:
1933			temp_pres = (IS4SLOT(softsp->nslots) ||
1934				IS5SLOT(softsp->nslots)) &&
1935				!(status1 & SYS_NOT_P_FAN_PRES);
1936			temp_psok = softsp->pps_fan_saved &
1937				SYS_AC_FAN_OK;
1938			is_fan_assy = TRUE;
1939			break;
1940		}
1941
1942		/* *** Phase 1 -- power supply presence tests *** */
1943
1944		/* do we know the presence status for this power supply? */
1945		if (pstatp->pshadow == PRES_UNKNOWN) {
1946			pstatp->pshadow = temp_pres ? PRES_IN : PRES_OUT;
1947			pstatp->dcshadow = temp_pres ? PS_BOOT : PS_OUT;
1948		} else {
1949			/* has the ps presence state changed? */
1950			if (!temp_pres ^ (pstatp->pshadow == PRES_IN)) {
1951				pstatp->pctr = 0;
1952			} else {
1953				/* a change! are we counting? */
1954				if (pstatp->pctr == 0) {
1955					pstatp->pctr = PS_PRES_CHANGE_TICKS;
1956				} else if (--pstatp->pctr == 0) {
1957					pstatp->pshadow = temp_pres ?
1958						PRES_IN : PRES_OUT;
1959					pstatp->dcshadow = temp_pres ?
1960						PS_UNKNOWN : PS_OUT;
1961
1962					/*
1963					 * Now we know the state has
1964					 * changed, so we should log it.
1965					 */
1966					ps_log_pres_change(softsp,
1967						i, temp_pres);
1968				}
1969			}
1970		}
1971
1972		/* *** Phase 2 -- power supply status tests *** */
1973
1974		/* check if the Power Supply is removed or same as before */
1975		if ((pstatp->dcshadow == PS_OUT) ||
1976		    ((pstatp->dcshadow == PS_OK) && temp_psok) ||
1977		    ((pstatp->dcshadow == PS_FAIL) && !temp_psok)) {
1978			pstatp->dcctr = 0;
1979		} else {
1980
1981			/* OK, a change, do we start the timer? */
1982			if (pstatp->dcctr == 0) {
1983				switch (pstatp->dcshadow) {
1984				case PS_BOOT:
1985					pstatp->dcctr = PS_FROM_BOOT_TICKS;
1986					break;
1987
1988				case PS_UNKNOWN:
1989					pstatp->dcctr = is_fan_assy ?
1990						PS_P_FAN_FROM_UNKNOWN_TICKS :
1991						PS_FROM_UNKNOWN_TICKS;
1992					break;
1993
1994				case PS_OK:
1995					pstatp->dcctr = is_precharge ?
1996						PS_PCH_FROM_OK_TICKS :
1997						PS_FROM_OK_TICKS;
1998					break;
1999
2000				case PS_FAIL:
2001					pstatp->dcctr = PS_FROM_FAIL_TICKS;
2002					break;
2003
2004				default:
2005					panic("sysctrl%d: Unknown Power "
2006					    "Supply State %d", pstatp->dcshadow,
2007					    ddi_get_instance(softsp->dip));
2008				}
2009			}
2010
2011			/* has the ticker expired? */
2012			if (--pstatp->dcctr == 0) {
2013
2014				/* we'll skip OK messages during boot */
2015				if (!((pstatp->dcshadow == PS_BOOT) &&
2016				    temp_psok)) {
2017					ps_log_state_change(softsp,
2018						i, temp_psok);
2019				}
2020
2021				/*
2022				 * remote console interface has to be
2023				 * reinitialized on the rising edge V5_AUX
2024				 * when it is NOT boot. At the boot time an
2025				 * an error condition exists if it was not
2026				 * enabled before.
2027				 */
2028				if ((i == SYS_V5_AUX_INDEX) &&
2029				    (pstatp->dcshadow != PS_BOOT) &&
2030				    (softsp->enable_rcons_atboot)) {
2031					if (temp_psok)
2032						rcons_reinit(softsp);
2033					else
2034						/* disable rconsole */
2035						*(softsp->clk_freq2) &=
2036						    ~RCONS_UART_EN;
2037					tmp_reg = *(softsp->csr);
2038#ifdef lint
2039					tmp_reg = tmp_reg;
2040#endif
2041
2042				}
2043
2044				/* regardless, update the shadow state */
2045				pstatp->dcshadow = temp_psok ? PS_OK : PS_FAIL;
2046
2047				/* always update board condition */
2048				sysc_policy_update(softsp, NULL,
2049					SYSC_EVT_BD_PS_CHANGE);
2050
2051			}
2052		}
2053
2054		/*
2055		 * We will need to continue polling for three reasons:
2056		 * - a failing power supply is detected and we haven't yet
2057		 *   determined the power supplies existence.
2058		 * - the power supply is just installed and we're waiting
2059		 *   to give it a change to power up,
2060		 * - a failed power supply state is recognized
2061		 *
2062		 * NOTE: PS_FAIL shadow state is not the same as !temp_psok
2063		 * because of the persistence of PS_FAIL->PS_OK.
2064		 */
2065		if (!temp_psok ||
2066		    (pstatp->dcshadow == PS_UNKNOWN) ||
2067		    (pstatp->dcshadow == PS_FAIL)) {
2068			poll_needed++;
2069		}
2070	}
2071
2072	/*
2073	 * Now, get the current power state for this instance.
2074	 * If the current state is different than what was known, complain.
2075	 */
2076	current_power_state = compute_power_state(softsp, 0);
2077
2078	if (softsp->power_state != current_power_state) {
2079		switch (current_power_state) {
2080		case BELOW_MINIMUM:
2081			cmn_err(CE_WARN,
2082				"Insufficient power available to system");
2083			if (!disable_insufficient_power_reboot) {
2084				cmn_err(CE_WARN, "System reboot in %d seconds",
2085					PS_INSUFFICIENT_COUNTDOWN_SEC);
2086			}
2087			reg_fault(1, FT_INSUFFICIENT_POWER, FT_SYSTEM);
2088			softsp->power_countdown = PS_POWER_COUNTDOWN_TICKS;
2089			break;
2090
2091		case MINIMUM:
2092			/* If we came from REDUNDANT, complain */
2093			if (softsp->power_state == REDUNDANT) {
2094				cmn_err(CE_WARN, "Redundant power lost");
2095			/* If we came from BELOW_MINIMUM, hurrah! */
2096			} else if (softsp->power_state == BELOW_MINIMUM) {
2097				cmn_err(CE_NOTE, "Minimum power available");
2098				clear_fault(1, FT_INSUFFICIENT_POWER,
2099					FT_SYSTEM);
2100			}
2101			break;
2102
2103		case REDUNDANT:
2104			/* If we aren't from boot, spread the good news */
2105			if (softsp->power_state != BOOT) {
2106				cmn_err(CE_NOTE, "Redundant power available");
2107				clear_fault(1, FT_INSUFFICIENT_POWER,
2108					FT_SYSTEM);
2109			}
2110			break;
2111
2112		default:
2113			break;
2114		}
2115		softsp->power_state = current_power_state;
2116		sysc_policy_update(softsp, NULL, SYSC_EVT_BD_PS_CHANGE);
2117	}
2118
2119	mutex_exit(&softsp->ps_fail_lock);
2120
2121	fhc_bdlist_unlock();
2122
2123	/*
2124	 * Are we in insufficient powerstate?
2125	 * If so, is it time to take action?
2126	 */
2127	if (softsp->power_state == BELOW_MINIMUM &&
2128	    softsp->power_countdown > 0 && --(softsp->power_countdown) == 0 &&
2129	    !disable_insufficient_power_reboot) {
2130		cmn_err(CE_WARN,
2131		    "Insufficient power. System Reboot Started...");
2132
2133		fhc_reboot();
2134	}
2135
2136	/*
2137	 * If we don't have ps problems that need to be polled for, then
2138	 * enable interrupts.
2139	 */
2140	if (!poll_needed) {
2141		mutex_enter(&softsp->csr_mutex);
2142		*(softsp->csr) |= SYS_PS_FAIL_EN;
2143		tmp_reg = *(softsp->csr);
2144#ifdef lint
2145		tmp_reg = tmp_reg;
2146#endif
2147		mutex_exit(&softsp->csr_mutex);
2148	}
2149
2150	/*
2151	 * Only the polling loop re-triggers the polling loop timeout
2152	 */
2153	if (!fromint) {
2154		(void) timeout(ps_fail_retry, softsp, ps_fail_timeout_hz);
2155	}
2156
2157	return (DDI_INTR_CLAIMED);
2158}
2159
2160/*
2161 * Compute the current power configuration for this system.
2162 * Disk boards and Clock boards are not counted.
2163 *
2164 * This function must be called with the ps_fail_lock held.
2165 */
2166enum power_state
2167compute_power_state(struct sysctrl_soft_state *softsp, int plus_load)
2168{
2169	int i;
2170	int ok_supply_count = 0;
2171	int load_count = 0;
2172	int minimum_power_count;
2173	int pps_ok;
2174	fhc_bd_t *list;
2175
2176	ASSERT(mutex_owned(&softsp->ps_fail_lock));
2177
2178	/*
2179	 * Walk down the interesting power supplies and
2180	 * count the operational power units
2181	 */
2182	for (i = 0; i < 8; i++) {
2183		/*
2184		 * power supply id 7 on a 4 or 5 slot system is PPS1.
2185		 * don't include it in the redundant core power calculation.
2186		 */
2187		if (i == 7 &&
2188		    (IS4SLOT(softsp->nslots) || IS5SLOT(softsp->nslots)))
2189			continue;
2190
2191		if (softsp->ps_stats[i].dcshadow == PS_OK)
2192			ok_supply_count++;
2193	}
2194
2195	/* Note the state of the PPS... */
2196	pps_ok = (softsp->ps_stats[SYS_PPS0_INDEX].dcshadow == PS_OK);
2197
2198	/*
2199	 * Dynamically compute the load count in the system.
2200	 * Don't count disk boards or boards in low power state.
2201	 */
2202	for (list = fhc_bd_first(); list; list = fhc_bd_next(list)) {
2203		ASSERT(list->sc.type != CLOCK_BOARD);
2204		if (list->sc.rstate == SYSC_CFGA_RSTATE_CONNECTED) {
2205			load_count++;
2206		}
2207	}
2208
2209	load_count += plus_load;
2210	/*
2211	 * If we are 8 slot and we have 7 or 8 boards, then the PPS
2212	 * can count as a power supply...
2213	 */
2214	if (IS8SLOT(softsp->nslots) && load_count >= 7 && pps_ok)
2215		ok_supply_count++;
2216
2217	/*
2218	 * This is to cover the corner case of a UE3500 having 5
2219	 * boards installed and still giving it N+1 power status.
2220	 */
2221	if (IS5SLOT(softsp->nslots) && (load_count >= 5))
2222		ok_supply_count++;
2223
2224	/*
2225	 * Determine our power situation.  This is a simple step
2226	 * function right now:
2227	 *
2228	 * minimum power count = min(7, floor((board count + 1) / 2))
2229	 */
2230	minimum_power_count = (load_count + 1) / 2;
2231	if (minimum_power_count > 7)
2232		minimum_power_count = 7;
2233
2234	if (ok_supply_count > minimum_power_count)
2235		return (REDUNDANT);
2236	else if (ok_supply_count == minimum_power_count)
2237		return (MINIMUM);
2238	else
2239		return (BELOW_MINIMUM);
2240}
2241
2242/*
2243 * log the change of power supply presence
2244 */
2245static void
2246ps_log_pres_change(struct sysctrl_soft_state *softsp, int index, int present)
2247{
2248	char	*trans = present ? "Installed" : "Removed";
2249
2250	switch (index) {
2251	/* the core power supplies (except for 7) */
2252	case 0: case 1: case 2: case 3:
2253	case 4: case 5: case 6:
2254		cmn_err(CE_NOTE, "%s %d %s", ft_str_table[FT_CORE_PS], index,
2255		    trans);
2256		if (!present) {
2257		    clear_fault(index, FT_CORE_PS, FT_SYSTEM);
2258		    sysc_policy_update(softsp, NULL, SYSC_EVT_BD_PS_CHANGE);
2259		}
2260		break;
2261
2262	/* power supply 7 / pps 1 */
2263	case 7:
2264		if (IS4SLOT(softsp->nslots) || IS5SLOT(softsp->nslots)) {
2265		    cmn_err(CE_NOTE, "%s 1 %s", ft_str_table[FT_PPS], trans);
2266		    if (!present) {
2267			clear_fault(1, FT_PPS, FT_SYSTEM);
2268		    }
2269		} else {
2270		    cmn_err(CE_NOTE, "%s %d %s", ft_str_table[FT_CORE_PS],
2271			index, trans);
2272		    if (!present) {
2273			clear_fault(7, FT_CORE_PS, FT_SYSTEM);
2274			sysc_policy_update(softsp, NULL, SYSC_EVT_BD_PS_CHANGE);
2275		    }
2276		}
2277		break;
2278
2279	/* the peripheral power supply 0 */
2280	case SYS_PPS0_INDEX:
2281		cmn_err(CE_NOTE, "%s 0 %s", ft_str_table[FT_PPS], trans);
2282		if (!present) {
2283			clear_fault(0, FT_PPS, FT_SYSTEM);
2284			sysc_policy_update(softsp, NULL, SYSC_EVT_BD_PS_CHANGE);
2285		}
2286		break;
2287
2288	/* the peripheral rack fan assy */
2289	case SYS_P_FAN_INDEX:
2290		cmn_err(CE_NOTE, "%s %s", ft_str_table[FT_PPS_FAN], trans);
2291		if (!present) {
2292			clear_fault(0, FT_PPS_FAN, FT_SYSTEM);
2293		}
2294		break;
2295
2296	/* we don't mention a change of presence state for any other power */
2297	}
2298}
2299
2300/*
2301 * log the change of power supply status
2302 */
2303static void
2304ps_log_state_change(struct sysctrl_soft_state *softsp, int index, int ps_ok)
2305{
2306	int level = ps_ok ? CE_NOTE : CE_WARN;
2307	char *s = ps_ok ? "OK" : "Failing";
2308
2309	switch (index) {
2310	/* the core power supplies (except 7) */
2311	case 0: case 1: case 2: case 3:
2312	case 4: case 5: case 6:
2313		cmn_err(level, "%s %d %s", ft_str_table[FT_CORE_PS], index, s);
2314		if (ps_ok) {
2315			clear_fault(index, FT_CORE_PS, FT_SYSTEM);
2316		} else {
2317			reg_fault(index, FT_CORE_PS, FT_SYSTEM);
2318		}
2319		break;
2320
2321	/* power supply 7 / pps 1 */
2322	case 7:
2323		if (IS4SLOT(softsp->nslots) || IS5SLOT(softsp->nslots)) {
2324			cmn_err(level, "%s 1 %s", ft_str_table[FT_PPS], s);
2325			if (ps_ok) {
2326				clear_fault(1, FT_PPS, FT_SYSTEM);
2327			} else {
2328				reg_fault(1, FT_PPS, FT_SYSTEM);
2329			}
2330		} else {
2331			cmn_err(level, "%s %d %s", ft_str_table[FT_CORE_PS],
2332				index, s);
2333			if (ps_ok) {
2334				clear_fault(index, FT_CORE_PS, FT_SYSTEM);
2335			} else {
2336				reg_fault(index, FT_CORE_PS, FT_SYSTEM);
2337			}
2338		}
2339		break;
2340
2341	/* the peripheral power supply */
2342	case SYS_PPS0_INDEX:
2343		cmn_err(level, "%s %s", ft_str_table[FT_PPS], s);
2344		if (ps_ok) {
2345			clear_fault(0, FT_PPS, FT_SYSTEM);
2346		} else {
2347			reg_fault(0, FT_PPS, FT_SYSTEM);
2348		}
2349		break;
2350
2351	/* shared 3.3v clock power */
2352	case SYS_CLK_33_INDEX:
2353		cmn_err(level, "%s %s", ft_str_table[FT_CLK_33], s);
2354		if (ps_ok) {
2355			clear_fault(0, FT_CLK_33, FT_SYSTEM);
2356		} else {
2357			reg_fault(0, FT_CLK_33, FT_SYSTEM);
2358		}
2359		break;
2360
2361	/* shared 5.0v clock power */
2362	case SYS_CLK_50_INDEX:
2363		cmn_err(level, "%s %s", ft_str_table[FT_CLK_50], s);
2364		if (ps_ok) {
2365			clear_fault(0, FT_CLK_50, FT_SYSTEM);
2366		} else {
2367			reg_fault(0, FT_CLK_50, FT_SYSTEM);
2368		}
2369		break;
2370
2371	/* peripheral 5v */
2372	case SYS_V5_P_INDEX:
2373		cmn_err(level, "%s %s", ft_str_table[FT_V5_P], s);
2374		if (ps_ok) {
2375			clear_fault(0, FT_V5_P, FT_SYSTEM);
2376		} else {
2377			reg_fault(0, FT_V5_P, FT_SYSTEM);
2378		}
2379		break;
2380
2381	/* peripheral 12v */
2382	case SYS_V12_P_INDEX:
2383		cmn_err(level, "%s %s", ft_str_table[FT_V12_P], s);
2384		if (ps_ok) {
2385			clear_fault(0, FT_V12_P, FT_SYSTEM);
2386		} else {
2387			reg_fault(0, FT_V12_P, FT_SYSTEM);
2388		}
2389		break;
2390
2391	/* aux 5v */
2392	case SYS_V5_AUX_INDEX:
2393		cmn_err(level, "%s %s", ft_str_table[FT_V5_AUX], s);
2394		if (ps_ok) {
2395			clear_fault(0, FT_V5_AUX, FT_SYSTEM);
2396		} else {
2397			reg_fault(0, FT_V5_AUX, FT_SYSTEM);
2398		}
2399		break;
2400
2401	/* peripheral 5v precharge */
2402	case SYS_V5_P_PCH_INDEX:
2403		cmn_err(level, "%s %s", ft_str_table[FT_V5_P_PCH], s);
2404		if (ps_ok) {
2405			clear_fault(0, FT_V5_P_PCH, FT_SYSTEM);
2406		} else {
2407			reg_fault(0, FT_V5_P_PCH, FT_SYSTEM);
2408		}
2409		break;
2410
2411	/* peripheral 12v precharge */
2412	case SYS_V12_P_PCH_INDEX:
2413		cmn_err(level, "%s %s", ft_str_table[FT_V12_P_PCH], s);
2414		if (ps_ok) {
2415			clear_fault(0, FT_V12_P_PCH, FT_SYSTEM);
2416		} else {
2417			reg_fault(0, FT_V12_P_PCH, FT_SYSTEM);
2418		}
2419		break;
2420
2421	/* 3.3v precharge */
2422	case SYS_V3_PCH_INDEX:
2423		cmn_err(level, "%s %s", ft_str_table[FT_V3_PCH], s);
2424		if (ps_ok) {
2425			clear_fault(0, FT_V3_PCH, FT_SYSTEM);
2426		} else {
2427			reg_fault(0, FT_V3_PCH, FT_SYSTEM);
2428		}
2429		break;
2430
2431	/* 5v precharge */
2432	case SYS_V5_PCH_INDEX:
2433		cmn_err(level, "%s %s", ft_str_table[FT_V5_PCH], s);
2434		if (ps_ok) {
2435			clear_fault(0, FT_V5_PCH, FT_SYSTEM);
2436		} else {
2437			reg_fault(0, FT_V5_PCH, FT_SYSTEM);
2438		}
2439		break;
2440
2441	/* peripheral power supply fans */
2442	case SYS_P_FAN_INDEX:
2443		cmn_err(level, "%s %s", ft_str_table[FT_PPS_FAN], s);
2444		if (ps_ok) {
2445			clear_fault(0, FT_PPS_FAN, FT_SYSTEM);
2446		} else {
2447			reg_fault(0, FT_PPS_FAN, FT_SYSTEM);
2448		}
2449		break;
2450	}
2451}
2452
2453/*
2454 * The timeout from ps_fail_handler() that simply re-triggers a check
2455 * of the ps condition.
2456 */
2457static void
2458ps_fail_retry(void *arg)
2459{
2460	struct sysctrl_soft_state *softsp = arg;
2461
2462	ASSERT(softsp);
2463
2464	ddi_trigger_softintr(softsp->ps_fail_poll_id);
2465}
2466
2467/*
2468 * pps_fanfail_handler
2469 *
2470 * This routine is called from the high level handler.
2471 */
2472static uint_t
2473pps_fanfail_handler(caddr_t arg)
2474{
2475	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
2476
2477	ASSERT(softsp);
2478
2479	/* always check again in a bit by re-enabling the fan interrupt */
2480	(void) timeout(pps_fanfail_retry, softsp, pps_fan_timeout_hz);
2481
2482	return (DDI_INTR_CLAIMED);
2483}
2484
2485/*
2486 * After a bit of waiting, we simply re-enable the interrupt to
2487 * see if we get another one.  The softintr triggered routine does
2488 * the dirty work for us since it runs in the interrupt context.
2489 */
2490static void
2491pps_fanfail_retry(void *arg)
2492{
2493	struct sysctrl_soft_state *softsp = arg;
2494
2495	ASSERT(softsp);
2496
2497	ddi_trigger_softintr(softsp->pps_fan_high_id);
2498}
2499
2500/*
2501 * The other half of the retry handler run from the interrupt context
2502 */
2503static uint_t
2504pps_fanfail_reenable(caddr_t arg)
2505{
2506	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
2507	uchar_t tmp_reg;
2508
2509	ASSERT(softsp);
2510
2511	mutex_enter(&softsp->csr_mutex);
2512
2513	/*
2514	 * re-initialize the bit field for all pps fans to assumed good.
2515	 * If the fans are still bad, we're going to get an immediate system
2516	 * interrupt which will put the correct state back anyway.
2517	 *
2518	 * NOTE: the polling routines that use this state understand the
2519	 * pulse resulting from above...
2520	 */
2521	softsp->pps_fan_saved = SYS_AC_FAN_OK | SYS_KEYSW_FAN_OK;
2522
2523	*(softsp->csr) |= SYS_PPS_FAN_FAIL_EN;
2524	tmp_reg = *(softsp->csr);
2525#ifdef lint
2526	tmp_reg = tmp_reg;
2527#endif
2528	mutex_exit(&softsp->csr_mutex);
2529
2530	return (DDI_INTR_CLAIMED);
2531}
2532
2533/*
2534 *
2535 * Poll the hardware shadow state to determine the pps fan status.
2536 * The shadow state is maintained by the system_high handler and its
2537 * associated pps_* functions (above).
2538 *
2539 * There is a short time interval where the shadow state is pulsed to
2540 * the OK state even when the fans are bad.  However, this polling
2541 * routine has some built in hysteresis to filter out those _normal_
2542 * events.
2543 */
2544static void
2545pps_fan_poll(void *arg)
2546{
2547	struct sysctrl_soft_state *softsp = arg;
2548	int i;
2549
2550	ASSERT(softsp);
2551
2552	for (i = 0; i < SYS_PPS_FAN_COUNT; i++) {
2553		int fanfail = FALSE;
2554
2555		/* determine fan status */
2556		switch (i) {
2557		case RACK:
2558			fanfail = softsp->pps_fan_saved & SYS_RACK_FANFAIL;
2559			break;
2560
2561		case AC:
2562			/*
2563			 * Don't bother polling the AC fan on 4 and 5 slot
2564			 * systems.
2565			 * Rather, it is handled by the power supply loop.
2566			 */
2567			fanfail = !(IS4SLOT(softsp->nslots) ||
2568				IS5SLOT(softsp->nslots)) &&
2569				!(softsp->pps_fan_saved & SYS_AC_FAN_OK);
2570			break;
2571
2572		case KEYSW:
2573			/*
2574			 * This signal is not usable if aux5v is missing
2575			 * so we will synthesize a failed fan when aux5v
2576			 * fails or when pps0 is out.
2577			 * The 4 and 5 slot systems behave the same.
2578			 */
2579			fanfail = (!(IS4SLOT(softsp->nslots) ||
2580				IS5SLOT(softsp->nslots)) &&
2581			    (softsp->ps_stats[SYS_V5_AUX_INDEX].dcshadow !=
2582				PS_OK)) ||
2583			    !(softsp->pps_fan_saved & SYS_KEYSW_FAN_OK);
2584			break;
2585
2586		}
2587
2588		/* is the fan bad? */
2589		if (fanfail) {
2590
2591			/* is this condition different than we know? */
2592			if (softsp->pps_fan_state_count[i] == 0) {
2593
2594				/* log the change to failed */
2595				pps_fan_state_change(softsp, i, FALSE);
2596			}
2597
2598			/* always restart the fan OK counter */
2599			softsp->pps_fan_state_count[i] = PPS_FROM_FAIL_TICKS;
2600		} else {
2601
2602			/* do we currently know the fan is bad? */
2603			if (softsp->pps_fan_state_count[i]) {
2604
2605				/* yes, but has it been stable? */
2606				if (--softsp->pps_fan_state_count[i] == 0) {
2607
2608					/* log the change to OK */
2609					pps_fan_state_change(softsp, i, TRUE);
2610				}
2611			}
2612		}
2613	}
2614
2615	/* always check again in a bit by re-enabling the fan interrupt */
2616	(void) timeout(pps_fan_poll, softsp, pps_fan_timeout_hz);
2617}
2618
2619/*
2620 * pps_fan_state_change()
2621 *
2622 * Log the changed fan condition and update the external status.
2623 */
2624static void
2625pps_fan_state_change(struct sysctrl_soft_state *softsp, int index, int fan_ok)
2626{
2627	char *fan_type;
2628	char *state = fan_ok ? "fans OK" : "fan failure detected";
2629
2630	switch (index) {
2631	case RACK:
2632		/* 4 and 5 slot systems behave the same */
2633		fan_type = (IS4SLOT(softsp->nslots) ||
2634				IS5SLOT(softsp->nslots)) ?
2635				"Disk Drive" : "Rack Exhaust";
2636		if (fan_ok) {
2637			softsp->pps_fan_external_state &= ~SYS_RACK_FANFAIL;
2638			clear_fault(0, (IS4SLOT(softsp->nslots) ||
2639				IS5SLOT(softsp->nslots)) ? FT_DSK_FAN :
2640				FT_RACK_EXH, FT_SYSTEM);
2641		} else {
2642			softsp->pps_fan_external_state |= SYS_RACK_FANFAIL;
2643			reg_fault(0, (IS4SLOT(softsp->nslots) ||
2644				IS5SLOT(softsp->nslots)) ? FT_DSK_FAN :
2645				FT_RACK_EXH, FT_SYSTEM);
2646		}
2647		break;
2648
2649	case AC:
2650		fan_type = "AC Box";
2651		if (fan_ok) {
2652			softsp->pps_fan_external_state |= SYS_AC_FAN_OK;
2653			clear_fault(0, FT_AC_FAN, FT_SYSTEM);
2654		} else {
2655			softsp->pps_fan_external_state &= ~SYS_AC_FAN_OK;
2656			reg_fault(0, FT_AC_FAN, FT_SYSTEM);
2657		}
2658		break;
2659
2660	case KEYSW:
2661		fan_type = "Keyswitch";
2662		if (fan_ok) {
2663			softsp->pps_fan_external_state |= SYS_KEYSW_FAN_OK;
2664			clear_fault(0, FT_KEYSW_FAN, FT_SYSTEM);
2665		} else {
2666			softsp->pps_fan_external_state &= ~SYS_KEYSW_FAN_OK;
2667			reg_fault(0, FT_KEYSW_FAN, FT_SYSTEM);
2668		}
2669		break;
2670	default:
2671		fan_type = "[invalid fan id]";
2672		break;
2673	}
2674
2675	/* now log the state change */
2676	cmn_err(fan_ok ? CE_NOTE : CE_WARN, "%s %s", fan_type, state);
2677}
2678
2679static uint_t
2680bd_insert_handler(caddr_t arg)
2681{
2682	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
2683
2684	ASSERT(softsp);
2685
2686	DPRINTF(SYSCTRL_ATTACH_DEBUG, ("bd_insert_handler()"));
2687
2688	(void) timeout(bd_insert_timeout, softsp, bd_insert_delay_hz);
2689
2690	return (DDI_INTR_CLAIMED);
2691}
2692
2693void
2694bd_remove_poll(struct sysctrl_soft_state *softsp)
2695{
2696	ASSERT(fhc_bdlist_locked());
2697
2698	if (!bd_remove_to_id) {
2699		bd_remove_to_id = timeout(bd_remove_timeout, softsp,
2700						bd_remove_timeout_hz);
2701	} else {
2702		DPRINTF(SYSCTRL_ATTACH_DEBUG,
2703			("bd_remove_poll ignoring start request"));
2704	}
2705}
2706
2707/*
2708 * bd_insert_timeout()
2709 *
2710 * This routine handles the board insert interrupt. It is called from a
2711 * timeout so that it does not run at interrupt level. The main job
2712 * of this routine is to find hotplugged boards and de-assert the
2713 * board insert interrupt coming from the board. For hotplug phase I,
2714 * the routine also powers down the board.
2715 * JTAG scan is used to find boards which have been inserted.
2716 * All other control of the boards is also done by JTAG scan.
2717 */
2718static void
2719bd_insert_timeout(void *arg)
2720{
2721	struct sysctrl_soft_state *softsp = arg;
2722	int found;
2723
2724	ASSERT(softsp);
2725
2726	if (sysctrl_hotplug_disabled) {
2727		sysc_policy_update(softsp, NULL, SYSC_EVT_BD_HP_DISABLED);
2728	} else {
2729		/*
2730		 * Lock the board list mutex. Keep it locked until all work
2731		 * is done.
2732		 */
2733		(void) fhc_bdlist_lock(-1);
2734
2735		found = fhc_bd_insert_scan();
2736
2737		if (found) {
2738			DPRINTF(SYSCTRL_ATTACH_DEBUG,
2739			    ("bd_insert_timeout starting bd_remove_poll()"));
2740			bd_remove_poll(softsp);
2741		}
2742
2743		fhc_bdlist_unlock();
2744	}
2745
2746	/*
2747	 * Enable interrupts.
2748	 */
2749	ddi_trigger_softintr(softsp->sbrd_gone_id);
2750}
2751
2752static void
2753bd_remove_timeout(void *arg)
2754{
2755	struct sysctrl_soft_state *softsp = arg;
2756	int keep_polling;
2757
2758	ASSERT(softsp);
2759
2760	/*
2761	 * Lock the board list mutex. Keep it locked until all work
2762	 * is done.
2763	 */
2764	(void) fhc_bdlist_lock(-1);
2765
2766	bd_remove_to_id = 0;	/* delete our timeout ID */
2767
2768	keep_polling = fhc_bd_remove_scan();
2769
2770	if (keep_polling) {
2771		bd_remove_poll(softsp);
2772	} else {
2773		DPRINTF(SYSCTRL_ATTACH_DEBUG, ("exiting bd_remove_poll."));
2774	}
2775
2776	fhc_bdlist_unlock();
2777}
2778
2779static uint_t
2780bd_insert_normal(caddr_t arg)
2781{
2782	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
2783	uchar_t tmp_reg;
2784
2785	ASSERT(softsp);
2786
2787	/* has the condition been removed? */
2788	/* XXX add deglitch state machine here */
2789	if (!(*(softsp->status1) & SYS_NOT_BRD_PRES)) {
2790		/* check again in a few */
2791		(void) timeout(bd_insert_timeout, softsp, bd_insert_retry_hz);
2792	} else {
2793		/* Turn on the enable bit for this interrupt */
2794		mutex_enter(&softsp->csr_mutex);
2795		*(softsp->csr) |= SYS_SBRD_PRES_EN;
2796		/* flush the hardware store buffer */
2797		tmp_reg = *(softsp->csr);
2798#ifdef lint
2799		tmp_reg = tmp_reg;
2800#endif
2801		mutex_exit(&softsp->csr_mutex);
2802	}
2803
2804	return (DDI_INTR_CLAIMED);
2805}
2806
2807/*
2808 * blink LED handler.
2809 *
2810 * The actual bit manipulation needs to occur at interrupt level
2811 * because we need access to the CSR with its CSR mutex
2812 */
2813static uint_t
2814blink_led_handler(caddr_t arg)
2815{
2816	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)arg;
2817	uchar_t tmp_reg;
2818
2819	ASSERT(softsp);
2820
2821	mutex_enter(&softsp->csr_mutex);
2822
2823	/*
2824	 * XXX - The lock for the sys_led is not held here. If more
2825	 * complicated tasks are done with the System LED, then
2826	 * locking should be done here.
2827	 */
2828
2829	/* read the hardware register. */
2830	tmp_reg = *(softsp->csr);
2831
2832	/* Only turn on the OS System LED bit if the softsp state is on. */
2833	if (softsp->sys_led) {
2834		tmp_reg |= SYS_LED_RIGHT;
2835	} else {
2836		tmp_reg &= ~SYS_LED_RIGHT;
2837	}
2838
2839	/* Turn on the yellow LED if system fault status is set. */
2840	if (softsp->sys_fault) {
2841		tmp_reg |= SYS_LED_MID;
2842	} else {
2843		tmp_reg &= ~SYS_LED_MID;
2844	}
2845
2846	/* write to the hardware register */
2847	*(softsp->csr) = tmp_reg;
2848
2849	/* flush the hardware store buffer */
2850	tmp_reg = *(softsp->csr);
2851#ifdef lint
2852	tmp_reg = tmp_reg;
2853#endif
2854	mutex_exit(&softsp->csr_mutex);
2855
2856	(void) timeout(blink_led_timeout, softsp, blink_led_timeout_hz);
2857
2858	return (DDI_INTR_CLAIMED);
2859}
2860
2861/*
2862 * simply re-trigger the interrupt handler on led timeout
2863 */
2864static void
2865blink_led_timeout(void *arg)
2866{
2867	struct sysctrl_soft_state *softsp = arg;
2868	int led_state;
2869
2870	ASSERT(softsp);
2871
2872	/*
2873	 * Process the system fault list here. This is where the driver
2874	 * must decide what yellow LEDs to turn on if any. The fault
2875	 * list is walked and each fhc_list entry is updated with it's
2876	 * yellow LED status. This info is used later by the routine
2877	 * toggle_board_green_leds().
2878	 *
2879	 * The variable system_fault is non-zero if any non-
2880	 * suppressed faults are found in the system.
2881	 */
2882	softsp->sys_fault = process_fault_list();
2883
2884	/* blink the system board OS LED */
2885	mutex_enter(&softsp->sys_led_lock);
2886	softsp->sys_led = !softsp->sys_led;
2887	led_state = softsp->sys_led;
2888	mutex_exit(&softsp->sys_led_lock);
2889
2890	toggle_board_green_leds(led_state);
2891
2892	ddi_trigger_softintr(softsp->blink_led_id);
2893}
2894
2895void
2896toggle_board_green_leds(int led_state)
2897{
2898	fhc_bd_t *list;
2899
2900	(void) fhc_bdlist_lock(-1);
2901	for (list = fhc_bd_first(); list; list = fhc_bd_next(list)) {
2902		uint_t value = 0;
2903
2904		if (list->sc.in_transition ||
2905		    (list->sc.rstate != SYSC_CFGA_RSTATE_CONNECTED))
2906			continue;
2907
2908		ASSERT(list->sc.type != CLOCK_BOARD);
2909		ASSERT(list->sc.type != DISK_BOARD);
2910		ASSERT(list->softsp);
2911
2912		if ((list->sc.ostate == SYSC_CFGA_OSTATE_CONFIGURED) &&
2913		    led_state)
2914			value |= FHC_LED_RIGHT;
2915
2916		if (list->fault)
2917			value |= FHC_LED_MID;
2918		else
2919			value &= ~FHC_LED_MID;
2920
2921		update_board_leds(list, FHC_LED_RIGHT|FHC_LED_MID, value);
2922	}
2923	fhc_bdlist_unlock();
2924}
2925
2926/*
2927 * timestamp an AC power failure in nvram
2928 */
2929static void
2930nvram_update_powerfail(struct sysctrl_soft_state *softsp)
2931{
2932	char buf[80];
2933	int len = 0;
2934
2935	numtos(gethrestime_sec(), buf);
2936
2937	if (softsp->options_nodeid) {
2938		len = prom_setprop(softsp->options_nodeid, "powerfail-time",
2939			buf, strlen(buf)+1);
2940	}
2941
2942	if (len <= 0) {
2943		cmn_err(CE_WARN, "sysctrl%d: failed to set powerfail-time "
2944			"to %s\n", ddi_get_instance(softsp->dip), buf);
2945	}
2946}
2947
2948void
2949sysctrl_add_kstats(struct sysctrl_soft_state *softsp)
2950{
2951	struct kstat	*ksp;		/* Generic sysctrl kstats */
2952	struct kstat	*pksp;		/* Power Supply kstat */
2953	struct kstat	*tksp;		/* Sysctrl temperatrure kstat */
2954	struct kstat	*ttsp;		/* Sysctrl temperature test kstat */
2955
2956	if ((ksp = kstat_create("unix", ddi_get_instance(softsp->dip),
2957	    SYSCTRL_KSTAT_NAME, "misc", KSTAT_TYPE_NAMED,
2958	    sizeof (struct sysctrl_kstat) / sizeof (kstat_named_t),
2959	    KSTAT_FLAG_PERSISTENT)) == NULL) {
2960		cmn_err(CE_WARN, "sysctrl%d: kstat_create failed",
2961			ddi_get_instance(softsp->dip));
2962	} else {
2963		struct sysctrl_kstat *sysksp;
2964
2965		sysksp = (struct sysctrl_kstat *)(ksp->ks_data);
2966
2967		/* now init the named kstats */
2968		kstat_named_init(&sysksp->csr, CSR_KSTAT_NAMED,
2969			KSTAT_DATA_CHAR);
2970
2971		kstat_named_init(&sysksp->status1, STAT1_KSTAT_NAMED,
2972			KSTAT_DATA_CHAR);
2973
2974		kstat_named_init(&sysksp->status2, STAT2_KSTAT_NAMED,
2975			KSTAT_DATA_CHAR);
2976
2977		kstat_named_init(&sysksp->clk_freq2, CLK_FREQ2_KSTAT_NAMED,
2978			KSTAT_DATA_CHAR);
2979
2980		kstat_named_init(&sysksp->fan_status, FAN_KSTAT_NAMED,
2981			KSTAT_DATA_CHAR);
2982
2983		kstat_named_init(&sysksp->key_status, KEY_KSTAT_NAMED,
2984			KSTAT_DATA_CHAR);
2985
2986		kstat_named_init(&sysksp->power_state, POWER_KSTAT_NAMED,
2987			KSTAT_DATA_INT32);
2988
2989		kstat_named_init(&sysksp->clk_ver, CLK_VER_KSTAT_NAME,
2990			KSTAT_DATA_CHAR);
2991
2992		ksp->ks_update = sysctrl_kstat_update;
2993		ksp->ks_private = (void *)softsp;
2994		kstat_install(ksp);
2995	}
2996
2997	if ((tksp = kstat_create("unix", CLOCK_BOARD_INDEX,
2998	    OVERTEMP_KSTAT_NAME, "misc", KSTAT_TYPE_RAW,
2999	    sizeof (struct temp_stats), KSTAT_FLAG_PERSISTENT)) == NULL) {
3000		cmn_err(CE_WARN, "sysctrl%d: kstat_create failed",
3001			ddi_get_instance(softsp->dip));
3002	} else {
3003		tksp->ks_update = overtemp_kstat_update;
3004		tksp->ks_private = (void *)&softsp->tempstat;
3005		kstat_install(tksp);
3006	}
3007
3008	if ((ttsp = kstat_create("unix", CLOCK_BOARD_INDEX,
3009	    TEMP_OVERRIDE_KSTAT_NAME, "misc", KSTAT_TYPE_RAW, sizeof (short),
3010		KSTAT_FLAG_PERSISTENT | KSTAT_FLAG_WRITABLE)) == NULL) {
3011		cmn_err(CE_WARN, "sysctrl%d: kstat_create failed",
3012			ddi_get_instance(softsp->dip));
3013	} else {
3014		ttsp->ks_update = temp_override_kstat_update;
3015		ttsp->ks_private = (void *)&softsp->tempstat.override;
3016		kstat_install(ttsp);
3017	}
3018
3019	if ((pksp = kstat_create("unix", ddi_get_instance(softsp->dip),
3020	    PSSHAD_KSTAT_NAME, "misc", KSTAT_TYPE_RAW,
3021	    SYS_PS_COUNT, KSTAT_FLAG_PERSISTENT)) == NULL) {
3022		cmn_err(CE_WARN, "sysctrl%d: kstat_create failed",
3023			ddi_get_instance(softsp->dip));
3024	} else {
3025		pksp->ks_update = psstat_kstat_update;
3026		pksp->ks_private = (void *)softsp;
3027		kstat_install(pksp);
3028	}
3029}
3030
3031static int
3032sysctrl_kstat_update(kstat_t *ksp, int rw)
3033{
3034	struct sysctrl_kstat *sysksp;
3035	struct sysctrl_soft_state *softsp;
3036
3037	sysksp = (struct sysctrl_kstat *)(ksp->ks_data);
3038	softsp = (struct sysctrl_soft_state *)(ksp->ks_private);
3039
3040	/* this is a read-only kstat. Exit on a write */
3041
3042	if (rw == KSTAT_WRITE) {
3043		return (EACCES);
3044	} else {
3045		/*
3046		 * copy the current state of the hardware into the
3047		 * kstat structure.
3048		 */
3049		sysksp->csr.value.c[0] = *(softsp->csr);
3050		sysksp->status1.value.c[0] = *(softsp->status1);
3051		sysksp->status2.value.c[0] = *(softsp->status2);
3052		sysksp->clk_freq2.value.c[0] = *(softsp->clk_freq2);
3053
3054		sysksp->fan_status.value.c[0] = softsp->pps_fan_external_state;
3055		sysksp->key_status.value.c[0] = softsp->key_shadow;
3056		sysksp->power_state.value.i32 = softsp->power_state;
3057
3058		/*
3059		 * non-existence of the clock version register returns the
3060		 * value 0xff when the hardware register location is read
3061		 */
3062		if (softsp->clk_ver != NULL)
3063			sysksp->clk_ver.value.c[0] = *(softsp->clk_ver);
3064		else
3065			sysksp->clk_ver.value.c[0] = (char)0xff;
3066	}
3067	return (0);
3068}
3069
3070static int
3071psstat_kstat_update(kstat_t *ksp, int rw)
3072{
3073	struct sysctrl_soft_state *softsp;
3074	uchar_t *ptr = (uchar_t *)(ksp->ks_data);
3075	int ps;
3076
3077	softsp = (struct sysctrl_soft_state *)(ksp->ks_private);
3078
3079	if (rw == KSTAT_WRITE) {
3080		return (EACCES);
3081	} else {
3082		for (ps = 0; ps < SYS_PS_COUNT; ps++) {
3083			*ptr++ = softsp->ps_stats[ps].dcshadow;
3084		}
3085	}
3086	return (0);
3087}
3088
3089static void
3090sysctrl_thread_wakeup(void *arg)
3091{
3092	int type = (int)(uintptr_t)arg;
3093
3094	/*
3095	 * grab mutex to guarantee that our wakeup call
3096	 * arrives after we go to sleep -- so we can't sleep forever.
3097	 */
3098	mutex_enter(&sslist_mutex);
3099	switch (type) {
3100	case OVERTEMP_POLL:
3101		cv_signal(&overtemp_cv);
3102		break;
3103	case KEYSWITCH_POLL:
3104		cv_signal(&keyswitch_cv);
3105		break;
3106	default:
3107		cmn_err(CE_WARN, "sysctrl: invalid type %d to wakeup\n", type);
3108		break;
3109	}
3110	mutex_exit(&sslist_mutex);
3111}
3112
3113static void
3114sysctrl_overtemp_poll(void)
3115{
3116	struct sysctrl_soft_state *list;
3117	callb_cpr_t cprinfo;
3118
3119	CALLB_CPR_INIT(&cprinfo, &sslist_mutex, callb_generic_cpr, "overtemp");
3120
3121	/* The overtemp data structures are protected by a mutex. */
3122	mutex_enter(&sslist_mutex);
3123
3124	while (sysctrl_do_overtemp_thread) {
3125
3126		for (list = sys_list; list != NULL; list = list->next) {
3127			if (list->temp_reg != NULL) {
3128				update_temp(list->pdip, &list->tempstat,
3129					*(list->temp_reg));
3130			}
3131		}
3132
3133		CALLB_CPR_SAFE_BEGIN(&cprinfo);
3134
3135		/* now have this thread sleep for a while */
3136		(void) timeout(sysctrl_thread_wakeup, (void *)OVERTEMP_POLL,
3137			overtemp_timeout_hz);
3138
3139		cv_wait(&overtemp_cv, &sslist_mutex);
3140
3141		CALLB_CPR_SAFE_END(&cprinfo, &sslist_mutex);
3142	}
3143	CALLB_CPR_EXIT(&cprinfo);
3144	thread_exit();
3145	/* NOTREACHED */
3146}
3147
3148static void
3149sysctrl_keyswitch_poll(void)
3150{
3151	struct sysctrl_soft_state *list;
3152	callb_cpr_t cprinfo;
3153
3154	CALLB_CPR_INIT(&cprinfo, &sslist_mutex, callb_generic_cpr, "keyswitch");
3155
3156	/* The keyswitch data strcutures are protected by a mutex. */
3157	mutex_enter(&sslist_mutex);
3158
3159	while (sysctrl_do_keyswitch_thread) {
3160
3161		for (list = sys_list; list != NULL; list = list->next) {
3162			if (list->status1 != NULL)
3163				update_key_state(list);
3164		}
3165
3166		CALLB_CPR_SAFE_BEGIN(&cprinfo);
3167
3168		/* now have this thread sleep for a while */
3169		(void) timeout(sysctrl_thread_wakeup, (void *)KEYSWITCH_POLL,
3170			keyswitch_timeout_hz);
3171
3172		cv_wait(&keyswitch_cv, &sslist_mutex);
3173
3174		CALLB_CPR_SAFE_END(&cprinfo, &sslist_mutex);
3175	}
3176	CALLB_CPR_EXIT(&cprinfo);
3177	thread_exit();
3178	/* NOTREACHED */
3179}
3180
3181/*
3182 * check the key switch position for state changes
3183 */
3184static void
3185update_key_state(struct sysctrl_soft_state *list)
3186{
3187	enum keyswitch_state key;
3188
3189	/*
3190	 * snapshot current hardware key position
3191	 */
3192	if (*(list->status1) & SYS_NOT_SECURE)
3193		key = KEY_NOT_SECURE;
3194	else
3195		key = KEY_SECURE;
3196
3197	/*
3198	 * check for state transition
3199	 */
3200	if (key != list->key_shadow) {
3201
3202		/*
3203		 * handle state transition
3204		 */
3205		switch (list->key_shadow) {
3206		case KEY_BOOT:
3207			cmn_err(CE_CONT, "?sysctrl%d: Key switch is%sin the "
3208			    "secure position\n", ddi_get_instance(list->dip),
3209			    (key == KEY_SECURE) ? " " : " not ");
3210			list->key_shadow = key;
3211			break;
3212		case KEY_SECURE:
3213		case KEY_NOT_SECURE:
3214			cmn_err(CE_NOTE, "sysctrl%d: Key switch has changed"
3215			    " to the %s position",
3216			    ddi_get_instance(list->dip),
3217			    (key == KEY_SECURE) ? "secure" : "not-secure");
3218			list->key_shadow = key;
3219			break;
3220		default:
3221			cmn_err(CE_CONT,
3222			    "?sysctrl%d: Key switch is in an unknown position,"
3223			    "treated as being in the %s position\n",
3224			    ddi_get_instance(list->dip),
3225			    (list->key_shadow == KEY_SECURE) ?
3226			    "secure" : "not-secure");
3227			break;
3228		}
3229	}
3230}
3231
3232/*
3233 * consider key switch position when handling an abort sequence
3234 */
3235static void
3236sysctrl_abort_seq_handler(char *msg)
3237{
3238	struct sysctrl_soft_state *list;
3239	uint_t secure = 0;
3240	char buf[64], inst[4];
3241
3242
3243	/*
3244	 * if any of the key switch positions are secure,
3245	 * then disallow entry to the prom/debugger
3246	 */
3247	mutex_enter(&sslist_mutex);
3248	buf[0] = (char)0;
3249	for (list = sys_list; list != NULL; list = list->next) {
3250		if (!(*(list->status1) & SYS_NOT_SECURE)) {
3251			if (secure++)
3252				(void) strcat(buf, ",");
3253			/*
3254			 * XXX: later, replace instance number with nodeid
3255			 */
3256			(void) sprintf(inst, "%d", ddi_get_instance(list->dip));
3257			(void) strcat(buf, inst);
3258		}
3259	}
3260	mutex_exit(&sslist_mutex);
3261
3262	if (secure) {
3263		cmn_err(CE_CONT,
3264			"!sysctrl(%s): ignoring debug enter sequence\n", buf);
3265	} else {
3266		cmn_err(CE_CONT, "!sysctrl: allowing debug enter\n");
3267		debug_enter(msg);
3268	}
3269}
3270
3271#define	TABLE_END	0xFF
3272
3273struct uart_cmd {
3274	uchar_t reg;
3275	uchar_t data;
3276};
3277
3278/*
3279 * Time constant defined by this formula:
3280 *	((4915200/32)/(baud) -2)
3281 */
3282
3283struct uart_cmd uart_table[] = {
3284	{ 0x09, 0xc0 },	/* Force hardware reset */
3285	{ 0x04, 0x46 },	/* X16 clock mode, 1 stop bit/char, no parity */
3286	{ 0x03, 0xc0 },	/* Rx is 8 bits/char */
3287	{ 0x05, 0xe2 },	/* DTR, Tx is 8 bits/char, RTS */
3288	{ 0x09, 0x02 },	/* No vector returned on interrupt */
3289	{ 0x0b, 0x55 },	/* Rx Clock = Tx Clock = BR generator = ~TRxC OUT */
3290	{ 0x0c, 0x0e },	/* Time Constant = 0x000e for 9600 baud */
3291	{ 0x0d, 0x00 },	/* High byte of time constant */
3292	{ 0x0e, 0x02 },	/* BR generator comes from Z-SCC's PCLK input */
3293	{ 0x03, 0xc1 },	/* Rx is 8 bits/char, Rx is enabled */
3294	{ 0x05, 0xea },	/* DTR, Tx is 8 bits/char, Tx is enabled, RTS */
3295	{ 0x0e, 0x03 },	/* BR comes from PCLK, BR generator is enabled */
3296	{ 0x00, 0x30 },	/* Error reset */
3297	{ 0x00, 0x30 },	/* Error reset */
3298	{ 0x00, 0x10 },	/* external status reset */
3299	{ 0x03, 0xc1 },	/* Rx is 8 bits/char, Rx is enabled */
3300	{ TABLE_END, 0x0 }
3301};
3302
3303static void
3304init_remote_console_uart(struct sysctrl_soft_state *softsp)
3305{
3306	int i = 0;
3307
3308	/*
3309	 * Serial chip expects software to write to the control
3310	 * register first with the desired register number. Then
3311	 * write to the control register with the desired data.
3312	 * So walk thru table writing the register/data pairs to
3313	 * the serial port chip.
3314	 */
3315	while (uart_table[i].reg != TABLE_END) {
3316		*(softsp->rcons_ctl) = uart_table[i].reg;
3317		*(softsp->rcons_ctl) = uart_table[i].data;
3318		i++;
3319	}
3320}
3321
3322/*
3323 * return the slot information of the system
3324 *
3325 * function take a sysctrl_soft_state, so it's ready for sunfire+
3326 * change which requires 2 registers to decide the system type.
3327 */
3328static void
3329sysc_slot_info(int nslots, int *start, int *limit, int *incr)
3330{
3331	switch (nslots) {
3332	case 8:
3333		*start = 0;
3334		*limit = 8;
3335		*incr = 1;
3336		break;
3337	case 5:
3338		*start = 1;
3339		*limit = 10;
3340		*incr = 2;
3341		break;
3342	case 4:
3343		*start = 1;
3344		*limit = 8;
3345		*incr = 2;
3346		break;
3347	case 0:
3348	case 16:
3349	default:
3350		*start = 0;
3351		*limit = 16;
3352		*incr = 1;
3353		break;
3354	}
3355}
3356
3357/*
3358 * reinitialize the Remote Console on the clock board
3359 *
3360 * with V5_AUX power outage the Remote Console ends up in
3361 * unknown state and has to be reinitilized if it was enabled
3362 * initially.
3363 */
3364static void
3365rcons_reinit(struct sysctrl_soft_state *softsp)
3366{
3367	uchar_t tmp_reg;
3368
3369	if (!(softsp->rcons_ctl))
3370		/*
3371		 * There is no OBP register set for the remote console UART,
3372		 * so offset from the last register set, the misc register
3373		 * set, in order to map in the remote console UART.
3374		 */
3375		if (ddi_map_regs(softsp->dip, 1, (caddr_t *)&softsp->rcons_ctl,
3376		    RMT_CONS_OFFSET, RMT_CONS_LEN)) {
3377			cmn_err(CE_WARN, "Unable to reinitialize "
3378				"remote console.");
3379			return;
3380		}
3381
3382
3383	/* Disable the remote console reset control bits. */
3384	*(softsp->clk_freq2) &= ~RCONS_UART_EN;
3385
3386	/* flush the hardware buffers */
3387	tmp_reg = *(softsp->csr);
3388
3389	/*
3390	 * Program the UART to watch ttya console.
3391	 */
3392	init_remote_console_uart(softsp);
3393
3394	/* Now enable the remote console reset control bits. */
3395	*(softsp->clk_freq2) |= RCONS_UART_EN;
3396
3397	/* flush the hardware buffers */
3398	tmp_reg = *(softsp->csr);
3399
3400	/* print some info for user to watch */
3401	cmn_err(CE_NOTE, "Remote console reinitialized");
3402#ifdef lint
3403	tmp_reg = tmp_reg;
3404#endif
3405}
3406