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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 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 <sys/cpuvar.h> 30 #include <sys/cpu_module.h> 31 #include <sys/kmem.h> 32 #include <sys/sunddi.h> 33 #include <sys/param.h> 34 #include <sys/obpdefs.h> 35 #include <sys/prom_plat.h> 36 #include <sys/sgsbbc_mailbox.h> 37 #include <sys/sbd_ioctl.h> 38 #include <sys/sbdp_priv.h> 39 #include <sys/sbdp_mbox.h> 40 #include <sys/promif.h> 41 #include <sys/plat_ecc_dimm.h> 42 43 #define UNKNOWN "unknown" 44 #define INITL_STATUS 0xdead 45 46 int sbdp_mbox_wait = 86400; /* in seconds */ 47 int sbdp_shw_bd_wait = 5; /* in seconds */ 48 49 int sbdp_sc_err_translation(int); 50 int sbdp_poweroff_wkaround = 1; 51 52 /* 53 * By default, DR of non-Panther procs is not allowed into a Panther 54 * domain with large page sizes enabled. Setting this to 0 will remove 55 * the restriction. 56 */ 57 static int sbdp_large_page_restriction = 1; 58 59 /* 60 * Initialize the data structs for the common part of the pkts 61 */ 62 void 63 sbdp_init_msg_pkt(sbbc_msg_t *msg, uint16_t sub_type, int len, caddr_t buf) 64 { 65 msg->msg_type.type = DR_MBOX; 66 msg->msg_type.sub_type = sub_type; 67 msg->msg_status = INITL_STATUS; 68 msg->msg_len = len; 69 msg->msg_buf = buf; 70 msg->msg_data[0] = 0; 71 msg->msg_data[1] = 0; 72 73 } 74 75 /* 76 * Convert a showboard data structure to the board structure shared 77 * between sbd and sbdp 78 */ 79 void 80 sbdp_showbd_2_sbd_stat(show_board_t *shbp, sbd_stat_t *stp, int board) 81 { 82 static fn_t f = "sbdp_showbd_2_sbd_stat"; 83 84 SBDP_DBG_FUNC("%s\n", f); 85 86 stp->s_board = board; 87 (void) strcpy(stp->s_info, shbp->s_info); 88 stp->s_power = shbp->s_power; 89 90 (void) strcpy(stp->s_type, shbp->s_type); 91 92 if (shbp->s_present == 0) { 93 /* 94 * This should go away since the SC should put the unknown 95 * We leave this here so Symon and other scripts don't have 96 * a problem 97 */ 98 (void) strcpy(stp->s_type, UNKNOWN); 99 stp->s_rstate = SBD_STAT_EMPTY; 100 } else if (shbp->s_claimed == 0) 101 stp->s_rstate = SBD_STAT_DISCONNECTED; 102 else 103 stp->s_rstate = SBD_STAT_CONNECTED; 104 105 106 stp->s_assigned = shbp->s_assigned; 107 stp->s_cond = shbp->s_cond; 108 } 109 110 /* 111 * Entry point from sbd. Get the status from the SC and then convert 112 * the info returned into something that sbd understands 113 * If the request times out or fails other than an illegal transaction 114 * copy the info from our inventory 115 */ 116 int 117 sbdp_get_board_status(sbdp_handle_t *hp, sbd_stat_t *stp) 118 { 119 int board = hp->h_board; 120 int node = hp->h_wnode; 121 sbbc_msg_t request, *reqp = &request; 122 sbbc_msg_t response, *resp = &response; 123 info_t inform, *informp = &inform; 124 show_board_t show_bd, *shbp = &show_bd; 125 int rv = 0; 126 sbd_error_t *sep = hp->h_err; 127 int len; 128 sbdp_bd_t *bdp; 129 static fn_t f = "sbdp_get_board_status"; 130 131 SBDP_DBG_FUNC("%s\n", f); 132 133 /* 134 * Check for options. If there are any, fail the operation 135 */ 136 if (hp->h_opts != NULL && hp->h_opts->copts != NULL) { 137 sbdp_set_err(sep, ESBD_INVAL_OPT, hp->h_opts->copts); 138 return (-1); 139 } 140 141 bdp = sbdp_get_bd_info(node, board); 142 143 informp->board = board; 144 informp->node = node; 145 informp->revision = 0xdead; 146 len = sizeof (info_t); 147 148 sbdp_init_msg_pkt(reqp, DR_MBOX_SHOW_BOARD, len, (caddr_t)informp); 149 150 bzero(shbp, sizeof (show_board_t)); 151 shbp->s_cond = -1; 152 shbp->s_power = -1; 153 shbp->s_assigned = -1; 154 shbp->s_claimed = -1; 155 shbp->s_present = -1; 156 len = sizeof (show_board_t); 157 158 sbdp_init_msg_pkt(resp, DR_MBOX_SHOW_BOARD, len, (caddr_t)shbp); 159 160 rv = sbbc_mbox_request_response(reqp, resp, sbdp_shw_bd_wait); 161 162 SBDP_DBG_MISC("show board completed: rv = %d\n", rv); 163 164 /* 165 * This domain has no access to this board. Return failure 166 */ 167 if ((resp->msg_status == SG_MBOX_STATUS_BOARD_ACCESS_DENIED) || 168 (resp->msg_status == SG_MBOX_STATUS_ILLEGAL_SLOT) || 169 (resp->msg_status == SG_MBOX_STATUS_ILLEGAL_NODE)) { 170 171 /* 172 * invalidate cached copy. 173 */ 174 bdp->valid_cp = -1; 175 176 sbdp_set_err(sep, ESGT_GET_BOARD_STAT, NULL); 177 return (EIO); 178 } 179 180 /* 181 * If we get any error see if we can return a cached copy of the 182 * board info. If one exists turn the busy flag on 183 */ 184 if (rv != 0) { 185 mutex_enter(&bdp->bd_mutex); 186 if (bdp->valid_cp == -1) { 187 sbdp_set_err(sep, ESGT_GET_BOARD_STAT, 188 NULL); 189 mutex_exit(&bdp->bd_mutex); 190 return (EIO); 191 } 192 193 /* 194 * we have a valid copy. Return it and set the 195 * busy flag on so the user know this is not the most 196 * recent copy 197 */ 198 bcopy(bdp->bd_sc, shbp, sizeof (show_board_t)); 199 mutex_exit(&bdp->bd_mutex); 200 stp->s_busy = 1; 201 /* 202 * The sbbc returns the error in both parts (i.e rv and status) 203 * so since we just took care of it reset rv 204 */ 205 rv = 0; 206 } else { 207 /* 208 * revalidate our copy of the returned data 209 */ 210 if (bdp == NULL) { 211 SBDP_DBG_MBOX("HUGE ERROR\n"); 212 } else { 213 mutex_enter(&bdp->bd_mutex); 214 bcopy(shbp, bdp->bd_sc, sizeof (show_board_t)); 215 bdp->valid_cp = 1; 216 mutex_exit(&bdp->bd_mutex); 217 } 218 } 219 220 221 SBDP_DBG_MBOX("Showboard: board\t%d\n\trevision\t%d\n\ts_cond\t%d\n\t" 222 "s_power\t%d\n\ts_assigned\t%d\n\ts_claimed\t%d\n\t" 223 "s_present\t%d\n\ts_ledstatus\t%d\n\ts_type\t%s\n\t" 224 "s_info\t%s\n", 225 board, shbp->revision, shbp->s_cond, shbp->s_power, 226 shbp->s_assigned, shbp->s_claimed, shbp->s_present, 227 shbp->s_ledstatus, shbp->s_type, shbp->s_info); 228 229 /* 230 * Now that we got the info run through the sbd-sbdp translator 231 */ 232 sbdp_showbd_2_sbd_stat(shbp, stp, board); 233 234 /* 235 * Last add the platform options 236 */ 237 SBDP_PLATFORM_OPTS(stp->s_platopts); 238 239 return (rv); 240 } 241 242 /* 243 * Entry point from sbd. Call down to the SC to assign the board 244 * We simply return the status the SC told us 245 */ 246 int 247 sbdp_assign_board(sbdp_handle_t *hp) 248 { 249 int board = hp->h_board; 250 int node = hp->h_wnode; 251 sbbc_msg_t request, *reqp = &request; 252 sbbc_msg_t response, *resp = &response; 253 int cmd_rev = -1; 254 info2_t inform, *informp = &inform; 255 int rv = 0; 256 sbd_error_t *sep; 257 int len; 258 static fn_t f = "sbdp_assign_board"; 259 260 SBDP_DBG_FUNC("%s\n", f); 261 262 sep = hp->h_err; 263 /* 264 * Check for options. If there are any, fail the operation 265 */ 266 if (hp->h_opts != NULL && hp->h_opts->copts != NULL) { 267 sbdp_set_err(sep, ESBD_INVAL_OPT, hp->h_opts->copts); 268 return (-1); 269 } 270 271 informp->board = board; 272 informp->node = node; 273 informp->extra = SBDP_ASSIGN; 274 len = sizeof (info2_t); 275 276 sbdp_init_msg_pkt(reqp, DR_MBOX_ASSIGN, len, (caddr_t)informp); 277 278 len = sizeof (cmd_rev); 279 280 sbdp_init_msg_pkt(resp, DR_MBOX_ASSIGN, len, (caddr_t)&cmd_rev); 281 282 rv = sbbc_mbox_request_response(reqp, resp, sbdp_mbox_wait); 283 284 if (rv != 0 || (rv = resp->msg_status != SG_MBOX_STATUS_SUCCESS)) { 285 SBDP_DBG_MISC("failed to assign board: rv = %d\n", rv); 286 sbdp_set_err(sep, sbdp_sc_err_translation(resp->msg_status), 287 NULL); 288 } 289 290 return (rv); 291 } 292 293 /* 294 * Entry point from sbd. Call down to the SC to unassign the board 295 * We simply return the status the SC told us 296 */ 297 int 298 sbdp_unassign_board(sbdp_handle_t *hp) 299 { 300 int board = hp->h_board; 301 int node = hp->h_wnode; 302 sbbc_msg_t request, *reqp = &request; 303 sbbc_msg_t response, *resp = &response; 304 int cmd_rev = -1; 305 info2_t inform, *informp = &inform; 306 int rv = 0; 307 sbd_error_t *sep; 308 int len; 309 static fn_t f = "sbdp_unassign_board"; 310 311 SBDP_DBG_FUNC("%s\n", f); 312 313 sep = hp->h_err; 314 /* 315 * Check for options. If there are any, fail the operation 316 */ 317 if (hp->h_opts != NULL && hp->h_opts->copts != NULL) { 318 sbdp_set_err(sep, ESBD_INVAL_OPT, hp->h_opts->copts); 319 return (-1); 320 } 321 322 informp->board = board; 323 informp->node = node; 324 informp->extra = SBDP_UNASSIGN; 325 len = sizeof (info2_t); 326 327 sbdp_init_msg_pkt(reqp, DR_MBOX_ASSIGN, len, (caddr_t)informp); 328 329 len = sizeof (cmd_rev); 330 331 sbdp_init_msg_pkt(resp, DR_MBOX_ASSIGN, len, (caddr_t)&cmd_rev); 332 333 rv = sbbc_mbox_request_response(reqp, resp, sbdp_mbox_wait); 334 335 if (rv != 0 || (rv = resp->msg_status != SG_MBOX_STATUS_SUCCESS)) { 336 SBDP_DBG_MISC("failed to unassign board: rv = %d\n", rv); 337 sbdp_set_err(sep, sbdp_sc_err_translation(resp->msg_status), 338 NULL); 339 } 340 341 return (rv); 342 } 343 344 static int 345 sg_attach_board(void *arg) 346 { 347 sbdp_handle_t *hp; 348 cpuset_t cset; 349 int rv; 350 static fn_t f = "sg_attach_board"; 351 352 SBDP_DBG_FUNC("%s\n", f); 353 354 hp = (sbdp_handle_t *)arg; 355 356 cset = cpu_ready_set; 357 promsafe_xc_attention(cset); 358 rv = prom_serengeti_attach_board(hp->h_wnode, hp->h_board); 359 xc_dismissed(cset); 360 361 return (rv); 362 } 363 364 static int 365 sg_detach_board(void *arg) 366 { 367 sbdp_handle_t *hp; 368 cpuset_t cset; 369 int rv; 370 static fn_t f = "sg_detach_board"; 371 372 SBDP_DBG_FUNC("%s\n", f); 373 374 hp = (sbdp_handle_t *)arg; 375 376 cset = cpu_ready_set; 377 promsafe_xc_attention(cset); 378 rv = prom_serengeti_detach_board(hp->h_wnode, hp->h_board); 379 xc_dismissed(cset); 380 381 return (rv); 382 } 383 384 /* 385 * Entry point from sbd. First we call down to the SC to "attach/claim" this 386 * board. As a side effect the SC updates the pda info so obp can create the 387 * device tree. If we are successful, we ask OBP to probe the board. OBP 388 * creates new nodes on its own obp tree 389 * As an added bonus, since we don't use the inkernel prober, we need to create 390 * the dev_info nodes but just to a point where they are created but 391 * Solaris can't use them (i.e BIND) 392 */ 393 int 394 sbdp_connect_board(sbdp_handle_t *hp) 395 { 396 sbbc_msg_t request, *reqp = &request; 397 sbbc_msg_t response, *resp = &response; 398 int rv = 0; 399 int board, node; 400 sbd_error_t *sep; 401 static fn_t f = "sbdp_connect_board"; 402 int panther_pages_enabled; 403 404 SBDP_DBG_FUNC("%s\n", f); 405 406 board = hp->h_board; 407 node = hp->h_wnode; 408 sep = hp->h_err; 409 410 /* 411 * Check for options. If there are any, fail the operation 412 */ 413 if (hp->h_opts != NULL && hp->h_opts->copts != NULL) { 414 sbdp_set_err(sep, ESBD_INVAL_OPT, hp->h_opts->copts); 415 return (-1); 416 } 417 418 /* 419 * Currently, we pass the info in the extra data fields. 420 * This may change in the SC. We need to change it then 421 */ 422 sbdp_init_msg_pkt(reqp, DR_MBOX_CLAIM, 0, (caddr_t)NULL); 423 reqp->msg_data[0] = node; 424 reqp->msg_data[1] = board; 425 426 sbdp_init_msg_pkt(resp, DR_MBOX_CLAIM, 0, (caddr_t)NULL); 427 428 rv = sbbc_mbox_request_response(reqp, resp, sbdp_mbox_wait); 429 430 if (rv != 0 || (rv = resp->msg_status != SG_MBOX_STATUS_SUCCESS)) { 431 SBDP_DBG_MISC("failed to claim board: rv = %d\n", rv); 432 sbdp_set_err(sep, sbdp_sc_err_translation(resp->msg_status), 433 NULL); 434 return (rv); 435 } 436 437 rv = prom_tree_update(sg_attach_board, hp); 438 if (rv != 0) { 439 SBDP_DBG_MISC("failed to prom attach board: rv = %d\n", rv); 440 sbdp_set_err(sep, ESGT_PROM_ATTACH, NULL); 441 /* 442 * Clean up 443 */ 444 sbdp_init_msg_pkt(reqp, DR_MBOX_UNCLAIM, 0, (caddr_t)NULL); 445 reqp->msg_data[0] = node; 446 reqp->msg_data[1] = board; 447 448 sbdp_init_msg_pkt(resp, DR_MBOX_UNCLAIM, 0, (caddr_t)NULL); 449 450 (void) sbbc_mbox_request_response(reqp, resp, sbdp_mbox_wait); 451 452 return (rv); 453 } 454 455 SBDP_DBG_MISC("prom attach worked\n"); 456 sbdp_attach_bd(node, board); 457 458 /* 459 * XXX Until the Solaris large pages support heterogeneous cpu 460 * domains, DR needs to prevent the addition of non-Panther cpus 461 * to an all-Panther domain with large pages enabled. 462 */ 463 panther_pages_enabled = (page_num_pagesizes() > DEFAULT_MMU_PAGE_SIZES); 464 if (sbdp_board_non_panther_cpus(node, board) > 0 && 465 panther_pages_enabled && sbdp_large_page_restriction) { 466 cmn_err(CE_WARN, "Domain shutdown is required to add a non-" 467 "UltraSPARC-IV+ board into an all UltraSPARC-IV+ domain"); 468 (void) sbdp_disconnect_board(hp); 469 sbdp_set_err(sep, ESGT_NOT_SUPP, NULL); 470 return (-1); 471 } 472 473 /* 474 * Now that the board has been successfully attached, obtain 475 * platform-specific DIMM serial id information for the board. 476 */ 477 if (SG_BOARD_IS_CPU_TYPE(board) && 478 plat_ecc_capability_sc_get(PLAT_ECC_DIMM_SID_MESSAGE)) { 479 (void) plat_request_mem_sids(board); 480 } 481 482 return (rv); 483 } 484 485 /* 486 * Entry point from sbd. Undo the connect call. We first need to remove 487 * the "dummy (i.e unusable)" nodes from solaris. We then call down to OBP 488 * to prune its tree. After all has been cleaned up from OBP and Solaris 489 * We call the SC to "detach/unclain" the board. A side effect is that the 490 * SC will clear the pda entries for this board 491 */ 492 int 493 sbdp_disconnect_board(sbdp_handle_t *hp) 494 { 495 sbbc_msg_t request, *reqp = &request; 496 sbbc_msg_t response, *resp = &response; 497 int rv = 0; 498 int board, node; 499 sbd_error_t *sep; 500 static fn_t f = "sbdp_disconnect_board"; 501 502 SBDP_DBG_FUNC("%s\n", f); 503 504 board = hp->h_board; 505 node = hp->h_wnode; 506 sep = hp->h_err; 507 508 SBDP_DBG_MISC("sbdp_disconnect_board: board = %d node = %d\n", 509 board, node); 510 511 /* 512 * Check for options. If there are any, fail the operation 513 */ 514 if (hp->h_opts != NULL && hp->h_opts->copts != NULL) { 515 sbdp_set_err(sep, ESBD_INVAL_OPT, hp->h_opts->copts); 516 return (-1); 517 } 518 519 if (sbdp_detach_bd(node, board, sep)) { 520 sbdp_attach_bd(node, board); 521 SBDP_DBG_ALL("failed to detach board %d\n", board); 522 return (-1); 523 } 524 525 rv = prom_tree_update(sg_detach_board, hp); 526 if (rv == -1) { 527 /* 528 * Clean up 529 */ 530 sbdp_attach_bd(node, board); 531 SBDP_DBG_MISC("failed to prom detach board: rv = %d\n", rv); 532 sbdp_set_err(sep, ESGT_PROM_DETACH, NULL); 533 return (rv); 534 } 535 536 SBDP_DBG_MISC("prom detach worked\n"); 537 /* 538 * Currently, we pass the info in the extra data fields. 539 * This may change in the SC. We need to change it then 540 */ 541 sbdp_init_msg_pkt(reqp, DR_MBOX_UNCLAIM, 0, (caddr_t)NULL); 542 reqp->msg_data[0] = node; 543 reqp->msg_data[1] = board; 544 545 sbdp_init_msg_pkt(resp, DR_MBOX_UNCLAIM, 0, (caddr_t)NULL); 546 547 rv = sbbc_mbox_request_response(reqp, resp, sbdp_mbox_wait); 548 549 if (rv != 0 || (rv = resp->msg_status != SG_MBOX_STATUS_SUCCESS)) { 550 SBDP_DBG_MISC("failed to unclaim board: rv = %d\n", rv); 551 sbdp_set_err(sep, sbdp_sc_err_translation(resp->msg_status), 552 NULL); 553 /* bring back the obp tree to what it was */ 554 (void) prom_tree_update(sg_attach_board, hp); 555 } 556 557 /* 558 * Now that the board has been successfully detached, discard 559 * platform-specific DIMM serial id information for the board. 560 */ 561 if (!rv && SG_BOARD_IS_CPU_TYPE(board) && 562 plat_ecc_capability_sc_get(PLAT_ECC_DIMM_SID_MESSAGE)) { 563 (void) plat_discard_mem_sids(board); 564 } 565 566 return (rv); 567 } 568 569 /* 570 * Entry point from sbd. Very simple. Just ask the SC to poweoff the board 571 * Return the status from the SC 572 */ 573 int 574 sbdp_poweroff_board(sbdp_handle_t *hp) 575 { 576 sbbc_msg_t request, *reqp = &request; 577 sbbc_msg_t response, *resp = &response; 578 int cmd_rev = -1; 579 info2_t inform, *informp; 580 int rv = 0; 581 sbd_error_t *sep; 582 int len; 583 static fn_t f = "sbdp_poweroff_board"; 584 585 SBDP_DBG_FUNC("%s\n", f); 586 587 sep = hp->h_err; 588 /* 589 * Check for options. If there are any, fail the operation 590 */ 591 if (hp->h_opts != NULL && hp->h_opts->copts != NULL) { 592 sbdp_set_err(sep, ESBD_INVAL_OPT, hp->h_opts->copts); 593 return (-1); 594 } 595 596 /* 597 * Can't check for bad options here since we use this for workaround 598 * on poweron. 599 */ 600 601 informp = &inform; 602 informp->board = hp->h_board; 603 informp->node = hp->h_wnode; 604 informp->extra = SBDP_POWER_OFF; 605 606 len = sizeof (info2_t); 607 sbdp_init_msg_pkt(reqp, DR_MBOX_POWER, len, (caddr_t)informp); 608 609 len = sizeof (cmd_rev); 610 sbdp_init_msg_pkt(resp, DR_MBOX_POWER, len, (caddr_t)&cmd_rev); 611 612 rv = sbbc_mbox_request_response(reqp, resp, sbdp_mbox_wait); 613 614 if (rv != 0 || (rv = resp->msg_status != SG_MBOX_STATUS_SUCCESS)) { 615 SBDP_DBG_MISC("failed to poweroff board: rv = %d\n", rv); 616 sbdp_set_err(sep, sbdp_sc_err_translation(resp->msg_status), 617 NULL); 618 } 619 620 return (rv); 621 } 622 623 /* 624 * Entry point from sbd. Ask the SC to poweron the board 625 * Return the status from the SC 626 */ 627 int 628 sbdp_poweron_board(sbdp_handle_t *hp) 629 { 630 sbbc_msg_t request, *reqp = &request; 631 sbbc_msg_t response, *resp = &response; 632 int cmd_rev = -1; 633 info2_t inform, *informp; 634 int rv = 0; 635 sbd_error_t *sep; 636 int len; 637 int board = hp->h_board; 638 static fn_t f = "sbdp_poweron_board"; 639 640 SBDP_DBG_FUNC("%s\n", f); 641 642 sep = hp->h_err; 643 /* 644 * Check for options. If there are any, fail the operation 645 */ 646 if (hp->h_opts != NULL && hp->h_opts->copts != NULL) { 647 sbdp_set_err(sep, ESBD_INVAL_OPT, hp->h_opts->copts); 648 return (-1); 649 } 650 651 if (sbdp_poweroff_wkaround) 652 if (SG_BOARD_IS_CPU_TYPE(board)) { 653 654 if ((rv = sbdp_poweroff_board(hp)) != 0) 655 return (rv); 656 } 657 658 informp = &inform; 659 informp->board = hp->h_board; 660 informp->node = hp->h_wnode; 661 informp->extra = SBDP_POWER_ON; 662 663 len = sizeof (info2_t); 664 sbdp_init_msg_pkt(reqp, DR_MBOX_POWER, len, (caddr_t)informp); 665 666 len = sizeof (cmd_rev); 667 sbdp_init_msg_pkt(resp, DR_MBOX_POWER, len, (caddr_t)&cmd_rev); 668 669 rv = sbbc_mbox_request_response(reqp, resp, sbdp_mbox_wait); 670 671 if (rv != 0 || (rv = resp->msg_status != SG_MBOX_STATUS_SUCCESS)) { 672 SBDP_DBG_MISC("failed to poweron board: rv = %d\n", rv); 673 sbdp_set_err(sep, sbdp_sc_err_translation(resp->msg_status), 674 NULL); 675 } 676 677 return (rv); 678 } 679 680 int 681 sbdp_get_diag(sbdp_opts_t *opts) 682 { 683 char *cptr; 684 static fn_t f = "sbdp_get_diag"; 685 686 SBDP_DBG_FUNC("%s\n", f); 687 688 if ((opts == NULL) || (opts->copts == NULL)) 689 return (SBDP_DIAG_NVCI); 690 691 if ((cptr = strstr(opts->copts, "diag=")) != NULL) { 692 /* 693 * We have args and need to process them 694 */ 695 cptr += strlen("diag="); 696 697 if (strncmp(cptr, "off", sizeof ("off")) == 0) { 698 return (SBDP_DIAG_OFF); 699 } else if (strncmp(cptr, "init", sizeof ("init")) == 0) { 700 return (SBDP_DIAG_INIT); 701 } else if (strncmp(cptr, "quick", sizeof ("quick")) == 0) { 702 return (SBDP_DIAG_QUICK); 703 } else if (strncmp(cptr, "min", sizeof ("min")) == 0) { 704 return (SBDP_DIAG_MIN); 705 } else if (strncmp(cptr, "default", sizeof ("default")) == 0 || 706 strncmp(cptr, "max", sizeof ("max")) == 0) { 707 return (SBDP_DIAG_DEFAULT); 708 } else if (strncmp(cptr, "mem1", sizeof ("mem1")) == 0) { 709 return (SBDP_DIAG_MEM1); 710 } else if (strncmp(cptr, "mem2", sizeof ("mem2")) == 0) { 711 return (SBDP_DIAG_MEM2); 712 } 713 } 714 SBDP_DBG_MISC("error: unrecognized arg\n"); 715 return (-1); 716 } 717 718 719 /* 720 * Entry point from sbd. Ask the SC to test the board. We still need to 721 * worry about the diag level. The user may have changed it 722 * 723 * NOTE: The flag field has 2 different meanings whether we are dealing 724 * with a cpu/mem board or an io board. In the case of a cpu/mem board it 725 * means retest the board to the diag level specified. In the case of an IO 726 * board, it means: Perform the necessary steps to prepare the board 727 * for the claim without running POST at the diag level specified. 728 */ 729 int 730 sbdp_test_board(sbdp_handle_t *hp, sbdp_opts_t *opts) 731 { 732 int board = hp->h_board; 733 int node = hp->h_wnode; 734 sbbc_msg_t request, *reqp = &request; 735 sbbc_msg_t response, *resp = &response; 736 int cmd_rev = -1; 737 testb_t inform, *informp = &inform; 738 int rv = 0; 739 sbd_error_t *sep; 740 int diag; 741 int len; 742 static fn_t f = "sbdp_test_board"; 743 744 SBDP_DBG_FUNC("%s\n", f); 745 746 sep = hp->h_err; 747 748 diag = sbdp_get_diag(opts); 749 750 if (diag == -1) { 751 sbdp_set_err(sep, ESBD_INVAL_OPT, opts != NULL ? 752 opts->copts : NULL); 753 return (-1); 754 } 755 756 SBDP_DBG_MISC("Diag level is 0x%x\n", diag); 757 758 informp->info.board = board; 759 informp->info.node = node; 760 761 informp->info.extra = diag; 762 763 /* 764 * Only force retest on CPU boards 765 */ 766 if (SG_BOARD_IS_CPU_TYPE(board)) 767 informp->flag = 1; 768 else { 769 /* 770 * For CPULESS IO pass the force to the SC 771 */ 772 if (hp->h_flags & SBDP_IOCTL_FLAG_FORCE) 773 informp->flag = 1; 774 else 775 informp->flag = 0; 776 777 } 778 779 len = sizeof (testb_t); 780 sbdp_init_msg_pkt(reqp, DR_MBOX_TEST_BD, len, (caddr_t)informp); 781 782 783 len = sizeof (cmd_rev); 784 sbdp_init_msg_pkt(resp, DR_MBOX_TEST_BD, len, (caddr_t)&cmd_rev); 785 786 rv = sbbc_mbox_request_response(reqp, resp, sbdp_mbox_wait); 787 788 if (rv != 0 || (resp->msg_status != SG_MBOX_STATUS_SUCCESS)) { 789 SBDP_DBG_MISC("failed to test board: rv = %d status = %d\n", 790 rv, resp->msg_status); 791 rv = resp->msg_status; 792 sbdp_set_err(sep, sbdp_sc_err_translation(resp->msg_status), 793 NULL); 794 } 795 796 return (rv); 797 } 798 799 /* 800 * Request the SC to update POST's memory slice table by swapping 801 * the entries for the two board numbers given 802 * This is used when performing a copy-rename operation. 803 */ 804 int 805 sbdp_swap_slices(int bd1, int bd2) 806 { 807 sbbc_msg_t request, *reqp = &request; 808 sbbc_msg_t response, *resp = &response; 809 int cmd_rev = -1; 810 swap_slices_t inform, *informp = &inform; 811 int rv; 812 int len; 813 static fn_t f = "sbdp_swap_slices"; 814 815 SBDP_DBG_FUNC("%s\n", f); 816 817 informp->board1 = bd1; 818 informp->board2 = bd2; 819 820 len = sizeof (swap_slices_t); 821 sbdp_init_msg_pkt(reqp, DR_MBOX_SWAP_SLICES, len, (caddr_t)informp); 822 823 len = sizeof (cmd_rev); 824 sbdp_init_msg_pkt(resp, DR_MBOX_SWAP_SLICES, len, (caddr_t)&cmd_rev); 825 826 rv = sbbc_mbox_request_response(reqp, resp, sbdp_mbox_wait); 827 828 if (rv != 0 || (resp->msg_status != SG_MBOX_STATUS_SUCCESS)) { 829 SBDP_DBG_MISC("failed to swap slices %d<->%d: rv = %d " 830 "status = %d\n", bd1, bd2, rv, resp->msg_status); 831 rv = sbdp_sc_err_translation(resp->msg_status); 832 } 833 834 return (rv); 835 } 836 837 int 838 sbdp_sc_err_translation(int error) 839 { 840 int err; 841 static fn_t f = "sbdp_sc_err_translation"; 842 843 SBDP_DBG_FUNC("%s\n", f); 844 845 switch (error) { 846 case SG_MBOX_STATUS_HARDWARE_FAILURE: 847 err = ESGT_HW_FAIL; 848 break; 849 case SG_MBOX_STATUS_ILLEGAL_PARAMETER: 850 case SG_MBOX_STATUS_ILLEGAL_NODE: 851 case SG_MBOX_STATUS_ILLEGAL_SLOT: 852 err = ESGT_INVAL; 853 break; 854 case SG_MBOX_STATUS_BOARD_ACCESS_DENIED: 855 err = ESGT_BD_ACCESS; 856 break; 857 case SG_MBOX_STATUS_STALE_CONTENTS: 858 err = ESGT_STALE_CMP; 859 break; 860 case SG_MBOX_STATUS_STALE_OBJECT: 861 err = ESGT_STALE_OBJ; 862 break; 863 case SG_MBOX_STATUS_NO_SEPROM_SPACE: 864 err = ESGT_NO_SEPROM_SPACE; 865 break; 866 case SG_MBOX_STATUS_NO_MEMORY: 867 err = ESGT_NO_MEM; 868 break; 869 case SG_MBOX_STATUS_NOT_SUPPORTED: 870 err = ESGT_NOT_SUPP; 871 break; 872 case SG_MBOX_STATUS_COMMAND_FAILURE: 873 default: 874 err = ESGT_INTERNAL; 875 break; 876 } 877 878 return (err); 879 } 880 881 int 882 sbdp_stop_cpu(processorid_t cpu) 883 { 884 sbbc_msg_t request, *reqp = &request; 885 sbbc_msg_t response, *resp = &response; 886 int rv = 0; 887 int len; 888 static fn_t f = "sbdp_stop_cpu"; 889 890 SBDP_DBG_FUNC("%s\n", f); 891 892 len = sizeof (processorid_t); 893 sbdp_init_msg_pkt(reqp, DR_MBOX_STOP_CPU, len, (caddr_t)&cpu); 894 895 sbdp_init_msg_pkt(resp, DR_MBOX_STOP_CPU, 0, (caddr_t)NULL); 896 897 rv = sbbc_mbox_request_response(reqp, resp, sbdp_mbox_wait); 898 899 if (rv != 0 || (rv = resp->msg_status != SG_MBOX_STATUS_SUCCESS)) { 900 SBDP_DBG_MISC("failed to stop cpu: rv = %d\n", rv); 901 } 902 903 return (rv); 904 } 905 906 int 907 sbdp_start_cpu(processorid_t cpu) 908 { 909 sbbc_msg_t request, *reqp = &request; 910 sbbc_msg_t response, *resp = &response; 911 int rv = 0; 912 int len; 913 static fn_t f = "sbdp_start_cpu"; 914 915 SBDP_DBG_FUNC("%s\n", f); 916 917 len = sizeof (cpu); 918 sbdp_init_msg_pkt(reqp, DR_MBOX_START_CPU, len, (caddr_t)&cpu); 919 920 sbdp_init_msg_pkt(resp, DR_MBOX_START_CPU, 0, (caddr_t)NULL); 921 922 rv = sbbc_mbox_request_response(reqp, resp, sbdp_mbox_wait); 923 924 if (rv != 0 || (rv = resp->msg_status != SG_MBOX_STATUS_SUCCESS)) { 925 SBDP_DBG_MISC("failed to start cpu: rv = %d\n", rv); 926 } 927 928 return (rv); 929 } 930 931 /* 932 * With the SIR implementation for CPU unconfigure, this mailbox 933 * call is obsolete. 934 */ 935 int 936 sbdp_start_cpu_pairs(processorid_t cpu) 937 { 938 sbbc_msg_t request, *reqp = &request; 939 sbbc_msg_t response, *resp = &response; 940 int rv = 0; 941 int len; 942 static fn_t f = "sbdp_start_cpu_pairs"; 943 944 SBDP_DBG_FUNC("%s\n", f); 945 946 len = sizeof (cpu); 947 sbdp_init_msg_pkt(reqp, DR_MBOX_START_CPU_PAIRS, len, (caddr_t)&cpu); 948 949 sbdp_init_msg_pkt(resp, DR_MBOX_START_CPU_PAIRS, 0, (caddr_t)NULL); 950 951 rv = sbbc_mbox_request_response(reqp, resp, sbdp_mbox_wait); 952 953 if (rv != 0 || (rv = resp->msg_status != SG_MBOX_STATUS_SUCCESS)) { 954 SBDP_DBG_MISC("failed to start cpu pair: rv = %d\n", rv); 955 } 956 957 return (rv); 958 } 959