xref: /onnv-gate/usr/src/lib/cfgadm_plugins/sbd/common/ap.c (revision 12004:93f274d4a367)
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