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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * memory support routines for sbd. 29 */ 30 31 #include <sys/debug.h> 32 #include <sys/types.h> 33 #include <sys/errno.h> 34 #include <sys/param.h> 35 #include <sys/dditypes.h> 36 #include <sys/kmem.h> 37 #include <sys/conf.h> 38 #include <sys/ddi.h> 39 #include <sys/sunddi.h> 40 #include <sys/sunndi.h> 41 #include <sys/ddi_impldefs.h> 42 #include <sys/sysmacros.h> 43 #include <sys/machsystm.h> 44 #include <sys/spitregs.h> 45 #include <sys/cpuvar.h> 46 #include <sys/cpu_module.h> 47 #include <sys/promif.h> 48 #include <sys/memlist_impl.h> 49 #include <sys/mem_cage.h> 50 #include <sys/lgrp.h> 51 #include <sys/platform_module.h> 52 #include <vm/seg_kmem.h> 53 54 #include <sys/sbdpriv.h> 55 56 #define _ptob64(p) ((uint64_t)(p) << PAGESHIFT) 57 #define _b64top(b) ((pgcnt_t)((b) >> PAGESHIFT)) 58 59 static int sbd_post_detach_mem_unit(sbd_mem_unit_t *mp, 60 sbderror_t *ep); 61 static int sbd_reserve_mem_spans(memhandle_t *mhp, 62 struct memlist *mlist); 63 static int sbd_check_boundaries(struct memlist *orig_memlist, 64 sbd_mem_unit_t *s_mp, 65 sbd_mem_unit_t *t_mp); 66 static int sbd_select_mem_target(sbd_handle_t *hp, 67 sbd_mem_unit_t *mp, struct memlist *ml); 68 static void sbd_init_mem_unit_data(sbd_mem_unit_t *mp, sbderror_t 69 *ep); 70 static int memlist_canfit(struct memlist *s_mlist, 71 struct memlist *t_mlist); 72 static void sbd_mem_cleanup(sbd_mem_unit_t *s_mp, 73 sbd_mem_unit_t *t_mp, sbderror_t *ep); 74 static void sbd_flush_ecache(uint64_t a, uint64_t b); 75 76 struct memlist * 77 sbd_get_memlist(sbd_mem_unit_t *mp, sbderror_t *ep) 78 { 79 struct memlist *mlist; 80 static fn_t f = "sbd_get_memlist"; 81 sbd_board_t *sbp = (sbd_board_t *)mp->sbm_cm.sbdev_sbp; 82 sbdp_handle_t *hdp; 83 sbd_handle_t *hp = MACHBD2HD(sbp); 84 85 PR_MEM("%s...\n", f); 86 87 /* 88 * Return cached memlist, if present. 89 * This memlist will be present following an 90 * unconfigure (a.k.a: detach) of this memunit. 91 * It should only be used in the case were a configure 92 * is bringing this memunit back in without going 93 * through the disconnect and connect states. 94 */ 95 if (mp->sbm_mlist) { 96 PR_MEM("%s: found cached memlist\n", f); 97 98 mlist = memlist_dup(mp->sbm_mlist); 99 } else { 100 /* attempt to construct a memlist using phys_install */ 101 102 /* 103 * NOTE: this code block assumes only one memunit per 104 * board. This is currently safe because the function 105 * sbd_init_mem_devlist() forces this assumption to be 106 * valid. 107 */ 108 109 /* round down to slice base address */ 110 /* build mlist from the lower layer */ 111 hdp = sbd_get_sbdp_handle(sbp, hp); 112 mlist = sbdp_get_memlist(hdp, mp->sbm_cm.sbdev_dip); 113 if (mlist == NULL) { 114 SBD_GET_PERR(hdp->h_err, ep); 115 PR_MEM("sbd:%s: failed to get memlist for " 116 "dip (0x%p) ecode %d errno %d", f, 117 (void *)mp->sbm_cm.sbdev_dip, 118 ep->e_code, ep->e_errno); 119 sbd_release_sbdp_handle(hdp); 120 return (NULL); 121 } 122 sbd_release_sbdp_handle(hdp); 123 } 124 125 PR_MEM("%s: memlist for mem-unit (%d.%d), dip 0x%p:\n", 126 f, sbp->sb_num, 127 mp->sbm_cm.sbdev_unum, 128 (void *)mp->sbm_cm.sbdev_dip); 129 SBD_MEMLIST_DUMP(mlist); 130 131 return (mlist); 132 } 133 134 int 135 sbd_pre_attach_mem(sbd_handle_t *hp, sbd_devlist_t devlist[], int devnum) 136 { 137 int err_flag = 0; 138 sbderror_t *ep = SBD_HD2ERR(hp); 139 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 140 int d, i; 141 sbdp_handle_t *hdp; 142 static fn_t f = "sbd_pre_attach_mem"; 143 144 PR_MEM("%s...\n", f); 145 146 SBD_SET_ERR(ep, 0); 147 hdp = sbd_get_sbdp_handle(sbp, hp); 148 149 for (d = 0; d < devnum; d++) { 150 sbd_mem_unit_t *mp; 151 int unit; 152 dev_info_t *dip; 153 sbd_istate_t state; 154 int rv; 155 156 /* sbd_get_devlist will not devlist element w/ dip of 0 */ 157 ASSERT(devlist[d].dv_dip != NULL); 158 159 dip = devlist[d].dv_dip; 160 unit = sbdp_get_unit_num(hdp, dip); 161 if (unit == -1) { 162 if (hp->h_flags & SBD_IOCTL_FLAG_FORCE) 163 continue; 164 else { 165 SBD_GET_PERR(hdp->h_err, ep); 166 err_flag = 1; 167 break; 168 } 169 } 170 171 mp = SBD_GET_BOARD_MEMUNIT(sbp, unit); 172 173 ASSERT(mp->sbm_cm.sbdev_sbp == sbp); 174 ASSERT(unit == mp->sbm_cm.sbdev_unum); 175 176 PR_MEM("sbd: OS attach mem-unit (%d.%d)\n", 177 sbp->sb_num, 178 mp->sbm_cm.sbdev_unum); 179 180 state = mp->sbm_cm.sbdev_state; 181 switch (state) { 182 case SBD_STATE_UNCONFIGURED: 183 /* use memlist cached by sbd_post_detach_mem_unit */ 184 if (mp->sbm_mlist != NULL) { 185 PR_MEM("%s: recovering from UNCONFIG" 186 " mem-unit (%d.%d)\n", 187 f, sbp->sb_num, 188 mp->sbm_cm.sbdev_unum); 189 190 PR_MEM("%s: re-configure cached memlist:\n", f); 191 SBD_MEMLIST_DUMP(mp->sbm_mlist); 192 193 /* 194 * kphysm del handle should have been freed 195 */ 196 ASSERT((mp->sbm_flags & SBD_MFLAG_RELOWNER) 197 == 0); 198 } else { 199 if (hp->h_flags & SBD_IOCTL_FLAG_FORCE) 200 continue; 201 else { 202 SBD_GET_PERR(hdp->h_err, ep); 203 err_flag = 1; 204 PR_MEM("%s: mem-unit (%d.%d)" 205 " unusable\n", 206 f, sbp->sb_num, 207 mp->sbm_cm.sbdev_unum); 208 break; 209 } 210 } 211 212 /*FALLTHROUGH*/ 213 214 case SBD_STATE_CONNECTED: 215 PR_MEM("%s: reprogramming mem hardware (board %d)\n", 216 f, sbp->sb_num); 217 218 for (i = 0; i < SBD_NUM_MC_PER_BOARD; i++) { 219 if (mp->sbm_dip[i] == NULL) 220 continue; 221 dip = mp->sbm_dip[i]; 222 223 PR_MEM("%s: enabling mc 0x%p on board %d\n", 224 f, (void *)dip, sbp->sb_num); 225 226 rv = sbdphw_enable_memctrl(hdp, dip); 227 if (rv < 0) { 228 SBD_GET_PERR(hdp->h_err, ep); 229 cmn_err(CE_WARN, 230 "%s: failed to program mem ctrlr %p on " 231 "board %d", f, (void *)mp->sbm_dip[i], 232 sbp->sb_num); 233 err_flag = 1; 234 } 235 } 236 break; 237 238 default: 239 cmn_err(CE_WARN, 240 "%s: unexpected state (%d) for mem-unit " 241 "(%d.%d)", f, state, sbp->sb_num, 242 mp->sbm_cm.sbdev_unum); 243 if (SBD_GET_ERR(ep) == 0) { 244 SBD_SET_ERR(ep, ESBD_STATE); 245 err_flag = 1; 246 } 247 break; 248 } 249 250 /* exit for loop if error encountered */ 251 if (err_flag) { 252 SBD_SET_ERRSTR(ep, 253 sbp->sb_mempath[mp->sbm_cm.sbdev_unum]); 254 break; 255 } 256 } 257 sbd_release_sbdp_handle(hdp); 258 259 return (err_flag ? -1 : 0); 260 } 261 262 int 263 sbd_post_attach_mem(sbd_handle_t *hp, sbd_devlist_t devlist[], int devnum) 264 { 265 int d; 266 sbdp_handle_t *hdp; 267 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 268 sbderror_t *ep = SBD_HD2ERR(hp); 269 static fn_t f = "sbd_post_attach_mem"; 270 271 PR_MEM("%s...\n", f); 272 hdp = sbd_get_sbdp_handle(sbp, hp); 273 274 for (d = 0; d < devnum; d++) { 275 sbd_mem_unit_t *mp; 276 dev_info_t *dip; 277 int unit; 278 struct memlist *mlist, *ml; 279 280 /* sbd_get_devlist will not devlist element w/ dip of 0 */ 281 ASSERT(devlist[d].dv_dip != NULL); 282 283 dip = devlist[d].dv_dip; 284 unit = sbdp_get_unit_num(hdp, dip); 285 if (unit == -1) { 286 if (hp->h_flags & SBD_IOCTL_FLAG_FORCE) 287 continue; 288 else { 289 SBD_GET_PERR(hdp->h_err, ep); 290 break; 291 } 292 } 293 294 mp = SBD_GET_BOARD_MEMUNIT(sbp, unit); 295 296 mlist = sbd_get_memlist(mp, ep); 297 if (mlist == NULL) { 298 cmn_err(CE_WARN, 299 "%s: no memlist for mem-unit (%d.%d)", 300 f, 301 sbp->sb_num, 302 mp->sbm_cm.sbdev_unum); 303 304 if (SBD_GET_ERR(ep) == 0) { 305 SBD_SET_ERR(ep, ESBD_MEMFAIL); 306 SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]); 307 } 308 309 continue; 310 } 311 312 /* 313 * Verify the memory really did successfully attach 314 * by checking for its existence in phys_install. 315 */ 316 317 memlist_read_lock(); 318 if (memlist_intersect(phys_install, mlist) == 0) { 319 memlist_read_unlock(); 320 321 cmn_err(CE_WARN, 322 "%s: mem-unit (%d.%d) memlist not in" 323 " phys_install", f, sbp->sb_num, 324 mp->sbm_cm.sbdev_unum); 325 326 if (SBD_GET_ERR(ep) == 0) { 327 SBD_SET_ERR(ep, ESBD_INTERNAL); 328 SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]); 329 } 330 331 memlist_delete(mlist); 332 continue; 333 } 334 memlist_read_unlock(); 335 336 for (ml = mlist; ml != NULL; ml = ml->next) { 337 (void) sbdp_mem_add_span(hdp, ml->address, ml->size); 338 } 339 340 memlist_delete(mlist); 341 342 /* 343 * Destroy cached memlist, if any. 344 * There will be a cached memlist in sbm_mlist if 345 * this board is being configured directly after 346 * an unconfigure. 347 * To support this transition, sbd_post_detach_mem 348 * left a copy of the last known memlist in sbm_mlist. 349 * This memlist could differ from any derived from 350 * hardware if while this memunit was last configured 351 * the system detected and deleted bad pages from 352 * phys_install. The location of those bad pages 353 * will be reflected in the cached memlist. 354 */ 355 if (mp->sbm_mlist) { 356 memlist_delete(mp->sbm_mlist); 357 mp->sbm_mlist = NULL; 358 } 359 sbd_init_mem_unit_data(mp, ep); 360 } 361 362 sbd_release_sbdp_handle(hdp); 363 return (0); 364 } 365 366 int 367 sbd_pre_detach_mem(sbd_handle_t *hp, sbd_devlist_t devlist[], int devnum) 368 { 369 int d; 370 int unit; 371 sbdp_handle_t *hdp; 372 sbderror_t *ep = SBD_HD2ERR(hp); 373 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 374 dev_info_t *dip; 375 376 hdp = sbd_get_sbdp_handle(sbp, hp); 377 378 for (d = 0; d < devnum; d++) { 379 sbd_mem_unit_t *mp; 380 381 /* sbd_get_devlist will not devlist element w/ dip of 0 */ 382 ASSERT(devlist[d].dv_dip != NULL); 383 384 dip = devlist[d].dv_dip; 385 unit = sbdp_get_unit_num(hdp, dip); 386 if (unit == -1) { 387 if (hp->h_flags & SBD_IOCTL_FLAG_FORCE) 388 continue; 389 else { 390 SBD_GET_PERR(hdp->h_err, ep); 391 sbd_release_sbdp_handle(hdp); 392 return (-1); 393 } 394 } 395 396 mp = SBD_GET_BOARD_MEMUNIT(sbp, unit); 397 398 /* sanity check */ 399 ASSERT(mp->sbm_cm.sbdev_sbp == sbp); 400 ASSERT(unit == mp->sbm_cm.sbdev_unum); 401 402 PR_MEM("sbd: OS detach mem-unit (%d.%d)\n", 403 sbp->sb_num, mp->sbm_cm.sbdev_unum); 404 } 405 406 sbd_release_sbdp_handle(hdp); 407 return (0); 408 } 409 410 int 411 sbd_post_detach_mem(sbd_handle_t *hp, sbd_devlist_t devlist[], int devnum) 412 { 413 int d, rv; 414 sbdp_handle_t *hdp; 415 sbd_board_t *sbp; 416 sbd_mem_unit_t *s_mp, *t_mp; 417 static fn_t f = "sbd_post_detach_mem"; 418 419 PR_MEM("%s...\n", f); 420 421 sbp = SBDH2BD(hp->h_sbd); 422 423 hdp = sbd_get_sbdp_handle(sbp, hp); 424 425 426 rv = 0; 427 for (d = 0; d < devnum; d++) { 428 sbderror_t *ep; 429 dev_info_t *dip; 430 int unit; 431 432 /* sbd_get_devlist will not devlist element w/ dip of 0 */ 433 ASSERT(devlist[d].dv_dip != NULL); 434 435 ep = &devlist[d].dv_error; 436 if ((SBD_GET_ERR(SBD_HD2ERR(hp)) != 0) || 437 (sbd_set_err_in_hdl(hp, ep) == 0)) { 438 rv = -1; 439 } 440 441 dip = devlist[d].dv_dip; 442 unit = sbdp_get_unit_num(hdp, dip); 443 if (unit == -1) { 444 if (hp->h_flags & SBD_IOCTL_FLAG_FORCE) 445 continue; 446 else { 447 if (rv != -1) 448 SBD_GET_PERR(hdp->h_err, ep); 449 break; 450 } 451 } 452 453 s_mp = SBD_GET_BOARD_MEMUNIT(sbp, unit); 454 455 ASSERT(s_mp->sbm_cm.sbdev_sbp == sbp); 456 457 if (rv == -1) { 458 if (s_mp->sbm_flags & SBD_MFLAG_SOURCE) { 459 t_mp = s_mp->sbm_peer; 460 } else { 461 /* this is no target unit */ 462 t_mp = NULL; 463 } 464 465 sbd_mem_cleanup(s_mp, t_mp, ep); 466 } else if (sbd_post_detach_mem_unit(s_mp, ep)) 467 rv = -1; 468 } 469 470 sbd_release_sbdp_handle(hdp); 471 return (rv); 472 } 473 474 static void 475 sbd_add_memory_spans(sbd_board_t *sbp, struct memlist *ml) 476 { 477 sbdp_handle_t *hdp; 478 static fn_t f = "sbd_add_memory_spans"; 479 480 PR_MEM("%s...", f); 481 SBD_MEMLIST_DUMP(ml); 482 483 #ifdef DEBUG 484 memlist_read_lock(); 485 if (memlist_intersect(phys_install, ml)) { 486 PR_MEM("%s:WARNING: memlist intersects with phys_install\n", f); 487 } 488 memlist_read_unlock(); 489 #endif 490 hdp = sbd_get_sbdp_handle(NULL, NULL); 491 492 for (; ml; ml = ml->next) { 493 update_membounds_t umb; 494 pfn_t base; 495 pgcnt_t npgs; 496 int rv; 497 498 base = _b64top(ml->address); 499 npgs = _b64top(ml->size); 500 501 umb.u_board = sbp->sb_num; 502 umb.u_base = (uint64_t)base << MMU_PAGESHIFT; 503 umb.u_len = (uint64_t)npgs << MMU_PAGESHIFT; 504 505 lgrp_plat_config(LGRP_CONFIG_MEM_ADD, (uintptr_t)&umb); 506 rv = kphysm_add_memory_dynamic(base, npgs); 507 508 (void) sbdp_mem_add_span(hdp, ml->address, ml->size); 509 510 if (rv != KPHYSM_OK) { 511 cmn_err(CE_WARN, "sbd:%s:" 512 " unexpected kphysm_add_memory_dynamic" 513 " return value %d;" 514 " basepfn=0x%lx, npages=%ld\n", 515 f, rv, base, npgs); 516 517 continue; 518 } 519 rv = kcage_range_add(base, npgs, KCAGE_DOWN); 520 if (rv != 0) 521 continue; 522 } 523 sbd_release_sbdp_handle(hdp); 524 } 525 526 /* hack for test scripts. *** remove before code finalized *** */ 527 int sbd_last_target; 528 529 static int 530 sbd_post_detach_mem_unit(sbd_mem_unit_t *s_mp, sbderror_t *ep) 531 { 532 uint64_t sz; 533 uint64_t sm; 534 uint64_t t_basepa; 535 uint64_t tmp_basepa; 536 uint64_t s_basepa; 537 sbd_board_t *sbp; 538 sbdp_handle_t *hdp; 539 uint64_t s_nbytes; 540 uint64_t s_new_basepa; 541 sbd_mem_unit_t *t_mp, *x_mp; 542 struct memlist *ml; 543 int rv; 544 static fn_t f = "sbd_post_detach_mem_unit"; 545 sbd_handle_t *hp; 546 547 PR_MEM("%s...\n", f); 548 549 sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp; 550 hp = MACHBD2HD(sbp); 551 hdp = sbd_get_sbdp_handle(sbp, hp); 552 553 if (sbdp_get_mem_alignment(hdp, s_mp->sbm_cm.sbdev_dip, &sz)) { 554 cmn_err(CE_WARN, 555 "sbd:%s: no alignment for mem-unit (%d.%d)", 556 f, sbp->sb_num, s_mp->sbm_cm.sbdev_unum); 557 SBD_GET_PERR(hdp->h_err, ep); 558 sbd_release_sbdp_handle(hdp); 559 return (-1); 560 } 561 sm = sz - 1; 562 563 /* s_mp->sbm_del_mlist could be NULL, meaning no deleted spans */ 564 PR_MEM("%s: brd %d: deleted memlist (EMPTY maybe okay):\n", 565 f, sbp->sb_num); 566 SBD_MEMLIST_DUMP(s_mp->sbm_del_mlist); 567 568 /* sanity check */ 569 ASSERT(s_mp->sbm_del_mlist == NULL || 570 (s_mp->sbm_flags & SBD_MFLAG_RELDONE) != 0); 571 572 if (s_mp->sbm_flags & SBD_MFLAG_SOURCE) { 573 t_mp = s_mp->sbm_peer; 574 575 ASSERT(t_mp != NULL); 576 ASSERT(t_mp->sbm_flags & SBD_MFLAG_TARGET); 577 ASSERT(t_mp->sbm_peer == s_mp); 578 579 ASSERT(t_mp->sbm_flags & SBD_MFLAG_RELDONE); 580 ASSERT(t_mp->sbm_del_mlist); 581 582 sbp = (sbd_board_t *)t_mp->sbm_cm.sbdev_sbp; 583 PR_MEM("%s: target brd %d: deleted memlist:\n", 584 f, sbp->sb_num); 585 SBD_MEMLIST_DUMP(t_mp->sbm_del_mlist); 586 } else { 587 /* this is no target unit */ 588 t_mp = NULL; 589 } 590 591 /* 592 * Verify the memory really did successfully detach 593 * by checking for its non-existence in phys_install. 594 */ 595 rv = 0; 596 memlist_read_lock(); 597 if (s_mp->sbm_flags & SBD_MFLAG_RELDONE) { 598 x_mp = s_mp; 599 rv = memlist_intersect(phys_install, x_mp->sbm_del_mlist); 600 } 601 if (rv == 0 && t_mp && (t_mp->sbm_flags & SBD_MFLAG_RELDONE)) { 602 x_mp = t_mp; 603 rv = memlist_intersect(phys_install, x_mp->sbm_del_mlist); 604 } 605 memlist_read_unlock(); 606 607 if (rv) { 608 sbp = (sbd_board_t *)x_mp->sbm_cm.sbdev_sbp; 609 610 cmn_err(CE_WARN, 611 "%s: %smem-unit (%d.%d) memlist still in phys_install", 612 f, 613 x_mp == t_mp ? "target " : "", 614 sbp->sb_num, 615 x_mp->sbm_cm.sbdev_unum); 616 SBD_SET_ERR(ep, ESBD_INTERNAL); 617 SBD_SET_ERRSTR(ep, sbp->sb_mempath[x_mp->sbm_cm.sbdev_unum]); 618 sbd_release_sbdp_handle(hdp); 619 return (-1); 620 } 621 622 s_basepa = _ptob64(s_mp->sbm_basepfn); 623 s_nbytes = _ptob64(s_mp->sbm_npages); 624 625 if (t_mp != NULL) { 626 t_basepa = _ptob64(t_mp->sbm_basepfn); 627 s_new_basepa = (s_basepa & ~ sm) + 628 _ptob64(t_mp->sbm_slice_offset); 629 630 /* 631 * We had to swap mem-units, so update 632 * memlists accordingly with new base 633 * addresses. 634 */ 635 for (ml = t_mp->sbm_mlist; ml; ml = ml->next) { 636 ml->address -= t_basepa; 637 ml->address += s_new_basepa; 638 } 639 640 /* 641 * There is no need to explicitly rename the target delete 642 * memlist, because sbm_del_mlist and sbm_mlist always 643 * point to the same memlist for a copy/rename operation. 644 */ 645 ASSERT(t_mp->sbm_del_mlist == t_mp->sbm_mlist); 646 647 PR_MEM("%s: renamed target memlist and delete memlist", f); 648 SBD_MEMLIST_DUMP(t_mp->sbm_mlist); 649 650 for (ml = s_mp->sbm_mlist; ml; ml = ml->next) { 651 ml->address -= s_basepa; 652 ml->address += t_basepa; 653 } 654 655 PR_MEM("%s: renamed source memlist", f); 656 SBD_MEMLIST_DUMP(s_mp->sbm_mlist); 657 658 #ifdef DEBUG 659 ASSERT(s_mp->sbm_mlist != s_mp->sbm_del_mlist); 660 /* 661 * Renaming s_mp->sbm_del_mlist is not necessary. This 662 * list is not used beyond this point, and in fact, is 663 * disposed of at the end of this function. 664 */ 665 for (ml = s_mp->sbm_del_mlist; ml; ml = ml->next) { 666 ml->address -= s_basepa; 667 ml->address += t_basepa; 668 } 669 670 PR_MEM("%s: renamed source delete memlist", f); 671 SBD_MEMLIST_DUMP(s_mp->sbm_del_mlist); 672 #endif 673 674 if (s_mp->sbm_flags & SBD_MFLAG_MEMUPSIZE) { 675 struct memlist *nl; 676 int mlret; 677 678 /* 679 * We had to perform a copy-rename from a 680 * small memory node to a big memory node. 681 * Need to add back the remaining memory on 682 * the big board that wasn't used by that 683 * from the small board during the copy. 684 * Subtract out the portion of the target memory 685 * node that was taken over by the source memory 686 * node. 687 */ 688 nl = memlist_dup(t_mp->sbm_mlist); 689 mlret = memlist_delete_span(s_basepa, s_nbytes, &nl); 690 PR_MEM("%s: mlret = %d\n", f, mlret); 691 692 sbp = (sbd_board_t *)t_mp->sbm_cm.sbdev_sbp; 693 PR_MEM("%s: adding back remaining portion" 694 " of mem-unit (%d.%d), memlist:\n", 695 f, sbp->sb_num, 696 t_mp->sbm_cm.sbdev_unum); 697 698 SBD_MEMLIST_DUMP(nl); 699 700 sbd_add_memory_spans(sbp, nl); 701 702 memlist_delete(nl); 703 } 704 } 705 706 707 if (t_mp != NULL) { 708 sbp = (sbd_board_t *)t_mp->sbm_cm.sbdev_sbp; 709 hdp->h_board = sbp->sb_num; 710 /* delete target's entire address space */ 711 tmp_basepa = t_basepa & ~ sm; 712 rv = sbdp_mem_del_span(hdp, tmp_basepa, sz); 713 ASSERT(rv == 0); 714 715 sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp; 716 hdp->h_board = sbp->sb_num; 717 tmp_basepa = s_basepa & ~ sm; 718 sz = s_new_basepa & sm; 719 /* delete source board's vacant address space */ 720 rv = sbdp_mem_del_span(hdp, tmp_basepa, sz); 721 ASSERT(rv == 0); 722 } else { 723 sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp; 724 hdp->h_board = sbp->sb_num; 725 tmp_basepa = s_basepa & ~ sm; 726 /* delete board's entire address space */ 727 rv = sbdp_mem_del_span(hdp, tmp_basepa, sz); 728 ASSERT(rv == 0); 729 } 730 731 #ifdef LINT 732 rv = rv; 733 #endif 734 735 sbd_mem_cleanup(s_mp, t_mp, ep); 736 737 sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp; 738 PR_MEM("%s: board %d's memlist:", f, sbp->sb_num); 739 SBD_MEMLIST_DUMP(s_mp->sbm_mlist); 740 741 sbd_release_sbdp_handle(hdp); 742 return (0); 743 } 744 745 static void 746 sbd_mem_cleanup(sbd_mem_unit_t *s_mp, sbd_mem_unit_t *t_mp, sbderror_t *ep) 747 { 748 sbd_board_t *sbp; 749 750 /* clean up target mem unit */ 751 if (t_mp != NULL) { 752 sbp = (sbd_board_t *)t_mp->sbm_cm.sbdev_sbp; 753 754 ASSERT(t_mp->sbm_del_mlist == t_mp->sbm_mlist); 755 /* 756 * sbm_del_mlist and sbm_mlist point at the same list 757 * We only need to delete one and then set both pointers 758 * to NULL 759 */ 760 memlist_delete(t_mp->sbm_del_mlist); 761 762 t_mp->sbm_del_mlist = NULL; 763 t_mp->sbm_mlist = NULL; 764 t_mp->sbm_peer = NULL; 765 t_mp->sbm_flags = 0; 766 t_mp->sbm_cm.sbdev_busy = 0; 767 sbd_init_mem_unit_data(t_mp, ep); 768 769 /* 770 * now that copy/rename has completed, undo this 771 * work that was done in sbd_release_mem_done. 772 */ 773 /* 774 * If error don't set the target to configured 775 */ 776 if (SBD_GET_ERR(ep) == 0) { 777 SBD_DEV_CLR_UNREFERENCED(sbp, SBD_COMP_MEM, 0); 778 SBD_DEV_CLR_RELEASED(sbp, SBD_COMP_MEM, 0); 779 SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, 0, 780 SBD_STATE_CONFIGURED); 781 } 782 783 /* hack for test scripts. *** remove before code finalized *** */ 784 sbd_last_target = sbp->sb_num; 785 } 786 787 /* 788 * clean up (source) board's mem unit structure. 789 * NOTE: sbm_mlist is retained. It is referred to as the 790 * cached memlist. The cached memlist is used to re-attach 791 * (configure back in) this memunit from the unconfigured 792 * state. 793 */ 794 if (s_mp != NULL) { 795 sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp; 796 797 /* 798 * Don't want to call memlist_delete for sbm_del_mlist, 799 * since that list points to the sbm_list 800 */ 801 s_mp->sbm_del_mlist = NULL; 802 s_mp->sbm_peer = NULL; 803 s_mp->sbm_flags = 0; 804 s_mp->sbm_cm.sbdev_busy = 0; 805 sbd_init_mem_unit_data(s_mp, ep); 806 } 807 } 808 809 /* 810 * Successful return from this function will have the memory 811 * handle in sbp->sb_dev[..mem-unit...].sbm_memhandle allocated 812 * and waiting. This routine's job is to select the memory that 813 * actually has to be released (detached) which may not necessarily 814 * be the same memory node that came in in devlist[], 815 * i.e. a copy-rename is needed. 816 */ 817 int 818 sbd_pre_release_mem(sbd_handle_t *hp, sbd_devlist_t devlist[], int devnum) 819 { 820 extern int kcage_on; 821 int d; 822 int err_flag = 0; 823 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 824 sbderror_t *ep = SBD_HD2ERR(hp); 825 sbderror_t *lep; 826 static fn_t f = "sbd_pre_release_mem"; 827 828 PR_MEM("%s...\n", f); 829 830 if (kcage_on == 0) { 831 /* 832 * Can't Detach memory if Cage is OFF. 833 */ 834 cmn_err(CE_WARN, "%s: kernel cage is disabled", f); 835 SBD_SET_ERR(ep, ESBD_KCAGE_OFF); 836 return (-1); 837 } 838 839 for (d = 0; d < devnum; d++) { 840 int rv; 841 memquery_t mq; 842 sbd_mem_unit_t *mp; 843 struct memlist *ml; 844 845 /* sbd_get_devlist will not devlist element w/ dip of 0 */ 846 ASSERT(devlist[d].dv_dip != NULL); 847 848 mp = SBD_GET_BOARD_MEMUNIT(sbp, d); 849 850 /* 851 * If all the mem unit is marked as failed then don't allow the 852 * operation 853 */ 854 if (mp->sbm_cm.sbdev_cond == SBD_COND_FAILED) { 855 SBD_SET_ERR(ep, ESBD_STATE); 856 SBD_SET_ERRSTR(ep, sbp->sb_mempath[d]); 857 err_flag = -1; 858 break; 859 } 860 861 ASSERT(d == mp->sbm_cm.sbdev_unum); 862 863 /* 864 * if interleave is set to across boards fail the op 865 */ 866 if (mp->sbm_interleave) { 867 SBD_SET_ERR(ep, ESBD_MEMINTLV); 868 SBD_SET_ERRSTR(ep, sbp->sb_mempath[d]); 869 err_flag = -1; 870 break; 871 } 872 873 lep = &devlist[d].dv_error; 874 if (SBD_GET_ERR(lep) != 0) { 875 err_flag = -1; 876 (void) sbd_set_err_in_hdl(hp, lep); 877 break; 878 } 879 880 if (mp->sbm_flags & SBD_MFLAG_RESERVED) { 881 /* 882 * Board is currently involved in a delete 883 * memory operation. Can't detach this guy until 884 * that operation completes. 885 */ 886 cmn_err(CE_WARN, 887 "%s: ineligible mem-unit (%d.%d) for detach", 888 f, sbp->sb_num, 889 mp->sbm_cm.sbdev_unum); 890 891 SBD_SET_ERR(lep, ESBD_INVAL); 892 SBD_SET_ERRSTR(lep, sbp->sb_mempath[d]); 893 (void) sbd_set_err_in_hdl(hp, lep); 894 err_flag = -1; 895 break; 896 } 897 898 /* 899 * Check whether the detaching memory requires a 900 * copy-rename. 901 */ 902 ASSERT(mp->sbm_npages != 0); 903 rv = kphysm_del_span_query( 904 mp->sbm_basepfn, mp->sbm_npages, &mq); 905 if (rv != KPHYSM_OK) { 906 cmn_err(CE_WARN, 907 "%s: unexpected kphysm_del_span_query" 908 " return value %d;" 909 " basepfn 0x%lx, npages 0x%lx," 910 " mem-unit (%d.%d), dip 0x%p", 911 f, 912 rv, 913 mp->sbm_basepfn, 914 mp->sbm_npages, 915 sbp->sb_num, 916 mp->sbm_cm.sbdev_unum, 917 (void *)mp->sbm_cm.sbdev_dip); 918 919 SBD_SET_ERR(lep, ESBD_INTERNAL); 920 SBD_SET_ERRSTR(lep, sbp->sb_mempath[d]); 921 (void) sbd_set_err_in_hdl(hp, lep); 922 err_flag = -1; 923 break; 924 } 925 926 if (mq.nonrelocatable != 0) { 927 if (!(hp->h_iap->i_flags & SBD_FLAG_QUIESCE_OKAY)) { 928 /* caller wasn't prompted for a suspend */ 929 SBD_SET_ERR(lep, ESBD_QUIESCE_REQD); 930 SBD_SET_ERRSTR(lep, sbp->sb_mempath[d]); 931 (void) sbd_set_err_in_hdl(hp, lep); 932 err_flag = 1; 933 break; 934 } 935 } 936 937 /* flags should be clean at this time */ 938 ASSERT(mp->sbm_flags == 0); 939 940 ASSERT(mp->sbm_del_mlist == NULL); /* should be null */ 941 942 if (mp->sbm_mlist != NULL) { 943 memlist_delete(mp->sbm_mlist); 944 mp->sbm_mlist = NULL; 945 } 946 947 ml = sbd_get_memlist(mp, lep); 948 (void) sbd_set_err_in_hdl(hp, lep); 949 if (ml == NULL) { 950 PR_MEM("%s: no memlist found for board %d\n", 951 f, sbp->sb_num); 952 err_flag = -1; 953 break; 954 } 955 956 /* allocate a kphysm handle */ 957 rv = kphysm_del_gethandle(&mp->sbm_memhandle); 958 if (rv != KPHYSM_OK) { 959 memlist_delete(ml); 960 961 cmn_err(CE_WARN, 962 "%s: unexpected kphysm_del_gethandle" 963 " return value %d", f, rv); 964 965 SBD_SET_ERR(lep, ESBD_INTERNAL); 966 SBD_SET_ERRSTR(lep, sbp->sb_mempath[d]); 967 (void) sbd_set_err_in_hdl(hp, lep); 968 err_flag = -1; 969 break; 970 } 971 mp->sbm_flags |= SBD_MFLAG_RELOWNER; 972 973 if ((mq.nonrelocatable != 0) || 974 sbd_reserve_mem_spans(&mp->sbm_memhandle, ml)) { 975 /* 976 * Either the detaching memory node contains 977 * non-reloc memory or we failed to reserve the 978 * detaching memory node (which did _not_ have 979 * any non-reloc memory, i.e. some non-reloc mem 980 * got onboard). 981 */ 982 983 if (sbd_select_mem_target(hp, mp, ml)) { 984 int rv; 985 986 /* 987 * We had no luck locating a target 988 * memory node to be the recipient of 989 * the non-reloc memory on the node 990 * we're trying to detach. 991 * Clean up be disposing the mem handle 992 * and the mem list. 993 */ 994 rv = kphysm_del_release(mp->sbm_memhandle); 995 if (rv != KPHYSM_OK) { 996 /* 997 * can do nothing but complain 998 * and hope helpful for debug 999 */ 1000 cmn_err(CE_WARN, "sbd:%s: unexpected" 1001 " kphysm_del_release return" 1002 " value %d", 1003 f, rv); 1004 } 1005 mp->sbm_flags &= ~SBD_MFLAG_RELOWNER; 1006 1007 memlist_delete(ml); 1008 1009 /* make sure sbm_flags is clean */ 1010 ASSERT(mp->sbm_flags == 0); 1011 1012 cmn_err(CE_WARN, 1013 "%s: no available target for " 1014 "mem-unit (%d.%d)", 1015 f, sbp->sb_num, 1016 mp->sbm_cm.sbdev_unum); 1017 1018 SBD_SET_ERR(lep, ESBD_NO_TARGET); 1019 SBD_SET_ERRSTR(lep, 1020 sbp->sb_mempath[mp->sbm_cm.sbdev_unum]); 1021 (void) sbd_set_err_in_hdl(hp, lep); 1022 1023 err_flag = -1; 1024 break; 1025 } 1026 1027 /* 1028 * ml is not memlist_deleted here because 1029 * it has been assigned to mp->sbm_mlist 1030 * by sbd_select_mem_target. 1031 */ 1032 } else { 1033 /* no target needed to detach this board */ 1034 mp->sbm_flags |= SBD_MFLAG_RESERVED; 1035 mp->sbm_peer = NULL; 1036 mp->sbm_del_mlist = ml; 1037 mp->sbm_mlist = ml; 1038 mp->sbm_cm.sbdev_busy = 1; 1039 } 1040 #ifdef DEBUG 1041 ASSERT(mp->sbm_mlist != NULL); 1042 1043 if (mp->sbm_flags & SBD_MFLAG_SOURCE) { 1044 int src, targ; 1045 1046 sbp = (sbd_board_t *) 1047 mp->sbm_peer->sbm_cm.sbdev_sbp; 1048 targ = sbp->sb_num; 1049 sbp = (sbd_board_t *)mp->sbm_cm.sbdev_sbp; 1050 src = sbp->sb_num; 1051 PR_MEM("%s: release of board %d requires copy/rename;" 1052 " selected target board %d\n", 1053 f, src, targ); 1054 } else { 1055 sbp = (sbd_board_t *)mp->sbm_cm.sbdev_sbp; 1056 PR_MEM("%s: copy/rename not required to release" 1057 " board %d\n", f, sbp->sb_num); 1058 } 1059 1060 ASSERT(mp->sbm_flags & SBD_MFLAG_RELOWNER); 1061 ASSERT(mp->sbm_flags & SBD_MFLAG_RESERVED); 1062 #endif 1063 } 1064 1065 return (err_flag); 1066 } 1067 1068 void 1069 sbd_release_mem_done(sbd_handle_t *hp, int unit) 1070 { 1071 sbd_mem_unit_t *s_mp, *t_mp, *mp; 1072 sbderror_t *ep = SBD_HD2ERR(hp); 1073 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 1074 int rv; 1075 static fn_t f = "sbd_release_mem_done"; 1076 1077 s_mp = SBD_GET_BOARD_MEMUNIT(sbp, unit); 1078 sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp; 1079 1080 /* 1081 * This unit will be flagged with SBD_MFLAG_SOURCE, if it 1082 * has a target unit. 1083 */ 1084 if (s_mp->sbm_flags & SBD_MFLAG_SOURCE) { 1085 t_mp = s_mp->sbm_peer; 1086 ASSERT(t_mp != NULL); 1087 ASSERT(t_mp->sbm_peer == s_mp); 1088 ASSERT(t_mp->sbm_flags & SBD_MFLAG_TARGET); 1089 ASSERT(t_mp->sbm_flags & SBD_MFLAG_RESERVED); 1090 } else { 1091 /* this is no target unit */ 1092 t_mp = NULL; 1093 } 1094 1095 /* free delete handle */ 1096 ASSERT(s_mp->sbm_flags & SBD_MFLAG_RELOWNER); 1097 ASSERT(s_mp->sbm_flags & SBD_MFLAG_RESERVED); 1098 1099 rv = kphysm_del_release(s_mp->sbm_memhandle); 1100 if (rv != KPHYSM_OK) { 1101 /* 1102 * can do nothing but complain 1103 * and hope helpful for debug 1104 */ 1105 cmn_err(CE_WARN, "sbd:%s: unexpected kphysm_del_release" 1106 " return value %d", f, rv); 1107 } 1108 s_mp->sbm_flags &= ~SBD_MFLAG_RELOWNER; 1109 1110 /* 1111 * If an error was encountered during release, clean up 1112 * the source (and target, if present) unit data. 1113 */ 1114 if (SBD_GET_ERR(ep) != 0) { 1115 1116 PR_MEM("%s: unit %d.%d: error %d noted\n", 1117 f, sbp->sb_num, 1118 s_mp->sbm_cm.sbdev_unum, 1119 SBD_GET_ERR(ep)); 1120 1121 sbd_mem_cleanup(s_mp, t_mp, ep); 1122 1123 /* bail out */ 1124 return; 1125 } 1126 1127 SBD_DEV_SET_RELEASED(sbp, SBD_COMP_MEM, unit); 1128 SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, unit, SBD_STATE_RELEASE); 1129 1130 if (t_mp != NULL) { 1131 sbp = (sbd_board_t *)t_mp->sbm_cm.sbdev_sbp; 1132 /* 1133 * the kphysm delete operation that drained the source 1134 * board also drained this target board. Since the source 1135 * board drain is now known to have succeeded, we know this 1136 * target board is drained too. 1137 */ 1138 SBD_DEV_SET_RELEASED(sbp, SBD_COMP_MEM, 1139 t_mp->sbm_cm.sbdev_unum); 1140 SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, 1141 t_mp->sbm_cm.sbdev_unum, 1142 SBD_STATE_RELEASE); 1143 1144 /* 1145 * NOTE: do not transition target's board state, 1146 * even if the mem-unit was the last configure 1147 * unit of the board. When copy/rename completes 1148 * this mem-unit will transitioned back to 1149 * the configured state. In the meantime, the 1150 * board's must remain as is. 1151 */ 1152 } 1153 1154 /* if board(s) had deleted memory, verify it is gone */ 1155 rv = 0; 1156 memlist_read_lock(); 1157 if (s_mp->sbm_del_mlist != NULL) { 1158 sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp; 1159 mp = s_mp; 1160 rv = memlist_intersect(phys_install, mp->sbm_del_mlist); 1161 } 1162 if (rv == 0 && t_mp && t_mp->sbm_del_mlist != NULL) { 1163 sbp = (sbd_board_t *)t_mp->sbm_cm.sbdev_sbp; 1164 mp = t_mp; 1165 rv = memlist_intersect(phys_install, mp->sbm_del_mlist); 1166 } 1167 memlist_read_unlock(); 1168 if (rv) { 1169 cmn_err(CE_WARN, "sbd:%s: %smem-unit (%d.%d): " 1170 "deleted memory still found in phys_install", 1171 f, 1172 (mp == t_mp ? "target " : ""), 1173 sbp->sb_num, 1174 mp->sbm_cm.sbdev_unum); 1175 1176 SBD_SET_ERR(ep, ESBD_INTERNAL); 1177 SBD_SET_ERRSTR(ep, sbp->sb_mempath[mp->sbm_cm.sbdev_unum]); 1178 return; 1179 } 1180 1181 s_mp->sbm_flags |= SBD_MFLAG_RELDONE; 1182 if (t_mp != NULL) { 1183 t_mp->sbm_flags &= ~SBD_MFLAG_RESERVED; 1184 t_mp->sbm_flags |= SBD_MFLAG_RELDONE; 1185 } 1186 1187 sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp; 1188 1189 SBD_DEV_SET_UNREFERENCED(sbp, SBD_COMP_MEM, unit); 1190 SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, unit, SBD_STATE_UNREFERENCED); 1191 1192 PR_MEM("%s: marking mem-unit (%d.%d) release DONE\n", 1193 f, sbp->sb_num, 1194 s_mp->sbm_cm.sbdev_unum); 1195 1196 s_mp->sbm_cm.sbdev_ostate = SBD_STAT_UNCONFIGURED; 1197 1198 if (t_mp != NULL) { 1199 sbp = (sbd_board_t *)t_mp->sbm_cm.sbdev_sbp; 1200 1201 SBD_DEV_SET_UNREFERENCED(sbp, SBD_COMP_MEM, 1202 t_mp->sbm_cm.sbdev_unum); 1203 SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, 1204 t_mp->sbm_cm.sbdev_unum, 1205 SBD_STATE_UNREFERENCED); 1206 1207 sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp; 1208 1209 PR_MEM("%s: marking mem-unit (%d.%d) release DONE\n", 1210 f, sbp->sb_num, 1211 t_mp->sbm_cm.sbdev_unum); 1212 1213 t_mp->sbm_cm.sbdev_ostate = SBD_STAT_UNCONFIGURED; 1214 } 1215 } 1216 1217 int 1218 sbd_disconnect_mem(sbd_handle_t *hp, int unit) 1219 { 1220 static fn_t f = "sbd_disconnect_mem"; 1221 sbd_mem_unit_t *mp; 1222 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 1223 1224 mp = SBD_GET_BOARD_MEMUNIT(sbp, unit); 1225 1226 ASSERT(mp->sbm_cm.sbdev_state == SBD_STATE_CONNECTED || 1227 mp->sbm_cm.sbdev_state == SBD_STATE_UNCONFIGURED); 1228 1229 PR_MEM("%s...\n", f); 1230 1231 if (mp->sbm_del_mlist && mp->sbm_del_mlist != mp->sbm_mlist) 1232 memlist_delete(mp->sbm_del_mlist); 1233 mp->sbm_del_mlist = NULL; 1234 1235 if (mp->sbm_mlist) { 1236 memlist_delete(mp->sbm_mlist); 1237 mp->sbm_mlist = NULL; 1238 } 1239 1240 return (0); 1241 } 1242 1243 int 1244 sbd_cancel_mem(sbd_handle_t *hp, int unit) 1245 { 1246 sbd_mem_unit_t *s_mp, *t_mp; 1247 sbd_istate_t state; 1248 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 1249 sbd_board_t *tsbp; 1250 static fn_t f = "sbd_cancel_mem"; 1251 sbderror_t *ep = SBD_HD2ERR(hp); 1252 1253 s_mp = SBD_GET_BOARD_MEMUNIT(sbp, unit); 1254 1255 state = s_mp->sbm_cm.sbdev_state; 1256 1257 if (s_mp->sbm_flags & SBD_MFLAG_TARGET) { 1258 /* must cancel source board, not target board */ 1259 SBD_SET_ERR(ep, ESBD_INTERNAL); 1260 SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]); 1261 return (-1); 1262 } else if (s_mp->sbm_flags & SBD_MFLAG_SOURCE) { 1263 t_mp = s_mp->sbm_peer; 1264 tsbp = t_mp->sbm_cm.sbdev_sbp; 1265 ASSERT(t_mp != NULL); 1266 ASSERT(t_mp->sbm_peer == s_mp); 1267 1268 /* must always match the source board's state */ 1269 ASSERT(t_mp->sbm_cm.sbdev_state == state); 1270 } else { 1271 /* this is no target unit */ 1272 t_mp = NULL; 1273 } 1274 1275 switch (state) { 1276 case SBD_STATE_UNREFERENCED: /* state set by sbd_release_mem_done */ 1277 ASSERT((s_mp->sbm_flags & SBD_MFLAG_RELOWNER) == 0); 1278 1279 if (t_mp != NULL && t_mp->sbm_del_mlist != NULL) { 1280 PR_MEM("%s: undoing target board %d memory delete\n", 1281 f, tsbp->sb_num); 1282 sbd_add_memory_spans(tsbp, t_mp->sbm_del_mlist); 1283 SBD_DEV_CLR_UNREFERENCED(tsbp, SBD_COMP_MEM, 1284 t_mp->sbm_cm.sbdev_unum); 1285 } 1286 1287 if (s_mp->sbm_del_mlist != NULL) { 1288 PR_MEM("%s: undoing board %d memory delete\n", 1289 f, sbp->sb_num); 1290 sbd_add_memory_spans(sbp, s_mp->sbm_del_mlist); 1291 } 1292 1293 /*FALLTHROUGH*/ 1294 1295 case SBD_STATE_CONFIGURED: 1296 /* 1297 * we got here because of an error early in the release process 1298 * Just leave the memory as is and report the error 1299 */ 1300 1301 ASSERT((s_mp->sbm_flags & SBD_MFLAG_RELOWNER) == 0); 1302 1303 if (t_mp != NULL) { 1304 ASSERT(t_mp->sbm_del_mlist == t_mp->sbm_mlist); 1305 t_mp->sbm_del_mlist = NULL; 1306 1307 if (t_mp->sbm_mlist != NULL) { 1308 memlist_delete(t_mp->sbm_mlist); 1309 t_mp->sbm_mlist = NULL; 1310 } 1311 1312 t_mp->sbm_peer = NULL; 1313 t_mp->sbm_flags = 0; 1314 t_mp->sbm_cm.sbdev_busy = 0; 1315 sbd_init_mem_unit_data(t_mp, ep); 1316 1317 SBD_DEV_CLR_RELEASED(tsbp, SBD_COMP_MEM, 1318 t_mp->sbm_cm.sbdev_unum); 1319 1320 SBD_DEVICE_TRANSITION(tsbp, SBD_COMP_MEM, 1321 t_mp->sbm_cm.sbdev_unum, 1322 SBD_STATE_CONFIGURED); 1323 } 1324 1325 if (s_mp->sbm_del_mlist != s_mp->sbm_mlist) 1326 memlist_delete(s_mp->sbm_del_mlist); 1327 s_mp->sbm_del_mlist = NULL; 1328 1329 if (s_mp->sbm_mlist != NULL) { 1330 memlist_delete(s_mp->sbm_mlist); 1331 s_mp->sbm_mlist = NULL; 1332 } 1333 1334 s_mp->sbm_peer = NULL; 1335 s_mp->sbm_flags = 0; 1336 s_mp->sbm_cm.sbdev_busy = 0; 1337 sbd_init_mem_unit_data(s_mp, ep); 1338 1339 return (0); 1340 default: 1341 PR_MEM("%s: WARNING unexpected state (%d) for " 1342 "mem-unit %d.%d\n", 1343 f, 1344 (int)state, 1345 sbp->sb_num, 1346 s_mp->sbm_cm.sbdev_unum); 1347 1348 return (-1); 1349 } 1350 /*NOTREACHED*/ 1351 } 1352 1353 void 1354 sbd_init_mem_unit(sbd_board_t *sbp, int unit, sbderror_t *ep) 1355 { 1356 sbd_istate_t new_state; 1357 sbd_mem_unit_t *mp; 1358 dev_info_t *cur_mc_dip; 1359 int failed_mcs = 0, present_mcs = 0; 1360 sbd_cond_t mc_cond; 1361 int i; 1362 1363 mp = SBD_GET_BOARD_MEMUNIT(sbp, unit); 1364 1365 if (SBD_DEV_IS_ATTACHED(sbp, SBD_COMP_MEM, unit)) { 1366 new_state = SBD_STATE_CONFIGURED; 1367 } else if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_MEM, unit)) { 1368 new_state = SBD_STATE_CONNECTED; 1369 } else if (mp->sbm_cm.sbdev_dip != NULL) { 1370 new_state = SBD_STATE_OCCUPIED; 1371 } else { 1372 new_state = SBD_STATE_EMPTY; 1373 } 1374 1375 /* 1376 * Check all the possible memory nodes on the board. If all of them 1377 * have a failed status mark memory as failed. Otherwise mem is ok 1378 */ 1379 if (!sbp->sb_memaccess_ok) { 1380 mp->sbm_cm.sbdev_cond = SBD_COND_UNKNOWN; 1381 return; 1382 } 1383 1384 for (i = 0; i < SBD_NUM_MC_PER_BOARD; i++) { 1385 cur_mc_dip = mp->sbm_dip[i]; 1386 1387 if (cur_mc_dip == NULL) 1388 continue; 1389 1390 present_mcs |= (1 << i); 1391 1392 mc_cond = sbd_get_comp_cond(cur_mc_dip); 1393 if (mc_cond == SBD_COND_FAILED) { 1394 failed_mcs |= (1 << i); 1395 } 1396 } 1397 1398 if (failed_mcs == present_mcs) { 1399 /* 1400 * All mem nodes failed, therefore mark all mem 1401 * as failed 1402 */ 1403 mp->sbm_cm.sbdev_cond = SBD_COND_FAILED; 1404 } else { 1405 mp->sbm_cm.sbdev_cond = SBD_COND_OK; 1406 } 1407 1408 sbd_init_mem_unit_data(mp, ep); 1409 1410 /* 1411 * Any changes to this memory unit should be performed above 1412 * this call to ensure the unit is fully initialized 1413 * before transitioning to the new state. 1414 */ 1415 SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, unit, new_state); 1416 1417 } 1418 1419 static void 1420 sbd_init_mem_unit_data(sbd_mem_unit_t *mp, sbderror_t *ep) 1421 { 1422 uint64_t basepa; 1423 uint64_t sz; 1424 sbd_board_t *sbp = mp->sbm_cm.sbdev_sbp; 1425 sbdp_handle_t *hdp; 1426 static fn_t f = "sbd_init_mem_unit_data"; 1427 sbd_handle_t *hp = MACHBD2HD(sbp); 1428 1429 PR_MEM("%s...\n", f); 1430 1431 /* a little sanity checking */ 1432 ASSERT(mp->sbm_peer == NULL); 1433 ASSERT(mp->sbm_flags == 0); 1434 1435 hdp = sbd_get_sbdp_handle(sbp, hp); 1436 1437 /* get basepfn of mem unit */ 1438 if (sbdphw_get_base_physaddr(hdp, mp->sbm_cm.sbdev_dip, &basepa)) { 1439 cmn_err(CE_WARN, "sbd:%s: failed to get physaddr" 1440 " for mem-unit (%d.%d)", 1441 f, 1442 sbp->sb_num, 1443 mp->sbm_cm.sbdev_unum); 1444 SBD_GET_PERR(hdp->h_err, ep); 1445 sbd_release_sbdp_handle(hdp); 1446 return; 1447 } 1448 mp->sbm_basepfn = _b64top(basepa); 1449 1450 /* attempt to get number of pages from PDA */ 1451 mp->sbm_npages = sbdp_get_mem_size(hdp); 1452 1453 /* if didn't work, calculate using memlist */ 1454 if (mp->sbm_npages == 0) { 1455 struct memlist *ml, *mlist; 1456 mlist = sbd_get_memlist(mp, ep); 1457 for (ml = mlist; ml; ml = ml->next) 1458 mp->sbm_npages += btop(ml->size); 1459 memlist_delete(mlist); 1460 } 1461 1462 1463 if (sbdp_get_mem_alignment(hdp, mp->sbm_cm.sbdev_dip, &sz)) { 1464 cmn_err(CE_WARN, 1465 "sbd:%s: no alignment for mem-unit (%d.%d)", 1466 f, sbp->sb_num, mp->sbm_cm.sbdev_unum); 1467 SBD_GET_PERR(hdp->h_err, ep); 1468 sbd_release_sbdp_handle(hdp); 1469 return; 1470 } 1471 mp->sbm_alignment_mask = _b64top(sz); 1472 1473 1474 mp->sbm_interleave = sbdp_isinterleaved(hdp, 1475 mp->sbm_cm.sbdev_dip); 1476 1477 PR_MEM("%s: board %d (basepfn = 0x%lx, npgs = 0x%lx interleave %d)\n", 1478 f, sbp->sb_num, 1479 mp->sbm_basepfn, 1480 mp->sbm_npages, 1481 mp->sbm_interleave); 1482 1483 sbd_release_sbdp_handle(hdp); 1484 } 1485 1486 static int 1487 sbd_reserve_mem_spans(memhandle_t *mhp, struct memlist *ml) 1488 { 1489 int err; 1490 pfn_t base; 1491 pgcnt_t npgs; 1492 struct memlist *mc; 1493 static fn_t f = "sbd_reserve_mem_spans"; 1494 1495 PR_MEM("%s...\n", f); 1496 1497 /* 1498 * Walk the supplied memlist scheduling each span for removal 1499 * with kphysm_del_span. It is possible that a span may intersect 1500 * an area occupied by the cage. 1501 */ 1502 for (mc = ml; mc != NULL; mc = mc->next) { 1503 base = _b64top(mc->address); 1504 npgs = _b64top(mc->size); 1505 1506 err = kphysm_del_span(*mhp, base, npgs); 1507 if (err != KPHYSM_OK) { 1508 cmn_err(CE_WARN, "sbd:%s memory reserve failed." 1509 " unexpected kphysm_del_span return value %d;" 1510 " basepfn=0x%lx npages=%ld", 1511 f, err, base, npgs); 1512 return (-1); 1513 } 1514 } 1515 return (0); 1516 } 1517 1518 /* debug counters */ 1519 int sbd_smt_realigned; 1520 int sbd_smt_preference[4]; 1521 1522 #ifdef DEBUG 1523 uint_t sbd_ignore_board; /* if bit[bnum-1] set, board won't be candidate */ 1524 #endif 1525 1526 /* 1527 * Verify that there is no memory overlapping if copy-rename is 1528 * done with the selected target board. 1529 * 1530 * Returns 0 if OK, -1 otherwise. 1531 */ 1532 static int 1533 sbd_check_boundaries(struct memlist *orig_memlist, sbd_mem_unit_t *s_mp, 1534 sbd_mem_unit_t *t_mp) 1535 { 1536 struct memlist *new_memlist; 1537 int mlret; 1538 static fn_t f = "sbd_check_boundaries"; 1539 1540 new_memlist = memlist_dup(orig_memlist); 1541 if (new_memlist == NULL) { 1542 PR_MEM("%s: can't dup original memlist\n", f); 1543 return (-1); 1544 } 1545 1546 mlret = memlist_delete_span( 1547 _ptob64(s_mp->sbm_basepfn), 1548 _ptob64(s_mp->sbm_npages), 1549 &new_memlist); 1550 if (mlret != MEML_SPANOP_OK) { 1551 PR_MEM("%s: del s/s mlret = %d\n", f, mlret); 1552 goto check_done; 1553 } 1554 1555 mlret = memlist_delete_span( 1556 _ptob64(t_mp->sbm_basepfn), 1557 _ptob64(t_mp->sbm_npages), 1558 &new_memlist); 1559 if (mlret != MEML_SPANOP_OK) { 1560 PR_MEM("%s: del t/t mlret = %d\n", f, mlret); 1561 goto check_done; 1562 } 1563 1564 mlret = memlist_add_span( 1565 _ptob64(t_mp->sbm_basepfn), 1566 _ptob64(s_mp->sbm_npages), 1567 &new_memlist); 1568 if (mlret != MEML_SPANOP_OK) { 1569 PR_MEM("%s: add t/s mlret = %d\n", f, mlret); 1570 goto check_done; 1571 } 1572 1573 mlret = memlist_add_span( 1574 _ptob64(s_mp->sbm_basepfn), 1575 _ptob64(t_mp->sbm_npages), 1576 &new_memlist); 1577 if (mlret != MEML_SPANOP_OK) { 1578 PR_MEM("%s: add s/t mlret = %d\n", f, mlret); 1579 } 1580 1581 check_done: 1582 memlist_delete(new_memlist); 1583 1584 if (mlret == MEML_SPANOP_OK) 1585 return (0); 1586 else 1587 return (-1); 1588 } 1589 1590 /* 1591 * Find and reserve a copy/rename target board suitable for the 1592 * given source board. 1593 * All boards in the system are examined and categorized in relation to 1594 * their memory size versus the source board's memory size. Order of 1595 * preference is: 1596 * 1st: board has same memory size 1597 * 2nd: board has larger memory size 1598 * 3rd: board has smaller memory size 1599 * 4th: board has smaller memory size, available memory will be reduced. 1600 * Boards in category 3 and 4 will have their MC's reprogrammed to locate the 1601 * span to which the MC responds to address span that appropriately covers 1602 * the nonrelocatable span of the source board. 1603 */ 1604 static int 1605 sbd_select_mem_target(sbd_handle_t *hp, 1606 sbd_mem_unit_t *s_mp, struct memlist *s_ml) 1607 { 1608 uint64_t sz; 1609 pgcnt_t sm; 1610 int n_sets = 4; /* same, larger, smaller, clipped */ 1611 int preference; /* lower value is higher preference */ 1612 int n_units_per_set; 1613 int idx; 1614 sbd_mem_unit_t **sets; 1615 sbdp_handle_t *hdp; 1616 int t_bd; 1617 sbd_softstate_t *softsp; 1618 int t_unit; 1619 int max_boards; 1620 int rv; 1621 sbd_board_t *s_sbp, *t_sbp; 1622 sbd_mem_unit_t *t_mp, *c_mp; 1623 struct memlist *d_ml, *t_ml, *x_ml; 1624 memquery_t s_mq = {0}; 1625 static fn_t f = "sbd_select_mem_target"; 1626 1627 PR_MEM("%s...\n", f); 1628 1629 ASSERT(s_ml != NULL); 1630 1631 s_sbp = s_mp->sbm_cm.sbdev_sbp; 1632 1633 hdp = sbd_get_sbdp_handle(s_sbp, hp); 1634 1635 if (sbdp_get_mem_alignment(hdp, s_mp->sbm_cm.sbdev_dip, &sz)) { 1636 sbderror_t *ep = SBD_HD2ERR(hp); 1637 cmn_err(CE_WARN, 1638 "sbd:%s: no alignment for mem-unit (%d.%d)", 1639 f, s_sbp->sb_num, s_mp->sbm_cm.sbdev_unum); 1640 SBD_GET_PERR(hdp->h_err, ep); 1641 sbd_release_sbdp_handle(hdp); 1642 return (-1); 1643 } 1644 sm = sz - 1; 1645 sbd_release_sbdp_handle(hdp); 1646 1647 softsp = (sbd_softstate_t *)s_sbp->sb_softsp; 1648 1649 max_boards = softsp->max_boards; 1650 n_units_per_set = max_boards * MAX_MEM_UNITS_PER_BOARD; 1651 sets = GETSTRUCT(sbd_mem_unit_t *, n_units_per_set * n_sets); 1652 1653 /* 1654 * Make one pass through all memory units on all boards 1655 * and categorize them with respect to the source board. 1656 */ 1657 for (t_bd = 0; t_bd < max_boards; t_bd++) { 1658 /* 1659 * The board structs are a contiguous array 1660 * so we take advantage of that to find the 1661 * correct board struct pointer for a given 1662 * board number. 1663 */ 1664 t_sbp = (sbd_board_t *)softsp->sbd_boardlist; 1665 t_sbp += t_bd; 1666 1667 /* source board can not be its own target */ 1668 if (s_sbp->sb_num == t_sbp->sb_num) 1669 continue; 1670 1671 for (t_unit = 0; t_unit < MAX_MEM_UNITS_PER_BOARD; t_unit++) { 1672 1673 t_mp = SBD_GET_BOARD_MEMUNIT(t_sbp, t_unit); 1674 1675 /* this memory node must be attached */ 1676 if (!SBD_DEV_IS_ATTACHED(t_sbp, SBD_COMP_MEM, t_unit)) 1677 continue; 1678 1679 /* source unit can not be its own target */ 1680 if (s_mp == t_mp) { 1681 /* catch this in debug kernels */ 1682 ASSERT(0); 1683 continue; 1684 } 1685 1686 /* 1687 * this memory node must not already be reserved 1688 * by some other memory delete operation. 1689 */ 1690 if (t_mp->sbm_flags & SBD_MFLAG_RESERVED) 1691 continue; 1692 1693 /* 1694 * categorize the memory node 1695 * If this is a smaller memory node, create a 1696 * temporary, edited copy of the source board's 1697 * memlist containing only the span of the non- 1698 * relocatable pages. 1699 */ 1700 if (t_mp->sbm_npages == s_mp->sbm_npages) { 1701 preference = 0; 1702 t_mp->sbm_slice_offset = 0; 1703 } else if (t_mp->sbm_npages > s_mp->sbm_npages) { 1704 preference = 1; 1705 t_mp->sbm_slice_offset = 0; 1706 } else { 1707 /* 1708 * We do not allow other options right now 1709 */ 1710 continue; 1711 } 1712 1713 sbd_smt_preference[preference]++; 1714 1715 /* calculate index to start of preference set */ 1716 idx = n_units_per_set * preference; 1717 /* calculate offset to respective element */ 1718 idx += t_bd * MAX_MEM_UNITS_PER_BOARD + t_unit; 1719 1720 ASSERT(idx < n_units_per_set * n_sets); 1721 sets[idx] = t_mp; 1722 } 1723 } 1724 1725 /* 1726 * NOTE: this would be a good place to sort each candidate 1727 * set in to some desired order, e.g. memory size in ascending 1728 * order. Without an additional sorting step here, the order 1729 * within a set is ascending board number order. 1730 */ 1731 1732 c_mp = NULL; 1733 x_ml = NULL; 1734 t_ml = NULL; 1735 for (idx = 0; idx < n_units_per_set * n_sets; idx++) { 1736 memquery_t mq; 1737 1738 /* cleanup t_ml after previous pass */ 1739 if (t_ml != NULL) { 1740 memlist_delete(t_ml); 1741 t_ml = NULL; 1742 } 1743 1744 /* get candidate target board mem unit */ 1745 t_mp = sets[idx]; 1746 if (t_mp == NULL) 1747 continue; 1748 1749 t_sbp = t_mp->sbm_cm.sbdev_sbp; 1750 1751 /* get target board memlist */ 1752 t_ml = sbd_get_memlist(t_mp, SBD_HD2ERR(hp)); 1753 if (t_ml == NULL) { 1754 cmn_err(CE_WARN, "sbd:%s: no memlist for" 1755 " mem-unit %d, board %d", 1756 f, 1757 t_sbp->sb_num, 1758 t_mp->sbm_cm.sbdev_unum); 1759 1760 continue; 1761 } 1762 1763 /* get appropriate source board memlist */ 1764 if (t_mp->sbm_npages < s_mp->sbm_npages) { 1765 spgcnt_t excess; 1766 1767 /* 1768 * make a copy of the source board memlist 1769 * then edit it to remove the spans that 1770 * are outside the calculated span of 1771 * [pfn..s_mq.last_nonrelocatable]. 1772 */ 1773 if (x_ml != NULL) 1774 memlist_delete(x_ml); 1775 1776 x_ml = memlist_dup(s_ml); 1777 if (x_ml == NULL) { 1778 PR_MEM("%s: memlist_dup failed\n", f); 1779 /* TODO: should abort */ 1780 continue; 1781 } 1782 1783 /* trim off lower portion */ 1784 excess = t_mp->sbm_slice_offset; 1785 if (excess > 0) { 1786 int mlret; 1787 1788 mlret = memlist_delete_span( 1789 _ptob64(s_mp->sbm_basepfn), 1790 _ptob64(excess), 1791 &x_ml); 1792 PR_MEM("%s: mlret = %d\n", f, mlret); 1793 } 1794 1795 /* 1796 * Since this candidate target board is smaller 1797 * than the source board, s_mq must have been 1798 * initialized in previous loop while processing 1799 * this or some other candidate board. 1800 * FIXME: this is weak. 1801 */ 1802 ASSERT(s_mq.phys_pages != 0); 1803 1804 /* trim off upper portion */ 1805 excess = (s_mp->sbm_basepfn + s_mp->sbm_npages) 1806 - (s_mq.last_nonrelocatable + 1); 1807 if (excess > 0) { 1808 pfn_t p; 1809 int mlret; 1810 1811 p = s_mq.last_nonrelocatable + 1; 1812 p -= excess; 1813 1814 mlret = memlist_delete_span( 1815 _ptob64(p), 1816 _ptob64(excess), 1817 &x_ml); 1818 PR_MEM("%s: mlret = %d\n", f, mlret); 1819 } 1820 1821 PR_MEM("%s: brd %d: edited source memlist:\n", 1822 f, s_sbp->sb_num); 1823 SBD_MEMLIST_DUMP(x_ml); 1824 1825 #ifdef DEBUG 1826 /* sanity check memlist */ 1827 d_ml = x_ml; 1828 while (d_ml->next != NULL) 1829 d_ml = d_ml->next; 1830 ASSERT(x_ml->address == _ptob64(s_mp->sbm_basepfn) + 1831 _ptob64(t_mp->sbm_slice_offset)); 1832 ASSERT(d_ml->address + d_ml->size == 1833 _ptob64(s_mq.last_nonrelocatable + 1)); 1834 #endif 1835 1836 /* 1837 * x_ml now describes only the portion of the 1838 * source board that will be moved during the 1839 * copy/rename operation. 1840 */ 1841 d_ml = x_ml; 1842 } else { 1843 /* use original memlist; all spans will be moved */ 1844 d_ml = s_ml; 1845 } 1846 1847 /* verify target can support source memory spans. */ 1848 if (memlist_canfit(d_ml, t_ml) == 0) { 1849 PR_MEM("%s: source memlist won't" 1850 " fit in target memlist\n", f); 1851 PR_MEM("%s: source memlist:\n", f); 1852 SBD_MEMLIST_DUMP(d_ml); 1853 PR_MEM("%s: target memlist:\n", f); 1854 SBD_MEMLIST_DUMP(t_ml); 1855 1856 continue; 1857 } 1858 1859 /* NOTE: the value of d_ml is not used beyond this point */ 1860 1861 PR_MEM("%s: checking for no-reloc on board %d, " 1862 " basepfn=0x%lx, npages=%ld\n", 1863 f, 1864 t_sbp->sb_num, 1865 t_mp->sbm_basepfn, 1866 t_mp->sbm_npages); 1867 1868 rv = kphysm_del_span_query( 1869 t_mp->sbm_basepfn, t_mp->sbm_npages, &mq); 1870 if (rv != KPHYSM_OK) { 1871 PR_MEM("%s: kphysm_del_span_query:" 1872 " unexpected return value %d\n", f, rv); 1873 1874 continue; 1875 } 1876 1877 if (mq.nonrelocatable != 0) { 1878 PR_MEM("%s: candidate board %d has" 1879 " nonrelocatable span [0x%lx..0x%lx]\n", 1880 f, 1881 t_sbp->sb_num, 1882 mq.first_nonrelocatable, 1883 mq.last_nonrelocatable); 1884 1885 continue; 1886 } 1887 1888 #ifdef DEBUG 1889 /* 1890 * This is a debug tool for excluding certain boards 1891 * from being selected as a target board candidate. 1892 * sbd_ignore_board is only tested by this driver. 1893 * It must be set with adb, obp, /etc/system or your 1894 * favorite debugger. 1895 */ 1896 if (sbd_ignore_board & 1897 (1 << (t_sbp->sb_num - 1))) { 1898 PR_MEM("%s: sbd_ignore_board flag set," 1899 " ignoring board %d as candidate\n", 1900 f, t_sbp->sb_num); 1901 continue; 1902 } 1903 #endif 1904 1905 /* 1906 * Make sure there is no memory overlap if this 1907 * target board is used for copy-rename. 1908 */ 1909 if (sbd_check_boundaries(phys_install, s_mp, t_mp) != 0) 1910 continue; 1911 1912 /* 1913 * Reserve excess source board memory, if any. 1914 * 1915 * When the number of pages on the candidate target 1916 * board is less than the number of pages on the source, 1917 * then some spans (clearly) of the source board's address 1918 * space will not be covered by physical memory after the 1919 * copy/rename completes. The following code block 1920 * schedules those spans to be deleted. 1921 */ 1922 if (t_mp->sbm_npages < s_mp->sbm_npages) { 1923 pfn_t pfn; 1924 int mlret; 1925 1926 d_ml = memlist_dup(s_ml); 1927 if (d_ml == NULL) { 1928 PR_MEM("%s: cant dup src brd memlist\n", f); 1929 /* TODO: should abort */ 1930 continue; 1931 } 1932 1933 /* calculate base pfn relative to target board */ 1934 pfn = s_mp->sbm_basepfn & ~sm; 1935 pfn += t_mp->sbm_slice_offset; 1936 1937 /* remove span that will reside on candidate board */ 1938 mlret = memlist_delete_span( 1939 _ptob64(pfn), 1940 _ptob64(t_mp->sbm_npages), 1941 &d_ml); 1942 PR_MEM("%s: mlret = %d\n", f, mlret); 1943 1944 PR_MEM("%s: brd %d: reserving src brd memlist:\n", 1945 f, s_sbp->sb_num); 1946 SBD_MEMLIST_DUMP(d_ml); 1947 1948 /* reserve excess spans */ 1949 if (sbd_reserve_mem_spans( 1950 &s_mp->sbm_memhandle, d_ml) != 0) { 1951 1952 /* likely more non-reloc pages appeared */ 1953 /* TODO: restart from top? */ 1954 continue; 1955 } 1956 } else { 1957 /* no excess source board memory */ 1958 d_ml = NULL; 1959 } 1960 1961 s_mp->sbm_flags |= SBD_MFLAG_RESERVED; 1962 1963 /* 1964 * reserve all memory on target board. 1965 * NOTE: source board's memhandle is used. 1966 * 1967 * If this succeeds (eq 0), then target selection is 1968 * complete and all unwanted memory spans, both source and 1969 * target, have been reserved. Loop is terminated. 1970 */ 1971 if (sbd_reserve_mem_spans(&s_mp->sbm_memhandle, t_ml) == 0) { 1972 PR_MEM("%s: brd %d: target board memory reserved\n", 1973 f, t_sbp->sb_num); 1974 1975 /* a candidate target board is now reserved */ 1976 t_mp->sbm_flags |= SBD_MFLAG_RESERVED; 1977 c_mp = t_mp; 1978 1979 /* *** EXITING LOOP *** */ 1980 break; 1981 } 1982 1983 /* did not successfully reserve the target board. */ 1984 PR_MEM("%s: could not reserve target board %d\n", 1985 f, t_sbp->sb_num); 1986 1987 /* 1988 * NOTE: an undo of the sbd_reserve_mem_span work 1989 * will happen automatically when the memhandle 1990 * (s_mp->sbm_memhandle) is kphysm_del_release'd. 1991 */ 1992 1993 s_mp->sbm_flags &= ~SBD_MFLAG_RESERVED; 1994 } 1995 1996 /* clean up after memlist editing logic */ 1997 if (x_ml != NULL) 1998 memlist_delete(x_ml); 1999 2000 FREESTRUCT(sets, sbd_mem_unit_t *, n_units_per_set * n_sets); 2001 2002 /* 2003 * c_mp will be NULL when the entire sets[] array 2004 * has been searched without reserving a target board. 2005 */ 2006 if (c_mp == NULL) { 2007 PR_MEM("%s: brd %d: target selection failed.\n", 2008 f, s_sbp->sb_num); 2009 2010 if (t_ml != NULL) 2011 memlist_delete(t_ml); 2012 2013 return (-1); 2014 } 2015 2016 PR_MEM("%s: found target board %d for source board %d\n", 2017 f, 2018 t_sbp->sb_num, 2019 s_sbp->sb_num); 2020 2021 s_mp->sbm_peer = c_mp; 2022 s_mp->sbm_flags |= SBD_MFLAG_SOURCE; 2023 s_mp->sbm_del_mlist = d_ml; /* spans to be deleted, if any */ 2024 s_mp->sbm_mlist = s_ml; 2025 s_mp->sbm_cm.sbdev_busy = 1; 2026 2027 c_mp->sbm_peer = s_mp; 2028 c_mp->sbm_flags |= SBD_MFLAG_TARGET; 2029 c_mp->sbm_del_mlist = t_ml; /* spans to be deleted */ 2030 c_mp->sbm_mlist = t_ml; 2031 c_mp->sbm_cm.sbdev_busy = 1; 2032 2033 s_mp->sbm_flags &= ~SBD_MFLAG_MEMRESIZE; 2034 if (c_mp->sbm_npages > s_mp->sbm_npages) { 2035 s_mp->sbm_flags |= SBD_MFLAG_MEMUPSIZE; 2036 PR_MEM("%s: upsize (source pgs 0x%lx < target pgs 0x%lx)\n", 2037 f, s_mp->sbm_npages, c_mp->sbm_npages); 2038 } else if (c_mp->sbm_npages < s_mp->sbm_npages) { 2039 s_mp->sbm_flags |= SBD_MFLAG_MEMDOWNSIZE; 2040 PR_MEM("%s: downsize (source pgs 0x%lx > target pgs 0x%lx)\n", 2041 f, s_mp->sbm_npages, c_mp->sbm_npages); 2042 } 2043 2044 return (0); 2045 } 2046 2047 int 2048 sbd_move_memory(sbd_handle_t *hp, sbd_board_t *s_bp, sbd_board_t *t_bp) 2049 { 2050 int ret; 2051 sbdp_handle_t *hdp; 2052 sbderror_t *ep = SBD_HD2ERR(hp); 2053 2054 hdp = sbd_get_sbdp_handle(s_bp, hp); 2055 2056 ret = sbdp_move_memory(hdp, t_bp->sb_num); 2057 if (ret != 0) 2058 SBD_GET_PERR(hdp->h_err, ep); 2059 2060 sbd_release_sbdp_handle(hdp); 2061 2062 return (ret); 2063 } 2064 2065 /* 2066 * Memlist support. 2067 */ 2068 void 2069 memlist_delete(struct memlist *mlist) 2070 { 2071 sbdp_handle_t *hdp; 2072 2073 hdp = sbd_get_sbdp_handle(NULL, NULL); 2074 2075 (void) sbdp_del_memlist(hdp, mlist); 2076 2077 sbd_release_sbdp_handle(hdp); 2078 } 2079 2080 struct memlist * 2081 memlist_dup(struct memlist *mlist) 2082 { 2083 struct memlist *hl, *prev; 2084 2085 if (mlist == NULL) 2086 return (NULL); 2087 2088 prev = NULL; 2089 hl = NULL; 2090 for (; mlist; mlist = mlist->next) { 2091 struct memlist *mp; 2092 2093 mp = memlist_get_one(); 2094 if (mp == NULL) { 2095 if (hl != NULL) 2096 memlist_free_list(hl); 2097 hl = NULL; 2098 break; 2099 } 2100 mp->address = mlist->address; 2101 mp->size = mlist->size; 2102 mp->next = NULL; 2103 mp->prev = prev; 2104 2105 if (prev == NULL) 2106 hl = mp; 2107 else 2108 prev->next = mp; 2109 prev = mp; 2110 } 2111 2112 return (hl); 2113 } 2114 2115 void 2116 memlist_dump(struct memlist *mlist) 2117 { 2118 register struct memlist *ml; 2119 2120 if (mlist == NULL) { 2121 PR_MEM("memlist> EMPTY\n"); 2122 } else { 2123 for (ml = mlist; ml; ml = ml->next) 2124 PR_MEM("memlist> 0x%" PRIx64 " " 2125 "0x%" PRIx64 " \n", 2126 ml->address, ml->size); 2127 } 2128 } 2129 2130 int 2131 memlist_intersect(struct memlist *al, struct memlist *bl) 2132 { 2133 uint64_t astart, aend, bstart, bend; 2134 2135 if ((al == NULL) || (bl == NULL)) 2136 return (0); 2137 2138 aend = al->address + al->size; 2139 bstart = bl->address; 2140 bend = bl->address + bl->size; 2141 2142 while (al && bl) { 2143 while (al && (aend <= bstart)) 2144 if ((al = al->next) != NULL) 2145 aend = al->address + al->size; 2146 if (al == NULL) 2147 return (0); 2148 2149 if ((astart = al->address) <= bstart) 2150 return (1); 2151 2152 while (bl && (bend <= astart)) 2153 if ((bl = bl->next) != NULL) 2154 bend = bl->address + bl->size; 2155 if (bl == NULL) 2156 return (0); 2157 2158 if ((bstart = bl->address) <= astart) 2159 return (1); 2160 } 2161 2162 return (0); 2163 } 2164 2165 /* 2166 * Determine whether the source memlist (s_mlist) will 2167 * fit into the target memlist (t_mlist) in terms of 2168 * size and holes (i.e. based on same relative base address). 2169 */ 2170 static int 2171 memlist_canfit(struct memlist *s_mlist, struct memlist *t_mlist) 2172 { 2173 int rv = 0; 2174 uint64_t s_basepa, t_basepa; 2175 struct memlist *s_ml, *t_ml; 2176 2177 if ((s_mlist == NULL) || (t_mlist == NULL)) 2178 return (0); 2179 2180 /* 2181 * Base both memlists on common base address (0). 2182 */ 2183 s_basepa = s_mlist->address; 2184 t_basepa = t_mlist->address; 2185 2186 for (s_ml = s_mlist; s_ml; s_ml = s_ml->next) 2187 s_ml->address -= s_basepa; 2188 2189 for (t_ml = t_mlist; t_ml; t_ml = t_ml->next) 2190 t_ml->address -= t_basepa; 2191 2192 s_ml = s_mlist; 2193 for (t_ml = t_mlist; t_ml && s_ml; t_ml = t_ml->next) { 2194 uint64_t s_start, s_end; 2195 uint64_t t_start, t_end; 2196 2197 t_start = t_ml->address; 2198 t_end = t_start + t_ml->size; 2199 2200 for (; s_ml; s_ml = s_ml->next) { 2201 s_start = s_ml->address; 2202 s_end = s_start + s_ml->size; 2203 2204 if ((s_start < t_start) || (s_end > t_end)) 2205 break; 2206 } 2207 } 2208 /* 2209 * If we ran out of source memlist chunks that mean 2210 * we found a home for all of them. 2211 */ 2212 if (s_ml == NULL) 2213 rv = 1; 2214 2215 /* 2216 * Need to add base addresses back since memlists 2217 * are probably in use by caller. 2218 */ 2219 for (s_ml = s_mlist; s_ml; s_ml = s_ml->next) 2220 s_ml->address += s_basepa; 2221 2222 for (t_ml = t_mlist; t_ml; t_ml = t_ml->next) 2223 t_ml->address += t_basepa; 2224 2225 return (rv); 2226 } 2227 2228 void 2229 sbd_attach_mem(sbd_handle_t *hp, sbderror_t *ep) 2230 { 2231 sbd_mem_unit_t *mp; 2232 dev_info_t *dip; 2233 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 2234 sbdp_handle_t *hdp; 2235 int err, unit; 2236 struct memlist *ml, *mc; 2237 static fn_t f = "sbd_attach_mem"; 2238 int i; 2239 2240 PR_MEM("%s...\n", f); 2241 2242 /* 2243 * all four cpus have to be attached before 2244 * configuring mem 2245 */ 2246 for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) { 2247 sbd_cpu_unit_t *cpup; 2248 struct cpu *cp; 2249 2250 if (!SBD_DEV_IS_PRESENT(sbp, SBD_COMP_CPU, i)) 2251 continue; 2252 2253 if (!SBD_DEV_IS_ATTACHED(sbp, SBD_COMP_CPU, i)) 2254 goto error; 2255 2256 cpup = SBD_GET_BOARD_CPUUNIT(sbp, i); 2257 2258 if (cpup == NULL) 2259 goto error; 2260 2261 mutex_enter(&cpu_lock); 2262 cp = cpu_get(cpup->sbc_cpu_id); 2263 if (cp == NULL) { 2264 mutex_exit(&cpu_lock); 2265 cmn_err(CE_WARN, 2266 "sbd:%s: cpu_get failed for cpu %d", 2267 f, cpup->sbc_cpu_id); 2268 goto error; 2269 } 2270 if (cpu_is_poweredoff(cp)) { 2271 mutex_exit(&cpu_lock); 2272 goto error; 2273 } 2274 mutex_exit(&cpu_lock); 2275 continue; 2276 2277 error: 2278 SBD_SET_ERR(ep, ESBD_CPUONLINE); 2279 SBD_SET_ERRSTR(ep, sbp->sb_mempath[i]); 2280 (void) sbd_set_err_in_hdl(hp, ep); 2281 return; 2282 } 2283 2284 dip = *(sbp->sb_devlist[NIX(SBD_COMP_MEM)]); 2285 2286 hdp = sbd_get_sbdp_handle(sbp, hp); 2287 unit = sbdp_get_unit_num(hdp, dip); 2288 if (unit < 0) { 2289 SBD_GET_PERR(hdp->h_err, ep); 2290 sbd_release_sbdp_handle(hdp); 2291 return; 2292 } 2293 2294 ASSERT(sbp->sb_mempath[unit] != NULL); 2295 ASSERT(e_ddi_branch_held(dip)); 2296 2297 (void) ddi_pathname(dip, sbp->sb_mempath[unit]); 2298 2299 mp = SBD_GET_BOARD_MEMUNIT(sbp, unit); 2300 2301 ml = sbd_get_memlist(mp, ep); 2302 if (ml == NULL) { 2303 cmn_err(CE_WARN, 2304 "sbd:%s: failed to get memlist for " 2305 "board %d", f, sbp->sb_num); 2306 /* 2307 * Need to record an error and return. 2308 */ 2309 SBD_SET_ERR(ep, ESBD_MEMFAIL); 2310 SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]); 2311 sbd_release_sbdp_handle(hdp); 2312 return; 2313 } 2314 2315 SBD_MEMLIST_DUMP(ml); 2316 err = 0; 2317 for (mc = ml; mc; mc = mc->next) { 2318 update_membounds_t umb; 2319 pfn_t base; 2320 pgcnt_t npgs; 2321 2322 base = (pfn_t)(mc->address >> PAGESHIFT); 2323 npgs = (pgcnt_t)(mc->size >> PAGESHIFT); 2324 2325 umb.u_board = sbp->sb_num; 2326 umb.u_base = (uint64_t)base << MMU_PAGESHIFT; 2327 umb.u_len = (uint64_t)npgs << MMU_PAGESHIFT; 2328 2329 lgrp_plat_config(LGRP_CONFIG_MEM_ADD, (uintptr_t)&umb); 2330 err = kphysm_add_memory_dynamic(base, npgs); 2331 2332 if (err != KPHYSM_OK) { 2333 cmn_err(CE_WARN, 2334 "%s: kphysm_add_memory_dynamic fail %d", f, err); 2335 2336 /* translate kphysm error */ 2337 switch (err) { 2338 case KPHYSM_ERESOURCE: 2339 err = ESBD_NOMEM; 2340 break; 2341 2342 case KPHYSM_EFAULT: 2343 err = ESBD_FAULT; 2344 break; 2345 2346 default: 2347 err = ESBD_INVAL; 2348 break; 2349 } 2350 break; 2351 } 2352 2353 err = kcage_range_add(base, npgs, KCAGE_DOWN); 2354 if (err != 0) { 2355 cmn_err(CE_WARN, 2356 "%s: kcage_range_add fail %d", f, err); 2357 2358 /* Translate kcage error. */ 2359 switch (err) { 2360 case ENOMEM: 2361 err = ESBD_NOMEM; 2362 break; 2363 default: 2364 err = ESBD_INVAL; 2365 break; 2366 } 2367 break; 2368 } 2369 (void) sbdp_mem_add_span(hdp, mc->address, mc->size); 2370 } 2371 2372 if (err != 0) { 2373 SBD_SET_ERR(ep, err); 2374 SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]); 2375 } 2376 2377 memlist_delete(ml); 2378 sbd_release_sbdp_handle(hdp); 2379 2380 /* 2381 * Now attach all mem devinfo nodes to the device tree. 2382 */ 2383 for (i = 0; i < SBD_NUM_MC_PER_BOARD; i++) { 2384 if (mp->sbm_dip[i] == NULL) 2385 continue; 2386 ASSERT(e_ddi_branch_held(mp->sbm_dip[i])); 2387 if (e_ddi_branch_configure(mp->sbm_dip[i], NULL, 0) && 2388 SBD_GET_ERR(ep) == 0) { 2389 SBD_SET_ERR(ep, ESBD_INVAL); 2390 SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]); 2391 } 2392 } 2393 } 2394 2395 typedef struct { 2396 kcondvar_t cond; 2397 kmutex_t lock; 2398 int error; 2399 int done; 2400 } sbd_release_mem_sync_t; 2401 2402 /* 2403 * When we reach here the memory being drained should have 2404 * already been reserved in sbd_pre_release_mem(). 2405 * Our only task here is to kick off the "drain". 2406 * Returns -1 when error encountered or zero for success. 2407 */ 2408 int 2409 sbd_release_mem(sbd_handle_t *hp, dev_info_t *dip, int unit) 2410 { 2411 memhandle_t mh; 2412 int err; 2413 int cancel_flag = 0; 2414 int e_code = 0; 2415 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 2416 sbd_release_mem_sync_t rms; 2417 static fn_t f = "sbd_release_mem"; 2418 2419 /* 2420 * If this node has a scheduled memory delete operation, 2421 * it will have a memhandle. If it does have a memhandle (the 2422 * return value of sbd_get_memhandle is zero when true), 2423 * then perform the delete. 2424 */ 2425 2426 if ((cancel_flag = sbd_get_memhandle(hp, dip, &mh)) != 0) { 2427 cmn_err(CE_WARN, "%s: couldn't get the memhandle\n", f); 2428 return (cancel_flag); 2429 } 2430 2431 bzero((void *) &rms, sizeof (rms)); 2432 2433 mutex_init(&rms.lock, NULL, MUTEX_DRIVER, NULL); 2434 cv_init(&rms.cond, NULL, CV_DRIVER, NULL); 2435 2436 mutex_enter(&rms.lock); 2437 err = kphysm_del_start(mh, sbd_release_memory_done, (void *) &rms); 2438 if (err == KPHYSM_OK) { 2439 /* wait for completion */ 2440 while (!rms.done) { 2441 if (cancel_flag) { 2442 /* previously canceled */ 2443 cv_wait(&rms.cond, &rms.lock); 2444 } else if (cv_wait_sig(&rms.cond, &rms.lock) == 0) { 2445 /* interrupted: cancel and wait */ 2446 cancel_flag = -1; 2447 (void) kphysm_del_cancel(mh); 2448 } 2449 } 2450 /* get the result of the memory delete operation */ 2451 err = rms.error; 2452 } else { 2453 (void) kphysm_del_release(mh); 2454 } 2455 2456 mutex_exit(&rms.lock); 2457 2458 cv_destroy(&rms.cond); 2459 mutex_destroy(&rms.lock); 2460 2461 if (err != KPHYSM_OK) { 2462 switch (err) { 2463 case KPHYSM_ENOWORK: 2464 e_code = ESBD_NOERROR; 2465 break; 2466 2467 case KPHYSM_EHANDLE: 2468 case KPHYSM_ESEQUENCE: 2469 e_code = ESBD_INTERNAL; 2470 break; 2471 2472 case KPHYSM_ENOTVIABLE: 2473 e_code = ESBD_MEM_NOTVIABLE; 2474 break; 2475 2476 case KPHYSM_EREFUSED: 2477 e_code = ESBD_MEM_REFUSED; 2478 break; 2479 2480 case KPHYSM_ENONRELOC: 2481 e_code = ESBD_MEM_NONRELOC; 2482 break; 2483 2484 case KPHYSM_ECANCELLED: 2485 e_code = ESBD_MEM_CANCELLED; 2486 break; 2487 2488 case KPHYSM_ERESOURCE: 2489 e_code = ESBD_MEMFAIL; 2490 break; 2491 2492 default: 2493 cmn_err(CE_WARN, "sbd:%s:" 2494 " unexpected kphysm error code %d," 2495 " dip 0x%p", 2496 f, err, (void *)dip); 2497 2498 e_code = ESBD_IO; 2499 break; 2500 } 2501 2502 if (e_code != 0) { 2503 cancel_flag = -1; 2504 SBD_SET_ERR(SBD_HD2ERR(hp), e_code); 2505 SBD_SET_ERRSTR(SBD_HD2ERR(hp), sbp->sb_mempath[unit]); 2506 } 2507 } 2508 2509 return (cancel_flag); 2510 } 2511 2512 /* 2513 * Memory has been logically removed by the time this routine is called. 2514 */ 2515 void 2516 sbd_release_memory_done(void *arg, int error) 2517 { 2518 sbd_release_mem_sync_t *ds = arg; 2519 2520 mutex_enter(&ds->lock); 2521 ds->error = error; 2522 ds->done = 1; 2523 cv_signal(&ds->cond); 2524 mutex_exit(&ds->lock); 2525 } 2526 2527 /* 2528 * If detaching node contains memory that is "non-permanent" 2529 * then the memory adr's are simply cleared. If the memory 2530 * is non-relocatable, then do a copy-rename. 2531 */ 2532 int 2533 sbd_detach_memory(sbd_handle_t *hp, sbderror_t *ep, sbd_mem_unit_t *s_mp, 2534 int unit) 2535 { 2536 int rv; 2537 sbd_mem_unit_t *t_mp; 2538 sbd_istate_t state; 2539 sbdp_handle_t *hdp; 2540 sbd_board_t *sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp; 2541 sbd_board_t *tbp; 2542 static fn_t f = "sbd_detach_memory"; 2543 2544 PR_MEM("%s...\n", f); 2545 2546 /* lookup target mem unit and target board structure, if any */ 2547 if (s_mp->sbm_flags & SBD_MFLAG_SOURCE) { 2548 t_mp = s_mp->sbm_peer; 2549 ASSERT(t_mp != NULL); 2550 ASSERT(t_mp->sbm_peer == s_mp); 2551 tbp = (sbd_board_t *)t_mp->sbm_cm.sbdev_sbp; 2552 } else { 2553 t_mp = NULL; 2554 } 2555 2556 /* verify mem unit's state is UNREFERENCED */ 2557 state = s_mp->sbm_cm.sbdev_state; 2558 if (state != SBD_STATE_UNREFERENCED) { 2559 cmn_err(CE_WARN, "%s: invalid state transition for" 2560 " mem-unit (%d.%d)", 2561 f, 2562 sbp->sb_num, 2563 s_mp->sbm_cm.sbdev_unum); 2564 SBD_SET_ERR(ep, ESBD_STATE); 2565 SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]); 2566 return (-1); 2567 } 2568 2569 /* verify target mem unit's state is UNREFERENCED, if any */ 2570 if (t_mp != NULL) { 2571 state = t_mp->sbm_cm.sbdev_state; 2572 if (state != SBD_STATE_UNREFERENCED) { 2573 cmn_err(CE_WARN, "%s: invalid state transition for" 2574 " target mem-unit (%d.%d)", 2575 f, 2576 tbp->sb_num, 2577 t_mp->sbm_cm.sbdev_unum); 2578 SBD_SET_ERR(ep, ESBD_STATE); 2579 SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]); 2580 return (-1); 2581 } 2582 } 2583 2584 /* 2585 * Displacement flush all ecaches in the system. 2586 * That's the fastest way to remove all cache references 2587 * to the detaching memory. 2588 */ 2589 xc_all(sbd_flush_ecache, 0, 0); 2590 2591 hdp = sbd_get_sbdp_handle(sbp, hp); 2592 2593 /* 2594 * If there is no target board (no copy/rename was needed), then 2595 * we're done! 2596 */ 2597 if (t_mp == NULL) { 2598 /* 2599 * Reprogram interconnect hardware and disable 2600 * memory controllers for memory node that's going away. 2601 */ 2602 2603 rv = sbdphw_disable_memctrl(hdp, s_mp->sbm_cm.sbdev_dip); 2604 if (rv) { 2605 cmn_err(CE_WARN, 2606 "%s: failed to deprogram mem-unit (%d.%d)," 2607 " dip 0x%p", 2608 f, 2609 sbp->sb_num, 2610 s_mp->sbm_cm.sbdev_unum, 2611 (void *)s_mp->sbm_cm.sbdev_dip); 2612 /* 2613 * Make sure we don't rewrite an sbdp error 2614 */ 2615 if (SBD_GET_ERR(ep) != 0) { 2616 SBD_SET_ERR(ep, ESBD_HW_PROGRAM); 2617 SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]); 2618 } 2619 } 2620 } else { 2621 rv = sbd_move_memory(hp, sbp, tbp); 2622 if (rv) { 2623 int i; 2624 2625 cmn_err(CE_WARN, "%s: failed to move memory" 2626 " from board %d to board %d", 2627 f, 2628 sbp->sb_num, 2629 tbp->sb_num); 2630 /* 2631 * Make sure we don't rewrite an sbdp error 2632 */ 2633 if (SBD_GET_ERR(ep) != 0) { 2634 SBD_SET_ERR(ep, ESBD_INTERNAL); 2635 SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]); 2636 } 2637 /* 2638 * If we failed here, it means that the target board's 2639 * memory has been unconfigured. We need to configure 2640 * it back 2641 */ 2642 for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 2643 int unit; 2644 dev_info_t *dip; 2645 dev_info_t **devlist; 2646 2647 2648 devlist = tbp->sb_devlist[NIX(SBD_COMP_MEM)]; 2649 dip = devlist[i]; 2650 sbd_reset_error_sbdph(hdp); 2651 unit = sbdp_get_unit_num(hdp, dip); 2652 2653 /* 2654 * We already saved the error that created 2655 * this mess. If we fail, make sure not 2656 * to overwrite the original error 2657 */ 2658 if (unit == -1) { 2659 continue; 2660 } 2661 if (sbd_cancel_mem(hp, unit) != 0) 2662 continue; 2663 2664 t_mp->sbm_flags = 0; 2665 /* 2666 * clean up 2667 */ 2668 sbd_mem_cleanup(s_mp, t_mp, ep); 2669 if (s_mp->sbm_mlist) { 2670 memlist_delete(s_mp->sbm_mlist); 2671 s_mp->sbm_mlist = NULL; 2672 } 2673 2674 SBD_DEVICE_TRANSITION(tbp, SBD_COMP_MEM, 2675 unit, SBD_STATE_CONFIGURED); 2676 } 2677 } 2678 2679 PR_MEM("%s: %s memory COPY-RENAME (board %d -> %d)\n", 2680 f, 2681 rv ? "FAILED" : "COMPLETED", 2682 sbp->sb_num, 2683 tbp->sb_num); 2684 } 2685 2686 if (rv == 0) { 2687 update_membounds_t umb; 2688 2689 umb.u_board = sbp->sb_num; 2690 umb.u_base = (uint64_t)-1; 2691 umb.u_len = (uint64_t)-1; 2692 2693 lgrp_plat_config(LGRP_CONFIG_MEM_DEL, (uintptr_t)&umb); 2694 } 2695 2696 sbd_release_sbdp_handle(hdp); 2697 return (rv); 2698 } 2699 2700 /*ARGSUSED*/ 2701 static void 2702 sbd_flush_ecache(uint64_t a, uint64_t b) 2703 { 2704 cpu_flush_ecache(); 2705 } 2706