xref: /illumos-gate/usr/src/lib/cfgadm_plugins/sysctrl/common/cfga.c (revision 6446bd46ed1b4e9f69da153665f82181ccaedad5)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <stddef.h>
28 #include <locale.h>
29 #include <ctype.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <errno.h>
36 #include <locale.h>
37 #include <langinfo.h>
38 #include <time.h>
39 #include <stdarg.h>
40 #include <sys/types.h>
41 #include <sys/ioctl.h>
42 #include <sys/dditypes.h>
43 #include <sys/modctl.h>
44 #include <sys/obpdefs.h>
45 #include <sys/fhc.h>
46 #include <sys/sysctrl.h>
47 #include <sys/openpromio.h>
48 #ifdef	SIM
49 #include <sys/stat.h>
50 #endif
51 #define	CFGA_PLUGIN_LIB
52 #include <config_admin.h>
53 
54 #ifdef	DEBUG
55 #define	DBG	printf
56 #define	DBG1	printf
57 #define	DBG3	printf
58 #define	DBG4	printf
59 #else
60 #define	DBG(a, b)
61 #define	DBG1(a)
62 #define	DBG3(a, b, c)
63 #define	DBG4(a, b, c, d)
64 #endif
65 
66 #define	BD_CPU			1
67 #define	BD_MEM			2
68 #define	BD_IO_2SBUS		3
69 #define	BD_IO_SBUS_FFB		4
70 #define	BD_IO_PCI		5
71 #define	BD_DISK			6
72 #define	BD_IO_2SBUS_SOCPLUS	7
73 #define	BD_IO_SBUS_FFB_SOCPLUS	8
74 #define	BD_UNKNOWN		9
75 #define	CMD_GETSTAT		10
76 #define	CMD_LIST		11
77 #define	CMD_CONNECT		12
78 #define	CMD_DISCONNECT		13
79 #define	CMD_CONFIGURE		14
80 #define	CMD_UNCONFIGURE		15
81 #define	CMD_QUIESCE		16
82 #define	CMD_INSERT		17
83 #define	CMD_REMOVE		18
84 #define	CMD_SET_COND		19
85 #define	OPT_ENABLE		20
86 #define	OPT_DISABLE		21
87 #define	ERR_PROM_OPEN		22
88 #define	ERR_PROM_GETPROP	23
89 #define	ERR_PROM_SETPROP	24
90 #define	ERR_TRANS		25
91 #define	ERR_CMD_INVAL		26
92 #define	ERR_OPT_INVAL		27
93 #define	ERR_AP_INVAL		28
94 #define	ERR_DISABLED		29
95 #define	DIAG_FORCE		30
96 #define	DIAG_TRANS_OK		31
97 #define	DIAG_FAILED		32
98 #define	DIAG_WAS_ENABLED	33
99 #define	DIAG_WAS_DISABLED	34
100 #define	DIAG_WILL_ENABLE	35
101 #define	DIAG_WILL_DISABLE	36
102 #define	HELP_HEADER		37
103 #define	HELP_QUIESCE		38
104 #define	HELP_INSERT		39
105 #define	HELP_REMOVE		40
106 #define	HELP_SET_COND		41
107 #define	HELP_ENABLE		42
108 #define	HELP_DISABLE		43
109 #define	HELP_UNKNOWN		44
110 #define	ASK_CONNECT		45
111 #define	STR_BD			46
112 #define	STR_COL			47
113 #define	COND_UNKNOWN		48
114 #define	COND_OK			49
115 #define	COND_FAILING		50
116 #define	COND_FAILED		51
117 #define	COND_UNUSABLE		52
118 #define	SYSC_COOLING		53
119 #define	SYSC_POWER		54
120 #define	SYSC_PRECHARGE		55
121 #define	SYSC_INTRANS		56
122 #define	SYSC_UTHREAD		57
123 #define	SYSC_KTHREAD		58
124 #define	SYSC_DEV_ATTACH		59
125 #define	SYSC_DEV_DETACH		60
126 #define	SYSC_NDI_ATTACH		61
127 #define	SYSC_NDI_DETACH		62
128 #define	SYSC_CORE_RESOURCE	63
129 #define	SYSC_OSTATE		64
130 #define	SYSC_RSTATE		65
131 #define	SYSC_COND		66
132 #define	SYSC_PROM		67
133 #define	SYSC_NOMEM		68
134 #define	SYSC_HOTPLUG		69
135 #define	SYSC_HW_COMPAT		70
136 #define	SYSC_NON_DR_PROM	71
137 #define	SYSC_SUSPEND		72
138 #define	SYSC_RESUME		73
139 #define	SYSC_UNKNOWN		74
140 #define	SYSC_DEVSTR		75
141 
142 /*
143  * The string table contains all the strings used by the platform
144  * library.  The comment next to each string specifies whether the
145  * string should be internationalized (y) or not (n).
146  * Note that there are calls to dgettext() with strings other than
147  * the ones below, they are marked by the li18 symbol.
148  */
149 static char *
150 cfga_strs[] = {
151 	/*   */ NULL,
152 	/* n */ "cpu/mem   ",
153 	/* n */ "mem       ",
154 	/* n */ "dual-sbus ",
155 	/* n */ "sbus-upa  ",
156 	/* n */ "dual-pci  ",
157 	/* n */ "disk      ",
158 	/* n */ "soc+sbus  ",
159 	/* n */ "soc+upa   ",
160 	/* n */ "unknown   ",
161 	/* n */ "get-status",
162 	/* n */ "list",
163 	/* n */ "connect",
164 	/* n */ "disconnect",
165 	/* n */ "configure",
166 	/* n */ "unconfigure",
167 	/* n */ "quiesce-test",
168 	/* n */ "insert-test",
169 	/* n */ "remove-test",
170 	/* n */ "set-condition-test",
171 	/* n */ "enable-at-boot",
172 	/* n */ "disable-at-boot",
173 	/* n */ "prom open",
174 	/* n */ "prom getprop",
175 	/* n */ "prom setprop",
176 	/* y */ "invalid transition",
177 	/* y */ "invalid command: ",
178 	/* y */ "invalid option: ",
179 	/* y */ "invalid attachment point: ",
180 	/* y */ "board is disabled: must override with ",
181 	/* n */ "[-f][-o enable-at-boot]",
182 	/* y */ "transition succeeded but ",
183 	/* y */ " failed: ",
184 	/* y */ "was already enabled at boot time",
185 	/* y */ "was already disabled at boot time",
186 	/* y */ "will be enabled at boot time",
187 	/* y */ "will be disabled at boot time",
188 	/* y */ "\nSysctrl specific commands/options:",
189 	/* n */ "\t-x quiesce-test ap_id [ap_id...]",
190 	/* n */ "\t-x insert-test  ap_id [ap_id...]",
191 	/* n */ "\t-x remove-test  ap_id [ap_id...]",
192 	/* n */ "\t-x set-condition-test=<condition>",
193 	/* n */ "\t-o enable-at-boot",
194 	/* n */ "\t-o disable-at-boot",
195 	/* y */ "\tunknown command or option: ",
196 	/* y */
197 	"system will be temporarily suspended to connect a board: proceed",
198 	/* y */ "board ",
199 	/* y */ ": ",
200 	/* n */ "unknown",
201 	/* n */ "ok",
202 	/* n */ "failing",
203 	/* n */ "failed",
204 	/* n */ "unusable",
205 	/* y */ "not enough cooling for a new board",
206 	/* y */ "not enough power for a new board",
207 	/* y */ "not enough precharge power for a new board",
208 	/* y */ "configuration operation already in progress on this board",
209 	/* y */ "could not suspend user process: ",
210 	/* y */ "could not suspend system processes",
211 	/* y */ "device did not attach",
212 	/* y */ "device did not detach",
213 	/* y */ "nexus error during attach",
214 	/* y */ "nexus error during detach",
215 	/* y */ "attempt to remove core system resource",
216 	/* y */ "invalid occupant state",
217 	/* y */ "invalid receptacle state",
218 	/* y */ "insufficient condition",
219 	/* y */ "firmware operation error",
220 	/* y */ "not enough memory",
221 	/* y */ "hotplug feature unavailable on this machine",
222 	/* y */ "board does not support dynamic reconfiguration",
223 	/* y */ "firmware does not support dynamic reconfiguration",
224 	/* y */ "system suspend error",
225 	/* y */ "system resume error",
226 	/* y */ "unknown system error",
227 	/*   */ NULL
228 };
229 
230 #define	cfga_str(i)		cfga_strs[(i)]
231 
232 #define	cfga_eid(a, b)		(((a) << 8) + (b))
233 
234 /*
235  *
236  *	Translation table for mapping from an <errno,sysc_err>
237  *	pair to an error string.
238  *
239  *
240  *	SYSC_COOLING,		EAGAIN,  SYSC_ERR_COOLING
241  *	SYSC_POWER,		EAGAIN,  SYSC_ERR_POWER
242  *	SYSC_PRECHARGE,		EAGAIN,  SYSC_ERR_PRECHARGE
243  *	SYSC_INTRANS,		EBUSY,   SYSC_ERR_INTRANS
244  *	SYSC_KTHREAD,		EBUSY,   SYSC_ERR_KTHREAD
245  *	SYSC_DEV_ATTACH,	EBUSY,   SYSC_ERR_NDI_ATTACH
246  *	SYSC_DEV_DETACH,	EBUSY,   SYSC_ERR_NDI_DETACH
247  *	SYSC_NDI_ATTACH,	EFAULT,  SYSC_ERR_NDI_ATTACH
248  *	SYSC_NDI_DETACH,	EFAULT,  SYSC_ERR_NDI_DETACH
249  *	SYSC_CORE_RESOURCE,	EINVAL,  SYSC_ERR_CORE_RESOURCE
250  *	SYSC_OSTATE,		EINVAL,  SYSC_ERR_OSTATE
251  *	SYSC_RSTATE,		EINVAL,  SYSC_ERR_RSTATE
252  *	SYSC_COND,		EINVAL,  SYSC_ERR_COND
253  *	SYSC_PROM,		EIO,     SYSC_ERR_PROM
254  *	SYSC_NOMEM,		ENOMEM,  SYSC_ERR_DR_INIT
255  *	SYSC_NOMEM,		ENOMEM,  SYSC_ERR_NDI_ATTACH
256  *	SYSC_NOMEM,		ENOMEM,  SYSC_ERR_NDI_DETACH
257  *	SYSC_HOTPLUG,		ENOTSUP, SYSC_ERR_HOTPLUG
258  *	SYSC_HW_COMPAT,		ENOTSUP, SYSC_ERR_HW_COMPAT
259  *	SYSC_NON_DR_PROM,	ENOTSUP, SYSC_ERR_NON_DR_PROM
260  *	SYSC_SUSPEND,		ENXIO,   SYSC_ERR_SUSPEND
261  *	SYSC_RESUME,		ENXIO,   SYSC_ERR_RESUME
262  *	SYSC_UTHREAD,		ESRCH,   SYSC_ERR_UTHREAD
263  */
264 static int
265 cfga_sid(int err, int scerr)
266 {
267 	if (scerr == SYSC_ERR_DEFAULT)
268 		return (SYSC_UNKNOWN);
269 
270 	switch (cfga_eid(err, scerr)) {
271 	case cfga_eid(EAGAIN, SYSC_ERR_COOLING):
272 		return (SYSC_COOLING);
273 	case cfga_eid(EAGAIN, SYSC_ERR_POWER):
274 		return (SYSC_POWER);
275 	case cfga_eid(EAGAIN, SYSC_ERR_PRECHARGE):
276 		return (SYSC_PRECHARGE);
277 	case cfga_eid(EBUSY, SYSC_ERR_INTRANS):
278 		return (SYSC_INTRANS);
279 	case cfga_eid(EBUSY, SYSC_ERR_KTHREAD):
280 		return (SYSC_KTHREAD);
281 	case cfga_eid(EBUSY, SYSC_ERR_NDI_ATTACH):
282 		return (SYSC_DEV_ATTACH);
283 	case cfga_eid(EBUSY, SYSC_ERR_NDI_DETACH):
284 		return (SYSC_DEV_DETACH);
285 	case cfga_eid(EFAULT, SYSC_ERR_NDI_ATTACH):
286 		return (SYSC_NDI_ATTACH);
287 	case cfga_eid(EFAULT, SYSC_ERR_NDI_DETACH):
288 		return (SYSC_NDI_DETACH);
289 	case cfga_eid(EINVAL, SYSC_ERR_CORE_RESOURCE):
290 		return (SYSC_CORE_RESOURCE);
291 	case cfga_eid(EINVAL, SYSC_ERR_OSTATE):
292 		return (SYSC_OSTATE);
293 	case cfga_eid(EINVAL, SYSC_ERR_RSTATE):
294 		return (SYSC_RSTATE);
295 	case cfga_eid(EINVAL, SYSC_ERR_COND):
296 		return (SYSC_COND);
297 	case cfga_eid(EIO, SYSC_ERR_PROM):
298 		return (SYSC_PROM);
299 	case cfga_eid(ENOMEM, SYSC_ERR_DR_INIT):
300 		return (SYSC_NOMEM);
301 	case cfga_eid(ENOMEM, SYSC_ERR_NDI_ATTACH):
302 		return (SYSC_NOMEM);
303 	case cfga_eid(ENOMEM, SYSC_ERR_NDI_DETACH):
304 		return (SYSC_NOMEM);
305 	case cfga_eid(ENOTSUP, SYSC_ERR_HOTPLUG):
306 		return (SYSC_HOTPLUG);
307 	case cfga_eid(ENOTSUP, SYSC_ERR_HW_COMPAT):
308 		return (SYSC_HW_COMPAT);
309 	case cfga_eid(ENOTSUP, SYSC_ERR_NON_DR_PROM):
310 		return (SYSC_NON_DR_PROM);
311 	case cfga_eid(ENXIO, SYSC_ERR_SUSPEND):
312 		return (SYSC_SUSPEND);
313 	case cfga_eid(ENXIO, SYSC_ERR_RESUME):
314 		return (SYSC_RESUME);
315 	case cfga_eid(ESRCH, SYSC_ERR_UTHREAD):
316 		return (SYSC_UTHREAD);
317 	default:
318 		break;
319 	}
320 
321 	return (SYSC_UNKNOWN);
322 }
323 
324 static void
325 sysc_cmd_init(sysc_cfga_cmd_t *sc, char *outputstr, int force)
326 {
327 	sc->force = force;
328 	sc->outputstr = outputstr;
329 	sc->errtype = SYSC_ERR_DEFAULT;
330 
331 	(void) memset((void *)outputstr, 0, sizeof (outputstr));
332 
333 	cfga_str(SYSC_DEVSTR) = outputstr;
334 }
335 
336 /*
337  * cfga_err() accepts a variable number of message IDs and constructs
338  * a corresponding error string which is returned via the errstring argument.
339  * cfga_err() calls dgettext() to internationalize proper messages.
340  */
341 static void
342 cfga_err(sysc_cfga_cmd_t *sc, char **errstring, ...)
343 {
344 	int a;
345 	int i;
346 	int n;
347 	int len;
348 	int flen;
349 	char *p;
350 	char *q;
351 	char *s[32];
352 	char *failed;
353 	va_list ap;
354 	char syserr_num[20];
355 
356 	/*
357 	 * If errstring is null it means user in not interested in getting
358 	 * error status. So we don't do all the work
359 	 */
360 	if (errstring == NULL) {
361 		return;
362 	}
363 	va_start(ap, errstring);
364 
365 	failed = dgettext(TEXT_DOMAIN, cfga_str(DIAG_FAILED));
366 	flen = strlen(failed);
367 
368 	for (n = len = 0; (a = va_arg(ap, int)) != 0; n++) {
369 
370 		switch (a) {
371 		case ERR_PROM_OPEN:
372 		case ERR_PROM_GETPROP:
373 		case ERR_PROM_SETPROP:
374 		case CMD_GETSTAT:
375 		case CMD_LIST:
376 		case CMD_CONNECT:
377 		case CMD_DISCONNECT:
378 		case CMD_CONFIGURE:
379 		case CMD_UNCONFIGURE:
380 		case CMD_QUIESCE:
381 		case CMD_INSERT:
382 		case CMD_REMOVE:
383 		case CMD_SET_COND:
384 			p =  cfga_str(a);
385 			len += (strlen(p) + flen);
386 			s[n] = p;
387 			s[++n] = failed;
388 
389 			DBG("<%s>", p);
390 			DBG("<%s>", failed);
391 			break;
392 
393 		case OPT_ENABLE:
394 		case OPT_DISABLE:
395 			p = dgettext(TEXT_DOMAIN, cfga_str(DIAG_TRANS_OK));
396 			q = cfga_str(a);
397 			len += (strlen(p) + strlen(q) + flen);
398 			s[n] = p;
399 			s[++n] = q;
400 			s[++n] = failed;
401 
402 			DBG("<%s>", p);
403 			DBG("<%s>", q);
404 			DBG("<%s>", failed);
405 			break;
406 
407 		case ERR_CMD_INVAL:
408 		case ERR_AP_INVAL:
409 		case ERR_OPT_INVAL:
410 			p =  dgettext(TEXT_DOMAIN, cfga_str(a));
411 			q = va_arg(ap, char *);
412 			len += (strlen(p) + strlen(q));
413 			s[n] = p;
414 			s[++n] = q;
415 
416 			DBG("<%s>", p);
417 			DBG("<%s>", q);
418 			break;
419 
420 		case ERR_TRANS:
421 		case ERR_DISABLED:
422 			p =  dgettext(TEXT_DOMAIN, cfga_str(a));
423 			len += strlen(p);
424 			s[n] = p;
425 
426 			DBG("<%s>", p);
427 			break;
428 
429 		case DIAG_FORCE:
430 		default:
431 			p =  cfga_str(a);
432 			len += strlen(p);
433 			s[n] = p;
434 
435 			DBG("<%s>", p);
436 			break;
437 		}
438 	}
439 
440 	DBG1("\n");
441 	va_end(ap);
442 
443 	if (errno) {
444 		if (sc)
445 			i = cfga_sid(errno, (int)sc->errtype);
446 		else
447 			i = SYSC_UNKNOWN;
448 
449 		DBG4("cfga_sid(%d,%d)=%d\n", errno, sc->errtype, i);
450 
451 		if (i == SYSC_UNKNOWN) {
452 			p = strerror(errno);
453 			if (p == NULL) {
454 				(void) sprintf(syserr_num, "errno=%d", errno);
455 				p = syserr_num;
456 			}
457 		} else
458 			p = dgettext(TEXT_DOMAIN, cfga_str(i));
459 
460 		len += strlen(p);
461 		s[n++] = p;
462 		p = cfga_str(SYSC_DEVSTR);
463 		if (p && p[0]) {
464 			q = cfga_str(STR_COL);
465 
466 			len += strlen(q);
467 			s[n++] = q;
468 			len += strlen(p);
469 			s[n++] = p;
470 		}
471 	}
472 
473 	if ((p = (char *)calloc(len, 1)) == NULL)
474 		return;
475 
476 	for (i = 0; i < n; i++)
477 		(void) strcat(p, s[i]);
478 
479 	*errstring = p;
480 #ifdef	SIM_MSG
481 	printf("%s\n", *errstring);
482 #endif
483 }
484 
485 /*
486  * This routine accepts a variable number of message IDs and constructs
487  * a corresponding error string which is printed via the message print routine
488  * argument.  The HELP_UNKNOWN message ID has an argument string (the unknown
489  * help topic) that follows.
490  */
491 static void
492 cfga_msg(struct cfga_msg *msgp, ...)
493 {
494 	int a;
495 	int i;
496 	int n;
497 	int len;
498 	char *p;
499 	char *s[32];
500 	va_list ap;
501 
502 	va_start(ap, msgp);
503 
504 	for (n = len = 0; (a = va_arg(ap, int)) != 0; n++) {
505 		DBG("<%d>", a);
506 		p =  dgettext(TEXT_DOMAIN, cfga_str(a));
507 		len += strlen(p);
508 		s[n] = p;
509 		if (a == HELP_UNKNOWN) {
510 			p = va_arg(ap, char *);
511 			len += strlen(p);
512 			s[++n] = p;
513 		}
514 	}
515 
516 	va_end(ap);
517 
518 	if ((p = (char *)calloc(len + 1, 1)) == NULL)
519 		return;
520 
521 	for (i = 0; i < n; i++)
522 		(void) strcat(p, s[i]);
523 	(void) strcat(p, "\n");
524 
525 #ifdef	SIM_MSG
526 	printf("%s", p);
527 #else
528 	(*msgp->message_routine)(msgp->appdata_ptr, p);
529 #endif
530 	free(p);
531 }
532 
533 static sysc_cfga_stat_t *
534 sysc_stat(const char *ap_id, int *fdp)
535 {
536 	int fd;
537 	static sysc_cfga_stat_t sc_list[MAX_BOARDS];
538 
539 
540 	if ((fd = open(ap_id, O_RDWR, 0)) == -1)
541 		return (NULL);
542 	else if (ioctl(fd, SYSC_CFGA_CMD_GETSTATUS, sc_list) == -1) {
543 		(void) close(fd);
544 		return (NULL);
545 	} else if (fdp)
546 		*fdp = fd;
547 	else
548 		(void) close(fd);
549 
550 	return (sc_list);
551 }
552 
553 /*
554  * This code implementes the simulation of the ioctls that transition state.
555  * The GETSTAT ioctl is not simulated.  In this way a snapshot of the system
556  * state is read and manipulated by the simulation routines.  It is basically
557  * a useful debugging tool.
558  */
559 #ifdef	SIM
560 static int sim_idx;
561 static int sim_fd = -1;
562 static int sim_size = MAX_BOARDS * sizeof (sysc_cfga_stat_t);
563 static sysc_cfga_stat_t sim_sc_list[MAX_BOARDS];
564 
565 static sysc_cfga_stat_t *
566 sim_sysc_stat(const char *ap_id, int *fdp)
567 {
568 	int fd;
569 	struct stat buf;
570 
571 	if (sim_fd != -1)
572 		return (sim_sc_list);
573 
574 	if ((sim_fd = open("/tmp/cfga_simdata", O_RDWR|O_CREAT)) == -1) {
575 		perror("sim_open");
576 		exit(1);
577 	} else if (fstat(sim_fd, &buf) == -1) {
578 		perror("sim_stat");
579 		exit(1);
580 	}
581 
582 	if (buf.st_size) {
583 		if (buf.st_size != sim_size) {
584 			perror("sim_size");
585 			exit(1);
586 		} else if (read(sim_fd, sim_sc_list, sim_size) == -1) {
587 			perror("sim_read");
588 			exit(1);
589 		}
590 	} else if ((fd = open(ap_id, O_RDWR, 0)) == -1)
591 		return (NULL);
592 	else if (ioctl(fd, SYSC_CFGA_CMD_GETSTATUS, sim_sc_list) == -1) {
593 		(void) close(fd);
594 		return (NULL);
595 	} else if (fdp)
596 		*fdp = fd;
597 
598 	return (sim_sc_list);
599 }
600 
601 static int
602 sim_open(char *a, int b, int c)
603 {
604 	printf("sim_open(%s)\n", a);
605 
606 	if (strcmp(a, "/dev/openprom") == 0)
607 		return (open(a, b, c));
608 	return (0);
609 }
610 
611 static int
612 sim_close(int a)
613 {
614 	return (0);
615 }
616 
617 static int
618 sim_ioctl(int fd, int cmd, void *a)
619 {
620 	printf("sim_ioctl(%d)\n", sim_idx);
621 
622 	switch (cmd) {
623 	case SYSC_CFGA_CMD_CONNECT:
624 		sim_sc_list[sim_idx].rstate = SYSC_CFGA_RSTATE_CONNECTED;
625 		break;
626 	case SYSC_CFGA_CMD_CONFIGURE:
627 		sim_sc_list[sim_idx].ostate = SYSC_CFGA_OSTATE_CONFIGURED;
628 		break;
629 	case SYSC_CFGA_CMD_UNCONFIGURE:
630 		sim_sc_list[sim_idx].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
631 		break;
632 	case SYSC_CFGA_CMD_DISCONNECT:
633 		sim_sc_list[sim_idx].rstate = SYSC_CFGA_RSTATE_DISCONNECTED;
634 		break;
635 	case SYSC_CFGA_CMD_QUIESCE_TEST:
636 	case SYSC_CFGA_CMD_TEST:
637 		return (0);
638 	case OPROMGETOPT:
639 		return (ioctl(fd, OPROMGETOPT, a));
640 	case OPROMSETOPT:
641 		return (ioctl(fd, OPROMSETOPT, a));
642 	}
643 
644 	if (lseek(sim_fd, SEEK_SET, 0) == -1) {
645 		perror("sim_seek");
646 		exit(1);
647 	}
648 	if (write(sim_fd, sim_sc_list, sim_size) == -1) {
649 		perror("sim_write");
650 		exit(1);
651 	}
652 
653 	return (0);
654 }
655 
656 #define	open(a, b, c)	sim_open((char *)(a), (int)(b), (int)(c))
657 #define	close(a)	sim_close(a)
658 #define	ioctl(a, b, c)	sim_ioctl((int)(a), (int)(b), (void *)(c))
659 #define	sysc_stat(a, b)	sim_sysc_stat(a, b)
660 #endif	/* SIM */
661 
662 static char *promdev = "/dev/openprom";
663 static char *dlprop = "disabled-board-list";
664 
665 #define	BUFSIZE		128
666 
667 typedef union {
668 	char buf[BUFSIZE];
669 	struct openpromio opp;
670 } oppbuf_t;
671 
672 static int
673 prom_get_prop(int prom_fd, char *var, char **val)
674 {
675 	static oppbuf_t oppbuf;
676 	struct openpromio *opp = &(oppbuf.opp);
677 
678 	(void) strncpy(opp->oprom_array, var, OBP_MAXPROPNAME);
679 	opp->oprom_array[OBP_MAXPROPNAME + 1] = '\0';
680 	opp->oprom_size = BUFSIZE;
681 
682 	DBG3("getprop(%s, %d)\n", opp->oprom_array, opp->oprom_size);
683 
684 	if (ioctl(prom_fd, OPROMGETOPT, opp) < 0)
685 		return (ERR_PROM_GETPROP);
686 	else if (opp->oprom_size > 0)
687 		*val = opp->oprom_array;
688 	else
689 		*val = NULL;
690 
691 	return (0);
692 }
693 
694 static cfga_err_t
695 prom_set_prop(int prom_fd, char *var, char *val)
696 {
697 	oppbuf_t oppbuf;
698 	struct openpromio *opp = &(oppbuf.opp);
699 	int varlen = strlen(var) + 1;
700 	int vallen = strlen(val);
701 
702 	DBG("prom_set_prop(%s)\n", val);
703 
704 	(void) strcpy(opp->oprom_array, var);
705 	(void) strcpy(opp->oprom_array + varlen, val);
706 	opp->oprom_size = varlen + vallen;
707 
708 	if (ioctl(prom_fd, OPROMSETOPT, opp) < 0)
709 		return (ERR_PROM_SETPROP);
710 
711 	return (0);
712 }
713 
714 static int
715 dlist_find(int board, char **dlist, int *disabled)
716 {
717 	int i;
718 	int err;
719 	int prom_fd;
720 	char *p;
721 	char *dl;
722 	char b[2];
723 
724 	if ((prom_fd = open(promdev, O_RDWR, 0)) < 0)
725 		return (ERR_PROM_OPEN);
726 	else if (err = prom_get_prop(prom_fd, dlprop, dlist)) {
727 		(void) close(prom_fd);
728 		return (err);
729 	} else
730 		(void) close(prom_fd);
731 
732 	b[1] = 0;
733 	*disabled = 0;
734 
735 	if ((dl = *dlist) != NULL) {
736 		int len = strlen(dl);
737 
738 		for (i = 0; i < len; i++) {
739 			int bd;
740 
741 			b[0] = dl[i];
742 			bd = strtol(b, &p, 16);
743 
744 			if (p != b && bd == board)
745 				(*disabled)++;
746 		}
747 	}
748 
749 	return (0);
750 }
751 
752 static int
753 dlist_update(int board, int disable, char *dlist, struct cfga_msg *msgp,
754     int verbose)
755 {
756 	int i, j, n;
757 	int err;
758 	int found;
759 	int update;
760 	int prom_fd;
761 	char *p;
762 	char b[2];
763 	char ndlist[64];
764 
765 	b[1] = 0;
766 	ndlist[0] = 0;
767 	j = 0;
768 	found = 0;
769 	update = 0;
770 
771 	if ((prom_fd = open(promdev, O_RDWR, 0)) < 0)
772 		return (ERR_PROM_OPEN);
773 
774 	if (dlist) {
775 		int len = strlen(dlist);
776 
777 		for (i = 0; i < len; i++) {
778 			int bd;
779 
780 			b[0] = dlist[i];
781 			bd = strtol(b, &p, 16);
782 
783 			if (p != b && bd == board) {
784 
785 				found++;
786 				if (disable) {
787 					if (verbose)
788 						cfga_msg(msgp, STR_BD,
789 						    DIAG_WAS_DISABLED, 0);
790 				} else {
791 					if (verbose)
792 						cfga_msg(msgp, STR_BD,
793 						    DIAG_WILL_ENABLE, 0);
794 					update++;
795 					continue;
796 				}
797 			}
798 			ndlist[j++] = dlist[i];
799 		}
800 		ndlist[j] = 0;
801 	}
802 
803 	if (!found)
804 		if (disable) {
805 			if (verbose)
806 				cfga_msg(msgp, STR_BD, DIAG_WILL_DISABLE, 0);
807 			p = &ndlist[j];
808 			n = sprintf(p, "%x", board);
809 			p[n] = 0;
810 			update++;
811 		} else {
812 			if (verbose)
813 				cfga_msg(msgp, STR_BD, DIAG_WAS_ENABLED, 0);
814 		}
815 
816 	if (update)
817 		err = prom_set_prop(prom_fd, dlprop, ndlist);
818 	else
819 		err = 0;
820 
821 	(void) close(prom_fd);
822 
823 	return (err);
824 }
825 
826 static int
827 ap_idx(const char *ap_id)
828 {
829 	int id;
830 	char *s;
831 	static char *slot = "slot";
832 
833 	DBG("ap_idx(%s)\n", ap_id);
834 
835 	if ((s = strstr(ap_id, slot)) == NULL)
836 		return (-1);
837 	else {
838 		int n;
839 
840 		s += strlen(slot);
841 		n = strlen(s);
842 
843 		DBG3("ap_idx: s=%s, n=%d\n", s, n);
844 
845 		switch (n) {
846 		case 2:
847 			if (!isdigit(s[1]))
848 				return (-1);
849 		/* FALLTHROUGH */
850 		case 1:
851 			if (!isdigit(s[0]))
852 				return (-1);
853 			break;
854 		default:
855 			return (-1);
856 		}
857 	}
858 
859 	if ((id = atoi(s)) > MAX_BOARDS)
860 		return (-1);
861 
862 	DBG3("ap_idx(%s)=%d\n", s, id);
863 
864 	return (id);
865 }
866 
867 /*ARGSUSED*/
868 cfga_err_t
869 cfga_change_state(
870 	cfga_cmd_t state_change_cmd,
871 	const char *ap_id,
872 	const char *options,
873 	struct cfga_confirm *confp,
874 	struct cfga_msg *msgp,
875 	char **errstring,
876 	cfga_flags_t flags)
877 {
878 	int fd;
879 	int idx;
880 	int err;
881 	int force;
882 	int verbose;
883 	int opterr;
884 	int disable;
885 	int disabled;
886 	cfga_err_t rc;
887 	sysc_cfga_stat_t *ss;
888 	sysc_cfga_cmd_t *sc, sysc_cmd;
889 	sysc_cfga_rstate_t rs;
890 	sysc_cfga_ostate_t os;
891 	char *dlist;
892 	char outputstr[SYSC_OUTPUT_LEN];
893 
894 	if (errstring != NULL)
895 		*errstring = NULL;
896 
897 	rc = CFGA_ERROR;
898 
899 	if (options) {
900 		disable = 0;
901 		if (strcmp(options, cfga_str(OPT_DISABLE)) == 0)
902 			disable++;
903 		else if (strcmp(options, cfga_str(OPT_ENABLE))) {
904 			cfga_err(NULL, errstring, ERR_OPT_INVAL, options, 0);
905 			return (rc);
906 		}
907 	}
908 
909 	if ((idx = ap_idx(ap_id)) == -1) {
910 		cfga_err(NULL, errstring, ERR_AP_INVAL, ap_id, 0);
911 		return (rc);
912 	} else if ((ss = sysc_stat(ap_id, &fd)) == NULL) {
913 		cfga_err(NULL, errstring, CMD_GETSTAT, 0);
914 		return (rc);
915 	}
916 #ifdef	SIM
917 	sim_idx = idx;
918 #endif
919 	/*
920 	 * We disallow connecting on the disabled list unless
921 	 * either the FORCE flag or the enable-at-boot option
922 	 * is set. The check is made further below
923 	 */
924 	if (opterr = dlist_find(idx, &dlist, &disabled)) {
925 		err = disable ? OPT_DISABLE : OPT_ENABLE;
926 		cfga_err(NULL, errstring, err, opterr, 0);
927 		(void) close(fd);
928 		return (rc);
929 	} else
930 		force = flags & CFGA_FLAG_FORCE;
931 
932 	rs = ss[idx].rstate;
933 	os = ss[idx].ostate;
934 
935 	sc = &sysc_cmd;
936 	sysc_cmd_init(sc, outputstr, force);
937 	verbose = flags & CFGA_FLAG_VERBOSE;
938 
939 	switch (state_change_cmd) {
940 	case CFGA_CMD_CONNECT:
941 		if (rs != SYSC_CFGA_RSTATE_DISCONNECTED)
942 			cfga_err(NULL, errstring, ERR_TRANS, 0);
943 		else if (disabled && !(force || (options && !disable)))
944 			cfga_err(NULL, errstring, CMD_CONNECT,
945 			    ERR_DISABLED, DIAG_FORCE, 0);
946 		else if (!(*confp->confirm)(confp->appdata_ptr,
947 		    cfga_str(ASK_CONNECT))) {
948 			(void) close(fd);
949 			return (CFGA_NACK);
950 		} else if (ioctl(fd, SYSC_CFGA_CMD_CONNECT, sc) == -1)
951 			cfga_err(sc, errstring, CMD_CONNECT, 0);
952 		else if (options && (opterr = dlist_update(idx, disable,
953 		    dlist, msgp, verbose))) {
954 			err = disable ? OPT_DISABLE : OPT_ENABLE;
955 			cfga_err(NULL, errstring, err, opterr, 0);
956 		} else
957 			rc = CFGA_OK;
958 		break;
959 
960 	case CFGA_CMD_DISCONNECT:
961 		if ((os == SYSC_CFGA_OSTATE_CONFIGURED) &&
962 		    (ioctl(fd, SYSC_CFGA_CMD_UNCONFIGURE, sc) == -1)) {
963 			cfga_err(sc, errstring, CMD_UNCONFIGURE, 0);
964 			(void) close(fd);
965 			return (CFGA_ERROR);
966 		} else
967 			sysc_cmd_init(sc, outputstr, force);
968 
969 		if (rs == SYSC_CFGA_RSTATE_CONNECTED) {
970 			if (ioctl(fd, SYSC_CFGA_CMD_DISCONNECT, sc) == -1)
971 				cfga_err(sc, errstring, CMD_DISCONNECT, 0);
972 			else if (options && (opterr = dlist_update(idx, disable,
973 			    dlist, msgp, verbose))) {
974 				err = disable ? OPT_DISABLE : OPT_ENABLE;
975 				cfga_err(NULL, errstring, err, opterr, 0);
976 			} else
977 				rc = CFGA_OK;
978 		} else
979 			cfga_err(NULL, errstring, ERR_TRANS, 0);
980 		break;
981 
982 	case CFGA_CMD_CONFIGURE:
983 		if (rs == SYSC_CFGA_RSTATE_DISCONNECTED)
984 			if (disabled && !(force || (options && !disable))) {
985 				cfga_err(NULL, errstring, CMD_CONFIGURE,
986 				    ERR_DISABLED, DIAG_FORCE, 0);
987 				(void) close(fd);
988 				return (CFGA_ERROR);
989 			} else if (!(*confp->confirm)(confp->appdata_ptr,
990 			    cfga_str(ASK_CONNECT))) {
991 				(void) close(fd);
992 				return (CFGA_NACK);
993 			} else if (ioctl(fd, SYSC_CFGA_CMD_CONNECT, sc) == -1) {
994 				cfga_err(sc, errstring, CMD_CONNECT, 0);
995 				(void) close(fd);
996 				return (CFGA_ERROR);
997 			} else
998 				sysc_cmd_init(sc, outputstr, force);
999 
1000 		if (os == SYSC_CFGA_OSTATE_UNCONFIGURED) {
1001 			if (ioctl(fd, SYSC_CFGA_CMD_CONFIGURE, sc) == -1)
1002 				cfga_err(sc, errstring, CMD_CONFIGURE, 0);
1003 			else if (options && (opterr = dlist_update(idx,
1004 			    disable, dlist, msgp, verbose))) {
1005 				err = disable ? OPT_DISABLE : OPT_ENABLE;
1006 				cfga_err(NULL, errstring, err, opterr, 0);
1007 			} else
1008 				rc = CFGA_OK;
1009 		} else
1010 			cfga_err(NULL, errstring, ERR_TRANS, 0);
1011 		break;
1012 
1013 	case CFGA_CMD_UNCONFIGURE:
1014 		if (os != SYSC_CFGA_OSTATE_CONFIGURED)
1015 			cfga_err(NULL, errstring, ERR_TRANS, 0);
1016 		else if (ioctl(fd, SYSC_CFGA_CMD_UNCONFIGURE, sc) == -1)
1017 			cfga_err(sc, errstring, CMD_UNCONFIGURE, 0);
1018 		else if (options && (opterr = dlist_update(idx, disable,
1019 		    dlist, msgp, verbose))) {
1020 			err = disable ? OPT_DISABLE : OPT_ENABLE;
1021 			cfga_err(NULL, errstring, err, opterr, 0);
1022 		} else
1023 			rc = CFGA_OK;
1024 		break;
1025 
1026 	default:
1027 		rc = CFGA_OPNOTSUPP;
1028 		break;
1029 	}
1030 
1031 	(void) close(fd);
1032 	return (rc);
1033 }
1034 
1035 static int
1036 str2cond(const char *cond)
1037 {
1038 	int c;
1039 
1040 	if (strcmp(cond, cfga_str(COND_UNKNOWN)) == 0)
1041 		c =  SYSC_CFGA_COND_UNKNOWN;
1042 	else if (strcmp(cond, cfga_str(COND_OK)) == 0)
1043 		c =  SYSC_CFGA_COND_OK;
1044 	else if (strcmp(cond, cfga_str(COND_FAILING)) == 0)
1045 		c =  SYSC_CFGA_COND_FAILING;
1046 	else if (strcmp(cond, cfga_str(COND_FAILED)) == 0)
1047 		c =  SYSC_CFGA_COND_FAILED;
1048 	else if (strcmp(cond, cfga_str(COND_UNUSABLE)) == 0)
1049 		c =  SYSC_CFGA_COND_UNUSABLE;
1050 	else
1051 		c = -1;
1052 
1053 	return (c);
1054 }
1055 
1056 /*ARGSUSED*/
1057 cfga_err_t
1058 cfga_private_func(
1059 	const char *function,
1060 	const char *ap_id,
1061 	const char *options,
1062 	struct cfga_confirm *confp,
1063 	struct cfga_msg *msgp,
1064 	char **errstring,
1065 	cfga_flags_t flags)
1066 {
1067 	int fd;
1068 	int idx;
1069 	int len;
1070 	int cmd;
1071 	int cond;
1072 	int err;
1073 	int opterr;
1074 	int verbose;
1075 	int disable;
1076 	int disabled;
1077 	cfga_err_t rc;
1078 	char *str;
1079 	char *dlist;
1080 	char outputstr[SYSC_OUTPUT_LEN];
1081 	sysc_cfga_cmd_t *sc, sysc_cmd;
1082 
1083 	if (errstring != NULL)
1084 		*errstring = NULL;
1085 
1086 	verbose = flags & CFGA_FLAG_VERBOSE;
1087 
1088 	rc = CFGA_ERROR;
1089 
1090 	if (options) {
1091 		disable = 0;
1092 		if (strcmp(options, cfga_str(OPT_DISABLE)) == 0)
1093 			disable++;
1094 		else if (strcmp(options, cfga_str(OPT_ENABLE))) {
1095 			cfga_err(NULL, errstring, ERR_OPT_INVAL, options, 0);
1096 			return (rc);
1097 		}
1098 	}
1099 
1100 	sc = &sysc_cmd;
1101 	str = cfga_str(CMD_SET_COND);
1102 	len = strlen(str);
1103 
1104 	if ((strncmp(function, str, len) == 0) && (function[len++] == '=') &&
1105 	    ((cond = (str2cond(&function[len]))) != -1)) {
1106 		cmd = SYSC_CFGA_CMD_TEST_SET_COND;
1107 		err = CMD_SET_COND;
1108 		sc->arg = cond;
1109 	} else if (strcmp(function, cfga_str(CMD_QUIESCE)) == 0) {
1110 		cmd = SYSC_CFGA_CMD_QUIESCE_TEST;
1111 		err = CMD_QUIESCE;
1112 	} else if (strcmp(function, cfga_str(CMD_INSERT)) == 0) {
1113 		cmd = SYSC_CFGA_CMD_TEST;
1114 		err = CMD_INSERT;
1115 	} else if (strcmp(function, cfga_str(CMD_REMOVE)) == 0) {
1116 		cmd = SYSC_CFGA_CMD_TEST;
1117 		err = CMD_REMOVE;
1118 	} else {
1119 		cfga_err(NULL, errstring, ERR_CMD_INVAL, (char *)function, 0);
1120 		return (rc);
1121 	}
1122 
1123 	sysc_cmd_init(sc, outputstr, 0);
1124 
1125 	if ((idx = ap_idx(ap_id)) == -1)
1126 		cfga_err(NULL, errstring, ERR_AP_INVAL, ap_id, 0);
1127 	else if (((fd = open(ap_id, O_RDWR, 0)) == -1) ||
1128 	    (ioctl(fd, cmd, sc) == -1))
1129 		cfga_err(NULL, errstring, err, 0);
1130 	else
1131 		rc = CFGA_OK;
1132 
1133 	if (options) {
1134 		opterr = (dlist_find(idx, &dlist, &disabled) ||
1135 		    dlist_update(idx, disable, dlist, msgp, verbose));
1136 		if (opterr) {
1137 			err = disable ? OPT_DISABLE : OPT_ENABLE;
1138 			if (verbose)
1139 				cfga_msg(msgp, err, opterr, 0);
1140 		}
1141 	}
1142 
1143 	(void) close(fd);
1144 	return (rc);
1145 }
1146 
1147 
1148 /*ARGSUSED*/
1149 cfga_err_t
1150 cfga_test(
1151 	const char *ap_id,
1152 	const char *options,
1153 	struct cfga_msg *msgp,
1154 	char **errstring,
1155 	cfga_flags_t flags)
1156 {
1157 	if (errstring != NULL)
1158 		*errstring = NULL;
1159 
1160 	return (CFGA_OPNOTSUPP);
1161 }
1162 
1163 static cfga_stat_t
1164 rstate_cvt(sysc_cfga_rstate_t rs)
1165 {
1166 	cfga_stat_t cs;
1167 
1168 	switch (rs) {
1169 	case SYSC_CFGA_RSTATE_EMPTY:
1170 		cs = CFGA_STAT_EMPTY;
1171 		break;
1172 	case SYSC_CFGA_RSTATE_DISCONNECTED:
1173 		cs = CFGA_STAT_DISCONNECTED;
1174 		break;
1175 	case SYSC_CFGA_RSTATE_CONNECTED:
1176 		cs = CFGA_STAT_CONNECTED;
1177 		break;
1178 	default:
1179 		cs = CFGA_STAT_NONE;
1180 		break;
1181 	}
1182 
1183 	return (cs);
1184 }
1185 
1186 static cfga_stat_t
1187 ostate_cvt(sysc_cfga_ostate_t os)
1188 {
1189 	cfga_stat_t cs;
1190 
1191 	switch (os) {
1192 	case SYSC_CFGA_OSTATE_UNCONFIGURED:
1193 		cs = CFGA_STAT_UNCONFIGURED;
1194 		break;
1195 	case SYSC_CFGA_OSTATE_CONFIGURED:
1196 		cs = CFGA_STAT_CONFIGURED;
1197 		break;
1198 	default:
1199 		cs = CFGA_STAT_NONE;
1200 		break;
1201 	}
1202 
1203 	return (cs);
1204 }
1205 
1206 static cfga_cond_t
1207 cond_cvt(sysc_cfga_cond_t sc)
1208 {
1209 	cfga_cond_t cc;
1210 
1211 	switch (sc) {
1212 	case SYSC_CFGA_COND_OK:
1213 		cc = CFGA_COND_OK;
1214 		break;
1215 	case SYSC_CFGA_COND_FAILING:
1216 		cc = CFGA_COND_FAILING;
1217 		break;
1218 	case SYSC_CFGA_COND_FAILED:
1219 		cc = CFGA_COND_FAILED;
1220 		break;
1221 	case SYSC_CFGA_COND_UNUSABLE:
1222 		cc = CFGA_COND_UNUSABLE;
1223 		break;
1224 	case SYSC_CFGA_COND_UNKNOWN:
1225 	default:
1226 		cc = CFGA_COND_UNKNOWN;
1227 		break;
1228 	}
1229 
1230 	return (cc);
1231 }
1232 
1233 static char *
1234 type_str(enum board_type type)
1235 {
1236 	char *type_str;
1237 
1238 	switch (type) {
1239 	case MEM_BOARD:
1240 		type_str = cfga_str(BD_MEM);
1241 		break;
1242 	case CPU_BOARD:
1243 		type_str = cfga_str(BD_CPU);
1244 		break;
1245 	case IO_2SBUS_BOARD:
1246 		type_str = cfga_str(BD_IO_2SBUS);
1247 		break;
1248 	case IO_SBUS_FFB_BOARD:
1249 		type_str = cfga_str(BD_IO_SBUS_FFB);
1250 		break;
1251 	case IO_PCI_BOARD:
1252 		type_str = cfga_str(BD_IO_PCI);
1253 		break;
1254 	case DISK_BOARD:
1255 		type_str = cfga_str(BD_DISK);
1256 		break;
1257 	case IO_2SBUS_SOCPLUS_BOARD:
1258 		type_str = cfga_str(BD_IO_2SBUS_SOCPLUS);
1259 		break;
1260 	case IO_SBUS_FFB_SOCPLUS_BOARD:
1261 		type_str = cfga_str(BD_IO_SBUS_FFB_SOCPLUS);
1262 		break;
1263 	case UNKNOWN_BOARD:
1264 	default:
1265 		type_str = cfga_str(BD_UNKNOWN);
1266 		break;
1267 	}
1268 	return (type_str);
1269 }
1270 
1271 static void
1272 info_set(sysc_cfga_stat_t *sc, cfga_info_t info, int disabled)
1273 {
1274 	int i;
1275 	struct cpu_info *cpu;
1276 	union bd_un *bd = &sc->bd;
1277 
1278 	*info = '\0';
1279 
1280 	switch (sc->type) {
1281 	case CPU_BOARD:
1282 		for (i = 0, cpu = bd->cpu; i < 2; i++, cpu++) {
1283 			if (cpu->cpu_speed > 1) {
1284 				info += sprintf(info, "cpu %d: ", i);
1285 				info += sprintf(info, "%3d MHz ",
1286 				    cpu->cpu_speed);
1287 				if (cpu->cache_size)
1288 					info += sprintf(info, "%0.1fM ",
1289 					    (float)cpu->cache_size /
1290 					    (float)(1024 * 1024));
1291 			}
1292 		}
1293 		break;
1294 	case IO_SBUS_FFB_BOARD:
1295 		switch (bd->io2.ffb_size) {
1296 		case FFB_SINGLE:
1297 			info += sprintf(info, "single buffered ffb   ");
1298 			break;
1299 		case FFB_DOUBLE:
1300 			info += sprintf(info, "double buffered ffb   ");
1301 			break;
1302 		case FFB_NOT_FOUND:
1303 #ifdef FFB_DR_SUPPORT
1304 			info += sprintf(info, "no ffb installed   ");
1305 #endif
1306 			break;
1307 		default:
1308 			info += sprintf(info, "illegal ffb size   ");
1309 			break;
1310 		}
1311 		break;
1312 	case DISK_BOARD:
1313 		for (i = 0; i < 2; i++)
1314 			if (bd->dsk.disk_pres[i])
1315 				info += sprintf(info, "target: %2d ",
1316 				    bd->dsk.disk_id[i]);
1317 			else
1318 				info += sprintf(info, "no disk   ");
1319 		break;
1320 	}
1321 
1322 	if (disabled)
1323 		info += sprintf(info, "disabled at boot   ");
1324 
1325 	if (sc->no_detach)
1326 		info += sprintf(info, "non-detachable   ");
1327 
1328 	if (sc->plus_board)
1329 		info += sprintf(info, "100 MHz capable   ");
1330 }
1331 
1332 static void
1333 sysc_cvt(sysc_cfga_stat_t *sc, cfga_stat_data_t *cs, int disabled)
1334 {
1335 	(void) strcpy(cs->ap_type, type_str(sc->type));
1336 	cs->ap_r_state = rstate_cvt(sc->rstate);
1337 	cs->ap_o_state = ostate_cvt(sc->ostate);
1338 	cs->ap_cond = cond_cvt(sc->condition);
1339 	cs->ap_busy = (cfga_busy_t)sc->in_transition;
1340 	cs->ap_status_time = sc->last_change;
1341 	info_set(sc, cs->ap_info, disabled);
1342 	cs->ap_log_id[0] = '\0';
1343 	cs->ap_phys_id[0] = '\0';
1344 }
1345 
1346 /*ARGSUSED*/
1347 cfga_err_t
1348 cfga_list(
1349 	const char *ap_id,
1350 	cfga_stat_data_t **ap_list,
1351 	int *nlist,
1352 	const char *options,
1353 	char **errstring)
1354 {
1355 	int i;
1356 	cfga_err_t rc;
1357 	sysc_cfga_stat_t *sc;
1358 	cfga_stat_data_t *cs;
1359 
1360 	if (errstring != NULL)
1361 		*errstring = NULL;
1362 
1363 	rc = CFGA_ERROR;
1364 
1365 	if (ap_idx(ap_id) == -1)
1366 		cfga_err(NULL, errstring, ERR_AP_INVAL, ap_id, 0);
1367 	else if ((sc = sysc_stat(ap_id, NULL)) == NULL)
1368 		cfga_err(NULL, errstring, CMD_LIST, 0);
1369 	else if (!(cs = (cfga_stat_data_t *)malloc(MAX_BOARDS * sizeof (*cs))))
1370 		cfga_err(NULL, errstring, CMD_LIST, 0);
1371 	else {
1372 		*ap_list = cs;
1373 
1374 		for (*nlist = 0, i = 0; i < MAX_BOARDS; i++, sc++) {
1375 			if (sc->board == -1)
1376 				continue;
1377 			sysc_cvt(sc, cs++, 0); /* XXX - disable */
1378 			(*nlist)++;
1379 		}
1380 
1381 		rc = CFGA_OK;
1382 	}
1383 
1384 	return (rc);
1385 }
1386 
1387 /*ARGSUSED*/
1388 cfga_err_t
1389 cfga_stat(
1390 	const char *ap_id,
1391 	struct cfga_stat_data *cs,
1392 	const char *options,
1393 	char **errstring)
1394 {
1395 	cfga_err_t rc;
1396 	int idx;
1397 	int err;
1398 	int opterr;
1399 	int disable;
1400 	int disabled;
1401 	char *dlist;
1402 	sysc_cfga_stat_t *sc;
1403 
1404 	if (errstring != NULL)
1405 		*errstring = NULL;
1406 
1407 	rc = CFGA_ERROR;
1408 
1409 	if (options && options[0]) {
1410 		disable = 0;
1411 		if (strcmp(options, cfga_str(OPT_DISABLE)) == 0)
1412 			disable++;
1413 		else if (strcmp(options, cfga_str(OPT_ENABLE))) {
1414 			cfga_err(NULL, errstring, ERR_OPT_INVAL, options, 0);
1415 			return (rc);
1416 		}
1417 	}
1418 
1419 	if ((idx = ap_idx(ap_id)) == -1)
1420 		cfga_err(NULL, errstring, ERR_AP_INVAL, ap_id, 0);
1421 	else if ((sc = sysc_stat(ap_id, NULL)) == NULL)
1422 		cfga_err(NULL, errstring, CMD_GETSTAT, 0);
1423 	else {
1424 		opterr = dlist_find(idx, &dlist, &disabled);
1425 		sysc_cvt(sc + idx, cs, disabled);
1426 
1427 		rc = CFGA_OK;
1428 
1429 		if (options && options[0] && ((opterr != 0) ||
1430 		    ((opterr = dlist_update(idx, disable, dlist, NULL, 0))
1431 		    != 0))) {
1432 				err = disable ? OPT_DISABLE : OPT_ENABLE;
1433 				cfga_err(NULL, errstring, err, opterr, 0);
1434 		}
1435 	}
1436 
1437 	return (rc);
1438 }
1439 
1440 /*ARGSUSED*/
1441 cfga_err_t
1442 cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
1443 {
1444 	int help = 0;
1445 
1446 	if (options) {
1447 		if (strcmp(options, cfga_str(OPT_DISABLE)) == 0)
1448 			help = HELP_DISABLE;
1449 		else if (strcmp(options, cfga_str(OPT_ENABLE)) == 0)
1450 			help = HELP_ENABLE;
1451 		else if (strcmp(options, cfga_str(CMD_INSERT)) == 0)
1452 			help = HELP_INSERT;
1453 		else if (strcmp(options, cfga_str(CMD_REMOVE)) == 0)
1454 			help = HELP_REMOVE;
1455 		else if (strcmp(options, cfga_str(CMD_QUIESCE)) == 0)
1456 			help = HELP_QUIESCE;
1457 		else
1458 			help = HELP_UNKNOWN;
1459 	}
1460 
1461 	if (help)  {
1462 		if (help == HELP_UNKNOWN)
1463 			cfga_msg(msgp, help, options, 0);
1464 		else
1465 			cfga_msg(msgp, help, 0);
1466 	} else {
1467 		cfga_msg(msgp, HELP_HEADER, 0);
1468 		cfga_msg(msgp, HELP_DISABLE, 0);
1469 		cfga_msg(msgp, HELP_ENABLE, 0);
1470 		cfga_msg(msgp, HELP_INSERT, 0);
1471 		cfga_msg(msgp, HELP_REMOVE, 0);
1472 		cfga_msg(msgp, HELP_QUIESCE, 0);
1473 		cfga_msg(msgp, HELP_SET_COND, 0);
1474 	}
1475 
1476 	return (CFGA_OK);
1477 }
1478 
1479 /*
1480  * cfga_ap_id_cmp -- use default_ap_id_cmp() in libcfgadm
1481  */
1482