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