1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stddef.h> 30 #include <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" 50 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 62 63 #ifndef P_DER_UE 64 /* 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. 67 */ 68 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 */ 73 74 #define DEV_DEBUG 75 #ifdef DEV_DEBUG 76 #include <stdio.h> 77 #include <stdlib.h> 78 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 */ 87 88 typedef struct { 89 uint_t board; 90 uint_t bank; 91 } mema_bank_t; 92 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 101 }; 102 103 #define OPT_NEEDS_VALUE(O) ((O) == OPT_TIMEOUT) 104 105 #define MAX_OPT_LENGTH (sizeof ("disable-at-boot")) 106 107 /* 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. 112 */ 113 struct opt_control { 114 int subopt; 115 int group; 116 }; 117 118 /* 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. 123 */ 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; 129 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) 137 138 static option_set_t process_options(const char *, struct opt_control *, 139 int *, char **); 140 141 static struct opt_control add_opts[] = { 142 {OPT_BOOT_ENABLE, 1}, 143 {OPT_BOOT_DISABLE, 1}, 144 {-1, 0} 145 }; 146 147 static struct opt_control del_opts[] = { 148 {OPT_BOOT_ENABLE, 1}, 149 {OPT_BOOT_DISABLE, 1}, 150 {OPT_TIMEOUT, 2}, 151 {-1, 0} 152 }; 153 154 static struct opt_control stat_opts[] = { 155 {OPT_BOOT_ENABLE, 1}, 156 {OPT_BOOT_DISABLE, 1}, 157 {-1, 0} 158 }; 159 160 #if !defined(TEXT_DOMAIN) 161 #define TEXT_DOMAIN "SYS_TEST" 162 #endif 163 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"; 201 202 203 #define mema_eid(a, b) (((a) << 8) + (b)) 204 #define mema_str(i) mema_strs[(i)] 205 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 241 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" 279 }; 280 281 /* 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 310 */ 311 static int 312 mema_sid(int err, int acerr) 313 { 314 if (acerr == AC_ERR_DEFAULT) 315 return (AC_UNKNOWN); 316 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; 376 } 377 378 return (AC_UNKNOWN); 379 } 380 381 static void 382 mema_err(ac_cfga_cmd_t *ac, int ret_errno, char **errstring, int cmd) 383 { 384 char *cname = mema_str(cmd); 385 char *syserr; 386 char syserr_num[20]; 387 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; 397 } 398 } 399 400 __fmt_errstring(errstring, strlen(syserr), 401 dgettext(TEXT_DOMAIN, cname), syserr); 402 } 403 404 static void 405 mema_cmd_init(ac_cfga_cmd_t *ac, void *cmd, char *outputstr, int force) 406 { 407 (void) memset((void *)ac, 0, sizeof (*ac)); 408 409 ac->errtype = AC_ERR_DEFAULT; 410 ac->private = cmd; 411 ac->force = force; 412 ac->outputstr = outputstr; 413 414 (void) memset((void *)outputstr, 0, AC_OUTPUT_LEN); 415 } 416 417 static int 418 ap_bk_idx(const char *ap_id) 419 { 420 int id; 421 char *s; 422 static char *bank = "bank"; 423 424 DBG("ap_bk_idx(%s)\n", ap_id); 425 426 if ((s = strstr(ap_id, bank)) == NULL) 427 return (-1); 428 else { 429 int n; 430 431 s += strlen(bank); 432 n = strlen(s); 433 434 DBG3("ap_bk_idx: s=%s, n=%d\n", s, n); 435 436 if ((n != 1) || !isdigit(s[0])) 437 return (-1); 438 } 439 440 id = atoi(s); 441 442 if (id < 0 || id > 1) 443 return (-1); 444 445 DBG3("ap_bk_idx(%s)=%d\n", s, id); 446 447 return (id); 448 } 449 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) 457 { 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]; 465 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); 470 } 471 472 bk.bank = bank; 473 474 if ((fd = open(bank_spec, ((fdp != NULL) ? O_RDWR : O_RDONLY), 0)) == 475 -1) { 476 char *syserr; 477 char syserr_num[20]; 478 479 syserr = strerror(errno); 480 if (syserr == NULL) { 481 (void) sprintf(syserr_num, "errno=%d", errno); 482 syserr = syserr_num; 483 } 484 __fmt_errstring(errstring, strlen(syserr) + 485 strlen(bank_spec), 486 dgettext(TEXT_DOMAIN, open_failed), bank_spec, syserr); 487 return (CFGA_ERROR); 488 } 489 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); 495 496 if (ret == -1) { 497 mema_err(&cmd, ret_errno, errstring, CMD_MEM_STAT); 498 (void) close(fd); 499 return (CFGA_ERROR); 500 } 501 502 if (fdp) 503 *fdp = fd; 504 else 505 (void) close(fd); 506 507 if (stp) 508 *stp = stat; 509 510 if (bkp) { 511 bkp->bank = bk.bank; 512 bkp->board = stat.board; 513 } 514 515 return (CFGA_OK); 516 } 517 518 static void 519 set_disabled_bits(mema_disabled_t *dp, int value) 520 { 521 if (value == 0) 522 *dp &= ~PROM_MEMORY_DISABLED; 523 else 524 *dp |= PROM_MEMORY_DISABLED; 525 } 526 527 static void 528 set_present_bits(mema_disabled_t *dp, ac_stat_t *asp) 529 { 530 if (asp->ostate == SYSC_CFGA_OSTATE_CONFIGURED) 531 *dp |= PROM_MEMORY_PRESENT; 532 else 533 *dp &= ~PROM_MEMORY_DISABLED; 534 } 535 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) 542 { 543 cfga_err_t ret; 544 mema_disabled_t disab; 545 546 if (!prom_read_disabled_list(&disab, board)) 547 return (CFGA_ERROR); 548 549 set_present_bits(&disab, asp); 550 551 ret = CFGA_OK; 552 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; 563 } 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; 574 } 575 } 576 577 return (ret); 578 } 579 580 static cfga_err_t 581 mema_add( 582 const char *bank_spec, 583 const char *options, 584 char **errstring, 585 int force) 586 { 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]; 593 594 ret = 0; 595 do_option = process_options(options, add_opts, &ret, errstring); 596 if (ret != 0) { 597 return (ret); 598 } 599 600 ret = ap_stat(bank_spec, &fd, &bk, &stat, errstring); 601 if (ret != CFGA_OK) 602 return (ret); 603 604 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); 611 } 612 613 if (!force) { 614 mema_disabled_t disab; 615 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); 623 } 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); 630 } 631 } else { 632 __fmt_errstring(errstring, 0, 633 dgettext(TEXT_DOMAIN, add_disab_err)); 634 (void) close(fd); 635 return (CFGA_ERROR); 636 } 637 } 638 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); 645 646 if (ret == -1) { 647 mema_err(&cmd, ret_errno, errstring, CMD_MEM_ADD); 648 return (CFGA_ERROR); 649 } 650 651 ret = prom_do_options(do_option, bk.board, &stat, errstring); 652 653 return (ret); 654 } 655 656 static cfga_err_t 657 mema_delete( 658 const char *bank_spec, 659 const char *options, 660 char **errstring, 661 int force) 662 { 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'. */ 670 671 ret = 0; 672 do_option = process_options(options, del_opts, &ret, errstring); 673 if (ret != 0) { 674 return (ret); 675 } 676 677 if (OPTSET_TEST(do_option, OPT_TIMEOUT)) { 678 char *to_val; 679 char *ep; 680 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); 687 } 688 } 689 690 ret = ap_stat(bank_spec, &fd, &bk, &stat, errstring); 691 if (ret != CFGA_OK) 692 return (ret); 693 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); 700 } 701 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); 709 710 if (ret == -1) { 711 mema_err(&cmd, ret_errno, errstring, CMD_MEM_DEL); 712 return (CFGA_ERROR); 713 } 714 715 ret = prom_do_options(do_option, bk.board, &stat, errstring); 716 717 return (ret); 718 } 719 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) 730 { 731 int force; 732 cfga_err_t rc; 733 734 if (errstring != NULL) 735 *errstring = NULL; 736 737 force = flags & CFGA_FLAG_FORCE; 738 739 switch (state_change_cmd) { 740 case CFGA_CMD_CONFIGURE: 741 rc = mema_add(ap_id, options, errstring, force); 742 break; 743 744 case CFGA_CMD_UNCONFIGURE: 745 rc = mema_delete(ap_id, options, errstring, force); 746 break; 747 748 default: 749 rc = CFGA_OPNOTSUPP; 750 break; 751 } 752 753 return (rc); 754 } 755 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) 766 { 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]; 772 773 if (errstring != NULL) 774 *errstring = NULL; 775 776 ret = ap_stat(ap_id, &fd, &bk, &stat, errstring); 777 if (ret != CFGA_OK) 778 return (ret); 779 780 if (strcmp(function, "relocate-test") == 0) { 781 struct ac_memx_relocate_stats rstat; 782 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((void *)&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); 793 794 if (ret == -1) { 795 mema_err(&cmd, ret_errno, errstring, CMD_MEM_RELOCTEST); 796 return (CFGA_ERROR); 797 } 798 return (CFGA_OK); 799 } 800 801 __fmt_errstring(errstring, strlen(function), 802 dgettext(TEXT_DOMAIN, pfunc_unknown), function); 803 804 return (CFGA_ERROR); 805 } 806 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) 815 { 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]; 823 824 (void) memset((void *)&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); 830 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); 836 } 837 if (ret_errno == EBUSY && test_start.tester_pid > 0) { 838 /* 839 * Bank appears to be being tested. Check that 840 * process 'tester_pid' is still running. 841 */ 842 if (kill(test_start.tester_pid, 0) != -1 || 843 errno != ESRCH) { 844 cfga_ap_log_id_t bname; 845 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); 853 } 854 /* 855 * Do a test stop and re-try the start. 856 */ 857 (void) memset((void *)&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); 867 /* 868 * Ignore test stop error processing and re-try the 869 * start. The error return will be derived from the 870 * result of start. 871 */ 872 (void) memset((void *)&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); 880 } 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); 886 } 887 } 888 (void) memset((void *)&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; 898 899 res = (*mtest_table[test_fun].test_func)(&handle); 900 901 mtest_deallocate_buf_all(&handle); 902 903 /* 904 * Convert memory test code to MEMA_ code. 905 */ 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; 926 } 927 928 (void) memset((void *)&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; 947 } 948 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); 958 } 959 return (res); 960 } 961 962 #define DRVHANDLE(H) (((ac_mem_test_start_t *)(H)->drvhandle)->handle) 963 964 int 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) 971 { 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]; 976 977 (void) memset((void *)&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; 987 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); 993 994 if (ret == -1) 995 return (-1); 996 return (0); 997 } 998 999 int 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) 1007 { 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]; 1013 1014 (void) memset((void *)&test_read, 0, sizeof (test_read)); 1015 (void) memset((void *)&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; 1026 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); 1032 1033 if (ret == -1) { 1034 if (ret_errno == EIO) { 1035 /* 1036 * Special case indicating CE or UE. 1037 */ 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); 1045 } 1046 } else { 1047 errp->error_type = MTEST_ERR_NONE; 1048 } 1049 return (0); 1050 } 1051 1052 static char * 1053 subopt_help_str(char *opts[]) 1054 { 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[] = "???"; 1061 1062 len = 0; 1063 n = 0; 1064 for (i = 0; opts[i] != NULL; i++) { 1065 n++; 1066 len += strlen(opts[i]); 1067 } 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; 1081 } 1082 return (str); 1083 } 1084 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) 1093 { 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; 1101 1102 if (errstring != NULL) 1103 *errstring = NULL; 1104 1105 /* 1106 * Decode test level and max error number. 1107 */ 1108 if (options != NULL && *options != '\0') { 1109 char **opts; 1110 char *value; 1111 char *cp, *free_cp; 1112 int subopt; 1113 1114 /* getsubopt() modifies the input string, so copy it. */ 1115 cp = strdup(options); 1116 if (cp == NULL) { 1117 return (CFGA_LIB_ERROR); 1118 } 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); 1124 } 1125 1126 while (*cp != '\0') { 1127 subopt = getsubopt(&cp, opts, &value); 1128 if (subopt == -1) { 1129 char *hlp; 1130 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); 1142 } 1143 /* Free after printing value. */ 1144 free((void *)free_cp); 1145 return (CFGA_ERROR); 1146 } 1147 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); 1156 } 1157 1158 if (subopt < maxerr_idx) 1159 test_fun = subopt; 1160 else { 1161 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); 1169 } 1170 1171 if (value == NULL) { 1172 __fmt_errstring(errstring, 1173 0, 1174 dgettext(TEXT_DOMAIN, no_num), 1175 ""); 1176 free((void *)free_cp); 1177 return (CFGA_ERROR); 1178 } 1179 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); 1189 } 1190 } 1191 } 1192 free((void *)free_cp); 1193 } 1194 1195 if (test_fun == -1) 1196 test_fun = MTEST_DEFAULT_TEST; 1197 if (max_errors == -1) 1198 max_errors = MAX_ERRORS; 1199 1200 ret = ap_stat(ap_id, &fd, &bk, &stat, errstring); 1201 if (ret != CFGA_OK) 1202 return (ret); 1203 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); 1210 } 1211 1212 ret = mtest_run(fd, test_fun, &bk, 1213 ((flags & CFGA_FLAG_VERBOSE) != 0) ? msgp : NULL, errstring, 1214 (ulong_t)max_errors); 1215 1216 (void) close(fd); 1217 1218 return (ret); 1219 } 1220 1221 static cfga_stat_t 1222 rstate_cvt(sysc_cfga_rstate_t rs) 1223 { 1224 cfga_stat_t cs; 1225 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; 1239 } 1240 1241 return (cs); 1242 } 1243 1244 static cfga_stat_t 1245 ostate_cvt(sysc_cfga_ostate_t os) 1246 { 1247 cfga_stat_t cs; 1248 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; 1259 } 1260 1261 return (cs); 1262 } 1263 1264 static cfga_cond_t 1265 cond_cvt(sysc_cfga_cond_t sc) 1266 { 1267 cfga_cond_t cc; 1268 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; 1286 } 1287 1288 return (cc); 1289 } 1290 1291 static void 1292 info_set(ac_stat_t *asp, mema_bank_t *bkp, cfga_info_t info) 1293 { 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; 1301 1302 end = &info[sizeof (cfga_info_t)]; 1303 *info = NULL; 1304 1305 board = bkp->board; 1306 1307 /* Print the board number in a way that matches the sysctrl AP. */ 1308 info += snprintf(info, end - info, "slot%d", board); 1309 1310 if (asp->real_size == 0) { 1311 info += snprintf(info, end - info, " empty"); 1312 return; 1313 } 1314 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); 1321 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); 1331 } 1332 1333 if (bkp->bank == 0) 1334 decode = asp->ac_decode0; 1335 else 1336 decode = asp->ac_decode1; 1337 1338 info += snprintf(info, end - info, " base 0x%llx", 1339 GRP_REALBASE(decode)); 1340 1341 if (bkp->bank == 0) 1342 intlv = INTLV0(asp->ac_memctl); 1343 else 1344 intlv = INTLV1(asp->ac_memctl); 1345 1346 if (intlv != 1) 1347 info += snprintf(info, end - info, " interleaved %u-way", 1348 intlv); 1349 1350 if (prom_read_disabled_list(&disab, board)) { 1351 if (disab != 0) { 1352 info += snprintf(info, end - info, " disabled at boot"); 1353 } 1354 1355 } 1356 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"); 1361 } 1362 1363 static void 1364 mema_cvt(ac_stat_t *ac, mema_bank_t *bkp, cfga_stat_data_t *cs) 1365 { 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; 1375 } 1376 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) 1384 { 1385 int ret; 1386 mema_bank_t bk; 1387 ac_stat_t stat; 1388 option_set_t do_option; 1389 1390 if (errstring != NULL) 1391 *errstring = NULL; 1392 1393 ret = 0; 1394 do_option = process_options(options, stat_opts, &ret, errstring); 1395 if (ret != 0) 1396 return (ret); 1397 1398 ret = ap_stat(ap_id, NULL, &bk, &stat, errstring); 1399 if (ret != CFGA_OK) 1400 return (ret); 1401 1402 mema_cvt(&stat, &bk, cs); 1403 1404 ret = prom_do_options(do_option, bk.board, &stat, errstring); 1405 1406 return (ret); 1407 } 1408 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) 1417 { 1418 if (errstring != NULL) 1419 *errstring = NULL; 1420 1421 return (CFGA_NOTSUPP); 1422 } 1423 1424 /* 1425 * cfga_ap_id_cmp -- use default_ap_id_cmp() in libcfgadm 1426 */ 1427 1428 /*ARGSUSED*/ 1429 cfga_err_t 1430 cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags) 1431 { 1432 1433 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); 1440 1441 return (CFGA_OK); 1442 } 1443 1444 #if 0 1445 static ac_mem_version_t 1446 get_version(int fd) 1447 { 1448 ac_mem_version_t ver; 1449 int ret, ret_errno; 1450 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); 1457 } 1458 #endif 1459 1460 static char * 1461 opt_help_str(struct opt_control *opts) 1462 { 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[] = "???"; 1469 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]); 1475 } 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; 1489 } 1490 return (str); 1491 } 1492 1493 static option_set_t 1494 process_options( 1495 const char *options, 1496 struct opt_control *opts, 1497 int *retp, 1498 char **errstring) 1499 { 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; 1508 1509 OPTSET_INIT(opt_set); 1510 1511 if (options == NULL || *options == '\0') { 1512 return (opt_set); 1513 } 1514 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); 1521 } 1522 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; 1528 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; 1535 } 1536 for (i = 0; opts[i].subopt != -1; i++) { 1537 if (opts[i].subopt == subopt) { 1538 group = opts[i].group; 1539 break; 1540 } 1541 } 1542 if (opts[i].subopt == -1) { 1543 char *hlp; 1544 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; 1553 } 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; 1561 } 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; 1568 } 1569 if (OPTSET_TEST(opt_set, subopt)) { 1570 /* Ignore repeated options. */ 1571 continue; 1572 } 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; 1580 } 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; 1588 } 1589 } 1590 OPTSET_SET_VAL(opt_set, subopt, value); 1591 } 1592 free((void *)optcopy_alloc); 1593 if (subopt_err) { 1594 *retp = CFGA_ERROR; 1595 } 1596 1597 return (opt_set); 1598 } 1599 1600 #ifdef DEV_DEBUG 1601 1602 static int 1603 debugging(void) 1604 { 1605 char *ep; 1606 static int inited; 1607 1608 if (inited) 1609 return (debug_fp != NULL); 1610 inited = 1; 1611 1612 if ((ep = getenv("MEMADM_DEBUG")) == NULL) { 1613 return (0); 1614 } 1615 if (*ep == '\0') 1616 debug_fp = stderr; 1617 else { 1618 if ((debug_fp = fopen(ep, "a")) == NULL) 1619 return (0); 1620 } 1621 (void) fprintf(debug_fp, "\nDebug started, pid=%d\n", (int)getpid()); 1622 return (1); 1623 } 1624 1625 static void 1626 dump_ioctl( 1627 int cmd, 1628 void *arg) 1629 { 1630 if (!debugging()) 1631 return; 1632 1633 switch (cmd) { 1634 case AC_MEM_CONFIGURE: 1635 (void) fprintf(debug_fp, "IOCTL: AC_MEM_CONFIGURE\n"); 1636 break; 1637 1638 case AC_MEM_UNCONFIGURE: 1639 (void) fprintf(debug_fp, "IOCTL: AC_MEM_UNCONFIGURE\n"); 1640 break; 1641 1642 case AC_MEM_TEST_START: 1643 (void) fprintf(debug_fp, "IOCTL: AC_MEM_TEST_START\n"); 1644 break; 1645 1646 case AC_MEM_TEST_STOP: { 1647 ac_mem_test_stop_t *tstop; 1648 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); 1652 } 1653 break; 1654 case AC_MEM_TEST_READ: { 1655 ac_mem_test_read_t *tread; 1656 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); 1663 } 1664 break; 1665 case AC_MEM_TEST_WRITE: { 1666 ac_mem_test_write_t *twrite; 1667 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); 1674 } 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; 1684 1685 cmdp = arg; 1686 (void) fprintf(debug_fp, "IOCTL: AC_MEM_EXERCISE arg=%d\n", 1687 cmdp->arg); 1688 break; 1689 } 1690 default: 1691 (void) fprintf(debug_fp, "IOCTL: unknown (%#x)\n", cmd); 1692 break; 1693 } 1694 (void) fflush(debug_fp); 1695 } 1696 1697 static void 1698 dump_ioctl_res( 1699 int cmd, 1700 void *arg, 1701 int ret, 1702 int ret_errno) 1703 { 1704 if (!debugging()) 1705 return; 1706 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); 1714 } 1715 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; 1722 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); 1731 } 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; 1738 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"); 1751 } 1752 } 1753 break; 1754 case AC_MEM_TEST_WRITE: 1755 break; 1756 case AC_MEM_ADMIN_VER: { 1757 ac_mem_version_t *ver; 1758 1759 ver = (ac_mem_version_t *)arg; 1760 (void) fprintf(debug_fp, " version %d\n", *ver); 1761 } 1762 break; 1763 case AC_MEM_STAT: { 1764 ac_stat_t *tstat; 1765 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); 1784 } 1785 break; 1786 case AC_MEM_EXERCISE: { 1787 ac_cfga_cmd_t *cmdp; 1788 1789 cmdp = arg; 1790 switch (cmdp->arg) { 1791 case AC_MEMX_RELOCATE_ALL: { 1792 struct ac_memx_relocate_stats *stp; 1793 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); 1801 } 1802 break; 1803 } 1804 default: 1805 break; 1806 } 1807 break; 1808 } 1809 default: 1810 break; 1811 } 1812 (void) fflush(debug_fp); 1813 } 1814 #endif /* DEV_DEBUG */ 1815