/*
* 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 <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <macros.h>
#include <dirent.h>
#include <libgen.h>
#include <libdevinfo.h>
#define CFGA_PLUGIN_LIB
#include <config_admin.h>
#include "ap.h"
/*ARGSUSED0*/
int
{
int n;
int rc;
char *p;
*symid = '\0';
rc = -1;
return (rc);
p = path + n;
char *cp;
*p = '\0';
continue;
cp--; /* Get the '/' */
rc = 0;
break;
}
}
return (rc);
}
char *
{
int n;
char *buf;
return (NULL);
/*
* Look for a symlink. On any error, fallback to
* driver and instance based logical ap_ids.
*/
else
/*
* Append the dynamic portion, if any.
*/
return (buf);
}
int
{
int i;
int rc;
int phys;
char c;
char *s;
char *p;
char *q;
char *base;
int len;
char *t;
if (a == NULL)
return (-1);
a->cnum = -1;
a->bnum = -1;
a->inst = -1;
rc = ERR_AP_INVAL;
goto done;
}
goto done;
}
/*
* For a physical ap_id, look only at the base part.
*/
phys = 1;
} else {
phys = 0;
goto done;
}
}
/*
* No ':' found, or got a '::'. If this is a physical
* ap_id, it must have a minor separtor ':' which must
* appear before the dynamic part (starting with '::').
* names.
*/
if (phys) {
rc = ERR_AP_INVAL;
goto done;
} else
s = base;
} else {
/*
* i.e. up to the minor node name.
*/
*s = '\0';
/*
*/
*p = '\0';
goto done;
}
*p++ = '@';
i = strtol(p, &q, 10);
if (q > p)
a->inst = i;
}
*s++ = ':';
a->minor = s;
}
/*
* Need to go to the end of the string before the :: if any
* If the string is null then we are done
*/
t = strstr(s, "::");
if (t != NULL)
else
len = 0;
p = s;
if (*p == '\0')
rc = ERR_AP_INVAL;
goto done;
} else {
/*
* Save the component id.
*/
*p++ = '\0';
*p++ = '\0';
a->cid = p;
}
/*
* Get the operation target, e.g. slot0, slot0::cpu0.
* At this point, a->path points to the /devices path
* minus the dynamic part, for a physical ap_id. In
* the case of a logical ap_id, the target is already
* initialized above.
*/
goto done;
}
goto done;
while ((*p != '\0') && !isdigit(*p))
p++;
/*
* Get the component unit number, if present.
*/
i = strtol(p, &s, 10);
/*
* There must be no characters after the unit number.
*/
if (*s != '\0') {
rc = ERR_CM_INVAL;
goto done;
}
if (s > p) {
/*
* Disallow leading zeroes, e.g. cpu00, cpu01, cpu001.
* If there are 2 or more digits and the first is a zero,
* we fail.
*/
if ((s-p) >= 2 && *p == '0') {
rc = ERR_CM_INVAL;
goto done;
}
a->cnum = i;
}
c = *p;
*p = '\0';
*p = c;
done:
switch (rc) {
case ERR_NONE:
break;
case ERR_CM_INVAL:
break;
default:
break;
}
DBG("drv=<%s> inst=%d minor=<%s> ",
}
/*
* Command table.
*
* The first set of commands in the table are in sequencing order,
* for example, the first group starts with assign and ends with
* configure. command sequencer relies on this ordering.
*/
static char *
ap_cmd_names[] = {
"assign",
"poweron",
"test",
"connect",
"configure",
"notify online",
"notify add capacity",
"suspend check",
"request suspend",
"request delete capacity",
"request offline",
"unconfigure",
"notify remove",
"notify capacity change",
"disconnect",
"poweroff",
"unassign",
"notify resume",
"status",
"getncm",
"passthru",
"help",
"errtest",
};
char *
ap_cmd_name(int i)
{
}
static char *
ap_opt_names[] = {
"unassign",
"skip",
"parsable",
"nopoweroff",
"code",
"mid",
"err",
"platform",
"sim",
};
char *
ap_opt_name(int i)
{
return (ap_opt_names[i]);
}
/*
* Command descriptor.
*
* Each command has a (command) mask specifying the AP target classes
* it operates on, e.g. the assign command applies only to boards.
* In addition each AP target class has a separate option mask specifying
* which command options are valid for that target class.
* A global value mask specifies which options require values.
*/
typedef struct {
int cmd;
} ap_cmd_t;
/*
* Command option definitions.
*/
#define NULOPT 0
static ap_cmd_t
ap_cmds[] = {
/*
* cmd cmd board cpu mem io cmp
* cmask omask omask omask omask omask
*/
{CMD_NONE, 0, 0, 0, 0, 0, 0, 0 }
};
/*
* Global mask for options that require values.
*/
#define AP_VMASK (\
#if SBD_DEBUG
void
{
int i;
dbg("%23s%5s%5s%9s%9s%9s%9s%9s\n",
"cmd", "msk", "none", "brd", "cpu", "mem", "io", "cmp");
}
dbg("\n");
}
}
#endif
int
{
int c;
int rc;
switch (i) {
case CFGA_CMD_CONNECT:
c = CMD_CONNECT;
break;
case CFGA_CMD_DISCONNECT:
c = CMD_DISCONNECT;
break;
case CFGA_CMD_CONFIGURE:
c = CMD_CONFIGURE;
break;
case CFGA_CMD_UNCONFIGURE:
c = CMD_UNCONFIGURE;
break;
case CFGA_CMD_LOAD:
case CFGA_CMD_UNLOAD:
rc = CFGA_OPNOTSUPP;
c = CMD_NONE;
break;
default:
rc = CFGA_INVAL;
c = CMD_NONE;
break;
}
*cmd = c;
return (rc);
}
static int
{
int i;
char **p;
return (CMD_NONE);
for (i = 0, p = ap_cmd_names; *p != NULL; p++, i++)
break;
if (*p == NULL)
i = CMD_NONE;
return (i);
}
static int
{
char *optstr;
/*
* Set default values.
*/
return (0);
return (-1);
}
return (0);
while (*optstr != '\0') {
int i;
int opt;
int omask;
char *p;
char *value;
char *optname;
if (opt == -1) {
return (-1);
}
if (i == 0) {
return (-1);
}
/*
* Check whether the option requires a value.
*/
return (-1);
return (-1);
}
/*
* Set the options's value.
*/
switch (opt) {
case OPT_SIM:
case OPT_PARSABLE:
case OPT_UNASSIGN:
break;
case OPT_CODE:
if (p > value)
break;
case OPT_MID:
break;
case OPT_ERR:
if (p > value)
break;
case OPT_NOPOWEROFF:
i = ap_cmd("poweroff");
break;
case OPT_SKIP: /* for debugging */
/*
* The skip value may be a ':' separated
* list of steps (commands) to be skipped
* during sequencing.
*/
ap_err(a, ERR_CMD_INVAL, p);
return (-1);
}
}
break;
case OPT_PLATFORM:
break;
default:
return (-1);
}
}
return (0);
}
static ap_cmd_t *
{
break;
return (NULL);
return (acp);
}
{
int c;
int all;
int tgt;
int target;
#ifdef _SBD_DEBUG
ap_cmds_dump();
#endif
rc = CFGA_INVAL;
ap_err(a, ERR_CMD_INVAL, f);
return (rc);
}
/*
* Change a->statonly to 1, if the case is CMD_STATUS. We are only
* wanting to read the devices and no more
*/
/*
* Get the status for all components if either the list all
* option being specified or if we are configuring/unconfiguring
* the board. The latter is needed for the RCM interface.
*/
switch (c) {
case CMD_STATUS:
a->statonly = 1;
break;
case CMD_CONFIGURE:
case CMD_UNCONFIGURE:
case CMD_CONNECT:
case CMD_DISCONNECT:
a->statonly = 0;
break;
default:
all = 0;
a->statonly = 0;
break;
}
return (rc);
rc = CFGA_INVAL;
/*
* Get the target here in case it is a component in which
* case its type is known after the initialization.
*/
DBG("cmd=%s(%d) tmask=0x%x cmask=0x%x omask=0x%x\n",
ap_err(a, ERR_CMD_NOTSUPP, c);
if (c == CMD_STATUS)
rc = ap_platopts_check(a, c, c);
else
}
#ifdef __x86
/*
* Currently on x86 platforms, only limited cfgadm commands are exposed
* to end users, though all cfgadm commands are supported by underlying
* dr driver. If the special platform option "acpi-update-status" is
* absent, reject all hidden commands.
* This is a ugly hack, it should be removed in future releases.
*/
switch (c) {
case CMD_STATUS:
case CMD_CONFIGURE:
case CMD_PASSTHRU:
break;
default:
rc = CFGA_INVAL;
ap_err(a, ERR_CMD_INVAL, f);
}
}
#endif /* __x86 */
if (cmd)
*cmd = c;
return (rc);
}
int
{
int cnt;
else
cnt = 1;
return (cnt);
}