#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/types.h>
#include <sys/ioctl.h>
#include <sys/dditypes.h>
#include <sys/modctl.h>
#include <sys/obpdefs.h>
#include <sys/fhc.h>
#include <sys/sysctrl.h>
#include <sys/openpromio.h>
#ifdef SIM
#include <sys/stat.h>
#endif
#define CFGA_PLUGIN_LIB
#include <config_admin.h>
#ifdef DEBUG
#define DBG printf
#define DBG1 printf
#define DBG3 printf
#define DBG4 printf
#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
static char *
cfga_strs[] = {
NULL,
"cpu/mem ",
"mem ",
"dual-sbus ",
"sbus-upa ",
"dual-pci ",
"disk ",
"soc+sbus ",
"soc+upa ",
"unknown ",
"get-status",
"list",
"connect",
"disconnect",
"configure",
"unconfigure",
"quiesce-test",
"insert-test",
"remove-test",
"set-condition-test",
"enable-at-boot",
"disable-at-boot",
"prom open",
"prom getprop",
"prom setprop",
"invalid transition",
"invalid command: ",
"invalid option: ",
"invalid attachment point: ",
"board is disabled: must override with ",
"[-f][-o enable-at-boot]",
"transition succeeded but ",
" failed: ",
"was already enabled at boot time",
"was already disabled at boot time",
"will be enabled at boot time",
"will be disabled at boot time",
"\nSysctrl specific commands/options:",
"\t-x quiesce-test ap_id [ap_id...]",
"\t-x insert-test ap_id [ap_id...]",
"\t-x remove-test ap_id [ap_id...]",
"\t-x set-condition-test=<condition>",
"\t-o enable-at-boot",
"\t-o disable-at-boot",
"\tunknown command or option: ",
"system will be temporarily suspended to connect a board: proceed",
"board ",
": ",
"unknown",
"ok",
"failing",
"failed",
"unusable",
"not enough cooling for a new board",
"not enough power for a new board",
"not enough precharge power for a new board",
"configuration operation already in progress on this board",
"could not suspend user process: ",
"could not suspend system processes",
"device did not attach",
"device did not detach",
"nexus error during attach",
"nexus error during detach",
"attempt to remove core system resource",
"invalid occupant state",
"invalid receptacle state",
"insufficient condition",
"firmware operation error",
"not enough memory",
"hotplug feature unavailable on this machine",
"board does not support dynamic reconfiguration",
"firmware does not support dynamic reconfiguration",
"system suspend error",
"system resume error",
"unknown system error",
NULL
};
#define cfga_str(i) cfga_strs[(i)]
#define cfga_eid(a, b) (((a) << 8) + (b))
static int
cfga_sid(int err, int scerr)
{
if (scerr == SYSC_ERR_DEFAULT)
return (SYSC_UNKNOWN);
switch (cfga_eid(err, scerr)) {
case cfga_eid(EAGAIN, SYSC_ERR_COOLING):
return (SYSC_COOLING);
case cfga_eid(EAGAIN, SYSC_ERR_POWER):
return (SYSC_POWER);
case cfga_eid(EAGAIN, SYSC_ERR_PRECHARGE):
return (SYSC_PRECHARGE);
case cfga_eid(EBUSY, SYSC_ERR_INTRANS):
return (SYSC_INTRANS);
case cfga_eid(EBUSY, SYSC_ERR_KTHREAD):
return (SYSC_KTHREAD);
case cfga_eid(EBUSY, SYSC_ERR_NDI_ATTACH):
return (SYSC_DEV_ATTACH);
case cfga_eid(EBUSY, SYSC_ERR_NDI_DETACH):
return (SYSC_DEV_DETACH);
case cfga_eid(EFAULT, SYSC_ERR_NDI_ATTACH):
return (SYSC_NDI_ATTACH);
case cfga_eid(EFAULT, SYSC_ERR_NDI_DETACH):
return (SYSC_NDI_DETACH);
case cfga_eid(EINVAL, SYSC_ERR_CORE_RESOURCE):
return (SYSC_CORE_RESOURCE);
case cfga_eid(EINVAL, SYSC_ERR_OSTATE):
return (SYSC_OSTATE);
case cfga_eid(EINVAL, SYSC_ERR_RSTATE):
return (SYSC_RSTATE);
case cfga_eid(EINVAL, SYSC_ERR_COND):
return (SYSC_COND);
case cfga_eid(EIO, SYSC_ERR_PROM):
return (SYSC_PROM);
case cfga_eid(ENOMEM, SYSC_ERR_DR_INIT):
return (SYSC_NOMEM);
case cfga_eid(ENOMEM, SYSC_ERR_NDI_ATTACH):
return (SYSC_NOMEM);
case cfga_eid(ENOMEM, SYSC_ERR_NDI_DETACH):
return (SYSC_NOMEM);
case cfga_eid(ENOTSUP, SYSC_ERR_HOTPLUG):
return (SYSC_HOTPLUG);
case cfga_eid(ENOTSUP, SYSC_ERR_HW_COMPAT):
return (SYSC_HW_COMPAT);
case cfga_eid(ENOTSUP, SYSC_ERR_NON_DR_PROM):
return (SYSC_NON_DR_PROM);
case cfga_eid(ENXIO, SYSC_ERR_SUSPEND):
return (SYSC_SUSPEND);
case cfga_eid(ENXIO, SYSC_ERR_RESUME):
return (SYSC_RESUME);
case cfga_eid(ESRCH, SYSC_ERR_UTHREAD):
return (SYSC_UTHREAD);
default:
break;
}
return (SYSC_UNKNOWN);
}
static void
sysc_cmd_init(sysc_cfga_cmd_t *sc, char *outputstr, int force)
{
sc->force = force;
sc->outputstr = outputstr;
sc->errtype = SYSC_ERR_DEFAULT;
(void) memset((void *)outputstr, 0, sizeof (outputstr));
cfga_str(SYSC_DEVSTR) = outputstr;
}
static void
cfga_err(sysc_cfga_cmd_t *sc, char **errstring, ...)
{
int a;
int i;
int n;
int len;
int flen;
char *p;
char *q;
char *s[32];
char *failed;
va_list ap;
char syserr_num[20];
if (errstring == NULL) {
return;
}
va_start(ap, errstring);
failed = dgettext(TEXT_DOMAIN, cfga_str(DIAG_FAILED));
flen = strlen(failed);
for (n = len = 0; (a = va_arg(ap, int)) != 0; n++) {
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);
len += (strlen(p) + flen);
s[n] = p;
s[++n] = failed;
DBG("<%s>", p);
DBG("<%s>", failed);
break;
case OPT_ENABLE:
case OPT_DISABLE:
p = dgettext(TEXT_DOMAIN, cfga_str(DIAG_TRANS_OK));
q = cfga_str(a);
len += (strlen(p) + strlen(q) + flen);
s[n] = p;
s[++n] = q;
s[++n] = failed;
DBG("<%s>", p);
DBG("<%s>", q);
DBG("<%s>", failed);
break;
case ERR_CMD_INVAL:
case ERR_AP_INVAL:
case ERR_OPT_INVAL:
p = dgettext(TEXT_DOMAIN, cfga_str(a));
q = va_arg(ap, char *);
len += (strlen(p) + strlen(q));
s[n] = p;
s[++n] = q;
DBG("<%s>", p);
DBG("<%s>", q);
break;
case ERR_TRANS:
case ERR_DISABLED:
p = dgettext(TEXT_DOMAIN, cfga_str(a));
len += strlen(p);
s[n] = p;
DBG("<%s>", p);
break;
case DIAG_FORCE:
default:
p = cfga_str(a);
len += strlen(p);
s[n] = p;
DBG("<%s>", p);
break;
}
}
DBG1("\n");
va_end(ap);
if (errno) {
if (sc)
i = cfga_sid(errno, (int)sc->errtype);
else
i = SYSC_UNKNOWN;
DBG4("cfga_sid(%d,%d)=%d\n", errno, sc->errtype, i);
if (i == SYSC_UNKNOWN) {
p = strerror(errno);
if (p == NULL) {
(void) sprintf(syserr_num, "errno=%d", errno);
p = syserr_num;
}
} else
p = dgettext(TEXT_DOMAIN, cfga_str(i));
len += strlen(p);
s[n++] = p;
p = cfga_str(SYSC_DEVSTR);
if (p && p[0]) {
q = cfga_str(STR_COL);
len += strlen(q);
s[n++] = q;
len += strlen(p);
s[n++] = p;
}
}
if ((p = (char *)calloc(len, 1)) == NULL)
return;
for (i = 0; i < n; i++)
(void) strcat(p, s[i]);
*errstring = p;
#ifdef SIM_MSG
printf("%s\n", *errstring);
#endif
}
static void
cfga_msg(struct cfga_msg *msgp, ...)
{
int a;
int i;
int n;
int len;
char *p;
char *s[32];
va_list ap;
va_start(ap, msgp);
for (n = len = 0; (a = va_arg(ap, int)) != 0; n++) {
DBG("<%d>", a);
p = dgettext(TEXT_DOMAIN, cfga_str(a));
len += strlen(p);
s[n] = p;
if (a == HELP_UNKNOWN) {
p = va_arg(ap, char *);
len += strlen(p);
s[++n] = p;
}
}
va_end(ap);
if ((p = (char *)calloc(len + 1, 1)) == NULL)
return;
for (i = 0; i < n; i++)
(void) strcat(p, s[i]);
(void) strcat(p, "\n");
#ifdef SIM_MSG
printf("%s", p);
#else
(*msgp->message_routine)(msgp->appdata_ptr, p);
#endif
free(p);
}
static sysc_cfga_stat_t *
sysc_stat(const char *ap_id, int *fdp)
{
int fd;
static sysc_cfga_stat_t sc_list[MAX_BOARDS];
if ((fd = open(ap_id, O_RDWR, 0)) == -1)
return (NULL);
else if (ioctl(fd, SYSC_CFGA_CMD_GETSTATUS, sc_list) == -1) {
(void) close(fd);
return (NULL);
} else if (fdp)
*fdp = fd;
else
(void) close(fd);
return (sc_list);
}
#ifdef SIM
static int sim_idx;
static int sim_fd = -1;
static int sim_size = MAX_BOARDS * sizeof (sysc_cfga_stat_t);
static sysc_cfga_stat_t sim_sc_list[MAX_BOARDS];
static sysc_cfga_stat_t *
sim_sysc_stat(const char *ap_id, int *fdp)
{
int fd;
struct stat buf;
if (sim_fd != -1)
return (sim_sc_list);
if ((sim_fd = open("/tmp/cfga_simdata", O_RDWR|O_CREAT)) == -1) {
perror("sim_open");
exit(1);
} else if (fstat(sim_fd, &buf) == -1) {
perror("sim_stat");
exit(1);
}
if (buf.st_size) {
if (buf.st_size != sim_size) {
perror("sim_size");
exit(1);
} else if (read(sim_fd, sim_sc_list, sim_size) == -1) {
perror("sim_read");
exit(1);
}
} else if ((fd = open(ap_id, O_RDWR, 0)) == -1)
return (NULL);
else if (ioctl(fd, SYSC_CFGA_CMD_GETSTATUS, sim_sc_list) == -1) {
(void) close(fd);
return (NULL);
} else if (fdp)
*fdp = fd;
return (sim_sc_list);
}
static int
sim_open(char *a, int b, int c)
{
printf("sim_open(%s)\n", a);
if (strcmp(a, "/dev/openprom") == 0)
return (open(a, b, c));
return (0);
}
static int
sim_close(int a)
{
return (0);
}
static int
sim_ioctl(int fd, int cmd, void *a)
{
printf("sim_ioctl(%d)\n", sim_idx);
switch (cmd) {
case SYSC_CFGA_CMD_CONNECT:
sim_sc_list[sim_idx].rstate = SYSC_CFGA_RSTATE_CONNECTED;
break;
case SYSC_CFGA_CMD_CONFIGURE:
sim_sc_list[sim_idx].ostate = SYSC_CFGA_OSTATE_CONFIGURED;
break;
case SYSC_CFGA_CMD_UNCONFIGURE:
sim_sc_list[sim_idx].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
break;
case SYSC_CFGA_CMD_DISCONNECT:
sim_sc_list[sim_idx].rstate = SYSC_CFGA_RSTATE_DISCONNECTED;
break;
case SYSC_CFGA_CMD_QUIESCE_TEST:
case SYSC_CFGA_CMD_TEST:
return (0);
case OPROMGETOPT:
return (ioctl(fd, OPROMGETOPT, a));
case OPROMSETOPT:
return (ioctl(fd, OPROMSETOPT, a));
}
if (lseek(sim_fd, SEEK_SET, 0) == -1) {
perror("sim_seek");
exit(1);
}
if (write(sim_fd, sim_sc_list, sim_size) == -1) {
perror("sim_write");
exit(1);
}
return (0);
}
#define open(a, b, c) sim_open((char *)(a), (int)(b), (int)(c))
#define close(a) sim_close(a)
#define ioctl(a, b, c) sim_ioctl((int)(a), (int)(b), (void *)(c))
#define sysc_stat(a, b) sim_sysc_stat(a, b)
#endif
static char *promdev = "/dev/openprom";
static char *dlprop = "disabled-board-list";
#define BUFSIZE 128
typedef union {
char buf[BUFSIZE];
struct openpromio opp;
} oppbuf_t;
static int
prom_get_prop(int prom_fd, char *var, char **val)
{
static oppbuf_t oppbuf;
struct openpromio *opp = &(oppbuf.opp);
(void) strncpy(opp->oprom_array, var, OBP_MAXPROPNAME);
opp->oprom_array[OBP_MAXPROPNAME + 1] = '\0';
opp->oprom_size = BUFSIZE;
DBG3("getprop(%s, %d)\n", opp->oprom_array, opp->oprom_size);
if (ioctl(prom_fd, OPROMGETOPT, opp) < 0)
return (ERR_PROM_GETPROP);
else if (opp->oprom_size > 0)
*val = opp->oprom_array;
else
*val = NULL;
return (0);
}
static cfga_err_t
prom_set_prop(int prom_fd, char *var, char *val)
{
oppbuf_t oppbuf;
struct openpromio *opp = &(oppbuf.opp);
int varlen = strlen(var) + 1;
int vallen = strlen(val);
DBG("prom_set_prop(%s)\n", val);
(void) strcpy(opp->oprom_array, var);
(void) strcpy(opp->oprom_array + varlen, val);
opp->oprom_size = varlen + vallen;
if (ioctl(prom_fd, OPROMSETOPT, opp) < 0)
return (ERR_PROM_SETPROP);
return (0);
}
static int
dlist_find(int board, char **dlist, int *disabled)
{
int i;
int err;
int prom_fd;
char *p;
char *dl;
char b[2];
if ((prom_fd = open(promdev, O_RDWR, 0)) < 0)
return (ERR_PROM_OPEN);
else if (err = prom_get_prop(prom_fd, dlprop, dlist)) {
(void) close(prom_fd);
return (err);
} else
(void) close(prom_fd);
b[1] = 0;
*disabled = 0;
if ((dl = *dlist) != NULL) {
int len = strlen(dl);
for (i = 0; i < len; i++) {
int bd;
b[0] = dl[i];
bd = strtol(b, &p, 16);
if (p != b && bd == board)
(*disabled)++;
}
}
return (0);
}
static int
dlist_update(int board, int disable, char *dlist, struct cfga_msg *msgp,
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;
if ((prom_fd = open(promdev, O_RDWR, 0)) < 0)
return (ERR_PROM_OPEN);
if (dlist) {
int len = strlen(dlist);
for (i = 0; i < len; i++) {
int bd;
b[0] = dlist[i];
bd = strtol(b, &p, 16);
if (p != b && bd == board) {
found++;
if (disable) {
if (verbose)
cfga_msg(msgp, STR_BD,
DIAG_WAS_DISABLED, 0);
} else {
if (verbose)
cfga_msg(msgp, STR_BD,
DIAG_WILL_ENABLE, 0);
update++;
continue;
}
}
ndlist[j++] = dlist[i];
}
ndlist[j] = 0;
}
if (!found)
if (disable) {
if (verbose)
cfga_msg(msgp, STR_BD, DIAG_WILL_DISABLE, 0);
p = &ndlist[j];
n = sprintf(p, "%x", board);
p[n] = 0;
update++;
} else {
if (verbose)
cfga_msg(msgp, STR_BD, DIAG_WAS_ENABLED, 0);
}
if (update)
err = prom_set_prop(prom_fd, dlprop, ndlist);
else
err = 0;
(void) close(prom_fd);
return (err);
}
static int
ap_idx(const char *ap_id)
{
int id;
char *s;
static char *slot = "slot";
DBG("ap_idx(%s)\n", ap_id);
if ((s = strstr(ap_id, slot)) == NULL)
return (-1);
else {
int n;
s += strlen(slot);
n = strlen(s);
DBG3("ap_idx: s=%s, n=%d\n", s, n);
switch (n) {
case 2:
if (!isdigit(s[1]))
return (-1);
case 1:
if (!isdigit(s[0]))
return (-1);
break;
default:
return (-1);
}
}
if ((id = atoi(s)) > MAX_BOARDS)
return (-1);
DBG3("ap_idx(%s)=%d\n", s, id);
return (id);
}
cfga_err_t
cfga_change_state(
cfga_cmd_t state_change_cmd,
const char *ap_id,
const char *options,
struct cfga_confirm *confp,
struct cfga_msg *msgp,
char **errstring,
cfga_flags_t flags)
{
int fd;
int idx;
int err;
int force;
int verbose;
int opterr;
int disable;
int disabled;
cfga_err_t rc;
sysc_cfga_stat_t *ss;
sysc_cfga_cmd_t *sc, sysc_cmd;
sysc_cfga_rstate_t rs;
sysc_cfga_ostate_t os;
char *dlist;
char outputstr[SYSC_OUTPUT_LEN];
if (errstring != NULL)
*errstring = NULL;
rc = CFGA_ERROR;
if (options) {
disable = 0;
if (strcmp(options, cfga_str(OPT_DISABLE)) == 0)
disable++;
else if (strcmp(options, cfga_str(OPT_ENABLE))) {
cfga_err(NULL, errstring, ERR_OPT_INVAL, options, 0);
return (rc);
}
}
if ((idx = ap_idx(ap_id)) == -1) {
cfga_err(NULL, errstring, ERR_AP_INVAL, ap_id, 0);
return (rc);
} else if ((ss = sysc_stat(ap_id, &fd)) == NULL) {
cfga_err(NULL, errstring, CMD_GETSTAT, 0);
return (rc);
}
#ifdef SIM
sim_idx = idx;
#endif
if (opterr = dlist_find(idx, &dlist, &disabled)) {
err = disable ? OPT_DISABLE : OPT_ENABLE;
cfga_err(NULL, errstring, err, opterr, 0);
(void) close(fd);
return (rc);
} else
force = flags & CFGA_FLAG_FORCE;
rs = ss[idx].rstate;
os = ss[idx].ostate;
sc = &sysc_cmd;
sysc_cmd_init(sc, outputstr, force);
verbose = flags & CFGA_FLAG_VERBOSE;
switch (state_change_cmd) {
case CFGA_CMD_CONNECT:
if (rs != SYSC_CFGA_RSTATE_DISCONNECTED)
cfga_err(NULL, errstring, ERR_TRANS, 0);
else if (disabled && !(force || (options && !disable)))
cfga_err(NULL, errstring, CMD_CONNECT,
ERR_DISABLED, DIAG_FORCE, 0);
else if (!(*confp->confirm)(confp->appdata_ptr,
cfga_str(ASK_CONNECT))) {
(void) close(fd);
return (CFGA_NACK);
} else if (ioctl(fd, SYSC_CFGA_CMD_CONNECT, sc) == -1)
cfga_err(sc, errstring, CMD_CONNECT, 0);
else if (options && (opterr = dlist_update(idx, disable,
dlist, msgp, verbose))) {
err = disable ? OPT_DISABLE : OPT_ENABLE;
cfga_err(NULL, errstring, err, opterr, 0);
} else
rc = CFGA_OK;
break;
case CFGA_CMD_DISCONNECT:
if ((os == SYSC_CFGA_OSTATE_CONFIGURED) &&
(ioctl(fd, SYSC_CFGA_CMD_UNCONFIGURE, sc) == -1)) {
cfga_err(sc, errstring, CMD_UNCONFIGURE, 0);
(void) close(fd);
return (CFGA_ERROR);
} else
sysc_cmd_init(sc, outputstr, force);
if (rs == SYSC_CFGA_RSTATE_CONNECTED) {
if (ioctl(fd, SYSC_CFGA_CMD_DISCONNECT, sc) == -1)
cfga_err(sc, errstring, CMD_DISCONNECT, 0);
else if (options && (opterr = dlist_update(idx, disable,
dlist, msgp, verbose))) {
err = disable ? OPT_DISABLE : OPT_ENABLE;
cfga_err(NULL, errstring, err, opterr, 0);
} else
rc = CFGA_OK;
} else
cfga_err(NULL, errstring, ERR_TRANS, 0);
break;
case CFGA_CMD_CONFIGURE:
if (rs == SYSC_CFGA_RSTATE_DISCONNECTED)
if (disabled && !(force || (options && !disable))) {
cfga_err(NULL, errstring, CMD_CONFIGURE,
ERR_DISABLED, DIAG_FORCE, 0);
(void) close(fd);
return (CFGA_ERROR);
} else if (!(*confp->confirm)(confp->appdata_ptr,
cfga_str(ASK_CONNECT))) {
(void) close(fd);
return (CFGA_NACK);
} else if (ioctl(fd, SYSC_CFGA_CMD_CONNECT, sc) == -1) {
cfga_err(sc, errstring, CMD_CONNECT, 0);
(void) close(fd);
return (CFGA_ERROR);
} else
sysc_cmd_init(sc, outputstr, force);
if (os == SYSC_CFGA_OSTATE_UNCONFIGURED) {
if (ioctl(fd, SYSC_CFGA_CMD_CONFIGURE, sc) == -1)
cfga_err(sc, errstring, CMD_CONFIGURE, 0);
else if (options && (opterr = dlist_update(idx,
disable, dlist, msgp, verbose))) {
err = disable ? OPT_DISABLE : OPT_ENABLE;
cfga_err(NULL, errstring, err, opterr, 0);
} else
rc = CFGA_OK;
} else
cfga_err(NULL, errstring, ERR_TRANS, 0);
break;
case CFGA_CMD_UNCONFIGURE:
if (os != SYSC_CFGA_OSTATE_CONFIGURED)
cfga_err(NULL, errstring, ERR_TRANS, 0);
else if (ioctl(fd, SYSC_CFGA_CMD_UNCONFIGURE, sc) == -1)
cfga_err(sc, errstring, CMD_UNCONFIGURE, 0);
else if (options && (opterr = dlist_update(idx, disable,
dlist, msgp, verbose))) {
err = disable ? OPT_DISABLE : OPT_ENABLE;
cfga_err(NULL, errstring, err, opterr, 0);
} else
rc = CFGA_OK;
break;
default:
rc = CFGA_OPNOTSUPP;
break;
}
(void) close(fd);
return (rc);
}
static int
str2cond(const char *cond)
{
int c;
if (strcmp(cond, cfga_str(COND_UNKNOWN)) == 0)
c = SYSC_CFGA_COND_UNKNOWN;
else if (strcmp(cond, cfga_str(COND_OK)) == 0)
c = SYSC_CFGA_COND_OK;
else if (strcmp(cond, cfga_str(COND_FAILING)) == 0)
c = SYSC_CFGA_COND_FAILING;
else if (strcmp(cond, cfga_str(COND_FAILED)) == 0)
c = SYSC_CFGA_COND_FAILED;
else if (strcmp(cond, cfga_str(COND_UNUSABLE)) == 0)
c = SYSC_CFGA_COND_UNUSABLE;
else
c = -1;
return (c);
}
cfga_err_t
cfga_private_func(
const char *function,
const char *ap_id,
const char *options,
struct cfga_confirm *confp,
struct cfga_msg *msgp,
char **errstring,
cfga_flags_t flags)
{
int fd;
int idx;
int len;
int cmd;
int cond;
int err;
int opterr;
int verbose;
int disable;
int disabled;
cfga_err_t rc;
char *str;
char *dlist;
char outputstr[SYSC_OUTPUT_LEN];
sysc_cfga_cmd_t *sc, sysc_cmd;
if (errstring != NULL)
*errstring = NULL;
verbose = flags & CFGA_FLAG_VERBOSE;
rc = CFGA_ERROR;
if (options) {
disable = 0;
if (strcmp(options, cfga_str(OPT_DISABLE)) == 0)
disable++;
else if (strcmp(options, cfga_str(OPT_ENABLE))) {
cfga_err(NULL, errstring, ERR_OPT_INVAL, options, 0);
return (rc);
}
}
sc = &sysc_cmd;
str = cfga_str(CMD_SET_COND);
len = strlen(str);
if ((strncmp(function, str, len) == 0) && (function[len++] == '=') &&
((cond = (str2cond(&function[len]))) != -1)) {
cmd = SYSC_CFGA_CMD_TEST_SET_COND;
err = CMD_SET_COND;
sc->arg = cond;
} else if (strcmp(function, cfga_str(CMD_QUIESCE)) == 0) {
cmd = SYSC_CFGA_CMD_QUIESCE_TEST;
err = CMD_QUIESCE;
} else if (strcmp(function, cfga_str(CMD_INSERT)) == 0) {
cmd = SYSC_CFGA_CMD_TEST;
err = CMD_INSERT;
} else if (strcmp(function, cfga_str(CMD_REMOVE)) == 0) {
cmd = SYSC_CFGA_CMD_TEST;
err = CMD_REMOVE;
} else {
cfga_err(NULL, errstring, ERR_CMD_INVAL, (char *)function, 0);
return (rc);
}
sysc_cmd_init(sc, outputstr, 0);
if ((idx = ap_idx(ap_id)) == -1)
cfga_err(NULL, errstring, ERR_AP_INVAL, ap_id, 0);
else if (((fd = open(ap_id, O_RDWR, 0)) == -1) ||
(ioctl(fd, cmd, sc) == -1))
cfga_err(NULL, errstring, err, 0);
else
rc = CFGA_OK;
if (options) {
opterr = (dlist_find(idx, &dlist, &disabled) ||
dlist_update(idx, disable, dlist, msgp, verbose));
if (opterr) {
err = disable ? OPT_DISABLE : OPT_ENABLE;
if (verbose)
cfga_msg(msgp, err, opterr, 0);
}
}
(void) close(fd);
return (rc);
}
cfga_err_t
cfga_test(
const char *ap_id,
const char *options,
struct cfga_msg *msgp,
char **errstring,
cfga_flags_t flags)
{
if (errstring != NULL)
*errstring = NULL;
return (CFGA_OPNOTSUPP);
}
static cfga_stat_t
rstate_cvt(sysc_cfga_rstate_t rs)
{
cfga_stat_t cs;
switch (rs) {
case SYSC_CFGA_RSTATE_EMPTY:
cs = CFGA_STAT_EMPTY;
break;
case SYSC_CFGA_RSTATE_DISCONNECTED:
cs = CFGA_STAT_DISCONNECTED;
break;
case SYSC_CFGA_RSTATE_CONNECTED:
cs = CFGA_STAT_CONNECTED;
break;
default:
cs = CFGA_STAT_NONE;
break;
}
return (cs);
}
static cfga_stat_t
ostate_cvt(sysc_cfga_ostate_t os)
{
cfga_stat_t cs;
switch (os) {
case SYSC_CFGA_OSTATE_UNCONFIGURED:
cs = CFGA_STAT_UNCONFIGURED;
break;
case SYSC_CFGA_OSTATE_CONFIGURED:
cs = CFGA_STAT_CONFIGURED;
break;
default:
cs = CFGA_STAT_NONE;
break;
}
return (cs);
}
static cfga_cond_t
cond_cvt(sysc_cfga_cond_t sc)
{
cfga_cond_t cc;
switch (sc) {
case SYSC_CFGA_COND_OK:
cc = CFGA_COND_OK;
break;
case SYSC_CFGA_COND_FAILING:
cc = CFGA_COND_FAILING;
break;
case SYSC_CFGA_COND_FAILED:
cc = CFGA_COND_FAILED;
break;
case SYSC_CFGA_COND_UNUSABLE:
cc = CFGA_COND_UNUSABLE;
break;
case SYSC_CFGA_COND_UNKNOWN:
default:
cc = CFGA_COND_UNKNOWN;
break;
}
return (cc);
}
static char *
type_str(enum board_type type)
{
char *type_str;
switch (type) {
case MEM_BOARD:
type_str = cfga_str(BD_MEM);
break;
case CPU_BOARD:
type_str = cfga_str(BD_CPU);
break;
case IO_2SBUS_BOARD:
type_str = cfga_str(BD_IO_2SBUS);
break;
case IO_SBUS_FFB_BOARD:
type_str = cfga_str(BD_IO_SBUS_FFB);
break;
case IO_PCI_BOARD:
type_str = cfga_str(BD_IO_PCI);
break;
case DISK_BOARD:
type_str = cfga_str(BD_DISK);
break;
case IO_2SBUS_SOCPLUS_BOARD:
type_str = cfga_str(BD_IO_2SBUS_SOCPLUS);
break;
case IO_SBUS_FFB_SOCPLUS_BOARD:
type_str = cfga_str(BD_IO_SBUS_FFB_SOCPLUS);
break;
case UNKNOWN_BOARD:
default:
type_str = cfga_str(BD_UNKNOWN);
break;
}
return (type_str);
}
static void
info_set(sysc_cfga_stat_t *sc, cfga_info_t info, int disabled)
{
int i;
struct cpu_info *cpu;
union bd_un *bd = &sc->bd;
*info = '\0';
switch (sc->type) {
case CPU_BOARD:
for (i = 0, cpu = bd->cpu; i < 2; i++, cpu++) {
if (cpu->cpu_speed > 1) {
info += sprintf(info, "cpu %d: ", i);
info += sprintf(info, "%3d MHz ",
cpu->cpu_speed);
if (cpu->cache_size)
info += sprintf(info, "%0.1fM ",
(float)cpu->cache_size /
(float)(1024 * 1024));
}
}
break;
case IO_SBUS_FFB_BOARD:
switch (bd->io2.ffb_size) {
case FFB_SINGLE:
info += sprintf(info, "single buffered ffb ");
break;
case FFB_DOUBLE:
info += sprintf(info, "double buffered ffb ");
break;
case FFB_NOT_FOUND:
#ifdef FFB_DR_SUPPORT
info += sprintf(info, "no ffb installed ");
#endif
break;
default:
info += sprintf(info, "illegal ffb size ");
break;
}
break;
case DISK_BOARD:
for (i = 0; i < 2; i++)
if (bd->dsk.disk_pres[i])
info += sprintf(info, "target: %2d ",
bd->dsk.disk_id[i]);
else
info += sprintf(info, "no disk ");
break;
}
if (disabled)
info += sprintf(info, "disabled at boot ");
if (sc->no_detach)
info += sprintf(info, "non-detachable ");
if (sc->plus_board)
info += sprintf(info, "100 MHz capable ");
}
static void
sysc_cvt(sysc_cfga_stat_t *sc, cfga_stat_data_t *cs, int disabled)
{
(void) strcpy(cs->ap_type, type_str(sc->type));
cs->ap_r_state = rstate_cvt(sc->rstate);
cs->ap_o_state = ostate_cvt(sc->ostate);
cs->ap_cond = cond_cvt(sc->condition);
cs->ap_busy = (cfga_busy_t)sc->in_transition;
cs->ap_status_time = sc->last_change;
info_set(sc, cs->ap_info, disabled);
cs->ap_log_id[0] = '\0';
cs->ap_phys_id[0] = '\0';
}
cfga_err_t
cfga_list(
const char *ap_id,
cfga_stat_data_t **ap_list,
int *nlist,
const char *options,
char **errstring)
{
int i;
cfga_err_t rc;
sysc_cfga_stat_t *sc;
cfga_stat_data_t *cs;
if (errstring != NULL)
*errstring = NULL;
rc = CFGA_ERROR;
if (ap_idx(ap_id) == -1)
cfga_err(NULL, errstring, ERR_AP_INVAL, ap_id, 0);
else if ((sc = sysc_stat(ap_id, NULL)) == NULL)
cfga_err(NULL, errstring, CMD_LIST, 0);
else if (!(cs = (cfga_stat_data_t *)malloc(MAX_BOARDS * sizeof (*cs))))
cfga_err(NULL, errstring, CMD_LIST, 0);
else {
*ap_list = cs;
for (*nlist = 0, i = 0; i < MAX_BOARDS; i++, sc++) {
if (sc->board == -1)
continue;
sysc_cvt(sc, cs++, 0);
(*nlist)++;
}
rc = CFGA_OK;
}
return (rc);
}
cfga_err_t
cfga_stat(
const char *ap_id,
struct cfga_stat_data *cs,
const char *options,
char **errstring)
{
cfga_err_t rc;
int idx;
int err;
int opterr;
int disable;
int disabled;
char *dlist;
sysc_cfga_stat_t *sc;
if (errstring != NULL)
*errstring = NULL;
rc = CFGA_ERROR;
if (options && options[0]) {
disable = 0;
if (strcmp(options, cfga_str(OPT_DISABLE)) == 0)
disable++;
else if (strcmp(options, cfga_str(OPT_ENABLE))) {
cfga_err(NULL, errstring, ERR_OPT_INVAL, options, 0);
return (rc);
}
}
if ((idx = ap_idx(ap_id)) == -1)
cfga_err(NULL, errstring, ERR_AP_INVAL, ap_id, 0);
else if ((sc = sysc_stat(ap_id, NULL)) == NULL)
cfga_err(NULL, errstring, CMD_GETSTAT, 0);
else {
opterr = dlist_find(idx, &dlist, &disabled);
sysc_cvt(sc + idx, cs, disabled);
rc = CFGA_OK;
if (options && options[0] && ((opterr != 0) ||
((opterr = dlist_update(idx, disable, dlist, NULL, 0))
!= 0))) {
err = disable ? OPT_DISABLE : OPT_ENABLE;
cfga_err(NULL, errstring, err, opterr, 0);
}
}
return (rc);
}
cfga_err_t
cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
{
int help = 0;
if (options) {
if (strcmp(options, cfga_str(OPT_DISABLE)) == 0)
help = HELP_DISABLE;
else if (strcmp(options, cfga_str(OPT_ENABLE)) == 0)
help = HELP_ENABLE;
else if (strcmp(options, cfga_str(CMD_INSERT)) == 0)
help = HELP_INSERT;
else if (strcmp(options, cfga_str(CMD_REMOVE)) == 0)
help = HELP_REMOVE;
else if (strcmp(options, cfga_str(CMD_QUIESCE)) == 0)
help = HELP_QUIESCE;
else
help = HELP_UNKNOWN;
}
if (help) {
if (help == HELP_UNKNOWN)
cfga_msg(msgp, help, options, 0);
else
cfga_msg(msgp, help, 0);
} else {
cfga_msg(msgp, HELP_HEADER, 0);
cfga_msg(msgp, HELP_DISABLE, 0);
cfga_msg(msgp, HELP_ENABLE, 0);
cfga_msg(msgp, HELP_INSERT, 0);
cfga_msg(msgp, HELP_REMOVE, 0);
cfga_msg(msgp, HELP_QUIESCE, 0);
cfga_msg(msgp, HELP_SET_COND, 0);
}
return (CFGA_OK);
}