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