xref: /onnv-gate/usr/src/lib/cfgadm_plugins/sbd/common/ap.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <assert.h>
30*0Sstevel@tonic-gate #include <ctype.h>
31*0Sstevel@tonic-gate #include <stdio.h>
32*0Sstevel@tonic-gate #include <stdlib.h>
33*0Sstevel@tonic-gate #include <string.h>
34*0Sstevel@tonic-gate #include <unistd.h>
35*0Sstevel@tonic-gate #include <macros.h>
36*0Sstevel@tonic-gate #include <dirent.h>
37*0Sstevel@tonic-gate #include <libgen.h>
38*0Sstevel@tonic-gate #include <libdevinfo.h>
39*0Sstevel@tonic-gate #define	CFGA_PLUGIN_LIB
40*0Sstevel@tonic-gate #include <config_admin.h>
41*0Sstevel@tonic-gate #include "ap.h"
42*0Sstevel@tonic-gate 
43*0Sstevel@tonic-gate int
44*0Sstevel@tonic-gate ap_symid(apd_t *a, char *apid, char *symid, size_t bufsize)
45*0Sstevel@tonic-gate {
46*0Sstevel@tonic-gate 	int n;
47*0Sstevel@tonic-gate 	int rc;
48*0Sstevel@tonic-gate 	char path[MAXPATHLEN];
49*0Sstevel@tonic-gate 	char *p;
50*0Sstevel@tonic-gate 	DIR *dirp;
51*0Sstevel@tonic-gate 	struct dirent *dp;
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate 	*symid = '\0';
54*0Sstevel@tonic-gate 	n = sprintf(path, "/dev/cfg/");
55*0Sstevel@tonic-gate 	rc = -1;
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate 	if ((dirp = opendir(path)) == NULL)
58*0Sstevel@tonic-gate 		return (rc);
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate 	p = path + n;
61*0Sstevel@tonic-gate 
62*0Sstevel@tonic-gate 	while ((dp = readdir(dirp)) != NULL) {
63*0Sstevel@tonic-gate 		char buf[MAXPATHLEN];
64*0Sstevel@tonic-gate 		char *cp;
65*0Sstevel@tonic-gate 		size_t len;
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate 		*p = '\0';
68*0Sstevel@tonic-gate 		(void) strcat(path, dp->d_name);
69*0Sstevel@tonic-gate 		if ((len = readlink(path, buf, sizeof (buf))) == (size_t)-1)
70*0Sstevel@tonic-gate 			continue;
71*0Sstevel@tonic-gate 		buf[len] = '\0';
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate 		len = strlen("../");
74*0Sstevel@tonic-gate 		cp = buf;
75*0Sstevel@tonic-gate 		while (strncmp(cp, "../", len) == 0)
76*0Sstevel@tonic-gate 			cp += len;
77*0Sstevel@tonic-gate 		if (cp != buf)
78*0Sstevel@tonic-gate 			cp--;	/* Get the '/' */
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate 		if (strcmp(cp, apid) == 0) {
81*0Sstevel@tonic-gate 			snprintf(symid, bufsize, "%s", dp->d_name);
82*0Sstevel@tonic-gate 			rc = 0;
83*0Sstevel@tonic-gate 			break;
84*0Sstevel@tonic-gate 		}
85*0Sstevel@tonic-gate 	}
86*0Sstevel@tonic-gate 
87*0Sstevel@tonic-gate 	closedir(dirp);
88*0Sstevel@tonic-gate 	return (rc);
89*0Sstevel@tonic-gate }
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate char *
92*0Sstevel@tonic-gate ap_logid(apd_t *a, char *apid)
93*0Sstevel@tonic-gate {
94*0Sstevel@tonic-gate 	int n;
95*0Sstevel@tonic-gate 	char *buf;
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate 	if ((buf = calloc(1, MAXPATHLEN)) == NULL)
98*0Sstevel@tonic-gate 		return (NULL);
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate 	/*
101*0Sstevel@tonic-gate 	 * Look for a symlink.  On any error, fallback to
102*0Sstevel@tonic-gate 	 * driver and instance based logical ap_ids.
103*0Sstevel@tonic-gate 	 */
104*0Sstevel@tonic-gate 	if (ap_symid(a, apid, buf, MAXPATHLEN) == 0)
105*0Sstevel@tonic-gate 		n = strlen(buf);
106*0Sstevel@tonic-gate 	else
107*0Sstevel@tonic-gate 		n = snprintf(buf, MAXPATHLEN, "%s%d:%s",
108*0Sstevel@tonic-gate 		    a->drv, a->inst, a->minor);
109*0Sstevel@tonic-gate 	/*
110*0Sstevel@tonic-gate 	 * Append the dynamic portion, if any.
111*0Sstevel@tonic-gate 	 */
112*0Sstevel@tonic-gate 	if (a->cid != NULL)
113*0Sstevel@tonic-gate 		(void) snprintf(&buf[n], MAXPATHLEN - n, "::%s", a->cid);
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate 	return (buf);
116*0Sstevel@tonic-gate }
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate int
119*0Sstevel@tonic-gate ap_parse(apd_t *a, const char *ap_id)
120*0Sstevel@tonic-gate {
121*0Sstevel@tonic-gate 	int i;
122*0Sstevel@tonic-gate 	int rc;
123*0Sstevel@tonic-gate 	int phys;
124*0Sstevel@tonic-gate 	char c;
125*0Sstevel@tonic-gate 	char *s;
126*0Sstevel@tonic-gate 	char *p;
127*0Sstevel@tonic-gate 	char *q;
128*0Sstevel@tonic-gate 	char *base;
129*0Sstevel@tonic-gate 	int len;
130*0Sstevel@tonic-gate 	char *t;
131*0Sstevel@tonic-gate 
132*0Sstevel@tonic-gate 	if (a == NULL)
133*0Sstevel@tonic-gate 		return (-1);
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate 	a->cnum = -1;
136*0Sstevel@tonic-gate 	a->bnum = -1;
137*0Sstevel@tonic-gate 	a->inst = -1;
138*0Sstevel@tonic-gate 	a->apid = ap_id;
139*0Sstevel@tonic-gate 	rc = ERR_NONE;
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate 	if (!str_valid(ap_id)) {
142*0Sstevel@tonic-gate 		rc = ERR_AP_INVAL;
143*0Sstevel@tonic-gate 		goto done;
144*0Sstevel@tonic-gate 	}
145*0Sstevel@tonic-gate 
146*0Sstevel@tonic-gate 	if ((a->path = strdup(ap_id)) == NULL) {
147*0Sstevel@tonic-gate 		rc = ERR_NOMEM;
148*0Sstevel@tonic-gate 		goto done;
149*0Sstevel@tonic-gate 	}
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate 	/*
152*0Sstevel@tonic-gate 	 * For a physical ap_id, look only at the base part.
153*0Sstevel@tonic-gate 	 * For a logical/symbolic one, use the entire ap_id.
154*0Sstevel@tonic-gate 	 */
155*0Sstevel@tonic-gate 	if (strncmp(a->path, DEVDIR, strlen(DEVDIR)) == 0) {
156*0Sstevel@tonic-gate 		phys = 1;
157*0Sstevel@tonic-gate 		base = strrchr((const char *)a->path, '/') + 1;
158*0Sstevel@tonic-gate 	} else {
159*0Sstevel@tonic-gate 		phys = 0;
160*0Sstevel@tonic-gate 		base = a->path;
161*0Sstevel@tonic-gate 		if ((a->target = strdup(a->path)) == NULL) {
162*0Sstevel@tonic-gate 			rc = ERR_NOMEM;
163*0Sstevel@tonic-gate 			goto done;
164*0Sstevel@tonic-gate 		}
165*0Sstevel@tonic-gate 	}
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate 	if ((s = strchr(base, ':')) == NULL || s[1] == ':') {
168*0Sstevel@tonic-gate 		/*
169*0Sstevel@tonic-gate 		 * No ':' found, or got a '::'.  If this is a physical
170*0Sstevel@tonic-gate 		 * ap_id, it must have a minor separtor ':' which must
171*0Sstevel@tonic-gate 		 * appear before the dynamic part (starting with '::').
172*0Sstevel@tonic-gate 		 * For a symbolic ap_id, skip looking for driver/minor
173*0Sstevel@tonic-gate 		 * names.
174*0Sstevel@tonic-gate 		 */
175*0Sstevel@tonic-gate 		if (phys) {
176*0Sstevel@tonic-gate 			rc = ERR_AP_INVAL;
177*0Sstevel@tonic-gate 			goto done;
178*0Sstevel@tonic-gate 		} else
179*0Sstevel@tonic-gate 			s = base;
180*0Sstevel@tonic-gate 	} else {
181*0Sstevel@tonic-gate 		/*
182*0Sstevel@tonic-gate 		 * Look for driver name/instance only up to the first ':',
183*0Sstevel@tonic-gate 		 * i.e. up to the minor node name.
184*0Sstevel@tonic-gate 		 */
185*0Sstevel@tonic-gate 		*s = '\0';
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate 		if ((p = strchr(base, '@')) != NULL) {
188*0Sstevel@tonic-gate 			/*
189*0Sstevel@tonic-gate 			 * Get the driver name/instance.
190*0Sstevel@tonic-gate 			 */
191*0Sstevel@tonic-gate 			*p = '\0';
192*0Sstevel@tonic-gate 			if ((a->drv = strdup(base)) == NULL) {
193*0Sstevel@tonic-gate 				rc = ERR_NOMEM;
194*0Sstevel@tonic-gate 				goto done;
195*0Sstevel@tonic-gate 			}
196*0Sstevel@tonic-gate 			*p++ = '@';
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate 			i = strtol(p, &q, 10);
199*0Sstevel@tonic-gate 			if (q > p)
200*0Sstevel@tonic-gate 				a->inst = i;
201*0Sstevel@tonic-gate 		}
202*0Sstevel@tonic-gate 
203*0Sstevel@tonic-gate 		*s++ = ':';
204*0Sstevel@tonic-gate 		a->minor = s;
205*0Sstevel@tonic-gate 	}
206*0Sstevel@tonic-gate 
207*0Sstevel@tonic-gate 	/*
208*0Sstevel@tonic-gate 	 * Need to go to the end of the string before the :: if any
209*0Sstevel@tonic-gate 	 * If the string is null then we are done
210*0Sstevel@tonic-gate 	 */
211*0Sstevel@tonic-gate 	t = strstr(s, "::");
212*0Sstevel@tonic-gate 	if (t != NULL)
213*0Sstevel@tonic-gate 		len = strlen(t);
214*0Sstevel@tonic-gate 	else
215*0Sstevel@tonic-gate 		len = 0;
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate 	s += (strlen(s) - len);
218*0Sstevel@tonic-gate 
219*0Sstevel@tonic-gate 	p = s;
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 	if (*p == '\0')
222*0Sstevel@tonic-gate 		a->tgt = AP_BOARD;
223*0Sstevel@tonic-gate 	else if (strncmp(p, "::", 2) != 0) {
224*0Sstevel@tonic-gate 		rc = ERR_AP_INVAL;
225*0Sstevel@tonic-gate 		goto done;
226*0Sstevel@tonic-gate 	} else {
227*0Sstevel@tonic-gate 		/*
228*0Sstevel@tonic-gate 		 * Save the component id.
229*0Sstevel@tonic-gate 		 */
230*0Sstevel@tonic-gate 		*p++ = '\0';
231*0Sstevel@tonic-gate 		*p++ = '\0';
232*0Sstevel@tonic-gate 		a->cid = p;
233*0Sstevel@tonic-gate 	}
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate 	/*
236*0Sstevel@tonic-gate 	 * Get the operation target, e.g. slot0, slot0::cpu0.
237*0Sstevel@tonic-gate 	 * At this point, a->path points to the /devices path
238*0Sstevel@tonic-gate 	 * minus the dynamic part, for a physical ap_id. In
239*0Sstevel@tonic-gate 	 * the case of a logical ap_id, the target is already
240*0Sstevel@tonic-gate 	 * initialized above.
241*0Sstevel@tonic-gate 	 */
242*0Sstevel@tonic-gate 	if (phys != 0 && (a->target = ap_logid(a, a->path)) == NULL) {
243*0Sstevel@tonic-gate 		rc = ERR_NOMEM;
244*0Sstevel@tonic-gate 		goto done;
245*0Sstevel@tonic-gate 	}
246*0Sstevel@tonic-gate 
247*0Sstevel@tonic-gate 	if (a->tgt == AP_BOARD)
248*0Sstevel@tonic-gate 		goto done;
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate 	while ((*p != '\0') && !isdigit(*p))
251*0Sstevel@tonic-gate 		p++;
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 	/*
254*0Sstevel@tonic-gate 	 * Get the component unit number, if present.
255*0Sstevel@tonic-gate 	 */
256*0Sstevel@tonic-gate 	i = strtol(p, &s, 10);
257*0Sstevel@tonic-gate 	/*
258*0Sstevel@tonic-gate 	 * There must be no characters after the unit number.
259*0Sstevel@tonic-gate 	 */
260*0Sstevel@tonic-gate 	if (*s != '\0') {
261*0Sstevel@tonic-gate 		rc = ERR_CM_INVAL;
262*0Sstevel@tonic-gate 		goto done;
263*0Sstevel@tonic-gate 	}
264*0Sstevel@tonic-gate 	if (s > p) {
265*0Sstevel@tonic-gate 		/*
266*0Sstevel@tonic-gate 		 * Disallow leading zeroes, e.g. cpu00, cpu01, cpu001.
267*0Sstevel@tonic-gate 		 * If there are 2 or more digits and the first is a zero,
268*0Sstevel@tonic-gate 		 * we fail.
269*0Sstevel@tonic-gate 		 */
270*0Sstevel@tonic-gate 		if ((s-p) >= 2 && *p == '0') {
271*0Sstevel@tonic-gate 			rc = ERR_CM_INVAL;
272*0Sstevel@tonic-gate 			goto done;
273*0Sstevel@tonic-gate 		}
274*0Sstevel@tonic-gate 		a->cnum = i;
275*0Sstevel@tonic-gate 	}
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate 	c = *p;
278*0Sstevel@tonic-gate 	*p = '\0';
279*0Sstevel@tonic-gate 	if ((a->cname = strdup(a->cid)) == NULL)
280*0Sstevel@tonic-gate 		rc = ERR_NOMEM;
281*0Sstevel@tonic-gate 	*p = c;
282*0Sstevel@tonic-gate done:
283*0Sstevel@tonic-gate 	switch (rc) {
284*0Sstevel@tonic-gate 	case ERR_NONE:
285*0Sstevel@tonic-gate 		break;
286*0Sstevel@tonic-gate 	case ERR_CM_INVAL:
287*0Sstevel@tonic-gate 		ap_err(a, ERR_CM_INVAL, a->cid);
288*0Sstevel@tonic-gate 		break;
289*0Sstevel@tonic-gate 	default:
290*0Sstevel@tonic-gate 		ap_err(a, rc);
291*0Sstevel@tonic-gate 		break;
292*0Sstevel@tonic-gate 	}
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate 	DBG("path=<%s> ", a->path ? a->path : "");
295*0Sstevel@tonic-gate 	DBG("drv=<%s> inst=%d minor=<%s> ",
296*0Sstevel@tonic-gate 		a->drv ? a->drv : "", a->inst, a->minor ? a->minor : "");
297*0Sstevel@tonic-gate 	DBG("target=<%s>\n", a->target ? a->target : "");
298*0Sstevel@tonic-gate 	DBG("cid=<%s> ", a->cid ? a->cid : "");
299*0Sstevel@tonic-gate 	DBG("cname=<%s> ", a->cname ? a->cname : "");
300*0Sstevel@tonic-gate 	DBG("cnum=%d\n", a->cnum);
301*0Sstevel@tonic-gate 	DBG("tgt=%d opts=%x\n", a->tgt, a->opts.flags);
302*0Sstevel@tonic-gate 
303*0Sstevel@tonic-gate 	return (rc == ERR_NONE? 0 :  -1);
304*0Sstevel@tonic-gate }
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate /*
307*0Sstevel@tonic-gate  * Command table.
308*0Sstevel@tonic-gate  *
309*0Sstevel@tonic-gate  * The first set of commands in the table are in sequencing order,
310*0Sstevel@tonic-gate  * for example, the first group starts with assign and ends with
311*0Sstevel@tonic-gate  * configure.  command sequencer relies on this ordering.
312*0Sstevel@tonic-gate  */
313*0Sstevel@tonic-gate static char *
314*0Sstevel@tonic-gate ap_cmd_names[] = {
315*0Sstevel@tonic-gate 	"assign",
316*0Sstevel@tonic-gate 	"poweron",
317*0Sstevel@tonic-gate 	"test",
318*0Sstevel@tonic-gate 	"connect",
319*0Sstevel@tonic-gate 	"configure",
320*0Sstevel@tonic-gate 	"notify online",
321*0Sstevel@tonic-gate 	"notify add capacity",
322*0Sstevel@tonic-gate 	"suspend check",
323*0Sstevel@tonic-gate 	"request suspend",
324*0Sstevel@tonic-gate 	"request delete capacity",
325*0Sstevel@tonic-gate 	"request offline",
326*0Sstevel@tonic-gate 	"unconfigure",
327*0Sstevel@tonic-gate 	"notify remove",
328*0Sstevel@tonic-gate 	"notify capacity change",
329*0Sstevel@tonic-gate 	"disconnect",
330*0Sstevel@tonic-gate 	"poweroff",
331*0Sstevel@tonic-gate 	"unassign",
332*0Sstevel@tonic-gate 	"notify resume",
333*0Sstevel@tonic-gate 	"status",
334*0Sstevel@tonic-gate 	"getncm",
335*0Sstevel@tonic-gate 	"passthru",
336*0Sstevel@tonic-gate 	"help",
337*0Sstevel@tonic-gate 	"errtest",
338*0Sstevel@tonic-gate 	NULL
339*0Sstevel@tonic-gate };
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate char *
342*0Sstevel@tonic-gate ap_cmd_name(int i)
343*0Sstevel@tonic-gate {
344*0Sstevel@tonic-gate 	return (ap_cmd_names[min(i, CMD_NONE)]);
345*0Sstevel@tonic-gate }
346*0Sstevel@tonic-gate 
347*0Sstevel@tonic-gate static char *
348*0Sstevel@tonic-gate ap_opt_names[] = {
349*0Sstevel@tonic-gate 	"unassign",
350*0Sstevel@tonic-gate 	"skip",
351*0Sstevel@tonic-gate 	"parsable",
352*0Sstevel@tonic-gate 	"nopoweroff",
353*0Sstevel@tonic-gate 	"code",
354*0Sstevel@tonic-gate 	"mid",
355*0Sstevel@tonic-gate 	"err",
356*0Sstevel@tonic-gate 	"platform",
357*0Sstevel@tonic-gate 	"sim",
358*0Sstevel@tonic-gate 	NULL
359*0Sstevel@tonic-gate };
360*0Sstevel@tonic-gate 
361*0Sstevel@tonic-gate char *
362*0Sstevel@tonic-gate ap_opt_name(int i)
363*0Sstevel@tonic-gate {
364*0Sstevel@tonic-gate 	return (ap_opt_names[i]);
365*0Sstevel@tonic-gate }
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate /*
368*0Sstevel@tonic-gate  * Command descriptor.
369*0Sstevel@tonic-gate  *
370*0Sstevel@tonic-gate  * Each command has a (command) mask specifying the AP target classes
371*0Sstevel@tonic-gate  * it operates on, e.g. the assign command applies only to boards.
372*0Sstevel@tonic-gate  * In addition each AP target class has a separate option mask specifying
373*0Sstevel@tonic-gate  * which command options are valid for that target class.
374*0Sstevel@tonic-gate  * A global value mask specifies which options require values.
375*0Sstevel@tonic-gate  */
376*0Sstevel@tonic-gate typedef struct {
377*0Sstevel@tonic-gate 	int cmd;
378*0Sstevel@tonic-gate 	uint_t cmask;
379*0Sstevel@tonic-gate 	uint_t omask[AP_NCLASS];
380*0Sstevel@tonic-gate } ap_cmd_t;
381*0Sstevel@tonic-gate 
382*0Sstevel@tonic-gate /*
383*0Sstevel@tonic-gate  * Command option definitions.
384*0Sstevel@tonic-gate  */
385*0Sstevel@tonic-gate #define	SHFT(i)	((uint_t)1 << (i))
386*0Sstevel@tonic-gate #define	NULOPT	0
387*0Sstevel@tonic-gate #define	ALLOPT	0xffffffff
388*0Sstevel@tonic-gate #define	CMNOPT	(SHFT(OPT_VERBOSE)|SHFT(OPT_PLATFORM)|SHFT(OPT_SIM))
389*0Sstevel@tonic-gate #define	CMFOPT	(CMNOPT|SHFT(OPT_FORCE))
390*0Sstevel@tonic-gate #define	STSOPT	(CMNOPT|SHFT(OPT_PARSABLE))
391*0Sstevel@tonic-gate #define	BRDDCN	(CMNOPT|SHFT(OPT_UNASSIGN)|SHFT(OPT_NOPOWEROFF))
392*0Sstevel@tonic-gate 
393*0Sstevel@tonic-gate #define	BRD	SHFT(AP_BOARD)
394*0Sstevel@tonic-gate #define	BIO	SHFT(AP_BOARD)|SHFT(AP_IO)
395*0Sstevel@tonic-gate #define	ALL	(BRD|SHFT(AP_CPU)|SHFT(AP_MEM)|SHFT(AP_IO)|SHFT(AP_CMP))
396*0Sstevel@tonic-gate 
397*0Sstevel@tonic-gate static ap_cmd_t
398*0Sstevel@tonic-gate ap_cmds[] = {
399*0Sstevel@tonic-gate 	/*
400*0Sstevel@tonic-gate 	 *	cmd		cmd	 board	 cpu	 mem	 io	cmp
401*0Sstevel@tonic-gate 	 *			cmask	 omask	 omask   omask   omask	omask
402*0Sstevel@tonic-gate 	 */
403*0Sstevel@tonic-gate 	{CMD_ASSIGN,		BRD, 0, CMNOPT, NULOPT, NULOPT, NULOPT, NULOPT},
404*0Sstevel@tonic-gate 	{CMD_UNASSIGN,		BRD, 0, CMNOPT, NULOPT, NULOPT, NULOPT, NULOPT},
405*0Sstevel@tonic-gate 	{CMD_POWERON,		BRD, 0, CMNOPT, NULOPT, NULOPT, NULOPT, NULOPT},
406*0Sstevel@tonic-gate 	{CMD_POWEROFF,		BRD, 0, CMNOPT, NULOPT, NULOPT, NULOPT, NULOPT},
407*0Sstevel@tonic-gate 	{CMD_CONNECT,		BRD, 0, CMFOPT, NULOPT, NULOPT, NULOPT, NULOPT},
408*0Sstevel@tonic-gate 	{CMD_DISCONNECT,	BRD, 0, BRDDCN, NULOPT, NULOPT, NULOPT, NULOPT},
409*0Sstevel@tonic-gate 	{CMD_CONFIGURE,		ALL, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
410*0Sstevel@tonic-gate 	{CMD_UNCONFIGURE,	ALL, 0, CMFOPT, CMFOPT, CMFOPT, CMFOPT, CMNOPT},
411*0Sstevel@tonic-gate 	{CMD_RCM_OFFLINE,	BIO, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
412*0Sstevel@tonic-gate 	{CMD_RCM_ONLINE,	BIO, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
413*0Sstevel@tonic-gate 	{CMD_RCM_SUSPEND,	BIO, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
414*0Sstevel@tonic-gate 	{CMD_RCM_RESUME,	BIO, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
415*0Sstevel@tonic-gate 	{CMD_RCM_CAP_ADD,	BIO, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
416*0Sstevel@tonic-gate 	{CMD_RCM_CAP_DEL,	BIO, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
417*0Sstevel@tonic-gate 	{CMD_RCM_CAP_NOTIFY,	BIO, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
418*0Sstevel@tonic-gate 	{CMD_RCM_REMOVE,	BIO, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
419*0Sstevel@tonic-gate 	{CMD_TEST,		BRD, 0, CMFOPT, NULOPT, NULOPT, NULOPT, NULOPT},
420*0Sstevel@tonic-gate 	{CMD_STATUS,		ALL, 0, STSOPT, STSOPT, STSOPT, STSOPT, STSOPT},
421*0Sstevel@tonic-gate 	{CMD_GETNCM,		BRD, 0, CMNOPT, NULOPT, NULOPT, NULOPT, NULOPT},
422*0Sstevel@tonic-gate 	{CMD_PASSTHRU,		ALL, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
423*0Sstevel@tonic-gate 	{CMD_HELP,		ALL, 0, CMNOPT, CMNOPT, CMNOPT, CMNOPT, CMNOPT},
424*0Sstevel@tonic-gate 	{CMD_ERRTEST,		ALL, 0, ALLOPT, ALLOPT, ALLOPT, ALLOPT, ALLOPT},
425*0Sstevel@tonic-gate 	{CMD_NONE,		0,   0,	0,	0,	0,	0,	0    }
426*0Sstevel@tonic-gate };
427*0Sstevel@tonic-gate 
428*0Sstevel@tonic-gate /*
429*0Sstevel@tonic-gate  * Global mask for options that require values.
430*0Sstevel@tonic-gate  */
431*0Sstevel@tonic-gate #define	AP_VMASK (\
432*0Sstevel@tonic-gate 	SHFT(OPT_CODE)|SHFT(OPT_MID)|SHFT(OPT_ERR)| \
433*0Sstevel@tonic-gate 	SHFT(OPT_PLATFORM)|SHFT(OPT_SKIP))
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate #if SBD_DEBUG
436*0Sstevel@tonic-gate void
437*0Sstevel@tonic-gate ap_cmds_dump()
438*0Sstevel@tonic-gate {
439*0Sstevel@tonic-gate 	int i;
440*0Sstevel@tonic-gate 	ap_cmd_t *acp;
441*0Sstevel@tonic-gate 
442*0Sstevel@tonic-gate 	dbg("vmask=0x%x\n", AP_VMASK);
443*0Sstevel@tonic-gate 	dbg("%23s%5s%5s%9s%9s%9s%9s%9s\n",
444*0Sstevel@tonic-gate 	    "cmd", "msk", "none", "brd", "cpu", "mem", "io", "cmp");
445*0Sstevel@tonic-gate 
446*0Sstevel@tonic-gate 	for (acp = ap_cmds; acp->cmd != CMD_NONE; acp++) {
447*0Sstevel@tonic-gate 		dbg("%23s%5x%5x", ap_cmd_name(acp->cmd), acp->cmask,
448*0Sstevel@tonic-gate 		    acp->omask[AP_NONE]);
449*0Sstevel@tonic-gate 		for (i = AP_BOARD; i < AP_NCLASS; i++) {
450*0Sstevel@tonic-gate 			dbg("%9x", acp->omask[i]);
451*0Sstevel@tonic-gate 		}
452*0Sstevel@tonic-gate 		dbg("\n");
453*0Sstevel@tonic-gate 	}
454*0Sstevel@tonic-gate }
455*0Sstevel@tonic-gate #endif
456*0Sstevel@tonic-gate 
457*0Sstevel@tonic-gate int
458*0Sstevel@tonic-gate ap_state_cmd(cfga_cmd_t i, int *cmd)
459*0Sstevel@tonic-gate {
460*0Sstevel@tonic-gate 	int c;
461*0Sstevel@tonic-gate 	int rc;
462*0Sstevel@tonic-gate 
463*0Sstevel@tonic-gate 	rc = CFGA_OK;
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate 	switch (i) {
466*0Sstevel@tonic-gate 	case CFGA_CMD_CONNECT:
467*0Sstevel@tonic-gate 		c = CMD_CONNECT;
468*0Sstevel@tonic-gate 		break;
469*0Sstevel@tonic-gate 	case CFGA_CMD_DISCONNECT:
470*0Sstevel@tonic-gate 		c = CMD_DISCONNECT;
471*0Sstevel@tonic-gate 		break;
472*0Sstevel@tonic-gate 	case CFGA_CMD_CONFIGURE:
473*0Sstevel@tonic-gate 		c = CMD_CONFIGURE;
474*0Sstevel@tonic-gate 		break;
475*0Sstevel@tonic-gate 	case CFGA_CMD_UNCONFIGURE:
476*0Sstevel@tonic-gate 		c = CMD_UNCONFIGURE;
477*0Sstevel@tonic-gate 		break;
478*0Sstevel@tonic-gate 	case CFGA_CMD_LOAD:
479*0Sstevel@tonic-gate 	case CFGA_CMD_UNLOAD:
480*0Sstevel@tonic-gate 		rc = CFGA_OPNOTSUPP;
481*0Sstevel@tonic-gate 		c = CMD_NONE;
482*0Sstevel@tonic-gate 		break;
483*0Sstevel@tonic-gate 	default:
484*0Sstevel@tonic-gate 		rc = CFGA_INVAL;
485*0Sstevel@tonic-gate 		c = CMD_NONE;
486*0Sstevel@tonic-gate 		break;
487*0Sstevel@tonic-gate 	}
488*0Sstevel@tonic-gate 
489*0Sstevel@tonic-gate 	*cmd = c;
490*0Sstevel@tonic-gate 
491*0Sstevel@tonic-gate 	return (rc);
492*0Sstevel@tonic-gate }
493*0Sstevel@tonic-gate 
494*0Sstevel@tonic-gate static int
495*0Sstevel@tonic-gate ap_cmd(char *name)
496*0Sstevel@tonic-gate {
497*0Sstevel@tonic-gate 	int i;
498*0Sstevel@tonic-gate 	char **p;
499*0Sstevel@tonic-gate 
500*0Sstevel@tonic-gate 	if (name == NULL)
501*0Sstevel@tonic-gate 		return (CMD_NONE);
502*0Sstevel@tonic-gate 
503*0Sstevel@tonic-gate 	for (i = 0, p = ap_cmd_names; *p != NULL; p++, i++)
504*0Sstevel@tonic-gate 		if (strcmp(*p, name) == 0)
505*0Sstevel@tonic-gate 			break;
506*0Sstevel@tonic-gate 	if (*p == NULL)
507*0Sstevel@tonic-gate 		i = CMD_NONE;
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate 	return (i);
510*0Sstevel@tonic-gate }
511*0Sstevel@tonic-gate 
512*0Sstevel@tonic-gate static int
513*0Sstevel@tonic-gate ap_opt_parse(apd_t *a, ap_cmd_t *acp, const char *options)
514*0Sstevel@tonic-gate {
515*0Sstevel@tonic-gate 	char *optstr;
516*0Sstevel@tonic-gate 	ap_opts_t *opts;
517*0Sstevel@tonic-gate 
518*0Sstevel@tonic-gate 	/*
519*0Sstevel@tonic-gate 	 * Set default values.
520*0Sstevel@tonic-gate 	 */
521*0Sstevel@tonic-gate 	opts = &a->opts;
522*0Sstevel@tonic-gate 	opts->mid = (char *)a->class;
523*0Sstevel@tonic-gate 	opts->err = ERR_CMD_FAIL;
524*0Sstevel@tonic-gate 
525*0Sstevel@tonic-gate 	if (options == NULL)
526*0Sstevel@tonic-gate 		return (0);
527*0Sstevel@tonic-gate 
528*0Sstevel@tonic-gate 	if ((optstr = strdup(options)) == NULL) {
529*0Sstevel@tonic-gate 		ap_err(a, ERR_NOMEM);
530*0Sstevel@tonic-gate 		return (-1);
531*0Sstevel@tonic-gate 	}
532*0Sstevel@tonic-gate 
533*0Sstevel@tonic-gate 	a->options = optstr;
534*0Sstevel@tonic-gate 
535*0Sstevel@tonic-gate 	if (acp->cmd == CMD_PASSTHRU)
536*0Sstevel@tonic-gate 		return (0);
537*0Sstevel@tonic-gate 
538*0Sstevel@tonic-gate 	while (*optstr != '\0') {
539*0Sstevel@tonic-gate 		int i;
540*0Sstevel@tonic-gate 		int opt;
541*0Sstevel@tonic-gate 		int omask;
542*0Sstevel@tonic-gate 		char *p;
543*0Sstevel@tonic-gate 		char *value;
544*0Sstevel@tonic-gate 		char *optname;
545*0Sstevel@tonic-gate 
546*0Sstevel@tonic-gate 		value = NULL;
547*0Sstevel@tonic-gate 		opt = getsubopt(&optstr, ap_opt_names, &value);
548*0Sstevel@tonic-gate 
549*0Sstevel@tonic-gate 		DBG("opt=%d\n", opt);
550*0Sstevel@tonic-gate 
551*0Sstevel@tonic-gate 		if (opt == -1) {
552*0Sstevel@tonic-gate 			ap_err(a, ERR_OPT_INVAL, value);
553*0Sstevel@tonic-gate 			return (-1);
554*0Sstevel@tonic-gate 		}
555*0Sstevel@tonic-gate 
556*0Sstevel@tonic-gate 		optname = ap_opt_names[opt];
557*0Sstevel@tonic-gate 		omask = acp->omask[a->tgt];
558*0Sstevel@tonic-gate 
559*0Sstevel@tonic-gate 		i = mask(opt) & omask;
560*0Sstevel@tonic-gate 
561*0Sstevel@tonic-gate 		DBG("tgt=%d opt=%x omask=%x\n", a->tgt, mask(opt), omask);
562*0Sstevel@tonic-gate 
563*0Sstevel@tonic-gate 		if (i == 0) {
564*0Sstevel@tonic-gate 			ap_err(a, ERR_OPT_INVAL, optname);
565*0Sstevel@tonic-gate 			return (-1);
566*0Sstevel@tonic-gate 		}
567*0Sstevel@tonic-gate 
568*0Sstevel@tonic-gate 		/*
569*0Sstevel@tonic-gate 		 * Check whether the option requires a value.
570*0Sstevel@tonic-gate 		 */
571*0Sstevel@tonic-gate 		i = mask(opt) & AP_VMASK;
572*0Sstevel@tonic-gate 		if (i != 0 && value == NULL) {
573*0Sstevel@tonic-gate 			ap_err(a, ERR_OPT_NOVAL, optname);
574*0Sstevel@tonic-gate 			return (-1);
575*0Sstevel@tonic-gate 		} else if (i == 0 && value != NULL) {
576*0Sstevel@tonic-gate 			ap_err(a, ERR_OPT_VAL, optname);
577*0Sstevel@tonic-gate 			return (-1);
578*0Sstevel@tonic-gate 		}
579*0Sstevel@tonic-gate 
580*0Sstevel@tonic-gate 		if (value == NULL)
581*0Sstevel@tonic-gate 			assert(opt != OPT_CODE);	/* XXX prefix */
582*0Sstevel@tonic-gate 
583*0Sstevel@tonic-gate 		/*
584*0Sstevel@tonic-gate 		 * Set the options's value.
585*0Sstevel@tonic-gate 		 */
586*0Sstevel@tonic-gate 		switch (opt) {
587*0Sstevel@tonic-gate 		case OPT_SIM:
588*0Sstevel@tonic-gate 		case OPT_PARSABLE:
589*0Sstevel@tonic-gate 		case OPT_UNASSIGN:
590*0Sstevel@tonic-gate 			break;
591*0Sstevel@tonic-gate 		case OPT_CODE:
592*0Sstevel@tonic-gate 			i = strtol(value, &p, 10);
593*0Sstevel@tonic-gate 			if (p > value)
594*0Sstevel@tonic-gate 				opts->code = i;
595*0Sstevel@tonic-gate 			break;
596*0Sstevel@tonic-gate 		case OPT_MID:
597*0Sstevel@tonic-gate 			opts->mid = value;
598*0Sstevel@tonic-gate 			break;
599*0Sstevel@tonic-gate 		case OPT_ERR:
600*0Sstevel@tonic-gate 			i = strtol(value, &p, 10);
601*0Sstevel@tonic-gate 			if (p > value)
602*0Sstevel@tonic-gate 				opts->err = i;
603*0Sstevel@tonic-gate 			break;
604*0Sstevel@tonic-gate 		case OPT_NOPOWEROFF:
605*0Sstevel@tonic-gate 			i = ap_cmd("poweroff");
606*0Sstevel@tonic-gate 			opts->skip |= mask(i);
607*0Sstevel@tonic-gate 			break;
608*0Sstevel@tonic-gate 		case OPT_SKIP:	/* for debugging */
609*0Sstevel@tonic-gate 			/*
610*0Sstevel@tonic-gate 			 * The skip value may be a ':' separated
611*0Sstevel@tonic-gate 			 * list of steps (commands) to be skipped
612*0Sstevel@tonic-gate 			 * during sequencing.
613*0Sstevel@tonic-gate 			 */
614*0Sstevel@tonic-gate 			for (p = strtok(value, ":"); p != NULL;
615*0Sstevel@tonic-gate 				p = strtok(NULL, ":")) {
616*0Sstevel@tonic-gate 				if ((i = ap_cmd(p)) == CMD_NONE) {
617*0Sstevel@tonic-gate 					ap_err(a, ERR_CMD_INVAL, p);
618*0Sstevel@tonic-gate 					return (-1);
619*0Sstevel@tonic-gate 				}
620*0Sstevel@tonic-gate 				opts->skip |= mask(i);
621*0Sstevel@tonic-gate 			}
622*0Sstevel@tonic-gate 			break;
623*0Sstevel@tonic-gate 		case OPT_PLATFORM:
624*0Sstevel@tonic-gate 			opts->platform = value;
625*0Sstevel@tonic-gate 			break;
626*0Sstevel@tonic-gate 		default:
627*0Sstevel@tonic-gate 			ap_err(a, ERR_OPT_INVAL, optname);
628*0Sstevel@tonic-gate 			return (-1);
629*0Sstevel@tonic-gate 		}
630*0Sstevel@tonic-gate 
631*0Sstevel@tonic-gate 		ap_setopt(a, opt);
632*0Sstevel@tonic-gate 	}
633*0Sstevel@tonic-gate 
634*0Sstevel@tonic-gate 	return (0);
635*0Sstevel@tonic-gate }
636*0Sstevel@tonic-gate 
637*0Sstevel@tonic-gate static ap_cmd_t *
638*0Sstevel@tonic-gate ap_cmdp(int cmd)
639*0Sstevel@tonic-gate {
640*0Sstevel@tonic-gate 	ap_cmd_t *acp;
641*0Sstevel@tonic-gate 
642*0Sstevel@tonic-gate 	for (acp = ap_cmds; acp->cmd != CMD_NONE; acp++)
643*0Sstevel@tonic-gate 		if (acp->cmd == cmd)
644*0Sstevel@tonic-gate 			break;
645*0Sstevel@tonic-gate 
646*0Sstevel@tonic-gate 	if (acp->cmd == CMD_NONE)
647*0Sstevel@tonic-gate 		return (NULL);
648*0Sstevel@tonic-gate 
649*0Sstevel@tonic-gate 	return (acp);
650*0Sstevel@tonic-gate }
651*0Sstevel@tonic-gate 
652*0Sstevel@tonic-gate cfga_err_t
653*0Sstevel@tonic-gate ap_cmd_parse(apd_t *a, const char *f, const char *options, int *cmd)
654*0Sstevel@tonic-gate {
655*0Sstevel@tonic-gate 	int c;
656*0Sstevel@tonic-gate 	int all;
657*0Sstevel@tonic-gate 	int tgt;
658*0Sstevel@tonic-gate 	int target;
659*0Sstevel@tonic-gate 	ap_cmd_t *acp;
660*0Sstevel@tonic-gate 	cfga_err_t rc;
661*0Sstevel@tonic-gate 
662*0Sstevel@tonic-gate #ifdef	_SBD_DEBUG
663*0Sstevel@tonic-gate 	ap_cmds_dump();
664*0Sstevel@tonic-gate #endif
665*0Sstevel@tonic-gate 
666*0Sstevel@tonic-gate 	rc = CFGA_INVAL;
667*0Sstevel@tonic-gate 
668*0Sstevel@tonic-gate 	if ((c = ap_cmd((char *)f)) == CMD_NONE ||
669*0Sstevel@tonic-gate 	    (acp = ap_cmdp(c)) == NULL) {
670*0Sstevel@tonic-gate 		ap_err(a, ERR_CMD_INVAL, f);
671*0Sstevel@tonic-gate 		return (rc);
672*0Sstevel@tonic-gate 	}
673*0Sstevel@tonic-gate 
674*0Sstevel@tonic-gate 	/*
675*0Sstevel@tonic-gate 	 * Change a->statonly to 1, if the case is CMD_STATUS.  We are only
676*0Sstevel@tonic-gate 	 * wanting to read the devices and no more
677*0Sstevel@tonic-gate 	 */
678*0Sstevel@tonic-gate 	/*
679*0Sstevel@tonic-gate 	 * Get the status for all components if either the list all
680*0Sstevel@tonic-gate 	 * option being specified or if we are configuring/unconfiguring
681*0Sstevel@tonic-gate 	 * the board.  The latter is needed for the RCM interface.
682*0Sstevel@tonic-gate 	 */
683*0Sstevel@tonic-gate 	switch (c) {
684*0Sstevel@tonic-gate 	case CMD_STATUS:
685*0Sstevel@tonic-gate 		all = ap_getopt(a, OPT_LIST_ALL);
686*0Sstevel@tonic-gate 		a->statonly = 1;
687*0Sstevel@tonic-gate 		break;
688*0Sstevel@tonic-gate 	case CMD_CONFIGURE:
689*0Sstevel@tonic-gate 	case CMD_UNCONFIGURE:
690*0Sstevel@tonic-gate 	case CMD_CONNECT:
691*0Sstevel@tonic-gate 	case CMD_DISCONNECT:
692*0Sstevel@tonic-gate 		all = (a->tgt == AP_BOARD);
693*0Sstevel@tonic-gate 		a->statonly = 0;
694*0Sstevel@tonic-gate 		break;
695*0Sstevel@tonic-gate 	default:
696*0Sstevel@tonic-gate 		all = 0;
697*0Sstevel@tonic-gate 		a->statonly = 0;
698*0Sstevel@tonic-gate 		break;
699*0Sstevel@tonic-gate 	}
700*0Sstevel@tonic-gate 
701*0Sstevel@tonic-gate 	if ((rc = apd_init(a, all)) != CFGA_OK)
702*0Sstevel@tonic-gate 		return (rc);
703*0Sstevel@tonic-gate 
704*0Sstevel@tonic-gate 	rc = CFGA_INVAL;
705*0Sstevel@tonic-gate 
706*0Sstevel@tonic-gate 	/*
707*0Sstevel@tonic-gate 	 * Get the target here in case it is a component in which
708*0Sstevel@tonic-gate 	 * case its type is known after the initialization.
709*0Sstevel@tonic-gate 	 */
710*0Sstevel@tonic-gate 	tgt = a->tgt;
711*0Sstevel@tonic-gate 	target = mask(tgt);
712*0Sstevel@tonic-gate 
713*0Sstevel@tonic-gate 	DBG("cmd=%s(%d) tmask=0x%x cmask=0x%x omask=0x%x\n",
714*0Sstevel@tonic-gate 		ap_cmd_name(c), c, target,
715*0Sstevel@tonic-gate 		acp->cmask, acp->omask[tgt]);
716*0Sstevel@tonic-gate 
717*0Sstevel@tonic-gate 	if ((acp->cmask & target) == 0)
718*0Sstevel@tonic-gate 		ap_err(a, ERR_CMD_NOTSUPP, c);
719*0Sstevel@tonic-gate 	else if (options != NULL && acp->omask[tgt] == 0)
720*0Sstevel@tonic-gate 		ap_err(a, ERR_OPT_INVAL, options);
721*0Sstevel@tonic-gate 	else if (ap_opt_parse(a, acp, options) != -1) {
722*0Sstevel@tonic-gate 		if (c == CMD_STATUS)
723*0Sstevel@tonic-gate 			rc = ap_platopts_check(a, c, c);
724*0Sstevel@tonic-gate 		else
725*0Sstevel@tonic-gate 			rc = CFGA_OK;
726*0Sstevel@tonic-gate 	}
727*0Sstevel@tonic-gate 
728*0Sstevel@tonic-gate 	if (cmd)
729*0Sstevel@tonic-gate 		*cmd = c;
730*0Sstevel@tonic-gate 
731*0Sstevel@tonic-gate 	return (rc);
732*0Sstevel@tonic-gate }
733*0Sstevel@tonic-gate 
734*0Sstevel@tonic-gate int
735*0Sstevel@tonic-gate ap_cnt(apd_t *a)
736*0Sstevel@tonic-gate {
737*0Sstevel@tonic-gate 	int cnt;
738*0Sstevel@tonic-gate 
739*0Sstevel@tonic-gate 	if ((a->tgt == AP_BOARD) && ap_getopt(a, OPT_LIST_ALL))
740*0Sstevel@tonic-gate 		cnt = a->ncm + 1;
741*0Sstevel@tonic-gate 	else
742*0Sstevel@tonic-gate 		cnt = 1;
743*0Sstevel@tonic-gate 
744*0Sstevel@tonic-gate 	return (cnt);
745*0Sstevel@tonic-gate }
746