drd_rcm.c revision 1d4b38e0077763e7c9b20768eacb841957e787bc
/*
* 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 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* RCM backend for the DR Daemon
*/
#include <unistd.h>
#include <strings.h>
#include <errno.h>
#include <kstat.h>
#include <libnvpair.h>
#include <librcm.h>
#include "drd.h"
/*
* RCM Backend Support
*/
static int drd_rcm_init(void);
static int drd_rcm_fini(void);
drd_rcm_init, /* init */
drd_rcm_fini, /* fini */
drd_rcm_cpu_config_request, /* cpu_config_request */
drd_rcm_cpu_config_notify, /* cpu_config_notify */
drd_rcm_cpu_unconfig_request, /* cpu_unconfig_request */
drd_rcm_cpu_unconfig_notify /* cpu_unconfig_notify */
};
#define RCM_CPU_ALL "SUNW_cpu"
#define RCM_CPU_MAX_LEN (32)
/* global RCM handle used in all RCM operations */
static rcm_handle_t *rcm_hdl;
/* functions that call into RCM */
/* utility functions */
static void drd_rcm_cpu_rlist_fini(char **rlist);
/* debugging utility functions */
static void dump_cpu_rlist(char **rlist);
static int
drd_rcm_init(void)
{
int rv;
drd_dbg("drd_rcm_init...");
if (rv == RCM_FAILURE) {
return (-1);
}
return (0);
}
static int
drd_rcm_fini(void)
{
drd_dbg("drd_rcm_fini...");
return (0);
}
static int
{
int idx;
drd_dbg("drd_rcm_cpu_config_request...");
/*
* There is no RCM operation to request the addition
* of resources. So, by definition, the operation for
* all the CPUs is allowed.
*/
return (0);
}
static int
{
int rv = 0;
drd_dbg("drd_rcm_cpu_config_notify...");
/* notify RCM about the newly added CPUs */
rv = -1;
goto done;
}
/* notify RCM about the increased CPU capacity */
rv = -1;
}
done:
return (rv);
}
static int
{
int rv = 0;
int idx;
drd_dbg("drd_rcm_cpu_unconfig_request...");
/* contact RCM to request a decrease in CPU capacity */
rv = -1;
goto done;
}
/* contact RCM to request the removal of CPUs */
rv = -1;
goto done;
}
done:
/*
* If any errors occurred, the status field for
* a CPU may still be in the INIT state. Set the
* status for any such CPU to DENY to ensure it
* gets processed properly.
*/
}
return (rv);
}
static int
{
int rv = 0;
drd_dbg("drd_rcm_cpu_unconfig_notify...");
/*
* Notify RCM about the CPUs that were removed.
* Failures are ignored so that CPUs that could
* not be unconfigured can be processed by RCM.
*/
/*
* Notify RCM about any CPUs that did not make it
* in to the unconfigured state.
*/
rv = -1;
goto done;
}
/* notify RCM about the decreased CPU capacity */
rv = -1;
}
done:
return (rv);
}
static int
{
char **rlist;
int rv = 0;
drd_dbg("drd_rcm_online_cpu_notify...");
DRCTL_STATUS_CONFIG_SUCCESS)) == NULL) {
drd_dbg(" no CPUs were successfully added, nothing to do");
return (0);
}
if (rv != RCM_SUCCESS) {
rv = -1;
}
return (rv);
}
static int
{
int ncpus;
int rv = -1;
int oldncpus = 0;
int newncpus = 0;
int idx;
drd_dbg("drd_rcm_add_cpu_notify...");
drd_err("add_cpu_notify: cpu list empty");
goto done;
}
}
/* allocate an nvlist for the RCM call */
goto done;
/*
* Added CPU capacity, so newcpus is the current list
* of CPUs in the system.
*/
goto done;
/*
* Since the operation added CPU capacity, the old CPU
* list is the new CPU list with the CPUs involved in
* the operation removed.
*/
goto done;
}
/* dump pre and post lists */
/* setup the nvlist for the RCM call */
goto done;
}
done:
return (rv);
}
static int
{
int ncpus;
int rv = -1;
int oldncpus = 0;
int newncpus = 0;
int idx;
drd_dbg("drd_rcm_del_cpu_request...");
drd_err("del_cpu_request: cpu list empty");
goto done;
}
}
/* allocate an nvlist for the RCM call */
goto done;
}
/*
* Removing CPU capacity, so oldcpus is the current
* list of CPUs in the system.
*/
goto done;
}
/*
* Since this is a request to remove CPU capacity,
* the new CPU list is the old CPU list with the CPUs
* involved in the operation removed.
*/
goto done;
}
}
/* dump pre and post lists */
/* setup the nvlist for the RCM call */
goto done;
}
if (rv != RCM_SUCCESS) {
/*
* Since the capcity change was blocked, we
* mark all CPUs as blocked. It is up to the
* user to reframe the query so that it can
* succeed.
*/
}
/* tack on message to first resource */
"specified number of CPUs");
drd_dbg(" unable to remove specified number of CPUs");
goto done;
}
rv = 0;
done:
return (rv);
}
static int
{
char **rlist;
int idx;
int state;
int rv = 0;
const char *rsrcstr;
const char *errstr;
drd_dbg("drd_rcm_offline_cpu_request...");
DRCTL_STATUS_INIT)) == NULL) {
drd_err("unable to generate resource list");
return (-1);
}
if (rv == RCM_SUCCESS) {
goto done;
}
/*
* Loop through the result of the operation and add
* any error messages to the resource structure.
*/
/* find the resource of interest */
continue;
}
if (errstr) {
}
}
rv = 0;
done:
/*
* Set the state of the resource based on the RCM
* state. CPUs in the offline state have the ok to
* proceed. All others have been blocked.
*/
state = 0;
/* find the resource of interest */
continue;
}
}
return (rv);
}
static int
{
char **rlist;
int rv = 0;
drd_dbg("drd_rcm_remove_cpu_notify...");
DRCTL_STATUS_CONFIG_SUCCESS)) == NULL) {
drd_dbg(" no CPUs in the success state, nothing to do");
return (0);
}
if (rv != RCM_SUCCESS) {
rv = -1;
}
return (rv);
}
static int
{
char **rlist;
char **full_rlist;
int idx;
int ridx;
int state;
int rv = 0;
drd_dbg("drd_rcm_restore_cpu_notify...");
DRCTL_STATUS_CONFIG_FAILURE)) == NULL) {
drd_dbg(" no CPUs in the failed state, nothing to do");
return (0);
}
/*
* Since the desired result of this operation is to
* restore resources to the online state, filter out
* the resources already in the online state before
* passing the list to RCM.
*/
/* allocate a zero filled array to ensure NULL terminated list */
rv = -1;
goto done;
}
state = 0;
if (state != RCM_STATE_ONLINE) {
ridx++;
}
}
/* check if everything got filtered out */
if (ridx == 0) {
drd_dbg(" all CPUs already online, nothing to do");
goto done;
}
if (rv != RCM_SUCCESS) {
rv = -1;
}
done:
return (rv);
}
static int
{
int rv = -1;
int oldncpus = 0;
int newncpus = 0;
int idx;
int cidx;
drd_dbg("drd_rcm_del_cpu_notify...");
drd_err("del_cpu_notify: cpu list empty");
goto done;
}
/*
* Filter out the CPUs that could not be unconfigured.
*/
continue;
cidx++;
}
/* nothing to do */
if (cidx == 0) {
rv = 0;
goto done;
}
/* allocate an nvlist for the RCM call */
goto done;
}
/*
* Removed CPU capacity, so newcpus is the current list
* of CPUs in the system.
*/
goto done;
}
/*
* Since the operation removed CPU capacity, the old CPU
* list is the new CPU list with the CPUs involved in
* the operation added.
*/
goto done;
}
}
}
/* dump pre and post lists */
/* setup the nvlist for the RCM call */
goto done;
}
done:
return (rv);
}
/*
* Given a list of resource structures, create a list of CPU
* resource strings formatted as expected by RCM. Only resources
* that are in the state specified by the status argument are
* included in the resulting list.
*/
static char **
{
char rbuf[RCM_CPU_MAX_LEN];
char **rlist;
int idx;
int ridx;
drd_dbg("drd_rcm_cpu_rlist_init...");
drd_dbg("cpu list is empty");
return (NULL);
}
/* allocate a zero filled array to ensure NULL terminated list */
return (NULL);
}
drd_dbg(" checking cpu %d, status=%d, expected status=%d",
/*
* Filter out the CPUs that are not in
* the requested state.
*/
continue;
/* generate the resource string */
return (NULL);
}
ridx++;
}
/* cleanup if the list is empty */
if (ridx == 0) {
}
drd_dbg("final rlist:");
return (rlist);
}
static void
drd_rcm_cpu_rlist_fini(char **rlist)
{
int idx;
drd_dbg("drd_rcm_cpu_rlist_fini...");
}
}
/*
* Convert an RCM CPU resource string into a numerical cpuid.
* where "<C>" is the numerical cpuid of interest.
*/
static cpuid_t
cpu_rsrcstr_to_cpuid(const char *rsrc)
{
char *cpuid_off;
/*
* Search for the last occurrance of 'u' in the
* This will give a pointer to the cpuid portion.
*/
cpuid_off++;
return (cpuid);
}
/*
* Given an RCM CPU resource string, return a pointer to the
* corresponding resource structure from the given resource list.
* NULL is returned if no matching resource structure can be
* found.
*/
static drctl_rsrc_t *
{
int idx;
}
return (NULL);
}
static int
{
int ncpu = 0;
int maxncpu;
drd_dbg("get_sys_cpuids...");
return (-1);
return (-1);
(void) kstat_close(kc);
return (-1);
}
}
(void) kstat_close(kc);
return (0);
}
static boolean_t
{
int idx;
return (B_FALSE);
return (B_TRUE);
}
return (B_FALSE);
}
#define CPUIDS_PER_LINE 16
static void
{
char *curr;
int i, j;
/* return if not debugging */
if (drd_debug == 0)
return;
/* print just the prefix if CPU list is empty */
if (ncpuids == 0) {
if (prefix)
return;
}
for (i = 0; i < ncpuids; i += CPUIDS_PER_LINE) {
/* start with the prefix */
/* format the CPUs for this line */
for (j = 0; (j < CPUIDS_PER_LINE) && ((i + j) < ncpuids); j++) {
}
}
}
static void
{
int idx;
char *errstr;
/* just return if not debugging */
if (drd_debug == 0)
return;
if (prefix)
/* get a pointer to the error string */
}
}
static void
dump_cpu_rlist(char **rlist)
{
int idx;
int state;
static char *rcm_state_str[] = {
"UNKNOWN", "ONLINE", "ONLINING",
"OFFLINE_FAIL", "OFFLINING", "OFFLINE",
"REMOVING", "INVALID_7", "INVALID_8",
"INVALID_9", "RESUMING", "SUSPEND_FAIL",
"SUSPENDING", "SUSPEND", "REMOVE",
"OFFLINE_QUERYING", "OFFLINE_QUERY_FAIL", "OFFLINE_QUERY",
"SUSPEND_QUERYING", "SUSPEND_QUERY_FAIL", "SUSPEND_QUERY"
};
/* just return if not debugging */
if (drd_debug == 0)
return;
drd_dbg(" empty rlist");
return;
}
state = 0;
}
}