dr.c revision 68ac2337c38c8af06edcf32a72e42de36ec72a9d
/*
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* PIM-DR layer of DR driver. Provides interface between user
* level applications and the PSM-DR layer.
*/
#include <sys/dditypes.h>
#include <sys/processor.h>
#include <sys/mem_config.h>
#include <sys/autoconf.h>
#include <sys/ddi_impldefs.h>
#include <sys/machsystm.h>
extern int nulldev();
extern int nodev();
extern struct memlist *phys_install;
#ifdef DEBUG
#endif /* DEBUG */
/*
* NOTE: state_str, nt_str and SBD_CMD_STR are only used in a debug
* kernel. They are, however, referenced during both debug and non-debug
* compiles.
*/
static char *state_str[] = {
"EMPTY", "OCCUPIED", "CONNECTED", "UNCONFIGURED",
"PARTIAL", "CONFIGURED", "RELEASE", "UNREFERENCED",
"FATAL"
};
#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_DISCONNECT) ? "DISCONNECT" : \
((c) == SBD_CMD_CONFIGURE) ? "CONFIGURE" : \
((c) == SBD_CMD_UNCONFIGURE) ? "UNCONFIGURE" : \
((c) == SBD_CMD_GETNCM) ? "GETNCM" : \
((c) == SBD_CMD_PASSTHRU) ? "PASSTHRU" : \
#define DR_MAKE_MINOR(i, b) (((i) << 16) | (b))
#define DR_MINOR2BNUM(m) ((m) & 0xffff)
/* struct for drmach device name to sbd_comp_type_t mapping */
typedef struct {
char *s_devtype;
} dr_devname_t;
/* struct to map starfire device attributes - name:sbd_comp_type_t */
static dr_devname_t dr_devattr[] = {
#if defined(DRMACH_DEVTYPE_SBUS)
#endif
#if defined(DRMACH_DEVTYPE_WCI)
#endif
/* last s_devtype must be NULL, s_nodetype must be SBD_COMP_UNKNOWN */
{ NULL, SBD_COMP_UNKNOWN }
};
/*
* Per instance soft-state structure.
*/
typedef struct dr_softstate {
int dr_initialized;
/*
* dr Global data elements
*/
struct dr_global {
} dr_g;
/*
* Table of known passthru commands.
*/
struct {
char *pt_name;
int (*pt_func)(dr_handle_t *);
} pt_arr[] = {
"quiesce", dr_pt_test_suspend,
};
int dr_modunload_okay = 0; /* set to non-zero to allow unload */
/*
* 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 dr_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_ASSIGN: return (4);
case SBD_CMD_UNASSIGN: return (5);
case SBD_CMD_POWERON: return (6);
case SBD_CMD_POWEROFF: return (7);
case SBD_CMD_TEST: return (8);
default: return (-1);
}
}
#define CMD2INDEX(c) _cmd2index(c)
static struct dr_state_trans {
int x_cmd;
struct {
int x_rv; /* return value of pre_op */
int x_err; /* error, if any */
} x_op[DR_STATE_MAX];
} dr_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 */
{ 0, 0 }, /* configured */
}
},
{
{ 0, 0 }, /* partial */
{ 0, 0 }, /* configured */
{ 0, 0 }, /* release */
{ 0, 0 }, /* unreferenced */
}
},
{
{ 0, 0 }, /* empty */
{ 0, 0 }, /* occupied */
}
},
{
{ 0, 0 }, /* empty */
{ 0, 0 }, /* occupied */
}
},
{
{ 0, 0 }, /* empty */
{ 0, 0 }, /* occupied */
}
},
{
{ 0, 0 }, /* empty */
{ 0, 0 }, /* occupied */
}
},
{ SBD_CMD_TEST,
{
{ 0, 0 }, /* empty */
{ 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.
*/
/*
* Head of the boardlist used as a reference point for
* locating board structs.
* TODO: eliminate dr_boardlist
*/
/*
* DR support functions.
*/
struct dr_state_trans *transp,
int cmd);
int bd);
/*
* DR driver (DDI) entry points.
*/
/*
* DR command processing operations.
*/
/*
* Autoconfiguration data structures
*/
dr_open, /* open */
dr_close, /* close */
nodev, /* strategy */
nodev, /* print */
nodev, /* dump */
nodev, /* read */
nodev, /* write */
dr_ioctl, /* ioctl */
nodev, /* devmap */
nodev, /* mmap */
nodev, /* segmap */
nochpoll, /* chpoll */
ddi_prop_op, /* cb_prop_op */
NULL, /* struct streamtab */
CB_REV, /* Rev */
nodev, /* cb_aread */
nodev /* cb_awrite */
};
struct dev_ops dr_dev_ops = {
DEVO_REV, /* build version */
0, /* dev ref count */
dr_getinfo, /* getinfo */
nulldev, /* identify */
dr_probe, /* probe */
dr_attach, /* attach */
dr_detach, /* detach */
nodev, /* reset */
&dr_cb_ops, /* cb_ops */
NULL /* power */
};
extern struct mod_ops mod_driverops;
"Dynamic Reconfiguration %I%",
};
static struct modlinkage modlinkage = {
(void *)&modldrv,
};
/*
* 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 (dr_softstate_t), 1);
if (err)
return (err);
return (mod_install(&modlinkage));
}
int
_fini(void)
{
int err;
return (err);
return (0);
}
int
{
}
/*ARGSUSED1*/
static int
{
int instance;
dr_board_t *bp;
/*
* Don't open unless we've attached.
*/
return (ENXIO);
if (!softsp->dr_initialized) {
int bd;
int rv = 0;
/* initialize each array element */
if (rv)
break;
}
if (rv == 0) {
} else {
/* destroy elements initialized thus far */
/* TODO: should this be another errno val ? */
return (ENXIO);
}
}
/*
* prevent opening of a dyn-ap for a board
* that does not exist
*/
if (!bp->b_assigned) {
return (ENODEV);
}
return (0);
}
/*ARGSUSED*/
static int
{
return (0);
}
/*
*/
int dr_enable = 1;
/*ARGSUSED3*/
static int
{
static int dr_dev_type_to_nt(char *);
int rv = 0;
int instance;
int bd;
static fn_t f = "dr_ioctl";
PR_ALL("%s...\n", f);
return (ENXIO);
}
if (!dr_enable) {
switch (cmd) {
case SBD_CMD_STATUS:
case SBD_CMD_GETNCM:
case SBD_CMD_PASSTHRU:
break;
default:
return (ENOTSUP);
}
}
if (bd >= MAX_BOARDS)
return (ENXIO);
/* get and initialize storage for new handle */
/* copy sbd command into handle */
if (rv) {
return (EINVAL);
}
/* translate canonical name to component type */
PR_ALL("%s: c_name = %s, c_type = %d\n",
f,
} else {
/*EMPTY*/
PR_ALL("%s: c_name is NULL\n", f);
}
/* determine scope of operation */
case SBD_CMD_STATUS:
case SBD_CMD_GETNCM:
/* 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".
*/
if (rv == 0)
break;
}
rv = 0;
if (rv == 0)
if (rv == 0)
if (rv == 0)
if (rv == -1)
/* undo locking, if any, done before dr_pre_op */
case SBD_CMD_STATUS:
case SBD_CMD_GETNCM:
break;
case SBD_CMD_ASSIGN:
case SBD_CMD_UNASSIGN:
case SBD_CMD_POWERON:
case SBD_CMD_POWEROFF:
case SBD_CMD_CONNECT:
case SBD_CMD_CONFIGURE:
case SBD_CMD_UNCONFIGURE:
case SBD_CMD_DISCONNECT:
/* Board changed state. Log a sysevent. */
if (rv == 0)
SE_SLEEP, 1);
/* Fall through */
default:
}
return (rv);
}
/*ARGSUSED*/
static int
{
return (DDI_PROBE_SUCCESS);
}
static int
{
int bd;
int instance;
switch (cmd) {
case DDI_ATTACH:
if (rv != DDI_SUCCESS) {
instance);
return (DDI_FAILURE);
}
/* initialize softstate structure */
/* allocate board array (aka boardlist) */
/* TODO: eliminate dr_boardlist */
/* initialize each array element */
rv = DDI_SUCCESS;
char *p, *name;
int l, minor_num;
/*
* initialized board attachment point path
* (relative to pseudo) in a form immediately
* reusable as an cfgadm command argument.
* TODO: clean this up
*/
while (*p != '\0') {
l--;
p++;
}
name = p;
if (err) {
sbd_err_clear(&err);
rv = DDI_FAILURE;
break;
}
if (rv != DDI_SUCCESS)
rv = DDI_FAILURE;
}
if (rv == DDI_SUCCESS) {
/*
* Announce the node's presence.
*/
} else {
}
/*
* Init registered unsafe devs.
*/
if (rv2 != DDI_PROP_SUCCESS)
dr_unsafe_devs.ndevs = 0;
return (rv);
default:
return (DDI_FAILURE);
}
/*NOTREACHED*/
}
static int
{
int instance;
switch (cmd) {
case DDI_DETACH:
if (!dr_modunload_okay)
return (DDI_FAILURE);
/* TODO: eliminate dr_boardlist */
/* remove all minor nodes */
if (softsp->dr_initialized) {
int bd;
}
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
/*NOTREACHED*/
}
static int
{
error = DDI_SUCCESS;
switch (cmd) {
case DDI_INFO_DEVT2DEVINFO:
return (DDI_FAILURE);
break;
case DDI_INFO_DEVT2INSTANCE:
break;
default:
error = DDI_FAILURE;
break;
}
return (error);
}
/*
* DR operations.
*/
static int
{
static fn_t f = "dr_copyin_iocmd";
return (EINVAL);
#ifdef _MULTI_DATAMODEL
"%s: (32bit) failed to copyin "
"sbdcmd-struct", f);
return (EFAULT);
}
case SBD_CMD_STATUS:
break;
default:
break;
}
} else
#endif /* _MULTI_DATAMODEL */
"%s: failed to copyin sbdcmd-struct", f);
return (EFAULT);
}
return (EFAULT);
}
}
return (0);
}
static int
{
static fn_t f = "dr_copyout_iocmd";
return (EINVAL);
#ifdef _MULTI_DATAMODEL
case SBD_CMD_GETNCM:
break;
default:
break;
}
"%s: (32bit) failed to copyout "
"sbdcmd-struct", f);
return (EFAULT);
}
} else
#endif /* _MULTI_DATAMODEL */
"%s: failed to copyout sbdcmd-struct", f);
return (EFAULT);
}
return (0);
}
static int
{
static fn_t f = "dr_copyout_errs";
return (0);
PR_ALL("%s: error %d %s",
}
#ifdef _MULTI_DATAMODEL
if (ddi_copyout((void *)serr32p,
"%s: (32bit) failed to copyout", f);
return (EFAULT);
}
} else
#endif /* _MULTI_DATAMODEL */
"%s: failed to copyout", f);
return (EFAULT);
}
return (0);
}
/*
* pre-op entry point must sbd_err_set_c(), if needed.
* Return value of non-zero indicates failure.
*/
static int
{
int rv = 0, t;
static fn_t f = "dr_pre_op";
PR_ALL("drmach_pre_op failed for cmd %s(%d)\n",
return (-1);
}
/*
* Check for valid state transitions.
*/
struct dr_state_trans *transp;
int state_err;
transp = &dr_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",
} else {
}
}
if (serr) {
rv = -1;
}
return (rv);
}
static int
{
int rv = 0;
int cmd;
static fn_t f = "dr_post_op";
/* errors should have been caught by now */
PR_ALL("drmach_post_op failed for cmd %s(%d)\n",
return (-1);
}
switch (cmd) {
case SBD_CMD_CONFIGURE:
case SBD_CMD_UNCONFIGURE:
case SBD_CMD_CONNECT:
case SBD_CMD_DISCONNECT:
case SBD_CMD_GETNCM:
case SBD_CMD_STATUS:
break;
default:
break;
}
return (rv);
}
static int
{
int rv = 0;
static fn_t f = "dr_exec_op";
/* errors should have been caught by now */
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_CONNECT:
dr_connect(hp);
break;
case SBD_CMD_CONFIGURE:
break;
case SBD_CMD_UNCONFIGURE:
else
break;
case SBD_CMD_DISCONNECT:
break;
case SBD_CMD_STATUS:
break;
case SBD_CMD_GETNCM:
break;
case SBD_CMD_PASSTHRU:
break;
default:
"%s: unknown command (%d)",
break;
}
rv = -1;
}
return (rv);
}
static void
{
}
}
static void
{
/*
* Block out status during unassign.
* Not doing cv_wait_sig here as starfire SSP software
* ignores unassign failure and removes board from
* domain mask causing system panic.
* TODO: Change cv_wait to cv_wait_sig when SSP software
* handles unassign failure.
*/
/*
* clear drmachid_t handle; not valid after board unassign
*/
bp->b_assigned = 0;
}
}
static void
{
}
static void
{
}
static void
{
}
/*
* Create and populate the component nodes for a board. Assumes that the
* devlists for the board have been initialized.
*/
static void
int i;
/*
* Make nodes for the individual components on the board.
* First we need to initialize memory unit data structures of board
* structure.
*/
for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
}
/*
* Initialize cpu unit data structures.
*/
for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
}
/*
* Initialize io unit data structures.
*/
for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
}
}
/*
* Only do work if called to operate on an entire board
* which doesn't already have components present.
*/
static void
{
static fn_t f = "dr_connect";
PR_ALL("%s...\n", f);
if (DR_DEVS_PRESENT(bp)) {
/*
* Board already has devices present.
*/
PR_ALL("%s: devices already present (0x%lx)\n",
f, DR_DEVS_PRESENT(bp));
return;
}
return;
return;
return;
} else {
return;
}
/*NOTREACHED*/
}
static int
{
int i;
static fn_t f = "dr_disconnect";
PR_ALL("%s...\n", f);
/*
* Only devices which are present, but
* unattached can be disconnected.
*/
return (0);
}
/*
* Block out status during disconnect.
*/
return (EINTR);
}
}
/*
* Update per-device state transitions.
*/
for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
continue;
if (dr_disconnect_cpu(cp) == 0)
}
for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
continue;
if (dr_disconnect_mem(mp) == 0)
}
for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
continue;
if (dr_disconnect_io(ip) == 0)
}
/*
* For certain errors, drmach_board_disconnect will mark
* the board as unusable; in these cases the devtree must
* be purged so that status calls will succeed.
* XXX
* This implementation checks for discrete error codes -
* someday, the i/f to drmach_board_disconnect should be
* changed to avoid the e_code testing.
*/
goto disconnect_done;
else
}
/*
* If the disconnect failed in a recoverable way,
* more work is required.
* XXX
* This implementation checks for discrete error codes -
* someday, the i/f to drmach_board_disconnect should be
* changed to avoid the e_code testing.
*/
/*
* With this failure, the board has been deprobed
* by IKP, and reprobed. We've already gotten rid
* of the old devtree, now we need to reconstruct it
* based on the new IKP probe
*/
goto disconnect_done;
}
}
/*
* 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.
*/
}
}
return (0);
}
/*
* Check if a particular device is a valid target of the current
* operation. Return 1 if it is a valid target, and 0 otherwise.
*/
static int
{
int is_present;
int is_attached;
/* check if the user requested this device */
return (0);
}
/*
* If the present_only flag is set, a valid target
* must be present but not attached. Otherwise, it
* must be both present and attached.
*/
/* sanity check */
return (1);
}
return (0);
}
static void
{
int unum;
int nunits;
int len;
switch (type) {
case SBD_COMP_CPU:
break;
case SBD_COMP_MEM:
break;
case SBD_COMP_IO:
break;
default:
/* catch this in debug kernels */
ASSERT(0);
break;
}
/* allocate list storage. */
/* record length of storage in first element */
/* get bit array signifying which units are to be involved */
/*
* Adjust the loop count for CPU devices since all cores
* in a CMP will be examined in a single iteration.
*/
if (type == SBD_COMP_CPU) {
}
/* populate list */
int core;
int cunum;
}
/* further processing is only required for CPUs */
if (type != SBD_COMP_CPU) {
continue;
}
/*
* Add any additional cores from the current CPU
* device. This is to ensure that all the cores
* are grouped together in the device list, and
* consequently sequenced together during the actual
* operation.
*/
}
}
}
/* calculate number of units in list, return result and list pointer */
}
static void
{
int len;
int n = 0;
/*
* move first encountered unit error to handle if handle
* does not yet have a recorded error.
*/
while (n++ < devnum) {
break;
}
}
}
/* free remaining unit errors */
while (n++ < devnum) {
}
}
/* free list */
list -= 1;
}
static int
{
rv = 0;
if (devnum > 0) {
if (rv == 0) {
int n;
for (n = 0; n < devnum; n++)
}
}
return (rv);
}
/*ARGSUSED*/
static int
{
return (0);
}
static void
{
int i;
static fn_t f = "dr_post_attach_devlist";
for (i = 0; i < devnum; i++) {
PR_ALL("%s: ERROR %s not attached\n",
f, cp->sbdev_path);
continue;
}
}
case DR_STATE_CONNECTED:
case DR_STATE_UNCONFIGURED:
if (devs_unattached == 0) {
/*
* All devices finally attached.
*/
} else if (devs_present != devs_unattached) {
/*
* Only some devices are fully attached.
*/
}
break;
case DR_STATE_PARTIAL:
/*
* All devices finally attached.
*/
if (devs_unattached == 0) {
}
break;
default:
break;
}
}
static void
{
int rv;
if (rv >= 0) {
}
if (rv >= 0) {
}
}
static void
{
/*
* If the entire board was released and all components
* unreferenced then transfer it to the UNREFERENCED state.
*/
}
}
/* called by dr_release_done [below] and dr_release_mem_done [dr_mem.c] */
int
{
return (0);
} else {
return (-1);
}
}
static void
{
dr_board_t *bp;
static fn_t f = "dr_release_done";
PR_ALL("%s...\n", f);
/* get board pointer & sanity check */
/*
* Transfer the device which just completed its release
* to the UNREFERENCED state.
*/
switch (cp->sbdev_type) {
case SBD_COMP_MEM:
break;
default:
(void) dr_release_dev_done(cp);
break;
}
/*
* If we're not already in the RELEASE state for this
* board and we now have released all that were previously
* attached, then transfer the board to the RELEASE state.
*/
}
}
static void
{
}
static void
{
int rv;
if (rv >= 0) {
}
if (rv >= 0) {
}
if (rv < 0)
/* else, b_busy will be cleared in dr_detach_update_state() */
}
static void
{
int i;
static fn_t f = "dr_detach_update_state";
for (i = 0; i < devnum; i++) {
if (dr_check_unit_attached(cp) >= 0) {
/*
* Device is still attached probably due
* to an error. Need to keep track of it.
*/
PR_ALL("%s: ERROR %s not detached\n",
f, cp->sbdev_path);
continue;
}
}
if (bstate != DR_STATE_UNCONFIGURED) {
/*
* All devices are finally detached.
*/
(DR_DEVS_ATTACHED(bp) !=
DR_DEVS_PRESENT(bp))) {
/*
* Some devices remain attached.
*/
}
}
}
static int
{
/*
* Block out status during IO unconfig.
*/
return (EINTR);
}
}
return (0);
}
static void
{
int i;
static fn_t f = "dr_dev_cancel";
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;
if (dr_cancel_cpu(cp) == 0)
else
}
for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
continue;
}
for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
continue;
if (dr_cancel_mem(mp) == 0)
else
}
if (DR_DEVS_RELEASED(bp) == 0) {
/*
* If the board no longer has any released devices
*/
else
}
}
}
static int
{
dr_devset_t devset = 0;
dr_board_t *bp;
int rv = 0;
#ifdef _MULTI_DATAMODEL
int sz32 = 0;
#endif /* _MULTI_DATAMODEL */
static fn_t f = "dr_status";
PR_ALL("%s...\n", f);
/*
* Block out disconnect, unassign, IO unconfigure and
* devinfo branch creation during status.
*/
return (EINTR);
}
}
ncm = 1;
/*
* Calculate the maximum number of components possible
* for a board. This number will be used to size the
* status scratch buffer used by board and component
* status functions.
* This buffer may differ in size from what is provided
* by the plugin, since the known component set on the
* board may change between the plugin's GETNCM call, and
* the status call. Sizing will be adjusted to the plugin's
* receptacle buffer at copyout time.
*/
} 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;
}
}
sz = sizeof (sbd_stat_t);
if (ncm > 1)
/*
* s_nbytes describes the size of the preallocated user
* buffer into which the application is execting to
* receive the sbd_stat_t and sbd_dev_stat_t structures.
*/
#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)
sizeof (sbd_dev_stat32_t);
}
#endif
/*
* Since one sbd_dev_stat_t is included in the sbd_stat_t,
* increment the plugin's nstat count.
*/
++pnstat;
} else {
if (err) {
goto status_done;
}
}
/*
* Detect transitions between empty and disconnected.
*/
if (devset == 0) {
/*
* No device chosen.
*/
PR_ALL("%s: no device present\n", f);
}
}
}
}
/*
* Due to a possible change in number of components between
* the time of plugin's GETNCM call and now, there may be
* more or less components than the plugin's buffer can
* hold. Adjust s_nstat accordingly.
*/
#ifdef _MULTI_DATAMODEL
int i, j;
/* Alignment Paranoia */
PR_ALL("%s: alignment: sz=0x%lx dstat32p=0x%p\n",
f, sizeof (sbd_stat32_t), dstat32p);
goto status_done;
}
/* paranoia: detect buffer overrun */
goto status_done;
}
/* copy sbd_stat_t structure members */
/* copy sbd_cm_stat_t structure members */
case SBD_COMP_CPU:
/* copy sbd_cpu_stat_t structure members */
break;
case SBD_COMP_MEM:
/* copy sbd_mem_stat_t structure members */
break;
case SBD_COMP_IO:
/* copy sbd_io_stat_t structure members */
for (j = 0; j < SBD_MAX_UNSAFE; j++)
d_io.is_unsafe_list[j]);
break;
case SBD_COMP_CMP:
/* copy sbd_cmp_stat_t structure members */
break;
default:
goto status_done;
}
}
if (ddi_copyout((void *)dstat32p,
"%s: failed to copyout status "
goto status_done;
}
} else
#endif /* _MULTI_DATAMODEL */
"%s: failed to copyout status for board %d",
goto status_done;
}
return (rv);
}
static int
{
int i;
int ncm = 0;
/*
* Handle CPUs first to deal with possible CMP
* devices. If the CPU is a CMP, we need to only
* increment ncm once even if there are multiple
* cores for that CMP present in the devset.
*/
for (i = 0; i < MAX_CMP_UNITS_PER_BOARD; i++) {
ncm++;
}
}
/* eliminate the CPU information from the devset */
for (i = 0; i < (sizeof (dr_devset_t) * 8); i++) {
devset >>= 1;
}
return (ncm);
}
/* used by dr_mem.c */
/* TODO: eliminate dr_boardlist */
dr_lookup_board(int board_num)
{
dr_board_t *bp;
return (bp);
}
static dr_dev_unit_t *
{
return (dp);
}
{
}
{
}
{
}
{
}
static dr_devset_t
{
static fn_t f = "dr_dev2devset";
case SBD_COMP_NONE:
break;
case SBD_COMP_CPU:
"%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:
if (unit == SBD_NULL_UNIT) {
unit = 0;
}
"%s: invalid mem unit# = %d",
f, unit);
devset = 0;
} else
break;
case SBD_COMP_IO:
"%s: invalid io unit# = %d",
f, unit);
devset = 0;
} else
break;
default:
case SBD_COMP_UNKNOWN:
devset = 0;
break;
}
return (devset);
}
/*
* Converts a dynamic attachment point name to a SBD_COMP_* type.
* Returns SDB_COMP_UNKNOWN if name is not recognized.
*/
static int
dr_dev_type_to_nt(char *type)
{
int i;
break;
return (dr_devattr[i].s_nodetype);
}
/*
* Converts a SBD_COMP_* type to a dynamic attachment point name.
* Return NULL if SBD_COMP_ type is not recognized.
*/
char *
dr_nt_to_dev_type(int nt)
{
int i;
break;
return (dr_devattr[i].s_devtype);
}
/*
* State transition policy is that if there is some component for which
* the state transition is valid, then let it through. The exception is
* SBD_CMD_DISCONNECT. On disconnect, the state transition must be valid
* for ALL components.
* Returns the state that is in error, if any.
*/
static int
{
int s, ut;
int state_err = 0;
static fn_t f = "dr_check_transition";
continue;
s = (int)cp->sbdev_state;
if (!DR_DEV_IS_PRESENT(cp)) {
} else {
if (!state_err)
state_err = s;
}
}
}
}
continue;
s = (int)cp->sbdev_state;
if (!DR_DEV_IS_PRESENT(cp)) {
} else {
if (!state_err)
state_err = s;
}
}
}
}
continue;
s = (int)cp->sbdev_state;
if (!DR_DEV_IS_PRESENT(cp)) {
} else {
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. The exception is SBD_CMD_DISCONNECT.
* On disconnect, the state transition must be valid for ALL
* components.
*/
if (cmd == SBD_CMD_DISCONNECT)
return (state_err);
}
void
{
PR_STATE("%s STATE %s(%d) -> %s(%d)\n",
cp->sbdev_path,
if (st == DR_STATE_CONFIGURED) {
(void) drv_getparm(TIME,
}
} else
}
static void
{
PR_STATE("BOARD %d STATE: %s(%d) -> %s(%d)\n",
}
void
{
}
void
{
}
/*
* A callback routine. Called from the drmach layer as a result of
* call to drmach_board_find_devices from dr_init_devlists.
*/
static sbd_error_t *
{
int nt;
static fn_t f = "dr_dev_found";
PR_ALL("%s (board = %d, name = %s, unum = %d, id = %p)...\n",
if (nt == SBD_COMP_UNKNOWN) {
/*
* this should not happen. When it does, it indicates
* a missmatch in devices supported by the drmach layer
* vs devices supported by this layer.
*/
return (DR_INTERNAL_ERROR());
}
/* sanity check */
/* render dynamic attachment point path of this unit */
return (NULL);
}
static sbd_error_t *
{
int i;
static fn_t f = "dr_init_devlists";
/* sanity check */
/*
* This routine builds the board's devlist and initializes
* the common portion of the unit data structures.
* Note: because the common portion is considered
* uninitialized, the dr_get_*_unit() routines can not
* be used.
*/
/*
* Clear out old entries, if any.
*/
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++) {
}
/* find devices on this board */
}
return (err);
}
/*
* Return the unit number of the respective drmachid if
* it's found to be attached.
*/
static int
{
int rv = 0;
extern struct memlist *phys_install;
int yes;
static fn_t f = "dr_check_unit_attached";
switch (cp->sbdev_type) {
case SBD_COMP_CPU:
if (err) {
rv = -1;
break;
}
rv = -1;
break;
case SBD_COMP_MEM:
if (err) {
rv = -1;
break;
}
/*
* basepa may not be on a alignment boundary, make it so.
*/
if (err) {
rv = -1;
break;
}
/*
* Check if base address is in phys_install.
*/
continue;
else
break;
rv = -1;
break;
case SBD_COMP_IO:
if (err) {
rv = -1;
break;
} else if (!yes)
rv = -1;
break;
default:
PR_ALL("%s: unexpected nodetype(%d) for id 0x%p\n",
rv = -1;
break;
}
return (rv);
}
/*
* See if drmach recognizes the passthru command. DRMACH expects the
* id to identify the thing to which the command is being applied. Using
* nonsense SBD terms, that information has been perversely encoded in the
* c_id member of the sbd_cmd_t structure. This logic reads those tea
* leaves, finds the associated drmach id, then calls drmach to process
* the passthru command.
*/
static int
{
} else {
if (nt == SBD_COMP_UNKNOWN) {
id = 0;
} else {
/* pt command applied to dynamic attachment point */
}
}
}
static int
{
int found;
char *copts;
static fn_t f = "dr_pt_ioctl";
PR_ALL("%s...\n", f);
return (EINVAL);
}
found = 0;
if (found)
break;
}
if (found)
else
return (rv);
}
/*
* 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 = "dr_board_discovery";
if (DR_DEVS_PRESENT(bp) == 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;
PR_ALL("%s: board %d, cpu-unit %d - attached\n",
}
}
/*
* Check for existence of memory.
*/
for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
continue;
PR_ALL("%s: board %d, mem-unit %d - attached\n",
}
}
/*
* Check for i/o state.
*/
for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
continue;
/*
* Found it!
*/
PR_ALL("%s: board %d, io-unit %d - attached\n",
}
}
int ut;
/*
* It is not legal on board discovery to have a
* board that is only partially attached. A board
* is either all attached or all connected. If a
* board has at least one attached device, then
* the the remaining devices, if any, must have
* been lost or disconnected. These devices can
* only be recovered by a full attach from scratch.
* Note that devices previously in the unreferenced
* state are subsequently lost until the next full
* attach. This is necessary since the driver unload
* that must have occurred would have wiped out the
* information necessary to re-configure the device
* back online, e.g. memlist.
*/
continue;
}
continue;
}
continue;
}
}
}
static int
{
/*
* Initialize the devlists
*/
if (err) {
sbd_err_clear(&err);
return (-1);
} 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 (DR_DEVS_UNATTACHED(bp) == 0) {
/*
* The board has no unattached devices, therefore
* by reason of insanity it must be configured!
*/
} else if (DR_DEVS_ATTACHED(bp)) {
} else {
}
}
return (0);
}
static void
{
PR_ALL("dr_board_destroy: num %d, path %s\n",
/*
* Free up MEM unit structs.
*/
/*
* Free up CPU unit structs.
*/
/*
* Free up IO unit structs.
*/
}
void
{
}
void
{
}
/*
* Extract flags passed via ioctl.
*/
int
{
}