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