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
66 struct 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
75 static 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]))
87 static struct regs_data reg_dt[MAX_BOARDS][NUM_REG];
88
89 int sysctrl_enable_regdump = 0;
90
91 static void precache_regdump(int board);
92 static void display_regdump(void);
93 static void boardstat_regdump(void);
94
95 #endif /* DEBUG */
96
97 extern void bd_remove_poll(struct sysctrl_soft_state *);
98 extern int sysctrl_getsystem_freq(void);
99 extern enum power_state compute_power_state(struct sysctrl_soft_state *, int);
100 extern enum temp_state fhc_env_temp_state(int);
101 extern int sysctrl_hotplug_disabled;
102 /* Let user disable Sunfire Dynamic Reconfiguration */
103 int enable_dynamic_reconfiguration = 1;
104
105 int enable_redist = 1;
106
107 static void sysc_dr_err_decode(sysc_dr_handle_t *, dev_info_t *, int);
108 static uint_t
109 sysc_policy_enough_cooling(struct sysctrl_soft_state *softsp,
110 sysc_cfga_stat_t *sysc_stat, uint_t ps_mutex_is_held);
111 static uint_t
112 sysc_policy_enough_precharge(struct sysctrl_soft_state *softsp,
113 sysc_cfga_stat_t *sysc_stat);
114 static uint_t
115 sysc_policy_enough_power(struct sysctrl_soft_state *softsp,
116 int plus_load, uint_t ps_mutex_is_held);
117 static uint_t
118 sysc_policy_hardware_compatible(struct sysctrl_soft_state *softsp,
119 sysc_cfga_stat_t *sysc_stat, sysc_cfga_pkt_t *pkt);
120 static 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);
124 static 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);
128 static void sysc_policy_connected_condition(struct sysctrl_soft_state *softsp,
129 sysc_cfga_stat_t *sysc_stat,
130 uint_t ps_mutex_is_held);
131 static void sysc_policy_set_condition(void *sp, sysc_cfga_stat_t *sysc_stat,
132 uint_t ps_mutex_is_held);
133 static void sysc_policy_audit_messages(sysc_audit_evt_t event,
134 sysc_cfga_stat_t *sysc_stat);
135
136 static void sysctrl_post_config_change(struct sysctrl_soft_state *softsp);
137 static int sysc_bd_connect(int, sysc_cfga_pkt_t *);
138 static int sysc_bd_disconnect(int, sysc_cfga_pkt_t *);
139 static int sysc_bd_configure(int, sysc_cfga_pkt_t *);
140 static int sysc_bd_unconfigure(int, sysc_cfga_pkt_t *);
141
142 static void sysc_dr_init(sysc_dr_handle_t *handle);
143 static void sysc_dr_uninit(sysc_dr_handle_t *handle);
144 static int sysc_dr_attach(sysc_dr_handle_t *handle, int board);
145 static int sysc_dr_detach(sysc_dr_handle_t *handle, int board);
146
147 static int sysc_prom_select(pnode_t pnode, void *arg, uint_t flag);
148 static void sysc_branch_callback(dev_info_t *rdip, void *arg, uint_t flags);
149
150 static int find_and_setup_cpu(int);
151
152 static int sysc_board_connect_supported(enum board_type);
153
154 static 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*/
161 static uint_t
sysc_policy_enough_power(struct sysctrl_soft_state * softsp,int plus_load,uint_t ps_mutex_is_held)162 sysc_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 */
200 static uint_t
sysc_policy_enough_cooling(struct sysctrl_soft_state * softsp,sysc_cfga_stat_t * sysc_stat,uint_t ps_mutex_is_held)201 sysc_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*/
228 static uint_t
sysc_policy_enough_precharge(struct sysctrl_soft_state * softsp,sysc_cfga_stat_t * sysc_stat)229 sysc_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
257 static 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 */
266 void
set_clockbrd_info(void)267 set_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*/
279 static uint_t
sysc_policy_hardware_compatible(struct sysctrl_soft_state * softsp,sysc_cfga_stat_t * sysc_stat,sysc_cfga_pkt_t * pkt)280 sysc_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*/
375 int
sysc_policy_connect(struct sysctrl_soft_state * softsp,sysc_cfga_pkt_t * pkt,sysc_cfga_stat_t * sysc_stat)376 sysc_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*/
480 int
sysc_policy_disconnect(struct sysctrl_soft_state * softsp,sysc_cfga_pkt_t * pkt,sysc_cfga_stat_t * sysc_stat)481 sysc_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*/
582 int
sysc_policy_unconfigure(struct sysctrl_soft_state * softsp,sysc_cfga_pkt_t * pkt,sysc_cfga_stat_t * sysc_stat)583 sysc_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*/
646 int
sysc_policy_configure(struct sysctrl_soft_state * softsp,sysc_cfga_pkt_t * pkt,sysc_cfga_stat_t * sysc_stat)647 sysc_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*/
709 static void
sysc_policy_empty_condition(struct sysctrl_soft_state * softsp,sysc_cfga_stat_t * sysc_stat,uint_t failure,uint_t ps_mutex_is_held)710 sysc_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*/
739 static void
sysc_policy_disconnected_condition(struct sysctrl_soft_state * softsp,sysc_cfga_stat_t * sysc_stat,uint_t failure,uint_t ps_mutex_is_held)740 sysc_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*/
800 static void
sysc_policy_connected_condition(struct sysctrl_soft_state * softsp,sysc_cfga_stat_t * sysc_stat,uint_t ps_mutex_is_held)801 sysc_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
831 static void
sysc_policy_set_condition(void * sp,sysc_cfga_stat_t * sysc_stat,uint_t ps_mutex_is_held)832 sysc_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
858 void
sysc_policy_update(void * softsp,sysc_cfga_stat_t * sysc_stat,sysc_evt_t event)859 sysc_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 */
974 static void
sysctrl_post_config_change(struct sysctrl_soft_state * softsp)975 sysctrl_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
987 static int
sysc_attach_board(void * arg)988 sysc_attach_board(void *arg)
989 {
990 int board = *(int *)arg;
991
992 return (prom_sunfire_attach_board((uint_t)board));
993 }
994
995 static int
sysc_bd_connect(int board,sysc_cfga_pkt_t * pkt)996 sysc_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 }
1059 done:
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
1070 static int
sysc_detach_board(void * arg)1071 sysc_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
1108 static int
sysc_bd_disconnect(int board,sysc_cfga_pkt_t * pkt)1109 sysc_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);
1157 done:
1158 (void) fhc_bdlist_lock(-1);
1159
1160 return (error);
1161 }
1162
1163 static int
sysc_bd_configure(int board,sysc_cfga_pkt_t * pkt)1164 sysc_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 }
1199 done:
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
1223 static int
sysc_bd_unconfigure(int board,sysc_cfga_pkt_t * pkt)1224 sysc_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
1349 done:
1350 (void) fhc_bdlist_lock(-1);
1351
1352 return (error);
1353 }
1354
1355
1356 typedef 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 */
1365 static int
sysc_dr_attach(sysc_dr_handle_t * handle,int board)1366 sysc_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*/
1406 static int
sysc_make_list(void * arg,int has_changed)1407 sysc_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 */
1452 static int
sysc_dr_detach(sysc_dr_handle_t * handle,int board)1453 sysc_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
1484 static void
sysc_dr_init(sysc_dr_handle_t * handle)1485 sysc_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*/
1493 static int
sysc_prom_select(pnode_t pnode,void * arg,uint_t flag)1494 sysc_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*/
1529 static void
sysc_branch_callback(dev_info_t * rdip,void * arg,uint_t flags)1530 sysc_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 */
1550 static void
sysc_dr_uninit(sysc_dr_handle_t * handle)1551 sysc_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
1559 static void
sysc_dr_err_decode(sysc_dr_handle_t * handle,dev_info_t * dip,int attach)1560 sysc_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
1588 static char *
sysc_rstate_typestr(sysc_cfga_rstate_t rstate,sysc_audit_evt_t event)1589 sysc_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
1649 static char *
sysc_ostate_typestr(sysc_cfga_ostate_t ostate,sysc_audit_evt_t event)1650 sysc_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
1691 static void
sysc_policy_audit_messages(sysc_audit_evt_t event,sysc_cfga_stat_t * sysc_stat)1692 sysc_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
1794 static int
find_and_setup_cpu(int cpuid)1795 find_and_setup_cpu(int cpuid)
1796 {
1797 return (prom_tree_access(find_and_setup_cpu_start, &cpuid, NULL));
1798 }
1799
1800 /* ARGSUSED */
1801 static int
find_and_setup_cpu_start(void * cpuid_arg,int has_changed)1802 find_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
1827 static char sysc_supp_conn[MAX_BOARD_TYPE + 1];
1828
1829 static int
sysc_board_connect_supported(enum board_type type)1830 sysc_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
1837 void
sysc_board_connect_supported_init(void)1838 sysc_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
1932 static void
precache_regdump(int board)1933 precache_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 *) ®_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
1959 static void
boardstat_regdump(void)1960 boardstat_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
1994 static void
display_regdump(void)1995 display_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