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