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