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