11708Sstevel /*
21708Sstevel * CDDL HEADER START
31708Sstevel *
41708Sstevel * The contents of this file are subject to the terms of the
51708Sstevel * Common Development and Distribution License (the "License").
61708Sstevel * You may not use this file except in compliance with the License.
71708Sstevel *
81708Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91708Sstevel * or http://www.opensolaris.org/os/licensing.
101708Sstevel * See the License for the specific language governing permissions
111708Sstevel * and limitations under the License.
121708Sstevel *
131708Sstevel * When distributing Covered Code, include this CDDL HEADER in each
141708Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151708Sstevel * If applicable, add the following below this CDDL HEADER, with the
161708Sstevel * fields enclosed by brackets "[]" replaced with your own identifying
171708Sstevel * information: Portions Copyright [yyyy] [name of copyright owner]
181708Sstevel *
191708Sstevel * CDDL HEADER END
201708Sstevel */
211708Sstevel
221708Sstevel /*
23*11311SSurya.Prakki@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
241708Sstevel * Use is subject to license terms.
251708Sstevel */
261708Sstevel
271708Sstevel #include <sys/types.h>
281708Sstevel #include <sys/cmn_err.h>
291708Sstevel #include <sys/conf.h>
301708Sstevel #include <sys/ddi_impldefs.h>
311708Sstevel #include <sys/autoconf.h>
321708Sstevel #include <sys/systm.h>
331708Sstevel #include <sys/modctl.h>
341708Sstevel #include <sys/ddi.h>
351708Sstevel #include <sys/sunddi.h>
361708Sstevel #include <sys/sunndi.h>
371708Sstevel #include <sys/ndi_impldefs.h>
381708Sstevel #include <sys/promif.h>
391708Sstevel #include <sys/stat.h>
401708Sstevel #include <sys/kmem.h>
411708Sstevel #include <sys/promif.h>
421708Sstevel #include <sys/conf.h>
431708Sstevel #include <sys/obpdefs.h>
441708Sstevel #include <sys/cpuvar.h>
451708Sstevel #include <vm/seg_kmem.h>
461708Sstevel #include <sys/prom_plat.h>
471708Sstevel #include <sys/machsystm.h>
481708Sstevel #include <sys/note.h>
491708Sstevel #include <sys/memlist.h>
501708Sstevel #include <sys/ssm.h>
511708Sstevel
521708Sstevel #include <sys/sbd_ioctl.h>
531708Sstevel #include <sys/sbd.h>
541708Sstevel #include <sys/sbdp_priv.h>
551708Sstevel #include <sys/sbdp_mem.h>
561708Sstevel #include <sys/sbdp_error.h>
571708Sstevel #include <sys/serengeti.h>
581708Sstevel
591708Sstevel #include <sys/sgsbbc.h> /* To get fn_t type definition */
601708Sstevel
611708Sstevel /*
621708Sstevel * Config information
631708Sstevel */
641708Sstevel #ifdef DEBUG
651708Sstevel uint_t sbdp_debug = 0x0;
661708Sstevel #endif /* DEBUG */
671708Sstevel
681708Sstevel /*
691708Sstevel * Enable or disable dr
701708Sstevel */
711708Sstevel int sbdp_dr_available = 1;
721708Sstevel
731708Sstevel /* name properties for some Serengeti device nodes */
741708Sstevel #define CMP_DEVNAME "cmp"
751708Sstevel #define MEM_DEVNAME "memory"
761708Sstevel #define CPU_DEVNAME "cpu"
771708Sstevel #define IO_PCI_DEVNAME "pci"
781708Sstevel #define IO_SGHSC_DEVNAME "sghsc"
791708Sstevel #define IO_WCI_DEVNAME "wci"
801708Sstevel
811708Sstevel static sbd_devattr_t sbdp_devattr[] = {
821708Sstevel { CMP_DEVNAME, "cmp", SBD_COMP_CMP },
831708Sstevel { MEM_DEVNAME, "memory-controller", SBD_COMP_MEM },
841708Sstevel { CPU_DEVNAME, "cpu", SBD_COMP_CPU },
851708Sstevel { IO_PCI_DEVNAME, "pci", SBD_COMP_IO },
861708Sstevel { IO_SGHSC_DEVNAME, "sghsc", SBD_COMP_IO },
871708Sstevel { IO_WCI_DEVNAME, "wci", SBD_COMP_IO },
881708Sstevel /* last item must be blank */
891708Sstevel { NULL, NULL, SBD_COMP_UNKNOWN }
901708Sstevel };
911708Sstevel
921708Sstevel /*
931708Sstevel * In the case of a busy mbox, if a status cmd comes in we return a cached
941708Sstevel * copy. This cache is a link list of wnodes that contains bd structs with
951708Sstevel * the appropriate info. When a new wnode is created a whole entry is added
961708Sstevel * to the list.
971708Sstevel */
981708Sstevel sbdp_wnode_t *first_node = NULL; /* first wnode. Entry to the link list */
991708Sstevel int cur_num_wnodes = 0; /* how many nodes are currently running */
1001708Sstevel
1011708Sstevel /* Macros to access fields in the previous array */
1021708Sstevel #define SBDP_CT(i) sbdp_devattr[i].s_dnodetype
1031708Sstevel #define SBDP_DEVNAME(i) sbdp_devattr[(i)].s_devname
1041708Sstevel #define SBDP_OTYPE(i) sbdp_devattr[(i)].s_obp_type
1051708Sstevel
1061708Sstevel /*
1071708Sstevel * Prototypes
1081708Sstevel */
1091708Sstevel sbdp_wnode_t *sbdp_get_wnodep(int);
1101708Sstevel
1111708Sstevel /*
1121708Sstevel * Module linkage information for the kernel.
1131708Sstevel */
1141708Sstevel
1151708Sstevel static struct modlmisc modlmisc = {
1161708Sstevel &mod_miscops,
1171708Sstevel "Serengeti sbdp",
1181708Sstevel };
1191708Sstevel
1201708Sstevel static struct modlinkage modlinkage = {
1211708Sstevel MODREV_1,
1221708Sstevel (void *)&modlmisc,
1231708Sstevel NULL
1241708Sstevel };
1251708Sstevel
1261708Sstevel /*
1271708Sstevel * VA area used during CPU shutdown.
1281708Sstevel */
1291708Sstevel caddr_t sbdp_shutdown_va;
1301708Sstevel
1311708Sstevel /*
1321708Sstevel * Mutex to protect our inventory
1331708Sstevel */
1341708Sstevel kmutex_t sbdp_wnode_mutex;
1351708Sstevel
1361708Sstevel int
_init(void)1371708Sstevel _init(void)
1381708Sstevel {
1391708Sstevel int e;
1401708Sstevel
1411708Sstevel e = mod_install(&modlinkage);
1421708Sstevel if (e != 0)
1431708Sstevel return (e);
1441708Sstevel
1451708Sstevel sbdp_shutdown_va = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP);
1461708Sstevel ASSERT(sbdp_shutdown_va != NULL);
1471708Sstevel sbdp_valp = (uint64_t *)vmem_alloc(static_alloc_arena,
1481708Sstevel sizeof (uint64_t), VM_SLEEP);
1491708Sstevel
1501708Sstevel mutex_init(&sbdp_wnode_mutex, NULL, MUTEX_DRIVER, NULL);
1511708Sstevel return (e);
1521708Sstevel }
1531708Sstevel
1541708Sstevel int
_fini(void)1551708Sstevel _fini(void)
1561708Sstevel {
1571708Sstevel int e;
1581708Sstevel
1591708Sstevel /*
1601708Sstevel * Remove the module.
1611708Sstevel */
1621708Sstevel e = mod_remove(&modlinkage);
1631708Sstevel if (e != 0)
1641708Sstevel return (e);
1651708Sstevel
1661708Sstevel vmem_free(heap_arena, sbdp_shutdown_va, PAGESIZE);
1671708Sstevel sbdp_shutdown_va = NULL;
1681708Sstevel vmem_free(static_alloc_arena, (void *)sbdp_valp, sizeof (uint64_t));
1691708Sstevel sbdp_valp = NULL;
1701708Sstevel
1711708Sstevel mutex_destroy(&sbdp_wnode_mutex);
1721708Sstevel return (e);
1731708Sstevel }
1741708Sstevel
1751708Sstevel int
_info(struct modinfo * modinfop)1761708Sstevel _info(struct modinfo *modinfop)
1771708Sstevel {
1781708Sstevel return (mod_info(&modlinkage, modinfop));
1791708Sstevel }
1801708Sstevel
1811708Sstevel int
sbdp_get_bd_and_wnode_num(pnode_t nodeid,int * bd,int * wnode)1821708Sstevel sbdp_get_bd_and_wnode_num(pnode_t nodeid, int *bd, int *wnode)
1831708Sstevel {
1841708Sstevel int portid;
1851708Sstevel static fn_t f = "sbdp_get_bd_and_wnode_num";
1861708Sstevel extern int get_portid(pnode_t node, pnode_t *cmpp);
1871708Sstevel
1881708Sstevel SBDP_DBG_FUNC("%s\n", f);
1891708Sstevel
1901708Sstevel if (sbdp_is_node_bad(nodeid))
1911708Sstevel return (-1);
1921708Sstevel
1931708Sstevel if ((portid = get_portid(nodeid, NULL)) == -1)
1941708Sstevel return (-1);
1951708Sstevel
1961708Sstevel /*
1971708Sstevel * decode the board number
1981708Sstevel */
1991708Sstevel *bd = SG_PORTID_TO_BOARD_NUM(portid);
2001708Sstevel *wnode = SG_PORTID_TO_NODEID(portid);
2011708Sstevel
2021708Sstevel return (0);
2031708Sstevel }
2041708Sstevel
2051708Sstevel int
sbdp_get_board_num(sbdp_handle_t * hp,dev_info_t * dip)2061708Sstevel sbdp_get_board_num(sbdp_handle_t *hp, dev_info_t *dip)
2071708Sstevel {
2081708Sstevel _NOTE(ARGUNUSED(hp))
2091708Sstevel
2101708Sstevel pnode_t nodeid;
2111708Sstevel int bd, wnode;
2121708Sstevel static fn_t f = "sbdp_get_board_num";
2131708Sstevel
2141708Sstevel SBDP_DBG_FUNC("%s\n", f);
2151708Sstevel
2161708Sstevel if (dip == NULL)
2171708Sstevel return (-1);
2181708Sstevel
2191708Sstevel nodeid = ddi_get_nodeid(dip);
2201708Sstevel
2211708Sstevel /*
2221708Sstevel * Portid has encoded the nodeid and the agent id. The top
2231708Sstevel * 4 bits are correspond to the wcnodeid and the lower 5 are the
2241708Sstevel * agent id.
2251708Sstevel * Each agent id represents a physical location hence we can
2261708Sstevel * obtain the board number
2271708Sstevel */
2281708Sstevel if (sbdp_get_bd_and_wnode_num(nodeid, &bd, &wnode) < 0)
2291708Sstevel return (-1);
2301708Sstevel
2311708Sstevel return (bd);
2321708Sstevel }
2331708Sstevel
2341708Sstevel
2351708Sstevel sbd_devattr_t *
sbdp_get_devattr(void)2361708Sstevel sbdp_get_devattr(void)
2371708Sstevel {
2381708Sstevel return (&sbdp_devattr[0]);
2391708Sstevel }
2401708Sstevel
2411708Sstevel int
sbdp_portid_to_cpu_unit(int cmp,int core)2421708Sstevel sbdp_portid_to_cpu_unit(int cmp, int core)
2431708Sstevel {
2441708Sstevel return (SG_PORTID_TO_CPU_UNIT(cmp, core));
2451708Sstevel }
2461708Sstevel
2471708Sstevel int
sbdp_get_unit_num(sbdp_handle_t * hp,dev_info_t * dip)2481708Sstevel sbdp_get_unit_num(sbdp_handle_t *hp, dev_info_t *dip)
2491708Sstevel {
2501708Sstevel int unit = -1;
2511708Sstevel int portid;
2521708Sstevel processorid_t cpuid;
2531708Sstevel sbd_comp_type_t type;
2541708Sstevel char dev_type[OBP_MAXPROPNAME];
2551708Sstevel int i;
2561708Sstevel pnode_t nodeid;
2571708Sstevel static fn_t f = "sbdp_get_unit_num";
2581708Sstevel
2591708Sstevel SBDP_DBG_FUNC("%s\n", f);
2601708Sstevel
2611708Sstevel if (dip == NULL)
2621708Sstevel return (-1);
2631708Sstevel
2641708Sstevel nodeid = ddi_get_nodeid(dip);
2651708Sstevel
2661708Sstevel if (sbdp_is_node_bad(nodeid))
2671708Sstevel return (-1);
2681708Sstevel
2691708Sstevel if (prom_getprop(nodeid, "device_type", (caddr_t)dev_type) < 0) {
2701708Sstevel SBDP_DBG_MISC("%s: couldn't get device_type\n", f);
2711708Sstevel return (-1);
2721708Sstevel }
2731708Sstevel
2741708Sstevel for (i = 0; SBDP_CT(i) != SBD_COMP_UNKNOWN; i++) {
2751708Sstevel if (strcmp(dev_type, SBDP_OTYPE(i)) != 0)
2761708Sstevel continue;
2771708Sstevel type = SBDP_CT(i);
2781708Sstevel }
2791708Sstevel
2801708Sstevel switch (type) {
2811708Sstevel case SBD_COMP_CPU:
2821708Sstevel if ((cpuid = sbdp_get_cpuid(hp, dip)) != -1) {
2831708Sstevel unit = SG_CPUID_TO_CPU_UNIT(cpuid);
2841708Sstevel }
2851708Sstevel break;
2861708Sstevel case SBD_COMP_MEM:
2871708Sstevel unit = 0;
2881708Sstevel break;
2891708Sstevel case SBD_COMP_IO: {
2901708Sstevel regspace_t regs[3];
2911708Sstevel int len = 0;
2921708Sstevel
2931708Sstevel /*
2941708Sstevel * Check to see if this is a cpci node
2951708Sstevel * cpci nodes are assign unit nums of 5 for now
2961708Sstevel * So they don't conflict with the pci unit nums
2971708Sstevel */
2981708Sstevel
2991708Sstevel if (strcmp(dev_type, "sghsc") == 0) {
3001708Sstevel SBDP_DBG_MISC("it is a sghsc\n");
3011708Sstevel return (4);
3021708Sstevel }
3031708Sstevel
3041708Sstevel if (prom_getprop(nodeid, "portid", (caddr_t)&portid) <= 0) {
3051708Sstevel SBDP_DBG_MISC("%s: couldn't get portid\n", f);
3061708Sstevel return (-1);
3071708Sstevel }
3081708Sstevel
3091708Sstevel len = prom_getproplen(nodeid, "reg");
3101708Sstevel if (len <= 0) {
3111708Sstevel SBDP_DBG_MISC("%s: couldn't get length\n", f);
3121708Sstevel return (-1);
3131708Sstevel }
3141708Sstevel
3151708Sstevel if (prom_getprop(nodeid, "reg", (caddr_t)regs) < 0) {
3161708Sstevel SBDP_DBG_MISC("%s: couldn't get registers\n", f);
3171708Sstevel return (-1);
3181708Sstevel }
3191708Sstevel
3201708Sstevel if ((portid % 2) != 0)
3211708Sstevel if ((regs[0].regspec_addr_lo & 0x700000) ==
322*11311SSurya.Prakki@Sun.COM 0x700000)
3231708Sstevel unit = 0;
3241708Sstevel else
3251708Sstevel unit = 1;
3261708Sstevel else
3271708Sstevel if ((regs[0].regspec_addr_lo & 0x700000) ==
3281708Sstevel 0x700000)
3291708Sstevel unit = 2;
3301708Sstevel else
3311708Sstevel unit = 3;
3321708Sstevel
3331708Sstevel SBDP_DBG_MISC("unit is %d\n", unit);
3341708Sstevel break;
3351708Sstevel }
3361708Sstevel default:
3371708Sstevel break;
3381708Sstevel
3391708Sstevel }
3401708Sstevel
3411708Sstevel return (unit);
3421708Sstevel }
3431708Sstevel
3441708Sstevel struct sbdp_mem_dip {
3451708Sstevel sbdp_bd_t *bdp;
3461708Sstevel dev_info_t *dip;
3471708Sstevel };
3481708Sstevel
3491708Sstevel static int
sbdp_get_mem_dip(pnode_t node,void * arg,uint_t flags)3501708Sstevel sbdp_get_mem_dip(pnode_t node, void *arg, uint_t flags)
3511708Sstevel {
3521708Sstevel _NOTE(ARGUNUSED(flags))
3531708Sstevel
3541708Sstevel struct sbdp_mem_dip *smdp = (struct sbdp_mem_dip *)arg;
3551708Sstevel mem_op_t mem = {0};
3561708Sstevel
3571708Sstevel if (node == OBP_NONODE || node == OBP_BADNODE)
3581708Sstevel return (DDI_FAILURE);
3591708Sstevel
3601708Sstevel mem.nodes = smdp->bdp->nodes;
3611708Sstevel mem.board = smdp->bdp->bd;
3621708Sstevel mem.nmem = smdp->bdp->nnum;
3631708Sstevel
3641708Sstevel (void) sbdp_is_mem(node, &mem);
3651708Sstevel
3661708Sstevel /*
3671708Sstevel * We need to find the dip only for the first nodeid
3681708Sstevel */
3691708Sstevel if (smdp->bdp->nnum == 0 && mem.nmem == 1) {
3701708Sstevel ASSERT(smdp->dip == NULL);
3711708Sstevel smdp->dip = e_ddi_nodeid_to_dip(node);
3721708Sstevel }
3731708Sstevel
3741708Sstevel smdp->bdp->nnum = mem.nmem;
3751708Sstevel
3761708Sstevel return (DDI_SUCCESS);
3771708Sstevel }
3781708Sstevel
3791708Sstevel
3801708Sstevel /*
3811708Sstevel * Update the board info. Required after a copy rename
3821708Sstevel */
3831708Sstevel void
sbdp_update_bd_info(sbdp_bd_t * bdp)3841708Sstevel sbdp_update_bd_info(sbdp_bd_t *bdp)
3851708Sstevel {
3861708Sstevel attach_pkt_t apkt, *apktp = &apkt;
3871708Sstevel struct sbdp_mem_dip smd = {0};
3881708Sstevel static fn_t f = "sbdp_update_bd_info";
3891708Sstevel
3901708Sstevel SBDP_DBG_FUNC("%s\n", f);
3911708Sstevel
3921708Sstevel if (bdp == NULL) {
3931708Sstevel return;
3941708Sstevel }
3951708Sstevel /*
3961708Sstevel * Grab the lock
3971708Sstevel */
3981708Sstevel mutex_enter(&bdp->bd_mutex);
3991708Sstevel
4001708Sstevel /*
4011708Sstevel * we get the top nodes here. This will have a side effect of
4021708Sstevel * updating the present bit for cpus
4031708Sstevel */
4041708Sstevel apktp->node = bdp->wnode;
4051708Sstevel apktp->board = bdp->bd;
4061708Sstevel apktp->num_of_nodes = 0;
4071708Sstevel apktp->flags = 0;
4081708Sstevel sbdp_walk_prom_tree(prom_rootnode(), sbdp_select_top_nodes,
4091708Sstevel (void *) apktp);
4101708Sstevel
4111708Sstevel /*
4121708Sstevel * We need to clear nnum since we are looking again for the
4131708Sstevel * nodes
4141708Sstevel */
4151708Sstevel bdp->nnum = 0;
4161708Sstevel smd.bdp = bdp;
4171708Sstevel
4181708Sstevel /*
4191708Sstevel * If a dip is found by sbdp_get_mem_dip(), it will be
4201708Sstevel * returned held
4211708Sstevel */
4221708Sstevel sbdp_walk_prom_tree(prom_rootnode(), sbdp_get_mem_dip, &smd);
4231708Sstevel if (smd.dip != NULL) {
4241708Sstevel sbdp_handle_t *hp;
4251708Sstevel
4261708Sstevel hp = kmem_zalloc(sizeof (sbdp_handle_t), KM_SLEEP);
4271708Sstevel hp->h_board = bdp->bd;
4281708Sstevel hp->h_wnode = bdp->wnode;
4291708Sstevel hp->h_err = kmem_zalloc(sizeof (*hp->h_err), KM_SLEEP);
4301708Sstevel if (bdp->ml != NULL) {
431*11311SSurya.Prakki@Sun.COM (void) sbdp_del_memlist(hp, bdp->ml);
4321708Sstevel }
4331708Sstevel bdp->ml = sbdp_get_memlist(hp, (dev_info_t *)NULL);
4341708Sstevel /*
4351708Sstevel * if the board doesn't have banks initialize them,
4361708Sstevel * otherwise we assume they have been updated if
4371708Sstevel * necessary
4381708Sstevel */
4391708Sstevel if (bdp->banks == NULL) {
4401708Sstevel sbdp_init_bd_banks(bdp);
4411708Sstevel }
4421708Sstevel #ifdef DEBUG
4431708Sstevel sbdp_print_bd_banks(bdp);
4441708Sstevel #endif
4451708Sstevel
4461708Sstevel if (sbdphw_get_base_physaddr(hp, smd.dip, &bdp->bpa))
4471708Sstevel bdp->bpa = -1;
4481708Sstevel ddi_release_devi(smd.dip);
4491708Sstevel kmem_free(hp->h_err, sizeof (*hp->h_err));
4501708Sstevel kmem_free(hp, sizeof (sbdp_handle_t));
4511708Sstevel }
4521708Sstevel mutex_exit(&bdp->bd_mutex);
4531708Sstevel }
4541708Sstevel
4551708Sstevel /*
4561708Sstevel * Initialize the board struct. This remains cached. We update it
4571708Sstevel * every time we have a successful show_board and after a copy-rename
4581708Sstevel */
4591708Sstevel void
sbdp_bd_init(sbdp_bd_t * bdp,int bd,int wnode)4601708Sstevel sbdp_bd_init(sbdp_bd_t *bdp, int bd, int wnode)
4611708Sstevel {
4621708Sstevel static fn_t f = "sbdp_bd_init";
4631708Sstevel
4641708Sstevel SBDP_DBG_FUNC("%s\n", f);
4651708Sstevel
4661708Sstevel bdp->bd = bd;
4671708Sstevel bdp->wnode = wnode;
4681708Sstevel
4691708Sstevel SBDP_UNSET_ALL_CPUS_IN_RESET(bdp);
4701708Sstevel
4711708Sstevel bdp->cpus_present = 0;
4721708Sstevel
4731708Sstevel sbdp_update_bd_info(bdp);
4741708Sstevel
4751708Sstevel mutex_init(&bdp->bd_mutex, NULL, MUTEX_DRIVER, NULL);
4761708Sstevel bdp->bd_sc = (show_board_t *)kmem_zalloc(sizeof (show_board_t),
4771708Sstevel KM_SLEEP);
4781708Sstevel bdp->valid_cp = -1;
4791708Sstevel }
4801708Sstevel
4811708Sstevel /*
4821708Sstevel * This entry is going away. Clean up
4831708Sstevel */
4841708Sstevel void
sbdp_bd_fini(sbdp_bd_t * bdp)4851708Sstevel sbdp_bd_fini(sbdp_bd_t *bdp)
4861708Sstevel {
4871708Sstevel static fn_t f = "sbdp_bd_fini";
4881708Sstevel
4891708Sstevel SBDP_DBG_FUNC("%s\n", f);
4901708Sstevel
4911708Sstevel sbdp_cleanup_bd(bdp->wnode, bdp->bd);
4921708Sstevel kmem_free(bdp->bd_sc, sizeof (show_board_t));
4931708Sstevel bdp->bd_sc = NULL;
4941708Sstevel mutex_destroy(&bdp->bd_mutex);
4951708Sstevel #ifdef DEBUG
4961708Sstevel sbdp_print_all_segs();
4971708Sstevel #endif
4981708Sstevel }
4991708Sstevel
5001708Sstevel /*
5011708Sstevel * A new wnode has arrived. Initialize the struct and create
5021708Sstevel * the board structures.
5031708Sstevel */
5041708Sstevel void
sbdp_wnode_init(sbdp_wnode_t * wnodep,int wnode,int boards)5051708Sstevel sbdp_wnode_init(sbdp_wnode_t *wnodep, int wnode, int boards)
5061708Sstevel {
5071708Sstevel int i;
5081708Sstevel static fn_t f = "sbdp_wnode_init";
5091708Sstevel
5101708Sstevel SBDP_DBG_FUNC("%s\n", f);
5111708Sstevel
5121708Sstevel wnodep->wnode = wnode;
5131708Sstevel wnodep->nbds = boards;
5141708Sstevel wnodep->bds = kmem_zalloc(sizeof (sbdp_bd_t) * boards, KM_SLEEP);
5151708Sstevel wnodep->next = wnodep->prev = NULL;
5161708Sstevel
5171708Sstevel for (i = 0; i < boards; i++)
5181708Sstevel sbdp_bd_init(&wnodep->bds[i], i, wnode);
5191708Sstevel }
5201708Sstevel
5211708Sstevel /*
5221708Sstevel * Wnode got DRed out. Clean up all the node stuff including the boards
5231708Sstevel */
5241708Sstevel void
sbdp_wnode_fini(sbdp_wnode_t * wnodep)5251708Sstevel sbdp_wnode_fini(sbdp_wnode_t *wnodep)
5261708Sstevel {
5271708Sstevel int boards;
5281708Sstevel int i;
5291708Sstevel static fn_t f = "sbdp_wnode_fini";
5301708Sstevel
5311708Sstevel SBDP_DBG_FUNC("%s\n", f);
5321708Sstevel
5331708Sstevel boards = wnodep->nbds;
5341708Sstevel
5351708Sstevel for (i = 0; i < boards; i++)
5361708Sstevel sbdp_bd_fini(&wnodep->bds[i]);
5371708Sstevel
5381708Sstevel kmem_free(wnodep->bds, sizeof (sbdp_bd_t) * boards);
5391708Sstevel wnodep->next = wnodep->prev = NULL;
5401708Sstevel kmem_free(wnodep, sizeof (sbdp_wnode_t));
5411708Sstevel }
5421708Sstevel
5431708Sstevel /*
5441708Sstevel * Add all the necessary fields to this board's struct
5451708Sstevel */
5461708Sstevel void
sbdp_add_new_bd_info(int wnode,int board)5471708Sstevel sbdp_add_new_bd_info(int wnode, int board)
5481708Sstevel {
5491708Sstevel sbdp_wnode_t *cur;
5501708Sstevel static fn_t f = "sbdp_add_new_bd_info";
5511708Sstevel
5521708Sstevel SBDP_DBG_FUNC("%s\n", f);
5531708Sstevel
5541708Sstevel cur = sbdp_get_wnodep(wnode);
5551708Sstevel
5561708Sstevel SBDP_DBG_MISC("adding new board info %d\n", board);
5571708Sstevel
5581708Sstevel sbdp_update_bd_info(&cur->bds[board]);
5591708Sstevel
5601708Sstevel }
5611708Sstevel
5621708Sstevel /*
5631708Sstevel * This board has gone away. Clean the necessary fields
5641708Sstevel */
5651708Sstevel void
sbdp_cleanup_bd(int wnode,int board)5661708Sstevel sbdp_cleanup_bd(int wnode, int board)
5671708Sstevel {
5681708Sstevel sbdp_wnode_t *cur;
5691708Sstevel sbdp_handle_t handle, *hp;
5701708Sstevel sbdp_bd_t *bdp;
5711708Sstevel int i;
5721708Sstevel static fn_t f = "sbdp_cleanup_bd";
5731708Sstevel
5741708Sstevel SBDP_DBG_FUNC("%s\n", f);
5751708Sstevel
5761708Sstevel cur = sbdp_get_wnodep(wnode);
5771708Sstevel
5781708Sstevel SBDP_DBG_MISC("cleaning up bd info for bd %d\n", board);
5791708Sstevel if (cur == NULL) {
5801708Sstevel SBDP_DBG_MISC("cur is null\n");
5811708Sstevel return;
5821708Sstevel }
5831708Sstevel
5841708Sstevel bdp = &cur->bds[board];
5851708Sstevel
5861708Sstevel /*
5871708Sstevel * Grab the lock
5881708Sstevel */
5891708Sstevel mutex_enter(&bdp->bd_mutex);
5901708Sstevel
5911708Sstevel for (i = 0; i < bdp->nnum; i++)
5921708Sstevel bdp->nodes[i] = (pnode_t)0;
5931708Sstevel bdp->nnum = 0;
5941708Sstevel
5951708Sstevel sbdp_fini_bd_banks(bdp);
5961708Sstevel
5971708Sstevel hp = &handle;
5981708Sstevel hp->h_board = bdp->bd;
5991708Sstevel hp->h_wnode = bdp->wnode;
6001708Sstevel if (bdp->ml) {
601*11311SSurya.Prakki@Sun.COM (void) sbdp_del_memlist(hp, bdp->ml);
6021708Sstevel }
6031708Sstevel
6041708Sstevel bdp->ml = NULL;
6051708Sstevel
6061708Sstevel bdp->bpa = -1;
6071708Sstevel
6081708Sstevel sbdp_cpu_in_reset(wnode, bdp->bd, SBDP_ALL_CPUS, 0);
6091708Sstevel
6101708Sstevel bdp->cpus_present = 0;
6111708Sstevel
6121708Sstevel mutex_exit(&bdp->bd_mutex);
6131708Sstevel }
6141708Sstevel
6151708Sstevel /*
6161708Sstevel * Traverse the list looking for wnode. Return it when found
6171708Sstevel */
6181708Sstevel sbdp_wnode_t *
sbdp_get_wnodep(int wnode)6191708Sstevel sbdp_get_wnodep(int wnode)
6201708Sstevel {
6211708Sstevel sbdp_wnode_t *cur;
6221708Sstevel int i;
6231708Sstevel static fn_t f = "sbdp_get_wnodep";
6241708Sstevel
6251708Sstevel SBDP_DBG_FUNC("%s\n", f);
6261708Sstevel
6271708Sstevel mutex_enter(&sbdp_wnode_mutex);
6281708Sstevel for (i = 0, cur = first_node; i < cur_num_wnodes; i++,
6291708Sstevel cur = cur->next) {
6301708Sstevel if (cur->wnode == wnode) {
6311708Sstevel mutex_exit(&sbdp_wnode_mutex);
6321708Sstevel return (cur);
6331708Sstevel }
6341708Sstevel }
6351708Sstevel mutex_exit(&sbdp_wnode_mutex);
6361708Sstevel
6371708Sstevel return (NULL);
6381708Sstevel }
6391708Sstevel
6401708Sstevel /*
6411708Sstevel * Insert this brand new node into our master list. It leaves it all
6421708Sstevel * initialized
6431708Sstevel */
6441708Sstevel void
sbdp_insert_wnode(int wnode,int max_boards)6451708Sstevel sbdp_insert_wnode(int wnode, int max_boards)
6461708Sstevel {
6471708Sstevel sbdp_wnode_t *wnodep;
6481708Sstevel sbdp_wnode_t *cur;
6491708Sstevel static fn_t f = "sbdp_insert_wnode";
6501708Sstevel
6511708Sstevel SBDP_DBG_FUNC("%s\n", f);
6521708Sstevel
6531708Sstevel wnodep = kmem_zalloc(sizeof (sbdp_wnode_t), KM_SLEEP);
6541708Sstevel
6551708Sstevel mutex_enter(&sbdp_wnode_mutex);
6561708Sstevel if (first_node == NULL) {
6571708Sstevel first_node = wnodep;
6581708Sstevel cur_num_wnodes++;
6591708Sstevel } else {
6601708Sstevel cur = first_node + cur_num_wnodes++;
6611708Sstevel cur->next = wnodep;
6621708Sstevel wnodep->prev = cur;
6631708Sstevel }
6641708Sstevel mutex_exit(&sbdp_wnode_mutex);
6651708Sstevel sbdp_wnode_init(wnodep, wnode, max_boards);
6661708Sstevel }
6671708Sstevel
6681708Sstevel /*
6691708Sstevel * This node is gone. Remove it from the list and also clean up
6701708Sstevel */
6711708Sstevel void
sbdp_remove_wnode(sbdp_wnode_t * wnodep)6721708Sstevel sbdp_remove_wnode(sbdp_wnode_t *wnodep)
6731708Sstevel {
6741708Sstevel sbdp_wnode_t *cur;
6751708Sstevel static fn_t f = "sbdp_remove_wnode";
6761708Sstevel
6771708Sstevel SBDP_DBG_FUNC("%s\n", f);
6781708Sstevel
6791708Sstevel if (wnodep != NULL) {
6801708Sstevel sbdp_wnode_fini(wnodep);
6811708Sstevel mutex_enter(&sbdp_wnode_mutex);
6821708Sstevel
6831708Sstevel if (first_node == wnodep)
6841708Sstevel first_node = NULL;
6851708Sstevel else {
6861708Sstevel cur = wnodep->prev;
6871708Sstevel if (cur != NULL)
6881708Sstevel cur->next = wnodep->next;
6891708Sstevel if (wnodep->next != NULL)
6901708Sstevel wnodep->next->prev = cur;
6911708Sstevel }
6921708Sstevel
6931708Sstevel cur_num_wnodes--;
6941708Sstevel mutex_exit(&sbdp_wnode_mutex);
6951708Sstevel }
6961708Sstevel }
6971708Sstevel
6981708Sstevel /*
6991708Sstevel * Entry point from sbd. This is called when a new node is added. We
7001708Sstevel * create an entry in our inventory and initialize all the stuff that will be
7011708Sstevel * needed
7021708Sstevel */
7031708Sstevel int
sbdp_setup_instance(caddr_t arg)7041708Sstevel sbdp_setup_instance(caddr_t arg)
7051708Sstevel {
7061708Sstevel ssm_sbdp_info_t *sbdp_info;
7071708Sstevel int instance;
7081708Sstevel int wnode;
7091708Sstevel int max_boards;
7101708Sstevel static fn_t f = "sbdp_setup_instance";
7111708Sstevel
7121708Sstevel SBDP_DBG_FUNC("%s\n", f);
7131708Sstevel
7141708Sstevel /*
7151708Sstevel * We get this directly from ssm
7161708Sstevel */
7171708Sstevel sbdp_info = (ssm_sbdp_info_t *)arg;
7181708Sstevel
7191708Sstevel instance = sbdp_info->instance;
7201708Sstevel wnode = sbdp_info->wnode;
7211708Sstevel max_boards = plat_max_boards();
7221708Sstevel
7231708Sstevel SBDP_DBG_MISC("sbdp_setup_instance: instance %d wnode %d\n", instance,
7241708Sstevel sbdp_info->wnode);
7251708Sstevel
7261708Sstevel if (sbdp_get_wnodep(wnode) == NULL) {
7271708Sstevel /*
7281708Sstevel * This node has not been instanstiated
7291708Sstevel * create one
7301708Sstevel */
7311708Sstevel sbdp_insert_wnode(wnode, max_boards);
7321708Sstevel }
7331708Sstevel
7341708Sstevel return (DDI_SUCCESS);
7351708Sstevel }
7361708Sstevel
7371708Sstevel /*
7381708Sstevel * Entry point from sbd. This is called when a node has been removed (or is
7391708Sstevel * going away. We do all the necessary cleanup
7401708Sstevel */
7411708Sstevel int
sbdp_teardown_instance(caddr_t arg)7421708Sstevel sbdp_teardown_instance(caddr_t arg)
7431708Sstevel {
7441708Sstevel ssm_sbdp_info_t *sbdp_info;
7451708Sstevel int instance;
7461708Sstevel int wnode;
7471708Sstevel sbdp_wnode_t *wnodep;
7481708Sstevel static fn_t f = "sbdp_teardown_instance";
7491708Sstevel
7501708Sstevel SBDP_DBG_FUNC("%s\n", f);
7511708Sstevel
7521708Sstevel /*
7531708Sstevel * ssm should have set this up
7541708Sstevel */
7551708Sstevel sbdp_info = (ssm_sbdp_info_t *)arg;
7561708Sstevel
7571708Sstevel instance = sbdp_info->instance;
7581708Sstevel wnode = sbdp_info->wnode;
7591708Sstevel
7601708Sstevel SBDP_DBG_MISC("sbdp_teardown_instance: instance %d wnode %d\n",
7611708Sstevel instance, wnode);
7621708Sstevel
7631708Sstevel /*
7641708Sstevel * Find this node and then remove it
7651708Sstevel */
7661708Sstevel if ((wnodep = sbdp_get_wnodep(wnode)) != NULL) {
7671708Sstevel sbdp_remove_wnode(wnodep);
7681708Sstevel }
7691708Sstevel return (DDI_SUCCESS);
7701708Sstevel }
7711708Sstevel
7721708Sstevel int
sbdp_disabled_component(sbdp_handle_t * hp)7731708Sstevel sbdp_disabled_component(sbdp_handle_t *hp)
7741708Sstevel {
7751708Sstevel #ifdef lint
7761708Sstevel hp = hp;
7771708Sstevel #endif
7781708Sstevel return (0);
7791708Sstevel }
7801708Sstevel
7811708Sstevel /* ARGSUSED */
7821708Sstevel int
sbdp_release_component(sbdp_handle_t * hp,dev_info_t * dip)7831708Sstevel sbdp_release_component(sbdp_handle_t *hp, dev_info_t *dip)
7841708Sstevel {
7851708Sstevel return (0);
7861708Sstevel }
7871708Sstevel
7881708Sstevel void
sbdp_set_err(sbd_error_t * ep,int ecode,char * rsc)7891708Sstevel sbdp_set_err(sbd_error_t *ep, int ecode, char *rsc)
7901708Sstevel {
7911708Sstevel static fn_t f = "sbdp_set_err";
7921708Sstevel
7931708Sstevel SBDP_DBG_FUNC("%s\n", f);
7941708Sstevel ASSERT(ep != NULL);
7951708Sstevel ep->e_code = ecode;
7961708Sstevel
7971708Sstevel if (rsc != NULL) {
7981708Sstevel (void) strcpy((caddr_t)(ep->e_rsc), (caddr_t)rsc);
7991708Sstevel }
8001708Sstevel }
8011708Sstevel
8021708Sstevel /*
8031708Sstevel * Serengeti DR passthrus are for debugging purposes only.
8041708Sstevel */
8051708Sstevel static struct {
8061708Sstevel const char *name;
8071708Sstevel int (*handler)(sbdp_handle_t *, void *);
8081708Sstevel } sbdp_passthrus[] = {
8091708Sstevel #ifdef DEBUG
8101708Sstevel { "readmem", sbdp_passthru_readmem },
8111708Sstevel { "prep-script", sbdp_passthru_prep_script },
8121708Sstevel { "test-quiesce", sbdp_passthru_test_quiesce },
8131708Sstevel { "inject-error", sbdp_passthru_inject_error },
8141708Sstevel { "reset-error", sbdp_passthru_reset_error },
8151708Sstevel #endif
8161708Sstevel
8171708Sstevel /* the following line must always be last */
8181708Sstevel { NULL, NULL }
8191708Sstevel };
8201708Sstevel
8211708Sstevel
8221708Sstevel /*ARGSUSED*/
8231708Sstevel int
sbdp_ioctl(sbdp_handle_t * hp,sbdp_ioctl_arg_t * sbdpi)8241708Sstevel sbdp_ioctl(sbdp_handle_t *hp, sbdp_ioctl_arg_t *sbdpi)
8251708Sstevel {
8261708Sstevel #ifdef DEBUG
8271708Sstevel char buf[512];
8281708Sstevel int rv;
8291708Sstevel sbd_ioctl_arg_t *sbdi = (sbd_ioctl_arg_t *)sbdpi->h_iap;
8301708Sstevel int i;
8311708Sstevel static fn_t f = "sbdp_ioctl";
8321708Sstevel
8331708Sstevel SBDP_DBG_FUNC("%s\n", f);
8341708Sstevel
8351708Sstevel if (sbdi->i_len >= sizeof (buf) ||
8361708Sstevel ddi_copyin(sbdi->i_opts, buf, sbdi->i_len, sbdpi->h_mode)) {
8371708Sstevel sbdp_set_err(hp->h_err, ESBD_FAULT, NULL);
8381708Sstevel return (-1);
8391708Sstevel }
8401708Sstevel
8411708Sstevel i = 0;
8421708Sstevel while (sbdp_passthrus[i].name != NULL) {
8431708Sstevel int len;
8441708Sstevel
8451708Sstevel len = strlen(sbdp_passthrus[i].name);
8461708Sstevel if (strncmp(sbdp_passthrus[i].name, buf, len) == 0)
8471708Sstevel break;
8481708Sstevel i++;
8491708Sstevel }
8501708Sstevel
8511708Sstevel if (sbdp_passthrus[i].name == NULL) {
8521708Sstevel sbdp_set_err(hp->h_err, ESBD_INVAL, NULL);
8531708Sstevel rv = EIO;
8541708Sstevel } else {
8551708Sstevel rv = (*sbdp_passthrus[i].handler)(hp, buf);
8561708Sstevel if (rv != ESBD_NOERROR) {
8571708Sstevel sbdp_set_err(hp->h_err, rv, NULL);
8581708Sstevel rv = EIO;
8591708Sstevel }
8601708Sstevel
8611708Sstevel }
8621708Sstevel
8631708Sstevel return (rv);
8641708Sstevel #else
8651708Sstevel return (0);
8661708Sstevel #endif
8671708Sstevel }
8681708Sstevel
8691708Sstevel /*
8701708Sstevel * Check the dnode we obtained. Need to find a better way to determine
8711708Sstevel * if the node has the correct starting address
8721708Sstevel */
8731708Sstevel int
sbdp_is_node_bad(pnode_t node)8741708Sstevel sbdp_is_node_bad(pnode_t node)
8751708Sstevel {
8761708Sstevel static fn_t f = "sbdp_is_node_bad";
8771708Sstevel
8781708Sstevel SBDP_DBG_FUNC("%s\n", f);
8791708Sstevel
8801708Sstevel return ((node == OBP_NONODE) || (node == OBP_BADNODE) ||
8811708Sstevel ((node & 0x80000000u) != 0x80000000u));
8821708Sstevel }
8831708Sstevel
8841708Sstevel /*
8851708Sstevel * Retrieve the information we have on this board from
8861708Sstevel * the inventory
8871708Sstevel */
8881708Sstevel sbdp_bd_t *
sbdp_get_bd_info(int wnode,int board)8891708Sstevel sbdp_get_bd_info(int wnode, int board)
8901708Sstevel {
8911708Sstevel sbdp_wnode_t *wnodep;
8921708Sstevel sbdp_bd_t *bdp;
8931708Sstevel int max_bds;
8941708Sstevel static fn_t f = "sbdp_get_bd_info";
8951708Sstevel
8961708Sstevel SBDP_DBG_FUNC("%s\n", f);
8971708Sstevel
8981708Sstevel wnodep = sbdp_get_wnodep(wnode);
8991708Sstevel max_bds = plat_max_boards();
9001708Sstevel
9011708Sstevel if ((wnodep == NULL) || ((board < 0) && (board > max_bds))) {
9021708Sstevel return (NULL);
9031708Sstevel }
9041708Sstevel
9051708Sstevel bdp = &wnodep->bds[board];
9061708Sstevel
9071708Sstevel /*
9081708Sstevel * We might not have the complete bd info. With cheetah we
9091708Sstevel * cannot access the memory decode registers when then cpu is
9101708Sstevel * in reset. If the mem info is incomplete, then we try to gather it
9111708Sstevel * here
9121708Sstevel */
9131708Sstevel sbdp_update_bd_info(bdp);
9141708Sstevel
9151708Sstevel return (bdp);
9161708Sstevel }
9171708Sstevel
9181708Sstevel /*
9191708Sstevel * There are certain cases where obp marks components as failed
9201708Sstevel * If the status is ok the node won't have any status property. It
9211708Sstevel * is only there if the status is other than ok.
9221708Sstevel */
9231708Sstevel sbd_cond_t
sbdp_get_comp_status(pnode_t nodeid)9241708Sstevel sbdp_get_comp_status(pnode_t nodeid)
9251708Sstevel {
9261708Sstevel char status_buf[OBP_MAXPROPNAME];
9271708Sstevel static const char *status = "status";
9281708Sstevel static const char *failed = "fail";
9291708Sstevel static const char *disabled = "disabled";
9301708Sstevel static fn_t f = "sbdp_get_comp_status";
9311708Sstevel
9321708Sstevel SBDP_DBG_FUNC("%s\n", f);
9331708Sstevel
9341708Sstevel if (sbdp_is_node_bad(nodeid)) {
9351708Sstevel SBDP_DBG_STATE("node is not ok\n");
9361708Sstevel return (SBD_COND_UNKNOWN);
9371708Sstevel }
9381708Sstevel
9391708Sstevel if (prom_getproplen(nodeid, (char *)status) <= 0) {
9401708Sstevel SBDP_DBG_STATE("status is ok\n");
9411708Sstevel return (SBD_COND_OK);
9421708Sstevel }
9431708Sstevel
9441708Sstevel if (prom_getprop(nodeid, (char *)status, status_buf) < 0) {
9451708Sstevel SBDP_DBG_STATE("status is unknown\n");
9461708Sstevel return (SBD_COND_UNKNOWN);
9471708Sstevel }
9481708Sstevel
9491708Sstevel if (strncmp(status_buf, failed, strlen(failed)) == 0) {
9501708Sstevel SBDP_DBG_STATE("status of failed\n");
9511708Sstevel return (SBD_COND_FAILED);
9521708Sstevel }
9531708Sstevel
9541708Sstevel if (strcmp(status_buf, disabled) == 0) {
9551708Sstevel SBDP_DBG_STATE("status of unusable\n");
9561708Sstevel return (SBD_COND_UNUSABLE);
9571708Sstevel }
9581708Sstevel
9591708Sstevel return (SBD_COND_OK);
9601708Sstevel }
9611708Sstevel
9621708Sstevel void
sbdp_cpu_in_reset(int node,int bd,int unit,int reset)9631708Sstevel sbdp_cpu_in_reset(int node, int bd, int unit, int reset)
9641708Sstevel {
9651708Sstevel sbdp_wnode_t *cur;
9661708Sstevel sbdp_bd_t *bdp;
9671708Sstevel static fn_t f = "sbdp_cpu_in_reset";
9681708Sstevel
9691708Sstevel SBDP_DBG_FUNC("%s\n", f);
9701708Sstevel
9711708Sstevel if ((unit < -1) || (bd < 0) || (node < 0)) {
9721708Sstevel return;
9731708Sstevel }
9741708Sstevel
9751708Sstevel cur = sbdp_get_wnodep(node);
9761708Sstevel
9771708Sstevel SBDP_DBG_MISC("marking cpu %d %s for board %d\n", unit,
9781708Sstevel (reset) ? "in reset" : "out of reset", bd);
9791708Sstevel
9801708Sstevel if (cur == NULL) {
9811708Sstevel return;
9821708Sstevel }
9831708Sstevel
9841708Sstevel bdp = &cur->bds[bd];
9851708Sstevel
9861708Sstevel if (unit == SBDP_ALL_CPUS)
9871708Sstevel if (reset == 1)
9881708Sstevel SBDP_SET_ALL_CPUS_IN_RESET(bdp);
9891708Sstevel else
9901708Sstevel SBDP_UNSET_ALL_CPUS_IN_RESET(bdp);
9911708Sstevel else
9921708Sstevel if (reset == 1)
9931708Sstevel SBDP_SET_CPU_IN_RESET(bdp, unit);
9941708Sstevel else
9951708Sstevel SBDP_UNSET_CPU_IN_RESET(bdp, unit);
9961708Sstevel }
9971708Sstevel
9981708Sstevel int
sbdp_set_cpu_present(int node,int bd,int unit)9991708Sstevel sbdp_set_cpu_present(int node, int bd, int unit)
10001708Sstevel {
10011708Sstevel sbdp_wnode_t *cur;
10021708Sstevel sbdp_bd_t *bdp;
10031708Sstevel static fn_t f = "sbdp_set_cpu_present";
10041708Sstevel
10051708Sstevel SBDP_DBG_FUNC("%s\n", f);
10061708Sstevel
10071708Sstevel if ((unit < 0) || (bd < 0) || (node < 0)) {
10081708Sstevel return (-1);
10091708Sstevel }
10101708Sstevel
10111708Sstevel cur = sbdp_get_wnodep(node);
10121708Sstevel if (cur == NULL) {
10131708Sstevel return (-1);
10141708Sstevel }
10151708Sstevel
10161708Sstevel bdp = &cur->bds[bd];
10171708Sstevel
10181708Sstevel SBDP_SET_CPU_PRESENT(bdp, unit);
10191708Sstevel
10201708Sstevel return (0);
10211708Sstevel }
10221708Sstevel
10231708Sstevel int
sbdp_is_cpu_present(int node,int bd,int unit)10241708Sstevel sbdp_is_cpu_present(int node, int bd, int unit)
10251708Sstevel {
10261708Sstevel sbdp_wnode_t *cur;
10271708Sstevel sbdp_bd_t *bdp;
10281708Sstevel static fn_t f = "sbdp_is_cpu_present";
10291708Sstevel
10301708Sstevel SBDP_DBG_FUNC("%s\n", f);
10311708Sstevel
10321708Sstevel if ((unit < 0) || (bd < 0) || (node < 0)) {
10331708Sstevel return (-1);
10341708Sstevel }
10351708Sstevel
10361708Sstevel cur = sbdp_get_wnodep(node);
10371708Sstevel if (cur == NULL) {
10381708Sstevel return (-1);
10391708Sstevel }
10401708Sstevel
10411708Sstevel bdp = &cur->bds[bd];
10421708Sstevel
10431708Sstevel return (SBDP_IS_CPU_PRESENT(bdp, unit));
10441708Sstevel }
10451708Sstevel
10461708Sstevel int
sbdp_is_cpu_in_reset(int node,int bd,int unit)10471708Sstevel sbdp_is_cpu_in_reset(int node, int bd, int unit)
10481708Sstevel {
10491708Sstevel sbdp_wnode_t *cur;
10501708Sstevel sbdp_bd_t *bdp;
10511708Sstevel static fn_t f = "sbdp_is_cpu_in_reset";
10521708Sstevel
10531708Sstevel SBDP_DBG_FUNC("%s\n", f);
10541708Sstevel
10551708Sstevel if ((unit < 0) || (bd < 0) || (node < 0)) {
10561708Sstevel return (-1);
10571708Sstevel }
10581708Sstevel
10591708Sstevel cur = sbdp_get_wnodep(node);
10601708Sstevel
10611708Sstevel if (cur == NULL) {
10621708Sstevel return (-1);
10631708Sstevel }
10641708Sstevel
10651708Sstevel bdp = &cur->bds[bd];
10661708Sstevel
10671708Sstevel return (SBDP_IS_CPU_IN_RESET(bdp, unit));
10681708Sstevel }
10691708Sstevel
10701708Sstevel int
sbdp_dr_avail(void)10711708Sstevel sbdp_dr_avail(void)
10721708Sstevel {
10731708Sstevel static fn_t f = "sbdp_dr_avail";
10741708Sstevel
10751708Sstevel SBDP_DBG_FUNC("%s\n", f);
10761708Sstevel
10771708Sstevel if (sbdp_dr_available)
10781708Sstevel if (sg_prom_sb_dr_check() == 0)
10791708Sstevel return (1);
10801708Sstevel return (0);
10811708Sstevel }
1082