17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
585f58038Sdp78419 * Common Development and Distribution License (the "License").
685f58038Sdp78419 * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
2107d06da5SSurya Prakki
227c478bd9Sstevel@tonic-gate /*
23*56f33205SJonathan Adams * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate * memory support routines for sbd.
297c478bd9Sstevel@tonic-gate */
307c478bd9Sstevel@tonic-gate
317c478bd9Sstevel@tonic-gate #include <sys/debug.h>
327c478bd9Sstevel@tonic-gate #include <sys/types.h>
337c478bd9Sstevel@tonic-gate #include <sys/errno.h>
347c478bd9Sstevel@tonic-gate #include <sys/param.h>
357c478bd9Sstevel@tonic-gate #include <sys/dditypes.h>
367c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
377c478bd9Sstevel@tonic-gate #include <sys/conf.h>
387c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
397c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
407c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
417c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
427c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
437c478bd9Sstevel@tonic-gate #include <sys/machsystm.h>
447c478bd9Sstevel@tonic-gate #include <sys/spitregs.h>
457c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
467c478bd9Sstevel@tonic-gate #include <sys/cpu_module.h>
477c478bd9Sstevel@tonic-gate #include <sys/promif.h>
487c478bd9Sstevel@tonic-gate #include <sys/memlist_impl.h>
497c478bd9Sstevel@tonic-gate #include <sys/mem_cage.h>
507c478bd9Sstevel@tonic-gate #include <sys/lgrp.h>
517c478bd9Sstevel@tonic-gate #include <sys/platform_module.h>
527c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h>
537c478bd9Sstevel@tonic-gate
547c478bd9Sstevel@tonic-gate #include <sys/sbdpriv.h>
557c478bd9Sstevel@tonic-gate
567c478bd9Sstevel@tonic-gate #define _ptob64(p) ((uint64_t)(p) << PAGESHIFT)
577c478bd9Sstevel@tonic-gate #define _b64top(b) ((pgcnt_t)((b) >> PAGESHIFT))
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate static int sbd_post_detach_mem_unit(sbd_mem_unit_t *mp,
607c478bd9Sstevel@tonic-gate sbderror_t *ep);
617c478bd9Sstevel@tonic-gate static int sbd_reserve_mem_spans(memhandle_t *mhp,
627c478bd9Sstevel@tonic-gate struct memlist *mlist);
637c478bd9Sstevel@tonic-gate static int sbd_check_boundaries(struct memlist *orig_memlist,
647c478bd9Sstevel@tonic-gate sbd_mem_unit_t *s_mp,
657c478bd9Sstevel@tonic-gate sbd_mem_unit_t *t_mp);
667c478bd9Sstevel@tonic-gate static int sbd_select_mem_target(sbd_handle_t *hp,
677c478bd9Sstevel@tonic-gate sbd_mem_unit_t *mp, struct memlist *ml);
687c478bd9Sstevel@tonic-gate static void sbd_init_mem_unit_data(sbd_mem_unit_t *mp, sbderror_t
697c478bd9Sstevel@tonic-gate *ep);
707c478bd9Sstevel@tonic-gate static int memlist_canfit(struct memlist *s_mlist,
717c478bd9Sstevel@tonic-gate struct memlist *t_mlist);
727c478bd9Sstevel@tonic-gate static void sbd_mem_cleanup(sbd_mem_unit_t *s_mp,
737c478bd9Sstevel@tonic-gate sbd_mem_unit_t *t_mp, sbderror_t *ep);
747c478bd9Sstevel@tonic-gate static void sbd_flush_ecache(uint64_t a, uint64_t b);
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gate struct memlist *
sbd_get_memlist(sbd_mem_unit_t * mp,sbderror_t * ep)777c478bd9Sstevel@tonic-gate sbd_get_memlist(sbd_mem_unit_t *mp, sbderror_t *ep)
787c478bd9Sstevel@tonic-gate {
797c478bd9Sstevel@tonic-gate struct memlist *mlist;
807c478bd9Sstevel@tonic-gate static fn_t f = "sbd_get_memlist";
817c478bd9Sstevel@tonic-gate sbd_board_t *sbp = (sbd_board_t *)mp->sbm_cm.sbdev_sbp;
827c478bd9Sstevel@tonic-gate sbdp_handle_t *hdp;
837c478bd9Sstevel@tonic-gate sbd_handle_t *hp = MACHBD2HD(sbp);
847c478bd9Sstevel@tonic-gate
857c478bd9Sstevel@tonic-gate PR_MEM("%s...\n", f);
867c478bd9Sstevel@tonic-gate
877c478bd9Sstevel@tonic-gate /*
887c478bd9Sstevel@tonic-gate * Return cached memlist, if present.
897c478bd9Sstevel@tonic-gate * This memlist will be present following an
907c478bd9Sstevel@tonic-gate * unconfigure (a.k.a: detach) of this memunit.
917c478bd9Sstevel@tonic-gate * It should only be used in the case were a configure
927c478bd9Sstevel@tonic-gate * is bringing this memunit back in without going
937c478bd9Sstevel@tonic-gate * through the disconnect and connect states.
947c478bd9Sstevel@tonic-gate */
957c478bd9Sstevel@tonic-gate if (mp->sbm_mlist) {
967c478bd9Sstevel@tonic-gate PR_MEM("%s: found cached memlist\n", f);
977c478bd9Sstevel@tonic-gate
987c478bd9Sstevel@tonic-gate mlist = memlist_dup(mp->sbm_mlist);
997c478bd9Sstevel@tonic-gate } else {
1007c478bd9Sstevel@tonic-gate /* attempt to construct a memlist using phys_install */
1017c478bd9Sstevel@tonic-gate
1027c478bd9Sstevel@tonic-gate /*
1037c478bd9Sstevel@tonic-gate * NOTE: this code block assumes only one memunit per
1047c478bd9Sstevel@tonic-gate * board. This is currently safe because the function
1057c478bd9Sstevel@tonic-gate * sbd_init_mem_devlist() forces this assumption to be
1067c478bd9Sstevel@tonic-gate * valid.
1077c478bd9Sstevel@tonic-gate */
1087c478bd9Sstevel@tonic-gate
1097c478bd9Sstevel@tonic-gate /* round down to slice base address */
1107c478bd9Sstevel@tonic-gate /* build mlist from the lower layer */
1117c478bd9Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp);
1127c478bd9Sstevel@tonic-gate mlist = sbdp_get_memlist(hdp, mp->sbm_cm.sbdev_dip);
1137c478bd9Sstevel@tonic-gate if (mlist == NULL) {
1147c478bd9Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep);
1157c478bd9Sstevel@tonic-gate PR_MEM("sbd:%s: failed to get memlist for "
1167c478bd9Sstevel@tonic-gate "dip (0x%p) ecode %d errno %d", f,
1177c478bd9Sstevel@tonic-gate (void *)mp->sbm_cm.sbdev_dip,
1187c478bd9Sstevel@tonic-gate ep->e_code, ep->e_errno);
1197c478bd9Sstevel@tonic-gate sbd_release_sbdp_handle(hdp);
1207c478bd9Sstevel@tonic-gate return (NULL);
1217c478bd9Sstevel@tonic-gate }
1227c478bd9Sstevel@tonic-gate sbd_release_sbdp_handle(hdp);
1237c478bd9Sstevel@tonic-gate }
1247c478bd9Sstevel@tonic-gate
1257c478bd9Sstevel@tonic-gate PR_MEM("%s: memlist for mem-unit (%d.%d), dip 0x%p:\n",
1267c478bd9Sstevel@tonic-gate f, sbp->sb_num,
1277c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_unum,
1287c478bd9Sstevel@tonic-gate (void *)mp->sbm_cm.sbdev_dip);
1297c478bd9Sstevel@tonic-gate SBD_MEMLIST_DUMP(mlist);
1307c478bd9Sstevel@tonic-gate
1317c478bd9Sstevel@tonic-gate return (mlist);
1327c478bd9Sstevel@tonic-gate }
1337c478bd9Sstevel@tonic-gate
1347c478bd9Sstevel@tonic-gate int
sbd_pre_attach_mem(sbd_handle_t * hp,sbd_devlist_t devlist[],int devnum)1357c478bd9Sstevel@tonic-gate sbd_pre_attach_mem(sbd_handle_t *hp, sbd_devlist_t devlist[], int devnum)
1367c478bd9Sstevel@tonic-gate {
1377c478bd9Sstevel@tonic-gate int err_flag = 0;
1387c478bd9Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp);
1397c478bd9Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd);
1407c478bd9Sstevel@tonic-gate int d, i;
1417c478bd9Sstevel@tonic-gate sbdp_handle_t *hdp;
1427c478bd9Sstevel@tonic-gate static fn_t f = "sbd_pre_attach_mem";
1437c478bd9Sstevel@tonic-gate
1447c478bd9Sstevel@tonic-gate PR_MEM("%s...\n", f);
1457c478bd9Sstevel@tonic-gate
1467c478bd9Sstevel@tonic-gate SBD_SET_ERR(ep, 0);
1477c478bd9Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp);
1487c478bd9Sstevel@tonic-gate
1497c478bd9Sstevel@tonic-gate for (d = 0; d < devnum; d++) {
1507c478bd9Sstevel@tonic-gate sbd_mem_unit_t *mp;
1517c478bd9Sstevel@tonic-gate int unit;
1527c478bd9Sstevel@tonic-gate dev_info_t *dip;
1537c478bd9Sstevel@tonic-gate sbd_istate_t state;
1547c478bd9Sstevel@tonic-gate int rv;
1557c478bd9Sstevel@tonic-gate
1567c478bd9Sstevel@tonic-gate /* sbd_get_devlist will not devlist element w/ dip of 0 */
1577c478bd9Sstevel@tonic-gate ASSERT(devlist[d].dv_dip != NULL);
1587c478bd9Sstevel@tonic-gate
1597c478bd9Sstevel@tonic-gate dip = devlist[d].dv_dip;
1607c478bd9Sstevel@tonic-gate unit = sbdp_get_unit_num(hdp, dip);
1617c478bd9Sstevel@tonic-gate if (unit == -1) {
1627c478bd9Sstevel@tonic-gate if (hp->h_flags & SBD_IOCTL_FLAG_FORCE)
1637c478bd9Sstevel@tonic-gate continue;
1647c478bd9Sstevel@tonic-gate else {
1657c478bd9Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep);
1667c478bd9Sstevel@tonic-gate err_flag = 1;
1677c478bd9Sstevel@tonic-gate break;
1687c478bd9Sstevel@tonic-gate }
1697c478bd9Sstevel@tonic-gate }
1707c478bd9Sstevel@tonic-gate
1717c478bd9Sstevel@tonic-gate mp = SBD_GET_BOARD_MEMUNIT(sbp, unit);
1727c478bd9Sstevel@tonic-gate
1737c478bd9Sstevel@tonic-gate ASSERT(mp->sbm_cm.sbdev_sbp == sbp);
1747c478bd9Sstevel@tonic-gate ASSERT(unit == mp->sbm_cm.sbdev_unum);
1757c478bd9Sstevel@tonic-gate
1767c478bd9Sstevel@tonic-gate PR_MEM("sbd: OS attach mem-unit (%d.%d)\n",
1777c478bd9Sstevel@tonic-gate sbp->sb_num,
1787c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_unum);
1797c478bd9Sstevel@tonic-gate
1807c478bd9Sstevel@tonic-gate state = mp->sbm_cm.sbdev_state;
1817c478bd9Sstevel@tonic-gate switch (state) {
1827c478bd9Sstevel@tonic-gate case SBD_STATE_UNCONFIGURED:
1837c478bd9Sstevel@tonic-gate /* use memlist cached by sbd_post_detach_mem_unit */
1847c478bd9Sstevel@tonic-gate if (mp->sbm_mlist != NULL) {
1857c478bd9Sstevel@tonic-gate PR_MEM("%s: recovering from UNCONFIG"
1867c478bd9Sstevel@tonic-gate " mem-unit (%d.%d)\n",
1877c478bd9Sstevel@tonic-gate f, sbp->sb_num,
1887c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_unum);
1897c478bd9Sstevel@tonic-gate
1907c478bd9Sstevel@tonic-gate PR_MEM("%s: re-configure cached memlist:\n", f);
1917c478bd9Sstevel@tonic-gate SBD_MEMLIST_DUMP(mp->sbm_mlist);
1927c478bd9Sstevel@tonic-gate
1937c478bd9Sstevel@tonic-gate /*
1947c478bd9Sstevel@tonic-gate * kphysm del handle should have been freed
1957c478bd9Sstevel@tonic-gate */
1967c478bd9Sstevel@tonic-gate ASSERT((mp->sbm_flags & SBD_MFLAG_RELOWNER)
1977c478bd9Sstevel@tonic-gate == 0);
1987c478bd9Sstevel@tonic-gate } else {
1997c478bd9Sstevel@tonic-gate if (hp->h_flags & SBD_IOCTL_FLAG_FORCE)
2007c478bd9Sstevel@tonic-gate continue;
2017c478bd9Sstevel@tonic-gate else {
2027c478bd9Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep);
2037c478bd9Sstevel@tonic-gate err_flag = 1;
2047c478bd9Sstevel@tonic-gate PR_MEM("%s: mem-unit (%d.%d)"
2057c478bd9Sstevel@tonic-gate " unusable\n",
2067c478bd9Sstevel@tonic-gate f, sbp->sb_num,
2077c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_unum);
2087c478bd9Sstevel@tonic-gate break;
2097c478bd9Sstevel@tonic-gate }
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate
2127c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/
2137c478bd9Sstevel@tonic-gate
2147c478bd9Sstevel@tonic-gate case SBD_STATE_CONNECTED:
2157c478bd9Sstevel@tonic-gate PR_MEM("%s: reprogramming mem hardware (board %d)\n",
2167c478bd9Sstevel@tonic-gate f, sbp->sb_num);
2177c478bd9Sstevel@tonic-gate
2187c478bd9Sstevel@tonic-gate for (i = 0; i < SBD_NUM_MC_PER_BOARD; i++) {
2197c478bd9Sstevel@tonic-gate if (mp->sbm_dip[i] == NULL)
2207c478bd9Sstevel@tonic-gate continue;
2217c478bd9Sstevel@tonic-gate dip = mp->sbm_dip[i];
2227c478bd9Sstevel@tonic-gate
2237c478bd9Sstevel@tonic-gate PR_MEM("%s: enabling mc 0x%p on board %d\n",
2247c478bd9Sstevel@tonic-gate f, (void *)dip, sbp->sb_num);
2257c478bd9Sstevel@tonic-gate
2267c478bd9Sstevel@tonic-gate rv = sbdphw_enable_memctrl(hdp, dip);
2277c478bd9Sstevel@tonic-gate if (rv < 0) {
2287c478bd9Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep);
2297c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
2307c478bd9Sstevel@tonic-gate "%s: failed to program mem ctrlr %p on "
2317c478bd9Sstevel@tonic-gate "board %d", f, (void *)mp->sbm_dip[i],
2327c478bd9Sstevel@tonic-gate sbp->sb_num);
2337c478bd9Sstevel@tonic-gate err_flag = 1;
2347c478bd9Sstevel@tonic-gate }
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate break;
2377c478bd9Sstevel@tonic-gate
2387c478bd9Sstevel@tonic-gate default:
2397c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
2407c478bd9Sstevel@tonic-gate "%s: unexpected state (%d) for mem-unit "
2417c478bd9Sstevel@tonic-gate "(%d.%d)", f, state, sbp->sb_num,
2427c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_unum);
2437c478bd9Sstevel@tonic-gate if (SBD_GET_ERR(ep) == 0) {
2447c478bd9Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_STATE);
2457c478bd9Sstevel@tonic-gate err_flag = 1;
2467c478bd9Sstevel@tonic-gate }
2477c478bd9Sstevel@tonic-gate break;
2487c478bd9Sstevel@tonic-gate }
2497c478bd9Sstevel@tonic-gate
2507c478bd9Sstevel@tonic-gate /* exit for loop if error encountered */
2517c478bd9Sstevel@tonic-gate if (err_flag) {
2527c478bd9Sstevel@tonic-gate SBD_SET_ERRSTR(ep,
2537c478bd9Sstevel@tonic-gate sbp->sb_mempath[mp->sbm_cm.sbdev_unum]);
2547c478bd9Sstevel@tonic-gate break;
2557c478bd9Sstevel@tonic-gate }
2567c478bd9Sstevel@tonic-gate }
2577c478bd9Sstevel@tonic-gate sbd_release_sbdp_handle(hdp);
2587c478bd9Sstevel@tonic-gate
2597c478bd9Sstevel@tonic-gate return (err_flag ? -1 : 0);
2607c478bd9Sstevel@tonic-gate }
2617c478bd9Sstevel@tonic-gate
2627c478bd9Sstevel@tonic-gate int
sbd_post_attach_mem(sbd_handle_t * hp,sbd_devlist_t devlist[],int devnum)2637c478bd9Sstevel@tonic-gate sbd_post_attach_mem(sbd_handle_t *hp, sbd_devlist_t devlist[], int devnum)
2647c478bd9Sstevel@tonic-gate {
2657c478bd9Sstevel@tonic-gate int d;
2667c478bd9Sstevel@tonic-gate sbdp_handle_t *hdp;
2677c478bd9Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd);
2687c478bd9Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp);
2697c478bd9Sstevel@tonic-gate static fn_t f = "sbd_post_attach_mem";
2707c478bd9Sstevel@tonic-gate
2717c478bd9Sstevel@tonic-gate PR_MEM("%s...\n", f);
2727c478bd9Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp);
2737c478bd9Sstevel@tonic-gate
2747c478bd9Sstevel@tonic-gate for (d = 0; d < devnum; d++) {
2757c478bd9Sstevel@tonic-gate sbd_mem_unit_t *mp;
2767c478bd9Sstevel@tonic-gate dev_info_t *dip;
2777c478bd9Sstevel@tonic-gate int unit;
2787c478bd9Sstevel@tonic-gate struct memlist *mlist, *ml;
2797c478bd9Sstevel@tonic-gate
2807c478bd9Sstevel@tonic-gate /* sbd_get_devlist will not devlist element w/ dip of 0 */
2817c478bd9Sstevel@tonic-gate ASSERT(devlist[d].dv_dip != NULL);
2827c478bd9Sstevel@tonic-gate
2837c478bd9Sstevel@tonic-gate dip = devlist[d].dv_dip;
2847c478bd9Sstevel@tonic-gate unit = sbdp_get_unit_num(hdp, dip);
2857c478bd9Sstevel@tonic-gate if (unit == -1) {
2867c478bd9Sstevel@tonic-gate if (hp->h_flags & SBD_IOCTL_FLAG_FORCE)
2877c478bd9Sstevel@tonic-gate continue;
2887c478bd9Sstevel@tonic-gate else {
2897c478bd9Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep);
2907c478bd9Sstevel@tonic-gate break;
2917c478bd9Sstevel@tonic-gate }
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate
2947c478bd9Sstevel@tonic-gate mp = SBD_GET_BOARD_MEMUNIT(sbp, unit);
2957c478bd9Sstevel@tonic-gate
2967c478bd9Sstevel@tonic-gate mlist = sbd_get_memlist(mp, ep);
2977c478bd9Sstevel@tonic-gate if (mlist == NULL) {
2987c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
2997c478bd9Sstevel@tonic-gate "%s: no memlist for mem-unit (%d.%d)",
3007c478bd9Sstevel@tonic-gate f,
3017c478bd9Sstevel@tonic-gate sbp->sb_num,
3027c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_unum);
3037c478bd9Sstevel@tonic-gate
3047c478bd9Sstevel@tonic-gate if (SBD_GET_ERR(ep) == 0) {
3057c478bd9Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_MEMFAIL);
3067c478bd9Sstevel@tonic-gate SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]);
3077c478bd9Sstevel@tonic-gate }
3087c478bd9Sstevel@tonic-gate
3097c478bd9Sstevel@tonic-gate continue;
3107c478bd9Sstevel@tonic-gate }
3117c478bd9Sstevel@tonic-gate
3127c478bd9Sstevel@tonic-gate /*
3137c478bd9Sstevel@tonic-gate * Verify the memory really did successfully attach
3147c478bd9Sstevel@tonic-gate * by checking for its existence in phys_install.
3157c478bd9Sstevel@tonic-gate */
3167c478bd9Sstevel@tonic-gate
3177c478bd9Sstevel@tonic-gate memlist_read_lock();
3187c478bd9Sstevel@tonic-gate if (memlist_intersect(phys_install, mlist) == 0) {
3197c478bd9Sstevel@tonic-gate memlist_read_unlock();
3207c478bd9Sstevel@tonic-gate
3217c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
3227c478bd9Sstevel@tonic-gate "%s: mem-unit (%d.%d) memlist not in"
3237c478bd9Sstevel@tonic-gate " phys_install", f, sbp->sb_num,
3247c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_unum);
3257c478bd9Sstevel@tonic-gate
3267c478bd9Sstevel@tonic-gate if (SBD_GET_ERR(ep) == 0) {
3277c478bd9Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_INTERNAL);
3287c478bd9Sstevel@tonic-gate SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]);
3297c478bd9Sstevel@tonic-gate }
3307c478bd9Sstevel@tonic-gate
3317c478bd9Sstevel@tonic-gate memlist_delete(mlist);
3327c478bd9Sstevel@tonic-gate continue;
3337c478bd9Sstevel@tonic-gate }
3347c478bd9Sstevel@tonic-gate memlist_read_unlock();
3357c478bd9Sstevel@tonic-gate
336*56f33205SJonathan Adams for (ml = mlist; ml != NULL; ml = ml->ml_next) {
337*56f33205SJonathan Adams (void) sbdp_mem_add_span(hdp, ml->ml_address,
338*56f33205SJonathan Adams ml->ml_size);
3397c478bd9Sstevel@tonic-gate }
3407c478bd9Sstevel@tonic-gate
3417c478bd9Sstevel@tonic-gate memlist_delete(mlist);
3427c478bd9Sstevel@tonic-gate
3437c478bd9Sstevel@tonic-gate /*
3447c478bd9Sstevel@tonic-gate * Destroy cached memlist, if any.
3457c478bd9Sstevel@tonic-gate * There will be a cached memlist in sbm_mlist if
3467c478bd9Sstevel@tonic-gate * this board is being configured directly after
3477c478bd9Sstevel@tonic-gate * an unconfigure.
3487c478bd9Sstevel@tonic-gate * To support this transition, sbd_post_detach_mem
3497c478bd9Sstevel@tonic-gate * left a copy of the last known memlist in sbm_mlist.
3507c478bd9Sstevel@tonic-gate * This memlist could differ from any derived from
3517c478bd9Sstevel@tonic-gate * hardware if while this memunit was last configured
3527c478bd9Sstevel@tonic-gate * the system detected and deleted bad pages from
3537c478bd9Sstevel@tonic-gate * phys_install. The location of those bad pages
3547c478bd9Sstevel@tonic-gate * will be reflected in the cached memlist.
3557c478bd9Sstevel@tonic-gate */
3567c478bd9Sstevel@tonic-gate if (mp->sbm_mlist) {
3577c478bd9Sstevel@tonic-gate memlist_delete(mp->sbm_mlist);
3587c478bd9Sstevel@tonic-gate mp->sbm_mlist = NULL;
3597c478bd9Sstevel@tonic-gate }
3607c478bd9Sstevel@tonic-gate sbd_init_mem_unit_data(mp, ep);
3617c478bd9Sstevel@tonic-gate }
3627c478bd9Sstevel@tonic-gate
3637c478bd9Sstevel@tonic-gate sbd_release_sbdp_handle(hdp);
3647c478bd9Sstevel@tonic-gate return (0);
3657c478bd9Sstevel@tonic-gate }
3667c478bd9Sstevel@tonic-gate
3677c478bd9Sstevel@tonic-gate int
sbd_pre_detach_mem(sbd_handle_t * hp,sbd_devlist_t devlist[],int devnum)3687c478bd9Sstevel@tonic-gate sbd_pre_detach_mem(sbd_handle_t *hp, sbd_devlist_t devlist[], int devnum)
3697c478bd9Sstevel@tonic-gate {
3707c478bd9Sstevel@tonic-gate int d;
3717c478bd9Sstevel@tonic-gate int unit;
3727c478bd9Sstevel@tonic-gate sbdp_handle_t *hdp;
3737c478bd9Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp);
3747c478bd9Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd);
3757c478bd9Sstevel@tonic-gate dev_info_t *dip;
3767c478bd9Sstevel@tonic-gate
3777c478bd9Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp);
3787c478bd9Sstevel@tonic-gate
3797c478bd9Sstevel@tonic-gate for (d = 0; d < devnum; d++) {
3807c478bd9Sstevel@tonic-gate sbd_mem_unit_t *mp;
3817c478bd9Sstevel@tonic-gate
3827c478bd9Sstevel@tonic-gate /* sbd_get_devlist will not devlist element w/ dip of 0 */
3837c478bd9Sstevel@tonic-gate ASSERT(devlist[d].dv_dip != NULL);
3847c478bd9Sstevel@tonic-gate
3857c478bd9Sstevel@tonic-gate dip = devlist[d].dv_dip;
3867c478bd9Sstevel@tonic-gate unit = sbdp_get_unit_num(hdp, dip);
3877c478bd9Sstevel@tonic-gate if (unit == -1) {
3887c478bd9Sstevel@tonic-gate if (hp->h_flags & SBD_IOCTL_FLAG_FORCE)
3897c478bd9Sstevel@tonic-gate continue;
3907c478bd9Sstevel@tonic-gate else {
3917c478bd9Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep);
3927c478bd9Sstevel@tonic-gate sbd_release_sbdp_handle(hdp);
3937c478bd9Sstevel@tonic-gate return (-1);
3947c478bd9Sstevel@tonic-gate }
3957c478bd9Sstevel@tonic-gate }
3967c478bd9Sstevel@tonic-gate
3977c478bd9Sstevel@tonic-gate mp = SBD_GET_BOARD_MEMUNIT(sbp, unit);
3987c478bd9Sstevel@tonic-gate
3997c478bd9Sstevel@tonic-gate /* sanity check */
4007c478bd9Sstevel@tonic-gate ASSERT(mp->sbm_cm.sbdev_sbp == sbp);
4017c478bd9Sstevel@tonic-gate ASSERT(unit == mp->sbm_cm.sbdev_unum);
4027c478bd9Sstevel@tonic-gate
4037c478bd9Sstevel@tonic-gate PR_MEM("sbd: OS detach mem-unit (%d.%d)\n",
4047c478bd9Sstevel@tonic-gate sbp->sb_num, mp->sbm_cm.sbdev_unum);
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate
4077c478bd9Sstevel@tonic-gate sbd_release_sbdp_handle(hdp);
4087c478bd9Sstevel@tonic-gate return (0);
4097c478bd9Sstevel@tonic-gate }
4107c478bd9Sstevel@tonic-gate
4117c478bd9Sstevel@tonic-gate int
sbd_post_detach_mem(sbd_handle_t * hp,sbd_devlist_t devlist[],int devnum)4127c478bd9Sstevel@tonic-gate sbd_post_detach_mem(sbd_handle_t *hp, sbd_devlist_t devlist[], int devnum)
4137c478bd9Sstevel@tonic-gate {
4147c478bd9Sstevel@tonic-gate int d, rv;
4157c478bd9Sstevel@tonic-gate sbdp_handle_t *hdp;
4167c478bd9Sstevel@tonic-gate sbd_board_t *sbp;
4177c478bd9Sstevel@tonic-gate sbd_mem_unit_t *s_mp, *t_mp;
4187c478bd9Sstevel@tonic-gate static fn_t f = "sbd_post_detach_mem";
4197c478bd9Sstevel@tonic-gate
4207c478bd9Sstevel@tonic-gate PR_MEM("%s...\n", f);
4217c478bd9Sstevel@tonic-gate
4227c478bd9Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd);
4237c478bd9Sstevel@tonic-gate
4247c478bd9Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp);
4257c478bd9Sstevel@tonic-gate
4267c478bd9Sstevel@tonic-gate
4277c478bd9Sstevel@tonic-gate rv = 0;
4287c478bd9Sstevel@tonic-gate for (d = 0; d < devnum; d++) {
4297c478bd9Sstevel@tonic-gate sbderror_t *ep;
4307c478bd9Sstevel@tonic-gate dev_info_t *dip;
4317c478bd9Sstevel@tonic-gate int unit;
4327c478bd9Sstevel@tonic-gate
4337c478bd9Sstevel@tonic-gate /* sbd_get_devlist will not devlist element w/ dip of 0 */
4347c478bd9Sstevel@tonic-gate ASSERT(devlist[d].dv_dip != NULL);
4357c478bd9Sstevel@tonic-gate
4367c478bd9Sstevel@tonic-gate ep = &devlist[d].dv_error;
4377c478bd9Sstevel@tonic-gate if ((SBD_GET_ERR(SBD_HD2ERR(hp)) != 0) ||
4387c478bd9Sstevel@tonic-gate (sbd_set_err_in_hdl(hp, ep) == 0)) {
4397c478bd9Sstevel@tonic-gate rv = -1;
4407c478bd9Sstevel@tonic-gate }
4417c478bd9Sstevel@tonic-gate
4427c478bd9Sstevel@tonic-gate dip = devlist[d].dv_dip;
4437c478bd9Sstevel@tonic-gate unit = sbdp_get_unit_num(hdp, dip);
4447c478bd9Sstevel@tonic-gate if (unit == -1) {
4457c478bd9Sstevel@tonic-gate if (hp->h_flags & SBD_IOCTL_FLAG_FORCE)
4467c478bd9Sstevel@tonic-gate continue;
4477c478bd9Sstevel@tonic-gate else {
4487c478bd9Sstevel@tonic-gate if (rv != -1)
4497c478bd9Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep);
4507c478bd9Sstevel@tonic-gate break;
4517c478bd9Sstevel@tonic-gate }
4527c478bd9Sstevel@tonic-gate }
4537c478bd9Sstevel@tonic-gate
4547c478bd9Sstevel@tonic-gate s_mp = SBD_GET_BOARD_MEMUNIT(sbp, unit);
4557c478bd9Sstevel@tonic-gate
4567c478bd9Sstevel@tonic-gate ASSERT(s_mp->sbm_cm.sbdev_sbp == sbp);
4577c478bd9Sstevel@tonic-gate
4587c478bd9Sstevel@tonic-gate if (rv == -1) {
4597c478bd9Sstevel@tonic-gate if (s_mp->sbm_flags & SBD_MFLAG_SOURCE) {
4607c478bd9Sstevel@tonic-gate t_mp = s_mp->sbm_peer;
4617c478bd9Sstevel@tonic-gate } else {
4627c478bd9Sstevel@tonic-gate /* this is no target unit */
4637c478bd9Sstevel@tonic-gate t_mp = NULL;
4647c478bd9Sstevel@tonic-gate }
4657c478bd9Sstevel@tonic-gate
4667c478bd9Sstevel@tonic-gate sbd_mem_cleanup(s_mp, t_mp, ep);
4677c478bd9Sstevel@tonic-gate } else if (sbd_post_detach_mem_unit(s_mp, ep))
4687c478bd9Sstevel@tonic-gate rv = -1;
4697c478bd9Sstevel@tonic-gate }
4707c478bd9Sstevel@tonic-gate
4717c478bd9Sstevel@tonic-gate sbd_release_sbdp_handle(hdp);
4727c478bd9Sstevel@tonic-gate return (rv);
4737c478bd9Sstevel@tonic-gate }
4747c478bd9Sstevel@tonic-gate
4757c478bd9Sstevel@tonic-gate static void
sbd_add_memory_spans(sbd_board_t * sbp,struct memlist * ml)4767c478bd9Sstevel@tonic-gate sbd_add_memory_spans(sbd_board_t *sbp, struct memlist *ml)
4777c478bd9Sstevel@tonic-gate {
4787c478bd9Sstevel@tonic-gate sbdp_handle_t *hdp;
4797c478bd9Sstevel@tonic-gate static fn_t f = "sbd_add_memory_spans";
4807c478bd9Sstevel@tonic-gate
4817c478bd9Sstevel@tonic-gate PR_MEM("%s...", f);
4827c478bd9Sstevel@tonic-gate SBD_MEMLIST_DUMP(ml);
4837c478bd9Sstevel@tonic-gate
4847c478bd9Sstevel@tonic-gate #ifdef DEBUG
4857c478bd9Sstevel@tonic-gate memlist_read_lock();
4867c478bd9Sstevel@tonic-gate if (memlist_intersect(phys_install, ml)) {
4877c478bd9Sstevel@tonic-gate PR_MEM("%s:WARNING: memlist intersects with phys_install\n", f);
4887c478bd9Sstevel@tonic-gate }
4897c478bd9Sstevel@tonic-gate memlist_read_unlock();
4907c478bd9Sstevel@tonic-gate #endif
4917c478bd9Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(NULL, NULL);
4927c478bd9Sstevel@tonic-gate
493*56f33205SJonathan Adams for (; ml; ml = ml->ml_next) {
4947c478bd9Sstevel@tonic-gate update_membounds_t umb;
4957c478bd9Sstevel@tonic-gate pfn_t base;
4967c478bd9Sstevel@tonic-gate pgcnt_t npgs;
4977c478bd9Sstevel@tonic-gate int rv;
4987c478bd9Sstevel@tonic-gate
499*56f33205SJonathan Adams base = _b64top(ml->ml_address);
500*56f33205SJonathan Adams npgs = _b64top(ml->ml_size);
5017c478bd9Sstevel@tonic-gate
5027c478bd9Sstevel@tonic-gate umb.u_board = sbp->sb_num;
5037c478bd9Sstevel@tonic-gate umb.u_base = (uint64_t)base << MMU_PAGESHIFT;
5047c478bd9Sstevel@tonic-gate umb.u_len = (uint64_t)npgs << MMU_PAGESHIFT;
5057c478bd9Sstevel@tonic-gate
5067c478bd9Sstevel@tonic-gate lgrp_plat_config(LGRP_CONFIG_MEM_ADD, (uintptr_t)&umb);
5077c478bd9Sstevel@tonic-gate rv = kphysm_add_memory_dynamic(base, npgs);
5087c478bd9Sstevel@tonic-gate
509*56f33205SJonathan Adams (void) sbdp_mem_add_span(hdp, ml->ml_address, ml->ml_size);
5107c478bd9Sstevel@tonic-gate
5117c478bd9Sstevel@tonic-gate if (rv != KPHYSM_OK) {
5127c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "sbd:%s:"
5137c478bd9Sstevel@tonic-gate " unexpected kphysm_add_memory_dynamic"
5147c478bd9Sstevel@tonic-gate " return value %d;"
5157c478bd9Sstevel@tonic-gate " basepfn=0x%lx, npages=%ld\n",
5167c478bd9Sstevel@tonic-gate f, rv, base, npgs);
5177c478bd9Sstevel@tonic-gate
5187c478bd9Sstevel@tonic-gate continue;
5197c478bd9Sstevel@tonic-gate }
52085f58038Sdp78419 rv = kcage_range_add(base, npgs, KCAGE_DOWN);
5217c478bd9Sstevel@tonic-gate if (rv != 0)
5227c478bd9Sstevel@tonic-gate continue;
5237c478bd9Sstevel@tonic-gate }
5247c478bd9Sstevel@tonic-gate sbd_release_sbdp_handle(hdp);
5257c478bd9Sstevel@tonic-gate }
5267c478bd9Sstevel@tonic-gate
5277c478bd9Sstevel@tonic-gate /* hack for test scripts. *** remove before code finalized *** */
5287c478bd9Sstevel@tonic-gate int sbd_last_target;
5297c478bd9Sstevel@tonic-gate
5307c478bd9Sstevel@tonic-gate static int
sbd_post_detach_mem_unit(sbd_mem_unit_t * s_mp,sbderror_t * ep)5317c478bd9Sstevel@tonic-gate sbd_post_detach_mem_unit(sbd_mem_unit_t *s_mp, sbderror_t *ep)
5327c478bd9Sstevel@tonic-gate {
5337c478bd9Sstevel@tonic-gate uint64_t sz;
5347c478bd9Sstevel@tonic-gate uint64_t sm;
5357c478bd9Sstevel@tonic-gate uint64_t t_basepa;
5367c478bd9Sstevel@tonic-gate uint64_t tmp_basepa;
5377c478bd9Sstevel@tonic-gate uint64_t s_basepa;
5387c478bd9Sstevel@tonic-gate sbd_board_t *sbp;
5397c478bd9Sstevel@tonic-gate sbdp_handle_t *hdp;
5407c478bd9Sstevel@tonic-gate uint64_t s_nbytes;
5417c478bd9Sstevel@tonic-gate uint64_t s_new_basepa;
5427c478bd9Sstevel@tonic-gate sbd_mem_unit_t *t_mp, *x_mp;
5437c478bd9Sstevel@tonic-gate struct memlist *ml;
5447c478bd9Sstevel@tonic-gate int rv;
5457c478bd9Sstevel@tonic-gate static fn_t f = "sbd_post_detach_mem_unit";
5467c478bd9Sstevel@tonic-gate sbd_handle_t *hp;
5477c478bd9Sstevel@tonic-gate
5487c478bd9Sstevel@tonic-gate PR_MEM("%s...\n", f);
5497c478bd9Sstevel@tonic-gate
5507c478bd9Sstevel@tonic-gate sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp;
5517c478bd9Sstevel@tonic-gate hp = MACHBD2HD(sbp);
5527c478bd9Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp);
5537c478bd9Sstevel@tonic-gate
5547c478bd9Sstevel@tonic-gate if (sbdp_get_mem_alignment(hdp, s_mp->sbm_cm.sbdev_dip, &sz)) {
5557c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
5567c478bd9Sstevel@tonic-gate "sbd:%s: no alignment for mem-unit (%d.%d)",
5577c478bd9Sstevel@tonic-gate f, sbp->sb_num, s_mp->sbm_cm.sbdev_unum);
5587c478bd9Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep);
5597c478bd9Sstevel@tonic-gate sbd_release_sbdp_handle(hdp);
5607c478bd9Sstevel@tonic-gate return (-1);
5617c478bd9Sstevel@tonic-gate }
5627c478bd9Sstevel@tonic-gate sm = sz - 1;
5637c478bd9Sstevel@tonic-gate
5647c478bd9Sstevel@tonic-gate /* s_mp->sbm_del_mlist could be NULL, meaning no deleted spans */
5657c478bd9Sstevel@tonic-gate PR_MEM("%s: brd %d: deleted memlist (EMPTY maybe okay):\n",
5667c478bd9Sstevel@tonic-gate f, sbp->sb_num);
5677c478bd9Sstevel@tonic-gate SBD_MEMLIST_DUMP(s_mp->sbm_del_mlist);
5687c478bd9Sstevel@tonic-gate
5697c478bd9Sstevel@tonic-gate /* sanity check */
5707c478bd9Sstevel@tonic-gate ASSERT(s_mp->sbm_del_mlist == NULL ||
5717c478bd9Sstevel@tonic-gate (s_mp->sbm_flags & SBD_MFLAG_RELDONE) != 0);
5727c478bd9Sstevel@tonic-gate
5737c478bd9Sstevel@tonic-gate if (s_mp->sbm_flags & SBD_MFLAG_SOURCE) {
5747c478bd9Sstevel@tonic-gate t_mp = s_mp->sbm_peer;
5757c478bd9Sstevel@tonic-gate
5767c478bd9Sstevel@tonic-gate ASSERT(t_mp != NULL);
5777c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_flags & SBD_MFLAG_TARGET);
5787c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_peer == s_mp);
5797c478bd9Sstevel@tonic-gate
5807c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_flags & SBD_MFLAG_RELDONE);
5817c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_del_mlist);
5827c478bd9Sstevel@tonic-gate
5837c478bd9Sstevel@tonic-gate sbp = (sbd_board_t *)t_mp->sbm_cm.sbdev_sbp;
5847c478bd9Sstevel@tonic-gate PR_MEM("%s: target brd %d: deleted memlist:\n",
5857c478bd9Sstevel@tonic-gate f, sbp->sb_num);
5867c478bd9Sstevel@tonic-gate SBD_MEMLIST_DUMP(t_mp->sbm_del_mlist);
5877c478bd9Sstevel@tonic-gate } else {
5887c478bd9Sstevel@tonic-gate /* this is no target unit */
5897c478bd9Sstevel@tonic-gate t_mp = NULL;
5907c478bd9Sstevel@tonic-gate }
5917c478bd9Sstevel@tonic-gate
5927c478bd9Sstevel@tonic-gate /*
5937c478bd9Sstevel@tonic-gate * Verify the memory really did successfully detach
5947c478bd9Sstevel@tonic-gate * by checking for its non-existence in phys_install.
5957c478bd9Sstevel@tonic-gate */
5967c478bd9Sstevel@tonic-gate rv = 0;
5977c478bd9Sstevel@tonic-gate memlist_read_lock();
5987c478bd9Sstevel@tonic-gate if (s_mp->sbm_flags & SBD_MFLAG_RELDONE) {
5997c478bd9Sstevel@tonic-gate x_mp = s_mp;
6007c478bd9Sstevel@tonic-gate rv = memlist_intersect(phys_install, x_mp->sbm_del_mlist);
6017c478bd9Sstevel@tonic-gate }
6027c478bd9Sstevel@tonic-gate if (rv == 0 && t_mp && (t_mp->sbm_flags & SBD_MFLAG_RELDONE)) {
6037c478bd9Sstevel@tonic-gate x_mp = t_mp;
6047c478bd9Sstevel@tonic-gate rv = memlist_intersect(phys_install, x_mp->sbm_del_mlist);
6057c478bd9Sstevel@tonic-gate }
6067c478bd9Sstevel@tonic-gate memlist_read_unlock();
6077c478bd9Sstevel@tonic-gate
6087c478bd9Sstevel@tonic-gate if (rv) {
6097c478bd9Sstevel@tonic-gate sbp = (sbd_board_t *)x_mp->sbm_cm.sbdev_sbp;
6107c478bd9Sstevel@tonic-gate
6117c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
6127c478bd9Sstevel@tonic-gate "%s: %smem-unit (%d.%d) memlist still in phys_install",
6137c478bd9Sstevel@tonic-gate f,
6147c478bd9Sstevel@tonic-gate x_mp == t_mp ? "target " : "",
6157c478bd9Sstevel@tonic-gate sbp->sb_num,
6167c478bd9Sstevel@tonic-gate x_mp->sbm_cm.sbdev_unum);
6177c478bd9Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_INTERNAL);
6187c478bd9Sstevel@tonic-gate SBD_SET_ERRSTR(ep, sbp->sb_mempath[x_mp->sbm_cm.sbdev_unum]);
6197c478bd9Sstevel@tonic-gate sbd_release_sbdp_handle(hdp);
6207c478bd9Sstevel@tonic-gate return (-1);
6217c478bd9Sstevel@tonic-gate }
6227c478bd9Sstevel@tonic-gate
6237c478bd9Sstevel@tonic-gate s_basepa = _ptob64(s_mp->sbm_basepfn);
6247c478bd9Sstevel@tonic-gate s_nbytes = _ptob64(s_mp->sbm_npages);
6257c478bd9Sstevel@tonic-gate
6267c478bd9Sstevel@tonic-gate if (t_mp != NULL) {
6277c478bd9Sstevel@tonic-gate t_basepa = _ptob64(t_mp->sbm_basepfn);
6287c478bd9Sstevel@tonic-gate s_new_basepa = (s_basepa & ~ sm) +
6297c478bd9Sstevel@tonic-gate _ptob64(t_mp->sbm_slice_offset);
6307c478bd9Sstevel@tonic-gate
6317c478bd9Sstevel@tonic-gate /*
6327c478bd9Sstevel@tonic-gate * We had to swap mem-units, so update
6337c478bd9Sstevel@tonic-gate * memlists accordingly with new base
6347c478bd9Sstevel@tonic-gate * addresses.
6357c478bd9Sstevel@tonic-gate */
636*56f33205SJonathan Adams for (ml = t_mp->sbm_mlist; ml; ml = ml->ml_next) {
637*56f33205SJonathan Adams ml->ml_address -= t_basepa;
638*56f33205SJonathan Adams ml->ml_address += s_new_basepa;
6397c478bd9Sstevel@tonic-gate }
6407c478bd9Sstevel@tonic-gate
6417c478bd9Sstevel@tonic-gate /*
6427c478bd9Sstevel@tonic-gate * There is no need to explicitly rename the target delete
6437c478bd9Sstevel@tonic-gate * memlist, because sbm_del_mlist and sbm_mlist always
6447c478bd9Sstevel@tonic-gate * point to the same memlist for a copy/rename operation.
6457c478bd9Sstevel@tonic-gate */
6467c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_del_mlist == t_mp->sbm_mlist);
6477c478bd9Sstevel@tonic-gate
6487c478bd9Sstevel@tonic-gate PR_MEM("%s: renamed target memlist and delete memlist", f);
6497c478bd9Sstevel@tonic-gate SBD_MEMLIST_DUMP(t_mp->sbm_mlist);
6507c478bd9Sstevel@tonic-gate
651*56f33205SJonathan Adams for (ml = s_mp->sbm_mlist; ml; ml = ml->ml_next) {
652*56f33205SJonathan Adams ml->ml_address -= s_basepa;
653*56f33205SJonathan Adams ml->ml_address += t_basepa;
6547c478bd9Sstevel@tonic-gate }
6557c478bd9Sstevel@tonic-gate
6567c478bd9Sstevel@tonic-gate PR_MEM("%s: renamed source memlist", f);
6577c478bd9Sstevel@tonic-gate SBD_MEMLIST_DUMP(s_mp->sbm_mlist);
6587c478bd9Sstevel@tonic-gate
6597c478bd9Sstevel@tonic-gate #ifdef DEBUG
6607c478bd9Sstevel@tonic-gate ASSERT(s_mp->sbm_mlist != s_mp->sbm_del_mlist);
6617c478bd9Sstevel@tonic-gate /*
6627c478bd9Sstevel@tonic-gate * Renaming s_mp->sbm_del_mlist is not necessary. This
6637c478bd9Sstevel@tonic-gate * list is not used beyond this point, and in fact, is
6647c478bd9Sstevel@tonic-gate * disposed of at the end of this function.
6657c478bd9Sstevel@tonic-gate */
666*56f33205SJonathan Adams for (ml = s_mp->sbm_del_mlist; ml; ml = ml->ml_next) {
667*56f33205SJonathan Adams ml->ml_address -= s_basepa;
668*56f33205SJonathan Adams ml->ml_address += t_basepa;
6697c478bd9Sstevel@tonic-gate }
6707c478bd9Sstevel@tonic-gate
6717c478bd9Sstevel@tonic-gate PR_MEM("%s: renamed source delete memlist", f);
6727c478bd9Sstevel@tonic-gate SBD_MEMLIST_DUMP(s_mp->sbm_del_mlist);
6737c478bd9Sstevel@tonic-gate #endif
6747c478bd9Sstevel@tonic-gate
6757c478bd9Sstevel@tonic-gate if (s_mp->sbm_flags & SBD_MFLAG_MEMUPSIZE) {
6767c478bd9Sstevel@tonic-gate struct memlist *nl;
6777c478bd9Sstevel@tonic-gate int mlret;
6787c478bd9Sstevel@tonic-gate
6797c478bd9Sstevel@tonic-gate /*
6807c478bd9Sstevel@tonic-gate * We had to perform a copy-rename from a
6817c478bd9Sstevel@tonic-gate * small memory node to a big memory node.
6827c478bd9Sstevel@tonic-gate * Need to add back the remaining memory on
6837c478bd9Sstevel@tonic-gate * the big board that wasn't used by that
6847c478bd9Sstevel@tonic-gate * from the small board during the copy.
6857c478bd9Sstevel@tonic-gate * Subtract out the portion of the target memory
6867c478bd9Sstevel@tonic-gate * node that was taken over by the source memory
6877c478bd9Sstevel@tonic-gate * node.
6887c478bd9Sstevel@tonic-gate */
6897c478bd9Sstevel@tonic-gate nl = memlist_dup(t_mp->sbm_mlist);
6907c478bd9Sstevel@tonic-gate mlret = memlist_delete_span(s_basepa, s_nbytes, &nl);
6917c478bd9Sstevel@tonic-gate PR_MEM("%s: mlret = %d\n", f, mlret);
6927c478bd9Sstevel@tonic-gate
6937c478bd9Sstevel@tonic-gate sbp = (sbd_board_t *)t_mp->sbm_cm.sbdev_sbp;
6947c478bd9Sstevel@tonic-gate PR_MEM("%s: adding back remaining portion"
6957c478bd9Sstevel@tonic-gate " of mem-unit (%d.%d), memlist:\n",
6967c478bd9Sstevel@tonic-gate f, sbp->sb_num,
6977c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_unum);
6987c478bd9Sstevel@tonic-gate
6997c478bd9Sstevel@tonic-gate SBD_MEMLIST_DUMP(nl);
7007c478bd9Sstevel@tonic-gate
7017c478bd9Sstevel@tonic-gate sbd_add_memory_spans(sbp, nl);
7027c478bd9Sstevel@tonic-gate
7037c478bd9Sstevel@tonic-gate memlist_delete(nl);
7047c478bd9Sstevel@tonic-gate }
7057c478bd9Sstevel@tonic-gate }
7067c478bd9Sstevel@tonic-gate
7077c478bd9Sstevel@tonic-gate
7087c478bd9Sstevel@tonic-gate if (t_mp != NULL) {
7097c478bd9Sstevel@tonic-gate sbp = (sbd_board_t *)t_mp->sbm_cm.sbdev_sbp;
7107c478bd9Sstevel@tonic-gate hdp->h_board = sbp->sb_num;
7117c478bd9Sstevel@tonic-gate /* delete target's entire address space */
7127c478bd9Sstevel@tonic-gate tmp_basepa = t_basepa & ~ sm;
7137c478bd9Sstevel@tonic-gate rv = sbdp_mem_del_span(hdp, tmp_basepa, sz);
7147c478bd9Sstevel@tonic-gate ASSERT(rv == 0);
7157c478bd9Sstevel@tonic-gate
7167c478bd9Sstevel@tonic-gate sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp;
7177c478bd9Sstevel@tonic-gate hdp->h_board = sbp->sb_num;
7187c478bd9Sstevel@tonic-gate tmp_basepa = s_basepa & ~ sm;
7197c478bd9Sstevel@tonic-gate sz = s_new_basepa & sm;
7207c478bd9Sstevel@tonic-gate /* delete source board's vacant address space */
7217c478bd9Sstevel@tonic-gate rv = sbdp_mem_del_span(hdp, tmp_basepa, sz);
7227c478bd9Sstevel@tonic-gate ASSERT(rv == 0);
7237c478bd9Sstevel@tonic-gate } else {
7247c478bd9Sstevel@tonic-gate sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp;
7257c478bd9Sstevel@tonic-gate hdp->h_board = sbp->sb_num;
7267c478bd9Sstevel@tonic-gate tmp_basepa = s_basepa & ~ sm;
7277c478bd9Sstevel@tonic-gate /* delete board's entire address space */
7287c478bd9Sstevel@tonic-gate rv = sbdp_mem_del_span(hdp, tmp_basepa, sz);
7297c478bd9Sstevel@tonic-gate ASSERT(rv == 0);
7307c478bd9Sstevel@tonic-gate }
7317c478bd9Sstevel@tonic-gate
7327c478bd9Sstevel@tonic-gate #ifdef LINT
7337c478bd9Sstevel@tonic-gate rv = rv;
7347c478bd9Sstevel@tonic-gate #endif
7357c478bd9Sstevel@tonic-gate
7367c478bd9Sstevel@tonic-gate sbd_mem_cleanup(s_mp, t_mp, ep);
7377c478bd9Sstevel@tonic-gate
7387c478bd9Sstevel@tonic-gate sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp;
7397c478bd9Sstevel@tonic-gate PR_MEM("%s: board %d's memlist:", f, sbp->sb_num);
7407c478bd9Sstevel@tonic-gate SBD_MEMLIST_DUMP(s_mp->sbm_mlist);
7417c478bd9Sstevel@tonic-gate
7427c478bd9Sstevel@tonic-gate sbd_release_sbdp_handle(hdp);
7437c478bd9Sstevel@tonic-gate return (0);
7447c478bd9Sstevel@tonic-gate }
7457c478bd9Sstevel@tonic-gate
7467c478bd9Sstevel@tonic-gate static void
sbd_mem_cleanup(sbd_mem_unit_t * s_mp,sbd_mem_unit_t * t_mp,sbderror_t * ep)7477c478bd9Sstevel@tonic-gate sbd_mem_cleanup(sbd_mem_unit_t *s_mp, sbd_mem_unit_t *t_mp, sbderror_t *ep)
7487c478bd9Sstevel@tonic-gate {
7497c478bd9Sstevel@tonic-gate sbd_board_t *sbp;
7507c478bd9Sstevel@tonic-gate
7517c478bd9Sstevel@tonic-gate /* clean up target mem unit */
7527c478bd9Sstevel@tonic-gate if (t_mp != NULL) {
7537c478bd9Sstevel@tonic-gate sbp = (sbd_board_t *)t_mp->sbm_cm.sbdev_sbp;
7547c478bd9Sstevel@tonic-gate
7557c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_del_mlist == t_mp->sbm_mlist);
7567c478bd9Sstevel@tonic-gate /*
7577c478bd9Sstevel@tonic-gate * sbm_del_mlist and sbm_mlist point at the same list
7587c478bd9Sstevel@tonic-gate * We only need to delete one and then set both pointers
7597c478bd9Sstevel@tonic-gate * to NULL
7607c478bd9Sstevel@tonic-gate */
7617c478bd9Sstevel@tonic-gate memlist_delete(t_mp->sbm_del_mlist);
7627c478bd9Sstevel@tonic-gate
7637c478bd9Sstevel@tonic-gate t_mp->sbm_del_mlist = NULL;
7647c478bd9Sstevel@tonic-gate t_mp->sbm_mlist = NULL;
7657c478bd9Sstevel@tonic-gate t_mp->sbm_peer = NULL;
7667c478bd9Sstevel@tonic-gate t_mp->sbm_flags = 0;
7677c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_busy = 0;
7687c478bd9Sstevel@tonic-gate sbd_init_mem_unit_data(t_mp, ep);
7697c478bd9Sstevel@tonic-gate
7707c478bd9Sstevel@tonic-gate /*
7717c478bd9Sstevel@tonic-gate * now that copy/rename has completed, undo this
7727c478bd9Sstevel@tonic-gate * work that was done in sbd_release_mem_done.
7737c478bd9Sstevel@tonic-gate */
7747c478bd9Sstevel@tonic-gate /*
7757c478bd9Sstevel@tonic-gate * If error don't set the target to configured
7767c478bd9Sstevel@tonic-gate */
7777c478bd9Sstevel@tonic-gate if (SBD_GET_ERR(ep) == 0) {
7787c478bd9Sstevel@tonic-gate SBD_DEV_CLR_UNREFERENCED(sbp, SBD_COMP_MEM, 0);
7797c478bd9Sstevel@tonic-gate SBD_DEV_CLR_RELEASED(sbp, SBD_COMP_MEM, 0);
7807c478bd9Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, 0,
7817c478bd9Sstevel@tonic-gate SBD_STATE_CONFIGURED);
7827c478bd9Sstevel@tonic-gate }
7837c478bd9Sstevel@tonic-gate
7847c478bd9Sstevel@tonic-gate /* hack for test scripts. *** remove before code finalized *** */
7857c478bd9Sstevel@tonic-gate sbd_last_target = sbp->sb_num;
7867c478bd9Sstevel@tonic-gate }
7877c478bd9Sstevel@tonic-gate
7887c478bd9Sstevel@tonic-gate /*
7897c478bd9Sstevel@tonic-gate * clean up (source) board's mem unit structure.
7907c478bd9Sstevel@tonic-gate * NOTE: sbm_mlist is retained. It is referred to as the
7917c478bd9Sstevel@tonic-gate * cached memlist. The cached memlist is used to re-attach
7927c478bd9Sstevel@tonic-gate * (configure back in) this memunit from the unconfigured
7937c478bd9Sstevel@tonic-gate * state.
7947c478bd9Sstevel@tonic-gate */
7957c478bd9Sstevel@tonic-gate if (s_mp != NULL) {
7967c478bd9Sstevel@tonic-gate sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp;
7977c478bd9Sstevel@tonic-gate
7987c478bd9Sstevel@tonic-gate /*
7997c478bd9Sstevel@tonic-gate * Don't want to call memlist_delete for sbm_del_mlist,
8007c478bd9Sstevel@tonic-gate * since that list points to the sbm_list
8017c478bd9Sstevel@tonic-gate */
8027c478bd9Sstevel@tonic-gate s_mp->sbm_del_mlist = NULL;
8037c478bd9Sstevel@tonic-gate s_mp->sbm_peer = NULL;
8047c478bd9Sstevel@tonic-gate s_mp->sbm_flags = 0;
8057c478bd9Sstevel@tonic-gate s_mp->sbm_cm.sbdev_busy = 0;
8067c478bd9Sstevel@tonic-gate sbd_init_mem_unit_data(s_mp, ep);
8077c478bd9Sstevel@tonic-gate }
8087c478bd9Sstevel@tonic-gate }
8097c478bd9Sstevel@tonic-gate
8107c478bd9Sstevel@tonic-gate /*
8117c478bd9Sstevel@tonic-gate * Successful return from this function will have the memory
8127c478bd9Sstevel@tonic-gate * handle in sbp->sb_dev[..mem-unit...].sbm_memhandle allocated
8137c478bd9Sstevel@tonic-gate * and waiting. This routine's job is to select the memory that
8147c478bd9Sstevel@tonic-gate * actually has to be released (detached) which may not necessarily
8157c478bd9Sstevel@tonic-gate * be the same memory node that came in in devlist[],
8167c478bd9Sstevel@tonic-gate * i.e. a copy-rename is needed.
8177c478bd9Sstevel@tonic-gate */
8187c478bd9Sstevel@tonic-gate int
sbd_pre_release_mem(sbd_handle_t * hp,sbd_devlist_t devlist[],int devnum)8197c478bd9Sstevel@tonic-gate sbd_pre_release_mem(sbd_handle_t *hp, sbd_devlist_t devlist[], int devnum)
8207c478bd9Sstevel@tonic-gate {
8217c478bd9Sstevel@tonic-gate extern int kcage_on;
8227c478bd9Sstevel@tonic-gate int d;
8237c478bd9Sstevel@tonic-gate int err_flag = 0;
8247c478bd9Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd);
8257c478bd9Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp);
8267c478bd9Sstevel@tonic-gate sbderror_t *lep;
8277c478bd9Sstevel@tonic-gate static fn_t f = "sbd_pre_release_mem";
8287c478bd9Sstevel@tonic-gate
8297c478bd9Sstevel@tonic-gate PR_MEM("%s...\n", f);
8307c478bd9Sstevel@tonic-gate
8317c478bd9Sstevel@tonic-gate if (kcage_on == 0) {
8327c478bd9Sstevel@tonic-gate /*
8337c478bd9Sstevel@tonic-gate * Can't Detach memory if Cage is OFF.
8347c478bd9Sstevel@tonic-gate */
8357c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s: kernel cage is disabled", f);
8367c478bd9Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_KCAGE_OFF);
8377c478bd9Sstevel@tonic-gate return (-1);
8387c478bd9Sstevel@tonic-gate }
8397c478bd9Sstevel@tonic-gate
8407c478bd9Sstevel@tonic-gate for (d = 0; d < devnum; d++) {
8417c478bd9Sstevel@tonic-gate int rv;
8427c478bd9Sstevel@tonic-gate memquery_t mq;
8437c478bd9Sstevel@tonic-gate sbd_mem_unit_t *mp;
8447c478bd9Sstevel@tonic-gate struct memlist *ml;
8457c478bd9Sstevel@tonic-gate
8467c478bd9Sstevel@tonic-gate /* sbd_get_devlist will not devlist element w/ dip of 0 */
8477c478bd9Sstevel@tonic-gate ASSERT(devlist[d].dv_dip != NULL);
8487c478bd9Sstevel@tonic-gate
8497c478bd9Sstevel@tonic-gate mp = SBD_GET_BOARD_MEMUNIT(sbp, d);
8507c478bd9Sstevel@tonic-gate
8517c478bd9Sstevel@tonic-gate /*
8527c478bd9Sstevel@tonic-gate * If all the mem unit is marked as failed then don't allow the
8537c478bd9Sstevel@tonic-gate * operation
8547c478bd9Sstevel@tonic-gate */
8557c478bd9Sstevel@tonic-gate if (mp->sbm_cm.sbdev_cond == SBD_COND_FAILED) {
8567c478bd9Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_STATE);
8577c478bd9Sstevel@tonic-gate SBD_SET_ERRSTR(ep, sbp->sb_mempath[d]);
8587c478bd9Sstevel@tonic-gate err_flag = -1;
8597c478bd9Sstevel@tonic-gate break;
8607c478bd9Sstevel@tonic-gate }
8617c478bd9Sstevel@tonic-gate
8627c478bd9Sstevel@tonic-gate ASSERT(d == mp->sbm_cm.sbdev_unum);
8637c478bd9Sstevel@tonic-gate
8647c478bd9Sstevel@tonic-gate /*
8657c478bd9Sstevel@tonic-gate * if interleave is set to across boards fail the op
8667c478bd9Sstevel@tonic-gate */
8677c478bd9Sstevel@tonic-gate if (mp->sbm_interleave) {
8687c478bd9Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_MEMINTLV);
8697c478bd9Sstevel@tonic-gate SBD_SET_ERRSTR(ep, sbp->sb_mempath[d]);
8707c478bd9Sstevel@tonic-gate err_flag = -1;
8717c478bd9Sstevel@tonic-gate break;
8727c478bd9Sstevel@tonic-gate }
8737c478bd9Sstevel@tonic-gate
8747c478bd9Sstevel@tonic-gate lep = &devlist[d].dv_error;
8757c478bd9Sstevel@tonic-gate if (SBD_GET_ERR(lep) != 0) {
8767c478bd9Sstevel@tonic-gate err_flag = -1;
8777c478bd9Sstevel@tonic-gate (void) sbd_set_err_in_hdl(hp, lep);
8787c478bd9Sstevel@tonic-gate break;
8797c478bd9Sstevel@tonic-gate }
8807c478bd9Sstevel@tonic-gate
8817c478bd9Sstevel@tonic-gate if (mp->sbm_flags & SBD_MFLAG_RESERVED) {
8827c478bd9Sstevel@tonic-gate /*
8837c478bd9Sstevel@tonic-gate * Board is currently involved in a delete
8847c478bd9Sstevel@tonic-gate * memory operation. Can't detach this guy until
8857c478bd9Sstevel@tonic-gate * that operation completes.
8867c478bd9Sstevel@tonic-gate */
8877c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
8887c478bd9Sstevel@tonic-gate "%s: ineligible mem-unit (%d.%d) for detach",
8897c478bd9Sstevel@tonic-gate f, sbp->sb_num,
8907c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_unum);
8917c478bd9Sstevel@tonic-gate
8927c478bd9Sstevel@tonic-gate SBD_SET_ERR(lep, ESBD_INVAL);
8937c478bd9Sstevel@tonic-gate SBD_SET_ERRSTR(lep, sbp->sb_mempath[d]);
8947c478bd9Sstevel@tonic-gate (void) sbd_set_err_in_hdl(hp, lep);
8957c478bd9Sstevel@tonic-gate err_flag = -1;
8967c478bd9Sstevel@tonic-gate break;
8977c478bd9Sstevel@tonic-gate }
8987c478bd9Sstevel@tonic-gate
8997c478bd9Sstevel@tonic-gate /*
9007c478bd9Sstevel@tonic-gate * Check whether the detaching memory requires a
9017c478bd9Sstevel@tonic-gate * copy-rename.
9027c478bd9Sstevel@tonic-gate */
9037c478bd9Sstevel@tonic-gate ASSERT(mp->sbm_npages != 0);
9047c478bd9Sstevel@tonic-gate rv = kphysm_del_span_query(
9057c478bd9Sstevel@tonic-gate mp->sbm_basepfn, mp->sbm_npages, &mq);
9067c478bd9Sstevel@tonic-gate if (rv != KPHYSM_OK) {
9077c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
9087c478bd9Sstevel@tonic-gate "%s: unexpected kphysm_del_span_query"
9097c478bd9Sstevel@tonic-gate " return value %d;"
9107c478bd9Sstevel@tonic-gate " basepfn 0x%lx, npages 0x%lx,"
9117c478bd9Sstevel@tonic-gate " mem-unit (%d.%d), dip 0x%p",
9127c478bd9Sstevel@tonic-gate f,
9137c478bd9Sstevel@tonic-gate rv,
9147c478bd9Sstevel@tonic-gate mp->sbm_basepfn,
9157c478bd9Sstevel@tonic-gate mp->sbm_npages,
9167c478bd9Sstevel@tonic-gate sbp->sb_num,
9177c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_unum,
9187c478bd9Sstevel@tonic-gate (void *)mp->sbm_cm.sbdev_dip);
9197c478bd9Sstevel@tonic-gate
9207c478bd9Sstevel@tonic-gate SBD_SET_ERR(lep, ESBD_INTERNAL);
9217c478bd9Sstevel@tonic-gate SBD_SET_ERRSTR(lep, sbp->sb_mempath[d]);
9227c478bd9Sstevel@tonic-gate (void) sbd_set_err_in_hdl(hp, lep);
9237c478bd9Sstevel@tonic-gate err_flag = -1;
9247c478bd9Sstevel@tonic-gate break;
9257c478bd9Sstevel@tonic-gate }
9267c478bd9Sstevel@tonic-gate
9277c478bd9Sstevel@tonic-gate if (mq.nonrelocatable != 0) {
9287c478bd9Sstevel@tonic-gate if (!(hp->h_iap->i_flags & SBD_FLAG_QUIESCE_OKAY)) {
9297c478bd9Sstevel@tonic-gate /* caller wasn't prompted for a suspend */
9307c478bd9Sstevel@tonic-gate SBD_SET_ERR(lep, ESBD_QUIESCE_REQD);
9317c478bd9Sstevel@tonic-gate SBD_SET_ERRSTR(lep, sbp->sb_mempath[d]);
9327c478bd9Sstevel@tonic-gate (void) sbd_set_err_in_hdl(hp, lep);
9337c478bd9Sstevel@tonic-gate err_flag = 1;
9347c478bd9Sstevel@tonic-gate break;
9357c478bd9Sstevel@tonic-gate }
9367c478bd9Sstevel@tonic-gate }
9377c478bd9Sstevel@tonic-gate
9387c478bd9Sstevel@tonic-gate /* flags should be clean at this time */
9397c478bd9Sstevel@tonic-gate ASSERT(mp->sbm_flags == 0);
9407c478bd9Sstevel@tonic-gate
9417c478bd9Sstevel@tonic-gate ASSERT(mp->sbm_del_mlist == NULL); /* should be null */
9427c478bd9Sstevel@tonic-gate
9437c478bd9Sstevel@tonic-gate if (mp->sbm_mlist != NULL) {
9447c478bd9Sstevel@tonic-gate memlist_delete(mp->sbm_mlist);
9457c478bd9Sstevel@tonic-gate mp->sbm_mlist = NULL;
9467c478bd9Sstevel@tonic-gate }
9477c478bd9Sstevel@tonic-gate
9487c478bd9Sstevel@tonic-gate ml = sbd_get_memlist(mp, lep);
9497c478bd9Sstevel@tonic-gate (void) sbd_set_err_in_hdl(hp, lep);
9507c478bd9Sstevel@tonic-gate if (ml == NULL) {
9517c478bd9Sstevel@tonic-gate PR_MEM("%s: no memlist found for board %d\n",
9527c478bd9Sstevel@tonic-gate f, sbp->sb_num);
9537c478bd9Sstevel@tonic-gate err_flag = -1;
9547c478bd9Sstevel@tonic-gate break;
9557c478bd9Sstevel@tonic-gate }
9567c478bd9Sstevel@tonic-gate
9577c478bd9Sstevel@tonic-gate /* allocate a kphysm handle */
9587c478bd9Sstevel@tonic-gate rv = kphysm_del_gethandle(&mp->sbm_memhandle);
9597c478bd9Sstevel@tonic-gate if (rv != KPHYSM_OK) {
9607c478bd9Sstevel@tonic-gate memlist_delete(ml);
9617c478bd9Sstevel@tonic-gate
9627c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
9637c478bd9Sstevel@tonic-gate "%s: unexpected kphysm_del_gethandle"
9647c478bd9Sstevel@tonic-gate " return value %d", f, rv);
9657c478bd9Sstevel@tonic-gate
9667c478bd9Sstevel@tonic-gate SBD_SET_ERR(lep, ESBD_INTERNAL);
9677c478bd9Sstevel@tonic-gate SBD_SET_ERRSTR(lep, sbp->sb_mempath[d]);
9687c478bd9Sstevel@tonic-gate (void) sbd_set_err_in_hdl(hp, lep);
9697c478bd9Sstevel@tonic-gate err_flag = -1;
9707c478bd9Sstevel@tonic-gate break;
9717c478bd9Sstevel@tonic-gate }
9727c478bd9Sstevel@tonic-gate mp->sbm_flags |= SBD_MFLAG_RELOWNER;
9737c478bd9Sstevel@tonic-gate
9747c478bd9Sstevel@tonic-gate if ((mq.nonrelocatable != 0) ||
9757c478bd9Sstevel@tonic-gate sbd_reserve_mem_spans(&mp->sbm_memhandle, ml)) {
9767c478bd9Sstevel@tonic-gate /*
9777c478bd9Sstevel@tonic-gate * Either the detaching memory node contains
9787c478bd9Sstevel@tonic-gate * non-reloc memory or we failed to reserve the
9797c478bd9Sstevel@tonic-gate * detaching memory node (which did _not_ have
9807c478bd9Sstevel@tonic-gate * any non-reloc memory, i.e. some non-reloc mem
9817c478bd9Sstevel@tonic-gate * got onboard).
9827c478bd9Sstevel@tonic-gate */
9837c478bd9Sstevel@tonic-gate
9847c478bd9Sstevel@tonic-gate if (sbd_select_mem_target(hp, mp, ml)) {
9857c478bd9Sstevel@tonic-gate int rv;
9867c478bd9Sstevel@tonic-gate
9877c478bd9Sstevel@tonic-gate /*
9887c478bd9Sstevel@tonic-gate * We had no luck locating a target
9897c478bd9Sstevel@tonic-gate * memory node to be the recipient of
9907c478bd9Sstevel@tonic-gate * the non-reloc memory on the node
9917c478bd9Sstevel@tonic-gate * we're trying to detach.
9927c478bd9Sstevel@tonic-gate * Clean up be disposing the mem handle
9937c478bd9Sstevel@tonic-gate * and the mem list.
9947c478bd9Sstevel@tonic-gate */
9957c478bd9Sstevel@tonic-gate rv = kphysm_del_release(mp->sbm_memhandle);
9967c478bd9Sstevel@tonic-gate if (rv != KPHYSM_OK) {
9977c478bd9Sstevel@tonic-gate /*
9987c478bd9Sstevel@tonic-gate * can do nothing but complain
9997c478bd9Sstevel@tonic-gate * and hope helpful for debug
10007c478bd9Sstevel@tonic-gate */
10017c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "sbd:%s: unexpected"
10027c478bd9Sstevel@tonic-gate " kphysm_del_release return"
10037c478bd9Sstevel@tonic-gate " value %d",
10047c478bd9Sstevel@tonic-gate f, rv);
10057c478bd9Sstevel@tonic-gate }
10067c478bd9Sstevel@tonic-gate mp->sbm_flags &= ~SBD_MFLAG_RELOWNER;
10077c478bd9Sstevel@tonic-gate
10087c478bd9Sstevel@tonic-gate memlist_delete(ml);
10097c478bd9Sstevel@tonic-gate
10107c478bd9Sstevel@tonic-gate /* make sure sbm_flags is clean */
10117c478bd9Sstevel@tonic-gate ASSERT(mp->sbm_flags == 0);
10127c478bd9Sstevel@tonic-gate
10137c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
10147c478bd9Sstevel@tonic-gate "%s: no available target for "
10157c478bd9Sstevel@tonic-gate "mem-unit (%d.%d)",
10167c478bd9Sstevel@tonic-gate f, sbp->sb_num,
10177c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_unum);
10187c478bd9Sstevel@tonic-gate
10197c478bd9Sstevel@tonic-gate SBD_SET_ERR(lep, ESBD_NO_TARGET);
10207c478bd9Sstevel@tonic-gate SBD_SET_ERRSTR(lep,
10217c478bd9Sstevel@tonic-gate sbp->sb_mempath[mp->sbm_cm.sbdev_unum]);
10227c478bd9Sstevel@tonic-gate (void) sbd_set_err_in_hdl(hp, lep);
10237c478bd9Sstevel@tonic-gate
10247c478bd9Sstevel@tonic-gate err_flag = -1;
10257c478bd9Sstevel@tonic-gate break;
10267c478bd9Sstevel@tonic-gate }
10277c478bd9Sstevel@tonic-gate
10287c478bd9Sstevel@tonic-gate /*
10297c478bd9Sstevel@tonic-gate * ml is not memlist_deleted here because
10307c478bd9Sstevel@tonic-gate * it has been assigned to mp->sbm_mlist
10317c478bd9Sstevel@tonic-gate * by sbd_select_mem_target.
10327c478bd9Sstevel@tonic-gate */
10337c478bd9Sstevel@tonic-gate } else {
10347c478bd9Sstevel@tonic-gate /* no target needed to detach this board */
10357c478bd9Sstevel@tonic-gate mp->sbm_flags |= SBD_MFLAG_RESERVED;
10367c478bd9Sstevel@tonic-gate mp->sbm_peer = NULL;
10377c478bd9Sstevel@tonic-gate mp->sbm_del_mlist = ml;
10387c478bd9Sstevel@tonic-gate mp->sbm_mlist = ml;
10397c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_busy = 1;
10407c478bd9Sstevel@tonic-gate }
10417c478bd9Sstevel@tonic-gate #ifdef DEBUG
10427c478bd9Sstevel@tonic-gate ASSERT(mp->sbm_mlist != NULL);
10437c478bd9Sstevel@tonic-gate
10447c478bd9Sstevel@tonic-gate if (mp->sbm_flags & SBD_MFLAG_SOURCE) {
10457c478bd9Sstevel@tonic-gate int src, targ;
10467c478bd9Sstevel@tonic-gate
10477c478bd9Sstevel@tonic-gate sbp = (sbd_board_t *)
10487c478bd9Sstevel@tonic-gate mp->sbm_peer->sbm_cm.sbdev_sbp;
10497c478bd9Sstevel@tonic-gate targ = sbp->sb_num;
10507c478bd9Sstevel@tonic-gate sbp = (sbd_board_t *)mp->sbm_cm.sbdev_sbp;
10517c478bd9Sstevel@tonic-gate src = sbp->sb_num;
10527c478bd9Sstevel@tonic-gate PR_MEM("%s: release of board %d requires copy/rename;"
10537c478bd9Sstevel@tonic-gate " selected target board %d\n",
10547c478bd9Sstevel@tonic-gate f, src, targ);
10557c478bd9Sstevel@tonic-gate } else {
10567c478bd9Sstevel@tonic-gate sbp = (sbd_board_t *)mp->sbm_cm.sbdev_sbp;
10577c478bd9Sstevel@tonic-gate PR_MEM("%s: copy/rename not required to release"
10587c478bd9Sstevel@tonic-gate " board %d\n", f, sbp->sb_num);
10597c478bd9Sstevel@tonic-gate }
10607c478bd9Sstevel@tonic-gate
10617c478bd9Sstevel@tonic-gate ASSERT(mp->sbm_flags & SBD_MFLAG_RELOWNER);
10627c478bd9Sstevel@tonic-gate ASSERT(mp->sbm_flags & SBD_MFLAG_RESERVED);
10637c478bd9Sstevel@tonic-gate #endif
10647c478bd9Sstevel@tonic-gate }
10657c478bd9Sstevel@tonic-gate
10667c478bd9Sstevel@tonic-gate return (err_flag);
10677c478bd9Sstevel@tonic-gate }
10687c478bd9Sstevel@tonic-gate
10697c478bd9Sstevel@tonic-gate void
sbd_release_mem_done(sbd_handle_t * hp,int unit)10707c478bd9Sstevel@tonic-gate sbd_release_mem_done(sbd_handle_t *hp, int unit)
10717c478bd9Sstevel@tonic-gate {
10727c478bd9Sstevel@tonic-gate sbd_mem_unit_t *s_mp, *t_mp, *mp;
10737c478bd9Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp);
10747c478bd9Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd);
10757c478bd9Sstevel@tonic-gate int rv;
10767c478bd9Sstevel@tonic-gate static fn_t f = "sbd_release_mem_done";
10777c478bd9Sstevel@tonic-gate
10787c478bd9Sstevel@tonic-gate s_mp = SBD_GET_BOARD_MEMUNIT(sbp, unit);
10797c478bd9Sstevel@tonic-gate sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp;
10807c478bd9Sstevel@tonic-gate
10817c478bd9Sstevel@tonic-gate /*
10827c478bd9Sstevel@tonic-gate * This unit will be flagged with SBD_MFLAG_SOURCE, if it
10837c478bd9Sstevel@tonic-gate * has a target unit.
10847c478bd9Sstevel@tonic-gate */
10857c478bd9Sstevel@tonic-gate if (s_mp->sbm_flags & SBD_MFLAG_SOURCE) {
10867c478bd9Sstevel@tonic-gate t_mp = s_mp->sbm_peer;
10877c478bd9Sstevel@tonic-gate ASSERT(t_mp != NULL);
10887c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_peer == s_mp);
10897c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_flags & SBD_MFLAG_TARGET);
10907c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_flags & SBD_MFLAG_RESERVED);
10917c478bd9Sstevel@tonic-gate } else {
10927c478bd9Sstevel@tonic-gate /* this is no target unit */
10937c478bd9Sstevel@tonic-gate t_mp = NULL;
10947c478bd9Sstevel@tonic-gate }
10957c478bd9Sstevel@tonic-gate
10967c478bd9Sstevel@tonic-gate /* free delete handle */
10977c478bd9Sstevel@tonic-gate ASSERT(s_mp->sbm_flags & SBD_MFLAG_RELOWNER);
10987c478bd9Sstevel@tonic-gate ASSERT(s_mp->sbm_flags & SBD_MFLAG_RESERVED);
10997c478bd9Sstevel@tonic-gate
11007c478bd9Sstevel@tonic-gate rv = kphysm_del_release(s_mp->sbm_memhandle);
11017c478bd9Sstevel@tonic-gate if (rv != KPHYSM_OK) {
11027c478bd9Sstevel@tonic-gate /*
11037c478bd9Sstevel@tonic-gate * can do nothing but complain
11047c478bd9Sstevel@tonic-gate * and hope helpful for debug
11057c478bd9Sstevel@tonic-gate */
11067c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "sbd:%s: unexpected kphysm_del_release"
11077c478bd9Sstevel@tonic-gate " return value %d", f, rv);
11087c478bd9Sstevel@tonic-gate }
11097c478bd9Sstevel@tonic-gate s_mp->sbm_flags &= ~SBD_MFLAG_RELOWNER;
11107c478bd9Sstevel@tonic-gate
11117c478bd9Sstevel@tonic-gate /*
11127c478bd9Sstevel@tonic-gate * If an error was encountered during release, clean up
11137c478bd9Sstevel@tonic-gate * the source (and target, if present) unit data.
11147c478bd9Sstevel@tonic-gate */
11157c478bd9Sstevel@tonic-gate if (SBD_GET_ERR(ep) != 0) {
11167c478bd9Sstevel@tonic-gate
11177c478bd9Sstevel@tonic-gate PR_MEM("%s: unit %d.%d: error %d noted\n",
11187c478bd9Sstevel@tonic-gate f, sbp->sb_num,
11197c478bd9Sstevel@tonic-gate s_mp->sbm_cm.sbdev_unum,
11207c478bd9Sstevel@tonic-gate SBD_GET_ERR(ep));
11217c478bd9Sstevel@tonic-gate
11227c478bd9Sstevel@tonic-gate sbd_mem_cleanup(s_mp, t_mp, ep);
11237c478bd9Sstevel@tonic-gate
11247c478bd9Sstevel@tonic-gate /* bail out */
11257c478bd9Sstevel@tonic-gate return;
11267c478bd9Sstevel@tonic-gate }
11277c478bd9Sstevel@tonic-gate
11287c478bd9Sstevel@tonic-gate SBD_DEV_SET_RELEASED(sbp, SBD_COMP_MEM, unit);
11297c478bd9Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, unit, SBD_STATE_RELEASE);
11307c478bd9Sstevel@tonic-gate
11317c478bd9Sstevel@tonic-gate if (t_mp != NULL) {
11327c478bd9Sstevel@tonic-gate sbp = (sbd_board_t *)t_mp->sbm_cm.sbdev_sbp;
11337c478bd9Sstevel@tonic-gate /*
11347c478bd9Sstevel@tonic-gate * the kphysm delete operation that drained the source
11357c478bd9Sstevel@tonic-gate * board also drained this target board. Since the source
11367c478bd9Sstevel@tonic-gate * board drain is now known to have succeeded, we know this
11377c478bd9Sstevel@tonic-gate * target board is drained too.
11387c478bd9Sstevel@tonic-gate */
11397c478bd9Sstevel@tonic-gate SBD_DEV_SET_RELEASED(sbp, SBD_COMP_MEM,
11407c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_unum);
11417c478bd9Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM,
11427c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_unum,
11437c478bd9Sstevel@tonic-gate SBD_STATE_RELEASE);
11447c478bd9Sstevel@tonic-gate
11457c478bd9Sstevel@tonic-gate /*
11467c478bd9Sstevel@tonic-gate * NOTE: do not transition target's board state,
11477c478bd9Sstevel@tonic-gate * even if the mem-unit was the last configure
11487c478bd9Sstevel@tonic-gate * unit of the board. When copy/rename completes
11497c478bd9Sstevel@tonic-gate * this mem-unit will transitioned back to
11507c478bd9Sstevel@tonic-gate * the configured state. In the meantime, the
11517c478bd9Sstevel@tonic-gate * board's must remain as is.
11527c478bd9Sstevel@tonic-gate */
11537c478bd9Sstevel@tonic-gate }
11547c478bd9Sstevel@tonic-gate
11557c478bd9Sstevel@tonic-gate /* if board(s) had deleted memory, verify it is gone */
11567c478bd9Sstevel@tonic-gate rv = 0;
11577c478bd9Sstevel@tonic-gate memlist_read_lock();
11587c478bd9Sstevel@tonic-gate if (s_mp->sbm_del_mlist != NULL) {
11597c478bd9Sstevel@tonic-gate sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp;
11607c478bd9Sstevel@tonic-gate mp = s_mp;
11617c478bd9Sstevel@tonic-gate rv = memlist_intersect(phys_install, mp->sbm_del_mlist);
11627c478bd9Sstevel@tonic-gate }
11637c478bd9Sstevel@tonic-gate if (rv == 0 && t_mp && t_mp->sbm_del_mlist != NULL) {
11647c478bd9Sstevel@tonic-gate sbp = (sbd_board_t *)t_mp->sbm_cm.sbdev_sbp;
11657c478bd9Sstevel@tonic-gate mp = t_mp;
11667c478bd9Sstevel@tonic-gate rv = memlist_intersect(phys_install, mp->sbm_del_mlist);
11677c478bd9Sstevel@tonic-gate }
11687c478bd9Sstevel@tonic-gate memlist_read_unlock();
11697c478bd9Sstevel@tonic-gate if (rv) {
11707c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "sbd:%s: %smem-unit (%d.%d): "
11717c478bd9Sstevel@tonic-gate "deleted memory still found in phys_install",
11727c478bd9Sstevel@tonic-gate f,
11737c478bd9Sstevel@tonic-gate (mp == t_mp ? "target " : ""),
11747c478bd9Sstevel@tonic-gate sbp->sb_num,
11757c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_unum);
11767c478bd9Sstevel@tonic-gate
11777c478bd9Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_INTERNAL);
11787c478bd9Sstevel@tonic-gate SBD_SET_ERRSTR(ep, sbp->sb_mempath[mp->sbm_cm.sbdev_unum]);
11797c478bd9Sstevel@tonic-gate return;
11807c478bd9Sstevel@tonic-gate }
11817c478bd9Sstevel@tonic-gate
11827c478bd9Sstevel@tonic-gate s_mp->sbm_flags |= SBD_MFLAG_RELDONE;
11837c478bd9Sstevel@tonic-gate if (t_mp != NULL) {
11847c478bd9Sstevel@tonic-gate t_mp->sbm_flags &= ~SBD_MFLAG_RESERVED;
11857c478bd9Sstevel@tonic-gate t_mp->sbm_flags |= SBD_MFLAG_RELDONE;
11867c478bd9Sstevel@tonic-gate }
11877c478bd9Sstevel@tonic-gate
11887c478bd9Sstevel@tonic-gate sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp;
11897c478bd9Sstevel@tonic-gate
11907c478bd9Sstevel@tonic-gate SBD_DEV_SET_UNREFERENCED(sbp, SBD_COMP_MEM, unit);
11917c478bd9Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, unit, SBD_STATE_UNREFERENCED);
11927c478bd9Sstevel@tonic-gate
11937c478bd9Sstevel@tonic-gate PR_MEM("%s: marking mem-unit (%d.%d) release DONE\n",
11947c478bd9Sstevel@tonic-gate f, sbp->sb_num,
11957c478bd9Sstevel@tonic-gate s_mp->sbm_cm.sbdev_unum);
11967c478bd9Sstevel@tonic-gate
11977c478bd9Sstevel@tonic-gate s_mp->sbm_cm.sbdev_ostate = SBD_STAT_UNCONFIGURED;
11987c478bd9Sstevel@tonic-gate
11997c478bd9Sstevel@tonic-gate if (t_mp != NULL) {
12007c478bd9Sstevel@tonic-gate sbp = (sbd_board_t *)t_mp->sbm_cm.sbdev_sbp;
12017c478bd9Sstevel@tonic-gate
12027c478bd9Sstevel@tonic-gate SBD_DEV_SET_UNREFERENCED(sbp, SBD_COMP_MEM,
12037c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_unum);
12047c478bd9Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM,
12057c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_unum,
12067c478bd9Sstevel@tonic-gate SBD_STATE_UNREFERENCED);
12077c478bd9Sstevel@tonic-gate
12087c478bd9Sstevel@tonic-gate sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp;
12097c478bd9Sstevel@tonic-gate
12107c478bd9Sstevel@tonic-gate PR_MEM("%s: marking mem-unit (%d.%d) release DONE\n",
12117c478bd9Sstevel@tonic-gate f, sbp->sb_num,
12127c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_unum);
12137c478bd9Sstevel@tonic-gate
12147c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_ostate = SBD_STAT_UNCONFIGURED;
12157c478bd9Sstevel@tonic-gate }
12167c478bd9Sstevel@tonic-gate }
12177c478bd9Sstevel@tonic-gate
12187c478bd9Sstevel@tonic-gate int
sbd_disconnect_mem(sbd_handle_t * hp,int unit)12197c478bd9Sstevel@tonic-gate sbd_disconnect_mem(sbd_handle_t *hp, int unit)
12207c478bd9Sstevel@tonic-gate {
12217c478bd9Sstevel@tonic-gate static fn_t f = "sbd_disconnect_mem";
12227c478bd9Sstevel@tonic-gate sbd_mem_unit_t *mp;
12237c478bd9Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd);
12247c478bd9Sstevel@tonic-gate
12257c478bd9Sstevel@tonic-gate mp = SBD_GET_BOARD_MEMUNIT(sbp, unit);
12267c478bd9Sstevel@tonic-gate
12277c478bd9Sstevel@tonic-gate ASSERT(mp->sbm_cm.sbdev_state == SBD_STATE_CONNECTED ||
12287c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_state == SBD_STATE_UNCONFIGURED);
12297c478bd9Sstevel@tonic-gate
12307c478bd9Sstevel@tonic-gate PR_MEM("%s...\n", f);
12317c478bd9Sstevel@tonic-gate
12327c478bd9Sstevel@tonic-gate if (mp->sbm_del_mlist && mp->sbm_del_mlist != mp->sbm_mlist)
12337c478bd9Sstevel@tonic-gate memlist_delete(mp->sbm_del_mlist);
12347c478bd9Sstevel@tonic-gate mp->sbm_del_mlist = NULL;
12357c478bd9Sstevel@tonic-gate
12367c478bd9Sstevel@tonic-gate if (mp->sbm_mlist) {
12377c478bd9Sstevel@tonic-gate memlist_delete(mp->sbm_mlist);
12387c478bd9Sstevel@tonic-gate mp->sbm_mlist = NULL;
12397c478bd9Sstevel@tonic-gate }
12407c478bd9Sstevel@tonic-gate
12417c478bd9Sstevel@tonic-gate return (0);
12427c478bd9Sstevel@tonic-gate }
12437c478bd9Sstevel@tonic-gate
12447c478bd9Sstevel@tonic-gate int
sbd_cancel_mem(sbd_handle_t * hp,int unit)12457c478bd9Sstevel@tonic-gate sbd_cancel_mem(sbd_handle_t *hp, int unit)
12467c478bd9Sstevel@tonic-gate {
12477c478bd9Sstevel@tonic-gate sbd_mem_unit_t *s_mp, *t_mp;
12487c478bd9Sstevel@tonic-gate sbd_istate_t state;
12497c478bd9Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd);
12507c478bd9Sstevel@tonic-gate sbd_board_t *tsbp;
12517c478bd9Sstevel@tonic-gate static fn_t f = "sbd_cancel_mem";
12527c478bd9Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp);
12537c478bd9Sstevel@tonic-gate
12547c478bd9Sstevel@tonic-gate s_mp = SBD_GET_BOARD_MEMUNIT(sbp, unit);
12557c478bd9Sstevel@tonic-gate
12567c478bd9Sstevel@tonic-gate state = s_mp->sbm_cm.sbdev_state;
12577c478bd9Sstevel@tonic-gate
12587c478bd9Sstevel@tonic-gate if (s_mp->sbm_flags & SBD_MFLAG_TARGET) {
12597c478bd9Sstevel@tonic-gate /* must cancel source board, not target board */
12607c478bd9Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_INTERNAL);
12617c478bd9Sstevel@tonic-gate SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]);
12627c478bd9Sstevel@tonic-gate return (-1);
12637c478bd9Sstevel@tonic-gate } else if (s_mp->sbm_flags & SBD_MFLAG_SOURCE) {
12647c478bd9Sstevel@tonic-gate t_mp = s_mp->sbm_peer;
12657c478bd9Sstevel@tonic-gate tsbp = t_mp->sbm_cm.sbdev_sbp;
12667c478bd9Sstevel@tonic-gate ASSERT(t_mp != NULL);
12677c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_peer == s_mp);
12687c478bd9Sstevel@tonic-gate
12697c478bd9Sstevel@tonic-gate /* must always match the source board's state */
12707c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_cm.sbdev_state == state);
12717c478bd9Sstevel@tonic-gate } else {
12727c478bd9Sstevel@tonic-gate /* this is no target unit */
12737c478bd9Sstevel@tonic-gate t_mp = NULL;
12747c478bd9Sstevel@tonic-gate }
12757c478bd9Sstevel@tonic-gate
12767c478bd9Sstevel@tonic-gate switch (state) {
12777c478bd9Sstevel@tonic-gate case SBD_STATE_UNREFERENCED: /* state set by sbd_release_mem_done */
12787c478bd9Sstevel@tonic-gate ASSERT((s_mp->sbm_flags & SBD_MFLAG_RELOWNER) == 0);
12797c478bd9Sstevel@tonic-gate
12807c478bd9Sstevel@tonic-gate if (t_mp != NULL && t_mp->sbm_del_mlist != NULL) {
12817c478bd9Sstevel@tonic-gate PR_MEM("%s: undoing target board %d memory delete\n",
12827c478bd9Sstevel@tonic-gate f, tsbp->sb_num);
12837c478bd9Sstevel@tonic-gate sbd_add_memory_spans(tsbp, t_mp->sbm_del_mlist);
12847c478bd9Sstevel@tonic-gate SBD_DEV_CLR_UNREFERENCED(tsbp, SBD_COMP_MEM,
12857c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_unum);
12867c478bd9Sstevel@tonic-gate }
12877c478bd9Sstevel@tonic-gate
12887c478bd9Sstevel@tonic-gate if (s_mp->sbm_del_mlist != NULL) {
12897c478bd9Sstevel@tonic-gate PR_MEM("%s: undoing board %d memory delete\n",
12907c478bd9Sstevel@tonic-gate f, sbp->sb_num);
12917c478bd9Sstevel@tonic-gate sbd_add_memory_spans(sbp, s_mp->sbm_del_mlist);
12927c478bd9Sstevel@tonic-gate }
12937c478bd9Sstevel@tonic-gate
12947c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/
12957c478bd9Sstevel@tonic-gate
12967c478bd9Sstevel@tonic-gate case SBD_STATE_CONFIGURED:
12977c478bd9Sstevel@tonic-gate /*
12987c478bd9Sstevel@tonic-gate * we got here because of an error early in the release process
12997c478bd9Sstevel@tonic-gate * Just leave the memory as is and report the error
13007c478bd9Sstevel@tonic-gate */
13017c478bd9Sstevel@tonic-gate
13027c478bd9Sstevel@tonic-gate ASSERT((s_mp->sbm_flags & SBD_MFLAG_RELOWNER) == 0);
13037c478bd9Sstevel@tonic-gate
13047c478bd9Sstevel@tonic-gate if (t_mp != NULL) {
13057c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_del_mlist == t_mp->sbm_mlist);
13067c478bd9Sstevel@tonic-gate t_mp->sbm_del_mlist = NULL;
13077c478bd9Sstevel@tonic-gate
13087c478bd9Sstevel@tonic-gate if (t_mp->sbm_mlist != NULL) {
13097c478bd9Sstevel@tonic-gate memlist_delete(t_mp->sbm_mlist);
13107c478bd9Sstevel@tonic-gate t_mp->sbm_mlist = NULL;
13117c478bd9Sstevel@tonic-gate }
13127c478bd9Sstevel@tonic-gate
13137c478bd9Sstevel@tonic-gate t_mp->sbm_peer = NULL;
13147c478bd9Sstevel@tonic-gate t_mp->sbm_flags = 0;
13157c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_busy = 0;
13167c478bd9Sstevel@tonic-gate sbd_init_mem_unit_data(t_mp, ep);
13177c478bd9Sstevel@tonic-gate
13187c478bd9Sstevel@tonic-gate SBD_DEV_CLR_RELEASED(tsbp, SBD_COMP_MEM,
13197c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_unum);
13207c478bd9Sstevel@tonic-gate
13217c478bd9Sstevel@tonic-gate SBD_DEVICE_TRANSITION(tsbp, SBD_COMP_MEM,
13227c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_unum,
13237c478bd9Sstevel@tonic-gate SBD_STATE_CONFIGURED);
13247c478bd9Sstevel@tonic-gate }
13257c478bd9Sstevel@tonic-gate
13267c478bd9Sstevel@tonic-gate if (s_mp->sbm_del_mlist != s_mp->sbm_mlist)
13277c478bd9Sstevel@tonic-gate memlist_delete(s_mp->sbm_del_mlist);
13287c478bd9Sstevel@tonic-gate s_mp->sbm_del_mlist = NULL;
13297c478bd9Sstevel@tonic-gate
13307c478bd9Sstevel@tonic-gate if (s_mp->sbm_mlist != NULL) {
13317c478bd9Sstevel@tonic-gate memlist_delete(s_mp->sbm_mlist);
13327c478bd9Sstevel@tonic-gate s_mp->sbm_mlist = NULL;
13337c478bd9Sstevel@tonic-gate }
13347c478bd9Sstevel@tonic-gate
13357c478bd9Sstevel@tonic-gate s_mp->sbm_peer = NULL;
13367c478bd9Sstevel@tonic-gate s_mp->sbm_flags = 0;
13377c478bd9Sstevel@tonic-gate s_mp->sbm_cm.sbdev_busy = 0;
13387c478bd9Sstevel@tonic-gate sbd_init_mem_unit_data(s_mp, ep);
13397c478bd9Sstevel@tonic-gate
13407c478bd9Sstevel@tonic-gate return (0);
13417c478bd9Sstevel@tonic-gate default:
13427c478bd9Sstevel@tonic-gate PR_MEM("%s: WARNING unexpected state (%d) for "
13437c478bd9Sstevel@tonic-gate "mem-unit %d.%d\n",
13447c478bd9Sstevel@tonic-gate f,
13457c478bd9Sstevel@tonic-gate (int)state,
13467c478bd9Sstevel@tonic-gate sbp->sb_num,
13477c478bd9Sstevel@tonic-gate s_mp->sbm_cm.sbdev_unum);
13487c478bd9Sstevel@tonic-gate
13497c478bd9Sstevel@tonic-gate return (-1);
13507c478bd9Sstevel@tonic-gate }
13517c478bd9Sstevel@tonic-gate /*NOTREACHED*/
13527c478bd9Sstevel@tonic-gate }
13537c478bd9Sstevel@tonic-gate
13547c478bd9Sstevel@tonic-gate void
sbd_init_mem_unit(sbd_board_t * sbp,int unit,sbderror_t * ep)13557c478bd9Sstevel@tonic-gate sbd_init_mem_unit(sbd_board_t *sbp, int unit, sbderror_t *ep)
13567c478bd9Sstevel@tonic-gate {
13577c478bd9Sstevel@tonic-gate sbd_istate_t new_state;
13587c478bd9Sstevel@tonic-gate sbd_mem_unit_t *mp;
13597c478bd9Sstevel@tonic-gate dev_info_t *cur_mc_dip;
13607c478bd9Sstevel@tonic-gate int failed_mcs = 0, present_mcs = 0;
13617c478bd9Sstevel@tonic-gate sbd_cond_t mc_cond;
13627c478bd9Sstevel@tonic-gate int i;
13637c478bd9Sstevel@tonic-gate
13647c478bd9Sstevel@tonic-gate mp = SBD_GET_BOARD_MEMUNIT(sbp, unit);
13657c478bd9Sstevel@tonic-gate
13667c478bd9Sstevel@tonic-gate if (SBD_DEV_IS_ATTACHED(sbp, SBD_COMP_MEM, unit)) {
13677c478bd9Sstevel@tonic-gate new_state = SBD_STATE_CONFIGURED;
13687c478bd9Sstevel@tonic-gate } else if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_MEM, unit)) {
13697c478bd9Sstevel@tonic-gate new_state = SBD_STATE_CONNECTED;
13707c478bd9Sstevel@tonic-gate } else if (mp->sbm_cm.sbdev_dip != NULL) {
13717c478bd9Sstevel@tonic-gate new_state = SBD_STATE_OCCUPIED;
13727c478bd9Sstevel@tonic-gate } else {
13737c478bd9Sstevel@tonic-gate new_state = SBD_STATE_EMPTY;
13747c478bd9Sstevel@tonic-gate }
13757c478bd9Sstevel@tonic-gate
13767c478bd9Sstevel@tonic-gate /*
13777c478bd9Sstevel@tonic-gate * Check all the possible memory nodes on the board. If all of them
13787c478bd9Sstevel@tonic-gate * have a failed status mark memory as failed. Otherwise mem is ok
13797c478bd9Sstevel@tonic-gate */
13807c478bd9Sstevel@tonic-gate if (!sbp->sb_memaccess_ok) {
13817c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_cond = SBD_COND_UNKNOWN;
13827c478bd9Sstevel@tonic-gate return;
13837c478bd9Sstevel@tonic-gate }
13847c478bd9Sstevel@tonic-gate
13857c478bd9Sstevel@tonic-gate for (i = 0; i < SBD_NUM_MC_PER_BOARD; i++) {
13867c478bd9Sstevel@tonic-gate cur_mc_dip = mp->sbm_dip[i];
13877c478bd9Sstevel@tonic-gate
13887c478bd9Sstevel@tonic-gate if (cur_mc_dip == NULL)
13897c478bd9Sstevel@tonic-gate continue;
13907c478bd9Sstevel@tonic-gate
13917c478bd9Sstevel@tonic-gate present_mcs |= (1 << i);
13927c478bd9Sstevel@tonic-gate
13937c478bd9Sstevel@tonic-gate mc_cond = sbd_get_comp_cond(cur_mc_dip);
13947c478bd9Sstevel@tonic-gate if (mc_cond == SBD_COND_FAILED) {
13957c478bd9Sstevel@tonic-gate failed_mcs |= (1 << i);
13967c478bd9Sstevel@tonic-gate }
13977c478bd9Sstevel@tonic-gate }
13987c478bd9Sstevel@tonic-gate
13997c478bd9Sstevel@tonic-gate if (failed_mcs == present_mcs) {
14007c478bd9Sstevel@tonic-gate /*
14017c478bd9Sstevel@tonic-gate * All mem nodes failed, therefore mark all mem
14027c478bd9Sstevel@tonic-gate * as failed
14037c478bd9Sstevel@tonic-gate */
14047c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_cond = SBD_COND_FAILED;
14057c478bd9Sstevel@tonic-gate } else {
14067c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_cond = SBD_COND_OK;
14077c478bd9Sstevel@tonic-gate }
14087c478bd9Sstevel@tonic-gate
14097c478bd9Sstevel@tonic-gate sbd_init_mem_unit_data(mp, ep);
14107c478bd9Sstevel@tonic-gate
14117c478bd9Sstevel@tonic-gate /*
14127c478bd9Sstevel@tonic-gate * Any changes to this memory unit should be performed above
14137c478bd9Sstevel@tonic-gate * this call to ensure the unit is fully initialized
14147c478bd9Sstevel@tonic-gate * before transitioning to the new state.
14157c478bd9Sstevel@tonic-gate */
14167c478bd9Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, unit, new_state);
14177c478bd9Sstevel@tonic-gate
14187c478bd9Sstevel@tonic-gate }
14197c478bd9Sstevel@tonic-gate
14207c478bd9Sstevel@tonic-gate static void
sbd_init_mem_unit_data(sbd_mem_unit_t * mp,sbderror_t * ep)14217c478bd9Sstevel@tonic-gate sbd_init_mem_unit_data(sbd_mem_unit_t *mp, sbderror_t *ep)
14227c478bd9Sstevel@tonic-gate {
14237c478bd9Sstevel@tonic-gate uint64_t basepa;
14247c478bd9Sstevel@tonic-gate uint64_t sz;
14257c478bd9Sstevel@tonic-gate sbd_board_t *sbp = mp->sbm_cm.sbdev_sbp;
14267c478bd9Sstevel@tonic-gate sbdp_handle_t *hdp;
14277c478bd9Sstevel@tonic-gate static fn_t f = "sbd_init_mem_unit_data";
14287c478bd9Sstevel@tonic-gate sbd_handle_t *hp = MACHBD2HD(sbp);
14297c478bd9Sstevel@tonic-gate
14307c478bd9Sstevel@tonic-gate PR_MEM("%s...\n", f);
14317c478bd9Sstevel@tonic-gate
14327c478bd9Sstevel@tonic-gate /* a little sanity checking */
14337c478bd9Sstevel@tonic-gate ASSERT(mp->sbm_peer == NULL);
14347c478bd9Sstevel@tonic-gate ASSERT(mp->sbm_flags == 0);
14357c478bd9Sstevel@tonic-gate
14367c478bd9Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp);
14377c478bd9Sstevel@tonic-gate
14387c478bd9Sstevel@tonic-gate /* get basepfn of mem unit */
14397c478bd9Sstevel@tonic-gate if (sbdphw_get_base_physaddr(hdp, mp->sbm_cm.sbdev_dip, &basepa)) {
14407c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "sbd:%s: failed to get physaddr"
14417c478bd9Sstevel@tonic-gate " for mem-unit (%d.%d)",
14427c478bd9Sstevel@tonic-gate f,
14437c478bd9Sstevel@tonic-gate sbp->sb_num,
14447c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_unum);
14457c478bd9Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep);
14467c478bd9Sstevel@tonic-gate sbd_release_sbdp_handle(hdp);
14477c478bd9Sstevel@tonic-gate return;
14487c478bd9Sstevel@tonic-gate }
14497c478bd9Sstevel@tonic-gate mp->sbm_basepfn = _b64top(basepa);
14507c478bd9Sstevel@tonic-gate
14517c478bd9Sstevel@tonic-gate /* attempt to get number of pages from PDA */
14527c478bd9Sstevel@tonic-gate mp->sbm_npages = sbdp_get_mem_size(hdp);
14537c478bd9Sstevel@tonic-gate
14547c478bd9Sstevel@tonic-gate /* if didn't work, calculate using memlist */
14557c478bd9Sstevel@tonic-gate if (mp->sbm_npages == 0) {
14567c478bd9Sstevel@tonic-gate struct memlist *ml, *mlist;
14577c478bd9Sstevel@tonic-gate mlist = sbd_get_memlist(mp, ep);
1458*56f33205SJonathan Adams for (ml = mlist; ml; ml = ml->ml_next)
1459*56f33205SJonathan Adams mp->sbm_npages += btop(ml->ml_size);
14607c478bd9Sstevel@tonic-gate memlist_delete(mlist);
14617c478bd9Sstevel@tonic-gate }
14627c478bd9Sstevel@tonic-gate
14637c478bd9Sstevel@tonic-gate
14647c478bd9Sstevel@tonic-gate if (sbdp_get_mem_alignment(hdp, mp->sbm_cm.sbdev_dip, &sz)) {
14657c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
14667c478bd9Sstevel@tonic-gate "sbd:%s: no alignment for mem-unit (%d.%d)",
14677c478bd9Sstevel@tonic-gate f, sbp->sb_num, mp->sbm_cm.sbdev_unum);
14687c478bd9Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep);
14697c478bd9Sstevel@tonic-gate sbd_release_sbdp_handle(hdp);
14707c478bd9Sstevel@tonic-gate return;
14717c478bd9Sstevel@tonic-gate }
14727c478bd9Sstevel@tonic-gate mp->sbm_alignment_mask = _b64top(sz);
14737c478bd9Sstevel@tonic-gate
14747c478bd9Sstevel@tonic-gate
14757c478bd9Sstevel@tonic-gate mp->sbm_interleave = sbdp_isinterleaved(hdp,
14767c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_dip);
14777c478bd9Sstevel@tonic-gate
14787c478bd9Sstevel@tonic-gate PR_MEM("%s: board %d (basepfn = 0x%lx, npgs = 0x%lx interleave %d)\n",
14797c478bd9Sstevel@tonic-gate f, sbp->sb_num,
14807c478bd9Sstevel@tonic-gate mp->sbm_basepfn,
14817c478bd9Sstevel@tonic-gate mp->sbm_npages,
14827c478bd9Sstevel@tonic-gate mp->sbm_interleave);
14837c478bd9Sstevel@tonic-gate
14847c478bd9Sstevel@tonic-gate sbd_release_sbdp_handle(hdp);
14857c478bd9Sstevel@tonic-gate }
14867c478bd9Sstevel@tonic-gate
14877c478bd9Sstevel@tonic-gate static int
sbd_reserve_mem_spans(memhandle_t * mhp,struct memlist * ml)14887c478bd9Sstevel@tonic-gate sbd_reserve_mem_spans(memhandle_t *mhp, struct memlist *ml)
14897c478bd9Sstevel@tonic-gate {
14907c478bd9Sstevel@tonic-gate int err;
14917c478bd9Sstevel@tonic-gate pfn_t base;
14927c478bd9Sstevel@tonic-gate pgcnt_t npgs;
14937c478bd9Sstevel@tonic-gate struct memlist *mc;
14947c478bd9Sstevel@tonic-gate static fn_t f = "sbd_reserve_mem_spans";
14957c478bd9Sstevel@tonic-gate
14967c478bd9Sstevel@tonic-gate PR_MEM("%s...\n", f);
14977c478bd9Sstevel@tonic-gate
14987c478bd9Sstevel@tonic-gate /*
14997c478bd9Sstevel@tonic-gate * Walk the supplied memlist scheduling each span for removal
15007c478bd9Sstevel@tonic-gate * with kphysm_del_span. It is possible that a span may intersect
15017c478bd9Sstevel@tonic-gate * an area occupied by the cage.
15027c478bd9Sstevel@tonic-gate */
1503*56f33205SJonathan Adams for (mc = ml; mc != NULL; mc = mc->ml_next) {
1504*56f33205SJonathan Adams base = _b64top(mc->ml_address);
1505*56f33205SJonathan Adams npgs = _b64top(mc->ml_size);
15067c478bd9Sstevel@tonic-gate
15077c478bd9Sstevel@tonic-gate err = kphysm_del_span(*mhp, base, npgs);
15087c478bd9Sstevel@tonic-gate if (err != KPHYSM_OK) {
15097c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "sbd:%s memory reserve failed."
15107c478bd9Sstevel@tonic-gate " unexpected kphysm_del_span return value %d;"
15117c478bd9Sstevel@tonic-gate " basepfn=0x%lx npages=%ld",
15127c478bd9Sstevel@tonic-gate f, err, base, npgs);
15137c478bd9Sstevel@tonic-gate return (-1);
15147c478bd9Sstevel@tonic-gate }
15157c478bd9Sstevel@tonic-gate }
15167c478bd9Sstevel@tonic-gate return (0);
15177c478bd9Sstevel@tonic-gate }
15187c478bd9Sstevel@tonic-gate
15197c478bd9Sstevel@tonic-gate /* debug counters */
15207c478bd9Sstevel@tonic-gate int sbd_smt_realigned;
15217c478bd9Sstevel@tonic-gate int sbd_smt_preference[4];
15227c478bd9Sstevel@tonic-gate
15237c478bd9Sstevel@tonic-gate #ifdef DEBUG
15247c478bd9Sstevel@tonic-gate uint_t sbd_ignore_board; /* if bit[bnum-1] set, board won't be candidate */
15257c478bd9Sstevel@tonic-gate #endif
15267c478bd9Sstevel@tonic-gate
15277c478bd9Sstevel@tonic-gate /*
15287c478bd9Sstevel@tonic-gate * Verify that there is no memory overlapping if copy-rename is
15297c478bd9Sstevel@tonic-gate * done with the selected target board.
15307c478bd9Sstevel@tonic-gate *
15317c478bd9Sstevel@tonic-gate * Returns 0 if OK, -1 otherwise.
15327c478bd9Sstevel@tonic-gate */
15337c478bd9Sstevel@tonic-gate static int
sbd_check_boundaries(struct memlist * orig_memlist,sbd_mem_unit_t * s_mp,sbd_mem_unit_t * t_mp)15347c478bd9Sstevel@tonic-gate sbd_check_boundaries(struct memlist *orig_memlist, sbd_mem_unit_t *s_mp,
15357c478bd9Sstevel@tonic-gate sbd_mem_unit_t *t_mp)
15367c478bd9Sstevel@tonic-gate {
15377c478bd9Sstevel@tonic-gate struct memlist *new_memlist;
15387c478bd9Sstevel@tonic-gate int mlret;
15397c478bd9Sstevel@tonic-gate static fn_t f = "sbd_check_boundaries";
15407c478bd9Sstevel@tonic-gate
15417c478bd9Sstevel@tonic-gate new_memlist = memlist_dup(orig_memlist);
15427c478bd9Sstevel@tonic-gate if (new_memlist == NULL) {
15437c478bd9Sstevel@tonic-gate PR_MEM("%s: can't dup original memlist\n", f);
15447c478bd9Sstevel@tonic-gate return (-1);
15457c478bd9Sstevel@tonic-gate }
15467c478bd9Sstevel@tonic-gate
15477c478bd9Sstevel@tonic-gate mlret = memlist_delete_span(
15487c478bd9Sstevel@tonic-gate _ptob64(s_mp->sbm_basepfn),
15497c478bd9Sstevel@tonic-gate _ptob64(s_mp->sbm_npages),
15507c478bd9Sstevel@tonic-gate &new_memlist);
15517c478bd9Sstevel@tonic-gate if (mlret != MEML_SPANOP_OK) {
15527c478bd9Sstevel@tonic-gate PR_MEM("%s: del s/s mlret = %d\n", f, mlret);
15537c478bd9Sstevel@tonic-gate goto check_done;
15547c478bd9Sstevel@tonic-gate }
15557c478bd9Sstevel@tonic-gate
15567c478bd9Sstevel@tonic-gate mlret = memlist_delete_span(
15577c478bd9Sstevel@tonic-gate _ptob64(t_mp->sbm_basepfn),
15587c478bd9Sstevel@tonic-gate _ptob64(t_mp->sbm_npages),
15597c478bd9Sstevel@tonic-gate &new_memlist);
15607c478bd9Sstevel@tonic-gate if (mlret != MEML_SPANOP_OK) {
15617c478bd9Sstevel@tonic-gate PR_MEM("%s: del t/t mlret = %d\n", f, mlret);
15627c478bd9Sstevel@tonic-gate goto check_done;
15637c478bd9Sstevel@tonic-gate }
15647c478bd9Sstevel@tonic-gate
15657c478bd9Sstevel@tonic-gate mlret = memlist_add_span(
15667c478bd9Sstevel@tonic-gate _ptob64(t_mp->sbm_basepfn),
15677c478bd9Sstevel@tonic-gate _ptob64(s_mp->sbm_npages),
15687c478bd9Sstevel@tonic-gate &new_memlist);
15697c478bd9Sstevel@tonic-gate if (mlret != MEML_SPANOP_OK) {
15707c478bd9Sstevel@tonic-gate PR_MEM("%s: add t/s mlret = %d\n", f, mlret);
15717c478bd9Sstevel@tonic-gate goto check_done;
15727c478bd9Sstevel@tonic-gate }
15737c478bd9Sstevel@tonic-gate
15747c478bd9Sstevel@tonic-gate mlret = memlist_add_span(
15757c478bd9Sstevel@tonic-gate _ptob64(s_mp->sbm_basepfn),
15767c478bd9Sstevel@tonic-gate _ptob64(t_mp->sbm_npages),
15777c478bd9Sstevel@tonic-gate &new_memlist);
15787c478bd9Sstevel@tonic-gate if (mlret != MEML_SPANOP_OK) {
15797c478bd9Sstevel@tonic-gate PR_MEM("%s: add s/t mlret = %d\n", f, mlret);
15807c478bd9Sstevel@tonic-gate }
15817c478bd9Sstevel@tonic-gate
15827c478bd9Sstevel@tonic-gate check_done:
15837c478bd9Sstevel@tonic-gate memlist_delete(new_memlist);
15847c478bd9Sstevel@tonic-gate
15857c478bd9Sstevel@tonic-gate if (mlret == MEML_SPANOP_OK)
15867c478bd9Sstevel@tonic-gate return (0);
15877c478bd9Sstevel@tonic-gate else
15887c478bd9Sstevel@tonic-gate return (-1);
15897c478bd9Sstevel@tonic-gate }
15907c478bd9Sstevel@tonic-gate
15917c478bd9Sstevel@tonic-gate /*
15927c478bd9Sstevel@tonic-gate * Find and reserve a copy/rename target board suitable for the
15937c478bd9Sstevel@tonic-gate * given source board.
15947c478bd9Sstevel@tonic-gate * All boards in the system are examined and categorized in relation to
15957c478bd9Sstevel@tonic-gate * their memory size versus the source board's memory size. Order of
15967c478bd9Sstevel@tonic-gate * preference is:
15977c478bd9Sstevel@tonic-gate * 1st: board has same memory size
15987c478bd9Sstevel@tonic-gate * 2nd: board has larger memory size
15997c478bd9Sstevel@tonic-gate * 3rd: board has smaller memory size
16007c478bd9Sstevel@tonic-gate * 4th: board has smaller memory size, available memory will be reduced.
16017c478bd9Sstevel@tonic-gate * Boards in category 3 and 4 will have their MC's reprogrammed to locate the
16027c478bd9Sstevel@tonic-gate * span to which the MC responds to address span that appropriately covers
16037c478bd9Sstevel@tonic-gate * the nonrelocatable span of the source board.
16047c478bd9Sstevel@tonic-gate */
16057c478bd9Sstevel@tonic-gate static int
sbd_select_mem_target(sbd_handle_t * hp,sbd_mem_unit_t * s_mp,struct memlist * s_ml)16067c478bd9Sstevel@tonic-gate sbd_select_mem_target(sbd_handle_t *hp,
16077c478bd9Sstevel@tonic-gate sbd_mem_unit_t *s_mp, struct memlist *s_ml)
16087c478bd9Sstevel@tonic-gate {
16097c478bd9Sstevel@tonic-gate uint64_t sz;
16107c478bd9Sstevel@tonic-gate pgcnt_t sm;
16117c478bd9Sstevel@tonic-gate int n_sets = 4; /* same, larger, smaller, clipped */
16127c478bd9Sstevel@tonic-gate int preference; /* lower value is higher preference */
16137c478bd9Sstevel@tonic-gate int n_units_per_set;
16147c478bd9Sstevel@tonic-gate int idx;
16157c478bd9Sstevel@tonic-gate sbd_mem_unit_t **sets;
16167c478bd9Sstevel@tonic-gate sbdp_handle_t *hdp;
16177c478bd9Sstevel@tonic-gate int t_bd;
16187c478bd9Sstevel@tonic-gate sbd_softstate_t *softsp;
16197c478bd9Sstevel@tonic-gate int t_unit;
16207c478bd9Sstevel@tonic-gate int max_boards;
16217c478bd9Sstevel@tonic-gate int rv;
16227c478bd9Sstevel@tonic-gate sbd_board_t *s_sbp, *t_sbp;
16237c478bd9Sstevel@tonic-gate sbd_mem_unit_t *t_mp, *c_mp;
16247c478bd9Sstevel@tonic-gate struct memlist *d_ml, *t_ml, *x_ml;
16257c478bd9Sstevel@tonic-gate memquery_t s_mq = {0};
16267c478bd9Sstevel@tonic-gate static fn_t f = "sbd_select_mem_target";
16277c478bd9Sstevel@tonic-gate
16287c478bd9Sstevel@tonic-gate PR_MEM("%s...\n", f);
16297c478bd9Sstevel@tonic-gate
16307c478bd9Sstevel@tonic-gate ASSERT(s_ml != NULL);
16317c478bd9Sstevel@tonic-gate
16327c478bd9Sstevel@tonic-gate s_sbp = s_mp->sbm_cm.sbdev_sbp;
16337c478bd9Sstevel@tonic-gate
16347c478bd9Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(s_sbp, hp);
16357c478bd9Sstevel@tonic-gate
16367c478bd9Sstevel@tonic-gate if (sbdp_get_mem_alignment(hdp, s_mp->sbm_cm.sbdev_dip, &sz)) {
16377c478bd9Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp);
16387c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
16397c478bd9Sstevel@tonic-gate "sbd:%s: no alignment for mem-unit (%d.%d)",
16407c478bd9Sstevel@tonic-gate f, s_sbp->sb_num, s_mp->sbm_cm.sbdev_unum);
16417c478bd9Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep);
16427c478bd9Sstevel@tonic-gate sbd_release_sbdp_handle(hdp);
16437c478bd9Sstevel@tonic-gate return (-1);
16447c478bd9Sstevel@tonic-gate }
16457c478bd9Sstevel@tonic-gate sm = sz - 1;
16467c478bd9Sstevel@tonic-gate sbd_release_sbdp_handle(hdp);
16477c478bd9Sstevel@tonic-gate
16487c478bd9Sstevel@tonic-gate softsp = (sbd_softstate_t *)s_sbp->sb_softsp;
16497c478bd9Sstevel@tonic-gate
16507c478bd9Sstevel@tonic-gate max_boards = softsp->max_boards;
16517c478bd9Sstevel@tonic-gate n_units_per_set = max_boards * MAX_MEM_UNITS_PER_BOARD;
16527c478bd9Sstevel@tonic-gate sets = GETSTRUCT(sbd_mem_unit_t *, n_units_per_set * n_sets);
16537c478bd9Sstevel@tonic-gate
16547c478bd9Sstevel@tonic-gate /*
16557c478bd9Sstevel@tonic-gate * Make one pass through all memory units on all boards
16567c478bd9Sstevel@tonic-gate * and categorize them with respect to the source board.
16577c478bd9Sstevel@tonic-gate */
16587c478bd9Sstevel@tonic-gate for (t_bd = 0; t_bd < max_boards; t_bd++) {
16597c478bd9Sstevel@tonic-gate /*
16607c478bd9Sstevel@tonic-gate * The board structs are a contiguous array
16617c478bd9Sstevel@tonic-gate * so we take advantage of that to find the
16627c478bd9Sstevel@tonic-gate * correct board struct pointer for a given
16637c478bd9Sstevel@tonic-gate * board number.
16647c478bd9Sstevel@tonic-gate */
16657c478bd9Sstevel@tonic-gate t_sbp = (sbd_board_t *)softsp->sbd_boardlist;
16667c478bd9Sstevel@tonic-gate t_sbp += t_bd;
16677c478bd9Sstevel@tonic-gate
16687c478bd9Sstevel@tonic-gate /* source board can not be its own target */
16697c478bd9Sstevel@tonic-gate if (s_sbp->sb_num == t_sbp->sb_num)
16707c478bd9Sstevel@tonic-gate continue;
16717c478bd9Sstevel@tonic-gate
16727c478bd9Sstevel@tonic-gate for (t_unit = 0; t_unit < MAX_MEM_UNITS_PER_BOARD; t_unit++) {
16737c478bd9Sstevel@tonic-gate
16747c478bd9Sstevel@tonic-gate t_mp = SBD_GET_BOARD_MEMUNIT(t_sbp, t_unit);
16757c478bd9Sstevel@tonic-gate
16767c478bd9Sstevel@tonic-gate /* this memory node must be attached */
16777c478bd9Sstevel@tonic-gate if (!SBD_DEV_IS_ATTACHED(t_sbp, SBD_COMP_MEM, t_unit))
16787c478bd9Sstevel@tonic-gate continue;
16797c478bd9Sstevel@tonic-gate
16807c478bd9Sstevel@tonic-gate /* source unit can not be its own target */
16817c478bd9Sstevel@tonic-gate if (s_mp == t_mp) {
16827c478bd9Sstevel@tonic-gate /* catch this in debug kernels */
16837c478bd9Sstevel@tonic-gate ASSERT(0);
16847c478bd9Sstevel@tonic-gate continue;
16857c478bd9Sstevel@tonic-gate }
16867c478bd9Sstevel@tonic-gate
16877c478bd9Sstevel@tonic-gate /*
16887c478bd9Sstevel@tonic-gate * this memory node must not already be reserved
16897c478bd9Sstevel@tonic-gate * by some other memory delete operation.
16907c478bd9Sstevel@tonic-gate */
16917c478bd9Sstevel@tonic-gate if (t_mp->sbm_flags & SBD_MFLAG_RESERVED)
16927c478bd9Sstevel@tonic-gate continue;
16937c478bd9Sstevel@tonic-gate
16947c478bd9Sstevel@tonic-gate /*
16957c478bd9Sstevel@tonic-gate * categorize the memory node
16967c478bd9Sstevel@tonic-gate * If this is a smaller memory node, create a
16977c478bd9Sstevel@tonic-gate * temporary, edited copy of the source board's
16987c478bd9Sstevel@tonic-gate * memlist containing only the span of the non-
16997c478bd9Sstevel@tonic-gate * relocatable pages.
17007c478bd9Sstevel@tonic-gate */
17017c478bd9Sstevel@tonic-gate if (t_mp->sbm_npages == s_mp->sbm_npages) {
17027c478bd9Sstevel@tonic-gate preference = 0;
17037c478bd9Sstevel@tonic-gate t_mp->sbm_slice_offset = 0;
17047c478bd9Sstevel@tonic-gate } else if (t_mp->sbm_npages > s_mp->sbm_npages) {
17057c478bd9Sstevel@tonic-gate preference = 1;
17067c478bd9Sstevel@tonic-gate t_mp->sbm_slice_offset = 0;
17077c478bd9Sstevel@tonic-gate } else {
17087c478bd9Sstevel@tonic-gate /*
17097c478bd9Sstevel@tonic-gate * We do not allow other options right now
17107c478bd9Sstevel@tonic-gate */
17117c478bd9Sstevel@tonic-gate continue;
17127c478bd9Sstevel@tonic-gate }
17137c478bd9Sstevel@tonic-gate
17147c478bd9Sstevel@tonic-gate sbd_smt_preference[preference]++;
17157c478bd9Sstevel@tonic-gate
17167c478bd9Sstevel@tonic-gate /* calculate index to start of preference set */
17177c478bd9Sstevel@tonic-gate idx = n_units_per_set * preference;
17187c478bd9Sstevel@tonic-gate /* calculate offset to respective element */
17197c478bd9Sstevel@tonic-gate idx += t_bd * MAX_MEM_UNITS_PER_BOARD + t_unit;
17207c478bd9Sstevel@tonic-gate
17217c478bd9Sstevel@tonic-gate ASSERT(idx < n_units_per_set * n_sets);
17227c478bd9Sstevel@tonic-gate sets[idx] = t_mp;
17237c478bd9Sstevel@tonic-gate }
17247c478bd9Sstevel@tonic-gate }
17257c478bd9Sstevel@tonic-gate
17267c478bd9Sstevel@tonic-gate /*
17277c478bd9Sstevel@tonic-gate * NOTE: this would be a good place to sort each candidate
17287c478bd9Sstevel@tonic-gate * set in to some desired order, e.g. memory size in ascending
17297c478bd9Sstevel@tonic-gate * order. Without an additional sorting step here, the order
17307c478bd9Sstevel@tonic-gate * within a set is ascending board number order.
17317c478bd9Sstevel@tonic-gate */
17327c478bd9Sstevel@tonic-gate
17337c478bd9Sstevel@tonic-gate c_mp = NULL;
17347c478bd9Sstevel@tonic-gate x_ml = NULL;
17357c478bd9Sstevel@tonic-gate t_ml = NULL;
17367c478bd9Sstevel@tonic-gate for (idx = 0; idx < n_units_per_set * n_sets; idx++) {
17377c478bd9Sstevel@tonic-gate memquery_t mq;
17387c478bd9Sstevel@tonic-gate
17397c478bd9Sstevel@tonic-gate /* cleanup t_ml after previous pass */
17407c478bd9Sstevel@tonic-gate if (t_ml != NULL) {
17417c478bd9Sstevel@tonic-gate memlist_delete(t_ml);
17427c478bd9Sstevel@tonic-gate t_ml = NULL;
17437c478bd9Sstevel@tonic-gate }
17447c478bd9Sstevel@tonic-gate
17457c478bd9Sstevel@tonic-gate /* get candidate target board mem unit */
17467c478bd9Sstevel@tonic-gate t_mp = sets[idx];
17477c478bd9Sstevel@tonic-gate if (t_mp == NULL)
17487c478bd9Sstevel@tonic-gate continue;
17497c478bd9Sstevel@tonic-gate
17507c478bd9Sstevel@tonic-gate t_sbp = t_mp->sbm_cm.sbdev_sbp;
17517c478bd9Sstevel@tonic-gate
17527c478bd9Sstevel@tonic-gate /* get target board memlist */
17537c478bd9Sstevel@tonic-gate t_ml = sbd_get_memlist(t_mp, SBD_HD2ERR(hp));
17547c478bd9Sstevel@tonic-gate if (t_ml == NULL) {
17557c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "sbd:%s: no memlist for"
17567c478bd9Sstevel@tonic-gate " mem-unit %d, board %d",
17577c478bd9Sstevel@tonic-gate f,
17587c478bd9Sstevel@tonic-gate t_sbp->sb_num,
17597c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_unum);
17607c478bd9Sstevel@tonic-gate
17617c478bd9Sstevel@tonic-gate continue;
17627c478bd9Sstevel@tonic-gate }
17637c478bd9Sstevel@tonic-gate
17647c478bd9Sstevel@tonic-gate /* get appropriate source board memlist */
17657c478bd9Sstevel@tonic-gate if (t_mp->sbm_npages < s_mp->sbm_npages) {
17667c478bd9Sstevel@tonic-gate spgcnt_t excess;
17677c478bd9Sstevel@tonic-gate
17687c478bd9Sstevel@tonic-gate /*
17697c478bd9Sstevel@tonic-gate * make a copy of the source board memlist
17707c478bd9Sstevel@tonic-gate * then edit it to remove the spans that
17717c478bd9Sstevel@tonic-gate * are outside the calculated span of
17727c478bd9Sstevel@tonic-gate * [pfn..s_mq.last_nonrelocatable].
17737c478bd9Sstevel@tonic-gate */
17747c478bd9Sstevel@tonic-gate if (x_ml != NULL)
17757c478bd9Sstevel@tonic-gate memlist_delete(x_ml);
17767c478bd9Sstevel@tonic-gate
17777c478bd9Sstevel@tonic-gate x_ml = memlist_dup(s_ml);
17787c478bd9Sstevel@tonic-gate if (x_ml == NULL) {
17797c478bd9Sstevel@tonic-gate PR_MEM("%s: memlist_dup failed\n", f);
17807c478bd9Sstevel@tonic-gate /* TODO: should abort */
17817c478bd9Sstevel@tonic-gate continue;
17827c478bd9Sstevel@tonic-gate }
17837c478bd9Sstevel@tonic-gate
17847c478bd9Sstevel@tonic-gate /* trim off lower portion */
17857c478bd9Sstevel@tonic-gate excess = t_mp->sbm_slice_offset;
17867c478bd9Sstevel@tonic-gate if (excess > 0) {
17877c478bd9Sstevel@tonic-gate int mlret;
17887c478bd9Sstevel@tonic-gate
17897c478bd9Sstevel@tonic-gate mlret = memlist_delete_span(
17907c478bd9Sstevel@tonic-gate _ptob64(s_mp->sbm_basepfn),
17917c478bd9Sstevel@tonic-gate _ptob64(excess),
17927c478bd9Sstevel@tonic-gate &x_ml);
17937c478bd9Sstevel@tonic-gate PR_MEM("%s: mlret = %d\n", f, mlret);
17947c478bd9Sstevel@tonic-gate }
17957c478bd9Sstevel@tonic-gate
17967c478bd9Sstevel@tonic-gate /*
17977c478bd9Sstevel@tonic-gate * Since this candidate target board is smaller
17987c478bd9Sstevel@tonic-gate * than the source board, s_mq must have been
17997c478bd9Sstevel@tonic-gate * initialized in previous loop while processing
18007c478bd9Sstevel@tonic-gate * this or some other candidate board.
18017c478bd9Sstevel@tonic-gate * FIXME: this is weak.
18027c478bd9Sstevel@tonic-gate */
18037c478bd9Sstevel@tonic-gate ASSERT(s_mq.phys_pages != 0);
18047c478bd9Sstevel@tonic-gate
18057c478bd9Sstevel@tonic-gate /* trim off upper portion */
18067c478bd9Sstevel@tonic-gate excess = (s_mp->sbm_basepfn + s_mp->sbm_npages)
18077c478bd9Sstevel@tonic-gate - (s_mq.last_nonrelocatable + 1);
18087c478bd9Sstevel@tonic-gate if (excess > 0) {
18097c478bd9Sstevel@tonic-gate pfn_t p;
18107c478bd9Sstevel@tonic-gate int mlret;
18117c478bd9Sstevel@tonic-gate
18127c478bd9Sstevel@tonic-gate p = s_mq.last_nonrelocatable + 1;
18137c478bd9Sstevel@tonic-gate p -= excess;
18147c478bd9Sstevel@tonic-gate
18157c478bd9Sstevel@tonic-gate mlret = memlist_delete_span(
18167c478bd9Sstevel@tonic-gate _ptob64(p),
18177c478bd9Sstevel@tonic-gate _ptob64(excess),
18187c478bd9Sstevel@tonic-gate &x_ml);
18197c478bd9Sstevel@tonic-gate PR_MEM("%s: mlret = %d\n", f, mlret);
18207c478bd9Sstevel@tonic-gate }
18217c478bd9Sstevel@tonic-gate
18227c478bd9Sstevel@tonic-gate PR_MEM("%s: brd %d: edited source memlist:\n",
18237c478bd9Sstevel@tonic-gate f, s_sbp->sb_num);
18247c478bd9Sstevel@tonic-gate SBD_MEMLIST_DUMP(x_ml);
18257c478bd9Sstevel@tonic-gate
18267c478bd9Sstevel@tonic-gate #ifdef DEBUG
18277c478bd9Sstevel@tonic-gate /* sanity check memlist */
18287c478bd9Sstevel@tonic-gate d_ml = x_ml;
1829*56f33205SJonathan Adams while (d_ml->ml_next != NULL)
1830*56f33205SJonathan Adams d_ml = d_ml->ml_next;
1831*56f33205SJonathan Adams ASSERT(x_ml->ml_address == _ptob64(s_mp->sbm_basepfn) +
18327c478bd9Sstevel@tonic-gate _ptob64(t_mp->sbm_slice_offset));
1833*56f33205SJonathan Adams ASSERT(d_ml->ml_address + d_ml->ml_size ==
18347c478bd9Sstevel@tonic-gate _ptob64(s_mq.last_nonrelocatable + 1));
18357c478bd9Sstevel@tonic-gate #endif
18367c478bd9Sstevel@tonic-gate
18377c478bd9Sstevel@tonic-gate /*
18387c478bd9Sstevel@tonic-gate * x_ml now describes only the portion of the
18397c478bd9Sstevel@tonic-gate * source board that will be moved during the
18407c478bd9Sstevel@tonic-gate * copy/rename operation.
18417c478bd9Sstevel@tonic-gate */
18427c478bd9Sstevel@tonic-gate d_ml = x_ml;
18437c478bd9Sstevel@tonic-gate } else {
18447c478bd9Sstevel@tonic-gate /* use original memlist; all spans will be moved */
18457c478bd9Sstevel@tonic-gate d_ml = s_ml;
18467c478bd9Sstevel@tonic-gate }
18477c478bd9Sstevel@tonic-gate
18487c478bd9Sstevel@tonic-gate /* verify target can support source memory spans. */
18497c478bd9Sstevel@tonic-gate if (memlist_canfit(d_ml, t_ml) == 0) {
18507c478bd9Sstevel@tonic-gate PR_MEM("%s: source memlist won't"
18517c478bd9Sstevel@tonic-gate " fit in target memlist\n", f);
18527c478bd9Sstevel@tonic-gate PR_MEM("%s: source memlist:\n", f);
18537c478bd9Sstevel@tonic-gate SBD_MEMLIST_DUMP(d_ml);
18547c478bd9Sstevel@tonic-gate PR_MEM("%s: target memlist:\n", f);
18557c478bd9Sstevel@tonic-gate SBD_MEMLIST_DUMP(t_ml);
18567c478bd9Sstevel@tonic-gate
18577c478bd9Sstevel@tonic-gate continue;
18587c478bd9Sstevel@tonic-gate }
18597c478bd9Sstevel@tonic-gate
18607c478bd9Sstevel@tonic-gate /* NOTE: the value of d_ml is not used beyond this point */
18617c478bd9Sstevel@tonic-gate
18627c478bd9Sstevel@tonic-gate PR_MEM("%s: checking for no-reloc on board %d, "
18637c478bd9Sstevel@tonic-gate " basepfn=0x%lx, npages=%ld\n",
18647c478bd9Sstevel@tonic-gate f,
18657c478bd9Sstevel@tonic-gate t_sbp->sb_num,
18667c478bd9Sstevel@tonic-gate t_mp->sbm_basepfn,
18677c478bd9Sstevel@tonic-gate t_mp->sbm_npages);
18687c478bd9Sstevel@tonic-gate
18697c478bd9Sstevel@tonic-gate rv = kphysm_del_span_query(
18707c478bd9Sstevel@tonic-gate t_mp->sbm_basepfn, t_mp->sbm_npages, &mq);
18717c478bd9Sstevel@tonic-gate if (rv != KPHYSM_OK) {
18727c478bd9Sstevel@tonic-gate PR_MEM("%s: kphysm_del_span_query:"
18737c478bd9Sstevel@tonic-gate " unexpected return value %d\n", f, rv);
18747c478bd9Sstevel@tonic-gate
18757c478bd9Sstevel@tonic-gate continue;
18767c478bd9Sstevel@tonic-gate }
18777c478bd9Sstevel@tonic-gate
18787c478bd9Sstevel@tonic-gate if (mq.nonrelocatable != 0) {
18797c478bd9Sstevel@tonic-gate PR_MEM("%s: candidate board %d has"
18807c478bd9Sstevel@tonic-gate " nonrelocatable span [0x%lx..0x%lx]\n",
18817c478bd9Sstevel@tonic-gate f,
18827c478bd9Sstevel@tonic-gate t_sbp->sb_num,
18837c478bd9Sstevel@tonic-gate mq.first_nonrelocatable,
18847c478bd9Sstevel@tonic-gate mq.last_nonrelocatable);
18857c478bd9Sstevel@tonic-gate
18867c478bd9Sstevel@tonic-gate continue;
18877c478bd9Sstevel@tonic-gate }
18887c478bd9Sstevel@tonic-gate
18897c478bd9Sstevel@tonic-gate #ifdef DEBUG
18907c478bd9Sstevel@tonic-gate /*
18917c478bd9Sstevel@tonic-gate * This is a debug tool for excluding certain boards
18927c478bd9Sstevel@tonic-gate * from being selected as a target board candidate.
18937c478bd9Sstevel@tonic-gate * sbd_ignore_board is only tested by this driver.
18947c478bd9Sstevel@tonic-gate * It must be set with adb, obp, /etc/system or your
18957c478bd9Sstevel@tonic-gate * favorite debugger.
18967c478bd9Sstevel@tonic-gate */
18977c478bd9Sstevel@tonic-gate if (sbd_ignore_board &
18987c478bd9Sstevel@tonic-gate (1 << (t_sbp->sb_num - 1))) {
18997c478bd9Sstevel@tonic-gate PR_MEM("%s: sbd_ignore_board flag set,"
19007c478bd9Sstevel@tonic-gate " ignoring board %d as candidate\n",
19017c478bd9Sstevel@tonic-gate f, t_sbp->sb_num);
19027c478bd9Sstevel@tonic-gate continue;
19037c478bd9Sstevel@tonic-gate }
19047c478bd9Sstevel@tonic-gate #endif
19057c478bd9Sstevel@tonic-gate
19067c478bd9Sstevel@tonic-gate /*
19077c478bd9Sstevel@tonic-gate * Make sure there is no memory overlap if this
19087c478bd9Sstevel@tonic-gate * target board is used for copy-rename.
19097c478bd9Sstevel@tonic-gate */
19107c478bd9Sstevel@tonic-gate if (sbd_check_boundaries(phys_install, s_mp, t_mp) != 0)
19117c478bd9Sstevel@tonic-gate continue;
19127c478bd9Sstevel@tonic-gate
19137c478bd9Sstevel@tonic-gate /*
19147c478bd9Sstevel@tonic-gate * Reserve excess source board memory, if any.
19157c478bd9Sstevel@tonic-gate *
19167c478bd9Sstevel@tonic-gate * When the number of pages on the candidate target
19177c478bd9Sstevel@tonic-gate * board is less than the number of pages on the source,
19187c478bd9Sstevel@tonic-gate * then some spans (clearly) of the source board's address
19197c478bd9Sstevel@tonic-gate * space will not be covered by physical memory after the
19207c478bd9Sstevel@tonic-gate * copy/rename completes. The following code block
19217c478bd9Sstevel@tonic-gate * schedules those spans to be deleted.
19227c478bd9Sstevel@tonic-gate */
19237c478bd9Sstevel@tonic-gate if (t_mp->sbm_npages < s_mp->sbm_npages) {
19247c478bd9Sstevel@tonic-gate pfn_t pfn;
19257c478bd9Sstevel@tonic-gate int mlret;
19267c478bd9Sstevel@tonic-gate
19277c478bd9Sstevel@tonic-gate d_ml = memlist_dup(s_ml);
19287c478bd9Sstevel@tonic-gate if (d_ml == NULL) {
19297c478bd9Sstevel@tonic-gate PR_MEM("%s: cant dup src brd memlist\n", f);
19307c478bd9Sstevel@tonic-gate /* TODO: should abort */
19317c478bd9Sstevel@tonic-gate continue;
19327c478bd9Sstevel@tonic-gate }
19337c478bd9Sstevel@tonic-gate
19347c478bd9Sstevel@tonic-gate /* calculate base pfn relative to target board */
19357c478bd9Sstevel@tonic-gate pfn = s_mp->sbm_basepfn & ~sm;
19367c478bd9Sstevel@tonic-gate pfn += t_mp->sbm_slice_offset;
19377c478bd9Sstevel@tonic-gate
19387c478bd9Sstevel@tonic-gate /* remove span that will reside on candidate board */
19397c478bd9Sstevel@tonic-gate mlret = memlist_delete_span(
19407c478bd9Sstevel@tonic-gate _ptob64(pfn),
19417c478bd9Sstevel@tonic-gate _ptob64(t_mp->sbm_npages),
19427c478bd9Sstevel@tonic-gate &d_ml);
19437c478bd9Sstevel@tonic-gate PR_MEM("%s: mlret = %d\n", f, mlret);
19447c478bd9Sstevel@tonic-gate
19457c478bd9Sstevel@tonic-gate PR_MEM("%s: brd %d: reserving src brd memlist:\n",
19467c478bd9Sstevel@tonic-gate f, s_sbp->sb_num);
19477c478bd9Sstevel@tonic-gate SBD_MEMLIST_DUMP(d_ml);
19487c478bd9Sstevel@tonic-gate
19497c478bd9Sstevel@tonic-gate /* reserve excess spans */
19507c478bd9Sstevel@tonic-gate if (sbd_reserve_mem_spans(
19517c478bd9Sstevel@tonic-gate &s_mp->sbm_memhandle, d_ml) != 0) {
19527c478bd9Sstevel@tonic-gate
19537c478bd9Sstevel@tonic-gate /* likely more non-reloc pages appeared */
19547c478bd9Sstevel@tonic-gate /* TODO: restart from top? */
19557c478bd9Sstevel@tonic-gate continue;
19567c478bd9Sstevel@tonic-gate }
19577c478bd9Sstevel@tonic-gate } else {
19587c478bd9Sstevel@tonic-gate /* no excess source board memory */
19597c478bd9Sstevel@tonic-gate d_ml = NULL;
19607c478bd9Sstevel@tonic-gate }
19617c478bd9Sstevel@tonic-gate
19627c478bd9Sstevel@tonic-gate s_mp->sbm_flags |= SBD_MFLAG_RESERVED;
19637c478bd9Sstevel@tonic-gate
19647c478bd9Sstevel@tonic-gate /*
19657c478bd9Sstevel@tonic-gate * reserve all memory on target board.
19667c478bd9Sstevel@tonic-gate * NOTE: source board's memhandle is used.
19677c478bd9Sstevel@tonic-gate *
19687c478bd9Sstevel@tonic-gate * If this succeeds (eq 0), then target selection is
19697c478bd9Sstevel@tonic-gate * complete and all unwanted memory spans, both source and
19707c478bd9Sstevel@tonic-gate * target, have been reserved. Loop is terminated.
19717c478bd9Sstevel@tonic-gate */
19727c478bd9Sstevel@tonic-gate if (sbd_reserve_mem_spans(&s_mp->sbm_memhandle, t_ml) == 0) {
19737c478bd9Sstevel@tonic-gate PR_MEM("%s: brd %d: target board memory reserved\n",
19747c478bd9Sstevel@tonic-gate f, t_sbp->sb_num);
19757c478bd9Sstevel@tonic-gate
19767c478bd9Sstevel@tonic-gate /* a candidate target board is now reserved */
19777c478bd9Sstevel@tonic-gate t_mp->sbm_flags |= SBD_MFLAG_RESERVED;
19787c478bd9Sstevel@tonic-gate c_mp = t_mp;
19797c478bd9Sstevel@tonic-gate
19807c478bd9Sstevel@tonic-gate /* *** EXITING LOOP *** */
19817c478bd9Sstevel@tonic-gate break;
19827c478bd9Sstevel@tonic-gate }
19837c478bd9Sstevel@tonic-gate
19847c478bd9Sstevel@tonic-gate /* did not successfully reserve the target board. */
19857c478bd9Sstevel@tonic-gate PR_MEM("%s: could not reserve target board %d\n",
19867c478bd9Sstevel@tonic-gate f, t_sbp->sb_num);
19877c478bd9Sstevel@tonic-gate
19887c478bd9Sstevel@tonic-gate /*
19897c478bd9Sstevel@tonic-gate * NOTE: an undo of the sbd_reserve_mem_span work
19907c478bd9Sstevel@tonic-gate * will happen automatically when the memhandle
19917c478bd9Sstevel@tonic-gate * (s_mp->sbm_memhandle) is kphysm_del_release'd.
19927c478bd9Sstevel@tonic-gate */
19937c478bd9Sstevel@tonic-gate
19947c478bd9Sstevel@tonic-gate s_mp->sbm_flags &= ~SBD_MFLAG_RESERVED;
19957c478bd9Sstevel@tonic-gate }
19967c478bd9Sstevel@tonic-gate
19977c478bd9Sstevel@tonic-gate /* clean up after memlist editing logic */
19987c478bd9Sstevel@tonic-gate if (x_ml != NULL)
19997c478bd9Sstevel@tonic-gate memlist_delete(x_ml);
20007c478bd9Sstevel@tonic-gate
20017c478bd9Sstevel@tonic-gate FREESTRUCT(sets, sbd_mem_unit_t *, n_units_per_set * n_sets);
20027c478bd9Sstevel@tonic-gate
20037c478bd9Sstevel@tonic-gate /*
20047c478bd9Sstevel@tonic-gate * c_mp will be NULL when the entire sets[] array
20057c478bd9Sstevel@tonic-gate * has been searched without reserving a target board.
20067c478bd9Sstevel@tonic-gate */
20077c478bd9Sstevel@tonic-gate if (c_mp == NULL) {
20087c478bd9Sstevel@tonic-gate PR_MEM("%s: brd %d: target selection failed.\n",
20097c478bd9Sstevel@tonic-gate f, s_sbp->sb_num);
20107c478bd9Sstevel@tonic-gate
20117c478bd9Sstevel@tonic-gate if (t_ml != NULL)
20127c478bd9Sstevel@tonic-gate memlist_delete(t_ml);
20137c478bd9Sstevel@tonic-gate
20147c478bd9Sstevel@tonic-gate return (-1);
20157c478bd9Sstevel@tonic-gate }
20167c478bd9Sstevel@tonic-gate
20177c478bd9Sstevel@tonic-gate PR_MEM("%s: found target board %d for source board %d\n",
20187c478bd9Sstevel@tonic-gate f,
20197c478bd9Sstevel@tonic-gate t_sbp->sb_num,
20207c478bd9Sstevel@tonic-gate s_sbp->sb_num);
20217c478bd9Sstevel@tonic-gate
20227c478bd9Sstevel@tonic-gate s_mp->sbm_peer = c_mp;
20237c478bd9Sstevel@tonic-gate s_mp->sbm_flags |= SBD_MFLAG_SOURCE;
20247c478bd9Sstevel@tonic-gate s_mp->sbm_del_mlist = d_ml; /* spans to be deleted, if any */
20257c478bd9Sstevel@tonic-gate s_mp->sbm_mlist = s_ml;
20267c478bd9Sstevel@tonic-gate s_mp->sbm_cm.sbdev_busy = 1;
20277c478bd9Sstevel@tonic-gate
20287c478bd9Sstevel@tonic-gate c_mp->sbm_peer = s_mp;
20297c478bd9Sstevel@tonic-gate c_mp->sbm_flags |= SBD_MFLAG_TARGET;
20307c478bd9Sstevel@tonic-gate c_mp->sbm_del_mlist = t_ml; /* spans to be deleted */
20317c478bd9Sstevel@tonic-gate c_mp->sbm_mlist = t_ml;
20327c478bd9Sstevel@tonic-gate c_mp->sbm_cm.sbdev_busy = 1;
20337c478bd9Sstevel@tonic-gate
20347c478bd9Sstevel@tonic-gate s_mp->sbm_flags &= ~SBD_MFLAG_MEMRESIZE;
20357c478bd9Sstevel@tonic-gate if (c_mp->sbm_npages > s_mp->sbm_npages) {
20367c478bd9Sstevel@tonic-gate s_mp->sbm_flags |= SBD_MFLAG_MEMUPSIZE;
20377c478bd9Sstevel@tonic-gate PR_MEM("%s: upsize (source pgs 0x%lx < target pgs 0x%lx)\n",
20387c478bd9Sstevel@tonic-gate f, s_mp->sbm_npages, c_mp->sbm_npages);
20397c478bd9Sstevel@tonic-gate } else if (c_mp->sbm_npages < s_mp->sbm_npages) {
20407c478bd9Sstevel@tonic-gate s_mp->sbm_flags |= SBD_MFLAG_MEMDOWNSIZE;
20417c478bd9Sstevel@tonic-gate PR_MEM("%s: downsize (source pgs 0x%lx > target pgs 0x%lx)\n",
20427c478bd9Sstevel@tonic-gate f, s_mp->sbm_npages, c_mp->sbm_npages);
20437c478bd9Sstevel@tonic-gate }
20447c478bd9Sstevel@tonic-gate
20457c478bd9Sstevel@tonic-gate return (0);
20467c478bd9Sstevel@tonic-gate }
20477c478bd9Sstevel@tonic-gate
20487c478bd9Sstevel@tonic-gate int
sbd_move_memory(sbd_handle_t * hp,sbd_board_t * s_bp,sbd_board_t * t_bp)20497c478bd9Sstevel@tonic-gate sbd_move_memory(sbd_handle_t *hp, sbd_board_t *s_bp, sbd_board_t *t_bp)
20507c478bd9Sstevel@tonic-gate {
20517c478bd9Sstevel@tonic-gate int ret;
20527c478bd9Sstevel@tonic-gate sbdp_handle_t *hdp;
20537c478bd9Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp);
20547c478bd9Sstevel@tonic-gate
20557c478bd9Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(s_bp, hp);
20567c478bd9Sstevel@tonic-gate
20577c478bd9Sstevel@tonic-gate ret = sbdp_move_memory(hdp, t_bp->sb_num);
20587c478bd9Sstevel@tonic-gate if (ret != 0)
20597c478bd9Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep);
20607c478bd9Sstevel@tonic-gate
20617c478bd9Sstevel@tonic-gate sbd_release_sbdp_handle(hdp);
20627c478bd9Sstevel@tonic-gate
20637c478bd9Sstevel@tonic-gate return (ret);
20647c478bd9Sstevel@tonic-gate }
20657c478bd9Sstevel@tonic-gate
20667c478bd9Sstevel@tonic-gate /*
20677c478bd9Sstevel@tonic-gate * Memlist support.
20687c478bd9Sstevel@tonic-gate */
20697c478bd9Sstevel@tonic-gate void
memlist_delete(struct memlist * mlist)20707c478bd9Sstevel@tonic-gate memlist_delete(struct memlist *mlist)
20717c478bd9Sstevel@tonic-gate {
20727c478bd9Sstevel@tonic-gate sbdp_handle_t *hdp;
20737c478bd9Sstevel@tonic-gate
20747c478bd9Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(NULL, NULL);
20757c478bd9Sstevel@tonic-gate
20767c478bd9Sstevel@tonic-gate (void) sbdp_del_memlist(hdp, mlist);
20777c478bd9Sstevel@tonic-gate
20787c478bd9Sstevel@tonic-gate sbd_release_sbdp_handle(hdp);
20797c478bd9Sstevel@tonic-gate }
20807c478bd9Sstevel@tonic-gate
20817c478bd9Sstevel@tonic-gate struct memlist *
memlist_dup(struct memlist * mlist)20827c478bd9Sstevel@tonic-gate memlist_dup(struct memlist *mlist)
20837c478bd9Sstevel@tonic-gate {
20847c478bd9Sstevel@tonic-gate struct memlist *hl, *prev;
20857c478bd9Sstevel@tonic-gate
20867c478bd9Sstevel@tonic-gate if (mlist == NULL)
20877c478bd9Sstevel@tonic-gate return (NULL);
20887c478bd9Sstevel@tonic-gate
20897c478bd9Sstevel@tonic-gate prev = NULL;
20907c478bd9Sstevel@tonic-gate hl = NULL;
2091*56f33205SJonathan Adams for (; mlist; mlist = mlist->ml_next) {
20927c478bd9Sstevel@tonic-gate struct memlist *mp;
20937c478bd9Sstevel@tonic-gate
20947c478bd9Sstevel@tonic-gate mp = memlist_get_one();
20957c478bd9Sstevel@tonic-gate if (mp == NULL) {
20967c478bd9Sstevel@tonic-gate if (hl != NULL)
20977c478bd9Sstevel@tonic-gate memlist_free_list(hl);
20987c478bd9Sstevel@tonic-gate hl = NULL;
20997c478bd9Sstevel@tonic-gate break;
21007c478bd9Sstevel@tonic-gate }
2101*56f33205SJonathan Adams mp->ml_address = mlist->ml_address;
2102*56f33205SJonathan Adams mp->ml_size = mlist->ml_size;
2103*56f33205SJonathan Adams mp->ml_next = NULL;
2104*56f33205SJonathan Adams mp->ml_prev = prev;
21057c478bd9Sstevel@tonic-gate
21067c478bd9Sstevel@tonic-gate if (prev == NULL)
21077c478bd9Sstevel@tonic-gate hl = mp;
21087c478bd9Sstevel@tonic-gate else
2109*56f33205SJonathan Adams prev->ml_next = mp;
21107c478bd9Sstevel@tonic-gate prev = mp;
21117c478bd9Sstevel@tonic-gate }
21127c478bd9Sstevel@tonic-gate
21137c478bd9Sstevel@tonic-gate return (hl);
21147c478bd9Sstevel@tonic-gate }
21157c478bd9Sstevel@tonic-gate
21167c478bd9Sstevel@tonic-gate void
memlist_dump(struct memlist * mlist)21177c478bd9Sstevel@tonic-gate memlist_dump(struct memlist *mlist)
21187c478bd9Sstevel@tonic-gate {
21197c478bd9Sstevel@tonic-gate register struct memlist *ml;
21207c478bd9Sstevel@tonic-gate
21217c478bd9Sstevel@tonic-gate if (mlist == NULL) {
21227c478bd9Sstevel@tonic-gate PR_MEM("memlist> EMPTY\n");
21237c478bd9Sstevel@tonic-gate } else {
2124*56f33205SJonathan Adams for (ml = mlist; ml; ml = ml->ml_next)
21257c478bd9Sstevel@tonic-gate PR_MEM("memlist> 0x%" PRIx64 " "
21267c478bd9Sstevel@tonic-gate "0x%" PRIx64 " \n",
2127*56f33205SJonathan Adams ml->ml_address, ml->ml_size);
21287c478bd9Sstevel@tonic-gate }
21297c478bd9Sstevel@tonic-gate }
21307c478bd9Sstevel@tonic-gate
21317c478bd9Sstevel@tonic-gate int
memlist_intersect(struct memlist * al,struct memlist * bl)21327c478bd9Sstevel@tonic-gate memlist_intersect(struct memlist *al, struct memlist *bl)
21337c478bd9Sstevel@tonic-gate {
21347c478bd9Sstevel@tonic-gate uint64_t astart, aend, bstart, bend;
21357c478bd9Sstevel@tonic-gate
21367c478bd9Sstevel@tonic-gate if ((al == NULL) || (bl == NULL))
21377c478bd9Sstevel@tonic-gate return (0);
21387c478bd9Sstevel@tonic-gate
2139*56f33205SJonathan Adams aend = al->ml_address + al->ml_size;
2140*56f33205SJonathan Adams bstart = bl->ml_address;
2141*56f33205SJonathan Adams bend = bl->ml_address + bl->ml_size;
21427c478bd9Sstevel@tonic-gate
21437c478bd9Sstevel@tonic-gate while (al && bl) {
21447c478bd9Sstevel@tonic-gate while (al && (aend <= bstart))
2145*56f33205SJonathan Adams if ((al = al->ml_next) != NULL)
2146*56f33205SJonathan Adams aend = al->ml_address + al->ml_size;
21477c478bd9Sstevel@tonic-gate if (al == NULL)
21487c478bd9Sstevel@tonic-gate return (0);
21497c478bd9Sstevel@tonic-gate
2150*56f33205SJonathan Adams if ((astart = al->ml_address) <= bstart)
21517c478bd9Sstevel@tonic-gate return (1);
21527c478bd9Sstevel@tonic-gate
21537c478bd9Sstevel@tonic-gate while (bl && (bend <= astart))
2154*56f33205SJonathan Adams if ((bl = bl->ml_next) != NULL)
2155*56f33205SJonathan Adams bend = bl->ml_address + bl->ml_size;
21567c478bd9Sstevel@tonic-gate if (bl == NULL)
21577c478bd9Sstevel@tonic-gate return (0);
21587c478bd9Sstevel@tonic-gate
2159*56f33205SJonathan Adams if ((bstart = bl->ml_address) <= astart)
21607c478bd9Sstevel@tonic-gate return (1);
21617c478bd9Sstevel@tonic-gate }
21627c478bd9Sstevel@tonic-gate
21637c478bd9Sstevel@tonic-gate return (0);
21647c478bd9Sstevel@tonic-gate }
21657c478bd9Sstevel@tonic-gate
21667c478bd9Sstevel@tonic-gate /*
21677c478bd9Sstevel@tonic-gate * Determine whether the source memlist (s_mlist) will
21687c478bd9Sstevel@tonic-gate * fit into the target memlist (t_mlist) in terms of
21697c478bd9Sstevel@tonic-gate * size and holes (i.e. based on same relative base address).
21707c478bd9Sstevel@tonic-gate */
21717c478bd9Sstevel@tonic-gate static int
memlist_canfit(struct memlist * s_mlist,struct memlist * t_mlist)21727c478bd9Sstevel@tonic-gate memlist_canfit(struct memlist *s_mlist, struct memlist *t_mlist)
21737c478bd9Sstevel@tonic-gate {
21747c478bd9Sstevel@tonic-gate int rv = 0;
21757c478bd9Sstevel@tonic-gate uint64_t s_basepa, t_basepa;
21767c478bd9Sstevel@tonic-gate struct memlist *s_ml, *t_ml;
21777c478bd9Sstevel@tonic-gate
21787c478bd9Sstevel@tonic-gate if ((s_mlist == NULL) || (t_mlist == NULL))
21797c478bd9Sstevel@tonic-gate return (0);
21807c478bd9Sstevel@tonic-gate
21817c478bd9Sstevel@tonic-gate /*
21827c478bd9Sstevel@tonic-gate * Base both memlists on common base address (0).
21837c478bd9Sstevel@tonic-gate */
2184*56f33205SJonathan Adams s_basepa = s_mlist->ml_address;
2185*56f33205SJonathan Adams t_basepa = t_mlist->ml_address;
21867c478bd9Sstevel@tonic-gate
2187*56f33205SJonathan Adams for (s_ml = s_mlist; s_ml; s_ml = s_ml->ml_next)
2188*56f33205SJonathan Adams s_ml->ml_address -= s_basepa;
21897c478bd9Sstevel@tonic-gate
2190*56f33205SJonathan Adams for (t_ml = t_mlist; t_ml; t_ml = t_ml->ml_next)
2191*56f33205SJonathan Adams t_ml->ml_address -= t_basepa;
21927c478bd9Sstevel@tonic-gate
21937c478bd9Sstevel@tonic-gate s_ml = s_mlist;
2194*56f33205SJonathan Adams for (t_ml = t_mlist; t_ml && s_ml; t_ml = t_ml->ml_next) {
21957c478bd9Sstevel@tonic-gate uint64_t s_start, s_end;
21967c478bd9Sstevel@tonic-gate uint64_t t_start, t_end;
21977c478bd9Sstevel@tonic-gate
2198*56f33205SJonathan Adams t_start = t_ml->ml_address;
2199*56f33205SJonathan Adams t_end = t_start + t_ml->ml_size;
22007c478bd9Sstevel@tonic-gate
2201*56f33205SJonathan Adams for (; s_ml; s_ml = s_ml->ml_next) {
2202*56f33205SJonathan Adams s_start = s_ml->ml_address;
2203*56f33205SJonathan Adams s_end = s_start + s_ml->ml_size;
22047c478bd9Sstevel@tonic-gate
22057c478bd9Sstevel@tonic-gate if ((s_start < t_start) || (s_end > t_end))
22067c478bd9Sstevel@tonic-gate break;
22077c478bd9Sstevel@tonic-gate }
22087c478bd9Sstevel@tonic-gate }
22097c478bd9Sstevel@tonic-gate /*
22107c478bd9Sstevel@tonic-gate * If we ran out of source memlist chunks that mean
22117c478bd9Sstevel@tonic-gate * we found a home for all of them.
22127c478bd9Sstevel@tonic-gate */
22137c478bd9Sstevel@tonic-gate if (s_ml == NULL)
22147c478bd9Sstevel@tonic-gate rv = 1;
22157c478bd9Sstevel@tonic-gate
22167c478bd9Sstevel@tonic-gate /*
22177c478bd9Sstevel@tonic-gate * Need to add base addresses back since memlists
22187c478bd9Sstevel@tonic-gate * are probably in use by caller.
22197c478bd9Sstevel@tonic-gate */
2220*56f33205SJonathan Adams for (s_ml = s_mlist; s_ml; s_ml = s_ml->ml_next)
2221*56f33205SJonathan Adams s_ml->ml_address += s_basepa;
22227c478bd9Sstevel@tonic-gate
2223*56f33205SJonathan Adams for (t_ml = t_mlist; t_ml; t_ml = t_ml->ml_next)
2224*56f33205SJonathan Adams t_ml->ml_address += t_basepa;
22257c478bd9Sstevel@tonic-gate
22267c478bd9Sstevel@tonic-gate return (rv);
22277c478bd9Sstevel@tonic-gate }
22287c478bd9Sstevel@tonic-gate
22297c478bd9Sstevel@tonic-gate void
sbd_attach_mem(sbd_handle_t * hp,sbderror_t * ep)22307c478bd9Sstevel@tonic-gate sbd_attach_mem(sbd_handle_t *hp, sbderror_t *ep)
22317c478bd9Sstevel@tonic-gate {
22327c478bd9Sstevel@tonic-gate sbd_mem_unit_t *mp;
22337c478bd9Sstevel@tonic-gate dev_info_t *dip;
22347c478bd9Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd);
22357c478bd9Sstevel@tonic-gate sbdp_handle_t *hdp;
22367c478bd9Sstevel@tonic-gate int err, unit;
22377c478bd9Sstevel@tonic-gate struct memlist *ml, *mc;
22387c478bd9Sstevel@tonic-gate static fn_t f = "sbd_attach_mem";
22397c478bd9Sstevel@tonic-gate int i;
22407c478bd9Sstevel@tonic-gate
22417c478bd9Sstevel@tonic-gate PR_MEM("%s...\n", f);
22427c478bd9Sstevel@tonic-gate
22437c478bd9Sstevel@tonic-gate /*
22447c478bd9Sstevel@tonic-gate * all four cpus have to be attached before
22457c478bd9Sstevel@tonic-gate * configuring mem
22467c478bd9Sstevel@tonic-gate */
22477c478bd9Sstevel@tonic-gate for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
22487c478bd9Sstevel@tonic-gate sbd_cpu_unit_t *cpup;
22497c478bd9Sstevel@tonic-gate struct cpu *cp;
22507c478bd9Sstevel@tonic-gate
22517c478bd9Sstevel@tonic-gate if (!SBD_DEV_IS_PRESENT(sbp, SBD_COMP_CPU, i))
22527c478bd9Sstevel@tonic-gate continue;
22537c478bd9Sstevel@tonic-gate
22547c478bd9Sstevel@tonic-gate if (!SBD_DEV_IS_ATTACHED(sbp, SBD_COMP_CPU, i))
22557c478bd9Sstevel@tonic-gate goto error;
22567c478bd9Sstevel@tonic-gate
22577c478bd9Sstevel@tonic-gate cpup = SBD_GET_BOARD_CPUUNIT(sbp, i);
22587c478bd9Sstevel@tonic-gate
22597c478bd9Sstevel@tonic-gate if (cpup == NULL)
22607c478bd9Sstevel@tonic-gate goto error;
22617c478bd9Sstevel@tonic-gate
22627c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock);
22637c478bd9Sstevel@tonic-gate cp = cpu_get(cpup->sbc_cpu_id);
22647c478bd9Sstevel@tonic-gate if (cp == NULL) {
22657c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock);
22667c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
22677c478bd9Sstevel@tonic-gate "sbd:%s: cpu_get failed for cpu %d",
22687c478bd9Sstevel@tonic-gate f, cpup->sbc_cpu_id);
22697c478bd9Sstevel@tonic-gate goto error;
22707c478bd9Sstevel@tonic-gate }
22717c478bd9Sstevel@tonic-gate if (cpu_is_poweredoff(cp)) {
22727c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock);
22737c478bd9Sstevel@tonic-gate goto error;
22747c478bd9Sstevel@tonic-gate }
22757c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock);
22767c478bd9Sstevel@tonic-gate continue;
22777c478bd9Sstevel@tonic-gate
22787c478bd9Sstevel@tonic-gate error:
22797c478bd9Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_CPUONLINE);
22807c478bd9Sstevel@tonic-gate SBD_SET_ERRSTR(ep, sbp->sb_mempath[i]);
22817c478bd9Sstevel@tonic-gate (void) sbd_set_err_in_hdl(hp, ep);
22827c478bd9Sstevel@tonic-gate return;
22837c478bd9Sstevel@tonic-gate }
22847c478bd9Sstevel@tonic-gate
22857c478bd9Sstevel@tonic-gate dip = *(sbp->sb_devlist[NIX(SBD_COMP_MEM)]);
22867c478bd9Sstevel@tonic-gate
22877c478bd9Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp);
22887c478bd9Sstevel@tonic-gate unit = sbdp_get_unit_num(hdp, dip);
22897c478bd9Sstevel@tonic-gate if (unit < 0) {
22907c478bd9Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep);
22917c478bd9Sstevel@tonic-gate sbd_release_sbdp_handle(hdp);
22927c478bd9Sstevel@tonic-gate return;
22937c478bd9Sstevel@tonic-gate }
22947c478bd9Sstevel@tonic-gate
22957c478bd9Sstevel@tonic-gate ASSERT(sbp->sb_mempath[unit] != NULL);
22967c478bd9Sstevel@tonic-gate ASSERT(e_ddi_branch_held(dip));
22977c478bd9Sstevel@tonic-gate
22987c478bd9Sstevel@tonic-gate (void) ddi_pathname(dip, sbp->sb_mempath[unit]);
22997c478bd9Sstevel@tonic-gate
23007c478bd9Sstevel@tonic-gate mp = SBD_GET_BOARD_MEMUNIT(sbp, unit);
23017c478bd9Sstevel@tonic-gate
23027c478bd9Sstevel@tonic-gate ml = sbd_get_memlist(mp, ep);
23037c478bd9Sstevel@tonic-gate if (ml == NULL) {
23047c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
23057c478bd9Sstevel@tonic-gate "sbd:%s: failed to get memlist for "
23067c478bd9Sstevel@tonic-gate "board %d", f, sbp->sb_num);
23077c478bd9Sstevel@tonic-gate /*
23087c478bd9Sstevel@tonic-gate * Need to record an error and return.
23097c478bd9Sstevel@tonic-gate */
23107c478bd9Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_MEMFAIL);
23117c478bd9Sstevel@tonic-gate SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]);
23127c478bd9Sstevel@tonic-gate sbd_release_sbdp_handle(hdp);
23137c478bd9Sstevel@tonic-gate return;
23147c478bd9Sstevel@tonic-gate }
23157c478bd9Sstevel@tonic-gate
23167c478bd9Sstevel@tonic-gate SBD_MEMLIST_DUMP(ml);
23177c478bd9Sstevel@tonic-gate err = 0;
2318*56f33205SJonathan Adams for (mc = ml; mc; mc = mc->ml_next) {
23197c478bd9Sstevel@tonic-gate update_membounds_t umb;
23207c478bd9Sstevel@tonic-gate pfn_t base;
23217c478bd9Sstevel@tonic-gate pgcnt_t npgs;
23227c478bd9Sstevel@tonic-gate
2323*56f33205SJonathan Adams base = (pfn_t)(mc->ml_address >> PAGESHIFT);
2324*56f33205SJonathan Adams npgs = (pgcnt_t)(mc->ml_size >> PAGESHIFT);
23257c478bd9Sstevel@tonic-gate
23267c478bd9Sstevel@tonic-gate umb.u_board = sbp->sb_num;
23277c478bd9Sstevel@tonic-gate umb.u_base = (uint64_t)base << MMU_PAGESHIFT;
23287c478bd9Sstevel@tonic-gate umb.u_len = (uint64_t)npgs << MMU_PAGESHIFT;
23297c478bd9Sstevel@tonic-gate
23307c478bd9Sstevel@tonic-gate lgrp_plat_config(LGRP_CONFIG_MEM_ADD, (uintptr_t)&umb);
23317c478bd9Sstevel@tonic-gate err = kphysm_add_memory_dynamic(base, npgs);
23327c478bd9Sstevel@tonic-gate
23337c478bd9Sstevel@tonic-gate if (err != KPHYSM_OK) {
23347c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
23357c478bd9Sstevel@tonic-gate "%s: kphysm_add_memory_dynamic fail %d", f, err);
23367c478bd9Sstevel@tonic-gate
23377c478bd9Sstevel@tonic-gate /* translate kphysm error */
23387c478bd9Sstevel@tonic-gate switch (err) {
23397c478bd9Sstevel@tonic-gate case KPHYSM_ERESOURCE:
23407c478bd9Sstevel@tonic-gate err = ESBD_NOMEM;
23417c478bd9Sstevel@tonic-gate break;
23427c478bd9Sstevel@tonic-gate
23437c478bd9Sstevel@tonic-gate case KPHYSM_EFAULT:
23447c478bd9Sstevel@tonic-gate err = ESBD_FAULT;
23457c478bd9Sstevel@tonic-gate break;
23467c478bd9Sstevel@tonic-gate
23477c478bd9Sstevel@tonic-gate default:
23487c478bd9Sstevel@tonic-gate err = ESBD_INVAL;
23497c478bd9Sstevel@tonic-gate break;
23507c478bd9Sstevel@tonic-gate }
23517c478bd9Sstevel@tonic-gate break;
23527c478bd9Sstevel@tonic-gate }
23537c478bd9Sstevel@tonic-gate
235485f58038Sdp78419 err = kcage_range_add(base, npgs, KCAGE_DOWN);
23557c478bd9Sstevel@tonic-gate if (err != 0) {
23567c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
23577c478bd9Sstevel@tonic-gate "%s: kcage_range_add fail %d", f, err);
23587c478bd9Sstevel@tonic-gate
23597c478bd9Sstevel@tonic-gate /* Translate kcage error. */
23607c478bd9Sstevel@tonic-gate switch (err) {
23617c478bd9Sstevel@tonic-gate case ENOMEM:
23627c478bd9Sstevel@tonic-gate err = ESBD_NOMEM;
23637c478bd9Sstevel@tonic-gate break;
23647c478bd9Sstevel@tonic-gate default:
23657c478bd9Sstevel@tonic-gate err = ESBD_INVAL;
23667c478bd9Sstevel@tonic-gate break;
23677c478bd9Sstevel@tonic-gate }
23687c478bd9Sstevel@tonic-gate break;
23697c478bd9Sstevel@tonic-gate }
2370*56f33205SJonathan Adams (void) sbdp_mem_add_span(hdp, mc->ml_address, mc->ml_size);
23717c478bd9Sstevel@tonic-gate }
23727c478bd9Sstevel@tonic-gate
23737c478bd9Sstevel@tonic-gate if (err != 0) {
23747c478bd9Sstevel@tonic-gate SBD_SET_ERR(ep, err);
23757c478bd9Sstevel@tonic-gate SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]);
23767c478bd9Sstevel@tonic-gate }
23777c478bd9Sstevel@tonic-gate
23787c478bd9Sstevel@tonic-gate memlist_delete(ml);
23797c478bd9Sstevel@tonic-gate sbd_release_sbdp_handle(hdp);
23807c478bd9Sstevel@tonic-gate
23817c478bd9Sstevel@tonic-gate /*
23827c478bd9Sstevel@tonic-gate * Now attach all mem devinfo nodes to the device tree.
23837c478bd9Sstevel@tonic-gate */
23847c478bd9Sstevel@tonic-gate for (i = 0; i < SBD_NUM_MC_PER_BOARD; i++) {
23857c478bd9Sstevel@tonic-gate if (mp->sbm_dip[i] == NULL)
23867c478bd9Sstevel@tonic-gate continue;
23877c478bd9Sstevel@tonic-gate ASSERT(e_ddi_branch_held(mp->sbm_dip[i]));
23887c478bd9Sstevel@tonic-gate if (e_ddi_branch_configure(mp->sbm_dip[i], NULL, 0) &&
23897c478bd9Sstevel@tonic-gate SBD_GET_ERR(ep) == 0) {
23907c478bd9Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_INVAL);
23917c478bd9Sstevel@tonic-gate SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]);
23927c478bd9Sstevel@tonic-gate }
23937c478bd9Sstevel@tonic-gate }
23947c478bd9Sstevel@tonic-gate }
23957c478bd9Sstevel@tonic-gate
23967c478bd9Sstevel@tonic-gate typedef struct {
23977c478bd9Sstevel@tonic-gate kcondvar_t cond;
23987c478bd9Sstevel@tonic-gate kmutex_t lock;
23997c478bd9Sstevel@tonic-gate int error;
24007c478bd9Sstevel@tonic-gate int done;
24017c478bd9Sstevel@tonic-gate } sbd_release_mem_sync_t;
24027c478bd9Sstevel@tonic-gate
24037c478bd9Sstevel@tonic-gate /*
24047c478bd9Sstevel@tonic-gate * When we reach here the memory being drained should have
24057c478bd9Sstevel@tonic-gate * already been reserved in sbd_pre_release_mem().
24067c478bd9Sstevel@tonic-gate * Our only task here is to kick off the "drain".
24077c478bd9Sstevel@tonic-gate * Returns -1 when error encountered or zero for success.
24087c478bd9Sstevel@tonic-gate */
24097c478bd9Sstevel@tonic-gate int
sbd_release_mem(sbd_handle_t * hp,dev_info_t * dip,int unit)24107c478bd9Sstevel@tonic-gate sbd_release_mem(sbd_handle_t *hp, dev_info_t *dip, int unit)
24117c478bd9Sstevel@tonic-gate {
24127c478bd9Sstevel@tonic-gate memhandle_t mh;
24137c478bd9Sstevel@tonic-gate int err;
24147c478bd9Sstevel@tonic-gate int cancel_flag = 0;
24157c478bd9Sstevel@tonic-gate int e_code = 0;
24167c478bd9Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd);
24177c478bd9Sstevel@tonic-gate sbd_release_mem_sync_t rms;
24187c478bd9Sstevel@tonic-gate static fn_t f = "sbd_release_mem";
24197c478bd9Sstevel@tonic-gate
24207c478bd9Sstevel@tonic-gate /*
24217c478bd9Sstevel@tonic-gate * If this node has a scheduled memory delete operation,
24227c478bd9Sstevel@tonic-gate * it will have a memhandle. If it does have a memhandle (the
24237c478bd9Sstevel@tonic-gate * return value of sbd_get_memhandle is zero when true),
24247c478bd9Sstevel@tonic-gate * then perform the delete.
24257c478bd9Sstevel@tonic-gate */
24267c478bd9Sstevel@tonic-gate
24277c478bd9Sstevel@tonic-gate if ((cancel_flag = sbd_get_memhandle(hp, dip, &mh)) != 0) {
24287c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s: couldn't get the memhandle\n", f);
24297c478bd9Sstevel@tonic-gate return (cancel_flag);
24307c478bd9Sstevel@tonic-gate }
24317c478bd9Sstevel@tonic-gate
24327c478bd9Sstevel@tonic-gate bzero((void *) &rms, sizeof (rms));
24337c478bd9Sstevel@tonic-gate
24347c478bd9Sstevel@tonic-gate mutex_init(&rms.lock, NULL, MUTEX_DRIVER, NULL);
24357c478bd9Sstevel@tonic-gate cv_init(&rms.cond, NULL, CV_DRIVER, NULL);
24367c478bd9Sstevel@tonic-gate
24377c478bd9Sstevel@tonic-gate mutex_enter(&rms.lock);
24387c478bd9Sstevel@tonic-gate err = kphysm_del_start(mh, sbd_release_memory_done, (void *) &rms);
24397c478bd9Sstevel@tonic-gate if (err == KPHYSM_OK) {
24407c478bd9Sstevel@tonic-gate /* wait for completion */
24417c478bd9Sstevel@tonic-gate while (!rms.done) {
24427c478bd9Sstevel@tonic-gate if (cancel_flag) {
24437c478bd9Sstevel@tonic-gate /* previously canceled */
24447c478bd9Sstevel@tonic-gate cv_wait(&rms.cond, &rms.lock);
24457c478bd9Sstevel@tonic-gate } else if (cv_wait_sig(&rms.cond, &rms.lock) == 0) {
24467c478bd9Sstevel@tonic-gate /* interrupted: cancel and wait */
24477c478bd9Sstevel@tonic-gate cancel_flag = -1;
24487c478bd9Sstevel@tonic-gate (void) kphysm_del_cancel(mh);
24497c478bd9Sstevel@tonic-gate }
24507c478bd9Sstevel@tonic-gate }
24517c478bd9Sstevel@tonic-gate /* get the result of the memory delete operation */
24527c478bd9Sstevel@tonic-gate err = rms.error;
24537c478bd9Sstevel@tonic-gate } else {
24547c478bd9Sstevel@tonic-gate (void) kphysm_del_release(mh);
24557c478bd9Sstevel@tonic-gate }
24567c478bd9Sstevel@tonic-gate
24577c478bd9Sstevel@tonic-gate mutex_exit(&rms.lock);
24587c478bd9Sstevel@tonic-gate
24597c478bd9Sstevel@tonic-gate cv_destroy(&rms.cond);
24607c478bd9Sstevel@tonic-gate mutex_destroy(&rms.lock);
24617c478bd9Sstevel@tonic-gate
24627c478bd9Sstevel@tonic-gate if (err != KPHYSM_OK) {
24637c478bd9Sstevel@tonic-gate switch (err) {
24647c478bd9Sstevel@tonic-gate case KPHYSM_ENOWORK:
24657c478bd9Sstevel@tonic-gate e_code = ESBD_NOERROR;
24667c478bd9Sstevel@tonic-gate break;
24677c478bd9Sstevel@tonic-gate
24687c478bd9Sstevel@tonic-gate case KPHYSM_EHANDLE:
24697c478bd9Sstevel@tonic-gate case KPHYSM_ESEQUENCE:
24707c478bd9Sstevel@tonic-gate e_code = ESBD_INTERNAL;
24717c478bd9Sstevel@tonic-gate break;
24727c478bd9Sstevel@tonic-gate
24737c478bd9Sstevel@tonic-gate case KPHYSM_ENOTVIABLE:
24747c478bd9Sstevel@tonic-gate e_code = ESBD_MEM_NOTVIABLE;
24757c478bd9Sstevel@tonic-gate break;
24767c478bd9Sstevel@tonic-gate
24777c478bd9Sstevel@tonic-gate case KPHYSM_EREFUSED:
24787c478bd9Sstevel@tonic-gate e_code = ESBD_MEM_REFUSED;
24797c478bd9Sstevel@tonic-gate break;
24807c478bd9Sstevel@tonic-gate
24817c478bd9Sstevel@tonic-gate case KPHYSM_ENONRELOC:
24827c478bd9Sstevel@tonic-gate e_code = ESBD_MEM_NONRELOC;
24837c478bd9Sstevel@tonic-gate break;
24847c478bd9Sstevel@tonic-gate
24857c478bd9Sstevel@tonic-gate case KPHYSM_ECANCELLED:
24867c478bd9Sstevel@tonic-gate e_code = ESBD_MEM_CANCELLED;
24877c478bd9Sstevel@tonic-gate break;
24887c478bd9Sstevel@tonic-gate
24897c478bd9Sstevel@tonic-gate case KPHYSM_ERESOURCE:
24907c478bd9Sstevel@tonic-gate e_code = ESBD_MEMFAIL;
24917c478bd9Sstevel@tonic-gate break;
24927c478bd9Sstevel@tonic-gate
24937c478bd9Sstevel@tonic-gate default:
24947c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "sbd:%s:"
24957c478bd9Sstevel@tonic-gate " unexpected kphysm error code %d,"
24967c478bd9Sstevel@tonic-gate " dip 0x%p",
24977c478bd9Sstevel@tonic-gate f, err, (void *)dip);
24987c478bd9Sstevel@tonic-gate
24997c478bd9Sstevel@tonic-gate e_code = ESBD_IO;
25007c478bd9Sstevel@tonic-gate break;
25017c478bd9Sstevel@tonic-gate }
25027c478bd9Sstevel@tonic-gate
25037c478bd9Sstevel@tonic-gate if (e_code != 0) {
25047c478bd9Sstevel@tonic-gate cancel_flag = -1;
25057c478bd9Sstevel@tonic-gate SBD_SET_ERR(SBD_HD2ERR(hp), e_code);
25067c478bd9Sstevel@tonic-gate SBD_SET_ERRSTR(SBD_HD2ERR(hp), sbp->sb_mempath[unit]);
25077c478bd9Sstevel@tonic-gate }
25087c478bd9Sstevel@tonic-gate }
25097c478bd9Sstevel@tonic-gate
25107c478bd9Sstevel@tonic-gate return (cancel_flag);
25117c478bd9Sstevel@tonic-gate }
25127c478bd9Sstevel@tonic-gate
25137c478bd9Sstevel@tonic-gate /*
25147c478bd9Sstevel@tonic-gate * Memory has been logically removed by the time this routine is called.
25157c478bd9Sstevel@tonic-gate */
25167c478bd9Sstevel@tonic-gate void
sbd_release_memory_done(void * arg,int error)25177c478bd9Sstevel@tonic-gate sbd_release_memory_done(void *arg, int error)
25187c478bd9Sstevel@tonic-gate {
25197c478bd9Sstevel@tonic-gate sbd_release_mem_sync_t *ds = arg;
25207c478bd9Sstevel@tonic-gate
25217c478bd9Sstevel@tonic-gate mutex_enter(&ds->lock);
25227c478bd9Sstevel@tonic-gate ds->error = error;
25237c478bd9Sstevel@tonic-gate ds->done = 1;
25247c478bd9Sstevel@tonic-gate cv_signal(&ds->cond);
25257c478bd9Sstevel@tonic-gate mutex_exit(&ds->lock);
25267c478bd9Sstevel@tonic-gate }
25277c478bd9Sstevel@tonic-gate
25287c478bd9Sstevel@tonic-gate /*
25297c478bd9Sstevel@tonic-gate * If detaching node contains memory that is "non-permanent"
25307c478bd9Sstevel@tonic-gate * then the memory adr's are simply cleared. If the memory
25317c478bd9Sstevel@tonic-gate * is non-relocatable, then do a copy-rename.
25327c478bd9Sstevel@tonic-gate */
25337c478bd9Sstevel@tonic-gate int
sbd_detach_memory(sbd_handle_t * hp,sbderror_t * ep,sbd_mem_unit_t * s_mp,int unit)25347c478bd9Sstevel@tonic-gate sbd_detach_memory(sbd_handle_t *hp, sbderror_t *ep, sbd_mem_unit_t *s_mp,
25357c478bd9Sstevel@tonic-gate int unit)
25367c478bd9Sstevel@tonic-gate {
25377c478bd9Sstevel@tonic-gate int rv;
25387c478bd9Sstevel@tonic-gate sbd_mem_unit_t *t_mp;
25397c478bd9Sstevel@tonic-gate sbd_istate_t state;
25407c478bd9Sstevel@tonic-gate sbdp_handle_t *hdp;
25417c478bd9Sstevel@tonic-gate sbd_board_t *sbp = (sbd_board_t *)s_mp->sbm_cm.sbdev_sbp;
25427c478bd9Sstevel@tonic-gate sbd_board_t *tbp;
25437c478bd9Sstevel@tonic-gate static fn_t f = "sbd_detach_memory";
25447c478bd9Sstevel@tonic-gate
25457c478bd9Sstevel@tonic-gate PR_MEM("%s...\n", f);
25467c478bd9Sstevel@tonic-gate
25477c478bd9Sstevel@tonic-gate /* lookup target mem unit and target board structure, if any */
25487c478bd9Sstevel@tonic-gate if (s_mp->sbm_flags & SBD_MFLAG_SOURCE) {
25497c478bd9Sstevel@tonic-gate t_mp = s_mp->sbm_peer;
25507c478bd9Sstevel@tonic-gate ASSERT(t_mp != NULL);
25517c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_peer == s_mp);
25527c478bd9Sstevel@tonic-gate tbp = (sbd_board_t *)t_mp->sbm_cm.sbdev_sbp;
25537c478bd9Sstevel@tonic-gate } else {
25547c478bd9Sstevel@tonic-gate t_mp = NULL;
25557c478bd9Sstevel@tonic-gate }
25567c478bd9Sstevel@tonic-gate
25577c478bd9Sstevel@tonic-gate /* verify mem unit's state is UNREFERENCED */
25587c478bd9Sstevel@tonic-gate state = s_mp->sbm_cm.sbdev_state;
25597c478bd9Sstevel@tonic-gate if (state != SBD_STATE_UNREFERENCED) {
25607c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s: invalid state transition for"
25617c478bd9Sstevel@tonic-gate " mem-unit (%d.%d)",
25627c478bd9Sstevel@tonic-gate f,
25637c478bd9Sstevel@tonic-gate sbp->sb_num,
25647c478bd9Sstevel@tonic-gate s_mp->sbm_cm.sbdev_unum);
25657c478bd9Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_STATE);
25667c478bd9Sstevel@tonic-gate SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]);
25677c478bd9Sstevel@tonic-gate return (-1);
25687c478bd9Sstevel@tonic-gate }
25697c478bd9Sstevel@tonic-gate
25707c478bd9Sstevel@tonic-gate /* verify target mem unit's state is UNREFERENCED, if any */
25717c478bd9Sstevel@tonic-gate if (t_mp != NULL) {
25727c478bd9Sstevel@tonic-gate state = t_mp->sbm_cm.sbdev_state;
25737c478bd9Sstevel@tonic-gate if (state != SBD_STATE_UNREFERENCED) {
25747c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s: invalid state transition for"
25757c478bd9Sstevel@tonic-gate " target mem-unit (%d.%d)",
25767c478bd9Sstevel@tonic-gate f,
25777c478bd9Sstevel@tonic-gate tbp->sb_num,
25787c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_unum);
25797c478bd9Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_STATE);
25807c478bd9Sstevel@tonic-gate SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]);
25817c478bd9Sstevel@tonic-gate return (-1);
25827c478bd9Sstevel@tonic-gate }
25837c478bd9Sstevel@tonic-gate }
25847c478bd9Sstevel@tonic-gate
25857c478bd9Sstevel@tonic-gate /*
25867c478bd9Sstevel@tonic-gate * Displacement flush all ecaches in the system.
25877c478bd9Sstevel@tonic-gate * That's the fastest way to remove all cache references
25887c478bd9Sstevel@tonic-gate * to the detaching memory.
25897c478bd9Sstevel@tonic-gate */
25907c478bd9Sstevel@tonic-gate xc_all(sbd_flush_ecache, 0, 0);
25917c478bd9Sstevel@tonic-gate
25927c478bd9Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp);
25937c478bd9Sstevel@tonic-gate
25947c478bd9Sstevel@tonic-gate /*
25957c478bd9Sstevel@tonic-gate * If there is no target board (no copy/rename was needed), then
25967c478bd9Sstevel@tonic-gate * we're done!
25977c478bd9Sstevel@tonic-gate */
25987c478bd9Sstevel@tonic-gate if (t_mp == NULL) {
25997c478bd9Sstevel@tonic-gate /*
26007c478bd9Sstevel@tonic-gate * Reprogram interconnect hardware and disable
26017c478bd9Sstevel@tonic-gate * memory controllers for memory node that's going away.
26027c478bd9Sstevel@tonic-gate */
26037c478bd9Sstevel@tonic-gate
26047c478bd9Sstevel@tonic-gate rv = sbdphw_disable_memctrl(hdp, s_mp->sbm_cm.sbdev_dip);
26057c478bd9Sstevel@tonic-gate if (rv) {
26067c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
26077c478bd9Sstevel@tonic-gate "%s: failed to deprogram mem-unit (%d.%d),"
26087c478bd9Sstevel@tonic-gate " dip 0x%p",
26097c478bd9Sstevel@tonic-gate f,
26107c478bd9Sstevel@tonic-gate sbp->sb_num,
26117c478bd9Sstevel@tonic-gate s_mp->sbm_cm.sbdev_unum,
26127c478bd9Sstevel@tonic-gate (void *)s_mp->sbm_cm.sbdev_dip);
26137c478bd9Sstevel@tonic-gate /*
26147c478bd9Sstevel@tonic-gate * Make sure we don't rewrite an sbdp error
26157c478bd9Sstevel@tonic-gate */
26167c478bd9Sstevel@tonic-gate if (SBD_GET_ERR(ep) != 0) {
26177c478bd9Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_HW_PROGRAM);
26187c478bd9Sstevel@tonic-gate SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]);
26197c478bd9Sstevel@tonic-gate }
26207c478bd9Sstevel@tonic-gate }
26217c478bd9Sstevel@tonic-gate } else {
26227c478bd9Sstevel@tonic-gate rv = sbd_move_memory(hp, sbp, tbp);
26237c478bd9Sstevel@tonic-gate if (rv) {
26247c478bd9Sstevel@tonic-gate int i;
26257c478bd9Sstevel@tonic-gate
26267c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s: failed to move memory"
26277c478bd9Sstevel@tonic-gate " from board %d to board %d",
26287c478bd9Sstevel@tonic-gate f,
26297c478bd9Sstevel@tonic-gate sbp->sb_num,
26307c478bd9Sstevel@tonic-gate tbp->sb_num);
26317c478bd9Sstevel@tonic-gate /*
26327c478bd9Sstevel@tonic-gate * Make sure we don't rewrite an sbdp error
26337c478bd9Sstevel@tonic-gate */
26347c478bd9Sstevel@tonic-gate if (SBD_GET_ERR(ep) != 0) {
26357c478bd9Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_INTERNAL);
26367c478bd9Sstevel@tonic-gate SBD_SET_ERRSTR(ep, sbp->sb_mempath[unit]);
26377c478bd9Sstevel@tonic-gate }
26387c478bd9Sstevel@tonic-gate /*
26397c478bd9Sstevel@tonic-gate * If we failed here, it means that the target board's
26407c478bd9Sstevel@tonic-gate * memory has been unconfigured. We need to configure
26417c478bd9Sstevel@tonic-gate * it back
26427c478bd9Sstevel@tonic-gate */
26437c478bd9Sstevel@tonic-gate for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
26447c478bd9Sstevel@tonic-gate int unit;
26457c478bd9Sstevel@tonic-gate dev_info_t *dip;
26467c478bd9Sstevel@tonic-gate dev_info_t **devlist;
26477c478bd9Sstevel@tonic-gate
26487c478bd9Sstevel@tonic-gate
26497c478bd9Sstevel@tonic-gate devlist = tbp->sb_devlist[NIX(SBD_COMP_MEM)];
26507c478bd9Sstevel@tonic-gate dip = devlist[i];
26517c478bd9Sstevel@tonic-gate sbd_reset_error_sbdph(hdp);
26527c478bd9Sstevel@tonic-gate unit = sbdp_get_unit_num(hdp, dip);
26537c478bd9Sstevel@tonic-gate
26547c478bd9Sstevel@tonic-gate /*
26557c478bd9Sstevel@tonic-gate * We already saved the error that created
26567c478bd9Sstevel@tonic-gate * this mess. If we fail, make sure not
26577c478bd9Sstevel@tonic-gate * to overwrite the original error
26587c478bd9Sstevel@tonic-gate */
26597c478bd9Sstevel@tonic-gate if (unit == -1) {
26607c478bd9Sstevel@tonic-gate continue;
26617c478bd9Sstevel@tonic-gate }
26627c478bd9Sstevel@tonic-gate if (sbd_cancel_mem(hp, unit) != 0)
26637c478bd9Sstevel@tonic-gate continue;
26647c478bd9Sstevel@tonic-gate
26657c478bd9Sstevel@tonic-gate t_mp->sbm_flags = 0;
26667c478bd9Sstevel@tonic-gate /*
26677c478bd9Sstevel@tonic-gate * clean up
26687c478bd9Sstevel@tonic-gate */
26697c478bd9Sstevel@tonic-gate sbd_mem_cleanup(s_mp, t_mp, ep);
26707c478bd9Sstevel@tonic-gate if (s_mp->sbm_mlist) {
26717c478bd9Sstevel@tonic-gate memlist_delete(s_mp->sbm_mlist);
26727c478bd9Sstevel@tonic-gate s_mp->sbm_mlist = NULL;
26737c478bd9Sstevel@tonic-gate }
26747c478bd9Sstevel@tonic-gate
26757c478bd9Sstevel@tonic-gate SBD_DEVICE_TRANSITION(tbp, SBD_COMP_MEM,
26767c478bd9Sstevel@tonic-gate unit, SBD_STATE_CONFIGURED);
26777c478bd9Sstevel@tonic-gate }
26787c478bd9Sstevel@tonic-gate }
26797c478bd9Sstevel@tonic-gate
26807c478bd9Sstevel@tonic-gate PR_MEM("%s: %s memory COPY-RENAME (board %d -> %d)\n",
26817c478bd9Sstevel@tonic-gate f,
26827c478bd9Sstevel@tonic-gate rv ? "FAILED" : "COMPLETED",
26837c478bd9Sstevel@tonic-gate sbp->sb_num,
26847c478bd9Sstevel@tonic-gate tbp->sb_num);
26857c478bd9Sstevel@tonic-gate }
26867c478bd9Sstevel@tonic-gate
26877c478bd9Sstevel@tonic-gate if (rv == 0) {
26887c478bd9Sstevel@tonic-gate update_membounds_t umb;
26897c478bd9Sstevel@tonic-gate
26907c478bd9Sstevel@tonic-gate umb.u_board = sbp->sb_num;
26917c478bd9Sstevel@tonic-gate umb.u_base = (uint64_t)-1;
26927c478bd9Sstevel@tonic-gate umb.u_len = (uint64_t)-1;
26937c478bd9Sstevel@tonic-gate
26947c478bd9Sstevel@tonic-gate lgrp_plat_config(LGRP_CONFIG_MEM_DEL, (uintptr_t)&umb);
26957c478bd9Sstevel@tonic-gate }
26967c478bd9Sstevel@tonic-gate
26977c478bd9Sstevel@tonic-gate sbd_release_sbdp_handle(hdp);
26987c478bd9Sstevel@tonic-gate return (rv);
26997c478bd9Sstevel@tonic-gate }
27007c478bd9Sstevel@tonic-gate
27017c478bd9Sstevel@tonic-gate /*ARGSUSED*/
27027c478bd9Sstevel@tonic-gate static void
sbd_flush_ecache(uint64_t a,uint64_t b)27037c478bd9Sstevel@tonic-gate sbd_flush_ecache(uint64_t a, uint64_t b)
27047c478bd9Sstevel@tonic-gate {
27057c478bd9Sstevel@tonic-gate cpu_flush_ecache();
27067c478bd9Sstevel@tonic-gate }
2707