17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5447e4a63Spetede * Common Development and Distribution License (the "License"). 6447e4a63Spetede * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 2107d06da5SSurya Prakki 227c478bd9Sstevel@tonic-gate /* 2356f33205SJonathan Adams * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 2589b43686SBayard Bell * Copyright (c) 2011 Bayard G. Bell. All rights reserved. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <sys/debug.h> 297c478bd9Sstevel@tonic-gate #include <sys/types.h> 307c478bd9Sstevel@tonic-gate #include <sys/varargs.h> 317c478bd9Sstevel@tonic-gate #include <sys/errno.h> 327c478bd9Sstevel@tonic-gate #include <sys/cred.h> 337c478bd9Sstevel@tonic-gate #include <sys/dditypes.h> 347c478bd9Sstevel@tonic-gate #include <sys/devops.h> 357c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 367c478bd9Sstevel@tonic-gate #include <sys/poll.h> 377c478bd9Sstevel@tonic-gate #include <sys/conf.h> 387c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 397c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 407c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 417c478bd9Sstevel@tonic-gate #include <sys/ndi_impldefs.h> 427c478bd9Sstevel@tonic-gate #include <sys/stat.h> 437c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 447c478bd9Sstevel@tonic-gate #include <sys/vmem.h> 457c478bd9Sstevel@tonic-gate #include <sys/processor.h> 467c478bd9Sstevel@tonic-gate #include <sys/spitregs.h> 477c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 487c478bd9Sstevel@tonic-gate #include <sys/cpupart.h> 497c478bd9Sstevel@tonic-gate #include <sys/mem_config.h> 507c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 517c478bd9Sstevel@tonic-gate #include <sys/systm.h> 527c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> 537c478bd9Sstevel@tonic-gate #include <sys/autoconf.h> 547c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 557c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 567c478bd9Sstevel@tonic-gate #include <sys/x_call.h> 577c478bd9Sstevel@tonic-gate #include <sys/promif.h> 587c478bd9Sstevel@tonic-gate #include <sys/prom_plat.h> 597c478bd9Sstevel@tonic-gate #include <sys/membar.h> 607c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h> 617c478bd9Sstevel@tonic-gate #include <sys/mem_cage.h> 627c478bd9Sstevel@tonic-gate #include <sys/stack.h> 637c478bd9Sstevel@tonic-gate #include <sys/archsystm.h> 647c478bd9Sstevel@tonic-gate #include <vm/hat_sfmmu.h> 657c478bd9Sstevel@tonic-gate #include <sys/pte.h> 667c478bd9Sstevel@tonic-gate #include <sys/mmu.h> 677c478bd9Sstevel@tonic-gate #include <sys/cpu_module.h> 687c478bd9Sstevel@tonic-gate #include <sys/obpdefs.h> 697c478bd9Sstevel@tonic-gate #include <sys/note.h> 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate #include <sys/starfire.h> /* plat_max_... decls */ 727c478bd9Sstevel@tonic-gate #include <sys/cvc.h> 737c478bd9Sstevel@tonic-gate #include <sys/cpu_sgnblk_defs.h> 747c478bd9Sstevel@tonic-gate #include <sys/drmach.h> 757c478bd9Sstevel@tonic-gate #include <sys/dr_util.h> 767c478bd9Sstevel@tonic-gate #include <sys/pda.h> 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate #include <sys/sysevent.h> 797c478bd9Sstevel@tonic-gate #include <sys/sysevent/dr.h> 807c478bd9Sstevel@tonic-gate #include <sys/sysevent/eventdefs.h> 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate extern void bcopy32_il(uint64_t, uint64_t); 847c478bd9Sstevel@tonic-gate extern void flush_ecache_il( 857c478bd9Sstevel@tonic-gate uint64_t physaddr, int size, int linesz); 867c478bd9Sstevel@tonic-gate extern uint_t ldphysio_il(uint64_t physaddr); 877c478bd9Sstevel@tonic-gate extern void stphysio_il(uint64_t physaddr, uint_t value); 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate extern uint64_t mc_get_mem_alignment(void); 90fa9e4066Sahrens extern uint64_t mc_get_asr_addr(pnode_t); 91fa9e4066Sahrens extern uint64_t mc_get_idle_addr(pnode_t); 92fa9e4066Sahrens extern uint64_t mc_get_alignment_mask(pnode_t); 93fa9e4066Sahrens extern int mc_read_asr(pnode_t, uint_t *); 94fa9e4066Sahrens extern int mc_write_asr(pnode_t, uint_t); 957c478bd9Sstevel@tonic-gate extern uint64_t mc_asr_to_pa(uint_t); 967c478bd9Sstevel@tonic-gate extern uint_t mc_pa_to_asr(uint_t, uint64_t); 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate extern int pc_madr_add(int, int, int, int); 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate typedef struct { 1017c478bd9Sstevel@tonic-gate struct drmach_node *node; 1027c478bd9Sstevel@tonic-gate void *data; 1037c478bd9Sstevel@tonic-gate } drmach_node_walk_args_t; 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate typedef struct drmach_node { 1067c478bd9Sstevel@tonic-gate void *here; 1077c478bd9Sstevel@tonic-gate 108fa9e4066Sahrens pnode_t (*get_dnode)(struct drmach_node *node); 1097c478bd9Sstevel@tonic-gate int (*walk)(struct drmach_node *node, void *data, 1107c478bd9Sstevel@tonic-gate int (*cb)(drmach_node_walk_args_t *args)); 1117c478bd9Sstevel@tonic-gate } drmach_node_t; 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate typedef struct { 1147c478bd9Sstevel@tonic-gate int min_index; 1157c478bd9Sstevel@tonic-gate int max_index; 1167c478bd9Sstevel@tonic-gate int arr_sz; 1177c478bd9Sstevel@tonic-gate drmachid_t *arr; 1187c478bd9Sstevel@tonic-gate } drmach_array_t; 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate typedef struct { 1217c478bd9Sstevel@tonic-gate void *isa; 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate sbd_error_t *(*release)(drmachid_t); 1247c478bd9Sstevel@tonic-gate sbd_error_t *(*status)(drmachid_t, drmach_status_t *); 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate char name[MAXNAMELEN]; 1277c478bd9Sstevel@tonic-gate } drmach_common_t; 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate typedef struct { 1307c478bd9Sstevel@tonic-gate drmach_common_t cm; 1317c478bd9Sstevel@tonic-gate int bnum; 1327c478bd9Sstevel@tonic-gate int assigned; 1337c478bd9Sstevel@tonic-gate int powered; 1347c478bd9Sstevel@tonic-gate int connect_cpuid; 1357c478bd9Sstevel@tonic-gate int cond; 1367c478bd9Sstevel@tonic-gate drmach_node_t *tree; 1377c478bd9Sstevel@tonic-gate drmach_array_t *devices; 1387c478bd9Sstevel@tonic-gate } drmach_board_t; 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate typedef struct { 1417c478bd9Sstevel@tonic-gate drmach_common_t cm; 1427c478bd9Sstevel@tonic-gate drmach_board_t *bp; 1437c478bd9Sstevel@tonic-gate int unum; 1447c478bd9Sstevel@tonic-gate int busy; 1457c478bd9Sstevel@tonic-gate int powered; 1467c478bd9Sstevel@tonic-gate const char *type; 1477c478bd9Sstevel@tonic-gate drmach_node_t *node; 1487c478bd9Sstevel@tonic-gate } drmach_device_t; 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate typedef struct { 1517c478bd9Sstevel@tonic-gate int flags; 1527c478bd9Sstevel@tonic-gate drmach_device_t *dp; 1537c478bd9Sstevel@tonic-gate sbd_error_t *err; 1547c478bd9Sstevel@tonic-gate dev_info_t *dip; 1557c478bd9Sstevel@tonic-gate } drmach_config_args_t; 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate typedef struct { 1587c478bd9Sstevel@tonic-gate uint64_t idle_addr; 1597c478bd9Sstevel@tonic-gate drmach_device_t *mem; 1607c478bd9Sstevel@tonic-gate } drmach_mc_idle_script_t; 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate typedef struct { 1637c478bd9Sstevel@tonic-gate uint64_t masr_addr; 1647c478bd9Sstevel@tonic-gate uint_t masr; 1657c478bd9Sstevel@tonic-gate uint_t _filler; 1667c478bd9Sstevel@tonic-gate } drmach_rename_script_t; 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate typedef struct { 1697c478bd9Sstevel@tonic-gate void (*run)(void *arg); 1707c478bd9Sstevel@tonic-gate caddr_t data; 1717c478bd9Sstevel@tonic-gate pda_handle_t *ph; 1727c478bd9Sstevel@tonic-gate struct memlist *c_ml; 1737c478bd9Sstevel@tonic-gate uint64_t s_copybasepa; 1747c478bd9Sstevel@tonic-gate uint64_t t_copybasepa; 1757c478bd9Sstevel@tonic-gate drmach_device_t *restless_mc; /* diagnostic output */ 1767c478bd9Sstevel@tonic-gate } drmach_copy_rename_program_t; 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate typedef enum { 1797c478bd9Sstevel@tonic-gate DO_IDLE, 1807c478bd9Sstevel@tonic-gate DO_UNIDLE, 1817c478bd9Sstevel@tonic-gate DO_PAUSE, 1827c478bd9Sstevel@tonic-gate DO_UNPAUSE 1837c478bd9Sstevel@tonic-gate } drmach_iopc_op_t; 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate typedef struct { 1867c478bd9Sstevel@tonic-gate drmach_board_t *obj; 1877c478bd9Sstevel@tonic-gate int ndevs; 1887c478bd9Sstevel@tonic-gate void *a; 1897c478bd9Sstevel@tonic-gate sbd_error_t *(*found)(void *a, const char *, int, drmachid_t); 1907c478bd9Sstevel@tonic-gate sbd_error_t *err; 1917c478bd9Sstevel@tonic-gate } drmach_board_cb_data_t; 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate static caddr_t drmach_shutdown_va; 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate static int drmach_initialized; 1967c478bd9Sstevel@tonic-gate static drmach_array_t *drmach_boards; 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate static int drmach_cpu_delay = 100; 1997c478bd9Sstevel@tonic-gate static int drmach_cpu_ntries = 50000; 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate volatile uchar_t *drmach_xt_mb; 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate /* 2047c478bd9Sstevel@tonic-gate * Do not change the drmach_shutdown_mbox structure without 2057c478bd9Sstevel@tonic-gate * considering the drmach_shutdown_asm assembly language code. 2067c478bd9Sstevel@tonic-gate */ 2077c478bd9Sstevel@tonic-gate struct drmach_shutdown_mbox { 2087c478bd9Sstevel@tonic-gate uint64_t estack; 2097c478bd9Sstevel@tonic-gate uint64_t flushaddr; 2107c478bd9Sstevel@tonic-gate int size; 2117c478bd9Sstevel@tonic-gate int linesize; 2127c478bd9Sstevel@tonic-gate uint64_t physaddr; 2137c478bd9Sstevel@tonic-gate }; 2147c478bd9Sstevel@tonic-gate struct drmach_shutdown_mbox *drmach_shutdown_asm_mbox; 2158682d1efSRichard Lowe 2168682d1efSRichard Lowe static int drmach_fini(void); 2177c478bd9Sstevel@tonic-gate static sbd_error_t *drmach_device_new(drmach_node_t *, 2187c478bd9Sstevel@tonic-gate drmach_board_t *, drmach_device_t **); 2197c478bd9Sstevel@tonic-gate static sbd_error_t *drmach_cpu_new(drmach_device_t *); 2207c478bd9Sstevel@tonic-gate static sbd_error_t *drmach_mem_new(drmach_device_t *); 2217c478bd9Sstevel@tonic-gate static sbd_error_t *drmach_io_new(drmach_device_t *); 2228682d1efSRichard Lowe static sbd_error_t *drmach_board_release(drmachid_t); 2238682d1efSRichard Lowe static sbd_error_t *drmach_board_status(drmachid_t, drmach_status_t *); 2248682d1efSRichard Lowe static sbd_error_t *drmach_cpu_release(drmachid_t); 2258682d1efSRichard Lowe static sbd_error_t *drmach_cpu_status(drmachid_t, drmach_status_t *); 2268682d1efSRichard Lowe static sbd_error_t *drmach_io_release(drmachid_t); 2278682d1efSRichard Lowe static sbd_error_t *drmach_io_status(drmachid_t, drmach_status_t *); 2288682d1efSRichard Lowe static sbd_error_t *drmach_mem_release(drmachid_t); 2298682d1efSRichard Lowe static sbd_error_t *drmach_mem_status(drmachid_t, drmach_status_t *); 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate extern struct cpu *SIGBCPU; 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate #ifdef DEBUG 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate #define DRMACH_PR if (drmach_debug) printf 2367c478bd9Sstevel@tonic-gate int drmach_debug = 0; /* set to non-zero to enable debug messages */ 2377c478bd9Sstevel@tonic-gate #else 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate #define DRMACH_PR _NOTE(CONSTANTCONDITION) if (0) printf 2407c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate #define DRMACH_OBJ(id) ((drmach_common_t *)id) 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate #define DRMACH_IS_BOARD_ID(id) \ 2457c478bd9Sstevel@tonic-gate ((id != 0) && \ 2467c478bd9Sstevel@tonic-gate (DRMACH_OBJ(id)->isa == (void *)drmach_board_new)) 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate #define DRMACH_IS_CPU_ID(id) \ 2497c478bd9Sstevel@tonic-gate ((id != 0) && \ 2507c478bd9Sstevel@tonic-gate (DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new)) 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate #define DRMACH_IS_MEM_ID(id) \ 2537c478bd9Sstevel@tonic-gate ((id != 0) && \ 2547c478bd9Sstevel@tonic-gate (DRMACH_OBJ(id)->isa == (void *)drmach_mem_new)) 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate #define DRMACH_IS_IO_ID(id) \ 2577c478bd9Sstevel@tonic-gate ((id != 0) && \ 2587c478bd9Sstevel@tonic-gate (DRMACH_OBJ(id)->isa == (void *)drmach_io_new)) 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate #define DRMACH_IS_DEVICE_ID(id) \ 2617c478bd9Sstevel@tonic-gate ((id != 0) && \ 2627c478bd9Sstevel@tonic-gate (DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new || \ 2637c478bd9Sstevel@tonic-gate DRMACH_OBJ(id)->isa == (void *)drmach_mem_new || \ 2647c478bd9Sstevel@tonic-gate DRMACH_OBJ(id)->isa == (void *)drmach_io_new)) 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate #define DRMACH_IS_ID(id) \ 2677c478bd9Sstevel@tonic-gate ((id != 0) && \ 2687c478bd9Sstevel@tonic-gate (DRMACH_OBJ(id)->isa == (void *)drmach_board_new || \ 2697c478bd9Sstevel@tonic-gate DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new || \ 2707c478bd9Sstevel@tonic-gate DRMACH_OBJ(id)->isa == (void *)drmach_mem_new || \ 2717c478bd9Sstevel@tonic-gate DRMACH_OBJ(id)->isa == (void *)drmach_io_new)) 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate #define DRMACH_CPUID2BNUM(cpuid) \ 2747c478bd9Sstevel@tonic-gate ((cpuid) / MAX_CPU_UNITS_PER_BOARD) 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate #define DRMACH_INTERNAL_ERROR() \ 2777c478bd9Sstevel@tonic-gate drerr_new(1, ESTF_INTERNAL, drmach_ie_fmt, __LINE__) 2787c478bd9Sstevel@tonic-gate static char *drmach_ie_fmt = "drmach.c %d"; 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate static struct { 2817c478bd9Sstevel@tonic-gate const char *name; 2827c478bd9Sstevel@tonic-gate const char *type; 2837c478bd9Sstevel@tonic-gate sbd_error_t *(*new)(drmach_device_t *); 2847c478bd9Sstevel@tonic-gate } name2type[] = { 2857c478bd9Sstevel@tonic-gate { "SUNW,UltraSPARC", DRMACH_DEVTYPE_CPU, drmach_cpu_new }, 2867c478bd9Sstevel@tonic-gate { "mem-unit", DRMACH_DEVTYPE_MEM, drmach_mem_new }, 2877c478bd9Sstevel@tonic-gate { "pci", DRMACH_DEVTYPE_PCI, drmach_io_new }, 2887c478bd9Sstevel@tonic-gate { "sbus", DRMACH_DEVTYPE_SBUS, drmach_io_new }, 2897c478bd9Sstevel@tonic-gate }; 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate /* node types to cleanup when a board is unconfigured */ 2927c478bd9Sstevel@tonic-gate #define MISC_COUNTER_TIMER_DEVNAME "counter-timer" 2937c478bd9Sstevel@tonic-gate #define MISC_PERF_COUNTER_DEVNAME "perf-counter" 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate /* utility */ 2967c478bd9Sstevel@tonic-gate #define MBYTE (1048576ull) 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate /* 2997c478bd9Sstevel@tonic-gate * drmach autoconfiguration data structures and interfaces 3007c478bd9Sstevel@tonic-gate */ 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate extern struct mod_ops mod_miscops; 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate static struct modlmisc modlmisc = { 3057c478bd9Sstevel@tonic-gate &mod_miscops, 306f500b196SRichard Bean "Sun Enterprise 10000 DR" 3077c478bd9Sstevel@tonic-gate }; 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 3107c478bd9Sstevel@tonic-gate MODREV_1, 3117c478bd9Sstevel@tonic-gate (void *)&modlmisc, 3127c478bd9Sstevel@tonic-gate NULL 3137c478bd9Sstevel@tonic-gate }; 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate static kmutex_t drmach_i_lock; 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate int 3187c478bd9Sstevel@tonic-gate _init(void) 3197c478bd9Sstevel@tonic-gate { 3207c478bd9Sstevel@tonic-gate int err; 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate /* check that we have the correct version of obp */ 3237c478bd9Sstevel@tonic-gate if (prom_test("SUNW,UE10000,add-brd") != 0) { 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "!OBP/SSP upgrade is required to enable " 3267c478bd9Sstevel@tonic-gate "DR Functionality"); 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate return (-1); 3297c478bd9Sstevel@tonic-gate } 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate mutex_init(&drmach_i_lock, NULL, MUTEX_DRIVER, NULL); 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate drmach_xt_mb = (uchar_t *)vmem_alloc(static_alloc_arena, 3347c478bd9Sstevel@tonic-gate NCPU * sizeof (uchar_t), VM_SLEEP); 3357c478bd9Sstevel@tonic-gate drmach_shutdown_asm_mbox = (struct drmach_shutdown_mbox *) 3367c478bd9Sstevel@tonic-gate vmem_alloc(static_alloc_arena, sizeof (struct drmach_shutdown_mbox), 3377c478bd9Sstevel@tonic-gate VM_SLEEP); 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate if ((err = mod_install(&modlinkage)) != 0) { 3407c478bd9Sstevel@tonic-gate mutex_destroy(&drmach_i_lock); 3417c478bd9Sstevel@tonic-gate vmem_free(static_alloc_arena, (void *)drmach_xt_mb, 3427c478bd9Sstevel@tonic-gate NCPU * sizeof (uchar_t)); 3437c478bd9Sstevel@tonic-gate vmem_free(static_alloc_arena, (void *)drmach_shutdown_asm_mbox, 3447c478bd9Sstevel@tonic-gate sizeof (struct drmach_shutdown_mbox)); 3457c478bd9Sstevel@tonic-gate } 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate return (err); 3487c478bd9Sstevel@tonic-gate } 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate int 3517c478bd9Sstevel@tonic-gate _fini(void) 3527c478bd9Sstevel@tonic-gate { 3537c478bd9Sstevel@tonic-gate if (drmach_fini()) 3547c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3557c478bd9Sstevel@tonic-gate else 3567c478bd9Sstevel@tonic-gate return (mod_remove(&modlinkage)); 3577c478bd9Sstevel@tonic-gate } 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate int 3607c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 3617c478bd9Sstevel@tonic-gate { 3627c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate 365fa9e4066Sahrens static pnode_t 3667c478bd9Sstevel@tonic-gate drmach_node_obp_get_dnode(drmach_node_t *np) 3677c478bd9Sstevel@tonic-gate { 36804580fdfSmathue return ((pnode_t)(uintptr_t)np->here); 3697c478bd9Sstevel@tonic-gate } 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate static int 3727c478bd9Sstevel@tonic-gate drmach_node_obp_walk(drmach_node_t *np, void *data, 3737c478bd9Sstevel@tonic-gate int (*cb)(drmach_node_walk_args_t *args)) 3747c478bd9Sstevel@tonic-gate { 375fa9e4066Sahrens pnode_t nodeid; 3767c478bd9Sstevel@tonic-gate int rv; 3777c478bd9Sstevel@tonic-gate drmach_node_walk_args_t args; 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate /* initialized args structure for callback */ 3807c478bd9Sstevel@tonic-gate args.node = np; 3817c478bd9Sstevel@tonic-gate args.data = data; 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate nodeid = prom_childnode(prom_rootnode()); 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate /* save our new position with in the tree */ 38604580fdfSmathue np->here = (void *)(uintptr_t)nodeid; 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate rv = 0; 3897c478bd9Sstevel@tonic-gate while (nodeid != OBP_NONODE) { 3907c478bd9Sstevel@tonic-gate rv = (*cb)(&args); 3917c478bd9Sstevel@tonic-gate if (rv) 3927c478bd9Sstevel@tonic-gate break; 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate nodeid = prom_nextnode(nodeid); 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate /* save our new position with in the tree */ 39704580fdfSmathue np->here = (void *)(uintptr_t)nodeid; 3987c478bd9Sstevel@tonic-gate } 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate return (rv); 4017c478bd9Sstevel@tonic-gate } 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate static drmach_node_t * 4047c478bd9Sstevel@tonic-gate drmach_node_new(void) 4057c478bd9Sstevel@tonic-gate { 4067c478bd9Sstevel@tonic-gate drmach_node_t *np; 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate np = kmem_zalloc(sizeof (drmach_node_t), KM_SLEEP); 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate np->get_dnode = drmach_node_obp_get_dnode; 4117c478bd9Sstevel@tonic-gate np->walk = drmach_node_obp_walk; 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate return (np); 4147c478bd9Sstevel@tonic-gate } 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate static void 4177c478bd9Sstevel@tonic-gate drmach_node_dispose(drmach_node_t *np) 4187c478bd9Sstevel@tonic-gate { 4197c478bd9Sstevel@tonic-gate kmem_free(np, sizeof (*np)); 4207c478bd9Sstevel@tonic-gate } 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate static dev_info_t * 4237c478bd9Sstevel@tonic-gate drmach_node_get_dip(drmach_node_t *np) 4247c478bd9Sstevel@tonic-gate { 425fa9e4066Sahrens pnode_t nodeid; 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate nodeid = np->get_dnode(np); 4287c478bd9Sstevel@tonic-gate if (nodeid == OBP_NONODE) 4297c478bd9Sstevel@tonic-gate return (NULL); 4307c478bd9Sstevel@tonic-gate else { 4317c478bd9Sstevel@tonic-gate dev_info_t *dip; 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate /* The root node doesn't have to be held */ 4347c478bd9Sstevel@tonic-gate dip = e_ddi_nodeid_to_dip(nodeid); 4357c478bd9Sstevel@tonic-gate if (dip) { 4367c478bd9Sstevel@tonic-gate /* 4377c478bd9Sstevel@tonic-gate * Branch rooted at dip is already held, so release 4387c478bd9Sstevel@tonic-gate * hold acquired in e_ddi_nodeid_to_dip() 4397c478bd9Sstevel@tonic-gate */ 4407c478bd9Sstevel@tonic-gate ddi_release_devi(dip); 4417c478bd9Sstevel@tonic-gate ASSERT(e_ddi_branch_held(dip)); 4427c478bd9Sstevel@tonic-gate } 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate return (dip); 4457c478bd9Sstevel@tonic-gate } 4467c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 4477c478bd9Sstevel@tonic-gate } 4487c478bd9Sstevel@tonic-gate 449fa9e4066Sahrens static pnode_t 4507c478bd9Sstevel@tonic-gate drmach_node_get_dnode(drmach_node_t *np) 4517c478bd9Sstevel@tonic-gate { 4527c478bd9Sstevel@tonic-gate return (np->get_dnode(np)); 4537c478bd9Sstevel@tonic-gate } 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate static int 4567c478bd9Sstevel@tonic-gate drmach_node_walk(drmach_node_t *np, void *param, 4577c478bd9Sstevel@tonic-gate int (*cb)(drmach_node_walk_args_t *args)) 4587c478bd9Sstevel@tonic-gate { 4597c478bd9Sstevel@tonic-gate return (np->walk(np, param, cb)); 4607c478bd9Sstevel@tonic-gate } 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate static int 4637c478bd9Sstevel@tonic-gate drmach_node_get_prop(drmach_node_t *np, char *name, void *buf) 4647c478bd9Sstevel@tonic-gate { 465fa9e4066Sahrens pnode_t nodeid; 4667c478bd9Sstevel@tonic-gate int rv; 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate nodeid = np->get_dnode(np); 4697c478bd9Sstevel@tonic-gate if (nodeid == OBP_NONODE) 4707c478bd9Sstevel@tonic-gate rv = -1; 4717c478bd9Sstevel@tonic-gate else if (prom_getproplen(nodeid, (caddr_t)name) < 0) 4727c478bd9Sstevel@tonic-gate rv = -1; 4737c478bd9Sstevel@tonic-gate else { 4747c478bd9Sstevel@tonic-gate (void) prom_getprop(nodeid, (caddr_t)name, (caddr_t)buf); 4757c478bd9Sstevel@tonic-gate rv = 0; 4767c478bd9Sstevel@tonic-gate } 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate return (rv); 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate static int 4827c478bd9Sstevel@tonic-gate drmach_node_get_proplen(drmach_node_t *np, char *name, int *len) 4837c478bd9Sstevel@tonic-gate { 484fa9e4066Sahrens pnode_t nodeid; 4857c478bd9Sstevel@tonic-gate int rv; 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate nodeid = np->get_dnode(np); 4887c478bd9Sstevel@tonic-gate if (nodeid == OBP_NONODE) 4897c478bd9Sstevel@tonic-gate rv = -1; 4907c478bd9Sstevel@tonic-gate else { 4917c478bd9Sstevel@tonic-gate *len = prom_getproplen(nodeid, (caddr_t)name); 4927c478bd9Sstevel@tonic-gate rv = (*len < 0 ? -1 : 0); 4937c478bd9Sstevel@tonic-gate } 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate return (rv); 4967c478bd9Sstevel@tonic-gate } 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate static drmachid_t 4997c478bd9Sstevel@tonic-gate drmach_node_dup(drmach_node_t *np) 5007c478bd9Sstevel@tonic-gate { 5017c478bd9Sstevel@tonic-gate drmach_node_t *dup; 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate dup = drmach_node_new(); 5047c478bd9Sstevel@tonic-gate dup->here = np->here; 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate return (dup); 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate /* 5107c478bd9Sstevel@tonic-gate * drmach_array provides convenient array construction, access, 5117c478bd9Sstevel@tonic-gate * bounds checking and array destruction logic. 5127c478bd9Sstevel@tonic-gate */ 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate static drmach_array_t * 5157c478bd9Sstevel@tonic-gate drmach_array_new(int min_index, int max_index) 5167c478bd9Sstevel@tonic-gate { 5177c478bd9Sstevel@tonic-gate drmach_array_t *arr; 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate arr = kmem_zalloc(sizeof (drmach_array_t), KM_SLEEP); 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate arr->arr_sz = (max_index - min_index + 1) * sizeof (void *); 5227c478bd9Sstevel@tonic-gate if (arr->arr_sz > 0) { 5237c478bd9Sstevel@tonic-gate arr->min_index = min_index; 5247c478bd9Sstevel@tonic-gate arr->max_index = max_index; 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate arr->arr = kmem_zalloc(arr->arr_sz, KM_SLEEP); 5277c478bd9Sstevel@tonic-gate return (arr); 5287c478bd9Sstevel@tonic-gate } else { 5297c478bd9Sstevel@tonic-gate kmem_free(arr, sizeof (*arr)); 5307c478bd9Sstevel@tonic-gate return (0); 5317c478bd9Sstevel@tonic-gate } 5327c478bd9Sstevel@tonic-gate } 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate static int 5357c478bd9Sstevel@tonic-gate drmach_array_set(drmach_array_t *arr, int idx, drmachid_t val) 5367c478bd9Sstevel@tonic-gate { 5377c478bd9Sstevel@tonic-gate if (idx < arr->min_index || idx > arr->max_index) 5387c478bd9Sstevel@tonic-gate return (-1); 5397c478bd9Sstevel@tonic-gate else { 5407c478bd9Sstevel@tonic-gate arr->arr[idx - arr->min_index] = val; 5417c478bd9Sstevel@tonic-gate return (0); 5427c478bd9Sstevel@tonic-gate } 5437c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 5447c478bd9Sstevel@tonic-gate } 5457c478bd9Sstevel@tonic-gate 5467c478bd9Sstevel@tonic-gate static int 5477c478bd9Sstevel@tonic-gate drmach_array_get(drmach_array_t *arr, int idx, drmachid_t *val) 5487c478bd9Sstevel@tonic-gate { 5497c478bd9Sstevel@tonic-gate if (idx < arr->min_index || idx > arr->max_index) 5507c478bd9Sstevel@tonic-gate return (-1); 5517c478bd9Sstevel@tonic-gate else { 5527c478bd9Sstevel@tonic-gate *val = arr->arr[idx - arr->min_index]; 5537c478bd9Sstevel@tonic-gate return (0); 5547c478bd9Sstevel@tonic-gate } 5557c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 5567c478bd9Sstevel@tonic-gate } 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate static int 5597c478bd9Sstevel@tonic-gate drmach_array_first(drmach_array_t *arr, int *idx, drmachid_t *val) 5607c478bd9Sstevel@tonic-gate { 5617c478bd9Sstevel@tonic-gate int rv; 5627c478bd9Sstevel@tonic-gate 5637c478bd9Sstevel@tonic-gate *idx = arr->min_index; 5647c478bd9Sstevel@tonic-gate while ((rv = drmach_array_get(arr, *idx, val)) == 0 && *val == NULL) 5657c478bd9Sstevel@tonic-gate *idx += 1; 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate return (rv); 5687c478bd9Sstevel@tonic-gate } 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate static int 5717c478bd9Sstevel@tonic-gate drmach_array_next(drmach_array_t *arr, int *idx, drmachid_t *val) 5727c478bd9Sstevel@tonic-gate { 5737c478bd9Sstevel@tonic-gate int rv; 5747c478bd9Sstevel@tonic-gate 5757c478bd9Sstevel@tonic-gate *idx += 1; 5767c478bd9Sstevel@tonic-gate while ((rv = drmach_array_get(arr, *idx, val)) == 0 && *val == NULL) 5777c478bd9Sstevel@tonic-gate *idx += 1; 5787c478bd9Sstevel@tonic-gate 5797c478bd9Sstevel@tonic-gate return (rv); 5807c478bd9Sstevel@tonic-gate } 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate static void 5837c478bd9Sstevel@tonic-gate drmach_array_dispose(drmach_array_t *arr, void (*disposer)(drmachid_t)) 5847c478bd9Sstevel@tonic-gate { 5857c478bd9Sstevel@tonic-gate drmachid_t val; 5867c478bd9Sstevel@tonic-gate int idx; 5877c478bd9Sstevel@tonic-gate int rv; 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate rv = drmach_array_first(arr, &idx, &val); 5907c478bd9Sstevel@tonic-gate while (rv == 0) { 5917c478bd9Sstevel@tonic-gate (*disposer)(val); 5927c478bd9Sstevel@tonic-gate rv = drmach_array_next(arr, &idx, &val); 5937c478bd9Sstevel@tonic-gate } 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate kmem_free(arr->arr, arr->arr_sz); 5967c478bd9Sstevel@tonic-gate kmem_free(arr, sizeof (*arr)); 5977c478bd9Sstevel@tonic-gate } 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6007c478bd9Sstevel@tonic-gate static int 601fa9e4066Sahrens drmach_prom_select(pnode_t nodeid, void *arg, uint_t flags) 6027c478bd9Sstevel@tonic-gate { 6037c478bd9Sstevel@tonic-gate int rprop[64]; 604fa9e4066Sahrens pnode_t saved; 6057c478bd9Sstevel@tonic-gate drmach_config_args_t *ap = (drmach_config_args_t *)arg; 6067c478bd9Sstevel@tonic-gate drmach_device_t *dp = ap->dp; 6077c478bd9Sstevel@tonic-gate sbd_error_t *err; 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate saved = drmach_node_get_dnode(dp->node); 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate if (nodeid != saved) 6127c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate if (saved == OBP_NONODE) { 6157c478bd9Sstevel@tonic-gate err = DRMACH_INTERNAL_ERROR(); 6167c478bd9Sstevel@tonic-gate DRERR_SET_C(&ap->err, &err); 6177c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6187c478bd9Sstevel@tonic-gate } 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate if (prom_getprop(nodeid, OBP_REG, (caddr_t)rprop) <= 0) { 6217c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6227c478bd9Sstevel@tonic-gate } 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 6257c478bd9Sstevel@tonic-gate } 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6287c478bd9Sstevel@tonic-gate static void 6297c478bd9Sstevel@tonic-gate drmach_branch_callback(dev_info_t *rdip, void *arg, uint_t flags) 6307c478bd9Sstevel@tonic-gate { 6317c478bd9Sstevel@tonic-gate drmach_config_args_t *ap = (drmach_config_args_t *)arg; 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate ASSERT(ap->dip == NULL); 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate ap->dip = rdip; 6367c478bd9Sstevel@tonic-gate } 6377c478bd9Sstevel@tonic-gate 6387c478bd9Sstevel@tonic-gate sbd_error_t * 6397c478bd9Sstevel@tonic-gate drmach_configure(drmachid_t id, int flags) 6407c478bd9Sstevel@tonic-gate { 6417c478bd9Sstevel@tonic-gate drmach_device_t *dp; 6427c478bd9Sstevel@tonic-gate sbd_error_t *err; 6437c478bd9Sstevel@tonic-gate drmach_config_args_t ca; 6447c478bd9Sstevel@tonic-gate devi_branch_t b = {0}; 6457c478bd9Sstevel@tonic-gate dev_info_t *fdip = NULL; 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate if (!DRMACH_IS_DEVICE_ID(id)) 6487c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 6497c478bd9Sstevel@tonic-gate dp = id; 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate ca.dp = dp; 6527c478bd9Sstevel@tonic-gate ca.flags = flags; 6537c478bd9Sstevel@tonic-gate ca.err = NULL; /* will be set if error detected */ 6547c478bd9Sstevel@tonic-gate ca.dip = NULL; 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate b.arg = &ca; 6577c478bd9Sstevel@tonic-gate b.type = DEVI_BRANCH_PROM; 6587c478bd9Sstevel@tonic-gate b.create.prom_branch_select = drmach_prom_select; 6597c478bd9Sstevel@tonic-gate b.devi_branch_callback = drmach_branch_callback; 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate if (e_ddi_branch_create(ddi_root_node(), &b, &fdip, 6627c478bd9Sstevel@tonic-gate DEVI_BRANCH_CHILD | DEVI_BRANCH_CONFIGURE) != 0) { 6637c478bd9Sstevel@tonic-gate char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate /* 6667c478bd9Sstevel@tonic-gate * If non-NULL, fdip is returned held and must be released. 6677c478bd9Sstevel@tonic-gate */ 6687c478bd9Sstevel@tonic-gate if (fdip != NULL) { 6697c478bd9Sstevel@tonic-gate (void) ddi_pathname(fdip, path); 6707c478bd9Sstevel@tonic-gate ddi_release_devi(fdip); 6717c478bd9Sstevel@tonic-gate } else if (ca.dip != NULL) { 6727c478bd9Sstevel@tonic-gate /* safe to call ddi_pathname as dip already held */ 6737c478bd9Sstevel@tonic-gate (void) ddi_pathname(ca.dip, path); 6747c478bd9Sstevel@tonic-gate } else { 6757c478bd9Sstevel@tonic-gate (void) strcpy(path, "<none>"); 6767c478bd9Sstevel@tonic-gate } 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate err = drerr_new(1, ESTF_DRVFAIL, path); 6797c478bd9Sstevel@tonic-gate DRERR_SET_C(&ca.err, &err); 6807c478bd9Sstevel@tonic-gate kmem_free(path, MAXPATHLEN); 6817c478bd9Sstevel@tonic-gate } 6827c478bd9Sstevel@tonic-gate 6837c478bd9Sstevel@tonic-gate return (ca.err); 6847c478bd9Sstevel@tonic-gate } 6857c478bd9Sstevel@tonic-gate 6867c478bd9Sstevel@tonic-gate static sbd_error_t * 6877c478bd9Sstevel@tonic-gate drmach_device_new(drmach_node_t *node, 6887c478bd9Sstevel@tonic-gate drmach_board_t *bp, drmach_device_t **dpp) 6897c478bd9Sstevel@tonic-gate { 6907c478bd9Sstevel@tonic-gate int i; 6917c478bd9Sstevel@tonic-gate int rv; 6927c478bd9Sstevel@tonic-gate drmach_device_t *dp; 6937c478bd9Sstevel@tonic-gate sbd_error_t *err; 6947c478bd9Sstevel@tonic-gate char name[OBP_MAXDRVNAME]; 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate rv = drmach_node_get_prop(node, OBP_NAME, name); 6977c478bd9Sstevel@tonic-gate if (rv) { 6987c478bd9Sstevel@tonic-gate /* every node is expected to have a name */ 6997c478bd9Sstevel@tonic-gate err = drerr_new(1, ESTF_GETPROP, 7007c478bd9Sstevel@tonic-gate "PROM Node 0x%x: property %s", 7017c478bd9Sstevel@tonic-gate (uint_t)node->get_dnode(node), OBP_NAME); 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate return (err); 7047c478bd9Sstevel@tonic-gate } 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate /* 7077c478bd9Sstevel@tonic-gate * The node currently being examined is not listed in the name2type[] 7087c478bd9Sstevel@tonic-gate * array. In this case, the node is no interest to drmach. Both 7097c478bd9Sstevel@tonic-gate * dp and err are initialized here to yield nothing (no device or 7107c478bd9Sstevel@tonic-gate * error structure) for this case. 7117c478bd9Sstevel@tonic-gate */ 7127c478bd9Sstevel@tonic-gate for (i = 0; i < sizeof (name2type) / sizeof (name2type[0]); i++) 7137c478bd9Sstevel@tonic-gate if (strcmp(name2type[i].name, name) == 0) 7147c478bd9Sstevel@tonic-gate break; 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate if (i < sizeof (name2type) / sizeof (name2type[0])) { 7177c478bd9Sstevel@tonic-gate dp = kmem_zalloc(sizeof (drmach_device_t), KM_SLEEP); 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate dp->bp = bp; 7207c478bd9Sstevel@tonic-gate dp->unum = -1; 7217c478bd9Sstevel@tonic-gate dp->node = drmach_node_dup(node); 7227c478bd9Sstevel@tonic-gate dp->type = name2type[i].type; 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate err = (name2type[i].new)(dp); 7257c478bd9Sstevel@tonic-gate if (err) { 7267c478bd9Sstevel@tonic-gate drmach_node_dispose(node); 7277c478bd9Sstevel@tonic-gate kmem_free(dp, sizeof (*dp)); 7287c478bd9Sstevel@tonic-gate dp = NULL; 7297c478bd9Sstevel@tonic-gate } 7307c478bd9Sstevel@tonic-gate 7317c478bd9Sstevel@tonic-gate *dpp = dp; 7327c478bd9Sstevel@tonic-gate return (err); 7337c478bd9Sstevel@tonic-gate } 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate /* 7367c478bd9Sstevel@tonic-gate * The node currently being examined is not listed in the name2type[] 7377c478bd9Sstevel@tonic-gate * array. In this case, the node is no interest to drmach. Both 7387c478bd9Sstevel@tonic-gate * dp and err are initialized here to yield nothing (no device or 7397c478bd9Sstevel@tonic-gate * error structure) for this case. 7407c478bd9Sstevel@tonic-gate */ 7417c478bd9Sstevel@tonic-gate *dpp = NULL; 7427c478bd9Sstevel@tonic-gate return (NULL); 7437c478bd9Sstevel@tonic-gate } 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate static void 7467c478bd9Sstevel@tonic-gate drmach_device_dispose(drmachid_t id) 7477c478bd9Sstevel@tonic-gate { 7487c478bd9Sstevel@tonic-gate drmach_device_t *self = id; 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate if (self->node) 7517c478bd9Sstevel@tonic-gate drmach_node_dispose(self->node); 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate kmem_free(self, sizeof (*self)); 7547c478bd9Sstevel@tonic-gate } 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate static sbd_error_t * 7577c478bd9Sstevel@tonic-gate drmach_device_get_prop(drmach_device_t *dp, char *name, void *buf) 7587c478bd9Sstevel@tonic-gate { 7597c478bd9Sstevel@tonic-gate sbd_error_t *err = NULL; 7607c478bd9Sstevel@tonic-gate int rv; 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate rv = drmach_node_get_prop(dp->node, name, buf); 7637c478bd9Sstevel@tonic-gate if (rv) { 7647c478bd9Sstevel@tonic-gate err = drerr_new(1, ESTF_GETPROP, 7657c478bd9Sstevel@tonic-gate "%s::%s: property %s", 7667c478bd9Sstevel@tonic-gate dp->bp->cm.name, dp->cm.name, name); 7677c478bd9Sstevel@tonic-gate } 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate return (err); 7707c478bd9Sstevel@tonic-gate } 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate static sbd_error_t * 7737c478bd9Sstevel@tonic-gate drmach_device_get_proplen(drmach_device_t *dp, char *name, int *len) 7747c478bd9Sstevel@tonic-gate { 7757c478bd9Sstevel@tonic-gate sbd_error_t *err = NULL; 7767c478bd9Sstevel@tonic-gate int rv; 7777c478bd9Sstevel@tonic-gate 7787c478bd9Sstevel@tonic-gate rv = drmach_node_get_proplen(dp->node, name, len); 7797c478bd9Sstevel@tonic-gate if (rv) { 7807c478bd9Sstevel@tonic-gate err = drerr_new(1, ESTF_GETPROPLEN, 7817c478bd9Sstevel@tonic-gate "%s::%s: property %s", 7827c478bd9Sstevel@tonic-gate dp->bp->cm.name, dp->cm.name, name); 7837c478bd9Sstevel@tonic-gate } 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate return (err); 7867c478bd9Sstevel@tonic-gate } 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate static drmach_board_t * 7897c478bd9Sstevel@tonic-gate drmach_board_new(int bnum) 7907c478bd9Sstevel@tonic-gate { 7917c478bd9Sstevel@tonic-gate drmach_board_t *bp; 7927c478bd9Sstevel@tonic-gate 7937c478bd9Sstevel@tonic-gate bp = kmem_zalloc(sizeof (drmach_board_t), KM_SLEEP); 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate bp->cm.isa = (void *)drmach_board_new; 7967c478bd9Sstevel@tonic-gate bp->cm.release = drmach_board_release; 7977c478bd9Sstevel@tonic-gate bp->cm.status = drmach_board_status; 7987c478bd9Sstevel@tonic-gate 7997c478bd9Sstevel@tonic-gate (void) drmach_board_name(bnum, bp->cm.name, sizeof (bp->cm.name)); 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate bp->bnum = bnum; 8027c478bd9Sstevel@tonic-gate bp->devices = NULL; 8037c478bd9Sstevel@tonic-gate bp->connect_cpuid = -1; 8047c478bd9Sstevel@tonic-gate bp->tree = drmach_node_new(); 8057c478bd9Sstevel@tonic-gate bp->assigned = !drmach_initialized; 8067c478bd9Sstevel@tonic-gate bp->powered = !drmach_initialized; 8077c478bd9Sstevel@tonic-gate 80807d06da5SSurya Prakki (void) drmach_array_set(drmach_boards, bnum, bp); 8097c478bd9Sstevel@tonic-gate return (bp); 8107c478bd9Sstevel@tonic-gate } 8117c478bd9Sstevel@tonic-gate 8127c478bd9Sstevel@tonic-gate static void 8137c478bd9Sstevel@tonic-gate drmach_board_dispose(drmachid_t id) 8147c478bd9Sstevel@tonic-gate { 8157c478bd9Sstevel@tonic-gate drmach_board_t *bp; 8167c478bd9Sstevel@tonic-gate 8177c478bd9Sstevel@tonic-gate ASSERT(DRMACH_IS_BOARD_ID(id)); 8187c478bd9Sstevel@tonic-gate bp = id; 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate if (bp->tree) 8217c478bd9Sstevel@tonic-gate drmach_node_dispose(bp->tree); 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate if (bp->devices) 8247c478bd9Sstevel@tonic-gate drmach_array_dispose(bp->devices, drmach_device_dispose); 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate kmem_free(bp, sizeof (*bp)); 8277c478bd9Sstevel@tonic-gate } 8287c478bd9Sstevel@tonic-gate 8297c478bd9Sstevel@tonic-gate static sbd_error_t * 8307c478bd9Sstevel@tonic-gate drmach_board_status(drmachid_t id, drmach_status_t *stat) 8317c478bd9Sstevel@tonic-gate { 8327c478bd9Sstevel@tonic-gate sbd_error_t *err = NULL; 8337c478bd9Sstevel@tonic-gate drmach_board_t *bp; 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate if (!DRMACH_IS_BOARD_ID(id)) 8367c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 8377c478bd9Sstevel@tonic-gate bp = id; 8387c478bd9Sstevel@tonic-gate 8397c478bd9Sstevel@tonic-gate stat->assigned = bp->assigned; 8407c478bd9Sstevel@tonic-gate stat->powered = bp->powered; 8417c478bd9Sstevel@tonic-gate stat->busy = 0; /* assume not busy */ 8427c478bd9Sstevel@tonic-gate stat->configured = 0; /* assume not configured */ 8437c478bd9Sstevel@tonic-gate stat->empty = 0; 8447c478bd9Sstevel@tonic-gate stat->cond = bp->cond = SBD_COND_OK; 84507d06da5SSurya Prakki (void) strncpy(stat->type, "System Brd", sizeof (stat->type)); 8467c478bd9Sstevel@tonic-gate stat->info[0] = '\0'; 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate if (bp->devices) { 8497c478bd9Sstevel@tonic-gate int rv; 8507c478bd9Sstevel@tonic-gate int d_idx; 8517c478bd9Sstevel@tonic-gate drmachid_t d_id; 8527c478bd9Sstevel@tonic-gate 8537c478bd9Sstevel@tonic-gate rv = drmach_array_first(bp->devices, &d_idx, &d_id); 8547c478bd9Sstevel@tonic-gate while (rv == 0) { 8557c478bd9Sstevel@tonic-gate drmach_status_t d_stat; 8567c478bd9Sstevel@tonic-gate 8577c478bd9Sstevel@tonic-gate err = drmach_status(d_id, &d_stat); 8587c478bd9Sstevel@tonic-gate if (err) 8597c478bd9Sstevel@tonic-gate break; 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate stat->busy |= d_stat.busy; 8627c478bd9Sstevel@tonic-gate stat->configured |= d_stat.configured; 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate rv = drmach_array_next(bp->devices, &d_idx, &d_id); 8657c478bd9Sstevel@tonic-gate } 8667c478bd9Sstevel@tonic-gate } 8677c478bd9Sstevel@tonic-gate 8687c478bd9Sstevel@tonic-gate return (err); 8697c478bd9Sstevel@tonic-gate } 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate /* a simple routine to reduce redundancy of this common logic */ 8727c478bd9Sstevel@tonic-gate static pda_handle_t 8737c478bd9Sstevel@tonic-gate drmach_pda_open(void) 8747c478bd9Sstevel@tonic-gate { 8757c478bd9Sstevel@tonic-gate pda_handle_t ph; 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate ph = pda_open(); 8787c478bd9Sstevel@tonic-gate if (ph == NULL) { 8797c478bd9Sstevel@tonic-gate /* catch in debug kernels */ 8807c478bd9Sstevel@tonic-gate ASSERT(0); 8817c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pda_open failed"); 8827c478bd9Sstevel@tonic-gate } 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate return (ph); 8857c478bd9Sstevel@tonic-gate } 8867c478bd9Sstevel@tonic-gate 8877c478bd9Sstevel@tonic-gate #ifdef DEBUG 8887c478bd9Sstevel@tonic-gate int drmach_init_break = 0; 8897c478bd9Sstevel@tonic-gate #endif 8907c478bd9Sstevel@tonic-gate 8917c478bd9Sstevel@tonic-gate static int 8927c478bd9Sstevel@tonic-gate hold_rele_branch(dev_info_t *rdip, void *arg) 8937c478bd9Sstevel@tonic-gate { 8947c478bd9Sstevel@tonic-gate int i; 8957c478bd9Sstevel@tonic-gate int *holdp = (int *)arg; 8967c478bd9Sstevel@tonic-gate char *name = ddi_node_name(rdip); 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate /* 8997c478bd9Sstevel@tonic-gate * For Starfire, we must be children of the root devinfo node 9007c478bd9Sstevel@tonic-gate */ 9017c478bd9Sstevel@tonic-gate ASSERT(ddi_get_parent(rdip) == ddi_root_node()); 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate for (i = 0; i < sizeof (name2type) / sizeof (name2type[0]); i++) 9047c478bd9Sstevel@tonic-gate if (strcmp(name2type[i].name, name) == 0) 9057c478bd9Sstevel@tonic-gate break; 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate if (i == sizeof (name2type) / sizeof (name2type[0])) { 9087c478bd9Sstevel@tonic-gate /* Not of interest to us */ 9097c478bd9Sstevel@tonic-gate return (DDI_WALK_PRUNECHILD); 9107c478bd9Sstevel@tonic-gate } 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate if (*holdp) { 9137c478bd9Sstevel@tonic-gate ASSERT(!e_ddi_branch_held(rdip)); 9147c478bd9Sstevel@tonic-gate e_ddi_branch_hold(rdip); 9157c478bd9Sstevel@tonic-gate } else { 9167c478bd9Sstevel@tonic-gate ASSERT(e_ddi_branch_held(rdip)); 9177c478bd9Sstevel@tonic-gate e_ddi_branch_rele(rdip); 9187c478bd9Sstevel@tonic-gate } 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate return (DDI_WALK_PRUNECHILD); 9217c478bd9Sstevel@tonic-gate } 9227c478bd9Sstevel@tonic-gate 9237c478bd9Sstevel@tonic-gate static int 9247c478bd9Sstevel@tonic-gate drmach_init(void) 9257c478bd9Sstevel@tonic-gate { 926fa9e4066Sahrens pnode_t nodeid; 9277c478bd9Sstevel@tonic-gate dev_info_t *rdip; 9287c478bd9Sstevel@tonic-gate int hold, circ; 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate #ifdef DEBUG 9317c478bd9Sstevel@tonic-gate if (drmach_init_break) 9327c478bd9Sstevel@tonic-gate debug_enter("drmach_init: drmach_init_break set\n"); 9337c478bd9Sstevel@tonic-gate #endif 9347c478bd9Sstevel@tonic-gate mutex_enter(&drmach_i_lock); 9357c478bd9Sstevel@tonic-gate if (drmach_initialized) { 9367c478bd9Sstevel@tonic-gate mutex_exit(&drmach_i_lock); 9377c478bd9Sstevel@tonic-gate return (0); 9387c478bd9Sstevel@tonic-gate } 9397c478bd9Sstevel@tonic-gate 9407c478bd9Sstevel@tonic-gate drmach_boards = drmach_array_new(0, MAX_BOARDS - 1); 9417c478bd9Sstevel@tonic-gate 9427c478bd9Sstevel@tonic-gate nodeid = prom_childnode(prom_rootnode()); 9437c478bd9Sstevel@tonic-gate do { 9447c478bd9Sstevel@tonic-gate int bnum; 9457c478bd9Sstevel@tonic-gate drmachid_t id; 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate bnum = -1; 9487c478bd9Sstevel@tonic-gate (void) prom_getprop(nodeid, OBP_BOARDNUM, (caddr_t)&bnum); 9497c478bd9Sstevel@tonic-gate if (bnum == -1) 9507c478bd9Sstevel@tonic-gate continue; 9517c478bd9Sstevel@tonic-gate 9527c478bd9Sstevel@tonic-gate if (drmach_array_get(drmach_boards, bnum, &id) == -1) { 9537c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "OBP node 0x%x has" 9547c478bd9Sstevel@tonic-gate " invalid property value, %s=%d", 9557c478bd9Sstevel@tonic-gate nodeid, OBP_BOARDNUM, bnum); 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate /* clean up */ 9587c478bd9Sstevel@tonic-gate drmach_array_dispose( 9597c478bd9Sstevel@tonic-gate drmach_boards, drmach_board_dispose); 9607c478bd9Sstevel@tonic-gate 9617c478bd9Sstevel@tonic-gate mutex_exit(&drmach_i_lock); 9627c478bd9Sstevel@tonic-gate return (-1); 9637c478bd9Sstevel@tonic-gate } else if (id == NULL) 9647c478bd9Sstevel@tonic-gate (void) drmach_board_new(bnum); 9657c478bd9Sstevel@tonic-gate } while ((nodeid = prom_nextnode(nodeid)) != OBP_NONODE); 9667c478bd9Sstevel@tonic-gate 9677c478bd9Sstevel@tonic-gate drmach_shutdown_va = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP); 9687c478bd9Sstevel@tonic-gate 9697c478bd9Sstevel@tonic-gate /* 9707c478bd9Sstevel@tonic-gate * Walk immediate children of devinfo root node and hold 9717c478bd9Sstevel@tonic-gate * all devinfo branches of interest. 9727c478bd9Sstevel@tonic-gate */ 9737c478bd9Sstevel@tonic-gate hold = 1; 9747c478bd9Sstevel@tonic-gate rdip = ddi_root_node(); 9757c478bd9Sstevel@tonic-gate 9767c478bd9Sstevel@tonic-gate ndi_devi_enter(rdip, &circ); 9777c478bd9Sstevel@tonic-gate ddi_walk_devs(ddi_get_child(rdip), hold_rele_branch, &hold); 9787c478bd9Sstevel@tonic-gate ndi_devi_exit(rdip, circ); 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate drmach_initialized = 1; 9817c478bd9Sstevel@tonic-gate 9827c478bd9Sstevel@tonic-gate mutex_exit(&drmach_i_lock); 9837c478bd9Sstevel@tonic-gate 9847c478bd9Sstevel@tonic-gate return (0); 9857c478bd9Sstevel@tonic-gate } 9867c478bd9Sstevel@tonic-gate 9877c478bd9Sstevel@tonic-gate static int 9887c478bd9Sstevel@tonic-gate drmach_fini(void) 9897c478bd9Sstevel@tonic-gate { 9907c478bd9Sstevel@tonic-gate dev_info_t *rdip; 9917c478bd9Sstevel@tonic-gate int hold, circ; 9927c478bd9Sstevel@tonic-gate 9937c478bd9Sstevel@tonic-gate if (drmach_initialized) { 9947c478bd9Sstevel@tonic-gate int busy = 0; 9957c478bd9Sstevel@tonic-gate int rv; 9967c478bd9Sstevel@tonic-gate int idx; 9977c478bd9Sstevel@tonic-gate drmachid_t id; 9987c478bd9Sstevel@tonic-gate 9997c478bd9Sstevel@tonic-gate ASSERT(drmach_boards != NULL); 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate rv = drmach_array_first(drmach_boards, &idx, &id); 10027c478bd9Sstevel@tonic-gate while (rv == 0) { 10037c478bd9Sstevel@tonic-gate sbd_error_t *err; 10047c478bd9Sstevel@tonic-gate drmach_status_t stat; 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate err = drmach_board_status(id, &stat); 10077c478bd9Sstevel@tonic-gate if (err) { 10087c478bd9Sstevel@tonic-gate /* catch in debug kernels */ 10097c478bd9Sstevel@tonic-gate ASSERT(0); 10107c478bd9Sstevel@tonic-gate sbd_err_clear(&err); 10117c478bd9Sstevel@tonic-gate busy = 1; 10127c478bd9Sstevel@tonic-gate } else 10137c478bd9Sstevel@tonic-gate busy |= stat.busy; 10147c478bd9Sstevel@tonic-gate 10157c478bd9Sstevel@tonic-gate rv = drmach_array_next(drmach_boards, &idx, &id); 10167c478bd9Sstevel@tonic-gate } 10177c478bd9Sstevel@tonic-gate 10187c478bd9Sstevel@tonic-gate if (busy) 10197c478bd9Sstevel@tonic-gate return (-1); 10207c478bd9Sstevel@tonic-gate 10217c478bd9Sstevel@tonic-gate drmach_array_dispose(drmach_boards, drmach_board_dispose); 10227c478bd9Sstevel@tonic-gate drmach_boards = NULL; 10237c478bd9Sstevel@tonic-gate 10247c478bd9Sstevel@tonic-gate vmem_free(heap_arena, drmach_shutdown_va, PAGESIZE); 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate /* 10277c478bd9Sstevel@tonic-gate * Walk immediate children of the root devinfo node 10287c478bd9Sstevel@tonic-gate * releasing holds acquired on branches in drmach_init() 10297c478bd9Sstevel@tonic-gate */ 10307c478bd9Sstevel@tonic-gate hold = 0; 10317c478bd9Sstevel@tonic-gate rdip = ddi_root_node(); 10327c478bd9Sstevel@tonic-gate 10337c478bd9Sstevel@tonic-gate ndi_devi_enter(rdip, &circ); 10347c478bd9Sstevel@tonic-gate ddi_walk_devs(ddi_get_child(rdip), hold_rele_branch, &hold); 10357c478bd9Sstevel@tonic-gate ndi_devi_exit(rdip, circ); 10367c478bd9Sstevel@tonic-gate 10377c478bd9Sstevel@tonic-gate mutex_destroy(&drmach_i_lock); 10387c478bd9Sstevel@tonic-gate 10397c478bd9Sstevel@tonic-gate drmach_initialized = 0; 10407c478bd9Sstevel@tonic-gate } 10417c478bd9Sstevel@tonic-gate if (drmach_xt_mb != NULL) { 10427c478bd9Sstevel@tonic-gate vmem_free(static_alloc_arena, (void *)drmach_xt_mb, 10437c478bd9Sstevel@tonic-gate NCPU * sizeof (uchar_t)); 10447c478bd9Sstevel@tonic-gate } 10457c478bd9Sstevel@tonic-gate if (drmach_shutdown_asm_mbox != NULL) { 10467c478bd9Sstevel@tonic-gate vmem_free(static_alloc_arena, (void *)drmach_shutdown_asm_mbox, 10477c478bd9Sstevel@tonic-gate sizeof (struct drmach_shutdown_mbox)); 10487c478bd9Sstevel@tonic-gate } 10497c478bd9Sstevel@tonic-gate return (0); 10507c478bd9Sstevel@tonic-gate } 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate static sbd_error_t * 10537c478bd9Sstevel@tonic-gate drmach_get_mc_asr_addr(drmachid_t id, uint64_t *pa) 10547c478bd9Sstevel@tonic-gate { 10557c478bd9Sstevel@tonic-gate drmach_device_t *dp; 1056fa9e4066Sahrens pnode_t nodeid; 10577c478bd9Sstevel@tonic-gate uint64_t addr; 10587c478bd9Sstevel@tonic-gate 10597c478bd9Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(id)) 10607c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 10617c478bd9Sstevel@tonic-gate dp = id; 10627c478bd9Sstevel@tonic-gate 10637c478bd9Sstevel@tonic-gate nodeid = drmach_node_get_dnode(dp->node); 10647c478bd9Sstevel@tonic-gate if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE) 10657c478bd9Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 10667c478bd9Sstevel@tonic-gate 10677c478bd9Sstevel@tonic-gate addr = mc_get_asr_addr(nodeid); 10687c478bd9Sstevel@tonic-gate if (addr == (uint64_t)-1) 10697c478bd9Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 10707c478bd9Sstevel@tonic-gate 10717c478bd9Sstevel@tonic-gate *pa = addr; 10727c478bd9Sstevel@tonic-gate return (NULL); 10737c478bd9Sstevel@tonic-gate } 10747c478bd9Sstevel@tonic-gate 10757c478bd9Sstevel@tonic-gate static sbd_error_t * 10767c478bd9Sstevel@tonic-gate drmach_get_mc_idle_addr(drmachid_t id, uint64_t *pa) 10777c478bd9Sstevel@tonic-gate { 10787c478bd9Sstevel@tonic-gate drmach_device_t *dp; 1079fa9e4066Sahrens pnode_t nodeid; 10807c478bd9Sstevel@tonic-gate uint64_t addr; 10817c478bd9Sstevel@tonic-gate 10827c478bd9Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(id)) 10837c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 10847c478bd9Sstevel@tonic-gate dp = id; 10857c478bd9Sstevel@tonic-gate 10867c478bd9Sstevel@tonic-gate nodeid = drmach_node_get_dnode(dp->node); 10877c478bd9Sstevel@tonic-gate if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE) 10887c478bd9Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 10897c478bd9Sstevel@tonic-gate 10907c478bd9Sstevel@tonic-gate addr = mc_get_idle_addr(nodeid); 10917c478bd9Sstevel@tonic-gate if (addr == (uint64_t)-1) 10927c478bd9Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 10937c478bd9Sstevel@tonic-gate 10947c478bd9Sstevel@tonic-gate *pa = addr; 10957c478bd9Sstevel@tonic-gate return (NULL); 10967c478bd9Sstevel@tonic-gate } 10977c478bd9Sstevel@tonic-gate 10987c478bd9Sstevel@tonic-gate static sbd_error_t * 10997c478bd9Sstevel@tonic-gate drmach_read_mc_asr(drmachid_t id, uint_t *mcregp) 11007c478bd9Sstevel@tonic-gate { 11017c478bd9Sstevel@tonic-gate drmach_device_t *dp; 1102fa9e4066Sahrens pnode_t nodeid; 11037c478bd9Sstevel@tonic-gate sbd_error_t *err; 11047c478bd9Sstevel@tonic-gate 11057c478bd9Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(id)) 11067c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 11077c478bd9Sstevel@tonic-gate dp = id; 11087c478bd9Sstevel@tonic-gate 11097c478bd9Sstevel@tonic-gate nodeid = drmach_node_get_dnode(dp->node); 11107c478bd9Sstevel@tonic-gate if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE) 11117c478bd9Sstevel@tonic-gate err = DRMACH_INTERNAL_ERROR(); 11127c478bd9Sstevel@tonic-gate else if (mc_read_asr(nodeid, mcregp) == -1) 11137c478bd9Sstevel@tonic-gate err = DRMACH_INTERNAL_ERROR(); 11147c478bd9Sstevel@tonic-gate else 11157c478bd9Sstevel@tonic-gate err = NULL; 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate return (err); 11187c478bd9Sstevel@tonic-gate } 11197c478bd9Sstevel@tonic-gate 11207c478bd9Sstevel@tonic-gate static sbd_error_t * 11217c478bd9Sstevel@tonic-gate drmach_write_mc_asr(drmachid_t id, uint_t mcreg) 11227c478bd9Sstevel@tonic-gate { 11237c478bd9Sstevel@tonic-gate drmach_device_t *dp; 1124fa9e4066Sahrens pnode_t nodeid; 11257c478bd9Sstevel@tonic-gate sbd_error_t *err; 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(id)) 11287c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 11297c478bd9Sstevel@tonic-gate dp = id; 11307c478bd9Sstevel@tonic-gate 11317c478bd9Sstevel@tonic-gate nodeid = drmach_node_get_dnode(dp->node); 11327c478bd9Sstevel@tonic-gate if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE) 11337c478bd9Sstevel@tonic-gate err = DRMACH_INTERNAL_ERROR(); 11347c478bd9Sstevel@tonic-gate else if (mc_write_asr(nodeid, mcreg) == -1) 11357c478bd9Sstevel@tonic-gate err = DRMACH_INTERNAL_ERROR(); 11367c478bd9Sstevel@tonic-gate else 11377c478bd9Sstevel@tonic-gate err = NULL; 11387c478bd9Sstevel@tonic-gate 11397c478bd9Sstevel@tonic-gate return (err); 11407c478bd9Sstevel@tonic-gate } 11417c478bd9Sstevel@tonic-gate 11427c478bd9Sstevel@tonic-gate static sbd_error_t * 11437c478bd9Sstevel@tonic-gate drmach_prep_rename_script(drmach_device_t *s_mem, drmach_device_t *t_mem, 11447c478bd9Sstevel@tonic-gate uint64_t t_slice_offset, caddr_t buf, int buflen) 11457c478bd9Sstevel@tonic-gate { 11467c478bd9Sstevel@tonic-gate int i, b, m; 11477c478bd9Sstevel@tonic-gate drmach_mc_idle_script_t *isp; 11487c478bd9Sstevel@tonic-gate drmach_rename_script_t *rsp; 11497c478bd9Sstevel@tonic-gate int s_bd, t_bd; 11507c478bd9Sstevel@tonic-gate uint_t s_masr, t_masr; 11517c478bd9Sstevel@tonic-gate uint64_t s_new_basepa, t_new_basepa; 11527c478bd9Sstevel@tonic-gate int b_idx, rv; 11537c478bd9Sstevel@tonic-gate sbd_error_t *err; 11547c478bd9Sstevel@tonic-gate drmachid_t b_id; 11557c478bd9Sstevel@tonic-gate drmach_board_t *brd; 11567c478bd9Sstevel@tonic-gate 11577c478bd9Sstevel@tonic-gate #ifdef DEBUG 11587c478bd9Sstevel@tonic-gate /* 11597c478bd9Sstevel@tonic-gate * Starfire CPU/MEM/IO boards have only one MC per board. 11607c478bd9Sstevel@tonic-gate * This function has been coded with that fact in mind. 11617c478bd9Sstevel@tonic-gate */ 11627c478bd9Sstevel@tonic-gate ASSERT(MAX_MEM_UNITS_PER_BOARD == 1); 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate /* 11657c478bd9Sstevel@tonic-gate * calculate the maximum space that could be consumed, 11667c478bd9Sstevel@tonic-gate * then verify the available buffer space is adequate. 11677c478bd9Sstevel@tonic-gate */ 11687c478bd9Sstevel@tonic-gate m = sizeof (drmach_mc_idle_script_t *) * 2; /* two MCs */ 11697c478bd9Sstevel@tonic-gate b = sizeof (drmach_rename_script_t *) * 3 * MAX_CPU_UNITS_PER_BOARD; 11707c478bd9Sstevel@tonic-gate b += sizeof (drmach_rename_script_t *) * 3 * MAX_IO_UNITS_PER_BOARD; 11717c478bd9Sstevel@tonic-gate b *= MAX_BOARDS; 11727c478bd9Sstevel@tonic-gate b += sizeof (drmach_rename_script_t *) * 3; 11737c478bd9Sstevel@tonic-gate b += sizeof (drmach_rename_script_t *) * 1; 11747c478bd9Sstevel@tonic-gate ASSERT(m + b < buflen); 11757c478bd9Sstevel@tonic-gate #endif 11767c478bd9Sstevel@tonic-gate 11777c478bd9Sstevel@tonic-gate /* 11787c478bd9Sstevel@tonic-gate * construct an array of MC idle register addresses of 11797c478bd9Sstevel@tonic-gate * both MCs. The array is zero terminated -- as expected 11807c478bd9Sstevel@tonic-gate * by drmach_copy_rename_prog__relocatable(). 11817c478bd9Sstevel@tonic-gate */ 11827c478bd9Sstevel@tonic-gate isp = (drmach_mc_idle_script_t *)buf; 11837c478bd9Sstevel@tonic-gate 11847c478bd9Sstevel@tonic-gate /* source mc */ 11857c478bd9Sstevel@tonic-gate err = drmach_get_mc_idle_addr(s_mem, &isp->idle_addr); 11867c478bd9Sstevel@tonic-gate if (err) 11877c478bd9Sstevel@tonic-gate return (err); 11887c478bd9Sstevel@tonic-gate isp->mem = s_mem; 11897c478bd9Sstevel@tonic-gate isp += 1; 11907c478bd9Sstevel@tonic-gate 11917c478bd9Sstevel@tonic-gate /* target mc */ 11927c478bd9Sstevel@tonic-gate err = drmach_get_mc_idle_addr(t_mem, &isp->idle_addr); 11937c478bd9Sstevel@tonic-gate if (err) 11947c478bd9Sstevel@tonic-gate return (err); 11957c478bd9Sstevel@tonic-gate isp->mem = t_mem; 11967c478bd9Sstevel@tonic-gate isp += 1; 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gate /* terminator */ 11997c478bd9Sstevel@tonic-gate isp->idle_addr = 0; 12007c478bd9Sstevel@tonic-gate isp->mem = NULL; 12017c478bd9Sstevel@tonic-gate isp += 1; 12027c478bd9Sstevel@tonic-gate 12037c478bd9Sstevel@tonic-gate /* fetch source mc asr register value */ 12047c478bd9Sstevel@tonic-gate err = drmach_read_mc_asr(s_mem, &s_masr); 12057c478bd9Sstevel@tonic-gate if (err) 12067c478bd9Sstevel@tonic-gate return (err); 12077c478bd9Sstevel@tonic-gate else if (s_masr & STARFIRE_MC_INTERLEAVE_MASK) { 12087c478bd9Sstevel@tonic-gate return (drerr_new(1, ESTF_INTERBOARD, "%s::%s", 12097c478bd9Sstevel@tonic-gate s_mem->bp->cm.name, s_mem->cm.name)); 12107c478bd9Sstevel@tonic-gate } 12117c478bd9Sstevel@tonic-gate 12127c478bd9Sstevel@tonic-gate /* fetch target mc asr register value */ 12137c478bd9Sstevel@tonic-gate err = drmach_read_mc_asr(t_mem, &t_masr); 12147c478bd9Sstevel@tonic-gate if (err) 12157c478bd9Sstevel@tonic-gate return (err); 12167c478bd9Sstevel@tonic-gate else if (t_masr & STARFIRE_MC_INTERLEAVE_MASK) { 12177c478bd9Sstevel@tonic-gate return (drerr_new(1, ESTF_INTERBOARD, "%s::%s", 12187c478bd9Sstevel@tonic-gate t_mem->bp->cm.name, t_mem->cm.name)); 12197c478bd9Sstevel@tonic-gate } 12207c478bd9Sstevel@tonic-gate 12217c478bd9Sstevel@tonic-gate /* get new source base pa from target's masr */ 12227c478bd9Sstevel@tonic-gate s_new_basepa = mc_asr_to_pa(t_masr); 12237c478bd9Sstevel@tonic-gate 12247c478bd9Sstevel@tonic-gate /* 12257c478bd9Sstevel@tonic-gate * remove any existing slice offset to realign 12267c478bd9Sstevel@tonic-gate * memory with board's slice boundary 12277c478bd9Sstevel@tonic-gate */ 12287c478bd9Sstevel@tonic-gate s_new_basepa &= ~ (mc_get_mem_alignment() - 1); 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate /* get new target base pa from source's masr */ 12317c478bd9Sstevel@tonic-gate t_new_basepa = mc_asr_to_pa(s_masr); 12327c478bd9Sstevel@tonic-gate 12337c478bd9Sstevel@tonic-gate /* remove any existing slice offset, then apply new offset */ 12347c478bd9Sstevel@tonic-gate t_new_basepa &= ~ (mc_get_mem_alignment() - 1); 12357c478bd9Sstevel@tonic-gate t_new_basepa += t_slice_offset; 12367c478bd9Sstevel@tonic-gate 12377c478bd9Sstevel@tonic-gate /* encode new base pa into s_masr. turn off mem present bit */ 12387c478bd9Sstevel@tonic-gate s_masr = mc_pa_to_asr(s_masr, s_new_basepa); 12397c478bd9Sstevel@tonic-gate s_masr &= ~STARFIRE_MC_MEM_PRESENT_MASK; 12407c478bd9Sstevel@tonic-gate 12417c478bd9Sstevel@tonic-gate /* encode new base pa into t_masr. turn on mem present bit */ 12427c478bd9Sstevel@tonic-gate t_masr = mc_pa_to_asr(t_masr, t_new_basepa); 12437c478bd9Sstevel@tonic-gate t_masr |= STARFIRE_MC_MEM_PRESENT_MASK; 12447c478bd9Sstevel@tonic-gate 12457c478bd9Sstevel@tonic-gate /* 12467c478bd9Sstevel@tonic-gate * Step 0: Mark source memory as not present. 12477c478bd9Sstevel@tonic-gate */ 12487c478bd9Sstevel@tonic-gate m = 0; 12497c478bd9Sstevel@tonic-gate rsp = (drmach_rename_script_t *)isp; 12507c478bd9Sstevel@tonic-gate err = drmach_get_mc_asr_addr(s_mem, &rsp[m].masr_addr); 12517c478bd9Sstevel@tonic-gate if (err) 12527c478bd9Sstevel@tonic-gate return (err); 12537c478bd9Sstevel@tonic-gate rsp[m].masr = s_masr; 12547c478bd9Sstevel@tonic-gate m++; 12557c478bd9Sstevel@tonic-gate 12567c478bd9Sstevel@tonic-gate /* 12577c478bd9Sstevel@tonic-gate * Step 1: Write source base address to target MC 12587c478bd9Sstevel@tonic-gate * with present bit off. 12597c478bd9Sstevel@tonic-gate */ 12607c478bd9Sstevel@tonic-gate err = drmach_get_mc_asr_addr(t_mem, &rsp[m].masr_addr); 12617c478bd9Sstevel@tonic-gate if (err) 12627c478bd9Sstevel@tonic-gate return (err); 12637c478bd9Sstevel@tonic-gate rsp[m].masr = t_masr & ~STARFIRE_MC_MEM_PRESENT_MASK; 12647c478bd9Sstevel@tonic-gate m++; 12657c478bd9Sstevel@tonic-gate 12667c478bd9Sstevel@tonic-gate /* 12677c478bd9Sstevel@tonic-gate * Step 2: Now rewrite target reg with present bit on. 12687c478bd9Sstevel@tonic-gate */ 12697c478bd9Sstevel@tonic-gate rsp[m].masr_addr = rsp[m-1].masr_addr; 12707c478bd9Sstevel@tonic-gate rsp[m].masr = t_masr; 12717c478bd9Sstevel@tonic-gate m++; 12727c478bd9Sstevel@tonic-gate 12737c478bd9Sstevel@tonic-gate s_bd = s_mem->bp->bnum; 12747c478bd9Sstevel@tonic-gate t_bd = t_mem->bp->bnum; 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate DRMACH_PR("preparing script for CPU and IO units:\n"); 12777c478bd9Sstevel@tonic-gate 12787c478bd9Sstevel@tonic-gate rv = drmach_array_first(drmach_boards, &b_idx, &b_id); 12797c478bd9Sstevel@tonic-gate if (rv) { 12807c478bd9Sstevel@tonic-gate /* catch this in debug kernels */ 12817c478bd9Sstevel@tonic-gate ASSERT(0); 12827c478bd9Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 12837c478bd9Sstevel@tonic-gate } 12847c478bd9Sstevel@tonic-gate 12857c478bd9Sstevel@tonic-gate do { 12867c478bd9Sstevel@tonic-gate int d_idx; 12877c478bd9Sstevel@tonic-gate drmachid_t d_id; 12887c478bd9Sstevel@tonic-gate drmach_device_t *device; 12897c478bd9Sstevel@tonic-gate 12907c478bd9Sstevel@tonic-gate ASSERT(DRMACH_IS_BOARD_ID(b_id)); 12917c478bd9Sstevel@tonic-gate brd = b_id; 12927c478bd9Sstevel@tonic-gate b = brd->bnum; 12937c478bd9Sstevel@tonic-gate 12947c478bd9Sstevel@tonic-gate /* 12957c478bd9Sstevel@tonic-gate * Step 3: Update PC MADR tables for CPUs. 12967c478bd9Sstevel@tonic-gate */ 1297141f8dd3Sjesusm if (brd->devices == NULL) { 1298141f8dd3Sjesusm /* devices not initialized */ 1299141f8dd3Sjesusm continue; 1300141f8dd3Sjesusm } 1301141f8dd3Sjesusm 13027c478bd9Sstevel@tonic-gate rv = drmach_array_first(brd->devices, &d_idx, &d_id); 13037c478bd9Sstevel@tonic-gate if (rv) { 13047c478bd9Sstevel@tonic-gate /* must mean no devices on this board */ 13057c478bd9Sstevel@tonic-gate break; 13067c478bd9Sstevel@tonic-gate } 13077c478bd9Sstevel@tonic-gate 13087c478bd9Sstevel@tonic-gate DRMACH_PR("\t%s\n", brd->cm.name); 13097c478bd9Sstevel@tonic-gate 13107c478bd9Sstevel@tonic-gate do { 13117c478bd9Sstevel@tonic-gate ASSERT(DRMACH_IS_DEVICE_ID(d_id)); 13127c478bd9Sstevel@tonic-gate 13137c478bd9Sstevel@tonic-gate if (!DRMACH_IS_CPU_ID(d_id)) 13147c478bd9Sstevel@tonic-gate continue; 13157c478bd9Sstevel@tonic-gate 13167c478bd9Sstevel@tonic-gate device = d_id; 13177c478bd9Sstevel@tonic-gate i = device->unum; 13187c478bd9Sstevel@tonic-gate 13197c478bd9Sstevel@tonic-gate DRMACH_PR("\t\t%s\n", device->cm.name); 13207c478bd9Sstevel@tonic-gate 13217c478bd9Sstevel@tonic-gate /* 13227c478bd9Sstevel@tonic-gate * Disabled detaching mem node. 13237c478bd9Sstevel@tonic-gate */ 13247c478bd9Sstevel@tonic-gate rsp[m].masr_addr = STARFIRE_PC_MADR_ADDR(b, s_bd, i); 13257c478bd9Sstevel@tonic-gate rsp[m].masr = s_masr; 13267c478bd9Sstevel@tonic-gate m++; 13277c478bd9Sstevel@tonic-gate /* 13287c478bd9Sstevel@tonic-gate * Always write masr with present bit 13297c478bd9Sstevel@tonic-gate * off and then again with it on. 13307c478bd9Sstevel@tonic-gate */ 13317c478bd9Sstevel@tonic-gate rsp[m].masr_addr = STARFIRE_PC_MADR_ADDR(b, t_bd, i); 13327c478bd9Sstevel@tonic-gate rsp[m].masr = t_masr & ~STARFIRE_MC_MEM_PRESENT_MASK; 13337c478bd9Sstevel@tonic-gate m++; 13347c478bd9Sstevel@tonic-gate rsp[m].masr_addr = rsp[m-1].masr_addr; 13357c478bd9Sstevel@tonic-gate rsp[m].masr = t_masr; 13367c478bd9Sstevel@tonic-gate m++; 13377c478bd9Sstevel@tonic-gate 13387c478bd9Sstevel@tonic-gate } while (drmach_array_next(brd->devices, &d_idx, &d_id) == 0); 13397c478bd9Sstevel@tonic-gate 13407c478bd9Sstevel@tonic-gate /* 13417c478bd9Sstevel@tonic-gate * Step 4: Update PC MADR tables for IOs. 13427c478bd9Sstevel@tonic-gate */ 13437c478bd9Sstevel@tonic-gate rv = drmach_array_first(brd->devices, &d_idx, &d_id); 13447c478bd9Sstevel@tonic-gate /* this worked for previous loop, must work here too */ 13457c478bd9Sstevel@tonic-gate ASSERT(rv == 0); 13467c478bd9Sstevel@tonic-gate 13477c478bd9Sstevel@tonic-gate do { 13487c478bd9Sstevel@tonic-gate ASSERT(DRMACH_IS_DEVICE_ID(d_id)); 13497c478bd9Sstevel@tonic-gate 13507c478bd9Sstevel@tonic-gate if (!DRMACH_IS_IO_ID(d_id)) 13517c478bd9Sstevel@tonic-gate continue; 13527c478bd9Sstevel@tonic-gate 13537c478bd9Sstevel@tonic-gate device = d_id; 13547c478bd9Sstevel@tonic-gate i = device->unum; 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate DRMACH_PR("\t\t%s\n", device->cm.name); 13577c478bd9Sstevel@tonic-gate 13587c478bd9Sstevel@tonic-gate /* 13597c478bd9Sstevel@tonic-gate * Disabled detaching mem node. 13607c478bd9Sstevel@tonic-gate */ 13617c478bd9Sstevel@tonic-gate rsp[m].masr_addr = STARFIRE_PC_MADR_ADDR(b, s_bd, i+4); 13627c478bd9Sstevel@tonic-gate rsp[m].masr = s_masr; 13637c478bd9Sstevel@tonic-gate m++; 13647c478bd9Sstevel@tonic-gate /* 13657c478bd9Sstevel@tonic-gate * Always write masr with present bit 13667c478bd9Sstevel@tonic-gate * off and then again with it on. 13677c478bd9Sstevel@tonic-gate */ 13687c478bd9Sstevel@tonic-gate rsp[m].masr_addr = STARFIRE_PC_MADR_ADDR(b, t_bd, i+4); 13697c478bd9Sstevel@tonic-gate rsp[m].masr = t_masr & ~STARFIRE_MC_MEM_PRESENT_MASK; 13707c478bd9Sstevel@tonic-gate m++; 13717c478bd9Sstevel@tonic-gate rsp[m].masr_addr = rsp[m-1].masr_addr; 13727c478bd9Sstevel@tonic-gate rsp[m].masr = t_masr; 13737c478bd9Sstevel@tonic-gate m++; 13747c478bd9Sstevel@tonic-gate 13757c478bd9Sstevel@tonic-gate } while (drmach_array_next(brd->devices, &d_idx, &d_id) == 0); 13767c478bd9Sstevel@tonic-gate } while (drmach_array_next(drmach_boards, &b_idx, &b_id) == 0); 13777c478bd9Sstevel@tonic-gate 13787c478bd9Sstevel@tonic-gate /* 13797c478bd9Sstevel@tonic-gate * Zero masr_addr value indicates the END. 13807c478bd9Sstevel@tonic-gate */ 13817c478bd9Sstevel@tonic-gate rsp[m].masr_addr = 0ull; 13827c478bd9Sstevel@tonic-gate rsp[m].masr = 0; 13837c478bd9Sstevel@tonic-gate DRMACH_PR("number of steps in rename script = %d\n", m); 13847c478bd9Sstevel@tonic-gate m++; 13857c478bd9Sstevel@tonic-gate 13867c478bd9Sstevel@tonic-gate /* paranoia */ 13877c478bd9Sstevel@tonic-gate ASSERT((caddr_t)&rsp[m] <= buf + buflen); 13887c478bd9Sstevel@tonic-gate 13897c478bd9Sstevel@tonic-gate #ifdef DEBUG 13907c478bd9Sstevel@tonic-gate { 13917c478bd9Sstevel@tonic-gate int j; 13927c478bd9Sstevel@tonic-gate 13937c478bd9Sstevel@tonic-gate DRMACH_PR("mc idle register address list:"); 13947c478bd9Sstevel@tonic-gate isp = (drmach_mc_idle_script_t *)buf; 139504580fdfSmathue DRMACH_PR("source mc idle addr 0x%lx, mem id %p", 139607d06da5SSurya Prakki isp[0].idle_addr, (void *)isp[0].mem); 139704580fdfSmathue DRMACH_PR("target mc idle addr 0x%lx, mem id %p", 139807d06da5SSurya Prakki isp[1].idle_addr, (void *)isp[1].mem); 13997c478bd9Sstevel@tonic-gate ASSERT(isp[2].idle_addr == 0); 14007c478bd9Sstevel@tonic-gate 14017c478bd9Sstevel@tonic-gate DRMACH_PR("copy-rename script:"); 14027c478bd9Sstevel@tonic-gate for (j = 0; j < m; j++) { 140304580fdfSmathue DRMACH_PR("0x%lx = 0x%08x", 14047c478bd9Sstevel@tonic-gate rsp[j].masr_addr, rsp[j].masr); 14057c478bd9Sstevel@tonic-gate } 14067c478bd9Sstevel@tonic-gate 14077c478bd9Sstevel@tonic-gate DELAY(1000000); 14087c478bd9Sstevel@tonic-gate } 14097c478bd9Sstevel@tonic-gate #endif 14107c478bd9Sstevel@tonic-gate 14117c478bd9Sstevel@tonic-gate /* return number of bytes consumed */ 14127c478bd9Sstevel@tonic-gate b = (caddr_t)&rsp[m] - buf; 14137c478bd9Sstevel@tonic-gate DRMACH_PR("total number of bytes consumed is %d\n", b); 14147c478bd9Sstevel@tonic-gate ASSERT(b <= buflen); 14157c478bd9Sstevel@tonic-gate 14167c478bd9Sstevel@tonic-gate #ifdef lint 14177c478bd9Sstevel@tonic-gate buflen = buflen; 14187c478bd9Sstevel@tonic-gate #endif 14197c478bd9Sstevel@tonic-gate 14207c478bd9Sstevel@tonic-gate return (NULL); 14217c478bd9Sstevel@tonic-gate } 14227c478bd9Sstevel@tonic-gate 14237c478bd9Sstevel@tonic-gate /* 14247c478bd9Sstevel@tonic-gate * The routine performs the necessary memory COPY and MC adr SWITCH. 14257c478bd9Sstevel@tonic-gate * Both operations MUST be at the same "level" so that the stack is 14267c478bd9Sstevel@tonic-gate * maintained correctly between the copy and switch. The switch 14277c478bd9Sstevel@tonic-gate * portion implements a caching mechanism to guarantee the code text 14287c478bd9Sstevel@tonic-gate * is cached prior to execution. This is to guard against possible 14297c478bd9Sstevel@tonic-gate * memory access while the MC adr's are being modified. 14307c478bd9Sstevel@tonic-gate * 14317c478bd9Sstevel@tonic-gate * IMPORTANT: The _drmach_copy_rename_end() function must immediately 14327c478bd9Sstevel@tonic-gate * follow drmach_copy_rename_prog__relocatable() so that the correct 14337c478bd9Sstevel@tonic-gate * "length" of the drmach_copy_rename_prog__relocatable can be 14347c478bd9Sstevel@tonic-gate * calculated. This routine MUST be a LEAF function, i.e. it can 14357c478bd9Sstevel@tonic-gate * make NO function calls, primarily for two reasons: 14367c478bd9Sstevel@tonic-gate * 14377c478bd9Sstevel@tonic-gate * 1. We must keep the stack consistent across the "switch". 14387c478bd9Sstevel@tonic-gate * 2. Function calls are compiled to relative offsets, and 14397c478bd9Sstevel@tonic-gate * we execute this function we'll be executing it from 14407c478bd9Sstevel@tonic-gate * a copied version in a different area of memory, thus 14417c478bd9Sstevel@tonic-gate * the relative offsets will be bogus. 14427c478bd9Sstevel@tonic-gate * 14437c478bd9Sstevel@tonic-gate * Moreover, it must have the "__relocatable" suffix to inform DTrace 14447c478bd9Sstevel@tonic-gate * providers (and anything else, for that matter) that this 14457c478bd9Sstevel@tonic-gate * function's text is manually relocated elsewhere before it is 14467c478bd9Sstevel@tonic-gate * executed. That is, it cannot be safely instrumented with any 14477c478bd9Sstevel@tonic-gate * methodology that is PC-relative. 14487c478bd9Sstevel@tonic-gate */ 14497c478bd9Sstevel@tonic-gate static void 14507c478bd9Sstevel@tonic-gate drmach_copy_rename_prog__relocatable(drmach_copy_rename_program_t *prog) 14517c478bd9Sstevel@tonic-gate { 14527c478bd9Sstevel@tonic-gate extern void drmach_exec_script_il(drmach_rename_script_t *rsp); 14537c478bd9Sstevel@tonic-gate 14547c478bd9Sstevel@tonic-gate drmach_mc_idle_script_t *isp; 14557c478bd9Sstevel@tonic-gate struct memlist *ml; 14567c478bd9Sstevel@tonic-gate int csize; 14577c478bd9Sstevel@tonic-gate int lnsize; 14587c478bd9Sstevel@tonic-gate uint64_t caddr; 14597c478bd9Sstevel@tonic-gate 14607c478bd9Sstevel@tonic-gate isp = (drmach_mc_idle_script_t *)prog->data; 14617c478bd9Sstevel@tonic-gate 14627c478bd9Sstevel@tonic-gate caddr = ecache_flushaddr; 14637c478bd9Sstevel@tonic-gate csize = (cpunodes[CPU->cpu_id].ecache_size << 1); 14647c478bd9Sstevel@tonic-gate lnsize = cpunodes[CPU->cpu_id].ecache_linesize; 14657c478bd9Sstevel@tonic-gate 14667c478bd9Sstevel@tonic-gate /* 14677c478bd9Sstevel@tonic-gate * DO COPY. 14687c478bd9Sstevel@tonic-gate */ 146956f33205SJonathan Adams for (ml = prog->c_ml; ml; ml = ml->ml_next) { 14707c478bd9Sstevel@tonic-gate uint64_t s_pa, t_pa; 14717c478bd9Sstevel@tonic-gate uint64_t nbytes; 14727c478bd9Sstevel@tonic-gate 147356f33205SJonathan Adams s_pa = prog->s_copybasepa + ml->ml_address; 147456f33205SJonathan Adams t_pa = prog->t_copybasepa + ml->ml_address; 147556f33205SJonathan Adams nbytes = ml->ml_size; 14767c478bd9Sstevel@tonic-gate 14777c478bd9Sstevel@tonic-gate while (nbytes != 0ull) { 14787c478bd9Sstevel@tonic-gate /* 14797c478bd9Sstevel@tonic-gate * This copy does NOT use an ASI 14807c478bd9Sstevel@tonic-gate * that avoids the Ecache, therefore 14817c478bd9Sstevel@tonic-gate * the dst_pa addresses may remain 14827c478bd9Sstevel@tonic-gate * in our Ecache after the dst_pa 14837c478bd9Sstevel@tonic-gate * has been removed from the system. 14847c478bd9Sstevel@tonic-gate * A subsequent write-back to memory 14857c478bd9Sstevel@tonic-gate * will cause an ARB-stop because the 14867c478bd9Sstevel@tonic-gate * physical address no longer exists 14877c478bd9Sstevel@tonic-gate * in the system. Therefore we must 14887c478bd9Sstevel@tonic-gate * flush out local Ecache after we 14897c478bd9Sstevel@tonic-gate * finish the copy. 14907c478bd9Sstevel@tonic-gate */ 14917c478bd9Sstevel@tonic-gate 14927c478bd9Sstevel@tonic-gate /* copy 32 bytes at src_pa to dst_pa */ 14937c478bd9Sstevel@tonic-gate bcopy32_il(s_pa, t_pa); 14947c478bd9Sstevel@tonic-gate 14957c478bd9Sstevel@tonic-gate /* increment by 32 bytes */ 14967c478bd9Sstevel@tonic-gate s_pa += (4 * sizeof (uint64_t)); 14977c478bd9Sstevel@tonic-gate t_pa += (4 * sizeof (uint64_t)); 14987c478bd9Sstevel@tonic-gate 14997c478bd9Sstevel@tonic-gate /* decrement by 32 bytes */ 15007c478bd9Sstevel@tonic-gate nbytes -= (4 * sizeof (uint64_t)); 15017c478bd9Sstevel@tonic-gate } 15027c478bd9Sstevel@tonic-gate } 15037c478bd9Sstevel@tonic-gate 15047c478bd9Sstevel@tonic-gate /* 15057c478bd9Sstevel@tonic-gate * Since bcopy32_il() does NOT use an ASI to bypass 15067c478bd9Sstevel@tonic-gate * the Ecache, we need to flush our Ecache after 15077c478bd9Sstevel@tonic-gate * the copy is complete. 15087c478bd9Sstevel@tonic-gate */ 15097c478bd9Sstevel@tonic-gate flush_ecache_il(caddr, csize, lnsize); /* inline version */ 15107c478bd9Sstevel@tonic-gate 15117c478bd9Sstevel@tonic-gate /* 15127c478bd9Sstevel@tonic-gate * Wait for MCs to go idle. 15137c478bd9Sstevel@tonic-gate */ 15147c478bd9Sstevel@tonic-gate do { 15157c478bd9Sstevel@tonic-gate register int t = 10; 15167c478bd9Sstevel@tonic-gate register uint_t v; 15177c478bd9Sstevel@tonic-gate 15187c478bd9Sstevel@tonic-gate /* loop t cycles waiting for each mc to indicate it's idle */ 15197c478bd9Sstevel@tonic-gate do { 15207c478bd9Sstevel@tonic-gate v = ldphysio_il(isp->idle_addr) 15217c478bd9Sstevel@tonic-gate & STARFIRE_MC_IDLE_MASK; 15227c478bd9Sstevel@tonic-gate 15237c478bd9Sstevel@tonic-gate } while (v != STARFIRE_MC_IDLE_MASK && t-- > 0); 15247c478bd9Sstevel@tonic-gate 15257c478bd9Sstevel@tonic-gate /* bailout if timedout */ 15267c478bd9Sstevel@tonic-gate if (t <= 0) { 15277c478bd9Sstevel@tonic-gate prog->restless_mc = isp->mem; 15287c478bd9Sstevel@tonic-gate return; 15297c478bd9Sstevel@tonic-gate } 15307c478bd9Sstevel@tonic-gate 15317c478bd9Sstevel@tonic-gate isp += 1; 15327c478bd9Sstevel@tonic-gate 15337c478bd9Sstevel@tonic-gate /* stop if terminating zero has been reached */ 15347c478bd9Sstevel@tonic-gate } while (isp->idle_addr != 0); 15357c478bd9Sstevel@tonic-gate 15367c478bd9Sstevel@tonic-gate /* advance passed terminating zero */ 15377c478bd9Sstevel@tonic-gate isp += 1; 15387c478bd9Sstevel@tonic-gate 15397c478bd9Sstevel@tonic-gate /* 15407c478bd9Sstevel@tonic-gate * The following inline assembly routine caches 15417c478bd9Sstevel@tonic-gate * the rename script and then caches the code that 15427c478bd9Sstevel@tonic-gate * will do the rename. This is necessary 15437c478bd9Sstevel@tonic-gate * so that we don't have any memory references during 15447c478bd9Sstevel@tonic-gate * the reprogramming. We accomplish this by first 15457c478bd9Sstevel@tonic-gate * jumping through the code to guarantee it's cached 15467c478bd9Sstevel@tonic-gate * before we actually execute it. 15477c478bd9Sstevel@tonic-gate */ 15487c478bd9Sstevel@tonic-gate drmach_exec_script_il((drmach_rename_script_t *)isp); 15497c478bd9Sstevel@tonic-gate } 15507c478bd9Sstevel@tonic-gate 15517c478bd9Sstevel@tonic-gate static void 15527c478bd9Sstevel@tonic-gate drmach_copy_rename_end(void) 15537c478bd9Sstevel@tonic-gate { 15547c478bd9Sstevel@tonic-gate /* 15557c478bd9Sstevel@tonic-gate * IMPORTANT: This function's location MUST be located immediately 15567c478bd9Sstevel@tonic-gate * following drmach_copy_rename_prog__relocatable to 15577c478bd9Sstevel@tonic-gate * accurately estimate its size. Note that this assumes 15587c478bd9Sstevel@tonic-gate * the compiler keeps these functions in the order in 15597c478bd9Sstevel@tonic-gate * which they appear :-o 15607c478bd9Sstevel@tonic-gate */ 15617c478bd9Sstevel@tonic-gate } 15627c478bd9Sstevel@tonic-gate 15637c478bd9Sstevel@tonic-gate sbd_error_t * 15647c478bd9Sstevel@tonic-gate drmach_copy_rename_init(drmachid_t t_id, uint64_t t_slice_offset, 15657c478bd9Sstevel@tonic-gate drmachid_t s_id, struct memlist *c_ml, drmachid_t *pgm_id) 15667c478bd9Sstevel@tonic-gate { 15677c478bd9Sstevel@tonic-gate drmach_device_t *s_mem; 15687c478bd9Sstevel@tonic-gate drmach_device_t *t_mem; 15697c478bd9Sstevel@tonic-gate struct memlist *x_ml; 15707c478bd9Sstevel@tonic-gate uint64_t off_mask, s_copybasepa, t_copybasepa, t_basepa; 15717c478bd9Sstevel@tonic-gate int len; 15727c478bd9Sstevel@tonic-gate caddr_t bp, wp; 15737c478bd9Sstevel@tonic-gate pda_handle_t ph; 15747c478bd9Sstevel@tonic-gate sbd_error_t *err; 15757c478bd9Sstevel@tonic-gate drmach_copy_rename_program_t *prog; 15767c478bd9Sstevel@tonic-gate 15777c478bd9Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(s_id)) 15787c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 15797c478bd9Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(t_id)) 15807c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 15817c478bd9Sstevel@tonic-gate s_mem = s_id; 15827c478bd9Sstevel@tonic-gate t_mem = t_id; 15837c478bd9Sstevel@tonic-gate 15847c478bd9Sstevel@tonic-gate /* get starting physical address of target memory */ 15857c478bd9Sstevel@tonic-gate err = drmach_mem_get_base_physaddr(t_id, &t_basepa); 15867c478bd9Sstevel@tonic-gate if (err) 15877c478bd9Sstevel@tonic-gate return (err); 15887c478bd9Sstevel@tonic-gate 15897c478bd9Sstevel@tonic-gate /* calculate slice offset mask from slice size */ 15907c478bd9Sstevel@tonic-gate off_mask = mc_get_mem_alignment() - 1; 15917c478bd9Sstevel@tonic-gate 15927c478bd9Sstevel@tonic-gate /* calculate source and target base pa */ 159356f33205SJonathan Adams s_copybasepa = c_ml->ml_address; 159456f33205SJonathan Adams t_copybasepa = 159556f33205SJonathan Adams t_basepa + ((c_ml->ml_address & off_mask) - t_slice_offset); 15967c478bd9Sstevel@tonic-gate 15977c478bd9Sstevel@tonic-gate /* paranoia */ 159856f33205SJonathan Adams ASSERT((c_ml->ml_address & off_mask) >= t_slice_offset); 15997c478bd9Sstevel@tonic-gate 16007c478bd9Sstevel@tonic-gate /* adjust copy memlist addresses to be relative to copy base pa */ 16017c478bd9Sstevel@tonic-gate x_ml = c_ml; 16027c478bd9Sstevel@tonic-gate while (x_ml != NULL) { 160356f33205SJonathan Adams x_ml->ml_address -= s_copybasepa; 160456f33205SJonathan Adams x_ml = x_ml->ml_next; 16057c478bd9Sstevel@tonic-gate } 16067c478bd9Sstevel@tonic-gate 16077c478bd9Sstevel@tonic-gate #ifdef DEBUG 16087c478bd9Sstevel@tonic-gate { 16097c478bd9Sstevel@tonic-gate uint64_t s_basepa, s_size, t_size; 16107c478bd9Sstevel@tonic-gate 16117c478bd9Sstevel@tonic-gate x_ml = c_ml; 161256f33205SJonathan Adams while (x_ml->ml_next != NULL) 161356f33205SJonathan Adams x_ml = x_ml->ml_next; 16147c478bd9Sstevel@tonic-gate 161504580fdfSmathue DRMACH_PR("source copy span: base pa 0x%lx, end pa 0x%lx\n", 16167c478bd9Sstevel@tonic-gate s_copybasepa, 161756f33205SJonathan Adams s_copybasepa + x_ml->ml_address + x_ml->ml_size); 16187c478bd9Sstevel@tonic-gate 161904580fdfSmathue DRMACH_PR("target copy span: base pa 0x%lx, end pa 0x%lx\n", 16207c478bd9Sstevel@tonic-gate t_copybasepa, 162156f33205SJonathan Adams t_copybasepa + x_ml->ml_address + x_ml->ml_size); 16227c478bd9Sstevel@tonic-gate 16237c478bd9Sstevel@tonic-gate DRMACH_PR("copy memlist (relative to copy base pa):\n"); 16247c478bd9Sstevel@tonic-gate MEMLIST_DUMP(c_ml); 16257c478bd9Sstevel@tonic-gate 16267c478bd9Sstevel@tonic-gate err = drmach_mem_get_base_physaddr(s_id, &s_basepa); 16277c478bd9Sstevel@tonic-gate ASSERT(err == NULL); 16287c478bd9Sstevel@tonic-gate 16297c478bd9Sstevel@tonic-gate err = drmach_mem_get_size(s_id, &s_size); 16307c478bd9Sstevel@tonic-gate ASSERT(err == NULL); 16317c478bd9Sstevel@tonic-gate 16327c478bd9Sstevel@tonic-gate err = drmach_mem_get_size(t_id, &t_size); 16337c478bd9Sstevel@tonic-gate ASSERT(err == NULL); 16347c478bd9Sstevel@tonic-gate 163504580fdfSmathue DRMACH_PR("current source base pa 0x%lx, size 0x%lx\n", 16367c478bd9Sstevel@tonic-gate s_basepa, s_size); 163704580fdfSmathue DRMACH_PR("current target base pa 0x%lx, size 0x%lx\n", 16387c478bd9Sstevel@tonic-gate t_basepa, t_size); 16397c478bd9Sstevel@tonic-gate 164056f33205SJonathan Adams ASSERT(s_copybasepa + x_ml->ml_address + x_ml->ml_size <= 164156f33205SJonathan Adams s_basepa + s_size); 164256f33205SJonathan Adams ASSERT(t_copybasepa + x_ml->ml_address + x_ml->ml_size <= 164356f33205SJonathan Adams t_basepa + t_size); 16447c478bd9Sstevel@tonic-gate } 16457c478bd9Sstevel@tonic-gate #endif 16467c478bd9Sstevel@tonic-gate 16477c478bd9Sstevel@tonic-gate ph = drmach_pda_open(); 16487c478bd9Sstevel@tonic-gate if (ph == NULL) 16497c478bd9Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 16507c478bd9Sstevel@tonic-gate 16517c478bd9Sstevel@tonic-gate /* 16527c478bd9Sstevel@tonic-gate * bp will be page aligned, since we're calling 16537c478bd9Sstevel@tonic-gate * kmem_zalloc() with an exact multiple of PAGESIZE. 16547c478bd9Sstevel@tonic-gate */ 16557c478bd9Sstevel@tonic-gate wp = bp = kmem_zalloc(PAGESIZE, KM_SLEEP); 16567c478bd9Sstevel@tonic-gate 16577c478bd9Sstevel@tonic-gate /* allocate space for copy rename struct */ 16587c478bd9Sstevel@tonic-gate len = sizeof (drmach_copy_rename_program_t); 165907d06da5SSurya Prakki DRMACH_PR("prog = 0x%p, header len %d\n", (void *)wp, len); 16607c478bd9Sstevel@tonic-gate prog = (drmach_copy_rename_program_t *)wp; 16617c478bd9Sstevel@tonic-gate wp += (len + ecache_alignsize - 1) & ~ (ecache_alignsize - 1); 16627c478bd9Sstevel@tonic-gate 16637c478bd9Sstevel@tonic-gate /* 16647c478bd9Sstevel@tonic-gate * Copy the code for the copy-rename routine into 16657c478bd9Sstevel@tonic-gate * a page aligned piece of memory. We do this to guarantee 16667c478bd9Sstevel@tonic-gate * that we're executing within the same page and thus reduce 16677c478bd9Sstevel@tonic-gate * the possibility of cache collisions between different 16687c478bd9Sstevel@tonic-gate * pages. 16697c478bd9Sstevel@tonic-gate */ 16707c478bd9Sstevel@tonic-gate len = (int)((ulong_t)drmach_copy_rename_end - 16717c478bd9Sstevel@tonic-gate (ulong_t)drmach_copy_rename_prog__relocatable); 16727c478bd9Sstevel@tonic-gate ASSERT(wp + len < bp + PAGESIZE); 16737c478bd9Sstevel@tonic-gate bcopy((caddr_t)drmach_copy_rename_prog__relocatable, wp, len); 16747c478bd9Sstevel@tonic-gate 167507d06da5SSurya Prakki DRMACH_PR("copy-rename function 0x%p, len %d\n", (void *)wp, len); 16767c478bd9Sstevel@tonic-gate prog->run = (void (*)())wp; 16777c478bd9Sstevel@tonic-gate wp += (len + ecache_alignsize - 1) & ~ (ecache_alignsize - 1); 16787c478bd9Sstevel@tonic-gate 16797c478bd9Sstevel@tonic-gate /* 16807c478bd9Sstevel@tonic-gate * Prepare data page that will contain script of 16817c478bd9Sstevel@tonic-gate * operations to perform during copy-rename. 16827c478bd9Sstevel@tonic-gate * Allocate temporary buffer to hold script. 16837c478bd9Sstevel@tonic-gate */ 16847c478bd9Sstevel@tonic-gate err = drmach_prep_rename_script(s_mem, t_mem, t_slice_offset, 16857c478bd9Sstevel@tonic-gate wp, PAGESIZE - (wp - bp)); 16867c478bd9Sstevel@tonic-gate if (err) { 16877c478bd9Sstevel@tonic-gate (void) drmach_copy_rename_fini(prog); 16887c478bd9Sstevel@tonic-gate return (err); 16897c478bd9Sstevel@tonic-gate } 16907c478bd9Sstevel@tonic-gate 169107d06da5SSurya Prakki DRMACH_PR("copy-rename script 0x%p, len %d\n", (void *)wp, len); 16927c478bd9Sstevel@tonic-gate prog->data = wp; 16937c478bd9Sstevel@tonic-gate wp += (len + ecache_alignsize - 1) & ~ (ecache_alignsize - 1); 16947c478bd9Sstevel@tonic-gate 16957c478bd9Sstevel@tonic-gate prog->ph = ph; 16967c478bd9Sstevel@tonic-gate prog->s_copybasepa = s_copybasepa; 16977c478bd9Sstevel@tonic-gate prog->t_copybasepa = t_copybasepa; 16987c478bd9Sstevel@tonic-gate prog->c_ml = c_ml; 16997c478bd9Sstevel@tonic-gate *pgm_id = prog; 17007c478bd9Sstevel@tonic-gate 17017c478bd9Sstevel@tonic-gate return (NULL); 17027c478bd9Sstevel@tonic-gate } 17037c478bd9Sstevel@tonic-gate 17047c478bd9Sstevel@tonic-gate sbd_error_t * 17057c478bd9Sstevel@tonic-gate drmach_copy_rename_fini(drmachid_t id) 17067c478bd9Sstevel@tonic-gate { 17077c478bd9Sstevel@tonic-gate drmach_copy_rename_program_t *prog = id; 17087c478bd9Sstevel@tonic-gate sbd_error_t *err = NULL; 17097c478bd9Sstevel@tonic-gate 17107c478bd9Sstevel@tonic-gate if (prog->c_ml != NULL) 17117c478bd9Sstevel@tonic-gate memlist_delete(prog->c_ml); 17127c478bd9Sstevel@tonic-gate 17137c478bd9Sstevel@tonic-gate if (prog->ph != NULL) 17147c478bd9Sstevel@tonic-gate pda_close(prog->ph); 17157c478bd9Sstevel@tonic-gate 17167c478bd9Sstevel@tonic-gate if (prog->restless_mc != 0) { 17177c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "MC did not idle; OBP Node 0x%x", 17187c478bd9Sstevel@tonic-gate (uint_t)drmach_node_get_dnode(prog->restless_mc->node)); 17197c478bd9Sstevel@tonic-gate 17207c478bd9Sstevel@tonic-gate err = DRMACH_INTERNAL_ERROR(); 17217c478bd9Sstevel@tonic-gate } 17227c478bd9Sstevel@tonic-gate 17237c478bd9Sstevel@tonic-gate kmem_free(prog, PAGESIZE); 17247c478bd9Sstevel@tonic-gate 17257c478bd9Sstevel@tonic-gate return (err); 17267c478bd9Sstevel@tonic-gate } 17277c478bd9Sstevel@tonic-gate 17287c478bd9Sstevel@tonic-gate static sbd_error_t * 17297c478bd9Sstevel@tonic-gate drmach_io_new(drmach_device_t *dp) 17307c478bd9Sstevel@tonic-gate { 17317c478bd9Sstevel@tonic-gate sbd_error_t *err; 17327c478bd9Sstevel@tonic-gate int portid; 17337c478bd9Sstevel@tonic-gate 17347c478bd9Sstevel@tonic-gate err = drmach_device_get_prop(dp, "upa-portid", &portid); 17357c478bd9Sstevel@tonic-gate if (err == NULL) { 17367c478bd9Sstevel@tonic-gate ASSERT(portid & 0x40); 17377c478bd9Sstevel@tonic-gate dp->unum = portid & 1; 17387c478bd9Sstevel@tonic-gate } 17397c478bd9Sstevel@tonic-gate 17407c478bd9Sstevel@tonic-gate dp->cm.isa = (void *)drmach_io_new; 17417c478bd9Sstevel@tonic-gate dp->cm.release = drmach_io_release; 17427c478bd9Sstevel@tonic-gate dp->cm.status = drmach_io_status; 17437c478bd9Sstevel@tonic-gate 174407d06da5SSurya Prakki (void) snprintf(dp->cm.name, sizeof (dp->cm.name), "%s%d", dp->type, 174507d06da5SSurya Prakki dp->unum); 17467c478bd9Sstevel@tonic-gate 17477c478bd9Sstevel@tonic-gate return (err); 17487c478bd9Sstevel@tonic-gate } 17497c478bd9Sstevel@tonic-gate 17507c478bd9Sstevel@tonic-gate static void 17517c478bd9Sstevel@tonic-gate drmach_iopc_op(pda_handle_t ph, drmach_iopc_op_t op) 17527c478bd9Sstevel@tonic-gate { 17537c478bd9Sstevel@tonic-gate register int b; 17547c478bd9Sstevel@tonic-gate 17557c478bd9Sstevel@tonic-gate for (b = 0; b < MAX_BOARDS; b++) { 17567c478bd9Sstevel@tonic-gate int p; 17577c478bd9Sstevel@tonic-gate ushort_t bda_ioc; 17587c478bd9Sstevel@tonic-gate board_desc_t *bdesc; 17597c478bd9Sstevel@tonic-gate 17607c478bd9Sstevel@tonic-gate if (pda_board_present(ph, b) == 0) 17617c478bd9Sstevel@tonic-gate continue; 17627c478bd9Sstevel@tonic-gate 17637c478bd9Sstevel@tonic-gate bdesc = (board_desc_t *)pda_get_board_info(ph, b); 17647c478bd9Sstevel@tonic-gate /* 17657c478bd9Sstevel@tonic-gate * Update PCs for IOCs. 17667c478bd9Sstevel@tonic-gate */ 17677c478bd9Sstevel@tonic-gate bda_ioc = bdesc->bda_ioc; 17687c478bd9Sstevel@tonic-gate for (p = 0; p < MAX_IOCS; p++) { 17697c478bd9Sstevel@tonic-gate u_longlong_t idle_addr; 17707c478bd9Sstevel@tonic-gate uchar_t value; 17717c478bd9Sstevel@tonic-gate 17727c478bd9Sstevel@tonic-gate if (BDA_NBL(bda_ioc, p) != BDAN_GOOD) 17737c478bd9Sstevel@tonic-gate continue; 17747c478bd9Sstevel@tonic-gate 17757c478bd9Sstevel@tonic-gate idle_addr = STARFIRE_BB_PC_ADDR(b, p, 1); 17767c478bd9Sstevel@tonic-gate 17777c478bd9Sstevel@tonic-gate switch (op) { 17787c478bd9Sstevel@tonic-gate case DO_PAUSE: 17797c478bd9Sstevel@tonic-gate value = STARFIRE_BB_PC_PAUSE(p); 17807c478bd9Sstevel@tonic-gate break; 17817c478bd9Sstevel@tonic-gate 17827c478bd9Sstevel@tonic-gate case DO_IDLE: 17837c478bd9Sstevel@tonic-gate value = STARFIRE_BB_PC_IDLE(p); 17847c478bd9Sstevel@tonic-gate break; 17857c478bd9Sstevel@tonic-gate 17867c478bd9Sstevel@tonic-gate case DO_UNPAUSE: 17877c478bd9Sstevel@tonic-gate value = ldbphysio(idle_addr); 17887c478bd9Sstevel@tonic-gate value &= ~STARFIRE_BB_PC_PAUSE(p); 17897c478bd9Sstevel@tonic-gate break; 17907c478bd9Sstevel@tonic-gate 17917c478bd9Sstevel@tonic-gate case DO_UNIDLE: 17927c478bd9Sstevel@tonic-gate value = ldbphysio(idle_addr); 17937c478bd9Sstevel@tonic-gate value &= ~STARFIRE_BB_PC_IDLE(p); 17947c478bd9Sstevel@tonic-gate break; 17957c478bd9Sstevel@tonic-gate 17967c478bd9Sstevel@tonic-gate default: 17977c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, 17987c478bd9Sstevel@tonic-gate "drmach_iopc_op: unknown op (%d)", 17997c478bd9Sstevel@tonic-gate (int)op); 18007c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 18017c478bd9Sstevel@tonic-gate } 18027c478bd9Sstevel@tonic-gate stbphysio(idle_addr, value); 18037c478bd9Sstevel@tonic-gate } 18047c478bd9Sstevel@tonic-gate } 18057c478bd9Sstevel@tonic-gate } 18067c478bd9Sstevel@tonic-gate 18077c478bd9Sstevel@tonic-gate void 18087c478bd9Sstevel@tonic-gate drmach_copy_rename(drmachid_t id) 18097c478bd9Sstevel@tonic-gate { 18107c478bd9Sstevel@tonic-gate drmach_copy_rename_program_t *prog = id; 18117c478bd9Sstevel@tonic-gate uint64_t neer; 18127c478bd9Sstevel@tonic-gate 18137c478bd9Sstevel@tonic-gate /* 18147c478bd9Sstevel@tonic-gate * UPA IDLE 18157c478bd9Sstevel@tonic-gate * Protocol = PAUSE -> IDLE -> UNPAUSE 18167c478bd9Sstevel@tonic-gate * In reality since we only "idle" the IOPCs it's sufficient 18177c478bd9Sstevel@tonic-gate * to just issue the IDLE operation since (in theory) all IOPCs 18187c478bd9Sstevel@tonic-gate * in the field are PC6. However, we'll be robust and do the 18197c478bd9Sstevel@tonic-gate * proper workaround protocol so that we never have to worry! 18207c478bd9Sstevel@tonic-gate */ 18217c478bd9Sstevel@tonic-gate drmach_iopc_op(prog->ph, DO_PAUSE); 18227c478bd9Sstevel@tonic-gate drmach_iopc_op(prog->ph, DO_IDLE); 18237c478bd9Sstevel@tonic-gate DELAY(100); 18247c478bd9Sstevel@tonic-gate drmach_iopc_op(prog->ph, DO_UNPAUSE); 18257c478bd9Sstevel@tonic-gate DELAY(100); 18267c478bd9Sstevel@tonic-gate 18277c478bd9Sstevel@tonic-gate /* disable CE reporting */ 18287c478bd9Sstevel@tonic-gate neer = get_error_enable(); 18297c478bd9Sstevel@tonic-gate set_error_enable(neer & ~EER_CEEN); 18307c478bd9Sstevel@tonic-gate 18317c478bd9Sstevel@tonic-gate /* run the copy/rename program */ 18327c478bd9Sstevel@tonic-gate prog->run(prog); 18337c478bd9Sstevel@tonic-gate 18347c478bd9Sstevel@tonic-gate /* enable CE reporting */ 18357c478bd9Sstevel@tonic-gate set_error_enable(neer); 18367c478bd9Sstevel@tonic-gate 18377c478bd9Sstevel@tonic-gate /* 18387c478bd9Sstevel@tonic-gate * UPA UNIDLE 18397c478bd9Sstevel@tonic-gate * Protocol = UNIDLE 18407c478bd9Sstevel@tonic-gate */ 18417c478bd9Sstevel@tonic-gate drmach_iopc_op(prog->ph, DO_UNIDLE); 18427c478bd9Sstevel@tonic-gate DELAY(100); 18437c478bd9Sstevel@tonic-gate } 18447c478bd9Sstevel@tonic-gate 18457c478bd9Sstevel@tonic-gate /* 18467c478bd9Sstevel@tonic-gate * The counter-timer and perf-counter nodes are not being cleaned 18477c478bd9Sstevel@tonic-gate * up after a board that was present at start of day is detached. 18487c478bd9Sstevel@tonic-gate * If the board has become unconfigured with this operation, walk 18497c478bd9Sstevel@tonic-gate * the prom tree and find all counter-timer and perf-counter nodes 18507c478bd9Sstevel@tonic-gate * that have the same board number as the board that was just 18517c478bd9Sstevel@tonic-gate * unconfigured and remove them. 18527c478bd9Sstevel@tonic-gate */ 18537c478bd9Sstevel@tonic-gate static sbd_error_t * 18547c478bd9Sstevel@tonic-gate drmach_remove_counter_nodes(drmachid_t id) 18557c478bd9Sstevel@tonic-gate { 18567c478bd9Sstevel@tonic-gate int num; 18577c478bd9Sstevel@tonic-gate char name[OBP_MAXDRVNAME]; 1858fa9e4066Sahrens pnode_t child; 18597c478bd9Sstevel@tonic-gate dev_info_t *dip; 18607c478bd9Sstevel@tonic-gate sbd_error_t *err; 18617c478bd9Sstevel@tonic-gate drmach_status_t stat; 18627c478bd9Sstevel@tonic-gate drmach_board_t *bp; 18637c478bd9Sstevel@tonic-gate 18647c478bd9Sstevel@tonic-gate if (!DRMACH_IS_BOARD_ID(id)) { 18657c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 18667c478bd9Sstevel@tonic-gate } 18677c478bd9Sstevel@tonic-gate 18687c478bd9Sstevel@tonic-gate if ((err = drmach_board_status(id, &stat)) != NULL) { 18697c478bd9Sstevel@tonic-gate return (err); 18707c478bd9Sstevel@tonic-gate } 18717c478bd9Sstevel@tonic-gate 18727c478bd9Sstevel@tonic-gate /* 18737c478bd9Sstevel@tonic-gate * Only clean up the counter-timer and perf-counter 18747c478bd9Sstevel@tonic-gate * nodes when the entire board is unconfigured. 18757c478bd9Sstevel@tonic-gate */ 18767c478bd9Sstevel@tonic-gate if (stat.configured) { 18777c478bd9Sstevel@tonic-gate return (NULL); 18787c478bd9Sstevel@tonic-gate } 18797c478bd9Sstevel@tonic-gate 18807c478bd9Sstevel@tonic-gate bp = (drmach_board_t *)id; 18817c478bd9Sstevel@tonic-gate 18827c478bd9Sstevel@tonic-gate err = NULL; 18837c478bd9Sstevel@tonic-gate 18847c478bd9Sstevel@tonic-gate for (child = prom_childnode(prom_rootnode()); child != OBP_NONODE; 18857c478bd9Sstevel@tonic-gate child = prom_nextnode(child)) { 18867c478bd9Sstevel@tonic-gate 18877c478bd9Sstevel@tonic-gate if (prom_getprop(child, OBP_BOARDNUM, (caddr_t)&num) == -1) { 18887c478bd9Sstevel@tonic-gate continue; 18897c478bd9Sstevel@tonic-gate } 18907c478bd9Sstevel@tonic-gate 18917c478bd9Sstevel@tonic-gate if (bp->bnum != num) { 18927c478bd9Sstevel@tonic-gate continue; 18937c478bd9Sstevel@tonic-gate } 18947c478bd9Sstevel@tonic-gate 18957c478bd9Sstevel@tonic-gate if (prom_getprop(child, OBP_NAME, (caddr_t)name) == -1) { 18967c478bd9Sstevel@tonic-gate continue; 18977c478bd9Sstevel@tonic-gate } 18987c478bd9Sstevel@tonic-gate 18997c478bd9Sstevel@tonic-gate if (strncmp(name, MISC_COUNTER_TIMER_DEVNAME, OBP_MAXDRVNAME) && 19007c478bd9Sstevel@tonic-gate strncmp(name, MISC_PERF_COUNTER_DEVNAME, OBP_MAXDRVNAME)) { 19017c478bd9Sstevel@tonic-gate continue; 19027c478bd9Sstevel@tonic-gate } 19037c478bd9Sstevel@tonic-gate 19047c478bd9Sstevel@tonic-gate /* Root node doesn't have to be held */ 19057c478bd9Sstevel@tonic-gate dip = e_ddi_nodeid_to_dip(child); 19067c478bd9Sstevel@tonic-gate 19077c478bd9Sstevel@tonic-gate /* 19087c478bd9Sstevel@tonic-gate * If the node is only in the OBP tree, then 19097c478bd9Sstevel@tonic-gate * we don't have to remove it. 19107c478bd9Sstevel@tonic-gate */ 19117c478bd9Sstevel@tonic-gate if (dip) { 19127c478bd9Sstevel@tonic-gate dev_info_t *fdip = NULL; 19137c478bd9Sstevel@tonic-gate 19147c478bd9Sstevel@tonic-gate DRMACH_PR("removing %s devinfo node\n", name); 19157c478bd9Sstevel@tonic-gate 19167c478bd9Sstevel@tonic-gate e_ddi_branch_hold(dip); 19177c478bd9Sstevel@tonic-gate ddi_release_devi(dip); /* held in e_ddi_nodeid_to_dip */ 19187c478bd9Sstevel@tonic-gate 19197c478bd9Sstevel@tonic-gate if (e_ddi_branch_destroy(dip, &fdip, 0)) { 19207c478bd9Sstevel@tonic-gate char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 19217c478bd9Sstevel@tonic-gate 19227c478bd9Sstevel@tonic-gate /* 19237c478bd9Sstevel@tonic-gate * If non-NULL, fdip is held and must be 19247c478bd9Sstevel@tonic-gate * released. 19257c478bd9Sstevel@tonic-gate */ 19267c478bd9Sstevel@tonic-gate if (fdip != NULL) { 19277c478bd9Sstevel@tonic-gate (void) ddi_pathname(fdip, path); 19287c478bd9Sstevel@tonic-gate ddi_release_devi(fdip); 19297c478bd9Sstevel@tonic-gate } else { 19307c478bd9Sstevel@tonic-gate (void) ddi_pathname(dip, path); 19317c478bd9Sstevel@tonic-gate } 19327c478bd9Sstevel@tonic-gate 19337c478bd9Sstevel@tonic-gate err = drerr_new(1, ESTF_DRVFAIL, path); 19347c478bd9Sstevel@tonic-gate kmem_free(path, MAXPATHLEN); 19357c478bd9Sstevel@tonic-gate e_ddi_branch_rele(dip); 19367c478bd9Sstevel@tonic-gate break; 19377c478bd9Sstevel@tonic-gate } 19387c478bd9Sstevel@tonic-gate } 19397c478bd9Sstevel@tonic-gate } 19407c478bd9Sstevel@tonic-gate 19417c478bd9Sstevel@tonic-gate return (err); 19427c478bd9Sstevel@tonic-gate } 19437c478bd9Sstevel@tonic-gate 19447c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 19457c478bd9Sstevel@tonic-gate sbd_error_t * 19467c478bd9Sstevel@tonic-gate drmach_pre_op(int cmd, drmachid_t id, drmach_opts_t *opts) 19477c478bd9Sstevel@tonic-gate { 19487c478bd9Sstevel@tonic-gate /* allow status and ncm operations to always succeed */ 19497c478bd9Sstevel@tonic-gate if ((cmd == SBD_CMD_STATUS) || (cmd == SBD_CMD_GETNCM)) { 19507c478bd9Sstevel@tonic-gate return (NULL); 19517c478bd9Sstevel@tonic-gate } 19527c478bd9Sstevel@tonic-gate 19537c478bd9Sstevel@tonic-gate /* check all other commands for the required option string */ 19547c478bd9Sstevel@tonic-gate if ((opts->size > 0) && (opts->copts != NULL)) { 19557c478bd9Sstevel@tonic-gate 19567c478bd9Sstevel@tonic-gate DRMACH_PR("platform options: %s\n", opts->copts); 19577c478bd9Sstevel@tonic-gate 19587c478bd9Sstevel@tonic-gate if (strstr(opts->copts, "xfdr") != NULL) { 19597c478bd9Sstevel@tonic-gate return (NULL); 19607c478bd9Sstevel@tonic-gate } 19617c478bd9Sstevel@tonic-gate } 19627c478bd9Sstevel@tonic-gate 19637c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_SUPPORT, NULL)); 19647c478bd9Sstevel@tonic-gate } 19657c478bd9Sstevel@tonic-gate 19667c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 19677c478bd9Sstevel@tonic-gate sbd_error_t * 19687c478bd9Sstevel@tonic-gate drmach_post_op(int cmd, drmachid_t id, drmach_opts_t *opts) 19697c478bd9Sstevel@tonic-gate { 19707c478bd9Sstevel@tonic-gate sbd_error_t *err = NULL; 19717c478bd9Sstevel@tonic-gate 19727c478bd9Sstevel@tonic-gate switch (cmd) { 19737c478bd9Sstevel@tonic-gate case SBD_CMD_UNCONFIGURE: 19747c478bd9Sstevel@tonic-gate 19757c478bd9Sstevel@tonic-gate err = drmach_remove_counter_nodes(id); 19767c478bd9Sstevel@tonic-gate break; 19777c478bd9Sstevel@tonic-gate 19787c478bd9Sstevel@tonic-gate case SBD_CMD_CONFIGURE: 19797c478bd9Sstevel@tonic-gate case SBD_CMD_DISCONNECT: 19807c478bd9Sstevel@tonic-gate case SBD_CMD_CONNECT: 19817c478bd9Sstevel@tonic-gate case SBD_CMD_GETNCM: 19827c478bd9Sstevel@tonic-gate case SBD_CMD_STATUS: 19837c478bd9Sstevel@tonic-gate break; 19847c478bd9Sstevel@tonic-gate 19857c478bd9Sstevel@tonic-gate default: 19867c478bd9Sstevel@tonic-gate break; 19877c478bd9Sstevel@tonic-gate } 19887c478bd9Sstevel@tonic-gate 19897c478bd9Sstevel@tonic-gate return (err); 19907c478bd9Sstevel@tonic-gate } 19917c478bd9Sstevel@tonic-gate 19927c478bd9Sstevel@tonic-gate sbd_error_t * 19937c478bd9Sstevel@tonic-gate drmach_board_assign(int bnum, drmachid_t *id) 19947c478bd9Sstevel@tonic-gate { 19957c478bd9Sstevel@tonic-gate sbd_error_t *err; 19967c478bd9Sstevel@tonic-gate 19977c478bd9Sstevel@tonic-gate if (!drmach_initialized && drmach_init() == -1) { 19987c478bd9Sstevel@tonic-gate err = DRMACH_INTERNAL_ERROR(); 19997c478bd9Sstevel@tonic-gate } else if (drmach_array_get(drmach_boards, bnum, id) == -1) { 20007c478bd9Sstevel@tonic-gate err = drerr_new(1, ESTF_BNUM, "%d", bnum); 20017c478bd9Sstevel@tonic-gate } else if (*id != NULL) { 20027c478bd9Sstevel@tonic-gate err = NULL; 20037c478bd9Sstevel@tonic-gate } else { 20047c478bd9Sstevel@tonic-gate drmach_board_t *bp; 20057c478bd9Sstevel@tonic-gate 20067c478bd9Sstevel@tonic-gate *id = (drmachid_t)drmach_board_new(bnum); 20077c478bd9Sstevel@tonic-gate bp = *id; 20087c478bd9Sstevel@tonic-gate bp->assigned = 1; 20097c478bd9Sstevel@tonic-gate err = NULL; 20107c478bd9Sstevel@tonic-gate } 20117c478bd9Sstevel@tonic-gate 20127c478bd9Sstevel@tonic-gate return (err); 20137c478bd9Sstevel@tonic-gate } 20147c478bd9Sstevel@tonic-gate 20157c478bd9Sstevel@tonic-gate static int 20167c478bd9Sstevel@tonic-gate drmach_attach_board(void *arg) 20177c478bd9Sstevel@tonic-gate { 20187c478bd9Sstevel@tonic-gate drmach_board_t *obj = (drmach_board_t *)arg; 20197c478bd9Sstevel@tonic-gate cpuset_t cset; 20207c478bd9Sstevel@tonic-gate int retval; 20217c478bd9Sstevel@tonic-gate 20227c478bd9Sstevel@tonic-gate /* 20237c478bd9Sstevel@tonic-gate * OBP disables traps during the board probe. 20247c478bd9Sstevel@tonic-gate * So, in order to prevent cross-call/cross-trap timeouts, 20257c478bd9Sstevel@tonic-gate * and thus panics, we effectively block anybody from 20267c478bd9Sstevel@tonic-gate * issuing xc's/xt's by doing a promsafe_xc_attention. 20277c478bd9Sstevel@tonic-gate * In the previous version of Starfire DR (2.6), a timeout 20287c478bd9Sstevel@tonic-gate * suspension mechanism was implemented in the send-mondo 20297c478bd9Sstevel@tonic-gate * assembly. That mechanism is unnecessary with the 20307c478bd9Sstevel@tonic-gate * existence of xc_attention/xc_dismissed. 20317c478bd9Sstevel@tonic-gate */ 20327c478bd9Sstevel@tonic-gate cset = cpu_ready_set; 20337c478bd9Sstevel@tonic-gate promsafe_xc_attention(cset); 20347c478bd9Sstevel@tonic-gate 20357c478bd9Sstevel@tonic-gate retval = prom_starfire_add_brd(obj->connect_cpuid); 20367c478bd9Sstevel@tonic-gate 20377c478bd9Sstevel@tonic-gate xc_dismissed(cset); 20387c478bd9Sstevel@tonic-gate 20397c478bd9Sstevel@tonic-gate return (retval); 20407c478bd9Sstevel@tonic-gate } 20417c478bd9Sstevel@tonic-gate 20427c478bd9Sstevel@tonic-gate sbd_error_t * 20437c478bd9Sstevel@tonic-gate drmach_board_connect(drmachid_t id, drmach_opts_t *opts) 20447c478bd9Sstevel@tonic-gate { 20457c478bd9Sstevel@tonic-gate drmach_board_t *obj = (drmach_board_t *)id; 20467c478bd9Sstevel@tonic-gate int retval; 20477c478bd9Sstevel@tonic-gate sbd_error_t *err; 20487c478bd9Sstevel@tonic-gate char *cptr, *copts; 20497c478bd9Sstevel@tonic-gate 20507c478bd9Sstevel@tonic-gate if (!DRMACH_IS_BOARD_ID(id)) 20517c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 20527c478bd9Sstevel@tonic-gate 20537c478bd9Sstevel@tonic-gate if (opts->size > 0) 20547c478bd9Sstevel@tonic-gate copts = opts->copts; 20557c478bd9Sstevel@tonic-gate 20567c478bd9Sstevel@tonic-gate if ((cptr = strstr(copts, "cpuid=")) != NULL) { 20577c478bd9Sstevel@tonic-gate int cpuid; 20587c478bd9Sstevel@tonic-gate 20597c478bd9Sstevel@tonic-gate cptr += strlen("cpuid="); 20607c478bd9Sstevel@tonic-gate cpuid = stoi(&cptr); 20617c478bd9Sstevel@tonic-gate 20627c478bd9Sstevel@tonic-gate if (DRMACH_CPUID2BNUM(cpuid) == obj->bnum) { 20637c478bd9Sstevel@tonic-gate obj->connect_cpuid = cpuid; 20647c478bd9Sstevel@tonic-gate obj->assigned = 1; 20657c478bd9Sstevel@tonic-gate } else 20667c478bd9Sstevel@tonic-gate return (drerr_new(1, ESTF_SETCPUVAL, "%d", cpuid)); 20677c478bd9Sstevel@tonic-gate } else { 20687c478bd9Sstevel@tonic-gate /* cpuid was not specified */ 20697c478bd9Sstevel@tonic-gate obj->connect_cpuid = -1; 20707c478bd9Sstevel@tonic-gate } 20717c478bd9Sstevel@tonic-gate 20727c478bd9Sstevel@tonic-gate if (obj->connect_cpuid == -1) { 20737c478bd9Sstevel@tonic-gate err = drerr_new(1, ESTF_NOCPUID, obj->cm.name); 20747c478bd9Sstevel@tonic-gate return (err); 20757c478bd9Sstevel@tonic-gate } 20767c478bd9Sstevel@tonic-gate 20777c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "DRMACH: PROM attach %s CPU %d\n", 20787c478bd9Sstevel@tonic-gate obj->cm.name, obj->connect_cpuid); 20797c478bd9Sstevel@tonic-gate 20807c478bd9Sstevel@tonic-gate retval = prom_tree_update(drmach_attach_board, obj); 20817c478bd9Sstevel@tonic-gate 20827c478bd9Sstevel@tonic-gate if (retval == 0) 20837c478bd9Sstevel@tonic-gate err = NULL; 20847c478bd9Sstevel@tonic-gate else { 20857c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "prom error: prom_starfire_add_brd(%d) " 20867c478bd9Sstevel@tonic-gate "returned %d", obj->connect_cpuid, retval); 20877c478bd9Sstevel@tonic-gate 20887c478bd9Sstevel@tonic-gate err = drerr_new(1, ESTF_PROBE, obj->cm.name); 20897c478bd9Sstevel@tonic-gate } 20907c478bd9Sstevel@tonic-gate 20917c478bd9Sstevel@tonic-gate obj->connect_cpuid = -1; 20927c478bd9Sstevel@tonic-gate 20937c478bd9Sstevel@tonic-gate return (err); 20947c478bd9Sstevel@tonic-gate } 20957c478bd9Sstevel@tonic-gate 20967c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 20977c478bd9Sstevel@tonic-gate sbd_error_t * 20987c478bd9Sstevel@tonic-gate drmach_board_disconnect(drmachid_t id, drmach_opts_t *opts) 20997c478bd9Sstevel@tonic-gate { 2100d8995facSha137994 drmach_board_t *bp; 2101d8995facSha137994 int rv; 2102d8995facSha137994 int d_idx; /* device index */ 2103d8995facSha137994 drmachid_t d_id; /* device ID */ 2104d8995facSha137994 sbd_error_t *err; 2105d8995facSha137994 2106d8995facSha137994 if (!DRMACH_IS_BOARD_ID(id)) 2107d8995facSha137994 return (drerr_new(0, ESTF_INAPPROP, NULL)); 2108d8995facSha137994 2109d8995facSha137994 bp = id; 2110d8995facSha137994 2111d8995facSha137994 /* 2112d8995facSha137994 * We need to make sure all of the board's device nodes 2113d8995facSha137994 * have been removed from the Solaris device tree before 2114d8995facSha137994 * continuing with the disconnect. Otherwise, we could 2115d8995facSha137994 * disconnect the board and remove the OBP device tree 2116d8995facSha137994 * nodes with Solaris device tree nodes remaining. 2117d8995facSha137994 * 2118d8995facSha137994 * On Starfire, Solaris device tree nodes are deleted 2119d8995facSha137994 * during unconfigure by drmach_unconfigure(). It's 2120d8995facSha137994 * necessary to do this here because drmach_unconfigure() 2121d8995facSha137994 * failures are not handled during unconfigure. 2122d8995facSha137994 */ 2123d8995facSha137994 if (bp->devices) { 2124d8995facSha137994 rv = drmach_array_first(bp->devices, &d_idx, &d_id); 2125d8995facSha137994 while (rv == 0) { 2126d8995facSha137994 err = drmach_unconfigure(d_id, DRMACH_DEVI_REMOVE); 2127d8995facSha137994 if (err) 2128d8995facSha137994 return (err); 2129d8995facSha137994 2130d8995facSha137994 rv = drmach_array_next(bp->devices, &d_idx, &d_id); 2131d8995facSha137994 } 2132d8995facSha137994 } 2133d8995facSha137994 2134d8995facSha137994 /* 2135d8995facSha137994 * Starfire board Solaris device tree counter nodes, 2136d8995facSha137994 * which are only present on start-of-day boards, are 2137d8995facSha137994 * removed in the dr_post_op() code flow after the 2138d8995facSha137994 * board is unconfigured. We call the counter node 2139d8995facSha137994 * removal function here because unconfigure errors 2140d8995facSha137994 * can cause the dr_post_op() function to be skipped 2141d8995facSha137994 * after an unconfigure operation even though all of 2142d8995facSha137994 * the board's devices have been transitioned to the 2143d8995facSha137994 * unconfigured state. 2144d8995facSha137994 */ 2145d8995facSha137994 err = drmach_remove_counter_nodes(id); 2146d8995facSha137994 if (err) 2147d8995facSha137994 return (err); 2148d8995facSha137994 21497c478bd9Sstevel@tonic-gate return (NULL); 21507c478bd9Sstevel@tonic-gate } 21517c478bd9Sstevel@tonic-gate 21527c478bd9Sstevel@tonic-gate static int 21537c478bd9Sstevel@tonic-gate drmach_board_find_devices_cb(drmach_node_walk_args_t *args) 21547c478bd9Sstevel@tonic-gate { 21557c478bd9Sstevel@tonic-gate drmach_node_t *node = args->node; 21567c478bd9Sstevel@tonic-gate drmach_board_cb_data_t *data = args->data; 21577c478bd9Sstevel@tonic-gate drmach_board_t *obj = data->obj; 21587c478bd9Sstevel@tonic-gate 21597c478bd9Sstevel@tonic-gate int rv; 21607c478bd9Sstevel@tonic-gate int bnum; 21617c478bd9Sstevel@tonic-gate drmach_device_t *device; 21627c478bd9Sstevel@tonic-gate 21637c478bd9Sstevel@tonic-gate rv = drmach_node_get_prop(node, OBP_BOARDNUM, &bnum); 21647c478bd9Sstevel@tonic-gate if (rv) { 21657c478bd9Sstevel@tonic-gate /* 21667c478bd9Sstevel@tonic-gate * if the node does not have a board# property, then 21677c478bd9Sstevel@tonic-gate * by that information alone it is known that drmach 21687c478bd9Sstevel@tonic-gate * is not interested in it. 21697c478bd9Sstevel@tonic-gate */ 21707c478bd9Sstevel@tonic-gate return (0); 21717c478bd9Sstevel@tonic-gate } else if (bnum != obj->bnum) 21727c478bd9Sstevel@tonic-gate return (0); 21737c478bd9Sstevel@tonic-gate 21747c478bd9Sstevel@tonic-gate /* 21757c478bd9Sstevel@tonic-gate * Create a device data structure from this node data. 21767c478bd9Sstevel@tonic-gate * The call may yield nothing if the node is not of interest 21777c478bd9Sstevel@tonic-gate * to drmach. 21787c478bd9Sstevel@tonic-gate */ 21797c478bd9Sstevel@tonic-gate data->err = drmach_device_new(node, obj, &device); 21807c478bd9Sstevel@tonic-gate if (data->err) 21817c478bd9Sstevel@tonic-gate return (-1); 21827c478bd9Sstevel@tonic-gate else if (device == NULL) { 21837c478bd9Sstevel@tonic-gate /* 21847c478bd9Sstevel@tonic-gate * drmach_device_new examined the node we passed in 21857c478bd9Sstevel@tonic-gate * and determined that it was one not of interest to 21867c478bd9Sstevel@tonic-gate * drmach. So, it is skipped. 21877c478bd9Sstevel@tonic-gate */ 21887c478bd9Sstevel@tonic-gate return (0); 21897c478bd9Sstevel@tonic-gate } 21907c478bd9Sstevel@tonic-gate 21917c478bd9Sstevel@tonic-gate rv = drmach_array_set(obj->devices, data->ndevs++, device); 21927c478bd9Sstevel@tonic-gate if (rv) { 21937c478bd9Sstevel@tonic-gate drmach_device_dispose(device); 21947c478bd9Sstevel@tonic-gate data->err = DRMACH_INTERNAL_ERROR(); 21957c478bd9Sstevel@tonic-gate return (-1); 21967c478bd9Sstevel@tonic-gate } 21977c478bd9Sstevel@tonic-gate 21987c478bd9Sstevel@tonic-gate data->err = (*data->found)(data->a, device->type, device->unum, device); 21997c478bd9Sstevel@tonic-gate return (data->err == NULL ? 0 : -1); 22007c478bd9Sstevel@tonic-gate } 22017c478bd9Sstevel@tonic-gate 22027c478bd9Sstevel@tonic-gate sbd_error_t * 22037c478bd9Sstevel@tonic-gate drmach_board_find_devices(drmachid_t id, void *a, 22047c478bd9Sstevel@tonic-gate sbd_error_t *(*found)(void *a, const char *, int, drmachid_t)) 22057c478bd9Sstevel@tonic-gate { 22067c478bd9Sstevel@tonic-gate extern int plat_max_cpu_units_per_board(); 22077c478bd9Sstevel@tonic-gate extern int plat_max_mem_units_per_board(); 22087c478bd9Sstevel@tonic-gate extern int plat_max_io_units_per_board(); 22097c478bd9Sstevel@tonic-gate 22107c478bd9Sstevel@tonic-gate drmach_board_t *obj = (drmach_board_t *)id; 22117c478bd9Sstevel@tonic-gate sbd_error_t *err; 22127c478bd9Sstevel@tonic-gate int max_devices; 22137c478bd9Sstevel@tonic-gate int rv; 22147c478bd9Sstevel@tonic-gate drmach_board_cb_data_t data; 22157c478bd9Sstevel@tonic-gate 22167c478bd9Sstevel@tonic-gate max_devices = plat_max_cpu_units_per_board(); 22177c478bd9Sstevel@tonic-gate max_devices += plat_max_mem_units_per_board(); 22187c478bd9Sstevel@tonic-gate max_devices += plat_max_io_units_per_board(); 22197c478bd9Sstevel@tonic-gate 22207c478bd9Sstevel@tonic-gate obj->devices = drmach_array_new(0, max_devices); 22217c478bd9Sstevel@tonic-gate 22227c478bd9Sstevel@tonic-gate data.obj = obj; 22237c478bd9Sstevel@tonic-gate data.ndevs = 0; 22247c478bd9Sstevel@tonic-gate data.found = found; 22257c478bd9Sstevel@tonic-gate data.a = a; 22267c478bd9Sstevel@tonic-gate data.err = NULL; 22277c478bd9Sstevel@tonic-gate 22287c478bd9Sstevel@tonic-gate rv = drmach_node_walk(obj->tree, &data, drmach_board_find_devices_cb); 22297c478bd9Sstevel@tonic-gate if (rv == 0) 22307c478bd9Sstevel@tonic-gate err = NULL; 22317c478bd9Sstevel@tonic-gate else { 22327c478bd9Sstevel@tonic-gate drmach_array_dispose(obj->devices, drmach_device_dispose); 22337c478bd9Sstevel@tonic-gate obj->devices = NULL; 22347c478bd9Sstevel@tonic-gate 22357c478bd9Sstevel@tonic-gate if (data.err) 22367c478bd9Sstevel@tonic-gate err = data.err; 22377c478bd9Sstevel@tonic-gate else 22387c478bd9Sstevel@tonic-gate err = DRMACH_INTERNAL_ERROR(); 22397c478bd9Sstevel@tonic-gate } 22407c478bd9Sstevel@tonic-gate 22417c478bd9Sstevel@tonic-gate return (err); 22427c478bd9Sstevel@tonic-gate } 22437c478bd9Sstevel@tonic-gate 22447c478bd9Sstevel@tonic-gate int 22457c478bd9Sstevel@tonic-gate drmach_board_lookup(int bnum, drmachid_t *id) 22467c478bd9Sstevel@tonic-gate { 22477c478bd9Sstevel@tonic-gate int rv = 0; 22487c478bd9Sstevel@tonic-gate 22497c478bd9Sstevel@tonic-gate if (!drmach_initialized && drmach_init() == -1) { 22507c478bd9Sstevel@tonic-gate *id = 0; 22517c478bd9Sstevel@tonic-gate rv = -1; 22527c478bd9Sstevel@tonic-gate } else if (drmach_array_get(drmach_boards, bnum, id)) { 22537c478bd9Sstevel@tonic-gate *id = 0; 22547c478bd9Sstevel@tonic-gate rv = -1; 22557c478bd9Sstevel@tonic-gate } 22567c478bd9Sstevel@tonic-gate return (rv); 22577c478bd9Sstevel@tonic-gate } 22587c478bd9Sstevel@tonic-gate 22597c478bd9Sstevel@tonic-gate sbd_error_t * 22607c478bd9Sstevel@tonic-gate drmach_board_name(int bnum, char *buf, int buflen) 22617c478bd9Sstevel@tonic-gate { 226207d06da5SSurya Prakki (void) snprintf(buf, buflen, "SB%d", bnum); 22637c478bd9Sstevel@tonic-gate return (NULL); 22647c478bd9Sstevel@tonic-gate } 22657c478bd9Sstevel@tonic-gate 22667c478bd9Sstevel@tonic-gate sbd_error_t * 22677c478bd9Sstevel@tonic-gate drmach_board_poweroff(drmachid_t id) 22687c478bd9Sstevel@tonic-gate { 22697c478bd9Sstevel@tonic-gate drmach_board_t *bp; 22707c478bd9Sstevel@tonic-gate sbd_error_t *err; 22717c478bd9Sstevel@tonic-gate drmach_status_t stat; 22727c478bd9Sstevel@tonic-gate 22737c478bd9Sstevel@tonic-gate if (!DRMACH_IS_BOARD_ID(id)) 22747c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 22757c478bd9Sstevel@tonic-gate bp = id; 22767c478bd9Sstevel@tonic-gate 22777c478bd9Sstevel@tonic-gate err = drmach_board_status(id, &stat); 22787c478bd9Sstevel@tonic-gate if (err) 22797c478bd9Sstevel@tonic-gate return (err); 22807c478bd9Sstevel@tonic-gate else if (stat.configured || stat.busy) 22817c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_CONFIGBUSY, bp->cm.name)); 22827c478bd9Sstevel@tonic-gate else { 22837c478bd9Sstevel@tonic-gate /* board power off is essentially a noop for Starfire */ 22847c478bd9Sstevel@tonic-gate bp->powered = 0; 22857c478bd9Sstevel@tonic-gate return (NULL); 22867c478bd9Sstevel@tonic-gate } 22877c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 22887c478bd9Sstevel@tonic-gate } 22897c478bd9Sstevel@tonic-gate 22907c478bd9Sstevel@tonic-gate sbd_error_t * 22917c478bd9Sstevel@tonic-gate drmach_board_poweron(drmachid_t id) 22927c478bd9Sstevel@tonic-gate { 22937c478bd9Sstevel@tonic-gate drmach_board_t *bp; 22947c478bd9Sstevel@tonic-gate 22957c478bd9Sstevel@tonic-gate if (!DRMACH_IS_BOARD_ID(id)) 22967c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 22977c478bd9Sstevel@tonic-gate bp = id; 22987c478bd9Sstevel@tonic-gate 22997c478bd9Sstevel@tonic-gate /* board power on is essentially a noop for Starfire */ 23007c478bd9Sstevel@tonic-gate bp->powered = 1; 23017c478bd9Sstevel@tonic-gate 23027c478bd9Sstevel@tonic-gate return (NULL); 23037c478bd9Sstevel@tonic-gate } 23047c478bd9Sstevel@tonic-gate 23057c478bd9Sstevel@tonic-gate static sbd_error_t * 23067c478bd9Sstevel@tonic-gate drmach_board_release(drmachid_t id) 23077c478bd9Sstevel@tonic-gate { 23087c478bd9Sstevel@tonic-gate if (!DRMACH_IS_BOARD_ID(id)) 23097c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 23107c478bd9Sstevel@tonic-gate return (NULL); 23117c478bd9Sstevel@tonic-gate } 23127c478bd9Sstevel@tonic-gate 23137c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 23147c478bd9Sstevel@tonic-gate sbd_error_t * 23157c478bd9Sstevel@tonic-gate drmach_board_test(drmachid_t id, drmach_opts_t *opts, int force) 23167c478bd9Sstevel@tonic-gate { 23177c478bd9Sstevel@tonic-gate return (NULL); 23187c478bd9Sstevel@tonic-gate } 23197c478bd9Sstevel@tonic-gate 23207c478bd9Sstevel@tonic-gate sbd_error_t * 23217c478bd9Sstevel@tonic-gate drmach_board_unassign(drmachid_t id) 23227c478bd9Sstevel@tonic-gate { 23237c478bd9Sstevel@tonic-gate drmach_board_t *bp; 23247c478bd9Sstevel@tonic-gate sbd_error_t *err; 23257c478bd9Sstevel@tonic-gate drmach_status_t stat; 23267c478bd9Sstevel@tonic-gate 23277c478bd9Sstevel@tonic-gate if (!DRMACH_IS_BOARD_ID(id)) 23287c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 23297c478bd9Sstevel@tonic-gate bp = id; 23307c478bd9Sstevel@tonic-gate 23317c478bd9Sstevel@tonic-gate err = drmach_board_status(id, &stat); 23327c478bd9Sstevel@tonic-gate if (err) 23337c478bd9Sstevel@tonic-gate return (err); 23347c478bd9Sstevel@tonic-gate else if (stat.configured || stat.busy) 23357c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_CONFIGBUSY, bp->cm.name)); 23367c478bd9Sstevel@tonic-gate else if (drmach_array_set(drmach_boards, bp->bnum, 0) != 0) 23377c478bd9Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 23387c478bd9Sstevel@tonic-gate else { 23397c478bd9Sstevel@tonic-gate drmach_board_dispose(bp); 23407c478bd9Sstevel@tonic-gate return (NULL); 23417c478bd9Sstevel@tonic-gate } 23427c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 23437c478bd9Sstevel@tonic-gate } 23447c478bd9Sstevel@tonic-gate 23457c478bd9Sstevel@tonic-gate static sbd_error_t * 23467c478bd9Sstevel@tonic-gate drmach_cpu_new(drmach_device_t *dp) 23477c478bd9Sstevel@tonic-gate { 23487c478bd9Sstevel@tonic-gate sbd_error_t *err; 23497c478bd9Sstevel@tonic-gate int portid; 23507c478bd9Sstevel@tonic-gate 23517c478bd9Sstevel@tonic-gate err = drmach_device_get_prop(dp, "upa-portid", &portid); 23527c478bd9Sstevel@tonic-gate if (err == NULL) 23537c478bd9Sstevel@tonic-gate dp->unum = portid & 3; 23547c478bd9Sstevel@tonic-gate 23557c478bd9Sstevel@tonic-gate dp->cm.isa = (void *)drmach_cpu_new; 23567c478bd9Sstevel@tonic-gate dp->cm.release = drmach_cpu_release; 23577c478bd9Sstevel@tonic-gate dp->cm.status = drmach_cpu_status; 23587c478bd9Sstevel@tonic-gate 235907d06da5SSurya Prakki (void) snprintf(dp->cm.name, sizeof (dp->cm.name), "%s%d", dp->type, 236007d06da5SSurya Prakki dp->unum); 23617c478bd9Sstevel@tonic-gate 23627c478bd9Sstevel@tonic-gate return (err); 23637c478bd9Sstevel@tonic-gate } 23647c478bd9Sstevel@tonic-gate 23657c478bd9Sstevel@tonic-gate /* 23667c478bd9Sstevel@tonic-gate * drmach_cpu_obp_detach() 23677c478bd9Sstevel@tonic-gate * This requires two steps, first, we must put the cpuid into the OBP 23687c478bd9Sstevel@tonic-gate * idle loop (Idle in Program) state. Then we call OBP to place the CPU 23697c478bd9Sstevel@tonic-gate * into the "Detached" state, which does any special processing to 23707c478bd9Sstevel@tonic-gate * actually detach the cpu, such as flushing ecache, and also ensures 23717c478bd9Sstevel@tonic-gate * that a subsequent breakpoint won't restart the cpu (if it was just in 23727c478bd9Sstevel@tonic-gate * Idle in Program state). 23737c478bd9Sstevel@tonic-gate */ 23747c478bd9Sstevel@tonic-gate static void 23757c478bd9Sstevel@tonic-gate drmach_cpu_obp_detach(int cpuid) 23767c478bd9Sstevel@tonic-gate { 23777c478bd9Sstevel@tonic-gate /* 23787c478bd9Sstevel@tonic-gate * Cpu may not be under OBP's control. Eg, if cpu exited to download 23797c478bd9Sstevel@tonic-gate * helper on a prior attach. 23807c478bd9Sstevel@tonic-gate */ 23817c478bd9Sstevel@tonic-gate if (CPU_SGN_EXISTS(cpuid) && 23827c478bd9Sstevel@tonic-gate !SGN_CPU_IS_OS(cpuid) && 23837c478bd9Sstevel@tonic-gate !SGN_CPU_IS_OBP(cpuid)) { 23847c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 23857c478bd9Sstevel@tonic-gate "unexpected signature (0x%x) for cpu %d", 23867c478bd9Sstevel@tonic-gate get_cpu_sgn(cpuid), cpuid); 23877c478bd9Sstevel@tonic-gate } 23887c478bd9Sstevel@tonic-gate 23897c478bd9Sstevel@tonic-gate /* 23907c478bd9Sstevel@tonic-gate * Now we place the CPU into the "Detached" idle loop in OBP. 23917c478bd9Sstevel@tonic-gate * This is so that the CPU won't be restarted if we break into 23927c478bd9Sstevel@tonic-gate * OBP with a breakpoint or BREAK key from the console, and also 23937c478bd9Sstevel@tonic-gate * if we need to do any special processing, such as flushing the 23947c478bd9Sstevel@tonic-gate * cpu's ecache, disabling interrupts (by turning of the ET bit in 23957c478bd9Sstevel@tonic-gate * the PSR) and/or spinning in BBSRAM rather than global memory. 23967c478bd9Sstevel@tonic-gate */ 23977c478bd9Sstevel@tonic-gate DRMACH_PR("prom_starfire_rm_cpu(%d)\n", cpuid); 23987c478bd9Sstevel@tonic-gate prom_starfire_rm_cpu(cpuid); 23997c478bd9Sstevel@tonic-gate } 24007c478bd9Sstevel@tonic-gate 24017c478bd9Sstevel@tonic-gate /* 24027c478bd9Sstevel@tonic-gate * drmach_cpu_obp_is_detached() returns TRUE if the cpu sigblock signature state 24037c478bd9Sstevel@tonic-gate * is SIGBST_DETACHED; otherwise it returns FALSE. This routine should only 24047c478bd9Sstevel@tonic-gate * be called after we have asked OBP to detach the CPU. It should NOT be 24057c478bd9Sstevel@tonic-gate * called as a check during any other flow. 24067c478bd9Sstevel@tonic-gate */ 24077c478bd9Sstevel@tonic-gate static int 24087c478bd9Sstevel@tonic-gate drmach_cpu_obp_is_detached(int cpuid) 24097c478bd9Sstevel@tonic-gate { 24107c478bd9Sstevel@tonic-gate if (!CPU_SGN_EXISTS(cpuid) || 24117c478bd9Sstevel@tonic-gate (SGN_CPU_IS_OS(cpuid) && SGN_CPU_STATE_IS_DETACHED(cpuid))) 24127c478bd9Sstevel@tonic-gate return (1); 24137c478bd9Sstevel@tonic-gate else 24147c478bd9Sstevel@tonic-gate return (0); 24157c478bd9Sstevel@tonic-gate } 24167c478bd9Sstevel@tonic-gate 24177c478bd9Sstevel@tonic-gate static int 24187c478bd9Sstevel@tonic-gate drmach_cpu_start(struct cpu *cp) 24197c478bd9Sstevel@tonic-gate { 24207c478bd9Sstevel@tonic-gate int cpuid = cp->cpu_id; 24217c478bd9Sstevel@tonic-gate int ntries = drmach_cpu_ntries; 24227c478bd9Sstevel@tonic-gate extern void restart_other_cpu(int); 24237c478bd9Sstevel@tonic-gate 24247c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 2425fa9e4066Sahrens ASSERT(cpunodes[cpuid].nodeid != (pnode_t)0); 24267c478bd9Sstevel@tonic-gate 24277c478bd9Sstevel@tonic-gate cp->cpu_flags &= ~CPU_POWEROFF; 24287c478bd9Sstevel@tonic-gate 24297c478bd9Sstevel@tonic-gate /* 24307c478bd9Sstevel@tonic-gate * NOTE: restart_other_cpu pauses cpus during the 24317c478bd9Sstevel@tonic-gate * slave cpu start. This helps to quiesce the 24327c478bd9Sstevel@tonic-gate * bus traffic a bit which makes the tick sync 24337c478bd9Sstevel@tonic-gate * routine in the prom more robust. 24347c478bd9Sstevel@tonic-gate */ 24357c478bd9Sstevel@tonic-gate DRMACH_PR("COLD START for cpu (%d)\n", cpuid); 24367c478bd9Sstevel@tonic-gate 24377c478bd9Sstevel@tonic-gate prom_starfire_add_cpu(cpuid); 24387c478bd9Sstevel@tonic-gate 24397c478bd9Sstevel@tonic-gate restart_other_cpu(cpuid); 24407c478bd9Sstevel@tonic-gate 24417c478bd9Sstevel@tonic-gate /* 24427c478bd9Sstevel@tonic-gate * Wait for the cpu to reach its idle thread before 24437c478bd9Sstevel@tonic-gate * we zap him with a request to blow away the mappings 24447c478bd9Sstevel@tonic-gate * he (might) have for the drmach_shutdown_asm code 24457c478bd9Sstevel@tonic-gate * he may have executed on unconfigure. 24467c478bd9Sstevel@tonic-gate */ 24477c478bd9Sstevel@tonic-gate while ((cp->cpu_thread != cp->cpu_idle_thread) && (ntries > 0)) { 24487c478bd9Sstevel@tonic-gate DELAY(drmach_cpu_delay); 24497c478bd9Sstevel@tonic-gate ntries--; 24507c478bd9Sstevel@tonic-gate } 24517c478bd9Sstevel@tonic-gate 24527c478bd9Sstevel@tonic-gate DRMACH_PR("waited %d out of %d loops for cpu %d\n", 24537c478bd9Sstevel@tonic-gate drmach_cpu_ntries - ntries, drmach_cpu_ntries, cpuid); 24547c478bd9Sstevel@tonic-gate 24557c478bd9Sstevel@tonic-gate xt_one(cpuid, vtag_flushpage_tl1, 24561e2e7a75Shuah (uint64_t)drmach_shutdown_va, (uint64_t)ksfmmup); 24577c478bd9Sstevel@tonic-gate 24587c478bd9Sstevel@tonic-gate return (0); 24597c478bd9Sstevel@tonic-gate } 24607c478bd9Sstevel@tonic-gate 24617c478bd9Sstevel@tonic-gate /* 24627c478bd9Sstevel@tonic-gate * A detaching CPU is xcalled with an xtrap to drmach_cpu_stop_self() after 24637c478bd9Sstevel@tonic-gate * it has been offlined. The function of this routine is to get the cpu 24647c478bd9Sstevel@tonic-gate * spinning in a safe place. The requirement is that the system will not 24657c478bd9Sstevel@tonic-gate * reference anything on the detaching board (memory and i/o is detached 24667c478bd9Sstevel@tonic-gate * elsewhere) and that the CPU not reference anything on any other board 24677c478bd9Sstevel@tonic-gate * in the system. This isolation is required during and after the writes 24687c478bd9Sstevel@tonic-gate * to the domain masks to remove the board from the domain. 24697c478bd9Sstevel@tonic-gate * 24707c478bd9Sstevel@tonic-gate * To accomplish this isolation the following is done: 24717c478bd9Sstevel@tonic-gate * 1) Create a locked mapping to a location in BBSRAM where 24727c478bd9Sstevel@tonic-gate * the cpu will execute. 24737c478bd9Sstevel@tonic-gate * 2) Copy the target function (drmach_shutdown_asm) in which 24747c478bd9Sstevel@tonic-gate * the cpu will execute into BBSRAM. 24757c478bd9Sstevel@tonic-gate * 3) Jump into function with BBSRAM. 24767c478bd9Sstevel@tonic-gate * Function will: 24777c478bd9Sstevel@tonic-gate * 3.1) Flush its Ecache (displacement). 24787c478bd9Sstevel@tonic-gate * 3.2) Flush its Dcache with HW mechanism. 24797c478bd9Sstevel@tonic-gate * 3.3) Flush its Icache with HW mechanism. 24807c478bd9Sstevel@tonic-gate * 3.4) Flush all valid and _unlocked_ D-TLB entries. 24817c478bd9Sstevel@tonic-gate * 3.5) Flush all valid and _unlocked_ I-TLB entries. 24827c478bd9Sstevel@tonic-gate * 3.6) Clear xt_mb to signal completion. Note: cache line is 24837c478bd9Sstevel@tonic-gate * recovered by drmach_cpu_poweroff(). 24847c478bd9Sstevel@tonic-gate * 4) Jump into a tight loop. 24857c478bd9Sstevel@tonic-gate */ 24867c478bd9Sstevel@tonic-gate #define DRMACH_BBSRAM_OFFSET 0x1000 24877c478bd9Sstevel@tonic-gate 24887c478bd9Sstevel@tonic-gate static void 24897c478bd9Sstevel@tonic-gate drmach_cpu_stop_self(void) 24907c478bd9Sstevel@tonic-gate { 24917c478bd9Sstevel@tonic-gate int cpuid = (int)CPU->cpu_id; 24927c478bd9Sstevel@tonic-gate tte_t tte; 24937c478bd9Sstevel@tonic-gate volatile uint_t *src, *dst; 2494*e0731422SRichard Lowe size_t funclen; 24957c478bd9Sstevel@tonic-gate uint64_t bbsram_pa, bbsram_offset; 24967c478bd9Sstevel@tonic-gate uint_t bbsram_pfn; 24977c478bd9Sstevel@tonic-gate uint64_t bbsram_addr; 24987c478bd9Sstevel@tonic-gate void (*bbsram_func)(uint64_t); 24997c478bd9Sstevel@tonic-gate extern void drmach_shutdown_asm(uint64_t); 25007c478bd9Sstevel@tonic-gate extern void drmach_shutdown_asm_end(void); 25017c478bd9Sstevel@tonic-gate 2502*e0731422SRichard Lowe funclen = (uintptr_t)drmach_shutdown_asm_end - 2503*e0731422SRichard Lowe (uintptr_t)drmach_shutdown_asm; 25047c478bd9Sstevel@tonic-gate ASSERT(funclen <= MMU_PAGESIZE); 25057c478bd9Sstevel@tonic-gate /* 25067c478bd9Sstevel@tonic-gate * We'll start from the 0th's base. 25077c478bd9Sstevel@tonic-gate */ 25087c478bd9Sstevel@tonic-gate bbsram_pa = STARFIRE_UPAID2UPS(cpuid) | STARFIRE_PSI_BASE; 25097c478bd9Sstevel@tonic-gate bbsram_offset = bbsram_pa | 0xfe0ULL; 25107c478bd9Sstevel@tonic-gate bbsram_pa += ldphysio(bbsram_offset) + DRMACH_BBSRAM_OFFSET; 25117c478bd9Sstevel@tonic-gate 25127c478bd9Sstevel@tonic-gate bbsram_pfn = (uint_t)(bbsram_pa >> MMU_PAGESHIFT); 25137c478bd9Sstevel@tonic-gate 25147c478bd9Sstevel@tonic-gate bbsram_addr = (uint64_t)drmach_shutdown_va; 2515*e0731422SRichard Lowe drmach_shutdown_asm_mbox->estack = bbsram_addr + funclen; 25167c478bd9Sstevel@tonic-gate 25177c478bd9Sstevel@tonic-gate tte.tte_inthi = TTE_VALID_INT | TTE_SZ_INT(TTE8K) | 25187c478bd9Sstevel@tonic-gate TTE_PFN_INTHI(bbsram_pfn); 25197c478bd9Sstevel@tonic-gate tte.tte_intlo = TTE_PFN_INTLO(bbsram_pfn) | 25207c478bd9Sstevel@tonic-gate TTE_HWWR_INT | TTE_PRIV_INT | TTE_LCK_INT; 25211e2e7a75Shuah sfmmu_dtlb_ld_kva(drmach_shutdown_va, &tte); /* load dtlb */ 25221e2e7a75Shuah sfmmu_itlb_ld_kva(drmach_shutdown_va, &tte); /* load itlb */ 25237c478bd9Sstevel@tonic-gate 25247c478bd9Sstevel@tonic-gate for (src = (uint_t *)drmach_shutdown_asm, dst = (uint_t *)bbsram_addr; 25257c478bd9Sstevel@tonic-gate src < (uint_t *)drmach_shutdown_asm_end; src++, dst++) 25267c478bd9Sstevel@tonic-gate *dst = *src; 25277c478bd9Sstevel@tonic-gate 25287c478bd9Sstevel@tonic-gate bbsram_func = (void (*)())bbsram_addr; 25297c478bd9Sstevel@tonic-gate drmach_shutdown_asm_mbox->flushaddr = ecache_flushaddr; 25307c478bd9Sstevel@tonic-gate drmach_shutdown_asm_mbox->size = (cpunodes[cpuid].ecache_size << 1); 25317c478bd9Sstevel@tonic-gate drmach_shutdown_asm_mbox->linesize = cpunodes[cpuid].ecache_linesize; 253256f33205SJonathan Adams drmach_shutdown_asm_mbox->physaddr = 253356f33205SJonathan Adams va_to_pa((void *)&drmach_xt_mb[cpuid]); 25347c478bd9Sstevel@tonic-gate 25357c478bd9Sstevel@tonic-gate /* 25367c478bd9Sstevel@tonic-gate * Signal to drmach_cpu_poweroff() is via drmach_xt_mb cleared 25377c478bd9Sstevel@tonic-gate * by asm code 25387c478bd9Sstevel@tonic-gate */ 25397c478bd9Sstevel@tonic-gate 25407c478bd9Sstevel@tonic-gate (*bbsram_func)(va_to_pa((void *)drmach_shutdown_asm_mbox)); 25417c478bd9Sstevel@tonic-gate } 25427c478bd9Sstevel@tonic-gate 25437c478bd9Sstevel@tonic-gate static void 25447c478bd9Sstevel@tonic-gate drmach_cpu_shutdown_self(void) 25457c478bd9Sstevel@tonic-gate { 25467c478bd9Sstevel@tonic-gate cpu_t *cp = CPU; 25477c478bd9Sstevel@tonic-gate int cpuid = cp->cpu_id; 25487c478bd9Sstevel@tonic-gate extern void flush_windows(void); 25497c478bd9Sstevel@tonic-gate 25507c478bd9Sstevel@tonic-gate flush_windows(); 25517c478bd9Sstevel@tonic-gate 25527c478bd9Sstevel@tonic-gate (void) spl8(); 25537c478bd9Sstevel@tonic-gate 25547c478bd9Sstevel@tonic-gate ASSERT(cp->cpu_intr_actv == 0); 25559d7041eeSandrei ASSERT(cp->cpu_thread == cp->cpu_idle_thread || 25569d7041eeSandrei cp->cpu_thread == cp->cpu_startup_thread); 25577c478bd9Sstevel@tonic-gate 25587c478bd9Sstevel@tonic-gate cp->cpu_flags = CPU_OFFLINE | CPU_QUIESCED | CPU_POWEROFF; 25597c478bd9Sstevel@tonic-gate 25607c478bd9Sstevel@tonic-gate drmach_cpu_stop_self(); 25617c478bd9Sstevel@tonic-gate 25627c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "CPU %d FAILED TO SHUTDOWN", cpuid); 25637c478bd9Sstevel@tonic-gate } 25647c478bd9Sstevel@tonic-gate 25657c478bd9Sstevel@tonic-gate /* a helper routine to keep the math in one place */ 25667c478bd9Sstevel@tonic-gate static processorid_t 25677c478bd9Sstevel@tonic-gate drmach_cpu_calc_id(drmach_device_t *dp) 25687c478bd9Sstevel@tonic-gate { 25697c478bd9Sstevel@tonic-gate return (dp->bp->bnum * MAX_CPU_UNITS_PER_BOARD + dp->unum); 25707c478bd9Sstevel@tonic-gate } 25717c478bd9Sstevel@tonic-gate 25727c478bd9Sstevel@tonic-gate /* 25737c478bd9Sstevel@tonic-gate * Move bootproc (SIGBCPU) to another cpu. If dst_cpu is NULL, a 25747c478bd9Sstevel@tonic-gate * destination cpu is chosen from the set of cpus not located on the 25757c478bd9Sstevel@tonic-gate * same board as the current bootproc cpu. 25767c478bd9Sstevel@tonic-gate */ 25777c478bd9Sstevel@tonic-gate static sbd_error_t * 25787c478bd9Sstevel@tonic-gate drmach_cpu_juggle_bootproc(drmach_device_t *dst_cpu) 25797c478bd9Sstevel@tonic-gate { 25807c478bd9Sstevel@tonic-gate processorid_t cpuid; 25817c478bd9Sstevel@tonic-gate struct cpu *cp; 25827c478bd9Sstevel@tonic-gate sbd_error_t *err; 25837c478bd9Sstevel@tonic-gate int rv; 25847c478bd9Sstevel@tonic-gate 25857c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 25867c478bd9Sstevel@tonic-gate 25877c478bd9Sstevel@tonic-gate /* dst_cpu is NULL when target cpu is unspecified. So, pick one. */ 25887c478bd9Sstevel@tonic-gate if (dst_cpu == NULL) { 25897c478bd9Sstevel@tonic-gate int avoid_board = DRMACH_CPUID2BNUM(SIGBCPU->cpu_id); 25907c478bd9Sstevel@tonic-gate int max_cpuid = MAX_BOARDS * MAX_CPU_UNITS_PER_BOARD; 25917c478bd9Sstevel@tonic-gate 25927c478bd9Sstevel@tonic-gate for (cpuid = 0; cpuid < max_cpuid; cpuid++) 25937c478bd9Sstevel@tonic-gate if (DRMACH_CPUID2BNUM(cpuid) != avoid_board) { 25947c478bd9Sstevel@tonic-gate cp = cpu_get(cpuid); 25957c478bd9Sstevel@tonic-gate if (cp != NULL && cpu_is_online(cp)) 25967c478bd9Sstevel@tonic-gate break; 25977c478bd9Sstevel@tonic-gate } 25987c478bd9Sstevel@tonic-gate 25997c478bd9Sstevel@tonic-gate if (cpuid == max_cpuid) { 26007c478bd9Sstevel@tonic-gate err = drerr_new(1, ESTF_JUGGLE, NULL); 26017c478bd9Sstevel@tonic-gate return (err); 26027c478bd9Sstevel@tonic-gate } 26037c478bd9Sstevel@tonic-gate 26047c478bd9Sstevel@tonic-gate /* else, cp points to the selected target cpu */ 26057c478bd9Sstevel@tonic-gate } else { 26067c478bd9Sstevel@tonic-gate cpuid = drmach_cpu_calc_id(dst_cpu); 26077c478bd9Sstevel@tonic-gate 26087c478bd9Sstevel@tonic-gate if ((cp = cpu_get(cpuid)) == NULL) { 26097c478bd9Sstevel@tonic-gate err = drerr_new(1, ESTF_NODEV, "%s::%s", 26107c478bd9Sstevel@tonic-gate dst_cpu->bp->cm.name, dst_cpu->cm.name); 26117c478bd9Sstevel@tonic-gate return (err); 26127c478bd9Sstevel@tonic-gate } 26137c478bd9Sstevel@tonic-gate 26147c478bd9Sstevel@tonic-gate if (cpuid == SIGBCPU->cpu_id) { 26157c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 26167c478bd9Sstevel@tonic-gate "SIGBCPU(%d) same as new selection(%d)", 26177c478bd9Sstevel@tonic-gate SIGBCPU->cpu_id, cpuid); 26187c478bd9Sstevel@tonic-gate 26197c478bd9Sstevel@tonic-gate /* technically not an error, but a no-op */ 26207c478bd9Sstevel@tonic-gate return (NULL); 26217c478bd9Sstevel@tonic-gate } 26227c478bd9Sstevel@tonic-gate } 26237c478bd9Sstevel@tonic-gate 26247c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "?relocating SIGBCPU from %d to %d", 26257c478bd9Sstevel@tonic-gate SIGBCPU->cpu_id, cpuid); 26267c478bd9Sstevel@tonic-gate 26277c478bd9Sstevel@tonic-gate DRMACH_PR("moving SIGBCPU to CPU %d\n", cpuid); 26287c478bd9Sstevel@tonic-gate 26297c478bd9Sstevel@tonic-gate /* 26307c478bd9Sstevel@tonic-gate * Tell OBP to initialize cvc-offset field of new CPU0 26317c478bd9Sstevel@tonic-gate * so that it's in sync with OBP and cvc_server 26327c478bd9Sstevel@tonic-gate */ 26337c478bd9Sstevel@tonic-gate prom_starfire_init_console(cpuid); 26347c478bd9Sstevel@tonic-gate 26357c478bd9Sstevel@tonic-gate /* 26367c478bd9Sstevel@tonic-gate * Assign cvc to new cpu0's bbsram for I/O. This has to be 26377c478bd9Sstevel@tonic-gate * done BEFORE cpu0 is moved via obp, since this logic 26387c478bd9Sstevel@tonic-gate * will cause obp_helper to switch to a different bbsram for 26397c478bd9Sstevel@tonic-gate * cvc I/O. We don't want cvc writing to a buffer from which 26407c478bd9Sstevel@tonic-gate * nobody will pick up the data! 26417c478bd9Sstevel@tonic-gate */ 26427c478bd9Sstevel@tonic-gate cvc_assign_iocpu(cpuid); 26437c478bd9Sstevel@tonic-gate 26447c478bd9Sstevel@tonic-gate rv = prom_starfire_move_cpu0(cpuid); 26457c478bd9Sstevel@tonic-gate 26467c478bd9Sstevel@tonic-gate if (rv == 0) { 26477c478bd9Sstevel@tonic-gate SIGBCPU = cp; 26487c478bd9Sstevel@tonic-gate 26497c478bd9Sstevel@tonic-gate DRMACH_PR("successfully juggled to CPU %d\n", cpuid); 26507c478bd9Sstevel@tonic-gate return (NULL); 26517c478bd9Sstevel@tonic-gate } else { 26527c478bd9Sstevel@tonic-gate DRMACH_PR("prom error: prom_starfire_move_cpu0(%d) " 26537c478bd9Sstevel@tonic-gate "returned %d\n", cpuid, rv); 26547c478bd9Sstevel@tonic-gate 26557c478bd9Sstevel@tonic-gate /* 26567c478bd9Sstevel@tonic-gate * The move failed, hopefully obp_helper is still back 26577c478bd9Sstevel@tonic-gate * at the old bootproc. Move cvc back there. 26587c478bd9Sstevel@tonic-gate */ 26597c478bd9Sstevel@tonic-gate cvc_assign_iocpu(SIGBCPU->cpu_id); 26607c478bd9Sstevel@tonic-gate 26617c478bd9Sstevel@tonic-gate 26627c478bd9Sstevel@tonic-gate err = drerr_new(1, ESTF_MOVESIGB, "CPU %d", cpuid); 26637c478bd9Sstevel@tonic-gate return (err); 26647c478bd9Sstevel@tonic-gate } 26657c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 26667c478bd9Sstevel@tonic-gate } 26677c478bd9Sstevel@tonic-gate 26687c478bd9Sstevel@tonic-gate static sbd_error_t * 26697c478bd9Sstevel@tonic-gate drmach_cpu_release(drmachid_t id) 26707c478bd9Sstevel@tonic-gate { 26717c478bd9Sstevel@tonic-gate drmach_device_t *dp; 26727c478bd9Sstevel@tonic-gate processorid_t cpuid; 26737c478bd9Sstevel@tonic-gate struct cpu *cp; 26747c478bd9Sstevel@tonic-gate sbd_error_t *err; 26757c478bd9Sstevel@tonic-gate 26767c478bd9Sstevel@tonic-gate if (!DRMACH_IS_CPU_ID(id)) 26777c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 26787c478bd9Sstevel@tonic-gate dp = id; 26797c478bd9Sstevel@tonic-gate cpuid = drmach_cpu_calc_id(dp); 26807c478bd9Sstevel@tonic-gate 26817c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 26827c478bd9Sstevel@tonic-gate 26837c478bd9Sstevel@tonic-gate cp = cpu_get(cpuid); 26847c478bd9Sstevel@tonic-gate if (cp == NULL) 26857c478bd9Sstevel@tonic-gate err = DRMACH_INTERNAL_ERROR(); 26867c478bd9Sstevel@tonic-gate else if (SIGBCPU->cpu_id == cp->cpu_id) 26877c478bd9Sstevel@tonic-gate err = drmach_cpu_juggle_bootproc(NULL); 26887c478bd9Sstevel@tonic-gate else 26897c478bd9Sstevel@tonic-gate err = NULL; 26907c478bd9Sstevel@tonic-gate 26917c478bd9Sstevel@tonic-gate return (err); 26927c478bd9Sstevel@tonic-gate } 26937c478bd9Sstevel@tonic-gate 26947c478bd9Sstevel@tonic-gate static sbd_error_t * 26957c478bd9Sstevel@tonic-gate drmach_cpu_status(drmachid_t id, drmach_status_t *stat) 26967c478bd9Sstevel@tonic-gate { 26977c478bd9Sstevel@tonic-gate drmach_device_t *dp; 26987c478bd9Sstevel@tonic-gate 26997c478bd9Sstevel@tonic-gate ASSERT(DRMACH_IS_CPU_ID(id)); 27007c478bd9Sstevel@tonic-gate dp = id; 27017c478bd9Sstevel@tonic-gate 27027c478bd9Sstevel@tonic-gate stat->assigned = dp->bp->assigned; 27037c478bd9Sstevel@tonic-gate stat->powered = dp->bp->powered; 27047c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock); 27057c478bd9Sstevel@tonic-gate stat->configured = (cpu_get(drmach_cpu_calc_id(dp)) != NULL); 27067c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock); 27077c478bd9Sstevel@tonic-gate stat->busy = dp->busy; 270807d06da5SSurya Prakki (void) strncpy(stat->type, dp->type, sizeof (stat->type)); 27097c478bd9Sstevel@tonic-gate stat->info[0] = '\0'; 27107c478bd9Sstevel@tonic-gate 27117c478bd9Sstevel@tonic-gate return (NULL); 27127c478bd9Sstevel@tonic-gate } 27137c478bd9Sstevel@tonic-gate 27147c478bd9Sstevel@tonic-gate sbd_error_t * 27157c478bd9Sstevel@tonic-gate drmach_cpu_disconnect(drmachid_t id) 27167c478bd9Sstevel@tonic-gate { 27177c478bd9Sstevel@tonic-gate drmach_device_t *cpu; 27187c478bd9Sstevel@tonic-gate int cpuid; 27197c478bd9Sstevel@tonic-gate int ntries; 27207c478bd9Sstevel@tonic-gate int p; 27217c478bd9Sstevel@tonic-gate u_longlong_t pc_addr; 27227c478bd9Sstevel@tonic-gate uchar_t rvalue; 27237c478bd9Sstevel@tonic-gate 27247c478bd9Sstevel@tonic-gate if (!DRMACH_IS_CPU_ID(id)) 27257c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 27267c478bd9Sstevel@tonic-gate cpu = id; 27277c478bd9Sstevel@tonic-gate 27287c478bd9Sstevel@tonic-gate cpuid = drmach_cpu_calc_id(cpu); 27297c478bd9Sstevel@tonic-gate if (SIGBCPU->cpu_id == cpuid) { 27307c478bd9Sstevel@tonic-gate /* this cpu is SIGBCPU, can't disconnect */ 27317c478bd9Sstevel@tonic-gate return (drerr_new(1, ESTF_HASSIGB, "%s::%s", 27327c478bd9Sstevel@tonic-gate cpu->bp->cm.name, cpu->cm.name)); 27337c478bd9Sstevel@tonic-gate } 27347c478bd9Sstevel@tonic-gate 27357c478bd9Sstevel@tonic-gate /* 27367c478bd9Sstevel@tonic-gate * Make sure SIGBST_DETACHED is set before 27377c478bd9Sstevel@tonic-gate * mapping out the sig block. 27387c478bd9Sstevel@tonic-gate */ 27397c478bd9Sstevel@tonic-gate ntries = drmach_cpu_ntries; 27407c478bd9Sstevel@tonic-gate while (!drmach_cpu_obp_is_detached(cpuid) && ntries) { 27417c478bd9Sstevel@tonic-gate DELAY(drmach_cpu_delay); 27427c478bd9Sstevel@tonic-gate ntries--; 27437c478bd9Sstevel@tonic-gate } 27447c478bd9Sstevel@tonic-gate if (!drmach_cpu_obp_is_detached(cpuid)) { 27457c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "failed to mark cpu %d detached in sigblock", 27467c478bd9Sstevel@tonic-gate cpuid); 27477c478bd9Sstevel@tonic-gate } 27487c478bd9Sstevel@tonic-gate 27497c478bd9Sstevel@tonic-gate /* map out signature block */ 27507c478bd9Sstevel@tonic-gate if (CPU_SGN_EXISTS(cpuid)) { 27517c478bd9Sstevel@tonic-gate CPU_SGN_MAPOUT(cpuid); 27527c478bd9Sstevel@tonic-gate } 27537c478bd9Sstevel@tonic-gate 27547c478bd9Sstevel@tonic-gate /* 27557c478bd9Sstevel@tonic-gate * We now PC IDLE the processor to guarantee we 27567c478bd9Sstevel@tonic-gate * stop any transactions from coming from it. 27577c478bd9Sstevel@tonic-gate */ 27587c478bd9Sstevel@tonic-gate p = cpu->unum & 1; 27597c478bd9Sstevel@tonic-gate pc_addr = STARFIRE_BB_PC_ADDR(cpu->bp->bnum, cpu->unum, 0); 27607c478bd9Sstevel@tonic-gate 27617c478bd9Sstevel@tonic-gate DRMACH_PR("PC idle cpu %d (addr = 0x%llx, port = %d, p = %d)", 27627c478bd9Sstevel@tonic-gate drmach_cpu_calc_id(cpu), pc_addr, cpu->unum, p); 27637c478bd9Sstevel@tonic-gate 27647c478bd9Sstevel@tonic-gate rvalue = ldbphysio(pc_addr); 27657c478bd9Sstevel@tonic-gate rvalue |= STARFIRE_BB_PC_IDLE(p); 27667c478bd9Sstevel@tonic-gate stbphysio(pc_addr, rvalue); 27677c478bd9Sstevel@tonic-gate DELAY(50000); 27687c478bd9Sstevel@tonic-gate 27697c478bd9Sstevel@tonic-gate return (NULL); 27707c478bd9Sstevel@tonic-gate } 27717c478bd9Sstevel@tonic-gate 27727c478bd9Sstevel@tonic-gate sbd_error_t * 27737c478bd9Sstevel@tonic-gate drmach_cpu_get_id(drmachid_t id, processorid_t *cpuid) 27747c478bd9Sstevel@tonic-gate { 27757c478bd9Sstevel@tonic-gate drmach_device_t *cpu; 27767c478bd9Sstevel@tonic-gate 27777c478bd9Sstevel@tonic-gate if (!DRMACH_IS_CPU_ID(id)) 27787c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 27797c478bd9Sstevel@tonic-gate cpu = id; 27807c478bd9Sstevel@tonic-gate 27817c478bd9Sstevel@tonic-gate *cpuid = drmach_cpu_calc_id(cpu); 27827c478bd9Sstevel@tonic-gate return (NULL); 27837c478bd9Sstevel@tonic-gate } 27847c478bd9Sstevel@tonic-gate 27857c478bd9Sstevel@tonic-gate sbd_error_t * 27867c478bd9Sstevel@tonic-gate drmach_cpu_get_impl(drmachid_t id, int *ip) 27877c478bd9Sstevel@tonic-gate { 27887c478bd9Sstevel@tonic-gate drmach_device_t *cpu; 27897c478bd9Sstevel@tonic-gate int impl; 27907c478bd9Sstevel@tonic-gate 27917c478bd9Sstevel@tonic-gate if (!DRMACH_IS_CPU_ID(id)) 27927c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 27937c478bd9Sstevel@tonic-gate 27947c478bd9Sstevel@tonic-gate cpu = id; 27957c478bd9Sstevel@tonic-gate 27967c478bd9Sstevel@tonic-gate if (drmach_node_get_prop(cpu->node, "implementation#", &impl) == -1) { 27977c478bd9Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 27987c478bd9Sstevel@tonic-gate } 27997c478bd9Sstevel@tonic-gate 28007c478bd9Sstevel@tonic-gate *ip = impl; 28017c478bd9Sstevel@tonic-gate 28027c478bd9Sstevel@tonic-gate return (NULL); 28037c478bd9Sstevel@tonic-gate } 28047c478bd9Sstevel@tonic-gate 28057c478bd9Sstevel@tonic-gate void 28067c478bd9Sstevel@tonic-gate drmach_cpu_flush_ecache_sync(void) 28077c478bd9Sstevel@tonic-gate { 28087c478bd9Sstevel@tonic-gate ASSERT(curthread->t_bound_cpu == CPU); 28097c478bd9Sstevel@tonic-gate 28107c478bd9Sstevel@tonic-gate /* 28117c478bd9Sstevel@tonic-gate * Now let's flush our ecache thereby removing all references 28127c478bd9Sstevel@tonic-gate * to the target (detaching) memory from all ecache's in 28137c478bd9Sstevel@tonic-gate * system. 28147c478bd9Sstevel@tonic-gate */ 28157c478bd9Sstevel@tonic-gate cpu_flush_ecache(); 28167c478bd9Sstevel@tonic-gate 28177c478bd9Sstevel@tonic-gate /* 28187c478bd9Sstevel@tonic-gate * Delay 100 usec out of paranoia to insure everything 28197c478bd9Sstevel@tonic-gate * (hardware queues) has drained before we start reprogramming 28207c478bd9Sstevel@tonic-gate * the hardware. 28217c478bd9Sstevel@tonic-gate */ 28227c478bd9Sstevel@tonic-gate DELAY(100); 28237c478bd9Sstevel@tonic-gate } 28247c478bd9Sstevel@tonic-gate 28257c478bd9Sstevel@tonic-gate sbd_error_t * 28267c478bd9Sstevel@tonic-gate drmach_get_dip(drmachid_t id, dev_info_t **dip) 28277c478bd9Sstevel@tonic-gate { 28287c478bd9Sstevel@tonic-gate drmach_device_t *dp; 28297c478bd9Sstevel@tonic-gate 28307c478bd9Sstevel@tonic-gate if (!DRMACH_IS_DEVICE_ID(id)) 28317c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 28327c478bd9Sstevel@tonic-gate dp = id; 28337c478bd9Sstevel@tonic-gate 28347c478bd9Sstevel@tonic-gate *dip = drmach_node_get_dip(dp->node); 28357c478bd9Sstevel@tonic-gate return (NULL); 28367c478bd9Sstevel@tonic-gate } 28377c478bd9Sstevel@tonic-gate 28387c478bd9Sstevel@tonic-gate sbd_error_t * 28397c478bd9Sstevel@tonic-gate drmach_io_is_attached(drmachid_t id, int *yes) 28407c478bd9Sstevel@tonic-gate { 28417c478bd9Sstevel@tonic-gate drmach_device_t *dp; 28427c478bd9Sstevel@tonic-gate dev_info_t *dip; 28437c478bd9Sstevel@tonic-gate int state; 28447c478bd9Sstevel@tonic-gate 28457c478bd9Sstevel@tonic-gate if (!DRMACH_IS_IO_ID(id)) 28467c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 28477c478bd9Sstevel@tonic-gate dp = id; 28487c478bd9Sstevel@tonic-gate 28497c478bd9Sstevel@tonic-gate dip = drmach_node_get_dip(dp->node); 28507c478bd9Sstevel@tonic-gate if (dip == NULL) { 28517c478bd9Sstevel@tonic-gate *yes = 0; 28527c478bd9Sstevel@tonic-gate return (NULL); 28537c478bd9Sstevel@tonic-gate } 28547c478bd9Sstevel@tonic-gate 28557c478bd9Sstevel@tonic-gate state = ddi_get_devstate(dip); 2856737d277aScth *yes = (i_ddi_devi_attached(dip) || (state == DDI_DEVSTATE_UP)); 28577c478bd9Sstevel@tonic-gate 28587c478bd9Sstevel@tonic-gate return (NULL); 28597c478bd9Sstevel@tonic-gate } 28607c478bd9Sstevel@tonic-gate 28617c478bd9Sstevel@tonic-gate sbd_error_t * 28627c478bd9Sstevel@tonic-gate drmach_io_pre_release(drmachid_t id) 28637c478bd9Sstevel@tonic-gate { 28647c478bd9Sstevel@tonic-gate if (!DRMACH_IS_IO_ID(id)) 28657c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 28667c478bd9Sstevel@tonic-gate return (NULL); 28677c478bd9Sstevel@tonic-gate } 28687c478bd9Sstevel@tonic-gate 28697c478bd9Sstevel@tonic-gate static sbd_error_t * 28707c478bd9Sstevel@tonic-gate drmach_io_release(drmachid_t id) 28717c478bd9Sstevel@tonic-gate { 28727c478bd9Sstevel@tonic-gate if (!DRMACH_IS_IO_ID(id)) 28737c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 28747c478bd9Sstevel@tonic-gate return (NULL); 28757c478bd9Sstevel@tonic-gate } 28767c478bd9Sstevel@tonic-gate 28777c478bd9Sstevel@tonic-gate sbd_error_t * 28787c478bd9Sstevel@tonic-gate drmach_io_unrelease(drmachid_t id) 28797c478bd9Sstevel@tonic-gate { 28807c478bd9Sstevel@tonic-gate if (!DRMACH_IS_IO_ID(id)) 28817c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 28827c478bd9Sstevel@tonic-gate return (NULL); 28837c478bd9Sstevel@tonic-gate } 28847c478bd9Sstevel@tonic-gate 28857c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 28867c478bd9Sstevel@tonic-gate sbd_error_t * 28877c478bd9Sstevel@tonic-gate drmach_io_post_release(drmachid_t id) 28887c478bd9Sstevel@tonic-gate { 28897c478bd9Sstevel@tonic-gate return (NULL); 28907c478bd9Sstevel@tonic-gate } 28917c478bd9Sstevel@tonic-gate 28927c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 28937c478bd9Sstevel@tonic-gate sbd_error_t * 28947c478bd9Sstevel@tonic-gate drmach_io_post_attach(drmachid_t id) 28957c478bd9Sstevel@tonic-gate { 28967c478bd9Sstevel@tonic-gate return (NULL); 28977c478bd9Sstevel@tonic-gate } 28987c478bd9Sstevel@tonic-gate 28997c478bd9Sstevel@tonic-gate static sbd_error_t * 29007c478bd9Sstevel@tonic-gate drmach_io_status(drmachid_t id, drmach_status_t *stat) 29017c478bd9Sstevel@tonic-gate { 29027c478bd9Sstevel@tonic-gate drmach_device_t *dp; 29037c478bd9Sstevel@tonic-gate sbd_error_t *err; 29047c478bd9Sstevel@tonic-gate int configured; 29057c478bd9Sstevel@tonic-gate 29067c478bd9Sstevel@tonic-gate ASSERT(DRMACH_IS_IO_ID(id)); 29077c478bd9Sstevel@tonic-gate dp = id; 29087c478bd9Sstevel@tonic-gate 29097c478bd9Sstevel@tonic-gate err = drmach_io_is_attached(id, &configured); 29107c478bd9Sstevel@tonic-gate if (err) 29117c478bd9Sstevel@tonic-gate return (err); 29127c478bd9Sstevel@tonic-gate 29137c478bd9Sstevel@tonic-gate stat->assigned = dp->bp->assigned; 29147c478bd9Sstevel@tonic-gate stat->powered = dp->bp->powered; 29157c478bd9Sstevel@tonic-gate stat->configured = (configured != 0); 29167c478bd9Sstevel@tonic-gate stat->busy = dp->busy; 291707d06da5SSurya Prakki (void) strncpy(stat->type, dp->type, sizeof (stat->type)); 29187c478bd9Sstevel@tonic-gate stat->info[0] = '\0'; 29197c478bd9Sstevel@tonic-gate 29207c478bd9Sstevel@tonic-gate return (NULL); 29217c478bd9Sstevel@tonic-gate } 29227c478bd9Sstevel@tonic-gate 29237c478bd9Sstevel@tonic-gate static sbd_error_t * 29247c478bd9Sstevel@tonic-gate drmach_mem_new(drmach_device_t *dp) 29257c478bd9Sstevel@tonic-gate { 29267c478bd9Sstevel@tonic-gate dp->unum = 0; 29277c478bd9Sstevel@tonic-gate dp->cm.isa = (void *)drmach_mem_new; 29287c478bd9Sstevel@tonic-gate dp->cm.release = drmach_mem_release; 29297c478bd9Sstevel@tonic-gate dp->cm.status = drmach_mem_status; 29307c478bd9Sstevel@tonic-gate 293107d06da5SSurya Prakki (void) snprintf(dp->cm.name, sizeof (dp->cm.name), "%s", dp->type); 29327c478bd9Sstevel@tonic-gate 29337c478bd9Sstevel@tonic-gate return (NULL); 29347c478bd9Sstevel@tonic-gate } 29357c478bd9Sstevel@tonic-gate 29367c478bd9Sstevel@tonic-gate sbd_error_t * 29377c478bd9Sstevel@tonic-gate drmach_mem_add_span(drmachid_t id, uint64_t basepa, uint64_t size) 29387c478bd9Sstevel@tonic-gate { 29397c478bd9Sstevel@tonic-gate pfn_t basepfn = (pfn_t)(basepa >> PAGESHIFT); 29407c478bd9Sstevel@tonic-gate pgcnt_t npages = (pgcnt_t)(size >> PAGESHIFT); 29417c478bd9Sstevel@tonic-gate pda_handle_t ph; 29427c478bd9Sstevel@tonic-gate int rv; 29437c478bd9Sstevel@tonic-gate 29447c478bd9Sstevel@tonic-gate ASSERT(size != 0); 29457c478bd9Sstevel@tonic-gate 29467c478bd9Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(id)) 29477c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 29487c478bd9Sstevel@tonic-gate 294985f58038Sdp78419 rv = kcage_range_add(basepfn, npages, KCAGE_DOWN); 29507c478bd9Sstevel@tonic-gate if (rv == ENOMEM) { 295107d06da5SSurya Prakki cmn_err(CE_WARN, "%lu megabytes not available to kernel cage", 295207d06da5SSurya Prakki (ulong_t)(size == 0 ? 0 : size / MBYTE)); 29537c478bd9Sstevel@tonic-gate } else if (rv != 0) { 29547c478bd9Sstevel@tonic-gate /* catch this in debug kernels */ 29557c478bd9Sstevel@tonic-gate ASSERT(0); 29567c478bd9Sstevel@tonic-gate 29577c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "unexpected kcage_range_add" 29587c478bd9Sstevel@tonic-gate " return value %d", rv); 29597c478bd9Sstevel@tonic-gate } 29607c478bd9Sstevel@tonic-gate 29617c478bd9Sstevel@tonic-gate /* 29627c478bd9Sstevel@tonic-gate * Update the PDA (post2obp) structure with the 29637c478bd9Sstevel@tonic-gate * range of the newly added memory. 29647c478bd9Sstevel@tonic-gate */ 29657c478bd9Sstevel@tonic-gate ph = drmach_pda_open(); 29667c478bd9Sstevel@tonic-gate if (ph != NULL) { 29677c478bd9Sstevel@tonic-gate pda_mem_add_span(ph, basepa, size); 29687c478bd9Sstevel@tonic-gate pda_close(ph); 29697c478bd9Sstevel@tonic-gate } 29707c478bd9Sstevel@tonic-gate 29717c478bd9Sstevel@tonic-gate return (NULL); 29727c478bd9Sstevel@tonic-gate } 29737c478bd9Sstevel@tonic-gate 29747c478bd9Sstevel@tonic-gate sbd_error_t * 29757c478bd9Sstevel@tonic-gate drmach_mem_del_span(drmachid_t id, uint64_t basepa, uint64_t size) 29767c478bd9Sstevel@tonic-gate { 29777c478bd9Sstevel@tonic-gate drmach_device_t *mem = id; 29787c478bd9Sstevel@tonic-gate pfn_t basepfn = (pfn_t)(basepa >> PAGESHIFT); 29797c478bd9Sstevel@tonic-gate pgcnt_t npages = (pgcnt_t)(size >> PAGESHIFT); 29807c478bd9Sstevel@tonic-gate uint_t mcreg; 29817c478bd9Sstevel@tonic-gate sbd_error_t *err; 29827c478bd9Sstevel@tonic-gate pda_handle_t ph; 29837c478bd9Sstevel@tonic-gate int rv; 29847c478bd9Sstevel@tonic-gate 29857c478bd9Sstevel@tonic-gate err = drmach_read_mc_asr(id, &mcreg); 29867c478bd9Sstevel@tonic-gate if (err) 29877c478bd9Sstevel@tonic-gate return (err); 29887c478bd9Sstevel@tonic-gate else if (mcreg & STARFIRE_MC_INTERLEAVE_MASK) { 29897c478bd9Sstevel@tonic-gate return (drerr_new(1, ESTF_INTERBOARD, "%s::%s", 29907c478bd9Sstevel@tonic-gate mem->bp->cm.name, mem->cm.name)); 29917c478bd9Sstevel@tonic-gate } 29927c478bd9Sstevel@tonic-gate 29937c478bd9Sstevel@tonic-gate if (size > 0) { 29947c478bd9Sstevel@tonic-gate rv = kcage_range_delete_post_mem_del(basepfn, npages); 29957c478bd9Sstevel@tonic-gate if (rv != 0) { 29967c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 29977c478bd9Sstevel@tonic-gate "unexpected kcage_range_delete_post_mem_del" 29987c478bd9Sstevel@tonic-gate " return value %d", rv); 29997c478bd9Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 30007c478bd9Sstevel@tonic-gate } 30017c478bd9Sstevel@tonic-gate } 30027c478bd9Sstevel@tonic-gate 30037c478bd9Sstevel@tonic-gate /* 30047c478bd9Sstevel@tonic-gate * Update the PDA (post2obp) structure with the 30057c478bd9Sstevel@tonic-gate * range of removed memory. 30067c478bd9Sstevel@tonic-gate */ 30077c478bd9Sstevel@tonic-gate ph = drmach_pda_open(); 30087c478bd9Sstevel@tonic-gate if (ph != NULL) { 30097c478bd9Sstevel@tonic-gate if (size > 0) 30107c478bd9Sstevel@tonic-gate pda_mem_del_span(ph, basepa, size); 30117c478bd9Sstevel@tonic-gate 30127c478bd9Sstevel@tonic-gate /* update PDA to board's new mc register settings */ 30137c478bd9Sstevel@tonic-gate pda_mem_sync(ph, mem->bp->bnum, 0); 30147c478bd9Sstevel@tonic-gate 30157c478bd9Sstevel@tonic-gate pda_close(ph); 30167c478bd9Sstevel@tonic-gate } 30177c478bd9Sstevel@tonic-gate 30187c478bd9Sstevel@tonic-gate return (NULL); 30197c478bd9Sstevel@tonic-gate } 30207c478bd9Sstevel@tonic-gate 30217c478bd9Sstevel@tonic-gate /* support routine for enable and disable */ 30227c478bd9Sstevel@tonic-gate static sbd_error_t * 30237c478bd9Sstevel@tonic-gate drmach_mem_update_interconnect(drmachid_t id, uint_t mcreg) 30247c478bd9Sstevel@tonic-gate { 30257c478bd9Sstevel@tonic-gate drmach_device_t *dp; 30267c478bd9Sstevel@tonic-gate pda_handle_t ph; 30277c478bd9Sstevel@tonic-gate int b; 30287c478bd9Sstevel@tonic-gate 30297c478bd9Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(id)) 30307c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 30317c478bd9Sstevel@tonic-gate dp = id; 30327c478bd9Sstevel@tonic-gate 30337c478bd9Sstevel@tonic-gate ph = drmach_pda_open(); 30347c478bd9Sstevel@tonic-gate if (ph == NULL) 30357c478bd9Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 30367c478bd9Sstevel@tonic-gate 30377c478bd9Sstevel@tonic-gate for (b = 0; b < MAX_BOARDS; b++) { 30387c478bd9Sstevel@tonic-gate int p; 30397c478bd9Sstevel@tonic-gate int rv; 30407c478bd9Sstevel@tonic-gate ushort_t bda_proc, bda_ioc; 30417c478bd9Sstevel@tonic-gate board_desc_t *bdesc; 30427c478bd9Sstevel@tonic-gate 30437c478bd9Sstevel@tonic-gate if (pda_board_present(ph, b) == 0) 30447c478bd9Sstevel@tonic-gate continue; 30457c478bd9Sstevel@tonic-gate 30467c478bd9Sstevel@tonic-gate bdesc = (board_desc_t *)pda_get_board_info(ph, b); 30477c478bd9Sstevel@tonic-gate 30487c478bd9Sstevel@tonic-gate /* 30497c478bd9Sstevel@tonic-gate * Update PCs for CPUs. 30507c478bd9Sstevel@tonic-gate */ 30517c478bd9Sstevel@tonic-gate 30527c478bd9Sstevel@tonic-gate /* make sure definition in platmod is in sync with pda */ 30537c478bd9Sstevel@tonic-gate ASSERT(MAX_PROCMODS == MAX_CPU_UNITS_PER_BOARD); 30547c478bd9Sstevel@tonic-gate 30557c478bd9Sstevel@tonic-gate bda_proc = bdesc->bda_proc; 30567c478bd9Sstevel@tonic-gate for (p = 0; p < MAX_PROCMODS; p++) { 30577c478bd9Sstevel@tonic-gate if (BDA_NBL(bda_proc, p) != BDAN_GOOD) 30587c478bd9Sstevel@tonic-gate continue; 30597c478bd9Sstevel@tonic-gate 30607c478bd9Sstevel@tonic-gate rv = pc_madr_add(b, dp->bp->bnum, p, mcreg); 30617c478bd9Sstevel@tonic-gate if (rv) { 30627c478bd9Sstevel@tonic-gate pda_close(ph); 30637c478bd9Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 30647c478bd9Sstevel@tonic-gate } 30657c478bd9Sstevel@tonic-gate } 30667c478bd9Sstevel@tonic-gate 30677c478bd9Sstevel@tonic-gate /* 30687c478bd9Sstevel@tonic-gate * Update PCs for IOCs. 30697c478bd9Sstevel@tonic-gate */ 30707c478bd9Sstevel@tonic-gate 30717c478bd9Sstevel@tonic-gate /* make sure definition in platmod is in sync with pda */ 30727c478bd9Sstevel@tonic-gate ASSERT(MAX_IOCS == MAX_IO_UNITS_PER_BOARD); 30737c478bd9Sstevel@tonic-gate 30747c478bd9Sstevel@tonic-gate bda_ioc = bdesc->bda_ioc; 30757c478bd9Sstevel@tonic-gate for (p = 0; p < MAX_IOCS; p++) { 30767c478bd9Sstevel@tonic-gate if (BDA_NBL(bda_ioc, p) != BDAN_GOOD) 30777c478bd9Sstevel@tonic-gate continue; 30787c478bd9Sstevel@tonic-gate 30797c478bd9Sstevel@tonic-gate rv = pc_madr_add(b, dp->bp->bnum, p + 4, mcreg); 30807c478bd9Sstevel@tonic-gate if (rv) { 30817c478bd9Sstevel@tonic-gate pda_close(ph); 30827c478bd9Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 30837c478bd9Sstevel@tonic-gate } 30847c478bd9Sstevel@tonic-gate } 30857c478bd9Sstevel@tonic-gate } 30867c478bd9Sstevel@tonic-gate 30877c478bd9Sstevel@tonic-gate pda_close(ph); 30887c478bd9Sstevel@tonic-gate return (NULL); 30897c478bd9Sstevel@tonic-gate } 30907c478bd9Sstevel@tonic-gate 30917c478bd9Sstevel@tonic-gate sbd_error_t * 30927c478bd9Sstevel@tonic-gate drmach_mem_disable(drmachid_t id) 30937c478bd9Sstevel@tonic-gate { 30947c478bd9Sstevel@tonic-gate sbd_error_t *err; 30957c478bd9Sstevel@tonic-gate uint_t mcreg; 30967c478bd9Sstevel@tonic-gate 30977c478bd9Sstevel@tonic-gate err = drmach_read_mc_asr(id, &mcreg); 30987c478bd9Sstevel@tonic-gate if (err == NULL) { 30997c478bd9Sstevel@tonic-gate ASSERT(mcreg & STARFIRE_MC_MEM_PRESENT_MASK); 31007c478bd9Sstevel@tonic-gate 31017c478bd9Sstevel@tonic-gate /* Turn off presence bit. */ 31027c478bd9Sstevel@tonic-gate mcreg &= ~STARFIRE_MC_MEM_PRESENT_MASK; 31037c478bd9Sstevel@tonic-gate 31047c478bd9Sstevel@tonic-gate err = drmach_mem_update_interconnect(id, mcreg); 31057c478bd9Sstevel@tonic-gate if (err == NULL) 31067c478bd9Sstevel@tonic-gate err = drmach_write_mc_asr(id, mcreg); 31077c478bd9Sstevel@tonic-gate } 31087c478bd9Sstevel@tonic-gate 31097c478bd9Sstevel@tonic-gate return (err); 31107c478bd9Sstevel@tonic-gate } 31117c478bd9Sstevel@tonic-gate 31127c478bd9Sstevel@tonic-gate sbd_error_t * 31137c478bd9Sstevel@tonic-gate drmach_mem_enable(drmachid_t id) 31147c478bd9Sstevel@tonic-gate { 31157c478bd9Sstevel@tonic-gate sbd_error_t *err; 31167c478bd9Sstevel@tonic-gate uint_t mcreg; 31177c478bd9Sstevel@tonic-gate 31187c478bd9Sstevel@tonic-gate err = drmach_read_mc_asr(id, &mcreg); 31197c478bd9Sstevel@tonic-gate if (err == NULL) { 31207c478bd9Sstevel@tonic-gate mcreg |= STARFIRE_MC_MEM_PRESENT_MASK; 31217c478bd9Sstevel@tonic-gate 31227c478bd9Sstevel@tonic-gate err = drmach_write_mc_asr(id, mcreg); 31237c478bd9Sstevel@tonic-gate if (err == NULL) 31247c478bd9Sstevel@tonic-gate err = drmach_mem_update_interconnect(id, mcreg); 31257c478bd9Sstevel@tonic-gate } 31267c478bd9Sstevel@tonic-gate 31277c478bd9Sstevel@tonic-gate return (err); 31287c478bd9Sstevel@tonic-gate } 31297c478bd9Sstevel@tonic-gate 31307c478bd9Sstevel@tonic-gate sbd_error_t * 31317c478bd9Sstevel@tonic-gate drmach_mem_get_alignment(drmachid_t id, uint64_t *mask) 31327c478bd9Sstevel@tonic-gate { 31337c478bd9Sstevel@tonic-gate drmach_device_t *mem; 31347c478bd9Sstevel@tonic-gate sbd_error_t *err; 3135fa9e4066Sahrens pnode_t nodeid; 31367c478bd9Sstevel@tonic-gate 31377c478bd9Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(id)) 31387c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 31397c478bd9Sstevel@tonic-gate mem = id; 31407c478bd9Sstevel@tonic-gate 31417c478bd9Sstevel@tonic-gate nodeid = drmach_node_get_dnode(mem->node); 31427c478bd9Sstevel@tonic-gate if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE) 31437c478bd9Sstevel@tonic-gate err = DRMACH_INTERNAL_ERROR(); 31447c478bd9Sstevel@tonic-gate else { 31457c478bd9Sstevel@tonic-gate uint64_t size; 31467c478bd9Sstevel@tonic-gate 31477c478bd9Sstevel@tonic-gate size = mc_get_alignment_mask(nodeid); 31487c478bd9Sstevel@tonic-gate if (size == (uint64_t)-1) 31497c478bd9Sstevel@tonic-gate err = DRMACH_INTERNAL_ERROR(); 31507c478bd9Sstevel@tonic-gate else { 31517c478bd9Sstevel@tonic-gate *mask = size - 1; 31527c478bd9Sstevel@tonic-gate err = NULL; 31537c478bd9Sstevel@tonic-gate } 31547c478bd9Sstevel@tonic-gate } 31557c478bd9Sstevel@tonic-gate 31567c478bd9Sstevel@tonic-gate return (err); 31577c478bd9Sstevel@tonic-gate } 31587c478bd9Sstevel@tonic-gate 31597c478bd9Sstevel@tonic-gate sbd_error_t * 31607c478bd9Sstevel@tonic-gate drmach_mem_get_base_physaddr(drmachid_t id, uint64_t *pa) 31617c478bd9Sstevel@tonic-gate { 31627c478bd9Sstevel@tonic-gate sbd_error_t *err; 31637c478bd9Sstevel@tonic-gate uint_t mcreg; 31647c478bd9Sstevel@tonic-gate 31657c478bd9Sstevel@tonic-gate err = drmach_read_mc_asr(id, &mcreg); 31667c478bd9Sstevel@tonic-gate if (err == NULL) 31677c478bd9Sstevel@tonic-gate *pa = mc_asr_to_pa(mcreg); 31687c478bd9Sstevel@tonic-gate 31697c478bd9Sstevel@tonic-gate return (err); 31707c478bd9Sstevel@tonic-gate } 31717c478bd9Sstevel@tonic-gate 31727c478bd9Sstevel@tonic-gate /* 31737c478bd9Sstevel@tonic-gate * Use of this routine after copy/rename will yield incorrect results, 31747c478bd9Sstevel@tonic-gate * because the OBP MEMAVAIL property will not correctly reflect the 31757c478bd9Sstevel@tonic-gate * programming of the MCs. 31767c478bd9Sstevel@tonic-gate */ 31777c478bd9Sstevel@tonic-gate sbd_error_t * 31787c478bd9Sstevel@tonic-gate drmach_mem_get_memlist(drmachid_t id, struct memlist **ml) 31797c478bd9Sstevel@tonic-gate { 31807c478bd9Sstevel@tonic-gate drmach_device_t *mem; 31817c478bd9Sstevel@tonic-gate int rv, i, rlen, rblks; 31827c478bd9Sstevel@tonic-gate sbd_error_t *err; 31837c478bd9Sstevel@tonic-gate struct memlist *mlist; 31847c478bd9Sstevel@tonic-gate struct sf_memunit_regspec *rlist; 31857c478bd9Sstevel@tonic-gate 31867c478bd9Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(id)) 31877c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 31887c478bd9Sstevel@tonic-gate mem = id; 31897c478bd9Sstevel@tonic-gate 31907c478bd9Sstevel@tonic-gate err = drmach_device_get_proplen(mem, "dr-available", &rlen); 31917c478bd9Sstevel@tonic-gate if (err) 31927c478bd9Sstevel@tonic-gate return (err); 31937c478bd9Sstevel@tonic-gate 31947c478bd9Sstevel@tonic-gate rlist = kmem_zalloc(rlen, KM_SLEEP); 31957c478bd9Sstevel@tonic-gate 31967c478bd9Sstevel@tonic-gate err = drmach_device_get_prop(mem, "dr-available", rlist); 31977c478bd9Sstevel@tonic-gate if (err) { 31987c478bd9Sstevel@tonic-gate kmem_free(rlist, rlen); 31997c478bd9Sstevel@tonic-gate return (err); 32007c478bd9Sstevel@tonic-gate } 32017c478bd9Sstevel@tonic-gate 32027c478bd9Sstevel@tonic-gate mlist = NULL; 32037c478bd9Sstevel@tonic-gate rblks = rlen / sizeof (struct sf_memunit_regspec); 32047c478bd9Sstevel@tonic-gate for (i = 0; i < rblks; i++) { 32057c478bd9Sstevel@tonic-gate uint64_t addr, size; 32067c478bd9Sstevel@tonic-gate 32077c478bd9Sstevel@tonic-gate addr = (uint64_t)rlist[i].regspec_addr_hi << 32; 32087c478bd9Sstevel@tonic-gate addr |= (uint64_t)rlist[i].regspec_addr_lo; 32097c478bd9Sstevel@tonic-gate size = (uint64_t)rlist[i].regspec_size_hi << 32; 32107c478bd9Sstevel@tonic-gate size |= (uint64_t)rlist[i].regspec_size_lo; 32117c478bd9Sstevel@tonic-gate 32127c478bd9Sstevel@tonic-gate mlist = memlist_add_span(mlist, addr, size); 32137c478bd9Sstevel@tonic-gate } 32147c478bd9Sstevel@tonic-gate 32157c478bd9Sstevel@tonic-gate kmem_free(rlist, rlen); 32167c478bd9Sstevel@tonic-gate 32177c478bd9Sstevel@tonic-gate /* 32187c478bd9Sstevel@tonic-gate * Make sure the incoming memlist doesn't already 32197c478bd9Sstevel@tonic-gate * intersect with what's present in the system (phys_install). 32207c478bd9Sstevel@tonic-gate */ 32217c478bd9Sstevel@tonic-gate memlist_read_lock(); 32227c478bd9Sstevel@tonic-gate rv = memlist_intersect(phys_install, mlist); 32237c478bd9Sstevel@tonic-gate memlist_read_unlock(); 32247c478bd9Sstevel@tonic-gate if (rv) { 32257c478bd9Sstevel@tonic-gate #ifdef DEBUG 32267c478bd9Sstevel@tonic-gate DRMACH_PR("OBP derived memlist intersects" 32277c478bd9Sstevel@tonic-gate " with phys_install\n"); 32287c478bd9Sstevel@tonic-gate memlist_dump(mlist); 32297c478bd9Sstevel@tonic-gate 32307c478bd9Sstevel@tonic-gate DRMACH_PR("phys_install memlist:\n"); 32317c478bd9Sstevel@tonic-gate memlist_dump(phys_install); 32327c478bd9Sstevel@tonic-gate #endif 32337c478bd9Sstevel@tonic-gate 32347c478bd9Sstevel@tonic-gate memlist_delete(mlist); 32357c478bd9Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 32367c478bd9Sstevel@tonic-gate } 32377c478bd9Sstevel@tonic-gate 32387c478bd9Sstevel@tonic-gate #ifdef DEBUG 32397c478bd9Sstevel@tonic-gate DRMACH_PR("OBP derived memlist:"); 32407c478bd9Sstevel@tonic-gate memlist_dump(mlist); 32417c478bd9Sstevel@tonic-gate #endif 32427c478bd9Sstevel@tonic-gate 32437c478bd9Sstevel@tonic-gate *ml = mlist; 32447c478bd9Sstevel@tonic-gate return (NULL); 32457c478bd9Sstevel@tonic-gate } 32467c478bd9Sstevel@tonic-gate 32477c478bd9Sstevel@tonic-gate sbd_error_t * 32487c478bd9Sstevel@tonic-gate drmach_mem_get_size(drmachid_t id, uint64_t *bytes) 32497c478bd9Sstevel@tonic-gate { 32507c478bd9Sstevel@tonic-gate drmach_device_t *mem; 32517c478bd9Sstevel@tonic-gate pda_handle_t ph; 32527c478bd9Sstevel@tonic-gate pgcnt_t npages; 32537c478bd9Sstevel@tonic-gate 32547c478bd9Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(id)) 32557c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 32567c478bd9Sstevel@tonic-gate mem = id; 32577c478bd9Sstevel@tonic-gate 32587c478bd9Sstevel@tonic-gate ph = drmach_pda_open(); 32597c478bd9Sstevel@tonic-gate if (ph == NULL) 32607c478bd9Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 32617c478bd9Sstevel@tonic-gate 32627c478bd9Sstevel@tonic-gate npages = pda_get_mem_size(ph, mem->bp->bnum); 32637c478bd9Sstevel@tonic-gate *bytes = (uint64_t)npages << PAGESHIFT; 32647c478bd9Sstevel@tonic-gate 32657c478bd9Sstevel@tonic-gate pda_close(ph); 32667c478bd9Sstevel@tonic-gate return (NULL); 32677c478bd9Sstevel@tonic-gate } 32687c478bd9Sstevel@tonic-gate 32697c478bd9Sstevel@tonic-gate sbd_error_t * 32707c478bd9Sstevel@tonic-gate drmach_mem_get_slice_size(drmachid_t id, uint64_t *bytes) 32717c478bd9Sstevel@tonic-gate { 32727c478bd9Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(id)) 32737c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 32747c478bd9Sstevel@tonic-gate 32757c478bd9Sstevel@tonic-gate *bytes = mc_get_mem_alignment(); 32767c478bd9Sstevel@tonic-gate return (NULL); 32777c478bd9Sstevel@tonic-gate } 32787c478bd9Sstevel@tonic-gate 32797c478bd9Sstevel@tonic-gate /* field debugging tool */ 32807c478bd9Sstevel@tonic-gate processorid_t drmach_mem_cpu_affinity_nail = 0; 32817c478bd9Sstevel@tonic-gate 32827c478bd9Sstevel@tonic-gate processorid_t 32837c478bd9Sstevel@tonic-gate drmach_mem_cpu_affinity(drmachid_t id) 32847c478bd9Sstevel@tonic-gate { 32857c478bd9Sstevel@tonic-gate drmach_device_t *mp; 32867c478bd9Sstevel@tonic-gate drmach_board_t *bp; 32877c478bd9Sstevel@tonic-gate processorid_t cpuid; 32887c478bd9Sstevel@tonic-gate 32897c478bd9Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(id)) 32907c478bd9Sstevel@tonic-gate return (CPU_CURRENT); 32917c478bd9Sstevel@tonic-gate 32927c478bd9Sstevel@tonic-gate if (drmach_mem_cpu_affinity_nail) { 32937c478bd9Sstevel@tonic-gate cpuid = drmach_mem_cpu_affinity_nail; 32947c478bd9Sstevel@tonic-gate 32957c478bd9Sstevel@tonic-gate if (cpuid < 0 || cpuid > NCPU) 32967c478bd9Sstevel@tonic-gate return (CPU_CURRENT); 32977c478bd9Sstevel@tonic-gate 32987c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock); 32997c478bd9Sstevel@tonic-gate if (cpu[cpuid] == NULL || !CPU_ACTIVE(cpu[cpuid])) 33007c478bd9Sstevel@tonic-gate cpuid = CPU_CURRENT; 33017c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock); 33027c478bd9Sstevel@tonic-gate 33037c478bd9Sstevel@tonic-gate return (cpuid); 33047c478bd9Sstevel@tonic-gate } 33057c478bd9Sstevel@tonic-gate 33067c478bd9Sstevel@tonic-gate /* try to choose a proc on the target board */ 33077c478bd9Sstevel@tonic-gate mp = id; 33087c478bd9Sstevel@tonic-gate bp = mp->bp; 33097c478bd9Sstevel@tonic-gate if (bp->devices) { 33107c478bd9Sstevel@tonic-gate int rv; 33117c478bd9Sstevel@tonic-gate int d_idx; 33127c478bd9Sstevel@tonic-gate drmachid_t d_id; 33137c478bd9Sstevel@tonic-gate 33147c478bd9Sstevel@tonic-gate rv = drmach_array_first(bp->devices, &d_idx, &d_id); 33157c478bd9Sstevel@tonic-gate while (rv == 0) { 33167c478bd9Sstevel@tonic-gate if (DRMACH_IS_CPU_ID(d_id)) { 33177c478bd9Sstevel@tonic-gate cpuid = drmach_cpu_calc_id(d_id); 33187c478bd9Sstevel@tonic-gate 33197c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock); 33207c478bd9Sstevel@tonic-gate if (cpu[cpuid] && CPU_ACTIVE(cpu[cpuid])) { 33217c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock); 33227c478bd9Sstevel@tonic-gate DRMACH_PR("drmach_mem_cpu_affinity: " 33237c478bd9Sstevel@tonic-gate "selected cpuid=%d\n", cpuid); 33247c478bd9Sstevel@tonic-gate return (cpuid); 33257c478bd9Sstevel@tonic-gate } else { 33267c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock); 33277c478bd9Sstevel@tonic-gate } 33287c478bd9Sstevel@tonic-gate } 33297c478bd9Sstevel@tonic-gate 33307c478bd9Sstevel@tonic-gate rv = drmach_array_next(bp->devices, &d_idx, &d_id); 33317c478bd9Sstevel@tonic-gate } 33327c478bd9Sstevel@tonic-gate } 33337c478bd9Sstevel@tonic-gate 33347c478bd9Sstevel@tonic-gate /* otherwise, this proc, wherever it is */ 33357c478bd9Sstevel@tonic-gate DRMACH_PR("drmach_mem_cpu_affinity: using default CPU_CURRENT\n"); 33367c478bd9Sstevel@tonic-gate 33377c478bd9Sstevel@tonic-gate return (CPU_CURRENT); 33387c478bd9Sstevel@tonic-gate } 33397c478bd9Sstevel@tonic-gate 33407c478bd9Sstevel@tonic-gate static sbd_error_t * 33417c478bd9Sstevel@tonic-gate drmach_mem_release(drmachid_t id) 33427c478bd9Sstevel@tonic-gate { 33437c478bd9Sstevel@tonic-gate if (!DRMACH_IS_MEM_ID(id)) 33447c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 33457c478bd9Sstevel@tonic-gate return (NULL); 33467c478bd9Sstevel@tonic-gate } 33477c478bd9Sstevel@tonic-gate 33487c478bd9Sstevel@tonic-gate static sbd_error_t * 33497c478bd9Sstevel@tonic-gate drmach_mem_status(drmachid_t id, drmach_status_t *stat) 33507c478bd9Sstevel@tonic-gate { 33517c478bd9Sstevel@tonic-gate drmach_device_t *dp; 33527c478bd9Sstevel@tonic-gate sbd_error_t *err; 33537c478bd9Sstevel@tonic-gate uint64_t pa, slice_size; 33547c478bd9Sstevel@tonic-gate struct memlist *ml; 33557c478bd9Sstevel@tonic-gate 33567c478bd9Sstevel@tonic-gate ASSERT(DRMACH_IS_MEM_ID(id)); 33577c478bd9Sstevel@tonic-gate dp = id; 33587c478bd9Sstevel@tonic-gate 33597c478bd9Sstevel@tonic-gate /* get starting physical address of target memory */ 33607c478bd9Sstevel@tonic-gate err = drmach_mem_get_base_physaddr(id, &pa); 33617c478bd9Sstevel@tonic-gate if (err) 33627c478bd9Sstevel@tonic-gate return (err); 33637c478bd9Sstevel@tonic-gate 33647c478bd9Sstevel@tonic-gate /* round down to slice boundary */ 33657c478bd9Sstevel@tonic-gate slice_size = mc_get_mem_alignment(); 33667c478bd9Sstevel@tonic-gate pa &= ~ (slice_size - 1); 33677c478bd9Sstevel@tonic-gate 33687c478bd9Sstevel@tonic-gate /* stop at first span that is in slice */ 33697c478bd9Sstevel@tonic-gate memlist_read_lock(); 337056f33205SJonathan Adams for (ml = phys_install; ml; ml = ml->ml_next) 337156f33205SJonathan Adams if (ml->ml_address >= pa && ml->ml_address < pa + slice_size) 33727c478bd9Sstevel@tonic-gate break; 33737c478bd9Sstevel@tonic-gate memlist_read_unlock(); 33747c478bd9Sstevel@tonic-gate 33757c478bd9Sstevel@tonic-gate stat->assigned = dp->bp->assigned; 33767c478bd9Sstevel@tonic-gate stat->powered = dp->bp->powered; 33777c478bd9Sstevel@tonic-gate stat->configured = (ml != NULL); 33787c478bd9Sstevel@tonic-gate stat->busy = dp->busy; 337907d06da5SSurya Prakki (void) strncpy(stat->type, dp->type, sizeof (stat->type)); 33807c478bd9Sstevel@tonic-gate stat->info[0] = '\0'; 33817c478bd9Sstevel@tonic-gate 33827c478bd9Sstevel@tonic-gate return (NULL); 33837c478bd9Sstevel@tonic-gate } 33847c478bd9Sstevel@tonic-gate 33857c478bd9Sstevel@tonic-gate static int 33867c478bd9Sstevel@tonic-gate drmach_detach_board(void *arg) 33877c478bd9Sstevel@tonic-gate { 33887c478bd9Sstevel@tonic-gate cpuset_t cset; 33897c478bd9Sstevel@tonic-gate int retval; 33907c478bd9Sstevel@tonic-gate drmach_board_t *bp = (drmach_board_t *)arg; 33917c478bd9Sstevel@tonic-gate 33927c478bd9Sstevel@tonic-gate cset = cpu_ready_set; 33937c478bd9Sstevel@tonic-gate promsafe_xc_attention(cset); 33947c478bd9Sstevel@tonic-gate 33957c478bd9Sstevel@tonic-gate retval = prom_starfire_rm_brd(bp->bnum); 33967c478bd9Sstevel@tonic-gate 33977c478bd9Sstevel@tonic-gate xc_dismissed(cset); 33987c478bd9Sstevel@tonic-gate 33997c478bd9Sstevel@tonic-gate return (retval); 34007c478bd9Sstevel@tonic-gate } 34017c478bd9Sstevel@tonic-gate 34027c478bd9Sstevel@tonic-gate sbd_error_t * 34037c478bd9Sstevel@tonic-gate drmach_board_deprobe(drmachid_t id) 34047c478bd9Sstevel@tonic-gate { 34057c478bd9Sstevel@tonic-gate drmach_board_t *bp; 34067c478bd9Sstevel@tonic-gate int retval; 34077c478bd9Sstevel@tonic-gate 34087c478bd9Sstevel@tonic-gate if (!DRMACH_IS_BOARD_ID(id)) 34097c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 34107c478bd9Sstevel@tonic-gate bp = id; 34117c478bd9Sstevel@tonic-gate 34127c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "DR: PROM detach board %d\n", bp->bnum); 34137c478bd9Sstevel@tonic-gate 34147c478bd9Sstevel@tonic-gate retval = prom_tree_update(drmach_detach_board, bp); 34157c478bd9Sstevel@tonic-gate 34167c478bd9Sstevel@tonic-gate if (retval == 0) 34177c478bd9Sstevel@tonic-gate return (NULL); 34187c478bd9Sstevel@tonic-gate else { 34197c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "prom error: prom_starfire_rm_brd(%d) " 34207c478bd9Sstevel@tonic-gate "returned %d", bp->bnum, retval); 34217c478bd9Sstevel@tonic-gate return (drerr_new(1, ESTF_DEPROBE, "%s", bp->cm.name)); 34227c478bd9Sstevel@tonic-gate } 34237c478bd9Sstevel@tonic-gate } 34247c478bd9Sstevel@tonic-gate 34257c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 34267c478bd9Sstevel@tonic-gate static sbd_error_t * 34277c478bd9Sstevel@tonic-gate drmach_pt_juggle_bootproc(drmachid_t id, drmach_opts_t *opts) 34287c478bd9Sstevel@tonic-gate { 34297c478bd9Sstevel@tonic-gate drmach_device_t *cpu; 34307c478bd9Sstevel@tonic-gate sbd_error_t *err; 34317c478bd9Sstevel@tonic-gate 34327c478bd9Sstevel@tonic-gate if (!DRMACH_IS_CPU_ID(id)) 34337c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 34347c478bd9Sstevel@tonic-gate cpu = id; 34357c478bd9Sstevel@tonic-gate 34367c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock); 34377c478bd9Sstevel@tonic-gate 34387c478bd9Sstevel@tonic-gate err = drmach_cpu_juggle_bootproc(cpu); 34397c478bd9Sstevel@tonic-gate 34407c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock); 34417c478bd9Sstevel@tonic-gate 34427c478bd9Sstevel@tonic-gate return (err); 34437c478bd9Sstevel@tonic-gate } 34447c478bd9Sstevel@tonic-gate 34457c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 34467c478bd9Sstevel@tonic-gate static sbd_error_t * 34477c478bd9Sstevel@tonic-gate drmach_pt_dump_pdainfo(drmachid_t id, drmach_opts_t *opts) 34487c478bd9Sstevel@tonic-gate { 34497c478bd9Sstevel@tonic-gate drmach_board_t *bp; 34507c478bd9Sstevel@tonic-gate int board; 34517c478bd9Sstevel@tonic-gate int i; 34527c478bd9Sstevel@tonic-gate pda_handle_t ph; 34537c478bd9Sstevel@tonic-gate board_desc_t *bdesc; 34547c478bd9Sstevel@tonic-gate 34557c478bd9Sstevel@tonic-gate if (!DRMACH_IS_BOARD_ID(id)) 34567c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 34577c478bd9Sstevel@tonic-gate bp = id; 34587c478bd9Sstevel@tonic-gate board = bp->bnum; 34597c478bd9Sstevel@tonic-gate 34607c478bd9Sstevel@tonic-gate ph = drmach_pda_open(); 34617c478bd9Sstevel@tonic-gate if (ph == NULL) 34627c478bd9Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 34637c478bd9Sstevel@tonic-gate 34647c478bd9Sstevel@tonic-gate if (pda_board_present(ph, board) == 0) { 34657c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "board %d is MISSING\n", board); 34667c478bd9Sstevel@tonic-gate pda_close(ph); 34677c478bd9Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 34687c478bd9Sstevel@tonic-gate } 34697c478bd9Sstevel@tonic-gate 34707c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "board %d is PRESENT\n", board); 34717c478bd9Sstevel@tonic-gate 34727c478bd9Sstevel@tonic-gate bdesc = (board_desc_t *)pda_get_board_info(ph, board); 34737c478bd9Sstevel@tonic-gate if (bdesc == NULL) { 34747c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 34757c478bd9Sstevel@tonic-gate "no board descriptor found for board %d\n", 34767c478bd9Sstevel@tonic-gate board); 34777c478bd9Sstevel@tonic-gate pda_close(ph); 34787c478bd9Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 34797c478bd9Sstevel@tonic-gate } 34807c478bd9Sstevel@tonic-gate 34817c478bd9Sstevel@tonic-gate /* make sure definition in platmod is in sync with pda */ 34827c478bd9Sstevel@tonic-gate ASSERT(MAX_PROCMODS == MAX_CPU_UNITS_PER_BOARD); 34837c478bd9Sstevel@tonic-gate 34847c478bd9Sstevel@tonic-gate for (i = 0; i < MAX_PROCMODS; i++) { 34857c478bd9Sstevel@tonic-gate if (BDA_NBL(bdesc->bda_proc, i) == BDAN_GOOD) 34867c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 34877c478bd9Sstevel@tonic-gate "proc %d.%d PRESENT\n", board, i); 34887c478bd9Sstevel@tonic-gate else 34897c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 34907c478bd9Sstevel@tonic-gate "proc %d.%d MISSING\n", board, i); 34917c478bd9Sstevel@tonic-gate } 34927c478bd9Sstevel@tonic-gate 34937c478bd9Sstevel@tonic-gate for (i = 0; i < MAX_MGROUPS; i++) { 34947c478bd9Sstevel@tonic-gate if (BDA_NBL(bdesc->bda_mgroup, i) == BDAN_GOOD) 34957c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 34967c478bd9Sstevel@tonic-gate "mgroup %d.%d PRESENT\n", board, i); 34977c478bd9Sstevel@tonic-gate else 34987c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 34997c478bd9Sstevel@tonic-gate "mgroup %d.%d MISSING\n", board, i); 35007c478bd9Sstevel@tonic-gate } 35017c478bd9Sstevel@tonic-gate 35027c478bd9Sstevel@tonic-gate /* make sure definition in platmod is in sync with pda */ 35037c478bd9Sstevel@tonic-gate ASSERT(MAX_IOCS == MAX_IO_UNITS_PER_BOARD); 35047c478bd9Sstevel@tonic-gate 35057c478bd9Sstevel@tonic-gate for (i = 0; i < MAX_IOCS; i++) { 35067c478bd9Sstevel@tonic-gate int s; 35077c478bd9Sstevel@tonic-gate 35087c478bd9Sstevel@tonic-gate if (BDA_NBL(bdesc->bda_ioc, i) == BDAN_GOOD) { 35097c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 35107c478bd9Sstevel@tonic-gate "ioc %d.%d PRESENT\n", board, i); 35117c478bd9Sstevel@tonic-gate for (s = 0; s < MAX_SLOTS_PER_IOC; s++) { 35127c478bd9Sstevel@tonic-gate if (BDA_NBL(bdesc->bda_ios[i], s) != BDAN_GOOD) 35137c478bd9Sstevel@tonic-gate continue; 35147c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 35157c478bd9Sstevel@tonic-gate "..scard %d.%d.%d PRESENT\n", 35167c478bd9Sstevel@tonic-gate board, i, s); 35177c478bd9Sstevel@tonic-gate } 35187c478bd9Sstevel@tonic-gate } else { 35197c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 35207c478bd9Sstevel@tonic-gate "ioc %d.%d MISSING\n", 35217c478bd9Sstevel@tonic-gate board, i); 35227c478bd9Sstevel@tonic-gate } 35237c478bd9Sstevel@tonic-gate } 35247c478bd9Sstevel@tonic-gate 35257c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 35267c478bd9Sstevel@tonic-gate "board %d memsize = %d pages\n", 35277c478bd9Sstevel@tonic-gate board, pda_get_mem_size(ph, board)); 35287c478bd9Sstevel@tonic-gate 35297c478bd9Sstevel@tonic-gate pda_close(ph); 35307c478bd9Sstevel@tonic-gate 35317c478bd9Sstevel@tonic-gate return (NULL); 35327c478bd9Sstevel@tonic-gate } 35337c478bd9Sstevel@tonic-gate 35347c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 35357c478bd9Sstevel@tonic-gate sbd_error_t * 35367c478bd9Sstevel@tonic-gate drmach_pt_readmem(drmachid_t id, drmach_opts_t *opts) 35377c478bd9Sstevel@tonic-gate { 35387c478bd9Sstevel@tonic-gate struct memlist *ml; 35397c478bd9Sstevel@tonic-gate uint64_t src_pa; 35407c478bd9Sstevel@tonic-gate uint64_t dst_pa; 35417c478bd9Sstevel@tonic-gate uint64_t dst; 35427c478bd9Sstevel@tonic-gate 35437c478bd9Sstevel@tonic-gate dst_pa = va_to_pa(&dst); 35447c478bd9Sstevel@tonic-gate 35457c478bd9Sstevel@tonic-gate memlist_read_lock(); 354656f33205SJonathan Adams for (ml = phys_install; ml; ml = ml->ml_next) { 35477c478bd9Sstevel@tonic-gate uint64_t nbytes; 35487c478bd9Sstevel@tonic-gate 354956f33205SJonathan Adams src_pa = ml->ml_address; 355056f33205SJonathan Adams nbytes = ml->ml_size; 35517c478bd9Sstevel@tonic-gate 35527c478bd9Sstevel@tonic-gate while (nbytes != 0ull) { 35537c478bd9Sstevel@tonic-gate 35547c478bd9Sstevel@tonic-gate /* copy 32 bytes at arc_pa to dst_pa */ 35557c478bd9Sstevel@tonic-gate bcopy32_il(src_pa, dst_pa); 35567c478bd9Sstevel@tonic-gate 35577c478bd9Sstevel@tonic-gate /* increment by 32 bytes */ 35587c478bd9Sstevel@tonic-gate src_pa += (4 * sizeof (uint64_t)); 35597c478bd9Sstevel@tonic-gate 35607c478bd9Sstevel@tonic-gate /* decrement by 32 bytes */ 35617c478bd9Sstevel@tonic-gate nbytes -= (4 * sizeof (uint64_t)); 35627c478bd9Sstevel@tonic-gate } 35637c478bd9Sstevel@tonic-gate } 35647c478bd9Sstevel@tonic-gate memlist_read_unlock(); 35657c478bd9Sstevel@tonic-gate 35667c478bd9Sstevel@tonic-gate return (NULL); 35677c478bd9Sstevel@tonic-gate } 35687c478bd9Sstevel@tonic-gate 35697c478bd9Sstevel@tonic-gate static struct { 35707c478bd9Sstevel@tonic-gate const char *name; 35717c478bd9Sstevel@tonic-gate sbd_error_t *(*handler)(drmachid_t id, drmach_opts_t *opts); 35727c478bd9Sstevel@tonic-gate } drmach_pt_arr[] = { 35737c478bd9Sstevel@tonic-gate { "juggle", drmach_pt_juggle_bootproc }, 35747c478bd9Sstevel@tonic-gate { "pda", drmach_pt_dump_pdainfo }, 35757c478bd9Sstevel@tonic-gate { "readmem", drmach_pt_readmem }, 35767c478bd9Sstevel@tonic-gate 35777c478bd9Sstevel@tonic-gate /* the following line must always be last */ 35787c478bd9Sstevel@tonic-gate { NULL, NULL } 35797c478bd9Sstevel@tonic-gate }; 35807c478bd9Sstevel@tonic-gate 35817c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 35827c478bd9Sstevel@tonic-gate sbd_error_t * 35837c478bd9Sstevel@tonic-gate drmach_passthru(drmachid_t id, drmach_opts_t *opts) 35847c478bd9Sstevel@tonic-gate { 35857c478bd9Sstevel@tonic-gate int i; 35867c478bd9Sstevel@tonic-gate sbd_error_t *err; 35877c478bd9Sstevel@tonic-gate 35887c478bd9Sstevel@tonic-gate i = 0; 35897c478bd9Sstevel@tonic-gate while (drmach_pt_arr[i].name != NULL) { 35907c478bd9Sstevel@tonic-gate int len = strlen(drmach_pt_arr[i].name); 35917c478bd9Sstevel@tonic-gate 35927c478bd9Sstevel@tonic-gate if (strncmp(drmach_pt_arr[i].name, opts->copts, len) == 0) 35937c478bd9Sstevel@tonic-gate break; 35947c478bd9Sstevel@tonic-gate 35957c478bd9Sstevel@tonic-gate i += 1; 35967c478bd9Sstevel@tonic-gate } 35977c478bd9Sstevel@tonic-gate 35987c478bd9Sstevel@tonic-gate if (drmach_pt_arr[i].name == NULL) 35997c478bd9Sstevel@tonic-gate err = drerr_new(0, ESTF_UNKPTCMD, opts->copts); 36007c478bd9Sstevel@tonic-gate else 36017c478bd9Sstevel@tonic-gate err = (*drmach_pt_arr[i].handler)(id, opts); 36027c478bd9Sstevel@tonic-gate 36037c478bd9Sstevel@tonic-gate return (err); 36047c478bd9Sstevel@tonic-gate } 36057c478bd9Sstevel@tonic-gate 36067c478bd9Sstevel@tonic-gate sbd_error_t * 36077c478bd9Sstevel@tonic-gate drmach_release(drmachid_t id) 36087c478bd9Sstevel@tonic-gate { 36097c478bd9Sstevel@tonic-gate drmach_common_t *cp; 36107c478bd9Sstevel@tonic-gate if (!DRMACH_IS_DEVICE_ID(id)) 36117c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 36127c478bd9Sstevel@tonic-gate cp = id; 36137c478bd9Sstevel@tonic-gate 36147c478bd9Sstevel@tonic-gate return (cp->release(id)); 36157c478bd9Sstevel@tonic-gate } 36167c478bd9Sstevel@tonic-gate 36177c478bd9Sstevel@tonic-gate sbd_error_t * 36187c478bd9Sstevel@tonic-gate drmach_status(drmachid_t id, drmach_status_t *stat) 36197c478bd9Sstevel@tonic-gate { 36207c478bd9Sstevel@tonic-gate drmach_common_t *cp; 36217c478bd9Sstevel@tonic-gate 36227c478bd9Sstevel@tonic-gate if (!DRMACH_IS_ID(id)) 36237c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_NOTID, NULL)); 36247c478bd9Sstevel@tonic-gate cp = id; 36257c478bd9Sstevel@tonic-gate 36267c478bd9Sstevel@tonic-gate return (cp->status(id, stat)); 36277c478bd9Sstevel@tonic-gate } 36287c478bd9Sstevel@tonic-gate 36297c478bd9Sstevel@tonic-gate sbd_error_t * 36307c478bd9Sstevel@tonic-gate drmach_unconfigure(drmachid_t id, int flags) 36317c478bd9Sstevel@tonic-gate { 36327c478bd9Sstevel@tonic-gate drmach_device_t *dp; 3633fa9e4066Sahrens pnode_t nodeid; 36347c478bd9Sstevel@tonic-gate dev_info_t *dip, *fdip = NULL; 36357c478bd9Sstevel@tonic-gate 36367c478bd9Sstevel@tonic-gate if (!DRMACH_IS_DEVICE_ID(id)) 36377c478bd9Sstevel@tonic-gate return (drerr_new(0, ESTF_INAPPROP, NULL)); 36387c478bd9Sstevel@tonic-gate 36397c478bd9Sstevel@tonic-gate dp = id; 36407c478bd9Sstevel@tonic-gate 36417c478bd9Sstevel@tonic-gate nodeid = drmach_node_get_dnode(dp->node); 36427c478bd9Sstevel@tonic-gate if (nodeid == OBP_NONODE) 36437c478bd9Sstevel@tonic-gate return (DRMACH_INTERNAL_ERROR()); 36447c478bd9Sstevel@tonic-gate 36457c478bd9Sstevel@tonic-gate dip = e_ddi_nodeid_to_dip(nodeid); 36467c478bd9Sstevel@tonic-gate if (dip == NULL) 36477c478bd9Sstevel@tonic-gate return (NULL); 36487c478bd9Sstevel@tonic-gate 36497c478bd9Sstevel@tonic-gate /* 36507c478bd9Sstevel@tonic-gate * Branch already held, so hold acquired in 36517c478bd9Sstevel@tonic-gate * e_ddi_nodeid_to_dip() can be released 36527c478bd9Sstevel@tonic-gate */ 36537c478bd9Sstevel@tonic-gate ddi_release_devi(dip); 36547c478bd9Sstevel@tonic-gate 365525cf1a30Sjl139090 if (flags & DEVI_BRANCH_DESTROY) 365625cf1a30Sjl139090 flags |= DEVI_BRANCH_EVENT; 36577c478bd9Sstevel@tonic-gate 36587c478bd9Sstevel@tonic-gate /* 36597c478bd9Sstevel@tonic-gate * Force flag is no longer necessary. See starcat/io/drmach.c 36607c478bd9Sstevel@tonic-gate * for details. 36617c478bd9Sstevel@tonic-gate */ 36627c478bd9Sstevel@tonic-gate ASSERT(e_ddi_branch_held(dip)); 366325cf1a30Sjl139090 if (e_ddi_branch_unconfigure(dip, &fdip, flags)) { 36647c478bd9Sstevel@tonic-gate sbd_error_t *err; 36657c478bd9Sstevel@tonic-gate char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 36667c478bd9Sstevel@tonic-gate 36677c478bd9Sstevel@tonic-gate /* 36687c478bd9Sstevel@tonic-gate * If non-NULL, fdip is returned held and must be released. 36697c478bd9Sstevel@tonic-gate */ 36707c478bd9Sstevel@tonic-gate if (fdip != NULL) { 36717c478bd9Sstevel@tonic-gate (void) ddi_pathname(fdip, path); 36727c478bd9Sstevel@tonic-gate ndi_rele_devi(fdip); 36737c478bd9Sstevel@tonic-gate } else { 36747c478bd9Sstevel@tonic-gate (void) ddi_pathname(dip, path); 36757c478bd9Sstevel@tonic-gate } 36767c478bd9Sstevel@tonic-gate 36777c478bd9Sstevel@tonic-gate err = drerr_new(1, ESTF_DRVFAIL, path); 36787c478bd9Sstevel@tonic-gate 36797c478bd9Sstevel@tonic-gate kmem_free(path, MAXPATHLEN); 36807c478bd9Sstevel@tonic-gate 36817c478bd9Sstevel@tonic-gate return (err); 36827c478bd9Sstevel@tonic-gate } 36837c478bd9Sstevel@tonic-gate 36847c478bd9Sstevel@tonic-gate return (NULL); 36857c478bd9Sstevel@tonic-gate } 36867c478bd9Sstevel@tonic-gate 36877c478bd9Sstevel@tonic-gate /* 36887c478bd9Sstevel@tonic-gate * drmach interfaces to legacy Starfire platmod logic 36897c478bd9Sstevel@tonic-gate * linkage via runtime symbol look up, called from plat_cpu_power* 36907c478bd9Sstevel@tonic-gate */ 36917c478bd9Sstevel@tonic-gate 36927c478bd9Sstevel@tonic-gate /* 36937c478bd9Sstevel@tonic-gate * Start up a cpu. It is possible that we're attempting to restart 36947c478bd9Sstevel@tonic-gate * the cpu after an UNCONFIGURE in which case the cpu will be 36957c478bd9Sstevel@tonic-gate * spinning in its cache. So, all we have to do is wakeup him up. 36967c478bd9Sstevel@tonic-gate * Under normal circumstances the cpu will be coming from a previous 36977c478bd9Sstevel@tonic-gate * CONNECT and thus will be spinning in OBP. In both cases, the 36987c478bd9Sstevel@tonic-gate * startup sequence is the same. 36997c478bd9Sstevel@tonic-gate */ 37007c478bd9Sstevel@tonic-gate int 37017c478bd9Sstevel@tonic-gate drmach_cpu_poweron(struct cpu *cp) 37027c478bd9Sstevel@tonic-gate { 37037c478bd9Sstevel@tonic-gate DRMACH_PR("drmach_cpu_poweron: starting cpuid %d\n", cp->cpu_id); 37047c478bd9Sstevel@tonic-gate 37057c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 37067c478bd9Sstevel@tonic-gate 37077c478bd9Sstevel@tonic-gate if (drmach_cpu_start(cp) != 0) 37087c478bd9Sstevel@tonic-gate return (EBUSY); 37097c478bd9Sstevel@tonic-gate else 37107c478bd9Sstevel@tonic-gate return (0); 37117c478bd9Sstevel@tonic-gate } 37127c478bd9Sstevel@tonic-gate 37137c478bd9Sstevel@tonic-gate int 37147c478bd9Sstevel@tonic-gate drmach_cpu_poweroff(struct cpu *cp) 37157c478bd9Sstevel@tonic-gate { 37167c478bd9Sstevel@tonic-gate int ntries, cnt; 37177c478bd9Sstevel@tonic-gate processorid_t cpuid = cp->cpu_id; 37187c478bd9Sstevel@tonic-gate void drmach_cpu_shutdown_self(void); 37197c478bd9Sstevel@tonic-gate 37207c478bd9Sstevel@tonic-gate DRMACH_PR("drmach_cpu_poweroff: stopping cpuid %d\n", cp->cpu_id); 37217c478bd9Sstevel@tonic-gate 37227c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 37237c478bd9Sstevel@tonic-gate 37247c478bd9Sstevel@tonic-gate /* 37257c478bd9Sstevel@tonic-gate * Capture all CPUs (except for detaching proc) to prevent 37267c478bd9Sstevel@tonic-gate * crosscalls to the detaching proc until it has cleared its 37277c478bd9Sstevel@tonic-gate * bit in cpu_ready_set. 37287c478bd9Sstevel@tonic-gate * 37297c478bd9Sstevel@tonic-gate * The CPU's remain paused and the prom_mutex is known to be free. 37307c478bd9Sstevel@tonic-gate * This prevents the x-trap victim from blocking when doing prom 37317c478bd9Sstevel@tonic-gate * IEEE-1275 calls at a high PIL level. 37327c478bd9Sstevel@tonic-gate */ 37337c478bd9Sstevel@tonic-gate promsafe_pause_cpus(); 37347c478bd9Sstevel@tonic-gate 37357c478bd9Sstevel@tonic-gate /* 37367c478bd9Sstevel@tonic-gate * Quiesce interrupts on the target CPU. We do this by setting 37377c478bd9Sstevel@tonic-gate * the CPU 'not ready'- (i.e. removing the CPU from cpu_ready_set) to 37387c478bd9Sstevel@tonic-gate * prevent it from receiving cross calls and cross traps. 37397c478bd9Sstevel@tonic-gate * This prevents the processor from receiving any new soft interrupts. 37407c478bd9Sstevel@tonic-gate */ 37417c478bd9Sstevel@tonic-gate mp_cpu_quiesce(cp); 37427c478bd9Sstevel@tonic-gate 37437c478bd9Sstevel@tonic-gate /* setup xt_mb, will be cleared by drmach_shutdown_asm when ready */ 37447c478bd9Sstevel@tonic-gate drmach_xt_mb[cpuid] = 0x80; 37457c478bd9Sstevel@tonic-gate 37467c478bd9Sstevel@tonic-gate xt_one_unchecked(cpuid, (xcfunc_t *)idle_stop_xcall, 37477c478bd9Sstevel@tonic-gate (uint64_t)drmach_cpu_shutdown_self, NULL); 37487c478bd9Sstevel@tonic-gate 37497c478bd9Sstevel@tonic-gate ntries = drmach_cpu_ntries; 37507c478bd9Sstevel@tonic-gate cnt = 0; 37517c478bd9Sstevel@tonic-gate while (drmach_xt_mb[cpuid] && ntries) { 37527c478bd9Sstevel@tonic-gate DELAY(drmach_cpu_delay); 37537c478bd9Sstevel@tonic-gate ntries--; 37547c478bd9Sstevel@tonic-gate cnt++; 37557c478bd9Sstevel@tonic-gate } 37567c478bd9Sstevel@tonic-gate 37577c478bd9Sstevel@tonic-gate drmach_xt_mb[cpuid] = 0; /* steal the cache line back */ 37587c478bd9Sstevel@tonic-gate 37597c478bd9Sstevel@tonic-gate start_cpus(); 37607c478bd9Sstevel@tonic-gate 37617c478bd9Sstevel@tonic-gate DRMACH_PR("waited %d out of %d tries for " 37627c478bd9Sstevel@tonic-gate "drmach_cpu_shutdown_self on cpu%d", 37637c478bd9Sstevel@tonic-gate drmach_cpu_ntries - ntries, drmach_cpu_ntries, cp->cpu_id); 37647c478bd9Sstevel@tonic-gate 37657c478bd9Sstevel@tonic-gate drmach_cpu_obp_detach(cpuid); 37667c478bd9Sstevel@tonic-gate 37677c478bd9Sstevel@tonic-gate CPU_SIGNATURE(OS_SIG, SIGST_DETACHED, SIGSUBST_NULL, cpuid); 37687c478bd9Sstevel@tonic-gate 37697c478bd9Sstevel@tonic-gate return (0); 37707c478bd9Sstevel@tonic-gate } 37717c478bd9Sstevel@tonic-gate 37727c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 37737c478bd9Sstevel@tonic-gate int 37747c478bd9Sstevel@tonic-gate drmach_verify_sr(dev_info_t *dip, int sflag) 37757c478bd9Sstevel@tonic-gate { 37767c478bd9Sstevel@tonic-gate return (0); 37777c478bd9Sstevel@tonic-gate } 37787c478bd9Sstevel@tonic-gate 37797c478bd9Sstevel@tonic-gate void 37807c478bd9Sstevel@tonic-gate drmach_suspend_last(void) 37817c478bd9Sstevel@tonic-gate { 37827c478bd9Sstevel@tonic-gate } 37837c478bd9Sstevel@tonic-gate 37847c478bd9Sstevel@tonic-gate void 37857c478bd9Sstevel@tonic-gate drmach_resume_first(void) 37867c478bd9Sstevel@tonic-gate { 37877c478bd9Sstevel@tonic-gate } 37887c478bd9Sstevel@tonic-gate 37897c478bd9Sstevel@tonic-gate /* 37907c478bd9Sstevel@tonic-gate * Log a DR sysevent. 37917c478bd9Sstevel@tonic-gate * Return value: 0 success, non-zero failure. 37927c478bd9Sstevel@tonic-gate */ 37937c478bd9Sstevel@tonic-gate int 37947c478bd9Sstevel@tonic-gate drmach_log_sysevent(int board, char *hint, int flag, int verbose) 37957c478bd9Sstevel@tonic-gate { 37967c478bd9Sstevel@tonic-gate sysevent_t *ev; 37977c478bd9Sstevel@tonic-gate sysevent_id_t eid; 37987c478bd9Sstevel@tonic-gate int rv, km_flag; 37997c478bd9Sstevel@tonic-gate sysevent_value_t evnt_val; 38007c478bd9Sstevel@tonic-gate sysevent_attr_list_t *evnt_attr_list = NULL; 38017c478bd9Sstevel@tonic-gate char attach_pnt[MAXNAMELEN]; 38027c478bd9Sstevel@tonic-gate 38037c478bd9Sstevel@tonic-gate km_flag = (flag == SE_SLEEP) ? KM_SLEEP : KM_NOSLEEP; 38047c478bd9Sstevel@tonic-gate attach_pnt[0] = '\0'; 38057c478bd9Sstevel@tonic-gate if (drmach_board_name(board, attach_pnt, MAXNAMELEN)) { 38067c478bd9Sstevel@tonic-gate rv = -1; 38077c478bd9Sstevel@tonic-gate goto logexit; 38087c478bd9Sstevel@tonic-gate } 38097c478bd9Sstevel@tonic-gate if (verbose) 38107c478bd9Sstevel@tonic-gate DRMACH_PR("drmach_log_sysevent: %s %s, flag: %d, verbose: %d\n", 38117c478bd9Sstevel@tonic-gate attach_pnt, hint, flag, verbose); 38127c478bd9Sstevel@tonic-gate 38137c478bd9Sstevel@tonic-gate if ((ev = sysevent_alloc(EC_DR, ESC_DR_AP_STATE_CHANGE, 38147c478bd9Sstevel@tonic-gate SUNW_KERN_PUB"dr", km_flag)) == NULL) { 38157c478bd9Sstevel@tonic-gate rv = -2; 38167c478bd9Sstevel@tonic-gate goto logexit; 38177c478bd9Sstevel@tonic-gate } 38187c478bd9Sstevel@tonic-gate evnt_val.value_type = SE_DATA_TYPE_STRING; 38197c478bd9Sstevel@tonic-gate evnt_val.value.sv_string = attach_pnt; 38207c478bd9Sstevel@tonic-gate if ((rv = sysevent_add_attr(&evnt_attr_list, DR_AP_ID, 38217c478bd9Sstevel@tonic-gate &evnt_val, km_flag)) != 0) 38227c478bd9Sstevel@tonic-gate goto logexit; 38237c478bd9Sstevel@tonic-gate 38247c478bd9Sstevel@tonic-gate evnt_val.value_type = SE_DATA_TYPE_STRING; 38257c478bd9Sstevel@tonic-gate evnt_val.value.sv_string = hint; 38267c478bd9Sstevel@tonic-gate if ((rv = sysevent_add_attr(&evnt_attr_list, DR_HINT, 38277c478bd9Sstevel@tonic-gate &evnt_val, km_flag)) != 0) { 38287c478bd9Sstevel@tonic-gate sysevent_free_attr(evnt_attr_list); 38297c478bd9Sstevel@tonic-gate goto logexit; 38307c478bd9Sstevel@tonic-gate } 38317c478bd9Sstevel@tonic-gate 38327c478bd9Sstevel@tonic-gate (void) sysevent_attach_attributes(ev, evnt_attr_list); 38337c478bd9Sstevel@tonic-gate 38347c478bd9Sstevel@tonic-gate /* 38357c478bd9Sstevel@tonic-gate * Log the event but do not sleep waiting for its 38367c478bd9Sstevel@tonic-gate * delivery. This provides insulation from syseventd. 38377c478bd9Sstevel@tonic-gate */ 38387c478bd9Sstevel@tonic-gate rv = log_sysevent(ev, SE_NOSLEEP, &eid); 38397c478bd9Sstevel@tonic-gate 38407c478bd9Sstevel@tonic-gate logexit: 38417c478bd9Sstevel@tonic-gate if (ev) 38427c478bd9Sstevel@tonic-gate sysevent_free(ev); 38437c478bd9Sstevel@tonic-gate if ((rv != 0) && verbose) 38447c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 38457c478bd9Sstevel@tonic-gate "drmach_log_sysevent failed (rv %d) for %s %s\n", 38467c478bd9Sstevel@tonic-gate rv, attach_pnt, hint); 38477c478bd9Sstevel@tonic-gate 38487c478bd9Sstevel@tonic-gate return (rv); 38497c478bd9Sstevel@tonic-gate } 38507c478bd9Sstevel@tonic-gate 38517c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 38527c478bd9Sstevel@tonic-gate int 38537c478bd9Sstevel@tonic-gate drmach_allow_memrange_modify(drmachid_t id) 38547c478bd9Sstevel@tonic-gate { 38557c478bd9Sstevel@tonic-gate return (1); /* TRUE */ 38567c478bd9Sstevel@tonic-gate } 3857