103831d35Sstevel /*
203831d35Sstevel  * CDDL HEADER START
303831d35Sstevel  *
403831d35Sstevel  * The contents of this file are subject to the terms of the
503831d35Sstevel  * Common Development and Distribution License (the "License").
603831d35Sstevel  * You may not use this file except in compliance with the License.
703831d35Sstevel  *
803831d35Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
903831d35Sstevel  * or http://www.opensolaris.org/os/licensing.
1003831d35Sstevel  * See the License for the specific language governing permissions
1103831d35Sstevel  * and limitations under the License.
1203831d35Sstevel  *
1303831d35Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
1403831d35Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1503831d35Sstevel  * If applicable, add the following below this CDDL HEADER, with the
1603831d35Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
1703831d35Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
1803831d35Sstevel  *
1903831d35Sstevel  * CDDL HEADER END
2003831d35Sstevel  */
2103831d35Sstevel 
2203831d35Sstevel /*
23*56f33205SJonathan Adams  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
2403831d35Sstevel  * Use is subject to license terms.
2503831d35Sstevel  */
2603831d35Sstevel 
2703831d35Sstevel /*
2803831d35Sstevel  * memory management for serengeti dr memory
2903831d35Sstevel  */
3003831d35Sstevel 
3103831d35Sstevel #include <sys/obpdefs.h>
3203831d35Sstevel #include <sys/types.h>
3303831d35Sstevel #include <sys/conf.h>
3403831d35Sstevel #include <sys/ddi.h>
3503831d35Sstevel #include <sys/cpuvar.h>
3603831d35Sstevel #include <sys/memlist_impl.h>
3703831d35Sstevel #include <sys/machsystm.h>
3803831d35Sstevel #include <sys/promif.h>
3903831d35Sstevel #include <sys/mem_cage.h>
4003831d35Sstevel #include <sys/kmem.h>
4103831d35Sstevel #include <sys/note.h>
4203831d35Sstevel #include <sys/lgrp.h>
4303831d35Sstevel 
4403831d35Sstevel #include <sys/sbd_ioctl.h>
4503831d35Sstevel #include <sys/sbd.h>
4603831d35Sstevel #include <sys/sbdp_priv.h>
4703831d35Sstevel #include <sys/sbdp_mem.h>
4803831d35Sstevel #include <sys/sun4asi.h>
4903831d35Sstevel #include <sys/cheetahregs.h>
5003831d35Sstevel #include <sys/cpu_module.h>
5103831d35Sstevel #include <sys/esunddi.h>
5203831d35Sstevel 
5303831d35Sstevel #include <vm/page.h>
5403831d35Sstevel 
5503831d35Sstevel static int	sbdp_get_meminfo(pnode_t, int, uint64_t *, uint64_t *);
5603831d35Sstevel int		mc_read_regs(pnode_t, mc_regs_t *);
5703831d35Sstevel uint64_t	mc_get_addr(pnode_t, int, uint_t *);
5803831d35Sstevel static pnode_t	mc_get_sibling_cpu(pnode_t nodeid);
5903831d35Sstevel static int	mc_get_sibling_cpu_impl(pnode_t nodeid);
6003831d35Sstevel static sbd_cond_t mc_check_sibling_cpu(pnode_t nodeid);
6103831d35Sstevel static void	_sbdp_copy_rename_end(void);
6203831d35Sstevel static int	sbdp_copy_rename__relocatable(sbdp_cr_handle_t *,
6303831d35Sstevel 			struct memlist *, sbdp_rename_script_t *);
6403831d35Sstevel static int	sbdp_prep_rename_script(sbdp_cr_handle_t *);
6503831d35Sstevel static int	sbdp_get_lowest_addr_in_node(pnode_t, uint64_t *);
6603831d35Sstevel 
6703831d35Sstevel extern void bcopy32_il(uint64_t, uint64_t);
6803831d35Sstevel extern void flush_ecache_il(uint64_t physaddr, size_t size, size_t linesize);
6903831d35Sstevel extern uint64_t lddphys_il(uint64_t physaddr);
7003831d35Sstevel extern uint64_t ldxasi_il(uint64_t physaddr, uint_t asi);
7103831d35Sstevel extern void sbdp_exec_script_il(sbdp_rename_script_t *rsp);
7203831d35Sstevel void sbdp_fill_bank_info(uint64_t, sbdp_bank_t **);
7303831d35Sstevel int sbdp_add_nodes_banks(pnode_t node, sbdp_bank_t **banks);
7403831d35Sstevel void sbdp_add_bank_to_seg(sbdp_bank_t *);
7503831d35Sstevel void sbdp_remove_bank_from_seg(sbdp_bank_t *);
7603831d35Sstevel uint64_t sbdp_determine_slice(sbdp_handle_t *);
7703831d35Sstevel sbdp_seg_t *sbdp_get_seg(uint64_t);
7803831d35Sstevel #ifdef DEBUG
7903831d35Sstevel void sbdp_print_seg(sbdp_seg_t *);
8003831d35Sstevel #endif
8103831d35Sstevel 
8203831d35Sstevel /*
8303831d35Sstevel  * Head to the system segments link list
8403831d35Sstevel  */
8503831d35Sstevel sbdp_seg_t *sys_seg = NULL;
8603831d35Sstevel 
8703831d35Sstevel uint64_t
sbdp_determine_slice(sbdp_handle_t * hp)8803831d35Sstevel sbdp_determine_slice(sbdp_handle_t *hp)
8903831d35Sstevel {
9003831d35Sstevel 	int size;
9103831d35Sstevel 
9203831d35Sstevel 	size = sbdp_get_mem_size(hp);
9303831d35Sstevel 
9403831d35Sstevel 	if (size <= SG_SLICE_16G_SIZE) {
9503831d35Sstevel 		return (SG_SLICE_16G_SIZE);
9603831d35Sstevel 	} else if (size <= SG_SLICE_32G_SIZE) {
9703831d35Sstevel 		return (SG_SLICE_32G_SIZE);
9803831d35Sstevel 	} else {
9903831d35Sstevel 		return (SG_SLICE_64G_SIZE);
10003831d35Sstevel 	}
10103831d35Sstevel }
10203831d35Sstevel 
10303831d35Sstevel /* ARGSUSED */
10403831d35Sstevel int
sbdp_get_mem_alignment(sbdp_handle_t * hp,dev_info_t * dip,uint64_t * align)10503831d35Sstevel sbdp_get_mem_alignment(sbdp_handle_t *hp, dev_info_t *dip, uint64_t *align)
10603831d35Sstevel {
10703831d35Sstevel 	*align = sbdp_determine_slice(hp);
10803831d35Sstevel 	return (0);
10903831d35Sstevel }
11003831d35Sstevel 
11103831d35Sstevel 
11203831d35Sstevel void
sbdp_memlist_dump(struct memlist * mlist)11303831d35Sstevel sbdp_memlist_dump(struct memlist *mlist)
11403831d35Sstevel {
11503831d35Sstevel 	register struct memlist *ml;
11603831d35Sstevel 
11703831d35Sstevel 	if (mlist == NULL) {
11803831d35Sstevel 		SBDP_DBG_MEM("memlist> EMPTY\n");
11903831d35Sstevel 	} else {
120*56f33205SJonathan Adams 		for (ml = mlist; ml; ml = ml->ml_next)
12103831d35Sstevel 			SBDP_DBG_MEM("memlist>  0x%" PRIx64", 0x%" PRIx64"\n",
122*56f33205SJonathan Adams 			    ml->ml_address, ml->ml_size);
12303831d35Sstevel 	}
12403831d35Sstevel }
12503831d35Sstevel 
12603831d35Sstevel struct mem_arg {
12703831d35Sstevel 	int	board;
12803831d35Sstevel 	int	ndips;
12903831d35Sstevel 	dev_info_t **list;
13003831d35Sstevel };
13103831d35Sstevel 
13203831d35Sstevel /*
13303831d35Sstevel  * Returns mem dip held
13403831d35Sstevel  */
13503831d35Sstevel static int
sbdp_get_mem_dip(pnode_t node,void * arg,uint_t flags)13603831d35Sstevel sbdp_get_mem_dip(pnode_t node, void *arg, uint_t flags)
13703831d35Sstevel {
13803831d35Sstevel 	_NOTE(ARGUNUSED(flags))
13903831d35Sstevel 
14003831d35Sstevel 	dev_info_t *dip;
14103831d35Sstevel 	pnode_t nodeid;
14203831d35Sstevel 	mem_op_t mem = {0};
14303831d35Sstevel 	struct mem_arg *ap = arg;
14403831d35Sstevel 
14503831d35Sstevel 	if (node == OBP_BADNODE || node == OBP_NONODE)
14603831d35Sstevel 		return (DDI_FAILURE);
14703831d35Sstevel 
14803831d35Sstevel 	mem.nodes = &nodeid;
14903831d35Sstevel 	mem.board = ap->board;
15003831d35Sstevel 	mem.nmem = 0;
15103831d35Sstevel 
15203831d35Sstevel 	(void) sbdp_is_mem(node, &mem);
15303831d35Sstevel 
15403831d35Sstevel 	ASSERT(mem.nmem == 0 || mem.nmem == 1);
15503831d35Sstevel 
15603831d35Sstevel 	if (mem.nmem == 0 || nodeid != node)
15703831d35Sstevel 		return (DDI_FAILURE);
15803831d35Sstevel 
15903831d35Sstevel 	dip = e_ddi_nodeid_to_dip(nodeid);
16003831d35Sstevel 	if (dip) {
16103831d35Sstevel 		ASSERT(ap->ndips < SBDP_MAX_MEM_NODES_PER_BOARD);
16203831d35Sstevel 		ap->list[ap->ndips++] = dip;
16303831d35Sstevel 	}
16403831d35Sstevel 	return (DDI_SUCCESS);
16503831d35Sstevel }
16603831d35Sstevel 
16703831d35Sstevel struct memlist *
sbdp_get_memlist(sbdp_handle_t * hp,dev_info_t * dip)16803831d35Sstevel sbdp_get_memlist(sbdp_handle_t *hp, dev_info_t *dip)
16903831d35Sstevel {
17003831d35Sstevel 	_NOTE(ARGUNUSED(dip))
17103831d35Sstevel 
17203831d35Sstevel 	int i, j, skip = 0;
17303831d35Sstevel 	dev_info_t	*list[SBDP_MAX_MEM_NODES_PER_BOARD];
17403831d35Sstevel 	struct mem_arg	arg = {0};
17503831d35Sstevel 	uint64_t	base_pa, size;
17603831d35Sstevel 	struct memlist	*mlist = NULL;
17703831d35Sstevel 
17803831d35Sstevel 	list[0] = NULL;
17903831d35Sstevel 	arg.board = hp->h_board;
18003831d35Sstevel 	arg.list = list;
18103831d35Sstevel 
18203831d35Sstevel 	sbdp_walk_prom_tree(prom_rootnode(), sbdp_get_mem_dip, &arg);
18303831d35Sstevel 
18403831d35Sstevel 	for (i = 0; i < arg.ndips; i++) {
18503831d35Sstevel 		if (list[i] == NULL)
18603831d35Sstevel 			continue;
18703831d35Sstevel 
18803831d35Sstevel 		size = 0;
18903831d35Sstevel 		for (j = 0; j < SBDP_MAX_MCS_PER_NODE; j++) {
19003831d35Sstevel 			if (sbdp_get_meminfo(ddi_get_nodeid(list[i]), j,
19103831d35Sstevel 			    &size, &base_pa)) {
19203831d35Sstevel 				skip++;
19303831d35Sstevel 				continue;
19403831d35Sstevel 			}
19503831d35Sstevel 			if (size == -1 || size == 0)
19603831d35Sstevel 				continue;
19703831d35Sstevel 
19803831d35Sstevel 			(void) memlist_add_span(base_pa, size, &mlist);
19903831d35Sstevel 		}
20003831d35Sstevel 
20103831d35Sstevel 		/*
20203831d35Sstevel 		 * Release hold acquired in sbdp_get_mem_dip()
20303831d35Sstevel 		 */
20403831d35Sstevel 		ddi_release_devi(list[i]);
20503831d35Sstevel 	}
20603831d35Sstevel 
20703831d35Sstevel 	/*
20803831d35Sstevel 	 * XXX - The following two lines are from existing code.
20903831d35Sstevel 	 * However, this appears to be incorrect - this check should be
21003831d35Sstevel 	 * made for each dip in list i.e within the for(i) loop.
21103831d35Sstevel 	 */
21203831d35Sstevel 	if (skip == SBDP_MAX_MCS_PER_NODE)
21303831d35Sstevel 		sbdp_set_err(hp->h_err, ESGT_INTERNAL, NULL);
21403831d35Sstevel 
21503831d35Sstevel 	SBDP_DBG_MEM("memlist for board %d\n", hp->h_board);
21603831d35Sstevel 	sbdp_memlist_dump(mlist);
21703831d35Sstevel 	return (mlist);
21803831d35Sstevel }
21903831d35Sstevel 
22003831d35Sstevel struct memlist *
sbdp_memlist_dup(struct memlist * mlist)22103831d35Sstevel sbdp_memlist_dup(struct memlist *mlist)
22203831d35Sstevel {
22303831d35Sstevel 	struct memlist *hl, *prev;
22403831d35Sstevel 
22503831d35Sstevel 	if (mlist == NULL)
22603831d35Sstevel 		return (NULL);
22703831d35Sstevel 
22803831d35Sstevel 	prev = NULL;
22903831d35Sstevel 	hl = NULL;
230*56f33205SJonathan Adams 	for (; mlist; mlist = mlist->ml_next) {
23103831d35Sstevel 		struct memlist *mp;
23203831d35Sstevel 
23303831d35Sstevel 		mp = memlist_get_one();
23403831d35Sstevel 		if (mp == NULL) {
23503831d35Sstevel 			if (hl != NULL)
23603831d35Sstevel 				memlist_free_list(hl);
23703831d35Sstevel 			hl = NULL;
23803831d35Sstevel 			break;
23903831d35Sstevel 		}
240*56f33205SJonathan Adams 		mp->ml_address = mlist->ml_address;
241*56f33205SJonathan Adams 		mp->ml_size = mlist->ml_size;
242*56f33205SJonathan Adams 		mp->ml_next = NULL;
243*56f33205SJonathan Adams 		mp->ml_prev = prev;
24403831d35Sstevel 
24503831d35Sstevel 		if (prev == NULL)
24603831d35Sstevel 			hl = mp;
24703831d35Sstevel 		else
248*56f33205SJonathan Adams 			prev->ml_next = mp;
24903831d35Sstevel 		prev = mp;
25003831d35Sstevel 	}
25103831d35Sstevel 
25203831d35Sstevel 	return (hl);
25303831d35Sstevel }
25403831d35Sstevel 
25503831d35Sstevel int
sbdp_del_memlist(sbdp_handle_t * hp,struct memlist * mlist)25603831d35Sstevel sbdp_del_memlist(sbdp_handle_t *hp, struct memlist *mlist)
25703831d35Sstevel {
25803831d35Sstevel 	_NOTE(ARGUNUSED(hp))
25903831d35Sstevel 
26003831d35Sstevel 	memlist_free_list(mlist);
26103831d35Sstevel 
26203831d35Sstevel 	return (0);
26303831d35Sstevel }
26403831d35Sstevel 
26503831d35Sstevel /*ARGSUSED*/
26603831d35Sstevel static void
sbdp_flush_ecache(uint64_t a,uint64_t b)26703831d35Sstevel sbdp_flush_ecache(uint64_t a, uint64_t b)
26803831d35Sstevel {
26903831d35Sstevel 	cpu_flush_ecache();
27003831d35Sstevel }
27103831d35Sstevel 
27203831d35Sstevel typedef enum {
27303831d35Sstevel 	SBDP_CR_OK,
27403831d35Sstevel 	SBDP_CR_MC_IDLE_ERR
27503831d35Sstevel } sbdp_cr_err_t;
27603831d35Sstevel 
27703831d35Sstevel int
sbdp_move_memory(sbdp_handle_t * hp,int t_bd)27803831d35Sstevel sbdp_move_memory(sbdp_handle_t *hp, int t_bd)
27903831d35Sstevel {
28003831d35Sstevel 	sbdp_bd_t	*s_bdp, *t_bdp;
28103831d35Sstevel 	int		err = 0;
28203831d35Sstevel 	caddr_t		mempage;
28303831d35Sstevel 	ulong_t		data_area, index_area;
28403831d35Sstevel 	ulong_t		e_area, e_page;
28503831d35Sstevel 	int		availlen, indexlen, funclen, scriptlen;
28603831d35Sstevel 	int		*indexp;
28703831d35Sstevel 	time_t		copytime;
28803831d35Sstevel 	int		(*funcp)();
28903831d35Sstevel 	size_t		size;
29003831d35Sstevel 	struct memlist	*mlist;
29103831d35Sstevel 	sbdp_sr_handle_t	*srhp;
29203831d35Sstevel 	sbdp_rename_script_t	*rsp;
29303831d35Sstevel 	sbdp_rename_script_t	*rsbuffer;
29403831d35Sstevel 	sbdp_cr_handle_t	*cph;
29503831d35Sstevel 	int		linesize;
29603831d35Sstevel 	uint64_t	neer;
29703831d35Sstevel 	sbdp_cr_err_t	cr_err;
29803831d35Sstevel 
29903831d35Sstevel 	cph =  kmem_zalloc(sizeof (sbdp_cr_handle_t), KM_SLEEP);
30003831d35Sstevel 
30103831d35Sstevel 	SBDP_DBG_MEM("moving memory from memory board %d to board %d\n",
30203831d35Sstevel 	    hp->h_board, t_bd);
30303831d35Sstevel 
30403831d35Sstevel 	s_bdp = sbdp_get_bd_info(hp->h_wnode, hp->h_board);
30503831d35Sstevel 	t_bdp = sbdp_get_bd_info(hp->h_wnode, t_bd);
30603831d35Sstevel 
30703831d35Sstevel 	if ((s_bdp == NULL) || (t_bdp == NULL)) {
30803831d35Sstevel 		sbdp_set_err(hp->h_err, ESGT_INTERNAL, NULL);
30903831d35Sstevel 		return (-1);
31003831d35Sstevel 	}
31103831d35Sstevel 
31203831d35Sstevel 	funclen = (int)((ulong_t)_sbdp_copy_rename_end -
313d3d50737SRafael Vanoni 	    (ulong_t)sbdp_copy_rename__relocatable);
31403831d35Sstevel 
31503831d35Sstevel 	if (funclen > PAGESIZE) {
31603831d35Sstevel 		cmn_err(CE_WARN,
31703831d35Sstevel 		    "sbdp: copy-rename funclen (%d) > PAGESIZE (%d)",
31803831d35Sstevel 		    funclen, PAGESIZE);
31903831d35Sstevel 		sbdp_set_err(hp->h_err, ESGT_INTERNAL, NULL);
32003831d35Sstevel 		return (-1);
32103831d35Sstevel 	}
32203831d35Sstevel 
32303831d35Sstevel 	/*
32403831d35Sstevel 	 * mempage will be page aligned, since we're calling
32503831d35Sstevel 	 * kmem_alloc() with an exact multiple of PAGESIZE.
32603831d35Sstevel 	 */
32703831d35Sstevel 	mempage = kmem_alloc(PAGESIZE, KM_SLEEP);
32803831d35Sstevel 
32907d06da5SSurya Prakki 	SBDP_DBG_MEM("mempage = 0x%p\n", (void *)mempage);
33003831d35Sstevel 
33103831d35Sstevel 	/*
33203831d35Sstevel 	 * Copy the code for the copy-rename routine into
33303831d35Sstevel 	 * a page aligned piece of memory.  We do this to guarantee
33403831d35Sstevel 	 * that we're executing within the same page and thus reduce
33503831d35Sstevel 	 * the possibility of cache collisions between different
33603831d35Sstevel 	 * pages.
33703831d35Sstevel 	 */
33803831d35Sstevel 	bcopy((caddr_t)sbdp_copy_rename__relocatable, mempage, funclen);
33903831d35Sstevel 
34003831d35Sstevel 	funcp = (int (*)())mempage;
34103831d35Sstevel 
34207d06da5SSurya Prakki 	SBDP_DBG_MEM("copy-rename funcp = 0x%p (len = 0x%x)\n", (void *)funcp,
34307d06da5SSurya Prakki 	    funclen);
34403831d35Sstevel 
34503831d35Sstevel 	/*
34603831d35Sstevel 	 * Prepare data page that will contain script of
34703831d35Sstevel 	 * operations to perform during copy-rename.
34803831d35Sstevel 	 * Allocate temporary buffer to hold script.
34903831d35Sstevel 	 */
35003831d35Sstevel 
35103831d35Sstevel 	size = sizeof (sbdp_rename_script_t) * SBDP_RENAME_MAXOP;
35203831d35Sstevel 	rsbuffer = kmem_zalloc(size, KM_SLEEP);
35303831d35Sstevel 
35403831d35Sstevel 	cph->s_bdp = s_bdp;
35503831d35Sstevel 	cph->t_bdp = t_bdp;
35603831d35Sstevel 	cph->script = rsbuffer;
35703831d35Sstevel 
35803831d35Sstevel 	/*
35903831d35Sstevel 	 * We need to make sure we don't switch cpus since we depend on the
36003831d35Sstevel 	 * correct cpu processing
36103831d35Sstevel 	 */
36203831d35Sstevel 	affinity_set(CPU_CURRENT);
36303831d35Sstevel 	scriptlen = sbdp_prep_rename_script(cph);
36403831d35Sstevel 	if (scriptlen <= 0) {
365d3d50737SRafael Vanoni 		cmn_err(CE_WARN, "sbdp failed to prep for copy-rename");
36603831d35Sstevel 		sbdp_set_err(hp->h_err, ESGT_INTERNAL, NULL);
36703831d35Sstevel 		err = 1;
36803831d35Sstevel 		goto cleanup;
36903831d35Sstevel 	}
37003831d35Sstevel 	SBDP_DBG_MEM("copy-rename script length = 0x%x\n", scriptlen);
37103831d35Sstevel 
37203831d35Sstevel 	indexlen = sizeof (*indexp) << 1;
37303831d35Sstevel 
37403831d35Sstevel 	if ((funclen + scriptlen + indexlen) > PAGESIZE) {
375d3d50737SRafael Vanoni 		cmn_err(CE_WARN, "sbdp: func len (%d) + script len (%d) "
376d3d50737SRafael Vanoni 		    "+ index len (%d) > PAGESIZE (%d)", funclen, scriptlen,
377d3d50737SRafael Vanoni 		    indexlen, PAGESIZE);
37803831d35Sstevel 		sbdp_set_err(hp->h_err, ESGT_INTERNAL, NULL);
37903831d35Sstevel 		err = 1;
38003831d35Sstevel 		goto cleanup;
38103831d35Sstevel 	}
38203831d35Sstevel 
38303831d35Sstevel 	linesize = cpunodes[CPU->cpu_id].ecache_linesize;
38403831d35Sstevel 
38503831d35Sstevel 	/*
38603831d35Sstevel 	 * Find aligned area within data page to maintain script.
38703831d35Sstevel 	 */
38803831d35Sstevel 	data_area = (ulong_t)mempage;
38903831d35Sstevel 	data_area += (ulong_t)funclen + (ulong_t)(linesize - 1);
39003831d35Sstevel 	data_area &= ~((ulong_t)(linesize - 1));
39103831d35Sstevel 
39203831d35Sstevel 	availlen = PAGESIZE - indexlen;
39303831d35Sstevel 	availlen -= (int)(data_area - (ulong_t)mempage);
39403831d35Sstevel 
39503831d35Sstevel 	if (availlen < scriptlen) {
396d3d50737SRafael Vanoni 		cmn_err(CE_WARN, "sbdp: available len (%d) < script len (%d)",
397d3d50737SRafael Vanoni 		    availlen, scriptlen);
39803831d35Sstevel 		sbdp_set_err(hp->h_err, ESGT_INTERNAL, NULL);
39903831d35Sstevel 		err = 1;
40003831d35Sstevel 		goto cleanup;
40103831d35Sstevel 	}
40203831d35Sstevel 
40303831d35Sstevel 	SBDP_DBG_MEM("copy-rename script data area = 0x%lx\n",
404d3d50737SRafael Vanoni 	    data_area);
40503831d35Sstevel 
40603831d35Sstevel 	bcopy((caddr_t)rsbuffer, (caddr_t)data_area, scriptlen);
40703831d35Sstevel 	rsp = (sbdp_rename_script_t *)data_area;
40803831d35Sstevel 
409d3d50737SRafael Vanoni 	index_area = data_area + (ulong_t)scriptlen + (ulong_t)(linesize - 1);
41003831d35Sstevel 	index_area &= ~((ulong_t)(linesize - 1));
41103831d35Sstevel 	indexp = (int *)index_area;
41203831d35Sstevel 	indexp[0] = 0;
41303831d35Sstevel 	indexp[1] = 0;
41403831d35Sstevel 
41503831d35Sstevel 	e_area = index_area + (ulong_t)indexlen;
41603831d35Sstevel 	e_page = (ulong_t)mempage + PAGESIZE;
41703831d35Sstevel 	if (e_area > e_page) {
41803831d35Sstevel 		cmn_err(CE_WARN,
419d3d50737SRafael Vanoni 		    "sbdp: index area size (%d) > available (%d)\n",
420d3d50737SRafael Vanoni 		    indexlen, (int)(e_page - index_area));
42103831d35Sstevel 		sbdp_set_err(hp->h_err, ESGT_INTERNAL, NULL);
42203831d35Sstevel 		err = 1;
42303831d35Sstevel 		goto cleanup;
42403831d35Sstevel 	}
42503831d35Sstevel 
42607d06da5SSurya Prakki 	SBDP_DBG_MEM("copy-rename index area = 0x%p\n", (void *)indexp);
42703831d35Sstevel 
42803831d35Sstevel 	SBDP_DBG_MEM("cpu %d\n", CPU->cpu_id);
42903831d35Sstevel 
43003831d35Sstevel 	srhp = sbdp_get_sr_handle();
43103831d35Sstevel 	ASSERT(srhp);
43203831d35Sstevel 
43303831d35Sstevel 	srhp->sr_flags = hp->h_flags;
43403831d35Sstevel 
435d3d50737SRafael Vanoni 	copytime = ddi_get_lbolt();
43603831d35Sstevel 
43703831d35Sstevel 	mutex_enter(&s_bdp->bd_mutex);
43803831d35Sstevel 	mlist = sbdp_memlist_dup(s_bdp->ml);
43903831d35Sstevel 	mutex_exit(&s_bdp->bd_mutex);
44003831d35Sstevel 
44103831d35Sstevel 	if (mlist == NULL) {
44203831d35Sstevel 		SBDP_DBG_MEM("Didn't find memory list\n");
44303831d35Sstevel 	}
44403831d35Sstevel 	SBDP_DBG_MEM("src\n\tbd\t%d\n\tnode\t%d\n\tbpa 0x%lx\n\tnodes\t%p\n",
44507d06da5SSurya Prakki 	    s_bdp->bd, s_bdp->wnode, s_bdp->bpa, (void *)s_bdp->nodes);
44603831d35Sstevel 	sbdp_memlist_dump(s_bdp->ml);
44703831d35Sstevel 	SBDP_DBG_MEM("tgt\n\tbd\t%d\n\tnode\t%d\n\tbpa 0x%lx\n\tnodes\t%p\n",
44807d06da5SSurya Prakki 	    t_bdp->bd, t_bdp->wnode, t_bdp->bpa, (void *)t_bdp->nodes);
44903831d35Sstevel 	sbdp_memlist_dump(t_bdp->ml);
45003831d35Sstevel 
45103831d35Sstevel 	/*
45203831d35Sstevel 	 * Quiesce the OS.
45303831d35Sstevel 	 */
45403831d35Sstevel 	if (sbdp_suspend(srhp)) {
45503831d35Sstevel 		sbd_error_t	*sep;
456d3d50737SRafael Vanoni 		cmn_err(CE_WARN, "sbdp: failed to quiesce OS for copy-rename");
45703831d35Sstevel 		sep = &srhp->sep;
45803831d35Sstevel 		sbdp_set_err(hp->h_err, sep->e_code, sep->e_rsc);
45903831d35Sstevel 		sbdp_release_sr_handle(srhp);
46007d06da5SSurya Prakki 		(void) sbdp_del_memlist(hp, mlist);
46103831d35Sstevel 		err = 1;
46203831d35Sstevel 		goto cleanup;
46303831d35Sstevel 	}
46403831d35Sstevel 
46503831d35Sstevel 	/*
46603831d35Sstevel 	 * =================================
46703831d35Sstevel 	 * COPY-RENAME BEGIN.
46803831d35Sstevel 	 * =================================
46903831d35Sstevel 	 */
47003831d35Sstevel 	SBDP_DBG_MEM("s_base 0x%lx t_base 0x%lx\n", cph->s_bdp->bpa,
47103831d35Sstevel 	    cph->t_bdp->bpa);
47203831d35Sstevel 
47303831d35Sstevel 	cph->ret = 0;
47403831d35Sstevel 
47503831d35Sstevel 	SBDP_DBG_MEM("cph return 0x%lx\n", cph->ret);
47603831d35Sstevel 
47703831d35Sstevel 	SBDP_DBG_MEM("Flushing all of the cpu caches\n");
47803831d35Sstevel 	xc_all(sbdp_flush_ecache, 0, 0);
47903831d35Sstevel 
48003831d35Sstevel 	/* disable CE reporting */
48103831d35Sstevel 	neer = get_error_enable();
48203831d35Sstevel 	set_error_enable(neer & ~EN_REG_CEEN);
48303831d35Sstevel 
48403831d35Sstevel 	cr_err = (*funcp)(cph, mlist, rsp);
48503831d35Sstevel 
48603831d35Sstevel 	/* enable CE reporting */
48703831d35Sstevel 	set_error_enable(neer);
48803831d35Sstevel 
48903831d35Sstevel 	SBDP_DBG_MEM("s_base 0x%lx t_base 0x%lx\n", cph->s_bdp->bpa,
49003831d35Sstevel 	    cph->t_bdp->bpa);
49103831d35Sstevel 	SBDP_DBG_MEM("cph return 0x%lx\n", cph->ret);
49203831d35Sstevel 	SBDP_DBG_MEM("after execking the function\n");
49303831d35Sstevel 
49403831d35Sstevel 	/*
49503831d35Sstevel 	 * =================================
49603831d35Sstevel 	 * COPY-RENAME END.
49703831d35Sstevel 	 * =================================
49803831d35Sstevel 	 */
49903831d35Sstevel 	SBDP_DBG_MEM("err is 0x%d\n", err);
50003831d35Sstevel 
50103831d35Sstevel 	/*
50203831d35Sstevel 	 * Resume the OS.
50303831d35Sstevel 	 */
50403831d35Sstevel 	sbdp_resume(srhp);
50503831d35Sstevel 	if (srhp->sep.e_code) {
50603831d35Sstevel 		sbd_error_t	*sep;
50703831d35Sstevel 		cmn_err(CE_WARN,
50803831d35Sstevel 		    "sbdp: failed to resume OS for copy-rename");
50903831d35Sstevel 		sep = &srhp->sep;
51003831d35Sstevel 		sbdp_set_err(hp->h_err, sep->e_code, sep->e_rsc);
51103831d35Sstevel 		err = 1;
51203831d35Sstevel 	}
51303831d35Sstevel 
514d3d50737SRafael Vanoni 	copytime = ddi_get_lbolt() - copytime;
51503831d35Sstevel 
51603831d35Sstevel 	sbdp_release_sr_handle(srhp);
51707d06da5SSurya Prakki 	(void) sbdp_del_memlist(hp, mlist);
51803831d35Sstevel 
51903831d35Sstevel 	SBDP_DBG_MEM("copy-rename elapsed time = %ld ticks (%ld secs)\n",
520d3d50737SRafael Vanoni 	    copytime, copytime / hz);
52103831d35Sstevel 
52203831d35Sstevel 	switch (cr_err) {
52303831d35Sstevel 	case SBDP_CR_OK:
52403831d35Sstevel 		break;
52503831d35Sstevel 	case SBDP_CR_MC_IDLE_ERR: {
52603831d35Sstevel 		dev_info_t *dip;
52703831d35Sstevel 		pnode_t nodeid = cph->busy_mc->node;
52803831d35Sstevel 		char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
52903831d35Sstevel 
53003831d35Sstevel 		dip = e_ddi_nodeid_to_dip(nodeid);
53103831d35Sstevel 
53203831d35Sstevel 		ASSERT(dip != NULL);
53303831d35Sstevel 
53403831d35Sstevel 		(void) ddi_pathname(dip, path);
53503831d35Sstevel 		ddi_release_devi(dip);
53603831d35Sstevel 		cmn_err(CE_WARN, "failed to idle memory controller %s: "
53703831d35Sstevel 		    "copy-rename aborted", path);
53803831d35Sstevel 		kmem_free(path, MAXPATHLEN);
53903831d35Sstevel 		sbdp_set_err(hp->h_err, ESBD_MEMFAIL, NULL);
54003831d35Sstevel 		err = 1;
54103831d35Sstevel 		break;
54203831d35Sstevel 	}
54303831d35Sstevel 	default:
54403831d35Sstevel 		sbdp_set_err(hp->h_err, ESGT_INTERNAL, NULL);
54503831d35Sstevel 		cmn_err(CE_WARN, "unknown copy-rename error code (%d)", cr_err);
54603831d35Sstevel 		err = 1;
54703831d35Sstevel 		break;
54803831d35Sstevel 	}
54903831d35Sstevel 
55003831d35Sstevel 	if (err)
55103831d35Sstevel 		goto cleanup;
55203831d35Sstevel 
55303831d35Sstevel 	/*
55403831d35Sstevel 	 * Rename memory for lgroup.
55503831d35Sstevel 	 * Source and target board numbers are packaged in arg.
55603831d35Sstevel 	 */
55703831d35Sstevel 	lgrp_plat_config(LGRP_CONFIG_MEM_RENAME,
558d3d50737SRafael Vanoni 	    (uintptr_t)(s_bdp->bd | (t_bdp->bd << 16)));
55903831d35Sstevel 
56003831d35Sstevel 	/*
56103831d35Sstevel 	 * swap list of banks
56203831d35Sstevel 	 */
56303831d35Sstevel 	sbdp_swap_list_of_banks(s_bdp, t_bdp);
56403831d35Sstevel 
56503831d35Sstevel 	/*
56603831d35Sstevel 	 * Update the cached board info for both the source and the target
56703831d35Sstevel 	 */
56803831d35Sstevel 	sbdp_update_bd_info(s_bdp);
56903831d35Sstevel 	sbdp_update_bd_info(t_bdp);
57003831d35Sstevel 
57103831d35Sstevel 	/*
57203831d35Sstevel 	 * Tell the sc that we have swapped slices.
57303831d35Sstevel 	 */
57403831d35Sstevel 	if (sbdp_swap_slices(s_bdp->bd, t_bdp->bd) != 0) {
57503831d35Sstevel 		/* This is dangerous. The in use slice could be re-used! */
57603831d35Sstevel 		SBDP_DBG_MEM("swaping slices failed\n");
57703831d35Sstevel 	}
57803831d35Sstevel 
57903831d35Sstevel cleanup:
58003831d35Sstevel 	kmem_free(rsbuffer, size);
58103831d35Sstevel 	kmem_free(mempage, PAGESIZE);
58203831d35Sstevel 	kmem_free(cph, sizeof (sbdp_cr_handle_t));
58303831d35Sstevel 	affinity_clear();
58403831d35Sstevel 
58503831d35Sstevel 	return (err ? -1 : 0);
58603831d35Sstevel }
58703831d35Sstevel 
58803831d35Sstevel static int
sbdp_copy_regs(pnode_t node,uint64_t bpa,uint64_t new_base,int inval,sbdp_rename_script_t * rsp,int * index)58903831d35Sstevel sbdp_copy_regs(pnode_t node, uint64_t bpa, uint64_t new_base, int inval,
59003831d35Sstevel 	sbdp_rename_script_t *rsp, int *index)
59103831d35Sstevel {
59203831d35Sstevel 	int		i, m;
59303831d35Sstevel 	mc_regs_t	regs;
59403831d35Sstevel 	uint64_t	*mc_decode;
59503831d35Sstevel 
59603831d35Sstevel 	if (mc_read_regs(node, &regs)) {
59703831d35Sstevel 		SBDP_DBG_MEM("sbdp_copy_regs: failed to read source Decode "
59803831d35Sstevel 		    "Regs");
59903831d35Sstevel 		return (-1);
60003831d35Sstevel 	}
60103831d35Sstevel 
60203831d35Sstevel 	mc_decode = regs.mc_decode;
60303831d35Sstevel 
60403831d35Sstevel 	m = *index;
60503831d35Sstevel 	for (i = 0; i < SBDP_MAX_MCS_PER_NODE; i++) {
60603831d35Sstevel 		uint64_t	offset, seg_pa, tmp_base;
60703831d35Sstevel 
60803831d35Sstevel 		/*
60903831d35Sstevel 		 * Skip invalid banks
61003831d35Sstevel 		 */
61103831d35Sstevel 		if ((mc_decode[i] & SG_DECODE_VALID) != SG_DECODE_VALID) {
61203831d35Sstevel 			continue;
61303831d35Sstevel 		}
61403831d35Sstevel 
61503831d35Sstevel 		tmp_base = new_base;
61603831d35Sstevel 		if (!inval) {
61703831d35Sstevel 			/*
61803831d35Sstevel 			 * We need to calculate the offset from the base pa
61903831d35Sstevel 			 * to add it appropriately to the new_base.
62003831d35Sstevel 			 * The offset needs to be in UM relative to the mc
62103831d35Sstevel 			 * decode register.  Since we are going from physical
62203831d35Sstevel 			 * address to UM, we need to shift it by PHYS2UM_SHIFT.
62303831d35Sstevel 			 * To get it ready to OR it with the MC decode reg,
62403831d35Sstevel 			 * we need to shift it left MC_UM_SHIFT
62503831d35Sstevel 			 */
62603831d35Sstevel 			seg_pa = MC_BASE(mc_decode[i]) << PHYS2UM_SHIFT;
62703831d35Sstevel 			offset = (seg_pa - bpa);
62803831d35Sstevel 			/* Convert tmp_base into a physical address */
62903831d35Sstevel 			tmp_base = (tmp_base >> MC_UM_SHIFT) << PHYS2UM_SHIFT;
63003831d35Sstevel 			tmp_base += offset;
63103831d35Sstevel 			/* Convert tmp_base to be MC reg ready */
63203831d35Sstevel 			tmp_base = (tmp_base >> PHYS2UM_SHIFT) << MC_UM_SHIFT;
63303831d35Sstevel 		}
63403831d35Sstevel 
63503831d35Sstevel 		mc_decode[i] &= ~SG_DECODE_UM;
63603831d35Sstevel 		mc_decode[i] |= tmp_base;
63703831d35Sstevel 		mc_decode[i] |= SG_DECODE_VALID;
63803831d35Sstevel 
63903831d35Sstevel 		/*
64003831d35Sstevel 		 * Step 1:	Write source base address to the MC
64103831d35Sstevel 		 *		with present bit off.
64203831d35Sstevel 		 */
64303831d35Sstevel 		rsp[m].masr_addr = mc_get_addr(node, i, &rsp[m].asi);
64403831d35Sstevel 		rsp[m].masr = mc_decode[i] & ~SG_DECODE_VALID;
64503831d35Sstevel 		m++;
64603831d35Sstevel 		/*
64703831d35Sstevel 		 * Step 2:	Now rewrite the mc reg with present bit on.
64803831d35Sstevel 		 */
64903831d35Sstevel 		rsp[m].masr_addr = rsp[m-1].masr_addr;
65003831d35Sstevel 		rsp[m].masr = mc_decode[i];
65103831d35Sstevel 		rsp[m].asi = rsp[m-1].asi;
65203831d35Sstevel 		m++;
65303831d35Sstevel 	}
65403831d35Sstevel 
65503831d35Sstevel 	*index = m;
65603831d35Sstevel 	return (0);
65703831d35Sstevel }
65803831d35Sstevel 
65903831d35Sstevel static int
sbdp_get_reg_addr(pnode_t nodeid,uint64_t * pa)66003831d35Sstevel sbdp_get_reg_addr(pnode_t nodeid, uint64_t *pa)
66103831d35Sstevel {
66203831d35Sstevel 	mc_regspace	reg;
66303831d35Sstevel 	int		len;
66403831d35Sstevel 
66503831d35Sstevel 	len = prom_getproplen(nodeid, "reg");
66603831d35Sstevel 	if (len != sizeof (mc_regspace))
66703831d35Sstevel 		return (-1);
66803831d35Sstevel 
66903831d35Sstevel 	if (prom_getprop(nodeid, "reg", (caddr_t)&reg) < 0)
67003831d35Sstevel 		return (-1);
67103831d35Sstevel 
67203831d35Sstevel 	ASSERT(pa != NULL);
67303831d35Sstevel 
67403831d35Sstevel 	*pa = ((uint64_t)reg.regspec_addr_hi) << 32;
67503831d35Sstevel 	*pa |= (uint64_t)reg.regspec_addr_lo;
67603831d35Sstevel 
67703831d35Sstevel 	return (0);
67803831d35Sstevel }
67903831d35Sstevel 
68003831d35Sstevel static int
mc_get_sibling_cpu_impl(pnode_t mc_node)68103831d35Sstevel mc_get_sibling_cpu_impl(pnode_t mc_node)
68203831d35Sstevel {
68303831d35Sstevel 	int	len, impl;
68403831d35Sstevel 	pnode_t	cpu_node;
68503831d35Sstevel 	char	namebuf[OBP_MAXPROPNAME];
68603831d35Sstevel 
68703831d35Sstevel 	cpu_node = mc_get_sibling_cpu(mc_node);
68803831d35Sstevel 	if (cpu_node == OBP_NONODE) {
68903831d35Sstevel 		SBDP_DBG_MEM("mc_get_sibling_cpu failed: dnode=0x%x\n",
69003831d35Sstevel 		    mc_node);
69103831d35Sstevel 		return (-1);
69203831d35Sstevel 	}
69303831d35Sstevel 
69403831d35Sstevel 	len = prom_getproplen(cpu_node, "name");
69503831d35Sstevel 	if (len < 0) {
69603831d35Sstevel 		SBDP_DBG_MEM("invalid prom_getproplen for name prop: "
69703831d35Sstevel 		    "len=%d, dnode=0x%x\n", len, cpu_node);
69803831d35Sstevel 		return (-1);
69903831d35Sstevel 	}
70003831d35Sstevel 
70103831d35Sstevel 	if (prom_getprop(cpu_node, "name", (caddr_t)namebuf) == -1) {
70203831d35Sstevel 		SBDP_DBG_MEM("failed to read name property for dnode=0x%x\n",
70303831d35Sstevel 		    cpu_node);
70403831d35Sstevel 		return (-1);
70503831d35Sstevel 	}
70603831d35Sstevel 
70703831d35Sstevel 	/*
70803831d35Sstevel 	 * If this is a CMP node, the child has the implementation
70903831d35Sstevel 	 * property.
71003831d35Sstevel 	 */
71103831d35Sstevel 	if (strcmp(namebuf, "cmp") == 0) {
71203831d35Sstevel 		cpu_node = prom_childnode(cpu_node);
71303831d35Sstevel 		ASSERT(cpu_node != OBP_NONODE);
71403831d35Sstevel 	}
71503831d35Sstevel 
71603831d35Sstevel 	if (prom_getprop(cpu_node, "implementation#", (caddr_t)&impl) == -1) {
71703831d35Sstevel 		SBDP_DBG_MEM("failed to read implementation# property for "
71803831d35Sstevel 		    "dnode=0x%x\n", cpu_node);
71903831d35Sstevel 		return (-1);
72003831d35Sstevel 	}
72103831d35Sstevel 
72203831d35Sstevel 	SBDP_DBG_MEM("mc_get_sibling_cpu_impl: found impl=0x%x, dnode=0x%x\n",
72303831d35Sstevel 	    impl, cpu_node);
72403831d35Sstevel 
72503831d35Sstevel 	return (impl);
72603831d35Sstevel }
72703831d35Sstevel 
72803831d35Sstevel /*
72903831d35Sstevel  * Provide EMU Activity Status register ASI and address.  Only valid for
73003831d35Sstevel  * Panther processors.
73103831d35Sstevel  */
73203831d35Sstevel static int
mc_get_idle_reg(pnode_t nodeid,uint64_t * addr,uint_t * asi)73303831d35Sstevel mc_get_idle_reg(pnode_t nodeid, uint64_t *addr, uint_t *asi)
73403831d35Sstevel {
73503831d35Sstevel 	int	portid;
73603831d35Sstevel 	uint64_t reg_pa;
73703831d35Sstevel 
73803831d35Sstevel 	ASSERT(nodeid != OBP_NONODE);
73903831d35Sstevel 	ASSERT(mc_get_sibling_cpu_impl(nodeid) == PANTHER_IMPL);
74003831d35Sstevel 
74103831d35Sstevel 	if (prom_getprop(nodeid, "portid", (caddr_t)&portid) < 0 ||
74203831d35Sstevel 	    portid == -1) {
74303831d35Sstevel 		SBDP_DBG_MEM("mc_get_idle_reg: failed to read portid prop "
74403831d35Sstevel 		    "for dnode=0x%x\n", nodeid);
74503831d35Sstevel 		return (-1);
74603831d35Sstevel 	}
74703831d35Sstevel 
74803831d35Sstevel 	if (sbdp_get_reg_addr(nodeid, &reg_pa) != 0) {
74903831d35Sstevel 		SBDP_DBG_MEM("mc_get_idle_reg: failed to read reg prop "
75003831d35Sstevel 		    "for dnode=0x%x\n", nodeid);
75103831d35Sstevel 		return (-1);
75203831d35Sstevel 	}
75303831d35Sstevel 
75403831d35Sstevel 	/*
75503831d35Sstevel 	 * Local access will be via ASI 0x4a, otherwise via Safari PIO.
75603831d35Sstevel 	 * This assumes the copy-rename will later run on the same proc,
75703831d35Sstevel 	 * hence there is an assumption we are already bound.
75803831d35Sstevel 	 */
75903831d35Sstevel 	ASSERT(curthread->t_bound_cpu == CPU);
76003831d35Sstevel 	if (SG_CPUID_TO_PORTID(CPU->cpu_id) == portid) {
76103831d35Sstevel 		*addr = ASI_EMU_ACT_STATUS_VA;
76203831d35Sstevel 		*asi = ASI_SAFARI_CONFIG;
76303831d35Sstevel 	} else {
76403831d35Sstevel 		*addr = MC_ACTIVITY_STATUS(reg_pa);
76503831d35Sstevel 		*asi = ASI_IO;
76603831d35Sstevel 	}
76703831d35Sstevel 
76803831d35Sstevel 	return (0);
76903831d35Sstevel }
77003831d35Sstevel 
77103831d35Sstevel /*
77203831d35Sstevel  * If non-Panther board, add phys_banks entry for each physical bank.
77303831d35Sstevel  * If Panther board, add mc_idle_regs entry for each EMU Activity Status
77403831d35Sstevel  * register.  Increment the array indices b_idx and r_idx for each entry
77503831d35Sstevel  * populated by this routine.
77603831d35Sstevel  *
77703831d35Sstevel  * The caller is responsible for allocating sufficient array entries.
77803831d35Sstevel  */
77903831d35Sstevel static int
sbdp_prep_mc_idle_one(sbdp_bd_t * bp,sbdp_rename_script_t phys_banks[],int * b_idx,sbdp_mc_idle_script_t mc_idle_regs[],int * r_idx)78003831d35Sstevel sbdp_prep_mc_idle_one(sbdp_bd_t *bp, sbdp_rename_script_t phys_banks[],
78103831d35Sstevel     int *b_idx, sbdp_mc_idle_script_t mc_idle_regs[], int *r_idx)
78203831d35Sstevel {
78303831d35Sstevel 	int		i, j;
78403831d35Sstevel 	pnode_t		*memnodes;
78503831d35Sstevel 	mc_regs_t	regs;
78603831d35Sstevel 	uint64_t	addr;
78703831d35Sstevel 	uint_t		asi;
78803831d35Sstevel 	sbd_cond_t	sibling_cpu_cond;
78903831d35Sstevel 	int		impl = -1;
79003831d35Sstevel 
79103831d35Sstevel 	memnodes = bp->nodes;
79203831d35Sstevel 
79303831d35Sstevel 	for (i = 0; i < SBDP_MAX_MEM_NODES_PER_BOARD; i++) {
79403831d35Sstevel 		if (memnodes[i] == OBP_NONODE) {
79503831d35Sstevel 			continue;
79603831d35Sstevel 		}
79703831d35Sstevel 
79803831d35Sstevel 		/* MC should not be accessed if cpu has failed  */
79903831d35Sstevel 		sibling_cpu_cond = mc_check_sibling_cpu(memnodes[i]);
80003831d35Sstevel 		if (sibling_cpu_cond == SBD_COND_FAILED ||
80103831d35Sstevel 		    sibling_cpu_cond == SBD_COND_UNUSABLE) {
80203831d35Sstevel 			SBDP_DBG_MEM("sbdp: skipping MC with failed cpu: "
80303831d35Sstevel 			    "board=%d, mem node=%d, condition=%d",
80403831d35Sstevel 			    bp->bd, i, sibling_cpu_cond);
80503831d35Sstevel 			continue;
80603831d35Sstevel 		}
80703831d35Sstevel 
80803831d35Sstevel 		/*
80903831d35Sstevel 		 * Initialize the board cpu type, assuming all board cpus are
81003831d35Sstevel 		 * the same type.  This is true of all Cheetah-based processors.
81103831d35Sstevel 		 * Failure to read the cpu type is considered a fatal error.
81203831d35Sstevel 		 */
81303831d35Sstevel 		if (impl == -1) {
81403831d35Sstevel 			impl = mc_get_sibling_cpu_impl(memnodes[i]);
81503831d35Sstevel 			if (impl == -1) {
81603831d35Sstevel 				SBDP_DBG_MEM("sbdp: failed to get cpu impl "
81703831d35Sstevel 				    "for MC dnode=0x%x\n", memnodes[i]);
81803831d35Sstevel 				return (-1);
81903831d35Sstevel 			}
82003831d35Sstevel 		}
82103831d35Sstevel 
82203831d35Sstevel 		switch (impl) {
82303831d35Sstevel 		case CHEETAH_IMPL:
82403831d35Sstevel 		case CHEETAH_PLUS_IMPL:
82503831d35Sstevel 		case JAGUAR_IMPL:
82603831d35Sstevel 			if (mc_read_regs(memnodes[i], &regs)) {
82703831d35Sstevel 				SBDP_DBG_MEM("sbdp: failed to read source "
82803831d35Sstevel 				    "Decode Regs of board %d", bp->bd);
82903831d35Sstevel 				return (-1);
83003831d35Sstevel 			}
83103831d35Sstevel 
83203831d35Sstevel 			for (j = 0; j < SBDP_MAX_MCS_PER_NODE; j++) {
83303831d35Sstevel 				uint64_t mc_decode = regs.mc_decode[j];
83403831d35Sstevel 
83503831d35Sstevel 				if ((mc_decode & SG_DECODE_VALID) !=
83603831d35Sstevel 				    SG_DECODE_VALID) {
83703831d35Sstevel 					continue;
83803831d35Sstevel 				}
83903831d35Sstevel 
84003831d35Sstevel 				addr = (MC_BASE(mc_decode) << PHYS2UM_SHIFT) |
84103831d35Sstevel 				    (MC_LM(mc_decode) << MC_LM_SHIFT);
84203831d35Sstevel 
84303831d35Sstevel 				phys_banks[*b_idx].masr_addr = addr;
84403831d35Sstevel 				phys_banks[*b_idx].masr = 0;	/* unused */
84503831d35Sstevel 				phys_banks[*b_idx].asi = ASI_MEM;
84603831d35Sstevel 				(*b_idx)++;
84703831d35Sstevel 			}
84803831d35Sstevel 			break;
84903831d35Sstevel 		case PANTHER_IMPL:
85003831d35Sstevel 			if (mc_get_idle_reg(memnodes[i], &addr, &asi)) {
85103831d35Sstevel 				return (-1);
85203831d35Sstevel 			}
85303831d35Sstevel 
85403831d35Sstevel 			mc_idle_regs[*r_idx].addr = addr;
85503831d35Sstevel 			mc_idle_regs[*r_idx].asi = asi;
85603831d35Sstevel 			mc_idle_regs[*r_idx].node = memnodes[i];
85703831d35Sstevel 			mc_idle_regs[*r_idx].bd_id = bp->bd;
85803831d35Sstevel 			(*r_idx)++;
85903831d35Sstevel 			break;
86003831d35Sstevel 		default:
86103831d35Sstevel 			cmn_err(CE_WARN, "Unknown cpu implementation=0x%x",
86203831d35Sstevel 			    impl);
86303831d35Sstevel 			ASSERT(0);
86403831d35Sstevel 			return (-1);
86503831d35Sstevel 		}
86603831d35Sstevel 	}
86703831d35Sstevel 
86803831d35Sstevel 	return (0);
86903831d35Sstevel }
87003831d35Sstevel 
87103831d35Sstevel /*
87203831d35Sstevel  * For non-Panther MCs that do not support read-bypass-write, we do a read
87303831d35Sstevel  * to each physical bank, relying on the reads to block until all outstanding
87403831d35Sstevel  * write requests have completed.  This mechanism is referred to as the bus
87503831d35Sstevel  * sync list and is used for Cheetah, Cheetah+, and Jaguar processors.  The
87603831d35Sstevel  * bus sync list PAs for the source and target are kept together and comprise
87703831d35Sstevel  * Section 1 of the rename script.
87803831d35Sstevel  *
87903831d35Sstevel  * For Panther processors that support the EMU Activity Status register,
88003831d35Sstevel  * we ensure the writes have completed by polling the MCU_ACT_STATUS
88103831d35Sstevel  * field several times to make sure the MC queues are empty.  The
88203831d35Sstevel  * EMU Activity Status register PAs for the source and target are
88303831d35Sstevel  * kept together and comprise Section 2 of the rename script.
88403831d35Sstevel  */
88503831d35Sstevel static int
sbdp_prep_mc_idle_script(sbdp_bd_t * s_bp,sbdp_bd_t * t_bp,sbdp_rename_script_t * rsp,int * rsp_idx)88603831d35Sstevel sbdp_prep_mc_idle_script(sbdp_bd_t *s_bp, sbdp_bd_t *t_bp,
88703831d35Sstevel     sbdp_rename_script_t *rsp, int *rsp_idx)
88803831d35Sstevel {
88903831d35Sstevel 	sbdp_rename_script_t *phys_banks;
89003831d35Sstevel 	sbdp_mc_idle_script_t *mc_idle_regs;
89103831d35Sstevel 	int	max_banks, max_regs;
89203831d35Sstevel 	size_t	bsize, msize;
89303831d35Sstevel 	int	nbanks = 0, nregs = 0;
89403831d35Sstevel 	int	i;
89503831d35Sstevel 
89603831d35Sstevel 	/* CONSTCOND */
89703831d35Sstevel 	ASSERT(sizeof (sbdp_rename_script_t) ==
89803831d35Sstevel 	    sizeof (sbdp_mc_idle_script_t));
89903831d35Sstevel 
90003831d35Sstevel 	/* allocate space for both source and target */
90103831d35Sstevel 	max_banks = SBDP_MAX_MEM_NODES_PER_BOARD *
90203831d35Sstevel 	    SG_MAX_BANKS_PER_MC * 2;
90303831d35Sstevel 	max_regs = SBDP_MAX_MEM_NODES_PER_BOARD * 2;
90403831d35Sstevel 
90503831d35Sstevel 	bsize = sizeof (sbdp_rename_script_t) * max_banks;
90603831d35Sstevel 	msize = sizeof (sbdp_mc_idle_script_t) * max_regs;
90703831d35Sstevel 
90803831d35Sstevel 	phys_banks = kmem_zalloc(bsize, KM_SLEEP);
90903831d35Sstevel 	mc_idle_regs = kmem_zalloc(msize, KM_SLEEP);
91003831d35Sstevel 
91103831d35Sstevel 	if (sbdp_prep_mc_idle_one(t_bp, phys_banks, &nbanks,
91203831d35Sstevel 	    mc_idle_regs, &nregs) != 0 ||
91303831d35Sstevel 	    sbdp_prep_mc_idle_one(s_bp, phys_banks, &nbanks,
91403831d35Sstevel 	    mc_idle_regs, &nregs) != 0) {
91503831d35Sstevel 		kmem_free(phys_banks, bsize);
91603831d35Sstevel 		kmem_free(mc_idle_regs, msize);
91703831d35Sstevel 		return (-1);
91803831d35Sstevel 	}
91903831d35Sstevel 
92003831d35Sstevel 	/* section 1 */
92103831d35Sstevel 	for (i = 0; i < nbanks; i++)
92203831d35Sstevel 		rsp[(*rsp_idx)++] = phys_banks[i];
92303831d35Sstevel 
92403831d35Sstevel 	/* section 2 */
92503831d35Sstevel 	for (i = 0; i < nregs; i++)
92603831d35Sstevel 		rsp[(*rsp_idx)++] = *(sbdp_rename_script_t *)&mc_idle_regs[i];
92703831d35Sstevel 
92803831d35Sstevel 	kmem_free(phys_banks, bsize);
92903831d35Sstevel 	kmem_free(mc_idle_regs, msize);
93003831d35Sstevel 
93103831d35Sstevel 	return (0);
93203831d35Sstevel }
93303831d35Sstevel 
93403831d35Sstevel /*
93503831d35Sstevel  * code assumes single mem-unit.
93603831d35Sstevel  */
93703831d35Sstevel static int
sbdp_prep_rename_script(sbdp_cr_handle_t * cph)93803831d35Sstevel sbdp_prep_rename_script(sbdp_cr_handle_t *cph)
93903831d35Sstevel {
94003831d35Sstevel 	pnode_t			*s_nodes, *t_nodes;
94103831d35Sstevel 	int			m = 0, i;
94203831d35Sstevel 	sbdp_bd_t		s_bd, t_bd, *s_bdp, *t_bdp;
94303831d35Sstevel 	sbdp_rename_script_t	*rsp;
94403831d35Sstevel 	uint64_t		new_base, old_base, temp_base;
94503831d35Sstevel 	int			s_num, t_num;
94603831d35Sstevel 
94703831d35Sstevel 	mutex_enter(&cph->s_bdp->bd_mutex);
94803831d35Sstevel 	s_bd = *cph->s_bdp;
94903831d35Sstevel 	mutex_exit(&cph->s_bdp->bd_mutex);
95003831d35Sstevel 	mutex_enter(&cph->t_bdp->bd_mutex);
95103831d35Sstevel 	t_bd = *cph->t_bdp;
95203831d35Sstevel 	mutex_exit(&cph->t_bdp->bd_mutex);
95303831d35Sstevel 
95403831d35Sstevel 	s_bdp = &s_bd;
95503831d35Sstevel 	t_bdp = &t_bd;
95603831d35Sstevel 	s_nodes = s_bdp->nodes;
95703831d35Sstevel 	t_nodes = t_bdp->nodes;
95803831d35Sstevel 	s_num = s_bdp->nnum;
95903831d35Sstevel 	t_num = t_bdp->nnum;
96003831d35Sstevel 	rsp = cph->script;
96103831d35Sstevel 
96203831d35Sstevel 	/*
96303831d35Sstevel 	 * Calculate the new base address for the target bd
96403831d35Sstevel 	 */
96503831d35Sstevel 
96603831d35Sstevel 	new_base = (s_bdp->bpa >> PHYS2UM_SHIFT) << MC_UM_SHIFT;
96703831d35Sstevel 
96803831d35Sstevel 	/*
96903831d35Sstevel 	 * Calculate the old base address for the source bd
97003831d35Sstevel 	 */
97103831d35Sstevel 
97203831d35Sstevel 	old_base = (t_bdp->bpa >> PHYS2UM_SHIFT) << MC_UM_SHIFT;
97303831d35Sstevel 
97403831d35Sstevel 	temp_base = SG_INVAL_UM;
97503831d35Sstevel 
97603831d35Sstevel 	SBDP_DBG_MEM("new 0x%lx old_base ox%lx temp_base 0x%lx\n", new_base,
97703831d35Sstevel 	    old_base, temp_base);
97803831d35Sstevel 
97903831d35Sstevel 	m = 0;
98003831d35Sstevel 
98103831d35Sstevel 	/*
98203831d35Sstevel 	 * Ensure the MC queues have been idled on the source and target
98303831d35Sstevel 	 * following the copy.
98403831d35Sstevel 	 */
98503831d35Sstevel 	if (sbdp_prep_mc_idle_script(s_bdp, t_bdp, rsp, &m) < 0)
98603831d35Sstevel 		return (-1);
98703831d35Sstevel 
98803831d35Sstevel 	/*
98903831d35Sstevel 	 * Script section terminator
99003831d35Sstevel 	 */
99103831d35Sstevel 	rsp[m].masr_addr = 0ull;
99203831d35Sstevel 	rsp[m].masr = 0;
99303831d35Sstevel 	rsp[m].asi = 0;
99403831d35Sstevel 	m++;
99503831d35Sstevel 
99603831d35Sstevel 	/*
99703831d35Sstevel 	 * Invalidate the base in the target mc registers
99803831d35Sstevel 	 */
99903831d35Sstevel 	for (i = 0; i < t_num; i++) {
100003831d35Sstevel 		if (sbdp_copy_regs(t_nodes[i], t_bdp->bpa, temp_base, 1, rsp,
100103831d35Sstevel 		    &m) < 0)
100203831d35Sstevel 			return (-1);
100303831d35Sstevel 	}
100403831d35Sstevel 	/*
100503831d35Sstevel 	 * Invalidate the base in the source mc registers
100603831d35Sstevel 	 */
100703831d35Sstevel 	for (i = 0; i < s_num; i++) {
100803831d35Sstevel 		if (sbdp_copy_regs(s_nodes[i], s_bdp->bpa, temp_base, 1, rsp,
100903831d35Sstevel 		    &m) < 0)
101003831d35Sstevel 			return (-1);
101103831d35Sstevel 	}
101203831d35Sstevel 	/*
101303831d35Sstevel 	 * Copy the new base into the targets mc registers
101403831d35Sstevel 	 */
101503831d35Sstevel 	for (i = 0; i < t_num; i++) {
101603831d35Sstevel 		if (sbdp_copy_regs(t_nodes[i], t_bdp->bpa, new_base, 0, rsp,
101703831d35Sstevel 		    &m) < 0)
101803831d35Sstevel 			return (-1);
101903831d35Sstevel 	}
102003831d35Sstevel 	/*
102103831d35Sstevel 	 * Copy the old base into the source mc registers
102203831d35Sstevel 	 */
102303831d35Sstevel 	for (i = 0; i < s_num; i++) {
102403831d35Sstevel 		if (sbdp_copy_regs(s_nodes[i], s_bdp->bpa, old_base, 0, rsp,
102503831d35Sstevel 		    &m) < 0)
102603831d35Sstevel 			return (-1);
102703831d35Sstevel 	}
102803831d35Sstevel 	/*
102903831d35Sstevel 	 * Zero masr_addr value indicates the END.
103003831d35Sstevel 	 */
103103831d35Sstevel 	rsp[m].masr_addr = 0ull;
103203831d35Sstevel 	rsp[m].masr = 0;
103303831d35Sstevel 	rsp[m].asi = 0;
103403831d35Sstevel 	m++;
103503831d35Sstevel 
103603831d35Sstevel #ifdef DEBUG
103703831d35Sstevel 	{
103803831d35Sstevel 		int	i;
103903831d35Sstevel 
104003831d35Sstevel 		SBDP_DBG_MEM("dumping copy-rename script:\n");
104103831d35Sstevel 		for (i = 0; i < m; i++) {
104203831d35Sstevel 			SBDP_DBG_MEM("0x%lx = 0x%lx, asi 0x%x\n",
1043d3d50737SRafael Vanoni 			    rsp[i].masr_addr, rsp[i].masr, rsp[i].asi);
104403831d35Sstevel 		}
104503831d35Sstevel 		DELAY(1000000);
104603831d35Sstevel 	}
104703831d35Sstevel #endif /* DEBUG */
104803831d35Sstevel 
104903831d35Sstevel 	return (m * sizeof (sbdp_rename_script_t));
105003831d35Sstevel }
105103831d35Sstevel 
105203831d35Sstevel /*
105303831d35Sstevel  * EMU Activity Status Register needs to be read idle several times.
105403831d35Sstevel  * See Panther PRM 12.5.
105503831d35Sstevel  */
105603831d35Sstevel #define	SBDP_MCU_IDLE_RETRIES	10
105703831d35Sstevel #define	SBDP_MCU_IDLE_READS	3
105803831d35Sstevel 
105903831d35Sstevel /*
106003831d35Sstevel  * Using the "__relocatable" suffix informs DTrace providers (and anything
106103831d35Sstevel  * else, for that matter) that this function's text may be manually relocated
106203831d35Sstevel  * elsewhere before it is executed.  That is, it cannot be safely instrumented
106303831d35Sstevel  * with any methodology that is PC-relative.
106403831d35Sstevel  */
106503831d35Sstevel static int
sbdp_copy_rename__relocatable(sbdp_cr_handle_t * hp,struct memlist * mlist,register sbdp_rename_script_t * rsp)106603831d35Sstevel sbdp_copy_rename__relocatable(sbdp_cr_handle_t *hp, struct memlist *mlist,
106703831d35Sstevel 		register sbdp_rename_script_t *rsp)
106803831d35Sstevel {
106903831d35Sstevel 	sbdp_cr_err_t	err = SBDP_CR_OK;
107003831d35Sstevel 	size_t		csize;
107103831d35Sstevel 	size_t		linesize;
107203831d35Sstevel 	uint_t		size;
107303831d35Sstevel 	uint64_t	caddr;
107403831d35Sstevel 	uint64_t	s_base, t_base;
107503831d35Sstevel 	sbdp_bd_t	*s_sbp, *t_sbp;
107603831d35Sstevel 	struct memlist	*ml;
107703831d35Sstevel 	sbdp_mc_idle_script_t *isp;
107803831d35Sstevel 	int		i;
107903831d35Sstevel 
108003831d35Sstevel 	caddr = ecache_flushaddr;
108103831d35Sstevel 	csize = (size_t)(cpunodes[CPU->cpu_id].ecache_size * 2);
108203831d35Sstevel 	linesize = (size_t)(cpunodes[CPU->cpu_id].ecache_linesize);
108303831d35Sstevel 
108403831d35Sstevel 	size = 0;
108503831d35Sstevel 	s_sbp = hp->s_bdp;
108603831d35Sstevel 	t_sbp = hp->t_bdp;
108703831d35Sstevel 
108803831d35Sstevel 	s_base = (uint64_t)s_sbp->bpa;
108903831d35Sstevel 	t_base = (uint64_t)t_sbp->bpa;
109003831d35Sstevel 
109103831d35Sstevel 	hp->ret = s_base;
109203831d35Sstevel 	/*
109303831d35Sstevel 	 * DO COPY.
109403831d35Sstevel 	 */
1095*56f33205SJonathan Adams 	for (ml = mlist; ml; ml = ml->ml_next) {
109603831d35Sstevel 		uint64_t	s_pa, t_pa;
109703831d35Sstevel 		uint64_t	nbytes;
109803831d35Sstevel 
1099*56f33205SJonathan Adams 		s_pa = ml->ml_address;
1100*56f33205SJonathan Adams 		t_pa = t_base + (ml->ml_address - s_base);
1101*56f33205SJonathan Adams 		nbytes = ml->ml_size;
110203831d35Sstevel 
110303831d35Sstevel 		size += nbytes;
110403831d35Sstevel 		while (nbytes != 0ull) {
110503831d35Sstevel 			/*
110603831d35Sstevel 			 * This copy does NOT use an ASI
110703831d35Sstevel 			 * that avoids the Ecache, therefore
110803831d35Sstevel 			 * the dst_pa addresses may remain
110903831d35Sstevel 			 * in our Ecache after the dst_pa
111003831d35Sstevel 			 * has been removed from the system.
111103831d35Sstevel 			 * A subsequent write-back to memory
111203831d35Sstevel 			 * will cause an ARB-stop because the
111303831d35Sstevel 			 * physical address no longer exists
111403831d35Sstevel 			 * in the system. Therefore we must
111503831d35Sstevel 			 * flush out local Ecache after we
111603831d35Sstevel 			 * finish the copy.
111703831d35Sstevel 			 */
111803831d35Sstevel 
111903831d35Sstevel 			/* copy 32 bytes at src_pa to dst_pa */
112003831d35Sstevel 			bcopy32_il(s_pa, t_pa);
112103831d35Sstevel 
112203831d35Sstevel 			/* increment by 32 bytes */
112303831d35Sstevel 			s_pa += (4 * sizeof (uint64_t));
112403831d35Sstevel 			t_pa += (4 * sizeof (uint64_t));
112503831d35Sstevel 
112603831d35Sstevel 			/* decrement by 32 bytes */
112703831d35Sstevel 			nbytes -= (4 * sizeof (uint64_t));
112803831d35Sstevel 		}
112903831d35Sstevel 	}
113003831d35Sstevel 
113103831d35Sstevel 	/*
113203831d35Sstevel 	 * Since bcopy32_il() does NOT use an ASI to bypass
113303831d35Sstevel 	 * the Ecache, we need to flush our Ecache after
113403831d35Sstevel 	 * the copy is complete.
113503831d35Sstevel 	 */
113603831d35Sstevel 	flush_ecache_il(caddr, csize, linesize);	/* inline version */
113703831d35Sstevel 
113803831d35Sstevel 	/*
113903831d35Sstevel 	 * Non-Panther MCs are idled by reading each physical bank.
114003831d35Sstevel 	 */
114103831d35Sstevel 	for (i = 0; rsp[i].asi == ASI_MEM; i++) {
114203831d35Sstevel 		(void) lddphys_il(rsp[i].masr_addr);
114303831d35Sstevel 	}
114403831d35Sstevel 
114503831d35Sstevel 	isp = (sbdp_mc_idle_script_t *)&rsp[i];
114603831d35Sstevel 
114703831d35Sstevel 	/*
114803831d35Sstevel 	 * Panther MCs are idled by polling until the MCU idle state
114903831d35Sstevel 	 * is read SBDP_MCU_IDLE_READS times in succession.
115003831d35Sstevel 	 */
115103831d35Sstevel 	while (isp->addr != 0ull) {
115203831d35Sstevel 		for (i = 0; i < SBDP_MCU_IDLE_RETRIES; i++) {
115303831d35Sstevel 			register uint64_t v;
115403831d35Sstevel 			register int n_idle = 0;
115503831d35Sstevel 
115603831d35Sstevel 
115703831d35Sstevel 			do {
115803831d35Sstevel 				v = ldxasi_il(isp->addr, isp->asi) &
115903831d35Sstevel 				    MCU_ACT_STATUS;
116003831d35Sstevel 			} while (v != MCU_ACT_STATUS &&
116103831d35Sstevel 			    ++n_idle < SBDP_MCU_IDLE_READS);
116203831d35Sstevel 
116303831d35Sstevel 			if (n_idle == SBDP_MCU_IDLE_READS)
116403831d35Sstevel 				break;
116503831d35Sstevel 		}
116603831d35Sstevel 
116703831d35Sstevel 		if (i == SBDP_MCU_IDLE_RETRIES) {
116803831d35Sstevel 			/* bailout */
116903831d35Sstevel 			hp->busy_mc = isp;
117003831d35Sstevel 			return (SBDP_CR_MC_IDLE_ERR);
117103831d35Sstevel 		}
117203831d35Sstevel 
117303831d35Sstevel 		isp++;
117403831d35Sstevel 	}
117503831d35Sstevel 
117603831d35Sstevel 	/* skip terminator */
117703831d35Sstevel 	isp++;
117803831d35Sstevel 
117903831d35Sstevel 	/*
118003831d35Sstevel 	 * The following inline assembly routine caches
118103831d35Sstevel 	 * the rename script and then caches the code that
118203831d35Sstevel 	 * will do the rename.  This is necessary
118303831d35Sstevel 	 * so that we don't have any memory references during
118403831d35Sstevel 	 * the reprogramming.  We accomplish this by first
118503831d35Sstevel 	 * jumping through the code to guarantee it's cached
118603831d35Sstevel 	 * before we actually execute it.
118703831d35Sstevel 	 */
118803831d35Sstevel 	sbdp_exec_script_il((sbdp_rename_script_t *)isp);
118903831d35Sstevel 
119003831d35Sstevel 	return (err);
119103831d35Sstevel }
119203831d35Sstevel static void
_sbdp_copy_rename_end(void)119303831d35Sstevel _sbdp_copy_rename_end(void)
119403831d35Sstevel {
119503831d35Sstevel 	/*
119603831d35Sstevel 	 * IMPORTANT:   This function's location MUST be located immediately
119703831d35Sstevel 	 *		following sbdp_copy_rename__relocatable to accurately
119803831d35Sstevel 	 *		estimate its size.  Note that this assumes (!)the
119903831d35Sstevel 	 *		compiler keeps these functions in the order in which
120003831d35Sstevel 	 *		they appear :-o
120103831d35Sstevel 	 */
120203831d35Sstevel }
120303831d35Sstevel int
sbdp_memory_rename(sbdp_handle_t * hp)120403831d35Sstevel sbdp_memory_rename(sbdp_handle_t *hp)
120503831d35Sstevel {
120603831d35Sstevel #ifdef lint
120703831d35Sstevel 	/*
120803831d35Sstevel 	 * Delete when implemented
120903831d35Sstevel 	 */
121003831d35Sstevel 	hp = hp;
121103831d35Sstevel #endif
121203831d35Sstevel 	return (0);
121303831d35Sstevel }
121403831d35Sstevel 
121503831d35Sstevel 
121603831d35Sstevel /*
121703831d35Sstevel  * In Serengeti this is a nop
121803831d35Sstevel  */
121903831d35Sstevel int
sbdp_post_configure_mem(sbdp_handle_t * hp)122003831d35Sstevel sbdp_post_configure_mem(sbdp_handle_t *hp)
122103831d35Sstevel {
122203831d35Sstevel #ifdef lint
122303831d35Sstevel 	hp = hp;
122403831d35Sstevel #endif
122503831d35Sstevel 	return (0);
122603831d35Sstevel }
122703831d35Sstevel 
122803831d35Sstevel /*
122903831d35Sstevel  * In Serengeti this is a nop
123003831d35Sstevel  */
123103831d35Sstevel int
sbdp_post_unconfigure_mem(sbdp_handle_t * hp)123203831d35Sstevel sbdp_post_unconfigure_mem(sbdp_handle_t *hp)
123303831d35Sstevel {
123403831d35Sstevel #ifdef lint
123503831d35Sstevel 	hp = hp;
123603831d35Sstevel #endif
123703831d35Sstevel 	return (0);
123803831d35Sstevel }
123903831d35Sstevel 
124003831d35Sstevel /* ARGSUSED */
124103831d35Sstevel int
sbdphw_disable_memctrl(sbdp_handle_t * hp,dev_info_t * dip)124203831d35Sstevel sbdphw_disable_memctrl(sbdp_handle_t *hp, dev_info_t *dip)
124303831d35Sstevel {
124403831d35Sstevel 	return (0);
124503831d35Sstevel }
124603831d35Sstevel 
124703831d35Sstevel /* ARGSUSED */
124803831d35Sstevel int
sbdphw_enable_memctrl(sbdp_handle_t * hp,dev_info_t * dip)124903831d35Sstevel sbdphw_enable_memctrl(sbdp_handle_t *hp, dev_info_t *dip)
125003831d35Sstevel {
125103831d35Sstevel 	return (0);
125203831d35Sstevel }
125303831d35Sstevel 
125403831d35Sstevel /*
125503831d35Sstevel  * We are assuming one memory node therefore the base address is the lowest
125603831d35Sstevel  * segment possible
125703831d35Sstevel  */
125803831d35Sstevel #define	PA_ABOVE_MAX	(0x8000000000000000ull)
125903831d35Sstevel int
sbdphw_get_base_physaddr(sbdp_handle_t * hp,dev_info_t * dip,uint64_t * pa)126003831d35Sstevel sbdphw_get_base_physaddr(sbdp_handle_t *hp, dev_info_t *dip, uint64_t *pa)
126103831d35Sstevel {
126203831d35Sstevel 	_NOTE(ARGUNUSED(hp))
126303831d35Sstevel 
126403831d35Sstevel 	int i, board = -1, wnode;
126503831d35Sstevel 	pnode_t	nodeid;
126603831d35Sstevel 	struct mem_arg arg = {0};
126703831d35Sstevel 	uint64_t seg_pa, tmp_pa;
126803831d35Sstevel 	dev_info_t *list[SBDP_MAX_MEM_NODES_PER_BOARD];
126903831d35Sstevel 	int rc;
127003831d35Sstevel 
127103831d35Sstevel 	if (dip == NULL)
127203831d35Sstevel 		return (-1);
127303831d35Sstevel 
127403831d35Sstevel 	nodeid = ddi_get_nodeid(dip);
127503831d35Sstevel 
127603831d35Sstevel 	if (sbdp_get_bd_and_wnode_num(nodeid, &board, &wnode) < 0)
127703831d35Sstevel 		return (-1);
127803831d35Sstevel 
127903831d35Sstevel 	list[0] = NULL;
128003831d35Sstevel 	arg.board = board;
128103831d35Sstevel 	arg.list = list;
128203831d35Sstevel 
128303831d35Sstevel 	(void) sbdp_walk_prom_tree(prom_rootnode(), sbdp_get_mem_dip, &arg);
128403831d35Sstevel 
128503831d35Sstevel 	if (arg.ndips <= 0)
128603831d35Sstevel 		return (-1);
128703831d35Sstevel 
128803831d35Sstevel 	seg_pa = PA_ABOVE_MAX;
128903831d35Sstevel 
129003831d35Sstevel 	rc = -1;
129103831d35Sstevel 	for (i = 0; i < arg.ndips; i++) {
129203831d35Sstevel 		if (list[i] == NULL)
129303831d35Sstevel 			continue;
129403831d35Sstevel 		if (sbdp_get_lowest_addr_in_node(ddi_get_nodeid(list[i]),
129503831d35Sstevel 		    &tmp_pa) == 0) {
129603831d35Sstevel 			rc = 0;
129703831d35Sstevel 			if (tmp_pa < seg_pa)
129803831d35Sstevel 				seg_pa = tmp_pa;
129903831d35Sstevel 		}
130003831d35Sstevel 
130103831d35Sstevel 		/*
130203831d35Sstevel 		 * Release hold acquired in sbdp_get_mem_dip()
130303831d35Sstevel 		 */
130403831d35Sstevel 		ddi_release_devi(list[i]);
130503831d35Sstevel 	}
130603831d35Sstevel 
130703831d35Sstevel 	if (rc == 0)
130803831d35Sstevel 		*pa = seg_pa;
130903831d35Sstevel 	else {
131003831d35Sstevel 		/*
131103831d35Sstevel 		 * Record the fact that an error has occurred
131203831d35Sstevel 		 */
131303831d35Sstevel 		sbdp_set_err(hp->h_err, ESGT_INTERNAL, NULL);
131403831d35Sstevel 	}
131503831d35Sstevel 
131603831d35Sstevel 	return (rc);
131703831d35Sstevel }
131803831d35Sstevel 
131903831d35Sstevel static int
sbdp_get_lowest_addr_in_node(pnode_t node,uint64_t * pa)132003831d35Sstevel sbdp_get_lowest_addr_in_node(pnode_t node, uint64_t *pa)
132103831d35Sstevel {
132203831d35Sstevel 	uint64_t	mc_decode, seg_pa, tmp_pa;
132303831d35Sstevel 	mc_regs_t	mc_regs, *mc_regsp = &mc_regs;
132403831d35Sstevel 	int		i, valid;
132503831d35Sstevel 	int		rc;
132603831d35Sstevel 
132703831d35Sstevel 
132803831d35Sstevel 	seg_pa = PA_ABOVE_MAX;
132903831d35Sstevel 
133003831d35Sstevel 	if (mc_read_regs(node, mc_regsp)) {
133103831d35Sstevel 		SBDP_DBG_MEM("sbdp_get_lowest_addr_in_node: failed to "
133203831d35Sstevel 		    "read source Decode Regs\n");
133303831d35Sstevel 		return (-1);
133403831d35Sstevel 	}
133503831d35Sstevel 
133603831d35Sstevel 	rc = -1;
133703831d35Sstevel 	for (i = 0; i < SBDP_MAX_MCS_PER_NODE; i++) {
133803831d35Sstevel 		mc_decode = mc_regsp->mc_decode[i];
133903831d35Sstevel 		valid = mc_decode >> MC_VALID_SHIFT;
134003831d35Sstevel 		tmp_pa = MC_BASE(mc_decode) << PHYS2UM_SHIFT;
134103831d35Sstevel 		if (valid)
134203831d35Sstevel 			rc = 0;
134303831d35Sstevel 		if (valid && (tmp_pa < seg_pa))
134403831d35Sstevel 			seg_pa = tmp_pa;
134503831d35Sstevel 	}
134603831d35Sstevel 
134703831d35Sstevel 	if (rc == 0)
134803831d35Sstevel 		*pa = seg_pa;
134903831d35Sstevel 
135003831d35Sstevel 	return (rc);
135103831d35Sstevel }
135203831d35Sstevel 
135303831d35Sstevel int
sbdp_is_mem(pnode_t node,void * arg)135403831d35Sstevel sbdp_is_mem(pnode_t node, void *arg)
135503831d35Sstevel {
135603831d35Sstevel 	mem_op_t	*memp = (mem_op_t *)arg;
135703831d35Sstevel 	char		type[OBP_MAXPROPNAME];
135803831d35Sstevel 	int		bd;
135903831d35Sstevel 	pnode_t		*list;
136003831d35Sstevel 	int		board;
136103831d35Sstevel 	char		name[OBP_MAXDRVNAME];
136203831d35Sstevel 	int		len;
136303831d35Sstevel 
136403831d35Sstevel 	ASSERT(memp);
136503831d35Sstevel 
136603831d35Sstevel 	list = memp->nodes;
136703831d35Sstevel 	board = memp->board;
136803831d35Sstevel 
136903831d35Sstevel 	/*
137003831d35Sstevel 	 * Make sure that this node doesn't have its status
137103831d35Sstevel 	 * as failed
137203831d35Sstevel 	 */
137303831d35Sstevel 	if (sbdp_get_comp_status(node) != SBD_COND_OK) {
137403831d35Sstevel 		return (DDI_FAILURE);
137503831d35Sstevel 	}
137603831d35Sstevel 
137703831d35Sstevel 	len = prom_getproplen(node, "device_type");
137803831d35Sstevel 	if ((len > 0) && (len < OBP_MAXPROPNAME))
137903831d35Sstevel 		(void) prom_getprop(node, "device_type", (caddr_t)type);
138003831d35Sstevel 	else
138103831d35Sstevel 		type[0] = '\0';
138203831d35Sstevel 
138303831d35Sstevel 	if (strcmp(type, "memory-controller") == 0) {
138403831d35Sstevel 		int	wnode;
138503831d35Sstevel 
138603831d35Sstevel 		if (sbdp_get_bd_and_wnode_num(node, &bd, &wnode) < 0)
138703831d35Sstevel 			return (DDI_FAILURE);
138803831d35Sstevel 
138903831d35Sstevel 		if (bd == board) {
139003831d35Sstevel 			/*
139103831d35Sstevel 			 * Make sure we don't overwrite the array
139203831d35Sstevel 			 */
139303831d35Sstevel 			if (memp->nmem >= SBDP_MAX_MEM_NODES_PER_BOARD)
139403831d35Sstevel 				return (DDI_FAILURE);
139503831d35Sstevel 			(void) prom_getprop(node, OBP_NAME, (caddr_t)name);
139603831d35Sstevel 			SBDP_DBG_MEM("name %s  boot bd %d board %d\n", name,
139703831d35Sstevel 			    board, bd);
139803831d35Sstevel 			list[memp->nmem++] = node;
139903831d35Sstevel 			return (DDI_SUCCESS);
140003831d35Sstevel 		}
140103831d35Sstevel 	}
140203831d35Sstevel 
140303831d35Sstevel 	return (DDI_FAILURE);
140403831d35Sstevel }
140503831d35Sstevel 
140603831d35Sstevel static int
sbdp_get_meminfo(pnode_t nodeid,int mc,uint64_t * size,uint64_t * base_pa)140703831d35Sstevel sbdp_get_meminfo(pnode_t nodeid, int mc, uint64_t *size, uint64_t *base_pa)
140803831d35Sstevel {
140903831d35Sstevel 	int		board, wnode;
141003831d35Sstevel 	int		valid;
141103831d35Sstevel 	mc_regs_t	mc_regs, *mc_regsp = &mc_regs;
141203831d35Sstevel 	uint64_t	mc_decode = 0;
141303831d35Sstevel 
141403831d35Sstevel 	if (sbdp_get_bd_and_wnode_num(nodeid, &board, &wnode) < 0)
141503831d35Sstevel 		return (-1);
141603831d35Sstevel 
141703831d35Sstevel 	if (mc_read_regs(nodeid, mc_regsp)) {
141803831d35Sstevel 		SBDP_DBG_MEM("sbdp_get_meminfo: failed to read source "
141903831d35Sstevel 		    "Decode Regs");
142003831d35Sstevel 		return (-1);
142103831d35Sstevel 	}
142203831d35Sstevel 	/*
142303831d35Sstevel 	 * Calculate memory size
142403831d35Sstevel 	 */
142503831d35Sstevel 	mc_decode = mc_regsp->mc_decode[mc];
142603831d35Sstevel 
142703831d35Sstevel 	/*
142803831d35Sstevel 	 * Check the valid bit to see if bank is there
142903831d35Sstevel 	 */
143003831d35Sstevel 	valid = mc_decode >> MC_VALID_SHIFT;
143103831d35Sstevel 	if (valid) {
143203831d35Sstevel 		*size = MC_UK2SPAN(mc_decode);
143303831d35Sstevel 		*base_pa = MC_BASE(mc_decode) << PHYS2UM_SHIFT;
143403831d35Sstevel 	}
143503831d35Sstevel 
143603831d35Sstevel 	return (0);
143703831d35Sstevel }
143803831d35Sstevel 
143903831d35Sstevel 
144003831d35Sstevel /*
144103831d35Sstevel  * Luckily for us mem nodes and cpu/CMP nodes are siblings.  All we need to
144203831d35Sstevel  * do is search in the same branch as the mem node for its sibling cpu or
144303831d35Sstevel  * CMP node.
144403831d35Sstevel  */
144503831d35Sstevel pnode_t
mc_get_sibling_cpu(pnode_t nodeid)144603831d35Sstevel mc_get_sibling_cpu(pnode_t nodeid)
144703831d35Sstevel {
144803831d35Sstevel 	int	portid;
144903831d35Sstevel 
145003831d35Sstevel 	if (prom_getprop(nodeid, OBP_PORTID, (caddr_t)&portid) < 0)
145103831d35Sstevel 		return (OBP_NONODE);
145203831d35Sstevel 
145303831d35Sstevel 	/*
145403831d35Sstevel 	 * cpus and memory are siblings so we don't need to traverse
145503831d35Sstevel 	 * the whole tree, just a branch
145603831d35Sstevel 	 */
145703831d35Sstevel 	return (sbdp_find_nearby_cpu_by_portid(nodeid, portid));
145803831d35Sstevel }
145903831d35Sstevel 
146003831d35Sstevel /*
146103831d35Sstevel  * Given a memory node, check it's sibling cpu or CMP to see if
146203831d35Sstevel  * access to mem will be ok. We need to search for the node and
146303831d35Sstevel  * if found get its condition.
146403831d35Sstevel  */
146503831d35Sstevel sbd_cond_t
mc_check_sibling_cpu(pnode_t nodeid)146603831d35Sstevel mc_check_sibling_cpu(pnode_t nodeid)
146703831d35Sstevel {
146803831d35Sstevel 	pnode_t	cpu_node;
146903831d35Sstevel 	sbd_cond_t	cond;
147003831d35Sstevel 	int		i;
147103831d35Sstevel 
147203831d35Sstevel 	cpu_node = mc_get_sibling_cpu(nodeid);
147303831d35Sstevel 
147403831d35Sstevel 	cond = sbdp_get_comp_status(cpu_node);
147503831d35Sstevel 
147603831d35Sstevel 	if (cond == SBD_COND_OK) {
147703831d35Sstevel 		int 		wnode;
147803831d35Sstevel 		int		bd;
147903831d35Sstevel 		int		unit;
148003831d35Sstevel 		int		portid;
148103831d35Sstevel 
148203831d35Sstevel 		if (sbdp_get_bd_and_wnode_num(nodeid, &bd, &wnode) < 0)
148303831d35Sstevel 			return (SBD_COND_UNKNOWN);
148403831d35Sstevel 
148503831d35Sstevel 		(void) prom_getprop(nodeid, OBP_PORTID, (caddr_t)&portid);
148603831d35Sstevel 
148703831d35Sstevel 		/*
148803831d35Sstevel 		 * Access to the memory controller should not
148903831d35Sstevel 		 * be attempted if any of the cores are marked
149003831d35Sstevel 		 * as being in reset.
149103831d35Sstevel 		 */
149225cf1a30Sjl 		for (i = 0; i < SBDP_MAX_CORES_PER_CMP; i++) {
149303831d35Sstevel 			unit = SG_PORTID_TO_CPU_UNIT(portid, i);
149403831d35Sstevel 			if (sbdp_is_cpu_present(wnode, bd, unit) &&
149503831d35Sstevel 			    sbdp_is_cpu_in_reset(wnode, bd, unit)) {
149603831d35Sstevel 				cond = SBD_COND_UNUSABLE;
149703831d35Sstevel 				break;
149803831d35Sstevel 			}
149903831d35Sstevel 		}
150003831d35Sstevel 	}
150103831d35Sstevel 
150203831d35Sstevel 	return (cond);
150303831d35Sstevel }
150403831d35Sstevel 
150503831d35Sstevel int
mc_read_regs(pnode_t nodeid,mc_regs_t * mc_regsp)150603831d35Sstevel mc_read_regs(pnode_t nodeid, mc_regs_t *mc_regsp)
150703831d35Sstevel {
150803831d35Sstevel 	int			len;
150903831d35Sstevel 	uint64_t		mc_addr, mask;
151003831d35Sstevel 	mc_regspace		reg;
151103831d35Sstevel 	sbd_cond_t		sibling_cpu_cond;
151203831d35Sstevel 	int			local_mc;
151303831d35Sstevel 	int			portid;
151403831d35Sstevel 	int			i;
151503831d35Sstevel 
151603831d35Sstevel 	if ((prom_getprop(nodeid, "portid", (caddr_t)&portid) < 0) ||
151703831d35Sstevel 	    (portid == -1))
151803831d35Sstevel 		return (-1);
151903831d35Sstevel 
152003831d35Sstevel 	/*
152103831d35Sstevel 	 * mc should not be accessed if their corresponding cpu
152203831d35Sstevel 	 * has failed.
152303831d35Sstevel 	 */
152403831d35Sstevel 	sibling_cpu_cond = mc_check_sibling_cpu(nodeid);
152503831d35Sstevel 
152603831d35Sstevel 	if ((sibling_cpu_cond == SBD_COND_FAILED) ||
152703831d35Sstevel 	    (sibling_cpu_cond == SBD_COND_UNUSABLE)) {
152803831d35Sstevel 		return (-1);
152903831d35Sstevel 	}
153003831d35Sstevel 
153103831d35Sstevel 	len = prom_getproplen(nodeid, "reg");
153203831d35Sstevel 	if (len != sizeof (mc_regspace))
153303831d35Sstevel 		return (-1);
153403831d35Sstevel 
153503831d35Sstevel 	if (prom_getprop(nodeid, "reg", (caddr_t)&reg) < 0)
153603831d35Sstevel 		return (-1);
153703831d35Sstevel 
153803831d35Sstevel 	mc_addr = ((uint64_t)reg.regspec_addr_hi) << 32;
153903831d35Sstevel 	mc_addr |= (uint64_t)reg.regspec_addr_lo;
154003831d35Sstevel 
154103831d35Sstevel 	/*
154203831d35Sstevel 	 * Make sure we don't switch cpus
154303831d35Sstevel 	 */
154403831d35Sstevel 	affinity_set(CPU_CURRENT);
154503831d35Sstevel 	if (portid == cpunodes[CPU->cpu_id].portid)
154603831d35Sstevel 		local_mc = 1;
154703831d35Sstevel 	else
154803831d35Sstevel 		local_mc = 0;
154903831d35Sstevel 
155003831d35Sstevel 	for (i = 0; i < SG_MAX_BANKS_PER_MC; i++) {
155103831d35Sstevel 		mask = SG_REG_2_OFFSET(i);
155203831d35Sstevel 
155303831d35Sstevel 		/*
155403831d35Sstevel 		 * If the memory controller is local to this CPU, we use
155503831d35Sstevel 		 * the special ASI to read the decode registers.
155603831d35Sstevel 		 * Otherwise, we load the values from a magic address in
155703831d35Sstevel 		 * I/O space.
155803831d35Sstevel 		 */
155903831d35Sstevel 		if (local_mc) {
156003831d35Sstevel 			mc_regsp->mc_decode[i] = lddmcdecode(
156103831d35Sstevel 			    mask & MC_OFFSET_MASK);
156203831d35Sstevel 		} else {
156303831d35Sstevel 			mc_regsp->mc_decode[i] = lddphysio(
156403831d35Sstevel 			    (mc_addr | mask));
156503831d35Sstevel 		}
156603831d35Sstevel 	}
156703831d35Sstevel 	affinity_clear();
156803831d35Sstevel 
156903831d35Sstevel 	return (0);
157003831d35Sstevel }
157103831d35Sstevel 
157203831d35Sstevel uint64_t
mc_get_addr(pnode_t nodeid,int mc,uint_t * asi)157303831d35Sstevel mc_get_addr(pnode_t nodeid, int mc, uint_t *asi)
157403831d35Sstevel {
157503831d35Sstevel 	int			len;
157603831d35Sstevel 	uint64_t		mc_addr, addr;
157703831d35Sstevel 	mc_regspace		reg;
157803831d35Sstevel 	int			portid;
157903831d35Sstevel 	int			local_mc;
158003831d35Sstevel 
158103831d35Sstevel 	if ((prom_getprop(nodeid, "portid", (caddr_t)&portid) < 0) ||
158203831d35Sstevel 	    (portid == -1))
158303831d35Sstevel 		return (-1);
158403831d35Sstevel 
158503831d35Sstevel 	len = prom_getproplen(nodeid, "reg");
158603831d35Sstevel 	if (len != sizeof (mc_regspace))
158703831d35Sstevel 		return (-1);
158803831d35Sstevel 
158903831d35Sstevel 	if (prom_getprop(nodeid, "reg", (caddr_t)&reg) < 0)
159003831d35Sstevel 		return (-1);
159103831d35Sstevel 
159203831d35Sstevel 	mc_addr = ((uint64_t)reg.regspec_addr_hi) << 32;
159303831d35Sstevel 	mc_addr |= (uint64_t)reg.regspec_addr_lo;
159403831d35Sstevel 
159503831d35Sstevel 	/*
159603831d35Sstevel 	 * Make sure we don't switch cpus
159703831d35Sstevel 	 */
159803831d35Sstevel 	affinity_set(CPU_CURRENT);
159903831d35Sstevel 	if (portid == cpunodes[CPU->cpu_id].portid)
160003831d35Sstevel 		local_mc = 1;
160103831d35Sstevel 	else
160203831d35Sstevel 		local_mc = 0;
160303831d35Sstevel 
160403831d35Sstevel 	if (local_mc) {
160503831d35Sstevel 		*asi = ASI_MC_DECODE;
160603831d35Sstevel 		addr = SG_REG_2_OFFSET(mc) & MC_OFFSET_MASK;
160703831d35Sstevel 	} else {
160803831d35Sstevel 		*asi = ASI_IO;
160903831d35Sstevel 		addr = SG_REG_2_OFFSET(mc) | mc_addr;
161003831d35Sstevel 	}
161103831d35Sstevel 	affinity_clear();
161203831d35Sstevel 
161303831d35Sstevel 	return (addr);
161403831d35Sstevel }
161503831d35Sstevel 
161603831d35Sstevel /* ARGSUSED */
161703831d35Sstevel int
sbdp_mem_add_span(sbdp_handle_t * hp,uint64_t address,uint64_t size)161803831d35Sstevel sbdp_mem_add_span(sbdp_handle_t *hp, uint64_t address, uint64_t size)
161903831d35Sstevel {
162003831d35Sstevel 	return (0);
162103831d35Sstevel }
162203831d35Sstevel 
162303831d35Sstevel int
sbdp_mem_del_span(sbdp_handle_t * hp,uint64_t address,uint64_t size)162403831d35Sstevel sbdp_mem_del_span(sbdp_handle_t *hp, uint64_t address, uint64_t size)
162503831d35Sstevel {
162603831d35Sstevel 	pfn_t		 basepfn = (pfn_t)(address >> PAGESHIFT);
162703831d35Sstevel 	pgcnt_t		 npages = (pgcnt_t)(size >> PAGESHIFT);
162803831d35Sstevel 
162903831d35Sstevel 	if (size > 0) {
163003831d35Sstevel 		int rv;
163103831d35Sstevel 		rv = kcage_range_delete_post_mem_del(basepfn, npages);
163203831d35Sstevel 		if (rv != 0) {
163303831d35Sstevel 			cmn_err(CE_WARN,
163403831d35Sstevel 			    "unexpected kcage_range_delete_post_mem_del"
163503831d35Sstevel 			    " return value %d", rv);
163603831d35Sstevel 			sbdp_set_err(hp->h_err, ESGT_INTERNAL, NULL);
163703831d35Sstevel 			return (-1);
163803831d35Sstevel 		}
163903831d35Sstevel 	}
164003831d35Sstevel 	return (0);
164103831d35Sstevel }
164203831d35Sstevel 
164303831d35Sstevel /*
164403831d35Sstevel  * This routine gets the size including the
164503831d35Sstevel  * bad banks
164603831d35Sstevel  */
164703831d35Sstevel int
sbdp_get_mem_size(sbdp_handle_t * hp)164803831d35Sstevel sbdp_get_mem_size(sbdp_handle_t *hp)
164903831d35Sstevel {
165003831d35Sstevel 	uint64_t	size = 0;
165103831d35Sstevel 	struct memlist	*mlist, *ml;
165203831d35Sstevel 
165303831d35Sstevel 	mlist = sbdp_get_memlist(hp, (dev_info_t *)NULL);
165403831d35Sstevel 
1655*56f33205SJonathan Adams 	for (ml = mlist; ml; ml = ml->ml_next)
1656*56f33205SJonathan Adams 		size += ml->ml_size;
165703831d35Sstevel 
165803831d35Sstevel 	(void) sbdp_del_memlist(hp, mlist);
165903831d35Sstevel 
166003831d35Sstevel 	SBDP_DBG_MEM("sbdp_get_mem_size: size 0x%" PRIx64 "\n", size);
166103831d35Sstevel 
166203831d35Sstevel 	return (btop(size));
166303831d35Sstevel }
166403831d35Sstevel 
166503831d35Sstevel /*
166603831d35Sstevel  * This function compares the list of banks passed with the banks
166703831d35Sstevel  * in the segment
166803831d35Sstevel  */
166903831d35Sstevel int
sbdp_check_seg_with_banks(sbdp_seg_t * seg,sbdp_bank_t * banks)167003831d35Sstevel sbdp_check_seg_with_banks(sbdp_seg_t *seg, sbdp_bank_t *banks)
167103831d35Sstevel {
167203831d35Sstevel 	sbdp_bank_t	*cur_bank, *bank;
167303831d35Sstevel 	int		i = 0;
167403831d35Sstevel 
167503831d35Sstevel 	for (cur_bank = seg->banks; cur_bank; cur_bank = cur_bank->seg_next) {
167603831d35Sstevel 		for (bank = banks; bank; bank = bank->bd_next) {
167703831d35Sstevel 			if (!bank->valid)
167803831d35Sstevel 				continue;
167903831d35Sstevel 
168003831d35Sstevel 			if (cur_bank == bank) {
168103831d35Sstevel 				i++;
168203831d35Sstevel 			}
168303831d35Sstevel 		}
168403831d35Sstevel 	}
168503831d35Sstevel 
168603831d35Sstevel 	SBDP_DBG_MEM("banks found = %d total banks = %d\n", i, seg->nbanks);
168703831d35Sstevel 	/*
168803831d35Sstevel 	 * If we find the same num of banks that are equal, then this segment
168903831d35Sstevel 	 * is not interleaved across boards
169003831d35Sstevel 	 */
169103831d35Sstevel 	if (i == seg->nbanks)
169203831d35Sstevel 		return (0);
169303831d35Sstevel 
169403831d35Sstevel 	return (1);
169503831d35Sstevel }
169603831d35Sstevel 
169703831d35Sstevel 
169803831d35Sstevel /*
169903831d35Sstevel  * This routine determines if any of the memory banks on the board
170003831d35Sstevel  * participate in across board memory interleaving
170103831d35Sstevel  */
170203831d35Sstevel int
sbdp_isinterleaved(sbdp_handle_t * hp,dev_info_t * dip)170303831d35Sstevel sbdp_isinterleaved(sbdp_handle_t *hp, dev_info_t *dip)
170403831d35Sstevel {
170503831d35Sstevel 	_NOTE(ARGUNUSED(dip))
170603831d35Sstevel 
170703831d35Sstevel 	sbdp_bank_t	*bankp;
170803831d35Sstevel 	int		wnode, board;
170903831d35Sstevel 	int		is_interleave = 0;
171003831d35Sstevel 	sbdp_bd_t	*bdp;
171103831d35Sstevel 	uint64_t	base;
171203831d35Sstevel 	sbdp_seg_t	*seg;
171303831d35Sstevel 
171403831d35Sstevel 	board = hp->h_board;
171503831d35Sstevel 	wnode = hp->h_wnode;
171603831d35Sstevel 
171703831d35Sstevel #ifdef DEBUG
171803831d35Sstevel 	sbdp_print_all_segs();
171903831d35Sstevel #endif
172003831d35Sstevel 	/*
172103831d35Sstevel 	 * Get the banks for this board
172203831d35Sstevel 	 */
172303831d35Sstevel 	bdp = sbdp_get_bd_info(wnode, board);
172403831d35Sstevel 
172503831d35Sstevel 	if (bdp == NULL)
172603831d35Sstevel 		return (-1);
172703831d35Sstevel 
172803831d35Sstevel 	/*
172903831d35Sstevel 	 * Search for the first bank with valid memory
173003831d35Sstevel 	 */
173103831d35Sstevel 	for (bankp = bdp->banks; bankp; bankp = bankp->bd_next)
173203831d35Sstevel 		if (bankp->valid)
173303831d35Sstevel 			break;
173403831d35Sstevel 
173503831d35Sstevel 	/*
173603831d35Sstevel 	 * If there are no banks in the board, then the board is
173703831d35Sstevel 	 * not interleaved across boards
173803831d35Sstevel 	 */
173903831d35Sstevel 	if (bankp == NULL) {
174003831d35Sstevel 		return (0);
174103831d35Sstevel 	}
174203831d35Sstevel 
174303831d35Sstevel 	base = bankp->um & ~(bankp->uk);
174403831d35Sstevel 
174503831d35Sstevel 	/*
174603831d35Sstevel 	 * Find the segment for the first bank
174703831d35Sstevel 	 */
174803831d35Sstevel 	if ((seg = sbdp_get_seg(base)) == NULL) {
174903831d35Sstevel 		/*
175003831d35Sstevel 		 * Something bad has happened.
175103831d35Sstevel 		 */
175203831d35Sstevel 		return (-1);
175303831d35Sstevel 	}
175403831d35Sstevel 	/*
175503831d35Sstevel 	 * Make sure that this segment is only composed of the banks
175603831d35Sstevel 	 * in this board. If one is missing or we have an extra one
175703831d35Sstevel 	 * the board is interleaved across boards
175803831d35Sstevel 	 */
175903831d35Sstevel 	is_interleave = sbdp_check_seg_with_banks(seg, bdp->banks);
176003831d35Sstevel 
176103831d35Sstevel 	SBDP_DBG_MEM("interleave is %d\n", is_interleave);
176203831d35Sstevel 
176303831d35Sstevel 	return (is_interleave);
176403831d35Sstevel }
176503831d35Sstevel 
176603831d35Sstevel 
176703831d35Sstevel /*
176803831d35Sstevel  * Each node has 4 logical banks.  This routine adds all the banks (including
176903831d35Sstevel  * the invalid ones to the passed list. Note that we use the bd list and not
177003831d35Sstevel  * the seg list
177103831d35Sstevel  */
177203831d35Sstevel int
sbdp_add_nodes_banks(pnode_t node,sbdp_bank_t ** banks)177303831d35Sstevel sbdp_add_nodes_banks(pnode_t node, sbdp_bank_t **banks)
177403831d35Sstevel {
177503831d35Sstevel 	int		i;
177603831d35Sstevel 	mc_regs_t	regs;
177703831d35Sstevel 	uint64_t	*mc_decode;
177803831d35Sstevel 	sbdp_bank_t 	*bank;
177903831d35Sstevel 
178003831d35Sstevel 	if (mc_read_regs(node, &regs) == -1)
178103831d35Sstevel 		return (-1);
178203831d35Sstevel 
178303831d35Sstevel 	mc_decode = regs.mc_decode;
178403831d35Sstevel 
178503831d35Sstevel 	for (i = 0; i < SBDP_MAX_MCS_PER_NODE; i++) {
178603831d35Sstevel 		/*
178703831d35Sstevel 		 * This creates the mem for the new member of the list
178803831d35Sstevel 		 */
178903831d35Sstevel 		sbdp_fill_bank_info(mc_decode[i], &bank);
179003831d35Sstevel 
179103831d35Sstevel 		SBDP_DBG_MEM("adding bank %d\n", bank->id);
179203831d35Sstevel 
179303831d35Sstevel 		/*
179403831d35Sstevel 		 * Insert bank into the beginning of the list
179503831d35Sstevel 		 */
179603831d35Sstevel 		bank->bd_next = *banks;
179703831d35Sstevel 		*banks = bank;
179803831d35Sstevel 
179903831d35Sstevel 		/*
180003831d35Sstevel 		 * Add this bank into its corresponding
180103831d35Sstevel 		 * segment
180203831d35Sstevel 		 */
180303831d35Sstevel 		sbdp_add_bank_to_seg(bank);
180403831d35Sstevel 	}
180503831d35Sstevel 	return (0);
180603831d35Sstevel }
180703831d35Sstevel 
180803831d35Sstevel /*
180903831d35Sstevel  * given the info, create a new bank node and set the info
181003831d35Sstevel  * as appropriate. We allocate the memory for the bank. It is
181103831d35Sstevel  * up to the caller to ensure the mem is freed
181203831d35Sstevel  */
181303831d35Sstevel void
sbdp_fill_bank_info(uint64_t mc_decode,sbdp_bank_t ** bank)181403831d35Sstevel sbdp_fill_bank_info(uint64_t mc_decode, sbdp_bank_t **bank)
181503831d35Sstevel {
181603831d35Sstevel 	static int	id = 0;
181703831d35Sstevel 	sbdp_bank_t	*new;
181803831d35Sstevel 
181903831d35Sstevel 	new = kmem_zalloc(sizeof (sbdp_bank_t), KM_SLEEP);
182003831d35Sstevel 
182103831d35Sstevel 	new->id = id++;
182203831d35Sstevel 	new->valid = (mc_decode >> MC_VALID_SHIFT);
182303831d35Sstevel 	new->uk = MC_UK(mc_decode);
182403831d35Sstevel 	new->um = MC_UM(mc_decode);
182503831d35Sstevel 	new->lk = MC_LK(mc_decode);
182603831d35Sstevel 	new->lm = MC_LM(mc_decode);
182703831d35Sstevel 	new->bd_next = NULL;
182803831d35Sstevel 	new->seg_next = NULL;
182903831d35Sstevel 
183003831d35Sstevel 	*bank = new;
183103831d35Sstevel }
183203831d35Sstevel 
183303831d35Sstevel /*
183403831d35Sstevel  * Each bd has the potential of having mem banks on it.  The banks
183503831d35Sstevel  * may be empty or not.  This routine gets all the mem banks
183603831d35Sstevel  * for this bd
183703831d35Sstevel  */
183803831d35Sstevel void
sbdp_init_bd_banks(sbdp_bd_t * bdp)183903831d35Sstevel sbdp_init_bd_banks(sbdp_bd_t *bdp)
184003831d35Sstevel {
184103831d35Sstevel 	int		i, nmem;
184203831d35Sstevel 	pnode_t		*lists;
184303831d35Sstevel 
184403831d35Sstevel 	lists = bdp->nodes;
184503831d35Sstevel 	nmem = bdp->nnum;
184603831d35Sstevel 
184703831d35Sstevel 	if (bdp->banks != NULL) {
184803831d35Sstevel 		return;
184903831d35Sstevel 	}
185003831d35Sstevel 
185103831d35Sstevel 	bdp->banks = NULL;
185203831d35Sstevel 
185303831d35Sstevel 	for (i = 0; i < nmem; i++) {
185403831d35Sstevel 		(void) sbdp_add_nodes_banks(lists[i], &bdp->banks);
185503831d35Sstevel 	}
185603831d35Sstevel }
185703831d35Sstevel 
185803831d35Sstevel /*
185903831d35Sstevel  * swap the list of banks for the 2 boards
186003831d35Sstevel  */
186103831d35Sstevel void
sbdp_swap_list_of_banks(sbdp_bd_t * bdp1,sbdp_bd_t * bdp2)186203831d35Sstevel sbdp_swap_list_of_banks(sbdp_bd_t *bdp1, sbdp_bd_t *bdp2)
186303831d35Sstevel {
186403831d35Sstevel 	sbdp_bank_t	*tmp_ptr;
186503831d35Sstevel 
186603831d35Sstevel 	if ((bdp1 == NULL) || (bdp2 == NULL))
186703831d35Sstevel 		return;
186803831d35Sstevel 
186903831d35Sstevel 	tmp_ptr = bdp1->banks;
187003831d35Sstevel 	bdp1->banks = bdp2->banks;
187103831d35Sstevel 	bdp2->banks = tmp_ptr;
187203831d35Sstevel }
187303831d35Sstevel 
187403831d35Sstevel /*
187503831d35Sstevel  * free all the banks on the board.  Note that a bank node belongs
187603831d35Sstevel  * to 2 lists. The first list is the board list. The second one is
187703831d35Sstevel  * the seg list. We only need to remove the bank from both lists but only
187803831d35Sstevel  * free the node once.
187903831d35Sstevel  */
188003831d35Sstevel void
sbdp_fini_bd_banks(sbdp_bd_t * bdp)188103831d35Sstevel sbdp_fini_bd_banks(sbdp_bd_t *bdp)
188203831d35Sstevel {
188303831d35Sstevel 	sbdp_bank_t	*bkp, *nbkp;
188403831d35Sstevel 
188503831d35Sstevel 	for (bkp = bdp->banks; bkp; ) {
188603831d35Sstevel 		/*
188703831d35Sstevel 		 * Remove the bank from the seg list first
188803831d35Sstevel 		 */
188903831d35Sstevel 		SBDP_DBG_MEM("Removing bank %d\n", bkp->id);
189003831d35Sstevel 		sbdp_remove_bank_from_seg(bkp);
189103831d35Sstevel 		nbkp = bkp->bd_next;
189203831d35Sstevel 		bkp->bd_next = NULL;
189303831d35Sstevel 		kmem_free(bkp, sizeof (sbdp_bank_t));
189403831d35Sstevel 
189503831d35Sstevel 		bkp = nbkp;
189603831d35Sstevel 	}
189703831d35Sstevel 	bdp->banks = NULL;
189803831d35Sstevel }
189903831d35Sstevel 
190003831d35Sstevel #ifdef DEBUG
190103831d35Sstevel void
sbdp_print_bd_banks(sbdp_bd_t * bdp)190203831d35Sstevel sbdp_print_bd_banks(sbdp_bd_t *bdp)
190303831d35Sstevel {
190403831d35Sstevel 	sbdp_bank_t	*bp;
190503831d35Sstevel 	int		i;
190603831d35Sstevel 
190703831d35Sstevel 	SBDP_DBG_MEM("BOARD %d\n", bdp->bd);
190803831d35Sstevel 
190903831d35Sstevel 	for (bp = bdp->banks, i = 0; bp; bp = bp->bd_next, i++) {
191003831d35Sstevel 		SBDP_DBG_MEM("BANK [%d]:\n", bp->id);
191103831d35Sstevel 		SBDP_DBG_MEM("\tvalid %d\tuk 0x%x\tum 0x%x\tlk 0x%x"
191203831d35Sstevel 		    "\tlm 0x%x\n", bp->valid, bp->uk, bp->um,
191303831d35Sstevel 		    bp->lk, bp->lm);
191403831d35Sstevel 	}
191503831d35Sstevel }
191603831d35Sstevel 
191703831d35Sstevel void
sbdp_print_all_segs(void)191803831d35Sstevel sbdp_print_all_segs(void)
191903831d35Sstevel {
192003831d35Sstevel 	sbdp_seg_t	*cur_seg;
192103831d35Sstevel 
192203831d35Sstevel 	for (cur_seg = sys_seg; cur_seg; cur_seg = cur_seg->next)
192303831d35Sstevel 		sbdp_print_seg(cur_seg);
192403831d35Sstevel }
192503831d35Sstevel 
192603831d35Sstevel void
sbdp_print_seg(sbdp_seg_t * seg)192703831d35Sstevel sbdp_print_seg(sbdp_seg_t *seg)
192803831d35Sstevel {
192903831d35Sstevel 	sbdp_bank_t	*bp;
193003831d35Sstevel 	int		i;
193103831d35Sstevel 
193203831d35Sstevel 	SBDP_DBG_MEM("SEG %d\n", seg->id);
193303831d35Sstevel 
193403831d35Sstevel 	for (bp = seg->banks, i = 0; bp; bp = bp->seg_next, i++) {
193503831d35Sstevel 		SBDP_DBG_MEM("BANK [%d]:\n", bp->id);
193603831d35Sstevel 		SBDP_DBG_MEM("\tvalid %d\tuk 0x%x\tum 0x%x\tlk 0x%x"
193703831d35Sstevel 		    "\tlm 0x%x\n", bp->valid, bp->uk, bp->um,
193803831d35Sstevel 		    bp->lk, bp->lm);
193903831d35Sstevel 	}
194003831d35Sstevel }
194103831d35Sstevel #endif
194203831d35Sstevel 
194303831d35Sstevel void
sbdp_add_bank_to_seg(sbdp_bank_t * bank)194403831d35Sstevel sbdp_add_bank_to_seg(sbdp_bank_t *bank)
194503831d35Sstevel {
194603831d35Sstevel 	uint64_t	base;
194703831d35Sstevel 	sbdp_seg_t	*cur_seg;
194803831d35Sstevel 	static int	id = 0;
194903831d35Sstevel 
195003831d35Sstevel 	/*
195103831d35Sstevel 	 * if we got an invalid bank just skip it
195203831d35Sstevel 	 */
195303831d35Sstevel 	if (bank == NULL || !bank->valid)
195403831d35Sstevel 		return;
195503831d35Sstevel 	base = bank->um & ~(bank->uk);
195603831d35Sstevel 
195703831d35Sstevel 	if ((cur_seg = sbdp_get_seg(base)) == NULL) {
195803831d35Sstevel 		/*
195903831d35Sstevel 		 * This bank is part of a new segment, so create
196003831d35Sstevel 		 * a struct for it and added to the list of segments
196103831d35Sstevel 		 */
196203831d35Sstevel 		cur_seg = kmem_zalloc(sizeof (sbdp_seg_t), KM_SLEEP);
196303831d35Sstevel 		cur_seg->id = id++;
196403831d35Sstevel 		cur_seg->base = base;
196503831d35Sstevel 		cur_seg->size = ((bank->uk +1) << PHYS2UM_SHIFT);
196603831d35Sstevel 		cur_seg->intlv = ((bank->lk ^ 0xF) + 1);
196703831d35Sstevel 		/*
196803831d35Sstevel 		 * add to the seg list
196903831d35Sstevel 		 */
197003831d35Sstevel 		cur_seg->next = sys_seg;
197103831d35Sstevel 		sys_seg = cur_seg;
197203831d35Sstevel 	}
197303831d35Sstevel 
197403831d35Sstevel 	cur_seg->nbanks++;
197503831d35Sstevel 	/*
197603831d35Sstevel 	 * add bank into segs bank list.  Note we add at the head
197703831d35Sstevel 	 */
197803831d35Sstevel 	bank->seg_next = cur_seg->banks;
197903831d35Sstevel 	cur_seg->banks = bank;
198003831d35Sstevel }
198103831d35Sstevel 
198203831d35Sstevel /*
198303831d35Sstevel  * Remove this segment from the seg list
198403831d35Sstevel  */
198503831d35Sstevel void
sbdp_rm_seg(sbdp_seg_t * seg)198603831d35Sstevel sbdp_rm_seg(sbdp_seg_t *seg)
198703831d35Sstevel {
198803831d35Sstevel 	sbdp_seg_t	**curpp, *curp;
198903831d35Sstevel 
199003831d35Sstevel 	curpp = &sys_seg;
199103831d35Sstevel 
199203831d35Sstevel 	while ((curp = *curpp) != NULL) {
199303831d35Sstevel 		if (curp == seg) {
199403831d35Sstevel 			*curpp = curp->next;
199503831d35Sstevel 			break;
199603831d35Sstevel 		}
199703831d35Sstevel 		curpp = &curp->next;
199803831d35Sstevel 	}
199903831d35Sstevel 
200003831d35Sstevel 	if (curp != NULL) {
200103831d35Sstevel 		kmem_free(curp, sizeof (sbdp_seg_t));
200203831d35Sstevel 		curp = NULL;
200303831d35Sstevel 	}
200403831d35Sstevel }
200503831d35Sstevel 
200603831d35Sstevel /*
200703831d35Sstevel  * remove this bank from its seg list
200803831d35Sstevel  */
200903831d35Sstevel void
sbdp_remove_bank_from_seg(sbdp_bank_t * bank)201003831d35Sstevel sbdp_remove_bank_from_seg(sbdp_bank_t *bank)
201103831d35Sstevel {
201203831d35Sstevel 	uint64_t	base;
201303831d35Sstevel 	sbdp_seg_t	*cur_seg;
201403831d35Sstevel 	sbdp_bank_t	**curpp, *curp;
201503831d35Sstevel 
201603831d35Sstevel 	/*
201703831d35Sstevel 	 * if we got an invalid bank just skip it
201803831d35Sstevel 	 */
201903831d35Sstevel 	if (bank == NULL || !bank->valid)
202003831d35Sstevel 		return;
202103831d35Sstevel 	base = bank->um & ~(bank->uk);
202203831d35Sstevel 
202303831d35Sstevel 	/*
202403831d35Sstevel 	 * If the bank doesn't belong to any seg just return
202503831d35Sstevel 	 */
202603831d35Sstevel 	if ((cur_seg = sbdp_get_seg(base)) == NULL) {
202703831d35Sstevel 		SBDP_DBG_MEM("bank %d with no segment\n", bank->id);
202803831d35Sstevel 		return;
202903831d35Sstevel 	}
203003831d35Sstevel 
203103831d35Sstevel 	/*
203203831d35Sstevel 	 * Find bank in the seg
203303831d35Sstevel 	 */
203403831d35Sstevel 	curpp = &cur_seg->banks;
203503831d35Sstevel 
203603831d35Sstevel 	while ((curp = *curpp) != NULL) {
203703831d35Sstevel 		if (curp->id == bank->id) {
203803831d35Sstevel 			/*
203903831d35Sstevel 			 * found node, remove it
204003831d35Sstevel 			 */
204103831d35Sstevel 			*curpp = curp->seg_next;
204203831d35Sstevel 			break;
204303831d35Sstevel 		}
204403831d35Sstevel 		curpp = &curp->seg_next;
204503831d35Sstevel 	}
204603831d35Sstevel 
204703831d35Sstevel 	if (curp != NULL) {
204803831d35Sstevel 		cur_seg->nbanks--;
204903831d35Sstevel 	}
205003831d35Sstevel 
205103831d35Sstevel 	if (cur_seg->nbanks == 0) {
205203831d35Sstevel 		/*
205303831d35Sstevel 		 * No banks left on this segment, remove the segment
205403831d35Sstevel 		 */
205503831d35Sstevel 		SBDP_DBG_MEM("No banks left in this segment, removing it\n");
205603831d35Sstevel 		sbdp_rm_seg(cur_seg);
205703831d35Sstevel 	}
205803831d35Sstevel }
205903831d35Sstevel 
206003831d35Sstevel sbdp_seg_t *
sbdp_get_seg(uint64_t base)206103831d35Sstevel sbdp_get_seg(uint64_t base)
206203831d35Sstevel {
206303831d35Sstevel 	sbdp_seg_t	*cur_seg;
206403831d35Sstevel 
206503831d35Sstevel 	for (cur_seg = sys_seg; cur_seg; cur_seg = cur_seg->next) {
206603831d35Sstevel 		if (cur_seg-> base == base)
206703831d35Sstevel 			break;
206803831d35Sstevel 	}
206903831d35Sstevel 
207003831d35Sstevel 	return (cur_seg);
207103831d35Sstevel }
207203831d35Sstevel 
207303831d35Sstevel #ifdef DEBUG
207403831d35Sstevel int
sbdp_passthru_readmem(sbdp_handle_t * hp,void * arg)207503831d35Sstevel sbdp_passthru_readmem(sbdp_handle_t *hp, void *arg)
207603831d35Sstevel {
207703831d35Sstevel 	_NOTE(ARGUNUSED(hp))
207803831d35Sstevel 	_NOTE(ARGUNUSED(arg))
207903831d35Sstevel 
208003831d35Sstevel 	struct memlist	*ml;
208103831d35Sstevel 	uint64_t	src_pa;
208203831d35Sstevel 	uint64_t	dst_pa;
208303831d35Sstevel 	uint64_t	dst;
208403831d35Sstevel 
208503831d35Sstevel 
208603831d35Sstevel 	dst_pa = va_to_pa(&dst);
208703831d35Sstevel 
208803831d35Sstevel 	memlist_read_lock();
2089*56f33205SJonathan Adams 	for (ml = phys_install; ml; ml = ml->ml_next) {
209003831d35Sstevel 		uint64_t	nbytes;
209103831d35Sstevel 
2092*56f33205SJonathan Adams 		src_pa = ml->ml_address;
2093*56f33205SJonathan Adams 		nbytes = ml->ml_size;
209403831d35Sstevel 
209503831d35Sstevel 		while (nbytes != 0ull) {
209603831d35Sstevel 
209703831d35Sstevel 			/* copy 32 bytes at src_pa to dst_pa */
209803831d35Sstevel 			bcopy32_il(src_pa, dst_pa);
209903831d35Sstevel 
210003831d35Sstevel 			/* increment by 32 bytes */
210103831d35Sstevel 			src_pa += (4 * sizeof (uint64_t));
210203831d35Sstevel 
210303831d35Sstevel 			/* decrement by 32 bytes */
210403831d35Sstevel 			nbytes -= (4 * sizeof (uint64_t));
210503831d35Sstevel 		}
210603831d35Sstevel 	}
210703831d35Sstevel 	memlist_read_unlock();
210803831d35Sstevel 
210903831d35Sstevel 	return (0);
211003831d35Sstevel }
211103831d35Sstevel 
211203831d35Sstevel static int
isdigit(int ch)211303831d35Sstevel isdigit(int ch)
211403831d35Sstevel {
211503831d35Sstevel 	return (ch >= '0' && ch <= '9');
211603831d35Sstevel }
211703831d35Sstevel 
211803831d35Sstevel #define	isspace(c)	((c) == ' ' || (c) == '\t' || (c) == '\n')
211903831d35Sstevel 
212003831d35Sstevel int
sbdp_strtoi(char * p,char ** pos)212103831d35Sstevel sbdp_strtoi(char *p, char **pos)
212203831d35Sstevel {
212303831d35Sstevel 	int n;
212403831d35Sstevel 	int c, neg = 0;
212503831d35Sstevel 
212603831d35Sstevel 	if (!isdigit(c = *p)) {
212703831d35Sstevel 		while (isspace(c))
212803831d35Sstevel 			c = *++p;
212903831d35Sstevel 		switch (c) {
213003831d35Sstevel 			case '-':
213103831d35Sstevel 				neg++;
213203831d35Sstevel 				/* FALLTHROUGH */
213303831d35Sstevel 			case '+':
213403831d35Sstevel 				c = *++p;
213503831d35Sstevel 		}
213603831d35Sstevel 		if (!isdigit(c)) {
213703831d35Sstevel 			if (pos != NULL)
213803831d35Sstevel 				*pos = p;
213903831d35Sstevel 			return (0);
214003831d35Sstevel 		}
214103831d35Sstevel 	}
214203831d35Sstevel 	for (n = '0' - c; isdigit(c = *++p); ) {
214303831d35Sstevel 		n *= 10; /* two steps to avoid unnecessary overflow */
214403831d35Sstevel 		n += '0' - c; /* accum neg to avoid surprises at MAX */
214503831d35Sstevel 	}
214603831d35Sstevel 	if (pos != NULL)
214703831d35Sstevel 		*pos = p;
214803831d35Sstevel 	return (neg ? n : -n);
214903831d35Sstevel }
215003831d35Sstevel 
215103831d35Sstevel int
sbdp_passthru_prep_script(sbdp_handle_t * hp,void * arg)215203831d35Sstevel sbdp_passthru_prep_script(sbdp_handle_t *hp, void *arg)
215303831d35Sstevel {
215403831d35Sstevel 	int			board, i;
215503831d35Sstevel 	sbdp_bd_t		*t_bdp, *s_bdp;
215603831d35Sstevel 	char			*opts;
215703831d35Sstevel 	int			t_board;
215803831d35Sstevel 	sbdp_rename_script_t	*rsbuffer;
215903831d35Sstevel 	sbdp_cr_handle_t	*cph;
216003831d35Sstevel 	int			scriptlen, size;
216103831d35Sstevel 
216203831d35Sstevel 	opts = (char *)arg;
216303831d35Sstevel 	board = hp->h_board;
216403831d35Sstevel 
216503831d35Sstevel 	opts += strlen("prep-script=");
216603831d35Sstevel 	t_board = sbdp_strtoi(opts, NULL);
216703831d35Sstevel 
216803831d35Sstevel 	cph =  kmem_zalloc(sizeof (sbdp_cr_handle_t), KM_SLEEP);
216903831d35Sstevel 
217003831d35Sstevel 	size = sizeof (sbdp_rename_script_t) * SBDP_RENAME_MAXOP;
217103831d35Sstevel 	rsbuffer = kmem_zalloc(size, KM_SLEEP);
217203831d35Sstevel 
217303831d35Sstevel 	s_bdp = sbdp_get_bd_info(hp->h_wnode, board);
217403831d35Sstevel 	t_bdp = sbdp_get_bd_info(hp->h_wnode, t_board);
217503831d35Sstevel 
217603831d35Sstevel 	cph->s_bdp = s_bdp;
217703831d35Sstevel 	cph->t_bdp = t_bdp;
217803831d35Sstevel 	cph->script = rsbuffer;
217903831d35Sstevel 
218003831d35Sstevel 	affinity_set(CPU_CURRENT);
218103831d35Sstevel 	scriptlen = sbdp_prep_rename_script(cph);
218203831d35Sstevel 
218303831d35Sstevel 	if (scriptlen <= 0) {
218403831d35Sstevel 		cmn_err(CE_WARN,
218503831d35Sstevel 		"sbdp failed to prep for copy-rename");
218603831d35Sstevel 	}
218703831d35Sstevel 	prom_printf("SCRIPT from board %d to board %d ->\n", board, t_board);
218803831d35Sstevel 	for (i = 0;  i < (scriptlen / (sizeof (sbdp_rename_script_t))); i++) {
218903831d35Sstevel 		prom_printf("0x%lx = 0x%lx, asi 0x%x\n",
219003831d35Sstevel 		    rsbuffer[i].masr_addr, rsbuffer[i].masr, rsbuffer[i].asi);
219103831d35Sstevel 	}
219203831d35Sstevel 	prom_printf("\n");
219303831d35Sstevel 
219403831d35Sstevel 	affinity_clear();
219503831d35Sstevel 	kmem_free(rsbuffer, size);
219603831d35Sstevel 	kmem_free(cph, sizeof (sbdp_cr_handle_t));
219703831d35Sstevel 
219803831d35Sstevel 	return (0);
219903831d35Sstevel }
220003831d35Sstevel #endif
2201