10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate #include <sys/debug.h> 300Sstevel@tonic-gate #include <sys/types.h> 310Sstevel@tonic-gate #include <sys/varargs.h> 320Sstevel@tonic-gate #include <sys/errno.h> 330Sstevel@tonic-gate #include <sys/cred.h> 340Sstevel@tonic-gate #include <sys/dditypes.h> 350Sstevel@tonic-gate #include <sys/devops.h> 360Sstevel@tonic-gate #include <sys/modctl.h> 370Sstevel@tonic-gate #include <sys/poll.h> 380Sstevel@tonic-gate #include <sys/conf.h> 390Sstevel@tonic-gate #include <sys/ddi.h> 400Sstevel@tonic-gate #include <sys/sunddi.h> 410Sstevel@tonic-gate #include <sys/sunndi.h> 420Sstevel@tonic-gate #include <sys/ndi_impldefs.h> 430Sstevel@tonic-gate #include <sys/stat.h> 440Sstevel@tonic-gate #include <sys/kmem.h> 450Sstevel@tonic-gate #include <sys/vmem.h> 460Sstevel@tonic-gate #include <sys/processor.h> 470Sstevel@tonic-gate #include <sys/spitregs.h> 480Sstevel@tonic-gate #include <sys/cpuvar.h> 490Sstevel@tonic-gate #include <sys/cpupart.h> 500Sstevel@tonic-gate #include <sys/mem_config.h> 510Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 520Sstevel@tonic-gate #include <sys/systm.h> 530Sstevel@tonic-gate #include <sys/machsystm.h> 540Sstevel@tonic-gate #include <sys/autoconf.h> 550Sstevel@tonic-gate #include <sys/cmn_err.h> 560Sstevel@tonic-gate #include <sys/sysmacros.h> 570Sstevel@tonic-gate #include <sys/x_call.h> 580Sstevel@tonic-gate #include <sys/promif.h> 590Sstevel@tonic-gate #include <sys/prom_plat.h> 600Sstevel@tonic-gate #include <sys/membar.h> 610Sstevel@tonic-gate #include <vm/seg_kmem.h> 620Sstevel@tonic-gate #include <sys/mem_cage.h> 630Sstevel@tonic-gate #include <sys/stack.h> 640Sstevel@tonic-gate #include <sys/archsystm.h> 650Sstevel@tonic-gate #include <vm/hat_sfmmu.h> 660Sstevel@tonic-gate #include <sys/pte.h> 670Sstevel@tonic-gate #include <sys/mmu.h> 680Sstevel@tonic-gate #include <sys/cpu_module.h> 690Sstevel@tonic-gate #include <sys/obpdefs.h> 700Sstevel@tonic-gate #include <sys/note.h> 710Sstevel@tonic-gate 720Sstevel@tonic-gate #include <sys/starfire.h> /* plat_max_... decls */ 730Sstevel@tonic-gate #include <sys/cvc.h> 740Sstevel@tonic-gate #include <sys/cpu_sgnblk_defs.h> 750Sstevel@tonic-gate #include <sys/drmach.h> 760Sstevel@tonic-gate #include <sys/dr_util.h> 770Sstevel@tonic-gate #include <sys/pda.h> 780Sstevel@tonic-gate 790Sstevel@tonic-gate #include <sys/sysevent.h> 800Sstevel@tonic-gate #include <sys/sysevent/dr.h> 810Sstevel@tonic-gate #include <sys/sysevent/eventdefs.h> 820Sstevel@tonic-gate 830Sstevel@tonic-gate 840Sstevel@tonic-gate extern void bcopy32_il(uint64_t, uint64_t); 850Sstevel@tonic-gate extern void flush_ecache_il( 860Sstevel@tonic-gate uint64_t physaddr, int size, int linesz); 870Sstevel@tonic-gate extern uint_t ldphysio_il(uint64_t physaddr); 880Sstevel@tonic-gate extern void stphysio_il(uint64_t physaddr, uint_t value); 890Sstevel@tonic-gate 900Sstevel@tonic-gate extern uint64_t mc_get_mem_alignment(void); 91789Sahrens extern uint64_t mc_get_asr_addr(pnode_t); 92789Sahrens extern uint64_t mc_get_idle_addr(pnode_t); 93789Sahrens extern uint64_t mc_get_alignment_mask(pnode_t); 94789Sahrens extern int mc_read_asr(pnode_t, uint_t *); 95789Sahrens extern int mc_write_asr(pnode_t, uint_t); 960Sstevel@tonic-gate extern uint64_t mc_asr_to_pa(uint_t); 970Sstevel@tonic-gate extern uint_t mc_pa_to_asr(uint_t, uint64_t); 980Sstevel@tonic-gate 990Sstevel@tonic-gate extern int pc_madr_add(int, int, int, int); 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate typedef struct { 1020Sstevel@tonic-gate struct drmach_node *node; 1030Sstevel@tonic-gate void *data; 1040Sstevel@tonic-gate } drmach_node_walk_args_t; 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate typedef struct drmach_node { 1070Sstevel@tonic-gate void *here; 1080Sstevel@tonic-gate 109789Sahrens pnode_t (*get_dnode)(struct drmach_node *node); 1100Sstevel@tonic-gate int (*walk)(struct drmach_node *node, void *data, 1110Sstevel@tonic-gate int (*cb)(drmach_node_walk_args_t *args)); 1120Sstevel@tonic-gate } drmach_node_t; 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate typedef struct { 1150Sstevel@tonic-gate int min_index; 1160Sstevel@tonic-gate int max_index; 1170Sstevel@tonic-gate int arr_sz; 1180Sstevel@tonic-gate drmachid_t *arr; 1190Sstevel@tonic-gate } drmach_array_t; 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate typedef struct { 1220Sstevel@tonic-gate void *isa; 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate sbd_error_t *(*release)(drmachid_t); 1250Sstevel@tonic-gate sbd_error_t *(*status)(drmachid_t, drmach_status_t *); 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate char name[MAXNAMELEN]; 1280Sstevel@tonic-gate } drmach_common_t; 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate typedef struct { 1310Sstevel@tonic-gate drmach_common_t cm; 1320Sstevel@tonic-gate int bnum; 1330Sstevel@tonic-gate int assigned; 1340Sstevel@tonic-gate int powered; 1350Sstevel@tonic-gate int connect_cpuid; 1360Sstevel@tonic-gate int cond; 1370Sstevel@tonic-gate drmach_node_t *tree; 1380Sstevel@tonic-gate drmach_array_t *devices; 1390Sstevel@tonic-gate } drmach_board_t; 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate typedef struct { 1420Sstevel@tonic-gate drmach_common_t cm; 1430Sstevel@tonic-gate drmach_board_t *bp; 1440Sstevel@tonic-gate int unum; 1450Sstevel@tonic-gate int busy; 1460Sstevel@tonic-gate int powered; 1470Sstevel@tonic-gate const char *type; 1480Sstevel@tonic-gate drmach_node_t *node; 1490Sstevel@tonic-gate } drmach_device_t; 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate typedef struct { 1520Sstevel@tonic-gate int flags; 1530Sstevel@tonic-gate drmach_device_t *dp; 1540Sstevel@tonic-gate sbd_error_t *err; 1550Sstevel@tonic-gate dev_info_t *dip; 1560Sstevel@tonic-gate } drmach_config_args_t; 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate typedef struct { 1590Sstevel@tonic-gate uint64_t idle_addr; 1600Sstevel@tonic-gate drmach_device_t *mem; 1610Sstevel@tonic-gate } drmach_mc_idle_script_t; 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate typedef struct { 1640Sstevel@tonic-gate uint64_t masr_addr; 1650Sstevel@tonic-gate uint_t masr; 1660Sstevel@tonic-gate uint_t _filler; 1670Sstevel@tonic-gate } drmach_rename_script_t; 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate typedef struct { 1700Sstevel@tonic-gate void (*run)(void *arg); 1710Sstevel@tonic-gate caddr_t data; 1720Sstevel@tonic-gate pda_handle_t *ph; 1730Sstevel@tonic-gate struct memlist *c_ml; 1740Sstevel@tonic-gate uint64_t s_copybasepa; 1750Sstevel@tonic-gate uint64_t t_copybasepa; 1760Sstevel@tonic-gate drmach_device_t *restless_mc; /* diagnostic output */ 1770Sstevel@tonic-gate } drmach_copy_rename_program_t; 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate typedef enum { 1800Sstevel@tonic-gate DO_IDLE, 1810Sstevel@tonic-gate DO_UNIDLE, 1820Sstevel@tonic-gate DO_PAUSE, 1830Sstevel@tonic-gate DO_UNPAUSE 1840Sstevel@tonic-gate } drmach_iopc_op_t; 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate typedef struct { 1870Sstevel@tonic-gate drmach_board_t *obj; 1880Sstevel@tonic-gate int ndevs; 1890Sstevel@tonic-gate void *a; 1900Sstevel@tonic-gate sbd_error_t *(*found)(void *a, const char *, int, drmachid_t); 1910Sstevel@tonic-gate sbd_error_t *err; 1920Sstevel@tonic-gate } drmach_board_cb_data_t; 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate static caddr_t drmach_shutdown_va; 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate static int drmach_initialized; 1970Sstevel@tonic-gate static drmach_array_t *drmach_boards; 1980Sstevel@tonic-gate 1990Sstevel@tonic-gate static int drmach_cpu_delay = 100; 2000Sstevel@tonic-gate static int drmach_cpu_ntries = 50000; 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate volatile uchar_t *drmach_xt_mb; 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate /* 2050Sstevel@tonic-gate * Do not change the drmach_shutdown_mbox structure without 2060Sstevel@tonic-gate * considering the drmach_shutdown_asm assembly language code. 2070Sstevel@tonic-gate */ 2080Sstevel@tonic-gate struct drmach_shutdown_mbox { 2090Sstevel@tonic-gate uint64_t estack; 2100Sstevel@tonic-gate uint64_t flushaddr; 2110Sstevel@tonic-gate int size; 2120Sstevel@tonic-gate int linesize; 2130Sstevel@tonic-gate uint64_t physaddr; 2140Sstevel@tonic-gate }; 2150Sstevel@tonic-gate struct drmach_shutdown_mbox *drmach_shutdown_asm_mbox; 2160Sstevel@tonic-gate static sbd_error_t *drmach_device_new(drmach_node_t *, 2170Sstevel@tonic-gate drmach_board_t *, drmach_device_t **); 2180Sstevel@tonic-gate static sbd_error_t *drmach_cpu_new(drmach_device_t *); 2190Sstevel@tonic-gate static sbd_error_t *drmach_mem_new(drmach_device_t *); 2200Sstevel@tonic-gate static sbd_error_t *drmach_io_new(drmach_device_t *); 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate extern struct cpu *SIGBCPU; 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate #ifdef DEBUG 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate #define DRMACH_PR if (drmach_debug) printf 2270Sstevel@tonic-gate int drmach_debug = 0; /* set to non-zero to enable debug messages */ 2280Sstevel@tonic-gate #else 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate #define DRMACH_PR _NOTE(CONSTANTCONDITION) if (0) printf 2310Sstevel@tonic-gate #endif /* DEBUG */ 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate #define DRMACH_OBJ(id) ((drmach_common_t *)id) 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate #define DRMACH_IS_BOARD_ID(id) \ 2360Sstevel@tonic-gate ((id != 0) && \ 2370Sstevel@tonic-gate (DRMACH_OBJ(id)->isa == (void *)drmach_board_new)) 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate #define DRMACH_IS_CPU_ID(id) \ 2400Sstevel@tonic-gate ((id != 0) && \ 2410Sstevel@tonic-gate (DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new)) 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate #define DRMACH_IS_MEM_ID(id) \ 2440Sstevel@tonic-gate ((id != 0) && \ 2450Sstevel@tonic-gate (DRMACH_OBJ(id)->isa == (void *)drmach_mem_new)) 2460Sstevel@tonic-gate 2470Sstevel@tonic-gate #define DRMACH_IS_IO_ID(id) \ 2480Sstevel@tonic-gate ((id != 0) && \ 2490Sstevel@tonic-gate (DRMACH_OBJ(id)->isa == (void *)drmach_io_new)) 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate #define DRMACH_IS_DEVICE_ID(id) \ 2520Sstevel@tonic-gate ((id != 0) && \ 2530Sstevel@tonic-gate (DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new || \ 2540Sstevel@tonic-gate DRMACH_OBJ(id)->isa == (void *)drmach_mem_new || \ 2550Sstevel@tonic-gate DRMACH_OBJ(id)->isa == (void *)drmach_io_new)) 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate #define DRMACH_IS_ID(id) \ 2580Sstevel@tonic-gate ((id != 0) && \ 2590Sstevel@tonic-gate (DRMACH_OBJ(id)->isa == (void *)drmach_board_new || \ 2600Sstevel@tonic-gate DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new || \ 2610Sstevel@tonic-gate DRMACH_OBJ(id)->isa == (void *)drmach_mem_new || \ 2620Sstevel@tonic-gate DRMACH_OBJ(id)->isa == (void *)drmach_io_new)) 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate #define DRMACH_CPUID2BNUM(cpuid) \ 2650Sstevel@tonic-gate ((cpuid) / MAX_CPU_UNITS_PER_BOARD) 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate #define DRMACH_INTERNAL_ERROR() \ 2680Sstevel@tonic-gate drerr_new(1, ESTF_INTERNAL, drmach_ie_fmt, __LINE__) 2690Sstevel@tonic-gate static char *drmach_ie_fmt = "drmach.c %d"; 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate static struct { 2720Sstevel@tonic-gate const char *name; 2730Sstevel@tonic-gate const char *type; 2740Sstevel@tonic-gate sbd_error_t *(*new)(drmach_device_t *); 2750Sstevel@tonic-gate } name2type[] = { 2760Sstevel@tonic-gate { "SUNW,UltraSPARC", DRMACH_DEVTYPE_CPU, drmach_cpu_new }, 2770Sstevel@tonic-gate { "mem-unit", DRMACH_DEVTYPE_MEM, drmach_mem_new }, 2780Sstevel@tonic-gate { "pci", DRMACH_DEVTYPE_PCI, drmach_io_new }, 2790Sstevel@tonic-gate { "sbus", DRMACH_DEVTYPE_SBUS, drmach_io_new }, 2800Sstevel@tonic-gate }; 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate /* node types to cleanup when a board is unconfigured */ 2830Sstevel@tonic-gate #define MISC_COUNTER_TIMER_DEVNAME "counter-timer" 2840Sstevel@tonic-gate #define MISC_PERF_COUNTER_DEVNAME "perf-counter" 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate /* utility */ 2870Sstevel@tonic-gate #define MBYTE (1048576ull) 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate /* 2900Sstevel@tonic-gate * This is necessary because the CPU support needs 2910Sstevel@tonic-gate * to call cvc_assign_iocpu. 2920Sstevel@tonic-gate */ 2930Sstevel@tonic-gate #ifndef lint 2940Sstevel@tonic-gate static char _depends_on[] = "drv/cvc"; 2950Sstevel@tonic-gate #endif /* lint */ 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate /* 2980Sstevel@tonic-gate * drmach autoconfiguration data structures and interfaces 2990Sstevel@tonic-gate */ 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate extern struct mod_ops mod_miscops; 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate static struct modlmisc modlmisc = { 3040Sstevel@tonic-gate &mod_miscops, 3050Sstevel@tonic-gate "Sun Enterprise 10000 DR %I%" 3060Sstevel@tonic-gate }; 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate static struct modlinkage modlinkage = { 3090Sstevel@tonic-gate MODREV_1, 3100Sstevel@tonic-gate (void *)&modlmisc, 3110Sstevel@tonic-gate NULL 3120Sstevel@tonic-gate }; 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate static kmutex_t drmach_i_lock; 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate int 3170Sstevel@tonic-gate _init(void) 3180Sstevel@tonic-gate { 3190Sstevel@tonic-gate int err; 3200Sstevel@tonic-gate 3210Sstevel@tonic-gate /* check that we have the correct version of obp */ 3220Sstevel@tonic-gate if (prom_test("SUNW,UE10000,add-brd") != 0) { 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate cmn_err(CE_WARN, "!OBP/SSP upgrade is required to enable " 3250Sstevel@tonic-gate "DR Functionality"); 3260Sstevel@tonic-gate 3270Sstevel@tonic-gate return (-1); 3280Sstevel@tonic-gate } 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate mutex_init(&drmach_i_lock, NULL, MUTEX_DRIVER, NULL); 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate drmach_xt_mb = (uchar_t *)vmem_alloc(static_alloc_arena, 3330Sstevel@tonic-gate NCPU * sizeof (uchar_t), VM_SLEEP); 3340Sstevel@tonic-gate drmach_shutdown_asm_mbox = (struct drmach_shutdown_mbox *) 3350Sstevel@tonic-gate vmem_alloc(static_alloc_arena, sizeof (struct drmach_shutdown_mbox), 3360Sstevel@tonic-gate VM_SLEEP); 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate if ((err = mod_install(&modlinkage)) != 0) { 3390Sstevel@tonic-gate mutex_destroy(&drmach_i_lock); 3400Sstevel@tonic-gate vmem_free(static_alloc_arena, (void *)drmach_xt_mb, 3410Sstevel@tonic-gate NCPU * sizeof (uchar_t)); 3420Sstevel@tonic-gate vmem_free(static_alloc_arena, (void *)drmach_shutdown_asm_mbox, 3430Sstevel@tonic-gate sizeof (struct drmach_shutdown_mbox)); 3440Sstevel@tonic-gate } 3450Sstevel@tonic-gate 3460Sstevel@tonic-gate return (err); 3470Sstevel@tonic-gate } 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate int 3500Sstevel@tonic-gate _fini(void) 3510Sstevel@tonic-gate { 3520Sstevel@tonic-gate static int drmach_fini(void); 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate if (drmach_fini()) 3550Sstevel@tonic-gate return (DDI_FAILURE); 3560Sstevel@tonic-gate else 3570Sstevel@tonic-gate return (mod_remove(&modlinkage)); 3580Sstevel@tonic-gate } 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate int 3610Sstevel@tonic-gate _info(struct modinfo *modinfop) 3620Sstevel@tonic-gate { 3630Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 3640Sstevel@tonic-gate } 3650Sstevel@tonic-gate 366789Sahrens static pnode_t 3670Sstevel@tonic-gate drmach_node_obp_get_dnode(drmach_node_t *np) 3680Sstevel@tonic-gate { 369789Sahrens return ((pnode_t)np->here); 3700Sstevel@tonic-gate } 3710Sstevel@tonic-gate 3720Sstevel@tonic-gate static int 3730Sstevel@tonic-gate drmach_node_obp_walk(drmach_node_t *np, void *data, 3740Sstevel@tonic-gate int (*cb)(drmach_node_walk_args_t *args)) 3750Sstevel@tonic-gate { 376789Sahrens pnode_t nodeid; 3770Sstevel@tonic-gate int rv; 3780Sstevel@tonic-gate drmach_node_walk_args_t args; 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate /* initialized args structure for callback */ 3810Sstevel@tonic-gate args.node = np; 3820Sstevel@tonic-gate args.data = data; 3830Sstevel@tonic-gate 3840Sstevel@tonic-gate nodeid = prom_childnode(prom_rootnode()); 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate /* save our new position with in the tree */ 3870Sstevel@tonic-gate np->here = (void *)nodeid; 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate rv = 0; 3900Sstevel@tonic-gate while (nodeid != OBP_NONODE) { 3910Sstevel@tonic-gate rv = (*cb)(&args); 3920Sstevel@tonic-gate if (rv) 3930Sstevel@tonic-gate break; 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate nodeid = prom_nextnode(nodeid); 3960Sstevel@tonic-gate 3970Sstevel@tonic-gate /* save our new position with in the tree */ 3980Sstevel@tonic-gate np->here = (void *)nodeid; 3990Sstevel@tonic-gate } 4000Sstevel@tonic-gate 4010Sstevel@tonic-gate return (rv); 4020Sstevel@tonic-gate } 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate static drmach_node_t * 4050Sstevel@tonic-gate drmach_node_new(void) 4060Sstevel@tonic-gate { 4070Sstevel@tonic-gate drmach_node_t *np; 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate np = kmem_zalloc(sizeof (drmach_node_t), KM_SLEEP); 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate np->get_dnode = drmach_node_obp_get_dnode; 4120Sstevel@tonic-gate np->walk = drmach_node_obp_walk; 4130Sstevel@tonic-gate 4140Sstevel@tonic-gate return (np); 4150Sstevel@tonic-gate } 4160Sstevel@tonic-gate 4170Sstevel@tonic-gate static void 4180Sstevel@tonic-gate drmach_node_dispose(drmach_node_t *np) 4190Sstevel@tonic-gate { 4200Sstevel@tonic-gate kmem_free(np, sizeof (*np)); 4210Sstevel@tonic-gate } 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate static dev_info_t * 4240Sstevel@tonic-gate drmach_node_get_dip(drmach_node_t *np) 4250Sstevel@tonic-gate { 426789Sahrens pnode_t nodeid; 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate nodeid = np->get_dnode(np); 4290Sstevel@tonic-gate if (nodeid == OBP_NONODE) 4300Sstevel@tonic-gate return (NULL); 4310Sstevel@tonic-gate else { 4320Sstevel@tonic-gate dev_info_t *dip; 4330Sstevel@tonic-gate 4340Sstevel@tonic-gate /* The root node doesn't have to be held */ 4350Sstevel@tonic-gate dip = e_ddi_nodeid_to_dip(nodeid); 4360Sstevel@tonic-gate if (dip) { 4370Sstevel@tonic-gate /* 4380Sstevel@tonic-gate * Branch rooted at dip is already held, so release 4390Sstevel@tonic-gate * hold acquired in e_ddi_nodeid_to_dip() 4400Sstevel@tonic-gate */ 4410Sstevel@tonic-gate ddi_release_devi(dip); 4420Sstevel@tonic-gate ASSERT(e_ddi_branch_held(dip)); 4430Sstevel@tonic-gate } 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate return (dip); 4460Sstevel@tonic-gate } 4470Sstevel@tonic-gate /*NOTREACHED*/ 4480Sstevel@tonic-gate } 4490Sstevel@tonic-gate 450789Sahrens static pnode_t 4510Sstevel@tonic-gate drmach_node_get_dnode(drmach_node_t *np) 4520Sstevel@tonic-gate { 4530Sstevel@tonic-gate return (np->get_dnode(np)); 4540Sstevel@tonic-gate } 4550Sstevel@tonic-gate 4560Sstevel@tonic-gate static int 4570Sstevel@tonic-gate drmach_node_walk(drmach_node_t *np, void *param, 4580Sstevel@tonic-gate int (*cb)(drmach_node_walk_args_t *args)) 4590Sstevel@tonic-gate { 4600Sstevel@tonic-gate return (np->walk(np, param, cb)); 4610Sstevel@tonic-gate } 4620Sstevel@tonic-gate 4630Sstevel@tonic-gate static int 4640Sstevel@tonic-gate drmach_node_get_prop(drmach_node_t *np, char *name, void *buf) 4650Sstevel@tonic-gate { 466789Sahrens pnode_t nodeid; 4670Sstevel@tonic-gate int rv; 4680Sstevel@tonic-gate 4690Sstevel@tonic-gate nodeid = np->get_dnode(np); 4700Sstevel@tonic-gate if (nodeid == OBP_NONODE) 4710Sstevel@tonic-gate rv = -1; 4720Sstevel@tonic-gate else if (prom_getproplen(nodeid, (caddr_t)name) < 0) 4730Sstevel@tonic-gate rv = -1; 4740Sstevel@tonic-gate else { 4750Sstevel@tonic-gate (void) prom_getprop(nodeid, (caddr_t)name, (caddr_t)buf); 4760Sstevel@tonic-gate rv = 0; 4770Sstevel@tonic-gate } 4780Sstevel@tonic-gate 4790Sstevel@tonic-gate return (rv); 4800Sstevel@tonic-gate } 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate static int 4830Sstevel@tonic-gate drmach_node_get_proplen(drmach_node_t *np, char *name, int *len) 4840Sstevel@tonic-gate { 485789Sahrens pnode_t nodeid; 4860Sstevel@tonic-gate int rv; 4870Sstevel@tonic-gate 4880Sstevel@tonic-gate nodeid = np->get_dnode(np); 4890Sstevel@tonic-gate if (nodeid == OBP_NONODE) 4900Sstevel@tonic-gate rv = -1; 4910Sstevel@tonic-gate else { 4920Sstevel@tonic-gate *len = prom_getproplen(nodeid, (caddr_t)name); 4930Sstevel@tonic-gate rv = (*len < 0 ? -1 : 0); 4940Sstevel@tonic-gate } 4950Sstevel@tonic-gate 4960Sstevel@tonic-gate return (rv); 4970Sstevel@tonic-gate } 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate static drmachid_t 5000Sstevel@tonic-gate drmach_node_dup(drmach_node_t *np) 5010Sstevel@tonic-gate { 5020Sstevel@tonic-gate drmach_node_t *dup; 5030Sstevel@tonic-gate 5040Sstevel@tonic-gate dup = drmach_node_new(); 5050Sstevel@tonic-gate dup->here = np->here; 5060Sstevel@tonic-gate 5070Sstevel@tonic-gate return (dup); 5080Sstevel@tonic-gate } 5090Sstevel@tonic-gate 5100Sstevel@tonic-gate /* 5110Sstevel@tonic-gate * drmach_array provides convenient array construction, access, 5120Sstevel@tonic-gate * bounds checking and array destruction logic. 5130Sstevel@tonic-gate */ 5140Sstevel@tonic-gate 5150Sstevel@tonic-gate static drmach_array_t * 5160Sstevel@tonic-gate drmach_array_new(int min_index, int max_index) 5170Sstevel@tonic-gate { 5180Sstevel@tonic-gate drmach_array_t *arr; 5190Sstevel@tonic-gate 5200Sstevel@tonic-gate arr = kmem_zalloc(sizeof (drmach_array_t), KM_SLEEP); 5210Sstevel@tonic-gate 5220Sstevel@tonic-gate arr->arr_sz = (max_index - min_index + 1) * sizeof (void *); 5230Sstevel@tonic-gate if (arr->arr_sz > 0) { 5240Sstevel@tonic-gate arr->min_index = min_index; 5250Sstevel@tonic-gate arr->max_index = max_index; 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate arr->arr = kmem_zalloc(arr->arr_sz, KM_SLEEP); 5280Sstevel@tonic-gate return (arr); 5290Sstevel@tonic-gate } else { 5300Sstevel@tonic-gate kmem_free(arr, sizeof (*arr)); 5310Sstevel@tonic-gate return (0); 5320Sstevel@tonic-gate } 5330Sstevel@tonic-gate } 5340Sstevel@tonic-gate 5350Sstevel@tonic-gate static int 5360Sstevel@tonic-gate drmach_array_set(drmach_array_t *arr, int idx, drmachid_t val) 5370Sstevel@tonic-gate { 5380Sstevel@tonic-gate if (idx < arr->min_index || idx > arr->max_index) 5390Sstevel@tonic-gate return (-1); 5400Sstevel@tonic-gate else { 5410Sstevel@tonic-gate arr->arr[idx - arr->min_index] = val; 5420Sstevel@tonic-gate return (0); 5430Sstevel@tonic-gate } 5440Sstevel@tonic-gate /*NOTREACHED*/ 5450Sstevel@tonic-gate } 5460Sstevel@tonic-gate 5470Sstevel@tonic-gate static int 5480Sstevel@tonic-gate drmach_array_get(drmach_array_t *arr, int idx, drmachid_t *val) 5490Sstevel@tonic-gate { 5500Sstevel@tonic-gate if (idx < arr->min_index || idx > arr->max_index) 5510Sstevel@tonic-gate return (-1); 5520Sstevel@tonic-gate else { 5530Sstevel@tonic-gate *val = arr->arr[idx - arr->min_index]; 5540Sstevel@tonic-gate return (0); 5550Sstevel@tonic-gate } 5560Sstevel@tonic-gate /*NOTREACHED*/ 5570Sstevel@tonic-gate } 5580Sstevel@tonic-gate 5590Sstevel@tonic-gate static int 5600Sstevel@tonic-gate drmach_array_first(drmach_array_t *arr, int *idx, drmachid_t *val) 5610Sstevel@tonic-gate { 5620Sstevel@tonic-gate int rv; 5630Sstevel@tonic-gate 5640Sstevel@tonic-gate *idx = arr->min_index; 5650Sstevel@tonic-gate while ((rv = drmach_array_get(arr, *idx, val)) == 0 && *val == NULL) 5660Sstevel@tonic-gate *idx += 1; 5670Sstevel@tonic-gate 5680Sstevel@tonic-gate return (rv); 5690Sstevel@tonic-gate } 5700Sstevel@tonic-gate 5710Sstevel@tonic-gate static int 5720Sstevel@tonic-gate drmach_array_next(drmach_array_t *arr, int *idx, drmachid_t *val) 5730Sstevel@tonic-gate { 5740Sstevel@tonic-gate int rv; 5750Sstevel@tonic-gate 5760Sstevel@tonic-gate *idx += 1; 5770Sstevel@tonic-gate while ((rv = drmach_array_get(arr, *idx, val)) == 0 && *val == NULL) 5780Sstevel@tonic-gate *idx += 1; 5790Sstevel@tonic-gate 5800Sstevel@tonic-gate return (rv); 5810Sstevel@tonic-gate } 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate static void 5840Sstevel@tonic-gate drmach_array_dispose(drmach_array_t *arr, void (*disposer)(drmachid_t)) 5850Sstevel@tonic-gate { 5860Sstevel@tonic-gate drmachid_t val; 5870Sstevel@tonic-gate int idx; 5880Sstevel@tonic-gate int rv; 5890Sstevel@tonic-gate 5900Sstevel@tonic-gate rv = drmach_array_first(arr, &idx, &val); 5910Sstevel@tonic-gate while (rv == 0) { 5920Sstevel@tonic-gate (*disposer)(val); 5930Sstevel@tonic-gate rv = drmach_array_next(arr, &idx, &val); 5940Sstevel@tonic-gate } 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate kmem_free(arr->arr, arr->arr_sz); 5970Sstevel@tonic-gate kmem_free(arr, sizeof (*arr)); 5980Sstevel@tonic-gate } 5990Sstevel@tonic-gate 6000Sstevel@tonic-gate /*ARGSUSED*/ 6010Sstevel@tonic-gate static int 602789Sahrens drmach_prom_select(pnode_t nodeid, void *arg, uint_t flags) 6030Sstevel@tonic-gate { 6040Sstevel@tonic-gate int rprop[64]; 605789Sahrens pnode_t saved; 6060Sstevel@tonic-gate drmach_config_args_t *ap = (drmach_config_args_t *)arg; 6070Sstevel@tonic-gate drmach_device_t *dp = ap->dp; 6080Sstevel@tonic-gate sbd_error_t *err; 6090Sstevel@tonic-gate 6100Sstevel@tonic-gate saved = drmach_node_get_dnode(dp->node); 6110Sstevel@tonic-gate 6120Sstevel@tonic-gate if (nodeid != saved) 6130Sstevel@tonic-gate return (DDI_FAILURE); 6140Sstevel@tonic-gate 6150Sstevel@tonic-gate if (saved == OBP_NONODE) { 6160Sstevel@tonic-gate err = DRMACH_INTERNAL_ERROR(); 6170Sstevel@tonic-gate DRERR_SET_C(&ap->err, &err); 6180Sstevel@tonic-gate return (DDI_FAILURE); 6190Sstevel@tonic-gate } 6200Sstevel@tonic-gate 6210Sstevel@tonic-gate if (prom_getprop(nodeid, OBP_REG, (caddr_t)rprop) <= 0) { 6220Sstevel@tonic-gate return (DDI_FAILURE); 6230Sstevel@tonic-gate } 6240Sstevel@tonic-gate 6250Sstevel@tonic-gate return (DDI_SUCCESS); 6260Sstevel@tonic-gate } 6270Sstevel@tonic-gate 6280Sstevel@tonic-gate /*ARGSUSED*/ 6290Sstevel@tonic-gate static void 6300Sstevel@tonic-gate drmach_branch_callback(dev_info_t *rdip, void *arg, uint_t flags) 6310Sstevel@tonic-gate { 6320Sstevel@tonic-gate drmach_config_args_t *ap = (drmach_config_args_t *)arg; 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate ASSERT(ap->dip == NULL); 6350Sstevel@tonic-gate 6360Sstevel@tonic-gate ap->dip = rdip; 6370Sstevel@tonic-gate } 6380Sstevel@tonic-gate 6390Sstevel@tonic-gate sbd_error_t * 6400Sstevel@tonic-gate drmach_configure(drmachid_t id, int flags) 6410Sstevel@tonic-gate { 6420Sstevel@tonic-gate drmach_device_t *dp; 6430Sstevel@tonic-gate sbd_error_t *err; 6440Sstevel@tonic-gate drmach_config_args_t ca; 6450Sstevel@tonic-gate devi_branch_t b = {0}; 6460Sstevel@tonic-gate dev_info_t *fdip = NULL; 6470Sstevel@tonic-gate 6480Sstevel@tonic-gate if (!DRMACH_IS_DEVICE_ID(id)) 6490Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 6500Sstevel@tonic-gate dp = id; 6510Sstevel@tonic-gate 6520Sstevel@tonic-gate ca.dp = dp; 6530Sstevel@tonic-gate ca.flags = flags; 6540Sstevel@tonic-gate ca.err = NULL; /* will be set if error detected */ 6550Sstevel@tonic-gate ca.dip = NULL; 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate b.arg = &ca; 6580Sstevel@tonic-gate b.type = DEVI_BRANCH_PROM; 6590Sstevel@tonic-gate b.create.prom_branch_select = drmach_prom_select; 6600Sstevel@tonic-gate b.devi_branch_callback = drmach_branch_callback; 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate if (e_ddi_branch_create(ddi_root_node(), &b, &fdip, 6630Sstevel@tonic-gate DEVI_BRANCH_CHILD | DEVI_BRANCH_CONFIGURE) != 0) { 6640Sstevel@tonic-gate char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 6650Sstevel@tonic-gate 6660Sstevel@tonic-gate /* 6670Sstevel@tonic-gate * If non-NULL, fdip is returned held and must be released. 6680Sstevel@tonic-gate */ 6690Sstevel@tonic-gate if (fdip != NULL) { 6700Sstevel@tonic-gate (void) ddi_pathname(fdip, path); 6710Sstevel@tonic-gate ddi_release_devi(fdip); 6720Sstevel@tonic-gate } else if (ca.dip != NULL) { 6730Sstevel@tonic-gate /* safe to call ddi_pathname as dip already held */ 6740Sstevel@tonic-gate (void) ddi_pathname(ca.dip, path); 6750Sstevel@tonic-gate } else { 6760Sstevel@tonic-gate (void) strcpy(path, "<none>"); 6770Sstevel@tonic-gate } 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate err = drerr_new(1, ESTF_DRVFAIL, path); 6800Sstevel@tonic-gate DRERR_SET_C(&ca.err, &err); 6810Sstevel@tonic-gate kmem_free(path, MAXPATHLEN); 6820Sstevel@tonic-gate } 6830Sstevel@tonic-gate 6840Sstevel@tonic-gate return (ca.err); 6850Sstevel@tonic-gate } 6860Sstevel@tonic-gate 6870Sstevel@tonic-gate static sbd_error_t * 6880Sstevel@tonic-gate drmach_device_new(drmach_node_t *node, 6890Sstevel@tonic-gate drmach_board_t *bp, drmach_device_t **dpp) 6900Sstevel@tonic-gate { 6910Sstevel@tonic-gate int i; 6920Sstevel@tonic-gate int rv; 6930Sstevel@tonic-gate drmach_device_t *dp; 6940Sstevel@tonic-gate sbd_error_t *err; 6950Sstevel@tonic-gate char name[OBP_MAXDRVNAME]; 6960Sstevel@tonic-gate 6970Sstevel@tonic-gate rv = drmach_node_get_prop(node, OBP_NAME, name); 6980Sstevel@tonic-gate if (rv) { 6990Sstevel@tonic-gate /* every node is expected to have a name */ 7000Sstevel@tonic-gate err = drerr_new(1, ESTF_GETPROP, 7010Sstevel@tonic-gate "PROM Node 0x%x: property %s", 7020Sstevel@tonic-gate (uint_t)node->get_dnode(node), OBP_NAME); 7030Sstevel@tonic-gate 7040Sstevel@tonic-gate return (err); 7050Sstevel@tonic-gate } 7060Sstevel@tonic-gate 7070Sstevel@tonic-gate /* 7080Sstevel@tonic-gate * The node currently being examined is not listed in the name2type[] 7090Sstevel@tonic-gate * array. In this case, the node is no interest to drmach. Both 7100Sstevel@tonic-gate * dp and err are initialized here to yield nothing (no device or 7110Sstevel@tonic-gate * error structure) for this case. 7120Sstevel@tonic-gate */ 7130Sstevel@tonic-gate for (i = 0; i < sizeof (name2type) / sizeof (name2type[0]); i++) 7140Sstevel@tonic-gate if (strcmp(name2type[i].name, name) == 0) 7150Sstevel@tonic-gate break; 7160Sstevel@tonic-gate 7170Sstevel@tonic-gate if (i < sizeof (name2type) / sizeof (name2type[0])) { 7180Sstevel@tonic-gate dp = kmem_zalloc(sizeof (drmach_device_t), KM_SLEEP); 7190Sstevel@tonic-gate 7200Sstevel@tonic-gate dp->bp = bp; 7210Sstevel@tonic-gate dp->unum = -1; 7220Sstevel@tonic-gate dp->node = drmach_node_dup(node); 7230Sstevel@tonic-gate dp->type = name2type[i].type; 7240Sstevel@tonic-gate 7250Sstevel@tonic-gate err = (name2type[i].new)(dp); 7260Sstevel@tonic-gate if (err) { 7270Sstevel@tonic-gate drmach_node_dispose(node); 7280Sstevel@tonic-gate kmem_free(dp, sizeof (*dp)); 7290Sstevel@tonic-gate dp = NULL; 7300Sstevel@tonic-gate } 7310Sstevel@tonic-gate 7320Sstevel@tonic-gate *dpp = dp; 7330Sstevel@tonic-gate return (err); 7340Sstevel@tonic-gate } 7350Sstevel@tonic-gate 7360Sstevel@tonic-gate /* 7370Sstevel@tonic-gate * The node currently being examined is not listed in the name2type[] 7380Sstevel@tonic-gate * array. In this case, the node is no interest to drmach. Both 7390Sstevel@tonic-gate * dp and err are initialized here to yield nothing (no device or 7400Sstevel@tonic-gate * error structure) for this case. 7410Sstevel@tonic-gate */ 7420Sstevel@tonic-gate *dpp = NULL; 7430Sstevel@tonic-gate return (NULL); 7440Sstevel@tonic-gate } 7450Sstevel@tonic-gate 7460Sstevel@tonic-gate static void 7470Sstevel@tonic-gate drmach_device_dispose(drmachid_t id) 7480Sstevel@tonic-gate { 7490Sstevel@tonic-gate drmach_device_t *self = id; 7500Sstevel@tonic-gate 7510Sstevel@tonic-gate if (self->node) 7520Sstevel@tonic-gate drmach_node_dispose(self->node); 7530Sstevel@tonic-gate 7540Sstevel@tonic-gate kmem_free(self, sizeof (*self)); 7550Sstevel@tonic-gate } 7560Sstevel@tonic-gate 7570Sstevel@tonic-gate static sbd_error_t * 7580Sstevel@tonic-gate drmach_device_get_prop(drmach_device_t *dp, char *name, void *buf) 7590Sstevel@tonic-gate { 7600Sstevel@tonic-gate sbd_error_t *err = NULL; 7610Sstevel@tonic-gate int rv; 7620Sstevel@tonic-gate 7630Sstevel@tonic-gate rv = drmach_node_get_prop(dp->node, name, buf); 7640Sstevel@tonic-gate if (rv) { 7650Sstevel@tonic-gate err = drerr_new(1, ESTF_GETPROP, 7660Sstevel@tonic-gate "%s::%s: property %s", 7670Sstevel@tonic-gate dp->bp->cm.name, dp->cm.name, name); 7680Sstevel@tonic-gate } 7690Sstevel@tonic-gate 7700Sstevel@tonic-gate return (err); 7710Sstevel@tonic-gate } 7720Sstevel@tonic-gate 7730Sstevel@tonic-gate static sbd_error_t * 7740Sstevel@tonic-gate drmach_device_get_proplen(drmach_device_t *dp, char *name, int *len) 7750Sstevel@tonic-gate { 7760Sstevel@tonic-gate sbd_error_t *err = NULL; 7770Sstevel@tonic-gate int rv; 7780Sstevel@tonic-gate 7790Sstevel@tonic-gate rv = drmach_node_get_proplen(dp->node, name, len); 7800Sstevel@tonic-gate if (rv) { 7810Sstevel@tonic-gate err = drerr_new(1, ESTF_GETPROPLEN, 7820Sstevel@tonic-gate "%s::%s: property %s", 7830Sstevel@tonic-gate dp->bp->cm.name, dp->cm.name, name); 7840Sstevel@tonic-gate } 7850Sstevel@tonic-gate 7860Sstevel@tonic-gate return (err); 7870Sstevel@tonic-gate } 7880Sstevel@tonic-gate 7890Sstevel@tonic-gate static drmach_board_t * 7900Sstevel@tonic-gate drmach_board_new(int bnum) 7910Sstevel@tonic-gate { 7920Sstevel@tonic-gate static sbd_error_t *drmach_board_release(drmachid_t); 7930Sstevel@tonic-gate static sbd_error_t *drmach_board_status(drmachid_t, drmach_status_t *); 7940Sstevel@tonic-gate 7950Sstevel@tonic-gate drmach_board_t *bp; 7960Sstevel@tonic-gate 7970Sstevel@tonic-gate bp = kmem_zalloc(sizeof (drmach_board_t), KM_SLEEP); 7980Sstevel@tonic-gate 7990Sstevel@tonic-gate bp->cm.isa = (void *)drmach_board_new; 8000Sstevel@tonic-gate bp->cm.release = drmach_board_release; 8010Sstevel@tonic-gate bp->cm.status = drmach_board_status; 8020Sstevel@tonic-gate 8030Sstevel@tonic-gate (void) drmach_board_name(bnum, bp->cm.name, sizeof (bp->cm.name)); 8040Sstevel@tonic-gate 8050Sstevel@tonic-gate bp->bnum = bnum; 8060Sstevel@tonic-gate bp->devices = NULL; 8070Sstevel@tonic-gate bp->connect_cpuid = -1; 8080Sstevel@tonic-gate bp->tree = drmach_node_new(); 8090Sstevel@tonic-gate bp->assigned = !drmach_initialized; 8100Sstevel@tonic-gate bp->powered = !drmach_initialized; 8110Sstevel@tonic-gate 8120Sstevel@tonic-gate drmach_array_set(drmach_boards, bnum, bp); 8130Sstevel@tonic-gate return (bp); 8140Sstevel@tonic-gate } 8150Sstevel@tonic-gate 8160Sstevel@tonic-gate static void 8170Sstevel@tonic-gate drmach_board_dispose(drmachid_t id) 8180Sstevel@tonic-gate { 8190Sstevel@tonic-gate drmach_board_t *bp; 8200Sstevel@tonic-gate 8210Sstevel@tonic-gate ASSERT(DRMACH_IS_BOARD_ID(id)); 8220Sstevel@tonic-gate bp = id; 8230Sstevel@tonic-gate 8240Sstevel@tonic-gate if (bp->tree) 8250Sstevel@tonic-gate drmach_node_dispose(bp->tree); 8260Sstevel@tonic-gate 8270Sstevel@tonic-gate if (bp->devices) 8280Sstevel@tonic-gate drmach_array_dispose(bp->devices, drmach_device_dispose); 8290Sstevel@tonic-gate 8300Sstevel@tonic-gate kmem_free(bp, sizeof (*bp)); 8310Sstevel@tonic-gate } 8320Sstevel@tonic-gate 8330Sstevel@tonic-gate static sbd_error_t * 8340Sstevel@tonic-gate drmach_board_status(drmachid_t id, drmach_status_t *stat) 8350Sstevel@tonic-gate { 8360Sstevel@tonic-gate sbd_error_t *err = NULL; 8370Sstevel@tonic-gate drmach_board_t *bp; 8380Sstevel@tonic-gate 8390Sstevel@tonic-gate if (!DRMACH_IS_BOARD_ID(id)) 8400Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 8410Sstevel@tonic-gate bp = id; 8420Sstevel@tonic-gate 8430Sstevel@tonic-gate stat->assigned = bp->assigned; 8440Sstevel@tonic-gate stat->powered = bp->powered; 8450Sstevel@tonic-gate stat->busy = 0; /* assume not busy */ 8460Sstevel@tonic-gate stat->configured = 0; /* assume not configured */ 8470Sstevel@tonic-gate stat->empty = 0; 8480Sstevel@tonic-gate stat->cond = bp->cond = SBD_COND_OK; 8490Sstevel@tonic-gate strncpy(stat->type, "System Brd", sizeof (stat->type)); 8500Sstevel@tonic-gate stat->info[0] = '\0'; 8510Sstevel@tonic-gate 8520Sstevel@tonic-gate if (bp->devices) { 8530Sstevel@tonic-gate int rv; 8540Sstevel@tonic-gate int d_idx; 8550Sstevel@tonic-gate drmachid_t d_id; 8560Sstevel@tonic-gate 8570Sstevel@tonic-gate rv = drmach_array_first(bp->devices, &d_idx, &d_id); 8580Sstevel@tonic-gate while (rv == 0) { 8590Sstevel@tonic-gate drmach_status_t d_stat; 8600Sstevel@tonic-gate 8610Sstevel@tonic-gate err = drmach_status(d_id, &d_stat); 8620Sstevel@tonic-gate if (err) 8630Sstevel@tonic-gate break; 8640Sstevel@tonic-gate 8650Sstevel@tonic-gate stat->busy |= d_stat.busy; 8660Sstevel@tonic-gate stat->configured |= d_stat.configured; 8670Sstevel@tonic-gate 8680Sstevel@tonic-gate rv = drmach_array_next(bp->devices, &d_idx, &d_id); 8690Sstevel@tonic-gate } 8700Sstevel@tonic-gate } 8710Sstevel@tonic-gate 8720Sstevel@tonic-gate return (err); 8730Sstevel@tonic-gate } 8740Sstevel@tonic-gate 8750Sstevel@tonic-gate /* a simple routine to reduce redundancy of this common logic */ 8760Sstevel@tonic-gate static pda_handle_t 8770Sstevel@tonic-gate drmach_pda_open(void) 8780Sstevel@tonic-gate { 8790Sstevel@tonic-gate pda_handle_t ph; 8800Sstevel@tonic-gate 8810Sstevel@tonic-gate ph = pda_open(); 8820Sstevel@tonic-gate if (ph == NULL) { 8830Sstevel@tonic-gate /* catch in debug kernels */ 8840Sstevel@tonic-gate ASSERT(0); 8850Sstevel@tonic-gate cmn_err(CE_WARN, "pda_open failed"); 8860Sstevel@tonic-gate } 8870Sstevel@tonic-gate 8880Sstevel@tonic-gate return (ph); 8890Sstevel@tonic-gate } 8900Sstevel@tonic-gate 8910Sstevel@tonic-gate #ifdef DEBUG 8920Sstevel@tonic-gate int drmach_init_break = 0; 8930Sstevel@tonic-gate #endif 8940Sstevel@tonic-gate 8950Sstevel@tonic-gate static int 8960Sstevel@tonic-gate hold_rele_branch(dev_info_t *rdip, void *arg) 8970Sstevel@tonic-gate { 8980Sstevel@tonic-gate int i; 8990Sstevel@tonic-gate int *holdp = (int *)arg; 9000Sstevel@tonic-gate char *name = ddi_node_name(rdip); 9010Sstevel@tonic-gate 9020Sstevel@tonic-gate /* 9030Sstevel@tonic-gate * For Starfire, we must be children of the root devinfo node 9040Sstevel@tonic-gate */ 9050Sstevel@tonic-gate ASSERT(ddi_get_parent(rdip) == ddi_root_node()); 9060Sstevel@tonic-gate 9070Sstevel@tonic-gate for (i = 0; i < sizeof (name2type) / sizeof (name2type[0]); i++) 9080Sstevel@tonic-gate if (strcmp(name2type[i].name, name) == 0) 9090Sstevel@tonic-gate break; 9100Sstevel@tonic-gate 9110Sstevel@tonic-gate if (i == sizeof (name2type) / sizeof (name2type[0])) { 9120Sstevel@tonic-gate /* Not of interest to us */ 9130Sstevel@tonic-gate return (DDI_WALK_PRUNECHILD); 9140Sstevel@tonic-gate } 9150Sstevel@tonic-gate 9160Sstevel@tonic-gate if (*holdp) { 9170Sstevel@tonic-gate ASSERT(!e_ddi_branch_held(rdip)); 9180Sstevel@tonic-gate e_ddi_branch_hold(rdip); 9190Sstevel@tonic-gate } else { 9200Sstevel@tonic-gate ASSERT(e_ddi_branch_held(rdip)); 9210Sstevel@tonic-gate e_ddi_branch_rele(rdip); 9220Sstevel@tonic-gate } 9230Sstevel@tonic-gate 9240Sstevel@tonic-gate return (DDI_WALK_PRUNECHILD); 9250Sstevel@tonic-gate } 9260Sstevel@tonic-gate 9270Sstevel@tonic-gate static int 9280Sstevel@tonic-gate drmach_init(void) 9290Sstevel@tonic-gate { 930789Sahrens pnode_t nodeid; 9310Sstevel@tonic-gate dev_info_t *rdip; 9320Sstevel@tonic-gate int hold, circ; 9330Sstevel@tonic-gate 9340Sstevel@tonic-gate #ifdef DEBUG 9350Sstevel@tonic-gate if (drmach_init_break) 9360Sstevel@tonic-gate debug_enter("drmach_init: drmach_init_break set\n"); 9370Sstevel@tonic-gate #endif 9380Sstevel@tonic-gate mutex_enter(&drmach_i_lock); 9390Sstevel@tonic-gate if (drmach_initialized) { 9400Sstevel@tonic-gate mutex_exit(&drmach_i_lock); 9410Sstevel@tonic-gate return (0); 9420Sstevel@tonic-gate } 9430Sstevel@tonic-gate 9440Sstevel@tonic-gate drmach_boards = drmach_array_new(0, MAX_BOARDS - 1); 9450Sstevel@tonic-gate 9460Sstevel@tonic-gate nodeid = prom_childnode(prom_rootnode()); 9470Sstevel@tonic-gate do { 9480Sstevel@tonic-gate int bnum; 9490Sstevel@tonic-gate drmachid_t id; 9500Sstevel@tonic-gate 9510Sstevel@tonic-gate bnum = -1; 9520Sstevel@tonic-gate (void) prom_getprop(nodeid, OBP_BOARDNUM, (caddr_t)&bnum); 9530Sstevel@tonic-gate if (bnum == -1) 9540Sstevel@tonic-gate continue; 9550Sstevel@tonic-gate 9560Sstevel@tonic-gate if (drmach_array_get(drmach_boards, bnum, &id) == -1) { 9570Sstevel@tonic-gate cmn_err(CE_WARN, "OBP node 0x%x has" 9580Sstevel@tonic-gate " invalid property value, %s=%d", 9590Sstevel@tonic-gate nodeid, OBP_BOARDNUM, bnum); 9600Sstevel@tonic-gate 9610Sstevel@tonic-gate /* clean up */ 9620Sstevel@tonic-gate drmach_array_dispose( 9630Sstevel@tonic-gate drmach_boards, drmach_board_dispose); 9640Sstevel@tonic-gate 9650Sstevel@tonic-gate mutex_exit(&drmach_i_lock); 9660Sstevel@tonic-gate return (-1); 9670Sstevel@tonic-gate } else if (id == NULL) 9680Sstevel@tonic-gate (void) drmach_board_new(bnum); 9690Sstevel@tonic-gate } while ((nodeid = prom_nextnode(nodeid)) != OBP_NONODE); 9700Sstevel@tonic-gate 9710Sstevel@tonic-gate drmach_shutdown_va = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP); 9720Sstevel@tonic-gate 9730Sstevel@tonic-gate /* 9740Sstevel@tonic-gate * Walk immediate children of devinfo root node and hold 9750Sstevel@tonic-gate * all devinfo branches of interest. 9760Sstevel@tonic-gate */ 9770Sstevel@tonic-gate hold = 1; 9780Sstevel@tonic-gate rdip = ddi_root_node(); 9790Sstevel@tonic-gate 9800Sstevel@tonic-gate ndi_devi_enter(rdip, &circ); 9810Sstevel@tonic-gate ddi_walk_devs(ddi_get_child(rdip), hold_rele_branch, &hold); 9820Sstevel@tonic-gate ndi_devi_exit(rdip, circ); 9830Sstevel@tonic-gate 9840Sstevel@tonic-gate drmach_initialized = 1; 9850Sstevel@tonic-gate 9860Sstevel@tonic-gate mutex_exit(&drmach_i_lock); 9870Sstevel@tonic-gate 9880Sstevel@tonic-gate return (0); 9890Sstevel@tonic-gate } 9900Sstevel@tonic-gate 9910Sstevel@tonic-gate static int 9920Sstevel@tonic-gate drmach_fini(void) 9930Sstevel@tonic-gate { 9940Sstevel@tonic-gate dev_info_t *rdip; 9950Sstevel@tonic-gate int hold, circ; 9960Sstevel@tonic-gate 9970Sstevel@tonic-gate if (drmach_initialized) { 9980Sstevel@tonic-gate int busy = 0; 9990Sstevel@tonic-gate int rv; 10000Sstevel@tonic-gate int idx; 10010Sstevel@tonic-gate drmachid_t id; 10020Sstevel@tonic-gate 10030Sstevel@tonic-gate ASSERT(drmach_boards != NULL); 10040Sstevel@tonic-gate 10050Sstevel@tonic-gate rv = drmach_array_first(drmach_boards, &idx, &id); 10060Sstevel@tonic-gate while (rv == 0) { 10070Sstevel@tonic-gate sbd_error_t *err; 10080Sstevel@tonic-gate drmach_status_t stat; 10090Sstevel@tonic-gate 10100Sstevel@tonic-gate err = drmach_board_status(id, &stat); 10110Sstevel@tonic-gate if (err) { 10120Sstevel@tonic-gate /* catch in debug kernels */ 10130Sstevel@tonic-gate ASSERT(0); 10140Sstevel@tonic-gate sbd_err_clear(&err); 10150Sstevel@tonic-gate busy = 1; 10160Sstevel@tonic-gate } else 10170Sstevel@tonic-gate busy |= stat.busy; 10180Sstevel@tonic-gate 10190Sstevel@tonic-gate rv = drmach_array_next(drmach_boards, &idx, &id); 10200Sstevel@tonic-gate } 10210Sstevel@tonic-gate 10220Sstevel@tonic-gate if (busy) 10230Sstevel@tonic-gate return (-1); 10240Sstevel@tonic-gate 10250Sstevel@tonic-gate drmach_array_dispose(drmach_boards, drmach_board_dispose); 10260Sstevel@tonic-gate drmach_boards = NULL; 10270Sstevel@tonic-gate 10280Sstevel@tonic-gate vmem_free(heap_arena, drmach_shutdown_va, PAGESIZE); 10290Sstevel@tonic-gate 10300Sstevel@tonic-gate /* 10310Sstevel@tonic-gate * Walk immediate children of the root devinfo node 10320Sstevel@tonic-gate * releasing holds acquired on branches in drmach_init() 10330Sstevel@tonic-gate */ 10340Sstevel@tonic-gate hold = 0; 10350Sstevel@tonic-gate rdip = ddi_root_node(); 10360Sstevel@tonic-gate 10370Sstevel@tonic-gate ndi_devi_enter(rdip, &circ); 10380Sstevel@tonic-gate ddi_walk_devs(ddi_get_child(rdip), hold_rele_branch, &hold); 10390Sstevel@tonic-gate ndi_devi_exit(rdip, circ); 10400Sstevel@tonic-gate 10410Sstevel@tonic-gate mutex_destroy(&drmach_i_lock); 10420Sstevel@tonic-gate 10430Sstevel@tonic-gate drmach_initialized = 0; 10440Sstevel@tonic-gate } 10450Sstevel@tonic-gate if (drmach_xt_mb != NULL) { 10460Sstevel@tonic-gate vmem_free(static_alloc_arena, (void *)drmach_xt_mb, 10470Sstevel@tonic-gate NCPU * sizeof (uchar_t)); 10480Sstevel@tonic-gate } 10490Sstevel@tonic-gate if (drmach_shutdown_asm_mbox != NULL) { 10500Sstevel@tonic-gate vmem_free(static_alloc_arena, (void *)drmach_shutdown_asm_mbox, 10510Sstevel@tonic-gate sizeof (struct drmach_shutdown_mbox)); 10520Sstevel@tonic-gate } 10530Sstevel@tonic-gate return (0); 10540Sstevel@tonic-gate } 10550Sstevel@tonic-gate 10560Sstevel@tonic-gate static sbd_error_t * 10570Sstevel@tonic-gate drmach_get_mc_asr_addr(drmachid_t id, uint64_t *pa) 10580Sstevel@tonic-gate { 10590Sstevel@tonic-gate drmach_device_t *dp; 1060789Sahrens pnode_t nodeid; 10610Sstevel@tonic-gate uint64_t addr; 10620Sstevel@tonic-gate 10630Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(id)) 10640Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 10650Sstevel@tonic-gate dp = id; 10660Sstevel@tonic-gate 10670Sstevel@tonic-gate nodeid = drmach_node_get_dnode(dp->node); 10680Sstevel@tonic-gate if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE) 10690Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 10700Sstevel@tonic-gate 10710Sstevel@tonic-gate addr = mc_get_asr_addr(nodeid); 10720Sstevel@tonic-gate if (addr == (uint64_t)-1) 10730Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 10740Sstevel@tonic-gate 10750Sstevel@tonic-gate *pa = addr; 10760Sstevel@tonic-gate return (NULL); 10770Sstevel@tonic-gate } 10780Sstevel@tonic-gate 10790Sstevel@tonic-gate static sbd_error_t * 10800Sstevel@tonic-gate drmach_get_mc_idle_addr(drmachid_t id, uint64_t *pa) 10810Sstevel@tonic-gate { 10820Sstevel@tonic-gate drmach_device_t *dp; 1083789Sahrens pnode_t nodeid; 10840Sstevel@tonic-gate uint64_t addr; 10850Sstevel@tonic-gate 10860Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(id)) 10870Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 10880Sstevel@tonic-gate dp = id; 10890Sstevel@tonic-gate 10900Sstevel@tonic-gate nodeid = drmach_node_get_dnode(dp->node); 10910Sstevel@tonic-gate if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE) 10920Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 10930Sstevel@tonic-gate 10940Sstevel@tonic-gate addr = mc_get_idle_addr(nodeid); 10950Sstevel@tonic-gate if (addr == (uint64_t)-1) 10960Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 10970Sstevel@tonic-gate 10980Sstevel@tonic-gate *pa = addr; 10990Sstevel@tonic-gate return (NULL); 11000Sstevel@tonic-gate } 11010Sstevel@tonic-gate 11020Sstevel@tonic-gate static sbd_error_t * 11030Sstevel@tonic-gate drmach_read_mc_asr(drmachid_t id, uint_t *mcregp) 11040Sstevel@tonic-gate { 11050Sstevel@tonic-gate drmach_device_t *dp; 1106789Sahrens pnode_t nodeid; 11070Sstevel@tonic-gate sbd_error_t *err; 11080Sstevel@tonic-gate 11090Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(id)) 11100Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 11110Sstevel@tonic-gate dp = id; 11120Sstevel@tonic-gate 11130Sstevel@tonic-gate nodeid = drmach_node_get_dnode(dp->node); 11140Sstevel@tonic-gate if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE) 11150Sstevel@tonic-gate err = DRMACH_INTERNAL_ERROR(); 11160Sstevel@tonic-gate else if (mc_read_asr(nodeid, mcregp) == -1) 11170Sstevel@tonic-gate err = DRMACH_INTERNAL_ERROR(); 11180Sstevel@tonic-gate else 11190Sstevel@tonic-gate err = NULL; 11200Sstevel@tonic-gate 11210Sstevel@tonic-gate return (err); 11220Sstevel@tonic-gate } 11230Sstevel@tonic-gate 11240Sstevel@tonic-gate static sbd_error_t * 11250Sstevel@tonic-gate drmach_write_mc_asr(drmachid_t id, uint_t mcreg) 11260Sstevel@tonic-gate { 11270Sstevel@tonic-gate drmach_device_t *dp; 1128789Sahrens pnode_t nodeid; 11290Sstevel@tonic-gate sbd_error_t *err; 11300Sstevel@tonic-gate 11310Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(id)) 11320Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 11330Sstevel@tonic-gate dp = id; 11340Sstevel@tonic-gate 11350Sstevel@tonic-gate nodeid = drmach_node_get_dnode(dp->node); 11360Sstevel@tonic-gate if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE) 11370Sstevel@tonic-gate err = DRMACH_INTERNAL_ERROR(); 11380Sstevel@tonic-gate else if (mc_write_asr(nodeid, mcreg) == -1) 11390Sstevel@tonic-gate err = DRMACH_INTERNAL_ERROR(); 11400Sstevel@tonic-gate else 11410Sstevel@tonic-gate err = NULL; 11420Sstevel@tonic-gate 11430Sstevel@tonic-gate return (err); 11440Sstevel@tonic-gate } 11450Sstevel@tonic-gate 11460Sstevel@tonic-gate static struct memlist * 11470Sstevel@tonic-gate memlist_add_span(struct memlist *mlist, uint64_t base, uint64_t len) 11480Sstevel@tonic-gate { 11490Sstevel@tonic-gate struct memlist *ml, *tl, *nl; 11500Sstevel@tonic-gate 11510Sstevel@tonic-gate if (len == 0ull) 11520Sstevel@tonic-gate return (NULL); 11530Sstevel@tonic-gate 11540Sstevel@tonic-gate if (mlist == NULL) { 11550Sstevel@tonic-gate mlist = GETSTRUCT(struct memlist, 1); 11560Sstevel@tonic-gate mlist->address = base; 11570Sstevel@tonic-gate mlist->size = len; 11580Sstevel@tonic-gate mlist->next = mlist->prev = NULL; 11590Sstevel@tonic-gate 11600Sstevel@tonic-gate return (mlist); 11610Sstevel@tonic-gate } 11620Sstevel@tonic-gate 11630Sstevel@tonic-gate for (tl = ml = mlist; ml; tl = ml, ml = ml->next) { 11640Sstevel@tonic-gate if (base < ml->address) { 11650Sstevel@tonic-gate if ((base + len) < ml->address) { 11660Sstevel@tonic-gate nl = GETSTRUCT(struct memlist, 1); 11670Sstevel@tonic-gate nl->address = base; 11680Sstevel@tonic-gate nl->size = len; 11690Sstevel@tonic-gate nl->next = ml; 11700Sstevel@tonic-gate if ((nl->prev = ml->prev) != NULL) 11710Sstevel@tonic-gate nl->prev->next = nl; 11720Sstevel@tonic-gate ml->prev = nl; 11730Sstevel@tonic-gate if (mlist == ml) 11740Sstevel@tonic-gate mlist = nl; 11750Sstevel@tonic-gate } else { 11760Sstevel@tonic-gate ml->size = MAX((base + len), 11770Sstevel@tonic-gate (ml->address + ml->size)) - 11780Sstevel@tonic-gate base; 11790Sstevel@tonic-gate ml->address = base; 11800Sstevel@tonic-gate } 11810Sstevel@tonic-gate break; 11820Sstevel@tonic-gate 11830Sstevel@tonic-gate } else if (base <= (ml->address + ml->size)) { 11840Sstevel@tonic-gate ml->size = MAX((base + len), 11850Sstevel@tonic-gate (ml->address + ml->size)) - 11860Sstevel@tonic-gate MIN(ml->address, base); 11870Sstevel@tonic-gate ml->address = MIN(ml->address, base); 11880Sstevel@tonic-gate break; 11890Sstevel@tonic-gate } 11900Sstevel@tonic-gate } 11910Sstevel@tonic-gate if (ml == NULL) { 11920Sstevel@tonic-gate nl = GETSTRUCT(struct memlist, 1); 11930Sstevel@tonic-gate nl->address = base; 11940Sstevel@tonic-gate nl->size = len; 11950Sstevel@tonic-gate nl->next = NULL; 11960Sstevel@tonic-gate nl->prev = tl; 11970Sstevel@tonic-gate tl->next = nl; 11980Sstevel@tonic-gate } 11990Sstevel@tonic-gate 12000Sstevel@tonic-gate memlist_coalesce(mlist); 12010Sstevel@tonic-gate 12020Sstevel@tonic-gate return (mlist); 12030Sstevel@tonic-gate } 12040Sstevel@tonic-gate 12050Sstevel@tonic-gate static sbd_error_t * 12060Sstevel@tonic-gate drmach_prep_rename_script(drmach_device_t *s_mem, drmach_device_t *t_mem, 12070Sstevel@tonic-gate uint64_t t_slice_offset, caddr_t buf, int buflen) 12080Sstevel@tonic-gate { 12090Sstevel@tonic-gate int i, b, m; 12100Sstevel@tonic-gate drmach_mc_idle_script_t *isp; 12110Sstevel@tonic-gate drmach_rename_script_t *rsp; 12120Sstevel@tonic-gate int s_bd, t_bd; 12130Sstevel@tonic-gate uint_t s_masr, t_masr; 12140Sstevel@tonic-gate uint64_t s_new_basepa, t_new_basepa; 12150Sstevel@tonic-gate int b_idx, rv; 12160Sstevel@tonic-gate sbd_error_t *err; 12170Sstevel@tonic-gate drmachid_t b_id; 12180Sstevel@tonic-gate drmach_board_t *brd; 12190Sstevel@tonic-gate 12200Sstevel@tonic-gate #ifdef DEBUG 12210Sstevel@tonic-gate /* 12220Sstevel@tonic-gate * Starfire CPU/MEM/IO boards have only one MC per board. 12230Sstevel@tonic-gate * This function has been coded with that fact in mind. 12240Sstevel@tonic-gate */ 12250Sstevel@tonic-gate ASSERT(MAX_MEM_UNITS_PER_BOARD == 1); 12260Sstevel@tonic-gate 12270Sstevel@tonic-gate /* 12280Sstevel@tonic-gate * calculate the maximum space that could be consumed, 12290Sstevel@tonic-gate * then verify the available buffer space is adequate. 12300Sstevel@tonic-gate */ 12310Sstevel@tonic-gate m = sizeof (drmach_mc_idle_script_t *) * 2; /* two MCs */ 12320Sstevel@tonic-gate b = sizeof (drmach_rename_script_t *) * 3 * MAX_CPU_UNITS_PER_BOARD; 12330Sstevel@tonic-gate b += sizeof (drmach_rename_script_t *) * 3 * MAX_IO_UNITS_PER_BOARD; 12340Sstevel@tonic-gate b *= MAX_BOARDS; 12350Sstevel@tonic-gate b += sizeof (drmach_rename_script_t *) * 3; 12360Sstevel@tonic-gate b += sizeof (drmach_rename_script_t *) * 1; 12370Sstevel@tonic-gate ASSERT(m + b < buflen); 12380Sstevel@tonic-gate #endif 12390Sstevel@tonic-gate 12400Sstevel@tonic-gate /* 12410Sstevel@tonic-gate * construct an array of MC idle register addresses of 12420Sstevel@tonic-gate * both MCs. The array is zero terminated -- as expected 12430Sstevel@tonic-gate * by drmach_copy_rename_prog__relocatable(). 12440Sstevel@tonic-gate */ 12450Sstevel@tonic-gate isp = (drmach_mc_idle_script_t *)buf; 12460Sstevel@tonic-gate 12470Sstevel@tonic-gate /* source mc */ 12480Sstevel@tonic-gate err = drmach_get_mc_idle_addr(s_mem, &isp->idle_addr); 12490Sstevel@tonic-gate if (err) 12500Sstevel@tonic-gate return (err); 12510Sstevel@tonic-gate isp->mem = s_mem; 12520Sstevel@tonic-gate isp += 1; 12530Sstevel@tonic-gate 12540Sstevel@tonic-gate /* target mc */ 12550Sstevel@tonic-gate err = drmach_get_mc_idle_addr(t_mem, &isp->idle_addr); 12560Sstevel@tonic-gate if (err) 12570Sstevel@tonic-gate return (err); 12580Sstevel@tonic-gate isp->mem = t_mem; 12590Sstevel@tonic-gate isp += 1; 12600Sstevel@tonic-gate 12610Sstevel@tonic-gate /* terminator */ 12620Sstevel@tonic-gate isp->idle_addr = 0; 12630Sstevel@tonic-gate isp->mem = NULL; 12640Sstevel@tonic-gate isp += 1; 12650Sstevel@tonic-gate 12660Sstevel@tonic-gate /* fetch source mc asr register value */ 12670Sstevel@tonic-gate err = drmach_read_mc_asr(s_mem, &s_masr); 12680Sstevel@tonic-gate if (err) 12690Sstevel@tonic-gate return (err); 12700Sstevel@tonic-gate else if (s_masr & STARFIRE_MC_INTERLEAVE_MASK) { 12710Sstevel@tonic-gate return (drerr_new(1, ESTF_INTERBOARD, "%s::%s", 12720Sstevel@tonic-gate s_mem->bp->cm.name, s_mem->cm.name)); 12730Sstevel@tonic-gate } 12740Sstevel@tonic-gate 12750Sstevel@tonic-gate /* fetch target mc asr register value */ 12760Sstevel@tonic-gate err = drmach_read_mc_asr(t_mem, &t_masr); 12770Sstevel@tonic-gate if (err) 12780Sstevel@tonic-gate return (err); 12790Sstevel@tonic-gate else if (t_masr & STARFIRE_MC_INTERLEAVE_MASK) { 12800Sstevel@tonic-gate return (drerr_new(1, ESTF_INTERBOARD, "%s::%s", 12810Sstevel@tonic-gate t_mem->bp->cm.name, t_mem->cm.name)); 12820Sstevel@tonic-gate } 12830Sstevel@tonic-gate 12840Sstevel@tonic-gate /* get new source base pa from target's masr */ 12850Sstevel@tonic-gate s_new_basepa = mc_asr_to_pa(t_masr); 12860Sstevel@tonic-gate 12870Sstevel@tonic-gate /* 12880Sstevel@tonic-gate * remove any existing slice offset to realign 12890Sstevel@tonic-gate * memory with board's slice boundary 12900Sstevel@tonic-gate */ 12910Sstevel@tonic-gate s_new_basepa &= ~ (mc_get_mem_alignment() - 1); 12920Sstevel@tonic-gate 12930Sstevel@tonic-gate /* get new target base pa from source's masr */ 12940Sstevel@tonic-gate t_new_basepa = mc_asr_to_pa(s_masr); 12950Sstevel@tonic-gate 12960Sstevel@tonic-gate /* remove any existing slice offset, then apply new offset */ 12970Sstevel@tonic-gate t_new_basepa &= ~ (mc_get_mem_alignment() - 1); 12980Sstevel@tonic-gate t_new_basepa += t_slice_offset; 12990Sstevel@tonic-gate 13000Sstevel@tonic-gate /* encode new base pa into s_masr. turn off mem present bit */ 13010Sstevel@tonic-gate s_masr = mc_pa_to_asr(s_masr, s_new_basepa); 13020Sstevel@tonic-gate s_masr &= ~STARFIRE_MC_MEM_PRESENT_MASK; 13030Sstevel@tonic-gate 13040Sstevel@tonic-gate /* encode new base pa into t_masr. turn on mem present bit */ 13050Sstevel@tonic-gate t_masr = mc_pa_to_asr(t_masr, t_new_basepa); 13060Sstevel@tonic-gate t_masr |= STARFIRE_MC_MEM_PRESENT_MASK; 13070Sstevel@tonic-gate 13080Sstevel@tonic-gate /* 13090Sstevel@tonic-gate * Step 0: Mark source memory as not present. 13100Sstevel@tonic-gate */ 13110Sstevel@tonic-gate m = 0; 13120Sstevel@tonic-gate rsp = (drmach_rename_script_t *)isp; 13130Sstevel@tonic-gate err = drmach_get_mc_asr_addr(s_mem, &rsp[m].masr_addr); 13140Sstevel@tonic-gate if (err) 13150Sstevel@tonic-gate return (err); 13160Sstevel@tonic-gate rsp[m].masr = s_masr; 13170Sstevel@tonic-gate m++; 13180Sstevel@tonic-gate 13190Sstevel@tonic-gate /* 13200Sstevel@tonic-gate * Step 1: Write source base address to target MC 13210Sstevel@tonic-gate * with present bit off. 13220Sstevel@tonic-gate */ 13230Sstevel@tonic-gate err = drmach_get_mc_asr_addr(t_mem, &rsp[m].masr_addr); 13240Sstevel@tonic-gate if (err) 13250Sstevel@tonic-gate return (err); 13260Sstevel@tonic-gate rsp[m].masr = t_masr & ~STARFIRE_MC_MEM_PRESENT_MASK; 13270Sstevel@tonic-gate m++; 13280Sstevel@tonic-gate 13290Sstevel@tonic-gate /* 13300Sstevel@tonic-gate * Step 2: Now rewrite target reg with present bit on. 13310Sstevel@tonic-gate */ 13320Sstevel@tonic-gate rsp[m].masr_addr = rsp[m-1].masr_addr; 13330Sstevel@tonic-gate rsp[m].masr = t_masr; 13340Sstevel@tonic-gate m++; 13350Sstevel@tonic-gate 13360Sstevel@tonic-gate s_bd = s_mem->bp->bnum; 13370Sstevel@tonic-gate t_bd = t_mem->bp->bnum; 13380Sstevel@tonic-gate 13390Sstevel@tonic-gate DRMACH_PR("preparing script for CPU and IO units:\n"); 13400Sstevel@tonic-gate 13410Sstevel@tonic-gate rv = drmach_array_first(drmach_boards, &b_idx, &b_id); 13420Sstevel@tonic-gate if (rv) { 13430Sstevel@tonic-gate /* catch this in debug kernels */ 13440Sstevel@tonic-gate ASSERT(0); 13450Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 13460Sstevel@tonic-gate } 13470Sstevel@tonic-gate 13480Sstevel@tonic-gate do { 13490Sstevel@tonic-gate int d_idx; 13500Sstevel@tonic-gate drmachid_t d_id; 13510Sstevel@tonic-gate drmach_device_t *device; 13520Sstevel@tonic-gate 13530Sstevel@tonic-gate ASSERT(DRMACH_IS_BOARD_ID(b_id)); 13540Sstevel@tonic-gate brd = b_id; 13550Sstevel@tonic-gate b = brd->bnum; 13560Sstevel@tonic-gate 13570Sstevel@tonic-gate /* 13580Sstevel@tonic-gate * Step 3: Update PC MADR tables for CPUs. 13590Sstevel@tonic-gate */ 13600Sstevel@tonic-gate rv = drmach_array_first(brd->devices, &d_idx, &d_id); 13610Sstevel@tonic-gate if (rv) { 13620Sstevel@tonic-gate /* must mean no devices on this board */ 13630Sstevel@tonic-gate break; 13640Sstevel@tonic-gate } 13650Sstevel@tonic-gate 13660Sstevel@tonic-gate DRMACH_PR("\t%s\n", brd->cm.name); 13670Sstevel@tonic-gate 13680Sstevel@tonic-gate do { 13690Sstevel@tonic-gate ASSERT(DRMACH_IS_DEVICE_ID(d_id)); 13700Sstevel@tonic-gate 13710Sstevel@tonic-gate if (!DRMACH_IS_CPU_ID(d_id)) 13720Sstevel@tonic-gate continue; 13730Sstevel@tonic-gate 13740Sstevel@tonic-gate device = d_id; 13750Sstevel@tonic-gate i = device->unum; 13760Sstevel@tonic-gate 13770Sstevel@tonic-gate DRMACH_PR("\t\t%s\n", device->cm.name); 13780Sstevel@tonic-gate 13790Sstevel@tonic-gate /* 13800Sstevel@tonic-gate * Disabled detaching mem node. 13810Sstevel@tonic-gate */ 13820Sstevel@tonic-gate rsp[m].masr_addr = STARFIRE_PC_MADR_ADDR(b, s_bd, i); 13830Sstevel@tonic-gate rsp[m].masr = s_masr; 13840Sstevel@tonic-gate m++; 13850Sstevel@tonic-gate /* 13860Sstevel@tonic-gate * Always write masr with present bit 13870Sstevel@tonic-gate * off and then again with it on. 13880Sstevel@tonic-gate */ 13890Sstevel@tonic-gate rsp[m].masr_addr = STARFIRE_PC_MADR_ADDR(b, t_bd, i); 13900Sstevel@tonic-gate rsp[m].masr = t_masr & ~STARFIRE_MC_MEM_PRESENT_MASK; 13910Sstevel@tonic-gate m++; 13920Sstevel@tonic-gate rsp[m].masr_addr = rsp[m-1].masr_addr; 13930Sstevel@tonic-gate rsp[m].masr = t_masr; 13940Sstevel@tonic-gate m++; 13950Sstevel@tonic-gate 13960Sstevel@tonic-gate } while (drmach_array_next(brd->devices, &d_idx, &d_id) == 0); 13970Sstevel@tonic-gate 13980Sstevel@tonic-gate /* 13990Sstevel@tonic-gate * Step 4: Update PC MADR tables for IOs. 14000Sstevel@tonic-gate */ 14010Sstevel@tonic-gate rv = drmach_array_first(brd->devices, &d_idx, &d_id); 14020Sstevel@tonic-gate /* this worked for previous loop, must work here too */ 14030Sstevel@tonic-gate ASSERT(rv == 0); 14040Sstevel@tonic-gate 14050Sstevel@tonic-gate do { 14060Sstevel@tonic-gate ASSERT(DRMACH_IS_DEVICE_ID(d_id)); 14070Sstevel@tonic-gate 14080Sstevel@tonic-gate if (!DRMACH_IS_IO_ID(d_id)) 14090Sstevel@tonic-gate continue; 14100Sstevel@tonic-gate 14110Sstevel@tonic-gate device = d_id; 14120Sstevel@tonic-gate i = device->unum; 14130Sstevel@tonic-gate 14140Sstevel@tonic-gate DRMACH_PR("\t\t%s\n", device->cm.name); 14150Sstevel@tonic-gate 14160Sstevel@tonic-gate /* 14170Sstevel@tonic-gate * Disabled detaching mem node. 14180Sstevel@tonic-gate */ 14190Sstevel@tonic-gate rsp[m].masr_addr = STARFIRE_PC_MADR_ADDR(b, s_bd, i+4); 14200Sstevel@tonic-gate rsp[m].masr = s_masr; 14210Sstevel@tonic-gate m++; 14220Sstevel@tonic-gate /* 14230Sstevel@tonic-gate * Always write masr with present bit 14240Sstevel@tonic-gate * off and then again with it on. 14250Sstevel@tonic-gate */ 14260Sstevel@tonic-gate rsp[m].masr_addr = STARFIRE_PC_MADR_ADDR(b, t_bd, i+4); 14270Sstevel@tonic-gate rsp[m].masr = t_masr & ~STARFIRE_MC_MEM_PRESENT_MASK; 14280Sstevel@tonic-gate m++; 14290Sstevel@tonic-gate rsp[m].masr_addr = rsp[m-1].masr_addr; 14300Sstevel@tonic-gate rsp[m].masr = t_masr; 14310Sstevel@tonic-gate m++; 14320Sstevel@tonic-gate 14330Sstevel@tonic-gate } while (drmach_array_next(brd->devices, &d_idx, &d_id) == 0); 14340Sstevel@tonic-gate } while (drmach_array_next(drmach_boards, &b_idx, &b_id) == 0); 14350Sstevel@tonic-gate 14360Sstevel@tonic-gate /* 14370Sstevel@tonic-gate * Zero masr_addr value indicates the END. 14380Sstevel@tonic-gate */ 14390Sstevel@tonic-gate rsp[m].masr_addr = 0ull; 14400Sstevel@tonic-gate rsp[m].masr = 0; 14410Sstevel@tonic-gate DRMACH_PR("number of steps in rename script = %d\n", m); 14420Sstevel@tonic-gate m++; 14430Sstevel@tonic-gate 14440Sstevel@tonic-gate /* paranoia */ 14450Sstevel@tonic-gate ASSERT((caddr_t)&rsp[m] <= buf + buflen); 14460Sstevel@tonic-gate 14470Sstevel@tonic-gate #ifdef DEBUG 14480Sstevel@tonic-gate { 14490Sstevel@tonic-gate int j; 14500Sstevel@tonic-gate 14510Sstevel@tonic-gate DRMACH_PR("mc idle register address list:"); 14520Sstevel@tonic-gate isp = (drmach_mc_idle_script_t *)buf; 14530Sstevel@tonic-gate DRMACH_PR("source mc idle addr 0x%llx, mem id %p", 14540Sstevel@tonic-gate isp[0].idle_addr, isp[0].mem); 14550Sstevel@tonic-gate DRMACH_PR("target mc idle addr 0x%llx, mem id %p", 14560Sstevel@tonic-gate isp[1].idle_addr, isp[1].mem); 14570Sstevel@tonic-gate ASSERT(isp[2].idle_addr == 0); 14580Sstevel@tonic-gate 14590Sstevel@tonic-gate DRMACH_PR("copy-rename script:"); 14600Sstevel@tonic-gate for (j = 0; j < m; j++) { 14610Sstevel@tonic-gate DRMACH_PR("0x%llx = 0x%08x", 14620Sstevel@tonic-gate rsp[j].masr_addr, rsp[j].masr); 14630Sstevel@tonic-gate } 14640Sstevel@tonic-gate 14650Sstevel@tonic-gate DELAY(1000000); 14660Sstevel@tonic-gate } 14670Sstevel@tonic-gate #endif 14680Sstevel@tonic-gate 14690Sstevel@tonic-gate /* return number of bytes consumed */ 14700Sstevel@tonic-gate b = (caddr_t)&rsp[m] - buf; 14710Sstevel@tonic-gate DRMACH_PR("total number of bytes consumed is %d\n", b); 14720Sstevel@tonic-gate ASSERT(b <= buflen); 14730Sstevel@tonic-gate 14740Sstevel@tonic-gate #ifdef lint 14750Sstevel@tonic-gate buflen = buflen; 14760Sstevel@tonic-gate #endif 14770Sstevel@tonic-gate 14780Sstevel@tonic-gate return (NULL); 14790Sstevel@tonic-gate } 14800Sstevel@tonic-gate 14810Sstevel@tonic-gate /* 14820Sstevel@tonic-gate * The routine performs the necessary memory COPY and MC adr SWITCH. 14830Sstevel@tonic-gate * Both operations MUST be at the same "level" so that the stack is 14840Sstevel@tonic-gate * maintained correctly between the copy and switch. The switch 14850Sstevel@tonic-gate * portion implements a caching mechanism to guarantee the code text 14860Sstevel@tonic-gate * is cached prior to execution. This is to guard against possible 14870Sstevel@tonic-gate * memory access while the MC adr's are being modified. 14880Sstevel@tonic-gate * 14890Sstevel@tonic-gate * IMPORTANT: The _drmach_copy_rename_end() function must immediately 14900Sstevel@tonic-gate * follow drmach_copy_rename_prog__relocatable() so that the correct 14910Sstevel@tonic-gate * "length" of the drmach_copy_rename_prog__relocatable can be 14920Sstevel@tonic-gate * calculated. This routine MUST be a LEAF function, i.e. it can 14930Sstevel@tonic-gate * make NO function calls, primarily for two reasons: 14940Sstevel@tonic-gate * 14950Sstevel@tonic-gate * 1. We must keep the stack consistent across the "switch". 14960Sstevel@tonic-gate * 2. Function calls are compiled to relative offsets, and 14970Sstevel@tonic-gate * we execute this function we'll be executing it from 14980Sstevel@tonic-gate * a copied version in a different area of memory, thus 14990Sstevel@tonic-gate * the relative offsets will be bogus. 15000Sstevel@tonic-gate * 15010Sstevel@tonic-gate * Moreover, it must have the "__relocatable" suffix to inform DTrace 15020Sstevel@tonic-gate * providers (and anything else, for that matter) that this 15030Sstevel@tonic-gate * function's text is manually relocated elsewhere before it is 15040Sstevel@tonic-gate * executed. That is, it cannot be safely instrumented with any 15050Sstevel@tonic-gate * methodology that is PC-relative. 15060Sstevel@tonic-gate */ 15070Sstevel@tonic-gate static void 15080Sstevel@tonic-gate drmach_copy_rename_prog__relocatable(drmach_copy_rename_program_t *prog) 15090Sstevel@tonic-gate { 15100Sstevel@tonic-gate extern void drmach_exec_script_il(drmach_rename_script_t *rsp); 15110Sstevel@tonic-gate 15120Sstevel@tonic-gate drmach_mc_idle_script_t *isp; 15130Sstevel@tonic-gate struct memlist *ml; 15140Sstevel@tonic-gate int csize; 15150Sstevel@tonic-gate int lnsize; 15160Sstevel@tonic-gate uint64_t caddr; 15170Sstevel@tonic-gate 15180Sstevel@tonic-gate isp = (drmach_mc_idle_script_t *)prog->data; 15190Sstevel@tonic-gate 15200Sstevel@tonic-gate caddr = ecache_flushaddr; 15210Sstevel@tonic-gate csize = (cpunodes[CPU->cpu_id].ecache_size << 1); 15220Sstevel@tonic-gate lnsize = cpunodes[CPU->cpu_id].ecache_linesize; 15230Sstevel@tonic-gate 15240Sstevel@tonic-gate /* 15250Sstevel@tonic-gate * DO COPY. 15260Sstevel@tonic-gate */ 15270Sstevel@tonic-gate for (ml = prog->c_ml; ml; ml = ml->next) { 15280Sstevel@tonic-gate uint64_t s_pa, t_pa; 15290Sstevel@tonic-gate uint64_t nbytes; 15300Sstevel@tonic-gate 15310Sstevel@tonic-gate s_pa = prog->s_copybasepa + ml->address; 15320Sstevel@tonic-gate t_pa = prog->t_copybasepa + ml->address; 15330Sstevel@tonic-gate nbytes = ml->size; 15340Sstevel@tonic-gate 15350Sstevel@tonic-gate while (nbytes != 0ull) { 15360Sstevel@tonic-gate /* 15370Sstevel@tonic-gate * This copy does NOT use an ASI 15380Sstevel@tonic-gate * that avoids the Ecache, therefore 15390Sstevel@tonic-gate * the dst_pa addresses may remain 15400Sstevel@tonic-gate * in our Ecache after the dst_pa 15410Sstevel@tonic-gate * has been removed from the system. 15420Sstevel@tonic-gate * A subsequent write-back to memory 15430Sstevel@tonic-gate * will cause an ARB-stop because the 15440Sstevel@tonic-gate * physical address no longer exists 15450Sstevel@tonic-gate * in the system. Therefore we must 15460Sstevel@tonic-gate * flush out local Ecache after we 15470Sstevel@tonic-gate * finish the copy. 15480Sstevel@tonic-gate */ 15490Sstevel@tonic-gate 15500Sstevel@tonic-gate /* copy 32 bytes at src_pa to dst_pa */ 15510Sstevel@tonic-gate bcopy32_il(s_pa, t_pa); 15520Sstevel@tonic-gate 15530Sstevel@tonic-gate /* increment by 32 bytes */ 15540Sstevel@tonic-gate s_pa += (4 * sizeof (uint64_t)); 15550Sstevel@tonic-gate t_pa += (4 * sizeof (uint64_t)); 15560Sstevel@tonic-gate 15570Sstevel@tonic-gate /* decrement by 32 bytes */ 15580Sstevel@tonic-gate nbytes -= (4 * sizeof (uint64_t)); 15590Sstevel@tonic-gate } 15600Sstevel@tonic-gate } 15610Sstevel@tonic-gate 15620Sstevel@tonic-gate /* 15630Sstevel@tonic-gate * Since bcopy32_il() does NOT use an ASI to bypass 15640Sstevel@tonic-gate * the Ecache, we need to flush our Ecache after 15650Sstevel@tonic-gate * the copy is complete. 15660Sstevel@tonic-gate */ 15670Sstevel@tonic-gate flush_ecache_il(caddr, csize, lnsize); /* inline version */ 15680Sstevel@tonic-gate 15690Sstevel@tonic-gate /* 15700Sstevel@tonic-gate * Wait for MCs to go idle. 15710Sstevel@tonic-gate */ 15720Sstevel@tonic-gate do { 15730Sstevel@tonic-gate register int t = 10; 15740Sstevel@tonic-gate register uint_t v; 15750Sstevel@tonic-gate 15760Sstevel@tonic-gate /* loop t cycles waiting for each mc to indicate it's idle */ 15770Sstevel@tonic-gate do { 15780Sstevel@tonic-gate v = ldphysio_il(isp->idle_addr) 15790Sstevel@tonic-gate & STARFIRE_MC_IDLE_MASK; 15800Sstevel@tonic-gate 15810Sstevel@tonic-gate } while (v != STARFIRE_MC_IDLE_MASK && t-- > 0); 15820Sstevel@tonic-gate 15830Sstevel@tonic-gate /* bailout if timedout */ 15840Sstevel@tonic-gate if (t <= 0) { 15850Sstevel@tonic-gate prog->restless_mc = isp->mem; 15860Sstevel@tonic-gate return; 15870Sstevel@tonic-gate } 15880Sstevel@tonic-gate 15890Sstevel@tonic-gate isp += 1; 15900Sstevel@tonic-gate 15910Sstevel@tonic-gate /* stop if terminating zero has been reached */ 15920Sstevel@tonic-gate } while (isp->idle_addr != 0); 15930Sstevel@tonic-gate 15940Sstevel@tonic-gate /* advance passed terminating zero */ 15950Sstevel@tonic-gate isp += 1; 15960Sstevel@tonic-gate 15970Sstevel@tonic-gate /* 15980Sstevel@tonic-gate * The following inline assembly routine caches 15990Sstevel@tonic-gate * the rename script and then caches the code that 16000Sstevel@tonic-gate * will do the rename. This is necessary 16010Sstevel@tonic-gate * so that we don't have any memory references during 16020Sstevel@tonic-gate * the reprogramming. We accomplish this by first 16030Sstevel@tonic-gate * jumping through the code to guarantee it's cached 16040Sstevel@tonic-gate * before we actually execute it. 16050Sstevel@tonic-gate */ 16060Sstevel@tonic-gate drmach_exec_script_il((drmach_rename_script_t *)isp); 16070Sstevel@tonic-gate } 16080Sstevel@tonic-gate 16090Sstevel@tonic-gate static void 16100Sstevel@tonic-gate drmach_copy_rename_end(void) 16110Sstevel@tonic-gate { 16120Sstevel@tonic-gate /* 16130Sstevel@tonic-gate * IMPORTANT: This function's location MUST be located immediately 16140Sstevel@tonic-gate * following drmach_copy_rename_prog__relocatable to 16150Sstevel@tonic-gate * accurately estimate its size. Note that this assumes 16160Sstevel@tonic-gate * the compiler keeps these functions in the order in 16170Sstevel@tonic-gate * which they appear :-o 16180Sstevel@tonic-gate */ 16190Sstevel@tonic-gate } 16200Sstevel@tonic-gate 16210Sstevel@tonic-gate sbd_error_t * 16220Sstevel@tonic-gate drmach_copy_rename_init(drmachid_t t_id, uint64_t t_slice_offset, 16230Sstevel@tonic-gate drmachid_t s_id, struct memlist *c_ml, drmachid_t *pgm_id) 16240Sstevel@tonic-gate { 16250Sstevel@tonic-gate drmach_device_t *s_mem; 16260Sstevel@tonic-gate drmach_device_t *t_mem; 16270Sstevel@tonic-gate struct memlist *x_ml; 16280Sstevel@tonic-gate uint64_t off_mask, s_copybasepa, t_copybasepa, t_basepa; 16290Sstevel@tonic-gate int len; 16300Sstevel@tonic-gate caddr_t bp, wp; 16310Sstevel@tonic-gate pda_handle_t ph; 16320Sstevel@tonic-gate sbd_error_t *err; 16330Sstevel@tonic-gate drmach_copy_rename_program_t *prog; 16340Sstevel@tonic-gate 16350Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(s_id)) 16360Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 16370Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(t_id)) 16380Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 16390Sstevel@tonic-gate s_mem = s_id; 16400Sstevel@tonic-gate t_mem = t_id; 16410Sstevel@tonic-gate 16420Sstevel@tonic-gate /* get starting physical address of target memory */ 16430Sstevel@tonic-gate err = drmach_mem_get_base_physaddr(t_id, &t_basepa); 16440Sstevel@tonic-gate if (err) 16450Sstevel@tonic-gate return (err); 16460Sstevel@tonic-gate 16470Sstevel@tonic-gate /* calculate slice offset mask from slice size */ 16480Sstevel@tonic-gate off_mask = mc_get_mem_alignment() - 1; 16490Sstevel@tonic-gate 16500Sstevel@tonic-gate /* calculate source and target base pa */ 16510Sstevel@tonic-gate s_copybasepa = c_ml->address; 16520Sstevel@tonic-gate t_copybasepa = t_basepa + ((c_ml->address & off_mask) - t_slice_offset); 16530Sstevel@tonic-gate 16540Sstevel@tonic-gate /* paranoia */ 16550Sstevel@tonic-gate ASSERT((c_ml->address & off_mask) >= t_slice_offset); 16560Sstevel@tonic-gate 16570Sstevel@tonic-gate /* adjust copy memlist addresses to be relative to copy base pa */ 16580Sstevel@tonic-gate x_ml = c_ml; 16590Sstevel@tonic-gate while (x_ml != NULL) { 16600Sstevel@tonic-gate x_ml->address -= s_copybasepa; 16610Sstevel@tonic-gate x_ml = x_ml->next; 16620Sstevel@tonic-gate } 16630Sstevel@tonic-gate 16640Sstevel@tonic-gate #ifdef DEBUG 16650Sstevel@tonic-gate { 16660Sstevel@tonic-gate uint64_t s_basepa, s_size, t_size; 16670Sstevel@tonic-gate 16680Sstevel@tonic-gate x_ml = c_ml; 16690Sstevel@tonic-gate while (x_ml->next != NULL) 16700Sstevel@tonic-gate x_ml = x_ml->next; 16710Sstevel@tonic-gate 16720Sstevel@tonic-gate DRMACH_PR("source copy span: base pa 0x%llx, end pa 0x%llx\n", 16730Sstevel@tonic-gate s_copybasepa, 16740Sstevel@tonic-gate s_copybasepa + x_ml->address + x_ml->size); 16750Sstevel@tonic-gate 16760Sstevel@tonic-gate DRMACH_PR("target copy span: base pa 0x%llx, end pa 0x%llx\n", 16770Sstevel@tonic-gate t_copybasepa, 16780Sstevel@tonic-gate t_copybasepa + x_ml->address + x_ml->size); 16790Sstevel@tonic-gate 16800Sstevel@tonic-gate DRMACH_PR("copy memlist (relative to copy base pa):\n"); 16810Sstevel@tonic-gate MEMLIST_DUMP(c_ml); 16820Sstevel@tonic-gate 16830Sstevel@tonic-gate err = drmach_mem_get_base_physaddr(s_id, &s_basepa); 16840Sstevel@tonic-gate ASSERT(err == NULL); 16850Sstevel@tonic-gate 16860Sstevel@tonic-gate err = drmach_mem_get_size(s_id, &s_size); 16870Sstevel@tonic-gate ASSERT(err == NULL); 16880Sstevel@tonic-gate 16890Sstevel@tonic-gate err = drmach_mem_get_size(t_id, &t_size); 16900Sstevel@tonic-gate ASSERT(err == NULL); 16910Sstevel@tonic-gate 16920Sstevel@tonic-gate DRMACH_PR("current source base pa 0x%llx, size 0x%llx\n", 16930Sstevel@tonic-gate s_basepa, s_size); 16940Sstevel@tonic-gate DRMACH_PR("current target base pa 0x%llx, size 0x%llx\n", 16950Sstevel@tonic-gate t_basepa, t_size); 16960Sstevel@tonic-gate 16970Sstevel@tonic-gate ASSERT(s_copybasepa + x_ml->address + x_ml->size <= s_basepa + s_size); 16980Sstevel@tonic-gate ASSERT(t_copybasepa + x_ml->address + x_ml->size <= t_basepa + t_size); 16990Sstevel@tonic-gate } 17000Sstevel@tonic-gate #endif 17010Sstevel@tonic-gate 17020Sstevel@tonic-gate ph = drmach_pda_open(); 17030Sstevel@tonic-gate if (ph == NULL) 17040Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 17050Sstevel@tonic-gate 17060Sstevel@tonic-gate /* 17070Sstevel@tonic-gate * bp will be page aligned, since we're calling 17080Sstevel@tonic-gate * kmem_zalloc() with an exact multiple of PAGESIZE. 17090Sstevel@tonic-gate */ 17100Sstevel@tonic-gate wp = bp = kmem_zalloc(PAGESIZE, KM_SLEEP); 17110Sstevel@tonic-gate 17120Sstevel@tonic-gate /* allocate space for copy rename struct */ 17130Sstevel@tonic-gate len = sizeof (drmach_copy_rename_program_t); 17140Sstevel@tonic-gate DRMACH_PR("prog = 0x%p, header len %d\n", wp, len); 17150Sstevel@tonic-gate prog = (drmach_copy_rename_program_t *)wp; 17160Sstevel@tonic-gate wp += (len + ecache_alignsize - 1) & ~ (ecache_alignsize - 1); 17170Sstevel@tonic-gate 17180Sstevel@tonic-gate /* 17190Sstevel@tonic-gate * Copy the code for the copy-rename routine into 17200Sstevel@tonic-gate * a page aligned piece of memory. We do this to guarantee 17210Sstevel@tonic-gate * that we're executing within the same page and thus reduce 17220Sstevel@tonic-gate * the possibility of cache collisions between different 17230Sstevel@tonic-gate * pages. 17240Sstevel@tonic-gate */ 17250Sstevel@tonic-gate len = (int)((ulong_t)drmach_copy_rename_end - 17260Sstevel@tonic-gate (ulong_t)drmach_copy_rename_prog__relocatable); 17270Sstevel@tonic-gate ASSERT(wp + len < bp + PAGESIZE); 17280Sstevel@tonic-gate bcopy((caddr_t)drmach_copy_rename_prog__relocatable, wp, len); 17290Sstevel@tonic-gate 17300Sstevel@tonic-gate DRMACH_PR("copy-rename function 0x%p, len %d\n", wp, len); 17310Sstevel@tonic-gate prog->run = (void (*)())wp; 17320Sstevel@tonic-gate wp += (len + ecache_alignsize - 1) & ~ (ecache_alignsize - 1); 17330Sstevel@tonic-gate 17340Sstevel@tonic-gate /* 17350Sstevel@tonic-gate * Prepare data page that will contain script of 17360Sstevel@tonic-gate * operations to perform during copy-rename. 17370Sstevel@tonic-gate * Allocate temporary buffer to hold script. 17380Sstevel@tonic-gate */ 17390Sstevel@tonic-gate err = drmach_prep_rename_script(s_mem, t_mem, t_slice_offset, 17400Sstevel@tonic-gate wp, PAGESIZE - (wp - bp)); 17410Sstevel@tonic-gate if (err) { 17420Sstevel@tonic-gate (void) drmach_copy_rename_fini(prog); 17430Sstevel@tonic-gate return (err); 17440Sstevel@tonic-gate } 17450Sstevel@tonic-gate 17460Sstevel@tonic-gate DRMACH_PR("copy-rename script 0x%p, len %d\n", wp, len); 17470Sstevel@tonic-gate prog->data = wp; 17480Sstevel@tonic-gate wp += (len + ecache_alignsize - 1) & ~ (ecache_alignsize - 1); 17490Sstevel@tonic-gate 17500Sstevel@tonic-gate prog->ph = ph; 17510Sstevel@tonic-gate prog->s_copybasepa = s_copybasepa; 17520Sstevel@tonic-gate prog->t_copybasepa = t_copybasepa; 17530Sstevel@tonic-gate prog->c_ml = c_ml; 17540Sstevel@tonic-gate *pgm_id = prog; 17550Sstevel@tonic-gate 17560Sstevel@tonic-gate return (NULL); 17570Sstevel@tonic-gate } 17580Sstevel@tonic-gate 17590Sstevel@tonic-gate sbd_error_t * 17600Sstevel@tonic-gate drmach_copy_rename_fini(drmachid_t id) 17610Sstevel@tonic-gate { 17620Sstevel@tonic-gate drmach_copy_rename_program_t *prog = id; 17630Sstevel@tonic-gate sbd_error_t *err = NULL; 17640Sstevel@tonic-gate 17650Sstevel@tonic-gate if (prog->c_ml != NULL) 17660Sstevel@tonic-gate memlist_delete(prog->c_ml); 17670Sstevel@tonic-gate 17680Sstevel@tonic-gate if (prog->ph != NULL) 17690Sstevel@tonic-gate pda_close(prog->ph); 17700Sstevel@tonic-gate 17710Sstevel@tonic-gate if (prog->restless_mc != 0) { 17720Sstevel@tonic-gate cmn_err(CE_WARN, "MC did not idle; OBP Node 0x%x", 17730Sstevel@tonic-gate (uint_t)drmach_node_get_dnode(prog->restless_mc->node)); 17740Sstevel@tonic-gate 17750Sstevel@tonic-gate err = DRMACH_INTERNAL_ERROR(); 17760Sstevel@tonic-gate } 17770Sstevel@tonic-gate 17780Sstevel@tonic-gate kmem_free(prog, PAGESIZE); 17790Sstevel@tonic-gate 17800Sstevel@tonic-gate return (err); 17810Sstevel@tonic-gate } 17820Sstevel@tonic-gate 17830Sstevel@tonic-gate static sbd_error_t * 17840Sstevel@tonic-gate drmach_io_new(drmach_device_t *dp) 17850Sstevel@tonic-gate { 17860Sstevel@tonic-gate static sbd_error_t *drmach_io_release(drmachid_t); 17870Sstevel@tonic-gate static sbd_error_t *drmach_io_status(drmachid_t, drmach_status_t *); 17880Sstevel@tonic-gate 17890Sstevel@tonic-gate sbd_error_t *err; 17900Sstevel@tonic-gate int portid; 17910Sstevel@tonic-gate 17920Sstevel@tonic-gate err = drmach_device_get_prop(dp, "upa-portid", &portid); 17930Sstevel@tonic-gate if (err == NULL) { 17940Sstevel@tonic-gate ASSERT(portid & 0x40); 17950Sstevel@tonic-gate dp->unum = portid & 1; 17960Sstevel@tonic-gate } 17970Sstevel@tonic-gate 17980Sstevel@tonic-gate dp->cm.isa = (void *)drmach_io_new; 17990Sstevel@tonic-gate dp->cm.release = drmach_io_release; 18000Sstevel@tonic-gate dp->cm.status = drmach_io_status; 18010Sstevel@tonic-gate 18020Sstevel@tonic-gate snprintf(dp->cm.name, sizeof (dp->cm.name), "%s%d", dp->type, dp->unum); 18030Sstevel@tonic-gate 18040Sstevel@tonic-gate return (err); 18050Sstevel@tonic-gate } 18060Sstevel@tonic-gate 18070Sstevel@tonic-gate static void 18080Sstevel@tonic-gate drmach_iopc_op(pda_handle_t ph, drmach_iopc_op_t op) 18090Sstevel@tonic-gate { 18100Sstevel@tonic-gate register int b; 18110Sstevel@tonic-gate 18120Sstevel@tonic-gate for (b = 0; b < MAX_BOARDS; b++) { 18130Sstevel@tonic-gate int p; 18140Sstevel@tonic-gate ushort_t bda_ioc; 18150Sstevel@tonic-gate board_desc_t *bdesc; 18160Sstevel@tonic-gate 18170Sstevel@tonic-gate if (pda_board_present(ph, b) == 0) 18180Sstevel@tonic-gate continue; 18190Sstevel@tonic-gate 18200Sstevel@tonic-gate bdesc = (board_desc_t *)pda_get_board_info(ph, b); 18210Sstevel@tonic-gate /* 18220Sstevel@tonic-gate * Update PCs for IOCs. 18230Sstevel@tonic-gate */ 18240Sstevel@tonic-gate bda_ioc = bdesc->bda_ioc; 18250Sstevel@tonic-gate for (p = 0; p < MAX_IOCS; p++) { 18260Sstevel@tonic-gate u_longlong_t idle_addr; 18270Sstevel@tonic-gate uchar_t value; 18280Sstevel@tonic-gate 18290Sstevel@tonic-gate if (BDA_NBL(bda_ioc, p) != BDAN_GOOD) 18300Sstevel@tonic-gate continue; 18310Sstevel@tonic-gate 18320Sstevel@tonic-gate idle_addr = STARFIRE_BB_PC_ADDR(b, p, 1); 18330Sstevel@tonic-gate 18340Sstevel@tonic-gate switch (op) { 18350Sstevel@tonic-gate case DO_PAUSE: 18360Sstevel@tonic-gate value = STARFIRE_BB_PC_PAUSE(p); 18370Sstevel@tonic-gate break; 18380Sstevel@tonic-gate 18390Sstevel@tonic-gate case DO_IDLE: 18400Sstevel@tonic-gate value = STARFIRE_BB_PC_IDLE(p); 18410Sstevel@tonic-gate break; 18420Sstevel@tonic-gate 18430Sstevel@tonic-gate case DO_UNPAUSE: 18440Sstevel@tonic-gate value = ldbphysio(idle_addr); 18450Sstevel@tonic-gate value &= ~STARFIRE_BB_PC_PAUSE(p); 18460Sstevel@tonic-gate break; 18470Sstevel@tonic-gate 18480Sstevel@tonic-gate case DO_UNIDLE: 18490Sstevel@tonic-gate value = ldbphysio(idle_addr); 18500Sstevel@tonic-gate value &= ~STARFIRE_BB_PC_IDLE(p); 18510Sstevel@tonic-gate break; 18520Sstevel@tonic-gate 18530Sstevel@tonic-gate default: 18540Sstevel@tonic-gate cmn_err(CE_PANIC, 18550Sstevel@tonic-gate "drmach_iopc_op: unknown op (%d)", 18560Sstevel@tonic-gate (int)op); 18570Sstevel@tonic-gate /*NOTREACHED*/ 18580Sstevel@tonic-gate } 18590Sstevel@tonic-gate stbphysio(idle_addr, value); 18600Sstevel@tonic-gate } 18610Sstevel@tonic-gate } 18620Sstevel@tonic-gate } 18630Sstevel@tonic-gate 18640Sstevel@tonic-gate void 18650Sstevel@tonic-gate drmach_copy_rename(drmachid_t id) 18660Sstevel@tonic-gate { 18670Sstevel@tonic-gate drmach_copy_rename_program_t *prog = id; 18680Sstevel@tonic-gate uint64_t neer; 18690Sstevel@tonic-gate 18700Sstevel@tonic-gate /* 18710Sstevel@tonic-gate * UPA IDLE 18720Sstevel@tonic-gate * Protocol = PAUSE -> IDLE -> UNPAUSE 18730Sstevel@tonic-gate * In reality since we only "idle" the IOPCs it's sufficient 18740Sstevel@tonic-gate * to just issue the IDLE operation since (in theory) all IOPCs 18750Sstevel@tonic-gate * in the field are PC6. However, we'll be robust and do the 18760Sstevel@tonic-gate * proper workaround protocol so that we never have to worry! 18770Sstevel@tonic-gate */ 18780Sstevel@tonic-gate drmach_iopc_op(prog->ph, DO_PAUSE); 18790Sstevel@tonic-gate drmach_iopc_op(prog->ph, DO_IDLE); 18800Sstevel@tonic-gate DELAY(100); 18810Sstevel@tonic-gate drmach_iopc_op(prog->ph, DO_UNPAUSE); 18820Sstevel@tonic-gate DELAY(100); 18830Sstevel@tonic-gate 18840Sstevel@tonic-gate /* disable CE reporting */ 18850Sstevel@tonic-gate neer = get_error_enable(); 18860Sstevel@tonic-gate set_error_enable(neer & ~EER_CEEN); 18870Sstevel@tonic-gate 18880Sstevel@tonic-gate /* run the copy/rename program */ 18890Sstevel@tonic-gate prog->run(prog); 18900Sstevel@tonic-gate 18910Sstevel@tonic-gate /* enable CE reporting */ 18920Sstevel@tonic-gate set_error_enable(neer); 18930Sstevel@tonic-gate 18940Sstevel@tonic-gate /* 18950Sstevel@tonic-gate * UPA UNIDLE 18960Sstevel@tonic-gate * Protocol = UNIDLE 18970Sstevel@tonic-gate */ 18980Sstevel@tonic-gate drmach_iopc_op(prog->ph, DO_UNIDLE); 18990Sstevel@tonic-gate DELAY(100); 19000Sstevel@tonic-gate } 19010Sstevel@tonic-gate 19020Sstevel@tonic-gate /* 19030Sstevel@tonic-gate * The counter-timer and perf-counter nodes are not being cleaned 19040Sstevel@tonic-gate * up after a board that was present at start of day is detached. 19050Sstevel@tonic-gate * If the board has become unconfigured with this operation, walk 19060Sstevel@tonic-gate * the prom tree and find all counter-timer and perf-counter nodes 19070Sstevel@tonic-gate * that have the same board number as the board that was just 19080Sstevel@tonic-gate * unconfigured and remove them. 19090Sstevel@tonic-gate */ 19100Sstevel@tonic-gate static sbd_error_t * 19110Sstevel@tonic-gate drmach_remove_counter_nodes(drmachid_t id) 19120Sstevel@tonic-gate { 19130Sstevel@tonic-gate int num; 19140Sstevel@tonic-gate char name[OBP_MAXDRVNAME]; 1915789Sahrens pnode_t child; 19160Sstevel@tonic-gate dev_info_t *dip; 19170Sstevel@tonic-gate sbd_error_t *err; 19180Sstevel@tonic-gate drmach_status_t stat; 19190Sstevel@tonic-gate drmach_board_t *bp; 19200Sstevel@tonic-gate 19210Sstevel@tonic-gate if (!DRMACH_IS_BOARD_ID(id)) { 19220Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 19230Sstevel@tonic-gate } 19240Sstevel@tonic-gate 19250Sstevel@tonic-gate if ((err = drmach_board_status(id, &stat)) != NULL) { 19260Sstevel@tonic-gate return (err); 19270Sstevel@tonic-gate } 19280Sstevel@tonic-gate 19290Sstevel@tonic-gate /* 19300Sstevel@tonic-gate * Only clean up the counter-timer and perf-counter 19310Sstevel@tonic-gate * nodes when the entire board is unconfigured. 19320Sstevel@tonic-gate */ 19330Sstevel@tonic-gate if (stat.configured) { 19340Sstevel@tonic-gate return (NULL); 19350Sstevel@tonic-gate } 19360Sstevel@tonic-gate 19370Sstevel@tonic-gate bp = (drmach_board_t *)id; 19380Sstevel@tonic-gate 19390Sstevel@tonic-gate err = NULL; 19400Sstevel@tonic-gate 19410Sstevel@tonic-gate for (child = prom_childnode(prom_rootnode()); child != OBP_NONODE; 19420Sstevel@tonic-gate child = prom_nextnode(child)) { 19430Sstevel@tonic-gate 19440Sstevel@tonic-gate if (prom_getprop(child, OBP_BOARDNUM, (caddr_t)&num) == -1) { 19450Sstevel@tonic-gate continue; 19460Sstevel@tonic-gate } 19470Sstevel@tonic-gate 19480Sstevel@tonic-gate if (bp->bnum != num) { 19490Sstevel@tonic-gate continue; 19500Sstevel@tonic-gate } 19510Sstevel@tonic-gate 19520Sstevel@tonic-gate if (prom_getprop(child, OBP_NAME, (caddr_t)name) == -1) { 19530Sstevel@tonic-gate continue; 19540Sstevel@tonic-gate } 19550Sstevel@tonic-gate 19560Sstevel@tonic-gate if (strncmp(name, MISC_COUNTER_TIMER_DEVNAME, OBP_MAXDRVNAME) && 19570Sstevel@tonic-gate strncmp(name, MISC_PERF_COUNTER_DEVNAME, OBP_MAXDRVNAME)) { 19580Sstevel@tonic-gate continue; 19590Sstevel@tonic-gate } 19600Sstevel@tonic-gate 19610Sstevel@tonic-gate /* Root node doesn't have to be held */ 19620Sstevel@tonic-gate dip = e_ddi_nodeid_to_dip(child); 19630Sstevel@tonic-gate 19640Sstevel@tonic-gate /* 19650Sstevel@tonic-gate * If the node is only in the OBP tree, then 19660Sstevel@tonic-gate * we don't have to remove it. 19670Sstevel@tonic-gate */ 19680Sstevel@tonic-gate if (dip) { 19690Sstevel@tonic-gate dev_info_t *fdip = NULL; 19700Sstevel@tonic-gate 19710Sstevel@tonic-gate DRMACH_PR("removing %s devinfo node\n", name); 19720Sstevel@tonic-gate 19730Sstevel@tonic-gate e_ddi_branch_hold(dip); 19740Sstevel@tonic-gate ddi_release_devi(dip); /* held in e_ddi_nodeid_to_dip */ 19750Sstevel@tonic-gate 19760Sstevel@tonic-gate if (e_ddi_branch_destroy(dip, &fdip, 0)) { 19770Sstevel@tonic-gate char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 19780Sstevel@tonic-gate 19790Sstevel@tonic-gate /* 19800Sstevel@tonic-gate * If non-NULL, fdip is held and must be 19810Sstevel@tonic-gate * released. 19820Sstevel@tonic-gate */ 19830Sstevel@tonic-gate if (fdip != NULL) { 19840Sstevel@tonic-gate (void) ddi_pathname(fdip, path); 19850Sstevel@tonic-gate ddi_release_devi(fdip); 19860Sstevel@tonic-gate } else { 19870Sstevel@tonic-gate (void) ddi_pathname(dip, path); 19880Sstevel@tonic-gate } 19890Sstevel@tonic-gate 19900Sstevel@tonic-gate err = drerr_new(1, ESTF_DRVFAIL, path); 19910Sstevel@tonic-gate kmem_free(path, MAXPATHLEN); 19920Sstevel@tonic-gate e_ddi_branch_rele(dip); 19930Sstevel@tonic-gate break; 19940Sstevel@tonic-gate } 19950Sstevel@tonic-gate } 19960Sstevel@tonic-gate } 19970Sstevel@tonic-gate 19980Sstevel@tonic-gate return (err); 19990Sstevel@tonic-gate } 20000Sstevel@tonic-gate 20010Sstevel@tonic-gate /*ARGSUSED*/ 20020Sstevel@tonic-gate sbd_error_t * 20030Sstevel@tonic-gate drmach_pre_op(int cmd, drmachid_t id, drmach_opts_t *opts) 20040Sstevel@tonic-gate { 20050Sstevel@tonic-gate /* allow status and ncm operations to always succeed */ 20060Sstevel@tonic-gate if ((cmd == SBD_CMD_STATUS) || (cmd == SBD_CMD_GETNCM)) { 20070Sstevel@tonic-gate return (NULL); 20080Sstevel@tonic-gate } 20090Sstevel@tonic-gate 20100Sstevel@tonic-gate /* check all other commands for the required option string */ 20110Sstevel@tonic-gate if ((opts->size > 0) && (opts->copts != NULL)) { 20120Sstevel@tonic-gate 20130Sstevel@tonic-gate DRMACH_PR("platform options: %s\n", opts->copts); 20140Sstevel@tonic-gate 20150Sstevel@tonic-gate if (strstr(opts->copts, "xfdr") != NULL) { 20160Sstevel@tonic-gate return (NULL); 20170Sstevel@tonic-gate } 20180Sstevel@tonic-gate } 20190Sstevel@tonic-gate 20200Sstevel@tonic-gate return (drerr_new(0, ESTF_SUPPORT, NULL)); 20210Sstevel@tonic-gate } 20220Sstevel@tonic-gate 20230Sstevel@tonic-gate /*ARGSUSED*/ 20240Sstevel@tonic-gate sbd_error_t * 20250Sstevel@tonic-gate drmach_post_op(int cmd, drmachid_t id, drmach_opts_t *opts) 20260Sstevel@tonic-gate { 20270Sstevel@tonic-gate sbd_error_t *err = NULL; 20280Sstevel@tonic-gate 20290Sstevel@tonic-gate switch (cmd) { 20300Sstevel@tonic-gate case SBD_CMD_UNCONFIGURE: 20310Sstevel@tonic-gate 20320Sstevel@tonic-gate err = drmach_remove_counter_nodes(id); 20330Sstevel@tonic-gate break; 20340Sstevel@tonic-gate 20350Sstevel@tonic-gate case SBD_CMD_CONFIGURE: 20360Sstevel@tonic-gate case SBD_CMD_DISCONNECT: 20370Sstevel@tonic-gate case SBD_CMD_CONNECT: 20380Sstevel@tonic-gate case SBD_CMD_GETNCM: 20390Sstevel@tonic-gate case SBD_CMD_STATUS: 20400Sstevel@tonic-gate break; 20410Sstevel@tonic-gate 20420Sstevel@tonic-gate default: 20430Sstevel@tonic-gate break; 20440Sstevel@tonic-gate } 20450Sstevel@tonic-gate 20460Sstevel@tonic-gate return (err); 20470Sstevel@tonic-gate } 20480Sstevel@tonic-gate 20490Sstevel@tonic-gate sbd_error_t * 20500Sstevel@tonic-gate drmach_board_assign(int bnum, drmachid_t *id) 20510Sstevel@tonic-gate { 20520Sstevel@tonic-gate sbd_error_t *err; 20530Sstevel@tonic-gate 20540Sstevel@tonic-gate if (!drmach_initialized && drmach_init() == -1) { 20550Sstevel@tonic-gate err = DRMACH_INTERNAL_ERROR(); 20560Sstevel@tonic-gate } else if (drmach_array_get(drmach_boards, bnum, id) == -1) { 20570Sstevel@tonic-gate err = drerr_new(1, ESTF_BNUM, "%d", bnum); 20580Sstevel@tonic-gate } else if (*id != NULL) { 20590Sstevel@tonic-gate err = NULL; 20600Sstevel@tonic-gate } else { 20610Sstevel@tonic-gate drmach_board_t *bp; 20620Sstevel@tonic-gate 20630Sstevel@tonic-gate *id = (drmachid_t)drmach_board_new(bnum); 20640Sstevel@tonic-gate bp = *id; 20650Sstevel@tonic-gate bp->assigned = 1; 20660Sstevel@tonic-gate err = NULL; 20670Sstevel@tonic-gate } 20680Sstevel@tonic-gate 20690Sstevel@tonic-gate return (err); 20700Sstevel@tonic-gate } 20710Sstevel@tonic-gate 20720Sstevel@tonic-gate static int 20730Sstevel@tonic-gate drmach_attach_board(void *arg) 20740Sstevel@tonic-gate { 20750Sstevel@tonic-gate drmach_board_t *obj = (drmach_board_t *)arg; 20760Sstevel@tonic-gate cpuset_t cset; 20770Sstevel@tonic-gate int retval; 20780Sstevel@tonic-gate 20790Sstevel@tonic-gate /* 20800Sstevel@tonic-gate * OBP disables traps during the board probe. 20810Sstevel@tonic-gate * So, in order to prevent cross-call/cross-trap timeouts, 20820Sstevel@tonic-gate * and thus panics, we effectively block anybody from 20830Sstevel@tonic-gate * issuing xc's/xt's by doing a promsafe_xc_attention. 20840Sstevel@tonic-gate * In the previous version of Starfire DR (2.6), a timeout 20850Sstevel@tonic-gate * suspension mechanism was implemented in the send-mondo 20860Sstevel@tonic-gate * assembly. That mechanism is unnecessary with the 20870Sstevel@tonic-gate * existence of xc_attention/xc_dismissed. 20880Sstevel@tonic-gate */ 20890Sstevel@tonic-gate cset = cpu_ready_set; 20900Sstevel@tonic-gate promsafe_xc_attention(cset); 20910Sstevel@tonic-gate 20920Sstevel@tonic-gate retval = prom_starfire_add_brd(obj->connect_cpuid); 20930Sstevel@tonic-gate 20940Sstevel@tonic-gate xc_dismissed(cset); 20950Sstevel@tonic-gate 20960Sstevel@tonic-gate return (retval); 20970Sstevel@tonic-gate } 20980Sstevel@tonic-gate 20990Sstevel@tonic-gate sbd_error_t * 21000Sstevel@tonic-gate drmach_board_connect(drmachid_t id, drmach_opts_t *opts) 21010Sstevel@tonic-gate { 21020Sstevel@tonic-gate drmach_board_t *obj = (drmach_board_t *)id; 21030Sstevel@tonic-gate int retval; 21040Sstevel@tonic-gate sbd_error_t *err; 21050Sstevel@tonic-gate char *cptr, *copts; 21060Sstevel@tonic-gate 21070Sstevel@tonic-gate if (!DRMACH_IS_BOARD_ID(id)) 21080Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 21090Sstevel@tonic-gate 21100Sstevel@tonic-gate if (opts->size > 0) 21110Sstevel@tonic-gate copts = opts->copts; 21120Sstevel@tonic-gate 21130Sstevel@tonic-gate if ((cptr = strstr(copts, "cpuid=")) != NULL) { 21140Sstevel@tonic-gate int cpuid; 21150Sstevel@tonic-gate 21160Sstevel@tonic-gate cptr += strlen("cpuid="); 21170Sstevel@tonic-gate cpuid = stoi(&cptr); 21180Sstevel@tonic-gate 21190Sstevel@tonic-gate if (DRMACH_CPUID2BNUM(cpuid) == obj->bnum) { 21200Sstevel@tonic-gate obj->connect_cpuid = cpuid; 21210Sstevel@tonic-gate obj->assigned = 1; 21220Sstevel@tonic-gate } else 21230Sstevel@tonic-gate return (drerr_new(1, ESTF_SETCPUVAL, "%d", cpuid)); 21240Sstevel@tonic-gate } else { 21250Sstevel@tonic-gate /* cpuid was not specified */ 21260Sstevel@tonic-gate obj->connect_cpuid = -1; 21270Sstevel@tonic-gate } 21280Sstevel@tonic-gate 21290Sstevel@tonic-gate if (obj->connect_cpuid == -1) { 21300Sstevel@tonic-gate err = drerr_new(1, ESTF_NOCPUID, obj->cm.name); 21310Sstevel@tonic-gate return (err); 21320Sstevel@tonic-gate } 21330Sstevel@tonic-gate 21340Sstevel@tonic-gate cmn_err(CE_CONT, "DRMACH: PROM attach %s CPU %d\n", 21350Sstevel@tonic-gate obj->cm.name, obj->connect_cpuid); 21360Sstevel@tonic-gate 21370Sstevel@tonic-gate retval = prom_tree_update(drmach_attach_board, obj); 21380Sstevel@tonic-gate 21390Sstevel@tonic-gate if (retval == 0) 21400Sstevel@tonic-gate err = NULL; 21410Sstevel@tonic-gate else { 21420Sstevel@tonic-gate cmn_err(CE_WARN, "prom error: prom_starfire_add_brd(%d) " 21430Sstevel@tonic-gate "returned %d", obj->connect_cpuid, retval); 21440Sstevel@tonic-gate 21450Sstevel@tonic-gate err = drerr_new(1, ESTF_PROBE, obj->cm.name); 21460Sstevel@tonic-gate } 21470Sstevel@tonic-gate 21480Sstevel@tonic-gate obj->connect_cpuid = -1; 21490Sstevel@tonic-gate 21500Sstevel@tonic-gate return (err); 21510Sstevel@tonic-gate } 21520Sstevel@tonic-gate 21530Sstevel@tonic-gate /*ARGSUSED*/ 21540Sstevel@tonic-gate sbd_error_t * 21550Sstevel@tonic-gate drmach_board_disconnect(drmachid_t id, drmach_opts_t *opts) 21560Sstevel@tonic-gate { 215790Sha137994 drmach_board_t *bp; 215890Sha137994 int rv; 215990Sha137994 int d_idx; /* device index */ 216090Sha137994 drmachid_t d_id; /* device ID */ 216190Sha137994 sbd_error_t *err; 216290Sha137994 216390Sha137994 if (!DRMACH_IS_BOARD_ID(id)) 216490Sha137994 return (drerr_new(0, ESTF_INAPPROP, NULL)); 216590Sha137994 216690Sha137994 bp = id; 216790Sha137994 216890Sha137994 /* 216990Sha137994 * We need to make sure all of the board's device nodes 217090Sha137994 * have been removed from the Solaris device tree before 217190Sha137994 * continuing with the disconnect. Otherwise, we could 217290Sha137994 * disconnect the board and remove the OBP device tree 217390Sha137994 * nodes with Solaris device tree nodes remaining. 217490Sha137994 * 217590Sha137994 * On Starfire, Solaris device tree nodes are deleted 217690Sha137994 * during unconfigure by drmach_unconfigure(). It's 217790Sha137994 * necessary to do this here because drmach_unconfigure() 217890Sha137994 * failures are not handled during unconfigure. 217990Sha137994 */ 218090Sha137994 if (bp->devices) { 218190Sha137994 rv = drmach_array_first(bp->devices, &d_idx, &d_id); 218290Sha137994 while (rv == 0) { 218390Sha137994 err = drmach_unconfigure(d_id, DRMACH_DEVI_REMOVE); 218490Sha137994 if (err) 218590Sha137994 return (err); 218690Sha137994 218790Sha137994 rv = drmach_array_next(bp->devices, &d_idx, &d_id); 218890Sha137994 } 218990Sha137994 } 219090Sha137994 219190Sha137994 /* 219290Sha137994 * Starfire board Solaris device tree counter nodes, 219390Sha137994 * which are only present on start-of-day boards, are 219490Sha137994 * removed in the dr_post_op() code flow after the 219590Sha137994 * board is unconfigured. We call the counter node 219690Sha137994 * removal function here because unconfigure errors 219790Sha137994 * can cause the dr_post_op() function to be skipped 219890Sha137994 * after an unconfigure operation even though all of 219990Sha137994 * the board's devices have been transitioned to the 220090Sha137994 * unconfigured state. 220190Sha137994 */ 220290Sha137994 err = drmach_remove_counter_nodes(id); 220390Sha137994 if (err) 220490Sha137994 return (err); 220590Sha137994 22060Sstevel@tonic-gate return (NULL); 22070Sstevel@tonic-gate } 22080Sstevel@tonic-gate 22090Sstevel@tonic-gate static int 22100Sstevel@tonic-gate drmach_board_find_devices_cb(drmach_node_walk_args_t *args) 22110Sstevel@tonic-gate { 22120Sstevel@tonic-gate drmach_node_t *node = args->node; 22130Sstevel@tonic-gate drmach_board_cb_data_t *data = args->data; 22140Sstevel@tonic-gate drmach_board_t *obj = data->obj; 22150Sstevel@tonic-gate 22160Sstevel@tonic-gate int rv; 22170Sstevel@tonic-gate int bnum; 22180Sstevel@tonic-gate drmach_device_t *device; 22190Sstevel@tonic-gate 22200Sstevel@tonic-gate rv = drmach_node_get_prop(node, OBP_BOARDNUM, &bnum); 22210Sstevel@tonic-gate if (rv) { 22220Sstevel@tonic-gate /* 22230Sstevel@tonic-gate * if the node does not have a board# property, then 22240Sstevel@tonic-gate * by that information alone it is known that drmach 22250Sstevel@tonic-gate * is not interested in it. 22260Sstevel@tonic-gate */ 22270Sstevel@tonic-gate return (0); 22280Sstevel@tonic-gate } else if (bnum != obj->bnum) 22290Sstevel@tonic-gate return (0); 22300Sstevel@tonic-gate 22310Sstevel@tonic-gate /* 22320Sstevel@tonic-gate * Create a device data structure from this node data. 22330Sstevel@tonic-gate * The call may yield nothing if the node is not of interest 22340Sstevel@tonic-gate * to drmach. 22350Sstevel@tonic-gate */ 22360Sstevel@tonic-gate data->err = drmach_device_new(node, obj, &device); 22370Sstevel@tonic-gate if (data->err) 22380Sstevel@tonic-gate return (-1); 22390Sstevel@tonic-gate else if (device == NULL) { 22400Sstevel@tonic-gate /* 22410Sstevel@tonic-gate * drmach_device_new examined the node we passed in 22420Sstevel@tonic-gate * and determined that it was one not of interest to 22430Sstevel@tonic-gate * drmach. So, it is skipped. 22440Sstevel@tonic-gate */ 22450Sstevel@tonic-gate return (0); 22460Sstevel@tonic-gate } 22470Sstevel@tonic-gate 22480Sstevel@tonic-gate rv = drmach_array_set(obj->devices, data->ndevs++, device); 22490Sstevel@tonic-gate if (rv) { 22500Sstevel@tonic-gate drmach_device_dispose(device); 22510Sstevel@tonic-gate data->err = DRMACH_INTERNAL_ERROR(); 22520Sstevel@tonic-gate return (-1); 22530Sstevel@tonic-gate } 22540Sstevel@tonic-gate 22550Sstevel@tonic-gate data->err = (*data->found)(data->a, device->type, device->unum, device); 22560Sstevel@tonic-gate return (data->err == NULL ? 0 : -1); 22570Sstevel@tonic-gate } 22580Sstevel@tonic-gate 22590Sstevel@tonic-gate sbd_error_t * 22600Sstevel@tonic-gate drmach_board_find_devices(drmachid_t id, void *a, 22610Sstevel@tonic-gate sbd_error_t *(*found)(void *a, const char *, int, drmachid_t)) 22620Sstevel@tonic-gate { 22630Sstevel@tonic-gate extern int plat_max_cpu_units_per_board(); 22640Sstevel@tonic-gate extern int plat_max_mem_units_per_board(); 22650Sstevel@tonic-gate extern int plat_max_io_units_per_board(); 22660Sstevel@tonic-gate 22670Sstevel@tonic-gate drmach_board_t *obj = (drmach_board_t *)id; 22680Sstevel@tonic-gate sbd_error_t *err; 22690Sstevel@tonic-gate int max_devices; 22700Sstevel@tonic-gate int rv; 22710Sstevel@tonic-gate drmach_board_cb_data_t data; 22720Sstevel@tonic-gate 22730Sstevel@tonic-gate max_devices = plat_max_cpu_units_per_board(); 22740Sstevel@tonic-gate max_devices += plat_max_mem_units_per_board(); 22750Sstevel@tonic-gate max_devices += plat_max_io_units_per_board(); 22760Sstevel@tonic-gate 22770Sstevel@tonic-gate obj->devices = drmach_array_new(0, max_devices); 22780Sstevel@tonic-gate 22790Sstevel@tonic-gate data.obj = obj; 22800Sstevel@tonic-gate data.ndevs = 0; 22810Sstevel@tonic-gate data.found = found; 22820Sstevel@tonic-gate data.a = a; 22830Sstevel@tonic-gate data.err = NULL; 22840Sstevel@tonic-gate 22850Sstevel@tonic-gate rv = drmach_node_walk(obj->tree, &data, drmach_board_find_devices_cb); 22860Sstevel@tonic-gate if (rv == 0) 22870Sstevel@tonic-gate err = NULL; 22880Sstevel@tonic-gate else { 22890Sstevel@tonic-gate drmach_array_dispose(obj->devices, drmach_device_dispose); 22900Sstevel@tonic-gate obj->devices = NULL; 22910Sstevel@tonic-gate 22920Sstevel@tonic-gate if (data.err) 22930Sstevel@tonic-gate err = data.err; 22940Sstevel@tonic-gate else 22950Sstevel@tonic-gate err = DRMACH_INTERNAL_ERROR(); 22960Sstevel@tonic-gate } 22970Sstevel@tonic-gate 22980Sstevel@tonic-gate return (err); 22990Sstevel@tonic-gate } 23000Sstevel@tonic-gate 23010Sstevel@tonic-gate int 23020Sstevel@tonic-gate drmach_board_lookup(int bnum, drmachid_t *id) 23030Sstevel@tonic-gate { 23040Sstevel@tonic-gate int rv = 0; 23050Sstevel@tonic-gate 23060Sstevel@tonic-gate if (!drmach_initialized && drmach_init() == -1) { 23070Sstevel@tonic-gate *id = 0; 23080Sstevel@tonic-gate rv = -1; 23090Sstevel@tonic-gate } else if (drmach_array_get(drmach_boards, bnum, id)) { 23100Sstevel@tonic-gate *id = 0; 23110Sstevel@tonic-gate rv = -1; 23120Sstevel@tonic-gate } 23130Sstevel@tonic-gate return (rv); 23140Sstevel@tonic-gate } 23150Sstevel@tonic-gate 23160Sstevel@tonic-gate sbd_error_t * 23170Sstevel@tonic-gate drmach_board_name(int bnum, char *buf, int buflen) 23180Sstevel@tonic-gate { 23190Sstevel@tonic-gate snprintf(buf, buflen, "SB%d", bnum); 23200Sstevel@tonic-gate return (NULL); 23210Sstevel@tonic-gate } 23220Sstevel@tonic-gate 23230Sstevel@tonic-gate sbd_error_t * 23240Sstevel@tonic-gate drmach_board_poweroff(drmachid_t id) 23250Sstevel@tonic-gate { 23260Sstevel@tonic-gate drmach_board_t *bp; 23270Sstevel@tonic-gate sbd_error_t *err; 23280Sstevel@tonic-gate drmach_status_t stat; 23290Sstevel@tonic-gate 23300Sstevel@tonic-gate if (!DRMACH_IS_BOARD_ID(id)) 23310Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 23320Sstevel@tonic-gate bp = id; 23330Sstevel@tonic-gate 23340Sstevel@tonic-gate err = drmach_board_status(id, &stat); 23350Sstevel@tonic-gate if (err) 23360Sstevel@tonic-gate return (err); 23370Sstevel@tonic-gate else if (stat.configured || stat.busy) 23380Sstevel@tonic-gate return (drerr_new(0, ESTF_CONFIGBUSY, bp->cm.name)); 23390Sstevel@tonic-gate else { 23400Sstevel@tonic-gate /* board power off is essentially a noop for Starfire */ 23410Sstevel@tonic-gate bp->powered = 0; 23420Sstevel@tonic-gate return (NULL); 23430Sstevel@tonic-gate } 23440Sstevel@tonic-gate /*NOTREACHED*/ 23450Sstevel@tonic-gate } 23460Sstevel@tonic-gate 23470Sstevel@tonic-gate sbd_error_t * 23480Sstevel@tonic-gate drmach_board_poweron(drmachid_t id) 23490Sstevel@tonic-gate { 23500Sstevel@tonic-gate drmach_board_t *bp; 23510Sstevel@tonic-gate 23520Sstevel@tonic-gate if (!DRMACH_IS_BOARD_ID(id)) 23530Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 23540Sstevel@tonic-gate bp = id; 23550Sstevel@tonic-gate 23560Sstevel@tonic-gate /* board power on is essentially a noop for Starfire */ 23570Sstevel@tonic-gate bp->powered = 1; 23580Sstevel@tonic-gate 23590Sstevel@tonic-gate return (NULL); 23600Sstevel@tonic-gate } 23610Sstevel@tonic-gate 23620Sstevel@tonic-gate static sbd_error_t * 23630Sstevel@tonic-gate drmach_board_release(drmachid_t id) 23640Sstevel@tonic-gate { 23650Sstevel@tonic-gate if (!DRMACH_IS_BOARD_ID(id)) 23660Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 23670Sstevel@tonic-gate return (NULL); 23680Sstevel@tonic-gate } 23690Sstevel@tonic-gate 23700Sstevel@tonic-gate /*ARGSUSED*/ 23710Sstevel@tonic-gate sbd_error_t * 23720Sstevel@tonic-gate drmach_board_test(drmachid_t id, drmach_opts_t *opts, int force) 23730Sstevel@tonic-gate { 23740Sstevel@tonic-gate return (NULL); 23750Sstevel@tonic-gate } 23760Sstevel@tonic-gate 23770Sstevel@tonic-gate sbd_error_t * 23780Sstevel@tonic-gate drmach_board_unassign(drmachid_t id) 23790Sstevel@tonic-gate { 23800Sstevel@tonic-gate drmach_board_t *bp; 23810Sstevel@tonic-gate sbd_error_t *err; 23820Sstevel@tonic-gate drmach_status_t stat; 23830Sstevel@tonic-gate 23840Sstevel@tonic-gate if (!DRMACH_IS_BOARD_ID(id)) 23850Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 23860Sstevel@tonic-gate bp = id; 23870Sstevel@tonic-gate 23880Sstevel@tonic-gate err = drmach_board_status(id, &stat); 23890Sstevel@tonic-gate if (err) 23900Sstevel@tonic-gate return (err); 23910Sstevel@tonic-gate else if (stat.configured || stat.busy) 23920Sstevel@tonic-gate return (drerr_new(0, ESTF_CONFIGBUSY, bp->cm.name)); 23930Sstevel@tonic-gate else if (drmach_array_set(drmach_boards, bp->bnum, 0) != 0) 23940Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 23950Sstevel@tonic-gate else { 23960Sstevel@tonic-gate drmach_board_dispose(bp); 23970Sstevel@tonic-gate return (NULL); 23980Sstevel@tonic-gate } 23990Sstevel@tonic-gate /*NOTREACHED*/ 24000Sstevel@tonic-gate } 24010Sstevel@tonic-gate 24020Sstevel@tonic-gate static sbd_error_t * 24030Sstevel@tonic-gate drmach_cpu_new(drmach_device_t *dp) 24040Sstevel@tonic-gate { 24050Sstevel@tonic-gate static sbd_error_t *drmach_cpu_release(drmachid_t); 24060Sstevel@tonic-gate static sbd_error_t *drmach_cpu_status(drmachid_t, drmach_status_t *); 24070Sstevel@tonic-gate 24080Sstevel@tonic-gate sbd_error_t *err; 24090Sstevel@tonic-gate int portid; 24100Sstevel@tonic-gate 24110Sstevel@tonic-gate err = drmach_device_get_prop(dp, "upa-portid", &portid); 24120Sstevel@tonic-gate if (err == NULL) 24130Sstevel@tonic-gate dp->unum = portid & 3; 24140Sstevel@tonic-gate 24150Sstevel@tonic-gate dp->cm.isa = (void *)drmach_cpu_new; 24160Sstevel@tonic-gate dp->cm.release = drmach_cpu_release; 24170Sstevel@tonic-gate dp->cm.status = drmach_cpu_status; 24180Sstevel@tonic-gate 24190Sstevel@tonic-gate snprintf(dp->cm.name, sizeof (dp->cm.name), "%s%d", dp->type, dp->unum); 24200Sstevel@tonic-gate 24210Sstevel@tonic-gate return (err); 24220Sstevel@tonic-gate } 24230Sstevel@tonic-gate 24240Sstevel@tonic-gate /* 24250Sstevel@tonic-gate * drmach_cpu_obp_detach() 24260Sstevel@tonic-gate * This requires two steps, first, we must put the cpuid into the OBP 24270Sstevel@tonic-gate * idle loop (Idle in Program) state. Then we call OBP to place the CPU 24280Sstevel@tonic-gate * into the "Detached" state, which does any special processing to 24290Sstevel@tonic-gate * actually detach the cpu, such as flushing ecache, and also ensures 24300Sstevel@tonic-gate * that a subsequent breakpoint won't restart the cpu (if it was just in 24310Sstevel@tonic-gate * Idle in Program state). 24320Sstevel@tonic-gate */ 24330Sstevel@tonic-gate static void 24340Sstevel@tonic-gate drmach_cpu_obp_detach(int cpuid) 24350Sstevel@tonic-gate { 24360Sstevel@tonic-gate /* 24370Sstevel@tonic-gate * Cpu may not be under OBP's control. Eg, if cpu exited to download 24380Sstevel@tonic-gate * helper on a prior attach. 24390Sstevel@tonic-gate */ 24400Sstevel@tonic-gate if (CPU_SGN_EXISTS(cpuid) && 24410Sstevel@tonic-gate !SGN_CPU_IS_OS(cpuid) && 24420Sstevel@tonic-gate !SGN_CPU_IS_OBP(cpuid)) { 24430Sstevel@tonic-gate cmn_err(CE_WARN, 24440Sstevel@tonic-gate "unexpected signature (0x%x) for cpu %d", 24450Sstevel@tonic-gate get_cpu_sgn(cpuid), cpuid); 24460Sstevel@tonic-gate } 24470Sstevel@tonic-gate 24480Sstevel@tonic-gate /* 24490Sstevel@tonic-gate * Now we place the CPU into the "Detached" idle loop in OBP. 24500Sstevel@tonic-gate * This is so that the CPU won't be restarted if we break into 24510Sstevel@tonic-gate * OBP with a breakpoint or BREAK key from the console, and also 24520Sstevel@tonic-gate * if we need to do any special processing, such as flushing the 24530Sstevel@tonic-gate * cpu's ecache, disabling interrupts (by turning of the ET bit in 24540Sstevel@tonic-gate * the PSR) and/or spinning in BBSRAM rather than global memory. 24550Sstevel@tonic-gate */ 24560Sstevel@tonic-gate DRMACH_PR("prom_starfire_rm_cpu(%d)\n", cpuid); 24570Sstevel@tonic-gate prom_starfire_rm_cpu(cpuid); 24580Sstevel@tonic-gate } 24590Sstevel@tonic-gate 24600Sstevel@tonic-gate /* 24610Sstevel@tonic-gate * drmach_cpu_obp_is_detached() returns TRUE if the cpu sigblock signature state 24620Sstevel@tonic-gate * is SIGBST_DETACHED; otherwise it returns FALSE. This routine should only 24630Sstevel@tonic-gate * be called after we have asked OBP to detach the CPU. It should NOT be 24640Sstevel@tonic-gate * called as a check during any other flow. 24650Sstevel@tonic-gate */ 24660Sstevel@tonic-gate static int 24670Sstevel@tonic-gate drmach_cpu_obp_is_detached(int cpuid) 24680Sstevel@tonic-gate { 24690Sstevel@tonic-gate if (!CPU_SGN_EXISTS(cpuid) || 24700Sstevel@tonic-gate (SGN_CPU_IS_OS(cpuid) && SGN_CPU_STATE_IS_DETACHED(cpuid))) 24710Sstevel@tonic-gate return (1); 24720Sstevel@tonic-gate else 24730Sstevel@tonic-gate return (0); 24740Sstevel@tonic-gate } 24750Sstevel@tonic-gate 24760Sstevel@tonic-gate static int 24770Sstevel@tonic-gate drmach_cpu_start(struct cpu *cp) 24780Sstevel@tonic-gate { 24790Sstevel@tonic-gate int cpuid = cp->cpu_id; 24800Sstevel@tonic-gate int ntries = drmach_cpu_ntries; 24810Sstevel@tonic-gate extern void restart_other_cpu(int); 24820Sstevel@tonic-gate 24830Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 2484789Sahrens ASSERT(cpunodes[cpuid].nodeid != (pnode_t)0); 24850Sstevel@tonic-gate 24860Sstevel@tonic-gate cp->cpu_flags &= ~CPU_POWEROFF; 24870Sstevel@tonic-gate 24880Sstevel@tonic-gate /* 24890Sstevel@tonic-gate * NOTE: restart_other_cpu pauses cpus during the 24900Sstevel@tonic-gate * slave cpu start. This helps to quiesce the 24910Sstevel@tonic-gate * bus traffic a bit which makes the tick sync 24920Sstevel@tonic-gate * routine in the prom more robust. 24930Sstevel@tonic-gate */ 24940Sstevel@tonic-gate DRMACH_PR("COLD START for cpu (%d)\n", cpuid); 24950Sstevel@tonic-gate 24960Sstevel@tonic-gate prom_starfire_add_cpu(cpuid); 24970Sstevel@tonic-gate 24980Sstevel@tonic-gate restart_other_cpu(cpuid); 24990Sstevel@tonic-gate 25000Sstevel@tonic-gate /* 25010Sstevel@tonic-gate * Wait for the cpu to reach its idle thread before 25020Sstevel@tonic-gate * we zap him with a request to blow away the mappings 25030Sstevel@tonic-gate * he (might) have for the drmach_shutdown_asm code 25040Sstevel@tonic-gate * he may have executed on unconfigure. 25050Sstevel@tonic-gate */ 25060Sstevel@tonic-gate while ((cp->cpu_thread != cp->cpu_idle_thread) && (ntries > 0)) { 25070Sstevel@tonic-gate DELAY(drmach_cpu_delay); 25080Sstevel@tonic-gate ntries--; 25090Sstevel@tonic-gate } 25100Sstevel@tonic-gate 25110Sstevel@tonic-gate DRMACH_PR("waited %d out of %d loops for cpu %d\n", 25120Sstevel@tonic-gate drmach_cpu_ntries - ntries, drmach_cpu_ntries, cpuid); 25130Sstevel@tonic-gate 25140Sstevel@tonic-gate xt_one(cpuid, vtag_flushpage_tl1, 25150Sstevel@tonic-gate (uint64_t)drmach_shutdown_va, (uint64_t)KCONTEXT); 25160Sstevel@tonic-gate 25170Sstevel@tonic-gate return (0); 25180Sstevel@tonic-gate } 25190Sstevel@tonic-gate 25200Sstevel@tonic-gate /* 25210Sstevel@tonic-gate * A detaching CPU is xcalled with an xtrap to drmach_cpu_stop_self() after 25220Sstevel@tonic-gate * it has been offlined. The function of this routine is to get the cpu 25230Sstevel@tonic-gate * spinning in a safe place. The requirement is that the system will not 25240Sstevel@tonic-gate * reference anything on the detaching board (memory and i/o is detached 25250Sstevel@tonic-gate * elsewhere) and that the CPU not reference anything on any other board 25260Sstevel@tonic-gate * in the system. This isolation is required during and after the writes 25270Sstevel@tonic-gate * to the domain masks to remove the board from the domain. 25280Sstevel@tonic-gate * 25290Sstevel@tonic-gate * To accomplish this isolation the following is done: 25300Sstevel@tonic-gate * 1) Create a locked mapping to a location in BBSRAM where 25310Sstevel@tonic-gate * the cpu will execute. 25320Sstevel@tonic-gate * 2) Copy the target function (drmach_shutdown_asm) in which 25330Sstevel@tonic-gate * the cpu will execute into BBSRAM. 25340Sstevel@tonic-gate * 3) Jump into function with BBSRAM. 25350Sstevel@tonic-gate * Function will: 25360Sstevel@tonic-gate * 3.1) Flush its Ecache (displacement). 25370Sstevel@tonic-gate * 3.2) Flush its Dcache with HW mechanism. 25380Sstevel@tonic-gate * 3.3) Flush its Icache with HW mechanism. 25390Sstevel@tonic-gate * 3.4) Flush all valid and _unlocked_ D-TLB entries. 25400Sstevel@tonic-gate * 3.5) Flush all valid and _unlocked_ I-TLB entries. 25410Sstevel@tonic-gate * 3.6) Clear xt_mb to signal completion. Note: cache line is 25420Sstevel@tonic-gate * recovered by drmach_cpu_poweroff(). 25430Sstevel@tonic-gate * 4) Jump into a tight loop. 25440Sstevel@tonic-gate */ 25450Sstevel@tonic-gate #define DRMACH_BBSRAM_OFFSET 0x1000 25460Sstevel@tonic-gate 25470Sstevel@tonic-gate static void 25480Sstevel@tonic-gate drmach_cpu_stop_self(void) 25490Sstevel@tonic-gate { 25500Sstevel@tonic-gate int cpuid = (int)CPU->cpu_id; 25510Sstevel@tonic-gate tte_t tte; 25520Sstevel@tonic-gate volatile uint_t *src, *dst; 25530Sstevel@tonic-gate uint_t funclen; 25540Sstevel@tonic-gate uint64_t bbsram_pa, bbsram_offset; 25550Sstevel@tonic-gate uint_t bbsram_pfn; 25560Sstevel@tonic-gate uint64_t bbsram_addr; 25570Sstevel@tonic-gate void (*bbsram_func)(uint64_t); 25580Sstevel@tonic-gate extern void drmach_shutdown_asm(uint64_t); 25590Sstevel@tonic-gate extern void drmach_shutdown_asm_end(void); 25600Sstevel@tonic-gate 25610Sstevel@tonic-gate funclen = (uint_t)drmach_shutdown_asm_end - (uint_t)drmach_shutdown_asm; 25620Sstevel@tonic-gate ASSERT(funclen <= MMU_PAGESIZE); 25630Sstevel@tonic-gate /* 25640Sstevel@tonic-gate * We'll start from the 0th's base. 25650Sstevel@tonic-gate */ 25660Sstevel@tonic-gate bbsram_pa = STARFIRE_UPAID2UPS(cpuid) | STARFIRE_PSI_BASE; 25670Sstevel@tonic-gate bbsram_offset = bbsram_pa | 0xfe0ULL; 25680Sstevel@tonic-gate bbsram_pa += ldphysio(bbsram_offset) + DRMACH_BBSRAM_OFFSET; 25690Sstevel@tonic-gate 25700Sstevel@tonic-gate bbsram_pfn = (uint_t)(bbsram_pa >> MMU_PAGESHIFT); 25710Sstevel@tonic-gate 25720Sstevel@tonic-gate bbsram_addr = (uint64_t)drmach_shutdown_va; 25730Sstevel@tonic-gate drmach_shutdown_asm_mbox->estack = bbsram_addr + (uint64_t)funclen; 25740Sstevel@tonic-gate 25750Sstevel@tonic-gate tte.tte_inthi = TTE_VALID_INT | TTE_SZ_INT(TTE8K) | 25760Sstevel@tonic-gate TTE_PFN_INTHI(bbsram_pfn); 25770Sstevel@tonic-gate tte.tte_intlo = TTE_PFN_INTLO(bbsram_pfn) | 25780Sstevel@tonic-gate TTE_HWWR_INT | TTE_PRIV_INT | TTE_LCK_INT; 25790Sstevel@tonic-gate sfmmu_dtlb_ld(drmach_shutdown_va, KCONTEXT, &tte); /* load dtlb */ 25800Sstevel@tonic-gate sfmmu_itlb_ld(drmach_shutdown_va, KCONTEXT, &tte); /* load itlb */ 25810Sstevel@tonic-gate 25820Sstevel@tonic-gate for (src = (uint_t *)drmach_shutdown_asm, dst = (uint_t *)bbsram_addr; 25830Sstevel@tonic-gate src < (uint_t *)drmach_shutdown_asm_end; src++, dst++) 25840Sstevel@tonic-gate *dst = *src; 25850Sstevel@tonic-gate 25860Sstevel@tonic-gate bbsram_func = (void (*)())bbsram_addr; 25870Sstevel@tonic-gate drmach_shutdown_asm_mbox->flushaddr = ecache_flushaddr; 25880Sstevel@tonic-gate drmach_shutdown_asm_mbox->size = (cpunodes[cpuid].ecache_size << 1); 25890Sstevel@tonic-gate drmach_shutdown_asm_mbox->linesize = cpunodes[cpuid].ecache_linesize; 25900Sstevel@tonic-gate drmach_shutdown_asm_mbox->physaddr 25910Sstevel@tonic-gate = va_to_pa((void *)&drmach_xt_mb[cpuid]); 25920Sstevel@tonic-gate 25930Sstevel@tonic-gate /* 25940Sstevel@tonic-gate * Signal to drmach_cpu_poweroff() is via drmach_xt_mb cleared 25950Sstevel@tonic-gate * by asm code 25960Sstevel@tonic-gate */ 25970Sstevel@tonic-gate 25980Sstevel@tonic-gate (*bbsram_func)(va_to_pa((void *)drmach_shutdown_asm_mbox)); 25990Sstevel@tonic-gate } 26000Sstevel@tonic-gate 26010Sstevel@tonic-gate static void 26020Sstevel@tonic-gate drmach_cpu_shutdown_self(void) 26030Sstevel@tonic-gate { 26040Sstevel@tonic-gate cpu_t *cp = CPU; 26050Sstevel@tonic-gate int cpuid = cp->cpu_id; 26060Sstevel@tonic-gate extern void flush_windows(void); 26070Sstevel@tonic-gate 26080Sstevel@tonic-gate flush_windows(); 26090Sstevel@tonic-gate 26100Sstevel@tonic-gate (void) spl8(); 26110Sstevel@tonic-gate 26120Sstevel@tonic-gate ASSERT(cp->cpu_intr_actv == 0); 2613*834Sandrei ASSERT(cp->cpu_thread == cp->cpu_idle_thread || 2614*834Sandrei cp->cpu_thread == cp->cpu_startup_thread); 26150Sstevel@tonic-gate 26160Sstevel@tonic-gate cp->cpu_flags = CPU_OFFLINE | CPU_QUIESCED | CPU_POWEROFF; 26170Sstevel@tonic-gate 26180Sstevel@tonic-gate drmach_cpu_stop_self(); 26190Sstevel@tonic-gate 26200Sstevel@tonic-gate cmn_err(CE_PANIC, "CPU %d FAILED TO SHUTDOWN", cpuid); 26210Sstevel@tonic-gate } 26220Sstevel@tonic-gate 26230Sstevel@tonic-gate /* a helper routine to keep the math in one place */ 26240Sstevel@tonic-gate static processorid_t 26250Sstevel@tonic-gate drmach_cpu_calc_id(drmach_device_t *dp) 26260Sstevel@tonic-gate { 26270Sstevel@tonic-gate return (dp->bp->bnum * MAX_CPU_UNITS_PER_BOARD + dp->unum); 26280Sstevel@tonic-gate } 26290Sstevel@tonic-gate 26300Sstevel@tonic-gate /* 26310Sstevel@tonic-gate * Move bootproc (SIGBCPU) to another cpu. If dst_cpu is NULL, a 26320Sstevel@tonic-gate * destination cpu is chosen from the set of cpus not located on the 26330Sstevel@tonic-gate * same board as the current bootproc cpu. 26340Sstevel@tonic-gate */ 26350Sstevel@tonic-gate static sbd_error_t * 26360Sstevel@tonic-gate drmach_cpu_juggle_bootproc(drmach_device_t *dst_cpu) 26370Sstevel@tonic-gate { 26380Sstevel@tonic-gate processorid_t cpuid; 26390Sstevel@tonic-gate struct cpu *cp; 26400Sstevel@tonic-gate sbd_error_t *err; 26410Sstevel@tonic-gate int rv; 26420Sstevel@tonic-gate 26430Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 26440Sstevel@tonic-gate 26450Sstevel@tonic-gate /* dst_cpu is NULL when target cpu is unspecified. So, pick one. */ 26460Sstevel@tonic-gate if (dst_cpu == NULL) { 26470Sstevel@tonic-gate int avoid_board = DRMACH_CPUID2BNUM(SIGBCPU->cpu_id); 26480Sstevel@tonic-gate int max_cpuid = MAX_BOARDS * MAX_CPU_UNITS_PER_BOARD; 26490Sstevel@tonic-gate 26500Sstevel@tonic-gate for (cpuid = 0; cpuid < max_cpuid; cpuid++) 26510Sstevel@tonic-gate if (DRMACH_CPUID2BNUM(cpuid) != avoid_board) { 26520Sstevel@tonic-gate cp = cpu_get(cpuid); 26530Sstevel@tonic-gate if (cp != NULL && cpu_is_online(cp)) 26540Sstevel@tonic-gate break; 26550Sstevel@tonic-gate } 26560Sstevel@tonic-gate 26570Sstevel@tonic-gate if (cpuid == max_cpuid) { 26580Sstevel@tonic-gate err = drerr_new(1, ESTF_JUGGLE, NULL); 26590Sstevel@tonic-gate return (err); 26600Sstevel@tonic-gate } 26610Sstevel@tonic-gate 26620Sstevel@tonic-gate /* else, cp points to the selected target cpu */ 26630Sstevel@tonic-gate } else { 26640Sstevel@tonic-gate cpuid = drmach_cpu_calc_id(dst_cpu); 26650Sstevel@tonic-gate 26660Sstevel@tonic-gate if ((cp = cpu_get(cpuid)) == NULL) { 26670Sstevel@tonic-gate err = drerr_new(1, ESTF_NODEV, "%s::%s", 26680Sstevel@tonic-gate dst_cpu->bp->cm.name, dst_cpu->cm.name); 26690Sstevel@tonic-gate return (err); 26700Sstevel@tonic-gate } 26710Sstevel@tonic-gate 26720Sstevel@tonic-gate if (cpuid == SIGBCPU->cpu_id) { 26730Sstevel@tonic-gate cmn_err(CE_WARN, 26740Sstevel@tonic-gate "SIGBCPU(%d) same as new selection(%d)", 26750Sstevel@tonic-gate SIGBCPU->cpu_id, cpuid); 26760Sstevel@tonic-gate 26770Sstevel@tonic-gate /* technically not an error, but a no-op */ 26780Sstevel@tonic-gate return (NULL); 26790Sstevel@tonic-gate } 26800Sstevel@tonic-gate } 26810Sstevel@tonic-gate 26820Sstevel@tonic-gate cmn_err(CE_NOTE, "?relocating SIGBCPU from %d to %d", 26830Sstevel@tonic-gate SIGBCPU->cpu_id, cpuid); 26840Sstevel@tonic-gate 26850Sstevel@tonic-gate DRMACH_PR("moving SIGBCPU to CPU %d\n", cpuid); 26860Sstevel@tonic-gate 26870Sstevel@tonic-gate /* 26880Sstevel@tonic-gate * Tell OBP to initialize cvc-offset field of new CPU0 26890Sstevel@tonic-gate * so that it's in sync with OBP and cvc_server 26900Sstevel@tonic-gate */ 26910Sstevel@tonic-gate prom_starfire_init_console(cpuid); 26920Sstevel@tonic-gate 26930Sstevel@tonic-gate /* 26940Sstevel@tonic-gate * Assign cvc to new cpu0's bbsram for I/O. This has to be 26950Sstevel@tonic-gate * done BEFORE cpu0 is moved via obp, since this logic 26960Sstevel@tonic-gate * will cause obp_helper to switch to a different bbsram for 26970Sstevel@tonic-gate * cvc I/O. We don't want cvc writing to a buffer from which 26980Sstevel@tonic-gate * nobody will pick up the data! 26990Sstevel@tonic-gate */ 27000Sstevel@tonic-gate cvc_assign_iocpu(cpuid); 27010Sstevel@tonic-gate 27020Sstevel@tonic-gate rv = prom_starfire_move_cpu0(cpuid); 27030Sstevel@tonic-gate 27040Sstevel@tonic-gate if (rv == 0) { 27050Sstevel@tonic-gate SIGBCPU = cp; 27060Sstevel@tonic-gate 27070Sstevel@tonic-gate DRMACH_PR("successfully juggled to CPU %d\n", cpuid); 27080Sstevel@tonic-gate return (NULL); 27090Sstevel@tonic-gate } else { 27100Sstevel@tonic-gate DRMACH_PR("prom error: prom_starfire_move_cpu0(%d) " 27110Sstevel@tonic-gate "returned %d\n", cpuid, rv); 27120Sstevel@tonic-gate 27130Sstevel@tonic-gate /* 27140Sstevel@tonic-gate * The move failed, hopefully obp_helper is still back 27150Sstevel@tonic-gate * at the old bootproc. Move cvc back there. 27160Sstevel@tonic-gate */ 27170Sstevel@tonic-gate cvc_assign_iocpu(SIGBCPU->cpu_id); 27180Sstevel@tonic-gate 27190Sstevel@tonic-gate 27200Sstevel@tonic-gate err = drerr_new(1, ESTF_MOVESIGB, "CPU %d", cpuid); 27210Sstevel@tonic-gate return (err); 27220Sstevel@tonic-gate } 27230Sstevel@tonic-gate /*NOTREACHED*/ 27240Sstevel@tonic-gate } 27250Sstevel@tonic-gate 27260Sstevel@tonic-gate static sbd_error_t * 27270Sstevel@tonic-gate drmach_cpu_release(drmachid_t id) 27280Sstevel@tonic-gate { 27290Sstevel@tonic-gate drmach_device_t *dp; 27300Sstevel@tonic-gate processorid_t cpuid; 27310Sstevel@tonic-gate struct cpu *cp; 27320Sstevel@tonic-gate sbd_error_t *err; 27330Sstevel@tonic-gate 27340Sstevel@tonic-gate if (!DRMACH_IS_CPU_ID(id)) 27350Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 27360Sstevel@tonic-gate dp = id; 27370Sstevel@tonic-gate cpuid = drmach_cpu_calc_id(dp); 27380Sstevel@tonic-gate 27390Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 27400Sstevel@tonic-gate 27410Sstevel@tonic-gate cp = cpu_get(cpuid); 27420Sstevel@tonic-gate if (cp == NULL) 27430Sstevel@tonic-gate err = DRMACH_INTERNAL_ERROR(); 27440Sstevel@tonic-gate else if (SIGBCPU->cpu_id == cp->cpu_id) 27450Sstevel@tonic-gate err = drmach_cpu_juggle_bootproc(NULL); 27460Sstevel@tonic-gate else 27470Sstevel@tonic-gate err = NULL; 27480Sstevel@tonic-gate 27490Sstevel@tonic-gate return (err); 27500Sstevel@tonic-gate } 27510Sstevel@tonic-gate 27520Sstevel@tonic-gate static sbd_error_t * 27530Sstevel@tonic-gate drmach_cpu_status(drmachid_t id, drmach_status_t *stat) 27540Sstevel@tonic-gate { 27550Sstevel@tonic-gate drmach_device_t *dp; 27560Sstevel@tonic-gate 27570Sstevel@tonic-gate ASSERT(DRMACH_IS_CPU_ID(id)); 27580Sstevel@tonic-gate dp = id; 27590Sstevel@tonic-gate 27600Sstevel@tonic-gate stat->assigned = dp->bp->assigned; 27610Sstevel@tonic-gate stat->powered = dp->bp->powered; 27620Sstevel@tonic-gate mutex_enter(&cpu_lock); 27630Sstevel@tonic-gate stat->configured = (cpu_get(drmach_cpu_calc_id(dp)) != NULL); 27640Sstevel@tonic-gate mutex_exit(&cpu_lock); 27650Sstevel@tonic-gate stat->busy = dp->busy; 27660Sstevel@tonic-gate strncpy(stat->type, dp->type, sizeof (stat->type)); 27670Sstevel@tonic-gate stat->info[0] = '\0'; 27680Sstevel@tonic-gate 27690Sstevel@tonic-gate return (NULL); 27700Sstevel@tonic-gate } 27710Sstevel@tonic-gate 27720Sstevel@tonic-gate sbd_error_t * 27730Sstevel@tonic-gate drmach_cpu_disconnect(drmachid_t id) 27740Sstevel@tonic-gate { 27750Sstevel@tonic-gate drmach_device_t *cpu; 27760Sstevel@tonic-gate int cpuid; 27770Sstevel@tonic-gate int ntries; 27780Sstevel@tonic-gate int p; 27790Sstevel@tonic-gate u_longlong_t pc_addr; 27800Sstevel@tonic-gate uchar_t rvalue; 27810Sstevel@tonic-gate 27820Sstevel@tonic-gate if (!DRMACH_IS_CPU_ID(id)) 27830Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 27840Sstevel@tonic-gate cpu = id; 27850Sstevel@tonic-gate 27860Sstevel@tonic-gate cpuid = drmach_cpu_calc_id(cpu); 27870Sstevel@tonic-gate if (SIGBCPU->cpu_id == cpuid) { 27880Sstevel@tonic-gate /* this cpu is SIGBCPU, can't disconnect */ 27890Sstevel@tonic-gate return (drerr_new(1, ESTF_HASSIGB, "%s::%s", 27900Sstevel@tonic-gate cpu->bp->cm.name, cpu->cm.name)); 27910Sstevel@tonic-gate } 27920Sstevel@tonic-gate 27930Sstevel@tonic-gate /* 27940Sstevel@tonic-gate * Make sure SIGBST_DETACHED is set before 27950Sstevel@tonic-gate * mapping out the sig block. 27960Sstevel@tonic-gate */ 27970Sstevel@tonic-gate ntries = drmach_cpu_ntries; 27980Sstevel@tonic-gate while (!drmach_cpu_obp_is_detached(cpuid) && ntries) { 27990Sstevel@tonic-gate DELAY(drmach_cpu_delay); 28000Sstevel@tonic-gate ntries--; 28010Sstevel@tonic-gate } 28020Sstevel@tonic-gate if (!drmach_cpu_obp_is_detached(cpuid)) { 28030Sstevel@tonic-gate cmn_err(CE_WARN, "failed to mark cpu %d detached in sigblock", 28040Sstevel@tonic-gate cpuid); 28050Sstevel@tonic-gate } 28060Sstevel@tonic-gate 28070Sstevel@tonic-gate /* map out signature block */ 28080Sstevel@tonic-gate if (CPU_SGN_EXISTS(cpuid)) { 28090Sstevel@tonic-gate CPU_SGN_MAPOUT(cpuid); 28100Sstevel@tonic-gate } 28110Sstevel@tonic-gate 28120Sstevel@tonic-gate /* 28130Sstevel@tonic-gate * We now PC IDLE the processor to guarantee we 28140Sstevel@tonic-gate * stop any transactions from coming from it. 28150Sstevel@tonic-gate */ 28160Sstevel@tonic-gate p = cpu->unum & 1; 28170Sstevel@tonic-gate pc_addr = STARFIRE_BB_PC_ADDR(cpu->bp->bnum, cpu->unum, 0); 28180Sstevel@tonic-gate 28190Sstevel@tonic-gate DRMACH_PR("PC idle cpu %d (addr = 0x%llx, port = %d, p = %d)", 28200Sstevel@tonic-gate drmach_cpu_calc_id(cpu), pc_addr, cpu->unum, p); 28210Sstevel@tonic-gate 28220Sstevel@tonic-gate rvalue = ldbphysio(pc_addr); 28230Sstevel@tonic-gate rvalue |= STARFIRE_BB_PC_IDLE(p); 28240Sstevel@tonic-gate stbphysio(pc_addr, rvalue); 28250Sstevel@tonic-gate DELAY(50000); 28260Sstevel@tonic-gate 28270Sstevel@tonic-gate return (NULL); 28280Sstevel@tonic-gate } 28290Sstevel@tonic-gate 28300Sstevel@tonic-gate sbd_error_t * 28310Sstevel@tonic-gate drmach_cpu_get_id(drmachid_t id, processorid_t *cpuid) 28320Sstevel@tonic-gate { 28330Sstevel@tonic-gate drmach_device_t *cpu; 28340Sstevel@tonic-gate 28350Sstevel@tonic-gate if (!DRMACH_IS_CPU_ID(id)) 28360Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 28370Sstevel@tonic-gate cpu = id; 28380Sstevel@tonic-gate 28390Sstevel@tonic-gate *cpuid = drmach_cpu_calc_id(cpu); 28400Sstevel@tonic-gate return (NULL); 28410Sstevel@tonic-gate } 28420Sstevel@tonic-gate 28430Sstevel@tonic-gate sbd_error_t * 28440Sstevel@tonic-gate drmach_cpu_get_impl(drmachid_t id, int *ip) 28450Sstevel@tonic-gate { 28460Sstevel@tonic-gate drmach_device_t *cpu; 28470Sstevel@tonic-gate int impl; 28480Sstevel@tonic-gate 28490Sstevel@tonic-gate if (!DRMACH_IS_CPU_ID(id)) 28500Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 28510Sstevel@tonic-gate 28520Sstevel@tonic-gate cpu = id; 28530Sstevel@tonic-gate 28540Sstevel@tonic-gate if (drmach_node_get_prop(cpu->node, "implementation#", &impl) == -1) { 28550Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 28560Sstevel@tonic-gate } 28570Sstevel@tonic-gate 28580Sstevel@tonic-gate *ip = impl; 28590Sstevel@tonic-gate 28600Sstevel@tonic-gate return (NULL); 28610Sstevel@tonic-gate } 28620Sstevel@tonic-gate 28630Sstevel@tonic-gate void 28640Sstevel@tonic-gate drmach_cpu_flush_ecache_sync(void) 28650Sstevel@tonic-gate { 28660Sstevel@tonic-gate ASSERT(curthread->t_bound_cpu == CPU); 28670Sstevel@tonic-gate 28680Sstevel@tonic-gate /* 28690Sstevel@tonic-gate * Now let's flush our ecache thereby removing all references 28700Sstevel@tonic-gate * to the target (detaching) memory from all ecache's in 28710Sstevel@tonic-gate * system. 28720Sstevel@tonic-gate */ 28730Sstevel@tonic-gate cpu_flush_ecache(); 28740Sstevel@tonic-gate 28750Sstevel@tonic-gate /* 28760Sstevel@tonic-gate * Delay 100 usec out of paranoia to insure everything 28770Sstevel@tonic-gate * (hardware queues) has drained before we start reprogramming 28780Sstevel@tonic-gate * the hardware. 28790Sstevel@tonic-gate */ 28800Sstevel@tonic-gate DELAY(100); 28810Sstevel@tonic-gate } 28820Sstevel@tonic-gate 28830Sstevel@tonic-gate sbd_error_t * 28840Sstevel@tonic-gate drmach_get_dip(drmachid_t id, dev_info_t **dip) 28850Sstevel@tonic-gate { 28860Sstevel@tonic-gate drmach_device_t *dp; 28870Sstevel@tonic-gate 28880Sstevel@tonic-gate if (!DRMACH_IS_DEVICE_ID(id)) 28890Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 28900Sstevel@tonic-gate dp = id; 28910Sstevel@tonic-gate 28920Sstevel@tonic-gate *dip = drmach_node_get_dip(dp->node); 28930Sstevel@tonic-gate return (NULL); 28940Sstevel@tonic-gate } 28950Sstevel@tonic-gate 28960Sstevel@tonic-gate sbd_error_t * 28970Sstevel@tonic-gate drmach_io_is_attached(drmachid_t id, int *yes) 28980Sstevel@tonic-gate { 28990Sstevel@tonic-gate drmach_device_t *dp; 29000Sstevel@tonic-gate dev_info_t *dip; 29010Sstevel@tonic-gate int state; 29020Sstevel@tonic-gate 29030Sstevel@tonic-gate if (!DRMACH_IS_IO_ID(id)) 29040Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 29050Sstevel@tonic-gate dp = id; 29060Sstevel@tonic-gate 29070Sstevel@tonic-gate dip = drmach_node_get_dip(dp->node); 29080Sstevel@tonic-gate if (dip == NULL) { 29090Sstevel@tonic-gate *yes = 0; 29100Sstevel@tonic-gate return (NULL); 29110Sstevel@tonic-gate } 29120Sstevel@tonic-gate 29130Sstevel@tonic-gate state = ddi_get_devstate(dip); 29140Sstevel@tonic-gate *yes = ((i_ddi_node_state(dip) >= DS_ATTACHED) || 29150Sstevel@tonic-gate (state == DDI_DEVSTATE_UP)); 29160Sstevel@tonic-gate 29170Sstevel@tonic-gate return (NULL); 29180Sstevel@tonic-gate } 29190Sstevel@tonic-gate 29200Sstevel@tonic-gate sbd_error_t * 29210Sstevel@tonic-gate drmach_io_pre_release(drmachid_t id) 29220Sstevel@tonic-gate { 29230Sstevel@tonic-gate if (!DRMACH_IS_IO_ID(id)) 29240Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 29250Sstevel@tonic-gate return (NULL); 29260Sstevel@tonic-gate } 29270Sstevel@tonic-gate 29280Sstevel@tonic-gate static sbd_error_t * 29290Sstevel@tonic-gate drmach_io_release(drmachid_t id) 29300Sstevel@tonic-gate { 29310Sstevel@tonic-gate if (!DRMACH_IS_IO_ID(id)) 29320Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 29330Sstevel@tonic-gate return (NULL); 29340Sstevel@tonic-gate } 29350Sstevel@tonic-gate 29360Sstevel@tonic-gate sbd_error_t * 29370Sstevel@tonic-gate drmach_io_unrelease(drmachid_t id) 29380Sstevel@tonic-gate { 29390Sstevel@tonic-gate if (!DRMACH_IS_IO_ID(id)) 29400Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 29410Sstevel@tonic-gate return (NULL); 29420Sstevel@tonic-gate } 29430Sstevel@tonic-gate 29440Sstevel@tonic-gate /*ARGSUSED*/ 29450Sstevel@tonic-gate sbd_error_t * 29460Sstevel@tonic-gate drmach_io_post_release(drmachid_t id) 29470Sstevel@tonic-gate { 29480Sstevel@tonic-gate return (NULL); 29490Sstevel@tonic-gate } 29500Sstevel@tonic-gate 29510Sstevel@tonic-gate /*ARGSUSED*/ 29520Sstevel@tonic-gate sbd_error_t * 29530Sstevel@tonic-gate drmach_io_post_attach(drmachid_t id) 29540Sstevel@tonic-gate { 29550Sstevel@tonic-gate return (NULL); 29560Sstevel@tonic-gate } 29570Sstevel@tonic-gate 29580Sstevel@tonic-gate static sbd_error_t * 29590Sstevel@tonic-gate drmach_io_status(drmachid_t id, drmach_status_t *stat) 29600Sstevel@tonic-gate { 29610Sstevel@tonic-gate drmach_device_t *dp; 29620Sstevel@tonic-gate sbd_error_t *err; 29630Sstevel@tonic-gate int configured; 29640Sstevel@tonic-gate 29650Sstevel@tonic-gate ASSERT(DRMACH_IS_IO_ID(id)); 29660Sstevel@tonic-gate dp = id; 29670Sstevel@tonic-gate 29680Sstevel@tonic-gate err = drmach_io_is_attached(id, &configured); 29690Sstevel@tonic-gate if (err) 29700Sstevel@tonic-gate return (err); 29710Sstevel@tonic-gate 29720Sstevel@tonic-gate stat->assigned = dp->bp->assigned; 29730Sstevel@tonic-gate stat->powered = dp->bp->powered; 29740Sstevel@tonic-gate stat->configured = (configured != 0); 29750Sstevel@tonic-gate stat->busy = dp->busy; 29760Sstevel@tonic-gate strncpy(stat->type, dp->type, sizeof (stat->type)); 29770Sstevel@tonic-gate stat->info[0] = '\0'; 29780Sstevel@tonic-gate 29790Sstevel@tonic-gate return (NULL); 29800Sstevel@tonic-gate } 29810Sstevel@tonic-gate 29820Sstevel@tonic-gate static sbd_error_t * 29830Sstevel@tonic-gate drmach_mem_new(drmach_device_t *dp) 29840Sstevel@tonic-gate { 29850Sstevel@tonic-gate static sbd_error_t *drmach_mem_release(drmachid_t); 29860Sstevel@tonic-gate static sbd_error_t *drmach_mem_status(drmachid_t, drmach_status_t *); 29870Sstevel@tonic-gate 29880Sstevel@tonic-gate dp->unum = 0; 29890Sstevel@tonic-gate dp->cm.isa = (void *)drmach_mem_new; 29900Sstevel@tonic-gate dp->cm.release = drmach_mem_release; 29910Sstevel@tonic-gate dp->cm.status = drmach_mem_status; 29920Sstevel@tonic-gate 29930Sstevel@tonic-gate snprintf(dp->cm.name, sizeof (dp->cm.name), "%s", dp->type); 29940Sstevel@tonic-gate 29950Sstevel@tonic-gate return (NULL); 29960Sstevel@tonic-gate } 29970Sstevel@tonic-gate 29980Sstevel@tonic-gate sbd_error_t * 29990Sstevel@tonic-gate drmach_mem_add_span(drmachid_t id, uint64_t basepa, uint64_t size) 30000Sstevel@tonic-gate { 30010Sstevel@tonic-gate pfn_t basepfn = (pfn_t)(basepa >> PAGESHIFT); 30020Sstevel@tonic-gate pgcnt_t npages = (pgcnt_t)(size >> PAGESHIFT); 30030Sstevel@tonic-gate pda_handle_t ph; 30040Sstevel@tonic-gate int rv; 30050Sstevel@tonic-gate 30060Sstevel@tonic-gate ASSERT(size != 0); 30070Sstevel@tonic-gate 30080Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(id)) 30090Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 30100Sstevel@tonic-gate 30110Sstevel@tonic-gate kcage_range_lock(); 30120Sstevel@tonic-gate rv = kcage_range_add(basepfn, npages, 1); 30130Sstevel@tonic-gate kcage_range_unlock(); 30140Sstevel@tonic-gate if (rv == ENOMEM) { 30150Sstevel@tonic-gate cmn_err(CE_WARN, "%lld megabytes not available to kernel cage", 30160Sstevel@tonic-gate (size == 0 ? 0 : size / MBYTE)); 30170Sstevel@tonic-gate } else if (rv != 0) { 30180Sstevel@tonic-gate /* catch this in debug kernels */ 30190Sstevel@tonic-gate ASSERT(0); 30200Sstevel@tonic-gate 30210Sstevel@tonic-gate cmn_err(CE_WARN, "unexpected kcage_range_add" 30220Sstevel@tonic-gate " return value %d", rv); 30230Sstevel@tonic-gate } 30240Sstevel@tonic-gate 30250Sstevel@tonic-gate /* 30260Sstevel@tonic-gate * Update the PDA (post2obp) structure with the 30270Sstevel@tonic-gate * range of the newly added memory. 30280Sstevel@tonic-gate */ 30290Sstevel@tonic-gate ph = drmach_pda_open(); 30300Sstevel@tonic-gate if (ph != NULL) { 30310Sstevel@tonic-gate pda_mem_add_span(ph, basepa, size); 30320Sstevel@tonic-gate pda_close(ph); 30330Sstevel@tonic-gate } 30340Sstevel@tonic-gate 30350Sstevel@tonic-gate return (NULL); 30360Sstevel@tonic-gate } 30370Sstevel@tonic-gate 30380Sstevel@tonic-gate sbd_error_t * 30390Sstevel@tonic-gate drmach_mem_del_span(drmachid_t id, uint64_t basepa, uint64_t size) 30400Sstevel@tonic-gate { 30410Sstevel@tonic-gate drmach_device_t *mem = id; 30420Sstevel@tonic-gate pfn_t basepfn = (pfn_t)(basepa >> PAGESHIFT); 30430Sstevel@tonic-gate pgcnt_t npages = (pgcnt_t)(size >> PAGESHIFT); 30440Sstevel@tonic-gate uint_t mcreg; 30450Sstevel@tonic-gate sbd_error_t *err; 30460Sstevel@tonic-gate pda_handle_t ph; 30470Sstevel@tonic-gate int rv; 30480Sstevel@tonic-gate 30490Sstevel@tonic-gate err = drmach_read_mc_asr(id, &mcreg); 30500Sstevel@tonic-gate if (err) 30510Sstevel@tonic-gate return (err); 30520Sstevel@tonic-gate else if (mcreg & STARFIRE_MC_INTERLEAVE_MASK) { 30530Sstevel@tonic-gate return (drerr_new(1, ESTF_INTERBOARD, "%s::%s", 30540Sstevel@tonic-gate mem->bp->cm.name, mem->cm.name)); 30550Sstevel@tonic-gate } 30560Sstevel@tonic-gate 30570Sstevel@tonic-gate if (size > 0) { 30580Sstevel@tonic-gate kcage_range_lock(); 30590Sstevel@tonic-gate rv = kcage_range_delete_post_mem_del(basepfn, npages); 30600Sstevel@tonic-gate kcage_range_unlock(); 30610Sstevel@tonic-gate if (rv != 0) { 30620Sstevel@tonic-gate cmn_err(CE_WARN, 30630Sstevel@tonic-gate "unexpected kcage_range_delete_post_mem_del" 30640Sstevel@tonic-gate " return value %d", rv); 30650Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 30660Sstevel@tonic-gate } 30670Sstevel@tonic-gate } 30680Sstevel@tonic-gate 30690Sstevel@tonic-gate /* 30700Sstevel@tonic-gate * Update the PDA (post2obp) structure with the 30710Sstevel@tonic-gate * range of removed memory. 30720Sstevel@tonic-gate */ 30730Sstevel@tonic-gate ph = drmach_pda_open(); 30740Sstevel@tonic-gate if (ph != NULL) { 30750Sstevel@tonic-gate if (size > 0) 30760Sstevel@tonic-gate pda_mem_del_span(ph, basepa, size); 30770Sstevel@tonic-gate 30780Sstevel@tonic-gate /* update PDA to board's new mc register settings */ 30790Sstevel@tonic-gate pda_mem_sync(ph, mem->bp->bnum, 0); 30800Sstevel@tonic-gate 30810Sstevel@tonic-gate pda_close(ph); 30820Sstevel@tonic-gate } 30830Sstevel@tonic-gate 30840Sstevel@tonic-gate return (NULL); 30850Sstevel@tonic-gate } 30860Sstevel@tonic-gate 30870Sstevel@tonic-gate /* support routine for enable and disable */ 30880Sstevel@tonic-gate static sbd_error_t * 30890Sstevel@tonic-gate drmach_mem_update_interconnect(drmachid_t id, uint_t mcreg) 30900Sstevel@tonic-gate { 30910Sstevel@tonic-gate drmach_device_t *dp; 30920Sstevel@tonic-gate pda_handle_t ph; 30930Sstevel@tonic-gate int b; 30940Sstevel@tonic-gate 30950Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(id)) 30960Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 30970Sstevel@tonic-gate dp = id; 30980Sstevel@tonic-gate 30990Sstevel@tonic-gate ph = drmach_pda_open(); 31000Sstevel@tonic-gate if (ph == NULL) 31010Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 31020Sstevel@tonic-gate 31030Sstevel@tonic-gate for (b = 0; b < MAX_BOARDS; b++) { 31040Sstevel@tonic-gate int p; 31050Sstevel@tonic-gate int rv; 31060Sstevel@tonic-gate ushort_t bda_proc, bda_ioc; 31070Sstevel@tonic-gate board_desc_t *bdesc; 31080Sstevel@tonic-gate 31090Sstevel@tonic-gate if (pda_board_present(ph, b) == 0) 31100Sstevel@tonic-gate continue; 31110Sstevel@tonic-gate 31120Sstevel@tonic-gate bdesc = (board_desc_t *)pda_get_board_info(ph, b); 31130Sstevel@tonic-gate 31140Sstevel@tonic-gate /* 31150Sstevel@tonic-gate * Update PCs for CPUs. 31160Sstevel@tonic-gate */ 31170Sstevel@tonic-gate 31180Sstevel@tonic-gate /* make sure definition in platmod is in sync with pda */ 31190Sstevel@tonic-gate ASSERT(MAX_PROCMODS == MAX_CPU_UNITS_PER_BOARD); 31200Sstevel@tonic-gate 31210Sstevel@tonic-gate bda_proc = bdesc->bda_proc; 31220Sstevel@tonic-gate for (p = 0; p < MAX_PROCMODS; p++) { 31230Sstevel@tonic-gate if (BDA_NBL(bda_proc, p) != BDAN_GOOD) 31240Sstevel@tonic-gate continue; 31250Sstevel@tonic-gate 31260Sstevel@tonic-gate rv = pc_madr_add(b, dp->bp->bnum, p, mcreg); 31270Sstevel@tonic-gate if (rv) { 31280Sstevel@tonic-gate pda_close(ph); 31290Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 31300Sstevel@tonic-gate } 31310Sstevel@tonic-gate } 31320Sstevel@tonic-gate 31330Sstevel@tonic-gate /* 31340Sstevel@tonic-gate * Update PCs for IOCs. 31350Sstevel@tonic-gate */ 31360Sstevel@tonic-gate 31370Sstevel@tonic-gate /* make sure definition in platmod is in sync with pda */ 31380Sstevel@tonic-gate ASSERT(MAX_IOCS == MAX_IO_UNITS_PER_BOARD); 31390Sstevel@tonic-gate 31400Sstevel@tonic-gate bda_ioc = bdesc->bda_ioc; 31410Sstevel@tonic-gate for (p = 0; p < MAX_IOCS; p++) { 31420Sstevel@tonic-gate if (BDA_NBL(bda_ioc, p) != BDAN_GOOD) 31430Sstevel@tonic-gate continue; 31440Sstevel@tonic-gate 31450Sstevel@tonic-gate rv = pc_madr_add(b, dp->bp->bnum, p + 4, mcreg); 31460Sstevel@tonic-gate if (rv) { 31470Sstevel@tonic-gate pda_close(ph); 31480Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 31490Sstevel@tonic-gate } 31500Sstevel@tonic-gate } 31510Sstevel@tonic-gate } 31520Sstevel@tonic-gate 31530Sstevel@tonic-gate pda_close(ph); 31540Sstevel@tonic-gate return (NULL); 31550Sstevel@tonic-gate } 31560Sstevel@tonic-gate 31570Sstevel@tonic-gate sbd_error_t * 31580Sstevel@tonic-gate drmach_mem_disable(drmachid_t id) 31590Sstevel@tonic-gate { 31600Sstevel@tonic-gate sbd_error_t *err; 31610Sstevel@tonic-gate uint_t mcreg; 31620Sstevel@tonic-gate 31630Sstevel@tonic-gate err = drmach_read_mc_asr(id, &mcreg); 31640Sstevel@tonic-gate if (err == NULL) { 31650Sstevel@tonic-gate ASSERT(mcreg & STARFIRE_MC_MEM_PRESENT_MASK); 31660Sstevel@tonic-gate 31670Sstevel@tonic-gate /* Turn off presence bit. */ 31680Sstevel@tonic-gate mcreg &= ~STARFIRE_MC_MEM_PRESENT_MASK; 31690Sstevel@tonic-gate 31700Sstevel@tonic-gate err = drmach_mem_update_interconnect(id, mcreg); 31710Sstevel@tonic-gate if (err == NULL) 31720Sstevel@tonic-gate err = drmach_write_mc_asr(id, mcreg); 31730Sstevel@tonic-gate } 31740Sstevel@tonic-gate 31750Sstevel@tonic-gate return (err); 31760Sstevel@tonic-gate } 31770Sstevel@tonic-gate 31780Sstevel@tonic-gate sbd_error_t * 31790Sstevel@tonic-gate drmach_mem_enable(drmachid_t id) 31800Sstevel@tonic-gate { 31810Sstevel@tonic-gate sbd_error_t *err; 31820Sstevel@tonic-gate uint_t mcreg; 31830Sstevel@tonic-gate 31840Sstevel@tonic-gate err = drmach_read_mc_asr(id, &mcreg); 31850Sstevel@tonic-gate if (err == NULL) { 31860Sstevel@tonic-gate mcreg |= STARFIRE_MC_MEM_PRESENT_MASK; 31870Sstevel@tonic-gate 31880Sstevel@tonic-gate err = drmach_write_mc_asr(id, mcreg); 31890Sstevel@tonic-gate if (err == NULL) 31900Sstevel@tonic-gate err = drmach_mem_update_interconnect(id, mcreg); 31910Sstevel@tonic-gate } 31920Sstevel@tonic-gate 31930Sstevel@tonic-gate return (err); 31940Sstevel@tonic-gate } 31950Sstevel@tonic-gate 31960Sstevel@tonic-gate sbd_error_t * 31970Sstevel@tonic-gate drmach_mem_get_alignment(drmachid_t id, uint64_t *mask) 31980Sstevel@tonic-gate { 31990Sstevel@tonic-gate drmach_device_t *mem; 32000Sstevel@tonic-gate sbd_error_t *err; 3201789Sahrens pnode_t nodeid; 32020Sstevel@tonic-gate 32030Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(id)) 32040Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 32050Sstevel@tonic-gate mem = id; 32060Sstevel@tonic-gate 32070Sstevel@tonic-gate nodeid = drmach_node_get_dnode(mem->node); 32080Sstevel@tonic-gate if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE) 32090Sstevel@tonic-gate err = DRMACH_INTERNAL_ERROR(); 32100Sstevel@tonic-gate else { 32110Sstevel@tonic-gate uint64_t size; 32120Sstevel@tonic-gate 32130Sstevel@tonic-gate size = mc_get_alignment_mask(nodeid); 32140Sstevel@tonic-gate if (size == (uint64_t)-1) 32150Sstevel@tonic-gate err = DRMACH_INTERNAL_ERROR(); 32160Sstevel@tonic-gate else { 32170Sstevel@tonic-gate *mask = size - 1; 32180Sstevel@tonic-gate err = NULL; 32190Sstevel@tonic-gate } 32200Sstevel@tonic-gate } 32210Sstevel@tonic-gate 32220Sstevel@tonic-gate return (err); 32230Sstevel@tonic-gate } 32240Sstevel@tonic-gate 32250Sstevel@tonic-gate sbd_error_t * 32260Sstevel@tonic-gate drmach_mem_get_base_physaddr(drmachid_t id, uint64_t *pa) 32270Sstevel@tonic-gate { 32280Sstevel@tonic-gate sbd_error_t *err; 32290Sstevel@tonic-gate uint_t mcreg; 32300Sstevel@tonic-gate 32310Sstevel@tonic-gate err = drmach_read_mc_asr(id, &mcreg); 32320Sstevel@tonic-gate if (err == NULL) 32330Sstevel@tonic-gate *pa = mc_asr_to_pa(mcreg); 32340Sstevel@tonic-gate 32350Sstevel@tonic-gate return (err); 32360Sstevel@tonic-gate } 32370Sstevel@tonic-gate 32380Sstevel@tonic-gate /* 32390Sstevel@tonic-gate * Use of this routine after copy/rename will yield incorrect results, 32400Sstevel@tonic-gate * because the OBP MEMAVAIL property will not correctly reflect the 32410Sstevel@tonic-gate * programming of the MCs. 32420Sstevel@tonic-gate */ 32430Sstevel@tonic-gate sbd_error_t * 32440Sstevel@tonic-gate drmach_mem_get_memlist(drmachid_t id, struct memlist **ml) 32450Sstevel@tonic-gate { 32460Sstevel@tonic-gate drmach_device_t *mem; 32470Sstevel@tonic-gate int rv, i, rlen, rblks; 32480Sstevel@tonic-gate sbd_error_t *err; 32490Sstevel@tonic-gate struct memlist *mlist; 32500Sstevel@tonic-gate struct sf_memunit_regspec *rlist; 32510Sstevel@tonic-gate 32520Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(id)) 32530Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 32540Sstevel@tonic-gate mem = id; 32550Sstevel@tonic-gate 32560Sstevel@tonic-gate err = drmach_device_get_proplen(mem, "dr-available", &rlen); 32570Sstevel@tonic-gate if (err) 32580Sstevel@tonic-gate return (err); 32590Sstevel@tonic-gate 32600Sstevel@tonic-gate rlist = kmem_zalloc(rlen, KM_SLEEP); 32610Sstevel@tonic-gate 32620Sstevel@tonic-gate err = drmach_device_get_prop(mem, "dr-available", rlist); 32630Sstevel@tonic-gate if (err) { 32640Sstevel@tonic-gate kmem_free(rlist, rlen); 32650Sstevel@tonic-gate return (err); 32660Sstevel@tonic-gate } 32670Sstevel@tonic-gate 32680Sstevel@tonic-gate mlist = NULL; 32690Sstevel@tonic-gate rblks = rlen / sizeof (struct sf_memunit_regspec); 32700Sstevel@tonic-gate for (i = 0; i < rblks; i++) { 32710Sstevel@tonic-gate uint64_t addr, size; 32720Sstevel@tonic-gate 32730Sstevel@tonic-gate addr = (uint64_t)rlist[i].regspec_addr_hi << 32; 32740Sstevel@tonic-gate addr |= (uint64_t)rlist[i].regspec_addr_lo; 32750Sstevel@tonic-gate size = (uint64_t)rlist[i].regspec_size_hi << 32; 32760Sstevel@tonic-gate size |= (uint64_t)rlist[i].regspec_size_lo; 32770Sstevel@tonic-gate 32780Sstevel@tonic-gate mlist = memlist_add_span(mlist, addr, size); 32790Sstevel@tonic-gate } 32800Sstevel@tonic-gate 32810Sstevel@tonic-gate kmem_free(rlist, rlen); 32820Sstevel@tonic-gate 32830Sstevel@tonic-gate /* 32840Sstevel@tonic-gate * Make sure the incoming memlist doesn't already 32850Sstevel@tonic-gate * intersect with what's present in the system (phys_install). 32860Sstevel@tonic-gate */ 32870Sstevel@tonic-gate memlist_read_lock(); 32880Sstevel@tonic-gate rv = memlist_intersect(phys_install, mlist); 32890Sstevel@tonic-gate memlist_read_unlock(); 32900Sstevel@tonic-gate if (rv) { 32910Sstevel@tonic-gate #ifdef DEBUG 32920Sstevel@tonic-gate DRMACH_PR("OBP derived memlist intersects" 32930Sstevel@tonic-gate " with phys_install\n"); 32940Sstevel@tonic-gate memlist_dump(mlist); 32950Sstevel@tonic-gate 32960Sstevel@tonic-gate DRMACH_PR("phys_install memlist:\n"); 32970Sstevel@tonic-gate memlist_dump(phys_install); 32980Sstevel@tonic-gate #endif 32990Sstevel@tonic-gate 33000Sstevel@tonic-gate memlist_delete(mlist); 33010Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 33020Sstevel@tonic-gate } 33030Sstevel@tonic-gate 33040Sstevel@tonic-gate #ifdef DEBUG 33050Sstevel@tonic-gate DRMACH_PR("OBP derived memlist:"); 33060Sstevel@tonic-gate memlist_dump(mlist); 33070Sstevel@tonic-gate #endif 33080Sstevel@tonic-gate 33090Sstevel@tonic-gate *ml = mlist; 33100Sstevel@tonic-gate return (NULL); 33110Sstevel@tonic-gate } 33120Sstevel@tonic-gate 33130Sstevel@tonic-gate sbd_error_t * 33140Sstevel@tonic-gate drmach_mem_get_size(drmachid_t id, uint64_t *bytes) 33150Sstevel@tonic-gate { 33160Sstevel@tonic-gate drmach_device_t *mem; 33170Sstevel@tonic-gate pda_handle_t ph; 33180Sstevel@tonic-gate pgcnt_t npages; 33190Sstevel@tonic-gate 33200Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(id)) 33210Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 33220Sstevel@tonic-gate mem = id; 33230Sstevel@tonic-gate 33240Sstevel@tonic-gate ph = drmach_pda_open(); 33250Sstevel@tonic-gate if (ph == NULL) 33260Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 33270Sstevel@tonic-gate 33280Sstevel@tonic-gate npages = pda_get_mem_size(ph, mem->bp->bnum); 33290Sstevel@tonic-gate *bytes = (uint64_t)npages << PAGESHIFT; 33300Sstevel@tonic-gate 33310Sstevel@tonic-gate pda_close(ph); 33320Sstevel@tonic-gate return (NULL); 33330Sstevel@tonic-gate } 33340Sstevel@tonic-gate 33350Sstevel@tonic-gate sbd_error_t * 33360Sstevel@tonic-gate drmach_mem_get_slice_size(drmachid_t id, uint64_t *bytes) 33370Sstevel@tonic-gate { 33380Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(id)) 33390Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 33400Sstevel@tonic-gate 33410Sstevel@tonic-gate *bytes = mc_get_mem_alignment(); 33420Sstevel@tonic-gate return (NULL); 33430Sstevel@tonic-gate } 33440Sstevel@tonic-gate 33450Sstevel@tonic-gate /* field debugging tool */ 33460Sstevel@tonic-gate processorid_t drmach_mem_cpu_affinity_nail = 0; 33470Sstevel@tonic-gate 33480Sstevel@tonic-gate processorid_t 33490Sstevel@tonic-gate drmach_mem_cpu_affinity(drmachid_t id) 33500Sstevel@tonic-gate { 33510Sstevel@tonic-gate drmach_device_t *mp; 33520Sstevel@tonic-gate drmach_board_t *bp; 33530Sstevel@tonic-gate processorid_t cpuid; 33540Sstevel@tonic-gate 33550Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(id)) 33560Sstevel@tonic-gate return (CPU_CURRENT); 33570Sstevel@tonic-gate 33580Sstevel@tonic-gate if (drmach_mem_cpu_affinity_nail) { 33590Sstevel@tonic-gate cpuid = drmach_mem_cpu_affinity_nail; 33600Sstevel@tonic-gate 33610Sstevel@tonic-gate if (cpuid < 0 || cpuid > NCPU) 33620Sstevel@tonic-gate return (CPU_CURRENT); 33630Sstevel@tonic-gate 33640Sstevel@tonic-gate mutex_enter(&cpu_lock); 33650Sstevel@tonic-gate if (cpu[cpuid] == NULL || !CPU_ACTIVE(cpu[cpuid])) 33660Sstevel@tonic-gate cpuid = CPU_CURRENT; 33670Sstevel@tonic-gate mutex_exit(&cpu_lock); 33680Sstevel@tonic-gate 33690Sstevel@tonic-gate return (cpuid); 33700Sstevel@tonic-gate } 33710Sstevel@tonic-gate 33720Sstevel@tonic-gate /* try to choose a proc on the target board */ 33730Sstevel@tonic-gate mp = id; 33740Sstevel@tonic-gate bp = mp->bp; 33750Sstevel@tonic-gate if (bp->devices) { 33760Sstevel@tonic-gate int rv; 33770Sstevel@tonic-gate int d_idx; 33780Sstevel@tonic-gate drmachid_t d_id; 33790Sstevel@tonic-gate 33800Sstevel@tonic-gate rv = drmach_array_first(bp->devices, &d_idx, &d_id); 33810Sstevel@tonic-gate while (rv == 0) { 33820Sstevel@tonic-gate if (DRMACH_IS_CPU_ID(d_id)) { 33830Sstevel@tonic-gate cpuid = drmach_cpu_calc_id(d_id); 33840Sstevel@tonic-gate 33850Sstevel@tonic-gate mutex_enter(&cpu_lock); 33860Sstevel@tonic-gate if (cpu[cpuid] && CPU_ACTIVE(cpu[cpuid])) { 33870Sstevel@tonic-gate mutex_exit(&cpu_lock); 33880Sstevel@tonic-gate DRMACH_PR("drmach_mem_cpu_affinity: " 33890Sstevel@tonic-gate "selected cpuid=%d\n", cpuid); 33900Sstevel@tonic-gate return (cpuid); 33910Sstevel@tonic-gate } else { 33920Sstevel@tonic-gate mutex_exit(&cpu_lock); 33930Sstevel@tonic-gate } 33940Sstevel@tonic-gate } 33950Sstevel@tonic-gate 33960Sstevel@tonic-gate rv = drmach_array_next(bp->devices, &d_idx, &d_id); 33970Sstevel@tonic-gate } 33980Sstevel@tonic-gate } 33990Sstevel@tonic-gate 34000Sstevel@tonic-gate /* otherwise, this proc, wherever it is */ 34010Sstevel@tonic-gate DRMACH_PR("drmach_mem_cpu_affinity: using default CPU_CURRENT\n"); 34020Sstevel@tonic-gate 34030Sstevel@tonic-gate return (CPU_CURRENT); 34040Sstevel@tonic-gate } 34050Sstevel@tonic-gate 34060Sstevel@tonic-gate static sbd_error_t * 34070Sstevel@tonic-gate drmach_mem_release(drmachid_t id) 34080Sstevel@tonic-gate { 34090Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(id)) 34100Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 34110Sstevel@tonic-gate return (NULL); 34120Sstevel@tonic-gate } 34130Sstevel@tonic-gate 34140Sstevel@tonic-gate static sbd_error_t * 34150Sstevel@tonic-gate drmach_mem_status(drmachid_t id, drmach_status_t *stat) 34160Sstevel@tonic-gate { 34170Sstevel@tonic-gate drmach_device_t *dp; 34180Sstevel@tonic-gate sbd_error_t *err; 34190Sstevel@tonic-gate uint64_t pa, slice_size; 34200Sstevel@tonic-gate struct memlist *ml; 34210Sstevel@tonic-gate 34220Sstevel@tonic-gate ASSERT(DRMACH_IS_MEM_ID(id)); 34230Sstevel@tonic-gate dp = id; 34240Sstevel@tonic-gate 34250Sstevel@tonic-gate /* get starting physical address of target memory */ 34260Sstevel@tonic-gate err = drmach_mem_get_base_physaddr(id, &pa); 34270Sstevel@tonic-gate if (err) 34280Sstevel@tonic-gate return (err); 34290Sstevel@tonic-gate 34300Sstevel@tonic-gate /* round down to slice boundary */ 34310Sstevel@tonic-gate slice_size = mc_get_mem_alignment(); 34320Sstevel@tonic-gate pa &= ~ (slice_size - 1); 34330Sstevel@tonic-gate 34340Sstevel@tonic-gate /* stop at first span that is in slice */ 34350Sstevel@tonic-gate memlist_read_lock(); 34360Sstevel@tonic-gate for (ml = phys_install; ml; ml = ml->next) 34370Sstevel@tonic-gate if (ml->address >= pa && ml->address < pa + slice_size) 34380Sstevel@tonic-gate break; 34390Sstevel@tonic-gate memlist_read_unlock(); 34400Sstevel@tonic-gate 34410Sstevel@tonic-gate stat->assigned = dp->bp->assigned; 34420Sstevel@tonic-gate stat->powered = dp->bp->powered; 34430Sstevel@tonic-gate stat->configured = (ml != NULL); 34440Sstevel@tonic-gate stat->busy = dp->busy; 34450Sstevel@tonic-gate strncpy(stat->type, dp->type, sizeof (stat->type)); 34460Sstevel@tonic-gate stat->info[0] = '\0'; 34470Sstevel@tonic-gate 34480Sstevel@tonic-gate return (NULL); 34490Sstevel@tonic-gate } 34500Sstevel@tonic-gate 34510Sstevel@tonic-gate static int 34520Sstevel@tonic-gate drmach_detach_board(void *arg) 34530Sstevel@tonic-gate { 34540Sstevel@tonic-gate cpuset_t cset; 34550Sstevel@tonic-gate int retval; 34560Sstevel@tonic-gate drmach_board_t *bp = (drmach_board_t *)arg; 34570Sstevel@tonic-gate 34580Sstevel@tonic-gate cset = cpu_ready_set; 34590Sstevel@tonic-gate promsafe_xc_attention(cset); 34600Sstevel@tonic-gate 34610Sstevel@tonic-gate retval = prom_starfire_rm_brd(bp->bnum); 34620Sstevel@tonic-gate 34630Sstevel@tonic-gate xc_dismissed(cset); 34640Sstevel@tonic-gate 34650Sstevel@tonic-gate return (retval); 34660Sstevel@tonic-gate } 34670Sstevel@tonic-gate 34680Sstevel@tonic-gate sbd_error_t * 34690Sstevel@tonic-gate drmach_board_deprobe(drmachid_t id) 34700Sstevel@tonic-gate { 34710Sstevel@tonic-gate drmach_board_t *bp; 34720Sstevel@tonic-gate int retval; 34730Sstevel@tonic-gate 34740Sstevel@tonic-gate if (!DRMACH_IS_BOARD_ID(id)) 34750Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 34760Sstevel@tonic-gate bp = id; 34770Sstevel@tonic-gate 34780Sstevel@tonic-gate cmn_err(CE_CONT, "DR: PROM detach board %d\n", bp->bnum); 34790Sstevel@tonic-gate 34800Sstevel@tonic-gate retval = prom_tree_update(drmach_detach_board, bp); 34810Sstevel@tonic-gate 34820Sstevel@tonic-gate if (retval == 0) 34830Sstevel@tonic-gate return (NULL); 34840Sstevel@tonic-gate else { 34850Sstevel@tonic-gate cmn_err(CE_WARN, "prom error: prom_starfire_rm_brd(%d) " 34860Sstevel@tonic-gate "returned %d", bp->bnum, retval); 34870Sstevel@tonic-gate return (drerr_new(1, ESTF_DEPROBE, "%s", bp->cm.name)); 34880Sstevel@tonic-gate } 34890Sstevel@tonic-gate } 34900Sstevel@tonic-gate 34910Sstevel@tonic-gate /*ARGSUSED*/ 34920Sstevel@tonic-gate static sbd_error_t * 34930Sstevel@tonic-gate drmach_pt_juggle_bootproc(drmachid_t id, drmach_opts_t *opts) 34940Sstevel@tonic-gate { 34950Sstevel@tonic-gate drmach_device_t *cpu; 34960Sstevel@tonic-gate sbd_error_t *err; 34970Sstevel@tonic-gate 34980Sstevel@tonic-gate if (!DRMACH_IS_CPU_ID(id)) 34990Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 35000Sstevel@tonic-gate cpu = id; 35010Sstevel@tonic-gate 35020Sstevel@tonic-gate mutex_enter(&cpu_lock); 35030Sstevel@tonic-gate 35040Sstevel@tonic-gate err = drmach_cpu_juggle_bootproc(cpu); 35050Sstevel@tonic-gate 35060Sstevel@tonic-gate mutex_exit(&cpu_lock); 35070Sstevel@tonic-gate 35080Sstevel@tonic-gate return (err); 35090Sstevel@tonic-gate } 35100Sstevel@tonic-gate 35110Sstevel@tonic-gate /*ARGSUSED*/ 35120Sstevel@tonic-gate static sbd_error_t * 35130Sstevel@tonic-gate drmach_pt_dump_pdainfo(drmachid_t id, drmach_opts_t *opts) 35140Sstevel@tonic-gate { 35150Sstevel@tonic-gate drmach_board_t *bp; 35160Sstevel@tonic-gate int board; 35170Sstevel@tonic-gate int i; 35180Sstevel@tonic-gate pda_handle_t ph; 35190Sstevel@tonic-gate board_desc_t *bdesc; 35200Sstevel@tonic-gate 35210Sstevel@tonic-gate if (!DRMACH_IS_BOARD_ID(id)) 35220Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 35230Sstevel@tonic-gate bp = id; 35240Sstevel@tonic-gate board = bp->bnum; 35250Sstevel@tonic-gate 35260Sstevel@tonic-gate ph = drmach_pda_open(); 35270Sstevel@tonic-gate if (ph == NULL) 35280Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 35290Sstevel@tonic-gate 35300Sstevel@tonic-gate if (pda_board_present(ph, board) == 0) { 35310Sstevel@tonic-gate cmn_err(CE_CONT, "board %d is MISSING\n", board); 35320Sstevel@tonic-gate pda_close(ph); 35330Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 35340Sstevel@tonic-gate } 35350Sstevel@tonic-gate 35360Sstevel@tonic-gate cmn_err(CE_CONT, "board %d is PRESENT\n", board); 35370Sstevel@tonic-gate 35380Sstevel@tonic-gate bdesc = (board_desc_t *)pda_get_board_info(ph, board); 35390Sstevel@tonic-gate if (bdesc == NULL) { 35400Sstevel@tonic-gate cmn_err(CE_CONT, 35410Sstevel@tonic-gate "no board descriptor found for board %d\n", 35420Sstevel@tonic-gate board); 35430Sstevel@tonic-gate pda_close(ph); 35440Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 35450Sstevel@tonic-gate } 35460Sstevel@tonic-gate 35470Sstevel@tonic-gate /* make sure definition in platmod is in sync with pda */ 35480Sstevel@tonic-gate ASSERT(MAX_PROCMODS == MAX_CPU_UNITS_PER_BOARD); 35490Sstevel@tonic-gate 35500Sstevel@tonic-gate for (i = 0; i < MAX_PROCMODS; i++) { 35510Sstevel@tonic-gate if (BDA_NBL(bdesc->bda_proc, i) == BDAN_GOOD) 35520Sstevel@tonic-gate cmn_err(CE_CONT, 35530Sstevel@tonic-gate "proc %d.%d PRESENT\n", board, i); 35540Sstevel@tonic-gate else 35550Sstevel@tonic-gate cmn_err(CE_CONT, 35560Sstevel@tonic-gate "proc %d.%d MISSING\n", board, i); 35570Sstevel@tonic-gate } 35580Sstevel@tonic-gate 35590Sstevel@tonic-gate for (i = 0; i < MAX_MGROUPS; i++) { 35600Sstevel@tonic-gate if (BDA_NBL(bdesc->bda_mgroup, i) == BDAN_GOOD) 35610Sstevel@tonic-gate cmn_err(CE_CONT, 35620Sstevel@tonic-gate "mgroup %d.%d PRESENT\n", board, i); 35630Sstevel@tonic-gate else 35640Sstevel@tonic-gate cmn_err(CE_CONT, 35650Sstevel@tonic-gate "mgroup %d.%d MISSING\n", board, i); 35660Sstevel@tonic-gate } 35670Sstevel@tonic-gate 35680Sstevel@tonic-gate /* make sure definition in platmod is in sync with pda */ 35690Sstevel@tonic-gate ASSERT(MAX_IOCS == MAX_IO_UNITS_PER_BOARD); 35700Sstevel@tonic-gate 35710Sstevel@tonic-gate for (i = 0; i < MAX_IOCS; i++) { 35720Sstevel@tonic-gate int s; 35730Sstevel@tonic-gate 35740Sstevel@tonic-gate if (BDA_NBL(bdesc->bda_ioc, i) == BDAN_GOOD) { 35750Sstevel@tonic-gate cmn_err(CE_CONT, 35760Sstevel@tonic-gate "ioc %d.%d PRESENT\n", board, i); 35770Sstevel@tonic-gate for (s = 0; s < MAX_SLOTS_PER_IOC; s++) { 35780Sstevel@tonic-gate if (BDA_NBL(bdesc->bda_ios[i], s) != BDAN_GOOD) 35790Sstevel@tonic-gate continue; 35800Sstevel@tonic-gate cmn_err(CE_CONT, 35810Sstevel@tonic-gate "..scard %d.%d.%d PRESENT\n", 35820Sstevel@tonic-gate board, i, s); 35830Sstevel@tonic-gate } 35840Sstevel@tonic-gate } else { 35850Sstevel@tonic-gate cmn_err(CE_CONT, 35860Sstevel@tonic-gate "ioc %d.%d MISSING\n", 35870Sstevel@tonic-gate board, i); 35880Sstevel@tonic-gate } 35890Sstevel@tonic-gate } 35900Sstevel@tonic-gate 35910Sstevel@tonic-gate cmn_err(CE_CONT, 35920Sstevel@tonic-gate "board %d memsize = %d pages\n", 35930Sstevel@tonic-gate board, pda_get_mem_size(ph, board)); 35940Sstevel@tonic-gate 35950Sstevel@tonic-gate pda_close(ph); 35960Sstevel@tonic-gate 35970Sstevel@tonic-gate return (NULL); 35980Sstevel@tonic-gate } 35990Sstevel@tonic-gate 36000Sstevel@tonic-gate /*ARGSUSED*/ 36010Sstevel@tonic-gate sbd_error_t * 36020Sstevel@tonic-gate drmach_pt_readmem(drmachid_t id, drmach_opts_t *opts) 36030Sstevel@tonic-gate { 36040Sstevel@tonic-gate struct memlist *ml; 36050Sstevel@tonic-gate uint64_t src_pa; 36060Sstevel@tonic-gate uint64_t dst_pa; 36070Sstevel@tonic-gate uint64_t dst; 36080Sstevel@tonic-gate 36090Sstevel@tonic-gate dst_pa = va_to_pa(&dst); 36100Sstevel@tonic-gate 36110Sstevel@tonic-gate memlist_read_lock(); 36120Sstevel@tonic-gate for (ml = phys_install; ml; ml = ml->next) { 36130Sstevel@tonic-gate uint64_t nbytes; 36140Sstevel@tonic-gate 36150Sstevel@tonic-gate src_pa = ml->address; 36160Sstevel@tonic-gate nbytes = ml->size; 36170Sstevel@tonic-gate 36180Sstevel@tonic-gate while (nbytes != 0ull) { 36190Sstevel@tonic-gate 36200Sstevel@tonic-gate /* copy 32 bytes at arc_pa to dst_pa */ 36210Sstevel@tonic-gate bcopy32_il(src_pa, dst_pa); 36220Sstevel@tonic-gate 36230Sstevel@tonic-gate /* increment by 32 bytes */ 36240Sstevel@tonic-gate src_pa += (4 * sizeof (uint64_t)); 36250Sstevel@tonic-gate 36260Sstevel@tonic-gate /* decrement by 32 bytes */ 36270Sstevel@tonic-gate nbytes -= (4 * sizeof (uint64_t)); 36280Sstevel@tonic-gate } 36290Sstevel@tonic-gate } 36300Sstevel@tonic-gate memlist_read_unlock(); 36310Sstevel@tonic-gate 36320Sstevel@tonic-gate return (NULL); 36330Sstevel@tonic-gate } 36340Sstevel@tonic-gate 36350Sstevel@tonic-gate static struct { 36360Sstevel@tonic-gate const char *name; 36370Sstevel@tonic-gate sbd_error_t *(*handler)(drmachid_t id, drmach_opts_t *opts); 36380Sstevel@tonic-gate } drmach_pt_arr[] = { 36390Sstevel@tonic-gate { "juggle", drmach_pt_juggle_bootproc }, 36400Sstevel@tonic-gate { "pda", drmach_pt_dump_pdainfo }, 36410Sstevel@tonic-gate { "readmem", drmach_pt_readmem }, 36420Sstevel@tonic-gate 36430Sstevel@tonic-gate /* the following line must always be last */ 36440Sstevel@tonic-gate { NULL, NULL } 36450Sstevel@tonic-gate }; 36460Sstevel@tonic-gate 36470Sstevel@tonic-gate /*ARGSUSED*/ 36480Sstevel@tonic-gate sbd_error_t * 36490Sstevel@tonic-gate drmach_passthru(drmachid_t id, drmach_opts_t *opts) 36500Sstevel@tonic-gate { 36510Sstevel@tonic-gate int i; 36520Sstevel@tonic-gate sbd_error_t *err; 36530Sstevel@tonic-gate 36540Sstevel@tonic-gate i = 0; 36550Sstevel@tonic-gate while (drmach_pt_arr[i].name != NULL) { 36560Sstevel@tonic-gate int len = strlen(drmach_pt_arr[i].name); 36570Sstevel@tonic-gate 36580Sstevel@tonic-gate if (strncmp(drmach_pt_arr[i].name, opts->copts, len) == 0) 36590Sstevel@tonic-gate break; 36600Sstevel@tonic-gate 36610Sstevel@tonic-gate i += 1; 36620Sstevel@tonic-gate } 36630Sstevel@tonic-gate 36640Sstevel@tonic-gate if (drmach_pt_arr[i].name == NULL) 36650Sstevel@tonic-gate err = drerr_new(0, ESTF_UNKPTCMD, opts->copts); 36660Sstevel@tonic-gate else 36670Sstevel@tonic-gate err = (*drmach_pt_arr[i].handler)(id, opts); 36680Sstevel@tonic-gate 36690Sstevel@tonic-gate return (err); 36700Sstevel@tonic-gate } 36710Sstevel@tonic-gate 36720Sstevel@tonic-gate sbd_error_t * 36730Sstevel@tonic-gate drmach_release(drmachid_t id) 36740Sstevel@tonic-gate { 36750Sstevel@tonic-gate drmach_common_t *cp; 36760Sstevel@tonic-gate if (!DRMACH_IS_DEVICE_ID(id)) 36770Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 36780Sstevel@tonic-gate cp = id; 36790Sstevel@tonic-gate 36800Sstevel@tonic-gate return (cp->release(id)); 36810Sstevel@tonic-gate } 36820Sstevel@tonic-gate 36830Sstevel@tonic-gate sbd_error_t * 36840Sstevel@tonic-gate drmach_status(drmachid_t id, drmach_status_t *stat) 36850Sstevel@tonic-gate { 36860Sstevel@tonic-gate drmach_common_t *cp; 36870Sstevel@tonic-gate 36880Sstevel@tonic-gate if (!DRMACH_IS_ID(id)) 36890Sstevel@tonic-gate return (drerr_new(0, ESTF_NOTID, NULL)); 36900Sstevel@tonic-gate cp = id; 36910Sstevel@tonic-gate 36920Sstevel@tonic-gate return (cp->status(id, stat)); 36930Sstevel@tonic-gate } 36940Sstevel@tonic-gate 36950Sstevel@tonic-gate sbd_error_t * 36960Sstevel@tonic-gate drmach_unconfigure(drmachid_t id, int flags) 36970Sstevel@tonic-gate { 36980Sstevel@tonic-gate drmach_device_t *dp; 3699789Sahrens pnode_t nodeid; 37000Sstevel@tonic-gate dev_info_t *dip, *fdip = NULL; 37010Sstevel@tonic-gate uint_t ddi_flags; 37020Sstevel@tonic-gate 37030Sstevel@tonic-gate if (!DRMACH_IS_DEVICE_ID(id)) 37040Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 37050Sstevel@tonic-gate 37060Sstevel@tonic-gate dp = id; 37070Sstevel@tonic-gate 37080Sstevel@tonic-gate nodeid = drmach_node_get_dnode(dp->node); 37090Sstevel@tonic-gate if (nodeid == OBP_NONODE) 37100Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 37110Sstevel@tonic-gate 37120Sstevel@tonic-gate dip = e_ddi_nodeid_to_dip(nodeid); 37130Sstevel@tonic-gate if (dip == NULL) 37140Sstevel@tonic-gate return (NULL); 37150Sstevel@tonic-gate 37160Sstevel@tonic-gate /* 37170Sstevel@tonic-gate * Branch already held, so hold acquired in 37180Sstevel@tonic-gate * e_ddi_nodeid_to_dip() can be released 37190Sstevel@tonic-gate */ 37200Sstevel@tonic-gate ddi_release_devi(dip); 37210Sstevel@tonic-gate 37220Sstevel@tonic-gate ddi_flags = 0; 37230Sstevel@tonic-gate 37240Sstevel@tonic-gate if (flags & DRMACH_DEVI_REMOVE) 37250Sstevel@tonic-gate ddi_flags |= DEVI_BRANCH_DESTROY | DEVI_BRANCH_EVENT; 37260Sstevel@tonic-gate 37270Sstevel@tonic-gate /* 37280Sstevel@tonic-gate * Force flag is no longer necessary. See starcat/io/drmach.c 37290Sstevel@tonic-gate * for details. 37300Sstevel@tonic-gate */ 37310Sstevel@tonic-gate ASSERT(e_ddi_branch_held(dip)); 37320Sstevel@tonic-gate if (e_ddi_branch_unconfigure(dip, &fdip, ddi_flags)) { 37330Sstevel@tonic-gate sbd_error_t *err; 37340Sstevel@tonic-gate char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 37350Sstevel@tonic-gate 37360Sstevel@tonic-gate /* 37370Sstevel@tonic-gate * If non-NULL, fdip is returned held and must be released. 37380Sstevel@tonic-gate */ 37390Sstevel@tonic-gate if (fdip != NULL) { 37400Sstevel@tonic-gate (void) ddi_pathname(fdip, path); 37410Sstevel@tonic-gate ndi_rele_devi(fdip); 37420Sstevel@tonic-gate } else { 37430Sstevel@tonic-gate (void) ddi_pathname(dip, path); 37440Sstevel@tonic-gate } 37450Sstevel@tonic-gate 37460Sstevel@tonic-gate err = drerr_new(1, ESTF_DRVFAIL, path); 37470Sstevel@tonic-gate 37480Sstevel@tonic-gate kmem_free(path, MAXPATHLEN); 37490Sstevel@tonic-gate 37500Sstevel@tonic-gate return (err); 37510Sstevel@tonic-gate } 37520Sstevel@tonic-gate 37530Sstevel@tonic-gate return (NULL); 37540Sstevel@tonic-gate } 37550Sstevel@tonic-gate 37560Sstevel@tonic-gate /* 37570Sstevel@tonic-gate * drmach interfaces to legacy Starfire platmod logic 37580Sstevel@tonic-gate * linkage via runtime symbol look up, called from plat_cpu_power* 37590Sstevel@tonic-gate */ 37600Sstevel@tonic-gate 37610Sstevel@tonic-gate /* 37620Sstevel@tonic-gate * Start up a cpu. It is possible that we're attempting to restart 37630Sstevel@tonic-gate * the cpu after an UNCONFIGURE in which case the cpu will be 37640Sstevel@tonic-gate * spinning in its cache. So, all we have to do is wakeup him up. 37650Sstevel@tonic-gate * Under normal circumstances the cpu will be coming from a previous 37660Sstevel@tonic-gate * CONNECT and thus will be spinning in OBP. In both cases, the 37670Sstevel@tonic-gate * startup sequence is the same. 37680Sstevel@tonic-gate */ 37690Sstevel@tonic-gate int 37700Sstevel@tonic-gate drmach_cpu_poweron(struct cpu *cp) 37710Sstevel@tonic-gate { 37720Sstevel@tonic-gate DRMACH_PR("drmach_cpu_poweron: starting cpuid %d\n", cp->cpu_id); 37730Sstevel@tonic-gate 37740Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 37750Sstevel@tonic-gate 37760Sstevel@tonic-gate if (drmach_cpu_start(cp) != 0) 37770Sstevel@tonic-gate return (EBUSY); 37780Sstevel@tonic-gate else 37790Sstevel@tonic-gate return (0); 37800Sstevel@tonic-gate } 37810Sstevel@tonic-gate 37820Sstevel@tonic-gate int 37830Sstevel@tonic-gate drmach_cpu_poweroff(struct cpu *cp) 37840Sstevel@tonic-gate { 37850Sstevel@tonic-gate int ntries, cnt; 37860Sstevel@tonic-gate processorid_t cpuid = cp->cpu_id; 37870Sstevel@tonic-gate void drmach_cpu_shutdown_self(void); 37880Sstevel@tonic-gate 37890Sstevel@tonic-gate DRMACH_PR("drmach_cpu_poweroff: stopping cpuid %d\n", cp->cpu_id); 37900Sstevel@tonic-gate 37910Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 37920Sstevel@tonic-gate 37930Sstevel@tonic-gate /* 37940Sstevel@tonic-gate * Capture all CPUs (except for detaching proc) to prevent 37950Sstevel@tonic-gate * crosscalls to the detaching proc until it has cleared its 37960Sstevel@tonic-gate * bit in cpu_ready_set. 37970Sstevel@tonic-gate * 37980Sstevel@tonic-gate * The CPU's remain paused and the prom_mutex is known to be free. 37990Sstevel@tonic-gate * This prevents the x-trap victim from blocking when doing prom 38000Sstevel@tonic-gate * IEEE-1275 calls at a high PIL level. 38010Sstevel@tonic-gate */ 38020Sstevel@tonic-gate promsafe_pause_cpus(); 38030Sstevel@tonic-gate 38040Sstevel@tonic-gate /* 38050Sstevel@tonic-gate * Quiesce interrupts on the target CPU. We do this by setting 38060Sstevel@tonic-gate * the CPU 'not ready'- (i.e. removing the CPU from cpu_ready_set) to 38070Sstevel@tonic-gate * prevent it from receiving cross calls and cross traps. 38080Sstevel@tonic-gate * This prevents the processor from receiving any new soft interrupts. 38090Sstevel@tonic-gate */ 38100Sstevel@tonic-gate mp_cpu_quiesce(cp); 38110Sstevel@tonic-gate 38120Sstevel@tonic-gate /* setup xt_mb, will be cleared by drmach_shutdown_asm when ready */ 38130Sstevel@tonic-gate drmach_xt_mb[cpuid] = 0x80; 38140Sstevel@tonic-gate 38150Sstevel@tonic-gate xt_one_unchecked(cpuid, (xcfunc_t *)idle_stop_xcall, 38160Sstevel@tonic-gate (uint64_t)drmach_cpu_shutdown_self, NULL); 38170Sstevel@tonic-gate 38180Sstevel@tonic-gate ntries = drmach_cpu_ntries; 38190Sstevel@tonic-gate cnt = 0; 38200Sstevel@tonic-gate while (drmach_xt_mb[cpuid] && ntries) { 38210Sstevel@tonic-gate DELAY(drmach_cpu_delay); 38220Sstevel@tonic-gate ntries--; 38230Sstevel@tonic-gate cnt++; 38240Sstevel@tonic-gate } 38250Sstevel@tonic-gate 38260Sstevel@tonic-gate drmach_xt_mb[cpuid] = 0; /* steal the cache line back */ 38270Sstevel@tonic-gate 38280Sstevel@tonic-gate start_cpus(); 38290Sstevel@tonic-gate 38300Sstevel@tonic-gate DRMACH_PR("waited %d out of %d tries for " 38310Sstevel@tonic-gate "drmach_cpu_shutdown_self on cpu%d", 38320Sstevel@tonic-gate drmach_cpu_ntries - ntries, drmach_cpu_ntries, cp->cpu_id); 38330Sstevel@tonic-gate 38340Sstevel@tonic-gate drmach_cpu_obp_detach(cpuid); 38350Sstevel@tonic-gate 38360Sstevel@tonic-gate CPU_SIGNATURE(OS_SIG, SIGST_DETACHED, SIGSUBST_NULL, cpuid); 38370Sstevel@tonic-gate 38380Sstevel@tonic-gate return (0); 38390Sstevel@tonic-gate } 38400Sstevel@tonic-gate 38410Sstevel@tonic-gate /*ARGSUSED*/ 38420Sstevel@tonic-gate int 38430Sstevel@tonic-gate drmach_verify_sr(dev_info_t *dip, int sflag) 38440Sstevel@tonic-gate { 38450Sstevel@tonic-gate return (0); 38460Sstevel@tonic-gate } 38470Sstevel@tonic-gate 38480Sstevel@tonic-gate void 38490Sstevel@tonic-gate drmach_suspend_last(void) 38500Sstevel@tonic-gate { 38510Sstevel@tonic-gate } 38520Sstevel@tonic-gate 38530Sstevel@tonic-gate void 38540Sstevel@tonic-gate drmach_resume_first(void) 38550Sstevel@tonic-gate { 38560Sstevel@tonic-gate } 38570Sstevel@tonic-gate 38580Sstevel@tonic-gate /* 38590Sstevel@tonic-gate * Log a DR sysevent. 38600Sstevel@tonic-gate * Return value: 0 success, non-zero failure. 38610Sstevel@tonic-gate */ 38620Sstevel@tonic-gate int 38630Sstevel@tonic-gate drmach_log_sysevent(int board, char *hint, int flag, int verbose) 38640Sstevel@tonic-gate { 38650Sstevel@tonic-gate sysevent_t *ev; 38660Sstevel@tonic-gate sysevent_id_t eid; 38670Sstevel@tonic-gate int rv, km_flag; 38680Sstevel@tonic-gate sysevent_value_t evnt_val; 38690Sstevel@tonic-gate sysevent_attr_list_t *evnt_attr_list = NULL; 38700Sstevel@tonic-gate char attach_pnt[MAXNAMELEN]; 38710Sstevel@tonic-gate 38720Sstevel@tonic-gate km_flag = (flag == SE_SLEEP) ? KM_SLEEP : KM_NOSLEEP; 38730Sstevel@tonic-gate attach_pnt[0] = '\0'; 38740Sstevel@tonic-gate if (drmach_board_name(board, attach_pnt, MAXNAMELEN)) { 38750Sstevel@tonic-gate rv = -1; 38760Sstevel@tonic-gate goto logexit; 38770Sstevel@tonic-gate } 38780Sstevel@tonic-gate if (verbose) 38790Sstevel@tonic-gate DRMACH_PR("drmach_log_sysevent: %s %s, flag: %d, verbose: %d\n", 38800Sstevel@tonic-gate attach_pnt, hint, flag, verbose); 38810Sstevel@tonic-gate 38820Sstevel@tonic-gate if ((ev = sysevent_alloc(EC_DR, ESC_DR_AP_STATE_CHANGE, 38830Sstevel@tonic-gate SUNW_KERN_PUB"dr", km_flag)) == NULL) { 38840Sstevel@tonic-gate rv = -2; 38850Sstevel@tonic-gate goto logexit; 38860Sstevel@tonic-gate } 38870Sstevel@tonic-gate evnt_val.value_type = SE_DATA_TYPE_STRING; 38880Sstevel@tonic-gate evnt_val.value.sv_string = attach_pnt; 38890Sstevel@tonic-gate if ((rv = sysevent_add_attr(&evnt_attr_list, DR_AP_ID, 38900Sstevel@tonic-gate &evnt_val, km_flag)) != 0) 38910Sstevel@tonic-gate goto logexit; 38920Sstevel@tonic-gate 38930Sstevel@tonic-gate evnt_val.value_type = SE_DATA_TYPE_STRING; 38940Sstevel@tonic-gate evnt_val.value.sv_string = hint; 38950Sstevel@tonic-gate if ((rv = sysevent_add_attr(&evnt_attr_list, DR_HINT, 38960Sstevel@tonic-gate &evnt_val, km_flag)) != 0) { 38970Sstevel@tonic-gate sysevent_free_attr(evnt_attr_list); 38980Sstevel@tonic-gate goto logexit; 38990Sstevel@tonic-gate } 39000Sstevel@tonic-gate 39010Sstevel@tonic-gate (void) sysevent_attach_attributes(ev, evnt_attr_list); 39020Sstevel@tonic-gate 39030Sstevel@tonic-gate /* 39040Sstevel@tonic-gate * Log the event but do not sleep waiting for its 39050Sstevel@tonic-gate * delivery. This provides insulation from syseventd. 39060Sstevel@tonic-gate */ 39070Sstevel@tonic-gate rv = log_sysevent(ev, SE_NOSLEEP, &eid); 39080Sstevel@tonic-gate 39090Sstevel@tonic-gate logexit: 39100Sstevel@tonic-gate if (ev) 39110Sstevel@tonic-gate sysevent_free(ev); 39120Sstevel@tonic-gate if ((rv != 0) && verbose) 39130Sstevel@tonic-gate cmn_err(CE_WARN, 39140Sstevel@tonic-gate "drmach_log_sysevent failed (rv %d) for %s %s\n", 39150Sstevel@tonic-gate rv, attach_pnt, hint); 39160Sstevel@tonic-gate 39170Sstevel@tonic-gate return (rv); 39180Sstevel@tonic-gate } 39190Sstevel@tonic-gate 39200Sstevel@tonic-gate /*ARGSUSED*/ 39210Sstevel@tonic-gate int 39220Sstevel@tonic-gate drmach_allow_memrange_modify(drmachid_t id) 39230Sstevel@tonic-gate { 39240Sstevel@tonic-gate return (1); /* TRUE */ 39250Sstevel@tonic-gate } 3926