cfga.c revision 3db86aab554edbb4244c8d1a1c90f152eee768af
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stddef.h>
#include <locale.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <locale.h>
#include <langinfo.h>
#include <time.h>
#include <stdarg.h>
#include <sys/dditypes.h>
#include <sys/openpromio.h>
#ifdef SIM
#endif
#define CFGA_PLUGIN_LIB
#include <config_admin.h>
#ifdef DEBUG
#else
#define DBG(a, b)
#define DBG1(a)
#define DBG3(a, b, c)
#define DBG4(a, b, c, d)
#endif
#define BD_CPU 1
#define BD_MEM 2
#define BD_IO_2SBUS 3
#define BD_IO_SBUS_FFB 4
#define BD_IO_PCI 5
#define BD_DISK 6
#define BD_IO_2SBUS_SOCPLUS 7
#define BD_IO_SBUS_FFB_SOCPLUS 8
#define BD_UNKNOWN 9
#define CMD_GETSTAT 10
#define CMD_LIST 11
#define CMD_CONNECT 12
#define CMD_DISCONNECT 13
#define CMD_CONFIGURE 14
#define CMD_UNCONFIGURE 15
#define CMD_QUIESCE 16
#define CMD_INSERT 17
#define CMD_REMOVE 18
#define CMD_SET_COND 19
#define OPT_ENABLE 20
#define OPT_DISABLE 21
#define ERR_PROM_OPEN 22
#define ERR_PROM_GETPROP 23
#define ERR_PROM_SETPROP 24
#define ERR_TRANS 25
#define ERR_CMD_INVAL 26
#define ERR_OPT_INVAL 27
#define ERR_AP_INVAL 28
#define ERR_DISABLED 29
#define DIAG_FORCE 30
#define DIAG_TRANS_OK 31
#define DIAG_FAILED 32
#define DIAG_WAS_ENABLED 33
#define DIAG_WAS_DISABLED 34
#define DIAG_WILL_ENABLE 35
#define DIAG_WILL_DISABLE 36
#define HELP_HEADER 37
#define HELP_QUIESCE 38
#define HELP_INSERT 39
#define HELP_REMOVE 40
#define HELP_SET_COND 41
#define HELP_ENABLE 42
#define HELP_DISABLE 43
#define HELP_UNKNOWN 44
#define ASK_CONNECT 45
#define STR_BD 46
#define STR_COL 47
#define COND_UNKNOWN 48
#define COND_OK 49
#define COND_FAILING 50
#define COND_FAILED 51
#define COND_UNUSABLE 52
#define SYSC_COOLING 53
#define SYSC_POWER 54
#define SYSC_PRECHARGE 55
#define SYSC_INTRANS 56
#define SYSC_UTHREAD 57
#define SYSC_KTHREAD 58
#define SYSC_DEV_ATTACH 59
#define SYSC_DEV_DETACH 60
#define SYSC_NDI_ATTACH 61
#define SYSC_NDI_DETACH 62
#define SYSC_CORE_RESOURCE 63
#define SYSC_OSTATE 64
#define SYSC_RSTATE 65
#define SYSC_COND 66
#define SYSC_PROM 67
#define SYSC_NOMEM 68
#define SYSC_HOTPLUG 69
#define SYSC_HW_COMPAT 70
#define SYSC_NON_DR_PROM 71
#define SYSC_SUSPEND 72
#define SYSC_RESUME 73
#define SYSC_UNKNOWN 74
#define SYSC_DEVSTR 75
/*
* The string table contains all the strings used by the platform
* library. The comment next to each string specifies whether the
* string should be internationalized (y) or not (n).
* Note that there are calls to dgettext() with strings other than
* the ones below, they are marked by the li18 symbol.
*/
static char *
cfga_strs[] = {
/* */ NULL,
/* n */ "mem ",
/* n */ "dual-sbus ",
/* n */ "sbus-upa ",
/* n */ "dual-pci ",
/* n */ "disk ",
/* n */ "soc+sbus ",
/* n */ "soc+upa ",
/* n */ "unknown ",
/* n */ "get-status",
/* n */ "list",
/* n */ "connect",
/* n */ "disconnect",
/* n */ "configure",
/* n */ "unconfigure",
/* n */ "quiesce-test",
/* n */ "insert-test",
/* n */ "remove-test",
/* n */ "set-condition-test",
/* n */ "enable-at-boot",
/* n */ "disable-at-boot",
/* n */ "prom open",
/* n */ "prom getprop",
/* n */ "prom setprop",
/* y */ "invalid transition",
/* y */ "invalid command: ",
/* y */ "invalid option: ",
/* y */ "invalid attachment point: ",
/* y */ "board is disabled: must override with ",
/* n */ "[-f][-o enable-at-boot]",
/* y */ "transition succeeded but ",
/* y */ " failed: ",
/* y */ "was already enabled at boot time",
/* y */ "was already disabled at boot time",
/* y */ "will be enabled at boot time",
/* y */ "will be disabled at boot time",
/* n */ "\t-x quiesce-test ap_id [ap_id...]",
/* n */ "\t-x insert-test ap_id [ap_id...]",
/* n */ "\t-x remove-test ap_id [ap_id...]",
/* n */ "\t-x set-condition-test=<condition>",
/* n */ "\t-o enable-at-boot",
/* n */ "\t-o disable-at-boot",
/* y */ "\tunknown command or option: ",
/* y */
"system will be temporarily suspended to connect a board: proceed",
/* y */ "board ",
/* y */ ": ",
/* n */ "unknown",
/* n */ "ok",
/* n */ "failing",
/* n */ "failed",
/* n */ "unusable",
/* y */ "not enough cooling for a new board",
/* y */ "not enough power for a new board",
/* y */ "not enough precharge power for a new board",
/* y */ "configuration operation already in progress on this board",
/* y */ "could not suspend user process: ",
/* y */ "could not suspend system processes",
/* y */ "device did not attach",
/* y */ "device did not detach",
/* y */ "nexus error during attach",
/* y */ "nexus error during detach",
/* y */ "attempt to remove core system resource",
/* y */ "invalid occupant state",
/* y */ "invalid receptacle state",
/* y */ "insufficient condition",
/* y */ "firmware operation error",
/* y */ "not enough memory",
/* y */ "hotplug feature unavailable on this machine",
/* y */ "board does not support dynamic reconfiguration",
/* y */ "firmware does not support dynamic reconfiguration",
/* y */ "system suspend error",
/* y */ "system resume error",
/* y */ "unknown system error",
/* */ NULL
};
#define cfga_eid(a, b) (((a) << 8) + (b))
/*
*
* Translation table for mapping from an <errno,sysc_err>
* pair to an error string.
*
*
* SYSC_COOLING, EAGAIN, SYSC_ERR_COOLING
* SYSC_POWER, EAGAIN, SYSC_ERR_POWER
* SYSC_PRECHARGE, EAGAIN, SYSC_ERR_PRECHARGE
* SYSC_INTRANS, EBUSY, SYSC_ERR_INTRANS
* SYSC_KTHREAD, EBUSY, SYSC_ERR_KTHREAD
* SYSC_DEV_ATTACH, EBUSY, SYSC_ERR_NDI_ATTACH
* SYSC_DEV_DETACH, EBUSY, SYSC_ERR_NDI_DETACH
* SYSC_NDI_ATTACH, EFAULT, SYSC_ERR_NDI_ATTACH
* SYSC_NDI_DETACH, EFAULT, SYSC_ERR_NDI_DETACH
* SYSC_CORE_RESOURCE, EINVAL, SYSC_ERR_CORE_RESOURCE
* SYSC_OSTATE, EINVAL, SYSC_ERR_OSTATE
* SYSC_RSTATE, EINVAL, SYSC_ERR_RSTATE
* SYSC_COND, EINVAL, SYSC_ERR_COND
* SYSC_PROM, EIO, SYSC_ERR_PROM
* SYSC_NOMEM, ENOMEM, SYSC_ERR_DR_INIT
* SYSC_NOMEM, ENOMEM, SYSC_ERR_NDI_ATTACH
* SYSC_NOMEM, ENOMEM, SYSC_ERR_NDI_DETACH
* SYSC_HOTPLUG, ENOTSUP, SYSC_ERR_HOTPLUG
* SYSC_HW_COMPAT, ENOTSUP, SYSC_ERR_HW_COMPAT
* SYSC_NON_DR_PROM, ENOTSUP, SYSC_ERR_NON_DR_PROM
* SYSC_SUSPEND, ENXIO, SYSC_ERR_SUSPEND
* SYSC_RESUME, ENXIO, SYSC_ERR_RESUME
* SYSC_UTHREAD, ESRCH, SYSC_ERR_UTHREAD
*/
static int
{
if (scerr == SYSC_ERR_DEFAULT)
return (SYSC_UNKNOWN);
return (SYSC_COOLING);
return (SYSC_POWER);
return (SYSC_PRECHARGE);
return (SYSC_INTRANS);
return (SYSC_KTHREAD);
return (SYSC_DEV_ATTACH);
return (SYSC_DEV_DETACH);
return (SYSC_NDI_ATTACH);
return (SYSC_NDI_DETACH);
return (SYSC_CORE_RESOURCE);
return (SYSC_OSTATE);
return (SYSC_RSTATE);
return (SYSC_COND);
return (SYSC_PROM);
return (SYSC_NOMEM);
return (SYSC_NOMEM);
return (SYSC_NOMEM);
return (SYSC_HOTPLUG);
return (SYSC_HW_COMPAT);
return (SYSC_NON_DR_PROM);
return (SYSC_SUSPEND);
return (SYSC_RESUME);
return (SYSC_UTHREAD);
default:
break;
}
return (SYSC_UNKNOWN);
}
static void
{
}
/*
* cfga_err() accepts a variable number of message IDs and constructs
* a corresponding error string which is returned via the errstring argument.
* cfga_err() calls dgettext() to internationalize proper messages.
*/
static void
{
int a;
int i;
int n;
int len;
int flen;
char *p;
char *q;
char *s[32];
char *failed;
char syserr_num[20];
/*
* If errstring is null it means user in not interested in getting
* error status. So we don't do all the work
*/
return;
}
switch (a) {
case ERR_PROM_OPEN:
case ERR_PROM_GETPROP:
case ERR_PROM_SETPROP:
case CMD_GETSTAT:
case CMD_LIST:
case CMD_CONNECT:
case CMD_DISCONNECT:
case CMD_CONFIGURE:
case CMD_UNCONFIGURE:
case CMD_QUIESCE:
case CMD_INSERT:
case CMD_REMOVE:
case CMD_SET_COND:
p = cfga_str(a);
s[n] = p;
s[++n] = failed;
DBG("<%s>", p);
break;
case OPT_ENABLE:
case OPT_DISABLE:
q = cfga_str(a);
s[n] = p;
s[++n] = q;
s[++n] = failed;
DBG("<%s>", p);
DBG("<%s>", q);
break;
case ERR_CMD_INVAL:
case ERR_AP_INVAL:
case ERR_OPT_INVAL:
s[n] = p;
s[++n] = q;
DBG("<%s>", p);
DBG("<%s>", q);
break;
case ERR_TRANS:
case ERR_DISABLED:
s[n] = p;
DBG("<%s>", p);
break;
case DIAG_FORCE:
default:
p = cfga_str(a);
s[n] = p;
DBG("<%s>", p);
break;
}
}
DBG1("\n");
if (errno) {
if (sc)
else
i = SYSC_UNKNOWN;
if (i == SYSC_UNKNOWN) {
if (p == NULL) {
p = syserr_num;
}
} else
s[n++] = p;
p = cfga_str(SYSC_DEVSTR);
if (p && p[0]) {
s[n++] = q;
s[n++] = p;
}
}
return;
for (i = 0; i < n; i++)
(void) strcat(p, s[i]);
*errstring = p;
#ifdef SIM_MSG
#endif
}
/*
* This routine accepts a variable number of message IDs and constructs
* a corresponding error string which is printed via the message print routine
* argument. The HELP_UNKNOWN message ID has an argument string (the unknown
* help topic) that follows.
*/
static void
{
int a;
int i;
int n;
int len;
char *p;
char *s[32];
DBG("<%d>", a);
s[n] = p;
if (a == HELP_UNKNOWN) {
s[++n] = p;
}
}
return;
for (i = 0; i < n; i++)
(void) strcat(p, s[i]);
(void) strcat(p, "\n");
#ifdef SIM_MSG
printf("%s", p);
#else
#endif
free(p);
}
static sysc_cfga_stat_t *
{
int fd;
return (NULL);
return (NULL);
} else if (fdp)
else
return (sc_list);
}
/*
* This code implementes the simulation of the ioctls that transition state.
* The GETSTAT ioctl is not simulated. In this way a snapshot of the system
* state is read and manipulated by the simulation routines. It is basically
* a useful debugging tool.
*/
#ifdef SIM
static int sim_idx;
static int sim_fd = -1;
static sysc_cfga_stat_t *
{
int fd;
if (sim_fd != -1)
return (sim_sc_list);
perror("sim_open");
exit(1);
perror("sim_stat");
exit(1);
}
perror("sim_size");
exit(1);
perror("sim_read");
exit(1);
}
return (NULL);
return (NULL);
} else if (fdp)
return (sim_sc_list);
}
static int
sim_open(char *a, int b, int c)
{
printf("sim_open(%s)\n", a);
return (open(a, b, c));
return (0);
}
static int
sim_close(int a) { return (0); }
static int
{
switch (cmd) {
case SYSC_CFGA_CMD_CONNECT:
break;
case SYSC_CFGA_CMD_CONFIGURE:
break;
break;
case SYSC_CFGA_CMD_DISCONNECT:
break;
case SYSC_CFGA_CMD_TEST:
return (0);
case OPROMGETOPT:
case OPROMSETOPT:
}
perror("sim_seek");
exit(1);
}
perror("sim_write");
exit(1);
}
return (0);
}
#define sysc_stat(a, b) sim_sysc_stat(a, b)
#endif /* SIM */
static char *dlprop = "disabled-board-list";
#define BUFSIZE 128
typedef union {
struct openpromio opp;
} oppbuf_t;
static int
{
return (ERR_PROM_GETPROP);
else if (opp->oprom_size > 0)
else
return (0);
}
static cfga_err_t
{
return (ERR_PROM_SETPROP);
return (0);
}
static int
{
int i;
int err;
int prom_fd;
char *p;
char *dl;
char b[2];
return (ERR_PROM_OPEN);
return (err);
} else
b[1] = 0;
*disabled = 0;
for (i = 0; i < len; i++) {
int bd;
b[0] = dl[i];
(*disabled)++;
}
}
return (0);
}
static int
int verbose)
{
int i, j, n;
int err;
int found;
int update;
int prom_fd;
char *p;
char b[2];
char ndlist[64];
b[1] = 0;
ndlist[0] = 0;
j = 0;
found = 0;
update = 0;
return (ERR_PROM_OPEN);
if (dlist) {
for (i = 0; i < len; i++) {
int bd;
b[0] = dlist[i];
found++;
if (disable) {
if (verbose)
DIAG_WAS_DISABLED, 0);
} else {
if (verbose)
DIAG_WILL_ENABLE, 0);
update++;
continue;
}
}
}
ndlist[j] = 0;
}
if (!found)
if (disable) {
if (verbose)
p = &ndlist[j];
p[n] = 0;
update++;
} else {
if (verbose)
}
if (update)
else
err = 0;
return (err);
}
static int
{
int id;
char *s;
static char *slot = "slot";
return (-1);
else {
int n;
n = strlen(s);
DBG3("ap_idx: s=%s, n=%d\n", s, n);
switch (n) {
case 2:
if (!isdigit(s[1]))
return (-1);
/* FALLTHROUGH */
case 1:
if (!isdigit(s[0]))
return (-1);
break;
default:
return (-1);
}
}
return (-1);
return (id);
}
/*ARGSUSED*/
const char *ap_id,
const char *options,
struct cfga_confirm *confp,
char **errstring,
{
int fd;
int idx;
int err;
int force;
int verbose;
int opterr;
int disable;
int disabled;
char *dlist;
char outputstr[SYSC_OUTPUT_LEN];
rc = CFGA_ERROR;
if (options) {
disable = 0;
disable++;
return (rc);
}
}
return (rc);
return (rc);
}
#ifdef SIM
#endif
/*
* We disallow connecting on the disabled list unless
* either the FORCE flag or the enable-at-boot option
* is set. The check is made further below
*/
return (rc);
} else
switch (state_change_cmd) {
case CFGA_CMD_CONNECT:
if (rs != SYSC_CFGA_RSTATE_DISCONNECTED)
ERR_DISABLED, DIAG_FORCE, 0);
cfga_str(ASK_CONNECT))) {
return (CFGA_NACK);
} else
break;
case CFGA_CMD_DISCONNECT:
if ((os == SYSC_CFGA_OSTATE_CONFIGURED) &&
return (CFGA_ERROR);
} else
if (rs == SYSC_CFGA_RSTATE_CONNECTED) {
} else
} else
break;
case CFGA_CMD_CONFIGURE:
if (rs == SYSC_CFGA_RSTATE_DISCONNECTED)
ERR_DISABLED, DIAG_FORCE, 0);
return (CFGA_ERROR);
cfga_str(ASK_CONNECT))) {
return (CFGA_NACK);
return (CFGA_ERROR);
} else
if (os == SYSC_CFGA_OSTATE_UNCONFIGURED) {
} else
} else
break;
case CFGA_CMD_UNCONFIGURE:
if (os != SYSC_CFGA_OSTATE_CONFIGURED)
} else
break;
default:
rc = CFGA_OPNOTSUPP;
break;
}
return (rc);
}
static int
{
int c;
c = SYSC_CFGA_COND_OK;
else
c = -1;
return (c);
}
/*ARGSUSED*/
const char *function,
const char *ap_id,
const char *options,
struct cfga_confirm *confp,
char **errstring,
{
int fd;
int idx;
int len;
int cmd;
int cond;
int err;
int opterr;
int verbose;
int disable;
int disabled;
char *str;
char *dlist;
char outputstr[SYSC_OUTPUT_LEN];
rc = CFGA_ERROR;
if (options) {
disable = 0;
disable++;
return (rc);
}
}
err = CMD_SET_COND;
err = CMD_QUIESCE;
err = CMD_INSERT;
err = CMD_REMOVE;
} else {
return (rc);
}
else
if (options) {
if (opterr) {
if (verbose)
}
}
return (rc);
}
/*ARGSUSED*/
const char *ap_id,
const char *options,
char **errstring,
{
return (CFGA_OPNOTSUPP);
}
static cfga_stat_t
{
switch (rs) {
case SYSC_CFGA_RSTATE_EMPTY:
break;
break;
break;
default:
cs = CFGA_STAT_NONE;
break;
}
return (cs);
}
static cfga_stat_t
{
switch (os) {
break;
break;
default:
cs = CFGA_STAT_NONE;
break;
}
return (cs);
}
static cfga_cond_t
{
switch (sc) {
case SYSC_CFGA_COND_OK:
cc = CFGA_COND_OK;
break;
case SYSC_CFGA_COND_FAILING:
break;
case SYSC_CFGA_COND_FAILED:
break;
case SYSC_CFGA_COND_UNUSABLE:
break;
case SYSC_CFGA_COND_UNKNOWN:
default:
break;
}
return (cc);
}
static char *
{
char *type_str;
switch (type) {
case MEM_BOARD:
break;
case CPU_BOARD:
break;
case IO_2SBUS_BOARD:
break;
case IO_SBUS_FFB_BOARD:
break;
case IO_PCI_BOARD:
break;
case DISK_BOARD:
break;
case IO_2SBUS_SOCPLUS_BOARD:
break;
break;
case UNKNOWN_BOARD:
default:
break;
}
return (type_str);
}
static void
{
int i;
case CPU_BOARD:
if (cpu->cache_size)
(float)cpu->cache_size /
(float)(1024 * 1024));
}
}
break;
case IO_SBUS_FFB_BOARD:
case FFB_SINGLE:
break;
case FFB_DOUBLE:
break;
case FFB_NOT_FOUND:
#ifdef FFB_DR_SUPPORT
#endif
break;
default:
break;
}
break;
case DISK_BOARD:
for (i = 0; i < 2; i++)
else
break;
}
if (disabled)
if (sc->plus_board)
}
static void
{
}
/*ARGSUSED*/
const char *ap_id,
int *nlist,
const char *options,
char **errstring)
{
int i;
rc = CFGA_ERROR;
else {
continue;
(*nlist)++;
}
}
return (rc);
}
/*ARGSUSED*/
const char *ap_id,
struct cfga_stat_data *cs,
const char *options,
char **errstring)
{
int idx;
int err;
int opterr;
int disable;
int disabled;
char *dlist;
rc = CFGA_ERROR;
disable = 0;
disable++;
return (rc);
}
}
else {
!= 0))) {
}
}
return (rc);
}
/*ARGSUSED*/
{
int help = 0;
if (options) {
help = HELP_DISABLE;
help = HELP_ENABLE;
help = HELP_INSERT;
help = HELP_REMOVE;
help = HELP_QUIESCE;
else
help = HELP_UNKNOWN;
}
if (help) {
if (help == HELP_UNKNOWN)
else
} else {
}
return (CFGA_OK);
}
/*
* cfga_ap_id_cmp -- use default_ap_id_cmp() in libcfgadm
*/