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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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