103831d35Sstevel /* 203831d35Sstevel * CDDL HEADER START 303831d35Sstevel * 403831d35Sstevel * The contents of this file are subject to the terms of the 503831d35Sstevel * Common Development and Distribution License (the "License"). 603831d35Sstevel * You may not use this file except in compliance with the License. 703831d35Sstevel * 803831d35Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 903831d35Sstevel * or http://www.opensolaris.org/os/licensing. 1003831d35Sstevel * See the License for the specific language governing permissions 1103831d35Sstevel * and limitations under the License. 1203831d35Sstevel * 1303831d35Sstevel * When distributing Covered Code, include this CDDL HEADER in each 1403831d35Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1503831d35Sstevel * If applicable, add the following below this CDDL HEADER, with the 1603831d35Sstevel * fields enclosed by brackets "[]" replaced with your own identifying 1703831d35Sstevel * information: Portions Copyright [yyyy] [name of copyright owner] 1803831d35Sstevel * 1903831d35Sstevel * CDDL HEADER END 2003831d35Sstevel */ 2103831d35Sstevel 2203831d35Sstevel /* 23*07d06da5SSurya Prakki * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 2403831d35Sstevel * Use is subject to license terms. 2503831d35Sstevel */ 2603831d35Sstevel 2703831d35Sstevel #include <sys/types.h> 2803831d35Sstevel #include <sys/cmn_err.h> 2903831d35Sstevel #include <sys/conf.h> 3003831d35Sstevel #include <sys/ddi_impldefs.h> 3103831d35Sstevel #include <sys/autoconf.h> 3203831d35Sstevel #include <sys/systm.h> 3303831d35Sstevel #include <sys/modctl.h> 3403831d35Sstevel #include <sys/ddi.h> 3503831d35Sstevel #include <sys/sunddi.h> 3603831d35Sstevel #include <sys/sunndi.h> 3703831d35Sstevel #include <sys/ndi_impldefs.h> 3803831d35Sstevel #include <sys/promif.h> 3903831d35Sstevel #include <sys/stat.h> 4003831d35Sstevel #include <sys/kmem.h> 4103831d35Sstevel #include <sys/promif.h> 4203831d35Sstevel #include <sys/conf.h> 4303831d35Sstevel #include <sys/obpdefs.h> 4403831d35Sstevel #include <sys/cpuvar.h> 4503831d35Sstevel #include <vm/seg_kmem.h> 4603831d35Sstevel #include <sys/prom_plat.h> 4703831d35Sstevel #include <sys/machsystm.h> 4803831d35Sstevel #include <sys/note.h> 4903831d35Sstevel #include <sys/memlist.h> 5003831d35Sstevel #include <sys/ssm.h> 5103831d35Sstevel 5203831d35Sstevel #include <sys/sbd_ioctl.h> 5303831d35Sstevel #include <sys/sbd.h> 5403831d35Sstevel #include <sys/sbdp_priv.h> 5503831d35Sstevel #include <sys/sbdp_mem.h> 5603831d35Sstevel #include <sys/sbdp_error.h> 5703831d35Sstevel #include <sys/serengeti.h> 5803831d35Sstevel 5903831d35Sstevel #include <sys/sgsbbc.h> /* To get fn_t type definition */ 6003831d35Sstevel 6103831d35Sstevel /* 6203831d35Sstevel * Config information 6303831d35Sstevel */ 6403831d35Sstevel #ifdef DEBUG 6503831d35Sstevel uint_t sbdp_debug = 0x0; 6603831d35Sstevel #endif /* DEBUG */ 6703831d35Sstevel 6803831d35Sstevel /* 6903831d35Sstevel * Enable or disable dr 7003831d35Sstevel */ 7103831d35Sstevel int sbdp_dr_available = 1; 7203831d35Sstevel 7303831d35Sstevel /* name properties for some Serengeti device nodes */ 7403831d35Sstevel #define CMP_DEVNAME "cmp" 7503831d35Sstevel #define MEM_DEVNAME "memory" 7603831d35Sstevel #define CPU_DEVNAME "cpu" 7703831d35Sstevel #define IO_PCI_DEVNAME "pci" 7803831d35Sstevel #define IO_SGHSC_DEVNAME "sghsc" 7903831d35Sstevel #define IO_WCI_DEVNAME "wci" 8003831d35Sstevel 8103831d35Sstevel static sbd_devattr_t sbdp_devattr[] = { 8203831d35Sstevel { CMP_DEVNAME, "cmp", SBD_COMP_CMP }, 8303831d35Sstevel { MEM_DEVNAME, "memory-controller", SBD_COMP_MEM }, 8403831d35Sstevel { CPU_DEVNAME, "cpu", SBD_COMP_CPU }, 8503831d35Sstevel { IO_PCI_DEVNAME, "pci", SBD_COMP_IO }, 8603831d35Sstevel { IO_SGHSC_DEVNAME, "sghsc", SBD_COMP_IO }, 8703831d35Sstevel { IO_WCI_DEVNAME, "wci", SBD_COMP_IO }, 8803831d35Sstevel /* last item must be blank */ 8903831d35Sstevel { NULL, NULL, SBD_COMP_UNKNOWN } 9003831d35Sstevel }; 9103831d35Sstevel 9203831d35Sstevel /* 9303831d35Sstevel * In the case of a busy mbox, if a status cmd comes in we return a cached 9403831d35Sstevel * copy. This cache is a link list of wnodes that contains bd structs with 9503831d35Sstevel * the appropriate info. When a new wnode is created a whole entry is added 9603831d35Sstevel * to the list. 9703831d35Sstevel */ 9803831d35Sstevel sbdp_wnode_t *first_node = NULL; /* first wnode. Entry to the link list */ 9903831d35Sstevel int cur_num_wnodes = 0; /* how many nodes are currently running */ 10003831d35Sstevel 10103831d35Sstevel /* Macros to access fields in the previous array */ 10203831d35Sstevel #define SBDP_CT(i) sbdp_devattr[i].s_dnodetype 10303831d35Sstevel #define SBDP_DEVNAME(i) sbdp_devattr[(i)].s_devname 10403831d35Sstevel #define SBDP_OTYPE(i) sbdp_devattr[(i)].s_obp_type 10503831d35Sstevel 10603831d35Sstevel /* 10703831d35Sstevel * Prototypes 10803831d35Sstevel */ 10903831d35Sstevel sbdp_wnode_t *sbdp_get_wnodep(int); 11003831d35Sstevel 11103831d35Sstevel /* 11203831d35Sstevel * Module linkage information for the kernel. 11303831d35Sstevel */ 11403831d35Sstevel 11503831d35Sstevel static struct modlmisc modlmisc = { 11603831d35Sstevel &mod_miscops, 11703831d35Sstevel "Serengeti sbdp", 11803831d35Sstevel }; 11903831d35Sstevel 12003831d35Sstevel static struct modlinkage modlinkage = { 12103831d35Sstevel MODREV_1, 12203831d35Sstevel (void *)&modlmisc, 12303831d35Sstevel NULL 12403831d35Sstevel }; 12503831d35Sstevel 12603831d35Sstevel /* 12703831d35Sstevel * VA area used during CPU shutdown. 12803831d35Sstevel */ 12903831d35Sstevel caddr_t sbdp_shutdown_va; 13003831d35Sstevel 13103831d35Sstevel /* 13203831d35Sstevel * Mutex to protect our inventory 13303831d35Sstevel */ 13403831d35Sstevel kmutex_t sbdp_wnode_mutex; 13503831d35Sstevel 13603831d35Sstevel int 13703831d35Sstevel _init(void) 13803831d35Sstevel { 13903831d35Sstevel int e; 14003831d35Sstevel 14103831d35Sstevel e = mod_install(&modlinkage); 14203831d35Sstevel if (e != 0) 14303831d35Sstevel return (e); 14403831d35Sstevel 14503831d35Sstevel sbdp_shutdown_va = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP); 14603831d35Sstevel ASSERT(sbdp_shutdown_va != NULL); 14703831d35Sstevel sbdp_valp = (uint64_t *)vmem_alloc(static_alloc_arena, 14803831d35Sstevel sizeof (uint64_t), VM_SLEEP); 14903831d35Sstevel 15003831d35Sstevel mutex_init(&sbdp_wnode_mutex, NULL, MUTEX_DRIVER, NULL); 15103831d35Sstevel return (e); 15203831d35Sstevel } 15303831d35Sstevel 15403831d35Sstevel int 15503831d35Sstevel _fini(void) 15603831d35Sstevel { 15703831d35Sstevel int e; 15803831d35Sstevel 15903831d35Sstevel /* 16003831d35Sstevel * Remove the module. 16103831d35Sstevel */ 16203831d35Sstevel e = mod_remove(&modlinkage); 16303831d35Sstevel if (e != 0) 16403831d35Sstevel return (e); 16503831d35Sstevel 16603831d35Sstevel vmem_free(heap_arena, sbdp_shutdown_va, PAGESIZE); 16703831d35Sstevel sbdp_shutdown_va = NULL; 16803831d35Sstevel vmem_free(static_alloc_arena, (void *)sbdp_valp, sizeof (uint64_t)); 16903831d35Sstevel sbdp_valp = NULL; 17003831d35Sstevel 17103831d35Sstevel mutex_destroy(&sbdp_wnode_mutex); 17203831d35Sstevel return (e); 17303831d35Sstevel } 17403831d35Sstevel 17503831d35Sstevel int 17603831d35Sstevel _info(struct modinfo *modinfop) 17703831d35Sstevel { 17803831d35Sstevel return (mod_info(&modlinkage, modinfop)); 17903831d35Sstevel } 18003831d35Sstevel 18103831d35Sstevel int 18203831d35Sstevel sbdp_get_bd_and_wnode_num(pnode_t nodeid, int *bd, int *wnode) 18303831d35Sstevel { 18403831d35Sstevel int portid; 18503831d35Sstevel static fn_t f = "sbdp_get_bd_and_wnode_num"; 18603831d35Sstevel extern int get_portid(pnode_t node, pnode_t *cmpp); 18703831d35Sstevel 18803831d35Sstevel SBDP_DBG_FUNC("%s\n", f); 18903831d35Sstevel 19003831d35Sstevel if (sbdp_is_node_bad(nodeid)) 19103831d35Sstevel return (-1); 19203831d35Sstevel 19303831d35Sstevel if ((portid = get_portid(nodeid, NULL)) == -1) 19403831d35Sstevel return (-1); 19503831d35Sstevel 19603831d35Sstevel /* 19703831d35Sstevel * decode the board number 19803831d35Sstevel */ 19903831d35Sstevel *bd = SG_PORTID_TO_BOARD_NUM(portid); 20003831d35Sstevel *wnode = SG_PORTID_TO_NODEID(portid); 20103831d35Sstevel 20203831d35Sstevel return (0); 20303831d35Sstevel } 20403831d35Sstevel 20503831d35Sstevel int 20603831d35Sstevel sbdp_get_board_num(sbdp_handle_t *hp, dev_info_t *dip) 20703831d35Sstevel { 20803831d35Sstevel _NOTE(ARGUNUSED(hp)) 20903831d35Sstevel 21003831d35Sstevel pnode_t nodeid; 21103831d35Sstevel int bd, wnode; 21203831d35Sstevel static fn_t f = "sbdp_get_board_num"; 21303831d35Sstevel 21403831d35Sstevel SBDP_DBG_FUNC("%s\n", f); 21503831d35Sstevel 21603831d35Sstevel if (dip == NULL) 21703831d35Sstevel return (-1); 21803831d35Sstevel 21903831d35Sstevel nodeid = ddi_get_nodeid(dip); 22003831d35Sstevel 22103831d35Sstevel /* 22203831d35Sstevel * Portid has encoded the nodeid and the agent id. The top 22303831d35Sstevel * 4 bits are correspond to the wcnodeid and the lower 5 are the 22403831d35Sstevel * agent id. 22503831d35Sstevel * Each agent id represents a physical location hence we can 22603831d35Sstevel * obtain the board number 22703831d35Sstevel */ 22803831d35Sstevel if (sbdp_get_bd_and_wnode_num(nodeid, &bd, &wnode) < 0) 22903831d35Sstevel return (-1); 23003831d35Sstevel 23103831d35Sstevel return (bd); 23203831d35Sstevel } 23303831d35Sstevel 23403831d35Sstevel 23503831d35Sstevel sbd_devattr_t * 23603831d35Sstevel sbdp_get_devattr(void) 23703831d35Sstevel { 23803831d35Sstevel return (&sbdp_devattr[0]); 23903831d35Sstevel } 24003831d35Sstevel 24103831d35Sstevel int 24203831d35Sstevel sbdp_portid_to_cpu_unit(int cmp, int core) 24303831d35Sstevel { 24403831d35Sstevel return (SG_PORTID_TO_CPU_UNIT(cmp, core)); 24503831d35Sstevel } 24603831d35Sstevel 24703831d35Sstevel int 24803831d35Sstevel sbdp_get_unit_num(sbdp_handle_t *hp, dev_info_t *dip) 24903831d35Sstevel { 25003831d35Sstevel int unit = -1; 25103831d35Sstevel int portid; 25203831d35Sstevel processorid_t cpuid; 25303831d35Sstevel sbd_comp_type_t type; 25403831d35Sstevel char dev_type[OBP_MAXPROPNAME]; 25503831d35Sstevel int i; 25603831d35Sstevel pnode_t nodeid; 25703831d35Sstevel static fn_t f = "sbdp_get_unit_num"; 25803831d35Sstevel 25903831d35Sstevel SBDP_DBG_FUNC("%s\n", f); 26003831d35Sstevel 26103831d35Sstevel if (dip == NULL) 26203831d35Sstevel return (-1); 26303831d35Sstevel 26403831d35Sstevel nodeid = ddi_get_nodeid(dip); 26503831d35Sstevel 26603831d35Sstevel if (sbdp_is_node_bad(nodeid)) 26703831d35Sstevel return (-1); 26803831d35Sstevel 26903831d35Sstevel if (prom_getprop(nodeid, "device_type", (caddr_t)dev_type) < 0) { 27003831d35Sstevel SBDP_DBG_MISC("%s: couldn't get device_type\n", f); 27103831d35Sstevel return (-1); 27203831d35Sstevel } 27303831d35Sstevel 27403831d35Sstevel for (i = 0; SBDP_CT(i) != SBD_COMP_UNKNOWN; i++) { 27503831d35Sstevel if (strcmp(dev_type, SBDP_OTYPE(i)) != 0) 27603831d35Sstevel continue; 27703831d35Sstevel type = SBDP_CT(i); 27803831d35Sstevel } 27903831d35Sstevel 28003831d35Sstevel switch (type) { 28103831d35Sstevel case SBD_COMP_CPU: 28203831d35Sstevel if ((cpuid = sbdp_get_cpuid(hp, dip)) != -1) { 28303831d35Sstevel unit = SG_CPUID_TO_CPU_UNIT(cpuid); 28403831d35Sstevel } 28503831d35Sstevel break; 28603831d35Sstevel case SBD_COMP_MEM: 28703831d35Sstevel unit = 0; 28803831d35Sstevel break; 28903831d35Sstevel case SBD_COMP_IO: { 29003831d35Sstevel regspace_t regs[3]; 29103831d35Sstevel int len = 0; 29203831d35Sstevel 29303831d35Sstevel /* 29403831d35Sstevel * Check to see if this is a cpci node 29503831d35Sstevel * cpci nodes are assign unit nums of 5 for now 29603831d35Sstevel * So they don't conflict with the pci unit nums 29703831d35Sstevel */ 29803831d35Sstevel 29903831d35Sstevel if (strcmp(dev_type, "sghsc") == 0) { 30003831d35Sstevel SBDP_DBG_MISC("it is a sghsc\n"); 30103831d35Sstevel return (4); 30203831d35Sstevel } 30303831d35Sstevel 30403831d35Sstevel if (prom_getprop(nodeid, "portid", (caddr_t)&portid) <= 0) { 30503831d35Sstevel SBDP_DBG_MISC("%s: couldn't get portid\n", f); 30603831d35Sstevel return (-1); 30703831d35Sstevel } 30803831d35Sstevel 30903831d35Sstevel len = prom_getproplen(nodeid, "reg"); 31003831d35Sstevel if (len <= 0) { 31103831d35Sstevel SBDP_DBG_MISC("%s: couldn't get length\n", f); 31203831d35Sstevel return (-1); 31303831d35Sstevel } 31403831d35Sstevel 31503831d35Sstevel if (prom_getprop(nodeid, "reg", (caddr_t)regs) < 0) { 31603831d35Sstevel SBDP_DBG_MISC("%s: couldn't get registers\n", f); 31703831d35Sstevel return (-1); 31803831d35Sstevel } 31903831d35Sstevel 32003831d35Sstevel if ((portid % 2) != 0) 32103831d35Sstevel if ((regs[0].regspec_addr_lo & 0x700000) == 32203831d35Sstevel 0x700000) 32303831d35Sstevel unit = 0; 32403831d35Sstevel else 32503831d35Sstevel unit = 1; 32603831d35Sstevel else 32703831d35Sstevel if ((regs[0].regspec_addr_lo & 0x700000) == 32803831d35Sstevel 0x700000) 32903831d35Sstevel unit = 2; 33003831d35Sstevel else 33103831d35Sstevel unit = 3; 33203831d35Sstevel 33303831d35Sstevel SBDP_DBG_MISC("unit is %d\n", unit); 33403831d35Sstevel break; 33503831d35Sstevel } 33603831d35Sstevel default: 33703831d35Sstevel break; 33803831d35Sstevel 33903831d35Sstevel } 34003831d35Sstevel 34103831d35Sstevel return (unit); 34203831d35Sstevel } 34303831d35Sstevel 34403831d35Sstevel struct sbdp_mem_dip { 34503831d35Sstevel sbdp_bd_t *bdp; 34603831d35Sstevel dev_info_t *dip; 34703831d35Sstevel }; 34803831d35Sstevel 34903831d35Sstevel static int 35003831d35Sstevel sbdp_get_mem_dip(pnode_t node, void *arg, uint_t flags) 35103831d35Sstevel { 35203831d35Sstevel _NOTE(ARGUNUSED(flags)) 35303831d35Sstevel 35403831d35Sstevel struct sbdp_mem_dip *smdp = (struct sbdp_mem_dip *)arg; 35503831d35Sstevel mem_op_t mem = {0}; 35603831d35Sstevel 35703831d35Sstevel if (node == OBP_NONODE || node == OBP_BADNODE) 35803831d35Sstevel return (DDI_FAILURE); 35903831d35Sstevel 36003831d35Sstevel mem.nodes = smdp->bdp->nodes; 36103831d35Sstevel mem.board = smdp->bdp->bd; 36203831d35Sstevel mem.nmem = smdp->bdp->nnum; 36303831d35Sstevel 36403831d35Sstevel (void) sbdp_is_mem(node, &mem); 36503831d35Sstevel 36603831d35Sstevel /* 36703831d35Sstevel * We need to find the dip only for the first nodeid 36803831d35Sstevel */ 36903831d35Sstevel if (smdp->bdp->nnum == 0 && mem.nmem == 1) { 37003831d35Sstevel ASSERT(smdp->dip == NULL); 37103831d35Sstevel smdp->dip = e_ddi_nodeid_to_dip(node); 37203831d35Sstevel } 37303831d35Sstevel 37403831d35Sstevel smdp->bdp->nnum = mem.nmem; 37503831d35Sstevel 37603831d35Sstevel return (DDI_SUCCESS); 37703831d35Sstevel } 37803831d35Sstevel 37903831d35Sstevel 38003831d35Sstevel /* 38103831d35Sstevel * Update the board info. Required after a copy rename 38203831d35Sstevel */ 38303831d35Sstevel void 38403831d35Sstevel sbdp_update_bd_info(sbdp_bd_t *bdp) 38503831d35Sstevel { 38603831d35Sstevel attach_pkt_t apkt, *apktp = &apkt; 38703831d35Sstevel struct sbdp_mem_dip smd = {0}; 38803831d35Sstevel static fn_t f = "sbdp_update_bd_info"; 38903831d35Sstevel 39003831d35Sstevel SBDP_DBG_FUNC("%s\n", f); 39103831d35Sstevel 39203831d35Sstevel if (bdp == NULL) { 39303831d35Sstevel return; 39403831d35Sstevel } 39503831d35Sstevel /* 39603831d35Sstevel * Grab the lock 39703831d35Sstevel */ 39803831d35Sstevel mutex_enter(&bdp->bd_mutex); 39903831d35Sstevel 40003831d35Sstevel /* 40103831d35Sstevel * we get the top nodes here. This will have a side effect of 40203831d35Sstevel * updating the present bit for cpus 40303831d35Sstevel */ 40403831d35Sstevel apktp->node = bdp->wnode; 40503831d35Sstevel apktp->board = bdp->bd; 40603831d35Sstevel apktp->num_of_nodes = 0; 40703831d35Sstevel apktp->flags = 0; 40803831d35Sstevel sbdp_walk_prom_tree(prom_rootnode(), sbdp_select_top_nodes, 40903831d35Sstevel (void *) apktp); 41003831d35Sstevel 41103831d35Sstevel /* 41203831d35Sstevel * We need to clear nnum since we are looking again for the 41303831d35Sstevel * nodes 41403831d35Sstevel */ 41503831d35Sstevel bdp->nnum = 0; 41603831d35Sstevel smd.bdp = bdp; 41703831d35Sstevel 41803831d35Sstevel /* 41903831d35Sstevel * If a dip is found by sbdp_get_mem_dip(), it will be 42003831d35Sstevel * returned held 42103831d35Sstevel */ 42203831d35Sstevel sbdp_walk_prom_tree(prom_rootnode(), sbdp_get_mem_dip, &smd); 42303831d35Sstevel if (smd.dip != NULL) { 42403831d35Sstevel sbdp_handle_t *hp; 42503831d35Sstevel 42603831d35Sstevel hp = kmem_zalloc(sizeof (sbdp_handle_t), KM_SLEEP); 42703831d35Sstevel hp->h_board = bdp->bd; 42803831d35Sstevel hp->h_wnode = bdp->wnode; 42903831d35Sstevel hp->h_err = kmem_zalloc(sizeof (*hp->h_err), KM_SLEEP); 43003831d35Sstevel if (bdp->ml != NULL) { 431*07d06da5SSurya Prakki (void) sbdp_del_memlist(hp, bdp->ml); 43203831d35Sstevel } 43303831d35Sstevel bdp->ml = sbdp_get_memlist(hp, (dev_info_t *)NULL); 43403831d35Sstevel /* 43503831d35Sstevel * if the board doesn't have banks initialize them, 43603831d35Sstevel * otherwise we assume they have been updated if 43703831d35Sstevel * necessary 43803831d35Sstevel */ 43903831d35Sstevel if (bdp->banks == NULL) { 44003831d35Sstevel sbdp_init_bd_banks(bdp); 44103831d35Sstevel } 44203831d35Sstevel #ifdef DEBUG 44303831d35Sstevel sbdp_print_bd_banks(bdp); 44403831d35Sstevel #endif 44503831d35Sstevel 44603831d35Sstevel if (sbdphw_get_base_physaddr(hp, smd.dip, &bdp->bpa)) 44703831d35Sstevel bdp->bpa = -1; 44803831d35Sstevel ddi_release_devi(smd.dip); 44903831d35Sstevel kmem_free(hp->h_err, sizeof (*hp->h_err)); 45003831d35Sstevel kmem_free(hp, sizeof (sbdp_handle_t)); 45103831d35Sstevel } 45203831d35Sstevel mutex_exit(&bdp->bd_mutex); 45303831d35Sstevel } 45403831d35Sstevel 45503831d35Sstevel /* 45603831d35Sstevel * Initialize the board struct. This remains cached. We update it 45703831d35Sstevel * every time we have a successful show_board and after a copy-rename 45803831d35Sstevel */ 45903831d35Sstevel void 46003831d35Sstevel sbdp_bd_init(sbdp_bd_t *bdp, int bd, int wnode) 46103831d35Sstevel { 46203831d35Sstevel static fn_t f = "sbdp_bd_init"; 46303831d35Sstevel 46403831d35Sstevel SBDP_DBG_FUNC("%s\n", f); 46503831d35Sstevel 46603831d35Sstevel bdp->bd = bd; 46703831d35Sstevel bdp->wnode = wnode; 46803831d35Sstevel 46903831d35Sstevel SBDP_UNSET_ALL_CPUS_IN_RESET(bdp); 47003831d35Sstevel 47103831d35Sstevel bdp->cpus_present = 0; 47203831d35Sstevel 47303831d35Sstevel sbdp_update_bd_info(bdp); 47403831d35Sstevel 47503831d35Sstevel mutex_init(&bdp->bd_mutex, NULL, MUTEX_DRIVER, NULL); 47603831d35Sstevel bdp->bd_sc = (show_board_t *)kmem_zalloc(sizeof (show_board_t), 47703831d35Sstevel KM_SLEEP); 47803831d35Sstevel bdp->valid_cp = -1; 47903831d35Sstevel } 48003831d35Sstevel 48103831d35Sstevel /* 48203831d35Sstevel * This entry is going away. Clean up 48303831d35Sstevel */ 48403831d35Sstevel void 48503831d35Sstevel sbdp_bd_fini(sbdp_bd_t *bdp) 48603831d35Sstevel { 48703831d35Sstevel static fn_t f = "sbdp_bd_fini"; 48803831d35Sstevel 48903831d35Sstevel SBDP_DBG_FUNC("%s\n", f); 49003831d35Sstevel 49103831d35Sstevel sbdp_cleanup_bd(bdp->wnode, bdp->bd); 49203831d35Sstevel kmem_free(bdp->bd_sc, sizeof (show_board_t)); 49303831d35Sstevel bdp->bd_sc = NULL; 49403831d35Sstevel mutex_destroy(&bdp->bd_mutex); 49503831d35Sstevel #ifdef DEBUG 49603831d35Sstevel sbdp_print_all_segs(); 49703831d35Sstevel #endif 49803831d35Sstevel } 49903831d35Sstevel 50003831d35Sstevel /* 50103831d35Sstevel * A new wnode has arrived. Initialize the struct and create 50203831d35Sstevel * the board structures. 50303831d35Sstevel */ 50403831d35Sstevel void 50503831d35Sstevel sbdp_wnode_init(sbdp_wnode_t *wnodep, int wnode, int boards) 50603831d35Sstevel { 50703831d35Sstevel int i; 50803831d35Sstevel static fn_t f = "sbdp_wnode_init"; 50903831d35Sstevel 51003831d35Sstevel SBDP_DBG_FUNC("%s\n", f); 51103831d35Sstevel 51203831d35Sstevel wnodep->wnode = wnode; 51303831d35Sstevel wnodep->nbds = boards; 51403831d35Sstevel wnodep->bds = kmem_zalloc(sizeof (sbdp_bd_t) * boards, KM_SLEEP); 51503831d35Sstevel wnodep->next = wnodep->prev = NULL; 51603831d35Sstevel 51703831d35Sstevel for (i = 0; i < boards; i++) 51803831d35Sstevel sbdp_bd_init(&wnodep->bds[i], i, wnode); 51903831d35Sstevel } 52003831d35Sstevel 52103831d35Sstevel /* 52203831d35Sstevel * Wnode got DRed out. Clean up all the node stuff including the boards 52303831d35Sstevel */ 52403831d35Sstevel void 52503831d35Sstevel sbdp_wnode_fini(sbdp_wnode_t *wnodep) 52603831d35Sstevel { 52703831d35Sstevel int boards; 52803831d35Sstevel int i; 52903831d35Sstevel static fn_t f = "sbdp_wnode_fini"; 53003831d35Sstevel 53103831d35Sstevel SBDP_DBG_FUNC("%s\n", f); 53203831d35Sstevel 53303831d35Sstevel boards = wnodep->nbds; 53403831d35Sstevel 53503831d35Sstevel for (i = 0; i < boards; i++) 53603831d35Sstevel sbdp_bd_fini(&wnodep->bds[i]); 53703831d35Sstevel 53803831d35Sstevel kmem_free(wnodep->bds, sizeof (sbdp_bd_t) * boards); 53903831d35Sstevel wnodep->next = wnodep->prev = NULL; 54003831d35Sstevel kmem_free(wnodep, sizeof (sbdp_wnode_t)); 54103831d35Sstevel } 54203831d35Sstevel 54303831d35Sstevel /* 54403831d35Sstevel * Add all the necessary fields to this board's struct 54503831d35Sstevel */ 54603831d35Sstevel void 54703831d35Sstevel sbdp_add_new_bd_info(int wnode, int board) 54803831d35Sstevel { 54903831d35Sstevel sbdp_wnode_t *cur; 55003831d35Sstevel static fn_t f = "sbdp_add_new_bd_info"; 55103831d35Sstevel 55203831d35Sstevel SBDP_DBG_FUNC("%s\n", f); 55303831d35Sstevel 55403831d35Sstevel cur = sbdp_get_wnodep(wnode); 55503831d35Sstevel 55603831d35Sstevel SBDP_DBG_MISC("adding new board info %d\n", board); 55703831d35Sstevel 55803831d35Sstevel sbdp_update_bd_info(&cur->bds[board]); 55903831d35Sstevel 56003831d35Sstevel } 56103831d35Sstevel 56203831d35Sstevel /* 56303831d35Sstevel * This board has gone away. Clean the necessary fields 56403831d35Sstevel */ 56503831d35Sstevel void 56603831d35Sstevel sbdp_cleanup_bd(int wnode, int board) 56703831d35Sstevel { 56803831d35Sstevel sbdp_wnode_t *cur; 56903831d35Sstevel sbdp_handle_t handle, *hp; 57003831d35Sstevel sbdp_bd_t *bdp; 57103831d35Sstevel int i; 57203831d35Sstevel static fn_t f = "sbdp_cleanup_bd"; 57303831d35Sstevel 57403831d35Sstevel SBDP_DBG_FUNC("%s\n", f); 57503831d35Sstevel 57603831d35Sstevel cur = sbdp_get_wnodep(wnode); 57703831d35Sstevel 57803831d35Sstevel SBDP_DBG_MISC("cleaning up bd info for bd %d\n", board); 57903831d35Sstevel if (cur == NULL) { 58003831d35Sstevel SBDP_DBG_MISC("cur is null\n"); 58103831d35Sstevel return; 58203831d35Sstevel } 58303831d35Sstevel 58403831d35Sstevel bdp = &cur->bds[board]; 58503831d35Sstevel 58603831d35Sstevel /* 58703831d35Sstevel * Grab the lock 58803831d35Sstevel */ 58903831d35Sstevel mutex_enter(&bdp->bd_mutex); 59003831d35Sstevel 59103831d35Sstevel for (i = 0; i < bdp->nnum; i++) 59203831d35Sstevel bdp->nodes[i] = (pnode_t)0; 59303831d35Sstevel bdp->nnum = 0; 59403831d35Sstevel 59503831d35Sstevel sbdp_fini_bd_banks(bdp); 59603831d35Sstevel 59703831d35Sstevel hp = &handle; 59803831d35Sstevel hp->h_board = bdp->bd; 59903831d35Sstevel hp->h_wnode = bdp->wnode; 60003831d35Sstevel if (bdp->ml) { 601*07d06da5SSurya Prakki (void) sbdp_del_memlist(hp, bdp->ml); 60203831d35Sstevel } 60303831d35Sstevel 60403831d35Sstevel bdp->ml = NULL; 60503831d35Sstevel 60603831d35Sstevel bdp->bpa = -1; 60703831d35Sstevel 60803831d35Sstevel sbdp_cpu_in_reset(wnode, bdp->bd, SBDP_ALL_CPUS, 0); 60903831d35Sstevel 61003831d35Sstevel bdp->cpus_present = 0; 61103831d35Sstevel 61203831d35Sstevel mutex_exit(&bdp->bd_mutex); 61303831d35Sstevel } 61403831d35Sstevel 61503831d35Sstevel /* 61603831d35Sstevel * Traverse the list looking for wnode. Return it when found 61703831d35Sstevel */ 61803831d35Sstevel sbdp_wnode_t * 61903831d35Sstevel sbdp_get_wnodep(int wnode) 62003831d35Sstevel { 62103831d35Sstevel sbdp_wnode_t *cur; 62203831d35Sstevel int i; 62303831d35Sstevel static fn_t f = "sbdp_get_wnodep"; 62403831d35Sstevel 62503831d35Sstevel SBDP_DBG_FUNC("%s\n", f); 62603831d35Sstevel 62703831d35Sstevel mutex_enter(&sbdp_wnode_mutex); 62803831d35Sstevel for (i = 0, cur = first_node; i < cur_num_wnodes; i++, 62903831d35Sstevel cur = cur->next) { 63003831d35Sstevel if (cur->wnode == wnode) { 63103831d35Sstevel mutex_exit(&sbdp_wnode_mutex); 63203831d35Sstevel return (cur); 63303831d35Sstevel } 63403831d35Sstevel } 63503831d35Sstevel mutex_exit(&sbdp_wnode_mutex); 63603831d35Sstevel 63703831d35Sstevel return (NULL); 63803831d35Sstevel } 63903831d35Sstevel 64003831d35Sstevel /* 64103831d35Sstevel * Insert this brand new node into our master list. It leaves it all 64203831d35Sstevel * initialized 64303831d35Sstevel */ 64403831d35Sstevel void 64503831d35Sstevel sbdp_insert_wnode(int wnode, int max_boards) 64603831d35Sstevel { 64703831d35Sstevel sbdp_wnode_t *wnodep; 64803831d35Sstevel sbdp_wnode_t *cur; 64903831d35Sstevel static fn_t f = "sbdp_insert_wnode"; 65003831d35Sstevel 65103831d35Sstevel SBDP_DBG_FUNC("%s\n", f); 65203831d35Sstevel 65303831d35Sstevel wnodep = kmem_zalloc(sizeof (sbdp_wnode_t), KM_SLEEP); 65403831d35Sstevel 65503831d35Sstevel mutex_enter(&sbdp_wnode_mutex); 65603831d35Sstevel if (first_node == NULL) { 65703831d35Sstevel first_node = wnodep; 65803831d35Sstevel cur_num_wnodes++; 65903831d35Sstevel } else { 66003831d35Sstevel cur = first_node + cur_num_wnodes++; 66103831d35Sstevel cur->next = wnodep; 66203831d35Sstevel wnodep->prev = cur; 66303831d35Sstevel } 66403831d35Sstevel mutex_exit(&sbdp_wnode_mutex); 66503831d35Sstevel sbdp_wnode_init(wnodep, wnode, max_boards); 66603831d35Sstevel } 66703831d35Sstevel 66803831d35Sstevel /* 66903831d35Sstevel * This node is gone. Remove it from the list and also clean up 67003831d35Sstevel */ 67103831d35Sstevel void 67203831d35Sstevel sbdp_remove_wnode(sbdp_wnode_t *wnodep) 67303831d35Sstevel { 67403831d35Sstevel sbdp_wnode_t *cur; 67503831d35Sstevel static fn_t f = "sbdp_remove_wnode"; 67603831d35Sstevel 67703831d35Sstevel SBDP_DBG_FUNC("%s\n", f); 67803831d35Sstevel 67903831d35Sstevel if (wnodep != NULL) { 68003831d35Sstevel sbdp_wnode_fini(wnodep); 68103831d35Sstevel mutex_enter(&sbdp_wnode_mutex); 68203831d35Sstevel 68303831d35Sstevel if (first_node == wnodep) 68403831d35Sstevel first_node = NULL; 68503831d35Sstevel else { 68603831d35Sstevel cur = wnodep->prev; 68703831d35Sstevel if (cur != NULL) 68803831d35Sstevel cur->next = wnodep->next; 68903831d35Sstevel if (wnodep->next != NULL) 69003831d35Sstevel wnodep->next->prev = cur; 69103831d35Sstevel } 69203831d35Sstevel 69303831d35Sstevel cur_num_wnodes--; 69403831d35Sstevel mutex_exit(&sbdp_wnode_mutex); 69503831d35Sstevel } 69603831d35Sstevel } 69703831d35Sstevel 69803831d35Sstevel /* 69903831d35Sstevel * Entry point from sbd. This is called when a new node is added. We 70003831d35Sstevel * create an entry in our inventory and initialize all the stuff that will be 70103831d35Sstevel * needed 70203831d35Sstevel */ 70303831d35Sstevel int 70403831d35Sstevel sbdp_setup_instance(caddr_t arg) 70503831d35Sstevel { 70603831d35Sstevel ssm_sbdp_info_t *sbdp_info; 70703831d35Sstevel int instance; 70803831d35Sstevel int wnode; 70903831d35Sstevel int max_boards; 71003831d35Sstevel static fn_t f = "sbdp_setup_instance"; 71103831d35Sstevel 71203831d35Sstevel SBDP_DBG_FUNC("%s\n", f); 71303831d35Sstevel 71403831d35Sstevel /* 71503831d35Sstevel * We get this directly from ssm 71603831d35Sstevel */ 71703831d35Sstevel sbdp_info = (ssm_sbdp_info_t *)arg; 71803831d35Sstevel 71903831d35Sstevel instance = sbdp_info->instance; 72003831d35Sstevel wnode = sbdp_info->wnode; 72103831d35Sstevel max_boards = plat_max_boards(); 72203831d35Sstevel 72303831d35Sstevel SBDP_DBG_MISC("sbdp_setup_instance: instance %d wnode %d\n", instance, 72403831d35Sstevel sbdp_info->wnode); 72503831d35Sstevel 72603831d35Sstevel if (sbdp_get_wnodep(wnode) == NULL) { 72703831d35Sstevel /* 72803831d35Sstevel * This node has not been instanstiated 72903831d35Sstevel * create one 73003831d35Sstevel */ 73103831d35Sstevel sbdp_insert_wnode(wnode, max_boards); 73203831d35Sstevel } 73303831d35Sstevel 73403831d35Sstevel return (DDI_SUCCESS); 73503831d35Sstevel } 73603831d35Sstevel 73703831d35Sstevel /* 73803831d35Sstevel * Entry point from sbd. This is called when a node has been removed (or is 73903831d35Sstevel * going away. We do all the necessary cleanup 74003831d35Sstevel */ 74103831d35Sstevel int 74203831d35Sstevel sbdp_teardown_instance(caddr_t arg) 74303831d35Sstevel { 74403831d35Sstevel ssm_sbdp_info_t *sbdp_info; 74503831d35Sstevel int instance; 74603831d35Sstevel int wnode; 74703831d35Sstevel sbdp_wnode_t *wnodep; 74803831d35Sstevel static fn_t f = "sbdp_teardown_instance"; 74903831d35Sstevel 75003831d35Sstevel SBDP_DBG_FUNC("%s\n", f); 75103831d35Sstevel 75203831d35Sstevel /* 75303831d35Sstevel * ssm should have set this up 75403831d35Sstevel */ 75503831d35Sstevel sbdp_info = (ssm_sbdp_info_t *)arg; 75603831d35Sstevel 75703831d35Sstevel instance = sbdp_info->instance; 75803831d35Sstevel wnode = sbdp_info->wnode; 75903831d35Sstevel 76003831d35Sstevel SBDP_DBG_MISC("sbdp_teardown_instance: instance %d wnode %d\n", 76103831d35Sstevel instance, wnode); 76203831d35Sstevel 76303831d35Sstevel /* 76403831d35Sstevel * Find this node and then remove it 76503831d35Sstevel */ 76603831d35Sstevel if ((wnodep = sbdp_get_wnodep(wnode)) != NULL) { 76703831d35Sstevel sbdp_remove_wnode(wnodep); 76803831d35Sstevel } 76903831d35Sstevel return (DDI_SUCCESS); 77003831d35Sstevel } 77103831d35Sstevel 77203831d35Sstevel int 77303831d35Sstevel sbdp_disabled_component(sbdp_handle_t *hp) 77403831d35Sstevel { 77503831d35Sstevel #ifdef lint 77603831d35Sstevel hp = hp; 77703831d35Sstevel #endif 77803831d35Sstevel return (0); 77903831d35Sstevel } 78003831d35Sstevel 78103831d35Sstevel /* ARGSUSED */ 78203831d35Sstevel int 78303831d35Sstevel sbdp_release_component(sbdp_handle_t *hp, dev_info_t *dip) 78403831d35Sstevel { 78503831d35Sstevel return (0); 78603831d35Sstevel } 78703831d35Sstevel 78803831d35Sstevel void 78903831d35Sstevel sbdp_set_err(sbd_error_t *ep, int ecode, char *rsc) 79003831d35Sstevel { 79103831d35Sstevel static fn_t f = "sbdp_set_err"; 79203831d35Sstevel 79303831d35Sstevel SBDP_DBG_FUNC("%s\n", f); 79403831d35Sstevel ASSERT(ep != NULL); 79503831d35Sstevel ep->e_code = ecode; 79603831d35Sstevel 79703831d35Sstevel if (rsc != NULL) { 79803831d35Sstevel (void) strcpy((caddr_t)(ep->e_rsc), (caddr_t)rsc); 79903831d35Sstevel } 80003831d35Sstevel } 80103831d35Sstevel 80203831d35Sstevel /* 80303831d35Sstevel * Serengeti DR passthrus are for debugging purposes only. 80403831d35Sstevel */ 80503831d35Sstevel static struct { 80603831d35Sstevel const char *name; 80703831d35Sstevel int (*handler)(sbdp_handle_t *, void *); 80803831d35Sstevel } sbdp_passthrus[] = { 80903831d35Sstevel #ifdef DEBUG 81003831d35Sstevel { "readmem", sbdp_passthru_readmem }, 81103831d35Sstevel { "prep-script", sbdp_passthru_prep_script }, 81203831d35Sstevel { "test-quiesce", sbdp_passthru_test_quiesce }, 81303831d35Sstevel { "inject-error", sbdp_passthru_inject_error }, 81403831d35Sstevel { "reset-error", sbdp_passthru_reset_error }, 81503831d35Sstevel #endif 81603831d35Sstevel 81703831d35Sstevel /* the following line must always be last */ 81803831d35Sstevel { NULL, NULL } 81903831d35Sstevel }; 82003831d35Sstevel 82103831d35Sstevel 82203831d35Sstevel /*ARGSUSED*/ 82303831d35Sstevel int 82403831d35Sstevel sbdp_ioctl(sbdp_handle_t *hp, sbdp_ioctl_arg_t *sbdpi) 82503831d35Sstevel { 82603831d35Sstevel #ifdef DEBUG 82703831d35Sstevel char buf[512]; 82803831d35Sstevel int rv; 82903831d35Sstevel sbd_ioctl_arg_t *sbdi = (sbd_ioctl_arg_t *)sbdpi->h_iap; 83003831d35Sstevel int i; 83103831d35Sstevel static fn_t f = "sbdp_ioctl"; 83203831d35Sstevel 83303831d35Sstevel SBDP_DBG_FUNC("%s\n", f); 83403831d35Sstevel 83503831d35Sstevel if (sbdi->i_len >= sizeof (buf) || 83603831d35Sstevel ddi_copyin(sbdi->i_opts, buf, sbdi->i_len, sbdpi->h_mode)) { 83703831d35Sstevel sbdp_set_err(hp->h_err, ESBD_FAULT, NULL); 83803831d35Sstevel return (-1); 83903831d35Sstevel } 84003831d35Sstevel 84103831d35Sstevel i = 0; 84203831d35Sstevel while (sbdp_passthrus[i].name != NULL) { 84303831d35Sstevel int len; 84403831d35Sstevel 84503831d35Sstevel len = strlen(sbdp_passthrus[i].name); 84603831d35Sstevel if (strncmp(sbdp_passthrus[i].name, buf, len) == 0) 84703831d35Sstevel break; 84803831d35Sstevel i++; 84903831d35Sstevel } 85003831d35Sstevel 85103831d35Sstevel if (sbdp_passthrus[i].name == NULL) { 85203831d35Sstevel sbdp_set_err(hp->h_err, ESBD_INVAL, NULL); 85303831d35Sstevel rv = EIO; 85403831d35Sstevel } else { 85503831d35Sstevel rv = (*sbdp_passthrus[i].handler)(hp, buf); 85603831d35Sstevel if (rv != ESBD_NOERROR) { 85703831d35Sstevel sbdp_set_err(hp->h_err, rv, NULL); 85803831d35Sstevel rv = EIO; 85903831d35Sstevel } 86003831d35Sstevel 86103831d35Sstevel } 86203831d35Sstevel 86303831d35Sstevel return (rv); 86403831d35Sstevel #else 86503831d35Sstevel return (0); 86603831d35Sstevel #endif 86703831d35Sstevel } 86803831d35Sstevel 86903831d35Sstevel /* 87003831d35Sstevel * Check the dnode we obtained. Need to find a better way to determine 87103831d35Sstevel * if the node has the correct starting address 87203831d35Sstevel */ 87303831d35Sstevel int 87403831d35Sstevel sbdp_is_node_bad(pnode_t node) 87503831d35Sstevel { 87603831d35Sstevel static fn_t f = "sbdp_is_node_bad"; 87703831d35Sstevel 87803831d35Sstevel SBDP_DBG_FUNC("%s\n", f); 87903831d35Sstevel 88003831d35Sstevel return ((node == OBP_NONODE) || (node == OBP_BADNODE) || 88103831d35Sstevel ((node & 0x80000000u) != 0x80000000u)); 88203831d35Sstevel } 88303831d35Sstevel 88403831d35Sstevel /* 88503831d35Sstevel * Retrieve the information we have on this board from 88603831d35Sstevel * the inventory 88703831d35Sstevel */ 88803831d35Sstevel sbdp_bd_t * 88903831d35Sstevel sbdp_get_bd_info(int wnode, int board) 89003831d35Sstevel { 89103831d35Sstevel sbdp_wnode_t *wnodep; 89203831d35Sstevel sbdp_bd_t *bdp; 89303831d35Sstevel int max_bds; 89403831d35Sstevel static fn_t f = "sbdp_get_bd_info"; 89503831d35Sstevel 89603831d35Sstevel SBDP_DBG_FUNC("%s\n", f); 89703831d35Sstevel 89803831d35Sstevel wnodep = sbdp_get_wnodep(wnode); 89903831d35Sstevel max_bds = plat_max_boards(); 90003831d35Sstevel 90103831d35Sstevel if ((wnodep == NULL) || ((board < 0) && (board > max_bds))) { 90203831d35Sstevel return (NULL); 90303831d35Sstevel } 90403831d35Sstevel 90503831d35Sstevel bdp = &wnodep->bds[board]; 90603831d35Sstevel 90703831d35Sstevel /* 90803831d35Sstevel * We might not have the complete bd info. With cheetah we 90903831d35Sstevel * cannot access the memory decode registers when then cpu is 91003831d35Sstevel * in reset. If the mem info is incomplete, then we try to gather it 91103831d35Sstevel * here 91203831d35Sstevel */ 91303831d35Sstevel sbdp_update_bd_info(bdp); 91403831d35Sstevel 91503831d35Sstevel return (bdp); 91603831d35Sstevel } 91703831d35Sstevel 91803831d35Sstevel /* 91903831d35Sstevel * There are certain cases where obp marks components as failed 92003831d35Sstevel * If the status is ok the node won't have any status property. It 92103831d35Sstevel * is only there if the status is other than ok. 92203831d35Sstevel */ 92303831d35Sstevel sbd_cond_t 92403831d35Sstevel sbdp_get_comp_status(pnode_t nodeid) 92503831d35Sstevel { 92603831d35Sstevel char status_buf[OBP_MAXPROPNAME]; 92703831d35Sstevel static const char *status = "status"; 92803831d35Sstevel static const char *failed = "fail"; 92903831d35Sstevel static const char *disabled = "disabled"; 93003831d35Sstevel static fn_t f = "sbdp_get_comp_status"; 93103831d35Sstevel 93203831d35Sstevel SBDP_DBG_FUNC("%s\n", f); 93303831d35Sstevel 93403831d35Sstevel if (sbdp_is_node_bad(nodeid)) { 93503831d35Sstevel SBDP_DBG_STATE("node is not ok\n"); 93603831d35Sstevel return (SBD_COND_UNKNOWN); 93703831d35Sstevel } 93803831d35Sstevel 93903831d35Sstevel if (prom_getproplen(nodeid, (char *)status) <= 0) { 94003831d35Sstevel SBDP_DBG_STATE("status is ok\n"); 94103831d35Sstevel return (SBD_COND_OK); 94203831d35Sstevel } 94303831d35Sstevel 94403831d35Sstevel if (prom_getprop(nodeid, (char *)status, status_buf) < 0) { 94503831d35Sstevel SBDP_DBG_STATE("status is unknown\n"); 94603831d35Sstevel return (SBD_COND_UNKNOWN); 94703831d35Sstevel } 94803831d35Sstevel 94903831d35Sstevel if (strncmp(status_buf, failed, strlen(failed)) == 0) { 95003831d35Sstevel SBDP_DBG_STATE("status of failed\n"); 95103831d35Sstevel return (SBD_COND_FAILED); 95203831d35Sstevel } 95303831d35Sstevel 95403831d35Sstevel if (strcmp(status_buf, disabled) == 0) { 95503831d35Sstevel SBDP_DBG_STATE("status of unusable\n"); 95603831d35Sstevel return (SBD_COND_UNUSABLE); 95703831d35Sstevel } 95803831d35Sstevel 95903831d35Sstevel return (SBD_COND_OK); 96003831d35Sstevel } 96103831d35Sstevel 96203831d35Sstevel void 96303831d35Sstevel sbdp_cpu_in_reset(int node, int bd, int unit, int reset) 96403831d35Sstevel { 96503831d35Sstevel sbdp_wnode_t *cur; 96603831d35Sstevel sbdp_bd_t *bdp; 96703831d35Sstevel static fn_t f = "sbdp_cpu_in_reset"; 96803831d35Sstevel 96903831d35Sstevel SBDP_DBG_FUNC("%s\n", f); 97003831d35Sstevel 97103831d35Sstevel if ((unit < -1) || (bd < 0) || (node < 0)) { 97203831d35Sstevel return; 97303831d35Sstevel } 97403831d35Sstevel 97503831d35Sstevel cur = sbdp_get_wnodep(node); 97603831d35Sstevel 97703831d35Sstevel SBDP_DBG_MISC("marking cpu %d %s for board %d\n", unit, 97803831d35Sstevel (reset) ? "in reset" : "out of reset", bd); 97903831d35Sstevel 98003831d35Sstevel if (cur == NULL) { 98103831d35Sstevel return; 98203831d35Sstevel } 98303831d35Sstevel 98403831d35Sstevel bdp = &cur->bds[bd]; 98503831d35Sstevel 98603831d35Sstevel if (unit == SBDP_ALL_CPUS) 98703831d35Sstevel if (reset == 1) 98803831d35Sstevel SBDP_SET_ALL_CPUS_IN_RESET(bdp); 98903831d35Sstevel else 99003831d35Sstevel SBDP_UNSET_ALL_CPUS_IN_RESET(bdp); 99103831d35Sstevel else 99203831d35Sstevel if (reset == 1) 99303831d35Sstevel SBDP_SET_CPU_IN_RESET(bdp, unit); 99403831d35Sstevel else 99503831d35Sstevel SBDP_UNSET_CPU_IN_RESET(bdp, unit); 99603831d35Sstevel } 99703831d35Sstevel 99803831d35Sstevel int 99903831d35Sstevel sbdp_set_cpu_present(int node, int bd, int unit) 100003831d35Sstevel { 100103831d35Sstevel sbdp_wnode_t *cur; 100203831d35Sstevel sbdp_bd_t *bdp; 100303831d35Sstevel static fn_t f = "sbdp_set_cpu_present"; 100403831d35Sstevel 100503831d35Sstevel SBDP_DBG_FUNC("%s\n", f); 100603831d35Sstevel 100703831d35Sstevel if ((unit < 0) || (bd < 0) || (node < 0)) { 100803831d35Sstevel return (-1); 100903831d35Sstevel } 101003831d35Sstevel 101103831d35Sstevel cur = sbdp_get_wnodep(node); 101203831d35Sstevel if (cur == NULL) { 101303831d35Sstevel return (-1); 101403831d35Sstevel } 101503831d35Sstevel 101603831d35Sstevel bdp = &cur->bds[bd]; 101703831d35Sstevel 101803831d35Sstevel SBDP_SET_CPU_PRESENT(bdp, unit); 101903831d35Sstevel 102003831d35Sstevel return (0); 102103831d35Sstevel } 102203831d35Sstevel 102303831d35Sstevel int 102403831d35Sstevel sbdp_is_cpu_present(int node, int bd, int unit) 102503831d35Sstevel { 102603831d35Sstevel sbdp_wnode_t *cur; 102703831d35Sstevel sbdp_bd_t *bdp; 102803831d35Sstevel static fn_t f = "sbdp_is_cpu_present"; 102903831d35Sstevel 103003831d35Sstevel SBDP_DBG_FUNC("%s\n", f); 103103831d35Sstevel 103203831d35Sstevel if ((unit < 0) || (bd < 0) || (node < 0)) { 103303831d35Sstevel return (-1); 103403831d35Sstevel } 103503831d35Sstevel 103603831d35Sstevel cur = sbdp_get_wnodep(node); 103703831d35Sstevel if (cur == NULL) { 103803831d35Sstevel return (-1); 103903831d35Sstevel } 104003831d35Sstevel 104103831d35Sstevel bdp = &cur->bds[bd]; 104203831d35Sstevel 104303831d35Sstevel return (SBDP_IS_CPU_PRESENT(bdp, unit)); 104403831d35Sstevel } 104503831d35Sstevel 104603831d35Sstevel int 104703831d35Sstevel sbdp_is_cpu_in_reset(int node, int bd, int unit) 104803831d35Sstevel { 104903831d35Sstevel sbdp_wnode_t *cur; 105003831d35Sstevel sbdp_bd_t *bdp; 105103831d35Sstevel static fn_t f = "sbdp_is_cpu_in_reset"; 105203831d35Sstevel 105303831d35Sstevel SBDP_DBG_FUNC("%s\n", f); 105403831d35Sstevel 105503831d35Sstevel if ((unit < 0) || (bd < 0) || (node < 0)) { 105603831d35Sstevel return (-1); 105703831d35Sstevel } 105803831d35Sstevel 105903831d35Sstevel cur = sbdp_get_wnodep(node); 106003831d35Sstevel 106103831d35Sstevel if (cur == NULL) { 106203831d35Sstevel return (-1); 106303831d35Sstevel } 106403831d35Sstevel 106503831d35Sstevel bdp = &cur->bds[bd]; 106603831d35Sstevel 106703831d35Sstevel return (SBDP_IS_CPU_IN_RESET(bdp, unit)); 106803831d35Sstevel } 106903831d35Sstevel 107003831d35Sstevel int 107103831d35Sstevel sbdp_dr_avail(void) 107203831d35Sstevel { 107303831d35Sstevel static fn_t f = "sbdp_dr_avail"; 107403831d35Sstevel 107503831d35Sstevel SBDP_DBG_FUNC("%s\n", f); 107603831d35Sstevel 107703831d35Sstevel if (sbdp_dr_available) 107803831d35Sstevel if (sg_prom_sb_dr_check() == 0) 107903831d35Sstevel return (1); 108003831d35Sstevel return (0); 108103831d35Sstevel } 1082