xref: /onnv-gate/usr/src/uts/sun4u/sunfire/io/ac_del.c (revision 4266:c151d8b35988)
11341Sstevel /*
21341Sstevel  * CDDL HEADER START
31341Sstevel  *
41341Sstevel  * The contents of this file are subject to the terms of the
51341Sstevel  * Common Development and Distribution License (the "License").
61341Sstevel  * You may not use this file except in compliance with the License.
71341Sstevel  *
81341Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91341Sstevel  * or http://www.opensolaris.org/os/licensing.
101341Sstevel  * See the License for the specific language governing permissions
111341Sstevel  * and limitations under the License.
121341Sstevel  *
131341Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
141341Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151341Sstevel  * If applicable, add the following below this CDDL HEADER, with the
161341Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
171341Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
181341Sstevel  *
191341Sstevel  * CDDL HEADER END
201341Sstevel  */
211341Sstevel 
221341Sstevel /*
23*4266Sdp78419  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
241341Sstevel  * Use is subject to license terms.
251341Sstevel  */
261341Sstevel 
271341Sstevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
281341Sstevel 
291341Sstevel #include <sys/types.h>
301341Sstevel #include <sys/systm.h>
311341Sstevel #include <sys/ddi.h>
321341Sstevel #include <sys/sunddi.h>
331341Sstevel #include <sys/ddi_impldefs.h>
341341Sstevel #include <sys/obpdefs.h>
351341Sstevel #include <sys/errno.h>
361341Sstevel #include <sys/kmem.h>
371341Sstevel #include <sys/vmem.h>
381341Sstevel #include <sys/debug.h>
391341Sstevel #include <sys/sysmacros.h>
401341Sstevel #include <sys/machsystm.h>
411341Sstevel #include <sys/machparam.h>
421341Sstevel #include <sys/modctl.h>
431341Sstevel #include <sys/fhc.h>
441341Sstevel #include <sys/ac.h>
451341Sstevel #include <sys/vm.h>
461341Sstevel #include <sys/cpu_module.h>
471341Sstevel #include <vm/seg_kmem.h>
481341Sstevel #include <vm/hat_sfmmu.h>
491341Sstevel #include <sys/mem_config.h>
501341Sstevel #include <sys/mem_cage.h>
511341Sstevel 
521341Sstevel extern ac_err_t ac_kpm_err_cvt(int);
531341Sstevel 
541341Sstevel int ac_del_clean = 0;
551341Sstevel 
561341Sstevel /*
571341Sstevel  * Default timeout, in seconds, for delete.
581341Sstevel  * Time is counted when no progress is being made.
591341Sstevel  */
601341Sstevel static int ac_del_timeout = 60;
611341Sstevel 
621341Sstevel #define	DEL_PAGESIZE	MMU_PAGESIZE
631341Sstevel 
641341Sstevel struct del_status {
651341Sstevel 	struct del_status *next;
661341Sstevel 	memhandle_t	handle;
671341Sstevel 	volatile int	its_done;
681341Sstevel 	int		done_error;
691341Sstevel 	kcondvar_t	ac_del_cv;
701341Sstevel 	int		del_timeout;
711341Sstevel 	int		del_noprogress;
721341Sstevel 	ac_err_t	cancel_code;
731341Sstevel 	timeout_id_t	to_id;
741341Sstevel 	pgcnt_t		last_collected;
751341Sstevel };
761341Sstevel static struct del_status *ac_del_list;
771341Sstevel static kmutex_t ac_del_mutex;
781341Sstevel 
791341Sstevel static struct del_status *
ac_del_alloc_status()801341Sstevel ac_del_alloc_status()
811341Sstevel {
821341Sstevel 	struct del_status *dsp;
831341Sstevel 
841341Sstevel 	dsp = (struct del_status *)kmem_zalloc(sizeof (*dsp), KM_SLEEP);
851341Sstevel 	mutex_enter(&ac_del_mutex);
861341Sstevel 	dsp->next = ac_del_list;
871341Sstevel 	ac_del_list = dsp;
881341Sstevel 	mutex_exit(&ac_del_mutex);
891341Sstevel 
901341Sstevel 	return (dsp);
911341Sstevel }
921341Sstevel 
931341Sstevel static void
ac_del_free_status(struct del_status * dsp)941341Sstevel ac_del_free_status(struct del_status *dsp)
951341Sstevel {
961341Sstevel 	struct del_status **dspp;
971341Sstevel 
981341Sstevel 	mutex_enter(&ac_del_mutex);
991341Sstevel 	dspp = &ac_del_list;
1001341Sstevel 	while (*dspp != NULL) {
1011341Sstevel 		if (*dspp == dsp)
1021341Sstevel 			break;
1031341Sstevel 		dspp = &(*dspp)->next;
1041341Sstevel 	}
1051341Sstevel 	ASSERT(*dspp == dsp);
1061341Sstevel 	if (*dspp == dsp) {
1071341Sstevel 		*dspp = dsp->next;
1081341Sstevel 	}
1091341Sstevel 	mutex_exit(&ac_del_mutex);
1101341Sstevel 	kmem_free((void *)dsp, sizeof (*dsp));
1111341Sstevel }
1121341Sstevel 
1131341Sstevel static void
del_comp(void * arg,int error)1141341Sstevel del_comp(void *arg, int error)
1151341Sstevel {
1161341Sstevel 	struct del_status *dsp;
1171341Sstevel 
1181341Sstevel 	dsp = (struct del_status *)arg;
1191341Sstevel 	mutex_enter(&ac_del_mutex);
1201341Sstevel #ifdef DEBUG
1211341Sstevel 	{
1221341Sstevel 		struct del_status *adsp;
1231341Sstevel 		for (adsp = ac_del_list; adsp != NULL; adsp = adsp->next) {
1241341Sstevel 			if (adsp == dsp)
1251341Sstevel 				break;
1261341Sstevel 		}
1271341Sstevel 		ASSERT(adsp != NULL);
1281341Sstevel 	}
1291341Sstevel #endif /* DEBUG */
1301341Sstevel 	dsp->its_done = 1;
1311341Sstevel 	dsp->done_error = error;
1321341Sstevel 	cv_signal(&dsp->ac_del_cv);
1331341Sstevel 	mutex_exit(&ac_del_mutex);
1341341Sstevel }
1351341Sstevel 
1361341Sstevel /*ARGSUSED*/
1371341Sstevel static void
del_to_scan(void * arg)1381341Sstevel del_to_scan(void *arg)
1391341Sstevel {
1401341Sstevel 	struct del_status *dsp;
1411341Sstevel 	int do_cancel;
1421341Sstevel 	memdelstat_t dstat;
1431341Sstevel 	int err;
1441341Sstevel 
1451341Sstevel 	dsp = arg;
1461341Sstevel 
1471341Sstevel #ifdef DEBUG
1481341Sstevel 	{
1491341Sstevel 		struct del_status *adsp;
1501341Sstevel 
1511341Sstevel 		mutex_enter(&ac_del_mutex);
1521341Sstevel 		for (adsp = ac_del_list; adsp != NULL; adsp = adsp->next) {
1531341Sstevel 			if (adsp == dsp)
1541341Sstevel 				break;
1551341Sstevel 		}
1561341Sstevel 		ASSERT(adsp != NULL);
1571341Sstevel 		mutex_exit(&ac_del_mutex);
1581341Sstevel 	}
1591341Sstevel #endif /* DEBUG */
1601341Sstevel 	do_cancel = 0;
1611341Sstevel 	err = kphysm_del_status(dsp->handle, &dstat);
1621341Sstevel 	mutex_enter(&ac_del_mutex);
1631341Sstevel 	if (dsp->its_done) {
1641341Sstevel 		mutex_exit(&ac_del_mutex);
1651341Sstevel 		return;
1661341Sstevel 	}
1671341Sstevel 	if ((err == KPHYSM_OK) &&
1681341Sstevel 	    (dsp->last_collected != dstat.collected)) {
1691341Sstevel 		dsp->del_noprogress = 0;
1701341Sstevel 		dsp->last_collected = dstat.collected;
1711341Sstevel 	} else {
1721341Sstevel 		dsp->del_noprogress++;
1731341Sstevel 		if (dsp->del_noprogress >= dsp->del_timeout) {
1741341Sstevel 			if (dsp->cancel_code == 0)
1751341Sstevel 				dsp->cancel_code = AC_ERR_TIMEOUT;
1761341Sstevel 			do_cancel = 1;
1771341Sstevel 		}
1781341Sstevel 	}
1791341Sstevel 	if (!do_cancel)
1801341Sstevel 		dsp->to_id = timeout(del_to_scan, arg, hz);
1811341Sstevel 	else
1821341Sstevel 		dsp->to_id = 0;
1831341Sstevel 	mutex_exit(&ac_del_mutex);
1841341Sstevel 	if (do_cancel)
1851341Sstevel 		(void) kphysm_del_cancel(dsp->handle);
1861341Sstevel }
1871341Sstevel 
1881341Sstevel static void
del_to_start(struct del_status * dsp)1891341Sstevel del_to_start(struct del_status *dsp)
1901341Sstevel {
1911341Sstevel 	if (dsp->del_timeout != 0)
1921341Sstevel 		dsp->to_id = timeout(del_to_scan, dsp, hz);
1931341Sstevel }
1941341Sstevel 
1951341Sstevel static void
del_to_stop(struct del_status * dsp)1961341Sstevel del_to_stop(struct del_status *dsp)
1971341Sstevel {
1981341Sstevel 	timeout_id_t tid;
1991341Sstevel 
2001341Sstevel 	while ((tid = dsp->to_id) != 0) {
2011341Sstevel 		dsp->to_id = 0;
2021341Sstevel 		mutex_exit(&ac_del_mutex);
2031341Sstevel 		(void) untimeout(tid);
2041341Sstevel 		mutex_enter(&ac_del_mutex);
2051341Sstevel 	}
2061341Sstevel }
2071341Sstevel 
2081341Sstevel static int
ac_del_bank_add_span(memhandle_t handle,ac_cfga_pkt_t * pkt)2091341Sstevel ac_del_bank_add_span(
2101341Sstevel 	memhandle_t handle,
2111341Sstevel 	ac_cfga_pkt_t *pkt)
2121341Sstevel {
2131341Sstevel 	uint64_t		decode;
2141341Sstevel 	uint64_t		base_pa;
2151341Sstevel 	uint64_t		bank_size;
2161341Sstevel 	pfn_t			base;
2171341Sstevel 	pgcnt_t			npgs;
2181341Sstevel 	int			errs;
2191341Sstevel 	int			ret;
2201341Sstevel 	struct ac_soft_state	*asp = pkt->softsp;
2211341Sstevel 	uint_t			ilv;
2221341Sstevel 
2231341Sstevel 	/*
2241341Sstevel 	 * Cannot delete interleaved banks at the moment.
2251341Sstevel 	 */
2261341Sstevel 	ilv = (pkt->bank == Bank0) ?
2271341Sstevel 	    INTLV0(*asp->ac_memctl) : INTLV1(*asp->ac_memctl);
2281341Sstevel 	if (ilv != 1) {
2291341Sstevel 		AC_ERR_SET(pkt, AC_ERR_MEM_DEINTLV);
2301341Sstevel 		return (EINVAL);
2311341Sstevel 	}
2321341Sstevel 	/*
2331341Sstevel 	 * Determine the physical location of the selected bank
2341341Sstevel 	 */
2351341Sstevel 	decode = (pkt->bank == Bank0) ?
2361341Sstevel 	    *asp->ac_memdecode0 : *asp->ac_memdecode1;
2371341Sstevel 	base_pa = GRP_REALBASE(decode);
2381341Sstevel 	bank_size = GRP_UK2SPAN(decode);
2391341Sstevel 
2401341Sstevel 	base = base_pa >> PAGESHIFT;
2411341Sstevel 	npgs = bank_size >> PAGESHIFT;
2421341Sstevel 
2431341Sstevel 	/*
2441341Sstevel 	 * Delete the pages from the cage growth list.
2451341Sstevel 	 */
2461341Sstevel 	ret = kcage_range_delete(base, npgs);
2471341Sstevel 	if (ret != 0) {
2481341Sstevel 		/* TODO: Should this be a separate error? */
2491341Sstevel 		AC_ERR_SET(pkt, AC_ERR_KPM_NONRELOC);
2501341Sstevel 		return (EINVAL);
2511341Sstevel 	}
2521341Sstevel 
2531341Sstevel 	/*
2541341Sstevel 	 * Add to delete memory list.
2551341Sstevel 	 */
2561341Sstevel 
2571341Sstevel 	if ((errs = kphysm_del_span(handle, base, npgs)) != KPHYSM_OK) {
2581341Sstevel 		AC_ERR_SET(pkt, ac_kpm_err_cvt(errs));
2591341Sstevel 		/*
2601341Sstevel 		 * Restore the pages to the cage growth list.
2611341Sstevel 		 * TODO: We should not unconditionally add back
2621341Sstevel 		 * if we conditionally add at memory add time.
2631341Sstevel 		 */
264*4266Sdp78419 		errs = kcage_range_add(base, npgs, KCAGE_DOWN);
2651341Sstevel 		/* TODO: deal with error return. */
2661341Sstevel 		if (errs != 0) {
2671341Sstevel 			AC_ERR_SET(pkt, ac_kpm_err_cvt(errs));
2681341Sstevel 			cmn_err(CE_NOTE, "ac_del_bank_add_span(): "
2691341Sstevel 			    "board %d, bank %d, "
2701341Sstevel 			    "kcage_range_add() returned %d",
2711341Sstevel 			    pkt->softsp->board, pkt->bank, errs);
2721341Sstevel 		}
2731341Sstevel 		return (EINVAL);
2741341Sstevel 	}
2751341Sstevel 	return (0);
2761341Sstevel }
2771341Sstevel 
2781341Sstevel static void
ac_del_bank_add_cage(struct bd_list * del,enum ac_bank_id bank)2791341Sstevel ac_del_bank_add_cage(
2801341Sstevel 	struct bd_list *del,
2811341Sstevel 	enum ac_bank_id bank)
2821341Sstevel {
2831341Sstevel 	uint64_t		decode;
2841341Sstevel 	uint64_t		base_pa;
2851341Sstevel 	uint64_t		bank_size;
2861341Sstevel 	pfn_t			base;
2871341Sstevel 	pgcnt_t			npgs;
2881341Sstevel 	int			errs;
2891341Sstevel 	struct ac_soft_state	*asp = (struct ac_soft_state *)(del->ac_softsp);
2901341Sstevel 
2911341Sstevel 	/*
2921341Sstevel 	 * Determine the physical location of the selected bank
2931341Sstevel 	 */
2941341Sstevel 	decode = (bank == Bank0) ? *asp->ac_memdecode0 : *asp->ac_memdecode1;
2951341Sstevel 	base_pa = GRP_REALBASE(decode);
2961341Sstevel 	bank_size = GRP_UK2SPAN(decode);
2971341Sstevel 
2981341Sstevel 	base = base_pa >> PAGESHIFT;
2991341Sstevel 	npgs = bank_size >> PAGESHIFT;
3001341Sstevel 
3011341Sstevel 	/*
3021341Sstevel 	 * Restore the pages to the cage growth list.
3031341Sstevel 	 * TODO: We should not unconditionally add back
3041341Sstevel 	 * if we conditionally add at memory add time.
3051341Sstevel 	 */
306*4266Sdp78419 	errs = kcage_range_add(base, npgs, KCAGE_DOWN);
3071341Sstevel 	/* TODO: deal with error return. */
3081341Sstevel 	if (errs != 0)
3091341Sstevel 		cmn_err(CE_NOTE, "ac_del_bank_add_cage(): "
3101341Sstevel 		    "board %d, bank %d, "
3111341Sstevel 		    "kcage_range_add() returned %d",
3121341Sstevel 		    del->sc.board, bank, errs);
3131341Sstevel }
3141341Sstevel 
3151341Sstevel static int
ac_del_bank_run(struct del_status * dsp,ac_cfga_pkt_t * pkt)3161341Sstevel ac_del_bank_run(struct del_status *dsp, ac_cfga_pkt_t *pkt)
3171341Sstevel {
3181341Sstevel 	int errs;
3191341Sstevel 
3201341Sstevel 	dsp->its_done = 0;
3211341Sstevel 	if ((errs = kphysm_del_start(dsp->handle, del_comp, (void *)dsp)) !=
3221341Sstevel 	    KPHYSM_OK) {
3231341Sstevel 		AC_ERR_SET(pkt, ac_kpm_err_cvt(errs));
3241341Sstevel 		return (EINVAL);
3251341Sstevel 	}
3261341Sstevel 	/* Wait for it to complete. */
3271341Sstevel 	mutex_enter(&ac_del_mutex);
3281341Sstevel 	del_to_start(dsp);
3291341Sstevel 	while (!dsp->its_done) {
3301341Sstevel 		if (!cv_wait_sig(&dsp->ac_del_cv, &ac_del_mutex)) {
3311341Sstevel 			if (dsp->cancel_code == 0)
3321341Sstevel 				dsp->cancel_code = AC_ERR_INTR;
3331341Sstevel 			mutex_exit(&ac_del_mutex);
3341341Sstevel 			errs = kphysm_del_cancel(dsp->handle);
3351341Sstevel 			mutex_enter(&ac_del_mutex);
3361341Sstevel 			if (errs != KPHYSM_OK) {
3371341Sstevel 				ASSERT(errs == KPHYSM_ENOTRUNNING);
3381341Sstevel 			}
3391341Sstevel 			break;
3401341Sstevel 		}
3411341Sstevel 	}
3421341Sstevel 	/*
3431341Sstevel 	 * If the loop exited due to a signal, we must continue to wait
3441341Sstevel 	 * using cv_wait() as the signal is pending until syscall exit.
3451341Sstevel 	 */
3461341Sstevel 	while (!dsp->its_done) {
3471341Sstevel 		cv_wait(&dsp->ac_del_cv, &ac_del_mutex);
3481341Sstevel 	}
3491341Sstevel 	if (dsp->done_error != KPHYSM_OK) {
3501341Sstevel 		AC_ERR_SET(pkt, ac_kpm_err_cvt(dsp->done_error));
3511341Sstevel 		if ((dsp->done_error == KPHYSM_ECANCELLED) ||
3521341Sstevel 		    (dsp->done_error == KPHYSM_EREFUSED)) {
3531341Sstevel 			errs = EINTR;
3541341Sstevel 			if (dsp->cancel_code != 0) {
3551341Sstevel 				AC_ERR_SET(pkt, dsp->cancel_code);
3561341Sstevel 			}
3571341Sstevel 		} else {
3581341Sstevel 			errs = EINVAL;
3591341Sstevel 		}
3601341Sstevel 	} else
3611341Sstevel 		errs = 0;
3621341Sstevel 	del_to_stop(dsp);
3631341Sstevel 	mutex_exit(&ac_del_mutex);
3641341Sstevel 
3651341Sstevel 	return (errs);
3661341Sstevel }
3671341Sstevel 
3681341Sstevel 
3691341Sstevel /*
3701341Sstevel  * set the memory to known state for debugging
3711341Sstevel  */
3721341Sstevel static void
ac_bank_write_pattern(struct bd_list * del,enum ac_bank_id bank)3731341Sstevel ac_bank_write_pattern(struct bd_list *del, enum ac_bank_id bank)
3741341Sstevel {
3751341Sstevel 	uint64_t		decode;
3761341Sstevel 	uint64_t		base_pa;
3771341Sstevel 	uint64_t		limit_pa;
3781341Sstevel 	uint64_t		bank_size;
3791341Sstevel 	uint64_t		current_pa;
3801341Sstevel 	caddr_t			base_va;
3811341Sstevel 	caddr_t			fill_buf;
3821341Sstevel 	struct ac_soft_state	*asp = (struct ac_soft_state *)(del->ac_softsp);
3831341Sstevel 	int			linesize;
3841341Sstevel 
3851341Sstevel 	/*
3861341Sstevel 	 * Determine the physical location of the selected bank
3871341Sstevel 	 */
3881341Sstevel 	decode = (bank == Bank0) ? *asp->ac_memdecode0 : *asp->ac_memdecode1;
3891341Sstevel 	base_pa = GRP_REALBASE(decode);
3901341Sstevel 	bank_size = GRP_UK2SPAN(decode);
3911341Sstevel 	limit_pa = base_pa + bank_size;
3921341Sstevel 	linesize = cpunodes[CPU->cpu_id].ecache_linesize;
3931341Sstevel 
3941341Sstevel 	/*
3951341Sstevel 	 * We need a page_va and a fill buffer for this operation
3961341Sstevel 	 */
3971341Sstevel 	base_va = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP);
3981341Sstevel 	fill_buf = kmem_zalloc(DEL_PAGESIZE, KM_SLEEP);
3991341Sstevel 	{
4001341Sstevel 		typedef uint32_t patt_t;
4011341Sstevel 		patt_t *bf, *bfe, patt;
4021341Sstevel 
4031341Sstevel 		bf = (patt_t *)fill_buf;
4041341Sstevel 		bfe = (patt_t *)((char *)fill_buf + DEL_PAGESIZE);
4051341Sstevel 		patt = 0xbeaddeed;
4061341Sstevel 		while (bf < bfe)
4071341Sstevel 			*bf++ = patt;
4081341Sstevel 	}
4091341Sstevel 
4101341Sstevel 	/*
4111341Sstevel 	 * 'empty' the memory
4121341Sstevel 	 */
4131341Sstevel 	kpreempt_disable();
4141341Sstevel 	for (current_pa = base_pa; current_pa < limit_pa;
4151341Sstevel 	    current_pa += DEL_PAGESIZE) {
4161341Sstevel 
4171341Sstevel 		/* map current pa */
4181341Sstevel 		ac_mapin(current_pa, base_va);
4191341Sstevel 
4201341Sstevel 		/* fill the target page */
4211341Sstevel 		ac_blkcopy(fill_buf, base_va,
4221341Sstevel 			DEL_PAGESIZE/linesize, linesize);
4231341Sstevel 
4241341Sstevel 		/* tear down translation */
4251341Sstevel 		ac_unmap(base_va);
4261341Sstevel 	}
4271341Sstevel 	kpreempt_enable();
4281341Sstevel 
4291341Sstevel 	/*
4301341Sstevel 	 * clean up temporary resources
4311341Sstevel 	 */
4321341Sstevel 	{
4331341Sstevel 		/* Distinguish the fill buf from memory deleted! */
4341341Sstevel 		typedef uint32_t patt_t;
4351341Sstevel 		patt_t *bf, *bfe, patt;
4361341Sstevel 
4371341Sstevel 		bf = (patt_t *)fill_buf;
4381341Sstevel 		bfe = (patt_t *)((char *)fill_buf + DEL_PAGESIZE);
4391341Sstevel 		patt = 0xbeadfeed;
4401341Sstevel 		while (bf < bfe)
4411341Sstevel 			*bf++ = patt;
4421341Sstevel 	}
4431341Sstevel 	kmem_free(fill_buf, DEL_PAGESIZE);
4441341Sstevel 	vmem_free(heap_arena, base_va, PAGESIZE);
4451341Sstevel }
4461341Sstevel 
4471341Sstevel int
ac_del_memory(ac_cfga_pkt_t * pkt)4481341Sstevel ac_del_memory(ac_cfga_pkt_t *pkt)
4491341Sstevel {
4501341Sstevel 	struct bd_list *board;
4511341Sstevel 	struct ac_mem_info *mem_info;
4521341Sstevel 	int busy_set;
4531341Sstevel 	struct del_status *dsp;
4541341Sstevel 	memdelstat_t dstat;
4551341Sstevel 	int retval;
4561341Sstevel 	int r_errs;
4571341Sstevel 	struct ac_soft_state *asp;
4581341Sstevel 
4591341Sstevel 	if (!kcage_on) {
4601341Sstevel 		static int cage_msg_done = 0;
4611341Sstevel 
4621341Sstevel 		if (!cage_msg_done) {
4631341Sstevel 			cage_msg_done = 1;
4641341Sstevel 			cmn_err(CE_NOTE, "ac: memory delete"
4651341Sstevel 			    " refused: cage is off");
4661341Sstevel 		}
4671341Sstevel 		AC_ERR_SET(pkt, ac_kpm_err_cvt(KPHYSM_ENONRELOC));
4681341Sstevel 		return (EINVAL);
4691341Sstevel 	}
4701341Sstevel 
4711341Sstevel 	dsp = ac_del_alloc_status();
4721341Sstevel 	if ((retval = kphysm_del_gethandle(&dsp->handle)) != KPHYSM_OK) {
4731341Sstevel 		ac_del_free_status(dsp);
4741341Sstevel 		AC_ERR_SET(pkt, ac_kpm_err_cvt(retval));
4751341Sstevel 		return (EINVAL);
4761341Sstevel 	}
4771341Sstevel 	retval = 0;
4781341Sstevel 	busy_set = 0;
4791341Sstevel 
4801341Sstevel 	board = fhc_bdlist_lock(pkt->softsp->board);
4811341Sstevel 	if (board == NULL || board->ac_softsp == NULL) {
4821341Sstevel 		fhc_bdlist_unlock();
4831341Sstevel 		AC_ERR_SET(pkt, AC_ERR_BD);
4841341Sstevel 		retval = EINVAL;
4851341Sstevel 		goto out;
4861341Sstevel 	}
4871341Sstevel 	ASSERT(pkt->softsp == board->ac_softsp);
4881341Sstevel 	asp = pkt->softsp;
4891341Sstevel 
4901341Sstevel 	/* verify the board is of the correct type */
4911341Sstevel 	switch (board->sc.type) {
4921341Sstevel 	case CPU_BOARD:
4931341Sstevel 	case MEM_BOARD:
4941341Sstevel 		break;
4951341Sstevel 	default:
4961341Sstevel 		fhc_bdlist_unlock();
4971341Sstevel 		AC_ERR_SET(pkt, AC_ERR_BD_TYPE);
4981341Sstevel 		retval = EINVAL;
4991341Sstevel 		goto out;
5001341Sstevel 	}
5011341Sstevel 
5021341Sstevel 	/* verify the memory condition is acceptable */
5031341Sstevel 	mem_info = &asp->bank[pkt->bank];
5041341Sstevel 	if (!MEM_BOARD_VISIBLE(board) || mem_info->busy ||
5051341Sstevel 	    fhc_bd_busy(pkt->softsp->board) ||
5061341Sstevel 	    mem_info->rstate != SYSC_CFGA_RSTATE_CONNECTED ||
5071341Sstevel 	    mem_info->ostate != SYSC_CFGA_OSTATE_CONFIGURED) {
5081341Sstevel 		fhc_bdlist_unlock();
5091341Sstevel 		AC_ERR_SET(pkt, AC_ERR_BD_STATE);
5101341Sstevel 		retval = EINVAL;
5111341Sstevel 		goto out;
5121341Sstevel 	}
5131341Sstevel 
5141341Sstevel 	if ((dsp->del_timeout = pkt->cmd_cfga.arg) == -1)
5151341Sstevel 		dsp->del_timeout = ac_del_timeout;
5161341Sstevel 
5171341Sstevel 	/*
5181341Sstevel 	 * at this point, we have an available bank to del.
5191341Sstevel 	 * mark it busy and initiate the del function.
5201341Sstevel 	 */
5211341Sstevel 	mem_info->busy = TRUE;
5221341Sstevel 	fhc_bdlist_unlock();
5231341Sstevel 
5241341Sstevel 	busy_set = 1;
5251341Sstevel 
5261341Sstevel 	retval = ac_del_bank_add_span(dsp->handle, pkt);
5271341Sstevel out:
5281341Sstevel 	if (retval != 0) {
5291341Sstevel 		r_errs = kphysm_del_release(dsp->handle);
5301341Sstevel 		ASSERT(r_errs == KPHYSM_OK);
5311341Sstevel 
5321341Sstevel 		if (busy_set) {
5331341Sstevel 			board = fhc_bdlist_lock(pkt->softsp->board);
5341341Sstevel 			ASSERT(board != NULL && board->ac_softsp != NULL);
5351341Sstevel 
5361341Sstevel 			ASSERT(board->sc.type == CPU_BOARD ||
5371341Sstevel 			    board->sc.type == MEM_BOARD);
5381341Sstevel 			ASSERT(asp ==
5391341Sstevel 			    (struct ac_soft_state *)(board->ac_softsp));
5401341Sstevel 			mem_info = &asp->bank[pkt->bank];
5411341Sstevel 			ASSERT(mem_info->busy != FALSE);
5421341Sstevel 			ASSERT(mem_info->ostate == SYSC_CFGA_OSTATE_CONFIGURED);
5431341Sstevel 			mem_info->busy = FALSE;
5441341Sstevel 			fhc_bdlist_unlock();
5451341Sstevel 		}
5461341Sstevel 
5471341Sstevel 		ac_del_free_status(dsp);
5481341Sstevel 		return (retval);
5491341Sstevel 	}
5501341Sstevel 
5511341Sstevel 	(void) kphysm_del_status(dsp->handle, &dstat);
5521341Sstevel 
5531341Sstevel 	retval = ac_del_bank_run(dsp, pkt);
5541341Sstevel 
5551341Sstevel 	r_errs = kphysm_del_release(dsp->handle);
5561341Sstevel 	ASSERT(r_errs == KPHYSM_OK);
5571341Sstevel 
5581341Sstevel 	board = fhc_bdlist_lock(pkt->softsp->board);
5591341Sstevel 	ASSERT(board != NULL && board->ac_softsp != NULL);
5601341Sstevel 
5611341Sstevel 	ASSERT(board->sc.type == CPU_BOARD || board->sc.type == MEM_BOARD);
5621341Sstevel 	ASSERT(asp == (struct ac_soft_state *)(board->ac_softsp));
5631341Sstevel 	mem_info = &asp->bank[pkt->bank];
5641341Sstevel 	ASSERT(mem_info->busy != FALSE);
5651341Sstevel 	ASSERT(mem_info->ostate == SYSC_CFGA_OSTATE_CONFIGURED);
5661341Sstevel 	mem_info->busy = FALSE;
5671341Sstevel 	if (retval == 0) {
5681341Sstevel 		mem_info->ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
5691341Sstevel 		mem_info->status_change = ddi_get_time();
5701341Sstevel 
5711341Sstevel 		if (ac_del_clean) {
5721341Sstevel 			/* DEBUG - set memory to known state */
5731341Sstevel 			ac_bank_write_pattern(board, pkt->bank);
5741341Sstevel 		}
5751341Sstevel 	} else {
5761341Sstevel 		/*
5771341Sstevel 		 * Restore the pages to the cage growth list.
5781341Sstevel 		 */
5791341Sstevel 		ac_del_bank_add_cage(board, pkt->bank);
5801341Sstevel 	}
5811341Sstevel 	fhc_bdlist_unlock();
5821341Sstevel 
5831341Sstevel 	ac_del_free_status(dsp);
5841341Sstevel 
5851341Sstevel 	return (retval);
5861341Sstevel }
587