xref: /titanic_52/usr/src/lib/cfgadm_plugins/ac/common/mema.c (revision 3db86aab554edbb4244c8d1a1c90f152eee768af)
1*3db86aabSstevel /*
2*3db86aabSstevel  * CDDL HEADER START
3*3db86aabSstevel  *
4*3db86aabSstevel  * The contents of this file are subject to the terms of the
5*3db86aabSstevel  * Common Development and Distribution License, Version 1.0 only
6*3db86aabSstevel  * (the "License").  You may not use this file except in compliance
7*3db86aabSstevel  * with the License.
8*3db86aabSstevel  *
9*3db86aabSstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*3db86aabSstevel  * or http://www.opensolaris.org/os/licensing.
11*3db86aabSstevel  * See the License for the specific language governing permissions
12*3db86aabSstevel  * and limitations under the License.
13*3db86aabSstevel  *
14*3db86aabSstevel  * When distributing Covered Code, include this CDDL HEADER in each
15*3db86aabSstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*3db86aabSstevel  * If applicable, add the following below this CDDL HEADER, with the
17*3db86aabSstevel  * fields enclosed by brackets "[]" replaced with your own identifying
18*3db86aabSstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
19*3db86aabSstevel  *
20*3db86aabSstevel  * CDDL HEADER END
21*3db86aabSstevel  */
22*3db86aabSstevel /*
23*3db86aabSstevel  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*3db86aabSstevel  * Use is subject to license terms.
25*3db86aabSstevel  */
26*3db86aabSstevel 
27*3db86aabSstevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*3db86aabSstevel 
29*3db86aabSstevel #include <stddef.h>
30*3db86aabSstevel #include <stdlib.h>
31*3db86aabSstevel #include <unistd.h>
32*3db86aabSstevel #include <ctype.h>
33*3db86aabSstevel #include <fcntl.h>
34*3db86aabSstevel #include <signal.h>
35*3db86aabSstevel #include <string.h>
36*3db86aabSstevel #include <locale.h>
37*3db86aabSstevel #include <errno.h>
38*3db86aabSstevel #include <assert.h>
39*3db86aabSstevel #include <sys/dditypes.h>
40*3db86aabSstevel #include <sys/param.h>
41*3db86aabSstevel #include <sys/obpdefs.h>
42*3db86aabSstevel #include <sys/fhc.h>
43*3db86aabSstevel #include <sys/sysctrl.h>
44*3db86aabSstevel #include <sys/ac.h>
45*3db86aabSstevel #include <sys/spitregs.h>
46*3db86aabSstevel #include <config_admin.h>
47*3db86aabSstevel #include "mema_util.h"
48*3db86aabSstevel #include "mema_test.h"
49*3db86aabSstevel #include "mema_prom.h"
50*3db86aabSstevel 
51*3db86aabSstevel #ifdef	DEBUG
52*3db86aabSstevel #define	DBG	(void) printf
53*3db86aabSstevel #define	DBG1	(void) printf
54*3db86aabSstevel #define	DBG3	(void) printf
55*3db86aabSstevel #define	DBG4	(void) printf
56*3db86aabSstevel #else
57*3db86aabSstevel #define	DBG(a, b)
58*3db86aabSstevel #define	DBG1(a)
59*3db86aabSstevel #define	DBG3(a, b, c)
60*3db86aabSstevel #define	DBG4(a, b, c, d)
61*3db86aabSstevel #endif
62*3db86aabSstevel 
63*3db86aabSstevel #ifndef P_DER_UE
64*3db86aabSstevel /*
65*3db86aabSstevel  * <sys/spitregs.h> has these defines inside 'ifdef _KERNEL' at the
66*3db86aabSstevel  * time of writing.  Re-define here if that is still the case.
67*3db86aabSstevel  */
68*3db86aabSstevel 
69*3db86aabSstevel #define	P_DER_UE	0x00000000000000200ULL	/* UE has occurred */
70*3db86aabSstevel #define	P_DER_CE	0x00000000000000100ULL	/* CE has occurred */
71*3db86aabSstevel #define	P_DER_E_SYND	0x000000000000000FFULL	/* SYND<7:0>: ECC syndrome */
72*3db86aabSstevel #endif /* ! P_DER_UE */
73*3db86aabSstevel 
74*3db86aabSstevel #define	DEV_DEBUG
75*3db86aabSstevel #ifdef DEV_DEBUG
76*3db86aabSstevel #include <stdio.h>
77*3db86aabSstevel #include <stdlib.h>
78*3db86aabSstevel 
79*3db86aabSstevel static FILE *debug_fp;
80*3db86aabSstevel static int debugging(void);
81*3db86aabSstevel static void dump_ioctl(int, void *);
82*3db86aabSstevel static void dump_ioctl_res(int, void *, int, int);
83*3db86aabSstevel #else /* DEV_DEBUG */
84*3db86aabSstevel #define	dump_ioctl(CMD, ARG)
85*3db86aabSstevel #define	dump_ioctl_res(CMD, ARG, RET, ERRNO)
86*3db86aabSstevel #endif /* DEV_DEBUG */
87*3db86aabSstevel 
88*3db86aabSstevel typedef struct {
89*3db86aabSstevel 	uint_t   board;
90*3db86aabSstevel 	uint_t   bank;
91*3db86aabSstevel } mema_bank_t;
92*3db86aabSstevel 
93*3db86aabSstevel static char *mema_opts[] = {
94*3db86aabSstevel #define	OPT_BOOT_DISABLE	0
95*3db86aabSstevel 	"disable-at-boot",
96*3db86aabSstevel #define	OPT_BOOT_ENABLE		1
97*3db86aabSstevel 	"enable-at-boot",
98*3db86aabSstevel #define	OPT_TIMEOUT		2
99*3db86aabSstevel 	"timeout",
100*3db86aabSstevel 	NULL
101*3db86aabSstevel };
102*3db86aabSstevel 
103*3db86aabSstevel #define	OPT_NEEDS_VALUE(O)	((O) == OPT_TIMEOUT)
104*3db86aabSstevel 
105*3db86aabSstevel #define	MAX_OPT_LENGTH		(sizeof ("disable-at-boot"))
106*3db86aabSstevel 
107*3db86aabSstevel /*
108*3db86aabSstevel  * For each function there is an array of opt_control structures giving
109*3db86aabSstevel  * the valid options.  The array is terminated by an element with the
110*3db86aabSstevel  * subopt field set to -1.  The group field is used to identify
111*3db86aabSstevel  * mutually exclusive options, with zero meaning no grouping.
112*3db86aabSstevel  */
113*3db86aabSstevel struct opt_control {
114*3db86aabSstevel 	int		subopt;
115*3db86aabSstevel 	int		group;
116*3db86aabSstevel };
117*3db86aabSstevel 
118*3db86aabSstevel /*
119*3db86aabSstevel  * Returned set of options.
120*3db86aabSstevel  * If the option takes a value, it will be set in 'val'
121*3db86aabSstevel  * if the corresponding bit is set in 'bits' is set,
122*3db86aabSstevel  * otherwise the pointer in 'val' is undefined.
123*3db86aabSstevel  */
124*3db86aabSstevel #define	OPT_VAL_ARRAY_SIZE	32	/* # bits in 'bits' */
125*3db86aabSstevel typedef struct {
126*3db86aabSstevel 	unsigned int	bits;
127*3db86aabSstevel 	char		*val[OPT_VAL_ARRAY_SIZE];
128*3db86aabSstevel } option_set_t;
129*3db86aabSstevel 
130*3db86aabSstevel #define	OPTSET_INIT(S)		((S).bits = 0)
131*3db86aabSstevel #define	_OPT_TO_BIT(O)		(1 << (O))
132*3db86aabSstevel #define	OPTSET_SET_VAL(S, O, V)	((S).bits |= _OPT_TO_BIT(O), \
133*3db86aabSstevel 				(S).val[(O)] = (V))
134*3db86aabSstevel #define	OPTSET_TEST(S, O)	(((S).bits & _OPT_TO_BIT(O)) != 0)
135*3db86aabSstevel #define	OPTSET_VAL(S, O)	((S).val[(O)])
136*3db86aabSstevel #define	OPTSET_IS_EMPTY(S)	((S).bits == 0)
137*3db86aabSstevel 
138*3db86aabSstevel static option_set_t process_options(const char *, struct opt_control *,
139*3db86aabSstevel 	int *, char **);
140*3db86aabSstevel 
141*3db86aabSstevel static struct opt_control add_opts[] = {
142*3db86aabSstevel 	{OPT_BOOT_ENABLE, 1},
143*3db86aabSstevel 	{OPT_BOOT_DISABLE, 1},
144*3db86aabSstevel 	{-1, 0}
145*3db86aabSstevel };
146*3db86aabSstevel 
147*3db86aabSstevel static struct opt_control del_opts[] = {
148*3db86aabSstevel 	{OPT_BOOT_ENABLE, 1},
149*3db86aabSstevel 	{OPT_BOOT_DISABLE, 1},
150*3db86aabSstevel 	{OPT_TIMEOUT, 2},
151*3db86aabSstevel 	{-1, 0}
152*3db86aabSstevel };
153*3db86aabSstevel 
154*3db86aabSstevel static struct opt_control stat_opts[] = {
155*3db86aabSstevel 	{OPT_BOOT_ENABLE, 1},
156*3db86aabSstevel 	{OPT_BOOT_DISABLE, 1},
157*3db86aabSstevel 	{-1, 0}
158*3db86aabSstevel };
159*3db86aabSstevel 
160*3db86aabSstevel #if !defined(TEXT_DOMAIN)
161*3db86aabSstevel #define	TEXT_DOMAIN	"SYS_TEST"
162*3db86aabSstevel #endif
163*3db86aabSstevel 
164*3db86aabSstevel static const char still_testing[] = "bank %s being tested by process %d";
165*3db86aabSstevel static const char no_value[] = "sub-option \"%s\" does not take a value";
166*3db86aabSstevel static const char missing_value[] = "sub-option \"%s\" needs a value";
167*3db86aabSstevel static const char conflict_opt[] = "sub-option \"%s\" conflicts with \"%s\"";
168*3db86aabSstevel static const char unk_subopt[] = "sub-option \"%s\" unknown\n"
169*3db86aabSstevel 	"choose from: %s";
170*3db86aabSstevel static const char not_valid[] =
171*3db86aabSstevel 	"sub-option \"%s\" not valid for this operation\n"
172*3db86aabSstevel 	"choose from: %s";
173*3db86aabSstevel static const char timeout_notnum[] =
174*3db86aabSstevel 	"timeout value not a positive integer \"%s\"";
175*3db86aabSstevel static const char calloc_fail[] = "memory allocation failed (%d*%d bytes)";
176*3db86aabSstevel static const char unk_test[] = "test \"%s\" unknown\n"
177*3db86aabSstevel 	"choose from: %s";
178*3db86aabSstevel static const char dup_test[] = "more than one test type specified (\"%s\")";
179*3db86aabSstevel static const char dup_num[] = "option specified more than once (\"%s\")";
180*3db86aabSstevel static const char no_num[] = "invalid number specified for max_errors(\"%s\")";
181*3db86aabSstevel static const char mtest_rw_error[] = "memory test read/write error";
182*3db86aabSstevel static const char mtest_lib_error[] = "memory test library error";
183*3db86aabSstevel static const char dlist_invalid[] = "invalid disabled-memory-list";
184*3db86aabSstevel static const char dlist_write_failed[] = "disabled-memory-list write failed";
185*3db86aabSstevel static const char mtest_unknown_error[] = "unknown memory test error";
186*3db86aabSstevel static const char ap_invalid[] = "invalid attachment point: %s";
187*3db86aabSstevel static const char trans_illegal[] = "illegal transition";
188*3db86aabSstevel static const char open_failed[] = "open failed: %s: %s";
189*3db86aabSstevel static const char mema_help[] =	"\nAc specific options:\n";
190*3db86aabSstevel static const char disable_opts[] = "\t-o disable-at-boot\n";
191*3db86aabSstevel static const char enable_opts[] = "\t-o enable-at-boot\n";
192*3db86aabSstevel static const char timeout_opts[] = "\t-o timeout=# (seconds)\n";
193*3db86aabSstevel static const char test_opts[] =
194*3db86aabSstevel 	"\t-o {quick, normal, extended},[max_errors=#] -t ap_id [ap_id...]\n";
195*3db86aabSstevel static const char private_funcs[] = "\t-x relocate-test ap_id [ap_id...]\n";
196*3db86aabSstevel static const char add_is_disabled[] = "memory is disabled at boot";
197*3db86aabSstevel static const char add_willbe_disabled[] =
198*3db86aabSstevel 	"memory will be disabled at boot";
199*3db86aabSstevel static const char add_disab_err[] = "cannot get memory disabled status";
200*3db86aabSstevel static const char pfunc_unknown[] = "private function \"%s\" unknown";
201*3db86aabSstevel 
202*3db86aabSstevel 
203*3db86aabSstevel #define	mema_eid(a, b)		(((a) << 8) + (b))
204*3db86aabSstevel #define	mema_str(i)		mema_strs[(i)]
205*3db86aabSstevel 
206*3db86aabSstevel #define	AC_BK_BUSY		0
207*3db86aabSstevel #define	AC_BK_ID		1
208*3db86aabSstevel #define	AC_BD_ID		2
209*3db86aabSstevel #define	AC_BD_TYPE		3
210*3db86aabSstevel #define	AC_BD_STATE		4
211*3db86aabSstevel #define	AC_MEM_TEST_ID		5
212*3db86aabSstevel #define	AC_MEM_TEST_PAR		6
213*3db86aabSstevel #define	AC_MEM_PERM		7
214*3db86aabSstevel #define	AC_KPM_CANCELLED	8
215*3db86aabSstevel #define	AC_KPM_REFUSED		9
216*3db86aabSstevel #define	AC_KPM_SPAN		10
217*3db86aabSstevel #define	AC_KPM_DUP		11
218*3db86aabSstevel #define	AC_KPM_FAULT		12
219*3db86aabSstevel #define	AC_KPM_RESOURCE		13
220*3db86aabSstevel #define	AC_KPM_NOTSUP		14
221*3db86aabSstevel #define	AC_KPM_NOHANDLES	15
222*3db86aabSstevel #define	AC_KPM_NONRELOC		16
223*3db86aabSstevel #define	AC_KPM_HANDLE		17
224*3db86aabSstevel #define	AC_KPM_BUSY		18
225*3db86aabSstevel #define	AC_KPM_NOTVIABLE	19
226*3db86aabSstevel #define	AC_KPM_SEQUENCE		20
227*3db86aabSstevel #define	AC_KPM_NOWORK		21
228*3db86aabSstevel #define	AC_KPM_NOTFINISHED	22
229*3db86aabSstevel #define	AC_KPM_NOTRUNNING	23
230*3db86aabSstevel #define	AC_VMEM			24
231*3db86aabSstevel #define	CMD_MEM_STAT		25
232*3db86aabSstevel #define	CMD_MEM_ADD		26
233*3db86aabSstevel #define	CMD_MEM_DEL		27
234*3db86aabSstevel #define	CMD_MEM_TEST_START	28
235*3db86aabSstevel #define	CMD_MEM_TEST_STOP	29
236*3db86aabSstevel #define	AC_UNKNOWN		30
237*3db86aabSstevel #define	AC_INTR			31
238*3db86aabSstevel #define	AC_TIMEOUT		32
239*3db86aabSstevel #define	CMD_MEM_RELOCTEST	33
240*3db86aabSstevel #define	AC_DEINTLV		34
241*3db86aabSstevel 
242*3db86aabSstevel static char *
243*3db86aabSstevel mema_strs[] = {
244*3db86aabSstevel 	"memory bank busy",
245*3db86aabSstevel 	"invalid memory bank",
246*3db86aabSstevel 	"invalid board id",
247*3db86aabSstevel 	"invalid board type",
248*3db86aabSstevel 	"invalid board state",
249*3db86aabSstevel 	"invalid memory test id",
250*3db86aabSstevel 	"invalid memory test parameter(s)",
251*3db86aabSstevel 	"no write permission",
252*3db86aabSstevel 	"memory operation cancelled",
253*3db86aabSstevel 	"memory operation refused",
254*3db86aabSstevel 	"memory already in use (add)",
255*3db86aabSstevel 	"memory span duplicate (delete)",
256*3db86aabSstevel 	"memory access test failed (add)",
257*3db86aabSstevel 	"some resource was not available",
258*3db86aabSstevel 	"operation not supported",
259*3db86aabSstevel 	"cannot allocate any more handles",
260*3db86aabSstevel 	"non-relocatable pages in span",
261*3db86aabSstevel 	"bad handle supplied",
262*3db86aabSstevel 	"memory in span is being deleted",
263*3db86aabSstevel 	"VM viability test failed",
264*3db86aabSstevel 	"function called out of sequence",
265*3db86aabSstevel 	"no memory to delete",
266*3db86aabSstevel 	"delete processing not finished",
267*3db86aabSstevel 	"delete processing not running",
268*3db86aabSstevel 	"insufficient virtual memory",
269*3db86aabSstevel 	"memory stat failed: %s",
270*3db86aabSstevel 	"memory add failed: %s",
271*3db86aabSstevel 	"memory delete failed: %s",
272*3db86aabSstevel 	"memory test start failed: %s",
273*3db86aabSstevel 	"memory test stop failed: %s",
274*3db86aabSstevel 	"unknown error",
275*3db86aabSstevel 	"memory delete killed",
276*3db86aabSstevel 	"memory delete timeout",
277*3db86aabSstevel 	"memory relocate-test failed: %s",
278*3db86aabSstevel 	"memory cannot be de-interleaved"
279*3db86aabSstevel };
280*3db86aabSstevel 
281*3db86aabSstevel /*
282*3db86aabSstevel  *	AC_MEM_PERM,		EBADF,   AC_ERR_MEM_PERM
283*3db86aabSstevel  *	AC_BK_BUSY,		EBUSY,   AC_ERR_MEM_BK
284*3db86aabSstevel  *	AC_KPM_CANCELLED,	EINTR,   AC_ERR_KPM_CANCELLED
285*3db86aabSstevel  *	AC_KPM_REFUSED,		EINTR,   AC_ERR_KPM_REFUSED
286*3db86aabSstevel  *	AC_BK_ID,		EINVAL,  AC_ERR_MEM_BK
287*3db86aabSstevel  *	AC_BD_ID,		EINVAL,  AC_ERR_BD
288*3db86aabSstevel  *	AC_BD_TYPE,		EINVAL,  AC_ERR_BD_TYPE
289*3db86aabSstevel  *	AC_BD_STATE,		EINVAL,  AC_ERR_BD_STATE
290*3db86aabSstevel  *	AC_MEM_TEST_ID,		EINVAL,  AC_ERR_MEM_TEST
291*3db86aabSstevel  *	AC_MEM_TEST_PAR,	EINVAL,  AC_ERR_MEM_TEST_PAR
292*3db86aabSstevel  *	AC_KPM_SPAN,		EINVAL,  AC_ERR_KPM_SPAN
293*3db86aabSstevel  *	AC_KPM_DUP,		EINVAL,  AC_ERR_KPM_DUP?
294*3db86aabSstevel  *	AC_KPM_FAULT,		EINVAL,  AC_ERR_KPM_FAULT
295*3db86aabSstevel  *	AC_KPM_RESOURCE,	EINVAL,  AC_ERR_KPM_RESOURCE
296*3db86aabSstevel  *	AC_KPM_NOTSUP,		EINVAL,  AC_ERR_KPM_NOTSUP
297*3db86aabSstevel  *	AC_KPM_NOHANDLES,	EINVAL,  AC_ERR_KPM_NOHANDLES
298*3db86aabSstevel  *	AC_KPM_NONRELOC,	EINVAL,  AC_ERR_KPM_NONRELOC
299*3db86aabSstevel  *	AC_KPM_HANDLE,		EINVAL,  AC_ERR_KPM_HANDLE
300*3db86aabSstevel  *	AC_KPM_BUSY,		EINVAL,  AC_ERR_KPM_BUSY
301*3db86aabSstevel  *	AC_KPM_NOTVIABLE,	EINVAL,  AC_ERR_KPM_NOTVIABLE
302*3db86aabSstevel  *	AC_KPM_SEQUENCE,	EINVAL,  AC_ERR_KPM_SEQUENCE
303*3db86aabSstevel  *	AC_KPM_NOWORK,		EINVAL,  AC_ERR_KPM_NOWORK
304*3db86aabSstevel  *	AC_KPM_NOTFINISHED,	EINVAL,  AC_ERR_KPM_NOTFINISHED
305*3db86aabSstevel  *	AC_KPM_NOTRUNNING,	EINVAL,  AC_ERR_KPM_NOTRUNNING
306*3db86aabSstevel  *	AC_VMEM,		ENOMEM,  AC_ERR_VMEM
307*3db86aabSstevel  *	AC_INTR,		EINTR,   AC_ERR_INTR
308*3db86aabSstevel  *	AC_TIMEOUT,		EINTR,   AC_ERR_TIMEOUT
309*3db86aabSstevel  *	AC_DEINTLV,		EINVAL,  AC_ERR_MEM_DEINTLV
310*3db86aabSstevel  */
311*3db86aabSstevel static int
312*3db86aabSstevel mema_sid(int err, int acerr)
313*3db86aabSstevel {
314*3db86aabSstevel 	if (acerr == AC_ERR_DEFAULT)
315*3db86aabSstevel 		return (AC_UNKNOWN);
316*3db86aabSstevel 
317*3db86aabSstevel 	switch (mema_eid(err, acerr)) {
318*3db86aabSstevel 	case mema_eid(EBADF, AC_ERR_MEM_PERM):
319*3db86aabSstevel 		return (AC_MEM_PERM);
320*3db86aabSstevel 	case mema_eid(EBUSY, AC_ERR_MEM_BK):
321*3db86aabSstevel 		return (AC_BK_BUSY);
322*3db86aabSstevel 	case mema_eid(EINTR, AC_ERR_KPM_CANCELLED):
323*3db86aabSstevel 		return (AC_KPM_CANCELLED);
324*3db86aabSstevel 	case mema_eid(EINTR, AC_ERR_KPM_REFUSED):
325*3db86aabSstevel 		return (AC_KPM_REFUSED);
326*3db86aabSstevel 	case mema_eid(EINVAL, AC_ERR_MEM_BK):
327*3db86aabSstevel 		return (AC_BK_ID);
328*3db86aabSstevel 	case mema_eid(EINVAL, AC_ERR_BD):
329*3db86aabSstevel 		return (AC_BD_ID);
330*3db86aabSstevel 	case mema_eid(EINVAL, AC_ERR_BD_TYPE):
331*3db86aabSstevel 		return (AC_BD_TYPE);
332*3db86aabSstevel 	case mema_eid(EINVAL, AC_ERR_BD_STATE):
333*3db86aabSstevel 		return (AC_BD_STATE);
334*3db86aabSstevel 	case mema_eid(EINVAL, AC_ERR_MEM_TEST):
335*3db86aabSstevel 		return (AC_MEM_TEST_ID);
336*3db86aabSstevel 	case mema_eid(EINVAL, AC_ERR_MEM_TEST_PAR):
337*3db86aabSstevel 		return (AC_MEM_TEST_PAR);
338*3db86aabSstevel 	case mema_eid(EINVAL, AC_ERR_KPM_SPAN):
339*3db86aabSstevel 		return (AC_KPM_SPAN);
340*3db86aabSstevel 	case mema_eid(EINVAL, AC_ERR_KPM_DUP):
341*3db86aabSstevel 		return (AC_KPM_DUP);
342*3db86aabSstevel 	case mema_eid(EINVAL, AC_ERR_KPM_FAULT):
343*3db86aabSstevel 		return (AC_KPM_FAULT);
344*3db86aabSstevel 	case mema_eid(EINVAL, AC_ERR_KPM_RESOURCE):
345*3db86aabSstevel 		return (AC_KPM_RESOURCE);
346*3db86aabSstevel 	case mema_eid(EINVAL, AC_ERR_KPM_NOTSUP):
347*3db86aabSstevel 		return (AC_KPM_NOTSUP);
348*3db86aabSstevel 	case mema_eid(EINVAL, AC_ERR_KPM_NOHANDLES):
349*3db86aabSstevel 		return (AC_KPM_NOHANDLES);
350*3db86aabSstevel 	case mema_eid(EINVAL, AC_ERR_KPM_NONRELOC):
351*3db86aabSstevel 		return (AC_KPM_NONRELOC);
352*3db86aabSstevel 	case mema_eid(EINVAL, AC_ERR_KPM_HANDLE):
353*3db86aabSstevel 		return (AC_KPM_HANDLE);
354*3db86aabSstevel 	case mema_eid(EINVAL, AC_ERR_KPM_BUSY):
355*3db86aabSstevel 		return (AC_KPM_BUSY);
356*3db86aabSstevel 	case mema_eid(EINVAL, AC_ERR_KPM_NOTVIABLE):
357*3db86aabSstevel 		return (AC_KPM_NOTVIABLE);
358*3db86aabSstevel 	case mema_eid(EINVAL, AC_ERR_KPM_SEQUENCE):
359*3db86aabSstevel 		return (AC_KPM_SEQUENCE);
360*3db86aabSstevel 	case mema_eid(EINVAL, AC_ERR_KPM_NOWORK):
361*3db86aabSstevel 		return (AC_KPM_NOWORK);
362*3db86aabSstevel 	case mema_eid(EINVAL, AC_ERR_KPM_NOTFINISHED):
363*3db86aabSstevel 		return (AC_KPM_NOTFINISHED);
364*3db86aabSstevel 	case mema_eid(EINVAL, AC_ERR_KPM_NOTRUNNING):
365*3db86aabSstevel 		return (AC_KPM_NOTRUNNING);
366*3db86aabSstevel 	case mema_eid(ENOMEM, AC_ERR_VMEM):
367*3db86aabSstevel 		return (AC_VMEM);
368*3db86aabSstevel 	case mema_eid(EINTR, AC_ERR_INTR):
369*3db86aabSstevel 		return (AC_INTR);
370*3db86aabSstevel 	case mema_eid(EINTR, AC_ERR_TIMEOUT):
371*3db86aabSstevel 		return (AC_TIMEOUT);
372*3db86aabSstevel 	case mema_eid(EINVAL, AC_ERR_MEM_DEINTLV):
373*3db86aabSstevel 		return (AC_DEINTLV);
374*3db86aabSstevel 	default:
375*3db86aabSstevel 		break;
376*3db86aabSstevel 	}
377*3db86aabSstevel 
378*3db86aabSstevel 	return (AC_UNKNOWN);
379*3db86aabSstevel }
380*3db86aabSstevel 
381*3db86aabSstevel static void
382*3db86aabSstevel mema_err(ac_cfga_cmd_t *ac, int ret_errno, char **errstring, int cmd)
383*3db86aabSstevel {
384*3db86aabSstevel 	char *cname = mema_str(cmd);
385*3db86aabSstevel 	char *syserr;
386*3db86aabSstevel 	char syserr_num[20];
387*3db86aabSstevel 
388*3db86aabSstevel 	if (ac) {
389*3db86aabSstevel 		syserr = mema_str(mema_sid(ret_errno, ac->errtype));
390*3db86aabSstevel 		syserr = dgettext(TEXT_DOMAIN, syserr);
391*3db86aabSstevel 	} else {
392*3db86aabSstevel 		syserr = strerror(ret_errno);
393*3db86aabSstevel 		/* strerror() does its own gettext(). */
394*3db86aabSstevel 		if (syserr == NULL) {
395*3db86aabSstevel 			(void) sprintf(syserr_num, "errno=%d", errno);
396*3db86aabSstevel 			syserr = syserr_num;
397*3db86aabSstevel 		}
398*3db86aabSstevel 	}
399*3db86aabSstevel 
400*3db86aabSstevel 	__fmt_errstring(errstring, strlen(syserr),
401*3db86aabSstevel 	    dgettext(TEXT_DOMAIN, cname), syserr);
402*3db86aabSstevel }
403*3db86aabSstevel 
404*3db86aabSstevel static void
405*3db86aabSstevel mema_cmd_init(ac_cfga_cmd_t *ac, void *cmd, char *outputstr, int force)
406*3db86aabSstevel {
407*3db86aabSstevel 	(void) memset((void *)ac, 0, sizeof (*ac));
408*3db86aabSstevel 
409*3db86aabSstevel 	ac->errtype = AC_ERR_DEFAULT;
410*3db86aabSstevel 	ac->private = cmd;
411*3db86aabSstevel 	ac->force = force;
412*3db86aabSstevel 	ac->outputstr = outputstr;
413*3db86aabSstevel 
414*3db86aabSstevel 	(void) memset((void *)outputstr, 0, AC_OUTPUT_LEN);
415*3db86aabSstevel }
416*3db86aabSstevel 
417*3db86aabSstevel static int
418*3db86aabSstevel ap_bk_idx(const char *ap_id)
419*3db86aabSstevel {
420*3db86aabSstevel 	int id;
421*3db86aabSstevel 	char *s;
422*3db86aabSstevel 	static char *bank = "bank";
423*3db86aabSstevel 
424*3db86aabSstevel 	DBG("ap_bk_idx(%s)\n", ap_id);
425*3db86aabSstevel 
426*3db86aabSstevel 	if ((s = strstr(ap_id, bank)) == NULL)
427*3db86aabSstevel 		return (-1);
428*3db86aabSstevel 	else {
429*3db86aabSstevel 		int n;
430*3db86aabSstevel 
431*3db86aabSstevel 		s += strlen(bank);
432*3db86aabSstevel 		n = strlen(s);
433*3db86aabSstevel 
434*3db86aabSstevel 		DBG3("ap_bk_idx: s=%s, n=%d\n", s, n);
435*3db86aabSstevel 
436*3db86aabSstevel 		if ((n != 1) || !isdigit(s[0]))
437*3db86aabSstevel 			return (-1);
438*3db86aabSstevel 	}
439*3db86aabSstevel 
440*3db86aabSstevel 	id = atoi(s);
441*3db86aabSstevel 
442*3db86aabSstevel 	if (id < 0 || id > 1)
443*3db86aabSstevel 		return (-1);
444*3db86aabSstevel 
445*3db86aabSstevel 	DBG3("ap_bk_idx(%s)=%d\n", s, id);
446*3db86aabSstevel 
447*3db86aabSstevel 	return (id);
448*3db86aabSstevel }
449*3db86aabSstevel 
450*3db86aabSstevel static cfga_err_t
451*3db86aabSstevel ap_stat(
452*3db86aabSstevel 	const char *bank_spec,
453*3db86aabSstevel 	int *fdp,
454*3db86aabSstevel 	mema_bank_t *bkp,
455*3db86aabSstevel 	ac_stat_t *stp,
456*3db86aabSstevel 	char **errstring)
457*3db86aabSstevel {
458*3db86aabSstevel 	int fd;
459*3db86aabSstevel 	int ret, ret_errno;
460*3db86aabSstevel 	int bank;
461*3db86aabSstevel 	mema_bank_t bk;
462*3db86aabSstevel 	ac_stat_t stat;
463*3db86aabSstevel 	ac_cfga_cmd_t cmd;
464*3db86aabSstevel 	char outputstr[AC_OUTPUT_LEN];
465*3db86aabSstevel 
466*3db86aabSstevel 	if ((bank = ap_bk_idx(bank_spec)) == -1) {
467*3db86aabSstevel 		__fmt_errstring(errstring, strlen(bank_spec),
468*3db86aabSstevel 			dgettext(TEXT_DOMAIN, ap_invalid), bank_spec);
469*3db86aabSstevel 		return (CFGA_ERROR);
470*3db86aabSstevel 	}
471*3db86aabSstevel 
472*3db86aabSstevel 	bk.bank = bank;
473*3db86aabSstevel 
474*3db86aabSstevel 	if ((fd = open(bank_spec, ((fdp != NULL) ? O_RDWR : O_RDONLY), 0)) ==
475*3db86aabSstevel 	    -1) {
476*3db86aabSstevel 		char *syserr;
477*3db86aabSstevel 		char syserr_num[20];
478*3db86aabSstevel 
479*3db86aabSstevel 		syserr = strerror(errno);
480*3db86aabSstevel 		if (syserr == NULL) {
481*3db86aabSstevel 			(void) sprintf(syserr_num, "errno=%d", errno);
482*3db86aabSstevel 			syserr = syserr_num;
483*3db86aabSstevel 		}
484*3db86aabSstevel 		__fmt_errstring(errstring, strlen(syserr) +
485*3db86aabSstevel 		    strlen(bank_spec),
486*3db86aabSstevel 		    dgettext(TEXT_DOMAIN, open_failed), bank_spec, syserr);
487*3db86aabSstevel 		return (CFGA_ERROR);
488*3db86aabSstevel 	}
489*3db86aabSstevel 
490*3db86aabSstevel 	mema_cmd_init(&cmd, &stat, outputstr, 0);
491*3db86aabSstevel 	dump_ioctl(AC_MEM_STAT, NULL);
492*3db86aabSstevel 	ret = ioctl(fd, AC_MEM_STAT, &cmd);
493*3db86aabSstevel 	ret_errno = errno;
494*3db86aabSstevel 	dump_ioctl_res(AC_MEM_STAT, &stat, ret, ret_errno);
495*3db86aabSstevel 
496*3db86aabSstevel 	if (ret == -1) {
497*3db86aabSstevel 		mema_err(&cmd, ret_errno, errstring, CMD_MEM_STAT);
498*3db86aabSstevel 		(void) close(fd);
499*3db86aabSstevel 		return (CFGA_ERROR);
500*3db86aabSstevel 	}
501*3db86aabSstevel 
502*3db86aabSstevel 	if (fdp)
503*3db86aabSstevel 		*fdp = fd;
504*3db86aabSstevel 	else
505*3db86aabSstevel 		(void) close(fd);
506*3db86aabSstevel 
507*3db86aabSstevel 	if (stp)
508*3db86aabSstevel 		*stp = stat;
509*3db86aabSstevel 
510*3db86aabSstevel 	if (bkp) {
511*3db86aabSstevel 		bkp->bank = bk.bank;
512*3db86aabSstevel 		bkp->board = stat.board;
513*3db86aabSstevel 	}
514*3db86aabSstevel 
515*3db86aabSstevel 	return (CFGA_OK);
516*3db86aabSstevel }
517*3db86aabSstevel 
518*3db86aabSstevel static void
519*3db86aabSstevel set_disabled_bits(mema_disabled_t *dp, int value)
520*3db86aabSstevel {
521*3db86aabSstevel 	if (value == 0)
522*3db86aabSstevel 		*dp &= ~PROM_MEMORY_DISABLED;
523*3db86aabSstevel 	else
524*3db86aabSstevel 		*dp |= PROM_MEMORY_DISABLED;
525*3db86aabSstevel }
526*3db86aabSstevel 
527*3db86aabSstevel static void
528*3db86aabSstevel set_present_bits(mema_disabled_t *dp, ac_stat_t *asp)
529*3db86aabSstevel {
530*3db86aabSstevel 	if (asp->ostate == SYSC_CFGA_OSTATE_CONFIGURED)
531*3db86aabSstevel 		*dp |= PROM_MEMORY_PRESENT;
532*3db86aabSstevel 	else
533*3db86aabSstevel 		*dp &= ~PROM_MEMORY_DISABLED;
534*3db86aabSstevel }
535*3db86aabSstevel 
536*3db86aabSstevel static cfga_err_t
537*3db86aabSstevel prom_do_options(
538*3db86aabSstevel 	option_set_t do_option,
539*3db86aabSstevel 	int board,
540*3db86aabSstevel 	ac_stat_t *asp,
541*3db86aabSstevel 	char **errstring)
542*3db86aabSstevel {
543*3db86aabSstevel 	cfga_err_t ret;
544*3db86aabSstevel 	mema_disabled_t disab;
545*3db86aabSstevel 
546*3db86aabSstevel 	if (!prom_read_disabled_list(&disab, board))
547*3db86aabSstevel 		return (CFGA_ERROR);
548*3db86aabSstevel 
549*3db86aabSstevel 	set_present_bits(&disab, asp);
550*3db86aabSstevel 
551*3db86aabSstevel 	ret = CFGA_OK;
552*3db86aabSstevel 
553*3db86aabSstevel 	if (OPTSET_TEST(do_option, OPT_BOOT_ENABLE)) {
554*3db86aabSstevel 		set_disabled_bits(&disab, 0);
555*3db86aabSstevel 		if (!prom_viable_disabled_list(&disab)) {
556*3db86aabSstevel 			__fmt_errstring(errstring, 0,
557*3db86aabSstevel 			    dgettext(TEXT_DOMAIN, dlist_invalid));
558*3db86aabSstevel 			ret = CFGA_ERROR;
559*3db86aabSstevel 		} else if (!prom_write_disabled_list(&disab, board)) {
560*3db86aabSstevel 			__fmt_errstring(errstring, 0,
561*3db86aabSstevel 			    dgettext(TEXT_DOMAIN, dlist_write_failed));
562*3db86aabSstevel 			ret = CFGA_ERROR;
563*3db86aabSstevel 		}
564*3db86aabSstevel 	} else if (OPTSET_TEST(do_option, OPT_BOOT_DISABLE)) {
565*3db86aabSstevel 		set_disabled_bits(&disab, 1);
566*3db86aabSstevel 		if (!prom_viable_disabled_list(&disab)) {
567*3db86aabSstevel 			__fmt_errstring(errstring, 0,
568*3db86aabSstevel 			    dgettext(TEXT_DOMAIN, dlist_invalid));
569*3db86aabSstevel 			ret = CFGA_ERROR;
570*3db86aabSstevel 		} else if (!prom_write_disabled_list(&disab, board)) {
571*3db86aabSstevel 			__fmt_errstring(errstring, 0,
572*3db86aabSstevel 			    dgettext(TEXT_DOMAIN, dlist_write_failed));
573*3db86aabSstevel 			ret = CFGA_ERROR;
574*3db86aabSstevel 		}
575*3db86aabSstevel 	}
576*3db86aabSstevel 
577*3db86aabSstevel 	return (ret);
578*3db86aabSstevel }
579*3db86aabSstevel 
580*3db86aabSstevel static cfga_err_t
581*3db86aabSstevel mema_add(
582*3db86aabSstevel 	const char *bank_spec,
583*3db86aabSstevel 	const char *options,
584*3db86aabSstevel 	char **errstring,
585*3db86aabSstevel 	int force)
586*3db86aabSstevel {
587*3db86aabSstevel 	mema_bank_t bk;
588*3db86aabSstevel 	int fd, ret, ret_errno;
589*3db86aabSstevel 	option_set_t do_option;
590*3db86aabSstevel 	ac_cfga_cmd_t cmd;
591*3db86aabSstevel 	ac_stat_t stat;
592*3db86aabSstevel 	char outputstr[AC_OUTPUT_LEN];
593*3db86aabSstevel 
594*3db86aabSstevel 	ret = 0;
595*3db86aabSstevel 	do_option = process_options(options, add_opts, &ret, errstring);
596*3db86aabSstevel 	if (ret != 0) {
597*3db86aabSstevel 		return (ret);
598*3db86aabSstevel 	}
599*3db86aabSstevel 
600*3db86aabSstevel 	ret = ap_stat(bank_spec, &fd, &bk, &stat, errstring);
601*3db86aabSstevel 	if (ret != CFGA_OK)
602*3db86aabSstevel 		return (ret);
603*3db86aabSstevel 
604*3db86aabSstevel 
605*3db86aabSstevel 	if (stat.rstate != SYSC_CFGA_RSTATE_CONNECTED ||
606*3db86aabSstevel 	    stat.ostate != SYSC_CFGA_OSTATE_UNCONFIGURED) {
607*3db86aabSstevel 		__fmt_errstring(errstring, 0,
608*3db86aabSstevel 		    dgettext(TEXT_DOMAIN, trans_illegal));
609*3db86aabSstevel 		(void) close(fd);
610*3db86aabSstevel 		return (CFGA_ERROR);
611*3db86aabSstevel 	}
612*3db86aabSstevel 
613*3db86aabSstevel 	if (!force) {
614*3db86aabSstevel 		mema_disabled_t disab;
615*3db86aabSstevel 
616*3db86aabSstevel 		if (prom_read_disabled_list(&disab, bk.board)) {
617*3db86aabSstevel 			if (disab != 0 &&
618*3db86aabSstevel 			    !OPTSET_TEST(do_option, OPT_BOOT_ENABLE)) {
619*3db86aabSstevel 				__fmt_errstring(errstring, 0,
620*3db86aabSstevel 				    dgettext(TEXT_DOMAIN, add_is_disabled));
621*3db86aabSstevel 				(void) close(fd);
622*3db86aabSstevel 				return (CFGA_ERROR);
623*3db86aabSstevel 			}
624*3db86aabSstevel 			if (disab == 0 &&
625*3db86aabSstevel 			    OPTSET_TEST(do_option, OPT_BOOT_DISABLE)) {
626*3db86aabSstevel 				__fmt_errstring(errstring, 0,
627*3db86aabSstevel 				    dgettext(TEXT_DOMAIN, add_willbe_disabled));
628*3db86aabSstevel 				(void) close(fd);
629*3db86aabSstevel 				return (CFGA_ERROR);
630*3db86aabSstevel 			}
631*3db86aabSstevel 		} else {
632*3db86aabSstevel 			__fmt_errstring(errstring, 0,
633*3db86aabSstevel 			    dgettext(TEXT_DOMAIN, add_disab_err));
634*3db86aabSstevel 			(void) close(fd);
635*3db86aabSstevel 			return (CFGA_ERROR);
636*3db86aabSstevel 		}
637*3db86aabSstevel 	}
638*3db86aabSstevel 
639*3db86aabSstevel 	mema_cmd_init(&cmd, NULL, outputstr, force);
640*3db86aabSstevel 	dump_ioctl(AC_MEM_CONFIGURE, NULL);
641*3db86aabSstevel 	ret = ioctl(fd, AC_MEM_CONFIGURE, &cmd);
642*3db86aabSstevel 	ret_errno = errno;
643*3db86aabSstevel 	dump_ioctl_res(AC_MEM_CONFIGURE, NULL, ret, ret_errno);
644*3db86aabSstevel 	(void) close(fd);
645*3db86aabSstevel 
646*3db86aabSstevel 	if (ret == -1) {
647*3db86aabSstevel 		mema_err(&cmd, ret_errno, errstring, CMD_MEM_ADD);
648*3db86aabSstevel 		return (CFGA_ERROR);
649*3db86aabSstevel 	}
650*3db86aabSstevel 
651*3db86aabSstevel 	ret = prom_do_options(do_option, bk.board, &stat, errstring);
652*3db86aabSstevel 
653*3db86aabSstevel 	return (ret);
654*3db86aabSstevel }
655*3db86aabSstevel 
656*3db86aabSstevel static cfga_err_t
657*3db86aabSstevel mema_delete(
658*3db86aabSstevel 	const char *bank_spec,
659*3db86aabSstevel 	const char *options,
660*3db86aabSstevel 	char **errstring,
661*3db86aabSstevel 	int force)
662*3db86aabSstevel {
663*3db86aabSstevel 	mema_bank_t bk;
664*3db86aabSstevel 	int fd, ret, ret_errno;
665*3db86aabSstevel 	option_set_t do_option;
666*3db86aabSstevel 	ac_cfga_cmd_t cmd;
667*3db86aabSstevel 	ac_stat_t stat;
668*3db86aabSstevel 	char outputstr[AC_OUTPUT_LEN];
669*3db86aabSstevel 	int timeout_secs = -1;	/* Init to 'use default'. */
670*3db86aabSstevel 
671*3db86aabSstevel 	ret = 0;
672*3db86aabSstevel 	do_option = process_options(options, del_opts, &ret, errstring);
673*3db86aabSstevel 	if (ret != 0) {
674*3db86aabSstevel 		return (ret);
675*3db86aabSstevel 	}
676*3db86aabSstevel 
677*3db86aabSstevel 	if (OPTSET_TEST(do_option, OPT_TIMEOUT)) {
678*3db86aabSstevel 		char *to_val;
679*3db86aabSstevel 		char *ep;
680*3db86aabSstevel 
681*3db86aabSstevel 		to_val = OPTSET_VAL(do_option, OPT_TIMEOUT);
682*3db86aabSstevel 		timeout_secs = (int)strtol(to_val, &ep, 10);
683*3db86aabSstevel 		if (*ep != '\0' || ep == to_val || timeout_secs < 0) {
684*3db86aabSstevel 			__fmt_errstring(errstring, strlen(to_val),
685*3db86aabSstevel 			    dgettext(TEXT_DOMAIN, timeout_notnum), to_val);
686*3db86aabSstevel 			return (CFGA_ERROR);
687*3db86aabSstevel 		}
688*3db86aabSstevel 	}
689*3db86aabSstevel 
690*3db86aabSstevel 	ret = ap_stat(bank_spec, &fd, &bk, &stat, errstring);
691*3db86aabSstevel 	if (ret != CFGA_OK)
692*3db86aabSstevel 		return (ret);
693*3db86aabSstevel 
694*3db86aabSstevel 	if (stat.rstate != SYSC_CFGA_RSTATE_CONNECTED ||
695*3db86aabSstevel 	    stat.ostate != SYSC_CFGA_OSTATE_CONFIGURED) {
696*3db86aabSstevel 		__fmt_errstring(errstring, 0,
697*3db86aabSstevel 		    dgettext(TEXT_DOMAIN, trans_illegal));
698*3db86aabSstevel 		(void) close(fd);
699*3db86aabSstevel 		return (CFGA_ERROR);
700*3db86aabSstevel 	}
701*3db86aabSstevel 
702*3db86aabSstevel 	mema_cmd_init(&cmd, NULL, outputstr, force);
703*3db86aabSstevel 	cmd.arg = timeout_secs;
704*3db86aabSstevel 	dump_ioctl(AC_MEM_UNCONFIGURE, NULL);
705*3db86aabSstevel 	ret = ioctl(fd, AC_MEM_UNCONFIGURE, &cmd);
706*3db86aabSstevel 	ret_errno = errno;
707*3db86aabSstevel 	dump_ioctl_res(AC_MEM_UNCONFIGURE, NULL, ret, ret_errno);
708*3db86aabSstevel 	(void) close(fd);
709*3db86aabSstevel 
710*3db86aabSstevel 	if (ret == -1) {
711*3db86aabSstevel 		mema_err(&cmd, ret_errno, errstring, CMD_MEM_DEL);
712*3db86aabSstevel 		return (CFGA_ERROR);
713*3db86aabSstevel 	}
714*3db86aabSstevel 
715*3db86aabSstevel 	ret = prom_do_options(do_option, bk.board, &stat, errstring);
716*3db86aabSstevel 
717*3db86aabSstevel 	return (ret);
718*3db86aabSstevel }
719*3db86aabSstevel 
720*3db86aabSstevel /*ARGSUSED*/
721*3db86aabSstevel cfga_err_t
722*3db86aabSstevel cfga_change_state(
723*3db86aabSstevel 	cfga_cmd_t state_change_cmd,
724*3db86aabSstevel 	const char *ap_id,
725*3db86aabSstevel 	const char *options,
726*3db86aabSstevel 	struct cfga_confirm *confp,
727*3db86aabSstevel 	struct cfga_msg *msgp,
728*3db86aabSstevel 	char **errstring,
729*3db86aabSstevel 	cfga_flags_t flags)
730*3db86aabSstevel {
731*3db86aabSstevel 	int force;
732*3db86aabSstevel 	cfga_err_t rc;
733*3db86aabSstevel 
734*3db86aabSstevel 	if (errstring != NULL)
735*3db86aabSstevel 		*errstring = NULL;
736*3db86aabSstevel 
737*3db86aabSstevel 	force = flags & CFGA_FLAG_FORCE;
738*3db86aabSstevel 
739*3db86aabSstevel 	switch (state_change_cmd) {
740*3db86aabSstevel 	case CFGA_CMD_CONFIGURE:
741*3db86aabSstevel 		rc =  mema_add(ap_id, options, errstring, force);
742*3db86aabSstevel 		break;
743*3db86aabSstevel 
744*3db86aabSstevel 	case CFGA_CMD_UNCONFIGURE:
745*3db86aabSstevel 		rc =  mema_delete(ap_id, options, errstring, force);
746*3db86aabSstevel 		break;
747*3db86aabSstevel 
748*3db86aabSstevel 	default:
749*3db86aabSstevel 		rc = CFGA_OPNOTSUPP;
750*3db86aabSstevel 		break;
751*3db86aabSstevel 	}
752*3db86aabSstevel 
753*3db86aabSstevel 	return (rc);
754*3db86aabSstevel }
755*3db86aabSstevel 
756*3db86aabSstevel /*ARGSUSED*/
757*3db86aabSstevel cfga_err_t
758*3db86aabSstevel cfga_private_func(
759*3db86aabSstevel 	const char *function,
760*3db86aabSstevel 	const char *ap_id,
761*3db86aabSstevel 	const char *options,
762*3db86aabSstevel 	struct cfga_confirm *confp,
763*3db86aabSstevel 	struct cfga_msg *msgp,
764*3db86aabSstevel 	char **errstring,
765*3db86aabSstevel 	cfga_flags_t flags)
766*3db86aabSstevel {
767*3db86aabSstevel 	mema_bank_t bk;
768*3db86aabSstevel 	ac_stat_t stat;
769*3db86aabSstevel 	int fd, ret, ret_errno;
770*3db86aabSstevel 	ac_cfga_cmd_t cmd;
771*3db86aabSstevel 	char outputstr[AC_OUTPUT_LEN];
772*3db86aabSstevel 
773*3db86aabSstevel 	if (errstring != NULL)
774*3db86aabSstevel 		*errstring = NULL;
775*3db86aabSstevel 
776*3db86aabSstevel 	ret = ap_stat(ap_id, &fd, &bk, &stat, errstring);
777*3db86aabSstevel 	if (ret != CFGA_OK)
778*3db86aabSstevel 		return (ret);
779*3db86aabSstevel 
780*3db86aabSstevel 	if (strcmp(function, "relocate-test") == 0) {
781*3db86aabSstevel 		struct ac_memx_relocate_stats rstat;
782*3db86aabSstevel 
783*3db86aabSstevel 		mema_cmd_init(&cmd, NULL, outputstr,
784*3db86aabSstevel 		    (flags & CFGA_FLAG_FORCE));
785*3db86aabSstevel 		cmd.arg = AC_MEMX_RELOCATE_ALL;
786*3db86aabSstevel 		cmd.private = &rstat;
787*3db86aabSstevel 		(void) memset((void *)&rstat, 0, sizeof (rstat));
788*3db86aabSstevel 		dump_ioctl(AC_MEM_EXERCISE, &cmd);
789*3db86aabSstevel 		ret = ioctl(fd, AC_MEM_EXERCISE, &cmd);
790*3db86aabSstevel 		ret_errno = errno;
791*3db86aabSstevel 		dump_ioctl_res(AC_MEM_EXERCISE, &cmd, ret, ret_errno);
792*3db86aabSstevel 		(void) close(fd);
793*3db86aabSstevel 
794*3db86aabSstevel 		if (ret == -1) {
795*3db86aabSstevel 			mema_err(&cmd, ret_errno, errstring, CMD_MEM_RELOCTEST);
796*3db86aabSstevel 			return (CFGA_ERROR);
797*3db86aabSstevel 		}
798*3db86aabSstevel 		return (CFGA_OK);
799*3db86aabSstevel 	}
800*3db86aabSstevel 
801*3db86aabSstevel 	__fmt_errstring(errstring, strlen(function),
802*3db86aabSstevel 	    dgettext(TEXT_DOMAIN, pfunc_unknown), function);
803*3db86aabSstevel 
804*3db86aabSstevel 	return (CFGA_ERROR);
805*3db86aabSstevel }
806*3db86aabSstevel 
807*3db86aabSstevel static int
808*3db86aabSstevel mtest_run(
809*3db86aabSstevel 	int fd,
810*3db86aabSstevel 	int test_fun,
811*3db86aabSstevel 	mema_bank_t *abkp,
812*3db86aabSstevel 	struct cfga_msg *msgp,
813*3db86aabSstevel 	char **errstring,
814*3db86aabSstevel 	ulong_t max_errors)
815*3db86aabSstevel {
816*3db86aabSstevel 	ac_mem_test_start_t test_start;
817*3db86aabSstevel 	ac_mem_test_stop_t test_stop;
818*3db86aabSstevel 	struct mtest_handle handle;
819*3db86aabSstevel 	int ret, ret_errno;
820*3db86aabSstevel 	int res;
821*3db86aabSstevel 	ac_cfga_cmd_t cmd;
822*3db86aabSstevel 	char outputstr[AC_OUTPUT_LEN];
823*3db86aabSstevel 
824*3db86aabSstevel 	(void) memset((void *)&test_start, 0, sizeof (test_start));
825*3db86aabSstevel 	mema_cmd_init(&cmd, &test_start, outputstr, 0);
826*3db86aabSstevel 	dump_ioctl(AC_MEM_TEST_START, &test_start);
827*3db86aabSstevel 	ret = ioctl(fd, AC_MEM_TEST_START, &cmd);
828*3db86aabSstevel 	ret_errno = errno;
829*3db86aabSstevel 	dump_ioctl_res(AC_MEM_TEST_START, &test_start, ret, ret_errno);
830*3db86aabSstevel 
831*3db86aabSstevel 	if (ret == -1) {
832*3db86aabSstevel 		if (ret_errno == ENOTSUP) {
833*3db86aabSstevel 			mema_err(&cmd, ret_errno, errstring,
834*3db86aabSstevel 				CMD_MEM_TEST_START);
835*3db86aabSstevel 			return (CFGA_OPNOTSUPP);
836*3db86aabSstevel 		}
837*3db86aabSstevel 		if (ret_errno == EBUSY && test_start.tester_pid > 0) {
838*3db86aabSstevel 			/*
839*3db86aabSstevel 			 * Bank appears to be being tested.  Check that
840*3db86aabSstevel 			 * process 'tester_pid' is still running.
841*3db86aabSstevel 			 */
842*3db86aabSstevel 			if (kill(test_start.tester_pid, 0) != -1 ||
843*3db86aabSstevel 			    errno != ESRCH) {
844*3db86aabSstevel 				cfga_ap_log_id_t bname;
845*3db86aabSstevel 
846*3db86aabSstevel 				/* Process still exists. */
847*3db86aabSstevel 				(void) sprintf(bname, "board %d bank%d",
848*3db86aabSstevel 				    abkp->board, abkp->bank);
849*3db86aabSstevel 				__fmt_errstring(errstring, strlen(bname),
850*3db86aabSstevel 				    dgettext(TEXT_DOMAIN, still_testing),
851*3db86aabSstevel 				    bname, test_start.tester_pid);
852*3db86aabSstevel 				return (CFGA_ERROR);
853*3db86aabSstevel 			}
854*3db86aabSstevel 			/*
855*3db86aabSstevel 			 * Do a test stop and re-try the start.
856*3db86aabSstevel 			 */
857*3db86aabSstevel 			(void) memset((void *)&test_stop, 0,
858*3db86aabSstevel 			    sizeof (test_stop));
859*3db86aabSstevel 			test_stop.handle = test_start.handle;
860*3db86aabSstevel 			test_stop.condition = SYSC_CFGA_COND_UNKNOWN;
861*3db86aabSstevel 			mema_cmd_init(&cmd, &test_stop, outputstr, 0);
862*3db86aabSstevel 			dump_ioctl(AC_MEM_TEST_STOP, &test_stop);
863*3db86aabSstevel 			ret = ioctl(fd, AC_MEM_TEST_STOP, &cmd);
864*3db86aabSstevel 			ret_errno = errno;
865*3db86aabSstevel 			dump_ioctl_res(AC_MEM_TEST_STOP, &test_stop,
866*3db86aabSstevel 			    ret, ret_errno);
867*3db86aabSstevel 			/*
868*3db86aabSstevel 			 * Ignore test stop error processing and re-try the
869*3db86aabSstevel 			 * start.  The error return will be derived from the
870*3db86aabSstevel 			 * result of start.
871*3db86aabSstevel 			 */
872*3db86aabSstevel 			(void) memset((void *)&test_start, 0,
873*3db86aabSstevel 			    sizeof (test_start));
874*3db86aabSstevel 			mema_cmd_init(&cmd, &test_start, outputstr, 0);
875*3db86aabSstevel 			dump_ioctl(AC_MEM_TEST_START, &test_start);
876*3db86aabSstevel 			ret = ioctl(fd, AC_MEM_TEST_START, &cmd);
877*3db86aabSstevel 			ret_errno = errno;
878*3db86aabSstevel 			dump_ioctl_res(AC_MEM_TEST_START, &test_start,
879*3db86aabSstevel 			    ret, ret_errno);
880*3db86aabSstevel 		}
881*3db86aabSstevel 		/* Test return code again to cover the case of a re-try. */
882*3db86aabSstevel 		if (ret == -1) {
883*3db86aabSstevel 			mema_err(&cmd, ret_errno, errstring,
884*3db86aabSstevel 			    CMD_MEM_TEST_START);
885*3db86aabSstevel 			return (CFGA_ERROR);
886*3db86aabSstevel 		}
887*3db86aabSstevel 	}
888*3db86aabSstevel 	(void) memset((void *)&handle, 0, sizeof (handle));
889*3db86aabSstevel 	handle.fd = fd;
890*3db86aabSstevel 	handle.drvhandle = (void *)&test_start;
891*3db86aabSstevel 	handle.msgp = msgp;
892*3db86aabSstevel 	handle.bank_size = test_start.bank_size;
893*3db86aabSstevel 	handle.page_size = test_start.page_size;
894*3db86aabSstevel 	handle.line_size = test_start.line_size;
895*3db86aabSstevel 	handle.lines_per_page = test_start.page_size / test_start.line_size;
896*3db86aabSstevel 	handle.condition = CFGA_COND_UNKNOWN;
897*3db86aabSstevel 	handle.max_errors = max_errors;
898*3db86aabSstevel 
899*3db86aabSstevel 	res = (*mtest_table[test_fun].test_func)(&handle);
900*3db86aabSstevel 
901*3db86aabSstevel 	mtest_deallocate_buf_all(&handle);
902*3db86aabSstevel 
903*3db86aabSstevel 	/*
904*3db86aabSstevel 	 * Convert memory test code to MEMA_ code.
905*3db86aabSstevel 	 */
906*3db86aabSstevel 	switch (res) {
907*3db86aabSstevel 	case MTEST_DONE:
908*3db86aabSstevel 		res = CFGA_OK;
909*3db86aabSstevel 		break;
910*3db86aabSstevel 	case MTEST_LIB_ERROR:
911*3db86aabSstevel 		__fmt_errstring(errstring, 0, dgettext(TEXT_DOMAIN,
912*3db86aabSstevel 		    mtest_lib_error));
913*3db86aabSstevel 		res = CFGA_ERROR;
914*3db86aabSstevel 		break;
915*3db86aabSstevel 	case MTEST_DEV_ERROR:
916*3db86aabSstevel 		__fmt_errstring(errstring, 0, dgettext(TEXT_DOMAIN,
917*3db86aabSstevel 		    mtest_rw_error));
918*3db86aabSstevel 		res = CFGA_ERROR;
919*3db86aabSstevel 		break;
920*3db86aabSstevel 	default:
921*3db86aabSstevel 		__fmt_errstring(errstring, 0, dgettext(TEXT_DOMAIN,
922*3db86aabSstevel 		    mtest_unknown_error));
923*3db86aabSstevel 		res = CFGA_ERROR;
924*3db86aabSstevel 		assert(0);
925*3db86aabSstevel 		break;
926*3db86aabSstevel 	}
927*3db86aabSstevel 
928*3db86aabSstevel 	(void) memset((void *)&test_stop, 0, sizeof (test_stop));
929*3db86aabSstevel 	test_stop.handle = test_start.handle;
930*3db86aabSstevel 	switch (handle.condition) {
931*3db86aabSstevel 	case CFGA_COND_OK:
932*3db86aabSstevel 		test_stop.condition = SYSC_CFGA_COND_OK;
933*3db86aabSstevel 		break;
934*3db86aabSstevel 	case CFGA_COND_FAILING:
935*3db86aabSstevel 		test_stop.condition = SYSC_CFGA_COND_FAILING;
936*3db86aabSstevel 		break;
937*3db86aabSstevel 	case CFGA_COND_FAILED:
938*3db86aabSstevel 		test_stop.condition = SYSC_CFGA_COND_FAILED;
939*3db86aabSstevel 		break;
940*3db86aabSstevel 	case CFGA_COND_UNKNOWN:
941*3db86aabSstevel 		test_stop.condition = SYSC_CFGA_COND_UNKNOWN;
942*3db86aabSstevel 		break;
943*3db86aabSstevel 	default:
944*3db86aabSstevel 		test_stop.condition = SYSC_CFGA_COND_UNKNOWN;
945*3db86aabSstevel 		assert(0);
946*3db86aabSstevel 		break;
947*3db86aabSstevel 	}
948*3db86aabSstevel 
949*3db86aabSstevel 	mema_cmd_init(&cmd, &test_stop, outputstr, 0);
950*3db86aabSstevel 	dump_ioctl(AC_MEM_TEST_STOP, &test_stop);
951*3db86aabSstevel 	ret = ioctl(fd, AC_MEM_TEST_STOP, &cmd);
952*3db86aabSstevel 	ret_errno = errno;
953*3db86aabSstevel 	dump_ioctl_res(AC_MEM_TEST_STOP, &test_stop, ret, ret_errno);
954*3db86aabSstevel 	if (ret == -1) {
955*3db86aabSstevel 		mema_err(&cmd, ret_errno, errstring,
956*3db86aabSstevel 		    CMD_MEM_TEST_STOP);
957*3db86aabSstevel 		return (CFGA_ERROR);
958*3db86aabSstevel 	}
959*3db86aabSstevel 	return (res);
960*3db86aabSstevel }
961*3db86aabSstevel 
962*3db86aabSstevel #define	DRVHANDLE(H)	(((ac_mem_test_start_t *)(H)->drvhandle)->handle)
963*3db86aabSstevel 
964*3db86aabSstevel int
965*3db86aabSstevel mtest_write(
966*3db86aabSstevel 	mtest_handle_t handle,
967*3db86aabSstevel 	void *page_buf,
968*3db86aabSstevel 	u_longlong_t page_no,
969*3db86aabSstevel 	uint_t line_offset,
970*3db86aabSstevel 	uint_t line_count)
971*3db86aabSstevel {
972*3db86aabSstevel 	ac_mem_test_write_t test_write;
973*3db86aabSstevel 	int fd, ret, ret_errno;
974*3db86aabSstevel 	ac_cfga_cmd_t cmd;
975*3db86aabSstevel 	char outputstr[AC_OUTPUT_LEN];
976*3db86aabSstevel 
977*3db86aabSstevel 	(void) memset((void *)&test_write, 0, sizeof (test_write));
978*3db86aabSstevel 	fd = handle->fd;
979*3db86aabSstevel 	test_write.handle = DRVHANDLE(handle);
980*3db86aabSstevel 	test_write.page_buf = page_buf;
981*3db86aabSstevel 	test_write.address.page_num = page_no;
982*3db86aabSstevel 	test_write.address.line_offset = line_offset;
983*3db86aabSstevel 	if (line_count == 0)
984*3db86aabSstevel 		test_write.address.line_count = handle->lines_per_page;
985*3db86aabSstevel 	else
986*3db86aabSstevel 		test_write.address.line_count = line_count;
987*3db86aabSstevel 
988*3db86aabSstevel 	mema_cmd_init(&cmd, &test_write, outputstr, 0);
989*3db86aabSstevel 	dump_ioctl(AC_MEM_TEST_WRITE, &test_write);
990*3db86aabSstevel 	ret = ioctl(fd, AC_MEM_TEST_WRITE, &cmd);
991*3db86aabSstevel 	ret_errno = errno;
992*3db86aabSstevel 	dump_ioctl_res(AC_MEM_TEST_WRITE, &test_write, ret, ret_errno);
993*3db86aabSstevel 
994*3db86aabSstevel 	if (ret == -1)
995*3db86aabSstevel 		return (-1);
996*3db86aabSstevel 	return (0);
997*3db86aabSstevel }
998*3db86aabSstevel 
999*3db86aabSstevel int
1000*3db86aabSstevel mtest_read(
1001*3db86aabSstevel 	mtest_handle_t handle,
1002*3db86aabSstevel 	void *page_buf,
1003*3db86aabSstevel 	u_longlong_t page_no,
1004*3db86aabSstevel 	uint_t line_offset,
1005*3db86aabSstevel 	uint_t line_count,
1006*3db86aabSstevel 	struct mtest_error *errp)
1007*3db86aabSstevel {
1008*3db86aabSstevel 	ac_mem_test_read_t test_read;
1009*3db86aabSstevel 	sunfire_processor_error_regs_t errbuf;
1010*3db86aabSstevel 	int fd, ret, ret_errno;
1011*3db86aabSstevel 	ac_cfga_cmd_t cmd;
1012*3db86aabSstevel 	char outputstr[AC_OUTPUT_LEN];
1013*3db86aabSstevel 
1014*3db86aabSstevel 	(void) memset((void *)&test_read, 0, sizeof (test_read));
1015*3db86aabSstevel 	(void) memset((void *)&errbuf, 0, sizeof (errbuf));
1016*3db86aabSstevel 	fd = handle->fd;
1017*3db86aabSstevel 	test_read.handle = DRVHANDLE(handle);
1018*3db86aabSstevel 	test_read.page_buf = page_buf;
1019*3db86aabSstevel 	test_read.address.page_num = page_no;
1020*3db86aabSstevel 	test_read.address.line_offset = line_offset;
1021*3db86aabSstevel 	test_read.error_buf =  &errbuf;
1022*3db86aabSstevel 	if (line_count == 0)
1023*3db86aabSstevel 		test_read.address.line_count = handle->lines_per_page;
1024*3db86aabSstevel 	else
1025*3db86aabSstevel 		test_read.address.line_count = line_count;
1026*3db86aabSstevel 
1027*3db86aabSstevel 	mema_cmd_init(&cmd, &test_read, outputstr, 0);
1028*3db86aabSstevel 	dump_ioctl(AC_MEM_TEST_READ, &test_read);
1029*3db86aabSstevel 	ret = ioctl(fd, AC_MEM_TEST_READ, &cmd);
1030*3db86aabSstevel 	ret_errno = errno;
1031*3db86aabSstevel 	dump_ioctl_res(AC_MEM_TEST_READ, &test_read, ret, ret_errno);
1032*3db86aabSstevel 
1033*3db86aabSstevel 	if (ret == -1) {
1034*3db86aabSstevel 		if (ret_errno == EIO) {
1035*3db86aabSstevel 			/*
1036*3db86aabSstevel 			 * Special case indicating CE or UE.
1037*3db86aabSstevel 			 */
1038*3db86aabSstevel 			if (((errbuf.udbh_error_reg | errbuf.udbl_error_reg) &
1039*3db86aabSstevel 			    P_DER_UE) != 0)
1040*3db86aabSstevel 				errp->error_type = MTEST_ERR_UE;
1041*3db86aabSstevel 			else
1042*3db86aabSstevel 				errp->error_type = MTEST_ERR_CE;
1043*3db86aabSstevel 		} else {
1044*3db86aabSstevel 			return (-1);
1045*3db86aabSstevel 		}
1046*3db86aabSstevel 	} else {
1047*3db86aabSstevel 		errp->error_type = MTEST_ERR_NONE;
1048*3db86aabSstevel 	}
1049*3db86aabSstevel 	return (0);
1050*3db86aabSstevel }
1051*3db86aabSstevel 
1052*3db86aabSstevel static char *
1053*3db86aabSstevel subopt_help_str(char *opts[])
1054*3db86aabSstevel {
1055*3db86aabSstevel 	char *str;
1056*3db86aabSstevel 	const char *sep;
1057*3db86aabSstevel 	int len;
1058*3db86aabSstevel 	int i, n;
1059*3db86aabSstevel 	static const char help_sep[] = ", ";
1060*3db86aabSstevel 	static const char help_nil[] = "???";
1061*3db86aabSstevel 
1062*3db86aabSstevel 	len = 0;
1063*3db86aabSstevel 	n = 0;
1064*3db86aabSstevel 	for (i = 0; opts[i] != NULL; i++) {
1065*3db86aabSstevel 		n++;
1066*3db86aabSstevel 		len += strlen(opts[i]);
1067*3db86aabSstevel 	}
1068*3db86aabSstevel 	if (n == 0)
1069*3db86aabSstevel 		return (strdup(help_nil));
1070*3db86aabSstevel 	len += (n - 1) * strlen(help_sep);
1071*3db86aabSstevel 	len++;
1072*3db86aabSstevel 	str = (char *)malloc(len);
1073*3db86aabSstevel 	if (str == NULL)
1074*3db86aabSstevel 		return (NULL);
1075*3db86aabSstevel 	*str = '\0';
1076*3db86aabSstevel 	sep = "";
1077*3db86aabSstevel 	for (i = 0; opts[i] != NULL; i++) {
1078*3db86aabSstevel 		(void) strcat(str, sep);
1079*3db86aabSstevel 		(void) strcat(str, opts[i]);
1080*3db86aabSstevel 		sep = help_sep;
1081*3db86aabSstevel 	}
1082*3db86aabSstevel 	return (str);
1083*3db86aabSstevel }
1084*3db86aabSstevel 
1085*3db86aabSstevel /*ARGSUSED*/
1086*3db86aabSstevel cfga_err_t
1087*3db86aabSstevel cfga_test(
1088*3db86aabSstevel 	const char *ap_id,
1089*3db86aabSstevel 	const char *options,
1090*3db86aabSstevel 	struct cfga_msg *msgp,
1091*3db86aabSstevel 	char **errstring,
1092*3db86aabSstevel 	cfga_flags_t flags)
1093*3db86aabSstevel {
1094*3db86aabSstevel 	mema_bank_t bk;
1095*3db86aabSstevel 	ac_stat_t stat;
1096*3db86aabSstevel 	int test_fun = -1;
1097*3db86aabSstevel 	int fd, ret;
1098*3db86aabSstevel 	int maxerr_idx;
1099*3db86aabSstevel 	long max_errors = -1;
1100*3db86aabSstevel 	char *ret_p;
1101*3db86aabSstevel 
1102*3db86aabSstevel 	if (errstring != NULL)
1103*3db86aabSstevel 		*errstring = NULL;
1104*3db86aabSstevel 
1105*3db86aabSstevel 	/*
1106*3db86aabSstevel 	 * Decode test level and max error number.
1107*3db86aabSstevel 	 */
1108*3db86aabSstevel 	if (options != NULL && *options != '\0') {
1109*3db86aabSstevel 		char **opts;
1110*3db86aabSstevel 		char *value;
1111*3db86aabSstevel 		char *cp, *free_cp;
1112*3db86aabSstevel 		int subopt;
1113*3db86aabSstevel 
1114*3db86aabSstevel 		/* getsubopt() modifies the input string, so copy it. */
1115*3db86aabSstevel 		cp = strdup(options);
1116*3db86aabSstevel 		if (cp == NULL) {
1117*3db86aabSstevel 			return (CFGA_LIB_ERROR);
1118*3db86aabSstevel 		}
1119*3db86aabSstevel 		free_cp = cp;
1120*3db86aabSstevel 		opts = mtest_build_opts(&maxerr_idx);
1121*3db86aabSstevel 		if (opts == NULL) {
1122*3db86aabSstevel 			free((void *)free_cp);
1123*3db86aabSstevel 			return (CFGA_LIB_ERROR);
1124*3db86aabSstevel 		}
1125*3db86aabSstevel 
1126*3db86aabSstevel 		while (*cp != '\0') {
1127*3db86aabSstevel 			subopt = getsubopt(&cp, opts, &value);
1128*3db86aabSstevel 			if (subopt == -1) {
1129*3db86aabSstevel 				char *hlp;
1130*3db86aabSstevel 
1131*3db86aabSstevel 				hlp = subopt_help_str(opts);
1132*3db86aabSstevel 				if (hlp != NULL) {
1133*3db86aabSstevel 					__fmt_errstring(errstring,
1134*3db86aabSstevel 					strlen(value) + strlen(hlp),
1135*3db86aabSstevel 					dgettext(TEXT_DOMAIN, unk_test),
1136*3db86aabSstevel 					value, hlp);
1137*3db86aabSstevel 					free((void *)hlp);
1138*3db86aabSstevel 				} else {
1139*3db86aabSstevel 					__fmt_errstring(errstring, 20,
1140*3db86aabSstevel 					dgettext(TEXT_DOMAIN, calloc_fail),
1141*3db86aabSstevel 						strlen(options) + 1, 1);
1142*3db86aabSstevel 				}
1143*3db86aabSstevel 				/* Free after printing value. */
1144*3db86aabSstevel 				free((void *)free_cp);
1145*3db86aabSstevel 				return (CFGA_ERROR);
1146*3db86aabSstevel 			}
1147*3db86aabSstevel 
1148*3db86aabSstevel 			if (test_fun != -1 && subopt != test_fun &&
1149*3db86aabSstevel 			    subopt != maxerr_idx) {
1150*3db86aabSstevel 				__fmt_errstring(errstring,
1151*3db86aabSstevel 				    strlen(opts[subopt]),
1152*3db86aabSstevel 				    dgettext(TEXT_DOMAIN, dup_test),
1153*3db86aabSstevel 				    opts[subopt]);
1154*3db86aabSstevel 				free((void *)free_cp);
1155*3db86aabSstevel 				return (CFGA_ERROR);
1156*3db86aabSstevel 			}
1157*3db86aabSstevel 
1158*3db86aabSstevel 			if (subopt < maxerr_idx)
1159*3db86aabSstevel 				test_fun = subopt;
1160*3db86aabSstevel 			else {
1161*3db86aabSstevel 
1162*3db86aabSstevel 				if (max_errors != -1 && subopt == maxerr_idx) {
1163*3db86aabSstevel 					__fmt_errstring(errstring,
1164*3db86aabSstevel 					strlen(opts[subopt]),
1165*3db86aabSstevel 					dgettext(TEXT_DOMAIN, dup_num),
1166*3db86aabSstevel 					opts[subopt]);
1167*3db86aabSstevel 					free((void *)free_cp);
1168*3db86aabSstevel 					return (CFGA_ERROR);
1169*3db86aabSstevel 				}
1170*3db86aabSstevel 
1171*3db86aabSstevel 				if (value == NULL) {
1172*3db86aabSstevel 					__fmt_errstring(errstring,
1173*3db86aabSstevel 					0,
1174*3db86aabSstevel 					dgettext(TEXT_DOMAIN, no_num),
1175*3db86aabSstevel 					"");
1176*3db86aabSstevel 					free((void *)free_cp);
1177*3db86aabSstevel 					return (CFGA_ERROR);
1178*3db86aabSstevel 				}
1179*3db86aabSstevel 
1180*3db86aabSstevel 				max_errors = strtol(value, &ret_p, 10);
1181*3db86aabSstevel 				if ((ret_p == value) || (*ret_p != '\0') ||
1182*3db86aabSstevel 				    (max_errors < 0)) {
1183*3db86aabSstevel 					__fmt_errstring(errstring,
1184*3db86aabSstevel 					strlen(value),
1185*3db86aabSstevel 					dgettext(TEXT_DOMAIN, no_num),
1186*3db86aabSstevel 					value);
1187*3db86aabSstevel 					free((void *)free_cp);
1188*3db86aabSstevel 					return (CFGA_ERROR);
1189*3db86aabSstevel 				}
1190*3db86aabSstevel 			}
1191*3db86aabSstevel 		}
1192*3db86aabSstevel 		free((void *)free_cp);
1193*3db86aabSstevel 	}
1194*3db86aabSstevel 
1195*3db86aabSstevel 	if (test_fun == -1)
1196*3db86aabSstevel 		test_fun = MTEST_DEFAULT_TEST;
1197*3db86aabSstevel 	if (max_errors == -1)
1198*3db86aabSstevel 		max_errors = MAX_ERRORS;
1199*3db86aabSstevel 
1200*3db86aabSstevel 	ret = ap_stat(ap_id, &fd, &bk, &stat, errstring);
1201*3db86aabSstevel 	if (ret != CFGA_OK)
1202*3db86aabSstevel 		return (ret);
1203*3db86aabSstevel 
1204*3db86aabSstevel 	if (stat.rstate != SYSC_CFGA_RSTATE_CONNECTED ||
1205*3db86aabSstevel 	    stat.ostate != SYSC_CFGA_OSTATE_UNCONFIGURED) {
1206*3db86aabSstevel 		__fmt_errstring(errstring, 0,
1207*3db86aabSstevel 		    dgettext(TEXT_DOMAIN, trans_illegal));
1208*3db86aabSstevel 		(void) close(fd);
1209*3db86aabSstevel 		return (CFGA_ERROR);
1210*3db86aabSstevel 	}
1211*3db86aabSstevel 
1212*3db86aabSstevel 	ret = mtest_run(fd, test_fun, &bk,
1213*3db86aabSstevel 	    ((flags & CFGA_FLAG_VERBOSE) != 0) ? msgp : NULL, errstring,
1214*3db86aabSstevel 	    (ulong_t)max_errors);
1215*3db86aabSstevel 
1216*3db86aabSstevel 	(void) close(fd);
1217*3db86aabSstevel 
1218*3db86aabSstevel 	return (ret);
1219*3db86aabSstevel }
1220*3db86aabSstevel 
1221*3db86aabSstevel static cfga_stat_t
1222*3db86aabSstevel rstate_cvt(sysc_cfga_rstate_t rs)
1223*3db86aabSstevel {
1224*3db86aabSstevel 	cfga_stat_t cs;
1225*3db86aabSstevel 
1226*3db86aabSstevel 	switch (rs) {
1227*3db86aabSstevel 	case SYSC_CFGA_RSTATE_EMPTY:
1228*3db86aabSstevel 		cs = CFGA_STAT_EMPTY;
1229*3db86aabSstevel 		break;
1230*3db86aabSstevel 	case SYSC_CFGA_RSTATE_DISCONNECTED:
1231*3db86aabSstevel 		cs = CFGA_STAT_DISCONNECTED;
1232*3db86aabSstevel 		break;
1233*3db86aabSstevel 	case SYSC_CFGA_RSTATE_CONNECTED:
1234*3db86aabSstevel 		cs = CFGA_STAT_CONNECTED;
1235*3db86aabSstevel 		break;
1236*3db86aabSstevel 	default:
1237*3db86aabSstevel 		cs = CFGA_STAT_NONE;
1238*3db86aabSstevel 		break;
1239*3db86aabSstevel 	}
1240*3db86aabSstevel 
1241*3db86aabSstevel 	return (cs);
1242*3db86aabSstevel }
1243*3db86aabSstevel 
1244*3db86aabSstevel static cfga_stat_t
1245*3db86aabSstevel ostate_cvt(sysc_cfga_ostate_t os)
1246*3db86aabSstevel {
1247*3db86aabSstevel 	cfga_stat_t cs;
1248*3db86aabSstevel 
1249*3db86aabSstevel 	switch (os) {
1250*3db86aabSstevel 	case SYSC_CFGA_OSTATE_UNCONFIGURED:
1251*3db86aabSstevel 		cs = CFGA_STAT_UNCONFIGURED;
1252*3db86aabSstevel 		break;
1253*3db86aabSstevel 	case SYSC_CFGA_OSTATE_CONFIGURED:
1254*3db86aabSstevel 		cs = CFGA_STAT_CONFIGURED;
1255*3db86aabSstevel 		break;
1256*3db86aabSstevel 	default:
1257*3db86aabSstevel 		cs = CFGA_STAT_NONE;
1258*3db86aabSstevel 		break;
1259*3db86aabSstevel 	}
1260*3db86aabSstevel 
1261*3db86aabSstevel 	return (cs);
1262*3db86aabSstevel }
1263*3db86aabSstevel 
1264*3db86aabSstevel static cfga_cond_t
1265*3db86aabSstevel cond_cvt(sysc_cfga_cond_t sc)
1266*3db86aabSstevel {
1267*3db86aabSstevel 	cfga_cond_t cc;
1268*3db86aabSstevel 
1269*3db86aabSstevel 	switch (sc) {
1270*3db86aabSstevel 	case SYSC_CFGA_COND_OK:
1271*3db86aabSstevel 		cc = CFGA_COND_OK;
1272*3db86aabSstevel 		break;
1273*3db86aabSstevel 	case SYSC_CFGA_COND_FAILING:
1274*3db86aabSstevel 		cc = CFGA_COND_FAILING;
1275*3db86aabSstevel 		break;
1276*3db86aabSstevel 	case SYSC_CFGA_COND_FAILED:
1277*3db86aabSstevel 		cc = CFGA_COND_FAILED;
1278*3db86aabSstevel 		break;
1279*3db86aabSstevel 	case SYSC_CFGA_COND_UNUSABLE:
1280*3db86aabSstevel 		cc = CFGA_COND_UNUSABLE;
1281*3db86aabSstevel 		break;
1282*3db86aabSstevel 	case SYSC_CFGA_COND_UNKNOWN:
1283*3db86aabSstevel 	default:
1284*3db86aabSstevel 		cc = CFGA_COND_UNKNOWN;
1285*3db86aabSstevel 		break;
1286*3db86aabSstevel 	}
1287*3db86aabSstevel 
1288*3db86aabSstevel 	return (cc);
1289*3db86aabSstevel }
1290*3db86aabSstevel 
1291*3db86aabSstevel static void
1292*3db86aabSstevel info_set(ac_stat_t *asp, mema_bank_t *bkp, cfga_info_t info)
1293*3db86aabSstevel {
1294*3db86aabSstevel 	mema_disabled_t disab;
1295*3db86aabSstevel 	uint_t board;
1296*3db86aabSstevel 	uint_t n;
1297*3db86aabSstevel 	u_longlong_t decode;
1298*3db86aabSstevel 	uint_t intlv;
1299*3db86aabSstevel 	char *f;
1300*3db86aabSstevel 	char *end;
1301*3db86aabSstevel 
1302*3db86aabSstevel 	end = &info[sizeof (cfga_info_t)];
1303*3db86aabSstevel 	*info = NULL;
1304*3db86aabSstevel 
1305*3db86aabSstevel 	board = bkp->board;
1306*3db86aabSstevel 
1307*3db86aabSstevel 	/* Print the board number in a way that matches the sysctrl AP. */
1308*3db86aabSstevel 	info += snprintf(info, end - info, "slot%d", board);
1309*3db86aabSstevel 
1310*3db86aabSstevel 	if (asp->real_size == 0) {
1311*3db86aabSstevel 		info += snprintf(info, end - info, " empty");
1312*3db86aabSstevel 		return;
1313*3db86aabSstevel 	}
1314*3db86aabSstevel 
1315*3db86aabSstevel 	if ((n = asp->real_size) >= 1024) {
1316*3db86aabSstevel 		n /= 1024;
1317*3db86aabSstevel 		f = "Gb";
1318*3db86aabSstevel 	} else
1319*3db86aabSstevel 		f = "Mb";
1320*3db86aabSstevel 	info += snprintf(info, end - info, " %d%s", n, f);
1321*3db86aabSstevel 
1322*3db86aabSstevel 	if (asp->rstate == SYSC_CFGA_RSTATE_CONNECTED &&
1323*3db86aabSstevel 	    asp->ostate == SYSC_CFGA_OSTATE_CONFIGURED &&
1324*3db86aabSstevel 	    asp->use_size != asp->real_size) {
1325*3db86aabSstevel 		if ((n = asp->use_size) >= 1024) {
1326*3db86aabSstevel 			n /= 1024;
1327*3db86aabSstevel 			f = "Gb";
1328*3db86aabSstevel 		} else
1329*3db86aabSstevel 			f = "Mb";
1330*3db86aabSstevel 		info += snprintf(info, end - info, " (%d%s used)", n, f);
1331*3db86aabSstevel 	}
1332*3db86aabSstevel 
1333*3db86aabSstevel 	if (bkp->bank == 0)
1334*3db86aabSstevel 		decode = asp->ac_decode0;
1335*3db86aabSstevel 	else
1336*3db86aabSstevel 		decode = asp->ac_decode1;
1337*3db86aabSstevel 
1338*3db86aabSstevel 	info += snprintf(info, end - info, " base 0x%llx",
1339*3db86aabSstevel 	    GRP_REALBASE(decode));
1340*3db86aabSstevel 
1341*3db86aabSstevel 	if (bkp->bank == 0)
1342*3db86aabSstevel 		intlv = INTLV0(asp->ac_memctl);
1343*3db86aabSstevel 	else
1344*3db86aabSstevel 		intlv = INTLV1(asp->ac_memctl);
1345*3db86aabSstevel 
1346*3db86aabSstevel 	if (intlv != 1)
1347*3db86aabSstevel 		info += snprintf(info, end - info, " interleaved %u-way",
1348*3db86aabSstevel 		    intlv);
1349*3db86aabSstevel 
1350*3db86aabSstevel 	if (prom_read_disabled_list(&disab, board)) {
1351*3db86aabSstevel 		if (disab != 0) {
1352*3db86aabSstevel 			info += snprintf(info, end - info, " disabled at boot");
1353*3db86aabSstevel 		}
1354*3db86aabSstevel 
1355*3db86aabSstevel 	}
1356*3db86aabSstevel 
1357*3db86aabSstevel 	if (asp->rstate == SYSC_CFGA_RSTATE_CONNECTED &&
1358*3db86aabSstevel 	    asp->ostate == SYSC_CFGA_OSTATE_CONFIGURED &&
1359*3db86aabSstevel 	    asp->nonrelocatable)
1360*3db86aabSstevel 		info += snprintf(info, end - info, " permanent");
1361*3db86aabSstevel }
1362*3db86aabSstevel 
1363*3db86aabSstevel static void
1364*3db86aabSstevel mema_cvt(ac_stat_t *ac, mema_bank_t *bkp, cfga_stat_data_t *cs)
1365*3db86aabSstevel {
1366*3db86aabSstevel 	(void) strcpy(cs->ap_type, "memory");
1367*3db86aabSstevel 	cs->ap_r_state = rstate_cvt(ac->rstate);
1368*3db86aabSstevel 	cs->ap_o_state = ostate_cvt(ac->ostate);
1369*3db86aabSstevel 	cs->ap_cond = cond_cvt(ac->condition);
1370*3db86aabSstevel 	cs->ap_busy = (cfga_busy_t)ac->busy;
1371*3db86aabSstevel 	cs->ap_status_time = ac->status_time;
1372*3db86aabSstevel 	info_set(ac, bkp, cs->ap_info);
1373*3db86aabSstevel 	cs->ap_log_id[0] = NULL;
1374*3db86aabSstevel 	cs->ap_phys_id[0] = NULL;
1375*3db86aabSstevel }
1376*3db86aabSstevel 
1377*3db86aabSstevel /*ARGSUSED*/
1378*3db86aabSstevel cfga_err_t
1379*3db86aabSstevel cfga_stat(
1380*3db86aabSstevel 	const char *ap_id,
1381*3db86aabSstevel 	struct cfga_stat_data *cs,
1382*3db86aabSstevel 	const char *options,
1383*3db86aabSstevel 	char **errstring)
1384*3db86aabSstevel {
1385*3db86aabSstevel 	int ret;
1386*3db86aabSstevel 	mema_bank_t bk;
1387*3db86aabSstevel 	ac_stat_t stat;
1388*3db86aabSstevel 	option_set_t do_option;
1389*3db86aabSstevel 
1390*3db86aabSstevel 	if (errstring != NULL)
1391*3db86aabSstevel 		*errstring = NULL;
1392*3db86aabSstevel 
1393*3db86aabSstevel 	ret = 0;
1394*3db86aabSstevel 	do_option = process_options(options, stat_opts, &ret, errstring);
1395*3db86aabSstevel 	if (ret != 0)
1396*3db86aabSstevel 		return (ret);
1397*3db86aabSstevel 
1398*3db86aabSstevel 	ret = ap_stat(ap_id, NULL, &bk, &stat, errstring);
1399*3db86aabSstevel 	if (ret != CFGA_OK)
1400*3db86aabSstevel 		return (ret);
1401*3db86aabSstevel 
1402*3db86aabSstevel 	mema_cvt(&stat, &bk, cs);
1403*3db86aabSstevel 
1404*3db86aabSstevel 	ret = prom_do_options(do_option, bk.board, &stat, errstring);
1405*3db86aabSstevel 
1406*3db86aabSstevel 	return (ret);
1407*3db86aabSstevel }
1408*3db86aabSstevel 
1409*3db86aabSstevel /*ARGSUSED*/
1410*3db86aabSstevel cfga_err_t
1411*3db86aabSstevel cfga_list(
1412*3db86aabSstevel 	const char *ap_id,
1413*3db86aabSstevel 	cfga_stat_data_t **ap_list,
1414*3db86aabSstevel 	int *nlist,
1415*3db86aabSstevel 	const char *options,
1416*3db86aabSstevel 	char **errstring)
1417*3db86aabSstevel {
1418*3db86aabSstevel 	if (errstring != NULL)
1419*3db86aabSstevel 		*errstring = NULL;
1420*3db86aabSstevel 
1421*3db86aabSstevel 	return (CFGA_NOTSUPP);
1422*3db86aabSstevel }
1423*3db86aabSstevel 
1424*3db86aabSstevel /*
1425*3db86aabSstevel  * cfga_ap_id_cmp -- use default_ap_id_cmp() in libcfgadm
1426*3db86aabSstevel  */
1427*3db86aabSstevel 
1428*3db86aabSstevel /*ARGSUSED*/
1429*3db86aabSstevel cfga_err_t
1430*3db86aabSstevel cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
1431*3db86aabSstevel {
1432*3db86aabSstevel 
1433*3db86aabSstevel 
1434*3db86aabSstevel 	(*msgp->message_routine)(msgp->appdata_ptr, mema_help);
1435*3db86aabSstevel 	(*msgp->message_routine)(msgp->appdata_ptr, disable_opts);
1436*3db86aabSstevel 	(*msgp->message_routine)(msgp->appdata_ptr, enable_opts);
1437*3db86aabSstevel 	(*msgp->message_routine)(msgp->appdata_ptr, timeout_opts);
1438*3db86aabSstevel 	(*msgp->message_routine)(msgp->appdata_ptr, test_opts);
1439*3db86aabSstevel 	(*msgp->message_routine)(msgp->appdata_ptr, private_funcs);
1440*3db86aabSstevel 
1441*3db86aabSstevel 	return (CFGA_OK);
1442*3db86aabSstevel }
1443*3db86aabSstevel 
1444*3db86aabSstevel #if 0
1445*3db86aabSstevel static ac_mem_version_t
1446*3db86aabSstevel get_version(int fd)
1447*3db86aabSstevel {
1448*3db86aabSstevel 	ac_mem_version_t ver;
1449*3db86aabSstevel 	int ret, ret_errno;
1450*3db86aabSstevel 
1451*3db86aabSstevel 	ver = 0;
1452*3db86aabSstevel 	dump_ioctl(AC_MEM_ADMIN_VER, &ver);
1453*3db86aabSstevel 	ret = ioctl(fd, AC_MEM_ADMIN_VER, &ver);
1454*3db86aabSstevel 	ret_errno = errno;
1455*3db86aabSstevel 	dump_ioctl_res(AC_MEM_ADMIN_VER, &ver, ret, ret_errno);
1456*3db86aabSstevel 	return (ver);
1457*3db86aabSstevel }
1458*3db86aabSstevel #endif
1459*3db86aabSstevel 
1460*3db86aabSstevel static char *
1461*3db86aabSstevel opt_help_str(struct opt_control *opts)
1462*3db86aabSstevel {
1463*3db86aabSstevel 	char *str;
1464*3db86aabSstevel 	const char *sep;
1465*3db86aabSstevel 	int len;
1466*3db86aabSstevel 	int i, n;
1467*3db86aabSstevel 	static const char help_sep[] = ", ";
1468*3db86aabSstevel 	static const char help_nil[] = "???";
1469*3db86aabSstevel 
1470*3db86aabSstevel 	len = 0;
1471*3db86aabSstevel 	n = 0;
1472*3db86aabSstevel 	for (i = 0; opts[i].subopt != -1; i++) {
1473*3db86aabSstevel 		n++;
1474*3db86aabSstevel 		len += strlen(mema_opts[opts[i].subopt]);
1475*3db86aabSstevel 	}
1476*3db86aabSstevel 	if (n == 0)
1477*3db86aabSstevel 		return (strdup(help_nil));
1478*3db86aabSstevel 	len += (n - 1) * strlen(help_sep);
1479*3db86aabSstevel 	len++;
1480*3db86aabSstevel 	str = (char *)malloc(len);
1481*3db86aabSstevel 	if (str == NULL)
1482*3db86aabSstevel 		return (NULL);
1483*3db86aabSstevel 	*str = '\0';
1484*3db86aabSstevel 	sep = "";
1485*3db86aabSstevel 	for (i = 0; opts[i].subopt != -1; i++) {
1486*3db86aabSstevel 		(void) strcat(str, sep);
1487*3db86aabSstevel 		(void) strcat(str, mema_opts[opts[i].subopt]);
1488*3db86aabSstevel 		sep = help_sep;
1489*3db86aabSstevel 	}
1490*3db86aabSstevel 	return (str);
1491*3db86aabSstevel }
1492*3db86aabSstevel 
1493*3db86aabSstevel static option_set_t
1494*3db86aabSstevel process_options(
1495*3db86aabSstevel 	const char *options,
1496*3db86aabSstevel 	struct opt_control *opts,
1497*3db86aabSstevel 	int *retp,
1498*3db86aabSstevel 	char **errstring)
1499*3db86aabSstevel {
1500*3db86aabSstevel 	option_set_t opt_set;
1501*3db86aabSstevel 	char *optcopy, *optcopy_alloc;
1502*3db86aabSstevel 	char *value;
1503*3db86aabSstevel 	int subopt;
1504*3db86aabSstevel 	int subopt_err;
1505*3db86aabSstevel 	int i;
1506*3db86aabSstevel 	int group;
1507*3db86aabSstevel 	int need_value;
1508*3db86aabSstevel 
1509*3db86aabSstevel 	OPTSET_INIT(opt_set);
1510*3db86aabSstevel 
1511*3db86aabSstevel 	if (options == NULL || *options == '\0') {
1512*3db86aabSstevel 		return (opt_set);
1513*3db86aabSstevel 	}
1514*3db86aabSstevel 
1515*3db86aabSstevel 	optcopy = optcopy_alloc = strdup(options);
1516*3db86aabSstevel 	if (optcopy_alloc == NULL) {
1517*3db86aabSstevel 		__fmt_errstring(errstring, 20,
1518*3db86aabSstevel 		    dgettext(TEXT_DOMAIN, calloc_fail), strlen(options) + 1, 1);
1519*3db86aabSstevel 		*retp = CFGA_LIB_ERROR;
1520*3db86aabSstevel 		return (opt_set);
1521*3db86aabSstevel 	}
1522*3db86aabSstevel 
1523*3db86aabSstevel 	subopt_err = 0;
1524*3db86aabSstevel 	while (*optcopy != '\0' && subopt_err == 0) {
1525*3db86aabSstevel 		subopt = getsubopt(&optcopy, mema_opts, &value);
1526*3db86aabSstevel 		if (subopt == -1) {
1527*3db86aabSstevel 			char *hlp;
1528*3db86aabSstevel 
1529*3db86aabSstevel 			hlp = opt_help_str(opts);
1530*3db86aabSstevel 			__fmt_errstring(errstring, strlen(value) + strlen(hlp),
1531*3db86aabSstevel 			    dgettext(TEXT_DOMAIN, unk_subopt), value, hlp);
1532*3db86aabSstevel 			free((void *)hlp);
1533*3db86aabSstevel 			subopt_err = 1;
1534*3db86aabSstevel 			break;
1535*3db86aabSstevel 		}
1536*3db86aabSstevel 		for (i = 0; opts[i].subopt != -1; i++) {
1537*3db86aabSstevel 			if (opts[i].subopt == subopt) {
1538*3db86aabSstevel 				group = opts[i].group;
1539*3db86aabSstevel 				break;
1540*3db86aabSstevel 			}
1541*3db86aabSstevel 		}
1542*3db86aabSstevel 		if (opts[i].subopt == -1) {
1543*3db86aabSstevel 			char *hlp;
1544*3db86aabSstevel 
1545*3db86aabSstevel 			hlp = opt_help_str(opts);
1546*3db86aabSstevel 			__fmt_errstring(errstring,
1547*3db86aabSstevel 			    MAX_OPT_LENGTH + strlen(hlp),
1548*3db86aabSstevel 			    dgettext(TEXT_DOMAIN, not_valid),
1549*3db86aabSstevel 			    mema_opts[subopt], hlp);
1550*3db86aabSstevel 			free((void *)hlp);
1551*3db86aabSstevel 			subopt_err = 1;
1552*3db86aabSstevel 			break;
1553*3db86aabSstevel 		}
1554*3db86aabSstevel 		need_value = OPT_NEEDS_VALUE(subopt);
1555*3db86aabSstevel 		if (!need_value && value != NULL) {
1556*3db86aabSstevel 			__fmt_errstring(errstring, MAX_OPT_LENGTH,
1557*3db86aabSstevel 			    dgettext(TEXT_DOMAIN, no_value),
1558*3db86aabSstevel 			    mema_opts[subopt]);
1559*3db86aabSstevel 			subopt_err = 1;
1560*3db86aabSstevel 			break;
1561*3db86aabSstevel 		}
1562*3db86aabSstevel 		if (need_value && value == NULL) {
1563*3db86aabSstevel 			__fmt_errstring(errstring, MAX_OPT_LENGTH,
1564*3db86aabSstevel 			    dgettext(TEXT_DOMAIN, missing_value),
1565*3db86aabSstevel 			    mema_opts[subopt]);
1566*3db86aabSstevel 			subopt_err = 1;
1567*3db86aabSstevel 			break;
1568*3db86aabSstevel 		}
1569*3db86aabSstevel 		if (OPTSET_TEST(opt_set, subopt)) {
1570*3db86aabSstevel 			/* Ignore repeated options. */
1571*3db86aabSstevel 			continue;
1572*3db86aabSstevel 		}
1573*3db86aabSstevel 		if (group != 0 && !OPTSET_IS_EMPTY(opt_set)) {
1574*3db86aabSstevel 			for (i = 0; opts[i].subopt != -1; i++) {
1575*3db86aabSstevel 				if (i == subopt)
1576*3db86aabSstevel 					continue;
1577*3db86aabSstevel 				if (opts[i].group == group &&
1578*3db86aabSstevel 				    OPTSET_TEST(opt_set, opts[i].subopt))
1579*3db86aabSstevel 					break;
1580*3db86aabSstevel 			}
1581*3db86aabSstevel 			if (opts[i].subopt != -1) {
1582*3db86aabSstevel 				__fmt_errstring(errstring, MAX_OPT_LENGTH * 2,
1583*3db86aabSstevel 				    dgettext(TEXT_DOMAIN, conflict_opt),
1584*3db86aabSstevel 				    mema_opts[subopt],
1585*3db86aabSstevel 				    mema_opts[opts[i].subopt]);
1586*3db86aabSstevel 				subopt_err = 1;
1587*3db86aabSstevel 				break;
1588*3db86aabSstevel 			}
1589*3db86aabSstevel 		}
1590*3db86aabSstevel 		OPTSET_SET_VAL(opt_set, subopt, value);
1591*3db86aabSstevel 	}
1592*3db86aabSstevel 	free((void *)optcopy_alloc);
1593*3db86aabSstevel 	if (subopt_err) {
1594*3db86aabSstevel 		*retp = CFGA_ERROR;
1595*3db86aabSstevel 	}
1596*3db86aabSstevel 
1597*3db86aabSstevel 	return (opt_set);
1598*3db86aabSstevel }
1599*3db86aabSstevel 
1600*3db86aabSstevel #ifdef DEV_DEBUG
1601*3db86aabSstevel 
1602*3db86aabSstevel static int
1603*3db86aabSstevel debugging(void)
1604*3db86aabSstevel {
1605*3db86aabSstevel 	char *ep;
1606*3db86aabSstevel 	static int inited;
1607*3db86aabSstevel 
1608*3db86aabSstevel 	if (inited)
1609*3db86aabSstevel 		return (debug_fp != NULL);
1610*3db86aabSstevel 	inited = 1;
1611*3db86aabSstevel 
1612*3db86aabSstevel 	if ((ep = getenv("MEMADM_DEBUG")) == NULL) {
1613*3db86aabSstevel 		return (0);
1614*3db86aabSstevel 	}
1615*3db86aabSstevel 	if (*ep == '\0')
1616*3db86aabSstevel 		debug_fp = stderr;
1617*3db86aabSstevel 	else {
1618*3db86aabSstevel 		if ((debug_fp = fopen(ep, "a")) == NULL)
1619*3db86aabSstevel 			return (0);
1620*3db86aabSstevel 	}
1621*3db86aabSstevel 	(void) fprintf(debug_fp, "\nDebug started, pid=%d\n", (int)getpid());
1622*3db86aabSstevel 	return (1);
1623*3db86aabSstevel }
1624*3db86aabSstevel 
1625*3db86aabSstevel static void
1626*3db86aabSstevel dump_ioctl(
1627*3db86aabSstevel 	int cmd,
1628*3db86aabSstevel 	void *arg)
1629*3db86aabSstevel {
1630*3db86aabSstevel 	if (!debugging())
1631*3db86aabSstevel 		return;
1632*3db86aabSstevel 
1633*3db86aabSstevel 	switch (cmd) {
1634*3db86aabSstevel 	case AC_MEM_CONFIGURE:
1635*3db86aabSstevel 		(void) fprintf(debug_fp, "IOCTL: AC_MEM_CONFIGURE\n");
1636*3db86aabSstevel 		break;
1637*3db86aabSstevel 
1638*3db86aabSstevel 	case AC_MEM_UNCONFIGURE:
1639*3db86aabSstevel 		(void) fprintf(debug_fp, "IOCTL: AC_MEM_UNCONFIGURE\n");
1640*3db86aabSstevel 		break;
1641*3db86aabSstevel 
1642*3db86aabSstevel 	case AC_MEM_TEST_START:
1643*3db86aabSstevel 		(void) fprintf(debug_fp, "IOCTL: AC_MEM_TEST_START\n");
1644*3db86aabSstevel 		break;
1645*3db86aabSstevel 
1646*3db86aabSstevel 	case AC_MEM_TEST_STOP: {
1647*3db86aabSstevel 		ac_mem_test_stop_t *tstop;
1648*3db86aabSstevel 
1649*3db86aabSstevel 		tstop = (ac_mem_test_stop_t *)arg;
1650*3db86aabSstevel 		(void) fprintf(debug_fp, "IOCTL: AC_MEM_TEST_STOP handle=%#x "
1651*3db86aabSstevel 		    "condition=%d\n", tstop->handle, tstop->condition);
1652*3db86aabSstevel 	}
1653*3db86aabSstevel 		break;
1654*3db86aabSstevel 	case AC_MEM_TEST_READ: {
1655*3db86aabSstevel 		ac_mem_test_read_t *tread;
1656*3db86aabSstevel 
1657*3db86aabSstevel 		tread = (ac_mem_test_read_t *)arg;
1658*3db86aabSstevel 		(void) fprintf(debug_fp, "IOCTL: AC_MEM_TEST_READ handle=%#x "
1659*3db86aabSstevel 		    "buf=%#p page=%#llx off=%#x count=%#x\n",
1660*3db86aabSstevel 		    tread->handle, tread->page_buf,
1661*3db86aabSstevel 		    tread->address.page_num,
1662*3db86aabSstevel 		    tread->address.line_offset, tread->address.line_count);
1663*3db86aabSstevel 	}
1664*3db86aabSstevel 		break;
1665*3db86aabSstevel 	case AC_MEM_TEST_WRITE: {
1666*3db86aabSstevel 		ac_mem_test_write_t *twrite;
1667*3db86aabSstevel 
1668*3db86aabSstevel 		twrite = (ac_mem_test_write_t *)arg;
1669*3db86aabSstevel 		(void) fprintf(debug_fp, "IOCTL: AC_MEM_TEST_WRITE handle=%#x "
1670*3db86aabSstevel 		    "buf=%#p page=%#llx off=%#x count=%#x\n",
1671*3db86aabSstevel 		    twrite->handle, twrite->page_buf,
1672*3db86aabSstevel 		    twrite->address.page_num,
1673*3db86aabSstevel 		    twrite->address.line_offset, twrite->address.line_count);
1674*3db86aabSstevel 	}
1675*3db86aabSstevel 		break;
1676*3db86aabSstevel 	case AC_MEM_ADMIN_VER:
1677*3db86aabSstevel 		(void) fprintf(debug_fp, "IOCTL: AC_MEM_ADMIN_VER:\n");
1678*3db86aabSstevel 		break;
1679*3db86aabSstevel 	case AC_MEM_STAT:
1680*3db86aabSstevel 		(void) fprintf(debug_fp, "IOCTL: AC_MEM_STAT\n");
1681*3db86aabSstevel 		break;
1682*3db86aabSstevel 	case AC_MEM_EXERCISE: {
1683*3db86aabSstevel 		ac_cfga_cmd_t *cmdp;
1684*3db86aabSstevel 
1685*3db86aabSstevel 		cmdp = arg;
1686*3db86aabSstevel 		(void) fprintf(debug_fp, "IOCTL: AC_MEM_EXERCISE arg=%d\n",
1687*3db86aabSstevel 		    cmdp->arg);
1688*3db86aabSstevel 		break;
1689*3db86aabSstevel 	}
1690*3db86aabSstevel 	default:
1691*3db86aabSstevel 		(void) fprintf(debug_fp, "IOCTL: unknown (%#x)\n", cmd);
1692*3db86aabSstevel 		break;
1693*3db86aabSstevel 	}
1694*3db86aabSstevel 	(void) fflush(debug_fp);
1695*3db86aabSstevel }
1696*3db86aabSstevel 
1697*3db86aabSstevel static void
1698*3db86aabSstevel dump_ioctl_res(
1699*3db86aabSstevel 	int cmd,
1700*3db86aabSstevel 	void *arg,
1701*3db86aabSstevel 	int ret,
1702*3db86aabSstevel 	int ret_errno)
1703*3db86aabSstevel {
1704*3db86aabSstevel 	if (!debugging())
1705*3db86aabSstevel 		return;
1706*3db86aabSstevel 
1707*3db86aabSstevel 	if (ret == -1) {
1708*3db86aabSstevel 		(void) fprintf(debug_fp, "IOCTL failed, \"%s\" (errno=%d)\n",
1709*3db86aabSstevel 		    strerror(ret_errno), ret_errno);
1710*3db86aabSstevel 		(void) fflush(debug_fp);
1711*3db86aabSstevel 		return;
1712*3db86aabSstevel 	} else {
1713*3db86aabSstevel 		(void) fprintf(debug_fp, "IOCTL succeeded, ret=%d\n", ret);
1714*3db86aabSstevel 	}
1715*3db86aabSstevel 
1716*3db86aabSstevel 	switch (cmd) {
1717*3db86aabSstevel 	case AC_MEM_CONFIGURE:
1718*3db86aabSstevel 	case AC_MEM_UNCONFIGURE:
1719*3db86aabSstevel 		break;
1720*3db86aabSstevel 	case AC_MEM_TEST_START: {
1721*3db86aabSstevel 		ac_mem_test_start_t *tstart;
1722*3db86aabSstevel 
1723*3db86aabSstevel 		tstart = (ac_mem_test_start_t *)arg;
1724*3db86aabSstevel 		(void) fprintf(debug_fp, "    handle=%#x tester_pid=%d "
1725*3db86aabSstevel 		    "prev_condition=%d bank_size=%#llx "
1726*3db86aabSstevel 		    "page_size=%#x line_size=%#x afar_base=%#llx\n",
1727*3db86aabSstevel 		    tstart->handle, (int)tstart->tester_pid,
1728*3db86aabSstevel 		    tstart->prev_condition,
1729*3db86aabSstevel 		    tstart->bank_size, tstart->page_size,
1730*3db86aabSstevel 		    tstart->line_size, tstart->afar_base);
1731*3db86aabSstevel 	}
1732*3db86aabSstevel 		break;
1733*3db86aabSstevel 	case AC_MEM_TEST_STOP:
1734*3db86aabSstevel 		break;
1735*3db86aabSstevel 	case AC_MEM_TEST_READ: {
1736*3db86aabSstevel 		ac_mem_test_read_t *tread;
1737*3db86aabSstevel 		sunfire_processor_error_regs_t *err;
1738*3db86aabSstevel 
1739*3db86aabSstevel 		tread = (ac_mem_test_read_t *)arg;
1740*3db86aabSstevel 		err = tread->error_buf;
1741*3db86aabSstevel 		if (ret_errno == EIO) {
1742*3db86aabSstevel 			(void) fprintf(debug_fp, "module_id=%#llx afsr=%#llx "
1743*3db86aabSstevel 			    "afar=%#llx udbh_error_reg=%#llx "
1744*3db86aabSstevel 			    "udbl_error_reg=%#llx\n",
1745*3db86aabSstevel 			    (longlong_t)err->module_id, (longlong_t)err->afsr,
1746*3db86aabSstevel 			    (longlong_t)err->afar,
1747*3db86aabSstevel 			    (longlong_t)err->udbh_error_reg,
1748*3db86aabSstevel 			    (longlong_t)err->udbl_error_reg);
1749*3db86aabSstevel 		} else {
1750*3db86aabSstevel 			(void) fprintf(debug_fp, "\n");
1751*3db86aabSstevel 		}
1752*3db86aabSstevel 	}
1753*3db86aabSstevel 		break;
1754*3db86aabSstevel 	case AC_MEM_TEST_WRITE:
1755*3db86aabSstevel 		break;
1756*3db86aabSstevel 	case AC_MEM_ADMIN_VER: {
1757*3db86aabSstevel 		ac_mem_version_t *ver;
1758*3db86aabSstevel 
1759*3db86aabSstevel 		ver = (ac_mem_version_t *)arg;
1760*3db86aabSstevel 		(void) fprintf(debug_fp, "    version %d\n", *ver);
1761*3db86aabSstevel 	}
1762*3db86aabSstevel 		break;
1763*3db86aabSstevel 	case AC_MEM_STAT: {
1764*3db86aabSstevel 		ac_stat_t *tstat;
1765*3db86aabSstevel 
1766*3db86aabSstevel 		tstat = (ac_stat_t *)arg;
1767*3db86aabSstevel 		(void) fprintf(debug_fp, "    rstate=%u ostate=%u "
1768*3db86aabSstevel 		    "condition=%u status_time=%#lx board=%u\n",
1769*3db86aabSstevel 		    (uint_t)tstat->rstate, (uint_t)tstat->ostate,
1770*3db86aabSstevel 		    (uint_t)tstat->condition, (ulong_t)tstat->status_time,
1771*3db86aabSstevel 		    tstat->board);
1772*3db86aabSstevel 		(void) fprintf(debug_fp, "    real_size=%u use_size=%u "
1773*3db86aabSstevel 		    "busy=%u\n",
1774*3db86aabSstevel 		    tstat->real_size, tstat->use_size, tstat->busy);
1775*3db86aabSstevel 		(void) fprintf(debug_fp, "    page_size=%#x "
1776*3db86aabSstevel 		    "phys_pages=%#llx managed=%#llx nonrelocatable=%#llx\n",
1777*3db86aabSstevel 		    tstat->page_size, (longlong_t)tstat->phys_pages,
1778*3db86aabSstevel 		    (longlong_t)tstat->managed,
1779*3db86aabSstevel 		    (longlong_t)tstat->nonrelocatable);
1780*3db86aabSstevel 		(void) fprintf(debug_fp, "    memctl=%#llx "
1781*3db86aabSstevel 		    "decode0=%#llx decode1=%#llx\n",
1782*3db86aabSstevel 		    (longlong_t)tstat->ac_memctl, (longlong_t)tstat->ac_decode0,
1783*3db86aabSstevel 		    (longlong_t)tstat->ac_decode1);
1784*3db86aabSstevel 	}
1785*3db86aabSstevel 		break;
1786*3db86aabSstevel 	case AC_MEM_EXERCISE: {
1787*3db86aabSstevel 		ac_cfga_cmd_t *cmdp;
1788*3db86aabSstevel 
1789*3db86aabSstevel 		cmdp = arg;
1790*3db86aabSstevel 		switch (cmdp->arg) {
1791*3db86aabSstevel 		case AC_MEMX_RELOCATE_ALL: {
1792*3db86aabSstevel 			struct ac_memx_relocate_stats *stp;
1793*3db86aabSstevel 
1794*3db86aabSstevel 			if ((stp = cmdp->private) != NULL) {
1795*3db86aabSstevel 				(void) fprintf(debug_fp, "    base=%u npgs=%u"
1796*3db86aabSstevel 				    " nopaget=%u nolock=%u isfree=%u reloc=%u"
1797*3db86aabSstevel 				    " noreloc=%u\n",
1798*3db86aabSstevel 				    stp->base, stp->npgs, stp->nopaget,
1799*3db86aabSstevel 				    stp->nolock, stp->isfree, stp->reloc,
1800*3db86aabSstevel 				    stp->noreloc);
1801*3db86aabSstevel 			}
1802*3db86aabSstevel 			break;
1803*3db86aabSstevel 		}
1804*3db86aabSstevel 		default:
1805*3db86aabSstevel 			break;
1806*3db86aabSstevel 		}
1807*3db86aabSstevel 		break;
1808*3db86aabSstevel 	}
1809*3db86aabSstevel 	default:
1810*3db86aabSstevel 		break;
1811*3db86aabSstevel 	}
1812*3db86aabSstevel 	(void) fflush(debug_fp);
1813*3db86aabSstevel }
1814*3db86aabSstevel #endif /* DEV_DEBUG */
1815