xref: /titanic_44/usr/src/uts/sun4u/io/sbd_mem.c (revision 56f33205c9ed776c3c909e07d52e94610a675740)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
585f58038Sdp78419  * Common Development and Distribution License (the "License").
685f58038Sdp78419  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2107d06da5SSurya Prakki 
227c478bd9Sstevel@tonic-gate /*
23*56f33205SJonathan Adams  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * memory support routines for sbd.
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <sys/debug.h>
327c478bd9Sstevel@tonic-gate #include <sys/types.h>
337c478bd9Sstevel@tonic-gate #include <sys/errno.h>
347c478bd9Sstevel@tonic-gate #include <sys/param.h>
357c478bd9Sstevel@tonic-gate #include <sys/dditypes.h>
367c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
377c478bd9Sstevel@tonic-gate #include <sys/conf.h>
387c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
397c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
407c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
417c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
427c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
437c478bd9Sstevel@tonic-gate #include <sys/machsystm.h>
447c478bd9Sstevel@tonic-gate #include <sys/spitregs.h>
457c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
467c478bd9Sstevel@tonic-gate #include <sys/cpu_module.h>
477c478bd9Sstevel@tonic-gate #include <sys/promif.h>
487c478bd9Sstevel@tonic-gate #include <sys/memlist_impl.h>
497c478bd9Sstevel@tonic-gate #include <sys/mem_cage.h>
507c478bd9Sstevel@tonic-gate #include <sys/lgrp.h>
517c478bd9Sstevel@tonic-gate #include <sys/platform_module.h>
527c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h>
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate #include <sys/sbdpriv.h>
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate #define	_ptob64(p) ((uint64_t)(p) << PAGESHIFT)
577c478bd9Sstevel@tonic-gate #define	_b64top(b) ((pgcnt_t)((b) >> PAGESHIFT))
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate static int		sbd_post_detach_mem_unit(sbd_mem_unit_t *mp,
607c478bd9Sstevel@tonic-gate 				sbderror_t *ep);
617c478bd9Sstevel@tonic-gate static int		sbd_reserve_mem_spans(memhandle_t *mhp,
627c478bd9Sstevel@tonic-gate 					struct memlist *mlist);
637c478bd9Sstevel@tonic-gate static int		sbd_check_boundaries(struct memlist *orig_memlist,
647c478bd9Sstevel@tonic-gate 					sbd_mem_unit_t *s_mp,
657c478bd9Sstevel@tonic-gate 					sbd_mem_unit_t *t_mp);
667c478bd9Sstevel@tonic-gate static int		sbd_select_mem_target(sbd_handle_t *hp,
677c478bd9Sstevel@tonic-gate 				sbd_mem_unit_t *mp, struct memlist *ml);
687c478bd9Sstevel@tonic-gate static void		sbd_init_mem_unit_data(sbd_mem_unit_t *mp, sbderror_t
697c478bd9Sstevel@tonic-gate 					*ep);
707c478bd9Sstevel@tonic-gate static int		memlist_canfit(struct memlist *s_mlist,
717c478bd9Sstevel@tonic-gate 					struct memlist *t_mlist);
727c478bd9Sstevel@tonic-gate static void		sbd_mem_cleanup(sbd_mem_unit_t *s_mp,
737c478bd9Sstevel@tonic-gate 				sbd_mem_unit_t *t_mp, sbderror_t *ep);
747c478bd9Sstevel@tonic-gate static void		sbd_flush_ecache(uint64_t a, uint64_t b);
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate struct memlist *
sbd_get_memlist(sbd_mem_unit_t * mp,sbderror_t * ep)777c478bd9Sstevel@tonic-gate sbd_get_memlist(sbd_mem_unit_t *mp, sbderror_t *ep)
787c478bd9Sstevel@tonic-gate {
797c478bd9Sstevel@tonic-gate 	struct memlist	*mlist;
807c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_get_memlist";
817c478bd9Sstevel@tonic-gate 	sbd_board_t 	*sbp = (sbd_board_t *)mp->sbm_cm.sbdev_sbp;
827c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
837c478bd9Sstevel@tonic-gate 	sbd_handle_t	*hp = MACHBD2HD(sbp);
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 	PR_MEM("%s...\n", f);
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 	/*
887c478bd9Sstevel@tonic-gate 	 * Return cached memlist, if present.
897c478bd9Sstevel@tonic-gate 	 * This memlist will be present following an
907c478bd9Sstevel@tonic-gate 	 * unconfigure (a.k.a: detach) of this memunit.
917c478bd9Sstevel@tonic-gate 	 * It should only be used in the case were a configure
927c478bd9Sstevel@tonic-gate 	 * is bringing this memunit back in without going
937c478bd9Sstevel@tonic-gate 	 * through the disconnect and connect states.
947c478bd9Sstevel@tonic-gate 	 */
957c478bd9Sstevel@tonic-gate 	if (mp->sbm_mlist) {
967c478bd9Sstevel@tonic-gate 		PR_MEM("%s: found cached memlist\n", f);
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 		mlist = memlist_dup(mp->sbm_mlist);
997c478bd9Sstevel@tonic-gate 	} else {
1007c478bd9Sstevel@tonic-gate 		/* attempt to construct a memlist using phys_install */
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 		/*
1037c478bd9Sstevel@tonic-gate 		 * NOTE: this code block assumes only one memunit per
1047c478bd9Sstevel@tonic-gate 		 * board.  This is currently safe because the function
1057c478bd9Sstevel@tonic-gate 		 * sbd_init_mem_devlist() forces this assumption to be
1067c478bd9Sstevel@tonic-gate 		 * valid.
1077c478bd9Sstevel@tonic-gate 		 */
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate 		/* round down to slice base address */
1107c478bd9Sstevel@tonic-gate 		/* build mlist from the lower layer */
1117c478bd9Sstevel@tonic-gate 		hdp = sbd_get_sbdp_handle(sbp, hp);
1127c478bd9Sstevel@tonic-gate 		mlist = sbdp_get_memlist(hdp, mp->sbm_cm.sbdev_dip);
1137c478bd9Sstevel@tonic-gate 		if (mlist == NULL) {
1147c478bd9Sstevel@tonic-gate 			SBD_GET_PERR(hdp->h_err, ep);
1157c478bd9Sstevel@tonic-gate 			PR_MEM("sbd:%s: failed to get memlist for "
1167c478bd9Sstevel@tonic-gate 				"dip (0x%p) ecode %d errno %d", f,
1177c478bd9Sstevel@tonic-gate 				(void *)mp->sbm_cm.sbdev_dip,
1187c478bd9Sstevel@tonic-gate 				ep->e_code, ep->e_errno);
1197c478bd9Sstevel@tonic-gate 			sbd_release_sbdp_handle(hdp);
1207c478bd9Sstevel@tonic-gate 			return (NULL);
1217c478bd9Sstevel@tonic-gate 		}
1227c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
1237c478bd9Sstevel@tonic-gate 	}
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 	PR_MEM("%s: memlist for mem-unit (%d.%d), dip 0x%p:\n",
1267c478bd9Sstevel@tonic-gate 		f, sbp->sb_num,
1277c478bd9Sstevel@tonic-gate 		mp->sbm_cm.sbdev_unum,
1287c478bd9Sstevel@tonic-gate 		(void *)mp->sbm_cm.sbdev_dip);
1297c478bd9Sstevel@tonic-gate 	SBD_MEMLIST_DUMP(mlist);
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 	return (mlist);
1327c478bd9Sstevel@tonic-gate }
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate int
sbd_pre_attach_mem(sbd_handle_t * hp,sbd_devlist_t devlist[],int devnum)1357c478bd9Sstevel@tonic-gate sbd_pre_attach_mem(sbd_handle_t *hp, sbd_devlist_t devlist[], int devnum)
1367c478bd9Sstevel@tonic-gate {
1377c478bd9Sstevel@tonic-gate 	int		err_flag = 0;
1387c478bd9Sstevel@tonic-gate 	sbderror_t	*ep = SBD_HD2ERR(hp);
1397c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
1407c478bd9Sstevel@tonic-gate 	int		d, i;
1417c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
1427c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_pre_attach_mem";
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 	PR_MEM("%s...\n", f);
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	SBD_SET_ERR(ep, 0);
1477c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 	for (d = 0; d < devnum; d++) {
1507c478bd9Sstevel@tonic-gate 		sbd_mem_unit_t	*mp;
1517c478bd9Sstevel@tonic-gate 		int		unit;
1527c478bd9Sstevel@tonic-gate 		dev_info_t	*dip;
1537c478bd9Sstevel@tonic-gate 		sbd_istate_t	state;
1547c478bd9Sstevel@tonic-gate 		int		rv;
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 		/* sbd_get_devlist will not devlist element w/ dip of 0 */
1577c478bd9Sstevel@tonic-gate 		ASSERT(devlist[d].dv_dip != NULL);
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 		dip = devlist[d].dv_dip;
1607c478bd9Sstevel@tonic-gate 		unit = sbdp_get_unit_num(hdp, dip);
1617c478bd9Sstevel@tonic-gate 		if (unit == -1) {
1627c478bd9Sstevel@tonic-gate 			if (hp->h_flags & SBD_IOCTL_FLAG_FORCE)
1637c478bd9Sstevel@tonic-gate 				continue;
1647c478bd9Sstevel@tonic-gate 			else {
1657c478bd9Sstevel@tonic-gate 				SBD_GET_PERR(hdp->h_err, ep);
1667c478bd9Sstevel@tonic-gate 				err_flag = 1;
1677c478bd9Sstevel@tonic-gate 				break;
1687c478bd9Sstevel@tonic-gate 			}
1697c478bd9Sstevel@tonic-gate 		}
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 		mp = SBD_GET_BOARD_MEMUNIT(sbp, unit);
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 		ASSERT(mp->sbm_cm.sbdev_sbp == sbp);
1747c478bd9Sstevel@tonic-gate 		ASSERT(unit == mp->sbm_cm.sbdev_unum);
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 		PR_MEM("sbd: OS attach mem-unit (%d.%d)\n",
1777c478bd9Sstevel@tonic-gate 			sbp->sb_num,
1787c478bd9Sstevel@tonic-gate 			mp->sbm_cm.sbdev_unum);
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 		state = mp->sbm_cm.sbdev_state;
1817c478bd9Sstevel@tonic-gate 		switch (state) {
1827c478bd9Sstevel@tonic-gate 		case SBD_STATE_UNCONFIGURED:
1837c478bd9Sstevel@tonic-gate 			/* use memlist cached by sbd_post_detach_mem_unit */
1847c478bd9Sstevel@tonic-gate 			if (mp->sbm_mlist != NULL) {
1857c478bd9Sstevel@tonic-gate 				PR_MEM("%s: recovering from UNCONFIG"
1867c478bd9Sstevel@tonic-gate 					" mem-unit (%d.%d)\n",
1877c478bd9Sstevel@tonic-gate 					f, sbp->sb_num,
1887c478bd9Sstevel@tonic-gate 					mp->sbm_cm.sbdev_unum);
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 				PR_MEM("%s: re-configure cached memlist:\n", f);
1917c478bd9Sstevel@tonic-gate 				SBD_MEMLIST_DUMP(mp->sbm_mlist);
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 				/*
1947c478bd9Sstevel@tonic-gate 				 * kphysm del handle should have been freed
1957c478bd9Sstevel@tonic-gate 				 */
1967c478bd9Sstevel@tonic-gate 				ASSERT((mp->sbm_flags & SBD_MFLAG_RELOWNER)
1977c478bd9Sstevel@tonic-gate 					== 0);
1987c478bd9Sstevel@tonic-gate 			} else {
1997c478bd9Sstevel@tonic-gate 				if (hp->h_flags & SBD_IOCTL_FLAG_FORCE)
2007c478bd9Sstevel@tonic-gate 					continue;
2017c478bd9Sstevel@tonic-gate 				else {
2027c478bd9Sstevel@tonic-gate 					SBD_GET_PERR(hdp->h_err, ep);
2037c478bd9Sstevel@tonic-gate 					err_flag = 1;
2047c478bd9Sstevel@tonic-gate 					PR_MEM("%s: mem-unit (%d.%d)"
2057c478bd9Sstevel@tonic-gate 						" unusable\n",
2067c478bd9Sstevel@tonic-gate 						f, sbp->sb_num,
2077c478bd9Sstevel@tonic-gate 						mp->sbm_cm.sbdev_unum);
2087c478bd9Sstevel@tonic-gate 					break;
2097c478bd9Sstevel@tonic-gate 				}
2107c478bd9Sstevel@tonic-gate 			}
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 			/*FALLTHROUGH*/
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 		case SBD_STATE_CONNECTED:
2157c478bd9Sstevel@tonic-gate 			PR_MEM("%s: reprogramming mem hardware (board %d)\n",
2167c478bd9Sstevel@tonic-gate 				f, sbp->sb_num);
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 			for (i = 0; i < SBD_NUM_MC_PER_BOARD; i++) {
2197c478bd9Sstevel@tonic-gate 				if (mp->sbm_dip[i] == NULL)
2207c478bd9Sstevel@tonic-gate 					continue;
2217c478bd9Sstevel@tonic-gate 				dip = mp->sbm_dip[i];
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 				PR_MEM("%s: enabling mc 0x%p on board %d\n",
2247c478bd9Sstevel@tonic-gate 					f, (void *)dip, sbp->sb_num);
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 				rv = sbdphw_enable_memctrl(hdp, dip);
2277c478bd9Sstevel@tonic-gate 				if (rv < 0) {
2287c478bd9Sstevel@tonic-gate 					SBD_GET_PERR(hdp->h_err, ep);
2297c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN,
2307c478bd9Sstevel@tonic-gate 					"%s: failed to program mem ctrlr %p on "
2317c478bd9Sstevel@tonic-gate 					"board %d", f, (void *)mp->sbm_dip[i],
2327c478bd9Sstevel@tonic-gate 					sbp->sb_num);
2337c478bd9Sstevel@tonic-gate 					err_flag = 1;
2347c478bd9Sstevel@tonic-gate 				}
2357c478bd9Sstevel@tonic-gate 			}
2367c478bd9Sstevel@tonic-gate 			break;
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 		default:
2397c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2407c478bd9Sstevel@tonic-gate 				"%s: unexpected state (%d) for mem-unit "
2417c478bd9Sstevel@tonic-gate 				"(%d.%d)", f, state, sbp->sb_num,
2427c478bd9Sstevel@tonic-gate 				mp->sbm_cm.sbdev_unum);
2437c478bd9Sstevel@tonic-gate 			if (SBD_GET_ERR(ep) == 0) {
2447c478bd9Sstevel@tonic-gate 				SBD_SET_ERR(ep, ESBD_STATE);
2457c478bd9Sstevel@tonic-gate 				err_flag = 1;
2467c478bd9Sstevel@tonic-gate 			}
2477c478bd9Sstevel@tonic-gate 			break;
2487c478bd9Sstevel@tonic-gate 		}
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 		/* exit for loop if error encountered */
2517c478bd9Sstevel@tonic-gate 		if (err_flag) {
2527c478bd9Sstevel@tonic-gate 			SBD_SET_ERRSTR(ep,
2537c478bd9Sstevel@tonic-gate 			    sbp->sb_mempath[mp->sbm_cm.sbdev_unum]);
2547c478bd9Sstevel@tonic-gate 			break;
2557c478bd9Sstevel@tonic-gate 		}
2567c478bd9Sstevel@tonic-gate 	}
2577c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 	return (err_flag ? -1 : 0);
2607c478bd9Sstevel@tonic-gate }
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate int
sbd_post_attach_mem(sbd_handle_t * hp,sbd_devlist_t devlist[],int devnum)2637c478bd9Sstevel@tonic-gate sbd_post_attach_mem(sbd_handle_t *hp, sbd_devlist_t devlist[], int devnum)
2647c478bd9Sstevel@tonic-gate {
2657c478bd9Sstevel@tonic-gate 	int		d;
2667c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
2677c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
2687c478bd9Sstevel@tonic-gate 	sbderror_t	*ep = SBD_HD2ERR(hp);
2697c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_post_attach_mem";
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	PR_MEM("%s...\n", f);
2727c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	for (d = 0; d < devnum; d++) {
2757c478bd9Sstevel@tonic-gate 		sbd_mem_unit_t	*mp;
2767c478bd9Sstevel@tonic-gate 		dev_info_t	*dip;
2777c478bd9Sstevel@tonic-gate 		int		unit;
2787c478bd9Sstevel@tonic-gate 		struct memlist	*mlist, *ml;
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 		/* sbd_get_devlist will not devlist element w/ dip of 0 */
2817c478bd9Sstevel@tonic-gate 		ASSERT(devlist[d].dv_dip != NULL);
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 		dip = devlist[d].dv_dip;
2847c478bd9Sstevel@tonic-gate 		unit = sbdp_get_unit_num(hdp, dip);
2857c478bd9Sstevel@tonic-gate 		if (unit == -1) {
2867c478bd9Sstevel@tonic-gate 			if (hp->h_flags & SBD_IOCTL_FLAG_FORCE)
2877c478bd9Sstevel@tonic-gate 				continue;
2887c478bd9Sstevel@tonic-gate 			else {
2897c478bd9Sstevel@tonic-gate 				SBD_GET_PERR(hdp->h_err, ep);
2907c478bd9Sstevel@tonic-gate 				break;
2917c478bd9Sstevel@tonic-gate 			}
2927c478bd9Sstevel@tonic-gate 		}
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 		mp = SBD_GET_BOARD_MEMUNIT(sbp, unit);
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 		mlist = sbd_get_memlist(mp, ep);
2977c478bd9Sstevel@tonic-gate 		if (mlist == NULL) {
2987c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2997c478bd9Sstevel@tonic-gate 				"%s: no memlist for mem-unit (%d.%d)",
3007c478bd9Sstevel@tonic-gate 				f,
3017c478bd9Sstevel@tonic-gate 				sbp->sb_num,
3027c478bd9Sstevel@tonic-gate 				mp->sbm_cm.sbdev_unum);
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 			if (SBD_GET_ERR(ep) == 0) {
3057c478bd9Sstevel@tonic-gate 				SBD_SET_ERR(ep, ESBD_MEMFAIL);
3067c478bd9Sstevel@tonic-gate 				SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]);
3077c478bd9Sstevel@tonic-gate 			}
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 			continue;
3107c478bd9Sstevel@tonic-gate 		}
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 		/*
3137c478bd9Sstevel@tonic-gate 		 * Verify the memory really did successfully attach
3147c478bd9Sstevel@tonic-gate 		 * by checking for its existence in phys_install.
3157c478bd9Sstevel@tonic-gate 		 */
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 		memlist_read_lock();
3187c478bd9Sstevel@tonic-gate 		if (memlist_intersect(phys_install, mlist) == 0) {
3197c478bd9Sstevel@tonic-gate 			memlist_read_unlock();
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
3227c478bd9Sstevel@tonic-gate 				"%s: mem-unit (%d.%d) memlist not in"
3237c478bd9Sstevel@tonic-gate 				" phys_install", f, sbp->sb_num,
3247c478bd9Sstevel@tonic-gate 				mp->sbm_cm.sbdev_unum);
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 			if (SBD_GET_ERR(ep) == 0) {
3277c478bd9Sstevel@tonic-gate 				SBD_SET_ERR(ep, ESBD_INTERNAL);
3287c478bd9Sstevel@tonic-gate 				SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]);
3297c478bd9Sstevel@tonic-gate 			}
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 			memlist_delete(mlist);
3327c478bd9Sstevel@tonic-gate 			continue;
3337c478bd9Sstevel@tonic-gate 		}
3347c478bd9Sstevel@tonic-gate 		memlist_read_unlock();
3357c478bd9Sstevel@tonic-gate 
336*56f33205SJonathan Adams 		for (ml = mlist; ml != NULL; ml = ml->ml_next) {
337*56f33205SJonathan Adams 			(void) sbdp_mem_add_span(hdp, ml->ml_address,
338*56f33205SJonathan Adams 			    ml->ml_size);
3397c478bd9Sstevel@tonic-gate 		}
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 		memlist_delete(mlist);
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 		/*
3447c478bd9Sstevel@tonic-gate 		 * Destroy cached memlist, if any.
3457c478bd9Sstevel@tonic-gate 		 * There will be a cached memlist in sbm_mlist if
3467c478bd9Sstevel@tonic-gate 		 * this board is being configured directly after
3477c478bd9Sstevel@tonic-gate 		 * an unconfigure.
3487c478bd9Sstevel@tonic-gate 		 * To support this transition, sbd_post_detach_mem
3497c478bd9Sstevel@tonic-gate 		 * left a copy of the last known memlist in sbm_mlist.
3507c478bd9Sstevel@tonic-gate 		 * This memlist could differ from any derived from
3517c478bd9Sstevel@tonic-gate 		 * hardware if while this memunit was last configured
3527c478bd9Sstevel@tonic-gate 		 * the system detected and deleted bad pages from
3537c478bd9Sstevel@tonic-gate 		 * phys_install.  The location of those bad pages
3547c478bd9Sstevel@tonic-gate 		 * will be reflected in the cached memlist.
3557c478bd9Sstevel@tonic-gate 		 */
3567c478bd9Sstevel@tonic-gate 		if (mp->sbm_mlist) {
3577c478bd9Sstevel@tonic-gate 			memlist_delete(mp->sbm_mlist);
3587c478bd9Sstevel@tonic-gate 			mp->sbm_mlist = NULL;
3597c478bd9Sstevel@tonic-gate 		}
3607c478bd9Sstevel@tonic-gate 		sbd_init_mem_unit_data(mp, ep);
3617c478bd9Sstevel@tonic-gate 	}
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
3647c478bd9Sstevel@tonic-gate 	return (0);
3657c478bd9Sstevel@tonic-gate }
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate int
sbd_pre_detach_mem(sbd_handle_t * hp,sbd_devlist_t devlist[],int devnum)3687c478bd9Sstevel@tonic-gate sbd_pre_detach_mem(sbd_handle_t *hp, sbd_devlist_t devlist[], int devnum)
3697c478bd9Sstevel@tonic-gate {
3707c478bd9Sstevel@tonic-gate 	int		d;
3717c478bd9Sstevel@tonic-gate 	int		unit;
3727c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
3737c478bd9Sstevel@tonic-gate 	sbderror_t	*ep = SBD_HD2ERR(hp);
3747c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
3757c478bd9Sstevel@tonic-gate 	dev_info_t	*dip;
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	for (d = 0; d < devnum; d++) {
3807c478bd9Sstevel@tonic-gate 		sbd_mem_unit_t *mp;
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 		/* sbd_get_devlist will not devlist element w/ dip of 0 */
3837c478bd9Sstevel@tonic-gate 		ASSERT(devlist[d].dv_dip != NULL);
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 		dip = devlist[d].dv_dip;
3867c478bd9Sstevel@tonic-gate 		unit = sbdp_get_unit_num(hdp, dip);
3877c478bd9Sstevel@tonic-gate 		if (unit == -1) {
3887c478bd9Sstevel@tonic-gate 			if (hp->h_flags & SBD_IOCTL_FLAG_FORCE)
3897c478bd9Sstevel@tonic-gate 				continue;
3907c478bd9Sstevel@tonic-gate 			else {
3917c478bd9Sstevel@tonic-gate 				SBD_GET_PERR(hdp->h_err, ep);
3927c478bd9Sstevel@tonic-gate 				sbd_release_sbdp_handle(hdp);
3937c478bd9Sstevel@tonic-gate 				return (-1);
3947c478bd9Sstevel@tonic-gate 			}
3957c478bd9Sstevel@tonic-gate 		}
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 		mp = SBD_GET_BOARD_MEMUNIT(sbp, unit);
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 		/* sanity check */
4007c478bd9Sstevel@tonic-gate 		ASSERT(mp->sbm_cm.sbdev_sbp == sbp);
4017c478bd9Sstevel@tonic-gate 		ASSERT(unit == mp->sbm_cm.sbdev_unum);
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 		PR_MEM("sbd: OS detach mem-unit (%d.%d)\n",
4047c478bd9Sstevel@tonic-gate 			sbp->sb_num, mp->sbm_cm.sbdev_unum);
4057c478bd9Sstevel@tonic-gate 	}
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
4087c478bd9Sstevel@tonic-gate 	return (0);
4097c478bd9Sstevel@tonic-gate }
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate int
sbd_post_detach_mem(sbd_handle_t * hp,sbd_devlist_t devlist[],int devnum)4127c478bd9Sstevel@tonic-gate sbd_post_detach_mem(sbd_handle_t *hp, sbd_devlist_t devlist[], int devnum)
4137c478bd9Sstevel@tonic-gate {
4147c478bd9Sstevel@tonic-gate 	int		d, rv;
4157c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
4167c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
4177c478bd9Sstevel@tonic-gate 	sbd_mem_unit_t	*s_mp, *t_mp;
4187c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_post_detach_mem";
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	PR_MEM("%s...\n", f);
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	rv = 0;
4287c478bd9Sstevel@tonic-gate 	for (d = 0; d < devnum; d++) {
4297c478bd9Sstevel@tonic-gate 		sbderror_t	*ep;
4307c478bd9Sstevel@tonic-gate 		dev_info_t	*dip;
4317c478bd9Sstevel@tonic-gate 		int		unit;
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 		/* sbd_get_devlist will not devlist element w/ dip of 0 */
4347c478bd9Sstevel@tonic-gate 		ASSERT(devlist[d].dv_dip != NULL);
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 		ep = &devlist[d].dv_error;
4377c478bd9Sstevel@tonic-gate 		if ((SBD_GET_ERR(SBD_HD2ERR(hp)) != 0) ||
4387c478bd9Sstevel@tonic-gate 		    (sbd_set_err_in_hdl(hp, ep) == 0)) {
4397c478bd9Sstevel@tonic-gate 			rv = -1;
4407c478bd9Sstevel@tonic-gate 		}
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 		dip = devlist[d].dv_dip;
4437c478bd9Sstevel@tonic-gate 		unit = sbdp_get_unit_num(hdp, dip);
4447c478bd9Sstevel@tonic-gate 		if (unit == -1) {
4457c478bd9Sstevel@tonic-gate 			if (hp->h_flags & SBD_IOCTL_FLAG_FORCE)
4467c478bd9Sstevel@tonic-gate 				continue;
4477c478bd9Sstevel@tonic-gate 			else {
4487c478bd9Sstevel@tonic-gate 				if (rv != -1)
4497c478bd9Sstevel@tonic-gate 					SBD_GET_PERR(hdp->h_err, ep);
4507c478bd9Sstevel@tonic-gate 				break;
4517c478bd9Sstevel@tonic-gate 			}
4527c478bd9Sstevel@tonic-gate 		}
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 		s_mp = SBD_GET_BOARD_MEMUNIT(sbp, unit);
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 		ASSERT(s_mp->sbm_cm.sbdev_sbp == sbp);
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 		if (rv == -1) {
4597c478bd9Sstevel@tonic-gate 			if (s_mp->sbm_flags & SBD_MFLAG_SOURCE) {
4607c478bd9Sstevel@tonic-gate 				t_mp = s_mp->sbm_peer;
4617c478bd9Sstevel@tonic-gate 			} else {
4627c478bd9Sstevel@tonic-gate 				/* this is no target unit */
4637c478bd9Sstevel@tonic-gate 				t_mp = NULL;
4647c478bd9Sstevel@tonic-gate 			}
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 			sbd_mem_cleanup(s_mp, t_mp, ep);
4677c478bd9Sstevel@tonic-gate 		} else if (sbd_post_detach_mem_unit(s_mp, ep))
4687c478bd9Sstevel@tonic-gate 			rv = -1;
4697c478bd9Sstevel@tonic-gate 	}
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
4727c478bd9Sstevel@tonic-gate 	return (rv);
4737c478bd9Sstevel@tonic-gate }
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate static void
sbd_add_memory_spans(sbd_board_t * sbp,struct memlist * ml)4767c478bd9Sstevel@tonic-gate sbd_add_memory_spans(sbd_board_t *sbp, struct memlist *ml)
4777c478bd9Sstevel@tonic-gate {
4787c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
4797c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_add_memory_spans";
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	PR_MEM("%s...", f);
4827c478bd9Sstevel@tonic-gate 	SBD_MEMLIST_DUMP(ml);
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate #ifdef DEBUG
4857c478bd9Sstevel@tonic-gate 	memlist_read_lock();
4867c478bd9Sstevel@tonic-gate 	if (memlist_intersect(phys_install, ml)) {
4877c478bd9Sstevel@tonic-gate 		PR_MEM("%s:WARNING: memlist intersects with phys_install\n", f);
4887c478bd9Sstevel@tonic-gate 	}
4897c478bd9Sstevel@tonic-gate 	memlist_read_unlock();
4907c478bd9Sstevel@tonic-gate #endif
4917c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(NULL, NULL);
4927c478bd9Sstevel@tonic-gate 
493*56f33205SJonathan Adams 	for (; ml; ml = ml->ml_next) {
4947c478bd9Sstevel@tonic-gate 		update_membounds_t umb;
4957c478bd9Sstevel@tonic-gate 		pfn_t	base;
4967c478bd9Sstevel@tonic-gate 		pgcnt_t	npgs;
4977c478bd9Sstevel@tonic-gate 		int	rv;
4987c478bd9Sstevel@tonic-gate 
499*56f33205SJonathan Adams 		base = _b64top(ml->ml_address);
500*56f33205SJonathan Adams 		npgs = _b64top(ml->ml_size);
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 		umb.u_board = sbp->sb_num;
5037c478bd9Sstevel@tonic-gate 		umb.u_base = (uint64_t)base << MMU_PAGESHIFT;
5047c478bd9Sstevel@tonic-gate 		umb.u_len = (uint64_t)npgs << MMU_PAGESHIFT;
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 		lgrp_plat_config(LGRP_CONFIG_MEM_ADD, (uintptr_t)&umb);
5077c478bd9Sstevel@tonic-gate 		rv = kphysm_add_memory_dynamic(base, npgs);
5087c478bd9Sstevel@tonic-gate 
509*56f33205SJonathan Adams 		(void) sbdp_mem_add_span(hdp, ml->ml_address, ml->ml_size);
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 		if (rv != KPHYSM_OK) {
5127c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "sbd:%s:"
5137c478bd9Sstevel@tonic-gate 				" unexpected kphysm_add_memory_dynamic"
5147c478bd9Sstevel@tonic-gate 				" return value %d;"
5157c478bd9Sstevel@tonic-gate 				" basepfn=0x%lx, npages=%ld\n",
5167c478bd9Sstevel@tonic-gate 				f, rv, base, npgs);
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 			continue;
5197c478bd9Sstevel@tonic-gate 		}
52085f58038Sdp78419 		rv = kcage_range_add(base, npgs, KCAGE_DOWN);
5217c478bd9Sstevel@tonic-gate 		if (rv != 0)
5227c478bd9Sstevel@tonic-gate 			continue;
5237c478bd9Sstevel@tonic-gate 	}
5247c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
5257c478bd9Sstevel@tonic-gate }
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate /* hack for test scripts.  *** remove before code finalized *** */
5287c478bd9Sstevel@tonic-gate int sbd_last_target;
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate static int
sbd_post_detach_mem_unit(sbd_mem_unit_t * s_mp,sbderror_t * ep)5317c478bd9Sstevel@tonic-gate sbd_post_detach_mem_unit(sbd_mem_unit_t *s_mp, sbderror_t *ep)
5327c478bd9Sstevel@tonic-gate {
5337c478bd9Sstevel@tonic-gate 	uint64_t	sz;
5347c478bd9Sstevel@tonic-gate 	uint64_t	sm;
5357c478bd9Sstevel@tonic-gate 	uint64_t	t_basepa;
5367c478bd9Sstevel@tonic-gate 	uint64_t	tmp_basepa;
5377c478bd9Sstevel@tonic-gate 	uint64_t	s_basepa;
5387c478bd9Sstevel@tonic-gate 	sbd_board_t 	*sbp;
5397c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
5407c478bd9Sstevel@tonic-gate 	uint64_t	s_nbytes;
5417c478bd9Sstevel@tonic-gate 	uint64_t	s_new_basepa;
5427c478bd9Sstevel@tonic-gate 	sbd_mem_unit_t	*t_mp, *x_mp;
5437c478bd9Sstevel@tonic-gate 	struct memlist	*ml;
5447c478bd9Sstevel@tonic-gate 	int		rv;
5457c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_post_detach_mem_unit";
5467c478bd9Sstevel@tonic-gate 	sbd_handle_t	*hp;
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	PR_MEM("%s...\n", f);
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 	sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp;
5517c478bd9Sstevel@tonic-gate 	hp = MACHBD2HD(sbp);
5527c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 	if (sbdp_get_mem_alignment(hdp, s_mp->sbm_cm.sbdev_dip, &sz)) {
5557c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
5567c478bd9Sstevel@tonic-gate 			"sbd:%s: no alignment for mem-unit (%d.%d)",
5577c478bd9Sstevel@tonic-gate 			f, sbp->sb_num, s_mp->sbm_cm.sbdev_unum);
5587c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, ep);
5597c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
5607c478bd9Sstevel@tonic-gate 		return (-1);
5617c478bd9Sstevel@tonic-gate 	}
5627c478bd9Sstevel@tonic-gate 	sm = sz - 1;
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 	/* s_mp->sbm_del_mlist could be NULL, meaning no deleted spans */
5657c478bd9Sstevel@tonic-gate 	PR_MEM("%s: brd %d: deleted memlist (EMPTY maybe okay):\n",
5667c478bd9Sstevel@tonic-gate 		f, sbp->sb_num);
5677c478bd9Sstevel@tonic-gate 	SBD_MEMLIST_DUMP(s_mp->sbm_del_mlist);
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 	/* sanity check */
5707c478bd9Sstevel@tonic-gate 	ASSERT(s_mp->sbm_del_mlist == NULL ||
5717c478bd9Sstevel@tonic-gate 		(s_mp->sbm_flags & SBD_MFLAG_RELDONE) != 0);
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	if (s_mp->sbm_flags & SBD_MFLAG_SOURCE) {
5747c478bd9Sstevel@tonic-gate 		t_mp = s_mp->sbm_peer;
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 		ASSERT(t_mp != NULL);
5777c478bd9Sstevel@tonic-gate 		ASSERT(t_mp->sbm_flags & SBD_MFLAG_TARGET);
5787c478bd9Sstevel@tonic-gate 		ASSERT(t_mp->sbm_peer == s_mp);
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 		ASSERT(t_mp->sbm_flags & SBD_MFLAG_RELDONE);
5817c478bd9Sstevel@tonic-gate 		ASSERT(t_mp->sbm_del_mlist);
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 		sbp = (sbd_board_t *)t_mp->sbm_cm.sbdev_sbp;
5847c478bd9Sstevel@tonic-gate 		PR_MEM("%s: target brd %d: deleted memlist:\n",
5857c478bd9Sstevel@tonic-gate 			f, sbp->sb_num);
5867c478bd9Sstevel@tonic-gate 		SBD_MEMLIST_DUMP(t_mp->sbm_del_mlist);
5877c478bd9Sstevel@tonic-gate 	} else {
5887c478bd9Sstevel@tonic-gate 		/* this is no target unit */
5897c478bd9Sstevel@tonic-gate 		t_mp = NULL;
5907c478bd9Sstevel@tonic-gate 	}
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 	/*
5937c478bd9Sstevel@tonic-gate 	 * Verify the memory really did successfully detach
5947c478bd9Sstevel@tonic-gate 	 * by checking for its non-existence in phys_install.
5957c478bd9Sstevel@tonic-gate 	 */
5967c478bd9Sstevel@tonic-gate 	rv = 0;
5977c478bd9Sstevel@tonic-gate 	memlist_read_lock();
5987c478bd9Sstevel@tonic-gate 	if (s_mp->sbm_flags & SBD_MFLAG_RELDONE) {
5997c478bd9Sstevel@tonic-gate 		x_mp = s_mp;
6007c478bd9Sstevel@tonic-gate 		rv = memlist_intersect(phys_install, x_mp->sbm_del_mlist);
6017c478bd9Sstevel@tonic-gate 	}
6027c478bd9Sstevel@tonic-gate 	if (rv == 0 && t_mp && (t_mp->sbm_flags & SBD_MFLAG_RELDONE)) {
6037c478bd9Sstevel@tonic-gate 		x_mp = t_mp;
6047c478bd9Sstevel@tonic-gate 		rv = memlist_intersect(phys_install, x_mp->sbm_del_mlist);
6057c478bd9Sstevel@tonic-gate 	}
6067c478bd9Sstevel@tonic-gate 	memlist_read_unlock();
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	if (rv) {
6097c478bd9Sstevel@tonic-gate 		sbp = (sbd_board_t *)x_mp->sbm_cm.sbdev_sbp;
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
6127c478bd9Sstevel@tonic-gate 			"%s: %smem-unit (%d.%d) memlist still in phys_install",
6137c478bd9Sstevel@tonic-gate 			f,
6147c478bd9Sstevel@tonic-gate 			x_mp == t_mp ? "target " : "",
6157c478bd9Sstevel@tonic-gate 			sbp->sb_num,
6167c478bd9Sstevel@tonic-gate 			x_mp->sbm_cm.sbdev_unum);
6177c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(ep, ESBD_INTERNAL);
6187c478bd9Sstevel@tonic-gate 		SBD_SET_ERRSTR(ep, sbp->sb_mempath[x_mp->sbm_cm.sbdev_unum]);
6197c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
6207c478bd9Sstevel@tonic-gate 		return (-1);
6217c478bd9Sstevel@tonic-gate 	}
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 	s_basepa	= _ptob64(s_mp->sbm_basepfn);
6247c478bd9Sstevel@tonic-gate 	s_nbytes	= _ptob64(s_mp->sbm_npages);
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 	if (t_mp != NULL) {
6277c478bd9Sstevel@tonic-gate 		t_basepa	= _ptob64(t_mp->sbm_basepfn);
6287c478bd9Sstevel@tonic-gate 		s_new_basepa	= (s_basepa & ~ sm) +
6297c478bd9Sstevel@tonic-gate 					_ptob64(t_mp->sbm_slice_offset);
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 		/*
6327c478bd9Sstevel@tonic-gate 		 * We had to swap mem-units, so update
6337c478bd9Sstevel@tonic-gate 		 * memlists accordingly with new base
6347c478bd9Sstevel@tonic-gate 		 * addresses.
6357c478bd9Sstevel@tonic-gate 		 */
636*56f33205SJonathan Adams 		for (ml = t_mp->sbm_mlist; ml; ml = ml->ml_next) {
637*56f33205SJonathan Adams 			ml->ml_address -= t_basepa;
638*56f33205SJonathan Adams 			ml->ml_address += s_new_basepa;
6397c478bd9Sstevel@tonic-gate 		}
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 		/*
6427c478bd9Sstevel@tonic-gate 		 * There is no need to explicitly rename the target delete
6437c478bd9Sstevel@tonic-gate 		 * memlist, because sbm_del_mlist and sbm_mlist always
6447c478bd9Sstevel@tonic-gate 		 * point to the same memlist for a copy/rename operation.
6457c478bd9Sstevel@tonic-gate 		 */
6467c478bd9Sstevel@tonic-gate 		ASSERT(t_mp->sbm_del_mlist == t_mp->sbm_mlist);
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 		PR_MEM("%s: renamed target memlist and delete memlist", f);
6497c478bd9Sstevel@tonic-gate 		SBD_MEMLIST_DUMP(t_mp->sbm_mlist);
6507c478bd9Sstevel@tonic-gate 
651*56f33205SJonathan Adams 		for (ml = s_mp->sbm_mlist; ml; ml = ml->ml_next) {
652*56f33205SJonathan Adams 			ml->ml_address -= s_basepa;
653*56f33205SJonathan Adams 			ml->ml_address += t_basepa;
6547c478bd9Sstevel@tonic-gate 		}
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 		PR_MEM("%s: renamed source memlist", f);
6577c478bd9Sstevel@tonic-gate 		SBD_MEMLIST_DUMP(s_mp->sbm_mlist);
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate #ifdef DEBUG
6607c478bd9Sstevel@tonic-gate 		ASSERT(s_mp->sbm_mlist != s_mp->sbm_del_mlist);
6617c478bd9Sstevel@tonic-gate 		/*
6627c478bd9Sstevel@tonic-gate 		 * Renaming s_mp->sbm_del_mlist is not necessary.  This
6637c478bd9Sstevel@tonic-gate 		 * list is not used beyond this point, and in fact, is
6647c478bd9Sstevel@tonic-gate 		 *  disposed of at the end of this function.
6657c478bd9Sstevel@tonic-gate 		 */
666*56f33205SJonathan Adams 		for (ml = s_mp->sbm_del_mlist; ml; ml = ml->ml_next) {
667*56f33205SJonathan Adams 			ml->ml_address -= s_basepa;
668*56f33205SJonathan Adams 			ml->ml_address += t_basepa;
6697c478bd9Sstevel@tonic-gate 		}
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 		PR_MEM("%s: renamed source delete memlist", f);
6727c478bd9Sstevel@tonic-gate 		SBD_MEMLIST_DUMP(s_mp->sbm_del_mlist);
6737c478bd9Sstevel@tonic-gate #endif
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 		if (s_mp->sbm_flags & SBD_MFLAG_MEMUPSIZE) {
6767c478bd9Sstevel@tonic-gate 			struct memlist	*nl;
6777c478bd9Sstevel@tonic-gate 			int mlret;
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 			/*
6807c478bd9Sstevel@tonic-gate 			 * We had to perform a copy-rename from a
6817c478bd9Sstevel@tonic-gate 			 * small memory node to a big memory node.
6827c478bd9Sstevel@tonic-gate 			 * Need to add back the remaining memory on
6837c478bd9Sstevel@tonic-gate 			 * the big board that wasn't used by that
6847c478bd9Sstevel@tonic-gate 			 * from the small board during the copy.
6857c478bd9Sstevel@tonic-gate 			 * Subtract out the portion of the target memory
6867c478bd9Sstevel@tonic-gate 			 * node that was taken over by the source memory
6877c478bd9Sstevel@tonic-gate 			 * node.
6887c478bd9Sstevel@tonic-gate 			 */
6897c478bd9Sstevel@tonic-gate 			nl = memlist_dup(t_mp->sbm_mlist);
6907c478bd9Sstevel@tonic-gate 			mlret = memlist_delete_span(s_basepa, s_nbytes, &nl);
6917c478bd9Sstevel@tonic-gate 			PR_MEM("%s: mlret = %d\n", f, mlret);
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 			sbp = (sbd_board_t *)t_mp->sbm_cm.sbdev_sbp;
6947c478bd9Sstevel@tonic-gate 			PR_MEM("%s: adding back remaining portion"
6957c478bd9Sstevel@tonic-gate 				" of mem-unit (%d.%d), memlist:\n",
6967c478bd9Sstevel@tonic-gate 				f, sbp->sb_num,
6977c478bd9Sstevel@tonic-gate 				t_mp->sbm_cm.sbdev_unum);
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 			SBD_MEMLIST_DUMP(nl);
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 			sbd_add_memory_spans(sbp, nl);
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 			memlist_delete(nl);
7047c478bd9Sstevel@tonic-gate 		}
7057c478bd9Sstevel@tonic-gate 	}
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 	if (t_mp != NULL) {
7097c478bd9Sstevel@tonic-gate 		sbp = (sbd_board_t *)t_mp->sbm_cm.sbdev_sbp;
7107c478bd9Sstevel@tonic-gate 		hdp->h_board = sbp->sb_num;
7117c478bd9Sstevel@tonic-gate 		/* delete target's entire address space */
7127c478bd9Sstevel@tonic-gate 		tmp_basepa = t_basepa & ~ sm;
7137c478bd9Sstevel@tonic-gate 		rv = sbdp_mem_del_span(hdp, tmp_basepa, sz);
7147c478bd9Sstevel@tonic-gate 		ASSERT(rv == 0);
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 		sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp;
7177c478bd9Sstevel@tonic-gate 		hdp->h_board = sbp->sb_num;
7187c478bd9Sstevel@tonic-gate 		tmp_basepa = s_basepa & ~ sm;
7197c478bd9Sstevel@tonic-gate 		sz = s_new_basepa & sm;
7207c478bd9Sstevel@tonic-gate 		/* delete source board's vacant address space */
7217c478bd9Sstevel@tonic-gate 		rv = sbdp_mem_del_span(hdp, tmp_basepa, sz);
7227c478bd9Sstevel@tonic-gate 		ASSERT(rv == 0);
7237c478bd9Sstevel@tonic-gate 	} else {
7247c478bd9Sstevel@tonic-gate 		sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp;
7257c478bd9Sstevel@tonic-gate 		hdp->h_board = sbp->sb_num;
7267c478bd9Sstevel@tonic-gate 		tmp_basepa = s_basepa & ~ sm;
7277c478bd9Sstevel@tonic-gate 		/* delete board's entire address space */
7287c478bd9Sstevel@tonic-gate 		rv = sbdp_mem_del_span(hdp, tmp_basepa, sz);
7297c478bd9Sstevel@tonic-gate 		ASSERT(rv == 0);
7307c478bd9Sstevel@tonic-gate 	}
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate #ifdef LINT
7337c478bd9Sstevel@tonic-gate 	rv = rv;
7347c478bd9Sstevel@tonic-gate #endif
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 	sbd_mem_cleanup(s_mp, t_mp, ep);
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate 	sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp;
7397c478bd9Sstevel@tonic-gate 	PR_MEM("%s: board %d's memlist:", f, sbp->sb_num);
7407c478bd9Sstevel@tonic-gate 	SBD_MEMLIST_DUMP(s_mp->sbm_mlist);
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
7437c478bd9Sstevel@tonic-gate 	return (0);
7447c478bd9Sstevel@tonic-gate }
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate static void
sbd_mem_cleanup(sbd_mem_unit_t * s_mp,sbd_mem_unit_t * t_mp,sbderror_t * ep)7477c478bd9Sstevel@tonic-gate sbd_mem_cleanup(sbd_mem_unit_t *s_mp, sbd_mem_unit_t *t_mp, sbderror_t *ep)
7487c478bd9Sstevel@tonic-gate {
7497c478bd9Sstevel@tonic-gate 	sbd_board_t *sbp;
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 	/* clean up target mem unit */
7527c478bd9Sstevel@tonic-gate 	if (t_mp != NULL) {
7537c478bd9Sstevel@tonic-gate 		sbp = (sbd_board_t *)t_mp->sbm_cm.sbdev_sbp;
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 		ASSERT(t_mp->sbm_del_mlist == t_mp->sbm_mlist);
7567c478bd9Sstevel@tonic-gate 		/*
7577c478bd9Sstevel@tonic-gate 		 * sbm_del_mlist and sbm_mlist point at the same list
7587c478bd9Sstevel@tonic-gate 		 * We only need to delete one and then set both pointers
7597c478bd9Sstevel@tonic-gate 		 * to NULL
7607c478bd9Sstevel@tonic-gate 		 */
7617c478bd9Sstevel@tonic-gate 		memlist_delete(t_mp->sbm_del_mlist);
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 		t_mp->sbm_del_mlist = NULL;
7647c478bd9Sstevel@tonic-gate 		t_mp->sbm_mlist = NULL;
7657c478bd9Sstevel@tonic-gate 		t_mp->sbm_peer = NULL;
7667c478bd9Sstevel@tonic-gate 		t_mp->sbm_flags = 0;
7677c478bd9Sstevel@tonic-gate 		t_mp->sbm_cm.sbdev_busy = 0;
7687c478bd9Sstevel@tonic-gate 		sbd_init_mem_unit_data(t_mp, ep);
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 		/*
7717c478bd9Sstevel@tonic-gate 		 * now that copy/rename has completed, undo this
7727c478bd9Sstevel@tonic-gate 		 * work that was done in sbd_release_mem_done.
7737c478bd9Sstevel@tonic-gate 		 */
7747c478bd9Sstevel@tonic-gate 		/*
7757c478bd9Sstevel@tonic-gate 		 * If error don't set the target to configured
7767c478bd9Sstevel@tonic-gate 		 */
7777c478bd9Sstevel@tonic-gate 		if (SBD_GET_ERR(ep) == 0) {
7787c478bd9Sstevel@tonic-gate 			SBD_DEV_CLR_UNREFERENCED(sbp, SBD_COMP_MEM, 0);
7797c478bd9Sstevel@tonic-gate 			SBD_DEV_CLR_RELEASED(sbp, SBD_COMP_MEM, 0);
7807c478bd9Sstevel@tonic-gate 			SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, 0,
7817c478bd9Sstevel@tonic-gate 				SBD_STATE_CONFIGURED);
7827c478bd9Sstevel@tonic-gate 		}
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate /* hack for test scripts.  *** remove before code finalized *** */
7857c478bd9Sstevel@tonic-gate sbd_last_target = sbp->sb_num;
7867c478bd9Sstevel@tonic-gate 	}
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 	/*
7897c478bd9Sstevel@tonic-gate 	 * clean up (source) board's mem unit structure.
7907c478bd9Sstevel@tonic-gate 	 * NOTE: sbm_mlist is retained.  It is referred to as the
7917c478bd9Sstevel@tonic-gate 	 * cached memlist.  The cached memlist is used to re-attach
7927c478bd9Sstevel@tonic-gate 	 * (configure back in) this memunit from the unconfigured
7937c478bd9Sstevel@tonic-gate 	 * state.
7947c478bd9Sstevel@tonic-gate 	 */
7957c478bd9Sstevel@tonic-gate 	if (s_mp != NULL) {
7967c478bd9Sstevel@tonic-gate 		sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp;
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 		/*
7997c478bd9Sstevel@tonic-gate 		 * Don't want to call memlist_delete for sbm_del_mlist,
8007c478bd9Sstevel@tonic-gate 		 * since that list points to the sbm_list
8017c478bd9Sstevel@tonic-gate 		 */
8027c478bd9Sstevel@tonic-gate 		s_mp->sbm_del_mlist = NULL;
8037c478bd9Sstevel@tonic-gate 		s_mp->sbm_peer = NULL;
8047c478bd9Sstevel@tonic-gate 		s_mp->sbm_flags = 0;
8057c478bd9Sstevel@tonic-gate 		s_mp->sbm_cm.sbdev_busy = 0;
8067c478bd9Sstevel@tonic-gate 		sbd_init_mem_unit_data(s_mp, ep);
8077c478bd9Sstevel@tonic-gate 	}
8087c478bd9Sstevel@tonic-gate }
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate /*
8117c478bd9Sstevel@tonic-gate  * Successful return from this function will have the memory
8127c478bd9Sstevel@tonic-gate  * handle in sbp->sb_dev[..mem-unit...].sbm_memhandle allocated
8137c478bd9Sstevel@tonic-gate  * and waiting.  This routine's job is to select the memory that
8147c478bd9Sstevel@tonic-gate  * actually has to be released (detached) which may not necessarily
8157c478bd9Sstevel@tonic-gate  * be the same memory node that came in in devlist[],
8167c478bd9Sstevel@tonic-gate  * i.e. a copy-rename is needed.
8177c478bd9Sstevel@tonic-gate  */
8187c478bd9Sstevel@tonic-gate int
sbd_pre_release_mem(sbd_handle_t * hp,sbd_devlist_t devlist[],int devnum)8197c478bd9Sstevel@tonic-gate sbd_pre_release_mem(sbd_handle_t *hp, sbd_devlist_t devlist[], int devnum)
8207c478bd9Sstevel@tonic-gate {
8217c478bd9Sstevel@tonic-gate 	extern int	kcage_on;
8227c478bd9Sstevel@tonic-gate 	int		d;
8237c478bd9Sstevel@tonic-gate 	int		err_flag = 0;
8247c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
8257c478bd9Sstevel@tonic-gate 	sbderror_t	*ep = SBD_HD2ERR(hp);
8267c478bd9Sstevel@tonic-gate 	sbderror_t	*lep;
8277c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_pre_release_mem";
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 	PR_MEM("%s...\n", f);
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 	if (kcage_on == 0) {
8327c478bd9Sstevel@tonic-gate 		/*
8337c478bd9Sstevel@tonic-gate 		 * Can't Detach memory if Cage is OFF.
8347c478bd9Sstevel@tonic-gate 		 */
8357c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s: kernel cage is disabled", f);
8367c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(ep, ESBD_KCAGE_OFF);
8377c478bd9Sstevel@tonic-gate 		return (-1);
8387c478bd9Sstevel@tonic-gate 	}
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate 	for (d = 0; d < devnum; d++) {
8417c478bd9Sstevel@tonic-gate 		int		rv;
8427c478bd9Sstevel@tonic-gate 		memquery_t	mq;
8437c478bd9Sstevel@tonic-gate 		sbd_mem_unit_t	*mp;
8447c478bd9Sstevel@tonic-gate 		struct memlist	*ml;
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate 		/* sbd_get_devlist will not devlist element w/ dip of 0 */
8477c478bd9Sstevel@tonic-gate 		ASSERT(devlist[d].dv_dip != NULL);
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 		mp = SBD_GET_BOARD_MEMUNIT(sbp, d);
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 		/*
8527c478bd9Sstevel@tonic-gate 		 * If all the mem unit is marked as failed then don't allow the
8537c478bd9Sstevel@tonic-gate 		 * operation
8547c478bd9Sstevel@tonic-gate 		 */
8557c478bd9Sstevel@tonic-gate 		if (mp->sbm_cm.sbdev_cond == SBD_COND_FAILED) {
8567c478bd9Sstevel@tonic-gate 			SBD_SET_ERR(ep, ESBD_STATE);
8577c478bd9Sstevel@tonic-gate 			SBD_SET_ERRSTR(ep, sbp->sb_mempath[d]);
8587c478bd9Sstevel@tonic-gate 			err_flag = -1;
8597c478bd9Sstevel@tonic-gate 			break;
8607c478bd9Sstevel@tonic-gate 		}
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 		ASSERT(d == mp->sbm_cm.sbdev_unum);
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 		/*
8657c478bd9Sstevel@tonic-gate 		 * if interleave is set to across boards fail the op
8667c478bd9Sstevel@tonic-gate 		 */
8677c478bd9Sstevel@tonic-gate 		if (mp->sbm_interleave) {
8687c478bd9Sstevel@tonic-gate 			SBD_SET_ERR(ep, ESBD_MEMINTLV);
8697c478bd9Sstevel@tonic-gate 			SBD_SET_ERRSTR(ep, sbp->sb_mempath[d]);
8707c478bd9Sstevel@tonic-gate 			err_flag = -1;
8717c478bd9Sstevel@tonic-gate 			break;
8727c478bd9Sstevel@tonic-gate 		}
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate 		lep = &devlist[d].dv_error;
8757c478bd9Sstevel@tonic-gate 		if (SBD_GET_ERR(lep) != 0) {
8767c478bd9Sstevel@tonic-gate 			err_flag = -1;
8777c478bd9Sstevel@tonic-gate 			(void) sbd_set_err_in_hdl(hp, lep);
8787c478bd9Sstevel@tonic-gate 			break;
8797c478bd9Sstevel@tonic-gate 		}
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 		if (mp->sbm_flags & SBD_MFLAG_RESERVED) {
8827c478bd9Sstevel@tonic-gate 			/*
8837c478bd9Sstevel@tonic-gate 			 * Board is currently involved in a delete
8847c478bd9Sstevel@tonic-gate 			 * memory operation. Can't detach this guy until
8857c478bd9Sstevel@tonic-gate 			 * that operation completes.
8867c478bd9Sstevel@tonic-gate 			 */
8877c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
8887c478bd9Sstevel@tonic-gate 				"%s: ineligible mem-unit (%d.%d) for detach",
8897c478bd9Sstevel@tonic-gate 				f, sbp->sb_num,
8907c478bd9Sstevel@tonic-gate 				mp->sbm_cm.sbdev_unum);
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate 			SBD_SET_ERR(lep, ESBD_INVAL);
8937c478bd9Sstevel@tonic-gate 			SBD_SET_ERRSTR(lep, sbp->sb_mempath[d]);
8947c478bd9Sstevel@tonic-gate 			(void) sbd_set_err_in_hdl(hp, lep);
8957c478bd9Sstevel@tonic-gate 			err_flag = -1;
8967c478bd9Sstevel@tonic-gate 			break;
8977c478bd9Sstevel@tonic-gate 		}
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 		/*
9007c478bd9Sstevel@tonic-gate 		 * Check whether the detaching memory requires a
9017c478bd9Sstevel@tonic-gate 		 * copy-rename.
9027c478bd9Sstevel@tonic-gate 		 */
9037c478bd9Sstevel@tonic-gate 		ASSERT(mp->sbm_npages != 0);
9047c478bd9Sstevel@tonic-gate 		rv = kphysm_del_span_query(
9057c478bd9Sstevel@tonic-gate 			mp->sbm_basepfn, mp->sbm_npages, &mq);
9067c478bd9Sstevel@tonic-gate 		if (rv != KPHYSM_OK) {
9077c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
9087c478bd9Sstevel@tonic-gate 				"%s: unexpected kphysm_del_span_query"
9097c478bd9Sstevel@tonic-gate 				" return value %d;"
9107c478bd9Sstevel@tonic-gate 				" basepfn 0x%lx, npages 0x%lx,"
9117c478bd9Sstevel@tonic-gate 				" mem-unit (%d.%d), dip 0x%p",
9127c478bd9Sstevel@tonic-gate 				f,
9137c478bd9Sstevel@tonic-gate 				rv,
9147c478bd9Sstevel@tonic-gate 				mp->sbm_basepfn,
9157c478bd9Sstevel@tonic-gate 				mp->sbm_npages,
9167c478bd9Sstevel@tonic-gate 				sbp->sb_num,
9177c478bd9Sstevel@tonic-gate 				mp->sbm_cm.sbdev_unum,
9187c478bd9Sstevel@tonic-gate 				(void *)mp->sbm_cm.sbdev_dip);
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 			SBD_SET_ERR(lep, ESBD_INTERNAL);
9217c478bd9Sstevel@tonic-gate 			SBD_SET_ERRSTR(lep, sbp->sb_mempath[d]);
9227c478bd9Sstevel@tonic-gate 			(void) sbd_set_err_in_hdl(hp, lep);
9237c478bd9Sstevel@tonic-gate 			err_flag = -1;
9247c478bd9Sstevel@tonic-gate 			break;
9257c478bd9Sstevel@tonic-gate 		}
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 		if (mq.nonrelocatable != 0) {
9287c478bd9Sstevel@tonic-gate 			if (!(hp->h_iap->i_flags & SBD_FLAG_QUIESCE_OKAY)) {
9297c478bd9Sstevel@tonic-gate 				/* caller wasn't prompted for a suspend */
9307c478bd9Sstevel@tonic-gate 					SBD_SET_ERR(lep, ESBD_QUIESCE_REQD);
9317c478bd9Sstevel@tonic-gate 					SBD_SET_ERRSTR(lep, sbp->sb_mempath[d]);
9327c478bd9Sstevel@tonic-gate 					(void) sbd_set_err_in_hdl(hp, lep);
9337c478bd9Sstevel@tonic-gate 					err_flag = 1;
9347c478bd9Sstevel@tonic-gate 					break;
9357c478bd9Sstevel@tonic-gate 			}
9367c478bd9Sstevel@tonic-gate 		}
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 		/* flags should be clean at this time */
9397c478bd9Sstevel@tonic-gate 		ASSERT(mp->sbm_flags == 0);
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 		ASSERT(mp->sbm_del_mlist == NULL);	/* should be null */
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate 		if (mp->sbm_mlist != NULL) {
9447c478bd9Sstevel@tonic-gate 			memlist_delete(mp->sbm_mlist);
9457c478bd9Sstevel@tonic-gate 			mp->sbm_mlist = NULL;
9467c478bd9Sstevel@tonic-gate 		}
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 		ml = sbd_get_memlist(mp, lep);
9497c478bd9Sstevel@tonic-gate 		(void) sbd_set_err_in_hdl(hp, lep);
9507c478bd9Sstevel@tonic-gate 		if (ml == NULL) {
9517c478bd9Sstevel@tonic-gate 			PR_MEM("%s: no memlist found for board %d\n",
9527c478bd9Sstevel@tonic-gate 				f, sbp->sb_num);
9537c478bd9Sstevel@tonic-gate 			err_flag = -1;
9547c478bd9Sstevel@tonic-gate 			break;
9557c478bd9Sstevel@tonic-gate 		}
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 		/* allocate a kphysm handle */
9587c478bd9Sstevel@tonic-gate 		rv = kphysm_del_gethandle(&mp->sbm_memhandle);
9597c478bd9Sstevel@tonic-gate 		if (rv != KPHYSM_OK) {
9607c478bd9Sstevel@tonic-gate 			memlist_delete(ml);
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
9637c478bd9Sstevel@tonic-gate 				"%s: unexpected kphysm_del_gethandle"
9647c478bd9Sstevel@tonic-gate 				" return value %d", f, rv);
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 			SBD_SET_ERR(lep, ESBD_INTERNAL);
9677c478bd9Sstevel@tonic-gate 			SBD_SET_ERRSTR(lep, sbp->sb_mempath[d]);
9687c478bd9Sstevel@tonic-gate 			(void) sbd_set_err_in_hdl(hp, lep);
9697c478bd9Sstevel@tonic-gate 			err_flag = -1;
9707c478bd9Sstevel@tonic-gate 			break;
9717c478bd9Sstevel@tonic-gate 		}
9727c478bd9Sstevel@tonic-gate 		mp->sbm_flags |= SBD_MFLAG_RELOWNER;
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate 		if ((mq.nonrelocatable != 0) ||
9757c478bd9Sstevel@tonic-gate 			sbd_reserve_mem_spans(&mp->sbm_memhandle, ml)) {
9767c478bd9Sstevel@tonic-gate 			/*
9777c478bd9Sstevel@tonic-gate 			 * Either the detaching memory node contains
9787c478bd9Sstevel@tonic-gate 			 * non-reloc memory or we failed to reserve the
9797c478bd9Sstevel@tonic-gate 			 * detaching memory node (which did _not_ have
9807c478bd9Sstevel@tonic-gate 			 * any non-reloc memory, i.e. some non-reloc mem
9817c478bd9Sstevel@tonic-gate 			 * got onboard).
9827c478bd9Sstevel@tonic-gate 			 */
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 			if (sbd_select_mem_target(hp, mp, ml)) {
9857c478bd9Sstevel@tonic-gate 				int rv;
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate 				/*
9887c478bd9Sstevel@tonic-gate 				 * We had no luck locating a target
9897c478bd9Sstevel@tonic-gate 				 * memory node to be the recipient of
9907c478bd9Sstevel@tonic-gate 				 * the non-reloc memory on the node
9917c478bd9Sstevel@tonic-gate 				 * we're trying to detach.
9927c478bd9Sstevel@tonic-gate 				 * Clean up be disposing the mem handle
9937c478bd9Sstevel@tonic-gate 				 * and the mem list.
9947c478bd9Sstevel@tonic-gate 				 */
9957c478bd9Sstevel@tonic-gate 				rv = kphysm_del_release(mp->sbm_memhandle);
9967c478bd9Sstevel@tonic-gate 				if (rv != KPHYSM_OK) {
9977c478bd9Sstevel@tonic-gate 					/*
9987c478bd9Sstevel@tonic-gate 					 * can do nothing but complain
9997c478bd9Sstevel@tonic-gate 					 * and hope helpful for debug
10007c478bd9Sstevel@tonic-gate 					 */
10017c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN, "sbd:%s: unexpected"
10027c478bd9Sstevel@tonic-gate 						" kphysm_del_release return"
10037c478bd9Sstevel@tonic-gate 						" value %d",
10047c478bd9Sstevel@tonic-gate 						f, rv);
10057c478bd9Sstevel@tonic-gate 				}
10067c478bd9Sstevel@tonic-gate 				mp->sbm_flags &= ~SBD_MFLAG_RELOWNER;
10077c478bd9Sstevel@tonic-gate 
10087c478bd9Sstevel@tonic-gate 				memlist_delete(ml);
10097c478bd9Sstevel@tonic-gate 
10107c478bd9Sstevel@tonic-gate 				/* make sure sbm_flags is clean */
10117c478bd9Sstevel@tonic-gate 				ASSERT(mp->sbm_flags == 0);
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
10147c478bd9Sstevel@tonic-gate 					"%s: no available target for "
10157c478bd9Sstevel@tonic-gate 					"mem-unit (%d.%d)",
10167c478bd9Sstevel@tonic-gate 					f, sbp->sb_num,
10177c478bd9Sstevel@tonic-gate 					mp->sbm_cm.sbdev_unum);
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate 				SBD_SET_ERR(lep, ESBD_NO_TARGET);
10207c478bd9Sstevel@tonic-gate 				SBD_SET_ERRSTR(lep,
10217c478bd9Sstevel@tonic-gate 					sbp->sb_mempath[mp->sbm_cm.sbdev_unum]);
10227c478bd9Sstevel@tonic-gate 				(void) sbd_set_err_in_hdl(hp, lep);
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate 				err_flag = -1;
10257c478bd9Sstevel@tonic-gate 				break;
10267c478bd9Sstevel@tonic-gate 			}
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate 			/*
10297c478bd9Sstevel@tonic-gate 			 * ml is not memlist_deleted here because
10307c478bd9Sstevel@tonic-gate 			 * it has been assigned to mp->sbm_mlist
10317c478bd9Sstevel@tonic-gate 			 * by sbd_select_mem_target.
10327c478bd9Sstevel@tonic-gate 			 */
10337c478bd9Sstevel@tonic-gate 		} else {
10347c478bd9Sstevel@tonic-gate 			/* no target needed to detach this board */
10357c478bd9Sstevel@tonic-gate 			mp->sbm_flags |= SBD_MFLAG_RESERVED;
10367c478bd9Sstevel@tonic-gate 			mp->sbm_peer = NULL;
10377c478bd9Sstevel@tonic-gate 			mp->sbm_del_mlist = ml;
10387c478bd9Sstevel@tonic-gate 			mp->sbm_mlist = ml;
10397c478bd9Sstevel@tonic-gate 			mp->sbm_cm.sbdev_busy = 1;
10407c478bd9Sstevel@tonic-gate 		}
10417c478bd9Sstevel@tonic-gate #ifdef DEBUG
10427c478bd9Sstevel@tonic-gate 		ASSERT(mp->sbm_mlist != NULL);
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate 		if (mp->sbm_flags & SBD_MFLAG_SOURCE) {
10457c478bd9Sstevel@tonic-gate 			int src, targ;
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate 			sbp = (sbd_board_t *)
10487c478bd9Sstevel@tonic-gate 				mp->sbm_peer->sbm_cm.sbdev_sbp;
10497c478bd9Sstevel@tonic-gate 			targ = sbp->sb_num;
10507c478bd9Sstevel@tonic-gate 			sbp = (sbd_board_t *)mp->sbm_cm.sbdev_sbp;
10517c478bd9Sstevel@tonic-gate 			src = sbp->sb_num;
10527c478bd9Sstevel@tonic-gate 			PR_MEM("%s: release of board %d requires copy/rename;"
10537c478bd9Sstevel@tonic-gate 				" selected target board %d\n",
10547c478bd9Sstevel@tonic-gate 				f, src, targ);
10557c478bd9Sstevel@tonic-gate 		} else {
10567c478bd9Sstevel@tonic-gate 			sbp = (sbd_board_t *)mp->sbm_cm.sbdev_sbp;
10577c478bd9Sstevel@tonic-gate 			PR_MEM("%s: copy/rename not required to release"
10587c478bd9Sstevel@tonic-gate 				" board %d\n", f, sbp->sb_num);
10597c478bd9Sstevel@tonic-gate 		}
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate 		ASSERT(mp->sbm_flags & SBD_MFLAG_RELOWNER);
10627c478bd9Sstevel@tonic-gate 		ASSERT(mp->sbm_flags & SBD_MFLAG_RESERVED);
10637c478bd9Sstevel@tonic-gate #endif
10647c478bd9Sstevel@tonic-gate 	}
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate 	return (err_flag);
10677c478bd9Sstevel@tonic-gate }
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate void
sbd_release_mem_done(sbd_handle_t * hp,int unit)10707c478bd9Sstevel@tonic-gate sbd_release_mem_done(sbd_handle_t *hp, int unit)
10717c478bd9Sstevel@tonic-gate {
10727c478bd9Sstevel@tonic-gate 	sbd_mem_unit_t	*s_mp, *t_mp, *mp;
10737c478bd9Sstevel@tonic-gate 	sbderror_t	*ep = SBD_HD2ERR(hp);
10747c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
10757c478bd9Sstevel@tonic-gate 	int		rv;
10767c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_release_mem_done";
10777c478bd9Sstevel@tonic-gate 
10787c478bd9Sstevel@tonic-gate 	s_mp = SBD_GET_BOARD_MEMUNIT(sbp, unit);
10797c478bd9Sstevel@tonic-gate 	sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp;
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate 	/*
10827c478bd9Sstevel@tonic-gate 	 * This unit will be flagged with SBD_MFLAG_SOURCE, if it
10837c478bd9Sstevel@tonic-gate 	 * has a target unit.
10847c478bd9Sstevel@tonic-gate 	 */
10857c478bd9Sstevel@tonic-gate 	if (s_mp->sbm_flags & SBD_MFLAG_SOURCE) {
10867c478bd9Sstevel@tonic-gate 		t_mp = s_mp->sbm_peer;
10877c478bd9Sstevel@tonic-gate 		ASSERT(t_mp != NULL);
10887c478bd9Sstevel@tonic-gate 		ASSERT(t_mp->sbm_peer == s_mp);
10897c478bd9Sstevel@tonic-gate 		ASSERT(t_mp->sbm_flags & SBD_MFLAG_TARGET);
10907c478bd9Sstevel@tonic-gate 		ASSERT(t_mp->sbm_flags & SBD_MFLAG_RESERVED);
10917c478bd9Sstevel@tonic-gate 	} else {
10927c478bd9Sstevel@tonic-gate 		/* this is no target unit */
10937c478bd9Sstevel@tonic-gate 		t_mp = NULL;
10947c478bd9Sstevel@tonic-gate 	}
10957c478bd9Sstevel@tonic-gate 
10967c478bd9Sstevel@tonic-gate 	/* free delete handle */
10977c478bd9Sstevel@tonic-gate 	ASSERT(s_mp->sbm_flags & SBD_MFLAG_RELOWNER);
10987c478bd9Sstevel@tonic-gate 	ASSERT(s_mp->sbm_flags & SBD_MFLAG_RESERVED);
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 	rv = kphysm_del_release(s_mp->sbm_memhandle);
11017c478bd9Sstevel@tonic-gate 	if (rv != KPHYSM_OK) {
11027c478bd9Sstevel@tonic-gate 		/*
11037c478bd9Sstevel@tonic-gate 		 * can do nothing but complain
11047c478bd9Sstevel@tonic-gate 		 * and hope helpful for debug
11057c478bd9Sstevel@tonic-gate 		 */
11067c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "sbd:%s: unexpected kphysm_del_release"
11077c478bd9Sstevel@tonic-gate 			" return value %d", f, rv);
11087c478bd9Sstevel@tonic-gate 	}
11097c478bd9Sstevel@tonic-gate 	s_mp->sbm_flags &= ~SBD_MFLAG_RELOWNER;
11107c478bd9Sstevel@tonic-gate 
11117c478bd9Sstevel@tonic-gate 	/*
11127c478bd9Sstevel@tonic-gate 	 * If an error was encountered during release, clean up
11137c478bd9Sstevel@tonic-gate 	 * the source (and target, if present) unit data.
11147c478bd9Sstevel@tonic-gate 	 */
11157c478bd9Sstevel@tonic-gate 	if (SBD_GET_ERR(ep) != 0) {
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 		PR_MEM("%s: unit %d.%d: error %d noted\n",
11187c478bd9Sstevel@tonic-gate 			f, sbp->sb_num,
11197c478bd9Sstevel@tonic-gate 			s_mp->sbm_cm.sbdev_unum,
11207c478bd9Sstevel@tonic-gate 			SBD_GET_ERR(ep));
11217c478bd9Sstevel@tonic-gate 
11227c478bd9Sstevel@tonic-gate 		sbd_mem_cleanup(s_mp, t_mp, ep);
11237c478bd9Sstevel@tonic-gate 
11247c478bd9Sstevel@tonic-gate 		/* bail out */
11257c478bd9Sstevel@tonic-gate 		return;
11267c478bd9Sstevel@tonic-gate 	}
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate 	SBD_DEV_SET_RELEASED(sbp, SBD_COMP_MEM, unit);
11297c478bd9Sstevel@tonic-gate 	SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, unit, SBD_STATE_RELEASE);
11307c478bd9Sstevel@tonic-gate 
11317c478bd9Sstevel@tonic-gate 	if (t_mp != NULL) {
11327c478bd9Sstevel@tonic-gate 		sbp = (sbd_board_t *)t_mp->sbm_cm.sbdev_sbp;
11337c478bd9Sstevel@tonic-gate 		/*
11347c478bd9Sstevel@tonic-gate 		 * the kphysm delete operation that drained the source
11357c478bd9Sstevel@tonic-gate 		 * board also drained this target board.  Since the source
11367c478bd9Sstevel@tonic-gate 		 * board drain is now known to have succeeded, we know this
11377c478bd9Sstevel@tonic-gate 		 * target board is drained too.
11387c478bd9Sstevel@tonic-gate 		 */
11397c478bd9Sstevel@tonic-gate 		SBD_DEV_SET_RELEASED(sbp, SBD_COMP_MEM,
11407c478bd9Sstevel@tonic-gate 			t_mp->sbm_cm.sbdev_unum);
11417c478bd9Sstevel@tonic-gate 		SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM,
11427c478bd9Sstevel@tonic-gate 			t_mp->sbm_cm.sbdev_unum,
11437c478bd9Sstevel@tonic-gate 			SBD_STATE_RELEASE);
11447c478bd9Sstevel@tonic-gate 
11457c478bd9Sstevel@tonic-gate 		/*
11467c478bd9Sstevel@tonic-gate 		 * NOTE: do not transition target's board state,
11477c478bd9Sstevel@tonic-gate 		 * even if the mem-unit was the last configure
11487c478bd9Sstevel@tonic-gate 		 * unit of the board.  When copy/rename completes
11497c478bd9Sstevel@tonic-gate 		 * this mem-unit will transitioned back to
11507c478bd9Sstevel@tonic-gate 		 * the configured state.  In the meantime, the
11517c478bd9Sstevel@tonic-gate 		 * board's must remain as is.
11527c478bd9Sstevel@tonic-gate 		 */
11537c478bd9Sstevel@tonic-gate 	}
11547c478bd9Sstevel@tonic-gate 
11557c478bd9Sstevel@tonic-gate 	/* if board(s) had deleted memory, verify it is gone */
11567c478bd9Sstevel@tonic-gate 	rv = 0;
11577c478bd9Sstevel@tonic-gate 	memlist_read_lock();
11587c478bd9Sstevel@tonic-gate 	if (s_mp->sbm_del_mlist != NULL) {
11597c478bd9Sstevel@tonic-gate 		sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp;
11607c478bd9Sstevel@tonic-gate 		mp = s_mp;
11617c478bd9Sstevel@tonic-gate 		rv = memlist_intersect(phys_install, mp->sbm_del_mlist);
11627c478bd9Sstevel@tonic-gate 	}
11637c478bd9Sstevel@tonic-gate 	if (rv == 0 && t_mp && t_mp->sbm_del_mlist != NULL) {
11647c478bd9Sstevel@tonic-gate 		sbp = (sbd_board_t *)t_mp->sbm_cm.sbdev_sbp;
11657c478bd9Sstevel@tonic-gate 		mp = t_mp;
11667c478bd9Sstevel@tonic-gate 		rv = memlist_intersect(phys_install, mp->sbm_del_mlist);
11677c478bd9Sstevel@tonic-gate 	}
11687c478bd9Sstevel@tonic-gate 	memlist_read_unlock();
11697c478bd9Sstevel@tonic-gate 	if (rv) {
11707c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "sbd:%s: %smem-unit (%d.%d): "
11717c478bd9Sstevel@tonic-gate 			"deleted memory still found in phys_install",
11727c478bd9Sstevel@tonic-gate 			f,
11737c478bd9Sstevel@tonic-gate 			(mp == t_mp ? "target " : ""),
11747c478bd9Sstevel@tonic-gate 			sbp->sb_num,
11757c478bd9Sstevel@tonic-gate 			mp->sbm_cm.sbdev_unum);
11767c478bd9Sstevel@tonic-gate 
11777c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(ep, ESBD_INTERNAL);
11787c478bd9Sstevel@tonic-gate 		SBD_SET_ERRSTR(ep, sbp->sb_mempath[mp->sbm_cm.sbdev_unum]);
11797c478bd9Sstevel@tonic-gate 		return;
11807c478bd9Sstevel@tonic-gate 	}
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate 	s_mp->sbm_flags |= SBD_MFLAG_RELDONE;
11837c478bd9Sstevel@tonic-gate 	if (t_mp != NULL) {
11847c478bd9Sstevel@tonic-gate 		t_mp->sbm_flags &= ~SBD_MFLAG_RESERVED;
11857c478bd9Sstevel@tonic-gate 		t_mp->sbm_flags |= SBD_MFLAG_RELDONE;
11867c478bd9Sstevel@tonic-gate 	}
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate 	sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp;
11897c478bd9Sstevel@tonic-gate 
11907c478bd9Sstevel@tonic-gate 	SBD_DEV_SET_UNREFERENCED(sbp, SBD_COMP_MEM, unit);
11917c478bd9Sstevel@tonic-gate 	SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, unit, SBD_STATE_UNREFERENCED);
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate 	PR_MEM("%s: marking mem-unit (%d.%d) release DONE\n",
11947c478bd9Sstevel@tonic-gate 		f, sbp->sb_num,
11957c478bd9Sstevel@tonic-gate 		s_mp->sbm_cm.sbdev_unum);
11967c478bd9Sstevel@tonic-gate 
11977c478bd9Sstevel@tonic-gate 	s_mp->sbm_cm.sbdev_ostate = SBD_STAT_UNCONFIGURED;
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate 	if (t_mp != NULL) {
12007c478bd9Sstevel@tonic-gate 		sbp = (sbd_board_t *)t_mp->sbm_cm.sbdev_sbp;
12017c478bd9Sstevel@tonic-gate 
12027c478bd9Sstevel@tonic-gate 		SBD_DEV_SET_UNREFERENCED(sbp, SBD_COMP_MEM,
12037c478bd9Sstevel@tonic-gate 			t_mp->sbm_cm.sbdev_unum);
12047c478bd9Sstevel@tonic-gate 		SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM,
12057c478bd9Sstevel@tonic-gate 			t_mp->sbm_cm.sbdev_unum,
12067c478bd9Sstevel@tonic-gate 			SBD_STATE_UNREFERENCED);
12077c478bd9Sstevel@tonic-gate 
12087c478bd9Sstevel@tonic-gate 		sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp;
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate 		PR_MEM("%s: marking mem-unit (%d.%d) release DONE\n",
12117c478bd9Sstevel@tonic-gate 			f, sbp->sb_num,
12127c478bd9Sstevel@tonic-gate 			t_mp->sbm_cm.sbdev_unum);
12137c478bd9Sstevel@tonic-gate 
12147c478bd9Sstevel@tonic-gate 		t_mp->sbm_cm.sbdev_ostate = SBD_STAT_UNCONFIGURED;
12157c478bd9Sstevel@tonic-gate 	}
12167c478bd9Sstevel@tonic-gate }
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate int
sbd_disconnect_mem(sbd_handle_t * hp,int unit)12197c478bd9Sstevel@tonic-gate sbd_disconnect_mem(sbd_handle_t *hp, int unit)
12207c478bd9Sstevel@tonic-gate {
12217c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_disconnect_mem";
12227c478bd9Sstevel@tonic-gate 	sbd_mem_unit_t	*mp;
12237c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
12247c478bd9Sstevel@tonic-gate 
12257c478bd9Sstevel@tonic-gate 	mp = SBD_GET_BOARD_MEMUNIT(sbp, unit);
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 	ASSERT(mp->sbm_cm.sbdev_state == SBD_STATE_CONNECTED ||
12287c478bd9Sstevel@tonic-gate 	    mp->sbm_cm.sbdev_state == SBD_STATE_UNCONFIGURED);
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate 	PR_MEM("%s...\n", f);
12317c478bd9Sstevel@tonic-gate 
12327c478bd9Sstevel@tonic-gate 	if (mp->sbm_del_mlist && mp->sbm_del_mlist != mp->sbm_mlist)
12337c478bd9Sstevel@tonic-gate 		memlist_delete(mp->sbm_del_mlist);
12347c478bd9Sstevel@tonic-gate 	mp->sbm_del_mlist = NULL;
12357c478bd9Sstevel@tonic-gate 
12367c478bd9Sstevel@tonic-gate 	if (mp->sbm_mlist) {
12377c478bd9Sstevel@tonic-gate 		memlist_delete(mp->sbm_mlist);
12387c478bd9Sstevel@tonic-gate 		mp->sbm_mlist = NULL;
12397c478bd9Sstevel@tonic-gate 	}
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate 	return (0);
12427c478bd9Sstevel@tonic-gate }
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate int
sbd_cancel_mem(sbd_handle_t * hp,int unit)12457c478bd9Sstevel@tonic-gate sbd_cancel_mem(sbd_handle_t *hp, int unit)
12467c478bd9Sstevel@tonic-gate {
12477c478bd9Sstevel@tonic-gate 	sbd_mem_unit_t	*s_mp, *t_mp;
12487c478bd9Sstevel@tonic-gate 	sbd_istate_t	state;
12497c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
12507c478bd9Sstevel@tonic-gate 	sbd_board_t	*tsbp;
12517c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_cancel_mem";
12527c478bd9Sstevel@tonic-gate 	sbderror_t	*ep = SBD_HD2ERR(hp);
12537c478bd9Sstevel@tonic-gate 
12547c478bd9Sstevel@tonic-gate 	s_mp = SBD_GET_BOARD_MEMUNIT(sbp, unit);
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate 	state = s_mp->sbm_cm.sbdev_state;
12577c478bd9Sstevel@tonic-gate 
12587c478bd9Sstevel@tonic-gate 	if (s_mp->sbm_flags & SBD_MFLAG_TARGET) {
12597c478bd9Sstevel@tonic-gate 		/* must cancel source board, not target board */
12607c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(ep, ESBD_INTERNAL);
12617c478bd9Sstevel@tonic-gate 		SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]);
12627c478bd9Sstevel@tonic-gate 		return (-1);
12637c478bd9Sstevel@tonic-gate 	} else if (s_mp->sbm_flags & SBD_MFLAG_SOURCE) {
12647c478bd9Sstevel@tonic-gate 		t_mp = s_mp->sbm_peer;
12657c478bd9Sstevel@tonic-gate 		tsbp = t_mp->sbm_cm.sbdev_sbp;
12667c478bd9Sstevel@tonic-gate 		ASSERT(t_mp != NULL);
12677c478bd9Sstevel@tonic-gate 		ASSERT(t_mp->sbm_peer == s_mp);
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate 		/* must always match the source board's state */
12707c478bd9Sstevel@tonic-gate 		ASSERT(t_mp->sbm_cm.sbdev_state == state);
12717c478bd9Sstevel@tonic-gate 	} else {
12727c478bd9Sstevel@tonic-gate 		/* this is no target unit */
12737c478bd9Sstevel@tonic-gate 		t_mp = NULL;
12747c478bd9Sstevel@tonic-gate 	}
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate 	switch (state) {
12777c478bd9Sstevel@tonic-gate 	case SBD_STATE_UNREFERENCED:	/* state set by sbd_release_mem_done */
12787c478bd9Sstevel@tonic-gate 		ASSERT((s_mp->sbm_flags & SBD_MFLAG_RELOWNER) == 0);
12797c478bd9Sstevel@tonic-gate 
12807c478bd9Sstevel@tonic-gate 		if (t_mp != NULL && t_mp->sbm_del_mlist != NULL) {
12817c478bd9Sstevel@tonic-gate 			PR_MEM("%s: undoing target board %d memory delete\n",
12827c478bd9Sstevel@tonic-gate 				f, tsbp->sb_num);
12837c478bd9Sstevel@tonic-gate 			sbd_add_memory_spans(tsbp, t_mp->sbm_del_mlist);
12847c478bd9Sstevel@tonic-gate 			SBD_DEV_CLR_UNREFERENCED(tsbp, SBD_COMP_MEM,
12857c478bd9Sstevel@tonic-gate 				t_mp->sbm_cm.sbdev_unum);
12867c478bd9Sstevel@tonic-gate 		}
12877c478bd9Sstevel@tonic-gate 
12887c478bd9Sstevel@tonic-gate 		if (s_mp->sbm_del_mlist != NULL) {
12897c478bd9Sstevel@tonic-gate 			PR_MEM("%s: undoing board %d memory delete\n",
12907c478bd9Sstevel@tonic-gate 				f, sbp->sb_num);
12917c478bd9Sstevel@tonic-gate 			sbd_add_memory_spans(sbp, s_mp->sbm_del_mlist);
12927c478bd9Sstevel@tonic-gate 		}
12937c478bd9Sstevel@tonic-gate 
12947c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
12957c478bd9Sstevel@tonic-gate 
12967c478bd9Sstevel@tonic-gate 	case SBD_STATE_CONFIGURED:
12977c478bd9Sstevel@tonic-gate 		/*
12987c478bd9Sstevel@tonic-gate 		 * we got here because of an error early in the release process
12997c478bd9Sstevel@tonic-gate 		 * Just leave the memory as is and report the error
13007c478bd9Sstevel@tonic-gate 		 */
13017c478bd9Sstevel@tonic-gate 
13027c478bd9Sstevel@tonic-gate 		ASSERT((s_mp->sbm_flags & SBD_MFLAG_RELOWNER) == 0);
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate 		if (t_mp != NULL) {
13057c478bd9Sstevel@tonic-gate 			ASSERT(t_mp->sbm_del_mlist == t_mp->sbm_mlist);
13067c478bd9Sstevel@tonic-gate 			t_mp->sbm_del_mlist = NULL;
13077c478bd9Sstevel@tonic-gate 
13087c478bd9Sstevel@tonic-gate 			if (t_mp->sbm_mlist != NULL) {
13097c478bd9Sstevel@tonic-gate 				memlist_delete(t_mp->sbm_mlist);
13107c478bd9Sstevel@tonic-gate 				t_mp->sbm_mlist = NULL;
13117c478bd9Sstevel@tonic-gate 			}
13127c478bd9Sstevel@tonic-gate 
13137c478bd9Sstevel@tonic-gate 			t_mp->sbm_peer = NULL;
13147c478bd9Sstevel@tonic-gate 			t_mp->sbm_flags = 0;
13157c478bd9Sstevel@tonic-gate 			t_mp->sbm_cm.sbdev_busy = 0;
13167c478bd9Sstevel@tonic-gate 			sbd_init_mem_unit_data(t_mp, ep);
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 			SBD_DEV_CLR_RELEASED(tsbp, SBD_COMP_MEM,
13197c478bd9Sstevel@tonic-gate 				t_mp->sbm_cm.sbdev_unum);
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate 			SBD_DEVICE_TRANSITION(tsbp, SBD_COMP_MEM,
13227c478bd9Sstevel@tonic-gate 				t_mp->sbm_cm.sbdev_unum,
13237c478bd9Sstevel@tonic-gate 				SBD_STATE_CONFIGURED);
13247c478bd9Sstevel@tonic-gate 		}
13257c478bd9Sstevel@tonic-gate 
13267c478bd9Sstevel@tonic-gate 		if (s_mp->sbm_del_mlist != s_mp->sbm_mlist)
13277c478bd9Sstevel@tonic-gate 			memlist_delete(s_mp->sbm_del_mlist);
13287c478bd9Sstevel@tonic-gate 		s_mp->sbm_del_mlist = NULL;
13297c478bd9Sstevel@tonic-gate 
13307c478bd9Sstevel@tonic-gate 		if (s_mp->sbm_mlist != NULL) {
13317c478bd9Sstevel@tonic-gate 			memlist_delete(s_mp->sbm_mlist);
13327c478bd9Sstevel@tonic-gate 			s_mp->sbm_mlist = NULL;
13337c478bd9Sstevel@tonic-gate 		}
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate 		s_mp->sbm_peer = NULL;
13367c478bd9Sstevel@tonic-gate 		s_mp->sbm_flags = 0;
13377c478bd9Sstevel@tonic-gate 		s_mp->sbm_cm.sbdev_busy = 0;
13387c478bd9Sstevel@tonic-gate 		sbd_init_mem_unit_data(s_mp, ep);
13397c478bd9Sstevel@tonic-gate 
13407c478bd9Sstevel@tonic-gate 		return (0);
13417c478bd9Sstevel@tonic-gate 	default:
13427c478bd9Sstevel@tonic-gate 		PR_MEM("%s: WARNING unexpected state (%d) for "
13437c478bd9Sstevel@tonic-gate 			"mem-unit %d.%d\n",
13447c478bd9Sstevel@tonic-gate 			f,
13457c478bd9Sstevel@tonic-gate 			(int)state,
13467c478bd9Sstevel@tonic-gate 			sbp->sb_num,
13477c478bd9Sstevel@tonic-gate 			s_mp->sbm_cm.sbdev_unum);
13487c478bd9Sstevel@tonic-gate 
13497c478bd9Sstevel@tonic-gate 		return (-1);
13507c478bd9Sstevel@tonic-gate 	}
13517c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
13527c478bd9Sstevel@tonic-gate }
13537c478bd9Sstevel@tonic-gate 
13547c478bd9Sstevel@tonic-gate void
sbd_init_mem_unit(sbd_board_t * sbp,int unit,sbderror_t * ep)13557c478bd9Sstevel@tonic-gate sbd_init_mem_unit(sbd_board_t *sbp, int unit, sbderror_t *ep)
13567c478bd9Sstevel@tonic-gate {
13577c478bd9Sstevel@tonic-gate 	sbd_istate_t	new_state;
13587c478bd9Sstevel@tonic-gate 	sbd_mem_unit_t	*mp;
13597c478bd9Sstevel@tonic-gate 	dev_info_t	*cur_mc_dip;
13607c478bd9Sstevel@tonic-gate 	int		failed_mcs = 0, present_mcs = 0;
13617c478bd9Sstevel@tonic-gate 	sbd_cond_t	mc_cond;
13627c478bd9Sstevel@tonic-gate 	int		i;
13637c478bd9Sstevel@tonic-gate 
13647c478bd9Sstevel@tonic-gate 	mp = SBD_GET_BOARD_MEMUNIT(sbp, unit);
13657c478bd9Sstevel@tonic-gate 
13667c478bd9Sstevel@tonic-gate 	if (SBD_DEV_IS_ATTACHED(sbp, SBD_COMP_MEM, unit)) {
13677c478bd9Sstevel@tonic-gate 		new_state = SBD_STATE_CONFIGURED;
13687c478bd9Sstevel@tonic-gate 	} else if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_MEM, unit)) {
13697c478bd9Sstevel@tonic-gate 		new_state = SBD_STATE_CONNECTED;
13707c478bd9Sstevel@tonic-gate 	} else if (mp->sbm_cm.sbdev_dip != NULL) {
13717c478bd9Sstevel@tonic-gate 		new_state = SBD_STATE_OCCUPIED;
13727c478bd9Sstevel@tonic-gate 	} else {
13737c478bd9Sstevel@tonic-gate 		new_state = SBD_STATE_EMPTY;
13747c478bd9Sstevel@tonic-gate 	}
13757c478bd9Sstevel@tonic-gate 
13767c478bd9Sstevel@tonic-gate 	/*
13777c478bd9Sstevel@tonic-gate 	 * Check all the possible memory nodes on the board.  If all of them
13787c478bd9Sstevel@tonic-gate 	 * have a failed status mark memory as failed. Otherwise mem is ok
13797c478bd9Sstevel@tonic-gate 	 */
13807c478bd9Sstevel@tonic-gate 	if (!sbp->sb_memaccess_ok) {
13817c478bd9Sstevel@tonic-gate 		mp->sbm_cm.sbdev_cond = SBD_COND_UNKNOWN;
13827c478bd9Sstevel@tonic-gate 		return;
13837c478bd9Sstevel@tonic-gate 	}
13847c478bd9Sstevel@tonic-gate 
13857c478bd9Sstevel@tonic-gate 	for (i = 0; i < SBD_NUM_MC_PER_BOARD; i++) {
13867c478bd9Sstevel@tonic-gate 		cur_mc_dip = mp->sbm_dip[i];
13877c478bd9Sstevel@tonic-gate 
13887c478bd9Sstevel@tonic-gate 		if (cur_mc_dip == NULL)
13897c478bd9Sstevel@tonic-gate 			continue;
13907c478bd9Sstevel@tonic-gate 
13917c478bd9Sstevel@tonic-gate 		present_mcs |= (1 << i);
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate 		mc_cond = sbd_get_comp_cond(cur_mc_dip);
13947c478bd9Sstevel@tonic-gate 		if (mc_cond == SBD_COND_FAILED) {
13957c478bd9Sstevel@tonic-gate 			failed_mcs |= (1 << i);
13967c478bd9Sstevel@tonic-gate 		}
13977c478bd9Sstevel@tonic-gate 	}
13987c478bd9Sstevel@tonic-gate 
13997c478bd9Sstevel@tonic-gate 	if (failed_mcs == present_mcs) {
14007c478bd9Sstevel@tonic-gate 		/*
14017c478bd9Sstevel@tonic-gate 		 * All mem nodes failed, therefore mark all mem
14027c478bd9Sstevel@tonic-gate 		 * as failed
14037c478bd9Sstevel@tonic-gate 		 */
14047c478bd9Sstevel@tonic-gate 		mp->sbm_cm.sbdev_cond = SBD_COND_FAILED;
14057c478bd9Sstevel@tonic-gate 	} else {
14067c478bd9Sstevel@tonic-gate 		mp->sbm_cm.sbdev_cond = SBD_COND_OK;
14077c478bd9Sstevel@tonic-gate 	}
14087c478bd9Sstevel@tonic-gate 
14097c478bd9Sstevel@tonic-gate 	sbd_init_mem_unit_data(mp, ep);
14107c478bd9Sstevel@tonic-gate 
14117c478bd9Sstevel@tonic-gate 	/*
14127c478bd9Sstevel@tonic-gate 	 * Any changes to this memory unit should be performed above
14137c478bd9Sstevel@tonic-gate 	 * this call to ensure the unit is fully initialized
14147c478bd9Sstevel@tonic-gate 	 * before transitioning to the new state.
14157c478bd9Sstevel@tonic-gate 	 */
14167c478bd9Sstevel@tonic-gate 	SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, unit, new_state);
14177c478bd9Sstevel@tonic-gate 
14187c478bd9Sstevel@tonic-gate }
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate static void
sbd_init_mem_unit_data(sbd_mem_unit_t * mp,sbderror_t * ep)14217c478bd9Sstevel@tonic-gate sbd_init_mem_unit_data(sbd_mem_unit_t *mp, sbderror_t *ep)
14227c478bd9Sstevel@tonic-gate {
14237c478bd9Sstevel@tonic-gate 	uint64_t	basepa;
14247c478bd9Sstevel@tonic-gate 	uint64_t	sz;
14257c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = mp->sbm_cm.sbdev_sbp;
14267c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
14277c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_init_mem_unit_data";
14287c478bd9Sstevel@tonic-gate 	sbd_handle_t	*hp = MACHBD2HD(sbp);
14297c478bd9Sstevel@tonic-gate 
14307c478bd9Sstevel@tonic-gate 	PR_MEM("%s...\n", f);
14317c478bd9Sstevel@tonic-gate 
14327c478bd9Sstevel@tonic-gate 	/* a little sanity checking */
14337c478bd9Sstevel@tonic-gate 	ASSERT(mp->sbm_peer == NULL);
14347c478bd9Sstevel@tonic-gate 	ASSERT(mp->sbm_flags == 0);
14357c478bd9Sstevel@tonic-gate 
14367c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
14377c478bd9Sstevel@tonic-gate 
14387c478bd9Sstevel@tonic-gate 	/* get basepfn of mem unit */
14397c478bd9Sstevel@tonic-gate 	if (sbdphw_get_base_physaddr(hdp, mp->sbm_cm.sbdev_dip, &basepa)) {
14407c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "sbd:%s: failed to get physaddr"
14417c478bd9Sstevel@tonic-gate 			" for mem-unit (%d.%d)",
14427c478bd9Sstevel@tonic-gate 			f,
14437c478bd9Sstevel@tonic-gate 			sbp->sb_num,
14447c478bd9Sstevel@tonic-gate 			mp->sbm_cm.sbdev_unum);
14457c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, ep);
14467c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
14477c478bd9Sstevel@tonic-gate 		return;
14487c478bd9Sstevel@tonic-gate 	}
14497c478bd9Sstevel@tonic-gate 	mp->sbm_basepfn = _b64top(basepa);
14507c478bd9Sstevel@tonic-gate 
14517c478bd9Sstevel@tonic-gate 	/* attempt to get number of pages from PDA */
14527c478bd9Sstevel@tonic-gate 	mp->sbm_npages = sbdp_get_mem_size(hdp);
14537c478bd9Sstevel@tonic-gate 
14547c478bd9Sstevel@tonic-gate 	/* if didn't work, calculate using memlist */
14557c478bd9Sstevel@tonic-gate 	if (mp->sbm_npages == 0) {
14567c478bd9Sstevel@tonic-gate 		struct memlist	*ml, *mlist;
14577c478bd9Sstevel@tonic-gate 		mlist = sbd_get_memlist(mp, ep);
1458*56f33205SJonathan Adams 		for (ml = mlist; ml; ml = ml->ml_next)
1459*56f33205SJonathan Adams 			mp->sbm_npages += btop(ml->ml_size);
14607c478bd9Sstevel@tonic-gate 		memlist_delete(mlist);
14617c478bd9Sstevel@tonic-gate 	}
14627c478bd9Sstevel@tonic-gate 
14637c478bd9Sstevel@tonic-gate 
14647c478bd9Sstevel@tonic-gate 	if (sbdp_get_mem_alignment(hdp, mp->sbm_cm.sbdev_dip, &sz)) {
14657c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
14667c478bd9Sstevel@tonic-gate 			"sbd:%s: no alignment for mem-unit (%d.%d)",
14677c478bd9Sstevel@tonic-gate 			f, sbp->sb_num, mp->sbm_cm.sbdev_unum);
14687c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, ep);
14697c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
14707c478bd9Sstevel@tonic-gate 		return;
14717c478bd9Sstevel@tonic-gate 	}
14727c478bd9Sstevel@tonic-gate 	mp->sbm_alignment_mask = _b64top(sz);
14737c478bd9Sstevel@tonic-gate 
14747c478bd9Sstevel@tonic-gate 
14757c478bd9Sstevel@tonic-gate 	mp->sbm_interleave = sbdp_isinterleaved(hdp,
14767c478bd9Sstevel@tonic-gate 	    mp->sbm_cm.sbdev_dip);
14777c478bd9Sstevel@tonic-gate 
14787c478bd9Sstevel@tonic-gate 	PR_MEM("%s: board %d (basepfn = 0x%lx, npgs = 0x%lx interleave %d)\n",
14797c478bd9Sstevel@tonic-gate 		f, sbp->sb_num,
14807c478bd9Sstevel@tonic-gate 		mp->sbm_basepfn,
14817c478bd9Sstevel@tonic-gate 		mp->sbm_npages,
14827c478bd9Sstevel@tonic-gate 		mp->sbm_interleave);
14837c478bd9Sstevel@tonic-gate 
14847c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
14857c478bd9Sstevel@tonic-gate }
14867c478bd9Sstevel@tonic-gate 
14877c478bd9Sstevel@tonic-gate static int
sbd_reserve_mem_spans(memhandle_t * mhp,struct memlist * ml)14887c478bd9Sstevel@tonic-gate sbd_reserve_mem_spans(memhandle_t *mhp, struct memlist *ml)
14897c478bd9Sstevel@tonic-gate {
14907c478bd9Sstevel@tonic-gate 	int		err;
14917c478bd9Sstevel@tonic-gate 	pfn_t		base;
14927c478bd9Sstevel@tonic-gate 	pgcnt_t		npgs;
14937c478bd9Sstevel@tonic-gate 	struct memlist	*mc;
14947c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_reserve_mem_spans";
14957c478bd9Sstevel@tonic-gate 
14967c478bd9Sstevel@tonic-gate 	PR_MEM("%s...\n", f);
14977c478bd9Sstevel@tonic-gate 
14987c478bd9Sstevel@tonic-gate 	/*
14997c478bd9Sstevel@tonic-gate 	 * Walk the supplied memlist scheduling each span for removal
15007c478bd9Sstevel@tonic-gate 	 * with kphysm_del_span.  It is possible that a span may intersect
15017c478bd9Sstevel@tonic-gate 	 * an area occupied by the cage.
15027c478bd9Sstevel@tonic-gate 	 */
1503*56f33205SJonathan Adams 	for (mc = ml; mc != NULL; mc = mc->ml_next) {
1504*56f33205SJonathan Adams 		base = _b64top(mc->ml_address);
1505*56f33205SJonathan Adams 		npgs = _b64top(mc->ml_size);
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate 		err = kphysm_del_span(*mhp, base, npgs);
15087c478bd9Sstevel@tonic-gate 		if (err != KPHYSM_OK) {
15097c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "sbd:%s memory reserve failed."
15107c478bd9Sstevel@tonic-gate 				" unexpected kphysm_del_span return value %d;"
15117c478bd9Sstevel@tonic-gate 				" basepfn=0x%lx npages=%ld",
15127c478bd9Sstevel@tonic-gate 				f, err, base, npgs);
15137c478bd9Sstevel@tonic-gate 			return (-1);
15147c478bd9Sstevel@tonic-gate 		}
15157c478bd9Sstevel@tonic-gate 	}
15167c478bd9Sstevel@tonic-gate 	return (0);
15177c478bd9Sstevel@tonic-gate }
15187c478bd9Sstevel@tonic-gate 
15197c478bd9Sstevel@tonic-gate /* debug counters */
15207c478bd9Sstevel@tonic-gate int sbd_smt_realigned;
15217c478bd9Sstevel@tonic-gate int sbd_smt_preference[4];
15227c478bd9Sstevel@tonic-gate 
15237c478bd9Sstevel@tonic-gate #ifdef DEBUG
15247c478bd9Sstevel@tonic-gate uint_t sbd_ignore_board; /* if bit[bnum-1] set, board won't be candidate */
15257c478bd9Sstevel@tonic-gate #endif
15267c478bd9Sstevel@tonic-gate 
15277c478bd9Sstevel@tonic-gate /*
15287c478bd9Sstevel@tonic-gate  * Verify that there is no memory overlapping if copy-rename is
15297c478bd9Sstevel@tonic-gate  * done with the selected target board.
15307c478bd9Sstevel@tonic-gate  *
15317c478bd9Sstevel@tonic-gate  * Returns 0 if OK, -1 otherwise.
15327c478bd9Sstevel@tonic-gate  */
15337c478bd9Sstevel@tonic-gate static int
sbd_check_boundaries(struct memlist * orig_memlist,sbd_mem_unit_t * s_mp,sbd_mem_unit_t * t_mp)15347c478bd9Sstevel@tonic-gate sbd_check_boundaries(struct memlist *orig_memlist, sbd_mem_unit_t *s_mp,
15357c478bd9Sstevel@tonic-gate 	sbd_mem_unit_t *t_mp)
15367c478bd9Sstevel@tonic-gate {
15377c478bd9Sstevel@tonic-gate 	struct memlist	*new_memlist;
15387c478bd9Sstevel@tonic-gate 	int mlret;
15397c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_check_boundaries";
15407c478bd9Sstevel@tonic-gate 
15417c478bd9Sstevel@tonic-gate 	new_memlist = memlist_dup(orig_memlist);
15427c478bd9Sstevel@tonic-gate 	if (new_memlist == NULL) {
15437c478bd9Sstevel@tonic-gate 		PR_MEM("%s: can't dup original memlist\n", f);
15447c478bd9Sstevel@tonic-gate 		return (-1);
15457c478bd9Sstevel@tonic-gate 	}
15467c478bd9Sstevel@tonic-gate 
15477c478bd9Sstevel@tonic-gate 	mlret = memlist_delete_span(
15487c478bd9Sstevel@tonic-gate 		_ptob64(s_mp->sbm_basepfn),
15497c478bd9Sstevel@tonic-gate 		_ptob64(s_mp->sbm_npages),
15507c478bd9Sstevel@tonic-gate 		&new_memlist);
15517c478bd9Sstevel@tonic-gate 	if (mlret != MEML_SPANOP_OK) {
15527c478bd9Sstevel@tonic-gate 		PR_MEM("%s: del s/s mlret = %d\n", f, mlret);
15537c478bd9Sstevel@tonic-gate 		goto check_done;
15547c478bd9Sstevel@tonic-gate 	}
15557c478bd9Sstevel@tonic-gate 
15567c478bd9Sstevel@tonic-gate 	mlret = memlist_delete_span(
15577c478bd9Sstevel@tonic-gate 		_ptob64(t_mp->sbm_basepfn),
15587c478bd9Sstevel@tonic-gate 		_ptob64(t_mp->sbm_npages),
15597c478bd9Sstevel@tonic-gate 		&new_memlist);
15607c478bd9Sstevel@tonic-gate 	if (mlret != MEML_SPANOP_OK) {
15617c478bd9Sstevel@tonic-gate 		PR_MEM("%s: del t/t mlret = %d\n", f, mlret);
15627c478bd9Sstevel@tonic-gate 		goto check_done;
15637c478bd9Sstevel@tonic-gate 	}
15647c478bd9Sstevel@tonic-gate 
15657c478bd9Sstevel@tonic-gate 	mlret = memlist_add_span(
15667c478bd9Sstevel@tonic-gate 		_ptob64(t_mp->sbm_basepfn),
15677c478bd9Sstevel@tonic-gate 		_ptob64(s_mp->sbm_npages),
15687c478bd9Sstevel@tonic-gate 		&new_memlist);
15697c478bd9Sstevel@tonic-gate 	if (mlret != MEML_SPANOP_OK) {
15707c478bd9Sstevel@tonic-gate 		PR_MEM("%s: add t/s mlret = %d\n", f, mlret);
15717c478bd9Sstevel@tonic-gate 		goto check_done;
15727c478bd9Sstevel@tonic-gate 	}
15737c478bd9Sstevel@tonic-gate 
15747c478bd9Sstevel@tonic-gate 	mlret = memlist_add_span(
15757c478bd9Sstevel@tonic-gate 		_ptob64(s_mp->sbm_basepfn),
15767c478bd9Sstevel@tonic-gate 		_ptob64(t_mp->sbm_npages),
15777c478bd9Sstevel@tonic-gate 		&new_memlist);
15787c478bd9Sstevel@tonic-gate 	if (mlret != MEML_SPANOP_OK) {
15797c478bd9Sstevel@tonic-gate 		PR_MEM("%s: add s/t mlret = %d\n", f, mlret);
15807c478bd9Sstevel@tonic-gate 	}
15817c478bd9Sstevel@tonic-gate 
15827c478bd9Sstevel@tonic-gate check_done:
15837c478bd9Sstevel@tonic-gate 	memlist_delete(new_memlist);
15847c478bd9Sstevel@tonic-gate 
15857c478bd9Sstevel@tonic-gate 	if (mlret == MEML_SPANOP_OK)
15867c478bd9Sstevel@tonic-gate 		return (0);
15877c478bd9Sstevel@tonic-gate 	else
15887c478bd9Sstevel@tonic-gate 		return (-1);
15897c478bd9Sstevel@tonic-gate }
15907c478bd9Sstevel@tonic-gate 
15917c478bd9Sstevel@tonic-gate /*
15927c478bd9Sstevel@tonic-gate  * Find and reserve a copy/rename target board suitable for the
15937c478bd9Sstevel@tonic-gate  * given source board.
15947c478bd9Sstevel@tonic-gate  * All boards in the system are examined and categorized in relation to
15957c478bd9Sstevel@tonic-gate  * their memory size versus the source board's memory size.  Order of
15967c478bd9Sstevel@tonic-gate  * preference is:
15977c478bd9Sstevel@tonic-gate  *	1st: board has same memory size
15987c478bd9Sstevel@tonic-gate  * 	2nd: board has larger memory size
15997c478bd9Sstevel@tonic-gate  *	3rd: board has smaller memory size
16007c478bd9Sstevel@tonic-gate  *	4th: board has smaller memory size, available memory will be reduced.
16017c478bd9Sstevel@tonic-gate  * Boards in category 3 and 4 will have their MC's reprogrammed to locate the
16027c478bd9Sstevel@tonic-gate  * span to which the MC responds to address span that appropriately covers
16037c478bd9Sstevel@tonic-gate  * the nonrelocatable span of the source board.
16047c478bd9Sstevel@tonic-gate  */
16057c478bd9Sstevel@tonic-gate static int
sbd_select_mem_target(sbd_handle_t * hp,sbd_mem_unit_t * s_mp,struct memlist * s_ml)16067c478bd9Sstevel@tonic-gate sbd_select_mem_target(sbd_handle_t *hp,
16077c478bd9Sstevel@tonic-gate 	sbd_mem_unit_t *s_mp, struct memlist *s_ml)
16087c478bd9Sstevel@tonic-gate {
16097c478bd9Sstevel@tonic-gate 	uint64_t	sz;
16107c478bd9Sstevel@tonic-gate 	pgcnt_t		sm;
16117c478bd9Sstevel@tonic-gate 	int		n_sets = 4; /* same, larger, smaller, clipped */
16127c478bd9Sstevel@tonic-gate 	int		preference; /* lower value is higher preference */
16137c478bd9Sstevel@tonic-gate 	int		n_units_per_set;
16147c478bd9Sstevel@tonic-gate 	int		idx;
16157c478bd9Sstevel@tonic-gate 	sbd_mem_unit_t	**sets;
16167c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
16177c478bd9Sstevel@tonic-gate 	int		t_bd;
16187c478bd9Sstevel@tonic-gate 	sbd_softstate_t	*softsp;
16197c478bd9Sstevel@tonic-gate 	int		t_unit;
16207c478bd9Sstevel@tonic-gate 	int		max_boards;
16217c478bd9Sstevel@tonic-gate 	int		rv;
16227c478bd9Sstevel@tonic-gate 	sbd_board_t	*s_sbp, *t_sbp;
16237c478bd9Sstevel@tonic-gate 	sbd_mem_unit_t	*t_mp, *c_mp;
16247c478bd9Sstevel@tonic-gate 	struct memlist	*d_ml, *t_ml, *x_ml;
16257c478bd9Sstevel@tonic-gate 	memquery_t	s_mq = {0};
16267c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_select_mem_target";
16277c478bd9Sstevel@tonic-gate 
16287c478bd9Sstevel@tonic-gate 	PR_MEM("%s...\n", f);
16297c478bd9Sstevel@tonic-gate 
16307c478bd9Sstevel@tonic-gate 	ASSERT(s_ml != NULL);
16317c478bd9Sstevel@tonic-gate 
16327c478bd9Sstevel@tonic-gate 	s_sbp = s_mp->sbm_cm.sbdev_sbp;
16337c478bd9Sstevel@tonic-gate 
16347c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(s_sbp, hp);
16357c478bd9Sstevel@tonic-gate 
16367c478bd9Sstevel@tonic-gate 	if (sbdp_get_mem_alignment(hdp, s_mp->sbm_cm.sbdev_dip, &sz)) {
16377c478bd9Sstevel@tonic-gate 		sbderror_t	*ep = SBD_HD2ERR(hp);
16387c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
16397c478bd9Sstevel@tonic-gate 			"sbd:%s: no alignment for mem-unit (%d.%d)",
16407c478bd9Sstevel@tonic-gate 			f, s_sbp->sb_num, s_mp->sbm_cm.sbdev_unum);
16417c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, ep);
16427c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
16437c478bd9Sstevel@tonic-gate 		return (-1);
16447c478bd9Sstevel@tonic-gate 	}
16457c478bd9Sstevel@tonic-gate 	sm = sz - 1;
16467c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
16477c478bd9Sstevel@tonic-gate 
16487c478bd9Sstevel@tonic-gate 	softsp = (sbd_softstate_t *)s_sbp->sb_softsp;
16497c478bd9Sstevel@tonic-gate 
16507c478bd9Sstevel@tonic-gate 	max_boards = softsp->max_boards;
16517c478bd9Sstevel@tonic-gate 	n_units_per_set = max_boards * MAX_MEM_UNITS_PER_BOARD;
16527c478bd9Sstevel@tonic-gate 	sets = GETSTRUCT(sbd_mem_unit_t *, n_units_per_set * n_sets);
16537c478bd9Sstevel@tonic-gate 
16547c478bd9Sstevel@tonic-gate 	/*
16557c478bd9Sstevel@tonic-gate 	 * Make one pass through all memory units on all boards
16567c478bd9Sstevel@tonic-gate 	 * and categorize them with respect to the source board.
16577c478bd9Sstevel@tonic-gate 	 */
16587c478bd9Sstevel@tonic-gate 	for (t_bd = 0; t_bd < max_boards; t_bd++) {
16597c478bd9Sstevel@tonic-gate 		/*
16607c478bd9Sstevel@tonic-gate 		 * The board structs are a contiguous array
16617c478bd9Sstevel@tonic-gate 		 * so we take advantage of that to find the
16627c478bd9Sstevel@tonic-gate 		 * correct board struct pointer for a given
16637c478bd9Sstevel@tonic-gate 		 * board number.
16647c478bd9Sstevel@tonic-gate 		 */
16657c478bd9Sstevel@tonic-gate 		t_sbp = (sbd_board_t *)softsp->sbd_boardlist;
16667c478bd9Sstevel@tonic-gate 		t_sbp += t_bd;
16677c478bd9Sstevel@tonic-gate 
16687c478bd9Sstevel@tonic-gate 		/* source board can not be its own target */
16697c478bd9Sstevel@tonic-gate 		if (s_sbp->sb_num == t_sbp->sb_num)
16707c478bd9Sstevel@tonic-gate 			continue;
16717c478bd9Sstevel@tonic-gate 
16727c478bd9Sstevel@tonic-gate 		for (t_unit = 0; t_unit < MAX_MEM_UNITS_PER_BOARD; t_unit++) {
16737c478bd9Sstevel@tonic-gate 
16747c478bd9Sstevel@tonic-gate 			t_mp = SBD_GET_BOARD_MEMUNIT(t_sbp, t_unit);
16757c478bd9Sstevel@tonic-gate 
16767c478bd9Sstevel@tonic-gate 			/* this memory node must be attached */
16777c478bd9Sstevel@tonic-gate 			if (!SBD_DEV_IS_ATTACHED(t_sbp, SBD_COMP_MEM, t_unit))
16787c478bd9Sstevel@tonic-gate 				continue;
16797c478bd9Sstevel@tonic-gate 
16807c478bd9Sstevel@tonic-gate 			/* source unit can not be its own target */
16817c478bd9Sstevel@tonic-gate 			if (s_mp == t_mp) {
16827c478bd9Sstevel@tonic-gate 				/* catch this in debug kernels */
16837c478bd9Sstevel@tonic-gate 				ASSERT(0);
16847c478bd9Sstevel@tonic-gate 				continue;
16857c478bd9Sstevel@tonic-gate 			}
16867c478bd9Sstevel@tonic-gate 
16877c478bd9Sstevel@tonic-gate 			/*
16887c478bd9Sstevel@tonic-gate 			 * this memory node must not already be reserved
16897c478bd9Sstevel@tonic-gate 			 * by some other memory delete operation.
16907c478bd9Sstevel@tonic-gate 			 */
16917c478bd9Sstevel@tonic-gate 			if (t_mp->sbm_flags & SBD_MFLAG_RESERVED)
16927c478bd9Sstevel@tonic-gate 				continue;
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate 			/*
16957c478bd9Sstevel@tonic-gate 			 * categorize the memory node
16967c478bd9Sstevel@tonic-gate 			 * If this is a smaller memory node, create a
16977c478bd9Sstevel@tonic-gate 			 * temporary, edited copy of the source board's
16987c478bd9Sstevel@tonic-gate 			 * memlist containing only the span of the non-
16997c478bd9Sstevel@tonic-gate 			 * relocatable pages.
17007c478bd9Sstevel@tonic-gate 			 */
17017c478bd9Sstevel@tonic-gate 			if (t_mp->sbm_npages == s_mp->sbm_npages) {
17027c478bd9Sstevel@tonic-gate 				preference = 0;
17037c478bd9Sstevel@tonic-gate 				t_mp->sbm_slice_offset = 0;
17047c478bd9Sstevel@tonic-gate 			} else if (t_mp->sbm_npages > s_mp->sbm_npages) {
17057c478bd9Sstevel@tonic-gate 				preference = 1;
17067c478bd9Sstevel@tonic-gate 				t_mp->sbm_slice_offset = 0;
17077c478bd9Sstevel@tonic-gate 			} else {
17087c478bd9Sstevel@tonic-gate 				/*
17097c478bd9Sstevel@tonic-gate 				 * We do not allow other options right now
17107c478bd9Sstevel@tonic-gate 				 */
17117c478bd9Sstevel@tonic-gate 				continue;
17127c478bd9Sstevel@tonic-gate 			}
17137c478bd9Sstevel@tonic-gate 
17147c478bd9Sstevel@tonic-gate 			sbd_smt_preference[preference]++;
17157c478bd9Sstevel@tonic-gate 
17167c478bd9Sstevel@tonic-gate 			/* calculate index to start of preference set */
17177c478bd9Sstevel@tonic-gate 			idx  = n_units_per_set * preference;
17187c478bd9Sstevel@tonic-gate 			/* calculate offset to respective element */
17197c478bd9Sstevel@tonic-gate 			idx += t_bd * MAX_MEM_UNITS_PER_BOARD + t_unit;
17207c478bd9Sstevel@tonic-gate 
17217c478bd9Sstevel@tonic-gate 			ASSERT(idx < n_units_per_set * n_sets);
17227c478bd9Sstevel@tonic-gate 			sets[idx] = t_mp;
17237c478bd9Sstevel@tonic-gate 		}
17247c478bd9Sstevel@tonic-gate 	}
17257c478bd9Sstevel@tonic-gate 
17267c478bd9Sstevel@tonic-gate 	/*
17277c478bd9Sstevel@tonic-gate 	 * NOTE: this would be a good place to sort each candidate
17287c478bd9Sstevel@tonic-gate 	 * set in to some desired order, e.g. memory size in ascending
17297c478bd9Sstevel@tonic-gate 	 * order.  Without an additional sorting step here, the order
17307c478bd9Sstevel@tonic-gate 	 * within a set is ascending board number order.
17317c478bd9Sstevel@tonic-gate 	 */
17327c478bd9Sstevel@tonic-gate 
17337c478bd9Sstevel@tonic-gate 	c_mp = NULL;
17347c478bd9Sstevel@tonic-gate 	x_ml = NULL;
17357c478bd9Sstevel@tonic-gate 	t_ml = NULL;
17367c478bd9Sstevel@tonic-gate 	for (idx = 0; idx < n_units_per_set * n_sets; idx++) {
17377c478bd9Sstevel@tonic-gate 		memquery_t mq;
17387c478bd9Sstevel@tonic-gate 
17397c478bd9Sstevel@tonic-gate 		/* cleanup t_ml after previous pass */
17407c478bd9Sstevel@tonic-gate 		if (t_ml != NULL) {
17417c478bd9Sstevel@tonic-gate 			memlist_delete(t_ml);
17427c478bd9Sstevel@tonic-gate 			t_ml = NULL;
17437c478bd9Sstevel@tonic-gate 		}
17447c478bd9Sstevel@tonic-gate 
17457c478bd9Sstevel@tonic-gate 		/* get candidate target board mem unit */
17467c478bd9Sstevel@tonic-gate 		t_mp = sets[idx];
17477c478bd9Sstevel@tonic-gate 		if (t_mp == NULL)
17487c478bd9Sstevel@tonic-gate 			continue;
17497c478bd9Sstevel@tonic-gate 
17507c478bd9Sstevel@tonic-gate 		t_sbp = t_mp->sbm_cm.sbdev_sbp;
17517c478bd9Sstevel@tonic-gate 
17527c478bd9Sstevel@tonic-gate 		/* get target board memlist */
17537c478bd9Sstevel@tonic-gate 		t_ml = sbd_get_memlist(t_mp, SBD_HD2ERR(hp));
17547c478bd9Sstevel@tonic-gate 		if (t_ml == NULL) {
17557c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "sbd:%s: no memlist for"
17567c478bd9Sstevel@tonic-gate 				" mem-unit %d, board %d",
17577c478bd9Sstevel@tonic-gate 				f,
17587c478bd9Sstevel@tonic-gate 				t_sbp->sb_num,
17597c478bd9Sstevel@tonic-gate 				t_mp->sbm_cm.sbdev_unum);
17607c478bd9Sstevel@tonic-gate 
17617c478bd9Sstevel@tonic-gate 			continue;
17627c478bd9Sstevel@tonic-gate 		}
17637c478bd9Sstevel@tonic-gate 
17647c478bd9Sstevel@tonic-gate 		/* get appropriate source board memlist */
17657c478bd9Sstevel@tonic-gate 		if (t_mp->sbm_npages < s_mp->sbm_npages) {
17667c478bd9Sstevel@tonic-gate 			spgcnt_t excess;
17677c478bd9Sstevel@tonic-gate 
17687c478bd9Sstevel@tonic-gate 			/*
17697c478bd9Sstevel@tonic-gate 			 * make a copy of the source board memlist
17707c478bd9Sstevel@tonic-gate 			 * then edit it to remove the spans that
17717c478bd9Sstevel@tonic-gate 			 * are outside the calculated span of
17727c478bd9Sstevel@tonic-gate 			 * [pfn..s_mq.last_nonrelocatable].
17737c478bd9Sstevel@tonic-gate 			 */
17747c478bd9Sstevel@tonic-gate 			if (x_ml != NULL)
17757c478bd9Sstevel@tonic-gate 				memlist_delete(x_ml);
17767c478bd9Sstevel@tonic-gate 
17777c478bd9Sstevel@tonic-gate 			x_ml = memlist_dup(s_ml);
17787c478bd9Sstevel@tonic-gate 			if (x_ml == NULL) {
17797c478bd9Sstevel@tonic-gate 				PR_MEM("%s: memlist_dup failed\n", f);
17807c478bd9Sstevel@tonic-gate 				/* TODO: should abort */
17817c478bd9Sstevel@tonic-gate 				continue;
17827c478bd9Sstevel@tonic-gate 			}
17837c478bd9Sstevel@tonic-gate 
17847c478bd9Sstevel@tonic-gate 			/* trim off lower portion */
17857c478bd9Sstevel@tonic-gate 			excess = t_mp->sbm_slice_offset;
17867c478bd9Sstevel@tonic-gate 			if (excess > 0) {
17877c478bd9Sstevel@tonic-gate 				int mlret;
17887c478bd9Sstevel@tonic-gate 
17897c478bd9Sstevel@tonic-gate 				mlret = memlist_delete_span(
17907c478bd9Sstevel@tonic-gate 					_ptob64(s_mp->sbm_basepfn),
17917c478bd9Sstevel@tonic-gate 					_ptob64(excess),
17927c478bd9Sstevel@tonic-gate 					&x_ml);
17937c478bd9Sstevel@tonic-gate 				PR_MEM("%s: mlret = %d\n", f, mlret);
17947c478bd9Sstevel@tonic-gate 			}
17957c478bd9Sstevel@tonic-gate 
17967c478bd9Sstevel@tonic-gate 			/*
17977c478bd9Sstevel@tonic-gate 			 * Since this candidate target board is smaller
17987c478bd9Sstevel@tonic-gate 			 * than the source board, s_mq must have been
17997c478bd9Sstevel@tonic-gate 			 * initialized in previous loop while processing
18007c478bd9Sstevel@tonic-gate 			 * this or some other candidate board.
18017c478bd9Sstevel@tonic-gate 			 * FIXME: this is weak.
18027c478bd9Sstevel@tonic-gate 			 */
18037c478bd9Sstevel@tonic-gate 			ASSERT(s_mq.phys_pages != 0);
18047c478bd9Sstevel@tonic-gate 
18057c478bd9Sstevel@tonic-gate 			/* trim off upper portion */
18067c478bd9Sstevel@tonic-gate 			excess = (s_mp->sbm_basepfn + s_mp->sbm_npages)
18077c478bd9Sstevel@tonic-gate 				- (s_mq.last_nonrelocatable + 1);
18087c478bd9Sstevel@tonic-gate 			if (excess > 0) {
18097c478bd9Sstevel@tonic-gate 				pfn_t p;
18107c478bd9Sstevel@tonic-gate 				int mlret;
18117c478bd9Sstevel@tonic-gate 
18127c478bd9Sstevel@tonic-gate 				p  = s_mq.last_nonrelocatable + 1;
18137c478bd9Sstevel@tonic-gate 				p -= excess;
18147c478bd9Sstevel@tonic-gate 
18157c478bd9Sstevel@tonic-gate 				mlret = memlist_delete_span(
18167c478bd9Sstevel@tonic-gate 					_ptob64(p),
18177c478bd9Sstevel@tonic-gate 					_ptob64(excess),
18187c478bd9Sstevel@tonic-gate 					&x_ml);
18197c478bd9Sstevel@tonic-gate 				PR_MEM("%s: mlret = %d\n", f, mlret);
18207c478bd9Sstevel@tonic-gate 			}
18217c478bd9Sstevel@tonic-gate 
18227c478bd9Sstevel@tonic-gate 			PR_MEM("%s: brd %d: edited source memlist:\n",
18237c478bd9Sstevel@tonic-gate 				f, s_sbp->sb_num);
18247c478bd9Sstevel@tonic-gate 			SBD_MEMLIST_DUMP(x_ml);
18257c478bd9Sstevel@tonic-gate 
18267c478bd9Sstevel@tonic-gate #ifdef DEBUG
18277c478bd9Sstevel@tonic-gate 			/* sanity check memlist */
18287c478bd9Sstevel@tonic-gate 			d_ml = x_ml;
1829*56f33205SJonathan Adams 			while (d_ml->ml_next != NULL)
1830*56f33205SJonathan Adams 				d_ml = d_ml->ml_next;
1831*56f33205SJonathan Adams 			ASSERT(x_ml->ml_address == _ptob64(s_mp->sbm_basepfn) +
18327c478bd9Sstevel@tonic-gate 				_ptob64(t_mp->sbm_slice_offset));
1833*56f33205SJonathan Adams 			ASSERT(d_ml->ml_address + d_ml->ml_size ==
18347c478bd9Sstevel@tonic-gate 				_ptob64(s_mq.last_nonrelocatable + 1));
18357c478bd9Sstevel@tonic-gate #endif
18367c478bd9Sstevel@tonic-gate 
18377c478bd9Sstevel@tonic-gate 			/*
18387c478bd9Sstevel@tonic-gate 			 * x_ml now describes only the portion of the
18397c478bd9Sstevel@tonic-gate 			 * source board that will be moved during the
18407c478bd9Sstevel@tonic-gate 			 * copy/rename operation.
18417c478bd9Sstevel@tonic-gate 			 */
18427c478bd9Sstevel@tonic-gate 			d_ml = x_ml;
18437c478bd9Sstevel@tonic-gate 		} else {
18447c478bd9Sstevel@tonic-gate 			/* use original memlist; all spans will be moved */
18457c478bd9Sstevel@tonic-gate 			d_ml = s_ml;
18467c478bd9Sstevel@tonic-gate 		}
18477c478bd9Sstevel@tonic-gate 
18487c478bd9Sstevel@tonic-gate 		/* verify target can support source memory spans. */
18497c478bd9Sstevel@tonic-gate 		if (memlist_canfit(d_ml, t_ml) == 0) {
18507c478bd9Sstevel@tonic-gate 			PR_MEM("%s: source memlist won't"
18517c478bd9Sstevel@tonic-gate 				" fit in target memlist\n", f);
18527c478bd9Sstevel@tonic-gate 			PR_MEM("%s: source memlist:\n", f);
18537c478bd9Sstevel@tonic-gate 			SBD_MEMLIST_DUMP(d_ml);
18547c478bd9Sstevel@tonic-gate 			PR_MEM("%s: target memlist:\n", f);
18557c478bd9Sstevel@tonic-gate 			SBD_MEMLIST_DUMP(t_ml);
18567c478bd9Sstevel@tonic-gate 
18577c478bd9Sstevel@tonic-gate 			continue;
18587c478bd9Sstevel@tonic-gate 		}
18597c478bd9Sstevel@tonic-gate 
18607c478bd9Sstevel@tonic-gate 		/* NOTE: the value of d_ml is not used beyond this point */
18617c478bd9Sstevel@tonic-gate 
18627c478bd9Sstevel@tonic-gate 		PR_MEM("%s: checking for no-reloc on board %d, "
18637c478bd9Sstevel@tonic-gate 			" basepfn=0x%lx, npages=%ld\n",
18647c478bd9Sstevel@tonic-gate 			f,
18657c478bd9Sstevel@tonic-gate 			t_sbp->sb_num,
18667c478bd9Sstevel@tonic-gate 			t_mp->sbm_basepfn,
18677c478bd9Sstevel@tonic-gate 			t_mp->sbm_npages);
18687c478bd9Sstevel@tonic-gate 
18697c478bd9Sstevel@tonic-gate 		rv = kphysm_del_span_query(
18707c478bd9Sstevel@tonic-gate 			t_mp->sbm_basepfn, t_mp->sbm_npages, &mq);
18717c478bd9Sstevel@tonic-gate 		if (rv != KPHYSM_OK) {
18727c478bd9Sstevel@tonic-gate 			PR_MEM("%s: kphysm_del_span_query:"
18737c478bd9Sstevel@tonic-gate 				" unexpected return value %d\n", f, rv);
18747c478bd9Sstevel@tonic-gate 
18757c478bd9Sstevel@tonic-gate 			continue;
18767c478bd9Sstevel@tonic-gate 		}
18777c478bd9Sstevel@tonic-gate 
18787c478bd9Sstevel@tonic-gate 		if (mq.nonrelocatable != 0) {
18797c478bd9Sstevel@tonic-gate 			PR_MEM("%s: candidate board %d has"
18807c478bd9Sstevel@tonic-gate 				" nonrelocatable span [0x%lx..0x%lx]\n",
18817c478bd9Sstevel@tonic-gate 				f,
18827c478bd9Sstevel@tonic-gate 				t_sbp->sb_num,
18837c478bd9Sstevel@tonic-gate 				mq.first_nonrelocatable,
18847c478bd9Sstevel@tonic-gate 				mq.last_nonrelocatable);
18857c478bd9Sstevel@tonic-gate 
18867c478bd9Sstevel@tonic-gate 			continue;
18877c478bd9Sstevel@tonic-gate 		}
18887c478bd9Sstevel@tonic-gate 
18897c478bd9Sstevel@tonic-gate #ifdef DEBUG
18907c478bd9Sstevel@tonic-gate 		/*
18917c478bd9Sstevel@tonic-gate 		 * This is a debug tool for excluding certain boards
18927c478bd9Sstevel@tonic-gate 		 * from being selected as a target board candidate.
18937c478bd9Sstevel@tonic-gate 		 * sbd_ignore_board is only tested by this driver.
18947c478bd9Sstevel@tonic-gate 		 * It must be set with adb, obp, /etc/system or your
18957c478bd9Sstevel@tonic-gate 		 * favorite debugger.
18967c478bd9Sstevel@tonic-gate 		 */
18977c478bd9Sstevel@tonic-gate 		if (sbd_ignore_board &
18987c478bd9Sstevel@tonic-gate 			(1 << (t_sbp->sb_num - 1))) {
18997c478bd9Sstevel@tonic-gate 			PR_MEM("%s: sbd_ignore_board flag set,"
19007c478bd9Sstevel@tonic-gate 				" ignoring board %d as candidate\n",
19017c478bd9Sstevel@tonic-gate 				f, t_sbp->sb_num);
19027c478bd9Sstevel@tonic-gate 			continue;
19037c478bd9Sstevel@tonic-gate 		}
19047c478bd9Sstevel@tonic-gate #endif
19057c478bd9Sstevel@tonic-gate 
19067c478bd9Sstevel@tonic-gate 		/*
19077c478bd9Sstevel@tonic-gate 		 * Make sure there is no memory overlap if this
19087c478bd9Sstevel@tonic-gate 		 * target board is used for copy-rename.
19097c478bd9Sstevel@tonic-gate 		 */
19107c478bd9Sstevel@tonic-gate 		if (sbd_check_boundaries(phys_install, s_mp, t_mp) != 0)
19117c478bd9Sstevel@tonic-gate 			continue;
19127c478bd9Sstevel@tonic-gate 
19137c478bd9Sstevel@tonic-gate 		/*
19147c478bd9Sstevel@tonic-gate 		 * Reserve excess source board memory, if any.
19157c478bd9Sstevel@tonic-gate 		 *
19167c478bd9Sstevel@tonic-gate 		 * When the number of pages on the candidate target
19177c478bd9Sstevel@tonic-gate 		 * board is less than the number of pages on the source,
19187c478bd9Sstevel@tonic-gate 		 * then some spans (clearly) of the source board's address
19197c478bd9Sstevel@tonic-gate 		 * space will not be covered by physical memory after the
19207c478bd9Sstevel@tonic-gate 		 * copy/rename completes.  The following code block
19217c478bd9Sstevel@tonic-gate 		 * schedules those spans to be deleted.
19227c478bd9Sstevel@tonic-gate 		 */
19237c478bd9Sstevel@tonic-gate 		if (t_mp->sbm_npages < s_mp->sbm_npages) {
19247c478bd9Sstevel@tonic-gate 			pfn_t pfn;
19257c478bd9Sstevel@tonic-gate 			int mlret;
19267c478bd9Sstevel@tonic-gate 
19277c478bd9Sstevel@tonic-gate 			d_ml = memlist_dup(s_ml);
19287c478bd9Sstevel@tonic-gate 			if (d_ml == NULL) {
19297c478bd9Sstevel@tonic-gate 				PR_MEM("%s: cant dup src brd memlist\n", f);
19307c478bd9Sstevel@tonic-gate 				/* TODO: should abort */
19317c478bd9Sstevel@tonic-gate 				continue;
19327c478bd9Sstevel@tonic-gate 			}
19337c478bd9Sstevel@tonic-gate 
19347c478bd9Sstevel@tonic-gate 			/* calculate base pfn relative to target board */
19357c478bd9Sstevel@tonic-gate 			pfn  = s_mp->sbm_basepfn & ~sm;
19367c478bd9Sstevel@tonic-gate 			pfn += t_mp->sbm_slice_offset;
19377c478bd9Sstevel@tonic-gate 
19387c478bd9Sstevel@tonic-gate 			/* remove span that will reside on candidate board */
19397c478bd9Sstevel@tonic-gate 			mlret = memlist_delete_span(
19407c478bd9Sstevel@tonic-gate 				_ptob64(pfn),
19417c478bd9Sstevel@tonic-gate 				_ptob64(t_mp->sbm_npages),
19427c478bd9Sstevel@tonic-gate 				&d_ml);
19437c478bd9Sstevel@tonic-gate 			PR_MEM("%s: mlret = %d\n", f, mlret);
19447c478bd9Sstevel@tonic-gate 
19457c478bd9Sstevel@tonic-gate 			PR_MEM("%s: brd %d: reserving src brd memlist:\n",
19467c478bd9Sstevel@tonic-gate 				f, s_sbp->sb_num);
19477c478bd9Sstevel@tonic-gate 			SBD_MEMLIST_DUMP(d_ml);
19487c478bd9Sstevel@tonic-gate 
19497c478bd9Sstevel@tonic-gate 			/* reserve excess spans */
19507c478bd9Sstevel@tonic-gate 			if (sbd_reserve_mem_spans(
19517c478bd9Sstevel@tonic-gate 				&s_mp->sbm_memhandle, d_ml) != 0) {
19527c478bd9Sstevel@tonic-gate 
19537c478bd9Sstevel@tonic-gate 				/* likely more non-reloc pages appeared */
19547c478bd9Sstevel@tonic-gate 				/* TODO: restart from top? */
19557c478bd9Sstevel@tonic-gate 				continue;
19567c478bd9Sstevel@tonic-gate 			}
19577c478bd9Sstevel@tonic-gate 		} else {
19587c478bd9Sstevel@tonic-gate 			/* no excess source board memory */
19597c478bd9Sstevel@tonic-gate 			d_ml = NULL;
19607c478bd9Sstevel@tonic-gate 		}
19617c478bd9Sstevel@tonic-gate 
19627c478bd9Sstevel@tonic-gate 		s_mp->sbm_flags |= SBD_MFLAG_RESERVED;
19637c478bd9Sstevel@tonic-gate 
19647c478bd9Sstevel@tonic-gate 		/*
19657c478bd9Sstevel@tonic-gate 		 * reserve all memory on target board.
19667c478bd9Sstevel@tonic-gate 		 * NOTE: source board's memhandle is used.
19677c478bd9Sstevel@tonic-gate 		 *
19687c478bd9Sstevel@tonic-gate 		 * If this succeeds (eq 0), then target selection is
19697c478bd9Sstevel@tonic-gate 		 * complete and all unwanted memory spans, both source and
19707c478bd9Sstevel@tonic-gate 		 * target, have been reserved.  Loop is terminated.
19717c478bd9Sstevel@tonic-gate 		 */
19727c478bd9Sstevel@tonic-gate 		if (sbd_reserve_mem_spans(&s_mp->sbm_memhandle, t_ml) == 0) {
19737c478bd9Sstevel@tonic-gate 			PR_MEM("%s: brd %d: target board memory reserved\n",
19747c478bd9Sstevel@tonic-gate 				f, t_sbp->sb_num);
19757c478bd9Sstevel@tonic-gate 
19767c478bd9Sstevel@tonic-gate 			/* a candidate target board is now reserved */
19777c478bd9Sstevel@tonic-gate 			t_mp->sbm_flags |= SBD_MFLAG_RESERVED;
19787c478bd9Sstevel@tonic-gate 			c_mp = t_mp;
19797c478bd9Sstevel@tonic-gate 
19807c478bd9Sstevel@tonic-gate 			/* *** EXITING LOOP *** */
19817c478bd9Sstevel@tonic-gate 			break;
19827c478bd9Sstevel@tonic-gate 		}
19837c478bd9Sstevel@tonic-gate 
19847c478bd9Sstevel@tonic-gate 		/* did not successfully reserve the target board. */
19857c478bd9Sstevel@tonic-gate 		PR_MEM("%s: could not reserve target board %d\n",
19867c478bd9Sstevel@tonic-gate 			f, t_sbp->sb_num);
19877c478bd9Sstevel@tonic-gate 
19887c478bd9Sstevel@tonic-gate 		/*
19897c478bd9Sstevel@tonic-gate 		 * NOTE: an undo of the sbd_reserve_mem_span work
19907c478bd9Sstevel@tonic-gate 		 * will happen automatically when the memhandle
19917c478bd9Sstevel@tonic-gate 		 * (s_mp->sbm_memhandle) is kphysm_del_release'd.
19927c478bd9Sstevel@tonic-gate 		 */
19937c478bd9Sstevel@tonic-gate 
19947c478bd9Sstevel@tonic-gate 		s_mp->sbm_flags &= ~SBD_MFLAG_RESERVED;
19957c478bd9Sstevel@tonic-gate 	}
19967c478bd9Sstevel@tonic-gate 
19977c478bd9Sstevel@tonic-gate 	/* clean up after memlist editing logic */
19987c478bd9Sstevel@tonic-gate 	if (x_ml != NULL)
19997c478bd9Sstevel@tonic-gate 		memlist_delete(x_ml);
20007c478bd9Sstevel@tonic-gate 
20017c478bd9Sstevel@tonic-gate 	FREESTRUCT(sets, sbd_mem_unit_t *, n_units_per_set * n_sets);
20027c478bd9Sstevel@tonic-gate 
20037c478bd9Sstevel@tonic-gate 	/*
20047c478bd9Sstevel@tonic-gate 	 * c_mp will be NULL when the entire sets[] array
20057c478bd9Sstevel@tonic-gate 	 * has been searched without reserving a target board.
20067c478bd9Sstevel@tonic-gate 	 */
20077c478bd9Sstevel@tonic-gate 	if (c_mp == NULL) {
20087c478bd9Sstevel@tonic-gate 		PR_MEM("%s: brd %d: target selection failed.\n",
20097c478bd9Sstevel@tonic-gate 			f, s_sbp->sb_num);
20107c478bd9Sstevel@tonic-gate 
20117c478bd9Sstevel@tonic-gate 		if (t_ml != NULL)
20127c478bd9Sstevel@tonic-gate 			memlist_delete(t_ml);
20137c478bd9Sstevel@tonic-gate 
20147c478bd9Sstevel@tonic-gate 		return (-1);
20157c478bd9Sstevel@tonic-gate 	}
20167c478bd9Sstevel@tonic-gate 
20177c478bd9Sstevel@tonic-gate 	PR_MEM("%s: found target board %d for source board %d\n",
20187c478bd9Sstevel@tonic-gate 		f,
20197c478bd9Sstevel@tonic-gate 		t_sbp->sb_num,
20207c478bd9Sstevel@tonic-gate 		s_sbp->sb_num);
20217c478bd9Sstevel@tonic-gate 
20227c478bd9Sstevel@tonic-gate 	s_mp->sbm_peer = c_mp;
20237c478bd9Sstevel@tonic-gate 	s_mp->sbm_flags |= SBD_MFLAG_SOURCE;
20247c478bd9Sstevel@tonic-gate 	s_mp->sbm_del_mlist = d_ml;	/* spans to be deleted, if any */
20257c478bd9Sstevel@tonic-gate 	s_mp->sbm_mlist = s_ml;
20267c478bd9Sstevel@tonic-gate 	s_mp->sbm_cm.sbdev_busy = 1;
20277c478bd9Sstevel@tonic-gate 
20287c478bd9Sstevel@tonic-gate 	c_mp->sbm_peer = s_mp;
20297c478bd9Sstevel@tonic-gate 	c_mp->sbm_flags |= SBD_MFLAG_TARGET;
20307c478bd9Sstevel@tonic-gate 	c_mp->sbm_del_mlist = t_ml;	/* spans to be deleted */
20317c478bd9Sstevel@tonic-gate 	c_mp->sbm_mlist = t_ml;
20327c478bd9Sstevel@tonic-gate 	c_mp->sbm_cm.sbdev_busy = 1;
20337c478bd9Sstevel@tonic-gate 
20347c478bd9Sstevel@tonic-gate 	s_mp->sbm_flags &= ~SBD_MFLAG_MEMRESIZE;
20357c478bd9Sstevel@tonic-gate 	if (c_mp->sbm_npages > s_mp->sbm_npages) {
20367c478bd9Sstevel@tonic-gate 		s_mp->sbm_flags |= SBD_MFLAG_MEMUPSIZE;
20377c478bd9Sstevel@tonic-gate 		PR_MEM("%s: upsize (source pgs 0x%lx < target pgs 0x%lx)\n",
20387c478bd9Sstevel@tonic-gate 			f, s_mp->sbm_npages, c_mp->sbm_npages);
20397c478bd9Sstevel@tonic-gate 	} else if (c_mp->sbm_npages < s_mp->sbm_npages) {
20407c478bd9Sstevel@tonic-gate 		s_mp->sbm_flags |= SBD_MFLAG_MEMDOWNSIZE;
20417c478bd9Sstevel@tonic-gate 		PR_MEM("%s: downsize (source pgs 0x%lx > target pgs 0x%lx)\n",
20427c478bd9Sstevel@tonic-gate 			f, s_mp->sbm_npages, c_mp->sbm_npages);
20437c478bd9Sstevel@tonic-gate 	}
20447c478bd9Sstevel@tonic-gate 
20457c478bd9Sstevel@tonic-gate 	return (0);
20467c478bd9Sstevel@tonic-gate }
20477c478bd9Sstevel@tonic-gate 
20487c478bd9Sstevel@tonic-gate int
sbd_move_memory(sbd_handle_t * hp,sbd_board_t * s_bp,sbd_board_t * t_bp)20497c478bd9Sstevel@tonic-gate sbd_move_memory(sbd_handle_t *hp, sbd_board_t *s_bp, sbd_board_t *t_bp)
20507c478bd9Sstevel@tonic-gate {
20517c478bd9Sstevel@tonic-gate 	int	ret;
20527c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
20537c478bd9Sstevel@tonic-gate 	sbderror_t	*ep = SBD_HD2ERR(hp);
20547c478bd9Sstevel@tonic-gate 
20557c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(s_bp, hp);
20567c478bd9Sstevel@tonic-gate 
20577c478bd9Sstevel@tonic-gate 	ret = sbdp_move_memory(hdp, t_bp->sb_num);
20587c478bd9Sstevel@tonic-gate 	if (ret != 0)
20597c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, ep);
20607c478bd9Sstevel@tonic-gate 
20617c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
20627c478bd9Sstevel@tonic-gate 
20637c478bd9Sstevel@tonic-gate 	return (ret);
20647c478bd9Sstevel@tonic-gate }
20657c478bd9Sstevel@tonic-gate 
20667c478bd9Sstevel@tonic-gate /*
20677c478bd9Sstevel@tonic-gate  * Memlist support.
20687c478bd9Sstevel@tonic-gate  */
20697c478bd9Sstevel@tonic-gate void
memlist_delete(struct memlist * mlist)20707c478bd9Sstevel@tonic-gate memlist_delete(struct memlist *mlist)
20717c478bd9Sstevel@tonic-gate {
20727c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
20737c478bd9Sstevel@tonic-gate 
20747c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(NULL, NULL);
20757c478bd9Sstevel@tonic-gate 
20767c478bd9Sstevel@tonic-gate 	(void) sbdp_del_memlist(hdp, mlist);
20777c478bd9Sstevel@tonic-gate 
20787c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
20797c478bd9Sstevel@tonic-gate }
20807c478bd9Sstevel@tonic-gate 
20817c478bd9Sstevel@tonic-gate struct memlist *
memlist_dup(struct memlist * mlist)20827c478bd9Sstevel@tonic-gate memlist_dup(struct memlist *mlist)
20837c478bd9Sstevel@tonic-gate {
20847c478bd9Sstevel@tonic-gate 	struct memlist *hl, *prev;
20857c478bd9Sstevel@tonic-gate 
20867c478bd9Sstevel@tonic-gate 	if (mlist == NULL)
20877c478bd9Sstevel@tonic-gate 		return (NULL);
20887c478bd9Sstevel@tonic-gate 
20897c478bd9Sstevel@tonic-gate 	prev = NULL;
20907c478bd9Sstevel@tonic-gate 	hl = NULL;
2091*56f33205SJonathan Adams 	for (; mlist; mlist = mlist->ml_next) {
20927c478bd9Sstevel@tonic-gate 		struct memlist *mp;
20937c478bd9Sstevel@tonic-gate 
20947c478bd9Sstevel@tonic-gate 		mp = memlist_get_one();
20957c478bd9Sstevel@tonic-gate 		if (mp == NULL) {
20967c478bd9Sstevel@tonic-gate 			if (hl != NULL)
20977c478bd9Sstevel@tonic-gate 				memlist_free_list(hl);
20987c478bd9Sstevel@tonic-gate 			hl = NULL;
20997c478bd9Sstevel@tonic-gate 			break;
21007c478bd9Sstevel@tonic-gate 		}
2101*56f33205SJonathan Adams 		mp->ml_address = mlist->ml_address;
2102*56f33205SJonathan Adams 		mp->ml_size = mlist->ml_size;
2103*56f33205SJonathan Adams 		mp->ml_next = NULL;
2104*56f33205SJonathan Adams 		mp->ml_prev = prev;
21057c478bd9Sstevel@tonic-gate 
21067c478bd9Sstevel@tonic-gate 		if (prev == NULL)
21077c478bd9Sstevel@tonic-gate 			hl = mp;
21087c478bd9Sstevel@tonic-gate 		else
2109*56f33205SJonathan Adams 			prev->ml_next = mp;
21107c478bd9Sstevel@tonic-gate 		prev = mp;
21117c478bd9Sstevel@tonic-gate 	}
21127c478bd9Sstevel@tonic-gate 
21137c478bd9Sstevel@tonic-gate 	return (hl);
21147c478bd9Sstevel@tonic-gate }
21157c478bd9Sstevel@tonic-gate 
21167c478bd9Sstevel@tonic-gate void
memlist_dump(struct memlist * mlist)21177c478bd9Sstevel@tonic-gate memlist_dump(struct memlist *mlist)
21187c478bd9Sstevel@tonic-gate {
21197c478bd9Sstevel@tonic-gate 	register struct memlist *ml;
21207c478bd9Sstevel@tonic-gate 
21217c478bd9Sstevel@tonic-gate 	if (mlist == NULL) {
21227c478bd9Sstevel@tonic-gate 		PR_MEM("memlist> EMPTY\n");
21237c478bd9Sstevel@tonic-gate 	} else {
2124*56f33205SJonathan Adams 		for (ml = mlist; ml; ml = ml->ml_next)
21257c478bd9Sstevel@tonic-gate 			PR_MEM("memlist> 0x%" PRIx64 " "
21267c478bd9Sstevel@tonic-gate 				"0x%" PRIx64 " \n",
2127*56f33205SJonathan Adams 				ml->ml_address, ml->ml_size);
21287c478bd9Sstevel@tonic-gate 	}
21297c478bd9Sstevel@tonic-gate }
21307c478bd9Sstevel@tonic-gate 
21317c478bd9Sstevel@tonic-gate int
memlist_intersect(struct memlist * al,struct memlist * bl)21327c478bd9Sstevel@tonic-gate memlist_intersect(struct memlist *al, struct memlist *bl)
21337c478bd9Sstevel@tonic-gate {
21347c478bd9Sstevel@tonic-gate 	uint64_t	astart, aend, bstart, bend;
21357c478bd9Sstevel@tonic-gate 
21367c478bd9Sstevel@tonic-gate 	if ((al == NULL) || (bl == NULL))
21377c478bd9Sstevel@tonic-gate 		return (0);
21387c478bd9Sstevel@tonic-gate 
2139*56f33205SJonathan Adams 	aend = al->ml_address + al->ml_size;
2140*56f33205SJonathan Adams 	bstart = bl->ml_address;
2141*56f33205SJonathan Adams 	bend = bl->ml_address + bl->ml_size;
21427c478bd9Sstevel@tonic-gate 
21437c478bd9Sstevel@tonic-gate 	while (al && bl) {
21447c478bd9Sstevel@tonic-gate 		while (al && (aend <= bstart))
2145*56f33205SJonathan Adams 			if ((al = al->ml_next) != NULL)
2146*56f33205SJonathan Adams 				aend = al->ml_address + al->ml_size;
21477c478bd9Sstevel@tonic-gate 		if (al == NULL)
21487c478bd9Sstevel@tonic-gate 			return (0);
21497c478bd9Sstevel@tonic-gate 
2150*56f33205SJonathan Adams 		if ((astart = al->ml_address) <= bstart)
21517c478bd9Sstevel@tonic-gate 			return (1);
21527c478bd9Sstevel@tonic-gate 
21537c478bd9Sstevel@tonic-gate 		while (bl && (bend <= astart))
2154*56f33205SJonathan Adams 			if ((bl = bl->ml_next) != NULL)
2155*56f33205SJonathan Adams 				bend = bl->ml_address + bl->ml_size;
21567c478bd9Sstevel@tonic-gate 		if (bl == NULL)
21577c478bd9Sstevel@tonic-gate 			return (0);
21587c478bd9Sstevel@tonic-gate 
2159*56f33205SJonathan Adams 		if ((bstart = bl->ml_address) <= astart)
21607c478bd9Sstevel@tonic-gate 			return (1);
21617c478bd9Sstevel@tonic-gate 	}
21627c478bd9Sstevel@tonic-gate 
21637c478bd9Sstevel@tonic-gate 	return (0);
21647c478bd9Sstevel@tonic-gate }
21657c478bd9Sstevel@tonic-gate 
21667c478bd9Sstevel@tonic-gate /*
21677c478bd9Sstevel@tonic-gate  * Determine whether the source memlist (s_mlist) will
21687c478bd9Sstevel@tonic-gate  * fit into the target memlist (t_mlist) in terms of
21697c478bd9Sstevel@tonic-gate  * size and holes (i.e. based on same relative base address).
21707c478bd9Sstevel@tonic-gate  */
21717c478bd9Sstevel@tonic-gate static int
memlist_canfit(struct memlist * s_mlist,struct memlist * t_mlist)21727c478bd9Sstevel@tonic-gate memlist_canfit(struct memlist *s_mlist, struct memlist *t_mlist)
21737c478bd9Sstevel@tonic-gate {
21747c478bd9Sstevel@tonic-gate 	int		rv = 0;
21757c478bd9Sstevel@tonic-gate 	uint64_t	s_basepa, t_basepa;
21767c478bd9Sstevel@tonic-gate 	struct memlist	*s_ml, *t_ml;
21777c478bd9Sstevel@tonic-gate 
21787c478bd9Sstevel@tonic-gate 	if ((s_mlist == NULL) || (t_mlist == NULL))
21797c478bd9Sstevel@tonic-gate 		return (0);
21807c478bd9Sstevel@tonic-gate 
21817c478bd9Sstevel@tonic-gate 	/*
21827c478bd9Sstevel@tonic-gate 	 * Base both memlists on common base address (0).
21837c478bd9Sstevel@tonic-gate 	 */
2184*56f33205SJonathan Adams 	s_basepa = s_mlist->ml_address;
2185*56f33205SJonathan Adams 	t_basepa = t_mlist->ml_address;
21867c478bd9Sstevel@tonic-gate 
2187*56f33205SJonathan Adams 	for (s_ml = s_mlist; s_ml; s_ml = s_ml->ml_next)
2188*56f33205SJonathan Adams 		s_ml->ml_address -= s_basepa;
21897c478bd9Sstevel@tonic-gate 
2190*56f33205SJonathan Adams 	for (t_ml = t_mlist; t_ml; t_ml = t_ml->ml_next)
2191*56f33205SJonathan Adams 		t_ml->ml_address -= t_basepa;
21927c478bd9Sstevel@tonic-gate 
21937c478bd9Sstevel@tonic-gate 	s_ml = s_mlist;
2194*56f33205SJonathan Adams 	for (t_ml = t_mlist; t_ml && s_ml; t_ml = t_ml->ml_next) {
21957c478bd9Sstevel@tonic-gate 		uint64_t	s_start, s_end;
21967c478bd9Sstevel@tonic-gate 		uint64_t	t_start, t_end;
21977c478bd9Sstevel@tonic-gate 
2198*56f33205SJonathan Adams 		t_start = t_ml->ml_address;
2199*56f33205SJonathan Adams 		t_end = t_start + t_ml->ml_size;
22007c478bd9Sstevel@tonic-gate 
2201*56f33205SJonathan Adams 		for (; s_ml; s_ml = s_ml->ml_next) {
2202*56f33205SJonathan Adams 			s_start = s_ml->ml_address;
2203*56f33205SJonathan Adams 			s_end = s_start + s_ml->ml_size;
22047c478bd9Sstevel@tonic-gate 
22057c478bd9Sstevel@tonic-gate 			if ((s_start < t_start) || (s_end > t_end))
22067c478bd9Sstevel@tonic-gate 				break;
22077c478bd9Sstevel@tonic-gate 		}
22087c478bd9Sstevel@tonic-gate 	}
22097c478bd9Sstevel@tonic-gate 	/*
22107c478bd9Sstevel@tonic-gate 	 * If we ran out of source memlist chunks that mean
22117c478bd9Sstevel@tonic-gate 	 * we found a home for all of them.
22127c478bd9Sstevel@tonic-gate 	 */
22137c478bd9Sstevel@tonic-gate 	if (s_ml == NULL)
22147c478bd9Sstevel@tonic-gate 		rv = 1;
22157c478bd9Sstevel@tonic-gate 
22167c478bd9Sstevel@tonic-gate 	/*
22177c478bd9Sstevel@tonic-gate 	 * Need to add base addresses back since memlists
22187c478bd9Sstevel@tonic-gate 	 * are probably in use by caller.
22197c478bd9Sstevel@tonic-gate 	 */
2220*56f33205SJonathan Adams 	for (s_ml = s_mlist; s_ml; s_ml = s_ml->ml_next)
2221*56f33205SJonathan Adams 		s_ml->ml_address += s_basepa;
22227c478bd9Sstevel@tonic-gate 
2223*56f33205SJonathan Adams 	for (t_ml = t_mlist; t_ml; t_ml = t_ml->ml_next)
2224*56f33205SJonathan Adams 		t_ml->ml_address += t_basepa;
22257c478bd9Sstevel@tonic-gate 
22267c478bd9Sstevel@tonic-gate 	return (rv);
22277c478bd9Sstevel@tonic-gate }
22287c478bd9Sstevel@tonic-gate 
22297c478bd9Sstevel@tonic-gate void
sbd_attach_mem(sbd_handle_t * hp,sbderror_t * ep)22307c478bd9Sstevel@tonic-gate sbd_attach_mem(sbd_handle_t *hp, sbderror_t *ep)
22317c478bd9Sstevel@tonic-gate {
22327c478bd9Sstevel@tonic-gate 	sbd_mem_unit_t	*mp;
22337c478bd9Sstevel@tonic-gate 	dev_info_t	*dip;
22347c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
22357c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
22367c478bd9Sstevel@tonic-gate 	int		err, unit;
22377c478bd9Sstevel@tonic-gate 	struct memlist	*ml, *mc;
22387c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_attach_mem";
22397c478bd9Sstevel@tonic-gate 	int		i;
22407c478bd9Sstevel@tonic-gate 
22417c478bd9Sstevel@tonic-gate 	PR_MEM("%s...\n", f);
22427c478bd9Sstevel@tonic-gate 
22437c478bd9Sstevel@tonic-gate 	/*
22447c478bd9Sstevel@tonic-gate 	 * all four cpus have to be attached before
22457c478bd9Sstevel@tonic-gate 	 * configuring mem
22467c478bd9Sstevel@tonic-gate 	 */
22477c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
22487c478bd9Sstevel@tonic-gate 		sbd_cpu_unit_t	*cpup;
22497c478bd9Sstevel@tonic-gate 		struct cpu	*cp;
22507c478bd9Sstevel@tonic-gate 
22517c478bd9Sstevel@tonic-gate 		if (!SBD_DEV_IS_PRESENT(sbp, SBD_COMP_CPU, i))
22527c478bd9Sstevel@tonic-gate 			continue;
22537c478bd9Sstevel@tonic-gate 
22547c478bd9Sstevel@tonic-gate 		if (!SBD_DEV_IS_ATTACHED(sbp, SBD_COMP_CPU, i))
22557c478bd9Sstevel@tonic-gate 			goto error;
22567c478bd9Sstevel@tonic-gate 
22577c478bd9Sstevel@tonic-gate 		cpup = SBD_GET_BOARD_CPUUNIT(sbp, i);
22587c478bd9Sstevel@tonic-gate 
22597c478bd9Sstevel@tonic-gate 		if (cpup == NULL)
22607c478bd9Sstevel@tonic-gate 			goto error;
22617c478bd9Sstevel@tonic-gate 
22627c478bd9Sstevel@tonic-gate 		mutex_enter(&cpu_lock);
22637c478bd9Sstevel@tonic-gate 		cp = cpu_get(cpup->sbc_cpu_id);
22647c478bd9Sstevel@tonic-gate 		if (cp == NULL) {
22657c478bd9Sstevel@tonic-gate 			mutex_exit(&cpu_lock);
22667c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
22677c478bd9Sstevel@tonic-gate 			    "sbd:%s: cpu_get failed for cpu %d",
22687c478bd9Sstevel@tonic-gate 			    f, cpup->sbc_cpu_id);
22697c478bd9Sstevel@tonic-gate 			goto error;
22707c478bd9Sstevel@tonic-gate 		}
22717c478bd9Sstevel@tonic-gate 		if (cpu_is_poweredoff(cp)) {
22727c478bd9Sstevel@tonic-gate 			mutex_exit(&cpu_lock);
22737c478bd9Sstevel@tonic-gate 			goto error;
22747c478bd9Sstevel@tonic-gate 		}
22757c478bd9Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
22767c478bd9Sstevel@tonic-gate 		continue;
22777c478bd9Sstevel@tonic-gate 
22787c478bd9Sstevel@tonic-gate error:
22797c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(ep, ESBD_CPUONLINE);
22807c478bd9Sstevel@tonic-gate 		SBD_SET_ERRSTR(ep, sbp->sb_mempath[i]);
22817c478bd9Sstevel@tonic-gate 		(void) sbd_set_err_in_hdl(hp, ep);
22827c478bd9Sstevel@tonic-gate 		return;
22837c478bd9Sstevel@tonic-gate 	}
22847c478bd9Sstevel@tonic-gate 
22857c478bd9Sstevel@tonic-gate 	dip = *(sbp->sb_devlist[NIX(SBD_COMP_MEM)]);
22867c478bd9Sstevel@tonic-gate 
22877c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
22887c478bd9Sstevel@tonic-gate 	unit = sbdp_get_unit_num(hdp, dip);
22897c478bd9Sstevel@tonic-gate 	if (unit < 0) {
22907c478bd9Sstevel@tonic-gate 		SBD_GET_PERR(hdp->h_err, ep);
22917c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
22927c478bd9Sstevel@tonic-gate 		return;
22937c478bd9Sstevel@tonic-gate 	}
22947c478bd9Sstevel@tonic-gate 
22957c478bd9Sstevel@tonic-gate 	ASSERT(sbp->sb_mempath[unit] != NULL);
22967c478bd9Sstevel@tonic-gate 	ASSERT(e_ddi_branch_held(dip));
22977c478bd9Sstevel@tonic-gate 
22987c478bd9Sstevel@tonic-gate 	(void) ddi_pathname(dip, sbp->sb_mempath[unit]);
22997c478bd9Sstevel@tonic-gate 
23007c478bd9Sstevel@tonic-gate 	mp = SBD_GET_BOARD_MEMUNIT(sbp, unit);
23017c478bd9Sstevel@tonic-gate 
23027c478bd9Sstevel@tonic-gate 	ml = sbd_get_memlist(mp, ep);
23037c478bd9Sstevel@tonic-gate 	if (ml == NULL) {
23047c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
23057c478bd9Sstevel@tonic-gate 			"sbd:%s: failed to get memlist for "
23067c478bd9Sstevel@tonic-gate 			"board %d", f, sbp->sb_num);
23077c478bd9Sstevel@tonic-gate 		/*
23087c478bd9Sstevel@tonic-gate 		 * Need to record an error and return.
23097c478bd9Sstevel@tonic-gate 		 */
23107c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(ep, ESBD_MEMFAIL);
23117c478bd9Sstevel@tonic-gate 		SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]);
23127c478bd9Sstevel@tonic-gate 		sbd_release_sbdp_handle(hdp);
23137c478bd9Sstevel@tonic-gate 		return;
23147c478bd9Sstevel@tonic-gate 	}
23157c478bd9Sstevel@tonic-gate 
23167c478bd9Sstevel@tonic-gate 	SBD_MEMLIST_DUMP(ml);
23177c478bd9Sstevel@tonic-gate 	err = 0;
2318*56f33205SJonathan Adams 	for (mc = ml; mc; mc = mc->ml_next) {
23197c478bd9Sstevel@tonic-gate 		update_membounds_t umb;
23207c478bd9Sstevel@tonic-gate 		pfn_t	base;
23217c478bd9Sstevel@tonic-gate 		pgcnt_t npgs;
23227c478bd9Sstevel@tonic-gate 
2323*56f33205SJonathan Adams 		base = (pfn_t)(mc->ml_address >> PAGESHIFT);
2324*56f33205SJonathan Adams 		npgs = (pgcnt_t)(mc->ml_size >> PAGESHIFT);
23257c478bd9Sstevel@tonic-gate 
23267c478bd9Sstevel@tonic-gate 		umb.u_board = sbp->sb_num;
23277c478bd9Sstevel@tonic-gate 		umb.u_base = (uint64_t)base << MMU_PAGESHIFT;
23287c478bd9Sstevel@tonic-gate 		umb.u_len = (uint64_t)npgs << MMU_PAGESHIFT;
23297c478bd9Sstevel@tonic-gate 
23307c478bd9Sstevel@tonic-gate 		lgrp_plat_config(LGRP_CONFIG_MEM_ADD, (uintptr_t)&umb);
23317c478bd9Sstevel@tonic-gate 		err = kphysm_add_memory_dynamic(base, npgs);
23327c478bd9Sstevel@tonic-gate 
23337c478bd9Sstevel@tonic-gate 		if (err != KPHYSM_OK) {
23347c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
23357c478bd9Sstevel@tonic-gate 			    "%s: kphysm_add_memory_dynamic fail %d", f, err);
23367c478bd9Sstevel@tonic-gate 
23377c478bd9Sstevel@tonic-gate 			/* translate kphysm error */
23387c478bd9Sstevel@tonic-gate 			switch (err) {
23397c478bd9Sstevel@tonic-gate 			case KPHYSM_ERESOURCE:
23407c478bd9Sstevel@tonic-gate 				err = ESBD_NOMEM;
23417c478bd9Sstevel@tonic-gate 				break;
23427c478bd9Sstevel@tonic-gate 
23437c478bd9Sstevel@tonic-gate 			case KPHYSM_EFAULT:
23447c478bd9Sstevel@tonic-gate 				err = ESBD_FAULT;
23457c478bd9Sstevel@tonic-gate 				break;
23467c478bd9Sstevel@tonic-gate 
23477c478bd9Sstevel@tonic-gate 			default:
23487c478bd9Sstevel@tonic-gate 				err = ESBD_INVAL;
23497c478bd9Sstevel@tonic-gate 				break;
23507c478bd9Sstevel@tonic-gate 			}
23517c478bd9Sstevel@tonic-gate 			break;
23527c478bd9Sstevel@tonic-gate 		}
23537c478bd9Sstevel@tonic-gate 
235485f58038Sdp78419 		err = kcage_range_add(base, npgs, KCAGE_DOWN);
23557c478bd9Sstevel@tonic-gate 		if (err != 0) {
23567c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
23577c478bd9Sstevel@tonic-gate 			    "%s: kcage_range_add fail %d", f, err);
23587c478bd9Sstevel@tonic-gate 
23597c478bd9Sstevel@tonic-gate 			/* Translate kcage error. */
23607c478bd9Sstevel@tonic-gate 			switch (err) {
23617c478bd9Sstevel@tonic-gate 			case ENOMEM:
23627c478bd9Sstevel@tonic-gate 				err = ESBD_NOMEM;
23637c478bd9Sstevel@tonic-gate 				break;
23647c478bd9Sstevel@tonic-gate 			default:
23657c478bd9Sstevel@tonic-gate 				err = ESBD_INVAL;
23667c478bd9Sstevel@tonic-gate 				break;
23677c478bd9Sstevel@tonic-gate 			}
23687c478bd9Sstevel@tonic-gate 			break;
23697c478bd9Sstevel@tonic-gate 		}
2370*56f33205SJonathan Adams 		(void) sbdp_mem_add_span(hdp, mc->ml_address, mc->ml_size);
23717c478bd9Sstevel@tonic-gate 	}
23727c478bd9Sstevel@tonic-gate 
23737c478bd9Sstevel@tonic-gate 	if (err != 0) {
23747c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(ep, err);
23757c478bd9Sstevel@tonic-gate 		SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]);
23767c478bd9Sstevel@tonic-gate 	}
23777c478bd9Sstevel@tonic-gate 
23787c478bd9Sstevel@tonic-gate 	memlist_delete(ml);
23797c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
23807c478bd9Sstevel@tonic-gate 
23817c478bd9Sstevel@tonic-gate 	/*
23827c478bd9Sstevel@tonic-gate 	 * Now attach all mem devinfo nodes to the device tree.
23837c478bd9Sstevel@tonic-gate 	 */
23847c478bd9Sstevel@tonic-gate 	for (i = 0; i < SBD_NUM_MC_PER_BOARD; i++) {
23857c478bd9Sstevel@tonic-gate 		if (mp->sbm_dip[i] == NULL)
23867c478bd9Sstevel@tonic-gate 			continue;
23877c478bd9Sstevel@tonic-gate 		ASSERT(e_ddi_branch_held(mp->sbm_dip[i]));
23887c478bd9Sstevel@tonic-gate 		if (e_ddi_branch_configure(mp->sbm_dip[i], NULL, 0) &&
23897c478bd9Sstevel@tonic-gate 		    SBD_GET_ERR(ep) == 0) {
23907c478bd9Sstevel@tonic-gate 			SBD_SET_ERR(ep, ESBD_INVAL);
23917c478bd9Sstevel@tonic-gate 			SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]);
23927c478bd9Sstevel@tonic-gate 		}
23937c478bd9Sstevel@tonic-gate 	}
23947c478bd9Sstevel@tonic-gate }
23957c478bd9Sstevel@tonic-gate 
23967c478bd9Sstevel@tonic-gate typedef struct {
23977c478bd9Sstevel@tonic-gate 	kcondvar_t cond;
23987c478bd9Sstevel@tonic-gate 	kmutex_t lock;
23997c478bd9Sstevel@tonic-gate 	int error;
24007c478bd9Sstevel@tonic-gate 	int done;
24017c478bd9Sstevel@tonic-gate } sbd_release_mem_sync_t;
24027c478bd9Sstevel@tonic-gate 
24037c478bd9Sstevel@tonic-gate /*
24047c478bd9Sstevel@tonic-gate  * When we reach here the memory being drained should have
24057c478bd9Sstevel@tonic-gate  * already been reserved in sbd_pre_release_mem().
24067c478bd9Sstevel@tonic-gate  * Our only task here is to kick off the "drain".
24077c478bd9Sstevel@tonic-gate  * Returns -1 when error encountered or zero for success.
24087c478bd9Sstevel@tonic-gate  */
24097c478bd9Sstevel@tonic-gate int
sbd_release_mem(sbd_handle_t * hp,dev_info_t * dip,int unit)24107c478bd9Sstevel@tonic-gate sbd_release_mem(sbd_handle_t *hp, dev_info_t *dip, int unit)
24117c478bd9Sstevel@tonic-gate {
24127c478bd9Sstevel@tonic-gate 	memhandle_t	mh;
24137c478bd9Sstevel@tonic-gate 	int		err;
24147c478bd9Sstevel@tonic-gate 	int		cancel_flag = 0;
24157c478bd9Sstevel@tonic-gate 	int		e_code = 0;
24167c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
24177c478bd9Sstevel@tonic-gate 	sbd_release_mem_sync_t rms;
24187c478bd9Sstevel@tonic-gate 	static fn_t	f = "sbd_release_mem";
24197c478bd9Sstevel@tonic-gate 
24207c478bd9Sstevel@tonic-gate 	/*
24217c478bd9Sstevel@tonic-gate 	 * If this node has a scheduled memory delete operation,
24227c478bd9Sstevel@tonic-gate 	 * it will have a memhandle.  If it does have a memhandle (the
24237c478bd9Sstevel@tonic-gate 	 * return value of sbd_get_memhandle is zero when true),
24247c478bd9Sstevel@tonic-gate 	 * then perform the delete.
24257c478bd9Sstevel@tonic-gate 	 */
24267c478bd9Sstevel@tonic-gate 
24277c478bd9Sstevel@tonic-gate 	if ((cancel_flag = sbd_get_memhandle(hp, dip, &mh)) != 0) {
24287c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s: couldn't get the memhandle\n", f);
24297c478bd9Sstevel@tonic-gate 		return (cancel_flag);
24307c478bd9Sstevel@tonic-gate 	}
24317c478bd9Sstevel@tonic-gate 
24327c478bd9Sstevel@tonic-gate 	bzero((void *) &rms, sizeof (rms));
24337c478bd9Sstevel@tonic-gate 
24347c478bd9Sstevel@tonic-gate 	mutex_init(&rms.lock, NULL, MUTEX_DRIVER, NULL);
24357c478bd9Sstevel@tonic-gate 	cv_init(&rms.cond, NULL, CV_DRIVER, NULL);
24367c478bd9Sstevel@tonic-gate 
24377c478bd9Sstevel@tonic-gate 	mutex_enter(&rms.lock);
24387c478bd9Sstevel@tonic-gate 	err = kphysm_del_start(mh, sbd_release_memory_done, (void *) &rms);
24397c478bd9Sstevel@tonic-gate 	if (err == KPHYSM_OK) {
24407c478bd9Sstevel@tonic-gate 		/* wait for completion */
24417c478bd9Sstevel@tonic-gate 		while (!rms.done) {
24427c478bd9Sstevel@tonic-gate 			if (cancel_flag) {
24437c478bd9Sstevel@tonic-gate 				/* previously canceled */
24447c478bd9Sstevel@tonic-gate 				cv_wait(&rms.cond, &rms.lock);
24457c478bd9Sstevel@tonic-gate 			} else if (cv_wait_sig(&rms.cond, &rms.lock) == 0) {
24467c478bd9Sstevel@tonic-gate 				/* interrupted: cancel and wait */
24477c478bd9Sstevel@tonic-gate 				cancel_flag = -1;
24487c478bd9Sstevel@tonic-gate 				(void) kphysm_del_cancel(mh);
24497c478bd9Sstevel@tonic-gate 			}
24507c478bd9Sstevel@tonic-gate 		}
24517c478bd9Sstevel@tonic-gate 		/* get the result of the memory delete operation */
24527c478bd9Sstevel@tonic-gate 		err = rms.error;
24537c478bd9Sstevel@tonic-gate 	} else {
24547c478bd9Sstevel@tonic-gate 		(void) kphysm_del_release(mh);
24557c478bd9Sstevel@tonic-gate 	}
24567c478bd9Sstevel@tonic-gate 
24577c478bd9Sstevel@tonic-gate 	mutex_exit(&rms.lock);
24587c478bd9Sstevel@tonic-gate 
24597c478bd9Sstevel@tonic-gate 	cv_destroy(&rms.cond);
24607c478bd9Sstevel@tonic-gate 	mutex_destroy(&rms.lock);
24617c478bd9Sstevel@tonic-gate 
24627c478bd9Sstevel@tonic-gate 	if (err != KPHYSM_OK) {
24637c478bd9Sstevel@tonic-gate 		switch (err) {
24647c478bd9Sstevel@tonic-gate 			case KPHYSM_ENOWORK:
24657c478bd9Sstevel@tonic-gate 				e_code = ESBD_NOERROR;
24667c478bd9Sstevel@tonic-gate 				break;
24677c478bd9Sstevel@tonic-gate 
24687c478bd9Sstevel@tonic-gate 			case KPHYSM_EHANDLE:
24697c478bd9Sstevel@tonic-gate 			case KPHYSM_ESEQUENCE:
24707c478bd9Sstevel@tonic-gate 				e_code = ESBD_INTERNAL;
24717c478bd9Sstevel@tonic-gate 				break;
24727c478bd9Sstevel@tonic-gate 
24737c478bd9Sstevel@tonic-gate 			case KPHYSM_ENOTVIABLE:
24747c478bd9Sstevel@tonic-gate 				e_code = ESBD_MEM_NOTVIABLE;
24757c478bd9Sstevel@tonic-gate 				break;
24767c478bd9Sstevel@tonic-gate 
24777c478bd9Sstevel@tonic-gate 			case KPHYSM_EREFUSED:
24787c478bd9Sstevel@tonic-gate 				e_code = ESBD_MEM_REFUSED;
24797c478bd9Sstevel@tonic-gate 				break;
24807c478bd9Sstevel@tonic-gate 
24817c478bd9Sstevel@tonic-gate 			case KPHYSM_ENONRELOC:
24827c478bd9Sstevel@tonic-gate 				e_code = ESBD_MEM_NONRELOC;
24837c478bd9Sstevel@tonic-gate 				break;
24847c478bd9Sstevel@tonic-gate 
24857c478bd9Sstevel@tonic-gate 			case KPHYSM_ECANCELLED:
24867c478bd9Sstevel@tonic-gate 				e_code = ESBD_MEM_CANCELLED;
24877c478bd9Sstevel@tonic-gate 				break;
24887c478bd9Sstevel@tonic-gate 
24897c478bd9Sstevel@tonic-gate 			case KPHYSM_ERESOURCE:
24907c478bd9Sstevel@tonic-gate 				e_code = ESBD_MEMFAIL;
24917c478bd9Sstevel@tonic-gate 				break;
24927c478bd9Sstevel@tonic-gate 
24937c478bd9Sstevel@tonic-gate 			default:
24947c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "sbd:%s:"
24957c478bd9Sstevel@tonic-gate 					" unexpected kphysm error code %d,"
24967c478bd9Sstevel@tonic-gate 					" dip 0x%p",
24977c478bd9Sstevel@tonic-gate 					f, err, (void *)dip);
24987c478bd9Sstevel@tonic-gate 
24997c478bd9Sstevel@tonic-gate 				e_code = ESBD_IO;
25007c478bd9Sstevel@tonic-gate 				break;
25017c478bd9Sstevel@tonic-gate 		}
25027c478bd9Sstevel@tonic-gate 
25037c478bd9Sstevel@tonic-gate 		if (e_code != 0) {
25047c478bd9Sstevel@tonic-gate 			cancel_flag = -1;
25057c478bd9Sstevel@tonic-gate 			SBD_SET_ERR(SBD_HD2ERR(hp), e_code);
25067c478bd9Sstevel@tonic-gate 			SBD_SET_ERRSTR(SBD_HD2ERR(hp), sbp->sb_mempath[unit]);
25077c478bd9Sstevel@tonic-gate 		}
25087c478bd9Sstevel@tonic-gate 	}
25097c478bd9Sstevel@tonic-gate 
25107c478bd9Sstevel@tonic-gate 	return (cancel_flag);
25117c478bd9Sstevel@tonic-gate }
25127c478bd9Sstevel@tonic-gate 
25137c478bd9Sstevel@tonic-gate /*
25147c478bd9Sstevel@tonic-gate  * Memory has been logically removed by the time this routine is called.
25157c478bd9Sstevel@tonic-gate  */
25167c478bd9Sstevel@tonic-gate void
sbd_release_memory_done(void * arg,int error)25177c478bd9Sstevel@tonic-gate sbd_release_memory_done(void *arg, int error)
25187c478bd9Sstevel@tonic-gate {
25197c478bd9Sstevel@tonic-gate 	sbd_release_mem_sync_t *ds = arg;
25207c478bd9Sstevel@tonic-gate 
25217c478bd9Sstevel@tonic-gate 	mutex_enter(&ds->lock);
25227c478bd9Sstevel@tonic-gate 	ds->error = error;
25237c478bd9Sstevel@tonic-gate 	ds->done = 1;
25247c478bd9Sstevel@tonic-gate 	cv_signal(&ds->cond);
25257c478bd9Sstevel@tonic-gate 	mutex_exit(&ds->lock);
25267c478bd9Sstevel@tonic-gate }
25277c478bd9Sstevel@tonic-gate 
25287c478bd9Sstevel@tonic-gate /*
25297c478bd9Sstevel@tonic-gate  * If detaching node contains memory that is "non-permanent"
25307c478bd9Sstevel@tonic-gate  * then the memory adr's are simply cleared.  If the memory
25317c478bd9Sstevel@tonic-gate  * is non-relocatable, then do a copy-rename.
25327c478bd9Sstevel@tonic-gate  */
25337c478bd9Sstevel@tonic-gate int
sbd_detach_memory(sbd_handle_t * hp,sbderror_t * ep,sbd_mem_unit_t * s_mp,int unit)25347c478bd9Sstevel@tonic-gate sbd_detach_memory(sbd_handle_t *hp, sbderror_t *ep, sbd_mem_unit_t *s_mp,
25357c478bd9Sstevel@tonic-gate 	int unit)
25367c478bd9Sstevel@tonic-gate {
25377c478bd9Sstevel@tonic-gate 	int			rv;
25387c478bd9Sstevel@tonic-gate 	sbd_mem_unit_t		*t_mp;
25397c478bd9Sstevel@tonic-gate 	sbd_istate_t		state;
25407c478bd9Sstevel@tonic-gate 	sbdp_handle_t		*hdp;
25417c478bd9Sstevel@tonic-gate 	sbd_board_t 		*sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp;
25427c478bd9Sstevel@tonic-gate 	sbd_board_t		*tbp;
25437c478bd9Sstevel@tonic-gate 	static fn_t		f = "sbd_detach_memory";
25447c478bd9Sstevel@tonic-gate 
25457c478bd9Sstevel@tonic-gate 	PR_MEM("%s...\n", f);
25467c478bd9Sstevel@tonic-gate 
25477c478bd9Sstevel@tonic-gate 	/* lookup target mem unit and target board structure, if any */
25487c478bd9Sstevel@tonic-gate 	if (s_mp->sbm_flags & SBD_MFLAG_SOURCE) {
25497c478bd9Sstevel@tonic-gate 		t_mp = s_mp->sbm_peer;
25507c478bd9Sstevel@tonic-gate 		ASSERT(t_mp != NULL);
25517c478bd9Sstevel@tonic-gate 		ASSERT(t_mp->sbm_peer == s_mp);
25527c478bd9Sstevel@tonic-gate 		tbp = (sbd_board_t *)t_mp->sbm_cm.sbdev_sbp;
25537c478bd9Sstevel@tonic-gate 	} else {
25547c478bd9Sstevel@tonic-gate 		t_mp = NULL;
25557c478bd9Sstevel@tonic-gate 	}
25567c478bd9Sstevel@tonic-gate 
25577c478bd9Sstevel@tonic-gate 	/* verify mem unit's state is UNREFERENCED */
25587c478bd9Sstevel@tonic-gate 	state = s_mp->sbm_cm.sbdev_state;
25597c478bd9Sstevel@tonic-gate 	if (state != SBD_STATE_UNREFERENCED) {
25607c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s: invalid state transition for"
25617c478bd9Sstevel@tonic-gate 			" mem-unit (%d.%d)",
25627c478bd9Sstevel@tonic-gate 			f,
25637c478bd9Sstevel@tonic-gate 			sbp->sb_num,
25647c478bd9Sstevel@tonic-gate 			s_mp->sbm_cm.sbdev_unum);
25657c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(ep, ESBD_STATE);
25667c478bd9Sstevel@tonic-gate 		SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]);
25677c478bd9Sstevel@tonic-gate 		return (-1);
25687c478bd9Sstevel@tonic-gate 	}
25697c478bd9Sstevel@tonic-gate 
25707c478bd9Sstevel@tonic-gate 	/* verify target mem unit's state is UNREFERENCED, if any */
25717c478bd9Sstevel@tonic-gate 	if (t_mp != NULL) {
25727c478bd9Sstevel@tonic-gate 		state = t_mp->sbm_cm.sbdev_state;
25737c478bd9Sstevel@tonic-gate 		if (state != SBD_STATE_UNREFERENCED) {
25747c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s: invalid state transition for"
25757c478bd9Sstevel@tonic-gate 				" target mem-unit (%d.%d)",
25767c478bd9Sstevel@tonic-gate 				f,
25777c478bd9Sstevel@tonic-gate 				tbp->sb_num,
25787c478bd9Sstevel@tonic-gate 				t_mp->sbm_cm.sbdev_unum);
25797c478bd9Sstevel@tonic-gate 			SBD_SET_ERR(ep, ESBD_STATE);
25807c478bd9Sstevel@tonic-gate 			SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]);
25817c478bd9Sstevel@tonic-gate 			return (-1);
25827c478bd9Sstevel@tonic-gate 		}
25837c478bd9Sstevel@tonic-gate 	}
25847c478bd9Sstevel@tonic-gate 
25857c478bd9Sstevel@tonic-gate 	/*
25867c478bd9Sstevel@tonic-gate 	 * Displacement flush all ecaches in the system.
25877c478bd9Sstevel@tonic-gate 	 * That's the fastest way to remove all cache references
25887c478bd9Sstevel@tonic-gate 	 * to the detaching memory.
25897c478bd9Sstevel@tonic-gate 	 */
25907c478bd9Sstevel@tonic-gate 	xc_all(sbd_flush_ecache, 0, 0);
25917c478bd9Sstevel@tonic-gate 
25927c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
25937c478bd9Sstevel@tonic-gate 
25947c478bd9Sstevel@tonic-gate 	/*
25957c478bd9Sstevel@tonic-gate 	 * If there is no target board (no copy/rename was needed), then
25967c478bd9Sstevel@tonic-gate 	 * we're done!
25977c478bd9Sstevel@tonic-gate 	 */
25987c478bd9Sstevel@tonic-gate 	if (t_mp == NULL) {
25997c478bd9Sstevel@tonic-gate 		/*
26007c478bd9Sstevel@tonic-gate 		 * Reprogram interconnect hardware and disable
26017c478bd9Sstevel@tonic-gate 		 * memory controllers for memory node that's going away.
26027c478bd9Sstevel@tonic-gate 		 */
26037c478bd9Sstevel@tonic-gate 
26047c478bd9Sstevel@tonic-gate 		rv = sbdphw_disable_memctrl(hdp, s_mp->sbm_cm.sbdev_dip);
26057c478bd9Sstevel@tonic-gate 		if (rv) {
26067c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
26077c478bd9Sstevel@tonic-gate 				"%s: failed to deprogram mem-unit (%d.%d),"
26087c478bd9Sstevel@tonic-gate 				" dip 0x%p",
26097c478bd9Sstevel@tonic-gate 				f,
26107c478bd9Sstevel@tonic-gate 				sbp->sb_num,
26117c478bd9Sstevel@tonic-gate 				s_mp->sbm_cm.sbdev_unum,
26127c478bd9Sstevel@tonic-gate 				(void *)s_mp->sbm_cm.sbdev_dip);
26137c478bd9Sstevel@tonic-gate 			/*
26147c478bd9Sstevel@tonic-gate 			 * Make sure we don't rewrite an sbdp error
26157c478bd9Sstevel@tonic-gate 			 */
26167c478bd9Sstevel@tonic-gate 			if (SBD_GET_ERR(ep) != 0) {
26177c478bd9Sstevel@tonic-gate 				SBD_SET_ERR(ep, ESBD_HW_PROGRAM);
26187c478bd9Sstevel@tonic-gate 				SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]);
26197c478bd9Sstevel@tonic-gate 			}
26207c478bd9Sstevel@tonic-gate 		}
26217c478bd9Sstevel@tonic-gate 	} else {
26227c478bd9Sstevel@tonic-gate 		rv = sbd_move_memory(hp, sbp, tbp);
26237c478bd9Sstevel@tonic-gate 		if (rv) {
26247c478bd9Sstevel@tonic-gate 			int i;
26257c478bd9Sstevel@tonic-gate 
26267c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s: failed to move memory"
26277c478bd9Sstevel@tonic-gate 				" from board %d to board %d",
26287c478bd9Sstevel@tonic-gate 				f,
26297c478bd9Sstevel@tonic-gate 				sbp->sb_num,
26307c478bd9Sstevel@tonic-gate 				tbp->sb_num);
26317c478bd9Sstevel@tonic-gate 			/*
26327c478bd9Sstevel@tonic-gate 			 * Make sure we don't rewrite an sbdp error
26337c478bd9Sstevel@tonic-gate 			 */
26347c478bd9Sstevel@tonic-gate 			if (SBD_GET_ERR(ep) != 0) {
26357c478bd9Sstevel@tonic-gate 				SBD_SET_ERR(ep, ESBD_INTERNAL);
26367c478bd9Sstevel@tonic-gate 				SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]);
26377c478bd9Sstevel@tonic-gate 			}
26387c478bd9Sstevel@tonic-gate 			/*
26397c478bd9Sstevel@tonic-gate 			 * If we failed here, it means that the target board's
26407c478bd9Sstevel@tonic-gate 			 * memory has been unconfigured.  We need to configure
26417c478bd9Sstevel@tonic-gate 			 * it back
26427c478bd9Sstevel@tonic-gate 			 */
26437c478bd9Sstevel@tonic-gate 			for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
26447c478bd9Sstevel@tonic-gate 				int		unit;
26457c478bd9Sstevel@tonic-gate 				dev_info_t	*dip;
26467c478bd9Sstevel@tonic-gate 				dev_info_t	**devlist;
26477c478bd9Sstevel@tonic-gate 
26487c478bd9Sstevel@tonic-gate 
26497c478bd9Sstevel@tonic-gate 				devlist = tbp->sb_devlist[NIX(SBD_COMP_MEM)];
26507c478bd9Sstevel@tonic-gate 				dip = devlist[i];
26517c478bd9Sstevel@tonic-gate 				sbd_reset_error_sbdph(hdp);
26527c478bd9Sstevel@tonic-gate 				unit = sbdp_get_unit_num(hdp, dip);
26537c478bd9Sstevel@tonic-gate 
26547c478bd9Sstevel@tonic-gate 				/*
26557c478bd9Sstevel@tonic-gate 				 * We already saved the error that created
26567c478bd9Sstevel@tonic-gate 				 * this mess.  If we fail, make sure not
26577c478bd9Sstevel@tonic-gate 				 * to overwrite the original error
26587c478bd9Sstevel@tonic-gate 				 */
26597c478bd9Sstevel@tonic-gate 				if (unit == -1) {
26607c478bd9Sstevel@tonic-gate 					continue;
26617c478bd9Sstevel@tonic-gate 				}
26627c478bd9Sstevel@tonic-gate 				if (sbd_cancel_mem(hp, unit) != 0)
26637c478bd9Sstevel@tonic-gate 					continue;
26647c478bd9Sstevel@tonic-gate 
26657c478bd9Sstevel@tonic-gate 				t_mp->sbm_flags = 0;
26667c478bd9Sstevel@tonic-gate 				/*
26677c478bd9Sstevel@tonic-gate 				 * clean up
26687c478bd9Sstevel@tonic-gate 				 */
26697c478bd9Sstevel@tonic-gate 				sbd_mem_cleanup(s_mp, t_mp, ep);
26707c478bd9Sstevel@tonic-gate 				if (s_mp->sbm_mlist) {
26717c478bd9Sstevel@tonic-gate 					memlist_delete(s_mp->sbm_mlist);
26727c478bd9Sstevel@tonic-gate 					s_mp->sbm_mlist = NULL;
26737c478bd9Sstevel@tonic-gate 				}
26747c478bd9Sstevel@tonic-gate 
26757c478bd9Sstevel@tonic-gate 				SBD_DEVICE_TRANSITION(tbp, SBD_COMP_MEM,
26767c478bd9Sstevel@tonic-gate 				    unit, SBD_STATE_CONFIGURED);
26777c478bd9Sstevel@tonic-gate 			}
26787c478bd9Sstevel@tonic-gate 		}
26797c478bd9Sstevel@tonic-gate 
26807c478bd9Sstevel@tonic-gate 		PR_MEM("%s: %s memory COPY-RENAME (board %d -> %d)\n",
26817c478bd9Sstevel@tonic-gate 			f,
26827c478bd9Sstevel@tonic-gate 			rv ? "FAILED" : "COMPLETED",
26837c478bd9Sstevel@tonic-gate 			sbp->sb_num,
26847c478bd9Sstevel@tonic-gate 			tbp->sb_num);
26857c478bd9Sstevel@tonic-gate 	}
26867c478bd9Sstevel@tonic-gate 
26877c478bd9Sstevel@tonic-gate 	if (rv == 0) {
26887c478bd9Sstevel@tonic-gate 		update_membounds_t umb;
26897c478bd9Sstevel@tonic-gate 
26907c478bd9Sstevel@tonic-gate 		umb.u_board = sbp->sb_num;
26917c478bd9Sstevel@tonic-gate 		umb.u_base = (uint64_t)-1;
26927c478bd9Sstevel@tonic-gate 		umb.u_len = (uint64_t)-1;
26937c478bd9Sstevel@tonic-gate 
26947c478bd9Sstevel@tonic-gate 		lgrp_plat_config(LGRP_CONFIG_MEM_DEL, (uintptr_t)&umb);
26957c478bd9Sstevel@tonic-gate 	}
26967c478bd9Sstevel@tonic-gate 
26977c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
26987c478bd9Sstevel@tonic-gate 	return (rv);
26997c478bd9Sstevel@tonic-gate }
27007c478bd9Sstevel@tonic-gate 
27017c478bd9Sstevel@tonic-gate /*ARGSUSED*/
27027c478bd9Sstevel@tonic-gate static void
sbd_flush_ecache(uint64_t a,uint64_t b)27037c478bd9Sstevel@tonic-gate sbd_flush_ecache(uint64_t a, uint64_t b)
27047c478bd9Sstevel@tonic-gate {
27057c478bd9Sstevel@tonic-gate 	cpu_flush_ecache();
27067c478bd9Sstevel@tonic-gate }
2707