xref: /titanic_51/usr/src/uts/sun4u/sunfire/io/ac_del.c (revision 85f5803819bea86c07827a9544494e4ad327d95d)
129949e86Sstevel /*
229949e86Sstevel  * CDDL HEADER START
329949e86Sstevel  *
429949e86Sstevel  * The contents of this file are subject to the terms of the
529949e86Sstevel  * Common Development and Distribution License (the "License").
629949e86Sstevel  * You may not use this file except in compliance with the License.
729949e86Sstevel  *
829949e86Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
929949e86Sstevel  * or http://www.opensolaris.org/os/licensing.
1029949e86Sstevel  * See the License for the specific language governing permissions
1129949e86Sstevel  * and limitations under the License.
1229949e86Sstevel  *
1329949e86Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
1429949e86Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1529949e86Sstevel  * If applicable, add the following below this CDDL HEADER, with the
1629949e86Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
1729949e86Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
1829949e86Sstevel  *
1929949e86Sstevel  * CDDL HEADER END
2029949e86Sstevel  */
2129949e86Sstevel 
2229949e86Sstevel /*
23*85f58038Sdp78419  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
2429949e86Sstevel  * Use is subject to license terms.
2529949e86Sstevel  */
2629949e86Sstevel 
2729949e86Sstevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
2829949e86Sstevel 
2929949e86Sstevel #include <sys/types.h>
3029949e86Sstevel #include <sys/systm.h>
3129949e86Sstevel #include <sys/ddi.h>
3229949e86Sstevel #include <sys/sunddi.h>
3329949e86Sstevel #include <sys/ddi_impldefs.h>
3429949e86Sstevel #include <sys/obpdefs.h>
3529949e86Sstevel #include <sys/errno.h>
3629949e86Sstevel #include <sys/kmem.h>
3729949e86Sstevel #include <sys/vmem.h>
3829949e86Sstevel #include <sys/debug.h>
3929949e86Sstevel #include <sys/sysmacros.h>
4029949e86Sstevel #include <sys/machsystm.h>
4129949e86Sstevel #include <sys/machparam.h>
4229949e86Sstevel #include <sys/modctl.h>
4329949e86Sstevel #include <sys/fhc.h>
4429949e86Sstevel #include <sys/ac.h>
4529949e86Sstevel #include <sys/vm.h>
4629949e86Sstevel #include <sys/cpu_module.h>
4729949e86Sstevel #include <vm/seg_kmem.h>
4829949e86Sstevel #include <vm/hat_sfmmu.h>
4929949e86Sstevel #include <sys/mem_config.h>
5029949e86Sstevel #include <sys/mem_cage.h>
5129949e86Sstevel 
5229949e86Sstevel extern ac_err_t ac_kpm_err_cvt(int);
5329949e86Sstevel 
5429949e86Sstevel int ac_del_clean = 0;
5529949e86Sstevel 
5629949e86Sstevel /*
5729949e86Sstevel  * Default timeout, in seconds, for delete.
5829949e86Sstevel  * Time is counted when no progress is being made.
5929949e86Sstevel  */
6029949e86Sstevel static int ac_del_timeout = 60;
6129949e86Sstevel 
6229949e86Sstevel #define	DEL_PAGESIZE	MMU_PAGESIZE
6329949e86Sstevel 
6429949e86Sstevel struct del_status {
6529949e86Sstevel 	struct del_status *next;
6629949e86Sstevel 	memhandle_t	handle;
6729949e86Sstevel 	volatile int	its_done;
6829949e86Sstevel 	int		done_error;
6929949e86Sstevel 	kcondvar_t	ac_del_cv;
7029949e86Sstevel 	int		del_timeout;
7129949e86Sstevel 	int		del_noprogress;
7229949e86Sstevel 	ac_err_t	cancel_code;
7329949e86Sstevel 	timeout_id_t	to_id;
7429949e86Sstevel 	pgcnt_t		last_collected;
7529949e86Sstevel };
7629949e86Sstevel static struct del_status *ac_del_list;
7729949e86Sstevel static kmutex_t ac_del_mutex;
7829949e86Sstevel 
7929949e86Sstevel static struct del_status *
8029949e86Sstevel ac_del_alloc_status()
8129949e86Sstevel {
8229949e86Sstevel 	struct del_status *dsp;
8329949e86Sstevel 
8429949e86Sstevel 	dsp = (struct del_status *)kmem_zalloc(sizeof (*dsp), KM_SLEEP);
8529949e86Sstevel 	mutex_enter(&ac_del_mutex);
8629949e86Sstevel 	dsp->next = ac_del_list;
8729949e86Sstevel 	ac_del_list = dsp;
8829949e86Sstevel 	mutex_exit(&ac_del_mutex);
8929949e86Sstevel 
9029949e86Sstevel 	return (dsp);
9129949e86Sstevel }
9229949e86Sstevel 
9329949e86Sstevel static void
9429949e86Sstevel ac_del_free_status(struct del_status *dsp)
9529949e86Sstevel {
9629949e86Sstevel 	struct del_status **dspp;
9729949e86Sstevel 
9829949e86Sstevel 	mutex_enter(&ac_del_mutex);
9929949e86Sstevel 	dspp = &ac_del_list;
10029949e86Sstevel 	while (*dspp != NULL) {
10129949e86Sstevel 		if (*dspp == dsp)
10229949e86Sstevel 			break;
10329949e86Sstevel 		dspp = &(*dspp)->next;
10429949e86Sstevel 	}
10529949e86Sstevel 	ASSERT(*dspp == dsp);
10629949e86Sstevel 	if (*dspp == dsp) {
10729949e86Sstevel 		*dspp = dsp->next;
10829949e86Sstevel 	}
10929949e86Sstevel 	mutex_exit(&ac_del_mutex);
11029949e86Sstevel 	kmem_free((void *)dsp, sizeof (*dsp));
11129949e86Sstevel }
11229949e86Sstevel 
11329949e86Sstevel static void
11429949e86Sstevel del_comp(void *arg, int error)
11529949e86Sstevel {
11629949e86Sstevel 	struct del_status *dsp;
11729949e86Sstevel 
11829949e86Sstevel 	dsp = (struct del_status *)arg;
11929949e86Sstevel 	mutex_enter(&ac_del_mutex);
12029949e86Sstevel #ifdef DEBUG
12129949e86Sstevel 	{
12229949e86Sstevel 		struct del_status *adsp;
12329949e86Sstevel 		for (adsp = ac_del_list; adsp != NULL; adsp = adsp->next) {
12429949e86Sstevel 			if (adsp == dsp)
12529949e86Sstevel 				break;
12629949e86Sstevel 		}
12729949e86Sstevel 		ASSERT(adsp != NULL);
12829949e86Sstevel 	}
12929949e86Sstevel #endif /* DEBUG */
13029949e86Sstevel 	dsp->its_done = 1;
13129949e86Sstevel 	dsp->done_error = error;
13229949e86Sstevel 	cv_signal(&dsp->ac_del_cv);
13329949e86Sstevel 	mutex_exit(&ac_del_mutex);
13429949e86Sstevel }
13529949e86Sstevel 
13629949e86Sstevel /*ARGSUSED*/
13729949e86Sstevel static void
13829949e86Sstevel del_to_scan(void *arg)
13929949e86Sstevel {
14029949e86Sstevel 	struct del_status *dsp;
14129949e86Sstevel 	int do_cancel;
14229949e86Sstevel 	memdelstat_t dstat;
14329949e86Sstevel 	int err;
14429949e86Sstevel 
14529949e86Sstevel 	dsp = arg;
14629949e86Sstevel 
14729949e86Sstevel #ifdef DEBUG
14829949e86Sstevel 	{
14929949e86Sstevel 		struct del_status *adsp;
15029949e86Sstevel 
15129949e86Sstevel 		mutex_enter(&ac_del_mutex);
15229949e86Sstevel 		for (adsp = ac_del_list; adsp != NULL; adsp = adsp->next) {
15329949e86Sstevel 			if (adsp == dsp)
15429949e86Sstevel 				break;
15529949e86Sstevel 		}
15629949e86Sstevel 		ASSERT(adsp != NULL);
15729949e86Sstevel 		mutex_exit(&ac_del_mutex);
15829949e86Sstevel 	}
15929949e86Sstevel #endif /* DEBUG */
16029949e86Sstevel 	do_cancel = 0;
16129949e86Sstevel 	err = kphysm_del_status(dsp->handle, &dstat);
16229949e86Sstevel 	mutex_enter(&ac_del_mutex);
16329949e86Sstevel 	if (dsp->its_done) {
16429949e86Sstevel 		mutex_exit(&ac_del_mutex);
16529949e86Sstevel 		return;
16629949e86Sstevel 	}
16729949e86Sstevel 	if ((err == KPHYSM_OK) &&
16829949e86Sstevel 	    (dsp->last_collected != dstat.collected)) {
16929949e86Sstevel 		dsp->del_noprogress = 0;
17029949e86Sstevel 		dsp->last_collected = dstat.collected;
17129949e86Sstevel 	} else {
17229949e86Sstevel 		dsp->del_noprogress++;
17329949e86Sstevel 		if (dsp->del_noprogress >= dsp->del_timeout) {
17429949e86Sstevel 			if (dsp->cancel_code == 0)
17529949e86Sstevel 				dsp->cancel_code = AC_ERR_TIMEOUT;
17629949e86Sstevel 			do_cancel = 1;
17729949e86Sstevel 		}
17829949e86Sstevel 	}
17929949e86Sstevel 	if (!do_cancel)
18029949e86Sstevel 		dsp->to_id = timeout(del_to_scan, arg, hz);
18129949e86Sstevel 	else
18229949e86Sstevel 		dsp->to_id = 0;
18329949e86Sstevel 	mutex_exit(&ac_del_mutex);
18429949e86Sstevel 	if (do_cancel)
18529949e86Sstevel 		(void) kphysm_del_cancel(dsp->handle);
18629949e86Sstevel }
18729949e86Sstevel 
18829949e86Sstevel static void
18929949e86Sstevel del_to_start(struct del_status *dsp)
19029949e86Sstevel {
19129949e86Sstevel 	if (dsp->del_timeout != 0)
19229949e86Sstevel 		dsp->to_id = timeout(del_to_scan, dsp, hz);
19329949e86Sstevel }
19429949e86Sstevel 
19529949e86Sstevel static void
19629949e86Sstevel del_to_stop(struct del_status *dsp)
19729949e86Sstevel {
19829949e86Sstevel 	timeout_id_t tid;
19929949e86Sstevel 
20029949e86Sstevel 	while ((tid = dsp->to_id) != 0) {
20129949e86Sstevel 		dsp->to_id = 0;
20229949e86Sstevel 		mutex_exit(&ac_del_mutex);
20329949e86Sstevel 		(void) untimeout(tid);
20429949e86Sstevel 		mutex_enter(&ac_del_mutex);
20529949e86Sstevel 	}
20629949e86Sstevel }
20729949e86Sstevel 
20829949e86Sstevel static int
20929949e86Sstevel ac_del_bank_add_span(
21029949e86Sstevel 	memhandle_t handle,
21129949e86Sstevel 	ac_cfga_pkt_t *pkt)
21229949e86Sstevel {
21329949e86Sstevel 	uint64_t		decode;
21429949e86Sstevel 	uint64_t		base_pa;
21529949e86Sstevel 	uint64_t		bank_size;
21629949e86Sstevel 	pfn_t			base;
21729949e86Sstevel 	pgcnt_t			npgs;
21829949e86Sstevel 	int			errs;
21929949e86Sstevel 	int			ret;
22029949e86Sstevel 	struct ac_soft_state	*asp = pkt->softsp;
22129949e86Sstevel 	uint_t			ilv;
22229949e86Sstevel 
22329949e86Sstevel 	/*
22429949e86Sstevel 	 * Cannot delete interleaved banks at the moment.
22529949e86Sstevel 	 */
22629949e86Sstevel 	ilv = (pkt->bank == Bank0) ?
22729949e86Sstevel 	    INTLV0(*asp->ac_memctl) : INTLV1(*asp->ac_memctl);
22829949e86Sstevel 	if (ilv != 1) {
22929949e86Sstevel 		AC_ERR_SET(pkt, AC_ERR_MEM_DEINTLV);
23029949e86Sstevel 		return (EINVAL);
23129949e86Sstevel 	}
23229949e86Sstevel 	/*
23329949e86Sstevel 	 * Determine the physical location of the selected bank
23429949e86Sstevel 	 */
23529949e86Sstevel 	decode = (pkt->bank == Bank0) ?
23629949e86Sstevel 	    *asp->ac_memdecode0 : *asp->ac_memdecode1;
23729949e86Sstevel 	base_pa = GRP_REALBASE(decode);
23829949e86Sstevel 	bank_size = GRP_UK2SPAN(decode);
23929949e86Sstevel 
24029949e86Sstevel 	base = base_pa >> PAGESHIFT;
24129949e86Sstevel 	npgs = bank_size >> PAGESHIFT;
24229949e86Sstevel 
24329949e86Sstevel 	/*
24429949e86Sstevel 	 * Delete the pages from the cage growth list.
24529949e86Sstevel 	 */
24629949e86Sstevel 	ret = kcage_range_delete(base, npgs);
24729949e86Sstevel 	if (ret != 0) {
24829949e86Sstevel 		/* TODO: Should this be a separate error? */
24929949e86Sstevel 		AC_ERR_SET(pkt, AC_ERR_KPM_NONRELOC);
25029949e86Sstevel 		return (EINVAL);
25129949e86Sstevel 	}
25229949e86Sstevel 
25329949e86Sstevel 	/*
25429949e86Sstevel 	 * Add to delete memory list.
25529949e86Sstevel 	 */
25629949e86Sstevel 
25729949e86Sstevel 	if ((errs = kphysm_del_span(handle, base, npgs)) != KPHYSM_OK) {
25829949e86Sstevel 		AC_ERR_SET(pkt, ac_kpm_err_cvt(errs));
25929949e86Sstevel 		/*
26029949e86Sstevel 		 * Restore the pages to the cage growth list.
26129949e86Sstevel 		 * TODO: We should not unconditionally add back
26229949e86Sstevel 		 * if we conditionally add at memory add time.
26329949e86Sstevel 		 */
264*85f58038Sdp78419 		errs = kcage_range_add(base, npgs, KCAGE_DOWN);
26529949e86Sstevel 		/* TODO: deal with error return. */
26629949e86Sstevel 		if (errs != 0) {
26729949e86Sstevel 			AC_ERR_SET(pkt, ac_kpm_err_cvt(errs));
26829949e86Sstevel 			cmn_err(CE_NOTE, "ac_del_bank_add_span(): "
26929949e86Sstevel 			    "board %d, bank %d, "
27029949e86Sstevel 			    "kcage_range_add() returned %d",
27129949e86Sstevel 			    pkt->softsp->board, pkt->bank, errs);
27229949e86Sstevel 		}
27329949e86Sstevel 		return (EINVAL);
27429949e86Sstevel 	}
27529949e86Sstevel 	return (0);
27629949e86Sstevel }
27729949e86Sstevel 
27829949e86Sstevel static void
27929949e86Sstevel ac_del_bank_add_cage(
28029949e86Sstevel 	struct bd_list *del,
28129949e86Sstevel 	enum ac_bank_id bank)
28229949e86Sstevel {
28329949e86Sstevel 	uint64_t		decode;
28429949e86Sstevel 	uint64_t		base_pa;
28529949e86Sstevel 	uint64_t		bank_size;
28629949e86Sstevel 	pfn_t			base;
28729949e86Sstevel 	pgcnt_t			npgs;
28829949e86Sstevel 	int			errs;
28929949e86Sstevel 	struct ac_soft_state	*asp = (struct ac_soft_state *)(del->ac_softsp);
29029949e86Sstevel 
29129949e86Sstevel 	/*
29229949e86Sstevel 	 * Determine the physical location of the selected bank
29329949e86Sstevel 	 */
29429949e86Sstevel 	decode = (bank == Bank0) ? *asp->ac_memdecode0 : *asp->ac_memdecode1;
29529949e86Sstevel 	base_pa = GRP_REALBASE(decode);
29629949e86Sstevel 	bank_size = GRP_UK2SPAN(decode);
29729949e86Sstevel 
29829949e86Sstevel 	base = base_pa >> PAGESHIFT;
29929949e86Sstevel 	npgs = bank_size >> PAGESHIFT;
30029949e86Sstevel 
30129949e86Sstevel 	/*
30229949e86Sstevel 	 * Restore the pages to the cage growth list.
30329949e86Sstevel 	 * TODO: We should not unconditionally add back
30429949e86Sstevel 	 * if we conditionally add at memory add time.
30529949e86Sstevel 	 */
306*85f58038Sdp78419 	errs = kcage_range_add(base, npgs, KCAGE_DOWN);
30729949e86Sstevel 	/* TODO: deal with error return. */
30829949e86Sstevel 	if (errs != 0)
30929949e86Sstevel 		cmn_err(CE_NOTE, "ac_del_bank_add_cage(): "
31029949e86Sstevel 		    "board %d, bank %d, "
31129949e86Sstevel 		    "kcage_range_add() returned %d",
31229949e86Sstevel 		    del->sc.board, bank, errs);
31329949e86Sstevel }
31429949e86Sstevel 
31529949e86Sstevel static int
31629949e86Sstevel ac_del_bank_run(struct del_status *dsp, ac_cfga_pkt_t *pkt)
31729949e86Sstevel {
31829949e86Sstevel 	int errs;
31929949e86Sstevel 
32029949e86Sstevel 	dsp->its_done = 0;
32129949e86Sstevel 	if ((errs = kphysm_del_start(dsp->handle, del_comp, (void *)dsp)) !=
32229949e86Sstevel 	    KPHYSM_OK) {
32329949e86Sstevel 		AC_ERR_SET(pkt, ac_kpm_err_cvt(errs));
32429949e86Sstevel 		return (EINVAL);
32529949e86Sstevel 	}
32629949e86Sstevel 	/* Wait for it to complete. */
32729949e86Sstevel 	mutex_enter(&ac_del_mutex);
32829949e86Sstevel 	del_to_start(dsp);
32929949e86Sstevel 	while (!dsp->its_done) {
33029949e86Sstevel 		if (!cv_wait_sig(&dsp->ac_del_cv, &ac_del_mutex)) {
33129949e86Sstevel 			if (dsp->cancel_code == 0)
33229949e86Sstevel 				dsp->cancel_code = AC_ERR_INTR;
33329949e86Sstevel 			mutex_exit(&ac_del_mutex);
33429949e86Sstevel 			errs = kphysm_del_cancel(dsp->handle);
33529949e86Sstevel 			mutex_enter(&ac_del_mutex);
33629949e86Sstevel 			if (errs != KPHYSM_OK) {
33729949e86Sstevel 				ASSERT(errs == KPHYSM_ENOTRUNNING);
33829949e86Sstevel 			}
33929949e86Sstevel 			break;
34029949e86Sstevel 		}
34129949e86Sstevel 	}
34229949e86Sstevel 	/*
34329949e86Sstevel 	 * If the loop exited due to a signal, we must continue to wait
34429949e86Sstevel 	 * using cv_wait() as the signal is pending until syscall exit.
34529949e86Sstevel 	 */
34629949e86Sstevel 	while (!dsp->its_done) {
34729949e86Sstevel 		cv_wait(&dsp->ac_del_cv, &ac_del_mutex);
34829949e86Sstevel 	}
34929949e86Sstevel 	if (dsp->done_error != KPHYSM_OK) {
35029949e86Sstevel 		AC_ERR_SET(pkt, ac_kpm_err_cvt(dsp->done_error));
35129949e86Sstevel 		if ((dsp->done_error == KPHYSM_ECANCELLED) ||
35229949e86Sstevel 		    (dsp->done_error == KPHYSM_EREFUSED)) {
35329949e86Sstevel 			errs = EINTR;
35429949e86Sstevel 			if (dsp->cancel_code != 0) {
35529949e86Sstevel 				AC_ERR_SET(pkt, dsp->cancel_code);
35629949e86Sstevel 			}
35729949e86Sstevel 		} else {
35829949e86Sstevel 			errs = EINVAL;
35929949e86Sstevel 		}
36029949e86Sstevel 	} else
36129949e86Sstevel 		errs = 0;
36229949e86Sstevel 	del_to_stop(dsp);
36329949e86Sstevel 	mutex_exit(&ac_del_mutex);
36429949e86Sstevel 
36529949e86Sstevel 	return (errs);
36629949e86Sstevel }
36729949e86Sstevel 
36829949e86Sstevel 
36929949e86Sstevel /*
37029949e86Sstevel  * set the memory to known state for debugging
37129949e86Sstevel  */
37229949e86Sstevel static void
37329949e86Sstevel ac_bank_write_pattern(struct bd_list *del, enum ac_bank_id bank)
37429949e86Sstevel {
37529949e86Sstevel 	uint64_t		decode;
37629949e86Sstevel 	uint64_t		base_pa;
37729949e86Sstevel 	uint64_t		limit_pa;
37829949e86Sstevel 	uint64_t		bank_size;
37929949e86Sstevel 	uint64_t		current_pa;
38029949e86Sstevel 	caddr_t			base_va;
38129949e86Sstevel 	caddr_t			fill_buf;
38229949e86Sstevel 	struct ac_soft_state	*asp = (struct ac_soft_state *)(del->ac_softsp);
38329949e86Sstevel 	int			linesize;
38429949e86Sstevel 
38529949e86Sstevel 	/*
38629949e86Sstevel 	 * Determine the physical location of the selected bank
38729949e86Sstevel 	 */
38829949e86Sstevel 	decode = (bank == Bank0) ? *asp->ac_memdecode0 : *asp->ac_memdecode1;
38929949e86Sstevel 	base_pa = GRP_REALBASE(decode);
39029949e86Sstevel 	bank_size = GRP_UK2SPAN(decode);
39129949e86Sstevel 	limit_pa = base_pa + bank_size;
39229949e86Sstevel 	linesize = cpunodes[CPU->cpu_id].ecache_linesize;
39329949e86Sstevel 
39429949e86Sstevel 	/*
39529949e86Sstevel 	 * We need a page_va and a fill buffer for this operation
39629949e86Sstevel 	 */
39729949e86Sstevel 	base_va = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP);
39829949e86Sstevel 	fill_buf = kmem_zalloc(DEL_PAGESIZE, KM_SLEEP);
39929949e86Sstevel 	{
40029949e86Sstevel 		typedef uint32_t patt_t;
40129949e86Sstevel 		patt_t *bf, *bfe, patt;
40229949e86Sstevel 
40329949e86Sstevel 		bf = (patt_t *)fill_buf;
40429949e86Sstevel 		bfe = (patt_t *)((char *)fill_buf + DEL_PAGESIZE);
40529949e86Sstevel 		patt = 0xbeaddeed;
40629949e86Sstevel 		while (bf < bfe)
40729949e86Sstevel 			*bf++ = patt;
40829949e86Sstevel 	}
40929949e86Sstevel 
41029949e86Sstevel 	/*
41129949e86Sstevel 	 * 'empty' the memory
41229949e86Sstevel 	 */
41329949e86Sstevel 	kpreempt_disable();
41429949e86Sstevel 	for (current_pa = base_pa; current_pa < limit_pa;
41529949e86Sstevel 	    current_pa += DEL_PAGESIZE) {
41629949e86Sstevel 
41729949e86Sstevel 		/* map current pa */
41829949e86Sstevel 		ac_mapin(current_pa, base_va);
41929949e86Sstevel 
42029949e86Sstevel 		/* fill the target page */
42129949e86Sstevel 		ac_blkcopy(fill_buf, base_va,
42229949e86Sstevel 			DEL_PAGESIZE/linesize, linesize);
42329949e86Sstevel 
42429949e86Sstevel 		/* tear down translation */
42529949e86Sstevel 		ac_unmap(base_va);
42629949e86Sstevel 	}
42729949e86Sstevel 	kpreempt_enable();
42829949e86Sstevel 
42929949e86Sstevel 	/*
43029949e86Sstevel 	 * clean up temporary resources
43129949e86Sstevel 	 */
43229949e86Sstevel 	{
43329949e86Sstevel 		/* Distinguish the fill buf from memory deleted! */
43429949e86Sstevel 		typedef uint32_t patt_t;
43529949e86Sstevel 		patt_t *bf, *bfe, patt;
43629949e86Sstevel 
43729949e86Sstevel 		bf = (patt_t *)fill_buf;
43829949e86Sstevel 		bfe = (patt_t *)((char *)fill_buf + DEL_PAGESIZE);
43929949e86Sstevel 		patt = 0xbeadfeed;
44029949e86Sstevel 		while (bf < bfe)
44129949e86Sstevel 			*bf++ = patt;
44229949e86Sstevel 	}
44329949e86Sstevel 	kmem_free(fill_buf, DEL_PAGESIZE);
44429949e86Sstevel 	vmem_free(heap_arena, base_va, PAGESIZE);
44529949e86Sstevel }
44629949e86Sstevel 
44729949e86Sstevel int
44829949e86Sstevel ac_del_memory(ac_cfga_pkt_t *pkt)
44929949e86Sstevel {
45029949e86Sstevel 	struct bd_list *board;
45129949e86Sstevel 	struct ac_mem_info *mem_info;
45229949e86Sstevel 	int busy_set;
45329949e86Sstevel 	struct del_status *dsp;
45429949e86Sstevel 	memdelstat_t dstat;
45529949e86Sstevel 	int retval;
45629949e86Sstevel 	int r_errs;
45729949e86Sstevel 	struct ac_soft_state *asp;
45829949e86Sstevel 
45929949e86Sstevel 	if (!kcage_on) {
46029949e86Sstevel 		static int cage_msg_done = 0;
46129949e86Sstevel 
46229949e86Sstevel 		if (!cage_msg_done) {
46329949e86Sstevel 			cage_msg_done = 1;
46429949e86Sstevel 			cmn_err(CE_NOTE, "ac: memory delete"
46529949e86Sstevel 			    " refused: cage is off");
46629949e86Sstevel 		}
46729949e86Sstevel 		AC_ERR_SET(pkt, ac_kpm_err_cvt(KPHYSM_ENONRELOC));
46829949e86Sstevel 		return (EINVAL);
46929949e86Sstevel 	}
47029949e86Sstevel 
47129949e86Sstevel 	dsp = ac_del_alloc_status();
47229949e86Sstevel 	if ((retval = kphysm_del_gethandle(&dsp->handle)) != KPHYSM_OK) {
47329949e86Sstevel 		ac_del_free_status(dsp);
47429949e86Sstevel 		AC_ERR_SET(pkt, ac_kpm_err_cvt(retval));
47529949e86Sstevel 		return (EINVAL);
47629949e86Sstevel 	}
47729949e86Sstevel 	retval = 0;
47829949e86Sstevel 	busy_set = 0;
47929949e86Sstevel 
48029949e86Sstevel 	board = fhc_bdlist_lock(pkt->softsp->board);
48129949e86Sstevel 	if (board == NULL || board->ac_softsp == NULL) {
48229949e86Sstevel 		fhc_bdlist_unlock();
48329949e86Sstevel 		AC_ERR_SET(pkt, AC_ERR_BD);
48429949e86Sstevel 		retval = EINVAL;
48529949e86Sstevel 		goto out;
48629949e86Sstevel 	}
48729949e86Sstevel 	ASSERT(pkt->softsp == board->ac_softsp);
48829949e86Sstevel 	asp = pkt->softsp;
48929949e86Sstevel 
49029949e86Sstevel 	/* verify the board is of the correct type */
49129949e86Sstevel 	switch (board->sc.type) {
49229949e86Sstevel 	case CPU_BOARD:
49329949e86Sstevel 	case MEM_BOARD:
49429949e86Sstevel 		break;
49529949e86Sstevel 	default:
49629949e86Sstevel 		fhc_bdlist_unlock();
49729949e86Sstevel 		AC_ERR_SET(pkt, AC_ERR_BD_TYPE);
49829949e86Sstevel 		retval = EINVAL;
49929949e86Sstevel 		goto out;
50029949e86Sstevel 	}
50129949e86Sstevel 
50229949e86Sstevel 	/* verify the memory condition is acceptable */
50329949e86Sstevel 	mem_info = &asp->bank[pkt->bank];
50429949e86Sstevel 	if (!MEM_BOARD_VISIBLE(board) || mem_info->busy ||
50529949e86Sstevel 	    fhc_bd_busy(pkt->softsp->board) ||
50629949e86Sstevel 	    mem_info->rstate != SYSC_CFGA_RSTATE_CONNECTED ||
50729949e86Sstevel 	    mem_info->ostate != SYSC_CFGA_OSTATE_CONFIGURED) {
50829949e86Sstevel 		fhc_bdlist_unlock();
50929949e86Sstevel 		AC_ERR_SET(pkt, AC_ERR_BD_STATE);
51029949e86Sstevel 		retval = EINVAL;
51129949e86Sstevel 		goto out;
51229949e86Sstevel 	}
51329949e86Sstevel 
51429949e86Sstevel 	if ((dsp->del_timeout = pkt->cmd_cfga.arg) == -1)
51529949e86Sstevel 		dsp->del_timeout = ac_del_timeout;
51629949e86Sstevel 
51729949e86Sstevel 	/*
51829949e86Sstevel 	 * at this point, we have an available bank to del.
51929949e86Sstevel 	 * mark it busy and initiate the del function.
52029949e86Sstevel 	 */
52129949e86Sstevel 	mem_info->busy = TRUE;
52229949e86Sstevel 	fhc_bdlist_unlock();
52329949e86Sstevel 
52429949e86Sstevel 	busy_set = 1;
52529949e86Sstevel 
52629949e86Sstevel 	retval = ac_del_bank_add_span(dsp->handle, pkt);
52729949e86Sstevel out:
52829949e86Sstevel 	if (retval != 0) {
52929949e86Sstevel 		r_errs = kphysm_del_release(dsp->handle);
53029949e86Sstevel 		ASSERT(r_errs == KPHYSM_OK);
53129949e86Sstevel 
53229949e86Sstevel 		if (busy_set) {
53329949e86Sstevel 			board = fhc_bdlist_lock(pkt->softsp->board);
53429949e86Sstevel 			ASSERT(board != NULL && board->ac_softsp != NULL);
53529949e86Sstevel 
53629949e86Sstevel 			ASSERT(board->sc.type == CPU_BOARD ||
53729949e86Sstevel 			    board->sc.type == MEM_BOARD);
53829949e86Sstevel 			ASSERT(asp ==
53929949e86Sstevel 			    (struct ac_soft_state *)(board->ac_softsp));
54029949e86Sstevel 			mem_info = &asp->bank[pkt->bank];
54129949e86Sstevel 			ASSERT(mem_info->busy != FALSE);
54229949e86Sstevel 			ASSERT(mem_info->ostate == SYSC_CFGA_OSTATE_CONFIGURED);
54329949e86Sstevel 			mem_info->busy = FALSE;
54429949e86Sstevel 			fhc_bdlist_unlock();
54529949e86Sstevel 		}
54629949e86Sstevel 
54729949e86Sstevel 		ac_del_free_status(dsp);
54829949e86Sstevel 		return (retval);
54929949e86Sstevel 	}
55029949e86Sstevel 
55129949e86Sstevel 	(void) kphysm_del_status(dsp->handle, &dstat);
55229949e86Sstevel 
55329949e86Sstevel 	retval = ac_del_bank_run(dsp, pkt);
55429949e86Sstevel 
55529949e86Sstevel 	r_errs = kphysm_del_release(dsp->handle);
55629949e86Sstevel 	ASSERT(r_errs == KPHYSM_OK);
55729949e86Sstevel 
55829949e86Sstevel 	board = fhc_bdlist_lock(pkt->softsp->board);
55929949e86Sstevel 	ASSERT(board != NULL && board->ac_softsp != NULL);
56029949e86Sstevel 
56129949e86Sstevel 	ASSERT(board->sc.type == CPU_BOARD || board->sc.type == MEM_BOARD);
56229949e86Sstevel 	ASSERT(asp == (struct ac_soft_state *)(board->ac_softsp));
56329949e86Sstevel 	mem_info = &asp->bank[pkt->bank];
56429949e86Sstevel 	ASSERT(mem_info->busy != FALSE);
56529949e86Sstevel 	ASSERT(mem_info->ostate == SYSC_CFGA_OSTATE_CONFIGURED);
56629949e86Sstevel 	mem_info->busy = FALSE;
56729949e86Sstevel 	if (retval == 0) {
56829949e86Sstevel 		mem_info->ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
56929949e86Sstevel 		mem_info->status_change = ddi_get_time();
57029949e86Sstevel 
57129949e86Sstevel 		if (ac_del_clean) {
57229949e86Sstevel 			/* DEBUG - set memory to known state */
57329949e86Sstevel 			ac_bank_write_pattern(board, pkt->bank);
57429949e86Sstevel 		}
57529949e86Sstevel 	} else {
57629949e86Sstevel 		/*
57729949e86Sstevel 		 * Restore the pages to the cage growth list.
57829949e86Sstevel 		 */
57929949e86Sstevel 		ac_del_bank_add_cage(board, pkt->bank);
58029949e86Sstevel 	}
58129949e86Sstevel 	fhc_bdlist_unlock();
58229949e86Sstevel 
58329949e86Sstevel 	ac_del_free_status(dsp);
58429949e86Sstevel 
58529949e86Sstevel 	return (retval);
58629949e86Sstevel }
587