1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 /* 27 * Copyright 2019 Peter Tribble. 28 */ 29 30 /* 31 * CPU support routines for DR 32 */ 33 34 #include <sys/debug.h> 35 #include <sys/types.h> 36 #include <sys/errno.h> 37 #include <sys/cred.h> 38 #include <sys/dditypes.h> 39 #include <sys/devops.h> 40 #include <sys/modctl.h> 41 #include <sys/poll.h> 42 #include <sys/conf.h> 43 #include <sys/ddi.h> 44 #include <sys/sunddi.h> 45 #include <sys/sunndi.h> 46 #include <sys/ddi_impldefs.h> 47 #include <sys/ndi_impldefs.h> 48 #include <sys/stat.h> 49 #include <sys/kmem.h> 50 #include <sys/processor.h> 51 #include <sys/cpuvar.h> 52 #include <sys/mem_config.h> 53 #include <sys/promif.h> 54 #include <sys/x_call.h> 55 #include <sys/cpu_sgnblk_defs.h> 56 #include <sys/membar.h> 57 #include <sys/stack.h> 58 #include <sys/sysmacros.h> 59 #include <sys/machsystm.h> 60 #include <sys/spitregs.h> 61 62 #include <sys/archsystm.h> 63 #include <vm/hat_sfmmu.h> 64 #include <sys/pte.h> 65 #include <sys/mmu.h> 66 #include <sys/x_call.h> 67 #include <sys/cpu_module.h> 68 #include <sys/cheetahregs.h> 69 70 #include <sys/autoconf.h> 71 #include <sys/cmn_err.h> 72 73 #include <sys/sbdpriv.h> 74 75 void 76 sbd_cpu_set_prop(sbd_cpu_unit_t *cp, dev_info_t *dip) 77 { 78 uint32_t clock_freq; 79 int ecache_size = 0; 80 char *cache_str = NULL; 81 82 /* read in the CPU speed */ 83 clock_freq = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 84 DDI_PROP_DONTPASS, "clock-frequency", 0); 85 86 ASSERT(clock_freq != 0); 87 88 /* 89 * The ecache property string is not the same 90 * for all CPU implementations. 91 */ 92 switch (cp->sbc_cpu_impl) { 93 case CHEETAH_IMPL: 94 case CHEETAH_PLUS_IMPL: 95 cache_str = "ecache-size"; 96 break; 97 case JAGUAR_IMPL: 98 cache_str = "l2-cache-size"; 99 break; 100 case PANTHER_IMPL: 101 cache_str = "l3-cache-size"; 102 break; 103 default: 104 cmn_err(CE_WARN, "cpu implementation type " 105 "is an unknown %d value", cp->sbc_cpu_impl); 106 ASSERT(0); 107 break; 108 } 109 110 if (cache_str != NULL) { 111 /* read in the ecache size */ 112 ecache_size = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 113 DDI_PROP_DONTPASS, cache_str, 0); 114 } 115 116 /* 117 * In the case the size is still 0, 118 * a zero value will be displayed running non-debug. 119 */ 120 ASSERT(ecache_size != 0); 121 122 /* convert to the proper units */ 123 cp->sbc_speed = (clock_freq + 500000) / 1000000; 124 cp->sbc_ecache = ecache_size / (1024 * 1024); 125 } 126 127 static void 128 sbd_fill_cpu_stat(sbd_cpu_unit_t *cp, dev_info_t *dip, sbd_cpu_stat_t *csp) 129 { 130 int namelen; 131 132 bzero((caddr_t)csp, sizeof (*csp)); 133 csp->cs_type = cp->sbc_cm.sbdev_type; 134 csp->cs_unit = cp->sbc_cm.sbdev_unum; 135 namelen = sizeof (csp->cs_name); 136 (void) ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 137 OBP_DEVICETYPE, (caddr_t)csp->cs_name, &namelen); 138 csp->cs_busy = cp->sbc_cm.sbdev_busy; 139 csp->cs_time = cp->sbc_cm.sbdev_time; 140 csp->cs_ostate = cp->sbc_cm.sbdev_ostate; 141 csp->cs_cpuid = cp->sbc_cpu_id; 142 csp->cs_suspend = 0; 143 144 /* 145 * If we have marked the cpu's condition previously 146 * then don't rewrite it 147 */ 148 if (csp->cs_cond != SBD_COND_UNUSABLE) 149 csp->cs_cond = sbd_get_comp_cond(dip); 150 151 /* 152 * If the speed and ecache properties have not been 153 * cached yet, read them in from the device tree. 154 */ 155 if ((cp->sbc_speed == 0) || (cp->sbc_ecache == 0)) 156 sbd_cpu_set_prop(cp, dip); 157 158 /* use the cached speed and ecache values */ 159 csp->cs_speed = cp->sbc_speed; 160 csp->cs_ecache = cp->sbc_ecache; 161 } 162 163 static void 164 sbd_fill_cmp_stat(sbd_cpu_stat_t *csp, int ncores, int impl, 165 sbd_cmp_stat_t *psp) 166 { 167 int core; 168 169 ASSERT(csp && psp && (ncores >= 1)); 170 171 bzero((caddr_t)psp, sizeof (*psp)); 172 173 /* 174 * Fill in the common status information based 175 * on the data for the first core. 176 */ 177 psp->ps_type = SBD_COMP_CMP; 178 psp->ps_unit = SBD_CMP_NUM(csp->cs_unit); 179 (void) strncpy(psp->ps_name, csp->cs_name, sizeof (psp->ps_name)); 180 psp->ps_cond = csp->cs_cond; 181 psp->ps_busy = csp->cs_busy; 182 psp->ps_time = csp->cs_time; 183 psp->ps_ostate = csp->cs_ostate; 184 psp->ps_suspend = csp->cs_suspend; 185 186 /* CMP specific status data */ 187 *psp->ps_cpuid = csp->cs_cpuid; 188 psp->ps_ncores = 1; 189 psp->ps_speed = csp->cs_speed; 190 psp->ps_ecache = csp->cs_ecache; 191 192 /* 193 * Walk through the data for the remaining cores. 194 * Make any adjustments to the common status data, 195 * or the shared CMP specific data if necessary. 196 */ 197 for (core = 1; core < ncores; core++) { 198 199 /* 200 * The following properties should be the same 201 * for all the cores of the CMP. 202 */ 203 ASSERT(psp->ps_unit == SBD_CMP_NUM(csp[core].cs_unit)); 204 ASSERT(psp->ps_speed == csp[core].cs_speed); 205 206 psp->ps_cpuid[core] = csp[core].cs_cpuid; 207 psp->ps_ncores++; 208 209 /* 210 * Jaguar has a split ecache, so the ecache 211 * for each core must be added together to 212 * get the total ecache for the whole chip. 213 */ 214 if (IS_JAGUAR(impl)) { 215 psp->ps_ecache += csp[core].cs_ecache; 216 } 217 218 /* adjust time if necessary */ 219 if (csp[core].cs_time > psp->ps_time) { 220 psp->ps_time = csp[core].cs_time; 221 } 222 223 psp->ps_busy |= csp[core].cs_busy; 224 225 /* 226 * If any of the cores are configured, the 227 * entire CMP is marked as configured. 228 */ 229 if (csp[core].cs_ostate == SBD_STAT_CONFIGURED) { 230 psp->ps_ostate = csp[core].cs_ostate; 231 } 232 } 233 } 234 235 int 236 sbd_cpu_flags(sbd_handle_t *hp, sbd_devset_t devset, sbd_dev_stat_t *dsp) 237 { 238 int cmp; 239 int ncpu; 240 sbd_board_t *sbp; 241 sbdp_handle_t *hdp; 242 sbd_cpu_stat_t cstat[MAX_CORES_PER_CMP]; 243 244 sbp = SBDH2BD(hp->h_sbd); 245 hdp = sbd_get_sbdp_handle(sbp, hp); 246 247 /* 248 * Grab the status lock before accessing the dip as we allow 249 * concurrent status and branch unconfigure and disconnect. 250 * 251 * The disconnect thread clears the present devset first 252 * and then destroys dips. It is possible that the status 253 * thread checks the present devset before they are cleared 254 * but accesses the dip after they are destroyed causing a 255 * panic. To prevent this, the status thread should check 256 * the present devset and access dips with status lock held. 257 * Similarly disconnect thread should clear the present devset 258 * and destroy dips with status lock held. 259 */ 260 mutex_enter(&sbp->sb_slock); 261 262 /* 263 * Only look for requested devices that are actually present. 264 */ 265 devset &= SBD_DEVS_PRESENT(sbp); 266 267 /* 268 * Treat every CPU as a CMP. In the case where the 269 * device is not a CMP, treat it as a CMP with only 270 * one core. 271 */ 272 for (cmp = ncpu = 0; cmp < MAX_CMP_UNITS_PER_BOARD; cmp++) { 273 274 int ncores; 275 int core; 276 dev_info_t *dip; 277 sbd_cpu_unit_t *cp; 278 sbd_cmp_stat_t *psp; 279 280 if (DEVSET_IN_SET(devset, SBD_COMP_CMP, cmp) == 0) 281 continue; 282 283 ncores = 0; 284 285 for (core = 0; core < MAX_CORES_PER_CMP; core++) { 286 int unit; 287 288 unit = sbdp_portid_to_cpu_unit(cmp, core); 289 290 /* 291 * Check to make sure the cpu is in a state 292 * where its fully initialized. 293 */ 294 if (SBD_DEVICE_STATE(sbp, SBD_COMP_CPU, unit) == 295 SBD_STATE_EMPTY) 296 continue; 297 298 dip = sbp->sb_devlist[NIX(SBD_COMP_CMP)][unit]; 299 if (dip == NULL) 300 continue; 301 302 cp = SBD_GET_BOARD_CPUUNIT(sbp, unit); 303 304 sbd_fill_cpu_stat(cp, dip, &cstat[ncores++]); 305 } 306 307 if (ncores == 0) 308 continue; 309 310 /* 311 * Store the data to the outgoing array. If the 312 * device is a CMP, combine all the data for the 313 * cores into a single stat structure. 314 * 315 * The check for a CMP device uses the last core 316 * found, assuming that all cores will have the 317 * same implementation. 318 */ 319 if (CPU_IMPL_IS_CMP(cp->sbc_cpu_impl)) { 320 psp = (sbd_cmp_stat_t *)dsp; 321 sbd_fill_cmp_stat(cstat, ncores, cp->sbc_cpu_impl, psp); 322 } else { 323 ASSERT(ncores == 1); 324 bcopy(cstat, dsp, sizeof (sbd_cpu_stat_t)); 325 } 326 327 dsp++; 328 ncpu++; 329 } 330 331 mutex_exit(&sbp->sb_slock); 332 333 sbd_release_sbdp_handle(hdp); 334 335 return (ncpu); 336 } 337 338 int 339 sbd_pre_release_cpu(sbd_handle_t *hp, sbd_devlist_t *devlist, int devnum) 340 { 341 int i, rv = 0, unit; 342 dev_info_t *dip; 343 processorid_t cpuid; 344 struct cpu *cpup; 345 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 346 sbderror_t *ep = SBD_HD2ERR(hp); 347 sbd_cpu_unit_t *cp; 348 static fn_t f = "sbd_pre_release_cpu"; 349 sbdp_handle_t *hdp; 350 351 hdp = sbd_get_sbdp_handle(sbp, hp); 352 /* 353 * May have to juggle bootproc in release_component 354 */ 355 mutex_enter(&cpu_lock); 356 357 for (i = 0; i < devnum; i++, devlist++) { 358 dip = devlist->dv_dip; 359 360 cpuid = sbdp_get_cpuid(hdp, dip); 361 if (cpuid < 0) { 362 if (hp->h_flags & SBD_IOCTL_FLAG_FORCE) { 363 cmn_err(CE_WARN, 364 "sbd:%s: failed to get cpuid for " 365 "dip (0x%p)", f, (void *)dip); 366 continue; 367 } else { 368 SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 369 break; 370 } 371 } 372 373 374 unit = sbdp_get_unit_num(hdp, dip); 375 if (unit < 0) { 376 if (hp->h_flags & SBD_IOCTL_FLAG_FORCE) { 377 cmn_err(CE_WARN, 378 "sbd:%s: failed to get unit (cpu %d)", 379 f, cpuid); 380 continue; 381 } else { 382 SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 383 break; 384 } 385 } 386 387 cp = SBD_GET_BOARD_CPUUNIT(sbp, unit); 388 cp->sbc_cpu_flags = cpu[cpuid]->cpu_flags; 389 390 if (cpu_flagged_active(cp->sbc_cpu_flags)) { 391 int cpu_offline_flags = 0; 392 393 if (hp->h_flags & SBD_IOCTL_FLAG_FORCE) 394 cpu_offline_flags = CPU_FORCED; 395 PR_CPU("%s: offlining cpuid %d unit %d", f, 396 cpuid, unit); 397 if (cpu_offline(cpu[cpuid], cpu_offline_flags)) { 398 cmn_err(CE_WARN, 399 "%s: failed to offline cpu %d", 400 f, cpuid); 401 rv = -1; 402 SBD_SET_ERR(ep, ESBD_OFFLINE); 403 SBD_SET_ERRSTR(ep, sbp->sb_cpupath[i]); 404 cpup = cpu_get(cpuid); 405 if (cpup && disp_bound_threads(cpup, 0)) { 406 cmn_err(CE_WARN, "sbd:%s: thread(s) " 407 "bound to cpu %d", 408 f, cpup->cpu_id); 409 } 410 break; 411 } 412 } 413 414 if (rv == 0) { 415 if (sbdp_release_component(hdp, dip)) { 416 SBD_GET_PERR(hdp->h_err, ep); 417 break; 418 } 419 } 420 421 if (rv) 422 break; 423 } 424 425 mutex_exit(&cpu_lock); 426 427 if (rv) { 428 /* 429 * Need to unwind others since at this level (pre-release) 430 * the device state has not yet transitioned and failures 431 * will prevent us from reaching the "post" release 432 * function where states are normally transitioned. 433 */ 434 for (; i >= 0; i--, devlist--) { 435 dip = devlist->dv_dip; 436 unit = sbdp_get_unit_num(hdp, dip); 437 if (unit < 0) { 438 cmn_err(CE_WARN, 439 "sbd:%s: failed to get unit for " 440 "dip (0x%p)", f, (void *)dip); 441 break; 442 } 443 (void) sbd_cancel_cpu(hp, unit); 444 } 445 } 446 447 SBD_INJECT_ERR(SBD_OFFLINE_CPU_PSEUDO_ERR, 448 hp->h_err, EIO, 449 ESBD_OFFLINE, 450 sbp->sb_cpupath[devnum - 1]); 451 452 sbd_release_sbdp_handle(hdp); 453 454 return (rv); 455 } 456 457 int 458 sbd_pre_attach_cpu(sbd_handle_t *hp, sbd_devlist_t *devlist, int devnum) 459 { 460 int i; 461 int unit; 462 processorid_t cpuid; 463 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 464 sbd_istate_t dstate; 465 dev_info_t *dip; 466 static fn_t f = "sbd_pre_attach_cpu"; 467 sbdp_handle_t *hdp; 468 469 PR_CPU("%s...\n", f); 470 471 hdp = sbd_get_sbdp_handle(sbp, hp); 472 473 for (i = 0; i < devnum; i++, devlist++) { 474 dip = devlist->dv_dip; 475 476 ASSERT(sbd_is_cmp_child(dip) || e_ddi_branch_held(dip)); 477 478 cpuid = sbdp_get_cpuid(hdp, dip); 479 if (cpuid < 0) { 480 if (hp->h_flags & SBD_IOCTL_FLAG_FORCE) { 481 cmn_err(CE_WARN, 482 "sbd:%s: failed to get cpuid for " 483 "dip (0x%p)", f, (void *)dip); 484 continue; 485 } else { 486 SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 487 break; 488 } 489 } 490 491 unit = sbdp_get_unit_num(hdp, dip); 492 if (unit < 0) { 493 if (hp->h_flags & SBD_IOCTL_FLAG_FORCE) { 494 cmn_err(CE_WARN, 495 "sbd:%s: failed to get unit (cpu %d)", 496 f, cpuid); 497 continue; 498 } else { 499 SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 500 break; 501 } 502 } 503 504 PR_CPU("%s: attach cpu-unit (%d.%d)\n", 505 f, sbp->sb_num, unit); 506 507 dstate = SBD_DEVICE_STATE(sbp, SBD_COMP_CPU, unit); 508 509 if (dstate == SBD_STATE_UNCONFIGURED) { 510 /* 511 * If we're coming from the UNCONFIGURED 512 * state then the cpu's sigblock will 513 * still be mapped in. Need to unmap it 514 * before continuing with attachment. 515 */ 516 PR_CPU("%s: unmapping sigblk for cpu %d\n", 517 f, cpuid); 518 } 519 520 } 521 522 mutex_enter(&cpu_lock); 523 524 sbd_release_sbdp_handle(hdp); 525 526 return (0); 527 } 528 529 int 530 sbd_post_attach_cpu(sbd_handle_t *hp, sbd_devlist_t *devlist, int devnum) 531 { 532 int i; 533 sbderror_t *ep = SBD_HD2ERR(hp); 534 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 535 processorid_t cpuid; 536 struct cpu *cp; 537 dev_info_t *dip; 538 int err = ESBD_NOERROR; 539 sbdp_handle_t *hdp; 540 static fn_t f = "sbd_post_attach_cpu"; 541 sbd_cpu_unit_t *cpup; 542 int unit; 543 544 hdp = sbd_get_sbdp_handle(sbp, hp); 545 546 /* Startup and online newly-attached CPUs */ 547 for (i = 0; i < devnum; i++, devlist++) { 548 dip = devlist->dv_dip; 549 cpuid = sbdp_get_cpuid(hdp, dip); 550 if (cpuid < 0) { 551 if (hp->h_flags & SBD_IOCTL_FLAG_FORCE) { 552 cmn_err(CE_WARN, 553 "sbd:%s: failed to get cpuid for " 554 "dip (0x%p)", f, (void *)dip); 555 continue; 556 } else { 557 SBD_GET_PERR(hdp->h_err, ep); 558 break; 559 } 560 } 561 562 cp = cpu_get(cpuid); 563 564 if (cp == NULL) { 565 if (hp->h_flags & SBD_IOCTL_FLAG_FORCE) { 566 cmn_err(CE_WARN, 567 "sbd:%s: cpu_get failed for cpu %d", 568 f, cpuid); 569 continue; 570 } else { 571 SBD_SET_ERR(ep, ESBD_INTERNAL); 572 SBD_SET_ERRSTR(ep, sbp->sb_cpupath[i]); 573 break; 574 } 575 } 576 577 if (cpu_is_poweredoff(cp)) { 578 if (cpu_poweron(cp) != 0) { 579 SBD_SET_ERR(ep, ESBD_CPUSTART); 580 SBD_SET_ERRSTR(ep, sbp->sb_cpupath[i]); 581 cmn_err(CE_WARN, 582 "%s: failed to power-on cpu %d", 583 f, cpuid); 584 break; 585 } 586 SBD_INJECT_ERR(SBD_POWERON_CPU_PSEUDO_ERR, 587 ep, EIO, 588 ESBD_CPUSTOP, 589 sbp->sb_cpupath[i]); 590 PR_CPU("%s: cpu %d powered ON\n", f, cpuid); 591 } 592 593 if (cpu_is_offline(cp)) { 594 PR_CPU("%s: onlining cpu %d...\n", f, cpuid); 595 596 if (cpu_online(cp) != 0) { 597 SBD_SET_ERR(ep, ESBD_ONLINE); 598 SBD_SET_ERRSTR(ep, sbp->sb_cpupath[i]); 599 cmn_err(CE_WARN, 600 "%s: failed to online cpu %d", 601 f, cp->cpu_id); 602 } 603 SBD_INJECT_ERR(SBD_ONLINE_CPU_PSEUDO_ERR, 604 ep, EIO, 605 ESBD_ONLINE, 606 sbp->sb_cpupath[i]); 607 } 608 609 /* 610 * if there is no error mark the cpu as OK to use 611 */ 612 if (SBD_GET_ERR(ep) == 0) { 613 unit = sbdp_get_unit_num(hdp, dip); 614 if (unit < 0) { 615 if (hp->h_flags & SBD_IOCTL_FLAG_FORCE) { 616 cmn_err(CE_WARN, 617 "sbd:%s: failed to get unit " 618 "(cpu %d)", f, cpuid); 619 continue; 620 } else { 621 SBD_GET_PERR(hdp->h_err, 622 SBD_HD2ERR(hp)); 623 break; 624 } 625 } 626 cpup = SBD_GET_BOARD_CPUUNIT(sbp, unit); 627 cpup->sbc_cm.sbdev_cond = SBD_COND_OK; 628 } 629 } 630 631 mutex_exit(&cpu_lock); 632 633 sbd_release_sbdp_handle(hdp); 634 635 if (err != ESBD_NOERROR) { 636 return (-1); 637 } else { 638 return (0); 639 } 640 } 641 642 int 643 sbd_pre_detach_cpu(sbd_handle_t *hp, sbd_devlist_t *devlist, int devnum) 644 { 645 int i; 646 int unit; 647 processorid_t cpuid; 648 dev_info_t *dip; 649 struct cpu *cpu; 650 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 651 sbderror_t *ep = SBD_HD2ERR(hp); 652 static fn_t f = "sbd_pre_detach_cpu"; 653 sbdp_handle_t *hdp; 654 int rv = 0; 655 656 PR_CPU("%s...\n", f); 657 658 hdp = sbd_get_sbdp_handle(sbp, hp); 659 660 mutex_enter(&cpu_lock); 661 662 for (i = 0; i < devnum; i++, devlist++) { 663 dip = devlist->dv_dip; 664 cpuid = sbdp_get_cpuid(hdp, dip); 665 if (cpuid < 0) { 666 if (hp->h_flags & SBD_IOCTL_FLAG_FORCE) { 667 cmn_err(CE_WARN, 668 "sbd:%s: failed to get cpuid for " 669 "dip (0x%p)", f, (void *)dip); 670 continue; 671 } else { 672 SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 673 break; 674 } 675 } 676 677 cpu = cpu_get(cpuid); 678 679 if (cpu == NULL) { 680 if (hp->h_flags & SBD_IOCTL_FLAG_FORCE) { 681 cmn_err(CE_WARN, 682 "sbd:%s: failed to get cpu %d", 683 f, cpuid); 684 continue; 685 } else { 686 SBD_SET_ERR(ep, ESBD_INTERNAL); 687 SBD_SET_ERRSTR(ep, sbp->sb_cpupath[i]); 688 break; 689 } 690 } 691 692 unit = sbdp_get_unit_num(hdp, dip); 693 if (unit < 0) { 694 if (hp->h_flags & SBD_IOCTL_FLAG_FORCE) { 695 cmn_err(CE_WARN, 696 "sbd:%s: failed to get unit (cpu %d)", 697 f, cpuid); 698 continue; 699 } else { 700 SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 701 break; 702 } 703 } 704 705 PR_CPU("%s: OS detach cpu-unit (%d.%d)\n", 706 f, sbp->sb_num, unit); 707 708 /* 709 * CPUs were offlined during Release. 710 */ 711 if (cpu_is_poweredoff(cpu)) { 712 PR_CPU("%s: cpu %d already powered OFF\n", f, cpuid); 713 continue; 714 } 715 716 if (cpu_is_offline(cpu)) { 717 int e; 718 719 if (e = cpu_poweroff(cpu)) { 720 cmn_err(CE_WARN, 721 "%s: failed to power-off cpu %d " 722 "(errno %d)", 723 f, cpu->cpu_id, e); 724 SBD_SET_ERR(ep, ESBD_CPUSTOP); 725 SBD_SET_ERRSTR(ep, sbp->sb_cpupath[i]); 726 727 rv = -1; 728 break; 729 } else { 730 PR_CPU("%s: cpu %d powered OFF\n", 731 f, cpuid); 732 } 733 } else { 734 cmn_err(CE_WARN, "%s: cpu %d still active", 735 f, cpu->cpu_id); 736 SBD_SET_ERR(ep, ESBD_BUSY); 737 SBD_SET_ERRSTR(ep, sbp->sb_cpupath[i]); 738 rv = -1; 739 break; 740 } 741 } 742 743 sbd_release_sbdp_handle(hdp); 744 745 return (rv); 746 } 747 748 int 749 sbd_post_detach_cpu(sbd_handle_t *hp, sbd_devlist_t *devlist, int devnum) 750 { 751 static fn_t f = "sbd_post_detach_cpu"; 752 int i; 753 sbderror_t *ep = SBD_HD2ERR(hp); 754 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 755 processorid_t cpuid; 756 dev_info_t *dip; 757 sbdp_handle_t *hdp; 758 sbd_cpu_unit_t *cpup; 759 int unit; 760 761 PR_CPU("%s...\n", f); 762 763 /* 764 * We should be holding the cpu_lock at this point, 765 * and should have blocked device tree changes. 766 */ 767 ASSERT(MUTEX_HELD(&cpu_lock)); 768 769 for (i = 0; i < devnum; i++, devlist++) { 770 dip = devlist->dv_dip; 771 hdp = sbd_get_sbdp_handle(sbp, hp); 772 cpuid = sbdp_get_cpuid(hdp, dip); 773 if (cpuid < 0) { 774 if (hp->h_flags & SBD_IOCTL_FLAG_FORCE) { 775 cmn_err(CE_WARN, 776 "sbd:%s: failed to get cpuid for " 777 "dip (0x%p)", f, (void *)dip); 778 continue; 779 } else { 780 SBD_GET_PERR(hdp->h_err, ep); 781 break; 782 } 783 } 784 /* 785 * if there is no error mark the cpu as unusable 786 */ 787 if (SBD_GET_ERR(ep) == 0) { 788 unit = sbdp_get_unit_num(hdp, dip); 789 if (unit < 0) { 790 if (hp->h_flags & SBD_IOCTL_FLAG_FORCE) { 791 cmn_err(CE_WARN, 792 "sbd:%s: failed to get unit " 793 "(cpu %d)", f, cpuid); 794 continue; 795 } else { 796 SBD_GET_PERR(hdp->h_err, 797 SBD_HD2ERR(hp)); 798 break; 799 } 800 } 801 cpup = SBD_GET_BOARD_CPUUNIT(sbp, unit); 802 cpup->sbc_cm.sbdev_cond = SBD_COND_UNUSABLE; 803 } 804 sbd_release_sbdp_handle(hdp); 805 } 806 807 mutex_exit(&cpu_lock); 808 809 810 return (0); 811 } 812 813 /* 814 * Cancel previous release operation for cpu. For cpus this means simply 815 * bringing cpus that were offline back online. Note that they had to have been 816 * online at the time they were released. If attempting to power on or online 817 * a CPU fails, SBD_CPUERR_FATAL is returned to indicate that the CPU appears to 818 * be unsalvageable. If a CPU reaches an online or nointr state but can't be 819 * taken to a "lesser" state, SBD_CPUERR_RECOVERABLE is returned to indicate 820 * that it was not returned to its original state but appears to be functional. 821 * Note that the latter case can occur due to unexpected but non-erroneous CPU 822 * manipulation (e.g. by the "psradm" command) during the DR operation. 823 */ 824 int 825 sbd_cancel_cpu(sbd_handle_t *hp, int unit) 826 { 827 int rv = SBD_CPUERR_NONE; 828 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 829 sbderror_t *ep = SBD_HD2ERR(hp); 830 sbd_cpu_unit_t *cp; 831 static fn_t f = "sbd_cancel_cpu"; 832 struct cpu *cpup; 833 int cpu_offline_flags = 0; 834 835 PR_ALL("%s...\n", f); 836 837 cp = SBD_GET_BOARD_CPUUNIT(sbp, unit); 838 839 /* 840 * If CPU should remain off, nothing needs to be done. 841 */ 842 if (cpu_flagged_poweredoff(cp->sbc_cpu_flags)) 843 return (rv); 844 845 if (hp->h_flags & SBD_IOCTL_FLAG_FORCE) 846 cpu_offline_flags = CPU_FORCED; 847 848 /* 849 * CPU had been either offline, online, or set to no-intr. We 850 * will return a component to its original state that it was 851 * prior to the failed DR operation. There is a possible race 852 * condition between the calls to this function and re-obtaining 853 * the cpu_lock where a cpu state could change. Because of this 854 * we can't externally document that we are trying to roll cpus 855 * back to their original state, but we believe a best effort 856 * should be made. 857 */ 858 859 mutex_enter(&cpu_lock); 860 cpup = cpu[cp->sbc_cpu_id]; 861 862 /* 863 * The following will compare the cpu's current state with a 864 * snapshot of its state taken before the failed DR operation 865 * had started. 866 */ 867 /* POWEROFF */ 868 if (cpu_is_poweredoff(cpup)) { 869 if (cpu_poweron(cpup)) { 870 cmn_err(CE_WARN, 871 "sbd:%s: failed to power-on cpu %d", 872 f, cp->sbc_cpu_id); 873 SBD_SET_ERR(ep, ESBD_CPUSTART); 874 SBD_SET_ERRSTR(ep, sbp->sb_cpupath[unit]); 875 rv = SBD_CPUERR_FATAL; 876 goto out; 877 } 878 SBD_INJECT_ERR(SBD_POWERON_CPU_PSEUDO_ERR, 879 hp->h_err, EIO, 880 ESBD_CPUSTART, 881 sbp->sb_cpupath[unit]); 882 } 883 884 /* OFFLINE */ 885 if (cpu_is_offline(cpup)) { 886 if (cpu_flagged_offline(cp->sbc_cpu_flags)) { 887 PR_CPU("%s: leaving cpu %d OFFLINE\n", 888 f, cp->sbc_cpu_id); 889 } else if (cpu_online(cpup)) { 890 cmn_err(CE_WARN, 891 "sbd:%s: failed to online cpu %d", 892 f, cp->sbc_cpu_id); 893 SBD_SET_ERR(ep, ESBD_ONLINE); 894 SBD_SET_ERRSTR(ep, sbp->sb_cpupath[unit]); 895 rv = SBD_CPUERR_FATAL; 896 goto out; 897 } else { 898 SBD_INJECT_ERR(SBD_ONLINE_CPU_PSEUDO_ERR, 899 hp->h_err, EIO, 900 ESBD_ONLINE, 901 sbp->sb_cpupath[unit]); 902 } 903 } 904 905 /* ONLINE */ 906 if (cpu_is_online(cpup)) { 907 if (cpu_flagged_online(cp->sbc_cpu_flags)) { 908 PR_CPU("%s: setting cpu %d ONLINE\n", 909 f, cp->sbc_cpu_id); 910 } else if (cpu_flagged_offline(cp->sbc_cpu_flags)) { 911 if (cpu_offline(cpup, cpu_offline_flags)) { 912 cmn_err(CE_WARN, 913 "sbd:%s: failed to offline" 914 " cpu %d", f, cp->sbc_cpu_id); 915 rv = SBD_CPUERR_RECOVERABLE; 916 goto out; 917 } 918 } else if (cpu_flagged_nointr(cp->sbc_cpu_flags)) { 919 if (cpu_intr_disable(cpup)) { 920 cmn_err(CE_WARN, "%s: failed to " 921 "disable interrupts on cpu %d", 922 f, cp->sbc_cpu_id); 923 rv = SBD_CPUERR_RECOVERABLE; 924 } else { 925 PR_CPU("%s: setting cpu %d to NOINTR" 926 " (was online)\n", 927 f, cp->sbc_cpu_id); 928 } 929 goto out; 930 } 931 } 932 933 /* NOINTR */ 934 if (cpu_is_nointr(cpup)) { 935 if (cpu_flagged_online(cp->sbc_cpu_flags)) { 936 cpu_intr_enable(cpup); 937 PR_CPU("%s: setting cpu %d ONLINE" 938 "(was nointr)\n", 939 f, cp->sbc_cpu_id); 940 } 941 if (cpu_flagged_offline(cp->sbc_cpu_flags)) { 942 if (cpu_offline(cpup, cpu_offline_flags)) { 943 cmn_err(CE_WARN, 944 "sbd:%s: failed to offline" 945 " cpu %d", f, cp->sbc_cpu_id); 946 rv = SBD_CPUERR_RECOVERABLE; 947 } 948 } 949 } 950 out: 951 mutex_exit(&cpu_lock); 952 953 return (rv); 954 } 955 956 int 957 sbd_connect_cpu(sbd_board_t *sbp, int unit) 958 { 959 int rv; 960 processorid_t cpuid; 961 struct cpu *cpu; 962 dev_info_t *dip; 963 sbdp_handle_t *hdp; 964 extern kmutex_t cpu_lock; 965 static fn_t f = "sbd_connect_cpu"; 966 sbd_handle_t *hp = MACHBD2HD(sbp); 967 968 /* 969 * get dip for cpu just located in tree walk 970 */ 971 if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_CPU, unit)) { 972 dip = sbp->sb_devlist[NIX(SBD_COMP_CPU)][unit]; 973 if (dip == NULL) { 974 cmn_err(CE_WARN, 975 "sbd:%s: bad dip for cpu unit %d board %d", 976 f, unit, sbp->sb_num); 977 return (-1); 978 } 979 PR_CPU("%s...\n", f); 980 } else { 981 return (0); 982 } 983 984 /* 985 * if sbd has attached this cpu, no need to bring 986 * it out of reset 987 */ 988 if (SBD_DEV_IS_ATTACHED(sbp, SBD_COMP_CPU, unit)) { 989 return (0); 990 } 991 992 hdp = sbd_get_sbdp_handle(sbp, hp); 993 994 cpuid = sbdp_get_cpuid(hdp, dip); 995 if (cpuid == -1) { 996 sbd_release_sbdp_handle(hdp); 997 return (-1); 998 } 999 1000 /* 1001 * if the cpu is already under Solaris control, 1002 * do not wake it up 1003 */ 1004 mutex_enter(&cpu_lock); 1005 cpu = cpu_get(cpuid); 1006 mutex_exit(&cpu_lock); 1007 if (cpu != NULL) { 1008 sbd_release_sbdp_handle(hdp); 1009 return (0); 1010 } 1011 1012 rv = sbdp_connect_cpu(hdp, dip, cpuid); 1013 1014 if (rv != 0) { 1015 sbp->sb_memaccess_ok = 0; 1016 cmn_err(CE_WARN, 1017 "sbd:%s: failed to wake up cpu unit %d board %d", 1018 f, unit, sbp->sb_num); 1019 sbd_release_sbdp_handle(hdp); 1020 return (rv); 1021 } 1022 sbd_release_sbdp_handle(hdp); 1023 1024 return (rv); 1025 } 1026 1027 int 1028 sbd_disconnect_cpu(sbd_handle_t *hp, int unit) 1029 { 1030 sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 1031 int rv; 1032 dev_info_t *dip; 1033 sbdp_handle_t *hdp; 1034 sbd_cpu_unit_t *cp; 1035 processorid_t cpuid; 1036 static fn_t f = "sbd_disconnect_cpu"; 1037 1038 PR_CPU("%s...\n", f); 1039 1040 ASSERT((SBD_DEVICE_STATE(sbp, SBD_COMP_CPU, unit) == 1041 SBD_STATE_CONNECTED) || 1042 (SBD_DEVICE_STATE(sbp, SBD_COMP_CPU, unit) == 1043 SBD_STATE_UNCONFIGURED)); 1044 1045 cp = SBD_GET_BOARD_CPUUNIT(sbp, unit); 1046 1047 cpuid = cp->sbc_cpu_id; 1048 1049 dip = sbp->sb_devlist[NIX(SBD_COMP_CPU)][unit]; 1050 1051 hdp = sbd_get_sbdp_handle(sbp, hp); 1052 1053 rv = sbdp_disconnect_cpu(hdp, dip, cpuid); 1054 1055 if (rv != 0) { 1056 SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 1057 } 1058 sbd_release_sbdp_handle(hdp); 1059 1060 return (rv); 1061 } 1062