sysctrl_dr.c revision 1341:6d7c4f090a72
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include <sys/types.h>
30#include <sys/conf.h>
31#include <sys/ddi.h>
32#include <sys/sunddi.h>
33#include <sys/sunndi.h>
34#include <sys/ddi_impldefs.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/machsystm.h>
47#include <sys/modctl.h>
48#include <sys/callb.h>
49#include <sys/file.h>
50#include <sys/open.h>
51#include <sys/stat.h>
52#include <sys/fhc.h>
53#include <sys/sysctrl.h>
54#include <sys/jtag.h>
55#include <sys/ac.h>
56#include <sys/simmstat.h>
57#include <sys/clock.h>
58#include <sys/promif.h>
59#include <sys/promimpl.h>
60#include <sys/cpr.h>
61#include <sys/cpuvar.h>
62#include <sys/machcpuvar.h>
63#include <sys/x_call.h>
64
65#ifdef DEBUG
66struct	regs_data {
67	caddr_t msg;
68	u_longlong_t physaddr;
69	uint_t pre_dsct;
70	uint_t post_dsct;
71	uint_t eflag;
72	uint_t oflag;
73};
74
75static	struct regs_data reg_tmpl[] = {
76	"AC  Control and Status reg = 0x", AC_BCSR(0), 0, 0, 0, 0,
77	"FHC Control and Status reg = 0x", FHC_CTRL(0), 0, 0, 0, 0,
78	"JTAG Control reg = 0x", FHC_JTAG_CTRL(0), 0, 0, 0, 0,
79	"Interrupt Group Number reg = 0x", FHC_IGN(0), 0, 0, 0, 0,
80	"System Interrupt Mapping reg = 0x", FHC_SIM(0), 0, 0, 0, 0,
81	"System Interrupt State reg = 0x", FHC_SSM(0), 0, 0, 0, 0,
82	"UART Interrupt Mapping reg = 0x", FHC_UIM(0), 0, 0, 0, 0,
83	"UART Interrupt State reg = 0x", FHC_USM(0), 0, 0, 0, 0
84};
85
86#define	NUM_REG  (sizeof (reg_tmpl)/sizeof (reg_tmpl[0]))
87static	struct regs_data reg_dt[MAX_BOARDS][NUM_REG];
88
89int sysctrl_enable_regdump = 0;
90
91static void precache_regdump(int board);
92static void display_regdump(void);
93static void boardstat_regdump(void);
94
95#endif /* DEBUG */
96
97extern void bd_remove_poll(struct sysctrl_soft_state *);
98extern int sysctrl_getsystem_freq(void);
99extern enum power_state compute_power_state(struct sysctrl_soft_state *, int);
100extern enum temp_state fhc_env_temp_state(int);
101extern int sysctrl_hotplug_disabled;
102/* Let user disable Sunfire Dynamic Reconfiguration */
103int enable_dynamic_reconfiguration = 1;
104
105int enable_redist = 1;
106
107static void sysc_dr_err_decode(sysc_dr_handle_t *, dev_info_t *, int);
108static uint_t
109sysc_policy_enough_cooling(struct sysctrl_soft_state *softsp,
110	sysc_cfga_stat_t *sysc_stat, uint_t ps_mutex_is_held);
111static uint_t
112sysc_policy_enough_precharge(struct sysctrl_soft_state *softsp,
113	sysc_cfga_stat_t *sysc_stat);
114static uint_t
115sysc_policy_enough_power(struct sysctrl_soft_state *softsp,
116	int plus_load, uint_t ps_mutex_is_held);
117static uint_t
118sysc_policy_hardware_compatible(struct sysctrl_soft_state *softsp,
119	sysc_cfga_stat_t *sysc_stat, sysc_cfga_pkt_t *pkt);
120static void sysc_policy_empty_condition(
121	struct sysctrl_soft_state *softsp,
122	sysc_cfga_stat_t *sysc_stat, uint_t failure,
123	uint_t ps_mutex_is_held);
124static void sysc_policy_disconnected_condition(
125	struct sysctrl_soft_state *softsp,
126	sysc_cfga_stat_t *sysc_stat, uint_t failure,
127	uint_t ps_mutex_is_held);
128static void sysc_policy_connected_condition(struct sysctrl_soft_state *softsp,
129		sysc_cfga_stat_t *sysc_stat,
130		uint_t ps_mutex_is_held);
131static void sysc_policy_set_condition(void *sp, sysc_cfga_stat_t *sysc_stat,
132				uint_t ps_mutex_is_held);
133static void sysc_policy_audit_messages(sysc_audit_evt_t event,
134		sysc_cfga_stat_t *sysc_stat);
135
136static void sysctrl_post_config_change(struct sysctrl_soft_state *softsp);
137static int sysc_bd_connect(int, sysc_cfga_pkt_t *);
138static int sysc_bd_disconnect(int, sysc_cfga_pkt_t *);
139static int sysc_bd_configure(int, sysc_cfga_pkt_t *);
140static int sysc_bd_unconfigure(int, sysc_cfga_pkt_t *);
141
142static void sysc_dr_init(sysc_dr_handle_t *handle);
143static void sysc_dr_uninit(sysc_dr_handle_t *handle);
144static int sysc_dr_attach(sysc_dr_handle_t *handle, int board);
145static int sysc_dr_detach(sysc_dr_handle_t *handle, int board);
146
147static int sysc_prom_select(pnode_t pnode, void *arg, uint_t flag);
148static void sysc_branch_callback(dev_info_t *rdip, void *arg, uint_t flags);
149
150static int find_and_setup_cpu(int);
151
152static int sysc_board_connect_supported(enum board_type);
153
154static int find_and_setup_cpu_start(void *cpuid_arg, int has_changed);
155/*
156 * This function will basically do a prediction on the power state
157 * based on adding one additional load to the equation implemented
158 * by the function compute_power_state.
159 */
160/*ARGSUSED*/
161static uint_t
162sysc_policy_enough_power(struct sysctrl_soft_state *softsp,
163	int plus_load, uint_t ps_mutex_is_held)
164{
165	int retval = 0;
166
167	ASSERT(softsp);
168
169	if (!ps_mutex_is_held) {
170		mutex_enter(&softsp->ps_fail_lock);
171	}
172
173	/*
174	 * note that we add one more load
175	 * to the equation in compute_power_state
176	 * and the answer better be REDUNDANT or
177	 * MINIMUM before proceeding.
178	 */
179	switch (compute_power_state(softsp, plus_load)) {
180		case REDUNDANT:
181		case MINIMUM:
182			retval = 1;
183			break;
184		case BELOW_MINIMUM:
185		default:
186			break;
187	}
188
189	if (!ps_mutex_is_held) {
190		mutex_exit(&softsp->ps_fail_lock);
191	}
192	return (retval);
193}
194
195/*
196 * This function gropes through the shadow registers in the sysctrl soft_state
197 * for the core power supply status, since fan status for them are ORed into
198 * the same status bit, and all other remaining fans.
199 */
200static uint_t
201sysc_policy_enough_cooling(struct sysctrl_soft_state *softsp,
202	sysc_cfga_stat_t *sysc_stat, uint_t ps_mutex_is_held)
203{
204	int	retval = 0;
205
206	if (!ps_mutex_is_held) {
207		mutex_enter(&softsp->ps_fail_lock);
208	}
209
210	/*
211	 * check the power supply in the slot in question
212	 * for fans then check all the common fans.
213	 */
214	retval = ((softsp->ps_stats[FHC_BOARD2PS(sysc_stat->board)].pshadow ==
215			PRES_IN) &&
216		(softsp->ps_stats[FHC_BOARD2PS(sysc_stat->board)].dcshadow ==
217			PS_OK));
218	if (!ps_mutex_is_held) {
219		mutex_exit(&softsp->ps_fail_lock);
220	}
221	return (retval);
222}
223
224/*
225 * This function will check all precharge voltage status.
226 */
227/*ARGSUSED*/
228static uint_t
229sysc_policy_enough_precharge(struct sysctrl_soft_state *softsp,
230	sysc_cfga_stat_t *sysc_stat)
231{
232	int	retval = 0;
233	int	ppsval = 0;
234
235	mutex_enter(&softsp->ps_fail_lock);
236
237		/*
238		 *	note that we always have to explicitly check
239		 *	the peripheral power supply for precharge since it
240		 *	supplies all of the precharge voltages.
241		 */
242	ppsval = (softsp->ps_stats[SYS_PPS0_INDEX].pshadow == PRES_IN) &&
243		(softsp->ps_stats[SYS_PPS0_INDEX].dcshadow == PS_OK);
244
245		/*
246		 *	check all the precharge status
247		 */
248	retval = ((softsp->ps_stats[SYS_V3_PCH_INDEX].pshadow == PRES_IN) &&
249		(softsp->ps_stats[SYS_V3_PCH_INDEX].dcshadow == PS_OK) &&
250		(softsp->ps_stats[SYS_V5_PCH_INDEX].pshadow == PRES_IN) &&
251		(softsp->ps_stats[SYS_V5_PCH_INDEX].dcshadow == PS_OK));
252
253	mutex_exit(&softsp->ps_fail_lock);
254	return (retval&&ppsval);
255}
256
257static int Fsys;
258
259/*
260 * This function should only be called once as we may
261 * zero the clock board registers to indicate a configuration change.
262 * The code to calculate the bus frequency has been removed and we
263 * read the eeprom property instead. Another static Fmod (module
264 * frequency may be needed later but so far it is commented out.
265 */
266void
267set_clockbrd_info(void)
268{
269	uint_t clock_freq = 0;
270
271	pnode_t root = prom_nextnode((pnode_t)0);
272	(void) prom_getprop(root, "clock-frequency", (caddr_t)&clock_freq);
273	Fsys = clock_freq / 1000000;
274}
275
276#define	abs(x)	((x) < 0 ? -(x) : (x))
277
278/*ARGSUSED*/
279static uint_t
280sysc_policy_hardware_compatible(struct sysctrl_soft_state *softsp,
281	sysc_cfga_stat_t *sysc_stat, sysc_cfga_pkt_t *pkt)
282{
283	int status;
284
285	ASSERT(Fsys > 0);
286
287	/* Only allow DR operations on supported hardware */
288	switch (sysc_stat->type) {
289	case CPU_BOARD: {
290#ifdef RFE_4174486
291		int i;
292		int cpu_freq;
293		int sram_mode;
294
295		ASSERT(Fmod > 0);
296
297		cpu_freq = CPU->cpu_type_info.pi_clock;
298
299		if (abs(cpu_freq - Fmod) < 8)
300			sram_mode = 1;
301		else
302			sram_mode = 2;
303
304		status = TRUE;
305		for (i = 0; i < 2; i++) {
306			/*
307			 * XXX: Add jtag code which rescans disabled boards.
308			 * For the time being disabled boards are not
309			 * checked for compatibility when cpu_speed is 0.
310			 */
311			if (sysc_stat->bd.cpu[i].cpu_speed == 0)
312				continue;
313
314			if (sysc_stat->bd.cpu[i].cpu_speed < cpu_freq) {
315				cmn_err(CE_WARN, "board %d, cpu module %c "
316					"rated at %d Mhz, system freq %d Mhz",
317					sysc_stat->board, (i == 0) ? 'A' : 'B',
318					sysc_stat->bd.cpu[i].cpu_speed,
319					cpu_freq);
320				status = FALSE;
321			}
322
323			if (sram_mode != sysc_stat->bd.cpu[i].cpu_sram_mode) {
324				cmn_err(CE_WARN, "board %d, cpu module %c "
325					"incompatible sram mode of %dx, "
326					"system is %dx", sysc_stat->board,
327					(i == 0) ? 'A' : 'B',
328					sysc_stat->bd.cpu[i].cpu_sram_mode,
329					sram_mode);
330				status = FALSE;
331			}
332		}
333		break;
334#endif /* RFE_4174486 */
335	}
336
337	case MEM_BOARD:
338	case IO_2SBUS_BOARD:
339	case IO_SBUS_FFB_BOARD:
340	case IO_PCI_BOARD:
341	case IO_2SBUS_SOCPLUS_BOARD:
342	case IO_SBUS_FFB_SOCPLUS_BOARD:
343		status = TRUE;
344		break;
345
346	case CLOCK_BOARD:
347	case DISK_BOARD:
348	default:
349		status = FALSE;		/* default is not supported */
350		break;
351	}
352
353	if (status == FALSE)
354		return (status);
355
356	/* Check for Sunfire boards in a Sunfire+ system */
357	if (status == TRUE && Fsys > 84 && !fhc_bd_is_plus(sysc_stat->board)) {
358		(void) snprintf(pkt->errbuf, SYSC_OUTPUT_LEN,
359		    "not 100 MHz capable   ");
360		cmn_err(CE_WARN, "board %d, is not capable of running at "
361		    "current system clock (%dMhz)", sysc_stat->board, Fsys);
362
363		status = FALSE;
364	}
365
366	return (status);
367}
368
369/*
370 * This function is called to check the policy for a request to transition
371 * to the connected state from the disconnected state. The generic policy
372 * is to do sanity checks again before going live.
373 */
374/*ARGSUSED*/
375int
376sysc_policy_connect(struct sysctrl_soft_state *softsp,
377		sysc_cfga_pkt_t *pkt, sysc_cfga_stat_t *sysc_stat)
378{
379	int retval;
380
381	ASSERT(fhc_bdlist_locked());
382
383	DPRINTF(SYSC_DEBUG, ("Previous RState: %d\n", sysc_stat->rstate));
384	DPRINTF(SYSC_DEBUG, ("Previous OState: %d\n", sysc_stat->ostate));
385
386	switch (sysc_stat->rstate) {
387	case SYSC_CFGA_RSTATE_DISCONNECTED:
388		/*
389		 * Safety policy: only allow connect if board is UNKNOWN cond.
390		 * cold start board will be demoted to UNKNOWN cond when
391		 * disconnected
392		 */
393		if (sysc_stat->condition != SYSC_CFGA_COND_UNKNOWN) {
394			SYSC_ERR_SET(pkt, SYSC_ERR_COND);
395			return (EINVAL);
396		}
397
398		if (!enable_dynamic_reconfiguration) {
399			SYSC_ERR_SET(pkt, SYSC_ERR_NON_DR_PROM);
400			return (ENOTSUP);
401		}
402
403		if (sysctrl_hotplug_disabled) {
404			SYSC_ERR_SET(pkt, SYSC_ERR_HOTPLUG);
405			return (ENOTSUP);
406		}
407
408		/* Check PROM support. */
409		if (!sysc_board_connect_supported(sysc_stat->type)) {
410			cmn_err(CE_WARN, "%s board %d connect"
411			    " is not supported by firmware.",
412			    fhc_bd_typestr(sysc_stat->type), sysc_stat->board);
413			SYSC_ERR_SET(pkt, SYSC_ERR_HW_COMPAT);
414			return (ENOTSUP);
415		}
416
417		if (!sysc_policy_enough_power(softsp, TRUE, FALSE)) {
418			SYSC_ERR_SET(pkt, SYSC_ERR_POWER);
419			return (EAGAIN);
420		}
421
422		if (!sysc_policy_enough_precharge(softsp, sysc_stat)) {
423			SYSC_ERR_SET(pkt, SYSC_ERR_PRECHARGE);
424			return (EAGAIN);
425		}
426
427		if (!sysc_policy_enough_cooling(softsp, sysc_stat, FALSE)) {
428			SYSC_ERR_SET(pkt, SYSC_ERR_COOLING);
429			return (EAGAIN);
430		}
431
432		if (!sysc_policy_hardware_compatible(softsp, sysc_stat, pkt)) {
433			SYSC_ERR_SET(pkt, SYSC_ERR_HW_COMPAT);
434			return (ENOTSUP);
435		}
436		sysc_policy_audit_messages(SYSC_AUDIT_RSTATE_CONNECT,
437			sysc_stat);
438
439		retval = sysc_bd_connect(sysc_stat->board, pkt);
440		if (!retval) {
441			sysc_stat->rstate = SYSC_CFGA_RSTATE_CONNECTED;
442			sysc_policy_connected_condition(softsp,
443				sysc_stat, FALSE);
444			sysc_policy_audit_messages(SYSC_AUDIT_RSTATE_SUCCEEDED,
445				sysc_stat);
446		} else {
447			uint_t prom_failure;
448
449			prom_failure = (retval == EIO &&
450			    pkt->cmd_cfga.errtype == SYSC_ERR_PROM) ?
451			    TRUE : FALSE;
452			sysc_policy_disconnected_condition(softsp,
453				sysc_stat, prom_failure, FALSE);
454			sysc_policy_audit_messages(
455				SYSC_AUDIT_RSTATE_CONNECT_FAILED,
456				sysc_stat);
457		}
458		break;
459	case SYSC_CFGA_RSTATE_EMPTY:
460	case SYSC_CFGA_RSTATE_CONNECTED:
461	default:
462		SYSC_ERR_SET(pkt, SYSC_ERR_RSTATE);
463		retval = EINVAL;
464		break;
465	}
466
467	DPRINTF(SYSC_DEBUG, ("Current RState: %d\n", sysc_stat->rstate));
468	DPRINTF(SYSC_DEBUG, ("Current OState: %d\n", sysc_stat->ostate));
469	DPRINTF(SYSC_DEBUG, ("Current Condition: %d\n", sysc_stat->condition));
470
471	return (retval);
472}
473
474/*
475 * This function is called to check the policy for a request to transition
476 * to the disconnected state from the connected/unconfigured state only.
477 * All other requests are invalid.
478 */
479/*ARGSUSED*/
480int
481sysc_policy_disconnect(struct sysctrl_soft_state *softsp,
482			sysc_cfga_pkt_t *pkt, sysc_cfga_stat_t *sysc_stat)
483{
484	int retval;
485
486	ASSERT(fhc_bdlist_locked());
487
488	DPRINTF(SYSC_DEBUG, ("Previous RState: %d\n", sysc_stat->rstate));
489	DPRINTF(SYSC_DEBUG, ("Previous OState: %d\n", sysc_stat->ostate));
490
491	switch (sysc_stat->rstate) {
492	case SYSC_CFGA_RSTATE_CONNECTED:
493		switch (sysc_stat->ostate) {
494		case SYSC_CFGA_OSTATE_UNCONFIGURED:
495			if (!enable_dynamic_reconfiguration) {
496				SYSC_ERR_SET(pkt, SYSC_ERR_NON_DR_PROM);
497				return (ENOTSUP);
498			}
499
500			/* Check PROM support. */
501			if (!sysc_board_connect_supported(sysc_stat->type)) {
502				cmn_err(CE_WARN, "%s board %d disconnect"
503				    " is not supported by firmware.",
504				    fhc_bd_typestr(sysc_stat->type),
505				    sysc_stat->board);
506				SYSC_ERR_SET(pkt, SYSC_ERR_HW_COMPAT);
507				return (ENOTSUP);
508			}
509
510			if (!sysc_policy_hardware_compatible(softsp,
511				sysc_stat, pkt)) {
512				cmn_err(CE_WARN, "%s board %d disconnect"
513				" is not yet supported.",
514				fhc_bd_typestr(sysc_stat->type),
515					sysc_stat->board);
516				SYSC_ERR_SET(pkt, SYSC_ERR_HW_COMPAT);
517				return (ENOTSUP);
518			}
519
520			if (fhc_bd_is_jtag_master(sysc_stat->board)) {
521				sysc_policy_update(softsp, sysc_stat,
522					SYSC_EVT_BD_CORE_RESOURCE_DISCONNECT);
523				SYSC_ERR_SET(pkt, SYSC_ERR_CORE_RESOURCE);
524				return (EINVAL);
525			}
526
527			sysc_policy_audit_messages(SYSC_AUDIT_RSTATE_DISCONNECT,
528				sysc_stat);
529
530			retval = sysc_bd_disconnect(sysc_stat->board, pkt);
531			if (!retval) {
532				sysc_stat->rstate =
533					SYSC_CFGA_RSTATE_DISCONNECTED;
534				DPRINTF(SYSCTRL_ATTACH_DEBUG,
535				    ("disconnect starting bd_remove_poll()"));
536				bd_remove_poll(softsp);
537				sysc_policy_disconnected_condition(
538					softsp,
539					sysc_stat, FALSE, FALSE);
540				sysc_policy_audit_messages(
541					SYSC_AUDIT_RSTATE_SUCCEEDED,
542					sysc_stat);
543				cmn_err(CE_NOTE,
544					"board %d is ready to remove",
545					sysc_stat->board);
546			} else {
547				sysc_policy_connected_condition(
548					softsp, sysc_stat, FALSE);
549				sysc_policy_audit_messages(
550					SYSC_AUDIT_RSTATE_DISCONNECT_FAILED,
551					sysc_stat);
552			}
553			break;
554		case SYSC_CFGA_OSTATE_CONFIGURED:
555		default:
556			SYSC_ERR_SET(pkt, SYSC_ERR_OSTATE);
557			retval = EINVAL;
558			break;
559		}
560		break;
561	case SYSC_CFGA_RSTATE_EMPTY:
562	case SYSC_CFGA_RSTATE_DISCONNECTED:
563	default:
564		SYSC_ERR_SET(pkt, SYSC_ERR_RSTATE);
565		retval = EINVAL;
566		break;
567	}
568
569	DPRINTF(SYSC_DEBUG, ("Current RState: %d\n", sysc_stat->rstate));
570	DPRINTF(SYSC_DEBUG, ("Current OState: %d\n", sysc_stat->ostate));
571	DPRINTF(SYSC_DEBUG, ("Current Condition: %d\n", sysc_stat->condition));
572
573	return (retval);
574}
575
576/*
577 * This function is called to check the policy for a request to transition
578 * from the connected/configured state to the connected/unconfigured state only.
579 * All other requests are invalid.
580 */
581/*ARGSUSED*/
582int
583sysc_policy_unconfigure(struct sysctrl_soft_state *softsp,
584			sysc_cfga_pkt_t *pkt, sysc_cfga_stat_t *sysc_stat)
585{
586	int retval;
587
588	ASSERT(fhc_bdlist_locked());
589
590	DPRINTF(SYSC_DEBUG, ("Previous RState: %d\n", sysc_stat->rstate));
591	DPRINTF(SYSC_DEBUG, ("Previous OState: %d\n", sysc_stat->ostate));
592
593	switch (sysc_stat->ostate) {
594	case SYSC_CFGA_OSTATE_CONFIGURED:
595		if (!enable_dynamic_reconfiguration) {
596			SYSC_ERR_SET(pkt, SYSC_ERR_NON_DR_PROM);
597			return (ENOTSUP);
598		}
599
600		if (!sysc_policy_hardware_compatible(softsp, sysc_stat, pkt)) {
601			cmn_err(CE_WARN, "%s board %d unconfigure"
602			" is not yet supported.",
603			fhc_bd_typestr(sysc_stat->type), sysc_stat->board);
604			SYSC_ERR_SET(pkt, SYSC_ERR_HW_COMPAT);
605			return (ENOTSUP);
606		}
607
608		sysc_policy_audit_messages(SYSC_AUDIT_OSTATE_UNCONFIGURE,
609			sysc_stat);
610
611		retval = sysc_bd_unconfigure(sysc_stat->board, pkt);
612		if (!retval) {
613		    sysc_stat->ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
614		    sysc_policy_audit_messages(
615			SYSC_AUDIT_OSTATE_SUCCEEDED,
616			sysc_stat);
617		} else {
618		    sysc_policy_audit_messages(
619			SYSC_AUDIT_OSTATE_UNCONFIGURE_FAILED,
620			sysc_stat);
621		}
622		sysc_policy_connected_condition(softsp, sysc_stat, FALSE);
623		break;
624	case SYSC_CFGA_OSTATE_UNCONFIGURED:
625	default:
626		SYSC_ERR_SET(pkt, SYSC_ERR_OSTATE);
627		retval = EINVAL;
628		break;
629	}
630
631	DPRINTF(SYSC_DEBUG, ("Current RState: %d\n", sysc_stat->rstate));
632	DPRINTF(SYSC_DEBUG, ("Current OState: %d\n", sysc_stat->ostate));
633	DPRINTF(SYSC_DEBUG, ("Current Condition: %d\n", sysc_stat->condition));
634
635	return (retval);
636}
637
638/*
639 * This function is called to check the policy for a requested transition
640 * from either the connected/unconfigured state or the connected/configured
641 * state to the connected/configured state.  The redundant state transition
642 * is permitted for partially configured set of devices.  Basically, we
643 * retry the configure.
644 */
645/*ARGSUSED*/
646int
647sysc_policy_configure(struct sysctrl_soft_state *softsp,
648			sysc_cfga_pkt_t *pkt, sysc_cfga_stat_t *sysc_stat)
649{
650	int retval;
651
652	ASSERT(fhc_bdlist_locked());
653
654	DPRINTF(SYSC_DEBUG, ("Previous RState: %d\n", sysc_stat->rstate));
655	DPRINTF(SYSC_DEBUG, ("Previous OState: %d\n", sysc_stat->ostate));
656
657	switch (sysc_stat->rstate) {
658	case SYSC_CFGA_RSTATE_CONNECTED:
659		switch (sysc_stat->ostate) {
660		case SYSC_CFGA_OSTATE_UNCONFIGURED:
661			if (sysc_stat->condition != SYSC_CFGA_COND_OK) {
662				SYSC_ERR_SET(pkt, SYSC_ERR_COND);
663				return (EINVAL);
664			}
665
666			sysc_policy_audit_messages(SYSC_AUDIT_OSTATE_CONFIGURE,
667				sysc_stat);
668			retval = sysc_bd_configure(sysc_stat->board, pkt);
669			sysc_stat->ostate = SYSC_CFGA_OSTATE_CONFIGURED;
670			sysc_policy_connected_condition(softsp,
671				sysc_stat, FALSE);
672			if (!retval) {
673				sysc_policy_audit_messages(
674					SYSC_AUDIT_OSTATE_SUCCEEDED,
675					sysc_stat);
676			} else {
677				sysc_policy_audit_messages(
678					SYSC_AUDIT_OSTATE_CONFIGURE_FAILED,
679					sysc_stat);
680			}
681			break;
682		case SYSC_CFGA_OSTATE_CONFIGURED:
683			SYSC_ERR_SET(pkt, SYSC_ERR_OSTATE);
684			retval = ENOTSUP;
685			break;
686		default:
687			SYSC_ERR_SET(pkt, SYSC_ERR_OSTATE);
688			retval = EINVAL;
689			break;
690		}
691		break;
692	case SYSC_CFGA_RSTATE_EMPTY:
693	case SYSC_CFGA_RSTATE_DISCONNECTED:
694	default:
695		SYSC_ERR_SET(pkt, SYSC_ERR_RSTATE);
696		retval = EINVAL;
697		break;
698	}
699
700
701	DPRINTF(SYSC_DEBUG, ("Current RState: %d\n", sysc_stat->rstate));
702	DPRINTF(SYSC_DEBUG, ("Current OState: %d\n", sysc_stat->ostate));
703	DPRINTF(SYSC_DEBUG, ("Current Condition: %d\n", sysc_stat->condition));
704
705	return (retval);
706}
707
708/*ARGSUSED*/
709static void
710sysc_policy_empty_condition(struct sysctrl_soft_state *softsp,
711	sysc_cfga_stat_t *sysc_stat, uint_t failure,
712	uint_t ps_mutex_is_held)
713{
714	ASSERT(fhc_bdlist_locked());
715
716	switch (sysc_stat->condition) {
717	case SYSC_CFGA_COND_UNKNOWN:
718	case SYSC_CFGA_COND_OK:
719	case SYSC_CFGA_COND_FAILING:
720	case SYSC_CFGA_COND_FAILED:
721	/* nothing in the slot so just check power supplies */
722	case SYSC_CFGA_COND_UNUSABLE:
723	    if (sysc_policy_enough_cooling(softsp, sysc_stat,
724		ps_mutex_is_held) &&
725		sysc_policy_enough_power(softsp, FALSE,
726		ps_mutex_is_held)) {
727		sysc_stat->condition = SYSC_CFGA_COND_UNKNOWN;
728	    } else {
729		sysc_stat->condition = SYSC_CFGA_COND_UNUSABLE;
730	    }
731	    sysc_stat->last_change = gethrestime_sec();
732	    break;
733	default:
734	    ASSERT(FALSE);
735	    break;
736	}
737}
738/*ARGSUSED*/
739static void
740sysc_policy_disconnected_condition(struct sysctrl_soft_state *softsp,
741	sysc_cfga_stat_t *sysc_stat, uint_t failure,
742	uint_t ps_mutex_is_held)
743{
744	ASSERT(fhc_bdlist_locked());
745
746	if (failure) {
747		sysc_stat->condition = SYSC_CFGA_COND_FAILED;
748		sysc_stat->last_change = gethrestime_sec();
749		return;
750	}
751	switch (sysc_stat->condition) {
752	/*
753	 * if unknown, we have come from hotplug case so do a quick
754	 * reevaluation.
755	 */
756	case SYSC_CFGA_COND_UNKNOWN:
757	/*
758	 * if ok, we have come from connected to disconnected and we stay
759	 * ok until removed or reevaluate when reconnect.  We might have
760	 * experienced a ps fail so reevaluate the condition.
761	 */
762	case SYSC_CFGA_COND_OK:
763	/*
764	 * if unsuable, either power supply was missing or
765	 * hardware was not compatible.  Check to see if
766	 * this is still true.
767	 */
768	case SYSC_CFGA_COND_UNUSABLE:
769	/*
770	 * failing must transition in the disconnected state
771	 * to either unusable or unknown.  We may have come here
772	 * from cfgadm -f -c disconnect after a power supply failure
773	 * in an attempt to protect the board.
774	 */
775	case SYSC_CFGA_COND_FAILING:
776	    if (sysc_policy_enough_cooling(softsp, sysc_stat,
777		ps_mutex_is_held) &&
778		sysc_policy_enough_power(softsp, FALSE,
779		ps_mutex_is_held)) {
780		sysc_stat->condition = SYSC_CFGA_COND_UNKNOWN;
781	    } else {
782		sysc_stat->condition = SYSC_CFGA_COND_UNUSABLE;
783	    }
784	    sysc_stat->last_change = gethrestime_sec();
785	    break;
786	/*
787	 * if failed, we have failed POST and must stay in this
788	 * condition until the board has been removed
789	 * before ever coming back into another condition
790	 */
791	case SYSC_CFGA_COND_FAILED:
792		break;
793	default:
794		ASSERT(FALSE);
795		break;
796	}
797}
798
799/*ARGSUSED*/
800static void
801sysc_policy_connected_condition(struct sysctrl_soft_state *softsp,
802		sysc_cfga_stat_t *sysc_stat,
803		uint_t ps_mutex_is_held)
804{
805	ASSERT(fhc_bdlist_locked());
806
807	switch (sysc_stat->condition) {
808	case SYSC_CFGA_COND_UNKNOWN:
809	case SYSC_CFGA_COND_OK:
810	case SYSC_CFGA_COND_FAILING:
811	case SYSC_CFGA_COND_UNUSABLE:
812	    if (sysc_policy_enough_cooling(softsp, sysc_stat,
813		ps_mutex_is_held) &&
814		sysc_policy_enough_power(softsp, FALSE,
815		ps_mutex_is_held) &&
816		(fhc_env_temp_state(sysc_stat->board) == TEMP_OK)) {
817			sysc_stat->condition = SYSC_CFGA_COND_OK;
818	    } else {
819			sysc_stat->condition = SYSC_CFGA_COND_FAILING;
820	    }
821	    sysc_stat->last_change = gethrestime_sec();
822	    break;
823	case SYSC_CFGA_COND_FAILED:
824	    break;
825	default:
826	    ASSERT(FALSE);
827	    break;
828	}
829}
830
831static void
832sysc_policy_set_condition(void *sp, sysc_cfga_stat_t *sysc_stat,
833		uint_t ps_mutex_is_held)
834{
835	struct sysctrl_soft_state *softsp = (struct sysctrl_soft_state *)sp;
836
837	ASSERT(fhc_bdlist_locked());
838
839	switch (sysc_stat->rstate) {
840	case SYSC_CFGA_RSTATE_EMPTY:
841		sysc_policy_empty_condition(softsp, sysc_stat,
842			FALSE, ps_mutex_is_held);
843		break;
844	case SYSC_CFGA_RSTATE_DISCONNECTED:
845		sysc_policy_disconnected_condition(softsp, sysc_stat,
846			FALSE, ps_mutex_is_held);
847		break;
848	case SYSC_CFGA_RSTATE_CONNECTED:
849		sysc_policy_connected_condition(softsp, sysc_stat,
850			ps_mutex_is_held);
851		break;
852	default:
853		ASSERT(FALSE);
854		break;
855	}
856}
857
858void
859sysc_policy_update(void *softsp, sysc_cfga_stat_t *sysc_stat,
860	sysc_evt_t event)
861{
862	fhc_bd_t *list;
863
864	ASSERT(event == SYSC_EVT_BD_HP_DISABLED || fhc_bdlist_locked());
865
866	switch (event) {
867	case SYSC_EVT_BD_EMPTY:
868		sysc_stat->rstate = SYSC_CFGA_RSTATE_EMPTY;
869		sysc_stat->ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
870		sysc_stat->condition = SYSC_CFGA_COND_UNKNOWN;
871		sysc_policy_empty_condition(softsp, sysc_stat, FALSE, FALSE);
872		break;
873	case SYSC_EVT_BD_PRESENT:
874		if (sysc_stat->type == DISK_BOARD) {
875			sysc_stat->rstate = SYSC_CFGA_RSTATE_DISCONNECTED;
876			sysc_stat->ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
877			sysc_stat->condition = SYSC_CFGA_COND_UNKNOWN;
878		} else {
879			sysc_stat->rstate = SYSC_CFGA_RSTATE_CONNECTED;
880			sysc_stat->ostate = SYSC_CFGA_OSTATE_CONFIGURED;
881			sysc_stat->condition = SYSC_CFGA_COND_OK;
882		}
883		sysc_stat->last_change = gethrestime_sec();
884		break;
885	case SYSC_EVT_BD_DISABLED:
886		sysc_stat->rstate = SYSC_CFGA_RSTATE_DISCONNECTED;
887		sysc_stat->ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
888		sysc_stat->condition = SYSC_CFGA_COND_UNKNOWN;
889		sysc_policy_disconnected_condition(softsp,
890			sysc_stat, FALSE, FALSE);
891		cmn_err(CE_NOTE,
892			"disabled %s board in slot %d",
893			fhc_bd_typestr(sysc_stat->type),
894			sysc_stat->board);
895		break;
896	case SYSC_EVT_BD_FAILED:
897		sysc_stat->rstate = SYSC_CFGA_RSTATE_DISCONNECTED;
898		sysc_stat->ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
899		sysc_stat->condition = SYSC_CFGA_COND_UNUSABLE;
900		sysc_policy_disconnected_condition(softsp, sysc_stat,
901			TRUE, FALSE);
902		cmn_err(CE_WARN,
903			"failed %s board in slot %d",
904			fhc_bd_typestr(sysc_stat->type),
905			sysc_stat->board);
906		break;
907	case SYSC_EVT_BD_OVERTEMP:
908	case SYSC_EVT_BD_TEMP_OK:
909		sysc_policy_set_condition((void *)softsp, sysc_stat, FALSE);
910		break;
911	case SYSC_EVT_BD_PS_CHANGE:
912		for (list = fhc_bd_first(); list; list = fhc_bd_next(list)) {
913			sysc_stat = &(list->sc);
914			sysc_policy_set_condition((void *)softsp,
915				sysc_stat, TRUE);
916		}
917		break;
918	case SYSC_EVT_BD_INS_FAILED:
919		cmn_err(CE_WARN, "powerdown of board %d failed",
920			sysc_stat->board);
921		break;
922	case SYSC_EVT_BD_INSERTED:
923		sysc_stat->rstate = SYSC_CFGA_RSTATE_DISCONNECTED;
924		sysc_stat->ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
925		sysctrl_post_config_change(softsp);
926		sysc_policy_disconnected_condition(softsp,
927			sysc_stat, FALSE, FALSE);
928		cmn_err(CE_NOTE, "%s board has been inserted into slot %d",
929			fhc_bd_typestr(sysc_stat->type), sysc_stat->board);
930		cmn_err(CE_NOTE,
931			"board %d can be removed", sysc_stat->board);
932		break;
933	case SYSC_EVT_BD_REMOVED:
934		sysc_stat->rstate = SYSC_CFGA_RSTATE_EMPTY;
935		sysc_stat->ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
936		sysc_stat->condition = SYSC_CFGA_COND_UNKNOWN;
937
938		/* now it is ok to free the ac pa memory database */
939		fhc_del_memloc(sysc_stat->board);
940
941		/* reinitialize sysc_cfga_stat structure */
942		sysc_stat->type = UNKNOWN_BOARD;
943		sysc_stat->fhc_compid = 0;
944		sysc_stat->ac_compid = 0;
945		(void) bzero(&(sysc_stat->prom_rev),
946			sizeof (sysc_stat->prom_rev));
947		(void) bzero(&(sysc_stat->bd),
948			sizeof (union bd_un));
949		sysc_stat->no_detach = sysc_stat->plus_board = 0;
950		sysc_policy_disconnected_condition(softsp,
951			sysc_stat, FALSE, FALSE);
952		cmn_err(CE_NOTE, "board %d has been removed",
953			sysc_stat->board);
954		break;
955	case SYSC_EVT_BD_HP_DISABLED:
956		cmn_err(CE_NOTE, "Hot Plug not supported in this system");
957		break;
958	case SYSC_EVT_BD_CORE_RESOURCE_DISCONNECT:
959		cmn_err(CE_WARN, "board %d cannot be disconnected because it"
960			" is a core system resource", sysc_stat->board);
961		break;
962	default:
963		ASSERT(FALSE);
964		break;
965	}
966
967}
968
969/*
970 * signal to POST that the system has been reconfigured and that
971 * the system configuration status information should be invalidated
972 * the next time through POST
973 */
974static void
975sysctrl_post_config_change(struct sysctrl_soft_state *softsp)
976{
977	/*
978	 * We are heading into a configuration change!
979	 * Tell post to invalidate its notion of the system configuration.
980	 * This is done by clearing the clock registers...
981	 */
982	*softsp->clk_freq1 = 0;
983	*softsp->clk_freq2 &=
984		~(CLOCK_FREQ_8 | CLOCK_DIV_1 | CLOCK_RANGE | CLOCK_DIV_0);
985}
986
987static int
988sysc_attach_board(void *arg)
989{
990	int board = *(int *)arg;
991
992	return (prom_sunfire_attach_board((uint_t)board));
993}
994
995static int
996sysc_bd_connect(int board, sysc_cfga_pkt_t *pkt)
997{
998	int error = 0;
999	fhc_bd_t *bdp;
1000	sysc_dr_handle_t *sh;
1001	uint64_t mempa;
1002	int del_kstat = 0;
1003
1004	ASSERT(fhc_bd_busy(board));
1005
1006	bdp = fhc_bd(board);
1007
1008	/* find gap for largest supported simm in advance */
1009#define	MAX_BANK_SIZE_MB	(2 * 1024)
1010#define	BANKS_PER_BOARD		2
1011	mempa = fhc_find_memloc_gap(BANKS_PER_BOARD * MAX_BANK_SIZE_MB);
1012
1013	fhc_bdlist_unlock();
1014
1015	/* TODO: Is mempa vulnerable to re-use here? */
1016
1017	sysctrl_suspend_prepare();
1018
1019	if ((error = sysctrl_suspend(pkt)) == DDI_SUCCESS) {
1020		/* ASSERT(jtag not held) */
1021		error = prom_tree_update(sysc_attach_board, &board);
1022		if (error) {
1023			error = EIO;
1024			SYSC_ERR_SET(pkt, SYSC_ERR_PROM);
1025		} else {
1026			/* attempt to program the memory while frozen */
1027			fhc_program_memory(board, mempa);
1028		}
1029		sysctrl_resume(pkt);
1030	}
1031
1032	if (error) {
1033		goto done;
1034	}
1035
1036	/*
1037	 * Must not delete kstat used by prtdiag until the PROM
1038	 * has successfully connected to board.
1039	 */
1040	del_kstat = 1;
1041
1042	sh = &bdp->sh[SYSC_DR_HANDLE_FHC];
1043	sh->flags |= SYSC_DR_FHC;
1044	sh->errstr = pkt->errbuf;
1045
1046	sysc_dr_init(sh);
1047
1048	error = sysc_dr_attach(sh, board);
1049	if (error)
1050		SYSC_ERR_SET(pkt, SYSC_ERR_NDI_ATTACH);
1051
1052	sysc_dr_uninit(sh);
1053
1054	if (enable_redist) {
1055		mutex_enter(&cpu_lock);
1056		intr_redist_all_cpus();
1057		mutex_exit(&cpu_lock);
1058	}
1059done:
1060	if (del_kstat && bdp->ksp) {
1061		kstat_delete(bdp->ksp);
1062		bdp->ksp = NULL;
1063	}
1064
1065	(void) fhc_bdlist_lock(-1);
1066
1067	return (error);
1068}
1069
1070static int
1071sysc_detach_board(void * arg)
1072{
1073	int rt;
1074	cpuset_t xcset;
1075	struct jt_mstr *jtm;
1076	int board = *(int *)arg;
1077
1078	(void) fhc_bdlist_lock(-1);
1079
1080#ifdef DEBUG
1081	/* it is important to have fhc_bdlist_lock() earlier */
1082	if (sysctrl_enable_regdump)
1083		precache_regdump(board);
1084#endif /* DEBUG */
1085
1086	jtm = jtag_master_lock();
1087	CPUSET_ALL(xcset);
1088	promsafe_xc_attention(xcset);
1089
1090#ifdef DEBUG
1091	if (sysctrl_enable_regdump)
1092		boardstat_regdump();
1093#endif /* DEBUG */
1094
1095	rt =  prom_sunfire_detach_board((uint_t)board);
1096
1097#ifdef DEBUG
1098	if (sysctrl_enable_regdump)
1099		display_regdump();
1100#endif /* DEBUG */
1101
1102	xc_dismissed(xcset);
1103	jtag_master_unlock(jtm);
1104	fhc_bdlist_unlock();
1105	return (rt);
1106}
1107
1108static int
1109sysc_bd_disconnect(int board, sysc_cfga_pkt_t *pkt)
1110{
1111	int error;
1112	fhc_bd_t *bdp;
1113	sysc_dr_handle_t *sh;
1114	void fhc_bd_ks_alloc(fhc_bd_t *);
1115
1116	ASSERT(fhc_bd_busy(board));
1117	ASSERT(!fhc_bd_is_jtag_master(board));
1118
1119
1120	bdp = fhc_bd(board);
1121
1122	bdp->flags |= BDF_DETACH;
1123
1124	fhc_bdlist_unlock();
1125
1126	sh = &bdp->sh[SYSC_DR_HANDLE_FHC];
1127	sh->errstr = pkt->errbuf;
1128
1129	ASSERT(sh->dip_list == NULL);
1130
1131	sh->flags |= SYSC_DR_FHC;
1132	sysc_dr_init(sh);
1133
1134	error = sysc_dr_detach(sh, board);
1135	sh->flags &= ~SYSC_DR_REMOVE;
1136
1137	sysc_dr_uninit(sh);
1138	if (error) {
1139		SYSC_ERR_SET(pkt, SYSC_ERR_NDI_DETACH);
1140		goto done;
1141	}
1142	error = prom_tree_update(sysc_detach_board, &board);
1143
1144	if (error) {
1145		error = EIO;
1146		SYSC_ERR_SET(pkt, SYSC_ERR_PROM);
1147		goto done;
1148	}
1149
1150	if (enable_redist) {
1151		mutex_enter(&cpu_lock);
1152		intr_redist_all_cpus();
1153		mutex_exit(&cpu_lock);
1154	}
1155
1156	fhc_bd_ks_alloc(bdp);
1157done:
1158	(void) fhc_bdlist_lock(-1);
1159
1160	return (error);
1161}
1162
1163static int
1164sysc_bd_configure(int board, sysc_cfga_pkt_t *pkt)
1165{
1166	int error = 0;
1167	fhc_bd_t *bdp;
1168	sysc_dr_handle_t *sh;
1169
1170	ASSERT(fhc_bd_busy(board));
1171
1172	bdp = fhc_bd(board);
1173
1174	fhc_bdlist_unlock();
1175
1176
1177	sh = &bdp->sh[SYSC_DR_HANDLE_DEVS];
1178	sh->errstr = pkt->errbuf;
1179
1180	ASSERT(sh->dip_list == NULL);
1181
1182	sysc_dr_init(sh);
1183
1184	sh->flags |= SYSC_DR_DEVS;
1185	error = sysc_dr_attach(sh, board);
1186	if (error) {
1187		SYSC_ERR_SET(pkt, SYSC_ERR_NDI_ATTACH);
1188		sysc_dr_uninit(sh);
1189		goto done;
1190	}
1191
1192	sysc_dr_uninit(sh);
1193
1194	if (enable_redist) {
1195		mutex_enter(&cpu_lock);
1196		intr_redist_all_cpus();
1197		mutex_exit(&cpu_lock);
1198	}
1199done:
1200	if (bdp->sc.type == CPU_BOARD) {
1201		/*
1202		 * Value of error gets lost for CPU boards.
1203		 */
1204		mutex_enter(&cpu_lock);
1205
1206		error = find_and_setup_cpu(FHC_BOARD2CPU_A(board));
1207		if ((error == 0) || (error == ENODEV)) {
1208			int retval_b;
1209
1210			retval_b = find_and_setup_cpu(FHC_BOARD2CPU_B(board));
1211			if (retval_b != ENODEV)
1212				error = retval_b;
1213		}
1214
1215		mutex_exit(&cpu_lock);
1216	}
1217
1218	(void) fhc_bdlist_lock(-1);
1219
1220	return (error);
1221}
1222
1223static int
1224sysc_bd_unconfigure(int board, sysc_cfga_pkt_t *pkt)
1225{
1226	int error;
1227	fhc_bd_t *bdp;
1228	sysc_dr_handle_t *sh;
1229
1230	ASSERT(fhc_bdlist_locked());
1231	ASSERT(fhc_bd_busy(board));
1232
1233	bdp = fhc_bd(board);
1234
1235	if (bdp->sc.type == CPU_BOARD || bdp->sc.type == MEM_BOARD) {
1236		struct ac_soft_state *acsp;
1237
1238		/*
1239		 * Check that any memory on board is not in use.
1240		 * This must be done while the board list lock is held
1241		 * as memory state can change while fhc_bd_busy() is true
1242		 * even though a memory operation cannot be started
1243		 * if fhc_bd_busy() is true.
1244		 */
1245		if ((acsp = (struct ac_soft_state *)bdp->ac_softsp) != NULL) {
1246			if (acsp->bank[Bank0].busy != 0 ||
1247			    acsp->bank[Bank0].ostate ==
1248			    SYSC_CFGA_OSTATE_CONFIGURED) {
1249				cmn_err(CE_WARN, "memory bank %d in "
1250				    "slot %d is in use.", Bank0, board);
1251				(void) snprintf(pkt->errbuf,
1252				    SYSC_OUTPUT_LEN,
1253				    "memory bank %d in use",
1254				    Bank0);
1255				return (EBUSY);
1256			}
1257
1258			if (acsp->bank[Bank1].busy != 0 ||
1259			    acsp->bank[Bank1].ostate ==
1260			    SYSC_CFGA_OSTATE_CONFIGURED) {
1261				cmn_err(CE_WARN, "memory bank %d in "
1262				    "slot %d is in use.", Bank1, board);
1263				(void) snprintf(pkt->errbuf,
1264				    SYSC_OUTPUT_LEN,
1265				    "memory bank %d in use",
1266				    Bank1);
1267				return (EBUSY);
1268			}
1269			/*
1270			 * Nothing more to do here. The memory interface
1271			 * will not make any transitions while
1272			 * fhc_bd_busy() is true. Once the ostate
1273			 * becomes unconfigured, the memory becomes
1274			 * invisible.
1275			 */
1276		}
1277		error = 0;
1278		if (bdp->sc.type == CPU_BOARD) {
1279			struct cpu *cpua, *cpub;
1280			int cpu_flags = 0;
1281
1282			if (pkt->cmd_cfga.force)
1283				cpu_flags = CPU_FORCED;
1284
1285			fhc_bdlist_unlock();
1286
1287			mutex_enter(&cpu_lock);	/* protects CPU states */
1288
1289			error = fhc_board_poweroffcpus(board, pkt->errbuf,
1290			    cpu_flags);
1291
1292			cpua = cpu_get(FHC_BOARD2CPU_A(board));
1293			cpub = cpu_get(FHC_BOARD2CPU_B(board));
1294
1295			if ((error == 0) && (cpua != NULL)) {
1296				error = cpu_unconfigure(cpua->cpu_id);
1297				if (error != 0) {
1298					(void) snprintf(pkt->errbuf,
1299					    SYSC_OUTPUT_LEN,
1300					    "processor %d unconfigure failed",
1301					    cpua->cpu_id);
1302				}
1303			}
1304			if ((error == 0) && (cpub != NULL)) {
1305				error = cpu_unconfigure(cpub->cpu_id);
1306				if (error != 0) {
1307					(void) snprintf(pkt->errbuf,
1308					    SYSC_OUTPUT_LEN,
1309					    "processor %d unconfigure failed",
1310					    cpub->cpu_id);
1311				}
1312			}
1313
1314			mutex_exit(&cpu_lock);
1315
1316			(void) fhc_bdlist_lock(-1);
1317		}
1318
1319		if (error != 0)
1320			return (error);
1321	}
1322
1323	fhc_bdlist_unlock();
1324
1325	sh = &bdp->sh[SYSC_DR_HANDLE_DEVS];
1326	sh->errstr = pkt->errbuf;
1327
1328	ASSERT(sh->dip_list == NULL);
1329
1330	sysc_dr_init(sh);
1331
1332	sh->flags |= SYSC_DR_DEVS;
1333	error = sysc_dr_detach(sh, board);
1334	sh->flags &= ~SYSC_DR_REMOVE;
1335	if (error) {
1336		SYSC_ERR_SET(pkt, SYSC_ERR_NDI_DETACH);
1337		sysc_dr_uninit(sh);
1338		goto done;
1339	}
1340
1341	sysc_dr_uninit(sh);
1342
1343	if (enable_redist) {
1344		mutex_enter(&cpu_lock);
1345		intr_redist_all_cpus();
1346		mutex_exit(&cpu_lock);
1347	}
1348
1349done:
1350	(void) fhc_bdlist_lock(-1);
1351
1352	return (error);
1353}
1354
1355
1356typedef struct sysc_prom {
1357	sysc_dr_handle_t *handle;	/* DR handle			*/
1358	int board;			/* board id			*/
1359	dev_info_t **dipp;		/* next slot for storing dip	*/
1360} sysc_prom_t;
1361
1362/*
1363 * Attaching devices on a board.
1364 */
1365static int
1366sysc_dr_attach(sysc_dr_handle_t  *handle, int board)
1367{
1368	int			i;
1369	int			err;
1370	sysc_prom_t		arg;
1371	devi_branch_t		b = {0};
1372
1373	arg.handle = handle;
1374	arg.board = board;
1375	arg.dipp = handle->dip_list;
1376
1377	b.arg = &arg;
1378	b.type = DEVI_BRANCH_PROM;
1379	b.create.prom_branch_select = sysc_prom_select;
1380	b.devi_branch_callback = sysc_branch_callback;
1381
1382	handle->error = e_ddi_branch_create(ddi_root_node(), &b,
1383	    NULL, DEVI_BRANCH_CHILD);
1384
1385	if (handle->error)
1386		return (handle->error);
1387
1388	for (i = 0, arg.dipp = handle->dip_list;
1389	    i < handle->dip_list_len; i++, arg.dipp++) {
1390
1391		err = e_ddi_branch_configure(*arg.dipp, NULL, 0);
1392		/*
1393		 * Error only if we fail for fhc dips
1394		 */
1395		if (err && (handle->flags & SYSC_DR_FHC)) {
1396			handle->error = err;
1397			sysc_dr_err_decode(handle, *arg.dipp, TRUE);
1398			return (handle->error);
1399		}
1400	}
1401
1402	return (0);
1403}
1404
1405/*ARGSUSED*/
1406static int
1407sysc_make_list(void *arg, int has_changed)
1408{
1409	dev_info_t *rdip;
1410	sysc_prom_t *wp = (sysc_prom_t *)arg;
1411	pnode_t nid = prom_childnode(prom_rootnode());
1412
1413	if (wp == NULL)
1414		return (EINVAL);
1415
1416	for (; nid != OBP_NONODE && nid != OBP_BADNODE;
1417	    nid = prom_nextnode(nid)) {
1418		if (sysc_prom_select(nid, arg, 0) != DDI_SUCCESS)
1419			continue;
1420		if (wp->handle->dip_list_len < SYSC_DR_MAX_NODE) {
1421			rdip = wp->handle->dip_list[wp->handle->dip_list_len] =
1422			    e_ddi_nodeid_to_dip(nid);
1423			if (rdip != NULL) {
1424				wp->handle->dip_list_len++;
1425				/*
1426				 * Branch rooted at dip already held, so
1427				 * release hold acquired in e_ddi_nodeid_to_dip
1428				 */
1429				ddi_release_devi(rdip);
1430				ASSERT(e_ddi_branch_held(rdip));
1431#ifdef	DEBUG
1432			} else {
1433				DPRINTF(SYSC_DEBUG, ("sysc_make_list:"
1434				    " e_ddi_nodeid_to_dip() failed for"
1435				    " nodeid: %d\n", nid));
1436#endif
1437			}
1438		} else {
1439#ifdef	DEBUG
1440			cmn_err(CE_WARN, "sysc_make_list: list overflow\n");
1441#endif
1442			return (EFAULT);
1443		}
1444	}
1445
1446	return (0);
1447}
1448
1449/*
1450 * Detaching devices on a board.
1451 */
1452static int
1453sysc_dr_detach(sysc_dr_handle_t *handle, int board)
1454{
1455	int		i;
1456	uint_t		flags;
1457	sysc_prom_t	arg;
1458
1459	ASSERT(handle->dip_list);
1460	ASSERT(handle->dip_list_len == 0);
1461	ASSERT(*handle->dip_list == NULL);
1462
1463	arg.handle = handle;
1464	arg.board = board;
1465	arg.dipp = NULL;
1466
1467	handle->error = prom_tree_access(sysc_make_list, &arg, NULL);
1468	if (handle->error)
1469		return (handle->error);
1470
1471	flags = DEVI_BRANCH_DESTROY | DEVI_BRANCH_EVENT;
1472
1473	for (i = handle->dip_list_len; i > 0; i--) {
1474		ASSERT(e_ddi_branch_held(handle->dip_list[i - 1]));
1475		handle->error = e_ddi_branch_unconfigure(
1476		    handle->dip_list[i - 1], NULL, flags);
1477		if (handle->error)
1478			return (handle->error);
1479	}
1480
1481	return (0);
1482}
1483
1484static void
1485sysc_dr_init(sysc_dr_handle_t *handle)
1486{
1487	handle->dip_list = kmem_zalloc(sizeof (dev_info_t *) * SYSC_DR_MAX_NODE,
1488	    KM_SLEEP);
1489	handle->dip_list_len = 0;
1490}
1491
1492/*ARGSUSED2*/
1493static int
1494sysc_prom_select(pnode_t pnode, void *arg, uint_t flag)
1495{
1496	int		bd_id;
1497	char		name[OBP_MAXDRVNAME];
1498	int		len;
1499	int		*regp;
1500	sysc_prom_t	*wp = (sysc_prom_t *)arg;
1501
1502	bd_id = -1;
1503	len = prom_getproplen(pnode, OBP_REG);
1504	if (len > 0) {
1505		regp = kmem_alloc(len, KM_SLEEP);
1506		(void) prom_getprop(pnode, OBP_REG, (caddr_t)regp);
1507		/*
1508		 * Get board id for EXXXX platforms where
1509		 * 0x1c0 is EXXXX platform specific data to
1510		 * acquire board id.
1511		 */
1512		bd_id = (*regp - 0x1c0) >> 2;
1513		kmem_free(regp, len);
1514	}
1515
1516	(void) prom_getprop(pnode, OBP_NAME, (caddr_t)name);
1517	if ((bd_id == wp->board) &&
1518	    ((wp->handle->flags & SYSC_DR_FHC) ?
1519	    (strcmp(name, "fhc") == 0):
1520	    (strcmp(name, "fhc") != 0)) &&
1521	    (strcmp(name, "central") != 0)) {
1522		return (DDI_SUCCESS);
1523	}
1524
1525	return (DDI_FAILURE);
1526}
1527
1528/*ARGSUSED*/
1529static void
1530sysc_branch_callback(dev_info_t *rdip, void *arg, uint_t flags)
1531{
1532	sysc_prom_t *wp = (sysc_prom_t *)arg;
1533
1534	ASSERT(wp->dipp != NULL);
1535	ASSERT(*wp->dipp == NULL);
1536	ASSERT((wp->handle->flags & SYSC_DR_REMOVE) == 0);
1537
1538	if (wp->handle->dip_list_len < SYSC_DR_MAX_NODE) {
1539		*wp->dipp = rdip;
1540		wp->dipp++;
1541		wp->handle->dip_list_len++;
1542	} else {
1543		cmn_err(CE_PANIC, "sysc_branch_callback: list overflow");
1544	}
1545}
1546
1547/*
1548 * Uninitialize devices for the state of a board.
1549 */
1550static void
1551sysc_dr_uninit(sysc_dr_handle_t *handle)
1552{
1553	kmem_free(handle->dip_list,
1554	    sizeof (dev_info_t *) * SYSC_DR_MAX_NODE);
1555	handle->dip_list = NULL;
1556	handle->dip_list_len = 0;
1557}
1558
1559static void
1560sysc_dr_err_decode(sysc_dr_handle_t *handle, dev_info_t *dip, int attach)
1561{
1562	char	*p;
1563
1564	ASSERT(handle->error != 0);
1565
1566	switch (handle->error) {
1567	case ENOMEM:
1568		break;
1569	case EBUSY:
1570		(void) ddi_pathname(dip, handle->errstr);
1571		break;
1572	default:
1573		handle->error = EFAULT;
1574		if (attach)
1575			(void) ddi_pathname(ddi_get_parent(dip),
1576			    handle->errstr);
1577		else
1578			(void) ddi_pathname(dip, handle->errstr);
1579		if (attach) {
1580			p = "/";
1581			(void) strcat(handle->errstr, p);
1582			(void) strcat(handle->errstr, ddi_node_name(dip));
1583		}
1584		break;
1585	}
1586}
1587
1588static char *
1589sysc_rstate_typestr(sysc_cfga_rstate_t rstate, sysc_audit_evt_t event)
1590{
1591	char *type_str;
1592
1593	switch (rstate) {
1594	case SYSC_CFGA_RSTATE_EMPTY:
1595		switch (event) {
1596		case SYSC_AUDIT_RSTATE_EMPTY:
1597			type_str = "emptying";
1598			break;
1599		case SYSC_AUDIT_RSTATE_SUCCEEDED:
1600			type_str = "emptied";
1601			break;
1602		case SYSC_AUDIT_RSTATE_EMPTY_FAILED:
1603			type_str = "empty";
1604			break;
1605		default:
1606			type_str = "empty?";
1607			break;
1608		}
1609		break;
1610	case SYSC_CFGA_RSTATE_DISCONNECTED:
1611		switch (event) {
1612		case SYSC_AUDIT_RSTATE_DISCONNECT:
1613			type_str = "disconnecting";
1614			break;
1615		case SYSC_AUDIT_RSTATE_SUCCEEDED:
1616			type_str = "disconnected";
1617			break;
1618		case SYSC_AUDIT_RSTATE_DISCONNECT_FAILED:
1619			type_str = "disconnect";
1620			break;
1621		default:
1622			type_str = "disconnect?";
1623			break;
1624		}
1625		break;
1626	case SYSC_CFGA_RSTATE_CONNECTED:
1627		switch (event) {
1628		case SYSC_AUDIT_RSTATE_CONNECT:
1629			type_str = "connecting";
1630			break;
1631		case SYSC_AUDIT_RSTATE_SUCCEEDED:
1632			type_str = "connected";
1633			break;
1634		case SYSC_AUDIT_RSTATE_CONNECT_FAILED:
1635			type_str = "connect";
1636			break;
1637		default:
1638			type_str = "connect?";
1639			break;
1640		}
1641		break;
1642	default:
1643		type_str = "undefined receptacle state";
1644		break;
1645	}
1646	return (type_str);
1647}
1648
1649static char *
1650sysc_ostate_typestr(sysc_cfga_ostate_t ostate, sysc_audit_evt_t event)
1651{
1652	char *type_str;
1653
1654	switch (ostate) {
1655	case SYSC_CFGA_OSTATE_UNCONFIGURED:
1656		switch (event) {
1657		case SYSC_AUDIT_OSTATE_UNCONFIGURE:
1658			type_str = "unconfiguring";
1659			break;
1660		case SYSC_AUDIT_OSTATE_SUCCEEDED:
1661		case SYSC_AUDIT_OSTATE_UNCONFIGURE_FAILED:
1662			type_str = "unconfigured";
1663			break;
1664		default:
1665			type_str = "unconfigure?";
1666			break;
1667		}
1668		break;
1669	case SYSC_CFGA_OSTATE_CONFIGURED:
1670		switch (event) {
1671		case SYSC_AUDIT_OSTATE_CONFIGURE:
1672			type_str = "configuring";
1673			break;
1674		case SYSC_AUDIT_OSTATE_SUCCEEDED:
1675		case SYSC_AUDIT_OSTATE_CONFIGURE_FAILED:
1676			type_str = "configured";
1677			break;
1678		default:
1679			type_str = "configure?";
1680			break;
1681		}
1682		break;
1683
1684	default:
1685		type_str = "undefined occupant state";
1686		break;
1687	}
1688	return (type_str);
1689}
1690
1691static void
1692sysc_policy_audit_messages(sysc_audit_evt_t event, sysc_cfga_stat_t *sysc_stat)
1693{
1694	switch (event) {
1695		case SYSC_AUDIT_RSTATE_CONNECT:
1696			cmn_err(CE_NOTE,
1697				"%s %s board in slot %d",
1698				sysc_rstate_typestr(SYSC_CFGA_RSTATE_CONNECTED,
1699				event),
1700				fhc_bd_typestr(sysc_stat->type),
1701				sysc_stat->board);
1702			break;
1703		case SYSC_AUDIT_RSTATE_DISCONNECT:
1704			cmn_err(CE_NOTE,
1705				"%s %s board in slot %d",
1706				sysc_rstate_typestr(
1707					SYSC_CFGA_RSTATE_DISCONNECTED,
1708					event),
1709				fhc_bd_typestr(sysc_stat->type),
1710				sysc_stat->board);
1711			break;
1712		case SYSC_AUDIT_RSTATE_SUCCEEDED:
1713			cmn_err(CE_NOTE,
1714				"%s board in slot %d is %s",
1715				fhc_bd_typestr(sysc_stat->type),
1716				sysc_stat->board,
1717				sysc_rstate_typestr(sysc_stat->rstate,
1718					event));
1719			break;
1720		case SYSC_AUDIT_RSTATE_CONNECT_FAILED:
1721			cmn_err(CE_NOTE,
1722				"%s board in slot %d failed to %s",
1723				fhc_bd_typestr(sysc_stat->type),
1724				sysc_stat->board,
1725				sysc_rstate_typestr(SYSC_CFGA_RSTATE_CONNECTED,
1726					event));
1727			break;
1728		case SYSC_AUDIT_RSTATE_DISCONNECT_FAILED:
1729			cmn_err(CE_NOTE,
1730				"%s board in slot %d failed to %s",
1731				fhc_bd_typestr(sysc_stat->type),
1732				sysc_stat->board,
1733				sysc_rstate_typestr(
1734					SYSC_CFGA_RSTATE_DISCONNECTED,
1735					event));
1736			break;
1737		case SYSC_AUDIT_OSTATE_CONFIGURE:
1738			cmn_err(CE_NOTE,
1739				"%s %s board in slot %d",
1740				sysc_ostate_typestr(SYSC_CFGA_OSTATE_CONFIGURED,
1741				event),
1742				fhc_bd_typestr(sysc_stat->type),
1743				sysc_stat->board);
1744			break;
1745		case SYSC_AUDIT_OSTATE_UNCONFIGURE:
1746			cmn_err(CE_NOTE,
1747				"%s %s board in slot %d",
1748				sysc_ostate_typestr(
1749					SYSC_CFGA_OSTATE_UNCONFIGURED,
1750					event),
1751				fhc_bd_typestr(sysc_stat->type),
1752				sysc_stat->board);
1753			break;
1754		case SYSC_AUDIT_OSTATE_SUCCEEDED:
1755			cmn_err(CE_NOTE,
1756				"%s board in slot %d is %s",
1757				fhc_bd_typestr(sysc_stat->type),
1758				sysc_stat->board,
1759				sysc_ostate_typestr(sysc_stat->ostate,
1760					event));
1761			break;
1762		case SYSC_AUDIT_OSTATE_CONFIGURE_FAILED:
1763			cmn_err(CE_NOTE,
1764				"%s board in slot %d partially %s",
1765				fhc_bd_typestr(sysc_stat->type),
1766				sysc_stat->board,
1767				sysc_ostate_typestr(
1768					SYSC_CFGA_OSTATE_CONFIGURED,
1769					event));
1770			break;
1771		case SYSC_AUDIT_OSTATE_UNCONFIGURE_FAILED:
1772			cmn_err(CE_NOTE,
1773				"%s board in slot %d partially %s",
1774				fhc_bd_typestr(sysc_stat->type),
1775				sysc_stat->board,
1776				sysc_ostate_typestr(
1777					SYSC_CFGA_OSTATE_UNCONFIGURED,
1778					event));
1779			break;
1780		default:
1781			cmn_err(CE_NOTE,
1782				"unknown audit of a %s %s board in"
1783				" slot %d",
1784				sysc_rstate_typestr(sysc_stat->rstate,
1785					event),
1786				fhc_bd_typestr(sysc_stat->type),
1787				sysc_stat->board);
1788			break;
1789	}
1790}
1791
1792#define	MAX_PROP_LEN	33	/* must be > strlen("cpu") */
1793
1794static int
1795find_and_setup_cpu(int cpuid)
1796{
1797	return (prom_tree_access(find_and_setup_cpu_start, &cpuid, NULL));
1798}
1799
1800/* ARGSUSED */
1801static int
1802find_and_setup_cpu_start(void *cpuid_arg, int has_changed)
1803{
1804	pnode_t nodeid;
1805	int upaid;
1806	char type[MAX_PROP_LEN];
1807	int cpuid = *(int *)cpuid_arg;
1808
1809	nodeid = prom_childnode(prom_rootnode());
1810	while (nodeid != OBP_NONODE) {
1811		if (prom_getproplen(nodeid, "device_type") < MAX_PROP_LEN)
1812			(void) prom_getprop(nodeid, "device_type",
1813			    (caddr_t)type);
1814		else
1815			type[0] = '\0';
1816		(void) prom_getprop(nodeid, "upa-portid", (caddr_t)&upaid);
1817		if ((strcmp(type, "cpu") == 0) && (upaid == cpuid)) {
1818			return (cpu_configure(cpuid));
1819		}
1820		nodeid = prom_nextnode(nodeid);
1821	}
1822	return (ENODEV);
1823}
1824
1825#define	MAX_BOARD_TYPE	IO_SBUS_FFB_SOCPLUS_BOARD
1826
1827static char sysc_supp_conn[MAX_BOARD_TYPE + 1];
1828
1829static int
1830sysc_board_connect_supported(enum board_type type)
1831{
1832	if (type > MAX_BOARD_TYPE)
1833		return (0);
1834	return (sysc_supp_conn[type]);
1835}
1836
1837void
1838sysc_board_connect_supported_init(void)
1839{
1840	pnode_t openprom_node;
1841	char sup_list[16];
1842	int proplen;
1843	int i;
1844	char tstr[3 * 5 + 1];
1845
1846	/* Check the firmware for Dynamic Reconfiguration support */
1847	if (prom_test("SUNW,Ultra-Enterprise,rm-brd") != 0) {
1848		/* The message was printed in platmod:set_platform_defaults */
1849		enable_dynamic_reconfiguration = 0;
1850	}
1851
1852	openprom_node = prom_finddevice("/openprom");
1853	if (openprom_node != OBP_BADNODE) {
1854		proplen = prom_bounded_getprop(openprom_node,
1855		    "add-brd-supported-types",
1856		    sup_list, sizeof (sup_list) - 1);
1857	} else {
1858		proplen = -1;
1859	}
1860
1861	if (proplen < 0) {
1862		/*
1863		 * This is an old prom which may cause a fatal reset,
1864		 * so don't allow any DR operations.
1865		 * If enable_dynamic_reconfiguration is 0
1866		 * we have already printed a similar message.
1867		 */
1868		if (enable_dynamic_reconfiguration) {
1869			cmn_err(CE_WARN, "Firmware does not support"
1870			    " Dynamic Reconfiguration");
1871			enable_dynamic_reconfiguration = 0;
1872		}
1873		return;
1874	}
1875	for (i = 0; i < proplen; i++) {
1876		switch (sup_list[i]) {
1877		case '0':
1878			sysc_supp_conn[CPU_BOARD] = 1;
1879			sysc_supp_conn[MEM_BOARD] = 1;
1880			break;
1881		case '1':
1882			sysc_supp_conn[IO_2SBUS_BOARD] = 1;
1883			break;
1884		case '2':
1885			sysc_supp_conn[IO_SBUS_FFB_BOARD] = 1;
1886			break;
1887		case '3':
1888			sysc_supp_conn[IO_PCI_BOARD] = 1;
1889			break;
1890		case '4':
1891			sysc_supp_conn[IO_2SBUS_SOCPLUS_BOARD] = 1;
1892			break;
1893		case '5':
1894			sysc_supp_conn[IO_SBUS_FFB_SOCPLUS_BOARD] = 1;
1895			break;
1896		default:
1897			/* Ignore other characters. */
1898			break;
1899		}
1900	}
1901	if (sysc_supp_conn[CPU_BOARD]) {
1902		cmn_err(CE_NOTE, "!Firmware supports Dynamic Reconfiguration"
1903		    " of CPU/Memory boards.");
1904	} else {
1905		cmn_err(CE_NOTE, "Firmware does not support Dynamic"
1906		    " Reconfiguration of CPU/Memory boards.");
1907	}
1908
1909	tstr[0] = '\0';
1910	if (sysc_supp_conn[IO_2SBUS_BOARD])
1911		(void) strcat(tstr, ", 1");
1912	if (sysc_supp_conn[IO_SBUS_FFB_BOARD])
1913		(void) strcat(tstr, ", 2");
1914	if (sysc_supp_conn[IO_PCI_BOARD])
1915		(void) strcat(tstr, ", 3");
1916	if (sysc_supp_conn[IO_2SBUS_SOCPLUS_BOARD])
1917		(void) strcat(tstr, ", 4");
1918	if (sysc_supp_conn[IO_SBUS_FFB_SOCPLUS_BOARD])
1919		(void) strcat(tstr, ", 5");
1920	if (tstr[0] != '\0') {
1921		/* Skip leading ", " using &tstr[2]. */
1922		cmn_err(CE_NOTE, "!Firmware supports Dynamic Reconfiguration"
1923		    " of I/O board types %s.", &tstr[2]);
1924	} else {
1925		cmn_err(CE_NOTE, "Firmware does not support Dynamic"
1926		    " Reconfiguration of I/O boards.");
1927	}
1928}
1929
1930#ifdef DEBUG
1931
1932static void
1933precache_regdump(int board)
1934{
1935	fhc_bd_t *curr_bdp;
1936	int bd_idx;
1937	int reg_idx;
1938
1939	for (bd_idx = 0; bd_idx < fhc_max_boards(); bd_idx++) {
1940		bcopy((void *) reg_tmpl, (void *) &reg_dt[bd_idx][0],
1941		    (sizeof (struct regs_data))*NUM_REG);
1942		curr_bdp = fhc_bd(bd_idx);
1943		if (curr_bdp->sc.rstate == SYSC_CFGA_RSTATE_CONNECTED) {
1944			for (reg_idx = 0; reg_idx < NUM_REG; reg_idx++) {
1945				reg_dt[bd_idx][reg_idx].eflag = TRUE;
1946				if (bd_idx != board)
1947					reg_dt[bd_idx][reg_idx].oflag = TRUE;
1948				reg_dt[bd_idx][reg_idx].physaddr +=
1949				    (FHC_BOARD_SPAN*2*bd_idx);
1950				reg_dt[bd_idx][reg_idx].pre_dsct =
1951				    ldphysio(reg_dt[bd_idx][reg_idx].physaddr);
1952			}
1953		}
1954	}
1955
1956
1957}
1958
1959static void
1960boardstat_regdump(void)
1961{
1962	int bd_idx;
1963
1964	prom_printf("\nBoard status before disconnect.\n");
1965	for (bd_idx = 0; bd_idx < fhc_max_boards(); bd_idx++) {
1966		if (reg_dt[bd_idx][0].eflag == 0) {
1967			prom_printf("Board #%d is idle.\n", bd_idx);
1968		} else {
1969			prom_printf("Board #%d is on.\n", bd_idx);
1970		}
1971	}
1972
1973	for (bd_idx = 0; bd_idx < fhc_max_boards(); bd_idx++) {
1974		if (reg_dt[bd_idx][0].eflag) {
1975			prom_printf("\nRegisters for Board #%d", bd_idx);
1976			prom_printf(" (before disconnect).\n");
1977			prom_printf("AC_BCSR   FHC_CTRL  JTAG      IGN   SIM"
1978			    "       SISM  UIM       USM\n");
1979			prom_printf("%08x  %08x  %08x  %04x"
1980			    "  %08x  %04x  %08x  %04x\n",
1981			    reg_dt[bd_idx][0].pre_dsct,
1982			    reg_dt[bd_idx][1].pre_dsct,
1983			    reg_dt[bd_idx][2].pre_dsct,
1984			    reg_dt[bd_idx][3].pre_dsct,
1985			    reg_dt[bd_idx][4].pre_dsct,
1986			    reg_dt[bd_idx][5].pre_dsct,
1987			    reg_dt[bd_idx][6].pre_dsct,
1988			    reg_dt[bd_idx][7].pre_dsct);
1989		}
1990	}
1991
1992}
1993
1994static void
1995display_regdump(void)
1996{
1997	int bd_idx;
1998	int reg_idx;
1999
2000	prom_printf("Board status after disconnect.\n");
2001	for (bd_idx = 0; bd_idx < fhc_max_boards(); bd_idx++) {
2002		if (reg_dt[bd_idx][0].oflag == 0) {
2003			prom_printf("Board #%d is idle.\n", bd_idx);
2004		} else {
2005			prom_printf("Board #%d is on.\n", bd_idx);
2006			for (reg_idx = 0; reg_idx < NUM_REG; reg_idx++)
2007				reg_dt[bd_idx][reg_idx].post_dsct =
2008				    ldphysio(reg_dt[bd_idx][reg_idx].physaddr);
2009		}
2010	}
2011
2012	for (bd_idx = 0; bd_idx < fhc_max_boards(); bd_idx++) {
2013		if (reg_dt[bd_idx][0].eflag) {
2014			prom_printf("\nRegisters for Board #%d", bd_idx);
2015			prom_printf(" (before and after disconnect).\n");
2016			prom_printf("AC_BCSR   FHC_CTRL  JTAG      IGN   SIM"
2017			    "       SISM  UIM       USM\n");
2018			prom_printf("%08x  %08x  %08x  %04x"
2019			    "  %08x  %04x  %08x  %04x\n",
2020			    reg_dt[bd_idx][0].pre_dsct,
2021			    reg_dt[bd_idx][1].pre_dsct,
2022			    reg_dt[bd_idx][2].pre_dsct,
2023			    reg_dt[bd_idx][3].pre_dsct,
2024			    reg_dt[bd_idx][4].pre_dsct,
2025			    reg_dt[bd_idx][5].pre_dsct,
2026			    reg_dt[bd_idx][6].pre_dsct,
2027			    reg_dt[bd_idx][7].pre_dsct);
2028			if (reg_dt[bd_idx][0].oflag) {
2029				prom_printf("%08x  %08x  %08x  %04x"
2030				    "  %08x  %04x  %08x  %04x\n",
2031				    reg_dt[bd_idx][0].post_dsct,
2032				    reg_dt[bd_idx][1].post_dsct,
2033				    reg_dt[bd_idx][2].post_dsct,
2034				    reg_dt[bd_idx][3].post_dsct,
2035				    reg_dt[bd_idx][4].post_dsct,
2036				    reg_dt[bd_idx][5].post_dsct,
2037				    reg_dt[bd_idx][6].post_dsct,
2038				    reg_dt[bd_idx][7].post_dsct);
2039			} else {
2040				prom_printf("no data (board got"
2041				    " disconnected)-------------------"
2042				    "---------------\n");
2043			}
2044		}
2045
2046	}
2047
2048}
2049
2050#endif /* DEBUG */
2051