2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <assert.h>
2N/A#include <ctype.h>
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <string.h>
2N/A#include <unistd.h>
2N/A#include <macros.h>
2N/A#include <dirent.h>
2N/A#include <libgen.h>
2N/A#include <libdevinfo.h>
2N/A#define CFGA_PLUGIN_LIB
2N/A#include <config_admin.h>
2N/A#include "ap.h"
2N/A
2N/A/*ARGSUSED0*/
2N/Aint
2N/Aap_symid(apd_t *a, char *apid, char *symid, size_t bufsize)
2N/A{
2N/A int n;
2N/A int rc;
2N/A char path[MAXPATHLEN];
2N/A char *p;
2N/A DIR *dirp;
2N/A struct dirent *dp;
2N/A
2N/A *symid = '\0';
2N/A n = sprintf(path, "/dev/cfg/");
2N/A rc = -1;
2N/A
2N/A if ((dirp = opendir(path)) == NULL)
2N/A return (rc);
2N/A
2N/A p = path + n;
2N/A
2N/A while ((dp = readdir(dirp)) != NULL) {
2N/A char buf[MAXPATHLEN];
2N/A char *cp;
2N/A size_t len;
2N/A
2N/A *p = '\0';
2N/A (void) strcat(path, dp->d_name);
2N/A if ((len = readlink(path, buf, sizeof (buf))) == (size_t)-1)
2N/A continue;
2N/A buf[len] = '\0';
2N/A
2N/A len = strlen("../");
2N/A cp = buf;
2N/A while (strncmp(cp, "../", len) == 0)
2N/A cp += len;
2N/A if (cp != buf)
2N/A cp--; /* Get the '/' */
2N/A
2N/A if (strcmp(cp, apid) == 0) {
2N/A (void) snprintf(symid, bufsize, "%s", dp->d_name);
2N/A rc = 0;
2N/A break;
2N/A }
2N/A }
2N/A
2N/A (void) closedir(dirp);
2N/A return (rc);
2N/A}
2N/A
2N/Achar *
2N/Aap_logid(apd_t *a, char *apid)
2N/A{
2N/A int n;
2N/A char *buf;
2N/A
2N/A if ((buf = calloc(1, MAXPATHLEN)) == NULL)
2N/A return (NULL);
2N/A
2N/A /*
2N/A * Look for a symlink. On any error, fallback to
2N/A * driver and instance based logical ap_ids.
2N/A */
2N/A if (ap_symid(a, apid, buf, MAXPATHLEN) == 0)
2N/A n = strlen(buf);
2N/A else
2N/A n = snprintf(buf, MAXPATHLEN, "%s%d:%s",
2N/A a->drv, a->inst, a->minor);
2N/A /*
2N/A * Append the dynamic portion, if any.
2N/A */
2N/A if (a->cid != NULL)
2N/A (void) snprintf(&buf[n], MAXPATHLEN - n, "::%s", a->cid);
2N/A
2N/A return (buf);
2N/A}
2N/A
2N/Aint
2N/Aap_parse(apd_t *a, const char *ap_id)
2N/A{
2N/A int i;
2N/A int rc;
2N/A int phys;
2N/A char c;
2N/A char *s;
2N/A char *p;
2N/A char *q;
2N/A char *base;
2N/A int len;
2N/A char *t;
2N/A
2N/A if (a == NULL)
2N/A return (-1);
2N/A
2N/A a->cnum = -1;
2N/A a->bnum = -1;
2N/A a->inst = -1;
2N/A a->apid = ap_id;
2N/A rc = ERR_NONE;
2N/A
2N/A if (!str_valid(ap_id)) {
2N/A rc = ERR_AP_INVAL;
2N/A goto done;
2N/A }
2N/A
2N/A if ((a->path = strdup(ap_id)) == NULL) {
2N/A rc = ERR_NOMEM;
2N/A goto done;
2N/A }
2N/A
2N/A /*
2N/A * For a physical ap_id, look only at the base part.
2N/A * For a logical/symbolic one, use the entire ap_id.
2N/A */
2N/A if (strncmp(a->path, DEVDIR, strlen(DEVDIR)) == 0) {
2N/A phys = 1;
2N/A base = strrchr((const char *)a->path, '/') + 1;
2N/A } else {
2N/A phys = 0;
2N/A base = a->path;
2N/A if ((a->target = strdup(a->path)) == NULL) {
2N/A rc = ERR_NOMEM;
2N/A goto done;
2N/A }
2N/A }
2N/A
2N/A if ((s = strchr(base, ':')) == NULL || s[1] == ':') {
2N/A /*
2N/A * No ':' found, or got a '::'. If this is a physical
2N/A * ap_id, it must have a minor separtor ':' which must
2N/A * appear before the dynamic part (starting with '::').
2N/A * For a symbolic ap_id, skip looking for driver/minor
2N/A * names.
2N/A */
2N/A if (phys) {
2N/A rc = ERR_AP_INVAL;
2N/A goto done;
2N/A } else
2N/A s = base;
2N/A } else {
2N/A /*
2N/A * Look for driver name/instance only up to the first ':',
2N/A * i.e. up to the minor node name.
2N/A */
2N/A *s = '\0';
2N/A
2N/A if ((p = strchr(base, '@')) != NULL) {
2N/A /*
2N/A * Get the driver name/instance.
2N/A */
2N/A *p = '\0';
2N/A if ((a->drv = strdup(base)) == NULL) {
2N/A rc = ERR_NOMEM;
2N/A goto done;
2N/A }
2N/A *p++ = '@';
2N/A
2N/A i = strtol(p, &q, 10);
2N/A if (q > p)
2N/A a->inst = i;
2N/A }
2N/A
2N/A *s++ = ':';
2N/A a->minor = s;
2N/A }
2N/A
2N/A /*
2N/A * Need to go to the end of the string before the :: if any
2N/A * If the string is null then we are done
2N/A */
2N/A t = strstr(s, "::");
2N/A if (t != NULL)
2N/A len = strlen(t);
2N/A else
2N/A len = 0;
2N/A
2N/A s += (strlen(s) - len);
2N/A
2N/A p = s;
2N/A
2N/A if (*p == '\0')
2N/A a->tgt = AP_BOARD;
2N/A else if (strncmp(p, "::", 2) != 0) {
2N/A rc = ERR_AP_INVAL;
2N/A goto done;
2N/A } else {
2N/A /*
2N/A * Save the component id.
2N/A */
2N/A *p++ = '\0';
2N/A *p++ = '\0';
2N/A a->cid = p;
2N/A }
2N/A
2N/A /*
2N/A * Get the operation target, e.g. slot0, slot0::cpu0.
2N/A * At this point, a->path points to the /devices path
2N/A * minus the dynamic part, for a physical ap_id. In
2N/A * the case of a logical ap_id, the target is already
2N/A * initialized above.
2N/A */
2N/A if (phys != 0 && (a->target = ap_logid(a, a->path)) == NULL) {
2N/A rc = ERR_NOMEM;
2N/A goto done;
2N/A }
2N/A
2N/A if (a->tgt == AP_BOARD)
2N/A goto done;
2N/A
2N/A while ((*p != '\0') && !isdigit(*p))
2N/A p++;
2N/A
2N/A /*
2N/A * Get the component unit number, if present.
2N/A */
2N/A i = strtol(p, &s, 10);
2N/A /*
2N/A * There must be no characters after the unit number.
2N/A */
2N/A if (*s != '\0') {
2N/A rc = ERR_CM_INVAL;
2N/A goto done;
2N/A }
2N/A if (s > p) {
2N/A /*
2N/A * Disallow leading zeroes, e.g. cpu00, cpu01, cpu001.
2N/A * If there are 2 or more digits and the first is a zero,
2N/A * we fail.
2N/A */
2N/A if ((s-p) >= 2 && *p == '0') {
2N/A rc = ERR_CM_INVAL;
2N/A goto done;
2N/A }
2N/A a->cnum = i;
2N/A }
2N/A
2N/A c = *p;
2N/A *p = '\0';
2N/A if ((a->cname = strdup(a->cid)) == NULL)
2N/A rc = ERR_NOMEM;
2N/A *p = c;
2N/Adone:
2N/A switch (rc) {
2N/A case ERR_NONE:
2N/A break;
2N/A case ERR_CM_INVAL:
2N/A ap_err(a, ERR_CM_INVAL, a->cid);
2N/A break;
2N/A default:
2N/A ap_err(a, rc);
2N/A break;
2N/A }
2N/A
2N/A DBG("path=<%s> ", a->path ? a->path : "");
2N/A DBG("drv=<%s> inst=%d minor=<%s> ",
2N/A a->drv ? a->drv : "", a->inst, a->minor ? a->minor : "");
2N/A DBG("target=<%s>\n", a->target ? a->target : "");
2N/A DBG("cid=<%s> ", a->cid ? a->cid : "");
2N/A DBG("cname=<%s> ", a->cname ? a->cname : "");
2N/A DBG("cnum=%d\n", a->cnum);
2N/A DBG("tgt=%d opts=%x\n", a->tgt, a->opts.flags);
2N/A
2N/A return (rc == ERR_NONE? 0 : -1);
2N/A}
2N/A
2N/A/*
2N/A * Command table.
2N/A *
2N/A * The first set of commands in the table are in sequencing order,
2N/A * for example, the first group starts with assign and ends with
2N/A * configure. command sequencer relies on this ordering.
2N/A */
2N/Astatic char *
2N/Aap_cmd_names[] = {
2N/A "assign",
2N/A "poweron",
2N/A "test",
2N/A "connect",
2N/A "configure",
2N/A "notify online",
2N/A "notify add capacity",
2N/A "suspend check",
2N/A "request suspend",
2N/A "request delete capacity",
2N/A "request offline",
2N/A "unconfigure",
2N/A "notify remove",
2N/A "notify capacity change",
2N/A "disconnect",
2N/A "poweroff",
2N/A "unassign",
2N/A "notify resume",
2N/A "status",
2N/A "getncm",
2N/A "passthru",
2N/A "help",
2N/A "errtest",
2N/A NULL
2N/A};
2N/A
2N/Achar *
2N/Aap_cmd_name(int i)
2N/A{
2N/A return (ap_cmd_names[min(i, CMD_NONE)]);
2N/A}
2N/A
2N/Astatic char *
2N/Aap_opt_names[] = {
2N/A "unassign",
2N/A "skip",
2N/A "parsable",
2N/A "nopoweroff",
2N/A "code",
2N/A "mid",
2N/A "err",
2N/A "platform",
2N/A "sim",
2N/A NULL
2N/A};
2N/A
2N/Achar *
2N/Aap_opt_name(int i)
2N/A{
2N/A return (ap_opt_names[i]);
2N/A}
2N/A
2N/A/*
2N/A * Command descriptor.
2N/A *
2N/A * Each command has a (command) mask specifying the AP target classes
2N/A * it operates on, e.g. the assign command applies only to boards.
2N/A * In addition each AP target class has a separate option mask specifying
2N/A * which command options are valid for that target class.
2N/A * A global value mask specifies which options require values.
2N/A */
2N/Atypedef struct {
2N/A int cmd;
2N/A uint_t cmask;
2N/A uint_t omask[AP_NCLASS];
2N/A} ap_cmd_t;
2N/A
2N/A/*
2N/A * Command option definitions.
2N/A */
2N/A#define SHFT(i) ((uint_t)1 << (i))
2N/A#define NULOPT 0
2N/A#define ALLOPT 0xffffffff
2N/A#define CMNOPT (SHFT(OPT_VERBOSE)|SHFT(OPT_PLATFORM)|SHFT(OPT_SIM))
2N/A#define CMFOPT (CMNOPT|SHFT(OPT_FORCE))
2N/A#define STSOPT (CMNOPT|SHFT(OPT_PARSABLE))
2N/A#define BRDDCN (CMNOPT|SHFT(OPT_UNASSIGN)|SHFT(OPT_NOPOWEROFF))
2N/A
2N/A#define BRD SHFT(AP_BOARD)
2N/A#define BIO SHFT(AP_BOARD)|SHFT(AP_IO)
2N/A#define ALL (BRD|SHFT(AP_CPU)|SHFT(AP_MEM)|SHFT(AP_IO)|SHFT(AP_CMP))
2N/A
2N/Astatic ap_cmd_t
2N/Aap_cmds[] = {
2N/A /*
2N/A * cmd cmd board cpu mem io cmp
2N/A * cmask omask omask omask omask omask
2N/A */
2N/A {CMD_ASSIGN, BRD, 0, CMNOPT, NULOPT, NULOPT, NULOPT, NULOPT},
2N/A {CMD_UNASSIGN, BRD, 0, CMNOPT, NULOPT, NULOPT, NULOPT, NULOPT},
2N/A {CMD_POWERON, BRD, 0, CMNOPT, NULOPT, NULOPT, NULOPT, NULOPT},
2N/A {CMD_POWEROFF, BRD, 0, CMNOPT, NULOPT, NULOPT, NULOPT, NULOPT},
2N/A {CMD_CONNECT, BRD, 0, CMFOPT, NULOPT, NULOPT, NULOPT, NULOPT},
2N/A {CMD_DISCONNECT, BRD, 0, BRDDCN, NULOPT, NULOPT, NULOPT, NULOPT},
2N/A {CMD_CONFIGURE, ALL, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
2N/A {CMD_UNCONFIGURE, ALL, 0, CMFOPT, CMFOPT, CMFOPT, CMFOPT, CMNOPT},
2N/A {CMD_RCM_OFFLINE, BIO, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
2N/A {CMD_RCM_ONLINE, BIO, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
2N/A {CMD_RCM_SUSPEND, BIO, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
2N/A {CMD_RCM_RESUME, BIO, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
2N/A {CMD_RCM_CAP_ADD, BIO, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
2N/A {CMD_RCM_CAP_DEL, BIO, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
2N/A {CMD_RCM_CAP_NOTIFY, BIO, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
2N/A {CMD_RCM_REMOVE, BIO, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
2N/A {CMD_TEST, BRD, 0, CMFOPT, NULOPT, NULOPT, NULOPT, NULOPT},
2N/A {CMD_STATUS, ALL, 0, STSOPT, STSOPT, STSOPT, STSOPT, STSOPT},
2N/A {CMD_GETNCM, BRD, 0, CMNOPT, NULOPT, NULOPT, NULOPT, NULOPT},
2N/A {CMD_PASSTHRU, ALL, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
2N/A {CMD_HELP, ALL, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
2N/A {CMD_ERRTEST, ALL, 0, ALLOPT, ALLOPT, ALLOPT, ALLOPT, ALLOPT},
2N/A {CMD_NONE, 0, 0, 0, 0, 0, 0, 0 }
2N/A};
2N/A
2N/A/*
2N/A * Global mask for options that require values.
2N/A */
2N/A#define AP_VMASK (\
2N/A SHFT(OPT_CODE)|SHFT(OPT_MID)|SHFT(OPT_ERR)| \
2N/A SHFT(OPT_PLATFORM)|SHFT(OPT_SKIP))
2N/A
2N/A#if SBD_DEBUG
2N/Avoid
2N/Aap_cmds_dump()
2N/A{
2N/A int i;
2N/A ap_cmd_t *acp;
2N/A
2N/A dbg("vmask=0x%x\n", AP_VMASK);
2N/A dbg("%23s%5s%5s%9s%9s%9s%9s%9s\n",
2N/A "cmd", "msk", "none", "brd", "cpu", "mem", "io", "cmp");
2N/A
2N/A for (acp = ap_cmds; acp->cmd != CMD_NONE; acp++) {
2N/A dbg("%23s%5x%5x", ap_cmd_name(acp->cmd), acp->cmask,
2N/A acp->omask[AP_NONE]);
2N/A for (i = AP_BOARD; i < AP_NCLASS; i++) {
2N/A dbg("%9x", acp->omask[i]);
2N/A }
2N/A dbg("\n");
2N/A }
2N/A}
2N/A#endif
2N/A
2N/Aint
2N/Aap_state_cmd(cfga_cmd_t i, int *cmd)
2N/A{
2N/A int c;
2N/A int rc;
2N/A
2N/A rc = CFGA_OK;
2N/A
2N/A switch (i) {
2N/A case CFGA_CMD_CONNECT:
2N/A c = CMD_CONNECT;
2N/A break;
2N/A case CFGA_CMD_DISCONNECT:
2N/A c = CMD_DISCONNECT;
2N/A break;
2N/A case CFGA_CMD_CONFIGURE:
2N/A c = CMD_CONFIGURE;
2N/A break;
2N/A case CFGA_CMD_UNCONFIGURE:
2N/A c = CMD_UNCONFIGURE;
2N/A break;
2N/A case CFGA_CMD_LOAD:
2N/A case CFGA_CMD_UNLOAD:
2N/A rc = CFGA_OPNOTSUPP;
2N/A c = CMD_NONE;
2N/A break;
2N/A default:
2N/A rc = CFGA_INVAL;
2N/A c = CMD_NONE;
2N/A break;
2N/A }
2N/A
2N/A *cmd = c;
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/Astatic int
2N/Aap_cmd(char *name)
2N/A{
2N/A int i;
2N/A char **p;
2N/A
2N/A if (name == NULL)
2N/A return (CMD_NONE);
2N/A
2N/A for (i = 0, p = ap_cmd_names; *p != NULL; p++, i++)
2N/A if (strcmp(*p, name) == 0)
2N/A break;
2N/A if (*p == NULL)
2N/A i = CMD_NONE;
2N/A
2N/A return (i);
2N/A}
2N/A
2N/Astatic int
2N/Aap_opt_parse(apd_t *a, ap_cmd_t *acp, const char *options)
2N/A{
2N/A char *optstr;
2N/A ap_opts_t *opts;
2N/A
2N/A /*
2N/A * Set default values.
2N/A */
2N/A opts = &a->opts;
2N/A opts->mid = (char *)a->class;
2N/A opts->err = ERR_CMD_FAIL;
2N/A
2N/A if (options == NULL)
2N/A return (0);
2N/A
2N/A if ((optstr = strdup(options)) == NULL) {
2N/A ap_err(a, ERR_NOMEM);
2N/A return (-1);
2N/A }
2N/A
2N/A a->options = optstr;
2N/A
2N/A if (acp->cmd == CMD_PASSTHRU)
2N/A return (0);
2N/A
2N/A while (*optstr != '\0') {
2N/A int i;
2N/A int opt;
2N/A int omask;
2N/A char *p;
2N/A char *value;
2N/A char *optname;
2N/A
2N/A value = NULL;
2N/A opt = getsubopt(&optstr, ap_opt_names, &value);
2N/A
2N/A DBG("opt=%d\n", opt);
2N/A
2N/A if (opt == -1) {
2N/A ap_err(a, ERR_OPT_INVAL, value);
2N/A return (-1);
2N/A }
2N/A
2N/A optname = ap_opt_names[opt];
2N/A omask = acp->omask[a->tgt];
2N/A
2N/A i = mask(opt) & omask;
2N/A
2N/A DBG("tgt=%d opt=%x omask=%x\n", a->tgt, mask(opt), omask);
2N/A
2N/A if (i == 0) {
2N/A ap_err(a, ERR_OPT_INVAL, optname);
2N/A return (-1);
2N/A }
2N/A
2N/A /*
2N/A * Check whether the option requires a value.
2N/A */
2N/A i = mask(opt) & AP_VMASK;
2N/A if (i != 0 && value == NULL) {
2N/A ap_err(a, ERR_OPT_NOVAL, optname);
2N/A return (-1);
2N/A } else if (i == 0 && value != NULL) {
2N/A ap_err(a, ERR_OPT_VAL, optname);
2N/A return (-1);
2N/A }
2N/A
2N/A if (value == NULL)
2N/A assert(opt != OPT_CODE); /* XXX prefix */
2N/A
2N/A /*
2N/A * Set the options's value.
2N/A */
2N/A switch (opt) {
2N/A case OPT_SIM:
2N/A case OPT_PARSABLE:
2N/A case OPT_UNASSIGN:
2N/A break;
2N/A case OPT_CODE:
2N/A i = strtol(value, &p, 10);
2N/A if (p > value)
2N/A opts->code = i;
2N/A break;
2N/A case OPT_MID:
2N/A opts->mid = value;
2N/A break;
2N/A case OPT_ERR:
2N/A i = strtol(value, &p, 10);
2N/A if (p > value)
2N/A opts->err = i;
2N/A break;
2N/A case OPT_NOPOWEROFF:
2N/A i = ap_cmd("poweroff");
2N/A opts->skip |= mask(i);
2N/A break;
2N/A case OPT_SKIP: /* for debugging */
2N/A /*
2N/A * The skip value may be a ':' separated
2N/A * list of steps (commands) to be skipped
2N/A * during sequencing.
2N/A */
2N/A for (p = strtok(value, ":"); p != NULL;
2N/A p = strtok(NULL, ":")) {
2N/A if ((i = ap_cmd(p)) == CMD_NONE) {
2N/A ap_err(a, ERR_CMD_INVAL, p);
2N/A return (-1);
2N/A }
2N/A opts->skip |= mask(i);
2N/A }
2N/A break;
2N/A case OPT_PLATFORM:
2N/A opts->platform = value;
2N/A break;
2N/A default:
2N/A ap_err(a, ERR_OPT_INVAL, optname);
2N/A return (-1);
2N/A }
2N/A
2N/A ap_setopt(a, opt);
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic ap_cmd_t *
2N/Aap_cmdp(int cmd)
2N/A{
2N/A ap_cmd_t *acp;
2N/A
2N/A for (acp = ap_cmds; acp->cmd != CMD_NONE; acp++)
2N/A if (acp->cmd == cmd)
2N/A break;
2N/A
2N/A if (acp->cmd == CMD_NONE)
2N/A return (NULL);
2N/A
2N/A return (acp);
2N/A}
2N/A
2N/Acfga_err_t
2N/Aap_cmd_parse(apd_t *a, const char *f, const char *options, int *cmd)
2N/A{
2N/A int c;
2N/A int all;
2N/A int tgt;
2N/A int target;
2N/A ap_cmd_t *acp;
2N/A cfga_err_t rc;
2N/A
2N/A#ifdef _SBD_DEBUG
2N/A ap_cmds_dump();
2N/A#endif
2N/A
2N/A rc = CFGA_INVAL;
2N/A
2N/A if ((c = ap_cmd((char *)f)) == CMD_NONE ||
2N/A (acp = ap_cmdp(c)) == NULL) {
2N/A ap_err(a, ERR_CMD_INVAL, f);
2N/A return (rc);
2N/A }
2N/A
2N/A /*
2N/A * Change a->statonly to 1, if the case is CMD_STATUS. We are only
2N/A * wanting to read the devices and no more
2N/A */
2N/A /*
2N/A * Get the status for all components if either the list all
2N/A * option being specified or if we are configuring/unconfiguring
2N/A * the board. The latter is needed for the RCM interface.
2N/A */
2N/A switch (c) {
2N/A case CMD_STATUS:
2N/A all = ap_getopt(a, OPT_LIST_ALL);
2N/A a->statonly = 1;
2N/A break;
2N/A case CMD_CONFIGURE:
2N/A case CMD_UNCONFIGURE:
2N/A case CMD_CONNECT:
2N/A case CMD_DISCONNECT:
2N/A all = (a->tgt == AP_BOARD);
2N/A a->statonly = 0;
2N/A break;
2N/A default:
2N/A all = 0;
2N/A a->statonly = 0;
2N/A break;
2N/A }
2N/A
2N/A if ((rc = apd_init(a, all)) != CFGA_OK)
2N/A return (rc);
2N/A
2N/A rc = CFGA_INVAL;
2N/A
2N/A /*
2N/A * Get the target here in case it is a component in which
2N/A * case its type is known after the initialization.
2N/A */
2N/A tgt = a->tgt;
2N/A target = mask(tgt);
2N/A
2N/A DBG("cmd=%s(%d) tmask=0x%x cmask=0x%x omask=0x%x\n",
2N/A ap_cmd_name(c), c, target, acp->cmask, acp->omask[tgt]);
2N/A
2N/A if ((acp->cmask & target) == 0)
2N/A ap_err(a, ERR_CMD_NOTSUPP, c);
2N/A else if (options != NULL && acp->omask[tgt] == 0)
2N/A ap_err(a, ERR_OPT_INVAL, options);
2N/A else if (ap_opt_parse(a, acp, options) != -1) {
2N/A if (c == CMD_STATUS)
2N/A rc = ap_platopts_check(a, c, c);
2N/A else
2N/A rc = CFGA_OK;
2N/A }
2N/A
2N/A#ifdef __x86
2N/A /*
2N/A * Currently on x86 platforms, only limited cfgadm commands are exposed
2N/A * to end users, though all cfgadm commands are supported by underlying
2N/A * dr driver. If the special platform option "acpi-update-status" is
2N/A * absent, reject all hidden commands.
2N/A * This is a ugly hack, it should be removed in future releases.
2N/A */
2N/A switch (c) {
2N/A case CMD_STATUS:
2N/A case CMD_CONFIGURE:
2N/A case CMD_PASSTHRU:
2N/A break;
2N/A default:
2N/A if ((a->opts.platform == NULL ||
2N/A strstr(a->opts.platform, "acpi-update-status") == NULL)) {
2N/A rc = CFGA_INVAL;
2N/A ap_err(a, ERR_CMD_INVAL, f);
2N/A }
2N/A }
2N/A#endif /* __x86 */
2N/A
2N/A if (cmd)
2N/A *cmd = c;
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/Aint
2N/Aap_cnt(apd_t *a)
2N/A{
2N/A int cnt;
2N/A
2N/A if ((a->tgt == AP_BOARD) && ap_getopt(a, OPT_LIST_ALL))
2N/A cnt = a->ncm + 1;
2N/A else
2N/A cnt = 1;
2N/A
2N/A return (cnt);
2N/A}