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