xref: /titanic_44/usr/src/uts/sun4u/serengeti/io/sbdp_mem.c (revision 28cdc3d776761766afeb198769d1b70ed7e0f2e1)
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 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * memory management for serengeti dr memory
31  */
32 
33 #include <sys/obpdefs.h>
34 #include <sys/types.h>
35 #include <sys/conf.h>
36 #include <sys/ddi.h>
37 #include <sys/cpuvar.h>
38 #include <sys/memlist_impl.h>
39 #include <sys/machsystm.h>
40 #include <sys/promif.h>
41 #include <sys/mem_cage.h>
42 #include <sys/kmem.h>
43 #include <sys/note.h>
44 #include <sys/lgrp.h>
45 
46 #include <sys/sbd_ioctl.h>
47 #include <sys/sbd.h>
48 #include <sys/sbdp_priv.h>
49 #include <sys/sbdp_mem.h>
50 #include <sys/sun4asi.h>
51 #include <sys/cheetahregs.h>
52 #include <sys/cpu_module.h>
53 #include <sys/esunddi.h>
54 
55 #include <vm/page.h>
56 
57 static int	sbdp_get_meminfo(pnode_t, int, uint64_t *, uint64_t *);
58 int		mc_read_regs(pnode_t, mc_regs_t *);
59 uint64_t	mc_get_addr(pnode_t, int, uint_t *);
60 static pnode_t	mc_get_sibling_cpu(pnode_t nodeid);
61 static int	mc_get_sibling_cpu_impl(pnode_t nodeid);
62 static sbd_cond_t mc_check_sibling_cpu(pnode_t nodeid);
63 static void	_sbdp_copy_rename_end(void);
64 static int	sbdp_copy_rename__relocatable(sbdp_cr_handle_t *,
65 			struct memlist *, sbdp_rename_script_t *);
66 static int	sbdp_prep_rename_script(sbdp_cr_handle_t *);
67 static int	sbdp_get_lowest_addr_in_node(pnode_t, uint64_t *);
68 
69 extern void bcopy32_il(uint64_t, uint64_t);
70 extern void flush_ecache_il(uint64_t physaddr, size_t size, size_t linesize);
71 extern uint64_t lddphys_il(uint64_t physaddr);
72 extern uint64_t ldxasi_il(uint64_t physaddr, uint_t asi);
73 extern void sbdp_exec_script_il(sbdp_rename_script_t *rsp);
74 void sbdp_fill_bank_info(uint64_t, sbdp_bank_t **);
75 int sbdp_add_nodes_banks(pnode_t node, sbdp_bank_t **banks);
76 void sbdp_add_bank_to_seg(sbdp_bank_t *);
77 void sbdp_remove_bank_from_seg(sbdp_bank_t *);
78 uint64_t sbdp_determine_slice(sbdp_handle_t *);
79 sbdp_seg_t *sbdp_get_seg(uint64_t);
80 #ifdef DEBUG
81 void sbdp_print_seg(sbdp_seg_t *);
82 #endif
83 
84 /*
85  * Head to the system segments link list
86  */
87 sbdp_seg_t *sys_seg = NULL;
88 
89 uint64_t
90 sbdp_determine_slice(sbdp_handle_t *hp)
91 {
92 	int size;
93 
94 	size = sbdp_get_mem_size(hp);
95 
96 	if (size <= SG_SLICE_16G_SIZE) {
97 		return (SG_SLICE_16G_SIZE);
98 	} else if (size <= SG_SLICE_32G_SIZE) {
99 		return (SG_SLICE_32G_SIZE);
100 	} else {
101 		return (SG_SLICE_64G_SIZE);
102 	}
103 }
104 
105 /* ARGSUSED */
106 int
107 sbdp_get_mem_alignment(sbdp_handle_t *hp, dev_info_t *dip, uint64_t *align)
108 {
109 	*align = sbdp_determine_slice(hp);
110 	return (0);
111 }
112 
113 
114 void
115 sbdp_memlist_dump(struct memlist *mlist)
116 {
117 	register struct memlist *ml;
118 
119 	if (mlist == NULL) {
120 		SBDP_DBG_MEM("memlist> EMPTY\n");
121 	} else {
122 		for (ml = mlist; ml; ml = ml->next)
123 			SBDP_DBG_MEM("memlist>  0x%" PRIx64", 0x%" PRIx64"\n",
124 			    ml->address, ml->size);
125 	}
126 }
127 
128 struct mem_arg {
129 	int	board;
130 	int	ndips;
131 	dev_info_t **list;
132 };
133 
134 /*
135  * Returns mem dip held
136  */
137 static int
138 sbdp_get_mem_dip(pnode_t node, void *arg, uint_t flags)
139 {
140 	_NOTE(ARGUNUSED(flags))
141 
142 	dev_info_t *dip;
143 	pnode_t nodeid;
144 	mem_op_t mem = {0};
145 	struct mem_arg *ap = arg;
146 
147 	if (node == OBP_BADNODE || node == OBP_NONODE)
148 		return (DDI_FAILURE);
149 
150 	mem.nodes = &nodeid;
151 	mem.board = ap->board;
152 	mem.nmem = 0;
153 
154 	(void) sbdp_is_mem(node, &mem);
155 
156 	ASSERT(mem.nmem == 0 || mem.nmem == 1);
157 
158 	if (mem.nmem == 0 || nodeid != node)
159 		return (DDI_FAILURE);
160 
161 	dip = e_ddi_nodeid_to_dip(nodeid);
162 	if (dip) {
163 		ASSERT(ap->ndips < SBDP_MAX_MEM_NODES_PER_BOARD);
164 		ap->list[ap->ndips++] = dip;
165 	}
166 	return (DDI_SUCCESS);
167 }
168 
169 struct memlist *
170 sbdp_get_memlist(sbdp_handle_t *hp, dev_info_t *dip)
171 {
172 	_NOTE(ARGUNUSED(dip))
173 
174 	int i, j, skip = 0;
175 	dev_info_t	*list[SBDP_MAX_MEM_NODES_PER_BOARD];
176 	struct mem_arg	arg = {0};
177 	uint64_t	base_pa, size;
178 	struct memlist	*mlist = NULL;
179 
180 	list[0] = NULL;
181 	arg.board = hp->h_board;
182 	arg.list = list;
183 
184 	sbdp_walk_prom_tree(prom_rootnode(), sbdp_get_mem_dip, &arg);
185 
186 	for (i = 0; i < arg.ndips; i++) {
187 		if (list[i] == NULL)
188 			continue;
189 
190 		size = 0;
191 		for (j = 0; j < SBDP_MAX_MCS_PER_NODE; j++) {
192 			if (sbdp_get_meminfo(ddi_get_nodeid(list[i]), j,
193 			    &size, &base_pa)) {
194 				skip++;
195 				continue;
196 			}
197 			if (size == -1 || size == 0)
198 				continue;
199 
200 			(void) memlist_add_span(base_pa, size, &mlist);
201 		}
202 
203 		/*
204 		 * Release hold acquired in sbdp_get_mem_dip()
205 		 */
206 		ddi_release_devi(list[i]);
207 	}
208 
209 	/*
210 	 * XXX - The following two lines are from existing code.
211 	 * However, this appears to be incorrect - this check should be
212 	 * made for each dip in list i.e within the for(i) loop.
213 	 */
214 	if (skip == SBDP_MAX_MCS_PER_NODE)
215 		sbdp_set_err(hp->h_err, ESGT_INTERNAL, NULL);
216 
217 	SBDP_DBG_MEM("memlist for board %d\n", hp->h_board);
218 	sbdp_memlist_dump(mlist);
219 	return (mlist);
220 }
221 
222 struct memlist *
223 sbdp_memlist_dup(struct memlist *mlist)
224 {
225 	struct memlist *hl, *prev;
226 
227 	if (mlist == NULL)
228 		return (NULL);
229 
230 	prev = NULL;
231 	hl = NULL;
232 	for (; mlist; mlist = mlist->next) {
233 		struct memlist *mp;
234 
235 		mp = memlist_get_one();
236 		if (mp == NULL) {
237 			if (hl != NULL)
238 				memlist_free_list(hl);
239 			hl = NULL;
240 			break;
241 		}
242 		mp->address = mlist->address;
243 		mp->size = mlist->size;
244 		mp->next = NULL;
245 		mp->prev = prev;
246 
247 		if (prev == NULL)
248 			hl = mp;
249 		else
250 			prev->next = mp;
251 		prev = mp;
252 	}
253 
254 	return (hl);
255 }
256 
257 int
258 sbdp_del_memlist(sbdp_handle_t *hp, struct memlist *mlist)
259 {
260 	_NOTE(ARGUNUSED(hp))
261 
262 	memlist_free_list(mlist);
263 
264 	return (0);
265 }
266 
267 /*ARGSUSED*/
268 static void
269 sbdp_flush_ecache(uint64_t a, uint64_t b)
270 {
271 	cpu_flush_ecache();
272 }
273 
274 typedef enum {
275 	SBDP_CR_OK,
276 	SBDP_CR_MC_IDLE_ERR
277 } sbdp_cr_err_t;
278 
279 int
280 sbdp_move_memory(sbdp_handle_t *hp, int t_bd)
281 {
282 	sbdp_bd_t	*s_bdp, *t_bdp;
283 	int		err = 0;
284 	caddr_t		mempage;
285 	ulong_t		data_area, index_area;
286 	ulong_t		e_area, e_page;
287 	int		availlen, indexlen, funclen, scriptlen;
288 	int		*indexp;
289 	time_t		copytime;
290 	int		(*funcp)();
291 	size_t		size;
292 	struct memlist	*mlist;
293 	sbdp_sr_handle_t	*srhp;
294 	sbdp_rename_script_t	*rsp;
295 	sbdp_rename_script_t	*rsbuffer;
296 	sbdp_cr_handle_t	*cph;
297 	int		linesize;
298 	uint64_t	neer;
299 	sbdp_cr_err_t	cr_err;
300 
301 	cph =  kmem_zalloc(sizeof (sbdp_cr_handle_t), KM_SLEEP);
302 
303 	SBDP_DBG_MEM("moving memory from memory board %d to board %d\n",
304 	    hp->h_board, t_bd);
305 
306 	s_bdp = sbdp_get_bd_info(hp->h_wnode, hp->h_board);
307 	t_bdp = sbdp_get_bd_info(hp->h_wnode, t_bd);
308 
309 	if ((s_bdp == NULL) || (t_bdp == NULL)) {
310 		sbdp_set_err(hp->h_err, ESGT_INTERNAL, NULL);
311 		return (-1);
312 	}
313 
314 	funclen = (int)((ulong_t)_sbdp_copy_rename_end -
315 			(ulong_t)sbdp_copy_rename__relocatable);
316 
317 	if (funclen > PAGESIZE) {
318 		cmn_err(CE_WARN,
319 		    "sbdp: copy-rename funclen (%d) > PAGESIZE (%d)",
320 		    funclen, PAGESIZE);
321 		sbdp_set_err(hp->h_err, ESGT_INTERNAL, NULL);
322 		return (-1);
323 	}
324 
325 	/*
326 	 * mempage will be page aligned, since we're calling
327 	 * kmem_alloc() with an exact multiple of PAGESIZE.
328 	 */
329 	mempage = kmem_alloc(PAGESIZE, KM_SLEEP);
330 
331 	SBDP_DBG_MEM("mempage = 0x%p\n", mempage);
332 
333 	/*
334 	 * Copy the code for the copy-rename routine into
335 	 * a page aligned piece of memory.  We do this to guarantee
336 	 * that we're executing within the same page and thus reduce
337 	 * the possibility of cache collisions between different
338 	 * pages.
339 	 */
340 	bcopy((caddr_t)sbdp_copy_rename__relocatable, mempage, funclen);
341 
342 	funcp = (int (*)())mempage;
343 
344 	SBDP_DBG_MEM("copy-rename funcp = 0x%p (len = 0x%x)\n", funcp, funclen);
345 
346 	/*
347 	 * Prepare data page that will contain script of
348 	 * operations to perform during copy-rename.
349 	 * Allocate temporary buffer to hold script.
350 	 */
351 
352 	size = sizeof (sbdp_rename_script_t) * SBDP_RENAME_MAXOP;
353 	rsbuffer = kmem_zalloc(size, KM_SLEEP);
354 
355 	cph->s_bdp = s_bdp;
356 	cph->t_bdp = t_bdp;
357 	cph->script = rsbuffer;
358 
359 	/*
360 	 * We need to make sure we don't switch cpus since we depend on the
361 	 * correct cpu processing
362 	 */
363 	affinity_set(CPU_CURRENT);
364 	scriptlen = sbdp_prep_rename_script(cph);
365 	if (scriptlen <= 0) {
366 		cmn_err(CE_WARN,
367 			"sbdp failed to prep for copy-rename");
368 		sbdp_set_err(hp->h_err, ESGT_INTERNAL, NULL);
369 		err = 1;
370 		goto cleanup;
371 	}
372 	SBDP_DBG_MEM("copy-rename script length = 0x%x\n", scriptlen);
373 
374 	indexlen = sizeof (*indexp) << 1;
375 
376 	if ((funclen + scriptlen + indexlen) > PAGESIZE) {
377 		cmn_err(CE_WARN,
378 			"sbdp: func len (%d) + script len (%d) "
379 			"+ index len (%d) > PAGESIZE (%d)",
380 			funclen, scriptlen, indexlen, PAGESIZE);
381 		sbdp_set_err(hp->h_err, ESGT_INTERNAL, NULL);
382 		err = 1;
383 		goto cleanup;
384 	}
385 
386 	linesize = cpunodes[CPU->cpu_id].ecache_linesize;
387 
388 	/*
389 	 * Find aligned area within data page to maintain script.
390 	 */
391 	data_area = (ulong_t)mempage;
392 	data_area += (ulong_t)funclen + (ulong_t)(linesize - 1);
393 	data_area &= ~((ulong_t)(linesize - 1));
394 
395 	availlen = PAGESIZE - indexlen;
396 	availlen -= (int)(data_area - (ulong_t)mempage);
397 
398 	if (availlen < scriptlen) {
399 		cmn_err(CE_WARN,
400 			"sbdp: available len (%d) < script len (%d)",
401 			availlen, scriptlen);
402 		sbdp_set_err(hp->h_err, ESGT_INTERNAL, NULL);
403 		err = 1;
404 		goto cleanup;
405 	}
406 
407 	SBDP_DBG_MEM("copy-rename script data area = 0x%lx\n",
408 		data_area);
409 
410 	bcopy((caddr_t)rsbuffer, (caddr_t)data_area, scriptlen);
411 	rsp = (sbdp_rename_script_t *)data_area;
412 
413 	index_area = data_area + (ulong_t)scriptlen +
414 			(ulong_t)(linesize - 1);
415 	index_area &= ~((ulong_t)(linesize - 1));
416 	indexp = (int *)index_area;
417 	indexp[0] = 0;
418 	indexp[1] = 0;
419 
420 	e_area = index_area + (ulong_t)indexlen;
421 	e_page = (ulong_t)mempage + PAGESIZE;
422 	if (e_area > e_page) {
423 		cmn_err(CE_WARN,
424 			"sbdp: index area size (%d) > available (%d)\n",
425 			indexlen, (int)(e_page - index_area));
426 		sbdp_set_err(hp->h_err, ESGT_INTERNAL, NULL);
427 		err = 1;
428 		goto cleanup;
429 	}
430 
431 	SBDP_DBG_MEM("copy-rename index area = 0x%p\n", indexp);
432 
433 	SBDP_DBG_MEM("cpu %d\n", CPU->cpu_id);
434 
435 	srhp = sbdp_get_sr_handle();
436 	ASSERT(srhp);
437 
438 	srhp->sr_flags = hp->h_flags;
439 
440 	copytime = lbolt;
441 
442 	mutex_enter(&s_bdp->bd_mutex);
443 	mlist = sbdp_memlist_dup(s_bdp->ml);
444 	mutex_exit(&s_bdp->bd_mutex);
445 
446 	if (mlist == NULL) {
447 		SBDP_DBG_MEM("Didn't find memory list\n");
448 	}
449 	SBDP_DBG_MEM("src\n\tbd\t%d\n\tnode\t%d\n\tbpa 0x%lx\n\tnodes\t%p\n",
450 	    s_bdp->bd, s_bdp->wnode, s_bdp->bpa, s_bdp->nodes);
451 	sbdp_memlist_dump(s_bdp->ml);
452 	SBDP_DBG_MEM("tgt\n\tbd\t%d\n\tnode\t%d\n\tbpa 0x%lx\n\tnodes\t%p\n",
453 	    t_bdp->bd, t_bdp->wnode, t_bdp->bpa, t_bdp->nodes);
454 	sbdp_memlist_dump(t_bdp->ml);
455 
456 	/*
457 	 * Quiesce the OS.
458 	 */
459 	if (sbdp_suspend(srhp)) {
460 		sbd_error_t	*sep;
461 		cmn_err(CE_WARN,
462 			"sbdp: failed to quiesce OS for copy-rename");
463 		sep = &srhp->sep;
464 		sbdp_set_err(hp->h_err, sep->e_code, sep->e_rsc);
465 		sbdp_release_sr_handle(srhp);
466 		sbdp_del_memlist(hp, mlist);
467 		err = 1;
468 		goto cleanup;
469 	}
470 
471 	/*
472 	 * =================================
473 	 * COPY-RENAME BEGIN.
474 	 * =================================
475 	 */
476 	SBDP_DBG_MEM("s_base 0x%lx t_base 0x%lx\n", cph->s_bdp->bpa,
477 	    cph->t_bdp->bpa);
478 
479 	cph->ret = 0;
480 
481 	SBDP_DBG_MEM("cph return 0x%lx\n", cph->ret);
482 
483 	SBDP_DBG_MEM("Flushing all of the cpu caches\n");
484 	xc_all(sbdp_flush_ecache, 0, 0);
485 
486 	/* disable CE reporting */
487 	neer = get_error_enable();
488 	set_error_enable(neer & ~EN_REG_CEEN);
489 
490 	cr_err = (*funcp)(cph, mlist, rsp);
491 
492 	/* enable CE reporting */
493 	set_error_enable(neer);
494 
495 	SBDP_DBG_MEM("s_base 0x%lx t_base 0x%lx\n", cph->s_bdp->bpa,
496 	    cph->t_bdp->bpa);
497 	SBDP_DBG_MEM("cph return 0x%lx\n", cph->ret);
498 	SBDP_DBG_MEM("after execking the function\n");
499 
500 	/*
501 	 * =================================
502 	 * COPY-RENAME END.
503 	 * =================================
504 	 */
505 	SBDP_DBG_MEM("err is 0x%d\n", err);
506 
507 	/*
508 	 * Resume the OS.
509 	 */
510 	sbdp_resume(srhp);
511 	if (srhp->sep.e_code) {
512 		sbd_error_t	*sep;
513 		cmn_err(CE_WARN,
514 		    "sbdp: failed to resume OS for copy-rename");
515 		sep = &srhp->sep;
516 		sbdp_set_err(hp->h_err, sep->e_code, sep->e_rsc);
517 		err = 1;
518 	}
519 
520 	copytime = lbolt - copytime;
521 
522 	sbdp_release_sr_handle(srhp);
523 	sbdp_del_memlist(hp, mlist);
524 
525 	SBDP_DBG_MEM("copy-rename elapsed time = %ld ticks (%ld secs)\n",
526 		copytime, copytime / hz);
527 
528 	switch (cr_err) {
529 	case SBDP_CR_OK:
530 		break;
531 	case SBDP_CR_MC_IDLE_ERR: {
532 		dev_info_t *dip;
533 		pnode_t nodeid = cph->busy_mc->node;
534 		char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
535 
536 		dip = e_ddi_nodeid_to_dip(nodeid);
537 
538 		ASSERT(dip != NULL);
539 
540 		(void) ddi_pathname(dip, path);
541 		ddi_release_devi(dip);
542 		cmn_err(CE_WARN, "failed to idle memory controller %s: "
543 		    "copy-rename aborted", path);
544 		kmem_free(path, MAXPATHLEN);
545 		sbdp_set_err(hp->h_err, ESBD_MEMFAIL, NULL);
546 		err = 1;
547 		break;
548 	}
549 	default:
550 		sbdp_set_err(hp->h_err, ESGT_INTERNAL, NULL);
551 		cmn_err(CE_WARN, "unknown copy-rename error code (%d)", cr_err);
552 		err = 1;
553 		break;
554 	}
555 
556 	if (err)
557 		goto cleanup;
558 
559 	/*
560 	 * Rename memory for lgroup.
561 	 * Source and target board numbers are packaged in arg.
562 	 */
563 	lgrp_plat_config(LGRP_CONFIG_MEM_RENAME,
564 		(uintptr_t)(s_bdp->bd | (t_bdp->bd << 16)));
565 
566 	/*
567 	 * swap list of banks
568 	 */
569 	sbdp_swap_list_of_banks(s_bdp, t_bdp);
570 
571 	/*
572 	 * Update the cached board info for both the source and the target
573 	 */
574 	sbdp_update_bd_info(s_bdp);
575 	sbdp_update_bd_info(t_bdp);
576 
577 	/*
578 	 * Tell the sc that we have swapped slices.
579 	 */
580 	if (sbdp_swap_slices(s_bdp->bd, t_bdp->bd) != 0) {
581 		/* This is dangerous. The in use slice could be re-used! */
582 		SBDP_DBG_MEM("swaping slices failed\n");
583 	}
584 
585 cleanup:
586 	kmem_free(rsbuffer, size);
587 	kmem_free(mempage, PAGESIZE);
588 	kmem_free(cph, sizeof (sbdp_cr_handle_t));
589 	affinity_clear();
590 
591 	return (err ? -1 : 0);
592 }
593 
594 static int
595 sbdp_copy_regs(pnode_t node, uint64_t bpa, uint64_t new_base, int inval,
596 	sbdp_rename_script_t *rsp, int *index)
597 {
598 	int		i, m;
599 	mc_regs_t	regs;
600 	uint64_t	*mc_decode;
601 
602 	if (mc_read_regs(node, &regs)) {
603 		SBDP_DBG_MEM("sbdp_copy_regs: failed to read source Decode "
604 		    "Regs");
605 		return (-1);
606 	}
607 
608 	mc_decode = regs.mc_decode;
609 
610 	m = *index;
611 	for (i = 0; i < SBDP_MAX_MCS_PER_NODE; i++) {
612 		uint64_t	offset, seg_pa, tmp_base;
613 
614 		/*
615 		 * Skip invalid banks
616 		 */
617 		if ((mc_decode[i] & SG_DECODE_VALID) != SG_DECODE_VALID) {
618 			continue;
619 		}
620 
621 		tmp_base = new_base;
622 		if (!inval) {
623 			/*
624 			 * We need to calculate the offset from the base pa
625 			 * to add it appropriately to the new_base.
626 			 * The offset needs to be in UM relative to the mc
627 			 * decode register.  Since we are going from physical
628 			 * address to UM, we need to shift it by PHYS2UM_SHIFT.
629 			 * To get it ready to OR it with the MC decode reg,
630 			 * we need to shift it left MC_UM_SHIFT
631 			 */
632 			seg_pa = MC_BASE(mc_decode[i]) << PHYS2UM_SHIFT;
633 			offset = (seg_pa - bpa);
634 			/* Convert tmp_base into a physical address */
635 			tmp_base = (tmp_base >> MC_UM_SHIFT) << PHYS2UM_SHIFT;
636 			tmp_base += offset;
637 			/* Convert tmp_base to be MC reg ready */
638 			tmp_base = (tmp_base >> PHYS2UM_SHIFT) << MC_UM_SHIFT;
639 		}
640 
641 		mc_decode[i] &= ~SG_DECODE_UM;
642 		mc_decode[i] |= tmp_base;
643 		mc_decode[i] |= SG_DECODE_VALID;
644 
645 		/*
646 		 * Step 1:	Write source base address to the MC
647 		 *		with present bit off.
648 		 */
649 		rsp[m].masr_addr = mc_get_addr(node, i, &rsp[m].asi);
650 		rsp[m].masr = mc_decode[i] & ~SG_DECODE_VALID;
651 		m++;
652 		/*
653 		 * Step 2:	Now rewrite the mc reg with present bit on.
654 		 */
655 		rsp[m].masr_addr = rsp[m-1].masr_addr;
656 		rsp[m].masr = mc_decode[i];
657 		rsp[m].asi = rsp[m-1].asi;
658 		m++;
659 	}
660 
661 	*index = m;
662 	return (0);
663 }
664 
665 static int
666 sbdp_get_reg_addr(pnode_t nodeid, uint64_t *pa)
667 {
668 	mc_regspace	reg;
669 	int		len;
670 
671 	len = prom_getproplen(nodeid, "reg");
672 	if (len != sizeof (mc_regspace))
673 		return (-1);
674 
675 	if (prom_getprop(nodeid, "reg", (caddr_t)&reg) < 0)
676 		return (-1);
677 
678 	ASSERT(pa != NULL);
679 
680 	*pa = ((uint64_t)reg.regspec_addr_hi) << 32;
681 	*pa |= (uint64_t)reg.regspec_addr_lo;
682 
683 	return (0);
684 }
685 
686 static int
687 mc_get_sibling_cpu_impl(pnode_t mc_node)
688 {
689 	int	len, impl;
690 	pnode_t	cpu_node;
691 	char	namebuf[OBP_MAXPROPNAME];
692 
693 	cpu_node = mc_get_sibling_cpu(mc_node);
694 	if (cpu_node == OBP_NONODE) {
695 		SBDP_DBG_MEM("mc_get_sibling_cpu failed: dnode=0x%x\n",
696 		    mc_node);
697 		return (-1);
698 	}
699 
700 	len = prom_getproplen(cpu_node, "name");
701 	if (len < 0) {
702 		SBDP_DBG_MEM("invalid prom_getproplen for name prop: "
703 		    "len=%d, dnode=0x%x\n", len, cpu_node);
704 		return (-1);
705 	}
706 
707 	if (prom_getprop(cpu_node, "name", (caddr_t)namebuf) == -1) {
708 		SBDP_DBG_MEM("failed to read name property for dnode=0x%x\n",
709 		    cpu_node);
710 		return (-1);
711 	}
712 
713 	/*
714 	 * If this is a CMP node, the child has the implementation
715 	 * property.
716 	 */
717 	if (strcmp(namebuf, "cmp") == 0) {
718 		cpu_node = prom_childnode(cpu_node);
719 		ASSERT(cpu_node != OBP_NONODE);
720 	}
721 
722 	if (prom_getprop(cpu_node, "implementation#", (caddr_t)&impl) == -1) {
723 		SBDP_DBG_MEM("failed to read implementation# property for "
724 		    "dnode=0x%x\n", cpu_node);
725 		return (-1);
726 	}
727 
728 	SBDP_DBG_MEM("mc_get_sibling_cpu_impl: found impl=0x%x, dnode=0x%x\n",
729 	    impl, cpu_node);
730 
731 	return (impl);
732 }
733 
734 /*
735  * Provide EMU Activity Status register ASI and address.  Only valid for
736  * Panther processors.
737  */
738 static int
739 mc_get_idle_reg(pnode_t nodeid, uint64_t *addr, uint_t *asi)
740 {
741 	int	portid;
742 	uint64_t reg_pa;
743 
744 	ASSERT(nodeid != OBP_NONODE);
745 	ASSERT(mc_get_sibling_cpu_impl(nodeid) == PANTHER_IMPL);
746 
747 	if (prom_getprop(nodeid, "portid", (caddr_t)&portid) < 0 ||
748 	    portid == -1) {
749 		SBDP_DBG_MEM("mc_get_idle_reg: failed to read portid prop "
750 		    "for dnode=0x%x\n", nodeid);
751 		return (-1);
752 	}
753 
754 	if (sbdp_get_reg_addr(nodeid, &reg_pa) != 0) {
755 		SBDP_DBG_MEM("mc_get_idle_reg: failed to read reg prop "
756 		    "for dnode=0x%x\n", nodeid);
757 		return (-1);
758 	}
759 
760 	/*
761 	 * Local access will be via ASI 0x4a, otherwise via Safari PIO.
762 	 * This assumes the copy-rename will later run on the same proc,
763 	 * hence there is an assumption we are already bound.
764 	 */
765 	ASSERT(curthread->t_bound_cpu == CPU);
766 	if (SG_CPUID_TO_PORTID(CPU->cpu_id) == portid) {
767 		*addr = ASI_EMU_ACT_STATUS_VA;
768 		*asi = ASI_SAFARI_CONFIG;
769 	} else {
770 		*addr = MC_ACTIVITY_STATUS(reg_pa);
771 		*asi = ASI_IO;
772 	}
773 
774 	return (0);
775 }
776 
777 /*
778  * If non-Panther board, add phys_banks entry for each physical bank.
779  * If Panther board, add mc_idle_regs entry for each EMU Activity Status
780  * register.  Increment the array indices b_idx and r_idx for each entry
781  * populated by this routine.
782  *
783  * The caller is responsible for allocating sufficient array entries.
784  */
785 static int
786 sbdp_prep_mc_idle_one(sbdp_bd_t *bp, sbdp_rename_script_t phys_banks[],
787     int *b_idx, sbdp_mc_idle_script_t mc_idle_regs[], int *r_idx)
788 {
789 	int		i, j;
790 	pnode_t		*memnodes;
791 	mc_regs_t	regs;
792 	uint64_t	addr;
793 	uint_t		asi;
794 	sbd_cond_t	sibling_cpu_cond;
795 	int		impl = -1;
796 
797 	memnodes = bp->nodes;
798 
799 	for (i = 0; i < SBDP_MAX_MEM_NODES_PER_BOARD; i++) {
800 		if (memnodes[i] == OBP_NONODE) {
801 			continue;
802 		}
803 
804 		/* MC should not be accessed if cpu has failed  */
805 		sibling_cpu_cond = mc_check_sibling_cpu(memnodes[i]);
806 		if (sibling_cpu_cond == SBD_COND_FAILED ||
807 		    sibling_cpu_cond == SBD_COND_UNUSABLE) {
808 			SBDP_DBG_MEM("sbdp: skipping MC with failed cpu: "
809 			    "board=%d, mem node=%d, condition=%d",
810 			    bp->bd, i, sibling_cpu_cond);
811 			continue;
812 		}
813 
814 		/*
815 		 * Initialize the board cpu type, assuming all board cpus are
816 		 * the same type.  This is true of all Cheetah-based processors.
817 		 * Failure to read the cpu type is considered a fatal error.
818 		 */
819 		if (impl == -1) {
820 			impl = mc_get_sibling_cpu_impl(memnodes[i]);
821 			if (impl == -1) {
822 				SBDP_DBG_MEM("sbdp: failed to get cpu impl "
823 				    "for MC dnode=0x%x\n", memnodes[i]);
824 				return (-1);
825 			}
826 		}
827 
828 		switch (impl) {
829 		case CHEETAH_IMPL:
830 		case CHEETAH_PLUS_IMPL:
831 		case JAGUAR_IMPL:
832 			if (mc_read_regs(memnodes[i], &regs)) {
833 				SBDP_DBG_MEM("sbdp: failed to read source "
834 				    "Decode Regs of board %d", bp->bd);
835 				return (-1);
836 			}
837 
838 			for (j = 0; j < SBDP_MAX_MCS_PER_NODE; j++) {
839 				uint64_t mc_decode = regs.mc_decode[j];
840 
841 				if ((mc_decode & SG_DECODE_VALID) !=
842 				    SG_DECODE_VALID) {
843 					continue;
844 				}
845 
846 				addr = (MC_BASE(mc_decode) << PHYS2UM_SHIFT) |
847 				    (MC_LM(mc_decode) << MC_LM_SHIFT);
848 
849 				phys_banks[*b_idx].masr_addr = addr;
850 				phys_banks[*b_idx].masr = 0;	/* unused */
851 				phys_banks[*b_idx].asi = ASI_MEM;
852 				(*b_idx)++;
853 			}
854 			break;
855 		case PANTHER_IMPL:
856 			if (mc_get_idle_reg(memnodes[i], &addr, &asi)) {
857 				return (-1);
858 			}
859 
860 			mc_idle_regs[*r_idx].addr = addr;
861 			mc_idle_regs[*r_idx].asi = asi;
862 			mc_idle_regs[*r_idx].node = memnodes[i];
863 			mc_idle_regs[*r_idx].bd_id = bp->bd;
864 			(*r_idx)++;
865 			break;
866 		default:
867 			cmn_err(CE_WARN, "Unknown cpu implementation=0x%x",
868 			    impl);
869 			ASSERT(0);
870 			return (-1);
871 		}
872 	}
873 
874 	return (0);
875 }
876 
877 /*
878  * For non-Panther MCs that do not support read-bypass-write, we do a read
879  * to each physical bank, relying on the reads to block until all outstanding
880  * write requests have completed.  This mechanism is referred to as the bus
881  * sync list and is used for Cheetah, Cheetah+, and Jaguar processors.  The
882  * bus sync list PAs for the source and target are kept together and comprise
883  * Section 1 of the rename script.
884  *
885  * For Panther processors that support the EMU Activity Status register,
886  * we ensure the writes have completed by polling the MCU_ACT_STATUS
887  * field several times to make sure the MC queues are empty.  The
888  * EMU Activity Status register PAs for the source and target are
889  * kept together and comprise Section 2 of the rename script.
890  */
891 static int
892 sbdp_prep_mc_idle_script(sbdp_bd_t *s_bp, sbdp_bd_t *t_bp,
893     sbdp_rename_script_t *rsp, int *rsp_idx)
894 {
895 	sbdp_rename_script_t *phys_banks;
896 	sbdp_mc_idle_script_t *mc_idle_regs;
897 	int	max_banks, max_regs;
898 	size_t	bsize, msize;
899 	int	nbanks = 0, nregs = 0;
900 	int	i;
901 
902 	/* CONSTCOND */
903 	ASSERT(sizeof (sbdp_rename_script_t) ==
904 	    sizeof (sbdp_mc_idle_script_t));
905 
906 	/* allocate space for both source and target */
907 	max_banks = SBDP_MAX_MEM_NODES_PER_BOARD *
908 	    SG_MAX_BANKS_PER_MC * 2;
909 	max_regs = SBDP_MAX_MEM_NODES_PER_BOARD * 2;
910 
911 	bsize = sizeof (sbdp_rename_script_t) * max_banks;
912 	msize = sizeof (sbdp_mc_idle_script_t) * max_regs;
913 
914 	phys_banks = kmem_zalloc(bsize, KM_SLEEP);
915 	mc_idle_regs = kmem_zalloc(msize, KM_SLEEP);
916 
917 	if (sbdp_prep_mc_idle_one(t_bp, phys_banks, &nbanks,
918 	    mc_idle_regs, &nregs) != 0 ||
919 	    sbdp_prep_mc_idle_one(s_bp, phys_banks, &nbanks,
920 	    mc_idle_regs, &nregs) != 0) {
921 		kmem_free(phys_banks, bsize);
922 		kmem_free(mc_idle_regs, msize);
923 		return (-1);
924 	}
925 
926 	/* section 1 */
927 	for (i = 0; i < nbanks; i++)
928 		rsp[(*rsp_idx)++] = phys_banks[i];
929 
930 	/* section 2 */
931 	for (i = 0; i < nregs; i++)
932 		rsp[(*rsp_idx)++] = *(sbdp_rename_script_t *)&mc_idle_regs[i];
933 
934 	kmem_free(phys_banks, bsize);
935 	kmem_free(mc_idle_regs, msize);
936 
937 	return (0);
938 }
939 
940 /*
941  * code assumes single mem-unit.
942  */
943 static int
944 sbdp_prep_rename_script(sbdp_cr_handle_t *cph)
945 {
946 	pnode_t			*s_nodes, *t_nodes;
947 	int			m = 0, i;
948 	sbdp_bd_t		s_bd, t_bd, *s_bdp, *t_bdp;
949 	sbdp_rename_script_t	*rsp;
950 	uint64_t		new_base, old_base, temp_base;
951 	int			s_num, t_num;
952 
953 	mutex_enter(&cph->s_bdp->bd_mutex);
954 	s_bd = *cph->s_bdp;
955 	mutex_exit(&cph->s_bdp->bd_mutex);
956 	mutex_enter(&cph->t_bdp->bd_mutex);
957 	t_bd = *cph->t_bdp;
958 	mutex_exit(&cph->t_bdp->bd_mutex);
959 
960 	s_bdp = &s_bd;
961 	t_bdp = &t_bd;
962 	s_nodes = s_bdp->nodes;
963 	t_nodes = t_bdp->nodes;
964 	s_num = s_bdp->nnum;
965 	t_num = t_bdp->nnum;
966 	rsp = cph->script;
967 
968 	/*
969 	 * Calculate the new base address for the target bd
970 	 */
971 
972 	new_base = (s_bdp->bpa >> PHYS2UM_SHIFT) << MC_UM_SHIFT;
973 
974 	/*
975 	 * Calculate the old base address for the source bd
976 	 */
977 
978 	old_base = (t_bdp->bpa >> PHYS2UM_SHIFT) << MC_UM_SHIFT;
979 
980 	temp_base = SG_INVAL_UM;
981 
982 	SBDP_DBG_MEM("new 0x%lx old_base ox%lx temp_base 0x%lx\n", new_base,
983 	    old_base, temp_base);
984 
985 	m = 0;
986 
987 	/*
988 	 * Ensure the MC queues have been idled on the source and target
989 	 * following the copy.
990 	 */
991 	if (sbdp_prep_mc_idle_script(s_bdp, t_bdp, rsp, &m) < 0)
992 		return (-1);
993 
994 	/*
995 	 * Script section terminator
996 	 */
997 	rsp[m].masr_addr = 0ull;
998 	rsp[m].masr = 0;
999 	rsp[m].asi = 0;
1000 	m++;
1001 
1002 	/*
1003 	 * Invalidate the base in the target mc registers
1004 	 */
1005 	for (i = 0; i < t_num; i++) {
1006 		if (sbdp_copy_regs(t_nodes[i], t_bdp->bpa, temp_base, 1, rsp,
1007 		    &m) < 0)
1008 			return (-1);
1009 	}
1010 	/*
1011 	 * Invalidate the base in the source mc registers
1012 	 */
1013 	for (i = 0; i < s_num; i++) {
1014 		if (sbdp_copy_regs(s_nodes[i], s_bdp->bpa, temp_base, 1, rsp,
1015 		    &m) < 0)
1016 			return (-1);
1017 	}
1018 	/*
1019 	 * Copy the new base into the targets mc registers
1020 	 */
1021 	for (i = 0; i < t_num; i++) {
1022 		if (sbdp_copy_regs(t_nodes[i], t_bdp->bpa, new_base, 0, rsp,
1023 		    &m) < 0)
1024 			return (-1);
1025 	}
1026 	/*
1027 	 * Copy the old base into the source mc registers
1028 	 */
1029 	for (i = 0; i < s_num; i++) {
1030 		if (sbdp_copy_regs(s_nodes[i], s_bdp->bpa, old_base, 0, rsp,
1031 		    &m) < 0)
1032 			return (-1);
1033 	}
1034 	/*
1035 	 * Zero masr_addr value indicates the END.
1036 	 */
1037 	rsp[m].masr_addr = 0ull;
1038 	rsp[m].masr = 0;
1039 	rsp[m].asi = 0;
1040 	m++;
1041 
1042 #ifdef DEBUG
1043 	{
1044 		int	i;
1045 
1046 		SBDP_DBG_MEM("dumping copy-rename script:\n");
1047 		for (i = 0; i < m; i++) {
1048 			SBDP_DBG_MEM("0x%lx = 0x%lx, asi 0x%x\n",
1049 				rsp[i].masr_addr, rsp[i].masr, rsp[i].asi);
1050 		}
1051 		DELAY(1000000);
1052 	}
1053 #endif /* DEBUG */
1054 
1055 	return (m * sizeof (sbdp_rename_script_t));
1056 }
1057 
1058 /*
1059  * EMU Activity Status Register needs to be read idle several times.
1060  * See Panther PRM 12.5.
1061  */
1062 #define	SBDP_MCU_IDLE_RETRIES	10
1063 #define	SBDP_MCU_IDLE_READS	3
1064 
1065 /*
1066  * Using the "__relocatable" suffix informs DTrace providers (and anything
1067  * else, for that matter) that this function's text may be manually relocated
1068  * elsewhere before it is executed.  That is, it cannot be safely instrumented
1069  * with any methodology that is PC-relative.
1070  */
1071 static int
1072 sbdp_copy_rename__relocatable(sbdp_cr_handle_t *hp, struct memlist *mlist,
1073 		register sbdp_rename_script_t *rsp)
1074 {
1075 	sbdp_cr_err_t	err = SBDP_CR_OK;
1076 	size_t		csize;
1077 	size_t		linesize;
1078 	uint_t		size;
1079 	uint64_t	caddr;
1080 	uint64_t	s_base, t_base;
1081 	sbdp_bd_t	*s_sbp, *t_sbp;
1082 	struct memlist	*ml;
1083 	sbdp_mc_idle_script_t *isp;
1084 	int		i;
1085 
1086 	caddr = ecache_flushaddr;
1087 	csize = (size_t)(cpunodes[CPU->cpu_id].ecache_size * 2);
1088 	linesize = (size_t)(cpunodes[CPU->cpu_id].ecache_linesize);
1089 
1090 	size = 0;
1091 	s_sbp = hp->s_bdp;
1092 	t_sbp = hp->t_bdp;
1093 
1094 	s_base = (uint64_t)s_sbp->bpa;
1095 	t_base = (uint64_t)t_sbp->bpa;
1096 
1097 	hp->ret = s_base;
1098 	/*
1099 	 * DO COPY.
1100 	 */
1101 	for (ml = mlist; ml; ml = ml->next) {
1102 		uint64_t	s_pa, t_pa;
1103 		uint64_t	nbytes;
1104 
1105 		s_pa = ml->address;
1106 		t_pa = t_base + (ml->address - s_base);
1107 		nbytes = ml->size;
1108 
1109 		size += nbytes;
1110 		while (nbytes != 0ull) {
1111 			/*
1112 			 * This copy does NOT use an ASI
1113 			 * that avoids the Ecache, therefore
1114 			 * the dst_pa addresses may remain
1115 			 * in our Ecache after the dst_pa
1116 			 * has been removed from the system.
1117 			 * A subsequent write-back to memory
1118 			 * will cause an ARB-stop because the
1119 			 * physical address no longer exists
1120 			 * in the system. Therefore we must
1121 			 * flush out local Ecache after we
1122 			 * finish the copy.
1123 			 */
1124 
1125 			/* copy 32 bytes at src_pa to dst_pa */
1126 			bcopy32_il(s_pa, t_pa);
1127 
1128 			/* increment by 32 bytes */
1129 			s_pa += (4 * sizeof (uint64_t));
1130 			t_pa += (4 * sizeof (uint64_t));
1131 
1132 			/* decrement by 32 bytes */
1133 			nbytes -= (4 * sizeof (uint64_t));
1134 		}
1135 	}
1136 
1137 	/*
1138 	 * Since bcopy32_il() does NOT use an ASI to bypass
1139 	 * the Ecache, we need to flush our Ecache after
1140 	 * the copy is complete.
1141 	 */
1142 	flush_ecache_il(caddr, csize, linesize);	/* inline version */
1143 
1144 	/*
1145 	 * Non-Panther MCs are idled by reading each physical bank.
1146 	 */
1147 	for (i = 0; rsp[i].asi == ASI_MEM; i++) {
1148 		(void) lddphys_il(rsp[i].masr_addr);
1149 	}
1150 
1151 	isp = (sbdp_mc_idle_script_t *)&rsp[i];
1152 
1153 	/*
1154 	 * Panther MCs are idled by polling until the MCU idle state
1155 	 * is read SBDP_MCU_IDLE_READS times in succession.
1156 	 */
1157 	while (isp->addr != 0ull) {
1158 		for (i = 0; i < SBDP_MCU_IDLE_RETRIES; i++) {
1159 			register uint64_t v;
1160 			register int n_idle = 0;
1161 
1162 
1163 			do {
1164 				v = ldxasi_il(isp->addr, isp->asi) &
1165 				    MCU_ACT_STATUS;
1166 			} while (v != MCU_ACT_STATUS &&
1167 			    ++n_idle < SBDP_MCU_IDLE_READS);
1168 
1169 			if (n_idle == SBDP_MCU_IDLE_READS)
1170 				break;
1171 		}
1172 
1173 		if (i == SBDP_MCU_IDLE_RETRIES) {
1174 			/* bailout */
1175 			hp->busy_mc = isp;
1176 			return (SBDP_CR_MC_IDLE_ERR);
1177 		}
1178 
1179 		isp++;
1180 	}
1181 
1182 	/* skip terminator */
1183 	isp++;
1184 
1185 	/*
1186 	 * The following inline assembly routine caches
1187 	 * the rename script and then caches the code that
1188 	 * will do the rename.  This is necessary
1189 	 * so that we don't have any memory references during
1190 	 * the reprogramming.  We accomplish this by first
1191 	 * jumping through the code to guarantee it's cached
1192 	 * before we actually execute it.
1193 	 */
1194 	sbdp_exec_script_il((sbdp_rename_script_t *)isp);
1195 
1196 	return (err);
1197 }
1198 static void
1199 _sbdp_copy_rename_end(void)
1200 {
1201 	/*
1202 	 * IMPORTANT:   This function's location MUST be located immediately
1203 	 *		following sbdp_copy_rename__relocatable to accurately
1204 	 *		estimate its size.  Note that this assumes (!)the
1205 	 *		compiler keeps these functions in the order in which
1206 	 *		they appear :-o
1207 	 */
1208 }
1209 int
1210 sbdp_memory_rename(sbdp_handle_t *hp)
1211 {
1212 #ifdef lint
1213 	/*
1214 	 * Delete when implemented
1215 	 */
1216 	hp = hp;
1217 #endif
1218 	return (0);
1219 }
1220 
1221 
1222 /*
1223  * In Serengeti this is a nop
1224  */
1225 int
1226 sbdp_post_configure_mem(sbdp_handle_t *hp)
1227 {
1228 #ifdef lint
1229 	hp = hp;
1230 #endif
1231 	return (0);
1232 }
1233 
1234 /*
1235  * In Serengeti this is a nop
1236  */
1237 int
1238 sbdp_post_unconfigure_mem(sbdp_handle_t *hp)
1239 {
1240 #ifdef lint
1241 	hp = hp;
1242 #endif
1243 	return (0);
1244 }
1245 
1246 /* ARGSUSED */
1247 int
1248 sbdphw_disable_memctrl(sbdp_handle_t *hp, dev_info_t *dip)
1249 {
1250 	return (0);
1251 }
1252 
1253 /* ARGSUSED */
1254 int
1255 sbdphw_enable_memctrl(sbdp_handle_t *hp, dev_info_t *dip)
1256 {
1257 	return (0);
1258 }
1259 
1260 /*
1261  * We are assuming one memory node therefore the base address is the lowest
1262  * segment possible
1263  */
1264 #define	PA_ABOVE_MAX	(0x8000000000000000ull)
1265 int
1266 sbdphw_get_base_physaddr(sbdp_handle_t *hp, dev_info_t *dip, uint64_t *pa)
1267 {
1268 	_NOTE(ARGUNUSED(hp))
1269 
1270 	int i, board = -1, wnode;
1271 	pnode_t	nodeid;
1272 	struct mem_arg arg = {0};
1273 	uint64_t seg_pa, tmp_pa;
1274 	dev_info_t *list[SBDP_MAX_MEM_NODES_PER_BOARD];
1275 	int rc;
1276 
1277 	if (dip == NULL)
1278 		return (-1);
1279 
1280 	nodeid = ddi_get_nodeid(dip);
1281 
1282 	if (sbdp_get_bd_and_wnode_num(nodeid, &board, &wnode) < 0)
1283 		return (-1);
1284 
1285 	list[0] = NULL;
1286 	arg.board = board;
1287 	arg.list = list;
1288 
1289 	(void) sbdp_walk_prom_tree(prom_rootnode(), sbdp_get_mem_dip, &arg);
1290 
1291 	if (arg.ndips <= 0)
1292 		return (-1);
1293 
1294 	seg_pa = PA_ABOVE_MAX;
1295 
1296 	rc = -1;
1297 	for (i = 0; i < arg.ndips; i++) {
1298 		if (list[i] == NULL)
1299 			continue;
1300 		if (sbdp_get_lowest_addr_in_node(ddi_get_nodeid(list[i]),
1301 		    &tmp_pa) == 0) {
1302 			rc = 0;
1303 			if (tmp_pa < seg_pa)
1304 				seg_pa = tmp_pa;
1305 		}
1306 
1307 		/*
1308 		 * Release hold acquired in sbdp_get_mem_dip()
1309 		 */
1310 		ddi_release_devi(list[i]);
1311 	}
1312 
1313 	if (rc == 0)
1314 		*pa = seg_pa;
1315 	else {
1316 		/*
1317 		 * Record the fact that an error has occurred
1318 		 */
1319 		sbdp_set_err(hp->h_err, ESGT_INTERNAL, NULL);
1320 	}
1321 
1322 	return (rc);
1323 }
1324 
1325 static int
1326 sbdp_get_lowest_addr_in_node(pnode_t node, uint64_t *pa)
1327 {
1328 	uint64_t	mc_decode, seg_pa, tmp_pa;
1329 	mc_regs_t	mc_regs, *mc_regsp = &mc_regs;
1330 	int		i, valid;
1331 	int		rc;
1332 
1333 
1334 	seg_pa = PA_ABOVE_MAX;
1335 
1336 	if (mc_read_regs(node, mc_regsp)) {
1337 		SBDP_DBG_MEM("sbdp_get_lowest_addr_in_node: failed to "
1338 		    "read source Decode Regs\n");
1339 		return (-1);
1340 	}
1341 
1342 	rc = -1;
1343 	for (i = 0; i < SBDP_MAX_MCS_PER_NODE; i++) {
1344 		mc_decode = mc_regsp->mc_decode[i];
1345 		valid = mc_decode >> MC_VALID_SHIFT;
1346 		tmp_pa = MC_BASE(mc_decode) << PHYS2UM_SHIFT;
1347 		if (valid)
1348 			rc = 0;
1349 		if (valid && (tmp_pa < seg_pa))
1350 			seg_pa = tmp_pa;
1351 	}
1352 
1353 	if (rc == 0)
1354 		*pa = seg_pa;
1355 
1356 	return (rc);
1357 }
1358 
1359 int
1360 sbdp_is_mem(pnode_t node, void *arg)
1361 {
1362 	mem_op_t	*memp = (mem_op_t *)arg;
1363 	char		type[OBP_MAXPROPNAME];
1364 	int		bd;
1365 	pnode_t		*list;
1366 	int		board;
1367 	char		name[OBP_MAXDRVNAME];
1368 	int		len;
1369 
1370 	ASSERT(memp);
1371 
1372 	list = memp->nodes;
1373 	board = memp->board;
1374 
1375 	/*
1376 	 * Make sure that this node doesn't have its status
1377 	 * as failed
1378 	 */
1379 	if (sbdp_get_comp_status(node) != SBD_COND_OK) {
1380 		return (DDI_FAILURE);
1381 	}
1382 
1383 	len = prom_getproplen(node, "device_type");
1384 	if ((len > 0) && (len < OBP_MAXPROPNAME))
1385 		(void) prom_getprop(node, "device_type", (caddr_t)type);
1386 	else
1387 		type[0] = '\0';
1388 
1389 	if (strcmp(type, "memory-controller") == 0) {
1390 		int	wnode;
1391 
1392 		if (sbdp_get_bd_and_wnode_num(node, &bd, &wnode) < 0)
1393 			return (DDI_FAILURE);
1394 
1395 		if (bd == board) {
1396 			/*
1397 			 * Make sure we don't overwrite the array
1398 			 */
1399 			if (memp->nmem >= SBDP_MAX_MEM_NODES_PER_BOARD)
1400 				return (DDI_FAILURE);
1401 			(void) prom_getprop(node, OBP_NAME, (caddr_t)name);
1402 			SBDP_DBG_MEM("name %s  boot bd %d board %d\n", name,
1403 			    board, bd);
1404 			list[memp->nmem++] = node;
1405 			return (DDI_SUCCESS);
1406 		}
1407 	}
1408 
1409 	return (DDI_FAILURE);
1410 }
1411 
1412 static int
1413 sbdp_get_meminfo(pnode_t nodeid, int mc, uint64_t *size, uint64_t *base_pa)
1414 {
1415 	int		board, wnode;
1416 	int		valid;
1417 	mc_regs_t	mc_regs, *mc_regsp = &mc_regs;
1418 	uint64_t	mc_decode = 0;
1419 
1420 	if (sbdp_get_bd_and_wnode_num(nodeid, &board, &wnode) < 0)
1421 		return (-1);
1422 
1423 	if (mc_read_regs(nodeid, mc_regsp)) {
1424 		SBDP_DBG_MEM("sbdp_get_meminfo: failed to read source "
1425 		    "Decode Regs");
1426 		return (-1);
1427 	}
1428 	/*
1429 	 * Calculate memory size
1430 	 */
1431 	mc_decode = mc_regsp->mc_decode[mc];
1432 
1433 	/*
1434 	 * Check the valid bit to see if bank is there
1435 	 */
1436 	valid = mc_decode >> MC_VALID_SHIFT;
1437 	if (valid) {
1438 		*size = MC_UK2SPAN(mc_decode);
1439 		*base_pa = MC_BASE(mc_decode) << PHYS2UM_SHIFT;
1440 	}
1441 
1442 	return (0);
1443 }
1444 
1445 
1446 /*
1447  * Luckily for us mem nodes and cpu/CMP nodes are siblings.  All we need to
1448  * do is search in the same branch as the mem node for its sibling cpu or
1449  * CMP node.
1450  */
1451 pnode_t
1452 mc_get_sibling_cpu(pnode_t nodeid)
1453 {
1454 	int	portid;
1455 
1456 	if (prom_getprop(nodeid, OBP_PORTID, (caddr_t)&portid) < 0)
1457 		return (OBP_NONODE);
1458 
1459 	/*
1460 	 * cpus and memory are siblings so we don't need to traverse
1461 	 * the whole tree, just a branch
1462 	 */
1463 	return (sbdp_find_nearby_cpu_by_portid(nodeid, portid));
1464 }
1465 
1466 /*
1467  * Given a memory node, check it's sibling cpu or CMP to see if
1468  * access to mem will be ok. We need to search for the node and
1469  * if found get its condition.
1470  */
1471 sbd_cond_t
1472 mc_check_sibling_cpu(pnode_t nodeid)
1473 {
1474 	pnode_t	cpu_node;
1475 	sbd_cond_t	cond;
1476 	int		i;
1477 
1478 	cpu_node = mc_get_sibling_cpu(nodeid);
1479 
1480 	cond = sbdp_get_comp_status(cpu_node);
1481 
1482 	if (cond == SBD_COND_OK) {
1483 		int 		wnode;
1484 		int		bd;
1485 		int		unit;
1486 		int		portid;
1487 
1488 		if (sbdp_get_bd_and_wnode_num(nodeid, &bd, &wnode) < 0)
1489 			return (SBD_COND_UNKNOWN);
1490 
1491 		(void) prom_getprop(nodeid, OBP_PORTID, (caddr_t)&portid);
1492 
1493 		/*
1494 		 * Access to the memory controller should not
1495 		 * be attempted if any of the cores are marked
1496 		 * as being in reset.
1497 		 */
1498 		for (i = 0; i < SBDP_MAX_CORES_PER_CMP; i++) {
1499 			unit = SG_PORTID_TO_CPU_UNIT(portid, i);
1500 			if (sbdp_is_cpu_present(wnode, bd, unit) &&
1501 			    sbdp_is_cpu_in_reset(wnode, bd, unit)) {
1502 				cond = SBD_COND_UNUSABLE;
1503 				break;
1504 			}
1505 		}
1506 	}
1507 
1508 	return (cond);
1509 }
1510 
1511 int
1512 mc_read_regs(pnode_t nodeid, mc_regs_t *mc_regsp)
1513 {
1514 	int			len;
1515 	uint64_t		mc_addr, mask;
1516 	mc_regspace		reg;
1517 	sbd_cond_t		sibling_cpu_cond;
1518 	int			local_mc;
1519 	int			portid;
1520 	int			i;
1521 
1522 	if ((prom_getprop(nodeid, "portid", (caddr_t)&portid) < 0) ||
1523 	    (portid == -1))
1524 		return (-1);
1525 
1526 	/*
1527 	 * mc should not be accessed if their corresponding cpu
1528 	 * has failed.
1529 	 */
1530 	sibling_cpu_cond = mc_check_sibling_cpu(nodeid);
1531 
1532 	if ((sibling_cpu_cond == SBD_COND_FAILED) ||
1533 	    (sibling_cpu_cond == SBD_COND_UNUSABLE)) {
1534 		return (-1);
1535 	}
1536 
1537 	len = prom_getproplen(nodeid, "reg");
1538 	if (len != sizeof (mc_regspace))
1539 		return (-1);
1540 
1541 	if (prom_getprop(nodeid, "reg", (caddr_t)&reg) < 0)
1542 		return (-1);
1543 
1544 	mc_addr = ((uint64_t)reg.regspec_addr_hi) << 32;
1545 	mc_addr |= (uint64_t)reg.regspec_addr_lo;
1546 
1547 	/*
1548 	 * Make sure we don't switch cpus
1549 	 */
1550 	affinity_set(CPU_CURRENT);
1551 	if (portid == cpunodes[CPU->cpu_id].portid)
1552 		local_mc = 1;
1553 	else
1554 		local_mc = 0;
1555 
1556 	for (i = 0; i < SG_MAX_BANKS_PER_MC; i++) {
1557 		mask = SG_REG_2_OFFSET(i);
1558 
1559 		/*
1560 		 * If the memory controller is local to this CPU, we use
1561 		 * the special ASI to read the decode registers.
1562 		 * Otherwise, we load the values from a magic address in
1563 		 * I/O space.
1564 		 */
1565 		if (local_mc) {
1566 			mc_regsp->mc_decode[i] = lddmcdecode(
1567 			    mask & MC_OFFSET_MASK);
1568 		} else {
1569 			mc_regsp->mc_decode[i] = lddphysio(
1570 			    (mc_addr | mask));
1571 		}
1572 	}
1573 	affinity_clear();
1574 
1575 	return (0);
1576 }
1577 
1578 uint64_t
1579 mc_get_addr(pnode_t nodeid, int mc, uint_t *asi)
1580 {
1581 	int			len;
1582 	uint64_t		mc_addr, addr;
1583 	mc_regspace		reg;
1584 	int			portid;
1585 	int			local_mc;
1586 
1587 	if ((prom_getprop(nodeid, "portid", (caddr_t)&portid) < 0) ||
1588 	    (portid == -1))
1589 		return (-1);
1590 
1591 	len = prom_getproplen(nodeid, "reg");
1592 	if (len != sizeof (mc_regspace))
1593 		return (-1);
1594 
1595 	if (prom_getprop(nodeid, "reg", (caddr_t)&reg) < 0)
1596 		return (-1);
1597 
1598 	mc_addr = ((uint64_t)reg.regspec_addr_hi) << 32;
1599 	mc_addr |= (uint64_t)reg.regspec_addr_lo;
1600 
1601 	/*
1602 	 * Make sure we don't switch cpus
1603 	 */
1604 	affinity_set(CPU_CURRENT);
1605 	if (portid == cpunodes[CPU->cpu_id].portid)
1606 		local_mc = 1;
1607 	else
1608 		local_mc = 0;
1609 
1610 	if (local_mc) {
1611 		*asi = ASI_MC_DECODE;
1612 		addr = SG_REG_2_OFFSET(mc) & MC_OFFSET_MASK;
1613 	} else {
1614 		*asi = ASI_IO;
1615 		addr = SG_REG_2_OFFSET(mc) | mc_addr;
1616 	}
1617 	affinity_clear();
1618 
1619 	return (addr);
1620 }
1621 
1622 /* ARGSUSED */
1623 int
1624 sbdp_mem_add_span(sbdp_handle_t *hp, uint64_t address, uint64_t size)
1625 {
1626 	return (0);
1627 }
1628 
1629 int
1630 sbdp_mem_del_span(sbdp_handle_t *hp, uint64_t address, uint64_t size)
1631 {
1632 	pfn_t		 basepfn = (pfn_t)(address >> PAGESHIFT);
1633 	pgcnt_t		 npages = (pgcnt_t)(size >> PAGESHIFT);
1634 
1635 	if (size > 0) {
1636 		int rv;
1637 		kcage_range_lock();
1638 		rv = kcage_range_delete_post_mem_del(basepfn, npages);
1639 		kcage_range_unlock();
1640 		if (rv != 0) {
1641 			cmn_err(CE_WARN,
1642 			    "unexpected kcage_range_delete_post_mem_del"
1643 			    " return value %d", rv);
1644 			sbdp_set_err(hp->h_err, ESGT_INTERNAL, NULL);
1645 			return (-1);
1646 		}
1647 	}
1648 	return (0);
1649 }
1650 
1651 /*
1652  * This routine gets the size including the
1653  * bad banks
1654  */
1655 int
1656 sbdp_get_mem_size(sbdp_handle_t *hp)
1657 {
1658 	uint64_t	size = 0;
1659 	struct memlist	*mlist, *ml;
1660 
1661 	mlist = sbdp_get_memlist(hp, (dev_info_t *)NULL);
1662 
1663 	for (ml = mlist; ml; ml = ml->next)
1664 		size += ml->size;
1665 
1666 	(void) sbdp_del_memlist(hp, mlist);
1667 
1668 	SBDP_DBG_MEM("sbdp_get_mem_size: size 0x%" PRIx64 "\n", size);
1669 
1670 	return (btop(size));
1671 }
1672 
1673 /*
1674  * This function compares the list of banks passed with the banks
1675  * in the segment
1676  */
1677 int
1678 sbdp_check_seg_with_banks(sbdp_seg_t *seg, sbdp_bank_t *banks)
1679 {
1680 	sbdp_bank_t	*cur_bank, *bank;
1681 	int		i = 0;
1682 
1683 	for (cur_bank = seg->banks; cur_bank; cur_bank = cur_bank->seg_next) {
1684 		for (bank = banks; bank; bank = bank->bd_next) {
1685 			if (!bank->valid)
1686 				continue;
1687 
1688 			if (cur_bank == bank) {
1689 				i++;
1690 			}
1691 		}
1692 	}
1693 
1694 	SBDP_DBG_MEM("banks found = %d total banks = %d\n", i, seg->nbanks);
1695 	/*
1696 	 * If we find the same num of banks that are equal, then this segment
1697 	 * is not interleaved across boards
1698 	 */
1699 	if (i == seg->nbanks)
1700 		return (0);
1701 
1702 	return (1);
1703 }
1704 
1705 
1706 /*
1707  * This routine determines if any of the memory banks on the board
1708  * participate in across board memory interleaving
1709  */
1710 int
1711 sbdp_isinterleaved(sbdp_handle_t *hp, dev_info_t *dip)
1712 {
1713 	_NOTE(ARGUNUSED(dip))
1714 
1715 	sbdp_bank_t	*bankp;
1716 	int		wnode, board;
1717 	int		is_interleave = 0;
1718 	sbdp_bd_t	*bdp;
1719 	uint64_t	base;
1720 	sbdp_seg_t	*seg;
1721 
1722 	board = hp->h_board;
1723 	wnode = hp->h_wnode;
1724 
1725 #ifdef DEBUG
1726 	sbdp_print_all_segs();
1727 #endif
1728 	/*
1729 	 * Get the banks for this board
1730 	 */
1731 	bdp = sbdp_get_bd_info(wnode, board);
1732 
1733 	if (bdp == NULL)
1734 		return (-1);
1735 
1736 	/*
1737 	 * Search for the first bank with valid memory
1738 	 */
1739 	for (bankp = bdp->banks; bankp; bankp = bankp->bd_next)
1740 		if (bankp->valid)
1741 			break;
1742 
1743 	/*
1744 	 * If there are no banks in the board, then the board is
1745 	 * not interleaved across boards
1746 	 */
1747 	if (bankp == NULL) {
1748 		return (0);
1749 	}
1750 
1751 	base = bankp->um & ~(bankp->uk);
1752 
1753 	/*
1754 	 * Find the segment for the first bank
1755 	 */
1756 	if ((seg = sbdp_get_seg(base)) == NULL) {
1757 		/*
1758 		 * Something bad has happened.
1759 		 */
1760 		return (-1);
1761 	}
1762 	/*
1763 	 * Make sure that this segment is only composed of the banks
1764 	 * in this board. If one is missing or we have an extra one
1765 	 * the board is interleaved across boards
1766 	 */
1767 	is_interleave = sbdp_check_seg_with_banks(seg, bdp->banks);
1768 
1769 	SBDP_DBG_MEM("interleave is %d\n", is_interleave);
1770 
1771 	return (is_interleave);
1772 }
1773 
1774 
1775 /*
1776  * Each node has 4 logical banks.  This routine adds all the banks (including
1777  * the invalid ones to the passed list. Note that we use the bd list and not
1778  * the seg list
1779  */
1780 int
1781 sbdp_add_nodes_banks(pnode_t node, sbdp_bank_t **banks)
1782 {
1783 	int		i;
1784 	mc_regs_t	regs;
1785 	uint64_t	*mc_decode;
1786 	sbdp_bank_t 	*bank;
1787 
1788 	if (mc_read_regs(node, &regs) == -1)
1789 		return (-1);
1790 
1791 	mc_decode = regs.mc_decode;
1792 
1793 	for (i = 0; i < SBDP_MAX_MCS_PER_NODE; i++) {
1794 		/*
1795 		 * This creates the mem for the new member of the list
1796 		 */
1797 		sbdp_fill_bank_info(mc_decode[i], &bank);
1798 
1799 		SBDP_DBG_MEM("adding bank %d\n", bank->id);
1800 
1801 		/*
1802 		 * Insert bank into the beginning of the list
1803 		 */
1804 		bank->bd_next = *banks;
1805 		*banks = bank;
1806 
1807 		/*
1808 		 * Add this bank into its corresponding
1809 		 * segment
1810 		 */
1811 		sbdp_add_bank_to_seg(bank);
1812 	}
1813 	return (0);
1814 }
1815 
1816 /*
1817  * given the info, create a new bank node and set the info
1818  * as appropriate. We allocate the memory for the bank. It is
1819  * up to the caller to ensure the mem is freed
1820  */
1821 void
1822 sbdp_fill_bank_info(uint64_t mc_decode, sbdp_bank_t **bank)
1823 {
1824 	static int	id = 0;
1825 	sbdp_bank_t	*new;
1826 
1827 	new = kmem_zalloc(sizeof (sbdp_bank_t), KM_SLEEP);
1828 
1829 	new->id = id++;
1830 	new->valid = (mc_decode >> MC_VALID_SHIFT);
1831 	new->uk = MC_UK(mc_decode);
1832 	new->um = MC_UM(mc_decode);
1833 	new->lk = MC_LK(mc_decode);
1834 	new->lm = MC_LM(mc_decode);
1835 	new->bd_next = NULL;
1836 	new->seg_next = NULL;
1837 
1838 	*bank = new;
1839 }
1840 
1841 /*
1842  * Each bd has the potential of having mem banks on it.  The banks
1843  * may be empty or not.  This routine gets all the mem banks
1844  * for this bd
1845  */
1846 void
1847 sbdp_init_bd_banks(sbdp_bd_t *bdp)
1848 {
1849 	int		i, nmem;
1850 	pnode_t		*lists;
1851 
1852 	lists = bdp->nodes;
1853 	nmem = bdp->nnum;
1854 
1855 	if (bdp->banks != NULL) {
1856 		return;
1857 	}
1858 
1859 	bdp->banks = NULL;
1860 
1861 	for (i = 0; i < nmem; i++) {
1862 		(void) sbdp_add_nodes_banks(lists[i], &bdp->banks);
1863 	}
1864 }
1865 
1866 /*
1867  * swap the list of banks for the 2 boards
1868  */
1869 void
1870 sbdp_swap_list_of_banks(sbdp_bd_t *bdp1, sbdp_bd_t *bdp2)
1871 {
1872 	sbdp_bank_t	*tmp_ptr;
1873 
1874 	if ((bdp1 == NULL) || (bdp2 == NULL))
1875 		return;
1876 
1877 	tmp_ptr = bdp1->banks;
1878 	bdp1->banks = bdp2->banks;
1879 	bdp2->banks = tmp_ptr;
1880 }
1881 
1882 /*
1883  * free all the banks on the board.  Note that a bank node belongs
1884  * to 2 lists. The first list is the board list. The second one is
1885  * the seg list. We only need to remove the bank from both lists but only
1886  * free the node once.
1887  */
1888 void
1889 sbdp_fini_bd_banks(sbdp_bd_t *bdp)
1890 {
1891 	sbdp_bank_t	*bkp, *nbkp;
1892 
1893 	for (bkp = bdp->banks; bkp; ) {
1894 		/*
1895 		 * Remove the bank from the seg list first
1896 		 */
1897 		SBDP_DBG_MEM("Removing bank %d\n", bkp->id);
1898 		sbdp_remove_bank_from_seg(bkp);
1899 		nbkp = bkp->bd_next;
1900 		bkp->bd_next = NULL;
1901 		kmem_free(bkp, sizeof (sbdp_bank_t));
1902 
1903 		bkp = nbkp;
1904 	}
1905 	bdp->banks = NULL;
1906 }
1907 
1908 #ifdef DEBUG
1909 void
1910 sbdp_print_bd_banks(sbdp_bd_t *bdp)
1911 {
1912 	sbdp_bank_t	*bp;
1913 	int		i;
1914 
1915 	SBDP_DBG_MEM("BOARD %d\n", bdp->bd);
1916 
1917 	for (bp = bdp->banks, i = 0; bp; bp = bp->bd_next, i++) {
1918 		SBDP_DBG_MEM("BANK [%d]:\n", bp->id);
1919 		SBDP_DBG_MEM("\tvalid %d\tuk 0x%x\tum 0x%x\tlk 0x%x"
1920 		    "\tlm 0x%x\n", bp->valid, bp->uk, bp->um,
1921 		    bp->lk, bp->lm);
1922 	}
1923 }
1924 
1925 void
1926 sbdp_print_all_segs(void)
1927 {
1928 	sbdp_seg_t	*cur_seg;
1929 
1930 	for (cur_seg = sys_seg; cur_seg; cur_seg = cur_seg->next)
1931 		sbdp_print_seg(cur_seg);
1932 }
1933 
1934 void
1935 sbdp_print_seg(sbdp_seg_t *seg)
1936 {
1937 	sbdp_bank_t	*bp;
1938 	int		i;
1939 
1940 	SBDP_DBG_MEM("SEG %d\n", seg->id);
1941 
1942 	for (bp = seg->banks, i = 0; bp; bp = bp->seg_next, i++) {
1943 		SBDP_DBG_MEM("BANK [%d]:\n", bp->id);
1944 		SBDP_DBG_MEM("\tvalid %d\tuk 0x%x\tum 0x%x\tlk 0x%x"
1945 		    "\tlm 0x%x\n", bp->valid, bp->uk, bp->um,
1946 		    bp->lk, bp->lm);
1947 	}
1948 }
1949 #endif
1950 
1951 void
1952 sbdp_add_bank_to_seg(sbdp_bank_t *bank)
1953 {
1954 	uint64_t	base;
1955 	sbdp_seg_t	*cur_seg;
1956 	static int	id = 0;
1957 
1958 	/*
1959 	 * if we got an invalid bank just skip it
1960 	 */
1961 	if (bank == NULL || !bank->valid)
1962 		return;
1963 	base = bank->um & ~(bank->uk);
1964 
1965 	if ((cur_seg = sbdp_get_seg(base)) == NULL) {
1966 		/*
1967 		 * This bank is part of a new segment, so create
1968 		 * a struct for it and added to the list of segments
1969 		 */
1970 		cur_seg = kmem_zalloc(sizeof (sbdp_seg_t), KM_SLEEP);
1971 		cur_seg->id = id++;
1972 		cur_seg->base = base;
1973 		cur_seg->size = ((bank->uk +1) << PHYS2UM_SHIFT);
1974 		cur_seg->intlv = ((bank->lk ^ 0xF) + 1);
1975 		/*
1976 		 * add to the seg list
1977 		 */
1978 		cur_seg->next = sys_seg;
1979 		sys_seg = cur_seg;
1980 	}
1981 
1982 	cur_seg->nbanks++;
1983 	/*
1984 	 * add bank into segs bank list.  Note we add at the head
1985 	 */
1986 	bank->seg_next = cur_seg->banks;
1987 	cur_seg->banks = bank;
1988 }
1989 
1990 /*
1991  * Remove this segment from the seg list
1992  */
1993 void
1994 sbdp_rm_seg(sbdp_seg_t *seg)
1995 {
1996 	sbdp_seg_t	**curpp, *curp;
1997 
1998 	curpp = &sys_seg;
1999 
2000 	while ((curp = *curpp) != NULL) {
2001 		if (curp == seg) {
2002 			*curpp = curp->next;
2003 			break;
2004 		}
2005 		curpp = &curp->next;
2006 	}
2007 
2008 	if (curp != NULL) {
2009 		kmem_free(curp, sizeof (sbdp_seg_t));
2010 		curp = NULL;
2011 	}
2012 }
2013 
2014 /*
2015  * remove this bank from its seg list
2016  */
2017 void
2018 sbdp_remove_bank_from_seg(sbdp_bank_t *bank)
2019 {
2020 	uint64_t	base;
2021 	sbdp_seg_t	*cur_seg;
2022 	sbdp_bank_t	**curpp, *curp;
2023 
2024 	/*
2025 	 * if we got an invalid bank just skip it
2026 	 */
2027 	if (bank == NULL || !bank->valid)
2028 		return;
2029 	base = bank->um & ~(bank->uk);
2030 
2031 	/*
2032 	 * If the bank doesn't belong to any seg just return
2033 	 */
2034 	if ((cur_seg = sbdp_get_seg(base)) == NULL) {
2035 		SBDP_DBG_MEM("bank %d with no segment\n", bank->id);
2036 		return;
2037 	}
2038 
2039 	/*
2040 	 * Find bank in the seg
2041 	 */
2042 	curpp = &cur_seg->banks;
2043 
2044 	while ((curp = *curpp) != NULL) {
2045 		if (curp->id == bank->id) {
2046 			/*
2047 			 * found node, remove it
2048 			 */
2049 			*curpp = curp->seg_next;
2050 			break;
2051 		}
2052 		curpp = &curp->seg_next;
2053 	}
2054 
2055 	if (curp != NULL) {
2056 		cur_seg->nbanks--;
2057 	}
2058 
2059 	if (cur_seg->nbanks == 0) {
2060 		/*
2061 		 * No banks left on this segment, remove the segment
2062 		 */
2063 		SBDP_DBG_MEM("No banks left in this segment, removing it\n");
2064 		sbdp_rm_seg(cur_seg);
2065 	}
2066 }
2067 
2068 sbdp_seg_t *
2069 sbdp_get_seg(uint64_t base)
2070 {
2071 	sbdp_seg_t	*cur_seg;
2072 
2073 	for (cur_seg = sys_seg; cur_seg; cur_seg = cur_seg->next) {
2074 		if (cur_seg-> base == base)
2075 			break;
2076 	}
2077 
2078 	return (cur_seg);
2079 }
2080 
2081 #ifdef DEBUG
2082 int
2083 sbdp_passthru_readmem(sbdp_handle_t *hp, void *arg)
2084 {
2085 	_NOTE(ARGUNUSED(hp))
2086 	_NOTE(ARGUNUSED(arg))
2087 
2088 	struct memlist	*ml;
2089 	uint64_t	src_pa;
2090 	uint64_t	dst_pa;
2091 	uint64_t	dst;
2092 
2093 
2094 	dst_pa = va_to_pa(&dst);
2095 
2096 	memlist_read_lock();
2097 	for (ml = phys_install; ml; ml = ml->next) {
2098 		uint64_t	nbytes;
2099 
2100 		src_pa = ml->address;
2101 		nbytes = ml->size;
2102 
2103 		while (nbytes != 0ull) {
2104 
2105 			/* copy 32 bytes at src_pa to dst_pa */
2106 			bcopy32_il(src_pa, dst_pa);
2107 
2108 			/* increment by 32 bytes */
2109 			src_pa += (4 * sizeof (uint64_t));
2110 
2111 			/* decrement by 32 bytes */
2112 			nbytes -= (4 * sizeof (uint64_t));
2113 		}
2114 	}
2115 	memlist_read_unlock();
2116 
2117 	return (0);
2118 }
2119 
2120 static int
2121 isdigit(int ch)
2122 {
2123 	return (ch >= '0' && ch <= '9');
2124 }
2125 
2126 #define	isspace(c)	((c) == ' ' || (c) == '\t' || (c) == '\n')
2127 
2128 int
2129 sbdp_strtoi(char *p, char **pos)
2130 {
2131 	int n;
2132 	int c, neg = 0;
2133 
2134 	if (!isdigit(c = *p)) {
2135 		while (isspace(c))
2136 			c = *++p;
2137 		switch (c) {
2138 			case '-':
2139 				neg++;
2140 				/* FALLTHROUGH */
2141 			case '+':
2142 				c = *++p;
2143 		}
2144 		if (!isdigit(c)) {
2145 			if (pos != NULL)
2146 				*pos = p;
2147 			return (0);
2148 		}
2149 	}
2150 	for (n = '0' - c; isdigit(c = *++p); ) {
2151 		n *= 10; /* two steps to avoid unnecessary overflow */
2152 		n += '0' - c; /* accum neg to avoid surprises at MAX */
2153 	}
2154 	if (pos != NULL)
2155 		*pos = p;
2156 	return (neg ? n : -n);
2157 }
2158 
2159 int
2160 sbdp_passthru_prep_script(sbdp_handle_t *hp, void *arg)
2161 {
2162 	int			board, i;
2163 	sbdp_bd_t		*t_bdp, *s_bdp;
2164 	char			*opts;
2165 	int			t_board;
2166 	sbdp_rename_script_t	*rsbuffer;
2167 	sbdp_cr_handle_t	*cph;
2168 	int			scriptlen, size;
2169 
2170 	opts = (char *)arg;
2171 	board = hp->h_board;
2172 
2173 	opts += strlen("prep-script=");
2174 	t_board = sbdp_strtoi(opts, NULL);
2175 
2176 	cph =  kmem_zalloc(sizeof (sbdp_cr_handle_t), KM_SLEEP);
2177 
2178 	size = sizeof (sbdp_rename_script_t) * SBDP_RENAME_MAXOP;
2179 	rsbuffer = kmem_zalloc(size, KM_SLEEP);
2180 
2181 	s_bdp = sbdp_get_bd_info(hp->h_wnode, board);
2182 	t_bdp = sbdp_get_bd_info(hp->h_wnode, t_board);
2183 
2184 	cph->s_bdp = s_bdp;
2185 	cph->t_bdp = t_bdp;
2186 	cph->script = rsbuffer;
2187 
2188 	affinity_set(CPU_CURRENT);
2189 	scriptlen = sbdp_prep_rename_script(cph);
2190 
2191 	if (scriptlen <= 0) {
2192 		cmn_err(CE_WARN,
2193 		"sbdp failed to prep for copy-rename");
2194 	}
2195 	prom_printf("SCRIPT from board %d to board %d ->\n", board, t_board);
2196 	for (i = 0;  i < (scriptlen / (sizeof (sbdp_rename_script_t))); i++) {
2197 		prom_printf("0x%lx = 0x%lx, asi 0x%x\n",
2198 		    rsbuffer[i].masr_addr, rsbuffer[i].masr, rsbuffer[i].asi);
2199 	}
2200 	prom_printf("\n");
2201 
2202 	affinity_clear();
2203 	kmem_free(rsbuffer, size);
2204 	kmem_free(cph, sizeof (sbdp_cr_handle_t));
2205 
2206 	return (0);
2207 }
2208 #endif
2209