/*
* 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.
*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <libdevinfo.h>
#include <errno.h>
#include <libintl.h>
#define CFGA_PLUGIN_LIB
#include <config_admin.h>
#include "ap.h"
#include <sys/processor.h>
#include <sys/sbd_ioctl.h>
#include <sys/int_fmtio.h>
static cfga_err_t
{
return (CFGA_LIB_ERROR);
return (CFGA_ERROR);
}
if (ncm)
return (CFGA_OK);
}
{
int fd;
int ncm;
int select;
int stsize;
int oflag;
rc = CFGA_LIB_ERROR;
/* Open the file descriptor if not already open */
if (a->fd == -1) {
if (a->statonly != 0)
else
ap_err(a, ERR_AP_INVAL);
return (rc);
}
} else {
}
return (rc);
}
/*
* The status target is the board. If we need to
* return component data (to support the -a option),
* get the number of components on the board.
*/
select = 0;
if (all) {
cfga_err_t r;
if (r != CFGA_OK) {
return (r);
}
} else {
ncm = 0;
}
} else {
select = 1;
ncm = 1;
}
/*
* The status structure contains space for one component;
* add the space for the other components if necessary.
*/
stsize = sizeof (sbd_stat_t);
if (ncm > 1)
return (rc);
}
if (all)
if (select) {
/*
* The target is a specific component. Pass its
* name and unit number to the driver. Set its
* type to UNKNOWN since the plugin does not know
* the type of the component specified by the user.
*/
}
DBG("ioctl(%d SBD_CMD_STATUS, sc=0x%p sz=%d flags=%d",
if (select)
DBG(")\n");
rc = CFGA_ERROR;
} else
return (rc);
}
/*
* Convert a component to a target type.
*/
static ap_target_t
{
ap_target_t c;
switch (type) {
case SBD_COMP_CPU:
c = AP_CPU;
break;
case SBD_COMP_MEM:
c = AP_MEM;
break;
case SBD_COMP_IO:
c = AP_IO;
break;
case SBD_COMP_CMP:
c = AP_CMP;
break;
default:
c = AP_NONE;
break;
}
return (c);
}
{
int i;
/*
* Ideally, for board operations (other than status) it is not
* necessary to issue the STATUS ioctl. The call however allows a
* final sanity check to ensure that the board number returned
* by the driver matches the plugin's notion of the board number
* as extracted from the ap_id. If this check is not desirable,
* we can change the code to issue the status call only when
* necessary. Note that for component operations, we need to do
* the STATUS in order to figure out the component type and
*/
ap_err(a, ERR_AP_INVAL);
return (rc);
}
/*
* Set the component count to the returned stat count.
*/
}
/*
* Initialize the RCM module here so that it can record
* the initial state of the capacity information.
*/
rc = ap_rcm_init(a);
return (rc);
}
DBG("ds_name,ds_unit,ds_type=<%s,%d,%d> ",
continue;
/*
* Consider the names matched if they are either
* both absent or the same. It is conceivable that
* a NULL component name be considered valid
* by the driver.
*/
DBG("found ");
break;
}
}
return (CFGA_INVAL);
}
/*
* Initialize the RCM module here so that it can record
* the initial state of the capacity information.
*/
rc = ap_rcm_init(a);
return (rc);
}
void
{
if (a == NULL)
return;
ap_rcm_fini(a);
if (a->fd != -1)
free(a);
}
apd_t *
{
apd_t *a;
return (NULL);
a->fd = -1;
a->class = "sbd";
if (flags & CFGA_FLAG_LIST_ALL)
ap_setopt(a, OPT_LIST_ALL);
if (flags & CFGA_FLAG_FORCE)
if (flags & CFGA_FLAG_VERBOSE)
ap_setopt(a, OPT_VERBOSE);
return (a);
apd_free(a);
return (NULL);
}
/*
* The type field is defined to be parsable by cfgadm(1M): It
* must not contain white space characters. This function
* converts white space to underscore.
*/
static void
{
char c;
while (n-- > 0) {
c = *ip++;
if (isspace(c))
c = '_';
*op++ = c;
if (c == '\0')
break;
}
}
void
{
DBG("ap_init bd=%d rs=%d os=%d type=<%s>\n",
}
typedef struct {
int cmd;
int ioc;
} ap_ioc_t;
static ap_ioc_t
ap_iocs[] = {
{CMD_ASSIGN, SBD_CMD_ASSIGN },
{CMD_TEST, SBD_CMD_TEST },
{CMD_STATUS, SBD_CMD_STATUS },
{CMD_GETNCM, SBD_CMD_GETNCM },
{CMD_NONE, 0 }
};
static int
{
break;
}
{
int ioc;
/*
* See if the a quiesce operation is required for
* this command for any of the components. If the
* command does not map to an ioctl, then there is
* nothing to do.
*/
return (CFGA_OK);
int i;
/*
* See if any component requires a
* OS suspension for this command.
*/
(*check)++;
} else {
(*check)++;
}
return (CFGA_OK);
}
{
int c;
/*
* If there are no platform options set then there
* is no need to check this operation
*/
return (CFGA_OK);
/*
* Check if any of the steps in the sequence
* allows for a platform option
*/
/*
* If the platopt is set it means that the platform does not
* support options for this cmd
*/
return (CFGA_OK);
}
return (CFGA_INVAL);
}
{
int ioc;
return (CFGA_LIB_ERROR);
}
if (ap_getopt(a, OPT_SUSPEND_OK))
else {
}
return (CFGA_LIB_ERROR);
}
/*
* If this is a passthru command, pass all of its
* options; otherwise, pass all options after the
* platform keyword.
*/
if (cmd == CMD_PASSTHRU)
else {
/*
* Only pass the platform option to the cmds that the platform
* has specified as ok
*/
}
return (CFGA_OK);
}
return (CFGA_ERROR);
}
return (CFGA_OK);
}
/*
* Return the error string corresponding to a given error code.
* String table and error code sets are provided by sbd_etab. This data
* structure is automatically generated at compile time from the error
* code and message text information in sbd_ioctl.h.
*/
static char *
{
int i;
char *s;
extern sbd_etab_t sbd_etab[];
extern int sbd_etab_len;
s = NULL;
for (i = 0; i < sbd_etab_len; i++) {
int index;
char **t_text;
/*
* Found it. Just extract the string
*/
break;
}
}
if (i == sbd_etab_len) {
}
return (s);
}
char *
{
int code;
char *p;
char *rsc;
/*
* The driver sets the errno to EIO if it returns
* more detailed error info via e_code. In all
* other cases, use standard error text.
*/
p = strdup(p);
return (p);
}
if (code)
p = strdup(p);
return (p);
}
/*
* cfgadm -o err=plugin-err,cmd=name,code=ecode -x errtest ap_id.
*/
{
int err;
int cmd;
switch (err) {
case ERR_CMD_INVAL:
break;
case ERR_CMD_NOTSUPP:
break;
case ERR_CMD_FAIL:
break;
case ERR_OPT_INVAL:
break;
case ERR_OPT_NOVAL:
break;
case ERR_AP_INVAL:
break;
case ERR_CM_INVAL:
break;
case ERR_TRANS_INVAL:
break;
}
return (CFGA_LIB_ERROR);
}
static char *
ap_help_topics[] = {
"\tcfgadm [-o parsable] -l ap_id\n",
"\tcfgadm [-o unassign|nopoweroff] -c disconnect ap_id\n",
"\tcfgadm -t ap_id\n",
"\tcfgadm -x assign ap_id\n",
"\tcfgadm -x unassign ap_id\n",
"\tcfgadm -x poweron ap_id\n",
"\tcfgadm -x poweroff ap_id\n",
};
/*ARGSUSED*/
{
int len;
char **p;
char *q;
return (CFGA_OK);
for (p = ap_help_topics; *p != NULL; p++) {
continue;
continue;
(void) strcpy(q, *p);
free(q);
}
return (CFGA_OK);
}
static char *
{
char *type;
case SBD_COMP_CPU:
type = "cpu";
break;
case SBD_COMP_MEM:
type = "memory";
break;
case SBD_COMP_IO:
type = "io";
break;
case SBD_COMP_CMP:
type = "cpu";
break;
default:
type = "other";
break;
}
return (type);
}
static sbd_dev_stat_t *
{
return (a->cmstat);
}
char *
{
int len;
char *path;
char *devpath;
/*
* If no component sequence number is provided
* default to the current target component.
* Assume an io component so that we can get
* the path if the component is indeed of type io.
*/
else {
}
else
return (NULL);
} else
return (devpath);
}
void
{
int unit;
char *name;
/*
* If the component has a unit number,
* add it to the id, otherwise just use
* the component's name.
*/
if (unit == -1)
else
}
/*
* Convert a component to a target type.
*/
{
ap_target_t c;
case SBD_COMP_CPU:
c = AP_CPU;
break;
case SBD_COMP_MEM:
c = AP_MEM;
break;
case SBD_COMP_IO:
c = AP_IO;
break;
case SBD_COMP_CMP:
c = AP_CMP;
break;
default:
c = AP_NONE;
break;
}
return (c);
}
int
{
int ncap;
case SBD_COMP_CPU:
case SBD_COMP_MEM:
case SBD_COMP_IO:
ncap = 1;
break;
case SBD_COMP_CMP:
break;
default:
ncap = 0;
break;
}
return (ncap);
}
int
{
int i;
return (0);
return (0);
if (ostate)
*ncap = 1;
case SBD_COMP_CPU: {
break;
}
case SBD_COMP_MEM: {
break;
}
case SBD_COMP_CMP: {
}
break;
}
default:
return (0);
}
for (i = 0; i < *ncap; i++) {
}
return (1);
}
void
{
char *type;
DBG("ap_cm_init bd=%d rs=%d os=%d type=<%s> seq=%d\n",
}
void
{
*rs = CFGA_STAT_NONE;
else
}
*os = CFGA_STAT_NONE;
else
}
}
#define BI_POWERED 0
static const char *
binfo[] = {
"powered-on",
", assigned"
};
static const char *
binfo_parsable[] = {
"powered-on",
" assigned"
};
static void
{
int i;
int nsep;
const char **p;
if (parsable) {
p = binfo_parsable;
nsep = 1;
} else {
p = binfo;
nsep = 2;
}
i = nsep;
i = 0;
}
if (st->s_assigned)
}
#define CI_CPUID 0
static const char *
cpuinfo[] = {
"cpuid %d",
", speed %d MHz",
", ecache %d MBytes"
};
static const char *
cpuinfo_parsable[] = {
"cpuid=%d",
" speed=%d",
" ecache=%d"
};
static void
{
const char **p;
if (parsable)
p = cpuinfo_parsable;
else
p = cpuinfo;
}
#define MI_ADDRESS 0
static const char *
meminfo_nonparsable[] = {
"base address 0x%" PRIx64,
", %lu KBytes total",
", %lu KBytes permanent",
", unconfigurable",
", memory delete requested on %s",
", memory delete in progress on %s",
", %lu KBytes deleted",
", %lu KBytes remaining",
", inter board interleave"
};
static const char *
meminfo_parsable[] = {
"address=0x%" PRIx64,
" size=%lu",
" permanent=%lu",
" unconfigurable",
" source=%s",
" target=%s",
" deleted=%lu",
" remaining=%lu",
" inter-board-interleave"
};
/*
* This function assumes pagesize > 1024 and that
* pagesize is a multiple of 1024.
*/
static ulong_t
{
long pagesize;
}
static uint64_t
{
long pagesize;
}
static void
{
const char **p;
int want_progress;
if (parsable)
p = meminfo_parsable;
else
p = meminfo_nonparsable;
if (dst->ms_noreloc_pages)
if (!dst->ms_cage_enabled)
if (dst->ms_interleave)
/*
* If there is a valid peer physical ap_id specified,
* convert it to a logical id.
*/
want_progress = 0;
char *cm;
char *peer;
/*
* Save the component portion of the physid and
* add it back after converting to logical format.
*/
*cm = '\0';
cm += 2;
}
/* attempt to resolve to symlink */
else
if (dst->ms_peer_is_target) {
if (cm)
want_progress = 1;
} else {
if (cm)
}
}
if (want_progress ||
dst->ms_detpages));
}
}
#define II_DEVICE 0
static const char *
ioinfo[] = {
"device %s",
", referenced"
};
static const char *
ioinfo_parsable[] = {
"device=%s",
" referenced"
};
static void
{
const char **p;
if (parsable)
p = ioinfo_parsable;
else
p = ioinfo;
if (dst->is_referenced)
}
#define PI_CPUID 0
static const char *
cmpinfo[] = {
"cpuid %d",
" and %d",
", %d",
", and %d",
", speed %d MHz",
", ecache %d MBytes"
};
static const char *
cmpinfo_parsable[] = {
"cpuid=%d",
",%d",
",%d",
",%d",
" speed=%d",
" ecache=%d"
};
static void
{
int i;
int last;
const char **p;
if (parsable)
p = cmpinfo_parsable;
else
p = cmpinfo;
/* Print the first cpuid */
/*
* Print the middle cpuids, if necessary. Stop before
* the last one, since printing the last cpuid is a
* special case for the non parsable form.
*/
}
/* Print the last cpuid, if necessary */
}
}
void
{
switch (tgt) {
case AP_BOARD:
break;
case AP_CPU:
break;
case AP_MEM:
break;
case AP_IO:
break;
case AP_CMP:
break;
default:
break;
}
}