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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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