/*
* 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 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* safari system board DR module.
*/
#include <sys/dditypes.h>
#include <sys/ndi_impldefs.h>
#include <sys/mem_config.h>
#include <sys/mem_cage.h>
#include <sys/autoconf.h>
#include <sys/ddi_impldefs.h>
#include <sys/machsystm.h>
/* start sbd includes */
#include <sys/sysmacros.h>
#include <vm/seg_kmem.h>
extern int nulldev();
extern int nodev();
typedef struct { /* arg to sbd_get_handle */
int cmd;
int mode;
/*
* sbd support operations.
*/
int sbd_errno2ecode(int error);
#ifdef DEBUG
#ifdef SBD_DEBUG_ERRS
/* controls which errors are injected */
/* controls printing about error injection */
#endif /* SBD_DEBUG_ERRS */
#endif /* DEBUG */
char *sbd_state_str[] = {
"EMPTY", "OCCUPIED", "CONNECTED", "UNCONFIGURED",
"PARTIAL", "CONFIGURED", "RELEASE", "UNREFERENCED",
"FATAL"
};
/* Note: this must be changed in tandem with sbd_ioctl.h */
char *sbd_ct_str[] = {
"NONE", "CPU", "MEM", "IO", "UNKNOWN"
};
/* Note: this must also be changed in tandem with sbd_ioctl.h */
#define SBD_CMD_STR(c) \
(((c) == SBD_CMD_ASSIGN) ? "ASSIGN" : \
((c) == SBD_CMD_UNASSIGN) ? "UNASSIGN" : \
((c) == SBD_CMD_POWERON) ? "POWERON" : \
((c) == SBD_CMD_POWEROFF) ? "POWEROFF" : \
((c) == SBD_CMD_TEST) ? "TEST" : \
((c) == SBD_CMD_CONNECT) ? "CONNECT" : \
((c) == SBD_CMD_CONFIGURE) ? "CONFIGURE" : \
((c) == SBD_CMD_UNCONFIGURE) ? "UNCONFIGURE" : \
((c) == SBD_CMD_DISCONNECT) ? "DISCONNECT" : \
((c) == SBD_CMD_STATUS) ? "STATUS" : \
((c) == SBD_CMD_GETNCM) ? "GETNCM" : \
/*
* Defines and structures for device tree naming and mapping
* to node types
*/
/* defines to access the attribute struct */
/*
* State transition table. States valid transitions for "board" state.
* Recall that non-zero return value terminates operation, however
* the herrno value is what really indicates an error , if any.
*/
static int
_cmd2index(int c)
{
/*
* Translate DR CMD to index into sbd_state_transition.
*/
switch (c) {
case SBD_CMD_CONNECT: return (0);
case SBD_CMD_DISCONNECT: return (1);
case SBD_CMD_CONFIGURE: return (2);
case SBD_CMD_UNCONFIGURE: return (3);
case SBD_CMD_POWEROFF: return (4);
case SBD_CMD_POWERON: return (5);
case SBD_CMD_UNASSIGN: return (6);
case SBD_CMD_ASSIGN: return (7);
case SBD_CMD_TEST: return (8);
default: return (-1);
}
}
static struct sbd_state_trans {
int x_cmd;
struct {
} sbd_state_transition[] = {
{
{ 0, 0 }, /* empty */
{ 0, 0 }, /* occupied */
}
},
{
{ 0, 0 }, /* occupied */
{ 0, 0 }, /* connected */
{ 0, 0 }, /* unconfigured */
}
},
{
{ 0, 0 }, /* connected */
{ 0, 0 }, /* unconfigured */
{ 0, 0 }, /* partial */
{ 1, 0 }, /* configured */
{ 0, 0 }, /* release */
{ 0, 0 }, /* unreferenced */
}
},
{
{ 0, 0 }, /* configured */
{ 0, 0 }, /* release */
{ 0, 0 }, /* unreferenced */
}
},
{
{ 0, 0 }, /* occupied */
}
},
{
{ 0, 0 }, /* occupied */
}
},
{
{ 0, 0 }, /* occupied */
}
},
{
{ 0, 0 }, /* occupied */
}
},
{ SBD_CMD_TEST,
{
{ 0, 0 }, /* occupied */
}
},
};
/*
* Global R/W lock to synchronize access across
* multiple boards. Users wanting multi-board access
* must grab WRITE lock, others must grab READ lock.
*/
/*
* Global to determine if an event needs to be sent
*/
char send_event = 0;
/*
*/
dev_info_t *dip);
/*
* Support functions.
*/
void *arg);
struct sbd_state_trans *transp);
int *count, int present_only);
static int sbd_name_to_idx(char *name);
static int sbd_otype_to_idx(char *otpye);
/*
* Autoconfiguration data structures
*/
extern struct mod_ops mod_miscops;
"System Board DR"
};
(void *)&modlmisc,
};
static int sbd_instances = 0;
/*
* dr Global data elements
*/
/*
* We want to be able to unload the module when we wish to do so, but we don't
* want anything else to unload it. Unloading cannot occur until
* sbd_teardown_instance is called by an explicit IOCTL into the parent node.
* This support is for debugging purposes and should it be expected to work
* on the field, it should be enhanced:
* Currently, there is still a window where sbd_teardow_instance gets called,
* sbd_prevent_unloading now = 0, the driver doesn't get unloaded, and
* sbd_setup_instance gets called. This may cause a panic.
*/
/*
* Driver entry points.
*/
int
_init(void)
{
int err;
/*
* If you need to support multiple nodes (instances), then
* whatever the maximum number of supported nodes is would
* need to passed as the third parameter to ddi_soft_state_init().
* Alternative would be to dynamically fini and re-init the
* soft state structure each time a node is attached.
*/
sizeof (sbd_softstate_t), SBD_MAX_INSTANCES);
if (err)
return (err);
return (err);
}
/* Get the array of names from platform helper routine */
return (err);
}
int
_fini(void)
{
int err;
return (DDI_FAILURE);
ASSERT(sbd_instances == 0);
return (err);
return (0);
}
int
{
}
int
{
static fn_t f = "sbd_ioctl";
int dr_avail;
/* Note: this must also be changed in tandem with sbd_ioctl.h */
switch (cmd) {
case SBD_CMD_ASSIGN:
case SBD_CMD_UNASSIGN:
case SBD_CMD_POWERON:
case SBD_CMD_POWEROFF:
case SBD_CMD_TEST:
case SBD_CMD_CONNECT:
case SBD_CMD_CONFIGURE:
case SBD_CMD_UNCONFIGURE:
case SBD_CMD_DISCONNECT:
case SBD_CMD_STATUS:
case SBD_CMD_GETNCM:
case SBD_CMD_PASSTHRU:
break;
default:
return (ENOTTY);
}
"sbd:%s:%d: module not yet attached",
f, instance);
return (ENXIO);
}
/* Check to see if we support dr */
dr_avail = sbdp_dr_avail();
if (dr_avail != 1) {
case SBD_CMD_STATUS:
case SBD_CMD_GETNCM:
case SBD_CMD_PASSTHRU:
break;
default:
return (ENOTSUP);
}
}
case SBD_CMD_STATUS:
case SBD_CMD_GETNCM:
case SBD_CMD_PASSTHRU:
/* no locks needed for these commands */
break;
default:
/*
* If we're dealing with memory at all, then we have
* to keep the "exclusive" global lock held. This is
* necessary since we will probably need to look at
* multiple board structs. Otherwise, we only have
* to deal with the board in question and so can drop
* the global lock to "shared".
*/
/*
* XXX This is incorrect. The sh_devset has not
* been set at this point - it is 0.
*/
if (rv == 0)
break;
}
/*
* Before any operations happen, reset the event flag
*/
send_event = 0;
if (sbd_pre_op(hp) == 0) {
}
*event = send_event;
/* undo locking, if any, done before sbd_pre_op */
case SBD_CMD_STATUS:
case SBD_CMD_GETNCM:
case SBD_CMD_PASSTHRU:
break;
default:
}
return (rv);
}
int
{
int b;
static fn_t f = "sbd_setup_instance";
return (DDI_FAILURE);
}
"sbd:%s:%d: failed to alloc soft-state",
f, instance);
(void) sbdp_teardown_instance(sbdp_arg);
return (DDI_FAILURE);
}
"sbd:%s:%d: failed to get soft-state instance",
f, instance);
goto exit;
}
if (sbd_boardlist == NULL) {
"sbd:%s: failed to alloc board list %d",
f, instance);
goto exit;
}
for (b = 0; b < max_boards; b++) {
}
return (DDI_SUCCESS);
exit:
(void) sbdp_teardown_instance(sbdp_arg);
return (DDI_FAILURE);
}
int
{
return (DDI_FAILURE);
return (DDI_FAILURE);
}
softsp->max_boards);
return (DDI_SUCCESS);
}
static void
{
static fn_t f = "sbd_exec_op";
int dev_canceled;
case SBD_CMD_CONNECT:
if (sbd_probe_board(hp))
break;
break;
case SBD_CMD_CONFIGURE:
break;
case SBD_CMD_UNCONFIGURE:
if (dev_canceled)
sbd_cancel(hp);
break;
case SBD_CMD_DISCONNECT:
if (sbd_disconnect(hp) == 0)
(void) sbd_deprobe_board(hp);
break;
case SBD_CMD_STATUS:
sbd_status(hp);
break;
case SBD_CMD_GETNCM:
break;
case SBD_CMD_ASSIGN:
break;
case SBD_CMD_UNASSIGN:
break;
case SBD_CMD_POWEROFF:
break;
case SBD_CMD_POWERON:
break;
case SBD_CMD_TEST:
break;
case SBD_CMD_PASSTHRU:
{
int rv;
if (rv != 0) {
}
break;
}
default:
"sbd:%s: unknown command (%d)",
break;
}
}
{
int i;
int devicelen;
/*
* if the board's connected or configured, search the
* devlists. Otherwise check the device tree
*/
switch (bstate) {
case SBD_STATE_CONNECTED:
case SBD_STATE_CONFIGURED:
case SBD_STATE_UNREFERENCED:
case SBD_STATE_UNCONFIGURED:
for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++)
return (SBD_COMP_MEM);
for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++)
return (SBD_COMP_CPU);
for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++)
return (SBD_COMP_IO);
/*FALLTHROUGH*/
default:
break;
for (i = 0; SBD_COMP(i) != SBD_COMP_UNKNOWN; i++) {
continue;
return (SBD_COMP(i));
}
break;
}
return (SBD_COMP_UNKNOWN);
}
static void
{
int n, unit;
pass = 1;
int err;
if (err < 0) {
break;
} else if (err > 0) {
pass++;
continue;
}
for (n = 0; n < devnum; n++) {
SBD_SET_ERRNO(ep, 0);
SBD_SET_ERR(ep, 0);
if (unit < 0) {
break;
}
switch (nodetype) {
case SBD_COMP_MEM:
return;
}
break;
case SBD_COMP_CPU:
break;
case SBD_COMP_IO:
break;
default:
break;
}
continue;
}
if (err < 0)
break;
pass++;
}
}
static int
{
int n, unit;
int err = 0;
int dev_canceled;
pass = 1;
while ((devlist =
if (err < 0) {
dev_canceled = 1;
break;
} else if (err > 0) {
pass++;
continue;
}
dev_canceled = 0;
for (n = 0; n < devnum; n++) {
if (unit < 0) {
break;
}
if ((nodetype == SBD_COMP_MEM) &&
dev_canceled++;
}
}
if (err < 0)
break;
if (dev_canceled)
break;
pass++;
}
if (dev_canceled)
return (dev_canceled);
return (err);
}
static int
{
int n, unit;
int dev_canceled = 0;
static fn_t f = "sbd_dev_unconfigure";
PR_ALL("%s...\n", f);
pass = 1;
if (err) {
/*
* Only cancel the operation for memory in
* case of failure.
*/
if (nodetype == SBD_COMP_MEM)
dev_canceled = 1;
break;
}
for (n = 0; n < devnum; n++) {
SBD_SET_ERRNO(ep, 0);
SBD_SET_ERR(ep, 0);
if (unit < 0) {
break;
}
switch (nodetype) {
case SBD_COMP_MEM:
break;
case SBD_COMP_CPU:
break;
case SBD_COMP_IO:
break;
default:
break;
}
detach_err = -1;
break;
}
}
if ((err < 0) || (detach_err < 0))
break;
pass++;
}
return (dev_canceled);
}
int
{
int rv;
switch (error) {
case EBUSY:
break;
case EINVAL:
rv = ESBD_INVAL;
break;
case EALREADY:
rv = ESBD_ALREADY;
break;
case ENODEV:
rv = ESBD_NODEV;
break;
case ENOMEM:
rv = ESBD_NOMEM;
break;
default:
rv = ESBD_INVAL;
}
return (rv);
}
static void
{
int rv = 0;
static fn_t f = "sbd_attach_cpu";
char *pathname;
/*
* With the introduction of CMP devices, the CPU nodes
* are no longer directly under the top node. Since
* there is no plan to support CPU attach in the near
* future, a branch configure operation is not required.
*/
if (cpuid < 0) {
rv = -1;
"sbd:%s: cpu_configure for cpuid %d failed",
f, cpuid);
}
if (rv == 0) {
}
}
/*
* translate errno
*/
void
{
switch (err) {
case ENOMEM:
break;
case EBUSY:
break;
case EIO:
break;
case ENXIO:
break;
case EINVAL:
break;
case EFAULT:
default:
break;
}
}
static void
{
int rv;
static fn_t f = "sbd_detach_cpu";
if (cpuid < 0) {
return;
}
"sbd:%s: cpu_unconfigure for cpu %d failed",
f, cpuid);
return;
}
/*
* Since CPU nodes are no longer configured in CPU
* attach, the corresponding branch unconfigure
* operation that would be performed here is also
* no longer required.
*/
}
int
{
int i, rv;
static fn_t f = "sbd_detach_mem";
return (-1);
}
/*
* Now detach mem devinfo nodes with status lock held.
*/
for (i = 0; i < SBD_NUM_MC_PER_BOARD; i++) {
continue;
if (rv) {
/*
* If non-NULL, fdip is returned held and must be
* released.
*/
} else {
}
}
}
return (0);
}
/* start beginning of sbd.c */
/*
* MDR memory support - somewhat disabled for now.
* UNSAFE unsafe driver code - I don't think we want this.
* need to check.
* DEVNODE This driver creates attachment points for individual
* components as well as boards. We only need board
* support.
* DEV2DEVSET Put only present devices in devset.
*/
static sbd_state_t
{
switch (state) {
case SBD_STATE_EMPTY:
cs = SBD_STAT_EMPTY;
break;
case SBD_STATE_OCCUPIED:
case SBD_STATE_FATAL:
break;
case SBD_STATE_CONFIGURED:
case SBD_STATE_CONNECTED:
case SBD_STATE_UNCONFIGURED:
case SBD_STATE_PARTIAL:
case SBD_STATE_RELEASE:
case SBD_STATE_UNREFERENCED:
break;
default:
cs = SBD_STAT_NONE;
break;
}
return (cs);
}
{
switch (state) {
case SBD_STATE_EMPTY:
case SBD_STATE_OCCUPIED:
case SBD_STATE_UNCONFIGURED:
case SBD_STATE_CONNECTED:
case SBD_STATE_FATAL:
break;
case SBD_STATE_PARTIAL:
case SBD_STATE_CONFIGURED:
case SBD_STATE_RELEASE:
case SBD_STATE_UNREFERENCED:
break;
default:
cs = SBD_STAT_NONE;
break;
}
return (cs);
}
int
{
int b;
static fn_t f = "sbd_dealloc_instance";
PR_ALL("%s...\n", f);
return (-1);
}
for (b = 0; b < max_boards; b++) {
sbd_board_destroy(sbp++);
}
return (0);
}
static sbd_devset_t
{
static fn_t f = "sbd_dev2devset";
case SBD_COMP_NONE:
break;
case SBD_COMP_CPU:
PR_ALL("%s: invalid cpu unit# = %d",
f, unit);
devset = 0;
} else
/*
* Generate a devset that includes all the
* cores of a CMP device. If this is not a
* CMP, the extra cores will be eliminated
* later since they are not present. This is
* also true for CMP devices that do not have
* all cores active.
*/
break;
case SBD_COMP_MEM:
#ifdef XXX_jeffco
PR_ALL("%s: invalid mem unit# = %d",
f, unit);
devset = 0;
#endif
PR_ALL("%s: adjusted MEM devset = 0x%x\n",
f, devset);
} else
break;
case SBD_COMP_IO:
PR_ALL("%s: invalid io unit# = %d",
f, unit);
devset = 0;
} else
break;
default:
case SBD_COMP_UNKNOWN:
devset = 0;
break;
}
return (devset);
}
/*
* Simple mutex for covering handle list ops as it is only
* used "infrequently". No need to add another mutex to the sbd_board_t.
*/
static sbd_handle_t *
{
int board;
/*
* Brand-new handle.
*/
return (hp);
}
void
{
}
int
{
/*
* If there is an error logged already, don't rewrite it
*/
return (0);
}
return (0);
}
return (-1);
}
static void
{
static fn_t f = "sbd_release_handle";
return;
/*
* Locate the handle in the board's reference list.
*/
/* empty */;
"sbd:%s: handle not found in board %d",
/*NOTREACHED*/
} else {
}
}
}
{
} else {
}
} else {
}
return (hdp);
}
void
{
return;
}
void
{
}
}
static int
{
static fn_t f = "sbd_copyin_ioarg";
return (EINVAL);
#ifdef _MULTI_DATAMODEL
sizeof (sbd_cmd32_t), mode)) {
"sbd:%s: (32bit) failed to copyin "
"sbdcmd-struct", f);
return (EFAULT);
}
if (cmd == SBD_CMD_PASSTHRU) {
sizeof (sbd_cmd32_t));
PR_BYP("passthru copyin: c_opts=%x, c_len=%d",
}
switch (cmd) {
case SBD_CMD_STATUS:
break;
default:
break;
}
} else
#endif /* _MULTI_DATAMODEL */
"sbd:%s: failed to copyin sbd cmd_t struct", f);
return (EFAULT);
}
/*
* A user may set platform specific options so we need to
* copy them in
*/
> 0)) {
/* copts is freed in sbd_release_handle(). */
"sbd:%s: failed to copyin options", f);
return (EFAULT);
}
}
return (0);
}
static int
{
static fn_t f = "sbd_copyout_ioarg";
return (EINVAL);
#ifdef _MULTI_DATAMODEL
switch (cmd) {
case SBD_CMD_GETNCM:
break;
default:
break;
}
sizeof (sbd_cmd32_t), mode)) {
"sbd:%s: (32bit) failed to copyout "
"sbdcmd struct", f);
return (EFAULT);
}
} else
#endif /* _MULTI_DATAMODEL */
"sbd:%s: failed to copyout sbdcmd struct", f);
return (EFAULT);
}
return (0);
}
static int
{
static fn_t f = "sbd_copyout_errs";
#ifdef _MULTI_DATAMODEL
sizeof (sbd_error32_t), mode)) {
"sbd:%s: failed to copyout ioctl32 errs",
f);
return (EFAULT);
}
} else
#endif /* _MULTI_DATAMODEL */
sizeof (sbd_error_t), mode) != 0) {
"sbd:%s: failed to copyout ioctl errs", f);
return (EFAULT);
}
return (0);
}
/*
* State transition policy is that if at least one
* device cannot make the transition, then none of
* the requested devices are allowed to transition.
*
* Returns the state that is in error, if any.
*/
static int
struct sbd_state_trans *transp)
{
int s, ut;
int state_err = 0;
static fn_t f = "sbd_check_transition";
if (!devset) {
/*
* Transition does not deal with any components.
* This is the case for addboard/deleteboard.
*/
PR_ALL("%s: no devs: requested devset = 0x%x,"
" final devset = 0x%x\n",
return (0);
}
continue;
if (!state_err)
state_err = s;
}
}
}
continue;
if (!state_err)
state_err = s;
}
}
}
continue;
if (!state_err)
state_err = s;
}
}
}
PR_ALL("%s: requested devset = 0x%x, final devset = 0x%x\n",
/*
* If there are some remaining components for which
* this state transition is valid, then allow them
* through, otherwise if none are left then return
* the state error.
*/
}
/*
* pre-op entry point must SET_ERRNO(), if needed.
* Return value of non-zero indicates failure.
*/
static int
{
int rv = 0, t;
static fn_t f = "sbd_pre_op";
switch (cmd) {
case SBD_CMD_CONNECT:
case SBD_CMD_DISCONNECT:
case SBD_CMD_UNCONFIGURE:
case SBD_CMD_CONFIGURE:
case SBD_CMD_ASSIGN:
case SBD_CMD_UNASSIGN:
case SBD_CMD_POWERON:
case SBD_CMD_POWEROFF:
case SBD_CMD_TEST:
/* ioctls allowed if caller has write permission */
return (-1);
}
default:
break;
}
if (rv) {
return (-1);
} else {
}
}
if (devset == 0) {
return (-1);
}
}
/*
* Always turn on these bits ala Sunfire DR.
*/
/*
* Check for valid state transitions.
*/
int state_err;
transp = &sbd_state_transition[t];
if (state_err < 0) {
/*
* Invalidate device.
*/
serr = -1;
PR_ALL("%s: invalid devset (0x%x)\n",
} else if (state_err != 0) {
/*
* State transition is not a valid one.
*/
PR_ALL("%s: invalid state %s(%d) for cmd %s(%d)\n",
}
/*
* A state transition error occurred.
*/
if (serr < 0) {
} else {
}
PR_ALL("%s: invalid state transition\n", f);
} else {
}
}
/*
* There was a state error. We successfully copied
* in the ioctl argument, so let's fill in the
* error and copy it back out.
*/
rv = -1;
}
return (rv);
}
static void
{
int cmd;
switch (cmd) {
case SBD_CMD_CONFIGURE:
case SBD_CMD_UNCONFIGURE:
case SBD_CMD_CONNECT:
case SBD_CMD_DISCONNECT:
break;
default:
break;
}
}
}
}
}
}
static int
{
int rv;
static fn_t f = "sbd_probe_board";
}
/*
* We need to force a recache after the connect. The cached
* info may be incorrect
*/
ESGT_PROBE, NULL);
return (rv);
}
static int
{
int rv;
static fn_t f = "sbd_deprobe_board";
PR_ALL("%s...\n", f);
}
ESGT_DEPROBE, NULL);
return (rv);
}
/*
* Check if a CPU node is part of a CMP.
*/
int
{
return (0);
}
return (1);
}
return (0);
}
/*
* Returns the nodetype if dip is a top dip on the board of
* interest or SBD_COMP_UNKNOWN otherwise
*/
static sbd_comp_type_t
{
int otypelen;
if (unitp)
*unitp = -1;
return (SBD_COMP_UNKNOWN);
}
/*
* sbdp_get_unit_num will return (-1) for cmp as there
* is no "device_type" property associated with cmp.
* Therefore we will just skip getting unit number for
* cmp. Callers of this function need to check the
* value set in unitp before using it to dereference
* an array.
*/
return (SBD_COMP_CMP);
}
return (SBD_COMP_UNKNOWN);
}
return (SBD_COMP_UNKNOWN);
}
if (unit == -1) {
return (SBD_COMP_UNKNOWN);
}
if (unitp)
}
typedef struct {
int nmc;
int hold;
} walk_tree_t;
static int
{
static fn_t f = "sbd_setup_devlists";
int unit;
PR_ALL("%s:bad arg\n", f);
return (DDI_WALK_TERMINATE);
}
switch (nodetype) {
case SBD_COMP_CPU:
break;
case SBD_COMP_MEM:
break;
case SBD_COMP_IO:
break;
case SBD_COMP_CMP:
case SBD_COMP_UNKNOWN:
/*
* This dip is not of interest to us
*/
return (DDI_WALK_CONTINUE);
default:
ASSERT(0);
return (DDI_WALK_CONTINUE);
}
/*
* dip's parent is being held busy by ddi_walk_devs(),
* so dip doesn't have to be held while calling ddi_pathname()
*/
if (pathname) {
}
/*
* The branch rooted at dip should already be held,
* unless we are dealing with a core of a CMP.
*/
/*
* This test is required if multiple devices are considered
* as one. This is the case for memory-controller nodes.
*/
}
if (nodetype == SBD_COMP_MEM) {
}
return (DDI_WALK_CONTINUE);
}
/*
* This routine is used to construct the memory devlist.
* In Starcat and Serengeti platforms, a system board can contain up to
* four memory controllers (MC). The MCs have been programmed by POST for
* optimum memory interleaving amongst their peers on the same board.
* This DR driver does not support deinterleaving. Therefore, the smallest
* unit of memory that can be manipulated by this driver is all of the
* memory on a board. Because of this restriction, a board's memory devlist
* is populated with only one of the four (possible) MC dnodes on that board.
* Care must be taken to ensure that the selected MC dnode represents the
* lowest physical address to which memory on the board will respond to.
* This is required in order to preserve the semantics of
* sbdp_get_base_physaddr() when applied to a MC dnode stored in the
* memory devlist.
*/
static void
{
int i;
return; /* No MC dips found for this board */
/* TODO: log complaint about dnode */
/*
* We are here because sbdphw_get_base_physaddr() failed.
* Although it is very unlikely to happen, it did. Lucky us.
* Since we can no longer examine _all_ of the MCs on this
* board to determine which one is programmed to the lowest
* physical address, we cannot involve any of the MCs on
* this board in DR operations. To ensure this, we pretend
* that this board does not contain any memory.
*
* Paranoia: clear the dev_present mask.
*/
}
for (i = 0; i < SBD_NUM_MC_PER_BOARD; i++) {
}
return;
}
/* assume this one will win. */
/*
* We know the base physical address of one of the MC devices. Now
* we will enumerate through all of the remaining MC devices on
* the board to find which of them is programmed to the lowest
* physical address.
*/
for (i = 1; i < SBD_NUM_MC_PER_BOARD; i++) {
break;
}
break;
}
}
}
}
static int
{
int idx;
break;
}
}
return (idx);
}
static int
{
int idx;
break;
}
}
return (idx);
}
static int
{
int i;
static fn_t f = "sbd_init_devlists";
/*
* Clear out old entries, if any.
*/
for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
}
for (i = 0; i < SBD_NUM_MC_PER_BOARD; i++) {
}
for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
}
for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
}
/*
* ddi_walk_devs() requires that topdip's parent be held.
*/
if (pdip) {
ndi_devi_enter(pdip, &i);
}
if (pdip) {
ndi_devi_exit(pdip, i);
}
/*
* There is no point checking all the components if there
* are no devices.
*/
sbp->sb_memaccess_ok = 0;
}
/*
* Initialize cpu sections before calling sbd_init_mem_devlists
* which will access the mmus.
*/
for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
sbd_init_cpu_unit(sbp, i);
if (sbd_connect_cpu(sbp, i)) {
}
}
}
if (sbp->sb_memaccess_ok) {
} else {
}
}
static void
{
int cpuid;
} else {
}
if (&sbdp_cpu_get_impl)
else
else
/*
* Any changes to the cpu should be performed above
* this call to ensure the cpu is fully initialized
* before transitioning to the new state.
*/
}
/*
* Only do work if called to operate on an entire board
* which doesn't already have components present.
*/
static void
{
static fn_t f = "sbd_connect";
if (SBD_DEVS_PRESENT(sbp)) {
/*
* Board already has devices present.
*/
PR_ALL("%s: devices already present (0x%x)\n",
f, SBD_DEVS_PRESENT(sbp));
return;
}
if (sbd_init_devlists(sbp) == 0) {
return;
} else {
int i;
/*
* Initialize mem-unit section of board structure.
*/
for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++)
/*
* Initialize sb_io sections.
*/
for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++)
sbd_init_io_unit(sbp, i);
}
}
static int
{
int i;
static fn_t f = "sbd_disconnect it";
PR_ALL("%s ...\n", f);
/*
* Only devices which are present, but
* unattached can be disconnected.
*/
/*
* Update per-device state transitions.
*/
for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++)
if (sbd_disconnect_mem(hp, i) == 0) {
}
}
for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++)
if (sbd_disconnect_cpu(hp, i) == 0) {
}
}
for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++)
if (sbd_disconnect_io(hp, i) == 0) {
}
}
/*
* Once all the components on a board have been disconnect
* the board's state can transition to disconnected and
* we can allow the deprobe to take place.
*/
if (SBD_DEVS_PRESENT(sbp) == 0) {
return (0);
} else {
return (-1);
}
}
static void
{
}
}
static void
{
if (sbdp_assign_board(hdp) != 0) {
}
}
static void
{
if (sbdp_unassign_board(hdp) != 0) {
}
}
static void
{
if (sbdp_poweron_board(hdp) != 0) {
}
}
static void
{
if (sbdp_poweroff_board(hdp) != 0) {
}
}
/*
* Return a list of the dip's of devices that are
* either present and attached, or present only but
* not yet attached for the given board.
*/
{
int i, ix;
*count = 0;
/*
* Turn into binary value since we're going
* to be using XOR for a comparison.
* if (present_only) then
* dev must be PRESENT, but NOT ATTACHED.
* else
* dev must be PRESENT AND ATTACHED.
* endif
*/
if (present_only)
present_only = 1;
/*
* For CMPs, we would like to perform DR operation on
* all the cores before moving onto the next chip.
* Therefore, when constructing the devlist, we process
* all the cores together.
*/
if (nodetype == SBD_COMP_CPU) {
/*
* Number of units to process in the inner loop
*/
/*
* The distance between the units in the
* board's sb_devlist structure.
*/
} else {
nunits = 1;
distance = 0;
}
for (j = 0; j < nunits; j++) {
continue;
if (ut == -1) {
PR_ALL("sbd_get_devlist bad unit %d"
" code %d errno %d",
}
continue;
1 : 0;
1 : 0;
ix++;
}
}
}
ret_devlist = NULL;
}
return (ret_devlist);
}
static sbd_devlist_t *
{
static fn_t f = "sbd_get_attach_devlist";
*devnump = 0;
/*
* We switch on next_pass for the cases where a board
* does not contain a particular type of component.
* In these situations we don't want to return NULL
* prematurely. We need to check other devices and
* we don't want to check the same type multiple times.
* For example, if there were no cpus, then on pass 1
* we would drop through and return the memory nodes.
* However, on pass 2 we would switch back to the memory
* nodes thereby returning them twice! Using next_pass
* forces us down to the end (or next item).
*/
if (pass == 1)
next_pass = 1;
switch (next_pass) {
case 1:
if (!devset || attach_devlist) {
next_pass = 2;
return (attach_devlist);
}
/*
* If the caller is interested in the entire
* board, but there aren't any cpus, then just
* fall through to check for the next component.
*/
}
/*FALLTHROUGH*/
case 2:
if (!devset || attach_devlist) {
next_pass = 3;
return (attach_devlist);
}
/*
* If the caller is interested in the entire
* board, but there isn't any memory, then
* just fall through to next component.
*/
}
/*FALLTHROUGH*/
case 3:
next_pass = -1;
if (!devset || attach_devlist) {
next_pass = 4;
return (attach_devlist);
}
}
/*FALLTHROUGH*/
default:
*devnump = 0;
return (NULL);
}
/*NOTREACHED*/
}
static int
{
static fn_t f = "sbd_pre_attach_devlist";
/*
* In this driver, all entries in a devlist[] are
* of the same nodetype.
*/
PR_ALL("%s (nt = %s(%d), num = %d)...\n",
switch (nodetype) {
case SBD_COMP_MEM:
break;
case SBD_COMP_CPU:
break;
case SBD_COMP_IO:
break;
default:
rv = -1;
break;
}
int i;
/*
* Need to clean up devlist
* if pre-op is going to fail.
*/
for (i = 0; i < max_units; i++) {
} else {
break;
}
}
}
/*
* If an error occurred, return "continue"
* indication so that we can continue attaching
* as much as possible.
*/
return (rv ? -1 : 0);
}
static int
{
static fn_t f = "sbd_post_attach_devlist";
PR_ALL("%s (nt = %s(%d), num = %d)...\n",
/*
* Need to free up devlist[] created earlier in
* sbd_get_attach_devlist().
*/
switch (nodetype) {
case SBD_COMP_CPU:
break;
case SBD_COMP_MEM:
break;
case SBD_COMP_IO:
break;
default:
rv = -1;
break;
}
for (i = 0; i < devnum; i++) {
int unit;
continue;
if (unit == -1) {
continue;
}
if (unit == -1) {
PR_ALL("%s: ERROR (nt=%s, b=%d, u=%d) not attached\n",
continue;
}
}
if (rv) {
PR_ALL("%s: errno %d, ecode %d during attach\n",
}
switch (SBD_BOARD_STATE(sbp)) {
case SBD_STATE_CONNECTED:
case SBD_STATE_UNCONFIGURED:
if (devs_unattached == 0) {
/*
* All devices finally attached.
*/
} else if (devs_present != devs_unattached) {
/*
* Only some devices are fully attached.
*/
}
break;
case SBD_STATE_PARTIAL:
/*
* All devices finally attached.
*/
if (devs_unattached == 0) {
}
break;
default:
break;
}
int i;
for (i = 0; i < max_units; i++) {
} else {
break;
}
}
}
/*
* Our policy is to attach all components that are
* possible, thus we always return "success" on the
* pre and post operations.
*/
return (0);
}
/*
* We only need to "release" cpu and memory devices.
*/
static sbd_devlist_t *
{
static fn_t f = "sbd_get_release_devlist";
*devnump = 0;
/*
* We switch on next_pass for the cases where a board
* does not contain a particular type of component.
* In these situations we don't want to return NULL
* prematurely. We need to check other devices and
* we don't want to check the same type multiple times.
* For example, if there were no cpus, then on pass 1
* we would drop through and return the memory nodes.
* However, on pass 2 we would switch back to the memory
* nodes thereby returning them twice! Using next_pass
* forces us down to the end (or next item).
*/
if (pass == 1)
next_pass = 1;
switch (next_pass) {
case 1:
if (!devset || release_devlist) {
next_pass = 2;
return (release_devlist);
}
/*
* If the caller is interested in the entire
* board, but there isn't any memory, then
* just fall through to next component.
*/
}
/*FALLTHROUGH*/
case 2:
if (!devset || release_devlist) {
next_pass = 3;
return (release_devlist);
}
/*
* If the caller is interested in the entire
* board, but there aren't any cpus, then just
* fall through to check for the next component.
*/
}
/*FALLTHROUGH*/
case 3:
next_pass = -1;
if (!devset || release_devlist) {
next_pass = 4;
return (release_devlist);
}
}
/*FALLTHROUGH*/
default:
*devnump = 0;
return (NULL);
}
/*NOTREACHED*/
}
static int
{
static fn_t f = "sbd_pre_release_devlist";
PR_ALL("%s (nt = %s(%d), num = %d)...\n",
switch (nodetype) {
case SBD_COMP_CPU: {
int i, mem_present = 0;
for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
/*
* if client also requested to unconfigure memory
* the we allow the operation. Therefore
* we need to warranty that memory gets unconfig
* before cpus
*/
continue;
}
mem_present = 1;
break;
}
}
if (mem_present) {
rv = -1;
} else {
}
break;
}
case SBD_COMP_MEM:
break;
case SBD_COMP_IO:
break;
default:
rv = -1;
break;
}
int i;
/*
* the individual pre_release component routines should
* have set the error in the handle. No need to set it
* here
*
* Need to clean up dynamically allocated devlist
* if pre-op is going to fail.
*/
for (i = 0; i < max_units; i++) {
} else {
break;
}
}
}
return (rv ? -1 : 0);
}
static int
{
int i, max_units = 0;
static fn_t f = "sbd_post_release_devlist";
PR_ALL("%s (nt = %s(%d), num = %d)...\n",
/*
* Need to free up devlist[] created earlier in
* sbd_get_release_devlist().
*/
switch (nodetype) {
case SBD_COMP_CPU:
break;
case SBD_COMP_MEM:
break;
case SBD_COMP_IO:
/*
* Need to check if specific I/O is referenced and
* fail post-op.
*/
PR_IO("%s: error - I/O devices ref'd\n", f);
}
break;
default:
{
f, (int)nodetype);
}
break;
}
for (i = 0; i < devnum; i++) {
int unit;
continue;
}
if (unit == -1) {
PR_ALL("%s bad unit num: %d code %d",
continue;
}
}
PR_ALL("%s: errno %d, ecode %d during release\n",
}
int i;
for (i = 0; i < max_units; i++) {
} else {
break;
}
}
}
}
static void
{
}
static void
{
int unit;
static fn_t f = "sbd_release_done";
PR_ALL("%s...\n", f);
"sbd:%s: unable to get unit for dip (0x%p)",
f, (void *)dip);
return;
}
/*
* Transfer the device which just completed its release
* to the UNREFERENCED state.
*/
switch (nodetype) {
case SBD_COMP_MEM:
break;
default:
break;
}
/*
* If the entire board was released and all components
* unreferenced then transfer it to the UNREFERENCED state.
*/
}
}
static sbd_devlist_t *
{
static fn_t f = "sbd_get_detach_devlist";
*devnump = 0;
/*
* We switch on next_pass for the cases where a board
* does not contain a particular type of component.
* In these situations we don't want to return NULL
* prematurely. We need to check other devices and
* we don't want to check the same type multiple times.
* For example, if there were no cpus, then on pass 1
* we would drop through and return the memory nodes.
* However, on pass 2 we would switch back to the memory
* nodes thereby returning them twice! Using next_pass
* forces us down to the end (or next item).
*/
if (pass == 1)
next_pass = 1;
switch (next_pass) {
case 1:
if (!devset || detach_devlist) {
next_pass = 2;
return (detach_devlist);
}
/*
* If the caller is interested in the entire
* board, but there isn't any memory, then
* just fall through to next component.
*/
}
/*FALLTHROUGH*/
case 2:
if (!devset || detach_devlist) {
next_pass = 2;
return (detach_devlist);
}
/*
* If the caller is interested in the entire
* board, but there aren't any cpus, then just
* fall through to check for the next component.
*/
}
/*FALLTHROUGH*/
case 3:
next_pass = -1;
if (!devset || detach_devlist) {
next_pass = 4;
return (detach_devlist);
}
}
/*FALLTHROUGH*/
default:
*devnump = 0;
return (NULL);
}
/*NOTREACHED*/
}
static int
{
int rv = 0;
static fn_t f = "sbd_pre_detach_devlist";
PR_ALL("%s (nt = %s(%d), num = %d)...\n",
switch (nodetype) {
case SBD_COMP_CPU:
break;
case SBD_COMP_MEM:
break;
case SBD_COMP_IO:
break;
default:
rv = -1;
break;
}
/*
* We want to continue attempting to detach
* other components.
*/
return (rv);
}
static int
{
static fn_t f = "sbd_post_detach_devlist";
PR_ALL("%s (nt = %s(%d), num = %d)...\n",
/*
* Need to free up devlist[] created earlier in
* sbd_get_detach_devlist().
*/
switch (nodetype) {
case SBD_COMP_CPU:
break;
case SBD_COMP_MEM:
break;
case SBD_COMP_IO:
break;
default:
rv = -1;
break;
}
for (i = 0; i < devnum; i++) {
int unit;
continue;
if (unit == -1) {
continue;
else {
break;
}
}
ep) >= 0) {
/*
* Device is still attached probably due
* to an error. Need to keep track of it.
*/
PR_ALL("%s: ERROR (nt=%s, b=%d, u=%d) not detached\n",
unit);
continue;
}
}
if (bstate != SBD_STATE_UNCONFIGURED) {
/*
* All devices are finally detached.
*/
SBD_DEVS_ATTACHED(sbp)) {
/*
* Some devices remain attached.
*/
}
}
if (rv) {
PR_ALL("%s: errno %d, ecode %d during detach\n",
}
int i;
for (i = 0; i < max_units; i++) {
} else {
break;
}
}
}
}
/*
* Return the unit number of the respective dip if
* it's found to be attached.
*/
static int
{
extern struct memlist *phys_install;
static fn_t f = "sbd_check_unit_attached";
switch (nodetype) {
case SBD_COMP_CPU:
if (cpuid < 0) {
break;
}
break;
case SBD_COMP_MEM:
break;
}
break;
}
/*
* Check if base address is in phys_install.
*/
continue;
else
break;
break;
case SBD_COMP_IO:
{
/*
* ddi_walk_devs() requires that topdip's parent be held.
*/
if (pdip) {
}
(void *)&tdip);
if (pdip) {
}
else
rv = -1;
break;
}
default:
PR_ALL("%s: unexpected nodetype(%d) for dip 0x%p\n",
rv = -1;
break;
}
/*
* Save the error that sbdp sent us and report it
*/
if (rv == -1)
return (rv);
}
/*
* Return memhandle, if in fact, this memunit is the owner of
* a scheduled memory delete.
*/
int
{
int unit;
static fn_t f = "sbd_get_memhandle";
PR_MEM("%s...\n", f);
if (unit == -1) {
return (-1);
}
return (0);
} else {
return (-1);
}
/*NOTREACHED*/
}
static int
{
int c, cix;
/*
* Only look for requested devices that are actually present.
*/
for (c = cix = 0; c < MAX_CMP_UNITS_PER_BOARD; c++) {
/*
* Index for core 1 , if exists.
* With the current implementation it is
* MAX_CMP_UNITS_PER_BOARD off from core 0.
* The calculation will need to change if
* the assumption is no longer true.
*/
continue;
}
/*
* Check to see if the dip(s) exist for this chip
*/
continue;
cix++;
}
return (cix);
}
static int
{
int i, ix;
/*
* Only look for requested devices that are actually present.
*/
for (i = ix = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
continue;
}
continue;
ix++;
}
return (ix);
}
/*
* NOTE: This routine is only partially smart about multiple
* mem-units. Need to make mem-status structure smart
* about them also.
*/
static int
{
extern int kcage_on;
int i;
static fn_t f = "sbd_mem_status";
/*
* Check the present devset and access the dip with
* status lock held to protect agains a concurrent
* unconfigure or disconnect thread.
*/
/*
* Only look for requested devices that are actually present.
*/
for (m = mix = 0; m < MAX_MEM_UNITS_PER_BOARD; m++) {
continue;
/*
* Check to make sure the memory unit is in a state
* where its fully initialized.
*/
continue;
continue;
/*
* The plugin expects -1 for the mem unit
*/
/*
* Get the memory name from what sbdp gave us
*/
for (i = 0; SBD_COMP(i) != SBD_COMP_UNKNOWN; i++) {
if (SBD_COMP(i) == SBD_COMP_MEM) {
}
}
/* XXX revisit this after memory conversion */
sbp, SBD_COMP_MEM, m));
else
/*
* Any pages above managed is "free",
* i.e. it's collected.
*/
} else {
/*
* If we're UNREFERENCED or UNCONFIGURED,
* then the number of detached pages is
* however many pages are on the board.
* I.e. detached = not in use by OS.
*/
/*
* changed to use cfgadm states
*
* was:
* case SFDR_STATE_UNREFERENCED:
* case SFDR_STATE_UNCONFIGURED:
*/
case SBD_STAT_UNCONFIGURED:
break;
default:
break;
}
}
if (mq.nonrelocatable) {
dsp->ds_suspend);
}
} else {
}
mix++;
dsp++;
}
return (mix);
}
static void
{
int i;
static fn_t f = "sbd_cancel";
int rv;
PR_ALL("%s...\n", f);
/*
* Only devices which have been "released" are
* subject to cancellation.
*/
/*
* Nothing to do for CPUs or IO other than change back
* their state.
*/
for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
continue;
} else {
}
}
for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
continue;
}
for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
continue;
} else if (rv == -1) {
}
}
if (SBD_DEVS_UNREFERENCED(sbp) == 0) {
/*
* If the board no longer has any released devices
*/
else
}
}
}
static void
{
int error;
/* pre_op restricted the devices to those selected by the ioctl */
if (error != 0)
}
static void
{
#ifdef _MULTI_DATAMODEL
int sz32;
#endif /* _MULTI_DATAMODEL */
static fn_t f = "sbd_status";
/*
* Get the number of components "ncm" on the board.
* Calculate size of buffer required to store one
* sbd_stat_t structure plus ncm-1 sbd_dev_stat_t
* structures. Note that sbd_stat_t already contains
* one sbd_dev_stat_t, so only an additional ncm-1
* sbd_dev_stat_t structures need to be accounted for
* in the calculation when more than one component
* is present.
*/
} else {
/*
* In the case of c_type == SBD_COMP_NONE, and
* SBD_FLAG_ALLCMP not specified, only the board
* info is to be returned, no components.
*/
ncm = 0;
devset = 0;
}
} else {
/* Confirm that only one component is selected. */
if (ncm != 1) {
PR_ALL("%s: expected ncm of 1, got %d, devset 0x%x\n",
return;
}
}
sz = sizeof (sbd_stat_t);
if (ncm > 1)
/*
* s_nbytes describes the size of the preallocated user
* buffer into which the application is executing to
* receive the sbd_stat_t and sbd_dev_stat_t structures.
* This buffer must be at least the required (sz) size.
*/
#ifdef _MULTI_DATAMODEL
/*
* More buffer space is required for the 64bit to 32bit
* conversion of data structures.
*/
sz32 = sizeof (sbd_stat32_t);
if (ncm > 1)
} else
sz32 = 0;
#endif
return;
}
#ifdef _MULTI_DATAMODEL
if (sz32 != 0)
#endif
/*
* if connected or better, provide cached status if available,
* otherwise call sbdp for status
*/
case SBD_STATE_CONNECTED:
case SBD_STATE_PARTIAL:
case SBD_STATE_CONFIGURED:
break;
}
/*FALLTHROUGH*/
default:
#ifdef _MULTI_DATAMODEL
if (sz32 != 0)
#endif
return;
}
/*
* Do not cache status if the busy flag has
* been set by the call to sbdp_get_board_status().
*/
/* Can get board busy flag now */
sizeof (sbd_stat_t));
}
break;
}
}
}
}
/* paranoia: detect buffer overrun */
PR_ALL("%s: buffer overrun\n", f);
#ifdef _MULTI_DATAMODEL
if (sz32 != 0)
#endif
return;
}
/* if necessary, move data into intermediate device status buffer */
#ifdef _MULTI_DATAMODEL
int i, j;
/* paranoia: detect buffer overrun */
"sbd:%s: buffer32 overrun", f);
#ifdef _MULTI_DATAMODEL
if (sz32 != 0)
#endif
return;
}
/*
* initialize 32 bit sbd board status structure
*/
/*
* copy common data for the device
*/
/* copy type specific data for the device */
case SBD_COMP_CPU:
break;
case SBD_COMP_MEM:
break;
case SBD_COMP_IO:
for (j = 0; j < SBD_MAX_UNSAFE; j++)
(int32_t)
break;
case SBD_COMP_CMP:
/* copy sbd_cmp_stat_t structure members */
break;
default:
"sbd:%s: unknown dev type (%d)", f,
break;
}
}
if (ddi_copyout((void *)dstat32p,
"sbd:%s: failed to copyout status "
}
} else
#endif /* _MULTI_DATAMODEL */
"sbd:%s: failed to copyout status for board %d",
}
#ifdef _MULTI_DATAMODEL
if (sz32 != 0)
#endif
}
/*
* Called at driver load time to determine the state and condition
* of an existing board in the system.
*/
static void
{
int i;
static fn_t f = "sbd_board_discovery";
if (SBD_DEVS_PRESENT(sbp) == 0) {
PR_ALL("%s: board %d has no devices present\n",
return;
}
/*
* Check for existence of cpus.
*/
for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
continue;
if (cpuid < 0) {
ep);
continue;
}
PR_ALL("%s: board %d, cpuid %d - attached\n",
}
sbd_init_cpu_unit(sbp, i);
}
}
/*
* Check for existence of memory.
*/
for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
extern struct memlist *phys_install;
continue;
continue;
/* omit phantom memory controllers on I/O boards */
}
continue;
}
/*
* basepa may not be on a alignment boundary, make it so.
*/
continue;
}
/*
* Check if base address is in phys_install.
*/
continue;
else
break;
if (ml) {
PR_ALL("%s: board %d, mem-unit %d - attached\n",
}
}
/*
* If so far we have found an error, we just log it but continue
*/
if (SBD_GET_ERRNO(ep) != 0)
SBD_GET_ERRNO(ep));
/*
* Check for i/o state.
*/
for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
continue;
continue;
/*
* XXX Is the devstate check needed ?
*/
if (i_ddi_devi_attached(dip) ||
/*
* Found it!
*/
PR_ALL("%s: board %d, io-unit %d - attached\n",
}
sbd_init_io_unit(sbp, i);
}
int ut;
/*
* A prior comment stated that a partially configured
* board was not permitted. The Serengeti architecture
* makes this possible, so the SB_DEVS_DISCONNECT
* at the end of this block has been removed.
*/
PR_ALL("%s: some devices not configured (0x%x)...\n",
f, devs_lost);
}
}
}
}
}
static int
{
case SBD_COMP_CMP:
case SBD_COMP_MEM:
case SBD_COMP_IO:
break;
case SBD_COMP_CPU:
/*
* All CPU nodes under CMP nodes should have
* gotten pruned when the CMP node was first
* encountered.
*/
break;
case SBD_COMP_UNKNOWN:
/* Not of interest to us */
return (DDI_WALK_CONTINUE);
default:
ASSERT(0);
return (DDI_WALK_PRUNECHILD);
}
} else {
}
return (DDI_WALK_PRUNECHILD);
}
static void
{
int i;
int circ;
/*
* For serengeti, top_dip doesn't need to be held because
* sbp i.e. sbd_board_t will be destroyed in sbd_teardown_instance()
* before top_dip detaches. For Daktari, top_dip is the
* root node which never has to be held.
*/
/*
* Allocate the devlist for cpus.
*/
/*
* Allocate the devlist for mem.
*/
/*
* Allocate the devlist for io.
*/
for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
}
for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
}
for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
}
/*
* Walk the device tree, find all top dips on this board and
* hold the branches rooted at them
*/
if (pdip)
if (pdip)
/*
* Initialize the devlists
*/
if (sbd_init_devlists(sbp) == 0) {
} else {
/*
* Couldn't have made it down here without
* having found at least one device.
*/
/*
* Check the state of any possible devices on the
* board.
*/
if (SBD_DEVS_UNATTACHED(sbp) == 0) {
/*
* The board has no unattached devices, therefore
* by reason of insanity it must be configured!
*/
} else if (SBD_DEVS_ATTACHED(sbp)) {
} else {
}
}
}
static void
{
int i;
int circ;
#ifdef DEBUG
for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
}
#endif /* DEBUG */
/*
* Free up MEM unit structs.
*/
/*
* Free up CPU unit structs.
*/
/*
* Free up IO unit structs.
*/
/*
* free up CPU devlists.
*/
for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
}
/*
* free up MEM devlists.
*/
for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
}
/*
* free up IO devlists.
*/
for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
}
/*
* Release all branches held earlier
*/
if (pdip)
if (pdip)
}
{
int i;
/* look up type in table */
for (i = 0; SBD_COMP(i) != SBD_COMP_UNKNOWN; i++) {
break;
}
}
return (type);
}
/*
* There are certain cases where obp marks components as failed
* If the status is ok the node won't have any status property. It
* is only there if the status is other than ok.
*
* The translation is as follows:
* If there is no status prop, the the cond is SBD_COND_OK
* If we find a status prop but can't get to it then cond is SBD_COND_UNKNOWN
* if we find a stat and it is failed the cond is SBD_COND_FAILED
* If the stat is disabled, the cond is SBD_COND_UNUSABLE
* Otherwise we return con as SBD_COND_OK
*/
{
int len;
char *status_buf;
PR_BYP("dip is NULL\n");
return (SBD_COND_UNKNOWN);
}
/*
* If retired, return FAILED
*/
PR_CPU("dip is retired\n");
return (SBD_COND_FAILED);
}
PR_CPU("status in sbd is ok\n");
return (SBD_COND_OK);
}
PR_CPU("status in sbd is unknown\n");
return (SBD_COND_UNKNOWN);
}
PR_CPU("status in sbd is failed\n");
return (SBD_COND_FAILED);
}
PR_CPU("status in sbd is unusable\n");
return (SBD_COND_UNUSABLE);
}
return (SBD_COND_OK);
}
#ifdef SBD_DEBUG_ERRS
/* function to simulate errors throughout the sbd code */
void
char *rsc)
{
static fn_t f = "sbd_inject_err";
if (sbd_err_debug == 0)
return;
return;
}
if (SBD_GET_ERRNO(ep) != 0) {
SBD_GET_ERRNO(ep));
return;
}
if (SBD_GET_ERR(ep) != 0) {
SBD_GET_ERR(ep));
return;
}
if (Errno != 0)
if (ecode != 0)
}
}
#endif