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