/*
* 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
*/
/*
*/
#include <libdevinfo.h>
#include <string.h>
#include <librcm.h>
#include <dlfcn.h>
#include <assert.h>
typedef struct rio_path {
} rio_path_t;
typedef struct rcm_arg {
char *rcm_root;
int rcm_supp;
int rcm_retcode;
int (*rcm_offline)();
int (*rcm_online)();
int (*rcm_remove)();
} rcm_arg_t;
typedef struct selector {
char *sel_name;
const char *file);
#define RIO_ASSERT(d, x) \
{"disk", disk_select},
{"nexus", nexus_select},
{"enclosure", enclosure_select},
{"smp", smp_select},
};
void *
{
if (fail) {
return (NULL);
} else {
}
}
static void
{
assert(0);
"Assertion failed: %s, file %s, line %d\n",
}
/*ARGSUSED*/
static int
{
"IDed this node as enclosure\n");
return (DI_WALK_TERMINATE);
}
static int
{
/*
* Check if this is an enclosure minor. If any one minor is DDI_NT_SGEN
* or DDI_NT_SCSI_ENCLOSURE we assume it is an enclosure.
*/
enclosure_minor) != 0) {
"di_walk_minor failed. Returning NOTSUP\n");
return (0);
}
enclosure_minor) != 0) {
"di_walk_minor failed. Returning NOTSUP\n");
return (0);
}
}
/*ARGSUSED*/
static int
{
"IDed this node as smp\n");
return (DI_WALK_TERMINATE);
}
static int
{
/*
* Check if this is an smp minor. If any one minor is DDI_NT_SMP
* we assume it is an smp.
*/
"di_walk_minor failed. Returning NOTSUP\n");
return (0);
}
}
/*ARGSUSED*/
static int
{
"IDed this node as disk\n");
return (DI_WALK_TERMINATE);
}
"Continuing minor walk\n");
return (DI_WALK_CONTINUE);
}
static int
{
/*
* Check if this is a disk minor. If any one minor is DDI_NT_BLOCK
* we assume it is a disk
*/
"failed. Returning NOTSUP\n");
return (0);
}
}
static int
{
int select;
char *path;
"di_devfs_path() is NULL. Returning NOTSUP\n");
return (0);
}
/*
* Check if it is a nexus
*/
path);
select = 1;
} else {
path);
select = 0;
}
return (select);
}
static int
{
int sel;
int i;
char *path;
/* skip pseudo nodes - we only retire real hardware */
"pseudo device in subtree - returning NOTSUP: %s\n",
path);
return (DI_WALK_TERMINATE);
}
/*
* retireable irrespective of the type of device,
* presumably the system is able to function without
* it.
*/
(state & DI_BUS_DOWN)) {
return (DI_WALK_CONTINUE);
}
sel = 0;
if (sel == 1) {
"found supported device: %s\n",
break;
}
}
if (sel != 1) {
/*
* This node is not a supported device. Retire cannot proceed
*/
"unsupported device. Returning NOTSUP\n");
return (DI_WALK_TERMINATE);
}
/*
* This node is supported. Check other nodes in this subtree.
*/
return (DI_WALK_CONTINUE);
}
/*
* when in doubt assume that retire is not supported for this device.
*/
static int
{
/*
* We should not be here if devinfo snapshot is NULL.
*/
/*
* Note: We initally set supported to 1, then walk the
* subtree rooted at devpath, allowing each node the
* opportunity to veto the support. We cannot do things
* the other way around i.e. assume "not supported" and
* let individual nodes indicate that they are supported.
* In the latter case, the supported flag would be set
* if any one node in the subtree was supported which is
* not what we want.
*/
"di_walk_node: failed. Returning NOTSUP\n");
}
}
}
static void
{
rio_path_t *p;
int retval;
int error;
for (p = rp->rcm_cons_nodes; p; ) {
tmp = p;
}
for (p = rp->rcm_rsrc_minors; p; ) {
tmp = p;
if (retcode == 0) {
} else {
}
if (retval != RCM_SUCCESS) {
"rcm_%s: retval=%d: error=%s: path=%s\n",
} else {
"rcm_%s: SUCCESS: path=%s\n",
}
}
}
/*ARGSUSED*/
static int
{
char *mnp;
int retval;
return (DI_WALK_TERMINATE);
}
return (DI_WALK_TERMINATE);
}
"/devices%s", mnp);
if (retval == RCM_FAILURE) {
return (DI_WALK_TERMINATE);
} else if (retval == RCM_SUCCESS) {
} else if (retval != RCM_NO_CONSTRAINT) {
return (DI_WALK_TERMINATE);
} else {
}
return (DI_WALK_CONTINUE);
}
static int
{
char *path;
/*
* We should already have terminated the walk
* in case of failure
*/
goto fail;
}
goto fail;
}
goto fail;
}
goto fail;
"returned: unknown RCM error code: %d, %s\n",
goto fail;
} else {
}
/*
* RCM_SUCCESS or RCM_NO_CONSTRAINT.
* RCM_SUCCESS implies we overcame a constraint, so keep walking.
* RCM_NO_CONSTRAINT implies no constraints applied via RCM.
* Continue walking in the hope that contracts or LDI will
* apply constraints
* set retcode to RCM_SUCCESS to show that at least 1 node
* completely walked
*/
return (DI_WALK_CONTINUE);
fail:
return (DI_WALK_TERMINATE);
}
/*
* Returns:
* RCM_SUCCESS: RCM constraints (if any) were applied. The
* device paths for which constraints were applied is passed
* back via the pp argument
*
* RCM_FAILURE: Either RCM constraints prevent a retire or
* an error occurred
*/
static int
{
rio_path_t *p;
char *plistp;
char *s;
if (rnode == DI_NODE_NIL) {
return (RCM_NO_CONSTRAINT);
}
/* online is idempotent - safe to online non-offlined nodes */
goto out;
}
goto out;
}
" - no nodes walked: RCM_NO_CONSTRAINT: %s\n",
} else {
}
/*
* Convert to a sequence of NUL separated strings terminated by '\0'\0'
*/
}
len++; /* list terminating '\0' */
goto out;
}
tmp = p;
s += strlen(s) + 1;
}
*s = '\0';
out:
return (rp->rcm_retcode);
}
/*ARGSUSED*/
int
{
void *librcm_hdl;
int (*librcm_alloc_handle)();
int (*librcm_free_handle)();
return (EINVAL);
return (EINVAL);
}
devpath);
return (EINVAL);
}
if (flags != 0) {
flags);
return (EINVAL);
}
/*
* dlopen rather than link against librcm since libdevinfo
* resides in / and librcm resides in /usr. The dlopen is
* safe to do since fmd which invokes the retire code
* resides on /usr and will not come here until /usr is
* mounted.
*/
if (librcm_hdl == NULL) {
return (ENOSYS);
}
if (librcm_alloc_handle == NULL ||
librcm_free_handle == NULL) {
goto out;
}
/*
* Take a libdevinfo snapshot here because we cannot do so
* after device is retired. If device doesn't attach, we retire
* anyway i.e. it is not fatal.
*/
"retiring anyway: %s\n", devpath);
}
!= RCM_SUCCESS) {
"RCM handle. Returning RCM failure: %s\n", devpath);
goto out;
}
/*
* If device is already detached/nonexistent and cannot be
* attached, allow retire without checking device type.
* XXX
* Else, check if retire is supported for this device type.
*/
"device. Bypassing retire_supported: %s\n", devpath);
} else if (!retire_supported(&rarg)) {
"device type: %s\n", devpath);
goto out;
}
clen = 0;
constraint = NULL;
if (retval == RCM_FAILURE) {
/* retire not permitted */
"retire: %s\n", devpath);
goto out;
} else if (retval == RCM_SUCCESS) {
": %s\n", devpath);
} else if (retval == RCM_NO_CONSTRAINT) {
": %s\n", devpath);
} else {
goto out;
}
goto out;
}
devpath);
rcm_finalize(&rarg, 0);
retval = 0;
out:
if (rarg.rcm_handle)
(void) dlclose(librcm_hdl);
return (retval);
}
/*ARGSUSED*/
int
{
return (EINVAL);
return (EINVAL);
}
devpath);
return (EINVAL);
}
return (err);
}
devpath);
return (0);
}