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 525cf1a30Sjl139090 * Common Development and Distribution License (the "License"). 625cf1a30Sjl139090 * 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 * DR memory support routines. 297c478bd9Sstevel@tonic-gate */ 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate #include <sys/note.h> 327c478bd9Sstevel@tonic-gate #include <sys/debug.h> 337c478bd9Sstevel@tonic-gate #include <sys/types.h> 347c478bd9Sstevel@tonic-gate #include <sys/errno.h> 357c478bd9Sstevel@tonic-gate #include <sys/param.h> 367c478bd9Sstevel@tonic-gate #include <sys/dditypes.h> 377c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 387c478bd9Sstevel@tonic-gate #include <sys/conf.h> 397c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 407c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 417c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 427c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 437c478bd9Sstevel@tonic-gate #include <sys/ndi_impldefs.h> 447c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 457c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> 467c478bd9Sstevel@tonic-gate #include <sys/spitregs.h> 477c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 487c478bd9Sstevel@tonic-gate #include <sys/promif.h> 497c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h> 507c478bd9Sstevel@tonic-gate #include <sys/lgrp.h> 517c478bd9Sstevel@tonic-gate #include <sys/platform_module.h> 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate #include <vm/page.h> 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate #include <sys/dr.h> 567c478bd9Sstevel@tonic-gate #include <sys/dr_util.h> 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate extern struct memlist *phys_install; 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate /* TODO: push this reference below drmach line */ 617c478bd9Sstevel@tonic-gate extern int kcage_on; 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate /* for the DR*INTERNAL_ERROR macros. see sys/dr.h. */ 64f500b196SRichard Bean static char *dr_ie_fmt = "dr_mem.c %d"; 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate static int dr_post_detach_mem_unit(dr_mem_unit_t *mp); 67d3d50737SRafael Vanoni static int dr_reserve_mem_spans(memhandle_t *mhp, struct memlist *mlist); 68d3d50737SRafael Vanoni static int dr_select_mem_target(dr_handle_t *hp, dr_mem_unit_t *mp, 69d3d50737SRafael Vanoni struct memlist *ml); 707c478bd9Sstevel@tonic-gate static void dr_init_mem_unit_data(dr_mem_unit_t *mp); 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate static int memlist_canfit(struct memlist *s_mlist, 737c478bd9Sstevel@tonic-gate struct memlist *t_mlist); 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate /* 767c478bd9Sstevel@tonic-gate * dr_mem_unit_t.sbm_flags 777c478bd9Sstevel@tonic-gate */ 787c478bd9Sstevel@tonic-gate #define DR_MFLAG_RESERVED 0x01 /* mem unit reserved for delete */ 797c478bd9Sstevel@tonic-gate #define DR_MFLAG_SOURCE 0x02 /* source brd of copy/rename op */ 807c478bd9Sstevel@tonic-gate #define DR_MFLAG_TARGET 0x04 /* target brd of copy/rename op */ 817c478bd9Sstevel@tonic-gate #define DR_MFLAG_MEMUPSIZE 0x08 /* move from big to small board */ 827c478bd9Sstevel@tonic-gate #define DR_MFLAG_MEMDOWNSIZE 0x10 /* move from small to big board */ 837c478bd9Sstevel@tonic-gate #define DR_MFLAG_MEMRESIZE 0x18 /* move to different size board */ 847c478bd9Sstevel@tonic-gate #define DR_MFLAG_RELOWNER 0x20 /* memory release (delete) owner */ 857c478bd9Sstevel@tonic-gate #define DR_MFLAG_RELDONE 0x40 /* memory release (delete) done */ 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate /* helper macros */ 887c478bd9Sstevel@tonic-gate #define _ptob64(p) ((uint64_t)(p) << PAGESHIFT) 897c478bd9Sstevel@tonic-gate #define _b64top(b) ((pgcnt_t)((b) >> PAGESHIFT)) 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate static struct memlist * 927c478bd9Sstevel@tonic-gate dr_get_memlist(dr_mem_unit_t *mp) 937c478bd9Sstevel@tonic-gate { 947c478bd9Sstevel@tonic-gate struct memlist *mlist = NULL; 957c478bd9Sstevel@tonic-gate sbd_error_t *err; 967c478bd9Sstevel@tonic-gate static fn_t f = "dr_get_memlist"; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate PR_MEM("%s for %s...\n", f, mp->sbm_cm.sbdev_path); 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate /* 1017c478bd9Sstevel@tonic-gate * Return cached memlist, if present. 1027c478bd9Sstevel@tonic-gate * This memlist will be present following an 1037c478bd9Sstevel@tonic-gate * unconfigure (a.k.a: detach) of this memunit. 1047c478bd9Sstevel@tonic-gate * It should only be used in the case were a configure 1057c478bd9Sstevel@tonic-gate * is bringing this memunit back in without going 1067c478bd9Sstevel@tonic-gate * through the disconnect and connect states. 1077c478bd9Sstevel@tonic-gate */ 1087c478bd9Sstevel@tonic-gate if (mp->sbm_mlist) { 1097c478bd9Sstevel@tonic-gate PR_MEM("%s: found cached memlist\n", f); 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate mlist = memlist_dup(mp->sbm_mlist); 1127c478bd9Sstevel@tonic-gate } else { 1137c478bd9Sstevel@tonic-gate uint64_t basepa = _ptob64(mp->sbm_basepfn); 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate /* attempt to construct a memlist using phys_install */ 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate /* round down to slice base address */ 1187c478bd9Sstevel@tonic-gate basepa &= ~(mp->sbm_slice_size - 1); 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate /* get a copy of phys_install to edit */ 1217c478bd9Sstevel@tonic-gate memlist_read_lock(); 1227c478bd9Sstevel@tonic-gate mlist = memlist_dup(phys_install); 1237c478bd9Sstevel@tonic-gate memlist_read_unlock(); 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate /* trim lower irrelevant span */ 1267c478bd9Sstevel@tonic-gate if (mlist) 1277c478bd9Sstevel@tonic-gate mlist = memlist_del_span(mlist, 0ull, basepa); 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate /* trim upper irrelevant span */ 1307c478bd9Sstevel@tonic-gate if (mlist) { 1317c478bd9Sstevel@tonic-gate uint64_t endpa; 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate basepa += mp->sbm_slice_size; 1347c478bd9Sstevel@tonic-gate endpa = _ptob64(physmax + 1); 1357c478bd9Sstevel@tonic-gate if (endpa > basepa) 1367c478bd9Sstevel@tonic-gate mlist = memlist_del_span( 1377c478bd9Sstevel@tonic-gate mlist, 1387c478bd9Sstevel@tonic-gate basepa, 1397c478bd9Sstevel@tonic-gate endpa - basepa); 1407c478bd9Sstevel@tonic-gate } 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate if (mlist) { 1437c478bd9Sstevel@tonic-gate /* successfully built a memlist */ 1447c478bd9Sstevel@tonic-gate PR_MEM("%s: derived memlist from phys_install\n", f); 1457c478bd9Sstevel@tonic-gate } 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate /* if no mlist yet, try platform layer */ 1487c478bd9Sstevel@tonic-gate if (!mlist) { 1497c478bd9Sstevel@tonic-gate err = drmach_mem_get_memlist( 1507c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_id, &mlist); 1517c478bd9Sstevel@tonic-gate if (err) { 1527c478bd9Sstevel@tonic-gate DRERR_SET_C(&mp->sbm_cm.sbdev_error, &err); 1537c478bd9Sstevel@tonic-gate mlist = NULL; /* paranoia */ 1547c478bd9Sstevel@tonic-gate } 1557c478bd9Sstevel@tonic-gate } 1567c478bd9Sstevel@tonic-gate } 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate PR_MEM("%s: memlist for %s\n", f, mp->sbm_cm.sbdev_path); 1597c478bd9Sstevel@tonic-gate PR_MEMLIST_DUMP(mlist); 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate return (mlist); 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate typedef struct { 1657c478bd9Sstevel@tonic-gate kcondvar_t cond; 1667c478bd9Sstevel@tonic-gate kmutex_t lock; 1677c478bd9Sstevel@tonic-gate int error; 1687c478bd9Sstevel@tonic-gate int done; 1697c478bd9Sstevel@tonic-gate } dr_release_mem_sync_t; 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate /* 1727c478bd9Sstevel@tonic-gate * Memory has been logically removed by the time this routine is called. 1737c478bd9Sstevel@tonic-gate */ 1747c478bd9Sstevel@tonic-gate static void 1757c478bd9Sstevel@tonic-gate dr_mem_del_done(void *arg, int error) 1767c478bd9Sstevel@tonic-gate { 1777c478bd9Sstevel@tonic-gate dr_release_mem_sync_t *ds = arg; 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate mutex_enter(&ds->lock); 1807c478bd9Sstevel@tonic-gate ds->error = error; 1817c478bd9Sstevel@tonic-gate ds->done = 1; 1827c478bd9Sstevel@tonic-gate cv_signal(&ds->cond); 1837c478bd9Sstevel@tonic-gate mutex_exit(&ds->lock); 1847c478bd9Sstevel@tonic-gate } 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate /* 1877c478bd9Sstevel@tonic-gate * When we reach here the memory being drained should have 1887c478bd9Sstevel@tonic-gate * already been reserved in dr_pre_release_mem(). 1897c478bd9Sstevel@tonic-gate * Our only task here is to kick off the "drain" and wait 1907c478bd9Sstevel@tonic-gate * for it to finish. 1917c478bd9Sstevel@tonic-gate */ 1927c478bd9Sstevel@tonic-gate void 1937c478bd9Sstevel@tonic-gate dr_release_mem(dr_common_unit_t *cp) 1947c478bd9Sstevel@tonic-gate { 1957c478bd9Sstevel@tonic-gate dr_mem_unit_t *mp = (dr_mem_unit_t *)cp; 1967c478bd9Sstevel@tonic-gate int err; 1977c478bd9Sstevel@tonic-gate dr_release_mem_sync_t rms; 1987c478bd9Sstevel@tonic-gate static fn_t f = "dr_release_mem"; 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate /* check that this memory unit has been reserved */ 2017c478bd9Sstevel@tonic-gate if (!(mp->sbm_flags & DR_MFLAG_RELOWNER)) { 2027c478bd9Sstevel@tonic-gate DR_DEV_INTERNAL_ERROR(&mp->sbm_cm); 2037c478bd9Sstevel@tonic-gate return; 2047c478bd9Sstevel@tonic-gate } 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate bzero((void *) &rms, sizeof (rms)); 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate mutex_init(&rms.lock, NULL, MUTEX_DRIVER, NULL); 2097c478bd9Sstevel@tonic-gate cv_init(&rms.cond, NULL, CV_DRIVER, NULL); 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate mutex_enter(&rms.lock); 212d3d50737SRafael Vanoni err = kphysm_del_start(mp->sbm_memhandle, dr_mem_del_done, 213d3d50737SRafael Vanoni (void *) &rms); 2147c478bd9Sstevel@tonic-gate if (err == KPHYSM_OK) { 2157c478bd9Sstevel@tonic-gate /* wait for completion or interrupt */ 2167c478bd9Sstevel@tonic-gate while (!rms.done) { 2177c478bd9Sstevel@tonic-gate if (cv_wait_sig(&rms.cond, &rms.lock) == 0) { 2187c478bd9Sstevel@tonic-gate /* then there is a pending UNIX signal */ 2197c478bd9Sstevel@tonic-gate (void) kphysm_del_cancel(mp->sbm_memhandle); 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate /* wait for completion */ 2227c478bd9Sstevel@tonic-gate while (!rms.done) 2237c478bd9Sstevel@tonic-gate cv_wait(&rms.cond, &rms.lock); 2247c478bd9Sstevel@tonic-gate } 2257c478bd9Sstevel@tonic-gate } 2267c478bd9Sstevel@tonic-gate /* get the result of the memory delete operation */ 2277c478bd9Sstevel@tonic-gate err = rms.error; 2287c478bd9Sstevel@tonic-gate } 2297c478bd9Sstevel@tonic-gate mutex_exit(&rms.lock); 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate cv_destroy(&rms.cond); 2327c478bd9Sstevel@tonic-gate mutex_destroy(&rms.lock); 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate if (err != KPHYSM_OK) { 2357c478bd9Sstevel@tonic-gate int e_code; 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate switch (err) { 2387c478bd9Sstevel@tonic-gate case KPHYSM_ENOWORK: 2397c478bd9Sstevel@tonic-gate e_code = ESBD_NOERROR; 2407c478bd9Sstevel@tonic-gate break; 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate case KPHYSM_EHANDLE: 2437c478bd9Sstevel@tonic-gate case KPHYSM_ESEQUENCE: 2447c478bd9Sstevel@tonic-gate e_code = ESBD_INTERNAL; 2457c478bd9Sstevel@tonic-gate break; 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate case KPHYSM_ENOTVIABLE: 2487c478bd9Sstevel@tonic-gate e_code = ESBD_MEM_NOTVIABLE; 2497c478bd9Sstevel@tonic-gate break; 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate case KPHYSM_EREFUSED: 2527c478bd9Sstevel@tonic-gate e_code = ESBD_MEM_REFUSED; 2537c478bd9Sstevel@tonic-gate break; 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate case KPHYSM_ENONRELOC: 2567c478bd9Sstevel@tonic-gate e_code = ESBD_MEM_NONRELOC; 2577c478bd9Sstevel@tonic-gate break; 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate case KPHYSM_ECANCELLED: 2607c478bd9Sstevel@tonic-gate e_code = ESBD_MEM_CANCELLED; 2617c478bd9Sstevel@tonic-gate break; 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate case KPHYSM_ERESOURCE: 2647c478bd9Sstevel@tonic-gate e_code = ESBD_MEMFAIL; 2657c478bd9Sstevel@tonic-gate break; 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate default: 2687c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 2697c478bd9Sstevel@tonic-gate "%s: unexpected kphysm error code %d," 2707c478bd9Sstevel@tonic-gate " id 0x%p", 2717c478bd9Sstevel@tonic-gate f, err, mp->sbm_cm.sbdev_id); 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate e_code = ESBD_IO; 2747c478bd9Sstevel@tonic-gate break; 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate if (e_code != ESBD_NOERROR) { 2787c478bd9Sstevel@tonic-gate dr_dev_err(CE_IGNORE, &mp->sbm_cm, e_code); 2797c478bd9Sstevel@tonic-gate } 2807c478bd9Sstevel@tonic-gate } 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate void 2847c478bd9Sstevel@tonic-gate dr_attach_mem(dr_handle_t *hp, dr_common_unit_t *cp) 2857c478bd9Sstevel@tonic-gate { 2867c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(hp)) 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate dr_mem_unit_t *mp = (dr_mem_unit_t *)cp; 2897c478bd9Sstevel@tonic-gate struct memlist *ml, *mc; 2907c478bd9Sstevel@tonic-gate sbd_error_t *err; 2917c478bd9Sstevel@tonic-gate static fn_t f = "dr_attach_mem"; 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate PR_MEM("%s...\n", f); 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate dr_lock_status(hp->h_bd); 2967c478bd9Sstevel@tonic-gate err = drmach_configure(cp->sbdev_id, 0); 2977c478bd9Sstevel@tonic-gate dr_unlock_status(hp->h_bd); 2987c478bd9Sstevel@tonic-gate if (err) { 2997c478bd9Sstevel@tonic-gate DRERR_SET_C(&cp->sbdev_error, &err); 3007c478bd9Sstevel@tonic-gate return; 3017c478bd9Sstevel@tonic-gate } 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate ml = dr_get_memlist(mp); 304*56f33205SJonathan Adams for (mc = ml; mc; mc = mc->ml_next) { 3057c478bd9Sstevel@tonic-gate int rv; 3067c478bd9Sstevel@tonic-gate sbd_error_t *err; 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate rv = kphysm_add_memory_dynamic( 309*56f33205SJonathan Adams (pfn_t)(mc->ml_address >> PAGESHIFT), 310*56f33205SJonathan Adams (pgcnt_t)(mc->ml_size >> PAGESHIFT)); 3117c478bd9Sstevel@tonic-gate if (rv != KPHYSM_OK) { 3127c478bd9Sstevel@tonic-gate /* 3137c478bd9Sstevel@tonic-gate * translate kphysm error and 3147c478bd9Sstevel@tonic-gate * store in devlist error 3157c478bd9Sstevel@tonic-gate */ 3167c478bd9Sstevel@tonic-gate switch (rv) { 3177c478bd9Sstevel@tonic-gate case KPHYSM_ERESOURCE: 3187c478bd9Sstevel@tonic-gate rv = ESBD_NOMEM; 3197c478bd9Sstevel@tonic-gate break; 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate case KPHYSM_EFAULT: 3227c478bd9Sstevel@tonic-gate rv = ESBD_FAULT; 3237c478bd9Sstevel@tonic-gate break; 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate default: 3267c478bd9Sstevel@tonic-gate rv = ESBD_INTERNAL; 3277c478bd9Sstevel@tonic-gate break; 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate if (rv == ESBD_INTERNAL) { 3317c478bd9Sstevel@tonic-gate DR_DEV_INTERNAL_ERROR(&mp->sbm_cm); 3327c478bd9Sstevel@tonic-gate } else 3337c478bd9Sstevel@tonic-gate dr_dev_err(CE_WARN, &mp->sbm_cm, rv); 3347c478bd9Sstevel@tonic-gate break; 3357c478bd9Sstevel@tonic-gate } 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate err = drmach_mem_add_span( 338*56f33205SJonathan Adams mp->sbm_cm.sbdev_id, mc->ml_address, mc->ml_size); 3397c478bd9Sstevel@tonic-gate if (err) { 3407c478bd9Sstevel@tonic-gate DRERR_SET_C(&mp->sbm_cm.sbdev_error, &err); 3417c478bd9Sstevel@tonic-gate break; 3427c478bd9Sstevel@tonic-gate } 3437c478bd9Sstevel@tonic-gate } 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate memlist_delete(ml); 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate /* back out if configure failed */ 3487c478bd9Sstevel@tonic-gate if (mp->sbm_cm.sbdev_error != NULL) { 3497c478bd9Sstevel@tonic-gate dr_lock_status(hp->h_bd); 35025cf1a30Sjl139090 err = drmach_unconfigure(cp->sbdev_id, 35125cf1a30Sjl139090 DEVI_BRANCH_DESTROY); 3527c478bd9Sstevel@tonic-gate if (err) 3537c478bd9Sstevel@tonic-gate sbd_err_clear(&err); 3547c478bd9Sstevel@tonic-gate dr_unlock_status(hp->h_bd); 3557c478bd9Sstevel@tonic-gate } 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate #define DR_SCRUB_VALUE 0x0d0e0a0d0b0e0e0fULL 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate static void 3617c478bd9Sstevel@tonic-gate dr_mem_ecache_scrub(dr_mem_unit_t *mp, struct memlist *mlist) 3627c478bd9Sstevel@tonic-gate { 3637c478bd9Sstevel@tonic-gate #ifdef DEBUG 364d3d50737SRafael Vanoni clock_t stime = ddi_get_lbolt(); 3657c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate struct memlist *ml; 3687c478bd9Sstevel@tonic-gate uint64_t scrub_value = DR_SCRUB_VALUE; 3697c478bd9Sstevel@tonic-gate processorid_t cpuid; 3707c478bd9Sstevel@tonic-gate static fn_t f = "dr_mem_ecache_scrub"; 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate cpuid = drmach_mem_cpu_affinity(mp->sbm_cm.sbdev_id); 3737c478bd9Sstevel@tonic-gate affinity_set(cpuid); 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate PR_MEM("%s: using proc %d, memlist...\n", f, 3767c478bd9Sstevel@tonic-gate (cpuid == CPU_CURRENT) ? CPU->cpu_id : cpuid); 3777c478bd9Sstevel@tonic-gate PR_MEMLIST_DUMP(mlist); 3787c478bd9Sstevel@tonic-gate 379*56f33205SJonathan Adams for (ml = mlist; ml; ml = ml->ml_next) { 3807c478bd9Sstevel@tonic-gate uint64_t dst_pa; 3817c478bd9Sstevel@tonic-gate uint64_t nbytes; 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate /* calculate the destination physical address */ 384*56f33205SJonathan Adams dst_pa = ml->ml_address; 385*56f33205SJonathan Adams if (ml->ml_address & PAGEOFFSET) 3867c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 38704580fdfSmathue "%s: address (0x%lx) not on " 388*56f33205SJonathan Adams "page boundary", f, ml->ml_address); 3897c478bd9Sstevel@tonic-gate 390*56f33205SJonathan Adams nbytes = ml->ml_size; 391*56f33205SJonathan Adams if (ml->ml_size & PAGEOFFSET) 3927c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 39304580fdfSmathue "%s: size (0x%lx) not on " 394*56f33205SJonathan Adams "page boundary", f, ml->ml_size); 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate /*LINTED*/ 3977c478bd9Sstevel@tonic-gate while (nbytes > 0) { 3987c478bd9Sstevel@tonic-gate /* write 64 bits to dst_pa */ 3997c478bd9Sstevel@tonic-gate stdphys(dst_pa, scrub_value); 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate /* increment/decrement by cacheline sizes */ 4027c478bd9Sstevel@tonic-gate dst_pa += DRMACH_COHERENCY_UNIT; 4037c478bd9Sstevel@tonic-gate nbytes -= DRMACH_COHERENCY_UNIT; 4047c478bd9Sstevel@tonic-gate } 4057c478bd9Sstevel@tonic-gate } 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate /* 4087c478bd9Sstevel@tonic-gate * flush this cpu's ecache and take care to ensure 4097c478bd9Sstevel@tonic-gate * that all of it's bus transactions have retired. 4107c478bd9Sstevel@tonic-gate */ 4117c478bd9Sstevel@tonic-gate drmach_cpu_flush_ecache_sync(); 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate affinity_clear(); 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate #ifdef DEBUG 416d3d50737SRafael Vanoni stime = ddi_get_lbolt() - stime; 4177c478bd9Sstevel@tonic-gate PR_MEM("%s: scrub ticks = %ld (%ld secs)\n", f, stime, stime / hz); 4187c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 4197c478bd9Sstevel@tonic-gate } 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate static int 4227c478bd9Sstevel@tonic-gate dr_move_memory(dr_handle_t *hp, dr_mem_unit_t *s_mp, dr_mem_unit_t *t_mp) 4237c478bd9Sstevel@tonic-gate { 4247c478bd9Sstevel@tonic-gate time_t copytime; 4257c478bd9Sstevel@tonic-gate drmachid_t cr_id; 4267c478bd9Sstevel@tonic-gate dr_sr_handle_t *srhp; 427db874c57Selowe struct memlist *c_ml, *d_ml; 4287c478bd9Sstevel@tonic-gate sbd_error_t *err; 4297c478bd9Sstevel@tonic-gate static fn_t f = "dr_move_memory"; 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate PR_MEM("%s: (INLINE) moving memory from %s to %s\n", 4327c478bd9Sstevel@tonic-gate f, 4337c478bd9Sstevel@tonic-gate s_mp->sbm_cm.sbdev_path, 4347c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_path); 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate ASSERT(s_mp->sbm_flags & DR_MFLAG_SOURCE); 4377c478bd9Sstevel@tonic-gate ASSERT(s_mp->sbm_peer == t_mp); 4387c478bd9Sstevel@tonic-gate ASSERT(s_mp->sbm_mlist); 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_flags & DR_MFLAG_TARGET); 4417c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_peer == s_mp); 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate /* 4447c478bd9Sstevel@tonic-gate * create a memlist of spans to copy by removing 4457c478bd9Sstevel@tonic-gate * the spans that have been deleted, if any, from 4467c478bd9Sstevel@tonic-gate * the full source board memlist. s_mp->sbm_del_mlist 4477c478bd9Sstevel@tonic-gate * will be NULL if there were no spans deleted from 4487c478bd9Sstevel@tonic-gate * the source board. 4497c478bd9Sstevel@tonic-gate */ 4507c478bd9Sstevel@tonic-gate c_ml = memlist_dup(s_mp->sbm_mlist); 4517c478bd9Sstevel@tonic-gate d_ml = s_mp->sbm_del_mlist; 4527c478bd9Sstevel@tonic-gate while (d_ml != NULL) { 453*56f33205SJonathan Adams c_ml = memlist_del_span(c_ml, d_ml->ml_address, d_ml->ml_size); 454*56f33205SJonathan Adams d_ml = d_ml->ml_next; 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate affinity_set(drmach_mem_cpu_affinity(t_mp->sbm_cm.sbdev_id)); 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate err = drmach_copy_rename_init( 4607c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_id, _ptob64(t_mp->sbm_slice_offset), 4617c478bd9Sstevel@tonic-gate s_mp->sbm_cm.sbdev_id, c_ml, &cr_id); 4627c478bd9Sstevel@tonic-gate if (err) { 4637c478bd9Sstevel@tonic-gate DRERR_SET_C(&s_mp->sbm_cm.sbdev_error, &err); 4647c478bd9Sstevel@tonic-gate affinity_clear(); 4657c478bd9Sstevel@tonic-gate return (-1); 4667c478bd9Sstevel@tonic-gate } 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate srhp = dr_get_sr_handle(hp); 4697c478bd9Sstevel@tonic-gate ASSERT(srhp); 4707c478bd9Sstevel@tonic-gate 471d3d50737SRafael Vanoni copytime = ddi_get_lbolt(); 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate /* Quiesce the OS. */ 4747c478bd9Sstevel@tonic-gate if (dr_suspend(srhp)) { 4757c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s: failed to quiesce OS" 4767c478bd9Sstevel@tonic-gate " for copy-rename", f); 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate dr_release_sr_handle(srhp); 4797c478bd9Sstevel@tonic-gate err = drmach_copy_rename_fini(cr_id); 4807c478bd9Sstevel@tonic-gate if (err) { 4817c478bd9Sstevel@tonic-gate /* 4827c478bd9Sstevel@tonic-gate * no error is expected since the program has 4837c478bd9Sstevel@tonic-gate * not yet run. 4847c478bd9Sstevel@tonic-gate */ 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate /* catch this in debug kernels */ 4877c478bd9Sstevel@tonic-gate ASSERT(0); 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate sbd_err_clear(&err); 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate /* suspend error reached via hp */ 4937c478bd9Sstevel@tonic-gate s_mp->sbm_cm.sbdev_error = hp->h_err; 4947c478bd9Sstevel@tonic-gate hp->h_err = NULL; 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate affinity_clear(); 4977c478bd9Sstevel@tonic-gate return (-1); 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate /* 5017c478bd9Sstevel@tonic-gate * Rename memory for lgroup. 5027c478bd9Sstevel@tonic-gate * Source and target board numbers are packaged in arg. 5037c478bd9Sstevel@tonic-gate */ 5047c478bd9Sstevel@tonic-gate { 5057c478bd9Sstevel@tonic-gate dr_board_t *t_bp, *s_bp; 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate s_bp = s_mp->sbm_cm.sbdev_bp; 5087c478bd9Sstevel@tonic-gate t_bp = t_mp->sbm_cm.sbdev_bp; 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate lgrp_plat_config(LGRP_CONFIG_MEM_RENAME, 5117c478bd9Sstevel@tonic-gate (uintptr_t)(s_bp->b_num | (t_bp->b_num << 16))); 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate drmach_copy_rename(cr_id); 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate /* Resume the OS. */ 5177c478bd9Sstevel@tonic-gate dr_resume(srhp); 5187c478bd9Sstevel@tonic-gate 519d3d50737SRafael Vanoni copytime = ddi_get_lbolt() - copytime; 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate dr_release_sr_handle(srhp); 5227c478bd9Sstevel@tonic-gate err = drmach_copy_rename_fini(cr_id); 5237c478bd9Sstevel@tonic-gate if (err) 5247c478bd9Sstevel@tonic-gate DRERR_SET_C(&s_mp->sbm_cm.sbdev_error, &err); 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate affinity_clear(); 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate PR_MEM("%s: copy-rename elapsed time = %ld ticks (%ld secs)\n", 5297c478bd9Sstevel@tonic-gate f, copytime, copytime / hz); 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate /* return -1 if dr_suspend or copy/rename recorded an error */ 5327c478bd9Sstevel@tonic-gate return (err == NULL ? 0 : -1); 5337c478bd9Sstevel@tonic-gate } 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate /* 5367c478bd9Sstevel@tonic-gate * If detaching node contains memory that is "non-permanent" 5377c478bd9Sstevel@tonic-gate * then the memory adr's are simply cleared. If the memory 5387c478bd9Sstevel@tonic-gate * is non-relocatable, then do a copy-rename. 5397c478bd9Sstevel@tonic-gate */ 5407c478bd9Sstevel@tonic-gate void 5417c478bd9Sstevel@tonic-gate dr_detach_mem(dr_handle_t *hp, dr_common_unit_t *cp) 5427c478bd9Sstevel@tonic-gate { 5437c478bd9Sstevel@tonic-gate int rv = 0; 5447c478bd9Sstevel@tonic-gate dr_mem_unit_t *s_mp = (dr_mem_unit_t *)cp; 5457c478bd9Sstevel@tonic-gate dr_mem_unit_t *t_mp; 5467c478bd9Sstevel@tonic-gate dr_state_t state; 5477c478bd9Sstevel@tonic-gate static fn_t f = "dr_detach_mem"; 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate PR_MEM("%s...\n", f); 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate /* lookup target mem unit and target board structure, if any */ 5527c478bd9Sstevel@tonic-gate if (s_mp->sbm_flags & DR_MFLAG_SOURCE) { 5537c478bd9Sstevel@tonic-gate t_mp = s_mp->sbm_peer; 5547c478bd9Sstevel@tonic-gate ASSERT(t_mp != NULL); 5557c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_peer == s_mp); 5567c478bd9Sstevel@tonic-gate } else { 5577c478bd9Sstevel@tonic-gate t_mp = NULL; 5587c478bd9Sstevel@tonic-gate } 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate /* verify mem unit's state is UNREFERENCED */ 5617c478bd9Sstevel@tonic-gate state = s_mp->sbm_cm.sbdev_state; 5627c478bd9Sstevel@tonic-gate if (state != DR_STATE_UNREFERENCED) { 5637c478bd9Sstevel@tonic-gate dr_dev_err(CE_IGNORE, &s_mp->sbm_cm, ESBD_STATE); 5647c478bd9Sstevel@tonic-gate return; 5657c478bd9Sstevel@tonic-gate } 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate /* verify target mem unit's state is UNREFERENCED, if any */ 5687c478bd9Sstevel@tonic-gate if (t_mp != NULL) { 5697c478bd9Sstevel@tonic-gate state = t_mp->sbm_cm.sbdev_state; 5707c478bd9Sstevel@tonic-gate if (state != DR_STATE_UNREFERENCED) { 5717c478bd9Sstevel@tonic-gate dr_dev_err(CE_IGNORE, &t_mp->sbm_cm, ESBD_STATE); 5727c478bd9Sstevel@tonic-gate return; 5737c478bd9Sstevel@tonic-gate } 5747c478bd9Sstevel@tonic-gate } 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate /* 5777c478bd9Sstevel@tonic-gate * Scrub deleted memory. This will cause all cachelines 5787c478bd9Sstevel@tonic-gate * referencing the memory to only be in the local cpu's 5797c478bd9Sstevel@tonic-gate * ecache. 5807c478bd9Sstevel@tonic-gate */ 5817c478bd9Sstevel@tonic-gate if (s_mp->sbm_flags & DR_MFLAG_RELDONE) { 5827c478bd9Sstevel@tonic-gate /* no del mlist for src<=dst mem size copy/rename */ 5837c478bd9Sstevel@tonic-gate if (s_mp->sbm_del_mlist) 5847c478bd9Sstevel@tonic-gate dr_mem_ecache_scrub(s_mp, s_mp->sbm_del_mlist); 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate if (t_mp != NULL && (t_mp->sbm_flags & DR_MFLAG_RELDONE)) { 5877c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_del_mlist); 5887c478bd9Sstevel@tonic-gate dr_mem_ecache_scrub(t_mp, t_mp->sbm_del_mlist); 5897c478bd9Sstevel@tonic-gate } 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate /* 5927c478bd9Sstevel@tonic-gate * If there is no target board (no copy/rename was needed), then 5937c478bd9Sstevel@tonic-gate * we're done! 5947c478bd9Sstevel@tonic-gate */ 5957c478bd9Sstevel@tonic-gate if (t_mp == NULL) { 5967c478bd9Sstevel@tonic-gate sbd_error_t *err; 5977c478bd9Sstevel@tonic-gate /* 5987c478bd9Sstevel@tonic-gate * Reprogram interconnect hardware and disable 5997c478bd9Sstevel@tonic-gate * memory controllers for memory node that's going away. 6007c478bd9Sstevel@tonic-gate */ 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate err = drmach_mem_disable(s_mp->sbm_cm.sbdev_id); 6037c478bd9Sstevel@tonic-gate if (err) { 6047c478bd9Sstevel@tonic-gate DRERR_SET_C(&s_mp->sbm_cm.sbdev_error, &err); 6057c478bd9Sstevel@tonic-gate rv = -1; 6067c478bd9Sstevel@tonic-gate } 6077c478bd9Sstevel@tonic-gate } else { 6087c478bd9Sstevel@tonic-gate rv = dr_move_memory(hp, s_mp, t_mp); 6097c478bd9Sstevel@tonic-gate PR_MEM("%s: %s memory COPY-RENAME (board %d -> %d)\n", 6107c478bd9Sstevel@tonic-gate f, 6117c478bd9Sstevel@tonic-gate rv ? "FAILED" : "COMPLETED", 6127c478bd9Sstevel@tonic-gate s_mp->sbm_cm.sbdev_bp->b_num, 6137c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_bp->b_num); 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate if (rv != 0) 6167c478bd9Sstevel@tonic-gate (void) dr_cancel_mem(s_mp); 6177c478bd9Sstevel@tonic-gate } 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate if (rv == 0) { 6207c478bd9Sstevel@tonic-gate sbd_error_t *err; 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate dr_lock_status(hp->h_bd); 6237c478bd9Sstevel@tonic-gate err = drmach_unconfigure(s_mp->sbm_cm.sbdev_id, 62425cf1a30Sjl139090 DEVI_BRANCH_DESTROY); 6257c478bd9Sstevel@tonic-gate dr_unlock_status(hp->h_bd); 6267c478bd9Sstevel@tonic-gate if (err) 6277c478bd9Sstevel@tonic-gate sbd_err_clear(&err); 6287c478bd9Sstevel@tonic-gate } 6297c478bd9Sstevel@tonic-gate } 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate #ifndef _STARFIRE 6327c478bd9Sstevel@tonic-gate /* 6337c478bd9Sstevel@tonic-gate * XXX workaround for certain lab configurations (see also starcat drmach.c) 6347c478bd9Sstevel@tonic-gate * Temporary code to get around observed incorrect results from 6357c478bd9Sstevel@tonic-gate * kphysm_del_span_query when the queried span contains address spans 6367c478bd9Sstevel@tonic-gate * not occupied by memory in between spans that do have memory. 6377c478bd9Sstevel@tonic-gate * This routine acts as a wrapper to kphysm_del_span_query. It builds 6387c478bd9Sstevel@tonic-gate * a memlist from phys_install of spans that exist between base and 6397c478bd9Sstevel@tonic-gate * base + npages, inclusively. Kphysm_del_span_query is called for each 6407c478bd9Sstevel@tonic-gate * node in the memlist with the results accumulated in *mp. 6417c478bd9Sstevel@tonic-gate */ 6427c478bd9Sstevel@tonic-gate static int 6437c478bd9Sstevel@tonic-gate dr_del_span_query(pfn_t base, pgcnt_t npages, memquery_t *mp) 6447c478bd9Sstevel@tonic-gate { 6457c478bd9Sstevel@tonic-gate uint64_t pa = _ptob64(base); 6467c478bd9Sstevel@tonic-gate uint64_t sm = ~ (137438953472ull - 1); 6477c478bd9Sstevel@tonic-gate uint64_t sa = pa & sm; 6487c478bd9Sstevel@tonic-gate struct memlist *mlist, *ml; 6497c478bd9Sstevel@tonic-gate int rv; 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate npages = npages; /* silence lint */ 6527c478bd9Sstevel@tonic-gate memlist_read_lock(); 6537c478bd9Sstevel@tonic-gate mlist = memlist_dup(phys_install); 6547c478bd9Sstevel@tonic-gate memlist_read_unlock(); 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate again: 657*56f33205SJonathan Adams for (ml = mlist; ml; ml = ml->ml_next) { 658*56f33205SJonathan Adams if ((ml->ml_address & sm) != sa) { 659*56f33205SJonathan Adams mlist = memlist_del_span(mlist, 660*56f33205SJonathan Adams ml->ml_address, ml->ml_size); 6617c478bd9Sstevel@tonic-gate goto again; 6627c478bd9Sstevel@tonic-gate } 6637c478bd9Sstevel@tonic-gate } 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate mp->phys_pages = 0; 6667c478bd9Sstevel@tonic-gate mp->managed = 0; 6677c478bd9Sstevel@tonic-gate mp->nonrelocatable = 0; 6687c478bd9Sstevel@tonic-gate mp->first_nonrelocatable = (pfn_t)-1; /* XXX */ 6697c478bd9Sstevel@tonic-gate mp->last_nonrelocatable = 0; 6707c478bd9Sstevel@tonic-gate 671*56f33205SJonathan Adams for (ml = mlist; ml; ml = ml->ml_next) { 6727c478bd9Sstevel@tonic-gate memquery_t mq; 6737c478bd9Sstevel@tonic-gate 6747c478bd9Sstevel@tonic-gate rv = kphysm_del_span_query( 675*56f33205SJonathan Adams _b64top(ml->ml_address), _b64top(ml->ml_size), &mq); 6767c478bd9Sstevel@tonic-gate if (rv) 6777c478bd9Sstevel@tonic-gate break; 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate mp->phys_pages += mq.phys_pages; 6807c478bd9Sstevel@tonic-gate mp->managed += mq.managed; 6817c478bd9Sstevel@tonic-gate mp->nonrelocatable += mq.nonrelocatable; 6827c478bd9Sstevel@tonic-gate 6837c478bd9Sstevel@tonic-gate if (mq.nonrelocatable != 0) { 6847c478bd9Sstevel@tonic-gate if (mq.first_nonrelocatable < mp->first_nonrelocatable) 6857c478bd9Sstevel@tonic-gate mp->first_nonrelocatable = 6867c478bd9Sstevel@tonic-gate mq.first_nonrelocatable; 6877c478bd9Sstevel@tonic-gate if (mq.last_nonrelocatable > mp->last_nonrelocatable) 6887c478bd9Sstevel@tonic-gate mp->last_nonrelocatable = 6897c478bd9Sstevel@tonic-gate mq.last_nonrelocatable; 6907c478bd9Sstevel@tonic-gate } 6917c478bd9Sstevel@tonic-gate } 6927c478bd9Sstevel@tonic-gate 6937c478bd9Sstevel@tonic-gate if (mp->nonrelocatable == 0) 6947c478bd9Sstevel@tonic-gate mp->first_nonrelocatable = 0; /* XXX */ 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate memlist_delete(mlist); 6977c478bd9Sstevel@tonic-gate return (rv); 6987c478bd9Sstevel@tonic-gate } 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate #define kphysm_del_span_query dr_del_span_query 7017c478bd9Sstevel@tonic-gate #endif /* _STARFIRE */ 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate /* 7047c478bd9Sstevel@tonic-gate * NOTE: This routine is only partially smart about multiple 7057c478bd9Sstevel@tonic-gate * mem-units. Need to make mem-status structure smart 7067c478bd9Sstevel@tonic-gate * about them also. 7077c478bd9Sstevel@tonic-gate */ 7087c478bd9Sstevel@tonic-gate int 7097c478bd9Sstevel@tonic-gate dr_mem_status(dr_handle_t *hp, dr_devset_t devset, sbd_dev_stat_t *dsp) 7107c478bd9Sstevel@tonic-gate { 7117c478bd9Sstevel@tonic-gate int m, mix; 7127c478bd9Sstevel@tonic-gate memdelstat_t mdst; 7137c478bd9Sstevel@tonic-gate memquery_t mq; 7147c478bd9Sstevel@tonic-gate dr_board_t *bp; 7157c478bd9Sstevel@tonic-gate dr_mem_unit_t *mp; 7167c478bd9Sstevel@tonic-gate sbd_mem_stat_t *msp; 7177c478bd9Sstevel@tonic-gate static fn_t f = "dr_mem_status"; 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate bp = hp->h_bd; 7207c478bd9Sstevel@tonic-gate devset &= DR_DEVS_PRESENT(bp); 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate for (m = mix = 0; m < MAX_MEM_UNITS_PER_BOARD; m++) { 7237c478bd9Sstevel@tonic-gate int rv; 7247c478bd9Sstevel@tonic-gate sbd_error_t *err; 7257c478bd9Sstevel@tonic-gate drmach_status_t pstat; 7267c478bd9Sstevel@tonic-gate dr_mem_unit_t *p_mp; 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_MEM, m) == 0) 7297c478bd9Sstevel@tonic-gate continue; 7307c478bd9Sstevel@tonic-gate 7317c478bd9Sstevel@tonic-gate mp = dr_get_mem_unit(bp, m); 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate if (mp->sbm_cm.sbdev_state == DR_STATE_EMPTY) { 7347c478bd9Sstevel@tonic-gate /* present, but not fully initialized */ 7357c478bd9Sstevel@tonic-gate continue; 7367c478bd9Sstevel@tonic-gate } 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate if (mp->sbm_cm.sbdev_id == (drmachid_t)0) 7397c478bd9Sstevel@tonic-gate continue; 7407c478bd9Sstevel@tonic-gate 7417c478bd9Sstevel@tonic-gate /* fetch platform status */ 7427c478bd9Sstevel@tonic-gate err = drmach_status(mp->sbm_cm.sbdev_id, &pstat); 7437c478bd9Sstevel@tonic-gate if (err) { 7447c478bd9Sstevel@tonic-gate DRERR_SET_C(&mp->sbm_cm.sbdev_error, &err); 7457c478bd9Sstevel@tonic-gate continue; 7467c478bd9Sstevel@tonic-gate } 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate msp = &dsp->d_mem; 7497c478bd9Sstevel@tonic-gate bzero((caddr_t)msp, sizeof (*msp)); 7507c478bd9Sstevel@tonic-gate 75107d06da5SSurya Prakki (void) strncpy(msp->ms_cm.c_id.c_name, pstat.type, 7527c478bd9Sstevel@tonic-gate sizeof (msp->ms_cm.c_id.c_name)); 7537c478bd9Sstevel@tonic-gate msp->ms_cm.c_id.c_type = mp->sbm_cm.sbdev_type; 7547c478bd9Sstevel@tonic-gate msp->ms_cm.c_id.c_unit = SBD_NULL_UNIT; 7557c478bd9Sstevel@tonic-gate msp->ms_cm.c_cond = mp->sbm_cm.sbdev_cond; 7567c478bd9Sstevel@tonic-gate msp->ms_cm.c_busy = mp->sbm_cm.sbdev_busy | pstat.busy; 7577c478bd9Sstevel@tonic-gate msp->ms_cm.c_time = mp->sbm_cm.sbdev_time; 7587c478bd9Sstevel@tonic-gate msp->ms_cm.c_ostate = mp->sbm_cm.sbdev_ostate; 7597c478bd9Sstevel@tonic-gate 7607c478bd9Sstevel@tonic-gate msp->ms_totpages = mp->sbm_npages; 7617c478bd9Sstevel@tonic-gate msp->ms_basepfn = mp->sbm_basepfn; 7627c478bd9Sstevel@tonic-gate msp->ms_pageslost = mp->sbm_pageslost; 7637c478bd9Sstevel@tonic-gate msp->ms_cage_enabled = kcage_on; 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate if (mp->sbm_flags & DR_MFLAG_RESERVED) 7667c478bd9Sstevel@tonic-gate p_mp = mp->sbm_peer; 7677c478bd9Sstevel@tonic-gate else 7687c478bd9Sstevel@tonic-gate p_mp = NULL; 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate if (p_mp == NULL) { 7717c478bd9Sstevel@tonic-gate msp->ms_peer_is_target = 0; 7727c478bd9Sstevel@tonic-gate msp->ms_peer_ap_id[0] = '\0'; 7737c478bd9Sstevel@tonic-gate } else if (p_mp->sbm_flags & DR_MFLAG_RESERVED) { 7747c478bd9Sstevel@tonic-gate char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 7757c478bd9Sstevel@tonic-gate char *minor; 7767c478bd9Sstevel@tonic-gate 7777c478bd9Sstevel@tonic-gate /* 7787c478bd9Sstevel@tonic-gate * b_dip doesn't have to be held for ddi_pathname() 7797c478bd9Sstevel@tonic-gate * because the board struct (dr_board_t) will be 7807c478bd9Sstevel@tonic-gate * destroyed before b_dip detaches. 7817c478bd9Sstevel@tonic-gate */ 7827c478bd9Sstevel@tonic-gate (void) ddi_pathname(bp->b_dip, path); 7837c478bd9Sstevel@tonic-gate minor = strchr(p_mp->sbm_cm.sbdev_path, ':'); 7847c478bd9Sstevel@tonic-gate 78507d06da5SSurya Prakki (void) snprintf(msp->ms_peer_ap_id, 7867c478bd9Sstevel@tonic-gate sizeof (msp->ms_peer_ap_id), "%s%s", 7877c478bd9Sstevel@tonic-gate path, (minor == NULL) ? "" : minor); 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate kmem_free(path, MAXPATHLEN); 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate if (p_mp->sbm_flags & DR_MFLAG_TARGET) 7927c478bd9Sstevel@tonic-gate msp->ms_peer_is_target = 1; 7937c478bd9Sstevel@tonic-gate } 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate if (mp->sbm_flags & DR_MFLAG_RELOWNER) 7967c478bd9Sstevel@tonic-gate rv = kphysm_del_status(mp->sbm_memhandle, &mdst); 7977c478bd9Sstevel@tonic-gate else 7987c478bd9Sstevel@tonic-gate rv = KPHYSM_EHANDLE; /* force 'if' to fail */ 7997c478bd9Sstevel@tonic-gate 8007c478bd9Sstevel@tonic-gate if (rv == KPHYSM_OK) { 8017c478bd9Sstevel@tonic-gate /* 8027c478bd9Sstevel@tonic-gate * Any pages above managed is "free", 8037c478bd9Sstevel@tonic-gate * i.e. it's collected. 8047c478bd9Sstevel@tonic-gate */ 8057c478bd9Sstevel@tonic-gate msp->ms_detpages += (uint_t)(mdst.collected + 8067c478bd9Sstevel@tonic-gate mdst.phys_pages - mdst.managed); 8077c478bd9Sstevel@tonic-gate } else { 8087c478bd9Sstevel@tonic-gate /* 8097c478bd9Sstevel@tonic-gate * If we're UNREFERENCED or UNCONFIGURED, 8107c478bd9Sstevel@tonic-gate * then the number of detached pages is 8117c478bd9Sstevel@tonic-gate * however many pages are on the board. 8127c478bd9Sstevel@tonic-gate * I.e. detached = not in use by OS. 8137c478bd9Sstevel@tonic-gate */ 8147c478bd9Sstevel@tonic-gate switch (msp->ms_cm.c_ostate) { 8157c478bd9Sstevel@tonic-gate /* 8167c478bd9Sstevel@tonic-gate * changed to use cfgadm states 8177c478bd9Sstevel@tonic-gate * 8187c478bd9Sstevel@tonic-gate * was: 8197c478bd9Sstevel@tonic-gate * case DR_STATE_UNREFERENCED: 8207c478bd9Sstevel@tonic-gate * case DR_STATE_UNCONFIGURED: 8217c478bd9Sstevel@tonic-gate */ 8227c478bd9Sstevel@tonic-gate case SBD_STAT_UNCONFIGURED: 8237c478bd9Sstevel@tonic-gate msp->ms_detpages = msp->ms_totpages; 8247c478bd9Sstevel@tonic-gate break; 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate default: 8277c478bd9Sstevel@tonic-gate break; 8287c478bd9Sstevel@tonic-gate } 8297c478bd9Sstevel@tonic-gate } 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate /* 8327c478bd9Sstevel@tonic-gate * kphysm_del_span_query can report non-reloc pages = total 8337c478bd9Sstevel@tonic-gate * pages for memory that is not yet configured 8347c478bd9Sstevel@tonic-gate */ 8357c478bd9Sstevel@tonic-gate if (mp->sbm_cm.sbdev_state != DR_STATE_UNCONFIGURED) { 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate rv = kphysm_del_span_query(mp->sbm_basepfn, 8387c478bd9Sstevel@tonic-gate mp->sbm_npages, &mq); 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate if (rv == KPHYSM_OK) { 8417c478bd9Sstevel@tonic-gate msp->ms_managed_pages = mq.managed; 8427c478bd9Sstevel@tonic-gate msp->ms_noreloc_pages = mq.nonrelocatable; 8437c478bd9Sstevel@tonic-gate msp->ms_noreloc_first = 8447c478bd9Sstevel@tonic-gate mq.first_nonrelocatable; 8457c478bd9Sstevel@tonic-gate msp->ms_noreloc_last = 8467c478bd9Sstevel@tonic-gate mq.last_nonrelocatable; 8477c478bd9Sstevel@tonic-gate msp->ms_cm.c_sflags = 0; 8487c478bd9Sstevel@tonic-gate if (mq.nonrelocatable) { 8497c478bd9Sstevel@tonic-gate SBD_SET_SUSPEND(SBD_CMD_UNCONFIGURE, 8507c478bd9Sstevel@tonic-gate msp->ms_cm.c_sflags); 8517c478bd9Sstevel@tonic-gate } 8527c478bd9Sstevel@tonic-gate } else { 8537c478bd9Sstevel@tonic-gate PR_MEM("%s: kphysm_del_span_query() = %d\n", 8547c478bd9Sstevel@tonic-gate f, rv); 8557c478bd9Sstevel@tonic-gate } 8567c478bd9Sstevel@tonic-gate } 8577c478bd9Sstevel@tonic-gate 8587c478bd9Sstevel@tonic-gate /* 8597c478bd9Sstevel@tonic-gate * Check source unit state during copy-rename 8607c478bd9Sstevel@tonic-gate */ 8617c478bd9Sstevel@tonic-gate if ((mp->sbm_flags & DR_MFLAG_SOURCE) && 8627c478bd9Sstevel@tonic-gate (mp->sbm_cm.sbdev_state == DR_STATE_UNREFERENCED || 8637c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_state == DR_STATE_RELEASE)) 8647c478bd9Sstevel@tonic-gate msp->ms_cm.c_ostate = SBD_STAT_CONFIGURED; 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate mix++; 8677c478bd9Sstevel@tonic-gate dsp++; 8687c478bd9Sstevel@tonic-gate } 8697c478bd9Sstevel@tonic-gate 8707c478bd9Sstevel@tonic-gate return (mix); 8717c478bd9Sstevel@tonic-gate } 8727c478bd9Sstevel@tonic-gate 8737c478bd9Sstevel@tonic-gate int 8747c478bd9Sstevel@tonic-gate dr_pre_attach_mem(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) 8757c478bd9Sstevel@tonic-gate { 8767c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(hp)) 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate int err_flag = 0; 8797c478bd9Sstevel@tonic-gate int d; 8807c478bd9Sstevel@tonic-gate sbd_error_t *err; 8817c478bd9Sstevel@tonic-gate static fn_t f = "dr_pre_attach_mem"; 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate PR_MEM("%s...\n", f); 8847c478bd9Sstevel@tonic-gate 8857c478bd9Sstevel@tonic-gate for (d = 0; d < devnum; d++) { 8867c478bd9Sstevel@tonic-gate dr_mem_unit_t *mp = (dr_mem_unit_t *)devlist[d]; 8877c478bd9Sstevel@tonic-gate dr_state_t state; 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "OS configure %s", mp->sbm_cm.sbdev_path); 8907c478bd9Sstevel@tonic-gate 8917c478bd9Sstevel@tonic-gate state = mp->sbm_cm.sbdev_state; 8927c478bd9Sstevel@tonic-gate switch (state) { 8937c478bd9Sstevel@tonic-gate case DR_STATE_UNCONFIGURED: 8947c478bd9Sstevel@tonic-gate PR_MEM("%s: recovering from UNCONFIG for %s\n", 8957c478bd9Sstevel@tonic-gate f, 8967c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_path); 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate /* use memlist cached by dr_post_detach_mem_unit */ 8997c478bd9Sstevel@tonic-gate ASSERT(mp->sbm_mlist != NULL); 9007c478bd9Sstevel@tonic-gate PR_MEM("%s: re-configuring cached memlist for %s:\n", 9017c478bd9Sstevel@tonic-gate f, mp->sbm_cm.sbdev_path); 9027c478bd9Sstevel@tonic-gate PR_MEMLIST_DUMP(mp->sbm_mlist); 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate /* kphysm del handle should be have been freed */ 9057c478bd9Sstevel@tonic-gate ASSERT((mp->sbm_flags & DR_MFLAG_RELOWNER) == 0); 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate case DR_STATE_CONNECTED: 9107c478bd9Sstevel@tonic-gate PR_MEM("%s: reprogramming mem hardware on %s\n", 9117c478bd9Sstevel@tonic-gate f, mp->sbm_cm.sbdev_bp->b_path); 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate PR_MEM("%s: enabling %s\n", 9147c478bd9Sstevel@tonic-gate f, mp->sbm_cm.sbdev_path); 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate err = drmach_mem_enable(mp->sbm_cm.sbdev_id); 9177c478bd9Sstevel@tonic-gate if (err) { 9187c478bd9Sstevel@tonic-gate DRERR_SET_C(&mp->sbm_cm.sbdev_error, &err); 9197c478bd9Sstevel@tonic-gate err_flag = 1; 9207c478bd9Sstevel@tonic-gate } 9217c478bd9Sstevel@tonic-gate break; 9227c478bd9Sstevel@tonic-gate 9237c478bd9Sstevel@tonic-gate default: 9247c478bd9Sstevel@tonic-gate dr_dev_err(CE_WARN, &mp->sbm_cm, ESBD_STATE); 9257c478bd9Sstevel@tonic-gate err_flag = 1; 9267c478bd9Sstevel@tonic-gate break; 9277c478bd9Sstevel@tonic-gate } 9287c478bd9Sstevel@tonic-gate 9297c478bd9Sstevel@tonic-gate /* exit for loop if error encountered */ 9307c478bd9Sstevel@tonic-gate if (err_flag) 9317c478bd9Sstevel@tonic-gate break; 9327c478bd9Sstevel@tonic-gate } 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate return (err_flag ? -1 : 0); 9357c478bd9Sstevel@tonic-gate } 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate int 9387c478bd9Sstevel@tonic-gate dr_post_attach_mem(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) 9397c478bd9Sstevel@tonic-gate { 9407c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(hp)) 9417c478bd9Sstevel@tonic-gate 9427c478bd9Sstevel@tonic-gate int d; 9437c478bd9Sstevel@tonic-gate static fn_t f = "dr_post_attach_mem"; 9447c478bd9Sstevel@tonic-gate 9457c478bd9Sstevel@tonic-gate PR_MEM("%s...\n", f); 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate for (d = 0; d < devnum; d++) { 9487c478bd9Sstevel@tonic-gate dr_mem_unit_t *mp = (dr_mem_unit_t *)devlist[d]; 9497c478bd9Sstevel@tonic-gate struct memlist *mlist, *ml; 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate mlist = dr_get_memlist(mp); 9527c478bd9Sstevel@tonic-gate if (mlist == NULL) { 9537c478bd9Sstevel@tonic-gate dr_dev_err(CE_WARN, &mp->sbm_cm, ESBD_MEMFAIL); 9547c478bd9Sstevel@tonic-gate continue; 9557c478bd9Sstevel@tonic-gate } 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate /* 9587c478bd9Sstevel@tonic-gate * Verify the memory really did successfully attach 9597c478bd9Sstevel@tonic-gate * by checking for its existence in phys_install. 9607c478bd9Sstevel@tonic-gate */ 9617c478bd9Sstevel@tonic-gate memlist_read_lock(); 9627c478bd9Sstevel@tonic-gate if (memlist_intersect(phys_install, mlist) == 0) { 9637c478bd9Sstevel@tonic-gate memlist_read_unlock(); 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate DR_DEV_INTERNAL_ERROR(&mp->sbm_cm); 9667c478bd9Sstevel@tonic-gate 9677c478bd9Sstevel@tonic-gate PR_MEM("%s: %s memlist not in phys_install", 9687c478bd9Sstevel@tonic-gate f, mp->sbm_cm.sbdev_path); 9697c478bd9Sstevel@tonic-gate 9707c478bd9Sstevel@tonic-gate memlist_delete(mlist); 9717c478bd9Sstevel@tonic-gate continue; 9727c478bd9Sstevel@tonic-gate } 9737c478bd9Sstevel@tonic-gate memlist_read_unlock(); 9747c478bd9Sstevel@tonic-gate 975*56f33205SJonathan Adams for (ml = mlist; ml != NULL; ml = ml->ml_next) { 9767c478bd9Sstevel@tonic-gate sbd_error_t *err; 9777c478bd9Sstevel@tonic-gate 9787c478bd9Sstevel@tonic-gate err = drmach_mem_add_span( 9797c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_id, 980*56f33205SJonathan Adams ml->ml_address, 981*56f33205SJonathan Adams ml->ml_size); 9827c478bd9Sstevel@tonic-gate if (err) 9837c478bd9Sstevel@tonic-gate DRERR_SET_C(&mp->sbm_cm.sbdev_error, &err); 9847c478bd9Sstevel@tonic-gate } 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate memlist_delete(mlist); 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate /* 9897c478bd9Sstevel@tonic-gate * Destroy cached memlist, if any. 9907c478bd9Sstevel@tonic-gate * There will be a cached memlist in sbm_mlist if 9917c478bd9Sstevel@tonic-gate * this board is being configured directly after 9927c478bd9Sstevel@tonic-gate * an unconfigure. 9937c478bd9Sstevel@tonic-gate * To support this transition, dr_post_detach_mem 9947c478bd9Sstevel@tonic-gate * left a copy of the last known memlist in sbm_mlist. 9957c478bd9Sstevel@tonic-gate * This memlist could differ from any derived from 9967c478bd9Sstevel@tonic-gate * hardware if while this memunit was last configured 9977c478bd9Sstevel@tonic-gate * the system detected and deleted bad pages from 9987c478bd9Sstevel@tonic-gate * phys_install. The location of those bad pages 9997c478bd9Sstevel@tonic-gate * will be reflected in the cached memlist. 10007c478bd9Sstevel@tonic-gate */ 10017c478bd9Sstevel@tonic-gate if (mp->sbm_mlist) { 10027c478bd9Sstevel@tonic-gate memlist_delete(mp->sbm_mlist); 10037c478bd9Sstevel@tonic-gate mp->sbm_mlist = NULL; 10047c478bd9Sstevel@tonic-gate } 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate /* 10077c478bd9Sstevel@tonic-gate * TODO: why is this call to dr_init_mem_unit_data here? 10087c478bd9Sstevel@tonic-gate * this has been done at discovery or connect time, so this is 10097c478bd9Sstevel@tonic-gate * probably redundant and unnecessary. 10107c478bd9Sstevel@tonic-gate */ 10117c478bd9Sstevel@tonic-gate dr_init_mem_unit_data(mp); 10127c478bd9Sstevel@tonic-gate } 10137c478bd9Sstevel@tonic-gate 10147c478bd9Sstevel@tonic-gate return (0); 10157c478bd9Sstevel@tonic-gate } 10167c478bd9Sstevel@tonic-gate 10177c478bd9Sstevel@tonic-gate int 10187c478bd9Sstevel@tonic-gate dr_pre_detach_mem(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) 10197c478bd9Sstevel@tonic-gate { 10207c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(hp)) 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate int d; 10237c478bd9Sstevel@tonic-gate 10247c478bd9Sstevel@tonic-gate for (d = 0; d < devnum; d++) { 10257c478bd9Sstevel@tonic-gate dr_mem_unit_t *mp = (dr_mem_unit_t *)devlist[d]; 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "OS unconfigure %s", mp->sbm_cm.sbdev_path); 10287c478bd9Sstevel@tonic-gate } 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate return (0); 10317c478bd9Sstevel@tonic-gate } 10327c478bd9Sstevel@tonic-gate 10337c478bd9Sstevel@tonic-gate 10347c478bd9Sstevel@tonic-gate int 10357c478bd9Sstevel@tonic-gate dr_post_detach_mem(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) 10367c478bd9Sstevel@tonic-gate { 10377c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(hp)) 10387c478bd9Sstevel@tonic-gate 10397c478bd9Sstevel@tonic-gate int d, rv; 10407c478bd9Sstevel@tonic-gate static fn_t f = "dr_post_detach_mem"; 10417c478bd9Sstevel@tonic-gate 10427c478bd9Sstevel@tonic-gate PR_MEM("%s...\n", f); 10437c478bd9Sstevel@tonic-gate 10447c478bd9Sstevel@tonic-gate rv = 0; 10457c478bd9Sstevel@tonic-gate for (d = 0; d < devnum; d++) { 10467c478bd9Sstevel@tonic-gate dr_mem_unit_t *mp = (dr_mem_unit_t *)devlist[d]; 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate ASSERT(mp->sbm_cm.sbdev_bp == hp->h_bd); 10497c478bd9Sstevel@tonic-gate 10507c478bd9Sstevel@tonic-gate if (dr_post_detach_mem_unit(mp)) 10517c478bd9Sstevel@tonic-gate rv = -1; 10527c478bd9Sstevel@tonic-gate } 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate return (rv); 10557c478bd9Sstevel@tonic-gate } 10567c478bd9Sstevel@tonic-gate 10577c478bd9Sstevel@tonic-gate static void 10587c478bd9Sstevel@tonic-gate dr_add_memory_spans(dr_mem_unit_t *mp, struct memlist *ml) 10597c478bd9Sstevel@tonic-gate { 10607c478bd9Sstevel@tonic-gate static fn_t f = "dr_add_memory_spans"; 10617c478bd9Sstevel@tonic-gate 10627c478bd9Sstevel@tonic-gate PR_MEM("%s...", f); 10637c478bd9Sstevel@tonic-gate PR_MEMLIST_DUMP(ml); 10647c478bd9Sstevel@tonic-gate 10657c478bd9Sstevel@tonic-gate #ifdef DEBUG 10667c478bd9Sstevel@tonic-gate memlist_read_lock(); 10677c478bd9Sstevel@tonic-gate if (memlist_intersect(phys_install, ml)) { 10687c478bd9Sstevel@tonic-gate PR_MEM("%s:WARNING: memlist intersects with phys_install\n", f); 10697c478bd9Sstevel@tonic-gate } 10707c478bd9Sstevel@tonic-gate memlist_read_unlock(); 10717c478bd9Sstevel@tonic-gate #endif 10727c478bd9Sstevel@tonic-gate 1073*56f33205SJonathan Adams for (; ml; ml = ml->ml_next) { 10747c478bd9Sstevel@tonic-gate pfn_t base; 10757c478bd9Sstevel@tonic-gate pgcnt_t npgs; 10767c478bd9Sstevel@tonic-gate int rv; 10777c478bd9Sstevel@tonic-gate sbd_error_t *err; 10787c478bd9Sstevel@tonic-gate 1079*56f33205SJonathan Adams base = _b64top(ml->ml_address); 1080*56f33205SJonathan Adams npgs = _b64top(ml->ml_size); 10817c478bd9Sstevel@tonic-gate 10827c478bd9Sstevel@tonic-gate rv = kphysm_add_memory_dynamic(base, npgs); 10837c478bd9Sstevel@tonic-gate 10847c478bd9Sstevel@tonic-gate err = drmach_mem_add_span( 10857c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_id, 1086*56f33205SJonathan Adams ml->ml_address, 1087*56f33205SJonathan Adams ml->ml_size); 10887c478bd9Sstevel@tonic-gate 10897c478bd9Sstevel@tonic-gate if (err) 10907c478bd9Sstevel@tonic-gate DRERR_SET_C(&mp->sbm_cm.sbdev_error, &err); 10917c478bd9Sstevel@tonic-gate 10927c478bd9Sstevel@tonic-gate if (rv != KPHYSM_OK) { 10937c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s:" 10947c478bd9Sstevel@tonic-gate " unexpected kphysm_add_memory_dynamic" 10957c478bd9Sstevel@tonic-gate " return value %d;" 10967c478bd9Sstevel@tonic-gate " basepfn=0x%lx, npages=%ld\n", 10977c478bd9Sstevel@tonic-gate f, rv, base, npgs); 10987c478bd9Sstevel@tonic-gate 10997c478bd9Sstevel@tonic-gate continue; 11007c478bd9Sstevel@tonic-gate } 11017c478bd9Sstevel@tonic-gate } 11027c478bd9Sstevel@tonic-gate } 11037c478bd9Sstevel@tonic-gate 11047c478bd9Sstevel@tonic-gate static int 11057c478bd9Sstevel@tonic-gate dr_post_detach_mem_unit(dr_mem_unit_t *s_mp) 11067c478bd9Sstevel@tonic-gate { 11077c478bd9Sstevel@tonic-gate uint64_t sz = s_mp->sbm_slice_size; 11087c478bd9Sstevel@tonic-gate uint64_t sm = sz - 1; 11097c478bd9Sstevel@tonic-gate /* old and new below refer to PAs before and after copy-rename */ 11107c478bd9Sstevel@tonic-gate uint64_t s_old_basepa, s_new_basepa; 11117c478bd9Sstevel@tonic-gate uint64_t t_old_basepa, t_new_basepa; 11127c478bd9Sstevel@tonic-gate uint64_t t_new_smallsize = 0; 11137c478bd9Sstevel@tonic-gate dr_mem_unit_t *t_mp, *x_mp; 11147c478bd9Sstevel@tonic-gate struct memlist *ml; 11157c478bd9Sstevel@tonic-gate int rv; 11167c478bd9Sstevel@tonic-gate sbd_error_t *err; 11177c478bd9Sstevel@tonic-gate static fn_t f = "dr_post_detach_mem_unit"; 11187c478bd9Sstevel@tonic-gate 11197c478bd9Sstevel@tonic-gate PR_MEM("%s...\n", f); 11207c478bd9Sstevel@tonic-gate 11217c478bd9Sstevel@tonic-gate /* s_mp->sbm_del_mlist could be NULL, meaning no deleted spans */ 11227c478bd9Sstevel@tonic-gate PR_MEM("%s: %s: deleted memlist (EMPTY maybe okay):\n", 11237c478bd9Sstevel@tonic-gate f, s_mp->sbm_cm.sbdev_path); 11247c478bd9Sstevel@tonic-gate PR_MEMLIST_DUMP(s_mp->sbm_del_mlist); 11257c478bd9Sstevel@tonic-gate 11267c478bd9Sstevel@tonic-gate /* sanity check */ 11277c478bd9Sstevel@tonic-gate ASSERT(s_mp->sbm_del_mlist == NULL || 11287c478bd9Sstevel@tonic-gate (s_mp->sbm_flags & DR_MFLAG_RELDONE) != 0); 11297c478bd9Sstevel@tonic-gate 11307c478bd9Sstevel@tonic-gate if (s_mp->sbm_flags & DR_MFLAG_SOURCE) { 11317c478bd9Sstevel@tonic-gate t_mp = s_mp->sbm_peer; 11327c478bd9Sstevel@tonic-gate ASSERT(t_mp != NULL); 11337c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_flags & DR_MFLAG_TARGET); 11347c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_peer == s_mp); 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_flags & DR_MFLAG_RELDONE); 11377c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_del_mlist); 11387c478bd9Sstevel@tonic-gate 11397c478bd9Sstevel@tonic-gate PR_MEM("%s: target %s: deleted memlist:\n", 11407c478bd9Sstevel@tonic-gate f, t_mp->sbm_cm.sbdev_path); 11417c478bd9Sstevel@tonic-gate PR_MEMLIST_DUMP(t_mp->sbm_del_mlist); 11427c478bd9Sstevel@tonic-gate } else { 11437c478bd9Sstevel@tonic-gate /* this is no target unit */ 11447c478bd9Sstevel@tonic-gate t_mp = NULL; 11457c478bd9Sstevel@tonic-gate } 11467c478bd9Sstevel@tonic-gate 11477c478bd9Sstevel@tonic-gate /* 11487c478bd9Sstevel@tonic-gate * Verify the memory really did successfully detach 11497c478bd9Sstevel@tonic-gate * by checking for its non-existence in phys_install. 11507c478bd9Sstevel@tonic-gate */ 11517c478bd9Sstevel@tonic-gate rv = 0; 11527c478bd9Sstevel@tonic-gate memlist_read_lock(); 11537c478bd9Sstevel@tonic-gate if (s_mp->sbm_flags & DR_MFLAG_RELDONE) { 11547c478bd9Sstevel@tonic-gate x_mp = s_mp; 11557c478bd9Sstevel@tonic-gate rv = memlist_intersect(phys_install, x_mp->sbm_del_mlist); 11567c478bd9Sstevel@tonic-gate } 11577c478bd9Sstevel@tonic-gate if (rv == 0 && t_mp && (t_mp->sbm_flags & DR_MFLAG_RELDONE)) { 11587c478bd9Sstevel@tonic-gate x_mp = t_mp; 11597c478bd9Sstevel@tonic-gate rv = memlist_intersect(phys_install, x_mp->sbm_del_mlist); 11607c478bd9Sstevel@tonic-gate } 11617c478bd9Sstevel@tonic-gate memlist_read_unlock(); 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate if (rv) { 11647c478bd9Sstevel@tonic-gate /* error: memlist still in phys_install */ 11657c478bd9Sstevel@tonic-gate DR_DEV_INTERNAL_ERROR(&x_mp->sbm_cm); 11667c478bd9Sstevel@tonic-gate } 11677c478bd9Sstevel@tonic-gate 11687c478bd9Sstevel@tonic-gate /* 11697c478bd9Sstevel@tonic-gate * clean mem unit state and bail out if an error has been recorded. 11707c478bd9Sstevel@tonic-gate */ 11717c478bd9Sstevel@tonic-gate rv = 0; 11727c478bd9Sstevel@tonic-gate if (s_mp->sbm_cm.sbdev_error) { 11737c478bd9Sstevel@tonic-gate PR_MEM("%s: %s flags=%x", f, 11747c478bd9Sstevel@tonic-gate s_mp->sbm_cm.sbdev_path, s_mp->sbm_flags); 11757c478bd9Sstevel@tonic-gate DR_DEV_CLR_UNREFERENCED(&s_mp->sbm_cm); 11767c478bd9Sstevel@tonic-gate DR_DEV_CLR_RELEASED(&s_mp->sbm_cm); 11777c478bd9Sstevel@tonic-gate dr_device_transition(&s_mp->sbm_cm, DR_STATE_CONFIGURED); 11787c478bd9Sstevel@tonic-gate rv = -1; 11797c478bd9Sstevel@tonic-gate } 11807c478bd9Sstevel@tonic-gate if (t_mp != NULL && t_mp->sbm_cm.sbdev_error != NULL) { 11817c478bd9Sstevel@tonic-gate PR_MEM("%s: %s flags=%x", f, 11827c478bd9Sstevel@tonic-gate s_mp->sbm_cm.sbdev_path, s_mp->sbm_flags); 11837c478bd9Sstevel@tonic-gate DR_DEV_CLR_UNREFERENCED(&t_mp->sbm_cm); 11847c478bd9Sstevel@tonic-gate DR_DEV_CLR_RELEASED(&t_mp->sbm_cm); 11857c478bd9Sstevel@tonic-gate dr_device_transition(&t_mp->sbm_cm, DR_STATE_CONFIGURED); 11867c478bd9Sstevel@tonic-gate rv = -1; 11877c478bd9Sstevel@tonic-gate } 11887c478bd9Sstevel@tonic-gate if (rv) 11897c478bd9Sstevel@tonic-gate goto cleanup; 11907c478bd9Sstevel@tonic-gate 11917c478bd9Sstevel@tonic-gate s_old_basepa = _ptob64(s_mp->sbm_basepfn); 11927c478bd9Sstevel@tonic-gate err = drmach_mem_get_base_physaddr(s_mp->sbm_cm.sbdev_id, 11937c478bd9Sstevel@tonic-gate &s_new_basepa); 11947c478bd9Sstevel@tonic-gate ASSERT(err == NULL); 11957c478bd9Sstevel@tonic-gate 119604580fdfSmathue PR_MEM("%s:s_old_basepa: 0x%lx\n", f, s_old_basepa); 119704580fdfSmathue PR_MEM("%s:s_new_basepa: 0x%lx\n", f, s_new_basepa); 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate if (t_mp != NULL) { 12007c478bd9Sstevel@tonic-gate struct memlist *s_copy_mlist; 12017c478bd9Sstevel@tonic-gate 12027c478bd9Sstevel@tonic-gate t_old_basepa = _ptob64(t_mp->sbm_basepfn); 12037c478bd9Sstevel@tonic-gate err = drmach_mem_get_base_physaddr(t_mp->sbm_cm.sbdev_id, 12047c478bd9Sstevel@tonic-gate &t_new_basepa); 12057c478bd9Sstevel@tonic-gate ASSERT(err == NULL); 12067c478bd9Sstevel@tonic-gate 120704580fdfSmathue PR_MEM("%s:t_old_basepa: 0x%lx\n", f, t_old_basepa); 120804580fdfSmathue PR_MEM("%s:t_new_basepa: 0x%lx\n", f, t_new_basepa); 12097c478bd9Sstevel@tonic-gate 12107c478bd9Sstevel@tonic-gate /* 12117c478bd9Sstevel@tonic-gate * Construct copy list with original source addresses. 12127c478bd9Sstevel@tonic-gate * Used to add back excess target mem. 12137c478bd9Sstevel@tonic-gate */ 12147c478bd9Sstevel@tonic-gate s_copy_mlist = memlist_dup(s_mp->sbm_mlist); 1215*56f33205SJonathan Adams for (ml = s_mp->sbm_del_mlist; ml; ml = ml->ml_next) { 12167c478bd9Sstevel@tonic-gate s_copy_mlist = memlist_del_span(s_copy_mlist, 1217*56f33205SJonathan Adams ml->ml_address, ml->ml_size); 12187c478bd9Sstevel@tonic-gate } 12197c478bd9Sstevel@tonic-gate 12207c478bd9Sstevel@tonic-gate PR_MEM("%s: source copy list:\n:", f); 12217c478bd9Sstevel@tonic-gate PR_MEMLIST_DUMP(s_copy_mlist); 12227c478bd9Sstevel@tonic-gate 12237c478bd9Sstevel@tonic-gate /* 12247c478bd9Sstevel@tonic-gate * We had to swap mem-units, so update 12257c478bd9Sstevel@tonic-gate * memlists accordingly with new base 12267c478bd9Sstevel@tonic-gate * addresses. 12277c478bd9Sstevel@tonic-gate */ 1228*56f33205SJonathan Adams for (ml = t_mp->sbm_mlist; ml; ml = ml->ml_next) { 1229*56f33205SJonathan Adams ml->ml_address -= t_old_basepa; 1230*56f33205SJonathan Adams ml->ml_address += t_new_basepa; 12317c478bd9Sstevel@tonic-gate } 12327c478bd9Sstevel@tonic-gate 12337c478bd9Sstevel@tonic-gate /* 12347c478bd9Sstevel@tonic-gate * There is no need to explicitly rename the target delete 12357c478bd9Sstevel@tonic-gate * memlist, because sbm_del_mlist and sbm_mlist always 12367c478bd9Sstevel@tonic-gate * point to the same memlist for a copy/rename operation. 12377c478bd9Sstevel@tonic-gate */ 12387c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_del_mlist == t_mp->sbm_mlist); 12397c478bd9Sstevel@tonic-gate 12407c478bd9Sstevel@tonic-gate PR_MEM("%s: renamed target memlist and delete memlist:\n", f); 12417c478bd9Sstevel@tonic-gate PR_MEMLIST_DUMP(t_mp->sbm_mlist); 12427c478bd9Sstevel@tonic-gate 1243*56f33205SJonathan Adams for (ml = s_mp->sbm_mlist; ml; ml = ml->ml_next) { 1244*56f33205SJonathan Adams ml->ml_address -= s_old_basepa; 1245*56f33205SJonathan Adams ml->ml_address += s_new_basepa; 12467c478bd9Sstevel@tonic-gate } 12477c478bd9Sstevel@tonic-gate 12487c478bd9Sstevel@tonic-gate PR_MEM("%s: renamed source memlist:\n", f); 12497c478bd9Sstevel@tonic-gate PR_MEMLIST_DUMP(s_mp->sbm_mlist); 12507c478bd9Sstevel@tonic-gate 12517c478bd9Sstevel@tonic-gate /* 12527c478bd9Sstevel@tonic-gate * Keep track of dynamically added segments 12537c478bd9Sstevel@tonic-gate * since they cannot be split if we need to delete 12547c478bd9Sstevel@tonic-gate * excess source memory later for this board. 12557c478bd9Sstevel@tonic-gate */ 12567c478bd9Sstevel@tonic-gate if (t_mp->sbm_dyn_segs) 12577c478bd9Sstevel@tonic-gate memlist_delete(t_mp->sbm_dyn_segs); 12587c478bd9Sstevel@tonic-gate t_mp->sbm_dyn_segs = s_mp->sbm_dyn_segs; 12597c478bd9Sstevel@tonic-gate s_mp->sbm_dyn_segs = NULL; 12607c478bd9Sstevel@tonic-gate 12617c478bd9Sstevel@tonic-gate /* 12627c478bd9Sstevel@tonic-gate * If the target memory range with the new target base PA 12637c478bd9Sstevel@tonic-gate * extends beyond the usable slice, prevent any "target excess" 12647c478bd9Sstevel@tonic-gate * from being added back after this copy/rename and 12657c478bd9Sstevel@tonic-gate * calculate the new smaller size of the target board 12667c478bd9Sstevel@tonic-gate * to be set as part of target cleanup. The base + npages 12677c478bd9Sstevel@tonic-gate * must only include the range of memory up to the end of 12687c478bd9Sstevel@tonic-gate * this slice. This will only be used after a category 4 12697c478bd9Sstevel@tonic-gate * large-to-small target type copy/rename - see comments 12707c478bd9Sstevel@tonic-gate * in dr_select_mem_target. 12717c478bd9Sstevel@tonic-gate */ 12727c478bd9Sstevel@tonic-gate if (((t_new_basepa & sm) + _ptob64(t_mp->sbm_npages)) > sz) { 12737c478bd9Sstevel@tonic-gate t_new_smallsize = sz - (t_new_basepa & sm); 12747c478bd9Sstevel@tonic-gate } 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate if (s_mp->sbm_flags & DR_MFLAG_MEMRESIZE && 12777c478bd9Sstevel@tonic-gate t_new_smallsize == 0) { 12787c478bd9Sstevel@tonic-gate struct memlist *t_excess_mlist; 12797c478bd9Sstevel@tonic-gate 12807c478bd9Sstevel@tonic-gate /* 12817c478bd9Sstevel@tonic-gate * Add back excess target memory. 12827c478bd9Sstevel@tonic-gate * Subtract out the portion of the target memory 12837c478bd9Sstevel@tonic-gate * node that was taken over by the source memory 12847c478bd9Sstevel@tonic-gate * node. 12857c478bd9Sstevel@tonic-gate */ 12867c478bd9Sstevel@tonic-gate t_excess_mlist = memlist_dup(t_mp->sbm_mlist); 1287*56f33205SJonathan Adams for (ml = s_copy_mlist; ml; ml = ml->ml_next) { 12887c478bd9Sstevel@tonic-gate t_excess_mlist = 12897c478bd9Sstevel@tonic-gate memlist_del_span(t_excess_mlist, 1290*56f33205SJonathan Adams ml->ml_address, ml->ml_size); 12917c478bd9Sstevel@tonic-gate } 12927c478bd9Sstevel@tonic-gate 12937c478bd9Sstevel@tonic-gate /* 12947c478bd9Sstevel@tonic-gate * Update dynamically added segs 12957c478bd9Sstevel@tonic-gate */ 1296*56f33205SJonathan Adams for (ml = s_mp->sbm_del_mlist; ml; ml = ml->ml_next) { 12977c478bd9Sstevel@tonic-gate t_mp->sbm_dyn_segs = 12987c478bd9Sstevel@tonic-gate memlist_del_span(t_mp->sbm_dyn_segs, 1299*56f33205SJonathan Adams ml->ml_address, ml->ml_size); 13007c478bd9Sstevel@tonic-gate } 1301*56f33205SJonathan Adams for (ml = t_excess_mlist; ml; ml = ml->ml_next) { 13027c478bd9Sstevel@tonic-gate t_mp->sbm_dyn_segs = 13037c478bd9Sstevel@tonic-gate memlist_cat_span(t_mp->sbm_dyn_segs, 1304*56f33205SJonathan Adams ml->ml_address, ml->ml_size); 13057c478bd9Sstevel@tonic-gate } 13067c478bd9Sstevel@tonic-gate PR_MEM("%s: %s: updated dynamic seg list:\n", 13077c478bd9Sstevel@tonic-gate f, t_mp->sbm_cm.sbdev_path); 13087c478bd9Sstevel@tonic-gate PR_MEMLIST_DUMP(t_mp->sbm_dyn_segs); 13097c478bd9Sstevel@tonic-gate 13107c478bd9Sstevel@tonic-gate PR_MEM("%s: adding back remaining portion" 13117c478bd9Sstevel@tonic-gate " of %s, memlist:\n", 13127c478bd9Sstevel@tonic-gate f, t_mp->sbm_cm.sbdev_path); 13137c478bd9Sstevel@tonic-gate PR_MEMLIST_DUMP(t_excess_mlist); 13147c478bd9Sstevel@tonic-gate 13157c478bd9Sstevel@tonic-gate dr_add_memory_spans(s_mp, t_excess_mlist); 13167c478bd9Sstevel@tonic-gate memlist_delete(t_excess_mlist); 13177c478bd9Sstevel@tonic-gate } 13187c478bd9Sstevel@tonic-gate memlist_delete(s_copy_mlist); 13197c478bd9Sstevel@tonic-gate 13207c478bd9Sstevel@tonic-gate #ifdef DEBUG 13217c478bd9Sstevel@tonic-gate /* 13227c478bd9Sstevel@tonic-gate * Renaming s_mp->sbm_del_mlist is not necessary. This 13237c478bd9Sstevel@tonic-gate * list is not used beyond this point, and in fact, is 13247c478bd9Sstevel@tonic-gate * disposed of at the end of this function. 13257c478bd9Sstevel@tonic-gate */ 1326*56f33205SJonathan Adams for (ml = s_mp->sbm_del_mlist; ml; ml = ml->ml_next) { 1327*56f33205SJonathan Adams ml->ml_address -= s_old_basepa; 1328*56f33205SJonathan Adams ml->ml_address += s_new_basepa; 13297c478bd9Sstevel@tonic-gate } 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate PR_MEM("%s: renamed source delete memlist", f); 13327c478bd9Sstevel@tonic-gate PR_MEMLIST_DUMP(s_mp->sbm_del_mlist); 13337c478bd9Sstevel@tonic-gate #endif 13347c478bd9Sstevel@tonic-gate 13357c478bd9Sstevel@tonic-gate } 13367c478bd9Sstevel@tonic-gate 13377c478bd9Sstevel@tonic-gate if (t_mp != NULL) { 13387c478bd9Sstevel@tonic-gate /* delete target's entire address space */ 1339d3d50737SRafael Vanoni err = drmach_mem_del_span(t_mp->sbm_cm.sbdev_id, 1340d3d50737SRafael Vanoni t_old_basepa & ~ sm, sz); 13417c478bd9Sstevel@tonic-gate if (err) 13427c478bd9Sstevel@tonic-gate DRERR_SET_C(&t_mp->sbm_cm.sbdev_error, &err); 13437c478bd9Sstevel@tonic-gate ASSERT(err == NULL); 13447c478bd9Sstevel@tonic-gate 13457c478bd9Sstevel@tonic-gate /* 13467c478bd9Sstevel@tonic-gate * After the copy/rename, the original address space 13477c478bd9Sstevel@tonic-gate * for the source board (which is now located on the 13487c478bd9Sstevel@tonic-gate * target board) may now have some excess to be deleted. 13497c478bd9Sstevel@tonic-gate * The amount is calculated by masking the slice 13507c478bd9Sstevel@tonic-gate * info and keeping the slice offset from t_new_basepa. 13517c478bd9Sstevel@tonic-gate */ 13527c478bd9Sstevel@tonic-gate err = drmach_mem_del_span(s_mp->sbm_cm.sbdev_id, 13537c478bd9Sstevel@tonic-gate s_old_basepa & ~ sm, t_new_basepa & sm); 13547c478bd9Sstevel@tonic-gate if (err) 13557c478bd9Sstevel@tonic-gate DRERR_SET_C(&s_mp->sbm_cm.sbdev_error, &err); 13567c478bd9Sstevel@tonic-gate ASSERT(err == NULL); 13577c478bd9Sstevel@tonic-gate 13587c478bd9Sstevel@tonic-gate } else { 13597c478bd9Sstevel@tonic-gate /* delete board's entire address space */ 13607c478bd9Sstevel@tonic-gate err = drmach_mem_del_span(s_mp->sbm_cm.sbdev_id, 13617c478bd9Sstevel@tonic-gate s_old_basepa & ~ sm, sz); 13627c478bd9Sstevel@tonic-gate if (err) 13637c478bd9Sstevel@tonic-gate DRERR_SET_C(&s_mp->sbm_cm.sbdev_error, &err); 13647c478bd9Sstevel@tonic-gate ASSERT(err == NULL); 13657c478bd9Sstevel@tonic-gate } 13667c478bd9Sstevel@tonic-gate 13677c478bd9Sstevel@tonic-gate cleanup: 13687c478bd9Sstevel@tonic-gate /* clean up target mem unit */ 13697c478bd9Sstevel@tonic-gate if (t_mp != NULL) { 13707c478bd9Sstevel@tonic-gate memlist_delete(t_mp->sbm_del_mlist); 13717c478bd9Sstevel@tonic-gate /* no need to delete sbm_mlist, it shares sbm_del_mlist */ 13727c478bd9Sstevel@tonic-gate 13737c478bd9Sstevel@tonic-gate t_mp->sbm_del_mlist = NULL; 13747c478bd9Sstevel@tonic-gate t_mp->sbm_mlist = NULL; 13757c478bd9Sstevel@tonic-gate t_mp->sbm_peer = NULL; 13767c478bd9Sstevel@tonic-gate t_mp->sbm_flags = 0; 13777c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_busy = 0; 13787c478bd9Sstevel@tonic-gate dr_init_mem_unit_data(t_mp); 13797c478bd9Sstevel@tonic-gate 13807c478bd9Sstevel@tonic-gate /* reduce target size if new PAs go past end of usable slice */ 13817c478bd9Sstevel@tonic-gate if (t_new_smallsize > 0) { 13827c478bd9Sstevel@tonic-gate t_mp->sbm_npages = _b64top(t_new_smallsize); 138304580fdfSmathue PR_MEM("%s: target new size 0x%lx bytes\n", 13847c478bd9Sstevel@tonic-gate f, t_new_smallsize); 13857c478bd9Sstevel@tonic-gate } 13867c478bd9Sstevel@tonic-gate } 13877c478bd9Sstevel@tonic-gate if (t_mp != NULL && t_mp->sbm_cm.sbdev_error == NULL) { 13887c478bd9Sstevel@tonic-gate /* 13897c478bd9Sstevel@tonic-gate * now that copy/rename has completed, undo this 13907c478bd9Sstevel@tonic-gate * work that was done in dr_release_mem_done. 13917c478bd9Sstevel@tonic-gate */ 13927c478bd9Sstevel@tonic-gate DR_DEV_CLR_UNREFERENCED(&t_mp->sbm_cm); 13937c478bd9Sstevel@tonic-gate DR_DEV_CLR_RELEASED(&t_mp->sbm_cm); 13947c478bd9Sstevel@tonic-gate dr_device_transition(&t_mp->sbm_cm, DR_STATE_CONFIGURED); 13957c478bd9Sstevel@tonic-gate } 13967c478bd9Sstevel@tonic-gate 13977c478bd9Sstevel@tonic-gate /* 13987c478bd9Sstevel@tonic-gate * clean up (source) board's mem unit structure. 13997c478bd9Sstevel@tonic-gate * NOTE: sbm_mlist is retained if no error has been record (in other 14007c478bd9Sstevel@tonic-gate * words, when s_mp->sbm_cm.sbdev_error is NULL). This memlist is 14017c478bd9Sstevel@tonic-gate * referred to elsewhere as the cached memlist. The cached memlist 14027c478bd9Sstevel@tonic-gate * is used to re-attach (configure back in) this memunit from the 14037c478bd9Sstevel@tonic-gate * unconfigured state. The memlist is retained because it may 14047c478bd9Sstevel@tonic-gate * represent bad pages that were detected while the memory was 14057c478bd9Sstevel@tonic-gate * configured into the OS. The OS deletes bad pages from phys_install. 14067c478bd9Sstevel@tonic-gate * Those deletes, if any, will be represented in the cached mlist. 14077c478bd9Sstevel@tonic-gate */ 14087c478bd9Sstevel@tonic-gate if (s_mp->sbm_del_mlist && s_mp->sbm_del_mlist != s_mp->sbm_mlist) 14097c478bd9Sstevel@tonic-gate memlist_delete(s_mp->sbm_del_mlist); 14107c478bd9Sstevel@tonic-gate 14117c478bd9Sstevel@tonic-gate if (s_mp->sbm_cm.sbdev_error && s_mp->sbm_mlist) { 14127c478bd9Sstevel@tonic-gate memlist_delete(s_mp->sbm_mlist); 14137c478bd9Sstevel@tonic-gate s_mp->sbm_mlist = NULL; 14147c478bd9Sstevel@tonic-gate } 14157c478bd9Sstevel@tonic-gate 14167c478bd9Sstevel@tonic-gate if (s_mp->sbm_dyn_segs != NULL && s_mp->sbm_cm.sbdev_error == 0) { 14177c478bd9Sstevel@tonic-gate memlist_delete(s_mp->sbm_dyn_segs); 14187c478bd9Sstevel@tonic-gate s_mp->sbm_dyn_segs = NULL; 14197c478bd9Sstevel@tonic-gate } 14207c478bd9Sstevel@tonic-gate 14217c478bd9Sstevel@tonic-gate s_mp->sbm_del_mlist = NULL; 14227c478bd9Sstevel@tonic-gate s_mp->sbm_peer = NULL; 14237c478bd9Sstevel@tonic-gate s_mp->sbm_flags = 0; 14247c478bd9Sstevel@tonic-gate s_mp->sbm_cm.sbdev_busy = 0; 14257c478bd9Sstevel@tonic-gate dr_init_mem_unit_data(s_mp); 14267c478bd9Sstevel@tonic-gate 14277c478bd9Sstevel@tonic-gate PR_MEM("%s: cached memlist for %s:", f, s_mp->sbm_cm.sbdev_path); 14287c478bd9Sstevel@tonic-gate PR_MEMLIST_DUMP(s_mp->sbm_mlist); 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate return (0); 14317c478bd9Sstevel@tonic-gate } 14327c478bd9Sstevel@tonic-gate 14337c478bd9Sstevel@tonic-gate /* 14347c478bd9Sstevel@tonic-gate * Successful return from this function will have the memory 14357c478bd9Sstevel@tonic-gate * handle in bp->b_dev[..mem-unit...].sbm_memhandle allocated 14367c478bd9Sstevel@tonic-gate * and waiting. This routine's job is to select the memory that 14377c478bd9Sstevel@tonic-gate * actually has to be released (detached) which may not necessarily 14387c478bd9Sstevel@tonic-gate * be the same memory node that came in in devlist[], 14397c478bd9Sstevel@tonic-gate * i.e. a copy-rename is needed. 14407c478bd9Sstevel@tonic-gate */ 14417c478bd9Sstevel@tonic-gate int 14427c478bd9Sstevel@tonic-gate dr_pre_release_mem(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) 14437c478bd9Sstevel@tonic-gate { 14447c478bd9Sstevel@tonic-gate int d; 14457c478bd9Sstevel@tonic-gate int err_flag = 0; 14467c478bd9Sstevel@tonic-gate static fn_t f = "dr_pre_release_mem"; 14477c478bd9Sstevel@tonic-gate 14487c478bd9Sstevel@tonic-gate PR_MEM("%s...\n", f); 14497c478bd9Sstevel@tonic-gate 14507c478bd9Sstevel@tonic-gate for (d = 0; d < devnum; d++) { 14517c478bd9Sstevel@tonic-gate dr_mem_unit_t *mp = (dr_mem_unit_t *)devlist[d]; 14527c478bd9Sstevel@tonic-gate int rv; 14537c478bd9Sstevel@tonic-gate memquery_t mq; 14547c478bd9Sstevel@tonic-gate struct memlist *ml; 14557c478bd9Sstevel@tonic-gate 14567c478bd9Sstevel@tonic-gate if (mp->sbm_cm.sbdev_error) { 14577c478bd9Sstevel@tonic-gate err_flag = 1; 14587c478bd9Sstevel@tonic-gate continue; 14597c478bd9Sstevel@tonic-gate } else if (!kcage_on) { 14607c478bd9Sstevel@tonic-gate dr_dev_err(CE_WARN, &mp->sbm_cm, ESBD_KCAGE_OFF); 14617c478bd9Sstevel@tonic-gate err_flag = 1; 14627c478bd9Sstevel@tonic-gate continue; 14637c478bd9Sstevel@tonic-gate } 14647c478bd9Sstevel@tonic-gate 14657c478bd9Sstevel@tonic-gate if (mp->sbm_flags & DR_MFLAG_RESERVED) { 14667c478bd9Sstevel@tonic-gate /* 14677c478bd9Sstevel@tonic-gate * Board is currently involved in a delete 14687c478bd9Sstevel@tonic-gate * memory operation. Can't detach this guy until 14697c478bd9Sstevel@tonic-gate * that operation completes. 14707c478bd9Sstevel@tonic-gate */ 14717c478bd9Sstevel@tonic-gate dr_dev_err(CE_WARN, &mp->sbm_cm, ESBD_INVAL); 14727c478bd9Sstevel@tonic-gate err_flag = 1; 14737c478bd9Sstevel@tonic-gate break; 14747c478bd9Sstevel@tonic-gate } 14757c478bd9Sstevel@tonic-gate 14767c478bd9Sstevel@tonic-gate /* 14777c478bd9Sstevel@tonic-gate * Check whether the detaching memory requires a 14787c478bd9Sstevel@tonic-gate * copy-rename. 14797c478bd9Sstevel@tonic-gate */ 14807c478bd9Sstevel@tonic-gate ASSERT(mp->sbm_npages != 0); 1481d3d50737SRafael Vanoni rv = kphysm_del_span_query(mp->sbm_basepfn, mp->sbm_npages, 1482d3d50737SRafael Vanoni &mq); 14837c478bd9Sstevel@tonic-gate if (rv != KPHYSM_OK) { 14847c478bd9Sstevel@tonic-gate DR_DEV_INTERNAL_ERROR(&mp->sbm_cm); 14857c478bd9Sstevel@tonic-gate err_flag = 1; 14867c478bd9Sstevel@tonic-gate break; 14877c478bd9Sstevel@tonic-gate } 14887c478bd9Sstevel@tonic-gate 14897c478bd9Sstevel@tonic-gate if (mq.nonrelocatable != 0) { 14907c478bd9Sstevel@tonic-gate if (!(dr_cmd_flags(hp) & 14917c478bd9Sstevel@tonic-gate (SBD_FLAG_FORCE | SBD_FLAG_QUIESCE_OKAY))) { 14927c478bd9Sstevel@tonic-gate /* caller wasn't prompted for a suspend */ 14937c478bd9Sstevel@tonic-gate dr_dev_err(CE_WARN, &mp->sbm_cm, 14947c478bd9Sstevel@tonic-gate ESBD_QUIESCE_REQD); 14957c478bd9Sstevel@tonic-gate err_flag = 1; 14967c478bd9Sstevel@tonic-gate break; 14977c478bd9Sstevel@tonic-gate } 14987c478bd9Sstevel@tonic-gate } 14997c478bd9Sstevel@tonic-gate 15007c478bd9Sstevel@tonic-gate /* flags should be clean at this time */ 15017c478bd9Sstevel@tonic-gate ASSERT(mp->sbm_flags == 0); 15027c478bd9Sstevel@tonic-gate 15037c478bd9Sstevel@tonic-gate ASSERT(mp->sbm_mlist == NULL); /* should be null */ 15047c478bd9Sstevel@tonic-gate ASSERT(mp->sbm_del_mlist == NULL); /* should be null */ 15057c478bd9Sstevel@tonic-gate if (mp->sbm_mlist != NULL) { 15067c478bd9Sstevel@tonic-gate memlist_delete(mp->sbm_mlist); 15077c478bd9Sstevel@tonic-gate mp->sbm_mlist = NULL; 15087c478bd9Sstevel@tonic-gate } 15097c478bd9Sstevel@tonic-gate 15107c478bd9Sstevel@tonic-gate ml = dr_get_memlist(mp); 15117c478bd9Sstevel@tonic-gate if (ml == NULL) { 15127c478bd9Sstevel@tonic-gate err_flag = 1; 15137c478bd9Sstevel@tonic-gate PR_MEM("%s: no memlist found for %s\n", 15147c478bd9Sstevel@tonic-gate f, mp->sbm_cm.sbdev_path); 15157c478bd9Sstevel@tonic-gate continue; 15167c478bd9Sstevel@tonic-gate } 15177c478bd9Sstevel@tonic-gate 15187c478bd9Sstevel@tonic-gate /* allocate a kphysm handle */ 15197c478bd9Sstevel@tonic-gate rv = kphysm_del_gethandle(&mp->sbm_memhandle); 15207c478bd9Sstevel@tonic-gate if (rv != KPHYSM_OK) { 15217c478bd9Sstevel@tonic-gate memlist_delete(ml); 15227c478bd9Sstevel@tonic-gate 15237c478bd9Sstevel@tonic-gate DR_DEV_INTERNAL_ERROR(&mp->sbm_cm); 15247c478bd9Sstevel@tonic-gate err_flag = 1; 15257c478bd9Sstevel@tonic-gate break; 15267c478bd9Sstevel@tonic-gate } 15277c478bd9Sstevel@tonic-gate mp->sbm_flags |= DR_MFLAG_RELOWNER; 15287c478bd9Sstevel@tonic-gate 15297c478bd9Sstevel@tonic-gate if ((mq.nonrelocatable != 0) || 15307c478bd9Sstevel@tonic-gate dr_reserve_mem_spans(&mp->sbm_memhandle, ml)) { 15317c478bd9Sstevel@tonic-gate /* 15327c478bd9Sstevel@tonic-gate * Either the detaching memory node contains 15337c478bd9Sstevel@tonic-gate * non-reloc memory or we failed to reserve the 15347c478bd9Sstevel@tonic-gate * detaching memory node (which did _not_ have 15357c478bd9Sstevel@tonic-gate * any non-reloc memory, i.e. some non-reloc mem 15367c478bd9Sstevel@tonic-gate * got onboard). 15377c478bd9Sstevel@tonic-gate */ 15387c478bd9Sstevel@tonic-gate 15397c478bd9Sstevel@tonic-gate if (dr_select_mem_target(hp, mp, ml)) { 15407c478bd9Sstevel@tonic-gate int rv; 15417c478bd9Sstevel@tonic-gate 15427c478bd9Sstevel@tonic-gate /* 15437c478bd9Sstevel@tonic-gate * We had no luck locating a target 15447c478bd9Sstevel@tonic-gate * memory node to be the recipient of 15457c478bd9Sstevel@tonic-gate * the non-reloc memory on the node 15467c478bd9Sstevel@tonic-gate * we're trying to detach. 15477c478bd9Sstevel@tonic-gate * Clean up be disposing the mem handle 15487c478bd9Sstevel@tonic-gate * and the mem list. 15497c478bd9Sstevel@tonic-gate */ 15507c478bd9Sstevel@tonic-gate rv = kphysm_del_release(mp->sbm_memhandle); 15517c478bd9Sstevel@tonic-gate if (rv != KPHYSM_OK) { 15527c478bd9Sstevel@tonic-gate /* 15537c478bd9Sstevel@tonic-gate * can do nothing but complain 15547c478bd9Sstevel@tonic-gate * and hope helpful for debug 15557c478bd9Sstevel@tonic-gate */ 15567c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s: unexpected" 15577c478bd9Sstevel@tonic-gate " kphysm_del_release return" 15587c478bd9Sstevel@tonic-gate " value %d", 15597c478bd9Sstevel@tonic-gate f, rv); 15607c478bd9Sstevel@tonic-gate } 15617c478bd9Sstevel@tonic-gate mp->sbm_flags &= ~DR_MFLAG_RELOWNER; 15627c478bd9Sstevel@tonic-gate 15637c478bd9Sstevel@tonic-gate memlist_delete(ml); 15647c478bd9Sstevel@tonic-gate 15657c478bd9Sstevel@tonic-gate /* make sure sbm_flags is clean */ 15667c478bd9Sstevel@tonic-gate ASSERT(mp->sbm_flags == 0); 15677c478bd9Sstevel@tonic-gate 1568d3d50737SRafael Vanoni dr_dev_err(CE_WARN, &mp->sbm_cm, 1569d3d50737SRafael Vanoni ESBD_NO_TARGET); 15707c478bd9Sstevel@tonic-gate 15717c478bd9Sstevel@tonic-gate err_flag = 1; 15727c478bd9Sstevel@tonic-gate break; 15737c478bd9Sstevel@tonic-gate } 15747c478bd9Sstevel@tonic-gate 15757c478bd9Sstevel@tonic-gate /* 15767c478bd9Sstevel@tonic-gate * ml is not memlist_delete'd here because 15777c478bd9Sstevel@tonic-gate * it has been assigned to mp->sbm_mlist 15787c478bd9Sstevel@tonic-gate * by dr_select_mem_target. 15797c478bd9Sstevel@tonic-gate */ 15807c478bd9Sstevel@tonic-gate } else { 15817c478bd9Sstevel@tonic-gate /* no target needed to detach this board */ 15827c478bd9Sstevel@tonic-gate mp->sbm_flags |= DR_MFLAG_RESERVED; 15837c478bd9Sstevel@tonic-gate mp->sbm_peer = NULL; 15847c478bd9Sstevel@tonic-gate mp->sbm_del_mlist = ml; 15857c478bd9Sstevel@tonic-gate mp->sbm_mlist = ml; 15867c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_busy = 1; 15877c478bd9Sstevel@tonic-gate } 15887c478bd9Sstevel@tonic-gate #ifdef DEBUG 15897c478bd9Sstevel@tonic-gate ASSERT(mp->sbm_mlist != NULL); 15907c478bd9Sstevel@tonic-gate 15917c478bd9Sstevel@tonic-gate if (mp->sbm_flags & DR_MFLAG_SOURCE) { 15927c478bd9Sstevel@tonic-gate PR_MEM("%s: release of %s requires copy/rename;" 15937c478bd9Sstevel@tonic-gate " selected target board %s\n", 15947c478bd9Sstevel@tonic-gate f, 15957c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_path, 15967c478bd9Sstevel@tonic-gate mp->sbm_peer->sbm_cm.sbdev_path); 15977c478bd9Sstevel@tonic-gate } else { 15987c478bd9Sstevel@tonic-gate PR_MEM("%s: copy/rename not required to release %s\n", 15997c478bd9Sstevel@tonic-gate f, mp->sbm_cm.sbdev_path); 16007c478bd9Sstevel@tonic-gate } 16017c478bd9Sstevel@tonic-gate 16027c478bd9Sstevel@tonic-gate ASSERT(mp->sbm_flags & DR_MFLAG_RELOWNER); 16037c478bd9Sstevel@tonic-gate ASSERT(mp->sbm_flags & DR_MFLAG_RESERVED); 16047c478bd9Sstevel@tonic-gate #endif 16057c478bd9Sstevel@tonic-gate } 16067c478bd9Sstevel@tonic-gate 16077c478bd9Sstevel@tonic-gate return (err_flag ? -1 : 0); 16087c478bd9Sstevel@tonic-gate } 16097c478bd9Sstevel@tonic-gate 16107c478bd9Sstevel@tonic-gate void 16117c478bd9Sstevel@tonic-gate dr_release_mem_done(dr_common_unit_t *cp) 16127c478bd9Sstevel@tonic-gate { 16137c478bd9Sstevel@tonic-gate dr_mem_unit_t *s_mp = (dr_mem_unit_t *)cp; 16147c478bd9Sstevel@tonic-gate dr_mem_unit_t *t_mp, *mp; 16157c478bd9Sstevel@tonic-gate int rv; 16167c478bd9Sstevel@tonic-gate static fn_t f = "dr_release_mem_done"; 16177c478bd9Sstevel@tonic-gate 16187c478bd9Sstevel@tonic-gate /* 16197c478bd9Sstevel@tonic-gate * This unit will be flagged with DR_MFLAG_SOURCE, if it 16207c478bd9Sstevel@tonic-gate * has a target unit. 16217c478bd9Sstevel@tonic-gate */ 16227c478bd9Sstevel@tonic-gate if (s_mp->sbm_flags & DR_MFLAG_SOURCE) { 16237c478bd9Sstevel@tonic-gate t_mp = s_mp->sbm_peer; 16247c478bd9Sstevel@tonic-gate ASSERT(t_mp != NULL); 16257c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_peer == s_mp); 16267c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_flags & DR_MFLAG_TARGET); 16277c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_flags & DR_MFLAG_RESERVED); 16287c478bd9Sstevel@tonic-gate } else { 16297c478bd9Sstevel@tonic-gate /* this is no target unit */ 16307c478bd9Sstevel@tonic-gate t_mp = NULL; 16317c478bd9Sstevel@tonic-gate } 16327c478bd9Sstevel@tonic-gate 16337c478bd9Sstevel@tonic-gate /* free delete handle */ 16347c478bd9Sstevel@tonic-gate ASSERT(s_mp->sbm_flags & DR_MFLAG_RELOWNER); 16357c478bd9Sstevel@tonic-gate ASSERT(s_mp->sbm_flags & DR_MFLAG_RESERVED); 16367c478bd9Sstevel@tonic-gate rv = kphysm_del_release(s_mp->sbm_memhandle); 16377c478bd9Sstevel@tonic-gate if (rv != KPHYSM_OK) { 16387c478bd9Sstevel@tonic-gate /* 16397c478bd9Sstevel@tonic-gate * can do nothing but complain 16407c478bd9Sstevel@tonic-gate * and hope helpful for debug 16417c478bd9Sstevel@tonic-gate */ 16427c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s: unexpected kphysm_del_release" 16437c478bd9Sstevel@tonic-gate " return value %d", f, rv); 16447c478bd9Sstevel@tonic-gate } 16457c478bd9Sstevel@tonic-gate s_mp->sbm_flags &= ~DR_MFLAG_RELOWNER; 16467c478bd9Sstevel@tonic-gate 16477c478bd9Sstevel@tonic-gate /* 16487c478bd9Sstevel@tonic-gate * If an error was encountered during release, clean up 16497c478bd9Sstevel@tonic-gate * the source (and target, if present) unit data. 16507c478bd9Sstevel@tonic-gate */ 16517c478bd9Sstevel@tonic-gate /* XXX Can we know that sbdev_error was encountered during release? */ 16527c478bd9Sstevel@tonic-gate if (s_mp->sbm_cm.sbdev_error != NULL) { 16537c478bd9Sstevel@tonic-gate PR_MEM("%s: %s: error %d noted\n", 16547c478bd9Sstevel@tonic-gate f, 16557c478bd9Sstevel@tonic-gate s_mp->sbm_cm.sbdev_path, 16567c478bd9Sstevel@tonic-gate s_mp->sbm_cm.sbdev_error->e_code); 16577c478bd9Sstevel@tonic-gate 16587c478bd9Sstevel@tonic-gate if (t_mp != NULL) { 16597c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_del_mlist == t_mp->sbm_mlist); 16607c478bd9Sstevel@tonic-gate t_mp->sbm_del_mlist = NULL; 16617c478bd9Sstevel@tonic-gate 16627c478bd9Sstevel@tonic-gate if (t_mp->sbm_mlist != NULL) { 16637c478bd9Sstevel@tonic-gate memlist_delete(t_mp->sbm_mlist); 16647c478bd9Sstevel@tonic-gate t_mp->sbm_mlist = NULL; 16657c478bd9Sstevel@tonic-gate } 16667c478bd9Sstevel@tonic-gate 16677c478bd9Sstevel@tonic-gate t_mp->sbm_peer = NULL; 16687c478bd9Sstevel@tonic-gate t_mp->sbm_flags = 0; 16697c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_busy = 0; 16707c478bd9Sstevel@tonic-gate } 16717c478bd9Sstevel@tonic-gate 16727c478bd9Sstevel@tonic-gate if (s_mp->sbm_del_mlist != s_mp->sbm_mlist) 16737c478bd9Sstevel@tonic-gate memlist_delete(s_mp->sbm_del_mlist); 16747c478bd9Sstevel@tonic-gate s_mp->sbm_del_mlist = NULL; 16757c478bd9Sstevel@tonic-gate 16767c478bd9Sstevel@tonic-gate if (s_mp->sbm_mlist != NULL) { 16777c478bd9Sstevel@tonic-gate memlist_delete(s_mp->sbm_mlist); 16787c478bd9Sstevel@tonic-gate s_mp->sbm_mlist = NULL; 16797c478bd9Sstevel@tonic-gate } 16807c478bd9Sstevel@tonic-gate 16817c478bd9Sstevel@tonic-gate s_mp->sbm_peer = NULL; 16827c478bd9Sstevel@tonic-gate s_mp->sbm_flags = 0; 16837c478bd9Sstevel@tonic-gate s_mp->sbm_cm.sbdev_busy = 0; 16847c478bd9Sstevel@tonic-gate 16857c478bd9Sstevel@tonic-gate /* bail out */ 16867c478bd9Sstevel@tonic-gate return; 16877c478bd9Sstevel@tonic-gate } 16887c478bd9Sstevel@tonic-gate 16897c478bd9Sstevel@tonic-gate DR_DEV_SET_RELEASED(&s_mp->sbm_cm); 16907c478bd9Sstevel@tonic-gate dr_device_transition(&s_mp->sbm_cm, DR_STATE_RELEASE); 16917c478bd9Sstevel@tonic-gate 16927c478bd9Sstevel@tonic-gate if (t_mp != NULL) { 16937c478bd9Sstevel@tonic-gate /* 16947c478bd9Sstevel@tonic-gate * the kphysm delete operation that drained the source 16957c478bd9Sstevel@tonic-gate * board also drained this target board. Since the source 16967c478bd9Sstevel@tonic-gate * board drain is now known to have succeeded, we know this 16977c478bd9Sstevel@tonic-gate * target board is drained too. 16987c478bd9Sstevel@tonic-gate * 16997c478bd9Sstevel@tonic-gate * because DR_DEV_SET_RELEASED and dr_device_transition 17007c478bd9Sstevel@tonic-gate * is done here, the dr_release_dev_done should not 17017c478bd9Sstevel@tonic-gate * fail. 17027c478bd9Sstevel@tonic-gate */ 17037c478bd9Sstevel@tonic-gate DR_DEV_SET_RELEASED(&t_mp->sbm_cm); 17047c478bd9Sstevel@tonic-gate dr_device_transition(&t_mp->sbm_cm, DR_STATE_RELEASE); 17057c478bd9Sstevel@tonic-gate 17067c478bd9Sstevel@tonic-gate /* 17077c478bd9Sstevel@tonic-gate * NOTE: do not transition target's board state, 17087c478bd9Sstevel@tonic-gate * even if the mem-unit was the last configure 17097c478bd9Sstevel@tonic-gate * unit of the board. When copy/rename completes 17107c478bd9Sstevel@tonic-gate * this mem-unit will transitioned back to 17117c478bd9Sstevel@tonic-gate * the configured state. In the meantime, the 17127c478bd9Sstevel@tonic-gate * board's must remain as is. 17137c478bd9Sstevel@tonic-gate */ 17147c478bd9Sstevel@tonic-gate } 17157c478bd9Sstevel@tonic-gate 17167c478bd9Sstevel@tonic-gate /* if board(s) had deleted memory, verify it is gone */ 17177c478bd9Sstevel@tonic-gate rv = 0; 17187c478bd9Sstevel@tonic-gate memlist_read_lock(); 17197c478bd9Sstevel@tonic-gate if (s_mp->sbm_del_mlist != NULL) { 17207c478bd9Sstevel@tonic-gate mp = s_mp; 17217c478bd9Sstevel@tonic-gate rv = memlist_intersect(phys_install, mp->sbm_del_mlist); 17227c478bd9Sstevel@tonic-gate } 17237c478bd9Sstevel@tonic-gate if (rv == 0 && t_mp && t_mp->sbm_del_mlist != NULL) { 17247c478bd9Sstevel@tonic-gate mp = t_mp; 17257c478bd9Sstevel@tonic-gate rv = memlist_intersect(phys_install, mp->sbm_del_mlist); 17267c478bd9Sstevel@tonic-gate } 17277c478bd9Sstevel@tonic-gate memlist_read_unlock(); 17287c478bd9Sstevel@tonic-gate if (rv) { 17297c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s: %smem-unit (%d.%d): " 17307c478bd9Sstevel@tonic-gate "deleted memory still found in phys_install", 17317c478bd9Sstevel@tonic-gate f, 17327c478bd9Sstevel@tonic-gate (mp == t_mp ? "target " : ""), 17337c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_bp->b_num, 17347c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_unum); 17357c478bd9Sstevel@tonic-gate 17367c478bd9Sstevel@tonic-gate DR_DEV_INTERNAL_ERROR(&s_mp->sbm_cm); 17377c478bd9Sstevel@tonic-gate return; 17387c478bd9Sstevel@tonic-gate } 17397c478bd9Sstevel@tonic-gate 17407c478bd9Sstevel@tonic-gate s_mp->sbm_flags |= DR_MFLAG_RELDONE; 17417c478bd9Sstevel@tonic-gate if (t_mp != NULL) 17427c478bd9Sstevel@tonic-gate t_mp->sbm_flags |= DR_MFLAG_RELDONE; 17437c478bd9Sstevel@tonic-gate 17447c478bd9Sstevel@tonic-gate /* this should not fail */ 17457c478bd9Sstevel@tonic-gate if (dr_release_dev_done(&s_mp->sbm_cm) != 0) { 17467c478bd9Sstevel@tonic-gate /* catch this in debug kernels */ 17477c478bd9Sstevel@tonic-gate ASSERT(0); 17487c478bd9Sstevel@tonic-gate return; 17497c478bd9Sstevel@tonic-gate } 17507c478bd9Sstevel@tonic-gate 17517c478bd9Sstevel@tonic-gate PR_MEM("%s: marking %s release DONE\n", 17527c478bd9Sstevel@tonic-gate f, s_mp->sbm_cm.sbdev_path); 17537c478bd9Sstevel@tonic-gate 17547c478bd9Sstevel@tonic-gate s_mp->sbm_cm.sbdev_ostate = SBD_STAT_UNCONFIGURED; 17557c478bd9Sstevel@tonic-gate 17567c478bd9Sstevel@tonic-gate if (t_mp != NULL) { 17577c478bd9Sstevel@tonic-gate /* should not fail */ 17587c478bd9Sstevel@tonic-gate rv = dr_release_dev_done(&t_mp->sbm_cm); 17597c478bd9Sstevel@tonic-gate if (rv != 0) { 17607c478bd9Sstevel@tonic-gate /* catch this in debug kernels */ 17617c478bd9Sstevel@tonic-gate ASSERT(0); 17627c478bd9Sstevel@tonic-gate return; 17637c478bd9Sstevel@tonic-gate } 17647c478bd9Sstevel@tonic-gate 17657c478bd9Sstevel@tonic-gate PR_MEM("%s: marking %s release DONE\n", 17667c478bd9Sstevel@tonic-gate f, t_mp->sbm_cm.sbdev_path); 17677c478bd9Sstevel@tonic-gate 17687c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_ostate = SBD_STAT_UNCONFIGURED; 17697c478bd9Sstevel@tonic-gate } 17707c478bd9Sstevel@tonic-gate } 17717c478bd9Sstevel@tonic-gate 17727c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 17737c478bd9Sstevel@tonic-gate int 17747c478bd9Sstevel@tonic-gate dr_disconnect_mem(dr_mem_unit_t *mp) 17757c478bd9Sstevel@tonic-gate { 17767c478bd9Sstevel@tonic-gate static fn_t f = "dr_disconnect_mem"; 17777c478bd9Sstevel@tonic-gate update_membounds_t umb; 17787c478bd9Sstevel@tonic-gate 17797c478bd9Sstevel@tonic-gate #ifdef DEBUG 17807c478bd9Sstevel@tonic-gate int state = mp->sbm_cm.sbdev_state; 1781d3d50737SRafael Vanoni ASSERT(state == DR_STATE_CONNECTED || state == DR_STATE_UNCONFIGURED); 17827c478bd9Sstevel@tonic-gate #endif 17837c478bd9Sstevel@tonic-gate 17847c478bd9Sstevel@tonic-gate PR_MEM("%s...\n", f); 17857c478bd9Sstevel@tonic-gate 17867c478bd9Sstevel@tonic-gate if (mp->sbm_del_mlist && mp->sbm_del_mlist != mp->sbm_mlist) 17877c478bd9Sstevel@tonic-gate memlist_delete(mp->sbm_del_mlist); 17887c478bd9Sstevel@tonic-gate mp->sbm_del_mlist = NULL; 17897c478bd9Sstevel@tonic-gate 17907c478bd9Sstevel@tonic-gate if (mp->sbm_mlist) { 17917c478bd9Sstevel@tonic-gate memlist_delete(mp->sbm_mlist); 17927c478bd9Sstevel@tonic-gate mp->sbm_mlist = NULL; 17937c478bd9Sstevel@tonic-gate } 17947c478bd9Sstevel@tonic-gate 17957c478bd9Sstevel@tonic-gate /* 17967c478bd9Sstevel@tonic-gate * Remove memory from lgroup 17977c478bd9Sstevel@tonic-gate * For now, only board info is required. 17987c478bd9Sstevel@tonic-gate */ 17997c478bd9Sstevel@tonic-gate umb.u_board = mp->sbm_cm.sbdev_bp->b_num; 18007c478bd9Sstevel@tonic-gate umb.u_base = (uint64_t)-1; 18017c478bd9Sstevel@tonic-gate umb.u_len = (uint64_t)-1; 18027c478bd9Sstevel@tonic-gate 18037c478bd9Sstevel@tonic-gate lgrp_plat_config(LGRP_CONFIG_MEM_DEL, (uintptr_t)&umb); 18047c478bd9Sstevel@tonic-gate 18057c478bd9Sstevel@tonic-gate return (0); 18067c478bd9Sstevel@tonic-gate } 18077c478bd9Sstevel@tonic-gate 18087c478bd9Sstevel@tonic-gate int 18097c478bd9Sstevel@tonic-gate dr_cancel_mem(dr_mem_unit_t *s_mp) 18107c478bd9Sstevel@tonic-gate { 18117c478bd9Sstevel@tonic-gate dr_mem_unit_t *t_mp; 18127c478bd9Sstevel@tonic-gate dr_state_t state; 18137c478bd9Sstevel@tonic-gate static fn_t f = "dr_cancel_mem"; 18147c478bd9Sstevel@tonic-gate 18157c478bd9Sstevel@tonic-gate state = s_mp->sbm_cm.sbdev_state; 18167c478bd9Sstevel@tonic-gate 18177c478bd9Sstevel@tonic-gate if (s_mp->sbm_flags & DR_MFLAG_TARGET) { 18187c478bd9Sstevel@tonic-gate /* must cancel source board, not target board */ 18197c478bd9Sstevel@tonic-gate /* TODO: set error */ 18207c478bd9Sstevel@tonic-gate return (-1); 18217c478bd9Sstevel@tonic-gate } else if (s_mp->sbm_flags & DR_MFLAG_SOURCE) { 18227c478bd9Sstevel@tonic-gate t_mp = s_mp->sbm_peer; 18237c478bd9Sstevel@tonic-gate ASSERT(t_mp != NULL); 18247c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_peer == s_mp); 18257c478bd9Sstevel@tonic-gate 18267c478bd9Sstevel@tonic-gate /* must always match the source board's state */ 18277c478bd9Sstevel@tonic-gate /* TODO: is this assertion correct? */ 18287c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_cm.sbdev_state == state); 18297c478bd9Sstevel@tonic-gate } else { 18307c478bd9Sstevel@tonic-gate /* this is no target unit */ 18317c478bd9Sstevel@tonic-gate t_mp = NULL; 18327c478bd9Sstevel@tonic-gate } 18337c478bd9Sstevel@tonic-gate 18347c478bd9Sstevel@tonic-gate switch (state) { 18357c478bd9Sstevel@tonic-gate case DR_STATE_UNREFERENCED: /* state set by dr_release_dev_done */ 18367c478bd9Sstevel@tonic-gate ASSERT((s_mp->sbm_flags & DR_MFLAG_RELOWNER) == 0); 18377c478bd9Sstevel@tonic-gate 18387c478bd9Sstevel@tonic-gate if (t_mp != NULL && t_mp->sbm_del_mlist != NULL) { 18397c478bd9Sstevel@tonic-gate PR_MEM("%s: undoing target %s memory delete\n", 18407c478bd9Sstevel@tonic-gate f, t_mp->sbm_cm.sbdev_path); 18417c478bd9Sstevel@tonic-gate dr_add_memory_spans(t_mp, t_mp->sbm_del_mlist); 18427c478bd9Sstevel@tonic-gate 18437c478bd9Sstevel@tonic-gate DR_DEV_CLR_UNREFERENCED(&t_mp->sbm_cm); 18447c478bd9Sstevel@tonic-gate } 18457c478bd9Sstevel@tonic-gate 18467c478bd9Sstevel@tonic-gate if (s_mp->sbm_del_mlist != NULL) { 18477c478bd9Sstevel@tonic-gate PR_MEM("%s: undoing %s memory delete\n", 18487c478bd9Sstevel@tonic-gate f, s_mp->sbm_cm.sbdev_path); 18497c478bd9Sstevel@tonic-gate 18507c478bd9Sstevel@tonic-gate dr_add_memory_spans(s_mp, s_mp->sbm_del_mlist); 18517c478bd9Sstevel@tonic-gate } 18527c478bd9Sstevel@tonic-gate 18537c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 18547c478bd9Sstevel@tonic-gate 18557c478bd9Sstevel@tonic-gate /* TODO: should no longer be possible to see the release state here */ 18567c478bd9Sstevel@tonic-gate case DR_STATE_RELEASE: /* state set by dr_release_mem_done */ 18577c478bd9Sstevel@tonic-gate 18587c478bd9Sstevel@tonic-gate ASSERT((s_mp->sbm_flags & DR_MFLAG_RELOWNER) == 0); 18597c478bd9Sstevel@tonic-gate 18607c478bd9Sstevel@tonic-gate if (t_mp != NULL) { 18617c478bd9Sstevel@tonic-gate ASSERT(t_mp->sbm_del_mlist == t_mp->sbm_mlist); 18627c478bd9Sstevel@tonic-gate t_mp->sbm_del_mlist = NULL; 18637c478bd9Sstevel@tonic-gate 18647c478bd9Sstevel@tonic-gate if (t_mp->sbm_mlist != NULL) { 18657c478bd9Sstevel@tonic-gate memlist_delete(t_mp->sbm_mlist); 18667c478bd9Sstevel@tonic-gate t_mp->sbm_mlist = NULL; 18677c478bd9Sstevel@tonic-gate } 18687c478bd9Sstevel@tonic-gate 18697c478bd9Sstevel@tonic-gate t_mp->sbm_peer = NULL; 18707c478bd9Sstevel@tonic-gate t_mp->sbm_flags = 0; 18717c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_busy = 0; 18727c478bd9Sstevel@tonic-gate dr_init_mem_unit_data(t_mp); 18737c478bd9Sstevel@tonic-gate 18747c478bd9Sstevel@tonic-gate DR_DEV_CLR_RELEASED(&t_mp->sbm_cm); 18757c478bd9Sstevel@tonic-gate 1876d3d50737SRafael Vanoni dr_device_transition(&t_mp->sbm_cm, 1877d3d50737SRafael Vanoni DR_STATE_CONFIGURED); 18787c478bd9Sstevel@tonic-gate } 18797c478bd9Sstevel@tonic-gate 18807c478bd9Sstevel@tonic-gate if (s_mp->sbm_del_mlist != s_mp->sbm_mlist) 18817c478bd9Sstevel@tonic-gate memlist_delete(s_mp->sbm_del_mlist); 18827c478bd9Sstevel@tonic-gate s_mp->sbm_del_mlist = NULL; 18837c478bd9Sstevel@tonic-gate 18847c478bd9Sstevel@tonic-gate if (s_mp->sbm_mlist != NULL) { 18857c478bd9Sstevel@tonic-gate memlist_delete(s_mp->sbm_mlist); 18867c478bd9Sstevel@tonic-gate s_mp->sbm_mlist = NULL; 18877c478bd9Sstevel@tonic-gate } 18887c478bd9Sstevel@tonic-gate 18897c478bd9Sstevel@tonic-gate s_mp->sbm_peer = NULL; 18907c478bd9Sstevel@tonic-gate s_mp->sbm_flags = 0; 18917c478bd9Sstevel@tonic-gate s_mp->sbm_cm.sbdev_busy = 0; 18927c478bd9Sstevel@tonic-gate dr_init_mem_unit_data(s_mp); 18937c478bd9Sstevel@tonic-gate 18947c478bd9Sstevel@tonic-gate return (0); 18957c478bd9Sstevel@tonic-gate 18967c478bd9Sstevel@tonic-gate default: 18977c478bd9Sstevel@tonic-gate PR_MEM("%s: WARNING unexpected state (%d) for %s\n", 18987c478bd9Sstevel@tonic-gate f, (int)state, s_mp->sbm_cm.sbdev_path); 18997c478bd9Sstevel@tonic-gate 19007c478bd9Sstevel@tonic-gate return (-1); 19017c478bd9Sstevel@tonic-gate } 19027c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 19037c478bd9Sstevel@tonic-gate } 19047c478bd9Sstevel@tonic-gate 19057c478bd9Sstevel@tonic-gate void 19067c478bd9Sstevel@tonic-gate dr_init_mem_unit(dr_mem_unit_t *mp) 19077c478bd9Sstevel@tonic-gate { 19087c478bd9Sstevel@tonic-gate dr_state_t new_state; 19097c478bd9Sstevel@tonic-gate 19107c478bd9Sstevel@tonic-gate 19117c478bd9Sstevel@tonic-gate if (DR_DEV_IS_ATTACHED(&mp->sbm_cm)) { 19127c478bd9Sstevel@tonic-gate new_state = DR_STATE_CONFIGURED; 19137c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_cond = SBD_COND_OK; 19147c478bd9Sstevel@tonic-gate } else if (DR_DEV_IS_PRESENT(&mp->sbm_cm)) { 19157c478bd9Sstevel@tonic-gate new_state = DR_STATE_CONNECTED; 19167c478bd9Sstevel@tonic-gate mp->sbm_cm.sbdev_cond = SBD_COND_OK; 19177c478bd9Sstevel@tonic-gate } else if (mp->sbm_cm.sbdev_id != (drmachid_t)0) { 19187c478bd9Sstevel@tonic-gate new_state = DR_STATE_OCCUPIED; 19197c478bd9Sstevel@tonic-gate } else { 19207c478bd9Sstevel@tonic-gate new_state = DR_STATE_EMPTY; 19217c478bd9Sstevel@tonic-gate } 19227c478bd9Sstevel@tonic-gate 19237c478bd9Sstevel@tonic-gate if (DR_DEV_IS_PRESENT(&mp->sbm_cm)) 19247c478bd9Sstevel@tonic-gate dr_init_mem_unit_data(mp); 19257c478bd9Sstevel@tonic-gate 19267c478bd9Sstevel@tonic-gate /* delay transition until fully initialized */ 19277c478bd9Sstevel@tonic-gate dr_device_transition(&mp->sbm_cm, new_state); 19287c478bd9Sstevel@tonic-gate } 19297c478bd9Sstevel@tonic-gate 19307c478bd9Sstevel@tonic-gate static void 19317c478bd9Sstevel@tonic-gate dr_init_mem_unit_data(dr_mem_unit_t *mp) 19327c478bd9Sstevel@tonic-gate { 19337c478bd9Sstevel@tonic-gate drmachid_t id = mp->sbm_cm.sbdev_id; 19347c478bd9Sstevel@tonic-gate uint64_t bytes; 19357c478bd9Sstevel@tonic-gate sbd_error_t *err; 19367c478bd9Sstevel@tonic-gate static fn_t f = "dr_init_mem_unit_data"; 19377c478bd9Sstevel@tonic-gate update_membounds_t umb; 19387c478bd9Sstevel@tonic-gate 19397c478bd9Sstevel@tonic-gate PR_MEM("%s...\n", f); 19407c478bd9Sstevel@tonic-gate 19417c478bd9Sstevel@tonic-gate /* a little sanity checking */ 19427c478bd9Sstevel@tonic-gate ASSERT(mp->sbm_peer == NULL); 19437c478bd9Sstevel@tonic-gate ASSERT(mp->sbm_flags == 0); 19447c478bd9Sstevel@tonic-gate 19457c478bd9Sstevel@tonic-gate /* get basepfn of mem unit */ 19467c478bd9Sstevel@tonic-gate err = drmach_mem_get_base_physaddr(id, &bytes); 19477c478bd9Sstevel@tonic-gate if (err) { 19487c478bd9Sstevel@tonic-gate DRERR_SET_C(&mp->sbm_cm.sbdev_error, &err); 19497c478bd9Sstevel@tonic-gate mp->sbm_basepfn = (pfn_t)-1; 19507c478bd9Sstevel@tonic-gate } else 19517c478bd9Sstevel@tonic-gate mp->sbm_basepfn = _b64top(bytes); 19527c478bd9Sstevel@tonic-gate 19537c478bd9Sstevel@tonic-gate /* attempt to get number of pages from PDA */ 19547c478bd9Sstevel@tonic-gate err = drmach_mem_get_size(id, &bytes); 19557c478bd9Sstevel@tonic-gate if (err) { 19567c478bd9Sstevel@tonic-gate DRERR_SET_C(&mp->sbm_cm.sbdev_error, &err); 19577c478bd9Sstevel@tonic-gate mp->sbm_npages = 0; 19587c478bd9Sstevel@tonic-gate } else 19597c478bd9Sstevel@tonic-gate mp->sbm_npages = _b64top(bytes); 19607c478bd9Sstevel@tonic-gate 19617c478bd9Sstevel@tonic-gate /* if didn't work, calculate using memlist */ 19627c478bd9Sstevel@tonic-gate if (mp->sbm_npages == 0) { 19637c478bd9Sstevel@tonic-gate struct memlist *ml, *mlist; 19647c478bd9Sstevel@tonic-gate /* 19657c478bd9Sstevel@tonic-gate * Either we couldn't open the PDA or our 19667c478bd9Sstevel@tonic-gate * PDA has garbage in it. We must have the 19677c478bd9Sstevel@tonic-gate * page count consistent and whatever the 19687c478bd9Sstevel@tonic-gate * OS states has precedence over the PDA 19697c478bd9Sstevel@tonic-gate * so let's check the kernel. 19707c478bd9Sstevel@tonic-gate */ 19717c478bd9Sstevel@tonic-gate /* TODO: curious comment. it suggests pda query should happen if this fails */ 19727c478bd9Sstevel@tonic-gate PR_MEM("%s: PDA query failed for npages." 19737c478bd9Sstevel@tonic-gate " Checking memlist for %s\n", 19747c478bd9Sstevel@tonic-gate f, mp->sbm_cm.sbdev_path); 19757c478bd9Sstevel@tonic-gate 19767c478bd9Sstevel@tonic-gate mlist = dr_get_memlist(mp); 1977*56f33205SJonathan Adams for (ml = mlist; ml; ml = ml->ml_next) 1978*56f33205SJonathan Adams mp->sbm_npages += btop(ml->ml_size); 19797c478bd9Sstevel@tonic-gate memlist_delete(mlist); 19807c478bd9Sstevel@tonic-gate } 19817c478bd9Sstevel@tonic-gate 19827c478bd9Sstevel@tonic-gate err = drmach_mem_get_alignment(id, &bytes); 19837c478bd9Sstevel@tonic-gate if (err) { 19847c478bd9Sstevel@tonic-gate DRERR_SET_C(&mp->sbm_cm.sbdev_error, &err); 19857c478bd9Sstevel@tonic-gate mp->sbm_alignment_mask = 0; 19867c478bd9Sstevel@tonic-gate } else 19877c478bd9Sstevel@tonic-gate mp->sbm_alignment_mask = _b64top(bytes); 19887c478bd9Sstevel@tonic-gate 19897c478bd9Sstevel@tonic-gate err = drmach_mem_get_slice_size(id, &bytes); 19907c478bd9Sstevel@tonic-gate if (err) { 19917c478bd9Sstevel@tonic-gate DRERR_SET_C(&mp->sbm_cm.sbdev_error, &err); 19927c478bd9Sstevel@tonic-gate mp->sbm_slice_size = 0; /* paranoia */ 19937c478bd9Sstevel@tonic-gate } else 19947c478bd9Sstevel@tonic-gate mp->sbm_slice_size = bytes; 19957c478bd9Sstevel@tonic-gate 19967c478bd9Sstevel@tonic-gate /* 19977c478bd9Sstevel@tonic-gate * Add memory to lgroup 19987c478bd9Sstevel@tonic-gate */ 19997c478bd9Sstevel@tonic-gate umb.u_board = mp->sbm_cm.sbdev_bp->b_num; 20007c478bd9Sstevel@tonic-gate umb.u_base = (uint64_t)mp->sbm_basepfn << MMU_PAGESHIFT; 20017c478bd9Sstevel@tonic-gate umb.u_len = (uint64_t)mp->sbm_npages << MMU_PAGESHIFT; 20027c478bd9Sstevel@tonic-gate 20037c478bd9Sstevel@tonic-gate lgrp_plat_config(LGRP_CONFIG_MEM_ADD, (uintptr_t)&umb); 20047c478bd9Sstevel@tonic-gate 200504580fdfSmathue PR_MEM("%s: %s (basepfn = 0x%lx, npgs = %ld)\n", 20067c478bd9Sstevel@tonic-gate f, mp->sbm_cm.sbdev_path, mp->sbm_basepfn, mp->sbm_npages); 20077c478bd9Sstevel@tonic-gate } 20087c478bd9Sstevel@tonic-gate 20097c478bd9Sstevel@tonic-gate static int 20107c478bd9Sstevel@tonic-gate dr_reserve_mem_spans(memhandle_t *mhp, struct memlist *ml) 20117c478bd9Sstevel@tonic-gate { 20127c478bd9Sstevel@tonic-gate int err; 20137c478bd9Sstevel@tonic-gate pfn_t base; 20147c478bd9Sstevel@tonic-gate pgcnt_t npgs; 20157c478bd9Sstevel@tonic-gate struct memlist *mc; 20167c478bd9Sstevel@tonic-gate static fn_t f = "dr_reserve_mem_spans"; 20177c478bd9Sstevel@tonic-gate 20187c478bd9Sstevel@tonic-gate PR_MEM("%s...\n", f); 20197c478bd9Sstevel@tonic-gate 20207c478bd9Sstevel@tonic-gate /* 20217c478bd9Sstevel@tonic-gate * Walk the supplied memlist scheduling each span for removal 20227c478bd9Sstevel@tonic-gate * with kphysm_del_span. It is possible that a span may intersect 20237c478bd9Sstevel@tonic-gate * an area occupied by the cage. 20247c478bd9Sstevel@tonic-gate */ 2025*56f33205SJonathan Adams for (mc = ml; mc != NULL; mc = mc->ml_next) { 2026*56f33205SJonathan Adams base = _b64top(mc->ml_address); 2027*56f33205SJonathan Adams npgs = _b64top(mc->ml_size); 20287c478bd9Sstevel@tonic-gate 20297c478bd9Sstevel@tonic-gate err = kphysm_del_span(*mhp, base, npgs); 20307c478bd9Sstevel@tonic-gate if (err != KPHYSM_OK) { 20317c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s memory reserve failed." 20327c478bd9Sstevel@tonic-gate " unexpected kphysm_del_span return value %d;" 20337c478bd9Sstevel@tonic-gate " basepfn=0x%lx npages=%ld", 20347c478bd9Sstevel@tonic-gate f, err, base, npgs); 20357c478bd9Sstevel@tonic-gate 20367c478bd9Sstevel@tonic-gate return (-1); 20377c478bd9Sstevel@tonic-gate } 20387c478bd9Sstevel@tonic-gate } 20397c478bd9Sstevel@tonic-gate 20407c478bd9Sstevel@tonic-gate return (0); 20417c478bd9Sstevel@tonic-gate } 20427c478bd9Sstevel@tonic-gate 20437c478bd9Sstevel@tonic-gate /* debug counters */ 20447c478bd9Sstevel@tonic-gate int dr_smt_realigned; 20457c478bd9Sstevel@tonic-gate int dr_smt_preference[4]; 20467c478bd9Sstevel@tonic-gate 20477c478bd9Sstevel@tonic-gate #ifdef DEBUG 20487c478bd9Sstevel@tonic-gate uint_t dr_ignore_board; /* if bit[bnum-1] set, board won't be candidate */ 20497c478bd9Sstevel@tonic-gate #endif 20507c478bd9Sstevel@tonic-gate 20517c478bd9Sstevel@tonic-gate /* 20527c478bd9Sstevel@tonic-gate * Find and reserve a copy/rename target board suitable for the 20537c478bd9Sstevel@tonic-gate * given source board. 20547c478bd9Sstevel@tonic-gate * All boards in the system are examined and categorized in relation to 20557c478bd9Sstevel@tonic-gate * their memory size versus the source board's memory size. Order of 20567c478bd9Sstevel@tonic-gate * preference is: 20577c478bd9Sstevel@tonic-gate * 1st: board has same memory size 20587c478bd9Sstevel@tonic-gate * 2nd: board has larger memory size 20597c478bd9Sstevel@tonic-gate * 3rd: board has smaller memory size 20607c478bd9Sstevel@tonic-gate * 4th: board has smaller memory size, available memory will be reduced. 20617c478bd9Sstevel@tonic-gate * Boards in category 3 and 4 will have their MC's reprogrammed to locate the 20627c478bd9Sstevel@tonic-gate * span to which the MC responds to address span that appropriately covers 20637c478bd9Sstevel@tonic-gate * the nonrelocatable span of the source board. 20647c478bd9Sstevel@tonic-gate */ 20657c478bd9Sstevel@tonic-gate static int 20667c478bd9Sstevel@tonic-gate dr_select_mem_target(dr_handle_t *hp, 20677c478bd9Sstevel@tonic-gate dr_mem_unit_t *s_mp, struct memlist *s_ml) 20687c478bd9Sstevel@tonic-gate { 20697c478bd9Sstevel@tonic-gate pgcnt_t sz = _b64top(s_mp->sbm_slice_size); 20707c478bd9Sstevel@tonic-gate pgcnt_t sm = sz - 1; /* mem_slice_mask */ 20717c478bd9Sstevel@tonic-gate pfn_t s_phi, t_phi; 20727c478bd9Sstevel@tonic-gate 20737c478bd9Sstevel@tonic-gate int n_sets = 4; /* same, larger, smaller, clipped */ 20747c478bd9Sstevel@tonic-gate int preference; /* lower value is higher preference */ 20757c478bd9Sstevel@tonic-gate int n_units_per_set; 20767c478bd9Sstevel@tonic-gate int idx; 20777c478bd9Sstevel@tonic-gate dr_mem_unit_t **sets; 20787c478bd9Sstevel@tonic-gate 20797c478bd9Sstevel@tonic-gate int t_bd; 20807c478bd9Sstevel@tonic-gate int t_unit; 20817c478bd9Sstevel@tonic-gate int rv; 20827c478bd9Sstevel@tonic-gate int allow_src_memrange_modify; 20837c478bd9Sstevel@tonic-gate int allow_targ_memrange_modify; 20847c478bd9Sstevel@tonic-gate drmachid_t t_id; 20857c478bd9Sstevel@tonic-gate dr_board_t *s_bp, *t_bp; 20867c478bd9Sstevel@tonic-gate dr_mem_unit_t *t_mp, *c_mp; 20877c478bd9Sstevel@tonic-gate struct memlist *d_ml, *t_ml, *x_ml; 20887c478bd9Sstevel@tonic-gate memquery_t s_mq = {0}; 20897c478bd9Sstevel@tonic-gate static fn_t f = "dr_select_mem_target"; 20907c478bd9Sstevel@tonic-gate 20917c478bd9Sstevel@tonic-gate PR_MEM("%s...\n", f); 20927c478bd9Sstevel@tonic-gate 20937c478bd9Sstevel@tonic-gate ASSERT(s_ml != NULL); 20947c478bd9Sstevel@tonic-gate 20957c478bd9Sstevel@tonic-gate n_units_per_set = MAX_BOARDS * MAX_MEM_UNITS_PER_BOARD; 20967c478bd9Sstevel@tonic-gate sets = GETSTRUCT(dr_mem_unit_t *, n_units_per_set * n_sets); 20977c478bd9Sstevel@tonic-gate 20987c478bd9Sstevel@tonic-gate s_bp = hp->h_bd; 20997c478bd9Sstevel@tonic-gate /* calculate the offset into the slice of the last source board pfn */ 21007c478bd9Sstevel@tonic-gate ASSERT(s_mp->sbm_npages != 0); 21017c478bd9Sstevel@tonic-gate s_phi = (s_mp->sbm_basepfn + s_mp->sbm_npages - 1) & sm; 21027c478bd9Sstevel@tonic-gate 21037c478bd9Sstevel@tonic-gate allow_src_memrange_modify = drmach_allow_memrange_modify(s_bp->b_id); 21047c478bd9Sstevel@tonic-gate 21057c478bd9Sstevel@tonic-gate /* 21067c478bd9Sstevel@tonic-gate * Make one pass through all memory units on all boards 21077c478bd9Sstevel@tonic-gate * and categorize them with respect to the source board. 21087c478bd9Sstevel@tonic-gate */ 21097c478bd9Sstevel@tonic-gate for (t_bd = 0; t_bd < MAX_BOARDS; t_bd++) { 21107c478bd9Sstevel@tonic-gate /* 21117c478bd9Sstevel@tonic-gate * The board structs are a contiguous array 21127c478bd9Sstevel@tonic-gate * so we take advantage of that to find the 21137c478bd9Sstevel@tonic-gate * correct board struct pointer for a given 21147c478bd9Sstevel@tonic-gate * board number. 21157c478bd9Sstevel@tonic-gate */ 21167c478bd9Sstevel@tonic-gate t_bp = dr_lookup_board(t_bd); 21177c478bd9Sstevel@tonic-gate 21187c478bd9Sstevel@tonic-gate /* source board can not be its own target */ 21197c478bd9Sstevel@tonic-gate if (s_bp->b_num == t_bp->b_num) 21207c478bd9Sstevel@tonic-gate continue; 21217c478bd9Sstevel@tonic-gate 21227c478bd9Sstevel@tonic-gate for (t_unit = 0; t_unit < MAX_MEM_UNITS_PER_BOARD; t_unit++) { 21237c478bd9Sstevel@tonic-gate 21247c478bd9Sstevel@tonic-gate t_mp = dr_get_mem_unit(t_bp, t_unit); 21257c478bd9Sstevel@tonic-gate 21267c478bd9Sstevel@tonic-gate /* this memory node must be attached */ 21277c478bd9Sstevel@tonic-gate if (!DR_DEV_IS_ATTACHED(&t_mp->sbm_cm)) 21287c478bd9Sstevel@tonic-gate continue; 21297c478bd9Sstevel@tonic-gate 21307c478bd9Sstevel@tonic-gate /* source unit can not be its own target */ 21317c478bd9Sstevel@tonic-gate if (s_mp == t_mp) { 21327c478bd9Sstevel@tonic-gate /* catch this is debug kernels */ 21337c478bd9Sstevel@tonic-gate ASSERT(0); 21347c478bd9Sstevel@tonic-gate continue; 21357c478bd9Sstevel@tonic-gate } 21367c478bd9Sstevel@tonic-gate 21377c478bd9Sstevel@tonic-gate /* 21387c478bd9Sstevel@tonic-gate * this memory node must not already be reserved 21397c478bd9Sstevel@tonic-gate * by some other memory delete operation. 21407c478bd9Sstevel@tonic-gate */ 21417c478bd9Sstevel@tonic-gate if (t_mp->sbm_flags & DR_MFLAG_RESERVED) 21427c478bd9Sstevel@tonic-gate continue; 21437c478bd9Sstevel@tonic-gate 21447c478bd9Sstevel@tonic-gate /* 21457c478bd9Sstevel@tonic-gate * categorize the memory node 21467c478bd9Sstevel@tonic-gate * If this is a smaller memory node, create a 21477c478bd9Sstevel@tonic-gate * temporary, edited copy of the source board's 21487c478bd9Sstevel@tonic-gate * memlist containing only the span of the non- 21497c478bd9Sstevel@tonic-gate * relocatable pages. 21507c478bd9Sstevel@tonic-gate */ 21517c478bd9Sstevel@tonic-gate t_phi = (t_mp->sbm_basepfn + t_mp->sbm_npages - 1) & sm; 21527c478bd9Sstevel@tonic-gate t_id = t_mp->sbm_cm.sbdev_bp->b_id; 21537c478bd9Sstevel@tonic-gate allow_targ_memrange_modify = 21547c478bd9Sstevel@tonic-gate drmach_allow_memrange_modify(t_id); 21557c478bd9Sstevel@tonic-gate if (t_mp->sbm_npages == s_mp->sbm_npages && 21567c478bd9Sstevel@tonic-gate t_phi == s_phi) { 21577c478bd9Sstevel@tonic-gate preference = 0; 21587c478bd9Sstevel@tonic-gate t_mp->sbm_slice_offset = 0; 21597c478bd9Sstevel@tonic-gate } else if (t_mp->sbm_npages > s_mp->sbm_npages && 21607c478bd9Sstevel@tonic-gate t_phi > s_phi) { 21617c478bd9Sstevel@tonic-gate /* 21627c478bd9Sstevel@tonic-gate * Selecting this target will require modifying 21637c478bd9Sstevel@tonic-gate * the source and/or target physical address 21647c478bd9Sstevel@tonic-gate * ranges. Skip if not supported by platform. 21657c478bd9Sstevel@tonic-gate */ 21667c478bd9Sstevel@tonic-gate if (!allow_src_memrange_modify || 21677c478bd9Sstevel@tonic-gate !allow_targ_memrange_modify) { 21687c478bd9Sstevel@tonic-gate PR_MEM("%s: skip target %s, memory " 21697c478bd9Sstevel@tonic-gate "range relocation not supported " 21707c478bd9Sstevel@tonic-gate "by platform\n", f, 21717c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_path); 21727c478bd9Sstevel@tonic-gate continue; 21737c478bd9Sstevel@tonic-gate } 21747c478bd9Sstevel@tonic-gate preference = 1; 21757c478bd9Sstevel@tonic-gate t_mp->sbm_slice_offset = 0; 21767c478bd9Sstevel@tonic-gate } else { 21777c478bd9Sstevel@tonic-gate pfn_t pfn = 0; 21787c478bd9Sstevel@tonic-gate 21797c478bd9Sstevel@tonic-gate /* 21807c478bd9Sstevel@tonic-gate * Selecting this target will require modifying 21817c478bd9Sstevel@tonic-gate * the source and/or target physical address 21827c478bd9Sstevel@tonic-gate * ranges. Skip if not supported by platform. 21837c478bd9Sstevel@tonic-gate */ 21847c478bd9Sstevel@tonic-gate if (!allow_src_memrange_modify || 21857c478bd9Sstevel@tonic-gate !allow_targ_memrange_modify) { 21867c478bd9Sstevel@tonic-gate PR_MEM("%s: skip target %s, memory " 21877c478bd9Sstevel@tonic-gate "range relocation not supported " 21887c478bd9Sstevel@tonic-gate "by platform\n", f, 21897c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_path); 21907c478bd9Sstevel@tonic-gate continue; 21917c478bd9Sstevel@tonic-gate } 21927c478bd9Sstevel@tonic-gate 21937c478bd9Sstevel@tonic-gate /* 21947c478bd9Sstevel@tonic-gate * Check if its mc can be programmed to relocate 21957c478bd9Sstevel@tonic-gate * the active address range to match the 21967c478bd9Sstevel@tonic-gate * nonrelocatable span of the source board. 21977c478bd9Sstevel@tonic-gate */ 21987c478bd9Sstevel@tonic-gate preference = 2; 21997c478bd9Sstevel@tonic-gate 22007c478bd9Sstevel@tonic-gate if (s_mq.phys_pages == 0) { 22017c478bd9Sstevel@tonic-gate /* 22027c478bd9Sstevel@tonic-gate * find non-relocatable span on 22037c478bd9Sstevel@tonic-gate * source board. 22047c478bd9Sstevel@tonic-gate */ 22057c478bd9Sstevel@tonic-gate rv = kphysm_del_span_query( 22067c478bd9Sstevel@tonic-gate s_mp->sbm_basepfn, 22077c478bd9Sstevel@tonic-gate s_mp->sbm_npages, &s_mq); 22087c478bd9Sstevel@tonic-gate if (rv != KPHYSM_OK) { 22097c478bd9Sstevel@tonic-gate PR_MEM("%s: %s: unexpected" 22107c478bd9Sstevel@tonic-gate " kphysm_del_span_query" 22117c478bd9Sstevel@tonic-gate " return value %d;" 2212d3d50737SRafael Vanoni " basepfn 0x%lx," 2213d3d50737SRafael Vanoni " npages %ld\n", 22147c478bd9Sstevel@tonic-gate f, 22157c478bd9Sstevel@tonic-gate s_mp->sbm_cm.sbdev_path, 22167c478bd9Sstevel@tonic-gate rv, 22177c478bd9Sstevel@tonic-gate s_mp->sbm_basepfn, 22187c478bd9Sstevel@tonic-gate s_mp->sbm_npages); 22197c478bd9Sstevel@tonic-gate 22207c478bd9Sstevel@tonic-gate /* paranoia */ 22217c478bd9Sstevel@tonic-gate s_mq.phys_pages = 0; 22227c478bd9Sstevel@tonic-gate 22237c478bd9Sstevel@tonic-gate continue; 22247c478bd9Sstevel@tonic-gate } 22257c478bd9Sstevel@tonic-gate 22267c478bd9Sstevel@tonic-gate /* more paranoia */ 22277c478bd9Sstevel@tonic-gate ASSERT(s_mq.phys_pages != 0); 22287c478bd9Sstevel@tonic-gate ASSERT(s_mq.nonrelocatable != 0); 22297c478bd9Sstevel@tonic-gate 22307c478bd9Sstevel@tonic-gate /* 22317c478bd9Sstevel@tonic-gate * this should not happen 22327c478bd9Sstevel@tonic-gate * if it does, it simply means that 22337c478bd9Sstevel@tonic-gate * we can not proceed with qualifying 22347c478bd9Sstevel@tonic-gate * this target candidate. 22357c478bd9Sstevel@tonic-gate */ 22367c478bd9Sstevel@tonic-gate if (s_mq.nonrelocatable == 0) 22377c478bd9Sstevel@tonic-gate continue; 22387c478bd9Sstevel@tonic-gate 22397c478bd9Sstevel@tonic-gate PR_MEM("%s: %s: nonrelocatable" 22407c478bd9Sstevel@tonic-gate " span (0x%lx..0x%lx)\n", 22417c478bd9Sstevel@tonic-gate f, 22427c478bd9Sstevel@tonic-gate s_mp->sbm_cm.sbdev_path, 22437c478bd9Sstevel@tonic-gate s_mq.first_nonrelocatable, 22447c478bd9Sstevel@tonic-gate s_mq.last_nonrelocatable); 22457c478bd9Sstevel@tonic-gate } 22467c478bd9Sstevel@tonic-gate 22477c478bd9Sstevel@tonic-gate /* 22487c478bd9Sstevel@tonic-gate * Round down the starting pfn of the 22497c478bd9Sstevel@tonic-gate * nonrelocatable span on the source board 22507c478bd9Sstevel@tonic-gate * to nearest programmable boundary possible 22517c478bd9Sstevel@tonic-gate * with this target candidate. 22527c478bd9Sstevel@tonic-gate */ 22537c478bd9Sstevel@tonic-gate pfn = s_mq.first_nonrelocatable & 22547c478bd9Sstevel@tonic-gate ~t_mp->sbm_alignment_mask; 22557c478bd9Sstevel@tonic-gate 22567c478bd9Sstevel@tonic-gate /* skip candidate if memory is too small */ 22577c478bd9Sstevel@tonic-gate if (pfn + t_mp->sbm_npages < 22587c478bd9Sstevel@tonic-gate s_mq.last_nonrelocatable) 22597c478bd9Sstevel@tonic-gate continue; 22607c478bd9Sstevel@tonic-gate 22617c478bd9Sstevel@tonic-gate /* 22627c478bd9Sstevel@tonic-gate * reprogramming an mc to relocate its 22637c478bd9Sstevel@tonic-gate * active address range means the beginning 22647c478bd9Sstevel@tonic-gate * address to which the DIMMS respond will 22657c478bd9Sstevel@tonic-gate * be somewhere above the slice boundary 22667c478bd9Sstevel@tonic-gate * address. The larger the size of memory 22677c478bd9Sstevel@tonic-gate * on this unit, the more likely part of it 22687c478bd9Sstevel@tonic-gate * will exist beyond the end of the slice. 22697c478bd9Sstevel@tonic-gate * The portion of the memory that does is 22707c478bd9Sstevel@tonic-gate * unavailable to the system until the mc 22717c478bd9Sstevel@tonic-gate * reprogrammed to a more favorable base 22727c478bd9Sstevel@tonic-gate * address. 22737c478bd9Sstevel@tonic-gate * An attempt is made to avoid the loss by 22747c478bd9Sstevel@tonic-gate * recalculating the mc base address relative 22757c478bd9Sstevel@tonic-gate * to the end of the slice. This may produce 22767c478bd9Sstevel@tonic-gate * a more favorable result. If not, we lower 22777c478bd9Sstevel@tonic-gate * the board's preference rating so that it 22787c478bd9Sstevel@tonic-gate * is one the last candidate boards to be 22797c478bd9Sstevel@tonic-gate * considered. 22807c478bd9Sstevel@tonic-gate */ 22817c478bd9Sstevel@tonic-gate if ((pfn + t_mp->sbm_npages) & ~sm) { 22827c478bd9Sstevel@tonic-gate pfn_t p; 22837c478bd9Sstevel@tonic-gate 22847c478bd9Sstevel@tonic-gate ASSERT(sz >= t_mp->sbm_npages); 22857c478bd9Sstevel@tonic-gate 22867c478bd9Sstevel@tonic-gate /* 22877c478bd9Sstevel@tonic-gate * calculate an alternative starting 22887c478bd9Sstevel@tonic-gate * address relative to the end of the 22897c478bd9Sstevel@tonic-gate * slice's address space. 22907c478bd9Sstevel@tonic-gate */ 22917c478bd9Sstevel@tonic-gate p = pfn & ~sm; 22927c478bd9Sstevel@tonic-gate p = p + (sz - t_mp->sbm_npages); 22937c478bd9Sstevel@tonic-gate p = p & ~t_mp->sbm_alignment_mask; 22947c478bd9Sstevel@tonic-gate 22957c478bd9Sstevel@tonic-gate if ((p > s_mq.first_nonrelocatable) || 22967c478bd9Sstevel@tonic-gate (p + t_mp->sbm_npages < 22977c478bd9Sstevel@tonic-gate s_mq.last_nonrelocatable)) { 22987c478bd9Sstevel@tonic-gate 22997c478bd9Sstevel@tonic-gate /* 23007c478bd9Sstevel@tonic-gate * alternative starting addr 23017c478bd9Sstevel@tonic-gate * won't work. Lower preference 23027c478bd9Sstevel@tonic-gate * rating of this board, since 23037c478bd9Sstevel@tonic-gate * some number of pages will 23047c478bd9Sstevel@tonic-gate * unavailable for use. 23057c478bd9Sstevel@tonic-gate */ 23067c478bd9Sstevel@tonic-gate preference = 3; 23077c478bd9Sstevel@tonic-gate } else { 23087c478bd9Sstevel@tonic-gate dr_smt_realigned++; 23097c478bd9Sstevel@tonic-gate pfn = p; 23107c478bd9Sstevel@tonic-gate } 23117c478bd9Sstevel@tonic-gate } 23127c478bd9Sstevel@tonic-gate 23137c478bd9Sstevel@tonic-gate /* 23147c478bd9Sstevel@tonic-gate * translate calculated pfn to an offset 23157c478bd9Sstevel@tonic-gate * relative to the slice boundary. If the 23167c478bd9Sstevel@tonic-gate * candidate board is selected, this offset 23177c478bd9Sstevel@tonic-gate * will be used to calculate the values 23187c478bd9Sstevel@tonic-gate * programmed into the mc. 23197c478bd9Sstevel@tonic-gate */ 23207c478bd9Sstevel@tonic-gate t_mp->sbm_slice_offset = pfn & sm; 23217c478bd9Sstevel@tonic-gate PR_MEM("%s: %s:" 23227c478bd9Sstevel@tonic-gate " proposed mc offset 0x%lx\n", 23237c478bd9Sstevel@tonic-gate f, 23247c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_path, 23257c478bd9Sstevel@tonic-gate t_mp->sbm_slice_offset); 23267c478bd9Sstevel@tonic-gate } 23277c478bd9Sstevel@tonic-gate 23287c478bd9Sstevel@tonic-gate dr_smt_preference[preference]++; 23297c478bd9Sstevel@tonic-gate 23307c478bd9Sstevel@tonic-gate /* calculate index to start of preference set */ 23317c478bd9Sstevel@tonic-gate idx = n_units_per_set * preference; 23327c478bd9Sstevel@tonic-gate /* calculate offset to respective element */ 23337c478bd9Sstevel@tonic-gate idx += t_bd * MAX_MEM_UNITS_PER_BOARD + t_unit; 23347c478bd9Sstevel@tonic-gate 23357c478bd9Sstevel@tonic-gate ASSERT(idx < n_units_per_set * n_sets); 23367c478bd9Sstevel@tonic-gate sets[idx] = t_mp; 23377c478bd9Sstevel@tonic-gate } 23387c478bd9Sstevel@tonic-gate } 23397c478bd9Sstevel@tonic-gate 23407c478bd9Sstevel@tonic-gate /* 23417c478bd9Sstevel@tonic-gate * NOTE: this would be a good place to sort each candidate 23427c478bd9Sstevel@tonic-gate * set in to some desired order, e.g. memory size in ascending 23437c478bd9Sstevel@tonic-gate * order. Without an additional sorting step here, the order 23447c478bd9Sstevel@tonic-gate * within a set is ascending board number order. 23457c478bd9Sstevel@tonic-gate */ 23467c478bd9Sstevel@tonic-gate 23477c478bd9Sstevel@tonic-gate c_mp = NULL; 23487c478bd9Sstevel@tonic-gate x_ml = NULL; 23497c478bd9Sstevel@tonic-gate t_ml = NULL; 23507c478bd9Sstevel@tonic-gate for (idx = 0; idx < n_units_per_set * n_sets; idx++) { 23517c478bd9Sstevel@tonic-gate memquery_t mq; 23527c478bd9Sstevel@tonic-gate 23537c478bd9Sstevel@tonic-gate /* cleanup t_ml after previous pass */ 23547c478bd9Sstevel@tonic-gate if (t_ml != NULL) { 23557c478bd9Sstevel@tonic-gate memlist_delete(t_ml); 23567c478bd9Sstevel@tonic-gate t_ml = NULL; 23577c478bd9Sstevel@tonic-gate } 23587c478bd9Sstevel@tonic-gate 23597c478bd9Sstevel@tonic-gate /* get candidate target board mem unit */ 23607c478bd9Sstevel@tonic-gate t_mp = sets[idx]; 23617c478bd9Sstevel@tonic-gate if (t_mp == NULL) 23627c478bd9Sstevel@tonic-gate continue; 23637c478bd9Sstevel@tonic-gate 23647c478bd9Sstevel@tonic-gate /* get target board memlist */ 23657c478bd9Sstevel@tonic-gate t_ml = dr_get_memlist(t_mp); 23667c478bd9Sstevel@tonic-gate if (t_ml == NULL) { 23677c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s: no memlist for" 23687c478bd9Sstevel@tonic-gate " mem-unit %d, board %d", 23697c478bd9Sstevel@tonic-gate f, 23707c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_bp->b_num, 23717c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_unum); 23727c478bd9Sstevel@tonic-gate 23737c478bd9Sstevel@tonic-gate continue; 23747c478bd9Sstevel@tonic-gate } 23757c478bd9Sstevel@tonic-gate 23767c478bd9Sstevel@tonic-gate /* get appropriate source board memlist */ 23777c478bd9Sstevel@tonic-gate t_phi = (t_mp->sbm_basepfn + t_mp->sbm_npages - 1) & sm; 23787c478bd9Sstevel@tonic-gate if (t_mp->sbm_npages < s_mp->sbm_npages || t_phi < s_phi) { 23797c478bd9Sstevel@tonic-gate spgcnt_t excess; 23807c478bd9Sstevel@tonic-gate 23817c478bd9Sstevel@tonic-gate /* 23827c478bd9Sstevel@tonic-gate * make a copy of the source board memlist 23837c478bd9Sstevel@tonic-gate * then edit it to remove the spans that 23847c478bd9Sstevel@tonic-gate * are outside the calculated span of 23857c478bd9Sstevel@tonic-gate * [pfn..s_mq.last_nonrelocatable]. 23867c478bd9Sstevel@tonic-gate */ 23877c478bd9Sstevel@tonic-gate if (x_ml != NULL) 23887c478bd9Sstevel@tonic-gate memlist_delete(x_ml); 23897c478bd9Sstevel@tonic-gate 23907c478bd9Sstevel@tonic-gate x_ml = memlist_dup(s_ml); 23917c478bd9Sstevel@tonic-gate if (x_ml == NULL) { 23927c478bd9Sstevel@tonic-gate PR_MEM("%s: memlist_dup failed\n", f); 23937c478bd9Sstevel@tonic-gate /* TODO: should abort */ 23947c478bd9Sstevel@tonic-gate continue; 23957c478bd9Sstevel@tonic-gate } 23967c478bd9Sstevel@tonic-gate 23977c478bd9Sstevel@tonic-gate /* trim off lower portion */ 23987c478bd9Sstevel@tonic-gate excess = t_mp->sbm_slice_offset - 23997c478bd9Sstevel@tonic-gate (s_mp->sbm_basepfn & sm); 24007c478bd9Sstevel@tonic-gate 24017c478bd9Sstevel@tonic-gate if (excess > 0) { 24027c478bd9Sstevel@tonic-gate x_ml = memlist_del_span( 24037c478bd9Sstevel@tonic-gate x_ml, 24047c478bd9Sstevel@tonic-gate _ptob64(s_mp->sbm_basepfn), 24057c478bd9Sstevel@tonic-gate _ptob64(excess)); 24067c478bd9Sstevel@tonic-gate } 24077c478bd9Sstevel@tonic-gate ASSERT(x_ml); 24087c478bd9Sstevel@tonic-gate 24097c478bd9Sstevel@tonic-gate /* 24107c478bd9Sstevel@tonic-gate * Since this candidate target board is smaller 24117c478bd9Sstevel@tonic-gate * than the source board, s_mq must have been 24127c478bd9Sstevel@tonic-gate * initialized in previous loop while processing 24137c478bd9Sstevel@tonic-gate * this or some other candidate board. 24147c478bd9Sstevel@tonic-gate * FIXME: this is weak. 24157c478bd9Sstevel@tonic-gate */ 24167c478bd9Sstevel@tonic-gate ASSERT(s_mq.phys_pages != 0); 24177c478bd9Sstevel@tonic-gate 24187c478bd9Sstevel@tonic-gate /* trim off upper portion */ 24197c478bd9Sstevel@tonic-gate excess = (s_mp->sbm_basepfn + s_mp->sbm_npages) 24207c478bd9Sstevel@tonic-gate - (s_mq.last_nonrelocatable + 1); 24217c478bd9Sstevel@tonic-gate if (excess > 0) { 24227c478bd9Sstevel@tonic-gate pfn_t p; 24237c478bd9Sstevel@tonic-gate 24247c478bd9Sstevel@tonic-gate p = s_mq.last_nonrelocatable + 1; 24257c478bd9Sstevel@tonic-gate x_ml = memlist_del_span( 24267c478bd9Sstevel@tonic-gate x_ml, 24277c478bd9Sstevel@tonic-gate _ptob64(p), 24287c478bd9Sstevel@tonic-gate _ptob64(excess)); 24297c478bd9Sstevel@tonic-gate } 24307c478bd9Sstevel@tonic-gate 24317c478bd9Sstevel@tonic-gate PR_MEM("%s: %s: edited source memlist:\n", 24327c478bd9Sstevel@tonic-gate f, s_mp->sbm_cm.sbdev_path); 24337c478bd9Sstevel@tonic-gate PR_MEMLIST_DUMP(x_ml); 24347c478bd9Sstevel@tonic-gate 24357c478bd9Sstevel@tonic-gate #ifdef DEBUG 24367c478bd9Sstevel@tonic-gate /* sanity check memlist */ 24377c478bd9Sstevel@tonic-gate d_ml = x_ml; 2438*56f33205SJonathan Adams while (d_ml->ml_next != NULL) 2439*56f33205SJonathan Adams d_ml = d_ml->ml_next; 24407c478bd9Sstevel@tonic-gate 2441*56f33205SJonathan Adams ASSERT(d_ml->ml_address + d_ml->ml_size == 24427c478bd9Sstevel@tonic-gate _ptob64(s_mq.last_nonrelocatable + 1)); 24437c478bd9Sstevel@tonic-gate #endif 24447c478bd9Sstevel@tonic-gate 24457c478bd9Sstevel@tonic-gate /* 24467c478bd9Sstevel@tonic-gate * x_ml now describes only the portion of the 24477c478bd9Sstevel@tonic-gate * source board that will be moved during the 24487c478bd9Sstevel@tonic-gate * copy/rename operation. 24497c478bd9Sstevel@tonic-gate */ 24507c478bd9Sstevel@tonic-gate d_ml = x_ml; 24517c478bd9Sstevel@tonic-gate } else { 24527c478bd9Sstevel@tonic-gate /* use original memlist; all spans will be moved */ 24537c478bd9Sstevel@tonic-gate d_ml = s_ml; 24547c478bd9Sstevel@tonic-gate } 24557c478bd9Sstevel@tonic-gate 24567c478bd9Sstevel@tonic-gate /* verify target can support source memory spans. */ 24577c478bd9Sstevel@tonic-gate if (memlist_canfit(d_ml, t_ml) == 0) { 24587c478bd9Sstevel@tonic-gate PR_MEM("%s: source memlist won't" 24597c478bd9Sstevel@tonic-gate " fit in target memlist\n", f); 24607c478bd9Sstevel@tonic-gate PR_MEM("%s: source memlist:\n", f); 24617c478bd9Sstevel@tonic-gate PR_MEMLIST_DUMP(d_ml); 24627c478bd9Sstevel@tonic-gate PR_MEM("%s: target memlist:\n", f); 24637c478bd9Sstevel@tonic-gate PR_MEMLIST_DUMP(t_ml); 24647c478bd9Sstevel@tonic-gate 24657c478bd9Sstevel@tonic-gate continue; 24667c478bd9Sstevel@tonic-gate } 24677c478bd9Sstevel@tonic-gate 24687c478bd9Sstevel@tonic-gate /* NOTE: the value of d_ml is not used beyond this point */ 24697c478bd9Sstevel@tonic-gate 24707c478bd9Sstevel@tonic-gate PR_MEM("%s: checking for no-reloc in %s, " 24717c478bd9Sstevel@tonic-gate " basepfn=0x%lx, npages=%ld\n", 24727c478bd9Sstevel@tonic-gate f, 24737c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_path, 24747c478bd9Sstevel@tonic-gate t_mp->sbm_basepfn, 24757c478bd9Sstevel@tonic-gate t_mp->sbm_npages); 24767c478bd9Sstevel@tonic-gate 24777c478bd9Sstevel@tonic-gate rv = kphysm_del_span_query( 24787c478bd9Sstevel@tonic-gate t_mp->sbm_basepfn, t_mp->sbm_npages, &mq); 24797c478bd9Sstevel@tonic-gate if (rv != KPHYSM_OK) { 24807c478bd9Sstevel@tonic-gate PR_MEM("%s: kphysm_del_span_query:" 24817c478bd9Sstevel@tonic-gate " unexpected return value %d\n", f, rv); 24827c478bd9Sstevel@tonic-gate 24837c478bd9Sstevel@tonic-gate continue; 24847c478bd9Sstevel@tonic-gate } 24857c478bd9Sstevel@tonic-gate 24867c478bd9Sstevel@tonic-gate if (mq.nonrelocatable != 0) { 24877c478bd9Sstevel@tonic-gate PR_MEM("%s: candidate %s has" 24887c478bd9Sstevel@tonic-gate " nonrelocatable span [0x%lx..0x%lx]\n", 24897c478bd9Sstevel@tonic-gate f, 24907c478bd9Sstevel@tonic-gate t_mp->sbm_cm.sbdev_path, 24917c478bd9Sstevel@tonic-gate mq.first_nonrelocatable, 24927c478bd9Sstevel@tonic-gate mq.last_nonrelocatable); 24937c478bd9Sstevel@tonic-gate 24947c478bd9Sstevel@tonic-gate continue; 24957c478bd9Sstevel@tonic-gate } 24967c478bd9Sstevel@tonic-gate 24977c478bd9Sstevel@tonic-gate #ifdef DEBUG 24987c478bd9Sstevel@tonic-gate /* 24997c478bd9Sstevel@tonic-gate * This is a debug tool for excluding certain boards 25007c478bd9Sstevel@tonic-gate * from being selected as a target board candidate. 25017c478bd9Sstevel@tonic-gate * dr_ignore_board is only tested by this driver. 25027c478bd9Sstevel@tonic-gate * It must be set with adb, obp, /etc/system or your 25037c478bd9Sstevel@tonic-gate * favorite debugger. 25047c478bd9Sstevel@tonic-gate */ 25057c478bd9Sstevel@tonic-gate if (dr_ignore_board & 25067c478bd9Sstevel@tonic-gate (1 << (t_mp->sbm_cm.sbdev_bp->b_num - 1))) { 25077c478bd9Sstevel@tonic-gate PR_MEM("%s: dr_ignore_board flag set," 25087c478bd9Sstevel@tonic-gate " ignoring %s as candidate\n", 25097c478bd9Sstevel@tonic-gate f, t_mp->sbm_cm.sbdev_path); 25107c478bd9Sstevel@tonic-gate continue; 25117c478bd9Sstevel@tonic-gate } 25127c478bd9Sstevel@tonic-gate #endif 25137c478bd9Sstevel@tonic-gate 25147c478bd9Sstevel@tonic-gate /* 25157c478bd9Sstevel@tonic-gate * Reserve excess source board memory, if any. 25167c478bd9Sstevel@tonic-gate * 25177c478bd9Sstevel@tonic-gate * When the number of pages on the candidate target 25187c478bd9Sstevel@tonic-gate * board is less than the number of pages on the source, 25197c478bd9Sstevel@tonic-gate * then some spans (clearly) of the source board's address 25207c478bd9Sstevel@tonic-gate * space will not be covered by physical memory after the 25217c478bd9Sstevel@tonic-gate * copy/rename completes. The following code block 25227c478bd9Sstevel@tonic-gate * schedules those spans to be deleted. 25237c478bd9Sstevel@tonic-gate */ 25247c478bd9Sstevel@tonic-gate if (t_mp->sbm_npages < s_mp->sbm_npages || t_phi < s_phi) { 25257c478bd9Sstevel@tonic-gate pfn_t pfn; 25267c478bd9Sstevel@tonic-gate uint64_t s_del_pa; 25277c478bd9Sstevel@tonic-gate struct memlist *ml; 25287c478bd9Sstevel@tonic-gate 25297c478bd9Sstevel@tonic-gate d_ml = memlist_dup(s_ml); 25307c478bd9Sstevel@tonic-gate if (d_ml == NULL) { 25317c478bd9Sstevel@tonic-gate PR_MEM("%s: cant dup src brd memlist\n", f); 25327c478bd9Sstevel@tonic-gate /* TODO: should abort */ 25337c478bd9Sstevel@tonic-gate continue; 25347c478bd9Sstevel@tonic-gate } 25357c478bd9Sstevel@tonic-gate 25367c478bd9Sstevel@tonic-gate /* calculate base pfn relative to target board */ 25377c478bd9Sstevel@tonic-gate pfn = s_mp->sbm_basepfn & ~sm; 25387c478bd9Sstevel@tonic-gate pfn += t_mp->sbm_slice_offset; 25397c478bd9Sstevel@tonic-gate 25407c478bd9Sstevel@tonic-gate /* 25417c478bd9Sstevel@tonic-gate * cannot split dynamically added segment 25427c478bd9Sstevel@tonic-gate */ 25437c478bd9Sstevel@tonic-gate s_del_pa = _ptob64(pfn + t_mp->sbm_npages); 25447c478bd9Sstevel@tonic-gate PR_MEM("%s: proposed src delete pa=0x%lx\n", f, 25457c478bd9Sstevel@tonic-gate s_del_pa); 25467c478bd9Sstevel@tonic-gate PR_MEM("%s: checking for split of dyn seg list:\n", f); 25477c478bd9Sstevel@tonic-gate PR_MEMLIST_DUMP(s_mp->sbm_dyn_segs); 2548*56f33205SJonathan Adams for (ml = s_mp->sbm_dyn_segs; ml; ml = ml->ml_next) { 2549*56f33205SJonathan Adams if (s_del_pa > ml->ml_address && 2550*56f33205SJonathan Adams s_del_pa < ml->ml_address + ml->ml_size) { 2551*56f33205SJonathan Adams s_del_pa = ml->ml_address; 25527c478bd9Sstevel@tonic-gate break; 25537c478bd9Sstevel@tonic-gate } 25547c478bd9Sstevel@tonic-gate } 25557c478bd9Sstevel@tonic-gate 25567c478bd9Sstevel@tonic-gate /* remove span that will reside on candidate board */ 25577c478bd9Sstevel@tonic-gate d_ml = memlist_del_span(d_ml, _ptob64(pfn), 25587c478bd9Sstevel@tonic-gate s_del_pa - _ptob64(pfn)); 25597c478bd9Sstevel@tonic-gate 25607c478bd9Sstevel@tonic-gate PR_MEM("%s: %s: reserving src brd memlist:\n", 25617c478bd9Sstevel@tonic-gate f, s_mp->sbm_cm.sbdev_path); 25627c478bd9Sstevel@tonic-gate PR_MEMLIST_DUMP(d_ml); 25637c478bd9Sstevel@tonic-gate 25647c478bd9Sstevel@tonic-gate /* reserve excess spans */ 2565d3d50737SRafael Vanoni if (dr_reserve_mem_spans(&s_mp->sbm_memhandle, d_ml) 2566d3d50737SRafael Vanoni != 0) { 25677c478bd9Sstevel@tonic-gate 25687c478bd9Sstevel@tonic-gate /* likely more non-reloc pages appeared */ 25697c478bd9Sstevel@tonic-gate /* TODO: restart from top? */ 25707c478bd9Sstevel@tonic-gate continue; 25717c478bd9Sstevel@tonic-gate } 25727c478bd9Sstevel@tonic-gate } else { 25737c478bd9Sstevel@tonic-gate /* no excess source board memory */ 25747c478bd9Sstevel@tonic-gate d_ml = NULL; 25757c478bd9Sstevel@tonic-gate } 25767c478bd9Sstevel@tonic-gate 25777c478bd9Sstevel@tonic-gate s_mp->sbm_flags |= DR_MFLAG_RESERVED; 25787c478bd9Sstevel@tonic-gate 25797c478bd9Sstevel@tonic-gate /* 25807c478bd9Sstevel@tonic-gate * reserve all memory on target board. 25817c478bd9Sstevel@tonic-gate * NOTE: source board's memhandle is used. 25827c478bd9Sstevel@tonic-gate * 25837c478bd9Sstevel@tonic-gate * If this succeeds (eq 0), then target selection is 25847c478bd9Sstevel@tonic-gate * complete and all unwanted memory spans, both source and 25857c478bd9Sstevel@tonic-gate * target, have been reserved. Loop is terminated. 25867c478bd9Sstevel@tonic-gate */ 25877c478bd9Sstevel@tonic-gate if (dr_reserve_mem_spans(&s_mp->sbm_memhandle, t_ml) == 0) { 25887c478bd9Sstevel@tonic-gate PR_MEM("%s: %s: target board memory reserved\n", 25897c478bd9Sstevel@tonic-gate f, t_mp->sbm_cm.sbdev_path); 25907c478bd9Sstevel@tonic-gate 25917c478bd9Sstevel@tonic-gate /* a candidate target board is now reserved */ 25927c478bd9Sstevel@tonic-gate t_mp->sbm_flags |= DR_MFLAG_RESERVED; 25937c478bd9Sstevel@tonic-gate c_mp = t_mp; 25947c478bd9Sstevel@tonic-gate 25957c478bd9Sstevel@tonic-gate /* *** EXITING LOOP *** */ 25967c478bd9Sstevel@tonic-gate break; 25977c478bd9Sstevel@tonic-gate } 25987c478bd9Sstevel@tonic-gate 25997c478bd9Sstevel@tonic-gate /* did not successfully reserve the target board. */ 26007c478bd9Sstevel@tonic-gate PR_MEM("%s: could not reserve target %s\n", 26017c478bd9Sstevel@tonic-gate f, t_mp->sbm_cm.sbdev_path); 26027c478bd9Sstevel@tonic-gate 26037c478bd9Sstevel@tonic-gate /* 26047c478bd9Sstevel@tonic-gate * NOTE: an undo of the dr_reserve_mem_span work 26057c478bd9Sstevel@tonic-gate * will happen automatically when the memhandle 26067c478bd9Sstevel@tonic-gate * (s_mp->sbm_memhandle) is kphysm_del_release'd. 26077c478bd9Sstevel@tonic-gate */ 26087c478bd9Sstevel@tonic-gate 26097c478bd9Sstevel@tonic-gate s_mp->sbm_flags &= ~DR_MFLAG_RESERVED; 26107c478bd9Sstevel@tonic-gate } 26117c478bd9Sstevel@tonic-gate 26127c478bd9Sstevel@tonic-gate /* clean up after memlist editing logic */ 26137c478bd9Sstevel@tonic-gate if (x_ml != NULL) 26147c478bd9Sstevel@tonic-gate memlist_delete(x_ml); 26157c478bd9Sstevel@tonic-gate 26167c478bd9Sstevel@tonic-gate FREESTRUCT(sets, dr_mem_unit_t *, n_units_per_set * n_sets); 26177c478bd9Sstevel@tonic-gate 26187c478bd9Sstevel@tonic-gate /* 26197c478bd9Sstevel@tonic-gate * c_mp will be NULL when the entire sets[] array 26207c478bd9Sstevel@tonic-gate * has been searched without reserving a target board. 26217c478bd9Sstevel@tonic-gate */ 26227c478bd9Sstevel@tonic-gate if (c_mp == NULL) { 26237c478bd9Sstevel@tonic-gate PR_MEM("%s: %s: target selection failed.\n", 26247c478bd9Sstevel@tonic-gate f, s_mp->sbm_cm.sbdev_path); 26257c478bd9Sstevel@tonic-gate 26267c478bd9Sstevel@tonic-gate if (t_ml != NULL) 26277c478bd9Sstevel@tonic-gate memlist_delete(t_ml); 26287c478bd9Sstevel@tonic-gate 26297c478bd9Sstevel@tonic-gate return (-1); 26307c478bd9Sstevel@tonic-gate } 26317c478bd9Sstevel@tonic-gate 26327c478bd9Sstevel@tonic-gate PR_MEM("%s: found target %s for source %s\n", 26337c478bd9Sstevel@tonic-gate f, 26347c478bd9Sstevel@tonic-gate c_mp->sbm_cm.sbdev_path, 26357c478bd9Sstevel@tonic-gate s_mp->sbm_cm.sbdev_path); 26367c478bd9Sstevel@tonic-gate 26377c478bd9Sstevel@tonic-gate s_mp->sbm_peer = c_mp; 26387c478bd9Sstevel@tonic-gate s_mp->sbm_flags |= DR_MFLAG_SOURCE; 26397c478bd9Sstevel@tonic-gate s_mp->sbm_del_mlist = d_ml; /* spans to be deleted, if any */ 26407c478bd9Sstevel@tonic-gate s_mp->sbm_mlist = s_ml; 26417c478bd9Sstevel@tonic-gate s_mp->sbm_cm.sbdev_busy = 1; 26427c478bd9Sstevel@tonic-gate 26437c478bd9Sstevel@tonic-gate c_mp->sbm_peer = s_mp; 26447c478bd9Sstevel@tonic-gate c_mp->sbm_flags |= DR_MFLAG_TARGET; 26457c478bd9Sstevel@tonic-gate c_mp->sbm_del_mlist = t_ml; /* spans to be deleted */ 26467c478bd9Sstevel@tonic-gate c_mp->sbm_mlist = t_ml; 26477c478bd9Sstevel@tonic-gate c_mp->sbm_cm.sbdev_busy = 1; 26487c478bd9Sstevel@tonic-gate 26497c478bd9Sstevel@tonic-gate s_mp->sbm_flags &= ~DR_MFLAG_MEMRESIZE; 26507c478bd9Sstevel@tonic-gate if (c_mp->sbm_npages > s_mp->sbm_npages) { 26517c478bd9Sstevel@tonic-gate s_mp->sbm_flags |= DR_MFLAG_MEMUPSIZE; 265204580fdfSmathue PR_MEM("%s: upsize detected (source=%ld < target=%ld)\n", 26537c478bd9Sstevel@tonic-gate f, s_mp->sbm_npages, c_mp->sbm_npages); 26547c478bd9Sstevel@tonic-gate } else if (c_mp->sbm_npages < s_mp->sbm_npages) { 26557c478bd9Sstevel@tonic-gate s_mp->sbm_flags |= DR_MFLAG_MEMDOWNSIZE; 265604580fdfSmathue PR_MEM("%s: downsize detected (source=%ld > target=%ld)\n", 26577c478bd9Sstevel@tonic-gate f, s_mp->sbm_npages, c_mp->sbm_npages); 26587c478bd9Sstevel@tonic-gate } 26597c478bd9Sstevel@tonic-gate 26607c478bd9Sstevel@tonic-gate return (0); 26617c478bd9Sstevel@tonic-gate } 26627c478bd9Sstevel@tonic-gate 26637c478bd9Sstevel@tonic-gate /* 26647c478bd9Sstevel@tonic-gate * Memlist support. 26657c478bd9Sstevel@tonic-gate */ 26667c478bd9Sstevel@tonic-gate 26677c478bd9Sstevel@tonic-gate /* 26687c478bd9Sstevel@tonic-gate * Determine whether the source memlist (s_mlist) will 26697c478bd9Sstevel@tonic-gate * fit into the target memlist (t_mlist) in terms of 26707c478bd9Sstevel@tonic-gate * size and holes (i.e. based on same relative base address). 26717c478bd9Sstevel@tonic-gate */ 26727c478bd9Sstevel@tonic-gate static int 26737c478bd9Sstevel@tonic-gate memlist_canfit(struct memlist *s_mlist, struct memlist *t_mlist) 26747c478bd9Sstevel@tonic-gate { 26757c478bd9Sstevel@tonic-gate int rv = 0; 26767c478bd9Sstevel@tonic-gate uint64_t s_basepa, t_basepa; 26777c478bd9Sstevel@tonic-gate struct memlist *s_ml, *t_ml; 26787c478bd9Sstevel@tonic-gate 26797c478bd9Sstevel@tonic-gate if ((s_mlist == NULL) || (t_mlist == NULL)) 26807c478bd9Sstevel@tonic-gate return (0); 26817c478bd9Sstevel@tonic-gate 26827c478bd9Sstevel@tonic-gate /* 26837c478bd9Sstevel@tonic-gate * Base both memlists on common base address (0). 26847c478bd9Sstevel@tonic-gate */ 2685*56f33205SJonathan Adams s_basepa = s_mlist->ml_address; 2686*56f33205SJonathan Adams t_basepa = t_mlist->ml_address; 26877c478bd9Sstevel@tonic-gate 2688*56f33205SJonathan Adams for (s_ml = s_mlist; s_ml; s_ml = s_ml->ml_next) 2689*56f33205SJonathan Adams s_ml->ml_address -= s_basepa; 26907c478bd9Sstevel@tonic-gate 2691*56f33205SJonathan Adams for (t_ml = t_mlist; t_ml; t_ml = t_ml->ml_next) 2692*56f33205SJonathan Adams t_ml->ml_address -= t_basepa; 26937c478bd9Sstevel@tonic-gate 26947c478bd9Sstevel@tonic-gate s_ml = s_mlist; 2695*56f33205SJonathan Adams for (t_ml = t_mlist; t_ml && s_ml; t_ml = t_ml->ml_next) { 26967c478bd9Sstevel@tonic-gate uint64_t s_start, s_end; 26977c478bd9Sstevel@tonic-gate uint64_t t_start, t_end; 26987c478bd9Sstevel@tonic-gate 2699*56f33205SJonathan Adams t_start = t_ml->ml_address; 2700*56f33205SJonathan Adams t_end = t_start + t_ml->ml_size; 27017c478bd9Sstevel@tonic-gate 2702*56f33205SJonathan Adams for (; s_ml; s_ml = s_ml->ml_next) { 2703*56f33205SJonathan Adams s_start = s_ml->ml_address; 2704*56f33205SJonathan Adams s_end = s_start + s_ml->ml_size; 27057c478bd9Sstevel@tonic-gate 27067c478bd9Sstevel@tonic-gate if ((s_start < t_start) || (s_end > t_end)) 27077c478bd9Sstevel@tonic-gate break; 27087c478bd9Sstevel@tonic-gate } 27097c478bd9Sstevel@tonic-gate } 27107c478bd9Sstevel@tonic-gate /* 27117c478bd9Sstevel@tonic-gate * If we ran out of source memlist chunks that mean 27127c478bd9Sstevel@tonic-gate * we found a home for all of them. 27137c478bd9Sstevel@tonic-gate */ 27147c478bd9Sstevel@tonic-gate if (s_ml == NULL) 27157c478bd9Sstevel@tonic-gate rv = 1; 27167c478bd9Sstevel@tonic-gate 27177c478bd9Sstevel@tonic-gate /* 27187c478bd9Sstevel@tonic-gate * Need to add base addresses back since memlists 27197c478bd9Sstevel@tonic-gate * are probably in use by caller. 27207c478bd9Sstevel@tonic-gate */ 2721*56f33205SJonathan Adams for (s_ml = s_mlist; s_ml; s_ml = s_ml->ml_next) 2722*56f33205SJonathan Adams s_ml->ml_address += s_basepa; 27237c478bd9Sstevel@tonic-gate 2724*56f33205SJonathan Adams for (t_ml = t_mlist; t_ml; t_ml = t_ml->ml_next) 2725*56f33205SJonathan Adams t_ml->ml_address += t_basepa; 27267c478bd9Sstevel@tonic-gate 27277c478bd9Sstevel@tonic-gate return (rv); 27287c478bd9Sstevel@tonic-gate } 2729