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