/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/ddi_impldefs.h>
#include <sys/ndi_impldefs.h>
#include <sys/sysmacros.h>
#include <sys/autoconf.h>
#include <sys/machsystm.h>
#include <sys/simmstat.h>
#include <sys/promimpl.h>
#include <sys/machcpuvar.h>
#ifdef DEBUG
struct regs_data {
};
"AC Control and Status reg = 0x", AC_BCSR(0), 0, 0, 0, 0,
"FHC Control and Status reg = 0x", FHC_CTRL(0), 0, 0, 0, 0,
"JTAG Control reg = 0x", FHC_JTAG_CTRL(0), 0, 0, 0, 0,
"Interrupt Group Number reg = 0x", FHC_IGN(0), 0, 0, 0, 0,
"System Interrupt Mapping reg = 0x", FHC_SIM(0), 0, 0, 0, 0,
"System Interrupt State reg = 0x", FHC_SSM(0), 0, 0, 0, 0,
"UART Interrupt Mapping reg = 0x", FHC_UIM(0), 0, 0, 0, 0,
"UART Interrupt State reg = 0x", FHC_USM(0), 0, 0, 0, 0
};
int sysctrl_enable_regdump = 0;
static void precache_regdump(int board);
static void display_regdump(void);
static void boardstat_regdump(void);
#endif /* DEBUG */
extern void bd_remove_poll(struct sysctrl_soft_state *);
extern int sysctrl_getsystem_freq(void);
extern enum temp_state fhc_env_temp_state(int);
extern int sysctrl_hotplug_disabled;
/* Let user disable Sunfire Dynamic Reconfiguration */
static uint_t
static uint_t
static uint_t
static uint_t
static void sysc_policy_empty_condition(
struct sysctrl_soft_state *softsp,
static void sysc_policy_disconnected_condition(
struct sysctrl_soft_state *softsp,
static int sysc_bd_connect(int, sysc_cfga_pkt_t *);
static int sysc_bd_disconnect(int, sysc_cfga_pkt_t *);
static int sysc_bd_configure(int, sysc_cfga_pkt_t *);
static int sysc_bd_unconfigure(int, sysc_cfga_pkt_t *);
static int find_and_setup_cpu(int);
static int sysc_board_connect_supported(enum board_type);
/*
* This function will basically do a prediction on the power state
* based on adding one additional load to the equation implemented
* by the function compute_power_state.
*/
/*ARGSUSED*/
static uint_t
{
int retval = 0;
if (!ps_mutex_is_held) {
}
/*
* note that we add one more load
* to the equation in compute_power_state
* and the answer better be REDUNDANT or
* MINIMUM before proceeding.
*/
case REDUNDANT:
case MINIMUM:
retval = 1;
break;
case BELOW_MINIMUM:
default:
break;
}
if (!ps_mutex_is_held) {
}
return (retval);
}
/*
* This function gropes through the shadow registers in the sysctrl soft_state
* for the core power supply status, since fan status for them are ORed into
* the same status bit, and all other remaining fans.
*/
static uint_t
{
int retval = 0;
if (!ps_mutex_is_held) {
}
/*
* check the power supply in the slot in question
* for fans then check all the common fans.
*/
PRES_IN) &&
PS_OK));
if (!ps_mutex_is_held) {
}
return (retval);
}
/*
* This function will check all precharge voltage status.
*/
/*ARGSUSED*/
static uint_t
{
int retval = 0;
int ppsval = 0;
/*
* note that we always have to explicitly check
* the peripheral power supply for precharge since it
* supplies all of the precharge voltages.
*/
/*
* check all the precharge status
*/
}
static int Fsys;
/*
* This function should only be called once as we may
* zero the clock board registers to indicate a configuration change.
* The code to calculate the bus frequency has been removed and we
* read the eeprom property instead. Another static Fmod (module
* frequency may be needed later but so far it is commented out.
*/
void
set_clockbrd_info(void)
{
}
#define abs(x) ((x) < 0 ? -(x) : (x))
/*ARGSUSED*/
static uint_t
{
int status;
/* Only allow DR operations on supported hardware */
case CPU_BOARD: {
#ifdef RFE_4174486
int i;
int cpu_freq;
int sram_mode;
sram_mode = 1;
else
sram_mode = 2;
for (i = 0; i < 2; i++) {
/*
* XXX: Add jtag code which rescans disabled boards.
* For the time being disabled boards are not
* checked for compatibility when cpu_speed is 0.
*/
continue;
"rated at %d Mhz, system freq %d Mhz",
cpu_freq);
}
"incompatible sram mode of %dx, "
(i == 0) ? 'A' : 'B',
}
}
break;
#endif /* RFE_4174486 */
}
case MEM_BOARD:
case IO_2SBUS_BOARD:
case IO_SBUS_FFB_BOARD:
case IO_PCI_BOARD:
case IO_2SBUS_SOCPLUS_BOARD:
break;
case CLOCK_BOARD:
case DISK_BOARD:
default:
break;
}
return (status);
/* Check for Sunfire boards in a Sunfire+ system */
"not 100 MHz capable ");
}
return (status);
}
/*
* This function is called to check the policy for a request to transition
* to the connected state from the disconnected state. The generic policy
* is to do sanity checks again before going live.
*/
/*ARGSUSED*/
int
{
int retval;
/*
* Safety policy: only allow connect if board is UNKNOWN cond.
* cold start board will be demoted to UNKNOWN cond when
* disconnected
*/
return (EINVAL);
}
if (!enable_dynamic_reconfiguration) {
return (ENOTSUP);
}
if (sysctrl_hotplug_disabled) {
return (ENOTSUP);
}
/* Check PROM support. */
" is not supported by firmware.",
return (ENOTSUP);
}
return (EAGAIN);
}
return (EAGAIN);
}
return (EAGAIN);
}
return (ENOTSUP);
}
if (!retval) {
} else {
}
break;
case SYSC_CFGA_RSTATE_EMPTY:
default:
break;
}
return (retval);
}
/*
* This function is called to check the policy for a request to transition
* to the disconnected state from the connected/unconfigured state only.
* All other requests are invalid.
*/
/*ARGSUSED*/
int
{
int retval;
if (!enable_dynamic_reconfiguration) {
return (ENOTSUP);
}
/* Check PROM support. */
" is not supported by firmware.",
return (ENOTSUP);
}
" is not yet supported.",
return (ENOTSUP);
}
return (EINVAL);
}
if (!retval) {
("disconnect starting bd_remove_poll()"));
"board %d is ready to remove",
} else {
}
break;
default:
break;
}
break;
case SYSC_CFGA_RSTATE_EMPTY:
default:
break;
}
return (retval);
}
/*
* This function is called to check the policy for a request to transition
* from the connected/configured state to the connected/unconfigured state only.
* All other requests are invalid.
*/
/*ARGSUSED*/
int
{
int retval;
if (!enable_dynamic_reconfiguration) {
return (ENOTSUP);
}
" is not yet supported.",
return (ENOTSUP);
}
if (!retval) {
} else {
}
break;
default:
break;
}
return (retval);
}
/*
* This function is called to check the policy for a requested transition
* from either the connected/unconfigured state or the connected/configured
* state to the connected/configured state. The redundant state transition
* is permitted for partially configured set of devices. Basically, we
* retry the configure.
*/
/*ARGSUSED*/
int
{
int retval;
return (EINVAL);
}
if (!retval) {
} else {
}
break;
break;
default:
break;
}
break;
case SYSC_CFGA_RSTATE_EMPTY:
default:
break;
}
return (retval);
}
/*ARGSUSED*/
static void
{
case SYSC_CFGA_COND_UNKNOWN:
case SYSC_CFGA_COND_OK:
case SYSC_CFGA_COND_FAILING:
case SYSC_CFGA_COND_FAILED:
/* nothing in the slot so just check power supplies */
case SYSC_CFGA_COND_UNUSABLE:
ps_mutex_is_held) &&
ps_mutex_is_held)) {
} else {
}
break;
default:
break;
}
}
/*ARGSUSED*/
static void
{
if (failure) {
return;
}
/*
* if unknown, we have come from hotplug case so do a quick
* reevaluation.
*/
case SYSC_CFGA_COND_UNKNOWN:
/*
* if ok, we have come from connected to disconnected and we stay
* ok until removed or reevaluate when reconnect. We might have
* experienced a ps fail so reevaluate the condition.
*/
case SYSC_CFGA_COND_OK:
/*
* if unsuable, either power supply was missing or
* hardware was not compatible. Check to see if
* this is still true.
*/
case SYSC_CFGA_COND_UNUSABLE:
/*
* failing must transition in the disconnected state
* to either unusable or unknown. We may have come here
* from cfgadm -f -c disconnect after a power supply failure
* in an attempt to protect the board.
*/
case SYSC_CFGA_COND_FAILING:
ps_mutex_is_held) &&
ps_mutex_is_held)) {
} else {
}
break;
/*
* if failed, we have failed POST and must stay in this
* condition until the board has been removed
* before ever coming back into another condition
*/
case SYSC_CFGA_COND_FAILED:
break;
default:
break;
}
}
/*ARGSUSED*/
static void
{
case SYSC_CFGA_COND_UNKNOWN:
case SYSC_CFGA_COND_OK:
case SYSC_CFGA_COND_FAILING:
case SYSC_CFGA_COND_UNUSABLE:
ps_mutex_is_held) &&
ps_mutex_is_held) &&
} else {
}
break;
case SYSC_CFGA_COND_FAILED:
break;
default:
break;
}
}
static void
{
case SYSC_CFGA_RSTATE_EMPTY:
break;
break;
break;
default:
break;
}
}
void
{
switch (event) {
case SYSC_EVT_BD_EMPTY:
break;
case SYSC_EVT_BD_PRESENT:
} else {
}
break;
case SYSC_EVT_BD_DISABLED:
"disabled %s board in slot %d",
break;
case SYSC_EVT_BD_FAILED:
"failed %s board in slot %d",
break;
case SYSC_EVT_BD_OVERTEMP:
case SYSC_EVT_BD_TEMP_OK:
break;
case SYSC_EVT_BD_PS_CHANGE:
sysc_policy_set_condition((void *)softsp,
}
break;
case SYSC_EVT_BD_INS_FAILED:
break;
case SYSC_EVT_BD_INSERTED:
break;
case SYSC_EVT_BD_REMOVED:
/* now it is ok to free the ac pa memory database */
/* reinitialize sysc_cfga_stat structure */
sysc_stat->fhc_compid = 0;
sizeof (union bd_un));
break;
case SYSC_EVT_BD_HP_DISABLED:
break;
break;
default:
break;
}
}
/*
* signal to POST that the system has been reconfigured and that
* the system configuration status information should be invalidated
* the next time through POST
*/
static void
{
/*
* We are heading into a configuration change!
* Tell post to invalidate its notion of the system configuration.
* This is done by clearing the clock registers...
*/
}
static int
{
}
static int
{
int error = 0;
int del_kstat = 0;
/* find gap for largest supported simm in advance */
/* TODO: Is mempa vulnerable to re-use here? */
/* ASSERT(jtag not held) */
if (error) {
} else {
/* attempt to program the memory while frozen */
}
}
if (error) {
goto done;
}
/*
* Must not delete kstat used by prtdiag until the PROM
* has successfully connected to board.
*/
del_kstat = 1;
if (error)
if (enable_redist) {
}
done:
}
(void) fhc_bdlist_lock(-1);
return (error);
}
static int
{
int rt;
(void) fhc_bdlist_lock(-1);
#ifdef DEBUG
/* it is important to have fhc_bdlist_lock() earlier */
#endif /* DEBUG */
jtm = jtag_master_lock();
#ifdef DEBUG
#endif /* DEBUG */
#ifdef DEBUG
#endif /* DEBUG */
return (rt);
}
static int
{
int error;
void fhc_bd_ks_alloc(fhc_bd_t *);
if (error) {
goto done;
}
if (error) {
goto done;
}
if (enable_redist) {
}
done:
(void) fhc_bdlist_lock(-1);
return (error);
}
static int
{
int error = 0;
if (error) {
goto done;
}
if (enable_redist) {
}
done:
/*
* Value of error gets lost for CPU boards.
*/
int retval_b;
}
}
(void) fhc_bdlist_lock(-1);
return (error);
}
static int
{
int error;
/*
* Check that any memory on board is not in use.
* This must be done while the board list lock is held
* as memory state can change while fhc_bd_busy() is true
* even though a memory operation cannot be started
* if fhc_bd_busy() is true.
*/
"memory bank %d in use",
Bank0);
return (EBUSY);
}
"memory bank %d in use",
Bank1);
return (EBUSY);
}
/*
* Nothing more to do here. The memory interface
* will not make any transitions while
* fhc_bd_busy() is true. Once the ostate
* becomes unconfigured, the memory becomes
* invisible.
*/
}
error = 0;
int cpu_flags = 0;
if (error != 0) {
"processor %d unconfigure failed",
}
}
if (error != 0) {
"processor %d unconfigure failed",
}
}
(void) fhc_bdlist_lock(-1);
}
if (error != 0)
return (error);
}
if (error) {
goto done;
}
if (enable_redist) {
}
done:
(void) fhc_bdlist_lock(-1);
return (error);
}
typedef struct sysc_prom {
} sysc_prom_t;
/*
* Attaching devices on a board.
*/
static int
{
int i;
int err;
devi_branch_t b = {0};
b.type = DEVI_BRANCH_PROM;
/*
* Error only if we fail for fhc dips
*/
}
}
return (0);
}
/*ARGSUSED*/
static int
{
return (EINVAL);
continue;
/*
* Branch rooted at dip already held, so
* release hold acquired in e_ddi_nodeid_to_dip
*/
#ifdef DEBUG
} else {
" e_ddi_nodeid_to_dip() failed for"
" nodeid: %d\n", nid));
#endif
}
} else {
#ifdef DEBUG
#endif
return (EFAULT);
}
}
return (0);
}
/*
* Detaching devices on a board.
*/
static int
{
int i;
for (i = handle->dip_list_len; i > 0; i--) {
}
return (0);
}
static void
{
KM_SLEEP);
handle->dip_list_len = 0;
}
/*ARGSUSED2*/
static int
{
int bd_id;
int len;
int *regp;
bd_id = -1;
if (len > 0) {
/*
* Get board id for EXXXX platforms where
* 0x1c0 is EXXXX platform specific data to
* acquire board id.
*/
}
return (DDI_SUCCESS);
}
return (DDI_FAILURE);
}
/*ARGSUSED*/
static void
{
} else {
}
}
/*
* Uninitialize devices for the state of a board.
*/
static void
{
sizeof (dev_info_t *) * SYSC_DR_MAX_NODE);
handle->dip_list_len = 0;
}
static void
{
char *p;
case ENOMEM:
break;
case EBUSY:
break;
default:
if (attach)
else
if (attach) {
p = "/";
}
break;
}
}
static char *
{
char *type_str;
switch (rstate) {
case SYSC_CFGA_RSTATE_EMPTY:
switch (event) {
case SYSC_AUDIT_RSTATE_EMPTY:
type_str = "emptying";
break;
type_str = "emptied";
break;
type_str = "empty";
break;
default:
type_str = "empty?";
break;
}
break;
switch (event) {
type_str = "disconnecting";
break;
type_str = "disconnected";
break;
type_str = "disconnect";
break;
default:
type_str = "disconnect?";
break;
}
break;
switch (event) {
type_str = "connecting";
break;
type_str = "connected";
break;
type_str = "connect";
break;
default:
type_str = "connect?";
break;
}
break;
default:
type_str = "undefined receptacle state";
break;
}
return (type_str);
}
static char *
{
char *type_str;
switch (ostate) {
switch (event) {
type_str = "unconfiguring";
break;
type_str = "unconfigured";
break;
default:
type_str = "unconfigure?";
break;
}
break;
switch (event) {
type_str = "configuring";
break;
type_str = "configured";
break;
default:
type_str = "configure?";
break;
}
break;
default:
type_str = "undefined occupant state";
break;
}
return (type_str);
}
static void
{
switch (event) {
"%s %s board in slot %d",
event),
break;
"%s %s board in slot %d",
event),
break;
"%s board in slot %d is %s",
event));
break;
"%s board in slot %d failed to %s",
event));
break;
"%s board in slot %d failed to %s",
event));
break;
"%s %s board in slot %d",
event),
break;
"%s %s board in slot %d",
event),
break;
"%s board in slot %d is %s",
event));
break;
"%s board in slot %d partially %s",
event));
break;
"%s board in slot %d partially %s",
event));
break;
default:
"unknown audit of a %s %s board in"
" slot %d",
event),
break;
}
}
static int
{
}
/* ARGSUSED */
static int
{
int upaid;
while (nodeid != OBP_NONODE) {
else
type[0] = '\0';
return (cpu_configure(cpuid));
}
}
return (ENODEV);
}
static int
{
if (type > MAX_BOARD_TYPE)
return (0);
return (sysc_supp_conn[type]);
}
void
{
int proplen;
int i;
/* Check the firmware for Dynamic Reconfiguration support */
if (prom_test("SUNW,Ultra-Enterprise,rm-brd") != 0) {
/* The message was printed in platmod:set_platform_defaults */
}
if (openprom_node != OBP_BADNODE) {
"add-brd-supported-types",
} else {
proplen = -1;
}
if (proplen < 0) {
/*
* This is an old prom which may cause a fatal reset,
* so don't allow any DR operations.
* If enable_dynamic_reconfiguration is 0
* we have already printed a similar message.
*/
" Dynamic Reconfiguration");
}
return;
}
for (i = 0; i < proplen; i++) {
switch (sup_list[i]) {
case '0':
break;
case '1':
break;
case '2':
break;
case '3':
break;
case '4':
break;
case '5':
break;
default:
/* Ignore other characters. */
break;
}
}
if (sysc_supp_conn[CPU_BOARD]) {
} else {
}
tstr[0] = '\0';
if (sysc_supp_conn[IO_2SBUS_BOARD])
if (sysc_supp_conn[IO_PCI_BOARD])
if (tstr[0] != '\0') {
/* Skip leading ", " using &tstr[2]. */
} else {
" Reconfiguration of I/O boards.");
}
}
#ifdef DEBUG
static void
{
int bd_idx;
int reg_idx;
}
}
}
}
static void
boardstat_regdump(void)
{
int bd_idx;
prom_printf("\nBoard status before disconnect.\n");
} else {
}
}
prom_printf(" (before disconnect).\n");
prom_printf("AC_BCSR FHC_CTRL JTAG IGN SIM"
" SISM UIM USM\n");
prom_printf("%08x %08x %08x %04x"
" %08x %04x %08x %04x\n",
}
}
}
static void
display_regdump(void)
{
int bd_idx;
int reg_idx;
prom_printf("Board status after disconnect.\n");
} else {
}
}
prom_printf(" (before and after disconnect).\n");
prom_printf("AC_BCSR FHC_CTRL JTAG IGN SIM"
" SISM UIM USM\n");
prom_printf("%08x %08x %08x %04x"
" %08x %04x %08x %04x\n",
prom_printf("%08x %08x %08x %04x"
" %08x %04x %08x %04x\n",
} else {
prom_printf("no data (board got"
" disconnected)-------------------"
"---------------\n");
}
}
}
}
#endif /* DEBUG */