/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 1998 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern ac_err_t ac_kpm_err_cvt(int); #ifdef DEBUG static void query_checker(pfn_t, pgcnt_t, memquery_t *); static int ac_do_query_check = 0; #endif /* DEBUG */ int ac_mem_stat(ac_cfga_pkt_t *pkt, int flag) { ac_stat_t *statp; memquery_t memq; struct ac_mem_info *mem_info; struct bd_list *board; struct ac_soft_state *ac; uint64_t decode; uint64_t base_pa; uint64_t bank_size; pfn_t base; pgcnt_t npgs; int ret; int retval; /* * Is the specified bank present? */ board = fhc_bdlist_lock(pkt->softsp->board); if (board == NULL || board->ac_softsp == NULL) { fhc_bdlist_unlock(); AC_ERR_SET(pkt, AC_ERR_BD); return (EINVAL); } /* verify the board is of the correct type */ switch (board->sc.type) { case CPU_BOARD: case MEM_BOARD: break; default: fhc_bdlist_unlock(); AC_ERR_SET(pkt, AC_ERR_BD_TYPE); return (EINVAL); } ASSERT(pkt->softsp == board->ac_softsp); ac = pkt->softsp; mem_info = &ac->bank[pkt->bank]; statp = kmem_zalloc(sizeof (ac_stat_t), KM_SLEEP); statp->rstate = mem_info->rstate; statp->ostate = mem_info->ostate; statp->condition = mem_info->condition; statp->status_time = mem_info->status_change; statp->board = ac->board; statp->real_size = mem_info->real_size; statp->use_size = mem_info->use_size; statp->ac_memctl = *(ac->ac_memctl); statp->ac_decode0 = *(ac->ac_memdecode0); statp->ac_decode1 = *(ac->ac_memdecode1); statp->page_size = PAGESIZE; /* * Busy could also be set for fhc_bd_busy(ac->board) * however, this is just advisory information so limit it * to memory operation in progress. */ statp->busy = (mem_info->busy != FALSE); /* * Determine the physical location of the selected bank */ decode = (pkt->bank == Bank0) ? *(ac->ac_memdecode0) : *(ac->ac_memdecode1); base_pa = GRP_REALBASE(decode); bank_size = GRP_UK2SPAN(decode); base = base_pa >> PAGESHIFT; npgs = bank_size >> PAGESHIFT; if (mem_info->ostate == SYSC_CFGA_OSTATE_CONFIGURED) { bzero(&memq, sizeof (memq)); ret = kphysm_del_span_query(base, npgs, &memq); if (ret != KPHYSM_OK) { fhc_bdlist_unlock(); AC_ERR_SET(pkt, ac_kpm_err_cvt(ret)); retval = EINVAL; goto out; } #ifdef DEBUG if (ac_do_query_check) { query_checker(base, npgs, &memq); if (memq.phys_pages != npgs) { /* * This can happen in normal concurrent * operation. */ cmn_err(CE_WARN, "ac_mem_stat(): " "memq.phys_pages != npgs (%ld != %ld)", (u_long)memq.phys_pages, (u_long)npgs); } } #endif /* DEBUG */ statp->phys_pages = memq.phys_pages; statp->managed = memq.managed; if (!kcage_on) statp->nonrelocatable = memq.phys_pages; else statp->nonrelocatable = memq.nonrelocatable; } else if (mem_info->rstate == SYSC_CFGA_RSTATE_CONNECTED) { /* Bank is in state Spare */ statp->phys_pages = npgs; } fhc_bdlist_unlock(); retval = DDI_SUCCESS; /* return the information to the user */ #ifdef _MULTI_DATAMODEL switch (ddi_model_convert_from(flag & FMODELS)) { case DDI_MODEL_ILP32: { ac_stat32_t *stat32p; stat32p = kmem_zalloc(sizeof (ac_stat32_t), KM_SLEEP); stat32p->rstate = statp->rstate; stat32p->ostate = statp->ostate; stat32p->condition = statp->condition; stat32p->status_time = (time32_t)statp->status_time; stat32p->board = statp->board; stat32p->real_size = statp->real_size; stat32p->use_size = statp->use_size; stat32p->busy = statp->busy; stat32p->page_size = statp->page_size; stat32p->phys_pages = statp->phys_pages; stat32p->managed = statp->managed; stat32p->nonrelocatable = statp->nonrelocatable; stat32p->ac_memctl = statp->ac_memctl; stat32p->ac_decode0 = statp->ac_decode0; stat32p->ac_decode1 = statp->ac_decode1; if (ddi_copyout(stat32p, pkt->cmd_cfga.private, sizeof (ac_stat32_t), flag) != 0) { retval = EFAULT; } kmem_free(stat32p, sizeof (ac_stat32_t)); break; } case DDI_MODEL_NONE: if (ddi_copyout(statp, pkt->cmd_cfga.private, sizeof (ac_stat_t), flag) != 0) { retval = EFAULT; } break; } #else /* _MULTI_DATAMODEL */ if (ddi_copyout(statp, pkt->cmd_cfga.private, sizeof (ac_stat_t), flag) != 0) { retval = EFAULT; } #endif /* _MULTI_DATAMODEL */ out: kmem_free(statp, sizeof (ac_stat_t)); return (retval); } #ifdef DEBUG static void query_checker( pfn_t base, pgcnt_t npgs, memquery_t *mqp) { memquery_t memq; memquery_t amemq; int done_first_nonreloc; int all_pop; pfn_t abase; pgcnt_t n; int ret; all_pop = (mqp->phys_pages == npgs); memq.phys_pages = 0; memq.managed = 0; memq.nonrelocatable = 0; memq.first_nonrelocatable = 0; memq.last_nonrelocatable = 0; done_first_nonreloc = 0; for (abase = base, n = npgs; n != 0; abase++, n--) { ret = kphysm_del_span_query(abase, 1, &amemq); if (ret != KPHYSM_OK) { printf("%ld: ret = %d\n", abase, ret); continue; } if (all_pop && amemq.phys_pages != 1) { printf("%ld: phys_pages = %ld, expected 1\n", abase, amemq.phys_pages); } else if (amemq.phys_pages != 0 && amemq.phys_pages != 1) { printf("%ld: phys_pages = %ld, expected 0 or 1\n", abase, amemq.phys_pages); } memq.phys_pages += amemq.phys_pages; if (amemq.managed != 0 && amemq.managed != 1) { printf("%ld: managed = %ld, expected 0 or 1\n", abase, amemq.managed); } memq.managed += amemq.managed; if (amemq.nonrelocatable != 0 && amemq.nonrelocatable != 1) { printf("%ld: nonrelocatable = %ld, expected 0 or 1\n", abase, amemq.nonrelocatable); } memq.nonrelocatable += amemq.nonrelocatable; if (amemq.nonrelocatable != 0) { if (amemq.first_nonrelocatable != abase) { printf("%ld: first_nonrelocatable = %ld\n", abase, amemq.first_nonrelocatable); } if (amemq.last_nonrelocatable != abase) { printf("%ld: last_nonrelocatable = %ld\n", abase, amemq.last_nonrelocatable); } if (!done_first_nonreloc) { memq.first_nonrelocatable = abase; done_first_nonreloc = 1; } memq.last_nonrelocatable = abase; } } if (mqp->phys_pages != memq.phys_pages) { printf("query phys_pages: %ld != %ld\n", mqp->phys_pages, memq.phys_pages); } if (mqp->managed != memq.managed) { printf("query managed: %ld != %ld\n", mqp->managed, memq.managed); } if (mqp->nonrelocatable != memq.nonrelocatable) { printf("query nonrelocatable: %ld != %ld\n", mqp->nonrelocatable, memq.nonrelocatable); } if (mqp->first_nonrelocatable != memq.first_nonrelocatable) { printf("query first_nonrelocatable: %ld != %ld\n", mqp->first_nonrelocatable, memq.first_nonrelocatable); } if (mqp->last_nonrelocatable != memq.last_nonrelocatable) { printf("query last_nonrelocatable: %ld != %ld\n", mqp->last_nonrelocatable, memq.last_nonrelocatable); } } #endif /* DEBUG */