10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*12004Sjiang.liu@intel.com * Common Development and Distribution License (the "License").
6*12004Sjiang.liu@intel.com * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*12004Sjiang.liu@intel.com * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #include <assert.h>
270Sstevel@tonic-gate #include <ctype.h>
280Sstevel@tonic-gate #include <stdio.h>
290Sstevel@tonic-gate #include <stdlib.h>
300Sstevel@tonic-gate #include <string.h>
310Sstevel@tonic-gate #include <unistd.h>
320Sstevel@tonic-gate #include <macros.h>
330Sstevel@tonic-gate #include <dirent.h>
340Sstevel@tonic-gate #include <libgen.h>
350Sstevel@tonic-gate #include <libdevinfo.h>
360Sstevel@tonic-gate #define CFGA_PLUGIN_LIB
370Sstevel@tonic-gate #include <config_admin.h>
380Sstevel@tonic-gate #include "ap.h"
390Sstevel@tonic-gate
40*12004Sjiang.liu@intel.com /*ARGSUSED0*/
410Sstevel@tonic-gate int
ap_symid(apd_t * a,char * apid,char * symid,size_t bufsize)420Sstevel@tonic-gate ap_symid(apd_t *a, char *apid, char *symid, size_t bufsize)
430Sstevel@tonic-gate {
440Sstevel@tonic-gate int n;
450Sstevel@tonic-gate int rc;
460Sstevel@tonic-gate char path[MAXPATHLEN];
470Sstevel@tonic-gate char *p;
480Sstevel@tonic-gate DIR *dirp;
490Sstevel@tonic-gate struct dirent *dp;
500Sstevel@tonic-gate
510Sstevel@tonic-gate *symid = '\0';
520Sstevel@tonic-gate n = sprintf(path, "/dev/cfg/");
530Sstevel@tonic-gate rc = -1;
540Sstevel@tonic-gate
550Sstevel@tonic-gate if ((dirp = opendir(path)) == NULL)
560Sstevel@tonic-gate return (rc);
570Sstevel@tonic-gate
580Sstevel@tonic-gate p = path + n;
590Sstevel@tonic-gate
600Sstevel@tonic-gate while ((dp = readdir(dirp)) != NULL) {
610Sstevel@tonic-gate char buf[MAXPATHLEN];
620Sstevel@tonic-gate char *cp;
630Sstevel@tonic-gate size_t len;
640Sstevel@tonic-gate
650Sstevel@tonic-gate *p = '\0';
660Sstevel@tonic-gate (void) strcat(path, dp->d_name);
670Sstevel@tonic-gate if ((len = readlink(path, buf, sizeof (buf))) == (size_t)-1)
680Sstevel@tonic-gate continue;
690Sstevel@tonic-gate buf[len] = '\0';
700Sstevel@tonic-gate
710Sstevel@tonic-gate len = strlen("../");
720Sstevel@tonic-gate cp = buf;
730Sstevel@tonic-gate while (strncmp(cp, "../", len) == 0)
740Sstevel@tonic-gate cp += len;
750Sstevel@tonic-gate if (cp != buf)
760Sstevel@tonic-gate cp--; /* Get the '/' */
770Sstevel@tonic-gate
780Sstevel@tonic-gate if (strcmp(cp, apid) == 0) {
79*12004Sjiang.liu@intel.com (void) snprintf(symid, bufsize, "%s", dp->d_name);
800Sstevel@tonic-gate rc = 0;
810Sstevel@tonic-gate break;
820Sstevel@tonic-gate }
830Sstevel@tonic-gate }
840Sstevel@tonic-gate
85*12004Sjiang.liu@intel.com (void) closedir(dirp);
860Sstevel@tonic-gate return (rc);
870Sstevel@tonic-gate }
880Sstevel@tonic-gate
890Sstevel@tonic-gate char *
ap_logid(apd_t * a,char * apid)900Sstevel@tonic-gate ap_logid(apd_t *a, char *apid)
910Sstevel@tonic-gate {
920Sstevel@tonic-gate int n;
930Sstevel@tonic-gate char *buf;
940Sstevel@tonic-gate
950Sstevel@tonic-gate if ((buf = calloc(1, MAXPATHLEN)) == NULL)
960Sstevel@tonic-gate return (NULL);
970Sstevel@tonic-gate
980Sstevel@tonic-gate /*
990Sstevel@tonic-gate * Look for a symlink. On any error, fallback to
1000Sstevel@tonic-gate * driver and instance based logical ap_ids.
1010Sstevel@tonic-gate */
1020Sstevel@tonic-gate if (ap_symid(a, apid, buf, MAXPATHLEN) == 0)
1030Sstevel@tonic-gate n = strlen(buf);
1040Sstevel@tonic-gate else
1050Sstevel@tonic-gate n = snprintf(buf, MAXPATHLEN, "%s%d:%s",
1060Sstevel@tonic-gate a->drv, a->inst, a->minor);
1070Sstevel@tonic-gate /*
1080Sstevel@tonic-gate * Append the dynamic portion, if any.
1090Sstevel@tonic-gate */
1100Sstevel@tonic-gate if (a->cid != NULL)
1110Sstevel@tonic-gate (void) snprintf(&buf[n], MAXPATHLEN - n, "::%s", a->cid);
1120Sstevel@tonic-gate
1130Sstevel@tonic-gate return (buf);
1140Sstevel@tonic-gate }
1150Sstevel@tonic-gate
1160Sstevel@tonic-gate int
ap_parse(apd_t * a,const char * ap_id)1170Sstevel@tonic-gate ap_parse(apd_t *a, const char *ap_id)
1180Sstevel@tonic-gate {
1190Sstevel@tonic-gate int i;
1200Sstevel@tonic-gate int rc;
1210Sstevel@tonic-gate int phys;
1220Sstevel@tonic-gate char c;
1230Sstevel@tonic-gate char *s;
1240Sstevel@tonic-gate char *p;
1250Sstevel@tonic-gate char *q;
1260Sstevel@tonic-gate char *base;
1270Sstevel@tonic-gate int len;
1280Sstevel@tonic-gate char *t;
1290Sstevel@tonic-gate
1300Sstevel@tonic-gate if (a == NULL)
1310Sstevel@tonic-gate return (-1);
1320Sstevel@tonic-gate
1330Sstevel@tonic-gate a->cnum = -1;
1340Sstevel@tonic-gate a->bnum = -1;
1350Sstevel@tonic-gate a->inst = -1;
1360Sstevel@tonic-gate a->apid = ap_id;
1370Sstevel@tonic-gate rc = ERR_NONE;
1380Sstevel@tonic-gate
1390Sstevel@tonic-gate if (!str_valid(ap_id)) {
1400Sstevel@tonic-gate rc = ERR_AP_INVAL;
1410Sstevel@tonic-gate goto done;
1420Sstevel@tonic-gate }
1430Sstevel@tonic-gate
1440Sstevel@tonic-gate if ((a->path = strdup(ap_id)) == NULL) {
1450Sstevel@tonic-gate rc = ERR_NOMEM;
1460Sstevel@tonic-gate goto done;
1470Sstevel@tonic-gate }
1480Sstevel@tonic-gate
1490Sstevel@tonic-gate /*
1500Sstevel@tonic-gate * For a physical ap_id, look only at the base part.
1510Sstevel@tonic-gate * For a logical/symbolic one, use the entire ap_id.
1520Sstevel@tonic-gate */
1530Sstevel@tonic-gate if (strncmp(a->path, DEVDIR, strlen(DEVDIR)) == 0) {
1540Sstevel@tonic-gate phys = 1;
1550Sstevel@tonic-gate base = strrchr((const char *)a->path, '/') + 1;
1560Sstevel@tonic-gate } else {
1570Sstevel@tonic-gate phys = 0;
1580Sstevel@tonic-gate base = a->path;
1590Sstevel@tonic-gate if ((a->target = strdup(a->path)) == NULL) {
1600Sstevel@tonic-gate rc = ERR_NOMEM;
1610Sstevel@tonic-gate goto done;
1620Sstevel@tonic-gate }
1630Sstevel@tonic-gate }
1640Sstevel@tonic-gate
1650Sstevel@tonic-gate if ((s = strchr(base, ':')) == NULL || s[1] == ':') {
1660Sstevel@tonic-gate /*
1670Sstevel@tonic-gate * No ':' found, or got a '::'. If this is a physical
1680Sstevel@tonic-gate * ap_id, it must have a minor separtor ':' which must
1690Sstevel@tonic-gate * appear before the dynamic part (starting with '::').
1700Sstevel@tonic-gate * For a symbolic ap_id, skip looking for driver/minor
1710Sstevel@tonic-gate * names.
1720Sstevel@tonic-gate */
1730Sstevel@tonic-gate if (phys) {
1740Sstevel@tonic-gate rc = ERR_AP_INVAL;
1750Sstevel@tonic-gate goto done;
1760Sstevel@tonic-gate } else
1770Sstevel@tonic-gate s = base;
1780Sstevel@tonic-gate } else {
1790Sstevel@tonic-gate /*
1800Sstevel@tonic-gate * Look for driver name/instance only up to the first ':',
1810Sstevel@tonic-gate * i.e. up to the minor node name.
1820Sstevel@tonic-gate */
1830Sstevel@tonic-gate *s = '\0';
1840Sstevel@tonic-gate
1850Sstevel@tonic-gate if ((p = strchr(base, '@')) != NULL) {
1860Sstevel@tonic-gate /*
1870Sstevel@tonic-gate * Get the driver name/instance.
1880Sstevel@tonic-gate */
1890Sstevel@tonic-gate *p = '\0';
1900Sstevel@tonic-gate if ((a->drv = strdup(base)) == NULL) {
1910Sstevel@tonic-gate rc = ERR_NOMEM;
1920Sstevel@tonic-gate goto done;
1930Sstevel@tonic-gate }
1940Sstevel@tonic-gate *p++ = '@';
1950Sstevel@tonic-gate
1960Sstevel@tonic-gate i = strtol(p, &q, 10);
1970Sstevel@tonic-gate if (q > p)
1980Sstevel@tonic-gate a->inst = i;
1990Sstevel@tonic-gate }
2000Sstevel@tonic-gate
2010Sstevel@tonic-gate *s++ = ':';
2020Sstevel@tonic-gate a->minor = s;
2030Sstevel@tonic-gate }
2040Sstevel@tonic-gate
2050Sstevel@tonic-gate /*
2060Sstevel@tonic-gate * Need to go to the end of the string before the :: if any
2070Sstevel@tonic-gate * If the string is null then we are done
2080Sstevel@tonic-gate */
2090Sstevel@tonic-gate t = strstr(s, "::");
2100Sstevel@tonic-gate if (t != NULL)
2110Sstevel@tonic-gate len = strlen(t);
2120Sstevel@tonic-gate else
2130Sstevel@tonic-gate len = 0;
2140Sstevel@tonic-gate
2150Sstevel@tonic-gate s += (strlen(s) - len);
2160Sstevel@tonic-gate
2170Sstevel@tonic-gate p = s;
2180Sstevel@tonic-gate
2190Sstevel@tonic-gate if (*p == '\0')
2200Sstevel@tonic-gate a->tgt = AP_BOARD;
2210Sstevel@tonic-gate else if (strncmp(p, "::", 2) != 0) {
2220Sstevel@tonic-gate rc = ERR_AP_INVAL;
2230Sstevel@tonic-gate goto done;
2240Sstevel@tonic-gate } else {
2250Sstevel@tonic-gate /*
2260Sstevel@tonic-gate * Save the component id.
2270Sstevel@tonic-gate */
2280Sstevel@tonic-gate *p++ = '\0';
2290Sstevel@tonic-gate *p++ = '\0';
2300Sstevel@tonic-gate a->cid = p;
2310Sstevel@tonic-gate }
2320Sstevel@tonic-gate
2330Sstevel@tonic-gate /*
2340Sstevel@tonic-gate * Get the operation target, e.g. slot0, slot0::cpu0.
2350Sstevel@tonic-gate * At this point, a->path points to the /devices path
2360Sstevel@tonic-gate * minus the dynamic part, for a physical ap_id. In
2370Sstevel@tonic-gate * the case of a logical ap_id, the target is already
2380Sstevel@tonic-gate * initialized above.
2390Sstevel@tonic-gate */
2400Sstevel@tonic-gate if (phys != 0 && (a->target = ap_logid(a, a->path)) == NULL) {
2410Sstevel@tonic-gate rc = ERR_NOMEM;
2420Sstevel@tonic-gate goto done;
2430Sstevel@tonic-gate }
2440Sstevel@tonic-gate
2450Sstevel@tonic-gate if (a->tgt == AP_BOARD)
2460Sstevel@tonic-gate goto done;
2470Sstevel@tonic-gate
2480Sstevel@tonic-gate while ((*p != '\0') && !isdigit(*p))
2490Sstevel@tonic-gate p++;
2500Sstevel@tonic-gate
2510Sstevel@tonic-gate /*
2520Sstevel@tonic-gate * Get the component unit number, if present.
2530Sstevel@tonic-gate */
2540Sstevel@tonic-gate i = strtol(p, &s, 10);
2550Sstevel@tonic-gate /*
2560Sstevel@tonic-gate * There must be no characters after the unit number.
2570Sstevel@tonic-gate */
2580Sstevel@tonic-gate if (*s != '\0') {
2590Sstevel@tonic-gate rc = ERR_CM_INVAL;
2600Sstevel@tonic-gate goto done;
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate if (s > p) {
2630Sstevel@tonic-gate /*
2640Sstevel@tonic-gate * Disallow leading zeroes, e.g. cpu00, cpu01, cpu001.
2650Sstevel@tonic-gate * If there are 2 or more digits and the first is a zero,
2660Sstevel@tonic-gate * we fail.
2670Sstevel@tonic-gate */
2680Sstevel@tonic-gate if ((s-p) >= 2 && *p == '0') {
2690Sstevel@tonic-gate rc = ERR_CM_INVAL;
2700Sstevel@tonic-gate goto done;
2710Sstevel@tonic-gate }
2720Sstevel@tonic-gate a->cnum = i;
2730Sstevel@tonic-gate }
2740Sstevel@tonic-gate
2750Sstevel@tonic-gate c = *p;
2760Sstevel@tonic-gate *p = '\0';
2770Sstevel@tonic-gate if ((a->cname = strdup(a->cid)) == NULL)
2780Sstevel@tonic-gate rc = ERR_NOMEM;
2790Sstevel@tonic-gate *p = c;
2800Sstevel@tonic-gate done:
2810Sstevel@tonic-gate switch (rc) {
2820Sstevel@tonic-gate case ERR_NONE:
2830Sstevel@tonic-gate break;
2840Sstevel@tonic-gate case ERR_CM_INVAL:
2850Sstevel@tonic-gate ap_err(a, ERR_CM_INVAL, a->cid);
2860Sstevel@tonic-gate break;
2870Sstevel@tonic-gate default:
2880Sstevel@tonic-gate ap_err(a, rc);
2890Sstevel@tonic-gate break;
2900Sstevel@tonic-gate }
2910Sstevel@tonic-gate
2920Sstevel@tonic-gate DBG("path=<%s> ", a->path ? a->path : "");
2930Sstevel@tonic-gate DBG("drv=<%s> inst=%d minor=<%s> ",
294*12004Sjiang.liu@intel.com a->drv ? a->drv : "", a->inst, a->minor ? a->minor : "");
2950Sstevel@tonic-gate DBG("target=<%s>\n", a->target ? a->target : "");
2960Sstevel@tonic-gate DBG("cid=<%s> ", a->cid ? a->cid : "");
2970Sstevel@tonic-gate DBG("cname=<%s> ", a->cname ? a->cname : "");
2980Sstevel@tonic-gate DBG("cnum=%d\n", a->cnum);
2990Sstevel@tonic-gate DBG("tgt=%d opts=%x\n", a->tgt, a->opts.flags);
3000Sstevel@tonic-gate
3010Sstevel@tonic-gate return (rc == ERR_NONE? 0 : -1);
3020Sstevel@tonic-gate }
3030Sstevel@tonic-gate
3040Sstevel@tonic-gate /*
3050Sstevel@tonic-gate * Command table.
3060Sstevel@tonic-gate *
3070Sstevel@tonic-gate * The first set of commands in the table are in sequencing order,
3080Sstevel@tonic-gate * for example, the first group starts with assign and ends with
3090Sstevel@tonic-gate * configure. command sequencer relies on this ordering.
3100Sstevel@tonic-gate */
3110Sstevel@tonic-gate static char *
3120Sstevel@tonic-gate ap_cmd_names[] = {
3130Sstevel@tonic-gate "assign",
3140Sstevel@tonic-gate "poweron",
3150Sstevel@tonic-gate "test",
3160Sstevel@tonic-gate "connect",
3170Sstevel@tonic-gate "configure",
3180Sstevel@tonic-gate "notify online",
3190Sstevel@tonic-gate "notify add capacity",
3200Sstevel@tonic-gate "suspend check",
3210Sstevel@tonic-gate "request suspend",
3220Sstevel@tonic-gate "request delete capacity",
3230Sstevel@tonic-gate "request offline",
3240Sstevel@tonic-gate "unconfigure",
3250Sstevel@tonic-gate "notify remove",
3260Sstevel@tonic-gate "notify capacity change",
3270Sstevel@tonic-gate "disconnect",
3280Sstevel@tonic-gate "poweroff",
3290Sstevel@tonic-gate "unassign",
3300Sstevel@tonic-gate "notify resume",
3310Sstevel@tonic-gate "status",
3320Sstevel@tonic-gate "getncm",
3330Sstevel@tonic-gate "passthru",
3340Sstevel@tonic-gate "help",
3350Sstevel@tonic-gate "errtest",
3360Sstevel@tonic-gate NULL
3370Sstevel@tonic-gate };
3380Sstevel@tonic-gate
3390Sstevel@tonic-gate char *
ap_cmd_name(int i)3400Sstevel@tonic-gate ap_cmd_name(int i)
3410Sstevel@tonic-gate {
3420Sstevel@tonic-gate return (ap_cmd_names[min(i, CMD_NONE)]);
3430Sstevel@tonic-gate }
3440Sstevel@tonic-gate
3450Sstevel@tonic-gate static char *
3460Sstevel@tonic-gate ap_opt_names[] = {
3470Sstevel@tonic-gate "unassign",
3480Sstevel@tonic-gate "skip",
3490Sstevel@tonic-gate "parsable",
3500Sstevel@tonic-gate "nopoweroff",
3510Sstevel@tonic-gate "code",
3520Sstevel@tonic-gate "mid",
3530Sstevel@tonic-gate "err",
3540Sstevel@tonic-gate "platform",
3550Sstevel@tonic-gate "sim",
3560Sstevel@tonic-gate NULL
3570Sstevel@tonic-gate };
3580Sstevel@tonic-gate
3590Sstevel@tonic-gate char *
ap_opt_name(int i)3600Sstevel@tonic-gate ap_opt_name(int i)
3610Sstevel@tonic-gate {
3620Sstevel@tonic-gate return (ap_opt_names[i]);
3630Sstevel@tonic-gate }
3640Sstevel@tonic-gate
3650Sstevel@tonic-gate /*
3660Sstevel@tonic-gate * Command descriptor.
3670Sstevel@tonic-gate *
3680Sstevel@tonic-gate * Each command has a (command) mask specifying the AP target classes
3690Sstevel@tonic-gate * it operates on, e.g. the assign command applies only to boards.
3700Sstevel@tonic-gate * In addition each AP target class has a separate option mask specifying
3710Sstevel@tonic-gate * which command options are valid for that target class.
3720Sstevel@tonic-gate * A global value mask specifies which options require values.
3730Sstevel@tonic-gate */
3740Sstevel@tonic-gate typedef struct {
3750Sstevel@tonic-gate int cmd;
3760Sstevel@tonic-gate uint_t cmask;
3770Sstevel@tonic-gate uint_t omask[AP_NCLASS];
3780Sstevel@tonic-gate } ap_cmd_t;
3790Sstevel@tonic-gate
3800Sstevel@tonic-gate /*
3810Sstevel@tonic-gate * Command option definitions.
3820Sstevel@tonic-gate */
3830Sstevel@tonic-gate #define SHFT(i) ((uint_t)1 << (i))
3840Sstevel@tonic-gate #define NULOPT 0
3850Sstevel@tonic-gate #define ALLOPT 0xffffffff
3860Sstevel@tonic-gate #define CMNOPT (SHFT(OPT_VERBOSE)|SHFT(OPT_PLATFORM)|SHFT(OPT_SIM))
3870Sstevel@tonic-gate #define CMFOPT (CMNOPT|SHFT(OPT_FORCE))
3880Sstevel@tonic-gate #define STSOPT (CMNOPT|SHFT(OPT_PARSABLE))
3890Sstevel@tonic-gate #define BRDDCN (CMNOPT|SHFT(OPT_UNASSIGN)|SHFT(OPT_NOPOWEROFF))
3900Sstevel@tonic-gate
3910Sstevel@tonic-gate #define BRD SHFT(AP_BOARD)
3920Sstevel@tonic-gate #define BIO SHFT(AP_BOARD)|SHFT(AP_IO)
3930Sstevel@tonic-gate #define ALL (BRD|SHFT(AP_CPU)|SHFT(AP_MEM)|SHFT(AP_IO)|SHFT(AP_CMP))
3940Sstevel@tonic-gate
3950Sstevel@tonic-gate static ap_cmd_t
3960Sstevel@tonic-gate ap_cmds[] = {
3970Sstevel@tonic-gate /*
3980Sstevel@tonic-gate * cmd cmd board cpu mem io cmp
3990Sstevel@tonic-gate * cmask omask omask omask omask omask
4000Sstevel@tonic-gate */
4010Sstevel@tonic-gate {CMD_ASSIGN, BRD, 0, CMNOPT, NULOPT, NULOPT, NULOPT, NULOPT},
4020Sstevel@tonic-gate {CMD_UNASSIGN, BRD, 0, CMNOPT, NULOPT, NULOPT, NULOPT, NULOPT},
4030Sstevel@tonic-gate {CMD_POWERON, BRD, 0, CMNOPT, NULOPT, NULOPT, NULOPT, NULOPT},
4040Sstevel@tonic-gate {CMD_POWEROFF, BRD, 0, CMNOPT, NULOPT, NULOPT, NULOPT, NULOPT},
4050Sstevel@tonic-gate {CMD_CONNECT, BRD, 0, CMFOPT, NULOPT, NULOPT, NULOPT, NULOPT},
4060Sstevel@tonic-gate {CMD_DISCONNECT, BRD, 0, BRDDCN, NULOPT, NULOPT, NULOPT, NULOPT},
4070Sstevel@tonic-gate {CMD_CONFIGURE, ALL, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
4080Sstevel@tonic-gate {CMD_UNCONFIGURE, ALL, 0, CMFOPT, CMFOPT, CMFOPT, CMFOPT, CMNOPT},
4090Sstevel@tonic-gate {CMD_RCM_OFFLINE, BIO, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
4100Sstevel@tonic-gate {CMD_RCM_ONLINE, BIO, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
4110Sstevel@tonic-gate {CMD_RCM_SUSPEND, BIO, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
4120Sstevel@tonic-gate {CMD_RCM_RESUME, BIO, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
4130Sstevel@tonic-gate {CMD_RCM_CAP_ADD, BIO, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
4140Sstevel@tonic-gate {CMD_RCM_CAP_DEL, BIO, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
4150Sstevel@tonic-gate {CMD_RCM_CAP_NOTIFY, BIO, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
4160Sstevel@tonic-gate {CMD_RCM_REMOVE, BIO, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
4170Sstevel@tonic-gate {CMD_TEST, BRD, 0, CMFOPT, NULOPT, NULOPT, NULOPT, NULOPT},
4180Sstevel@tonic-gate {CMD_STATUS, ALL, 0, STSOPT, STSOPT, STSOPT, STSOPT, STSOPT},
4190Sstevel@tonic-gate {CMD_GETNCM, BRD, 0, CMNOPT, NULOPT, NULOPT, NULOPT, NULOPT},
4200Sstevel@tonic-gate {CMD_PASSTHRU, ALL, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
4210Sstevel@tonic-gate {CMD_HELP, ALL, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
4220Sstevel@tonic-gate {CMD_ERRTEST, ALL, 0, ALLOPT, ALLOPT, ALLOPT, ALLOPT, ALLOPT},
4230Sstevel@tonic-gate {CMD_NONE, 0, 0, 0, 0, 0, 0, 0 }
4240Sstevel@tonic-gate };
4250Sstevel@tonic-gate
4260Sstevel@tonic-gate /*
4270Sstevel@tonic-gate * Global mask for options that require values.
4280Sstevel@tonic-gate */
4290Sstevel@tonic-gate #define AP_VMASK (\
4300Sstevel@tonic-gate SHFT(OPT_CODE)|SHFT(OPT_MID)|SHFT(OPT_ERR)| \
4310Sstevel@tonic-gate SHFT(OPT_PLATFORM)|SHFT(OPT_SKIP))
4320Sstevel@tonic-gate
4330Sstevel@tonic-gate #if SBD_DEBUG
4340Sstevel@tonic-gate void
ap_cmds_dump()4350Sstevel@tonic-gate ap_cmds_dump()
4360Sstevel@tonic-gate {
4370Sstevel@tonic-gate int i;
4380Sstevel@tonic-gate ap_cmd_t *acp;
4390Sstevel@tonic-gate
4400Sstevel@tonic-gate dbg("vmask=0x%x\n", AP_VMASK);
4410Sstevel@tonic-gate dbg("%23s%5s%5s%9s%9s%9s%9s%9s\n",
4420Sstevel@tonic-gate "cmd", "msk", "none", "brd", "cpu", "mem", "io", "cmp");
4430Sstevel@tonic-gate
4440Sstevel@tonic-gate for (acp = ap_cmds; acp->cmd != CMD_NONE; acp++) {
4450Sstevel@tonic-gate dbg("%23s%5x%5x", ap_cmd_name(acp->cmd), acp->cmask,
4460Sstevel@tonic-gate acp->omask[AP_NONE]);
4470Sstevel@tonic-gate for (i = AP_BOARD; i < AP_NCLASS; i++) {
4480Sstevel@tonic-gate dbg("%9x", acp->omask[i]);
4490Sstevel@tonic-gate }
4500Sstevel@tonic-gate dbg("\n");
4510Sstevel@tonic-gate }
4520Sstevel@tonic-gate }
4530Sstevel@tonic-gate #endif
4540Sstevel@tonic-gate
4550Sstevel@tonic-gate int
ap_state_cmd(cfga_cmd_t i,int * cmd)4560Sstevel@tonic-gate ap_state_cmd(cfga_cmd_t i, int *cmd)
4570Sstevel@tonic-gate {
4580Sstevel@tonic-gate int c;
4590Sstevel@tonic-gate int rc;
4600Sstevel@tonic-gate
4610Sstevel@tonic-gate rc = CFGA_OK;
4620Sstevel@tonic-gate
4630Sstevel@tonic-gate switch (i) {
4640Sstevel@tonic-gate case CFGA_CMD_CONNECT:
4650Sstevel@tonic-gate c = CMD_CONNECT;
4660Sstevel@tonic-gate break;
4670Sstevel@tonic-gate case CFGA_CMD_DISCONNECT:
4680Sstevel@tonic-gate c = CMD_DISCONNECT;
4690Sstevel@tonic-gate break;
4700Sstevel@tonic-gate case CFGA_CMD_CONFIGURE:
4710Sstevel@tonic-gate c = CMD_CONFIGURE;
4720Sstevel@tonic-gate break;
4730Sstevel@tonic-gate case CFGA_CMD_UNCONFIGURE:
4740Sstevel@tonic-gate c = CMD_UNCONFIGURE;
4750Sstevel@tonic-gate break;
4760Sstevel@tonic-gate case CFGA_CMD_LOAD:
4770Sstevel@tonic-gate case CFGA_CMD_UNLOAD:
4780Sstevel@tonic-gate rc = CFGA_OPNOTSUPP;
4790Sstevel@tonic-gate c = CMD_NONE;
4800Sstevel@tonic-gate break;
4810Sstevel@tonic-gate default:
4820Sstevel@tonic-gate rc = CFGA_INVAL;
4830Sstevel@tonic-gate c = CMD_NONE;
4840Sstevel@tonic-gate break;
4850Sstevel@tonic-gate }
4860Sstevel@tonic-gate
4870Sstevel@tonic-gate *cmd = c;
4880Sstevel@tonic-gate
4890Sstevel@tonic-gate return (rc);
4900Sstevel@tonic-gate }
4910Sstevel@tonic-gate
4920Sstevel@tonic-gate static int
ap_cmd(char * name)4930Sstevel@tonic-gate ap_cmd(char *name)
4940Sstevel@tonic-gate {
4950Sstevel@tonic-gate int i;
4960Sstevel@tonic-gate char **p;
4970Sstevel@tonic-gate
4980Sstevel@tonic-gate if (name == NULL)
4990Sstevel@tonic-gate return (CMD_NONE);
5000Sstevel@tonic-gate
5010Sstevel@tonic-gate for (i = 0, p = ap_cmd_names; *p != NULL; p++, i++)
5020Sstevel@tonic-gate if (strcmp(*p, name) == 0)
5030Sstevel@tonic-gate break;
5040Sstevel@tonic-gate if (*p == NULL)
5050Sstevel@tonic-gate i = CMD_NONE;
5060Sstevel@tonic-gate
5070Sstevel@tonic-gate return (i);
5080Sstevel@tonic-gate }
5090Sstevel@tonic-gate
5100Sstevel@tonic-gate static int
ap_opt_parse(apd_t * a,ap_cmd_t * acp,const char * options)5110Sstevel@tonic-gate ap_opt_parse(apd_t *a, ap_cmd_t *acp, const char *options)
5120Sstevel@tonic-gate {
5130Sstevel@tonic-gate char *optstr;
5140Sstevel@tonic-gate ap_opts_t *opts;
5150Sstevel@tonic-gate
5160Sstevel@tonic-gate /*
5170Sstevel@tonic-gate * Set default values.
5180Sstevel@tonic-gate */
5190Sstevel@tonic-gate opts = &a->opts;
5200Sstevel@tonic-gate opts->mid = (char *)a->class;
5210Sstevel@tonic-gate opts->err = ERR_CMD_FAIL;
5220Sstevel@tonic-gate
5230Sstevel@tonic-gate if (options == NULL)
5240Sstevel@tonic-gate return (0);
5250Sstevel@tonic-gate
5260Sstevel@tonic-gate if ((optstr = strdup(options)) == NULL) {
5270Sstevel@tonic-gate ap_err(a, ERR_NOMEM);
5280Sstevel@tonic-gate return (-1);
5290Sstevel@tonic-gate }
5300Sstevel@tonic-gate
5310Sstevel@tonic-gate a->options = optstr;
5320Sstevel@tonic-gate
5330Sstevel@tonic-gate if (acp->cmd == CMD_PASSTHRU)
5340Sstevel@tonic-gate return (0);
5350Sstevel@tonic-gate
5360Sstevel@tonic-gate while (*optstr != '\0') {
5370Sstevel@tonic-gate int i;
5380Sstevel@tonic-gate int opt;
5390Sstevel@tonic-gate int omask;
5400Sstevel@tonic-gate char *p;
5410Sstevel@tonic-gate char *value;
5420Sstevel@tonic-gate char *optname;
5430Sstevel@tonic-gate
5440Sstevel@tonic-gate value = NULL;
5450Sstevel@tonic-gate opt = getsubopt(&optstr, ap_opt_names, &value);
5460Sstevel@tonic-gate
5470Sstevel@tonic-gate DBG("opt=%d\n", opt);
5480Sstevel@tonic-gate
5490Sstevel@tonic-gate if (opt == -1) {
5500Sstevel@tonic-gate ap_err(a, ERR_OPT_INVAL, value);
5510Sstevel@tonic-gate return (-1);
5520Sstevel@tonic-gate }
5530Sstevel@tonic-gate
5540Sstevel@tonic-gate optname = ap_opt_names[opt];
5550Sstevel@tonic-gate omask = acp->omask[a->tgt];
5560Sstevel@tonic-gate
5570Sstevel@tonic-gate i = mask(opt) & omask;
5580Sstevel@tonic-gate
5590Sstevel@tonic-gate DBG("tgt=%d opt=%x omask=%x\n", a->tgt, mask(opt), omask);
5600Sstevel@tonic-gate
5610Sstevel@tonic-gate if (i == 0) {
5620Sstevel@tonic-gate ap_err(a, ERR_OPT_INVAL, optname);
5630Sstevel@tonic-gate return (-1);
5640Sstevel@tonic-gate }
5650Sstevel@tonic-gate
5660Sstevel@tonic-gate /*
5670Sstevel@tonic-gate * Check whether the option requires a value.
5680Sstevel@tonic-gate */
5690Sstevel@tonic-gate i = mask(opt) & AP_VMASK;
5700Sstevel@tonic-gate if (i != 0 && value == NULL) {
5710Sstevel@tonic-gate ap_err(a, ERR_OPT_NOVAL, optname);
5720Sstevel@tonic-gate return (-1);
5730Sstevel@tonic-gate } else if (i == 0 && value != NULL) {
5740Sstevel@tonic-gate ap_err(a, ERR_OPT_VAL, optname);
5750Sstevel@tonic-gate return (-1);
5760Sstevel@tonic-gate }
5770Sstevel@tonic-gate
5780Sstevel@tonic-gate if (value == NULL)
5790Sstevel@tonic-gate assert(opt != OPT_CODE); /* XXX prefix */
5800Sstevel@tonic-gate
5810Sstevel@tonic-gate /*
5820Sstevel@tonic-gate * Set the options's value.
5830Sstevel@tonic-gate */
5840Sstevel@tonic-gate switch (opt) {
5850Sstevel@tonic-gate case OPT_SIM:
5860Sstevel@tonic-gate case OPT_PARSABLE:
5870Sstevel@tonic-gate case OPT_UNASSIGN:
5880Sstevel@tonic-gate break;
5890Sstevel@tonic-gate case OPT_CODE:
5900Sstevel@tonic-gate i = strtol(value, &p, 10);
5910Sstevel@tonic-gate if (p > value)
5920Sstevel@tonic-gate opts->code = i;
5930Sstevel@tonic-gate break;
5940Sstevel@tonic-gate case OPT_MID:
5950Sstevel@tonic-gate opts->mid = value;
5960Sstevel@tonic-gate break;
5970Sstevel@tonic-gate case OPT_ERR:
5980Sstevel@tonic-gate i = strtol(value, &p, 10);
5990Sstevel@tonic-gate if (p > value)
6000Sstevel@tonic-gate opts->err = i;
6010Sstevel@tonic-gate break;
6020Sstevel@tonic-gate case OPT_NOPOWEROFF:
6030Sstevel@tonic-gate i = ap_cmd("poweroff");
6040Sstevel@tonic-gate opts->skip |= mask(i);
6050Sstevel@tonic-gate break;
6060Sstevel@tonic-gate case OPT_SKIP: /* for debugging */
6070Sstevel@tonic-gate /*
6080Sstevel@tonic-gate * The skip value may be a ':' separated
6090Sstevel@tonic-gate * list of steps (commands) to be skipped
6100Sstevel@tonic-gate * during sequencing.
6110Sstevel@tonic-gate */
6120Sstevel@tonic-gate for (p = strtok(value, ":"); p != NULL;
613*12004Sjiang.liu@intel.com p = strtok(NULL, ":")) {
6140Sstevel@tonic-gate if ((i = ap_cmd(p)) == CMD_NONE) {
6150Sstevel@tonic-gate ap_err(a, ERR_CMD_INVAL, p);
6160Sstevel@tonic-gate return (-1);
6170Sstevel@tonic-gate }
6180Sstevel@tonic-gate opts->skip |= mask(i);
6190Sstevel@tonic-gate }
6200Sstevel@tonic-gate break;
6210Sstevel@tonic-gate case OPT_PLATFORM:
6220Sstevel@tonic-gate opts->platform = value;
6230Sstevel@tonic-gate break;
6240Sstevel@tonic-gate default:
6250Sstevel@tonic-gate ap_err(a, ERR_OPT_INVAL, optname);
6260Sstevel@tonic-gate return (-1);
6270Sstevel@tonic-gate }
6280Sstevel@tonic-gate
6290Sstevel@tonic-gate ap_setopt(a, opt);
6300Sstevel@tonic-gate }
6310Sstevel@tonic-gate
6320Sstevel@tonic-gate return (0);
6330Sstevel@tonic-gate }
6340Sstevel@tonic-gate
6350Sstevel@tonic-gate static ap_cmd_t *
ap_cmdp(int cmd)6360Sstevel@tonic-gate ap_cmdp(int cmd)
6370Sstevel@tonic-gate {
6380Sstevel@tonic-gate ap_cmd_t *acp;
6390Sstevel@tonic-gate
6400Sstevel@tonic-gate for (acp = ap_cmds; acp->cmd != CMD_NONE; acp++)
6410Sstevel@tonic-gate if (acp->cmd == cmd)
6420Sstevel@tonic-gate break;
6430Sstevel@tonic-gate
6440Sstevel@tonic-gate if (acp->cmd == CMD_NONE)
6450Sstevel@tonic-gate return (NULL);
6460Sstevel@tonic-gate
6470Sstevel@tonic-gate return (acp);
6480Sstevel@tonic-gate }
6490Sstevel@tonic-gate
6500Sstevel@tonic-gate cfga_err_t
ap_cmd_parse(apd_t * a,const char * f,const char * options,int * cmd)6510Sstevel@tonic-gate ap_cmd_parse(apd_t *a, const char *f, const char *options, int *cmd)
6520Sstevel@tonic-gate {
6530Sstevel@tonic-gate int c;
6540Sstevel@tonic-gate int all;
6550Sstevel@tonic-gate int tgt;
6560Sstevel@tonic-gate int target;
6570Sstevel@tonic-gate ap_cmd_t *acp;
6580Sstevel@tonic-gate cfga_err_t rc;
6590Sstevel@tonic-gate
6600Sstevel@tonic-gate #ifdef _SBD_DEBUG
6610Sstevel@tonic-gate ap_cmds_dump();
6620Sstevel@tonic-gate #endif
6630Sstevel@tonic-gate
6640Sstevel@tonic-gate rc = CFGA_INVAL;
6650Sstevel@tonic-gate
6660Sstevel@tonic-gate if ((c = ap_cmd((char *)f)) == CMD_NONE ||
6670Sstevel@tonic-gate (acp = ap_cmdp(c)) == NULL) {
6680Sstevel@tonic-gate ap_err(a, ERR_CMD_INVAL, f);
6690Sstevel@tonic-gate return (rc);
6700Sstevel@tonic-gate }
6710Sstevel@tonic-gate
6720Sstevel@tonic-gate /*
6730Sstevel@tonic-gate * Change a->statonly to 1, if the case is CMD_STATUS. We are only
6740Sstevel@tonic-gate * wanting to read the devices and no more
6750Sstevel@tonic-gate */
6760Sstevel@tonic-gate /*
6770Sstevel@tonic-gate * Get the status for all components if either the list all
6780Sstevel@tonic-gate * option being specified or if we are configuring/unconfiguring
6790Sstevel@tonic-gate * the board. The latter is needed for the RCM interface.
6800Sstevel@tonic-gate */
6810Sstevel@tonic-gate switch (c) {
6820Sstevel@tonic-gate case CMD_STATUS:
6830Sstevel@tonic-gate all = ap_getopt(a, OPT_LIST_ALL);
6840Sstevel@tonic-gate a->statonly = 1;
6850Sstevel@tonic-gate break;
6860Sstevel@tonic-gate case CMD_CONFIGURE:
6870Sstevel@tonic-gate case CMD_UNCONFIGURE:
6880Sstevel@tonic-gate case CMD_CONNECT:
6890Sstevel@tonic-gate case CMD_DISCONNECT:
6900Sstevel@tonic-gate all = (a->tgt == AP_BOARD);
6910Sstevel@tonic-gate a->statonly = 0;
6920Sstevel@tonic-gate break;
6930Sstevel@tonic-gate default:
6940Sstevel@tonic-gate all = 0;
6950Sstevel@tonic-gate a->statonly = 0;
6960Sstevel@tonic-gate break;
6970Sstevel@tonic-gate }
6980Sstevel@tonic-gate
6990Sstevel@tonic-gate if ((rc = apd_init(a, all)) != CFGA_OK)
7000Sstevel@tonic-gate return (rc);
7010Sstevel@tonic-gate
7020Sstevel@tonic-gate rc = CFGA_INVAL;
7030Sstevel@tonic-gate
7040Sstevel@tonic-gate /*
7050Sstevel@tonic-gate * Get the target here in case it is a component in which
7060Sstevel@tonic-gate * case its type is known after the initialization.
7070Sstevel@tonic-gate */
7080Sstevel@tonic-gate tgt = a->tgt;
7090Sstevel@tonic-gate target = mask(tgt);
7100Sstevel@tonic-gate
7110Sstevel@tonic-gate DBG("cmd=%s(%d) tmask=0x%x cmask=0x%x omask=0x%x\n",
712*12004Sjiang.liu@intel.com ap_cmd_name(c), c, target, acp->cmask, acp->omask[tgt]);
7130Sstevel@tonic-gate
7140Sstevel@tonic-gate if ((acp->cmask & target) == 0)
7150Sstevel@tonic-gate ap_err(a, ERR_CMD_NOTSUPP, c);
7160Sstevel@tonic-gate else if (options != NULL && acp->omask[tgt] == 0)
7170Sstevel@tonic-gate ap_err(a, ERR_OPT_INVAL, options);
7180Sstevel@tonic-gate else if (ap_opt_parse(a, acp, options) != -1) {
7190Sstevel@tonic-gate if (c == CMD_STATUS)
7200Sstevel@tonic-gate rc = ap_platopts_check(a, c, c);
7210Sstevel@tonic-gate else
7220Sstevel@tonic-gate rc = CFGA_OK;
7230Sstevel@tonic-gate }
7240Sstevel@tonic-gate
7250Sstevel@tonic-gate if (cmd)
7260Sstevel@tonic-gate *cmd = c;
7270Sstevel@tonic-gate
7280Sstevel@tonic-gate return (rc);
7290Sstevel@tonic-gate }
7300Sstevel@tonic-gate
7310Sstevel@tonic-gate int
ap_cnt(apd_t * a)7320Sstevel@tonic-gate ap_cnt(apd_t *a)
7330Sstevel@tonic-gate {
7340Sstevel@tonic-gate int cnt;
7350Sstevel@tonic-gate
7360Sstevel@tonic-gate if ((a->tgt == AP_BOARD) && ap_getopt(a, OPT_LIST_ALL))
7370Sstevel@tonic-gate cnt = a->ncm + 1;
7380Sstevel@tonic-gate else
7390Sstevel@tonic-gate cnt = 1;
7400Sstevel@tonic-gate
7410Sstevel@tonic-gate return (cnt);
7420Sstevel@tonic-gate }
743