diff options
Diffstat (limited to 'usr/src')
444 files changed, 34336 insertions, 11952 deletions
diff --git a/usr/src/Makefile.lint b/usr/src/Makefile.lint index 07302499f5..00cea4ea4b 100644 --- a/usr/src/Makefile.lint +++ b/usr/src/Makefile.lint @@ -20,7 +20,7 @@ # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -405,7 +405,7 @@ sparc_SUBDIRS= \ lib/wrsm \ stand -$(CLOSED_BUILD)sparc_SUBDIRS += $(CLOSED)/cmd/mtst +$(CLOSED_BUILD)COMMON_SUBDIRS += $(CLOSED)/cmd/mtst LINTSUBDIRS= $(COMMON_SUBDIRS) $($(MACH)_SUBDIRS) diff --git a/usr/src/cmd/Makefile b/usr/src/cmd/Makefile index 782f634907..3957b67f77 100644 --- a/usr/src/cmd/Makefile +++ b/usr/src/cmd/Makefile @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -424,6 +424,7 @@ $(CLOSED_BUILD)COMMON_SUBDIRS += \ $(CLOSED)/cmd/llc2 \ $(CLOSED)/cmd/localedef \ $(CLOSED)/cmd/more_xpg4 \ + $(CLOSED)/cmd/mtst \ $(CLOSED)/cmd/od \ $(CLOSED)/cmd/patch \ $(CLOSED)/cmd/pax \ @@ -447,7 +448,6 @@ sparc_SUBDIRS= \ cvcd \ dcs \ fruadm \ - $(CLOSED)/cmd/mtst \ prtfru \ $(CLOSED)/cmd/scadm \ sckmd \ diff --git a/usr/src/cmd/devfsadm/i386/misc_link_i386.c b/usr/src/cmd/devfsadm/i386/misc_link_i386.c index d588d0a828..484214dfa7 100644 --- a/usr/src/cmd/devfsadm/i386/misc_link_i386.c +++ b/usr/src/cmd/devfsadm/i386/misc_link_i386.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -33,6 +33,7 @@ #include <stdlib.h> #include <limits.h> #include <ctype.h> +#include <sys/mc.h> static int lp(di_minor_t minor, di_node_t node); static int serial_dialout(di_minor_t minor, di_node_t node); @@ -43,6 +44,7 @@ static int kdmouse(di_minor_t minor, di_node_t node); static int bmc(di_minor_t minor, di_node_t node); static int smbios(di_minor_t minor, di_node_t node); static int agp_process(di_minor_t minor, di_node_t node); +static int mc_node(di_minor_t minor, di_node_t node); static devfsadm_create_t misc_cbt[] = { { "vt00", "ddi_display", NULL, @@ -69,17 +71,20 @@ static devfsadm_create_t misc_cbt[] = { { "serial", "ddi_serial:dialout,mb", NULL, TYPE_EXACT, ILEVEL_1, serial_dialout }, - {"agp", "ddi_agp:pseudo", NULL, + { "agp", "ddi_agp:pseudo", NULL, TYPE_EXACT, ILEVEL_0, agp_process }, - {"agp", "ddi_agp:target", NULL, + { "agp", "ddi_agp:target", NULL, TYPE_EXACT, ILEVEL_0, agp_process }, - {"agp", "ddi_agp:cpugart", NULL, + { "agp", "ddi_agp:cpugart", NULL, TYPE_EXACT, ILEVEL_0, agp_process }, - {"agp", "ddi_agp:master", NULL, + { "agp", "ddi_agp:master", NULL, TYPE_EXACT, ILEVEL_0, agp_process + }, + { "memory-controller", "ddi_mem_ctrl", NULL, + TYPE_EXACT, ILEVEL_0, mc_node } }; @@ -428,3 +433,30 @@ agp_process(di_minor_t minor, di_node_t node) return (DEVFSADM_CONTINUE); } + +/* + * /dev/mc/mc<chipid> -> /devices/.../pci1022,1102@<chipid+24>,2:mc-amd + */ +static int +mc_node(di_minor_t minor, di_node_t node) +{ + const char *minorname = di_minor_name(minor); + const char *busaddr = di_bus_addr(node); + char linkpath[PATH_MAX]; + int unitaddr; + char *c; + + if (minorname == NULL || busaddr == NULL) + return (DEVFSADM_CONTINUE); + + errno = 0; + unitaddr = strtol(busaddr, &c, 16); + + if (errno != 0 || unitaddr < MC_AMD_DEV_OFFSET) + return (DEVFSADM_CONTINUE); + + (void) snprintf(linkpath, sizeof (linkpath), "mc/mc%u", + unitaddr - MC_AMD_DEV_OFFSET); + (void) devfsadm_mklink(linkpath, node, minor, 0); + return (DEVFSADM_CONTINUE); +} diff --git a/usr/src/cmd/fm/Makefile b/usr/src/cmd/fm/Makefile index 976f8e3e05..e4861dd8ed 100644 --- a/usr/src/cmd/fm/Makefile +++ b/usr/src/cmd/fm/Makefile @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -31,12 +31,12 @@ SUBDIRS = \ fmdump \ fminject \ fmstat \ + fmtopo \ schemes \ scripts \ modules \ dicts \ - eversholt \ - topo + eversholt include ./Makefile.subdirs diff --git a/usr/src/cmd/fm/dicts/AMD.dict b/usr/src/cmd/fm/dicts/AMD.dict new file mode 100644 index 0000000000..5a3e0f0321 --- /dev/null +++ b/usr/src/cmd/fm/dicts/AMD.dict @@ -0,0 +1,47 @@ +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +#ident "%Z%%M% %I% %E% SMI" +# +# DO NOT EDIT -- this file is generated by the Event Registry. +# + +FMDICT: name=AMD version=1 maxkey=1 dictid=0x414d + +fault.memory.page=1 +fault.memory.dimm_sb=2 +fault.memory.dimm_ck=3 +fault.memory.dimm_ue=4 +fault.cpu.amd.l2cachedata=5 +fault.cpu.amd.l2cachetag=6 +fault.cpu.amd.icachedata=7 +fault.cpu.amd.icachetag=8 +fault.cpu.amd.icachestag=9 +fault.cpu.amd.dcachedata=10 +fault.cpu.amd.dcachetag=11 +fault.cpu.amd.l1itlb=12 +fault.cpu.amd.l2itlb=13 +fault.cpu.amd.dcachestag=14 +fault.cpu.amd.l1dtlb=15 +fault.cpu.amd.l2dtlb=16 +fault.cpu.amd.datapath=17 diff --git a/usr/src/cmd/fm/dicts/AMD.po b/usr/src/cmd/fm/dicts/AMD.po new file mode 100644 index 0000000000..897a9066f6 --- /dev/null +++ b/usr/src/cmd/fm/dicts/AMD.po @@ -0,0 +1,299 @@ +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +#ident "%Z%%M% %I% %E% SMI" +# +# DO NOT EDIT -- this file is generated by the Event Registry. +# +# +# code: AMD-8000-1W +# keys: fault.memory.page +# +msgid "AMD-8000-1W.type" +msgstr "Fault" +msgid "AMD-8000-1W.severity" +msgstr "Minor" +msgid "AMD-8000-1W.description" +msgstr "The number of errors associated with this memory page has exceeded acceptable levels. Refer to %s for more information." +msgid "AMD-8000-1W.response" +msgstr "An attempt will be made to remove this memory page from service." +msgid "AMD-8000-1W.impact" +msgstr "The performance of the system may be minimally impacted as a result of removing the memory page from operation." +msgid "AMD-8000-1W.action" +msgstr "No repair action is recommended at this time." +# +# code: AMD-8000-2F +# keys: fault.memory.dimm_sb +# +msgid "AMD-8000-2F.type" +msgstr "Fault" +msgid "AMD-8000-2F.severity" +msgstr "Major" +msgid "AMD-8000-2F.description" +msgstr "The number of errors associated with this memory module has exceeded acceptable levels. Refer to %s for more information." +msgid "AMD-8000-2F.response" +msgstr "Pages of memory associated with this memory module are being removed from service as errors are reported." +msgid "AMD-8000-2F.impact" +msgstr "Total system memory capacity will be reduced as pages are retired." +msgid "AMD-8000-2F.action" +msgstr "Schedule a repair procedure to replace the affected memory module. Use fmdump -v -u to identify the module." +# +# code: AMD-8000-3K +# keys: fault.memory.dimm_ck +# +msgid "AMD-8000-3K.type" +msgstr "Fault" +msgid "AMD-8000-3K.severity" +msgstr "Major" +msgid "AMD-8000-3K.description" +msgstr "The number of errors associated with this memory module has exceeded acceptable levels. Refer to %s for more information." +msgid "AMD-8000-3K.response" +msgstr "Pages of memory associated with this memory module are being removed from service as errors are reported." +msgid "AMD-8000-3K.impact" +msgstr "Total system memory capacity will be reduced as pages are retired." +msgid "AMD-8000-3K.action" +msgstr "Schedule a repair procedure to replace the affected memory module. Use fmdump -v -u to identify the module." +# +# code: AMD-8000-48 +# keys: fault.memory.dimm_ue +# +msgid "AMD-8000-48.type" +msgstr "Fault" +msgid "AMD-8000-48.severity" +msgstr "Major" +msgid "AMD-8000-48.description" +msgstr "The number of errors associated with this memory module has exceeded acceptable levels. Refer to %s for more information." +msgid "AMD-8000-48.response" +msgstr "Pages of memory associated with this memory module are being removed from service as errors are reported." +msgid "AMD-8000-48.impact" +msgstr "Total system memory capacity will be reduced as pages are retired." +msgid "AMD-8000-48.action" +msgstr "Schedule a repair procedure to replace the affected memory module. Use fmdump -v -u to identify the module." +# +# code: AMD-8000-5M +# keys: fault.cpu.amd.l2cachedata +# +msgid "AMD-8000-5M.type" +msgstr "Fault" +msgid "AMD-8000-5M.severity" +msgstr "Major" +msgid "AMD-8000-5M.description" +msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." +msgid "AMD-8000-5M.response" +msgstr "An attempt will be made to remove this CPU from service." +msgid "AMD-8000-5M.impact" +msgstr "Performance of this system may be affected." +msgid "AMD-8000-5M.action" +msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u to identify the module." +# +# code: AMD-8000-67 +# keys: fault.cpu.amd.l2cachetag +# +msgid "AMD-8000-67.type" +msgstr "Fault" +msgid "AMD-8000-67.severity" +msgstr "Major" +msgid "AMD-8000-67.description" +msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." +msgid "AMD-8000-67.response" +msgstr "An attempt will be made to remove this CPU from service." +msgid "AMD-8000-67.impact" +msgstr "Performance of this system may be affected." +msgid "AMD-8000-67.action" +msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u to identify the module." +# +# code: AMD-8000-7U +# keys: fault.cpu.amd.icachedata +# +msgid "AMD-8000-7U.type" +msgstr "Fault" +msgid "AMD-8000-7U.severity" +msgstr "Major" +msgid "AMD-8000-7U.description" +msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." +msgid "AMD-8000-7U.response" +msgstr "An attempt will be made to remove this CPU from service." +msgid "AMD-8000-7U.impact" +msgstr "Performance of this system may be affected." +msgid "AMD-8000-7U.action" +msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u to identify the module." +# +# code: AMD-8000-8L +# keys: fault.cpu.amd.icachetag +# +msgid "AMD-8000-8L.type" +msgstr "Fault" +msgid "AMD-8000-8L.severity" +msgstr "Major" +msgid "AMD-8000-8L.description" +msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." +msgid "AMD-8000-8L.response" +msgstr "An attempt will be made to remove this CPU from service." +msgid "AMD-8000-8L.impact" +msgstr "Performance of this system may be affected." +msgid "AMD-8000-8L.action" +msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u to identify the module." +# +# code: AMD-8000-9G +# keys: fault.cpu.amd.icachestag +# +msgid "AMD-8000-9G.type" +msgstr "Fault" +msgid "AMD-8000-9G.severity" +msgstr "Major" +msgid "AMD-8000-9G.description" +msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." +msgid "AMD-8000-9G.response" +msgstr "An attempt will be made to remove this CPU from service." +msgid "AMD-8000-9G.impact" +msgstr "Performance of this system may be affected." +msgid "AMD-8000-9G.action" +msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u to identify the module." +# +# code: AMD-8000-AV +# keys: fault.cpu.amd.dcachedata +# +msgid "AMD-8000-AV.type" +msgstr "Fault" +msgid "AMD-8000-AV.severity" +msgstr "Major" +msgid "AMD-8000-AV.description" +msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." +msgid "AMD-8000-AV.response" +msgstr "An attempt will be made to remove this CPU from service." +msgid "AMD-8000-AV.impact" +msgstr "Performance of this system may be affected." +msgid "AMD-8000-AV.action" +msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u to identify the module." +# +# code: AMD-8000-C0 +# keys: fault.cpu.amd.dcachetag +# +msgid "AMD-8000-C0.type" +msgstr "Fault" +msgid "AMD-8000-C0.severity" +msgstr "Major" +msgid "AMD-8000-C0.description" +msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." +msgid "AMD-8000-C0.response" +msgstr "An attempt will be made to remove this CPU from service." +msgid "AMD-8000-C0.impact" +msgstr "Performance of this system may be affected." +msgid "AMD-8000-C0.action" +msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u to identify the module." +# +# code: AMD-8000-DT +# keys: fault.cpu.amd.l1itlb +# +msgid "AMD-8000-DT.type" +msgstr "Fault" +msgid "AMD-8000-DT.severity" +msgstr "Major" +msgid "AMD-8000-DT.description" +msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." +msgid "AMD-8000-DT.response" +msgstr "An attempt will be made to remove this CPU from service." +msgid "AMD-8000-DT.impact" +msgstr "Performance of this system may be affected." +msgid "AMD-8000-DT.action" +msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u to identify the module." +# +# code: AMD-8000-E6 +# keys: fault.cpu.amd.l2itlb +# +msgid "AMD-8000-E6.type" +msgstr "Fault" +msgid "AMD-8000-E6.severity" +msgstr "Major" +msgid "AMD-8000-E6.description" +msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." +msgid "AMD-8000-E6.response" +msgstr "An attempt will be made to remove this CPU from service." +msgid "AMD-8000-E6.impact" +msgstr "Performance of this system may be affected." +msgid "AMD-8000-E6.action" +msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u to identify the module." +# +# code: AMD-8000-FN +# keys: fault.cpu.amd.dcachestag +# +msgid "AMD-8000-FN.type" +msgstr "Fault" +msgid "AMD-8000-FN.severity" +msgstr "Major" +msgid "AMD-8000-FN.description" +msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." +msgid "AMD-8000-FN.response" +msgstr "An attempt will be made to remove this CPU from service." +msgid "AMD-8000-FN.impact" +msgstr "Performance of this system may be affected." +msgid "AMD-8000-FN.action" +msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u to identify the module." +# +# code: AMD-8000-G9 +# keys: fault.cpu.amd.l1dtlb +# +msgid "AMD-8000-G9.type" +msgstr "Fault" +msgid "AMD-8000-G9.severity" +msgstr "Major" +msgid "AMD-8000-G9.description" +msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." +msgid "AMD-8000-G9.response" +msgstr "An attempt will be made to remove this CPU from service." +msgid "AMD-8000-G9.impact" +msgstr "Performance of this system may be affected." +msgid "AMD-8000-G9.action" +msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u to identify the module." +# +# code: AMD-8000-HK +# keys: fault.cpu.amd.l2dtlb +# +msgid "AMD-8000-HK.type" +msgstr "Fault" +msgid "AMD-8000-HK.severity" +msgstr "Major" +msgid "AMD-8000-HK.description" +msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." +msgid "AMD-8000-HK.response" +msgstr "An attempt will be made to remove this CPU from service." +msgid "AMD-8000-HK.impact" +msgstr "Performance of this system may be affected." +msgid "AMD-8000-HK.action" +msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u to identify the module." +# +# code: AMD-8000-JF +# keys: fault.cpu.amd.datapath +# +msgid "AMD-8000-JF.type" +msgstr "Fault" +msgid "AMD-8000-JF.severity" +msgstr "Major" +msgid "AMD-8000-JF.description" +msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." +msgid "AMD-8000-JF.response" +msgstr "An attempt will be made to remove this CPU from service." +msgid "AMD-8000-JF.impact" +msgstr "Performance of this system may be affected." +msgid "AMD-8000-JF.action" +msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u to identify the module." diff --git a/usr/src/cmd/fm/dicts/Makefile b/usr/src/cmd/fm/dicts/Makefile index 3e2c670c1f..0693aff863 100644 --- a/usr/src/cmd/fm/dicts/Makefile +++ b/usr/src/cmd/fm/dicts/Makefile @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -36,6 +36,9 @@ common_DCNAMES = \ SCA500 \ SCA1000 +i386_DCNAMES = \ + AMD + sparc_DCNAMES = \ SUN4 \ SUN4U \ @@ -47,7 +50,8 @@ DCNAMES = \ ALLDCNAMES = \ $(common_DCNAMES) \ - $(sparc_DCNAMES) + $(sparc_DCNAMES) \ + $(i386_DCNAMES) DCFILES = $(DCNAMES:%=%.dict) POFILES = $(DCNAMES:%=%.po) diff --git a/usr/src/cmd/fm/eversholt/common/check.c b/usr/src/cmd/fm/eversholt/common/check.c index 6be85ec55b..4c82d3cd6c 100644 --- a/usr/src/cmd/fm/eversholt/common/check.c +++ b/usr/src/cmd/fm/eversholt/common/check.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * check.c -- routines for checking the prop tree @@ -47,12 +47,15 @@ static int check_reportlist(enum nodetype t, const char *s, struct node *np); static int check_num(enum nodetype t, const char *s, struct node *np); static int check_quote(enum nodetype t, const char *s, struct node *np); +static int check_action(enum nodetype t, const char *s, struct node *np); static int check_num_func(enum nodetype t, const char *s, struct node *np); static int check_fru_asru(enum nodetype t, const char *s, struct node *np); static int check_engine(enum nodetype t, const char *s, struct node *np); +static int check_count(enum nodetype t, const char *s, struct node *np); static int check_timeval(enum nodetype t, const char *s, struct node *np); static int check_id(enum nodetype t, const char *s, struct node *np); static int check_serd_method(enum nodetype t, const char *s, struct node *np); +static int check_serd_id(enum nodetype t, const char *s, struct node *np); static int check_nork(struct node *np); static void check_cycle_lhs(struct node *stmtnp, struct node *arrow); static void check_cycle_lhs_try(struct node *stmtnp, struct node *lhs, @@ -70,6 +73,9 @@ static struct { { T_FAULT, "FITrate", 1, check_num_func, O_ERR }, { T_FAULT, "FRU", 0, check_fru_asru, O_ERR }, { T_FAULT, "ASRU", 0, check_fru_asru, O_ERR }, + { T_FAULT, "message", 0, check_num_func, O_ERR }, + { T_FAULT, "action", 0, check_action, O_ERR }, + { T_FAULT, "count", 0, check_count, O_ERR }, { T_UPSET, "engine", 0, check_engine, O_ERR }, { T_DEFECT, "FRU", 0, check_fru_asru, O_ERR }, { T_DEFECT, "ASRU", 0, check_fru_asru, O_ERR }, @@ -80,6 +86,7 @@ static struct { { T_SERD, "method", 1, check_serd_method, O_ERR }, { T_SERD, "trip", 1, check_reportlist, O_ERR }, { T_SERD, "FRU", 0, check_fru_asru, O_ERR }, + { T_SERD, "id", 0, check_serd_id, O_ERR }, { T_ERROR, "ASRU", 0, check_fru_asru, O_ERR }, { T_CONFIG, NULL, 0, check_quote, O_ERR }, { 0, NULL, 0 }, @@ -255,6 +262,18 @@ check_quote(enum nodetype t, const char *s, struct node *np) } static int +check_action(enum nodetype t, const char *s, struct node *np) +{ + ASSERTinfo(np != NULL, ptree_nodetype2str(t)); + + if (np->t != T_FUNC) + outfl(O_ERR, np->file, np->line, + "%s %s property must be a function or list of functions", + ptree_nodetype2str(t), s); + return (1); +} + +static int check_num_func(enum nodetype t, const char *s, struct node *np) { ASSERTinfo(np != NULL, ptree_nodetype2str(t)); @@ -307,6 +326,20 @@ check_engine(enum nodetype t, const char *s, struct node *np) } static int +check_count(enum nodetype t, const char *s, struct node *np) +{ + ASSERTinfo(np != NULL, ptree_nodetype2str(t)); + if (np->t != T_EVENT) + outfl(O_ERR, np->file, np->line, + "%s %s property must be an engine name " + "(i.e. stat.x or stat.x@a/b)", + ptree_nodetype2str(t), s); + + /* XXX confirm engine has been declared */ + return (1); +} + +static int check_timeval(enum nodetype t, const char *s, struct node *np) { ASSERTinfo(np != NULL, ptree_nodetype2str(t)); @@ -341,6 +374,17 @@ check_serd_method(enum nodetype t, const char *s, struct node *np) return (1); } +static int +check_serd_id(enum nodetype t, const char *s, struct node *np) +{ + ASSERTinfo(np != NULL, ptree_nodetype2str(t)); + if (np->t != T_GLOBID) + outfl(O_ERR, np->file, np->line, + "%s %s property must be a global ID", + ptree_nodetype2str(t), s); + return (1); +} + void check_stmt_required_properties(struct node *stmtnp) { @@ -791,7 +835,7 @@ check_cycle_lhs(struct node *stmtnp, struct node *arrow) /* * return if there's a list of events internal to * cascaded props (which is not allowed) - */ + */ if (arrow->u.arrow.lhs->u.arrow.rhs->t != T_EVENT) return; @@ -1081,6 +1125,14 @@ check_func(struct node *np) "argument to is_type() must be a call to " "fru() or asru()"); } + } else if (np->u.func.s == L_confcall) { + if (np->u.func.arglist->t != T_QUOTE && + (np->u.func.arglist->t != T_LIST || + np->u.func.arglist->u.expr.left->t != T_QUOTE)) + outfl(O_ERR, np->u.func.arglist->file, + np->u.func.arglist->line, + "confcall(): first argument must be a string " + "(the name of the operation)"); } else if (np->u.func.s == L_confprop) { if (np->u.func.arglist->t == T_LIST && (np->u.func.arglist->u.expr.left->t == T_FUNC && @@ -1095,11 +1147,49 @@ check_func(struct node *np) "fru() or asru(); " "second argument must be a string"); } + } else if (np->u.func.s == L_count) { + if (np->u.func.arglist->t != T_EVENT) { + outfl(O_ERR, np->u.func.arglist->file, + np->u.func.arglist->line, + "count(): argument must be an engine name"); + } + } else if (np->u.func.s == L_defined) { + if (np->u.func.arglist->t != T_GLOBID) + outfl(O_ERR, np->u.func.arglist->file, + np->u.func.arglist->line, + "argument to defined() must be a global"); } else if (np->u.func.s == L_payloadprop) { if (np->u.func.arglist->t != T_QUOTE) outfl(O_ERR, np->u.func.arglist->file, np->u.func.arglist->line, "argument to payloadprop() must be a string"); + } else if (np->u.func.s == L_payloadprop_contains) { + if (np->u.func.arglist->t != T_LIST || + np->u.func.arglist->u.expr.left->t != T_QUOTE || + np->u.func.arglist->u.expr.right == NULL) + outfl(O_ERR, np->u.func.arglist->file, + np->u.func.arglist->line, + "args to payloadprop_contains(): must be a quoted " + "string (property name) and an expression " + "(to match)"); + } else if (np->u.func.s == L_payloadprop_defined) { + if (np->u.func.arglist->t != T_QUOTE) + outfl(O_ERR, np->u.func.arglist->file, + np->u.func.arglist->line, + "arg to payloadprop_defined(): must be a quoted " + "string"); + } else if (np->u.func.s == L_setpayloadprop) { + if (np->u.func.arglist->t == T_LIST && + np->u.func.arglist->u.expr.left->t == T_QUOTE) { + if (np->u.func.arglist->u.expr.right->t == T_FUNC) + check_func(np->u.func.arglist->u.expr.right); + } else { + outfl(O_ERR, np->u.func.arglist->file, + np->u.func.arglist->line, + "setpayloadprop(): " + "first arg must be a string, " + "second arg a value"); + } } else if (np->u.func.s == L_envprop) { if (np->u.func.arglist->t != T_QUOTE) outfl(O_ERR, np->u.func.arglist->file, @@ -1130,7 +1220,7 @@ void check_event(struct node *np) { ASSERT(np != NULL); - ASSERT(np->t == T_EVENT); + ASSERTinfo(np->t == T_EVENT, ptree_nodetype2str(np->t)); if (np->u.event.epname == NULL) { outfl(O_ERR|O_NONL, np->file, np->line, diff --git a/usr/src/cmd/fm/eversholt/common/esclex.c b/usr/src/cmd/fm/eversholt/common/esclex.c index ef69da88ce..89faae18b8 100644 --- a/usr/src/cmd/fm/eversholt/common/esclex.c +++ b/usr/src/cmd/fm/eversholt/common/esclex.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * esclex.c -- lexer for esc @@ -99,6 +99,7 @@ static const struct { const int val; } Rwords[] = { { "asru", ASRU }, + { "count", COUNT }, { "div", DIV }, { "engine", ENGINE }, { "event", EVENT }, diff --git a/usr/src/cmd/fm/eversholt/common/escparse.y b/usr/src/cmd/fm/eversholt/common/escparse.y index 94136d7396..2e88efdc1a 100644 --- a/usr/src/cmd/fm/eversholt/common/escparse.y +++ b/usr/src/cmd/fm/eversholt/common/escparse.y @@ -20,7 +20,7 @@ * * CDDL HEADER END * - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * escparse.y -- parser for esc @@ -85,7 +85,7 @@ %right '!' '~' %left '.' -%token <tok> PROP MASK ARROW EVENT ENGINE ASRU FRU CONFIG +%token <tok> PROP MASK ARROW EVENT ENGINE ASRU FRU COUNT CONFIG %token <tok> ID QUOTE NUMBER IF PATHFUNC %type <tok> enameid %type <np> root stmtlist stmt nvpairlist nvpair nvname nvexpr @@ -189,6 +189,12 @@ nvpair : nvname '=' nvexpr $$ = tree_expr(T_NVPAIR, tree_name($1.s, IT_NONE, $1.file, $1.line), $3); } + | COUNT '=' nvexpr + /* "count" is a reserved word, but a valid property name */ + { + $$ = tree_expr(T_NVPAIR, + tree_name($1.s, IT_NONE, $1.file, $1.line), $3); + } ; nvname : ID @@ -205,6 +211,8 @@ nvexpr : numexpr | ename epname { $$ = tree_event($1, $2, NULL); } | pname + | globid + | func | NUMBER ID /* * ID must be timevals only ("ms", "us", etc.). @@ -357,11 +365,16 @@ parg : pfunc { $$ = tree_quote($1.s, $1.file, $1.line); } ; -/* asru() and fru() show up as functions in the parse tree */ +/* + * these functions are in the grammar so we can force the arg to be + * a path or an event. they show up as functions in the parse tree. + */ pfunc : ASRU '(' pname ')' { $$ = tree_func($1.s, tree_pname($3), $1.file, $1.line); } | FRU '(' pname ')' { $$ = tree_func($1.s, tree_pname($3), $1.file, $1.line); } + | COUNT '(' event ')' + { $$ = tree_func($1.s, $3, $1.file, $1.line); } ; globid : '$' ID diff --git a/usr/src/cmd/fm/eversholt/common/literals.h b/usr/src/cmd/fm/eversholt/common/literals.h index a695ccb5cc..bfb87a8ef5 100644 --- a/usr/src/cmd/fm/eversholt/common/literals.h +++ b/usr/src/cmd/fm/eversholt/common/literals.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * literals.h -- public definitions for literals in string table @@ -72,6 +72,7 @@ L_DECL(ereport); /* engine types */ L_DECL(serd); +L_DECL(stat); /* timeval suffixes */ L_DECL(nanosecond); @@ -119,9 +120,11 @@ L_DECL(infinity); /* property names */ L_DECL(ASRU); +L_DECL(action); L_DECL(FITrate); L_DECL(FRU); -L_DECL(FRU); +L_DECL(id); +L_DECL(message); L_DECL(FRUID); L_DECL(N); L_DECL(T); @@ -147,14 +150,20 @@ L_DECL(inhibit); */ L_DECL(within); L_DECL(call); +L_DECL(confcall); L_DECL(confprop); +L_DECL(defined); L_DECL(payloadprop); +L_DECL(payloadprop_contains); +L_DECL(payloadprop_defined); +L_DECL(setpayloadprop); L_DECL(envprop); L_DECL(is_connected); L_DECL(is_under); L_DECL(is_on); L_DECL(is_present); L_DECL(is_type); +L_DECL(count); /* our enumerated types (used for debugging) */ L_DECL(T_NOTHING); @@ -201,6 +210,7 @@ L_DECL(T_DEFECT); L_DECL(T_ERROR); L_DECL(T_EREPORT); L_DECL(T_SERD); +L_DECL(T_STAT); L_DECL(T_PROP); L_DECL(T_MASK); L_DECL(N_UNSPEC); diff --git a/usr/src/cmd/fm/eversholt/common/ptree.c b/usr/src/cmd/fm/eversholt/common/ptree.c index 98f3e0dfbe..7d565efc82 100644 --- a/usr/src/cmd/fm/eversholt/common/ptree.c +++ b/usr/src/cmd/fm/eversholt/common/ptree.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * ptree.c -- routines for printing the prop tree @@ -76,6 +76,7 @@ is_stmt(struct node *np) case T_ERROR: case T_EREPORT: case T_SERD: + case T_STAT: case T_PROP: case T_MASK: case T_ASRU: @@ -371,6 +372,7 @@ ptree(int flags, struct node *np, int no_iterators, int fileline) out(flags, ";"); break; case T_SERD: + case T_STAT: if (fileline) out(flags, "# %d \"%s\"", np->line, np->file); out(flags|O_NONL, "engine "); @@ -532,6 +534,7 @@ ptree_nodetype2str(enum nodetype t) case T_ERROR: return L_error; case T_EREPORT: return L_ereport; case T_SERD: return L_serd; + case T_STAT: return L_stat; case T_PROP: return L_prop; case T_MASK: return L_mask; default: @@ -553,6 +556,7 @@ ptree_nametype2str(enum nametype t) case N_ERROR: return L_error; case N_EREPORT: return L_ereport; case N_SERD: return L_serd; + case N_STAT: return L_stat; default: (void) sprintf(buf, "[unexpected nametype: %d]", t); return (buf); @@ -701,6 +705,9 @@ ptree_type_pattern(int flags, enum nodetype t, const char *pat) case T_SERD: lut_walk(SERDs, (lut_cb)byname_printer, (void *)&info); return; + case T_STAT: + lut_walk(STATs, (lut_cb)byname_printer, (void *)&info); + return; case T_ASRU: lut_walk(ASRUs, (lut_cb)byname_printer, (void *)&info); return; @@ -768,6 +775,12 @@ ptree_serd(int flags, const char *pat) } void +ptree_stat(int flags, const char *pat) +{ + ptree_type_pattern(flags, T_STAT, pat); +} + +void ptree_asru(int flags, const char *pat) { ptree_type_pattern(flags, T_ASRU, pat); diff --git a/usr/src/cmd/fm/eversholt/common/ptree.h b/usr/src/cmd/fm/eversholt/common/ptree.h index 8cba67dd5a..07116e09a7 100644 --- a/usr/src/cmd/fm/eversholt/common/ptree.h +++ b/usr/src/cmd/fm/eversholt/common/ptree.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * ptree.h -- public definitions for tree print module @@ -66,6 +66,7 @@ void ptree_defect(int flags, const char *pat); void ptree_error(int flags, const char *pat); void ptree_ereport(int flags, const char *pat); void ptree_serd(int flags, const char *pat); +void ptree_stat(int flags, const char *pat); void ptree_config(int flags, const char *pat); void ptree_prop(int flags, const char *pat); void ptree_mask(int flags, const char *pat); diff --git a/usr/src/cmd/fm/eversholt/common/stats.c b/usr/src/cmd/fm/eversholt/common/stats.c index 4a8131ace8..4501b8909d 100644 --- a/usr/src/cmd/fm/eversholt/common/stats.c +++ b/usr/src/cmd/fm/eversholt/common/stats.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * stats.c -- simple stats tracking table module @@ -153,6 +153,17 @@ stats_counter_add(struct stats *sp, int n) sp->u.counter += n; } +void +stats_counter_reset(struct stats *sp) +{ + if (sp == NULL) + return; + + ASSERT(sp->t == STATS_COUNTER); + + sp->u.counter = 0; +} + int stats_counter_value(struct stats *sp) { diff --git a/usr/src/cmd/fm/eversholt/common/stats.h b/usr/src/cmd/fm/eversholt/common/stats.h index ebde8709d8..873a96ac33 100644 --- a/usr/src/cmd/fm/eversholt/common/stats.h +++ b/usr/src/cmd/fm/eversholt/common/stats.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * stats.h -- public definitions for stats module @@ -43,6 +43,7 @@ struct stats *stats_new_counter(const char *name, const char *desc, int ext); void stats_delete(struct stats *sp); void stats_counter_bump(struct stats *sp); void stats_counter_add(struct stats *sp, int n); +void stats_counter_reset(struct stats *sp); int stats_counter_value(struct stats *sp); struct stats *stats_new_elapse(const char *name, const char *desc, int ext); void stats_elapse_start(struct stats *sp); diff --git a/usr/src/cmd/fm/eversholt/common/tree.c b/usr/src/cmd/fm/eversholt/common/tree.c index 9111305887..064da60795 100644 --- a/usr/src/cmd/fm/eversholt/common/tree.c +++ b/usr/src/cmd/fm/eversholt/common/tree.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * tree.c -- routines for manipulating the prop tree @@ -58,6 +58,7 @@ static struct stats *Defectcount; static struct stats *Errorcount; static struct stats *Ereportcount; static struct stats *SERDcount; +static struct stats *STATcount; static struct stats *ASRUcount; static struct stats *FRUcount; static struct stats *Configcount; @@ -76,6 +77,7 @@ tree_init(void) Errorcount = stats_new_counter("parser.error", "error decls", 1); Ereportcount = stats_new_counter("parser.ereport", "ereport decls", 1); SERDcount = stats_new_counter("parser.SERD", "SERD engine decls", 1); + STATcount = stats_new_counter("parser.STAT", "STAT engine decls", 1); ASRUcount = stats_new_counter("parser.ASRU", "ASRU decls", 1); FRUcount = stats_new_counter("parser.FRU", "FRU decls", 1); Configcount = stats_new_counter("parser.config", "config stmts", 1); @@ -97,6 +99,7 @@ tree_fini(void) stats_delete(Errorcount); stats_delete(Ereportcount); stats_delete(SERDcount); + stats_delete(STATcount); stats_delete(ASRUcount); stats_delete(FRUcount); stats_delete(Configcount); @@ -124,6 +127,8 @@ tree_fini(void) Ereportenames = NULL; lut_free(SERDs, NULL, NULL); SERDs = NULL; + lut_free(STATs, NULL, NULL); + STATs = NULL; lut_free(ASRUs, NULL, NULL); ASRUs = NULL; lut_free(FRUs, NULL, NULL); @@ -169,8 +174,6 @@ tree_free(struct node *root) break; case T_FUNC: tree_free(root->u.func.arglist); - if (root->u.func.cachedval != NULL) - FREE(root->u.func.cachedval); break; case T_AND: case T_OR: @@ -225,6 +228,7 @@ tree_free(struct node *root) case T_ASRU: case T_FRU: case T_SERD: + case T_STAT: case T_CONFIG: tree_free(root->u.stmt.np); if (root->u.stmt.nvpairs) @@ -352,6 +356,7 @@ tree_treecmp(struct node *np1, struct node *np2, enum nodetype t, case T_ASRU: case T_FRU: case T_SERD: + case T_STAT: if (tree_treecmp(np1->u.stmt.np, np2->u.stmt.np, t, cmp_func)) return (1); return (tree_treecmp(np1->u.stmt.nvpairs, np2->u.stmt.nvpairs, @@ -504,6 +509,8 @@ tree_name(const char *s, enum itertype it, const char *file, int line) ret->u.name.t = N_EREPORT; else if (s == L_serd) ret->u.name.t = N_SERD; + else if (s == L_stat) + ret->u.name.t = N_STAT; else outfl(O_ERR, file, line, "unknown class: %s", s); } @@ -680,7 +687,7 @@ tree_func(const char *s, struct node *np, const char *file, int line) * iterator names. */ static void -make_explicit(struct node *np) +make_explicit(struct node *np, int eventonly) { struct node *pnp; /* component of pathname */ struct node *pnp2; @@ -696,20 +703,46 @@ make_explicit(struct node *np) return; /* all done */ switch (np->t) { - case T_ARROW: - /* cascaded arrow, already done */ - break; - + case T_ASSIGN: + case T_CONDIF: + case T_CONDELSE: + case T_NE: + case T_EQ: + case T_LT: + case T_LE: + case T_GT: + case T_GE: + case T_BITAND: + case T_BITOR: + case T_BITXOR: + case T_BITNOT: + case T_LSHIFT: + case T_RSHIFT: case T_LIST: - make_explicit(np->u.expr.left); - make_explicit(np->u.expr.right); + case T_AND: + case T_OR: + case T_NOT: + case T_ADD: + case T_SUB: + case T_MUL: + case T_DIV: + case T_MOD: + make_explicit(np->u.expr.left, eventonly); + make_explicit(np->u.expr.right, eventonly); break; case T_EVENT: - make_explicit(np->u.event.epname); + make_explicit(np->u.event.epname, 0); + make_explicit(np->u.event.eexprlist, 1); + break; + + case T_FUNC: + make_explicit(np->u.func.arglist, eventonly); break; case T_NAME: + if (eventonly) + return; for (pnp = np; pnp != NULL; pnp = pnp->u.name.next) if (pnp->u.name.child == NULL) { /* @@ -758,19 +791,13 @@ make_explicit(struct node *np) pnp->u.name.childgen = 1; } break; - - default: - outfl(O_DIE, np->file, np->line, - "internal error: make_explicit: " - "unexpected type: %s", - ptree_nodetype2str(np->t)); } } struct node * tree_pname(struct node *np) { - make_explicit(np); + make_explicit(np, 0); return (np); } @@ -791,8 +818,8 @@ tree_arrow(struct node *lhs, struct node *nnp, struct node *knp, ret->u.arrow.knp = knp; ret->u.arrow.rhs = rhs; - make_explicit(lhs); - make_explicit(rhs); + make_explicit(lhs, 0); + make_explicit(rhs, 0); check_arrow(ret); @@ -1008,6 +1035,11 @@ tree_decl(enum nodetype t, struct node *np, struct node *nvpairs, lut_walk(Upsets, update_serd_refstmt, np); break; + case N_STAT: + ret = dodecl(T_STAT, file, line, np, nvpairs, + &STATs, STATcount, 0); + break; + default: outfl(O_ERR, file, line, "tree_decl: internal error, engine name type %s", @@ -1150,6 +1182,7 @@ tree_report() lut_walk(Errors, (lut_cb)check_required_props, (void *)T_ERROR); lut_walk(Ereports, (lut_cb)check_required_props, (void *)T_EREPORT); lut_walk(SERDs, (lut_cb)check_required_props, (void *)T_SERD); + lut_walk(STATs, (lut_cb)check_required_props, (void *)T_STAT); /* * we do this now rather than while building the parse diff --git a/usr/src/cmd/fm/eversholt/common/tree.h b/usr/src/cmd/fm/eversholt/common/tree.h index 58def5e6cc..c3a6f49845 100644 --- a/usr/src/cmd/fm/eversholt/common/tree.h +++ b/usr/src/cmd/fm/eversholt/common/tree.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * tree.h -- public definitions for tree module @@ -84,6 +84,7 @@ struct node { T_ERROR, /* error declaration */ T_EREPORT, /* ereport declaration */ T_SERD, /* SERD engine declaration */ + T_STAT, /* STAT engine declaration */ T_PROP, /* prop statement */ T_MASK, /* mask statement */ T_CONFIG /* config statement */ @@ -155,7 +156,8 @@ struct node { N_DEFECT, N_ERROR, N_EREPORT, - N_SERD + N_SERD, + N_STAT } t:3; enum itertype { IT_NONE, @@ -193,7 +195,6 @@ struct node { */ const char *s; /* name of function */ struct node *arglist; - void *cachedval; /* runtime cache of value */ } func; struct { @@ -308,6 +309,7 @@ struct lut *Errors; struct lut *Ereports; struct lut *Ereportenames; struct lut *SERDs; +struct lut *STATs; struct lut *ASRUs; struct lut *FRUs; struct lut *Configs; diff --git a/usr/src/cmd/fm/eversholt/common/version.h b/usr/src/cmd/fm/eversholt/common/version.h index 855f76b58a..16a59bfde9 100644 --- a/usr/src/cmd/fm/eversholt/common/version.h +++ b/usr/src/cmd/fm/eversholt/common/version.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * verion.h -- define current version numbers for eversholt @@ -37,7 +37,7 @@ extern "C" { #endif #define VERSION_MAJOR 1 -#define VERSION_MINOR 13 +#define VERSION_MINOR 16 #ifdef __cplusplus } diff --git a/usr/src/cmd/fm/eversholt/files/i386/Makefile b/usr/src/cmd/fm/eversholt/files/i386/Makefile index 28becbc3c9..1268b20362 100644 --- a/usr/src/cmd/fm/eversholt/files/i386/Makefile +++ b/usr/src/cmd/fm/eversholt/files/i386/Makefile @@ -20,11 +20,14 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" +SUBDIRS=i86pc EFT_COMMON_FILES= pci.eft sca500.eft sca1000.eft +include ../../../Makefile.subdirs + include ../Makefile.com diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V245/Makefile b/usr/src/cmd/fm/eversholt/files/i386/i86pc/Makefile index 55fe0e0381..0f12c27e70 100644 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V245/Makefile +++ b/usr/src/cmd/fm/eversholt/files/i386/i86pc/Makefile @@ -25,7 +25,7 @@ # #ident "%Z%%M% %I% %E% SMI" -TOPOSUBDIR = SUNW,Sun-Fire-V245 -TOPOFILES = platform.topo +EFT_PLAT= i86pc +EFT_PLAT_FILES= amd64.eft include ../../Makefile.com diff --git a/usr/src/cmd/fm/eversholt/files/i386/i86pc/amd64.esc b/usr/src/cmd/fm/eversholt/files/i386/i86pc/amd64.esc new file mode 100644 index 0000000000..bf39646ece --- /dev/null +++ b/usr/src/cmd/fm/eversholt/files/i386/i86pc/amd64.esc @@ -0,0 +1,841 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#pragma dictionary "AMD" + +/* + * Eversholt rules for the AMD Opteron CPU/Memory + */ + +fru dimm; +asru dimm; + +fru chip; +asru chip/cpu; + + +/* #MEM# + * GET_ADDR relies on the fact that variables have global scope across an FME. + * Thus for each FME the assignment only occurs for the first invocation + * but the comparison happens on each. Thus if the new address matches the + * address of an existing open FME, then we return true running in the context + * of that FME. If the new address doesn't match the address of any existing + * open FME, then we return true in the context of a newly opened FME. + */ +#define GET_ADDR (defined($addr) ? ($addr == payloadprop("addr")) : \ + ($addr = payloadprop("addr"))) + +#define GET_OFFSET ($offset = payloadprop("resource[0].hc-specific.offset")) + +/* + * SET_ADDR is used to set a payload value in the fault that we diagnose + * for page faults, to record the physical address of the faulting page. + */ +#define SET_ADDR (setpayloadprop("asru-physaddr", $addr)) + +#define SET_OFFSET (setpayloadprop("asru-offset", $offset)) + +/* + * RESOURCE_EXISTS is true if a pair with name "resource" exists in the + * payload - regardless of type (e.g., nvlist or nvlist array) or value. + */ +#define RESOURCE_EXISTS (payloadprop_defined("resource")) + +/* + * CONTAINS_DIMM is true if the "resource" nvlist array (as used in memory + * ereports) exists and one if its members matches the path for the + * dimm node. Our memory propogation are of the form "foo@dimm -> blah@cpu" + * since cpus detect memory errors; in eversholt such a propogation, where + * the lhs path and rhs path do not match, expands to the cross-product of + * all dimms and cpus in the system. We use CONTAINS_DIMM to constrain + * the propogation such that it only happens if the payload resource + * matches the dimm. + */ +#define CONTAINS_DIMM (payloadprop_contains("resource", asru(dimm))) + +/* + * The following will tell us whether a syndrome that is known to be + * correctable (from a mem_ecc1) is single-bit or multi-bit. For a + * correctable ChipKill syndrome the number of bits set in the lowest + * nibble indicates how many bit were in error. + */ + +#define CBITMASK(synd) ((synd) & 0xf) + +#define CKSINGLE(synd) \ + ((synd) == 0 || \ + (CBITMASK(synd) == 0x1 || CBITMASK(synd) == 0x2 || \ + CBITMASK(synd) == 0x4 || CBITMASK(synd) == 0x8)) + +#define SINGLE_BIT_CE \ + (payloadprop("syndrome-type") == "E" || \ + (payloadprop("syndrome-type") == "C" && \ + CKSINGLE(payloadprop("syndrome")))) + +#define MULTI_BIT_CE \ + (payloadprop("syndrome-type") == "C" && \ + !CKSINGLE(payloadprop("syndrome"))) + +/* + * A single bit fault in a memory dimm can cause: + * + * - mem_ce : reported by nb for an access from a remote cpu + * + * Single-bit errors are fed into a per-DIMM SERD engine; if a SERD engine + * trips we diagnose a fault.memory.page so that the response agent can + * retire the page that caused the trip. If the total number of pages + * faulted in this way on a single DIMM exceeds a threshold we will + * diagnose a fault.memory.dimm_sb against the DIMM. + * + * Multibit ChipKill-correctable errors produce an immediate page fault + * and corresponding fault.memory.dimm_ck. This is achieved through + * SERD engines using N=0 so the facility is there to be a little more + * tolerant of these errors. + * + * Uncorrectable errors produce an immediate page fault and corresponding + * fault.memory.dimm_ue. + * + * Page faults are essentially internal - action is only required when + * they are accompanied by a dimm fault. As such we include message=0 + * on DIMM faults. + */ + +event ereport.cpu.amd.nb.mem_ce@cpu; + +/* + * If the address is not valid then no resource member will be included + * in a nb.mem_ce or nb.mem_ue ereport. These cases should be rare. + * We will discard such ereports. An alternative may be to SERD them + * on a per MC basis and trip if we see too many such events. + */ + +event upset.memory.discard@cpu; + +/* #PAGE# + * Page faults of all types diagnose to a single fault class and are + * counted with a stat. + * + * Single-bit errors are diagnosed as upsets and feed into per-DIMM + * SERD engines which diagnose fault.memory.page if they trip. + */ + +#define PAGE_FIT 1 +#define PAGE_SB_COUNT 2 +#define PAGE_SB_TIME 72h +#define PAGE_CK_COUNT 0 +#define PAGE_CK_TIME 1h + +engine stat.page_fault@dimm; +event fault.memory.page@dimm, FITrate=PAGE_FIT, + ASRU=dimm, message=0, count=stat.page_fault@dimm, + action=confcall("rewrite-ASRU"); +event error.memory.page_sb@dimm; +event error.memory.page_ck@dimm; +event error.memory.page_ue@dimm; + +prop fault.memory.page@dimm (1)-> + error.memory.page_sb@dimm, + error.memory.page_ck@dimm, + error.memory.page_ue@dimm; + +event ereport.memory.page_sb_trip@dimm; +engine serd.memory.page_sb@dimm, N=PAGE_SB_COUNT, T=PAGE_SB_TIME, + method=persistent, trip=ereport.memory.page_sb_trip@dimm; +event upset.memory.page_sb@dimm, engine=serd.memory.page_sb@dimm; + +event ereport.memory.page_ck_trip@dimm; +engine serd.memory.page_ck@dimm, N=PAGE_CK_COUNT, T=PAGE_CK_TIME, + method=persistent, trip=ereport.memory.page_ck_trip@dimm; +event upset.memory.page_ck@dimm, engine=serd.memory.page_ck@dimm; + +prop upset.memory.page_sb@dimm (0)-> + ereport.cpu.amd.nb.mem_ce@cpu { CONTAINS_DIMM && SINGLE_BIT_CE }; + +prop upset.memory.page_ck@dimm (0)-> + ereport.cpu.amd.nb.mem_ce@cpu { CONTAINS_DIMM && MULTI_BIT_CE }; + +prop error.memory.page_sb@dimm (1)-> + ereport.memory.page_sb_trip@dimm; + +prop error.memory.page_ck@dimm (1)-> + ereport.memory.page_ck_trip@dimm; + +prop fault.memory.page@dimm { SET_ADDR && SET_OFFSET } (0)-> + ereport.cpu.amd.nb.mem_ce@cpu { CONTAINS_DIMM && GET_ADDR && GET_OFFSET }; + +prop upset.memory.discard@cpu (1)-> + ereport.cpu.amd.nb.mem_ce@cpu { !RESOURCE_EXISTS }; + +/* #DIMM_SB# + * Single-bit DIMM faults are diagnosed when the number of page faults + * (of all types since they all are counted in a single per-DIMM stat engine) + * reaches a threshold. Since our tolerance of ChipKill and UE faults + * is much lower than that for single-bit errors the threshold will only be + * reached for repeated single-bit page faults. We do not stop diagnosing + * further single-bit page faults once we have declared a single-bit DIMM + * fault - we continue diagnosing them and response agents can continue to + * retire those pages up to the system-imposed retirement limit. + * + * We maintain a parallel SERD engine to the page_sb engine which trips + * in unison, but on trip it generates a distinct ereport which we + * diagnose to a dimm_sb fault if the threshold has been reached, or + * to a throwaway upset if not. + */ + +#define DIMM_SB_FIT 2000 +#define DIMM_SB_THRESH 128 + +event fault.memory.dimm_sb@dimm, FITrate=DIMM_SB_FIT, FRU=dimm, ASRU=dimm; + +event ereport.memory.dimm_sb_trip@dimm; +event upset.memory.discard@dimm; +engine serd.memory.dimm_sb@dimm, N=PAGE_SB_COUNT, T=PAGE_SB_TIME, + method=persistent, trip=ereport.memory.dimm_sb_trip@dimm; +event upset.memory.dimm_sb@dimm, engine=serd.memory.dimm_sb@dimm; + +prop upset.memory.dimm_sb@dimm (0)-> + ereport.cpu.amd.nb.mem_ce@cpu { CONTAINS_DIMM }; /* sb and ck */ + +prop upset.memory.discard@dimm (1)-> + ereport.memory.dimm_sb_trip@dimm; + +prop fault.memory.dimm_sb@dimm (0)-> + ereport.memory.dimm_sb_trip@dimm { + count(stat.page_fault@dimm) >= DIMM_SB_THRESH }; + +/* #DIMM_CK# + * ChipKill-correctable multi-bit faults indicate a likely failing SDRAM + * part. We will SERD them but with a very low/zero tolerance. + */ + +#define DIMM_CK_FIT 4000 +#define DIMM_CK_COUNT 0 +#define DIMM_CK_TIME 1h + +event fault.memory.dimm_ck@dimm, FITrate=DIMM_CK_FIT, FRU=dimm, ASRU=dimm; + +event ereport.memory.dimm_ck_trip@dimm; +engine serd.memory.dimm_ck@dimm, N=DIMM_CK_COUNT, T=DIMM_CK_TIME, + method=persistent, trip=ereport.memory.dimm_ck_trip@dimm; +event upset.memory.dimm_ck@dimm, engine=serd.memory.dimm_ck@dimm; + +prop upset.memory.dimm_ck@dimm (0)-> + ereport.cpu.amd.nb.mem_ce@cpu { CONTAINS_DIMM && MULTI_BIT_CE }; + +prop fault.memory.dimm_ck@dimm (1)-> + ereport.memory.dimm_ck_trip@dimm; + +prop fault.memory.page@dimm { SET_ADDR && SET_OFFSET } (0)-> + ereport.cpu.amd.nb.mem_ce@cpu { CONTAINS_DIMM && MULTI_BIT_CE && + GET_ADDR && GET_OFFSET }; + +/* #DIMM_UE# + * A multi-bit fault in a memory dimm can cause: + * + * - ue : reported by nb for an access from a remote cpu + * + * Note we use a SERD engine here simply as a way of ensuring that we get + * both dimm and page faults reported + */ + +#define DIMM_UE_FIT 6000 + +event ereport.cpu.amd.nb.mem_ue@cpu; +event ereport.memory.page_ue_trip@dimm; +event ereport.memory.dimm_ue_trip@dimm; +event fault.memory.dimm_ue@dimm, FITrate=DIMM_UE_FIT, FRU=dimm, ASRU=dimm; +event upset.memory.page_ue@dimm, engine=serd.memory.page_ue@dimm; +event upset.memory.dimm_ue@dimm, engine=serd.memory.dimm_ue@dimm; + +engine serd.memory.dimm_ue@dimm, N=0, T=1h, + method=persistent, trip=ereport.memory.dimm_ue_trip@dimm; + +engine serd.memory.page_ue@dimm, N=0, T=1h, + method=persistent, trip=ereport.memory.page_ue_trip@dimm; + +prop upset.memory.page_ue@dimm (0)-> + ereport.cpu.amd.nb.mem_ue@cpu { CONTAINS_DIMM }; + +prop upset.memory.dimm_ue@dimm (0)-> + ereport.cpu.amd.nb.mem_ue@cpu { CONTAINS_DIMM }; + +prop error.memory.page_ue@dimm (1)-> + ereport.memory.page_ue_trip@dimm; + +prop fault.memory.page@dimm { SET_ADDR && SET_OFFSET } (0)-> + ereport.cpu.amd.nb.mem_ue@cpu { CONTAINS_DIMM && GET_ADDR & GET_OFFSET }; + +prop fault.memory.dimm_ue@dimm (1)-> + ereport.memory.dimm_ue_trip@dimm; + +prop upset.memory.discard@cpu (1)-> + ereport.cpu.amd.nb.mem_ce@cpu { !RESOURCE_EXISTS }; + +/* #L2D# + * l2 cache data errors. + */ + +#define L2CACHEDATA_FIT 1000 +#define L2CACHEDATA_SB_COUNT 3 +#define L2CACHEDATA_SB_TIME 12h + +event fault.cpu.amd.l2cachedata@chip/cpu, FITrate=L2CACHEDATA_FIT, + FRU=chip, ASRU=chip/cpu; +event error.cpu.amd.l2cachedata_sb@chip/cpu; +event error.cpu.amd.l2cachedata_mb@chip/cpu; + +prop fault.cpu.amd.l2cachedata@chip/cpu (1)-> + error.cpu.amd.l2cachedata_sb@chip/cpu, + error.cpu.amd.l2cachedata_mb@chip/cpu; + +/* #L2D_SINGLE# + * A single bit data array fault in an l2 cache can cause: + * + * - inf_l2_ecc1 : reported by ic on this cpu + * - inf_l2_ecc1 : reported by dc on this cpu + * - l2d_ecc1 : reported by bu on copyback or on snoop from another cpu + * + * Single-bit errors are diagnosed to cache upsets. SERD engines are used + * to count upsets resulting from CEs. + */ + +event ereport.cpu.amd.ic.inf_l2_ecc1@chip/cpu{within(5s)}; +event ereport.cpu.amd.dc.inf_l2_ecc1@chip/cpu{within(5s)}; +event ereport.cpu.amd.bu.l2d_ecc1@chip/cpu{within(5s)}; +event ereport.cpu.amd.l2d_sb_trip@chip/cpu; + +engine serd.cpu.amd.l2d_sb@chip/cpu, + N=L2CACHEDATA_SB_COUNT, T=L2CACHEDATA_SB_TIME, method=persistent, + trip=ereport.cpu.amd.l2d_sb_trip@chip/cpu; + +event upset.cpu.amd.l2d_sb@chip/cpu, + engine=serd.cpu.amd.l2d_sb@chip/cpu; + +prop upset.cpu.amd.l2d_sb@chip/cpu (1)-> + ereport.cpu.amd.ic.inf_l2_ecc1@chip/cpu, + ereport.cpu.amd.dc.inf_l2_ecc1@chip/cpu, + ereport.cpu.amd.bu.l2d_ecc1@chip/cpu; + +prop error.cpu.amd.l2cachedata_sb@chip/cpu (1)-> + ereport.cpu.amd.l2d_sb_trip@chip/cpu; + +prop fault.cpu.amd.l2cachedata@chip/cpu (0)-> + ereport.cpu.amd.ic.inf_l2_ecc1@chip/cpu, + ereport.cpu.amd.dc.inf_l2_ecc1@chip/cpu, + ereport.cpu.amd.bu.l2d_ecc1@chip/cpu; + +/* #L2D_MULTI# + * A multi-bit data array fault in an l2 cache can cause: + * + * - inf_l2_eccm : reported by ic on this cpu + * - inf_l2_eccm : reported by dc on this cpu + * - l2d_eccm : reported by bu on copyback or on snoop from another cpu + */ + +event ereport.cpu.amd.ic.inf_l2_eccm@chip/cpu; +event ereport.cpu.amd.dc.inf_l2_eccm@chip/cpu; +event ereport.cpu.amd.bu.l2d_eccm@chip/cpu; + +prop error.cpu.amd.l2cachedata_mb@chip/cpu (1)-> + ereport.cpu.amd.ic.inf_l2_eccm@chip/cpu, + ereport.cpu.amd.dc.inf_l2_eccm@chip/cpu, + ereport.cpu.amd.bu.l2d_eccm@chip/cpu; + +prop fault.cpu.amd.l2cachedata@chip/cpu (0)-> + ereport.cpu.amd.ic.inf_l2_eccm@chip/cpu, + ereport.cpu.amd.dc.inf_l2_eccm@chip/cpu, + ereport.cpu.amd.bu.l2d_eccm@chip/cpu; + +/* #L2T# + * l2 cache main tag errors + */ + +#define L2CACHETAG_FIT 1000 +#define L2CACHETAG_SB_COUNT 3 +#define L2CACHETAG_SB_TIME 12h + +event fault.cpu.amd.l2cachetag@chip/cpu, FITrate=L2CACHETAG_FIT, + FRU=chip, ASRU=chip/cpu; +event error.cpu.amd.l2cachetag_sb@chip/cpu; +event error.cpu.amd.l2cachetag_mb@chip/cpu; + +prop fault.cpu.amd.l2cachetag@chip/cpu (1)-> + error.cpu.amd.l2cachetag_sb@chip/cpu, + error.cpu.amd.l2cachetag_mb@chip/cpu; + +/* #L2T_SINGLE# + * A single bit tag array fault in an l2 cache can cause: + * + * - l2t_ecc1 : reported by bu on this cpu when detected during snoop + * - l2t_par : reported by bu on this cpu when detected other than during snoop + * + * Note that the bu.l2t_par ereport could be due to a single bit or multi bit + * event. If the l2t_sb_trip has already triggered it will be treated as another + * ce, otherwise it will be treated as a ue event. + */ + +event ereport.cpu.amd.bu.l2t_ecc1@chip/cpu{within(5s)}; +event ereport.cpu.amd.bu.l2t_par@chip/cpu; +event ereport.cpu.amd.l2t_sb_trip@chip/cpu; + +engine serd.cpu.amd.l2t_sb@chip/cpu, + N=L2CACHETAG_SB_COUNT, T=L2CACHETAG_SB_TIME, method=persistent, + trip=ereport.cpu.amd.l2t_sb_trip@chip/cpu; + +event upset.cpu.amd.l2t_sb@chip/cpu, + engine=serd.cpu.amd.l2t_sb@chip/cpu; + +prop upset.cpu.amd.l2t_sb@chip/cpu (1)-> + ereport.cpu.amd.bu.l2t_ecc1@chip/cpu, + ereport.cpu.amd.bu.l2t_par@chip/cpu; + +prop error.cpu.amd.l2cachetag_sb@chip/cpu (1)-> + ereport.cpu.amd.l2t_sb_trip@chip/cpu; + +prop fault.cpu.amd.l2cachetag@chip/cpu (0)-> + ereport.cpu.amd.bu.l2t_ecc1@chip/cpu, + ereport.cpu.amd.bu.l2t_par@chip/cpu; + +/* #L2T_MULTI# + * A multi-bit tag array fault in an l2 cache can cause: + * + * - l2t_eccm : reported by bu on this cpu when detected during snoop + * - l2t_par : reported by bu on this cpu when detected other than during snoop + */ + +event ereport.cpu.amd.bu.l2t_eccm@chip/cpu; + +prop error.cpu.amd.l2cachetag_mb@chip/cpu (1)-> + ereport.cpu.amd.bu.l2t_eccm@chip/cpu, + ereport.cpu.amd.bu.l2t_par@chip/cpu; + +prop fault.cpu.amd.l2cachetag@chip/cpu (0)-> + ereport.cpu.amd.bu.l2t_eccm@chip/cpu, + ereport.cpu.amd.bu.l2t_par@chip/cpu; + +/* #ICD_PAR# + * A data array parity fault in an I cache can cause: + * + * - data_par : reported by ic on this cpu + */ + +#define ICACHEDATA_FIT 1000 +#define ICACHEDATA_SB_COUNT 2 +#define ICACHEDATA_SB_TIME 168h + +event ereport.cpu.amd.ic.data_par@chip/cpu{within(5s)}; +event ereport.cpu.amd.ic_dp_trip@chip/cpu; + +event fault.cpu.amd.icachedata@chip/cpu, FITrate=ICACHEDATA_FIT, + FRU=chip, ASRU=chip/cpu; + +engine serd.cpu.amd.icachedata@chip/cpu, + N=ICACHEDATA_SB_COUNT, T=ICACHEDATA_SB_TIME, method=persistent, + trip=ereport.cpu.amd.ic_dp_trip@chip/cpu; + +event upset.cpu.amd.icachedata@chip/cpu, + engine=serd.cpu.amd.icachedata@chip/cpu; + +prop upset.cpu.amd.icachedata@chip/cpu (1)-> + ereport.cpu.amd.ic.data_par@chip/cpu; + +prop fault.cpu.amd.icachedata@chip/cpu (1)-> + ereport.cpu.amd.ic_dp_trip@chip/cpu; + +prop fault.cpu.amd.icachedata@chip/cpu (0)-> + ereport.cpu.amd.ic.data_par@chip/cpu; + +/* #ICT_PAR# + * A tag array parity fault in an I cache can cause: + * + * - tag_par : reported by ic on this cpu + */ + +#define ICACHETAG_FIT 1000 +#define ICACHETAG_SB_COUNT 2 +#define ICACHETAG_SB_TIME 168h + +event ereport.cpu.amd.ic.tag_par@chip/cpu{within(5s)}; +event ereport.cpu.amd.ic_tp_trip@chip/cpu; + +event fault.cpu.amd.icachetag@chip/cpu, FITrate=ICACHETAG_FIT, + FRU=chip, ASRU=chip/cpu; + +engine serd.cpu.amd.icachetag@chip/cpu, + N=ICACHETAG_SB_COUNT, T=ICACHETAG_SB_TIME, method=persistent, + trip=ereport.cpu.amd.ic_tp_trip@chip/cpu; + +event upset.cpu.amd.icachetag@chip/cpu, + engine=serd.cpu.amd.icachetag@chip/cpu; + +prop upset.cpu.amd.icachetag@chip/cpu (1)-> + ereport.cpu.amd.ic.tag_par@chip/cpu; + +prop fault.cpu.amd.icachetag@chip/cpu (1)-> + ereport.cpu.amd.ic_tp_trip@chip/cpu; + +prop fault.cpu.amd.icachetag@chip/cpu (0)-> + ereport.cpu.amd.ic.tag_par@chip/cpu; + +/* #ICT_SNOOP# + * A snoop tag array parity fault in an I cache can cause: + * + * - stag_par : reported by ic on this cpu + */ + +#define ICACHESTAG_FIT 1000 + +event ereport.cpu.amd.ic.stag_par@chip/cpu{within(5s)}; + +event fault.cpu.amd.icachestag@chip/cpu, FITrate=ICACHESTAG_FIT, + FRU=chip, ASRU=chip/cpu; + +prop fault.cpu.amd.icachestag@chip/cpu (1)-> + ereport.cpu.amd.ic.stag_par@chip/cpu; + +/* #ICTLB_1# + * An l1tlb parity fault in an I cache can cause: + * + * - l1tlb_par : reported by ic on this cpu + */ + +#define ICACHEL1TLB_FIT 1000 +#define ICACHEL1TLB_SB_COUNT 2 +#define ICACHEL1TLB_SB_TIME 168h + +event ereport.cpu.amd.ic.l1tlb_par@chip/cpu{within(5s)}; +event ereport.cpu.amd.ic_l1tlb_trip@chip/cpu; + +event fault.cpu.amd.l1itlb@chip/cpu, FITrate=ICACHEL1TLB_FIT, + FRU=chip, ASRU=chip/cpu; + +engine serd.cpu.amd.l1itlb@chip/cpu, + N=ICACHEL1TLB_SB_COUNT, T=ICACHEL1TLB_SB_TIME, method=persistent, + trip=ereport.cpu.amd.ic_l1tlb_trip@chip/cpu; + +event upset.cpu.amd.l1itlb@chip/cpu, + engine=serd.cpu.amd.l1itlb@chip/cpu; + +prop upset.cpu.amd.l1itlb@chip/cpu (1)-> + ereport.cpu.amd.ic.l1tlb_par@chip/cpu; + +prop fault.cpu.amd.l1itlb@chip/cpu (1)-> + ereport.cpu.amd.ic_l1tlb_trip@chip/cpu; + +prop fault.cpu.amd.l1itlb@chip/cpu (0)-> + ereport.cpu.amd.ic.l1tlb_par@chip/cpu; + +/* #ICTLB_2# + * An l2tlb parity fault in an I cache can cause: + * + * - l2tlb_par : reported by ic on this cpu + */ + +#define ICACHEL2TLB_FIT 1000 +#define ICACHEL2TLB_SB_COUNT 2 +#define ICACHEL2TLB_SB_TIME 168h + +event ereport.cpu.amd.ic.l2tlb_par@chip/cpu{within(5s)}; +event ereport.cpu.amd.ic_l2tlb_trip@chip/cpu; + +event fault.cpu.amd.l2itlb@chip/cpu, FITrate=ICACHEL2TLB_FIT, + FRU=chip, ASRU=chip/cpu; + +engine serd.cpu.amd.l2itlb@chip/cpu, + N=ICACHEL2TLB_SB_COUNT, T=ICACHEL2TLB_SB_TIME, method=persistent, + trip=ereport.cpu.amd.ic_l2tlb_trip@chip/cpu; + +event upset.cpu.amd.l2itlb@chip/cpu, + engine=serd.cpu.amd.l2itlb@chip/cpu; + +prop upset.cpu.amd.l2itlb@chip/cpu (1)-> + ereport.cpu.amd.ic.l2tlb_par@chip/cpu; + +prop fault.cpu.amd.l2itlb@chip/cpu (1)-> + ereport.cpu.amd.ic_l2tlb_trip@chip/cpu; + +prop fault.cpu.amd.l2itlb@chip/cpu (0)-> + ereport.cpu.amd.ic.l2tlb_par@chip/cpu; + +/* #DCD# + * dcache data errors + */ + +#define DCACHEDATA_FIT 1000 +#define DCACHEDATA_SB_COUNT 2 +#define DCACHEDATA_SB_TIME 168h + +event fault.cpu.amd.dcachedata@chip/cpu, FITrate=DCACHEDATA_FIT, + FRU=chip, ASRU=chip/cpu; +event error.cpu.amd.dcachedata_sb@chip/cpu; +event error.cpu.amd.dcachedata_mb@chip/cpu; + +prop fault.cpu.amd.dcachedata@chip/cpu (1)-> + error.cpu.amd.dcachedata_sb@chip/cpu, + error.cpu.amd.dcachedata_mb@chip/cpu; + +/* #DCD_SINGLE# + * A single bit data array fault in an D cache can cause: + * + * - data_ecc1 : reported by dc on this cpu by scrubber + * - data_ecc1_uc : reported by dc on this cpu other than by scrubber + * + * Make data_ecc1_uc fault immediately as it may have caused a panic + */ + +event ereport.cpu.amd.dc.data_ecc1@chip/cpu{within(5s)}; +event ereport.cpu.amd.dc.data_ecc1_uc@chip/cpu{within(5s)}; +event ereport.cpu.amd.dc_sb_trip@chip/cpu; + +engine serd.cpu.amd.dc_sb@chip/cpu, + N=DCACHEDATA_SB_COUNT, T=DCACHEDATA_SB_TIME, method=persistent, + trip=ereport.cpu.amd.dc_sb_trip@chip/cpu; + +engine serd.cpu.amd.dc_sb_uc@chip/cpu, + N=0, T=1hr, method=persistent, + trip=ereport.cpu.amd.dc_sb_trip@chip/cpu; + +event upset.cpu.amd.dc_sb@chip/cpu, + engine=serd.cpu.amd.dc_sb@chip/cpu; + +event upset.cpu.amd.dc_sb_uc@chip/cpu, + engine=serd.cpu.amd.dc_sb_uc@chip/cpu; + +prop upset.cpu.amd.dc_sb@chip/cpu (1)-> + ereport.cpu.amd.dc.data_ecc1@chip/cpu; + +prop upset.cpu.amd.dc_sb_uc@chip/cpu (1)-> + ereport.cpu.amd.dc.data_ecc1_uc@chip/cpu; + +prop error.cpu.amd.dcachedata_sb@chip/cpu (1)-> + ereport.cpu.amd.dc_sb_trip@chip/cpu; + +prop fault.cpu.amd.dcachedata@chip/cpu (0)-> + ereport.cpu.amd.dc.data_ecc1@chip/cpu, + ereport.cpu.amd.dc.data_ecc1_uc@chip/cpu; + +/* #DCD_MULTI# + * A multi-bit data array fault in an D cache can cause: + * + * - data_eccm : reported by dc on this cpu + */ + +event ereport.cpu.amd.dc.data_eccm@chip/cpu; + +prop error.cpu.amd.dcachedata_mb@chip/cpu (1)-> + ereport.cpu.amd.dc.data_eccm@chip/cpu; + +prop fault.cpu.amd.dcachedata@chip/cpu (0)-> + ereport.cpu.amd.dc.data_eccm@chip/cpu; + +/* #DCT_PAR# + * A tag array parity fault in an D cache can cause: + * + * - tag_par : reported by dc on this cpu + */ + +#define DCACHETAG_FIT 1000 + +event ereport.cpu.amd.dc.tag_par@chip/cpu{within(5s)}; + +event fault.cpu.amd.dcachetag@chip/cpu, FITrate=DCACHETAG_FIT, + FRU=chip, ASRU=chip/cpu; + +prop fault.cpu.amd.dcachetag@chip/cpu (1)-> + ereport.cpu.amd.dc.tag_par@chip/cpu; + +/* #DCT_SNOOP# + * A snoop tag array parity fault in an D cache can cause: + * + * - stag_par : reported by dc on this cpu + */ + +#define DCACHESTAG_FIT 1000 + +event ereport.cpu.amd.dc.stag_par@chip/cpu{within(5s)}; + +event fault.cpu.amd.dcachestag@chip/cpu, FITrate=DCACHESTAG_FIT, + FRU=chip, ASRU=chip/cpu; + +prop fault.cpu.amd.dcachestag@chip/cpu (1)-> + ereport.cpu.amd.dc.stag_par@chip/cpu; + +/* #DCTLB_1# + * An l1tlb parity fault in an D cache can cause: + * + * - l1tlb_par : reported by dc on this cpu + */ + +#define L1DTLB_FIT 1000 + +event ereport.cpu.amd.dc.l1tlb_par@chip/cpu{within(5s)}; + +event fault.cpu.amd.l1dtlb@chip/cpu, FITrate=L1DTLB_FIT, + FRU=chip, ASRU=chip/cpu; + +prop fault.cpu.amd.l1dtlb@chip/cpu (1)-> + ereport.cpu.amd.dc.l1tlb_par@chip/cpu; + +/* #DCTLB_2# + * An l2tlb parity fault in an D cache can cause: + * + * - l2tlb_par : reported by dc on this cpu + */ + +#define L2DTLB_FIT 1000 + +event ereport.cpu.amd.dc.l2tlb_par@chip/cpu{within(5s)}; + +event fault.cpu.amd.l2dtlb@chip/cpu, FITrate=L2DTLB_FIT, + FRU=chip, ASRU=chip/cpu; + +prop fault.cpu.amd.l2dtlb@chip/cpu (1)-> + ereport.cpu.amd.dc.l2tlb_par@chip/cpu; + +/* #DPATH_SB# + * Datapath errors between NB/MC and core. + */ + +#define CPU_DP_FIT 1000 + +event fault.cpu.amd.datapath@chip/cpu, FITrate=CPU_DP_FIT, FRU=chip, + ASRU=chip/cpu; +event error.cpu.amd.datapath_sb@chip/cpu; +event error.cpu.amd.datapath_mb@chip/cpu; + +prop fault.cpu.amd.datapath@chip/cpu (1)-> + error.cpu.amd.datapath_sb@chip/cpu, + error.cpu.amd.datapath_mb@chip/cpu; + +/* + * A single bit fault in the datapath between the NB and requesting core + * can cause: + * + * - inf_sys_ecc1 : reported by ic on access from a local cpu + * - inf_sys_ecc1 : reported by dc on access from a local cpu + * - s_ecc1 : reported by bu on access from a local cpu (hw prefetch etc) + */ + +#define CPU_DP_COUNT 3 +#define CPU_DP_TIME 12h + +event ereport.cpu.amd.ic.inf_sys_ecc1@chip/cpu{within(5s)}; +event ereport.cpu.amd.dc.inf_sys_ecc1@chip/cpu{within(5s)}; +event ereport.cpu.amd.bu.s_ecc1@chip/cpu{within(5s)}; +event upset.cpu.dp_sb@chip/cpu, engine=serd.cpu.dp_sb@chip/cpu; +event ereport.cpu.amd.dp_sb_trip@chip/cpu; + +engine serd.cpu.dp_sb@chip/cpu, N=CPU_DP_COUNT, T=CPU_DP_TIME, + method=persistent, trip=ereport.cpu.amd.dp_sb_trip@chip/cpu; + +prop upset.cpu.dp_sb@chip/cpu (1)-> + ereport.cpu.amd.ic.inf_sys_ecc1@chip/cpu, + ereport.cpu.amd.dc.inf_sys_ecc1@chip/cpu, + ereport.cpu.amd.bu.s_ecc1@chip/cpu; + +prop error.cpu.amd.datapath_sb@chip/cpu (1)-> + ereport.cpu.amd.dp_sb_trip@chip/cpu; + +prop fault.cpu.amd.datapath@chip/cpu (0)-> + ereport.cpu.amd.ic.inf_sys_ecc1@chip/cpu, + ereport.cpu.amd.dc.inf_sys_ecc1@chip/cpu, + ereport.cpu.amd.bu.s_ecc1@chip/cpu; + +/* #DPATH_MB# + * A multi-bit fault in the datapath between the NB and requesting core + * can cause: + * + * - inf_sys_eccm : reported by ic on access from a local cpu + * - inf_sys_eccm : reported by dc on access from a local cpu + * - s_eccm : reported by bu on access from a local cpu (hw prefetch etc) + */ + +event ereport.cpu.amd.ic.inf_sys_eccm@chip/cpu; +event ereport.cpu.amd.dc.inf_sys_eccm@chip/cpu; +event ereport.cpu.amd.bu.s_eccm@chip/cpu; + +prop error.cpu.amd.datapath_mb@chip/cpu (1)-> + ereport.cpu.amd.ic.inf_sys_eccm@chip/cpu, + ereport.cpu.amd.dc.inf_sys_eccm@chip/cpu, + ereport.cpu.amd.bu.s_eccm@chip/cpu; + +prop fault.cpu.amd.datapath@chip/cpu (0)-> + ereport.cpu.amd.ic.inf_sys_eccm@chip/cpu, + ereport.cpu.amd.dc.inf_sys_eccm@chip/cpu, + ereport.cpu.amd.bu.s_eccm@chip/cpu; + +/* + * Ereports that should not normally happen and which we will discard + * without diagnosis if they do. These fall into a few categories: + * + * - the corresponding detector is not enabled, typically because + * detection/handling of the event is taking place elsewhere + * (nb.ma, nb.ta, ls.rde, ic.rdde, bu.s_rde, nb.gart_walk) + * - the event is associated with a sync flood so even if the detector is + * enabled we will never handle the event and generate an ereport *and* + * even if the ereport did arrive we could perform no useful diagnosis + * e.g., the NB can be configured for sync flood on nb.mem_eccm + * but we don't choose to discard that ereport here since we could have + * made a useful diagnosis from it had it been delivered + * (nb.ht_sync, nb.ht_crc) + * - events that will be accompanied by an immediate panic and + * delivery of the ereport during subsequent reboot but from + * which no useful diagnosis can be made. (nb.rmw, nb.wdog) + * + * Ereports for all of these can be generated by error simulation and + * injection. We will perform a null diagnosos of all these ereports in order + * to avoid "no subscription" complaints during test harness runs. + */ + +event ereport.cpu.amd.nb.ma@cpu; +event ereport.cpu.amd.nb.ta@cpu; +event ereport.cpu.amd.ls.s_rde@cpu; +event ereport.cpu.amd.ic.rdde@cpu; +event ereport.cpu.amd.bu.s_rde@cpu; +event ereport.cpu.amd.nb.gart_walk@cpu; +event ereport.cpu.amd.nb.ht_sync@cpu; +event ereport.cpu.amd.nb.ht_crc@cpu; +event ereport.cpu.amd.nb.rmw@cpu; +event ereport.cpu.amd.nb.wdog@cpu; +event ereport.cpu.amd.unknown@cpu; + +event upset.null_diag@cpu; + +prop upset.null_diag@cpu (1)-> + ereport.cpu.amd.nb.ma@cpu, + ereport.cpu.amd.nb.ta@cpu, + ereport.cpu.amd.ls.s_rde@cpu, + ereport.cpu.amd.ic.rdde@cpu, + ereport.cpu.amd.bu.s_rde@cpu, + ereport.cpu.amd.nb.gart_walk@cpu, + ereport.cpu.amd.nb.ht_sync@cpu, + ereport.cpu.amd.nb.ht_crc@cpu, + ereport.cpu.amd.nb.rmw@cpu, + ereport.cpu.amd.nb.wdog@cpu, + ereport.cpu.amd.unknown@cpu; diff --git a/usr/src/cmd/fm/fmd/Makefile.fmd b/usr/src/cmd/fm/fmd/Makefile.fmd index cef38069bf..1d534bac7d 100644 --- a/usr/src/cmd/fm/fmd/Makefile.fmd +++ b/usr/src/cmd/fm/fmd/Makefile.fmd @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -112,7 +112,7 @@ CPPFLAGS += -D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT CFLAGS += $(CTF_FLAGS) $(CCVERBOSE) $(XSTRCONST) LINTFLAGS += -mu LDFLAGS += -R/usr/lib/fm -LDLIBS += -L$(ROOTLIB)/fm -ldiagcode -lsysevent -luuid -lnvpair +LDLIBS += -L$(ROOTLIB)/fm -ltopo -ldiagcode -lsysevent -lsmbios -luuid -lnvpair LDLIBS += -lexacct -lnsl -lrt -lumem $(DMOD) := CFLAGS += $(CC_PICFLAGS) -G $(XREGSFLAG) diff --git a/usr/src/cmd/fm/fmd/common/fmd.c b/usr/src/cmd/fm/fmd/common/fmd.c index 261fe1e536..d1ede5c2f0 100644 --- a/usr/src/cmd/fm/fmd/common/fmd.c +++ b/usr/src/cmd/fm/fmd/common/fmd.c @@ -32,7 +32,9 @@ #include <sys/param.h> #include <sys/systeminfo.h> #include <sys/fm/util.h> +#include <fm/libtopo.h> +#include <smbios.h> #include <limits.h> #include <unistd.h> #include <signal.h> @@ -70,6 +72,8 @@ const char _fmd_version[] = "1.1"; /* daemon version string */ static char _fmd_plat[MAXNAMELEN]; /* native platform string */ static char _fmd_isa[MAXNAMELEN]; /* native instruction set */ static struct utsname _fmd_uts; /* native uname(2) info */ +static char _fmd_csn[MAXNAMELEN]; /* chassis serial number */ +static char _fmd_prod[MAXNAMELEN]; /* product name string */ /* * Note: the configuration file path is ordered from most common to most host- @@ -223,7 +227,7 @@ static const fmd_conf_formal_t _fmd_conf[] = { { "agent.path", &fmd_conf_path, _fmd_agent_path }, /* path for agents */ { "alloc_msecs", &fmd_conf_uint32, "10" }, /* msecs before alloc retry */ { "alloc_tries", &fmd_conf_uint32, "3" }, /* max # of alloc retries */ -{ "chassis", &fmd_conf_string, NULL }, /* chassis serial number */ +{ "chassis", &fmd_conf_string, _fmd_csn }, /* chassis serial number */ { "ckpt.dir", &fmd_conf_string, "var/fm/fmd/ckpt" }, /* ckpt directory path */ { "ckpt.dirmode", &fmd_conf_int32, "0700" }, /* ckpt directory perm mode */ { "ckpt.mode", &fmd_conf_int32, "0400" }, /* ckpt file perm mode */ @@ -270,6 +274,7 @@ static const fmd_conf_formal_t _fmd_conf[] = { { "platform", &fmd_conf_string, _fmd_plat }, /* platform string (uname -i) */ { "plugin.close", &fmd_conf_bool, "true" }, /* dlclose plugins on fini */ { "plugin.path", &fmd_conf_path, _fmd_plugin_path }, /* path for plugin mods */ +{ "product", &fmd_conf_string, _fmd_prod }, /* product name string */ { "rootdir", &fmd_conf_string, "" }, /* root directory for paths */ { "rpc.adm.path", &fmd_conf_string, NULL }, /* FMD_ADM rendezvous file */ { "rpc.adm.prog", &fmd_conf_uint32, "100169" }, /* FMD_ADM rpc program num */ @@ -318,10 +323,24 @@ fmd_create(fmd_t *dp, const char *arg0, const char *root, const char *conf) fmd_stat_t *sp; int i; + smbios_hdl_t *shp; + smbios_system_t s1; + smbios_info_t s2; + id_t id; + (void) sysinfo(SI_PLATFORM, _fmd_plat, sizeof (_fmd_plat)); (void) sysinfo(SI_ARCHITECTURE, _fmd_isa, sizeof (_fmd_isa)); (void) uname(&_fmd_uts); + if ((shp = smbios_open(NULL, SMB_VERSION, 0, NULL)) != NULL) { + if ((id = smbios_info_system(shp, &s1)) != SMB_ERR && + smbios_info_common(shp, id, &s2) != SMB_ERR) { + (void) strlcpy(_fmd_prod, s2.smbi_product, MAXNAMELEN); + (void) strlcpy(_fmd_csn, s2.smbi_serial, MAXNAMELEN); + } + smbios_close(shp); + } + bzero(dp, sizeof (fmd_t)); dp->d_version = _fmd_version; @@ -575,6 +594,9 @@ fmd_destroy(fmd_t *dp) if (dp->d_conf != NULL) fmd_conf_close(dp->d_conf); + if (dp->d_topo != NULL) + topo_close(dp->d_topo); + nvlist_free(dp->d_auth); (void) nv_alloc_fini(&dp->d_nva); dp->d_clockops->fto_fini(dp->d_clockptr); @@ -694,7 +716,7 @@ fmd_run(fmd_t *dp, int pfd) const char *name; fmd_conf_path_t *pap; fmd_event_t *e; - int dbout; + int dbout, err; /* * Cache all the current debug property settings in d_fmd_debug, @@ -723,6 +745,14 @@ fmd_run(fmd_t *dp, int pfd) * This work is done here rather than in fmd_create() to permit the -o * command-line option to modify properties after fmd_create() is done. */ + name = dp->d_rootdir != NULL && + *dp->d_rootdir != '\0' ? dp->d_rootdir : NULL; + + if ((dp->d_topo = topo_open(TOPO_VERSION, name, &err)) == NULL) { + fmd_error(EFMD_EXIT, "failed to initialize " + "topology library: %s\n", topo_strerror(err)); + } + dp->d_clockptr = dp->d_clockops->fto_init(); dp->d_xprt_ids = fmd_idspace_create("xprt_ids", 1, INT_MAX); fmd_xprt_suspend_all(); diff --git a/usr/src/cmd/fm/fmd/common/fmd.h b/usr/src/cmd/fm/fmd/common/fmd.h index ce649baf9d..06c858c88a 100644 --- a/usr/src/cmd/fm/fmd/common/fmd.h +++ b/usr/src/cmd/fm/fmd/common/fmd.h @@ -21,7 +21,7 @@ */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -51,6 +51,7 @@ struct fmd_modhash; /* see <fmd_module.h> */ struct fmd_module; /* see <fmd_module.h> */ struct fmd_log; /* see <fmd_log.h> */ struct fmd_idspace; /* see <fmd_idspace.h> */ +struct topo_hdl; /* see <fm/libtopo.h> */ typedef struct fmd_statistics { fmd_stat_t ds_log_replayed; /* number of events replayed from log */ @@ -109,6 +110,7 @@ typedef struct fmd { void *d_dr_hdl; /* DR event handle (see fmd_dr.c) */ nv_alloc_t d_nva; /* libnvpair allocator handle */ nvlist_t *d_auth; /* FMRI authority nvlist */ + struct topo_hdl *d_topo; /* libtopo handle */ struct fmd_conf *d_conf; /* global configuration properties */ uint_t d_fg; /* cached value of "fg" property */ diff --git a/usr/src/cmd/fm/fmd/common/fmd_api.c b/usr/src/cmd/fm/fmd/common/fmd_api.c index 05aad51749..9ff325de59 100644 --- a/usr/src/cmd/fm/fmd/common/fmd_api.c +++ b/usr/src/cmd/fm/fmd/common/fmd_api.c @@ -29,6 +29,7 @@ #include <sys/types.h> #include <sys/fm/protocol.h> +#include <fm/libtopo.h> #include <unistd.h> #include <signal.h> @@ -686,6 +687,22 @@ fmd_hdl_opendict(fmd_hdl_t *hdl, const char *dict) fmd_module_unlock(mp); } +topo_hdl_t * +fmd_hdl_topology(fmd_hdl_t *hdl, int v) +{ + fmd_module_t *mp = fmd_api_module_lock(hdl); + topo_hdl_t *thp; + + if (v != TOPO_VERSION) { + fmd_api_error(mp, EFMD_MOD_TOPO, "libtopo version mismatch: " + "fmd version %d != client version %d\n", TOPO_VERSION, v); + } + + thp = fmd.d_topo; + fmd_module_unlock(mp); + return (thp); +} + void * fmd_hdl_alloc(fmd_hdl_t *hdl, size_t size, int flags) { @@ -1103,8 +1120,9 @@ fmd_case_add_ereport(fmd_hdl_t *hdl, fmd_case_t *cp, fmd_event_t *ep) fmd_module_t *mp = fmd_api_module_lock(hdl); (void) fmd_api_case_impl(mp, cp); /* validate 'cp' */ - fmd_case_insert_event(cp, ep); - mp->mod_stats->ms_accepted.fmds_value.ui64++; + + if (fmd_case_insert_event(cp, ep)) + mp->mod_stats->ms_accepted.fmds_value.ui64++; fmd_module_unlock(mp); } @@ -1124,10 +1142,11 @@ fmd_case_add_serd(fmd_hdl_t *hdl, fmd_case_t *cp, const char *name) (void) fmd_api_case_impl(mp, cp); /* validate 'cp' */ for (sep = fmd_list_next(&sgp->sg_list); - sep != NULL; sep = fmd_list_next(sep)) - fmd_case_insert_event(cp, sep->se_event); + sep != NULL; sep = fmd_list_next(sep)) { + if (fmd_case_insert_event(cp, sep->se_event)) + mp->mod_stats->ms_accepted.fmds_value.ui64++; + } - mp->mod_stats->ms_accepted.fmds_value.ui64 += sgp->sg_count; fmd_module_unlock(mp); } @@ -1187,8 +1206,9 @@ fmd_case_setprincipal(fmd_hdl_t *hdl, fmd_case_t *cp, fmd_event_t *ep) fmd_module_t *mp = fmd_api_module_lock(hdl); (void) fmd_api_case_impl(mp, cp); /* validate 'cp' */ - fmd_case_insert_principal(cp, ep); - mp->mod_stats->ms_accepted.fmds_value.ui64++; + + if (fmd_case_insert_principal(cp, ep)) + mp->mod_stats->ms_accepted.fmds_value.ui64++; fmd_module_unlock(mp); } @@ -1716,6 +1736,28 @@ fmd_nvl_fmri_unusable(fmd_hdl_t *hdl, nvlist_t *nvl) } int +fmd_nvl_fmri_faulty(fmd_hdl_t *hdl, nvlist_t *nvl) +{ + fmd_module_t *mp = fmd_api_module_lock(hdl); + fmd_asru_hash_t *ahp = fmd.d_asrus; + fmd_asru_t *ap; + int rv = 0; + + if (nvl == NULL) { + fmd_api_error(mp, EFMD_NVL_INVAL, + "invalid nvlist %p\n", (void *)nvl); + } + + if ((ap = fmd_asru_hash_lookup_nvl(ahp, nvl, FMD_B_FALSE)) != NULL) { + rv = (ap->asru_flags & FMD_ASRU_FAULTY) != 0; + fmd_asru_hash_release(ahp, ap); + } + + fmd_module_unlock(mp); + return (rv); +} + +int fmd_nvl_fmri_contains(fmd_hdl_t *hdl, nvlist_t *n1, nvlist_t *n2) { fmd_module_t *mp = fmd_api_module_lock(hdl); diff --git a/usr/src/cmd/fm/fmd/common/fmd_api.h b/usr/src/cmd/fm/fmd/common/fmd_api.h index 8848894612..1700c24bdb 100644 --- a/usr/src/cmd/fm/fmd/common/fmd_api.h +++ b/usr/src/cmd/fm/fmd/common/fmd_api.h @@ -21,7 +21,7 @@ */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -59,6 +59,8 @@ typedef struct fmd_event fmd_event_t; typedef struct fmd_case fmd_case_t; typedef struct fmd_xprt fmd_xprt_t; +struct topo_hdl; + #define FMD_B_FALSE 0 /* false value for booleans as int */ #define FMD_B_TRUE 1 /* true value for booleans as int */ @@ -132,6 +134,7 @@ extern void fmd_hdl_setspecific(fmd_hdl_t *, void *); extern void *fmd_hdl_getspecific(fmd_hdl_t *); extern void fmd_hdl_opendict(fmd_hdl_t *, const char *); +extern struct topo_hdl *fmd_hdl_topology(fmd_hdl_t *, int); #define FMD_NOSLEEP 0x0 /* do not sleep or retry on failure */ #define FMD_SLEEP 0x1 /* sleep or retry if alloc fails */ @@ -220,6 +223,7 @@ extern int fmd_nvl_class_match(fmd_hdl_t *, nvlist_t *, const char *); extern int fmd_nvl_fmri_expand(fmd_hdl_t *, nvlist_t *); extern int fmd_nvl_fmri_present(fmd_hdl_t *, nvlist_t *); extern int fmd_nvl_fmri_unusable(fmd_hdl_t *, nvlist_t *); +extern int fmd_nvl_fmri_faulty(fmd_hdl_t *, nvlist_t *); extern int fmd_nvl_fmri_contains(fmd_hdl_t *, nvlist_t *, nvlist_t *); extern nvlist_t *fmd_nvl_fmri_translate(fmd_hdl_t *, nvlist_t *, nvlist_t *); diff --git a/usr/src/cmd/fm/fmd/common/fmd_api.map b/usr/src/cmd/fm/fmd/common/fmd_api.map index 930293626f..7d56fe4f92 100644 --- a/usr/src/cmd/fm/fmd/common/fmd_api.map +++ b/usr/src/cmd/fm/fmd/common/fmd_api.map @@ -1,7 +1,4 @@ # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# # CDDL HEADER START # # The contents of this file are subject to the terms of the @@ -22,6 +19,9 @@ # # CDDL HEADER END # +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# #ident "%Z%%M% %I% %E% SMI" { @@ -65,6 +65,7 @@ fmd_hdl_strdup = FUNCTION extern; fmd_hdl_strfree = FUNCTION extern; fmd_hdl_subscribe = FUNCTION extern; + fmd_hdl_topology = FUNCTION extern; fmd_hdl_unregister = FUNCTION extern; fmd_hdl_unsubscribe = FUNCTION extern; fmd_hdl_vabort = FUNCTION extern; @@ -77,6 +78,7 @@ fmd_nvl_fmri_expand = FUNCTION extern; fmd_nvl_fmri_present = FUNCTION extern; fmd_nvl_fmri_unusable = FUNCTION extern; + fmd_nvl_fmri_faulty = FUNCTION extern; fmd_nvl_fmri_contains = FUNCTION extern; fmd_nvl_fmri_translate = FUNCTION extern; diff --git a/usr/src/cmd/fm/fmd/common/fmd_asru.c b/usr/src/cmd/fm/fmd/common/fmd_asru.c index a24440f3a5..f7fd62c3b2 100644 --- a/usr/src/cmd/fm/fmd/common/fmd_asru.c +++ b/usr/src/cmd/fm/fmd/common/fmd_asru.c @@ -21,7 +21,7 @@ */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -658,7 +658,6 @@ fmd_asru_logevent(fmd_asru_t *ap) char *class; ASSERT(MUTEX_HELD(&ap->asru_lock)); - ASSERT(ap->asru_case != NULL); cip = (fmd_case_impl_t *)ap->asru_case; if ((lp = ap->asru_log) == NULL) @@ -668,7 +667,8 @@ fmd_asru_logevent(fmd_asru_t *ap) return; /* can't log events if we can't open the log */ nvl = fmd_protocol_rsrc_asru(_fmd_asru_events[f | (u << 1)], - ap->asru_fmri, cip->ci_uuid, cip->ci_code, f, u, m, ap->asru_event); + ap->asru_fmri, cip ? cip->ci_uuid : NULL, + cip ? cip->ci_code : NULL, f, u, m, ap->asru_event); (void) nvlist_lookup_string(nvl, FM_CLASS, &class); e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, class); diff --git a/usr/src/cmd/fm/fmd/common/fmd_case.c b/usr/src/cmd/fm/fmd/common/fmd_case.c index 70ab574af6..45a8bae271 100644 --- a/usr/src/cmd/fm/fmd/common/fmd_case.c +++ b/usr/src/cmd/fm/fmd/common/fmd_case.c @@ -701,12 +701,14 @@ fmd_case_rele(fmd_case_t *cp) (void) pthread_mutex_unlock(&cip->ci_lock); } -void +int fmd_case_insert_principal(fmd_case_t *cp, fmd_event_t *ep) { fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; + fmd_case_item_t *cit; fmd_event_t *oep; uint_t state; + int new; fmd_event_hold(ep); (void) pthread_mutex_lock(&cip->ci_lock); @@ -719,7 +721,14 @@ fmd_case_insert_principal(fmd_case_t *cp, fmd_event_t *ep) oep = cip->ci_principal; cip->ci_principal = ep; + for (cit = cip->ci_items; cit != NULL; cit = cit->cit_next) { + if (cit->cit_event == ep) + break; + } + cip->ci_flags |= FMD_CF_DIRTY; + new = cit == NULL && ep != oep; + (void) pthread_mutex_unlock(&cip->ci_lock); fmd_module_setcdirty(cip->ci_mod); @@ -727,34 +736,58 @@ fmd_case_insert_principal(fmd_case_t *cp, fmd_event_t *ep) if (oep != NULL) fmd_event_rele(oep); + + return (new); } -void +int fmd_case_insert_event(fmd_case_t *cp, fmd_event_t *ep) { fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; - fmd_case_item_t *cit = fmd_alloc(sizeof (fmd_case_item_t), FMD_SLEEP); + fmd_case_item_t *cit; uint_t state; + int new; - fmd_event_hold(ep); (void) pthread_mutex_lock(&cip->ci_lock); + if (cip->ci_flags & FMD_CF_SOLVED) + state = FMD_EVS_DIAGNOSED; + else + state = FMD_EVS_ACCEPTED; + + for (cit = cip->ci_items; cit != NULL; cit = cit->cit_next) { + if (cit->cit_event == ep) + break; + } + + new = cit == NULL && ep != cip->ci_principal; + + /* + * If the event is already in the case or the case is already solved, + * there is no reason to save it: just transition it appropriately. + */ + if (cit != NULL || (cip->ci_flags & FMD_CF_SOLVED)) { + (void) pthread_mutex_unlock(&cip->ci_lock); + fmd_event_transition(ep, state); + return (new); + } + + cit = fmd_alloc(sizeof (fmd_case_item_t), FMD_SLEEP); + fmd_event_hold(ep); + cit->cit_next = cip->ci_items; cit->cit_event = ep; cip->ci_items = cit; cip->ci_nitems++; - if (cip->ci_flags & FMD_CF_SOLVED) - state = FMD_EVS_DIAGNOSED; - else - state = FMD_EVS_ACCEPTED; - cip->ci_flags |= FMD_CF_DIRTY; (void) pthread_mutex_unlock(&cip->ci_lock); fmd_module_setcdirty(cip->ci_mod); fmd_event_transition(ep, state); + + return (new); } void diff --git a/usr/src/cmd/fm/fmd/common/fmd_case.h b/usr/src/cmd/fm/fmd/common/fmd_case.h index fe14a99d8a..3e82709228 100644 --- a/usr/src/cmd/fm/fmd/common/fmd_case.h +++ b/usr/src/cmd/fm/fmd/common/fmd_case.h @@ -110,8 +110,9 @@ extern void fmd_case_hold(fmd_case_t *); extern void fmd_case_hold_locked(fmd_case_t *); extern void fmd_case_rele(fmd_case_t *); -extern void fmd_case_insert_principal(fmd_case_t *, fmd_event_t *); -extern void fmd_case_insert_event(fmd_case_t *, fmd_event_t *); +extern int fmd_case_insert_principal(fmd_case_t *, fmd_event_t *); +extern int fmd_case_insert_event(fmd_case_t *, fmd_event_t *); + extern void fmd_case_insert_suspect(fmd_case_t *, nvlist_t *); extern void fmd_case_recreate_suspect(fmd_case_t *, nvlist_t *); extern void fmd_case_reset_suspects(fmd_case_t *); diff --git a/usr/src/cmd/fm/fmd/common/fmd_conf.c b/usr/src/cmd/fm/fmd/common/fmd_conf.c index f6280a8bbe..81ea7830d3 100644 --- a/usr/src/cmd/fm/fmd/common/fmd_conf.c +++ b/usr/src/cmd/fm/fmd/common/fmd_conf.c @@ -19,8 +19,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -899,6 +900,34 @@ fmd_conf_getparam(fmd_conf_t *cfp, const char *name) return (NULL); } +/* + * String-friendly version of fmd_conf_getprop(): return the string as our + * return value, and return NULL if the string is the empty string. + */ +const char * +fmd_conf_getnzstr(fmd_conf_t *cfp, const char *name) +{ + const fmd_conf_param_t *pp; + char *s = NULL; + + (void) pthread_rwlock_rdlock(&cfp->cf_lock); + + if ((pp = fmd_conf_getparam(cfp, name)) != NULL) { + ASSERT(pp->cp_formal->cf_ops == &fmd_conf_string); + pp->cp_formal->cf_ops->co_get(pp, &s); + } else + (void) fmd_set_errno(EFMD_CONF_NOPROP); + + (void) pthread_rwlock_unlock(&cfp->cf_lock); + + if (s != NULL && s[0] == '\0') { + (void) fmd_set_errno(EFMD_CONF_UNDEF); + s = NULL; + } + + return (s); +} + const fmd_conf_ops_t * fmd_conf_gettype(fmd_conf_t *cfp, const char *name) { diff --git a/usr/src/cmd/fm/fmd/common/fmd_conf.h b/usr/src/cmd/fm/fmd/common/fmd_conf.h index e6a8793624..584465f0a0 100644 --- a/usr/src/cmd/fm/fmd/common/fmd_conf.h +++ b/usr/src/cmd/fm/fmd/common/fmd_conf.h @@ -21,7 +21,7 @@ */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -129,6 +129,7 @@ extern void fmd_conf_merge(fmd_conf_t *, const char *); extern void fmd_conf_propagate(fmd_conf_t *, fmd_conf_t *, const char *); extern void fmd_conf_close(fmd_conf_t *); +extern const char *fmd_conf_getnzstr(fmd_conf_t *, const char *); extern const fmd_conf_ops_t *fmd_conf_gettype(fmd_conf_t *, const char *); extern int fmd_conf_getprop(fmd_conf_t *, const char *, void *); extern int fmd_conf_setprop(fmd_conf_t *, const char *, const char *); diff --git a/usr/src/cmd/fm/fmd/common/fmd_error.h b/usr/src/cmd/fm/fmd/common/fmd_error.h index 6d2caf8ce9..1e46cf842a 100644 --- a/usr/src/cmd/fm/fmd/common/fmd_error.h +++ b/usr/src/cmd/fm/fmd/common/fmd_error.h @@ -21,7 +21,7 @@ */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -62,6 +62,7 @@ typedef enum fmd_errno { EFMD_CONF_PROPNAME, /* configuration property name is not an identifier */ EFMD_CONF_RDONLY, /* configuration property is read-only */ EFMD_CONF_DEFER, /* invalid deferred configuration file property */ + EFMD_CONF_UNDEF, /* configuration property is not defined */ EFMD_MOD_INIT, /* failed to initialize module */ EFMD_MOD_FINI, /* failed to uninitialize module */ EFMD_MOD_THR, /* failed to create processing thread for module */ @@ -71,6 +72,7 @@ typedef enum fmd_errno { EFMD_MOD_LOADED, /* specified module is already loaded */ EFMD_MOD_NOMOD, /* specified module is not loaded */ EFMD_MOD_FAIL, /* module failed due to preceding error */ + EFMD_MOD_TOPO, /* failed to obtain topology handle */ EFMD_RTLD_OPEN, /* rtld failed to open shared library plug-in */ EFMD_RTLD_INIT, /* shared library plug-in does not define _fmd_init */ EFMD_BLTIN_NAME, /* built-in plug-in name not found in definition list */ diff --git a/usr/src/cmd/fm/fmd/common/fmd_fmri.c b/usr/src/cmd/fm/fmd/common/fmd_fmri.c index df7855bdf3..1eb317c88b 100644 --- a/usr/src/cmd/fm/fmd/common/fmd_fmri.c +++ b/usr/src/cmd/fm/fmd/common/fmd_fmri.c @@ -21,7 +21,7 @@ */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -39,6 +39,8 @@ #include <fmd_fmri.h> #include <fmd.h> +#include <fm/libtopo.h> + /* * Interfaces to be used by the plugins */ @@ -229,6 +231,13 @@ fmd_fmri_get_drgen(void) return (gen); } +struct topo_hdl * +fmd_fmri_topology(int version) +{ + ASSERT(version == TOPO_VERSION); + return (fmd.d_topo); +} + /* * Interfaces for users of the plugins */ diff --git a/usr/src/cmd/fm/fmd/common/fmd_fmri.h b/usr/src/cmd/fm/fmd/common/fmd_fmri.h index 472529ab72..e16af0fbfa 100644 --- a/usr/src/cmd/fm/fmd/common/fmd_fmri.h +++ b/usr/src/cmd/fm/fmd/common/fmd_fmri.h @@ -21,7 +21,7 @@ */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -54,6 +54,8 @@ extern "C" { * fmd to facilitate the implementation of each FMRI scheme library. */ +struct topo_hdl; + #ifndef MIN #define MIN(x, y) ((x) < (y) ? (x) : (y)) #endif @@ -79,6 +81,8 @@ extern const char *fmd_fmri_get_platform(void); extern uint64_t fmd_fmri_get_drgen(void); +extern struct topo_hdl *fmd_fmri_topology(int); + /* * The following entry points are to be implemented by each scheme: */ diff --git a/usr/src/cmd/fm/fmd/common/fmd_fmri.map b/usr/src/cmd/fm/fmd/common/fmd_fmri.map index 15654d765b..51ac2f9114 100644 --- a/usr/src/cmd/fm/fmd/common/fmd_fmri.map +++ b/usr/src/cmd/fm/fmd/common/fmd_fmri.map @@ -1,5 +1,5 @@ # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # CDDL HEADER START @@ -37,4 +37,5 @@ fmd_fmri_get_rootdir = FUNCTION extern; fmd_fmri_get_platform = FUNCTION extern; fmd_fmri_get_drgen = FUNCTION extern; + fmd_fmri_topology = FUNCTION extern; }; diff --git a/usr/src/cmd/fm/fmd/common/fmd_protocol.c b/usr/src/cmd/fm/fmd/common/fmd_protocol.c index f5ae14bbce..05b9db8108 100644 --- a/usr/src/cmd/fm/fmd/common/fmd_protocol.c +++ b/usr/src/cmd/fm/fmd/common/fmd_protocol.c @@ -21,7 +21,7 @@ */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -55,16 +55,20 @@ fmd_protocol_authority(void) fmd_panic("failed to xalloc authority nvlist"); err |= nvlist_add_uint8(nvl, FM_VERSION, FM_FMRI_AUTH_VERSION); - (void) fmd_conf_getprop(fmd.d_conf, "platform", &str); - err |= nvlist_add_string(nvl, FM_FMRI_AUTH_PRODUCT, str); - if (fmd_conf_getprop(fmd.d_conf, "chassis", &str) == 0 && str != NULL) + if ((str = fmd_conf_getnzstr(fmd.d_conf, "product")) == NULL) + str = fmd_conf_getnzstr(fmd.d_conf, "platform"); + + if (str != NULL) + err |= nvlist_add_string(nvl, FM_FMRI_AUTH_PRODUCT, str); + + if ((str = fmd_conf_getnzstr(fmd.d_conf, "chassis")) != NULL) err |= nvlist_add_string(nvl, FM_FMRI_AUTH_CHASSIS, str); - if (fmd_conf_getprop(fmd.d_conf, "domain", &str) == 0 && str != NULL) + if ((str = fmd_conf_getnzstr(fmd.d_conf, "domain")) != NULL) err |= nvlist_add_string(nvl, FM_FMRI_AUTH_DOMAIN, str); - if (fmd_conf_getprop(fmd.d_conf, "server", &str) == 0 && str != NULL) + if ((str = fmd_conf_getnzstr(fmd.d_conf, "server")) != NULL) err |= nvlist_add_string(nvl, FM_FMRI_AUTH_SERVER, str); if (err != 0) @@ -188,8 +192,13 @@ fmd_protocol_rsrc_asru(const char *class, err |= nvlist_add_uint8(nvl, FM_VERSION, FM_RSRC_VERSION); err |= nvlist_add_string(nvl, FM_CLASS, class); err |= nvlist_add_nvlist(nvl, FM_RSRC_RESOURCE, fmri); - err |= nvlist_add_string(nvl, FM_RSRC_ASRU_UUID, uuid); - err |= nvlist_add_string(nvl, FM_RSRC_ASRU_CODE, code); + + if (uuid != NULL) + err |= nvlist_add_string(nvl, FM_RSRC_ASRU_UUID, uuid); + + if (code != NULL) + err |= nvlist_add_string(nvl, FM_RSRC_ASRU_CODE, code); + err |= nvlist_add_boolean_value(nvl, FM_RSRC_ASRU_FAULTY, faulty); err |= nvlist_add_boolean_value(nvl, FM_RSRC_ASRU_UNUSABLE, unusable); err |= nvlist_add_boolean_value(nvl, FM_SUSPECT_MESSAGE, message); diff --git a/usr/src/cmd/fm/fmd/common/fmd_sysevent.c b/usr/src/cmd/fm/fmd/common/fmd_sysevent.c index 1464cf55a1..ff7f30f07e 100644 --- a/usr/src/cmd/fm/fmd/common/fmd_sysevent.c +++ b/usr/src/cmd/fm/fmd/common/fmd_sysevent.c @@ -21,7 +21,7 @@ */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -34,6 +34,7 @@ #include <sys/sysmacros.h> #include <sys/dumphdr.h> #include <sys/dumpadm.h> +#include <sys/fm/util.h> #include <libsysevent.h> #include <libnvpair.h> diff --git a/usr/src/cmd/fm/fmdump/Makefile.com b/usr/src/cmd/fm/fmdump/Makefile.com index f092c87d04..873c62481e 100644 --- a/usr/src/cmd/fm/fmdump/Makefile.com +++ b/usr/src/cmd/fm/fmdump/Makefile.com @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -38,7 +38,7 @@ ROOTPROG = $(ROOTUSRSBIN)/$(PROG) $(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG CPPFLAGS += -I. -I../common -I../../include CFLAGS += $(CTF_FLAGS) $(CCVERBOSE) $(XSTRCONST) -LDLIBS += -L$(ROOT)/usr/lib/fm -lfmd_log -lnvpair +LDLIBS += -L$(ROOT)/usr/lib/fm -lfmd_log -lnvpair -ltopo LDFLAGS += -R/usr/lib/fm LINTFLAGS += -mnu diff --git a/usr/src/cmd/fm/fmdump/common/fault.c b/usr/src/cmd/fm/fmdump/common/fault.c index ecd5de804f..8554d91757 100644 --- a/usr/src/cmd/fm/fmdump/common/fault.c +++ b/usr/src/cmd/fm/fmdump/common/fault.c @@ -19,8 +19,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -60,8 +61,8 @@ flt_verb1(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp) } for (i = 0; i < size; i++) { - char *class = NULL, *rname = NULL, *fname = NULL; - nvlist_t *fru, *rsc; + char *class = NULL, *rname = NULL, *aname = NULL, *fname = NULL; + nvlist_t *fru, *asru, *rsrc; uint8_t pct = 0; (void) nvlist_lookup_uint8(nva[i], FM_FAULT_CERTAINTY, &pct); @@ -70,17 +71,30 @@ flt_verb1(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp) if (nvlist_lookup_nvlist(nva[i], FM_FAULT_FRU, &fru) == 0) fname = fmdump_nvl2str(fru); - if (nvlist_lookup_nvlist(nva[i], FM_FAULT_RESOURCE, &rsc) == 0) - rname = fmdump_nvl2str(rsc); - else if (nvlist_lookup_nvlist(nva[i], FM_FAULT_ASRU, &rsc) == 0) - rname = fmdump_nvl2str(rsc); + if (nvlist_lookup_nvlist(nva[i], FM_FAULT_ASRU, &asru) == 0) + aname = fmdump_nvl2str(asru); + + if (nvlist_lookup_nvlist(nva[i], FM_FAULT_RESOURCE, &rsrc) == 0) + rname = fmdump_nvl2str(rsrc); + + fmdump_printf(fp, " %3u%% %s\n\n", + pct, class ? class : "-"); + + /* + * Originally we didn't require FM_FAULT_RESOURCE, so if it + * isn't defined in the event, display the ASRU FMRI instead. + */ + fmdump_printf(fp, " Problem in: %s\n", + rname ? rname : aname ? aname : "-"); + + fmdump_printf(fp, " Affects: %s\n", + aname ? aname : "-"); - fmdump_printf(fp, " %3u%% %s\n" - " FRU: %s\n rsrc: %s\n\n", - pct, class ? class : "-", - fname ? fname : "-", rname ? rname : "-"); + fmdump_printf(fp, " FRU: %s\n\n", + fname ? fname : "-"); free(fname); + free(aname); free(rname); } diff --git a/usr/src/cmd/fm/fmdump/common/fmdump.c b/usr/src/cmd/fm/fmdump/common/fmdump.c index 1e794ec120..919a2577d7 100644 --- a/usr/src/cmd/fm/fmdump/common/fmdump.c +++ b/usr/src/cmd/fm/fmdump/common/fmdump.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -48,6 +48,7 @@ const char *g_pname; ulong_t g_errs; ulong_t g_recs; char *g_root; +struct topo_hdl *g_thp; /*PRINTFLIKE2*/ void diff --git a/usr/src/cmd/fm/fmdump/common/fmdump.h b/usr/src/cmd/fm/fmdump/common/fmdump.h index 180b22e0fa..5fd9a743af 100644 --- a/usr/src/cmd/fm/fmdump/common/fmdump.h +++ b/usr/src/cmd/fm/fmdump/common/fmdump.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -39,6 +39,7 @@ extern "C" { #include <sys/types.h> #include <sys/fm/protocol.h> #include <fm/fmd_log.h> +#include <fm/libtopo.h> enum { FMDUMP_SHORT, @@ -76,6 +77,7 @@ extern const char *g_pname; extern ulong_t g_errs; extern ulong_t g_recs; extern char *g_root; +extern struct topo_hdl *g_thp; extern void fmdump_printf(FILE *, const char *, ...); extern void fmdump_warn(const char *, ...); diff --git a/usr/src/cmd/fm/fmdump/common/scheme.c b/usr/src/cmd/fm/fmdump/common/scheme.c index 7cc6d11170..fd388807cc 100644 --- a/usr/src/cmd/fm/fmdump/common/scheme.c +++ b/usr/src/cmd/fm/fmdump/common/scheme.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -301,3 +301,20 @@ fmd_fmri_warn(const char *format, ...) fmdump_vwarn(format, ap); va_end(ap); } + +/*ARGSUSED*/ +struct topo_hdl * +fmd_fmri_topology(int version) +{ + int err; + + if (g_thp == NULL) { + if ((g_thp = topo_open(TOPO_VERSION, "/", &err)) == NULL) { + (void) fprintf(stderr, "topo_open failed: %s\n", + topo_strerror(err)); + exit(1); + } + } + + return (g_thp); +} diff --git a/usr/src/cmd/fm/fminject/Makefile.com b/usr/src/cmd/fm/fminject/Makefile.com index 0f14676f82..32f33dfc81 100644 --- a/usr/src/cmd/fm/fminject/Makefile.com +++ b/usr/src/cmd/fm/fminject/Makefile.com @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -49,10 +49,11 @@ LINTFILES = $(SRCS:%.c=%.ln) CLEANFILES += inj_grammar.c inj_grammar.h inj_lex.c y.tab.h y.tab.c CPPFLAGS += -I. -I../common -CFLAGS += $(CCVERBOSE) +CFLAGS += $(CCVERBOSE) $(CTF_FLAGS) LDLIBS += -L$(ROOT)/usr/lib/fm -lfmd_log -lsysevent -lnvpair -lumem LDFLAGS += -R/usr/lib/fm LINTFLAGS = -mnux +STRIPFLAG = LFLAGS = -t -v YFLAGS = -d @@ -63,6 +64,7 @@ all: $(PROG) $(PROG): $(OBJS) $(LINK.c) $(OBJS) -o $@ $(LDLIBS) + $(CTFMERGE) -L VERSION -o $@ $(OBJS) $(POST_PROCESS) inj_lex.c: ../common/inj_lex.l inj_grammar.c @@ -75,9 +77,11 @@ inj_grammar.c: ../common/inj_grammar.y %.o: %.c $(COMPILE.c) $< + $(CTFCONVERT_O) %.o: ../common/%.c $(COMPILE.c) $< + $(CTFCONVERT_O) clean: $(RM) $(OBJS) $(LINTFILES) $(CLEANFILES) diff --git a/usr/src/cmd/fm/fminject/common/inj.h b/usr/src/cmd/fm/fminject/common/inj.h index 93eccbb7a7..f4cf1c0467 100644 --- a/usr/src/cmd/fm/fminject/common/inj.h +++ b/usr/src/cmd/fm/fminject/common/inj.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -47,19 +47,23 @@ extern "C" { #endif /* - * The injector allows for the declaration, definition, and injection of three - * types of things - Events, FMRIs, and Authorities. While each has a different - * function within the FMA framework, their internal composition is similar - * enough to allow for the use of a single struct to represent all three. The - * inj_itemtype_t enum is used to describe which of the three types is being - * represented by a given object. + * The injector allows for the declaration, definition, and injection of four + * types of things - Events, FMRIs, Authorities, and lists. The first three + * are essentially lists with extra membership requirements (FMRIs, for + * example, must include a member called `scheme'). So while each has a + * different function within the FMA framework, we can use a single struct to + * store all three. The inj_itemtype_t enum is used to describe which of the + * four types is being represented by a given object. */ typedef enum inj_itemtype { ITEMTYPE_EVENT, ITEMTYPE_FMRI, - ITEMTYPE_AUTH + ITEMTYPE_AUTH, + ITEMTYPE_LIST } inj_itemtype_t; +#define ITEMTYPE_NITEMS 4 + /* * The member name-value pairs of Events, FMRIs, and Authorities are typed. */ @@ -78,7 +82,8 @@ typedef enum inj_memtype { MEMTYPE_ENUM, MEMTYPE_EVENT, MEMTYPE_FMRI, - MEMTYPE_AUTH + MEMTYPE_AUTH, + MEMTYPE_LIST } inj_memtype_t; /* @@ -157,7 +162,7 @@ typedef enum inj_defnmemtype { DEFNMEM_FMRI, DEFNMEM_AUTH, DEFNMEM_ARRAY, - DEFNMEM_SUBLIST + DEFNMEM_LIST } inj_defnmemtype_t; typedef struct inj_defnmem { @@ -168,7 +173,7 @@ typedef struct inj_defnmem { union { const char *_dfm_str; /* String value of member */ - inj_list_t _dfm_list; /* Enum, evt, auth, arr, sublist vals */ + inj_list_t _dfm_list; /* Enum, evt, auth, arr, list vals */ } _dfm_u; } inj_defnmem_t; diff --git a/usr/src/cmd/fm/fminject/common/inj_decl.c b/usr/src/cmd/fm/fminject/common/inj_decl.c index 071b588a3d..67b5f16ed2 100644 --- a/usr/src/cmd/fm/fminject/common/inj_decl.c +++ b/usr/src/cmd/fm/fminject/common/inj_decl.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -41,7 +41,7 @@ #include <inj_list.h> #include <inj.h> -static inj_hash_t inj_decls[3]; +static inj_hash_t inj_decls[ITEMTYPE_NITEMS]; static int inj_decls_initialized; static inj_hash_t * @@ -224,10 +224,9 @@ inj_decl_validate_fmri(inj_decl_t *decl) return (1); } -/* Authorities don't have any semantic requirements - yet */ /*ARGSUSED*/ static int -inj_decl_validate_auth(inj_decl_t *decl) +inj_decl_validate_nop(inj_decl_t *decl) { return (1); } @@ -238,7 +237,8 @@ inj_decl_finish(inj_decl_t *decl, const char *name, inj_itemtype_t type) static int (*const validators[])(inj_decl_t *) = { inj_decl_validate_event, inj_decl_validate_fmri, - inj_decl_validate_auth + inj_decl_validate_nop, /* no validation for auth */ + inj_decl_validate_nop /* no validation for lists */ }; inj_hash_t *hash = item2hash(type); diff --git a/usr/src/cmd/fm/fminject/common/inj_defn.c b/usr/src/cmd/fm/fminject/common/inj_defn.c index c7ac8e8301..a521632e62 100644 --- a/usr/src/cmd/fm/fminject/common/inj_defn.c +++ b/usr/src/cmd/fm/fminject/common/inj_defn.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -89,7 +89,7 @@ inj_defn_destroy_memlist(inj_defnmem_t *m) switch (m->dfm_type) { case DEFNMEM_ARRAY: - case DEFNMEM_SUBLIST: + case DEFNMEM_LIST: inj_defn_destroy_memlist(inj_list_next(&m->dfm_list)); break; default: @@ -546,11 +546,11 @@ inj_defn_memcmp_strenum_array(inj_declmem_t *dlm, inj_defnmem_t *dfm, } /* - * Validator for embedded lists (events, fmris, authorities, etc.). There are - * two cases to deal with here. The user could either have provided the name - * of a previously-defined list, in which case we just make a copy of said - * list for insertion into ours. Alternatively, the user could simply define - * a new sublist here. In that case, we recursively invoke the member + * Validator for embedded lists (events, fmris, authorities, lists, etc.). + * There are two cases to deal with here. The user could either have provided + * the name of a previously-defined list, in which case we just make a copy of + * said list for insertion into ours. Alternatively, the user could simply + * define a new list here. In that case, we recursively invoke the member * comparator, but against the list type for the member being defined. */ static nvlist_t *inj_defn_validate_memlist(inj_declmem_t *, inj_defnmem_t *); @@ -604,7 +604,7 @@ inj_defn_memcmp_sub_makenvl(inj_declmem_t *dlm, inj_defnmem_t *dfm) inj_memtype_t dltype = dlm->dlm_type; nvlist_t *new = NULL; - if (dftype == DEFNMEM_SUBLIST) + if (dftype == DEFNMEM_LIST) new = inj_defn_memcmp_sub_list(dlm, dfm); else if (dftype == DEFNMEM_IDENT && (dltype == MEMTYPE_EVENT || dltype == MEMTYPE_FMRI || dltype == MEMTYPE_AUTH)) @@ -669,7 +669,7 @@ inj_defn_memcmp_sub_array(inj_declmem_t *dlm, inj_defnmem_t *dfm, nvlist_t *nvl) /* * The declaration-definition member comparator. Designed to recursive - * invocation to allow for the validation of embedded/referenced sublists. + * invocation to allow for the validation of embedded/referenced lists. */ nvlist_t * inj_defn_validate_memlist(inj_declmem_t *dlm, inj_defnmem_t *dfm) @@ -742,6 +742,7 @@ inj_defn_validate_memlist(inj_declmem_t *dlm, inj_defnmem_t *dfm) case MEMTYPE_EVENT: case MEMTYPE_FMRI: case MEMTYPE_AUTH: + case MEMTYPE_LIST: if (dlm->dlm_flags & DECLMEM_F_ARRAY) rc = inj_defn_memcmp_sub_array(dlm, dfm, nvl); else diff --git a/usr/src/cmd/fm/fminject/common/inj_grammar.y b/usr/src/cmd/fm/fminject/common/inj_grammar.y index fac250dc6b..dcc83d88d3 100644 --- a/usr/src/cmd/fm/fminject/common/inj_grammar.y +++ b/usr/src/cmd/fm/fminject/common/inj_grammar.y @@ -20,7 +20,7 @@ * * CDDL HEADER END * - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -82,6 +82,7 @@ %token INJ_TOK_EVDEF %token INJ_TOK_FMRIDEF %token INJ_TOK_AUTHDEF +%token INJ_TOK_LISTDEF %token INJ_TOK_INT8 %token INJ_TOK_INT16 @@ -98,6 +99,7 @@ %token INJ_TOK_EVENT %token INJ_TOK_FMRI %token INJ_TOK_AUTH +%token INJ_TOK_LIST %token INJ_TOK_ADDHRT %token INJ_TOK_ENDHRT @@ -125,7 +127,7 @@ statement: decl ; /* - * Event, FMRI, Authority declarations + * Event, FMRI, Authority, and list declarations */ decl: INJ_TOK_EVDEF INJ_TOK_FMACLASS '{' decl_memlist '}' { @@ -140,6 +142,10 @@ decl: INJ_TOK_EVDEF INJ_TOK_FMACLASS '{' decl_memlist '}' { if ($4 != NULL) inj_decl_finish($4, $2, ITEMTYPE_AUTH); } + | INJ_TOK_LISTDEF INJ_TOK_IDENT '{' decl_memlist '}' { + if ($4 != NULL) + inj_decl_finish($4, $2, ITEMTYPE_LIST); + } ; decl_memlist: /* EMPTY */ { $$ = NULL; } @@ -207,6 +213,10 @@ decl_mem_cplx: INJ_TOK_ENUM INJ_TOK_IDENT '{' decl_enumlist '}' { $$ = inj_decl_mem_create_defined($3, $2, ITEMTYPE_AUTH); } + | INJ_TOK_LIST INJ_TOK_IDENT INJ_TOK_IDENT { + $$ = inj_decl_mem_create_defined($3, $2, + ITEMTYPE_LIST); + } ; decl_enumlist: INJ_TOK_IDENT { @@ -225,7 +235,7 @@ decl_enumlist: INJ_TOK_IDENT { ; /* - * Event, FMRI, Authority definitions + * Event, FMRI, Authority, and list definitions */ defn: INJ_TOK_EVENT INJ_TOK_FMACLASS INJ_TOK_IDENT '=' @@ -268,7 +278,7 @@ defn_memvals: defn_val $$ = inj_defn_mem_create_list($2, DEFNMEM_ARRAY); } | '{' defn_memlist '}' { - $$ = inj_defn_mem_create_list($2, DEFNMEM_SUBLIST); + $$ = inj_defn_mem_create_list($2, DEFNMEM_LIST); } ; @@ -360,7 +370,10 @@ inj_program_read(const char *file) if ((yyin = fopen(file, "r")) == NULL) die("failed to open %s", file); - if ((yyinname = strrchr(file, '/')) == NULL) + yyinname = strrchr(file, '/'); + if (yyinname != NULL) + yyinname++; + else yyinname = file; } diff --git a/usr/src/cmd/fm/fminject/common/inj_lex.l b/usr/src/cmd/fm/fminject/common/inj_lex.l index cd88ea3c48..f3d03b96b1 100644 --- a/usr/src/cmd/fm/fminject/common/inj_lex.l +++ b/usr/src/cmd/fm/fminject/common/inj_lex.l @@ -20,7 +20,7 @@ * * CDDL HEADER END * - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -42,8 +42,6 @@ const char *yyinname; %} -%a 3000 /* Number of transitions */ - /* * S0 is for normal input processing. SCOMMENT is used to process comments. * We need a separate state for comments to prevent the lex regexp engine from @@ -64,6 +62,7 @@ RGX_IDENT [a-zA-Z][a-zA-Z0-9\-_]* <S0>evdef { return (INJ_TOK_EVDEF); } <S0>fmridef { return (INJ_TOK_FMRIDEF); } <S0>authdef { return (INJ_TOK_AUTHDEF); } +<S0>listdef { return (INJ_TOK_LISTDEF); } <S0>int8_t { return (INJ_TOK_INT8); } <S0>int16_t { return (INJ_TOK_INT16); } @@ -81,6 +80,7 @@ RGX_IDENT [a-zA-Z][a-zA-Z0-9\-_]* <S0>event { return (INJ_TOK_EVENT); } <S0>fmri { return (INJ_TOK_FMRI); } <S0>auth { return (INJ_TOK_AUTH); } +<S0>list { return (INJ_TOK_LIST); } <S0>addhrtime { return (INJ_TOK_ADDHRT); } <S0>endhrtime { return (INJ_TOK_ENDHRT); } diff --git a/usr/src/cmd/fm/fminject/common/inj_util.c b/usr/src/cmd/fm/fminject/common/inj_util.c index 2a5f060744..48f45bd6e1 100644 --- a/usr/src/cmd/fm/fminject/common/inj_util.c +++ b/usr/src/cmd/fm/fminject/common/inj_util.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -33,7 +33,7 @@ const char * inj_item2str(inj_itemtype_t item) { - static const char *const names[] = { "event", "fmri", "auth" }; + static const char *const names[] = { "event", "fmri", "auth", "list" }; return (item >= 0 && item < sizeof (names) / sizeof (char *) ? names[item] : "???"); @@ -43,7 +43,7 @@ inj_memtype_t inj_item2mem(inj_itemtype_t item) { static const inj_memtype_t mems[] = { - MEMTYPE_EVENT, MEMTYPE_FMRI, MEMTYPE_AUTH + MEMTYPE_EVENT, MEMTYPE_FMRI, MEMTYPE_AUTH, MEMTYPE_LIST }; assert(item >= 0 && item < sizeof (mems) / sizeof (inj_memtype_t)); @@ -63,6 +63,8 @@ inj_mem2item(inj_memtype_t mem) return (ITEMTYPE_FMRI); case MEMTYPE_AUTH: return (ITEMTYPE_AUTH); + case MEMTYPE_LIST: + return (ITEMTYPE_LIST); default: return (-1); } diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V445/Makefile b/usr/src/cmd/fm/fmtopo/Makefile index 30c479d087..2e8360f71f 100644 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V445/Makefile +++ b/usr/src/cmd/fm/fmtopo/Makefile @@ -25,7 +25,6 @@ # #ident "%Z%%M% %I% %E% SMI" -TOPOSUBDIR = SUNW,Sun-Fire-V445 -TOPOFILES = platform.topo +SUBDIRS = $(MACH) -include ../../Makefile.com +include ../Makefile.subdirs diff --git a/usr/src/cmd/fm/topo/prtopo/Makefile.com b/usr/src/cmd/fm/fmtopo/Makefile.com index e36f587e51..7b09bbbd87 100644 --- a/usr/src/cmd/fm/topo/prtopo/Makefile.com +++ b/usr/src/cmd/fm/fmtopo/Makefile.com @@ -19,59 +19,68 @@ # # CDDL HEADER END # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. + +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" .KEEP_STATE: +.SUFFIXES: -PROG = prtopo - -OBJS = $(PROG:=.o) -SRCS = $(OBJS:.o=.c) +SRCS += fmtopo.c +OBJS = $(SRCS:%.c=%.o) +LINTFILES = $(SRCS:%.c=%.ln) -LINTSRCS = $(OBJS:%.o=../common/%.c) -LINTFLAGS = -mnux - -CPPFLAGS += -I../common -CFLAGS += $(CTF_FLAGS) +PROG = fmtopo +ROOTLIBFM = $(ROOT)/usr/lib/fm +ROOTLIBFMD = $(ROOT)/usr/lib/fm/fmd +ROOTPROG = $(ROOTLIBFMD)/$(PROG) +$(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG +CPPFLAGS += -I. -I../common +CFLAGS += $(CTF_FLAGS) $(CCVERBOSE) $(XSTRCONST) +LDLIBS += -L$(ROOT)/usr/lib/fm -ltopo -lnvpair LDFLAGS += -R/usr/lib/fm -LDLIBS += -lnvpair -lumem -L$(ROOTLIB)/fm -ltopo - -ROOTPDIR = $(ROOT)/usr/lib/fm -ROOTPROG = $(ROOTPDIR)/$(PROG) +LINTFLAGS += -mnu -all debug: $(PROG) +.NO_PARALLEL: +.PARALLEL: $(OBJS) $(LINTFILES) -install: all $(ROOTPROG) - -_msg install_h: - -lint: $(LINTSRCS) - $(LINT.c) $(LINTSRCS) $(LDLIBS) +all: $(PROG) $(PROG): $(OBJS) - $(LINK.c) -o $@ $(OBJS) $(LDLIBS) + $(LINK.c) $(OBJS) -o $@ $(LDLIBS) $(CTFMERGE) -L VERSION -o $@ $(OBJS) $(POST_PROCESS) +%.o: ../common/%.c + $(COMPILE.c) $< + $(CTFCONVERT_O) + +%.o: %.c + $(COMPILE.c) $< + $(CTFCONVERT_O) + clean: - $(RM) $(OBJS) core + $(RM) $(OBJS) $(LINTFILES) clobber: clean $(RM) $(PROG) -$(ROOT)/usr/lib/fm: - $(INS.dir) +%.ln: ../common/%.c + $(LINT.c) -c $< + +%.ln: %.c + $(LINT.c) -c $< -$(ROOTPDIR): $(ROOT)/usr/lib/fm - $(INS.dir) +lint: $(LINTFILES) + $(LINT) $(LINTFLAGS) $(LINTFILES) -$(ROOTPDIR)/%: % +$(ROOTLIBFMD)/%: % $(INS.file) -%.o: ../common/%.c - $(COMPILE.c) $< - $(CTFCONVERT_O) +install_h: + +install: all $(ROOTPROG) diff --git a/usr/src/cmd/fm/fmtopo/common/fmtopo.c b/usr/src/cmd/fm/fmtopo/common/fmtopo.c new file mode 100644 index 0000000000..22c58b7649 --- /dev/null +++ b/usr/src/cmd/fm/fmtopo/common/fmtopo.c @@ -0,0 +1,315 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/fm/protocol.h> +#include <fm/libtopo.h> +#include <limits.h> +#include <strings.h> +#include <stdio.h> +#include <errno.h> + +#define FMTOPO_EXIT_SUCCESS 0 +#define FMTOPO_EXIT_ERROR 1 +#define FMTOPO_EXIT_USAGE 2 + +static const char *g_pname; + +static const char *opt_R = "/"; +static const char *opt_s = FM_FMRI_SCHEME_HC; + +static int opt_e; +static int opt_d; +static int opt_v; +static int opt_V; + +static int +usage(FILE *fp) +{ + (void) fprintf(fp, + "Usage: %s [-Cdev] [-R root] [-s scheme]\n", g_pname); + + (void) fprintf(fp, + "\t-C dump core after completing execution\n" + "\t-d set debug mode for libtopo\n" + "\t-e display nodes as paths using esc/eft notation\n" + "\t-R set root directory for libtopo plug-ins and other files\n" + "\t-s display topology for the specified FMRI scheme\n" + "\t-v set verbose mode (display node ASRU, FRU and label)\n" + "\t-V set verbose mode (display node properties)\n"); + + return (FMTOPO_EXIT_USAGE); +} + +static void +print_fmri(topo_hdl_t *thp, tnode_t *node) +{ + int err; + char *name; + nvlist_t *fmri; + + if (topo_node_resource(node, &fmri, &err) < 0) { + (void) fprintf(stderr, "%s: failed to get fmri for %s=%d: %s\n", + g_pname, topo_node_name(node), + topo_node_instance(node), topo_strerror(err)); + return; + } + + if (topo_fmri_nvl2str(thp, fmri, &name, &err) < 0) { + (void) fprintf(stderr, "%s: failed to convert fmri for %s=%d " + "to a string: %s\n", g_pname, topo_node_name(node), + topo_node_instance(node), topo_strerror(err)); + nvlist_free(fmri); + return; + } + + (void) printf("%s\n", name); + + if (opt_v) { + char *aname = NULL, *fname = NULL, *lname = NULL; + nvlist_t *asru = NULL; + nvlist_t *fru = NULL; + + if (topo_node_asru(node, &asru, NULL, &err) == 0) + (void) topo_fmri_nvl2str(thp, asru, &aname, &err); + if (topo_node_fru(node, &fru, NULL, &err) == 0) + (void) topo_fmri_nvl2str(thp, fru, &fname, &err); + (void) topo_node_label(node, &lname, &err); + if (aname != NULL) { + nvlist_free(asru); + (void) printf("\tASRU: %s\n", aname); + topo_hdl_strfree(thp, aname); + } else { + (void) printf("\tASRU: -\n"); + } + if (fname != NULL) { + nvlist_free(fru); + (void) printf("\tFRU: %s\n", fname); + topo_hdl_strfree(thp, fname); + } else { + (void) printf("\tFRU: -\n"); + } + if (lname != NULL) { + (void) printf("\tLabel: %s\n", lname); + topo_hdl_strfree(thp, lname); + } else { + (void) printf("\tLabel: -\n"); + } + } + + nvlist_free(fmri); + + if (opt_d) { + fmri = NULL; + + if (topo_fmri_str2nvl(thp, name, &fmri, &err) < 0) { + (void) fprintf(stderr, "%s: failed to convert " + "alternate fmri for %s=%d: %s\n", g_pname, + topo_node_name(node), topo_node_instance(node), + topo_strerror(err)); + } else { + nvlist_print(stderr, fmri); + nvlist_free(fmri); + } + } + + topo_hdl_strfree(thp, name); +} + +static void +print_everstyle(tnode_t *node) +{ + char buf[PATH_MAX], numbuf[64]; + nvlist_t *fmri, **hcl; + int i, err; + uint_t n; + + if (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL, + TOPO_PROP_RESOURCE, &fmri, &err) < 0) { + (void) fprintf(stderr, "%s: failed to get fmri for %s=%d: %s\n", + g_pname, topo_node_name(node), + topo_node_instance(node), topo_strerror(err)); + return; + } + + if (nvlist_lookup_nvlist_array(fmri, FM_FMRI_HC_LIST, &hcl, &n) != 0) { + (void) fprintf(stderr, "%s: failed to find %s for %s=%d\n", + g_pname, FM_FMRI_HC_LIST, topo_node_name(node), + topo_node_instance(node)); + return; + } + + buf[0] = '\0'; + + for (i = 0; i < n; i++) { + char *name, *inst, *estr; + ulong_t ul; + + if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &name) != 0 || + nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &inst) != 0) { + (void) fprintf(stderr, "%s: failed to get " + "name-instance for %s=%d\n", g_pname, + topo_node_name(node), topo_node_instance(node)); + return; + } + + errno = 0; + ul = strtoul(inst, &estr, 10); + + if (errno != 0 || estr == inst) { + (void) fprintf(stderr, "%s: instance %s does not " + "convert to an unsigned integer\n", g_pname, inst); + } + + (void) strlcat(buf, "/", sizeof (buf)); + (void) strlcat(buf, name, sizeof (buf)); + (void) snprintf(numbuf, sizeof (numbuf), "%u", ul); + (void) strlcat(buf, numbuf, sizeof (buf)); + } + + (void) printf("%s\n", buf); +} + +/*ARGSUSED*/ +static int +print_tnode(topo_hdl_t *thp, tnode_t *node, void *arg) +{ + if (opt_e && strcmp(opt_s, FM_FMRI_SCHEME_HC) == 0) + print_everstyle(node); + else + print_fmri(thp, node); + + if (opt_V) { + nvlist_t *nvl = topo_prop_get_all(thp, node); + + if (nvl == NULL) { + (void) fprintf(stderr, "%s: failed to get properties " + "for %s=%d\n", g_pname, topo_node_name(node), + topo_node_instance(node)); + } else { + nvlist_print(stdout, nvl); + nvlist_free(nvl); + } + } + + return (TOPO_WALK_NEXT); +} + +int +main(int argc, char *argv[]) +{ + topo_hdl_t *thp; + topo_walk_t *twp; + char *uuid; + int c, err; + + g_pname = argv[0]; + + while (optind < argc) { + while ((c = getopt(argc, argv, "aCdeR:s:vV")) != -1) { + switch (c) { + case 'C': + atexit(abort); + break; + case 'd': + opt_d++; + break; + case 'e': + opt_e++; + break; + case 'v': + opt_v++; + break; + case 'V': + opt_V++; + break; + case 'R': + opt_R = optarg; + break; + case 's': + opt_s = optarg; + break; + default: + return (usage(stderr)); + } + } + + if (optind < argc) { + (void) fprintf(stderr, "%s: illegal argument -- %s\n", + g_pname, argv[optind]); + return (FMTOPO_EXIT_USAGE); + } + } + + if ((thp = topo_open(TOPO_VERSION, opt_R, &err)) == NULL) { + (void) fprintf(stderr, "%s: failed to open topology tree: %s\n", + g_pname, topo_strerror(err)); + return (FMTOPO_EXIT_ERROR); + } + + if (opt_d) + topo_debug_set(thp, TOPO_DBG_ALL, "stderr"); + + if ((uuid = topo_snap_hold(thp, NULL, &err)) == NULL) { + (void) fprintf(stderr, "%s: failed to snapshot topology: %s\n", + g_pname, topo_strerror(err)); + topo_close(thp); + return (FMTOPO_EXIT_ERROR); + } + + if ((twp = topo_walk_init(thp, opt_s, print_tnode, NULL, &err)) + == NULL) { + (void) fprintf(stderr, "%s: failed to walk %s topology:" + " %s\n", g_pname, opt_s, topo_strerror(err)); + + topo_hdl_strfree(thp, uuid); + topo_close(thp); + + return (err ? FMTOPO_EXIT_ERROR : FMTOPO_EXIT_SUCCESS); + } + + if (!opt_e) + (void) printf("Topology Snapshot %s\n", uuid); + + topo_hdl_strfree(thp, uuid); + + if (topo_walk_step(twp, TOPO_WALK_CHILD) == TOPO_WALK_ERR) { + (void) fprintf(stderr, "%s: failed to walk topology\n", + g_pname); + topo_close(thp); + return (FMTOPO_EXIT_ERROR); + } + + if (opt_d) + (void) printf("--------------------\n"); + + topo_walk_fini(twp); + topo_snap_release(thp); + topo_close(thp); + + return (FMTOPO_EXIT_SUCCESS); +} diff --git a/usr/src/cmd/fm/topo/prtopo/i386/Makefile b/usr/src/cmd/fm/fmtopo/i386/Makefile index 617fb6a35b..719d6803ef 100644 --- a/usr/src/cmd/fm/topo/prtopo/i386/Makefile +++ b/usr/src/cmd/fm/fmtopo/i386/Makefile @@ -20,10 +20,10 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" -include ../../../../Makefile.cmd +include ../../../Makefile.cmd include ../Makefile.com diff --git a/usr/src/cmd/fm/topo/prtopo/sparc/Makefile b/usr/src/cmd/fm/fmtopo/sparc/Makefile index 617fb6a35b..719d6803ef 100644 --- a/usr/src/cmd/fm/topo/prtopo/sparc/Makefile +++ b/usr/src/cmd/fm/fmtopo/sparc/Makefile @@ -20,10 +20,10 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" -include ../../../../Makefile.cmd +include ../../../Makefile.cmd include ../Makefile.com diff --git a/usr/src/cmd/fm/modules/Makefile.plugin b/usr/src/cmd/fm/modules/Makefile.plugin index 78a19027c5..0f87397900 100644 --- a/usr/src/cmd/fm/modules/Makefile.plugin +++ b/usr/src/cmd/fm/modules/Makefile.plugin @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -81,7 +81,7 @@ $(PROG): $(OBJS) $(APIMAP) $(CTFCONVERT_O) clean: - $(RM) $(OBJS) $(LINTFILES) + $(RM) $(OBJS) $(LINTFILES) $(CLEANFILES) clobber: clean $(RM) $(PROG) diff --git a/usr/src/cmd/fm/modules/common/cpumem-retire/Makefile b/usr/src/cmd/fm/modules/common/cpumem-retire/Makefile index b2c8edd855..906fc33e08 100644 --- a/usr/src/cmd/fm/modules/common/cpumem-retire/Makefile +++ b/usr/src/cmd/fm/modules/common/cpumem-retire/Makefile @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -39,3 +39,5 @@ CMA_VERSION = "1.1" INCDIRS = . CPPFLAGS += $(INCDIRS:%=-I%) -DCMA_VERSION='$(CMA_VERSION)' +LDFLAGS += -R/usr/lib/fm +LDLIBS += -L$(ROOTLIB)/fm -ltopo diff --git a/usr/src/cmd/fm/modules/common/cpumem-retire/cma.h b/usr/src/cmd/fm/modules/common/cpumem-retire/cma.h index a4a165c872..0b3477937b 100644 --- a/usr/src/cmd/fm/modules/common/cpumem-retire/cma.h +++ b/usr/src/cmd/fm/modules/common/cpumem-retire/cma.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -57,6 +57,7 @@ typedef struct cma { hrtime_t cma_page_maxdelay; /* Maximum retry sleep interval */ id_t cma_page_timerid; /* fmd timer ID for retry sleep */ uint_t cma_page_doretire; /* Whether to retire pages */ + uint_t cma_page_maxretries; /* Maximum retry on page retires */ } cma_t; typedef struct cma_stats { @@ -69,6 +70,7 @@ typedef struct cma_stats { fmd_stat_t page_fails; /* Failed page retires */ fmd_stat_t page_supp; /* Suppressed retires */ fmd_stat_t page_nonent; /* Retires for non-present pages */ + fmd_stat_t page_retmax; /* Retires for page reached max */ fmd_stat_t bad_flts; /* Malformed faults */ fmd_stat_t nop_flts; /* Inapplicable faults */ fmd_stat_t auto_flts; /* Auto-close faults */ diff --git a/usr/src/cmd/fm/modules/common/cpumem-retire/cma_main.c b/usr/src/cmd/fm/modules/common/cpumem-retire/cma_main.c index bfbdc1d7e3..138359c17a 100644 --- a/usr/src/cmd/fm/modules/common/cpumem-retire/cma_main.c +++ b/usr/src/cmd/fm/modules/common/cpumem-retire/cma_main.c @@ -21,7 +21,7 @@ */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -47,6 +47,7 @@ cma_stats_t cma_stats = { { "page_fails", FMD_TYPE_UINT64, "page faults unresolveable" }, { "page_supp", FMD_TYPE_UINT64, "page retires suppressed" }, { "page_nonent", FMD_TYPE_UINT64, "retires for non-existent fmris" }, + { "page_retmax", FMD_TYPE_UINT64, "hit max retries for page retire" }, { "bad_flts", FMD_TYPE_UINT64, "invalid fault events received" }, { "nop_flts", FMD_TYPE_UINT64, "inapplicable fault events received" }, { "auto_flts", FMD_TYPE_UINT64, "auto-close faults received" } @@ -60,10 +61,18 @@ typedef struct cma_subscriber { } cma_subscriber_t; static const cma_subscriber_t cma_subrs[] = { + { "fault.cpu.*", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, + cma_cpu_retire }, { "fault.memory.page", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, cma_page_retire }, { "fault.memory.dimm", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, + { "fault.memory.dimm_sb", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, + NULL }, + { "fault.memory.dimm_ck", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, + NULL }, + { "fault.memory.dimm_ue", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, + NULL }, { "fault.memory.bank", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.memory.datapath", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, @@ -196,6 +205,18 @@ static const fmd_prop_t fmd_props[] = { { "page_ret_mindelay", FMD_TYPE_TIME, "1sec" }, { "page_ret_maxdelay", FMD_TYPE_TIME, "5min" }, { "page_retire_enable", FMD_TYPE_BOOL, "true" }, +#ifdef i386 + /* + * On i386, leaving cases open while we retry the + * retire can cause the eft module to use large amounts + * of memory. Until eft is fixed, we set a maximum number + * of retries on page retires, after which the case will + * be closed. + */ + { "page_retire_maxretries", FMD_TYPE_UINT32, "8" }, +#else + { "page_retire_maxretries", FMD_TYPE_UINT32, "0" }, +#endif /* i386 */ { NULL, 0, NULL } }; @@ -232,6 +253,8 @@ _fmd_init(fmd_hdl_t *hdl) cma.cma_cpu_doblacklist = fmd_prop_get_int32(hdl, "cpu_blacklist_enable"); cma.cma_page_doretire = fmd_prop_get_int32(hdl, "page_retire_enable"); + cma.cma_page_maxretries = + fmd_prop_get_int32(hdl, "page_retire_maxretries"); if (cma.cma_page_maxdelay < cma.cma_page_mindelay) fmd_hdl_abort(hdl, "page retirement delays conflict\n"); diff --git a/usr/src/cmd/fm/modules/common/cpumem-retire/cma_page.c b/usr/src/cmd/fm/modules/common/cpumem-retire/cma_page.c index a24981522d..9e82c3ff76 100644 --- a/usr/src/cmd/fm/modules/common/cpumem-retire/cma_page.c +++ b/usr/src/cmd/fm/modules/common/cpumem-retire/cma_page.c @@ -19,8 +19,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -56,6 +57,7 @@ #include <unistd.h> #include <strings.h> #include <fm/fmd_api.h> +#include <fm/libtopo.h> #include <sys/fm/protocol.h> #include <sys/mem.h> @@ -110,12 +112,29 @@ cma_page_free(fmd_hdl_t *hdl, cma_page_t *page) fmd_hdl_free(hdl, page, sizeof (cma_page_t)); } +/* + * Retire the specified ASRU, referring to a memory page by PA or by DIMM + * offset (i.e. the encoded coordinates internal bank, row, and column). + * In the initial FMA implementation, fault.memory.page exported an ASRU + * with an explicit physical address, which is valid at the initial time of + * diagnosis but may not be later following DR, DIMM removal, or interleave + * changes. On SPARC, this issue was solved by exporting the DIMM offset + * and pushing the entire FMRI to the platform memory controller through + * /dev/mem so it can derive the current PA from the DIMM and offset. + * On x64, we also use DIMM and offset, but the mem:/// unum string is an + * encoded hc:/// FMRI that is then used by the x64 memory controller driver. + * At some point these three approaches need to be rationalized: all platforms + * should use the same scheme, either with decoding in the kernel or decoding + * in userland (i.e. with a libtopo method to compute and update the PA). + */ /*ARGSUSED*/ void cma_page_retire(fmd_hdl_t *hdl, nvlist_t *nvl, nvlist_t *asru, const char *uuid) { cma_page_t *page; uint64_t pageaddr; + char *unumstr; + nvlist_t *asrucp = NULL; /* It should already be expanded, but we'll do it again anyway */ if (fmd_nvl_fmri_expand(hdl, asru) < 0) { @@ -146,12 +165,54 @@ cma_page_retire(fmd_hdl_t *hdl, nvlist_t *nvl, nvlist_t *asru, const char *uuid) return; } - if (cma_page_cmd(hdl, MEM_PAGE_FMRI_RETIRE, asru) == 0) { + /* + * If the unum is an hc fmri string expand it to an fmri and include + * that in a modified asru nvlist. + */ + if (nvlist_lookup_string(asru, FM_FMRI_MEM_UNUM, &unumstr) == 0 && + strncmp(unumstr, "hc:/", 4) == 0) { + int err; + nvlist_t *unumfmri; + struct topo_hdl *thp = fmd_hdl_topology(hdl, TOPO_VERSION); + + if (topo_fmri_str2nvl(thp, unumstr, &unumfmri, &err) != 0) { + fmd_hdl_debug(hdl, "page retire str2nvl failed: %s\n", + topo_strerror(err)); + return; + } + + if (nvlist_dup(asru, &asrucp, 0) != 0) { + fmd_hdl_debug(hdl, "page retire nvlist dup failed\n"); + nvlist_free(unumfmri); + return; + } + + if (nvlist_add_nvlist(asrucp, FM_FMRI_MEM_UNUM "-fmri", + unumfmri) != 0) { + fmd_hdl_debug(hdl, "page retire failed to add " + "unumfmri to modified asru"); + nvlist_free(unumfmri); + nvlist_free(asrucp); + return; + } + nvlist_free(unumfmri); + } + + if (cma_page_cmd(hdl, MEM_PAGE_FMRI_RETIRE, + asrucp ? asrucp : asru) == 0) { fmd_hdl_debug(hdl, "retired page 0x%llx\n", (u_longlong_t)pageaddr); cma_stats.page_flts.fmds_value.ui64++; if (uuid != NULL) fmd_case_uuclose(hdl, uuid); + if (asrucp) + nvlist_free(asrucp); + return; + } else if (errno != EAGAIN) { + fmd_hdl_debug(hdl, "retire of page 0x%llx failed, will not " + "retry: %s\n", (u_longlong_t)pageaddr, strerror(errno)); + if (asrucp) + nvlist_free(asrucp); return; } @@ -163,7 +224,11 @@ cma_page_retire(fmd_hdl_t *hdl, nvlist_t *nvl, nvlist_t *asru, const char *uuid) page = fmd_hdl_zalloc(hdl, sizeof (cma_page_t), FMD_SLEEP); page->pg_addr = pageaddr; - (void) nvlist_dup(asru, &page->pg_fmri, 0); + if (asrucp) { + page->pg_fmri = asrucp; + } else { + (void) nvlist_dup(asru, &page->pg_fmri, 0); + } if (uuid != NULL) page->pg_uuid = fmd_hdl_strdup(hdl, uuid, FMD_SLEEP); @@ -246,9 +311,28 @@ cma_page_retry(fmd_hdl_t *hdl) fmd_hdl_strfree(hdl, page->pg_uuid); cma_page_free(hdl, page); - } else { + } else if (cma.cma_page_maxretries == 0 || + page->pg_nretries < cma.cma_page_maxretries) { page->pg_nretries++; pagep = &page->pg_next; + } else { + /* + * Tunable maxretries was set and we reached + * the max, so just close the case. + */ + fmd_hdl_debug(hdl, + "giving up page retire 0x%llx on retry %u\n", + page->pg_addr, page->pg_nretries); + cma_stats.page_retmax.fmds_value.ui64++; + + if (page->pg_uuid != NULL) { + fmd_case_uuclose(hdl, page->pg_uuid); + fmd_hdl_strfree(hdl, page->pg_uuid); + } + + *pagep = page->pg_next; + + cma_page_free(hdl, page); } } diff --git a/usr/src/cmd/fm/modules/common/eversholt/Makefile b/usr/src/cmd/fm/modules/common/eversholt/Makefile index 1be725f133..84d3fdebbe 100644 --- a/usr/src/cmd/fm/modules/common/eversholt/Makefile +++ b/usr/src/cmd/fm/modules/common/eversholt/Makefile @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -37,7 +37,7 @@ CLASS = common YSRCS=escparse.y SRCS = alloc.c check.c config.c eft.c eftread.c esclex.c eval.c evnv.c \ - fme.c io.c ipath.c itree.c lut.c literals.c out.c platform.c \ + fme.c iexpr.c io.c ipath.c itree.c lut.c literals.c out.c platform.c \ ptree.c stable.c stats.c tree.c include ../../Makefile.plugin @@ -46,6 +46,8 @@ CPPFLAGS += -DFMAPLUGIN -I$(EVERSRCDIR) -I. LDFLAGS += -R/usr/lib/fm LDLIBS += -L$(ROOTLIB)/fm -ltopo +CLEANFILES += y.tab.h y.tab.c + esclex.o: escparse.o %.o: $(EVERSRCDIR)/%.c @@ -56,6 +58,6 @@ esclex.o: escparse.o $(LINT.c) -c $< escparse.o: $(EVERSRCDIR)/escparse.y - $(YACC) -dtv $(EVERSRCDIR)/escparse.y + $(YACC) -dt $(EVERSRCDIR)/escparse.y $(COMPILE.c) -DYYDEBUG -c -o $@ y.tab.c $(CTFCONVERT_O) diff --git a/usr/src/cmd/fm/modules/common/eversholt/eft.c b/usr/src/cmd/fm/modules/common/eversholt/eft.c index 35fc4b5292..0b8d6d0450 100644 --- a/usr/src/cmd/fm/modules/common/eversholt/eft.c +++ b/usr/src/cmd/fm/modules/common/eversholt/eft.c @@ -21,7 +21,7 @@ */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -41,6 +41,7 @@ #include "tree.h" #include "ipath.h" #include "itree.h" +#include "iexpr.h" #include "ptree.h" #include "check.h" #include "version.h" @@ -57,6 +58,7 @@ fmd_hdl_t *Hdl; /* handle in global for platform.c */ int Debug = 1; /* turn on here and let fmd_hdl_debug() decide if really on */ char *Autoclose; /* close cases automatically after solving */ +int Dupclose; /* close cases on duplicate diagosis */ hrtime_t Hesitate; /* hesitation time in ns */ int Verbose; int Estats; @@ -110,6 +112,7 @@ eft_close(fmd_hdl_t *hdl, fmd_case_t *fmcase) static const fmd_prop_t eft_props[] = { { "autoclose", FMD_TYPE_STRING, NULL }, + { "dupclose", FMD_TYPE_BOOL, "false" }, { "estats", FMD_TYPE_BOOL, "false" }, { "hesitate", FMD_TYPE_INT64, "10000000000" }, { "verbose", FMD_TYPE_INT32, "0" }, @@ -190,6 +193,8 @@ call_finis(void) fme_fini(); itree_fini(); ipath_fini(); + iexpr_fini(); + istat_fini(); lex_free(); check_fini(); tree_fini(); @@ -232,6 +237,7 @@ _fmd_init(fmd_hdl_t *hdl) lut_init(); tree_init(); ipath_init(); + iexpr_init(); Efts = platform_get_eft_files(); lex_init(Efts, NULL, 0); check_init(); @@ -264,6 +270,7 @@ _fmd_init(fmd_hdl_t *hdl) Verbose = fmd_prop_get_int32(hdl, "verbose"); Warn = fmd_prop_get_int32(hdl, "warn"); Autoclose = fmd_prop_get_string(hdl, "autoclose"); + Dupclose = fmd_prop_get_int32(hdl, "dupclose"); Hesitate = fmd_prop_get_int64(hdl, "hesitate"); Max_fme = fmd_prop_get_int32(hdl, "maxfme"); @@ -284,14 +291,16 @@ _fmd_init(fmd_hdl_t *hdl) out(O_ALTFP|O_STAMP, "\neft.so startup"); } - out(O_DEBUG, - "initialized, verbose %d warn %d autoclose %s maxfme %d", - Verbose, Warn, Autoclose == NULL ? "(NULL)" : Autoclose, Max_fme); + out(O_DEBUG, "initialized, verbose %d warn %d autoclose %s " + "dupclose %d maxfme %d", + Verbose, Warn, Autoclose == NULL ? "(NULL)" : Autoclose, + Dupclose, Max_fme); out(O_DEBUG, "reconstituting any existing fmes"); while ((casep = fmd_case_next(hdl, casep)) != NULL) { fme_restart(hdl, casep); } + fme_istat_load(hdl); } /*ARGSUSED*/ diff --git a/usr/src/cmd/fm/modules/common/eversholt/eft.conf b/usr/src/cmd/fm/modules/common/eversholt/eft.conf index 59e47bfee9..0afc4d32a4 100644 --- a/usr/src/cmd/fm/modules/common/eversholt/eft.conf +++ b/usr/src/cmd/fm/modules/common/eversholt/eft.conf @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -37,6 +37,14 @@ # to "all" closes all cases automatcally, setting it # to "upsets" closes only those containing only upsets. # +# setprop dupclose true +# +# Turns on detection of "duplicate diagnosis" which is +# defined as a diagnosis producing a suspect list made up +# entirely of resources already marked "faulty" by the +# system. Such diagoses are silently closed when dupclose +# is true. +# # setprop estats true # # Enables "extended stats" visible via "fmstat -m eft". @@ -66,3 +74,4 @@ # dictionary SUNOS setprop autoclose upsets +setprop dupclose true diff --git a/usr/src/cmd/fm/modules/common/eversholt/eval.c b/usr/src/cmd/fm/modules/common/eversholt/eval.c index 8d7fe840b5..2b26a25056 100644 --- a/usr/src/cmd/fm/modules/common/eversholt/eval.c +++ b/usr/src/cmd/fm/modules/common/eversholt/eval.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * eval.c -- constraint evaluation module @@ -42,13 +42,17 @@ #include "tree.h" #include "ptree.h" #include "itree.h" +#include "ipath.h" #include "eval.h" #include "config.h" #include "platform.h" - +#include "fme.h" +#include "stats.h" static struct node *eval_dup(struct node *np, struct lut *ex, - struct node *epnames[]); + struct node *epnames[]); +static int check_expr_args(struct evalue *lp, struct evalue *rp, + enum datatype dtype, struct node *np); /* * begins_with -- return true if rhs path begins with everything in lhs path @@ -158,6 +162,12 @@ eval_func(struct node *funcnp, struct lut *ex, struct node *epnames[], valuep->t = NODEPTR; valuep->v = (unsigned long long)eval_asru(np); return (1); + } else if (funcname == L_defined) { + ASSERTeq(np->t, T_GLOBID, ptree_nodetype2str); + valuep->t = UINT64; + valuep->v = (lut_lookup(*globals, + (void *)np->u.globid.s, NULL) != NULL); + return (1); } else if (funcname == L_call) { return (! platform_call(np, globals, croot, arrowp, valuep)); } else if (funcname == L_is_connected) { @@ -174,53 +184,190 @@ eval_func(struct node *funcnp, struct lut *ex, struct node *epnames[], outfl(O_DIE, np->file, np->line, "eval_func: %s not yet supported", funcname); } else if (funcname == L_payloadprop) { - outfl(O_ALTFP|O_VERB|O_NONL, np->file, np->line, + outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line, "payloadprop(\"%s\") ", np->u.quote.s); - if (funcnp->u.func.cachedval != NULL) { - *valuep = *(struct evalue *)(funcnp->u.func.cachedval); + if (platform_payloadprop(np, valuep)) { + /* platform_payloadprop() returned false */ + out(O_ALTFP|O_VERB2, "not found."); + return (0); + } else { switch (valuep->t) { case UINT64: case NODEPTR: - out(O_ALTFP|O_VERB, "cached: %llu", valuep->v); + out(O_ALTFP|O_VERB2, "found: %llu", valuep->v); break; case STRING: - out(O_ALTFP|O_VERB, "cached: \"%s\"", + out(O_ALTFP|O_VERB2, "found: \"%s\"", (char *)valuep->v); break; default: - out(O_ALTFP|O_VERB, "undefined"); + out(O_ALTFP|O_VERB2, "found: undefined"); break; } - return (1); - } else if (platform_payloadprop(np, valuep)) { - /* platform_payloadprop() returned false, pass it on */ - out(O_ALTFP|O_VERB, "failed."); - return (0); + } + } else if (funcname == L_setpayloadprop) { + struct evalue *payloadvalp; + + ASSERTinfo(np->t == T_LIST, ptree_nodetype2str(np->t)); + ASSERTinfo(np->u.expr.left->t == T_QUOTE, + ptree_nodetype2str(np->u.expr.left->t)); + + outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line, + "setpayloadprop: %s: %s=", + arrowp->tail->myevent->enode->u.event.ename->u.name.s, + np->u.expr.left->u.quote.s); + ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np->u.expr.right); + + /* + * allocate a struct evalue to hold the payload property's + * value, unless we've been here already, in which case we + * might calculate a different value, but we'll store it + * in the already-allocated struct evalue. + */ + if ((payloadvalp = (struct evalue *)lut_lookup( + arrowp->tail->myevent->payloadprops, + (void *)np->u.expr.left->u.quote.s, NULL)) == NULL) { + payloadvalp = MALLOC(sizeof (*payloadvalp)); + } + + if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, + arrowp, try, payloadvalp)) { + out(O_ALTFP|O_VERB2, " (cannot eval, using zero)"); + payloadvalp->t = UINT64; + payloadvalp->v = 0; } else { - /* got back true, cache the value */ - funcnp->u.func.cachedval = - MALLOC(sizeof (struct evalue)); - *(struct evalue *)(funcnp->u.func.cachedval) = - *valuep; + if (payloadvalp->t == UINT64) + out(O_ALTFP|O_VERB2, + " (%llu)", payloadvalp->v); + else + out(O_ALTFP|O_VERB2, + " (\"%s\")", (char *)payloadvalp->v); + } - switch (valuep->t) { - case UINT64: - case NODEPTR: - out(O_ALTFP|O_VERB, "cached: %llu", valuep->v); - break; - case STRING: - out(O_ALTFP|O_VERB, "cached: \"%s\"", - (char *)valuep->v); - break; - default: - out(O_ALTFP|O_VERB, "undefined"); - break; + /* add to table of payload properties for current problem */ + arrowp->tail->myevent->payloadprops = + lut_add(arrowp->tail->myevent->payloadprops, + (void *)np->u.expr.left->u.quote.s, + (void *)payloadvalp, NULL); + + /* function is always true */ + valuep->t = UINT64; + valuep->v = 1; + return (1); + } else if (funcname == L_payloadprop_defined) { + outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line, + "payloadprop_defined(\"%s\") ", np->u.quote.s); + + if (platform_payloadprop(np, NULL)) { + /* platform_payloadprop() returned false */ + valuep->v = 0; + out(O_ALTFP|O_VERB2, "not found."); + } else { + valuep->v = 1; + out(O_ALTFP|O_VERB2, "found."); + } + valuep->t = UINT64; + return (1); + } else if (funcname == L_payloadprop_contains) { + int nvals; + struct evalue *vals; + struct evalue cmpval; + + ASSERTinfo(np->t == T_LIST, ptree_nodetype2str(np->t)); + ASSERTinfo(np->u.expr.left->t == T_QUOTE, + ptree_nodetype2str(np->u.expr.left->t)); + + outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line, + "payloadprop_contains(\"%s\", ", + np->u.expr.left->u.quote.s); + ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np->u.expr.right); + outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line, ") "); + + /* evaluate the expression we're comparing against */ + if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, + arrowp, try, &cmpval)) { + out(O_ALTFP|O_VERB2|O_NONL, + "(cannot eval, using zero) "); + cmpval.t = UINT64; + cmpval.v = 0; + } else { + if (cmpval.t == UINT64) + out(O_ALTFP|O_VERB2, + "(%llu) ", cmpval.v); + else + out(O_ALTFP|O_VERB2, + "(\"%s\") ", (char *)cmpval.v); + } + + /* get the payload values and check for a match */ + vals = platform_payloadprop_values(np->u.expr.left->u.quote.s, + &nvals); + valuep->t = UINT64; + valuep->v = 0; + if (nvals == 0) { + out(O_ALTFP|O_VERB2, "not found."); + } else { + struct evalue preval; + int i; + + out(O_ALTFP|O_VERB2|O_NONL, "found %d values ", nvals); + + for (i = 0; i < nvals; i++) { + + preval.t = vals[i].t; + preval.v = vals[i].v; + + if (check_expr_args(&vals[i], &cmpval, + UNDEFINED, np)) + continue; + + /* + * If we auto-converted the value to a + * string, we need to free the + * original tree value. + */ + if (preval.t == NODEPTR && + ((struct node *)(preval.v))->t == T_NAME) { + tree_free((struct node *)preval.v); + } + + if (vals[i].v == cmpval.v) { + valuep->v = 1; + break; + } } - return (1); + if (valuep->v) + out(O_ALTFP|O_VERB2, "match."); + else + out(O_ALTFP|O_VERB2, "no match."); + + for (i = 0; i < nvals; i++) { + if (vals[i].t == NODEPTR) { + tree_free((struct node *)vals[i].v); + break; + } + } + FREE(vals); } + return (1); + } else if (funcname == L_confcall) { + return (!platform_confcall(np, globals, croot, arrowp, valuep)); + } else if (funcname == L_count) { + struct stats *statp; + + ASSERTinfo(np->t == T_EVENT, ptree_nodetype2str(np->t)); + + valuep->t = UINT64; + if ((statp = (struct stats *) + lut_lookup(Istats, np, (lut_cmp)istat_cmp)) == NULL) + valuep->v = 0; + else + valuep->v = stats_counter_value(statp); + + return (1); } else outfl(O_DIE, np->file, np->line, "eval_func: unexpected func: %s", funcname); @@ -419,6 +566,18 @@ eval_dup(struct node *np, struct lut *ex, struct node *epnames[]) break; } + case T_EVENT: + newnp = newnode(T_NAME, np->file, np->line); + + newnp->u.name.t = np->u.event.ename->u.name.t; + newnp->u.name.s = np->u.event.ename->u.name.s; + newnp->u.name.it = np->u.event.ename->u.name.it; + newnp->u.name.last = newnp; + + return (tree_event(newnp, + eval_dup(np->u.event.epname, ex, epnames), + eval_dup(np->u.event.eexprlist, ex, epnames))); + case T_FUNC: return (tree_func(np->u.func.s, eval_dup(np->u.func.arglist, ex, epnames), @@ -525,6 +684,37 @@ static int check_expr_args(struct evalue *lp, struct evalue *rp, enum datatype dtype, struct node *np) { + /* auto-convert T_NAMES to strings */ + if (lp->t == NODEPTR && ((struct node *)(lp->v))->t == T_NAME) { + char *s = ipath2str(NULL, ipath((struct node *)lp->v)); + lp->t = STRING; + lp->v = (unsigned long long)stable(s); + FREE(s); + out(O_ALTFP|O_VERB2, "convert lhs path to \"%s\"", + (char *)lp->v); + } + if (rp != NULL && + rp->t == NODEPTR && ((struct node *)(rp->v))->t == T_NAME) { + char *s = ipath2str(NULL, ipath((struct node *)rp->v)); + rp->t = STRING; + rp->v = (unsigned long long)stable(s); + FREE(s); + out(O_ALTFP|O_VERB2, "convert rhs path to \"%s\"", + (char *)rp->v); + } + + /* auto-convert strings to numbers */ + if (dtype == UINT64) { + if (lp->t == STRING) { + lp->t = UINT64; + lp->v = strtoull((char *)lp->v, NULL, 0); + } + if (rp != NULL && rp->t == STRING) { + rp->t = UINT64; + rp->v = strtoull((char *)rp->v, NULL, 0); + } + } + if (dtype != UNDEFINED && lp->t != dtype) { outfl(O_OK, np->file, np->line, "invalid datatype of argument for operation %s", @@ -619,8 +809,23 @@ eval_expr(struct node *np, struct lut *ex, struct node *epnames[], gval->t = rval.t; gval->v = rval.v; - valuep->t = rval.t; - valuep->v = rval.v; + + if (gval->t == UINT64) { + out(O_ALTFP|O_VERB2, + "assign $%s=%llu", + np->u.expr.left->u.globid.s, gval->v); + } else { + out(O_ALTFP|O_VERB2, + "assign $%s=\"%s\"", + np->u.expr.left->u.globid.s, (char *)gval->v); + } + + /* + * but always return true -- an assignment should not + * cause a constraint to be false. + */ + valuep->t = UINT64; + valuep->v = 1; return (1); case T_EQ: @@ -675,7 +880,7 @@ eval_expr(struct node *np, struct lut *ex, struct node *epnames[], if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, arrowp, try, &rval)) return (0); - if (check_expr_args(&lval, &rval, UNDEFINED, np)) + if (check_expr_args(&lval, &rval, UINT64, np)) return (0); valuep->t = UINT64; @@ -689,7 +894,7 @@ eval_expr(struct node *np, struct lut *ex, struct node *epnames[], if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, arrowp, try, &rval)) return (0); - if (check_expr_args(&lval, &rval, UNDEFINED, np)) + if (check_expr_args(&lval, &rval, UINT64, np)) return (0); valuep->t = UINT64; @@ -703,7 +908,7 @@ eval_expr(struct node *np, struct lut *ex, struct node *epnames[], if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, arrowp, try, &rval)) return (0); - if (check_expr_args(&lval, &rval, UNDEFINED, np)) + if (check_expr_args(&lval, &rval, UINT64, np)) return (0); valuep->t = UINT64; @@ -717,7 +922,7 @@ eval_expr(struct node *np, struct lut *ex, struct node *epnames[], if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot, arrowp, try, &rval)) return (0); - if (check_expr_args(&lval, &rval, UNDEFINED, np)) + if (check_expr_args(&lval, &rval, UINT64, np)) return (0); valuep->t = UINT64; diff --git a/usr/src/cmd/fm/modules/common/eversholt/fme.c b/usr/src/cmd/fm/modules/common/eversholt/fme.c index 3f2f03a8bb..9da052134d 100644 --- a/usr/src/cmd/fm/modules/common/eversholt/fme.c +++ b/usr/src/cmd/fm/modules/common/eversholt/fme.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * fme.c -- fault management exercise module @@ -57,9 +57,13 @@ /* imported from eft.c... */ extern char *Autoclose; +extern int Dupclose; extern hrtime_t Hesitate; extern nv_alloc_t Eft_nv_hdl; extern int Max_fme; +extern fmd_hdl_t *Hdl; + +static int Istat_need_save; /* fme under construction is global so we can free it on module abort */ static struct fme *Nfmep; @@ -106,7 +110,8 @@ static struct fme { FME_NOTHING = 5000, /* not evaluated yet */ FME_WAIT, /* need to wait for more info */ FME_CREDIBLE, /* suspect list is credible */ - FME_DISPROVED /* no valid suspects found */ + FME_DISPROVED, /* no valid suspects found */ + FME_DEFERRED /* don't know yet (k-count not met) */ } state; unsigned long long pull; /* time passed since created */ @@ -134,8 +139,7 @@ static struct case_list { static void fme_eval(struct fme *fmep, fmd_event_t *ffep); static enum fme_state hypothesise(struct fme *fmep, struct event *ep, - unsigned long long at_latest_by, unsigned long long *pdelay, - struct arrow *arrowp); + unsigned long long at_latest_by, unsigned long long *pdelay); static struct node *eventprop_lookup(struct event *ep, const char *propname); static struct node *pathstring2epnamenp(char *path); static void publish_undiagnosable(fmd_hdl_t *hdl, fmd_event_t *ffep); @@ -466,6 +470,7 @@ reconstitute_observations(struct fme *fmep) pkd = MALLOC(pkdlen); fmd_buf_read(fmep->hdl, fmep->fmcase, tmpbuf, pkd, pkdlen); + ASSERT(ep->nvp == NULL); if (nvlist_xunpack(pkd, pkdlen, &ep->nvp, &Eft_nv_hdl) != 0) out(O_DIE|O_SYS, "pack of observed nvl failed"); @@ -645,6 +650,17 @@ badcase: } } +/*ARGSUSED*/ +static void +globals_destructor(void *left, void *right, void *arg) +{ + struct evalue *evp = (struct evalue *)right; + if (evp->t == NODEPTR) + tree_free((struct node *)evp->v); + evp->v = NULL; + FREE(evp); +} + void destroy_fme(struct fme *f) { @@ -659,6 +675,7 @@ destroy_fme(struct fme *f) itree_free(f->eventtree); config_free(f->cfgdata); + lut_free(f->globals, globals_destructor, NULL); FREE(f); } @@ -670,6 +687,7 @@ fme_state2str(enum fme_state s) case FME_WAIT: return ("WAIT"); case FME_CREDIBLE: return ("CREDIBLE"); case FME_DISPROVED: return ("DISPROVED"); + case FME_DEFERRED: return ("DEFERRED"); default: return ("UNKNOWN"); } } @@ -698,32 +716,6 @@ is_upset(enum nametype t) return (t == N_UPSET); } -/*ARGSUSED*/ -static void -clear_causes_tested(struct event *lhs, struct event *ep, void *arg) -{ - struct bubble *bp; - struct arrowlist *ap; - - for (bp = itree_next_bubble(ep, NULL); bp; - bp = itree_next_bubble(ep, bp)) { - if (bp->t != B_FROM) - continue; - for (ap = itree_next_arrow(bp, NULL); ap; - ap = itree_next_arrow(bp, ap)) - ap->arrowp->causes_tested = 0; - } -} - -/* - * call this function with initcode set to 0 to initialize cycle tracking - */ -static void -initialize_cycles(struct fme *fmep) -{ - lut_walk(fmep->eventtree, (lut_cb)clear_causes_tested, NULL); -} - static void fme_print(int flags, struct fme *fmep) { @@ -786,11 +778,13 @@ pathstring2epnamenp(char *path) * returns true if engine tripped and *enamep and *ippp were filled in. */ static int -serd_eval(fmd_hdl_t *hdl, fmd_event_t *ffep, fmd_case_t *fmcase, - struct event *sp, const char **enamep, const struct ipath **ippp) +serd_eval(struct fme *fmep, fmd_hdl_t *hdl, fmd_event_t *ffep, + fmd_case_t *fmcase, struct event *sp, const char **enamep, + const struct ipath **ippp) { struct node *serdinst; char *serdname; + struct node *nid; ASSERT(sp->t == N_UPSET); ASSERT(ffep != NULL); @@ -807,6 +801,39 @@ serd_eval(fmd_hdl_t *hdl, fmd_event_t *ffep, fmd_case_t *fmcase, serdname = ipath2str(serdinst->u.stmt.np->u.event.ename->u.name.s, ipath(serdinst->u.stmt.np->u.event.epname)); + /* handle serd engine "id" property, if there is one */ + if ((nid = + lut_lookup(serdinst->u.stmt.lutp, (void *)L_id, NULL)) != NULL) { + struct evalue *gval; + char suffixbuf[200]; + char *suffix; + char *nserdname; + size_t nname; + + out(O_ALTFP|O_NONL, "serd \"%s\" id: ", serdname); + ptree_name_iter(O_ALTFP|O_NONL, nid); + + ASSERTinfo(nid->t == T_GLOBID, ptree_nodetype2str(nid->t)); + + if ((gval = lut_lookup(fmep->globals, + (void *)nid->u.globid.s, NULL)) == NULL) { + out(O_ALTFP, " undefined"); + } else if (gval->t == UINT64) { + out(O_ALTFP, " %llu", gval->v); + (void) sprintf(suffixbuf, "%llu", gval->v); + suffix = suffixbuf; + } else { + out(O_ALTFP, " \"%s\"", (char *)gval->v); + suffix = (char *)gval->v; + } + + nname = strlen(serdname) + strlen(suffix) + 2; + nserdname = MALLOC(nname); + (void) snprintf(nserdname, nname, "%s:%s", serdname, suffix); + FREE(serdname); + serdname = nserdname; + } + if (!fmd_serd_exists(hdl, serdname)) { struct node *nN, *nT; @@ -869,13 +896,6 @@ upsets_eval(struct fme *fmep, fmd_event_t *ffep) int ntrip, nupset, i; /* - * we avoid recursion by calling fme_receive_report() at the end of - * this function with a NULL ffep - */ - if (ffep == NULL) - return (0); - - /* * count the number of upsets to determine the upper limit on * expected trip ereport strings. remember that one upset can * lead to at most one ereport. @@ -899,12 +919,12 @@ upsets_eval(struct fme *fmep, fmd_event_t *ffep) ntrip = 0; for (sp = fmep->suspects; sp; sp = sp->suspects) if (sp->t == N_UPSET && - serd_eval(fmep->hdl, ffep, fmep->fmcase, sp, + serd_eval(fmep, fmep->hdl, ffep, fmep->fmcase, sp, &tripped[ntrip].ename, &tripped[ntrip].ipp)) ntrip++; for (i = 0; i < ntrip; i++) - fme_receive_report(fmep->hdl, NULL, + fme_receive_report(fmep->hdl, ffep, tripped[i].ename, tripped[i].ipp, NULL); return (ntrip); @@ -939,6 +959,28 @@ fme_receive_external_report(fmd_hdl_t *hdl, fmd_event_t *ffep, nvlist_t *nvl, fme_receive_report(hdl, ffep, stable(eventstring), ipp, nvl); } +static int mark_arrows(struct fme *fmep, struct event *ep, int mark, + unsigned long long at_latest_by, unsigned long long *pdelay); + +/* ARGSUSED */ +static void +clear_arrows(struct event *ep, struct event *ep2, struct fme *fmep) +{ + struct bubble *bp; + struct arrowlist *ap; + + ep->cached_state = 0; + for (bp = itree_next_bubble(ep, NULL); bp; + bp = itree_next_bubble(ep, bp)) { + if (bp->t != B_FROM) + continue; + bp->mark = 0; + for (ap = itree_next_arrow(bp, NULL); ap; + ap = itree_next_arrow(bp, ap)) + ap->arrowp->mark = 0; + } +} + static void fme_receive_report(fmd_hdl_t *hdl, fmd_event_t *ffep, const char *eventstring, const struct ipath *ipp, nvlist_t *nvl) @@ -959,6 +1001,7 @@ fme_receive_report(fmd_hdl_t *hdl, fmd_event_t *ffep, int prev_verbose; unsigned long long my_delay = TIMEVAL_EVENTUALLY; enum fme_state state; + nvlist_t *pre_peek_nvp = NULL; if (fmep->overflow) { if (!(fmd_case_closed(fmep->hdl, fmep->fmcase))) @@ -979,6 +1022,10 @@ fme_receive_report(fmd_hdl_t *hdl, fmd_event_t *ffep, ep->observations = fmep->observations; fmep->observations = ep; ep->nvp = evnv_dupnvl(nvl); + } else { + /* use new payload values for peek */ + pre_peek_nvp = ep->nvp; + ep->nvp = evnv_dupnvl(nvl); } /* tell hypothesise() not to mess with suspect list */ @@ -989,8 +1036,8 @@ fme_receive_report(fmd_hdl_t *hdl, fmd_event_t *ffep, if (Debug == 0) Verbose = 0; - initialize_cycles(fmep); - state = hypothesise(fmep, fmep->e0, fmep->ull, &my_delay, NULL); + lut_walk(fmep->eventtree, (lut_cb)clear_arrows, (void *)fmep); + state = hypothesise(fmep, fmep->e0, fmep->ull, &my_delay); fmep->peek = 0; @@ -1004,6 +1051,9 @@ fme_receive_report(fmd_hdl_t *hdl, fmd_event_t *ffep, ipath_print(O_ALTFP|O_NONL, eventstring, ipp); out(O_ALTFP, " explained by FME%d]", fmep->id); + if (pre_peek_nvp) + nvlist_free(pre_peek_nvp); + if (ep->count == 1) serialize_observation(fmep, eventstring, ipp); @@ -1024,6 +1074,9 @@ fme_receive_report(fmd_hdl_t *hdl, fmd_event_t *ffep, ep->observations = NULL; nvlist_free(ep->nvp); ep->nvp = NULL; + } else { + nvlist_free(ep->nvp); + ep->nvp = pre_peek_nvp; } } } @@ -1112,6 +1165,10 @@ fme_receive_report(fmd_hdl_t *hdl, fmd_event_t *ffep, fmep->observations = ep; ep->nvp = evnv_dupnvl(nvl); serialize_observation(fmep, eventstring, ipp); + } else { + /* new payload overrides any previous */ + nvlist_free(ep->nvp); + ep->nvp = evnv_dupnvl(nvl); } stats_counter_bump(fmep->Rcount); @@ -1551,6 +1608,264 @@ trim_suspects(struct fme *fmep, boolean_t no_upsets, struct rsl **begin, rsluniq(*begin, *end, &fmep->nsuspects, &fmep->nonfault); } +/* + * addpayloadprop -- add a payload prop to a problem + */ +static void +addpayloadprop(const char *lhs, struct evalue *rhs, nvlist_t *fault) +{ + ASSERT(fault != NULL); + ASSERT(lhs != NULL); + ASSERT(rhs != NULL); + + if (rhs->t == UINT64) { + out(O_ALTFP|O_VERB2, "addpayloadprop: %s=%llu", lhs, rhs->v); + + if (nvlist_add_uint64(fault, lhs, rhs->v) != 0) + out(O_DIE, + "cannot add payloadprop \"%s\" to fault", lhs); + } else { + out(O_ALTFP|O_VERB2, "addpayloadprop: %s=\"%s\"", + lhs, (char *)rhs->v); + + if (nvlist_add_string(fault, lhs, (char *)rhs->v) != 0) + out(O_DIE, + "cannot add payloadprop \"%s\" to fault", lhs); + } +} + +static char *Istatbuf; +static char *Istatbufptr; +static int Istatsz; + +/* + * istataddsize -- calculate size of istat and add it to Istatsz + */ +/*ARGSUSED2*/ +static void +istataddsize(const struct istat_entry *lhs, struct stats *rhs, void *arg) +{ + int val; + + ASSERT(lhs != NULL); + ASSERT(rhs != NULL); + + if ((val = stats_counter_value(rhs)) == 0) + return; /* skip zero-valued stats */ + + /* count up the size of the stat name */ + Istatsz += ipath2strlen(lhs->ename, lhs->ipath); + Istatsz++; /* for the trailing NULL byte */ + + /* count up the size of the stat value */ + Istatsz += snprintf(NULL, 0, "%d", val); + Istatsz++; /* for the trailing NULL byte */ +} + +/* + * istat2str -- serialize an istat, writing result to *Istatbufptr + */ +/*ARGSUSED2*/ +static void +istat2str(const struct istat_entry *lhs, struct stats *rhs, void *arg) +{ + char *str; + int len; + int val; + + ASSERT(lhs != NULL); + ASSERT(rhs != NULL); + + if ((val = stats_counter_value(rhs)) == 0) + return; /* skip zero-valued stats */ + + /* serialize the stat name */ + str = ipath2str(lhs->ename, lhs->ipath); + len = strlen(str); + + ASSERT(Istatbufptr + len + 1 < &Istatbuf[Istatsz]); + (void) strlcpy(Istatbufptr, str, &Istatbuf[Istatsz] - Istatbufptr); + Istatbufptr += len; + FREE(str); + *Istatbufptr++ = '\0'; + + /* serialize the stat value */ + Istatbufptr += snprintf(Istatbufptr, &Istatbuf[Istatsz] - Istatbufptr, + "%d", val); + *Istatbufptr++ = '\0'; + + ASSERT(Istatbufptr <= &Istatbuf[Istatsz]); +} + +void +istat_save() +{ + if (Istat_need_save == 0) + return; + + /* figure out how big the serialzed info is */ + Istatsz = 0; + lut_walk(Istats, (lut_cb)istataddsize, NULL); + + if (Istatsz == 0) { + /* no stats to save */ + fmd_buf_destroy(Hdl, NULL, WOBUF_ISTATS); + return; + } + + /* create the serialized buffer */ + Istatbufptr = Istatbuf = MALLOC(Istatsz); + lut_walk(Istats, (lut_cb)istat2str, NULL); + + /* clear out current saved stats */ + fmd_buf_destroy(Hdl, NULL, WOBUF_ISTATS); + + /* write out the new version */ + fmd_buf_write(Hdl, NULL, WOBUF_ISTATS, Istatbuf, Istatsz); + FREE(Istatbuf); + + Istat_need_save = 0; +} + +int +istat_cmp(struct istat_entry *ent1, struct istat_entry *ent2) +{ + if (ent1->ename != ent2->ename) + return (ent2->ename - ent1->ename); + if (ent1->ipath != ent2->ipath) + return ((char *)ent2->ipath - (char *)ent1->ipath); + + return (0); +} + +/* + * istat-verify -- verify the component associated with a stat still exists + * + * if the component no longer exists, this routine resets the stat and + * returns 0. if the component still exists, it returns 1. + */ +static int +istat_verify(struct node *snp, struct istat_entry *entp) +{ + struct stats *statp; + nvlist_t *fmri; + + fmri = node2fmri(snp->u.event.epname); + if (platform_path_exists(fmri)) { + nvlist_free(fmri); + return (1); + } + nvlist_free(fmri); + + /* component no longer in system. zero out the associated stats */ + if ((statp = (struct stats *) + lut_lookup(Istats, entp, (lut_cmp)istat_cmp)) == NULL || + stats_counter_value(statp) == 0) + return (0); /* stat is already reset */ + + Istat_need_save = 1; + stats_counter_reset(statp); + return (0); +} + +static void +istat_bump(struct node *snp, int n) +{ + struct stats *statp; + struct istat_entry ent; + + ASSERT(snp != NULL); + ASSERTinfo(snp->t == T_EVENT, ptree_nodetype2str(snp->t)); + ASSERT(snp->u.event.epname != NULL); + + /* class name should be hoisted into a single stable entry */ + ASSERT(snp->u.event.ename->u.name.next == NULL); + ent.ename = snp->u.event.ename->u.name.s; + ent.ipath = ipath(snp->u.event.epname); + + if (!istat_verify(snp, &ent)) { + /* component no longer exists in system, nothing to do */ + return; + } + + if ((statp = (struct stats *) + lut_lookup(Istats, &ent, (lut_cmp)istat_cmp)) == NULL) { + /* need to create the counter */ + int cnt = 0; + struct node *np; + char *sname; + char *snamep; + struct istat_entry *newentp; + + /* count up the size of the stat name */ + np = snp->u.event.ename; + while (np != NULL) { + cnt += strlen(np->u.name.s); + cnt++; /* for the '.' or '@' */ + np = np->u.name.next; + } + np = snp->u.event.epname; + while (np != NULL) { + cnt += snprintf(NULL, 0, "%s%llu", + np->u.name.s, np->u.name.child->u.ull); + cnt++; /* for the '/' or trailing NULL byte */ + np = np->u.name.next; + } + + /* build the stat name */ + snamep = sname = alloca(cnt); + np = snp->u.event.ename; + while (np != NULL) { + snamep += snprintf(snamep, &sname[cnt] - snamep, + "%s", np->u.name.s); + np = np->u.name.next; + if (np) + *snamep++ = '.'; + } + *snamep++ = '@'; + np = snp->u.event.epname; + while (np != NULL) { + snamep += snprintf(snamep, &sname[cnt] - snamep, + "%s%llu", np->u.name.s, np->u.name.child->u.ull); + np = np->u.name.next; + if (np) + *snamep++ = '/'; + } + *snamep++ = '\0'; + + /* create the new stat & add it to our list */ + newentp = MALLOC(sizeof (*newentp)); + *newentp = ent; + statp = stats_new_counter(NULL, sname, 0); + Istats = lut_add(Istats, (void *)newentp, (void *)statp, + (lut_cmp)istat_cmp); + } + + /* if n is non-zero, set that value instead of bumping */ + if (n) { + stats_counter_reset(statp); + stats_counter_add(statp, n); + } else + stats_counter_bump(statp); + Istat_need_save = 1; +} + +/*ARGSUSED*/ +static void +istat_destructor(void *left, void *right, void *arg) +{ + struct istat_entry *entp = (struct istat_entry *)left; + struct stats *statp = (struct stats *)right; + FREE(entp); + stats_delete(statp); +} + +void +istat_fini(void) +{ + lut_free(Istats, istat_destructor, NULL); +} + static void publish_suspects(struct fme *fmep) { @@ -1562,8 +1877,11 @@ publish_suspects(struct fme *fmep) uint8_t cert; uint_t *frs; uint_t fravg, frsum, fr; + uint_t messval; + struct node *snp; int frcnt, fridx; boolean_t no_upsets = B_FALSE; + boolean_t allfaulty = B_TRUE; stats_counter_bump(fmep->diags); @@ -1680,6 +1998,8 @@ publish_suspects(struct fme *fmep) for (rp = erl; rp >= srl; rp--) { if (rp->suspect == NULL) continue; + if (!is_fault(rp->suspect->t)) + allfaulty = B_FALSE; if (fmep->nonfault != fmep->nsuspects) cert = percentof(frs[--fridx], frsum); fault = fmd_nvl_create_fault(fmep->hdl, @@ -1690,13 +2010,83 @@ publish_suspects(struct fme *fmep) rp->rsrc); if (fault == NULL) out(O_DIE, "fault creation failed"); + /* if "message" property exists, add it to the fault */ + if (node2uint(eventprop_lookup(rp->suspect, L_message), + &messval) == 0) { + + out(O_ALTFP, + "[FME%d, %s adds message=%d to suspect list]", + fmep->id, + rp->suspect->enode->u.event.ename->u.name.s, + messval); + if (nvlist_add_boolean_value(fault, + FM_SUSPECT_MESSAGE, + (messval) ? B_TRUE : B_FALSE) != 0) { + out(O_DIE, "cannot add no-message to fault"); + } + } + /* add any payload properties */ + lut_walk(rp->suspect->payloadprops, + (lut_cb)addpayloadprop, (void *)fault); fmd_case_add_suspect(fmep->hdl, fmep->fmcase, fault); rp->suspect->fault = fault; rslfree(rp); + /* if "count" property exists, increment the appropriate stat */ + if ((snp = eventprop_lookup(rp->suspect, L_count)) != NULL) { + out(O_ALTFP|O_NONL, + "[FME%d, %s count ", fmep->id, + rp->suspect->enode->u.event.ename->u.name.s); + ptree_name_iter(O_ALTFP|O_NONL, snp); + out(O_ALTFP, "]"); + istat_bump(snp, 0); + } + /* if "action" property exists, evaluate it */ + if ((snp = eventprop_lookup(rp->suspect, L_action)) != NULL) { + struct evalue evalue; + + out(O_ALTFP|O_NONL, + "[FME%d, %s action ", fmep->id, + rp->suspect->enode->u.event.ename->u.name.s); + ptree_name_iter(O_ALTFP|O_NONL, snp); + out(O_ALTFP, "]"); + Action_nvl = fault; + (void) eval_expr(snp, NULL, NULL, NULL, NULL, + NULL, 0, &evalue); + } + /* + * if "dupclose" tunable is set, check if the asru is + * already marked as "faulty". + */ + if (Dupclose && allfaulty) { + nvlist_t *asru; + + out(O_ALTFP|O_VERB, "FMD%d dupclose check ", fmep->id); + itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, rp->suspect); + out(O_ALTFP|O_VERB|O_NONL, " "); + if (nvlist_lookup_nvlist(fault, + FM_FAULT_ASRU, &asru) != 0) { + out(O_ALTFP|O_VERB, "NULL asru"); + allfaulty = B_FALSE; + } else if (fmd_nvl_fmri_faulty(fmep->hdl, asru)) { + out(O_ALTFP|O_VERB, "faulty"); + } else { + out(O_ALTFP|O_VERB, "not faulty"); + allfaulty = B_FALSE; + } + } + + } + if (Dupclose && allfaulty) { + out(O_ALTFP, "[dupclose FME%d, case %s]", fmep->id, + fmd_case_uuid(fmep->hdl, fmep->fmcase)); + fmd_case_close(fmep->hdl, fmep->fmcase); + } else { + out(O_ALTFP, "[solving FME%d, case %s]", fmep->id, + fmd_case_uuid(fmep->hdl, fmep->fmcase)); + fmd_case_solve(fmep->hdl, fmep->fmcase); } - fmd_case_solve(fmep->hdl, fmep->fmcase); - out(O_ALTFP, "[solving FME%d, case %s]", fmep->id, - fmd_case_uuid(fmep->hdl, fmep->fmcase)); + + istat_save(); /* write out any istat changes */ /* * revert to the original suspect list @@ -1837,7 +2227,7 @@ fme_close_case(fmd_hdl_t *hdl, fmd_case_t *fmcase) * If the time we need to wait for the given FME is less than the * current timer, kick that old timer out and establish a new one. */ -static void +static int fme_set_timer(struct fme *fmep, unsigned long long wull) { out(O_ALTFP|O_VERB|O_NONL, " fme_set_timer: request to wait "); @@ -1848,7 +2238,7 @@ fme_set_timer(struct fme *fmep, unsigned long long wull) ptree_timeval(O_ALTFP|O_VERB, &fmep->pull); out(O_ALTFP|O_VERB, NULL); /* we've waited at least wull already, don't need timer */ - return; + return (0); } out(O_ALTFP|O_VERB|O_NONL, " currently "); @@ -1864,15 +2254,25 @@ fme_set_timer(struct fme *fmep, unsigned long long wull) if (fmep->wull != 0) if (wull >= fmep->wull) /* New timer would fire later than established timer */ - return; + return (0); - if (fmep->wull != 0) + if (fmep->wull != 0) { fmd_timer_remove(fmep->hdl, fmep->timer); + if (fmep->timer == fmep->htid) { + out(O_ALTFP, + "[stopped hesitating FME%d, case %s]", + fmep->id, + fmd_case_uuid(fmep->hdl, + fmep->fmcase)); + fmep->htid = 0; + } + } fmep->timer = fmd_timer_install(fmep->hdl, (void *)fmep, fmep->e0r, wull); out(O_ALTFP|O_VERB, "timer set, id is %ld", fmep->timer); fmep->wull = wull; + return (1); } void @@ -1890,14 +2290,19 @@ fme_timer_fired(struct fme *fmep, id_t tid) return; } + out(O_ALTFP, "Timer fired %lx %lx", tid, fmep->htid); if (tid != fmep->htid) { /* - * normal timer (not the hesitation timer + * normal timer (not the hesitation timer) */ fmep->pull = fmep->wull; fmep->wull = 0; fmd_buf_write(fmep->hdl, fmep->fmcase, WOBUF_PULL, (void *)&fmep->pull, sizeof (fmep->pull)); + /* + * no point in heistating if we've already waited. + */ + fmep->hesitated = 1; } else { fmep->hesitated = 1; } @@ -1968,8 +2373,8 @@ fme_eval(struct fme *fmep, fmd_event_t *ffep) out(O_ALTFP|O_VERB, "Evaluate FME %d", fmep->id); indent_set(" "); - initialize_cycles(fmep); - fmep->state = hypothesise(fmep, fmep->e0, fmep->ull, &my_delay, NULL); + lut_walk(fmep->eventtree, (lut_cb)clear_arrows, (void *)fmep); + fmep->state = hypothesise(fmep, fmep->e0, fmep->ull, &my_delay); out(O_ALTFP|O_VERB|O_NONL, "FME%d state: %s, suspect list:", fmep->id, fme_state2str(fmep->state)); @@ -2030,10 +2435,8 @@ fme_eval(struct fme *fmep, fmd_event_t *ffep) ptree_timeval(O_ALTFP|O_NONL, (unsigned long long *)&Hesitate); out(O_ALTFP, "]"); - fme_set_timer(fmep, my_delay); - fmep->htid = - fmd_timer_install(fmep->hdl, - (void *)fmep, NULL, Hesitate); + if (fme_set_timer(fmep, Hesitate)) + fmep->htid = fmep->timer; } else { out(O_ALTFP, "[still hesitating FME%d, case %s]", @@ -2071,7 +2474,7 @@ fme_eval(struct fme *fmep, fmd_event_t *ffep) fmep->state = FME_CREDIBLE; } else { ASSERT(my_delay > fmep->ull); - fme_set_timer(fmep, my_delay); + (void) fme_set_timer(fmep, my_delay); print_suspects(SLWAIT, fmep); } break; @@ -2111,22 +2514,65 @@ fme_eval(struct fme *fmep, fmd_event_t *ffep) } } -/* - * below here is the code derived from the Emrys prototype - */ - static void indent(void); static int triggered(struct fme *fmep, struct event *ep, int mark); -static void mark_arrows(struct fme *fmep, struct event *ep, int mark); static enum fme_state effects_test(struct fme *fmep, - struct event *fault_event); + struct event *fault_event, unsigned long long at_latest_by, + unsigned long long *pdelay); static enum fme_state requirements_test(struct fme *fmep, struct event *ep, - unsigned long long at_latest_by, unsigned long long *pdelay, - struct arrow *arrowp); + unsigned long long at_latest_by, unsigned long long *pdelay); static enum fme_state causes_test(struct fme *fmep, struct event *ep, unsigned long long at_latest_by, unsigned long long *pdelay); static int +checkconstraints(struct fme *fmep, struct arrow *arrowp) +{ + struct constraintlist *ctp; + struct evalue value; + + if (arrowp->forever_false) { + char *sep = ""; + indent(); + out(O_ALTFP|O_VERB|O_NONL, " Forever false constraint: "); + for (ctp = arrowp->constraints; ctp != NULL; ctp = ctp->next) { + out(O_ALTFP|O_VERB|O_NONL, sep); + ptree(O_ALTFP|O_VERB|O_NONL, ctp->cnode, 1, 0); + sep = ", "; + } + out(O_ALTFP|O_VERB, NULL); + return (0); + } + + for (ctp = arrowp->constraints; ctp != NULL; ctp = ctp->next) { + if (eval_expr(ctp->cnode, NULL, NULL, + &fmep->globals, fmep->cfgdata->cooked, + arrowp, 0, &value)) { + /* evaluation successful */ + if (value.t == UNDEFINED || value.v == 0) { + /* known false */ + arrowp->forever_false = 1; + indent(); + out(O_ALTFP|O_VERB|O_NONL, + " False constraint: "); + ptree(O_ALTFP|O_VERB|O_NONL, ctp->cnode, 1, 0); + out(O_ALTFP|O_VERB, NULL); + return (0); + } + } else { + /* evaluation unsuccessful -- unknown value */ + indent(); + out(O_ALTFP|O_VERB|O_NONL, + " Deferred constraint: "); + ptree(O_ALTFP|O_VERB|O_NONL, ctp->cnode, 1, 0); + out(O_ALTFP|O_VERB, NULL); + return (2); + } + } + /* known true */ + return (1); +} + +static int triggered(struct fme *fmep, struct event *ep, int mark) { struct bubble *bp; @@ -2141,7 +2587,7 @@ triggered(struct fme *fmep, struct event *ep, int mark) for (ap = itree_next_arrow(bp, NULL); ap; ap = itree_next_arrow(bp, ap)) { /* check count of marks against K in the bubble */ - if (ap->arrowp->tail->mark == mark && + if ((ap->arrowp->mark & mark) && ++count >= bp->nork) return (1); } @@ -2149,79 +2595,151 @@ triggered(struct fme *fmep, struct event *ep, int mark) return (0); } -static void -mark_arrows(struct fme *fmep, struct event *ep, int mark) +static int +mark_arrows(struct fme *fmep, struct event *ep, int mark, + unsigned long long at_latest_by, unsigned long long *pdelay) { struct bubble *bp; struct arrowlist *ap; + unsigned long long overall_delay = TIMEVAL_EVENTUALLY; + unsigned long long my_delay; + enum fme_state result; + int retval = 0; for (bp = itree_next_bubble(ep, NULL); bp; bp = itree_next_bubble(ep, bp)) { if (bp->t != B_FROM) continue; - if (bp->mark != mark) { - stats_counter_bump(fmep->Marrowcount); - bp->mark = mark; - for (ap = itree_next_arrow(bp, NULL); ap; - ap = itree_next_arrow(bp, ap)) { - struct constraintlist *ctp; - struct evalue value; - int do_not_follow = 0; - /* - * see if false constraint prevents us - * from traversing this arrow, but don't - * bother if the event is an ereport we - * haven't seen - */ - if (ap->arrowp->head->myevent->t != N_EREPORT || - ap->arrowp->head->myevent->count != 0) { - platform_set_payloadnvp( - ap->arrowp->head->myevent->nvp); - for (ctp = ap->arrowp->constraints; - ctp != NULL; ctp = ctp->next) { - if (eval_expr(ctp->cnode, - NULL, NULL, - &fmep->globals, - fmep->cfgdata->cooked, - ap->arrowp, 0, - &value) == 0 || - value.t == UNDEFINED || - value.v == 0) { - do_not_follow = 1; - break; - } - } - platform_set_payloadnvp(NULL); + stats_counter_bump(fmep->Marrowcount); + for (ap = itree_next_arrow(bp, NULL); ap; + ap = itree_next_arrow(bp, ap)) { + struct event *ep2 = ap->arrowp->head->myevent; + /* + * if we're clearing marks, we can avoid doing + * all that work evaluating constraints. + */ + if (mark == 0) { + ap->arrowp->mark &= ~EFFECTS_COUNTER; + ep2->cached_state &= + ~(WAIT_EFFECT|CREDIBLE_EFFECT|PARENT_WAIT); + (void) mark_arrows(fmep, ep2, mark, 0, NULL); + continue; + } + if (ep2->cached_state & REQMNTS_DISPROVED) { + indent(); + out(O_ALTFP|O_VERB|O_NONL, + " ALREADY DISPROVED "); + itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2); + out(O_ALTFP|O_VERB, NULL); + continue; + } + if (ep2->cached_state & WAIT_EFFECT) { + indent(); + out(O_ALTFP|O_VERB|O_NONL, + " ALREADY EFFECTS WAIT "); + itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2); + out(O_ALTFP|O_VERB, NULL); + continue; + } + if (ep2->cached_state & CREDIBLE_EFFECT) { + indent(); + out(O_ALTFP|O_VERB|O_NONL, + " ALREADY EFFECTS CREDIBLE "); + itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2); + out(O_ALTFP|O_VERB, NULL); + continue; + } + if ((ep2->cached_state & PARENT_WAIT) && + (mark & PARENT_WAIT)) { + indent(); + out(O_ALTFP|O_VERB|O_NONL, + " ALREADY PARENT EFFECTS WAIT "); + itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2); + out(O_ALTFP|O_VERB, NULL); + continue; + } + platform_set_payloadnvp(ep2->nvp); + if (checkconstraints(fmep, ap->arrowp) != 1) { + platform_set_payloadnvp(NULL); + indent(); + out(O_ALTFP|O_VERB|O_NONL, + " CONSTRAINTS FAIL "); + itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2); + out(O_ALTFP|O_VERB, NULL); + continue; + } + platform_set_payloadnvp(NULL); + ap->arrowp->mark |= EFFECTS_COUNTER; + if (!triggered(fmep, ep2, EFFECTS_COUNTER)) { + indent(); + out(O_ALTFP|O_VERB|O_NONL, + " K-COUNT NOT YET MET "); + itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2); + out(O_ALTFP|O_VERB, NULL); + continue; + } + ep2->cached_state &= ~PARENT_WAIT; + result = requirements_test(fmep, ep2, at_latest_by + + ap->arrowp->maxdelay, + &my_delay); + if (result == FME_WAIT) { + retval = WAIT_EFFECT; + if (overall_delay > my_delay) + overall_delay = my_delay; + ep2->cached_state |= WAIT_EFFECT; + indent(); + out(O_ALTFP|O_VERB|O_NONL, " EFFECTS WAIT "); + itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2); + out(O_ALTFP|O_VERB, NULL); + indent_push(" E"); + if (mark_arrows(fmep, ep2, PARENT_WAIT, + at_latest_by, &my_delay) == WAIT_EFFECT) { + retval = WAIT_EFFECT; + if (overall_delay > my_delay) + overall_delay = my_delay; } - - if (do_not_follow) { - indent(); + indent_pop(); + } else if (result == FME_DISPROVED) { + indent(); + out(O_ALTFP|O_VERB|O_NONL, + " EFFECTS DISPROVED "); + itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2); + out(O_ALTFP|O_VERB, NULL); + } else { + ep2->cached_state |= mark; + indent(); + if (mark == CREDIBLE_EFFECT) out(O_ALTFP|O_VERB|O_NONL, - " False arrow to "); - itree_pevent_brief( - O_ALTFP|O_VERB|O_NONL, - ap->arrowp->head->myevent); - out(O_ALTFP|O_VERB|O_NONL, " "); - ptree(O_ALTFP|O_VERB|O_NONL, - ctp->cnode, 1, 0); - out(O_ALTFP|O_VERB, NULL); - continue; + " EFFECTS CREDIBLE "); + else + out(O_ALTFP|O_VERB|O_NONL, + " PARENT EFFECTS WAIT "); + itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2); + out(O_ALTFP|O_VERB, NULL); + indent_push(" E"); + if (mark_arrows(fmep, ep2, mark, at_latest_by, + &my_delay) == WAIT_EFFECT) { + retval = WAIT_EFFECT; + if (overall_delay > my_delay) + overall_delay = my_delay; } - - if (triggered(fmep, ap->arrowp->head->myevent, - mark)) - mark_arrows(fmep, - ap->arrowp->head->myevent, mark); + indent_pop(); } } } + if (retval == WAIT_EFFECT) + *pdelay = overall_delay; + return (retval); } static enum fme_state -effects_test(struct fme *fmep, struct event *fault_event) +effects_test(struct fme *fmep, struct event *fault_event, + unsigned long long at_latest_by, unsigned long long *pdelay) { struct event *error_event; enum fme_state return_value = FME_CREDIBLE; + unsigned long long overall_delay = TIMEVAL_EVENTUALLY; + unsigned long long my_delay; stats_counter_bump(fmep->Ecallcount); indent_push(" E"); @@ -2230,13 +2748,22 @@ effects_test(struct fme *fmep, struct event *fault_event) itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, fault_event); out(O_ALTFP|O_VERB, NULL); - mark_arrows(fmep, fault_event, 1); + (void) mark_arrows(fmep, fault_event, CREDIBLE_EFFECT, at_latest_by, + &my_delay); for (error_event = fmep->observations; error_event; error_event = error_event->observations) { indent(); out(O_ALTFP|O_VERB|O_NONL, " "); itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, error_event); - if (!triggered(fmep, error_event, 1)) { + if (!(error_event->cached_state & CREDIBLE_EFFECT)) { + if (error_event->cached_state & + (PARENT_WAIT|WAIT_EFFECT)) { + return_value = FME_WAIT; + if (overall_delay > my_delay) + overall_delay = my_delay; + out(O_ALTFP|O_VERB, " NOT YET triggered"); + continue; + } return_value = FME_DISPROVED; out(O_ALTFP|O_VERB, " NOT triggered"); break; @@ -2244,23 +2771,26 @@ effects_test(struct fme *fmep, struct event *fault_event) out(O_ALTFP|O_VERB, " triggered"); } } - mark_arrows(fmep, fault_event, 0); + (void) mark_arrows(fmep, fault_event, 0, 0, NULL); indent(); - out(O_ALTFP|O_VERB|O_NONL, "<-%s ", fme_state2str(return_value)); + out(O_ALTFP|O_VERB|O_NONL, "<-EFFECTS %s ", + fme_state2str(return_value)); itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, fault_event); out(O_ALTFP|O_VERB, NULL); indent_pop(); + if (return_value == FME_WAIT) + *pdelay = overall_delay; return (return_value); } static enum fme_state requirements_test(struct fme *fmep, struct event *ep, - unsigned long long at_latest_by, unsigned long long *pdelay, - struct arrow *arrowp) + unsigned long long at_latest_by, unsigned long long *pdelay) { int waiting_events; int credible_events; + int deferred_events; enum fme_state return_value = FME_CREDIBLE; unsigned long long overall_delay = TIMEVAL_EVENTUALLY; unsigned long long arrow_delay; @@ -2269,6 +2799,30 @@ requirements_test(struct fme *fmep, struct event *ep, struct bubble *bp; struct arrowlist *ap; + if (ep->cached_state & REQMNTS_CREDIBLE) { + indent(); + out(O_ALTFP|O_VERB|O_NONL, " REQMNTS ALREADY CREDIBLE "); + itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); + out(O_ALTFP|O_VERB, NULL); + return (FME_CREDIBLE); + } + if (ep->cached_state & REQMNTS_DISPROVED) { + indent(); + out(O_ALTFP|O_VERB|O_NONL, " REQMNTS ALREADY DISPROVED "); + itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); + out(O_ALTFP|O_VERB, NULL); + return (FME_DISPROVED); + } + if (ep->cached_state & REQMNTS_WAIT) { + indent(); + *pdelay = ep->cached_delay; + out(O_ALTFP|O_VERB|O_NONL, " REQMNTS ALREADY WAIT "); + itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); + out(O_ALTFP|O_VERB|O_NONL, ", wait for: "); + ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by); + out(O_ALTFP|O_VERB, NULL); + return (FME_WAIT); + } stats_counter_bump(fmep->Rcallcount); indent_push(" R"); indent(); @@ -2283,49 +2837,26 @@ requirements_test(struct fme *fmep, struct event *ep, if (fmep->pull >= at_latest_by) { return_value = FME_DISPROVED; } else { - *pdelay = at_latest_by; + ep->cached_delay = *pdelay = at_latest_by; return_value = FME_WAIT; } - } else if (arrowp != NULL) { - /* - * evaluate constraints only for current observation - */ - struct constraintlist *ctp; - struct evalue value; - - platform_set_payloadnvp(ep->nvp); - for (ctp = arrowp->constraints; ctp != NULL; - ctp = ctp->next) { - if (eval_expr(ctp->cnode, NULL, NULL, - &fmep->globals, fmep->cfgdata->cooked, - arrowp, 0, &value) == 0 || - value.t == UNDEFINED || value.v == 0) { - indent(); - out(O_ALTFP|O_VERB|O_NONL, - " False constraint "); - out(O_ALTFP|O_VERB|O_NONL, " "); - ptree(O_ALTFP|O_VERB|O_NONL, - ctp->cnode, 1, 0); - out(O_ALTFP|O_VERB, NULL); - return_value = FME_DISPROVED; - break; - } - } - platform_set_payloadnvp(NULL); } indent(); switch (return_value) { case FME_CREDIBLE: - out(O_ALTFP|O_VERB|O_NONL, "<-CREDIBLE "); + ep->cached_state |= REQMNTS_CREDIBLE; + out(O_ALTFP|O_VERB|O_NONL, "<-REQMNTS CREDIBLE "); itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); break; case FME_DISPROVED: - out(O_ALTFP|O_VERB|O_NONL, "<-DISPROVED "); + ep->cached_state |= REQMNTS_DISPROVED; + out(O_ALTFP|O_VERB|O_NONL, "<-REQMNTS DISPROVED "); itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); break; case FME_WAIT: - out(O_ALTFP|O_VERB|O_NONL, "<-WAIT "); + ep->cached_state |= REQMNTS_WAIT; + out(O_ALTFP|O_VERB|O_NONL, "<-REQMNTS WAIT "); itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); out(O_ALTFP|O_VERB|O_NONL, " to "); ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by); @@ -2343,124 +2874,129 @@ requirements_test(struct fme *fmep, struct event *ep, /* this event is not a report, descend the tree */ for (bp = itree_next_bubble(ep, NULL); bp; bp = itree_next_bubble(ep, bp)) { + int n; + if (bp->t != B_FROM) continue; - if (bp->mark == 0) { - int n = bp->nork; - bp->mark = 1; - credible_events = 0; - waiting_events = 0; - arrow_delay = TIMEVAL_EVENTUALLY; - /* - * n is -1 for 'A' so adjust it. - * XXX just count up the arrows for now. - */ - if (n < 0) { - n = 0; - for (ap = itree_next_arrow(bp, NULL); ap; - ap = itree_next_arrow(bp, ap)) - n++; - indent(); - out(O_ALTFP|O_VERB, " Bubble Counted N=%d", n); - } else { - indent(); - out(O_ALTFP|O_VERB, " Bubble N=%d", n); - } + n = bp->nork; + + credible_events = 0; + waiting_events = 0; + deferred_events = 0; + arrow_delay = TIMEVAL_EVENTUALLY; + /* + * n is -1 for 'A' so adjust it. + * XXX just count up the arrows for now. + */ + if (n < 0) { + n = 0; + for (ap = itree_next_arrow(bp, NULL); ap; + ap = itree_next_arrow(bp, ap)) + n++; + indent(); + out(O_ALTFP|O_VERB, " Bubble Counted N=%d", n); + } else { + indent(); + out(O_ALTFP|O_VERB, " Bubble N=%d", n); + } + if (n == 0) + continue; + if (!(bp->mark & (BUBBLE_ELIDED|BUBBLE_OK))) { for (ap = itree_next_arrow(bp, NULL); ap; ap = itree_next_arrow(bp, ap)) { ep2 = ap->arrowp->head->myevent; - if (n <= credible_events) + platform_set_payloadnvp(ep2->nvp); + if (checkconstraints(fmep, ap->arrowp) == 0) { + /* + * if any arrow is invalidated by the + * constraints, then we should elide the + * whole bubble to be consistant with + * the tree creation time behaviour + */ + bp->mark |= BUBBLE_ELIDED; + platform_set_payloadnvp(NULL); break; + } + platform_set_payloadnvp(NULL); + } + } + if (bp->mark & BUBBLE_ELIDED) + continue; + bp->mark |= BUBBLE_OK; + for (ap = itree_next_arrow(bp, NULL); ap; + ap = itree_next_arrow(bp, ap)) { + ep2 = ap->arrowp->head->myevent; + if (n <= credible_events) + break; - if (triggered(fmep, ep2, 1)) - /* XXX adding max timevals! */ - switch (requirements_test(fmep, ep2, - at_latest_by + ap->arrowp->maxdelay, - &my_delay, ap->arrowp)) { - case FME_CREDIBLE: - credible_events++; - break; - case FME_DISPROVED: - break; - case FME_WAIT: - if (my_delay < arrow_delay) - arrow_delay = my_delay; - waiting_events++; - break; - default: - out(O_DIE, - "Bug in requirements_test."); - } - else + ap->arrowp->mark |= REQMNTS_COUNTER; + if (triggered(fmep, ep2, REQMNTS_COUNTER)) + /* XXX adding max timevals! */ + switch (requirements_test(fmep, ep2, + at_latest_by + ap->arrowp->maxdelay, + &my_delay)) { + case FME_DEFERRED: + deferred_events++; + break; + case FME_CREDIBLE: credible_events++; - } - indent(); - out(O_ALTFP|O_VERB, " Credible: %d Waiting %d", - credible_events, waiting_events); - if (credible_events + waiting_events < n) { - /* Can never meet requirements */ - indent(); - out(O_ALTFP|O_VERB|O_NONL, "<-DISPROVED "); - itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); - out(O_ALTFP|O_VERB, NULL); - indent_pop(); - return (FME_DISPROVED); - } - if (credible_events < n) { /* will have to wait */ - /* wait time is shortest known */ - if (arrow_delay < overall_delay) - overall_delay = arrow_delay; - return_value = FME_WAIT; - } - } else { + break; + case FME_DISPROVED: + break; + case FME_WAIT: + if (my_delay < arrow_delay) + arrow_delay = my_delay; + waiting_events++; + break; + default: + out(O_DIE, + "Bug in requirements_test."); + } + else + deferred_events++; + } + indent(); + out(O_ALTFP|O_VERB, " Credible: %d Waiting %d", + credible_events + deferred_events, waiting_events); + if (credible_events + deferred_events + waiting_events < n) { + /* Can never meet requirements */ + ep->cached_state |= REQMNTS_DISPROVED; indent(); - out(O_ALTFP|O_VERB|O_NONL, " Mark was set: "); + out(O_ALTFP|O_VERB|O_NONL, "<-REQMNTS DISPROVED "); itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); - out(O_ALTFP|O_VERB|O_NONL, " to"); - for (ap = itree_next_arrow(bp, NULL); ap; - ap = itree_next_arrow(bp, ap)) { - out(O_ALTFP|O_VERB|O_NONL, " "); - itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, - ap->arrowp->head->myevent); - } out(O_ALTFP|O_VERB, NULL); + indent_pop(); + return (FME_DISPROVED); + } + if (credible_events + deferred_events < n) { + /* will have to wait */ + /* wait time is shortest known */ + if (arrow_delay < overall_delay) + overall_delay = arrow_delay; + return_value = FME_WAIT; + } else if (credible_events < n) { + if (return_value != FME_WAIT) + return_value = FME_DEFERRED; } } /* - * evaluate constraints for ctlist, which is the list of - * constraints for the arrow pointing into this node of the tree + * don't mark as FME_DEFERRED. If this event isn't reached by another + * path, then this will be considered FME_CREDIBLE. But if it is + * reached by a different path so the K-count is met, then might + * get overridden by FME_WAIT or FME_DISPROVED. */ - if (return_value == FME_CREDIBLE && arrowp != NULL) { - struct constraintlist *ctp; - struct evalue value; - - platform_set_payloadnvp(ep->nvp); - for (ctp = arrowp->constraints; ctp != NULL; - ctp = ctp->next) { - if (eval_expr(ctp->cnode, NULL, NULL, &fmep->globals, - fmep->cfgdata->cooked, arrowp, 0, &value) == 0 || - value.t == UNDEFINED || value.v == 0) { - indent(); - out(O_ALTFP|O_VERB|O_NONL, - " False constraint "); - out(O_ALTFP|O_VERB|O_NONL, " "); - ptree(O_ALTFP|O_VERB|O_NONL, - ctp->cnode, 1, 0); - out(O_ALTFP|O_VERB, NULL); - return_value = FME_DISPROVED; - break; - } - } - platform_set_payloadnvp(NULL); + if (return_value == FME_WAIT) { + ep->cached_state |= REQMNTS_WAIT; + ep->cached_delay = *pdelay = overall_delay; + } else if (return_value == FME_CREDIBLE) { + ep->cached_state |= REQMNTS_CREDIBLE; } - - if (return_value == FME_WAIT) - *pdelay = overall_delay; indent(); - out(O_ALTFP|O_VERB|O_NONL, "<-%s ", fme_state2str(return_value)); + out(O_ALTFP|O_VERB|O_NONL, "<-REQMNTS %s ", + fme_state2str(return_value)); itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); out(O_ALTFP|O_VERB, NULL); indent_pop(); @@ -2495,27 +3031,30 @@ causes_test(struct fme *fmep, struct event *ep, k = bp->nork; /* remember the K value */ for (ap = itree_next_arrow(bp, NULL); ap; ap = itree_next_arrow(bp, ap)) { - struct constraintlist *ctp; - struct evalue value; int do_not_follow = 0; + + /* + * if we get to the same event multiple times + * only worry about the first one. + */ + if (ap->arrowp->tail->myevent->cached_state & + CAUSES_TESTED) { + indent(); + out(O_ALTFP|O_VERB|O_NONL, + " causes test already run for "); + itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, + ap->arrowp->tail->myevent); + out(O_ALTFP|O_VERB, NULL); + continue; + } + /* * see if false constraint prevents us * from traversing this arrow */ platform_set_payloadnvp(ep->nvp); - for (ctp = ap->arrowp->constraints; - ctp != NULL; ctp = ctp->next) { - if (eval_expr(ctp->cnode, NULL, NULL, - &fmep->globals, - fmep->cfgdata->cooked, - ap->arrowp, 0, - &value) == 0 || - value.t == UNDEFINED || - value.v == 0) { - do_not_follow = 1; - break; - } - } + if (checkconstraints(fmep, ap->arrowp) != 1) + do_not_follow = 1; platform_set_payloadnvp(NULL); if (do_not_follow) { indent(); @@ -2523,32 +3062,15 @@ causes_test(struct fme *fmep, struct event *ep, " False arrow from "); itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ap->arrowp->tail->myevent); - out(O_ALTFP|O_VERB|O_NONL, " "); - ptree(O_ALTFP|O_VERB|O_NONL, ctp->cnode, 1, 0); out(O_ALTFP|O_VERB, NULL); continue; } - if (ap->arrowp->causes_tested++ > 0) { - /* - * get to this point if this is not the - * first time we're going through this - * arrow in the causes test. consider this - * branch to be credible and let the - * credible/noncredible outcome depend on - * the other branches in this cycle. - */ - fstate = FME_CREDIBLE; - } else { - /* - * get to this point if this is the first - * time we're going through this arrow. - */ - tail_event = ap->arrowp->tail->myevent; - fstate = hypothesise(fmep, tail_event, - at_latest_by, - &my_delay, ap->arrowp); - } + ap->arrowp->tail->myevent->cached_state |= + CAUSES_TESTED; + tail_event = ap->arrowp->tail->myevent; + fstate = hypothesise(fmep, tail_event, at_latest_by, + &my_delay); switch (fstate) { case FME_WAIT: @@ -2564,15 +3086,12 @@ causes_test(struct fme *fmep, struct event *ep, default: out(O_DIE, "Bug in causes_test"); } - - ap->arrowp->causes_tested--; - ASSERT(ap->arrowp->causes_tested >= 0); } } /* compare against K */ if (credible_results + waiting_results < k) { indent(); - out(O_ALTFP|O_VERB|O_NONL, "<-DISPROVED "); + out(O_ALTFP|O_VERB|O_NONL, "<-CAUSES DISPROVED "); itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); out(O_ALTFP|O_VERB, NULL); indent_pop(); @@ -2581,7 +3100,7 @@ causes_test(struct fme *fmep, struct event *ep, if (waiting_results != 0) { *pdelay = overall_delay; indent(); - out(O_ALTFP|O_VERB|O_NONL, "<-WAIT "); + out(O_ALTFP|O_VERB|O_NONL, "<-CAUSES WAIT "); itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); out(O_ALTFP|O_VERB|O_NONL, " to "); ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by); @@ -2590,7 +3109,7 @@ causes_test(struct fme *fmep, struct event *ep, return (FME_WAIT); } indent(); - out(O_ALTFP|O_VERB|O_NONL, "<-CREDIBLE "); + out(O_ALTFP|O_VERB|O_NONL, "<-CAUSES CREDIBLE "); itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); out(O_ALTFP|O_VERB, NULL); indent_pop(); @@ -2599,8 +3118,7 @@ causes_test(struct fme *fmep, struct event *ep, static enum fme_state hypothesise(struct fme *fmep, struct event *ep, - unsigned long long at_latest_by, unsigned long long *pdelay, - struct arrow *arrowp) + unsigned long long at_latest_by, unsigned long long *pdelay) { enum fme_state rtr, otr; unsigned long long my_delay; @@ -2615,13 +3133,12 @@ hypothesise(struct fme *fmep, struct event *ep, ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by); out(O_ALTFP|O_VERB, NULL); - rtr = requirements_test(fmep, ep, at_latest_by, &my_delay, arrowp); - mark_arrows(fmep, ep, 0); /* clean up after requirements test */ + rtr = requirements_test(fmep, ep, at_latest_by, &my_delay); if ((rtr == FME_WAIT) && (my_delay < overall_delay)) overall_delay = my_delay; if (rtr != FME_DISPROVED) { if (is_problem(ep->t)) { - otr = effects_test(fmep, ep); + otr = effects_test(fmep, ep, at_latest_by, &my_delay); if (otr != FME_DISPROVED) { if (fmep->peek == 0 && ep->is_suspect++ == 0) { ep->suspects = fmep->suspects; @@ -2680,3 +3197,72 @@ hypothesise(struct fme *fmep, struct event *ep, indent_pop(); return (FME_CREDIBLE); } + +/* + * fme_istat_load -- reconstitute any persistent istats + */ +void +fme_istat_load(fmd_hdl_t *hdl) +{ + int sz; + char *sbuf; + char *ptr; + + if ((sz = fmd_buf_size(hdl, NULL, WOBUF_ISTATS)) == 0) { + out(O_ALTFP, "fme_istat_load: No stats"); + return; + } + + sbuf = alloca(sz); + + fmd_buf_read(hdl, NULL, WOBUF_ISTATS, sbuf, sz); + + /* + * pick apart the serialized stats + * + * format is: + * <class-name>, '@', <path>, '\0', <value>, '\0' + * for example: + * "stat.first@stat0/path0\02\0stat.second@stat0/path1\023\0" + * + * since this is parsing our own serialized data, any parsing issues + * are fatal, so we check for them all with ASSERT() below. + */ + ptr = sbuf; + while (ptr < &sbuf[sz]) { + char *sepptr; + struct node *np; + int val; + + sepptr = strchr(ptr, '@'); + ASSERT(sepptr != NULL); + *sepptr = '\0'; + + /* construct the event */ + np = newnode(T_EVENT, NULL, 0); + np->u.event.ename = newnode(T_NAME, NULL, 0); + np->u.event.ename->u.name.t = N_STAT; + np->u.event.ename->u.name.s = stable(ptr); + np->u.event.ename->u.name.it = IT_ENAME; + np->u.event.ename->u.name.last = np->u.event.ename; + + ptr = sepptr + 1; + ASSERT(ptr < &sbuf[sz]); + ptr += strlen(ptr); + ptr++; /* move past the '\0' separating path from value */ + ASSERT(ptr < &sbuf[sz]); + ASSERT(isdigit(*ptr)); + val = atoi(ptr); + ASSERT(val > 0); + ptr += strlen(ptr); + ptr++; /* move past the final '\0' for this entry */ + + np->u.event.epname = pathstring2epnamenp(sepptr + 1); + ASSERT(np->u.event.epname != NULL); + + istat_bump(np, val); + tree_free(np); + } + + istat_save(); +} diff --git a/usr/src/cmd/fm/modules/common/eversholt/fme.h b/usr/src/cmd/fm/modules/common/eversholt/fme.h index 36a5f88aa7..8b7c21f13a 100644 --- a/usr/src/cmd/fm/modules/common/eversholt/fme.h +++ b/usr/src/cmd/fm/modules/common/eversholt/fme.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * fme.h -- public definitions for fme module @@ -63,16 +63,27 @@ extern "C" { #define WOBUF_PULL "timewaited" #define WOBUF_CFG "rawcfgdata" #define WOBUF_ID "fmeid" +#define WOBUF_ISTATS "istats" + +struct lut *Istats; /* instanced stats a la "count=" */ struct fme; void fme_receive_external_report(fmd_hdl_t *hdl, fmd_event_t *ffep, nvlist_t *nvl, const char *eventstring); void fme_restart(fmd_hdl_t *hdl, fmd_case_t *inprogress); +void fme_istat_load(fmd_hdl_t *hdl); void fme_close_case(fmd_hdl_t *hdl, fmd_case_t *fmcase); void fme_timer_fired(struct fme *, id_t); void fme_status(int flags); void fme_fini(void); +void istat_fini(void); + +struct istat_entry { + const char *ename; + const struct ipath *ipath; +}; +int istat_cmp(struct istat_entry *ent1, struct istat_entry *ent2); #ifdef __cplusplus } diff --git a/usr/src/cmd/fm/modules/common/eversholt/iexpr.c b/usr/src/cmd/fm/modules/common/eversholt/iexpr.c new file mode 100644 index 0000000000..2493516d84 --- /dev/null +++ b/usr/src/cmd/fm/modules/common/eversholt/iexpr.c @@ -0,0 +1,290 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * iexpr.c -- instanced expression cache module + * + * this module provides a cache of fully instantized expressions. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <string.h> +#include "alloc.h" +#include "out.h" +#include "lut.h" +#include "tree.h" +#include "ptree.h" +#include "itree.h" +#include "ipath.h" +#include "iexpr.h" +#include "stats.h" +#include "eval.h" +#include "config.h" + +#define IEXPRSZ 1024 /* hash table size */ + +static struct stats *Niexpr; + +/* the cache is a hash table of these structs */ +static struct iexpr { + struct node *np; + struct iexpr *next; /* next entry in hash bucket */ +} *Cache[IEXPRSZ]; + +/* + * iexpr_init -- initialize the iexpr module + */ +void +iexpr_init(void) +{ + Niexpr = stats_new_counter("iexpr.niexpr", "iexpr cache entries", 1); +} + +/* + * iexpr_hash -- produce a simple hash from an instanced expression tree + */ +static unsigned +iexpr_hash(struct node *np) +{ + if (np == NULL) + return (1); + + switch (np->t) { + case T_GLOBID: + return ((int)np->u.globid.s); + + case T_ASSIGN: + case T_CONDIF: + case T_CONDELSE: + case T_NE: + case T_EQ: + case T_LT: + case T_LE: + case T_GT: + case T_GE: + case T_BITAND: + case T_BITOR: + case T_BITXOR: + case T_BITNOT: + case T_LSHIFT: + case T_RSHIFT: + case T_LIST: + case T_AND: + case T_OR: + case T_NOT: + case T_ADD: + case T_SUB: + case T_MUL: + case T_DIV: + case T_MOD: + return ((int)np->t * + (iexpr_hash(np->u.expr.left) + + iexpr_hash(np->u.expr.right))); + + case T_NAME: + return ((int)np->u.name.s); + + case T_EVENT: + return (iexpr_hash(np->u.event.ename) + + iexpr_hash(np->u.event.epname)); + + case T_FUNC: + return ((int)np->u.func.s + + iexpr_hash(np->u.func.arglist)); + + case T_QUOTE: + return ((int)np->u.quote.s); + + case T_NUM: + return ((int)np->u.ull); + + default: + outfl(O_DIE, np->file, np->line, + "iexpr_hash: unexpected node type: %s", + ptree_nodetype2str(np->t)); + } + /*NOTREACHED*/ +} + +/* + * iexpr_cmp -- compare two instanced expression trees + */ +static int +iexpr_cmp(struct node *np1, struct node *np2) +{ + int diff; + + if (np1 == np2) + return (0); + + if (np1 == NULL) + return (1); + + if (np2 == NULL) + return (-1); + + if (np1->t != np2->t) + return (np2->t - np1->t); + + /* types match, need to see additional info matches */ + switch (np1->t) { + case T_GLOBID: + return (np2->u.globid.s - np1->u.globid.s); + + case T_ASSIGN: + case T_CONDIF: + case T_CONDELSE: + case T_NE: + case T_EQ: + case T_LT: + case T_LE: + case T_GT: + case T_GE: + case T_BITAND: + case T_BITOR: + case T_BITXOR: + case T_BITNOT: + case T_LSHIFT: + case T_RSHIFT: + case T_LIST: + case T_AND: + case T_OR: + case T_NOT: + case T_ADD: + case T_SUB: + case T_MUL: + case T_DIV: + case T_MOD: + diff = iexpr_cmp(np1->u.expr.left, np2->u.expr.left); + if (diff != 0) + return (diff); + return (iexpr_cmp(np1->u.expr.right, np2->u.expr.right)); + + case T_NAME: + if (np2->u.name.s != np1->u.name.s) + return (np2->u.name.s - np1->u.name.s); + diff = iexpr_cmp(np1->u.name.child, np2->u.name.child); + if (diff != 0) + return (diff); + return (iexpr_cmp(np1->u.name.next, np2->u.name.next)); + + case T_EVENT: + diff = iexpr_cmp(np1->u.event.ename, np2->u.event.ename); + if (diff != 0) + return (diff); + return (iexpr_cmp(np1->u.event.epname, np2->u.event.epname)); + + case T_FUNC: + if (np1->u.func.s != np2->u.func.s) + return (np2->u.func.s - np1->u.func.s); + return (iexpr_cmp(np1->u.func.arglist, np2->u.func.arglist)); + + case T_QUOTE: + return (np2->u.quote.s - np1->u.quote.s); + + case T_NUM: + if (np2->u.ull > np1->u.ull) + return (1); + else if (np1->u.ull > np2->u.ull) + return (-1); + else + return (0); + + default: + outfl(O_DIE, np1->file, np1->line, + "iexpr_cmp: unexpected node type: %s", + ptree_nodetype2str(np1->t)); + } + /*NOTREACHED*/ +} + +/* + * iexpr -- find instanced expr in cache, or add it if necessary + */ +struct node * +iexpr(struct node *np) +{ + unsigned idx = iexpr_hash(np) % IEXPRSZ; + struct iexpr *bucketp = Cache[idx]; + struct iexpr *cp; + + /* search cache */ + for (cp = bucketp; cp != NULL; cp = cp->next) + if (iexpr_cmp(cp->np, np) == 0) { + /* found it */ + tree_free(np); + return (cp->np); + } + + /* allocate new cache entry */ + cp = MALLOC(sizeof (*cp)); + cp->np = np; + cp->next = bucketp; + Cache[idx] = cp; + + stats_counter_bump(Niexpr); + + return (np); +} + +/* + * iexpr_cached -- return true if np is in the iexpr cache + */ +int +iexpr_cached(struct node *np) +{ + struct iexpr *cp = Cache[iexpr_hash(np) % IEXPRSZ]; + + /* search cache */ + for (; cp != NULL; cp = cp->next) + if (iexpr_cmp(cp->np, np) == 0) { + /* found it */ + return (1); + } + + return (0); +} + +/* + * iexpr_fini -- free the iexpr cache + */ +void +iexpr_fini(void) +{ + int i; + + for (i = 0; i < IEXPRSZ; i++) { + struct iexpr *cp; + struct iexpr *ncp; + + for (cp = Cache[i]; cp != NULL; cp = ncp) { + tree_free(cp->np); + ncp = cp->next; + FREE(cp); + } + Cache[i] = NULL; + } +} diff --git a/usr/src/cmd/fm/modules/common/eversholt/iexpr.h b/usr/src/cmd/fm/modules/common/eversholt/iexpr.h new file mode 100644 index 0000000000..7dc5cf175c --- /dev/null +++ b/usr/src/cmd/fm/modules/common/eversholt/iexpr.h @@ -0,0 +1,48 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * iexpr.h -- public definitions for iexpr module + * + */ + +#ifndef _EFT_IEXPR_H +#define _EFT_IEXPR_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +void iexpr_init(void); +struct node *iexpr(struct node *np); +int iexpr_cached(struct node *np); +void iexpr_fini(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _EFT_IEXPR_H */ diff --git a/usr/src/cmd/fm/modules/common/eversholt/ipath.c b/usr/src/cmd/fm/modules/common/eversholt/ipath.c index e80be26011..9f776bc5a9 100644 --- a/usr/src/cmd/fm/modules/common/eversholt/ipath.c +++ b/usr/src/cmd/fm/modules/common/eversholt/ipath.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * ipath.c -- instanced pathname module @@ -265,6 +265,35 @@ ipath2str(const char *ename, const struct ipath *ipp) } /* + * ipath2strlen -- calculate the len of what ipath2str() would return + */ +size_t +ipath2strlen(const char *ename, const struct ipath *ipp) +{ + int i; + size_t len = 0; + + /* count up length of class string */ + if (ename != NULL) + len += strlen(ename); + + /* count up length of path string, including slash separators */ + if (ipp != NULL) { + for (i = 0; ipp[i].s != NULL; i++) { + /* add slash separator, but no leading slash */ + if (i != 0) + len++; + len += snprintf(NULL, 0, "%s%d", ipp[i].s, ipp[i].i); + } + } + + if (ename != NULL && ipp != NULL) + len++; /* room for '@' */ + + return (len); +} + +/* * ipath_print -- print out an ename, ipath, or both with '@' between them */ void diff --git a/usr/src/cmd/fm/modules/common/eversholt/ipath.h b/usr/src/cmd/fm/modules/common/eversholt/ipath.h index 17d7c4e9df..2112c12661 100644 --- a/usr/src/cmd/fm/modules/common/eversholt/ipath.h +++ b/usr/src/cmd/fm/modules/common/eversholt/ipath.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * ipath.h -- public definitions for ipath module @@ -39,6 +39,7 @@ extern "C" { void ipath_init(void); const struct ipath *ipath(struct node *np); char *ipath2str(const char *ename, const struct ipath *ipp); +size_t ipath2strlen(const char *ename, const struct ipath *ipp); void ipath_print(int flags, const char *ename, const struct ipath *ipp); void ipath_fini(void); diff --git a/usr/src/cmd/fm/modules/common/eversholt/itree.c b/usr/src/cmd/fm/modules/common/eversholt/itree.c index 63bf01f08f..ff3ebdcbd8 100644 --- a/usr/src/cmd/fm/modules/common/eversholt/itree.c +++ b/usr/src/cmd/fm/modules/common/eversholt/itree.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * itree.c -- instance tree creation and manipulation @@ -43,6 +43,7 @@ #include "ptree.h" #include "itree.h" #include "ipath.h" +#include "iexpr.h" #include "eval.h" #include "config.h" @@ -438,8 +439,17 @@ nv_instantiate(void *name, void *val, void *arg) nrhs = tevent_dup_to_epname(orhs, pd->epname); pd->props = lut_add(pd->props, name, nrhs, NULL); break; + case T_GLOBID: + nrhs = newnode(T_GLOBID, orhs->file, orhs->line); + nrhs->u.globid.s = orhs->u.globid.s; + pd->props = lut_add(pd->props, name, nrhs, NULL); + break; + case T_FUNC: + /* for T_FUNC, we don't duplicate it, just point to node */ + pd->props = lut_add(pd->props, name, orhs, NULL); + break; default: - out(O_DEBUG, "unexpected nvpair value type %s", + out(O_DIE, "unexpected nvpair value type %s", ptree_nodetype2str(((struct node *)val)->t)); } } @@ -468,7 +478,15 @@ instances_destructor(void *left, void *right, void *arg) lut_free(dn->u.stmt.lutp, instances_destructor, NULL); dn->u.stmt.lutp = NULL; } - tree_free(dn); + if (dn->t != T_FUNC) /* T_FUNC pointed to original node */ + tree_free(dn); +} + +/*ARGSUSED*/ +static void +payloadprops_destructor(void *left, void *right, void *arg) +{ + FREE(right); } /* @@ -1591,6 +1609,9 @@ itree_destructor(void *left, void *right, void *arg) /* Free the properties */ lut_free(ep->props, instances_destructor, NULL); + /* Free the payload properties */ + lut_free(ep->payloadprops, payloadprops_destructor, NULL); + /* Free my bubbles */ for (bub = ep->bubbles; bub != NULL; ) { nextbub = bub->next; @@ -1718,6 +1739,7 @@ itree_add_arrow(struct bubble *frombubblep, struct bubble *tobubblep, ASSERTinfo(tobubblep->t == B_TO || tobubblep->t == B_INHIBIT, itree_bubbletype2str(tobubblep->t)); newa = MALLOC(sizeof (struct arrow)); + bzero(newa, sizeof (struct arrow)); newa->tail = frombubblep; newa->head = tobubblep; newa->pnode = apnode; @@ -1800,7 +1822,7 @@ itree_set_arrow_traits(struct arrow *ap, struct node *fromev, /* if we came up with any deferred constraints, add them to arrow */ if (newc != NULL) - (void) itree_add_constraint(ap, newc); + (void) itree_add_constraint(ap, iexpr(newc)); return (1); /* constraints allow arrow */ } @@ -1937,7 +1959,8 @@ itree_free_constraints(struct arrow *ap) while (cl != NULL) { ncl = cl->next; ASSERT(cl->cnode != NULL); - tree_free(cl->cnode); + if (!iexpr_cached(cl->cnode)) + tree_free(cl->cnode); bzero(cl, sizeof (*cl)); FREE(cl); cl = ncl; diff --git a/usr/src/cmd/fm/modules/common/eversholt/itree.h b/usr/src/cmd/fm/modules/common/eversholt/itree.h index 3ba16ef45a..e551514d12 100644 --- a/usr/src/cmd/fm/modules/common/eversholt/itree.h +++ b/usr/src/cmd/fm/modules/common/eversholt/itree.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * itree.h -- public definitions for itree module @@ -42,6 +42,38 @@ extern "C" { /* Numerical representation of propagation N value (A), short for All */ #define N_IS_ALL -1 +/* + * effects_test event cached_state bits + * - reset on each call to effects_test() + */ +#define CREDIBLE_EFFECT 1 +#define WAIT_EFFECT 2 +#define PARENT_WAIT 4 + +/* + * arrow mark bits (for K-count) + */ +#define EFFECTS_COUNTER 8 +#define REQMNTS_COUNTER 16 + +/* + * requirements_test event cached_state bits + */ +#define REQMNTS_CREDIBLE 32 +#define REQMNTS_DISPROVED 64 +#define REQMNTS_WAIT 128 + +/* + * requirements_test bubble mark bits + */ +#define BUBBLE_ELIDED 256 +#define BUBBLE_OK 512 + +/* + * causes_test event cached_state bits + */ +#define CAUSES_TESTED 1024 + struct event { enum nametype t; /* defined in tree.h */ struct event *suspects; @@ -52,7 +84,10 @@ struct event { struct node *enode; /* event node in parse tree */ const struct ipath *ipp; /* instanced version of event */ struct lut *props; /* instanced version of nvpairs */ + struct lut *payloadprops; /* nvpairs for problem payload */ int count; /* for reports, number seen */ + int cached_state; + unsigned long long cached_delay; struct bubble { struct bubble *next; int gen; /* generation # */ @@ -76,7 +111,8 @@ struct event { /* deferred constraints */ struct node *cnode; } *constraints; - int causes_tested; + int forever_false; + int mark; unsigned long long mindelay; unsigned long long maxdelay; } *arrowp; diff --git a/usr/src/cmd/fm/modules/common/eversholt/platform.c b/usr/src/cmd/fm/modules/common/eversholt/platform.c index 65bb101295..1fdd7f1a71 100644 --- a/usr/src/cmd/fm/modules/common/eversholt/platform.c +++ b/usr/src/cmd/fm/modules/common/eversholt/platform.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -19,8 +18,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * platform.c -- interfaces to the platform's configuration information @@ -48,7 +48,7 @@ #include <sys/param.h> #include <sys/fm/protocol.h> #include <fm/fmd_api.h> -#include <fm/libtopo_enum.h> +#include <fm/libtopo.h> #include "alloc.h" #include "out.h" #include "tree.h" @@ -70,6 +70,7 @@ extern fmd_hdl_t *Hdl; /* handle from eft.c */ * we take one and save it in Initcfg below. */ static struct cfgdata *Lastcfg; +static topo_hdl_t *Eft_topo_hdl; /* * Initcfg points to any config snapshot we have to make prior @@ -77,12 +78,6 @@ static struct cfgdata *Lastcfg; */ static struct cfgdata *Initcfg; -void -topo_use_out(const char *obuf) -{ - out(O_ALTFP, "topo: %s", obuf); -} - void * topo_use_alloc(size_t bytes) { @@ -125,6 +120,8 @@ nv_alloc_t Eft_nv_hdl; static char *Root; static char *Mach; static char *Plat; +static char tmpbuf[MAXPATHLEN]; +static char numbuf[MAXPATHLEN]; /* * platform_globals -- set global variables based on sysinfo() calls @@ -145,51 +142,17 @@ platform_free_globals() fmd_prop_free_string(Hdl, Plat); } -static void -platform_topo_paths(int *n, const char ***p) -{ - const char **cp; - char *tmpbuf; - - *n = 2; - cp = *p = MALLOC(2 * sizeof (const char *)); - - tmpbuf = MALLOC(MAXPATHLEN); - (void) snprintf(tmpbuf, - MAXPATHLEN, "%s/usr/lib/fm/topo/%s", Root, Plat); - *cp++ = STRDUP(tmpbuf); - (void) snprintf(tmpbuf, MAXPATHLEN, "%s/usr/lib/fm/topo", Root); - *cp = STRDUP(tmpbuf); - FREE(tmpbuf); -} - -void -platform_free_paths(int n, const char **p) -{ - int i; - - for (i = 0; i < n; i++) - FREE((void *)p[i]); - FREE(p); -} - /* * platform_init -- perform any platform-specific initialization */ void platform_init(void) { - const char **paths; - int npaths; - (void) nv_alloc_init(&Eft_nv_hdl, &Eft_nv_alloc_ops); - topo_set_mem_methods(topo_use_alloc, topo_use_free); - topo_set_out_method(topo_use_out); - + Eft_topo_hdl = fmd_hdl_topology(Hdl, TOPO_VERSION); platform_globals(); - platform_topo_paths(&npaths, &paths); - topo_init(npaths, (const char **)paths); - platform_free_paths(npaths, paths); + + out(O_ALTFP, "platform_init() sucessful"); } void @@ -206,7 +169,8 @@ platform_fini(void) platform_free_globals(); (void) nv_alloc_fini(&Eft_nv_hdl); - topo_fini(); + + out(O_ALTFP, "platform_fini() sucessful"); } /* @@ -374,35 +338,164 @@ cfgadjust(struct cfgdata *rawdata, int addlen) } } +static char * +hc_path(tnode_t *node) +{ + int i, err; + char *name, *instance, *estr; + nvlist_t *fmri, **hcl; + ulong_t ul; + uint_t nhc; + + if (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_RESOURCE, + &fmri, &err) < 0) + return (NULL); + + if (nvlist_lookup_nvlist_array(fmri, FM_FMRI_HC_LIST, &hcl, &nhc) + != 0) { + nvlist_free(fmri); + return (NULL); + } + + tmpbuf[0] = '\0'; + for (i = 0; i < nhc; ++i) { + err = nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &name); + err |= nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &instance); + if (err) { + nvlist_free(fmri); + return (NULL); + } + + ul = strtoul(instance, &estr, 10); + /* conversion to number failed? */ + if (estr == instance) { + nvlist_free(fmri); + return (NULL); + } + + (void) strlcat(tmpbuf, "/", MAXPATHLEN); + (void) strlcat(tmpbuf, name, MAXPATHLEN); + (void) snprintf(numbuf, MAXPATHLEN, "%u", ul); + (void) strlcat(tmpbuf, numbuf, MAXPATHLEN); + } + + nvlist_free(fmri); + + return (tmpbuf); +} + +static void +add_prop_val(topo_hdl_t *thp, struct cfgdata *rawdata, char *propn, + nvpair_t *pv_nvp) +{ + int addlen, err; + char *propv, *fmristr = NULL; + nvlist_t *fmri; + + /* + * At least try to collect the protocol + * properties + */ + if (nvpair_type(pv_nvp) == DATA_TYPE_NVLIST) { + (void) nvpair_value_nvlist(pv_nvp, &fmri); + if (topo_fmri_nvl2str(thp, fmri, &fmristr, &err) < 0) { + out(O_ALTFP, "cfgcollect: failed to convert fmri to " + "string"); + return; + } else { + propv = fmristr; + } + + } else if (nvpair_type(pv_nvp) == DATA_TYPE_STRING) + (void) nvpair_value_string(pv_nvp, &propv); + else { + return; + } + + /* = & NULL */ + addlen = strlen(propn) + strlen(propv) + 2; + cfgadjust(rawdata, addlen); + (void) snprintf(rawdata->nextfree, + rawdata->end - rawdata->nextfree, "%s=%s", + propn, propv); + rawdata->nextfree += addlen; + + if (fmristr != NULL) + topo_hdl_strfree(thp, fmristr); +} + /* * cfgcollect -- Assemble raw configuration data in string form suitable * for checkpointing. */ -static void -cfgcollect(tnode_t *node, void *arg) +static int +cfgcollect(topo_hdl_t *thp, tnode_t *node, void *arg) { struct cfgdata *rawdata = (struct cfgdata *)arg; - const char *propn, *propv; - char *path; int addlen; + char *propn, *path = NULL; + nvlist_t *p_nv, *pg_nv, *pv_nv; + nvpair_t *nvp, *pg_nvp, *pv_nvp; + + path = hc_path(node); + if (path == NULL) + return (TOPO_WALK_ERR); - path = topo_hc_path(node); addlen = strlen(path) + 1; cfgadjust(rawdata, addlen); (void) strcpy(rawdata->nextfree, path); rawdata->nextfree += addlen; - propn = NULL; - while ((propn = topo_next_prop(node, propn)) != NULL) { - propv = topo_get_prop(node, propn); - addlen = strlen(propn) + strlen(propv) + 2; /* = & NULL */ - cfgadjust(rawdata, addlen); - (void) snprintf(rawdata->nextfree, - rawdata->end - rawdata->nextfree, "%s=%s", propn, propv); - rawdata->nextfree += addlen; + /* + * Collect properties + * + * eversholt should support alternate property types + * Better yet, topo properties could be represented as + * a packed nvlist + */ + p_nv = topo_prop_get_all(thp, node); + for (nvp = nvlist_next_nvpair(p_nv, NULL); nvp != NULL; + nvp = nvlist_next_nvpair(p_nv, nvp)) { + if (strcmp(TOPO_PROP_GROUP, nvpair_name(nvp)) != 0 || + nvpair_type(nvp) != DATA_TYPE_NVLIST) + continue; + + (void) nvpair_value_nvlist(nvp, &pg_nv); + + for (pg_nvp = nvlist_next_nvpair(pg_nv, NULL); pg_nvp != NULL; + pg_nvp = nvlist_next_nvpair(pg_nv, pg_nvp)) { + + if (strcmp(TOPO_PROP_VAL, nvpair_name(pg_nvp)) != 0 || + nvpair_type(pg_nvp) != DATA_TYPE_NVLIST) + continue; + + (void) nvpair_value_nvlist(pg_nvp, &pv_nv); + + for (pv_nvp = nvlist_next_nvpair(pv_nv, NULL); + pv_nvp != NULL; + pv_nvp = nvlist_next_nvpair(pv_nv, pv_nvp)) { + + /* Get property name */ + propn = nvpair_name(pv_nvp); + if (strcmp(TOPO_PROP_VAL_NAME, propn) != 0) + continue; + if (nvpair_value_string(pv_nvp, &propn) != 0) + continue; + + /* + * Get property value + */ + pv_nvp = nvlist_next_nvpair(pv_nv, pv_nvp); + add_prop_val(thp, rawdata, propn, pv_nvp); + } + + } } - topo_free_path(path); + + nvlist_free(p_nv); + + return (TOPO_WALK_NEXT); } /* @@ -411,7 +504,9 @@ cfgcollect(tnode_t *node, void *arg) struct cfgdata * platform_config_snapshot(void) { - tnode_t *root; + int err; + char *uuid; + topo_walk_t *twp; /* * @@ -437,322 +532,83 @@ platform_config_snapshot(void) Lastcfg->devcache = NULL; Lastcfg->cpucache = NULL; - if ((root = topo_next_sibling(NULL, NULL)) == NULL) - out(O_DIE, "NULL topology tree"); - - topo_walk(root, TOPO_VISIT_SELF_FIRST, Lastcfg, cfgcollect); - topo_tree_release(root); - topo_reset(); - - return (Lastcfg); -} + out(O_ALTFP, "platform_config_snapshot(): topo snapshot"); + if ((uuid = topo_snap_hold(Eft_topo_hdl, NULL, &err)) == NULL) + out(O_DIE, "platform_config_snapshot: topo snapshot failed: %s", + topo_strerror(err)); -static nvlist_t ** -make_hc_pairs(char *fromstr, int *num) -{ - nvlist_t **pa; - char *starti, *startn, *endi, *endi2; - char *ne, *ns; - char *cname; - char *find; - char *cid; - int nslashes = 0; - int npairs = 0; - int i, e; - - /* - * Count equal signs and slashes to determine how many - * hc-pairs will be present in the final FMRI. There should - * be at least as many slashes as equal signs. There can be - * more, though if the string after an = includes them. - */ - find = fromstr; - while ((ne = strchr(find, '=')) != NULL) { - find = ne + 1; - npairs++; + if ((twp = topo_walk_init(Eft_topo_hdl, FM_FMRI_SCHEME_HC, cfgcollect, + Lastcfg, &err)) == NULL) { + topo_hdl_strfree(Eft_topo_hdl, uuid); + out(O_DIE, "platform_config_snapshot: NULL topology tree: %s", + topo_strerror(err)); } - find = fromstr; - while ((ns = strchr(find, '/')) != NULL) { - find = ns + 1; - nslashes++; + if (topo_walk_step(twp, TOPO_WALK_CHILD) == TOPO_WALK_ERR) { + topo_hdl_strfree(Eft_topo_hdl, uuid); + topo_walk_fini(twp); + out(O_DIE, "platform_config_snapshot: error walking topology " + "tree"); } - /* - * Do we appear to have a well-formed string version of the FMRI? - */ - if (nslashes < npairs || npairs == 0) - return (NULL); - - *num = npairs; - - find = fromstr; - pa = MALLOC(npairs * sizeof (nvlist_t *)); - /* - * We go through a pretty complicated procedure to find the - * name and id for each pair. That's because, unfortunately, - * we have some ids that can have slashes within them. So - * we can't just search for the next slash after the equal sign - * and decide that starts a new pair. Instead we have to find - * an equal sign for the next pair and work our way back to the - * slash from there. - */ - for (i = 0; i < npairs; i++) { - pa[i] = NULL; - startn = strchr(find, '/'); - if (startn == NULL) - break; - startn++; - starti = strchr(find, '='); - if (starti == NULL) - break; - *starti = '\0'; - cname = STRDUP(startn); - *starti++ = '='; - endi = strchr(starti, '='); - if (endi != NULL) { - *endi = '\0'; - endi2 = strrchr(starti, '/'); - if (endi2 == NULL) - break; - *endi = '='; - *endi2 = '\0'; - cid = STRDUP(starti); - *endi2 = '/'; - find = endi2; - } else { - cid = STRDUP(starti); - find = starti + strlen(starti); - } - e = nvlist_xalloc(&pa[i], NV_UNIQUE_NAME, &Eft_nv_hdl); - if (e != 0) - out(O_DIE|O_SYS, "alloc of an fmri nvl failed"); - e = nvlist_add_string(pa[i], FM_FMRI_HC_NAME, cname); - e |= nvlist_add_string(pa[i], FM_FMRI_HC_ID, cid); - FREE(cname); - FREE(cid); - if (e != 0) { - out(O_DEBUG|O_SYS, - "Construction of new hc-pair nvl failed"); - break; - } - } - if (i < npairs) { - while (i >= 0) - if (pa[i--] != NULL) - nvlist_free(pa[i + 1]); - FREE(pa); - return (NULL); - } - return (pa); -} - -static nvlist_t * -hc_fmri_fromstr(const char *str) -{ - nvlist_t **pa = NULL; - nvlist_t *na = NULL; - nvlist_t *nf = NULL; - char *copy; - int npairs; - int i, e; - - /* We're expecting a string version of an hc scheme FMRI */ - if (strncmp(str, "hc:///", 6) != 0) - return (NULL); + topo_walk_fini(twp); - copy = STRDUP(str + 5); - if ((pa = make_hc_pairs(copy, &npairs)) == NULL) { - FREE(copy); - return (NULL); - } + topo_hdl_strfree(Eft_topo_hdl, uuid); + topo_snap_release(Eft_topo_hdl); - FREE(copy); - if ((e = nvlist_xalloc(&na, NV_UNIQUE_NAME, &Eft_nv_hdl)) != 0) { - out(O_DEBUG|O_SYS, "alloc of an fmri nvl failed"); - goto hcfmbail; - } - e = nvlist_add_string(na, FM_FMRI_AUTH_PRODUCT, Plat); - if (e != 0) { - out(O_DEBUG|O_SYS, "Construction of new authority nvl failed"); - goto hcfmbail; - } - - if ((e = nvlist_xalloc(&nf, NV_UNIQUE_NAME, &Eft_nv_hdl)) != 0) { - out(O_DEBUG|O_SYS, "alloc of an fmri nvl failed"); - goto hcfmbail; - } - e = nvlist_add_string(nf, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC); - e |= nvlist_add_nvlist(nf, FM_FMRI_AUTHORITY, na); - e |= nvlist_add_uint8(nf, FM_VERSION, FM_HC_SCHEME_VERSION); - e |= nvlist_add_string(nf, FM_FMRI_HC_ROOT, ""); - e |= nvlist_add_uint32(nf, FM_FMRI_HC_LIST_SZ, npairs); - if (e == 0) - e = nvlist_add_nvlist_array(nf, FM_FMRI_HC_LIST, pa, npairs); - if (e != 0) { - out(O_DEBUG|O_SYS, "Construction of new hc nvl failed"); - goto hcfmbail; - } - nvlist_free(na); - for (i = 0; i < npairs; i++) - nvlist_free(pa[i]); - FREE(pa); - return (nf); - -hcfmbail: - if (nf != NULL) - nvlist_free(nf); - if (na != NULL) - nvlist_free(na); - for (i = 0; i < npairs; i++) - nvlist_free(pa[i]); - FREE(pa); - return (NULL); + return (Lastcfg); } -static nvlist_t * -cpu_fmri(struct config *cpu, int cpu_id) +static const char * +cfgstrprop_lookup(struct config *croot, char *path, char *pname) { - nvlist_t *na = NULL; - const char *propv; - uint64_t ser_id; - int e; + struct config *cresource; + const char *fmristr; - if ((propv = config_getprop(cpu, "SERIAL-ID")) == NULL) { - out(O_DEBUG|O_SYS, "cpu serial id missing"); + /* + * The first order of business is to find the resource in the + * config database so we can examine properties associated with + * that node. + */ + if ((cresource = config_lookup(croot, path, 0)) == NULL) { + out(O_ALTFP, "Cannot find config info for %s.", path); return (NULL); } - ser_id = strtoll(propv, NULL, 0); - - if ((e = nvlist_xalloc(&na, NV_UNIQUE_NAME, &Eft_nv_hdl)) != 0) - out(O_DIE|O_SYS, "alloc of an fmri nvl failed"); - - e = nvlist_add_string(na, FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU); - e |= nvlist_add_uint8(na, FM_VERSION, FM_CPU_SCHEME_VERSION); - e |= nvlist_add_uint32(na, FM_FMRI_CPU_ID, cpu_id); - e |= nvlist_add_uint64(na, FM_FMRI_CPU_SERIAL_ID, ser_id); - if (e != 0) { - out(O_DEBUG|O_SYS, "Construction of new ASRU nvl failed"); - nvlist_free(na); + if ((fmristr = config_getprop(cresource, pname)) == NULL) { + out(O_ALTFP, "Cannot find %s property for %s resource " + "re-write", pname, path); return (NULL); } - return (na); + return (fmristr); } static nvlist_t * -dev_fmri(const char *devpath) +rewrite_resource(char *pname, struct config *croot, char *path) { - nvlist_t *na = NULL; - int e; + const char *fmristr; + nvlist_t *fmri; + int err; - if (strcmp(devpath, "none") == 0) + if ((fmristr = cfgstrprop_lookup(croot, path, pname)) == NULL) return (NULL); - if ((e = nvlist_xalloc(&na, NV_UNIQUE_NAME, &Eft_nv_hdl)) != 0) - out(O_DIE|O_SYS, "alloc of an fmri nvl failed"); - e = nvlist_add_string(na, FM_FMRI_SCHEME, FM_FMRI_SCHEME_DEV); - e |= nvlist_add_uint8(na, FM_VERSION, FM_DEV_SCHEME_VERSION); - e |= nvlist_add_string(na, FM_FMRI_DEV_PATH, devpath); - if (e != 0) { - out(O_DEBUG|O_SYS, "Construction of new ASRU nvl failed"); - nvlist_free(na); + if (topo_fmri_str2nvl(Eft_topo_hdl, fmristr, &fmri, &err) < 0) { + out(O_ALTFP, "Can not convert config info: %s", + topo_strerror(err)); return (NULL); } - return (na); -} - -static void -rewrite_asru(nvlist_t **ap, struct config *croot, char *path) -{ - struct config *casru; - nvlist_t *na = NULL; - const char *propv; - char *cname; - int cinst; - - /* - * The first order of business is to find the ASRU in the - * config database so we can examine properties associated with - * that node. - */ - if ((casru = config_lookup(croot, path, 0)) == NULL) { - out(O_DEBUG, "Cannot find config info for %s.", path); - return; - } - - /* - * CPUs have their own scheme. - */ - config_getcompname(casru, &cname, &cinst); - if (cname == NULL) { - out(O_DEBUG, - "Final component of ASRU path (%s) has no name ?", path); - return; - } else if (strcmp(cname, "cpu") == 0) { - if ((na = cpu_fmri(casru, cinst)) != NULL) - *ap = na; - return; - } - - /* - * Look for a PLAT-ASRU property. - */ - if ((propv = config_getprop(casru, PLATASRU)) != NULL) { - if ((na = hc_fmri_fromstr(propv)) != NULL) - *ap = na; - return; - } - out(O_DEBUG, "No " PLATASRU " prop for constructing " - "rewritten version of %s.", path); - - /* - * No, PLAT-ASRU, how about DEV? - */ - if ((propv = config_getprop(casru, DEV)) == NULL) { - out(O_DEBUG, "No " DEV " prop for constructing " - "dev scheme version of %s.", path); - return; - } - if ((na = dev_fmri(propv)) != NULL) - *ap = na; -} - -static void -rewrite_fru(nvlist_t **fp, struct config *croot, char *path) -{ - struct config *cfru; - const char *propv; - nvlist_t *na = NULL; - - /* - * The first order of business is to find the FRU in the - * config database so we can examine properties associated with - * that node. - */ - if ((cfru = config_lookup(croot, path, 0)) == NULL) { - out(O_DEBUG, "Cannot find config info for %s.", path); - return; - } - /* - * Look first for a PLAT-FRU property. - */ - if ((propv = config_getprop(cfru, PLATFRU)) != NULL) { - if ((na = hc_fmri_fromstr(propv)) != NULL) - *fp = na; - return; - } - out(O_DEBUG, "No " PLATFRU " prop for constructing " - "rewritten version of %s.", path); + return (fmri); } static void defect_units(nvlist_t **ap, nvlist_t **fp, struct config *croot, char *path) { - struct config *cnode; - const char *drvname; - nvlist_t *nf = NULL; + const char *driverstr; + nvlist_t *cf, *nf; nvlist_t *na; + nvlist_t *arg; + int err; /* * Defects aren't required to have ASRUs and FRUs defined with @@ -764,26 +620,48 @@ defect_units(nvlist_t **ap, nvlist_t **fp, struct config *croot, char *path) return; /* - * In order to find an ASRU and FRU for the defect we need - * the name of the driver. + * Find the driver for this resource and use that to get + * mod and pkg fmris for ASRU and FRU respectively. */ - if ((cnode = config_lookup(croot, path, 0)) == NULL) { - out(O_DEBUG, "Cannot find config info for %s.", path); + if ((driverstr = cfgstrprop_lookup(croot, path, "DRIVER")) == NULL) + return; + + if (topo_hdl_nvalloc(Eft_topo_hdl, &arg, NV_UNIQUE_NAME) != 0) { + out(O_ALTFP, "Can not allocate nvlist for MOD fmri lookup"); return; } - if ((drvname = config_getprop(cnode, DRIVER)) == NULL) { - out(O_DEBUG, "No " DRIVER "prop for constructing " - "mod scheme version of %s.", path); + if (nvlist_add_string(arg, "DRIVER", driverstr) != 0) { + out(O_ALTFP, "Failed to add DRIVER string to arg nvlist"); + nvlist_free(arg); return; } - if ((na = topo_driver_asru(drvname, &nf)) == NULL) + na = topo_fmri_create(Eft_topo_hdl, FM_FMRI_SCHEME_MOD, + FM_FMRI_SCHEME_MOD, 0, arg, &err); + if (na == NULL) { + out(O_ALTFP, "topo_fmri_create() of %s scheme fmri" + " for driver %s failed.", FM_FMRI_SCHEME_MOD, driverstr); + nvlist_free(arg); return; + } + nvlist_free(arg); - if (*ap == NULL) - *ap = na; + if (*ap != NULL) + nvlist_free(*ap); + *ap = na; - if (*fp == NULL) - *fp = nf; + err = nvlist_lookup_nvlist(na, FM_FMRI_MOD_PKG, &cf); + if (err != 0) { + out(O_ALTFP, "No pkg RTI within mod FMRI for %s (%s)\n", + driverstr, topo_strerror(err)); + return; + } + if (nvlist_xdup(cf, &nf, &Eft_nv_hdl) != 0) { + out(O_ALTFP, "Dup of pkg FMRI to be FRU FMRI failed\n"); + return; + } + if (*fp != NULL) + nvlist_free(*fp); + *fp = nf; } /* @@ -796,19 +674,20 @@ void platform_units_translate(int isdefect, struct config *croot, nvlist_t **dfltasru, nvlist_t **dfltfru, nvlist_t **dfltrsrc, char *path) { - nvlist_t *sva; - nvlist_t *svf; - - out(O_DEBUG, "platform_units_translate(%d, ....)", isdefect); + nvlist_t *asru, *rsrc, *fru; - sva = *dfltasru; - svf = *dfltfru; + out(O_ALTFP, "platform_units_translate(%d, ....)", isdefect); /* - * If there's room, keep a copy of our original ASRU as the rsrc + * Get our FMRIs from libtopo */ - if (*dfltrsrc == NULL) - *dfltrsrc = *dfltasru; + if ((rsrc = rewrite_resource(TOPO_PROP_RESOURCE, croot, path)) + == NULL) { + out(O_ALTFP, "Cannot rewrite resource for %s.", path); + } else { + nvlist_free(*dfltrsrc); + *dfltrsrc = rsrc; + } /* * If it is a defect we want to re-write the FRU as the pkg @@ -818,42 +697,27 @@ platform_units_translate(int isdefect, struct config *croot, */ if (isdefect) { defect_units(dfltasru, dfltfru, croot, path); - if (sva != *dfltasru && sva != *dfltrsrc && sva != NULL) - nvlist_free(sva); - if (svf != *dfltfru && svf != NULL) - nvlist_free(svf); return; } - if (*dfltasru != NULL) { - /* - * The ASRU will be re-written per the following rules: - * - * 1) If there's a PLAT-ASRU property, we convert it into - * a real hc FMRI nvlist. - * 2) Otherwise, if we find a DEV property, we make a DEV - * scheme FMRI of it - * 3) Otherwise, we leave the ASRU as is. - */ - rewrite_asru(dfltasru, croot, path); + /* + * Find the TOPO_PROP_ASRU and TOPO_PROP_FRU properties + * for this resource + */ + if ((asru = rewrite_resource(TOPO_PROP_ASRU, croot, path)) == NULL) { + out(O_ALTFP, "Cannot rewrite %s for %s.", TOPO_PROP_ASRU, path); + } else { + nvlist_free(*dfltasru); + *dfltasru = asru; } - if (*dfltfru != NULL) { - /* - * The FRU will be re-written per the following rules: - * - * 1) If there's a PLAT-FRU property, we convert it into - * a real hc FMRI nvlist. - * 2) Otherwise, we leave the ASRU as is, but include a - * FRU label property if possible. - */ - rewrite_fru(dfltfru, croot, path); + if ((fru = rewrite_resource(TOPO_PROP_FRU, croot, path)) == NULL) { + out(O_ALTFP, "Cannot rewrite %s for %s.", + TOPO_PROP_FRU, path); + } else { + nvlist_free(*dfltfru); + *dfltfru = fru; } - - if (sva != *dfltasru && sva != *dfltrsrc && sva != NULL) - nvlist_free(sva); - if (svf != *dfltfru && svf != NULL) - nvlist_free(svf); } /* @@ -933,6 +797,8 @@ platform_get_files(const char *dirname[], const char *fnstr, int nodups) totlen = strlen(dirname[i]) + 1; totlen += strlen(dp->d_name) + 1; files[nfiles] = MALLOC(totlen); + out(O_DEBUG, "File %d: \"%s/%s\"", nfiles, + dirname[i], dp->d_name); (void) snprintf(files[nfiles++], totlen, "%s/%s", dirname[i], dp->d_name); } @@ -1121,60 +987,6 @@ forkandexecve(const char *path, char *const argv[], char *const envp[], return (rt); } -/* - * extract the first string in outbuf, either - * a) convert it to a number, or - * b) convert it to an address via stable() - * and place the result (number or address) in valuep. - * - * return 0 if conversion was successful, nonzero if otherwise - */ -static int -string2number(char *outbuf, size_t outbuflen, struct evalue *valuep) -{ - char *ptr, *startptr, *endptr; - int spval; - size_t nchars, i, ier; - - /* determine start and length of first string */ - nchars = 0; - for (i = 0; i < outbuflen && *(outbuf + i) != '\0'; i++) { - spval = isspace((int)*(outbuf + i)); - if (spval != 0 && nchars > 0) - break; - if (spval == 0) { - /* startptr: first nonspace character */ - if (nchars == 0) - startptr = outbuf + i; - nchars++; - } - } - if (nchars == 0) - return (1); - - ptr = MALLOC(sizeof (char) * (nchars + 1)); - (void) strncpy(ptr, startptr, nchars); - *(ptr + nchars) = '\0'; - - /* attempt conversion to number */ - errno = 0; - valuep->t = UINT64; - valuep->v = strtoull(ptr, &endptr, 0); - ier = errno; - - /* - * test for endptr since the call to strtoull() should be - * considered a success only if the whole string was converted - */ - if (ier != 0 || endptr != (ptr + nchars)) { - valuep->t = STRING; - valuep->v = (unsigned long long)stable(ptr); - } - FREE(ptr); - - return (0); -} - #define MAXDIGITIDX 23 static int @@ -1447,10 +1259,16 @@ platform_call(struct node *np, struct lut **globals, struct config *croot, outfl(O_OK, np->file, np->line, "call: failure in fork + exec of %s", argv[0]); } else { - ret = string2number(outbuf, sizeof (outbuf), valuep); - if (ret) - outfl(O_OK, np->file, np->line, - "call: no result from %s", argv[0]); + char *ptr; + + /* chomp the result */ + for (ptr = outbuf; *ptr; ptr++) + if (*ptr == '\n' || *ptr == '\r') { + *ptr = '\0'; + break; + } + valuep->t = STRING; + valuep->v = (unsigned long long)stable(outbuf); } if (errbuf[0] != '\0') { @@ -1468,6 +1286,125 @@ platform_call(struct node *np, struct lut **globals, struct config *croot, } /* + * platform_confcall -- call a configuration database function + * + * returns result in *valuep, return 0 on success + */ +/*ARGSUSED*/ +int +platform_confcall(struct node *np, struct lut **globals, struct config *croot, + struct arrow *arrowp, struct evalue *valuep) +{ + nvlist_t *rsrc, *hcs; + nvpair_t *nvp; + + ASSERT(np != NULL); + + /* assume we're returning true */ + valuep->t = UINT64; + valuep->v = 1; + + /* + * We've detected a well-formed confcall() to rewrite + * an ASRU in a fault. We get here via lines like this + * in the eversholt rules: + * + * event fault.memory.page@dimm, FITrate=PAGE_FIT, + * ASRU=dimm, message=0, + * count=stat.page_fault@dimm, + * action=confcall("rewrite-ASRU"); + * + * So first rewrite the resource in the fault. Any payload data + * following the FM_FMRI_HC_SPECIFIC member is used to expand the + * resource nvlist. Next, use libtopo to compute the ASRU from + * from the new resource. + */ + if (np->t == T_QUOTE && np->u.quote.s == stable("rewrite-ASRU")) { + int err; + nvlist_t *asru; + + out(O_ALTFP|O_VERB, "platform_confcall: rewrite-ASRU"); + + if (nvlist_lookup_nvlist(Action_nvl, FM_FAULT_RESOURCE, &rsrc) + != 0) { + outfl(O_ALTFP|O_VERB, np->file, np->line, "no resource " + "in fault event"); + return (0); + } + + if (topo_hdl_nvalloc(Eft_topo_hdl, &hcs, NV_UNIQUE_NAME) != 0) { + outfl(O_ALTFP|O_VERB, np->file, np->line, + "unable to allocate nvlist for resource rewrite"); + return (0); + } + + /* + * Loop until we run across asru-specific payload + */ + for (nvp = nvlist_next_nvpair(Action_nvl, NULL); nvp != NULL; + nvp = nvlist_next_nvpair(Action_nvl, nvp)) { + uint64_t ui; + char *us; + + if (strncmp(nvpair_name(nvp), "asru-", 5) != 0) + continue; + + if (nvpair_type(nvp) == DATA_TYPE_UINT64) { + err = nvpair_value_uint64(nvp, &ui); + err |= nvlist_add_uint64(hcs, nvpair_name(nvp), + ui); + } else if (nvpair_type(nvp) == DATA_TYPE_STRING) { + err = nvpair_value_string(nvp, &us); + err |= nvlist_add_string(hcs, nvpair_name(nvp), + us); + } else { + continue; + } + + if (err != 0) { + nvlist_free(hcs); + outfl(O_ALTFP|O_VERB, np->file, np->line, + "unable to rewrite resource"); + return (0); + } + } + + if (nvlist_add_nvlist(rsrc, FM_FMRI_HC_SPECIFIC, hcs) != 0) { + nvlist_free(hcs); + outfl(O_ALTFP|O_VERB, np->file, np->line, "unable to " + "rewrite resource with HC specific data"); + return (0); + } + nvlist_free(hcs); + + if (topo_fmri_asru(Eft_topo_hdl, rsrc, &asru, &err) != 0) { + outfl(O_ALTFP|O_VERB, np->file, np->line, "unable to " + "rewrite asru: %s", topo_strerror(err)); + return (0); + } + + if (nvlist_remove(Action_nvl, FM_FAULT_ASRU, DATA_TYPE_NVLIST) + != 0) { + nvlist_free(asru); + outfl(O_ALTFP|O_VERB, np->file, np->line, + "failed to remove old asru during rewrite"); + return (0); + } + if (nvlist_add_nvlist(Action_nvl, FM_FAULT_ASRU, asru) != 0) { + nvlist_free(asru); + outfl(O_ALTFP|O_VERB, np->file, np->line, + "unable to add re-written asru"); + return (0); + } + nvlist_free(asru); + } else { + outfl(O_ALTFP|O_VERB, np->file, np->line, "unknown confcall"); + } + + return (0); +} + +/* * platform_get_eft_files -- return names of all eft files we should load * * this routine doesn't return NULL, even if no files are found (in that @@ -1560,19 +1497,26 @@ get_array_info(const char *inputstr, const char **name, unsigned int *index) return (0); } +/* + * platform_payloadprop -- fetch a payload value + * + * XXX this function should be replaced and eval_func() should be + * XXX changed to use the more general platform_payloadprop_values(). + */ int platform_payloadprop(struct node *np, struct evalue *valuep) { nvlist_t *basenvp; + nvlist_t *embnvp = NULL; nvpair_t *nvpair; const char *nameptr, *propstr, *lastnameptr; int not_array = 0; unsigned int index = 0; uint_t nelem; char *nvpname, *nameslist = NULL; + char *scheme = NULL; ASSERT(np->t == T_QUOTE); - valuep->t = UNDEFINED; propstr = np->u.quote.s; if (payloadnvp == NULL) { @@ -1652,12 +1596,28 @@ platform_payloadprop(struct node *np, struct evalue *valuep) if (nvpair == NULL) { out(O_ALTFP, "platform_payloadprop: no entry for %s", propstr); return (1); + } else if (valuep == NULL) { + /* + * caller is interested in the existence of a property with + * this name, regardless of type or value + */ + return (0); } + valuep->t = UNDEFINED; + /* * get to this point if we found an entry. figure out its data * type and copy its value. */ + (void) nvpair_value_nvlist(nvpair, &embnvp); + if (nvlist_lookup_string(embnvp, FM_FMRI_SCHEME, &scheme) == 0) { + if (strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) { + valuep->t = NODEPTR; + valuep->v = (unsigned long long)hc_fmri_nodeize(embnvp); + return (0); + } + } switch (nvpair_type(nvpair)) { case DATA_TYPE_BOOLEAN: case DATA_TYPE_BOOLEAN_VALUE: { @@ -1844,7 +1804,7 @@ platform_payloadprop(struct node *np, struct evalue *valuep) } default : - out(O_DEBUG, + out(O_ALTFP|O_VERB2, "platform_payloadprop: unsupported data type for %s", propstr); return (1); @@ -1853,7 +1813,380 @@ platform_payloadprop(struct node *np, struct evalue *valuep) return (0); invalid: - out(O_DEBUG, "platform_payloadprop: invalid array reference for %s", - propstr); + out(O_ALTFP|O_VERB2, + "platform_payloadprop: invalid array reference for %s", propstr); return (1); } + +/*ARGSUSED*/ +int +platform_path_exists(nvlist_t *fmri) +{ + return (fmd_nvl_fmri_present(Hdl, fmri)); +} + +struct evalue * +platform_payloadprop_values(const char *propstr, int *nvals) +{ + struct evalue *retvals; + nvlist_t *basenvp; + nvpair_t *nvpair; + char *nvpname; + + *nvals = 0; + + if (payloadnvp == NULL) + return (NULL); + + basenvp = payloadnvp; + + /* search for nvpair entry */ + nvpair = NULL; + while ((nvpair = nvlist_next_nvpair(basenvp, nvpair)) != NULL) { + nvpname = nvpair_name(nvpair); + ASSERT(nvpname != NULL); + + if (strcmp(propstr, nvpname) == 0) + break; + } + + if (nvpair == NULL) + return (NULL); /* property not found */ + + switch (nvpair_type(nvpair)) { + case DATA_TYPE_NVLIST: { + nvlist_t *embnvp = NULL; + char *scheme = NULL; + + (void) nvpair_value_nvlist(nvpair, &embnvp); + if (nvlist_lookup_string(embnvp, FM_FMRI_SCHEME, + &scheme) == 0) { + if (strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) { + *nvals = 1; + retvals = MALLOC(sizeof (struct evalue)); + retvals->t = NODEPTR; + retvals->v = + (unsigned long long)hc_fmri_nodeize(embnvp); + return (retvals); + } + } + return (NULL); + } + case DATA_TYPE_NVLIST_ARRAY: { + char *scheme = NULL; + nvlist_t **nvap; + uint_t nel; + int i; + int hccount; + + /* + * since we're only willing to handle hc fmri's, we + * must count them first before allocating retvals. + */ + if (nvpair_value_nvlist_array(nvpair, &nvap, &nel) != 0) + return (NULL); + + hccount = 0; + for (i = 0; i < nel; i++) { + if (nvlist_lookup_string(nvap[i], FM_FMRI_SCHEME, + &scheme) == 0 && + strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) { + hccount++; + } + } + + if (hccount == 0) + return (NULL); + + *nvals = hccount; + retvals = MALLOC(sizeof (struct evalue) * hccount); + + hccount = 0; + for (i = 0; i < nel; i++) { + if (nvlist_lookup_string(nvap[i], FM_FMRI_SCHEME, + &scheme) == 0 && + strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) { + retvals[hccount].t = NODEPTR; + retvals[hccount].v = (unsigned long long) + hc_fmri_nodeize(nvap[i]); + hccount++; + } + } + return (retvals); + } + case DATA_TYPE_BOOLEAN: + case DATA_TYPE_BOOLEAN_VALUE: { + boolean_t val; + + *nvals = 1; + retvals = MALLOC(sizeof (struct evalue)); + (void) nvpair_value_boolean_value(nvpair, &val); + retvals->t = UINT64; + retvals->v = (unsigned long long)val; + return (retvals); + } + case DATA_TYPE_BYTE: { + uchar_t val; + + *nvals = 1; + retvals = MALLOC(sizeof (struct evalue)); + (void) nvpair_value_byte(nvpair, &val); + retvals->t = UINT64; + retvals->v = (unsigned long long)val; + return (retvals); + } + case DATA_TYPE_STRING: { + char *val; + + *nvals = 1; + retvals = MALLOC(sizeof (struct evalue)); + retvals->t = STRING; + (void) nvpair_value_string(nvpair, &val); + retvals->v = (unsigned long long)stable(val); + return (retvals); + } + + case DATA_TYPE_INT8: { + int8_t val; + + *nvals = 1; + retvals = MALLOC(sizeof (struct evalue)); + (void) nvpair_value_int8(nvpair, &val); + retvals->t = UINT64; + retvals->v = (unsigned long long)val; + return (retvals); + } + case DATA_TYPE_UINT8: { + uint8_t val; + + *nvals = 1; + retvals = MALLOC(sizeof (struct evalue)); + (void) nvpair_value_uint8(nvpair, &val); + retvals->t = UINT64; + retvals->v = (unsigned long long)val; + return (retvals); + } + + case DATA_TYPE_INT16: { + int16_t val; + + *nvals = 1; + retvals = MALLOC(sizeof (struct evalue)); + (void) nvpair_value_int16(nvpair, &val); + retvals->t = UINT64; + retvals->v = (unsigned long long)val; + return (retvals); + } + case DATA_TYPE_UINT16: { + uint16_t val; + + *nvals = 1; + retvals = MALLOC(sizeof (struct evalue)); + (void) nvpair_value_uint16(nvpair, &val); + retvals->t = UINT64; + retvals->v = (unsigned long long)val; + return (retvals); + } + + case DATA_TYPE_INT32: { + int32_t val; + + *nvals = 1; + retvals = MALLOC(sizeof (struct evalue)); + (void) nvpair_value_int32(nvpair, &val); + retvals->t = UINT64; + retvals->v = (unsigned long long)val; + return (retvals); + } + case DATA_TYPE_UINT32: { + uint32_t val; + + *nvals = 1; + retvals = MALLOC(sizeof (struct evalue)); + (void) nvpair_value_uint32(nvpair, &val); + retvals->t = UINT64; + retvals->v = (unsigned long long)val; + return (retvals); + } + + case DATA_TYPE_INT64: { + int64_t val; + + *nvals = 1; + retvals = MALLOC(sizeof (struct evalue)); + (void) nvpair_value_int64(nvpair, &val); + retvals->t = UINT64; + retvals->v = (unsigned long long)val; + return (retvals); + } + case DATA_TYPE_UINT64: { + uint64_t val; + + *nvals = 1; + retvals = MALLOC(sizeof (struct evalue)); + (void) nvpair_value_uint64(nvpair, &val); + retvals->t = UINT64; + retvals->v = (unsigned long long)val; + return (retvals); + } + + case DATA_TYPE_BOOLEAN_ARRAY: { + boolean_t *val; + uint_t nel; + int i; + + (void) nvpair_value_boolean_array(nvpair, &val, &nel); + *nvals = nel; + retvals = MALLOC(sizeof (struct evalue) * nel); + for (i = 0; i < nel; i++) { + retvals[i].t = UINT64; + retvals[i].v = (unsigned long long)val[i]; + } + return (retvals); + } + case DATA_TYPE_BYTE_ARRAY: { + uchar_t *val; + uint_t nel; + int i; + + (void) nvpair_value_byte_array(nvpair, &val, &nel); + *nvals = nel; + retvals = MALLOC(sizeof (struct evalue) * nel); + for (i = 0; i < nel; i++) { + retvals[i].t = UINT64; + retvals[i].v = (unsigned long long)val[i]; + } + return (retvals); + } + case DATA_TYPE_STRING_ARRAY: { + char **val; + uint_t nel; + int i; + + (void) nvpair_value_string_array(nvpair, &val, &nel); + *nvals = nel; + retvals = MALLOC(sizeof (struct evalue) * nel); + for (i = 0; i < nel; i++) { + retvals[i].t = STRING; + retvals[i].v = (unsigned long long)stable(val[i]); + } + return (retvals); + } + + case DATA_TYPE_INT8_ARRAY: { + int8_t *val; + uint_t nel; + int i; + + (void) nvpair_value_int8_array(nvpair, &val, &nel); + *nvals = nel; + retvals = MALLOC(sizeof (struct evalue) * nel); + for (i = 0; i < nel; i++) { + retvals[i].t = UINT64; + retvals[i].v = (unsigned long long)val[i]; + } + return (retvals); + } + case DATA_TYPE_UINT8_ARRAY: { + uint8_t *val; + uint_t nel; + int i; + + (void) nvpair_value_uint8_array(nvpair, &val, &nel); + *nvals = nel; + retvals = MALLOC(sizeof (struct evalue) * nel); + for (i = 0; i < nel; i++) { + retvals[i].t = UINT64; + retvals[i].v = (unsigned long long)val[i]; + } + return (retvals); + } + case DATA_TYPE_INT16_ARRAY: { + int16_t *val; + uint_t nel; + int i; + + (void) nvpair_value_int16_array(nvpair, &val, &nel); + *nvals = nel; + retvals = MALLOC(sizeof (struct evalue) * nel); + for (i = 0; i < nel; i++) { + retvals[i].t = UINT64; + retvals[i].v = (unsigned long long)val[i]; + } + return (retvals); + } + case DATA_TYPE_UINT16_ARRAY: { + uint16_t *val; + uint_t nel; + int i; + + (void) nvpair_value_uint16_array(nvpair, &val, &nel); + *nvals = nel; + retvals = MALLOC(sizeof (struct evalue) * nel); + for (i = 0; i < nel; i++) { + retvals[i].t = UINT64; + retvals[i].v = (unsigned long long)val[i]; + } + return (retvals); + } + case DATA_TYPE_INT32_ARRAY: { + int32_t *val; + uint_t nel; + int i; + + (void) nvpair_value_int32_array(nvpair, &val, &nel); + *nvals = nel; + retvals = MALLOC(sizeof (struct evalue) * nel); + for (i = 0; i < nel; i++) { + retvals[i].t = UINT64; + retvals[i].v = (unsigned long long)val[i]; + } + return (retvals); + } + case DATA_TYPE_UINT32_ARRAY: { + uint32_t *val; + uint_t nel; + int i; + + (void) nvpair_value_uint32_array(nvpair, &val, &nel); + *nvals = nel; + retvals = MALLOC(sizeof (struct evalue) * nel); + for (i = 0; i < nel; i++) { + retvals[i].t = UINT64; + retvals[i].v = (unsigned long long)val[i]; + } + return (retvals); + } + case DATA_TYPE_INT64_ARRAY: { + int64_t *val; + uint_t nel; + int i; + + (void) nvpair_value_int64_array(nvpair, &val, &nel); + *nvals = nel; + retvals = MALLOC(sizeof (struct evalue) * nel); + for (i = 0; i < nel; i++) { + retvals[i].t = UINT64; + retvals[i].v = (unsigned long long)val[i]; + } + return (retvals); + } + case DATA_TYPE_UINT64_ARRAY: { + uint64_t *val; + uint_t nel; + int i; + + (void) nvpair_value_uint64_array(nvpair, &val, &nel); + *nvals = nel; + retvals = MALLOC(sizeof (struct evalue) * nel); + for (i = 0; i < nel; i++) { + retvals[i].t = UINT64; + retvals[i].v = (unsigned long long)val[i]; + } + return (retvals); + } + + } + + return (NULL); +} diff --git a/usr/src/cmd/fm/modules/common/eversholt/platform.h b/usr/src/cmd/fm/modules/common/eversholt/platform.h index db3c3a7fab..5281124cc1 100644 --- a/usr/src/cmd/fm/modules/common/eversholt/platform.h +++ b/usr/src/cmd/fm/modules/common/eversholt/platform.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * platform -- platform-specific access to configuration database @@ -39,6 +39,8 @@ extern "C" { #include "config.h" +nvlist_t *Action_nvl; /* nvl for problem with action=... prop on it */ + void platform_init(void); void platform_fini(void); void platform_run_poller(const char *poller); @@ -54,7 +56,11 @@ void platform_free_eft_files(char **); int platform_call(struct node *np, struct lut **globals, struct config *croot, struct arrow *arrowp, struct evalue *valuep); +int platform_confcall(struct node *np, struct lut **globals, + struct config *croot, struct arrow *arrowp, struct evalue *valuep); int platform_payloadprop(struct node *np, struct evalue *valuep); +struct evalue *platform_payloadprop_values(const char *s, int *nvals); +int platform_path_exists(nvlist_t *fmri); #ifdef __cplusplus } diff --git a/usr/src/cmd/fm/modules/common/eversholt/stats.c b/usr/src/cmd/fm/modules/common/eversholt/stats.c index 945ef66518..e013ccff68 100644 --- a/usr/src/cmd/fm/modules/common/eversholt/stats.c +++ b/usr/src/cmd/fm/modules/common/eversholt/stats.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * stats.c -- simple stats tracking table module @@ -79,11 +79,21 @@ stats_new(const char *name, const char *desc, enum stats_type t) bzero(ret, sizeof (*ret)); ret->t = t; - (void) strlcpy(ret->fmd_stats.fmds_name, name, - sizeof (ret->fmd_stats.fmds_name)); (void) strlcpy(ret->fmd_stats.fmds_desc, desc, sizeof (ret->fmd_stats.fmds_desc)); + /* NULL name means generate a unique name */ + if (name == NULL) { + static int uniqstat; + + (void) snprintf(ret->fmd_stats.fmds_name, + sizeof (ret->fmd_stats.fmds_name), + "stat.rules%d", uniqstat++); + } else { + (void) strlcpy(ret->fmd_stats.fmds_name, name, + sizeof (ret->fmd_stats.fmds_name)); + } + switch (t) { case STATS_COUNTER: ret->fmd_stats.fmds_type = FMD_TYPE_INT32; @@ -147,6 +157,17 @@ stats_counter_add(struct stats *sp, int n) sp->fmd_stats.fmds_value.i32 += n; } +void +stats_counter_reset(struct stats *sp) +{ + if (sp == NULL) + return; + + ASSERT(sp->t == STATS_COUNTER); + + sp->fmd_stats.fmds_value.i32 = 0; +} + int stats_counter_value(struct stats *sp) { diff --git a/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_cpu.c b/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_cpu.c index a580bba9c2..159825e531 100644 --- a/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_cpu.c +++ b/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_cpu.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -921,7 +921,8 @@ cmd_cpu_lookup(fmd_hdl_t *hdl, nvlist_t *asru, const char *class) FM_VERSION, DATA_TYPE_UINT8, &vers, FM_FMRI_SCHEME, DATA_TYPE_STRING, &scheme, FM_FMRI_CPU_ID, DATA_TYPE_UINT32, &cpuid, - NULL) != 0 || vers != FM_EREPORT_VERSION || + NULL) != 0 || (vers != CPU_SCHEME_VERSION0 && + vers != CPU_SCHEME_VERSION1) || strcmp(scheme, FM_FMRI_SCHEME_CPU) != 0) { CMD_STAT_BUMP(bad_cpu_asru); return (NULL); diff --git a/usr/src/cmd/fm/modules/sun4u/cpumem-diagnosis/cmd_dp.c b/usr/src/cmd/fm/modules/sun4u/cpumem-diagnosis/cmd_dp.c index e1c167e683..d0bbd5c854 100644 --- a/usr/src/cmd/fm/modules/sun4u/cpumem-diagnosis/cmd_dp.c +++ b/usr/src/cmd/fm/modules/sun4u/cpumem-diagnosis/cmd_dp.c @@ -50,6 +50,7 @@ dp_cpu_fmri(fmd_hdl_t *hdl, uint32_t cpuid, uint64_t serial_id) { nvlist_t *nvl = NULL; int err; + char sbuf[21]; /* sizeof (UINT64_MAX) + '\0' */ if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) return (NULL); @@ -57,7 +58,12 @@ dp_cpu_fmri(fmd_hdl_t *hdl, uint32_t cpuid, uint64_t serial_id) err = nvlist_add_string(nvl, FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU); err |= nvlist_add_uint8(nvl, FM_VERSION, FM_CPU_SCHEME_VERSION); err |= nvlist_add_uint32(nvl, FM_FMRI_CPU_ID, cpuid); - err |= nvlist_add_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, serial_id); + + /* + * Version 1 calls for a string-based serial number + */ + (void) snprintf(sbuf, sizeof (sbuf), "%llX", (u_longlong_t)serial_id); + err |= nvlist_add_string(nvl, FM_FMRI_CPU_SERIAL_ID, sbuf); if (err != 0) { nvlist_free(nvl); return (NULL); diff --git a/usr/src/cmd/fm/schemes/Makefile b/usr/src/cmd/fm/schemes/Makefile index e1b0f4d767..4f1dd443df 100644 --- a/usr/src/cmd/fm/schemes/Makefile +++ b/usr/src/cmd/fm/schemes/Makefile @@ -20,22 +20,19 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" -sparc_SUBDIRS = \ - mem - SUBDIRS = \ cpu \ dev \ fmd \ hc \ legacy-hc \ + mem \ mod \ - pkg \ - $($(MACH)_SUBDIRS) + pkg include ../Makefile.subdirs diff --git a/usr/src/cmd/fm/schemes/Makefile.targ b/usr/src/cmd/fm/schemes/Makefile.targ index 7fa87601d0..ac6966fc4c 100644 --- a/usr/src/cmd/fm/schemes/Makefile.targ +++ b/usr/src/cmd/fm/schemes/Makefile.targ @@ -36,19 +36,40 @@ $(PROG): $(OBJS) $(MAPFILE) $(CTFMERGE) -L VERSION -o $@ $(OBJS) $(POST_PROCESS_SO) +%.o: %.c + $(COMPILE.c) $< + $(CTFCONVERT_O) + +%.o: ../$(MACH)/%.c + $(COMPILE.c) $< + $(CTFCONVERT_O) + %.o: ../%.c $(COMPILE.c) $< $(CTFCONVERT_O) +%.o: ../../common/%.c + $(COMPILE.c) $< + $(CTFCONVERT_O) + clean: $(RM) $(OBJS) $(LINTFILES) clobber: clean $(RM) $(PROG) +%.ln: %.c + $(LINT.c) -c $< + +%.ln: ../$(MACH)/%.c + $(LINT.c) -c $< + %.ln: ../%.c $(LINT.c) -c $< +%.ln: ../../common/%.c + $(LINT.c) -erroff=E_BAD_PTR_CAST_ALIGN -v -c $< + lint: $(LINTFILES) $(LINT) $(LINTFLAGS) $(LINTFILES) $(LDLIBS) diff --git a/usr/src/cmd/fm/schemes/cpu/amd64/Makefile b/usr/src/cmd/fm/schemes/cpu/amd64/Makefile index 750b494a6d..320bdf8e60 100644 --- a/usr/src/cmd/fm/schemes/cpu/amd64/Makefile +++ b/usr/src/cmd/fm/schemes/cpu/amd64/Makefile @@ -26,11 +26,12 @@ # ident "%Z%%M% %I% %E% SMI" # -include ../Makefile.com +include ../../Makefile.com include $(SRC)/Makefile.master.64 -LDFLAGS += -R/usr/lib/fm/$(MACH64) +SRCS = cpu.c +LDFLAGS += -lkstat -include ../Makefile.targ +include ../../Makefile.targ install: all $(ROOTPROG64) diff --git a/usr/src/cmd/fm/schemes/cpu/cpu.c b/usr/src/cmd/fm/schemes/cpu/cpu.c index ef78d27cb1..ce32443c81 100644 --- a/usr/src/cmd/fm/schemes/cpu/cpu.c +++ b/usr/src/cmd/fm/schemes/cpu/cpu.c @@ -19,8 +19,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -30,14 +31,13 @@ #include <sys/processor.h> #include <fm/fmd_fmri.h> -#include <string.h> #include <strings.h> #include <errno.h> #include <kstat.h> + #ifdef sparc -#include <sys/mdesc.h> -#include <cpu.h> -#endif /* sparc */ +#include <cpu_mdesc.h> +#endif /* * The scheme plugin for cpu FMRIs. @@ -52,18 +52,47 @@ cpu_t cpu; ssize_t fmd_fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen) { + int err; uint8_t version; uint32_t cpuid; - uint64_t serialid; + uint64_t serint; + char *serstr; - if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || - version > FM_CPU_SCHEME_VERSION || - nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0 || - nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, &serialid) != 0) + if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0) return (fmd_fmri_set_errno(EINVAL)); - return (snprintf(buf, buflen, "cpu:///%s=%u/%s=%llX", FM_FMRI_CPU_ID, - cpuid, FM_FMRI_CPU_SERIAL_ID, (u_longlong_t)serialid)); + if (version == CPU_SCHEME_VERSION0) { + if (nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0 || + nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, &serint) + != 0) + return (fmd_fmri_set_errno(EINVAL)); + + return (snprintf(buf, buflen, "cpu:///%s=%u/%s=%llX", + FM_FMRI_CPU_ID, cpuid, FM_FMRI_CPU_SERIAL_ID, + (u_longlong_t)serint)); + + } else if (version == CPU_SCHEME_VERSION1) { + if (nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0) + return (fmd_fmri_set_errno(EINVAL)); + + /* + * Serial number is an optional element + */ + if ((err = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID, + &serstr)) != 0) + if (err == ENOENT) + return (snprintf(buf, buflen, "cpu:///%s=%u", + FM_FMRI_CPU_ID, cpuid)); + else + return (fmd_fmri_set_errno(EINVAL)); + else + return (snprintf(buf, buflen, "cpu:///%s=%u/%s=%s", + FM_FMRI_CPU_ID, cpuid, FM_FMRI_CPU_SERIAL_ID, + serstr)); + + } else { + return (fmd_fmri_set_errno(EINVAL)); + } } static int @@ -74,7 +103,7 @@ cpu_get_serialid_kstat(uint32_t cpuid, uint64_t *serialidp) kstat_t *ksp; int i; - if ((kc = kstat_open()) == NULL) /* XXX commonify */ + if ((kc = kstat_open()) == NULL) return (-1); /* errno is set for us */ if ((ksp = kstat_lookup(kc, "cpu_info", cpuid, NULL)) == NULL) { @@ -97,18 +126,34 @@ cpu_get_serialid_kstat(uint32_t cpuid, uint64_t *serialidp) } (void) kstat_close(kc); - return (fmd_fmri_set_errno(ENOENT)); } static int -cpu_get_serialid(uint32_t cpuid, uint64_t *serialidp) +cpu_get_serialid_V1(uint32_t cpuid, char *serbuf, size_t len) { + int err; + uint64_t serial = 0; + #ifdef sparc if (cpu.cpu_mdesc_cpus != NULL) - return (cpu_get_serialid_mdesc(cpuid, serialidp)); + err = cpu_get_serialid_mdesc(cpuid, &serial); else #endif /* sparc */ + err = cpu_get_serialid_kstat(cpuid, &serial); + + (void) snprintf(serbuf, len, "%llX", (u_longlong_t)serial); + return (err); +} + +static int +cpu_get_serialid_V0(uint32_t cpuid, uint64_t *serialidp) +{ +#ifdef sparc + if (cpu.cpu_mdesc_cpus != NULL) + return (cpu_get_serialid_mdesc(cpuid, serialidp)); + else +#endif /* sparc */ return (cpu_get_serialid_kstat(cpuid, serialidp)); } @@ -142,24 +187,41 @@ fmd_fmri_expand(nvlist_t *nvl) uint8_t version; uint32_t cpuid; uint64_t serialid; + char *serstr, serbuf[21]; /* sizeof (UINT64_MAX) + '\0' */ int rc; if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || - version > FM_CPU_SCHEME_VERSION || nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0) return (fmd_fmri_set_errno(EINVAL)); - if ((rc = nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, - &serialid)) != 0) { - if (rc != ENOENT) - return (fmd_fmri_set_errno(rc)); + if (version == CPU_SCHEME_VERSION0) { + if ((rc = nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, + &serialid)) != 0) { + if (rc != ENOENT) + return (fmd_fmri_set_errno(rc)); + + if (cpu_get_serialid_V0(cpuid, &serialid) != 0) + return (-1); /* errno is set for us */ + + if ((rc = nvlist_add_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, + serialid)) != 0) + return (fmd_fmri_set_errno(rc)); + } + } else if (version == CPU_SCHEME_VERSION1) { + if ((rc = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID, + &serstr)) != 0) { + if (rc != ENOENT) + return (fmd_fmri_set_errno(rc)); - if (cpu_get_serialid(cpuid, &serialid) != 0) - return (-1); /* errno is set for us */ + if (cpu_get_serialid_V1(cpuid, serbuf, 21) != 0) + return (0); /* Serial number is optional */ - if ((rc = nvlist_add_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, - serialid)) != 0) - return (fmd_fmri_set_errno(rc)); + if ((rc = nvlist_add_string(nvl, FM_FMRI_CPU_SERIAL_ID, + serbuf)) != 0) + return (fmd_fmri_set_errno(rc)); + } + } else { + return (fmd_fmri_set_errno(EINVAL)); } #ifdef sparc @@ -186,20 +248,42 @@ fmd_fmri_expand(nvlist_t *nvl) int fmd_fmri_present(nvlist_t *nvl) { + int rc; uint8_t version; uint32_t cpuid; uint64_t nvlserid, curserid; + char *nvlserstr, curserbuf[21]; /* sizeof (UINT64_MAX) + '\0' */ if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || - version > FM_CPU_SCHEME_VERSION || - nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0 || - nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, &nvlserid) != 0) + nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0) return (fmd_fmri_set_errno(EINVAL)); - if (cpu_get_serialid(cpuid, &curserid) != 0) - return (errno == ENOENT ? 0 : -1); + if (version == CPU_SCHEME_VERSION0) { + if (nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, + &nvlserid) != 0) + return (fmd_fmri_set_errno(EINVAL)); + if (cpu_get_serialid_V0(cpuid, &curserid) != 0) + return (errno == ENOENT ? 0 : -1); + + return (curserid == nvlserid); + + } else if (version == CPU_SCHEME_VERSION1) { + if ((rc = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID, + &nvlserstr)) != 0) + if (rc != ENOENT) + return (fmd_fmri_set_errno(EINVAL)); - return (curserid == nvlserid); + /* + * Serial id may not be available, return true + */ + if (cpu_get_serialid_V1(cpuid, curserbuf, 21) != 0) + return (1); + + return (strcmp(curserbuf, nvlserstr) == 0 ? 1 : 0); + + } else { + return (fmd_fmri_set_errno(EINVAL)); + } } int @@ -235,7 +319,6 @@ fmd_fmri_unusable(nvlist_t *nvl) int fmd_fmri_init(void) { - bzero(&cpu, sizeof (cpu_t)); return (cpu_mdesc_init()); } diff --git a/usr/src/cmd/fm/schemes/cpu/i386/Makefile b/usr/src/cmd/fm/schemes/cpu/i386/Makefile index 842f8be4cb..e592391fad 100644 --- a/usr/src/cmd/fm/schemes/cpu/i386/Makefile +++ b/usr/src/cmd/fm/schemes/cpu/i386/Makefile @@ -26,10 +26,11 @@ # ident "%Z%%M% %I% %E% SMI" # -include ../Makefile.com +include ../../Makefile.com -LDFLAGS += -R/usr/lib/fm +SRCS = cpu.c +LDLIBS += -lkstat -include ../Makefile.targ +include ../../Makefile.targ install: all $(ROOTPROG) diff --git a/usr/src/cmd/fm/schemes/cpu/sparc/Makefile b/usr/src/cmd/fm/schemes/cpu/sparc/Makefile index bdf8e6911a..91f55c24df 100644 --- a/usr/src/cmd/fm/schemes/cpu/sparc/Makefile +++ b/usr/src/cmd/fm/schemes/cpu/sparc/Makefile @@ -26,11 +26,14 @@ # ident "%Z%%M% %I% %E% SMI" # -include ../Makefile.com +include ../../Makefile.com -LDLIBS += -L$(ROOTLIB)/fm -lmdesc +SRCS = cpu.c cpu_mdesc.c mdesc_devinit.c + +CPPFLAGS += -I. +LDLIBS += -L$(ROOTLIB)/fm -lmdesc -lkstat LDFLAGS += -R/usr/lib/fm -include ../Makefile.targ +include ../../Makefile.targ install: all $(ROOTPROG) diff --git a/usr/src/cmd/fm/schemes/cpu/cpu_mdesc.c b/usr/src/cmd/fm/schemes/cpu/sparc/cpu_mdesc.c index d14c14b17e..558ff36bdf 100644 --- a/usr/src/cmd/fm/schemes/cpu/cpu_mdesc.c +++ b/usr/src/cmd/fm/schemes/cpu/sparc/cpu_mdesc.c @@ -19,8 +19,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -32,8 +33,7 @@ #include <sys/param.h> #include <string.h> #include <errno.h> -#include <sys/mdesc.h> -#include <cpu.h> +#include <cpu_mdesc.h> int cpu_get_serialid_mdesc(uint32_t cpuid, uint64_t *serialidp) @@ -41,15 +41,14 @@ cpu_get_serialid_mdesc(uint32_t cpuid, uint64_t *serialidp) int i; md_cpumap_t *mcmp; - if (cpu.cpu_mdesc_cpus != NULL) { - for (i = 0, mcmp = cpu.cpu_mdesc_cpus; - i < cpu.cpu_mdesc_ncpus; i++, mcmp++) { - if (cpuid == mcmp->cpumap_pid) { - *serialidp = mcmp->cpumap_serialno; - return (0); - } + for (i = 0, mcmp = cpu.cpu_mdesc_cpus; + i < cpu.cpu_mdesc_ncpus; i++, mcmp++) { + if (cpuid == mcmp->cpumap_pid) { + *serialidp = mcmp->cpumap_serialno; + return (0); } } + return (fmd_fmri_set_errno(ENOENT)); } @@ -62,13 +61,11 @@ cpu_mdesc_init(void) int num_nodes, idx; size_t bufsiz = 0; - mdp = mdesc_devinit(&bufsiz); - if (mdp == NULL) + if ((mdp = mdesc_devinit(&bufsiz)) == NULL) return (0); /* successful, no mdesc */ num_nodes = md_node_count(mdp); - - listp = (mde_cookie_t *)fmd_fmri_alloc(sizeof (mde_cookie_t)*num_nodes); + listp = fmd_fmri_alloc(sizeof (mde_cookie_t) * num_nodes); cpu.cpu_mdesc_ncpus = md_scan_dag(mdp, MDE_INVAL_ELEM_COOKIE, @@ -96,16 +93,19 @@ cpu_mdesc_init(void) &mcmp->cpumap_serialno) < 0) mcmp->cpumap_serialno = 0; } - fmd_fmri_free(listp, sizeof (mde_cookie_t)*num_nodes); + + fmd_fmri_free(listp, sizeof (mde_cookie_t) * num_nodes); fmd_fmri_free(*mdp, bufsiz); (void) md_fini(mdp); + return (0); } void cpu_mdesc_fini(void) { - if (cpu.cpu_mdesc_cpus != NULL) + if (cpu.cpu_mdesc_cpus != NULL) { fmd_fmri_free(cpu.cpu_mdesc_cpus, cpu.cpu_mdesc_ncpus * sizeof (md_cpumap_t)); + } } diff --git a/usr/src/cmd/fm/schemes/cpu/cpu.h b/usr/src/cmd/fm/schemes/cpu/sparc/cpu_mdesc.h index 62d0661244..dc17f8032e 100644 --- a/usr/src/cmd/fm/schemes/cpu/cpu.h +++ b/usr/src/cmd/fm/schemes/cpu/sparc/cpu_mdesc.h @@ -19,8 +19,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -29,6 +30,9 @@ #pragma ident "%Z%%M% %I% %E% SMI" +#include <sys/types.h> +#include <sys/mdesc.h> + #ifdef __cplusplus extern "C" { #endif @@ -47,11 +51,8 @@ typedef struct cpu { extern cpu_t cpu; extern int cpu_get_serialid_mdesc(uint32_t, uint64_t *); - extern int cpu_mdesc_init(void); - extern void cpu_mdesc_fini(void); - extern md_t *mdesc_devinit(size_t *); #ifdef __cplusplus diff --git a/usr/src/cmd/fm/schemes/cpu/sparcv9/Makefile b/usr/src/cmd/fm/schemes/cpu/sparcv9/Makefile index b07e0556f5..c12b244ccd 100644 --- a/usr/src/cmd/fm/schemes/cpu/sparcv9/Makefile +++ b/usr/src/cmd/fm/schemes/cpu/sparcv9/Makefile @@ -26,12 +26,14 @@ # ident "%Z%%M% %I% %E% SMI" # -include ../Makefile.com +include ../../Makefile.com include $(SRC)/Makefile.master.64 -LDLIBS += -L$(ROOTLIB)/fm/$(MACH64) -lmdesc +SRCS = cpu.c cpu_mdesc.c mdesc_devinit.c +CPPFLAGS += -I../sparc +LDLIBS += -L$(ROOTLIB)/fm/$(MACH64) -lmdesc -lkstat LDFLAGS += -R/usr/lib/fm/$(MACH64) -include ../Makefile.targ +include ../../Makefile.targ install: all $(ROOTPROG64) diff --git a/usr/src/cmd/fm/schemes/mem/Makefile.com b/usr/src/cmd/fm/schemes/mem/Makefile.com index 4e8d6a9f93..bc1ca1a6bf 100644 --- a/usr/src/cmd/fm/schemes/mem/Makefile.com +++ b/usr/src/cmd/fm/schemes/mem/Makefile.com @@ -28,10 +28,7 @@ include ../../Makefile.com -SCHEME_COMMON = ../../common - SRCS = \ - mdesc_devinit.c \ mem.c \ mem_disc.c \ mem_read.c \ diff --git a/usr/src/cmd/fm/schemes/mem/amd64/Makefile b/usr/src/cmd/fm/schemes/mem/amd64/Makefile new file mode 100644 index 0000000000..639ceed3d8 --- /dev/null +++ b/usr/src/cmd/fm/schemes/mem/amd64/Makefile @@ -0,0 +1,36 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +include ../Makefile.com +include $(SRC)/Makefile.master.64 +include ../../Makefile.targ + +LDLIBS += -L$(ROOTLIB)/fm/$(MACH64) -ltopo +LDFLAGS += -R/usr/lib/fm/$(MACH64) + +install: all $(ROOTPROG64) diff --git a/usr/src/cmd/fm/schemes/mem/i386/Makefile b/usr/src/cmd/fm/schemes/mem/i386/Makefile new file mode 100644 index 0000000000..7062448fbf --- /dev/null +++ b/usr/src/cmd/fm/schemes/mem/i386/Makefile @@ -0,0 +1,35 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +include ../Makefile.com +include ../../Makefile.targ + +LDLIBS += -L$(ROOTLIB)/fm -ltopo +LDFLAGS += -R/usr/lib/fm + +install: all $(ROOTPROG) diff --git a/usr/src/cmd/fm/schemes/mem/i386/mem_disc.c b/usr/src/cmd/fm/schemes/mem/i386/mem_disc.c new file mode 100644 index 0000000000..062805108c --- /dev/null +++ b/usr/src/cmd/fm/schemes/mem/i386/mem_disc.c @@ -0,0 +1,39 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * We do not yet support DIMM enumeration in the x86 mem scheme because our + * diagnosis is using the new libtopo functionality and hopefully won't need + * this before we eventually replace scheme plug-ins entirely w/ libtopo. + */ +int +mem_discover(void) +{ + return (0); +} diff --git a/usr/src/cmd/fm/schemes/mem/mem.c b/usr/src/cmd/fm/schemes/mem/mem.c index 4a2a92c9c8..9d05f818c4 100644 --- a/usr/src/cmd/fm/schemes/mem/mem.c +++ b/usr/src/cmd/fm/schemes/mem/mem.c @@ -36,12 +36,9 @@ #include <time.h> #include <sys/mem.h> -/* - * The scheme plugin for mem FMRIs. - */ - mem_t mem; +#ifdef sparc /* * Retry values for handling the case where the kernel is not yet ready * to provide DIMM serial ids. Some platforms acquire DIMM serial id @@ -221,7 +218,10 @@ mem_get_serids_from_cache(const char *unum, char ***seridsp, size_t *nseridsp) return (rc); } +#else +/*ARGSUSED*/ static int +#endif /* sparc */ mem_get_serids_by_unum(const char *unum, char ***seridsp, size_t *nseridsp) { /* @@ -229,10 +229,15 @@ mem_get_serids_by_unum(const char *unum, char ***seridsp, size_t *nseridsp) * mem scheme plugin but instead support making serial ids available * via the kernel. */ +#ifdef sparc if (mem.mem_dm == NULL) return (mem_get_serids_from_kernel(unum, seridsp, nseridsp)); else return (mem_get_serids_from_cache(unum, seridsp, nseridsp)); +#else + errno = ENOTSUP; + return (-1); +#endif /* sparc */ } static int @@ -254,40 +259,70 @@ mem_fmri_get_unum(nvlist_t *nvl, char **unump) ssize_t fmd_fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen) { - const char *fmt = "mem:///component=%1$s"; + char format[64]; ssize_t size, presz; - uint64_t pa; - char *rawunum, *preunum, *escunum; + char *rawunum, *preunum, *escunum, *prefix; + uint64_t val; int i; if (mem_fmri_get_unum(nvl, &rawunum) < 0) return (-1); /* errno is set for us */ - if (nvlist_lookup_uint64(nvl, FM_FMRI_MEM_PHYSADDR, &pa) == 0) - fmt = "mem:///pa=%2$llx/component=%1$s"; + /* + * If we have a well-formed unum (hc-FMRI), use the string verbatim + * to form the initial mem:/// components. Otherwise use unum=%s. + */ + if (strncmp(rawunum, "hc:///", 6) != 0) + prefix = FM_FMRI_MEM_UNUM "="; + else + prefix = ""; /* - * If we leave the unum as-is, the spaces and colons will be escaped, - * rendering the resulting FMRI pretty much unreadable. We're therefore - * going to do some escaping of our own first. + * If we have a DIMM offset, include it in the string. If we have a PA + * then use that. Otherwise just format the unum element. */ - preunum = fmd_fmri_strdup(rawunum); - presz = strlen(preunum) + 1; - - for (i = 0; i < presz - 1; i++) { - if (preunum[i] == ':' && preunum[i + 1] == ' ') { - bcopy(preunum + i + 2, preunum + i + 1, - presz - (i + 2)); - } else if (preunum[i] == ' ') { - preunum[i] = ','; - } + if (nvlist_lookup_uint64(nvl, FM_FMRI_MEM_OFFSET, &val) == 0) { + (void) snprintf(format, sizeof (format), + "%s:///%s%%1$s/%s=%%2$llx", + FM_FMRI_SCHEME_MEM, prefix, FM_FMRI_MEM_OFFSET); + } else if (nvlist_lookup_uint64(nvl, FM_FMRI_MEM_PHYSADDR, &val) == 0) { + (void) snprintf(format, sizeof (format), + "%s:///%s%%1$s/%s=%%2$llx", + FM_FMRI_SCHEME_MEM, prefix, FM_FMRI_MEM_PHYSADDR); + } else { + (void) snprintf(format, sizeof (format), + "%s:///%s%%1$s", FM_FMRI_SCHEME_MEM, prefix); } - escunum = fmd_fmri_strescape(preunum); - fmd_fmri_free(preunum, presz); + /* + * If we have a well-formed unum (hc-FMRI), leave it as is. + * Otherwise, the spaces and colons will be escaped, + * rendering the resulting FMRI pretty much unreadable. + * We're therefore going to do some escaping of our own first. + */ + if (strncmp(rawunum, "hc:///", 6) == 0) { + /* LINTED: variable format specifier */ + size = snprintf(buf, buflen, format, rawunum + 6, val); + } else { + preunum = fmd_fmri_strdup(rawunum); + presz = strlen(preunum) + 1; + + for (i = 0; i < presz - 1; i++) { + if (preunum[i] == ':' && preunum[i + 1] == ' ') { + bcopy(preunum + i + 2, preunum + i + 1, + presz - (i + 2)); + } else if (preunum[i] == ' ') { + preunum[i] = ','; + } + } - size = snprintf(buf, buflen, fmt, escunum, (u_longlong_t)pa); - fmd_fmri_strfree(escunum); + escunum = fmd_fmri_strescape(preunum); + fmd_fmri_free(preunum, presz); + + /* LINTED: variable format specifier */ + size = snprintf(buf, buflen, format, escunum, val); + fmd_fmri_strfree(escunum); + } return (size); } @@ -409,7 +444,7 @@ int fmd_fmri_contains(nvlist_t *er, nvlist_t *ee) { char *erunum, *eeunum; - uint64_t erpa = 0, eepa = 0; + uint64_t erval = 0, eeval = 0; if (mem_fmri_get_unum(er, &erunum) < 0 || mem_fmri_get_unum(ee, &eeunum) < 0) @@ -418,47 +453,69 @@ fmd_fmri_contains(nvlist_t *er, nvlist_t *ee) if (mem_unum_contains(erunum, eeunum) <= 0) return (0); /* can't parse/match, so assume no containment */ - if (nvlist_lookup_uint64(er, FM_FMRI_MEM_PHYSADDR, &erpa) == 0) { - /* container has a PA; only match if containee has same PA */ - return (nvlist_lookup_uint64(ee, FM_FMRI_MEM_PHYSADDR, - &eepa) == 0 && erpa == eepa); + if (nvlist_lookup_uint64(er, FM_FMRI_MEM_OFFSET, &erval) == 0) { + return (nvlist_lookup_uint64(ee, + FM_FMRI_MEM_OFFSET, &eeval) == 0 && erval == eeval); + } + + if (nvlist_lookup_uint64(er, FM_FMRI_MEM_PHYSADDR, &erval) == 0) { + return (nvlist_lookup_uint64(ee, + FM_FMRI_MEM_PHYSADDR, &eeval) == 0 && erval == eeval); } return (1); } +/* + * We can only make a usable/unusable determination for pages. Mem FMRIs + * without page addresses will be reported as usable since Solaris has no + * way at present to dynamically disable an entire DIMM or DIMM pair. + */ int fmd_fmri_unusable(nvlist_t *nvl) { - uint64_t pageaddr; + uint64_t val; uint8_t version; - int rc, err; - - /* - * We can only make a usable/unusable determination for pages. FMRIs - * without page addresses will be reported as usable. - */ + int rc, err1, err2; + nvlist_t *nvlcp = NULL; + int retval; if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || version > FM_MEM_SCHEME_VERSION) return (fmd_fmri_set_errno(EINVAL)); - if ((err = nvlist_lookup_uint64(nvl, FM_FMRI_MEM_PHYSADDR, - &pageaddr)) == ENOENT) + err1 = nvlist_lookup_uint64(nvl, FM_FMRI_MEM_OFFSET, &val); + err2 = nvlist_lookup_uint64(nvl, FM_FMRI_MEM_PHYSADDR, &val); + + if (err1 == ENOENT && err2 == ENOENT) return (0); /* no page, so assume it's still usable */ - else if (err != 0) + + if ((err1 != 0 && err1 != ENOENT) || (err2 != 0 && err2 != ENOENT)) return (fmd_fmri_set_errno(EINVAL)); - if ((rc = mem_page_cmd(MEM_PAGE_FMRI_ISRETIRED, nvl)) < 0 && - errno == EIO) { - return (0); /* the page wonders, "why all the fuss?" */ + if ((err1 = mem_unum_rewrite(nvl, &nvlcp)) != 0) + return (fmd_fmri_set_errno(err1)); + + /* + * Ask the kernel if the page is retired, using either the rewritten + * hc FMRI or the original mem FMRI with the specified offset or PA. + * Refer to the kernel's page_retire_check() for the error codes. + */ + rc = mem_page_cmd(MEM_PAGE_FMRI_ISRETIRED, nvlcp ? nvlcp : nvl); + + if (rc == -1 && errno == EIO) { + /* + * The page is not retired and is not scheduled for retirement + * (i.e. no request pending and has not seen any errors) + */ + retval = 0; } else if (rc == 0 || errno == EAGAIN || errno == EINVAL) { /* * The page has been retired, is in the process of being * retired, or doesn't exist. The latter is valid if the page * existed in the past but has been DR'd out. */ - return (1); + retval = 1; } else { /* * Errors are only signalled to the caller if they're the @@ -466,21 +523,33 @@ fmd_fmri_unusable(nvlist_t *nvl) * retirement-check code. We'll whine about it and tell * the caller the page is unusable. */ - fmd_fmri_warn("failed to determine usability of page %llx", - pageaddr); - return (1); + fmd_fmri_warn("failed to determine page %s=%llx usability: " + "rc=%d errno=%d\n", err1 == 0 ? FM_FMRI_MEM_OFFSET : + FM_FMRI_MEM_PHYSADDR, (u_longlong_t)val, rc, errno); + retval = 1; } + + if (nvlcp) + nvlist_free(nvlcp); + + return (retval); } int fmd_fmri_init(void) { - bzero(&mem, sizeof (mem_t)); return (mem_discover()); } void fmd_fmri_fini(void) { - mem_destroy(); + mem_dimm_map_t *dm, *em; + + for (dm = mem.mem_dm; dm != NULL; dm = em) { + em = dm->dm_next; + fmd_fmri_strfree(dm->dm_label); + fmd_fmri_strfree(dm->dm_device); + fmd_fmri_free(dm, sizeof (mem_dimm_map_t)); + } } diff --git a/usr/src/cmd/fm/schemes/mem/mem.h b/usr/src/cmd/fm/schemes/mem/mem.h index 87ae40b322..d6a8f37b80 100644 --- a/usr/src/cmd/fm/schemes/mem/mem.h +++ b/usr/src/cmd/fm/schemes/mem/mem.h @@ -19,8 +19,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -30,7 +31,6 @@ #pragma ident "%Z%%M% %I% %E% SMI" #include <sys/types.h> -#include <sys/mdesc.h> #include <sys/nvpair.h> #ifdef __cplusplus @@ -105,8 +105,6 @@ extern "C" { /* 8+nul for SPD, 6+nul for SEEPROM, 15+nul max for Serengeti, Starcat, LW8 */ #define MEM_SERID_MAXLEN 16 -#define MDESC_PATH "%s/devices/pseudo/mdesc@0:mdesc" -#define MDESC_MAXPATHLEN 128 typedef struct mem_dimm_map { struct mem_dimm_map *dm_next; /* The next DIMM map */ @@ -119,18 +117,14 @@ typedef struct mem_dimm_map { typedef struct mem { mem_dimm_map_t *mem_dm; /* List supported DIMMs */ uint64_t mem_memconfig; /* HV memory-configuration-id# */ - md_t *mem_mdp; /* pointer to mdesc buffer */ - size_t mem_mdbufsz; /* size of mdesc buffer */ } mem_t; -extern md_t *mdesc_devinit(size_t *); extern int mem_discover(void); -extern void mem_destroy(void); - extern int mem_get_serid(const char *, char *, size_t); extern int mem_unum_burst(const char *, char ***, size_t *); extern int mem_unum_contains(const char *, const char *); +extern int mem_unum_rewrite(nvlist_t *, nvlist_t **); extern void mem_strarray_free(char **, size_t); extern int mem_page_cmd(int, nvlist_t *); diff --git a/usr/src/cmd/fm/schemes/mem/mem_unum.c b/usr/src/cmd/fm/schemes/mem/mem_unum.c index a418e2606f..04a3b16443 100644 --- a/usr/src/cmd/fm/schemes/mem/mem_unum.c +++ b/usr/src/cmd/fm/schemes/mem/mem_unum.c @@ -28,6 +28,7 @@ #include <mem.h> #include <fm/fmd_fmri.h> +#include <fm/libtopo.h> #include <string.h> #include <strings.h> @@ -368,3 +369,39 @@ mem_unum_contains(const char *erunum, const char *eeunum) return (rc); } + +/* + * If an asru has a unum string that is an hc path string then return + * a new nvl (to be freed by the caller) that is a duplicate of the + * original but with an additional member of a reconstituted hc fmri. + */ +int +mem_unum_rewrite(nvlist_t *nvl, nvlist_t **rnvl) +{ + int err; + char *unumstr; + nvlist_t *unum; + struct topo_hdl *thp; + + if (nvlist_lookup_string(nvl, FM_FMRI_MEM_UNUM, &unumstr) != 0 || + strncmp(unumstr, "hc:/", 4) != 0) + return (0); + + thp = fmd_fmri_topology(TOPO_VERSION); + + if (topo_fmri_str2nvl(thp, unumstr, &unum, &err) != 0) + return (EINVAL); + + if ((err = nvlist_dup(nvl, rnvl, 0)) != 0) { + nvlist_free(unum); + return (err); + } + + err = nvlist_add_nvlist(*rnvl, FM_FMRI_MEM_UNUM "-fmri", unum); + nvlist_free(unum); + + if (err != 0) + nvlist_free(*rnvl); + + return (err); +} diff --git a/usr/src/cmd/fm/schemes/mem/sparc/Makefile b/usr/src/cmd/fm/schemes/mem/sparc/Makefile index bdf8e6911a..c1f1bdc590 100644 --- a/usr/src/cmd/fm/schemes/mem/sparc/Makefile +++ b/usr/src/cmd/fm/schemes/mem/sparc/Makefile @@ -28,9 +28,10 @@ include ../Makefile.com -LDLIBS += -L$(ROOTLIB)/fm -lmdesc +SRCS += mdesc_devinit.c +LDLIBS += -L$(ROOTLIB)/fm -lmdesc -ltopo LDFLAGS += -R/usr/lib/fm -include ../Makefile.targ +include ../../Makefile.targ install: all $(ROOTPROG) diff --git a/usr/src/cmd/fm/schemes/mem/mem_disc.c b/usr/src/cmd/fm/schemes/mem/sparc/mem_disc.c index 20ca9ca5cc..fa031c1ac5 100644 --- a/usr/src/cmd/fm/schemes/mem/mem_disc.c +++ b/usr/src/cmd/fm/schemes/mem/sparc/mem_disc.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -44,6 +44,9 @@ * names) and the serial numbers of the dimms occupying those slots. */ +#include <sys/param.h> +#include <sys/mdesc.h> + #include <mem.h> #include <fm/fmd_fmri.h> @@ -52,7 +55,8 @@ #include <string.h> #include <strings.h> #include <errno.h> -#include <sys/param.h> + +extern md_t *mdesc_devinit(size_t *); #define PICL_FRUTREE_PATH \ "%s/usr/platform/%s/lib/picl/plugins/piclfrutree.conf" @@ -340,22 +344,19 @@ path_map_destroy(mem_path_map_t *pm) } int -mem_discover_mdesc(void) +mem_discover_mdesc(md_t *mdp, size_t mdbufsz) { mde_cookie_t *listp; int num_nodes, idx, mdesc_dimm_count; mem_dimm_map_t *dm; - md_t *mdp = mem.mem_mdp; num_nodes = md_node_count(mdp); - - listp = (mde_cookie_t *)fmd_fmri_alloc(sizeof (mde_cookie_t)*num_nodes); + listp = fmd_fmri_alloc(sizeof (mde_cookie_t) * num_nodes); /* * Find first 'memory' node -- there should only be one. Extract * 'memory-generation-id#' value from it. */ - mdesc_dimm_count = md_scan_dag(mdp, MDE_INVAL_ELEM_COOKIE, md_find_name(mdp, "memory"), md_find_name(mdp, "fwd"), listp); @@ -378,29 +379,17 @@ mem_discover_mdesc(void) dm = fmd_fmri_zalloc(sizeof (mem_dimm_map_t)); dm->dm_label = fmd_fmri_strdup(unum); - (void) strncpy(dm->dm_serid, serial, MEM_SERID_MAXLEN-1); + (void) strncpy(dm->dm_serid, serial, MEM_SERID_MAXLEN - 1); dm->dm_next = mem.mem_dm; mem.mem_dm = dm; } - fmd_fmri_free(listp, sizeof (mde_cookie_t)*num_nodes); - fmd_fmri_free(*mdp, mem.mem_mdbufsz); - (void) md_fini(mdp); - return (0); -} - -void -mem_destroy(void) -{ - mem_dimm_map_t *dm, *next; - for (dm = mem.mem_dm; dm != NULL; dm = next) { - next = dm->dm_next; + fmd_fmri_free(listp, sizeof (mde_cookie_t) * num_nodes); + fmd_fmri_free(*mdp, mdbufsz); - fmd_fmri_strfree(dm->dm_label); - fmd_fmri_strfree(dm->dm_device); - fmd_fmri_free(dm, sizeof (mem_dimm_map_t)); - } + (void) md_fini(mdp); + return (0); } int @@ -440,7 +429,6 @@ mem_discover_picl(void) } mem.mem_dm = dma.dma_dm; - return (0); } @@ -448,14 +436,14 @@ mem_discover_picl(void) * Sun4v: if a valid 'mdesc' machine description file exists, * read the mapping of dimm unum+jnum to serial number from it. */ - int mem_discover(void) { - mem.mem_mdp = mdesc_devinit(&mem.mem_mdbufsz); + size_t mdbufsz = 0; + md_t *mdp = mdesc_devinit(&mdbufsz); - if (mem.mem_mdp == NULL) + if (mdp == NULL) return (mem_discover_picl()); else - return (mem_discover_mdesc()); + return (mem_discover_mdesc(mdp, mdbufsz)); } diff --git a/usr/src/cmd/fm/schemes/mem/sparcv9/Makefile b/usr/src/cmd/fm/schemes/mem/sparcv9/Makefile index b07e0556f5..002728769a 100644 --- a/usr/src/cmd/fm/schemes/mem/sparcv9/Makefile +++ b/usr/src/cmd/fm/schemes/mem/sparcv9/Makefile @@ -29,9 +29,10 @@ include ../Makefile.com include $(SRC)/Makefile.master.64 -LDLIBS += -L$(ROOTLIB)/fm/$(MACH64) -lmdesc +SRCS += mdesc_devinit.c +LDLIBS += -L$(ROOTLIB)/fm/$(MACH64) -lmdesc -ltopo LDFLAGS += -R/usr/lib/fm/$(MACH64) -include ../Makefile.targ +include ../../Makefile.targ install: all $(ROOTPROG64) diff --git a/usr/src/cmd/fm/topo/files/Makefile b/usr/src/cmd/fm/topo/files/Makefile deleted file mode 100644 index 574ce9e926..0000000000 --- a/usr/src/cmd/fm/topo/files/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -SUBDIRS = $(MACH) - -include ../../Makefile.subdirs diff --git a/usr/src/cmd/fm/topo/files/Makefile.link b/usr/src/cmd/fm/topo/files/Makefile.link deleted file mode 100644 index 3b5c1edf6a..0000000000 --- a/usr/src/cmd/fm/topo/files/Makefile.link +++ /dev/null @@ -1,48 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -include ../../../../../Makefile.cmd - -ROOT_TOPO_ROOT = $(ROOT)/usr/lib/fm/topo -ROOT_TOPO_SDIR = $(ROOT_TOPO_ROOT)/$(TOPOSRCDIR) -ROOT_TOPO_DIR = $(ROOT_TOPO_ROOT)/$(TOPOTARGDIR) -ROOT_TOPOSRC = $(TOPOFILE:%=$(ROOT_TOPO_SDIR)/%) -ROOT_TOPOTARG = $(TOPOFILE:%=$(ROOT_TOPO_DIR)/%) - -include ../../../Makefile.rootdirs - -all clean install_h lint _msg: - -install:= FILEMODE = 0444 - -install: $(ROOT_TOPOTARG) - -clobber: - $(RM) $(ROOT_TOPOTARG) - -$(ROOT_TOPOTARG): $$(@D) - $(RM) $@; $(LN) $(ROOT_TOPOSRC) $(ROOT_TOPOTARG) diff --git a/usr/src/cmd/fm/topo/files/sparc/Makefile b/usr/src/cmd/fm/topo/files/sparc/Makefile deleted file mode 100644 index 7bbb0e2e99..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/Makefile +++ /dev/null @@ -1,55 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -SUBDIRS= \ - SUNW,Sun-Blade-1000 SUNW,Sun-Fire-880 SUNW,Sun-Fire-V240 \ - SUNW,Sun-Fire-480R SUNW,Netra-T12 \ - SUNW,Serverblade1 SUNW,Sun-Blade-100 \ - SUNW,Sun-Blade-1500 SUNW,Sun-Blade-2500 \ - SUNW,Sun-Fire SUNW,Sun-Fire-15000 \ - SUNW,Sun-Fire-V440 SUNW,Ultra-250 \ - SUNW,Ultra-30 SUNW,Ultra-4 SUNW,Ultra-5_10 SUNW,Ultra-60 \ - SUNW,Ultra-80 SUNW,UltraAX-i2 SUNW,Netra-210 \ - SUNW,Netra-T4 SUNW,Sun-Blade-2000 SUNW,Sun-Fire-280R \ - SUNW,Sun-Fire-V890 SUNW,Sun-Fire-V490 SUNW,Sun-Fire-V250 \ - SUNW,Sun-Fire-V210 SUNW,Netra-240 SUNW,Netra-440 \ - SUNW,Sun-Fire-T200 SUNW,Netra-CP3010 SUNW,A70 \ - SUNW,Sun-Fire-T1000 SUNW,Sun-Fire-V215 SUNW,Sun-Fire-V245 \ - SUNW,Sun-Fire-V445 - -include ../../../Makefile.subdirs - -SUNW,Netra-T4: SUNW,Sun-Blade-1000 -SUNW,Sun-Blade-2000: SUNW,Sun-Blade-1000 -SUNW,Sun-Fire-280R: SUNW,Sun-Blade-1000 -SUNW,Sun-Fire-V890: SUNW,Sun-Fire-880 -SUNW,Sun-Fire-V490: SUNW,Sun-Fire-480R -SUNW,Sun-Fire-V210: SUNW,Sun-Fire-V240 -SUNW,Sun-Fire-V250: SUNW,Sun-Fire-V240 -SUNW,Netra-240: SUNW,Sun-Fire-V240 -SUNW,Netra-440: SUNW,Sun-Fire-V440 -SUNW,Sun-Fire-V215: SUNW,Sun-Fire-V245 diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,A70/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,A70/Makefile deleted file mode 100644 index 3a8d5d0672..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,A70/Makefile +++ /dev/null @@ -1,55 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# - -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -include ../../../../../Makefile.cmd - -TOPOFILE = platform.topo -TOPOINCFILES = pcidev.topo pciexdev.topo -TOPOSRCDIR = SUNW,Sun-Fire-T200 -TOPOTARGDIR = SUNW,A70 -ROOT_TOPO_ROOT = $(ROOT)/usr/lib/fm/topo -ROOT_TOPO_SDIR = $(ROOT_TOPO_ROOT)/$(TOPOSRCDIR) -ROOT_TOPO_DIR = $(ROOT_TOPO_ROOT)/$(TOPOTARGDIR) -ROOT_TOPOFILE = $(TOPOFILE:%=$(ROOT_TOPO_DIR)/%) -ROOT_TOPOINCTARG = $(TOPOINCFILES:%=$(ROOT_TOPO_DIR)/%) - -include ../../../Makefile.rootdirs - -all: - -install:= FILEMODE = 0444 - -install: $(ROOT_TOPOFILE) $(ROOT_TOPOINCTARG) - -clobber: - $(RM) $(ROOT_TOPOFILE) $(ROOT_TOPOINCTARG) - -clean install_h lint _msg: - -$(ROOT_TOPO_DIR)/%: $(ROOT_TOPO_SDIR)/% - $(RM) $@; $(LN) $< $@ diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,A70/platform.topo b/usr/src/cmd/fm/topo/files/sparc/SUNW,A70/platform.topo deleted file mode 100644 index b55863c221..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,A70/platform.topo +++ /dev/null @@ -1,302 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (the "License"). -# You may not use this file except in compliance with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# - -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "%Z%%M% %I% %E% SMI" -# -/motherboard0 - PLAT-FRU = hc:///motherboard=0 -/motherboard0/cpumodule0/cpu[0] -/motherboard0/cpumodule1/cpu[1] -/motherboard0/hostbridge0 - PLAT-FRU = hc:///motherboard=0 -/motherboard0/hostbridge0/pciexrc0 - DEV = /pci@1e,600000 - PLAT-FRU = hc:///motherboard=0 - ON = true - DRIVER = px - EXCAP = pciexrc - DEVTYPE = pciex -/motherboard0/hostbridge0/pciexrc0/pciexbus2 - PLAT-FRU = hc:///motherboard=0 -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0 - PLAT-FRU = hc:///motherboard=0 -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0 - DEVICE-ID = 8532 - DEV = /pci@1e,600000/pci@0 - PLAT-FRU = hc:///motherboard=0 - VENDOR-ID = 10b5 - ON = true - DRIVER = px_pci - EXCAP = pciexswu - DEVTYPE = pciex -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3 - PLAT-FRU = hc:///motherboard=0 -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1 - PLAT-FRU = hc:///motherboard=0 -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0 - DEVICE-ID = 8532 - DEV = /pci@1e,600000/pci@0/pci@1 - PLAT-FRU = hc:///motherboard=0 - VENDOR-ID = 10b5 - ON = true - DRIVER = px_pci - EXCAP = pciexswd - DEVTYPE = pciex -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4 - PLAT-FRU = hc:///motherboard=0 -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0 - PLAT-FRU = hc:///motherboard=0 -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn0 - DEVICE-ID = 5249 - DEV = /pci@1e,600000/pci@0/pci@1/pci@0 - PLAT-FRU = hc:///motherboard=0 - VENDOR-ID = 10b9 - ON = true - DRIVER = px_pci - EXCAP = pcibus - DEVTYPE = pciex -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn0/pcibus5 - PLAT-FRU = hc:///motherboard=0 -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn0/pcibus5/pcidev28 - PLAT-FRU = hc:///motherboard=0 -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn0/pcibus5/pcidev28/pcifn0 - DEVICE-ID = 5237 - DEV = /pci@1e,600000/pci@0/pci@1/pci@0/usb@1c - PLAT-FRU = hc:///motherboard=0 - VENDOR-ID = 10b9 - ON = true - DRIVER = ohci -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn0/pcibus5/pcidev28/pcifn1 - DEVICE-ID = 5237 - DEV = /pci@1e,600000/pci@0/pci@1/pci@0/usb@1c,1 - PLAT-FRU = hc:///motherboard=0 - VENDOR-ID = 10b9 - ON = true - DRIVER = ohci -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn0/pcibus5/pcidev28/pcifn2 - DEVICE-ID = 5237 - DEV = /pci@1e,600000/pci@0/pci@1/pci@0/usb@1c,2 - PLAT-FRU = hc:///motherboard=0 - VENDOR-ID = 10b9 - ON = true - DRIVER = ohci -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn0/pcibus5/pcidev28/pcifn3 - DEVICE-ID = 5239 - DEV = /pci@1e,600000/pci@0/pci@1/pci@0/usb@1c,3 - PLAT-FRU = hc:///motherboard=0 - VENDOR-ID = 10b9 - ON = true - DRIVER = ehci -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn0/pcibus5/pcidev29 - PLAT-FRU = hc:///motherboard=0 -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn0/pcibus5/pcidev29/pcifn0 - DEVICE-ID = 5455 - DEV = /pci@1e,600000/pci@0/pci@1/pci@0/sound@1d - PLAT-FRU = hc:///motherboard=0 - VENDOR-ID = 10b9 - ON = true -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn0/pcibus5/pcidev29/pcifn1 - DEVICE-ID = 5457 - DEV = /pci@1e,600000/pci@0/pci@1/pci@0/pci10b9,5457@1d,1 - PLAT-FRU = hc:///motherboard=0 - VENDOR-ID = 10b9 - ON = true -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn0/pcibus5/pcidev30 - PLAT-FRU = hc:///motherboard=0 -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn0/pcibus5/pcidev30/pcifn0 - DEVICE-ID = 1575 - DEV = /pci@1e,600000/pci@0/pci@1/pci@0/isa@1e - PLAT-FRU = hc:///motherboard=0 - VENDOR-ID = 10b9 - ON = true - DRIVER = ebus -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn0/pcibus5/pcidev30/pcifn1 - DEVICE-ID = 7101 - DEV = /pci@1e,600000/pci@0/pci@1/pci@0/pmu@1e,1 - PLAT-FRU = hc:///motherboard=0 - VENDOR-ID = 10b9 - ON = true - DRIVER = pmubus -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn0/pcibus5/pcidev31 - PLAT-FRU = hc:///motherboard=0 -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn0/pcibus5/pcidev31/pcifn0 - DEVICE-ID = 5229 - DEV = /pci@1e,600000/pci@0/pci@1/pci@0/ide@1f - PLAT-FRU = hc:///motherboard=0 - VENDOR-ID = 10b9 - ON = true - DRIVER = uata - DEVTYPE = ide -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev2 - PLAT-FRU = hc:///motherboard=0 -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev2/pciexfn0 - DEVICE-ID = 8532 - DEV = /pci@1e,600000/pci@0/pci@2 - PLAT-FRU = hc:///motherboard=0 - VENDOR-ID = 10b5 - ON = true - DRIVER = px_pci - EXCAP = pciexswd - DEVTYPE = pciex -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev2/pciexfn0/pciexbus6 - PLAT-FRU = hc:///motherboard=0 -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev2/pciexfn0/pciexbus6/pciexdev0 - PLAT-FRU = hc:///motherboard=0 -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev2/pciexfn0/pciexbus6/pciexdev0/pciexfn0 - DEVICE-ID = 103 - DEV = /pci@1e,600000/pci@0/pci@2/pci@0 - PLAT-FRU = hc:///motherboard=0 - VENDOR-ID = 1166 - ON = true - DRIVER = px_pci - EXCAP = pcibus - DEVTYPE = pciex -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev2/pciexfn0/pciexbus6/pciexdev0/pciexfn0/pcibus7 - PLAT-FRU = hc:///motherboard=0 -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev2/pciexfn0/pciexbus6/pciexdev0/pciexfn0/pcibus7/pcidev4 - PLAT-FRU = hc:///motherboard=0 -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev2/pciexfn0/pciexbus6/pciexdev0/pciexfn0/pcibus7/pcidev4/pcifn0 - DEVICE-ID = 1678 - DEV = /pci@1e,600000/pci@0/pci@2/pci@0/network@4 - PLAT-FRU = hc:///motherboard=0 - VENDOR-ID = 14e4 - ON = true - DRIVER = bge - DEVTYPE = network -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev2/pciexfn0/pciexbus6/pciexdev0/pciexfn0/pcibus7/pcidev4/pcifn1 - DEVICE-ID = 1678 - DEV = /pci@1e,600000/pci@0/pci@2/pci@0/network@4,1 - PLAT-FRU = hc:///motherboard=0 - VENDOR-ID = 14e4 - ON = true - DRIVER = bge - DEVTYPE = network -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev3 - PLAT-FRU = hc:///motherboard=0 -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev3/pciexfn0 - DEVICE-ID = 8532 - DEV = /pci@1e,600000/pci@0/pci@3 - PLAT-FRU = hc:///motherboard=0 - VENDOR-ID = 10b5 - ON = true - DRIVER = px_pci - EXCAP = pciexswd - DEVTYPE = pciex -# -# Expansion slot 2 (PCI-Express) -# -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev3/pciexfn0/pciexbus[8] - PLAT-FRU = "hc:///component=SLOT 2" -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev3/pciexfn0/pciexbus[8]/pciexdev[0] - PLAT-FRU = "hc:///component=SLOT 2" -# -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev8 - PLAT-FRU = hc:///motherboard=0 -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev8/pciexfn0 - DEVICE-ID = 8532 - DEV = /pci@1e,600000/pci@0/pci@8 - PLAT-FRU = hc:///motherboard=0 - VENDOR-ID = 10b5 - ON = true - DRIVER = px_pci - EXCAP = pciexswd - DEVTYPE = pciex -# -# Expansion slot 3 (PCI-Express) -# -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev8/pciexfn0/pciexbus[9] - PLAT-FRU = "hc:///component=SLOT 3" -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev8/pciexfn0/pciexbus[9]/pciexdev[0] - PLAT-FRU = "hc:///component=SLOT 3" -# -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev9 - PLAT-FRU = hc:///motherboard=0 -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev9/pciexfn0 - DEVICE-ID = 8532 - DEV = /pci@1e,600000/pci@0/pci@9 - PLAT-FRU = hc:///motherboard=0 - VENDOR-ID = 10b5 - ON = true - DRIVER = px_pci - EXCAP = pciexswd - DEVTYPE = pciex -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev9/pciexfn0/pciexbus10 - PLAT-FRU = hc:///motherboard=0 -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev9/pciexfn0/pciexbus10/pciexdev0 - PLAT-FRU = hc:///motherboard=0 -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev9/pciexfn0/pciexbus10/pciexdev0/pciexfn0 - DEVICE-ID = 340 - DEV = /pci@1e,600000/pci@0/pci@9/pci@0 - PLAT-FRU = hc:///motherboard=0 - VENDOR-ID = 8086 - ON = true - DRIVER = px_pci - EXCAP = pcibus - DEVTYPE = pciex -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev9/pciexfn0/pciexbus10/pciexdev0/pciexfn0/pcibus11 - PLAT-FRU = hc:///motherboard=0 -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev9/pciexfn0/pciexbus10/pciexdev0/pciexfn0/pcibus11/pcidev1 - PLAT-FRU = hc:///motherboard=0 -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev9/pciexfn0/pciexbus10/pciexdev0/pciexfn0/pcibus11/pcidev1/pcifn0 - DEVICE-ID = 50 - DEV = /pci@1e,600000/pci@0/pci@9/pci@0/scsi@1 - PLAT-FRU = hc:///motherboard=0 - VENDOR-ID = 1000 - ON = true - DRIVER = mpt - DEVTYPE = scsi-2 -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev9/pciexfn0/pciexbus10/pciexdev0/pciexfn2 - DEVICE-ID = 341 - DEV = /pci@1e,600000/pci@0/pci@9/pci@0,2 - PLAT-FRU = hc:///motherboard=0 - VENDOR-ID = 8086 - ON = true - DRIVER = px_pci - EXCAP = pcibus - DEVTYPE = pciex -# -# Expansion slots 0 and 1 (PCI-X) -# -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev9/pciexfn0/pciexbus10/pciexdev0/pciexfn2/pcibus[12] - PLAT-FRU = hc:///motherboard=0 -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev9/pciexfn0/pciexbus10/pciexdev0/pciexfn2/pcibus[12]/pcidev[2] - PLAT-FRU = "hc:///component=SLOT 0" -/motherboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev9/pciexfn0/pciexbus10/pciexdev0/pciexfn2/pcibus[12]/pcidev[1] - PLAT-FRU = "hc:///component=SLOT 1" -# -/motherboard0/hostbridge0/pciexrc1 - DEV = /pci@1f,700000 - PLAT-FRU = hc:///motherboard=0 - ON = true - DRIVER = px - EXCAP = pciexrc - DEVTYPE = pciex -# -# Expansion slot 4 (PCI-Express, graphics) -# -/motherboard0/hostbridge0/pciexrc1/pciexbus[2] - PLAT-FRU = "hc:///component=SLOT 4" -/motherboard0/hostbridge0/pciexrc1/pciexbus[2]/pciexdev[0] - PLAT-FRU = "hc:///component=SLOT 4" diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/Makefile deleted file mode 100644 index 17a2ca9c00..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOSUBDIR = SUNW,Netra-210 -TOPOFILES = platform.topo - -include ../../Makefile.com diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/platform.topo b/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/platform.topo deleted file mode 100644 index 5cd6976d77..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/platform.topo +++ /dev/null @@ -1,48 +0,0 @@ -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -#ident "%Z%%M% %I% %E% SMI" - -# -# The CPUs on this platform are not considered FRUs. For this platform, -# a CPU problem means the whole motherboard must be replaced. -# Since no PLAT-FRU is specified, libtopo automatically assigns -# the motherboard as the FRU. -# -/motherboard0/cpu[0-1] -/motherboard0/hostbridge0 - DEV=/pci@1c -/motherboard0/hostbridge0/pcibus[0] - DEV=/pci@1c,600000 -/motherboard0/hostbridge0/pcibus[1] - .SLOTNM1="hc:///component=PCI 0" - DEV=/pci@1d,700000 -/motherboard0/hostbridge1 - DEV=/pci@1e -/motherboard0/hostbridge1/pcibus[0] - .SLOTNM2="hc:///component=PCI 1" - .SLOTNM3="hc:///component=PCI 2" - DEV=/pci@1e,600000 -/motherboard0/hostbridge1/pcibus[1] - DEV=/pci@1f,700000 diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-240/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-240/Makefile deleted file mode 100644 index 04a6489a52..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-240/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOFILE = platform.topo -TOPOSRCDIR = SUNW,Sun-Fire-V240 -TOPOTARGDIR = SUNW,Netra-240 - -include ../../Makefile.link diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-440/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-440/Makefile deleted file mode 100644 index 192b58a8ce..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-440/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOFILE = platform.topo -TOPOSRCDIR = SUNW,Sun-Fire-V440 -TOPOTARGDIR = SUNW,Netra-440 - -include ../../Makefile.link diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/Makefile deleted file mode 100644 index 8609abc0a4..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "%Z%%M% %I% %E% SMI" -# -TOPOSUBDIR = SUNW,Netra-CP3010 -TOPOFILES = platform.topo - -include ../../Makefile.com diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/platform.topo b/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/platform.topo deleted file mode 100644 index 33ccefd72b..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/platform.topo +++ /dev/null @@ -1,42 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -/motherboard0/cpumodule0/cpu[0] - PLAT-FRU=hc:///component=CPU0 -/motherboard0/cpu[1] - PLAT-FRU=hc:///component=CPU1 -/motherboard0/hostbridge0 - DEV=/pci@1c -/motherboard0/hostbridge0/pcibus[0] - DEV=/pci@1c,600000 -/motherboard0/hostbridge0/pcibus[1] - DEV=/pci@1d,700000 -/motherboard0/hostbridge1 - DEV=/pci@1e -/motherboard0/hostbridge1/pcibus[0] - DEV=/pci@1e,600000 -/motherboard0/hostbridge1/pcibus[1] - DEV=/pci@1f,700000 diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/Makefile deleted file mode 100644 index b4cd75dcb4..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOSUBDIR = SUNW,Netra-T12 -TOPOFILES = platform.topo - -include ../../Makefile.com diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/platform.topo b/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/platform.topo deleted file mode 100644 index b6b3b2ab7c..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/platform.topo +++ /dev/null @@ -1,31 +0,0 @@ -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -#ident "%Z%%M% %I% %E% SMI" - -/motherboard0/cpu0 -/motherboard0/hostbridge0 - DEV=/pci@1f -/motherboard0/hostbridge0/pcibus[0] - DEV=/pci@1f,0 diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T4/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T4/Makefile deleted file mode 100644 index 26472c41cc..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T4/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOFILE = platform.topo -TOPOSRCDIR = SUNW,Sun-Blade-1000 -TOPOTARGDIR = SUNW,Netra-T4 - -include ../../Makefile.link diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/Makefile deleted file mode 100644 index b932fafe47..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOSUBDIR = SUNW,Serverblade1 -TOPOFILES = platform.topo - -include ../../Makefile.com diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/platform.topo b/usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/platform.topo deleted file mode 100644 index af945e81f1..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/platform.topo +++ /dev/null @@ -1,36 +0,0 @@ -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -#ident "%Z%%M% %I% %E% SMI" - -/blade0 - PLAT-FRU="hc:///component=blade" -/blade0/cpu0 - PLAT-FRU="hc:///component=blade" -/blade0/hostbridge0 - DEV=/pci@1f - PLAT-FRU="hc:///component=blade" -/blade0/hostbridge0/pcibus[0] - DEV=/pci@1f,0 - PLAT-FRU="hc:///component=blade" diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/Makefile deleted file mode 100644 index 623338e2b0..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOSUBDIR = SUNW,Sun-Blade-100 -TOPOFILES = platform.topo - -include ../../Makefile.com diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/platform.topo b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/platform.topo deleted file mode 100644 index b6b3b2ab7c..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/platform.topo +++ /dev/null @@ -1,31 +0,0 @@ -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -#ident "%Z%%M% %I% %E% SMI" - -/motherboard0/cpu0 -/motherboard0/hostbridge0 - DEV=/pci@1f -/motherboard0/hostbridge0/pcibus[0] - DEV=/pci@1f,0 diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/Makefile deleted file mode 100644 index f3d82206fb..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOSUBDIR = SUNW,Sun-Blade-1000 -TOPOFILES = platform.topo - -include ../../Makefile.com diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/platform.topo b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/platform.topo deleted file mode 100644 index d00b1b193a..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/platform.topo +++ /dev/null @@ -1,36 +0,0 @@ -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -#ident "%Z%%M% %I% %E% SMI" - -/motherboard0/cpumodule0/cpu[0] - PLAT-FRU=hc:///component=CPU0 -/motherboard0/cpumodule0/cpu[1] - PLAT-FRU=hc:///component=CPU1 -/motherboard0/hostbridge0 - DEV=/pci@8 -/motherboard0/hostbridge0/pcibus[0] - DEV=/pci@8,600000 -/motherboard0/hostbridge0/pcibus[1] - DEV=/pci@8,700000 diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/Makefile deleted file mode 100644 index e8ccdf4f45..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOSUBDIR = SUNW,Sun-Blade-1500 -TOPOFILES = platform.topo - -include ../../Makefile.com diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/platform.topo b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/platform.topo deleted file mode 100644 index c0c66425fc..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/platform.topo +++ /dev/null @@ -1,34 +0,0 @@ -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -#ident "%Z%%M% %I% %E% SMI" - -/motherboard0/cpumodule0/cpu[0] - PLAT-FRU=hc:///component=CPU0 -/motherboard0/hostbridge0 - DEV=/pci@1e -/motherboard0/hostbridge0/pcibus[0] - DEV=/pci@1e,600000 -/motherboard0/hostbridge0/pcibus[1] - DEV=/pci@1f,700000 diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2000/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2000/Makefile deleted file mode 100644 index 5b5b83a1e3..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2000/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOFILE = platform.topo -TOPOSRCDIR = SUNW,Sun-Blade-1000 -TOPOTARGDIR = SUNW,Sun-Blade-2000 - -include ../../Makefile.link diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/Makefile deleted file mode 100644 index 1d199d3dc3..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOSUBDIR = SUNW,Sun-Blade-2500 -TOPOFILES = platform.topo - -include ../../Makefile.com diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/platform.topo b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/platform.topo deleted file mode 100644 index 3aff5d0863..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/platform.topo +++ /dev/null @@ -1,42 +0,0 @@ -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -#ident "%Z%%M% %I% %E% SMI" - -/motherboard0/cpumodule0/cpu[0] - PLAT-FRU=hc:///component=CPU0 -/motherboard0/cpu[1] - PLAT-FRU=hc:///component=CPU1 -/motherboard0/hostbridge0 - DEV=/pci@1c -/motherboard0/hostbridge0/pcibus[0] - DEV=/pci@1c,600000 -/motherboard0/hostbridge0/pcibus[1] - DEV=/pci@1d,700000 -/motherboard0/hostbridge1 - DEV=/pci@1e -/motherboard0/hostbridge1/pcibus[0] - DEV=/pci@1e,600000 -/motherboard0/hostbridge1/pcibus[1] - DEV=/pci@1f,700000 diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/Makefile deleted file mode 100644 index 8708fe41ef..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOSUBDIR = SUNW,Sun-Fire-15000 -TOPOFILES = platform.topo - -include ../../Makefile.com diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/platform.topo b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/platform.topo deleted file mode 100644 index 7965029b45..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/platform.topo +++ /dev/null @@ -1,917 +0,0 @@ -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -#ident "%Z%%M% %I% %E% SMI" - -/interconnect0/systemboard[0] - PLAT-ASRU=hc:///component=SB0 - PLAT-FRU=hc:///component=SB0 -/interconnect0/systemboard[0]/cpu[0-3] -/interconnect0/systemboard[1] - PLAT-ASRU=hc:///component=SB1 - PLAT-FRU=hc:///component=SB1 -/interconnect0/systemboard[1]/cpu[32-35] -/interconnect0/systemboard[2] - PLAT-ASRU=hc:///component=SB2 - PLAT-FRU=hc:///component=SB1 -/interconnect0/systemboard[2]/cpu[64-67] -/interconnect0/systemboard[3] - PLAT-ASRU=hc:///component=SB3 - PLAT-FRU=hc:///component=SB3 -/interconnect0/systemboard[3]/cpu[96-99] -/interconnect0/systemboard[4] - PLAT-ASRU=hc:///component=SB4 - PLAT-FRU=hc:///component=SB4 -/interconnect0/systemboard[4]/cpu[128-131] -/interconnect0/systemboard[5] - PLAT-ASRU=hc:///component=SB5 - PLAT-FRU=hc:///component=SB5 -/interconnect0/systemboard[5]/cpu[160-163] -/interconnect0/systemboard[6] - PLAT-ASRU=hc:///component=SB6 - PLAT-FRU=hc:///component=SB6 -/interconnect0/systemboard[6]/cpu[192-195] -/interconnect0/systemboard[7] - PLAT-ASRU=hc:///component=SB7 - PLAT-FRU=hc:///component=SB7 -/interconnect0/systemboard[7]/cpu[224-227] -/interconnect0/systemboard[8] - PLAT-ASRU=hc:///component=SB8 - PLAT-FRU=hc:///component=SB8 -/interconnect0/systemboard[8]/cpu[256-259] -/interconnect0/systemboard[9] - PLAT-ASRU=hc:///component=SB9 - PLAT-FRU=hc:///component=SB9 -/interconnect0/systemboard[9]/cpu[288-291] -/interconnect0/systemboard[10] - PLAT-ASRU=hc:///component=SB10 - PLAT-FRU=hc:///component=SB10 -/interconnect0/systemboard[10]/cpu[320-323] -/interconnect0/systemboard[11] - PLAT-ASRU=hc:///component=SB11 - PLAT-FRU=hc:///component=SB11 -/interconnect0/systemboard[11]/cpu[352-355] -/interconnect0/systemboard[12] - PLAT-ASRU=hc:///component=SB12 - PLAT-FRU=hc:///component=SB12 -/interconnect0/systemboard[12]/cpu[384-387] -/interconnect0/systemboard[13] - PLAT-ASRU=hc:///component=SB13 - PLAT-FRU=hc:///component=SB13 -/interconnect0/systemboard[13]/cpu[416-419] -/interconnect0/systemboard[14] - PLAT-ASRU=hc:///component=SB14 - PLAT-FRU=hc:///component=SB14 -/interconnect0/systemboard[14]/cpu[448-451] -/interconnect0/systemboard[15] - PLAT-ASRU=hc:///component=SB15 - PLAT-FRU=hc:///component=SB15 -/interconnect0/systemboard[15]/cpu[480-483] -/interconnect0/systemboard[16] - PLAT-ASRU=hc:///component=SB16 - PLAT-FRU=hc:///component=SB16 -/interconnect0/systemboard[16]/cpu[512-515] -/interconnect0/systemboard[17] - PLAT-ASRU=hc:///component=SB17 - PLAT-FRU=hc:///component=SB17 -/interconnect0/systemboard[17]/cpu[544-547] -/interconnect0/maxcpu[0]/cpu[8-9] - PLAT-ASRU=hc:///component=IO0 - PLAT-FRU=hc:///component=IO0 -/interconnect0/maxcpu[1]/cpu[40-41] - PLAT-ASRU=hc:///component=IO1 - PLAT-FRU=hc:///component=IO1 -/interconnect0/maxcpu[2]/cpu[72-73] - PLAT-ASRU=hc:///component=IO2 - PLAT-FRU=hc:///component=IO2 -/interconnect0/maxcpu[3]/cpu[104-105] - PLAT-ASRU=hc:///component=IO3 - PLAT-FRU=hc:///component=IO3 -/interconnect0/maxcpu[4]/cpu[136-137] - PLAT-ASRU=hc:///component=IO4 - PLAT-FRU=hc:///component=IO4 -/interconnect0/maxcpu[5]/cpu[168-169] - PLAT-ASRU=hc:///component=IO5 - PLAT-FRU=hc:///component=IO5 -/interconnect0/maxcpu[6]/cpu[200-201] - PLAT-ASRU=hc:///component=IO6 - PLAT-FRU=hc:///component=IO6 -/interconnect0/maxcpu[7]/cpu[232-233] - PLAT-ASRU=hc:///component=IO7 - PLAT-FRU=hc:///component=IO7 -/interconnect0/maxcpu[8]/cpu[264-265] - PLAT-ASRU=hc:///component=IO8 - PLAT-FRU=hc:///component=IO8 -/interconnect0/maxcpu[9]/cpu[296-297] - PLAT-ASRU=hc:///component=IO9 - PLAT-FRU=hc:///component=IO9 -/interconnect0/maxcpu[10]/cpu[328-329] - PLAT-ASRU=hc:///component=IO10 - PLAT-FRU=hc:///component=IO10 -/interconnect0/maxcpu[11]/cpu[360-361] - PLAT-ASRU=hc:///component=IO11 - PLAT-FRU=hc:///component=IO11 -/interconnect0/maxcpu[12]/cpu[392-393] - PLAT-ASRU=hc:///component=IO12 - PLAT-FRU=hc:///component=IO12 -/interconnect0/maxcpu[13]/cpu[424-425] - PLAT-ASRU=hc:///component=IO13 - PLAT-FRU=hc:///component=IO13 -/interconnect0/maxcpu[14]/cpu[456-457] - PLAT-ASRU=hc:///component=IO14 - PLAT-FRU=hc:///component=IO14 -/interconnect0/maxcpu[15]/cpu[488-489] - PLAT-ASRU=hc:///component=IO15 - PLAT-FRU=hc:///component=IO15 -/interconnect0/maxcpu[16]/cpu[520-521] - PLAT-ASRU=hc:///component=IO16 - PLAT-FRU=hc:///component=IO16 -/interconnect0/ioboard[0] - PLAT-ASRU=hc:///component=IO0 - PLAT-FRU=hc:///component=IO0 -/interconnect0/ioboard[0]/hostbridge0 - PLAT-ASRU=hc:///component=IO0 - PLAT-FRU=hc:///component=IO0 - DEV=/pci@1c -/interconnect0/ioboard[0]/hostbridge0/pcibus[0] - DEV=/pci@1c,600000 -/interconnect0/ioboard[0]/hostbridge0/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch1:e00b1slot0 - PLAT-FRU=hc:///component=IO0/C3V0 -/interconnect0/ioboard[0]/hostbridge0/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch1:e00b1slot0 - PLAT-FRU=hc:///component=IO0/C3V0 -/interconnect0/ioboard[0]/hostbridge0/pcibus[1] - DEV=/pci@1c,700000 -/interconnect0/ioboard[0]/hostbridge0/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch0:e00b1slot1 - PLAT-FRU=hc:///component=IO0/C5V0 -/interconnect0/ioboard[0]/hostbridge0/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch0:e00b1slot1 - PLAT-FRU=hc:///component=IO0/C5V0 -/interconnect0/ioboard[0]/hostbridge1 - PLAT-ASRU=hc:///component=IO0 - PLAT-FRU=hc:///component=IO0 - DEV=/pci@1d -/interconnect0/ioboard[0]/hostbridge1/pcibus[0] - DEV=/pci@1d,600000 -/interconnect0/ioboard[0]/hostbridge1/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch3:e00b1slot2 - PLAT-FRU=hc:///component=IO0/C3V1 -/interconnect0/ioboard[0]/hostbridge1/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch3:e00b1slot2 - PLAT-FRU=hc:///component=IO0/C3V1 -/interconnect0/ioboard[0]/hostbridge1/pcibus[1] - DEV=/pci@1d,700000 -/interconnect0/ioboard[0]/hostbridge1/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch2:e00b1slot3 - PLAT-FRU=hc:///component=IO0/C5V1 -/interconnect0/ioboard[0]/hostbridge1/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch2:e00b1slot3 - PLAT-FRU=hc:///component=IO0/C5V1 -/interconnect0/ioboard[1] - PLAT-ASRU=hc:///component=IO1 - PLAT-FRU=hc:///component=IO1 -/interconnect0/ioboard[1]/hostbridge0 - PLAT-ASRU=hc:///component=IO1 - PLAT-FRU=hc:///component=IO1 - DEV=/pci@3c -/interconnect0/ioboard[1]/hostbridge0/pcibus[0] - DEV=/pci@3c,600000 -/interconnect0/ioboard[1]/hostbridge0/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch1:e01b1slot0 - PLAT-FRU=hc:///component=IO1/C3V0 -/interconnect0/ioboard[1]/hostbridge0/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch1:e01b1slot0 - PLAT-FRU=hc:///component=IO1/C3V0 -/interconnect0/ioboard[1]/hostbridge0/pcibus[1] - DEV=/pci@3c,700000 -/interconnect0/ioboard[1]/hostbridge0/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch0:e01b1slot1 - PLAT-FRU=hc:///component=IO1/C5V0 -/interconnect0/ioboard[1]/hostbridge0/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch0:e01b1slot1 - PLAT-FRU=hc:///component=IO1/C5V0 -/interconnect0/ioboard[1]/hostbridge1 - PLAT-ASRU=hc:///component=IO1 - PLAT-FRU=hc:///component=IO1 - DEV=/pci@3d -/interconnect0/ioboard[1]/hostbridge1/pcibus[0] - DEV=/pci@3d,600000 -/interconnect0/ioboard[1]/hostbridge1/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch3:e01b1slot2 - PLAT-FRU=hc:///component=IO1/C3V1 -/interconnect0/ioboard[1]/hostbridge1/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch3:e01b1slot2 - PLAT-FRU=hc:///component=IO1/C3V1 -/interconnect0/ioboard[1]/hostbridge1/pcibus[1] - DEV=/pci@3d,700000 -/interconnect0/ioboard[1]/hostbridge1/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch2:e01b1slot3 - PLAT-FRU=hc:///component=IO1/C5V1 -/interconnect0/ioboard[1]/hostbridge1/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch2:e01b1slot3 - PLAT-FRU=hc:///component=IO1/C5V1 -/interconnect0/ioboard[2] - PLAT-ASRU=hc:///component=IO2 - PLAT-FRU=hc:///component=IO2 -/interconnect0/ioboard[2]/hostbridge0 - PLAT-ASRU=hc:///component=IO2 - PLAT-FRU=hc:///component=IO2 - DEV=/pci@5c -/interconnect0/ioboard[2]/hostbridge0/pcibus[0] - DEV=/pci@5c,600000 -/interconnect0/ioboard[2]/hostbridge0/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch1:e02b1slot0 - PLAT-FRU=hc:///component=IO2/C3V0 -/interconnect0/ioboard[2]/hostbridge0/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch1:e02b1slot0 - PLAT-FRU=hc:///component=IO2/C3V0 -/interconnect0/ioboard[2]/hostbridge0/pcibus[1] - DEV=/pci@5c,700000 -/interconnect0/ioboard[2]/hostbridge0/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch0:e02b1slot1 - PLAT-FRU=hc:///component=IO2/C5V0 -/interconnect0/ioboard[2]/hostbridge0/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch0:e02b1slot1 - PLAT-FRU=hc:///component=IO2/C5V0 -/interconnect0/ioboard[2]/hostbridge1 - PLAT-ASRU=hc:///component=IO2 - PLAT-FRU=hc:///component=IO2 - DEV=/pci@5d -/interconnect0/ioboard[2]/hostbridge1/pcibus[0] - DEV=/pci@5d,600000 -/interconnect0/ioboard[2]/hostbridge1/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch3:e02b1slot2 - PLAT-FRU=hc:///component=IO2/C3V1 -/interconnect0/ioboard[2]/hostbridge1/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch3:e02b1slot2 - PLAT-FRU=hc:///component=IO2/C3V1 -/interconnect0/ioboard[2]/hostbridge1/pcibus[1] - DEV=/pci@5d,700000 -/interconnect0/ioboard[2]/hostbridge1/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch2:e02b1slot3 - PLAT-FRU=hc:///component=IO2/C5V1 -/interconnect0/ioboard[2]/hostbridge1/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch2:e02b1slot3 - PLAT-FRU=hc:///component=IO2/C5V1 -/interconnect0/ioboard[3] - PLAT-ASRU=hc:///component=IO3 - PLAT-FRU=hc:///component=IO3 -/interconnect0/ioboard[3]/hostbridge0 - PLAT-ASRU=hc:///component=IO3 - PLAT-FRU=hc:///component=IO3 - DEV=/pci@7c -/interconnect0/ioboard[3]/hostbridge0/pcibus[0] - DEV=/pci@7c,600000 -/interconnect0/ioboard[3]/hostbridge0/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch1:e03b1slot0 - PLAT-FRU=hc:///component=IO3/C3V0 -/interconnect0/ioboard[3]/hostbridge0/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch1:e03b1slot0 - PLAT-FRU=hc:///component=IO3/C3V0 -/interconnect0/ioboard[3]/hostbridge0/pcibus[1] - DEV=/pci@7c,700000 -/interconnect0/ioboard[3]/hostbridge0/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch0:e03b1slot1 - PLAT-FRU=hc:///component=IO3/C5V0 -/interconnect0/ioboard[3]/hostbridge0/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch0:e03b1slot1 - PLAT-FRU=hc:///component=IO3/C5V0 -/interconnect0/ioboard[3]/hostbridge1 - PLAT-ASRU=hc:///component=IO3 - PLAT-FRU=hc:///component=IO3 - DEV=/pci@7d -/interconnect0/ioboard[3]/hostbridge1/pcibus[0] - DEV=/pci@7d,600000 -/interconnect0/ioboard[3]/hostbridge1/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch3:e03b1slot2 - PLAT-FRU=hc:///component=IO3/C3V1 -/interconnect0/ioboard[3]/hostbridge1/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch3:e03b1slot2 - PLAT-FRU=hc:///component=IO3/C3V1 -/interconnect0/ioboard[3]/hostbridge1/pcibus[1] - DEV=/pci@7d,700000 -/interconnect0/ioboard[3]/hostbridge1/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch2:e03b1slot3 - PLAT-FRU=hc:///component=IO3/C5V1 -/interconnect0/ioboard[3]/hostbridge1/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch2:e03b1slot3 - PLAT-FRU=hc:///component=IO3/C5V1 -/interconnect0/ioboard[4] - PLAT-ASRU=hc:///component=IO4 - PLAT-FRU=hc:///component=IO4 -/interconnect0/ioboard[4]/hostbridge0 - PLAT-ASRU=hc:///component=IO4 - PLAT-FRU=hc:///component=IO4 - DEV=/pci@9c -/interconnect0/ioboard[4]/hostbridge0/pcibus[0] - DEV=/pci@9c,600000 -/interconnect0/ioboard[4]/hostbridge0/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch1:e04b1slot0 - PLAT-FRU=hc:///component=IO4/C3V0 -/interconnect0/ioboard[4]/hostbridge0/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch1:e04b1slot0 - PLAT-FRU=hc:///component=IO4/C3V0 -/interconnect0/ioboard[4]/hostbridge0/pcibus[1] - DEV=/pci@9c,700000 -/interconnect0/ioboard[4]/hostbridge0/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch0:e04b1slot1 - PLAT-FRU=hc:///component=IO4/C5V0 -/interconnect0/ioboard[4]/hostbridge0/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch0:e04b1slot1 - PLAT-FRU=hc:///component=IO4/C5V0 -/interconnect0/ioboard[4]/hostbridge1 - PLAT-ASRU=hc:///component=IO4 - PLAT-FRU=hc:///component=IO4 - DEV=/pci@9d -/interconnect0/ioboard[4]/hostbridge1/pcibus[0] - DEV=/pci@9d,600000 -/interconnect0/ioboard[4]/hostbridge1/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch3:e04b1slot2 - PLAT-FRU=hc:///component=IO4/C3V1 -/interconnect0/ioboard[4]/hostbridge1/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch3:e04b1slot2 - PLAT-FRU=hc:///component=IO4/C3V1 -/interconnect0/ioboard[4]/hostbridge1/pcibus[1] - DEV=/pci@9d,700000 -/interconnect0/ioboard[4]/hostbridge1/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch2:e04b1slot3 - PLAT-FRU=hc:///component=IO4/C5V1 -/interconnect0/ioboard[4]/hostbridge1/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch2:e04b1slot3 - PLAT-FRU=hc:///component=IO4/C5V1 -/interconnect0/ioboard[5] - PLAT-ASRU=hc:///component=IO5 - PLAT-FRU=hc:///component=IO5 -/interconnect0/ioboard[5]/hostbridge0 - PLAT-ASRU=hc:///component=IO5 - PLAT-FRU=hc:///component=IO5 - DEV=/pci@bc -/interconnect0/ioboard[5]/hostbridge0/pcibus[0] - DEV=/pci@bc,600000 -/interconnect0/ioboard[5]/hostbridge0/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch1:e05b1slot0 - PLAT-FRU=hc:///component=IO5/C3V0 -/interconnect0/ioboard[5]/hostbridge0/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch1:e05b1slot0 - PLAT-FRU=hc:///component=IO5/C3V0 -/interconnect0/ioboard[5]/hostbridge0/pcibus[1] - DEV=/pci@bc,700000 -/interconnect0/ioboard[5]/hostbridge0/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch0:e05b1slot1 - PLAT-FRU=hc:///component=IO5/C5V0 -/interconnect0/ioboard[5]/hostbridge0/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch0:e05b1slot1 - PLAT-FRU=hc:///component=IO5/C5V0 -/interconnect0/ioboard[5]/hostbridge1 - PLAT-ASRU=hc:///component=IO5 - PLAT-FRU=hc:///component=IO5 - DEV=/pci@bd -/interconnect0/ioboard[5]/hostbridge1/pcibus[0] - DEV=/pci@bd,600000 -/interconnect0/ioboard[5]/hostbridge1/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch3:e05b1slot2 - PLAT-FRU=hc:///component=IO5/C3V1 -/interconnect0/ioboard[5]/hostbridge1/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch3:e05b1slot2 - PLAT-FRU=hc:///component=IO5/C3V1 -/interconnect0/ioboard[5]/hostbridge1/pcibus[1] - DEV=/pci@bd,700000 -/interconnect0/ioboard[5]/hostbridge1/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch2:e05b1slot3 - PLAT-FRU=hc:///component=IO5/C5V1 -/interconnect0/ioboard[5]/hostbridge1/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch2:e05b1slot3 - PLAT-FRU=hc:///component=IO5/C5V1 -/interconnect0/ioboard[6] - PLAT-ASRU=hc:///component=IO6 - PLAT-FRU=hc:///component=IO6 -/interconnect0/ioboard[6]/hostbridge0 - PLAT-ASRU=hc:///component=IO6 - PLAT-FRU=hc:///component=IO6 - DEV=/pci@dc -/interconnect0/ioboard[6]/hostbridge0/pcibus[0] - DEV=/pci@dc,600000 -/interconnect0/ioboard[6]/hostbridge0/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch1:e06b1slot0 - PLAT-FRU=hc:///component=IO6/C3V0 -/interconnect0/ioboard[6]/hostbridge0/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch1:e06b1slot0 - PLAT-FRU=hc:///component=IO6/C3V0 -/interconnect0/ioboard[6]/hostbridge0/pcibus[1] - DEV=/pci@dc,700000 -/interconnect0/ioboard[6]/hostbridge0/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch0:e06b1slot1 - PLAT-FRU=hc:///component=IO6/C5V0 -/interconnect0/ioboard[6]/hostbridge0/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch0:e06b1slot1 - PLAT-FRU=hc:///component=IO6/C5V0 -/interconnect0/ioboard[6]/hostbridge1 - PLAT-ASRU=hc:///component=IO6 - PLAT-FRU=hc:///component=IO6 - DEV=/pci@dd -/interconnect0/ioboard[6]/hostbridge1/pcibus[0] - DEV=/pci@dd,600000 -/interconnect0/ioboard[6]/hostbridge1/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch3:e06b1slot2 - PLAT-FRU=hc:///component=IO6/C3V1 -/interconnect0/ioboard[6]/hostbridge1/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch3:e06b1slot2 - PLAT-FRU=hc:///component=IO6/C3V1 -/interconnect0/ioboard[6]/hostbridge1/pcibus[1] - DEV=/pci@dd,700000 -/interconnect0/ioboard[6]/hostbridge1/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch2:e06b1slot3 - PLAT-FRU=hc:///component=IO6/C5V1 -/interconnect0/ioboard[6]/hostbridge1/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch2:e06b1slot3 - PLAT-FRU=hc:///component=IO6/C5V1 -/interconnect0/ioboard[7] - PLAT-ASRU=hc:///component=IO7 - PLAT-FRU=hc:///component=IO7 -/interconnect0/ioboard[7]/hostbridge0 - PLAT-ASRU=hc:///component=IO7 - PLAT-FRU=hc:///component=IO7 - DEV=/pci@fc -/interconnect0/ioboard[7]/hostbridge0/pcibus[0] - DEV=/pci@fc,600000 -/interconnect0/ioboard[7]/hostbridge0/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch1:e07b1slot0 - PLAT-FRU=hc:///component=IO7/C3V0 -/interconnect0/ioboard[7]/hostbridge0/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch1:e07b1slot0 - PLAT-FRU=hc:///component=IO7/C3V0 -/interconnect0/ioboard[7]/hostbridge0/pcibus[1] - DEV=/pci@fc,700000 -/interconnect0/ioboard[7]/hostbridge0/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch0:e07b1slot1 - PLAT-FRU=hc:///component=IO7/C5V0 -/interconnect0/ioboard[7]/hostbridge0/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch0:e07b1slot1 - PLAT-FRU=hc:///component=IO7/C5V0 -/interconnect0/ioboard[7]/hostbridge1 - PLAT-ASRU=hc:///component=IO7 - PLAT-FRU=hc:///component=IO7 - DEV=/pci@fd -/interconnect0/ioboard[7]/hostbridge1/pcibus[0] - DEV=/pci@fd,600000 -/interconnect0/ioboard[7]/hostbridge1/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch3:e07b1slot2 - PLAT-FRU=hc:///component=IO7/C3V1 -/interconnect0/ioboard[7]/hostbridge1/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch3:e07b1slot2 - PLAT-FRU=hc:///component=IO7/C3V1 -/interconnect0/ioboard[7]/hostbridge1/pcibus[1] - DEV=/pci@fd,700000 -/interconnect0/ioboard[7]/hostbridge1/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch2:e07b1slot3 - PLAT-FRU=hc:///component=IO7/C5V1 -/interconnect0/ioboard[7]/hostbridge1/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch2:e07b1slot3 - PLAT-FRU=hc:///component=IO7/C5V1 -/interconnect0/ioboard[8] - PLAT-ASRU=hc:///component=IO8 - PLAT-FRU=hc:///component=IO8 -/interconnect0/ioboard[8]/hostbridge0 - PLAT-ASRU=hc:///component=IO8 - PLAT-FRU=hc:///component=IO8 - DEV=/pci@11c -/interconnect0/ioboard[8]/hostbridge0/pcibus[0] - DEV=/pci@11c,600000 -/interconnect0/ioboard[8]/hostbridge0/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch1:e08b1slot0 - PLAT-FRU=hc:///component=IO8/C3V0 -/interconnect0/ioboard[8]/hostbridge0/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch1:e08b1slot0 - PLAT-FRU=hc:///component=IO8/C3V0 -/interconnect0/ioboard[8]/hostbridge0/pcibus[1] - DEV=/pci@11c,700000 -/interconnect0/ioboard[8]/hostbridge0/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch0:e08b1slot1 - PLAT-FRU=hc:///component=IO8/C5V0 -/interconnect0/ioboard[8]/hostbridge0/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch0:e08b1slot1 - PLAT-FRU=hc:///component=IO8/C5V0 -/interconnect0/ioboard[8]/hostbridge1 - PLAT-ASRU=hc:///component=IO8 - PLAT-FRU=hc:///component=IO8 - DEV=/pci@11d -/interconnect0/ioboard[8]/hostbridge1/pcibus[0] - DEV=/pci@11d,600000 -/interconnect0/ioboard[8]/hostbridge1/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch3:e08b1slot2 - PLAT-FRU=hc:///component=IO8/C3V1 -/interconnect0/ioboard[8]/hostbridge1/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch3:e08b1slot2 - PLAT-FRU=hc:///component=IO8/C3V1 -/interconnect0/ioboard[8]/hostbridge1/pcibus[1] - DEV=/pci@11d,700000 -/interconnect0/ioboard[9] - PLAT-ASRU=hc:///component=IO9 - PLAT-FRU=hc:///component=IO9 -/interconnect0/ioboard[9]/hostbridge0 - PLAT-ASRU=hc:///component=IO9 - PLAT-FRU=hc:///component=IO9 - DEV=/pci@13c -/interconnect0/ioboard[9]/hostbridge0/pcibus[0] - DEV=/pci@13c,600000 -/interconnect0/ioboard[9]/hostbridge0/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch1:e09b1slot0 - PLAT-FRU=hc:///component=IO9/C3V0 -/interconnect0/ioboard[9]/hostbridge0/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch1:e09b1slot0 - PLAT-FRU=hc:///component=IO9/C3V0 -/interconnect0/ioboard[9]/hostbridge0/pcibus[1] - DEV=/pci@13c,700000 -/interconnect0/ioboard[9]/hostbridge0/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch0:e09b1slot1 - PLAT-FRU=hc:///component=IO9/C5V0 -/interconnect0/ioboard[9]/hostbridge0/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch0:e09b1slot1 - PLAT-FRU=hc:///component=IO9/C5V0 -/interconnect0/ioboard[9]/hostbridge1 - PLAT-ASRU=hc:///component=IO9 - PLAT-FRU=hc:///component=IO9 - DEV=/pci@13d -/interconnect0/ioboard[9]/hostbridge1/pcibus[0] - DEV=/pci@13d,600000 -/interconnect0/ioboard[9]/hostbridge1/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch3:e09b1slot2 - PLAT-FRU=hc:///component=IO9/C3V1 -/interconnect0/ioboard[9]/hostbridge1/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch3:e09b1slot2 - PLAT-FRU=hc:///component=IO9/C3V1 -/interconnect0/ioboard[9]/hostbridge1/pcibus[1] - DEV=/pci@13d,700000 -/interconnect0/ioboard[9]/hostbridge1/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch2:e09b1slot3 - PLAT-FRU=hc:///component=IO9/C5V1 -/interconnect0/ioboard[9]/hostbridge1/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch2:e09b1slot3 - PLAT-FRU=hc:///component=IO9/C5V1 -/interconnect0/ioboard[10] - PLAT-ASRU=hc:///component=IO10 - PLAT-FRU=hc:///component=IO10 -/interconnect0/ioboard[10]/hostbridge0 - PLAT-ASRU=hc:///component=IO10 - PLAT-FRU=hc:///component=IO10 - DEV=/pci@15c -/interconnect0/ioboard[10]/hostbridge0/pcibus[0] - DEV=/pci@15c,600000 -/interconnect0/ioboard[10]/hostbridge0/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch1:e10b1slot0 - PLAT-FRU=hc:///component=IO10/C3V0 -/interconnect0/ioboard[10]/hostbridge0/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch1:e10b1slot0 - PLAT-FRU=hc:///component=IO10/C3V0 -/interconnect0/ioboard[10]/hostbridge0/pcibus[1] - DEV=/pci@15c,700000 -/interconnect0/ioboard[10]/hostbridge0/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch0:e10b1slot1 - PLAT-FRU=hc:///component=IO10/C5V0 -/interconnect0/ioboard[10]/hostbridge0/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch0:e10b1slot1 - PLAT-FRU=hc:///component=IO10/C5V0 -/interconnect0/ioboard[10]/hostbridge1 - PLAT-ASRU=hc:///component=IO10 - PLAT-FRU=hc:///component=IO10 - DEV=/pci@15d -/interconnect0/ioboard[10]/hostbridge1/pcibus[0] - DEV=/pci@15d,600000 -/interconnect0/ioboard[10]/hostbridge1/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch3:e10b1slot2 - PLAT-FRU=hc:///component=IO10/C3V1 -/interconnect0/ioboard[10]/hostbridge1/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch3:e10b1slot2 - PLAT-FRU=hc:///component=IO10/C3V1 -/interconnect0/ioboard[10]/hostbridge1/pcibus[1] - DEV=/pci@15d,700000 -/interconnect0/ioboard[10]/hostbridge1/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch2:e10b1slot3 - PLAT-FRU=hc:///component=IO10/C5V1 -/interconnect0/ioboard[10]/hostbridge1/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch2:e10b1slot3 - PLAT-FRU=hc:///component=IO10/C5V1 -/interconnect0/ioboard[11] - PLAT-ASRU=hc:///component=IO11 - PLAT-FRU=hc:///component=IO11 -/interconnect0/ioboard[11]/hostbridge0 - PLAT-ASRU=hc:///component=IO11 - PLAT-FRU=hc:///component=IO11 - DEV=/pci@17c -/interconnect0/ioboard[11]/hostbridge0/pcibus[0] - DEV=/pci@17c,600000 -/interconnect0/ioboard[11]/hostbridge0/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch1:e11b1slot0 - PLAT-FRU=hc:///component=IO11/C3V0 -/interconnect0/ioboard[11]/hostbridge0/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch1:e11b1slot0 - PLAT-FRU=hc:///component=IO11/C3V0 -/interconnect0/ioboard[11]/hostbridge0/pcibus[1] - DEV=/pci@17c,700000 -/interconnect0/ioboard[11]/hostbridge0/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch0:e11b1slot1 - PLAT-FRU=hc:///component=IO11/C5V0 -/interconnect0/ioboard[11]/hostbridge0/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch0:e11b1slot1 - PLAT-FRU=hc:///component=IO11/C5V0 -/interconnect0/ioboard[11]/hostbridge1 - PLAT-ASRU=hc:///component=IO11 - PLAT-FRU=hc:///component=IO11 - DEV=/pci@17d -/interconnect0/ioboard[11]/hostbridge1/pcibus[0] - DEV=/pci@17d,600000 -/interconnect0/ioboard[11]/hostbridge1/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch3:e11b1slot2 - PLAT-FRU=hc:///component=IO11/C3V1 -/interconnect0/ioboard[11]/hostbridge1/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch3:e11b1slot2 - PLAT-FRU=hc:///component=IO11/C3V1 -/interconnect0/ioboard[11]/hostbridge1/pcibus[1] - DEV=/pci@17d,700000 -/interconnect0/ioboard[11]/hostbridge1/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch2:e11b1slot3 - PLAT-FRU=hc:///component=IO11/C5V1 -/interconnect0/ioboard[11]/hostbridge1/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch2:e11b1slot3 - PLAT-FRU=hc:///component=IO11/C5V1 -/interconnect0/ioboard[12] - PLAT-ASRU=hc:///component=IO12 - PLAT-FRU=hc:///component=IO12 -/interconnect0/ioboard[12]/hostbridge0 - PLAT-ASRU=hc:///component=IO12 - PLAT-FRU=hc:///component=IO12 - DEV=/pci@19c -/interconnect0/ioboard[12]/hostbridge0/pcibus[0] - DEV=/pci@19c,600000 -/interconnect0/ioboard[12]/hostbridge0/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch1:e12b1slot0 - PLAT-FRU=hc:///component=IO12/C3V0 -/interconnect0/ioboard[12]/hostbridge0/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch1:e12b1slot0 - PLAT-FRU=hc:///component=IO12/C3V0 -/interconnect0/ioboard[12]/hostbridge0/pcibus[1] - DEV=/pci@19c,700000 -/interconnect0/ioboard[12]/hostbridge0/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch0:e12b1slot1 - PLAT-FRU=hc:///component=IO12/C5V0 -/interconnect0/ioboard[12]/hostbridge0/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch0:e12b1slot1 - PLAT-FRU=hc:///component=IO12/C5V0 -/interconnect0/ioboard[12]/hostbridge1 - PLAT-ASRU=hc:///component=IO12 - PLAT-FRU=hc:///component=IO12 - DEV=/pci@19d -/interconnect0/ioboard[12]/hostbridge1/pcibus[0] - DEV=/pci@19d,600000 -/interconnect0/ioboard[12]/hostbridge1/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch3:e12b1slot2 - PLAT-FRU=hc:///component=IO12/C3V1 -/interconnect0/ioboard[12]/hostbridge1/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch3:e12b1slot2 - PLAT-FRU=hc:///component=IO12/C3V1 -/interconnect0/ioboard[12]/hostbridge1/pcibus[1] - DEV=/pci@19d,700000 -/interconnect0/ioboard[12]/hostbridge1/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch2:e12b1slot3 - PLAT-FRU=hc:///component=IO12/C5V1 -/interconnect0/ioboard[12]/hostbridge1/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch2:e12b1slot3 - PLAT-FRU=hc:///component=IO12/C5V1 -/interconnect0/ioboard[13] - PLAT-ASRU=hc:///component=IO13 - PLAT-FRU=hc:///component=IO13 -/interconnect0/ioboard[13]/hostbridge0 - PLAT-ASRU=hc:///component=IO13 - PLAT-FRU=hc:///component=IO13 - DEV=/pci@1bc -/interconnect0/ioboard[13]/hostbridge0/pcibus[0] - DEV=/pci@1bc,600000 -/interconnect0/ioboard[13]/hostbridge0/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch1:e13b1slot0 - PLAT-FRU=hc:///component=IO13/C3V0 -/interconnect0/ioboard[13]/hostbridge0/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch1:e13b1slot0 - PLAT-FRU=hc:///component=IO13/C3V0 -/interconnect0/ioboard[13]/hostbridge0/pcibus[1] - DEV=/pci@1bc,700000 -/interconnect0/ioboard[13]/hostbridge0/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch0:e13b1slot1 - PLAT-FRU=hc:///component=IO13/C5V0 -/interconnect0/ioboard[13]/hostbridge0/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch0:e13b1slot1 - PLAT-FRU=hc:///component=IO13/C5V0 -/interconnect0/ioboard[13]/hostbridge1 - PLAT-ASRU=hc:///component=IO13 - PLAT-FRU=hc:///component=IO13 - DEV=/pci@1bd -/interconnect0/ioboard[13]/hostbridge1/pcibus[0] - DEV=/pci@1bd,600000 -/interconnect0/ioboard[13]/hostbridge1/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch3:e13b1slot2 - PLAT-FRU=hc:///component=IO13/C3V1 -/interconnect0/ioboard[13]/hostbridge1/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch3:e13b1slot2 - PLAT-FRU=hc:///component=IO13/C3V1 -/interconnect0/ioboard[13]/hostbridge1/pcibus[1] - DEV=/pci@1bd,700000 -/interconnect0/ioboard[13]/hostbridge1/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch2:e13b1slot3 - PLAT-FRU=hc:///component=IO13/C5V1 -/interconnect0/ioboard[13]/hostbridge1/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch2:e13b1slot3 - PLAT-FRU=hc:///component=IO13/C5V1 -/interconnect0/ioboard[14] - PLAT-ASRU=hc:///component=IO14 - PLAT-FRU=hc:///component=IO14 -/interconnect0/ioboard[14]/hostbridge0 - PLAT-ASRU=hc:///component=IO14 - PLAT-FRU=hc:///component=IO14 - DEV=/pci@1dc -/interconnect0/ioboard[14]/hostbridge0/pcibus[0] - DEV=/pci@1dc,600000 -/interconnect0/ioboard[14]/hostbridge0/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch1:e14b1slot0 - PLAT-FRU=hc:///component=IO14/C3V0 -/interconnect0/ioboard[14]/hostbridge0/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch1:e14b1slot0 - PLAT-FRU=hc:///component=IO14/C3V0 -/interconnect0/ioboard[14]/hostbridge0/pcibus[1] - DEV=/pci@1dc,700000 -/interconnect0/ioboard[14]/hostbridge0/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch0:e14b1slot1 - PLAT-FRU=hc:///component=IO14/C5V0 -/interconnect0/ioboard[14]/hostbridge0/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch0:e14b1slot1 - PLAT-FRU=hc:///component=IO14/C5V0 -/interconnect0/ioboard[14]/hostbridge1 - PLAT-ASRU=hc:///component=IO14 - PLAT-FRU=hc:///component=IO14 - DEV=/pci@1dd -/interconnect0/ioboard[14]/hostbridge1/pcibus[0] - DEV=/pci@1dd,600000 -/interconnect0/ioboard[14]/hostbridge1/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch3:e14b1slot2 - PLAT-FRU=hc:///component=IO14/C3V1 -/interconnect0/ioboard[14]/hostbridge1/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch3:e14b1slot2 - PLAT-FRU=hc:///component=IO14/C3V1 -/interconnect0/ioboard[14]/hostbridge1/pcibus[1] - DEV=/pci@1dd,700000 -/interconnect0/ioboard[14]/hostbridge1/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch2:e14b1slot3 - PLAT-FRU=hc:///component=IO14/C5V1 -/interconnect0/ioboard[14]/hostbridge1/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch2:e14b1slot3 - PLAT-FRU=hc:///component=IO14/C5V1 -/interconnect0/ioboard[15] - PLAT-ASRU=hc:///component=IO15 - PLAT-FRU=hc:///component=IO15 -/interconnect0/ioboard[15]/hostbridge0 - PLAT-ASRU=hc:///component=IO15 - PLAT-FRU=hc:///component=IO15 - DEV=/pci@1fc -/interconnect0/ioboard[15]/hostbridge0/pcibus[0] - DEV=/pci@1fc,600000 -/interconnect0/ioboard[15]/hostbridge0/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch1:e15b1slot0 - PLAT-FRU=hc:///component=IO15/C3V0 -/interconnect0/ioboard[15]/hostbridge0/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch1:e15b1slot0 - PLAT-FRU=hc:///component=IO15/C3V0 -/interconnect0/ioboard[15]/hostbridge0/pcibus[1] - DEV=/pci@1fc,700000 -/interconnect0/ioboard[15]/hostbridge0/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch0:e15b1slot1 - PLAT-FRU=hc:///component=IO15/C5V0 -/interconnect0/ioboard[15]/hostbridge0/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch0:e15b1slot1 - PLAT-FRU=hc:///component=IO15/C5V0 -/interconnect0/ioboard[15]/hostbridge1 - PLAT-ASRU=hc:///component=IO15 - PLAT-FRU=hc:///component=IO15 - DEV=/pci@1fd -/interconnect0/ioboard[15]/hostbridge1/pcibus[0] - DEV=/pci@1fd,600000 -/interconnect0/ioboard[15]/hostbridge1/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch3:e15b1slot2 - PLAT-FRU=hc:///component=IO15/C3V1 -/interconnect0/ioboard[15]/hostbridge1/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch3:e15b1slot2 - PLAT-FRU=hc:///component=IO15/C3V1 -/interconnect0/ioboard[15]/hostbridge1/pcibus[1] - DEV=/pci@1fd,700000 -/interconnect0/ioboard[15]/hostbridge1/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch2:e15b1slot3 - PLAT-FRU=hc:///component=IO15/C5V1 -/interconnect0/ioboard[15]/hostbridge1/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch2:e15b1slot3 - PLAT-FRU=hc:///component=IO15/C5V1 -/interconnect0/ioboard[16] - PLAT-ASRU=hc:///component=IO16 - PLAT-FRU=hc:///component=IO16 -/interconnect0/ioboard[16]/hostbridge0 - PLAT-ASRU=hc:///component=IO16 - PLAT-FRU=hc:///component=IO16 - DEV=/pci@21c -/interconnect0/ioboard[16]/hostbridge0/pcibus[0] - DEV=/pci@21c,600000 -/interconnect0/ioboard[16]/hostbridge0/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch1:e16b1slot0 - PLAT-FRU=hc:///component=IO16/C3V0 -/interconnect0/ioboard[16]/hostbridge0/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch1:e16b1slot0 - PLAT-FRU=hc:///component=IO16/C3V0 -/interconnect0/ioboard[16]/hostbridge0/pcibus[1] - DEV=/pci@21c,700000 -/interconnect0/ioboard[16]/hostbridge0/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch0:e16b1slot1 - PLAT-FRU=hc:///component=IO16/C5V0 -/interconnect0/ioboard[16]/hostbridge0/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch0:e16b1slot1 - PLAT-FRU=hc:///component=IO16/C5V0 -/interconnect0/ioboard[16]/hostbridge1 - PLAT-ASRU=hc:///component=IO16 - PLAT-FRU=hc:///component=IO16 - DEV=/pci@21d -/interconnect0/ioboard[16]/hostbridge1/pcibus[0] - DEV=/pci@21d,600000 -/interconnect0/ioboard[16]/hostbridge1/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch3:e16b1slot2 - PLAT-FRU=hc:///component=IO16/C3V1 -/interconnect0/ioboard[16]/hostbridge1/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch3:e16b1slot2 - PLAT-FRU=hc:///component=IO16/C3V1 -/interconnect0/ioboard[16]/hostbridge1/pcibus[1] - DEV=/pci@21d,700000 -/interconnect0/ioboard[16]/hostbridge1/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch2:e16b1slot3 - PLAT-FRU=hc:///component=IO16/C5V1 -/interconnect0/ioboard[16]/hostbridge1/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch2:e16b1slot3 - PLAT-FRU=hc:///component=IO16/C5V1 -/interconnect0/ioboard[17] - PLAT-ASRU=hc:///component=IO17 - PLAT-FRU=hc:///component=IO17 -/interconnect0/ioboard[17]/hostbridge0 - PLAT-ASRU=hc:///component=IO17 - PLAT-FRU=hc:///component=IO17 - DEV=/pci@23c -/interconnect0/ioboard[17]/hostbridge0/pcibus[0] - DEV=/pci@23c,600000 -/interconnect0/ioboard[17]/hostbridge0/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch1:e17b1slot0 - PLAT-FRU=hc:///component=IO17/C3V0 -/interconnect0/ioboard[17]/hostbridge0/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch1:e17b1slot0 - PLAT-FRU=hc:///component=IO17/C3V0 -/interconnect0/ioboard[17]/hostbridge0/pcibus[1] - DEV=/pci@23c,700000 -/interconnect0/ioboard[17]/hostbridge0/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch0:e17b1slot1 - PLAT-FRU=hc:///component=IO17/C5V0 -/interconnect0/ioboard[17]/hostbridge0/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch0:e17b1slot1 - PLAT-FRU=hc:///component=IO17/C5V0 -/interconnect0/ioboard[17]/hostbridge1 - PLAT-ASRU=hc:///component=IO17 - PLAT-FRU=hc:///component=IO17 - DEV=/pci@23d -/interconnect0/ioboard[17]/hostbridge1/pcibus[0] - DEV=/pci@23d,600000 -/interconnect0/ioboard[17]/hostbridge1/pcibus[0]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch3:e17b1slot2 - PLAT-FRU=hc:///component=IO17/C3V1 -/interconnect0/ioboard[17]/hostbridge1/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch3:e17b1slot2 - PLAT-FRU=hc:///component=IO17/C3V1 -/interconnect0/ioboard[17]/hostbridge1/pcibus[1] - DEV=/pci@23d,700000 -/interconnect0/ioboard[17]/hostbridge1/pcibus[1]/pcidev[1] - PLAT-ASRU=hc:///component=pcisch2:e17b1slot3 - PLAT-FRU=hc:///component=IO17/C5V1 -/interconnect0/ioboard[17]/hostbridge1/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-ASRU=hc:///component=pcisch2:e17b1slot3 - PLAT-FRU=hc:///component=IO17/C5V1 diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-280R/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-280R/Makefile deleted file mode 100644 index fc151bb329..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-280R/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOFILE = platform.topo -TOPOSRCDIR = SUNW,Sun-Blade-1000 -TOPOTARGDIR = SUNW,Sun-Fire-280R - -include ../../Makefile.link diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/Makefile deleted file mode 100644 index c2cf89171c..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOSUBDIR = SUNW,Sun-Fire-480R -TOPOFILES = platform.topo - -include ../../Makefile.com diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/platform.topo b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/platform.topo deleted file mode 100644 index 7510d663ec..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/platform.topo +++ /dev/null @@ -1,46 +0,0 @@ -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -#ident "%Z%%M% %I% %E% SMI" - -/motherboard0/systemboard[0] - PLAT-FRU="hc:///component=Slot A" -/motherboard0/systemboard[0]/cpu[0] -/motherboard0/systemboard[0]/cpu[2] -/motherboard0/systemboard[1] - PLAT-FRU="hc:///component=Slot B" -/motherboard0/systemboard[1]/cpu[1] -/motherboard0/systemboard[1]/cpu[3] -/motherboard0/hostbridge0 - DEV=/pci@8 -/motherboard0/hostbridge0/pcibus[0] - DEV=/pci@8,600000 -/motherboard0/hostbridge0/pcibus[1] - DEV=/pci@8,700000 -/motherboard0/hostbridge1 - DEV=/pci@9 -/motherboard0/hostbridge1/pcibus[0] - DEV=/pci@9,600000 -/motherboard0/hostbridge1/pcibus[1] - DEV=/pci@9,700000 diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/Makefile deleted file mode 100644 index 55f1ec0243..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOSUBDIR = SUNW,Sun-Fire-880 -TOPOFILES = platform.topo - -include ../../Makefile.com diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/platform.topo b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/platform.topo deleted file mode 100644 index 3cb91171c7..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/platform.topo +++ /dev/null @@ -1,54 +0,0 @@ -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -#ident "%Z%%M% %I% %E% SMI" - -/motherboard0/systemboard[0] - PLAT-FRU="hc:///component=Slot A" -/motherboard0/systemboard[0]/cpu[0] -/motherboard0/systemboard[0]/cpu[2] -/motherboard0/systemboard[1] - PLAT-FRU="hc:///component=Slot B" -/motherboard0/systemboard[1]/cpu[1] -/motherboard0/systemboard[1]/cpu[3] -/motherboard0/systemboard[2] - PLAT-FRU="hc:///component=Slot C" -/motherboard0/systemboard[2]/cpu[4] -/motherboard0/systemboard[2]/cpu[6] -/motherboard0/systemboard[3] - PLAT-FRU="hc:///component=Slot D" -/motherboard0/systemboard[3]/cpu[5] -/motherboard0/systemboard[3]/cpu[7] -/motherboard0/hostbridge0 - DEV=/pci@8 -/motherboard0/hostbridge0/pcibus[0] - DEV=/pci@8,600000 -/motherboard0/hostbridge0/pcibus[1] - DEV=/pci@8,700000 -/motherboard0/hostbridge1 - DEV=/pci@9 -/motherboard0/hostbridge1/pcibus[0] - DEV=/pci@9,600000 -/motherboard0/hostbridge1/pcibus[1] - DEV=/pci@9,700000 diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/Makefile deleted file mode 100644 index d1ca0989ed..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# - -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOSUBDIR = SUNW,Sun-Fire-T200 -TOPOFILES = platform.topo pcidev.topo pciexdev.topo - -include ../../Makefile.com diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/platform.topo b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/platform.topo deleted file mode 100644 index 7eadf1e78e..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/platform.topo +++ /dev/null @@ -1,323 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (the "License"). -# You may not use this file except in compliance with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# - -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - - -# -# Single mother board -# -/motherboard0 - PLAT-FRU=hc:///component=MB - -# -# CPU chip -# -/motherboard0/cmp0 - PLAT-FRU=hc:///component=MB/CMP0 - -# -# 32 strands -# -/motherboard0/cmp0/cpu[0-31] - -# -# Single IO board and all the root complexes, switches and on-board devices -# -/ioboard0 - PLAT-FRU = hc:///component=IOBD -/ioboard0/hostbridge0 -/ioboard0/hostbridge0/pciexrc0 - DEV = /pci@780 - PLAT-FRU = hc:///component=IOBD - ON = true - DRIVER = px - EXCAP = pciexrc - DEVTYPE = pciex -/ioboard0/hostbridge0/pciexrc0/pciexbus2 - PLAT-FRU = hc:///component=IOBD -/ioboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0 - PLAT-FRU = hc:///component=IOBD -/ioboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0 - DEVICE-ID = 8532 - DEV = /pci@780/pci@0 - PLAT-FRU = hc:///component=IOBD - VENDOR-ID = 10b5 - ON = true - DRIVER = px_pci - EXCAP = pciexswu - DEVTYPE = pciex -/ioboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3 - PLAT-FRU = hc:///component=IOBD -/ioboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1 - PLAT-FRU = hc:///component=IOBD -/ioboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0 - DEVICE-ID = 8532 - DEV = /pci@780/pci@0/pci@1 - PLAT-FRU = hc:///component=IOBD - VENDOR-ID = 10b5 - ON = true - DRIVER = px_pci - EXCAP = pciexswd - DEVTYPE = pciex -/ioboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4 - PLAT-FRU = hc:///component=IOBD -/ioboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0 - PLAT-FRU = hc:///component=IOBD -/ioboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn0 - DEVICE-ID = 105e - DEV = /pci@780/pci@0/pci@1/network@0 - PLAT-FRU = hc:///component=IOBD - VENDOR-ID = 8086 - ON = true - DRIVER = ipge - DEVTYPE = network -/ioboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn1 - DEVICE-ID = 105e - DEV = /pci@780/pci@0/pci@1/network@0,1 - PLAT-FRU = hc:///component=IOBD - VENDOR-ID = 8086 - ON = true - DRIVER = ipge - DEVTYPE = network -/ioboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev2 - PLAT-FRU = hc:///component=IOBD -/ioboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev2/pciexfn0 - DEVICE-ID = 8532 - DEV = /pci@780/pci@0/pci@2 - PLAT-FRU = hc:///component=IOBD - VENDOR-ID = 10b5 - ON = true - DRIVER = px_pci - EXCAP = pciexswd - DEVTYPE = pciex -/ioboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev8 - PLAT-FRU = hc:///component=IOBD -/ioboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev8/pciexfn0 - DEVICE-ID = 8532 - DEV = /pci@780/pci@0/pci@8 - PLAT-FRU = hc:///component=IOBD - VENDOR-ID = 10b5 - ON = true - DRIVER = px_pci - EXCAP = pciexswd - DEVTYPE = pciex -# -# Expansion slot PCI0 (PCI-Express) -# -/ioboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev8/pciexfn0/pciexbus6 - PLAT-FRU = hc:///component=PCIE0 -/ioboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev8/pciexfn0/pciexbus6/pciexdev[0] - PLAT-FRU = hc:///component=PCIE0 -# -/ioboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev9 - PLAT-FRU = hc:///component=IOBD -/ioboard0/hostbridge0/pciexrc0/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev9/pciexfn0 - DEVICE-ID = 8532 - DEV = /pci@780/pci@0/pci@9 - PLAT-FRU = hc:///component=IOBD - VENDOR-ID = 10b5 - ON = true - DRIVER = px_pci - EXCAP = pciexswd - DEVTYPE = pciex -/ioboard0/hostbridge0/pciexrc1 - DEV = /pci@7c0 - PLAT-FRU = hc:///component=IOBD - ON = true - DRIVER = px - EXCAP = pciexrc - DEVTYPE = pciex -/ioboard0/hostbridge0/pciexrc1/pciexbus2 - PLAT-FRU = hc:///component=IOBD -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0 - PLAT-FRU = hc:///component=IOBD -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0 - DEVICE-ID = 8532 - DEV = /pci@7c0/pci@0 - PLAT-FRU = hc:///component=IOBD - VENDOR-ID = 10b5 - ON = true - DRIVER = px_pci - EXCAP = pciexswu - DEVTYPE = pciex -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3 - PLAT-FRU = hc:///component=IOBD -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1 - PLAT-FRU = hc:///component=IOBD -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0 - DEVICE-ID = 8532 - DEV = /pci@7c0/pci@0/pci@1 - PLAT-FRU = hc:///component=IOBD - VENDOR-ID = 10b5 - ON = true - DRIVER = px_pci - EXCAP = pciexswd - DEVTYPE = pciex -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4 - PLAT-FRU = hc:///component=IOBD -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0 - PLAT-FRU = hc:///component=IOBD -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn0 - DEVICE-ID = 340 - DEV = /pci@7c0/pci@0/pci@1/pci@0 - PLAT-FRU = hc:///component=IOBD - VENDOR-ID = 8086 - ON = true - DRIVER = px_pci - EXCAP = pcibus - DEVTYPE = pciex -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn0/pcibus5 - PLAT-FRU = hc:///component=IOBD -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn0/pcibus5/pcidev2 - PLAT-FRU = hc:///component=IOBD -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn0/pcibus5/pcidev2/pcifn0 - DEVICE-ID = 1533 - DEV = /pci@7c0/pci@0/pci@1/pci@0/isa@2 - PLAT-FRU = hc:///component=IOBD - VENDOR-ID = 10b9 - ON = true - DRIVER = ebus -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn0/pcibus5/pcidev5 - PLAT-FRU = hc:///component=IOBD -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn0/pcibus5/pcidev5/pcifn0 - DEVICE-ID = 5237 - DEV = /pci@7c0/pci@0/pci@1/pci@0/usb@5 - PLAT-FRU = hc:///component=IOBD - VENDOR-ID = 10b9 - ON = true - DRIVER = ohci -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn0/pcibus5/pcidev6 - PLAT-FRU = hc:///component=IOBD -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn0/pcibus5/pcidev6/pcifn0 - DEVICE-ID = 5237 - DEV = /pci@7c0/pci@0/pci@1/pci@0/usb@6 - PLAT-FRU = hc:///component=IOBD - VENDOR-ID = 10b9 - ON = true - DRIVER = ohci -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn0/pcibus5/pcidev8 - PLAT-FRU = hc:///component=IOBD -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn0/pcibus5/pcidev8/pcifn0 - DEVICE-ID = 5229 - DEV = /pci@7c0/pci@0/pci@1/pci@0/ide@8 - PLAT-FRU = hc:///component=IOBD - VENDOR-ID = 10b9 - ON = true - DRIVER = uata - DEVTYPE = ide -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn2 - DEVICE-ID = 341 - DEV = /pci@7c0/pci@0/pci@1/pci@0,2 - PLAT-FRU = hc:///component=IOBD - VENDOR-ID = 8086 - ON = true - DRIVER = px_pci - EXCAP = pcibus - DEVTYPE = pciex -# -# Expansion slot PCI4 (PCI) -# -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn2/pcibus6 - PLAT-FRU = hc:///component=PCIX1 -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn2/pcibus6/pcidev[1] - PLAT-FRU = hc:///component=PCIX1 -# -# Expansion slot PCI3 (PCI) -# -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn2/pcibus6 - PLAT-FRU = hc:///component=PCIX0 -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev1/pciexfn0/pciexbus4/pciexdev0/pciexfn2/pcibus6/pcidev[2] - PLAT-FRU = hc:///component=PCIX0 -# -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev2 - PLAT-FRU = hc:///component=IOBD -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev2/pciexfn0 - DEVICE-ID = 8532 - DEV = /pci@7c0/pci@0/pci@2 - PLAT-FRU = hc:///component=IOBD - VENDOR-ID = 10b5 - ON = true - DRIVER = px_pci - EXCAP = pciexswd - DEVTYPE = pciex -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev2/pciexfn0/pciexbus7 - PLAT-FRU = hc:///component=IOBD -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev2/pciexfn0/pciexbus7/pciexdev0 - PLAT-FRU = hc:///component=IOBD -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev2/pciexfn0/pciexbus7/pciexdev0/pciexfn0 - DEVICE-ID = 105e - DEV = /pci@7c0/pci@0/pci@2/network@0 - PLAT-FRU = hc:///component=IOBD - VENDOR-ID = 8086 - ON = true - DRIVER = ipge - DEVTYPE = network -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev2/pciexfn0/pciexbus7/pciexdev0/pciexfn1 - DEVICE-ID = 105e - DEV = /pci@7c0/pci@0/pci@2/network@0,1 - PLAT-FRU = hc:///component=IOBD - VENDOR-ID = 8086 - ON = true - DRIVER = ipge - DEVTYPE = network -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev8 - PLAT-FRU = hc:///component=IOBD -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev8/pciexfn0 - DEVICE-ID = 8532 - DEV = /pci@7c0/pci@0/pci@8 - PLAT-FRU = hc:///component=IOBD - VENDOR-ID = 10b5 - ON = true - DRIVER = px_pci - EXCAP = pciexswd - DEVTYPE = pciex -# -# Expansion slot PCI1 (PCI-Express) -# -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev8/pciexfn0/pciexbus8 - PLAT-FRU = hc:///component=PCIE1 -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev8/pciexfn0/pciexbus8/pciexdev[0] - PLAT-FRU = hc:///component=PCIE1 -# -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev9 - PLAT-FRU = hc:///component=IOBD -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev9/pciexfn0 - DEVICE-ID = 8532 - DEV = /pci@7c0/pci@0/pci@9 - PLAT-FRU = hc:///component=IOBD - VENDOR-ID = 10b5 - ON = true - DRIVER = px_pci - EXCAP = pciexswd - DEVTYPE = pciex -# -# Expansion slot PCI2 (PCI-Express) -# -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev9/pciexfn0/pciexbus9 - PLAT-FRU = hc:///component=PCIE2 -/ioboard0/hostbridge0/pciexrc1/pciexbus2/pciexdev0/pciexfn0/pciexbus3/pciexdev9/pciexfn0/pciexbus9/pciexdev[0] - PLAT-FRU = hc:///component=PCIE2 -# diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V210/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V210/Makefile deleted file mode 100644 index 900733d401..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V210/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOFILE = platform.topo -TOPOSRCDIR = SUNW,Sun-Fire-V240 -TOPOTARGDIR = SUNW,Sun-Fire-V210 - -include ../../Makefile.link diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/Makefile deleted file mode 100644 index 0e3b2b181d..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOSUBDIR = SUNW,Sun-Fire-V240 -TOPOFILES = platform.topo - -include ../../Makefile.com diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/platform.topo b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/platform.topo deleted file mode 100644 index fc729ba5d0..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/platform.topo +++ /dev/null @@ -1,45 +0,0 @@ -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -#ident "%Z%%M% %I% %E% SMI" - -/motherboard0/cpu[0] - PLAT-FRU=hc:///component=CPU0 -/motherboard0/cpu[1] - PLAT-FRU=hc:///component=CPU1 -/motherboard0/hostbridge0 - DEV=/pci@1c -/motherboard0/hostbridge0/pcibus[0] - DEV=/pci@1c,600000 -/motherboard0/hostbridge0/pcibus[1] - .SLOTNM1=hc:///component=PCI0 - DEV=/pci@1d,700000 -/motherboard0/hostbridge1 - DEV=/pci@1e -/motherboard0/hostbridge1/pcibus[0] - .SLOTNM2=hc:///component=PCI2 - .SLOTNM3=hc:///component=PCI1 - DEV=/pci@1e,600000 -/motherboard0/hostbridge1/pcibus[1] - DEV=/pci@1f,700000 diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V250/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V250/Makefile deleted file mode 100644 index 1ddc691c28..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V250/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOFILE = platform.topo -TOPOSRCDIR = SUNW,Sun-Fire-V240 -TOPOTARGDIR = SUNW,Sun-Fire-V250 - -include ../../Makefile.link diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/Makefile deleted file mode 100644 index e97ffd76d4..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOSUBDIR = SUNW,Sun-Fire-V440 -TOPOFILES = platform.topo - -include ../../Makefile.com diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/platform.topo b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/platform.topo deleted file mode 100644 index f82ed5372f..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/platform.topo +++ /dev/null @@ -1,48 +0,0 @@ -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -#ident "%Z%%M% %I% %E% SMI" - -/motherboard0/cpumodule[0] - PLAT-FRU=hc:///component=C0 -/motherboard0/cpumodule[0]/cpu[0] -/motherboard0/cpumodule[1] - PLAT-FRU=hc:///component=C1 -/motherboard0/cpumodule[1]/cpu[1] -/motherboard0/cpumodule[2] - PLAT-FRU=hc:///component=C2 -/motherboard0/cpumodule[2]/cpu[2] -/motherboard0/cpumodule[3] - PLAT-FRU=hc:///component=C3 -/motherboard0/cpumodule[3]/cpu[3] -/motherboard0/hostbridge0/pcibus[0] - DEV=/pci@1c,600000 -/motherboard0/hostbridge0/pcibus[1] - DEV=/pci@1d,700000 - .SLOTNM1=PCI4 - .SLOTNM2=PCI2 -/motherboard0/hostbridge1/pcibus[0] - DEV=/pci@1e,600000 -/motherboard0/hostbridge1/pcibus[1] - DEV=/pci@1f,700000 diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V490/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V490/Makefile deleted file mode 100644 index 0e4595998e..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V490/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOFILE = platform.topo -TOPOSRCDIR = SUNW,Sun-Fire-480R -TOPOTARGDIR = SUNW,Sun-Fire-V490 - -include ../../Makefile.link diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V890/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V890/Makefile deleted file mode 100644 index e341194dcf..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V890/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOFILE = platform.topo -TOPOSRCDIR = SUNW,Sun-Fire-880 -TOPOTARGDIR = SUNW,Sun-Fire-V890 - -include ../../Makefile.link diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/Makefile deleted file mode 100644 index f7f91392d7..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOSUBDIR = SUNW,Sun-Fire -TOPOFILES = platform.topo - -include ../../Makefile.com diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/platform.topo b/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/platform.topo deleted file mode 100644 index 7e50119475..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/platform.topo +++ /dev/null @@ -1,356 +0,0 @@ -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -#ident "%Z%%M% %I% %E% SMI" - -/centerplane0 - PLAT-FRU=hc:///component=centerplane -/centerplane0/systemboard[0] - PLAT-ASRU=hc:///component=N0/SB0 - PLAT-FRU=hc:///component=N0/SB0 - -# The ASRU for CPUs is computed, and of form cpu:///cpuid=NN/serial=XXXXX -/centerplane0/systemboard[0]/cpumodule0 - PLAT-ASRU=hc:///component=N0/SB0::cpu0 - PLAT-FRU=hc:///component=N0/SB0/P0 -/centerplane0/systemboard[0]/cpumodule0/cpu[0] -/centerplane0/systemboard[0]/cpumodule1 - PLAT-ASRU=hc:///component=N0/SB0::cpu1 - PLAT-FRU=hc:///component=N0/SB0/P1 -/centerplane0/systemboard[0]/cpumodule1/cpu[1] -/centerplane0/systemboard[0]/cpumodule2 - PLAT-ASRU=hc:///component=N0/SB0::cpu2 - PLAT-FRU=hc:///component=N0/SB0/P2 -/centerplane0/systemboard[0]/cpumodule2/cpu[2] -/centerplane0/systemboard[0]/cpumodule3 - PLAT-ASRU=hc:///component=N0/SB0::cpu3 - PLAT-FRU=hc:///component=N0/SB0/P3 -/centerplane0/systemboard[0]/cpumodule3/cpu[3] -/centerplane0/systemboard[1] - PLAT-ASRU=hc:///component=N0/SB1 - PLAT-FRU=hc:///component=N0/SB1 -/centerplane0/systemboard[1]/cpumodule0 - PLAT-ASRU=hc:///component=N0/SB1::cpu0 - PLAT-FRU=hc:///component=N0/SB1/P0 -/centerplane0/systemboard[1]/cpumodule0/cpu[4] -/centerplane0/systemboard[1]/cpumodule1 - PLAT-ASRU=hc:///component=N0/SB1::cpu1 - PLAT-FRU=hc:///component=N0/SB1/P1 -/centerplane0/systemboard[1]/cpumodule1/cpu[5] -/centerplane0/systemboard[1]/cpumodule2 - PLAT-ASRU=hc:///component=N0/SB1::cpu2 - PLAT-FRU=hc:///component=N0/SB1/P2 -/centerplane0/systemboard[1]/cpumodule2/cpu[6] -/centerplane0/systemboard[1]/cpumodule3 - PLAT-ASRU=hc:///component=N0/SB1::cpu3 - PLAT-FRU=hc:///component=N0/SB1/P3 -/centerplane0/systemboard[1]/cpumodule3/cpu[7] - PLAT-FRU=hc:///component=N0/SB1/P3 -/centerplane0/systemboard[2] - PLAT-ASRU=hc:///component=N0/SB2 - PLAT-FRU=hc:///component=N0/SB2 -/centerplane0/systemboard[2]/cpumodule0 - PLAT-ASRU=hc:///component=N0/SB2::cpu0 - PLAT-FRU=hc:///component=N0/SB2/P0 -/centerplane0/systemboard[2]/cpumodule0/cpu[8] -/centerplane0/systemboard[2]/cpumodule1 - PLAT-ASRU=hc:///component=N0/SB2::cpu1 - PLAT-FRU=hc:///component=N0/SB2/P1 -/centerplane0/systemboard[2]/cpumodule1/cpu[9] -/centerplane0/systemboard[2]/cpumodule2 - PLAT-ASRU=hc:///component=N0/SB2::cpu2 - PLAT-FRU=hc:///component=N0/SB2/P2 -/centerplane0/systemboard[2]/cpumodule2/cpu[10] -/centerplane0/systemboard[2]/cpumodule3 - PLAT-ASRU=hc:///component=N0/SB2::cpu3 - PLAT-FRU=hc:///component=N0/SB2/P3 -/centerplane0/systemboard[2]/cpumodule3/cpu[11] -/centerplane0/systemboard[3] - PLAT-ASRU=hc:///component=N0/SB3 - PLAT-FRU=hc:///component=N0/SB3 -/centerplane0/systemboard[3]/cpumodule0 - PLAT-ASRU=hc:///component=N0/SB3::cpu0 - PLAT-FRU=hc:///component=N0/SB3/P0 -/centerplane0/systemboard[3]/cpumodule0/cpu[12] -/centerplane0/systemboard[3]/cpumodule1 - PLAT-ASRU=hc:///component=N0/SB3::cpu1 - PLAT-FRU=hc:///component=N0/SB3/P1 -/centerplane0/systemboard[3]/cpumodule1/cpu[13] -/centerplane0/systemboard[3]/cpumodule2 - PLAT-ASRU=hc:///component=N0/SB3::cpu2 - PLAT-FRU=hc:///component=N0/SB3/P2 -/centerplane0/systemboard[3]/cpumodule2/cpu[14] -/centerplane0/systemboard[3]/cpumodule3 - PLAT-ASRU=hc:///component=N0/SB3::cpu3 - PLAT-FRU=hc:///component=N0/SB3/P3 -/centerplane0/systemboard[3]/cpumodule3/cpu[15] -/centerplane0/systemboard[4] - PLAT-ASRU=hc:///component=N0/SB4 - PLAT-FRU=hc:///component=N0/SB4 -/centerplane0/systemboard[4]/cpumodule0 - PLAT-ASRU=hc:///component=N0/SB4::cpu0 - PLAT-FRU=hc:///component=N0/SB4/P0 -/centerplane0/systemboard[4]/cpumodule0/cpu[16] -/centerplane0/systemboard[4]/cpumodule1 - PLAT-ASRU=hc:///component=N0/SB4::cpu1 - PLAT-FRU=hc:///component=N0/SB4/P1 -/centerplane0/systemboard[4]/cpumodule1/cpu[17] -/centerplane0/systemboard[4]/cpumodule2 - PLAT-ASRU=hc:///component=N0/SB4::cpu2 - PLAT-FRU=hc:///component=N0/SB4/P2 -/centerplane0/systemboard[4]/cpumodule2/cpu[18] -/centerplane0/systemboard[4]/cpumodule3 - PLAT-ASRU=hc:///component=N0/SB4::cpu3 - PLAT-FRU=hc:///component=N0/SB4/P3 -/centerplane0/systemboard[4]/cpumodule3/cpu[19] -/centerplane0/systemboard[5] - PLAT-ASRU=hc:///component=N0/SB5 - PLAT-FRU=hc:///component=N0/SB5 -/centerplane0/systemboard[5]/cpumodule0 - PLAT-ASRU=hc:///component=N0/SB5::cpu0 - PLAT-FRU=hc:///component=N0/SB5/P0 -/centerplane0/systemboard[5]/cpumodule0/cpu[20] -/centerplane0/systemboard[5]/cpumodule1 - PLAT-ASRU=hc:///component=N0/SB5::cpu1 - PLAT-FRU=hc:///component=N0/SB5/P1 -/centerplane0/systemboard[5]/cpumodule1/cpu[21] -/centerplane0/systemboard[5]/cpumodule2 - PLAT-ASRU=hc:///component=N0/SB5::cpu2 - PLAT-FRU=hc:///component=N0/SB5/P2 -/centerplane0/systemboard[5]/cpumodule2/cpu[22] -/centerplane0/systemboard[5]/cpumodule3 - PLAT-ASRU=hc:///component=N0/SB5::cpu3 - PLAT-FRU=hc:///component=N0/SB5/P3 -/centerplane0/systemboard[5]/cpumodule3/cpu[23] -/centerplane0/ioboard[6] - PLAT-ASRU=hc:///component=N0/IB6 - PLAT-FRU=hc:///component=N0/IB6 -/centerplane0/ioboard[6]/hostbridge0 - DEV=/ssm@0,0/pci@18 - PLAT-FRU=hc:///component=N0/IB6 -/centerplane0/ioboard[6]/hostbridge1 - DEV=/ssm@0,0/pci@19 - PLAT-FRU=hc:///component=N0/IB6 -/centerplane0/ioboard[6]/hostbridge0/pcibus[0] - DEV=/ssm@0,0/pci@18,600000 - PLAT-FRU=hc:///component=N0/IB6 -/centerplane0/ioboard[6]/hostbridge0/pcibus[0]/pcidev[1] - PLAT-FRU="hc:///component=N0/IB6/component=slot 3" -/centerplane0/ioboard[6]/hostbridge0/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB6/component=slot 3" -/centerplane0/ioboard[6]/hostbridge0/pcibus[1] - DEV=/ssm@0,0/pci@18,700000 - PLAT-FRU=hc:///component=N0/IB6 -/centerplane0/ioboard[6]/hostbridge0/pcibus[1]/pcidev[1] - PLAT-FRU="hc:///component=N0/IB6/component=slot 0" -/centerplane0/ioboard[6]/hostbridge0/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB6/component=slot 0" -/centerplane0/ioboard[6]/hostbridge0/pcibus[1]/pcidev[2] - PLAT-FRU="hc:///component=N0/IB6/component=slot 1" -/centerplane0/ioboard[6]/hostbridge0/pcibus[1]/pcidev[2]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB6/component=slot 1" -/centerplane0/ioboard[6]/hostbridge0/pcibus[1]/pcidev[3] - PLAT-FRU="hc:///component=N0/IB6/component=slot 2" -/centerplane0/ioboard[6]/hostbridge0/pcibus[1]/pcidev[3]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB6/component=slot 2" -/centerplane0/ioboard[6]/hostbridge1/pcibus[0] - DEV=/ssm@0,0/pci@19,600000 - PLAT-FRU=hc:///component=N0/IB6 -/centerplane0/ioboard[6]/hostbridge1/pcibus[0]/pcidev[1] - PLAT-FRU="hc:///component=N0/IB6/component=slot 7" -/centerplane0/ioboard[6]/hostbridge1/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB6/component=slot 7" -/centerplane0/ioboard[6]/hostbridge1/pcibus[1] - DEV=/ssm@0,0/pci@19,700000 - PLAT-FRU=hc:///component=N0/IB6 -/centerplane0/ioboard[6]/hostbridge1/pcibus[1]/pcidev[1] - PLAT-FRU="hc:///component=N0/IB6/component=slot 4" -/centerplane0/ioboard[6]/hostbridge1/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB6/component=slot 4" -/centerplane0/ioboard[6]/hostbridge1/pcibus[1]/pcidev[2] - PLAT-FRU="hc:///component=N0/IB6/component=slot 5" -/centerplane0/ioboard[6]/hostbridge1/pcibus[1]/pcidev[2]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB6/component=slot 5" -/centerplane0/ioboard[6]/hostbridge1/pcibus[1]/pcidev[3] - PLAT-FRU="hc:///component=N0/IB6/component=slot 6" -/centerplane0/ioboard[6]/hostbridge1/pcibus[1]/pcidev[3]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB6/component=slot 6" -/centerplane0/ioboard[7] - PLAT-FRU=hc:///component=N0/IB7 -/centerplane0/ioboard[7]/hostbridge0 - DEV=/ssm@0,0/pci@1a - PLAT-FRU=hc:///component=N0/IB7 -/centerplane0/ioboard[7]/hostbridge1 - DEV=/ssm@0,0/pci@1b - PLAT-FRU=hc:///component=N0/IB7 -/centerplane0/ioboard[7]/hostbridge0/pcibus[0] - DEV=/ssm@0,0/pci@1a,600000 - PLAT-FRU=hc:///component=N0/IB7 -/centerplane0/ioboard[7]/hostbridge0/pcibus[0]/pcidev[1] - PLAT-FRU="hc:///component=N0/IB7/component=slot 3" -/centerplane0/ioboard[7]/hostbridge0/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB7/component=slot 3" -/centerplane0/ioboard[7]/hostbridge0/pcibus[1] - DEV=/ssm@0,0/pci@1a,700000 - PLAT-FRU=hc:///component=N0/IB7 -/centerplane0/ioboard[7]/hostbridge0/pcibus[1]/pcidev[1] - PLAT-FRU="hc:///component=N0/IB7/component=slot 0" -/centerplane0/ioboard[7]/hostbridge0/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB7/component=slot 0" -/centerplane0/ioboard[7]/hostbridge0/pcibus[1]/pcidev[2] - PLAT-FRU="hc:///component=N0/IB7/component=slot 1" -/centerplane0/ioboard[7]/hostbridge0/pcibus[1]/pcidev[2]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB7/component=slot 1" -/centerplane0/ioboard[7]/hostbridge0/pcibus[1]/pcidev[3] - PLAT-FRU="hc:///component=N0/IB7/component=slot 2" -/centerplane0/ioboard[7]/hostbridge0/pcibus[1]/pcidev[3]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB7/component=slot 2" -/centerplane0/ioboard[7]/hostbridge1/pcibus[0] - DEV=/ssm@0,0/pci@1b,600000 - PLAT-FRU=hc:///component=N0/IB7 -/centerplane0/ioboard[7]/hostbridge1/pcibus[0]/pcidev[1] - PLAT-FRU="hc:///component=N0/IB7/component=slot 7" -/centerplane0/ioboard[7]/hostbridge1/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB7/component=slot 7" -/centerplane0/ioboard[7]/hostbridge1/pcibus[1] - DEV=/ssm@0,0/pci@1b,700000 - PLAT-FRU=hc:///component=N0/IB7 -/centerplane0/ioboard[7]/hostbridge1/pcibus[1]/pcidev[1] - PLAT-FRU="hc:///component=N0/IB7/component=slot 4" -/centerplane0/ioboard[7]/hostbridge1/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB7/component=slot 4" -/centerplane0/ioboard[7]/hostbridge1/pcibus[1]/pcidev[2] - PLAT-FRU="hc:///component=N0/IB7/component=slot 5" -/centerplane0/ioboard[7]/hostbridge1/pcibus[1]/pcidev[2]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB7/component=slot 5" -/centerplane0/ioboard[7]/hostbridge1/pcibus[1]/pcidev[3] - PLAT-FRU="hc:///component=N0/IB7/component=slot 6" -/centerplane0/ioboard[7]/hostbridge1/pcibus[1]/pcidev[3]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB7/component=slot 6" -/centerplane0/ioboard[8] - PLAT-ASRU=hc:///component=N0/IB8 - PLAT-FRU=hc:///component=N0/IB8 -/centerplane0/ioboard[8]/hostbridge0 - DEV=/ssm@0,0/pci@1c - PLAT-FRU=hc:///component=N0/IB8 -/centerplane0/ioboard[8]/hostbridge1 - DEV=/ssm@0,0/pci@1d - PLAT-FRU=hc:///component=N0/IB8 -/centerplane0/ioboard[8]/hostbridge0/pcibus[0] - DEV=/ssm@0,0/pci@1c,600000 - PLAT-FRU=hc:///component=N0/IB8 -/centerplane0/ioboard[8]/hostbridge0/pcibus[0]/pcidev[1] - PLAT-FRU="hc:///component=N0/IB8/component=slot 3" -/centerplane0/ioboard[8]/hostbridge0/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB8/component=slot 3" -/centerplane0/ioboard[8]/hostbridge0/pcibus[1] - DEV=/ssm@0,0/pci@1c,700000 - PLAT-FRU=hc:///component=N0/IB8 -/centerplane0/ioboard[8]/hostbridge0/pcibus[1]/pcidev[1] - PLAT-FRU="hc:///component=N0/IB8/component=slot 0" -/centerplane0/ioboard[8]/hostbridge0/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB8/component=slot 0" -/centerplane0/ioboard[8]/hostbridge0/pcibus[1]/pcidev[2] - PLAT-FRU="hc:///component=N0/IB8/component=slot 1" -/centerplane0/ioboard[8]/hostbridge0/pcibus[1]/pcidev[2]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB8/component=slot 1" -/centerplane0/ioboard[8]/hostbridge0/pcibus[1]/pcidev[3] - PLAT-FRU="hc:///component=N0/IB8/component=slot 2" -/centerplane0/ioboard[8]/hostbridge0/pcibus[1]/pcidev[3]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB8/component=slot 2" -/centerplane0/ioboard[8]/hostbridge1/pcibus[0] - DEV=/ssm@0,0/pci@1d,600000 - PLAT-FRU=hc:///component=N0/IB8 -/centerplane0/ioboard[8]/hostbridge1/pcibus[0]/pcidev[1] - PLAT-FRU="hc:///component=N0/IB8/component=slot 7" -/centerplane0/ioboard[8]/hostbridge1/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB8/component=slot 7" -/centerplane0/ioboard[8]/hostbridge1/pcibus[1] - DEV=/ssm@0,0/pci@1d,700000 - PLAT-FRU=hc:///component=N0/IB8 -/centerplane0/ioboard[8]/hostbridge1/pcibus[1]/pcidev[1] - PLAT-FRU="hc:///component=N0/IB8/component=slot 4" -/centerplane0/ioboard[8]/hostbridge1/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB8/component=slot 4" -/centerplane0/ioboard[8]/hostbridge1/pcibus[1]/pcidev[2] - PLAT-FRU="hc:///component=N0/IB8/component=slot 5" -/centerplane0/ioboard[8]/hostbridge1/pcibus[1]/pcidev[2]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB8/component=slot 5" -/centerplane0/ioboard[8]/hostbridge1/pcibus[1]/pcidev[3] - PLAT-FRU="hc:///component=N0/IB8/component=slot 6" -/centerplane0/ioboard[8]/hostbridge1/pcibus[1]/pcidev[3]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB8/component=slot 6" -/centerplane0/ioboard[9] - PLAT-ASRU=hc:///component=N0/IB9 - PLAT-FRU=hc:///component=N0/IB9 -/centerplane0/ioboard[9]/hostbridge0 - DEV=/ssm@0,0/pci@1e - PLAT-FRU=hc:///component=N0/IB9 -/centerplane0/ioboard[9]/hostbridge1 - DEV=/ssm@0,0/pci@1f - PLAT-FRU=hc:///component=N0/IB9 -/centerplane0/ioboard[9]/hostbridge0/pcibus[0] - DEV=/ssm@0,0/pci@1e,600000 - PLAT-FRU=hc:///component=N0/IB9 -/centerplane0/ioboard[9]/hostbridge0/pcibus[0]/pcidev[1] - PLAT-FRU="hc:///component=N0/IB9/component=slot 3" -/centerplane0/ioboard[9]/hostbridge0/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB9/component=slot 3" -/centerplane0/ioboard[9]/hostbridge0/pcibus[1] - DEV=/ssm@0,0/pci@1e,700000 - PLAT-FRU=hc:///component=N0/IB9 -/centerplane0/ioboard[9]/hostbridge0/pcibus[1]/pcidev[1] - PLAT-FRU="hc:///component=N0/IB9/component=slot 0" -/centerplane0/ioboard[9]/hostbridge0/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB9/component=slot 0" -/centerplane0/ioboard[9]/hostbridge0/pcibus[1]/pcidev[2] - PLAT-FRU="hc:///component=N0/IB9/component=slot 1" -/centerplane0/ioboard[9]/hostbridge0/pcibus[1]/pcidev[2]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB9/component=slot 1" -/centerplane0/ioboard[9]/hostbridge0/pcibus[1]/pcidev[3] - PLAT-FRU="hc:///component=N0/IB9/component=slot 2" -/centerplane0/ioboard[9]/hostbridge0/pcibus[1]/pcidev[3]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB9/component=slot 2" -/centerplane0/ioboard[9]/hostbridge1/pcibus[0] - DEV=/ssm@0,0/pci@1f,600000 - PLAT-FRU=hc:///component=N0/IB9 -/centerplane0/ioboard[9]/hostbridge1/pcibus[0]/pcidev[1] - PLAT-FRU="hc:///component=N0/IB9/component=slot 7" -/centerplane0/ioboard[9]/hostbridge1/pcibus[0]/pcidev[1]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB9/component=slot 7" -/centerplane0/ioboard[9]/hostbridge1/pcibus[1] - DEV=/ssm@0,0/pci@1f,700000 - PLAT-FRU=hc:///component=N0/IB9 -/centerplane0/ioboard[9]/hostbridge1/pcibus[1]/pcidev[1] - PLAT-FRU="hc:///component=N0/IB9/component=slot 4" -/centerplane0/ioboard[9]/hostbridge1/pcibus[1]/pcidev[1]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB9/component=slot 4" -/centerplane0/ioboard[9]/hostbridge1/pcibus[1]/pcidev[2] - PLAT-FRU="hc:///component=N0/IB9/component=slot 5" -/centerplane0/ioboard[9]/hostbridge1/pcibus[1]/pcidev[2]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB9/component=slot 5" -/centerplane0/ioboard[9]/hostbridge1/pcibus[1]/pcidev[3] - PLAT-FRU="hc:///component=N0/IB9/component=slot 6" -/centerplane0/ioboard[9]/hostbridge1/pcibus[1]/pcidev[3]/pcifn[0-7] - PLAT-FRU="hc:///component=N0/IB9/component=slot 6" diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/Makefile deleted file mode 100644 index 305b3afe74..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOSUBDIR = SUNW,Ultra-250 -TOPOFILES = platform.topo - -include ../../Makefile.com diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/platform.topo b/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/platform.topo deleted file mode 100644 index 37f4a5facf..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/platform.topo +++ /dev/null @@ -1,42 +0,0 @@ -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -#ident "%Z%%M% %I% %E% SMI" - -/motherboard0/cpu[0] - PLAT-FRU=hc:///component=CPU0 -/motherboard0/cpu[1] - PLAT-FRU=hc:///component=CPU1 -/motherboard0/hostbridge0 - DEV=/pci@1c -/motherboard0/hostbridge0/pcibus[0] - DEV=/pci@1c,600000 -/motherboard0/hostbridge0/pcibus[1] - DEV=/pci@1e,600000 -/motherboard0/hostbridge1 - DEV=/pci@1d -/motherboard0/hostbridge1/pcibus[0] - DEV=/pci@1d,700000 -/motherboard0/hostbridge1/pcibus[1] - DEV=/pci@1f,700000 diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/Makefile deleted file mode 100644 index 922adf3f93..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOSUBDIR = SUNW,Ultra-30 -TOPOFILES = platform.topo - -include ../../Makefile.com diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/platform.topo b/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/platform.topo deleted file mode 100644 index 489190b024..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/platform.topo +++ /dev/null @@ -1,34 +0,0 @@ -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -#ident "%Z%%M% %I% %E% SMI" - -/motherboard0/cpumodule0/cpu0 - PLAT-FRU=hc:///component=CPU0 -/motherboard0/hostbridge0 - DEV=/pci@1f -/motherboard0/hostbridge0/pcibus[0] - DEV=/pci@1f,2000 -/motherboard0/hostbridge0/pcibus[1] - DEV=/pci@1f,4000 diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/Makefile deleted file mode 100644 index 52d0dae65c..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOSUBDIR = SUNW,Ultra-4 -TOPOFILES = platform.topo - -include ../../Makefile.com diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/platform.topo b/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/platform.topo deleted file mode 100644 index 11da242e85..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/platform.topo +++ /dev/null @@ -1,52 +0,0 @@ -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -#ident "%Z%%M% %I% %E% SMI" - -/motherboard0/cpumodule0/cpu[0] - PLAT-FRU=hc:///component=CPU0 -/motherboard0/cpumodule1/cpu[1] - PLAT-FRU=hc:///component=CPU1 -/motherboard0/cpumodule2/cpu[2] - PLAT-FRU=hc:///component=CPU2 -/motherboard0/cpumodule3/cpu[3] - PLAT-FRU=hc:///component=CPU3 -/motherboard0/hostbridge0 - DEV=/pci@1f -/motherboard0/hostbridge0/pcibus[0] - DEV=/pci@1f,2000 -/motherboard0/hostbridge0/pcibus[1] - DEV=/pci@1f,4000 -/motherboard0/hostbridge1 - DEV=/pci@4 -/motherboard0/hostbridge1/pcibus[0] - DEV=/pci@4,2000 -/motherboard0/hostbridge1/pcibus[1] - DEV=/pci@4,4000 -/motherboard0/hostbridge2 - DEV=/pci@6 -/motherboard0/hostbridge2/pcibus[0] - DEV=/pci@6,2000 -/motherboard0/hostbridge2/pcibus[1] - DEV=/pci@6,4000 diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/Makefile deleted file mode 100644 index 15f0f384d3..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOSUBDIR = SUNW,Ultra-5_10 -TOPOFILES = platform.topo - -include ../../Makefile.com diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/platform.topo b/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/platform.topo deleted file mode 100644 index 6bd0e748f7..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/platform.topo +++ /dev/null @@ -1,34 +0,0 @@ -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -#ident "%Z%%M% %I% %E% SMI" - -/motherboard0/cpumodule0/cpu[0] - PLAT-FRU=hc:///component=CPU0 -/motherboard0/cpumodule1/cpu[1] - PLAT-FRU=hc:///component=CPU1 -/motherboard0/hostbridge0 - DEV=/pci@1f -/motherboard0/hostbridge0/pcibus[0] - DEV=/pci@1f,0 diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/Makefile deleted file mode 100644 index 418ac83ea9..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOSUBDIR = SUNW,Ultra-60 -TOPOFILES = platform.topo - -include ../../Makefile.com diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/platform.topo b/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/platform.topo deleted file mode 100644 index e647ce28c6..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/platform.topo +++ /dev/null @@ -1,38 +0,0 @@ -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -#ident "%Z%%M% %I% %E% SMI" - -/motherboard0/cpumodule0 - PLAT-FRU="hc:///component=UPA Slot 0" -/motherboard0/cpumodule0/cpu[0] -/motherboard0/cpumodule1 - PLAT-FRU="hc:///component=UPA Slot 1" -/motherboard0/cpumodule1/cpu[2] -/motherboard0/hostbridge0 - DEV=/pci@1f -/motherboard0/hostbridge0/pcibus[0] - DEV=/pci@1f,2000 -/motherboard0/hostbridge0/pcibus[1] - DEV=/pci@1f,4000 diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/Makefile deleted file mode 100644 index e65a1cc3c2..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOSUBDIR = SUNW,Ultra-80 -TOPOFILES = platform.topo - -include ../../Makefile.com diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/platform.topo b/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/platform.topo deleted file mode 100644 index 440d76e7eb..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/platform.topo +++ /dev/null @@ -1,40 +0,0 @@ -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -#ident "%Z%%M% %I% %E% SMI" - -/motherboard0/cpumodule0/cpu[0] - PLAT-FRU=hc:///component=CPU0 -/motherboard0/cpumodule1/cpu[1] - PLAT-FRU=hc:///component=CPU1 -/motherboard0/cpumodule2/cpu[2] - PLAT-FRU=hc:///component=CPU2 -/motherboard0/cpumodule3/cpu[3] - PLAT-FRU=hc:///component=CPU3 -/motherboard0/hostbridge0 - DEV=/pci@1f -/motherboard0/hostbridge0/pcibus[0] - DEV=/pci@1f,2000 -/motherboard0/hostbridge0/pcibus[1] - DEV=/pci@1f,4000 diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/Makefile deleted file mode 100644 index bc3a4649a8..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -TOPOSUBDIR = SUNW,UltraAX-i2 -TOPOFILES = platform.topo - -include ../../Makefile.com diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/platform.topo b/usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/platform.topo deleted file mode 100644 index b16b0379a4..0000000000 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/platform.topo +++ /dev/null @@ -1,32 +0,0 @@ -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -#ident "%Z%%M% %I% %E% SMI" - -/motherboard0/cpu0 - PLAT-FRU=hc:///component=CPU0 -/motherboard0/hostbridge0 - DEV=/pci@1f -/motherboard0/hostbridge0/pcibus[0] - DEV=/pci@1f,0 diff --git a/usr/src/cmd/fm/topo/plugins/Makefile b/usr/src/cmd/fm/topo/plugins/Makefile deleted file mode 100644 index f4530bfceb..0000000000 --- a/usr/src/cmd/fm/topo/plugins/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -sparc_SUBDIRS = -i386_SUBDIRS = - -SUBDIRS = common $($(MACH)_SUBDIRS) - -include ../../Makefile.subdirs diff --git a/usr/src/cmd/fm/topo/plugins/Makefile.topoonly b/usr/src/cmd/fm/topo/plugins/Makefile.topoonly deleted file mode 100644 index 9661ae784a..0000000000 --- a/usr/src/cmd/fm/topo/plugins/Makefile.topoonly +++ /dev/null @@ -1,54 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -.KEEP_STATE: -.SUFFIXES: - -include ../../../../../Makefile.cmd - -TOPO = $(MODULE:%=%.topo) - -# -# Set ROOTPROG and ROOTTOPO based on the values of MODULE, CLASS, and PLATFORMS -# We expect these macros to be defined by the Makefile that is including us. -# -common_TOPODIR = $(ROOT)/usr/lib/fm/topo -arch_TOPODIR = $(ROOT)/usr/lib/fm/topo/$(ARCH) -ROOT_TOPO_DIR = $($(CLASS)_TOPODIR) - -ROOTTOPO = $(ROOT_TOPO_DIR)/$(TOPO) - -include ../../../Makefile.rootdirs - -all clean install_h lint _msg: - -install:= FILEMODE = 0444 - -install: $(ROOTTOPO) - -clobber: - $(RM) $(ROOTTOPO) diff --git a/usr/src/cmd/fm/topo/plugins/common/Makefile b/usr/src/cmd/fm/topo/plugins/common/Makefile deleted file mode 100644 index 0fe2af7cd4..0000000000 --- a/usr/src/cmd/fm/topo/plugins/common/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -SUBDIRS = cpu pcibus pciexbus pciexrc - -include ../../../Makefile.subdirs diff --git a/usr/src/cmd/fm/topo/plugins/common/cpu/cpu.c b/usr/src/cmd/fm/topo/plugins/common/cpu/cpu.c deleted file mode 100644 index 77c81f601e..0000000000 --- a/usr/src/cmd/fm/topo/plugins/common/cpu/cpu.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <fm/libtopo_enum.h> -#include <sys/types.h> -#include <sys/processor.h> -#include <string.h> -#include <kstat.h> - -#define SERIALNUMPROP "SERIAL-ID" -#define STATUSPROP "CPU-STATUS" - -int topo_cpu_init(void); -void topo_cpu_fini(void); -void topo_cpu_enum(tnode_t *); - -static struct tenumr cpu_enumr = { - NULL, - topo_cpu_init, - topo_cpu_fini, - topo_cpu_enum -}; - -struct tenumr * -_enum_init(void) -{ - return (&cpu_enumr); -} - -int -topo_cpu_init(void) -{ - return (TE_INITOK); -} - -void -topo_cpu_fini(void) -{ -} - -static void -cpu_fru_prop(tnode_t *tn) -{ - const char *pv; - - if ((pv = topo_get_prop(tn, PLATFRU)) != NULL) - return; - if ((pv = topo_get_prop(topo_parent(tn), PLATFRU)) != NULL) - (void) topo_set_prop(tn, PLATFRU, pv); -} - -static void -cpu_serialid_prop(tnode_t *tn, uint32_t cpuid, int status) -{ - kstat_named_t *kn; - kstat_ctl_t *kc; - uint64_t serialid; - kstat_t *ksp; - char as_str[21]; /* uint64_t will have as many as 20 digits */ - int i; - - (void) snprintf(as_str, 21, "%d", status); - (void) topo_set_prop(tn, STATUSPROP, as_str); - - if ((kc = kstat_open()) == NULL) - return; - - if ((ksp = kstat_lookup(kc, "cpu_info", cpuid, NULL)) == NULL) { - (void) kstat_close(kc); - return; - } - - if (kstat_read(kc, ksp, NULL) == -1) { - (void) kstat_close(kc); - return; - } - - for (kn = ksp->ks_data, i = 0; i < ksp->ks_ndata; i++, kn++) { - if (strcmp(kn->name, "device_ID") == 0) { - serialid = kn->value.ui64; - (void) snprintf(as_str, 21, "%llu", serialid); - (void) topo_set_prop(tn, SERIALNUMPROP, as_str); - break; - } - } - (void) kstat_close(kc); -} - -void -topo_cpu_enum(tnode_t *node) -{ - tnode_t *self; - tnode_t *pn; - int c, s, min, max; - - /* - * This is a dirt simple enumerator that relies on the static - * numbering scheme the platforms we care about seem to follow. - * The node we're being asked to enumerate may have either a - * single id or a range of ids. We just use p_online() to see - * if that id of cpu is present. If so, we'll also try to find - * the serial number and set a property containing that. - */ - topo_get_instance_range(node, &min, &max); - if (min < 0 || max < 0) { - topo_out(TOPO_DEBUG, - "Unexpected cpu instance range min = %d - max = %d.\n", - min, max); - return; - } - for (c = min; c <= max; c++) { - /* - * If we get an error, we'll assume the processor isn't - * present. - */ - if ((s = p_online(c, P_STATUS)) < 0) - continue; - self = topo_set_instance_num(node, c); - cpu_fru_prop(self); - cpu_serialid_prop(self, c, s); - /* - * If this cpu is a descendant of a topo node that's - * not enumerated but whose instance number is - * unambiguous, we now know that ancestor is - * present, and can enumerate it. - */ - pn = topo_parent(node); - while (pn != NULL) { - if (topo_get_instance_num(pn) < 0) { - topo_get_instance_range(pn, &min, &max); - if (min == max && min >= 0) - (void) topo_set_instance_num(pn, min); - } - pn = topo_parent(pn); - } - } -} diff --git a/usr/src/cmd/fm/topo/plugins/common/cpu/cpu.topo b/usr/src/cmd/fm/topo/plugins/common/cpu/cpu.topo deleted file mode 100644 index 5089cf3883..0000000000 --- a/usr/src/cmd/fm/topo/plugins/common/cpu/cpu.topo +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -#ident "%Z%%M% %I% %E% SMI" - -# No sub-topology-nodes are expected beneath a cpu node diff --git a/usr/src/cmd/fm/topo/plugins/common/pcibus/Makefile b/usr/src/cmd/fm/topo/plugins/common/pcibus/Makefile deleted file mode 100644 index 88e0e82d4e..0000000000 --- a/usr/src/cmd/fm/topo/plugins/common/pcibus/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -MODULE = pcibus -CLASS = common -SRCS = pcibus.c - -include ../../Makefile.plugin - -LDLIBS += -ldevinfo diff --git a/usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.c b/usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.c deleted file mode 100644 index 934dbb4a24..0000000000 --- a/usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.c +++ /dev/null @@ -1,1356 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <fm/libtopo_enum.h> -#include <sys/fm/protocol.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <strings.h> -#include <alloca.h> -#include <sys/param.h> -#include <sys/pci.h> -#include <sys/pcie.h> -#include "enumpci.h" - -static struct tenumr pci_enumr = { - NULL, - topo_pci_init, - topo_pci_fini, - topo_pci_enum -}; - -static di_prom_handle_t Promtree = DI_PROM_HANDLE_NIL; -static di_node_t Devtree = DI_NODE_NIL; - -void instantiate_children(tnode_t *, di_node_t, di_prom_handle_t); -di_node_t pciex_di_match(const char *); -di_node_t pci_di_match(const char *); - -struct tenumr * -_enum_init(void) -{ - return (&pci_enumr); -} - -int -topo_pci_init(void) -{ -/* Devtree = di_init("/", DINFOCACHE); */ - Devtree = di_init("/", DINFOCPYALL); - - if (Devtree == DI_NODE_NIL) { - topo_out(TOPO_ERR, "PCI enumerator: di_init failed.\n"); - return (TE_INITFAIL); - } - - Promtree = di_prom_init(); - if (Promtree == DI_PROM_HANDLE_NIL) { - di_fini(Devtree); - topo_out(TOPO_ERR, - "PCI enumerator: di_prom_handle_init failed.\n"); - return (TE_INITFAIL); - } - topo_out(TOPO_DEBUG, "PCI Enumr initd\n"); - return (TE_INITOK); -} - -void -topo_pci_fini(void) -{ - di_prom_fini(Promtree); - di_fini(Devtree); -} - -/* - * If this devinfo node came originally from OBP data, we'll have prom - * properties associated with the node where we can find properties of - * interest. We ignore anything after the the first four bytes of the - * property, and interpet those first four bytes as our unsigned - * integer. If we don't find the property or it's not large enough, - * 'val' will remained unchanged and we'll return -1. Otherwise 'val' - * gets updated with the property value and we return 0. - */ -static int -promprop2uint(di_node_t n, di_prom_handle_t ph, const char *propnm, - uint_t *val) -{ - di_prom_prop_t pp = DI_PROM_PROP_NIL; - uchar_t *buf; - - while ((pp = di_prom_prop_next(ph, n, pp)) != DI_PROM_PROP_NIL) { - if (strcmp(di_prom_prop_name(pp), propnm) == 0) { - if (di_prom_prop_data(pp, &buf) < sizeof (uint_t)) - continue; - bcopy(buf, val, sizeof (uint_t)); - return (0); - } - } - return (-1); -} - -/* - * If this devinfo node was added by the PCI hotplug framework it - * doesn't have the PROM properties, but hopefully has the properties - * we're looking for attached directly to the devinfo node. We only - * care about the first four bytes of the property, which we read as - * our unsigned integer. The remaining bytes are ignored. If we - * don't find the property we're looking for, or can't get its value, - * 'val' remains unchanged and we return -1. Otherwise 'val' gets the - * property value and we return 0. - */ -static int -hwprop2uint(di_node_t n, const char *propnm, uint_t *val) -{ - di_prop_t hp = DI_PROP_NIL; - uchar_t *buf; - - while ((hp = di_prop_next(n, hp)) != DI_PROP_NIL) { - if (strcmp(di_prop_name(hp), propnm) == 0) { - if (di_prop_bytes(hp, &buf) < sizeof (uint_t)) - continue; - bcopy(buf, val, sizeof (uint_t)); - return (0); - } - } - return (-1); -} - -/* - * copy_ancestor_prop - * Look for a prop of name 'prop' on an ancestor node in the - * topo tree and duplicate that property and its value on node. - */ -static void -copy_ancestor_prop(tnode_t *node, const char *prop) -{ - const char *value; - tnode_t *p = node; - - if (p == NULL || prop == NULL) - return; - - while ((p = topo_parent(p)) != NULL) - if ((value = topo_get_prop(p, prop)) != NULL) { - (void) topo_set_prop(node, prop, value); - break; - } -} - -/* - * copy_prop - * Look for a prop of name 'prop' on the 'from' node in the - * topo tree and duplicate that property and its value on node. - */ -static void -copy_prop(const char *prop, tnode_t *node, tnode_t *from) -{ - const char *value; - - if (node == NULL || prop == NULL || from == NULL) - return; - - if ((value = topo_get_prop(from, prop)) != NULL) - (void) topo_set_prop(node, prop, value); -} - -static void -set_fru_info(tnode_t *node) -{ - if (topo_get_prop(node, PLATFRU) == NULL) - copy_ancestor_prop(node, PLATFRU); -} - -static void -set_devtype_prop(tnode_t *node, di_node_t dinode, di_prom_handle_t ph) -{ - di_prom_prop_t pp = DI_PROM_PROP_NIL; - di_prop_t hp = DI_PROP_NIL; - uchar_t *typbuf; - char *tmpbuf; - int sz = -1; - - tmpbuf = alloca(MAXPATHLEN); - - while ((hp = di_prop_next(dinode, hp)) != DI_PROP_NIL) { - if (strcmp(di_prop_name(hp), DEVTYPEPROP) == 0) { - if ((sz = di_prop_bytes(hp, &typbuf)) < 0) - continue; - break; - } - } - - if (sz < 0) { - while ((pp = di_prom_prop_next(ph, dinode, pp)) != - DI_PROM_PROP_NIL) { - if (strcmp(di_prom_prop_name(pp), DEVTYPEPROP) == 0) { - sz = di_prom_prop_data(pp, &typbuf); - if (sz < 0) - continue; - break; - } - } - } - - if (sz > 0 && sz < MAXPATHLEN - 1) { - bcopy(typbuf, tmpbuf, sz); - tmpbuf[sz] = 0; - (void) topo_set_prop(node, DEVTYPE, tmpbuf); - } -} - -/* - * Look for a hardware property containing the contents of this node's - * pci express capability register. For now, only look at hardware - * properties and not prom properties. Take the prom handle, though, in - * case we decide we need to check prom properties at a later date. - */ -/*ARGSUSED*/ -static int -get_excap(di_node_t dinode, di_prom_handle_t ph) -{ - int excap; - - if (hwprop2uint(dinode, SAVED_PCIEX_CAP_REG, (uint_t *)&excap) != 0) - return (-1); - return (excap); -} - -/* - * Set an EXCAP prop for pci-express capabilities. - */ -static void -set_excap_prop(tnode_t *node, int excap) -{ - if (excap < 0) - return; - - switch (excap & PCIE_PCIECAP_DEV_TYPE_MASK) { - case PCIE_PCIECAP_DEV_TYPE_ROOT: - (void) topo_set_prop(node, EXCAPTPROP, PCIEX_ROOT); - break; - case PCIE_PCIECAP_DEV_TYPE_UP: - (void) topo_set_prop(node, EXCAPTPROP, PCIEX_SWUP); - break; - case PCIE_PCIECAP_DEV_TYPE_DOWN: - (void) topo_set_prop(node, EXCAPTPROP, PCIEX_SWDWN); - break; - case PCIE_PCIECAP_DEV_TYPE_PCI2PCIE: - (void) topo_set_prop(node, EXCAPTPROP, PCIEX_BUS); - break; - case PCIE_PCIECAP_DEV_TYPE_PCIE2PCI: - (void) topo_set_prop(node, EXCAPTPROP, PCI_BUS); - break; - case PCIE_PCIECAP_DEV_TYPE_PCIE_DEV: - (void) topo_set_prop(node, EXCAPTPROP, PCIEX_DEVICE); - break; - } -} - -/* - * Get any physical slot name property on this node. The node has to - * declare itself as representing a physical slot number by having a - * .PHYSLOTNUM property. We then look for a .PHYSLOTNAME<slot-#> - * property on the node or an ancestor of the node. If the property - * is found on an ancestor, this routine has the side-effect of - * copying the property to this node. - */ -const char * -slotname_from_tprops(tnode_t *node) -{ - const char *str; - char *tmpbuf; - char *left; - int physlot; - - if ((str = topo_get_prop(node, ".PHYSLOTNUM")) == NULL) - return (NULL); - - physlot = (int)strtol(str, &left, 0); - if (str == left || physlot < 0 || physlot > 0x1fff) - return (NULL); - - tmpbuf = alloca(20); - (void) snprintf(tmpbuf, 20, ".PHYSLOTNAME%d", physlot); - if ((str = topo_get_prop(node, tmpbuf)) != NULL) - return (str); - copy_ancestor_prop(node, tmpbuf); - return (topo_get_prop(node, tmpbuf)); -} - -static void -set_std_properties(tnode_t *node, di_node_t dinode, di_prom_handle_t ph) -{ - const char *labelval; - const char *platval; - tnode_t *pop; - char *tmpbuf; - char *dnpath; - char *dnm; - int devno; - - /* - * If it's a root complex, set the pciex capabilities property - */ - if (strcmp(PCIEX_ROOT, topo_name(node)) == 0) - (void) topo_set_prop(node, EXCAPTPROP, PCIEX_ROOT); - - /* - * If it's a device node, we pretty much don't add any props - */ - if (strcmp(PCI_DEVICE, topo_name(node)) == 0 || - strcmp(PCIEX_DEVICE, topo_name(node)) == 0) { - set_fru_info(node); - return; - } - - tmpbuf = alloca(MAXPATHLEN); - - /* - * Create a DEVTYPE property as necessary - */ - set_devtype_prop(node, dinode, ph); - - /* - * Cheat for now and always say the thing is ON - */ - (void) topo_set_prop(node, ON, TPROP_TRUE); - - if ((dnpath = di_devfs_path(dinode)) != NULL) { - (void) topo_set_prop(node, DEV, dnpath); - di_devfs_path_free(dnpath); - } - - if ((dnm = di_driver_name(dinode)) != NULL) - (void) topo_set_prop(node, DRIVER, dnm); - - /* - * For functions, set LABEL based on a .SLOTNM<devno> property - * in our parent's parent or a .PHYSLOTNAME<slot-#> property - * in an ancestor, or the parent's parent's LABEL, but only if - * LABEL is not already set. Also set PLATFRU and PLATASRU - * based on any .PLATFRU<devno> and .PLATASRU<devno> - * properties from parent's parent. - */ - if (strcmp(PCI_FUNCTION, topo_name(node)) != 0 && - strcmp(PCIEX_FUNCTION, topo_name(node)) != 0) - return; - - pop = topo_parent(topo_parent(node)); - devno = topo_get_instance_num(topo_parent(node)); - - if ((labelval = topo_get_prop(node, LABEL)) == NULL) { - (void) snprintf(tmpbuf, MAXPATHLEN, ".SLOTNM%d", devno); - if ((labelval = topo_get_prop(pop, tmpbuf)) != NULL || - (labelval = slotname_from_tprops(pop)) != NULL) { - (void) topo_set_prop(node, LABEL, labelval); - } else { - copy_ancestor_prop(node, LABEL); - } - } - - if (topo_get_prop(node, PLATASRU) == NULL) { - (void) snprintf(tmpbuf, MAXPATHLEN, ".%s%d", PLATASRU, devno); - if ((platval = topo_get_prop(pop, tmpbuf)) != NULL) - (void) topo_set_prop(node, PLATASRU, platval); - } - - /* - * Pecking order for determining the value of PLAT-FRU: - * - * PLAT-FRU already defined by the .topo file, done. - * .PLATFRU<devno> defined, copy that as the value, done. - * LABEL defined (and not inherited), copy that as the value, - * done. - * Copy value from an ancestor. - */ - if (topo_get_prop(node, PLATFRU) == NULL) { - (void) snprintf(tmpbuf, MAXPATHLEN, ".%s%d", PLATFRU, devno); - if ((platval = topo_get_prop(pop, tmpbuf)) != NULL) { - (void) topo_set_prop(node, PLATFRU, platval); - } else { - if (labelval != NULL) - (void) topo_set_prop(node, PLATFRU, labelval); - else - copy_ancestor_prop(node, PLATFRU); - } - } -} - -/* - * fix_dev_prop -- sometimes di_devfs_path() doesn't tell the whole - * story, leaving off the device and function number. Chances are if - * devfs doesn't put these on then we'll never see this device as an - * error detector called out in an ereport. Unfortunately, there are - * races and we sometimes do get ereports from devices that devfs - * decides aren't there. For example, the error injector card seems - * to bounce in and out of existence according to devfs. We tack on - * the missing dev and fn here so that the DEV property used to look - * up the topology node is correct. - */ -static void -fix_dev_prop(tnode_t *node, int devno, int fnno) -{ - const char *curdev; - char *lastslash; - char *newpath; - int need; - - /* Check if there is a DEV prop to fix. */ - if ((curdev = topo_get_prop(node, DEV)) == NULL) - return; - - /* - * We only care about the last component of the dev path. If - * we don't find a slash, something is probably weird and we'll - * just bail. - */ - if ((lastslash = strrchr(curdev, '/')) == NULL) - return; - - /* - * If an @ sign is present in the last component, the - * di_devfs_path() result had the device,fn unit-address. - * In that case there's nothing we need do. - */ - if (strchr(lastslash, '@') != NULL) - return; - - if (fnno == 0) - need = snprintf(NULL, 0, "%s@%x", curdev, devno); - else - need = snprintf(NULL, 0, "%s@%x,%x", curdev, devno, fnno); - need++; - - newpath = alloca(need); - - if (fnno == 0) - (void) snprintf(newpath, need, "%s@%x", curdev, devno); - else - (void) snprintf(newpath, need, "%s@%x,%x", curdev, devno, fnno); - (void) topo_set_prop(node, DEV, newpath); -} - -static int -slot_info_from_props(di_node_t n, di_prom_handle_t ph, - int *physlot, uint_t *slotmap, uchar_t **slotbuf) -{ - di_prom_prop_t pp = DI_PROM_PROP_NIL; - di_prop_t hp = DI_PROP_NIL; - uint_t slotcap = 0; - uint_t excap = 0; - char *prnm; - int slotsz = -1; - - while ((hp = di_prop_next(n, hp)) != DI_PROP_NIL) { - prnm = di_prop_name(hp); - if (strcmp(prnm, SLOTPROP) == 0) { - slotsz = di_prop_bytes(hp, slotbuf); - if (slotsz < sizeof (uint_t)) - continue; - bcopy(*slotbuf, slotmap, sizeof (uint_t)); - break; - } else if (strcmp(prnm, PHYSPROP) == 0) { - slotsz = di_prop_bytes(hp, slotbuf); - if (slotsz != sizeof (int)) - continue; - bcopy(*slotbuf, physlot, sizeof (int)); - break; - } - } - - if (slotsz < 0) { - while ((pp = di_prom_prop_next(ph, n, pp)) != - DI_PROM_PROP_NIL) { - prnm = di_prom_prop_name(pp); - if (strcmp(prnm, SLOTPROP) == 0) { - slotsz = di_prom_prop_data(pp, slotbuf); - if (slotsz < sizeof (uint_t)) - continue; - bcopy(*slotbuf, slotmap, sizeof (uint_t)); - break; - } else if (strcmp(prnm, PHYSPROP) == 0) { - slotsz = di_prom_prop_data(pp, slotbuf); - if (slotsz != sizeof (int)) - continue; - bcopy(*slotbuf, physlot, sizeof (int)); - break; - } - } - } - - if (slotsz < 0) { - if (hwprop2uint(n, SAVED_PCIEX_CAP_REG, &excap) != 0 || - (excap & PCIE_PCIECAP_SLOT_IMPL) == 0 || - hwprop2uint(n, SAVED_PCIEX_SLOTCAP_REG, &slotcap) != 0) - return (slotsz); - *physlot = slotcap >> PCIE_SLOTCAP_PHY_SLOT_NUM_SHIFT; - slotsz = 0; - } - - return (slotsz); -} - -static void -set_slot_info(tnode_t *tn, di_node_t n, di_prom_handle_t ph) -{ - const char *slotnumstr; - uchar_t *slotbuf; - uint_t slotmap = 0; - char *slotname; - char *tmphcbuf; - char *fmribuf; - char *tmpbuf; - char *left; - int physlot = -1; - int andbit; - - /* - * An absolute physical slot number defined in the .topo overrides - * anything we might find in devinfo properties. - */ - if ((slotnumstr = topo_get_prop(tn, ".PHYSLOTNUM")) != NULL) { - physlot = (int)strtol(slotnumstr, &left, 0); - /* - * Check for failure to interpret the property - * as a valid slot number, or for a bogus slot - * number. - */ - if (slotnumstr == left || physlot < 0 || physlot > 0x1fff) - physlot = -1; - } - - /* - * No .topo override, so look for "slot-names" or - * "physical-slot#" properties. - */ - if (physlot < 0 && - slot_info_from_props(n, ph, &physlot, &slotmap, &slotbuf) < 0) - return; - - /* - * physical-slot# of zero indicates everything is on-board, ... - */ - if (physlot == 0) - return; - - /* - * ... else it's the pciexpress indicator for what slot the child is - * in and so we'll set a property for later use in describing the - * FRU. - */ - if (physlot > 0 && physlot <= 0x1fff) { - /* - * If no .PHYSLOTNUM property is set, we should set one - * so folks coming along later can use that number to find - * the .PHYSLOTNAME<.PHYSLOTNUM> property. - */ - tmpbuf = alloca(20); - if (topo_get_prop(tn, ".PHYSLOTNUM") == NULL) { - (void) snprintf(tmpbuf, 20, "%d", physlot); - (void) topo_set_prop(tn, ".PHYSLOTNUM", tmpbuf); - } - /* - * A .PHYSLOTNAME defined in the .topo overrides any - * value we would set. The name is allowed to be on - * any of our ancestors, so we copy it here first. - */ - (void) snprintf(tmpbuf, 20, ".PHYSLOTNAME%d", physlot); - if (topo_get_prop(tn, tmpbuf) == NULL) - copy_ancestor_prop(tn, tmpbuf); - if (topo_get_prop(tn, tmpbuf) == NULL) { - /* - * No .PHYSLOTNAME<slot-#> is set, so we - * create one, making it the somewhat boring - * "hc:///component=SLOT <slot-#>". - */ - fmribuf = alloca(32); - (void) snprintf(fmribuf, 32, - "hc:///component=SLOT %d", physlot); - (void) topo_set_prop(tn, tmpbuf, fmribuf); - } - return; - } - - if (slotmap == 0) - return; - - tmpbuf = alloca(10); - tmphcbuf = alloca(MAXPATHLEN); - - slotname = (char *)&slotbuf[4]; - for (andbit = 0; andbit < 32; andbit++) { - if (slotmap & (1<<andbit)) { - char *s = slotname; - (void) snprintf(tmpbuf, 10, ".SLOTNM%d", andbit); - slotname += strlen(s) + 1; - /* - * Let a slot name defined in the .topo override - * the value from the slot-names property. This - * allows us to fix up mistakes in the OBP (can - * you say chalupa) or elsewise fudge the label - * creatively from the .topo file. - */ - if (topo_get_prop(tn, tmpbuf) == NULL) { - (void) snprintf(tmphcbuf, - MAXPATHLEN, "hc:///component=%s", s); - (void) topo_set_prop(tn, tmpbuf, tmphcbuf); - } - } - } -} - -static int -minorwalkcb(di_node_t din, di_minor_t dim, void *arg) -{ - tnode_t *tn = (tnode_t *)arg; - char *pnm; - char *devname; - char *apath; - - apath = alloca(MAXPATHLEN); - pnm = alloca(MAXPATHLEN); - - /* - * Use any attachment point info to indirectly set PLATASRU - * and PLATFRU properties on children of the bus node. We set - * .ASRU# and .FRU# values to be inherited by the appropriate - * children. We allow these to be overridden in the .topo file - * by not setting a property value here if one already exists. - */ - if ((devname = di_devfs_path(din)) == NULL) - return (DI_WALK_CONTINUE); - - (void) snprintf(pnm, - MAXPATHLEN, ".%s%d", PLATASRU, dim->dev_minor % 256); - if (topo_get_prop(tn, pnm) == NULL) { - (void) snprintf(apath, - MAXPATHLEN, "hc:///component=%s", di_minor_name(dim)); - (void) topo_set_prop(tn, pnm, apath); - } - (void) snprintf(pnm, - MAXPATHLEN, ".%s%d", PLATFRU, dim->dev_minor % 256); - if (topo_get_prop(tn, pnm) == NULL) { - (void) snprintf(apath, - MAXPATHLEN, - "hc:///component=%s:%s", - devname, - di_minor_name(dim)); - (void) topo_set_prop(tn, pnm, apath); - } - di_devfs_path_free(devname); - return (DI_WALK_CONTINUE); -} - -static void -set_attachpt_info(tnode_t *tn, di_node_t n) -{ - (void) di_walk_minor(n, "ddi_ctl:attachment_point:pci", 0, - (void *)tn, minorwalkcb); -} - -#define IDBUFLEN 13 - -static const char * -set_pci_properties(tnode_t *tn, di_node_t n, di_prom_handle_t ph) -{ - static char idstring[IDBUFLEN]; /* pciVVVV,DDDD */ - uint_t vendor = 0x10000; /* out of legal range for a vendor-id */ - uint_t device = 0x10000; /* out of legal range for a device-id */ - char *tmpbuf; - - tmpbuf = alloca(MAXPATHLEN); - - (void) hwprop2uint(n, DEVIDPROP, &device); - if (device == 0x10000) - (void) promprop2uint(n, ph, DEVIDPROP, &device); - if (device != 0x10000) { - (void) snprintf(tmpbuf, MAXPATHLEN, "%x", device); - (void) topo_set_prop(tn, DEVIDTPROP, tmpbuf); - } - - (void) hwprop2uint(n, VENDIDPROP, &vendor); - if (vendor == 0x10000) - (void) promprop2uint(n, ph, VENDIDPROP, &vendor); - if (vendor != 0x10000) { - (void) snprintf(tmpbuf, MAXPATHLEN, "%x", vendor); - (void) topo_set_prop(tn, VENDIDTPROP, tmpbuf); - } - - if (device != 0x10000 && vendor != 0x10000) { - (void) snprintf(idstring, IDBUFLEN, "pci%x,%x", vendor, device); - return (idstring); - } - return (NULL); -} - -static int -get_class_code_and_reg(uint_t *cc, uint_t *reg, di_node_t n, - di_prom_handle_t ph) -{ - if (hwprop2uint(n, REGPROP, reg) < 0 && - promprop2uint(n, ph, REGPROP, reg) < 0) - return (-1); - - if (hwprop2uint(n, CLASSPROP, cc) < 0 && - promprop2uint(n, ph, CLASSPROP, cc) < 0) - return (-1); - - return (0); -} - -static tnode_t * -expected_child(tnode_t *parent, const char *expect_type, int intent) -{ - tnode_t *cn = NULL; - int min, max; - - /* - * We prefer to instance a child node that's uninstanced, so - * it inherits all the right properties. - */ - while ((cn = topo_next_child(parent, cn)) != NULL) { - if (strcmp(topo_name(cn), expect_type) != 0) - continue; - if (topo_get_instance_num(cn) < 0) { - topo_get_instance_range(cn, &min, &max); - if (intent < 0 || (intent >= min && intent <= max)) - break; - } - } - - if (cn == NULL) { - topo_out(TOPO_DEBUG, - "Expected to set instance %d of a %s topo node. " - "But found no match.", intent, expect_type); - } - return (cn); -} - -static void -examine_prom_props(tnode_t *pn, di_node_t n, di_prom_handle_t ph) -{ - tnode_t *ppn; - tnode_t *cn = NULL; - uint_t reg, cc; - const char *topof; - const char *parentcap; - uint_t childclass, childsubclass; - int childcap, childetyp; - int busno, devno, fnno; - - if (get_class_code_and_reg(&cc, ®, n, ph) < 0) - return; - - busno = PCI_REG_BUS_G(reg); - devno = PCI_REG_DEV_G(reg); - fnno = PCI_REG_FUNC_G(reg); - - /* - * Get the child's pci express capabilities (if any). We'll later - * convert this to a property on the appropriate topo node. - */ - childcap = get_excap(n, ph); - if (childcap > 0) - childetyp = childcap & PCIE_PCIECAP_DEV_TYPE_MASK; - childclass = GETCLASS(cc); - childsubclass = GETSUBCLASS(cc); - - /* - * If the child is a root complex, enumerate it as such rather - * than as just another dev/fn of the parent pcibus. - */ - if (childcap > 0 && childetyp == PCIE_PCIECAP_DEV_TYPE_ROOT) { - if ((ppn = topo_parent(pn)) == NULL || - (pn = expected_child(ppn, PCIEX_ROOT, devno)) == NULL) { - topo_out(TOPO_DEBUG, "found pci-express root" - "complex, but grand-parent topo node " - "lacks a " PCIEX_ROOT " child node.\n"); - return; - } - pn = topo_set_instance_num(pn, devno); - set_excap_prop(pn, childcap); - set_slot_info(pn, n, ph); - /* - * Beneath a root complex we expect to find a switch, - * bridge or direct link. Whichever it is, it will be - * enumerated as a pci-express bus/dev/fn trio. - */ - if ((cn = expected_child(pn, PCIEX_BUS, -1)) == NULL) { - topo_out(TOPO_DEBUG, - "found pci-express root complex " - "that lacks a " PCIEX_BUS - "child node to instance.\n"); - return; - } - instantiate_children(cn, n, ph); - return; - } - - /* - * Sanity check here: The child of an upstream switch should - * be a downstream switch. - */ - if ((parentcap = topo_get_prop(pn, EXCAPTPROP)) != NULL) { - if (strcmp(parentcap, PCIEX_SWUP) == 0) { - if (childclass != PCI_CLASS_BRIDGE || - childetyp != PCIE_PCIECAP_DEV_TYPE_DOWN) { - topo_out(TOPO_DEBUG, - "Devinfo child of UP switch is not a " - "down switch.\n"); - return; - } - } - } - - /* - * If the parent is an unenumerated bus, do it a favor and set - * an instance number based on the bus defined for this - * device. - */ - if ((strcmp(PCI_BUS, topo_name(pn)) == 0 || - strcmp(PCIEX_BUS, topo_name(pn)) == 0) && - topo_get_instance_num(pn) < 0) { - pn = topo_set_instance_num(pn, busno); - topo_out(TOPO_DEBUG, "Set parent's bus instance #%d," - " np=%p.\n", busno, (void *)pn); - set_slot_info(pn, di_parent_node(n), ph); - set_attachpt_info(pn, di_parent_node(n)); - set_fru_info(pn); - } - - if (strcmp(PCI_BUS, topo_name(pn)) == 0 && - (cn = expected_child(pn, PCI_DEVICE, devno)) == NULL) - return; - if (strcmp(PCIEX_BUS, topo_name(pn)) == 0 && - (cn = expected_child(pn, PCIEX_DEVICE, devno)) == - NULL) - return; - if (cn == NULL) { - topo_out(TOPO_DEBUG, "Topo node is neither " PCI_BUS - " nor " PCIEX_BUS " so, we don't know what the heck " - "the child node would be.\n"); - return; - } - - pn = topo_set_instance_num(cn, devno); - topo_out(TOPO_DEBUG, "Set device instance #%d.\n", devno); - set_std_properties(pn, n, ph); - - if (strcmp(PCI_DEVICE, topo_name(pn)) == 0 && - (cn = expected_child(pn, PCI_FUNCTION, fnno)) == NULL) - return; - if (strcmp(PCIEX_DEVICE, topo_name(pn)) == 0 && - (cn = expected_child(pn, PCIEX_FUNCTION, fnno)) == NULL) - return; - pn = topo_set_instance_num(cn, fnno); - topo_out(TOPO_DEBUG, "Set function instance #%d.\n", fnno); - set_excap_prop(pn, childcap); - set_std_properties(pn, n, ph); - fix_dev_prop(pn, devno, fnno); - - if ((topof = set_pci_properties(pn, n, ph)) != NULL) { - /* - * Look for topology information specific to this - * vendor-id & device-id, if any. - */ - (void) topo_load(topof, pn); - } - - if (childclass == PCI_CLASS_BRIDGE) { - topo_out(TOPO_DEBUG, "device/fn is a bridge, "); - - if (childsubclass != PCI_BRIDGE_PCI) { - topo_out(TOPO_DEBUG, "but not to PCI.\n"); - return; - } - /* - * What sort of child is this? If there is no - * PCI-express capability or if the capability is a - * bridge to PCI, then children we will enumerate are - * PCI buses. - */ - if (childcap < 0 || - childetyp == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) { - topo_out(TOPO_DEBUG, - "no PCI-express capabilities, or a " - "bridge to PCI.\n"); - if ((cn = expected_child(pn, PCI_BUS, -1)) == NULL) { - topo_out(TOPO_DEBUG, - "BUT the topo nodes lacks a " - PCI_BUS - "child node.\n"); - return; - } - } else { - topo_out(TOPO_DEBUG, - "and has PCI-express capability.\n"); - cn = expected_child(pn, PCIEX_BUS, -1); - if (cn == NULL) { - topo_out(TOPO_DEBUG, - "but the topo nodes lacks a " - PCIEX_BUS - "child node.\n"); - return; - } - } - /* - * We don't know the instance number of this bus, - * so we'll have to rely on it getting filled in - * later by one of its children. - */ - instantiate_children(cn, n, Promtree); - return; - } -} - -void -instantiate_children(tnode_t *tn, di_node_t n, di_prom_handle_t ph) -{ - di_node_t pn; - - pn = di_child_node(n); - while (pn != DI_NODE_NIL) { - examine_prom_props(tn, pn, ph); - pn = di_sibling_node(pn); - } -} - -static di_node_t -drivers_match(const char *drvr_type, const char *devprop) -{ - di_node_t pnode; - char *dnpath; - - topo_out(TOPO_DEBUG, "search for drivers of type %s.\n", drvr_type); - - pnode = di_drv_first_node(drvr_type, Devtree); - while (pnode != DI_NODE_NIL) { - if ((dnpath = di_devfs_path(pnode)) == NULL) - continue; - topo_out(TOPO_DEBUG, "%s within %s ? ", dnpath, devprop); - if (strcmp(devprop, dnpath) == 0) { - topo_out(TOPO_DEBUG, "yesh!\n"); - di_devfs_path_free(dnpath); - break; - } - topo_out(TOPO_DEBUG, "no.\n"); - di_devfs_path_free(dnpath); - pnode = di_drv_next_node(pnode); - } - return (pnode); -} - -static void -represent_hostbridge_pbm(tnode_t *node) -{ - tnode_t *parent; - tnode_t *cn, *cn1; - - /* - * Only do this for PCI_BUS nodes - */ - if (strcmp(PCI_BUS, topo_name(node)) != 0) - return; - - if ((cn = expected_child(node, PCI_DEVICE, 32)) == NULL) - return; - cn = topo_set_instance_num(cn, 32); - set_fru_info(cn); - if (strcmp(PCI_DEVICE, topo_name(cn)) == 0 && - (cn1 = expected_child(cn, PCI_FUNCTION, 0)) == NULL) - return; - if (strcmp(PCIEX_DEVICE, topo_name(cn)) == 0 && - (cn1 = expected_child(cn, PCIEX_FUNCTION, 0)) == NULL) - return; - cn = topo_set_instance_num(cn1, 0); - copy_ancestor_prop(cn, DEV); - copy_ancestor_prop(cn, ATTACHD); - copy_ancestor_prop(cn, DRIVER); - copy_ancestor_prop(cn, ON); - set_fru_info(cn); - - (void) topo_set_prop(node, DEV, "none"); - - /* - * The topo node for the hostbridge should inherit the node's - * DRIVER property. The hostbridge is driven by the same - * software as the bus. - */ - if ((parent = topo_parent(node)) != NULL && - strcmp(topo_name(parent), "hostbridge") == 0) - copy_prop(DRIVER, parent, node); -} - -static void -instantiate_all(tnode_t *node, const char *drvr_type, di_prom_handle_t ph) -{ - di_node_t pnode; - char *dnpath; - - pnode = di_drv_first_node(drvr_type, Devtree); - while (pnode != DI_NODE_NIL) { - const char *devprop; - tnode_t *parent; - - if ((dnpath = di_devfs_path(pnode)) == NULL) - continue; - if ((parent = topo_parent(node)) != NULL) - devprop = topo_get_prop(parent, DEV); - - if (parent == NULL || - devprop == NULL || - strcmp(devprop, dnpath) == 0) { - set_std_properties(node, pnode, ph); - set_slot_info(node, pnode, ph); - set_attachpt_info(node, pnode); - set_fru_info(node); - represent_hostbridge_pbm(node); - instantiate_children(node, pnode, ph); - } - di_devfs_path_free(dnpath); - pnode = di_drv_next_node(pnode); - } -} - -di_node_t -pci_di_match(const char *devproppath) -{ - di_node_t pnode; - - /* - * Search for devinfo nodes for psycho, schizo, or generic - * pci bus and find one that matches the DEV property path - * passed to us. - */ - pnode = drivers_match(PSYCHO, devproppath); - if (pnode != DI_NODE_NIL) - return (pnode); - - pnode = drivers_match(SCHIZO, devproppath); - if (pnode != DI_NODE_NIL) - return (pnode); - - pnode = drivers_match(NPE, devproppath); - if (pnode != DI_NODE_NIL) - return (pnode); - - pnode = drivers_match(PX, devproppath); - if (pnode != DI_NODE_NIL) - return (pnode); - - pnode = drivers_match(PCI, devproppath); - return (pnode); -} - -di_node_t -pciex_di_match(const char *devproppath) -{ - di_node_t pnode; - - pnode = drivers_match(NPE, devproppath); - if (pnode != DI_NODE_NIL) - return (pnode); - - pnode = drivers_match(PX, devproppath); - return (pnode); -} - -/* - * Check to see if "node" is the descendant of a topo node that's not - * enumerated, but whose instance number is unambiguous. If it is, - * we can enumerate that puppy because we now know that the ancestor - * is for real. - */ -static void -confirm_ancestors(tnode_t *node) -{ - tnode_t *parent; - int min, max; - - parent = topo_parent(node); - while (parent != NULL) { - if (topo_get_instance_num(parent) < 0) { - topo_get_instance_range(parent, &min, &max); - if (min == max && min >= 0) - (void) topo_set_instance_num(parent, min); - } - parent = topo_parent(parent); - } -} - -/* - * The enum_pci_bus() routine gets called by topo to set instance - * numbers for all the PCI bus nodes. The enumerator takes care of - * all devices, functions, bridges, and sub-buses beneath the bus - * node as well. - */ -void -enum_pci_bus(tnode_t *node) -{ - const char *dev, *scan; - di_node_t selfdn; - tnode_t *self; - int express; - int min, max; - - /* - * First thing, decide if we're looking for pci-express or - * good old pci. Then orient ourselves within the devinfo - * tree. The static topo info hopefully will have left us an - * orienting clue by providing a DEV property. - * - * Alternatively if there is no DEV, but there's a SCAN - * property, we'll scan for pci buses. - */ - if (strcmp(PCIEX_ROOT, topo_name(node)) == 0) - express = 1; - else if (strcmp(PCI_BUS, topo_name(node)) == 0) - express = 0; - else - return; - - if ((dev = topo_get_prop(node, DEV)) == NULL) { - scan = topo_get_prop(node, SCAN); - if (scan == NULL) { - topo_out(TOPO_DEBUG, - "Bus tnode has no DEV or SCAN prop\n"); - return; - } - if (express == 0) { - instantiate_all(node, PCI, Promtree); - instantiate_all(node, NPE, Promtree); - instantiate_all(node, PX, Promtree); - } else { - instantiate_all(node, NPE, Promtree); - instantiate_all(node, PX, Promtree); - } - return; - } else { - if (express == 0 && - (selfdn = pci_di_match(dev)) == DI_NODE_NIL) { - topo_out(TOPO_DEBUG, - "No match found for %s in devinfo.\n", dev); - return; - } - if (express == 1 && - (selfdn = pciex_di_match(dev)) == DI_NODE_NIL) { - topo_out(TOPO_DEBUG, - "No match found for %s in devinfo.\n", dev); - return; - } - } - - /* - * We've found ourselves in the devtree. A correctly written - * .topo file will have left the instance number unambiguous - * (a range of exactly one number) and so we'll know and can - * officially establish the instance number of the bus or root - * complex. This creates a new topo node returned to us, with - * children for which we must set instance numbers... - */ - topo_get_instance_range(node, &min, &max); - if (min < 0 || max < 0 || min != max) { - topo_out(TOPO_DEBUG, - "Unexpected bus instance min %d != max %d.\n", - min, max); - return; - } - self = topo_set_instance_num(node, min); - set_std_properties(self, selfdn, Promtree); - set_slot_info(self, selfdn, Promtree); - set_attachpt_info(self, selfdn); - set_fru_info(self); - - if (express == 0) { - /* - * We represent the hostbridge's PCI bus module as a "device" - * on the bus outside of the range of normal devices. - */ - represent_hostbridge_pbm(self); - } else { - /* - * Beneath a root complex we expect to find a switch, - * bridge or direct link. Whichever it is, it will be - * enumerated as a pci-express bus/dev/fn trio. - */ - if ((self = expected_child(self, PCIEX_BUS, -1)) == NULL) { - topo_out(TOPO_DEBUG, - "Found pci-express root complex " - "that lacks a " PCIEX_BUS - " child node to instance.\n"); - return; - } - } - instantiate_children(self, selfdn, Promtree); - confirm_ancestors(self); -} - -/* - * find_devinfo_childdev() - * - * Search through pci/pci-express devinfo nodes that are a child of - * the parent, looking for ones whose device # matches devno. The - * function is recallable because a device can have multiple - * functions. - */ -di_node_t -find_devinfo_childdev(di_node_t parent, di_node_t child, int devno, int *fnno) -{ - di_node_t cn; - uint_t reg, cc; - int cdevno; - - if (child != DI_NODE_NIL) - cn = di_sibling_node(child); - else - cn = di_child_node(parent); - while (cn != DI_NODE_NIL) { - if (get_class_code_and_reg(&cc, ®, cn, Promtree) < 0) - continue; - cdevno = PCI_REG_DEV_G(reg); - *fnno = PCI_REG_FUNC_G(reg); - if (cdevno == devno) - break; - cn = di_sibling_node(cn); - } - return (cn); -} - -/* - * The enum_pci_dev() routine gets called by topo to explicitly set - * instance numbers for specific PCI or PCI-Express device nodes. - */ -void -enum_pci_dev(tnode_t *node) -{ - const char *dev; - di_node_t ancdn, selfdn; - tnode_t *fn = DI_NODE_NIL; - tnode_t *pn; - const char *topof; - int fno; - int excap; - int min, max; - - /* - * Our parent's parent node should have a DEV property. From - * this we should be able to orient ourselves in the devinfo - * tree. - */ - if (((pn = topo_parent(node)) == NULL) || - ((pn = topo_parent(pn)) == NULL) || - ((dev = topo_get_prop(pn, DEV)) == NULL)) - return; - - if ((ancdn = di_init(dev, DINFOCPYALL)) == DI_NODE_NIL) { - topo_out(TOPO_ERR, - "PCI enumerator: " - "di_init failed for device ancestor failed.\n"); - return; - } - /* - * We've found ourselves in the devtree. A correctly written - * .topo file will have left the instance number unambiguous - * (a range of exactly one number) and so we'll know and can - * officially establish the instance number of the device. - * This creates a new topo node returned to us, with children - * for which we must set instance numbers... - */ - topo_get_instance_range(node, &min, &max); - if (min < 0 || max < 0 || min != max) { - topo_out(TOPO_DEBUG, - "Unexpected device instance min %d != max %d.\n", - min, max); - di_fini(ancdn); - return; - } - selfdn = find_devinfo_childdev(ancdn, DI_NODE_NIL, min, &fno); - if (selfdn == DI_NODE_NIL) { - topo_out(TOPO_DEBUG, "No device # %d found.\n", min); - di_fini(ancdn); - return; - } - node = topo_set_instance_num(node, min); - topo_out(TOPO_DEBUG, "Set device instance #%d.\n", min); - set_std_properties(node, selfdn, Promtree); - do { - excap = get_excap(selfdn, Promtree); - if (strcmp(PCI_DEVICE, topo_name(node)) == 0 && - (fn = expected_child(node, PCI_FUNCTION, fno)) == NULL) { - topo_out(TOPO_DEBUG, - PCI_DEVICE "node lacks a " PCI_FUNCTION - "child node.\n"); - di_fini(ancdn); - return; - } - if (strcmp(PCIEX_DEVICE, topo_name(node)) == 0 && - (fn = expected_child(node, PCIEX_FUNCTION, fno)) == NULL) { - topo_out(TOPO_DEBUG, - PCIEX_DEVICE "node lacks a " PCIEX_FUNCTION - "child node.\n"); - di_fini(ancdn); - return; - } - fn = topo_set_instance_num(fn, fno); - topo_out(TOPO_DEBUG, "Set function instance #%d.\n", fno); - set_excap_prop(fn, excap); - set_std_properties(fn, selfdn, Promtree); - fix_dev_prop(fn, min, fno); - topof = set_pci_properties(fn, selfdn, Promtree); - if (topof != NULL) { - /* - * Look for topology information specific to this - * vendor-id & device-id, if any. - */ - (void) topo_load(topof, fn); - } - selfdn = find_devinfo_childdev(DI_NODE_NIL, selfdn, min, &fno); - } while (selfdn != DI_NODE_NIL); - - if (fn != DI_NODE_NIL) - confirm_ancestors(fn); - di_fini(ancdn); -} - -void -topo_pci_enum(tnode_t *node) -{ - /* - * Any enumerations other than buses should have already - * happened at the time the bus was enumerated, so we can just - * return. - */ - if (strcmp(PCI_BUS, topo_name(node)) == 0 || - strcmp(PCIEX_ROOT, topo_name(node)) == 0) { - enum_pci_bus(node); - } else if (strcmp(PCI_DEVICE, topo_name(node)) == 0 || - strcmp(PCIEX_DEVICE, topo_name(node)) == 0) { - enum_pci_dev(node); - } -} diff --git a/usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.topo b/usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.topo deleted file mode 100644 index 76d51514e7..0000000000 --- a/usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.topo +++ /dev/null @@ -1,29 +0,0 @@ -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -#ident "%Z%%M% %I% %E% SMI" - -/pcidev[0-31]/pcifn[0-7]/pcibus[0-15] -/pcidev[0-31]/pcifn[0-7]/pciexrc[0-31] -/pcidev[32]/pcifn[0] diff --git a/usr/src/cmd/fm/topo/plugins/common/pciexbus/Makefile b/usr/src/cmd/fm/topo/plugins/common/pciexbus/Makefile deleted file mode 100644 index be0539f7ef..0000000000 --- a/usr/src/cmd/fm/topo/plugins/common/pciexbus/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -MODULE = pciexbus -CLASS = common - -include ../../Makefile.topoonly diff --git a/usr/src/cmd/fm/topo/plugins/common/pciexbus/pciexbus.topo b/usr/src/cmd/fm/topo/plugins/common/pciexbus/pciexbus.topo deleted file mode 100644 index ca5b09a73e..0000000000 --- a/usr/src/cmd/fm/topo/plugins/common/pciexbus/pciexbus.topo +++ /dev/null @@ -1,29 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -/pciexdev[0-31]/pciexfn[0-7]/pciexbus[0-15] -/pciexdev[0-31]/pciexfn[0-7]/pcibus[0-15] diff --git a/usr/src/cmd/fm/topo/plugins/common/pciexrc/Makefile b/usr/src/cmd/fm/topo/plugins/common/pciexrc/Makefile deleted file mode 100644 index a92a602f48..0000000000 --- a/usr/src/cmd/fm/topo/plugins/common/pciexrc/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -MODULE = pciexrc -CLASS = common - -include ../../Makefile.topoonly diff --git a/usr/src/cmd/fm/topo/plugins/common/pciexrc/pciexrc.topo b/usr/src/cmd/fm/topo/plugins/common/pciexrc/pciexrc.topo deleted file mode 100644 index 897abf307a..0000000000 --- a/usr/src/cmd/fm/topo/plugins/common/pciexrc/pciexrc.topo +++ /dev/null @@ -1,30 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -!share pcibus - -/pciexbus[0-31] diff --git a/usr/src/cmd/fm/topo/prtopo/Makefile b/usr/src/cmd/fm/topo/prtopo/Makefile deleted file mode 100644 index 18bde5d7dc..0000000000 --- a/usr/src/cmd/fm/topo/prtopo/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -debug := TARGET += debug - -SUBDIRS = $(MACH) - -debug: $(SUBDIRS) - -include ../../Makefile.subdirs diff --git a/usr/src/cmd/fm/topo/prtopo/common/prtopo.c b/usr/src/cmd/fm/topo/prtopo/common/prtopo.c deleted file mode 100644 index f41e42ac41..0000000000 --- a/usr/src/cmd/fm/topo/prtopo/common/prtopo.c +++ /dev/null @@ -1,318 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/fm/protocol.h> -#include <fm/libtopo.h> - -int Allprops; -int Everstyle; - -void -Usage(char *progname, char badopt) -{ - (void) fprintf(stderr, "Option not recognized -%c\n", badopt); - (void) fprintf(stderr, "Usage: %s [-a] [-d] [-e] [-v] [-p path]\n\n", - progname); - (void) fprintf(stderr, "\tBy default, %s\n" - "\tdisplays each node in the topology tree of the system in\n" - "\thc FMRI string format, for example:\n" - "\t\thc:///motherboard=0/pcibus=0/pcidev=1/pcifn=0\n\n", - progname); - (void) fprintf(stderr, "\t-v: " - "display properties attached to a node along with the node\n"); - (void) fprintf(stderr, "\t-a: " - "same as -v except includes \"invisible\" properties \n"); - (void) fprintf(stderr, "\t-d: " - "display massive amounts of debug output from libtopo\n"); - (void) fprintf(stderr, "\t-e: " - "display nodes as simple paths, \"eversholt style\", " - "for example:\n" - "\t\t/motherboard0/pcibus0/pcidev1/pcifn0\n\n"); - (void) fprintf(stderr, "\t-p path:\n" - "\t\tdisplay the topology node associated with the\n" - "\t\tprovided simple path.\n\n"); - exit(3); -} - -void -print_buf(const char *pme) -{ - (void) printf("%s", pme); -} - -/* - * buf_append -- Append str to buf if it's non-NULL. Add prepend to buf - * in front of str and append behind it (if they're non-NULL). Update - * size as you proceed, even if we run out of space to actually stuff - * characters in the buffer. - */ -static void -buf_append(ssize_t *sz, char *buf, size_t buflen, char *str, - char *prepend, char *append) -{ - ssize_t left; - - if (str == NULL) - return; - - if (buflen == 0 || (left = buflen - *sz) < 0) - left = 0; - - if (buf != NULL && left != 0) - buf += *sz; - - if (prepend == NULL && append == NULL) - *sz += snprintf(buf, left, "%s", str); - else if (prepend == NULL) - *sz += snprintf(buf, left, "%s%s", str, append); - else - *sz += snprintf(buf, left, "%s%s%s", prepend, str, append); -} - - -ssize_t -fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen) -{ - nvlist_t **hcprs = NULL; - nvlist_t *anvl = NULL; - uint8_t version; - ssize_t size = 0; - uint_t hcnprs; - char *achas = NULL; - char *adom = NULL; - char *aprod = NULL; - char *asrvr = NULL; - char *serial = NULL; - char *part = NULL; - char *root = NULL; - char *rev = NULL; - int more_auth = 0; - int err, i; - - if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || - version > FM_HC_SCHEME_VERSION) - return (-1); - - /* Get authority, if present */ - err = nvlist_lookup_nvlist(nvl, FM_FMRI_AUTHORITY, &anvl); - if (err != ENOENT) - return (-1); - - if ((err = nvlist_lookup_string(nvl, FM_FMRI_HC_ROOT, &root)) != 0) - return (-1); - - err = nvlist_lookup_nvlist_array(nvl, FM_FMRI_HC_LIST, &hcprs, &hcnprs); - if (err != 0 || hcprs == NULL) - return (-1); - - (void) nvlist_lookup_string(anvl, FM_FMRI_AUTH_PRODUCT, &aprod); - (void) nvlist_lookup_string(anvl, FM_FMRI_AUTH_CHASSIS, &achas); - (void) nvlist_lookup_string(anvl, FM_FMRI_AUTH_DOMAIN, &adom); - (void) nvlist_lookup_string(anvl, FM_FMRI_AUTH_SERVER, &asrvr); - if (aprod != NULL) - more_auth++; - if (achas != NULL) - more_auth++; - if (adom != NULL) - more_auth++; - if (asrvr != NULL) - more_auth++; - - (void) nvlist_lookup_string(nvl, FM_FMRI_HC_SERIAL_ID, &serial); - (void) nvlist_lookup_string(nvl, FM_FMRI_HC_PART, &part); - (void) nvlist_lookup_string(nvl, FM_FMRI_HC_REVISION, &rev); - - /* hc:// */ - buf_append(&size, buf, buflen, FM_FMRI_SCHEME_HC, NULL, "://"); - - /* authority, if any */ - more_auth--; - buf_append(&size, buf, buflen, aprod, FM_FMRI_AUTH_PRODUCT "=", - more_auth > 0 ? "," : NULL); - more_auth--; - buf_append(&size, buf, buflen, achas, FM_FMRI_AUTH_CHASSIS "=", - more_auth > 0 ? "," : NULL); - more_auth--; - buf_append(&size, buf, buflen, adom, FM_FMRI_AUTH_DOMAIN "=", - more_auth > 0 ? "," : NULL); - more_auth--; - buf_append(&size, buf, buflen, asrvr, FM_FMRI_AUTH_SERVER "=", NULL); - - /* separating slash */ - if (serial != NULL || part != NULL || rev != NULL) - buf_append(&size, buf, buflen, "/", NULL, NULL); - - /* hardware-id part */ - buf_append(&size, buf, buflen, serial, ":" FM_FMRI_HC_SERIAL_ID "=", - NULL); - buf_append(&size, buf, buflen, part, ":" FM_FMRI_HC_PART "=", NULL); - buf_append(&size, buf, buflen, rev, ":" FM_FMRI_HC_REVISION "=", NULL); - - /* separating slash */ - buf_append(&size, buf, buflen, "/", NULL, NULL); - - /* hc-root */ - buf_append(&size, buf, buflen, root, NULL, NULL); - - /* all the pairs */ - for (i = 0; i < hcnprs; i++) { - char *nm = NULL; - char *id = NULL; - - if (i > 0) - buf_append(&size, buf, buflen, "/", NULL, NULL); - (void) nvlist_lookup_string(hcprs[i], FM_FMRI_HC_NAME, &nm); - (void) nvlist_lookup_string(hcprs[i], FM_FMRI_HC_ID, &id); - if (nm == NULL || id == NULL) - return (-1); - buf_append(&size, buf, buflen, nm, NULL, "="); - buf_append(&size, buf, buflen, id, NULL, NULL); - } - - return (size); -} - -void -print_hc_fmri(nvlist_t *fmri) -{ - ssize_t len; - char *pbuf; - - len = fmri_nvl2str(fmri, NULL, 0); - if (len < 0 || (pbuf = malloc(len + 1)) == NULL) - return; - (void) fmri_nvl2str(fmri, pbuf, len + 1); - (void) printf("%s\n", pbuf); - free(pbuf); -} - -void -print_tnode(tnode_t *node, void *arg) -{ - const char *propn, *propv; - char *path; - nvlist_t *asfmri; - - if (Everstyle) { - path = topo_hc_path(node); - (void) printf("%s\n", path); - topo_free_path(path); - } else { - asfmri = topo_hc_fmri(node); - print_hc_fmri(asfmri); - topo_free_fmri(asfmri); - } - - if ((int)arg == 0) - return; - - propn = NULL; - while ((propn = topo_next_prop(node, propn)) != NULL) { - propv = topo_get_prop(node, propn); - if (!Allprops && propn[0] == '.') - continue; - if (strchr(propv, ' ') != NULL || strchr(propv, '\t') != NULL) - (void) printf("\t%s = \"%s\"\n", propn, propv); - else - (void) printf("\t%s = %s\n", propn, propv); - } -} - -void -main(int argc, char **argv) -{ - tnode_t *root, *node; - char *Path = NULL; - int Verbose = 0; - int Debug = 0; - int c; - - while ((c = getopt(argc, argv, ":adevp:")) != -1) { - switch (c) { - case 'a': - Allprops++; - Verbose++; - break; - case 'd': - Debug++; - break; - case 'e': - Everstyle++; - break; - case 'v': - Verbose++; - break; - case 'p': - Path = optarg; - break; - case ':': /* path not included with the given -p */ - (void) fprintf(stderr, "Path option (-p) " - "requires accompanying hc path.\n"); - exit(1); - /*NOTREACHED*/ - case '?': - default: - Usage(argv[0], optopt); - /*NOTREACHED*/ - } - } - - topo_set_out_method(print_buf); - topo_init(0, NULL); - - if (Debug) - topo_debug_on(0); - - root = topo_next_sibling(NULL, NULL); - if (root == NULL) { - (void) printf("No root of topo tree.\n"); - exit(5); - } - - if (Path != NULL) { - if ((node = topo_find_path(root, Path)) == NULL) { - (void) fprintf(stderr, - "No node found for path %s.\n", Path); - exit(2); - } else { - print_tnode(node, (void *)Verbose); - exit(0); - } - } - - if (Debug) - (void) printf("--------------------\n"); - - topo_walk(root, TOPO_VISIT_SELF_FIRST, (void *)Verbose, print_tnode); - topo_tree_release(root); - topo_fini(); - exit(0); -} diff --git a/usr/src/cmd/mdb/common/kmdb/kmdb_kvm.c b/usr/src/cmd/mdb/common/kmdb/kmdb_kvm.c index a9720e96c3..18f0d4eb7c 100644 --- a/usr/src/cmd/mdb/common/kmdb/kmdb_kvm.c +++ b/usr/src/cmd/mdb/common/kmdb/kmdb_kvm.c @@ -615,6 +615,10 @@ static const mdb_dcmd_t kmt_dcmds[] = { { "out", ":[-L len] val", "write to I/O port", kmt_out_dcmd }, { "rdmsr", ":", "read an MSR", kmt_rdmsr }, { "wrmsr", ": val", "write an MSR", kmt_wrmsr }, + { "rdpcicfg", ": bus dev func", "read a register in PCI config space", + kmt_rdpcicfg }, + { "wrpcicfg", ": bus dev func val", "write a register in PCI config " + "space", kmt_wrpcicfg }, #endif { "noducttape", NULL, NULL, kmt_noducttape }, { "regs", NULL, "print general-purpose registers", kmt_regs }, diff --git a/usr/src/cmd/mdb/common/mdb/mdb_module_load.c b/usr/src/cmd/mdb/common/mdb/mdb_module_load.c index 523f1554cb..f8a3ffcd6b 100644 --- a/usr/src/cmd/mdb/common/mdb/mdb_module_load.c +++ b/usr/src/cmd/mdb/common/mdb/mdb_module_load.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -30,6 +30,7 @@ #include <unistd.h> #include <strings.h> #include <dlfcn.h> +#include <ctype.h> #include <link.h> #include <mdb/mdb_module.h> @@ -46,7 +47,7 @@ mdb_module_load(const char *name, int mode) { const char *wformat = "no module '%s' could be found\n"; const char *fullname = NULL; - char buf[MAXPATHLEN], *p; + char buf[MAXPATHLEN], *p, *q; int i; ASSERT(!(mode & MDB_MOD_DEFER)); @@ -56,8 +57,25 @@ mdb_module_load(const char *name, int mode) (void) mdb_iob_snprintf(buf, sizeof (buf), "%s", strbasename(name)); - if ((p = strchr(buf, '.')) != NULL) - *p = '\0'; /* eliminate suffixes */ + + /* + * Remove any .so(.[0-9]+)? suffix + */ + if ((p = strrchr(buf, '.')) != NULL) { + for (q = p + 1; isdigit(*q); q++) + ; + + if (*q == '\0') { + /* found digits to remove */ + *p = '\0'; + p = strrchr(buf, '.'); /* search for ".so" */ + } + } + + if (p != NULL) { + if (strcmp(p, ".so") == 0) + *p = '\0'; + } fullname = name; name = buf; diff --git a/usr/src/cmd/mdb/common/modules/mpxio/main.h b/usr/src/cmd/mdb/common/modules/mpxio/main.h index 649496d1d7..0ebe84f463 100644 --- a/usr/src/cmd/mdb/common/modules/mpxio/main.h +++ b/usr/src/cmd/mdb/common/modules/mpxio/main.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -51,8 +51,6 @@ extern "C" { #include <sys/scsi/scsi_types.h> #include <sys/disp.h> #include <sys/types.h> -#include <sys/nvpair.h> -#include <sys/nvpair_impl.h> #include <sys/mdb_modapi.h> #define FT(var, typ) (*((typ *)(&(var)))) diff --git a/usr/src/cmd/mdb/i86pc/modules/Makefile b/usr/src/cmd/mdb/i86pc/modules/Makefile index ec7f1fb68b..e65e64d422 100644 --- a/usr/src/cmd/mdb/i86pc/modules/Makefile +++ b/usr/src/cmd/mdb/i86pc/modules/Makefile @@ -20,10 +20,15 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" -SUBDIRS = pcplusmp unix uppc +SUBDIRS = \ + amd_opteron \ + pcplusmp \ + uppc \ + unix + include ../../Makefile.subdirs diff --git a/usr/src/cmd/mdb/i86pc/modules/amd_opteron/Makefile b/usr/src/cmd/mdb/i86pc/modules/amd_opteron/Makefile new file mode 100644 index 0000000000..6774431b99 --- /dev/null +++ b/usr/src/cmd/mdb/i86pc/modules/amd_opteron/Makefile @@ -0,0 +1,31 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +include $(SRC)/Makefile.master +SUBDIRS = ia32 +$(BUILD64)SUBDIRS += $(MACH64) +include ../../../Makefile.subdirs diff --git a/usr/src/cmd/mdb/i86pc/modules/amd_opteron/amd64/Makefile b/usr/src/cmd/mdb/i86pc/modules/amd_opteron/amd64/Makefile new file mode 100644 index 0000000000..d4dcef0c55 --- /dev/null +++ b/usr/src/cmd/mdb/i86pc/modules/amd_opteron/amd64/Makefile @@ -0,0 +1,42 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +MODULE = cpu.AuthenticAMD.15.so +MDBTGT = kvm + +MODSRCS = ao.c + +include ../../../../../Makefile.cmd +include ../../../../../Makefile.cmd.64 +include ../../../../intel/Makefile.amd64 +include ../../../Makefile.i86pc +include ../../../../Makefile.module + +CPPFLAGS += -I../../../../common +CPPFLAGS += -I$(SRC)/uts/i86pc/cpu +CPPFLAGS += -I$(SRC)/uts/intel +CPPFLAGS += -I$(SRC)/uts/i86pc diff --git a/usr/src/cmd/mdb/i86pc/modules/amd_opteron/ao.c b/usr/src/cmd/mdb/i86pc/modules/amd_opteron/ao.c new file mode 100644 index 0000000000..78c6b7a3ac --- /dev/null +++ b/usr/src/cmd/mdb/i86pc/modules/amd_opteron/ao.c @@ -0,0 +1,279 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <mdb/mdb_modapi.h> +#include <amd_opteron/ao.h> + +#define ALLBITS (u_longlong_t)-1 + +static const mdb_bitmask_t ao_nbcfg_bits[] = { + { "NbMcaToMstCpuEn", ALLBITS, AMD_NB_CFG_NBMCATOMSTCPUEN }, + { "DisPciCfgCpuErrRsp", ALLBITS, AMD_NB_CFG_DISPCICFGCPUERRRSP }, + { "IoRdDatErrEn", ALLBITS, AMD_NB_CFG_IORDDATERREN }, + { "ChipKillEccEn", ALLBITS, AMD_NB_CFG_CHIPKILLECCEN }, + { "EccEn", ALLBITS, AMD_NB_CFG_ECCEN }, + { "SyncOnAnyErrEn", ALLBITS, AMD_NB_CFG_SYNCONANYERREN }, + { "SyncOnWdogEn", ALLBITS, AMD_NB_CFG_SYNCONWDOGEN }, + { "GenCrcErrByte1", ALLBITS, AMD_NB_CFG_GENCRCERRBYTE1 }, + { "GenCrcErrByte0", ALLBITS, AMD_NB_CFG_GENCRCERRBYTE0 }, + /* LdtLinkSel handled separately */ + /* WdogTmrBaseSel handled separately */ + /* WdogTmrCntSel handled separately */ + /* WdogTmrDis handled separately */ + { "IoErrDis", ALLBITS, AMD_NB_CFG_IOERRDIS }, + { "CpuErrDis", ALLBITS, AMD_NB_CFG_CPUERRDIS }, + { "IoMstAbortDis", ALLBITS, AMD_NB_CFG_IOMSTABORTDIS }, + { "SyncPktPropDis", ALLBITS, AMD_NB_CFG_SYNCPKTPROPDIS }, + { "SyncPktGenDis", ALLBITS, AMD_NB_CFG_SYNCPKTGENDIS }, + { "SyncOnUcEccEn", ALLBITS, AMD_NB_CFG_SYNCONUCECCEN }, + { "CpuRdDatErrEn", ALLBITS, AMD_NB_CFG_CPURDDATERREN } +}; + +/*ARGSUSED*/ +static int +ao_nbcfg_describe(uintptr_t val, uint_t flags, int argc, const mdb_arg_t *argv) +{ + const mdb_bitmask_t *bm; + uintptr_t field; + int nbits, i; + + if (argc != 0 || !(flags & DCMD_ADDRSPEC)) + return (DCMD_USAGE); + + for (nbits = 0, bm = ao_nbcfg_bits, i = 0; + i < sizeof (ao_nbcfg_bits) / sizeof (mdb_bitmask_t); i++, bm++) { + if (!(val & bm->bm_bits)) + continue; + + mdb_printf("\t0x%08x %s\n", bm->bm_bits, bm->bm_name); + + val &= ~bm->bm_bits; + nbits++; + } + + if ((field = (val & AMD_NB_CFG_LDTLINKSEL_MASK)) != 0) { + mdb_printf("\tLdtLinkSel = %d", field >> + AMD_NB_CFG_LDTLINKSEL_SHIFT); + } + + if (!(val & AMD_NB_CFG_WDOGTMRDIS)) { + static const uint_t wdogcounts[] = { + 4095, 2047, 1023, 511, 255, 127, 63, 31 + }; + + uintptr_t cntfld = (val & AMD_NB_CFG_WDOGTMRCNTSEL_MASK); + uintptr_t basefld = (val & AMD_NB_CFG_WDOGTMRBASESEL_MASK); + uintptr_t count; + int valid = 1; + const char *units; + + if (cntfld < sizeof (wdogcounts) / sizeof (uint_t)) + count = wdogcounts[cntfld]; + else + valid = 0; + + switch (basefld) { + case AMD_NB_CFG_WDOGTMRBASESEL_1MS: + units = "ms"; + break; + case AMD_NB_CFG_WDOGTMRBASESEL_1US: + units = "us"; + break; + case AMD_NB_CFG_WDOGTMRBASESEL_5NS: + count *= 5; + units = "ns"; + break; + default: + units = " (unknown units)"; + break; + } + + if (valid) { + mdb_printf("\tWatchdog timeout: %u%s\n", count, + units); + } else { + mdb_printf("\tInvalid Watchdog: Count %u, Base %u\n", + cntfld, basefld); + } + } + + return (DCMD_OK); +} + +/*ARGSUSED3*/ +static int +ao_mpt_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + static const char *const whatstrs[] = { + "cyc-err", "poke-err", "unfault" + }; + + ao_mca_poll_trace_t mpt; + const char *what; + + if (argc != 0 || !(flags & DCMD_ADDRSPEC)) + return (DCMD_USAGE); + + if (mdb_vread(&mpt, sizeof (mpt), addr) != sizeof (mpt)) { + mdb_warn("failed to read ao_mca_poll_trace_t at %p", addr); + return (DCMD_ERR); + } + + if (DCMD_HDRSPEC(flags)) { + mdb_printf("%<u>%?s%</u> %<u>%?s%</u> %<u>%9s%</u> " + "%<u>%4s%</u>\n", "ADDR", "WHEN", "WHAT", "NERR"); + } + + if (mpt.mpt_what < sizeof (whatstrs) / sizeof (char *)) + what = whatstrs[mpt.mpt_what]; + else + what = "???"; + + mdb_printf("%?p %?p %9s %4u\n", addr, mpt.mpt_when, what, + mpt.mpt_nerr); + + return (DCMD_OK); +} + +typedef struct mptwalk_data { + uintptr_t mw_traceaddr; + ao_mca_poll_trace_t *mw_trace; + size_t mw_tracesz; + uint_t mw_tracenent; + uint_t mw_curtrace; +} mptwalk_data_t; + +static int +ao_mptwalk_init(mdb_walk_state_t *wsp) +{ + ao_mca_poll_trace_t *mpt; + mptwalk_data_t *mw; + GElf_Sym sym; + uint_t nent, i; + hrtime_t latest; + + if (wsp->walk_addr == NULL) { + mdb_warn("the address of a poll trace array must be specified"); + return (WALK_ERR); + } + + if (mdb_lookup_by_name("ao_mca_poll_trace_nent", &sym) < 0 || + sym.st_size != sizeof (uint_t) || mdb_vread(&nent, sizeof (uint_t), + sym.st_value) != sizeof (uint_t)) { + mdb_warn("failed to read ao_mca_poll_trace_nent from kernel"); + return (WALK_ERR); + } + + mw = mdb_alloc(sizeof (mptwalk_data_t), UM_SLEEP); + mw->mw_traceaddr = wsp->walk_addr; + mw->mw_tracenent = nent; + mw->mw_tracesz = nent * sizeof (ao_mca_poll_trace_t); + mw->mw_trace = mdb_alloc(mw->mw_tracesz, UM_SLEEP); + + if (mdb_vread(mw->mw_trace, mw->mw_tracesz, wsp->walk_addr) != + mw->mw_tracesz) { + mdb_free(mw->mw_trace, mw->mw_tracesz); + mdb_free(mw, sizeof (mptwalk_data_t)); + mdb_warn("failed to read poll trace array from kernel"); + return (WALK_ERR); + } + + latest = 0; + mw->mw_curtrace = 0; + for (mpt = mw->mw_trace, i = 0; i < mw->mw_tracenent; i++, mpt++) { + if (mpt->mpt_when > latest) { + latest = mpt->mpt_when; + mw->mw_curtrace = i; + } + } + + if (latest == 0) { + mdb_free(mw->mw_trace, mw->mw_tracesz); + mdb_free(mw, sizeof (mptwalk_data_t)); + return (WALK_DONE); /* trace array is empty */ + } + + wsp->walk_data = mw; + + return (WALK_NEXT); +} + +static int +ao_mptwalk_step(mdb_walk_state_t *wsp) +{ + mptwalk_data_t *mw = wsp->walk_data; + ao_mca_poll_trace_t *thismpt, *prevmpt; + int prev, rv; + + thismpt = &mw->mw_trace[mw->mw_curtrace]; + + rv = wsp->walk_callback(mw->mw_traceaddr + (mw->mw_curtrace * + sizeof (ao_mca_poll_trace_t)), thismpt, wsp->walk_cbdata); + + if (rv != WALK_NEXT) + return (rv); + + prev = (mw->mw_curtrace - 1) % mw->mw_tracenent; + prevmpt = &mw->mw_trace[prev]; + + if (prevmpt->mpt_when == 0 || prevmpt->mpt_when > thismpt->mpt_when) + return (WALK_DONE); + + mw->mw_curtrace = prev; + + return (WALK_NEXT); +} + +static void +ao_mptwalk_fini(mdb_walk_state_t *wsp) +{ + mptwalk_data_t *mw = wsp->walk_data; + + mdb_free(mw->mw_trace, mw->mw_tracesz); + mdb_free(mw, sizeof (mptwalk_data_t)); +} + +static const mdb_dcmd_t dcmds[] = { + { "ao_poll_trace", ":", "dump a poll trace buffer", ao_mpt_dump }, + { "ao_nbcfg", ":", "decode Northbridge config bits", + ao_nbcfg_describe }, + { NULL } +}; + +static const mdb_walker_t walkers[] = { + { "ao_poll_trace", "walks poll trace buffers in reverse chronological " + "order", ao_mptwalk_init, ao_mptwalk_step, ao_mptwalk_fini }, + { NULL } +}; + +static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; + +const mdb_modinfo_t * +_mdb_init(void) +{ + return (&modinfo); +} diff --git a/usr/src/cmd/fm/topo/files/Makefile.com b/usr/src/cmd/mdb/i86pc/modules/amd_opteron/ia32/Makefile index 94c89d5321..9f6cd0fe8e 100644 --- a/usr/src/cmd/fm/topo/files/Makefile.com +++ b/usr/src/cmd/mdb/i86pc/modules/amd_opteron/ia32/Makefile @@ -20,26 +20,22 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" -include ../../../../../Makefile.cmd - -ROOT_TOPO_ROOT = $(ROOT)/usr/lib/fm/topo -ROOT_TOPO_DIR = $(ROOT_TOPO_ROOT)/$(TOPOSUBDIR) -ROOT_TOPOFILES = $(TOPOFILES:%=$(ROOT_TOPO_DIR)/%) - -include ../../../Makefile.rootdirs - -all:= FILEMODE = 0444 +MODULE = cpu.AuthenticAMD.15.so +MDBTGT = kvm -install: all +MODSRCS = ao.c -all: $(ROOT_TOPOFILES) - -clobber: - $(RM) $(ROOT_TOPOFILES) - -clean install_h lint _msg: +include ../../../../../Makefile.cmd +include ../../../../intel/Makefile.ia32 +include ../../../Makefile.i86pc +include ../../../../Makefile.module + +CPPFLAGS += -I../../../../common +CPPFLAGS += -I$(SRC)/uts/i86pc/cpu +CPPFLAGS += -I$(SRC)/uts/intel +CPPFLAGS += -I$(SRC)/uts/i86pc diff --git a/usr/src/cmd/mdb/intel/kmdb/kvm_isadep.c b/usr/src/cmd/mdb/intel/kmdb/kvm_isadep.c index b52279f725..86e56a6ea3 100644 --- a/usr/src/cmd/mdb/intel/kmdb/kvm_isadep.c +++ b/usr/src/cmd/mdb/intel/kmdb/kvm_isadep.c @@ -46,6 +46,7 @@ #include <sys/frame.h> #include <sys/trap.h> #include <sys/bitmap.h> +#include <sys/pci_impl.h> /* Higher than the highest trap number for which we have a defined specifier */ #define KMT_MAXTRAPNO 0x20 @@ -278,6 +279,15 @@ kmt_in_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) return (DCMD_OK); } +static uint64_t +kmt_numarg(const mdb_arg_t *arg) +{ + if (arg->a_type == MDB_TYPE_STRING) + return (mdb_strtoull(arg->a_un.a_str)); + else + return (arg->a_un.a_val); +} + /*ARGSUSED1*/ int kmt_out_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) @@ -294,10 +304,7 @@ kmt_out_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) len = mdb.m_dcount; argv += argc - 1; - if (argv->a_type == MDB_TYPE_STRING) - val = mdb_strtoull(argv->a_un.a_str); - else - val = argv->a_un.a_val; + val = kmt_numarg(argv); if (kmt_io_check(len, addr, IOCHECK_WARN) < 0) return (DCMD_ERR); @@ -360,10 +367,7 @@ kmt_wrmsr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) if (!(flags & DCMD_ADDRSPEC) || argc != 1) return (DCMD_USAGE); - if (argv->a_type == MDB_TYPE_STRING) - val = mdb_strtoull(argv->a_un.a_str); - else - val = argv->a_un.a_val; + val = kmt_numarg(argv); if (kmt_rwmsr(addr, &val, wrmsr)) { warn("wrmsr failed"); @@ -433,6 +437,89 @@ kmt_iowrite(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr) return (kmt_iorw(t, (void *)buf, nbytes, addr, kmt_out)); } +static int +kmt_pcicfg_common(uintptr_t off, uint32_t *valp, const mdb_arg_t *argv, + void (*rw)(void *, size_t, uintptr_t)) +{ + uint32_t bus, dev, func; + uint32_t addr; + + bus = kmt_numarg(&argv[0]); + dev = kmt_numarg(&argv[1]); + func = kmt_numarg(&argv[2]); + + if ((bus & 0xffff) != bus) { + warn("invalid bus number (must be 0-0xffff)\n"); + return (DCMD_ERR); + } + + if ((dev & 0x1f) != dev) { + warn("invalid device number (must be 0-0x1f)\n"); + return (DCMD_ERR); + } + + if ((func & 0x7) != func) { + warn("invalid function number (must be 0-7)\n"); + return (DCMD_ERR); + } + + if ((off & 0xfc) != off) { + warn("invalid register number (must be 0-0xff, and 4-byte " + "aligned\n"); + return (DCMD_ERR); + } + + addr = PCI_CADDR1(bus, dev, func, off); + + if (kmt_iowrite(mdb.m_target, &addr, sizeof (addr), PCI_CONFADD) != + sizeof (addr)) { + warn("write of PCI_CONFADD failed"); + return (DCMD_ERR); + } + + if (kmt_iorw(mdb.m_target, valp, sizeof (*valp), PCI_CONFDATA, rw) != + sizeof (*valp)) { + warn("access to PCI_CONFDATA failed"); + return (DCMD_ERR); + } + + return (DCMD_OK); +} + +/*ARGSUSED*/ +int +kmt_rdpcicfg(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + uint32_t val; + + if (argc != 3 || !(flags & DCMD_ADDRSPEC)) + return (DCMD_USAGE); + + if (kmt_pcicfg_common(addr, &val, argv, kmt_in) != DCMD_OK) + return (DCMD_ERR); + + mdb_printf("%llx\n", (u_longlong_t)val); + + return (DCMD_OK); +} + +/*ARGSUSED*/ +int +kmt_wrpcicfg(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + uint32_t val; + + if (argc != 4 || !(flags & DCMD_ADDRSPEC)) + return (DCMD_USAGE); + + val = (uint32_t)kmt_numarg(&argv[3]); + + if (kmt_pcicfg_common(addr, &val, argv, kmt_out) != DCMD_OK) + return (DCMD_ERR); + + return (DCMD_OK); +} + const char * kmt_trapname(int trapnum) { diff --git a/usr/src/cmd/mdb/intel/kmdb/kvm_isadep.h b/usr/src/cmd/mdb/intel/kmdb/kvm_isadep.h index 44ac1bdd4f..d03ae5eafa 100644 --- a/usr/src/cmd/mdb/intel/kmdb/kvm_isadep.h +++ b/usr/src/cmd/mdb/intel/kmdb/kvm_isadep.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -44,6 +44,9 @@ extern int kmt_out_dcmd(uintptr_t, uint_t, int, const mdb_arg_t *); extern int kmt_rdmsr(uintptr_t, uint_t, int, const mdb_arg_t *); extern int kmt_wrmsr(uintptr_t, uint_t, int, const mdb_arg_t *); +extern int kmt_rdpcicfg(uintptr_t, uint_t, int, const mdb_arg_t *); +extern int kmt_wrpcicfg(uintptr_t, uint_t, int, const mdb_arg_t *); + extern int kmt_msr_validate(const kmdb_msr_t *); #ifdef __cplusplus diff --git a/usr/src/common/mc/mc-amd/Makefile.mcamd b/usr/src/common/mc/mc-amd/Makefile.mcamd new file mode 100644 index 0000000000..bc43249db1 --- /dev/null +++ b/usr/src/common/mc/mc-amd/Makefile.mcamd @@ -0,0 +1,37 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +MCAMD_CMN_SRCS = \ + mcamd_err.c \ + mcamd_misc.c \ + mcamd_patounum.c \ + mcamd_unumtopa.c \ + mcamd_synd.c \ + mcamd_rowcol_tbl.c \ + mcamd_rowcol.c + +MCAMD_CMN_OBJS = $(MCAMD_CMN_SRCS:%.c=%.o) diff --git a/usr/src/common/mc/mc-amd/mcamd_api.h b/usr/src/common/mc/mc-amd/mcamd_api.h new file mode 100644 index 0000000000..646f457fdc --- /dev/null +++ b/usr/src/common/mc/mc-amd/mcamd_api.h @@ -0,0 +1,218 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _MCAMD_API_H +#define _MCAMD_API_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Primary header file for mcamd_* routines in $SRC/common/mc. The + * routines not implemented there are required to be implemented in the + * kernel or userland consumer of this interface (such as the mc-amd driver). + * The common code must use the wrapper functions provided by the consumer + * to navigate the MC tree, get properties etc. + */ + +#if defined(_KERNEL) +#include <sys/systm.h> +#include <sys/sunddi.h> +#else +#include <string.h> +#include <assert.h> +#endif + +#include <sys/types.h> +#include <sys/mc.h> +#include <sys/mca_amd.h> +#include <sys/mc_amd.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Consumers of this common code must implement the following types. + */ +typedef struct mcamd_node mcamd_node_t; +struct mcamd_hdl; + +/* + * If changing the properties below be sure to propogate to mcamd_misc.c + * in common code, mcamd_subr.c in the mc-amd driver, and mcamd_prop.c + * from libmcamd. + */ + +#define MCAMD_PROP_NUM 0 +#define MCAMD_PROP_BASE_ADDR 1 +#define MCAMD_PROP_LIM_ADDR 2 +#define MCAMD_PROP_MASK 3 +#define MCAMD_PROP_DRAM_ILEN 4 +#define MCAMD_PROP_DRAM_ILSEL 5 +#define MCAMD_PROP_DRAM_HOLE 6 +#define MCAMD_PROP_DRAM_CONFIG 7 +#define MCAMD_PROP_ACCESS_WIDTH 8 +#define MCAMD_PROP_LODIMM 9 +#define MCAMD_PROP_UPDIMM 10 +#define MCAMD_PROP_CSBANKMAP 11 +#define MCAMD_PROP_SIZE 12 +#define MCAMD_PROP_CSBANK_INTLV 13 +#define MCAMD_PROP_CS0 14 /* CS0 to CS3 must be contiguous */ +#define MCAMD_PROP_CS1 15 +#define MCAMD_PROP_CS2 16 +#define MCAMD_PROP_CS3 17 +#define MCAMD_PROP_REV 18 +#define MCAMD_PROP_DISABLED_CS 19 + +#define MCAMD_NUMPROPS 20 + +#define MCAMD_PROPSTR_NUM "num" +#define MCAMD_PROPSTR_BASE_ADDR "base-addr" +#define MCAMD_PROPSTR_LIM_ADDR "lim-addr" +#define MCAMD_PROPSTR_MASK "mask" +#define MCAMD_PROPSTR_DRAM_ILEN "dram-ilen" +#define MCAMD_PROPSTR_DRAM_ILSEL "dram-ilsel" +#define MCAMD_PROPSTR_DRAM_HOLE "dram-hole" +#define MCAMD_PROPSTR_DRAM_CONFIG "dram-config" +#define MCAMD_PROPSTR_ACCESS_WIDTH "access-width" +#define MCAMD_PROPSTR_LODIMM "lodimm-num" +#define MCAMD_PROPSTR_UPDIMM "updimm-num" +#define MCAMD_PROPSTR_CSBANKMAP "bank-mapping" +#define MCAMD_PROPSTR_SIZE "size" +#define MCAMD_PROPSTR_CSBANK_INTLV "csbank-intlv" +#define MCAMD_PROPSTR_CS0 "csnum0" +#define MCAMD_PROPSTR_CS1 "csnum1" +#define MCAMD_PROPSTR_CS2 "csnum2" +#define MCAMD_PROPSTR_CS3 "csnum3" +#define MCAMD_PROPSTR_REV "revision" +#define MCAMD_PROPSTR_DISABLED_CS "disabled-cs" + +/* + * Flags for mcamd_dprintf + */ +#define MCAMD_DBG_ERR 0x1 +#define MCAMD_DBG_FLOW 0x2 + +typedef union mcamd_dimm_offset_un mcamd_dimm_offset_un_t; + +/* + * Offset definition. Encode everything in a single uint64_t, allowing some + * room for growth in numbers of rows/columns/banks in future MC revisions. + * Some consumers will handle this as an opaque uint64 to be passed around, + * while others will want to look inside via the union defined below. + */ + +#define MCAMD_OFFSET_VERSION_0 0x0 +#define MCAMD_OFFSET_VERSION MCAMD_OFFSET_VERSION_0 + +union mcamd_dimm_offset_un { + uint64_t _dou_offset; + struct { + struct { + uint32_t dou_col:20; /* column address */ + uint32_t dou_bank:4; /* internal sdram bank number */ + uint32_t unused:8; + } lo; + struct { + uint32_t dou_row:20; /* row address */ + uint32_t dou_rank:3; /* cs rank on dimm */ + uint32_t unused:4; + uint32_t dou_version:4; /* offset encoding version */ + uint32_t dou_valid:1; /* set if valid */ + } hi; + } _dou_hilo; +}; + +#define do_offset _dou_offset + +#define do_valid _dou_hilo.hi.dou_valid +#define do_version _dou_hilo.hi.dou_version +#define do_rank _dou_hilo.hi.dou_rank +#define do_row _dou_hilo.hi.dou_row +#define do_bank _dou_hilo.lo.dou_bank +#define do_col _dou_hilo.lo.dou_col + +/* + * The following work on an offset treated as a uint64_t. + */ +#define MCAMD_RC_OFFSET_VALID(offset) (((uint64_t)(offset) & (1ULL << 63)) != 0) +#define MCAMD_RC_OFFSET_VERSION(offset) (((uint64_t)offset >> 59) & 0xf) + +/* + * Value to be used to indicate an invalid offset. + */ +#define MCAMD_RC_INVALID_OFFSET 0x0 + +/* + * Routines provided by the common mcamd code. + */ +extern const char *mcamd_get_propname(uint_t); + +extern int mcamd_patounum(struct mcamd_hdl *, mcamd_node_t *, uint64_t, + uint32_t, int, struct mc_unum *); + +extern int mcamd_unumtopa(struct mcamd_hdl *, mcamd_node_t *, struct mc_unum *, + uint64_t *); + +extern int mcamd_cs_size(struct mcamd_hdl *, mcamd_node_t *, int, size_t *); + +extern int mcamd_synd_validate(struct mcamd_hdl *, uint32_t, int); +extern int mcamd_eccsynd_decode(struct mcamd_hdl *, uint32_t, uint_t *); +extern int mcamd_cksynd_decode(struct mcamd_hdl *, uint32_t, uint_t *, + uint_t *); +extern int mcamd_cksym_decode(struct mcamd_hdl *, uint_t, int *, int *, + int *, int *); + +extern void *mcamd_set_errno_ptr(struct mcamd_hdl *, int); +extern const char *mcamd_strerror(int); +extern const char *mcamd_errmsg(struct mcamd_hdl *); + +/* + * Routines to be provided by wrapper code. + */ +extern mcamd_node_t *mcamd_mc_next(struct mcamd_hdl *, mcamd_node_t *, + mcamd_node_t *); +extern mcamd_node_t *mcamd_cs_next(struct mcamd_hdl *, mcamd_node_t *, + mcamd_node_t *); +extern mcamd_node_t *mcamd_dimm_next(struct mcamd_hdl *, mcamd_node_t *, + mcamd_node_t *); + +extern mcamd_node_t *mcamd_cs_mc(struct mcamd_hdl *, mcamd_node_t *); +extern mcamd_node_t *mcamd_dimm_mc(struct mcamd_hdl *, mcamd_node_t *); + +extern int mcamd_get_numprop(struct mcamd_hdl *, mcamd_node_t *, uint_t, + uint64_t *); + +extern int mcamd_errno(struct mcamd_hdl *); +extern int mcamd_set_errno(struct mcamd_hdl *, int); +extern void mcamd_dprintf(struct mcamd_hdl *, int, const char *, ...); + +#ifdef __cplusplus +} +#endif + +#endif /* _MCAMD_API_H */ diff --git a/usr/src/common/mc/mc-amd/mcamd_err.c b/usr/src/common/mc/mc-amd/mcamd_err.c new file mode 100644 index 0000000000..d0e1666423 --- /dev/null +++ b/usr/src/common/mc/mc-amd/mcamd_err.c @@ -0,0 +1,63 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <mcamd_api.h> +#include <mcamd_err.h> + +static const char *const _mcamd_errlist[] = { + "Invalid syndrome", /* EMCAMD_SYNDINVALID */ + "Invalid configuration tree", /* EMCAMD_TREEINVALID */ + "Address not found" /* EMCAMD_NOADDR */ + "Operation not supported" /* EMCAMD_NOTSUP */ +}; + +static const int _mcamd_nerr = sizeof (_mcamd_errlist) / + sizeof (_mcamd_errlist[0]); + +void * +mcamd_set_errno_ptr(struct mcamd_hdl *mcamd, int err) +{ + (void) mcamd_set_errno(mcamd, err); + return (NULL); +} + +const char * +mcamd_strerror(int err) +{ + const char *str = NULL; + + if (err >= EMCAMD_BASE && (err - EMCAMD_BASE) < _mcamd_nerr) + str = _mcamd_errlist[err - EMCAMD_BASE]; + + return (str == NULL ? "Unknown error" : str); +} + +const char * +mcamd_errmsg(struct mcamd_hdl *mcamd) +{ + return (mcamd_strerror(mcamd_errno(mcamd))); +} diff --git a/usr/src/common/mc/mc-amd/mcamd_err.h b/usr/src/common/mc/mc-amd/mcamd_err.h new file mode 100644 index 0000000000..f9a762e211 --- /dev/null +++ b/usr/src/common/mc/mc-amd/mcamd_err.h @@ -0,0 +1,54 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _MCAMD_ERR_H +#define _MCAMD_ERR_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#define EMCAMD_BASE 2000 /* out of system's and consumer's way */ + +enum { + EMCAMD_SYNDINVALID = EMCAMD_BASE, /* invalid syndrome */ + EMCAMD_TREEINVALID, /* invalid configuration tree */ + EMCAMD_NOADDR, /* address not found */ + EMCAMD_NOTSUP /* operation not supported */ +}; + +extern const char *mcamd_errmsg(struct mcamd_hdl *); +extern const char *mcamd_strerror(int); +extern int mcamd_errno(struct mcamd_hdl *); +extern int mcamd_set_errno(struct mcamd_hdl *, int); +extern void *mcamd_set_errno_ptr(struct mcamd_hdl *, int); + +#ifdef __cplusplus +} +#endif + +#endif /* _MCAMD_ERR_H */ diff --git a/usr/src/common/mc/mc-amd/mcamd_misc.c b/usr/src/common/mc/mc-amd/mcamd_misc.c new file mode 100644 index 0000000000..2bd4d508a3 --- /dev/null +++ b/usr/src/common/mc/mc-amd/mcamd_misc.c @@ -0,0 +1,65 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> + +#include <mcamd_api.h> + +static const char *const _mcamd_proplist[] = { + MCAMD_PROPSTR_NUM, + MCAMD_PROPSTR_BASE_ADDR, + MCAMD_PROPSTR_LIM_ADDR, + MCAMD_PROPSTR_MASK, + MCAMD_PROPSTR_DRAM_ILEN, + MCAMD_PROPSTR_DRAM_ILSEL, + MCAMD_PROPSTR_DRAM_HOLE, + MCAMD_PROPSTR_DRAM_CONFIG, + MCAMD_PROPSTR_ACCESS_WIDTH, + MCAMD_PROPSTR_LODIMM, + MCAMD_PROPSTR_UPDIMM, + MCAMD_PROPSTR_CSBANKMAP, + MCAMD_PROPSTR_SIZE, + MCAMD_PROPSTR_CSBANK_INTLV, + MCAMD_PROPSTR_CS0, + MCAMD_PROPSTR_CS1, + MCAMD_PROPSTR_CS2, + MCAMD_PROPSTR_CS3, + MCAMD_PROPSTR_REV, + MCAMD_PROPSTR_DISABLED_CS, +}; + +static const int _mcamd_nprop = sizeof (_mcamd_proplist) / + sizeof (_mcamd_proplist[0]); + +const char * +mcamd_get_propname(uint_t code) +{ + if (code < _mcamd_nprop) + return (_mcamd_proplist[code]); + else + return (NULL); +} diff --git a/usr/src/common/mc/mc-amd/mcamd_patounum.c b/usr/src/common/mc/mc-amd/mcamd_patounum.c new file mode 100644 index 0000000000..9bad114f30 --- /dev/null +++ b/usr/src/common/mc/mc-amd/mcamd_patounum.c @@ -0,0 +1,552 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Given a physical address and an optional syndrome, determine the + * name of the memory module that contains it. + */ + +#include <sys/errno.h> +#include <sys/types.h> +#include <sys/mc.h> + +#include <mcamd_api.h> +#include <mcamd_err.h> + +extern int mc_pa_to_offset(struct mcamd_hdl *, mcamd_node_t *, mcamd_node_t *, + mcamd_node_t *, uint64_t, uint64_t *); + +#define LO_DIMM 0x1 +#define UP_DIMM 0x2 + +#define BITS(val, high, low) \ + ((val) & (((2ULL << (high)) - 1) & ~((1ULL << (low)) - 1))) + +static int +iaddr_gen(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa, + uint64_t *iaddrp) +{ + uint64_t orig = pa; + uint64_t mcnum, base, lim, dramaddr, ilen, ilsel, top, dramhole; + + if (!mcamd_get_numprop(hdl, mc, MCAMD_PROP_NUM, &mcnum) || + !mcamd_get_numprop(hdl, mc, MCAMD_PROP_BASE_ADDR, &base) || + !mcamd_get_numprop(hdl, mc, MCAMD_PROP_LIM_ADDR, &lim) || + !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_ILEN, &ilen) || + !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_ILSEL, &ilsel) || + !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_HOLE, &dramhole)) { + mcamd_dprintf(hdl, MCAMD_DBG_ERR, "iaddr_gen: failed to " + "lookup required properties"); + return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); + } + + if (pa < base || pa > lim) { + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "iaddr_gen: PA 0x%llx not " + "in range [0x%llx, 0x%llx] of MC %d\n", pa, base, lim, + (int)mcnum); + return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); + } + + /* + * Rev E and later added the DRAM Hole Address Register for + * memory hoisting. In earlier revisions memory hoisting is + * achieved by following some algorithm to modify the CS bases etc, + * and this pa to unum algorithm will simply see those modified + * values. But if the Hole Address Register is being used then + * we need to reduce any address at or above 4GB by the size of + * the hole. + */ + if (dramhole & MC_DC_HOLE_VALID && pa >= 0x100000000) { + uint64_t holesize = (dramhole & MC_DC_HOLE_OFFSET_MASK) << + MC_DC_HOLE_OFFSET_LSHIFT; + pa -= holesize; + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "iaddr_gen: dram hole " + "valid; pa decremented from 0x%llx to 0x%llx for " + "a dramhole size of 0x%llx\n", orig, pa, holesize); + } + + dramaddr = BITS(pa, 39, 0) - BITS(base, 39, 24); + + if (ilen != 0) { + int pailsel; + + if (ilen != 1 && ilen != 3 && ilen != 7) { + mcamd_dprintf(hdl, MCAMD_DBG_ERR, "Invalid intlven " + "of %d for MC %d\n", (int)ilen, (int)mcnum); + return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); + } + + if ((pailsel = BITS(pa, 14, 12) >> 12 & ilen) != ilsel) { + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "iaddr_gen: " + "PA 0x%llx in a %d-way node interleave indicates " + "selection %d, MC %d has ilsel of %d\n", + pa, (int)ilen + 1, pailsel, (int)mcnum, (int)ilsel); + return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); + } + + if (ilen == 1) + top = BITS(dramaddr, 36, 13) >> 1; + else if (ilen == 3) + top = BITS(dramaddr, 37, 14) >> 2; + else if (ilen == 7) + top = BITS(dramaddr, 38, 15) >> 3; + } else { + top = BITS(dramaddr, 35, 12); + } + + *iaddrp = top | BITS(dramaddr, 11, 0); + + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "iaddr_gen: PA 0x%llx in range " + "[0x%llx, 0x%llx] of MC %d; normalized address for cs compare " + "is 0x%llx\n", pa, base, lim, (int)mcnum, *iaddrp); + + return (0); +} + +static int +cs_match(struct mcamd_hdl *hdl, uint64_t iaddr, mcamd_node_t *cs) +{ + uint64_t csnum, csbase, csmask; + int match; + + if (!mcamd_get_numprop(hdl, cs, MCAMD_PROP_NUM, &csnum) || + !mcamd_get_numprop(hdl, cs, MCAMD_PROP_BASE_ADDR, &csbase) || + !mcamd_get_numprop(hdl, cs, MCAMD_PROP_MASK, &csmask)) { + mcamd_dprintf(hdl, MCAMD_DBG_ERR, "cs_match: failed to lookup " + "required properties\n"); + return (0); + } + + match = ((iaddr & ~csmask) == (csbase & ~csmask)); + + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "cs_match: iaddr 0x%llx does " + "%smatch CS %d (base 0x%llx, mask 0x%llx)\n", iaddr, + match ? "" : "not ", (int)csnum, csbase, csmask); + + return (match); +} + +static int +unum_fill(struct mcamd_hdl *hdl, mcamd_node_t *cs, int which, + uint64_t iaddr, struct mc_unum *unump, int incloff) +{ + mcamd_node_t *mc, *dimm; + uint64_t chipnum, csnum, lonum, upnum; + int i; + int offsetdimm; + + if ((mc = mcamd_cs_mc(hdl, cs)) == NULL || + !mcamd_get_numprop(hdl, mc, MCAMD_PROP_NUM, &chipnum) || + !mcamd_get_numprop(hdl, cs, MCAMD_PROP_NUM, &csnum)) { + mcamd_dprintf(hdl, MCAMD_DBG_ERR, "unum_fill: failed to " + "lookup required properties\n"); + return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); + } + + if ((which & LO_DIMM) && + !mcamd_get_numprop(hdl, cs, MCAMD_PROP_LODIMM, &lonum) || + (which & UP_DIMM) && + !mcamd_get_numprop(hdl, cs, MCAMD_PROP_UPDIMM, &upnum)) { + mcamd_dprintf(hdl, MCAMD_DBG_ERR, "unum_fill: failed to " + "lookup lodimm/hidimm properties\n"); + return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); + } + + unump->unum_board = 0; + unump->unum_chip = chipnum; + unump->unum_mc = 0; + unump->unum_cs = csnum; + + for (i = 0; i < MC_UNUM_NDIMM; i++) { + unump->unum_dimms[i] = -1; + } + switch (which) { + case LO_DIMM: + unump->unum_dimms[0] = lonum; + offsetdimm = lonum; + break; + case UP_DIMM: + unump->unum_dimms[0] = upnum; + offsetdimm = upnum; + break; + case LO_DIMM | UP_DIMM: + unump->unum_dimms[0] = lonum; + unump->unum_dimms[1] = upnum; + offsetdimm = lonum; + break; + } + + if (!incloff) { + unump->unum_offset = MCAMD_RC_INVALID_OFFSET; + return (0); + } + + /* + * We wish to calculate a dimm offset. In the paired case we will + * lookup the lodimm (see offsetdimm above). + */ + for (dimm = mcamd_dimm_next(hdl, mc, NULL); dimm != NULL; + dimm = mcamd_dimm_next(hdl, mc, dimm)) { + uint64_t dnum; + if (!mcamd_get_numprop(hdl, dimm, MCAMD_PROP_NUM, &dnum)) { + mcamd_dprintf(hdl, MCAMD_DBG_ERR, "unum_fill: failed " + "to lookup dimm number property\n"); + continue; + } + if (dnum == offsetdimm) + break; + } + + if (dimm == NULL) { + mcamd_dprintf(hdl, MCAMD_DBG_ERR, "unum_fill: failed to " + "find dimm with number %d for offset calculation\n", + offsetdimm); + unump->unum_offset = MCAMD_RC_INVALID_OFFSET; + return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); + } + + /* + * mc_pa_to_offset sets the offset to an invalid value if + * it hits an error. + */ + (void) mc_pa_to_offset(hdl, mc, cs, dimm, iaddr, &unump->unum_offset); + + return (0); +} + +/* + * We have translated a system address to a (node, chip-select). That + * identifies one (in 64-bit MC mode) or two (in 128-bit MC mode DIMMs, + * either a lodimm or a lodimm/updimm pair. For all cases except an + * uncorrectable ChipKill error we can interpret the address alignment and + * syndrome to deduce whether we are on the lodimm or updimm. + */ +static int +mc_whichdimm(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa, + uint32_t synd, int syndtype) +{ + uint64_t accwidth; + uint_t sym, pat; + int lobit, hibit, data, check; + + if (!mcamd_get_numprop(hdl, mc, MCAMD_PROP_ACCESS_WIDTH, &accwidth) || + (accwidth != 64 && accwidth != 128)) { + mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mc_whichdimm: failed " + "to lookup required properties\n"); + return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); + } + + /* + * In 64 bit mode only LO dimms are occupied. + */ + if (accwidth == 64) { + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: 64-bit mode " + "therefore LO_DIMM\n"); + return (LO_DIMM); + } + + if (syndtype == AMD_SYNDTYPE_ECC) { + /* + * 64/8 ECC is checked separately for the upper and lower + * halves, so even an uncorrectable error is contained within + * one of the two halves. The error address is accurate to + * 8 bytes, so bit 4 distinguises upper from lower. + */ + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: 64/8 ECC " + "and PA 0x%llx is in %s half\n", pa, + pa & 8 ? "lower" : "upper"); + return (pa & 8 ? UP_DIMM : LO_DIMM); + } + + /* + * ChipKill ECC (necessarily in 128-bit mode. + */ + if (mcamd_cksynd_decode(hdl, synd, &sym, &pat)) { + /* + * A correctable ChipKill syndrome and we can tell + * which half the error was in from the symbol number. + */ + if (mcamd_cksym_decode(hdl, sym, &lobit, &hibit, &data, + &check) == 0) + return (mcamd_set_errno(hdl, EMCAMD_SYNDINVALID)); + + if (data && hibit <= 63 || check && hibit <= 7) { + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: " + "ChipKill symbol %d (%s %d..%d), so LODIMM\n", sym, + data ? "data" : "check", lobit, hibit); + return (LO_DIMM); + } else { + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: " + "ChipKill symbol %d (%s %d..%d), so UPDIMM\n", sym, + data ? "data" : "check", lobit, hibit); + return (UP_DIMM); + } + } else { + /* + * An uncorrectable error while in ChipKill ECC mode - can't + * tell which dimm or dimms the errors lie within. + */ + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichhdimm: " + "uncorrectable ChipKill, could be either LODIMM " + "or UPDIMM\n"); + return (LO_DIMM | UP_DIMM); + } +} + +/* + * Brute-force BKDG pa to cs translation. The following is from BKDG 3.29 + * so is for revisions prior to F. It is coded to look as much like the + * BKDG code as possible. + */ +static int +mc_bkdg_patounum(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa, + uint32_t synd, int syndtype, struct mc_unum *unump) +{ + int which; + uint64_t mcnum; + mcamd_node_t *cs; + /* + * Variables as per BKDG + */ + int Ilog; + uint32_t SystemAddr = (uint32_t)(pa >> 8); + uint64_t IntlvEn, IntlvSel; + uint32_t DramBase, DramLimit; /* assume DramEn */ + uint32_t HoleOffset, HoleEn; + uint32_t CSBase, CSMask; /* assuume CSBE */ + uint32_t InputAddr, Temp; + + /* + * Additional variables which we need since we will reading + * MC properties instead of PCI config space, and the MC properties + * are stored in a cooked state. + */ + uint64_t prop_drambase, prop_dramlimit, prop_dramhole; + uint64_t prop_intlven, prop_intlvsel; + uint64_t prop_csbase, prop_csmask; + + if (!mcamd_get_numprop(hdl, mc, MCAMD_PROP_NUM, &mcnum) || + !mcamd_get_numprop(hdl, mc, MCAMD_PROP_BASE_ADDR, &prop_drambase) || + !mcamd_get_numprop(hdl, mc, MCAMD_PROP_LIM_ADDR, &prop_dramlimit) || + !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_HOLE, &prop_dramhole) || + !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_ILEN, &prop_intlven) || + !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_ILSEL, + &prop_intlvsel)) { + mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mc_bkdg_patounm: failed " + "to lookup required properties\n"); + return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); + } + + /* + * Brute force deconstruction of the MC properties. If we decide to + * keep this then we need some of the mcamd.g defines available to us. + */ + DramBase = ((prop_drambase >> 8) & 0xffff0000) | (prop_intlven << 8); + IntlvEn = (DramBase & 0x00000700) >> 8; + DramBase &= 0xffff0000; + DramLimit = ((prop_dramlimit >> 8) & 0xffff0000) | (prop_intlvsel << 8); + IntlvSel = (DramLimit & 0x00000700) >> 8; + DramLimit |= 0x0000ffff; + HoleEn = prop_dramhole; /* uncooked */ + HoleOffset = (HoleEn & 0x0000ff00) << 8; + HoleEn &= 0x00000001; + + if (!(DramBase <= SystemAddr && SystemAddr <= DramLimit)) { + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_bkdg_patounum: " + "SystemAddr 0x%x derived from PA 0x%llx is not in the " + "address range [0x%x, 0x%x] of MC %d\n", + SystemAddr, pa, DramBase, DramLimit, (int)mcnum); + return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); + } + + if (IntlvEn) { + if (IntlvSel == ((SystemAddr >> 4) & IntlvEn)) { + switch (IntlvEn) { + case 1: + Ilog = 1; + break; + case 3: + Ilog = 2; + break; + case 7: + Ilog = 3; + break; + default: + return (mcamd_set_errno(hdl, + EMCAMD_TREEINVALID)); + } + Temp = (SystemAddr >> (4 + Ilog)) << 4; + InputAddr = (Temp | (SystemAddr & 0x0000000f)) << 4; + } else { + /* not this node */ + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_bkdg_patounum: " + "Node interleaving, MC node %d not selected\n", + (int)mcnum); + return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); + } + } else { + /* No interleave */ + InputAddr = (SystemAddr - DramBase) << 4; + } + + if (HoleEn && SystemAddr > 0x00ffffff) + InputAddr -= HoleOffset; + + for (cs = mcamd_cs_next(hdl, mc, NULL); cs != NULL; + cs = mcamd_cs_next(hdl, mc, cs)) { + uint64_t csnum; + + if (!mcamd_get_numprop(hdl, cs, MCAMD_PROP_BASE_ADDR, + &prop_csbase) || + !mcamd_get_numprop(hdl, cs, MCAMD_PROP_MASK, + &prop_csmask) || + !mcamd_get_numprop(hdl, cs, MCAMD_PROP_NUM, &csnum)) { + mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mc_bkdg_patounm: " + "failed to read cs properties\n"); + return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); + } + + CSBase = ((prop_csbase >> 4) & 0xffe00000) | + ((prop_csbase >> 4) & 0x0000fe00); + CSBase &= 0xffe0fe00; + CSMask = ((prop_csmask >> 4) & 0x3fe00000) | + ((prop_csmask >> 4) & 0x0000fe00); + CSMask = (CSMask | 0x001f01ff) & 0x3fffffff; + + if (((InputAddr & ~CSMask) == (CSBase & ~CSMask))) { + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_bkdg_patounum: " + "match for chip select %d of MC %d\n", (int)csnum, + (int)mcnum); + + if ((which = mc_whichdimm(hdl, mc, pa, synd, + syndtype)) < 0) + return (-1); /* errno is set for us */ + + /* + * The BKDG algorithm drops low-order bits that + * are unimportant in deriving chip-select but are + * included in row/col/bank mapping, so do not + * perform offset calculation in this case. + */ + if (unum_fill(hdl, cs, which, InputAddr, unump, 0) < 0) + return (-1); /* errno is set for us */ + + return (0); + } + } + + mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mc_bkdg_patounum: in range " + "for MC %d but no cs responds\n", (int)mcnum); + + return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); +} + +/*ARGSUSED*/ +static int +mc_patounum(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa, + uint32_t synd, int syndtype, struct mc_unum *unump) +{ + uint64_t iaddr; + mcamd_node_t *cs; + int which; +#ifdef DEBUG + struct mc_unum bkdg_unum; + int bkdgres; + + /* + * We perform the translation twice, once using the brute-force + * approach of the BKDG and again using a more elegant but more + * difficult to review against the BKDG approach. Note that both + * approaches need to change for rev F since it increases max CS + * size and so iaddr calculation etc changes. + */ + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "BKDG brute-force method begins\n"); + bkdgres = mc_bkdg_patounum(hdl, mc, pa, synd, syndtype, &bkdg_unum); + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "BKDG brute-force method ends\n"); +#endif + + if (iaddr_gen(hdl, mc, pa, &iaddr) < 0) + return (-1); /* errno is set for us */ + + for (cs = mcamd_cs_next(hdl, mc, NULL); cs != NULL; + cs = mcamd_cs_next(hdl, mc, cs)) { + if (cs_match(hdl, iaddr, cs)) + break; + } + + if (cs == NULL) + return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); + + if ((which = mc_whichdimm(hdl, mc, pa, synd, syndtype)) < 0) + return (-1); /* errno is set for us */ + + if (unum_fill(hdl, cs, which, iaddr, unump, 1) < 0) + return (-1); /* errno is set for us */ + +#ifdef DEBUG + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "bkdgres=%d res=0\n", bkdgres); +#ifndef _KERNEL + /* offset is not checked - see note in BKDG algorithm */ + assert(bkdgres == 0 && unump->unum_board == bkdg_unum.unum_board && + unump->unum_chip == bkdg_unum.unum_chip && + unump->unum_mc == bkdg_unum.unum_mc && + unump->unum_cs == bkdg_unum.unum_cs && + unump->unum_dimms[0] == bkdg_unum.unum_dimms[0] && + unump->unum_dimms[1] == bkdg_unum.unum_dimms[1]); +#endif /* !_KERNEL */ +#endif /* DEBUG */ + + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "Result: chip %d mc %d cs %d " + "offset 0x%llx\n", unump->unum_chip, unump->unum_mc, + unump->unum_cs, unump->unum_offset); + + return (0); +} + +int +mcamd_patounum(struct mcamd_hdl *hdl, mcamd_node_t *root, uint64_t pa, + uint32_t synd, int syndtype, struct mc_unum *unump) +{ + mcamd_node_t *mc; + + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_patounum: pa=0x%llx, " + "synd=0x%x, syndtype=%d\n", pa, synd, syndtype); + + if (!mcamd_synd_validate(hdl, synd, syndtype)) + return (mcamd_set_errno(hdl, EMCAMD_SYNDINVALID)); + + for (mc = mcamd_mc_next(hdl, root, NULL); mc != NULL; + mc = mcamd_mc_next(hdl, root, mc)) { + if (mc_patounum(hdl, mc, pa, synd, syndtype, unump) == 0) + return (0); + + if (mcamd_errno(hdl) != EMCAMD_NOADDR) + break; + } + + return (-1); /* errno is set for us */ +} diff --git a/usr/src/common/mc/mc-amd/mcamd_rowcol.c b/usr/src/common/mc/mc-amd/mcamd_rowcol.c new file mode 100644 index 0000000000..3309d69421 --- /dev/null +++ b/usr/src/common/mc/mc-amd/mcamd_rowcol.c @@ -0,0 +1,573 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <mcamd_api.h> +#include <mcamd_err.h> +#include <mcamd_rowcol_impl.h> + +/* + * Convenience structures to stash MC and CS properties in. Some of these + * are read directly, while others are then calculated. + */ +struct rcp_mc { + uint64_t num; /* corresponding chip number */ + uint64_t rev; /* revision */ + uint64_t width; /* access width */ + uint64_t base; /* MC base address */ + uint64_t lim; /* MC limit address */ + uint64_t csbnkmap; /* chip-select bank map */ + uint64_t intlven; /* Node-interleave mask */ + uint64_t intlvsel; /* Node-interleave selection for this node */ + uint64_t csintlvfctr; /* chip-select interleave factor on this node */ + int bnkswzl; /* bank-swizzle mode - derived */ +}; + +struct rcp_cs { + uint64_t num; /* chip-select number */ + uint64_t base; /* chip-select base address */ + uint64_t mask; /* chip-select mask */ +}; + +static int +getmcprops(struct mcamd_hdl *hdl, mcamd_node_t *mc, const char *caller, + struct rcp_mc *pp) +{ + if (!mcamd_get_numprop(hdl, mc, MCAMD_PROP_NUM, &pp->num) || + !mcamd_get_numprop(hdl, mc, MCAMD_PROP_REV, &pp->rev) || + !mcamd_get_numprop(hdl, mc, MCAMD_PROP_ACCESS_WIDTH, &pp->width) || + !mcamd_get_numprop(hdl, mc, MCAMD_PROP_BASE_ADDR, &pp->base) || + !mcamd_get_numprop(hdl, mc, MCAMD_PROP_LIM_ADDR, &pp->lim) || + !mcamd_get_numprop(hdl, mc, MCAMD_PROP_CSBANKMAP, &pp->csbnkmap) || + !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_ILEN, &pp->intlven) || + !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_ILSEL, &pp->intlvsel) || + !mcamd_get_numprop(hdl, mc, MCAMD_PROP_CSBANK_INTLV, + &pp->csintlvfctr)) { + mcamd_dprintf(hdl, MCAMD_DBG_ERR, "%s: failed to read mc " + "props for mc 0x%p\n", caller, mc); + return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); + } + + pp->bnkswzl = ((pp->csbnkmap & MC_DC_BAM_CSBANK_SWIZZLE) != 0); + + return (0); +} + +static int +getcsprops(struct mcamd_hdl *hdl, mcamd_node_t *cs, const char *caller, + struct rcp_cs *csp) +{ + if (!mcamd_get_numprop(hdl, cs, MCAMD_PROP_NUM, &csp->num) || + !mcamd_get_numprop(hdl, cs, MCAMD_PROP_BASE_ADDR, &csp->base) || + !mcamd_get_numprop(hdl, cs, MCAMD_PROP_MASK, &csp->mask)) { + mcamd_dprintf(hdl, MCAMD_DBG_ERR, "%s: failed to read cs " + "props for cs 0x%p\n", caller, cs); + return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); + } + + return (0); +} + +static int +gettbls(struct mcamd_hdl *hdl, uint_t csmode, struct rcp_mc *mcpp, + const struct bankaddr_mode **bamp, const struct csrcb_map **rcbmp, + struct csintlv_desc *csid, const char *caller) +{ + if (bamp && (*bamp = rct_bankaddr_mode(mcpp->rev, csmode)) == NULL) { + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "%s: no bank address mode " + "table for MC rev %d csmode %d\n", caller, + (int)mcpp->rev, csmode); + return (mcamd_set_errno(hdl, EMCAMD_NOTSUP)); + } + + if (rcbmp && (*rcbmp = rct_rcbmap(mcpp->rev, mcpp->width, + csmode)) == NULL) { + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "%s: no dram address map " + "table for MC rev %d csmode %d\n", caller, + (int)mcpp->rev, csmode); + return (mcamd_set_errno(hdl, EMCAMD_NOTSUP)); + } + + if (csid) { + if (mcpp->csintlvfctr != 0) { + rct_csintlv_bits(mcpp->rev, mcpp->width, csmode, + mcpp->csintlvfctr, csid); + if (csid->csi_factor == 0) { + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "%s: " + "could not work out cs interleave " + "paramters for MC rev %d, width %d, " + "csmode %d, factor %d\n", caller, + (int)mcpp->rev, (int)mcpp->width, csmode, + (int)mcpp->csintlvfctr); + return (mcamd_set_errno(hdl, EMCAMD_NOTSUP)); + } + } else { + csid->csi_factor = 0; + } + } + + return (0); +} + +static uint64_t +iaddr_add(struct mcamd_hdl *hdl, uint64_t in, uint64_t add, const char *what) +{ + uint64_t new = in | add; + + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "%s: 0x%llx | 0x%llx --> 0x%llx", + what, in, add, new); + + return (add); +} + +/* + * Where the number of row/col address bits is ambiguous (affects CG and + * earlier only) we will assign the "floating" bit to row address. If + * we adopt the same convention in address reconstruction then all should work. + */ +static uint32_t +iaddr_to_row(struct mcamd_hdl *hdl, const struct bankaddr_mode *bamp, + const struct csrcb_map *rcbm, struct csintlv_desc *csid, uint64_t iaddr) +{ + uint32_t addr = 0; + int abitno, ibitno; + int nbits = bamp->bam_nrows; + int swapped = 0; + + for (abitno = 0; abitno < nbits; abitno++) { + ibitno = rcbm->csrcb_rowbits[abitno]; + if (MC_RC_CSI_SWAPPED_BIT(csid, ibitno)) { + ibitno = MC_RC_CSI_BITSWAP(csid, ibitno); + swapped++; + } + if (iaddr & (1 << ibitno)) + addr |= (1 << abitno); + } + + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "iaddr_to_row: iaddr 0x%llx --> " + "row 0x%x (%d bits swapped for cs intlv)\n", iaddr, addr, swapped); + + return (addr); +} + +/*ARGSUSED*/ +static uint64_t +row_to_iaddr(struct mcamd_hdl *hdl, const struct bankaddr_mode *bamp, + const struct csrcb_map *rcbm, struct csintlv_desc *csid, uint32_t rowaddr) +{ + uint64_t iaddr = 0; + int abitno, ibitno; + int nbits = bamp->bam_nrows; + + for (abitno = 0; abitno < nbits; abitno++) { + if (BIT(rowaddr, abitno) == 0) + continue; + ibitno = rcbm->csrcb_rowbits[abitno]; + if (MC_RC_CSI_SWAPPED_BIT(csid, ibitno)) { + ibitno = MC_RC_CSI_BITSWAP(csid, ibitno); + } + SETBIT(iaddr, ibitno); + } + + return (iaddr); +} + + +static uint32_t +iaddr_to_col(struct mcamd_hdl *hdl, const struct bankaddr_mode *bamp, + const struct csrcb_map *rcbm, uint64_t iaddr) +{ + uint32_t addr = 0; + int abitno, ibitno, bias = 0; + int nbits = bamp->bam_ncols; + + /* + * Knock off a column bit if the numbers are ambiguous + */ + if (bamp->bam_ambig) + nbits--; + + for (abitno = 0; abitno < nbits; abitno++) { + if (abitno == MC_PC_COLADDRBIT) + bias = 1; + + ibitno = rcbm->csrcb_colbits[abitno + bias]; + + if (iaddr & (1 << ibitno)) + SETBIT(addr, abitno); + } + + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "iaddr_to_col: iaddr 0x%llx --> " + "col 0x%x\n", iaddr, addr); + + return (addr); +} + +/*ARGSUSED*/ +static uint64_t +col_to_iaddr(struct mcamd_hdl *hdl, const struct bankaddr_mode *bamp, + const struct csrcb_map *rcbm, uint32_t coladdr) +{ + uint64_t iaddr = 0; + int abitno, ibitno, bias = 0; + int nbits = bamp->bam_ncols; + + /* + * Knock off a column bit if the numbers are ambiguous + */ + if (bamp->bam_ambig) + nbits--; + + for (abitno = 0; abitno < nbits; abitno++) { + if (BIT(coladdr, abitno) == 0) + continue; + + if (abitno == MC_PC_COLADDRBIT) + bias = 1; + + ibitno = rcbm->csrcb_colbits[abitno + bias]; + SETBIT(iaddr, ibitno); + } + + return (iaddr); +} + +/* + * Extract bank bit arguments and xor them together. Tables for + * non bank-swizzling should have all but the first argument zero. + */ +static uint32_t +iaddr_to_bank(struct mcamd_hdl *hdl, const struct csrcb_map *rcbm, + int bnkswzl, uint64_t iaddr) +{ + uint32_t addr = 0; + int abitno, ibitno, i; + int bnkargs = bnkswzl ? MC_RC_BANKARGS : 1; + + for (abitno = 0; abitno < MC_RC_BANKBITS; abitno++) { + uint32_t val = 0; + for (i = 0; i < bnkargs; i++) { + ibitno = rcbm->csrcb_bankargs[abitno][i]; + val ^= ((iaddr >> ibitno) & 0x1); + } + addr |= (val << abitno); + } + + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "iaddr_to_bank: iaddr 0x%llx --> " + "bank 0x%x\n", iaddr, addr); + + return (addr); +} + +/* + * bank_to_iaddr requires the iaddr reconstructed thus far with at least the + * row bits repopulated. That's because in bank swizzle mode + * the bank bits are the result of xor'ing three original iaddr bits + * together - two of which come from the row address and the third we + * can reconstruct here. Note that a zero bankaddr bit *can* result + * in a nonzero iaddr bit (unlike in row and col reconstruction). + */ +/*ARGSUSED*/ +static uint64_t +bank_to_iaddr(struct mcamd_hdl *hdl, const struct csrcb_map *rcbm, + int bnkswzl, uint64_t partiaddr, uint32_t bankaddr) +{ + uint64_t iaddr = 0; + int abitno, pibitno, i; + + for (abitno = 0; abitno < MC_RC_BANKBITS; abitno++) { + uint32_t val = BITVAL(bankaddr, abitno); + if (bnkswzl) { + for (i = 1; i < MC_RC_BANKARGS; i++) { + pibitno = rcbm->csrcb_bankargs[abitno][i]; + val ^= BITVAL(partiaddr, pibitno); + } + } + if (val) + SETBIT(iaddr, rcbm->csrcb_bankargs[abitno][0]); + } + + return (iaddr); +} + +static int +iaddr_to_rcb(struct mcamd_hdl *hdl, uint_t csmode, struct rcp_mc *mcpp, + uint64_t iaddr, uint32_t *rowp, uint32_t *colp, uint32_t *bankp) +{ + const struct bankaddr_mode *bamp; + const struct csrcb_map *rcbm; + struct csintlv_desc csi; + + if (gettbls(hdl, csmode, mcpp, &bamp, &rcbm, &csi, "iaddr_to_rcb") < 0) + return (-1); /* errno already set */ + + *rowp = iaddr_to_row(hdl, bamp, rcbm, &csi, iaddr); + *colp = iaddr_to_col(hdl, bamp, rcbm, iaddr); + *bankp = iaddr_to_bank(hdl, rcbm, mcpp->bnkswzl, iaddr); + + return (0); +} + +/* + * Take a reconstructed InputAddr and undo the normalization described in + * BKDG 3.29 3.4.4 to include the base address of the MC if no node + * interleave or to insert the node interleave selection bits. + */ +static int +iaddr_unnormalize(struct mcamd_hdl *hdl, struct rcp_mc *mcpp, uint64_t iaddr, + uint64_t *rsltp) +{ + uint64_t dramaddr; + int intlvbits; + + switch (mcpp->intlven) { + case 0x0: + intlvbits = 0; + break; + case 0x1: + intlvbits = 1; + break; + case 0x3: + intlvbits = 2; + break; + case 0x7: + intlvbits = 3; + break; + default: + mcamd_dprintf(hdl, MCAMD_DBG_ERR, "iaddr_unnormalize: " + "illegal IntlvEn of %d for MC 0x%p\n", + (int)mcpp->intlven, (int)mcpp->num); + return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); + } + + if (intlvbits != 0) { + /* + * For a 2/4/8 way interleave iaddr was formed by excising + * 1, 2, or 3 bits 12:12, 13:12, or 14:12 from dramaddr, + * the removed bits having done their job by selecting the + * responding node. So we must move bits 35:12 of the + * reconstructed iaddr up to make a 1, 2 or 3 bit hole and + * then fill those bits with the current IntlvSel value for + * this node. The node base address must be zero if nodes + * are interleaved. + */ + dramaddr = (BITS(iaddr, 35, 12) << intlvbits) | + (mcpp->intlvsel << 12) | BITS(iaddr, 11, 0); + } else { + dramaddr = iaddr + mcpp->base; + } + + *rsltp = dramaddr; + + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "iaddr_unnormalize: iaddr 0x%llx " + "intlven 0x%x intlvsel 0x%x MC base 0x%llx --> 0x%llx\n", + iaddr, (int)mcpp->intlven, (int)mcpp->intlvsel, (int)mcpp->base, + dramaddr); + + return (0); +} + +int +mc_pa_to_offset(struct mcamd_hdl *hdl, mcamd_node_t *mc, mcamd_node_t *cs, + mcamd_node_t *dimm, uint64_t iaddr, uint64_t *offsetp) +{ + mcamd_dimm_offset_un_t offset_un; + uint_t csmode; + uint32_t bankaddr, rowaddr, coladdr; + int rank; + mcamd_node_t *tcs; + struct rcp_mc mcp; + struct rcp_cs csp; + + *offsetp = MCAMD_RC_INVALID_OFFSET; + + if (getmcprops(hdl, mc, "mc_dimm_offset", &mcp) < 0 || + getcsprops(hdl, cs, "mc_dimm_offset", &csp) < 0) + return (-1); /* errno already set */ + + csmode = MC_CS_MODE(mcp.csbnkmap, csp.num); + + /* + * Convert chip-select number 0 .. 7 to a DIMM rank 0 .. 3. The + * rank is the index of the member of the dimm mcd_cs array which + * matches cs. + */ + for (rank = 0, tcs = mcamd_cs_next(hdl, (mcamd_node_t *)dimm, NULL); + tcs != NULL; + rank++, tcs = mcamd_cs_next(hdl, (mcamd_node_t *)dimm, tcs)) { + struct rcp_cs tcsp; + + if (getcsprops(hdl, tcs, "mc_dimm_offset", &tcsp) < 0) + return (-1); /* errno already set */ + if (tcsp.num == csp.num) + break; + } + if (rank == MC_CHIP_DIMMRANKMAX) { + mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mcamd_dimm_offset: " + "iteration over chip-selects of dimm 0x%p failed " + "to match on expected csnum %d\n", dimm, (int)csp.num); + return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); + } + + if (iaddr_to_rcb(hdl, csmode, &mcp, iaddr, &rowaddr, + &coladdr, &bankaddr) < 0) + return (-1); /* errno already set */ + + offset_un.do_offset = 0; + + offset_un.do_valid = 1; + offset_un.do_version = MCAMD_OFFSET_VERSION; + offset_un.do_rank = rank; + offset_un.do_row = rowaddr; + offset_un.do_bank = bankaddr; + offset_un.do_col = coladdr; + + *offsetp = offset_un.do_offset; + + return (0); +} + +/* + * Given a MC and DIMM and offset (dimm rank, row, col, internal bank) we + * find the corresponding chip-select for the rank and then reconstruct + * a system address. In the absence of serial number support it is possible + * that we may be asked to perform this operation on a dimm which has been + * swapped, perhaps even for a dimm of different size and number of ranks. + * This may happen if fmadm repair has not been used. There are some + * unused bits in the offset and we could guard against this a little + * by recording in those bit some of the physical characteristic of the + * original DIMM such as size, number of ranks etc. + */ +int +mc_offset_to_pa(struct mcamd_hdl *hdl, mcamd_node_t *mc, mcamd_node_t *dimm, + uint64_t offset, uint64_t *pap) +{ + mcamd_node_t *cs; + mcamd_dimm_offset_un_t off_un; + uint32_t rank, rowaddr, bankaddr, coladdr; + int i; + uint64_t iaddr = 0; + const struct bankaddr_mode *bamp; + const struct csrcb_map *rcbm; + struct csintlv_desc csi; + struct rcp_mc mcp; + struct rcp_cs csp; + uint64_t csmode; + int maskhi_hi = MC_DC_CSM_MASKHI_HIBIT; + int maskhi_lo = MC_DC_CSM_MASKHI_LOBIT; + int masklo_hi = MC_DC_CSM_MASKLO_HIBIT; + int masklo_lo = MC_DC_CSM_MASKLO_LOBIT; + + off_un.do_offset = offset; + rank = off_un.do_rank; + bankaddr = off_un.do_bank; + rowaddr = off_un.do_row; + coladdr = off_un.do_col; + + if (getmcprops(hdl, mc, "mc_offset_to_pa", &mcp) < 0) + return (-1); /* errno already set */ + + /* + * Find the rank'th chip-select on this dimm. + */ + i = 0; + cs = mcamd_cs_next(hdl, dimm, NULL); + while (i != rank && cs != NULL) { + cs = mcamd_cs_next(hdl, dimm, cs); + i++; + } + if (i != rank || cs == NULL) { + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_offset_to_pa: Current " + "dimm in this slot does not have an %d'th cs\n", + rank); + return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); + } + + if (getcsprops(hdl, cs, "mc_offset_to_pa", &csp) < 0) + return (-1); /* errno already set */ + + csmode = MC_CS_MODE(mcp.csbnkmap, csp.num); + + if (gettbls(hdl, csmode, &mcp, &bamp, &rcbm, &csi, + "mc_offset_to_pa") < 0) + return (-1); /* errno already set */ + + /*CONSTANTCONDITION*/ + if (MC_DC_CSM_UNMASKED_BITS != 0) { + iaddr |= iaddr_add(hdl, iaddr, + BITS(csp.base, maskhi_hi + MC_DC_CSM_UNMASKED_BITS, + maskhi_hi + 1), "unmaskable cs basehi bits"); + } + + iaddr |= iaddr_add(hdl, iaddr, + BITS(csp.base, maskhi_hi, maskhi_lo) & + ~BITS(csp.mask, maskhi_hi, maskhi_lo), + "cs basehi bits not being masked"); + + if (mcp.csintlvfctr != 0) { + iaddr |= iaddr_add(hdl, iaddr, + BITS(csp.base, masklo_hi, masklo_lo) & + ~BITS(csp.mask, masklo_hi, masklo_lo), + "cs baselo bits not being masked"); + } + + iaddr |= iaddr_add(hdl, iaddr, + row_to_iaddr(hdl, bamp, rcbm, &csi, rowaddr), + "add iaddr bits from row"); + + iaddr |= iaddr_add(hdl, iaddr, + col_to_iaddr(hdl, bamp, rcbm, coladdr), + "add iaddr bits from col"); + + iaddr |= iaddr_add(hdl, iaddr, + bank_to_iaddr(hdl, rcbm, mcp.bnkswzl, iaddr, bankaddr), + "add iaddr bits from bank"); + + if (iaddr_unnormalize(hdl, &mcp, iaddr, pap) < 0) + return (-1); /* errno already set */ + + return (0); +} + +int +mcamd_cs_size(struct mcamd_hdl *hdl, mcamd_node_t *mc, int csnum, size_t *szp) +{ + uint_t csmode; + struct rcp_mc mcp; + const struct bankaddr_mode *bamp; + + if (getmcprops(hdl, mc, "mcamd_cs_size", &mcp) < 0) + return (-1); /* errno already set */ + + csmode = MC_CS_MODE(mcp.csbnkmap, csnum); + + if (gettbls(hdl, csmode, &mcp, &bamp, NULL, NULL, "mcamd_cs_size") < 0) + return (-1); /* errno already set */ + + *szp = MC_CS_SIZE(bamp, mcp.width); + + return (0); +} diff --git a/usr/src/common/mc/mc-amd/mcamd_rowcol_impl.h b/usr/src/common/mc/mc-amd/mcamd_rowcol_impl.h new file mode 100644 index 0000000000..d7341e9b28 --- /dev/null +++ b/usr/src/common/mc/mc-amd/mcamd_rowcol_impl.h @@ -0,0 +1,132 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _MCAMD_ROWCOL_IMPL_H +#define _MCAMD_ROWCOL_IMPL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <mcamd_api.h> +#include <sys/mc_amd.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define MC_PC_COLADDRBIT 10 /* col address bit used for precharge */ +#define MC_PC_ALL -1 /* marker used in tables */ + +#define MC_CS_SCALE (1024 * 1024) +#define MC_CS_SIZE(bam, width) \ + ((size_t)bam->bam_sizemb * MC_CS_SCALE * ((width) == 128 ? 2 : 1)) + +#define MC_CS_MODE(csbmap, csnum) \ + (csbmap >> MC_CHIP_DIMMPAIR(csnum) * MC_DC_BAM_CSBANK_SHIFT & \ + MC_DC_BAM_CSBANK_MASK) + +#define BIT(val, num) ((val) & 1ULL << num) + +#define BITS(val, high, low) \ + ((val) & (((2ULL << (high)) - 1) & ~((1ULL << (low)) - 1))) + +#define SETBIT(var, num) (var |= (1ULL << (num))) + +#define BITVAL(var, num) ((BIT(var, num) >> (num)) & 1ULL) + +#define MC_RC_ROW_MAX 14 /* maximum number of row address bits */ +#define MC_RC_COL_MAX 12 /* maximum number of col address bits */ +#define MC_RC_BANKBITS 2 /* number of internal banksel bits */ +#define MC_RC_BANKARGS 3 /* bits used for 1 banksel bit */ +#define MC_RC_CSMODES 16 /* max number of cs bankaddr modes */ + +/* + * Row, column and bank mapping is derived after allowing for interleave + * from the normalized dram address through the tables of BKDG 3.29 + * section 3.5.6.1. We have tables for: + * + * . rev CG and earlier, 64-bit MC mode + * . rev CG and earlier, 128-bit MC mode + * . rev D and later, 64-bit MC mode (no bank swizzling if rev E) + * . rev D and later, 128-bit MC mode (no bank swizzling if rev E) + * . rev E and later, 64-bit MC mode with bank swizzling + * . rev E and later, 128-bit MC mode with bank swizzling + * + * Each table is indexed by CS Mode (equivalently, CS size) and tells us + * which bits of the normalized dram address (i.e., the address modified for + * the local MC base address and with node interleave selection bits removed) + * to use in forming the column address, row address and internal bank + * selection. + * + * Note that for rev CG and earlier there is some overloading of CS mode + * encoding such that we do not know the number of row and column address + * bits from the CS mode alone, e.g., for 128MB DIMM modules we may have + * 13 row bits and 9 column, or 12 row and 10 column. In these case the + * tables held in the structures defined below will have a duplicated bit + * number in the row and column bits. In these ambiguous cases cm_rc_ambig + * should be set in the table. + */ + +struct bankaddr_mode { + int bam_sizemb; /* DIMM size in MB */ + int bam_nrows; /* number of row address bits */ + int bam_ncols; /* number of column address bits */ + int bam_ambig; /* numbers are maximums; keep last */ +}; + +struct csrcb_map { + int csrcb_bankargs[MC_RC_BANKBITS][MC_RC_BANKARGS]; + int csrcb_rowbits[MC_RC_ROW_MAX]; + int csrcb_colbits[MC_RC_COL_MAX + 1]; /* one for MC_PC_ALL */ +}; + +struct csrcb_map_tbl { + int mt_rev; /* revision to which this applies */ + int mt_width; /* MC mode (64 or 128) */ + struct csrcb_map mt_csmap[MC_RC_CSMODES]; +}; + +struct csintlv_desc { + int csi_factor; /* cs interleave factor */ + int csi_hibit; /* first non-offset bit in addr */ + int csi_lobit; /* first row bit in addr */ + int csi_nbits; /* number of bits to swap in mask */ +}; + +#define MC_RC_CSI_SWAPPED_BIT(csidp, n) \ + (csidp->csi_factor && n >= csidp->csi_lobit && \ + n <= csidp->csi_lobit + csidp->csi_nbits - 1) + +#define MC_RC_CSI_BITSWAP(csidp, n) \ + (csidp->csi_hibit + n - csidp->csi_lobit) + +extern const struct bankaddr_mode *rct_bankaddr_mode(uint_t, uint_t); +extern const struct csrcb_map *rct_rcbmap(uint_t, int, uint_t); +extern void rct_csintlv_bits(uint_t, int, uint_t, int, struct csintlv_desc *); + +#ifdef __cplusplus +} +#endif + +#endif /* _MCAMD_ROWCOL_IMPL_H */ diff --git a/usr/src/common/mc/mc-amd/mcamd_rowcol_tbl.c b/usr/src/common/mc/mc-amd/mcamd_rowcol_tbl.c new file mode 100644 index 0000000000..db10f90095 --- /dev/null +++ b/usr/src/common/mc/mc-amd/mcamd_rowcol_tbl.c @@ -0,0 +1,591 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <mcamd_api.h> +#include <mcamd_err.h> +#include <mcamd_rowcol_impl.h> + +/* + * Chip-Select Bank Address Mode Encodings - BKDG 3.29 3.5.6 + */ +static const struct bankaddr_mode bankaddr_modes_pre_d[]; +static const struct bankaddr_mode bankaddr_modes_d_e[]; + +static const struct bam_desc { + int rev; + int nmodes; + const struct bankaddr_mode *modetbl; +} bankaddr_modes[] = { + { MC_REV_PRE_D, 7, bankaddr_modes_pre_d }, + { MC_REV_D_E, 11, bankaddr_modes_d_e }, +}; + +/* + * DRAM Address Mappings for bank/row/column - BKDG 3.29 3.5.6.1 + */ +static const struct csrcb_map_tbl dram_addrmap_pre_d_128; +static const struct csrcb_map_tbl dram_addrmap_pre_d_64; +static const struct csrcb_map_tbl dram_addrmap_d_e_64; +static const struct csrcb_map_tbl dram_addrmap_d_e_128; + +static const struct rcbmap_desc { + int nmodes; + const struct csrcb_map_tbl *rcbmap; +} rcbmaps[] = { + { 7, &dram_addrmap_pre_d_64 }, + { 7, &dram_addrmap_pre_d_128 }, + { 11, &dram_addrmap_d_e_64 }, + { 11, &dram_addrmap_d_e_128 }, +}; + +/* + * Lookup the Chip-Select Bank Address Mode Encoding table for a given + * chip revision and chip-select mode. + */ +const struct bankaddr_mode * +rct_bankaddr_mode(uint_t mcrev, uint_t csmode) +{ + int i; + const struct bam_desc *bdp = bankaddr_modes; + + for (i = 0; i < sizeof (bankaddr_modes) / sizeof (struct bam_desc); + i++, bdp++) { + if (bdp->rev == mcrev && csmode < bdp->nmodes) + return (&bdp->modetbl[csmode]); + + } + + return (NULL); +} + +/* + * Lookup the DRAM Address Mapping table for a given chip revision, access + * width, bank-swizzle and chip-select mode. + */ +const struct csrcb_map * +rct_rcbmap(uint_t mcrev, int width, uint_t csmode) +{ + const struct csrcb_map_tbl *rcbm; + int i; + + for (i = 0; i < sizeof (rcbmaps) / sizeof (struct rcbmap_desc); i++) { + rcbm = rcbmaps[i].rcbmap; + if (rcbm->mt_rev == mcrev && rcbm->mt_width == width && + csmode < rcbmaps[i].nmodes) + return (&rcbm->mt_csmap[csmode]); + } + + return (NULL); +} + +/* + * DRAM Address Mapping in Interleaving Mode - BKDG 3.29 section 3.5.6.2. + * + * Chip-select interleave is performed by addressing across the columns + * of the first row of internal bank-select 0 on a chip-select, then the + * next row on internal bank-select 1, then 2 then 3; instead of then + * moving on to the next row of this chip-select we then rotate across + * other chip-selects in the interleave. The row/column/bank mappings + * described elsewhere in this file show that a DRAM InputAddr breaks down + * as follows (example is the first line of table 7 which is for a 32MB + * chip-select requiring 25 bits to address all of it) for the non-interleaved + * case: + * + * chip-selection bits | offset within chip-select bits | + * | row bits | bank bits | column bits | - | + * 24 13 12 11 10 3 2 0 + * + * The high-order chip-selection bits select the chip-select and the + * offset bits offset within the chosen chip-select. + * + * To establish say a 2-way interleave in which we consume all of one + * row number and all internal bank numbers on one cs before moving on + * to the next to do the same we will target the first row bit - bit 13; + * a 4-way interleave would use bits 14 and 13, and an 8-way interleave + * bits 15, 14 and 13. We swap the chosen bits with the least significant + * high order chip-selection bits. + * + * Tables 13-16 of BKDG 3.5.6.2 really just describe the above. Working + * out the high-order bits to swap is easy since that is derived directly + * from the chip-select size. The low-order bits depend on the device + * parameters since we need to target the least significant row address bits - + * but we have that information from the rcbmaps since the first row bit + * simply follows the last bank address bit. + * + * Short version: we will do tables 13 to 16 programatically rather than + * replicating those tables. + */ + +/* + * Yet another highbit function. This really needs to go to common source. + * Returns range 0 to 64 inclusive; + */ +static int +topbit(uint64_t i) +{ + int h = 1; + + if (i == 0) + return (0); + + if (i & 0xffffffff00000000ULL) { + h += 32; + i >>= 32; + } + + if (i & 0xffff0000) { + h += 16; + i >>= 16; + } + + if (i & 0xff00) { + h += 8; + i >>= 8; + } + + if (i & 0xf0) { + h += 4; + i >>= 4; + } + + if (i & 0xc) { + h += 2; + i >>= 2; + } + + if (i & 0x2) + h += 1; + + return (h); +} + +void +rct_csintlv_bits(uint_t mcrev, int width, uint_t csmode, int factor, + struct csintlv_desc *csid) +{ + int i, lstbnkbit; + size_t csz; + const struct bankaddr_mode *bam; + const struct csrcb_map *rcm; + + /* + * Dispatch the three "Not implemented" exceptions. + */ + if ((mcrev == MC_REV_PRE_D && width == 128 && csmode == 0x6) || + (mcrev == MC_REV_D_E && width == 128 && (csmode == 0x9 || + csmode == 0xa))) { + csid->csi_factor = 0; + return; + } + + if ((bam = rct_bankaddr_mode(mcrev, csmode)) == NULL || + (rcm = rct_rcbmap(mcrev, width, csmode)) == NULL) { + csid->csi_factor = 0; + return; + } + + csz = MC_CS_SIZE(bam, width); + + switch (factor) { + case 2: + csid->csi_nbits = 1; + break; + case 4: + csid->csi_nbits = 2; + break; + case 8: + csid->csi_nbits = 3; + break; + default: + csid->csi_factor = 0; + return; + } + + csid->csi_hibit = topbit(csz) - 1; + + lstbnkbit = 0; + for (i = 0; i < MC_RC_BANKBITS; i++) { + /* first bank arg for a bit is "real" bank bit */ + if (rcm->csrcb_bankargs[i][0] > lstbnkbit) + lstbnkbit = rcm->csrcb_bankargs[i][0]; + } + + /* first row bit is immediately after last bank bit */ + csid->csi_lobit = lstbnkbit + 1; + + csid->csi_factor = factor; +} + + +/* + * General notes for CS Bank Address Mode Encoding tables. + * + * These are the tables of BKDG 3.29 section 3.5.6. They are indexed + * by chip-select mode. Where the numbers of rows and columns is + * ambiguous (as it is for a number of rev CG and earlier cases) + * the bam_config should be initialized to 1 and the numbers of rows + * and columns should be the maximums. + */ + +/* + * Chip Select Bank Address Mode Encoding for rev CG and earlier. + */ +static const struct bankaddr_mode bankaddr_modes_pre_d[] = { + { /* 000 */ + 32, 12, 8 + }, + { /* 001 */ + 64, 12, 9 + }, + { /* 010 */ + 128, 13, 10, 1 + }, + { /* 011 */ + 256, 13, 11, 1 + }, + { /* 100 */ + 512, 14, 11, 1 + }, + { /* 101 */ + 1024, 14, 12, 1 + }, + { /* 110 */ + 2048, 14, 12 + } +}; + +/* + * Chip Select Bank Address Mode Encoding for revs D and E. + */ +static const struct bankaddr_mode bankaddr_modes_d_e[] = { + { /* 0000 */ + 32, 12, 8 + }, + { /* 0001 */ + 64, 12, 9 + }, + { /* 0010 */ + 128, 13, 9 + }, + { /* 0011 */ + 128, 12, 10 + }, + { /* 0100 */ + 256, 13, 10 + }, + { /* 0101 */ + 512, 14, 10 + }, + { /* 0110 */ + 256, 12, 11 + }, + { /* 0111 */ + 512, 13, 11 + }, + { /* 1000 */ + 1024, 14, 11 + }, + { /* 1001 */ + 1024, 13, 12 + }, + { /* 1010 */ + 2048, 14, 12 + } +}; + +/* + * General notes on Row/Column/Bank table initialisation. + * + * These are the tables 7, 8, 9, 10, 11 and 12 of BKDG 3.29 section 3.5.6.1. + * They apply in non-interleave (node or cs) mode and describe how for + * a given revision, access width, bank-swizzle mode, and current chip-select + * mode the row, column and internal sdram bank are derived from the + * normalizied InputAddr presented to the DRAM controller. + * + * The mt_csmap array is indexed by chip-select mode. Within it the + * bankargs, rowbits and colbits arrays are indexed by bit number, so + * match the BKDG tables if the latter are read right-to-left. + * + * The bankargs list up to three bit numbers per bank bit. For revisions + * CG and earlier there is no bank swizzling, so just a single number + * should be listed. Revisions D and E have the same row/column/bank mapping, + * but rev E has the additional feature of being able to xor two row bits + * into each bank bit. The consumer will know whether they are using bank + * swizzling - if so then they should xor the bankargs bits together. + * The first argument must be the bit number not already used in forming + * part of the row address - eg in table 12 for csmode 0000b bank address + * bit 0 is bit 12 xor bit 18 xor bit 21, and 18 and 21 are also mentioned in + * the row address (bits 10 and 1) so we must list bit 12 first. We will + * use this information in chip-select interleave decoding in which we need + * to know which is the first bit after column and bank address bits. + * + * Column address A10 is always used for the Precharge All signal. Where + * "PC" appears in the BKDG tables we will include MC_PC_ALL in the + * corresponding bit position. + * + * For some rev CG and earlier chipselect modes the number of rows and columns + * is ambiguous. This is reflected in these tables by some bit being + * duplicated between row and column address. In practice we will follow + * the convention of always assigning the floating bit to the row address. + */ + +/* + * Row/Column/Bank address mappings for rev CG in 64-bit mode, no interleave. + * See BKDG 3.29 3.5.6 Table 7. + */ +static const struct csrcb_map_tbl dram_addrmap_pre_d_64 = { + MC_REV_PRE_D, + 64, + { + { /* 000 */ + { { 11 }, { 12 } }, + { 19, 20, 21, 22, 23, 24, 13, 14, 15, 16, 17, 18 }, + { 3, 4, 5, 6, 7, 8, 9, 10 } + }, + { /* 001 */ + { { 13 }, { 12 } }, + { 19, 20, 21, 22, 23, 24, 25, 14, 15, 16, 17, 18 }, + { 3, 4, 5, 6, 7, 8, 9, 10, 11 } + }, + { /* 010 */ + { { 13 }, { 12 } }, + { 19, 20, 21, 22, 23, 24, 25, 14, 15, 16, 17, 18, 26 }, + { 3, 4, 5, 6, 7, 8, 9, 10, 11, 26 } + }, + { /* 011 */ + { { 13 }, { 14 } }, + { 19, 20, 21, 22, 23, 24, 25, 26, 15, 16, 17, 18, 27 }, + { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, MC_PC_ALL, 27 } + }, + { /* 100 */ + { { 13 }, { 14 } }, + { 19, 20, 21, 22, 23, 24, 25, 26, 15, 16, 17, 18, 27, 28 }, + { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, MC_PC_ALL, 28 } + }, + { /* 101 */ + { { 15 }, { 14 } }, + { 19, 20, 21, 22, 23, 24, 25, 26, 29, 16, 17, 18, 27, 28 }, + { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, MC_PC_ALL, 13, 28 } + }, + { /* 110 */ + { { 15 }, { 14 } }, + { 19, 20, 21, 22, 23, 24, 25, 26, 29, 16, 17, 18, 27, 28 }, + { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, MC_PC_ALL, 13, 30 } + }, + /* + * remainder unused + */ + } + +}; + +/* + * Row/Column/Bank address mappings for rev CG in 128-bit mode, no interleave. + * See BKDG 3.29 3.5.6 Table 8. + */ +static const struct csrcb_map_tbl dram_addrmap_pre_d_128 = { + MC_REV_PRE_D, + 128, + { + { /* 000 */ + { { 12 }, { 13 } }, + { 20, 21, 22, 23, 24, 25, 14, 15, 16, 17, 18, 19 }, + { 4, 5, 6, 7, 8, 9, 10, 11 } + }, + { /* 001 */ + { { 14 }, { 13 } }, + { 20, 21, 22, 23, 24, 25, 26, 15, 16, 17, 18, 19 }, + { 4, 5, 6, 7, 8, 9, 10, 11, 12 } + }, + { /* 010 */ + { { 14 }, { 13 } }, + { 20, 21, 22, 23, 24, 25, 26, 15, 16, 17, 18, 19, 27 }, + { 4, 5, 6, 7, 8, 9, 10, 11, 12, 27 } + }, + { /* 011 */ + { { 14 }, { 15 } }, + { 20, 21, 22, 23, 24, 25, 26, 27, 16, 17, 18, 19, 28 }, + { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, MC_PC_ALL, 28 } + }, + { /* 100 */ + { { 14 }, { 15 } }, + { 20, 21, 22, 23, 24, 25, 26, 27, 16, 17, 18, 19, 28, 29 }, + { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, MC_PC_ALL, 29 } + }, + { /* 101 */ + { { 16 }, { 15 } }, + { 20, 21, 22, 23, 24, 25, 26, 27, 30, 17, 18, 19, 28, 29 }, + { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, MC_PC_ALL, 14, 29 } + }, + { /* 110 */ + { { 16 }, { 15 } }, + { 20, 21, 22, 23, 24, 25, 26, 27, 30, 17, 18, 19, 28, 29 }, + { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, MC_PC_ALL, 14, 31 } + }, + /* + * remainder unused + */ + } +}; + +/* + * Row/Column/Bank address mappings for rev D/E in 64-bit mode, no interleave. + * See BKDG 3.29 3.5.6 Table 9. + */ +static const struct csrcb_map_tbl dram_addrmap_d_e_64 = { + MC_REV_D_E, + 64, + { + { /* 0000 */ + { { 11, 17, 20 }, { 12, 18, 21 } }, + { 19, 20, 21, 22, 23, 24, 13, 14, 15, 16, 17, 18 }, + { 3, 4, 5, 6, 7, 8, 9, 10 } + }, + { /* 0001 */ + { { 12, 17, 20 }, { 13, 18, 21 } }, + { 19, 20, 21, 22, 23, 24, 25, 14, 15, 16, 17, 18, 26 }, + { 3, 4, 5, 6, 7, 8, 9, 10, 11 } + }, + { /* 0010 */ + { { 12, 17, 20 }, { 13, 18, 21 } }, + { 19, 20, 21, 22, 23, 24, 25, 14, 15, 16, 17, 18, 26 }, + { 3, 4, 5, 6, 7, 8, 9, 10, 11 } + }, + { /* 0011 */ + { { 13, 17, 20 }, { 14, 18, 21 } }, + { 19, 20, 21, 22, 23, 24, 25, 26, 15, 16, 17, 18, 27, 28 }, + { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 } + }, + { /* 0100 */ + { { 13, 17, 20 }, { 14, 18, 21 } }, + { 19, 20, 21, 22, 23, 24, 25, 26, 15, 16, 17, 18, 27, 28 }, + { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 } + }, + { /* 0101 */ + { { 13, 17, 20 }, { 14, 18, 21 } }, + { 19, 20, 21, 22, 23, 24, 25, 26, 15, 16, 17, 18, 27, 28 }, + { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 } + }, + { /* 0110 */ + { { 14, 17, 20 }, { 15, 18, 21 } }, + { 19, 20, 21, 22, 23, 24, 25, 26, 27, 16, 17, 18, 28, 29 }, + { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, MC_PC_ALL, 13 } + }, + { /* 0111 */ + { { 14, 17, 20 }, { 15, 18, 21 } }, + { 19, 20, 21, 22, 23, 24, 25, 26, 27, 16, 17, 18, 28, 29 }, + { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, MC_PC_ALL, 13 } + }, + { /* 1000 */ + { { 14, 17, 20 }, { 15, 18, 21 } }, + { 19, 20, 21, 22, 23, 24, 25, 26, 27, 16, 17, 18, 28, 29 }, + { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, MC_PC_ALL, 13 } + }, + { /* 1001 */ + { { 15, 17, 20 }, { 16, 18, 21 } }, + { 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 17, 18, 29, 30 }, + { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, MC_PC_ALL, 13, 14 } + }, + { /* 1010 */ + { { 15, 17, 20 }, { 16, 18, 21 } }, + { 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 17, 18, 29, 30 }, + { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, MC_PC_ALL, 13, 14 } + }, + /* + * remainder unused + */ + } +}; + +/* + * Row/Column/Bank address mappings for rev D/E in 128-bit mode, no interleave. + * See BKDG 3.29 3.5.6 Table 9. + */ +static const struct csrcb_map_tbl dram_addrmap_d_e_128 = { + MC_REV_D_E, + 128, + { + { /* 0000 */ + { { 12, 18, 21 }, { 13, 19, 22 } }, + { 20, 21, 22, 23, 24, 25, 14, 15, 16, 17, 18, 19 }, + { 4, 5, 6, 7, 8, 9, 10, 11 } + }, + { /* 0001 */ + { { 13, 18, 21 }, { 14, 19, 22 } }, + { 20, 21, 22, 23, 24, 25, 26, 15, 16, 17, 18, 19, 27 }, + { 4, 5, 6, 7, 8, 9, 10, 11, 12 } + }, + { /* 0010 */ + { { 13, 18, 21 }, { 14, 19, 22 } }, + { 20, 21, 22, 23, 24, 25, 26, 15, 16, 17, 18, 19, 27 }, + { 4, 5, 6, 7, 8, 9, 10, 11, 12 } + }, + { /* 0011 */ + { { 14, 18, 21 }, { 15, 19, 22 } }, + { 20, 21, 22, 23, 24, 25, 26, 27, 16, 17, 18, 19, 28, 29 }, + { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 } + }, + { /* 0100 */ + { { 14, 18, 21 }, { 15, 19, 22 } }, + { 20, 21, 22, 23, 24, 25, 26, 27, 16, 17, 18, 19, 28, 29 }, + { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 } + }, + { /* 0101 */ + { { 14, 18, 21 }, { 15, 19, 22 } }, + { 20, 21, 22, 23, 24, 25, 26, 27, 16, 17, 18, 19, 28, 29 }, + { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 } + }, + { /* 0110 */ + { { 15, 18, 21 }, { 16, 19, 22 } }, + { 20, 21, 22, 23, 24, 25, 26, 27, 28, 17, 18, 19, 29, 30 }, + { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, MC_PC_ALL, 14 } + }, + { /* 0111 */ + { { 15, 18, 21 }, { 16, 19, 22 } }, + { 20, 21, 22, 23, 24, 25, 26, 27, 28, 17, 18, 19, 29, 30 }, + { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, MC_PC_ALL, 14 } + }, + { /* 1000 */ + { { 15, 18, 21 }, { 16, 19, 22 } }, + { 20, 21, 22, 23, 24, 25, 26, 27, 28, 17, 18, 19, 29, 30 }, + { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, MC_PC_ALL, 14 } + }, + { /* 1001 */ + { { 16, 18, 21 }, { 17, 19, 22 } }, + { 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 18, 19, 30, 31 }, + { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, MC_PC_ALL, 14, 15 } + }, + { /* 1010 */ + { { 16, 18, 21 }, { 17, 19, 22 } }, + { 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 18, 19, 30, 31 }, + { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, MC_PC_ALL, 14, 15 } + }, + /* + * remainder unused + */ + } +}; diff --git a/usr/src/common/mc/mc-amd/mcamd_synd.c b/usr/src/common/mc/mc-amd/mcamd_synd.c new file mode 100644 index 0000000000..65308d3d1d --- /dev/null +++ b/usr/src/common/mc/mc-amd/mcamd_synd.c @@ -0,0 +1,281 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <mcamd_api.h> + +/* + * Indexed by syndrome, value is bit number. If value is -1, a multi-bit + * error has been detected. A special case is the zero'th entry - a + * syndrome of 0x0 indicates no bits in error. + */ +static char eccsynd[] = { + -1, 64, 65, -1, 66, -1, -1, -1, 67, -1, -1, 17, -1, -1, 16, -1, + 68, -1, -1, 18, -1, 19, 20, -1, -1, 21, 22, -1, 23, -1, -1, -1, + 69, -1, -1, 8, -1, 9, 10, -1, -1, 11, 12, -1, 13, -1, -1, -1, + -1, 14, -1, -1, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 70, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, -1, -1, -1, -1, 32, + -1, -1, 34, -1, 35, -1, -1, 36, 37, -1, -1, 38, -1, 39, -1, -1, + -1, -1, 56, -1, 57, -1, -1, 58, 59, -1, -1, 60, -1, 61, -1, -1, + 62, -1, -1, -1, -1, 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 71, -1, -1, -1, -1, -1, -1, -1, -1, -1, 49, -1, -1, -1, -1, 48, + -1, -1, 50, -1, 51, -1, -1, 52, 53, -1, -1, 54, -1, 55, -1, -1, + -1, -1, 40, -1, 41, -1, -1, 42, 43, -1, -1, 44, -1, 45, -1, -1, + 46, -1, -1, -1, -1, 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 0, -1, + -1, -1, -1, 2, -1, 3, 4, -1, -1, 5, 6, -1, 7, -1, -1, -1, + -1, -1, -1, 24, -1, 25, 26, -1, -1, 27, 28, -1, 29, -1, -1, -1, + -1, 30, -1, -1, 31, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + +/* + * The first dimension of this table is the errored bit pattern, which is the + * column dimension of the table in the BKDG. Conveniently, the bit pattern + * is also the lowest-order nibble in the syndrome, thus allowing the first + * dimension value to be calculated. The second dimension is the symbol + * number, which can be found by searching for a matching syndrome. + * + * Note that the first dimension is actually (errored_bit_pattern - 1) since + * 0 is not a valid errored bit pattern. + */ +#define MCAMD_CKSYND_NPATS 15 +#define MCAMD_CKSYND_NSYMS 36 + +static uint16_t cksynd[MCAMD_CKSYND_NPATS][MCAMD_CKSYND_NSYMS] = { + /* table column 0x1 */ + { 0xe821, 0x5d31, 0x0001, 0x2021, 0x5041, 0xbe21, 0x4951, 0x74e1, + 0x15c1, 0x3d01, 0x9801, 0xd131, 0xe1d1, 0x6051, 0xa4c1, 0x11c1, + 0x45d1, 0x63e1, 0xb741, 0xdd41, 0x2bd1, 0x83c1, 0x8fd1, 0x4791, + 0x5781, 0xbf41, 0x9391, 0xcce1, 0xa761, 0xff61, 0x5451, 0x6fc1, + 0xbe01, 0x4101, 0xc441, 0x7621 }, + + /* table column 0x2 */ + { 0x7c32, 0xa612, 0x0002, 0x3032, 0xa082, 0xd732, 0x8ea2, 0x9872, + 0x2a42, 0x1602, 0xec02, 0x6212, 0x7262, 0xb0a2, 0xf842, 0x2242, + 0x8a62, 0xb172, 0xd982, 0x6682, 0x3d62, 0xc142, 0xc562, 0x89e2, + 0xa9c2, 0xd582, 0xe1e2, 0x4472, 0xf9b2, 0x55b2, 0xa8a2, 0xb542, + 0xd702, 0x8202, 0x4882, 0x9b32 }, + + /* table column 0x3 */ + { 0x9413, 0xfb23, 0x0003, 0x1013, 0xf0c3, 0x6913, 0xc7f3, 0xec93, + 0x3f83, 0x2b03, 0x7403, 0xb323, 0x93b3, 0xd0f3, 0x5c83, 0x3383, + 0xcfb3, 0xd293, 0x6ec3, 0xbbc3, 0x16b3, 0x4283, 0x4ab3, 0xce73, + 0xfe43, 0x6ac3, 0x7273, 0x8893, 0x5ed3, 0xaad3, 0xfcf3, 0xda83, + 0x6903, 0xc303, 0x8cc3, 0xed13 }, + + /* table column 0x4 */ + { 0xbb44, 0x9584, 0x0004, 0x4044, 0x9054, 0x2144, 0x5394, 0xd6b4, + 0xcef4, 0x8504, 0x6b04, 0x3884, 0xb834, 0x1094, 0xe6f4, 0xc8f4, + 0x5e34, 0x14b4, 0x2254, 0x3554, 0x4f34, 0xa4f4, 0xa934, 0x5264, + 0x92a4, 0x2954, 0x6464, 0xfdb4, 0xe214, 0x7914, 0x9694, 0x19f4, + 0x2104, 0x5804, 0xf654, 0xda44 }, + + /* table column 0x5 */ + { 0x5365, 0xc8b5, 0x0005, 0x6065, 0xc015, 0x9f65, 0x1ac5, 0xa255, + 0xdb35, 0xb805, 0xf305, 0xe9b5, 0x59e5, 0x70c5, 0x4235, 0xd935, + 0x1be5, 0x7755, 0x9515, 0xe815, 0x64e5, 0x2735, 0x26e5, 0x15f5, + 0xc525, 0x9615, 0xf7f5, 0x3155, 0x4575, 0x8675, 0xc2c5, 0x7635, + 0x9f05, 0x1905, 0x3215, 0xac65 }, + + /* table column 0x6 */ + { 0xc776, 0x3396, 0x0006, 0x7076, 0x30d6, 0xf676, 0xdd36, 0x4ec6, + 0xe4b6, 0x9306, 0x8706, 0x5a96, 0xca56, 0xa036, 0x1eb6, 0xeab6, + 0xd456, 0xa5c6, 0xfbd6, 0x53d6, 0x7256, 0x65b6, 0x6c56, 0xdb86, + 0x3b66, 0xfcd6, 0x8586, 0xb9c6, 0x1ba6, 0x2ca6, 0x3e36, 0xacb6, + 0xf606, 0xda06, 0xbed6, 0x4176 }, + + /* table column 0x7 */ + { 0x2f57, 0x6ea7, 0x0007, 0x5057, 0x6097, 0x4857, 0x9467, 0x3a27, + 0xf177, 0xae07, 0x1f07, 0x8ba7, 0x2b87, 0xc067, 0xba77, 0xfb77, + 0x9187, 0xc627, 0x4c97, 0x8e97, 0x5987, 0xe677, 0xe387, 0x9c17, + 0x6ce7, 0x4397, 0x1617, 0x7527, 0xbcc7, 0xd3c7, 0x6a67, 0xc377, + 0x4807, 0x9b07, 0x7a97, 0x3757 }, + + /* table column 0x8 */ + { 0xdd88, 0xeac8, 0x0008, 0x8088, 0xe0a8, 0x3288, 0xa1e8, 0x6bd8, + 0x4758, 0xca08, 0xbd08, 0x1cc8, 0xdc18, 0x20e8, 0x7b58, 0x4c58, + 0xa718, 0x28d8, 0x33a8, 0x1aa8, 0x8518, 0xf858, 0xfe18, 0xa3b8, + 0xe3f8, 0x3ea8, 0xb8b8, 0x56d8, 0x7328, 0x9e28, 0xebe8, 0x2e58, + 0x3208, 0xac08, 0x5ba8, 0x6f88 }, + + /* table column 0x9 */ + { 0x35a9, 0xb7f9, 0x0009, 0xa0a9, 0xb0e9, 0x8ca9, 0xe8b9, 0x1f39, + 0x5299, 0xf709, 0x2509, 0xcdf9, 0x3dc9, 0x40b9, 0xdf99, 0x5d99, + 0xe2c9, 0x4b39, 0x84e9, 0xc7e9, 0xaec9, 0x7b99, 0x71c9, 0xe429, + 0xb479, 0x81e9, 0x2b29, 0x9a39, 0xd449, 0x6149, 0xbfb9, 0x4199, + 0x8c09, 0xed09, 0x9fe9, 0x19a9 }, + + /* table column 0xa */ + { 0xa1ba, 0x4cda, 0x000a, 0xb0ba, 0x402a, 0xe5ba, 0x2f4a, 0xf3aa, + 0x6d1a, 0xdc0a, 0x510a, 0x7eda, 0xae7a, 0x904a, 0x831a, 0x6e1a, + 0x2d7a, 0x99aa, 0xea2a, 0x7c2a, 0xb87a, 0x391a, 0x3b7a, 0x2a5a, + 0x4a3a, 0xeb2a, 0x595a, 0x12aa, 0x8a9a, 0xcb9a, 0x434a, 0x9b1a, + 0xe50a, 0x2e0a, 0x132a, 0xf4ba }, + + /* table column 0xb */ + { 0x499b, 0x11eb, 0x000b, 0x909b, 0x106b, 0x5b9b, 0x661b, 0x874b, + 0x78db, 0xe10b, 0xc90b, 0xafeb, 0x4fab, 0xf01b, 0x27db, 0x7fdb, + 0x68ab, 0xfa4b, 0x5d6b, 0xa16b, 0x93ab, 0xbadb, 0xb4ab, 0x6dcb, + 0x1dbb, 0x546b, 0xcacb, 0xde4b, 0x2dfb, 0x34fb, 0x171b, 0xf4db, + 0x5b0b, 0x6f0b, 0xd76b, 0x829b }, + + /* table column 0xc */ + { 0x66cc, 0x7f4c, 0x000c, 0xc0cc, 0x70fc, 0x13cc, 0xf27c, 0xbd6c, + 0x89ac, 0x4f0c, 0xd60c, 0x244c, 0x642c, 0x307c, 0x9dac, 0x84ac, + 0xf92c, 0x3c6c, 0x11fc, 0x2ffc, 0xca2c, 0x5cac, 0x572c, 0xf1dc, + 0x715c, 0x17fc, 0xdcdc, 0xab6c, 0x913c, 0xe73c, 0x7d7c, 0x37ac, + 0x130c, 0xf40c, 0xadfc, 0xb5cc }, + + /* table column 0xd */ + { 0x8eed, 0x227d, 0x000d, 0xe0ed, 0x20bd, 0xaded, 0xbb2d, 0xc98d, + 0x9c6d, 0x720d, 0x4e0d, 0xf57d, 0x85fd, 0x502d, 0x396d, 0x956d, + 0xbcfd, 0x5f8d, 0xa6bd, 0xf2bd, 0xe1fd, 0xdf6d, 0xd8fd, 0xb64d, + 0x26dd, 0xa8bd, 0x4f4d, 0x678d, 0x365d, 0x185d, 0x292d, 0x586d, + 0xad0d, 0xb50d, 0x69bd, 0xc3ed }, + + /* table column 0xe */ + { 0x1afe, 0xd95e, 0x000e, 0xf0fe, 0xd07e, 0xc4fe, 0x7cde, 0x251e, + 0xa3ee, 0x590e, 0x3a0e, 0x465e, 0x164e, 0x80de, 0x65ee, 0xa6ee, + 0x734e, 0x8d1e, 0xc87e, 0x497e, 0xf74e, 0x9dee, 0x924e, 0x783e, + 0xd89e, 0xc27e, 0x3d3e, 0xef1e, 0x688e, 0xb28e, 0xd5de, 0x82ee, + 0xc40e, 0x760e, 0xe57e, 0x2efe }, + + /* table column 0xf */ + { 0xf2df, 0x846f, 0x000f, 0xd0df, 0x803f, 0x7adf, 0x358f, 0x51ff, + 0xb62f, 0x640f, 0xa20f, 0x976f, 0xf79f, 0xe08f, 0xc12f, 0xb72f, + 0x369f, 0xeeff, 0x7f3f, 0x943f, 0xdc9f, 0x1e2f, 0x1d9f, 0x3faf, + 0x8f1f, 0x7d3f, 0xaeaf, 0x23ff, 0xcfef, 0x4def, 0x818f, 0xed2f, + 0x7a0f, 0x370f, 0x213f, 0x58df } +}; + +int +mcamd_synd_validate(struct mcamd_hdl *hdl, uint32_t synd, int syndtype) +{ + int result; + + switch (syndtype) { + case AMD_SYNDTYPE_ECC: + result = (synd > 0 && synd <= 0xff); + break; + case AMD_SYNDTYPE_CHIPKILL: + result = (synd > 0 && synd <= 0xffff); + break; + default: + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, + "mcamd_synd_validate: invalid syndtype %d\n", syndtype); + return (0); + } + + if (result == 0) + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_synd_validate: " + "invalid %s syndrome 0x%x\n", + syndtype == AMD_SYNDTYPE_ECC ? "64/8" : "ChipKill", + synd); + + return (result); +} + +int +mcamd_eccsynd_decode(struct mcamd_hdl *hdl, uint32_t synd, uint_t *bitp) +{ + char bit; + + if (synd > 0xff) { + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_eccsynd_decode: " + "invalid synd 0x%x\n", synd); + return (0); + } + if ((bit = eccsynd[synd]) == -1) { + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_eccsynd_decode: " + "synd 0x%x is a multi-bit syndrome\n", synd); + return (0); + } + + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_eccsynd_decode: " + "synd 0x%x is single-bit and indicates %s bit %d\n", synd, + bit >= 64 ? "check" : "data", + bit >= 64 ? bit - 64 : bit); + + *bitp = bit; + return (1); +} + +int +mcamd_cksynd_decode(struct mcamd_hdl *hdl, uint32_t synd, uint_t *symp, + uint_t *patp) +{ + int pat = synd & 0xf; + int i; + + if (pat == 0) { + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_cksynd_decode: " + "synd 0x%x is not a correctable syndrome\n", synd); + return (0); + } + + for (i = 0; i < MCAMD_CKSYND_NSYMS; i++) { + if (cksynd[pat - 1][i] == synd) { + *symp = i; + *patp = pat; + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, + "mcamd_cksynd_decode: synd 0x%x is correctable " + "and indicates symbol %d\n", synd, i); + return (1); + } + } + + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_cksynd_decode: " + "synd 0x%x is not a correctable syndrome\n", synd); + return (0); +} + +/* + * symbols 0 to 0xf: data[63:0] + * symbols 0x10 to 0x1f: data[127:64] + * symbols 0x20, 0x21: checkbits for [63:0] + * symbols 0x22, 0x23: checkbits for [127:64] + */ +/*ARGSUSED*/ +int +mcamd_cksym_decode(struct mcamd_hdl *hdl, uint_t sym, int *lowbitp, + int *hibitp, int *data, int *check) +{ + if (sym <= 0xf || sym >= 0x10 && sym <= 0x1f) { + *data = 1; + *check = 0; + *lowbitp = sym * 4; + *hibitp = (sym + 1) * 4 - 1; + } else if (sym >= 0x20 && sym <= 0x23) { + *data = 0; + *check = 1; + *lowbitp = (sym - 0x20) * 4; + *hibitp = (sym + 1 - 0x20) * 4 - 1; + } else { + return (0); + } + + return (1); +} diff --git a/usr/src/common/mc/mc-amd/mcamd_unumtopa.c b/usr/src/common/mc/mc-amd/mcamd_unumtopa.c new file mode 100644 index 0000000000..90c1dcd56f --- /dev/null +++ b/usr/src/common/mc/mc-amd/mcamd_unumtopa.c @@ -0,0 +1,139 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Given a unum including an offset calculate the associated system + * address. This may be different to when the original PA to unum + * calculation took place if interleave etc has changed. + */ + +#include <sys/errno.h> +#include <sys/types.h> +#include <sys/mc.h> + +#include <mcamd_api.h> +#include <mcamd_err.h> + +extern int mc_offset_to_pa(struct mcamd_hdl *, mcamd_node_t *, mcamd_node_t *, + uint64_t, uint64_t *); + +/* + * The submitted unum must have the MC and DIMM numbers and an offset. + * Any cs info it has will not be used - we will reconstruct cs info. + * This is because cs is not in the topology used for diagnosis. + */ +int +mcamd_unumtopa(struct mcamd_hdl *hdl, mcamd_node_t *root, struct mc_unum *unump, + uint64_t *pa) +{ + mcamd_node_t *mc, *dimm; + uint64_t num, hole; + + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: chip %d " + "mc %d dimm %d offset 0x%llx\n", unump->unum_chip, unump->unum_mc, + unump->unum_dimms[0], unump->unum_offset); + + if (!MCAMD_RC_OFFSET_VALID(unump->unum_offset)) { + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "Offset invalid\n"); + return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); + } + + /* + * Search current config for a MC number matching the chip in the + * unum. MC property num is by chip, not MC on chip. + */ + for (mc = mcamd_mc_next(hdl, root, NULL); mc != NULL; + mc = mcamd_mc_next(hdl, root, mc)) { + if (!mcamd_get_numprop(hdl, mc, MCAMD_PROP_NUM, &num) || + !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_HOLE, &hole)) { + mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mcamd_unumtopa: " + "failed to lookup num, dramhole for MC 0x%p\n", mc); + return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); + } + if (num == unump->unum_chip) + break; + } + if (mc == NULL) { + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa; " + "no match for MC %d\n", unump->unum_chip); + return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); + } + + /* + * Search DIMMs of this MC. We can match against the + * first dimm in the unum - if there is more than one they all + * share the same chip-selects anyway and the pa we will resolve + * to is not finer grained than the 128-bits of a dimm pair. + */ + for (dimm = mcamd_dimm_next(hdl, mc, NULL); dimm != NULL; + dimm = mcamd_dimm_next(hdl, mc, dimm)) { + if (!mcamd_get_numprop(hdl, dimm, MCAMD_PROP_NUM, &num)) { + mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mcamd_unumtopa: " + "failed to lookup num for dimm 0xx%p\n", + dimm); + return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); + } + if (num == unump->unum_dimms[0]) + break; + } + if (dimm == NULL) { + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa; " + "no match for dimm %d cs %d on MC %d\n", + unump->unum_dimms[0], unump->unum_cs, unump->unum_chip); + return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); + } + + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: matched " + "mc 0x%p dimm 0x%p; resolving offset 0x%llx\n", + mc, dimm, unump->unum_offset); + + if (mc_offset_to_pa(hdl, mc, dimm, unump->unum_offset, pa) < 0) { + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: " + "mc_offset_to_pa failed: %s\n", mcamd_errmsg(hdl)); + return (-1); /* errno already set */ + } + + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: " + "mc_offset_to_pa succeeded and returned pa=0x%llx: %\n", + *pa); + + /* + * If this MC has a dram address hole just below 4GB then we must + * hoist all address from the hole start upwards by the hole size + */ + if (hole & MC_DC_HOLE_VALID) { + uint64_t hsz = (hole & MC_DC_HOLE_OFFSET_MASK) << + MC_DC_HOLE_OFFSET_LSHIFT; + if (*pa >= 0x100000000 - hsz) + *pa += hsz; + mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_untopa: hoist " + "above dram hole of size 0x%llx to get pa=0x%llx", + hsz, *pa); + } + + return (0); +} diff --git a/usr/src/lib/fm/Makefile b/usr/src/lib/fm/Makefile index 1387d471ce..e291783fd4 100644 --- a/usr/src/lib/fm/Makefile +++ b/usr/src/lib/fm/Makefile @@ -26,9 +26,19 @@ # ident "%Z%%M% %I% %E% SMI" # -sparc_SUBDIRS = libmdesc +include ../Makefile.lib -SUBDIRS = libdiagcode libfmd_adm libfmd_log libfmd_snmp libtopo \ - $($(MACH)_SUBDIRS) +sparc_SUBDIRS = \ + libmdesc + +i386_SUBDIRS = + +SUBDIRS = \ + libdiagcode \ + libfmd_adm \ + libfmd_log \ + libfmd_snmp \ + $($(MACH)_SUBDIRS) \ + topo include ./Makefile.subdirs diff --git a/usr/src/lib/fm/Makefile.lib b/usr/src/lib/fm/Makefile.lib index a0f6c08767..374ed76677 100644 --- a/usr/src/lib/fm/Makefile.lib +++ b/usr/src/lib/fm/Makefile.lib @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -33,4 +33,8 @@ ROOTFMHDRDIR = $(ROOTHDRDIR)/fm ROOTFMHDRS = $(FMHDRS:%=$(ROOTFMHDRDIR)/%) ROOTLIBDIR = $(ROOT)/usr/lib/fm -ROOTLIBDIR64 = $(ROOT)/usr/lib/fm/$(MACH64) +ROOTLIBDIR64 = $(ROOTLIBDIR)/$(MACH64) + +ROOTLIBTOPODIR = $(ROOT)/usr/lib/fm/topo +ROOTLIBTOPODIR64 = $(ROOTLIBTOPODIR)/$(MACH64) + diff --git a/usr/src/lib/fm/Makefile.targ b/usr/src/lib/fm/Makefile.targ index ba83923efb..d12f636b20 100644 --- a/usr/src/lib/fm/Makefile.targ +++ b/usr/src/lib/fm/Makefile.targ @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -34,3 +34,9 @@ $(ROOTFMHDRDIR): $(ROOTFMHDRDIR)/%: common/% $(INS.file) + +$(ROOTLIBTOPODIR): + $(INS.dir) + +$(ROOTLIBTOPODIR64): $(ROOTLIBTOPODIR) + $(INS.dir) diff --git a/usr/src/lib/fm/libtopo/Makefile.com b/usr/src/lib/fm/libtopo/Makefile.com deleted file mode 100644 index e040b41286..0000000000 --- a/usr/src/lib/fm/libtopo/Makefile.com +++ /dev/null @@ -1,72 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -LIBRARY = libtopo.a -VERS = .1 - -LIBSRCS = topo.c topo_enum.c topo_hash.c topo_hcfmri.c topo_hcpath.c \ - topo_mem.c topo_out.c topo_parse.c topo_paths.c topo_pkg.c \ - topo_prop.c topo_traverse.c -OBJECTS = $(LIBSRCS:%.c=%.o) - -include ../../../Makefile.lib -include ../../Makefile.lib - -SRCS = $(LIBSRCS:%.c=../common/%.c) -LIBS = $(DYNLIB) $(LINTLIB) - -SRCDIR = ../common -SPECMAPFILE = $(MAPDIR)/mapfile - -CPPFLAGS += -I../common -I. -CFLAGS += $(CCVERBOSE) -K PIC -CFLAGS64 += $(CCVERBOSE) -K PIC -LDLIBS += -lnvpair -lc - -LINTFLAGS = -msux -LINTFLAGS64 = -msux -Xarch=$(MACH64:sparcv9=v9) - -$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) -$(LINTLIB) := LINTFLAGS = -nsvx -$(LINTLIB) := LINTFLAGS64 = -nsvx -Xarch=$(MACH64:sparcv9=v9) - -.KEEP_STATE: - -all: $(LIBS) - -lint: $(LINTLIB) lintcheck - -pics/%.o: ../$(MACH)/%.c - $(COMPILE.c) -o $@ $< - $(POST_PROCESS_O) - -%.o: ../common/%.c - $(COMPILE.c) -o $@ $< - $(POST_PROCESS_O) - -include ../../../Makefile.targ -include ../../Makefile.targ diff --git a/usr/src/lib/fm/libtopo/common/libtopo.h b/usr/src/lib/fm/libtopo/common/libtopo.h deleted file mode 100644 index 99b8930285..0000000000 --- a/usr/src/lib/fm/libtopo/common/libtopo.h +++ /dev/null @@ -1,309 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _LIBTOPO_H -#define _LIBTOPO_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <libnvpair.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * System Topology Modeling Library generic interfaces - * - * Note: The contents of this file are private to the implementation of the - * Solaris system and FMD subsystem and are subject to change at any time - * without notice. Applications and drivers using these interfaces will fail - * to run on future releases. These interfaces should not be used for any - * purpose until they are publicly documented for use outside of Sun. - * - * Library libtopo is intended as a simple, extensible, library for - * capturing hardware topology information. System topology is - * abstracted in a tree of "topology nodes" or "tnode_t"s. The - * topology tree is constructed by combining static topology - * information from ".topo" files with instance information collected - * by enumerators. An enumerator is software either built-in to or - * loaded by libtopo to search for and enumerate hardware components - * present in the system. Parsing the static information in the - * system's ".topo" files produces a topology tree including many - * possible topologies. Enumerators then refine the topology tree to - * include only those hardware components actually present in the - * system. - */ - -/* - * A topology tree node is an opaque tnode_t. - */ -typedef struct tnode tnode_t; - -/* - * A topology consumer can traverse the entire topology tree. - * Consumers first must acquire a pointer to the root of the tree. - * There are two ways to do this, for example: - * - * root = topo_next_sibling(NULL, NULL); or - * root = topo_next_child(NULL, NULL); - * - * Consumers should call topo_tree_release() with the acquired root - * when the topology tree (including any node properties) is no longer - * needed. - */ -tnode_t *topo_parent(tnode_t *); -tnode_t *topo_next_sibling(tnode_t *, tnode_t *); -tnode_t *topo_next_child(tnode_t *, tnode_t *); - -void topo_tree_release(tnode_t *); - -/* - * Each topo node includes a name, representing a specific type of - * hardware component. The name of a given node may be retrieved via - * this function... - */ -const char *topo_name(tnode_t *); - -/* - * In addition to a name, topo nodes have instance information. Topo - * nodes resulting from parsing .topo files have either specific - * instance numbers or allowed ranges of instance numbers, indicating - * that the hardware components may or may not be present. Consider a - * very simple system that has a motherboard and up to four I/O - * controllers. The .topo file for such a system might look like - * this: - * - * /mb0/io[0-3] - * - * Parsing this .topo file results in a topology tree with two nodes, - * one with a specific instance number and one with an allowed range. - * - * [mb 0] - * | - * | - * [io 0-3] - * - * The topo_get_instance_num() interface retrieves the instance number - * of a topo node. If the instance number for the node is set, the - * instance number is returned. If the instance number for the node - * is not set, the value -1 is returned. The range of allowed - * instances can then be determined with topo_get_instance_range(). - * If this function is called for a node with a set instance number - * the min and max returned will both be -1. - * - * After the .topo file is parsed the "io" enumerator is called to - * refine the tree. The enumerator is provided with a pointer to the - * tnode_t for the io topo node. If, for example, the system in - * question has only two I/O controllers, with instances 1 and 3, the - * enumerator will twice call topo_set_instance_num(). The first time - * it will provide the given tnode_t * and the instance number 1. The - * second time it will provide the given tnode_t * and the instance - * number 3. After the enumerator makes these calls the topology tree - * looks like this: - * - * [mb 0] - * / \ \______ - * / \ \ - * [io 0-3] [io 1] [io 3] - * - * When all enumerators have completed their work, the library makes - * a final pass through the topology tree and eliminates nodes - * without set instance numbers. The final topology tree for our - * example looks like: - * - * [mb 0] - * | \ - * | \ - * [io 1] [io 3] - */ -int topo_get_instance_num(tnode_t *); -void topo_get_instance_range(tnode_t *, int *, int *); -tnode_t *topo_set_instance_num(tnode_t *, int); - -/* - * An enumerator may also instigate expansion of the topology tree - * from a given node. A call to topo_load() forces the library to - * look for a .topo file to parse with the given basename, and if it - * finds one, parses it and adds topology nodes as children to the - * node given as the second argument. - */ -tnode_t *topo_load(const char *, tnode_t *); - - -/* - * The libtopo library allows named properties to be attached to a - * topo node. A property is simply a string. Libtopo does not - * interpret property values in any way, it merely maintains the - * association between the property and the node. Properties are - * established via topo_set_prop(). A specific property's string - * value may be obtained with topo_get_prop(). A consumer may iterate - * through the properties attached to a node in the following manner: - * - * const char *propn = NULL; - * - * while ((propn = topo_next_prop(topo_node, propn)) != NULL) - * printf("%s=%s", propn, topo_get_prop(topo_node, propn)); - */ -const char *topo_get_prop(tnode_t *, const char *); -const char *topo_next_prop(tnode_t *, const char *); -int topo_set_prop(tnode_t *, const char *, const char *); - -/* - * For quick lookups, libtopo indexes all properties set on all topo - * nodes. The topo_find_propval() interface may be used to iterate - * through all ALL topo nodes having a property that matches both the - * requested name and requested value. The initial call can be made - * from any topo node (the first argument must be a valid non-NULL - * tnode_t pointer anywhere in the current topology tree) and 'more' - * should point to a NULL value. Multiple matches can be found by - * making successive calls to the function, sending the 'more' cookie - * back to the function untouched. The function returns a pointer to - * the matching node or NULL if no further matches exist in the - * topology tree. - */ -tnode_t *topo_find_propval(tnode_t *, const char *, const char *, - void **); - -/* - * The entire topology tree can be visited with a callback to a - * consumer function using topo_walk(). The second argument is a flag - * specifying whether to visit a node before or after its children. - */ -#define TOPO_VISIT_SELF_FIRST 1 -#define TOPO_VISIT_CHILDREN_FIRST 2 - -void topo_walk(tnode_t *, int, void *, void (*cb)(tnode_t *, void *)); - -/* - * A topology node can be represented both as a path and an FMRI. - * The topo_hc_path() and topo_hc_fmri() functions provide a path to - * or FMRI describing, respectively, the specified node. The - * topo_hc_path() function allocates space, the caller should use - * topo_free_path() to de-allocate that space when it's finished with - * the path. The topo_hc_fmri() function allocates an nvlist. The - * caller should use topo_free_fmri() to de-allocate this space when - * its finished with the FMRI. - * - * A consumer may also use topo_find_path() to search for the - * topology node corresponding to a provided hc path. The first - * argument must be a valid non-NULL tnode_t pointer anywhere in the - * current topology tree. - */ -char *topo_hc_path(tnode_t *); -nvlist_t *topo_hc_fmri(tnode_t *); - -tnode_t *topo_find_path(tnode_t *, char *); - -void topo_free_path(char *); -void topo_free_fmri(nvlist_t *); - -/* - * The topo_init() function must be called once by a consumer to - * initialize the topology library. This routine must be called - * prior to attempting to access any topo nodes. A set of paths to - * be searched for .topo files may optionally be provided (the first - * argument is the number of paths provided, the second argument is - * an array of path strings). If no paths are provided, the library - * by default searches first in /usr/lib/fm/topo/`uname -i`, and - * second in /usr/lib/fm/topo. - * - * The topo_fini() function should be called when libtopo functions - * are no longer needed and all topology trees have been released. The - * topo_reset() function resets all enumerators but leaves other libtopo - * state (such as memory and out methods) unscathed. The topo_reset() - * function can be used to ensure an ensuing topology snapshot is not - * created from any cached enumerator state. - */ -void topo_init(int, const char **); -void topo_fini(void); -void topo_reset(void); - -/* - * The topo library does not presume it may write to the stdout or - * stderr of its consumer. Instead, error and debugging messages - * from the library are buffered. - * - * Debugging output from libtopo may be enabled/disabled by calling - * these functions. The flags argument is reserved for future use and - * should always be zero. This output is disabled by default. An output - * method must be established to display or otherwise capture the - * output. See topo_set_out_method() below. - */ -void topo_debug_on(uint_t flags); -void topo_debug_off(void); - -/* - * Retrieve the current line in the message buffer. - */ -const char *topo_errbuf(void); - -/* - * Flags to control writes to the message buffer (via - * topo_out()). One or more flags may be bitwise ORd together. - * Writes with TOPO_DEBUG set will only make it to the buffer (and - * further captured via the output method) if topo_debug_on() has been - * called. - */ -#define TOPO_ERR 0x1 -#define TOPO_DEBUG 0x2 - -/* - * Write data to the message buffer. The first argument is a flag - * that determines what calls succeed in getting data into the buffer. - */ -void topo_out(int flag, char *format, ...); - -/* - * Interface manipulation - * Allow override of defaults for: - * - * no-fail, zeroed memory allocator/de-allocator (topo_set_mem_methods) - * - * Function for displaying or otherwise capturing the contents of the - * message buffer. (topo_set_out_method) - */ -void topo_set_mem_methods(void * (*zallocfn)(size_t), void (*freefn)(void *)); -void topo_set_out_method(void (*outfn)(const char *)); - -/* - * Given the name of a driver, topo can search out module information - * and create a 'mod' scheme FMRI representing the driver as - * an ASRU. As part of determining this FMRI's contents, the FRU FMRI - * for the driver is also determined, and will be returned in the frup - * argument if it is non-NULL. - * - * Use topo_free_fmri() to de-allocate the space assigned to FMRIs - * retrieved using these functions. No topology node is necessary to - * obtain this information. - */ -nvlist_t *topo_driver_asru(const char *, nvlist_t **frup); - -#ifdef __cplusplus -} -#endif - -#endif /* _LIBTOPO_H */ diff --git a/usr/src/lib/fm/libtopo/common/libtopo_enum.h b/usr/src/lib/fm/libtopo/common/libtopo_enum.h deleted file mode 100644 index bd83ea7961..0000000000 --- a/usr/src/lib/fm/libtopo/common/libtopo_enum.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _LIBTOPO_ENUM_H -#define _LIBTOPO_ENUM_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <fm/libtopo.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * System Topology Modeling Library Enumerator interfaces - * - * Note: The contents of this file are private to the implementation of the - * Solaris system and FMD subsystem and are subject to change at any time - * without notice. Applications and drivers using these interfaces will fail - * to run on future releases. These interfaces should not be used for any - * purpose until they are publicly documented for use outside of Sun. - * - * Library libtopo is intended as a simple, extensible, library for - * capturing hardware topology information. System topology is - * abstracted in a tree of "topology nodes" or "tnode_t"s. The - * topology tree is constructed by combining static topology - * information from ".topo" files with instance information collected - * by enumerators. This include file contains definitions - * specifically for use by these enumerators. - */ - -/* - * Standard properties placed on enumerated components - */ -#define PLATASRU "PLAT-ASRU" -#define PLATFRU "PLAT-FRU" - -#define ATTACHP "ATTACHMENT-POINT" -#define ATTACHD "DRIVER-ATTACHED" -#define DEVTYPE "DEVTYPE" -#define DRIVER "DRIVER" -#define LABEL "LABEL" -#define SCAN "SCAN" -#define DEV "DEV" -#define PKG "PKG" -#define ON "ON" - -#define TPROP_FALSE "false" -#define TPROP_TRUE "true" - -/* - * The structure below describes an enumerator. Enumerators are - * chunks of code either built-in to or loaded by the library to - * search for and enumerate items in the hardware topology. They - * currently have just three entry points, initialize and finish entry - * points te_init() and te_fini() and then the actual enumeration - * function te_enum(). The te_init() routine will be called exactly - * once, the first time that libtopo needs to use the enumerator. If - * initialization of the enumerator fails, the te_init() function - * should return a value of TE_INITFAIL, else it should return - * TE_INITOK. The te_fini() routine will also be called exactly once, - * when libtopo shuts down. The te_enum() routine may be called - * multiple times to request enumeration at various points in the - * topology. - * - * An enumerator is required to have an _enum_init() function that - * libtopo will call when the enumerator is initially loaded. The - * function is expected to return a pointer to a struct tenumr. - */ - -#define TE_INITOK 0 -#define TE_INITFAIL 1 - -struct tenumr { - /* - * te_private should be initialized to NULL by a registering - * enumerator and not manipulated by the enumerator in any - * other manner. - */ - void *te_private; - int (*te_init)(void); - void (*te_fini)(void); - void (*te_enum)(tnode_t *); -}; - -#ifdef __cplusplus -} -#endif - -#endif /* _LIBTOPO_ENUM_H */ diff --git a/usr/src/lib/fm/libtopo/common/topo.c b/usr/src/lib/fm/libtopo/common/topo.c deleted file mode 100644 index a24a685caa..0000000000 --- a/usr/src/lib/fm/libtopo/common/topo.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - * - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <sys/param.h> -#include <sys/systeminfo.h> -#include <sys/types.h> -#include <fm/libtopo.h> -#include "topo_impl.h" - -/*ARGSUSED*/ -void -tnode_print(tnode_t *node, void *ignore) -{ - const char *propn, *propv; - int inum, min, max; - - topo_indent(); - topo_out(TOPO_DEBUG, "%s ", topo_name(node)); - if ((inum = topo_get_instance_num(node)) >= 0) { - topo_out(TOPO_DEBUG, "(%d)", inum); - } else { - topo_get_instance_range(node, &min, &max); - topo_out(TOPO_DEBUG, "(%d - %d)", min, max); - } - topo_out(TOPO_DEBUG, " [%p]\n", (void *)node); - - propn = NULL; - while ((propn = topo_next_prop(node, propn)) != NULL) { - propv = topo_get_prop(node, propn); - topo_indent(); - topo_out(TOPO_DEBUG, " %s = %s\n", propn, propv); - } -} - -tnode_t * -tnode_add_child(tnode_t *node, tnode_t *child) -{ - struct tnode_list *newchild; - struct tnode_list *lc = NULL; - struct tnode_list *wc; - - for (wc = node->children; wc != NULL; wc = wc->next) - lc = wc; - - newchild = topo_zalloc(sizeof (struct tnode_list)); - newchild->tnode = child; - - if (lc == NULL) - node->children = newchild; - else - lc->next = newchild; - - child->parent = node; - child->root = node->root; - return (child); -} - -void -tnode_destroy(tnode_t *node) -{ - struct tnode_list *dc, *nc; - - topo_free((void *)node->name); - node->parent = NULL; - - dc = node->children; - while (dc != NULL) { - tnode_destroy(dc->tnode); - nc = dc->next; - topo_free(dc); - dc = nc; - } - node->children = NULL; - - tprop_hash_destroy(node->props); - node->props = NULL; - - topo_free(node); -} - -struct tnode_list * -tnode_del_child(tnode_t *node, tnode_t *child) -{ - struct tnode_list *lc = NULL; - struct tnode_list *dc; - - if (node == NULL) - return (NULL); - - for (dc = node->children; dc != NULL; dc = dc->next) { - if (dc->tnode == child) - break; - lc = dc; - } - - /* XXX this should actually be an assert */ - if (dc == NULL) { - topo_out(TOPO_INFO, "topo_del_child: "); - topo_out(TOPO_INFO, "Deleting a child that doesn't exist?\n"); - return (NULL); - } - - if (lc == NULL) - node->children = dc->next; - else - lc->next = dc->next; - - return (dc); -} - -tnode_t * -tnode_dup(tnode_t *src) -{ - const char *propn; - tnode_t *tmpc; - tnode_t *new; - tnode_t *nc; - - new = topo_zalloc(sizeof (tnode_t)); - new->name = topo_strdup(src->name); - new->state = src->state; - new->u.range.min = src->u.range.min; - new->u.range.max = src->u.range.max; - - tmpc = NULL; - while ((tmpc = topo_next_child(src, tmpc)) != NULL) { - nc = tnode_dup(tmpc); - (void) tnode_add_child(new, nc); - } - - propn = NULL; - while ((propn = topo_next_prop(src, propn)) != NULL) - (void) topo_set_prop(new, propn, topo_get_prop(src, propn)); - - return (new); -} - -uint_t -tnode_depth(tnode_t *node) -{ - if (node == NULL || node->state == TOPO_ROOT) - return (0); - else - return (1 + tnode_depth(topo_parent(node))); -} - -const char * -topo_name(tnode_t *node) -{ - return (node->name); -} - -tnode_t * -topo_getroot(tnode_t *node) -{ - return (node->root); -} - -tnode_t * -topo_create(tnode_t *parent, const char *nodename) -{ - tnode_t *new; - - new = topo_zalloc(sizeof (tnode_t)); - new->name = topo_strdup(nodename); - new->state = TOPO_LIMBO; - - if (parent == NULL) { - new->state = TOPO_ROOT; - new->root = new; - return (new); - } - - return (tnode_add_child(parent, new)); -} diff --git a/usr/src/lib/fm/libtopo/common/topo_enum.c b/usr/src/lib/fm/libtopo/common/topo_enum.c deleted file mode 100644 index a5e80cc1ed..0000000000 --- a/usr/src/lib/fm/libtopo/common/topo_enum.c +++ /dev/null @@ -1,329 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <dlfcn.h> -#include <alloca.h> -#include <sys/param.h> -#include <sys/types.h> -#include <sys/systeminfo.h> -#include "topo_impl.h" -#include "topo_enum.h" - -struct trim_data { - int valid; - struct tnode_list *children; - struct tnode_list *self; -}; - -static void -trim(tnode_t *node, void *arg) -{ - struct trim_data *td; - - td = arg; - if (td->valid == 1) { - td->self->tnode->children = td->children; - tnode_destroy(td->self->tnode); - topo_free(td->self); - td->valid = 0; - return; - } - - if (node->state == TOPO_LIMBO || node->state == TOPO_RANGE) { - td->valid = 1; - td->self = tnode_del_child(topo_parent(node), node); - td->children = td->self->tnode->children; - td->self->tnode->children = NULL; - } -} - -struct tenumr *topo_enumr_hash_lookup(const char *); -struct tenumr *topo_load_enumerator(const char *); - -static int -enumr_ready(struct tenumr *e) -{ - struct tenumr_prvt_data *pd; - - if (e == NULL || e->te_enum == NULL) - return (0); - - pd = (struct tenumr_prvt_data *)e->te_private; - return (pd->status & ENUMR_INITD); -} - -/*ARGSUSED*/ -static void -enum_all(tnode_t *start, void *arg) -{ - struct tenumr *enumr; - const char *enumrnm; - tnode_t *parent; - int inum, min, max; - - topo_out(TOPO_DEBUG, "enumall: "); - topo_out(TOPO_DEBUG, "Enumerating %s ", topo_name(start)); - if ((inum = topo_get_instance_num(start)) >= 0) { - topo_out(TOPO_DEBUG, "(%d)", inum); - } else { - topo_get_instance_range(start, &min, &max); - topo_out(TOPO_DEBUG, "(%d - %d)", min, max); - } - topo_out(TOPO_DEBUG, " [%p], ", (void *)start); - - if ((parent = topo_parent(start)) == NULL) { - topo_out(TOPO_DEBUG, "\n"); - } else { - topo_out(TOPO_DEBUG, "Child of %s ", topo_name(parent)); - if ((inum = topo_get_instance_num(parent)) >= 0) { - topo_out(TOPO_DEBUG, "(%d)", inum); - } else { - topo_get_instance_range(parent, &min, &max); - topo_out(TOPO_DEBUG, "(%d - %d)", min, max); - } - topo_out(TOPO_DEBUG, "[%p]\n", (void *)parent); - } - - if (start->state == TOPO_LIMBO || start->state == TOPO_INST) - return; - - /* - * Have a range and need to get the actual instances. - * Determine the name of the enumerator and if we have the - * enumerator already loaded. - */ - if ((enumrnm = tealias_find(start)) == NULL) - enumrnm = topo_name(start); - - if ((enumr = topo_enumr_hash_lookup(enumrnm)) == NULL) - enumr = topo_load_enumerator(enumrnm); - - if (enumr_ready(enumr)) - enumr->te_enum(start); -} - -void -topo_enum(tnode_t *root) -{ - struct trim_data td; - - td.valid = 0; - td.children = td.self = NULL; - - topo_walk(root, TOPO_VISIT_SELF_FIRST, NULL, enum_all); - topo_walk(root, - TOPO_DESTRUCTIVE_WALK | TOPO_VISIT_SELF_FIRST | TOPO_REVISIT_SELF, - &td, trim); -} - -#define ENUMR_HASHLEN 101 -static struct tenumr_hash Enumerators; - -void -topo_enumr_hash_create(void) -{ - Enumerators.te_hashlen = ENUMR_HASHLEN; - Enumerators.te_hash = topo_zalloc(Enumerators.te_hashlen * - sizeof (struct tenumr_hashent)); -} - -void -topo_enumr_hash_destroy(int destroy_tes) -{ - struct tenumr_prvt_data *pd; - struct tenumr_hashent *entry, *next; - int idx; - - for (idx = 0; idx < Enumerators.te_hashlen; idx++) { - entry = Enumerators.te_hash[idx]; - while (entry != NULL) { - topo_out(TOPO_HASH, - "Destroy hash bucket %d entry for %s.", - idx, - entry->te_nodetype); - pd = (struct tenumr_prvt_data *)entry->te->te_private; - - topo_out(TOPO_HASH, " Status is %x.\n", pd->status); - if (pd->status & ENUMR_INITD) { - pd->status &= ~ENUMR_INITD; - if (entry->te->te_fini) - entry->te->te_fini(); - } - if (destroy_tes) { - void *dlp = pd->hdl; - uint_t status = pd->status; - - topo_free(pd); - entry->te->te_private = NULL; - if (dlp != NULL) - topo_dlclose(dlp); - if (status & (ENUMR_NOTFOUND|ENUMR_BAD)) - topo_free(entry->te); - } - next = entry->te_next; - topo_free((void *)entry->te_nodetype); - topo_free(entry); - entry = next; - } - } - topo_free(Enumerators.te_hash); -} - -void -topo_enumr_hash_insert(const char *key, struct tenumr *enumr) -{ - struct tenumr_prvt_data *pd; - struct tenumr_hashent *new; - int idx = topo_strhash(key) % ENUMR_HASHLEN; - int initfail = TE_INITOK; - - Enumerators.te_nelems++; - - new = topo_zalloc(sizeof (struct tenumr_hashent)); - new->te_nodetype = key; - new->te = enumr; - - pd = (struct tenumr_prvt_data *)new->te->te_private; - if (!(pd->status & ENUMR_INITD)) { - if (new->te->te_init) - initfail = new->te->te_init(); - } - - if (initfail != TE_INITOK) { - topo_out(TOPO_ERR, "Enumerator for %s failed to initialize.\n", - key); - pd->status |= ENUMR_INITFAIL; - } else { - pd->status |= ENUMR_INITD; - } - - topo_out(TOPO_HASH, "Insert [key=%s] into Enumerator bucket %d ", - key, idx); - - if (Enumerators.te_hash[idx] == NULL) { - Enumerators.te_hash[idx] = new; - topo_out(TOPO_HASH, ", first enumerator in bucket.\n"); - } else { - new->te_next = Enumerators.te_hash[idx]; - Enumerators.te_hash[idx] = new; - topo_out(TOPO_HASH, "\n"); - } -} - -struct tenumr * -topo_enumr_hash_lookup(const char *nodetype) -{ - struct tenumr_hashent *hent; - int idx = topo_strhash(nodetype) % ENUMR_HASHLEN; - - topo_out(TOPO_HASH, "Searching [key=%s] in Enumerator bucket %d ", - nodetype, idx); - hent = Enumerators.te_hash[idx]; - while (hent != NULL) { - if (strcmp(nodetype, hent->te_nodetype) == 0) { - topo_out(TOPO_HASH, "found\n"); - break; - } - topo_out(TOPO_HASH, "%s!=%s\n", nodetype, hent->te_nodetype); - hent = hent->te_next; - } - if (hent) - return (hent->te); - return (NULL); -} - -/*ARGSUSED*/ -struct tenumr * -topo_load_enumerator(const char *nodetype) -{ - struct tenumr_prvt_data *newenumr; - struct tenumr *ret, *eret; - char *tmpname = alloca(MAXPATHLEN); - void *dlp; - - newenumr = topo_zalloc(sizeof (struct tenumr_prvt_data)); - ret = topo_zalloc(sizeof (struct tenumr)); - - (void) snprintf(tmpname, MAXPATHLEN, "%s.so", nodetype); - if ((dlp = topo_dlopen(tmpname)) == NULL) { - /* - * create a negative hash entry to keep us from - * looking for the same .so's every time - */ - newenumr->status |= ENUMR_NOTFOUND; - goto eloaded; - } - - newenumr->einit = (struct tenumr *(*)())dlsym(dlp, "_enum_init"); - - if (newenumr->einit == NULL) { - topo_out(TOPO_ERR, "%s missing _enum_init()\n", tmpname); - goto einitbad; - } - - if ((eret = newenumr->einit()) == NULL) { - topo_out(TOPO_ERR, "%s _enum_init() returned NULL\n", tmpname); - goto einitbad; - } - - if (eret->te_enum == NULL) { - topo_out(TOPO_ERR, "%s has NULL te_enum()\n", tmpname); - goto einitbad; - } - - newenumr->hdl = dlp; - topo_free(ret); - ret = eret; - goto eloaded; - -einitbad: - newenumr->status |= ENUMR_BAD; - topo_dlclose(dlp); - -eloaded: - ret->te_private = (void *)newenumr; - topo_enumr_hash_insert(topo_strdup(nodetype), ret); - return (ret); -} - -void -topo_enum_init(void) -{ - topo_enumr_hash_create(); -} - -void -topo_enum_fini(void) -{ - topo_enumr_hash_destroy(1); -} diff --git a/usr/src/lib/fm/libtopo/common/topo_enum.h b/usr/src/lib/fm/libtopo/common/topo_enum.h deleted file mode 100644 index f2cdc15b25..0000000000 --- a/usr/src/lib/fm/libtopo/common/topo_enum.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _TOPO_ENUM_H -#define _TOPO_ENUM_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <fm/libtopo_enum.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * The structures below describe hashes of enumerators. Enumerators - * are chunks of code either built-in to or loaded by the library to - * search for and enumerate items in the hardware topology. They - * currently have just three entry points, initialize and finish entry - * points te_init() and te_fini() and then the actual enumeration - * function te_enum(). The te_init() routine will be called exactly - * once, the first time that libtopo needs to use the enumerator. If - * initialization of the enumerator fails, the te_init() function - * should return a value of TE_INITFAIL, else it should return - * TE_INITOK. The te_fini() routine will also be called exactly once, - * called exactly once, the first time that libtopo needs to use the - * enumerator. The te_fini() routine will also be called exactly - * once, when libtopo shuts down. The te_enum() routine may be called - * multiple times to enumerate items at various points in the - * topology. - */ - -struct tenumr_hashent { - const char *te_nodetype; - struct tenumr *te; - struct tenumr_hashent *te_next; -}; - -struct tenumr_hash { - struct tenumr_hashent **te_hash; /* hash bucket array */ - uint_t te_hashlen; /* size of hash bucket array */ - uint_t te_nelems; /* # of nodes in the hash */ -}; - -/* - * Enumerator status, stashed in the status field of the - * tenumr_prvt_data structure - */ -#define ENUMR_INITD 0x1 -#define ENUMR_NOTFOUND 0x2 -#define ENUMR_BAD 0x4 -#define ENUMR_INITFAIL 0x8 - -struct tenumr_prvt_data { - struct tenumr *(*einit)(void); - uint_t status; - void *hdl; -}; - -/* - * The enumeration subsystem has its own bookkeeping to do, accomplished - * in its own init() and fini() routines, prototyped below. - */ -void topo_enum_init(void); -void topo_enum_fini(void); - -#ifdef __cplusplus -} -#endif - -#endif /* _TOPO_ENUM_H */ diff --git a/usr/src/lib/fm/libtopo/common/topo_hash.c b/usr/src/lib/fm/libtopo/common/topo_hash.c deleted file mode 100644 index adfeb5a6a2..0000000000 --- a/usr/src/lib/fm/libtopo/common/topo_hash.c +++ /dev/null @@ -1,375 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/types.h> -#include <string.h> -#include "libtopo.h" -#include "topo_impl.h" - -ulong_t -topo_strhash(const char *key) -{ - ulong_t g, h = 0; - const char *p; - - for (p = key; *p != '\0'; p++) { - h = (h << 4) + *p; - - if ((g = (h & 0xf0000000)) != 0) { - h ^= (g >> 24); - h ^= g; - } - } - - return (h); -} - -#define REC_HASHLEN 101 - -struct tprop * -tprop_create(const char *name, const char *val) -{ - struct tprop *newp; - - newp = topo_zalloc(sizeof (struct tprop)); - newp->p_name = topo_strdup(name); - newp->p_val = topo_strdup(val); - return (newp); -} - -void -tprop_destroy(struct tprop *p) -{ - topo_free((void *)p->p_name); - topo_free((void *)p->p_val); - topo_free(p); -} - -struct tprop_hash * -tprop_hash_create(void) -{ - struct tprop_hash *r = topo_zalloc(sizeof (struct tprop_hash)); - - r->tp_hashlen = REC_HASHLEN; - r->tp_hash = topo_zalloc(r->tp_hashlen * sizeof (struct tprop *)); - return (r); -} - -void -tprop_hash_destroy(struct tprop_hash *ht) -{ - struct tprop *d, *n; - int idx; - - if (ht == NULL) - return; - - for (idx = 0; idx < ht->tp_hashlen; idx++) { - for (d = ht->tp_hash[idx]; d != NULL; ) { - n = d->p_next; - tprop_destroy(d); - d = n; - } - } - - topo_free(ht->tp_hash); - topo_free(ht); -} - -void -tprop_hash_insert(struct tprop_hash *tab, const char *key, struct tprop *new) -{ - int idx = topo_strhash(key) % tab->tp_hashlen; - - tab->tp_nelems++; - topo_out(TOPO_HASH, "Insert [key=%s] into %p, bucket %d ", - key, (void *)tab, idx); - if (tab->tp_hash[idx] == NULL) { - tab->tp_hash[idx] = new; - topo_out(TOPO_HASH, "first entry.\n"); - } else { - new->p_next = tab->tp_hash[idx]; - tab->tp_hash[idx] = new; - topo_out(TOPO_HASH, "\n"); - } -} - -struct tprop * -tprop_hash_lookup(struct tprop_hash *tab, const char *key) -{ - int idx = topo_strhash(key) % tab->tp_hashlen; - - return (tab->tp_hash[idx]); -} - -struct tprop * -tprop_hash_lookup_next(struct tprop_hash *tab, const char *prevkey, - struct tprop *prevprop) -{ - int idx = 0; - - if (prevprop != NULL && prevprop->p_next != NULL) - return (prevprop->p_next); - - if (prevkey != NULL) { - idx = topo_strhash(prevkey) % tab->tp_hashlen; - idx++; - } - - while (tab->tp_hash[idx] == NULL && idx < tab->tp_hashlen) - idx++; - - if (idx >= tab->tp_hashlen) - return (NULL); - else - return (tab->tp_hash[idx]); -} - -struct tnode_hashent * -tnode_hashent_create(struct tnode *node) -{ - struct tnode_hashent *r = topo_zalloc(sizeof (struct tnode_hashent)); - r->e_node = node; - return (r); -} - -void -tnode_hashent_destroy(struct tnode_hashent *e) -{ - topo_free(e); -} - -struct tnode_hash * -tnode_hash_create(void) -{ - struct tnode_hash *r = topo_zalloc(sizeof (struct tnode_hash)); - - r->tn_hashlen = REC_HASHLEN; - r->tn_hash = topo_zalloc(r->tn_hashlen * sizeof (struct tnode *)); - return (r); -} - -void -tnode_hash_destroy(struct tnode_hash *ht) -{ - struct tnode_hashent *d, *n; - int idx; - - if (ht == NULL) - return; - - for (idx = 0; idx < ht->tn_hashlen; idx++) { - for (d = ht->tn_hash[idx]; d != NULL; ) { - n = d->e_next; - tnode_hashent_destroy(d); - d = n; - } - } - - topo_free(ht->tn_hash); - topo_free(ht); -} - -void -tnode_hash_insert(struct tnode_hash *tab, const char *key, struct tnode *new) -{ - struct tnode_hashent *newent; - int idx = topo_strhash(key) % tab->tn_hashlen; - - newent = tnode_hashent_create(new); - - tab->tn_nelems++; - topo_out(TOPO_HASH, "Insert [key=%s] into %p, bucket %d ", - key, (void *)tab, idx); - if (tab->tn_hash[idx] == NULL) { - tab->tn_hash[idx] = newent; - topo_out(TOPO_HASH, "first entry.\n"); - } else { - newent->e_next = tab->tn_hash[idx]; - tab->tn_hash[idx] = newent; - topo_out(TOPO_HASH, "\n"); - } -} - -struct tnode_hashent * -tnode_hash_lookup(struct tnode_hash *tab, const char *key) -{ - int idx = topo_strhash(key) % tab->tn_hashlen; - - topo_out(TOPO_HASH, "Lookup [key=%s] in %p falls into bucket %d\n", - key, (void *)tab, idx); - return (tab->tn_hash[idx]); -} - -static struct t_extend * -get_extend(struct tnode *node) -{ - struct tnode *rn; - - if ((rn = node->root) == NULL) - return (NULL); - - if (rn->extend == NULL) - rn->extend = topo_zalloc(sizeof (struct t_extend)); - - return (rn->extend); -} - -void -tprop_index(struct tnode *node, const char *propname) -{ - struct tnode_hash *ht; - struct t_extend *re; - - /* - * We keep an index of what nodes have what properties on the - * root node - */ - if ((re = get_extend(node)) == NULL) - return; - - if ((ht = re->te_index) == NULL) { - ht = tnode_hash_create(); - re->te_index = ht; - topo_out(TOPO_HASH, "props index table is %p\n", (void *)ht); - } - tnode_hash_insert(ht, propname, node); -} - -static struct tnode * -next_nv_match(const char *name, const char *val, void **more) -{ - struct tnode_hashent *e; - struct tnode *n; - const char *pv; - - for (;;) { - if ((e = *more) == NULL) - return (NULL); - n = e->e_node; - *more = e->e_next; - pv = topo_get_prop(n, name); - if (pv == NULL) - continue; - if (strcmp(pv, val) == 0) - return (n); - } - /*NOTREACHED*/ -} - -struct tnode * -topo_find_propval(struct tnode *node, const char *name, const char *value, - void **more) -{ - struct tnode *r; - - if (more == NULL || *more == (void *)1) - return (NULL); - - if (*more == NULL) { - struct tnode_hash *ht; - struct t_extend *re; - - /* - * We keep an index of what nodes have what properties - * on the root node - */ - if ((re = get_extend(node)) == NULL) - return (NULL); - - if ((ht = re->te_index) == NULL) - return (NULL); - - *more = tnode_hash_lookup(ht, name); - } - - r = next_nv_match(name, value, more); - if (*more == NULL) - *more = (void *)1; - return (r); -} - -void -tealias_add(tnode_t *node, char *shared_enumr) -{ - struct tenum_alias *a, *na; - struct tenum_alias *pa = NULL; - struct t_extend *re; - - /* - * We keep an index of what node types have enumerator aliases - * on the root node - */ - if ((re = get_extend(node)) == NULL) - return; - - a = re->te_aliases; - while (a != NULL) { - if (strcmp(a->tea_type, topo_name(node)) == 0) { - /* found an alias, so just replace it */ - topo_free(a->tea_share); - a->tea_share = shared_enumr; - return; - } - pa = a; - a = a->tea_next; - } - na = topo_zalloc(sizeof (struct tenum_alias)); - na->tea_type = topo_name(node); - na->tea_share = shared_enumr; - if (pa == NULL) - re->te_aliases = na; - else - pa->tea_next = na; -} - -const char * -tealias_find(struct tnode *node) -{ - struct tenum_alias *a; - struct t_extend *re; - - /* - * We keep an index of what node types have enumerator aliases - * on the root node - */ - if ((re = get_extend(node)) == NULL) - return (NULL); - - a = re->te_aliases; - while (a != NULL) { - if (strcmp(a->tea_type, topo_name(node)) == 0) { - /* found an alias, so return it */ - topo_out(TOPO_DEBUG, "for %s use %s.so\n", - a->tea_type, a->tea_share); - return (a->tea_share); - } - a = a->tea_next; - } - return (NULL); -} diff --git a/usr/src/lib/fm/libtopo/common/topo_hcfmri.c b/usr/src/lib/fm/libtopo/common/topo_hcfmri.c deleted file mode 100644 index 471e54476e..0000000000 --- a/usr/src/lib/fm/libtopo/common/topo_hcfmri.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - * - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <libnvpair.h> -#include <sys/param.h> -#include <sys/types.h> -#include <sys/systeminfo.h> -#include <sys/fm/protocol.h> -#include "topo_impl.h" -#include "libtopo.h" - -static char instbuf[MAXINSTLEN]; - -nvlist_t * -build_fmri(tnode_t *n, nvlist_t **nvl, uint_t sz, uint_t idx) -{ - nvlist_t *f = NULL; - nvlist_t *p = NULL; - int e; - - if (n == NULL || n->state == TOPO_ROOT) { - errno = nvlist_xalloc(&f, NV_UNIQUE_NAME, &Topo_nv_alloc_hdl); - if (errno != 0) { - topo_out(TOPO_ERR, "alloc of big nvl failed:"); - return (NULL); - } - e = nvlist_add_string(f, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC); - e |= nvlist_add_uint8(f, FM_VERSION, FM_HC_SCHEME_VERSION); - e |= nvlist_add_string(f, FM_FMRI_HC_ROOT, ""); - e |= nvlist_add_uint32(f, FM_FMRI_HC_LIST_SZ, sz); - e |= nvlist_add_nvlist_array(f, FM_FMRI_HC_LIST, nvl, sz); - if (e == 0) - return (f); - topo_out(TOPO_ERR, "construct of big nvl failed:"); - nvlist_free(f); - return (NULL); - } - - if (n->state != TOPO_INST) - return (NULL); - - idx--; - (void) snprintf(instbuf, MAXINSTLEN, "%d", n->u.inst); - - errno = nvlist_xalloc(&p, NV_UNIQUE_NAME, &Topo_nv_alloc_hdl); - if (errno != 0) { - topo_out(TOPO_ERR, "alloc of an hc-pair failed:"); - return (NULL); - } - e = nvlist_add_string(p, FM_FMRI_HC_NAME, topo_name(n)); - e |= nvlist_add_string(p, FM_FMRI_HC_ID, instbuf); - if (e != 0) { - topo_out(TOPO_ERR, "construct of hc-pair failed:"); - nvlist_free(p); - return (NULL); - } - nvl[idx] = p; - return (build_fmri(topo_parent(n), nvl, sz, idx)); -} - -nvlist_t * -topo_hc_fmri(tnode_t *tothisnode) -{ - const char *nam, *val; - nvlist_t **nvl = NULL; - nvlist_t *r; - uint_t sz; - - sz = tnode_depth(tothisnode); - if (sz < 1) - return (NULL); - - /* - * The final fmri will contain sz nvlists, each list having - * an hc-name, hc-id pair. - */ - nvl = topo_zalloc(sz * sizeof (nvlist_t *)); - - if ((r = build_fmri(tothisnode, nvl, sz, sz)) == NULL) - goto out; - - /* now add the properties */ - nam = NULL; - errno = 0; - while ((nam = topo_next_prop(tothisnode, nam)) != NULL) { - val = topo_get_prop(tothisnode, nam); - if ((errno = nvlist_add_string(r, nam, val)) != 0) { - nvlist_free(r); - break; - } - } - -out: - free(nvl); - return (r); -} diff --git a/usr/src/lib/fm/libtopo/common/topo_hcpath.c b/usr/src/lib/fm/libtopo/common/topo_hcpath.c deleted file mode 100644 index b48800f700..0000000000 --- a/usr/src/lib/fm/libtopo/common/topo_hcpath.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - * - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <sys/param.h> -#include <sys/systeminfo.h> -#include <fm/libtopo.h> -#include "topo_impl.h" - -static char tmpbuf[MAXPATHLEN]; -static char numbuf[MAXINSTLEN]; - -static int -intsize(int i) -{ - int r; - for (r = 1; i > 0; r++) - i = i/10; - return (r); -} - -static const char * -tnode_as_str(tnode_t *node) -{ - if (node->state == TOPO_ROOT) { - tmpbuf[0] = '\0'; - return (tmpbuf); - } - - (void) strcpy(tmpbuf, "/"); - if (node->state == TOPO_LIMBO) { - (void) strcat(tmpbuf, "?"); - (void) strlcat(tmpbuf, node->name, MAXPATHLEN); - (void) strlcat(tmpbuf, "?", MAXPATHLEN); - return (tmpbuf); - } - - (void) strlcat(tmpbuf, node->name, MAXPATHLEN); - if (node->state == TOPO_RANGE) { - (void) strlcat(tmpbuf, "[", MAXPATHLEN); - if (node->u.range.min == node->u.range.max) { - (void) snprintf(numbuf, MAXINSTLEN, "%d", - node->u.range.min); - (void) strlcat(tmpbuf, numbuf, MAXPATHLEN); - (void) strlcat(tmpbuf, "]", MAXPATHLEN); - return (tmpbuf); - } - (void) snprintf(numbuf, MAXINSTLEN, "%d", node->u.range.min); - (void) strlcat(tmpbuf, numbuf, MAXPATHLEN); - (void) strlcat(tmpbuf, "-", MAXPATHLEN); - (void) snprintf(numbuf, MAXINSTLEN, "%d", node->u.range.max); - (void) strlcat(tmpbuf, numbuf, MAXPATHLEN); - (void) strlcat(tmpbuf, "]", MAXPATHLEN); - return (tmpbuf); - } - (void) snprintf(numbuf, MAXINSTLEN, "%d", node->u.inst); - (void) strlcat(tmpbuf, numbuf, MAXPATHLEN); - return (tmpbuf); -} - -static int -tnode_strlen(tnode_t *node) -{ - int len; - - if (node == NULL) - return (0); - - len = strlen(node->name); - - switch (node->state) { - case TOPO_LIMBO: - len += 2; /* ? before and after */ - break; - case TOPO_RANGE: - len += 2; /* open and close brackets */ - if (node->u.range.min == node->u.range.max) { - len += intsize(node->u.range.max); - break; - } - len++; /* - between range elements */ - len += intsize(node->u.range.min); - len += intsize(node->u.range.max); - break; - case TOPO_INST: - len += intsize(node->u.inst); - } - - len++; /* leading slash */ - - return (len); -} - -static void -build_path(tnode_t *n, char **buf, int *len) -{ - const char *s; - - if (n == NULL) { - if (*len > 0) { - (*len)++; /* trailing null byte */ - *buf = topo_zalloc(*len); - } - return; - } else { - (*len) += tnode_strlen(n); - build_path(topo_parent(n), buf, len); - } - - if (*buf == NULL) - return; - - s = tnode_as_str(n); - (void) strlcat(*buf, s, *len); -} - -char * -topo_hc_path(tnode_t *tothisnode) -{ - char *buf = NULL; - int len = 0; - - build_path(tothisnode, &buf, &len); - return (buf); -} - -tnode_t * -topo_find_path(tnode_t *anchor, char *hcpath) -{ - tnode_t *root, *cn = NULL; - char *name = NULL; - char *inst = NULL; - char *cont; - int ignore; - int instno; - - if (anchor == NULL || hcpath == NULL || - (root = topo_getroot(anchor)) == NULL) - return (NULL); - - cont = topo_whiteskip(hcpath); - while ((cont = topo_component_from_path(cont, &name, &inst)) != NULL) { - - if (topo_inst_from_str(inst, &ignore, &ignore, &instno) != 0) { - topo_out(TOPO_DEBUG, "failed instno extract from %s\n", - inst); - return (NULL); - } - - while ((cn = topo_next_child(root, cn)) != NULL) { - topo_out(TOPO_DEBUG, "%s%d ?= %s%d\n", topo_name(cn), - topo_get_instance_num(cn), name, instno); - if (strcmp(topo_name(cn), name) == 0 && - topo_get_instance_num(cn) == instno) - break; - } - - if (cn == NULL) - return (NULL); - - root = cn; - cn = NULL; - - topo_free(name); - topo_free(inst); - name = inst = NULL; - } - return (root); -} diff --git a/usr/src/lib/fm/libtopo/common/topo_impl.h b/usr/src/lib/fm/libtopo/common/topo_impl.h deleted file mode 100644 index 47655fd774..0000000000 --- a/usr/src/lib/fm/libtopo/common/topo_impl.h +++ /dev/null @@ -1,180 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - * - */ - -#ifndef _TOPO_IMPL_H -#define _TOPO_IMPL_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <libnvpair.h> -#include <sys/types.h> - -#ifdef __cplusplus -extern "C" { -#endif - -struct tnode; - -struct tprop { - const char *p_name; - const char *p_val; - struct tprop *p_next; -}; - -struct tnode_hashent { - struct tnode *e_node; - struct tnode_hashent *e_next; -}; - -struct tnode_hash { - struct tnode_hashent **tn_hash; /* hash bucket array */ - uint_t tn_hashlen; /* size of hash bucket array */ - uint_t tn_nelems; /* number of nodes in the hash */ -}; - -struct tprop_hash { - struct tprop **tp_hash; /* hash bucket array */ - uint_t tp_hashlen; /* size of hash bucket array */ - uint_t tp_nelems; /* number of nodes in the hash */ -}; - -struct tenum_alias { - struct tenum_alias *tea_next; - const char *tea_type; - char *tea_share; -}; - -struct t_extend { - struct tnode_hash *te_index; - struct tenum_alias *te_aliases; -}; - -struct tnode { - const char *name; - enum { TOPO_ROOT = -2, TOPO_LIMBO = -1, TOPO_RANGE, TOPO_INST } state; - union { - struct { - int min; - int max; - } range; /* TOPO_RANGE only */ - int inst; /* TOPO_INST only */ - } u; - struct tnode_list { - int visited; - struct tnode *tnode; - struct tnode_list *next; - } *children; - struct tprop_hash *props; - struct tnode *parent; - struct tnode *root; /* quick access to root node for indexes */ - /* extended info */ - void *extend; -}; - -struct tnode *topo_set_instance_range(struct tnode *node, int min, int max); -struct tnode *topo_create(struct tnode *parent, const char *nodename); - -struct tnode *topo_parse(struct tnode *appendto, const char *filename); -void topo_enum(struct tnode *root); - -struct tnode_list *tnode_del_child(struct tnode *node, struct tnode *child); -struct tnode *tnode_dup(struct tnode *src); -struct tnode *tnode_add_child(struct tnode *node, struct tnode *child); -void tnode_destroy(struct tnode *node); -void tnode_print(struct tnode *node, void *ignore); -uint_t tnode_depth(struct tnode *node); - -/* This creates a topo tree */ -struct tnode *topo_root(void); - -/* This returns the root of an EXISTING topo tree */ -struct tnode *topo_getroot(struct tnode *); - -void topo_mem_init(void); -void topo_mem_fini(void); -void topo_indent(void); - -void topo_paths_init(int, const char **); -void topo_paths_fini(void); - -void topo_driver_fini(void); - -/* private topo_walk() categories */ -#define TOPO_REVISIT_SELF 4 -#define TOPO_DESTRUCTIVE_WALK 8 - -ulong_t topo_strhash(const char *); - -struct tprop_hash *tprop_hash_create(void); -struct tprop *tprop_hash_lookup_next(struct tprop_hash *, const char *, - struct tprop *); -struct tprop *tprop_hash_lookup(struct tprop_hash *, const char *); -struct tprop *tprop_create(const char *name, const char *val); -void tprop_hash_insert(struct tprop_hash *, const char *, struct tprop *); -void tprop_hash_destroy(struct tprop_hash *); -void tprop_destroy(struct tprop *); - -void tprop_index(struct tnode *node, const char *propname); - -struct tnode_hash *tnode_hash_create(void); -void tnode_hash_destroy(struct tnode_hash *); - -void tealias_add(struct tnode *, char *); -const char *tealias_find(struct tnode *); - -/* Common usage between hc_path and hc_fmri routines */ -#define MAXINSTLEN 256 - -void *topo_zalloc(size_t bytes); -char *topo_strdup(const char *str); -void topo_free(void *ptr); - -FILE *topo_open(const char *); -void topo_close(FILE *); -void *topo_dlopen(const char *); -void topo_dlclose(void *); - -/* parsing utilities */ -char *topo_whiteskip(char *); -char *topo_component_from_path(char *, char **, char **); -int topo_inst_from_str(char *, int *, int *, int *); - -/* private TOPO_OUT categories */ -#define TOPO_INFO 0x4 -#define TOPO_HASH 0x8 -#define TOPO_BUFONLY 0x10 /* don't call Outmethod, even if one exists */ - -extern void (*Outmethod)(const char *); -extern unsigned int Topo_out_mask; - -extern nv_alloc_t Topo_nv_alloc_hdl; - -#ifdef __cplusplus -} -#endif - -#endif /* _TOPO_IMPL_H */ diff --git a/usr/src/lib/fm/libtopo/common/topo_mem.c b/usr/src/lib/fm/libtopo/common/topo_mem.c deleted file mode 100644 index 8898f03e07..0000000000 --- a/usr/src/lib/fm/libtopo/common/topo_mem.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - * - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <libnvpair.h> -#include <sys/param.h> -#include <sys/systeminfo.h> -#include "topo_impl.h" -#include "libtopo.h" - -static void * (*Topo_zalloc_sleep)(size_t); -static void (*Topo_free)(void *); - -static void * -_topo_zalloc_sleep(size_t bytes) -{ - void *r; - - while ((r = malloc(bytes)) == NULL) - topo_out(TOPO_INFO, "_topo_zalloc_sleep: " - "Must wait for %llu bytes memory...\n", - (unsigned long long)bytes); - (void) memset(r, 0, bytes); - return (r); -} - -static void -_topo_free(void *p) -{ - free(p); -} - -/*ARGSUSED*/ -static void * -Topo_nv_alloc(nv_alloc_t *nva, size_t size) -{ - return (Topo_zalloc_sleep(size)); -} - -/*ARGSUSED*/ -static void -Topo_nv_free(nv_alloc_t *nva, void *p, size_t sz) -{ - Topo_free(p); -} - -const nv_alloc_ops_t Topo_nv_alloc_ops = { - NULL, /* nv_ao_init() */ - NULL, /* nv_ao_fini() */ - Topo_nv_alloc, /* nv_ao_alloc() */ - Topo_nv_free, /* nv_ao_free() */ - NULL /* nv_ao_reset() */ -}; - -nv_alloc_t Topo_nv_alloc_hdl; - -void -topo_mem_init() -{ - if (Topo_zalloc_sleep == NULL) - Topo_zalloc_sleep = _topo_zalloc_sleep; - if (Topo_free == NULL) - Topo_free = _topo_free; - (void) nv_alloc_init(&Topo_nv_alloc_hdl, &Topo_nv_alloc_ops); -} - -void -topo_mem_fini(void) -{ - (void) nv_alloc_fini(&Topo_nv_alloc_hdl); -} - -void * -topo_zalloc(size_t bytes) -{ - return (Topo_zalloc_sleep(bytes)); -} - -char * -topo_strdup(const char *str) -{ - char *r; - - r = Topo_zalloc_sleep(strlen(str) + 1); - (void) strcpy(r, str); - return (r); -} - -void -topo_free(void *ptr) -{ - Topo_free(ptr); -} - -void -topo_free_path(char *path) -{ - topo_free(path); -} - -void -topo_free_fmri(nvlist_t *fmri) -{ - nvlist_free(fmri); -} - -void -topo_set_mem_methods(void * (*zallocfn)(size_t), void (*freefn)(void *)) -{ - if (zallocfn == NULL || freefn == NULL) - return; - Topo_zalloc_sleep = zallocfn; - Topo_free = freefn; -} diff --git a/usr/src/lib/fm/libtopo/common/topo_out.c b/usr/src/lib/fm/libtopo/common/topo_out.c deleted file mode 100644 index 7bd2d902e1..0000000000 --- a/usr/src/lib/fm/libtopo/common/topo_out.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <stdio.h> -#include <stdarg.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <sys/param.h> -#include <sys/systeminfo.h> -#include "topo_impl.h" -#include "libtopo.h" - -unsigned int Topo_out_mask = TOPO_ERR; - -static char Topobuf[MAXPATHLEN]; -static int Topoidx; - -/*PRINTFLIKE2*/ -void -topo_out(int flag, char *format, ...) -{ - va_list ap; - char *errstr = NULL; - int len; - - if (!(flag & Topo_out_mask)) - return; - - if (*(format + strlen(format) - 1) == ':') - errstr = topo_strdup(strerror(errno)); - - va_start(ap, format); - /* print out remainder of message */ - len = vsnprintf(&Topobuf[Topoidx], MAXPATHLEN - Topoidx, format, ap); - if (len >= 0) - Topoidx += len; - - if (Topoidx >= MAXPATHLEN) - Topoidx = MAXPATHLEN - 1; - - if (errstr) { - (void) snprintf(&Topobuf[Topoidx], MAXPATHLEN - Topoidx, - " %s\n", errstr); - topo_free(errstr); - Topoidx = 0; - } else if (*(format + strlen(format) - 1) == '\n') { - Topoidx = 0; - } - - if (Topoidx == 0 && !(flag & TOPO_BUFONLY) && Outmethod != NULL) - Outmethod(Topobuf); - - va_end(ap); -} - -void -topo_debug_on(uint_t flags) -{ - Topo_out_mask |= flags; - Topo_out_mask |= TOPO_DEBUG; -} - -void -topo_debug_off(void) -{ - Topo_out_mask = TOPO_ERR; -} - -int Topo_depth = 0; - -void -topo_indent(void) -{ - int ic = Topo_depth; - - while (ic-- > 0) - topo_out(TOPO_DEBUG, " "); -} - -const char * -topo_errbuf(void) -{ - return (Topobuf); -} - -void -topo_set_out_method(void (*outfn)(const char *)) -{ - Outmethod = outfn; -} diff --git a/usr/src/lib/fm/libtopo/common/topo_parse.c b/usr/src/lib/fm/libtopo/common/topo_parse.c deleted file mode 100644 index ccec7bb60e..0000000000 --- a/usr/src/lib/fm/libtopo/common/topo_parse.c +++ /dev/null @@ -1,616 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <alloca.h> -#include <sys/param.h> -#include "topo_impl.h" -#include "topo_enum.h" - -#define TOPO_FILE "platform.topo" -#define TOPO_SHARE_DIRECTIVE "share" - -void (*Outmethod)(const char *); - -void -topo_init(int npaths, const char **paths) -{ - topo_mem_init(); - topo_paths_init(npaths, paths); - topo_enum_init(); -} - -void -topo_fini(void) -{ - topo_driver_fini(); - topo_paths_fini(); - topo_enum_fini(); - topo_mem_fini(); -} - -void -topo_reset(void) -{ - topo_enum_fini(); - topo_enum_init(); -} - -void -topo_tree_release(tnode_t *node) -{ - tnode_t *ar = node; /* actual root node */ - struct t_extend *re; - struct tenum_alias *cur, *nxt; - - if (ar->state != TOPO_ROOT) - ar = ar->root; - - if ((re = ar->extend) != NULL) { - tnode_hash_destroy(re->te_index); - cur = re->te_aliases; - while (cur != NULL) { - nxt = cur->tea_next; - topo_free(cur->tea_share); - topo_free(cur); - cur = nxt; - } - topo_free(re); - } - tnode_destroy(ar); -} - -/* - * The PLATFRU property is special. It is inherited by static nodes - * automatically from their parent, if it is not set within the .topo - * file. For the root node, the node name itself is the PLATFRU value. - */ -static void -topo_inherits(tnode_t *root) -{ - const char *pv; - tnode_t *tmp = NULL; - char *pbuf = NULL; - int inst; - - topo_out(TOPO_DEBUG, "topo_inherits: [%p]\n", (void *)root); - - while ((tmp = topo_next_child(root, tmp)) != NULL) { - topo_out(TOPO_DEBUG, " [%p]", (void *)tmp); - if (topo_get_prop(tmp, "NOINHERIT") != NULL) { - topo_out(TOPO_DEBUG, " declines inheritance\n"); - continue; - } - if ((pv = topo_get_prop(tmp, PLATFRU)) != NULL) { - topo_out(TOPO_DEBUG, PLATFRU " already set\n"); - continue; - } - if ((inst = topo_get_instance_num(tmp)) < 0) { - topo_out(TOPO_DEBUG, " not enumerated\n"); - continue; - } - if (root->state == TOPO_ROOT) { - if (pbuf == NULL) - pbuf = alloca(MAXPATHLEN); - (void) snprintf(pbuf, - MAXPATHLEN, "hc:///%s=%d", topo_name(tmp), inst); - (void) topo_set_prop(tmp, PLATFRU, pbuf); - topo_out(TOPO_DEBUG, "set to %s\n", pbuf); - topo_inherits(tmp); - } else if ((pv = topo_get_prop(root, PLATFRU)) != NULL) { - (void) topo_set_prop(tmp, PLATFRU, pv); - topo_out(TOPO_DEBUG, "set to %s\n", pv); - topo_inherits(tmp); - } else { - topo_out(TOPO_DEBUG, "no prop value to inherit\n"); - } - - } -} - -struct tnode * -topo_root(void) -{ - struct tnode *root = topo_create(NULL, ""); - - if (topo_parse(root, TOPO_FILE) == NULL) - return (root); - - topo_inherits(root); - - topo_walk(root, TOPO_VISIT_SELF_FIRST, NULL, tnode_print); - topo_enum(root); - return (root); -} - -static struct tnode *chew(char *, struct tnode *, struct tnode *); -static void syntax_error(const char *, int); -static void toolong_error(const char *, int); -int Empty = 0; - -struct tnode * -topo_parse(struct tnode *root, const char *filename) -{ - struct tnode *leaf, *newleaf; - FILE *fp; - char *parsebuf; - int line = 0; - - topo_out(TOPO_DEBUG, "topo_parse(%s)\n", filename); - - if (root == NULL) - return (NULL); - - if ((fp = topo_open(filename)) == NULL) - return (NULL); - - parsebuf = alloca(MAXPATHLEN); - - leaf = NULL; - while (fgets(parsebuf, MAXPATHLEN, fp) != NULL) { - line++; - if (*parsebuf == '\0' || - parsebuf[strlen(parsebuf) - 1] != '\n') { - int c; - while ((c = getc(fp)) != EOF && (c != '\n')) - ; - toolong_error(filename, line); - continue; - } - newleaf = chew(parsebuf, root, leaf); - if (newleaf == NULL && Empty != 1) { - syntax_error(filename, line); - } else if (newleaf != NULL) { - topo_walk(root, TOPO_VISIT_SELF_FIRST, NULL, - tnode_print); - leaf = newleaf; - } - } - - topo_close(fp); - return (root); -} - -struct tnode * -topo_load(const char *basename, struct tnode *subroot) -{ - char *filenmbuf = alloca(MAXPATHLEN); - - (void) snprintf(filenmbuf, MAXPATHLEN, "%s.topo", basename); - return (topo_parse(subroot, filenmbuf)); -} - -#define UPPER_MAX_RECURSE 10 -#define DFLT_MAX_RECURSE 5 -int Topo_max_recurse = DFLT_MAX_RECURSE; - -void -topo_set_recurse_depth(int newdepth) -{ - if (newdepth < 0 || newdepth > UPPER_MAX_RECURSE) { - topo_out(TOPO_ERR, "bogus max recurse depth %d ignored.\n", - newdepth); - return; - } - Topo_max_recurse = newdepth; -} - -void -topo_subtree_parse(struct tnode *subroot) -{ - static int recurse_depth = 0; - char *filenmbuf; - - if (++recurse_depth > Topo_max_recurse) { - recurse_depth--; - return; - } - - filenmbuf = alloca(MAXPATHLEN); - - (void) snprintf(filenmbuf, MAXPATHLEN, "%s.topo", topo_name(subroot)); - (void) topo_parse(subroot, filenmbuf); - - recurse_depth--; -} - -/* - * Declare a syntax error on the current line - */ -void -syntax_error(const char *pathname, int lineno) -{ - topo_out(TOPO_ERR, "%s: syntax error or bad directive on line %d\n", - pathname, lineno); -} - -/* - * Declare the current line too long - */ -void -toolong_error(const char *pathname, int lineno) -{ - topo_out(TOPO_ERR, "%s: line %d too long, ignored\n", pathname, lineno); -} - -/* - * Skip whitespace, return pointer to start of next token - */ -char * -topo_whiteskip(char *srcbuf) -{ - char *t; - - if ((t = srcbuf) == NULL) - return (NULL); - - while (*t == ' ' || *t == '\t') - t++; - - if (*t == '\0' || *t == '#' || *t == '\n') - return (NULL); - else - return (t); -} - -int -topo_inst_from_str(char *src, int *min, int *max, int *instno) -{ - char *b; - char *e; - char s; - long l; - - *min = *max = *instno = -1; - - if (isdigit(*src) != 0) { - errno = 0; - l = strtol(src, NULL, 10); - if (errno != 0) - return (-1); - *instno = (int)l; - return (0); - } - - if (*src++ != '[') - return (-1); - - b = src; - e = b; - while (isdigit(*e) != 0) - e++; - s = *e; - *e = '\0'; - errno = 0; - l = strtol(b, NULL, 10); - *e = s; - if (errno != 0) - return (-1); - - if (*e == ']') { - *min = *max = (int)l; - return (0); - } - - if (*e++ != '-') - return (-1); - *min = (int)l; - b = e; - while (isdigit(*e) != 0) - e++; - s = *e; - *e = '\0'; - errno = 0; - l = strtol(b, NULL, 10); - *e = s; - if (errno != 0) - return (-1); - if (*e++ != ']') - return (-1); - if (*e != '\0') - return (-1); - *max = (int)l; - return (0); -} - -char * -topo_component_from_path(char *src, char **name, char **inst) -{ - char *b = src; - char *e; - char s; - - if (src == NULL || *src == '\0') - return (NULL); - - b++; /* skip leading slash */ - e = b; - while (isalpha(*e) != 0 || *e == '_') - e++; - - if (*e == '\0' || *e == '\n') - return (NULL); - - s = *e; - *e = '\0'; - *name = topo_strdup(b); - *e = s; - - /* rest up to next slash is instance part */ - b = e; - while (*e != '\0' && *e != '\n' && *e != '/') - e++; - s = *e; - *e = '\0'; - *inst = topo_strdup(b); - *e = s; - - return (e); -} - -static int -prop_from_inbuf(char *src, char **name, char **val) -{ - char *b = src; - char *e; - char s; - int quoted = 0; - - b = e = src; - - /* property name must start with alpha character, _ or . */ - if (isalpha(*e) == 0 && *e != '_' && *e != '.') - return (-1); - - e++; - while (isalnum(*e) != 0 || *e == '_' || *e == '.' || *e == '-') - e++; - - if (*e == '\0' || *e == '\n') - return (-1); - - s = *e; - *e = '\0'; - *name = topo_strdup(b); - *e = s; - - b = topo_whiteskip(e); - if (b == NULL || *b != '=') { - topo_free(*name); - return (-1); - } - b = topo_whiteskip(++b); - if (*b == '"') { - b++; - quoted++; - } - e = b; - if (quoted) { - while (*e != '"' && *e != '\0' && *e != '\n') - e++; - if (*e != '"') { - topo_free(*name); - return (-1); - } - } else { - while (*e != '\0' && *e != '\n' && *e != ' ' && *e != '\t') - e++; - } - s = *e; - *e = '\0'; - *val = topo_strdup(b); - *e = s; - - if (quoted) - e++; - b = topo_whiteskip(e); - if (b != NULL) { - topo_free(*name); - topo_free(*val); - return (-1); - } - - return (0); -} - -/* - * Add a child to 'parent' with name and instance number - * described by 'name' and 'inst'. If one already exists, - * just return a pointer to the existing one. - */ -static struct tnode * -new_child(struct tnode *parent, char *name, char *inst) -{ - tnode_t *tmp = NULL; - int min, max, instno; - - if (topo_inst_from_str(inst, &min, &max, &instno) != 0) - return (NULL); - - while ((tmp = topo_next_child(parent, tmp)) != NULL) { - if (strcmp(name, topo_name(tmp)) != 0) - continue; - if (instno >= 0 && tmp->state == TOPO_INST && - tmp->u.inst == instno) - break; - if (min >= 0 && tmp->state == TOPO_RANGE && - tmp->u.range.min == min && tmp->u.range.max == max) - break; - } - - if (tmp != NULL) - topo_out(TOPO_DEBUG, "child %s%s of %p present, = %p\n", - name, inst, (void *)parent, (void *)tmp); - - if (tmp != NULL) - return (tmp); - - tmp = topo_create(parent, name); - if (instno >= 0) - (void) topo_set_instance_num(tmp, instno); - else - (void) topo_set_instance_range(tmp, min, max); - - topo_out(TOPO_DEBUG, "child %s%s of %p created = %p\n", - name, inst, (void *)parent, (void *)tmp); - - return (tmp); -} - -static struct tnode * -grow_path(char *buf, struct tnode *root) -{ - struct tnode *n; - char *name = NULL; - char *inst = NULL; - char *cont; - - topo_out(TOPO_DEBUG, "grow_path: %s\n", buf); - cont = topo_component_from_path(buf, &name, &inst); - - if (cont == NULL) { - if (name != NULL) - topo_free(name); - if (inst != NULL) - topo_free(inst); - return (root); - } - - if ((n = new_child(root, name, inst)) == NULL) { - topo_free(name); - topo_free(inst); - return (NULL); - } - - /* - * If the node specifies a dynamic range, there may be a .topo - * file associated with the node type describing a hierarchy - * of possible nodes under this node. - */ - if (topo_get_instance_num(n) < 0) - topo_subtree_parse(n); - - topo_free(name); - topo_free(inst); - - return (grow_path(cont, n)); -} - -struct tnode * -consume_prop(char *buf, struct tnode *addto) -{ - char *name, *val; - - if (addto == NULL) - return (NULL); - - if (prop_from_inbuf(buf, &name, &val) != 0) - return (NULL); - - topo_out(TOPO_DEBUG, "setting prop on %p: %s = %s\n", (void *)addto, - name, val); - (void) topo_set_prop(addto, name, val); - - topo_free(name); - topo_free(val); - - return (addto); -} - -struct tnode * -consume_directive(char *buf, struct tnode *rnode) -{ - char *alias; - char *b, *e; - char s; - - /* Skip exclamation declaring a directive, and any following space */ - b = e = topo_whiteskip(++buf); - - /* directive must start with alpha character or _ */ - if (isalpha(*e) == 0 && *e != '_') - return (NULL); - - e++; - while (isalpha(*e) != 0 || *e == '_') - e++; - - /* - * Presently we only have one valid directive. If we add more - * we should add a jump-table sort of structure. - */ - s = *e; - *e = '\0'; - if (strcmp(TOPO_SHARE_DIRECTIVE, b) == 0) { - *e = s; - if (*e == '\0' || *e == '\n') - return (NULL); - b = e = topo_whiteskip(e); - e++; - while (isalpha(*e) != 0 || *e == '_') - e++; - /* No enumerator provided to share */ - if (b == e) - return (NULL); - s = *e; - *e = '\0'; - alias = topo_strdup(b); - tealias_add(rnode, alias); - *e = s; - return (rnode); - } - *e = s; - return (NULL); -} - -struct tnode * -chew(char *buf, struct tnode *root, struct tnode *lastleaf) -{ - char *t; - - topo_out(TOPO_DEBUG, "chew:%s [%p]\n", buf, (void *)root); - if ((t = topo_whiteskip(buf)) == NULL) { - Empty = 1; - return (NULL); - } - Empty = 0; - - if (*t == '/') - /* a new path to add, growpath returns the leaf node */ - return (grow_path(t, root)); - - if (*t == '!') - /* a directive is (probably) present in the topology file */ - return (consume_directive(t, root)); - - return (consume_prop(t, lastleaf)); -} diff --git a/usr/src/lib/fm/libtopo/common/topo_paths.c b/usr/src/lib/fm/libtopo/common/topo_paths.c deleted file mode 100644 index 796a3c7ce5..0000000000 --- a/usr/src/lib/fm/libtopo/common/topo_paths.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/param.h> -#include <sys/systeminfo.h> -#include <stdio.h> -#include <dlfcn.h> -#include <link.h> -#include <fm/libtopo.h> -#include "topo_impl.h" - -#define DEFAULT_DIR "/usr/lib/fm/topo" - -static char pathbuf[MAXPATHLEN]; - -static char **Topopaths; -static int NTopopaths; - -static void -default_paths(void) -{ - char *platform; - - /* - * Probably should make sure it fits, but we're giving it an - * awfully large buffer :-) - */ - (void) sysinfo(SI_PLATFORM, pathbuf, MAXPATHLEN); - platform = topo_strdup(pathbuf); - (void) snprintf(pathbuf, MAXPATHLEN, "%s/%s", DEFAULT_DIR, platform); - topo_free(platform); - - NTopopaths = 2; - Topopaths = topo_zalloc(NTopopaths * sizeof (char *)); - Topopaths[0] = topo_strdup(pathbuf); - Topopaths[1] = topo_strdup(DEFAULT_DIR); -} - -void -topo_paths_init(int npaths, const char **paths) -{ - int i; - - if (paths == NULL) { - default_paths(); - return; - } - - NTopopaths = npaths; - Topopaths = topo_zalloc(NTopopaths * sizeof (char *)); - - for (i = 0; i < NTopopaths; i++) - Topopaths[i] = topo_strdup(paths[i]); -} - -void -topo_paths_fini(void) -{ - int i; - - for (i = 0; i < NTopopaths; i++) - topo_free(Topopaths[i]); - topo_free(Topopaths); -} - -FILE * -topo_open(const char *filename) -{ - FILE *fp = NULL; - int i; - - for (i = 0; i < NTopopaths; i++) { - (void) snprintf(pathbuf, MAXPATHLEN, "%s/%s", - Topopaths[i], filename); - if ((fp = fopen(pathbuf, "r")) != NULL) - break; - else - topo_out(TOPO_DEBUG, "%s:", pathbuf); - } - return (fp); -} - -void * -topo_dlopen(const char *filename) -{ - void *dlp = NULL; - int i; - - for (i = 0; i < NTopopaths; i++) { - (void) snprintf(pathbuf, MAXPATHLEN, "%s/%s", - Topopaths[i], filename); - if ((dlp = dlopen(pathbuf, RTLD_LOCAL | RTLD_NOW)) != NULL) - break; - else - topo_out(TOPO_DEBUG, "%s: %s\n", pathbuf, dlerror()); - } - return (dlp); -} - -void -topo_dlclose(void *dlp) -{ - (void) dlclose(dlp); -} - -void -topo_close(FILE *fp) -{ - (void) fclose(fp); -} diff --git a/usr/src/lib/fm/libtopo/common/topo_pkg.c b/usr/src/lib/fm/libtopo/common/topo_pkg.c deleted file mode 100644 index 557f41f8f9..0000000000 --- a/usr/src/lib/fm/libtopo/common/topo_pkg.c +++ /dev/null @@ -1,372 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <strings.h> -#include <string.h> -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <sys/stat.h> -#include <sys/systeminfo.h> -#include <sys/modctl.h> -#include <sys/fm/protocol.h> -#include <alloca.h> -#include <libtopo.h> -#include "topo_impl.h" - -/* - * mod_filename_bindpath -- - * - * Determine that path to a particular mod_filename. The path is determined - * using the module load path hierarchy for the machine obtained from the - * kernel via MODGETPATH modctl and kernel run mode information obtained from - * MODGETPATHSUFFIX - and searching for the module on this path. A match - * corresponds to the same path the kernel would use to load the module. - * - * This function returns a pointer to a malloced path. The caller - * must free this to avoid leaks. - * - * NOTE: this function is typically called for an unbound path - * (unloaded module, so MODINFO_MODPATH failed). We may however call - * this for a bound path (loaded module) if MODINFO_MODPATH returned - * path does not start with '/'. This situation may occur with - * primary modules loaded by OBP, like krtld. - */ -#define MOD_SEP " :" - -static char *Moddirsave; -static char *Suffixdir; - -static char * -mod_filename_bindpath(const char *mod_filename) -{ - char *moddir; - char path[MAXPATHLEN]; - char *dir = NULL; - char *ls; - struct stat st; - int len; - - /* - * On first call, initialize the string that describes the - * directories searched by the kernel to locate a module. - */ - if (Moddirsave == NULL) { - if (modctl(MODGETPATHLEN, NULL, &len) != 0) - goto out; - Moddirsave = topo_zalloc(len + 1); - if (modctl(MODGETPATH, NULL, Moddirsave) != 0) { - topo_free(Moddirsave); - Moddirsave = topo_strdup(""); - goto out; - } - topo_out(TOPO_DEBUG, "%s\n", Moddirsave); - } - - /* - * On first call, initialize architecture specific directory suffix. - */ - if (Suffixdir == NULL) { - char *tmpbuf = alloca(MAXPATHLEN); - char *sufbuf = alloca(MAXPATHLEN); - - (void) sysinfo(SI_ARCHITECTURE_K, tmpbuf, MAXPATHLEN); - if (strcmp(tmpbuf, "i386") == 0) { - Suffixdir = topo_strdup("drv"); - } else { - (void) snprintf(sufbuf, MAXPATHLEN, "drv/%s", tmpbuf); - Suffixdir = topo_strdup(sufbuf); - } - } - - /* find the last '/' in mod_filename */ - ls = strrchr(mod_filename, '/'); - - /* initialize for module path string breakup */ - moddir = topo_strdup(Moddirsave); - dir = strtok(moddir, MOD_SEP); - - /* loop over the directories searched to locate a module */ - while (dir != NULL) { - /* - * break out of loop if we find the file. - * try the Suffixdir (e.g, "sparcv9") specific path first - */ - if (ls) { - /* - * split mod_filename into a path piece and a - * file piece, then interject our suffix - * between the pieces. - * - * i.e, if path comes in as drv/fish - * and Suffixdir is determined to be sparcv9, - * we end up with .../drv/sparcv9/fish. - */ - *ls = 0; - (void) snprintf(path, sizeof (path), "%s/%s/%s/%s", - dir, mod_filename, Suffixdir, &ls[1]); - *ls = '/'; - if ((stat(path, &st) == 0) && - ((st.st_mode & S_IFMT) == S_IFREG)) - break; - } else { - /* we don't have a '/' in path, Suffixdir goes first */ - (void) snprintf(path, sizeof (path), - "%s/%s/%s", dir, Suffixdir, mod_filename); - if ((stat(path, &st) == 0) && - ((st.st_mode & S_IFMT) == S_IFREG)) - break; - } - - /* try straight mod_filename. */ - (void) snprintf(path, sizeof (path), "%s/%s", - dir, mod_filename); - if ((stat(path, &st) == 0) && - ((st.st_mode & S_IFMT) == S_IFREG)) - break; - - dir = strtok((char *)NULL, MOD_SEP); - } - - topo_free(moddir); - -out: if (dir == NULL) - return (NULL); - - return (topo_strdup(path)); -} - -static int -read_thru(FILE *fp, const char *substr) -{ - char *tmpbuf = alloca(2 * MAXPATHLEN); - int notfound = 1; - - while (fgets(tmpbuf, 2 * MAXPATHLEN, fp) != NULL) { - if (substr == NULL) - topo_out(TOPO_DEBUG, "%s", tmpbuf); - else if (strstr(tmpbuf, substr) != NULL) { - notfound = 0; - break; - } - } - return (notfound); -} - -static nvlist_t * -construct_asru_fmri(struct modinfo *mi, nvlist_t *fru) -{ - nvlist_t *a = NULL; - int e; - - errno = nvlist_xalloc(&a, NV_UNIQUE_NAME, &Topo_nv_alloc_hdl); - if (errno != 0) { - topo_out(TOPO_ERR, "alloc of mod nvl failed:"); - goto fmrialeave; - } - - mi->mi_name[MODMAXNAMELEN - 1] = '\0'; - mi->mi_msinfo[0].msi_linkinfo[MODMAXNAMELEN - 1] = '\0'; - - e = nvlist_add_string(a, FM_FMRI_SCHEME, FM_FMRI_SCHEME_MOD); - e |= nvlist_add_uint8(a, FM_VERSION, FM_MOD_SCHEME_VERSION); - e |= nvlist_add_nvlist(a, FM_FMRI_MOD_PKG, fru); - e |= nvlist_add_string(a, FM_FMRI_MOD_NAME, mi->mi_name); - e |= nvlist_add_int32(a, FM_FMRI_MOD_ID, mi->mi_id); - e |= nvlist_add_string(a, FM_FMRI_MOD_DESC, - mi->mi_msinfo[0].msi_linkinfo); - if (e != 0) { - topo_out(TOPO_ERR, "construct of mod nvl failed:"); - goto fmrialeave; - } - - return (a); - -fmrialeave: - if (a != NULL) - nvlist_free(a); - return (NULL); -} - -static nvlist_t * -construct_fru_fmri(const char *pkgname, FILE *fp) -{ - nvlist_t *f = NULL; - char *tmpbuf = alloca(2 * MAXPATHLEN); - char *pkgdir = NULL; - char *pkgver = NULL; - char *token; - int e; - - if (pkgname == NULL) - return (NULL); - - while (fgets(tmpbuf, 2 * MAXPATHLEN, fp) != NULL) { - if (strstr(tmpbuf, "VERSION:") != NULL) { - token = strtok(tmpbuf, ":"); - token = strtok(NULL, ": \t\n"); - pkgver = topo_strdup(token); - } else if (strstr(tmpbuf, "BASEDIR:") != NULL) { - token = strtok(tmpbuf, ":"); - token = strtok(NULL, ": \t\n"); - pkgdir = topo_strdup(token); - } - } - - if (pkgdir == NULL || pkgver == NULL) - goto fmrileave; - - errno = nvlist_xalloc(&f, NV_UNIQUE_NAME, &Topo_nv_alloc_hdl); - if (errno != 0) { - topo_out(TOPO_ERR, "alloc of pkg nvl failed:"); - goto fmrileave; - } - e = nvlist_add_string(f, FM_FMRI_SCHEME, FM_FMRI_SCHEME_PKG); - e |= nvlist_add_uint8(f, FM_VERSION, FM_PKG_SCHEME_VERSION); - e |= nvlist_add_string(f, FM_FMRI_PKG_BASEDIR, pkgdir); - e |= nvlist_add_string(f, FM_FMRI_PKG_INST, pkgname); - e |= nvlist_add_string(f, FM_FMRI_PKG_VERSION, pkgver); - if (e == 0) - goto fmrileave; - - topo_out(TOPO_ERR, "construct of pkg nvl failed:"); - nvlist_free(f); - f = NULL; - -fmrileave: - if (pkgdir != NULL) - topo_free(pkgdir); - if (pkgver != NULL) - topo_free(pkgver); - - return (f); -} - -#define PKGINFO_CMD "LC_MESSAGES= /usr/bin/pkginfo -l %s 2>/dev/null" -#define PKGCHK_CMD "LC_MESSAGES= /usr/sbin/pkgchk -lp %s 2>/dev/null" -#define PKG_KEYPHRASE "Referenced by the following packages:" - -/* - * topo_driver_fru -- Given a driver name, find the path that module, - * and then look up the package delivering that module to the - * system. Then construct a 'pkg' scheme FMRI that describes the - * package. - */ -static nvlist_t * -topo_driver_fru(const char *drvrname) -{ - nvlist_t *f = NULL; - FILE *pcout; - char *tmpbuf = alloca(2 * MAXPATHLEN); - char *findpkgname; - char *pkgname = NULL; - char *path; - - if ((path = mod_filename_bindpath(drvrname)) != NULL) { - (void) snprintf(tmpbuf, 2 * MAXPATHLEN, PKGCHK_CMD, path); - topo_out(TOPO_DEBUG, "popen of %s\n", tmpbuf); - pcout = popen(tmpbuf, "r"); - if (read_thru(pcout, PKG_KEYPHRASE)) { - (void) pclose(pcout); - goto drvfrufail; - } - (void) fgets(tmpbuf, 2 * MAXPATHLEN, pcout); - (void) pclose(pcout); - topo_out(TOPO_DEBUG, "%s", tmpbuf); - - if ((findpkgname = strtok(tmpbuf, " \n")) == NULL) - goto drvfrufail; - pkgname = topo_strdup(findpkgname); - (void) snprintf(tmpbuf, 2 * MAXPATHLEN, PKGINFO_CMD, pkgname); - topo_out(TOPO_DEBUG, "popen of %s\n", tmpbuf); - pcout = popen(tmpbuf, "r"); - f = construct_fru_fmri(pkgname, pcout); - (void) pclose(pcout); - } - -drvfrufail: - if (pkgname != NULL) - topo_free(pkgname); - if (path != NULL) - topo_free(path); - return (f); -} - -/* - * topo_driver_asru -- Given a driver name, first create its FRU fmri - * and if that goes well, get the rest of the module information - * and put it in a 'mod' scheme FMRI describing the driver as an - * ASRU. - */ -nvlist_t * -topo_driver_asru(const char *drvrname, nvlist_t **frup) -{ - struct modinfo mi; - nvlist_t *a = NULL; - nvlist_t *f = NULL; - int true = 1; - int id = -1; /* get info for all loaded modules */ - - if ((f = topo_driver_fru(drvrname)) == NULL) - goto drvasrufail; - - mi.mi_id = mi.mi_nextid = id; - mi.mi_info = MI_INFO_ALL | MI_INFO_NOBASE; - do { - if (modctl(MODINFO, id, &mi) < 0) - break; - if (strncmp(mi.mi_name, drvrname, MODMAXNAMELEN) == 0) { - if ((a = construct_asru_fmri(&mi, f)) == NULL) - goto drvasrufail; - break; - } - id = mi.mi_id; - } while (true); - - if (f != NULL && frup != NULL) - *frup = f; - return (a); - -drvasrufail: - if (f != NULL) - nvlist_free(f); - return (NULL); -} - -void -topo_driver_fini(void) -{ - if (Moddirsave != NULL) { - topo_free(Moddirsave); - Moddirsave = NULL; - } - if (Suffixdir != NULL) { - topo_free(Suffixdir); - Suffixdir = NULL; - } -} diff --git a/usr/src/lib/fm/libtopo/common/topo_prop.c b/usr/src/lib/fm/libtopo/common/topo_prop.c deleted file mode 100644 index 7cfe59ee81..0000000000 --- a/usr/src/lib/fm/libtopo/common/topo_prop.c +++ /dev/null @@ -1,264 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - * - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <sys/param.h> -#include <sys/systeminfo.h> -#include "topo_impl.h" -#include "libtopo.h" - -int -topo_set_prop(tnode_t *node, const char *name, const char *val) -{ - struct tprop *newp = NULL; - struct tprop *wp; - - /* does a properties table even exist yet? */ - if (node->props == NULL) { - node->props = tprop_hash_create(); - topo_out(TOPO_HASH, "prop hash for %p is %p\n", (void *)node, - (void *)node->props); - newp = tprop_create(name, val); - tprop_hash_insert(node->props, name, newp); - if (node->state == TOPO_INST) - tprop_index(node, name); - return (0); - } - - wp = tprop_hash_lookup(node->props, name); - for (; wp != NULL; wp = wp->p_next) { - if ((strcmp(wp->p_name, name)) == 0) { - newp = wp; - break; - } - } - - /* - * XXX any issue here for someone who's already looked up the - * property and saved that pointer? Probably not, as they - * would have just used it right away... Does that argue we - * should return an alloc'd buffer? - */ - if (newp != NULL) { - /* replacing existing property */ - topo_out(TOPO_DEBUG, - "in %p replace %s (= %s) with %s\n", - (void *)node->props, name, newp->p_val, val); - topo_free((void *)newp->p_val); - newp->p_val = topo_strdup(val); - return (0); - } - - newp = tprop_create(name, val); - tprop_hash_insert(node->props, name, newp); - if (node->state == TOPO_INST) - tprop_index(node, name); - return (0); -} - -const char * -topo_get_prop(tnode_t *node, const char *propname) -{ - struct tprop *wp; - int c = -1; - - if (node->props == NULL) - return (NULL); - - wp = tprop_hash_lookup(node->props, propname); - for (; wp != NULL; wp = wp->p_next) - if ((c = strcmp(wp->p_name, propname)) == 0) - break; - return ((c == 0) ? wp->p_val : NULL); -} - -const char * -topo_next_prop(tnode_t *node, const char *prevprop) -{ - struct tprop *wp = NULL; - - if (node->props == NULL) - return (NULL); - - if (prevprop != NULL) { - wp = tprop_hash_lookup(node->props, prevprop); - for (; wp != NULL; wp = wp->p_next) - if (strcmp(wp->p_name, prevprop) == 0) - break; - } - - if ((wp = tprop_hash_lookup_next(node->props, prevprop, wp)) == NULL) - return (NULL); - return (wp->p_name); -} - -tnode_t * -topo_match_childr(tnode_t *node, int min, int max) -{ - tnode_t *tmp = NULL; - - while ((tmp = topo_next_child(topo_parent(node), tmp)) != NULL) { - if (tmp->state == TOPO_RANGE && - tmp->u.range.min == min && tmp->u.range.max == max && - strcmp(topo_name(tmp), topo_name(node)) == 0) - break; - } - return (tmp); -} - -tnode_t * -topo_match_childi(tnode_t *node, int instance) -{ - tnode_t *tmp = NULL; - - while ((tmp = topo_next_child(topo_parent(node), tmp)) != NULL) - if (tmp->state == TOPO_INST && tmp->u.inst == instance && - strcmp(topo_name(tmp), topo_name(node)) == 0) - break; - return (tmp); -} - -static void -dup_children(tnode_t *from, tnode_t *to) -{ - tnode_t *tmp = NULL; - tnode_t *nc; - - if (from == NULL || from->children == NULL) - return; - - while ((tmp = topo_next_child(from, tmp)) != NULL) { - nc = tnode_dup(tmp); - (void) tnode_add_child(to, nc); - } -} - -static void -dup_props(tnode_t *from, tnode_t *to) -{ - const char *propn; - - propn = NULL; - while ((propn = topo_next_prop(from, propn)) != NULL) - (void) topo_set_prop(to, propn, topo_get_prop(from, propn)); -} - -static void -inherit_props(tnode_t *node) -{ - tnode_t *tmp = NULL; - - while ((tmp = topo_next_child(topo_parent(node), tmp)) != NULL) - if (tmp->state == TOPO_RANGE && - strcmp(topo_name(tmp), topo_name(node)) == 0 && - tmp->u.range.min <= node->u.inst && - tmp->u.range.max >= node->u.inst) - dup_props(tmp, node); -} - -static void -inherit_children(tnode_t *node) -{ - /* - * for a confirmed instance number, have it inherit copies of the - * children of any 'range' nodes it falls within - */ - tnode_t *tmp = NULL; - - while ((tmp = topo_next_child(topo_parent(node), tmp)) != NULL) { - if (tmp->state == TOPO_RANGE && - strcmp(topo_name(tmp), topo_name(node)) == 0 && - tmp->u.range.min <= node->u.inst && - tmp->u.range.max >= node->u.inst) - dup_children(tmp, node); - } -} - -tnode_t * -topo_set_instance_num(tnode_t *node, int instance) -{ - tnode_t *tmp; - tnode_t *new; - - topo_out(TOPO_DEBUG, "topo_set_instance_num: %p [%d].\n", - (void *)node, instance); - - if (node->state == TOPO_LIMBO) { - node->state = TOPO_INST; - node->u.inst = instance; - return (node); - /*NOTREACHED*/ - } - - tmp = topo_match_childi(node, instance); - if (tmp != NULL) { - return (tmp); - /*NOTREACHED*/ - } - - new = topo_create(topo_parent(node), topo_name(node)); - (void) topo_set_instance_num(new, instance); - - inherit_props(new); - inherit_children(new); - return (new); -} - -tnode_t * -topo_set_instance_range(tnode_t *node, int min, int max) -{ - tnode_t *tmp; - tnode_t *new; - - if (min > max || node == NULL) - return (NULL); - - if (node->state == TOPO_LIMBO) { - node->state = TOPO_RANGE; - node->u.range.min = min; - node->u.range.max = max; - return (node); - /*NOTREACHED*/ - } - - tmp = topo_match_childr(node, min, max); - if (tmp != NULL) { - return (tmp); - /*NOTREACHED*/ - } - - new = topo_create(topo_parent(node), topo_name(node)); - (void) topo_set_instance_range(new, min, max); - - return (new); -} diff --git a/usr/src/lib/fm/libtopo/common/topo_traverse.c b/usr/src/lib/fm/libtopo/common/topo_traverse.c deleted file mode 100644 index 0afcac88c2..0000000000 --- a/usr/src/lib/fm/libtopo/common/topo_traverse.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - * - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <sys/param.h> -#include <sys/systeminfo.h> -#include "topo_impl.h" -#include "libtopo.h" - -tnode_t * -topo_parent(tnode_t *node) -{ - return (node->parent); -} - -tnode_t * -topo_next_child(tnode_t *parent, tnode_t *prevchild) -{ - struct tnode_list *wc; - - if (parent == NULL && prevchild == NULL) - return (topo_root()); - - if (parent->children == NULL) - return (NULL); - - if (prevchild == NULL) - return (parent->children->tnode); - - for (wc = parent->children; wc != NULL; wc = wc->next) - if (wc->tnode == prevchild) - break; - - if (wc == NULL || wc->next == NULL) - return (NULL); - - return (wc->next->tnode); -} - -tnode_t * -topo_next_sibling(tnode_t *node, tnode_t *prevsib) -{ - tnode_t *parent; - - if (node == NULL && prevsib == NULL) - return (topo_root()); - - if (node == NULL) - return (NULL); - - parent = topo_parent(node); - if (parent == NULL) - return (NULL); - - return (topo_next_child(parent, prevsib)); -} - -int -topo_get_instance_num(tnode_t *node) -{ - if (node->state == TOPO_LIMBO || node->state == TOPO_RANGE) - return (-1); - return (node->u.inst); -} - -void -topo_get_instance_range(tnode_t *node, int *min, int *max) -{ - if (node->state == TOPO_LIMBO || node->state == TOPO_INST) { - if (min != NULL) - *min = -1; - if (max != NULL) - *max = -1; - return; - } - if (min != NULL) - *min = node->u.range.min; - if (max != NULL) - *max = node->u.range.max; -} - -extern int Topo_depth; - -void -topo_walk(tnode_t *start, int flag, void *arg, - void (*cb)(tnode_t *, void *)) -{ - struct tnode_list *nwc, *wc; - - if (flag & TOPO_VISIT_SELF_FIRST && start->state != TOPO_ROOT) - cb(start, arg); - - /* - * Go through the children but do so in a manner such that we - * never use a pointer that could have changed from underneath - * us. We can't just use a simple loop. A child might delete - * itself from our list and if we just loop we'll follow a - * stray pointer. A child might establish more children, and - * we don't want to miss out on visiting them, either. (For - * example when we are enumerating). - */ - Topo_depth++; - for (wc = start->children; wc != NULL; ) { - if (flag & TOPO_DESTRUCTIVE_WALK) - nwc = wc->next; - topo_walk(wc->tnode, flag, arg, cb); - if (flag & TOPO_DESTRUCTIVE_WALK) - wc = nwc; - else - wc = wc->next; - } - Topo_depth--; - - if (flag & TOPO_VISIT_SELF_FIRST && !(flag & TOPO_REVISIT_SELF)) - return; - - if (start->state != TOPO_ROOT) - cb(start, arg); -} diff --git a/usr/src/lib/fm/libtopo/sparcv9/Makefile b/usr/src/lib/fm/libtopo/sparcv9/Makefile deleted file mode 100644 index 98cef7b91a..0000000000 --- a/usr/src/lib/fm/libtopo/sparcv9/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" - -MAPDIR = ../spec/sparcv9 -include ../Makefile.com -include ../../../Makefile.lib.64 - -install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64) diff --git a/usr/src/lib/fm/libtopo/spec/topo.spec b/usr/src/lib/fm/libtopo/spec/topo.spec deleted file mode 100644 index cf47f3b17c..0000000000 --- a/usr/src/lib/fm/libtopo/spec/topo.spec +++ /dev/null @@ -1,145 +0,0 @@ -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -#ident "%Z%%M% %I% %E% SMI" - -function topo_name -version SUNWprivate -end - -function topo_set_instance_num -version SUNWprivate -end - -function topo_get_instance_num -version SUNWprivate -end - -function topo_get_instance_range -version SUNWprivate -end - -function topo_get_prop -version SUNWprivate -end - -function topo_next_prop -version SUNWprivate -end - -function topo_set_prop -version SUNWprivate -end - -function topo_find_propval -version SUNWprivate -end - -function topo_find_path -version SUNWprivate -end - -function topo_parent -version SUNWprivate -end - -function topo_next_sibling -version SUNWprivate -end - -function topo_next_child -version SUNWprivate -end - -function topo_tree_release -version SUNWprivate -end - -function topo_walk -version SUNWprivate -end - -function topo_hc_path -version SUNWprivate -end - -function topo_hc_fmri -version SUNWprivate -end - -function topo_free_path -version SUNWprivate -end - -function topo_free_fmri -version SUNWprivate -end - -function topo_init -version SUNWprivate -end - -function topo_reset -version SUNWprivate -end - -function topo_fini -version SUNWprivate -end - -function topo_load -version SUNWprivate -end - -function topo_errbuf -version SUNWprivate -end - -function topo_set_mem_methods -version SUNWprivate -end - -function topo_set_out_method -version SUNWprivate -end - -function topo_out -version SUNWprivate -end - -function topo_set_recurse_depth -version SUNWprivate -end - -function topo_driver_asru -version SUNWprivate -end - -function topo_debug_on -version SUNWprivate -end - -function topo_debug_off -version SUNWprivate -end diff --git a/usr/src/cmd/fm/topo/Makefile b/usr/src/lib/fm/topo/Makefile index b8d2a772bb..6d0f9d2e68 100644 --- a/usr/src/cmd/fm/topo/Makefile +++ b/usr/src/lib/fm/topo/Makefile @@ -20,11 +20,11 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" -SUBDIRS = files plugins prtopo +SUBDIRS = libtopo modules files include ../Makefile.subdirs diff --git a/usr/src/cmd/fm/topo/Makefile.rootdirs b/usr/src/lib/fm/topo/Makefile.rootdirs index a5dd325bde..6cb20f44ba 100644 --- a/usr/src/cmd/fm/topo/Makefile.rootdirs +++ b/usr/src/lib/fm/topo/Makefile.rootdirs @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -32,11 +32,31 @@ $(ROOT)/usr/lib/fm: $(INS.dir) -$(ROOT_TOPO_ROOT): $(ROOT)/usr/lib/fm +$(ROOT)/usr/lib/fm/topo: $(ROOT)/usr/lib/fm $(INS.dir) -$(ROOT_TOPO_DIR): +$(ROOT)/usr/lib/fm/topo/%: $(ROOT)/usr/lib/fm/topo $(INS.dir) -$(ROOT_TOPO_DIR)/%: $(ROOT_TOPO_DIR) % - $(INS.file) +# +# Define the transitive set of rules to create a platform module's install dir +# within the proto area. This is used by all Makefile.<class> files. +# +$(ROOT)/usr/platform/%/lib/fm: + $(INS.dir) + +$(ROOT)/usr/platform/%/lib/fm/topo: $(ROOT)/usr/platform/%/lib/fm + $(INS.dir) + +$(ROOT)/usr/platform/%/lib/fm/topo/$(MODCLASS): $(ROOT)/usr/platform/%/lib/fm/topo + $(INS.dir) + +# +# Define the transitive set of rules to create platform.xml install directories +# within the proto area. This is used by all Makefile.xml files +# +$(ROOT)/usr/platform/%/lib/fm: + $(INS.dir) + +$(ROOT)/usr/platform/%/lib/fm/topo: $(ROOT)/usr/platform/%/lib/fm + $(INS.dir) diff --git a/usr/src/cmd/fm/schemes/cpu/Makefile.targ b/usr/src/lib/fm/topo/files/Makefile index 9a6d4cc380..8a76e32968 100644 --- a/usr/src/cmd/fm/schemes/cpu/Makefile.targ +++ b/usr/src/lib/fm/topo/files/Makefile @@ -24,13 +24,10 @@ # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" -# -include ../../Makefile.targ +sparc_SUBDIRS = sun4u sun4v SUNW,Sun-Fire SUNW,Sun-Fire-T200 SUNW,Sun-Fire-15000 +i386_SUBDIRS = i86pc -%.o: $(SCHEME_COMMON)/%.c - $(COMPILE.c) -o $@ $< - $(CTFCONVERT_O) +SUBDIRS = $($(MACH)_SUBDIRS) -%.ln: $(SCHEME_COMMON)/%.c - $(LINT.c) -erroff=E_BAD_PTR_CAST_ALIGN -v -c $< +include ../../Makefile.subdirs diff --git a/usr/src/lib/fm/topo/files/Makefile.file b/usr/src/lib/fm/topo/files/Makefile.file new file mode 100644 index 0000000000..da113c1af8 --- /dev/null +++ b/usr/src/lib/fm/topo/files/Makefile.file @@ -0,0 +1,63 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" + +include ../../../Makefile.lib +include ../../../../Makefile.lib + +DTDSRC = $(DTDFILE:%=../common/%) +DTDTARG = $(DTDFILE:%=%) +ROOT_DTDTARG = $(DTDTARG:%=$(ROOT)/usr/share/lib/xml/dtd/%) + +TOPOTARG = $(TOPOFILE:%=%) +common_TOPOTARG = $(ROOT)/usr/lib/fm/topo/$(TOPOTARG) +arch_TOPOTARG = $(ROOT)/usr/platform/$(ARCH)/lib/fm/topo/$(TOPOTARG) +platform_TOPOTARG = \ + $(PLATFORMS:%=$(ROOT)/usr/platform/%/lib/fm/topo/$(TOPOTARG)) +ROOT_TOPOTARG = $($(CLASS)_TOPOTARG) + +all: $(ROOT_DTDTARG) $(ROOT_TOPOTARG) + +clean: + $(RM) $(ROOT_DTDTARG) $(ROOT_TOPOTARG) + +clobber: clean + +check: $(CHECKHDRS) + +install_h lint _msg: + +$(ROOT_DTDTARG): $$(@D) + $(RM) $@; $(INS) -s -m 0444 -f $(@D) $(DTDSRC) + +$(ROOT_TOPOTARG): $$(@D) + $(RM) $@; $(INS) -s -m 0444 -f $(@D) $(TOPOTARG) + +install: $(ROOT_DTDTARG) $(ROOT_TOPOTARG) + +include ../../Makefile.rootdirs + diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V245/platform.topo b/usr/src/lib/fm/topo/files/SUNW,Sun-Fire-15000/Makefile index 6624b54bba..c876d2ff4a 100644 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V245/platform.topo +++ b/usr/src/lib/fm/topo/files/SUNW,Sun-Fire-15000/Makefile @@ -25,9 +25,10 @@ # #ident "%Z%%M% %I% %E% SMI" -/motherboard0/cpumodule0/cpu[0] -/motherboard0/cpumodule1/cpu[1] -/motherboard0/hostbridge0/pciexrc[0] - DEV = /pci@1e,600000 -/motherboard0/hostbridge0/pciexrc[1] - DEV = /pci@1f,700000 +PLATFORMS = SUNW,Sun-Fire-15000 +CLASS = platform +DTDFILE = +TOPOFILE = hc-topology.xml +SRCDIR = ../SUNW,Sun-Fire-15000 + +include ../Makefile.file diff --git a/usr/src/lib/fm/topo/files/SUNW,Sun-Fire-15000/hc-topology.xml b/usr/src/lib/fm/topo/files/SUNW,Sun-Fire-15000/hc-topology.xml new file mode 100644 index 0000000000..04eea53854 --- /dev/null +++ b/usr/src/lib/fm/topo/files/SUNW,Sun-Fire-15000/hc-topology.xml @@ -0,0 +1,48 @@ +<?xml version="1.0"?> +<!DOCTYPE topology SYSTEM "/usr/share/lib/xml/dtd/topology.dtd.1"> +<!-- + Copyright 2006 Sun Microsystems, Inc. All rights reserved. + Use is subject to license terms. + + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (the "License"). + You may not use this file except in compliance with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END + + ident "%Z%%M% %I% %E% SMI" +--> + +<topology name='SUNW,Sun-Fire-15000' scheme='hc'> + <range name='interconnect' min='0' max='0'> + <node instance='0'> + <propgroup name='protocol'> + <propval name='FRU' type='fmri' + value='hc:///interconnect=0' /> + </propgroup> + </node> + <dependents grouping='children'> + <range name='ioboard' min='0' max='17'> + <enum-method name='ioboard' version='1' + path='%r/usr/platform/SUNW,Sun-Fire-15000/lib/fm/topo/plugins' /> + </range> + <range name='cpu' min='0' max='100'> + <enum-method name='chip' version='1' + path='%r/usr/platform/sun4u/lib/fm/topo/plugins' /> + </range> + </dependents> + </range> +</topology> diff --git a/usr/src/lib/fm/topo/files/SUNW,Sun-Fire-T200/Makefile b/usr/src/lib/fm/topo/files/SUNW,Sun-Fire-T200/Makefile new file mode 100644 index 0000000000..51ac282be8 --- /dev/null +++ b/usr/src/lib/fm/topo/files/SUNW,Sun-Fire-T200/Makefile @@ -0,0 +1,34 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +PLATFORMS = SUNW,Sun-Fire-T200 +CLASS = platform +DTDFILE = +TOPOFILE = hc-topology.xml +SRCDIR = ../SUNW,Sun-Fire-T200 + +include ../Makefile.file diff --git a/usr/src/lib/fm/topo/files/SUNW,Sun-Fire-T200/hc-topology.xml b/usr/src/lib/fm/topo/files/SUNW,Sun-Fire-T200/hc-topology.xml new file mode 100644 index 0000000000..a2a4237a34 --- /dev/null +++ b/usr/src/lib/fm/topo/files/SUNW,Sun-Fire-T200/hc-topology.xml @@ -0,0 +1,74 @@ +<?xml version="1.0"?> +<!DOCTYPE topology SYSTEM "/usr/share/lib/xml/dtd/topology.dtd.1"> +<!-- + Copyright 2006 Sun Microsystems, Inc. All rights reserved. + Use is subject to license terms. + + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (the "License"). + You may not use this file except in compliance with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END + + ident "%Z%%M% %I% %E% SMI" +--> + +<topology name='SUNW,Sun-Fire-T200' scheme='hc'> + <range name='motherboard' min='0' max='0'> + <node instance='0'> + <propgroup name='protocol'> + <propval name='FRU' type='fmri' + value='hc:///motherboard=0' /> + <propval name='label' type='string' + value='MB' /> + </propgroup> + </node> + <dependents grouping='children'> + <range name='CMP' min='0' max='0'> + <node instance='0'> + <propgroup name='protocol'> + <propval name='FRU' type='fmri' + value='hc:///motherboard=0/CMP=0' /> + <propval name='label' type='string' + value='MB/CMP0' /> + </propgroup> + </node> + <dependents grouping='children'> + <range name='cpu' min='0' max='100'> + <enum-method name='chip' version='1' + path='%r/usr/platform/sun4v/lib/fm/topo/plugins' /> + </range> + </dependents> + </range> + </dependents> + </range> + <range name='ioboard' min='0' max='0'> + <node instance='0'> + <propgroup name='protocol'> + <propval name='FRU' type='fmri' + value='hc:///ioboard=0' /> + <propval name='label' type='string' + value='IOBD' /> + </propgroup> + </node> + <dependents grouping='children'> + <range name='hostbridge' min='0' max='254'> + <enum-method name='hostbridge' version='1' + path='%r/usr/platform/sun4v/lib/fm/topo/plugins' /> + </range> + </dependents> + </range> +</topology> diff --git a/usr/src/lib/fm/topo/files/SUNW,Sun-Fire/Makefile b/usr/src/lib/fm/topo/files/SUNW,Sun-Fire/Makefile new file mode 100644 index 0000000000..feba1c71fa --- /dev/null +++ b/usr/src/lib/fm/topo/files/SUNW,Sun-Fire/Makefile @@ -0,0 +1,34 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +PLATFORMS = SUNW,Sun-Fire +CLASS = platform +DTDFILE = +TOPOFILE = hc-topology.xml +SRCDIR = ../SUNW,Sun-Fire + +include ../Makefile.file diff --git a/usr/src/lib/fm/topo/files/SUNW,Sun-Fire/hc-topology.xml b/usr/src/lib/fm/topo/files/SUNW,Sun-Fire/hc-topology.xml new file mode 100644 index 0000000000..4dedd2237a --- /dev/null +++ b/usr/src/lib/fm/topo/files/SUNW,Sun-Fire/hc-topology.xml @@ -0,0 +1,48 @@ +<?xml version="1.0"?> +<!DOCTYPE topology SYSTEM "/usr/share/lib/xml/dtd/topology.dtd.1"> +<!-- + Copyright 2006 Sun Microsystems, Inc. All rights reserved. + Use is subject to license terms. + + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (the "License"). + You may not use this file except in compliance with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END + + ident "%Z%%M% %I% %E% SMI" +--> + +<topology name='SUNW,Sun-Fire' scheme='hc'> + <range name='centerplane' min='0' max='0'> + <node instance='0'> + <propgroup name='protocol'> + <propval name='FRU' type='fmri' + value='hc:///centerplane=0' /> + </propgroup> + </node> + <dependents grouping='children'> + <range name='ioboard' min='0' max='9'> + <enum-method name='ioboard' version='1' + path='%r/usr/platform/SUNW,Sun-Fire/lib/fm/topo/plugins' /> + </range> + <range name='cpu' min='0' max='100'> + <enum-method name='chip' version='1' + path='%r/usr/platform/sun4u/lib/fm/topo/plugins' /> + </range> + </dependents> + </range> +</topology> diff --git a/usr/src/lib/fm/topo/files/common/topology.dtd.1 b/usr/src/lib/fm/topo/files/common/topology.dtd.1 new file mode 100644 index 0000000000..fd772bcac8 --- /dev/null +++ b/usr/src/lib/fm/topo/files/common/topology.dtd.1 @@ -0,0 +1,295 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright 2006 Sun Microsystems, Inc. All rights reserved. + Use is subject to license terms. + + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License, Version 1.0 only + (the "License"). You may not use this file except in compliance + with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END + + ident "%Z%%M% %I% %E% SMI" +--> + +<!-- + Topology description DTD + + Most attributes are string values (or an individual string from a + restricted set), but attributes with a specific type requirement are + noted in the comment describing the element. +--> + +<!-- + XInclude support + + Topologies may be composed via the xi:include tag. + libtopo(3LIB) interfaces enforce that all composed topologies be of the + same scheme. +--> + +<!ELEMENT xi:include + (xi:fallback) > + +<!ATTLIST xi:include + href CDATA #REQUIRED + parse (xml|text) "xml" + encoding CDATA #IMPLIED + xmlns:xi CDATA #FIXED "http://www.w3.org/2001/XInclude" + > + +<!ELEMENT xi:fallback + ANY + > +<!ATTLIST xi:fallback + xmlns:xi CDATA #FIXED "http://www.w3.org/2001/XInclude" + > + +<!-- + data-stability + + This element associates an SMI stability level with the parent + element's data. See attributes(5) for an explanation of interface + stability levels. + + Its attribute is + + value The stability level of the parent element's data. +--> + +<!ELEMENT data-stability EMPTY> + +<!ATTLIST data-stability + value ( Standard | Stable | Evolving | Unstable | + External | Obsolete ) #REQUIRED > + +<!-- + name-stability + + This element associates an SMI stability level with the parent + element's name. See attributes(5) for an explanation of interface + stability levels. + + Its attribute is + + value The stability level of the parent element's name. +--> + +<!ELEMENT name-stability EMPTY> + +<!ATTLIST name-stability + value ( Standard | Stable | Evolving | Unstable | + External | Obsolete ) #REQUIRED > + +<!-- Properties and property groups --> + +<!-- + propval + + This element is for a singly valued property within a property + group. + + Its attributes are + + name The name of this property. + + type The data type for this property. + + value The value for this property. Must match type + restriction of type attribute. + + immutable This value remains unchanged for the lifetime of a snapshot. +--> + +<!ELEMENT propval + (name-stability?, data-stability?) > + +<!ATTLIST propval + name CDATA #REQUIRED + type ( int32 | uint32 | int64 | uint64 | + string | fmri ) #REQUIRED + value CDATA #REQUIRED + immutable ( true | false ) "true" > + +<!-- + propgroup + + This element is for a set of related properties on a topo node + It contains an optional stability element, as well as + zero or more property-containing elements. + + Its attributes are + + name The name of this property group. + +--> + +<!ELEMENT propgroup + ( name-stability?, propval* ) > + +<!ATTLIST propgroup + name CDATA #REQUIRED> + +<!-- Methods --> + +<!-- + argval + + An method argument. It has two attributes: + + name The name of the argument. + type The data type of the argument. +--> + +<!ELEMENT argval EMPTY> + +<!ATTLIST argval + name CDATA #REQUIRED + type CDATA #REQUIRED > + +<!-- + enum-method + + This element describes the enumeration method used to + populate a composition of topo nodes. Its interpretation is + left to the enumerator to which a particular topo node is + assigned. It contains a set of attributes, context, and an optional + stability element for the optional args that can be included. + + Its attributes are + + name Name of this method. The method names are + usually a defined interface of the enumerator to which a + topo instance assigned. + + path location of enumerator + + version Version of the enumeration API +--> + +<!ELEMENT enum-method + ( apply-method* ) > + +<!ATTLIST enum-method + name CDATA #REQUIRED + path CDATA #REQUIRED + version CDATA #REQUIRED > + +<!-- + apply-method + + This element describes one of the methods used by an enumerator + to act populate a composition of topo nodes. Its interpretation is + left to the enumerator to which a particular topo node is + assigned. It contains a set of attributes, context, and an optional + stability element for the optional args that can be included. + + Its attributes are + + name Name of this method. The method names are + usually a defined interface of the enumerator to which a + topo instance assigned. + + version Version of the function API + + description English description of the method +--> + +<!ELEMENT apply-method + ( name-stability?, argval* ) > + +<!ATTLIST apply-method + name CDATA #REQUIRED + version CDATA #REQUIRED + description CDATA #REQUIRED > + +<!-- + node + + This element identifies a known topology node. + + Its attributes are + + name The name of the topo node + + instance The instance number of the known node + +--> + +<!ELEMENT node + ( propgroup*, dependents* ) > + +<!ATTLIST node + instance CDATA #REQUIRED > + +<!-- + dependents + + Ranges may have a number of "dependent" ranges, linked to + the original range hierarchically as children or siblings. + + Its attribute is: + grouping "children", "siblings" +--> + +<!ELEMENT dependents + ( range | xi:include )+ > + +<!ATTLIST dependents + grouping ( children | siblings ) #REQUIRED > + +<!-- + range + + This element identifies a range of possible topology nodes. + + Its attributes are + + name The common name of all the possible topo nodes + + min The smallest allowed instance number for an + actual topo node. + + max The largest allowed instance number for an + actual topo node. + +--> + +<!ELEMENT range + ( enum-method?, node*, propgroup*, dependents* ) > + +<!ATTLIST range + name CDATA #REQUIRED + min CDATA #REQUIRED + max CDATA #REQUIRED > + +<!-- + topology + + This is the root-level for the scheme-specific topology + + Its attributes are: + name topology name + scheme "hc", "dev" +--> + +<!ELEMENT topology + (range* | xi:include*)> + +<!ATTLIST topology + name CDATA #REQUIRED + scheme (hc | dev) #REQUIRED > diff --git a/usr/src/lib/fm/topo/files/i86pc/Makefile b/usr/src/lib/fm/topo/files/i86pc/Makefile new file mode 100644 index 0000000000..fe24fb86ac --- /dev/null +++ b/usr/src/lib/fm/topo/files/i86pc/Makefile @@ -0,0 +1,34 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +ARCH = i86pc +CLASS = arch +DTDFILE = topology.dtd.1 +TOPOFILE = hc-topology.xml +SRCDIR = ../i86pc + +include ../Makefile.file diff --git a/usr/src/lib/fm/topo/files/i86pc/hc-topology.xml b/usr/src/lib/fm/topo/files/i86pc/hc-topology.xml new file mode 100644 index 0000000000..335e09708b --- /dev/null +++ b/usr/src/lib/fm/topo/files/i86pc/hc-topology.xml @@ -0,0 +1,50 @@ +<?xml version="1.0"?> +<!DOCTYPE topology SYSTEM "/usr/share/lib/xml/dtd/topology.dtd.1"> +<!-- + Copyright 2006 Sun Microsystems, Inc. All rights reserved. + Use is subject to license terms. + + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (the "License"). + You may not use this file except in compliance with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END + + ident "%Z%%M% %I% %E% SMI" +--> + +<topology name='i86pc' scheme='hc'> + + <range name='motherboard' min='0' max='0'> + <node instance='0'> + <propgroup name='protocol'> + <propval name='FRU' type='fmri' + value='hc:///motherboard=0' /> + <propval name='label' type='string' + value='MB' /> + </propgroup> + </node> + <dependents grouping='children'> + + <range name='chip' min='0' max='100'> + <enum-method name='chip' version='1' + path='%r/usr/platform/i86pc/lib/fm/topo/plugins' /> + </range> + + </dependents> + </range> + +</topology> diff --git a/usr/src/lib/fm/topo/files/sun4u/Makefile b/usr/src/lib/fm/topo/files/sun4u/Makefile new file mode 100644 index 0000000000..7f44ddd4f8 --- /dev/null +++ b/usr/src/lib/fm/topo/files/sun4u/Makefile @@ -0,0 +1,34 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +ARCH = sun4u +CLASS = arch +DTDFILE = topology.dtd.1 +TOPOFILE = hc-topology.xml +SRCDIR = ../sun4u + +include ../Makefile.file diff --git a/usr/src/lib/fm/topo/files/sun4u/hc-topology.xml b/usr/src/lib/fm/topo/files/sun4u/hc-topology.xml new file mode 100644 index 0000000000..a92532f575 --- /dev/null +++ b/usr/src/lib/fm/topo/files/sun4u/hc-topology.xml @@ -0,0 +1,50 @@ +<?xml version="1.0"?> +<!DOCTYPE topology SYSTEM "/usr/share/lib/xml/dtd/topology.dtd.1"> +<!-- + Copyright 2006 Sun Microsystems, Inc. All rights reserved. + Use is subject to license terms. + + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (the "License"). + You may not use this file except in compliance with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END + + ident "%Z%%M% %I% %E% SMI" +--> + +<topology name='sun4u' scheme='hc'> + <range name='motherboard' min='0' max='0'> + <node instance='0'> + <propgroup name='protocol'> + <propval name='FRU' type='fmri' + value='hc:///motherboard=0' /> + <propval name='label' type='string' + value='MB' /> + </propgroup> + </node> + <dependents grouping='children'> + <range name='hostbridge' min='0' max='254'> + <enum-method name='hostbridge' version='1' + path='%r/usr/platform/sun4u/lib/fm/topo/plugins' /> + </range> + <range name='cpu' min='0' max='100'> + <enum-method name='chip' version='1' + path='%r/usr/platform/sun4u/lib/fm/topo/plugins' /> + </range> + </dependents> + </range> +</topology> diff --git a/usr/src/lib/fm/topo/files/sun4v/Makefile b/usr/src/lib/fm/topo/files/sun4v/Makefile new file mode 100644 index 0000000000..1cbb332e04 --- /dev/null +++ b/usr/src/lib/fm/topo/files/sun4v/Makefile @@ -0,0 +1,34 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +ARCH = sun4v +CLASS = arch +DTDFILE = +TOPOFILE = hc-topology.xml +SRCDIR = ../sun4v + +include ../Makefile.file diff --git a/usr/src/lib/fm/topo/files/sun4v/hc-topology.xml b/usr/src/lib/fm/topo/files/sun4v/hc-topology.xml new file mode 100644 index 0000000000..abfba7d850 --- /dev/null +++ b/usr/src/lib/fm/topo/files/sun4v/hc-topology.xml @@ -0,0 +1,62 @@ +<?xml version="1.0"?> +<!DOCTYPE topology SYSTEM "/usr/share/lib/xml/dtd/topology.dtd.1"> +<!-- + Copyright 2006 Sun Microsystems, Inc. All rights reserved. + Use is subject to license terms. + + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (the "License"). + You may not use this file except in compliance with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END + + ident "%Z%%M% %I% %E% SMI" +--> + +<topology name='sun4v' scheme='hc'> + <range name='motherboard' min='0' max='0'> + <node instance='0'> + <propgroup name='protocol'> + <propval name='FRU' type='fmri' + value='hc:///motherboard=0' /> + <propval name='label' type='string' + value='MB' /> + </propgroup> + </node> + <dependents grouping='children'> + <range name='CMP' min='0' max='0'> + <node instance='0'> + <propgroup name='protocol'> + <propval name='FRU' type='fmri' + value='hc:///motherboard=0' /> + <propval name='label' type='string' + value='MB' /> + </propgroup> + </node> + <dependents grouping='children'> + <range name='cpu' min='0' max='100'> + <enum-method name='chip' version='1' + path='%r/usr/platform/sun4v/lib/fm/topo/plugins' /> + </range> + </dependents> + </range> + <range name='hostbridge' min='0' max='254'> + <enum-method name='hostbridge' version='1' + path='%r/usr/platform/sun4v/lib/fm/topo/plugins' /> + </range> + </dependents> + </range> +</topology> diff --git a/usr/src/lib/fm/libtopo/Makefile b/usr/src/lib/fm/topo/libtopo/Makefile index 8e4e1333c1..506f95de93 100644 --- a/usr/src/lib/fm/libtopo/Makefile +++ b/usr/src/lib/fm/topo/libtopo/Makefile @@ -20,18 +20,21 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" +include ../../../Makefile.lib include ../../Makefile.lib -include ../Makefile.lib -FMHDRS = libtopo.h libtopo_enum.h +FMHDRS = libtopo.h topo_mod.h HDRDIR = common -SUBDIRS = $(MACH) +MACH_SUBDIRS = $(MACH) + +SUBDIRS = $(MACH) + $(BUILD64)SUBDIRS += $(MACH64) all := TARGET = all @@ -57,5 +60,5 @@ spec $(SUBDIRS): FRC FRC: +include ../../../Makefile.targ include ../../Makefile.targ -include ../Makefile.targ diff --git a/usr/src/lib/fm/topo/libtopo/Makefile.com b/usr/src/lib/fm/topo/libtopo/Makefile.com new file mode 100644 index 0000000000..2022b7bbf5 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/Makefile.com @@ -0,0 +1,107 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" + +LIBRARY = libtopo.a +VERS = .1 + +BUILTINSRCS = \ + cpu.c \ + hc.c \ + mem.c \ + mod.c \ + pkg.c + +LIBSRCS = \ + topo_alloc.c \ + topo_builtin.c \ + topo_error.c \ + topo_file.c \ + topo_fmri.c \ + topo_list.c \ + topo_method.c \ + topo_mod.c \ + topo_module.c \ + topo_node.c \ + topo_nvl.c \ + topo_parse.c \ + topo_prop.c \ + topo_protocol.c \ + topo_rtld.c \ + topo_snap.c \ + topo_string.c \ + topo_subr.c \ + topo_tree.c \ + topo_xml.c + +OBJECTS = $(BUILTINSRCS:%.c=%.o) $(LIBSRCS:%.c=%.o) + +include ../../../../Makefile.lib +include ../../../Makefile.lib + +SRCS = $(BUILTINSRCS:%.c=../common/%.c) $(LIBSRCS:%.c=../common/%.c) +LIBS = $(DYNLIB) $(LINTLIB) + +SRCDIR = ../common +SPECMAPFILE = $(MAPDIR)/mapfile + +CLEANFILES += ../common/topo_error.c + +CPPFLAGS += -I../common -I/usr/include/libxml2 -I. +CFLAGS += $(CCVERBOSE) $(C_BIGPICFLAGS) +CFLAGS += -D_POSIX_PTHREAD_SEMANTICS +CFLAGS64 += $(CCVERBOSE) $(C_BIGPICFLAGS) + +LINTFLAGS = -msux +LINTFLAGS64 = -msux -Xarch=$(MACH64:sparcv9=v9) + +$(DYNLIB) := LDLIBS += -lnvpair -lelf -lumem -lxml2 -lkstat -luuid -lc + +$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) +$(LINTLIB) := LINTFLAGS = -nsvx +$(LINTLIB) := LINTFLAGS64 = -nsvx -Xarch=$(MACH64:sparcv9=v9) +$(LINTLIB) := LDLIBS += -lnvpair -lumem -lc + +.KEEP_STATE: + +all: $(LIBS) + +lint: $(LINTLIB) lintcheck + +pics/%.o: ../$(MACH)/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +%.o: ../common/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +../common/topo_error.c: ../common/mkerror.sh ../common/topo_error.h + sh ../common/mkerror.sh internal < ../common/topo_error.h > $@ + sh ../common/mkerror.sh external < ../common/topo_mod.h >> $@ + +include ../../../../Makefile.targ +include ../../../Makefile.targ diff --git a/usr/src/lib/fm/libtopo/amd64/Makefile b/usr/src/lib/fm/topo/libtopo/amd64/Makefile index 07fe45208f..15debba846 100644 --- a/usr/src/lib/fm/libtopo/amd64/Makefile +++ b/usr/src/lib/fm/topo/libtopo/amd64/Makefile @@ -20,13 +20,13 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" MAPDIR = ../spec/amd64 include ../Makefile.com -include ../../../Makefile.lib.64 +include ../../../../Makefile.lib.64 install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64) diff --git a/usr/src/lib/fm/topo/libtopo/common/cpu.c b/usr/src/lib/fm/topo/libtopo/common/cpu.c new file mode 100644 index 0000000000..f7dffc2434 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/cpu.c @@ -0,0 +1,433 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <errno.h> +#include <kstat.h> +#include <limits.h> +#include <strings.h> +#include <unistd.h> +#include <fm/topo_mod.h> +#include <sys/fm/protocol.h> + +#include <topo_error.h> + +typedef struct cpu_node { + kstat_ctl_t *cn_kc; + kstat_t **cn_cpustats; + uint_t cn_ncpustats; +} cpu_node_t; + +static int cpu_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, + topo_instance_t, void *); +static void cpu_release(topo_mod_t *, tnode_t *); +static int cpu_nvl2str(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); +static int cpu_str2nvl(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); +static int cpu_present(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); +static int cpu_unusable(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); +static int cpu_contains(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); +static int cpu_expand(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); +static int cpu_fmri_asru(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); +static nvlist_t *fmri_create(topo_mod_t *, uint32_t, uint8_t, char *); + +#define CPU_VERSION TOPO_VERSION + +static const topo_method_t cpu_methods[] = { + { TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION, + TOPO_STABILITY_INTERNAL, cpu_nvl2str }, + { TOPO_METH_STR2NVL, TOPO_METH_STR2NVL_DESC, TOPO_METH_STR2NVL_VERSION, + TOPO_STABILITY_INTERNAL, cpu_str2nvl }, + { TOPO_METH_PRESENT, TOPO_METH_PRESENT_DESC, TOPO_METH_PRESENT_VERSION, + TOPO_STABILITY_INTERNAL, cpu_present }, + { TOPO_METH_CONTAINS, TOPO_METH_CONTAINS_DESC, + TOPO_METH_CONTAINS_VERSION, TOPO_STABILITY_INTERNAL, cpu_contains }, + { TOPO_METH_UNUSABLE, TOPO_METH_UNUSABLE_DESC, + TOPO_METH_UNUSABLE_VERSION, TOPO_STABILITY_INTERNAL, cpu_unusable }, + { TOPO_METH_EXPAND, TOPO_METH_EXPAND_DESC, + TOPO_METH_EXPAND_VERSION, TOPO_STABILITY_INTERNAL, cpu_expand }, + { TOPO_METH_ASRU_COMPUTE, TOPO_METH_ASRU_COMPUTE_DESC, + TOPO_METH_ASRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL, + cpu_fmri_asru }, + { NULL } +}; + +static const topo_modinfo_t cpu_info = + { "cpu", CPU_VERSION, cpu_enum, cpu_release }; + +void +cpu_init(topo_mod_t *mod) +{ + cpu_node_t *cpuip; + + topo_mod_setdebug(mod, TOPO_DBG_ALL); + topo_mod_dprintf(mod, "initializing cpu builtin\n"); + + if ((cpuip = topo_mod_zalloc(mod, sizeof (cpu_node_t))) == NULL) + return; + + if ((cpuip->cn_kc = kstat_open()) == NULL) { + topo_mod_dprintf(mod, "kstat_open failed: %s\n", + strerror(errno)); + topo_mod_free(mod, cpuip, sizeof (cpu_node_t)); + return; + } + + cpuip->cn_ncpustats = sysconf(_SC_CPUID_MAX); + if ((cpuip->cn_cpustats = topo_mod_zalloc(mod, ( + cpuip->cn_ncpustats + 1) * sizeof (kstat_t *))) == NULL) { + (void) kstat_close(cpuip->cn_kc); + topo_mod_free(mod, cpuip, sizeof (cpu_node_t)); + return; + } + + if (topo_mod_register(mod, &cpu_info, (void *)cpuip) != 0) { + topo_mod_dprintf(mod, "failed to register cpu_info: " + "%s\n", topo_mod_errmsg(mod)); + topo_mod_free(mod, cpuip->cn_cpustats, + (cpuip->cn_ncpustats + 1) * sizeof (kstat_t *)); + (void) kstat_close(cpuip->cn_kc); + topo_mod_free(mod, cpuip, sizeof (cpu_node_t)); + return; + } +} + +void +cpu_fini(topo_mod_t *mod) +{ + cpu_node_t *cpuip; + + cpuip = topo_mod_private(mod); + + if (cpuip->cn_cpustats != NULL) + topo_mod_free(mod, cpuip->cn_cpustats, + (cpuip->cn_ncpustats + 1) * sizeof (kstat_t *)); + + (void) kstat_close(cpuip->cn_kc); + topo_mod_free(mod, cpuip, sizeof (cpu_node_t)); + + topo_mod_unregister(mod); +} + +static int +cpu_kstat_init(cpu_node_t *cpuip, int i) +{ + kstat_t *ksp; + + if (cpuip->cn_cpustats[i] == NULL) { + if ((ksp = kstat_lookup(cpuip->cn_kc, "cpu_info", i, NULL)) == + NULL || kstat_read(cpuip->cn_kc, ksp, NULL) < 0) + return (-1); + + cpuip->cn_cpustats[i] = ksp; + } else { + ksp = cpuip->cn_cpustats[i]; + } + + return (ksp->ks_instance); +} + +/*ARGSUSED*/ +static int +cpu_create(topo_mod_t *mod, tnode_t *rnode, const char *name, + topo_instance_t min, topo_instance_t max, cpu_node_t *cpuip) +{ + int i; + processorid_t cpu_id; + char *s, sbuf[21]; + kstat_named_t *ks; + nvlist_t *fmri; + + for (i = 0; i <= cpuip->cn_ncpustats; i++) { + + if ((cpu_id = cpu_kstat_init(cpuip, i)) < 0) + continue; + + if ((ks = kstat_data_lookup(cpuip->cn_cpustats[i], + "device_ID")) != NULL) { + (void) snprintf(sbuf, 21, "%llX", ks->value.ui64); + s = sbuf; + } else { + s = NULL; + } + + if ((fmri = fmri_create(mod, cpu_id, 0, s)) == NULL) + continue; + (void) topo_node_bind(mod, rnode, name, cpu_id, fmri, NULL); + nvlist_free(fmri); + } + + return (0); +} + + +/*ARGSUSED*/ +static int +cpu_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, + topo_instance_t min, topo_instance_t max, void *arg) +{ + cpu_node_t *cpuip = (cpu_node_t *)arg; + + if (topo_node_range_create(mod, pnode, "cpu", 0, + cpuip->cn_ncpustats + 1) < 0) { + topo_mod_dprintf(mod, "cpu enumeration failed to create cpu " + "range [0-%d]: %s\n", cpuip->cn_ncpustats + 1, + topo_mod_errmsg(mod)); + return (-1); /* mod_errno set */ + } + + (void) topo_method_register(mod, pnode, cpu_methods); + + return (cpu_create(mod, pnode, name, min, max, cpuip)); +} + +static void +cpu_release(topo_mod_t *mod, tnode_t *node) +{ + topo_method_unregister_all(mod, node); +} + +ssize_t +fmri_nvl2str(nvlist_t *nvl, uint8_t version, char *buf, size_t buflen) +{ + int rc; + uint32_t cpuid; + uint64_t serint; + char *serstr; + + if (version == CPU_SCHEME_VERSION0) { + if (nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0 || + nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, &serint) + != 0) + return (0); + + return (snprintf(buf, buflen, "cpu:///%s=%u/%s=%llX", + FM_FMRI_CPU_ID, cpuid, FM_FMRI_CPU_SERIAL_ID, + (u_longlong_t)serint)); + } else if (version == CPU_SCHEME_VERSION1) { + if (nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0) + return (0); + + /* + * Serial number is an optional element + */ + if ((rc = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID, + &serstr)) != 0) + if (rc == ENOENT) + return (snprintf(buf, buflen, "cpu:///%s=%u", + FM_FMRI_CPU_ID, cpuid)); + else + return (0); + else + return (snprintf(buf, buflen, "cpu:///%s=%u/%s=%s", + FM_FMRI_CPU_ID, cpuid, FM_FMRI_CPU_SERIAL_ID, + serstr)); + + } else { + return (0); + } +} + +/*ARGSUSED*/ +static int +cpu_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + uint8_t fver; + ssize_t len; + char *name; + + if (version > TOPO_METH_NVL2STR_VERSION) + return (topo_mod_seterrno(mod, EMOD_VER_NEW)); + + if (nvlist_lookup_uint8(in, FM_VERSION, &fver) != 0) + return (topo_mod_seterrno(mod, EMOD_FMRI_VERSION)); + + if ((len = fmri_nvl2str(in, fver, NULL, 0)) == 0 || + (name = topo_mod_alloc(mod, len + 1)) == NULL || + fmri_nvl2str(in, fver, name, len + 1) == 0) + return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); + + if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) < 0) { + topo_mod_free(mod, name, len + 1); + return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); + } + + if (nvlist_add_string(*out, "fmri-string", name) != 0) { + topo_mod_free(mod, name, len + 1); + return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); + } + topo_mod_free(mod, name, len + 1); + + return (0); +} + +/*ARGSUSED*/ +static int +cpu_str2nvl(topo_mod_t *mod, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + int err; + uint32_t cpuid; + char *str, *s, *end; + char *serial = NULL; + nvlist_t *fmri; + + if (version > TOPO_METH_STR2NVL_VERSION) + return (topo_mod_seterrno(mod, EMOD_VER_NEW)); + + if (nvlist_lookup_string(in, "fmri-string", &str) != 0) + return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); + + /* We're expecting a string version of a cpu scheme FMRI */ + if (strncmp(str, "cpu:///", 7) != 0) + return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); + + s = strchr(str + 7, '='); + if (s == NULL) + return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); + + ++s; + cpuid = strtoul(s, &end, 0); + + if (cpuid == ULONG_MAX && errno == ERANGE) + return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); + + if (*(s = end) == '/') { + s = strchr(s, '='); + ++s; + serial = s; + } + + if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0) + return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); + + err = nvlist_add_uint8(fmri, FM_VERSION, CPU_SCHEME_VERSION1); + err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU); + err |= nvlist_add_uint32(fmri, FM_FMRI_CPU_ID, cpuid); + err |= nvlist_add_uint8(fmri, FM_FMRI_CPU_MASK, 0); + if (serial != NULL) + err |= nvlist_add_string(fmri, FM_FMRI_CPU_SERIAL_ID, + serial); + + if (err != 0) { + nvlist_free(fmri); + return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); + } + *out = fmri; + + return (0); +} + +/*ARGSUSED*/ +static int +cpu_present(topo_mod_t *mod, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + return (topo_mod_seterrno(mod, EMOD_METHOD_NOTSUP)); +} + +/*ARGSUSED*/ +static int +cpu_contains(topo_mod_t *mod, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + return (topo_mod_seterrno(mod, EMOD_METHOD_NOTSUP)); +} + +/*ARGSUSED*/ +static int +cpu_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + return (topo_mod_seterrno(mod, EMOD_METHOD_NOTSUP)); +} + +/*ARGSUSED*/ +static int +cpu_expand(topo_mod_t *mod, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + return (topo_mod_seterrno(mod, EMOD_METHOD_NOTSUP)); +} + +static nvlist_t * +fmri_create(topo_mod_t *mod, uint32_t cpu_id, uint8_t cpumask, char *s) +{ + int err; + nvlist_t *fmri; + + if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0) { + (void) topo_mod_seterrno(mod, EMOD_FMRI_NVL); + return (NULL); + } + + err = nvlist_add_uint8(fmri, FM_VERSION, FM_CPU_SCHEME_VERSION); + err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU); + err |= nvlist_add_uint32(fmri, FM_FMRI_CPU_ID, cpu_id); + err |= nvlist_add_uint8(fmri, FM_FMRI_CPU_MASK, cpumask); + if (s != NULL) + err |= nvlist_add_string(fmri, FM_FMRI_CPU_SERIAL_ID, s); + if (err != 0) { + nvlist_free(fmri); + (void) topo_mod_seterrno(mod, EMOD_FMRI_NVL); + return (NULL); + } + + return (fmri); +} + +/*ARGSUSED*/ +static int +cpu_fmri_asru(topo_mod_t *mod, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + int rc; + uint32_t cpu_id; + uint8_t cpumask = 0; + char *serial = NULL; + + if ((rc = nvlist_lookup_uint32(in, FM_FMRI_CPU_ID, &cpu_id)) != 0) { + if (rc == ENOENT) + return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); + else + return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); + } + + (void) nvlist_lookup_string(in, FM_FMRI_CPU_SERIAL_ID, &serial); + (void) nvlist_lookup_uint8(in, FM_FMRI_CPU_MASK, &cpumask); + + *out = fmri_create(mod, cpu_id, cpumask, serial); + + return (0); +} diff --git a/usr/src/lib/fm/topo/libtopo/common/cpu.h b/usr/src/lib/fm/topo/libtopo/common/cpu.h new file mode 100644 index 0000000000..587609d471 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/cpu.h @@ -0,0 +1,43 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef CPU_H +#define CPU_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +extern void cpu_init(topo_mod_t *); +extern void cpu_fini(topo_mod_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* CPU_H */ diff --git a/usr/src/lib/fm/topo/libtopo/common/hc.c b/usr/src/lib/fm/topo/libtopo/common/hc.c new file mode 100644 index 0000000000..f71f1f0609 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/hc.c @@ -0,0 +1,776 @@ +/* + * + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <alloca.h> +#include <limits.h> +#include <fm/topo_mod.h> +#include <sys/param.h> +#include <sys/systeminfo.h> +#include <sys/fm/protocol.h> +#include <topo_parse.h> + +#include <hc_canon.h> + +#define HC "hc" +#define HC_VERSION TOPO_VERSION + +static int hc_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, + topo_instance_t, void *); +static void hc_release(topo_mod_t *, tnode_t *); +static int hc_contains(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); +static int hc_present(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); +static int hc_unusable(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); +static int hc_fmri_nvl2str(topo_mod_t *, tnode_t *, topo_version_t, + nvlist_t *, nvlist_t **); +static int hc_fmri_str2nvl(topo_mod_t *, tnode_t *, topo_version_t, + nvlist_t *, nvlist_t **); +static int hc_compare(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); +static int hc_fmri_create_meth(topo_mod_t *, tnode_t *, topo_version_t, + nvlist_t *, nvlist_t **); + +static nvlist_t *hc_fmri_create(topo_mod_t *, nvlist_t *, int, const char *, + topo_instance_t inst, const nvlist_t *, const char *, const char *, + const char *); + +const topo_method_t hc_methods[] = { + { "hc_contains", "Hardware Component Contains", HC_VERSION, + TOPO_STABILITY_INTERNAL, hc_contains }, + { "hc_present", "Hardware Component Present", HC_VERSION, + TOPO_STABILITY_INTERNAL, hc_present }, + { "hc_unusable", "Hardware Component Unusable", HC_VERSION, + TOPO_STABILITY_INTERNAL, hc_unusable }, + { TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION, + TOPO_STABILITY_INTERNAL, hc_fmri_nvl2str }, + { TOPO_METH_STR2NVL, TOPO_METH_STR2NVL_DESC, TOPO_METH_STR2NVL_VERSION, + TOPO_STABILITY_INTERNAL, hc_fmri_str2nvl }, + { TOPO_METH_COMPARE, TOPO_METH_COMPARE_DESC, TOPO_METH_COMPARE_VERSION, + TOPO_STABILITY_INTERNAL, hc_compare }, + { TOPO_METH_FMRI, TOPO_METH_FMRI_DESC, TOPO_METH_FMRI_VERSION, + TOPO_STABILITY_INTERNAL, hc_fmri_create_meth }, + { NULL } +}; + +const topo_modinfo_t hc_info = + { HC, HC_VERSION, hc_enum, hc_release }; + +void +hc_init(topo_mod_t *mp) +{ + /* + * Turn on module debugging output + */ + topo_mod_setdebug(mp, TOPO_DBG_ALL); + topo_mod_dprintf(mp, "initializing hc builtin\n"); + + if (topo_mod_register(mp, &hc_info, NULL) != 0) { + topo_mod_dprintf(mp, "failed to register hc: " + "%s\n", topo_mod_errmsg(mp)); + } +} + +void +hc_fini(topo_mod_t *mp) +{ + topo_mod_unregister(mp); +} + +/*ARGSUSED*/ +int +hc_enum(topo_mod_t *mp, tnode_t *pnode, const char *name, topo_instance_t min, + topo_instance_t max, void *notused) +{ + nvlist_t *pfmri = NULL; + nvlist_t *nvl; + int err; + /* + * Register root node methods + */ + if (strcmp(name, HC) == 0) { + (void) topo_method_register(mp, pnode, hc_methods); + return (0); + } + if (min != max) { + topo_mod_dprintf(mp, + "Request to enumerate %s component with an " + "ambiguous instance number, min (%d) != max (%d).\n", + HC, min, max); + return (topo_mod_seterrno(mp, EINVAL)); + } + + (void) topo_node_resource(pnode, &pfmri, &err); + nvl = hc_fmri_create(mp, pfmri, FM_HC_SCHEME_VERSION, name, min, + NULL, NULL, NULL, NULL); + nvlist_free(pfmri); /* callee ignores NULLs */ + if (nvl == NULL) + return (-1); + + if (topo_node_bind(mp, pnode, name, min, nvl, NULL) == NULL) { + topo_mod_dprintf(mp, "topo_node_bind failed: %s\n", + topo_strerror(topo_mod_errno(mp))); + nvlist_free(nvl); + return (-1); + } + nvlist_free(nvl); + return (0); +} + +/*ARGSUSED*/ +static void +hc_release(topo_mod_t *mp, tnode_t *node) +{ + topo_method_unregister_all(mp, node); +} + +/*ARGSUSED*/ +static int +hc_contains(topo_mod_t *mp, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + return (topo_mod_seterrno(mp, EMOD_METHOD_NOTSUP)); +} + +/*ARGSUSED*/ +static int +hc_present(topo_mod_t *mp, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + return (topo_mod_seterrno(mp, EMOD_METHOD_NOTSUP)); +} + +/*ARGSUSED*/ +static int +hc_unusable(topo_mod_t *mp, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + return (topo_mod_seterrno(mp, EMOD_METHOD_NOTSUP)); +} + +/*ARGSUSED*/ +static int +hc_compare(topo_mod_t *mp, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + uint8_t v1, v2; + nvlist_t *nv1, *nv2; + nvlist_t **hcp1, **hcp2; + int err, i; + uint_t nhcp1, nhcp2; + + if (version > TOPO_METH_COMPARE_VERSION) + return (topo_mod_seterrno(mp, EMOD_VER_NEW)); + + if (nvlist_lookup_nvlist(in, "nv1", &nv1) != 0 || + nvlist_lookup_nvlist(in, "nv2", &nv2) != 0) + return (topo_mod_seterrno(mp, EMOD_METHOD_INVAL)); + + if (nvlist_lookup_uint8(nv1, FM_VERSION, &v1) != 0 || + nvlist_lookup_uint8(nv2, FM_VERSION, &v2) != 0 || + v1 > FM_HC_SCHEME_VERSION || v2 > FM_HC_SCHEME_VERSION) + return (topo_mod_seterrno(mp, EMOD_FMRI_VERSION)); + + err = nvlist_lookup_nvlist_array(nv1, FM_FMRI_HC_LIST, &hcp1, &nhcp1); + err |= nvlist_lookup_nvlist_array(nv2, FM_FMRI_HC_LIST, &hcp2, &nhcp2); + if (err != 0) + return (topo_mod_seterrno(mp, EMOD_FMRI_NVL)); + + if (nhcp1 != nhcp2) + return (0); + + for (i = 0; i < nhcp1; i++) { + char *nm1 = NULL; + char *nm2 = NULL; + char *id1 = NULL; + char *id2 = NULL; + + (void) nvlist_lookup_string(hcp1[i], FM_FMRI_HC_NAME, &nm1); + (void) nvlist_lookup_string(hcp2[i], FM_FMRI_HC_NAME, &nm2); + (void) nvlist_lookup_string(hcp1[i], FM_FMRI_HC_ID, &id1); + (void) nvlist_lookup_string(hcp2[i], FM_FMRI_HC_ID, &id2); + if (nm1 == NULL || nm2 == NULL || id1 == NULL || id2 == NULL) + return (topo_mod_seterrno(mp, EMOD_FMRI_NVL)); + + if (strcmp(nm1, nm2) == 0 && strcmp(id1, id2) == 0) + continue; + + return (0); + } + + return (1); +} + +/* + * buf_append -- Append str to buf (if it's non-NULL). Place prepend + * in buf in front of str and append behind it (if they're non-NULL). + * Continue to update size even if we run out of space to actually + * stuff characters in the buffer. + */ +static void +buf_append(ssize_t *sz, char *buf, size_t buflen, char *str, + char *prepend, char *append) +{ + ssize_t left; + + if (str == NULL) + return; + + if (buflen == 0 || (left = buflen - *sz) < 0) + left = 0; + + if (buf != NULL && left != 0) + buf += *sz; + + if (prepend == NULL && append == NULL) + *sz += snprintf(buf, left, "%s", str); + else if (append == NULL) + *sz += snprintf(buf, left, "%s%s", prepend, str); + else if (prepend == NULL) + *sz += snprintf(buf, left, "%s%s", str, append); + else + *sz += snprintf(buf, left, "%s%s%s", prepend, str, append); +} + +static ssize_t +fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen) +{ + nvlist_t **hcprs = NULL; + nvlist_t *anvl = NULL; + uint8_t version; + ssize_t size = 0; + uint_t hcnprs; + char *achas = NULL; + char *adom = NULL; + char *aprod = NULL; + char *asrvr = NULL; + char *ahost = NULL; + char *serial = NULL; + char *part = NULL; + char *root = NULL; + char *rev = NULL; + int more_auth = 0; + int err, i; + + if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || + version > FM_HC_SCHEME_VERSION) + return (-1); + + /* Get authority, if present */ + err = nvlist_lookup_nvlist(nvl, FM_FMRI_AUTHORITY, &anvl); + if (err != 0 && err != ENOENT) + return (-1); + + if ((err = nvlist_lookup_string(nvl, FM_FMRI_HC_ROOT, &root)) != 0) + return (-1); + + err = nvlist_lookup_nvlist_array(nvl, FM_FMRI_HC_LIST, &hcprs, &hcnprs); + if (err != 0 || hcprs == NULL) + return (-1); + + if (anvl != NULL) { + (void) nvlist_lookup_string(anvl, + FM_FMRI_AUTH_PRODUCT, &aprod); + (void) nvlist_lookup_string(anvl, + FM_FMRI_AUTH_CHASSIS, &achas); + (void) nvlist_lookup_string(anvl, + FM_FMRI_AUTH_DOMAIN, &adom); + (void) nvlist_lookup_string(anvl, + FM_FMRI_AUTH_SERVER, &asrvr); + (void) nvlist_lookup_string(anvl, + FM_FMRI_AUTH_HOST, &ahost); + if (aprod != NULL) + more_auth++; + if (achas != NULL) + more_auth++; + if (adom != NULL) + more_auth++; + if (asrvr != NULL) + more_auth++; + if (ahost != NULL) + more_auth++; + } + + (void) nvlist_lookup_string(nvl, FM_FMRI_HC_SERIAL_ID, &serial); + (void) nvlist_lookup_string(nvl, FM_FMRI_HC_PART, &part); + (void) nvlist_lookup_string(nvl, FM_FMRI_HC_REVISION, &rev); + + /* hc:// */ + buf_append(&size, buf, buflen, FM_FMRI_SCHEME_HC, NULL, "://"); + + /* authority, if any */ + if (aprod != NULL) + buf_append(&size, buf, buflen, aprod, FM_FMRI_AUTH_PRODUCT "=", + --more_auth > 0 ? "," : NULL); + if (achas != NULL) + buf_append(&size, buf, buflen, achas, FM_FMRI_AUTH_CHASSIS "=", + --more_auth > 0 ? "," : NULL); + if (adom != NULL) + buf_append(&size, buf, buflen, adom, FM_FMRI_AUTH_DOMAIN "=", + --more_auth > 0 ? "," : NULL); + if (asrvr != NULL) + buf_append(&size, buf, buflen, asrvr, FM_FMRI_AUTH_SERVER "=", + --more_auth > 0 ? "," : NULL); + if (ahost != NULL) + buf_append(&size, buf, buflen, ahost, FM_FMRI_AUTH_HOST "=", + NULL); + + /* separating slash */ + if (serial != NULL || part != NULL || rev != NULL) + buf_append(&size, buf, buflen, "/", NULL, NULL); + + /* hardware-id part */ + buf_append(&size, buf, buflen, serial, ":" FM_FMRI_HC_SERIAL_ID "=", + NULL); + buf_append(&size, buf, buflen, part, ":" FM_FMRI_HC_PART "=", NULL); + buf_append(&size, buf, buflen, rev, ":" FM_FMRI_HC_REVISION "=", NULL); + + /* separating slash */ + buf_append(&size, buf, buflen, "/", NULL, NULL); + + /* hc-root */ + buf_append(&size, buf, buflen, root, NULL, NULL); + + /* all the pairs */ + for (i = 0; i < hcnprs; i++) { + char *nm = NULL; + char *id = NULL; + + if (i > 0) + buf_append(&size, buf, buflen, "/", NULL, NULL); + (void) nvlist_lookup_string(hcprs[i], FM_FMRI_HC_NAME, &nm); + (void) nvlist_lookup_string(hcprs[i], FM_FMRI_HC_ID, &id); + if (nm == NULL || id == NULL) + return (0); + buf_append(&size, buf, buflen, nm, NULL, "="); + buf_append(&size, buf, buflen, id, NULL, NULL); + } + + return (size); +} + +/*ARGSUSED*/ +static int +hc_fmri_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version, + nvlist_t *nvl, nvlist_t **out) +{ + ssize_t len; + char *name = NULL; + nvlist_t *fmristr; + + if (version > TOPO_METH_NVL2STR_VERSION) + return (topo_mod_seterrno(mod, EMOD_VER_NEW)); + + if ((len = fmri_nvl2str(nvl, NULL, 0)) == 0 || + (name = topo_mod_alloc(mod, len + 1)) == NULL || + fmri_nvl2str(nvl, name, len + 1) == 0) { + if (name != NULL) + topo_mod_free(mod, name, len + 1); + return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); + } + + if (topo_mod_nvalloc(mod, &fmristr, NV_UNIQUE_NAME) != 0) + return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); + if (nvlist_add_string(fmristr, "fmri-string", name) != 0) { + topo_mod_free(mod, name, len + 1); + nvlist_free(fmristr); + return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); + } + topo_mod_free(mod, name, len + 1); + *out = fmristr; + + return (0); +} + +static nvlist_t * +hc_base_fmri_create(topo_mod_t *mod, const nvlist_t *auth, const char *part, + const char *rev, const char *serial) +{ + nvlist_t *fmri; + int err = 0; + + /* + * Create base HC nvlist + */ + if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0) + return (NULL); + + err = nvlist_add_uint8(fmri, FM_VERSION, FM_HC_SCHEME_VERSION); + err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC); + err |= nvlist_add_string(fmri, FM_FMRI_HC_ROOT, ""); + if (err != 0) { + nvlist_free(fmri); + return (NULL); + } + + /* + * Add optional payload members + */ + if (serial != NULL) + (void) nvlist_add_string(fmri, FM_FMRI_HC_SERIAL_ID, serial); + if (part != NULL) + (void) nvlist_add_string(fmri, FM_FMRI_HC_PART, part); + if (rev != NULL) + (void) nvlist_add_string(fmri, FM_FMRI_HC_REVISION, rev); + if (auth != NULL) + (void) nvlist_add_nvlist(fmri, FM_FMRI_AUTHORITY, + (nvlist_t *)auth); + + return (fmri); +} + +static nvlist_t ** +make_hc_pairs(topo_mod_t *mod, char *fromstr, int *num) +{ + nvlist_t **pa; + char *starti, *startn, *endi, *endi2; + char *ne, *ns; + char *cname; + char *find; + char *cid; + int nslashes = 0; + int npairs = 0; + int i, e; + + /* + * Count equal signs and slashes to determine how many + * hc-pairs will be present in the final FMRI. There should + * be at least as many slashes as equal signs. There can be + * more, though if the string after an = includes them. + */ + find = fromstr; + while ((ne = strchr(find, '=')) != NULL) { + find = ne + 1; + npairs++; + } + + find = fromstr; + while ((ns = strchr(find, '/')) != NULL) { + find = ns + 1; + nslashes++; + } + + /* + * Do we appear to have a well-formed string version of the FMRI? + */ + if (nslashes < npairs || npairs == 0) + return (NULL); + + *num = npairs; + + find = fromstr; + + pa = topo_mod_alloc(mod, npairs * sizeof (nvlist_t *)); + /* + * We go through a pretty complicated procedure to find the + * name and id for each pair. That's because, unfortunately, + * we have some ids that can have slashes within them. So + * we can't just search for the next slash after the equal sign + * and decide that starts a new pair. Instead we have to find + * an equal sign for the next pair and work our way back to the + * slash from there. + */ + for (i = 0; i < npairs; i++) { + pa[i] = NULL; + startn = strchr(find, '/'); + if (startn == NULL) + break; + startn++; + starti = strchr(find, '='); + if (starti == NULL) + break; + *starti = '\0'; + cname = topo_mod_strdup(mod, startn); + *starti++ = '='; + endi = strchr(starti, '='); + if (endi != NULL) { + *endi = '\0'; + endi2 = strrchr(starti, '/'); + if (endi2 == NULL) + break; + *endi = '='; + *endi2 = '\0'; + cid = topo_mod_strdup(mod, starti); + *endi2 = '/'; + find = endi2; + } else { + cid = topo_mod_strdup(mod, starti); + find = starti + strlen(starti); + } + if ((e = topo_mod_nvalloc(mod, &pa[i], NV_UNIQUE_NAME)) != 0) { + topo_mod_strfree(mod, cname); + topo_mod_strfree(mod, cid); + break; + } + + e = nvlist_add_string(pa[i], FM_FMRI_HC_NAME, cname); + e |= nvlist_add_string(pa[i], FM_FMRI_HC_ID, cid); + + topo_mod_strfree(mod, cname); + topo_mod_strfree(mod, cid); + + if (e != 0) { + break; + } + } + if (i < npairs) { + while (i >= 0) + if (pa[i--] != NULL) + nvlist_free(pa[i + 1]); + topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *)); + return (NULL); + } + + return (pa); +} + +/*ARGSUSED*/ +static int +hc_fmri_str2nvl(topo_mod_t *mod, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + nvlist_t **pa = NULL; + nvlist_t *nf = NULL; + char *str, *copy; + int npairs; + int i, e; + + if (version > TOPO_METH_STR2NVL_VERSION) + return (topo_mod_seterrno(mod, EMOD_VER_NEW)); + + if (nvlist_lookup_string(in, "fmri-string", &str) != 0) + return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); + + /* We're expecting a string version of an hc scheme FMRI */ + if (strncmp(str, "hc:///", 6) != 0) + return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); + + copy = topo_mod_strdup(mod, str + 5); + if ((pa = make_hc_pairs(mod, copy, &npairs)) == NULL) { + topo_mod_strfree(mod, copy); + return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); + } + topo_mod_strfree(mod, copy); + + if ((nf = hc_base_fmri_create(mod, NULL, NULL, NULL, NULL)) == NULL) + goto hcfmbail; + if ((e = nvlist_add_uint32(nf, FM_FMRI_HC_LIST_SZ, npairs)) == 0) + e = nvlist_add_nvlist_array(nf, FM_FMRI_HC_LIST, pa, npairs); + if (e != 0) { + topo_mod_dprintf(mod, "construction of new hc nvl failed"); + goto hcfmbail; + } + for (i = 0; i < npairs; i++) + nvlist_free(pa[i]); + topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *)); + *out = nf; + + return (0); + +hcfmbail: + if (nf != NULL) + nvlist_free(nf); + for (i = 0; i < npairs; i++) + nvlist_free(pa[i]); + topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *)); + return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); +} + +static nvlist_t * +hc_list_create(topo_mod_t *mod, const char *name, char *inst) +{ + int err; + nvlist_t *hc; + + if (topo_mod_nvalloc(mod, &hc, NV_UNIQUE_NAME) != 0) + return (NULL); + + err = nvlist_add_string(hc, FM_FMRI_HC_NAME, name); + err |= nvlist_add_string(hc, FM_FMRI_HC_ID, inst); + if (err != 0) { + nvlist_free(hc); + return (NULL); + } + + return (hc); +} + +static nvlist_t * +hc_create_seterror(topo_mod_t *mod, nvlist_t **hcl, int n, nvlist_t *fmri, + int err) +{ + int i; + + if (hcl != NULL) { + for (i = 0; i < n + 1; ++i) + nvlist_free(hcl[i]); + + topo_mod_free(mod, hcl, sizeof (nvlist_t *) * (n + 1)); + } + + nvlist_free(fmri); + + (void) topo_mod_seterrno(mod, err); + + topo_mod_dprintf(mod, "unable to create hc FMRI: %s\n", + topo_mod_errmsg(mod)); + + return (NULL); +} + +static int +hc_name_canonical(const char *name) +{ + int i; + /* + * Only enumerate elements with correct canonical names + */ + for (i = 0; i < Hc_ncanon; i++) { + if (strcmp(name, Hc_canon[i]) == 0) + break; + } + if (i >= Hc_ncanon) + return (0); + else + return (1); +} + +static nvlist_t * +hc_fmri_create(topo_mod_t *mod, nvlist_t *pfmri, int version, const char *name, + topo_instance_t inst, const nvlist_t *auth, const char *part, + const char *rev, const char *serial) +{ + int i; + char str[21]; /* sizeof (UINT64_MAX) + '\0' */ + uint_t pelems = 0; + nvlist_t **phcl = NULL; + nvlist_t **hcl = NULL; + nvlist_t *fmri = NULL; + + if (version > FM_HC_SCHEME_VERSION) + return (hc_create_seterror(mod, + hcl, pelems, fmri, EMOD_VER_OLD)); + else if (version < FM_HC_SCHEME_VERSION) + return (hc_create_seterror(mod, + hcl, pelems, fmri, EMOD_VER_NEW)); + + /* + * Check that the requested name is in our canonical list + */ + if (hc_name_canonical(name) == 0) + return (hc_create_seterror(mod, + hcl, pelems, fmri, EMOD_NONCANON)); + /* + * Copy the parent's HC_LIST + */ + if (pfmri != NULL) { + if (nvlist_lookup_nvlist_array(pfmri, FM_FMRI_HC_LIST, + &phcl, &pelems) != 0) + return (hc_create_seterror(mod, + hcl, pelems, fmri, EMOD_FMRI_MALFORM)); + } + + hcl = topo_mod_zalloc(mod, sizeof (nvlist_t *) * (pelems + 1)); + if (hcl == NULL) + return (hc_create_seterror(mod, hcl, pelems, fmri, + EMOD_NOMEM)); + + for (i = 0; i < pelems; ++i) + if (topo_mod_nvdup(mod, phcl[i], &hcl[i]) != 0) + return (hc_create_seterror(mod, + hcl, pelems, fmri, EMOD_FMRI_NVL)); + + (void) snprintf(str, sizeof (str), "%d", inst); + if ((hcl[i] = hc_list_create(mod, name, str)) == NULL) + return (hc_create_seterror(mod, + hcl, pelems, fmri, EMOD_FMRI_NVL)); + + if ((fmri = hc_base_fmri_create(mod, auth, part, rev, serial)) == NULL) + return (hc_create_seterror(mod, + hcl, pelems, fmri, EMOD_FMRI_NVL)); + + if (nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST, hcl, pelems + 1) + != 0) + return (hc_create_seterror(mod, + hcl, pelems, fmri, EMOD_FMRI_NVL)); + + if (hcl != NULL) { + for (i = 0; i < pelems + 1; ++i) { + if (hcl[i] != NULL) + nvlist_free(hcl[i]); + } + topo_mod_free(mod, hcl, sizeof (nvlist_t *) * (pelems + 1)); + } + + return (fmri); +} + +/*ARGSUSED*/ +static int +hc_fmri_create_meth(topo_mod_t *mp, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + nvlist_t *args, *pfmri; + nvlist_t *auth; + uint32_t inst; + char *name, *serial, *rev, *part; + + if (version > TOPO_METH_FMRI_VERSION) + return (topo_mod_seterrno(mp, EMOD_VER_NEW)); + + /* First the must-have fields */ + if (nvlist_lookup_string(in, TOPO_METH_FMRI_ARG_NAME, &name) != 0) + return (topo_mod_seterrno(mp, EMOD_METHOD_INVAL)); + if (nvlist_lookup_uint32(in, TOPO_METH_FMRI_ARG_INST, &inst) != 0) + return (topo_mod_seterrno(mp, EMOD_METHOD_INVAL)); + if (nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NVL, &args) != 0) + return (topo_mod_seterrno(mp, EMOD_METHOD_INVAL)); + if (nvlist_lookup_nvlist(args, TOPO_METH_FMRI_ARG_PARENT, &pfmri) != 0) + return (topo_mod_seterrno(mp, EMOD_METHOD_INVAL)); + + /* And then optional arguments */ + auth = NULL; + serial = rev = part = NULL; + (void) nvlist_lookup_nvlist(args, TOPO_METH_FMRI_ARG_AUTH, &auth); + (void) nvlist_lookup_string(args, TOPO_METH_FMRI_ARG_PART, &part); + (void) nvlist_lookup_string(args, TOPO_METH_FMRI_ARG_REV, &rev); + (void) nvlist_lookup_string(args, TOPO_METH_FMRI_ARG_SER, &serial); + + *out = hc_fmri_create(mp, + pfmri, version, name, inst, auth, part, rev, serial); + if (*out == NULL) + return (-1); + return (0); +} diff --git a/usr/src/lib/fm/topo/libtopo/common/hc.h b/usr/src/lib/fm/topo/libtopo/common/hc.h new file mode 100644 index 0000000000..0b86abba80 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/hc.h @@ -0,0 +1,43 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef HC_H +#define HC_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +extern void hc_init(topo_mod_t *); +extern void hc_fini(topo_mod_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* HC_H */ diff --git a/usr/src/lib/fm/topo/libtopo/common/hc_canon.h b/usr/src/lib/fm/topo/libtopo/common/hc_canon.h new file mode 100644 index 0000000000..4652fa4ede --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/hc_canon.h @@ -0,0 +1,71 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _HC_CANON_H +#define _HC_CANON_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <topo_parse.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Array declaring all known canonical HC scheme component names. + * Hopefully this file will one day be generated from the event registry + * automagically. + */ +static const char *Hc_canon[] = { + "CMP", + "centerplane", + "chip", + "chip-select", + "cpu", + "dimm", + "hostbridge", + "interconnect", + "ioboard", + "memory-controller", + "motherboard", + "pcibus", + "pcidev", + "pciexbus", + "pciexdev", + "pciexfn", + "pciexrc", + "pcifn", + "systemboard" +}; + +static int Hc_ncanon = sizeof (Hc_canon) / sizeof (const char *); + +#ifdef __cplusplus +} +#endif + +#endif /* _HC_CANON_H */ diff --git a/usr/src/lib/fm/topo/libtopo/common/libtopo.h b/usr/src/lib/fm/topo/libtopo/common/libtopo.h new file mode 100644 index 0000000000..892f2ca91a --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/libtopo.h @@ -0,0 +1,218 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _LIBTOPO_H +#define _LIBTOPO_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/nvpair.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define TOPO_VERSION 1 /* Library ABI Interface Version */ + +typedef struct topo_hdl topo_hdl_t; +typedef struct topo_node tnode_t; +typedef struct topo_walk topo_walk_t; +typedef int32_t topo_instance_t; +typedef uint32_t topo_version_t; + +/* + * Topo stability attributes + * + * Each topology node advertises the name and data stability of each of its + * modules and properties. (see attributes(5)) + */ + +typedef enum topo_stability { + TOPO_STABILITY_INTERNAL = 0, /* private to libtopo */ + TOPO_STABILITY_PRIVATE, /* private to Sun */ + TOPO_STABILITY_OBSOLETE, /* scheduled for removal */ + TOPO_STABILITY_EXTERNAL, /* not controlled by Sun */ + TOPO_STABILITY_UNSTABLE, /* new or rapidly changing */ + TOPO_STABILITY_EVOLVING, /* less rapidly changing */ + TOPO_STABILITY_STABLE, /* mature interface from Sun */ + TOPO_STABILITY_STANDARD, /* industry standard */ + TOPO_STABILITY_MAX /* end */ +} topo_stability_t; + +#define TOPO_STABILITY_MAX TOPO_STABILITY_STANDARD /* max valid stability */ + +typedef enum { + TOPO_TYPE_INVALID = 0, + TOPO_TYPE_BOOLEAN, /* boolean */ + TOPO_TYPE_INT32, /* int32_t */ + TOPO_TYPE_UINT32, /* uint32_t */ + TOPO_TYPE_INT64, /* int64_t */ + TOPO_TYPE_UINT64, /* uint64_t */ + TOPO_TYPE_STRING, /* const char* */ + TOPO_TYPE_TIME, /* uint64_t */ + TOPO_TYPE_SIZE, /* uint64_t */ + TOPO_TYPE_FMRI /* nvlist_t */ +} topo_type_t; + +typedef int (*topo_walk_cb_t)(topo_hdl_t *, tnode_t *, void *); + +extern topo_hdl_t *topo_open(int, const char *, int *); +extern void topo_close(topo_hdl_t *); +extern char *topo_snap_hold(topo_hdl_t *, const char *, int *); +extern void topo_snap_release(topo_hdl_t *); +extern topo_walk_t *topo_walk_init(topo_hdl_t *, const char *, topo_walk_cb_t, + void *, int *); +extern int topo_walk_step(topo_walk_t *, int); +extern void topo_walk_fini(topo_walk_t *); + +#define TOPO_WALK_ERR -1 +#define TOPO_WALK_NEXT 0 +#define TOPO_WALK_TERMINATE 1 + +#define TOPO_WALK_CHILD 0x0001 +#define TOPO_WALK_SIBLING 0x0002 + +extern int topo_fmri_present(topo_hdl_t *, nvlist_t *, int *); +extern int topo_fmri_contains(topo_hdl_t *, nvlist_t *, nvlist_t *, int *); +extern int topo_fmri_unusable(topo_hdl_t *, nvlist_t *, int *); +extern int topo_fmri_nvl2str(topo_hdl_t *, nvlist_t *, char **, int *); +extern int topo_fmri_str2nvl(topo_hdl_t *, const char *, nvlist_t **, int *); +extern int topo_fmri_asru(topo_hdl_t *, nvlist_t *, nvlist_t **, int *); +extern int topo_fmri_fru(topo_hdl_t *, nvlist_t *, nvlist_t **, + int *); +extern int topo_fmri_compare(topo_hdl_t *, nvlist_t *, nvlist_t *, int *); +extern int topo_fmri_invoke(topo_hdl_t *, nvlist_t *, topo_walk_cb_t, void *, + int *); +extern nvlist_t *topo_fmri_create(topo_hdl_t *, const char *, const char *, + topo_instance_t, nvlist_t *, int *); + +/* + * Topo node utilities: callable from topo_walk_step() callback or module + * enumeration, topo_mod_enumerate() + */ +extern char *topo_node_name(tnode_t *); +extern topo_instance_t topo_node_instance(tnode_t *); +extern void *topo_node_private(tnode_t *); +extern int topo_node_asru(tnode_t *, nvlist_t **, nvlist_t *, int *); +extern int topo_node_fru(tnode_t *, nvlist_t **, nvlist_t *, int *); +extern int topo_node_resource(tnode_t *, nvlist_t **, int *); +extern int topo_node_label(tnode_t *, char **, int *); +extern int topo_node_asru_set(tnode_t *node, nvlist_t *, int, int *); +extern int topo_node_fru_set(tnode_t *node, nvlist_t *, int, int *); +extern int topo_node_label_set(tnode_t *node, char *, int *); +extern int topo_method_invoke(tnode_t *node, const char *, topo_version_t, + nvlist_t *, nvlist_t **, int *); + +extern int topo_pgroup_create(tnode_t *, const char *, topo_stability_t, int *); +extern void topo_pgroup_destroy(tnode_t *, const char *); +extern int topo_prop_get_int32(tnode_t *, const char *, const char *, + int32_t *, int *); +extern int topo_prop_get_uint32(tnode_t *, const char *, const char *, + uint32_t *, int *); +extern int topo_prop_get_int64(tnode_t *, const char *, const char *, + int64_t *, int *); +extern int topo_prop_get_uint64(tnode_t *, const char *, const char *, + uint64_t *, int *); +extern int topo_prop_get_string(tnode_t *, const char *, const char *, + char **, int *); +extern int topo_prop_get_fmri(tnode_t *, const char *, const char *, + nvlist_t **, int *); +extern int topo_prop_set_int32(tnode_t *, const char *, const char *, int, + int32_t, int *); +extern int topo_prop_set_uint32(tnode_t *, const char *, const char *, int, + uint32_t, int *); +extern int topo_prop_set_int64(tnode_t *, const char *, const char *, + int, int64_t, int *); +extern int topo_prop_set_uint64(tnode_t *, const char *, const char *, + int, uint64_t, int *); +extern int topo_prop_set_string(tnode_t *, const char *, const char *, + int, const char *, int *); +extern int topo_prop_set_fmri(tnode_t *, const char *, const char *, + int, const nvlist_t *, int *); +extern int topo_prop_stability(tnode_t *, const char *, topo_stability_t *); +extern nvlist_t *topo_prop_get_all(topo_hdl_t *, tnode_t *); +extern int topo_prop_inherit(tnode_t *, const char *, const char *, int *); + +#define TOPO_PROP_SET_ONCE 0 +#define TOPO_PROP_SET_MULTIPLE 1 + +#define TOPO_ASRU_COMPUTE 0x0001 /* Compute ASRU dynamically */ +#define TOPO_FRU_COMPUTE 0x0002 /* Compute FRU dynamically */ + +/* Protocol property group and property names */ +#define TOPO_PGROUP_PROTOCOL "protocol" /* Required property group */ +#define TOPO_PROP_RESOURCE "resource" /* resource FMRI */ +#define TOPO_PROP_ASRU "ASRU" /* ASRU FMRI */ +#define TOPO_PROP_FRU "FRU" /* FRU FMRI */ +#define TOPO_PROP_MOD "module" /* software module FMRI */ +#define TOPO_PROP_PKG "package" /* software package FMRI */ +#define TOPO_PROP_LABEL "label" /* property LABEL */ + +/* + * Legacy TOPO property group: this group supports legacy platform.topo + * property names + */ +#define TOPO_PGROUP_LEGACY "legacy" /* Legacy property group */ +#define TOPO_PROP_PLATASRU "PLAT-ASRU" +#define TOPO_PROP_PLATFRU "PLAT-FRU" + +/* + * System property group + */ +#define TOPO_PGROUP_SYSTEM "system" +#define TOPO_PROP_PLATFORM "platform" +#define TOPO_PROP_ISA "isa" +#define TOPO_PROP_MACHINE "machine" + +/* Property node NVL names */ +#define TOPO_PROP_GROUP "property-group" +#define TOPO_PROP_GROUP_NAME "property-group-name" +#define TOPO_PROP_VAL "property" +#define TOPO_PROP_VAL_NAME "property-name" +#define TOPO_PROP_VAL_VAL "property-value" + +extern const char *topo_strerror(int); +extern void topo_debug_set(topo_hdl_t *, int, char *); +extern void *topo_hdl_alloc(topo_hdl_t *, size_t); +extern void *topo_hdl_zalloc(topo_hdl_t *, size_t); +extern void topo_hdl_free(topo_hdl_t *, void *, size_t); +extern int topo_hdl_nvalloc(topo_hdl_t *, nvlist_t **, uint_t); +extern int topo_hdl_nvdup(topo_hdl_t *, nvlist_t *, nvlist_t **); +extern char *topo_hdl_strdup(topo_hdl_t *, const char *); +extern void topo_hdl_strfree(topo_hdl_t *, char *); + +#define TOPO_DBG_ERR 0x0001 /* enable error handling debug messages */ +#define TOPO_DBG_MOD 0x0002 /* enable module subsystem debug messages */ +#define TOPO_DBG_LOG 0x0004 /* enable log subsystem debug messages */ +#define TOPO_DBG_WALK 0x0008 /* enable walker subsystem debug messages */ +#define TOPO_DBG_TREE 0x0010 /* enable tree subsystem debug messages */ +#define TOPO_DBG_ALL 0xffff /* enable all debug modes */ + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBTOPO_H */ diff --git a/usr/src/lib/fm/libtopo/common/llib-ltopo b/usr/src/lib/fm/topo/libtopo/common/llib-ltopo index f1f4120dfd..b6b2228c63 100644 --- a/usr/src/lib/fm/libtopo/common/llib-ltopo +++ b/usr/src/lib/fm/topo/libtopo/common/llib-ltopo @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ diff --git a/usr/src/lib/fm/topo/libtopo/common/mem.c b/usr/src/lib/fm/topo/libtopo/common/mem.c new file mode 100644 index 0000000000..7ea07bda30 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/mem.c @@ -0,0 +1,250 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <errno.h> +#include <kstat.h> +#include <limits.h> +#include <strings.h> +#include <unistd.h> +#include <fm/topo_mod.h> +#include <sys/fm/protocol.h> + +#include <topo_error.h> + +static int mem_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, + topo_instance_t, void *); +static void mem_release(topo_mod_t *, tnode_t *); +static int mem_nvl2str(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); +static int mem_str2nvl(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); +static int mem_present(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); +static int mem_contains(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); +static int mem_unusable(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); +static int mem_expand(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); +static int mem_asru(topo_mod_t *, tnode_t *, topo_version_t, + nvlist_t *, nvlist_t **); + +#define MEM_VERSION TOPO_VERSION + +static const topo_method_t mem_methods[] = { + { TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION, + TOPO_STABILITY_INTERNAL, mem_nvl2str }, + { TOPO_METH_STR2NVL, TOPO_METH_STR2NVL_DESC, TOPO_METH_STR2NVL_VERSION, + TOPO_STABILITY_INTERNAL, mem_str2nvl }, + { TOPO_METH_PRESENT, TOPO_METH_PRESENT_DESC, TOPO_METH_PRESENT_VERSION, + TOPO_STABILITY_INTERNAL, mem_present }, + { TOPO_METH_CONTAINS, TOPO_METH_CONTAINS_DESC, + TOPO_METH_CONTAINS_VERSION, TOPO_STABILITY_INTERNAL, mem_contains }, + { TOPO_METH_UNUSABLE, TOPO_METH_UNUSABLE_DESC, + TOPO_METH_UNUSABLE_VERSION, TOPO_STABILITY_INTERNAL, mem_unusable }, + { TOPO_METH_EXPAND, TOPO_METH_UNUSABLE_DESC, + TOPO_METH_EXPAND_VERSION, TOPO_STABILITY_INTERNAL, mem_expand }, + { TOPO_METH_ASRU_COMPUTE, TOPO_METH_ASRU_COMPUTE_DESC, + TOPO_METH_ASRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL, mem_asru }, + { NULL } +}; + +static const topo_modinfo_t mem_info = + { "mem", MEM_VERSION, mem_enum, mem_release }; + +void +mem_init(topo_mod_t *mod) +{ + + topo_mod_setdebug(mod, TOPO_DBG_ALL); + topo_mod_dprintf(mod, "initializing mem builtin\n"); + + if (topo_mod_register(mod, &mem_info, NULL) != 0) { + topo_mod_dprintf(mod, "failed to register mem_info: " + "%s\n", topo_mod_errmsg(mod)); + return; + } +} + +void +mem_fini(topo_mod_t *mod) +{ + topo_mod_unregister(mod); +} + +/*ARGSUSED*/ +static int +mem_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, + topo_instance_t min, topo_instance_t max, void *arg) +{ + (void) topo_method_register(mod, pnode, mem_methods); + + return (0); +} + +static void +mem_release(topo_mod_t *mod, tnode_t *node) +{ + topo_method_unregister_all(mod, node); +} + +/*ARGSUSED*/ +static int +mem_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + const char *format; + nvlist_t *nvl; + uint64_t val; + char *buf, *unum; + size_t len; + int err; + + if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0) + return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); + + if (nvlist_lookup_string(in, FM_FMRI_MEM_UNUM, &unum) != 0) { + nvlist_free(nvl); + return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); + } + + /* + * If we have a DIMM offset, include it in the string. If we have a + * PA then use that. Otherwise just format the unum element. + */ + if (nvlist_lookup_uint64(nvl, FM_FMRI_MEM_OFFSET, &val) == 0) { + format = FM_FMRI_SCHEME_MEM ":///" + FM_FMRI_MEM_UNUM "=%1$s/" FM_FMRI_MEM_OFFSET "=%2$llx"; + } else if (nvlist_lookup_uint64(nvl, FM_FMRI_MEM_PHYSADDR, &val) == 0) { + format = FM_FMRI_SCHEME_MEM ":///" + FM_FMRI_MEM_UNUM "=%1$s/" FM_FMRI_MEM_PHYSADDR "=%2$llx"; + } else + format = FM_FMRI_SCHEME_MEM ":///" FM_FMRI_MEM_UNUM "=%1$s"; + + len = snprintf(NULL, 0, format, unum, val); + buf = topo_mod_zalloc(mod, len); + + if (buf == NULL) { + nvlist_free(nvl); + return (topo_mod_seterrno(mod, EMOD_NOMEM)); + } + + (void) snprintf(buf, len, format, unum, val); + err = nvlist_add_string(nvl, "fmri-string", buf); + topo_mod_free(mod, buf, len); + + if (err != 0) { + nvlist_free(nvl); + return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); + } + + *out = nvl; + return (0); +} + +/*ARGSUSED*/ +static int +mem_str2nvl(topo_mod_t *mod, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + return (-1); +} + +/*ARGSUSED*/ +static int +mem_present(topo_mod_t *mod, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + return (-1); +} + +/*ARGSUSED*/ +static int +mem_contains(topo_mod_t *mod, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + return (-1); +} + +/*ARGSUSED*/ +static int +mem_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + return (-1); +} + +/*ARGSUSED*/ +static int +mem_expand(topo_mod_t *mod, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + return (-1); +} + +/*ARGSUSED*/ +static int +mem_asru(topo_mod_t *mod, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + int err; + uint64_t pa = 0, offset = 0; + nvlist_t *hcsp = NULL; + nvlist_t *asru; + char *cstr; + + if (nvlist_lookup_nvlist(in, FM_FMRI_HC_SPECIFIC, &hcsp) == 0) { + (void) nvlist_lookup_uint64(hcsp, "asru-"FM_FMRI_MEM_PHYSADDR, + &pa); + (void) nvlist_lookup_uint64(hcsp, "asru-"FM_FMRI_MEM_OFFSET, + &offset); + } + + if (topo_fmri_nvl2str(topo_mod_handle(mod), in, &cstr, &err) < 0) + return (topo_mod_seterrno(mod, err)); + + if (topo_mod_nvalloc(mod, &asru, NV_UNIQUE_NAME) != 0) { + topo_mod_strfree(mod, cstr); + return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); + } + err = nvlist_add_uint8(asru, FM_VERSION, FM_MEM_SCHEME_VERSION); + err |= nvlist_add_string(asru, FM_FMRI_SCHEME, FM_FMRI_SCHEME_MEM); + err |= nvlist_add_string(asru, FM_FMRI_MEM_UNUM, cstr); + err |= nvlist_add_uint64(asru, FM_FMRI_MEM_PHYSADDR, pa); + err |= nvlist_add_uint64(asru, FM_FMRI_MEM_OFFSET, offset); + topo_mod_strfree(mod, cstr); + if (err != 0) { + nvlist_free(asru); + return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); + } + + *out = asru; + + return (0); +} diff --git a/usr/src/lib/fm/topo/libtopo/common/mkerror.sh b/usr/src/lib/fm/topo/libtopo/common/mkerror.sh new file mode 100644 index 0000000000..8ce9a05a31 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/mkerror.sh @@ -0,0 +1,135 @@ +#!/bin/sh +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +#pragma ident "%Z%%M% %I% %E% SMI" + + +input="`cat`" +[ -z "$input" ] && exit 1 + +if [ $1 = "internal" ] ; then +echo "\ +/*\n\ + * Copyright 2006 Sun Microsystems, Inc. All rights reserved.\n\ + * Use is subject to license terms.\n\ + */\n\ +\n\ +#pragma ident\t\"@(#)mkerror.sh\t1.2\t05/06/08 SMI\"\n\ +\n\ +#include <strings.h> +#include <topo_error.h> +#include <topo_mod.h> + +\n\ +static const char *const _topo_errstrs[] = {" + +pattern='^[ ]*ETOPO_[A-Z0-9_]*.*\* \(.*\) \*.*' +replace=' "\1",' + +echo "$input" | sed -n "s/$pattern/$replace/p" || exit 1 + +echo "\ +};\n\ +\n\ +static const int _topo_nerrstrs =\n\ + sizeof (_topo_errstrs) / sizeof (_topo_errstrs[0]);\n\ +\n\ + +int +topo_hdl_errno(topo_hdl_t *thp) +{ + return (thp->th_errno); +} + +int +topo_hdl_seterrno(topo_hdl_t *thp, int err) +{ + thp->th_errno = err; + return (-1); +} + +const char * +topo_hdl_errmsg(topo_hdl_t *thp) +{ + return (topo_strerror(thp->th_errno)); +}" + +else + +echo "\ +static const char *const _topo_moderrstrs[] = {" + +pattern='^[ ]*EMOD_[A-Z0-9_]*.*\* \(.*\) \*.*' +replace=' "\1",' + +echo "$input" | sed -n "s/$pattern/$replace/p" || exit 1 + +echo "\ +};\n\ +\n\ +static const int _topo_nmoderrstrs =\n\ + sizeof (_topo_moderrstrs) / sizeof (_topo_moderrstrs[0]);\n\ +\n\ + +int +topo_mod_errno(topo_mod_t *mp) +{ + return (mp->tm_errno); +} + +int +topo_mod_seterrno(topo_mod_t *mp, int err) +{ + mp->tm_errno = err; + return (-1); +} + +const char * +topo_mod_errmsg(topo_mod_t *mp) +{ + return (topo_strerror(mp->tm_errno)); +} + +const char * +topo_strerror(int err) +{ + const char *s; + + if (err >= ETOPO_UNKNOWN && (err - ETOPO_UNKNOWN) < _topo_nerrstrs) + s = _topo_errstrs[err - ETOPO_UNKNOWN]; + else if (err >= EMOD_UNKNOWN && (err - EMOD_UNKNOWN) < _topo_nmoderrstrs) + s = _topo_moderrstrs[err - EMOD_UNKNOWN]; + else + s = _topo_errstrs[0]; + + return (s); +}" + +fi + +exit 0 diff --git a/usr/src/lib/fm/topo/libtopo/common/mod.c b/usr/src/lib/fm/topo/libtopo/common/mod.c new file mode 100644 index 0000000000..042aae03e7 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/mod.c @@ -0,0 +1,271 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <limits.h> +#include <strings.h> +#include <unistd.h> +#include <libnvpair.h> +#include <fm/topo_mod.h> +#include <sys/fm/protocol.h> + +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/objfs.h> +#include <sys/modctl.h> +#include <libelf.h> +#include <gelf.h> + +#include <topo_error.h> + +static int mod_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, + topo_instance_t, void *); +static void mod_release(topo_mod_t *, tnode_t *); +static int mod_fmri_create_meth(topo_mod_t *, tnode_t *, topo_version_t, + nvlist_t *, nvlist_t **); + +#define MOD_VERSION TOPO_VERSION + +static const topo_method_t mod_methods[] = { + { TOPO_METH_FMRI, TOPO_METH_FMRI_DESC, TOPO_METH_FMRI_VERSION, + TOPO_STABILITY_INTERNAL, mod_fmri_create_meth }, + { NULL } +}; + +static const topo_modinfo_t mod_info = + { "mod", MOD_VERSION, mod_enum, mod_release }; + +void +mod_init(topo_mod_t *mod) +{ + topo_mod_setdebug(mod, TOPO_DBG_ALL); + topo_mod_dprintf(mod, "initializing mod builtin\n"); + + if (topo_mod_register(mod, &mod_info, NULL) != 0) { + topo_mod_dprintf(mod, "failed to register mod_info: " + "%s\n", topo_mod_errmsg(mod)); + return; + } +} + +void +mod_fini(topo_mod_t *mod) +{ + topo_mod_unregister(mod); +} + +/*ARGSUSED*/ +static int +mod_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, + topo_instance_t min, topo_instance_t max, void *arg) +{ + (void) topo_method_register(mod, pnode, mod_methods); + return (0); +} + +static void +mod_release(topo_mod_t *mod, tnode_t *node) +{ + topo_method_unregister_all(mod, node); +} + +static char * +mod_binary_path_get(topo_mod_t *mp, char *objpath) +{ + static char Pathbuf[PATH_MAX]; + Elf *elf = NULL; + Elf_Scn *scn = NULL; + Elf_Data *edata; + GElf_Ehdr ehdr; + GElf_Shdr shdr; + int fd; + + if ((fd = open(objpath, O_RDONLY)) < 0) { + topo_mod_dprintf(mp, "failed to open %s", objpath); + goto mbpg_bail; + } + if (elf_version(EV_CURRENT) == EV_NONE) { + topo_mod_dprintf(mp, "Elf version out of whack\n"); + goto mbpg_bail; + } + if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { + topo_mod_dprintf(mp, "elf_begin failed\n"); + goto mbpg_bail; + } + if ((gelf_getehdr(elf, &ehdr)) == NULL) { + topo_mod_dprintf(mp, "gelf_getehdr failed\n"); + goto mbpg_bail; + } + scn = elf_getscn(elf, 0); /* "seek" to start of sections */ + while ((scn = elf_nextscn(elf, scn)) != NULL) { + const char *sh_name; + if (gelf_getshdr(scn, &shdr) == NULL) { + topo_mod_dprintf(mp, "gelf_getshdr failed\n"); + goto mbpg_bail; + } + if (shdr.sh_type != SHT_PROGBITS) + continue; + sh_name = elf_strptr(elf, + ehdr.e_shstrndx, (size_t)shdr.sh_name); + if (strcmp(sh_name, ".filename") != 0) + continue; + if ((edata = elf_getdata(scn, NULL)) == NULL) { + topo_mod_dprintf(mp, "no filename data"); + break; + } + (void) strlcpy(Pathbuf, edata->d_buf, PATH_MAX); + break; + } + elf_end(elf); + (void) close(fd); + return (Pathbuf); + +mbpg_bail: + if (elf != NULL) + elf_end(elf); + if (fd >= 0) + (void) close(fd); + (void) topo_mod_seterrno(mp, EMOD_METHOD_INVAL); + return (NULL); +} + +static int +mod_nvl_data(topo_mod_t *mp, nvlist_t *out, const char *path) +{ + struct modinfo mi; + struct stat64 s; + int id, e; + + if (stat64(path, &s) < 0) { + topo_mod_dprintf(mp, + "No system object file for driver %s", path); + return (topo_mod_seterrno(mp, EMOD_METHOD_INVAL)); + } + + id = OBJFS_MODID(s.st_ino); + mi.mi_id = mi.mi_nextid = id; + mi.mi_info = MI_INFO_ONE | MI_INFO_NOBASE; + if (modctl(MODINFO, id, &mi) < 0) { + topo_mod_dprintf(mp, "failed to get modinfo for %s", path); + return (topo_mod_seterrno(mp, EMOD_METHOD_INVAL)); + } + mi.mi_name[MODMAXNAMELEN - 1] = '\0'; + mi.mi_msinfo[0].msi_linkinfo[MODMAXNAMELEN - 1] = '\0'; + e = nvlist_add_string(out, FM_FMRI_SCHEME, FM_FMRI_SCHEME_MOD); + e |= nvlist_add_uint8(out, FM_VERSION, FM_MOD_SCHEME_VERSION); + e |= nvlist_add_int32(out, FM_FMRI_MOD_ID, id); + e |= nvlist_add_string(out, FM_FMRI_MOD_NAME, mi.mi_name); + e |= nvlist_add_string(out, + FM_FMRI_MOD_DESC, mi.mi_msinfo[0].msi_linkinfo); + if (e != 0) + return (topo_mod_seterrno(mp, EMOD_FMRI_NVL)); + + return (0); +} + +static nvlist_t * +mod_fmri_create(topo_mod_t *mp, const char *driver) +{ + topo_hdl_t *thp; + nvlist_t *arg = NULL; + nvlist_t *out = NULL; + nvlist_t *pkg = NULL; + char objpath[PATH_MAX]; + char *path = NULL; + int err; + + if (topo_mod_nvalloc(mp, &arg, NV_UNIQUE_NAME) != 0 || + topo_mod_nvalloc(mp, &out, NV_UNIQUE_NAME) != 0) { + (void) topo_mod_seterrno(mp, EMOD_FMRI_NVL); + goto mfc_bail; + } + + (void) snprintf(objpath, PATH_MAX, "%s/%s/object", OBJFS_ROOT, driver); + + if ((path = mod_binary_path_get(mp, objpath)) == NULL) + goto mfc_bail; + if (nvlist_add_string(arg, "path", path) != 0) { + (void) topo_mod_seterrno(mp, EMOD_FMRI_NVL); + goto mfc_bail; + } + + if (mod_nvl_data(mp, out, objpath) < 0) + goto mfc_bail; + + thp = topo_mod_handle(mp); + pkg = topo_fmri_create(thp, + FM_FMRI_SCHEME_PKG, FM_FMRI_SCHEME_PKG, 0, arg, &err); + if (pkg == NULL) { + (void) topo_mod_seterrno(mp, err); + goto mfc_bail; + } + nvlist_free(arg); + arg = NULL; + + if (nvlist_add_nvlist(out, FM_FMRI_MOD_PKG, pkg) != 0) { + (void) topo_mod_seterrno(mp, EMOD_FMRI_NVL); + goto mfc_bail; + } + nvlist_free(pkg); + + return (out); + +mfc_bail: + nvlist_free(pkg); + nvlist_free(out); + nvlist_free(arg); + return (NULL); +} + +/*ARGSUSED*/ +static int +mod_fmri_create_meth(topo_mod_t *mp, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + nvlist_t *args; + nvlist_t *modnvl; + char *driver; + + if (version > TOPO_METH_FMRI_VERSION) + return (topo_mod_seterrno(mp, EMOD_VER_NEW)); + + if (nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NVL, &args) != 0 || + nvlist_lookup_string(args, "DRIVER", &driver) != 0) { + topo_mod_dprintf(mp, "no DRIVER string in method argument\n"); + return (topo_mod_seterrno(mp, EMOD_METHOD_INVAL)); + } + + modnvl = mod_fmri_create(mp, driver); + if (modnvl == NULL) { + *out = NULL; + topo_mod_dprintf(mp, "failed to create contained mod FMRI\n"); + return (topo_mod_seterrno(mp, EMOD_FMRI_NVL)); + } + *out = modnvl; + return (0); +} diff --git a/usr/src/lib/fm/topo/libtopo/common/pkg.c b/usr/src/lib/fm/topo/libtopo/common/pkg.c new file mode 100644 index 0000000000..867b2f6deb --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/pkg.c @@ -0,0 +1,233 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <limits.h> +#include <strings.h> +#include <string.h> +#include <unistd.h> +#include <stdio.h> +#include <alloca.h> +#include <libnvpair.h> +#include <fm/topo_mod.h> +#include <sys/fm/protocol.h> + +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/objfs.h> +#include <sys/modctl.h> +#include <libelf.h> +#include <gelf.h> + +#include <topo_error.h> + +#define BUFLEN (2 * PATH_MAX) + +static int pkg_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, + topo_instance_t, void *); +static void pkg_release(topo_mod_t *, tnode_t *); +static int pkg_fmri_create_meth(topo_mod_t *, tnode_t *, topo_version_t, + nvlist_t *, nvlist_t **); + +#define PKG_VERSION TOPO_VERSION + +static const topo_method_t pkg_methods[] = { + { TOPO_METH_FMRI, TOPO_METH_FMRI_DESC, TOPO_METH_FMRI_VERSION, + TOPO_STABILITY_INTERNAL, pkg_fmri_create_meth }, + { NULL } +}; + +static const topo_modinfo_t pkg_info = + { "pkg", PKG_VERSION, pkg_enum, pkg_release }; + +void +pkg_init(topo_mod_t *mod) +{ + topo_mod_setdebug(mod, TOPO_DBG_ALL); + topo_mod_dprintf(mod, "initializing mod builtin\n"); + + if (topo_mod_register(mod, &pkg_info, NULL) != 0) { + topo_mod_dprintf(mod, "failed to register pkg_info: " + "%s\n", topo_mod_errmsg(mod)); + return; + } +} + +void +pkg_fini(topo_mod_t *mod) +{ + topo_mod_unregister(mod); +} + +/*ARGSUSED*/ +static int +pkg_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, + topo_instance_t min, topo_instance_t max, void *arg) +{ + (void) topo_method_register(mod, pnode, pkg_methods); + return (0); +} + +static void +pkg_release(topo_mod_t *mod, tnode_t *node) +{ + topo_method_unregister_all(mod, node); +} + +static int +read_thru(topo_mod_t *mp, FILE *fp, const char *substr) +{ + char *tmpbuf = alloca(2 * MAXPATHLEN); + int notfound = 1; + + while (fgets(tmpbuf, 2 * MAXPATHLEN, fp) != NULL) { + if (substr == NULL) + topo_mod_dprintf(mp, "%s", tmpbuf); + else if (strstr(tmpbuf, substr) != NULL) { + notfound = 0; + break; + } + } + return (notfound); +} + +static nvlist_t * +construct_fru_fmri(topo_mod_t *mp, const char *pkgname, FILE *fp) +{ + nvlist_t *f = NULL; + char *tmpbuf = alloca(BUFLEN); + char *pkgdir = NULL; + char *pkgver = NULL; + char *token; + int e; + + while (fgets(tmpbuf, BUFLEN, fp) != NULL) { + if (strstr(tmpbuf, "VERSION:") != NULL) { + token = strtok(tmpbuf, ":"); + token = strtok(NULL, ": \t\n"); + pkgver = topo_mod_strdup(mp, token); + } else if (strstr(tmpbuf, "BASEDIR:") != NULL) { + token = strtok(tmpbuf, ":"); + token = strtok(NULL, ": \t\n"); + pkgdir = topo_mod_strdup(mp, token); + } + } + + if (pkgdir == NULL || pkgver == NULL) { + (void) topo_mod_seterrno(mp, EMOD_METHOD_INVAL); + goto fmrileave; + } + + if (topo_mod_nvalloc(mp, &f, NV_UNIQUE_NAME) != 0) { + (void) topo_mod_seterrno(mp, EMOD_FMRI_NVL); + goto fmrileave; + } + + e = nvlist_add_string(f, FM_FMRI_SCHEME, FM_FMRI_SCHEME_PKG); + e |= nvlist_add_uint8(f, FM_VERSION, FM_PKG_SCHEME_VERSION); + e |= nvlist_add_string(f, FM_FMRI_PKG_BASEDIR, pkgdir); + e |= nvlist_add_string(f, FM_FMRI_PKG_INST, pkgname); + e |= nvlist_add_string(f, FM_FMRI_PKG_VERSION, pkgver); + if (e == 0) + goto fmrileave; + + topo_mod_dprintf(mp, "construction of pkg nvl failed"); + (void) topo_mod_seterrno(mp, EMOD_FMRI_NVL); + nvlist_free(f); + f = NULL; + +fmrileave: + if (pkgdir != NULL) + topo_mod_strfree(mp, pkgdir); + if (pkgver != NULL) + topo_mod_strfree(mp, pkgver); + + return (f); +} + +#define PKGINFO_CMD "LC_MESSAGES= /usr/bin/pkginfo -l %s 2>/dev/null" +#define PKGCHK_CMD "LC_MESSAGES= /usr/sbin/pkgchk -lp %s 2>/dev/null" +#define PKG_KEYPHRASE "Referenced by the following packages:" + +static nvlist_t * +pkg_fmri_create(topo_mod_t *mp, const char *path) +{ + static char tmpbuf[BUFLEN]; + char *findpkgname; + char *pkgname = NULL; + FILE *pcout; + nvlist_t *out = NULL; + + (void) snprintf(tmpbuf, BUFLEN, PKGCHK_CMD, path); + topo_mod_dprintf(mp, "popen of %s\n", tmpbuf); + pcout = popen(tmpbuf, "r"); + if (read_thru(mp, pcout, PKG_KEYPHRASE)) { + (void) pclose(pcout); + goto pfc_bail; + } + (void) fgets(tmpbuf, BUFLEN, pcout); + (void) pclose(pcout); + topo_mod_dprintf(mp, "%s", tmpbuf); + + if ((findpkgname = strtok(tmpbuf, " \n")) == NULL) + goto pfc_bail; + pkgname = topo_mod_strdup(mp, findpkgname); + + (void) snprintf(tmpbuf, BUFLEN, PKGINFO_CMD, pkgname); + topo_mod_dprintf(mp, "popen of %s\n", tmpbuf); + pcout = popen(tmpbuf, "r"); + out = construct_fru_fmri(mp, pkgname, pcout); + (void) pclose(pcout); + +pfc_bail: + if (pkgname != NULL) + topo_mod_strfree(mp, pkgname); + return (out); +} + +/*ARGSUSED*/ +static int +pkg_fmri_create_meth(topo_mod_t *mp, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + nvlist_t *args = NULL; + char *path; + + if (version > TOPO_METH_FMRI_VERSION) + return (topo_mod_seterrno(mp, EMOD_VER_NEW)); + + if (nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NVL, &args) != 0 || + nvlist_lookup_string(args, "path", &path) != 0) { + topo_mod_dprintf(mp, "no path string in method argument\n"); + return (topo_mod_seterrno(mp, EMOD_METHOD_INVAL)); + } + + if ((*out = pkg_fmri_create(mp, path)) == NULL) + return (-1); + return (0); +} diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_alloc.c b/usr/src/lib/fm/topo/libtopo/common/topo_alloc.c new file mode 100644 index 0000000000..e0aaf888a5 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_alloc.c @@ -0,0 +1,97 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <umem.h> +#include <strings.h> + +#include <topo_alloc.h> + +void * +topo_alloc(size_t size, int flags) +{ + return (umem_alloc(size, flags)); +} + +/*ARGSUSED*/ +void * +topo_zalloc(size_t size, int flags) +{ + void *data = topo_alloc(size, flags); + if (data != NULL) + bzero(data, size); + + return (data); +} + +void +topo_free(void *data, size_t size) +{ + umem_free(data, size); +} + +void * +topo_hdl_alloc(topo_hdl_t *thp, size_t size) +{ + topo_alloc_t *ap = thp->th_alloc; + + return (ap->ta_alloc(size, ap->ta_flags)); +} + +void * +topo_hdl_zalloc(topo_hdl_t *thp, size_t size) +{ + topo_alloc_t *ap = thp->th_alloc; + + return (ap->ta_zalloc(size, ap->ta_flags)); +} + +void +topo_hdl_free(topo_hdl_t *thp, void *data, size_t size) +{ + topo_alloc_t *ap = thp->th_alloc; + + ap->ta_free(data, size); +} + +void * +topo_mod_alloc(topo_mod_t *mod, size_t size) +{ + return (topo_hdl_alloc(mod->tm_hdl, size)); +} + +void * +topo_mod_zalloc(topo_mod_t *mod, size_t size) +{ + return (topo_hdl_zalloc(mod->tm_hdl, size)); +} + +void +topo_mod_free(topo_mod_t *mod, void *data, size_t size) +{ + topo_hdl_free(mod->tm_hdl, data, size); +} diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_alloc.h b/usr/src/lib/fm/topo/libtopo/common/topo_alloc.h new file mode 100644 index 0000000000..ce956e5afe --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_alloc.h @@ -0,0 +1,50 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _TOPO_ALLOC_H +#define _TOPO_ALLOC_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <topo_module.h> +#include <libnvpair.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern void *topo_alloc(size_t, int); +extern void *topo_zalloc(size_t, int); +extern void topo_free(void *, size_t); +extern void *topo_nv_alloc(nv_alloc_t *, size_t); +extern void topo_nv_free(nv_alloc_t *, void *, size_t); + +#ifdef __cplusplus +} +#endif + +#endif /* _TOPO_ALLOC_H */ diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_builtin.c b/usr/src/lib/fm/topo/libtopo/common/topo_builtin.c new file mode 100644 index 0000000000..0d2f75dda6 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_builtin.c @@ -0,0 +1,138 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <pthread.h> + +#include <topo_module.h> +#include <topo_string.h> +#include <topo_builtin.h> +#include <topo_error.h> +#include <topo_subr.h> + +static const struct topo_builtin _topo_builtins[] = { + { "cpu", cpu_init, cpu_fini }, + { "mem", mem_init, mem_fini }, + { "hc", hc_init, hc_fini }, + { "mod", mod_init, mod_fini }, + { "pkg", pkg_init, pkg_fini }, + { NULL, NULL, NULL } +}; + +static int +bltin_init(topo_mod_t *mp) +{ + const topo_builtin_t *bp; + + for (bp = _topo_builtins; bp->bltin_name != NULL; bp++) { + if (strcmp(mp->tm_name, bp->bltin_name) == 0) + break; + } + + mp->tm_data = (void *)bp; + + (*bp->bltin_init)(mp); + + if (mp->tm_info == NULL) { + topo_dprintf(TOPO_DBG_ERR, + "unable initialize builtin module: %s\n", bp->bltin_name); + return (topo_mod_seterrno(mp, ETOPO_MOD_INIT)); + } + + return (0); +} + +static int +bltin_fini(topo_mod_t *mp) +{ + topo_builtin_t *bp = mp->tm_data; + + if (mp->tm_info != NULL) { + (*bp->bltin_fini)(mp); + + } + + return (0); +} + +const topo_modops_t topo_bltin_ops = { + bltin_init, + bltin_fini, +}; + +/*ARGSUSED*/ +int +topo_builtin_create(topo_hdl_t *thp, const char *rootdir) +{ + const topo_builtin_t *bp; + topo_mod_t *mod; + ttree_t *tp; + tnode_t *rnode; + + /* + * Create a scheme-specific topo tree for all builtins + */ + for (bp = _topo_builtins; bp->bltin_name != NULL; bp++) { + + /* + * Load scheme-specific module + */ + if ((mod = topo_modhash_load(thp, bp->bltin_name, + &topo_bltin_ops)) == NULL) { + topo_dprintf(TOPO_DBG_ERR, "unable to create scheme " + "tree for %s:%s\n", bp->bltin_name, + topo_hdl_errmsg(thp)); + return (-1); + } + if ((tp = topo_tree_create(thp, mod, bp->bltin_name)) + == NULL) { + topo_dprintf(TOPO_DBG_ERR, "unable to create scheme " + "tree for %s:%s\n", bp->bltin_name, + topo_hdl_errmsg(thp)); + return (-1); + } + topo_list_append(&thp->th_trees, tp); + + /* + * Call the enumerator on the root of the tree, with the + * scheme name as the name to enumerate. This will + * establish methods on the root node. + */ + rnode = tp->tt_root; + if (topo_mod_enumerate(mod, rnode, mod->tm_name, rnode->tn_name, + rnode->tn_instance, rnode->tn_instance) < 0) { + /* + * If we see a failure, note it in the handle and + * drive on + */ + (void) topo_hdl_seterrno(thp, ETOPO_ENUM_PARTIAL); + } + + } + + return (0); +} diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_builtin.h b/usr/src/lib/fm/topo/libtopo/common/topo_builtin.h new file mode 100644 index 0000000000..76dd274b14 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_builtin.h @@ -0,0 +1,72 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _TOPO_BUILTIN_H +#define _TOPO_BUILTIN_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <topo_tree.h> +#include <topo_module.h> + +/* + * topo_builtin.h + * + * This header file provides prototypes for any built-in scheme enumerators + * that are compiled directly into topo. Prototypes for their init and + * fini routines can be added here and corresponding linkage information to + * these functions should be added to the table found in topo_builtin.c. + */ + +typedef struct topo_builtin { + const char *bltin_name; + void (*bltin_init)(topo_mod_t *); + void (*bltin_fini)(topo_mod_t *); +} topo_builtin_t; + +extern int topo_builtin_create(topo_hdl_t *, const char *); + +extern void hc_init(topo_mod_t *); /* see hc.c */ +extern void hc_fini(topo_mod_t *); /* see hc.c */ +extern void cpu_init(topo_mod_t *); /* see cpu.c */ +extern void cpu_fini(topo_mod_t *); /* see cpu.c */ +extern void mem_init(topo_mod_t *); /* see mem.c */ +extern void mem_fini(topo_mod_t *); /* see mem.c */ +extern void mod_init(topo_mod_t *); /* see mod.c */ +extern void mod_fini(topo_mod_t *); /* see mod.c */ +extern void pkg_init(topo_mod_t *); /* see pkg.c */ +extern void pkg_fini(topo_mod_t *); /* see pkg.c */ + +#ifdef __cplusplus +} +#endif + +#endif /* _TOPO_BUILTIN_H */ diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_error.h b/usr/src/lib/fm/topo/libtopo/common/topo_error.h new file mode 100644 index 0000000000..fd3bb7bd66 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_error.h @@ -0,0 +1,116 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _TOPO_ERROR_H +#define _TOPO_ERROR_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <topo_tree.h> +#include <topo_module.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This enum definition is used to define a set of error tags associated with + * the fmd daemon's various error conditions. The shell script mkerror.sh is + * used to parse this file and create a corresponding topo_error.c source file. + * If you do something other than add a new error tag here, you may need to + * update the mkerror shell script as it is based upon simple regexps. + */ +typedef enum topo_errno { + ETOPO_UNKNOWN = 1000, /* unknown libtopo error */ + ETOPO_NOMEM, /* memory limit exceeded */ + ETOPO_MODULE, /* module detected or caused an error */ + ETOPO_HDL_VER, /* handle opened with invalid ABI version */ + ETOPO_HDL_SNAP, /* snapshot already taken */ + ETOPO_HDL_INVAL, /* invalid argument specified */ + ETOPO_HDL_UUID, /* uuid already set */ + ETOPO_MOD_INIT, /* failed to initialize module */ + ETOPO_MOD_FINI, /* failed to uninitialize module */ + ETOPO_MOD_LOADED, /* specified module is already loaded */ + ETOPO_MOD_NOMOD, /* specified module is not loaded */ + ETOPO_MOD_NONVL, /* specified module is not loaded */ + ETOPO_MOD_INVAL, /* module invalid argument */ + ETOPO_MOD_DUP, /* module duplicate node entry */ + ETOPO_MOD_NOREG, /* module failed to register */ + ETOPO_MOD_NOENT, /* module path invalid */ + ETOPO_MOD_NOSUP, /* enumerator not supported in this module */ + ETOPO_RTLD_OPEN, /* rtld failed to open shared library plug-in */ + ETOPO_RTLD_INIT, /* shared library plug-in does not define _topo_init */ + ETOPO_RTLD_NOMEM, /* memory limit exceeded when opening shared library */ + ETOPO_BLTIN_NAME, /* built-in plug-in name not found in definition list */ + ETOPO_BLTIN_INIT, /* built-in plug-in does not define init function */ + ETOPO_NODE_INVAL, /* node opertation invalid argument */ + ETOPO_NODE_LINKED, /* node already linked */ + ETOPO_NODE_BOUND, /* node already bound */ + ETOPO_NODE_DUP, /* duplicate node */ + ETOPO_NODE_RANGE, /* invalid instance range */ + ETOPO_NODE_NOENT, /* node not found */ + ETOPO_NODE_FMRI, /* no fmri specified */ + ETOPO_VER_OLD, /* plugin compiled using an obsolete topo ABI */ + ETOPO_VER_NEW, /* plugin is compiled using a newer topo ABI */ + ETOPO_ENUM_PARTIAL, /* partial enumeration completed for client */ + ETOPO_PROP_NOENT, /* undefined property or property group */ + ETOPO_PROP_DEFD, /* static property already defined */ + ETOPO_PROP_NOMEM, /* memory limit exceeded during property allocation */ + ETOPO_PROP_TYPE, /* invalid property type */ + ETOPO_PROP_NOINHERIT, /* can not inherit property */ + ETOPO_FMRI_NVL, /* nvlist allocation failure for FMRI */ + ETOPO_FMRI_VERSION, /* invalid FMRI scheme version */ + ETOPO_FMRI_MALFORM, /* malformed FMRI */ + ETOPO_NVL_INVAL, /* invalid nvlist function argument */ + ETOPO_METHOD_INVAL, /* invalid method registration */ + ETOPO_METHOD_NOTSUP, /* method not supported */ + ETOPO_METHOD_FAIL, /* method failed */ + ETOPO_FILE_NOENT, /* no topology file found */ + ETOPO_PRSR_BADGRP, /* unrecognized grouping */ + ETOPO_PRSR_BADNUM, /* unable to interpret attribute numerically */ + ETOPO_PRSR_BADRNG, /* non-sensical range */ + ETOPO_PRSR_BADSCH, /* unrecognized scheme */ + ETOPO_PRSR_BADSTAB, /* unrecognized stability */ + ETOPO_PRSR_BADTYPE, /* unrecognized property value type */ + ETOPO_PRSR_NOATTR, /* tag missing attribute */ + ETOPO_PRSR_NOENT, /* topology xml file not found */ + ETOPO_PRSR_NOMETH, /* range missing enum-method */ + ETOPO_PRSR_NVPROP, /* properties as nvlist missing crucial field */ + ETOPO_PRSR_OOR, /* node instance out of declared range */ + ETOPO_WALK_EMPTY, /* empty topology */ + ETOPO_WALK_NOTFOUND, /* scheme based topology not found */ + ETOPO_END /* end of custom errno list (to ease auto-merge) */ +} topo_errno_t; + +extern int topo_hdl_seterrno(topo_hdl_t *, int); +extern const char *topo_hdl_errmsg(topo_hdl_t *); +extern int topo_hdl_errno(topo_hdl_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _TOPO_ERROR_H */ diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_file.c b/usr/src/lib/fm/topo/libtopo/common/topo_file.c new file mode 100644 index 0000000000..928a2337b1 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_file.c @@ -0,0 +1,169 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <limits.h> +#include <string.h> +#include <sys/param.h> +#include <topo_error.h> +#include <topo_tree.h> +#include <topo_subr.h> +#include <topo_file.h> + +/* + * topo_file.c + * + * This file hides the details of any file manipulation to + * establish topology for a given scheme. It has two outward + * facing interfaces topo_file_load() and topo_file_unload(). + */ + +#define TOPO_DEFAULT_FILE "%s-topology.xml" +#define PLATFORM_TOPO_PATH "%susr/platform/%s/lib/fm/topo/%s" +#define COMMON_TOPO_PATH "%susr/lib/fm/topo/%s" + +static char _topo_file[MAXNAMELEN * 2]; +static char _topo_path[PATH_MAX]; + +static int +xml_read(topo_hdl_t *hp, ttree_t *tp) +{ + topo_file_t *tfp; + char *pplat, *pmach; + int err, e; + + tfp = (topo_file_t *)tp->tt_file; + + (void) snprintf(_topo_file, + 2 * MAXNAMELEN, TOPO_DEFAULT_FILE, tp->tt_scheme); + + /* + * Look for a platform-specific topology file first + */ + e = topo_prop_get_string(tp->tt_root, TOPO_PGROUP_SYSTEM, + TOPO_PROP_PLATFORM, &pplat, &err); + if (e < 0) + return (topo_hdl_seterrno(hp, err)); + (void) snprintf(_topo_path, PATH_MAX, PLATFORM_TOPO_PATH, + hp->th_rootdir, pplat, _topo_file); + + tfp->tf_fileinfo = + topo_xml_read(tfp->tf_mod, _topo_path, tp->tt_scheme); + if (tfp->tf_fileinfo != NULL) { + topo_hdl_strfree(hp, pplat); + return (0); + } + + topo_dprintf(TOPO_DBG_MOD, "failed to load topology file %s: %s\n", + _topo_path, topo_strerror(topo_hdl_errno(hp))); + + /* + * No luck with the platform-specific file, how about a + * machine-specific one? + */ + e = topo_prop_get_string(tp->tt_root, TOPO_PGROUP_SYSTEM, + TOPO_PROP_MACHINE, &pmach, &err); + if (e < 0) { + topo_hdl_strfree(hp, pplat); + return (topo_hdl_seterrno(hp, err)); + } + /* + * Don't waste time trying to open the same file twice in the + * cases where the platform name is identical to the machine + * name + */ + if (strcmp(pplat, pmach) != 0) { + (void) snprintf(_topo_path, PATH_MAX, PLATFORM_TOPO_PATH, + hp->th_rootdir, pmach, _topo_file); + tfp->tf_fileinfo = + topo_xml_read(tfp->tf_mod, _topo_path, tp->tt_scheme); + } + if (tfp->tf_fileinfo != NULL) { + topo_hdl_strfree(hp, pplat); + topo_hdl_strfree(hp, pmach); + return (0); + } else { + topo_dprintf(TOPO_DBG_MOD, + "failed to load topology file %s: %s\n", + _topo_path, topo_strerror(topo_hdl_errno(hp))); + } + topo_hdl_strfree(hp, pplat); + topo_hdl_strfree(hp, pmach); + (void) snprintf(_topo_path, PATH_MAX, COMMON_TOPO_PATH, + hp->th_rootdir, _topo_file); + tfp->tf_fileinfo = + topo_xml_read(tfp->tf_mod, _topo_path, tp->tt_scheme); + if (tfp->tf_fileinfo == NULL) { + topo_dprintf(TOPO_DBG_MOD, + "failed to load topology file %s: %s\n", + _topo_path, topo_strerror(topo_hdl_errno(hp))); + return (topo_hdl_seterrno(hp, ETOPO_FILE_NOENT)); + } + return (0); +} + +int +topo_file_load(topo_hdl_t *thp, topo_mod_t *mod, ttree_t *tp) +{ + topo_file_t *tfp; + + if ((tfp = topo_hdl_zalloc(thp, sizeof (topo_file_t))) == NULL) + return (topo_hdl_seterrno(thp, ETOPO_NOMEM)); + + tp->tt_file = tfp; + + tfp->tf_mod = mod; + + if (xml_read(thp, tp) < 0) { + topo_file_unload(thp, tp); + return (-1); + } + + if (topo_xml_enum(tfp->tf_mod, tfp->tf_fileinfo, tp->tt_root) < 0) { + topo_dprintf(TOPO_DBG_ERR, + "Failed to enumerate topology: %s\n", + topo_strerror(topo_hdl_errno(thp))); + topo_file_unload(thp, tp); + return (-1); + } + return (0); +} + +void +topo_file_unload(topo_hdl_t *thp, ttree_t *tp) +{ + topo_file_t *tfp = tp->tt_file; + + if (tfp == NULL) + return; + + if (tfp->tf_fileinfo != NULL) + tf_info_free(tfp->tf_mod, tfp->tf_fileinfo); + + topo_hdl_free(thp, tfp, sizeof (topo_file_t)); + tp->tt_file = NULL; +} diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_file.h b/usr/src/lib/fm/topo/libtopo/common/topo_file.h new file mode 100644 index 0000000000..ce2f3a258a --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_file.h @@ -0,0 +1,59 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _TOPO_FILE_H +#define _TOPO_FILE_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <topo_parse.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * We support loading topology from a file. The topo_tree routines + * don't need to know anymore than to call topo_file_load() to try to + * load the topology initially, and topo_file_unload() to clean up. + */ +typedef struct topo_file { + /* + * Currently we directly parse xml into topology nodes. The + * tf_info_t is created and used by the xml parsing routines. + */ + tf_info_t *tf_fileinfo; + /* + * Module on whose behalf the enumeration-from-file is occuring. + */ + topo_mod_t *tf_mod; +} topo_file_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _TOPO_FILE_H */ diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_fmri.c b/usr/src/lib/fm/topo/libtopo/common/topo_fmri.c new file mode 100644 index 0000000000..7be3f60dc0 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_fmri.c @@ -0,0 +1,481 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <string.h> +#include <limits.h> +#include <fm/topo_mod.h> +#include <sys/fm/protocol.h> +#include <topo_alloc.h> +#include <topo_error.h> +#include <topo_subr.h> +#include <topo_string.h> + +/*ARGSUSED*/ +static int +set_error(topo_hdl_t *thp, int err, int *errp, char *method, nvlist_t *nvlp) +{ + if (nvlp != NULL) + nvlist_free(nvlp); + + topo_dprintf(TOPO_DBG_ERR, "%s failed: %s\n", method, + topo_strerror(err)); + + *errp = err; + return (-1); +} + +/*ARGSUSED*/ +static nvlist_t * +set_nverror(topo_hdl_t *thp, int err, int *errp, char *method, nvlist_t *nvlp) +{ + if (nvlp != NULL) + nvlist_free(nvlp); + + topo_dprintf(TOPO_DBG_ERR, "%s failed: %s\n", method, + topo_strerror(err)); + + *errp = err; + return (NULL); +} + +int +topo_fmri_nvl2str(topo_hdl_t *thp, nvlist_t *fmri, char **fmristr, int *err) +{ + char *scheme, *str; + nvlist_t *out = NULL; + tnode_t *rnode; + + if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) + return (set_error(thp, ETOPO_FMRI_MALFORM, err, + TOPO_METH_NVL2STR, out)); + + if ((rnode = topo_hdl_root(thp, scheme)) == NULL) + return (set_error(thp, ETOPO_METHOD_NOTSUP, err, + TOPO_METH_NVL2STR, out)); + + if (topo_method_invoke(rnode, TOPO_METH_NVL2STR, + TOPO_METH_NVL2STR_VERSION, fmri, &out, err) != 0) + return (set_error(thp, *err, err, TOPO_METH_NVL2STR, out)); + + if (out == NULL || nvlist_lookup_string(out, "fmri-string", &str) != 0) + return (set_error(thp, ETOPO_METHOD_INVAL, err, + TOPO_METH_NVL2STR, out)); + + if ((*fmristr = topo_hdl_strdup(thp, str)) == NULL) + return (set_error(thp, ETOPO_NOMEM, err, + TOPO_METH_NVL2STR, out)); + + nvlist_free(out); + + return (0); +} + +int +topo_fmri_str2nvl(topo_hdl_t *thp, const char *fmristr, nvlist_t **fmri, + int *err) +{ + char *f, scheme[PATH_MAX]; + nvlist_t *out = NULL, *in = NULL; + tnode_t *rnode; + + (void) strlcpy(scheme, fmristr, sizeof (scheme)); + if ((f = strrchr(scheme, ':')) == NULL) + return (set_error(thp, ETOPO_FMRI_MALFORM, err, + TOPO_METH_STR2NVL, in)); + + *f = '\0'; /* strip trailing FMRI path */ + + if ((rnode = topo_hdl_root(thp, scheme)) == NULL) + return (set_error(thp, ETOPO_METHOD_NOTSUP, err, + TOPO_METH_STR2NVL, in)); + + if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) + return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_STR2NVL, + in)); + + if (nvlist_add_string(in, "fmri-string", fmristr) != 0) + return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_STR2NVL, + in)); + + if (topo_method_invoke(rnode, TOPO_METH_STR2NVL, + TOPO_METH_STR2NVL_VERSION, in, &out, err) != 0) + return (set_error(thp, *err, err, TOPO_METH_STR2NVL, in)); + + if (out == NULL || + topo_hdl_nvdup(thp, out, fmri) != 0) + return (set_error(thp, ETOPO_FMRI_NVL, err, + TOPO_METH_STR2NVL, in)); + + nvlist_free(out); + nvlist_free(in); + + return (0); +} + +int +topo_fmri_present(topo_hdl_t *thp, nvlist_t *fmri, int *err) +{ + int rc; + char *scheme; + nvlist_t *out = NULL; + tnode_t *rnode; + + if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) + return (set_error(thp, ETOPO_FMRI_MALFORM, err, + TOPO_METH_PRESENT, out)); + + if ((rnode = topo_hdl_root(thp, scheme)) == NULL) + return (set_error(thp, ETOPO_METHOD_NOTSUP, err, + TOPO_METH_PRESENT, out)); + + if ((rc = topo_method_invoke(rnode, TOPO_METH_PRESENT, + TOPO_METH_PRESENT_VERSION, fmri, &out, err)) < 0) + return (set_error(thp, *err, err, TOPO_METH_PRESENT, out)); + + return (rc); +} + +int +topo_fmri_contains(topo_hdl_t *thp, nvlist_t *fmri, nvlist_t *subfmri, int *err) +{ + int rc; + char *scheme; + nvlist_t *in, *out = NULL; + tnode_t *rnode; + + if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) + return (set_error(thp, ETOPO_FMRI_MALFORM, err, + TOPO_METH_CONTAINS, out)); + + if ((rnode = topo_hdl_root(thp, scheme)) == NULL) + return (set_error(thp, ETOPO_METHOD_NOTSUP, err, + TOPO_METH_CONTAINS, out)); + + if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) + return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS, + out)); + + if (nvlist_add_nvlist(in, "fmri", fmri) != 0 || + nvlist_add_nvlist(in, "subfmri", subfmri) != 0) + return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS, + out)); + + if (topo_hdl_nvalloc(thp, &out, NV_UNIQUE_NAME) != 0) + return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS, + out)); + + if ((rc = topo_method_invoke(rnode, TOPO_METH_CONTAINS, + TOPO_METH_CONTAINS_VERSION, fmri, &out, err)) < 0) + return (set_error(thp, *err, err, TOPO_METH_CONTAINS, out)); + + return (rc); +} + +int +topo_fmri_unusable(topo_hdl_t *thp, nvlist_t *fmri, int *err) +{ + int rc; + char *scheme; + nvlist_t *out = NULL; + tnode_t *rnode; + + if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) + return (set_error(thp, ETOPO_FMRI_MALFORM, err, + TOPO_METH_UNUSABLE, out)); + + if ((rnode = topo_hdl_root(thp, scheme)) == NULL) + return (set_error(thp, ETOPO_METHOD_NOTSUP, err, + TOPO_METH_UNUSABLE, out)); + + if ((rc = topo_method_invoke(rnode, TOPO_METH_UNUSABLE, + TOPO_METH_UNUSABLE_VERSION, fmri, &out, err)) < 0) + return (set_error(thp, *err, err, TOPO_METH_UNUSABLE, out)); + + return (rc); +} + +int +topo_fmri_expand(topo_hdl_t *thp, nvlist_t *fmri, int *err) +{ + char *scheme; + nvlist_t *out = NULL; + tnode_t *rnode; + + if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) + return (set_error(thp, ETOPO_FMRI_MALFORM, err, + TOPO_METH_EXPAND, out)); + + if ((rnode = topo_hdl_root(thp, scheme)) == NULL) + return (set_error(thp, ETOPO_METHOD_NOTSUP, err, + TOPO_METH_EXPAND, out)); + + if (topo_method_invoke(rnode, TOPO_METH_EXPAND, + TOPO_METH_EXPAND_VERSION, fmri, &out, err) != 0) + return (set_error(thp, *err, err, TOPO_METH_EXPAND, out)); + + return (0); +} + +static struct rsrc { + int rs_err; + int rs_flag; + nvlist_t **rs_fprop; + nvlist_t *rs_priv; +}; + +/*ARGSUSED*/ +static int +get_prop(topo_hdl_t *thp, tnode_t *node, void *pdata) +{ + struct rsrc *rsp = (struct rsrc *)pdata; + + if (rsp->rs_flag == 0) { + if (topo_node_asru(node, rsp->rs_fprop, rsp->rs_priv, + &rsp->rs_err) < 0) + return (-1); + + return (0); + } else { + if (topo_node_fru(node, rsp->rs_fprop, rsp->rs_priv, + &rsp->rs_err) < 0) + return (-1); + + return (0); + } +} + +int +topo_fmri_asru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **asru, int *err) +{ + char *uuid = NULL; + struct rsrc r; + + if (thp->th_uuid == NULL) { + if ((uuid = topo_snap_hold(thp, NULL, err)) == NULL) + return (set_error(thp, *err, err, "topo_fmri_asru", + NULL)); + } + + r.rs_flag = 0; + r.rs_err = 0; + r.rs_priv = nvl; + r.rs_fprop = asru; + if (topo_fmri_invoke(thp, nvl, get_prop, &r, err) < 0) { + if (uuid != NULL) { + topo_hdl_strfree(thp, uuid); + topo_snap_release(thp); + } + + return (set_error(thp, *err, err, "topo_fmri_asru", NULL)); + } + + if (uuid != NULL) { + topo_hdl_strfree(thp, uuid); + topo_snap_release(thp); + } + + return (0); +} + +int +topo_fmri_fru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **fru, + int *err) +{ + char *uuid = NULL; + struct rsrc r; + + if (thp->th_uuid == NULL) { + if ((uuid = topo_snap_hold(thp, NULL, err)) == NULL) + return (set_error(thp, *err, err, "topo_fmri_fru", + NULL)); + } + + r.rs_flag = 1; + r.rs_err = 0; + r.rs_priv = nvl; + r.rs_fprop = fru; + if (topo_fmri_invoke(thp, nvl, get_prop, &r, err) < 0) { + if (uuid != NULL) { + topo_hdl_strfree(thp, uuid); + topo_snap_release(thp); + } + + return (set_error(thp, *err, err, "topo_fmri_fru", NULL)); + } + + if (uuid != NULL) { + topo_hdl_strfree(thp, uuid); + topo_snap_release(thp); + } + + return (0); +} + +int +topo_fmri_compare(topo_hdl_t *thp, nvlist_t *f1, nvlist_t *f2, int *err) +{ + int rc; + char *scheme1, *scheme2; + nvlist_t *in; + nvlist_t *out = NULL; + tnode_t *rnode; + + if (nvlist_lookup_string(f1, FM_FMRI_SCHEME, &scheme1) != 0) + return (set_error(thp, ETOPO_FMRI_MALFORM, err, + TOPO_METH_COMPARE, NULL)); + if (nvlist_lookup_string(f1, FM_FMRI_SCHEME, &scheme2) != 0) + return (set_error(thp, ETOPO_FMRI_MALFORM, err, + TOPO_METH_COMPARE, NULL)); + + if (strcmp(scheme1, scheme2) != 0) + return (0); + + if ((rnode = topo_hdl_root(thp, scheme1)) == NULL) + return (set_error(thp, ETOPO_METHOD_NOTSUP, err, + TOPO_METH_COMPARE, NULL)); + + if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) + return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE, + NULL)); + + if (nvlist_add_nvlist(in, "nv1", f1) != 0 || + nvlist_add_nvlist(in, "nv2", f2) != 0) + return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE, + in)); + + if ((rc = topo_method_invoke(rnode, TOPO_METH_COMPARE, + TOPO_METH_COMPARE_VERSION, in, &out, err)) < 0) + return (set_error(thp, *err, err, TOPO_METH_COMPARE, in)); + + nvlist_free(in); + + return (rc); +} + +struct topo_lookup { + nvlist_t *tl_resource; + topo_walk_cb_t tl_func; + int tl_err; + void *tl_pdata; +}; + +static int +walk_lookup(topo_hdl_t *thp, tnode_t *node, void *pdata) +{ + int rc; + struct topo_lookup *tlp = (struct topo_lookup *)pdata; + nvlist_t *r1, *r2 = tlp->tl_resource; + + if (topo_node_resource(node, &r1, &tlp->tl_err) != 0) + return (TOPO_WALK_ERR); + + rc = topo_fmri_compare(thp, r1, r2, &tlp->tl_err); + nvlist_free(r1); + if (rc == 0) + return (TOPO_WALK_NEXT); + else if (rc == -1) + return (TOPO_WALK_ERR); + + tlp->tl_err = tlp->tl_func(thp, node, tlp->tl_pdata); + + return (TOPO_WALK_TERMINATE); +} + +int +topo_fmri_invoke(topo_hdl_t *thp, nvlist_t *nvl, topo_walk_cb_t cb_f, + void *pdata, int *err) +{ + topo_walk_t *wp; + char *scheme; + struct topo_lookup tl; + + if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme) != 0) + return (set_error(thp, ETOPO_METHOD_INVAL, err, + "topo_fmri_invoke", NULL)); + + tl.tl_resource = nvl; + tl.tl_func = cb_f; + tl.tl_pdata = pdata; + tl.tl_err = 0; + if ((wp = topo_walk_init(thp, scheme, walk_lookup, &tl, err)) == NULL) + return (set_error(thp, *err, err, "topo_fmri_invoke", NULL)); + + (void) topo_walk_step(wp, TOPO_WALK_CHILD); + topo_walk_fini(wp); + + if (tl.tl_err != 0) { + *err = tl.tl_err; + return (-1); + } + + return (0); +} + +/* + * topo_fmri_create + * + * If possible, creates an FMRI of the requested version in the + * requested scheme. Args are passed as part of the inputs to the + * fmri-create method of the scheme. + */ +nvlist_t * +topo_fmri_create(topo_hdl_t *thp, const char *scheme, const char *name, + topo_instance_t inst, nvlist_t *nvl, int *err) +{ + nvlist_t *ins; + nvlist_t *out; + tnode_t *rnode; + + ins = out = NULL; + + if ((rnode = topo_hdl_root(thp, scheme)) == NULL) + return (set_nverror(thp, ETOPO_METHOD_NOTSUP, err, + TOPO_METH_FMRI, NULL)); + + if ((*err = topo_hdl_nvalloc(thp, &ins, NV_UNIQUE_NAME)) != 0) + return (set_nverror(thp, ETOPO_FMRI_NVL, err, + TOPO_METH_FMRI, NULL)); + + if (nvlist_add_string(ins, TOPO_METH_FMRI_ARG_NAME, name) != 0 || + nvlist_add_uint32(ins, TOPO_METH_FMRI_ARG_INST, inst) != 0) { + return (set_nverror(thp, ETOPO_FMRI_NVL, err, + TOPO_METH_FMRI, ins)); + } + + if (nvl != NULL && + nvlist_add_nvlist(ins, TOPO_METH_FMRI_ARG_NVL, nvl) != 0) { + return (set_nverror(thp, ETOPO_FMRI_NVL, err, + TOPO_METH_FMRI, ins)); + } + if (topo_method_invoke(rnode, + TOPO_METH_FMRI, TOPO_METH_FMRI_VERSION, ins, &out, err) != 0) { + return (set_nverror(thp, *err, err, TOPO_METH_FMRI, ins)); + } + nvlist_free(ins); + return (out); +} diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_list.c b/usr/src/lib/fm/topo/libtopo/common/topo_list.c new file mode 100644 index 0000000000..6e87d3b5d2 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_list.c @@ -0,0 +1,185 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <unistd.h> +#include <assert.h> + +#include <topo_list.h> +#include <topo_tree.h> + +/* + * Embedded Linked Lists + * + * Simple doubly-linked list implementation. This implementation assumes that + * each list element contains an embedded topo_list_t (previous and next + * pointers), which is typically the first member of the element struct. + * An additional topo_list_t is used to store the head (l_next) and tail + * (l_prev) pointers. The current head and tail list elements have their + * previous and next pointers set to NULL, respectively. + * + * NOTE: The embeddable list code in this file intentionally provides no + * locking of any kind. The implementation of any list in topo must provide + * an appropriate locking strategy to protect the list or to protect access + * to the embedded topo_list_t inside of each list element to avoid corruption. + * Refer to comments in the source files that use topo_list_t for lock details. + */ + + +void +topo_list_append(topo_list_t *lp, void *new) +{ + topo_list_t *p = lp->l_prev; /* p = tail list element */ + topo_list_t *q = new; /* q = new list element */ + + lp->l_prev = q; + q->l_prev = p; + q->l_next = NULL; + + if (p != NULL) { + assert(p->l_next == NULL); + p->l_next = q; + } else { + assert(lp->l_next == NULL); + lp->l_next = q; + } +} + +void +topo_list_prepend(topo_list_t *lp, void *new) +{ + topo_list_t *p = new; /* p = new list element */ + topo_list_t *q = lp->l_next; /* q = head list element */ + + lp->l_next = p; + p->l_prev = NULL; + p->l_next = q; + + if (q != NULL) { + assert(q->l_prev == NULL); + q->l_prev = p; + } else { + assert(lp->l_prev == NULL); + lp->l_prev = p; + } +} + +void +topo_list_insert_before(topo_list_t *lp, void *before_me, void *new) +{ + topo_list_t *p = before_me; + topo_list_t *q = new; + + if (p == NULL || p->l_prev == NULL) { + topo_list_prepend(lp, new); + return; + } + + q->l_prev = p->l_prev; + q->l_next = p; + p->l_prev = q; + q->l_prev->l_next = q; +} + +void +topo_list_insert_after(topo_list_t *lp, void *after_me, void *new) +{ + topo_list_t *p = after_me; + topo_list_t *q = new; + + if (p == NULL || p->l_next == NULL) { + topo_list_append(lp, new); + return; + } + + q->l_next = p->l_next; + q->l_prev = p; + p->l_next = q; + q->l_next->l_prev = q; +} + +void +topo_list_delete(topo_list_t *lp, void *existing) +{ + topo_list_t *p = existing; + + if (p->l_prev != NULL) + p->l_prev->l_next = p->l_next; + else + lp->l_next = p->l_next; + + if (p->l_next != NULL) + p->l_next->l_prev = p->l_prev; + else + lp->l_prev = p->l_prev; +} + +tnode_t * +topo_child_first(tnode_t *pnode) +{ + int i; + topo_nodehash_t *nhp; + + for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL; + nhp = topo_list_next(nhp)) { + for (i = 0; i < nhp->th_arrlen; ++i) { + if (nhp->th_nodearr[i] != NULL) + return (nhp->th_nodearr[i]); + } + } + + return (NULL); +} + +tnode_t * +topo_child_next(tnode_t *pnode, tnode_t *node) +{ + int i; + int index; + topo_nodehash_t *nhp; + + if (node == NULL) { + return (topo_child_first(pnode)); + } + + /* + * Begin search for next child in the current hash array + * If none found or we are at the end of the array, move + * on to the next array + */ + index = topo_node_hash(node->tn_phash, node->tn_instance) + 1; + for (nhp = node->tn_phash; nhp != NULL; nhp = topo_list_next(nhp)) { + for (i = index; i < nhp->th_arrlen; ++i) { + if (nhp->th_nodearr[i] != NULL) { + return (nhp->th_nodearr[i]); + } + } + index = 0; + } + + return (NULL); +} diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_list.h b/usr/src/lib/fm/topo/libtopo/common/topo_list.h new file mode 100644 index 0000000000..7143490915 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_list.h @@ -0,0 +1,61 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _TOPO_LIST_H +#define _TOPO_LIST_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <fm/libtopo.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct topo_list { + struct topo_list *l_prev; + struct topo_list *l_next; +} topo_list_t; + +#define topo_list_prev(elem) ((void *)(((topo_list_t *)(elem))->l_prev)) +#define topo_list_next(elem) ((void *)(((topo_list_t *)(elem))->l_next)) + +extern void topo_list_append(topo_list_t *, void *); +extern void topo_list_prepend(topo_list_t *, void *); +extern void topo_list_insert_before(topo_list_t *, void *, void *); +extern void topo_list_insert_after(topo_list_t *, void *, void *); +extern void topo_list_delete(topo_list_t *, void *); + +/* Helpers for child/sibling lists */ +extern tnode_t *topo_child_first(tnode_t *); +extern tnode_t *topo_child_next(tnode_t *, tnode_t *); +extern topo_list_t *topo_sibling_list(tnode_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _TOPO_LIST_H */ diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_method.c b/usr/src/lib/fm/topo/libtopo/common/topo_method.c new file mode 100644 index 0000000000..984e2c1699 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_method.c @@ -0,0 +1,251 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <pthread.h> +#include <assert.h> +#include <errno.h> +#include <dirent.h> +#include <limits.h> +#include <alloca.h> +#include <unistd.h> +#include <stdio.h> +#include <strings.h> + +#include <topo_mod.h> + +#include <topo_error.h> +#include <topo_module.h> +#include <topo_subr.h> +#include <topo_tree.h> + +static topo_imethod_t * +topo_method_lookup(tnode_t *node, const char *name) +{ + topo_imethod_t *mp; + + topo_node_lock(node); + for (mp = topo_list_next(&node->tn_methods); mp != NULL; + mp = topo_list_next(mp)) { + if (strcmp(name, mp->tim_name) == 0) { + topo_node_unlock(node); + return (mp); + } + } + topo_node_unlock(node); + + return (NULL); +} + +static void +topo_method_enter(topo_imethod_t *mp) +{ + (void) pthread_mutex_lock(&mp->tim_lock); + + while (mp->tim_busy != 0) + (void) pthread_cond_wait(&mp->tim_cv, &mp->tim_lock); + + ++mp->tim_busy; + + (void) pthread_mutex_unlock(&mp->tim_lock); +} + +static void +topo_method_exit(topo_imethod_t *mp) +{ + (void) pthread_mutex_lock(&mp->tim_lock); + --mp->tim_busy; + + assert(mp->tim_busy == 0); + + (void) pthread_mutex_unlock(&mp->tim_lock); +} + +static int +set_methregister_error(topo_mod_t *mod, tnode_t *node, topo_imethod_t *mp, + int err) +{ + if (mp != NULL) { + topo_list_delete(&node->tn_methods, mp); + if (mp->tim_name != NULL) + topo_mod_strfree(mod, mp->tim_name); + if (mp->tim_desc != NULL) + topo_mod_strfree(mod, mp->tim_desc); + + topo_mod_free(mod, mp, sizeof (topo_imethod_t)); + } + + topo_dprintf(TOPO_DBG_ERR, "method registration failed for %s: %s\n", + mod->tm_name, topo_strerror(err)); + + return (topo_mod_seterrno(mod, err)); +} + +int +topo_method_register(topo_mod_t *mod, tnode_t *node, const topo_method_t *mp) +{ + topo_imethod_t *imp; + const topo_method_t *meth; + + /* + * Initialize module methods + */ + for (meth = &mp[0]; meth->tm_name != NULL; meth++) { + + if (topo_method_lookup(node, meth->tm_name) != NULL) + continue; + + if (meth->tm_stability < TOPO_STABILITY_INTERNAL || + meth->tm_stability > TOPO_STABILITY_MAX || + meth->tm_func == NULL) + return (set_methregister_error(mod, node, NULL, + ETOPO_METHOD_INVAL)); + + imp = topo_mod_zalloc(mod, sizeof (topo_imethod_t)); + if (imp == NULL) + return (set_methregister_error(mod, node, imp, + ETOPO_NOMEM)); + + if ((imp->tim_name = topo_mod_strdup(mod, meth->tm_name)) + == NULL) + return (set_methregister_error(mod, node, imp, + ETOPO_NOMEM)); + + if ((imp->tim_desc = topo_mod_strdup(mod, meth->tm_desc)) + == NULL) + return (set_methregister_error(mod, node, imp, + ETOPO_NOMEM)); + + + imp->tim_stability = meth->tm_stability; + imp->tim_version = meth->tm_version; + imp->tim_func = meth->tm_func; + imp->tim_mod = mod; + + topo_node_lock(node); + topo_list_append(&node->tn_methods, imp); + topo_node_unlock(node); + + topo_dprintf(TOPO_DBG_MOD, "registered module %s method " + "%s for %s=%d\n", mod->tm_name, imp->tim_name, + topo_node_name(node), topo_node_instance(node)); + + } + + return (0); +} + +void +topo_method_unregister(topo_mod_t *mod, tnode_t *node, const char *name) +{ + topo_imethod_t *mp; + + topo_node_lock(node); + for (mp = topo_list_next(&node->tn_methods); mp != NULL; + mp = topo_list_next(mp)) { + if (strcmp(name, mp->tim_name) == 0) + break; + } + + if (mp == NULL) { + topo_node_unlock(node); + return; + } + + topo_list_delete(&node->tn_methods, mp); + topo_node_unlock(node); + + if (mp->tim_name != NULL) + topo_mod_strfree(mod, mp->tim_name); + if (mp->tim_desc != NULL) + topo_mod_strfree(mod, mp->tim_desc); + + topo_mod_free(mod, mp, sizeof (topo_imethod_t)); +} + +void +topo_method_unregister_all(topo_mod_t *mod, tnode_t *node) +{ + topo_imethod_t *mp; + + topo_node_lock(node); + while ((mp = topo_list_next(&node->tn_methods)) != NULL) { + topo_list_delete(&node->tn_methods, mp); + if (mp->tim_name != NULL) + topo_mod_strfree(mod, mp->tim_name); + if (mp->tim_desc != NULL) + topo_mod_strfree(mod, mp->tim_desc); + topo_mod_free(mod, mp, sizeof (topo_imethod_t)); + } + topo_node_unlock(node); +} + + +int +topo_method_invoke(tnode_t *node, const char *method, + topo_version_t version, nvlist_t *in, nvlist_t **out, int *err) +{ + int rc; + topo_imethod_t *mp; + + topo_node_hold(node); + for (mp = topo_list_next(&node->tn_methods); mp != NULL; + mp = topo_list_next(mp)) { + if (strcmp(method, mp->tim_name) != 0) + continue; + + if (version < mp->tim_version) { + *err = ETOPO_VER_NEW; + topo_node_rele(node); + return (-1); + } else if (version > mp->tim_version) { + *err = ETOPO_VER_OLD; + topo_node_rele(node); + return (-1); + } + + topo_method_enter(mp); + if ((rc = mp->tim_func(mp->tim_mod, node, version, in, out)) + < 0) { + if (mp->tim_mod->tm_errno == 0) + *err = ETOPO_METHOD_FAIL; + else + *err = mp->tim_mod->tm_errno; + } + topo_method_exit(mp); + + topo_node_rele(node); + + return (rc); + + } + topo_node_rele(node); + + *err = ETOPO_METHOD_NOTSUP; + + return (-1); +} diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_mod.c b/usr/src/lib/fm/topo/libtopo/common/topo_mod.c new file mode 100644 index 0000000000..80a2088920 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_mod.c @@ -0,0 +1,281 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Topology Plugin Modules + * + * Topology plugin modules are shared libraries that are dlopen'd and + * used to enumerate resources in the system. + * They are loaded by our builtin scheme-specific plugins or other modules + * to enumerate and create nodes for resources that are present in the system. + * They may also export a set of resource (node) specific methods that can be + * called on node-by-node basis. + * + * Module Plugin API + * + * Enumerators must provide entry points for intialization and clean-up + * (_topo_init() and _topo_fini()). In their _topo_init() function, an + * enumerator should register (topo_mod_register()) its enumeration callback + * and allocate resources required for a subsequent call to the callback. + * Optionally, methods may also be registered with topo_method_register(). + * + * In its enumeration callback routine, the module should search for resources + * within its realm of resposibility and create any node ranges, + * topo_node_range_create() or nodes, topo_node_bind(). The Enumerator + * module is handed a node to which it may begin attaching additional + * topology nodes. + * + * If additional helper modules need to be loaded to complete the enumeration + * the module may do so by calling topo_mod_load(). Enumeration may then + * continue with the module handing off enumeration to its helper module + * by calling topo_mod_enumerate(). + * + * If the module registers a release callback, it will be called on a node + * by node basis during topo_snap_rele(). Any private node data may be + * deallocated or methods unregistered at that time. Global module data + * should be clean-up before or at the time that the module _topo_fini + * entry point is called. + */ + +#include <pthread.h> +#include <assert.h> +#include <errno.h> +#include <dirent.h> +#include <limits.h> +#include <alloca.h> +#include <unistd.h> +#include <stdio.h> + +#include <topo_module.h> +#include <topo_alloc.h> +#include <topo_string.h> +#include <topo_error.h> +#include <topo_subr.h> + +topo_mod_t * +topo_mod_load(topo_mod_t *pmod, const char *path) +{ + int err = 0; + char *p; + topo_mod_t *mod = NULL; + topo_hdl_t *thp; + + thp = pmod->tm_hdl; + + /* + * Already loaded, bump the ref count + */ + if ((mod = topo_mod_lookup(thp, path)) != NULL) { + topo_mod_hold(mod); + return (mod); + } + + /* + * Check for a valid path + */ + if (access(path, F_OK) != 0) { + (void) topo_mod_seterrno(pmod, ETOPO_MOD_NOENT); + return (NULL); + } + + if ((p = strrchr(path, '.')) != NULL && strcmp(p, ".so") == 0) { + if ((mod = topo_modhash_load(thp, path, + &topo_rtld_ops)) == NULL) { /* returned with mod held */ + (void) topo_mod_seterrno(pmod, err ? err : + ETOPO_MOD_NOENT); + return (NULL); + } + } else { + (void) topo_mod_seterrno(pmod, err ? err : ETOPO_MOD_NOENT); + return (NULL); + } + + return (mod); +} + +void +topo_mod_unload(topo_mod_t *mod) +{ + topo_mod_rele(mod); +} + +static int +set_register_error(topo_mod_t *mod, int err) +{ + if (mod->tm_info != NULL) + topo_mod_unregister(mod); + + topo_dprintf(TOPO_DBG_ERR, "module registration failed for %s: %s\n", + mod->tm_name, topo_strerror(err)); + + return (topo_mod_seterrno(mod, err)); +} + +int +topo_mod_register(topo_mod_t *mod, const topo_modinfo_t *mip, void *priv) +{ + + assert(!(mod->tm_flags & TOPO_MOD_FINI || + mod->tm_flags & TOPO_MOD_REG)); + + if (mod->tm_version > mip->tmi_version) + return (set_register_error(mod, ETOPO_VER_OLD)); + if (mod->tm_version < mip->tmi_version) + return (set_register_error(mod, ETOPO_VER_NEW)); + + if ((mod->tm_info = topo_mod_alloc(mod, sizeof (topo_modinfo_t))) + == NULL) + return (set_register_error(mod, ETOPO_NOMEM)); + + mod->tm_info->tmi_desc = topo_mod_strdup(mod, mip->tmi_desc); + if (mod->tm_info->tmi_desc == NULL) + return (set_register_error(mod, ETOPO_NOMEM)); + + mod->tm_info->tmi_version = (topo_version_t)mip->tmi_version; + mod->tm_info->tmi_enum = mip->tmi_enum; + mod->tm_info->tmi_release = mip->tmi_release; + + mod->tm_flags |= TOPO_MOD_REG; + mod->tm_priv = priv; + + if (mod == NULL) { + topo_dprintf(TOPO_DBG_MOD, "registration succeeded for %s\n", + mod->tm_name); + + return (0); + } + + + topo_dprintf(TOPO_DBG_MOD, "registration succeeded for %s\n", + mod->tm_name); + + return (0); +} + +void +topo_mod_unregister(topo_mod_t *mod) +{ + if (mod->tm_info == NULL) + return; + + assert(!(mod->tm_flags & TOPO_MOD_FINI)); + + mod->tm_flags &= ~TOPO_MOD_REG; + + if (mod->tm_info == NULL) + return; + + if (mod->tm_info->tmi_desc != NULL) + topo_mod_strfree(mod, mod->tm_info->tmi_desc); + + topo_mod_free(mod, mod->tm_info, sizeof (topo_modinfo_t)); + + mod->tm_info = NULL; +} + +int +topo_mod_enumerate(topo_mod_t *mod, tnode_t *node, const char *enum_name, + const char *name, topo_instance_t min, topo_instance_t max) +{ + int err = 0; + topo_mod_t *enum_mod; + + assert(mod->tm_flags & TOPO_MOD_REG); + + if ((enum_mod = topo_mod_lookup(mod->tm_hdl, enum_name)) == NULL) + return (topo_mod_seterrno(mod, ETOPO_MOD_NOENT)); + + topo_node_hold(node); + + topo_dprintf(TOPO_DBG_MOD, "module %s enumerating node %s=%d\n", + (char *)mod->tm_name, (char *)node->tn_name, node->tn_instance); + + topo_mod_enter(enum_mod); + err = enum_mod->tm_info->tmi_enum(enum_mod, node, name, min, max, + enum_mod->tm_priv); + topo_mod_exit(enum_mod); + + if (err != 0) { + (void) topo_mod_seterrno(mod, ETOPO_MODULE); + + topo_dprintf(TOPO_DBG_ERR, "module %s failed enumeration for " + " node %s=%d\n", (char *)mod->tm_name, + (char *)node->tn_name, node->tn_instance); + + topo_node_rele(node); + return (-1); + } + + topo_node_rele(node); + + return (0); +} + +char * +topo_mod_rootdir(topo_mod_t *mod) +{ + return (mod->tm_rootdir); +} + +topo_hdl_t * +topo_mod_handle(topo_mod_t *mod) +{ + return (mod->tm_hdl); +} + +void * +topo_mod_private(topo_mod_t *mod) +{ + return (mod->tm_priv); +} + +void +topo_mod_setdebug(topo_mod_t *mod, int mask) +{ + mod->tm_debug |= mask; +} + +void +topo_mod_clrdebug(topo_mod_t *mod) +{ + mod->tm_debug = 0; +} + +/*PRINTFLIKE2*/ +void +topo_mod_dprintf(topo_mod_t *mod, const char *format, ...) +{ + if (mod->tm_debug & mod->tm_hdl->th_debug) { + va_list alist; + + va_start(alist, format); + (void) fputs("libtopo DEBUG: ", stderr); + (void) vfprintf(stderr, format, alist); + va_end(alist); + } +} diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_mod.h b/usr/src/lib/fm/topo/libtopo/common/topo_mod.h new file mode 100644 index 0000000000..a0edeb0cb4 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_mod.h @@ -0,0 +1,184 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _TOPO_MOD_H +#define _TOPO_MOD_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <fm/libtopo.h> +#include <libnvpair.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Enumerator and method supplier module API + */ +typedef struct topo_mod topo_mod_t; + +typedef int topo_method_f(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); +typedef int topo_enum_f(topo_mod_t *, tnode_t *, const char *, topo_instance_t, + topo_instance_t, void *); +typedef void topo_release_f(topo_mod_t *, tnode_t *); + +typedef struct topo_method { + const char *tm_name; /* Method name */ + const char *tm_desc; /* Method description */ + const topo_version_t tm_version; /* Method version */ + const topo_stability_t tm_stability; /* Attributes of method */ + topo_method_f *tm_func; /* Method function */ +} topo_method_t; + +typedef struct topo_mod_info { + char *tmi_desc; /* Client module description */ + topo_version_t tmi_version; /* Client module version */ + topo_enum_f *tmi_enum; /* enumerator function */ + topo_release_f *tmi_release; /* de-enumerator function */ +} topo_modinfo_t; + +extern topo_mod_t *topo_mod_load(topo_mod_t *, const char *); +extern void topo_mod_unload(topo_mod_t *); +extern int topo_mod_register(topo_mod_t *, const topo_modinfo_t *, void *); +extern void topo_mod_unregister(topo_mod_t *); +extern int topo_mod_enumerate(topo_mod_t *, tnode_t *, const char *, + const char *, topo_instance_t, topo_instance_t); +extern void topo_mod_release(topo_mod_t *, tnode_t *); +extern char *topo_mod_rootdir(topo_mod_t *); +extern void *topo_mod_private(topo_mod_t *); +extern topo_hdl_t *topo_mod_handle(topo_mod_t *); + +extern int topo_method_register(topo_mod_t *, tnode_t *, const topo_method_t *); +extern void topo_method_unregister(topo_mod_t *, tnode_t *, const char *); +extern void topo_method_unregister_all(topo_mod_t *, tnode_t *); + +/* + * FMRI methods + */ +#define TOPO_METH_ASRU_COMPUTE "topo_asru_compute" +#define TOPO_METH_FRU_COMPUTE "topo_fru_compute" +#define TOPO_METH_FMRI "topo_fmri" +#define TOPO_METH_LABEL "topo_label" +#define TOPO_METH_NVL2STR "topo_nvl2str" +#define TOPO_METH_STR2NVL "topo_str2nvl" +#define TOPO_METH_PRESENT "topo_present" +#define TOPO_METH_CONTAINS "topo_contains" +#define TOPO_METH_UNUSABLE "topo_unusable" +#define TOPO_METH_EXPAND "topo_expand" +#define TOPO_METH_COMPARE "topo_compare" + +#define TOPO_METH_FMRI_VERSION 0 +#define TOPO_METH_LABEL_VERSION 0 +#define TOPO_METH_FRU_COMPUTE_VERSION 0 +#define TOPO_METH_ASRU_COMPUTE_VERSION 0 +#define TOPO_METH_NVL2STR_VERSION 0 +#define TOPO_METH_STR2NVL_VERSION 0 +#define TOPO_METH_PRESENT_VERSION 0 +#define TOPO_METH_CONTAINS_VERSION 0 +#define TOPO_METH_UNUSABLE_VERSION 0 +#define TOPO_METH_EXPAND_VERSION 0 +#define TOPO_METH_COMPARE_VERSION 0 + +#define TOPO_METH_ASRU_COMPUTE_DESC "Dynamic ASRU constructor" +#define TOPO_METH_FRU_COMPUTE_DESC "Dynamic FRU constructor" +#define TOPO_METH_FMRI_DESC "Dynamic FMRI constructor" +#define TOPO_METH_LABEL_DESC "Dynamic label discovery" +#define TOPO_METH_NVL2STR_DESC "FMRI to string" +#define TOPO_METH_STR2NVL_DESC "string to FMRI" +#define TOPO_METH_PRESENT_DESC "FMRI is present" +#define TOPO_METH_CONTAINS_DESC "FMRI contains sub-FMRI" +#define TOPO_METH_UNUSABLE_DESC "FMRI is unusable" +#define TOPO_METH_EXPAND_DESC "expand FMRI" +#define TOPO_METH_COMPARE_DESC "compare two FMRIs" + +#define TOPO_METH_FMRI_ARG_NAME "child-name" +#define TOPO_METH_FMRI_ARG_INST "child-inst" +#define TOPO_METH_FMRI_ARG_NVL "args" +#define TOPO_METH_FMRI_ARG_PARENT "parent-fmri" +#define TOPO_METH_FMRI_ARG_AUTH "auth" +#define TOPO_METH_FMRI_ARG_PART "part" +#define TOPO_METH_FMRI_ARG_REV "rev" +#define TOPO_METH_FMRI_ARG_SER "serial" + +#define TOPO_METH_LABEL_ARG_NVL "label-private" +#define TOPO_METH_LABEL_RET_STR "label-string" + +extern void *topo_mod_alloc(topo_mod_t *, size_t); +extern void *topo_mod_zalloc(topo_mod_t *, size_t); +extern void topo_mod_free(topo_mod_t *, void *, size_t); +extern char *topo_mod_strdup(topo_mod_t *, const char *); +extern void topo_mod_strfree(topo_mod_t *, char *); +extern int topo_mod_nvalloc(topo_mod_t *, nvlist_t **, uint_t); +extern int topo_mod_nvdup(topo_mod_t *, nvlist_t *, nvlist_t **); + +extern void topo_mod_clrdebug(topo_mod_t *); +extern void topo_mod_setdebug(topo_mod_t *, int); +extern void topo_mod_dprintf(topo_mod_t *, const char *, ...); +extern const char *topo_mod_errmsg(topo_mod_t *); +extern int topo_mod_errno(topo_mod_t *); + +/* + * Topo node utilities: callable from module enumeration, topo_mod_enumerate() + */ +extern int topo_node_range_create(topo_mod_t *, tnode_t *, const char *, + topo_instance_t, topo_instance_t); +extern void topo_node_range_destroy(tnode_t *, const char *); +extern tnode_t *topo_node_bind(topo_mod_t *, tnode_t *, const char *, + topo_instance_t, nvlist_t *, void *); +extern void topo_node_unbind(tnode_t *); + +/* + * This enum definition is used to define a set of error tags associated with + * the fmd daemon's various error conditions. The shell script mkerror.sh is + * used to parse this file and create a corresponding topo_error.c source file. + * If you do something other than add a new error tag here, you may need to + * update the mkerror shell script as it is based upon simple regexps. + */ +typedef enum topo_mod_errno { + EMOD_UNKNOWN = 2000, /* unknown libtopo error */ + EMOD_NOMEM, /* module memory limit exceeded */ + EMOD_PARTIAL_ENUM, /* module completed partial enumeration */ + EMOD_METHOD_INVAL, /* method arguments invalid */ + EMOD_METHOD_NOTSUP, /* method not supported */ + EMOD_FMRI_NVL, /* nvlist allocation failure for FMRI */ + EMOD_FMRI_VERSION, /* invalid FMRI scheme version */ + EMOD_FMRI_MALFORM, /* malformed FMRI */ + EMOD_VER_OLD, /* module compiled using an obsolete topo ABI */ + EMOD_VER_NEW, /* module is compiled using a newer topo ABI */ + EMOD_NVL_INVAL, /* invalid nvlist */ + EMOD_NONCANON, /* non-canonical component name requested */ + EMOD_END /* end of mod errno list (to ease auto-merge) */ +} topo_mod_errno_t; + +extern int topo_mod_seterrno(topo_mod_t *, int); + +#ifdef __cplusplus +} +#endif + +#endif /* _TOPO_MOD_H */ diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_mod.map b/usr/src/lib/fm/topo/libtopo/common/topo_mod.map new file mode 100644 index 0000000000..d48b37c00d --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_mod.map @@ -0,0 +1,67 @@ +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +#ident "%Z%%M% %I% %E% SMI" + +{ + topo_node_range_create = FUNCTION extern; + topo_node_range_destroy = FUNCTION extern; + topo_node_bind = FUNCTION extern; + topo_node_unbind = FUNCTION extern; + topo_node_name = FUNCTION extern; + topo_node_private = FUNCTION extern; + topo_node_instance = FUNCTION extern; + + topo_mod_alloc = FUNCTION extern; + topo_mod_zalloc = FUNCTION extern; + topo_mod_free = FUNCTION extern; + topo_mod_nvalloc = FUNCTION extern; + topo_mod_nvdup = FUNCTION extern; + topo_mod_strfree = FUNCTION extern; + topo_mod_strdup = FUNCTION extern; + + topo_fmri_create = FUNCTION extern; + + topo_mod_clrdebug = FUNCTION extern; + topo_mod_setdebug = FUNCTION extern; + topo_mod_dprintf = FUNCTION extern; + topo_mod_errmsg = FUNCTION extern; + topo_mod_errno = FUNCTION extern; + + topo_mod_load = FUNCTION extern; + topo_mod_unload = FUNCTION extern; + topo_mod_register = FUNCTION extern; + topo_mod_unregister = FUNCTION extern; + topo_mod_enumerate = FUNCTION extern; + topo_mod_release = FUNCTION extern; + topo_mod_rootdir = FUNCTION extern; + topo_mod_handle = FUNCTION extern; + topo_mod_private = FUNCTION extern; + + topo_method_register = FUNCTION extern; + topo_method_unregister = FUNCTION extern; + topo_method_unregister_all = FUNCTION extern; + topo_method_invoke = FUNCTION extern; + +}; diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_module.c b/usr/src/lib/fm/topo/libtopo/common/topo_module.c new file mode 100644 index 0000000000..4eb9ea9254 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_module.c @@ -0,0 +1,406 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in comodliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <signal.h> +#include <dirent.h> +#include <limits.h> +#include <alloca.h> +#include <unistd.h> +#include <stdio.h> +#include <pthread.h> +#include <errno.h> +#include <strings.h> +#include <assert.h> +#include <sys/nvpair.h> + +#include <topo_string.h> +#include <topo_alloc.h> +#include <topo_module.h> +#include <topo_error.h> +#include <topo_subr.h> + +extern nv_alloc_ops_t topo_nv_alloc_ops; + +void +topo_mod_release(topo_mod_t *mod, tnode_t *node) +{ + topo_mod_enter(mod); + + if (mod->tm_info->tmi_release != NULL) + mod->tm_info->tmi_release(mod, node); + + topo_mod_exit(mod); +} + +void +topo_mod_hold(topo_mod_t *mod) +{ + (void) pthread_mutex_lock(&mod->tm_lock); + mod->tm_refs++; + assert(mod->tm_refs != 0); + (void) pthread_mutex_unlock(&mod->tm_lock); +} + +void +topo_mod_rele(topo_mod_t *mod) +{ + assert(mod->tm_refs != 0); + + (void) pthread_mutex_lock(&mod->tm_lock); + + /* + * Lazy unload module + */ + if (--mod->tm_refs == 0) + topo_modhash_unload(mod); + else + (void) pthread_mutex_unlock(&mod->tm_lock); +} + +void +topo_mod_enter(topo_mod_t *mod) +{ + (void) pthread_mutex_lock(&mod->tm_lock); + + while (mod->tm_busy != 0) + (void) pthread_cond_wait(&mod->tm_cv, &mod->tm_lock); + + ++mod->tm_busy; + + (void) pthread_mutex_unlock(&mod->tm_lock); +} + +void +topo_mod_exit(topo_mod_t *mod) +{ + (void) pthread_mutex_lock(&mod->tm_lock); + --mod->tm_busy; + + assert(mod->tm_busy == 0); + + (void) pthread_cond_broadcast(&mod->tm_cv); + (void) pthread_mutex_unlock(&mod->tm_lock); +} + +static void +topo_modhash_lock(topo_modhash_t *mhp) +{ + (void) pthread_mutex_lock(&mhp->mh_lock); +} + +static void +topo_modhash_unlock(topo_modhash_t *mhp) +{ + (void) pthread_mutex_unlock(&mhp->mh_lock); +} + +static void +topo_mod_stop(topo_mod_t *mod) +{ + if (mod->tm_flags & TOPO_MOD_INIT) { + mod->tm_mops->mop_fini(mod); + if (mod->tm_flags & TOPO_MOD_REG) + topo_mod_unregister(mod); + } + + mod->tm_flags = TOPO_MOD_FINI; + + topo_dprintf(TOPO_DBG_MOD, "module %s stopped\n", mod->tm_name); +} + +static int +topo_mod_start(topo_mod_t *mod) +{ + topo_dprintf(TOPO_DBG_MOD, "starting module %s\n", mod->tm_name); + + if (mod->tm_mops->mop_init(mod) != 0) { + mod->tm_errno = errno ? errno : ETOPO_MOD_INIT; + topo_dprintf(TOPO_DBG_ERR, + "module %s failed to initialize: %s\n", mod->tm_name, + topo_strerror(mod->tm_errno)); + return (-1); + } + + mod->tm_flags |= TOPO_MOD_INIT; + + if (!(mod->tm_flags & TOPO_MOD_REG)) { + topo_dprintf(TOPO_DBG_ERR, + "module %s failed to register\n", mod->tm_name); + mod->tm_errno = ETOPO_MOD_NOREG; + topo_mod_stop(mod); + return (-1); + } + + topo_dprintf(TOPO_DBG_MOD, "module %s started\n", mod->tm_name); + + return (0); +} + +topo_mod_t * +topo_mod_lookup(topo_hdl_t *thp, const char *path) +{ + char *p; + char name[PATH_MAX]; + topo_mod_t *mod; + topo_modhash_t *mhp = thp->th_modhash; + + (void) strlcpy(name, topo_strbasename(path), sizeof (name)); + if ((p = strrchr(name, '.')) != NULL && strcmp(p, ".so") == 0) + *p = '\0'; /* strip trailing .so from any module name */ + + topo_modhash_lock(mhp); + mod = topo_modhash_lookup(mhp, name); + topo_modhash_unlock(mhp); + + return (mod); +} + +static void +topo_mod_destroy(topo_mod_t *mod) +{ + topo_hdl_t *thp = mod->tm_hdl; + + if (mod == NULL) + return; + + assert(mod->tm_refs == 0); + assert(!topo_mutex_held(&mod->tm_lock)); + + if (mod->tm_name != NULL) + topo_hdl_strfree(thp, mod->tm_name); + if (mod->tm_path != NULL) + topo_hdl_strfree(thp, mod->tm_path); + if (mod->tm_rootdir != NULL) + topo_hdl_strfree(thp, mod->tm_rootdir); + + topo_hdl_free(thp, mod, sizeof (topo_mod_t)); +} + +static topo_mod_t * +set_create_error(topo_hdl_t *thp, topo_mod_t *mod, const char *path, int err) +{ + topo_dprintf(TOPO_DBG_ERR, "unable to load module %s: %s\n", + path, topo_strerror(err)); + + if (mod != NULL) + topo_mod_destroy(mod); + + (void) topo_hdl_seterrno(thp, err); + + return (NULL); +} + +static topo_mod_t * +topo_mod_create(topo_hdl_t *thp, const char *name, const char *path, + const topo_modops_t *ops) +{ + topo_mod_t *mod; + + if (topo_modhash_lookup(thp->th_modhash, name) != NULL) + return (set_create_error(thp, NULL, path, ETOPO_MOD_LOADED)); + + if ((mod = topo_hdl_zalloc(thp, sizeof (topo_mod_t))) == NULL) + return (set_create_error(thp, mod, path, ETOPO_NOMEM)); + + (void) pthread_mutex_init(&mod->tm_lock, NULL); + + mod->tm_name = topo_hdl_strdup(thp, name); + mod->tm_path = topo_hdl_strdup(thp, path); + mod->tm_rootdir = topo_hdl_strdup(thp, thp->th_rootdir); + if (mod->tm_name == NULL || mod->tm_path == NULL || + mod->tm_rootdir == NULL) + return (set_create_error(thp, mod, path, ETOPO_NOMEM)); + + mod->tm_mops = (topo_modops_t *)ops; + mod->tm_hdl = thp; + mod->tm_alloc = thp->th_alloc; + mod->tm_version = TOPO_VERSION; + + /* + * Module will be held upon a successful return from topo_mod_start() + */ + if ((topo_mod_start(mod)) < 0) + return (set_create_error(thp, mod, path, mod->tm_errno)); + + topo_dprintf(TOPO_DBG_MOD, "loaded module %s\n", mod->tm_name); + + return (mod); +} + +topo_modhash_t * +topo_modhash_create(topo_hdl_t *thp) +{ + topo_modhash_t *mhp; + + if ((mhp = topo_hdl_zalloc(thp, sizeof (topo_modhash_t))) == NULL) + return (NULL); + + mhp->mh_hashlen = TOPO_HASH_BUCKETS; + if ((mhp->mh_hash = topo_hdl_zalloc(thp, + sizeof (void *) * mhp->mh_hashlen)) == NULL) { + topo_hdl_free(thp, mhp, sizeof (topo_modhash_t)); + return (NULL); + } + mhp->mh_nelems = 0; + (void) pthread_mutex_init(&mhp->mh_lock, NULL); + + thp->th_modhash = mhp; + + return (mhp); +} + +void +topo_modhash_destroy(topo_hdl_t *thp) +{ + topo_modhash_t *mhp = thp->th_modhash; + + if (mhp == NULL) + return; + + assert(mhp->mh_nelems == 0); + + topo_hdl_free(thp, mhp->mh_hash, sizeof (void *) * mhp->mh_hashlen); + topo_hdl_free(thp, mhp, sizeof (topo_modhash_t)); + thp->th_modhash = NULL; +} + +topo_mod_t * +topo_modhash_lookup(topo_modhash_t *mhp, const char *name) +{ + topo_mod_t *mod = NULL; + uint_t h; + + h = topo_strhash(name) % mhp->mh_hashlen; + + for (mod = mhp->mh_hash[h]; mod != NULL; mod = mod->tm_next) { + if (strcmp(name, mod->tm_name) == 0) + break; + } + + return (mod); +} + +topo_mod_t * +topo_modhash_load(topo_hdl_t *thp, const char *path, const topo_modops_t *ops) +{ + char name[PATH_MAX], *p; + topo_modhash_t *mhp = thp->th_modhash; + topo_mod_t *mod; + uint_t h; + + topo_modhash_lock(mhp); + + (void) strlcpy(name, topo_strbasename(path), sizeof (name)); + if ((p = strrchr(name, '.')) != NULL && strcmp(p, ".so") == 0) + *p = '\0'; /* strip trailing .so from any module name */ + + if ((mod = topo_mod_create(thp, name, path, ops)) == NULL) { + topo_hdl_unlock(thp); + return (NULL); /* th_errno set */ + } + + topo_mod_hold(mod); + + h = topo_strhash(name) % mhp->mh_hashlen; + mod->tm_next = mhp->mh_hash[h]; + mhp->mh_hash[h] = mod; + mhp->mh_nelems++; + topo_modhash_unlock(mhp); + + return (mod); +} + +void +topo_modhash_unload(topo_mod_t *mod) +{ + uint_t h; + topo_mod_t **pp, *mp; + topo_hdl_t *thp = mod->tm_hdl; + topo_modhash_t *mhp; + + assert(topo_mutex_held(&mod->tm_lock)); + assert(mod->tm_busy == 0); + + mhp = thp->th_modhash; + topo_modhash_lock(mhp); + + assert(mhp != NULL); + + h = topo_strhash(mod->tm_name) % mhp->mh_hashlen; + pp = &mhp->mh_hash[h]; + + for (mp = *pp; mp != NULL; mp = mp->tm_next) { + if (mp == mod) + break; + else + pp = &mp->tm_next; + } + + if (mp != NULL) { + *pp = mod->tm_next; + + assert(mhp->mh_nelems != 0); + + mhp->mh_nelems--; + + } + topo_modhash_unlock(mhp); + + (void) pthread_mutex_unlock(&mod->tm_lock); + + topo_mod_stop(mod); + topo_mod_destroy(mod); + +} + +void +topo_modhash_unload_all(topo_hdl_t *thp) +{ + int i; + topo_modhash_t *mhp = thp->th_modhash; + topo_mod_t *mp, **pp; + + topo_modhash_lock(mhp); + for (i = 0; i < TOPO_HASH_BUCKETS; ++i) { + pp = &mhp->mh_hash[i]; + mp = *pp; + while (mp != NULL) { + topo_mod_stop(mp); + + assert(mp->tm_refs == 1); + + --mp->tm_refs; + *pp = mp->tm_next; + topo_mod_destroy(mp); + mp = *pp; + + --mhp->mh_nelems; + } + } + topo_modhash_unlock(mhp); +} diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_module.h b/usr/src/lib/fm/topo/libtopo/common/topo_module.h new file mode 100644 index 0000000000..e482b524d1 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_module.h @@ -0,0 +1,105 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _TOPO_MODULE_H +#define _TOPO_MODULE_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <fm/topo_mod.h> + +#include <topo_list.h> +#include <topo_tree.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct topo_modops { + int (*mop_init)(struct topo_mod *); + int (*mop_fini)(struct topo_mod *); +} topo_modops_t; + +#define TOPO_HASH_BUCKETS 3 + +struct topo_modhash { + pthread_mutex_t mh_lock; /* hash lock */ + struct topo_mod **mh_hash; /* hash bucket array */ + uint_t mh_hashlen; /* size of hash bucket array */ + uint_t mh_nelems; /* number of modules in hash */ +}; + +struct topo_mod { + pthread_mutex_t tm_lock; /* Lock for tm_cv/owner/flags/refs */ + pthread_cond_t tm_cv; /* Module condition variable */ + uint_t tm_busy; /* Busy indicator */ + struct topo_mod *tm_next; /* Next module in hash chain */ + topo_hdl_t *tm_hdl; /* Topo handle for this module */ + topo_alloc_t *tm_alloc; /* Allocators */ + char *tm_name; /* Basename of module */ + char *tm_path; /* Full pathname of module file */ + char *tm_rootdir; /* Relative root directory of module */ + void *tm_priv; /* Module private data */ + topo_version_t tm_version; /* Module ABI version */ + topo_stability_t tm_stability; /* SMI stability level */ + uint_t tm_refs; /* Module reference count */ + uint_t tm_flags; /* Miscellaneous flags (see below) */ + uint_t tm_debug; /* Debug printf mask */ + void *tm_data; /* Private rtld/builtin data */ + topo_modops_t *tm_mops; /* Module class ops vector */ + topo_modinfo_t *tm_info; /* Module info registered with handle */ + int tm_errno; /* Module error */ +}; + +#define TOPO_MOD_INIT 0x001 /* Module init completed */ +#define TOPO_MOD_FINI 0x002 /* Module fini completed */ +#define TOPO_MOD_REG 0x004 /* topo_modinfo_t registered */ +#define TOPO_MOD_UNREG 0x008 /* Module unregistered */ + +extern const topo_modops_t topo_bltin_ops; +extern const topo_modops_t topo_rtld_ops; + +extern void topo_mod_enter(topo_mod_t *); +extern void topo_mod_exit(topo_mod_t *); +extern void topo_mod_hold(topo_mod_t *); +extern void topo_mod_rele(topo_mod_t *); + +extern topo_modhash_t *topo_modhash_create(topo_hdl_t *); +extern void topo_modhash_destroy(topo_hdl_t *); +extern topo_mod_t *topo_modhash_lookup(topo_modhash_t *, const char *); +extern topo_mod_t *topo_modhash_load(topo_hdl_t *, const char *, + const topo_modops_t *); +extern void topo_modhash_unload(topo_mod_t *); +extern void topo_modhash_unload_all(topo_hdl_t *); + +extern void topo_mod_release(topo_mod_t *, tnode_t *); +extern topo_mod_t *topo_mod_lookup(topo_hdl_t *, const char *); + +#ifdef __cplusplus +} +#endif + +#endif /* _TOPO_MODULE_H */ diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_node.c b/usr/src/lib/fm/topo/libtopo/common/topo_node.c new file mode 100644 index 0000000000..2b9f8257a7 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_node.c @@ -0,0 +1,502 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Topology Nodes + * + * Topology nodes, tnode_t, are data structures containing per-FMRI + * information and are linked together to form the topology tree. + * Nodes are created during the enumeration process of topo_snap_hold() + * and destroyed during topo_snap_rele(). For the most part, tnode_t data + * is read-only and no lock protection is required. Nodes are + * held in place during tree walk functions. Tree walk functions + * may access node data safely without locks. The exception to this rule + * is data associated with node properties (topo_prop.c). Properties + * may change at anytime and are protected by a per-property locking + * strategy. + * + * Enumerator plugin modules may also safely access node data. Enumeration + * occurs only during topo_snap_hold() where a per-topo_hdl_t lock prevents + * multi-threaded access to the topology trees. + * + * Like tree walking functions, method plugin modules have access to read-only + * node data but may make changes to property information. + * + * Node Interfaces + * + * Nodes are created when an enumerator calls topo_node_bind(). Prior to the + * call to topo_node_bind(), the caller should have reserved a range of + * node instances with topo_node_range_create(). topo_node_range_create() + * does not allocate any node resources but creates the infrastruture + * required for a fully populated topology level. This allows enumerators + * reading from a <scheme>-topology.xml file to parse the file for a range + * of resources before confirming the existence of a resource via a helper + * plugin. Only when the resource has been confirmed to exist should + * the node be bound. + * + * Node range and node linkage is only performed during enumeration when it + * is safe to change node hash lists and next pointers. Nodes and node ranges + * are deallocated when all references to the node have been released: + * last walk completes and topo_snap_rele() is called. + * + * Node Hash/Ranges + * + * Each parent node may have one or more ranges of child nodes. Each range + * serves as a hash list of like sibling nodes all with the same name but + * different instance numbers. A parent may have more than one node hash + * (child range). If that is the case, the hash lists are strung together to + * form sibling relationships between ranges. Hash/Ranges are sparsely + * populated with only nodes that have represented resources in the system. + */ + +#include <assert.h> +#include <pthread.h> +#include <strings.h> +#include <topo_alloc.h> +#include <topo_tree.h> +#include <topo_subr.h> +#include <topo_error.h> + +static void +topo_node_destroy(tnode_t *node) +{ + int i; + tnode_t *pnode = node->tn_parent; + topo_nodehash_t *nhp; + topo_mod_t *hmod, *mod = node->tn_enum; + + if (node == NULL) + return; + + assert(node->tn_refs == 0); + + topo_dprintf(TOPO_DBG_TREE, "destroying node %s=%d\n", node->tn_name, + node->tn_instance); + /* + * If not a root node, remove this node from the parent's node hash + */ + + if (!(node->tn_state & TOPO_NODE_ROOT)) { + topo_node_lock(pnode); + + nhp = node->tn_phash; + for (i = 0; i < nhp->th_arrlen; i++) { + if (node == nhp->th_nodearr[i]) { + nhp->th_nodearr[i] = NULL; + + /* + * Release hold on parent + */ + --pnode->tn_refs; + if (pnode->tn_refs == 0) + topo_node_destroy(pnode); + } + } + topo_node_unlock(pnode); + } + + topo_node_unlock(node); + + /* + * Allow enumerator to clean-up private data and then release + * ref count + */ + if (mod->tm_info->tmi_release != NULL) + mod->tm_info->tmi_release(mod, node); + + topo_method_unregister_all(mod, node); + + /* + * Destroy all node hash lists + */ + while ((nhp = topo_list_next(&node->tn_children)) != NULL) { + for (i = 0; i < nhp->th_arrlen; i++) { + assert(nhp->th_nodearr[i] == NULL); + } + hmod = nhp->th_enum; + topo_mod_strfree(hmod, nhp->th_name); + topo_mod_free(hmod, nhp->th_nodearr, + nhp->th_arrlen * sizeof (tnode_t *)); + topo_list_delete(&node->tn_children, nhp); + topo_mod_free(hmod, nhp, sizeof (topo_nodehash_t)); + topo_mod_rele(hmod); + } + + /* + * Destroy all property data structures, free the node and release + * the module that created it + */ + topo_pgroup_destroy_all(node); + topo_mod_free(mod, node, sizeof (tnode_t)); + topo_mod_rele(mod); +} + +void +topo_node_lock(tnode_t *node) +{ + (void) pthread_mutex_lock(&node->tn_lock); +} + +void +topo_node_unlock(tnode_t *node) +{ + (void) pthread_mutex_unlock(&node->tn_lock); +} + +void +topo_node_hold(tnode_t *node) +{ + topo_node_lock(node); + ++node->tn_refs; + topo_node_unlock(node); +} + +void +topo_node_rele(tnode_t *node) +{ + topo_node_lock(node); + --node->tn_refs; + + /* + * Ok to remove this node from the topo tree and destroy it + */ + if (node->tn_refs == 0) + topo_node_destroy(node); + else + topo_node_unlock(node); +} + +char * +topo_node_name(tnode_t *node) +{ + return (node->tn_name); +} + +topo_instance_t +topo_node_instance(tnode_t *node) +{ + return (node->tn_instance); +} + +void * +topo_node_private(tnode_t *node) +{ + return (node->tn_priv); +} + +static int +node_create_seterror(topo_mod_t *mod, tnode_t *pnode, topo_nodehash_t *nhp, + int err) +{ + topo_node_unlock(pnode); + + topo_dprintf(TOPO_DBG_ERR, "unable to insert child:" + "%s\n", topo_strerror(err)); + + if (nhp != NULL) { + if (nhp->th_name != NULL) + topo_mod_strfree(mod, nhp->th_name); + if (nhp->th_nodearr != NULL) { + topo_mod_free(mod, nhp->th_nodearr, + nhp->th_arrlen * sizeof (tnode_t *)); + } + topo_mod_free(mod, nhp, sizeof (topo_nodehash_t)); + } + + return (topo_mod_seterrno(mod, err)); +} + +int +topo_node_range_create(topo_mod_t *mod, tnode_t *pnode, const char *name, + topo_instance_t min, topo_instance_t max) +{ + topo_nodehash_t *nhp; + + topo_node_lock(pnode); + + assert((pnode->tn_state & TOPO_NODE_BOUND) || + (pnode->tn_state & TOPO_NODE_ROOT)); + + for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL; + nhp = topo_list_next(nhp)) { + if (strcmp(nhp->th_name, name) == 0) + return (node_create_seterror(mod, pnode, NULL, + ETOPO_NODE_DUP)); + } + + if (min < 0 || max < min) + return (node_create_seterror(mod, pnode, NULL, + ETOPO_NODE_INVAL)); + + if ((nhp = topo_mod_zalloc(mod, sizeof (topo_nodehash_t))) == NULL) + return (node_create_seterror(mod, pnode, nhp, ETOPO_NOMEM)); + + if ((nhp->th_name = topo_mod_strdup(mod, name)) == NULL) + return (node_create_seterror(mod, pnode, nhp, ETOPO_NOMEM)); + + nhp->th_arrlen = max - min + 1; + + if ((nhp->th_nodearr = topo_mod_zalloc(mod, + nhp->th_arrlen * sizeof (tnode_t *))) == NULL) + return (node_create_seterror(mod, pnode, nhp, ETOPO_NOMEM)); + + nhp->th_range.tr_min = min; + nhp->th_range.tr_max = max; + nhp->th_enum = mod; + topo_mod_hold(mod); + + /* + * Add these nodes to parent child list + */ + topo_list_append(&pnode->tn_children, nhp); + topo_node_unlock(pnode); + + topo_dprintf(TOPO_DBG_MOD, "created node range %s[%d-%d]\n", name, + min, max); + + return (0); +} + +void +topo_node_range_destroy(tnode_t *pnode, const char *name) +{ + int i; + topo_nodehash_t *nhp; + topo_mod_t *mod; + + topo_node_lock(pnode); + for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL; + nhp = topo_list_next(nhp)) { + if (strcmp(nhp->th_name, name) == 0) { + break; + } + } + + if (nhp == NULL) { + topo_node_unlock(pnode); + return; + } + + topo_list_delete(&pnode->tn_children, nhp); + topo_node_unlock(pnode); + + /* + * Should be an empty node range + */ + for (i = 0; i < nhp->th_arrlen; i++) { + topo_node_unbind(nhp->th_nodearr[i]); + } + + mod = nhp->th_enum; + if (nhp->th_name != NULL) + topo_mod_strfree(mod, nhp->th_name); + if (nhp->th_nodearr != NULL) { + topo_mod_free(mod, nhp->th_nodearr, + nhp->th_arrlen * sizeof (tnode_t *)); + } + topo_mod_free(mod, nhp, sizeof (topo_nodehash_t)); + topo_mod_rele(mod); + +} + +tnode_t * +topo_node_lookup(tnode_t *pnode, const char *name, topo_instance_t inst) +{ + int h; + tnode_t *node; + topo_nodehash_t *nhp; + + topo_node_lock(pnode); + for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL; + nhp = topo_list_next(nhp)) { + if (strcmp(nhp->th_name, name) == 0) { + + if (inst > nhp->th_range.tr_max || + inst < nhp->th_range.tr_min) { + topo_node_unlock(pnode); + return (NULL); + } + + h = topo_node_hash(nhp, inst); + node = nhp->th_nodearr[h]; + topo_node_unlock(pnode); + return (node); + } + } + topo_node_unlock(pnode); + + return (NULL); +} + +int +topo_node_hash(topo_nodehash_t *nhp, topo_instance_t inst) +{ + return (nhp->th_range.tr_max == 0 ? + nhp->th_range.tr_max : inst % (nhp->th_range.tr_max + 1)); +} + +static tnode_t * +node_bind_seterror(topo_mod_t *mod, tnode_t *pnode, tnode_t *node, int err) +{ + topo_node_unlock(pnode); + + (void) topo_mod_seterrno(mod, err); + + if (node == NULL) + return (NULL); + + topo_dprintf(TOPO_DBG_ERR, "unable to bind %s=%d: " + "%s\n", (node->tn_name != NULL ? node->tn_name : "unknown"), + node->tn_instance, topo_strerror(err)); + + topo_node_lock(node); /* expected to be locked */ + topo_node_destroy(node); + + return (NULL); +} + +tnode_t * +topo_node_bind(topo_mod_t *mod, tnode_t *pnode, const char *name, + topo_instance_t inst, nvlist_t *fmri, void *priv) +{ + int h, err; + tnode_t *node; + topo_nodehash_t *nhp; + + topo_node_lock(pnode); + for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL; + nhp = topo_list_next(nhp)) { + if (strcmp(nhp->th_name, name) == 0) { + + if (inst > nhp->th_range.tr_max || + inst < nhp->th_range.tr_min) + return (node_bind_seterror(mod, pnode, NULL, + ETOPO_NODE_INVAL)); + + h = topo_node_hash(nhp, inst); + if (nhp->th_nodearr[h] != NULL) + return (node_bind_seterror(mod, pnode, NULL, + ETOPO_NODE_BOUND)); + else + break; + + } + } + + if (nhp == NULL) + return (node_bind_seterror(mod, pnode, NULL, ETOPO_NODE_NOENT)); + + if ((node = topo_mod_zalloc(mod, sizeof (tnode_t))) == NULL) + return (node_bind_seterror(mod, pnode, NULL, ETOPO_NOMEM)); + + (void) pthread_mutex_init(&node->tn_lock, NULL); + + node->tn_enum = mod; + node->tn_hdl = mod->tm_hdl; + node->tn_parent = pnode; + node->tn_name = nhp->th_name; + node->tn_instance = inst; + node->tn_phash = nhp; + node->tn_refs = 0; + + /* Ref count module that bound this node */ + topo_mod_hold(mod); + + if (fmri == NULL) + return (node_bind_seterror(mod, pnode, node, ETOPO_NODE_INVAL)); + + if (topo_pgroup_create(node, TOPO_PGROUP_PROTOCOL, + TOPO_STABILITY_PRIVATE, &err) < 0) + return (node_bind_seterror(mod, pnode, node, err)); + + if (topo_prop_set_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_RESOURCE, + TOPO_PROP_SET_ONCE, fmri, &err) < 0) + return (node_bind_seterror(mod, pnode, node, err)); + + topo_dprintf(TOPO_DBG_MOD, "node bound %s=%d\n", node->tn_name, + node->tn_instance); + + node->tn_state |= TOPO_NODE_BOUND; + node->tn_priv = priv; + + topo_node_hold(node); + nhp->th_nodearr[h] = node; + ++pnode->tn_refs; + topo_node_unlock(pnode); + + if (topo_pgroup_create(node, TOPO_PGROUP_SYSTEM, + TOPO_STABILITY_PRIVATE, &err) == 0) { + (void) topo_prop_inherit(node, TOPO_PGROUP_SYSTEM, + TOPO_PROP_PLATFORM, &err); + (void) topo_prop_inherit(node, TOPO_PGROUP_SYSTEM, + TOPO_PROP_ISA, &err); + (void) topo_prop_inherit(node, TOPO_PGROUP_SYSTEM, + TOPO_PROP_MACHINE, &err); + } + + return (node); +} + +void +topo_node_unbind(tnode_t *node) +{ + if (node == NULL) + return; + + topo_node_lock(node); + if (!(node->tn_state & TOPO_NODE_BOUND)) { + topo_node_unlock(node); + return; + } + + node->tn_state &= ~TOPO_NODE_BOUND; + topo_node_unlock(node); + + topo_node_rele(node); +} + +/*ARGSUSED*/ +int +topo_node_present(tnode_t *node) +{ + return (0); +} + +/*ARGSUSED*/ +int +topo_node_contains(tnode_t *er, tnode_t *ee) +{ + return (0); +} + +/*ARGSUSED*/ +int +topo_node_unusable(tnode_t *node) +{ + return (0); +} diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_nvl.c b/usr/src/lib/fm/topo/libtopo/common/topo_nvl.c new file mode 100644 index 0000000000..f42d99ce15 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_nvl.c @@ -0,0 +1,70 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <umem.h> +#include <topo_alloc.h> +#include <topo_module.h> + +/*ARGSUSED*/ +void * +topo_nv_alloc(nv_alloc_t *nva, size_t size) +{ + return (topo_zalloc(size, UMEM_DEFAULT)); +} + +/*ARGSUSED*/ +void +topo_nv_free(nv_alloc_t *nva, void *data, size_t size) +{ + topo_free(data, size); +} + +int +topo_mod_nvalloc(topo_mod_t *mod, nvlist_t **nvlp, uint_t nvflag) +{ + return (nvlist_xalloc(nvlp, nvflag, &mod->tm_alloc->ta_nva)); +} + +int +topo_mod_nvdup(topo_mod_t *mod, nvlist_t *nvl, nvlist_t **nvlp) +{ + return (nvlist_xdup(nvl, nvlp, &mod->tm_alloc->ta_nva)); +} + +int +topo_hdl_nvalloc(topo_hdl_t *thp, nvlist_t **nvlp, uint_t nvflag) +{ + + return (nvlist_xalloc(nvlp, nvflag, &thp->th_alloc->ta_nva)); +} + +int +topo_hdl_nvdup(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **nvlp) +{ + return (nvlist_xdup(nvl, nvlp, &thp->th_alloc->ta_nva)); +} diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_parse.c b/usr/src/lib/fm/topo/libtopo/common/topo_parse.c new file mode 100644 index 0000000000..847c9bad13 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_parse.c @@ -0,0 +1,229 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <libxml/parser.h> +#include <fm/libtopo.h> +#include <topo_alloc.h> +#include <topo_error.h> +#include <topo_parse.h> + +extern const char * const Name; +const char * const Min = "min"; +const char * const Max = "max"; + + +tf_info_t * +tf_info_new(topo_mod_t *mp, const char *fn, xmlDocPtr doc, xmlChar *scheme) +{ + tf_info_t *r; + + if ((r = topo_mod_zalloc(mp, sizeof (tf_info_t))) == NULL) + return (NULL); + r->tf_flags = TF_LIVE; + if ((r->tf_fn = topo_mod_strdup(mp, fn)) == NULL) { + tf_info_free(mp, r); + return (NULL); + } + if ((r->tf_scheme = topo_mod_strdup(mp, (char *)scheme)) == NULL) { + tf_info_free(mp, r); + return (NULL); + } + r->tf_xdoc = doc; + return (r); +} + +void +tf_info_free(topo_mod_t *mp, tf_info_t *p) +{ + if (p->tf_xdoc != NULL) + xmlFreeDoc(p->tf_xdoc); + if (p->tf_fn != NULL) + topo_mod_strfree(mp, p->tf_fn); + if (p->tf_scheme != NULL) + topo_mod_strfree(mp, p->tf_scheme); + tf_rdata_free(mp, p->tf_rd); + topo_mod_free(mp, p, sizeof (tf_info_t)); +} + +tf_rdata_t * +tf_rdata_new(topo_mod_t *mp, tf_info_t *xinfo, xmlNodePtr n, tnode_t *troot) +{ + tf_rdata_t *r; + uint64_t ui; + xmlChar *name = NULL; + + topo_mod_dprintf(mp, "new rdata\n"); + if ((r = topo_mod_zalloc(mp, sizeof (tf_rdata_t))) == NULL) { + (void) topo_mod_seterrno(mp, ETOPO_NOMEM); + return (NULL); + } + r->rd_pn = troot; + if ((name = xmlGetProp(n, (xmlChar *)Name)) == NULL) { + (void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR); + goto rdata_nogood; + } + if ((r->rd_name = topo_mod_strdup(mp, (char *)name)) == NULL) { + (void) topo_mod_seterrno(mp, ETOPO_NOMEM); + goto rdata_nogood; + } + if (xmlattr_to_int(mp, n, Min, &ui) < 0) + goto rdata_nogood; + r->rd_min = (int)ui; + if (xmlattr_to_int(mp, n, Max, &ui) < 0) + goto rdata_nogood; + r->rd_max = (int)ui; + if (r->rd_min < 0 || r->rd_max < 0 || r->rd_max < r->rd_min) { + (void) topo_mod_seterrno(mp, ETOPO_PRSR_BADRNG); + goto rdata_nogood; + } + r->rd_finfo = xinfo; + r->rd_mod = mp; + + if (topo_xml_range_process(mp, n, r) < 0) + goto rdata_nogood; + + xmlFree(name); + return (r); + +rdata_nogood: + if (name != NULL) + xmlFree(name); + tf_rdata_free(mp, r); + return (NULL); +} + +void +tf_rdata_free(topo_mod_t *mp, tf_rdata_t *p) +{ + if (p == NULL) + return; + tf_rdata_free(mp, p->rd_next); + if (p->rd_name != NULL) + topo_mod_strfree(mp, p->rd_name); + tf_edata_free(mp, p->rd_einfo); + tf_idata_free(mp, p->rd_instances); + tf_pad_free(mp, p->rd_pad); + topo_mod_free(mp, p, sizeof (tf_rdata_t)); +} + +tf_idata_t * +tf_idata_new(topo_mod_t *mp, topo_instance_t i, tnode_t *tn) +{ + tf_idata_t *r; + + topo_mod_dprintf(mp, "new idata %d\n", i); + if ((r = topo_mod_zalloc(mp, sizeof (tf_idata_t))) == NULL) + return (NULL); + r->ti_tn = tn; + r->ti_i = i; + return (r); +} + +void +tf_idata_free(topo_mod_t *mp, tf_idata_t *p) +{ + if (p == NULL) + return; + tf_idata_free(mp, p->ti_next); + tf_pad_free(mp, p->ti_pad); + topo_mod_free(mp, p, sizeof (tf_idata_t)); +} + +int +tf_idata_insert(topo_mod_t *mp, tf_idata_t **head, tf_idata_t *ni) +{ + tf_idata_t *l, *p; + + topo_mod_dprintf(mp, "idata insert %d\n", ni->ti_i); + p = NULL; + for (l = *head; l != NULL; l = l->ti_next) { + if (ni->ti_i < l->ti_i) + break; + p = l; + } + ni->ti_next = l; + if (p == NULL) + *head = ni; + else + p->ti_next = ni; + return (0); +} + +tf_idata_t * +tf_idata_lookup(topo_mod_t *mp, tf_idata_t *head, topo_instance_t i) +{ + tf_idata_t *f; + topo_mod_dprintf(mp, "idata lookup %d\n", i); + for (f = head; f != NULL; f = f->ti_next) + if (i == f->ti_i) + break; + return (f); +} + +tf_pad_t * +tf_pad_new(topo_mod_t *mp, int pcnt, int dcnt) +{ + tf_pad_t *r; + + topo_mod_dprintf(mp, "new pad p=%d, d=%d\n", pcnt, dcnt); + if ((r = topo_mod_zalloc(mp, sizeof (tf_pad_t))) == NULL) + return (NULL); + r->tpad_pgcnt = pcnt; + r->tpad_dcnt = dcnt; + return (r); +} + +void +tf_pad_free(topo_mod_t *mp, tf_pad_t *p) +{ + int n; + if (p == NULL) + return; + if (p->tpad_pgs != NULL) { + for (n = 0; n < p->tpad_pgcnt; n++) + if (p->tpad_pgs[n] != NULL) + nvlist_free(p->tpad_pgs[n]); + topo_mod_free(mp, + p->tpad_pgs, p->tpad_pgcnt * sizeof (nvlist_t *)); + } + tf_rdata_free(mp, p->tpad_child); + tf_rdata_free(mp, p->tpad_sibs); + topo_mod_free(mp, p, sizeof (tf_pad_t)); +} + +void +tf_edata_free(topo_mod_t *mp, tf_edata_t *p) +{ + if (p == NULL) + return; + if (p->te_name != NULL) + xmlFree(p->te_name); + if (p->te_path != NULL) + xmlFree(p->te_path); + topo_mod_free(mp, p, sizeof (tf_edata_t)); +} diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_parse.h b/usr/src/lib/fm/topo/libtopo/common/topo_parse.h new file mode 100644 index 0000000000..b3516b0e06 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_parse.h @@ -0,0 +1,159 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _TOPO_PARSE_H +#define _TOPO_PARSE_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <libxml/parser.h> +#include <libnvpair.h> +#include <fm/libtopo.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define TOPO_DTD_PATH "topology.dtd.1" +#define TOPO_FILE "topology.xml" +#define TOPO_PLATFORM_PATH "%susr/platform/%s/lib/fm/topo/%s" +#define TOPO_COMMON_PATH "%susr/lib/fm/topo/%s" + +/* + * Plenty of room to hold string representation of an instance + * number + */ +#define MAXINSTSTRLEN 64 + +/* + * Forward declaration + */ +struct tf_rdata; +struct tf_info; + +/* + * This structure summarizes an enumerator as described by an xml + * topology file. + */ +typedef struct tf_edata { + char *te_name; /* name of the enumerator, if any */ + char *te_path; /* path to the enumerator, if any */ + topo_stability_t te_stab; /* stability of the enumerator, if any */ + int te_vers; /* version of the enumerator, if any */ + int te_amcnt; /* number of apply-methods */ + nvlist_t **te_ams; /* apply-methods */ +} tf_edata_t; + +/* properties and dependents off of an instance or a range */ +typedef struct tf_pad { + int tpad_pgcnt; /* number of property-groups of node */ + int tpad_dcnt; /* number of dependents groups of node */ + nvlist_t **tpad_pgs; /* property-groups as nvlists */ + struct tf_rdata *tpad_child; /* children ranges */ + struct tf_rdata *tpad_sibs; /* sibling ranges */ +} tf_pad_t; + +typedef struct tf_idata { + struct tf_idata *ti_next; /* next instance */ + topo_instance_t ti_i; /* hard instance */ + tnode_t *ti_tn; /* topology node representing the instance */ + tf_pad_t *ti_pad; /* properties and dependents */ +} tf_idata_t; + +/* + * This structure summarizes a topology node range as described by a + * topology file. + */ +typedef struct tf_rdata { + struct tf_rdata *rd_next; /* for linking a group of tf_rdatas */ + int rd_cnt; /* number of tf_rdatas in the list */ + struct tf_info *rd_finfo; /* pointer back to .xml file details */ + topo_mod_t *rd_mod; /* pointer to loaded enumerator */ + tnode_t *rd_pn; /* parent topology node */ + char *rd_name; /* node name */ + int rd_min; /* minimum instance number of node */ + int rd_max; /* maximum instance number of node */ + tf_edata_t *rd_einfo; /* enumerator information, if any */ + struct tf_idata *rd_instances; /* hard instances */ + tf_pad_t *rd_pad; /* properties and dependents */ +} tf_rdata_t; + +/* + * While we're parsing we need a handy way to pass around the data + * related to what we're currently parsing, what topology nodes may be + * affected, etc. + */ +typedef struct tf_info { + char *tf_fn; /* name of file read */ + char *tf_scheme; /* scheme of topology in file */ + /* UUID ? */ + uint_t tf_flags; /* behavior modifiers (see values below) */ + xmlDocPtr tf_xdoc; /* the parsed xml doc */ + tf_rdata_t *tf_rd; /* data for forming topology nodes */ +} tf_info_t; + +#define TF_LIVE 0x1 /* Parsing should create topology nodes */ +#define TF_BIN 0x2 /* Parsing should create intermediate binary */ + +/* + * We store properties using nvlists as an intermediate form. The + * following defines are names for fields in this intermediate form. + */ +#define INV_IMMUTE "prop-immutable" +#define INV_PGRP_ALLPROPS "propgrp-props" +#define INV_PGRP_NAME "propgrp-name" +#define INV_PGRP_NPROP "propgrp-numprops" +#define INV_PGRP_STAB "propgrp-name-stability" +#define INV_PNAME "prop-name" +#define INV_PVAL "prop-val" +#define INV_PVALTYPE "prop-valtype" + +extern tf_idata_t *tf_idata_lookup(topo_mod_t *, tf_idata_t *, topo_instance_t); +extern tf_rdata_t *tf_rdata_new(topo_mod_t *, + tf_info_t *, xmlNodePtr, tnode_t *); +extern tf_idata_t *tf_idata_new(topo_mod_t *, topo_instance_t, tnode_t *); +extern tf_info_t *topo_xml_read(topo_mod_t *, const char *, const char *); +extern tf_info_t *tf_info_new(topo_mod_t *, + const char *, xmlDocPtr, xmlChar *); +extern tf_pad_t *tf_pad_new(topo_mod_t *, int, int); +extern void topo_xml_cleanup(topo_mod_t *, tf_info_t *); +extern void tf_rdata_free(topo_mod_t *, tf_rdata_t *); +extern void tf_edata_free(topo_mod_t *, tf_edata_t *); +extern void tf_idata_free(topo_mod_t *, tf_idata_t *); +extern void tf_info_free(topo_mod_t *, tf_info_t *); +extern void tf_pad_free(topo_mod_t *, tf_pad_t *); +extern int topo_xml_range_process(topo_mod_t *, xmlNodePtr, tf_rdata_t *); +extern int topo_xml_enum(topo_mod_t *, tf_info_t *, tnode_t *); +extern int tf_idata_insert(topo_mod_t *, tf_idata_t **, tf_idata_t *); +extern int xmlattr_to_int(topo_mod_t *, xmlNodePtr, const char *, uint64_t *); +extern int xmlattr_to_stab(topo_mod_t *, xmlNodePtr, topo_stability_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _TOPO_PARSE_H */ diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_prop.c b/usr/src/lib/fm/topo/libtopo/common/topo_prop.c new file mode 100644 index 0000000000..d4c6259656 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_prop.c @@ -0,0 +1,676 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <strings.h> +#include <assert.h> +#include <fm/libtopo.h> +#include <topo_prop.h> +#include <topo_string.h> +#include <topo_alloc.h> +#include <topo_error.h> + +static topo_pgroup_t * +pgroup_get(tnode_t *node, const char *pgname) +{ + topo_pgroup_t *pg; + /* + * Check for an existing pgroup + */ + for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; + pg = topo_list_next(pg)) { + if (strcmp(pg->tpg_name, pgname) == 0) { + return (pg); + } + } + + return (NULL); +} + +static topo_propval_t * +propval_get(topo_pgroup_t *pg, const char *pname) +{ + topo_proplist_t *pvl; + + for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL; + pvl = topo_list_next(pvl)) { + if (strcmp(pvl->tp_pval->tp_name, pname) == 0) + return (pvl->tp_pval); + } + + return (NULL); +} + +static topo_propval_t * +topo_prop_get(tnode_t *node, const char *pgname, const char *pname, int *err) +{ + topo_pgroup_t *pg = NULL; + topo_propval_t *pv = NULL; + + if ((pg = pgroup_get(node, pgname)) == NULL) { + *err = ETOPO_PROP_NOENT; + return (NULL); + } + + if ((pv = propval_get(pg, pname)) == NULL) { + *err = ETOPO_PROP_NOENT; + return (NULL); + } + + return (pv); +} + +static int +prop_val_add(nvlist_t *nvl, topo_propval_t *pv) +{ + switch (pv->tp_type) { + case TOPO_TYPE_INT32: + return (nvlist_add_int32(nvl, TOPO_PROP_VAL_VAL, + pv->tp_u.tp_int32)); + case TOPO_TYPE_UINT32: + return (nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, + pv->tp_u.tp_uint32)); + case TOPO_TYPE_INT64: + return (nvlist_add_int64(nvl, TOPO_PROP_VAL_VAL, + pv->tp_u.tp_int64)); + case TOPO_TYPE_UINT64: + return (nvlist_add_uint64(nvl, TOPO_PROP_VAL_VAL, + pv->tp_u.tp_uint64)); + case TOPO_TYPE_STRING: + return (nvlist_add_string(nvl, TOPO_PROP_VAL_VAL, + pv->tp_u.tp_string)); + case TOPO_TYPE_FMRI: + return (nvlist_add_nvlist(nvl, TOPO_PROP_VAL_VAL, + pv->tp_u.tp_fmri)); + default: + return (ETOPO_PROP_TYPE); + } +} + +nvlist_t * +get_all_seterror(topo_hdl_t *thp, nvlist_t *nvl, int err) +{ + if (nvl != NULL) + nvlist_free(nvl); + + (void) topo_hdl_seterrno(thp, err); + + return (NULL); +} + +nvlist_t * +topo_prop_get_all(topo_hdl_t *thp, tnode_t *node) +{ + int err; + nvlist_t *nvl, *pgnvl, *pvnvl; + topo_pgroup_t *pg; + topo_propval_t *pv; + topo_proplist_t *pvl; + + if (topo_hdl_nvalloc(thp, &nvl, 0) != 0) { + return (get_all_seterror(thp, NULL, ETOPO_NOMEM)); + } + + for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; + pg = topo_list_next(pg)) { + err = 0; + if (topo_hdl_nvalloc(thp, &pgnvl, 0) != 0) + return (get_all_seterror(thp, nvl, ETOPO_NOMEM)); + + if ((err = nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NAME, + pg->tpg_name)) != 0) + return (get_all_seterror(thp, nvl, err)); + + for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL; + pvl = topo_list_next(pvl)) { + + pv = pvl->tp_pval; + if (topo_hdl_nvalloc(thp, &pvnvl, 0) + != 0) { + nvlist_free(pgnvl); + return (get_all_seterror(thp, nvl, + ETOPO_NOMEM)); + } + if ((err = nvlist_add_string(pvnvl, TOPO_PROP_VAL_NAME, + pv->tp_name)) != 0) { + nvlist_free(pgnvl); + nvlist_free(pvnvl); + return (get_all_seterror(thp, nvl, err)); + } + if ((err = prop_val_add(pvnvl, pv)) != 0) { + nvlist_free(pgnvl); + nvlist_free(pvnvl); + return (get_all_seterror(thp, nvl, err)); + } + if ((err = nvlist_add_nvlist(pgnvl, TOPO_PROP_VAL, + pvnvl)) != 0) { + nvlist_free(pgnvl); + nvlist_free(pvnvl); + return (get_all_seterror(thp, nvl, err)); + } + + nvlist_free(pvnvl); + } + if ((err = nvlist_add_nvlist(nvl, TOPO_PROP_GROUP, pgnvl)) + != 0) { + nvlist_free(pgnvl); + return (get_all_seterror(thp, nvl, err)); + } + + nvlist_free(pgnvl); + } + + return (nvl); +} + +static int +get_seterror(tnode_t *node, int *errp, int err) +{ + topo_node_unlock(node); + *errp = err; + return (-1); +} + +int +topo_prop_get_int32(tnode_t *node, const char *pgname, const char *pname, + int32_t *val, int *err) +{ + topo_propval_t *pv; + + topo_node_lock(node); + if ((pv = topo_prop_get(node, pgname, pname, err)) + == NULL) + return (get_seterror(node, err, *err)); + + if (pv->tp_type != TOPO_TYPE_INT32) + return (get_seterror(node, err, ETOPO_PROP_TYPE)); + + *val = pv->tp_u.tp_int32; + + topo_node_unlock(node); + + return (0); +} + +int +topo_prop_get_uint32(tnode_t *node, const char *pgname, const char *pname, + uint32_t *val, int *err) +{ + topo_propval_t *pv; + + topo_node_lock(node); + if ((pv = topo_prop_get(node, pgname, pname, err)) + == NULL) + return (get_seterror(node, err, *err)); + + if (pv->tp_type != TOPO_TYPE_UINT32) + return (get_seterror(node, err, ETOPO_PROP_TYPE)); + + *val = pv->tp_u.tp_uint32; + + topo_node_unlock(node); + + return (0); +} + +int +topo_prop_get_int64(tnode_t *node, const char *pgname, const char *pname, + int64_t *val, int *err) +{ + topo_propval_t *pv; + + topo_node_lock(node); + if ((pv = topo_prop_get(node, pgname, pname, err)) + == NULL) + return (get_seterror(node, err, *err)); + + if (pv->tp_type != TOPO_TYPE_INT64) + return (get_seterror(node, err, ETOPO_PROP_TYPE)); + + *val = pv->tp_u.tp_int64; + + topo_node_unlock(node); + + return (0); +} + +int +topo_prop_get_uint64(tnode_t *node, const char *pgname, const char *pname, + uint64_t *val, int *err) +{ + topo_propval_t *pv; + + topo_node_lock(node); + if ((pv = topo_prop_get(node, pgname, pname, err)) + == NULL) + return (get_seterror(node, err, *err)); + + if (pv->tp_type != TOPO_TYPE_UINT64) + return (get_seterror(node, err, ETOPO_PROP_TYPE)); + + *val = pv->tp_u.tp_int64; + + topo_node_unlock(node); + + return (0); +} + +int +topo_prop_get_string(tnode_t *node, const char *pgname, const char *pname, + char **val, int *err) +{ + topo_propval_t *pv; + + topo_node_lock(node); + if ((pv = topo_prop_get(node, pgname, pname, err)) == NULL) + return (get_seterror(node, err, *err)); + + if (pv->tp_type != TOPO_TYPE_STRING) + return (get_seterror(node, err, ETOPO_PROP_TYPE)); + + if ((*val = topo_hdl_strdup(node->tn_hdl, pv->tp_u.tp_string)) + == NULL) + return (get_seterror(node, err, ETOPO_NOMEM)); + + topo_node_unlock(node); + + return (0); +} + +int +topo_prop_get_fmri(tnode_t *node, const char *pgname, const char *pname, + nvlist_t **val, int *err) +{ + topo_propval_t *pv; + + topo_node_lock(node); + if ((pv = topo_prop_get(node, pgname, pname, err)) == NULL) + return (get_seterror(node, err, *err)); + + if (pv->tp_type != TOPO_TYPE_FMRI) + return (get_seterror(node, err, ETOPO_PROP_TYPE)); + + if (topo_hdl_nvdup(node->tn_hdl, pv->tp_u.tp_fmri, val) < 0) + return (get_seterror(node, err, ETOPO_NOMEM)); + + topo_node_unlock(node); + + return (0); +} + +static void +topo_propval_strfree(topo_propval_t *pv) +{ + topo_hdl_strfree(pv->tp_hdl, pv->tp_u.tp_string); +} + +static void +topo_propval_nvlfree(topo_propval_t *pv) +{ + nvlist_free(pv->tp_u.tp_fmri); +} + +static int +set_seterror(tnode_t *node, int *errp, int err) +{ + topo_node_unlock(node); + + *errp = err; + + return (-1); +} + +static int +topo_prop_set(tnode_t *node, const char *pgname, const char *pname, + topo_type_t type, int flag, void *val, int *err) +{ + topo_hdl_t *thp = node->tn_hdl; + topo_pgroup_t *pg; + topo_propval_t *pv; + topo_proplist_t *pvl; + + topo_node_lock(node); + if ((pg = pgroup_get(node, pgname)) == NULL) + return (set_seterror(node, err, ETOPO_PROP_NOENT)); + + if ((pv = propval_get(pg, pname)) != NULL) { + if (pv->tp_type != type) + return (set_seterror(node, err, ETOPO_PROP_TYPE)); + else if (pv->tp_flag == TOPO_PROP_SET_ONCE) + return (set_seterror(node, err, ETOPO_PROP_DEFD)); + } else { + /* + * Property values may be a shared resources among + * different nodes. We will allocate resources + * on a per-handle basis. + */ + if ((pvl = topo_hdl_zalloc(thp, sizeof (topo_proplist_t))) + == NULL) + return (set_seterror(node, err, ETOPO_NOMEM)); + + if ((pv = topo_hdl_zalloc(thp, sizeof (topo_propval_t))) + == NULL) { + topo_hdl_free(thp, pvl, sizeof (topo_proplist_t)); + return (set_seterror(node, err, ETOPO_NOMEM)); + } + if ((pv->tp_name = topo_hdl_strdup(thp, pname)) + == NULL) { + topo_hdl_free(thp, pvl, sizeof (topo_proplist_t)); + topo_hdl_free(thp, pv, sizeof (topo_propval_t)); + return (set_seterror(node, err, ETOPO_NOMEM)); + } + pv->tp_flag = flag; + pv->tp_type = type; + pv->tp_hdl = thp; + topo_prop_hold(pv); + pvl->tp_pval = pv; + topo_list_append(&pg->tpg_pvals, pvl); + + + } + + switch (type) { + case TOPO_TYPE_INT32: + pv->tp_u.tp_int32 = *(int32_t *)val; + break; + case TOPO_TYPE_UINT32: + pv->tp_u.tp_uint32 = *(uint32_t *)val; + break; + case TOPO_TYPE_INT64: + pv->tp_u.tp_int64 = *(int64_t *)val; + break; + case TOPO_TYPE_UINT64: + pv->tp_u.tp_uint64 = *(uint64_t *)val; + break; + case TOPO_TYPE_STRING: + pv->tp_u.tp_string = topo_hdl_strdup(thp, (char *)val); + if (pv->tp_u.tp_string == NULL) + return (set_seterror(node, err, ETOPO_NOMEM)); + pv->tp_free = topo_propval_strfree; + break; + case TOPO_TYPE_FMRI: + if (topo_hdl_nvdup(thp, + (nvlist_t *)val, &pv->tp_u.tp_fmri) < 0) + return (set_seterror(node, err, ETOPO_NOMEM)); + pv->tp_free = topo_propval_nvlfree; + break; + default: + return (set_seterror(node, err, ETOPO_PROP_TYPE)); + } + + topo_node_unlock(node); + + return (0); +} + +int +topo_prop_set_int32(tnode_t *node, const char *pgname, const char *pname, + int flag, int32_t val, int *err) +{ + return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT32, flag, + &val, err)); +} + +int +topo_prop_set_uint32(tnode_t *node, const char *pgname, const char *pname, + int flag, uint32_t val, int *err) +{ + return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT32, flag, + &val, err)); +} + +int +topo_prop_set_int64(tnode_t *node, const char *pgname, const char *pname, + int flag, int64_t val, int *err) +{ + return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT64, flag, + &val, err)); +} + +int +topo_prop_set_uint64(tnode_t *node, const char *pgname, const char *pname, + int flag, uint64_t val, int *err) +{ + return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT64, flag, + &val, err)); +} + +int +topo_prop_set_string(tnode_t *node, const char *pgname, const char *pname, + int flag, const char *val, int *err) +{ + return (topo_prop_set(node, pgname, pname, TOPO_TYPE_STRING, flag, + (void *)val, err)); +} + +int +topo_prop_set_fmri(tnode_t *node, const char *pgname, const char *pname, + int flag, const nvlist_t *fmri, int *err) +{ + return (topo_prop_set(node, pgname, pname, TOPO_TYPE_FMRI, flag, + (void *)fmri, err)); +} + +static int +inherit_seterror(tnode_t *node, int *errp, int err) +{ + topo_node_unlock(node); + topo_node_unlock(node->tn_parent); + + *errp = err; + + return (-1); +} + +int +topo_prop_inherit(tnode_t *node, const char *pgname, const char *name, int *err) +{ + topo_hdl_t *thp = node->tn_hdl; + tnode_t *pnode = node->tn_parent; + topo_pgroup_t *pg; + topo_propval_t *pv; + topo_proplist_t *pvl; + + topo_node_lock(pnode); + topo_node_lock(node); + /* + * Check for an existing property group and prop val + */ + if ((pg = pgroup_get(pnode, pgname)) == NULL) + return (inherit_seterror(node, err, ETOPO_PROP_NOENT)); + + if ((pv = propval_get(pg, name)) == NULL) + return (inherit_seterror(node, err, ETOPO_PROP_NOENT)); + + /* + * Can this propval be inherited? + */ + if (pv->tp_flag != TOPO_PROP_SET_ONCE) + return (inherit_seterror(node, err, ETOPO_PROP_NOINHERIT)); + + /* + * Property group should already exist: bump the ref count for this + * propval and add it to the node's property group + */ + if ((pg = pgroup_get(node, pgname)) == NULL) + return (inherit_seterror(node, err, ETOPO_PROP_NOENT)); + + if ((pvl = topo_hdl_zalloc(thp, sizeof (topo_proplist_t))) + == NULL) + return (inherit_seterror(node, err, ETOPO_NOMEM)); + + topo_prop_hold(pv); + pvl->tp_pval = pv; + topo_list_append(&pg->tpg_pvals, pvl); + + topo_node_unlock(node); + topo_node_unlock(pnode); + + return (0); +} + +int +topo_prop_stability(tnode_t *node, const char *pgname, topo_stability_t *stab) +{ + topo_pgroup_t *pg; + + for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; + pg = topo_list_next(pg)) { + if (strcmp(pgname, pg->tpg_name) == 0) { + *stab = pg->tpg_stability; + return (0); + } + } + + return (-1); +} + +int +topo_pgroup_create(tnode_t *node, const char *pname, topo_stability_t stab, + int *err) +{ + topo_pgroup_t *pg; + + *err = 0; + + /* + * Check for an existing pgroup + */ + for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; + pg = topo_list_next(pg)) { + if (strcmp(pg->tpg_name, pname) == 0) { + *err = ETOPO_PROP_DEFD; + return (-1); + } + } + + if ((pg = topo_hdl_zalloc(node->tn_hdl, + sizeof (topo_pgroup_t))) == NULL) { + *err = ETOPO_NOMEM; + return (-1); + } + + if ((pg->tpg_name = topo_hdl_strdup(node->tn_hdl, pname)) == NULL) { + topo_hdl_free(node->tn_hdl, pg, sizeof (topo_pgroup_t)); + *err = ETOPO_NOMEM; + return (-1); + } + + pg->tpg_stability = stab; + + topo_list_append(&node->tn_pgroups, pg); + + return (0); +} + +void +topo_pgroup_destroy(tnode_t *node, const char *pname) +{ + topo_hdl_t *thp = node->tn_hdl; + topo_pgroup_t *pg; + topo_proplist_t *pvl; + + topo_node_lock(node); + for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; + pg = topo_list_next(pg)) { + if (strcmp(pg->tpg_name, pname) == 0) { + break; + } + } + + if (pg == NULL) { + topo_node_unlock(node); + return; + } + + while ((pvl = topo_list_next(&pg->tpg_list)) != NULL) { + topo_list_delete(&pg->tpg_pvals, pvl); + topo_prop_rele(pvl->tp_pval); + topo_hdl_free(thp, pvl, sizeof (topo_proplist_t)); + } + + topo_list_delete(&node->tn_pgroups, pg); + + if (pg->tpg_name != NULL) + topo_hdl_strfree(thp, pg->tpg_name); + topo_hdl_free(thp, pg, sizeof (topo_pgroup_t)); + + topo_node_unlock(node); +} + +void +topo_pgroup_destroy_all(tnode_t *node) +{ + topo_hdl_t *thp = node->tn_hdl; + topo_pgroup_t *pg; + topo_proplist_t *pvl; + + topo_node_lock(node); + while ((pg = topo_list_next(&node->tn_pgroups)) != NULL) { + while ((pvl = topo_list_next(&pg->tpg_pvals)) != NULL) { + topo_list_delete(&pg->tpg_pvals, pvl); + topo_prop_rele(pvl->tp_pval); + topo_hdl_free(thp, pvl, sizeof (topo_proplist_t)); + } + + topo_list_delete(&node->tn_pgroups, pg); + + if (pg->tpg_name != NULL) + topo_hdl_strfree(thp, pg->tpg_name); + topo_hdl_free(thp, pg, sizeof (topo_pgroup_t)); + } + topo_node_unlock(node); +} +static void +topo_propval_destroy(topo_propval_t *pv) +{ + topo_hdl_t *thp = pv->tp_hdl; + + if (pv->tp_name != NULL) + topo_hdl_strfree(thp, pv->tp_name); + + if (pv->tp_free != NULL) + pv->tp_free(pv); + + topo_hdl_free(thp, pv, sizeof (topo_propval_t)); +} + +void +topo_prop_hold(topo_propval_t *pv) +{ + pv->tp_refs++; +} + +void +topo_prop_rele(topo_propval_t *pv) +{ + pv->tp_refs--; + + assert(pv->tp_refs >= 0); + + if (pv->tp_refs == 0) + topo_propval_destroy(pv); +} diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_prop.h b/usr/src/lib/fm/topo/libtopo/common/topo_prop.h new file mode 100644 index 0000000000..25dcf33702 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_prop.h @@ -0,0 +1,78 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _TOPO_PROP_H +#define _TOPO_PROP_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <fm/libtopo.h> + +#include <topo_list.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct topo_pgroup { + topo_list_t tpg_list; /* next/prev pointers */ + char *tpg_name; /* Group name */ + topo_stability_t tpg_stability; /* SMI Stability level */ + topo_list_t tpg_pvals; /* Property values */ +} topo_pgroup_t; + +typedef struct topo_propval { + char *tp_name; /* Prop name */ + topo_type_t tp_type; /* Prop type */ + int tp_flag; /* Dynamic property */ + int tp_refs; /* ref count for this prop val */ + topo_hdl_t *tp_hdl; /* handle pointer for allocations */ + void (*tp_free)(struct topo_propval *); /* Prop value destructor */ + union { + int32_t tp_int32; + int32_t tp_uint32; + int64_t tp_int64; + int64_t tp_uint64; + char *tp_string; + nvlist_t *tp_fmri; + } tp_u; +} topo_propval_t; + +typedef struct topo_proplist { + topo_list_t tp_list; /* next/prev pointers */ + topo_propval_t *tp_pval; /* actual value */ +} topo_proplist_t; + +extern int topo_prop_inherit(tnode_t *, const char *, const char *, int *); +extern void topo_prop_hold(topo_propval_t *); +extern void topo_prop_rele(topo_propval_t *); +extern void topo_pgroup_destroy_all(tnode_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _TOPO_PROP_H */ diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_protocol.c b/usr/src/lib/fm/topo/libtopo/common/topo_protocol.c new file mode 100644 index 0000000000..81ae45e3ca --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_protocol.c @@ -0,0 +1,239 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <assert.h> +#include <pthread.h> +#include <strings.h> +#include <sys/fm/protocol.h> + +#include <topo_alloc.h> +#include <topo_error.h> +#include <topo_protocol.h> +#include <topo_subr.h> + +#include <libtopo.h> + +static int +topo_asru_compute(topo_hdl_t *thp, const char *scheme, nvlist_t *rsrc, + nvlist_t **asru) +{ + int err; + tnode_t *rnode; + + if ((rnode = topo_hdl_root(thp, scheme)) == NULL) + return (ETOPO_METHOD_NOTSUP); + + if (topo_method_invoke(rnode, TOPO_METH_ASRU_COMPUTE, + TOPO_METH_ASRU_COMPUTE_VERSION, rsrc, asru, &err) != 0) + return (err); + + return (0); +} + +static int +topo_fru_compute(topo_hdl_t *thp, const char *scheme, nvlist_t *rsrc, + nvlist_t **fru) +{ + int err; + tnode_t *rnode; + + if ((rnode = topo_hdl_root(thp, scheme)) == NULL) + return (ETOPO_METHOD_NOTSUP); + + if (topo_method_invoke(rnode, TOPO_METH_FRU_COMPUTE, + TOPO_METH_FRU_COMPUTE_VERSION, rsrc, fru, &err) != 0) + return (err); + + return (0); +} + +int +topo_node_asru(tnode_t *node, nvlist_t **asru, nvlist_t *priv, int *err) +{ + int rc; + nvlist_t *ap; + char *scheme; + + if (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU, &ap, + err) != 0) + return (-1); + + if (node->tn_fflags & TOPO_ASRU_COMPUTE) { + if ((rc = nvlist_lookup_string(ap, FM_FMRI_SCHEME, &scheme)) + != 0) { + if (rc == ENOENT) + *err = ETOPO_FMRI_MALFORM; + else + *err = ETOPO_FMRI_NVL; + nvlist_free(ap); + return (-1); + } + if ((rc = topo_asru_compute(node->tn_hdl, scheme, priv, asru)) + != 0) { + nvlist_free(ap); + *err = rc; + return (-1); + } + nvlist_free(ap); + return (0); + } else { + *asru = ap; + } + + return (0); +} + +int +topo_node_fru(tnode_t *node, nvlist_t **fru, nvlist_t *priv, int *err) +{ + int rc; + nvlist_t *fp; + char *scheme; + + if (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU, &fp, + err) != 0) + return (-1); + + if (node->tn_fflags & TOPO_FRU_COMPUTE) { + if ((rc = nvlist_lookup_string(fp, FM_FMRI_SCHEME, &scheme)) + != 0) { + if (rc == ENOENT) + *err = ETOPO_FMRI_MALFORM; + else + *err = ETOPO_FMRI_NVL; + + nvlist_free(fp); + return (-1); + } + if ((rc = topo_fru_compute(node->tn_hdl, scheme, priv, fru)) + != 0) { + nvlist_free(fp); + *err = rc; + return (-1); + } + nvlist_free(fp); + return (0); + } else { + *fru = fp; + } + + return (0); +} + +int +topo_node_resource(tnode_t *node, nvlist_t **resource, int *err) +{ + + return (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL, + TOPO_PROP_RESOURCE, resource, err)); +} + +int +topo_node_label(tnode_t *node, char **label, int *err) +{ + + return (topo_prop_get_string(node, TOPO_PGROUP_PROTOCOL, + TOPO_PROP_LABEL, label, err)); +} + +int +topo_node_asru_set(tnode_t *node, nvlist_t *asru, int flag, int *err) +{ + + /* + * Inherit ASRU property from our parent if not specified + */ + if (asru == NULL) { + if (topo_prop_inherit(node, TOPO_PGROUP_PROTOCOL, + TOPO_PROP_ASRU, err) < 0) { + return (-1); + } + } else { + /* + * ASRU must be computed on the fly. asru will + * contain the scheme module to call for the + * computation + */ + if (flag & TOPO_ASRU_COMPUTE) + node->tn_fflags |= TOPO_ASRU_COMPUTE; + + if (topo_prop_set_fmri(node, TOPO_PGROUP_PROTOCOL, + TOPO_PROP_ASRU, TOPO_PROP_SET_ONCE, asru, err) < 0) + return (-1); + } + + return (0); +} + +int +topo_node_fru_set(tnode_t *node, nvlist_t *fru, int flag, int *err) +{ + + /* + * Inherit FRU property from our parent if * not specified + */ + if (fru == NULL) { + if (topo_prop_inherit(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU, + err) < 0) { + return (-1); + } + } else { + /* + * FRU must be computed on the fly + */ + if (flag & TOPO_FRU_COMPUTE) + node->tn_fflags |= TOPO_FRU_COMPUTE; + + if (topo_prop_set_fmri(node, TOPO_PGROUP_PROTOCOL, + TOPO_PROP_FRU, TOPO_PROP_SET_ONCE, fru, err) < 0) + return (-1); + } + + return (0); +} + +int +topo_node_label_set(tnode_t *node, char *label, int *err) +{ + + /* + * Inherit FRU property from our parent if * not specified + */ + if (label == NULL) { + if (topo_prop_inherit(node, TOPO_PGROUP_PROTOCOL, + TOPO_PROP_LABEL, err) < 0) { + return (-1); + } + } else { + if (topo_prop_set_string(node, TOPO_PGROUP_PROTOCOL, + TOPO_PROP_LABEL, TOPO_PROP_SET_ONCE, label, err) < 0) + return (-1); + } + + return (0); +} diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_protocol.h b/usr/src/lib/fm/topo/libtopo/common/topo_protocol.h new file mode 100644 index 0000000000..68d90f9f8c --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_protocol.h @@ -0,0 +1,48 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _TOPO_PROTOCOL_H +#define _TOPO_PROTOCOL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/nvpair.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* Protocol property group and property names */ +#define TOPO_PGROUP_PROTOCOL "protocol" /* Required property group */ +#define TOPO_PROP_RESOURCE "resource" /* resource FMRI */ +#define TOPO_PROP_ASRU "ASRU" /* ASRU FMRI */ +#define TOPO_PROP_FRU "FRU" /* FRU FMRI */ +#define TOPO_PROP_LABEL "label" /* property LABEL */ + +#ifdef __cplusplus +} +#endif + +#endif /* _TOPO_PROTOCOL_H */ diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_rtld.c b/usr/src/lib/fm/topo/libtopo/common/topo_rtld.c new file mode 100644 index 0000000000..8b7b35082c --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_rtld.c @@ -0,0 +1,112 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in comodliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <dlfcn.h> +#include <link.h> +#include <pthread.h> +#include <assert.h> + +#include <fm/topo_mod.h> + +#include <topo_error.h> +#include <topo_alloc.h> +#include <topo_subr.h> + +typedef struct topo_rtld { + void *rtld_dlp; /* libdl(3DL) handle for shared library */ + int (*rtld_init)(topo_mod_t *); /* shared library's _topo_init() */ + void (*rtld_fini)(topo_mod_t *); /* shared library's _topo_fini() */ +} topo_rtld_t; + +static int +rtld_fini(topo_mod_t *mod) +{ + topo_rtld_t *rp = mod->tm_data; + + assert(mod != NULL); + + if (mod->tm_flags & TOPO_MOD_REG) { + rp->rtld_fini(mod); + if (mod->tm_flags & TOPO_MOD_REG) { + topo_mod_unregister(mod); + } + } + + if (getenv("TOPONODLCLOSE") == NULL) + (void) dlclose(rp->rtld_dlp); + topo_mod_free(mod, rp, sizeof (topo_rtld_t)); + + return (0); +} + +static int +rtld_init(topo_mod_t *mod) +{ + int err; + topo_rtld_t *rp; + void *dlp; + + if ((dlp = dlopen(mod->tm_path, RTLD_LOCAL | RTLD_NOW)) == NULL) { + topo_dprintf(TOPO_DBG_ERR, + "dlopen() failed: %s\n", dlerror()); + return (topo_mod_seterrno(mod, ETOPO_RTLD_OPEN)); + } + + if ((rp = mod->tm_data = topo_mod_alloc(mod, sizeof (topo_rtld_t))) + == NULL) + return (topo_mod_seterrno(mod, ETOPO_RTLD_OPEN)); + + rp->rtld_dlp = dlp; + rp->rtld_init = (int (*)())dlsym(dlp, "_topo_init"); + rp->rtld_fini = (void (*)())dlsym(dlp, "_topo_fini"); + + if (rp->rtld_init == NULL) { + (void) dlclose(dlp); + topo_free(rp, sizeof (topo_rtld_t)); + return (topo_mod_seterrno(mod, ETOPO_RTLD_INIT)); + } + + (void) pthread_mutex_unlock(&mod->tm_lock); + + /* + * Call _topo_init() in the module. + */ + err = rp->rtld_init(mod); + + if (err < 0 || !(mod->tm_flags & TOPO_MOD_REG)) { + (void) rtld_fini(mod); + return (topo_mod_seterrno(mod, ETOPO_MOD_NOREG)); + } + + return (0); +} + +const topo_modops_t topo_rtld_ops = { + rtld_init, + rtld_fini, +}; diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_snap.c b/usr/src/lib/fm/topo/libtopo/common/topo_snap.c new file mode 100644 index 0000000000..5c68f5624f --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_snap.c @@ -0,0 +1,563 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Snapshot Library Interfaces + * + * Consumers of topology data may use the interfaces in this file to open, + * snapshot and close a topology exported by FMRI scheme (hc, mem and cpu) + * builtin plugins and their helper modules. A topology handle is obtained + * by calling topo_open(). Upon a successful return, the caller may use this + * handle to open a new snapshot. Each snapshot is assigned a Universally + * Unique Identifier that in a future enchancement to the libtopo API will be + * used as the file locator in /var/fm/topo to persist new snapshots or lookup + * a previously captured snapshot. topo_snap_hold() will capture the current + * system topology. All consumers of the topo_hdl_t argument will be + * blocked from accessing the topology trees until the snapshot completes. + * + * A snapshot may be cleared by calling topo_snap_rele(). As with + * topo_snap_hold(), all topology accesses are blocked until the topology + * trees have been released and deallocated. + * + * Walker Library Interfaces + * + * Once a snapshot has been taken with topo_snap_hold(), topo_hdl_t holders + * may initiate topology tree walks on a scheme-tree basis. topo_walk_init() + * will initiate the data structures required to walk any one one of the + * FMRI scheme trees. The walker data structure, topo_walk_t, is an opaque + * handle passed to topo_walk_step to begin the walk. At each node in the + * topology tree, a callback function is called with access to the node at + * which our current walk falls. The callback function is passed in during + * calls to topo_walk_init() and used throughout the walk_step of the + * scheme tree. At any time, the callback may terminate the walk by returning + * TOPO_WALK_TERMINATE or TOPO_WALK_ERR. TOPO_WALK_NEXT will continue the + * walk. + * + * Walks through the tree may be breadth first or depth first by + * respectively passing in TOPO_WALK_SIBLING or TOPO_WALK_CHILD to + * the topo_walk_step() function. Topology nodes associated with an + * outstanding walk are held in place and will not be deallocated until + * the walk through that node completes. + * + * Once the walk has terminated, the walking process should call + * topo_walk_fini() to clean-up resources created in topo_walk_init() + * and release nodes that may be still held. + */ + +#include <pthread.h> +#include <limits.h> +#include <assert.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <uuid/uuid.h> + +#include <fm/libtopo.h> + +#include <topo_alloc.h> +#include <topo_builtin.h> +#include <topo_string.h> +#include <topo_error.h> +#include <topo_subr.h> + +static void topo_snap_destroy(topo_hdl_t *); + +static topo_hdl_t * +set_open_errno(topo_hdl_t *thp, int *errp, int err) +{ + if (thp != NULL) { + topo_close(thp); + } + if (errp != NULL) + *errp = err; + return (NULL); +} + +topo_hdl_t * +topo_open(int version, const char *rootdir, int *errp) +{ + topo_hdl_t *thp = NULL; + topo_alloc_t *tap; + struct stat st; + + if (version < TOPO_VERSION) + return (set_open_errno(thp, errp, ETOPO_HDL_VER)); + + if (version > TOPO_VERSION) + return (set_open_errno(thp, errp, ETOPO_HDL_VER)); + + if (rootdir != NULL && stat(rootdir, &st) < 0) + return (set_open_errno(thp, errp, ETOPO_HDL_INVAL)); + + if ((thp = topo_zalloc(sizeof (topo_hdl_t), 0)) == NULL) + return (set_open_errno(thp, errp, ETOPO_NOMEM)); + + if ((tap = topo_zalloc(sizeof (topo_alloc_t), 0)) == NULL) + return (set_open_errno(thp, errp, ETOPO_NOMEM)); + + /* + * Install default allocators + */ + tap->ta_flags = 0; + tap->ta_alloc = topo_alloc; + tap->ta_zalloc = topo_zalloc; + tap->ta_free = topo_free; + tap->ta_nvops.nv_ao_alloc = topo_nv_alloc; + tap->ta_nvops.nv_ao_free = topo_nv_free; + (void) nv_alloc_init(&tap->ta_nva, &tap->ta_nvops); + thp->th_alloc = tap; + + if ((thp->th_modhash = topo_modhash_create(thp)) == NULL) + return (set_open_errno(thp, errp, ETOPO_NOMEM)); + + if (rootdir == NULL) { + rootdir = topo_hdl_strdup(thp, "/"); + thp->th_rootdir = (char *)rootdir; + } else { + if (strlen(rootdir) > PATH_MAX) + return (set_open_errno(thp, errp, EINVAL)); + + thp->th_rootdir = topo_hdl_strdup(thp, rootdir); + } + + if (thp->th_rootdir == NULL) + return (set_open_errno(thp, errp, ETOPO_NOMEM)); + + if (topo_builtin_create(thp, thp->th_rootdir) != 0) { + topo_dprintf(TOPO_DBG_ERR, "failed to load builtin modules: " + "%s\n", topo_hdl_errmsg(thp)); + return (NULL); + } + + return (thp); +} + +void +topo_close(topo_hdl_t *thp) +{ + ttree_t *tp; + + topo_hdl_lock(thp); + if (thp->th_rootdir != NULL) + topo_hdl_strfree(thp, thp->th_rootdir); + + /* + * Clean-up snapshot + */ + topo_snap_destroy(thp); + + /* + * Clean-up trees + */ + while ((tp = topo_list_next(&thp->th_trees)) != NULL) { + topo_list_delete(&thp->th_trees, tp); + topo_tree_destroy(thp, tp); + } + + /* + * Unload all plugins + */ + topo_modhash_unload_all(thp); + + if (thp->th_modhash != NULL) + topo_modhash_destroy(thp); + if (thp->th_alloc != NULL) + topo_free(thp->th_alloc, sizeof (topo_alloc_t)); + + topo_hdl_unlock(thp); + + topo_free(thp, sizeof (topo_hdl_t)); +} + +static char * +topo_snap_create(topo_hdl_t *thp, int *errp) +{ + uuid_t uuid; + char *ustr = NULL; + + topo_hdl_lock(thp); + if (thp->th_uuid != NULL) { + *errp = ETOPO_HDL_UUID; + topo_hdl_unlock(thp); + return (NULL); + } + + if ((thp->th_uuid = topo_hdl_zalloc(thp, TOPO_UUID_SIZE)) == NULL) { + *errp = ETOPO_NOMEM; + topo_dprintf(TOPO_DBG_ERR, "unable to allocate uuid: %s\n", + topo_strerror(*errp)); + topo_hdl_unlock(thp); + return (NULL); + } + + uuid_generate(uuid); + uuid_unparse(uuid, thp->th_uuid); + + if (topo_tree_enum_all(thp) < 0) { + topo_dprintf(TOPO_DBG_ERR, "enumeration failure: %s\n", + topo_hdl_errmsg(thp)); + if (topo_hdl_errno(thp) != ETOPO_ENUM_PARTIAL) { + *errp = thp->th_errno; + topo_hdl_unlock(thp); + return (NULL); + } + } + + if ((ustr = topo_hdl_strdup(thp, thp->th_uuid)) == NULL) + *errp = ETOPO_NOMEM; + + topo_hdl_unlock(thp); + + return (ustr); +} + +/*ARGSUSED*/ +static char * +topo_snap_log_create(topo_hdl_t *thp, const char *uuid, int *errp) +{ + return ((char *)uuid); +} + +/* + * Return snapshot id + */ +char * +topo_snap_hold(topo_hdl_t *thp, const char *uuid, int *errp) +{ + if (thp == NULL) + return (NULL); + + if (uuid == NULL) + return (topo_snap_create(thp, errp)); + else + return (topo_snap_log_create(thp, uuid, errp)); +} + +/*ARGSUSED*/ +static int +topo_walk_destroy(topo_hdl_t *thp, tnode_t *node, void *notused) +{ + tnode_t *cnode; + + cnode = topo_child_first(node); + + if (cnode != NULL) + return (TOPO_WALK_NEXT); + + topo_node_unbind(node); + + return (TOPO_WALK_NEXT); +} + +static void +topo_snap_destroy(topo_hdl_t *thp) +{ + int i; + ttree_t *tp; + topo_walk_t *twp; + tnode_t *root; + topo_nodehash_t *nhp; + topo_mod_t *mod; + + for (tp = topo_list_next(&thp->th_trees); tp != NULL; + tp = topo_list_next(tp)) { + + root = tp->tt_root; + twp = tp->tt_walk; + /* + * Clean-up tree nodes from the bottom-up + */ + if ((twp->tw_node = topo_child_first(root)) != NULL) { + twp->tw_cb = topo_walk_destroy; + topo_node_hold(root); + topo_node_hold(twp->tw_node); /* released at walk end */ + (void) topo_walk_bottomup(twp, TOPO_WALK_CHILD); + topo_node_rele(root); + } + + /* + * Tidy-up the root node + */ + while ((nhp = topo_list_next(&root->tn_children)) != NULL) { + for (i = 0; i < nhp->th_arrlen; i++) { + assert(nhp->th_nodearr[i] == NULL); + } + mod = nhp->th_enum; + topo_mod_strfree(mod, nhp->th_name); + topo_mod_free(mod, nhp->th_nodearr, + nhp->th_arrlen * sizeof (tnode_t *)); + topo_list_delete(&root->tn_children, nhp); + topo_mod_free(mod, nhp, sizeof (topo_nodehash_t)); + topo_mod_rele(mod); + } + + /* + * Release the file handle + */ + if (tp->tt_file != NULL) + topo_file_unload(thp, tp); + + } + +} + +void +topo_snap_release(topo_hdl_t *thp) +{ + if (thp == NULL) + return; + + topo_hdl_lock(thp); + if (thp->th_uuid != NULL) { + topo_hdl_free(thp, thp->th_uuid, TOPO_UUID_SIZE); + topo_snap_destroy(thp); + thp->th_uuid = NULL; + } + topo_hdl_unlock(thp); + +} + +topo_walk_t * +topo_walk_init(topo_hdl_t *thp, const char *scheme, topo_walk_cb_t cb_f, + void *pdata, int *errp) +{ + tnode_t *child; + ttree_t *tp; + topo_walk_t *wp; + + for (tp = topo_list_next(&thp->th_trees); tp != NULL; + tp = topo_list_next(tp)) { + if (strcmp(scheme, tp->tt_scheme) == 0) { + + /* + * Hold the root node and start walk at the first + * child node + */ + assert(tp->tt_root != NULL); + + topo_node_hold(tp->tt_root); + + /* + * Nothing to walk + */ + if ((child = topo_child_first(tp->tt_root)) == NULL) { + *errp = ETOPO_WALK_EMPTY; + topo_node_rele(tp->tt_root); + return (NULL); + } + + if ((wp = topo_hdl_zalloc(thp, sizeof (topo_walk_t))) + == NULL) { + *errp = ETOPO_NOMEM; + topo_node_rele(tp->tt_root); + return (NULL); + } + + topo_node_hold(child); + + wp->tw_root = tp->tt_root; + wp->tw_node = child; + wp->tw_cb = cb_f; + wp->tw_pdata = pdata; + wp->tw_thp = thp; + + return (wp); + } + } + + *errp = ETOPO_WALK_NOTFOUND; + return (NULL); +} + +static int +step_child(tnode_t *cnp, topo_walk_t *wp, int bottomup) +{ + int status; + tnode_t *nnp; + + nnp = topo_child_first(cnp); + + if (nnp == NULL) + return (TOPO_WALK_TERMINATE); + + topo_dprintf(TOPO_DBG_WALK, "walk through child node %s=%d\n", + nnp->tn_name, nnp->tn_instance); + + topo_node_hold(nnp); /* released on return from walk_step */ + wp->tw_node = nnp; + if (bottomup == 1) + status = topo_walk_bottomup(wp, TOPO_WALK_CHILD); + else + status = topo_walk_step(wp, TOPO_WALK_CHILD); + + return (status); +} + +static int +step_sibling(tnode_t *cnp, topo_walk_t *wp, int bottomup) +{ + int status; + tnode_t *nnp; + + nnp = topo_child_next(cnp->tn_parent, cnp); + + if (nnp == NULL) + return (TOPO_WALK_TERMINATE); + + topo_dprintf(TOPO_DBG_WALK, "walk through sibling node %s=%d\n", + nnp->tn_name, nnp->tn_instance); + + topo_node_hold(nnp); /* released on return from walk_step */ + wp->tw_node = nnp; + if (bottomup == 1) + status = topo_walk_bottomup(wp, TOPO_WALK_CHILD); + else + status = topo_walk_step(wp, TOPO_WALK_CHILD); + + return (status); +} + +int +topo_walk_step(topo_walk_t *wp, int flag) +{ + int status; + tnode_t *cnp = wp->tw_node; + + if (flag != TOPO_WALK_CHILD && flag != TOPO_WALK_SIBLING) { + topo_node_rele(cnp); + return (TOPO_WALK_ERR); + } + + /* + * End of the line + */ + if (cnp == NULL) { + topo_dprintf(TOPO_DBG_WALK, "walk_step terminated\n"); + topo_node_rele(cnp); + return (TOPO_WALK_TERMINATE); + } + + topo_dprintf(TOPO_DBG_WALK, "%s walk_step through node %s=%d\n", + (flag == TOPO_WALK_CHILD ? "TOPO_WALK_CHILD" : "TOPO_WALK_SIBLING"), + cnp->tn_name, cnp->tn_instance); + + if ((status = wp->tw_cb(wp->tw_thp, cnp, wp->tw_pdata)) + != TOPO_WALK_NEXT) { + topo_node_rele(cnp); + return (status); + } + + if (flag == TOPO_WALK_CHILD) + status = step_child(cnp, wp, 0); + else + status = step_sibling(cnp, wp, 0); + + /* + * End of the walk, try next child or sibling + */ + if (status == TOPO_WALK_TERMINATE) { + if (flag == TOPO_WALK_CHILD) + status = step_sibling(cnp, wp, 0); + else + status = step_child(cnp, wp, 0); + } + + topo_node_rele(cnp); /* done with current node */ + + return (status); +} + +void +topo_walk_fini(topo_walk_t *wp) +{ + if (wp == NULL) + return; + + topo_node_rele(wp->tw_root); + + topo_hdl_free(wp->tw_thp, wp, sizeof (topo_walk_t)); +} + +int +topo_walk_bottomup(topo_walk_t *wp, int flag) +{ + int status; + tnode_t *cnp; + + if (wp == NULL) + return (TOPO_WALK_ERR); + + cnp = wp->tw_node; + if (flag != TOPO_WALK_CHILD && flag != TOPO_WALK_SIBLING) { + topo_node_rele(cnp); + return (TOPO_WALK_ERR); + } + + /* + * End of the line + */ + if (cnp == NULL) { + topo_dprintf(TOPO_DBG_WALK, "walk_bottomup terminated\n"); + topo_node_rele(cnp); + return (TOPO_WALK_TERMINATE); + } + + topo_dprintf(TOPO_DBG_WALK, "%s walk_bottomup through node %s=%d\n", + (flag == TOPO_WALK_CHILD ? "TOPO_WALK_CHILD" : "TOPO_WALK_SIBLING"), + cnp->tn_name, cnp->tn_instance); + + if (flag == TOPO_WALK_CHILD) + status = step_child(cnp, wp, 1); + else + status = step_sibling(cnp, wp, 1); + + /* + * At a leaf, run the callback + */ + if (status == TOPO_WALK_TERMINATE) { + if ((status = wp->tw_cb(wp->tw_thp, cnp, wp->tw_pdata)) + != TOPO_WALK_NEXT) { + topo_node_rele(cnp); + return (status); + } + } + + /* + * Try next child or sibling + */ + if (status == TOPO_WALK_NEXT) { + if (flag == TOPO_WALK_CHILD) + status = step_sibling(cnp, wp, 1); + else + status = step_child(cnp, wp, 1); + } + + topo_node_rele(cnp); /* done with current node */ + + return (status); +} diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_string.c b/usr/src/lib/fm/topo/libtopo/common/topo_string.c new file mode 100644 index 0000000000..2c1f451770 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_string.c @@ -0,0 +1,256 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <strings.h> +#include <ctype.h> +#include <fm/libtopo.h> +#include <fm/topo_mod.h> +#include <topo_alloc.h> + +char * +topo_hdl_strdup(topo_hdl_t *thp, const char *s) +{ + char *p; + + if (s != NULL) + p = topo_hdl_alloc(thp, strlen(s) + 1); + else + p = NULL; + + if (p != NULL) + (void) strcpy(p, s); + + return (p); +} + +void +topo_hdl_strfree(topo_hdl_t *thp, char *s) +{ + if (s != NULL) + topo_hdl_free(thp, s, strlen(s) + 1); +} + +char * +topo_mod_strdup(topo_mod_t *mod, const char *s) +{ + return (topo_hdl_strdup(mod->tm_hdl, s)); +} + +void +topo_mod_strfree(topo_mod_t *mod, char *s) +{ + topo_hdl_strfree(mod->tm_hdl, s); +} + +const char * +topo_strbasename(const char *s) +{ + const char *p = strrchr(s, '/'); + + if (p == NULL) + return (s); + + return (++p); +} + +char * +topo_strdirname(char *s) +{ + static char slash[] = "/"; + static char dot[] = "."; + char *p; + + if (s == NULL || *s == '\0') + return (dot); + + for (p = s + strlen(s); p != s && *--p == '/'; ) + continue; + + if (p == s && *p == '/') + return (slash); + + while (p != s) { + if (*--p == '/') { + while (*p == '/' && p != s) + p--; + *++p = '\0'; + return (s); + } + } + + return (dot); +} + +ulong_t +topo_strhash(const char *key) +{ + ulong_t g, h = 0; + const char *p; + + for (p = key; *p != '\0'; p++) { + h = (h << 4) + *p; + + if ((g = (h & 0xf0000000)) != 0) { + h ^= (g >> 24); + h ^= g; + } + } + + return (h); +} + +/* + * Transform string s inline, converting each embedded C escape sequence string + * to the corresponding character. For example, the substring "\n" is replaced + * by an inline '\n' character. The length of the resulting string is returned. + */ +size_t +topo_stresc2chr(char *s) +{ + char *p, *q, c; + int esc = 0; + int x; + + for (p = q = s; (c = *p) != '\0'; p++) { + if (esc) { + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + c -= '0'; + p++; + + if (*p >= '0' && *p <= '7') { + c = c * 8 + *p++ - '0'; + + if (*p >= '0' && *p <= '7') + c = c * 8 + *p - '0'; + else + p--; + } else + p--; + + *q++ = c; + break; + + case 'a': + *q++ = '\a'; + break; + case 'b': + *q++ = '\b'; + break; + case 'f': + *q++ = '\f'; + break; + case 'n': + *q++ = '\n'; + break; + case 'r': + *q++ = '\r'; + break; + case 't': + *q++ = '\t'; + break; + case 'v': + *q++ = '\v'; + break; + + case 'x': + for (x = 0; (c = *++p) != '\0'; ) { + if (c >= '0' && c <= '9') + x = x * 16 + c - '0'; + else if (c >= 'a' && c <= 'f') + x = x * 16 + c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + x = x * 16 + c - 'A' + 10; + else + break; + } + *q++ = (char)x; + p--; + break; + + case '"': + case '\\': + *q++ = c; + break; + default: + *q++ = '\\'; + *q++ = c; + } + + esc = 0; + + } else { + if ((esc = c == '\\') == 0) + *q++ = c; + } + } + + *q = '\0'; + return ((size_t)(q - s)); +} + +int +topo_strmatch(const char *s, const char *p) +{ + char c; + + if (p == NULL) + return (0); + + if (s == NULL) + s = ""; /* treat NULL string as the empty string */ + + do { + if ((c = *p++) == '\0') + return (*s == '\0'); + + if (c == '*') { + while (*p == '*') + p++; /* consecutive *'s can be collapsed */ + + if (*p == '\0') + return (1); + + while (*s != '\0') { + if (topo_strmatch(s++, p) != 0) + return (1); + } + + return (0); + } + } while (c == *s++); + + return (0); +} diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_string.h b/usr/src/lib/fm/topo/libtopo/common/topo_string.h new file mode 100644 index 0000000000..7c4a29d872 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_string.h @@ -0,0 +1,52 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _TOPO_STRING_H +#define _TOPO_STRING_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> +#include <strings.h> +#include <topo_tree.h> + +extern const char *topo_strbasename(const char *); +extern char *topo_strdirname(char *); + +extern ulong_t topo_strhash(const char *); +extern size_t topo_stresc2chr(char *); +extern const char *topo_strbadid(const char *, int); +extern int topo_strmatch(const char *, const char *); + +#ifdef __cplusplus +} +#endif + +#endif /* _TOPO_STRING_H */ diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_subr.c b/usr/src/lib/fm/topo/libtopo/common/topo_subr.c new file mode 100644 index 0000000000..40458f00e6 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_subr.c @@ -0,0 +1,163 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <alloca.h> +#include <syslog.h> +#include <strings.h> + +#include <topo_error.h> +#include <topo_subr.h> + +struct _rwlock; +struct _lwp_mutex; + +int _topo_debug = 0; /* debug messages enabled (off) */ +int _topo_dbout = 0; /* debug messages output mode */ + +int +topo_rw_read_held(pthread_rwlock_t *lock) +{ + extern int _rw_read_held(struct _rwlock *); + return (_rw_read_held((struct _rwlock *)lock)); +} + +int +topo_rw_write_held(pthread_rwlock_t *lock) +{ + extern int _rw_write_held(struct _rwlock *); + return (_rw_write_held((struct _rwlock *)lock)); +} + +int +topo_mutex_held(pthread_mutex_t *lock) +{ + extern int _mutex_held(struct _lwp_mutex *); + return (_mutex_held((struct _lwp_mutex *)lock)); +} + +void +topo_hdl_lock(topo_hdl_t *thp) +{ + (void) pthread_mutex_lock(&thp->th_lock); +} + +void +topo_hdl_unlock(topo_hdl_t *thp) +{ + (void) pthread_mutex_unlock(&thp->th_lock); +} + +const char * +topo_stability_name(topo_stability_t s) +{ + switch (s) { + case TOPO_STABILITY_INTERNAL: return ("Internal"); + case TOPO_STABILITY_PRIVATE: return ("Private"); + case TOPO_STABILITY_OBSOLETE: return ("Obsolete"); + case TOPO_STABILITY_EXTERNAL: return ("External"); + case TOPO_STABILITY_UNSTABLE: return ("Unstable"); + case TOPO_STABILITY_EVOLVING: return ("Evolving"); + case TOPO_STABILITY_STABLE: return ("Stable"); + case TOPO_STABILITY_STANDARD: return ("Standard"); + default: return (NULL); + } +} + +static const topo_debug_mode_t _topo_dbout_modes[] = { + { "stderr", "send debug messages to stderr", TOPO_DBOUT_STDERR }, + { "syslog", "send debug messages to syslog", TOPO_DBOUT_SYSLOG }, + { NULL, NULL, 0 } +}; + +void +topo_debug_set(topo_hdl_t *thp, int mask, char *dout) +{ + int i; + + for (i = 0; i < 2; ++i) { + if (strcmp(_topo_dbout_modes[i].tdm_name, dout) == 0) { + thp->th_dbout = _topo_dbout = + _topo_dbout_modes[i].tdm_mode; + thp->th_debug = _topo_debug = mask; + topo_dprintf(mask, _topo_dbout_modes[i].tdm_desc); + } + } +} + +void +topo_vdprintf(int mask, const char *format, va_list ap) +{ + char *msg; + size_t len; + char c; + + if (!(_topo_debug & mask)) + return; + + len = vsnprintf(&c, 1, format, ap); + msg = alloca(len + 2); + (void) vsnprintf(msg, len + 1, format, ap); + + if (msg[len - 1] != '\n') + (void) strcpy(&msg[len], "\n"); + + if (_topo_dbout == TOPO_DBOUT_STDERR) + (void) fprintf(stderr, "libtopo DEBUG: %s", msg); + + if (_topo_dbout == TOPO_DBOUT_SYSLOG) + syslog(LOG_DEBUG | LOG_USER, "libtopo DEBUG: %s", msg); +} + +/*PRINTFLIKE2*/ +void +topo_dprintf(int mask, const char *format, ...) +{ + va_list ap; + + if (!(_topo_debug & mask)) + return; + + va_start(ap, format); + topo_vdprintf(mask, format, ap); + va_end(ap); +} + +tnode_t * +topo_hdl_root(topo_hdl_t *thp, const char *scheme) +{ + ttree_t *tp; + + for (tp = topo_list_next(&thp->th_trees); tp != NULL; + tp = topo_list_next(tp)) { + if (strcmp(scheme, tp->tt_scheme) == 0) + return (tp->tt_root); + } + + return (NULL); +} diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_subr.h b/usr/src/lib/fm/topo/libtopo/common/topo_subr.h new file mode 100644 index 0000000000..241f0892ec --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_subr.h @@ -0,0 +1,72 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _TOPO_SUBR_H +#define _TOPO_SUBR_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <fm/libtopo.h> +#include <topo_list.h> + +#include <pthread.h> +#include <stdarg.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct topo_debug_mode { + char *tdm_name; /* mode name */ + char *tdm_desc; /* mode description */ + int tdm_mode; /* mode: See below */ +} topo_debug_mode_t; + +#define TOPO_DBOUT_STDERR 0 /* Debug messages to stderr */ +#define TOPO_DBOUT_SYSLOG 1 /* Debug messages to syslog */ + +extern int topo_rw_read_held(pthread_rwlock_t *); +extern int topo_rw_write_held(pthread_rwlock_t *); +extern int topo_mutex_held(pthread_mutex_t *); + +extern void topo_hdl_lock(topo_hdl_t *); +extern void topo_hdl_unlock(topo_hdl_t *); + +extern const char *topo_stability_name(topo_stability_t); +extern char *topo_version_num2str(topo_version_t, char *, size_t); +extern int topo_version_str2num(const char *, topo_version_t); +extern int topo_version_defined(topo_version_t); + +extern void topo_dprintf(int, const char *, ...); +extern void topo_vdprintf(int, const char *, va_list); + +extern tnode_t *topo_hdl_root(topo_hdl_t *, const char *); + +#ifdef __cplusplus +} +#endif + +#endif /* _TOPO_SUBR_H */ diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_tree.c b/usr/src/lib/fm/topo/libtopo/common/topo_tree.c new file mode 100644 index 0000000000..736d3a3993 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_tree.c @@ -0,0 +1,207 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Topology Trees + * + * Toplogy trees are instantiated for each builtin (FMRI) scheme specified + * in topo_builtin.c. Each ttree_t data structure contains the + * skeleton of the topology tree (scheme, root node, and file information). + * The root node of a topology does not represent any FMRI but rather serves + * as the entry point for topology access interfaces. The file information + * provides a handle to access static .xml files that seed scheme-specifc + * topologies + * + * Topology trees will remain unpopulated until topo_snap_hold() is called. + * At that time, a ttree_t structure is allocated and added to the list + * trees maintained in topo_hdl_t. Builtin scheme-specific enumerators are + * called upon to create nodes that represent FMRIs for resources present in the + * system. If a <scheme>-topology.xml file exists in a standard file + * location, the file is used to seed the topology while the rest is + * dynamically created by the builtin or helper enumerator modules. + * For example, the 'hc' tree is enumerated by the hc enumerator (hc.c) + * after the hc-topology.xml is read from /usr/platform/`uname -i`/lib/fm/topo, + * /usr/platform/`uname -r`/lib/fm/topo, or /usr/lib/fm/topo. Each node + * is created with a properly formatted hc FMRI resource. + * + * Toplogy trees are released and deallocated when topo_snap_hold is called. + * Upon return from topo_snap_rele(), all node resources are deallocated + * and all that remains is the ttree_t structure containing the root node. + */ + +#include <pthread.h> +#include <limits.h> +#include <assert.h> +#include <sys/param.h> +#include <sys/systeminfo.h> +#include <sys/utsname.h> + +#include <topo_alloc.h> +#include <topo_error.h> +#include <topo_module.h> +#include <topo_string.h> +#include <topo_subr.h> +#include <topo_tree.h> + +static ttree_t * +set_create_error(topo_hdl_t *thp, ttree_t *tp, int err) +{ + if (tp != NULL) + topo_tree_destroy(thp, tp); + + if (err != 0) + (void) topo_hdl_seterrno(thp, err); + + return (NULL); +} + +static void +set_system_props(tnode_t *node) +{ + int err; + char platform[MAXNAMELEN]; + char isa[MAXNAMELEN]; + struct utsname uts; + + platform[0] = '\0'; + isa[0] = '\0'; + (void) sysinfo(SI_PLATFORM, platform, sizeof (platform)); + (void) sysinfo(SI_ARCHITECTURE, isa, sizeof (isa)); + (void) uname(&uts); + + (void) topo_pgroup_create(node, TOPO_PGROUP_SYSTEM, + TOPO_STABILITY_PRIVATE, &err); + (void) topo_prop_set_string(node, TOPO_PGROUP_SYSTEM, + TOPO_PROP_PLATFORM, TOPO_PROP_SET_ONCE, platform, &err); + (void) topo_prop_set_string(node, TOPO_PGROUP_SYSTEM, + TOPO_PROP_ISA, TOPO_PROP_SET_ONCE, isa, &err); + (void) topo_prop_set_string(node, TOPO_PGROUP_SYSTEM, + TOPO_PROP_MACHINE, TOPO_PROP_SET_ONCE, uts.machine, &err); +} + +ttree_t * +topo_tree_create(topo_hdl_t *thp, topo_mod_t *mod, const char *scheme) +{ + ttree_t *tp; + tnode_t *rp; + + if ((tp = topo_hdl_zalloc(thp, sizeof (ttree_t))) == NULL) + return (set_create_error(thp, NULL, ETOPO_NOMEM)); + + if ((tp->tt_scheme = topo_hdl_strdup(thp, scheme)) == NULL) + return (set_create_error(thp, tp, ETOPO_NOMEM)); + + /* + * Initialize a private walker for internal use + */ + if ((tp->tt_walk = topo_hdl_zalloc(thp, sizeof (topo_walk_t))) == NULL) + return (set_create_error(thp, tp, ETOPO_NOMEM)); + + /* + * Create the root of this tree: LINKED but never BOUND + */ + if ((rp = topo_mod_zalloc(mod, sizeof (tnode_t))) == NULL) + return (set_create_error(thp, tp, 0)); /* th_errno set */ + + rp->tn_state = TOPO_NODE_ROOT | TOPO_NODE_INIT; + rp->tn_name = tp->tt_scheme; + rp->tn_instance = 0; + rp->tn_enum = mod; + rp->tn_hdl = thp; + + set_system_props(rp); + topo_node_hold(rp); + + tp->tt_walk->tw_root = rp; + tp->tt_walk->tw_thp = thp; + + topo_mod_hold(mod); /* released when root node destroyed */ + + tp->tt_root = rp; + + return (tp); +} + +void +topo_tree_destroy(topo_hdl_t *thp, ttree_t *tp) +{ + if (tp == NULL) + return; + + if (tp->tt_scheme != NULL) + topo_hdl_strfree(thp, tp->tt_scheme); + if (tp->tt_walk != NULL) + topo_hdl_free(thp, tp->tt_walk, sizeof (topo_walk_t)); + + if (tp->tt_file != NULL) + topo_file_unload(thp, tp); + + if (tp->tt_root != NULL) { + assert(tp->tt_root->tn_refs == 1); + topo_node_rele(tp->tt_root); + } + + topo_hdl_free(thp, tp, sizeof (ttree_t)); +} + +static int +topo_tree_enum(topo_hdl_t *thp, ttree_t *tp) +{ + tnode_t *rnode; + + rnode = tp->tt_root; + /* + * Attempt to populate the tree from a topology file + */ + if (topo_file_load(thp, rnode->tn_enum, tp) < 0) { + /* + * If this tree does not have a matching static topology file, + * continue on. + */ + if (topo_hdl_errno(thp) != ETOPO_FILE_NOENT) + return (topo_hdl_seterrno(thp, ETOPO_ENUM_PARTIAL)); + } + return (0); +} + +int +topo_tree_enum_all(topo_hdl_t *thp) +{ + int err = 0; + ttree_t *tp; + + for (tp = topo_list_next(&thp->th_trees); tp != NULL; + tp = topo_list_next(tp)) { + err |= topo_tree_enum(thp, tp); + } + + if (err != 0) + return (-1); + else + return (0); +} diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_tree.h b/usr/src/lib/fm/topo/libtopo/common/topo_tree.h new file mode 100644 index 0000000000..3409c1f377 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_tree.h @@ -0,0 +1,151 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _TOPO_TREE_H +#define _TOPO_TREE_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <fm/topo_mod.h> + +#include <topo_list.h> +#include <topo_prop.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct topo_modhash topo_modhash_t; + +typedef struct topo_range { + topo_instance_t tr_min; + topo_instance_t tr_max; +} topo_range_t; + +typedef struct topo_nodehash { + topo_list_t th_list; /* next/prev pointers */ + tnode_t **th_nodearr; /* node array */ + uint_t th_arrlen; /* size of node array */ + char *th_name; /* name for all nodes in this hash */ + topo_mod_t *th_enum; /* enumerator module */ + topo_range_t th_range; /* instance ranges for nodes */ +} topo_nodehash_t; + +typedef struct topo_imethod { + topo_list_t tim_list; /* next/prev pointers */ + pthread_mutex_t tim_lock; /* method entry lock */ + pthread_cond_t tim_cv; /* method entry cv */ + uint_t tim_busy; /* method entry busy indicator */ + char *tim_name; /* Method name */ + topo_version_t tim_version; /* Method version */ + topo_stability_t tim_stability; /* SMI stability of method */ + char *tim_desc; /* Method description */ + topo_method_f *tim_func; /* Method function */ + struct topo_mod *tim_mod; /* Ptr to controlling module */ +} topo_imethod_t; + +struct topo_node { + pthread_mutex_t tn_lock; /* lock protecting members */ + char *tn_name; /* Node name */ + topo_instance_t tn_instance; /* Node instance */ + int tn_state; /* node state (see below) */ + int tn_fflags; /* fmri flags (see libtopo.h) */ + struct topo_node *tn_parent; /* Node parent */ + topo_nodehash_t *tn_phash; /* parent hash bucket for this node */ + topo_hdl_t *tn_hdl; /* topo handle pointer */ + topo_mod_t *tn_enum; /* Enumerator module */ + topo_list_t tn_children; /* hash table of child nodes */ + topo_list_t tn_pgroups; /* Property group list */ + topo_list_t tn_methods; /* Registered method list */ + void *tn_priv; /* Private enumerator data */ + int tn_refs; /* node reference count */ +}; + +#define TOPO_NODE_INIT 0x0001 +#define TOPO_NODE_ROOT 0x0002 +#define TOPO_NODE_BOUND 0x0004 +#define TOPO_NODE_LINKED 0x0008 + +typedef struct topo_tree { + topo_list_t tt_list; /* next/prev pointers */ + char *tt_scheme; /* Scheme name */ + void *tt_file; /* Topology file info */ + struct topo_node *tt_root; /* Root node */ + topo_walk_t *tt_walk; /* private walker */ +} ttree_t; + +struct topo_walk { + struct topo_hdl *tw_thp; /* Topo handle pointer */ + struct topo_node *tw_root; /* Root node of current walk */ + struct topo_node *tw_node; /* Current walker node */ + topo_walk_cb_t tw_cb; /* Walker callback function */ + void *tw_pdata; /* Private callback data */ +}; + +typedef struct topo_alloc { + int ta_flags; + nv_alloc_t ta_nva; + nv_alloc_ops_t ta_nvops; + void *(*ta_alloc)(size_t, int); + void *(*ta_zalloc)(size_t, int); + void (*ta_free)(void *, size_t); +} topo_alloc_t; + +struct topo_hdl { + pthread_mutex_t th_lock; /* lock protecting hdl */ + char *th_uuid; /* uuid of snapshot */ + char *th_rootdir; /* Root directory of plugin paths */ + topo_modhash_t *th_modhash; /* Module hash */ + topo_list_t th_trees; /* Scheme-specific topo tree list */ + topo_alloc_t *th_alloc; /* allocators */ + int th_errno; /* errno */ + int th_debug; /* Debug mask */ + int th_dbout; /* Debug channel */ +}; + +#define TOPO_UUID_SIZE 37 /* libuuid limit + 1 */ + +extern ttree_t *topo_tree_create(topo_hdl_t *, topo_mod_t *, const char *); +extern void topo_tree_destroy(topo_hdl_t *, ttree_t *); +extern int topo_tree_enum_all(topo_hdl_t *); + +extern int topo_file_load(topo_hdl_t *, topo_mod_t *, ttree_t *); +extern void topo_file_unload(topo_hdl_t *, ttree_t *); + +extern void topo_node_lock(tnode_t *); +extern void topo_node_unlock(tnode_t *); +extern void topo_node_hold(tnode_t *); +extern void topo_node_rele(tnode_t *); +extern tnode_t *topo_node_lookup(tnode_t *, const char *, topo_instance_t); +extern int topo_node_hash(topo_nodehash_t *, topo_instance_t); + +extern int topo_walk_bottomup(topo_walk_t *, int); + +#ifdef __cplusplus +} +#endif + +#endif /* _TOPO_TREE_H */ diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_xml.c b/usr/src/lib/fm/topo/libtopo/common/topo_xml.c new file mode 100644 index 0000000000..fbcf10b690 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/common/topo_xml.c @@ -0,0 +1,1080 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <libxml/parser.h> +#include <libxml/xinclude.h> +#include <sys/fm/protocol.h> +#include <assert.h> +#include <string.h> +#include <strings.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <fm/libtopo.h> +#include <unistd.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <topo_mod.h> +#include <topo_subr.h> +#include <topo_alloc.h> +#include <topo_parse.h> +#include <topo_error.h> + +const char * const Children = "children"; +const char * const Dependents = "dependents"; +const char * const FMRI = "fmri"; +const char * const Grouping = "grouping"; +const char * const Immutable = "immutable"; +const char * const Instance = "instance"; +const char * const Int32 = "int32"; +const char * const Int64 = "int64"; +const char * const Name = "name"; +const char * const Path = "path"; +const char * const Range = "range"; +const char * const Scheme = "scheme"; +const char * const Siblings = "siblings"; +const char * const String = "string"; +const char * const Topology = "topology"; +const char * const Type = "type"; +const char * const UInt32 = "uint32"; +const char * const UInt64 = "uint64"; +const char * const Value = "value"; +const char * const Verify = "verify"; +const char * const Version = "version"; + +const char * const Enum_meth = "enum-method"; +const char * const Propgrp = "propgroup"; +const char * const Propval = "propval"; + +const char * const Node = "node"; +const char * const Hc = "hc"; + +const char * const True = "true"; +const char * const False = "false"; + +const char * const Namestab = "name-stability"; +const char * const Datastab = "data-stability"; + +const char * const Evolving = "Evolving"; +const char * const External = "External"; +const char * const Internal = "Internal"; +const char * const Obsolete = "Obsolete"; +const char * const Private = "Private"; +const char * const Stable = "Stable"; +const char * const Standard = "Standard"; +const char * const Unstable = "Unstable"; + +static tf_rdata_t *topo_xml_walk(topo_mod_t *, + tf_info_t *, xmlNodePtr, tnode_t *); + +static void +txml_dump(int g, xmlNodePtr p) +{ + if (p && p->name) { + topo_dprintf(TOPO_DBG_MOD, "%d %s\n", g, p->name); + + for (p = p->xmlChildrenNode; p != NULL; p = p->next) + txml_dump(g + 1, p); + } +} + +int +xmlattr_to_stab(topo_mod_t *mp, xmlNodePtr n, topo_stability_t *rs) +{ + xmlChar *str; + int rv = 0; + + if (n == NULL) { + /* If there is no Stability defined, we default to private */ + *rs = TOPO_STABILITY_PRIVATE; + return (0); + } + if ((str = xmlGetProp(n, (xmlChar *)Value)) == NULL) + return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR)); + if (xmlStrcmp(str, (xmlChar *)Internal) == 0) { + *rs = TOPO_STABILITY_INTERNAL; + } else if (xmlStrcmp(str, (xmlChar *)Private) == 0) { + *rs = TOPO_STABILITY_PRIVATE; + } else if (xmlStrcmp(str, (xmlChar *)Obsolete) == 0) { + *rs = TOPO_STABILITY_OBSOLETE; + } else if (xmlStrcmp(str, (xmlChar *)External) == 0) { + *rs = TOPO_STABILITY_EXTERNAL; + } else if (xmlStrcmp(str, (xmlChar *)Unstable) == 0) { + *rs = TOPO_STABILITY_UNSTABLE; + } else if (xmlStrcmp(str, (xmlChar *)Evolving) == 0) { + *rs = TOPO_STABILITY_EVOLVING; + } else if (xmlStrcmp(str, (xmlChar *)Stable) == 0) { + *rs = TOPO_STABILITY_STABLE; + } else if (xmlStrcmp(str, (xmlChar *)Standard) == 0) { + *rs = TOPO_STABILITY_STANDARD; + } else { + xmlFree(str); + return (topo_mod_seterrno(mp, ETOPO_PRSR_BADSTAB)); + } + xmlFree(str); + return (rv); +} + +int +xmlattr_to_int(topo_mod_t *mp, + xmlNodePtr n, const char *propname, uint64_t *value) +{ + xmlChar *str; + xmlChar *estr; + + topo_mod_dprintf(mp, "attribute to int\n"); + if ((str = xmlGetProp(n, (xmlChar *)propname)) == NULL) + return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR)); + *value = strtoull((char *)str, (char **)&estr, 10); + if (estr == str) { + /* no conversion was done */ + xmlFree(str); + return (topo_mod_seterrno(mp, ETOPO_PRSR_BADNUM)); + } + xmlFree(str); + return (0); +} + +static int +xmlattr_to_fmri(topo_mod_t *mp, + xmlNodePtr xn, const char *propname, nvlist_t **rnvl) +{ + int err; + xmlChar *str; + + topo_mod_dprintf(mp, "attribute to int\n"); + if ((str = xmlGetProp(xn, (xmlChar *)propname)) == NULL) + return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR)); + if (topo_fmri_str2nvl(topo_mod_handle(mp), (const char *)str, rnvl, + &err) < 0) + return (-1); + xmlFree(str); + return (0); +} + +static topo_type_t +xmlattr_to_type(topo_mod_t *mp, xmlNodePtr xn) +{ + topo_type_t rv; + xmlChar *str; + if ((str = xmlGetProp(xn, (xmlChar *)Type)) == NULL) { + topo_mod_dprintf(mp, "Property missing type"); + (void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR); + return (TOPO_TYPE_INVALID); + } + if (xmlStrcmp(str, (xmlChar *)Int32) == 0) { + rv = TOPO_TYPE_INT32; + } else if (xmlStrcmp(str, (xmlChar *)UInt32) == 0) { + rv = TOPO_TYPE_UINT32; + } else if (xmlStrcmp(str, (xmlChar *)Int64) == 0) { + rv = TOPO_TYPE_INT64; + } else if (xmlStrcmp(str, (xmlChar *)UInt64) == 0) { + rv = TOPO_TYPE_UINT64; + } else if (xmlStrcmp(str, (xmlChar *)FMRI) == 0) { + rv = TOPO_TYPE_FMRI; + } else if (xmlStrcmp(str, (xmlChar *)String) == 0) { + rv = TOPO_TYPE_STRING; + } else { + xmlFree(str); + topo_mod_dprintf(mp, "Unrecognized type attribute.\n"); + (void) topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE); + return (TOPO_TYPE_INVALID); + } + xmlFree(str); + return (rv); +} + +static int +xmlprop_xlate(topo_mod_t *mp, xmlNodePtr xn, nvlist_t *nvl) +{ + topo_type_t ptype; + xmlChar *str; + nvlist_t *fmri; + uint64_t ui; + int e; + + if ((str = xmlGetProp(xn, (xmlChar *)Immutable)) != NULL) { + if (xmlStrcmp(str, (xmlChar *)False) == 0) + e = nvlist_add_boolean_value(nvl, INV_IMMUTE, B_FALSE); + else + e = nvlist_add_boolean_value(nvl, INV_IMMUTE, B_TRUE); + xmlFree(str); + if (e != 0) + return (-1); + } + /* FMXXX stability of the property value */ + if ((ptype = xmlattr_to_type(mp, xn)) == TOPO_TYPE_INVALID) + return (-1); + e = nvlist_add_int32(nvl, INV_PVALTYPE, ptype); + if (e != 0) + return (-1); + switch (ptype) { + case TOPO_TYPE_INT32: + if (xmlattr_to_int(mp, xn, Value, &ui) < 0) + return (-1); + e = nvlist_add_int32(nvl, INV_PVAL, (int32_t)ui); + break; + case TOPO_TYPE_UINT32: + if (xmlattr_to_int(mp, xn, Value, &ui) < 0) + return (-1); + e = nvlist_add_uint32(nvl, INV_PVAL, (uint32_t)ui); + break; + case TOPO_TYPE_INT64: + if (xmlattr_to_int(mp, xn, Value, &ui) < 0) + return (-1); + e = nvlist_add_int64(nvl, INV_PVAL, (int64_t)ui); + break; + case TOPO_TYPE_UINT64: + if (xmlattr_to_int(mp, xn, Value, &ui) < 0) + return (-1); + e = nvlist_add_uint64(nvl, INV_PVAL, ui); + break; + case TOPO_TYPE_FMRI: + if (xmlattr_to_fmri(mp, xn, Value, &fmri) < 0) + return (-1); + e = nvlist_add_nvlist(nvl, INV_PVAL, fmri); + nvlist_free(fmri); + break; + case TOPO_TYPE_STRING: + if ((str = xmlGetProp(xn, (xmlChar *)Value)) == NULL) + return (-1); + e = nvlist_add_string(nvl, INV_PVAL, (char *)str); + xmlFree(str); + break; + default: + topo_mod_dprintf(mp, "Unrecognized type attribute.\n"); + return (topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE)); + } + if (e != 0) { + topo_mod_dprintf(mp, "Nvlist construction failed.\n"); + return (topo_mod_seterrno(mp, ETOPO_NOMEM)); + } + return (0); +} + +static int +dependent_create(topo_mod_t *mp, + tf_info_t *xinfo, tf_pad_t *pad, xmlNodePtr dxn, tnode_t *ptn) +{ + tf_rdata_t *rp, *pp, *np; + xmlChar *grptype; + int sibs = 0; + + topo_mod_dprintf(mp, "dependent create\n"); + if ((grptype = xmlGetProp(dxn, (xmlChar *)Grouping)) == NULL) { + topo_mod_dprintf(mp, "Dependents missing grouping attribute"); + return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR)); + } + + pp = NULL; + if (xmlStrcmp(grptype, (xmlChar *)Siblings) == 0) { + rp = pad->tpad_sibs; + sibs++; + } else if (xmlStrcmp(grptype, (xmlChar *)Children) == 0) { + rp = pad->tpad_child; + } else { + topo_mod_dprintf(mp, + "Dependents have bogus grouping attribute"); + xmlFree(grptype); + return (topo_mod_seterrno(mp, ETOPO_PRSR_BADGRP)); + } + xmlFree(grptype); + /* Add processed dependents to the tail of the list */ + while (rp != NULL) { + pp = rp; + rp = rp->rd_next; + } + if ((np = topo_xml_walk(mp, xinfo, dxn, ptn)) == NULL) { + topo_mod_dprintf(mp, + "error within dependent .xml topology: " + "%s\n", topo_strerror(topo_mod_errno(mp))); + return (-1); + } + if (pp != NULL) + pp->rd_next = np; + else if (sibs == 1) + pad->tpad_sibs = np; + else + pad->tpad_child = np; + return (0); +} + +static int +dependents_create(topo_mod_t *mp, + tf_info_t *xinfo, tf_pad_t *pad, xmlNodePtr pxn, tnode_t *ptn) +{ + xmlNodePtr cn; + + topo_mod_dprintf(mp, "dependents create\n"); + for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) { + if (xmlStrcmp(cn->name, (xmlChar *)Dependents) == 0) { + if (dependent_create(mp, xinfo, pad, cn, ptn) < 0) + return (-1); + } + } + return (0); +} + +static int +prop_create(topo_mod_t *mp, + nvlist_t *pfmri, tnode_t *ptn, const char *gnm, const char *pnm, + topo_type_t ptype, int flag) +{ + nvlist_t *fmri; + uint32_t ui32; + uint64_t ui64; + int32_t i32; + int64_t i64; + char *str; + int err, e; + + topo_mod_dprintf(mp, "prop create\n"); + switch (ptype) { + case TOPO_TYPE_INT32: + e = nvlist_lookup_int32(pfmri, INV_PVAL, &i32); + break; + case TOPO_TYPE_UINT32: + e = nvlist_lookup_uint32(pfmri, INV_PVAL, &ui32); + break; + case TOPO_TYPE_INT64: + e = nvlist_lookup_int64(pfmri, INV_PVAL, &i64); + break; + case TOPO_TYPE_UINT64: + e = nvlist_lookup_uint64(pfmri, INV_PVAL, &ui64); + break; + case TOPO_TYPE_FMRI: + e = nvlist_lookup_nvlist(pfmri, INV_PVAL, &fmri); + break; + case TOPO_TYPE_STRING: + e = nvlist_lookup_string(pfmri, INV_PVAL, &str); + break; + default: + e = ETOPO_PRSR_BADTYPE; + } + if (e != 0) { + topo_mod_dprintf(mp, "prop value lookup failed.\n"); + return (topo_mod_seterrno(mp, e)); + } + switch (ptype) { + case TOPO_TYPE_INT32: + e = topo_prop_set_int32(ptn, gnm, pnm, flag, i32, &err); + break; + case TOPO_TYPE_UINT32: + e = topo_prop_set_uint32(ptn, gnm, pnm, flag, ui32, &err); + break; + case TOPO_TYPE_INT64: + e = topo_prop_set_int64(ptn, gnm, pnm, flag, i64, &err); + break; + case TOPO_TYPE_UINT64: + e = topo_prop_set_uint64(ptn, gnm, pnm, flag, ui64, &err); + break; + case TOPO_TYPE_FMRI: + e = topo_prop_set_fmri(ptn, gnm, pnm, flag, fmri, &err); + break; + case TOPO_TYPE_STRING: + e = topo_prop_set_string(ptn, gnm, pnm, flag, str, &err); + break; + } + if (e != 0) { + topo_mod_dprintf(mp, "prop set failed.\n"); + return (topo_mod_seterrno(mp, err)); + } + return (0); +} + +static int +props_create(topo_mod_t *mp, + tnode_t *ptn, const char *gnm, nvlist_t **props, int nprops) +{ + topo_type_t ptype; + boolean_t pim; + char *pnm; + int32_t i32; + int flag; + int pn; + int e; + + topo_mod_dprintf(mp, "props create\n"); + for (pn = 0; pn < nprops; pn++) { + e = nvlist_lookup_string(props[pn], INV_PNAME, &pnm); + if (e != 0) { + topo_mod_dprintf(mp, + "props create lookup (%s) failure: %s", + INV_PNAME, topo_strerror(e)); + return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP)); + } + e = nvlist_lookup_boolean_value(props[pn], INV_IMMUTE, &pim); + if (e != 0) { + topo_mod_dprintf(mp, + "props create lookup (%s) failure: %s", + INV_IMMUTE, topo_strerror(e)); + return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP)); + } + flag = (pim == B_TRUE) ? + TOPO_PROP_SET_ONCE : TOPO_PROP_SET_MULTIPLE; + + e = nvlist_lookup_int32(props[pn], INV_PVALTYPE, &i32); + if (e != 0) { + topo_mod_dprintf(mp, + "props create lookup (%s) failure: %s", + INV_PVALTYPE, topo_strerror(e)); + return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP)); + } + ptype = (topo_type_t)i32; + if (prop_create(mp, props[pn], ptn, gnm, pnm, ptype, flag) < 0) + return (-1); + } + return (0); +} + +static int +pgroups_create(topo_mod_t *mp, tf_pad_t *pad, tnode_t *ptn) +{ + topo_stability_t gs; + nvlist_t **props; + char *gnm; + uint32_t rnprops, nprops; + uint32_t ui32; + int pg; + int e; + + topo_mod_dprintf(mp, "pgroups create\n"); + for (pg = 0; pg < pad->tpad_pgcnt; pg++) { + e = nvlist_lookup_string(pad->tpad_pgs[pg], + INV_PGRP_NAME, &gnm); + if (e != 0) { + topo_mod_dprintf(mp, "pad lookup (%s) failed.\n", + INV_PGRP_NAME); + return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP)); + } + e = nvlist_lookup_uint32(pad->tpad_pgs[pg], + INV_PGRP_STAB, &ui32); + if (e != 0) { + topo_mod_dprintf(mp, "pad lookup (%s) failed.\n", + INV_PGRP_STAB); + return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP)); + } + gs = (topo_stability_t)ui32; + if (topo_pgroup_create(ptn, gnm, gs, &e) != 0) { + if (e != ETOPO_PROP_DEFD) { + topo_mod_dprintf(mp, + "pgroups create failure: %s\n", + topo_strerror(e)); + return (-1); + } + } + e = nvlist_lookup_uint32(pad->tpad_pgs[pg], + INV_PGRP_NPROP, &rnprops); + e |= nvlist_lookup_nvlist_array(pad->tpad_pgs[pg], + INV_PGRP_ALLPROPS, &props, &nprops); + if (rnprops != nprops) { + topo_mod_dprintf(mp, + "warning: recorded number of props %d does not " + "match number of props recorded %d.\n", + rnprops, nprops); + } + if (props_create(mp, ptn, gnm, props, nprops) < 0) + return (-1); + } + return (0); +} + +static nvlist_t * +pval_record(topo_mod_t *mp, xmlNodePtr xn) +{ + nvlist_t *pnvl = NULL; + xmlChar *pname; + + topo_mod_dprintf(mp, "pval record\n"); + if ((pname = xmlGetProp(xn, (xmlChar *)Name)) == NULL) { + topo_mod_dprintf(mp, "propval lacks a name\n"); + (void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR); + return (NULL); + } + if (topo_mod_nvalloc(mp, &pnvl, NV_UNIQUE_NAME) < 0) { + xmlFree(pname); + return (NULL); + } + if (nvlist_add_string(pnvl, INV_PNAME, (char *)pname) < 0) { + xmlFree(pname); + nvlist_free(pnvl); + return (NULL); + } + xmlFree(pname); + /* FMXXX stability of the property name */ + + if (xmlprop_xlate(mp, xn, pnvl) < 0) { + nvlist_free(pnvl); + return (NULL); + } + return (pnvl); +} + +static int +pgroup_record(topo_mod_t *mp, xmlNodePtr pxn, tf_pad_t *rpad, int pi) +{ + topo_stability_t nmstab; + xmlNodePtr sn = NULL; + xmlNodePtr cn; + xmlChar *name; + nvlist_t **apl = NULL; + nvlist_t *pgnvl = NULL; + int pcnt = 0; + int ai = 0; + int e; + + topo_mod_dprintf(mp, "pgroup record\n"); + if ((name = xmlGetProp(pxn, (xmlChar *)Name)) == NULL) { + topo_mod_dprintf(mp, "propgroup lacks a name\n"); + return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR)); + } + topo_mod_dprintf(mp, "pgroup %s\n", (char *)name); + for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) { + if (xmlStrcmp(cn->name, (xmlChar *)Propval) == 0) + pcnt++; + else if (xmlStrcmp(cn->name, (xmlChar *)Namestab) == 0) + sn = cn; + } + if (xmlattr_to_stab(mp, sn, &nmstab) < 0) { + xmlFree(name); + return (-1); + } + if (topo_mod_nvalloc(mp, &pgnvl, NV_UNIQUE_NAME) < 0) { + xmlFree(name); + return (-1); + } + + e = nvlist_add_string(pgnvl, INV_PGRP_NAME, (char *)name); + e |= nvlist_add_uint32(pgnvl, INV_PGRP_STAB, nmstab); + e |= nvlist_add_uint32(pgnvl, INV_PGRP_NPROP, pcnt); + if (e != 0 || + (apl = topo_mod_zalloc(mp, pcnt * sizeof (nvlist_t *))) == NULL) { + xmlFree(name); + nvlist_free(pgnvl); + return (-1); + } + for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) { + if (xmlStrcmp(cn->name, (xmlChar *)Propval) == 0) { + if (ai < pcnt) { + if ((apl[ai] = pval_record(mp, cn)) == NULL) + break; + } + ai++; + } + } + xmlFree(name); + e |= (ai != pcnt); + e |= nvlist_add_nvlist_array(pgnvl, INV_PGRP_ALLPROPS, apl, pcnt); + for (ai = 0; ai < pcnt; ai++) + if (apl[ai] != NULL) + nvlist_free(apl[ai]); + topo_mod_free(mp, apl, pcnt * sizeof (nvlist_t *)); + if (e != 0) { + nvlist_free(pgnvl); + return (-1); + } + rpad->tpad_pgs[pi] = pgnvl; + return (0); +} + +static int +pgroups_record(topo_mod_t *mp, xmlNodePtr pxn, tf_pad_t *rpad) +{ + xmlNodePtr cn; + int pi = 0; + + topo_mod_dprintf(mp, "pgroups record\n"); + for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) { + if (xmlStrcmp(cn->name, (xmlChar *)Propgrp) == 0) { + if (pgroup_record(mp, cn, rpad, pi++) < 0) + return (-1); + } + } + return (0); +} + +/* + * Process the property group and dependents xmlNode children of + * parent xmlNode pxn. + */ +static int +pad_process(topo_mod_t *mp, + tf_info_t *xinfo, xmlNodePtr pxn, tnode_t *ptn, tf_pad_t **rpad) +{ + xmlNodePtr cn; + int pgcnt = 0; + int dcnt = 0; + + topo_mod_dprintf(mp, "pad process beneath %s\n", topo_node_name(ptn)); + if (*rpad == NULL) { + for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) { + if (xmlStrcmp(cn->name, (xmlChar *)Dependents) == 0) + dcnt++; + else if (xmlStrcmp(cn->name, (xmlChar *)Propgrp) == 0) + pgcnt++; + } + if ((*rpad = tf_pad_new(mp, pgcnt, dcnt)) == NULL) + return (-1); + if (dcnt == 0 && pgcnt == 0) + return (0); + if (pgcnt > 0) { + (*rpad)->tpad_pgs = + topo_mod_zalloc(mp, pgcnt * sizeof (nvlist_t *)); + if ((*rpad)->tpad_pgs == NULL) { + tf_pad_free(mp, *rpad); + return (-1); + } + if (pgroups_record(mp, pxn, *rpad) < 0) { + tf_pad_free(mp, *rpad); + return (-1); + } + } + } + + if ((*rpad)->tpad_dcnt > 0) + if (dependents_create(mp, xinfo, *rpad, pxn, ptn) < 0) + return (-1); + + if ((*rpad)->tpad_pgcnt > 0) + if (pgroups_create(mp, *rpad, ptn) < 0) + return (-1); + return (0); +} + +static int +node_process(topo_mod_t *mp, xmlNodePtr nn, tf_rdata_t *rd) +{ + topo_instance_t inst; + tf_idata_t *newi; + tnode_t *ntn; + uint64_t ui; + int rv = -1; + + topo_mod_dprintf(mp, "node process %s\n", rd->rd_name); + if (xmlattr_to_int(mp, nn, Instance, &ui) < 0) + goto nodedone; + inst = (topo_instance_t)ui; + + if (topo_mod_enumerate(rd->rd_mod, + rd->rd_pn, rd->rd_finfo->tf_scheme, rd->rd_name, inst, inst) < 0) + goto nodedone; + ntn = topo_node_lookup(rd->rd_pn, rd->rd_name, inst); + if (ntn == NULL) + goto nodedone; + + if ((newi = tf_idata_new(mp, inst, ntn)) == NULL) { + topo_mod_dprintf(mp, "tf_idata_new failed.\n"); + goto nodedone; + } + if (tf_idata_insert(mp, &rd->rd_instances, newi) < 0) { + topo_mod_dprintf(mp, "tf_idata_insert failed.\n"); + goto nodedone; + } + if (pad_process(mp, rd->rd_finfo, nn, ntn, &newi->ti_pad) < 0) + goto nodedone; + rv = 0; +nodedone: + topo_mod_dprintf(mp, "done with node %s.\n", rd->rd_name); + return (rv); +} + +static tf_edata_t * +enum_attributes_process(topo_mod_t *mp, xmlNodePtr en) +{ + tf_edata_t *einfo; + uint64_t ui; + + topo_mod_dprintf(mp, "enum attributes process\n"); + if ((einfo = topo_mod_zalloc(mp, sizeof (tf_edata_t))) == NULL) { + (void) topo_mod_seterrno(mp, ETOPO_NOMEM); + return (NULL); + } + einfo->te_name = (char *)xmlGetProp(en, (xmlChar *)Name); + if (einfo->te_name == NULL) { + topo_mod_dprintf(mp, "Enumerator name attribute missing.\n"); + (void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR); + goto enodedone; + } + einfo->te_path = (char *)xmlGetProp(en, (xmlChar *)Path); + if (einfo->te_path == NULL) { + topo_mod_dprintf(mp, "Enumerator path attribute missing.\n"); + (void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR); + goto enodedone; + } + if (xmlattr_to_int(mp, en, Version, &ui) < 0) + goto enodedone; + einfo->te_vers = (int)ui; + /* + * FMXXX must deal with name-stability and apply-methods (which are + * child xmlNodes) + */ + return (einfo); + +enodedone: + if (einfo->te_name != NULL) + xmlFree(einfo->te_name); + if (einfo->te_path != NULL) + xmlFree(einfo->te_path); + return (NULL); +} + +static int +enum_run(topo_mod_t *mp, tf_rdata_t *rd) +{ + int e = -1; + + /* + * first see if the module is already loaded + */ + rd->rd_mod = topo_mod_lookup(mp->tm_hdl, rd->rd_einfo->te_name); + if (rd->rd_mod == NULL) { + char *mostpath = topo_mod_alloc(mp, PATH_MAX); + char *skip; + int prepend = 0; + + if (mostpath == NULL) + return (-1); + skip = rd->rd_einfo->te_path; + if (*skip == '%' && *(skip + 1) == 'r') { + prepend = 1; + skip += 2; + } + (void) snprintf(mostpath, + PATH_MAX, "%s%s/%s.so", + (prepend == 1) ? topo_mod_rootdir(mp) : "", + skip, rd->rd_einfo->te_name); + topo_mod_dprintf(mp, + "enum_run, load %s.\n", mostpath); + if ((rd->rd_mod = topo_mod_load(mp, mostpath)) == NULL) { + topo_mod_dprintf(mp, + "mod_load of %s failed: %s.\n", + mostpath, topo_strerror(topo_mod_errno(mp))); + topo_free(mostpath, PATH_MAX); + return (e); + } + topo_free(mostpath, PATH_MAX); + } + /* + * We're live, so let's enumerate. + */ + topo_mod_dprintf(mp, "enumerate request. (%s)\n", + rd->rd_einfo->te_name); + e = topo_mod_enumerate(rd->rd_mod, rd->rd_pn, rd->rd_einfo->te_name, + rd->rd_name, rd->rd_min, rd->rd_max); + topo_mod_dprintf(mp, "back from enumeration. %d\n", e); + if (e != 0) { + topo_mod_dprintf(mp, "Enumeration failed (%s)\n", + topo_strerror(topo_mod_errno(mp))); + return (topo_mod_seterrno(mp, EMOD_PARTIAL_ENUM)); + } + return (e); +} + +int +topo_xml_range_process(topo_mod_t *mp, xmlNodePtr rn, tf_rdata_t *rd) +{ + /* + * The range may have several children xmlNodes, that may + * represent the enumeration method, property groups, + * dependents or nodes. + */ + xmlNodePtr cn; + tnode_t *ct; + int e; + + topo_mod_dprintf(mp, "process %s range beneath %s\n", + rd->rd_name, topo_node_name(rd->rd_pn)); + e = topo_node_range_create(mp, + rd->rd_pn, rd->rd_name, rd->rd_min, rd->rd_max); + if (e != 0) { + topo_mod_dprintf(mp, "Range create failed due to %s.\n", + topo_strerror(topo_mod_errno(mp))); + return (-1); + } + for (cn = rn->xmlChildrenNode; cn != NULL; cn = cn->next) + if (xmlStrcmp(cn->name, (xmlChar *)Enum_meth) == 0) + break; + + if (cn != NULL) { + if ((rd->rd_einfo = enum_attributes_process(mp, cn)) == NULL) + return (-1); + if (enum_run(mp, rd) < 0) { + topo_mod_dprintf(mp, "Enumeration failed.\n"); + return (-1); + } + } + + /* Now look for nodes, i.e., hard instances */ + for (cn = rn->xmlChildrenNode; cn != NULL; cn = cn->next) { + if (xmlStrcmp(cn->name, (xmlChar *)Node) == 0) + if (node_process(mp, cn, rd) < 0) { + topo_mod_dprintf(mp, + "node processing failed: %s.\n", + topo_strerror(topo_mod_errno(mp))); + return (topo_mod_seterrno(mp, + EMOD_PARTIAL_ENUM)); + } + } + + /* Property groups and Dependencies */ + ct = topo_child_first(rd->rd_pn); + while (ct != NULL) { + /* Only care about instances within the range */ + if (strcmp(topo_node_name(ct), rd->rd_name) != 0) { + ct = topo_child_next(rd->rd_pn, ct); + continue; + } + if (pad_process(mp, rd->rd_finfo, rn, ct, &rd->rd_pad) < 0) + return (-1); + ct = topo_child_next(rd->rd_pn, ct); + } + topo_mod_dprintf(mp, "end range process %s\n", + rd->rd_name); + return (0); +} + +static tf_rdata_t * +topo_xml_walk(topo_mod_t *mp, + tf_info_t *xinfo, xmlNodePtr croot, tnode_t *troot) +{ + xmlNodePtr curr; + tf_rdata_t *rr, *pr, *rdp; + + /* + * What we're interested in are children xmlNodes of croot tagged + * as 'ranges', these define topology nodes may exist, and need + * to be verified. + */ + topo_mod_dprintf(mp, "topo_xml_walk\n"); + rr = pr = NULL; + for (curr = croot->xmlChildrenNode; curr != NULL; curr = curr->next) { + if (curr->name == NULL) { + topo_mod_dprintf(mp, "Ignoring nameless xmlnode.\n"); + continue; + } + if (xmlStrcmp(curr->name, (xmlChar *)Range) != 0) { + topo_mod_dprintf(mp, + "Ignoring non-range %s.\n", curr->name); + continue; + } + if ((rdp = tf_rdata_new(mp, xinfo, curr, troot)) == NULL) { + tf_rdata_free(mp, rr); + return (NULL); + } + if (pr == NULL) { + rr = pr = rdp; + } else { + pr->rd_next = rdp; + pr = rdp; + } + rr->rd_cnt++; + } + return (rr); +} + +/* + * Convert parsed xml topology description into topology nodes + */ +int +topo_xml_enum(topo_mod_t *tmp, tf_info_t *xinfo, tnode_t *troot) +{ + xmlNodePtr xroot; + + if ((xroot = xmlDocGetRootElement(xinfo->tf_xdoc)) == NULL) { + topo_mod_dprintf(tmp, "Couldn't get root xmlNode.\n"); + return (-1); + } + if ((xinfo->tf_rd = topo_xml_walk(tmp, xinfo, xroot, troot)) == NULL) { + topo_mod_dprintf(tmp, + "error within .xml topology: %s\n", + topo_strerror(topo_mod_errno(tmp))); + return (-1); + } + return (0); +} + +/* + * Load an XML tree from filename and read it into a DOM parse tree. + */ +static tf_info_t * +txml_file_parse(topo_mod_t *tmp, + int fd, const char *filenm, const char *escheme) +{ + xmlValidCtxtPtr vcp; + xmlNodePtr cursor; + xmlDocPtr document; + xmlDtdPtr dtd = NULL; + xmlChar *scheme = NULL; + char *dtdpath = NULL; + int readflags = 0; + tf_info_t *r; + int e; + + /* + * Since topologies can XInclude other topologies, and libxml2 + * doesn't do DTD-based validation with XInclude, by default + * we don't validate topology files. One can force + * validation, though, by creating a TOPOXML_VALIDATE + * environment variable and creating a TOPO_DTD environment + * variable with the path to the DTD against which to validate. + */ + if (getenv("TOPOXML_VALIDATE") != NULL) { + dtdpath = getenv("TOPO_DTD"); + if (dtdpath != NULL) + xmlLoadExtDtdDefaultValue = 0; + } + + /* + * Splat warnings and errors related to parsing the topology + * file if the TOPOXML_PERROR environment variable exists. + */ + if (getenv("TOPOXML_PERROR") == NULL) + readflags = XML_PARSE_NOERROR | XML_PARSE_NOWARNING; + + if ((document = xmlReadFd(fd, filenm, NULL, readflags)) == NULL) { + topo_mod_dprintf(tmp, "couldn't parse document.\n"); + return (NULL); + } + + /* + * Verify that this is a document type we understand. + */ + if ((dtd = xmlGetIntSubset(document)) == NULL) { + topo_mod_dprintf(tmp, "document has no DTD.\n"); + return (NULL); + } + + if (strcmp((const char *)dtd->SystemID, TOPO_DTD_PATH) == -1) { + topo_mod_dprintf(tmp, + "document DTD unknown; bad topology file?\n"); + return (NULL); + } + + if ((cursor = xmlDocGetRootElement(document)) == NULL) { + topo_mod_dprintf(tmp, "document is empty.\n"); + xmlFreeDoc(document); + return (NULL); + } + + /* + * Make sure we're looking at a topology description in the + * expected scheme. + */ + if (xmlStrcmp(cursor->name, (xmlChar *)Topology) != 0) { + topo_mod_dprintf(tmp, + "document is not a topology description.\n"); + xmlFreeDoc(document); + return (NULL); + } + if ((scheme = xmlGetProp(cursor, (xmlChar *)Scheme)) == NULL) { + topo_mod_dprintf(tmp, "topology lacks a scheme.\n"); + (void) topo_mod_seterrno(tmp, ETOPO_PRSR_NOATTR); + xmlFreeDoc(document); + return (NULL); + } + if (xmlStrcmp(scheme, (xmlChar *)escheme) != 0) { + topo_mod_dprintf(tmp, + "topology in unrecognized scheme, %s, expecting %s\n", + scheme, escheme); + (void) topo_mod_seterrno(tmp, ETOPO_PRSR_BADSCH); + xmlFree(scheme); + xmlFreeDoc(document); + return (NULL); + } + + if (dtdpath != NULL) { + dtd = xmlParseDTD(NULL, (xmlChar *)dtdpath); + if (dtd == NULL) { + topo_mod_dprintf(tmp, + "Could not parse DTD \"%s\".\n", + dtdpath); + return (NULL); + } + + if (document->extSubset != NULL) + xmlFreeDtd(document->extSubset); + + document->extSubset = dtd; + } + + if (xmlXIncludeProcessFlags(document, XML_PARSE_XINCLUDE) == -1) {; + topo_mod_dprintf(tmp, + "couldn't handle XInclude statements in document\n"); + return (NULL); + } + + if ((vcp = xmlNewValidCtxt()) == NULL) { + xmlFree(scheme); + scheme = NULL; + return (NULL); + } + vcp->warning = xmlParserValidityWarning; + vcp->error = xmlParserValidityError; + + e = xmlValidateDocument(vcp, document); + + xmlFreeValidCtxt(vcp); + + if (e == 0) { + topo_mod_dprintf(tmp, "Document is not valid.\n"); + xmlFreeDoc(document); + return (NULL); + } + + if ((r = tf_info_new(tmp, filenm, document, scheme)) == NULL) + return (NULL); + + /* txml_dump(0, cursor); */ + + xmlFree(scheme); + scheme = NULL; + return (r); +} + +static int +txml_file_open(topo_mod_t *mp, const char *filename) +{ + int rfd; + if ((rfd = open(filename, O_RDONLY)) < 0) + return (topo_mod_seterrno(mp, ETOPO_PRSR_NOENT)); + return (rfd); +} + +tf_info_t * +topo_xml_read(topo_mod_t *tmp, const char *path, const char *escheme) +{ + int fd; + tf_info_t *tip; + + if ((fd = txml_file_open(tmp, path)) < 0) { + return (NULL); + } + tip = txml_file_parse(tmp, fd, path, escheme); + (void) close(fd); + return (tip); +} diff --git a/usr/src/lib/fm/libtopo/i386/Makefile b/usr/src/lib/fm/topo/libtopo/i386/Makefile index 905c136359..c4b1489ab7 100644 --- a/usr/src/lib/fm/libtopo/i386/Makefile +++ b/usr/src/lib/fm/topo/libtopo/i386/Makefile @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" diff --git a/usr/src/lib/fm/libtopo/sparc/Makefile b/usr/src/lib/fm/topo/libtopo/sparc/Makefile index 65682c4299..a925bc82f9 100644 --- a/usr/src/lib/fm/libtopo/sparc/Makefile +++ b/usr/src/lib/fm/topo/libtopo/sparc/Makefile @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" diff --git a/usr/src/lib/fm/topo/libtopo/sparcv9/Makefile b/usr/src/lib/fm/topo/libtopo/sparcv9/Makefile new file mode 100644 index 0000000000..3e287aef61 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/sparcv9/Makefile @@ -0,0 +1,32 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +MAPDIR = ../spec/sparcv9 +include ../Makefile.com +include ../../../../Makefile.lib.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64) diff --git a/usr/src/lib/fm/libtopo/spec/Makefile b/usr/src/lib/fm/topo/libtopo/spec/Makefile index babb709ad7..1208d7a09f 100644 --- a/usr/src/lib/fm/libtopo/spec/Makefile +++ b/usr/src/lib/fm/topo/libtopo/spec/Makefile @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" diff --git a/usr/src/lib/fm/libtopo/spec/Makefile.targ b/usr/src/lib/fm/topo/libtopo/spec/Makefile.targ index 50e80a5d55..e1102bd53f 100644 --- a/usr/src/lib/fm/libtopo/spec/Makefile.targ +++ b/usr/src/lib/fm/topo/libtopo/spec/Makefile.targ @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" diff --git a/usr/src/lib/fm/libtopo/spec/amd64/Makefile b/usr/src/lib/fm/topo/libtopo/spec/amd64/Makefile index 2445e1779f..a04ea5eb47 100644 --- a/usr/src/lib/fm/libtopo/spec/amd64/Makefile +++ b/usr/src/lib/fm/topo/libtopo/spec/amd64/Makefile @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -31,7 +31,6 @@ DISABLE_APPTRACE= $(POUND_SIGN) include ../Makefile.targ include $(SRC)/lib/Makefile.lib include $(SRC)/lib/Makefile.lib.64 - include $(SRC)/lib/Makefile.spec $(DISABLE_APPTRACE)install: $(ROOTABILIB64) diff --git a/usr/src/lib/fm/libtopo/spec/i386/Makefile b/usr/src/lib/fm/topo/libtopo/spec/i386/Makefile index 684c03a198..afd97ec009 100644 --- a/usr/src/lib/fm/libtopo/spec/i386/Makefile +++ b/usr/src/lib/fm/topo/libtopo/spec/i386/Makefile @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" diff --git a/usr/src/lib/fm/libtopo/spec/sparc/Makefile b/usr/src/lib/fm/topo/libtopo/spec/sparc/Makefile index 281960b060..afd97ec009 100644 --- a/usr/src/lib/fm/libtopo/spec/sparc/Makefile +++ b/usr/src/lib/fm/topo/libtopo/spec/sparc/Makefile @@ -20,13 +20,13 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" # To enable apptrace, comment out the next line -DISABLE_APPTRACE= $(POUND_SIGN) +DISABLE_APPTRACE= $(POUND_SIGN) include ../Makefile.targ include $(SRC)/lib/Makefile.lib diff --git a/usr/src/lib/fm/libtopo/spec/sparcv9/Makefile b/usr/src/lib/fm/topo/libtopo/spec/sparcv9/Makefile index 9f9cb6ace4..a04ea5eb47 100644 --- a/usr/src/lib/fm/libtopo/spec/sparcv9/Makefile +++ b/usr/src/lib/fm/topo/libtopo/spec/sparcv9/Makefile @@ -20,13 +20,13 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" # To enable apptrace, comment out the next line -DISABLE_APPTRACE= $(POUND_SIGN) +DISABLE_APPTRACE= $(POUND_SIGN) include ../Makefile.targ include $(SRC)/lib/Makefile.lib diff --git a/usr/src/lib/fm/topo/libtopo/spec/topo.spec b/usr/src/lib/fm/topo/libtopo/spec/topo.spec new file mode 100644 index 0000000000..3954952908 --- /dev/null +++ b/usr/src/lib/fm/topo/libtopo/spec/topo.spec @@ -0,0 +1,377 @@ +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# ident "%Z%%M% %I% %E% SMI" + +function topo_open +version SUNWprivate +end + +function topo_close +version SUNWprivate +end + +function topo_snap_hold +version SUNWprivate +end + +function topo_snap_release +version SUNWprivate +end + +function topo_node_name +version SUNWprivate +end + +function topo_node_instance +version SUNWprivate +end + +function topo_node_private +version SUNWprivate +end + +function topo_hdl_errno +version SUNWprivate +end + +function topo_strerror +version SUNWprivate +end + +function topo_hdl_errmsg +version SUNWprivate +end + +function topo_hdl_alloc +version SUNWprivate +end + +function topo_hdl_zalloc +version SUNWprivate +end + +function topo_hdl_free +version SUNWprivate +end + +function topo_hdl_nvalloc +version SUNWprivate +end + +function topo_hdl_nvdup +version SUNWprivate +end + +function topo_hdl_strdup +version SUNWprivate +end + +function topo_hdl_strfree +version SUNWprivate +end + +function topo_walk_init +version SUNWprivate +end + +function topo_walk_step +version SUNWprivate +end + +function topo_walk_fini +version SUNWprivate +end + +function topo_debug_set +version SUNWprivate +end + +function topo_pgroup_create +version SUNWprivate +end + +function topo_pgroup_destroy +version SUNWprivate +end + +function topo_prop_get_int32 +version SUNWprivate +end + +function topo_prop_get_uint32 +version SUNWprivate +end + +function topo_prop_get_int64 +version SUNWprivate +end + +function topo_prop_get_uint64 +version SUNWprivate +end + +function topo_prop_get_string +version SUNWprivate +end + +function topo_prop_get_fmri +version SUNWprivate +end + +function topo_prop_get_all +version SUNWprivate +end + +function topo_prop_set_int32 +version SUNWprivate +end + +function topo_prop_set_uint32 +version SUNWprivate +end + +function topo_prop_set_int64 +version SUNWprivate +end + +function topo_prop_set_uint64 +version SUNWprivate +end + +function topo_prop_set_string +version SUNWprivate +end + +function topo_prop_set_fmri +version SUNWprivate +end + +function topo_prop_inherit +version SUNWprivate +end + +function topo_prop_stability +version SUNWprivate +end + +function topo_node_resource +version SUNWprivate +end + +function topo_node_asru +version SUNWprivate +end + +function topo_node_fru +version SUNWprivate +end + +function topo_node_label +version SUNWprivate +end + +function topo_node_fru_set +version SUNWprivate +end + +function topo_node_asru_set +version SUNWprivate +end + +function topo_node_label_set +version SUNWprivate +end + +function topo_node_range_create +version SUNWprivate +end + +function topo_node_range_destroy +version SUNWprivate +end + +function topo_node_bind +version SUNWprivate +end + +function topo_node_unbind +version SUNWprivate +end + +function topo_node_name +version SUNWprivate +end + +function topo_node_private +version SUNWprivate +end + +function topo_node_instance +version SUNWprivate +end + +function topo_mod_alloc +version SUNWprivate +end + +function topo_mod_zalloc +version SUNWprivate +end + +function topo_mod_free +version SUNWprivate +end + +function topo_mod_nvalloc +version SUNWprivate +end + +function topo_mod_nvdup +version SUNWprivate +end + +function topo_mod_strfree +version SUNWprivate +end + +function topo_mod_strdup +version SUNWprivate +end + +function topo_fmri_present +version SUNWprivate +end + +function topo_fmri_contains +version SUNWprivate +end + +function topo_fmri_create +version SUNWprivate +end + +function topo_fmri_unusable +version SUNWprivate +end + +function topo_fmri_nvl2str +version SUNWprivate +end + +function topo_fmri_str2nvl +version SUNWprivate +end + +function topo_fmri_expand +version SUNWprivate +end + +function topo_fmri_asru +version SUNWprivate +end + +function topo_fmri_fru +version SUNWprivate +end + +function topo_fmri_compare +version SUNWprivate +end + +function topo_fmri_invoke +version SUNWprivate +end + +function topo_mod_clrdebug +version SUNWprivate +end + +function topo_mod_setdebug +version SUNWprivate +end + +function topo_mod_seterrno +version SUNWprivate +end + +function topo_mod_dprintf +version SUNWprivate +end + +function topo_mod_errmsg +version SUNWprivate +end + +function topo_mod_errno +version SUNWprivate +end + +function topo_mod_load +version SUNWprivate +end + +function topo_mod_unload +version SUNWprivate +end + +function topo_mod_register +version SUNWprivate +end + +function topo_mod_unregister +version SUNWprivate +end + +function topo_mod_enumerate +version SUNWprivate +end + +function topo_method_invoke +version SUNWprivate +end + +function topo_method_register +version SUNWprivate +end + +function topo_method_unregister +version SUNWprivate +end + +function topo_method_unregister_all +version SUNWprivate +end + +function topo_mod_rootdir +version SUNWprivate +end + +function topo_mod_private +version SUNWprivate +end + +function topo_mod_handle +version SUNWprivate +end + diff --git a/usr/src/lib/fm/libtopo/spec/versions b/usr/src/lib/fm/topo/libtopo/spec/versions index de52db1857..7a65542162 100644 --- a/usr/src/lib/fm/libtopo/spec/versions +++ b/usr/src/lib/fm/topo/libtopo/spec/versions @@ -1,5 +1,5 @@ # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # CDDL HEADER START diff --git a/usr/src/cmd/fm/schemes/mem/Makefile.targ b/usr/src/lib/fm/topo/modules/Makefile index 9a6d4cc380..97ab5867d8 100644 --- a/usr/src/cmd/fm/schemes/mem/Makefile.targ +++ b/usr/src/lib/fm/topo/modules/Makefile @@ -24,13 +24,10 @@ # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" -# -include ../../Makefile.targ +sparc_SUBDIRS = sun4u sun4v SUNW,Sun-Fire SUNW,Sun-Fire-15000 +i386_SUBDIRS = i86pc -%.o: $(SCHEME_COMMON)/%.c - $(COMPILE.c) -o $@ $< - $(CTFCONVERT_O) +SUBDIRS = $($(MACH)_SUBDIRS) -%.ln: $(SCHEME_COMMON)/%.c - $(LINT.c) -erroff=E_BAD_PTR_CAST_ALIGN -v -c $< +include ../../Makefile.subdirs diff --git a/usr/src/cmd/fm/topo/plugins/Makefile.plugin b/usr/src/lib/fm/topo/modules/Makefile.plugin index c0db88713a..e711bbd58d 100644 --- a/usr/src/cmd/fm/topo/plugins/Makefile.plugin +++ b/usr/src/lib/fm/topo/modules/Makefile.plugin @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -19,64 +18,82 @@ # # CDDL HEADER END # + # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -#ident "%Z%%M% %I% %E% SMI" +# ident "%Z%%M% %I% %E% SMI" .KEEP_STATE: .SUFFIXES: -include ../../../../../Makefile.cmd +MODCLASS = plugins + +include ../../../../Makefile.lib +include ../../../../../Makefile.lib # # Set PROG and OBJS based on the values of MODULE and SRCS. We expect that # these macros to be defined by the Makefile that is including this file. # +SRCS = $(MODULESRCS:%.c=%.c) PROG = $(MODULE:%=%.so) -TOPO = $(MODULE:%=%.topo) -YOBJS = $(YSRCS:%.y=%.o) -OBJS = $(YOBJS) $(SRCS:%.c=%.o) +OBJS = $(SRCS:%.c=%.o) # -# Set ROOTPROG and ROOTTOPO based on the values of MODULE, CLASS, and PLATFORMS +# Set ROOTPROG and ROOTCONF based on the values of MODULE, CLASS, and PLATFORMS # We expect these macros to be defined by the Makefile that is including us. # -common_TOPODIR = $(ROOT)/usr/lib/fm/topo -arch_TOPODIR = $(ROOT)/usr/lib/fm/topo/$(ARCH) -ROOT_TOPO_DIR = $($(CLASS)_TOPODIR) +common_ROOTPROG = $(ROOT)/usr/lib/fm/topo/plugins/$(PROG) +arch_ROOTPROG = $(ROOT)/usr/platform/$(ARCH)/lib/fm/topo/plugins/$(PROG) +plat_ROOTPROG = $(PLATFORMS:%=$(ROOT)/usr/platform/%/lib/fm/topo/plugins/$(PROG)) +ROOTPROG = $($(CLASS)_ROOTPROG) -ROOTPROG = $(ROOT_TOPO_DIR)/$(PROG) -ROOTTOPO = $(ROOT_TOPO_DIR)/$(TOPO) +common_ROOTCONF = $(ROOT)/usr/lib/fm/topo/plugins/$(CONF) +arch_ROOTCONF = $(ROOT)/usr/platform/$(ARCH)/lib/fm/topo/plugins/$(CONF) +plat_ROOTCONF = $(PLATFORMS:%=$(ROOT)/usr/platform/%/lib/fm/topo/plugins/$(CONF)) +ROOTCONF = $($(CLASS)_ROOTCONF) LINTFLAGS += -mu LINTFILES = $(SRCS:%.c=%.ln) -LINTLDLIBS += -L$(ROOTLIB)/fm -ltopo -CFLAGS += $(CTF_FLAGS) $(CCVERBOSE) -xstrconst -K pic -G $(XREGSFLAG) + +APIMAP = ../../../libtopo/common/topo_mod.map + +CFLAGS += $(CTF_FLAGS) $(CCVERBOSE) $(XSTRCONST) $(CC_PICFLAGS) +CFLAGS += -G $(XREGSFLAG) + +CPPFLAGS += -I. -I../../common -I../../../libtopo/common CPPFLAGS += -D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT -LDFLAGS += -z text -z combreloc -z defs -z ignore -R/usr/lib/fm -LDLIBS += -L$(ROOTLIB)/fm -ltopo -lc +LDFLAGS += $(ZIGNORE) -M$(APIMAP) +LDLIBS += -L$(ROOTLIBDIR)/fm -R/usr/lib/fm -ltopo -lnvpair -lc all: $(PROG) .NO_PARALLEL: .PARALLEL: $(OBJS) $(LINTFILES) -$(PROG): $(OBJS) - $(LINK.c) $(OBJS) -o $@ $(LDLIBS) +$(PROG): $(OBJS) $(APIMAP) + $(LINK.c) $(DYNFLAGS) $(OBJS) -o $@ $(LDLIBS) $(CTFMERGE) -L VERSION -o $@ $(OBJS) $(POST_PROCESS_SO) +%.o: ../../common/%.c + $(COMPILE.c) $< + $(CTFCONVERT_O) + %.o: %.c $(COMPILE.c) $< $(CTFCONVERT_O) clean: - $(RM) $(OBJS) $(LINTFILES) + $(RM) $(OBJS) $(LINTFILES) $(CLEANFILES) clobber: clean - $(RM) $(PROG) $(ROOTTOPO) $(ROOTPROG) + $(RM) $(PROG) + +%.ln: ../../common/%.c + $(LINT.c) -c $< %.ln: %.c $(LINT.c) -c $< @@ -84,14 +101,13 @@ clobber: clean lint: $(LINTFILES) $(LINT) $(LINTFLAGS) $(LINTFILES) $(LDLIBS) +check: $(CHECKHDRS) + install_h: $(ROOTPROG): $$(@D) $(PROG) $(RM) $@; $(INS) -s -m 0555 -f $(@D) $(PROG) -$(ROOTTOPO): $$(@D) $(TOPO) - $(RM) $@; $(INS) -s -m 0444 -f $(@D) $(TOPO) - -install: $(ROOTTOPO) $(ROOTPROG) +install: $(ROOTPROG) include ../../../Makefile.rootdirs diff --git a/usr/src/lib/fm/topo/modules/SUNW,Sun-Fire-15000/Makefile b/usr/src/lib/fm/topo/modules/SUNW,Sun-Fire-15000/Makefile new file mode 100644 index 0000000000..122db7a134 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/SUNW,Sun-Fire-15000/Makefile @@ -0,0 +1,32 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" + +SUBDIRS = ioboard + +.PARALLEL: $(SUBDIRS) + +include ../../../Makefile.subdirs diff --git a/usr/src/lib/fm/topo/modules/SUNW,Sun-Fire-15000/ioboard/Makefile b/usr/src/lib/fm/topo/modules/SUNW,Sun-Fire-15000/ioboard/Makefile new file mode 100644 index 0000000000..4440050a4a --- /dev/null +++ b/usr/src/lib/fm/topo/modules/SUNW,Sun-Fire-15000/ioboard/Makefile @@ -0,0 +1,30 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" + +PLATFORMS = SUNW,Sun-Fire-15000 + +include ../../sun4/ioboard/Makefile.iob diff --git a/usr/src/lib/fm/topo/modules/SUNW,Sun-Fire-15000/ioboard/iob_platform.c b/usr/src/lib/fm/topo/modules/SUNW,Sun-Fire-15000/ioboard/iob_platform.c new file mode 100644 index 0000000000..d12c46c19f --- /dev/null +++ b/usr/src/lib/fm/topo/modules/SUNW,Sun-Fire-15000/ioboard/iob_platform.c @@ -0,0 +1,144 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL IOB_SUNFIRE in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL IOB_SUNFIRE, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * SUNW,Sun-Fire platform ioboard topology enumerator + */ + +#include <string.h> +#include <libdevinfo.h> +#include <fm/topo_mod.h> + +#include "did.h" +#include "hostbridge.h" +#include "ioboard.h" +#include "util.h" + +extern did_hash_t *Didhash; + +/*ARGSUSED*/ +int +platform_iob_label(tnode_t *node, nvlist_t *ignored, nvlist_t **out) +{ + /* + * For E15K, the label is simply IOXX where XX is the + * instance number of the ioboard. + */ + char buf[10]; /* up to a million I/O boards :-) */ + + *out = NULL; + (void) snprintf(buf, 10, "IO%d", topo_node_instance(node)); + if (topo_mod_nvalloc(IobHdl, out, NV_UNIQUE_NAME) == 0 && + nvlist_add_string(*out, TOPO_METH_LABEL_RET_STR, buf) == 0) + return (0); + nvlist_free(*out); + *out = NULL; + return (-1); +} + +#define IOB_BASEADDR 0x1c +#define BUS_ADDRDIST 0x20 + +/*ARGSUSED*/ +int +platform_iob_enum(tnode_t *parent, topo_instance_t imin, topo_instance_t imax) +{ + /* + * An E15K and its successors may have up to 18 I/O boards, + * numbered 0 through 17. Each board has two hostbridges, and + * there are a pair of PCI buses under each hostbridge. We can + * discover the existence of a board by the presence of + * devinfo nodes for those hostbridges. We let the hostbridge + * enumerator actually create nodes for the hostbridges, + * passing them the did_t's for all the hostbridge nodes we + * know indicate that the ioboard exists. + */ + di_node_t devtree; + di_node_t pnode; + did_t *iobs[18][2][2]; + int brd, br, bus, i; + + devtree = di_init("/", DINFOCPYALL); + if (devtree == DI_NODE_NIL) { + topo_mod_dprintf(IobHdl, "devinfo init failed."); + return (-1); + } + + for (i = 0; i < 18; i++) { + iobs[i][0][0] = iobs[i][0][1] = NULL; + iobs[i][1][0] = iobs[i][1][1] = NULL; + } + + pnode = di_drv_first_node(SCHIZO, devtree); + while (pnode != DI_NODE_NIL) { + did_t *d; + + d = split_bus_address(Didhash, + pnode, IOB_BASEADDR, BUS_ADDRDIST, 0, 17, &brd, &br, &bus); + if (d == NULL) { + pnode = di_drv_next_node(pnode); + continue; + } + iobs[brd][br][bus] = d; + pnode = di_drv_next_node(pnode); + } + + for (i = 0; i < 18; i++) { + tnode_t *ion; + /* + * Make sure we found all the buses and bridges + */ + if (iobs[i][0][0] == NULL || iobs[i][0][1] == NULL || + iobs[i][1][0] == NULL || iobs[i][1][1] == NULL) + continue; + did_did_link_set(iobs[i][0][0], iobs[i][0][1]); + did_did_link_set(iobs[i][1][0], iobs[i][1][1]); + did_did_chain_set(iobs[i][0][0], iobs[i][1][0]); + if ((ion = ioboard_declare(parent, i, iobs[i][0][0])) == NULL) { + topo_mod_dprintf(IobHdl, + "Creation of tnode for %s%d failed.\n", IOBOARD, i); + continue; + } + if (topo_mod_enumerate(IobHdl, + ion, HOSTBRIDGE, HOSTBRIDGE, 0, 0) < 0) { + topo_mod_dprintf(IobHdl, + "Enumeration of %s%d/%s%d failed.\n", + IOBOARD, i, HOSTBRIDGE, 0); + continue; + } + if (topo_mod_enumerate(IobHdl, + ion, HOSTBRIDGE, HOSTBRIDGE, 1, 1) < 0) { + topo_mod_dprintf(IobHdl, + "Enumeration of %s%d/%s%d failed.\n", + IOBOARD, i, HOSTBRIDGE, 1); + continue; + } + } + di_fini(devtree); + return (0); +} diff --git a/usr/src/lib/fm/topo/modules/SUNW,Sun-Fire/Makefile b/usr/src/lib/fm/topo/modules/SUNW,Sun-Fire/Makefile new file mode 100644 index 0000000000..122db7a134 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/SUNW,Sun-Fire/Makefile @@ -0,0 +1,32 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" + +SUBDIRS = ioboard + +.PARALLEL: $(SUBDIRS) + +include ../../../Makefile.subdirs diff --git a/usr/src/lib/fm/topo/modules/SUNW,Sun-Fire/ioboard/Makefile b/usr/src/lib/fm/topo/modules/SUNW,Sun-Fire/ioboard/Makefile new file mode 100644 index 0000000000..f71e7188b6 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/SUNW,Sun-Fire/ioboard/Makefile @@ -0,0 +1,30 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" + +PLATFORMS = SUNW,Sun-Fire + +include ../../sun4/ioboard/Makefile.iob diff --git a/usr/src/lib/fm/topo/modules/SUNW,Sun-Fire/ioboard/iob_platform.c b/usr/src/lib/fm/topo/modules/SUNW,Sun-Fire/ioboard/iob_platform.c new file mode 100644 index 0000000000..03627bac8a --- /dev/null +++ b/usr/src/lib/fm/topo/modules/SUNW,Sun-Fire/ioboard/iob_platform.c @@ -0,0 +1,144 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL IOB_SUNFIRE in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL IOB_SUNFIRE, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * SUNW,Sun-Fire platform ioboard topology enumerator + */ + +#include <string.h> +#include <libdevinfo.h> +#include <fm/topo_mod.h> + +#include "did.h" +#include "hostbridge.h" +#include "ioboard.h" +#include "util.h" + +extern did_hash_t *Didhash; + +/*ARGSUSED*/ +int +platform_iob_label(tnode_t *node, nvlist_t *ignored, nvlist_t **out) +{ + /* + * For SUNW,Sun-Fire the label is simply N0.IBXX where XX is the + * instance number of the ioboard. + */ + char buf[13]; /* up to a million I/O boards :-) */ + + *out = NULL; + (void) snprintf(buf, 10, "N0.IB%d", topo_node_instance(node)); + if (topo_mod_nvalloc(IobHdl, out, NV_UNIQUE_NAME) == 0 && + nvlist_add_string(*out, TOPO_METH_LABEL_RET_STR, buf) == 0) + return (0); + nvlist_free(*out); + *out = NULL; + return (-1); +} + +#define IOB_BASEADDR 0x18 +#define BUS_ADDRDIST 0x2 + +/*ARGSUSED*/ +int +platform_iob_enum(tnode_t *parent, topo_instance_t imin, topo_instance_t imax) +{ + /* + * A SUNW,Sun-Fire and its successors may have up to 4 I/O boards, + * numbered 6 through 9. Each board has two hostbridges, and + * there are a pair of PCI buses under each hostbridge. We can + * discover the existence of a board by the presence of + * devinfo nodes for those hostbridges. We let the hostbridge + * enumerator actually create nodes for the hostbridges, + * passing them the did_t's for all the hostbridge nodes we + * know indicate that the ioboard exists. + */ + di_node_t devtree; + di_node_t pnode; + did_t *iobs[18][2][2]; + int brd, br, bus, i; + + devtree = di_init("/", DINFOCPYALL); + if (devtree == DI_NODE_NIL) { + topo_mod_dprintf(IobHdl, "devinfo init failed."); + return (-1); + } + + for (i = 6; i <= 9; i++) { + iobs[i][0][0] = iobs[i][0][1] = NULL; + iobs[i][1][0] = iobs[i][1][1] = NULL; + } + + pnode = di_drv_first_node(SCHIZO, devtree); + while (pnode != DI_NODE_NIL) { + did_t *d; + + d = split_bus_address(Didhash, + pnode, IOB_BASEADDR, BUS_ADDRDIST, 6, 9, &brd, &br, &bus); + if (d == NULL) { + pnode = di_drv_next_node(pnode); + continue; + } + iobs[brd][br][bus] = d; + pnode = di_drv_next_node(pnode); + } + + for (i = 6; i < 9; i++) { + tnode_t *ion; + /* + * Make sure we found all the buses and bridges + */ + if (iobs[i][0][0] == NULL || iobs[i][0][1] == NULL || + iobs[i][1][0] == NULL || iobs[i][1][1] == NULL) + continue; + did_did_link_set(iobs[i][0][0], iobs[i][0][1]); + did_did_link_set(iobs[i][1][0], iobs[i][1][1]); + did_did_chain_set(iobs[i][0][0], iobs[i][1][0]); + if ((ion = ioboard_declare(parent, i, iobs[i][0][0])) == NULL) { + topo_mod_dprintf(IobHdl, + "Creation of tnode for %s%d failed.\n", IOBOARD, i); + continue; + } + if (topo_mod_enumerate(IobHdl, + ion, HOSTBRIDGE, HOSTBRIDGE, 0, 0) < 0) { + topo_mod_dprintf(IobHdl, + "Enumeration of %s%d/%s%d failed.\n", + IOBOARD, i, HOSTBRIDGE, 0); + continue; + } + if (topo_mod_enumerate(IobHdl, + ion, HOSTBRIDGE, HOSTBRIDGE, 1, 1) < 0) { + topo_mod_dprintf(IobHdl, + "Enumeration of %s%d/%s%d failed.\n", + IOBOARD, i, HOSTBRIDGE, 1); + continue; + } + } + di_fini(devtree); + return (0); +} diff --git a/usr/src/lib/fm/topo/modules/common/did.c b/usr/src/lib/fm/topo/modules/common/did.c new file mode 100644 index 0000000000..25d4d17e27 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/common/did.c @@ -0,0 +1,530 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * did.c + * The acronym did means "Dev-Info-Data". Many properties and + * characteristics of topology nodes are, with a bit of coaxing + * derived from devinfo nodes. These routines do some of the + * derivation and also encapsulate the discoveries in did_t + * structures that get associated with topology nodes as their + * "private" data. + */ +#include <alloca.h> +#include <assert.h> +#include <string.h> +#include <strings.h> +#include <sys/types.h> +#include <libtopo.h> +#include <libnvpair.h> +#include <libdevinfo.h> +#include <sys/pcie.h> + +#include "topo_mod.h" +#include "hostbridge.h" +#include "pcibus.h" +#include "did_impl.h" +#include "did_props.h" + +static void slotnm_destroy(slotnm_t *); + +static slotnm_t * +slotnm_create(topo_mod_t *mp, int dev, char *str) +{ + slotnm_t *p; + + if ((p = topo_mod_alloc(mp, sizeof (slotnm_t))) == NULL) + return (NULL); + p->snm_mod = mp; + p->snm_next = NULL; + p->snm_dev = dev; + p->snm_label = topo_mod_strdup(mp, str); + if (p->snm_label == NULL) { + slotnm_destroy(p); + return (NULL); + } + return (p); +} + +static void +slotnm_destroy(slotnm_t *p) +{ + if (p == NULL) + return; + slotnm_destroy(p->snm_next); + if (p->snm_label != NULL) + topo_mod_strfree(p->snm_mod, p->snm_label); + topo_mod_free(p->snm_mod, p, sizeof (slotnm_t)); +} + +static int +slotnm_cp(did_t *from, did_t *to, int *nslots) +{ + slotnm_t *nxt, *new; + slotnm_t *last = NULL; + + *nslots = 0; + for (nxt = from->dp_slotnames; nxt != NULL; nxt = nxt->snm_next) { + new = slotnm_create(to->dp_mod, nxt->snm_dev, nxt->snm_label); + if (new == NULL) { + if (to->dp_slotnames != NULL) + slotnm_destroy(to->dp_slotnames); + to->dp_slotnames = NULL; + *nslots = 0; + return (-1); + } + if (last == NULL) { + to->dp_slotnames = last = new; + } else { + last->snm_next = new; + last = new; + } + (*nslots)++; + } + if (*nslots > 0) + topo_mod_dprintf(to->dp_mod, + "%p inherits %d slot label(s) from %p.\n", + to, *nslots, from); + return (0); +} + +static int +di_physlotinfo_get(topo_mod_t *mp, di_node_t src, uint_t excap, + int *slotnum, char **slotnm) +{ + char *slotbuf; + + *slotnum = -1; + (void) di_uintprop_get(src, DI_PHYSPROP, (uint_t *)slotnum); + /* + * If no physical slot number property was found, then the + * capabilities register may indicate the pci-express device + * implements a slot, and we should record which slot. + */ + if (*slotnum == -1 && (excap & PCIE_PCIECAP_SLOT_IMPL) != 0) { + uint_t slotcap; + int e; + e = di_uintprop_get(src, SAVED_PCIEX_SLOTCAP_REG, &slotcap); + if (e == 0) + *slotnum = slotcap >> PCIE_SLOTCAP_PHY_SLOT_NUM_SHIFT; + } + if (*slotnum == -1) + return (0); + + /* + * Make generic description string "SLOT <num>", allow up 10 + * digits for number + */ + slotbuf = alloca(16); + (void) snprintf(slotbuf, 16, "SLOT %d", *slotnum); + + if ((*slotnm = topo_mod_strdup(mp, slotbuf)) == NULL) + return (-1); + + return (0); +} + +static int +di_slotinfo_get(topo_mod_t *mp, di_node_t src, int *nslots, slotnm_t **slots) +{ + slotnm_t *lastslot = NULL; + slotnm_t *newslot; + uchar_t *slotbuf; + uint_t slotmap = 0; + char *slotname; + int andbit; + int sz = -1; + + *slots = NULL; + *nslots = 0; + if (di_bytes_get(src, DI_SLOTPROP, &sz, &slotbuf) < 0) + return (0); + if (sz < sizeof (uint_t)) + return (0); + bcopy(slotbuf, &slotmap, sizeof (uint_t)); + if (slotmap == 0) + return (0); + + slotname = (char *)&slotbuf[4]; + for (andbit = 0; andbit < 32; andbit++) { + if (slotmap & (1 << andbit)) { + char *s = slotname; + slotname += strlen(s) + 1; + if ((newslot = slotnm_create(mp, andbit, s)) == NULL) { + slotnm_destroy(*slots); + *slots = NULL; + *nslots = 0; + return (-1); + } + if (lastslot == NULL) + *slots = lastslot = newslot; + else + lastslot->snm_next = newslot; + (*nslots)++; + } + } + return (0); +} + +int +did_physslot(did_t *did) +{ + assert(did != NULL); + return (did->dp_physlot); +} + + +did_hash_t * +did_hash(did_t *did) +{ + assert(did != NULL); + return (did->dp_hash); +} + +did_t * +did_create(did_hash_t *dhash, di_node_t src, + int ibrd, int ibrdge, int irc, int ibus) +{ + topo_mod_t *mp; + did_t *np; + did_t *pd; + uint_t code; + uint_t reg; + + mp = dhash->dph_mod; + if ((pd = did_hash_lookup(dhash, src)) != NULL) { + topo_mod_dprintf(mp, "Attempt to create existing did_t.\n"); + assert(ibus == TRUST_BDF || (pd->dp_bus == ibus)); + return (pd); + } + + if ((np = topo_mod_zalloc(mp, sizeof (did_t))) == NULL) + return (NULL); + np->dp_mod = mp; + np->dp_src = src; + np->dp_hash = dhash; + + /* + * We must have a reg prop and from it we extract the bus #, + * device #, and function #. + */ + if (di_uintprop_get(src, DI_REGPROP, ®) < 0) { + topo_mod_free(mp, np, sizeof (did_t)); + return (NULL); + } + np->dp_board = ibrd; + np->dp_bridge = ibrdge; + np->dp_rc = irc; + if (ibus == TRUST_BDF) + np->dp_bus = PCI_REG_BUS_G(reg); + else + np->dp_bus = ibus; + np->dp_dev = PCI_REG_DEV_G(reg); + np->dp_fn = PCI_REG_FUNC_G(reg); + /* + * There *may* be a class code we can capture. If there wasn't + * one, capture that fact by setting the class value to -1. + */ + if (di_uintprop_get(src, DI_CCPROP, &code) == 0) { + np->dp_class = GETCLASS(code); + np->dp_subclass = GETSUBCLASS(code); + } else { + np->dp_class = -1; + } + /* + * There *may* be a PCI-express capabilities register we can capture. + * If there wasn't one, the capabilities will be the out-of-bounds + * value of zero. + */ + (void) di_uintprop_get(src, SAVED_PCIEX_CAP_REG, &np->dp_excap); + /* + * There *may* be a physical slot number property we can capture. + */ + if (di_physlotinfo_get(mp, + src, np->dp_excap, &np->dp_physlot, &np->dp_physlot_label) < 0) { + topo_mod_free(mp, np, sizeof (did_t)); + return (NULL); + } + /* + * There *may* be PCI slot info we can capture + */ + if (di_slotinfo_get(mp, src, &np->dp_nslots, &np->dp_slotnames) < 0) { + if (np->dp_physlot_label != NULL) + topo_mod_strfree(mp, np->dp_physlot_label); + topo_mod_free(mp, np, sizeof (did_t)); + return (NULL); + } + did_hash_insert(dhash, src, np); + did_hold(np); + return (np); +} + +did_t * +did_link_get(did_t *dp) +{ + assert(dp != NULL); + return (dp->dp_link); +} + +did_t * +did_chain_get(did_t *dp) +{ + assert(dp != NULL); + return (dp->dp_chain); +} + +void +did_link_set(tnode_t *head, did_t *tail) +{ + did_t *hd, *pd; + + assert(head != NULL); + pd = hd = topo_node_private(head); + assert(hd != NULL); + while ((hd = did_link_get(hd)) != NULL) + pd = hd; + pd->dp_link = tail; + tail->dp_link = NULL; +} + +void +did_did_link_set(did_t *from, did_t *to) +{ + assert(from != NULL && to != NULL); + from->dp_link = to; +} + +void +did_did_chain_set(did_t *from, did_t *to) +{ + assert(from != NULL && to != NULL); + from->dp_chain = to; +} + +void +did_destroy(did_t *dp) +{ + assert(dp != NULL); + + /* + * did_destroy() is called only from did_hash_destroy() when + * all references to the did_t have been released. We can + * safely destroy the did_t. If at some later time, more + * fine-grained reference count control is desired, this + * code will need to change + */ + + if (dp->dp_physlot_label != NULL) + topo_mod_strfree(dp->dp_mod, dp->dp_physlot_label); + slotnm_destroy(dp->dp_slotnames); + topo_mod_free(dp->dp_mod, dp, sizeof (did_t)); +} + +void +did_hold(did_t *dp) +{ + assert(dp != NULL); + dp->dp_refcnt++; +} + +void +did_rele(did_t *dp) +{ + assert(dp != NULL); + assert(dp->dp_refcnt > 0); + dp->dp_refcnt--; +} + +di_node_t +did_dinode(did_t *dp) +{ + assert(dp != NULL); + assert(dp->dp_src != NULL); + return (dp->dp_src); +} + +topo_mod_t * +did_mod(did_t *dp) +{ + assert(dp != NULL); + return (dp->dp_mod); +} + +void +did_markrc(did_t *dp) +{ + assert(dp != NULL); + dp->dp_excap |= PCIE_PCIECAP_DEV_TYPE_ROOT; +} + +void +did_BDF(did_t *dp, int *bus, int *dev, int *fn) +{ + assert(dp != NULL); + if (bus != NULL) + *bus = dp->dp_bus; + if (dev != NULL) + *dev = dp->dp_dev; + if (fn != NULL) + *fn = dp->dp_fn; +} + +int +did_board(did_t *did) +{ + assert(did != NULL); + return (did->dp_board); +} + +int +did_bridge(did_t *did) +{ + assert(did != NULL); + return (did->dp_bridge); +} + +int +did_rc(did_t *did) +{ + assert(did != NULL); + return (did->dp_rc); +} + +static int +did_numlabels(did_t *dp) +{ + assert(dp != NULL); + return (dp->dp_nslots); +} + +int +did_excap(did_t *dp) +{ + assert(dp != NULL); + return ((int)dp->dp_excap); +} + +const char * +did_label(did_t *dp, int dev) +{ + slotnm_t *slot; + + assert(dp != NULL); + if (dp->dp_physlot_label != NULL) + return (dp->dp_physlot_label); + for (slot = dp->dp_slotnames; slot != NULL; slot = slot->snm_next) + if (slot->snm_dev == dev) + break; + if (slot != NULL) + return (slot->snm_label); + return (NULL); +} + +did_t * +did_find(did_hash_t *dhash, di_node_t dn) +{ + return (did_hash_lookup(dhash, dn)); +} + +int +pci_BDF_get(did_hash_t *dhash, di_node_t dn, int *bus, int *dev, int *fn) +{ + did_t *dp; + + if ((dp = did_find(dhash, dn)) == NULL) + return (-1); + *bus = dp->dp_bus; + *dev = dp->dp_dev; + *fn = dp->dp_fn; + did_rele(dp); + return (0); +} + +int +pci_classcode_get(did_hash_t *dhash, + di_node_t dn, uint_t *class, uint_t *sub) +{ + did_t *dp; + + if ((dp = did_find(dhash, dn)) == NULL) + return (-1); + if (dp->dp_class < 0) { + did_rele(dp); + return (-1); + } + *class = dp->dp_class; + *sub = dp->dp_subclass; + did_rele(dp); + return (0); +} + +int +pciex_cap_get(did_hash_t *dhash, di_node_t dn) +{ + did_t *dp; + + if ((dp = did_find(dhash, dn)) == NULL) + return (-1); + did_rele(dp); + return (dp->dp_excap); +} + +int +did_inherit(tnode_t *parent, tnode_t *child) +{ + did_t *pdp, *dp; + + /* + * If the child already has a label, we're done. + */ + dp = topo_node_private(child); + assert(dp != NULL); + if (did_numlabels(dp) > 0) + return (0); + + pdp = topo_node_private(parent); + assert(pdp != NULL); + + /* + * If the child and parent are the same, we're done. + */ + if (dp == pdp) + return (0); + + if (pdp->dp_physlot_label != NULL) { + topo_mod_dprintf(dp->dp_mod, + "%p inherits physlot label from %p.\n", dp, pdp); + dp->dp_physlot_label = + topo_mod_strdup(dp->dp_mod, pdp->dp_physlot_label); + if (dp->dp_physlot_label == NULL) + return (-1); + } + if (slotnm_cp(pdp, dp, &dp->dp_nslots) < 0) + return (-1); + return (0); +} diff --git a/usr/src/lib/fm/topo/modules/common/did.h b/usr/src/lib/fm/topo/modules/common/did.h new file mode 100644 index 0000000000..c952eb61ef --- /dev/null +++ b/usr/src/lib/fm/topo/modules/common/did.h @@ -0,0 +1,74 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _DID_H +#define _DID_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/pci.h> +#include <fm/libtopo.h> +#include <libdevinfo.h> +#include <libnvpair.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct did did_t; +typedef struct did_hash did_hash_t; + +extern topo_mod_t *did_mod(did_t *); +extern di_node_t did_dinode(did_t *); +extern void did_BDF(did_t *, int *, int *, int *); +extern void did_markrc(did_t *); +extern const char *did_label(did_t *, int); +extern int did_board(did_t *); +extern int did_bridge(did_t *); +extern int did_rc(did_t *); +extern int did_physslot(did_t *); +extern int did_inherit(tnode_t *, tnode_t *); +extern int did_excap(did_t *); + +extern did_t *did_create(did_hash_t *, di_node_t, int, int, int, int); +extern did_t *did_find(did_hash_t *, di_node_t); +extern did_t *did_link_get(did_t *); +extern did_t *did_chain_get(did_t *); +extern void did_destroy(did_t *); +extern did_hash_t *did_hash(did_t *); +extern void did_hash_fini(did_hash_t *); +extern void did_hold(did_t *); +extern void did_link_set(tnode_t *, did_t *); +extern void did_did_link_set(did_t *, did_t *); +extern void did_did_chain_set(did_t *, did_t *); +extern void did_rele(did_t *); +extern did_hash_t *did_hash_init(topo_mod_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _DID_H */ diff --git a/usr/src/lib/fm/topo/modules/common/did_hash.c b/usr/src/lib/fm/topo/modules/common/did_hash.c new file mode 100644 index 0000000000..16af34014f --- /dev/null +++ b/usr/src/lib/fm/topo/modules/common/did_hash.c @@ -0,0 +1,156 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <sys/types.h> +#include <libdevinfo.h> +#include <topo_mod.h> + +#include "pcibus.h" +#include "did_impl.h" +#include "did_props.h" + +did_hash_t * +did_hash_init(topo_mod_t *hdl) +{ + return (did_hash_create(hdl)); +} + +void +did_hash_fini(did_hash_t *dh) +{ + if (dh == NULL) + return; + did_hash_destroy(dh); +} + +static uint64_t +did_dnhash(di_node_t key) +{ + static uint64_t key_divisor = 0; + uint64_t keyn; + + /* + * A bit naughty here, we're aware that a di_info_t is a + * pointer to a struct. For our hashing, we want use the size + * of that struct, which we determine here, somewhat + * impolitely. + */ + if (key_divisor == 0) + key_divisor = sizeof (*key); + + keyn = (uint64_t)key; + + return (keyn / key_divisor); +} + +did_hash_t * +did_hash_create(topo_mod_t *hdl) +{ + did_hash_t *r = topo_mod_zalloc(hdl, sizeof (did_hash_t)); + + if (r == NULL) { + (void) topo_mod_seterrno(hdl, EMOD_NOMEM); + return (NULL); + } + r->dph_mod = hdl; + r->dph_hashlen = REC_HASHLEN; + r->dph_hash = topo_mod_zalloc(hdl, + r->dph_hashlen * sizeof (did_t *)); + if (r->dph_hash == NULL) { + topo_mod_free(hdl, r, sizeof (did_hash_t)); + (void) topo_mod_seterrno(hdl, EMOD_NOMEM); + return (NULL); + } + return (r); +} + +void +did_hash_destroy(did_hash_t *ht) +{ + did_t *e, *n; + int idx; + + if (ht == NULL) + return; + for (idx = 0; idx < ht->dph_hashlen; idx++) { + for (e = ht->dph_hash[idx]; e != NULL; ) { + n = e->dp_next; + did_destroy(e); + e = n; + } + } + topo_mod_free(ht->dph_mod, + ht->dph_hash, ht->dph_hashlen * sizeof (did_t *)); + topo_mod_free(ht->dph_mod, ht, sizeof (did_hash_t)); +} + +void +did_hash_insert(did_hash_t *tab, di_node_t key, did_t *new) +{ + did_t *assertchk; + int idx = did_dnhash(key) % tab->dph_hashlen; + + tab->dph_nelems++; + did_hold(new); + topo_mod_dprintf(tab->dph_mod, "Insert [key=%p] into %p, bucket %d\n", + key, (void *)tab, idx); + if (tab->dph_hash[idx] == NULL) { + tab->dph_hash[idx] = new; + topo_mod_dprintf(tab->dph_mod, "first entry.\n"); + } else { + /* + * We should not be putting in a duplicate entry + */ + for (assertchk = tab->dph_hash[idx]; + assertchk != NULL; + assertchk = assertchk->dp_next) + assert(assertchk->dp_src != key); + new->dp_next = tab->dph_hash[idx]; + tab->dph_hash[idx] = new; + } +} + +did_t * +did_hash_lookup(did_hash_t *tab, di_node_t key) +{ + did_t *e; + int idx = did_dnhash(key) % tab->dph_hashlen; + + e = tab->dph_hash[idx]; + while (e != NULL) { + if (e->dp_src == key) { + did_hold(e); + return (e); + } + e = e->dp_next; + } + return (NULL); +} diff --git a/usr/src/lib/fm/topo/modules/common/did_impl.h b/usr/src/lib/fm/topo/modules/common/did_impl.h new file mode 100644 index 0000000000..a79ecf76f7 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/common/did_impl.h @@ -0,0 +1,113 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _DID_IMPL_H +#define _DID_IMPL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/pci.h> +#include <fm/libtopo.h> +#include <libdevinfo.h> +#include <libnvpair.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define REC_HASHLEN 253 + +struct did_hash; + +/* + * Slot name info is attached to devinfo nodes, compressed inside of + * a "slot-names" property. When we dig this out we store each name + * as an FMRI, along with the device number to which it applies. + */ +typedef struct slotnm { + topo_mod_t *snm_mod; /* module that allocated the slot name */ + struct slotnm *snm_next; + int snm_dev; /* device on the bus that implements the slot */ + char *snm_label; /* label describing the slot */ +} slotnm_t; + +/* + * Private data stored with a tnode_t. We collect slot-name info from + * di_nodes that describe buses, but then don't use it until we get to + * a tnode_t actually describing a function of a device. We also use + * this struct to pass around bus, dev, function info so that doesn't + * have to be re-computed. + */ +typedef struct did { + struct did *dp_next; /* for chaining in a hash bucket */ + struct did *dp_link; /* for chaining to related did_t */ + struct did *dp_chain; /* for chaining to another chain of did_ts */ + struct did_hash *dp_hash; /* the hash table where we reside */ + topo_mod_t *dp_mod; /* module that allocated the did private data */ + di_node_t dp_src; /* di_node_t from which the info was derived */ + int dp_refcnt; /* multiple nodes allowed to point at a did_t */ + uint_t dp_excap; /* PCI-Express capabilities */ + int dp_physlot; /* PCI-Express physical slot # */ + char *dp_physlot_label; /* PCI-Express slot implemented */ + int dp_class; /* PCI class */ + int dp_subclass; /* PCI subclass */ + int dp_board; /* Board number */ + int dp_bridge; /* Bridge number */ + int dp_rc; /* Root Complex number */ + int dp_bus; /* PCI bus number */ + int dp_dev; /* PCI device number on the above bus */ + int dp_fn; /* PCI function number of the above device */ + /* + * There may be some slot name info on devinfo node for a bus or + * hostbridge. We'll copy or reference it for child nodes of that + * bus or hostbridge. + */ + int dp_nslots; /* number of slots actually described */ + slotnm_t *dp_slotnames; /* the slot names as labels */ +} did_t; + +typedef struct did_hash { + did_t **dph_hash; /* hash bucket array */ + uint_t dph_hashlen; /* size of hash bucket array */ + uint_t dph_nelems; /* number of elements in the hash */ + topo_mod_t *dph_mod; /* module that allocated the hash table */ +} did_hash_t; + +extern did_hash_t *did_hash_create(topo_mod_t *); +extern did_t *did_hash_lookup(did_hash_t *, di_node_t); +extern void did_hash_destroy(did_hash_t *); +extern void did_hash_insert(did_hash_t *, di_node_t, did_t *); + +extern did_t *did_create(did_hash_t *, di_node_t, int, int, int, int); +extern void did_destroy(did_t *); +extern void did_hold(did_t *); +extern void did_rele(did_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _DID_IMPL_H */ diff --git a/usr/src/lib/fm/topo/modules/common/did_props.c b/usr/src/lib/fm/topo/modules/common/did_props.c new file mode 100644 index 0000000000..e88d8270a7 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/common/did_props.c @@ -0,0 +1,676 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <assert.h> +#include <alloca.h> +#include <string.h> +#include <strings.h> +#include <limits.h> +#include <sys/types.h> +#include <sys/pci.h> +#include <sys/pcie.h> +#include <sys/fm/protocol.h> +#include <fm/topo_mod.h> +#include <libdevinfo.h> +#include <topo_error.h> + +#include "hostbridge.h" +#include "pcibus.h" +#include "did.h" +#include "did_props.h" + +static int ASRU_set(tnode_t *, did_t *, + const char *, const char *, const char *); +static int FRU_set(tnode_t *, did_t *, + const char *, const char *, const char *); +static int DEVprop_set(tnode_t *, did_t *, + const char *, const char *, const char *); +static int DRIVERprop_set(tnode_t *, did_t *, + const char *, const char *, const char *); +static int EXCAP_set(tnode_t *, did_t *, + const char *, const char *, const char *); +static int label_set(tnode_t *, did_t *, + const char *, const char *, const char *); +static int maybe_di_chars_copy(tnode_t *, did_t *, + const char *, const char *, const char *); +static int maybe_di_uint_to_str(tnode_t *, did_t *, + const char *, const char *, const char *); + +/* + * Arrays of "property translation routines" to set the properties a + * given type of topology node should have. + * + * Note that the label_set translation *MUST COME BEFORE* the FRU + * translation. For the near term we're setting the FRU fmri to + * be a legacy-hc style FMRI based on the label, so the label needs + * to have been set before we do the FRU translation. + * + */ + +txprop_t Fn_common_props[] = { + { NULL, TOPO_PGROUP_IO, TOPO_PROP_DEV, + TOPO_STABILITY_PRIVATE, DEVprop_set }, + { DI_DEVTYPPROP, TOPO_PGROUP_IO, TOPO_PROP_DEVTYPE, + TOPO_STABILITY_PRIVATE, maybe_di_chars_copy }, + { DI_DEVIDPROP, TOPO_PGROUP_PCI, TOPO_PROP_DEVID, + TOPO_STABILITY_PRIVATE, maybe_di_uint_to_str }, + { NULL, TOPO_PGROUP_IO, TOPO_PROP_DRIVER, + TOPO_STABILITY_PRIVATE, DRIVERprop_set }, + { NULL, TOPO_PGROUP_PCI, TOPO_PROP_EXCAP, + TOPO_STABILITY_PRIVATE, EXCAP_set }, + { DI_VENDIDPROP, TOPO_PGROUP_PCI, TOPO_PROP_VENDID, + TOPO_STABILITY_PRIVATE, maybe_di_uint_to_str }, + { NULL, TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL, + TOPO_STABILITY_PRIVATE, label_set }, + { NULL, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU, + TOPO_STABILITY_PRIVATE, FRU_set }, + { NULL, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU, + TOPO_STABILITY_PRIVATE, ASRU_set } +}; + +txprop_t Dev_common_props[] = { + { NULL, TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL, + TOPO_STABILITY_PRIVATE, label_set }, + { NULL, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU, + TOPO_STABILITY_PRIVATE, FRU_set }, + { NULL, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU, + TOPO_STABILITY_PRIVATE, ASRU_set } +}; + +txprop_t Bus_common_props[] = { + { DI_DEVTYPPROP, TOPO_PGROUP_IO, TOPO_PROP_DEVTYPE, + TOPO_STABILITY_PRIVATE, maybe_di_chars_copy }, + { NULL, TOPO_PGROUP_IO, TOPO_PROP_DRIVER, + TOPO_STABILITY_PRIVATE, DRIVERprop_set }, + { NULL, TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL, + TOPO_STABILITY_PRIVATE, label_set }, + { NULL, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU, + TOPO_STABILITY_PRIVATE, FRU_set }, + { NULL, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU, + TOPO_STABILITY_PRIVATE, ASRU_set } +}; + +txprop_t RC_common_props[] = { + { NULL, TOPO_PGROUP_IO, TOPO_PROP_DEV, + TOPO_STABILITY_PRIVATE, DEVprop_set }, + { DI_DEVTYPPROP, TOPO_PGROUP_IO, TOPO_PROP_DEVTYPE, + TOPO_STABILITY_PRIVATE, maybe_di_chars_copy }, + { NULL, TOPO_PGROUP_IO, TOPO_PROP_DRIVER, + TOPO_STABILITY_PRIVATE, DRIVERprop_set }, + { NULL, TOPO_PGROUP_PCI, TOPO_PROP_EXCAP, + TOPO_STABILITY_PRIVATE, EXCAP_set }, + { NULL, TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL, + TOPO_STABILITY_PRIVATE, label_set }, + { NULL, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU, + TOPO_STABILITY_PRIVATE, FRU_set }, + { NULL, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU, + TOPO_STABILITY_PRIVATE, ASRU_set } +}; + +txprop_t ExHB_common_props[] = { + { NULL, TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL, + TOPO_STABILITY_PRIVATE, label_set }, + { NULL, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU, + TOPO_STABILITY_PRIVATE, FRU_set }, + { NULL, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU, + TOPO_STABILITY_PRIVATE, ASRU_set } +}; + +txprop_t IOB_common_props[] = { + { NULL, TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL, + TOPO_STABILITY_PRIVATE, label_set }, + { NULL, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU, + TOPO_STABILITY_PRIVATE, FRU_set }, + { NULL, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU, + TOPO_STABILITY_PRIVATE, ASRU_set } +}; + +txprop_t HB_common_props[] = { + { NULL, TOPO_PGROUP_IO, TOPO_PROP_DEV, + TOPO_STABILITY_PRIVATE, DEVprop_set }, + { NULL, TOPO_PGROUP_IO, TOPO_PROP_DRIVER, + TOPO_STABILITY_PRIVATE, DRIVERprop_set }, + { NULL, TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL, + TOPO_STABILITY_PRIVATE, label_set }, + { NULL, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU, + TOPO_STABILITY_PRIVATE, FRU_set }, + { NULL, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU, + TOPO_STABILITY_PRIVATE, ASRU_set } +}; + +int Bus_propcnt = sizeof (Bus_common_props) / sizeof (txprop_t); +int Dev_propcnt = sizeof (Dev_common_props) / sizeof (txprop_t); +int ExHB_propcnt = sizeof (ExHB_common_props) / sizeof (txprop_t); +int HB_propcnt = sizeof (HB_common_props) / sizeof (txprop_t); +int IOB_propcnt = sizeof (IOB_common_props) / sizeof (txprop_t); +int RC_propcnt = sizeof (RC_common_props) / sizeof (txprop_t); +int Fn_propcnt = sizeof (Fn_common_props) / sizeof (txprop_t); + +/* + * If this devinfo node came originally from OBP data, we'll have prom + * properties associated with the node where we can find properties of + * interest. We ignore anything after the the first four bytes of the + * property, and interpet those first four bytes as our unsigned + * integer. If we don't find the property or it's not large enough, + * 'val' will remained unchanged and we'll return -1. Otherwise 'val' + * gets updated with the property value and we return 0. + */ +static int +promprop2uint(di_node_t n, const char *propnm, uint_t *val) +{ + di_prom_prop_t pp = DI_PROM_PROP_NIL; + uchar_t *buf; + + while ((pp = di_prom_prop_next(Promtree, n, pp)) != DI_PROM_PROP_NIL) { + if (strcmp(di_prom_prop_name(pp), propnm) == 0) { + if (di_prom_prop_data(pp, &buf) < sizeof (uint_t)) + continue; + bcopy(buf, val, sizeof (uint_t)); + return (0); + } + } + return (-1); +} + +/* + * If this devinfo node was added by the PCI hotplug framework it + * doesn't have the PROM properties, but hopefully has the properties + * we're looking for attached directly to the devinfo node. We only + * care about the first four bytes of the property, which we read as + * our unsigned integer. The remaining bytes are ignored. If we + * don't find the property we're looking for, or can't get its value, + * 'val' remains unchanged and we return -1. Otherwise 'val' gets the + * property value and we return 0. + */ +static int +hwprop2uint(di_node_t n, const char *propnm, uint_t *val) +{ + di_prop_t hp = DI_PROP_NIL; + uchar_t *buf; + + while ((hp = di_prop_next(n, hp)) != DI_PROP_NIL) { + if (strcmp(di_prop_name(hp), propnm) == 0) { + if (di_prop_bytes(hp, &buf) < sizeof (uint_t)) + continue; + bcopy(buf, val, sizeof (uint_t)); + return (0); + } + } + return (-1); +} + +int +di_uintprop_get(di_node_t n, const char *pnm, uint_t *pv) +{ + if (hwprop2uint(n, pnm, pv) < 0) + if (promprop2uint(n, pnm, pv) < 0) + return (-1); + return (0); +} + +int +di_bytes_get(di_node_t n, const char *pnm, int *sz, uchar_t **db) +{ + di_prom_prop_t pp = DI_PROM_PROP_NIL; + di_prop_t hp = DI_PROP_NIL; + + *sz = -1; + while ((hp = di_prop_next(n, hp)) != DI_PROP_NIL) { + if (strcmp(di_prop_name(hp), pnm) == 0) { + if ((*sz = di_prop_bytes(hp, db)) < 0) + continue; + break; + } + } + if (*sz < 0) { + while ((pp = di_prom_prop_next(Promtree, n, pp)) != + DI_PROM_PROP_NIL) { + if (strcmp(di_prom_prop_name(pp), pnm) == 0) { + *sz = di_prom_prop_data(pp, db); + if (*sz < 0) + continue; + break; + } + } + } + if (*sz < 0) + return (-1); + return (0); +} + +/* + * fix_dev_prop -- sometimes di_devfs_path() doesn't tell the whole + * story, leaving off the device and function number. Chances are if + * devfs doesn't put these on then we'll never see this device as an + * error detector called out in an ereport. Unfortunately, there are + * races and we sometimes do get ereports from devices that devfs + * decides aren't there. For example, the error injector card seems + * to bounce in and out of existence according to devfs. We tack on + * the missing dev and fn here so that the DEV property used to look + * up the topology node is correct. + */ +static char * +dev_path_fix(topo_mod_t *mp, char *path, int devno, int fnno) +{ + char *lastslash; + char *newpath; + int need; + + /* + * We only care about the last component of the dev path. If + * we don't find a slash, something is weird. + */ + lastslash = strrchr(path, '/'); + assert(lastslash != NULL); + + /* + * If an @ sign is present in the last component, the + * di_devfs_path() result had the device,fn unit-address. + * In that case there's nothing we need do. + */ + if (strchr(lastslash, '@') != NULL) + return (path); + + if (fnno == 0) + need = snprintf(NULL, 0, "%s@%x", path, devno); + else + need = snprintf(NULL, 0, "%s@%x,%x", path, devno, fnno); + need++; + + if ((newpath = topo_mod_alloc(mp, need)) == NULL) { + topo_mod_strfree(mp, path); + return (NULL); + } + + if (fnno == 0) + (void) snprintf(newpath, need, "%s@%x", path, devno); + else + (void) snprintf(newpath, need, "%s@%x,%x", path, devno, fnno); + + topo_mod_strfree(mp, path); + return (newpath); +} + +/* + * dev_for_hostbridge() -- For hostbridges we truncate the devfs path + * after the first element in the bus address. + */ +static char * +dev_for_hostbridge(topo_mod_t *mp, char *path) +{ + char *lastslash; + char *newpath; + char *comma; + + /* + * We only care about the last component of the dev path. If + * we don't find a slash, something is weird. + */ + lastslash = strrchr(path, '/'); + assert(lastslash != NULL); + + /* + * Find the comma in the last component component@x,y, and + * truncate the comma and any following number. + */ + comma = strchr(lastslash, ','); + assert(comma != NULL); + + *comma = '\0'; + if ((newpath = topo_mod_strdup(mp, path)) == NULL) + return (path); + *comma = ','; + topo_mod_strfree(mp, path); + return (newpath); +} + +/*ARGSUSED*/ +static int +ASRU_set(tnode_t *tn, did_t *pd, + const char *dpnm, const char *tpgrp, const char *tpnm) +{ + topo_mod_t *mp; + nvlist_t *fmri; + char *nm; + int e; + + /* + * If this topology node represents a device, and that device + * implements a slot, set the ASRU to be the resource describing + * this topology node. Otherwise, inherit our parent's ASRU value. + */ + mp = did_mod(pd); + nm = topo_node_name(tn); + if (strcmp(nm, PCI_DEVICE) == 0 || strcmp(nm, PCIEX_DEVICE) == 0) { + if (did_label(pd, topo_node_instance(tn)) != NULL) { + if (topo_prop_get_fmri(tn, TOPO_PGROUP_PROTOCOL, + TOPO_PROP_RESOURCE, &fmri, &e) < 0) + return (topo_mod_seterrno(mp, e)); + if (topo_node_asru_set(tn, fmri, 0, &e) < 0) { + nvlist_free(fmri); + return (topo_mod_seterrno(mp, e)); + } + nvlist_free(fmri); + return (0); + } + } + if (topo_node_asru_set(tn, NULL, 0, &e) < 0) + if (e != ETOPO_PROP_NOENT) + return (topo_mod_seterrno(mp, e)); + return (0); +} + +/* + * Hopefully this hack routine goes away when fmdump can print the labels. + */ +static int +FRU_fmri_hack(topo_mod_t *mp, tnode_t *tn, const char *label) +{ + topo_hdl_t *hp; + char buf[PATH_MAX]; + nvlist_t *fmri; + int err, e; + + hp = topo_mod_handle(mp); + + (void) snprintf(buf, PATH_MAX, "hc:///component=%s", label); + if (topo_fmri_str2nvl(hp, buf, &fmri, &err) < 0) + return (topo_mod_seterrno(mp, err)); + + e = topo_node_fru_set(tn, fmri, 0, &err); + nvlist_free(fmri); + if (e < 0) + return (topo_mod_seterrno(mp, err)); + return (0); +} + +/*ARGSUSED*/ +static int +FRU_set(tnode_t *tn, did_t *pd, + const char *dpnm, const char *tpgrp, const char *tpnm) +{ + topo_mod_t *mp; + char *label, *nm; + int e; + + nm = topo_node_name(tn); + mp = did_mod(pd); + + /* + * If this topology node represents something other than an + * ioboard or a device that implements a slot, inherit the + * parent's FRU value. If there is no label, inherit our + * parent's FRU value. Otherwise, munge up an fmri based on + * the label. + */ + if (strcmp(nm, "ioboard") != 0 && strcmp(nm, PCI_DEVICE) != 0 && + strcmp(nm, PCIEX_DEVICE) != 0) { + if (topo_node_fru_set(tn, NULL, 0, &e) < 0) { + if (e != ETOPO_PROP_NOENT) + return (topo_mod_seterrno(mp, e)); + } + return (0); + } + + if (topo_prop_get_string(tn, + TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL, &label, &e) < 0) { + if (e != ETOPO_PROP_NOENT) + return (topo_mod_seterrno(mp, e)); + if (topo_node_fru_set(tn, NULL, 0, &e) < 0) { + if (e != ETOPO_PROP_NOENT) + return (topo_mod_seterrno(mp, e)); + } + return (0); + } + e = FRU_fmri_hack(mp, tn, label); + topo_mod_strfree(mp, label); + return (e); +} + +/*ARGSUSED*/ +static int +label_set(tnode_t *tn, did_t *pd, + const char *dpnm, const char *tpgrp, const char *tpnm) +{ + topo_mod_t *mp; + nvlist_t *in, *out; + char *label; + int err; + + mp = did_mod(pd); + if (topo_mod_nvalloc(mp, &in, NV_UNIQUE_NAME) != 0) + return (topo_mod_seterrno(mp, EMOD_FMRI_NVL)); + if (nvlist_add_uint64(in, TOPO_METH_LABEL_ARG_NVL, (uint64_t)pd) != 0) { + nvlist_free(in); + return (topo_mod_seterrno(mp, EMOD_NOMEM)); + } + if (topo_method_invoke(tn, + TOPO_METH_LABEL, TOPO_METH_LABEL_VERSION, in, &out, &err) != 0) { + nvlist_free(in); + return (topo_mod_seterrno(mp, err)); + } + nvlist_free(in); + if (out != NULL && + nvlist_lookup_string(out, TOPO_METH_LABEL_RET_STR, &label) == 0) { + if (topo_prop_set_string(tn, TOPO_PGROUP_PROTOCOL, + TOPO_PROP_LABEL, TOPO_PROP_SET_ONCE, label, &err) != 0) { + nvlist_free(out); + return (topo_mod_seterrno(mp, err)); + } + nvlist_free(out); + } + return (0); +} + +/*ARGSUSED*/ +static int +EXCAP_set(tnode_t *tn, did_t *pd, + const char *dpnm, const char *tpgrp, const char *tpnm) +{ + int excap; + int err; + int e = 0; + + if ((excap = did_excap(pd)) <= 0) + return (0); + + switch (excap & PCIE_PCIECAP_DEV_TYPE_MASK) { + case PCIE_PCIECAP_DEV_TYPE_ROOT: + e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, + TOPO_PROP_EXCAP, TOPO_PROP_SET_ONCE, PCIEX_ROOT, &err); + break; + case PCIE_PCIECAP_DEV_TYPE_UP: + e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, + TOPO_PROP_EXCAP, TOPO_PROP_SET_ONCE, PCIEX_SWUP, &err); + break; + case PCIE_PCIECAP_DEV_TYPE_DOWN: + e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, + TOPO_PROP_EXCAP, TOPO_PROP_SET_ONCE, PCIEX_SWDWN, &err); + break; + case PCIE_PCIECAP_DEV_TYPE_PCI2PCIE: + e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, + TOPO_PROP_EXCAP, TOPO_PROP_SET_ONCE, PCIEX_BUS, &err); + break; + case PCIE_PCIECAP_DEV_TYPE_PCIE2PCI: + e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, + TOPO_PROP_EXCAP, TOPO_PROP_SET_ONCE, PCI_BUS, &err); + break; + case PCIE_PCIECAP_DEV_TYPE_PCIE_DEV: + e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, + TOPO_PROP_EXCAP, TOPO_PROP_SET_ONCE, PCIEX_DEVICE, &err); + break; + } + if (e != 0) + return (topo_mod_seterrno(did_mod(pd), err)); + return (0); +} + +/*ARGSUSED*/ +static int +DEVprop_set(tnode_t *tn, did_t *pd, + const char *dpnm, const char *tpgrp, const char *tpnm) +{ + topo_mod_t *mp; + char *dnpath; + char *path, *fpath; + int d, f; + int err, e; + + mp = did_mod(pd); + if ((dnpath = di_devfs_path(did_dinode(pd))) == NULL) { + topo_mod_dprintf(mp, "NULL di_devfs_path.\n"); + return (topo_mod_seterrno(mp, ETOPO_PROP_NOENT)); + } + if ((path = topo_mod_strdup(mp, dnpath)) == NULL) { + di_devfs_path_free(dnpath); + return (-1); + } + di_devfs_path_free(dnpath); + + /* The DEV path is modified for hostbridges */ + if (strcmp(topo_node_name(tn), HOSTBRIDGE) == 0) { + fpath = dev_for_hostbridge(did_mod(pd), path); + } else { + did_BDF(pd, NULL, &d, &f); + fpath = dev_path_fix(mp, path, d, f); + } + if (fpath == NULL) + return (-1); + e = topo_prop_set_string(tn, + tpgrp, tpnm, TOPO_PROP_SET_ONCE, fpath, &err); + topo_mod_strfree(mp, fpath); + if (e != 0) + return (topo_mod_seterrno(mp, err)); + return (0); +} + +/*ARGSUSED*/ +static int +DRIVERprop_set(tnode_t *tn, did_t *pd, + const char *dpnm, const char *tpgrp, const char *tpnm) +{ + char *dnm; + int err; + + if ((dnm = di_driver_name(did_dinode(pd))) == NULL) + return (0); + if (topo_prop_set_string(tn, + tpgrp, tpnm, TOPO_PROP_SET_ONCE, dnm, &err) < 0) + return (topo_mod_seterrno(did_mod(pd), err)); + + return (0); +} + +/*ARGSUSED*/ +static int +maybe_di_chars_copy(tnode_t *tn, did_t *pd, + const char *dpnm, const char *tpgrp, const char *tpnm) +{ + topo_mod_t *mp; + uchar_t *typbuf; + char *tmpbuf; + int sz = -1; + int err, e; + + if (di_bytes_get(did_dinode(pd), dpnm, &sz, &typbuf) < 0) + return (0); + mp = did_mod(pd); + tmpbuf = topo_mod_alloc(mp, sz + 1); + bcopy(typbuf, tmpbuf, sz); + tmpbuf[sz] = 0; + e = topo_prop_set_string(tn, + tpgrp, tpnm, TOPO_PROP_SET_ONCE, tmpbuf, &err); + topo_mod_free(mp, tmpbuf, sz + 1); + if (e != 0) + return (topo_mod_seterrno(mp, err)); + return (0); +} + +static int +uint_to_strprop(topo_mod_t *mp, uint_t v, tnode_t *tn, + const char *tpgrp, const char *tpnm) +{ + char str[21]; /* sizeof (UINT64_MAX) + '\0' */ + int e; + + (void) snprintf(str, 21, "%x", v); + if (topo_prop_set_string(tn, + tpgrp, tpnm, TOPO_PROP_SET_ONCE, str, &e) < 0) + return (topo_mod_seterrno(mp, e)); + return (0); +} + +static int +maybe_di_uint_to_str(tnode_t *tn, did_t *pd, + const char *dpnm, const char *tpgrp, const char *tpnm) +{ + uint_t v; + + if (di_uintprop_get(did_dinode(pd), dpnm, &v) < 0) + return (0); + + return (uint_to_strprop(did_mod(pd), v, tn, tpgrp, tpnm)); +} + +int +did_props_set(tnode_t *tn, did_t *pd, txprop_t txarray[], int txnum) +{ + topo_mod_t *mp; + const char *ppgroup = NULL; + int i, r, e; + + mp = did_mod(pd); + for (i = 0; i < txnum; i++) { + /* + * Ensure the property group has been created. + */ + if (ppgroup == NULL || + strcmp(txarray[i].tx_tpgroup, ppgroup) != 0) { + if (topo_pgroup_create(tn, txarray[i].tx_tpgroup, + txarray[i].tx_pgstab, &e) < 0) { + if (e != ETOPO_PROP_DEFD) + return (topo_mod_seterrno(mp, e)); + } + } + + topo_mod_dprintf(mp, + "Setting property %s in group %s.\n", + txarray[i].tx_tprop, txarray[i].tx_tpgroup); + r = txarray[i].tx_xlate(tn, pd, + txarray[i].tx_diprop, txarray[i].tx_tpgroup, + txarray[i].tx_tprop); + if (r != 0) { + topo_mod_dprintf(mp, "failed.\n"); + topo_mod_dprintf(mp, "Error was %s.\n", + topo_strerror(topo_mod_errno(mp))); + return (-1); + } + topo_mod_dprintf(mp, "succeeded.\n"); + } + return (0); +} diff --git a/usr/src/lib/fm/topo/modules/common/did_props.h b/usr/src/lib/fm/topo/modules/common/did_props.h new file mode 100644 index 0000000000..ec3d0bbf8f --- /dev/null +++ b/usr/src/lib/fm/topo/modules/common/did_props.h @@ -0,0 +1,94 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _DID_PROPS_H +#define _DID_PROPS_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/pci.h> +#include <fm/libtopo.h> +#include <libdevinfo.h> +#include <libnvpair.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * pci_props_set() processes an array of structures that translate + * from devinfo props to properties on topology nodes. The structure + * provides the name of a devinfo prop, the name of the property + * group, the name of the property and the stability of the property + * group that should be established on the topology node, as well as a + * function to do the work. + */ +typedef struct txprop { + const char *tx_diprop; /* property examined off the di_node_t */ + const char *tx_tpgroup; /* property group defined on the tnode_t */ + const char *tx_tprop; /* property defined on the tnode_t */ + topo_stability_t tx_pgstab; /* stability of property group */ + /* + * translation function + * If NULL, the devinfo prop's value is copied to the + * topo property. + */ + int (*tx_xlate)(tnode_t *, did_t *, + const char *, const char *, const char *); +} txprop_t; + +#define TOPO_PGROUP_PCI "pci" +#define TOPO_PGROUP_IO "io" + +#define TOPO_PROP_DEVTYPE "DEVTYPE" +#define TOPO_PROP_DRIVER "DRIVER" +#define TOPO_PROP_VENDID "VENDOR-ID" +#define TOPO_PROP_DEVID "DEVICE-ID" +#define TOPO_PROP_EXCAP "EXCAP" +#define TOPO_PROP_DEV "DEV" + +#define DI_DEVTYPPROP "device_type" +#define DI_VENDIDPROP "vendor-id" +#define DI_DEVIDPROP "device-id" +#define DI_REGPROP "reg" +#define DI_CCPROP "class-code" +#define DI_PHYSPROP "physical-slot#" +#define DI_SLOTPROP "slot-names" + +extern int did_props_set(tnode_t *, did_t *, txprop_t[], int); + +extern int pciex_cap_get(did_hash_t *, di_node_t); +extern int pci_BDF_get(did_hash_t *, di_node_t, int *, int *, int *); +extern int pci_classcode_get(did_hash_t *, di_node_t, uint_t *, uint_t *); + +extern int di_uintprop_get(di_node_t, const char *, uint_t *); +extern int di_bytes_get(di_node_t, const char *, int *, uchar_t **); + +#ifdef __cplusplus +} +#endif + +#endif /* _DID_PROPS_H */ diff --git a/usr/src/lib/fm/topo/modules/common/hostbridge.c b/usr/src/lib/fm/topo/modules/common/hostbridge.c new file mode 100644 index 0000000000..e7a47c6c46 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/common/hostbridge.c @@ -0,0 +1,418 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <string.h> +#include <fm/topo_mod.h> +#include <libdevinfo.h> +#include <limits.h> +#include <sys/fm/protocol.h> +#include <sys/param.h> +#include <sys/systeminfo.h> +#include <assert.h> + +#include "hostbridge.h" +#include "pcibus.h" +#include "did.h" +#include "did_props.h" +#include "util.h" + +/* + * hostbridge.c + * Generic code shared by all the hostbridge enumerators + */ +di_prom_handle_t Promtree = DI_PROM_HANDLE_NIL; +topo_mod_t *HbHdl; + +did_hash_t *Didhash; + +static void hb_release(topo_mod_t *, tnode_t *); +static int hb_contains(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); +static int hb_present(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); +static int hb_label(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); +static int hb_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, + topo_instance_t, void *); + +extern int platform_hb_label(tnode_t *, nvlist_t *, nvlist_t **); +extern int platform_hb_enum(tnode_t *, + const char *, topo_instance_t, topo_instance_t); + +extern txprop_t ExHB_common_props[]; +extern txprop_t HB_common_props[]; +extern txprop_t RC_common_props[]; +extern int ExHB_propcnt; +extern int HB_propcnt; +extern int RC_propcnt; + +static int specific_hb_enum(tnode_t *, const char *, topo_instance_t, + topo_instance_t); + +const topo_modinfo_t Hb_info = + { HOSTBRIDGE, HB_ENUMR_VERS, hb_enum, hb_release }; + +const topo_method_t Hb_methods[] = { + { "hb_contains", "hb element contains other element", HB_ENUMR_VERS, + TOPO_STABILITY_INTERNAL, hb_contains }, + { "hb_present", "hb element currently present", HB_ENUMR_VERS, + TOPO_STABILITY_INTERNAL, hb_present }, + { TOPO_METH_LABEL, TOPO_METH_LABEL_DESC, + TOPO_METH_LABEL_VERSION, TOPO_STABILITY_INTERNAL, hb_label }, + { NULL } +}; + +void +_topo_init(topo_mod_t *modhdl) +{ + /* + * Turn on module debugging output + */ + if (getenv("TOPOHBDBG") != NULL) + topo_mod_setdebug(modhdl, TOPO_DBG_ALL); + topo_mod_dprintf(modhdl, "initializing hostbridge enumerator\n"); + + if ((Promtree = di_prom_init()) == DI_PROM_HANDLE_NIL) { + topo_mod_dprintf(modhdl, + "Hostbridge enumerator: di_prom_handle_init failed.\n"); + return; + } + HbHdl = modhdl; + topo_mod_register(modhdl, &Hb_info, NULL); + topo_mod_dprintf(modhdl, "Hostbridge enumr initd\n"); +} + +void +_topo_fini(topo_mod_t *modhdl) +{ + di_prom_fini(Promtree); + topo_mod_unregister(modhdl); +} + +/*ARGSUSED*/ +static int +hb_contains(topo_mod_t *mp, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + return (0); +} + +/*ARGSUSED*/ +static int +hb_present(topo_mod_t *mp, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + return (0); +} + +static int +hb_label(topo_mod_t *mp, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + if (version > TOPO_METH_LABEL_VERSION) + return (topo_mod_seterrno(mp, EMOD_VER_NEW)); + return (platform_hb_label(node, in, out)); +} + +static topo_mod_t * +pci_enumr_load(topo_mod_t *mp, tnode_t *parent) +{ + topo_mod_t *rp = NULL; + char *plat, *mach; + char *pcipath; + char *rootdir; + int err; + + plat = mach = NULL; + + if (topo_prop_get_string(parent, + TOPO_PGROUP_SYSTEM, TOPO_PROP_PLATFORM, &plat, &err) < 0) { + (void) topo_mod_seterrno(mp, err); + return (NULL); + } + if (topo_prop_get_string(parent, + TOPO_PGROUP_SYSTEM, TOPO_PROP_MACHINE, &mach, &err) < 0) { + (void) topo_mod_seterrno(mp, err); + return (NULL); + } + pcipath = topo_mod_alloc(mp, PATH_MAX); + rootdir = topo_mod_rootdir(mp); + (void) snprintf(pcipath, + PATH_MAX, PATH_TO_PCI_ENUM, rootdir ? rootdir : "", plat); + + if ((rp = topo_mod_load(mp, pcipath)) == NULL) { + topo_mod_dprintf(HbHdl, + "%s enumerator could not load %s.\n", HOSTBRIDGE, pcipath); + (void) snprintf(pcipath, + PATH_MAX, PATH_TO_PCI_ENUM, rootdir ? rootdir : "", mach); + if ((rp = topo_mod_load(mp, pcipath)) == NULL) { + topo_mod_dprintf(HbHdl, + "%s enumerator could not load %s.\n", + HOSTBRIDGE, pcipath); + } + } + topo_mod_strfree(mp, plat); + topo_mod_strfree(mp, mach); + topo_mod_free(mp, pcipath, PATH_MAX); + return (rp); +} + +/*ARGSUSED*/ +static int +hb_enum(topo_mod_t *mp, tnode_t *pn, const char *name, topo_instance_t imin, + topo_instance_t imax, void *notused) +{ + static topo_mod_t *Pcimod = NULL; + + if (strcmp(name, HOSTBRIDGE) != 0) { + topo_mod_dprintf(HbHdl, + "Currently only know how to enumerate %s components.\n", + HOSTBRIDGE); + return (0); + } + /* + * Load the pcibus enumerator, we'll soon need it! + */ + if (Pcimod == NULL && (Pcimod = pci_enumr_load(mp, pn)) == NULL) + return (-1); + + /* + * If we're asked to enumerate a whole range of hostbridges, then + * we need to find them all. If we're just asked to enumerate a + * single hostbridge, we expect our caller to have passed us linked + * did_t structures we can use to enumerate the singled out hostbridge. + */ + if (imin != imax) { + int rv; + + if ((Didhash = did_hash_init(mp)) == NULL) { + di_prom_fini(Promtree); + topo_mod_dprintf(mp, + "Hash initialization for hostbridge " + "enumerator failed.\n"); + return (-1); + } + if ((rv = platform_hb_enum(pn, name, imin, imax)) < 0) + topo_mod_seterrno(mp, EMOD_PARTIAL_ENUM); + did_hash_fini(Didhash); + Didhash = NULL; + return (rv); + } else { + return (specific_hb_enum(pn, name, imin, imax)); + } +} + +/*ARGSUSED*/ +static void +hb_release(topo_mod_t *mp, tnode_t *node) +{ + topo_method_unregister_all(mp, node); + + /* + * node private data (did_t) for this node is destroyed in + * did_hash_destroy() + */ + +} + +static tnode_t * +hb_tnode_create(tnode_t *parent, + const char *name, topo_instance_t i, void *priv) +{ + topo_hdl_t *thp; + nvlist_t *args, *fmri, *pfmri; + tnode_t *ntn; + int err; + + thp = topo_mod_handle(HbHdl); + + if (topo_node_resource(parent, &pfmri, &err) < 0) { + topo_mod_seterrno(HbHdl, err); + topo_mod_dprintf(HbHdl, + "Unable to retrieve parent resource.\n"); + return (NULL); + } + if (topo_mod_nvalloc(HbHdl, &args, NV_UNIQUE_NAME) != 0) { + (void) topo_mod_seterrno(HbHdl, EMOD_FMRI_NVL); + nvlist_free(pfmri); + return (NULL); + } + err = nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_PARENT, pfmri); + if (err != 0) { + nvlist_free(pfmri); + nvlist_free(args); + (void) topo_mod_seterrno(HbHdl, EMOD_FMRI_NVL); + return (NULL); + } + + fmri = topo_fmri_create(thp, FM_FMRI_SCHEME_HC, name, i, args, &err); + if (fmri == NULL) { + nvlist_free(pfmri); + nvlist_free(args); + (void) topo_mod_seterrno(HbHdl, err); + topo_mod_dprintf(HbHdl, + "Unable to make nvlist for %s bind: %s.\n", + name, topo_strerror(err)); + return (NULL); + } + + nvlist_free(pfmri); + nvlist_free(args); + ntn = topo_node_bind(HbHdl, parent, name, i, fmri, priv); + if (ntn == NULL) { + topo_mod_dprintf(HbHdl, + "topo_node_bind (%s%d/%s%d) failed: %s\n", + topo_node_name(parent), topo_node_instance(parent), + name, i, + topo_strerror(topo_mod_errno(HbHdl))); + nvlist_free(fmri); + return (NULL); + } + nvlist_free(fmri); + if (topo_method_register(HbHdl, ntn, Hb_methods) < 0) { + topo_mod_dprintf(HbHdl, "topo_method_register failed: %s\n", + topo_strerror(topo_mod_errno(HbHdl))); + topo_node_unbind(ntn); + return (NULL); + } + return (ntn); +} + +tnode_t * +pcihostbridge_declare(tnode_t *parent, di_node_t din, topo_instance_t i) +{ + did_t *pd; + tnode_t *ntn; + + if ((pd = did_find(Didhash, din)) == NULL) + return (NULL); + if ((ntn = hb_tnode_create(parent, HOSTBRIDGE, i, pd)) == NULL) + return (NULL); + if (did_props_set(ntn, pd, HB_common_props, HB_propcnt) < 0) { + topo_node_unbind(ntn); + return (NULL); + } + /* + * We expect to find pci buses beneath the hostbridge. + */ + if (child_range_add(HbHdl, ntn, PCI_BUS, 0, MAX_HB_BUSES) < 0) { + topo_node_unbind(ntn); + return (NULL); + } + return (ntn); +} + +tnode_t * +pciexhostbridge_declare(tnode_t *parent, di_node_t din, topo_instance_t hi) +{ + did_t *pd; + tnode_t *ntn; + + if ((pd = did_find(Didhash, din)) == NULL) + return (NULL); + if ((ntn = hb_tnode_create(parent, HOSTBRIDGE, hi, pd)) == NULL) + return (NULL); + if (did_props_set(ntn, pd, ExHB_common_props, ExHB_propcnt) < 0) { + topo_node_unbind(ntn); + return (NULL); + } + /* + * We expect to find root complexes beneath the hostbridge. + */ + if (child_range_add(HbHdl, ntn, PCIEX_ROOT, 0, MAX_HB_BUSES) < 0) { + topo_node_unbind(ntn); + return (NULL); + } + return (ntn); +} + +tnode_t * +pciexrc_declare(tnode_t *parent, di_node_t din, topo_instance_t ri) +{ + did_t *pd; + tnode_t *ntn; + + if ((pd = did_find(Didhash, din)) == NULL) + return (NULL); + did_markrc(pd); + if ((ntn = hb_tnode_create(parent, PCIEX_ROOT, ri, pd)) == NULL) + return (NULL); + if (did_props_set(ntn, pd, RC_common_props, RC_propcnt) < 0) { + topo_node_unbind(ntn); + return (NULL); + } + /* + * We expect to find pci-express buses beneath a root complex + */ + if (child_range_add(HbHdl, ntn, PCIEX_BUS, 0, MAX_HB_BUSES) < 0) { + topo_node_range_destroy(ntn, PCIEX_BUS); + return (NULL); + } + return (ntn); +} + +/*ARGSUSED*/ +static int +specific_hb_enum(tnode_t *pn, const char *name, topo_instance_t imin, + topo_instance_t imax) +{ + tnode_t *hb; + did_t *iodid, *didp; + char *pname; + int brc = 0; + int bus; + + pname = topo_node_name(pn); + if ((iodid = topo_node_private(pn)) == NULL) { + topo_mod_dprintf(HbHdl, + "Parent %s node missing private data.\n" + "Unable to proceed with %s enumeration.\n", + pname, name); + return (-1); + } + Didhash = did_hash(iodid); + + /* + * Find the hostbridge of interest + */ + didp = iodid; + for (brc = 0; brc < imin; brc++) + didp = did_chain_get(didp); + assert(didp != NULL); + + if ((hb = pcihostbridge_declare(pn, did_dinode(didp), imin)) == NULL) + return (-1); + while (didp != NULL) { + did_BDF(didp, &bus, NULL, NULL); + if (topo_mod_enumerate(HbHdl, + hb, PCI_BUS, PCI_BUS, bus, bus) != 0) + return (topo_mod_seterrno(HbHdl, EMOD_PARTIAL_ENUM)); + didp = did_link_get(didp); + } + return (0); +} diff --git a/usr/src/lib/fm/topo/modules/common/hostbridge.h b/usr/src/lib/fm/topo/modules/common/hostbridge.h new file mode 100644 index 0000000000..d514bd301a --- /dev/null +++ b/usr/src/lib/fm/topo/modules/common/hostbridge.h @@ -0,0 +1,80 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _HOSTBRIDGE_H +#define _HOSTBRIDGE_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <libdevinfo.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define HB_ENUMR_VERS 1 + +#define PATH_TO_HB_ENUM "%s/usr/platform/%s/lib/fm/topo/plugins/hostbridge.so" + +#define HOSTBRIDGE "hostbridge" + +#define MAX_HBS 255 + +/* + * Solaris Drivers for hostbridge ASICs. + */ +#define SCHIZO "pcisch" +#define PSYCHO "pcipsy" +#define NPE "npe" +#define PCI "pci" +#define PX "px" + +/* + * These #defines are special values of bus and root complex instance + * numbers, used in calls to did_create(). They're here because it's + * the hostbridge enumerator that generally establishes the did_t values + * at the top level. + */ +#define TRUST_BDF (-1) /* Believe the bus value in the reg property */ +#define NO_RC (-2) /* Not a pci-express bus, so no root complex */ + +/* + * PCI-express bridges to PCI, root complex instance is set to + * (instance of the PCI-express side root complex - TO_PCI) + */ +#define TO_PCI (1000) + +extern topo_mod_t *HbHdl; + +extern tnode_t *pcihostbridge_declare(tnode_t *, di_node_t, topo_instance_t); +extern tnode_t *pciexhostbridge_declare(tnode_t *, di_node_t, topo_instance_t); +extern tnode_t *pciexrc_declare(tnode_t *, di_node_t, topo_instance_t); + +#ifdef __cplusplus +} +#endif + +#endif /* _HOSTBRIDGE_H */ diff --git a/usr/src/lib/fm/topo/modules/common/pcibus.c b/usr/src/lib/fm/topo/modules/common/pcibus.c new file mode 100644 index 0000000000..6af6c3dde6 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/common/pcibus.c @@ -0,0 +1,530 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/fm/protocol.h> +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <alloca.h> +#include <sys/param.h> +#include <sys/pci.h> +#include <sys/pcie.h> +#include <libdevinfo.h> +#include <libnvpair.h> +#include <fm/topo_mod.h> + +#include "hostbridge.h" +#include "pcibus.h" +#include "did.h" +#include "did_props.h" +#include "util.h" + +extern txprop_t Bus_common_props[]; +extern txprop_t Dev_common_props[]; +extern txprop_t Fn_common_props[]; +extern int Bus_propcnt; +extern int Dev_propcnt; +extern int Fn_propcnt; + +extern int platform_pci_label(tnode_t *, nvlist_t *, nvlist_t **); + +di_prom_handle_t Promtree = DI_PROM_HANDLE_NIL; +topo_mod_t *PciHdl; + +static void pci_release(topo_mod_t *, tnode_t *); +static int pci_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, + topo_instance_t, void *); +static int pci_contains(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); +static int pci_present(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); +static int pci_label(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); + +const topo_modinfo_t Pci_info = + { PCI_BUS, PCI_ENUMR_VERS, pci_enum, pci_release }; + +const topo_method_t Pci_methods[] = { + { "pci_contains", "pci element contains other element", PCI_ENUMR_VERS, + TOPO_STABILITY_INTERNAL, pci_contains }, + { "pci_present", "pci element currently present", PCI_ENUMR_VERS, + TOPO_STABILITY_INTERNAL, pci_present }, + { TOPO_METH_LABEL, TOPO_METH_LABEL_DESC, + TOPO_METH_LABEL_VERSION, TOPO_STABILITY_INTERNAL, pci_label }, + { NULL } +}; + +static did_hash_t *Didhash; + +void +_topo_init(topo_mod_t *modhdl) +{ + /* + * Turn on module debugging output + */ + if (getenv("TOPOPCIDBG") != NULL) + topo_mod_setdebug(modhdl, TOPO_DBG_ALL); + topo_mod_dprintf(modhdl, "initializing pcibus builtin\n"); + + if ((Promtree = di_prom_init()) == DI_PROM_HANDLE_NIL) { + topo_mod_dprintf(modhdl, + "Pcibus enumerator: di_prom_handle_init failed.\n"); + return; + } + PciHdl = modhdl; + topo_mod_register(PciHdl, &Pci_info, NULL); + topo_mod_dprintf(PciHdl, "PCI Enumr initd\n"); +} + +void +_topo_fini(topo_mod_t *modhdl) +{ + di_prom_fini(Promtree); + topo_mod_unregister(modhdl); +} + +/*ARGSUSED*/ +static int +pci_contains(topo_mod_t *mp, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + return (0); +} + +/*ARGSUSED*/ +static int +pci_present(topo_mod_t *mp, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + return (0); +} + +static int +pci_label(topo_mod_t *mp, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + if (version > TOPO_METH_LABEL_VERSION) + return (topo_mod_seterrno(mp, EMOD_VER_NEW)); + return (platform_pci_label(node, in, out)); +} + +static tnode_t * +pci_tnode_create(tnode_t *parent, + const char *name, topo_instance_t i, void *priv) +{ + tnode_t *ntn; + + if ((ntn = tnode_create(PciHdl, parent, name, i, priv)) == NULL) + return (NULL); + if (topo_method_register(PciHdl, ntn, Pci_methods) < 0) { + topo_mod_dprintf(PciHdl, "topo_method_register failed: %s\n", + topo_strerror(topo_mod_errno(PciHdl))); + topo_node_unbind(ntn); + return (NULL); + } + return (ntn); +} + +/*ARGSUSED*/ +static int +hostbridge_asdevice(tnode_t *bus) +{ + did_t *pd; + di_node_t di; + tnode_t *dev32; + + pd = topo_node_private(bus); + assert(pd != NULL); + di = did_dinode(pd); + assert(di != DI_NODE_NIL); + + if ((dev32 = pcidev_declare(bus, di, 32)) == NULL) + return (-1); + if (pcifn_declare(dev32, di, 0) == NULL) + return (-1); + return (0); +} + +tnode_t * +pciexfn_declare(tnode_t *parent, di_node_t dn, topo_instance_t i) +{ + did_t *pd; + tnode_t *ntn; + + if ((pd = did_find(Didhash, dn)) == NULL) + return (NULL); + if ((ntn = pci_tnode_create(parent, PCIEX_FUNCTION, i, pd)) == NULL) + return (NULL); + if (did_props_set(ntn, pd, Fn_common_props, Fn_propcnt) < 0) { + topo_node_unbind(ntn); + return (NULL); + } + /* + * We may find pci-express buses or plain-pci buses beneath a function + */ + if (child_range_add(PciHdl, ntn, PCIEX_BUS, 0, MAX_HB_BUSES) < 0) { + topo_node_range_destroy(ntn, PCIEX_BUS); + return (NULL); + } + if (child_range_add(PciHdl, ntn, PCI_BUS, 0, MAX_HB_BUSES) < 0) { + topo_node_range_destroy(ntn, PCI_BUS); + return (NULL); + } + return (ntn); +} + +tnode_t * +pciexdev_declare(tnode_t *parent, di_node_t dn, topo_instance_t i) +{ + did_t *pd; + tnode_t *ntn; + + if ((pd = did_find(Didhash, dn)) == NULL) + return (NULL); + if ((ntn = pci_tnode_create(parent, PCIEX_DEVICE, i, pd)) == NULL) + return (NULL); + if (did_props_set(ntn, pd, Dev_common_props, Dev_propcnt) < 0) { + topo_node_unbind(ntn); + return (NULL); + } + /* + * We can expect to find pci-express functions beneath the device + */ + if (child_range_add(PciHdl, + ntn, PCIEX_FUNCTION, 0, MAX_PCIDEV_FNS) < 0) { + topo_node_range_destroy(ntn, PCIEX_FUNCTION); + return (NULL); + } + return (ntn); +} + +tnode_t * +pciexbus_declare(tnode_t *parent, di_node_t dn, topo_instance_t i) +{ + did_t *pd; + tnode_t *ntn; + + if ((pd = did_find(Didhash, dn)) == NULL) + return (NULL); + if ((ntn = pci_tnode_create(parent, PCIEX_BUS, i, pd)) == NULL) + return (NULL); + if (did_props_set(ntn, pd, Bus_common_props, Bus_propcnt) < 0) { + topo_node_range_destroy(ntn, PCI_DEVICE); + topo_node_unbind(ntn); + return (NULL); + } + /* + * We can expect to find pci-express devices beneath the bus + */ + if (child_range_add(PciHdl, + ntn, PCIEX_DEVICE, 0, MAX_PCIBUS_DEVS) < 0) { + topo_node_range_destroy(ntn, PCIEX_DEVICE); + return (NULL); + } + return (ntn); +} + +tnode_t * +pcifn_declare(tnode_t *parent, di_node_t dn, topo_instance_t i) +{ + did_t *pd; + tnode_t *ntn; + + if ((pd = did_find(Didhash, dn)) == NULL) + return (NULL); + if ((ntn = pci_tnode_create(parent, PCI_FUNCTION, i, pd)) == NULL) + return (NULL); + if (did_props_set(ntn, pd, Fn_common_props, Fn_propcnt) < 0) { + topo_node_unbind(ntn); + return (NULL); + } + /* + * We may find pci buses beneath a function + */ + if (child_range_add(PciHdl, ntn, PCI_BUS, 0, MAX_HB_BUSES) < 0) { + topo_node_unbind(ntn); + return (NULL); + } + return (ntn); +} + +tnode_t * +pcidev_declare(tnode_t *parent, di_node_t dn, topo_instance_t i) +{ + did_t *pd; + tnode_t *ntn; + + if ((pd = did_find(Didhash, dn)) == NULL) + return (NULL); + if ((ntn = pci_tnode_create(parent, PCI_DEVICE, i, pd)) == NULL) + return (NULL); + /* + * If our devinfo node is lacking certain information of its + * own, we may need/want to inherit the information available + * from our parent node's private data. + */ + did_inherit(parent, ntn); + if (did_props_set(ntn, pd, Dev_common_props, Dev_propcnt) < 0) { + topo_node_unbind(ntn); + return (NULL); + } + /* + * We can expect to find pci functions beneath the device + */ + if (child_range_add(PciHdl, ntn, PCI_FUNCTION, 0, MAX_PCIDEV_FNS) < 0) { + topo_node_range_destroy(ntn, PCI_FUNCTION); + topo_node_unbind(ntn); + return (NULL); + } + return (ntn); +} + +tnode_t * +pcibus_declare(tnode_t *parent, di_node_t dn, topo_instance_t i) +{ + did_t *pd; + tnode_t *ntn; + int hbchild = 0; + + if ((pd = did_find(Didhash, dn)) == NULL) + return (NULL); + if ((ntn = pci_tnode_create(parent, PCI_BUS, i, pd)) == NULL) + return (NULL); + /* + * If our devinfo node is lacking certain information of its + * own, and our parent topology node is a hostbridge, we may + * need/want to inherit information available in the + * hostbridge node's private data. + */ + if (strcmp(topo_node_name(parent), HOSTBRIDGE) == 0) + hbchild = 1; + if (did_props_set(ntn, pd, Bus_common_props, Bus_propcnt) < 0) { + topo_node_unbind(ntn); + return (NULL); + } + /* + * We can expect to find pci devices beneath the bus + */ + if (child_range_add(PciHdl, ntn, PCI_DEVICE, 0, MAX_PCIBUS_DEVS) < 0) { + topo_node_unbind(ntn); + return (NULL); + } + /* + * On each bus child of the hostbridge, we represent the + * hostbridge as a device outside the range of legal device + * numbers. + */ + if (hbchild == 1) { + if (hostbridge_asdevice(ntn) < 0) { + topo_node_range_destroy(ntn, PCI_DEVICE); + topo_node_unbind(ntn); + return (NULL); + } + } + return (ntn); +} + +static int +declare_dev_and_fn(tnode_t *bus, tnode_t **dev, di_node_t din, + int board, int bridge, int rc, int devno, int fnno, int depth) +{ + tnode_t *fn; + uint_t class, subclass; + int err; + + if (*dev == NULL) { + if (rc >= 0) + *dev = pciexdev_declare(bus, din, devno); + else + *dev = pcidev_declare(bus, din, devno); + if (*dev == NULL) + return (-1); + } + if (rc >= 0) + fn = pciexfn_declare(*dev, din, fnno); + else + fn = pcifn_declare(*dev, din, fnno); + if (fn == NULL) + return (-1); + if (pci_classcode_get(Didhash, din, &class, &subclass) < 0) + return (-1); + if (class == PCI_CLASS_BRIDGE && subclass == PCI_BRIDGE_PCI) { + int excap, extyp; + + excap = pciex_cap_get(Didhash, din); + extyp = excap & PCIE_PCIECAP_DEV_TYPE_MASK; + if (excap <= 0 || + extyp != PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) + err = pci_children_instantiate(fn, + din, board, bridge, rc, TRUST_BDF, depth + 1); + else + err = pci_children_instantiate(fn, + din, board, bridge, rc - TO_PCI, + TRUST_BDF, depth + 1); + if (err < 0) + return (-1); + } + return (0); +} + +int +pci_children_instantiate(tnode_t *parent, di_node_t pn, + int board, int bridge, int rc, int bover, int depth) +{ + did_t *pps[MAX_PCIBUS_DEVS][MAX_PCIDEV_FNS]; + did_t *bp = NULL; + did_t *np; + di_node_t sib; + di_node_t din; + tnode_t *bn = NULL; + tnode_t *dn = NULL; + int pb = -1; + int b, d, f; + + for (d = 0; d < MAX_PCIBUS_DEVS; d++) + for (f = 0; f < MAX_PCIDEV_FNS; f++) + pps[d][f] = NULL; + + /* start at the parent's first sibling */ + sib = di_child_node(pn); + while (sib != DI_NODE_NIL) { + np = did_create(Didhash, sib, board, bridge, rc, bover); + if (np == NULL) + return (-1); + did_BDF(np, &b, &d, &f); + pps[d][f] = np; + if (bp == NULL) + bp = np; + if (pb < 0) + pb = ((bover == TRUST_BDF) ? b : bover); + sib = di_sibling_node(sib); + } + if (pb < 0 && bover < 0) + return (0); + if (rc >= 0) + bn = pciexbus_declare(parent, pn, ((pb < 0) ? bover : pb)); + else + bn = pcibus_declare(parent, pn, ((pb < 0) ? bover : pb)); + if (bn == NULL) + return (-1); + if (pb < 0) + return (0); + + for (d = 0; d < MAX_PCIBUS_DEVS; d++) { + for (f = 0; f < MAX_PCIDEV_FNS; f++) { + if (pps[d][f] == NULL) + continue; + din = did_dinode(pps[d][f]); + if ((declare_dev_and_fn(bn, + &dn, din, board, bridge, rc, d, f, depth)) != 0) + return (-1); + did_rele(pps[d][f]); + } + dn = NULL; + } + return (0); +} + +/*ARGSUSED*/ +static int +pci_enum(topo_mod_t *ignored, tnode_t *troot, const char *name, + topo_instance_t min, topo_instance_t max, void *notused) +{ + did_t *hbdid, *didp; + char *pname; + + topo_mod_dprintf(PciHdl, "Enumerating pci!\n"); + + if (strcmp(name, PCI_BUS) != 0 && strcmp(name, PCIEX_BUS) != 0) { + topo_mod_dprintf(PciHdl, + "Currently only know how to enumerate %s or %s.\n", + PCI_BUS, PCIEX_BUS); + return (0); + } + pname = topo_node_name(troot); + if (strcmp(pname, HOSTBRIDGE) != 0 && strcmp(pname, PCIEX_ROOT) != 0) { + topo_mod_dprintf(PciHdl, + "Currently can only enumerate a %s or %s directly\n", + PCI_BUS, PCIEX_BUS); + topo_mod_dprintf(PciHdl, + "descended from a %s or %s node.\n", + HOSTBRIDGE, PCIEX_ROOT); + return (0); + } + if ((hbdid = topo_node_private(troot)) == NULL) { + topo_mod_dprintf(PciHdl, + "Parent %s node missing private data.\n" + "Unable to proceed with %s enumeration.\n", + pname, name); + return (0); + } + Didhash = did_hash(hbdid); + /* + * If we're looking for a specific bus-instance, find the right + * did_t in the chain, otherwise, there should be only one did_t. + * Cache the did_t of interest in *this* enumerator's cache. + */ + if (min == max) { + int b; + didp = hbdid; + while (didp != NULL) { + did_BDF(didp, &b, NULL, NULL); + if (b == min) + break; + didp = did_link_get(didp); + } + if (didp == NULL) { + topo_mod_dprintf(PciHdl, + "Parent %s node missing private data related\n" + "to %s instance %d.\n", pname, name, min); + return (0); + } + } else { + assert(did_link_get(hbdid) == NULL); + didp = hbdid; + } + return (pci_children_instantiate(troot, did_dinode(didp), + did_board(didp), did_bridge(didp), did_rc(didp), + (min == max) ? min : TRUST_BDF, 0)); +} + +/*ARGSUSED*/ +static void +pci_release(topo_mod_t *mp, tnode_t *node) +{ + topo_method_unregister_all(mp, node); + + /* + * node private data (did_t) for this node is destroyed in + * did_hash_destroy() + */ + + topo_node_unbind(node); +} diff --git a/usr/src/cmd/fm/topo/plugins/common/pcibus/enumpci.h b/usr/src/lib/fm/topo/modules/common/pcibus.h index e998bb5603..684da57886 100644 --- a/usr/src/cmd/fm/topo/plugins/common/pcibus/enumpci.h +++ b/usr/src/lib/fm/topo/modules/common/pcibus.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -19,27 +18,33 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#ifndef _TOPO_PCI_H -#define _TOPO_PCI_H +#ifndef _PCIBUS_H +#define _PCIBUS_H #pragma ident "%Z%%M% %I% %E% SMI" -#include <fm/libtopo_enum.h> +#include <sys/pci.h> +#include <fm/topo_mod.h> +#include <fm/libtopo.h> #include <libdevinfo.h> -#ifdef __cplusplus +#ifdef __cplusplus extern "C" { #endif +#define PCI_ENUMR_VERS 1 + +#define PATH_TO_PCI_ENUM "%s/usr/platform/%s/lib/fm/topo/plugins/pcibus.so" + #define PCI_BUS "pcibus" #define PCI_DEVICE "pcidev" #define PCI_FUNCTION "pcifn" - #define PCIEX_ROOT "pciexrc" #define PCIEX_SWUP "pciexswu" #define PCIEX_SWDWN "pciexswd" @@ -47,41 +52,31 @@ extern "C" { #define PCIEX_DEVICE "pciexdev" #define PCIEX_FUNCTION "pciexfn" -extern struct tenumr *Pci_enumr; - #define PCIEXTYPE "pciex" #define PCITYPE "pci" -#define SCHIZO "pcisch" -#define PSYCHO "pcipsy" -#define NPE "npe" -#define PCI "pci" -#define PX "px" - -#define DEVTYPEPROP "device_type" -#define VENDIDPROP "vendor-id" -#define DEVIDPROP "device-id" -#define CLASSPROP "class-code" -#define PHYSPROP "physical-slot#" -#define SLOTPROP "slot-names" -#define REGPROP "reg" - -#define VENDIDTPROP "VENDOR-ID" -#define DEVIDTPROP "DEVICE-ID" -#define EXCAPTPROP "EXCAP" +#define MAX_HB_BUSES 255 +#define MAX_PCIBUS_DEVS 32 +#define MAX_PCIDEV_FNS 8 #define GETCLASS(x) (((x) & 0xff0000) >> 16) #define GETSUBCLASS(x) (((x) & 0xff00) >> 8) -#define GETPROGIF(x) ((x) & 0xff) -void examine_children(di_node_t n, di_prom_handle_t ph); +extern tnode_t *pcibus_declare(tnode_t *, di_node_t, topo_instance_t); +extern tnode_t *pcidev_declare(tnode_t *, di_node_t, topo_instance_t); +extern tnode_t *pcifn_declare(tnode_t *, di_node_t, topo_instance_t); +extern tnode_t *pciexbus_declare(tnode_t *, di_node_t, topo_instance_t); +extern tnode_t *pciexdev_declare(tnode_t *, di_node_t, topo_instance_t); +extern tnode_t *pciexfn_declare(tnode_t *, di_node_t, topo_instance_t); +extern int pci_children_instantiate(tnode_t *, di_node_t, + int, int, int, int, int); -int topo_pci_init(void); -void topo_pci_fini(void); -void topo_pci_enum(tnode_t *); +extern di_prom_handle_t Promtree; +extern topo_mod_t *PciHdl; +extern const topo_method_t Pci_methods[]; -#ifdef __cplusplus +#ifdef __cplusplus } #endif -#endif /* _TOPO_PCI_H */ +#endif /* _PCIBUS_H */ diff --git a/usr/src/lib/fm/topo/modules/common/pcibus_labels.c b/usr/src/lib/fm/topo/modules/common/pcibus_labels.c new file mode 100644 index 0000000000..1933f8aa30 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/common/pcibus_labels.c @@ -0,0 +1,203 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <libnvpair.h> +#include <fm/topo_mod.h> +#include <assert.h> +#include <string.h> + +#include "topo_error.h" +#include "did.h" +#include "pcibus.h" +#include "pcibus_labels.h" + +extern slotnm_rewrite_t *Slot_Rewrites; +extern physlot_names_t *Physlot_Names; +extern missing_names_t *Missing_Names; + +static const char * +pci_physslot_name_lookup(char *platform, did_t *dp) +{ + const char *rlabel = NULL; + int n, p, i; + + if ((n = did_physslot(dp)) < 0 || Physlot_Names == NULL) + return (NULL); + + for (p = 0; p < Physlot_Names->psn_nplats; p++) { + if (strcmp(Physlot_Names->psn_names[p].pnm_platform, + platform) != 0) + continue; + for (i = 0; i < Physlot_Names->psn_names[p].pnm_nnames; i++) { + physnm_t ps; + ps = Physlot_Names->psn_names[p].pnm_names[i]; + if (ps.ps_num == n) { + rlabel = ps.ps_label; + break; + } + } + break; + } + return (rlabel); +} + +static const char * +pci_slotname_rewrite(char *platform, const char *label) +{ + const char *rlabel = label; + int s, i; + + if (Slot_Rewrites == NULL) + return (rlabel); + + for (s = 0; s < Slot_Rewrites->srw_nplats; s++) { + if (strcmp(Slot_Rewrites->srw_platrewrites[s].prw_platform, + platform) != 0) + continue; + for (i = 0; + i < Slot_Rewrites->srw_platrewrites[s].prw_nrewrites; + i++) { + slot_rwd_t rw; + rw = Slot_Rewrites->srw_platrewrites[s].prw_rewrites[i]; + if (strcmp(rw.srw_obp, label) == 0) { + rlabel = rw.srw_new; + break; + } + } + break; + } + assert(rlabel != NULL); + return (rlabel); +} + +static const char * +pci_missing_match(char *platform, did_t *dp) +{ + const char *rlabel = NULL; + int board, bridge, rc, bus, dev; + int p, i; + + if (Missing_Names == NULL) + return (NULL); + bridge = did_bridge(dp); + board = did_board(dp); + rc = did_rc(dp); + did_BDF(dp, &bus, &dev, NULL); + + topo_mod_dprintf(PciHdl, "Missing a name for %d, %d, %d, %d, %d ?\n", + board, bridge, rc, bus, dev); + + for (p = 0; p < Missing_Names->mn_nplats; p++) { + if (strcmp(Missing_Names->mn_names[p].pdl_platform, + platform) != 0) + continue; + for (i = 0; i < Missing_Names->mn_names[p].pdl_nnames; i++) { + devlab_t m; + m = Missing_Names->mn_names[p].pdl_names[i]; + if (m.dl_board == board && m.dl_bridge == bridge && + m.dl_rc == rc && m.dl_bus == bus && + m.dl_dev == dev) { + rlabel = m.dl_label; + break; + } + } + break; + } + return (rlabel); +} + +static const char * +pci_slotname_lookup(tnode_t *node, did_t *dp) +{ + const char *l; + char *plat; + int err; + int d; + + if (topo_prop_get_string(node, + TOPO_PGROUP_SYSTEM, TOPO_PROP_PLATFORM, &plat, &err) < 0) { + (void) topo_mod_seterrno(PciHdl, err); + return (NULL); + } + did_BDF(dp, NULL, &d, NULL); + if ((l = pci_physslot_name_lookup(plat, dp)) == NULL) + if ((l = did_label(dp, d)) != NULL) { + l = pci_slotname_rewrite(plat, l); + } else { + l = pci_missing_match(plat, dp); + } + topo_mod_strfree(PciHdl, plat); + return (l); +} + +int +pci_label_cmn(tnode_t *node, nvlist_t *in, nvlist_t **out) +{ + uint64_t ptr; + const char *l; + did_t *dp; + char *nm; + int err; + + /* + * If it's not a device, just inherit any label from our parent + */ + *out = NULL; + nm = topo_node_name(node); + if (strcmp(nm, PCI_DEVICE) != 0 && strcmp(nm, PCIEX_DEVICE) != 0) { + if (topo_node_label_set(node, NULL, &err) < 0) + if (err != ETOPO_PROP_NOENT) + return (topo_mod_seterrno(PciHdl, err)); + return (0); + } + + if (nvlist_lookup_uint64(in, TOPO_METH_LABEL_ARG_NVL, &ptr) != 0) { + topo_mod_dprintf(PciHdl, + "label method argument not found.\n"); + return (-1); + } + dp = (did_t *)ptr; + + /* + * Is there a slotname associated with the device? + */ + if ((l = pci_slotname_lookup(node, dp)) != NULL) { + nvlist_t *rnvl; + + if (topo_mod_nvalloc(PciHdl, &rnvl, NV_UNIQUE_NAME) != 0 || + nvlist_add_string(rnvl, TOPO_METH_LABEL_RET_STR, l) != 0) + return (topo_mod_seterrno(PciHdl, EMOD_FMRI_NVL)); + *out = rnvl; + return (0); + } else { + if (topo_node_label_set(node, NULL, &err) < 0) + if (err != ETOPO_PROP_NOENT) + return (topo_mod_seterrno(PciHdl, err)); + return (0); + } +} diff --git a/usr/src/lib/fm/topo/modules/common/pcibus_labels.h b/usr/src/lib/fm/topo/modules/common/pcibus_labels.h new file mode 100644 index 0000000000..6a7d3fb645 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/common/pcibus_labels.h @@ -0,0 +1,110 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _PCI_LABELS_H +#define _PCI_LABELS_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include "hostbridge.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * When all we're provided is a physical slot number, these structures + * allow us to attach an accompanying label. + */ +typedef struct physnm { + int ps_num; + const char *ps_label; +} physnm_t; + +typedef struct pphysnm { + const char *pnm_platform; /* platform on which the names apply */ + int pnm_nnames; /* number of names */ + struct physnm *pnm_names; /* array of labels */ +} pphysnm_t; + +typedef struct physlot_names { + int psn_nplats; + struct pphysnm *psn_names; +} physlot_names_t; + +/* + * Sometimes OBP gets it wrong, there's a slot-names property, but it + * is incorrect. These structures allow us to replace a given label A + * with a different label B prior to attaching the label to a topology node. + */ +typedef struct slot_rwd { + const char *srw_obp; /* slot name found */ + const char *srw_new; /* replacement slot name */ +} slot_rwd_t; + +typedef struct plat_rwd { + const char *prw_platform; /* platform on which the names apply */ + int prw_nrewrites; /* number of rewrites */ + struct slot_rwd *prw_rewrites; /* array of rewrites */ +} plat_rwd_t; + +typedef struct slotnm_rewrite { + int srw_nplats; + struct plat_rwd *srw_platrewrites; +} slotnm_rewrite_t; + +/* + * We can locate a label without help from OBP slot-names or a + * physical slot-name, if need be. Having to resort to this, though is + * really an indication that there's a bug in the platform OBP. + */ +typedef struct devlab { + int dl_board; + int dl_bridge; + int dl_rc; + int dl_bus; + int dl_dev; + const char *dl_label; +} devlab_t; + +typedef struct pdevlabs { + const char *pdl_platform; /* Name of the platform */ + int pdl_nnames; /* number of missing names */ + struct devlab *pdl_names; /* the missing names */ +} pdevlabs_t; + +typedef struct missing_names { + int mn_nplats; /* number of platforms with entries */ + struct pdevlabs *mn_names; /* platform entries */ +} missing_names_t; + +extern int pci_label_cmn(tnode_t *, nvlist_t *, nvlist_t **); + +#ifdef __cplusplus +} +#endif + +#endif /* _PCI_LABELS_H */ diff --git a/usr/src/lib/fm/topo/modules/common/util.c b/usr/src/lib/fm/topo/modules/common/util.c new file mode 100644 index 0000000000..43adf4e66c --- /dev/null +++ b/usr/src/lib/fm/topo/modules/common/util.c @@ -0,0 +1,138 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdlib.h> +#include <sys/fm/protocol.h> +#include <fm/topo_mod.h> + +#include "topo_error.h" + +int +child_range_add(topo_mod_t *mp, tnode_t *tn, const char *cnm, + topo_instance_t imin, topo_instance_t imax) +{ + int e; + + e = topo_node_range_create(mp, tn, cnm, imin, imax); + if (e != 0) { + topo_mod_dprintf(mp, "add child range (%s) failed: %s\n", + cnm, topo_strerror(topo_mod_errno(mp))); + return (-1); + } + return (0); +} + +ulong_t +strtonum(topo_mod_t *mp, char *str, int *err) +{ + ulong_t r; + char *e; + + r = strtoul(str, &e, 16); + if (e == str) { + topo_mod_dprintf(mp, + "Trouble converting %s to a number!\n", str); + *err = -1; + return (0); + } + *err = 0; + return (r); +} + +tnode_t * +tnode_create(topo_mod_t *mp, tnode_t *parent, + const char *name, topo_instance_t i, void *priv) +{ + topo_hdl_t *thp; + nvlist_t *fmri, *pfmri, *nvl; + tnode_t *ntn; + int err; + + thp = topo_mod_handle(mp); + + if (topo_node_resource(parent, &pfmri, &err) < 0) { + topo_mod_seterrno(mp, err); + topo_mod_dprintf(mp, "Unable to retrieve parent resource.\n"); + return (NULL); + } + if (topo_mod_nvalloc(mp, &nvl, NV_UNIQUE_NAME) != 0) { + (void) topo_mod_seterrno(mp, EMOD_FMRI_NVL); + nvlist_free(pfmri); + return (NULL); + } + err = nvlist_add_nvlist(nvl, TOPO_METH_FMRI_ARG_PARENT, pfmri); + if (err != 0) { + nvlist_free(pfmri); + nvlist_free(nvl); + (void) topo_mod_seterrno(mp, EMOD_FMRI_NVL); + return (NULL); + } + + fmri = topo_fmri_create(thp, FM_FMRI_SCHEME_HC, name, i, nvl, &err); + if (fmri == NULL) { + nvlist_free(pfmri); + nvlist_free(nvl); + topo_mod_seterrno(mp, err); + topo_mod_dprintf(mp, + "Unable to make nvlist for %s bind.\n", name); + return (NULL); + } + + nvlist_free(pfmri); + nvlist_free(nvl); + ntn = topo_node_bind(mp, parent, name, i, fmri, priv); + if (ntn == NULL) { + topo_mod_dprintf(mp, + "topo_node_bind (%s%d/%s%d) failed: %s\n", + topo_node_name(parent), topo_node_instance(parent), + name, i, + topo_strerror(topo_mod_errno(mp))); + nvlist_free(fmri); + return (NULL); + } + nvlist_free(fmri); + return (ntn); +} + +/*ARGSUSED*/ +int +labelmethod_inherit(topo_mod_t *mp, tnode_t *tn, nvlist_t *in, nvlist_t **out) +{ + int err; + + /* + * Ignore the input and output nvlists and directly set the + * label as inheritance from the parent + */ + *out = NULL; + if (topo_node_label_set(tn, NULL, &err) < 0) { + if (err != ETOPO_PROP_NOENT) + return (topo_mod_seterrno(mp, err)); + } + return (0); +} diff --git a/usr/src/lib/fm/topo/modules/common/util.h b/usr/src/lib/fm/topo/modules/common/util.h new file mode 100644 index 0000000000..8dda2b6304 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/common/util.h @@ -0,0 +1,50 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _UTIL_H +#define _UTIL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <fm/topo_mod.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern int child_range_add(topo_mod_t *, tnode_t *, const char *, + topo_instance_t, topo_instance_t); +extern int labelmethod_inherit(topo_mod_t *, tnode_t *, nvlist_t *, + nvlist_t **); +extern ulong_t strtonum(topo_mod_t *, char *, int *); +extern tnode_t *tnode_create(topo_mod_t *, tnode_t *, const char *, + topo_instance_t, void *); + +#ifdef __cplusplus +} +#endif + +#endif /* _UTIL_H */ diff --git a/usr/src/lib/fm/topo/modules/i86pc/Makefile b/usr/src/lib/fm/topo/modules/i86pc/Makefile new file mode 100644 index 0000000000..7cc4f0e51e --- /dev/null +++ b/usr/src/lib/fm/topo/modules/i86pc/Makefile @@ -0,0 +1,32 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" + +SUBDIRS = chip hostbridge pcibus + +.PARALLEL: $(SUBDIRS) + +include ../../../Makefile.subdirs diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V215/Makefile b/usr/src/lib/fm/topo/modules/i86pc/chip/Makefile index 4a575514e1..2a2d40c922 100644 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V215/Makefile +++ b/usr/src/lib/fm/topo/modules/i86pc/chip/Makefile @@ -25,8 +25,11 @@ # #ident "%Z%%M% %I% %E% SMI" -TOPOFILE = platform.topo -TOPOSRCDIR = SUNW,Sun-Fire-V245 -TOPOTARGDIR = SUNW,Sun-Fire-V215 +MODULE = chip +ARCH = i86pc +CLASS = arch +MODULESRCS = chip.c -include ../../Makefile.link +include ../../Makefile.plugin + +LDLIBS += -lkstat diff --git a/usr/src/lib/fm/topo/modules/i86pc/chip/chip.c b/usr/src/lib/fm/topo/modules/i86pc/chip/chip.c new file mode 100644 index 0000000000..10543c0d38 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/i86pc/chip/chip.c @@ -0,0 +1,689 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <limits.h> +#include <alloca.h> +#include <kstat.h> +#include <fcntl.h> +#include <errno.h> +#include <libnvpair.h> +#include <sys/types.h> +#include <sys/bitmap.h> +#include <sys/processor.h> +#include <sys/param.h> +#include <sys/fm/protocol.h> +#include <sys/systeminfo.h> +#include <sys/mc.h> +#include <fm/topo_mod.h> + +#include "chip.h" + +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +/* + * Enumerates the processing chips, or sockets, (as distinct from cores) in a + * system. For each chip found, the necessary nodes (one or more cores, and + * possibly a memory controller) are constructed underneath. + */ + +static int chip_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, + topo_instance_t, void *); + +const topo_modinfo_t chip_info = + { "chip", CHIP_VERSION, chip_enum, NULL}; + +int +_topo_init(topo_mod_t *mod) +{ + chip_t *chip; + + topo_mod_setdebug(mod, TOPO_DBG_ALL); + topo_mod_dprintf(mod, "initializing chip enumerator\n"); + + if ((chip = topo_mod_zalloc(mod, sizeof (chip_t))) == NULL) + return (topo_mod_seterrno(mod, EMOD_NOMEM)); + + if ((chip->chip_kc = kstat_open()) == NULL) { + topo_mod_dprintf(mod, "kstat_open failed: %s\n", + strerror(errno)); + topo_mod_free(mod, chip, sizeof (chip_t)); + return (topo_mod_seterrno(mod, errno)); + } + + chip->chip_ncpustats = sysconf(_SC_CPUID_MAX); + if ((chip->chip_cpustats = topo_mod_zalloc(mod, ( + chip->chip_ncpustats + 1) * sizeof (kstat_t *))) == NULL) { + (void) kstat_close(chip->chip_kc); + topo_mod_free(mod, chip, sizeof (chip_t)); + return (topo_mod_seterrno(mod, EMOD_NOMEM)); + } + + if (topo_mod_register(mod, &chip_info, (void *)chip) != 0) { + topo_mod_dprintf(mod, "failed to register hc: " + "%s\n", topo_mod_errmsg(mod)); + topo_mod_free(mod, chip->chip_cpustats, + (chip->chip_ncpustats + 1) * sizeof (kstat_t *)); + (void) kstat_close(chip->chip_kc); + topo_mod_free(mod, chip, sizeof (chip_t)); + return (-1); /* mod errno set */ + } + + return (0); +} + +void +_topo_fini(topo_mod_t *mod) +{ + chip_t *chip = topo_mod_private(mod); + + if (chip->chip_cpustats != NULL) + topo_mod_free(mod, chip->chip_cpustats, + (chip->chip_ncpustats + 1) * sizeof (kstat_t *)); + + (void) kstat_close(chip->chip_kc); + topo_mod_free(mod, chip, sizeof (chip_t)); + + topo_mod_unregister(mod); +} + +static int +chip_strprop(tnode_t *cnode, kstat_t *ksp, const char *name) +{ + int err; + kstat_named_t *k; + + if ((k = kstat_data_lookup(ksp, (char *)name)) == NULL) + return (0); + + (void) topo_prop_set_string(cnode, CHIP_PGROUP, name, + TOPO_PROP_SET_ONCE, k->value.str.addr.ptr, &err); + + return (-1); +} + +static int +chip_longprop(tnode_t *cnode, kstat_t *ksp, const char *name) +{ + int err; + kstat_named_t *k; + + if ((k = kstat_data_lookup(ksp, (char *)name)) == NULL) + return (0); + + (void) topo_prop_set_int32(cnode, CHIP_PGROUP, name, TOPO_PROP_SET_ONCE, + k->value.l, &err); + + return (-1); +} + +static nvlist_t * +cpu_fmri_create(topo_mod_t *mod, uint32_t cpuid, char *s, uint8_t cpumask) +{ + int err; + nvlist_t *asru; + + if (topo_mod_nvalloc(mod, &asru, NV_UNIQUE_NAME) != 0) + return (NULL); + + err = nvlist_add_uint8(asru, FM_VERSION, FM_CPU_SCHEME_VERSION); + err |= nvlist_add_string(asru, FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU); + err |= nvlist_add_uint32(asru, FM_FMRI_CPU_ID, cpuid); + err |= nvlist_add_uint8(asru, FM_FMRI_CPU_MASK, cpumask); + if (s != NULL) + err |= nvlist_add_string(asru, FM_FMRI_CPU_SERIAL_ID, s); + if (err != 0) { + nvlist_free(asru); + (void) topo_mod_seterrno(mod, EMOD_FMRI_NVL); + return (NULL); + } + + return (asru); +} + +static int +cpu_create(topo_mod_t *mod, tnode_t *pnode, const char *name, int chipid, + chip_t *chip) +{ + kstat_named_t *k; + topo_hdl_t *thp; + nvlist_t *fmri, *pfmri, *asru, *args; + tnode_t *cnode; + int i, err, nerr = 0; + + if (topo_node_range_create(mod, pnode, name, 0, + chip->chip_ncpustats) < 0) + return (-1); + + thp = topo_mod_handle(mod); + + for (i = 0; i <= chip->chip_ncpustats; i++) { + + if (chip->chip_cpustats[i] == NULL) + continue; + + if ((k = kstat_data_lookup(chip->chip_cpustats[i], "chip_id")) + == NULL || k->value.l != chipid) { + ++nerr; + continue; + } + + if ((k = kstat_data_lookup(chip->chip_cpustats[i], "clog_id")) + == NULL) { + ++nerr; + continue; + } + + args = pfmri = NULL; + if (topo_node_resource(pnode, &pfmri, &err) < 0 || + topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0 || + nvlist_add_nvlist(args, + TOPO_METH_FMRI_ARG_PARENT, pfmri) != 0) { + nvlist_free(pfmri); + nvlist_free(args); + ++nerr; + continue; + } + + fmri = topo_fmri_create(thp, FM_FMRI_SCHEME_HC, name, + (topo_instance_t)k->value.l, args, &err); + nvlist_free(pfmri); + nvlist_free(args); + if (fmri == NULL) { + ++nerr; + continue; + } + + if ((cnode = topo_node_bind(mod, pnode, name, i, fmri, + NULL)) == NULL) { + ++nerr; + nvlist_free(fmri); + continue; + } + nvlist_free(fmri); + + if ((asru = cpu_fmri_create(mod, i, NULL, 0)) != NULL) { + (void) topo_node_asru_set(cnode, asru, 0, &err); + nvlist_free(asru); + } else { + ++nerr; + } + (void) topo_node_fru_set(cnode, NULL, 0, &err); + } + + if (nerr != 0) + return (-1); + else + return (0); +} + +static int +nvprop_add(nvpair_t *nvp, const char *pgname, tnode_t *node) +{ + int err; + char *pname = nvpair_name(nvp); + + switch (nvpair_type(nvp)) { + case DATA_TYPE_BOOLEAN_VALUE: { + boolean_t val; + + if (nvpair_value_boolean_value(nvp, &val) == 0) { + (void) topo_prop_set_string(node, pgname, pname, + TOPO_PROP_SET_ONCE, (val ? "true" : "false"), &err); + } + return (0); + } + + case DATA_TYPE_UINT64: { + uint64_t val; + + if (nvpair_value_uint64(nvp, &val) == 0) { + (void) topo_prop_set_uint64(node, pgname, pname, + TOPO_PROP_SET_ONCE, val, &err); + } + return (0); + } + + case DATA_TYPE_STRING: { + char *str; + + if (nvpair_value_string(nvp, &str) == 0) + (void) topo_prop_set_string(node, pgname, pname, + TOPO_PROP_SET_ONCE, str, &err); + return (0); + } + + default: + return (-1); + } +} + +nvlist_t * +mem_fmri_create(topo_mod_t *mod) +{ + nvlist_t *asru; + + if (topo_mod_nvalloc(mod, &asru, NV_UNIQUE_NAME) != 0) + return (NULL); + + if (nvlist_add_string(asru, FM_FMRI_SCHEME, FM_FMRI_SCHEME_MEM) != 0 || + nvlist_add_uint8(asru, FM_VERSION, FM_MEM_SCHEME_VERSION) != 0) { + nvlist_free(asru); + return (NULL); + } + + return (asru); +} + +static int +cs_create(topo_mod_t *mod, tnode_t *pnode, const char *name, nvlist_t *mc) +{ + int i, err, nerr = 0; + nvpair_t *nvp; + tnode_t *csnode; + topo_hdl_t *thp; + nvlist_t *fmri, **csarr = NULL; + nvlist_t *pfmri, *args; + uint64_t csnum; + uint_t ncs; + + if (nvlist_lookup_nvlist_array(mc, "cslist", &csarr, &ncs) != 0) + return (-1); + + if (topo_node_range_create(mod, pnode, name, 0, ncs) < 0) + return (-1); + + thp = topo_mod_handle(mod); + for (i = 0; i < ncs; i++) { + if (nvlist_lookup_uint64(csarr[i], "num", &csnum) != 0) { + ++nerr; + continue; + } + + args = pfmri = NULL; + if (topo_node_resource(pnode, &pfmri, &err) < 0 || + topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0 || + nvlist_add_nvlist(args, + TOPO_METH_FMRI_ARG_PARENT, pfmri) != 0) { + nvlist_free(pfmri); + nvlist_free(args); + ++nerr; + continue; + } + fmri = topo_fmri_create(thp, FM_FMRI_SCHEME_HC, name, + csnum, args, &err); + nvlist_free(pfmri); + nvlist_free(args); + if (fmri == NULL) { + ++nerr; + continue; + } + + if ((csnode = topo_node_bind(mod, pnode, name, csnum, fmri, + NULL)) == NULL) { + nvlist_free(fmri); + ++nerr; + continue; + } + + nvlist_free(fmri); + + (void) topo_pgroup_create(csnode, CS_PGROUP, + TOPO_STABILITY_PRIVATE, &err); + + for (nvp = nvlist_next_nvpair(csarr[i], NULL); nvp != NULL; + nvp = nvlist_next_nvpair(csarr[i], nvp)) { + (void) nvprop_add(nvp, CS_PGROUP, csnode); + } + } + + if (nerr != 0) + return (-1); + else + return (0); +} + +static int +dimm_create(topo_mod_t *mod, tnode_t *pnode, const char *name, nvlist_t *mc) +{ + int i, err, nerr = 0; + nvpair_t *nvp; + tnode_t *dimmnode; + nvlist_t *fmri, *asru, **dimmarr = NULL; + nvlist_t *pfmri, *args; + uint64_t ldimmnum; + uint_t ndimm; + topo_hdl_t *thp; + + thp = topo_mod_handle(mod); + + if (nvlist_lookup_nvlist_array(mc, "dimmlist", &dimmarr, &ndimm) != 0) + return (-1); + + if (topo_node_range_create(mod, pnode, name, 0, ndimm) < 0) + return (-1); + + for (i = 0; i < ndimm; i++) { + if (nvlist_lookup_uint64(dimmarr[i], "num", &ldimmnum) != 0) { + ++nerr; + continue; + } + + args = pfmri = NULL; + if (topo_node_resource(pnode, &pfmri, &err) < 0 || + topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0 || + nvlist_add_nvlist(args, + TOPO_METH_FMRI_ARG_PARENT, pfmri) != 0) { + nvlist_free(pfmri); + nvlist_free(args); + ++nerr; + continue; + } + fmri = topo_fmri_create(thp, + FM_FMRI_SCHEME_HC, name, ldimmnum, args, &err); + nvlist_free(pfmri); + nvlist_free(args); + if (fmri == NULL) { + ++nerr; + continue; + } + + if ((dimmnode = topo_node_bind(mod, pnode, name, ldimmnum, fmri, + NULL)) == NULL) { + nvlist_free(fmri); + ++nerr; + continue; + } + + (void) topo_node_fru_set(dimmnode, fmri, 0, &err); + if ((asru = mem_fmri_create(mod)) != NULL) { + (void) topo_node_asru_set(dimmnode, asru, + TOPO_ASRU_COMPUTE, &err); + nvlist_free(asru); + } + + nvlist_free(fmri); + + (void) topo_pgroup_create(dimmnode, DIMM_PGROUP, + TOPO_STABILITY_PRIVATE, &err); + + for (nvp = nvlist_next_nvpair(dimmarr[i], NULL); nvp != NULL; + nvp = nvlist_next_nvpair(dimmarr[i], nvp)) { + if (nvprop_add(nvp, DIMM_PGROUP, dimmnode) == 0) { + continue; + } else if (nvpair_type(nvp) == DATA_TYPE_UINT64_ARRAY) { + uint64_t *csnumarr; + uint_t ncs; + int i; + + if (strcmp(nvpair_name(nvp), "csnums") != 0 || + nvpair_value_uint64_array(nvp, &csnumarr, + &ncs) != 0) + continue; + + for (i = 0; i < ncs; i++) { + char name[7]; + (void) snprintf(name, sizeof (name), + "csnum%d", i); + (void) topo_prop_set_uint64(dimmnode, + DIMM_PGROUP, name, + TOPO_PROP_SET_ONCE, + csnumarr[i], &err); + } + } + } + } + + if (nerr != 0) + return (-1); + else + return (0); +} + +static nvlist_t * +mc_lookup_by_mcid(topo_mod_t *mod, topo_instance_t id) +{ + mc_snapshot_info_t mcs; + void *buf = NULL; + + nvlist_t *nvl; + char path[64]; + int fd, err; + + (void) snprintf(path, sizeof (path), "/dev/mc/mc%d", id); + fd = open(path, O_RDONLY); + + if (fd == -1) { + topo_mod_dprintf(mod, "mc failed to open %s: %s\n", + path, strerror(errno)); + return (NULL); + } + + if (ioctl(fd, MC_IOC_SNAPSHOT_INFO, &mcs) == -1 || + (buf = topo_mod_alloc(mod, mcs.mcs_size)) == NULL || + ioctl(fd, MC_IOC_SNAPSHOT, buf) == -1) { + + topo_mod_dprintf(mod, "mc failed to snapshot %s: %s\n", + path, strerror(errno)); + + free(buf); + (void) close(fd); + return (NULL); + } + + (void) close(fd); + err = nvlist_unpack(buf, mcs.mcs_size, &nvl, 0); + topo_mod_free(mod, buf, mcs.mcs_size); + return (err ? NULL : nvl); +} + +static int +mc_create(topo_mod_t *mod, tnode_t *pnode, const char *name) +{ + int err, rc = 0; + tnode_t *mcnode; + nvlist_t *fmri; + nvpair_t *nvp; + nvlist_t *mc = NULL; + nvlist_t *pfmri, *args; + topo_hdl_t *thp; + + thp = topo_mod_handle(mod); + args = pfmri = NULL; + if (topo_node_resource(pnode, &pfmri, &err) < 0 || + topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0 || + nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_PARENT, pfmri) != 0) { + nvlist_free(pfmri); + nvlist_free(args); + return (-1); + } + fmri = topo_fmri_create(thp, FM_FMRI_SCHEME_HC, name, 0, args, &err); + nvlist_free(pfmri); + nvlist_free(args); + if (fmri == NULL) + return (-1); + + if (topo_node_range_create(mod, pnode, name, 0, 0) < 0) { + nvlist_free(fmri); + return (-1); + } + + /* + * Gather and create memory controller topology + */ + if ((mc = mc_lookup_by_mcid(mod, topo_node_instance(pnode))) == NULL || + (mcnode = topo_node_bind(mod, pnode, + name, 0, fmri, NULL)) == NULL) { + if (mc != NULL) + nvlist_free(mc); + topo_node_range_destroy(pnode, name); + nvlist_free(fmri); + return (-1); + } + + (void) topo_node_fru_set(mcnode, NULL, 0, &err); + nvlist_free(fmri); + + /* + * Add memory controller properties + */ + (void) topo_pgroup_create(mcnode, MC_PGROUP, + TOPO_STABILITY_PRIVATE, &err); + + for (nvp = nvlist_next_nvpair(mc, NULL); nvp != NULL; + nvp = nvlist_next_nvpair(mc, nvp)) { + if (nvprop_add(nvp, MC_PGROUP, mcnode) == 0) + continue; + else if (nvpair_type(nvp) == DATA_TYPE_NVLIST_ARRAY) + break; + } + + if (dimm_create(mod, mcnode, DIMM_NODE_NAME, mc) != 0 || + cs_create(mod, mcnode, CS_NODE_NAME, mc) != 0) + rc = -1; + + nvlist_free(mc); + return (rc); +} + +static int +chip_create(topo_mod_t *mod, tnode_t *pnode, const char *name, + topo_instance_t min, topo_instance_t max, chip_t *chip) +{ + int i, nerr = 0; + kstat_t *ksp; + ulong_t *chipmap; + tnode_t *cnode; + nvlist_t *pfmri, *fmri, *args; + topo_hdl_t *thp; + + thp = topo_mod_handle(mod); + + if ((chipmap = topo_mod_zalloc(mod, BT_BITOUL(chip->chip_ncpustats) * + sizeof (ulong_t))) == NULL) + return (topo_mod_seterrno(mod, EMOD_NOMEM)); + + for (i = min; i <= MAX(max, chip->chip_ncpustats); i++) { + + if (i < min || i > max) + break; + + if ((ksp = kstat_lookup(chip->chip_kc, "cpu_info", i, NULL)) == + NULL || kstat_read(chip->chip_kc, ksp, NULL) < 0) + continue; + + chip->chip_cpustats[i] = ksp; + } + + for (i = 0; i <= chip->chip_ncpustats; i++) { + kstat_named_t *k; + int err, chipid; + + if ((ksp = chip->chip_cpustats[i]) == NULL) + continue; + + if ((k = kstat_data_lookup(ksp, "chip_id")) == NULL) { + ++nerr; + continue; + } + + chipid = k->value.l; + if (BT_TEST(chipmap, chipid)) + continue; + + if (chipid < min || chipid > max) + continue; + + args = pfmri = NULL; + if (topo_node_resource(pnode, &pfmri, &err) < 0 || + topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0 || + nvlist_add_nvlist(args, + TOPO_METH_FMRI_ARG_PARENT, pfmri) != 0) { + nvlist_free(pfmri); + nvlist_free(args); + ++nerr; + continue; + } + fmri = topo_fmri_create(thp, + FM_FMRI_SCHEME_HC, name, chipid, args, &err); + nvlist_free(pfmri); + nvlist_free(args); + if (fmri == NULL) { + ++nerr; + continue; + } + + if ((cnode = topo_node_bind(mod, pnode, name, chipid, fmri, + NULL)) == NULL) { + ++nerr; + nvlist_free(fmri); + continue; + } + + (void) topo_node_fru_set(cnode, fmri, 0, &err); + + nvlist_free(fmri); + + (void) topo_pgroup_create(cnode, CHIP_PGROUP, + TOPO_STABILITY_PRIVATE, &err); + (void) chip_strprop(cnode, ksp, CHIP_VENDOR_ID); + (void) chip_longprop(cnode, ksp, CHIP_FAMILY); + (void) chip_longprop(cnode, ksp, CHIP_MODEL); + (void) chip_longprop(cnode, ksp, CHIP_STEPPING); + + if (mc_create(mod, cnode, MC_NODE_NAME) != 0 || + cpu_create(mod, cnode, CPU_NODE_NAME, chipid, chip) != 0) + ++nerr; + } + + topo_mod_free(mod, chipmap, BT_BITOUL(chip->chip_ncpustats) * + sizeof (ulong_t)); + + if (nerr != 0) + (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM); + + return (0); +} + +static int +chip_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, + topo_instance_t min, topo_instance_t max, void *arg) +{ + chip_t *chip = (chip_t *)arg; + + if (strcmp(name, "chip") == 0) + return (chip_create(mod, pnode, name, min, max, chip)); + + return (0); +} diff --git a/usr/src/lib/fm/topo/modules/i86pc/chip/chip.h b/usr/src/lib/fm/topo/modules/i86pc/chip/chip.h new file mode 100644 index 0000000000..269dfa4f37 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/i86pc/chip/chip.h @@ -0,0 +1,70 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _CHIP_H +#define _CHIP_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <kstat.h> +#include <libnvpair.h> +#include <fm/libtopo.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define CHIP_VERSION TOPO_VERSION + +#define MC_NODE_NAME "memory-controller" +#define CPU_NODE_NAME "cpu" +#define CS_NODE_NAME "chip-select" +#define DIMM_NODE_NAME "dimm" + +#define CHIP_PGROUP "chip-properties" +#define CS_PGROUP "chip-select-properties" +#define MC_PGROUP "memory-contoller-properties" +#define DIMM_PGROUP "dimm-properties" + +/* + * CHIP_PGROUP properties + */ +#define CHIP_VENDOR_ID "vendor-id" +#define CHIP_FAMILY "family" +#define CHIP_MODEL "model" +#define CHIP_STEPPING "stepping" + +typedef struct chip { + kstat_ctl_t *chip_kc; + kstat_t **chip_cpustats; + uint_t chip_ncpustats; +} chip_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _CHIP_H */ diff --git a/usr/src/lib/fm/topo/modules/i86pc/hostbridge/Makefile b/usr/src/lib/fm/topo/modules/i86pc/hostbridge/Makefile new file mode 100644 index 0000000000..c333b37290 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/i86pc/hostbridge/Makefile @@ -0,0 +1,35 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" + +MODULE = hostbridge +ARCH = i86pc +CLASS = arch +HBSRCS = hostbridge.c did.c did_hash.c did_props.c util.c +MODULESRCS = $(HBSRCS) hb_i86pc.c + +include ../../Makefile.plugin + +LDLIBS += -ldevinfo diff --git a/usr/src/lib/fm/topo/modules/i86pc/hostbridge/hb_i86pc.c b/usr/src/lib/fm/topo/modules/i86pc/hostbridge/hb_i86pc.c new file mode 100644 index 0000000000..5fe5bd5c1e --- /dev/null +++ b/usr/src/lib/fm/topo/modules/i86pc/hostbridge/hb_i86pc.c @@ -0,0 +1,127 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <fm/topo_mod.h> +#include <libdevinfo.h> +#include "pcibus.h" +#include "hostbridge.h" +#include "did.h" +#include "util.h" + +extern did_hash_t *Didhash; + +static int +hb_process(tnode_t *ptn, topo_instance_t hbi, di_node_t bn) +{ + tnode_t *hb; + + if (did_create(Didhash, bn, 0, hbi, NO_RC, TRUST_BDF) == NULL) + return (-1); + if ((hb = pcihostbridge_declare(ptn, bn, hbi)) == NULL) + return (-1); + return (topo_mod_enumerate(HbHdl, + hb, PCI_BUS, PCI_BUS, 0, MAX_HB_BUSES)); +} + +static int +rc_process(tnode_t *ptn, topo_instance_t hbi, di_node_t bn) +{ + tnode_t *hb; + tnode_t *rc; + + if (did_create(Didhash, bn, 0, hbi, hbi, TRUST_BDF) == NULL) + return (-1); + if ((hb = pciexhostbridge_declare(ptn, bn, hbi)) == NULL) + return (-1); + if ((rc = pciexrc_declare(hb, bn, hbi)) == NULL) + return (-1); + return (topo_mod_enumerate(HbHdl, + rc, PCI_BUS, PCIEX_BUS, 0, MAX_HB_BUSES)); +} + + +int +pci_hostbridges_find(tnode_t *ptn) +{ + di_node_t devtree; + di_node_t pnode; + char *eplain; + int hbcnt = 0; + + /* Scan for buses, top-level devinfo nodes with the right driver */ + devtree = di_init("/", DINFOCPYALL); + if (devtree == DI_NODE_NIL) { + topo_mod_dprintf(HbHdl, "devinfo init failed."); + topo_node_range_destroy(ptn, HOSTBRIDGE); + return (0); + } + + /* + * By default we do not enumerate generic PCI on x86 + */ + eplain = getenv("TOPOENUMPLAINPCI"); + if (eplain != NULL) { + pnode = di_drv_first_node(PCI, devtree); + while (pnode != DI_NODE_NIL) { + if (hb_process(ptn, hbcnt++, pnode) < 0) { + di_fini(devtree); + topo_node_range_destroy(ptn, HOSTBRIDGE); + return (topo_mod_seterrno(HbHdl, + EMOD_PARTIAL_ENUM)); + } + pnode = di_drv_next_node(pnode); + } + } + + pnode = di_drv_first_node(NPE, devtree); + while (pnode != DI_NODE_NIL) { + if (rc_process(ptn, hbcnt++, pnode) < 0) { + di_fini(devtree); + topo_node_range_destroy(ptn, HOSTBRIDGE); + return (topo_mod_seterrno(HbHdl, EMOD_PARTIAL_ENUM)); + } + pnode = di_drv_next_node(pnode); + } + di_fini(devtree); + return (0); +} + +/*ARGSUSED*/ +int +platform_hb_enum(tnode_t *parent, const char *name, + topo_instance_t imin, topo_instance_t imax) +{ + return (pci_hostbridges_find(parent)); +} + +/*ARGSUSED*/ +int +platform_hb_label(tnode_t *node, nvlist_t *in, nvlist_t **out) +{ + return (labelmethod_inherit(HbHdl, node, in, out)); +} diff --git a/usr/src/lib/fm/topo/modules/i86pc/pcibus/Makefile b/usr/src/lib/fm/topo/modules/i86pc/pcibus/Makefile new file mode 100644 index 0000000000..7c38cceaed --- /dev/null +++ b/usr/src/lib/fm/topo/modules/i86pc/pcibus/Makefile @@ -0,0 +1,37 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +MODULE = pcibus +ARCH = i86pc +CLASS = arch +PCISRCS = pcibus.c did.c did_hash.c did_props.c util.c pcibus_labels.c +MODULESRCS = $(PCISRCS) pci_i86pc.c + +include ../../Makefile.plugin + +LDLIBS += -ldevinfo diff --git a/usr/src/lib/fm/topo/modules/i86pc/pcibus/pci_i86pc.c b/usr/src/lib/fm/topo/modules/i86pc/pcibus/pci_i86pc.c new file mode 100644 index 0000000000..0e81f4e373 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/i86pc/pcibus/pci_i86pc.c @@ -0,0 +1,42 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <fm/topo_mod.h> + +#include "pcibus.h" +#include "pcibus_labels.h" + +slotnm_rewrite_t *Slot_Rewrites = NULL; +physlot_names_t *Physlot_Names = NULL; +missing_names_t *Missing_Names = NULL; + +int +platform_pci_label(tnode_t *node, nvlist_t *in, nvlist_t **out) +{ + return (pci_label_cmn(node, in, out)); +} diff --git a/usr/src/cmd/fm/topo/plugins/common/cpu/Makefile b/usr/src/lib/fm/topo/modules/sun4/chip/Makefile.chip index 266924d296..1b59cc44cf 100644 --- a/usr/src/cmd/fm/topo/plugins/common/cpu/Makefile +++ b/usr/src/lib/fm/topo/modules/sun4/chip/Makefile.chip @@ -20,15 +20,23 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" -MODULE = cpu -CLASS = common -SRCS = cpu.c +MODULE = chip +CLASS = arch +SUN4DIR = ../../sun4/$(MODULE) +MODULESRCS = chip.c include ../../Makefile.plugin LDLIBS += -lkstat + +%.o: $(SUN4DIR)/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + +%.ln: $(SUN4DIR)/%.c + $(LINT.c) -c $< diff --git a/usr/src/lib/fm/topo/modules/sun4/chip/chip.c b/usr/src/lib/fm/topo/modules/sun4/chip/chip.c new file mode 100644 index 0000000000..85d09da2a4 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/sun4/chip/chip.c @@ -0,0 +1,285 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <limits.h> +#include <alloca.h> +#include <kstat.h> +#include <errno.h> +#include <libnvpair.h> +#include <sys/types.h> +#include <sys/bitmap.h> +#include <sys/processor.h> +#include <sys/param.h> +#include <sys/fm/protocol.h> +#include <sys/systeminfo.h> +#include <fm/topo_mod.h> + +/* + * Enumerates the processing chips, or sockets, (as distinct from cores) in a + * system. For each chip found, the necessary nodes (one or more cores, and + * possibly a memory controller) are constructed underneath. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define CHIP_VERSION TOPO_VERSION +#define CPU_NODE_NAME "cpu" +#define CHIP_NODE_NAME "chip" + +typedef struct chip { + kstat_ctl_t *chip_kc; + kstat_t **chip_cpustats; + uint_t chip_ncpustats; +} chip_t; + +static int chip_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, + topo_instance_t, void *); + +const topo_modinfo_t chip_info = + { "chip", CHIP_VERSION, chip_enum, NULL}; + +int +_topo_init(topo_mod_t *mod) +{ + chip_t *chip; + + topo_mod_setdebug(mod, TOPO_DBG_ALL); + topo_mod_dprintf(mod, "initializing chip enumerator\n"); + + if ((chip = topo_mod_zalloc(mod, sizeof (chip_t))) == NULL) + return (-1); + + if ((chip->chip_kc = kstat_open()) == NULL) { + topo_mod_dprintf(mod, "kstat_open failed: %s\n", + strerror(errno)); + topo_mod_free(mod, chip, sizeof (chip_t)); + return (-1); + } + + chip->chip_ncpustats = sysconf(_SC_CPUID_MAX); + if ((chip->chip_cpustats = topo_mod_zalloc(mod, ( + chip->chip_ncpustats + 1) * sizeof (kstat_t *))) == NULL) { + (void) kstat_close(chip->chip_kc); + topo_mod_free(mod, chip, sizeof (chip_t)); + return (-1); + } + + if (topo_mod_register(mod, &chip_info, (void *)chip) != 0) { + topo_mod_dprintf(mod, "failed to register hc: " + "%s\n", topo_mod_errmsg(mod)); + topo_mod_free(mod, chip->chip_cpustats, + (chip->chip_ncpustats + 1) * sizeof (kstat_t *)); + (void) kstat_close(chip->chip_kc); + topo_mod_free(mod, chip, sizeof (chip_t)); + return (-1); + } + + return (0); +} + +void +_topo_fini(topo_mod_t *mod) +{ + chip_t *chip; + + chip = topo_mod_private(mod); + + if (chip->chip_cpustats != NULL) + topo_mod_free(mod, chip->chip_cpustats, + (chip->chip_ncpustats + 1) * sizeof (kstat_t *)); + + (void) kstat_close(chip->chip_kc); + topo_mod_free(mod, chip, sizeof (chip_t)); + + topo_mod_unregister(mod); +} + +static int +cpu_kstat_init(chip_t *chip, int i) +{ + kstat_t *ksp; + + if (chip->chip_cpustats[i] == NULL) { + if ((ksp = kstat_lookup(chip->chip_kc, "cpu_info", i, NULL)) == + NULL || kstat_read(chip->chip_kc, ksp, NULL) < 0) + return (-1); + + chip->chip_cpustats[i] = ksp; + } else { + ksp = chip->chip_cpustats[i]; + } + + return (ksp->ks_instance); +} + +static nvlist_t * +cpu_fmri_create(topo_mod_t *mod, uint32_t cpuid, char *s, uint8_t cpumask) +{ + int err; + nvlist_t *asru; + + if (topo_mod_nvalloc(mod, &asru, NV_UNIQUE_NAME) != 0) + return (NULL); + + err = nvlist_add_uint8(asru, FM_VERSION, FM_CPU_SCHEME_VERSION); + err |= nvlist_add_string(asru, FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU); + err |= nvlist_add_uint32(asru, FM_FMRI_CPU_ID, cpuid); + err |= nvlist_add_uint8(asru, FM_FMRI_CPU_MASK, cpumask); + if (s != NULL) + err |= nvlist_add_string(asru, FM_FMRI_CPU_SERIAL_ID, s); + if (err != 0) { + nvlist_free(asru); + (void) topo_mod_seterrno(mod, EMOD_FMRI_NVL); + return (NULL); + } + + return (asru); +} + +/*ARGSUSED*/ +static int +cpu_create(topo_mod_t *mod, tnode_t *rnode, const char *name, + topo_instance_t min, topo_instance_t max, chip_t *chip) +{ + int i, err, chip_id, nerr = 0; + char *s, sbuf[21]; + tnode_t *cnode; + kstat_named_t *ks, *kf; + nvlist_t *pfmri, *fmri, *asru; + nvlist_t *args = NULL; + topo_hdl_t *thp; + + /* + * Override what was created for us + */ + topo_node_range_destroy(rnode, name); + if (topo_node_range_create(mod, rnode, name, 0, chip->chip_ncpustats) + < 0) + return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM)); + + thp = topo_mod_handle(mod); + for (i = 0; i <= chip->chip_ncpustats; i++) { + + if ((chip_id = cpu_kstat_init(chip, i)) < 0) + continue; + + if ((ks = kstat_data_lookup(chip->chip_cpustats[i], + "device_ID")) != NULL) { + (void) snprintf(sbuf, 21, "%llX", ks->value.ui64); + s = sbuf; + } else { + s = NULL; + } + + pfmri = NULL; + if (topo_node_resource(rnode, &pfmri, &err) < 0 || + topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0) { + nvlist_free(pfmri); + ++nerr; + continue; + } + err = nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_PARENT, pfmri); + if (err != 0 || + (s != NULL && + nvlist_add_string(args, TOPO_METH_FMRI_ARG_SER, s) != 0)) { + nvlist_free(pfmri); + nvlist_free(args); + ++nerr; + continue; + } + nvlist_free(pfmri); + + fmri = topo_fmri_create(thp, FM_FMRI_SCHEME_HC, + name, (topo_instance_t)chip_id, args, &err); + nvlist_free(args); + if (fmri == NULL || (cnode = topo_node_bind(mod, + rnode, name, i, fmri, NULL)) == NULL) { + ++nerr; + nvlist_free(fmri); + continue; + } + nvlist_free(fmri); + + if ((asru = cpu_fmri_create(mod, i, s, 0)) != NULL) { + (void) topo_node_asru_set(cnode, asru, 0, &err); + nvlist_free(asru); + } else { + ++nerr; + } + + /* + * We look for a cpu_fru kstat. If one is available and + * it contains something useful, use it as the label and + * and the FRU. + * + * This is a problem for platforms that do not properly + * support the cpu_fru kstat like Ontario or if + * we start exporting a different type of FRU label + */ + if ((kf = kstat_data_lookup(chip->chip_cpustats[i], "cpu_fru")) + != NULL && strcmp(KSTAT_NAMED_STR_PTR(kf), + "hc:///component=") != 0) { + nvlist_t *fru; + + if (topo_fmri_str2nvl(thp, KSTAT_NAMED_STR_PTR(kf), + &fru, &err) == 0) { + (void) topo_node_fru_set(cnode, fru, 0, &err); + nvlist_free(fru); + } + + (void) topo_node_label_set(cnode, + KSTAT_NAMED_STR_PTR(kf), &err); + } else { + (void) topo_node_label_set(cnode, NULL, &err); + } + } + + if (nerr != 0) + return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM)); + else + return (0); +} + +static int +chip_enum(topo_mod_t *mod, tnode_t *rnode, const char *name, + topo_instance_t min, topo_instance_t max, void *arg) +{ + chip_t *chip = (chip_t *)arg; + + if (strcmp(name, CPU_NODE_NAME) == 0) + return (cpu_create(mod, rnode, name, min, max, chip)); + + return (0); +} diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V445/platform.topo b/usr/src/lib/fm/topo/modules/sun4/hostbridge/Makefile.hb index 0658cf339a..ccd5d4ec9a 100644 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V445/platform.topo +++ b/usr/src/lib/fm/topo/modules/sun4/hostbridge/Makefile.hb @@ -23,17 +23,22 @@ # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -#ident "%Z%%M% %I% %E% SMI" +# ident "%Z%%M% %I% %E% SMI" -/motherboard0/cpumodule0/cpu[0] - PLAT-FRU = hc:///component=MB/C0 -/motherboard0/cpumodule1/cpu[1] - PLAT-FRU = hc:///component=MB/C1 -/motherboard0/cpumodule2/cpu[2] - PLAT-FRU = hc:///component=MB/C2 -/motherboard0/cpumodule3/cpu[3] - PLAT-FRU = hc:///component=MB/C3 -/motherboard0/hostbridge0/pciexrc[0] - DEV = /pci@1e,600000 -/motherboard0/hostbridge0/pciexrc[1] - DEV = /pci@1f,700000 +MODULE = hostbridge +CLASS = arch +SUN4DIR = ../../sun4/$(MODULE) +HBSRCS = hostbridge.c hb_sun4.c did.c did_hash.c did_props.c util.c +MODULESRCS = $(HBSRCS) hb_$(ARCH).c + +include ../../Makefile.plugin + +LDLIBS += -ldevinfo +CPPFLAGS += -I$(SUN4DIR) + +%.o: $(SUN4DIR)/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + +%.ln: $(SUN4DIR)/%.c + $(LINT.c) -c $< diff --git a/usr/src/lib/fm/topo/modules/sun4/hostbridge/hb_sun4.c b/usr/src/lib/fm/topo/modules/sun4/hostbridge/hb_sun4.c new file mode 100644 index 0000000000..6b67773fc9 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/sun4/hostbridge/hb_sun4.c @@ -0,0 +1,308 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <string.h> +#include <fm/topo_mod.h> +#include <libdevinfo.h> +#include <sys/param.h> +#include <sys/systeminfo.h> + +#include "hb_sun4.h" +#include "util.h" +#include "topo_error.h" +#include "hostbridge.h" +#include "pcibus.h" +#include "did.h" + +extern did_hash_t *Didhash; + +busorrc_t * +busorrc_new(const char *bus_addr, di_node_t di) +{ + busorrc_t *pp; + char *comma; + char *bac; + int e; + + if ((pp = topo_mod_zalloc(HbHdl, sizeof (busorrc_t))) == NULL) + return (NULL); + pp->br_din = di; + bac = topo_mod_strdup(HbHdl, bus_addr); + if ((comma = strchr(bac, ',')) != NULL) + *comma = '\0'; + pp->br_ba_bc = strtonum(HbHdl, bac, &e); + if (e < 0) { + topo_mod_dprintf(HbHdl, + "Trouble interpreting bus_addr before comma.\n"); + if (comma != NULL) + *comma = ','; + topo_mod_strfree(HbHdl, bac); + topo_mod_free(HbHdl, pp, sizeof (busorrc_t)); + return (NULL); + } + if (comma == NULL) { + pp->br_ba_ac = 0; + topo_mod_strfree(HbHdl, bac); + return (pp); + } + pp->br_ba_ac = strtonum(HbHdl, comma + 1, &e); + if (e < 0) { + topo_mod_dprintf(HbHdl, + "Trouble interpreting bus_addr after comma.\n"); + *comma = ','; + topo_mod_strfree(HbHdl, bac); + topo_mod_free(HbHdl, pp, sizeof (busorrc_t)); + return (NULL); + } + *comma = ','; + topo_mod_strfree(HbHdl, bac); + return (pp); +} + +void +busorrc_insert(busorrc_t **head, busorrc_t *new) +{ + busorrc_t *ppci, *pci; + + topo_mod_dprintf(HbHdl, + "inserting (%x,%x)\n", new->br_ba_bc, new->br_ba_ac); + + /* No entries yet? */ + if (*head == NULL) { + *head = new; + return; + } + + ppci = NULL; + pci = *head; + + while (pci != NULL) { + if (new->br_ba_ac == pci->br_ba_ac) + if (new->br_ba_bc < pci->br_ba_bc) + break; + if (new->br_ba_ac < pci->br_ba_ac) + break; + ppci = pci; + pci = pci->br_nextbus; + } + if (ppci == NULL) { + new->br_nextbus = pci; + pci->br_prevbus = new; + *head = new; + } else { + new->br_nextbus = ppci->br_nextbus; + if (new->br_nextbus != NULL) + new->br_nextbus->br_prevbus = new; + ppci->br_nextbus = new; + new->br_prevbus = ppci; + } +} + +int +busorrc_add(busorrc_t **list, di_node_t n) +{ + busorrc_t *nb; + char *ba; + + topo_mod_dprintf(HbHdl, "busorrc_add\n"); + ba = di_bus_addr(n); + if (ba == NULL || + (nb = busorrc_new(ba, n)) == NULL) { + topo_mod_dprintf(HbHdl, "busorrc_new() failed.\n"); + return (-1); + } + busorrc_insert(list, nb); + return (0); +} + +void +busorrc_free(busorrc_t *pb) +{ + if (pb == NULL) + return; + busorrc_free(pb->br_nextbus); + topo_mod_free(HbHdl, pb, sizeof (busorrc_t)); +} + +tnode_t * +hb_process(tnode_t *ptn, topo_instance_t hbi, topo_instance_t bi, di_node_t bn) +{ + tnode_t *hb; + + if ((hb = pcihostbridge_declare(ptn, bn, hbi)) == NULL) + return (NULL); + if (topo_mod_enumerate(HbHdl, hb, PCI_BUS, PCI_BUS, bi, bi) == 0) + return (hb); + return (NULL); +} + +tnode_t * +rc_process(tnode_t *ptn, topo_instance_t rci, di_node_t bn) +{ + tnode_t *rc; + + if ((rc = pciexrc_declare(ptn, bn, rci)) == NULL) + return (NULL); + if (topo_mod_enumerate(HbHdl, + rc, PCI_BUS, PCIEX_BUS, 0, MAX_HB_BUSES) == 0) + return (rc); + return (NULL); +} + +/* + * declare_exbuses() assumes the elements in the provided busorrc list + * are sorted thusly: + * + * (Hostbridge #0, Root Complex #0, ExBus #0) + * (Hostbridge #0, Root Complex #0, ExBus #1) + * ... + * (Hostbridge #0, Root Complex #0, ExBus #(buses/rc)) + * (Hostbridge #0, Root Complex #1, ExBus #0) + * ... + * (Hostbridge #0, Root Complex #1, ExBus #(buses/rc)) + * ... + * ... + * (Hostbridge #0, Root Complex #(rcs/hostbridge), ExBus #(buses/rc)) + * (Hostbridge #1, Root Complex #0, ExBus #0) + * ... + * ... + * ... + * ... + * (Hostbridge #nhb, Root Complex #(rcs/hostbridge), ExBus #(buses/rc)) + */ +int +declare_exbuses(busorrc_t *list, tnode_t *ptn, int nhb, int nrc) +{ + tnode_t **rcs; + tnode_t **hb; + busorrc_t *p; + int br, rc; + + /* + * Allocate an array to point at the hostbridge tnode_t pointers. + */ + if ((hb = topo_mod_zalloc(HbHdl, nhb * sizeof (tnode_t *))) == NULL) + return (topo_mod_seterrno(HbHdl, ETOPO_NOMEM)); + + /* + * Allocate an array to point at the root complex tnode_t pointers. + */ + if ((rcs = topo_mod_zalloc(HbHdl, nrc * sizeof (tnode_t *))) == NULL) + return (topo_mod_seterrno(HbHdl, ETOPO_NOMEM)); + + br = rc = 0; + for (p = list; p != NULL; p = p->br_nextbus) { + topo_mod_dprintf(HbHdl, + "declaring (%x,%x)\n", p->br_ba_bc, p->br_ba_ac); + + if (did_create(Didhash, p->br_din, 0, br, rc, rc) == NULL) + return (-1); + + if (hb[br] == NULL) { + hb[br] = pciexhostbridge_declare(ptn, p->br_din, br); + if (hb[br] == NULL) + return (-1); + } + if (rcs[rc] == NULL) { + rcs[rc] = rc_process(hb[br], rc, p->br_din); + if (rcs[rc] == NULL) + return (-1); + } else { + if (topo_mod_enumerate(HbHdl, + rcs[rc], PCI_BUS, PCIEX_BUS, 0, MAX_HB_BUSES) < 0) + return (-1); + } + rc++; + if (rc == nrc) { + rc = 0; + br++; + if (br == nhb) + br = 0; + } + } + topo_mod_free(HbHdl, rcs, nrc * sizeof (tnode_t *)); + topo_mod_free(HbHdl, hb, nhb * sizeof (tnode_t *)); + return (0); +} + +/* + * declare_buses() assumes the elements in the provided busorrc list + * are sorted thusly: + * + * (Hostbridge #0, Bus #0) + * (Hostbridge #1, Bus #0) + * ... + * (Hostbridge #nhb, Bus #0) + * (Hostbridge #0, Bus #1) + * ... + * ... + * (Hostbridge #nhb, Bus #(buses/hostbridge)) + */ +int +declare_buses(busorrc_t *list, tnode_t *ptn, int nhb) +{ + busorrc_t *p; + tnode_t **hb; + did_t *link; + int br, bus; + + /* + * Allocate an array to point at the hostbridge tnode_t pointers. + */ + if ((hb = topo_mod_zalloc(HbHdl, nhb * sizeof (tnode_t *))) == NULL) + return (topo_mod_seterrno(HbHdl, EMOD_NOMEM)); + + br = bus = 0; + for (p = list; p != NULL; p = p->br_nextbus) { + topo_mod_dprintf(HbHdl, + "declaring (%x,%x)\n", p->br_ba_bc, p->br_ba_ac); + + if ((link = + did_create(Didhash, p->br_din, 0, br, NO_RC, bus)) == NULL) + return (-1); + + if (hb[br] == NULL) { + hb[br] = hb_process(ptn, br, bus, p->br_din); + if (hb[br] == NULL) + return (-1); + } else { + did_link_set(hb[br], link); + if (topo_mod_enumerate(HbHdl, + hb[br], PCI_BUS, PCI_BUS, bus, bus) < 0) { + return (-1); + } + } + br++; + if (br == nhb) { + br = 0; + bus++; + } + } + topo_mod_free(HbHdl, hb, nhb * sizeof (tnode_t *)); + return (0); +} diff --git a/usr/src/lib/fm/topo/modules/sun4/hostbridge/hb_sun4.h b/usr/src/lib/fm/topo/modules/sun4/hostbridge/hb_sun4.h new file mode 100644 index 0000000000..7efc189caf --- /dev/null +++ b/usr/src/lib/fm/topo/modules/sun4/hostbridge/hb_sun4.h @@ -0,0 +1,63 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _HB_SUN4_H +#define _HB_SUN4_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <fm/topo_mod.h> +#include <sys/types.h> +#include <libdevinfo.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct busorrc { + struct busorrc *br_nextbus; /* next bus or root complex */ + struct busorrc *br_prevbus; /* previous bus or root complex */ + ulong_t br_ba_ac; /* bus addr, after the comma */ + ulong_t br_ba_bc; /* bus addr, before the comma */ + di_node_t br_din; /* devinfo node */ +} busorrc_t; + +extern busorrc_t *busorrc_new(const char *, di_node_t); +extern void busorrc_insert(busorrc_t **, busorrc_t *); +extern int busorrc_add(busorrc_t **, di_node_t); +extern void busorrc_free(busorrc_t *); + +extern tnode_t *hb_process(tnode_t *, + topo_instance_t, topo_instance_t, di_node_t); +extern tnode_t *rc_process(tnode_t *, topo_instance_t, di_node_t); +extern int declare_buses(busorrc_t *, tnode_t *, int); +extern int declare_exbuses(busorrc_t *, tnode_t *, int, int); + +#ifdef __cplusplus +} +#endif + +#endif /* _HB_SUN4_H */ diff --git a/usr/src/lib/fm/topo/modules/sun4/ioboard/Makefile.iob b/usr/src/lib/fm/topo/modules/sun4/ioboard/Makefile.iob new file mode 100644 index 0000000000..398598e8b8 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/sun4/ioboard/Makefile.iob @@ -0,0 +1,44 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" + +MODULE = ioboard +CLASS = plat +SUN4DIR = ../../sun4/$(MODULE) +IOBSRCS = ioboard.c did.c did_hash.c did_props.c util.c +MODULESRCS = $(IOBSRCS) iob_platform.c + +include ../../Makefile.plugin + +LDLIBS += -ldevinfo +CPPFLAGS += -I$(SUN4DIR) + +%.o: $(SUN4DIR)/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + +%.ln: $(SUN4DIR)/%.c + $(LINT.c) -c $< diff --git a/usr/src/lib/fm/topo/modules/sun4/ioboard/ioboard.c b/usr/src/lib/fm/topo/modules/sun4/ioboard/ioboard.c new file mode 100644 index 0000000000..7dd48e6563 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/sun4/ioboard/ioboard.c @@ -0,0 +1,349 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <string.h> +#include <sys/fm/protocol.h> +#include <fm/topo_mod.h> +#include <libdevinfo.h> +#include <limits.h> +#include <sys/param.h> +#include <sys/systeminfo.h> + +#include "hostbridge.h" +#include "ioboard.h" +#include "did.h" +#include "did_props.h" +#include "util.h" + +/* + * ioboard.c + * Generic code shared by all the ioboard enumerators + */ +di_prom_handle_t Promtree = DI_PROM_HANDLE_NIL; +topo_mod_t *IobHdl; + +did_hash_t *Didhash; + +static void iob_release(topo_mod_t *, tnode_t *); +static int iob_contains(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); +static int iob_present(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); +static int iob_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, + topo_instance_t, void *); +static int iob_label(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); + +extern int platform_iob_enum(tnode_t *, topo_instance_t, topo_instance_t); +extern int platform_iob_label(tnode_t *, nvlist_t *, nvlist_t **); + +extern txprop_t IOB_common_props[]; +extern int IOB_propcnt; + +const topo_modinfo_t Iob_info = + { IOBOARD, IOB_ENUMR_VERS, iob_enum, iob_release }; + +const topo_method_t Iob_methods[] = { + { "iob_contains", "ioboard element contains other element", + IOB_ENUMR_VERS, TOPO_STABILITY_INTERNAL, iob_contains }, + { "iob_present", "ioboard element currently present", + IOB_ENUMR_VERS, TOPO_STABILITY_INTERNAL, iob_present }, + { TOPO_METH_LABEL, TOPO_METH_LABEL_DESC, + TOPO_METH_LABEL_VERSION, TOPO_STABILITY_INTERNAL, iob_label }, + { NULL } +}; + +void +_topo_init(topo_mod_t *modhdl) +{ + /* + * Turn on module debugging output + */ + if (getenv("TOPOIOBDBG") != NULL) + topo_mod_setdebug(modhdl, TOPO_DBG_ALL); + topo_mod_dprintf(modhdl, "initializing ioboard enumerator\n"); + + if ((Promtree = di_prom_init()) == DI_PROM_HANDLE_NIL) { + topo_mod_dprintf(modhdl, + "Ioboard enumerator: di_prom_handle_init failed.\n"); + return; + } + if ((Didhash = did_hash_init(modhdl)) == NULL) { + di_prom_fini(Promtree); + topo_mod_dprintf(modhdl, + "Hash initialization for ioboard enumerator failed.\n"); + return; + } + IobHdl = modhdl; + topo_mod_register(modhdl, &Iob_info, NULL); + topo_mod_dprintf(modhdl, "Ioboard enumr initd\n"); +} + +void +_topo_fini(topo_mod_t *modhdl) +{ + did_hash_fini(Didhash); + di_prom_fini(Promtree); + topo_mod_unregister(modhdl); +} + +/*ARGSUSED*/ +static int +iob_contains(topo_mod_t *mp, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + return (0); +} + +/*ARGSUSED*/ +static int +iob_present(topo_mod_t *mp, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + return (0); +} + +static int +iob_label(topo_mod_t *mp, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + if (version > TOPO_METH_LABEL_VERSION) + return (topo_mod_seterrno(mp, EMOD_VER_NEW)); + return (platform_iob_label(node, in, out)); +} + +static topo_mod_t * +hb_enumr_load(topo_mod_t *mp, tnode_t *parent) +{ + topo_mod_t *rp = NULL; + char *plat, *mach; + char *hbpath; + char *rootdir; + int err; + + plat = mach = NULL; + + if (topo_prop_get_string(parent, + TOPO_PGROUP_SYSTEM, TOPO_PROP_PLATFORM, &plat, &err) < 0) { + (void) topo_mod_seterrno(mp, err); + return (NULL); + } + if (topo_prop_get_string(parent, + TOPO_PGROUP_SYSTEM, TOPO_PROP_MACHINE, &mach, &err) < 0) { + (void) topo_mod_seterrno(mp, err); + return (NULL); + } + hbpath = topo_mod_alloc(mp, PATH_MAX); + rootdir = topo_mod_rootdir(mp); + (void) snprintf(hbpath, + PATH_MAX, PATH_TO_HB_ENUM, rootdir ? rootdir : "", plat); + + if ((rp = topo_mod_load(mp, hbpath)) == NULL) { + topo_mod_dprintf(IobHdl, + "%s enumerator could not load %s.\n", IOBOARD, hbpath); + (void) snprintf(hbpath, + PATH_MAX, PATH_TO_HB_ENUM, rootdir ? rootdir : "", mach); + if ((rp = topo_mod_load(mp, hbpath)) == NULL) { + topo_mod_dprintf(IobHdl, + "%s enumerator could not load %s.\n", + IOBOARD, hbpath); + } + } + topo_mod_strfree(mp, plat); + topo_mod_strfree(mp, mach); + topo_mod_free(mp, hbpath, PATH_MAX); + return (rp); +} + +/*ARGSUSED*/ +static int +iob_enum(topo_mod_t *mp, tnode_t *pn, const char *name, topo_instance_t imin, + topo_instance_t imax, void *notused) +{ + static topo_mod_t *Hbmod = NULL; + int rv; + + if (strcmp(name, IOBOARD) != 0) { + topo_mod_dprintf(IobHdl, + "Currently only know how to enumerate %s components.\n", + IOBOARD); + return (0); + } + /* + * Load the hostbridge enumerator, we'll soon need it! + */ + if (Hbmod == NULL && (Hbmod = hb_enumr_load(mp, pn)) == NULL) + return (-1); + + rv = platform_iob_enum(pn, imin, imax); + if (rv < 0) + return (topo_mod_seterrno(mp, EMOD_PARTIAL_ENUM)); + else + return (0); +} + +/*ARGSUSED*/ +static void +iob_release(topo_mod_t *mp, tnode_t *node) +{ + + /* + * node private data (did_t) for this node is destroyed in + * did_hash_destroy() + */ + + topo_method_unregister_all(mp, node); +} + +static tnode_t * +iob_tnode_create(tnode_t *parent, + const char *name, topo_instance_t i, void *priv) +{ + topo_hdl_t *thp; + nvlist_t *args, *fmri, *pfmri; + tnode_t *ntn; + int err; + + thp = topo_mod_handle(IobHdl); + + if (topo_node_resource(parent, &pfmri, &err) < 0) { + topo_mod_seterrno(IobHdl, err); + topo_mod_dprintf(IobHdl, + "Unable to retrieve parent resource.\n"); + return (NULL); + } + if (topo_mod_nvalloc(IobHdl, &args, NV_UNIQUE_NAME) != 0) { + (void) topo_mod_seterrno(IobHdl, EMOD_FMRI_NVL); + nvlist_free(pfmri); + return (NULL); + } + err = nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_PARENT, pfmri); + if (err != 0) { + nvlist_free(pfmri); + nvlist_free(args); + (void) topo_mod_seterrno(IobHdl, EMOD_FMRI_NVL); + return (NULL); + } + fmri = topo_fmri_create(thp, FM_FMRI_SCHEME_HC, name, i, args, &err); + if (fmri == NULL) { + topo_mod_dprintf(IobHdl, + "Unable to make nvlist for %s bind.\n", name); + return (NULL); + } + ntn = topo_node_bind(IobHdl, parent, name, i, fmri, priv); + if (ntn == NULL) { + topo_mod_dprintf(IobHdl, + "topo_node_bind (%s%d/%s%d) failed: %s\n", + topo_node_name(parent), topo_node_instance(parent), + name, i, + topo_strerror(topo_mod_errno(IobHdl))); + nvlist_free(fmri); + return (NULL); + } + nvlist_free(fmri); + if (topo_method_register(IobHdl, ntn, Iob_methods) < 0) { + topo_mod_dprintf(IobHdl, "topo_method_register failed: %s\n", + topo_strerror(topo_mod_errno(IobHdl))); + topo_node_unbind(ntn); + return (NULL); + } + return (ntn); +} + +tnode_t * +ioboard_declare(tnode_t *parent, topo_instance_t i, void *priv) +{ + tnode_t *ntn; + + if ((ntn = iob_tnode_create(parent, IOBOARD, i, priv)) == NULL) + return (NULL); + if (did_props_set(ntn, priv, IOB_common_props, IOB_propcnt) < 0) { + topo_node_unbind(ntn); + return (NULL); + } + /* + * We expect to find host bridges beneath the ioboard. + */ + if (child_range_add(IobHdl, ntn, HOSTBRIDGE, 0, MAX_HBS) < 0) { + topo_node_unbind(ntn); + return (NULL); + } + return (ntn); +} + +did_t * +split_bus_address(did_hash_t *dhash, di_node_t dp, uint_t baseaddr, + uint_t bussep, int minbrd, int maxbrd, int *brd, int *br, int *bus) +{ + uint_t bc, ac; + char *comma; + char *bac; + char *ba; + int e; + + if ((ba = di_bus_addr(dp)) == NULL || + (bac = topo_mod_strdup(IobHdl, ba)) == NULL) + return (NULL); + + topo_mod_dprintf(IobHdl, + "Transcribing %s into board, bus, etc.\n", bac); + + if ((comma = strchr(bac, ',')) == NULL) { + topo_mod_strfree(IobHdl, bac); + return (NULL); + } + *comma = '\0'; + bc = strtonum(IobHdl, bac, &e); + *comma = ','; + if (e < 0) { + topo_mod_dprintf(IobHdl, + "Trouble interpreting %s before comma.\n", bac); + topo_mod_strfree(IobHdl, bac); + return (NULL); + } + ac = strtonum(IobHdl, comma + 1, &e); + if (e < 0) { + topo_mod_dprintf(IobHdl, + "Trouble interpreting %s after comma.\n", bac); + topo_mod_strfree(IobHdl, bac); + return (NULL); + } + topo_mod_strfree(IobHdl, bac); + + *brd = ((bc - baseaddr) / bussep) + minbrd; + *br = (bc - baseaddr) % bussep; + *bus = ((ac == IOB_BUSADDR1) ? 0 : 1); + if (*brd < minbrd || *brd > maxbrd || (*br != 0 && *br != 1) || + (ac != IOB_BUSADDR1 && ac != IOB_BUSADDR2)) { + topo_mod_dprintf(IobHdl, "Trouble with transcription\n"); + topo_mod_dprintf(IobHdl, "brd=%d br=%d bus=%d bc=%x ac=%x\n", + *brd, *br, *bus, bc, ac); + return (NULL); + } + return (did_create(dhash, dp, *brd, *br, NO_RC, *bus)); +} diff --git a/usr/src/lib/fm/topo/modules/sun4/ioboard/ioboard.h b/usr/src/lib/fm/topo/modules/sun4/ioboard/ioboard.h new file mode 100644 index 0000000000..1f7d33ccd0 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/sun4/ioboard/ioboard.h @@ -0,0 +1,65 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _IOBOARD_H +#define _IOBOARD_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <libdevinfo.h> +#include "did.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define IOB_ENUMR_VERS 1 + +#define IOBOARD "ioboard" + +/* + * For all machines that currently use this enumerator, buses have one + * of the following addresses. + */ +#define IOB_BUSADDR1 0x600000 +#define IOB_BUSADDR2 0x700000 + +extern topo_mod_t *IobHdl; + +extern tnode_t *ioboard_declare(tnode_t *, topo_instance_t, void *); + +/* + * This routine works for splitting up the string we get from + * di_bus_addr() for all machines that currently use this enumerator. + */ +extern did_t *split_bus_address(did_hash_t *, di_node_t, uint_t, uint_t, + int, int, int *, int *, int *); + +#ifdef __cplusplus +} +#endif + +#endif /* _IOBOARD_H */ diff --git a/usr/src/lib/fm/topo/modules/sun4u/Makefile b/usr/src/lib/fm/topo/modules/sun4u/Makefile new file mode 100644 index 0000000000..7cc4f0e51e --- /dev/null +++ b/usr/src/lib/fm/topo/modules/sun4u/Makefile @@ -0,0 +1,32 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" + +SUBDIRS = chip hostbridge pcibus + +.PARALLEL: $(SUBDIRS) + +include ../../../Makefile.subdirs diff --git a/usr/src/cmd/fm/topo/files/i386/Makefile b/usr/src/lib/fm/topo/modules/sun4u/chip/Makefile index 53c91fb757..de6828189a 100644 --- a/usr/src/cmd/fm/topo/files/i386/Makefile +++ b/usr/src/lib/fm/topo/modules/sun4u/chip/Makefile @@ -20,12 +20,11 @@ # CDDL HEADER END # # -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" -SUBDIRS= +ARCH = sun4u -include ../../../Makefile.subdirs +include ../../sun4/chip/Makefile.chip diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/pcidev.topo b/usr/src/lib/fm/topo/modules/sun4u/hostbridge/Makefile index d66742bb72..d270d2f950 100644 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/pcidev.topo +++ b/usr/src/lib/fm/topo/modules/sun4u/hostbridge/Makefile @@ -20,11 +20,11 @@ # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -#ident "%Z%%M% %I% %E% SMI" +# ident "%Z%%M% %I% %E% SMI" -!share pcibus +ARCH = sun4u -/pcifn[0-7] +include ../../sun4/hostbridge/Makefile.hb diff --git a/usr/src/lib/fm/topo/modules/sun4u/hostbridge/hb_sun4u.c b/usr/src/lib/fm/topo/modules/sun4u/hostbridge/hb_sun4u.c new file mode 100644 index 0000000000..2b45efc591 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/sun4u/hostbridge/hb_sun4u.c @@ -0,0 +1,186 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include "hb_sun4.h" +#include "hostbridge.h" +#include "pcibus.h" +#include "util.h" + +int +count_busorrc(busorrc_t *list, int *hbc, int *bph) +{ + ulong_t start; + busorrc_t *p; + int bt; + + start = list->br_ba_ac; + p = list->br_nextbus; + bt = *hbc = 1; + while (p != NULL) { + if (p->br_ba_ac == start) + (*hbc)++; + bt++; + p = p->br_nextbus; + } + + /* + * sanity check that we have the correct number of buses/root + * complexes in the list to have the same number of buses on + * each hostbridge + */ + if (bt % *hbc != 0) { + topo_mod_dprintf(HbHdl, + "Imbalance between bus/root complex count and " + "the number of hostbridges.\n"); + return (topo_mod_seterrno(HbHdl, EMOD_PARTIAL_ENUM)); + } + *bph = bt / *hbc; + topo_mod_dprintf(HbHdl, + "%d hostbridge%s\n", *hbc, (*hbc > 1) ? "s." : "."); + topo_mod_dprintf(HbHdl, "%d buses total.\n", bt); + return (0); +} + +static int +busorrc_process(busorrc_t *list, int isrc, tnode_t *ptn) +{ + int hbc, busper; + + if (list == NULL) { + if (isrc == 1) + topo_mod_dprintf(HbHdl, "No root complexes found.\n"); + else + topo_mod_dprintf(HbHdl, "No pci buses found.\n"); + return (0); + } + + /* + * At this point we've looked through all the top-level device + * tree nodes for instances of drivers that represent logical + * PCI buses or root complexes. We've sorted them into a + * list, ordered by "bus address". We retrieved "bus address" + * using di_bus_addr(). That gave us a string that contains + * either a single hex number or a pair of them separated by a + * comma. If there was a single number, we've assumed the + * second number to be zero. + * + * So, we always have a pair of numbers describing a bus/root + * complex, X1 and X2, with X1 being the number before the + * comma, and X2 being the number after (or the assumed zero). + * As each node was examined, we then sorted these buses/root + * complexes, first by the value of X2, and using X1 to order + * amongst buses/root complexes with the same value for X2. + * + * We infer the existence of hostbridges by observing a + * pattern that X2 is recycled for different hostbridges, and + * that sorting by X1 within buses/root complexes with equal + * values of X2 maintains the correct associations of + * buses/root complexes and bridges. + */ + if (count_busorrc(list, &hbc, &busper) < 0) + return (-1); + if (isrc == 1) + return (declare_exbuses(list, ptn, hbc, busper)); + else + return (declare_buses(list, ptn, hbc)); +} + +static int +pci_hostbridges_find(tnode_t *ptn) +{ + busorrc_t *buses = NULL; + busorrc_t *rcs = NULL; + di_node_t devtree; + di_node_t pnode; + + /* Scan for buses, top-level devinfo nodes with the right driver */ + devtree = di_init("/", DINFOCPYALL); + if (devtree == DI_NODE_NIL) { + topo_mod_dprintf(HbHdl, "devinfo init failed."); + topo_node_range_destroy(ptn, HOSTBRIDGE); + return (topo_mod_seterrno(HbHdl, EMOD_PARTIAL_ENUM)); + } + + pnode = di_drv_first_node(PCI, devtree); + while (pnode != DI_NODE_NIL) { + if (busorrc_add(&buses, pnode) < 0) { + di_fini(devtree); + return (topo_mod_seterrno(HbHdl, EMOD_PARTIAL_ENUM)); + } + pnode = di_drv_next_node(pnode); + } + pnode = di_drv_first_node(PSYCHO, devtree); + while (pnode != DI_NODE_NIL) { + if (busorrc_add(&buses, pnode) < 0) { + di_fini(devtree); + return (topo_mod_seterrno(HbHdl, EMOD_PARTIAL_ENUM)); + } + pnode = di_drv_next_node(pnode); + } + pnode = di_drv_first_node(SCHIZO, devtree); + while (pnode != DI_NODE_NIL) { + if (busorrc_add(&buses, pnode) < 0) { + di_fini(devtree); + return (topo_mod_seterrno(HbHdl, EMOD_PARTIAL_ENUM)); + } + pnode = di_drv_next_node(pnode); + } + pnode = di_drv_first_node(PX, devtree); + while (pnode != DI_NODE_NIL) { + if (busorrc_add(&rcs, pnode) < 0) { + di_fini(devtree); + return (topo_mod_seterrno(HbHdl, EMOD_PARTIAL_ENUM)); + } + pnode = di_drv_next_node(pnode); + } + if (busorrc_process(buses, 0, ptn) < 0) + return (topo_mod_seterrno(HbHdl, EMOD_PARTIAL_ENUM)); + + if (busorrc_process(rcs, 1, ptn) < 0) + return (topo_mod_seterrno(HbHdl, EMOD_PARTIAL_ENUM)); + + busorrc_free(buses); + busorrc_free(rcs); + di_fini(devtree); + return (0); +} + +/*ARGSUSED*/ +int +platform_hb_enum(tnode_t *parent, const char *name, + topo_instance_t imin, topo_instance_t imax) +{ + return (pci_hostbridges_find(parent)); +} + +/*ARGSUSED*/ +int +platform_hb_label(tnode_t *node, nvlist_t *in, nvlist_t **out) +{ + return (labelmethod_inherit(HbHdl, node, in, out)); +} diff --git a/usr/src/lib/fm/topo/modules/sun4u/pcibus/Makefile b/usr/src/lib/fm/topo/modules/sun4u/pcibus/Makefile new file mode 100644 index 0000000000..d40de8fde4 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/sun4u/pcibus/Makefile @@ -0,0 +1,37 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +MODULE = pcibus +ARCH = sun4u +CLASS = arch +PCISRCS = pcibus.c pcibus_labels.c did.c did_hash.c did_props.c util.c +MODULESRCS = $(PCISRCS) pci_sun4u.c + +include ../../Makefile.plugin + +LDLIBS += -ldevinfo diff --git a/usr/src/lib/fm/topo/modules/sun4u/pcibus/pci_sun4u.c b/usr/src/lib/fm/topo/modules/sun4u/pcibus/pci_sun4u.c new file mode 100644 index 0000000000..dd9202c2ef --- /dev/null +++ b/usr/src/lib/fm/topo/modules/sun4u/pcibus/pci_sun4u.c @@ -0,0 +1,43 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <fm/topo_mod.h> + +/* + * Including the following file gives us definitions of the three + * global arrays used to adjust labels, Slot_Rewrites, Physlot_Names, + * and Missing_Names. With those defined we can use the common labeling + * routines for pci. + */ +#include "pci_sun4u.h" + +int +platform_pci_label(tnode_t *node, nvlist_t *in, nvlist_t **out) +{ + return (pci_label_cmn(node, in, out)); +} diff --git a/usr/src/lib/fm/topo/modules/sun4u/pcibus/pci_sun4u.h b/usr/src/lib/fm/topo/modules/sun4u/pcibus/pci_sun4u.h new file mode 100644 index 0000000000..3ff4ba5515 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/sun4u/pcibus/pci_sun4u.h @@ -0,0 +1,64 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _PCI_SUN4U_H +#define _PCI_SUN4U_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include "pcibus_labels.h" + +#ifdef __cplusplus +extern "C" { +#endif + +slot_rwd_t v240_rewrites[] = { + /* From OPB, Should Be */ + { "PCI3", "PCI0" }, + { "PCI1", "PCI2" }, + { "PCI2", "PCI1" } +}; + +plat_rwd_t plat_rewrites[] = { + { "SUNW,Sun-Fire-V240", + sizeof (v240_rewrites) / sizeof (slot_rwd_t), + v240_rewrites } +}; + +slotnm_rewrite_t SlotRWs = { + 1, + plat_rewrites +}; + +slotnm_rewrite_t *Slot_Rewrites = &SlotRWs; +physlot_names_t *Physlot_Names = NULL; +missing_names_t *Missing_Names = NULL; + +#ifdef __cplusplus +} +#endif + +#endif /* _PCI_SUN4U_H */ diff --git a/usr/src/lib/fm/topo/modules/sun4v/Makefile b/usr/src/lib/fm/topo/modules/sun4v/Makefile new file mode 100644 index 0000000000..7b5c6b10dc --- /dev/null +++ b/usr/src/lib/fm/topo/modules/sun4v/Makefile @@ -0,0 +1,30 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" + +SUBDIRS = chip hostbridge pcibus + +include ../../../Makefile.subdirs diff --git a/usr/src/lib/fm/topo/modules/sun4v/chip/Makefile b/usr/src/lib/fm/topo/modules/sun4v/chip/Makefile new file mode 100644 index 0000000000..350c67427c --- /dev/null +++ b/usr/src/lib/fm/topo/modules/sun4v/chip/Makefile @@ -0,0 +1,30 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +ARCH = sun4v + +include ../../sun4/chip/Makefile.chip diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/pciexdev.topo b/usr/src/lib/fm/topo/modules/sun4v/hostbridge/Makefile index f111eb5edf..862782dd5b 100644 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/pciexdev.topo +++ b/usr/src/lib/fm/topo/modules/sun4v/hostbridge/Makefile @@ -20,11 +20,11 @@ # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -#ident "%Z%%M% %I% %E% SMI" +# ident "%Z%%M% %I% %E% SMI" -!share pcibus +ARCH = sun4v -/pciexfn[0-7] +include ../../sun4/hostbridge/Makefile.hb diff --git a/usr/src/lib/fm/topo/modules/sun4v/hostbridge/hb_sun4v.c b/usr/src/lib/fm/topo/modules/sun4v/hostbridge/hb_sun4v.c new file mode 100644 index 0000000000..ba94f015db --- /dev/null +++ b/usr/src/lib/fm/topo/modules/sun4v/hostbridge/hb_sun4v.c @@ -0,0 +1,98 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include "hb_sun4.h" +#include "hostbridge.h" +#include "pcibus.h" +#include "util.h" + +static int +rcs_process(busorrc_t *list, tnode_t *ptn) +{ + busorrc_t *p; + int nrc = 0; + + if (list == NULL) { + topo_mod_dprintf(HbHdl, "No root complexes found.\n"); + return (0); + } + + /* + * At press time, all sun4v machines have 1 FIRE ASIC as a + * hostbridge, and then each PX driver instance we see is a + * PCI-Express root complex. + */ + for (p = list; p != NULL; p = p->br_nextbus) + nrc++; + + topo_mod_dprintf(HbHdl, "root complex count: %d\n", nrc); + return (declare_exbuses(list, ptn, 1, nrc)); +} + +static int +pci_hostbridges_find(tnode_t *ptn) +{ + busorrc_t *rcs = NULL; + di_node_t devtree; + di_node_t pnode; + + /* Scan for buses, top-level devinfo nodes with the right driver */ + devtree = di_init("/", DINFOCPYALL); + if (devtree == DI_NODE_NIL) { + topo_mod_dprintf(HbHdl, "devinfo init failed."); + topo_node_range_destroy(ptn, HOSTBRIDGE); + return (0); + } + pnode = di_drv_first_node(PX, devtree); + while (pnode != DI_NODE_NIL) { + if (busorrc_add(&rcs, pnode) < 0) { + di_fini(devtree); + return (-1); + } + pnode = di_drv_next_node(pnode); + } + rcs_process(rcs, ptn); + busorrc_free(rcs); + di_fini(devtree); + return (0); +} + +/*ARGSUSED*/ +int +platform_hb_enum(tnode_t *parent, const char *name, + topo_instance_t imin, topo_instance_t imax) +{ + return (pci_hostbridges_find(parent)); +} + +/*ARGSUSED*/ +int +platform_hb_label(tnode_t *node, nvlist_t *in, nvlist_t **out) +{ + return (labelmethod_inherit(HbHdl, node, in, out)); +} diff --git a/usr/src/lib/fm/topo/modules/sun4v/pcibus/Makefile b/usr/src/lib/fm/topo/modules/sun4v/pcibus/Makefile new file mode 100644 index 0000000000..9a676ffa5e --- /dev/null +++ b/usr/src/lib/fm/topo/modules/sun4v/pcibus/Makefile @@ -0,0 +1,37 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +MODULE = pcibus +ARCH = sun4v +CLASS = arch +PCISRCS = pcibus.c pcibus_labels.c did.c did_hash.c did_props.c util.c +MODULESRCS = $(PCISRCS) pci_sun4v.c + +include ../../Makefile.plugin + +LDLIBS += -ldevinfo diff --git a/usr/src/lib/fm/topo/modules/sun4v/pcibus/pci_sun4v.c b/usr/src/lib/fm/topo/modules/sun4v/pcibus/pci_sun4v.c new file mode 100644 index 0000000000..545805f1cc --- /dev/null +++ b/usr/src/lib/fm/topo/modules/sun4v/pcibus/pci_sun4v.c @@ -0,0 +1,43 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <fm/topo_mod.h> + +/* + * Including the following file gives us definitions of the three + * global arrays used to adjust labels, Slot_Rewrites, Physlot_Names, + * and Missing_Names. With those defined we can use the common labeling + * routines for pci. + */ +#include "pci_sun4v.h" + +int +platform_pci_label(tnode_t *node, nvlist_t *in, nvlist_t **out) +{ + return (pci_label_cmn(node, in, out)); +} diff --git a/usr/src/lib/fm/topo/modules/sun4v/pcibus/pci_sun4v.h b/usr/src/lib/fm/topo/modules/sun4v/pcibus/pci_sun4v.h new file mode 100644 index 0000000000..d533346a43 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/sun4v/pcibus/pci_sun4v.h @@ -0,0 +1,81 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _PCI_SUN4V_H +#define _PCI_SUN4V_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include "pcibus_labels.h" + +#ifdef __cplusplus +extern "C" { +#endif + +physnm_t t200_pnms[] = { + /* Slot #, Label */ + { 224, "PCIE0" }, + { 225, "PCIE1" }, + { 226, "PCIE2" } +}; + +pphysnm_t plat_pnames[] = { + { "SUNW,Sun-Fire-T200", + sizeof (t200_pnms) / sizeof (physnm_t), + t200_pnms } +}; + +physlot_names_t PhyslotNMs = { + 1, + plat_pnames +}; + +devlab_t t200_missing[] = { + /* board, bridge, root-complex, bus, dev, label */ + { 0, 0, 1 - TO_PCI, 6, 1, "PCIX1" }, + { 0, 0, 1 - TO_PCI, 6, 2, "PCIX0" } +}; + +pdevlabs_t plats_missing[] = { + { "SUNW,Sun-Fire-T200", + sizeof (t200_missing) / sizeof (devlab_t), + t200_missing } +}; + +missing_names_t Missing = { + 1, + plats_missing +}; + +slotnm_rewrite_t *Slot_Rewrites = NULL; +physlot_names_t *Physlot_Names = &PhyslotNMs; +missing_names_t *Missing_Names = &Missing; + +#ifdef __cplusplus +} +#endif + +#endif /* _PCI_SUN4V_H */ diff --git a/usr/src/lib/libexacct/common/exacct_ops.c b/usr/src/lib/libexacct/common/exacct_ops.c index 6e077fb301..7a42545b23 100644 --- a/usr/src/lib/libexacct/common/exacct_ops.c +++ b/usr/src/lib/libexacct/common/exacct_ops.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -594,6 +594,7 @@ xget_object( /* exacct_error set above. */ return (EO_ERROR); if (xread(f, buf, sz) != sz) { + ea_free(buf, sz); EXACCT_SET_ERR(EXR_CORRUPT_FILE); return (EO_ERROR); } diff --git a/usr/src/pkgdefs/Makefile b/usr/src/pkgdefs/Makefile index 65cfe0bfed..f4d4f5d7a2 100644 --- a/usr/src/pkgdefs/Makefile +++ b/usr/src/pkgdefs/Makefile @@ -105,6 +105,7 @@ i386_SUBDIRS= \ SUNWgrub \ SUNWgrubS \ SUNWkvm.i \ + SUNWonmtst.i \ SUNWos86r \ SUNWpsdcr \ SUNWpsdir \ diff --git a/usr/src/pkgdefs/SUNW0on/prototype_com b/usr/src/pkgdefs/SUNW0on/prototype_com index 1543f8a543..dad01f4ffd 100644 --- a/usr/src/pkgdefs/SUNW0on/prototype_com +++ b/usr/src/pkgdefs/SUNW0on/prototype_com @@ -43,6 +43,7 @@ d none usr/lib/locale 755 root bin d none usr/lib/locale/C 755 root bin d none usr/lib/locale/C/LC_MESSAGES 755 root bin d none usr/lib/locale/C/LC_TIME 755 root bin +f none usr/lib/locale/C/LC_MESSAGES/AMD.po 644 root bin f none usr/lib/locale/C/LC_MESSAGES/FMD.po 644 root bin f none usr/lib/locale/C/LC_MESSAGES/SMF.po 644 root bin f none usr/lib/locale/C/LC_MESSAGES/SUN4.po 644 root bin diff --git a/usr/src/pkgdefs/SUNWcakr.i/prototype_com b/usr/src/pkgdefs/SUNWcakr.i/prototype_com index e3667100cd..7ac93198db 100644 --- a/usr/src/pkgdefs/SUNWcakr.i/prototype_com +++ b/usr/src/pkgdefs/SUNWcakr.i/prototype_com @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #pragma ident "%Z%%M% %I% %E% SMI" @@ -58,7 +58,25 @@ d none platform/i86pc 755 root sys f none platform/i86pc/biosint 755 root sys f none platform/i86pc/multiboot 755 root sys d none platform/i86pc/kernel 755 root sys +d none platform/i86pc/kernel/amd64 755 root sys +f none platform/i86pc/kernel/amd64/unix 755 root sys +d none platform/i86pc/kernel/cpu 755 root sys +d none platform/i86pc/kernel/cpu/amd64 755 root sys +f none platform/i86pc/kernel/cpu/amd64/cpu.AuthenticAMD.15 755 root sys +f none platform/i86pc/kernel/cpu/amd64/cpu.generic 755 root sys +f none platform/i86pc/kernel/cpu/cpu.AuthenticAMD.15 755 root sys +f none platform/i86pc/kernel/cpu/cpu.generic 755 root sys d none platform/i86pc/kernel/drv 755 root sys +d none platform/i86pc/kernel/drv/amd64 755 root sys +f none platform/i86pc/kernel/drv/amd64/bmc 755 root sys +f none platform/i86pc/kernel/drv/amd64/isa 755 root sys +f none platform/i86pc/kernel/drv/amd64/kb8042 755 root sys +f none platform/i86pc/kernel/drv/amd64/mc-amd 755 root sys +f none platform/i86pc/kernel/drv/amd64/npe 755 root sys +f none platform/i86pc/kernel/drv/amd64/pci 755 root sys +f none platform/i86pc/kernel/drv/amd64/pcie_pci 755 root sys +f none platform/i86pc/kernel/drv/amd64/power 755 root sys +f none platform/i86pc/kernel/drv/amd64/rootnex 755 root sys f none platform/i86pc/kernel/drv/bmc 755 root sys f none platform/i86pc/kernel/drv/bmc.conf 644 root sys f none platform/i86pc/kernel/drv/bscbus 755 root sys @@ -67,6 +85,8 @@ f none platform/i86pc/kernel/drv/bscv 755 root sys f none platform/i86pc/kernel/drv/bscv.conf 644 root sys f none platform/i86pc/kernel/drv/isa 755 root sys f none platform/i86pc/kernel/drv/kb8042 755 root sys +f none platform/i86pc/kernel/drv/mc-amd 755 root sys +f none platform/i86pc/kernel/drv/mc-amd.conf 644 root sys f none platform/i86pc/kernel/drv/npe 755 root sys f none platform/i86pc/kernel/drv/pci 755 root sys f none platform/i86pc/kernel/drv/pcie_pci 755 root sys @@ -75,28 +95,17 @@ f none platform/i86pc/kernel/drv/power 755 root sys f none platform/i86pc/kernel/drv/power.conf 644 root sys f none platform/i86pc/kernel/drv/rootnex 755 root sys d none platform/i86pc/kernel/mach 755 root sys -f none platform/i86pc/kernel/mach/uppc 755 root sys -d none platform/i86pc/kernel/misc 755 root sys -f none platform/i86pc/kernel/misc/bootdev 755 root sys -f none platform/i86pc/kernel/misc/gfx_private 755 root sys -f none platform/i86pc/kernel/misc/pci_autoconfig 755 root sys -f none platform/i86pc/kernel/misc/pciehpc 755 root sys -f none platform/i86pc/kernel/unix 755 root sys -d none platform/i86pc/kernel/drv/amd64 755 root sys -f none platform/i86pc/kernel/drv/amd64/bmc 755 root sys -f none platform/i86pc/kernel/drv/amd64/isa 755 root sys -f none platform/i86pc/kernel/drv/amd64/kb8042 755 root sys -f none platform/i86pc/kernel/drv/amd64/npe 755 root sys -f none platform/i86pc/kernel/drv/amd64/pci 755 root sys -f none platform/i86pc/kernel/drv/amd64/pcie_pci 755 root sys -f none platform/i86pc/kernel/drv/amd64/power 755 root sys -f none platform/i86pc/kernel/drv/amd64/rootnex 755 root sys d none platform/i86pc/kernel/mach/amd64 755 root sys f none platform/i86pc/kernel/mach/amd64/uppc 755 root sys +f none platform/i86pc/kernel/mach/uppc 755 root sys +d none platform/i86pc/kernel/misc 755 root sys d none platform/i86pc/kernel/misc/amd64 755 root sys f none platform/i86pc/kernel/misc/amd64/bootdev 755 root sys f none platform/i86pc/kernel/misc/amd64/gfx_private 755 root sys f none platform/i86pc/kernel/misc/amd64/pci_autoconfig 755 root sys f none platform/i86pc/kernel/misc/amd64/pciehpc 755 root sys -d none platform/i86pc/kernel/amd64 755 root sys -f none platform/i86pc/kernel/amd64/unix 755 root sys +f none platform/i86pc/kernel/misc/bootdev 755 root sys +f none platform/i86pc/kernel/misc/gfx_private 755 root sys +f none platform/i86pc/kernel/misc/pci_autoconfig 755 root sys +f none platform/i86pc/kernel/misc/pciehpc 755 root sys +f none platform/i86pc/kernel/unix 755 root sys diff --git a/usr/src/pkgdefs/SUNWfmd/prototype_com b/usr/src/pkgdefs/SUNWfmd/prototype_com index dc932d631f..723d7f38ac 100644 --- a/usr/src/pkgdefs/SUNWfmd/prototype_com +++ b/usr/src/pkgdefs/SUNWfmd/prototype_com @@ -30,8 +30,6 @@ i pkginfo i copyright i depend # -# SUNWfmd -# d none usr 755 root sys d none usr/include 755 root bin d none usr/include/fm 755 root bin @@ -42,7 +40,7 @@ f none usr/include/fm/fmd_fmri.h 644 root bin f none usr/include/fm/fmd_log.h 644 root bin f none usr/include/fm/fmd_snmp.h 644 root bin f none usr/include/fm/libtopo.h 644 root bin -f none usr/include/fm/libtopo_enum.h 644 root bin +f none usr/include/fm/topo_mod.h 644 root bin d none usr/lib 755 root bin d none usr/lib/fm 755 root bin d none usr/lib/fm/dict 755 root bin @@ -57,6 +55,7 @@ d none usr/lib/fm/fmd 755 root bin f none usr/lib/fm/fmd/fmd 555 root bin f none usr/lib/fm/fmd/fminject 555 root bin f none usr/lib/fm/fmd/fmsim 555 root bin +f none usr/lib/fm/fmd/fmtopo 555 root bin d none usr/lib/fm/fmd/plugins 755 root bin f none usr/lib/fm/fmd/plugins/cpumem-retire.conf 644 root bin f none usr/lib/fm/fmd/plugins/cpumem-retire.so 555 root bin @@ -76,6 +75,7 @@ f none usr/lib/fm/fmd/schemes/dev.so 555 root bin f none usr/lib/fm/fmd/schemes/fmd.so 555 root bin f none usr/lib/fm/fmd/schemes/hc.so 555 root bin f none usr/lib/fm/fmd/schemes/legacy-hc.so 555 root bin +f none usr/lib/fm/fmd/schemes/mem.so 555 root bin f none usr/lib/fm/fmd/schemes/mod.so 555 root bin f none usr/lib/fm/fmd/schemes/pkg.so 555 root bin f none usr/lib/fm/libdiagcode.so.1 755 root bin @@ -98,13 +98,6 @@ f none usr/lib/fm/libtopo.so.1 755 root bin s none usr/lib/fm/libtopo.so=libtopo.so.1 f none usr/lib/fm/llib-ltopo 644 root bin f none usr/lib/fm/llib-ltopo.ln 644 root bin -d none usr/lib/fm/topo 755 root bin -f none usr/lib/fm/topo/cpu.so 555 root sys -f none usr/lib/fm/topo/cpu.topo 444 root bin -f none usr/lib/fm/topo/pcibus.so 555 root sys -f none usr/lib/fm/topo/pcibus.topo 444 root bin -f none usr/lib/fm/topo/pciexbus.topo 444 root bin -f none usr/lib/fm/topo/pciexrc.topo 444 root bin d none usr/lib/locale 755 root bin d none usr/lib/locale/C 755 root bin d none usr/lib/locale/C/LC_MESSAGES 755 root bin @@ -120,3 +113,8 @@ d none usr/sbin 755 root bin f none usr/sbin/fmadm 555 root bin f none usr/sbin/fmdump 555 root bin f none usr/sbin/fmstat 555 root bin +d none usr/share 755 root sys +d none usr/share/lib 755 root sys +d none usr/share/lib/xml 755 root sys +d none usr/share/lib/xml/dtd 755 root sys +f none usr/share/lib/xml/dtd/topology.dtd.1 444 root bin diff --git a/usr/src/pkgdefs/SUNWfmd/prototype_i386 b/usr/src/pkgdefs/SUNWfmd/prototype_i386 index 2c318a5e18..c7012f3702 100644 --- a/usr/src/pkgdefs/SUNWfmd/prototype_i386 +++ b/usr/src/pkgdefs/SUNWfmd/prototype_i386 @@ -26,18 +26,8 @@ # ident "%Z%%M% %I% %E% SMI" # -# -# Include ISA independent files (prototype_com) -# !include prototype_com -# -# -# List files which are i386 specific here -# -# source locations relative to the prototype file -# -# SUNWfmd -# + d none usr/lib/fm/amd64 755 root bin f none usr/lib/fm/amd64/libdiagcode.so.1 755 root bin s none usr/lib/fm/amd64/libdiagcode.so=./libdiagcode.so.1 @@ -60,5 +50,20 @@ f none usr/lib/fm/fmd/schemes/amd64/dev.so 555 root bin f none usr/lib/fm/fmd/schemes/amd64/fmd.so 555 root bin f none usr/lib/fm/fmd/schemes/amd64/hc.so 555 root bin f none usr/lib/fm/fmd/schemes/amd64/legacy-hc.so 555 root bin +f none usr/lib/fm/fmd/schemes/amd64/mem.so 555 root bin f none usr/lib/fm/fmd/schemes/amd64/mod.so 555 root bin f none usr/lib/fm/fmd/schemes/amd64/pkg.so 555 root bin +f none usr/lib/fm/dict/AMD.dict 444 root bin +f none usr/lib/locale/C/LC_MESSAGES/AMD.mo 444 root bin +d none usr/platform 755 root sys +d none usr/platform/i86pc 755 root sys +d none usr/platform/i86pc/lib 755 root bin +d none usr/platform/i86pc/lib/fm 755 root bin +d none usr/platform/i86pc/lib/fm/eft 755 root bin +f none usr/platform/i86pc/lib/fm/eft/amd64.eft 444 root bin +d none usr/platform/i86pc/lib/fm/topo 755 root bin +d none usr/platform/i86pc/lib/fm/topo/plugins 755 root bin +f none usr/platform/i86pc/lib/fm/topo/plugins/chip.so 555 root bin +f none usr/platform/i86pc/lib/fm/topo/plugins/hostbridge.so 555 root bin +f none usr/platform/i86pc/lib/fm/topo/plugins/pcibus.so 555 root bin +f none usr/platform/i86pc/lib/fm/topo/hc-topology.xml 444 root bin diff --git a/usr/src/pkgdefs/SUNWfmd/prototype_sparc b/usr/src/pkgdefs/SUNWfmd/prototype_sparc index 4be722df69..be5e999d51 100644 --- a/usr/src/pkgdefs/SUNWfmd/prototype_sparc +++ b/usr/src/pkgdefs/SUNWfmd/prototype_sparc @@ -31,7 +31,6 @@ f none usr/lib/fm/dict/SUN4.dict 444 root bin f none usr/lib/fm/dict/SUN4U.dict 444 root bin f none usr/lib/fm/dict/SUN4V.dict 444 root bin -f none usr/lib/fm/fmd/schemes/mem.so 555 root bin f none usr/lib/fm/libmdesc.so.1 755 root bin s none usr/lib/fm/libmdesc.so=libmdesc.so.1 755 root bin f none usr/lib/fm/llib-lmdesc 644 root bin @@ -64,82 +63,6 @@ f none usr/lib/fm/sparcv9/llib-lfmd_snmp.ln 644 root bin f none usr/lib/fm/sparcv9/libtopo.so.1 755 root bin s none usr/lib/fm/sparcv9/libtopo.so=libtopo.so.1 f none usr/lib/fm/sparcv9/llib-ltopo.ln 644 root bin -d none usr/lib/fm/topo/SUNW,Netra-210 755 root bin -f none usr/lib/fm/topo/SUNW,Netra-210/platform.topo 444 root bin -d none usr/lib/fm/topo/SUNW,Netra-T12 755 root bin -f none usr/lib/fm/topo/SUNW,Netra-T12/platform.topo 444 root bin -d none usr/lib/fm/topo/SUNW,Serverblade1 755 root bin -f none usr/lib/fm/topo/SUNW,Serverblade1/platform.topo 444 root bin -d none usr/lib/fm/topo/SUNW,Sun-Blade-100 755 root bin -f none usr/lib/fm/topo/SUNW,Sun-Blade-100/platform.topo 444 root bin -d none usr/lib/fm/topo/SUNW,Sun-Blade-1000 755 root bin -f none usr/lib/fm/topo/SUNW,Sun-Blade-1000/platform.topo 444 root bin -d none usr/lib/fm/topo/SUNW,Sun-Blade-1500 755 root bin -f none usr/lib/fm/topo/SUNW,Sun-Blade-1500/platform.topo 444 root bin -d none usr/lib/fm/topo/SUNW,Sun-Blade-2500 755 root bin -f none usr/lib/fm/topo/SUNW,Sun-Blade-2500/platform.topo 444 root bin -d none usr/lib/fm/topo/SUNW,Netra-CP3010 755 root bin -f none usr/lib/fm/topo/SUNW,Netra-CP3010/platform.topo 444 root bin -d none usr/lib/fm/topo/SUNW,Sun-Fire-15000 755 root bin -f none usr/lib/fm/topo/SUNW,Sun-Fire-15000/platform.topo 444 root bin -d none usr/lib/fm/topo/SUNW,Sun-Fire-480R 755 root bin -f none usr/lib/fm/topo/SUNW,Sun-Fire-480R/platform.topo 444 root bin -d none usr/lib/fm/topo/SUNW,Sun-Fire-880 755 root bin -f none usr/lib/fm/topo/SUNW,Sun-Fire-880/platform.topo 444 root bin -d none usr/lib/fm/topo/SUNW,Sun-Fire-T1000 755 root bin -f none usr/lib/fm/topo/SUNW,Sun-Fire-T1000/platform.topo 444 root bin -d none usr/lib/fm/topo/SUNW,Sun-Fire-V240 755 root bin -f none usr/lib/fm/topo/SUNW,Sun-Fire-V240/platform.topo 444 root bin -d none usr/lib/fm/topo/SUNW,Sun-Fire-V245 755 root bin -f none usr/lib/fm/topo/SUNW,Sun-Fire-V245/platform.topo 444 root bin -d none usr/lib/fm/topo/SUNW,Sun-Fire-V440 755 root bin -f none usr/lib/fm/topo/SUNW,Sun-Fire-V440/platform.topo 444 root bin -d none usr/lib/fm/topo/SUNW,Sun-Fire-V445 755 root bin -f none usr/lib/fm/topo/SUNW,Sun-Fire-V445/platform.topo 444 root bin -d none usr/lib/fm/topo/SUNW,Sun-Fire 755 root bin -f none usr/lib/fm/topo/SUNW,Sun-Fire/platform.topo 444 root bin -d none usr/lib/fm/topo/SUNW,Ultra-250 755 root bin -f none usr/lib/fm/topo/SUNW,Ultra-250/platform.topo 444 root bin -d none usr/lib/fm/topo/SUNW,Ultra-30 755 root bin -f none usr/lib/fm/topo/SUNW,Ultra-30/platform.topo 444 root bin -d none usr/lib/fm/topo/SUNW,Ultra-4 755 root bin -f none usr/lib/fm/topo/SUNW,Ultra-4/platform.topo 444 root bin -d none usr/lib/fm/topo/SUNW,Ultra-5_10 755 root bin -f none usr/lib/fm/topo/SUNW,Ultra-5_10/platform.topo 444 root bin -d none usr/lib/fm/topo/SUNW,Ultra-60 755 root bin -f none usr/lib/fm/topo/SUNW,Ultra-60/platform.topo 444 root bin -d none usr/lib/fm/topo/SUNW,Ultra-80 755 root bin -f none usr/lib/fm/topo/SUNW,Ultra-80/platform.topo 444 root bin -d none usr/lib/fm/topo/SUNW,UltraAX-i2 755 root bin -f none usr/lib/fm/topo/SUNW,UltraAX-i2/platform.topo 444 root bin -d none usr/lib/fm/topo/SUNW,Netra-T4 755 root bin -l none usr/lib/fm/topo/SUNW,Netra-T4/platform.topo=../../../../../usr/lib/fm/topo/SUNW,Sun-Blade-1000/platform.topo -d none usr/lib/fm/topo/SUNW,Netra-440 755 root bin -l none usr/lib/fm/topo/SUNW,Netra-440/platform.topo=../../../../../usr/lib/fm/topo/SUNW,Sun-Fire-V440/platform.topo -d none usr/lib/fm/topo/SUNW,Sun-Blade-2000 755 root bin -l none usr/lib/fm/topo/SUNW,Sun-Blade-2000/platform.topo=../../../../../usr/lib/fm/topo/SUNW,Sun-Blade-1000/platform.topo -d none usr/lib/fm/topo/SUNW,Sun-Fire-280R 755 root bin -l none usr/lib/fm/topo/SUNW,Sun-Fire-280R/platform.topo=../../../../../usr/lib/fm/topo/SUNW,Sun-Blade-1000/platform.topo -d none usr/lib/fm/topo/SUNW,Netra-240 755 root bin -l none usr/lib/fm/topo/SUNW,Netra-240/platform.topo=../../../../../usr/lib/fm/topo/SUNW,Sun-Fire-V240/platform.topo -d none usr/lib/fm/topo/SUNW,Sun-Fire-V210 755 root bin -l none usr/lib/fm/topo/SUNW,Sun-Fire-V210/platform.topo=../../../../../usr/lib/fm/topo/SUNW,Sun-Fire-V240/platform.topo -d none usr/lib/fm/topo/SUNW,Sun-Fire-V215 755 root bin -l none usr/lib/fm/topo/SUNW,Sun-Fire-V215/platform.topo=../../../../../usr/lib/fm/topo/SUNW,Sun-Fire-V245/platform.topo -d none usr/lib/fm/topo/SUNW,Sun-Fire-V250 755 root bin -l none usr/lib/fm/topo/SUNW,Sun-Fire-V250/platform.topo=../../../../../usr/lib/fm/topo/SUNW,Sun-Fire-V240/platform.topo -d none usr/lib/fm/topo/SUNW,Sun-Fire-V490 755 root bin -l none usr/lib/fm/topo/SUNW,Sun-Fire-V490/platform.topo=../../../../../usr/lib/fm/topo/SUNW,Sun-Fire-480R/platform.topo -d none usr/lib/fm/topo/SUNW,Sun-Fire-V890 755 root bin -l none usr/lib/fm/topo/SUNW,Sun-Fire-V890/platform.topo=../../../../../usr/lib/fm/topo/SUNW,Sun-Fire-880/platform.topo -d none usr/lib/fm/topo/SUNW,Sun-Fire-T200 755 root bin -f none usr/lib/fm/topo/SUNW,Sun-Fire-T200/platform.topo 444 root bin -f none usr/lib/fm/topo/SUNW,Sun-Fire-T200/pciexdev.topo 444 root bin -f none usr/lib/fm/topo/SUNW,Sun-Fire-T200/pcidev.topo 444 root bin -d none usr/lib/fm/topo/SUNW,A70 755 root bin -f none usr/lib/fm/topo/SUNW,A70/platform.topo 444 root bin -l none usr/lib/fm/topo/SUNW,A70/pciexdev.topo=../../../../../usr/lib/fm/topo/SUNW,Sun-Fire-T200/pciexdev.topo -l none usr/lib/fm/topo/SUNW,A70/pcidev.topo=../../../../../usr/lib/fm/topo/SUNW,Sun-Fire-T200/pcidev.topo f none usr/lib/locale/C/LC_MESSAGES/SUN4.mo 444 root bin f none usr/lib/locale/C/LC_MESSAGES/SUN4U.mo 444 root bin f none usr/lib/locale/C/LC_MESSAGES/SUN4V.mo 444 root bin @@ -161,6 +84,12 @@ f none usr/platform/sun4u/lib/fm/fmd/plugins/datapath-retire.so 555 root bin f none usr/platform/sun4u/lib/fm/fmd/plugins/datapath-retire.conf 644 root bin f none usr/platform/sun4u/lib/fm/fmd/plugins/USII-io-diagnosis.so 555 root bin f none usr/platform/sun4u/lib/fm/fmd/plugins/USII-io-diagnosis.conf 644 root bin +d none usr/platform/sun4u/lib/fm/topo 755 root bin +f none usr/platform/sun4u/lib/fm/topo/hc-topology.xml 444 root bin +d none usr/platform/sun4u/lib/fm/topo/plugins 755 root bin +f none usr/platform/sun4u/lib/fm/topo/plugins/chip.so 555 root bin +f none usr/platform/sun4u/lib/fm/topo/plugins/hostbridge.so 555 root bin +f none usr/platform/sun4u/lib/fm/topo/plugins/pcibus.so 555 root bin d none usr/platform/sun4v 755 root sys d none usr/platform/sun4v/lib 755 root bin d none usr/platform/sun4v/lib/fm 755 root bin @@ -172,8 +101,30 @@ f none usr/platform/sun4v/lib/fm/fmd/plugins/cpumem-diagnosis.so 555 root bin f none usr/platform/sun4v/lib/fm/fmd/plugins/cpumem-diagnosis.conf 644 root bin f none usr/platform/sun4v/lib/fm/fmd/plugins/etm.so 555 root bin f none usr/platform/sun4v/lib/fm/fmd/plugins/etm.conf 644 root bin +d none usr/platform/sun4v/lib/fm/topo 755 root bin +f none usr/platform/sun4v/lib/fm/topo/hc-topology.xml 444 root bin +d none usr/platform/sun4v/lib/fm/topo/plugins 755 root bin +f none usr/platform/sun4v/lib/fm/topo/plugins/chip.so 555 root bin +f none usr/platform/sun4v/lib/fm/topo/plugins/hostbridge.so 555 root bin +f none usr/platform/sun4v/lib/fm/topo/plugins/pcibus.so 555 root bin +d none usr/platform/SUNW,Sun-Fire 755 root sys +d none usr/platform/SUNW,Sun-Fire/lib 755 root bin +d none usr/platform/SUNW,Sun-Fire/lib/fm 755 root bin +d none usr/platform/SUNW,Sun-Fire/lib/fm/topo 755 root bin +f none usr/platform/SUNW,Sun-Fire/lib/fm/topo/hc-topology.xml 444 root bin +d none usr/platform/SUNW,Sun-Fire/lib/fm/topo/plugins 755 root bin +f none usr/platform/SUNW,Sun-Fire/lib/fm/topo/plugins/ioboard.so 555 root bin d none usr/platform/SUNW,Sun-Fire-15000 755 root sys d none usr/platform/SUNW,Sun-Fire-15000/lib 755 root bin d none usr/platform/SUNW,Sun-Fire-15000/lib/fm 755 root bin d none usr/platform/SUNW,Sun-Fire-15000/lib/fm/eft 755 root bin f none usr/platform/SUNW,Sun-Fire-15000/lib/fm/eft/SUNW,Sun-Fire-15000.eft 444 root bin +d none usr/platform/SUNW,Sun-Fire-15000/lib/fm/topo 755 root bin +f none usr/platform/SUNW,Sun-Fire-15000/lib/fm/topo/hc-topology.xml 444 root bin +d none usr/platform/SUNW,Sun-Fire-15000/lib/fm/topo/plugins 755 root bin +f none usr/platform/SUNW,Sun-Fire-15000/lib/fm/topo/plugins/ioboard.so 555 root bin +d none usr/platform/SUNW,Sun-Fire-T200 755 root sys +d none usr/platform/SUNW,Sun-Fire-T200/lib 755 root bin +d none usr/platform/SUNW,Sun-Fire-T200/lib/fm 755 root bin +d none usr/platform/SUNW,Sun-Fire-T200/lib/fm/topo 755 root bin +f none usr/platform/SUNW,Sun-Fire-T200/lib/fm/topo/hc-topology.xml 444 root bin diff --git a/usr/src/pkgdefs/SUNWhea/prototype_i386 b/usr/src/pkgdefs/SUNWhea/prototype_i386 index 66028bcc8e..35b0b72129 100644 --- a/usr/src/pkgdefs/SUNWhea/prototype_i386 +++ b/usr/src/pkgdefs/SUNWhea/prototype_i386 @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -95,6 +95,10 @@ f none usr/include/sys/i2o/i2omstr.h 644 root bin f none usr/include/sys/i8272A.h 644 root bin f none usr/include/sys/immu.h 644 root bin f none usr/include/sys/kd.h 644 root bin +f none usr/include/sys/mc.h 644 root bin +f none usr/include/sys/mc_amd.h 644 root bin +f none usr/include/sys/mca_amd.h 644 root bin +f none usr/include/sys/mca_x86.h 644 root bin f none usr/include/sys/mmu.h 644 root bin f none usr/include/sys/mutex_impl.h 644 root bin f none usr/include/sys/obpdefs.h 644 root bin diff --git a/usr/src/pkgdefs/SUNWmdb/prototype_i386 b/usr/src/pkgdefs/SUNWmdb/prototype_i386 index abfaa178c6..e1e2cb7c8d 100644 --- a/usr/src/pkgdefs/SUNWmdb/prototype_i386 +++ b/usr/src/pkgdefs/SUNWmdb/prototype_i386 @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -38,13 +38,15 @@ d none usr/platform/i86pc 755 root sys d none usr/platform/i86pc/lib 755 root bin d none usr/platform/i86pc/lib/mdb 755 root sys d none usr/platform/i86pc/lib/mdb/kvm 755 root sys -f none usr/platform/i86pc/lib/mdb/kvm/pcplusmp.so 555 root sys -f none usr/platform/i86pc/lib/mdb/kvm/unix.so 555 root sys -f none usr/platform/i86pc/lib/mdb/kvm/uppc.so 555 root sys d none usr/platform/i86pc/lib/mdb/kvm/amd64 755 root sys +f none usr/platform/i86pc/lib/mdb/kvm/amd64/cpu.AuthenticAMD.15.so 555 root sys f none usr/platform/i86pc/lib/mdb/kvm/amd64/pcplusmp.so 555 root sys -f none usr/platform/i86pc/lib/mdb/kvm/amd64/unix.so 555 root sys f none usr/platform/i86pc/lib/mdb/kvm/amd64/uppc.so 555 root sys +f none usr/platform/i86pc/lib/mdb/kvm/amd64/unix.so 555 root sys +f none usr/platform/i86pc/lib/mdb/kvm/cpu.AuthenticAMD.15.so 555 root sys +f none usr/platform/i86pc/lib/mdb/kvm/pcplusmp.so 555 root sys +f none usr/platform/i86pc/lib/mdb/kvm/uppc.so 555 root sys +f none usr/platform/i86pc/lib/mdb/kvm/unix.so 555 root sys d none usr/lib/mdb/kvm/amd64 755 root sys f none usr/lib/mdb/kvm/amd64/audiosup.so 555 root sys f none usr/lib/mdb/kvm/amd64/cpc.so 555 root sys diff --git a/usr/src/pkgdefs/SUNWmdbr/prototype_i386 b/usr/src/pkgdefs/SUNWmdbr/prototype_i386 index e3db96a5e8..07fe248387 100644 --- a/usr/src/pkgdefs/SUNWmdbr/prototype_i386 +++ b/usr/src/pkgdefs/SUNWmdbr/prototype_i386 @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -84,10 +84,12 @@ d none platform 755 root sys d none platform/i86pc 755 root sys d none platform/i86pc/kernel 755 root sys d none platform/i86pc/kernel/kmdb 755 root sys -f none platform/i86pc/kernel/kmdb/pcplusmp 555 root sys -f none platform/i86pc/kernel/kmdb/unix 555 root sys -f none platform/i86pc/kernel/kmdb/uppc 555 root sys d none platform/i86pc/kernel/kmdb/amd64 755 root sys +f none platform/i86pc/kernel/kmdb/amd64/cpu.AuthenticAMD.15 555 root sys f none platform/i86pc/kernel/kmdb/amd64/pcplusmp 555 root sys -f none platform/i86pc/kernel/kmdb/amd64/unix 555 root sys f none platform/i86pc/kernel/kmdb/amd64/uppc 555 root sys +f none platform/i86pc/kernel/kmdb/amd64/unix 555 root sys +f none platform/i86pc/kernel/kmdb/cpu.AuthenticAMD.15 555 root sys +f none platform/i86pc/kernel/kmdb/pcplusmp 555 root sys +f none platform/i86pc/kernel/kmdb/uppc 555 root sys +f none platform/i86pc/kernel/kmdb/unix 555 root sys diff --git a/usr/src/pkgdefs/SUNWonfmes/prototype_com b/usr/src/pkgdefs/SUNWonfmes/prototype_com index d24628e7a9..3bf104243b 100644 --- a/usr/src/pkgdefs/SUNWonfmes/prototype_com +++ b/usr/src/pkgdefs/SUNWonfmes/prototype_com @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -29,14 +29,11 @@ i pkginfo i copyright i depend # -# SUNWfmd -# d none usr 755 root sys d none usr/lib 755 root bin d none usr/lib/fm 755 root bin f none usr/lib/fm/esc 555 root bin f none usr/lib/fm/eftinfo 555 root bin -f none usr/lib/fm/prtopo 555 root bin f none usr/lib/fm/buildcode 555 root bin f none usr/lib/fm/bustcode 555 root bin f none usr/lib/fm/dictck 555 root bin diff --git a/usr/src/pkgdefs/SUNWonfmes/prototype_i386 b/usr/src/pkgdefs/SUNWonfmes/prototype_i386 index df1a7efb10..90e2355594 100644 --- a/usr/src/pkgdefs/SUNWonfmes/prototype_i386 +++ b/usr/src/pkgdefs/SUNWonfmes/prototype_i386 @@ -20,10 +20,9 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" -# + !include prototype_com -# diff --git a/usr/src/pkgdefs/SUNWonmtst.i/Makefile b/usr/src/pkgdefs/SUNWonmtst.i/Makefile new file mode 100644 index 0000000000..12f3bc9dca --- /dev/null +++ b/usr/src/pkgdefs/SUNWonmtst.i/Makefile @@ -0,0 +1,38 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +DATAFILES += depend + +.KEEP_STATE: + +all: $(FILES) +install: all pkg + +include ../Makefile.targ diff --git a/usr/src/pkgdefs/SUNWonmtst.i/pkginfo.tmpl b/usr/src/pkgdefs/SUNWonmtst.i/pkginfo.tmpl new file mode 100644 index 0000000000..a217996024 --- /dev/null +++ b/usr/src/pkgdefs/SUNWonmtst.i/pkginfo.tmpl @@ -0,0 +1,54 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# +# This required package information file describes characteristics of the +# package, such as package abbreviation, full package name, package version, +# and package architecture. +# +PKG="SUNWonmtst" +NAME="CPU/memory error injector" +ARCH="i386.i86pc" +VERSION="ONVERS,REV=0.0.0" +SUNW_PRODNAME="SunOS" +SUNW_PRODVERS="RELEASE/VERSION" +SUNW_PKGTYPE="internal" +MAXINST="1000" +CATEGORY="internal" +DESC="CPU/memory error injector for internal testing" +VENDOR="Sun Microsystems, Inc." +HOTLINE="Please contact fma-interest@sun.com" +EMAIL="fma-interest@sun.com" +CLASSES="none" +BASEDIR=/ +SUNW_PKGVERS="1.0" +#VSTOCK="<reserved by Release Engineering for package part #>" +#ISTATES="<developer defined>" +#RSTATES='<developer defined>' +#ULIMIT="<developer defined>" +#ORDER="<developer defined>" +#PSTAMP="<developer defined>" +#INTONLY="<developer defined>" diff --git a/usr/src/pkgdefs/SUNWonmtst.i/postinstall b/usr/src/pkgdefs/SUNWonmtst.i/postinstall new file mode 100644 index 0000000000..b4d306b3ef --- /dev/null +++ b/usr/src/pkgdefs/SUNWonmtst.i/postinstall @@ -0,0 +1,36 @@ +#!/sbin/sh +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +grep -w memtest $BASEDIR/etc/name_to_major >/dev/null 2>&1 +if [ $? -ne 0 ]; then + add_drv -b ${BASEDIR:-/} -m '* 0660 root sys' memtest >/dev/null + exit $? +fi + +exit 0 diff --git a/usr/src/pkgdefs/SUNWonmtst.i/preremove b/usr/src/pkgdefs/SUNWonmtst.i/preremove new file mode 100644 index 0000000000..4dfb38b7a0 --- /dev/null +++ b/usr/src/pkgdefs/SUNWonmtst.i/preremove @@ -0,0 +1,35 @@ +#!/sbin/sh +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# + +if grep -w memtest $BASEDIR/etc/name_to_major >/dev/null 2>&1; then + rem_drv -b ${BASEDIR:-/} memtest + exit $? +fi + +exit 0 diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T1000/platform.topo b/usr/src/pkgdefs/SUNWonmtst.i/prototype_com index e86aa70120..70b07b42ed 100644 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T1000/platform.topo +++ b/usr/src/pkgdefs/SUNWonmtst.i/prototype_com @@ -1,7 +1,4 @@ # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# # CDDL HEADER START # # The contents of this file are subject to the terms of the @@ -22,38 +19,34 @@ # # CDDL HEADER END # -#pragma ident "%Z%%M% %I% %E% SMI" - - -# -# Single mother board -# -/motherboard0 - PLAT-FRU=hc:///component=MB - # -# CPU chip -# -/motherboard0/cmp0 - PLAT-FRU=hc:///component=MB/CMP0 - +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. # -# 32 strands +#pragma ident "%Z%%M% %I% %E% SMI" # -/motherboard0/cmp0/cpu[0-31] +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment +# packaging files +i pkginfo +i copyright +i depend +i postinstall +i preremove # -# Leaf A +# source locations relative to the prototype file # -/motherboard0/hostbridge0/pciexrc[0] - DEV=/pci@780 - PLAT-FRU=hc:///component=MB - -# -# Leaf B +# SUNWonmtst.i # -/motherboard0/hostbridge0/pciexrc[1] - DEV=/pci@7c0 - PLAT-FRU=hc:///component=MB - +d none platform 755 root sys +d none usr 755 root sys +d none usr/platform 755 root sys +d none usr/bin 755 root bin diff --git a/usr/src/pkgdefs/SUNWonmtst.i/prototype_i386 b/usr/src/pkgdefs/SUNWonmtst.i/prototype_i386 new file mode 100644 index 0000000000..92fe94b555 --- /dev/null +++ b/usr/src/pkgdefs/SUNWonmtst.i/prototype_i386 @@ -0,0 +1,66 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment + +# +# Include ISA independent files (prototype_com) +# +!include prototype_com +# +# +# +# List files which are x86-specific here +# +# source locations relative to the prototype file +# +# +# SUNWonmtst +# +d none platform/i86pc 755 root sys +d none platform/i86pc/kernel 755 root sys +d none platform/i86pc/kernel/drv 755 root sys +d none platform/i86pc/kernel/drv/amd64 755 root sys +f none platform/i86pc/kernel/drv/amd64/memtest 755 root sys +f none platform/i86pc/kernel/drv/memtest 755 root sys +f none platform/i86pc/kernel/drv/memtest.conf 644 root sys +f none usr/bin/mtst 555 root bin +d none usr/include 755 root bin +d none usr/include/sys 755 root bin +f none usr/include/sys/memtest.h 644 root sys +d none usr/platform/i86pc 755 root sys +d none usr/platform/i86pc/lib 755 root bin +d none usr/platform/i86pc/lib/mtst 755 root bin +f none usr/platform/i86pc/lib/mtst/mtst_AuthenticAMD_15.so 755 root bin diff --git a/usr/src/pkgdefs/SUNWonmtst.u/pkginfo.tmpl b/usr/src/pkgdefs/SUNWonmtst.u/pkginfo.tmpl index 7b13fae57b..5096e4e3ee 100644 --- a/usr/src/pkgdefs/SUNWonmtst.u/pkginfo.tmpl +++ b/usr/src/pkgdefs/SUNWonmtst.u/pkginfo.tmpl @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -30,7 +30,7 @@ # and package architecture. # PKG="SUNWonmtst" -NAME="sun4u CPU/memory error injector" +NAME="CPU/memory error injector" ARCH="sparc.sun4u" VERSION="ONVERS,REV=0.0.0" SUNW_PRODNAME="SunOS" @@ -38,10 +38,10 @@ SUNW_PRODVERS="RELEASE/VERSION" SUNW_PKGTYPE="internal" MAXINST="1000" CATEGORY="internal" -DESC="Sun4u-specific CPU/memory error injector for internal testing" +DESC="CPU/memory error injector for internal testing" VENDOR="Sun Microsystems, Inc." -HOTLINE="Please contact Mike Shapiro (mws@eng)" -EMAIL="mws@eng" +HOTLINE="Please contact fma-interest@sun.com" +EMAIL="fma-interest@sun.com" CLASSES="none" BASEDIR=/ SUNW_PKGVERS="1.0" diff --git a/usr/src/pkgdefs/SUNWonmtst.v/pkginfo.tmpl b/usr/src/pkgdefs/SUNWonmtst.v/pkginfo.tmpl index 534a0f1d65..64c0e371ee 100644 --- a/usr/src/pkgdefs/SUNWonmtst.v/pkginfo.tmpl +++ b/usr/src/pkgdefs/SUNWonmtst.v/pkginfo.tmpl @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -30,7 +30,7 @@ # and package architecture. # PKG="SUNWonmtst" -NAME="sun4v CPU/memory error injector" +NAME="CPU/memory error injector" ARCH="sparc.sun4v" VERSION="ONVERS,REV=0.0.0" SUNW_PRODNAME="SunOS" @@ -38,10 +38,10 @@ SUNW_PRODVERS="RELEASE/VERSION" SUNW_PKGTYPE="internal" MAXINST="1000" CATEGORY="internal" -DESC="Sun4v-specific CPU/memory error injector for internal testing" +DESC="CPU/memory error injector for internal testing" VENDOR="Sun Microsystems, Inc." -HOTLINE="Please contact Mike Shapiro (mws@eng)" -EMAIL="mws@eng" +HOTLINE="Please contact fma-interest@sun.com" +EMAIL="fma-interest@sun.com" CLASSES="none" BASEDIR=/ SUNW_PKGVERS="1.0" diff --git a/usr/src/tools/scripts/bfu.sh b/usr/src/tools/scripts/bfu.sh index 1f36244a4c..dc15a45252 100644 --- a/usr/src/tools/scripts/bfu.sh +++ b/usr/src/tools/scripts/bfu.sh @@ -4344,6 +4344,16 @@ mondo_loop() { rm -rf $usr/platform/SUNW,Sun-Fire-15000/lib/fm # + # Remove old topology data + # + rm -rf $usr/lib/fm/topo + + # + # Remove old prtopo + # + rm -f $usr/lib/fm/prtopo + + # # Remove obsolete buildmnttab script. Backwards BFUs will # resurrect it by extracting it from the archives. # diff --git a/usr/src/tools/scripts/check_rtime.pl b/usr/src/tools/scripts/check_rtime.pl index 3d0b891dbf..d490f79345 100644 --- a/usr/src/tools/scripts/check_rtime.pl +++ b/usr/src/tools/scripts/check_rtime.pl @@ -117,7 +117,8 @@ $SkipUndefDirs = qr{ usr/lib/rmmount | # rmmount actions have callbacks /lib/mdb/ | # mdb modules have callbacks /lib/fm/fmd/plugins/ | # fmd modules have callbacks - /lib/fm/fmd/schemes/ # fmd schemes have callbacks + /lib/fm/fmd/schemes/ | # fmd schemes have callbacks + /i86pc/lib/mtst/ # mtst modules have callbacks }x; $SkipUndefFiles = qr{ ^(?: diff --git a/usr/src/uts/Makefile.targ b/usr/src/uts/Makefile.targ index aebc896db7..40526b3af2 100644 --- a/usr/src/uts/Makefile.targ +++ b/usr/src/uts/Makefile.targ @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -146,6 +146,9 @@ $(USR_MOD_DIRS_32): $(USR_MOD_DIR) $(ROOT_MOD_DIR)/%: $(OBJS_DIR)/% $(ROOT_MOD_DIR) FRC $(INS.file) +$(ROOT_CPU_DIR)/%: $(OBJS_DIR)/% $(ROOT_CPU_DIR) FRC + $(INS.file) + $(ROOT_DRV_DIR)/%: $(OBJS_DIR)/% $(ROOT_DRV_DIR) FRC $(INS.file) diff --git a/usr/src/uts/common/io/mem.c b/usr/src/uts/common/io/mem.c index 0569b0ebae..11667e8c59 100644 --- a/usr/src/uts/common/io/mem.c +++ b/usr/src/uts/common/io/mem.c @@ -68,13 +68,15 @@ #include <sys/debug.h> #include <sys/fm/protocol.h> -#ifdef __sparc +#if defined(__sparc) extern int cpu_get_mem_name(uint64_t, uint64_t *, uint64_t, char *, int, int *); extern int cpu_get_mem_info(uint64_t, uint64_t, uint64_t *, uint64_t *, uint64_t *, int *, int *, int *); extern size_t cpu_get_name_bufsize(void); extern int cpu_get_mem_sid(char *, char *, int, int *); extern int cpu_get_mem_addr(char *, char *, uint64_t, uint64_t *); +#elif defined(__i386) || defined(__amd64) +#include <sys/cpu_module.h> #endif /* __sparc */ /* @@ -415,6 +417,9 @@ mmwrite(dev_t dev, struct uio *uio, cred_t *cred) static int mmioctl_vtop(intptr_t data) { +#ifdef _SYSCALL32 + mem_vtop32_t vtop32; +#endif mem_vtop_t mem_vtop; proc_t *p; pfn_t pfn = (pfn_t)PFN_INVALID; @@ -422,13 +427,36 @@ mmioctl_vtop(intptr_t data) struct as *as; struct seg *seg; - if (copyin((void *)data, &mem_vtop, sizeof (mem_vtop_t))) - return (EFAULT); + if (get_udatamodel() == DATAMODEL_NATIVE) { + if (copyin((void *)data, &mem_vtop, sizeof (mem_vtop_t))) + return (EFAULT); + } +#ifdef _SYSCALL32 + else { + if (copyin((void *)data, &vtop32, sizeof (mem_vtop32_t))) + return (EFAULT); + mem_vtop.m_as = (struct as *)vtop32.m_as; + mem_vtop.m_va = (void *)vtop32.m_va; + + if (mem_vtop.m_as != NULL) + return (EINVAL); + } +#endif + if (mem_vtop.m_as == &kas) { pfn = hat_getpfnum(kas.a_hat, mem_vtop.m_va); - } else if (mem_vtop.m_as == NULL) { - return (EIO); } else { + if (mem_vtop.m_as == NULL) { + /* + * Assume the calling process's address space if the + * caller didn't specify one. + */ + p = curthread->t_procp; + if (p == NULL) + return (EIO); + mem_vtop.m_as = p->p_as; + } + mutex_enter(&pidlock); for (p = practive; p != NULL; p = p->p_next) { if (p->p_as == mem_vtop.m_as) { @@ -461,8 +489,18 @@ mmioctl_vtop(intptr_t data) mem_vtop.m_pfn = pfn; if (pfn == PFN_INVALID) return (EIO); - if (copyout(&mem_vtop, (void *)data, sizeof (mem_vtop_t))) - return (EFAULT); + + if (get_udatamodel() == DATAMODEL_NATIVE) { + if (copyout(&mem_vtop, (void *)data, sizeof (mem_vtop_t))) + return (EFAULT); + } +#ifdef _SYSCALL32 + else { + vtop32.m_pfn = mem_vtop.m_pfn; + if (copyout(&vtop32, (void *)data, sizeof (mem_vtop32_t))) + return (EFAULT); + } +#endif return (0); } @@ -533,7 +571,7 @@ mmioctl_page_fmri_retire(int cmd, intptr_t data) if ((err = mm_get_mem_fmri(&mpage, &nvl)) < 0) return (err); - if ((err = mm_get_paddr(nvl, &pa)) < 0) { + if ((err = mm_get_paddr(nvl, &pa)) != 0) { nvlist_free(nvl); return (err); } @@ -1120,7 +1158,7 @@ mm_get_paddr(nvlist_t *nvl, uint64_t *paddr) * If the "offset" member is not present, then the address is * retrieved from the "physaddr" member. */ -#ifdef __sparc +#if defined(__sparc) if (nvlist_lookup_uint64(nvl, FM_FMRI_MEM_OFFSET, &offset) != 0) { if (nvlist_lookup_uint64(nvl, FM_FMRI_MEM_PHYSADDR, &pa) != 0) { @@ -1134,9 +1172,11 @@ mm_get_paddr(nvlist_t *nvl, uint64_t *paddr) if ((err = cpu_get_mem_addr(unum, serids[0], offset, &pa)) != 0) return (err); } -#else /* __i386, __amd64 */ - if (nvlist_lookup_uint64(nvl, FM_FMRI_MEM_PHYSADDR, &pa) != 0) +#elif defined(__i386) || defined(__amd64) + if (cmi_mc_unumtopa(NULL, nvl, &pa) == 0) return (EINVAL); +#else +#error "port me" #endif /* __sparc */ *paddr = pa; diff --git a/usr/src/uts/common/krtld/kobj.c b/usr/src/uts/common/krtld/kobj.c index 6df0916ea0..003022d104 100644 --- a/usr/src/uts/common/krtld/kobj.c +++ b/usr/src/uts/common/krtld/kobj.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -2970,7 +2970,7 @@ kobj_getelfsym(char *name, void *mp, int *size) } uintptr_t -kobj_lookup(void *mod, char *name) +kobj_lookup(struct module *mod, const char *name) { Sym *sp; diff --git a/usr/src/uts/common/krtld/kobj_stubs.c b/usr/src/uts/common/krtld/kobj_stubs.c index 7bc82c5139..3d972194bb 100644 --- a/usr/src/uts/common/krtld/kobj_stubs.c +++ b/usr/src/uts/common/krtld/kobj_stubs.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -159,7 +159,7 @@ kobj_searchsym(struct module *mp, uintptr_t value, ulong_t *offset) /*ARGSUSED*/ uintptr_t -kobj_lookup(void *mod, char *name) +kobj_lookup(struct module *mod, const char *name) { return (0); } diff --git a/usr/src/uts/common/os/chip.c b/usr/src/uts/common/os/chip.c index b6fcbe89d2..8b0bfd765d 100644 --- a/usr/src/uts/common/os/chip.c +++ b/usr/src/uts/common/os/chip.c @@ -124,6 +124,18 @@ chip_find(chipid_t chipid) return (NULL); } +chip_t * +chip_lookup(chipid_t chipid) +{ + chip_t *chp; + + mutex_enter(&cpu_lock); + chp = chip_find(chipid); + mutex_exit(&cpu_lock); + + return (chp); +} + #ifndef sun4v /* * Setup the kstats for this chip, if needed diff --git a/usr/src/uts/common/os/cpu.c b/usr/src/uts/common/os/cpu.c index e9f4453f81..674f8bd6e5 100644 --- a/usr/src/uts/common/os/cpu.c +++ b/usr/src/uts/common/os/cpu.c @@ -59,6 +59,9 @@ #include <sys/msacct.h> #include <sys/time.h> #include <sys/archsystm.h> +#if defined(__i386) || defined(__amd64) +#include <sys/x86_archext.h> +#endif extern int mp_cpu_start(cpu_t *); extern int mp_cpu_stop(cpu_t *); @@ -2067,12 +2070,19 @@ static struct { kstat_named_t ci_clock_MHz; kstat_named_t ci_chip_id; kstat_named_t ci_implementation; -#ifdef __sparcv9 + kstat_named_t ci_brandstr; + kstat_named_t ci_core_id; +#if defined(__sparcv9) kstat_named_t ci_device_ID; kstat_named_t ci_cpu_fru; #endif - kstat_named_t ci_brandstr; - kstat_named_t ci_core_id; +#if defined(__i386) || defined(__amd64) + kstat_named_t ci_vendorstr; + kstat_named_t ci_family; + kstat_named_t ci_model; + kstat_named_t ci_step; + kstat_named_t ci_clogid; +#endif } cpu_info_template = { { "state", KSTAT_DATA_CHAR }, { "state_begin", KSTAT_DATA_LONG }, @@ -2081,12 +2091,19 @@ static struct { { "clock_MHz", KSTAT_DATA_LONG }, { "chip_id", KSTAT_DATA_LONG }, { "implementation", KSTAT_DATA_STRING }, -#ifdef __sparcv9 + { "brand", KSTAT_DATA_STRING }, + { "core_id", KSTAT_DATA_LONG }, +#if defined(__sparcv9) { "device_ID", KSTAT_DATA_UINT64 }, { "cpu_fru", KSTAT_DATA_STRING }, #endif - { "brand", KSTAT_DATA_STRING }, - { "core_id", KSTAT_DATA_LONG }, +#if defined(__i386) || defined(__amd64) + { "vendor_id", KSTAT_DATA_STRING }, + { "family", KSTAT_DATA_INT32 }, + { "model", KSTAT_DATA_INT32 }, + { "stepping", KSTAT_DATA_INT32 }, + { "clog_id", KSTAT_DATA_INT32 }, +#endif }; static kmutex_t cpu_info_template_lock; @@ -2132,13 +2149,23 @@ cpu_info_kstat_update(kstat_t *ksp, int rw) cpu_info_template.ci_chip_id.value.l = chip_plat_get_chipid(cp); kstat_named_setstr(&cpu_info_template.ci_implementation, cp->cpu_idstr); -#ifdef __sparcv9 + kstat_named_setstr(&cpu_info_template.ci_brandstr, cp->cpu_brandstr); + +#if defined(__sparcv9) cpu_info_template.ci_device_ID.value.ui64 = cpunodes[cp->cpu_id].device_id; kstat_named_setstr(&cpu_info_template.ci_cpu_fru, cpu_fru_fmri(cp)); #endif - kstat_named_setstr(&cpu_info_template.ci_brandstr, cp->cpu_brandstr); +#if defined(__i386) || defined(__amd64) cpu_info_template.ci_core_id.value.l = chip_plat_get_coreid(cp); + kstat_named_setstr(&cpu_info_template.ci_vendorstr, + cpuid_getvendorstr(cp)); + cpu_info_template.ci_family.value.l = cpuid_getfamily(cp); + cpu_info_template.ci_model.value.l = cpuid_getmodel(cp); + cpu_info_template.ci_step.value.l = cpuid_getstep(cp); + cpu_info_template.ci_clogid.value.l = chip_plat_get_clogid(cp); +#endif + return (0); } @@ -2155,13 +2182,16 @@ cpu_info_kstat_create(cpu_t *cp) zoneid = ALL_ZONES; if ((cp->cpu_info_kstat = kstat_create_zone("cpu_info", cp->cpu_id, NULL, "misc", KSTAT_TYPE_NAMED, - sizeof (cpu_info_template) / sizeof (kstat_named_t), - KSTAT_FLAG_VIRTUAL, zoneid)) != NULL) { + sizeof (cpu_info_template) / sizeof (kstat_named_t), + KSTAT_FLAG_VIRTUAL, zoneid)) != NULL) { cp->cpu_info_kstat->ks_data_size += 2 * CPU_IDSTRLEN; -#ifdef __sparcv9 +#if defined(__sparcv9) cp->cpu_info_kstat->ks_data_size += strlen(cpu_fru_fmri(cp)) + 1; #endif +#if defined(__i386) || defined(__amd64) + cp->cpu_info_kstat->ks_data_size += X86_VENDOR_STRLEN; +#endif cp->cpu_info_kstat->ks_lock = &cpu_info_template_lock; cp->cpu_info_kstat->ks_data = &cpu_info_template; cp->cpu_info_kstat->ks_private = cp; diff --git a/usr/src/uts/common/os/ddifm.c b/usr/src/uts/common/os/ddifm.c index 911a7d9a2f..6edd829ba8 100644 --- a/usr/src/uts/common/os/ddifm.c +++ b/usr/src/uts/common/os/ddifm.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -477,7 +477,10 @@ ddi_fm_handler_register(dev_info_t *dip, ddi_err_func_t handler, return; } - pdip = (dev_info_t *)DEVI(dip)->devi_parent; + if (dip == ddi_root_node()) + pdip = dip; + else + pdip = (dev_info_t *)DEVI(dip)->devi_parent; ASSERT(pdip); @@ -529,7 +532,10 @@ ddi_fm_handler_unregister(dev_info_t *dip) return; } - pdip = (dev_info_t *)DEVI(dip)->devi_parent; + if (dip == ddi_root_node()) + pdip = dip; + else + pdip = (dev_info_t *)DEVI(dip)->devi_parent; ASSERT(pdip); @@ -581,10 +587,11 @@ ddi_fm_handler_unregister(dev_info_t *dip) * This function must be called from a driver's attach(9E) entry point. */ void -ddi_fm_init(dev_info_t *dip, int *fmcap, ddi_iblock_cookie_t *ibc) +ddi_fm_init(dev_info_t *dip, int *fmcap, ddi_iblock_cookie_t *ibcp) { struct dev_info *devi = DEVI(dip); struct i_ddi_fmhdl *fmhdl; + ddi_iblock_cookie_t ibc; int pcap, newcap = DDI_FM_NOT_CAPABLE; if (!DEVI_IS_ATTACHING(dip)) { @@ -606,11 +613,12 @@ ddi_fm_init(dev_info_t *dip, int *fmcap, ddi_iblock_cookie_t *ibc) * Initialize the default ibc. The parent may change it * depending upon its capabilities. */ - *ibc = (ddi_iblock_cookie_t)ipltospl(FM_ERR_PIL); + ibc = (ddi_iblock_cookie_t)ipltospl(FM_ERR_PIL); - pcap = i_ndi_busop_fm_init(dip, *fmcap, ibc); + pcap = i_ndi_busop_fm_init(dip, *fmcap, &ibc); } else { pcap = *fmcap; + ibc = *ibcp; } /* Initialize the per-device instance FM handle */ @@ -636,7 +644,7 @@ ddi_fm_init(dev_info_t *dip, int *fmcap, ddi_iblock_cookie_t *ibc) fmhdl->fh_acc_cache = NULL; fmhdl->fh_tgts = NULL; fmhdl->fh_dip = dip; - fmhdl->fh_ibc = *ibc; + fmhdl->fh_ibc = ibc; mutex_init(&fmhdl->fh_lock, NULL, MUTEX_DRIVER, fmhdl->fh_ibc); devi->devi_fmhdl = fmhdl; @@ -672,7 +680,7 @@ ddi_fm_init(dev_info_t *dip, int *fmcap, ddi_iblock_cookie_t *ibc) */ if (DDI_FM_DMA_ERR_CAP(*fmcap) && DDI_FM_DMA_ERR_CAP(pcap)) { - i_ndi_fmc_create(&fmhdl->fh_dma_cache, 2, *ibc); + i_ndi_fmc_create(&fmhdl->fh_dma_cache, 2, ibc); /* Set-up dma chk capability prop */ if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, @@ -684,7 +692,7 @@ ddi_fm_init(dev_info_t *dip, int *fmcap, ddi_iblock_cookie_t *ibc) } if (DDI_FM_ACC_ERR_CAP(*fmcap) && DDI_FM_ACC_ERR_CAP(pcap)) { - i_ndi_fmc_create(&fmhdl->fh_acc_cache, 2, *ibc); + i_ndi_fmc_create(&fmhdl->fh_acc_cache, 2, ibc); /* Set-up dma chk capability prop */ if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "fm-accchk-capable", 0) == 0) @@ -700,6 +708,9 @@ ddi_fm_init(dev_info_t *dip, int *fmcap, ddi_iblock_cookie_t *ibc) */ fmhdl->fh_cap = newcap; *fmcap = newcap; + + if (ibcp != NULL) + *ibcp = ibc; } /* diff --git a/usr/src/uts/common/os/fm.c b/usr/src/uts/common/os/fm.c index 33e8357a88..897697c2dc 100644 --- a/usr/src/uts/common/os/fm.c +++ b/usr/src/uts/common/os/fm.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -60,7 +60,6 @@ #include <sys/sysevent.h> #include <sys/sysevent_impl.h> #include <sys/nvpair.h> -#include <sys/nvpair_impl.h> #include <sys/cmn_err.h> #include <sys/cpuvar.h> #include <sys/sysmacros.h> @@ -73,6 +72,8 @@ #include <sys/cpuvar.h> #include <sys/console.h> #include <sys/panic.h> +#include <sys/kobj.h> +#include <sys/sunddi.h> #include <sys/systeminfo.h> #include <sys/sysevent/eventdefs.h> #include <sys/fm/util.h> @@ -614,15 +615,13 @@ fm_nvlist_create(nv_alloc_t *nva) void fm_nvlist_destroy(nvlist_t *nvl, int flag) { - nv_alloc_t *nvhdl; - - nvhdl = ((nvpriv_t *)(uintptr_t)nvl->nvl_priv)->nvp_nva; + nv_alloc_t *nva = nvlist_lookup_nv_alloc(nvl); nvlist_free(nvl); - if (nvhdl != NULL) { + if (nva != NULL) { if (flag == FM_NVA_FREE) - fm_nva_xdestroy(nvhdl); + fm_nva_xdestroy(nva); } } @@ -820,53 +819,88 @@ fm_ereport_set(nvlist_t *ereport, int version, const char *erpt_class, atomic_add_64(&erpt_kstat_data.erpt_set_failed.value.ui64, 1); } +/* + * Set-up and validate the members of an hc fmri according to; + * + * Member name Type Value + * =================================================== + * version uint8_t 0 + * auth nvlist_t <auth> + * hc-name string <name> + * hc-id string <id> + * + * Note that auth and hc-id are optional members. + */ + +#define HC_MAXPAIRS 20 +#define HC_MAXNAMELEN 50 + static int -i_fm_fmri_hc_set_v0(nvlist_t *hc, uint32_t size, va_list ap) +fm_fmri_hc_set_common(nvlist_t *fmri, int version, const nvlist_t *auth) { - int i, ret; - const char *name, *id; - nvlist_t **hc_nvl; + if (version != FM_HC_SCHEME_VERSION) { + atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); + return (0); + } - if (size <= 0) + if (nvlist_add_uint8(fmri, FM_VERSION, version) != 0 || + nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC) != 0) { + atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); return (0); + } - hc_nvl = kmem_zalloc(size * sizeof (nvlist_t *), KM_SLEEP); + if (auth != NULL && nvlist_add_nvlist(fmri, FM_FMRI_AUTHORITY, + (nvlist_t *)auth) != 0) { + atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); + return (0); + } - for (i = 0; i < size; ++i) { - name = va_arg(ap, const char *); - if (name == NULL) { - ret = EINVAL; - goto fail; - } - id = va_arg(ap, const char *); - if ((hc_nvl[i] = fm_nvlist_create( - ((nvpriv_t *)(uintptr_t)hc->nvl_priv)->nvp_nva)) == NULL) { - ret = ENOMEM; - goto fail; + return (1); +} + +void +fm_fmri_hc_set(nvlist_t *fmri, int version, const nvlist_t *auth, + nvlist_t *snvl, int npairs, ...) +{ + nv_alloc_t *nva = nvlist_lookup_nv_alloc(fmri); + nvlist_t *pairs[HC_MAXPAIRS]; + va_list ap; + int i; + + if (!fm_fmri_hc_set_common(fmri, version, auth)) + return; + + npairs = MIN(npairs, HC_MAXPAIRS); + + va_start(ap, npairs); + for (i = 0; i < npairs; i++) { + const char *name = va_arg(ap, const char *); + uint32_t id = va_arg(ap, uint32_t); + char idstr[11]; + + (void) snprintf(idstr, sizeof (idstr), "%u", id); + + pairs[i] = fm_nvlist_create(nva); + if (nvlist_add_string(pairs[i], FM_FMRI_HC_NAME, name) != 0 || + nvlist_add_string(pairs[i], FM_FMRI_HC_ID, idstr) != 0) { + atomic_add_64( + &erpt_kstat_data.fmri_set_failed.value.ui64, 1); } - if ((ret = nvlist_add_string(hc_nvl[i], FM_FMRI_HC_NAME, - name)) != 0) - goto fail; - if ((ret = nvlist_add_string(hc_nvl[i], FM_FMRI_HC_ID, - id)) != 0) - goto fail; } + va_end(ap); - if ((ret = nvlist_add_nvlist_array(hc, FM_FMRI_HC_LIST, hc_nvl, - size)) != 0) - goto fail; + if (nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST, pairs, npairs) != 0) + atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); - kmem_free(hc_nvl, size * sizeof (nvlist_t *)); - return (0); + for (i = 0; i < npairs; i++) + fm_nvlist_destroy(pairs[i], FM_NVA_RETAIN); -fail: - for (i = 0; i < size; ++i) { - if (hc_nvl[i] != NULL) - fm_nvlist_destroy(hc_nvl[i], FM_NVA_RETAIN); + if (snvl != NULL) { + if (nvlist_add_nvlist(fmri, FM_FMRI_HC_SPECIFIC, snvl) != 0) { + atomic_add_64( + &erpt_kstat_data.fmri_set_failed.value.ui64, 1); + } } - - kmem_free(hc_nvl, size * sizeof (nvlist_t *)); - return (ret); } /* @@ -930,47 +964,45 @@ fm_fmri_dev_set(nvlist_t *fmri_dev, int version, const nvlist_t *auth, * cpumask uint8_t <cpu_mask> * serial uint64_t <serial_id> * - * Note that auth is an optional member. + * Note that auth, cpumask, serial are optional members. * */ void fm_fmri_cpu_set(nvlist_t *fmri_cpu, int version, const nvlist_t *auth, - uint32_t cpu_id, uint8_t cpu_mask, uint64_t serial_id) + uint32_t cpu_id, uint8_t *cpu_maskp, const char *serial_idp) { - if (version != CPU_SCHEME_VERSION0) { - atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); + uint64_t *failedp = &erpt_kstat_data.fmri_set_failed.value.ui64; + + if (version < CPU_SCHEME_VERSION1) { + atomic_add_64(failedp, 1); return; } if (nvlist_add_uint8(fmri_cpu, FM_VERSION, version) != 0) { - atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); + atomic_add_64(failedp, 1); return; } if (nvlist_add_string(fmri_cpu, FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU) != 0) { - atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); + atomic_add_64(failedp, 1); return; } - if (auth != NULL) - if (nvlist_add_nvlist(fmri_cpu, FM_FMRI_AUTHORITY, - (nvlist_t *)auth) != 0) { - atomic_add_64( - &erpt_kstat_data.fmri_set_failed.value.ui64, 1); - } + if (auth != NULL && nvlist_add_nvlist(fmri_cpu, FM_FMRI_AUTHORITY, + (nvlist_t *)auth) != 0) + atomic_add_64(failedp, 1); - if (nvlist_add_uint32(fmri_cpu, FM_FMRI_CPU_ID, cpu_id) != 0) { - atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); - } + if (nvlist_add_uint32(fmri_cpu, FM_FMRI_CPU_ID, cpu_id) != 0) + atomic_add_64(failedp, 1); - if (nvlist_add_uint8(fmri_cpu, FM_FMRI_CPU_MASK, cpu_mask) != 0) { - atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); - } + if (cpu_maskp != NULL && nvlist_add_uint8(fmri_cpu, FM_FMRI_CPU_MASK, + *cpu_maskp) != 0) + atomic_add_64(failedp, 1); - if (nvlist_add_uint64(fmri_cpu, FM_FMRI_CPU_SERIAL_ID, serial_id) - != 0) - atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); + if (serial_idp == NULL || nvlist_add_string(fmri_cpu, + FM_FMRI_CPU_SERIAL_ID, (char *)serial_idp) != 0) + atomic_add_64(failedp, 1); } /* @@ -1159,3 +1191,29 @@ fm_ena_time_get(uint64_t ena) return (time); } + +/* + * Convert a getpcstack() trace to symbolic name+offset, and add the resulting + * string array to a Fault Management ereport as FM_EREPORT_PAYLOAD_NAME_STACK. + */ +void +fm_payload_stack_add(nvlist_t *payload, const pc_t *stack, int depth) +{ + int i; + char *sym; + ulong_t off; + char *stkpp[FM_STK_DEPTH]; + char buf[FM_STK_DEPTH * FM_SYM_SZ]; + char *stkp = buf; + + for (i = 0; i < depth && i != FM_STK_DEPTH; i++, stkp += FM_SYM_SZ) { + if ((sym = kobj_getsymname(stack[i], &off)) != NULL) + (void) snprintf(stkp, FM_SYM_SZ, "%s+%lx", sym, off); + else + (void) snprintf(stkp, FM_SYM_SZ, "%lx", (long)stack[i]); + stkpp[i] = stkp; + } + + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_STACK, + DATA_TYPE_STRING_ARRAY, FM_STK_DEPTH, stkpp, NULL); +} diff --git a/usr/src/uts/common/os/kcpc.c b/usr/src/uts/common/os/kcpc.c index f3bfd93d24..569344e8ca 100644 --- a/usr/src/uts/common/os/kcpc.c +++ b/usr/src/uts/common/os/kcpc.c @@ -19,8 +19,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -1515,41 +1516,12 @@ kcpc_invalidate(kthread_t *t) int kcpc_pcbe_tryload(const char *prefix, uint_t first, uint_t second, uint_t third) { - char modname[PCBE_NAMELEN]; - char stub[PCBE_NAMELEN]; - - if (prefix != NULL) - (void) snprintf(stub, PCBE_NAMELEN, "pcbe.%s", prefix); - else - (void) snprintf(stub, PCBE_NAMELEN, "pcbe"); - - (void) snprintf(modname, PCBE_NAMELEN, "%s.%u.%u.%u", - stub, first, second, third); - - DTRACE_PROBE1(kcpc__pcbe__spec, char *, modname); - - if (modload("pcbe", modname) >= 0) - return (0); - - (void) snprintf(modname, PCBE_NAMELEN, "%s.%u.%u", - stub, first, second); - if (modload("pcbe", modname) >= 0) - return (0); - - (void) snprintf(modname, PCBE_NAMELEN, "%s.%u", stub, first); - if (modload("pcbe", modname) >= 0) - return (0); - - if (prefix == NULL) - /* - * If no prefix was given, we have tried all possible - * PCBE names. - */ - return (-1); + uint_t s[3]; - (void) snprintf(modname, PCBE_NAMELEN, "%s", stub); - if (modload("pcbe", modname) >= 0) - return (0); + s[0] = first; + s[1] = second; + s[2] = third; - return (-1); + return (modload_qualified("pcbe", + "pcbe", prefix, ".", s, 3) < 0 ? -1 : 0); } diff --git a/usr/src/uts/common/os/modconf.c b/usr/src/uts/common/os/modconf.c index 2c033495bc..f270cad2a0 100644 --- a/usr/src/uts/common/os/modconf.c +++ b/usr/src/uts/common/os/modconf.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -101,6 +101,11 @@ struct mod_ops mod_miscops = { mod_null, mod_null, mod_infonull }; +/* CPU Modules */ +struct mod_ops mod_cpuops = { + mod_null, mod_null, mod_infonull +}; + /* * Cryptographic Modules */ diff --git a/usr/src/uts/common/os/modctl.c b/usr/src/uts/common/os/modctl.c index 73e0447ab1..e776a36310 100644 --- a/usr/src/uts/common/os/modctl.c +++ b/usr/src/uts/common/os/modctl.c @@ -19,6 +19,7 @@ * * CDDL HEADER END */ + /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. @@ -84,15 +85,14 @@ static int modinfo(modid_t, struct modinfo *); static void mod_uninstall_all(void); static int mod_getinfo(struct modctl *, struct modinfo *); -static struct modctl *allocate_modp(char *, char *); +static struct modctl *allocate_modp(const char *, const char *); static int mod_load(struct modctl *, int); static void mod_unload(struct modctl *); static int modinstall(struct modctl *); static int moduninstall(struct modctl *); -static struct modctl *mod_hold_by_name_common(struct modctl *, char *); -static struct modctl *mod_hold_by_id(modid_t); +static struct modctl *mod_hold_by_name_common(struct modctl *, const char *); static struct modctl *mod_hold_next_by_id(modid_t); static struct modctl *mod_hold_loaded_mod(struct modctl *, char *, int *); static struct modctl *mod_hold_installed_mod(char *, int, int *); @@ -1943,6 +1943,71 @@ modload(char *subdir, char *filename) } /* + * Load a module using a series of qualified names from most specific to least + * specific, e.g. for subdir "foo", p1 "bar", p2 "baz", we might try: + * + * foo/bar.baz.1.2.3 + * foo/bar.baz.1.2 + * foo/bar.baz.1 + * + * Return the module ID on success; -1 if no module was loaded. + */ +int +modload_qualified(const char *subdir, const char *p1, + const char *p2, const char *delim, uint_t suffv[], int suffc) +{ + char path[MOD_MAXPATH]; + size_t n, resid = sizeof (path); + char *p = path; + + char **dotv; + int i, rc, id; + modctl_t *mp; + + if (p2 != NULL) + n = snprintf(p, resid, "%s/%s%s%s", subdir, p1, delim, p2); + else + n = snprintf(p, resid, "%s/%s", subdir, p1); + + if (n >= resid) + return (-1); + + p += n; + resid -= n; + dotv = kmem_alloc(sizeof (char *) * (suffc + 1), KM_SLEEP); + + for (i = 0; i < suffc; i++) { + dotv[i] = p; + n = snprintf(p, resid, "%s%u", delim, suffv[i]); + + if (n >= resid) { + kmem_free(dotv, sizeof (char *) * (suffc + 1)); + return (-1); + } + + p += n; + resid -= n; + } + + dotv[suffc] = p; + + for (i = suffc; i >= 0; i--) { + dotv[i][0] = '\0'; + mp = mod_hold_installed_mod(path, 1, &rc); + + if (mp != NULL) { + kmem_free(dotv, sizeof (char *) * (suffc + 1)); + id = mp->mod_id; + mod_release_mod(mp); + return (id); + } + } + + kmem_free(dotv, sizeof (char *) * (suffc + 1)); + return (-1); +} + +/* * Load a module. */ int @@ -2440,7 +2505,7 @@ modadd(struct modctl *mp) /*ARGSUSED*/ static struct modctl * -allocate_modp(char *filename, char *modname) +allocate_modp(const char *filename, const char *modname) { struct modctl *mp; @@ -2473,12 +2538,12 @@ modgetsymname(uintptr_t value, ulong_t *offset) } /* - * Lookup a symbol in a specified module. This is a wrapper routine that - * calls kobj_lookup(). kobj_lookup() may go away but this - * wrapper will prevent callers from noticing. + * Lookup a symbol in a specified module. These are wrapper routines that + * call kobj_lookup(). kobj_lookup() may go away but these wrappers will + * prevent callers from noticing. */ uintptr_t -modlookup(char *modname, char *symname) +modlookup(const char *modname, const char *symname) { struct modctl *modp; uintptr_t val; @@ -2490,6 +2555,14 @@ modlookup(char *modname, char *symname) return (val); } +uintptr_t +modlookup_by_modctl(modctl_t *modp, const char *symname) +{ + ASSERT(modp->mod_ref > 0 || modp->mod_busy); + + return (kobj_lookup(modp->mod_mp, symname)); +} + /* * Ask the user for the name of the system file and the default path * for modules. @@ -3149,9 +3222,9 @@ mod_hold_by_modctl(struct modctl *mp, int f) } static struct modctl * -mod_hold_by_name_common(struct modctl *dep, char *filename) +mod_hold_by_name_common(struct modctl *dep, const char *filename) { - char *modname; + const char *modname; struct modctl *mp; char *curname, *newname; int found = 0; @@ -3232,12 +3305,12 @@ mod_hold_by_name_requisite(struct modctl *dep, char *filename) } struct modctl * -mod_hold_by_name(char *filename) +mod_hold_by_name(const char *filename) { return (mod_hold_by_name_common(NULL, filename)); } -static struct modctl * +struct modctl * mod_hold_by_id(modid_t modid) { struct modctl *mp; diff --git a/usr/src/uts/common/os/panic.c b/usr/src/uts/common/os/panic.c index e085b0e586..87910574f5 100644 --- a/usr/src/uts/common/os/panic.c +++ b/usr/src/uts/common/os/panic.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -143,6 +143,7 @@ #include <sys/spl.h> #include <sys/errorq.h> #include <sys/panic.h> +#include <sys/fm/util.h> /* * Panic variables which are set once during the QUIESCE state by the diff --git a/usr/src/uts/common/os/policy.c b/usr/src/uts/common/os/policy.c index 0dccc35dce..fe4a5c82df 100644 --- a/usr/src/uts/common/os/policy.c +++ b/usr/src/uts/common/os/policy.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -1279,6 +1279,12 @@ secpolicy_kmdb(const cred_t *scr) return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); } +int +secpolicy_error_inject(const cred_t *scr) +{ + return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); +} + /* * Processor sets, cpu configuration, resource pools. */ diff --git a/usr/src/uts/common/sys/Makefile b/usr/src/uts/common/sys/Makefile index bb8e6e8d7a..f82a933903 100644 --- a/usr/src/uts/common/sys/Makefile +++ b/usr/src/uts/common/sys/Makefile @@ -20,7 +20,7 @@ # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -657,12 +657,6 @@ FMHDRS= \ protocol.h \ util.h -sparc_FMCPUHDRS= \ - UltraSPARC-II.h \ - UltraSPARC-III.h \ - UltraSPARC-T1.h -FMCPUHDRS=$($(MACH)_FMCPUHDRS) - FMIOHDRS= \ ddi.h \ pci.h \ @@ -920,7 +914,6 @@ CHECKHDRS= \ $(TAVORHDRS:%.h=ib/adapters/tavor/%.check) \ $(ISOHDRS:%.h=iso/%.check) \ $(FMHDRS:%.h=fm/%.check) \ - $(FMCPUHDRS:%.h=fm/cpu/%.check) \ $(FMIOHDRS:%.h=fm/io/%.check) \ $(FSHDRS:%.h=fs/%.check) \ $(LVMHDRS:%.h=lvm/%.check) \ @@ -955,8 +948,7 @@ CHECKHDRS= \ $(ROOTDCAMHDRS) \ $(ROOTISOHDRS) \ $(ROOTFMHDRS) \ - $(ROOTFMCPUHDRS) \ - $(ROOTFMIOHDRS) \ + $(ROOTFMIOHDRS) \ $(ROOTFSHDRS) \ $(ROOTIBDHDRS) \ $(ROOTIBHDRS) \ @@ -1000,7 +992,6 @@ install_h: \ $(ROOTDCAMHDRS) \ $(ROOTISOHDRS) \ $(ROOTFMHDRS) \ - $(ROOTFMCPUHDRS) \ $(ROOTFMIOHDRS) \ $(ROOTFSHDRS) \ $(ROOTIBDHDRS) \ diff --git a/usr/src/uts/common/sys/chip.h b/usr/src/uts/common/sys/chip.h index e33b521783..80b9541d9a 100644 --- a/usr/src/uts/common/sys/chip.h +++ b/usr/src/uts/common/sys/chip.h @@ -172,6 +172,7 @@ void chip_cpu_fini(cpu_t *); void chip_cpu_assign(cpu_t *); void chip_cpu_unassign(cpu_t *); void chip_cpu_startup(cpu_t *); +chip_t *chip_lookup(chipid_t); void chip_bootstrap_cpu(cpu_t *); void chip_cpu_move_part(cpu_t *, struct cpupart *, diff --git a/usr/src/uts/common/sys/dumphdr.h b/usr/src/uts/common/sys/dumphdr.h index 7be14a40ed..5949b218c8 100644 --- a/usr/src/uts/common/sys/dumphdr.h +++ b/usr/src/uts/common/sys/dumphdr.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -33,7 +33,6 @@ #include <sys/param.h> #include <sys/utsname.h> #include <sys/log.h> -#include <sys/fm/util.h> #ifdef __cplusplus extern "C" { diff --git a/usr/src/uts/common/sys/fm/protocol.h b/usr/src/uts/common/sys/fm/protocol.h index 32f4d099f0..89b761ef6c 100644 --- a/usr/src/uts/common/sys/fm/protocol.h +++ b/usr/src/uts/common/sys/fm/protocol.h @@ -21,7 +21,7 @@ */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -177,7 +177,8 @@ extern "C" { #define FM_HC_VERS0 0 #define FM_HC_SCHEME_VERSION FM_HC_VERS0 #define CPU_SCHEME_VERSION0 0 -#define FM_CPU_SCHEME_VERSION CPU_SCHEME_VERSION0 +#define CPU_SCHEME_VERSION1 1 +#define FM_CPU_SCHEME_VERSION CPU_SCHEME_VERSION1 #define MEM_SCHEME_VERSION0 0 #define FM_MEM_SCHEME_VERSION MEM_SCHEME_VERSION0 #define MOD_SCHEME_VERSION0 0 @@ -194,6 +195,7 @@ extern "C" { #define FM_FMRI_HC_ROOT "hc-root" #define FM_FMRI_HC_LIST_SZ "hc-list-sz" #define FM_FMRI_HC_LIST "hc-list" +#define FM_FMRI_HC_SPECIFIC "hc-specific" /* hc-list version and member names */ #define FM_FMRI_HC_NAME "hc-name" @@ -202,6 +204,9 @@ extern "C" { #define HC_LIST_VERSION0 0 #define FM_HC_LIST_VERSION HC_LIST_VERSION0 +/* hc-specific member names */ +#define FM_FMRI_HC_SPECIFIC_OFFSET "offset" + /* fmd module scheme member names */ #define FM_FMRI_FMD_NAME "mod-name" #define FM_FMRI_FMD_VERSION "mod-version" @@ -261,13 +266,13 @@ extern void fm_ereport_set(nvlist_t *, int, const char *, uint64_t, const nvlist_t *, ...); extern void fm_payload_set(nvlist_t *, ...); extern int i_fm_payload_set(nvlist_t *, const char *, va_list); -extern void fm_fmri_hc_set(nvlist_t *, int, const nvlist_t *, const char *, - const char *, const char *, const char *, uint32_t, ...); +extern void fm_fmri_hc_set(nvlist_t *, int, const nvlist_t *, nvlist_t *, + int, ...); extern void fm_fmri_dev_set(nvlist_t *, int, const nvlist_t *, const char *, const char *); extern void fm_fmri_de_set(nvlist_t *, int, const nvlist_t *, const char *); extern void fm_fmri_cpu_set(nvlist_t *, int, const nvlist_t *, uint32_t, - uint8_t, uint64_t); + uint8_t *, const char *); extern void fm_fmri_mem_set(nvlist_t *, int, const nvlist_t *, const char *, const char *, uint64_t); extern void fm_authority_set(nvlist_t *, int, const char *, const char *, diff --git a/usr/src/uts/common/sys/fm/util.h b/usr/src/uts/common/sys/fm/util.h index c0dc908ddc..33f5876cab 100644 --- a/usr/src/uts/common/sys/fm/util.h +++ b/usr/src/uts/common/sys/fm/util.h @@ -19,8 +19,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -74,9 +75,14 @@ typedef struct erpt_dump { } erpt_dump_t; #ifdef _KERNEL +#include <sys/systm.h> +#define FM_STK_DEPTH 20 /* maximum stack depth */ +#define FM_SYM_SZ 64 /* maximum symbol size */ #define FM_ERR_PIL 2 /* PIL for ereport_errorq drain processing */ +#define FM_EREPORT_PAYLOAD_NAME_STACK "stack" + extern errorq_t *ereport_errorq; extern void *ereport_dumpbuf; extern size_t ereport_dumplen; @@ -89,6 +95,8 @@ extern void fm_banner(void); extern void fm_ereport_dump(void); extern void fm_ereport_post(nvlist_t *, int); +extern void fm_payload_stack_add(nvlist_t *, const pc_t *, int); + #endif /* _KERNEL */ #ifdef __cplusplus diff --git a/usr/src/uts/common/sys/kobj.h b/usr/src/uts/common/sys/kobj.h index c2f8b2f9cb..7d2bd0922e 100644 --- a/usr/src/uts/common/sys/kobj.h +++ b/usr/src/uts/common/sys/kobj.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -152,7 +152,7 @@ typedef struct { extern int kobj_load_module(struct modctl *, int); extern void kobj_unload_module(struct modctl *); -extern uintptr_t kobj_lookup(void *, char *); +extern uintptr_t kobj_lookup(struct module *, const char *); extern Sym *kobj_lookup_all(struct module *, char *, int); extern int kobj_addrcheck(void *, caddr_t); extern int kobj_module_to_id(void *); diff --git a/usr/src/uts/common/sys/mem.h b/usr/src/uts/common/sys/mem.h index f6f749ef0e..d1307589a1 100644 --- a/usr/src/uts/common/sys/mem.h +++ b/usr/src/uts/common/sys/mem.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -55,6 +55,14 @@ typedef struct mem_vtop { pfn_t m_pfn; } mem_vtop_t; +#if defined(_SYSCALL32) +typedef struct mem_vtop32 { + uint32_t m_as; + uint32_t m_va; + uint32_t m_pfn; +} mem_vtop32_t; +#endif + /* * Private ioctls for fmd(1M). These interfaces are Sun Private. Applications * and drivers should not make use of these interfaces: they can change without diff --git a/usr/src/uts/common/sys/modctl.h b/usr/src/uts/common/sys/modctl.h index 06019d5f0f..d2f4cfd803 100644 --- a/usr/src/uts/common/sys/modctl.h +++ b/usr/src/uts/common/sys/modctl.h @@ -62,6 +62,9 @@ struct mod_ops { * The defined set of mod_ops structures for each loadable module type * Defined in modctl.c */ +#if defined(__i386) || defined(__amd64) +extern struct mod_ops mod_cpuops; +#endif extern struct mod_ops mod_cryptoops; extern struct mod_ops mod_driverops; extern struct mod_ops mod_execops; @@ -107,6 +110,17 @@ struct modlfs { struct vfsdef_v3 *fs_vfsdef; /* version may actually vary */ }; +#if defined(__i386) || defined(__amd64) +struct cmi_ops; + +/* For CPU modules */ +struct modlcpu { + struct mod_ops *cpu_modops; + char *cpu_linkinfo; + struct cmi_ops *cpu_cmiops; +}; +#endif + /* For cryptographic providers */ struct modlcrypto { struct mod_ops *crypto_modops; @@ -417,7 +431,7 @@ struct modctl_list { * are replicated in the modctl structure so that mod_containing_pc() * doesn't have to grab any locks (modctls are persistent; modules are not.) */ -struct modctl { +typedef struct modctl { struct modctl *mod_next; /* &modules based list */ struct modctl *mod_prev; int mod_id; @@ -449,7 +463,7 @@ struct modctl { int mod_gencount; /* # times loaded/unloaded */ struct modctl *mod_requisite_loading; /* mod circular dependency */ -}; +} modctl_t; /* * mod_loadflags @@ -479,7 +493,10 @@ extern int moddebug; * this is the head of a doubly linked list. Only the next and prev * pointers are used */ -extern struct modctl modules; +extern modctl_t modules; + +extern int modload_qualified(const char *, + const char *, const char *, const char *, uint_t[], int); extern void mod_setup(void); extern int modload(char *, char *); @@ -494,7 +511,7 @@ extern int mod_remove_by_name(char *); extern int mod_sysvar(const char *, const char *, u_longlong_t *); extern int mod_sysctl(int, void *); struct sysparam; -extern int mod_hold_by_modctl(struct modctl *, int); +extern int mod_hold_by_modctl(modctl_t *, int); #define MOD_WAIT_ONCE 0x01 #define MOD_WAIT_FOREVER 0x02 #define MOD_LOCK_HELD 0x04 @@ -506,13 +523,15 @@ extern void mod_release_stub(struct mod_stub_info *); extern void mod_askparams(void); extern void mod_uninstall_daemon(void); extern void modreap(void); -extern struct modctl *mod_hold_by_name(char *); -extern void mod_release_mod(struct modctl *); -extern uintptr_t modlookup(char *, char *); +extern modctl_t *mod_hold_by_id(modid_t); +extern modctl_t *mod_hold_by_name(const char *); +extern void mod_release_mod(modctl_t *); +extern uintptr_t modlookup(const char *, const char *); +extern uintptr_t modlookup_by_modctl(modctl_t *, const char *); extern char *modgetsymname(uintptr_t, unsigned long *); -extern void mod_release_requisites(struct modctl *); -extern struct modctl *mod_load_requisite(struct modctl *, char *); -extern struct modctl *mod_find_by_filename(char *, char *); +extern void mod_release_requisites(modctl_t *); +extern modctl_t *mod_load_requisite(modctl_t *, char *); +extern modctl_t *mod_find_by_filename(char *, char *); extern uintptr_t modgetsymvalue(char *, int); extern void mod_rele_dev_by_major(major_t); @@ -532,11 +551,11 @@ extern void read_class_file(void); extern void setbootpath(char *); extern void setbootfstype(char *); -extern int install_stubs_by_name(struct modctl *, char *); -extern void install_stubs(struct modctl *); -extern void uninstall_stubs(struct modctl *); -extern void reset_stubs(struct modctl *); -extern struct modctl *mod_getctl(struct modlinkage *); +extern int install_stubs_by_name(modctl_t *, char *); +extern void install_stubs(modctl_t *); +extern void uninstall_stubs(modctl_t *); +extern void reset_stubs(modctl_t *); +extern modctl_t *mod_getctl(struct modlinkage *); extern major_t mod_name_to_major(char *); extern modid_t mod_name_to_modid(char *); extern char *mod_major_to_name(major_t); @@ -550,7 +569,7 @@ extern char *mod_containing_pc(caddr_t); extern int mod_in_autounload(void); extern char *mod_modname(struct modlinkage *); -extern int dev_minorperm(dev_info_t *dip, char *name, mperm_t *rmp); +extern int dev_minorperm(dev_info_t *, char *, mperm_t *); /* * Declarations used for dynamic linking support routines. Interfaces diff --git a/usr/src/uts/common/sys/policy.h b/usr/src/uts/common/sys/policy.h index 3e1b260c1e..9653a58b0e 100644 --- a/usr/src/uts/common/sys/policy.h +++ b/usr/src/uts/common/sys/policy.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -88,6 +88,7 @@ boolean_t secpolicy_contract_event_choice(const cred_t *); int secpolicy_coreadm(const cred_t *); int secpolicy_cpc_cpu(const cred_t *); int secpolicy_dispadm(const cred_t *); +int secpolicy_error_inject(const cred_t *); int secpolicy_excl_open(const cred_t *); int secpolicy_fs_mount(cred_t *, vnode_t *, struct vfs *); int secpolicy_fs_unmount(cred_t *, struct vfs *); diff --git a/usr/src/uts/i86pc/Makefile b/usr/src/uts/i86pc/Makefile index 90cc8f9dd2..a4bafb16ff 100644 --- a/usr/src/uts/i86pc/Makefile +++ b/usr/src/uts/i86pc/Makefile @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -69,11 +69,16 @@ check := TARGET= check .PARALLEL: $(KMODS) $(CLOSED_KMODS) $(XMODS) $(CLOSED_XMODS) \ modlist modlist.intel -def all clean clobber clean.lint: genassym unix .WAIT \ +INITIAL_TARGETS = \ + genassym \ + unix \ + cpu/scripts + +def all clean clobber clean.lint: setup genassym unix .WAIT \ $(KMODS) $(CLOSED_KMODS) $(XMODS) $(CLOSED_XMODS) -install: install_platforms genassym unix .WAIT $(KMODS) $(CLOSED_KMODS) \ - $(XMODS) $(CLOSED_XMODS) +install: install_platforms setup genassym unix .WAIT \ + $(KMODS) $(CLOSED_KMODS) $(XMODS) $(CLOSED_XMODS) # list the modules under i86pc. modlist: unix $(KMODS) $(CLOSED_KMODS) $(XMODS) $(CLOSED_XMODS) @@ -91,6 +96,9 @@ modlintlib: $(KMODS) $(CLOSED_KMODS) genassym unix $(KMODS): FRC @cd $@; pwd; $(MAKE) $(NO_STATE) $(TARGET) +setup: FRC + @cd cpu/scripts; pwd; $(MAKE) setup + $(XMODS): FRC @if [ -f $@/Makefile ]; then \ cd $@; pwd; $(MAKE) $(NO_STATE) $(TARGET); \ diff --git a/usr/src/uts/i86pc/Makefile.files b/usr/src/uts/i86pc/Makefile.files index ff2999c94c..d9195b54ac 100644 --- a/usr/src/uts/i86pc/Makefile.files +++ b/usr/src/uts/i86pc/Makefile.files @@ -20,7 +20,7 @@ # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -37,6 +37,7 @@ CORE_OBJS += \ beeper.o \ biosdisk.o \ cbe.o \ + cmi.o \ confunix.o \ cpuid.o \ dis_tables.o \ @@ -127,6 +128,12 @@ AGPGART_OBJS += agpgart.o \ AGPTARGET_OBJS += agptarget.o AMD64GART_OBJS += amd64_gart.o +include $(SRC)/common/mc/mc-amd/Makefile.mcamd +MCAMD_OBJS += \ + $(MCAMD_CMN_OBJS) \ + mcamd_drv.o \ + mcamd_subr.o + # # PCI-Express driver modules # diff --git a/usr/src/uts/i86pc/Makefile.i86pc.shared b/usr/src/uts/i86pc/Makefile.i86pc.shared index c983d2a6ca..fcbd150bb8 100644 --- a/usr/src/uts/i86pc/Makefile.i86pc.shared +++ b/usr/src/uts/i86pc/Makefile.i86pc.shared @@ -21,7 +21,7 @@ # # uts/i86pc/Makefile.i86pc # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -260,16 +260,18 @@ DRV_KMODS += agptarget DRV_KMODS += amd64_gart DRV_KMODS += cpc +DRV_KMODS += mc-amd DRV_KMODS += power -$(CLOSED_BUILD)CLOSED_DRV_KMODS += ata -$(CLOSED_BUILD)CLOSED_DRV_KMODS += audiovia823x +$(CLOSED_BUILD)CLOSED_DRV_KMODS += ata +$(CLOSED_BUILD)CLOSED_DRV_KMODS += audiovia823x $(CLOSED_BUILD)CLOSED_DRV_KMODS += audioens $(CLOSED_BUILD)CLOSED_DRV_KMODS += bmc $(CLOSED_BUILD)CLOSED_DRV_KMODS_32 += bscbus $(CLOSED_BUILD)CLOSED_DRV_KMODS_32 += bscv $(CLOSED_BUILD)CLOSED_DRV_KMODS += elxl $(CLOSED_BUILD)CLOSED_DRV_KMODS += iprb +$(CLOSED_BUILD)CLOSED_DRV_KMODS += memtest $(CLOSED_BUILD)CLOSED_DRV_KMODS_32 += ncrs $(CLOSED_BUILD)CLOSED_DRV_KMODS += pcic $(CLOSED_BUILD)CLOSED_DRV_KMODS += pcn @@ -277,6 +279,12 @@ $(CLOSED_BUILD)CLOSED_DRV_KMODS += rtls $(CLOSED_BUILD)CLOSED_DRV_KMODS_32 += sbpro # +# CPU Modules +# +CPU_KMODS += amd_opteron +CPU_KMODS += generic_cpu + +# # Exec Class Modules (/kernel/exec): # EXEC_KMODS += diff --git a/usr/src/uts/i86pc/Makefile.rules b/usr/src/uts/i86pc/Makefile.rules index a272f48bf5..772db5ece7 100644 --- a/usr/src/uts/i86pc/Makefile.rules +++ b/usr/src/uts/i86pc/Makefile.rules @@ -20,7 +20,7 @@ # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #pragma ident "%Z%%M% %I% %E% SMI" @@ -45,10 +45,28 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/conf/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) +$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/cpu/amd_opteron/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + +$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/cpu/amd_opteron/%.s + $(COMPILE.s) -o $@ $< + +$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/cpu/generic_cpu/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + +$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/cpu/generic_cpu/%.s + $(COMPILE.s) -o $@ $< + $(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/io/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) +$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/io/mc/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + $(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/io/pci/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) @@ -118,6 +136,10 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/io/power/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) +$(OBJS_DIR)/%.o: $(SRC)/common/mc/mc-amd/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + $(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/io/acpica/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) @@ -179,9 +201,24 @@ $(DTRACESTUBS): $(DTRACESTUBS_O) $(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/conf/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) +$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/cpu/amd_opteron/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + +$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/cpu/amd_opteron/%.s + @($(LHEAD) $(LINT.s) $< $(LTAIL)) + +$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/cpu/generic_cpu/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + +$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/cpu/generic_cpu/%.s + @($(LHEAD) $(LINT.s) $< $(LTAIL)) + $(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) +$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/mc/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + $(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/pci/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) @@ -227,6 +264,9 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/agpgart/%.c $(LINTS_DIR)/%.ln: $(SRC)/common/atomic/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) +$(LINTS_DIR)/%.ln: $(SRC)/common/mc/mc-amd/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + $(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/acpica/%.s @($(LHEAD) $(LINT.s) $< $(LTAIL)) diff --git a/usr/src/uts/i86pc/Makefile.workarounds b/usr/src/uts/i86pc/Makefile.workarounds index f6f79bde49..ffd5a20e69 100644 --- a/usr/src/uts/i86pc/Makefile.workarounds +++ b/usr/src/uts/i86pc/Makefile.workarounds @@ -19,10 +19,7 @@ # # CDDL HEADER END # -# -# uts/i86pc/Makefile.workarounds -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -57,6 +54,11 @@ WORKAROUND_DEFS += -DOPTERON_ERRATUM_95 WORKAROUND_DEFS += -DOPTERON_ERRATUM_100 # +# DRAM Scrubber May Cause Data Corruption When Using Node-Interleaved Memory +# +WORKAROUND_DEFS += -DOPTERON_ERRATUM_101 + +# # CPUID Instruction May Return Incorrect Model Number in Some Processors # WORKAROUND_DEFS += -DOPTERON_ERRATUM_108 diff --git a/usr/src/uts/i86pc/amd_opteron/Makefile b/usr/src/uts/i86pc/amd_opteron/Makefile new file mode 100644 index 0000000000..50db5b7db0 --- /dev/null +++ b/usr/src/uts/i86pc/amd_opteron/Makefile @@ -0,0 +1,105 @@ +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = cpu.AuthenticAMD.15 +# +OBJECTS = $(CPU_AO_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(CPU_AO_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_PSM_CPU_DIR)/$(MODULE) + +SRCDIR = ../cpu/amd_opteron + +AO_MCA_DISP_C = $(OBJS_DIR)/ao_mca_disp.c +AO_MCA_DISP_SRC = $(SRCDIR)/ao_mca_disp.in +AO_GENDISP = ../cpu/scripts/ao_gendisp + +# +# Include common rules. +# +include ../cpu/Makefile.cpu + +# +# Our lint library has a different name from that of the module we build. +# +LINT_MODULE = amd_opteron + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(LINT_MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +# +# Overrides and additions +# +CLEANFILES += $(AO_MCA_DISP_C) +CPPFLAGS += -I$(SRCDIR) -I$(OBJS_DIR) +ASFLAGS += -I$(SRCDIR) -I$(OBJS_DIR) + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +# +# Create ao_mca_disp.c +# +$(AO_MCA_DISP_C): $(AO_MCA_DISP_SRC) $(AO_GENDISP) + $(AO_GENDISP) $(AO_MCA_DISP_SRC) >$@ + +$(OBJS_DIR)/%.o: $(OBJS_DIR)/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + +# +# Include common targets. +# +include ../Makefile.targ diff --git a/usr/src/uts/i86pc/cpu/Makefile.cpu b/usr/src/uts/i86pc/cpu/Makefile.cpu new file mode 100644 index 0000000000..c73344de87 --- /dev/null +++ b/usr/src/uts/i86pc/cpu/Makefile.cpu @@ -0,0 +1,28 @@ +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include $(UTSBASE)/i86pc/Makefile.i86pc +include $(UTSBASE)/i86pc/cpu/Makefile.files diff --git a/usr/src/uts/i86pc/cpu/Makefile.files b/usr/src/uts/i86pc/cpu/Makefile.files new file mode 100644 index 0000000000..3252058682 --- /dev/null +++ b/usr/src/uts/i86pc/cpu/Makefile.files @@ -0,0 +1,37 @@ +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +CPU_AO_OBJS = \ + ao_cpu.o \ + ao_main.o \ + ao_mc.o \ + ao_mca.o \ + ao_mca_disp.o \ + ao_poll.o + +CPU_GCPU_OBJS = \ + gcpu_main.o \ + gcpu_mca.o diff --git a/usr/src/uts/i86pc/cpu/amd_opteron/ao.h b/usr/src/uts/i86pc/cpu/amd_opteron/ao.h new file mode 100644 index 0000000000..e5f6c518a8 --- /dev/null +++ b/usr/src/uts/i86pc/cpu/amd_opteron/ao.h @@ -0,0 +1,235 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _AO_H +#define _AO_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/mc.h> +#include <sys/mca_amd.h> +#include <sys/cpu_module_impl.h> +#include <sys/nvpair.h> +#include <sys/cyclic.h> +#include <sys/errorq.h> +#include <sys/kobj.h> +#include <sys/fm/util.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define AO_MCA_MAX_ERRORS 10 + +typedef struct ao_data ao_data_t; + +typedef struct ao_bank_regs { + uint32_t abr_status; + uint32_t abr_addr; +} ao_bank_regs_t; + +extern ao_bank_regs_t ao_bank_regs[AMD_MCA_BANK_COUNT]; + +/* + * Rather than using torturous conditionals, we match errors using a table of + * ao_error_disp_t's. The members in the ao_error_disp_t are matched against + * the value of MCi_STATUS, with a successful match indicating that the given + * error occurred. + * + * While aed_stat_code will match most of the status code bits, a few of the + * status code fields are either/or, and are treated separately so as to + * minimize the number of ao_error_disp_t structures that must be created. + * For example, the dc.tag_par error can have r4 values drd or dwr. Rather + * than creating two ao_error_disp_t's, we use the separate aed_stat_r4_bits + * field to indicate both AO_MCA_R4_BIT_DRD and AO_MCA_R4_BIT_DWD. As the + * matching r4 values are drawn from aed_stat_r4_bits, we don't use the r4 + * bits in aed_stat_code for matching. Similar reasoning lies behind the + * creation of the pp and ii fields. + */ +#define AO_AED_PANIC_NEVER 0x00000000 +#define AO_AED_PANIC_PRIV 0x00000001 +#define AO_AED_PANIC_USER 0x00000002 +#define AO_AED_PANIC_ALWAYS 0x00000003 + +#define AO_AED_F_CORRECTABLE 0x00000001 +#define AO_AED_F_LOFAULT_OK 0x00000002 + +typedef struct ao_error_disp { + const char *aed_class; /* ereport class for use if match */ + uint64_t aed_ereport_members; /* ereport contents flags if match */ + uint64_t aed_stat_mask; /* status msr bits for match */ + uint64_t aed_stat_mask_res; /* status mask result for match */ + uint16_t aed_stat_code; /* status code for match */ + uint8_t aed_stat_extcode; /* extended status code for match */ + uint8_t aed_stat_pp_bits:4; /* AO_MCA_PP_BIT_* for pp matching */ + uint8_t aed_stat_ii_bits:4; /* AO_MCA_II_BIT_* for ii matching */ + uint16_t aed_stat_r4_bits; /* AO_MCA_R4_BIT_* for r4 matching */ + uint8_t aed_panic_when; /* extra conditions for panic */ + uint8_t aed_flags; /* AO_AED_F_* */ +} ao_error_disp_t; + +/* + * The poller has two parts. First is the omni cyclic, which runs on all + * CPUs, and which polls the error MSRs at some fixed (long) interval. This + * cyclic will run on all machines, all the time, and thus must have minimal + * runtime impact. The second portion of the poller is manually-initiated, and + * is used by the error injector/synthesizer to request an immediate poll of the + * error state registers. + * + * With this number of moving parts, it is essential that we have some sort of + * audit log for post-mortem analysis. A circular array of trace buffers + * (ao_mca_poll_trace_t structures) is kept to record this activity. Whenever + * an event occurs that is of interest to the poller, an entry is made in + * the trace array describing that event. + */ +#define AO_MPT_WHAT_CYC_ERR 0 /* cyclic-induced poll */ +#define AO_MPT_WHAT_POKE_ERR 1 /* manually-induced poll */ +#define AO_MPT_WHAT_UNFAULTING 2 /* discarded error state */ + +typedef struct ao_mca_poll_trace { + hrtime_t mpt_when; /* timestamp of event */ + uint8_t mpt_what; /* AO_MPT_WHAT_* (which event?) */ + uint8_t mpt_nerr; /* number of errors discovered */ + uint16_t mpt_pad1; + uint32_t mpt_pad2; +} ao_mca_poll_trace_t; + +/* + * Processor error state is saved in logout areas. There are three separate + * logout areas, each used for a different purpose. The logout areas are stored + * in an array (ao_mca_logout), indexed by the AO_MCA_LOGOUT_* macros. + * + * The save areas are: + * + * 1. Exception handler MSR save - Written to by the initial portion of the #mc + * handler. Read from by the main body of the exception handler. + * + * 3. Poller MSR save - Used by the poller to store error state MSR values. + * While this logout area doesn't necessarily have to live in the ao_mca_t, + * it does so to enhance observability. + * + * The logout areas contain both global error state (acl_ip, acl_timestamp, + * etc.), as well as a bank array. The bank array contains one ao_bank_logout_t + * per error reporting bank. + */ + +typedef struct ao_bank_logout { + uint64_t abl_status; /* Saved MCi_STATUS register */ + uint64_t abl_addr; /* Saved MCi_ADDR register */ +} ao_bank_logout_t; + +#define AO_ACL_F_PRIV 0x1 /* #mc in kernel mode (else user) */ +#define AO_ACL_F_FATAL 0x2 /* logout detected fatal error(s) */ + +typedef struct ao_cpu_logout { + ao_data_t *acl_ao; /* pointer to per-cpu ao_data_t */ + uintptr_t acl_ip; /* instruction pointer if #mc trap */ + uint64_t acl_timestamp; /* gethrtime() at time of logout */ + uint64_t acl_mcg_status; /* MCG_STATUS register value */ + ao_bank_logout_t acl_banks[AMD_MCA_BANK_COUNT]; /* bank state saves */ + pc_t acl_stack[FM_STK_DEPTH]; /* saved stack trace (if any) */ + int acl_stackdepth; /* saved stack trace depth */ + uint_t acl_flags; /* flags (see AO_ACL_F_* above) */ +} ao_cpu_logout_t; + +/* Index for ao_mca_logout, below */ +#define AO_MCA_LOGOUT_EXCEPTION 0 +#define AO_MCA_LOGOUT_POLLER 1 +#define AO_MCA_LOGOUT_NUM 2 + +#define AO_MCA_F_UNFAULTING 0x1 /* CPU exiting faulted state */ + +/* + * We store config as inherited from the BIOS to assist in troubleshooting. + */ +typedef struct ao_bios_cfg { + uint64_t bcfg_bank_ctl[AMD_MCA_BANK_COUNT]; + uint64_t bcfg_bank_mask[AMD_MCA_BANK_COUNT]; + uint32_t bcfg_nb_cfg; +} ao_bios_cfg_t; + +/* + * The master data structure used to hold MCA-related state. + */ +typedef struct ao_mca { + ao_bios_cfg_t ao_mca_bios_cfg; /* Bank and NB config before our init */ + ao_cpu_logout_t ao_mca_logout[AO_MCA_LOGOUT_NUM]; /* save areas */ + kmutex_t ao_mca_poll_lock; /* keep pollers from colliding */ + ao_mca_poll_trace_t *ao_mca_poll_trace; /* trace buffers for this cpu */ + uint_t ao_mca_poll_curtrace; /* most recently-filled trace buffer */ + uint_t ao_mca_flags; /* AO_MCA_F_* */ +} ao_mca_t; + +/* + * Per-CPU state + */ +struct ao_data { + ao_mca_t ao_mca; /* MCA state for this CPU */ + cpu_t *ao_cpu; /* link to CPU's cpu_t */ + const cmi_mc_ops_t *ao_mc_ops; /* memory controller ops */ + void *ao_mc_data; /* argument for memory controller ops */ +}; + +#ifdef _KERNEL + +struct regs; + +extern errorq_t *ao_mca_queue; +extern const cmi_ops_t _cmi_ops; + +extern void ao_faulted_enter(void *); +extern void ao_faulted_exit(void *); +extern int ao_scrubber_enable(void *, uint64_t, uint64_t); + +extern void ao_mca_post_init(void *); +extern void ao_mca_init(void *); +extern int ao_mca_trap(void *, struct regs *); +extern int ao_mca_inject(void *, cmi_mca_regs_t *, uint_t); +extern void ao_mca_poke(void *); +extern void ao_mca_poll_init(ao_mca_t *); +extern void ao_mca_poll_start(void); + +extern int ao_mca_logout(ao_cpu_logout_t *, struct regs *, int *); +extern void ao_mca_drain(void *, const void *, const errorq_elem_t *); +extern nvlist_t *ao_fmri_create(ao_data_t *, nv_alloc_t *); + +extern void ao_mc_register(void *, const cmi_mc_ops_t *, void *); +extern const struct cmi_mc_ops *ao_mc_getops(void *); +extern int ao_mc_patounum(ao_data_t *, uint64_t, uint32_t, int, mc_unum_t *); +extern int ao_mc_unumtopa(ao_data_t *, mc_unum_t *, nvlist_t *, uint64_t *); + +extern void ao_pcicfg_write(uint_t, uint_t, uint_t, uint32_t); +extern uint32_t ao_pcicfg_read(uint_t, uint_t, uint_t); + +#endif /* _KERNEL */ + +#ifdef __cplusplus +} +#endif + +#endif /* _AO_H */ diff --git a/usr/src/uts/i86pc/cpu/amd_opteron/ao_cpu.c b/usr/src/uts/i86pc/cpu/amd_opteron/ao_cpu.c new file mode 100644 index 0000000000..e13c672fac --- /dev/null +++ b/usr/src/uts/i86pc/cpu/amd_opteron/ao_cpu.c @@ -0,0 +1,203 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/chip.h> +#include <sys/cmn_err.h> +#include <sys/sysmacros.h> +#include <sys/fm/protocol.h> + +#include "ao.h" + +/* + * AMD Opteron CPU Subroutines + * + * The following three tunables are used to determine the scrubbing rates for + * the D$, L2$, and DRAM hardware scrubbers. The values range from 0x00-0x16 + * as described in BKDG 3.6.6 Scrub Control Register. A value of zero disables + * the scrubber. Values above zero indicate rates in descending order. + * + * The current default values are used on several Sun systems. In the future + * this code should assign values dynamically based on memory sizing. If you + * tune these values manually be aware of the following architectural issue: + * At present, Opteron can only survive certain kinds of multi-bit errors if + * they are detected by the scrubbers. Therefore in general we want these + * values tuned as high as possible without impacting workload performance. + */ +uint32_t ao_scrub_rate_dcache = 8; /* 64B every 5.12 us */ +uint32_t ao_scrub_rate_l2cache = 9; /* 64B every 10.2 us */ +uint32_t ao_scrub_rate_dram = 0xd; /* 64B every 163.8 us */ + +uint32_t ao_scrub_system; /* debug stash for system's value */ +uint32_t ao_scrub_bios; /* debug stash for bios's value */ +uint32_t ao_scrub_lo; /* debug stash for system low addr */ +uint32_t ao_scrub_hi; /* debug stash for system high addr */ + +enum { + AO_SCRUB_DEFAULT, /* retain system default values */ + AO_SCRUB_FIXED, /* assign ao_scrub_rate_* values */ + AO_SCRUB_MAX /* assign max of system and tunables */ +} ao_scrub_policy = AO_SCRUB_MAX; + +nvlist_t * +ao_fmri_create(ao_data_t *ao, nv_alloc_t *nva) +{ + nvlist_t *nvl = fm_nvlist_create(nva); + + fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, NULL, 3, + "motherboard", 0, + "chip", ao->ao_cpu->cpu_chip->chip_id, + "cpu", chip_plat_get_clogid(ao->ao_cpu)); + + return (nvl); +} + +/* + * Return the maximum scrubbing rate between r1 and r2, where r2 is extracted + * from the specified 'cfg' register value using 'mask' and 'shift'. If a + * value is zero, scrubbing is off so return the opposite value. Otherwise + * the maximum rate is the smallest non-zero value of the two values. + */ +static uint32_t +ao_scrubber_max(uint32_t r1, uint32_t cfg, uint32_t mask, uint32_t shift) +{ + uint32_t r2 = (cfg & mask) >> shift; + + if (r1 != 0 && r2 != 0) + return (MIN(r1, r2)); + + return (r1 ? r1 : r2); +} + +/* + * Enable the chip-specific hardware scrubbers for the D$, L2$, and DRAM, and + * return a boolean value indicating if we enabled the DRAM scrubber. We set + * the scrubber rate based on a set of tunables defined at the top of the file. + * The 'base' parameter is the DRAM Base Address for this chip and is used to + * determine where the scrubber starts. The 'ilen' value is the IntvlEn field + * from the DRAM configuration indicating the node-interleaving configuration. + */ +int +ao_scrubber_enable(void *data, uint64_t base, uint64_t ilen) +{ + ao_data_t *ao = data; + chipid_t chipid = chip_plat_get_chipid(ao->ao_cpu); + uint32_t scrubctl, lo, hi; + int rv = 1; + + /* + * Read the initial scrubber configuration and save it for debugging. + * If ao_scrub_policy is DEFAULT, return immediately. Otherwise we + * disable scrubbing activity while we fiddle with the configuration. + */ + scrubctl = ao_pcicfg_read(chipid, AMD_NB_FUNC, AMD_NB_REG_SCRUBCTL); + cas32(&ao_scrub_bios, 0, scrubctl); + + if (ao_scrub_policy == AO_SCRUB_DEFAULT) + return ((scrubctl & AMD_NB_SCRUBCTL_DRAM_MASK) != 0); + + scrubctl &= ~AMD_NB_SCRUBCTL_DRAM_MASK; + scrubctl &= ~AMD_NB_SCRUBCTL_L2_MASK; + scrubctl &= ~AMD_NB_SCRUBCTL_DC_MASK; + + ao_pcicfg_write(chipid, AMD_NB_FUNC, AMD_NB_REG_SCRUBCTL, scrubctl); + + /* + * Read the DRAM Scrub Address Low and High registers, clear their + * address fields, enable sequential-redirect mode, and update the + * address fields using the specified DRAM Base Address. + */ + lo = ao_pcicfg_read(chipid, AMD_NB_FUNC, AMD_NB_REG_SCRUBADDR_LO); + hi = ao_pcicfg_read(chipid, AMD_NB_FUNC, AMD_NB_REG_SCRUBADDR_HI); + + lo &= ~AMD_NB_SCRUBADDR_LO_MASK; + hi &= ~AMD_NB_SCRUBADDR_HI_MASK; + + lo |= AMD_NB_SCRUBADDR_MKLO(base) | AMD_NB_SCRUBADDR_LO_SCRUBREDIREN; + hi |= AMD_NB_SCRUBADDR_MKHI(base); + + ao_scrub_lo = lo; + ao_scrub_hi = hi; + + ao_pcicfg_write(chipid, AMD_NB_FUNC, AMD_NB_REG_SCRUBADDR_LO, lo); + ao_pcicfg_write(chipid, AMD_NB_FUNC, AMD_NB_REG_SCRUBADDR_HI, hi); + + if (ao_scrub_rate_dcache > AMD_NB_SCRUBCTL_RATE_MAX) { + cmn_err(CE_WARN, "ao_scrub_rate_dcache is too large; " + "resetting to 0x%x\n", AMD_NB_SCRUBCTL_RATE_MAX); + ao_scrub_rate_dcache = AMD_NB_SCRUBCTL_RATE_MAX; + } + + if (ao_scrub_rate_l2cache > AMD_NB_SCRUBCTL_RATE_MAX) { + cmn_err(CE_WARN, "ao_scrub_rate_l2cache is too large; " + "resetting to 0x%x\n", AMD_NB_SCRUBCTL_RATE_MAX); + ao_scrub_rate_l2cache = AMD_NB_SCRUBCTL_RATE_MAX; + } + + if (ao_scrub_rate_dram > AMD_NB_SCRUBCTL_RATE_MAX) { + cmn_err(CE_WARN, "ao_scrub_rate_dram is too large; " + "resetting to 0x%x\n", AMD_NB_SCRUBCTL_RATE_MAX); + ao_scrub_rate_dram = AMD_NB_SCRUBCTL_RATE_MAX; + } + + if (ao_scrub_policy == AO_SCRUB_MAX) { + ao_scrub_rate_dcache = + ao_scrubber_max(ao_scrub_rate_dcache, ao_scrub_bios, + AMD_NB_SCRUBCTL_DC_MASK, AMD_NB_SCRUBCTL_DC_SHIFT); + + ao_scrub_rate_l2cache = + ao_scrubber_max(ao_scrub_rate_l2cache, ao_scrub_bios, + AMD_NB_SCRUBCTL_L2_MASK, AMD_NB_SCRUBCTL_L2_SHIFT); + + ao_scrub_rate_dram = + ao_scrubber_max(ao_scrub_rate_dram, ao_scrub_bios, + AMD_NB_SCRUBCTL_DRAM_MASK, AMD_NB_SCRUBCTL_DRAM_SHIFT); + } + +#ifdef OPTERON_ERRATUM_101 + /* + * If the DRAM Base Address register's IntlvEn field indicates that + * node interleaving is enabled, we must disable the DRAM scrubber + * and return zero to indicate that Solaris should use s/w instead. + */ + if (ilen != 0) { + cmn_err(CE_CONT, "?Opteron DRAM scrubber disabled because " + "DRAM memory is node-interleaved"); + ao_scrub_rate_dram = 0; + rv = 0; + } +#endif + scrubctl |= AMD_NB_MKSCRUBCTL(ao_scrub_rate_dcache, + ao_scrub_rate_l2cache, ao_scrub_rate_dram); + + ao_scrub_system = scrubctl; + ao_pcicfg_write(chipid, AMD_NB_FUNC, AMD_NB_REG_SCRUBCTL, scrubctl); + + return (rv); +} diff --git a/usr/src/uts/i86pc/cpu/amd_opteron/ao_main.c b/usr/src/uts/i86pc/cpu/amd_opteron/ao_main.c new file mode 100644 index 0000000000..777538adf0 --- /dev/null +++ b/usr/src/uts/i86pc/cpu/amd_opteron/ao_main.c @@ -0,0 +1,135 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * The CPU module for the AMD Athlon64 and Opteron processors + */ + +#include <sys/types.h> +#include <sys/cmn_err.h> +#include <sys/sunddi.h> +#include <sys/cpu_module_impl.h> +#include <sys/cpuvar.h> +#include <sys/x86_archext.h> +#include <sys/kmem.h> +#include <sys/modctl.h> +#include <sys/mc.h> + +#include "ao.h" + +/* + * At present this CPU module only supports the features for Athlon64 and + * Opteron up to and including the Rev E processor. If we detect Rev F or + * later, return ENOTSUP and let the generic x86 CPU module load instead. + * Opteron Rev F is currently defined as Family 0xF Model [0x40 .. 0x5F]. + */ +static uint_t ao_model_limit = 0x40; + +static int +ao_init(cpu_t *cp, void **datap) +{ + ao_data_t *ao; + + if (cpuid_getmodel(cp) >= ao_model_limit) + return (ENOTSUP); + + ao = *datap = kmem_zalloc(sizeof (ao_data_t), KM_SLEEP); + ao->ao_cpu = cp; + + return (0); +} + +static void +ao_fini(void *data) +{ + kmem_free(data, sizeof (ao_data_t)); +} + +const cmi_ops_t _cmi_ops = { + ao_init, + ao_mca_post_init, + ao_fini, + ao_faulted_enter, + ao_faulted_exit, + ao_scrubber_enable, + ao_mca_init, + ao_mca_trap, + ao_mca_inject, + ao_mca_poke, + ao_mc_register, + ao_mc_getops +}; + +static struct modlcpu modlcpu = { + &mod_cpuops, + "AMD Athlon64/Opteron CPU Module" +}; + +static struct modlinkage modlinkage = { + MODREV_1, + (void *)&modlcpu, + NULL +}; + +int +_init(void) +{ + int err; + + ao_mca_queue = errorq_create("ao_mca_queue", + ao_mca_drain, NULL, AO_MCA_MAX_ERRORS * (max_ncpus + 1), + sizeof (ao_cpu_logout_t), 1, ERRORQ_VITAL); + + if (ao_mca_queue == NULL) + return (EAGAIN); /* errorq_create() logs a message for us */ + + if ((err = mod_install(&modlinkage)) != 0) { + errorq_destroy(ao_mca_queue); + ao_mca_queue = NULL; + } + + return (err); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + +int +_fini(void) +{ + int err; + + if ((err = mod_remove(&modlinkage)) == 0) + errorq_destroy(ao_mca_queue); + + return (err); +} diff --git a/usr/src/uts/i86pc/cpu/amd_opteron/ao_mc.c b/usr/src/uts/i86pc/cpu/amd_opteron/ao_mc.c new file mode 100644 index 0000000000..b2fd0ca82f --- /dev/null +++ b/usr/src/uts/i86pc/cpu/amd_opteron/ao_mc.c @@ -0,0 +1,72 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/cmn_err.h> +#include <sys/cpu_module_impl.h> + +#include "ao.h" + +void +ao_mc_register(void *data, const cmi_mc_ops_t *mcops, void *mcdata) +{ + ao_data_t *ao = data; + + ASSERT(ao->ao_mc_ops == NULL); + + ao->ao_mc_ops = mcops; + ao->ao_mc_data = mcdata; +} + +const struct cmi_mc_ops * +ao_mc_getops(void *data) +{ + ao_data_t *ao = data; + + return (ao->ao_mc_ops); +} + +int +ao_mc_patounum(ao_data_t *ao, uint64_t pa, uint32_t synd, int syndtype, + mc_unum_t *unump) +{ + if (ao->ao_mc_ops == NULL) + return (0); /* mc not registered, or failed to load */ + + return (ao->ao_mc_ops->cmi_mc_patounum(ao->ao_mc_data, pa, synd, + syndtype, unump)); +} + +int +ao_mc_unumtopa(ao_data_t *ao, mc_unum_t *unump, nvlist_t *nvl, uint64_t *pap) +{ + if (ao->ao_mc_ops == NULL) + return (0); /* mc not registered, or failed to load */ + + return (ao->ao_mc_ops->cmi_mc_unumtopa(ao->ao_mc_data, unump, nvl, + pap)); +} diff --git a/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca.c b/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca.c new file mode 100644 index 0000000000..e8884f212d --- /dev/null +++ b/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca.c @@ -0,0 +1,811 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/regset.h> +#include <sys/privregs.h> +#include <sys/pci_impl.h> +#include <sys/cpuvar.h> +#include <sys/x86_archext.h> +#include <sys/cmn_err.h> +#include <sys/systm.h> +#include <sys/sysmacros.h> +#include <sys/chip.h> +#include <sys/cyclic.h> +#include <sys/cpu_module_impl.h> +#include <sys/pci_cfgspace_impl.h> +#include <sys/sysevent.h> +#include <sys/smbios.h> +#include <sys/mca_x86.h> +#include <sys/mca_amd.h> +#include <sys/mc.h> +#include <sys/psw.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/sdt.h> +#include <sys/fm/util.h> +#include <sys/fm/protocol.h> +#include <sys/fm/cpu/AMD.h> + +#include "ao.h" +#include "ao_mca_disp.h" + +errorq_t *ao_mca_queue; /* machine-check ereport queue */ +int ao_mca_stack_flag = 1; /* record stack trace in ereports */ +int ao_mca_smi_disable = 1; /* attempt to disable SMI polling */ + +ao_bank_regs_t ao_bank_regs[AMD_MCA_BANK_COUNT] = { + { AMD_MSR_DC_STATUS, AMD_MSR_DC_ADDR }, + { AMD_MSR_IC_STATUS, AMD_MSR_IC_ADDR }, + { AMD_MSR_BU_STATUS, AMD_MSR_BU_ADDR }, + { AMD_MSR_LS_STATUS, AMD_MSR_LS_ADDR }, + { AMD_MSR_NB_STATUS, AMD_MSR_NB_ADDR } +}; + +typedef struct ao_bank_cfg { + uint_t bank_ctl; + uint_t bank_ctl_mask; + uint64_t bank_ctl_init; + uint_t bank_status; + uint_t bank_addr; +} ao_bank_cfg_t; + +static const ao_bank_cfg_t ao_bank_cfgs[] = { + { AMD_MSR_DC_CTL, AMD_MSR_DC_MASK, AMD_DC_CTL_INIT, AMD_MSR_DC_STATUS, + AMD_MSR_DC_ADDR }, + { AMD_MSR_IC_CTL, AMD_MSR_IC_MASK, AMD_IC_CTL_INIT, AMD_MSR_IC_STATUS, + AMD_MSR_IC_ADDR }, + { AMD_MSR_BU_CTL, AMD_MSR_BU_MASK, AMD_BU_CTL_INIT, AMD_MSR_BU_STATUS, + AMD_MSR_BU_ADDR }, + { AMD_MSR_LS_CTL, AMD_MSR_LS_MASK, AMD_LS_CTL_INIT, AMD_MSR_LS_STATUS, + AMD_MSR_LS_ADDR }, + { AMD_MSR_NB_CTL, AMD_MSR_NB_MASK, AMD_NB_CTL_INIT, AMD_MSR_NB_STATUS, + AMD_MSR_NB_ADDR } +}; + +static const ao_error_disp_t ao_disp_unknown = { + FM_EREPORT_CPU_AMD_UNKNOWN, + FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_UNKNOWN +}; + +/* + * This is quite awful but necessary to work around x86 system vendor's view of + * the world. Other operating systems (you know who you are) don't understand + * Opteron-specific error handling, so BIOS and system vendors often hide these + * conditions from them by using SMI polling to copy out any errors from the + * machine-check registers. When Solaris runs on a system with this feature, + * we want to disable the SMI polling so we can use FMA instead. Sadly, there + * isn't even a standard self-describing way to express the whole situation, + * so we have to resort to hard-coded values. This should all be changed to + * be a self-describing vendor-specific SMBIOS structure in the future. + */ +static const struct ao_smi_disable { + const char *asd_sys_vendor; /* SMB_TYPE_SYSTEM vendor prefix */ + const char *asd_bios_vendor; /* SMB_TYPE_BIOS vendor prefix */ + uint32_t asd_port; /* output port for SMI disable */ + uint32_t asd_code; /* output code for SMI disable */ +} ao_smi_disable[] = { + { "Sun Microsystems", "American Megatrends", 0x502F, 0x59 }, + { NULL, NULL, 0, 0 } +}; + +static int +ao_disp_match_r4(uint16_t ref, uint8_t r4) +{ + static const uint16_t ao_r4_map[] = { + AO_MCA_R4_BIT_GEN, /* AMD_ERRCODE_R4_GEN */ + AO_MCA_R4_BIT_RD, /* AMD_ERRCODE_R4_RD */ + AO_MCA_R4_BIT_WR, /* AMD_ERRCODE_R4_WR */ + AO_MCA_R4_BIT_DRD, /* AMD_ERRCODE_R4_DRD */ + AO_MCA_R4_BIT_DWR, /* AMD_ERRCODE_R4_DWR */ + AO_MCA_R4_BIT_IRD, /* AMD_ERRCODE_R4_IRD */ + AO_MCA_R4_BIT_PREFETCH, /* AMD_ERRCODE_R4_PREFETCH */ + AO_MCA_R4_BIT_EVICT, /* AMD_ERRCODE_R4_EVICT */ + AO_MCA_R4_BIT_SNOOP /* AMD_ERRCODE_R4_SNOOP */ + }; + + ASSERT(r4 < sizeof (ao_r4_map) / sizeof (uint16_t)); + + return ((ref & ao_r4_map[r4]) != 0); +} + +static int +ao_disp_match_pp(uint8_t ref, uint8_t pp) +{ + static const uint8_t ao_pp_map[] = { + AO_MCA_PP_BIT_SRC, /* AMD_ERRCODE_PP_SRC */ + AO_MCA_PP_BIT_RSP, /* AMD_ERRCODE_PP_RSP */ + AO_MCA_PP_BIT_OBS, /* AMD_ERRCODE_PP_OBS */ + AO_MCA_PP_BIT_GEN /* AMD_ERRCODE_PP_GEN */ + }; + + ASSERT(pp < sizeof (ao_pp_map) / sizeof (uint8_t)); + + return ((ref & ao_pp_map[pp]) != 0); +} + +static int +ao_disp_match_ii(uint8_t ref, uint8_t ii) +{ + static const uint8_t ao_ii_map[] = { + AO_MCA_II_BIT_MEM, /* AMD_ERRCODE_II_MEM */ + 0, + AO_MCA_II_BIT_IO, /* AMD_ERRCODE_II_IO */ + AO_MCA_II_BIT_GEN /* AMD_ERRCODE_II_GEN */ + }; + + ASSERT(ii < sizeof (ao_ii_map) / sizeof (uint8_t)); + + return ((ref & ao_ii_map[ii]) != 0); +} + +static uint8_t +bit_strip(uint16_t *codep, uint16_t mask, uint16_t shift) +{ + uint8_t val = (*codep & mask) >> shift; + *codep &= ~mask; + return (val); +} + +#define BIT_STRIP(codep, name) \ + bit_strip(codep, AMD_ERRCODE_##name##_MASK, AMD_ERRCODE_##name##_SHIFT) + +static int +ao_disp_match_one(const ao_error_disp_t *aed, uint64_t status) +{ + uint16_t code = status & AMD_ERRCODE_MASK; + uint8_t extcode = (status & AMD_ERREXT_MASK) >> AMD_ERREXT_SHIFT; + uint64_t stat_mask = aed->aed_stat_mask; + uint64_t stat_mask_res = aed->aed_stat_mask_res; + + /* + * If the bank's status register indicates overflow, then we can no + * longer rely on the value of CECC: our experience with actual fault + * injection has shown that multiple CE's overwriting each other shows + * AMD_BANK_STAT_CECC and AMD_BANK_STAT_UECC both set to zero. This + * should be clarified in a future BKDG or by the Revision Guide. + */ + if (status & AMD_BANK_STAT_OVER) { + stat_mask &= ~AMD_BANK_STAT_CECC; + stat_mask_res &= ~AMD_BANK_STAT_CECC; + } + + if ((status & stat_mask) != stat_mask_res) + return (0); + + /* + * r4 and pp bits are stored separately, so we mask off and compare them + * for the code types that use them. Once we've taken the r4 and pp + * bits out of the equation, we can directly compare the resulting code + * with the one stored in the ao_error_disp_t. + */ + if (AMD_ERRCODE_ISMEM(code)) { + uint8_t r4 = BIT_STRIP(&code, R4); + + if (!ao_disp_match_r4(aed->aed_stat_r4_bits, r4)) + return (0); + + } else if (AMD_ERRCODE_ISBUS(code)) { + uint8_t r4 = BIT_STRIP(&code, R4); + uint8_t pp = BIT_STRIP(&code, PP); + uint8_t ii = BIT_STRIP(&code, II); + + if (!ao_disp_match_r4(aed->aed_stat_r4_bits, r4) || + !ao_disp_match_pp(aed->aed_stat_pp_bits, pp) || + !ao_disp_match_ii(aed->aed_stat_ii_bits, ii)) + return (0); + } + + return (code == aed->aed_stat_code && extcode == aed->aed_stat_extcode); +} + +static const ao_error_disp_t * +ao_disp_match(uint_t bankno, uint64_t status) +{ + const ao_error_disp_t *aed; + + for (aed = ao_error_disp[bankno]; aed->aed_stat_mask != 0; aed++) { + if (ao_disp_match_one(aed, status)) + return (aed); + } + + return (&ao_disp_unknown); +} + +void +ao_pcicfg_write(uint_t chipid, uint_t func, uint_t reg, uint32_t val) +{ + ASSERT(chipid + 24 <= 31); + ASSERT((func & 7) == func); + ASSERT((reg & 3) == 0 && reg < 256); + + pci_mech1_putl(0, chipid + 24, func, reg, val); +} + +uint32_t +ao_pcicfg_read(uint_t chipid, uint_t func, uint_t reg) +{ + ASSERT(chipid + 24 <= 31); + ASSERT((func & 7) == func); + ASSERT((reg & 3) == 0 && reg < 256); + + return (pci_mech1_getl(0, chipid + 24, func, reg)); +} + +/* + * Setup individual bank detectors after stashing their bios settings. + */ +static void +ao_bank_cfg(ao_mca_t *mca) +{ + ao_bios_cfg_t *bioscfg = &mca->ao_mca_bios_cfg; + const ao_bank_cfg_t *bankcfg = ao_bank_cfgs; + int i; + + for (i = 0; i < AMD_MCA_BANK_COUNT; i++, bankcfg++) { + bioscfg->bcfg_bank_ctl[i] = rdmsr(bankcfg->bank_ctl); + bioscfg->bcfg_bank_mask[i] = rdmsr(bankcfg->bank_ctl_mask); + wrmsr(bankcfg->bank_ctl, bankcfg->bank_ctl_init); + } +} + +/* + * Bits to be added to the NorthBridge (NB) configuration register. + * See BKDG 3.29 Section 3.6.4.2 for more information. + */ +uint32_t ao_nb_cfg_add = + AMD_NB_CFG_NBMCATOMSTCPUEN | + AMD_NB_CFG_DISPCICFGCPUERRRSP | + AMD_NB_CFG_SYNCONUCECCEN | + AMD_NB_CFG_CPUECCERREN; + +/* + * Bits to be cleared from the NorthBridge (NB) configuration register. + * See BKDG 3.29 Section 3.6.4.2 for more information. + */ +uint32_t ao_nb_cfg_remove = + AMD_NB_CFG_IORDDATERREN | + AMD_NB_CFG_SYNCONANYERREN | + AMD_NB_CFG_SYNCONWDOGEN | + AMD_NB_CFG_IOERRDIS | + AMD_NB_CFG_IOMSTABORTDIS | + AMD_NB_CFG_SYNCPKTPROPDIS | + AMD_NB_CFG_SYNCPKTGENDIS; + +/* + * Bits to be used if we configure the NorthBridge (NB) Watchdog. The watchdog + * triggers a machine check exception when no response to an NB system access + * occurs within a specified time interval. If the BIOS (i.e. platform design) + * has enabled the watchdog, we leave its rate alone. If the BIOS has not + * enabled the watchdog, we enable it and set the rate to one specified below. + * To disable the watchdog, add the AMD_NB_CFG_WDOGTMRDIS bit to ao_nb_cfg_add. + */ +uint32_t ao_nb_cfg_wdog = + AMD_NB_CFG_WDOGTMRCNTSEL_4095 | + AMD_NB_CFG_WDOGTMRBASESEL_1MS; + +static void +ao_nb_cfg(ao_mca_t *mca) +{ + uint_t chipid = chip_plat_get_chipid(CPU); + uint32_t val; + + if (chip_plat_get_clogid(CPU) != 0) + return; /* only configure NB once per CPU */ + + /* + * Read the NorthBridge (NB) configuration register in PCI space, + * modify the settings accordingly, and store the new value back. + */ + mca->ao_mca_bios_cfg.bcfg_nb_cfg = val = + ao_pcicfg_read(chipid, AMD_NB_FUNC, AMD_NB_REG_CFG); + + /* + * If the watchdog was disabled, enable it according to the policy + * described above. Then apply the ao_nb_cfg_[add|remove] masks. + */ + if (val & AMD_NB_CFG_WDOGTMRDIS) { + val &= ~AMD_NB_CFG_WDOGTMRBASESEL_MASK; + val &= ~AMD_NB_CFG_WDOGTMRCNTSEL_MASK; + val &= ~AMD_NB_CFG_WDOGTMRDIS; + val |= ao_nb_cfg_wdog; + } + + val &= ~ao_nb_cfg_remove; + val |= ao_nb_cfg_add; + + ao_pcicfg_write(chipid, AMD_NB_FUNC, AMD_NB_REG_CFG, val); +} + +/* + * Capture the machine-check exception state into our per-CPU logout area, and + * dispatch a copy of the logout area to our error queue for ereport creation. + * If 'rp' is non-NULL, we're being called from trap context; otherwise we're + * being polled or poked by the injector. We return the number of errors + * found through 'np', and a boolean indicating whether the error is fatal. + * The caller is expected to call fm_panic() if we return fatal (non-zero). + */ +int +ao_mca_logout(ao_cpu_logout_t *acl, struct regs *rp, int *np) +{ + int i, fatal, n = 0; + + acl->acl_timestamp = gethrtime_waitfree(); + acl->acl_mcg_status = rdmsr(IA32_MSR_MCG_STATUS); + acl->acl_ip = rp ? rp->r_pc : 0; + acl->acl_flags = 0; + + /* + * Iterate over the banks of machine-check registers, read the address + * and status registers into the logout area, and clear them as we go. + */ + for (i = 0; i < AMD_MCA_BANK_COUNT; i++) { + ao_bank_logout_t *abl = &acl->acl_banks[i]; + + abl->abl_addr = rdmsr(ao_bank_regs[i].abr_addr); + abl->abl_status = rdmsr(ao_bank_regs[i].abr_status); + + if (abl->abl_status & AMD_BANK_STAT_VALID) + wrmsr(ao_bank_regs[i].abr_status, 0); + } + + if (rp == NULL || !USERMODE(rp->r_cs)) + acl->acl_flags |= AO_ACL_F_PRIV; + + if (ao_mca_stack_flag) + acl->acl_stackdepth = getpcstack(acl->acl_stack, FM_STK_DEPTH); + else + acl->acl_stackdepth = 0; + + /* + * Clear MCG_STATUS, indicating that machine-check trap processing is + * complete. Once we do this, another machine-check trap can occur. + */ + wrmsr(IA32_MSR_MCG_STATUS, 0); + + /* + * If we took a machine-check trap, then the error is fatal if the + * return instruction pointer is not valid in the global register. + */ + fatal = rp != NULL && !(acl->acl_mcg_status & MCG_STATUS_RIPV); + + /* + * Now iterate over the saved logout area, determining whether the + * error that we saw is fatal or not based upon our dispositions + * and the hardware's indicators of whether or not we can resume. + */ + for (i = 0; i < AMD_MCA_BANK_COUNT; i++) { + ao_bank_logout_t *abl = &acl->acl_banks[i]; + const ao_error_disp_t *aed; + + if (!(abl->abl_status & AMD_BANK_STAT_VALID)) + continue; + + aed = ao_disp_match(i, abl->abl_status); + fatal |= (aed->aed_panic_when != AO_AED_PANIC_NEVER); + + /* + * If we are taking a machine-check exception and the overflow + * bit is set or our context is corrupt, then we must die. + * NOTE: This code assumes that if the overflow bit is set and + * we didn't take a #mc exception (i.e. the poller found it), + * then multiple correctable errors overwrote each other. + * This will need to change if we eventually use the Opteron + * Rev E exception mechanism for detecting correctable errors. + */ + if (rp != NULL && (abl->abl_status & + (AMD_BANK_STAT_OVER | AMD_BANK_STAT_PCC))) + fatal = 1; + + /* + * If we are taking a machine-check exception and we don't + * recognize the error case at all, then assume it's fatal. + * This will need to change if we eventually use the Opteron + * Rev E exception mechanism for detecting correctable errors. + */ + if (rp != NULL && aed == &ao_disp_unknown) + fatal = 1; + + n++; + } + + if (n > 0) { + errorq_dispatch(ao_mca_queue, acl, sizeof (ao_cpu_logout_t), + fatal && cmi_panic_on_uncorrectable_error ? + ERRORQ_SYNC : ERRORQ_ASYNC); + } + + if (np != NULL) + *np = n; /* return number of errors found to caller */ + + return (fatal); +} + +static uint_t +ao_ereport_synd(ao_mca_t *mca, + const ao_bank_logout_t *abl, uint_t *typep, int is_nb) +{ + if (is_nb) { + if ((mca->ao_mca_bios_cfg.bcfg_nb_cfg & + AMD_NB_CFG_CHIPKILLECCEN) != 0) { + *typep = AMD_SYNDTYPE_CHIPKILL; + return (AMD_NB_STAT_CKSYND(abl->abl_status)); + } else { + *typep = AMD_SYNDTYPE_ECC; + return (AMD_BANK_SYND(abl->abl_status)); + } + } else { + *typep = AMD_SYNDTYPE_ECC; + return (AMD_BANK_SYND(abl->abl_status)); + } +} + +static void +ao_ereport_create_resource_elem(nvlist_t **nvlp, nv_alloc_t *nva, + mc_unum_t *unump, int dimmnum) +{ + nvlist_t *snvl; + *nvlp = fm_nvlist_create(nva); /* freed by caller */ + + snvl = fm_nvlist_create(nva); + + (void) nvlist_add_uint64(snvl, FM_FMRI_HC_SPECIFIC_OFFSET, + unump->unum_offset); + + fm_fmri_hc_set(*nvlp, FM_HC_SCHEME_VERSION, NULL, snvl, 4, + "motherboard", unump->unum_board, + "chip", unump->unum_chip, + "memory-controller", unump->unum_mc, + "dimm", unump->unum_dimms[dimmnum]); + + fm_nvlist_destroy(snvl, FM_NVA_FREE); +} + +static void +ao_ereport_add_resource(nvlist_t *payload, nv_alloc_t *nva, mc_unum_t *unump) +{ + + nvlist_t *elems[MC_UNUM_NDIMM]; + int nelems = 0; + int i; + + for (i = 0; i < MC_UNUM_NDIMM; i++) { + if (unump->unum_dimms[i] == -1) + break; + ao_ereport_create_resource_elem(&elems[nelems++], nva, + unump, i); + } + + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RESOURCE, + DATA_TYPE_NVLIST_ARRAY, nelems, elems); + + for (i = 0; i < nelems; i++) + fm_nvlist_destroy(elems[i], FM_NVA_FREE); +} + +static void +ao_ereport_add_logout(ao_data_t *ao, nvlist_t *payload, nv_alloc_t *nva, + const ao_cpu_logout_t *acl, uint_t bankno, const ao_error_disp_t *aed) +{ + uint64_t members = aed->aed_ereport_members; + ao_mca_t *mca = &ao->ao_mca; + const ao_bank_logout_t *abl = &acl->acl_banks[bankno]; + uint_t synd, syndtype; + + synd = ao_ereport_synd(mca, abl, &syndtype, bankno == AMD_MCA_BANK_NB); + + if (members & FM_EREPORT_PAYLOAD_FLAG_BANK_STAT) { + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BANK_STAT, + DATA_TYPE_UINT64, abl->abl_status, NULL); + } + + if (members & FM_EREPORT_PAYLOAD_FLAG_BANK_NUM) { + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BANK_NUM, + DATA_TYPE_UINT8, bankno, NULL); + } + + if (members & FM_EREPORT_PAYLOAD_FLAG_ADDR) { + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ADDR, + DATA_TYPE_UINT64, abl->abl_addr, NULL); + } + + if (members & FM_EREPORT_PAYLOAD_FLAG_ADDR_VALID) { + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ADDR_VALID, + DATA_TYPE_BOOLEAN_VALUE, (abl->abl_status & + AMD_BANK_STAT_ADDRV) ? B_TRUE : B_FALSE); + } + + if (members & FM_EREPORT_PAYLOAD_FLAG_SYND) { + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SYND, + DATA_TYPE_UINT16, synd, NULL); + } + + if (members & FM_EREPORT_PAYLOAD_FLAG_SYND_TYPE) { + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SYND_TYPE, + DATA_TYPE_STRING, (syndtype == AMD_SYNDTYPE_CHIPKILL ? + "C" : "E"), NULL); + } + + if (members & FM_EREPORT_PAYLOAD_FLAG_IP) { + uint64_t ip = (acl->acl_mcg_status & MCG_STATUS_EIPV) ? + acl->acl_ip : 0; + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_IP, + DATA_TYPE_UINT64, ip, NULL); + } + + if (members & FM_EREPORT_PAYLOAD_FLAG_PRIV) { + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PRIV, + DATA_TYPE_BOOLEAN_VALUE, (acl->acl_flags & AO_ACL_F_PRIV) ? + B_TRUE : B_FALSE, NULL); + } + + if (members & FM_EREPORT_PAYLOAD_FLAG_RESOURCE) { + mc_unum_t unum; + int addrvalid; + + addrvalid = (members & FM_EREPORT_PAYLOAD_FLAG_ADDR) && + (members & FM_EREPORT_PAYLOAD_FLAG_ADDR_VALID) && + (abl->abl_status & AMD_BANK_STAT_ADDRV); + + if (addrvalid && ao_mc_patounum(ao, abl->abl_addr, synd, + syndtype, &unum)) + ao_ereport_add_resource(payload, nva, &unum); + } + + if (ao_mca_stack_flag && members & FM_EREPORT_PAYLOAD_FLAG_STACK) { + fm_payload_stack_add(payload, acl->acl_stack, + acl->acl_stackdepth); + } +} + +static void +ao_ereport_post(const ao_cpu_logout_t *acl, + int bankno, const ao_error_disp_t *aed) +{ + ao_data_t *ao = acl->acl_ao; + errorq_elem_t *eqep; + nvlist_t *ereport, *detector; + nv_alloc_t *nva = NULL; + char buf[FM_MAX_CLASS]; + + if (panicstr) { + if ((eqep = errorq_reserve(ereport_errorq)) == NULL) + return; + ereport = errorq_elem_nvl(ereport_errorq, eqep); + nva = errorq_elem_nva(ereport_errorq, eqep); + } else { + ereport = fm_nvlist_create(nva); + } + + /* + * Create the scheme "cpu" FMRI + */ + detector = ao_fmri_create(ao, nva); + + /* + * Encode all the common data into the ereport. + */ + (void) snprintf(buf, FM_MAX_CLASS, "%s.%s.%s", + FM_ERROR_CPU, "amd", aed->aed_class); + + fm_ereport_set(ereport, FM_EREPORT_VERSION, buf, + fm_ena_generate_cpu(acl->acl_timestamp, ao->ao_cpu->cpu_id, + FM_ENA_FMT1), detector, NULL); + + /* + * Encode the error-specific data that was saved in the logout area. + */ + ao_ereport_add_logout(ao, ereport, nva, acl, bankno, aed); + + if (panicstr) { + errorq_commit(ereport_errorq, eqep, ERRORQ_SYNC); + } else { + (void) fm_ereport_post(ereport, EVCH_TRYHARD); + fm_nvlist_destroy(ereport, FM_NVA_FREE); + fm_nvlist_destroy(detector, FM_NVA_FREE); + } +} + +/*ARGSUSED*/ +void +ao_mca_drain(void *ignored, const void *data, const errorq_elem_t *eqe) +{ + const ao_cpu_logout_t *acl = data; + int i; + + for (i = 0; i < AMD_MCA_BANK_COUNT; i++) { + const ao_bank_logout_t *abl = &acl->acl_banks[i]; + const ao_error_disp_t *aed; + + if (abl->abl_status & AMD_BANK_STAT_VALID) { + aed = ao_disp_match(i, abl->abl_status); + ao_ereport_post(acl, i, aed); + } + } +} + +int +ao_mca_trap(void *data, struct regs *rp) +{ + ao_data_t *ao = data; + ao_mca_t *mca = &ao->ao_mca; + ao_cpu_logout_t *acl = &mca->ao_mca_logout[AO_MCA_LOGOUT_EXCEPTION]; + return (ao_mca_logout(acl, rp, NULL)); +} + +/*ARGSUSED*/ +int +ao_mca_inject(void *data, cmi_mca_regs_t *regs, uint_t nregs) +{ + uint64_t hwcr, oldhwcr; + int i; + + oldhwcr = rdmsr(MSR_AMD_HWCR); + hwcr = oldhwcr | AMD_HWCR_MCI_STATUS_WREN; + wrmsr(MSR_AMD_HWCR, hwcr); + + for (i = 0; i < nregs; i++) + wrmsr(regs[i].cmr_msrnum, regs[i].cmr_msrval); + + wrmsr(MSR_AMD_HWCR, oldhwcr); + return (0); +} + +void +ao_mca_init(void *data) +{ + ao_data_t *ao = data; + ao_mca_t *mca = &ao->ao_mca; + uint64_t cap; + int i; + + ao_mca_poll_init(mca); + + ASSERT(x86_feature & X86_MCA); + cap = rdmsr(IA32_MSR_MCG_CAP); + ASSERT(cap & MCG_CAP_CTL_P); + + /* + * If the hardware's bank count is different than what we expect, then + * we're running on some Opteron variant that we don't understand yet. + */ + if ((cap & MCG_CAP_COUNT_MASK) != AMD_MCA_BANK_COUNT) { + cmn_err(CE_WARN, "CPU %d has %llu MCA banks; expected %u: " + "disabling MCA on this CPU", ao->ao_cpu->cpu_id, + (u_longlong_t)cap & MCG_CAP_COUNT_MASK, AMD_MCA_BANK_COUNT); + return; + } + + /* + * Configure the logout areas. We preset every logout area's acl_ao + * pointer to refer back to our per-CPU state for errorq drain usage. + */ + for (i = 0; i < AO_MCA_LOGOUT_NUM; i++) + mca->ao_mca_logout[i].acl_ao = ao; + + ao_bank_cfg(mca); + ao_nb_cfg(mca); + + wrmsr(IA32_MSR_MCG_CTL, AMD_MCG_EN_ALL); + + /* + * Throw away all existing bank state. We do this because some BIOSes, + * perhaps during POST, do things to the machine that cause MCA state + * to be updated. If we interpret this state as an actual error, we + * may end up indicting something that's not actually broken. + */ + for (i = 0; i < sizeof (ao_bank_cfgs) / sizeof (ao_bank_cfg_t); i++) + wrmsr(ao_bank_cfgs[i].bank_status, 0ULL); + + wrmsr(IA32_MSR_MCG_STATUS, 0ULL); + membar_producer(); + + setcr4(getcr4() | CR4_MCE); /* enable #mc exceptions */ +} + +/*ARGSUSED*/ +void +ao_mca_post_init(void *data) +{ + const struct ao_smi_disable *asd; + id_t id; + + smbios_system_t sy; + smbios_bios_t sb; + smbios_info_t si; + + /* + * Fetch the System and BIOS vendor strings from SMBIOS and see if they + * match a value in our table. If so, disable SMI error polling. This + * is grotesque and should be replaced by self-describing vendor- + * specific SMBIOS data or a specification enhancement instead. + */ + if (ao_mca_smi_disable && ksmbios != NULL && + smbios_info_bios(ksmbios, &sb) != SMB_ERR && + (id = smbios_info_system(ksmbios, &sy)) != SMB_ERR && + smbios_info_common(ksmbios, id, &si) != SMB_ERR) { + + for (asd = ao_smi_disable; asd->asd_sys_vendor != NULL; asd++) { + if (strncmp(asd->asd_sys_vendor, si.smbi_manufacturer, + strlen(asd->asd_sys_vendor)) != 0 || + strncmp(asd->asd_bios_vendor, sb.smbb_vendor, + strlen(asd->asd_bios_vendor)) != 0) + continue; + + cmn_err(CE_CONT, "?SMI polling disabled in favor of " + "Solaris Fault Management for AMD Processors"); + + outl(asd->asd_port, asd->asd_code); + break; + } + } + + ao_mca_poll_start(); +} + +/* + * Called after a CPU has been marked with CPU_FAULTED. Not called on the + * faulted CPU. cpu_lock is held. + */ +/*ARGSUSED*/ +void +ao_faulted_enter(void *data) +{ + /* + * Nothing to do here. We'd like to turn off the faulted CPU's + * correctable error detectors, but that can only be done by the + * faulted CPU itself. cpu_get_state() will now return P_FAULTED, + * allowing the poller to skip this CPU until it is re-enabled. + */ +} + +/* + * Called after the CPU_FAULTED bit has been cleared from a previously-faulted + * CPU. Not called on the faulted CPU. cpu_lock is held. + */ +void +ao_faulted_exit(void *data) +{ + ao_data_t *ao = data; + + /* + * We'd like to clear the faulted CPU's MCi_STATUS registers so as to + * avoid generating ereports for errors which occurred while the CPU was + * officially faulted. Unfortunately, those registers can only be + * cleared by the CPU itself, so we can't do it here. + * + * We're going to set the UNFAULTING bit on the formerly-faulted CPU's + * MCA state. This will tell the poller that the MCi_STATUS registers + * can't yet be trusted. The poller, which is the first thing we + * control that'll execute on that CPU, will clear the registers, and + * will then clear the bit. + */ + + ao->ao_mca.ao_mca_flags |= AO_MCA_F_UNFAULTING; +} diff --git a/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca_disp.h b/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca_disp.h new file mode 100644 index 0000000000..ccb1c01bce --- /dev/null +++ b/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca_disp.h @@ -0,0 +1,67 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _AO_MCA_DISP_H +#define _AO_MCA_DISP_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/mca_amd.h> +#include <sys/fm/cpu/AMD.h> + +#include "ao.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define AO_MCA_PP_BIT_SRC 0x1 +#define AO_MCA_PP_BIT_RSP 0x2 +#define AO_MCA_PP_BIT_OBS 0x4 +#define AO_MCA_PP_BIT_GEN 0x8 + +#define AO_MCA_II_BIT_MEM 0x1 +#define AO_MCA_II_BIT_IO 0x2 +#define AO_MCA_II_BIT_GEN 0x4 + +#define AO_MCA_R4_BIT_GEN 0x001 +#define AO_MCA_R4_BIT_RD 0x002 +#define AO_MCA_R4_BIT_WR 0x004 +#define AO_MCA_R4_BIT_DRD 0x008 +#define AO_MCA_R4_BIT_DWD 0x010 +#define AO_MCA_R4_BIT_DWR 0x020 +#define AO_MCA_R4_BIT_IRD 0x040 +#define AO_MCA_R4_BIT_PREFETCH 0x080 +#define AO_MCA_R4_BIT_EVICT 0x100 +#define AO_MCA_R4_BIT_SNOOP 0x200 + +extern const ao_error_disp_t *ao_error_disp[]; + +#ifdef __cplusplus +} +#endif + +#endif /* _AO_MCA_DISP_H */ diff --git a/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca_disp.in b/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca_disp.in new file mode 100644 index 0000000000..b8d88e71a5 --- /dev/null +++ b/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca_disp.in @@ -0,0 +1,778 @@ +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +funcunit = dc + +desc = Correctable D$ data infill from system memory +error = ereport.cpu.amd.dc.inf_sys_ecc1 + +mask on = AMD_BANK_STAT_CECC +mask off = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 bus src 0 drd mem/io lg - + +panic = never +flags = correctable + +# --- + +desc = Correctable D$ data infill from L2$ +error = ereport.cpu.amd.dc.inf_l2_ecc1 + +mask on = AMD_BANK_STAT_CECC +mask off = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - drd - l2 data + +panic = never +flags = correctable + +# --- + +desc = Uncorrectable D$ data infill from system memory +error = ereport.cpu.amd.dc.inf_sys_eccm + +mask on = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC +mask off = AMD_BANK_STAT_CECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 bus src 0 drd mem/io lg - + +panic = always +flags = + +# --- + +desc = Uncorrectable D$ data infill from L2$ +error = ereport.cpu.amd.dc.inf_l2_eccm + +mask on = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC +mask off = AMD_BANK_STAT_CECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - drd - l2 data + +panic = always +flags = correctable + +# --- + +desc = Correctable single-bit error in Data Array from scrub +error = ereport.cpu.amd.dc.data_ecc1 + +mask on = AMD_BANK_STAT_CECC, AMD_BANK_STAT_SCRUB +mask off = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - gen - l1 data + +panic = never +flags = correctable + +# --- + +desc = Uncorrectable single-bit error in Data Array +error = ereport.cpu.amd.dc.data_ecc1_uc + +mask on = AMD_BANK_STAT_UC, AMD_BANK_STAT_CECC +mask off = AMD_BANK_STAT_SCRUB + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - drd/dwr/ev/snp - l1 data + +panic = always +flags = + +# --- + +desc = Uncorrectable multi-bit error in Data Array +error = ereport.cpu.amd.dc.data_eccm + +mask on = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_SCRUB + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - drd/dwr/ev/snp - l1 data + +panic = always +flags = + +# --- + +desc = Uncorrectable multi-bit error in Data Array from scrub +error = ereport.cpu.amd.dc.data_eccm + +mask on = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC, AMD_BANK_STAT_SCRUB +mask off = AMD_BANK_STAT_CECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - gen - l1 data + +panic = always +flags = + +# --- + +desc = Main Tag Array Parity Error +error = ereport.cpu.amd.dc.tag_par + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - drd/dwr - l1 data + +panic = always +flags = + +# --- + +desc = Snoop Tag Array Parity Error +error = ereport.cpu.amd.dc.stag_par + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - snp/ev - l1 data + +panic = always +flags = + +# --- + +desc = L1 DTLB Parity Error +error = ereport.cpu.amd.dc.l1tlb_par + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 tlb - - - - l1 data + +panic = always +flags = + +# --- + +desc = L1 DTLB Parity Error (multimatch) +error = ereport.cpu.amd.dc.l1tlb_par + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0001 tlb - - - - l1 data + +panic = always +flags = + +# --- + +desc = L2 DTLB Parity Error +error = ereport.cpu.amd.dc.l2tlb_par + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 tlb - - - - l2 data + +panic = always +flags = + +# --- + +desc = L2 DTLB Parity Error (multimatch) +error = ereport.cpu.amd.dc.l2tlb_par + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0001 tlb - - - - l2 data + +panic = always +flags = + +# +# Instruction Cache Functional Unit +# + +funcunit = ic + +desc = Correctable I$ data infill from system memory +error = ereport.cpu.amd.ic.inf_sys_ecc1 + +mask on = AMD_BANK_STAT_CECC +mask off = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 bus src 0 ird mem lg - + +panic = never +flags = correctable + +# ---- + +desc = Correctable I$ data infill from L2$ +error = ereport.cpu.amd.ic.inf_l2_ecc1 + +mask on = AMD_BANK_STAT_CECC +mask off = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - ird - l2 instr + +panic = never +flags = correctable + +# ---- + +desc = Uncorrectable I$ data infill from system memory +error = ereport.cpu.amd.ic.inf_sys_eccm + +mask on = AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 bus src 0 ird mem lg - + +panic = always +flags = + +# --- + +desc = Uncorrectable I$ data infill from L2$ +error = ereport.cpu.amd.ic.inf_l2_eccm + +mask on = AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - ird - l2 instr + +panic = always +flags = + +# --- + +desc = Data Array Parity Error +error = ereport.cpu.amd.ic.data_par + +mask on = +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - ird - l1 instr + +panic = never +flags = correctable + +# --- + +desc = Main Tag Array Parity Error +error = ereport.cpu.amd.ic.tag_par + +mask on = +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - ird/ev - l1 instr + +panic = never +flags = correctable + +# --- + +desc = Snoop Tag Array Parity Error +error = ereport.cpu.amd.ic.stag_par + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - snp/ev - l1 instr + +panic = always +flags = + +# --- + +desc = L1 ITLB Parity Error +error = ereport.cpu.amd.ic.l1tlb_par + +mask on = +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 tlb - - - - l1 instr + +panic = never +flags = correctable + +# --- + +desc = L1 ITLB Parity Error (multimatch) +error = ereport.cpu.amd.ic.l1tlb_par + +mask on = +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0001 tlb - - - - l1 instr + +panic = never +flags = correctable + +# --- + +desc = L2 ITLB Parity Error +error = ereport.cpu.amd.ic.l2tlb_par + +mask on = +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 tlb - - - - l2 instr + +panic = never +flags = correctable + +# --- + +desc = L2 ITLB Parity Error (multimatch) +error = ereport.cpu.amd.ic.l2tlb_par + +mask on = +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0001 tlb - - - - l2 instr + +panic = never +flags = correctable + +# --- + +desc = System Data Read Error +error = ereport.cpu.amd.ic.rdde + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 bus src 0 ird mem lg - + +panic = always +flags = + +# +# --- +# + +funcunit = bu + +# --- + +desc = L2 data array single-bit ECC during TLB reload, snoop, or copyback +error = ereport.cpu.amd.bu.l2d_ecc1 + +mask on = AMD_BANK_STAT_CECC +mask off = AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - rd/snp/ev - l2 gen + +panic = never +flags = correctable + +# --- + +desc = L2 data array multi-bit ECC during TLB reload, snoop, or copyback +error = ereport.cpu.amd.bu.l2d_eccm + +mask on = AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - rd/snp/ev - l2 gen + +panic = always +flags = + +# --- + +desc = L2 main tag array single-bit ECC error on scrubber access +error = ereport.cpu.amd.bu.l2t_ecc1 + +mask on = AMD_BANK_STAT_CECC, AMD_BANK_STAT_SCRUB +mask off = AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0010 mem - - gen - l2 instr + +panic = never +flags = correctable + +# --- + +desc = L2 main tag array multi-bit ECC error on scrubber access +error = ereport.cpu.amd.bu.l2t_eccm + +mask on = AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC, AMD_BANK_STAT_SCRUB +mask off = AMD_BANK_STAT_CECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0010 mem - - gen - l2 instr + +panic = always +flags = + +# --- + +desc = L2 main tag array parity error on I$ fetch +error = ereport.cpu.amd.bu.l2t_par + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0010 mem - - ird - l2 instr + +panic = always +flags = + +# --- + +desc = L2 main tag array parity error on D$ fetch +error = ereport.cpu.amd.bu.l2t_par + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0010 mem - - drd - l2 data + +panic = always +flags = + +# --- + +desc = L2 main tag array parity error on TLB reload, snoop, or copyback +error = ereport.cpu.amd.bu.l2t_par + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0010 mem - - rd/snp/ev - l2 gen + +panic = always +flags = + +# --- + +desc = L2 main tag array parity error on scrubber access +error = ereport.cpu.amd.bu.l2t_par + +mask on = AMD_BANK_STAT_UC, AMD_BANK_STAT_SCRUB +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0010 mem - - gen - l2 instr + +panic = always +flags = + +# --- + +desc = System data single-bit ECC for hardware prefetch or TLB reload +error = ereport.cpu.amd.bu.s_ecc1 + +mask on = AMD_BANK_STAT_CECC +mask off = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 bus src 0 rd/pf mem/io lg - + +panic = never +flags = correctable + +# --- + +desc = System data multi-bit ECC for hardware prefetch or TLB reload +error = ereport.cpu.amd.bu.s_eccm + +mask on = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC +mask off = AMD_BANK_STAT_CECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 bus src 0 rd/pf mem/io lg - + +panic = always +flags = + +# --- + +desc = System data read error for TLB reload or hardware prefetch +error = ereport.cpu.amd.bu.s_rde + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 bus src 0 rd/pf mem/io lg - + +panic = always +flags = + +# +# --- +# + +funcunit = ls + +desc = System data read error +error = ereport.cpu.amd.ls.s_rde + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 bus src 0 rd/wr mem/io lg - + +panic = always +flags = + +# +# --- +# + +funcunit = nb + +desc = Correctable ECC error from Normal ECC +error = ereport.cpu.amd.nb.mem_ce + +mask on = AMD_BANK_STAT_CECC +mask off = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 bus src/rsp 0 rd/wr mem lg - + +panic = never +flags = correctable + +# --- + +desc = Uncorrectable ECC error from Normal ECC +error = ereport.cpu.amd.nb.mem_ue + +mask on = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC +mask off = AMD_BANK_STAT_CECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 bus src/rsp 0 rd/wr mem lg - + +panic = always +flags = + +# --- + +desc = Correctable ECC error from ChipKill ECC +error = ereport.cpu.amd.nb.mem_ce + +mask on = AMD_BANK_STAT_CECC +mask off = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 1000 bus src/rsp 0 rd/wr mem lg - + +panic = never +flags = correctable + +# --- + +desc = Uncorrectable ECC error from ChipKill ECC +error = ereport.cpu.amd.nb.mem_ue + +mask on = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC +mask off = AMD_BANK_STAT_CECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 1000 bus src/rsp 0 rd/wr mem lg - + +panic = always +flags = + +# --- + +desc = Hypertransport CRC error +error = ereport.cpu.amd.nb.ht_crc + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0001 bus obs 0 gen gen lg - + +panic = always +flags = + +# --- + +desc = Hypertransport Sync packet error +error = ereport.cpu.amd.nb.ht_sync + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0010 bus obs 0 gen gen lg - + +panic = always +flags = + +# --- + +desc = Master Abort +error = ereport.cpu.amd.nb.ma + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0011 bus src/obs 0 rd/wr mem/io lg - + +panic = never +flags = + +# --- + +desc = Target Abort +error = ereport.cpu.amd.nb.ta + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0100 bus src/obs 0 rd/wr mem/io lg - + +panic = never +flags = + +# --- + +desc = GART Table Walk Error +error = ereport.cpu.amd.nb.gart_walk + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0101 tlb - - - - lg gen + +panic = always +flags = + +# --- + +desc = Atomic Read/Modify/Write error +error = ereport.cpu.amd.nb.rmw + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0110 bus obs 0 gen io lg - + +panic = always +flags = + +# --- + +desc = Watchdog error (timeout) +error = ereport.cpu.amd.nb.wdog + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0111 bus gen 1 gen gen lg - + +panic = always +flags = diff --git a/usr/src/uts/i86pc/cpu/amd_opteron/ao_poll.c b/usr/src/uts/i86pc/cpu/amd_opteron/ao_poll.c new file mode 100644 index 0000000000..e083351d12 --- /dev/null +++ b/usr/src/uts/i86pc/cpu/amd_opteron/ao_poll.c @@ -0,0 +1,194 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * AMD Athlon64/Opteron CPU Module Machine-Check Poller + * + * The AMD Opteron processor doesn't yet report correctable errors via #mc's. + * Instead, it fixes the problem, silently updates the error state MSRs, and + * resumes operation. In order to discover occurrances of correctable errors, + * we have to poll in the background using the omni cyclics mechanism. The + * error injector also has the ability to manually request an immediate poll. + * Locking is fairly simple within the poller: the per-CPU mutex + * ao->ao_mca.ao_mca_poll_lock ensures that only one poll request is active. + */ + +#include <sys/types.h> +#include <sys/sysmacros.h> +#include <sys/x86_archext.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/ksynch.h> +#include <sys/sdt.h> + +#include "ao.h" + +static uint_t ao_mca_poll_trace_nent = 100; +#ifdef DEBUG +static uint_t ao_mca_poll_trace_always = 1; +#else +static uint_t ao_mca_poll_trace_always = 0; +#endif + +static cyclic_id_t ao_mca_poll_cycid; +static hrtime_t ao_mca_poll_interval = NANOSEC * 10ULL; + +static void +ao_mca_poll_trace(ao_mca_t *mca, uint32_t what, uint32_t nerr) +{ + uint_t next; + ao_mca_poll_trace_t *pt; + + ASSERT(MUTEX_HELD(&mca->ao_mca_poll_lock)); + DTRACE_PROBE2(ao__poll__trace, uint32_t, what, uint32_t, nerr); + + if (mca->ao_mca_poll_trace == NULL) + return; /* poll trace buffer is disabled */ + + next = (mca->ao_mca_poll_curtrace + 1) % ao_mca_poll_trace_nent; + pt = &mca->ao_mca_poll_trace[next]; + + pt->mpt_when = 0; + pt->mpt_what = what; + + if (what == AO_MPT_WHAT_CYC_ERR) + pt->mpt_nerr = MIN(nerr, UINT8_MAX); + + pt->mpt_when = gethrtime(); + mca->ao_mca_poll_curtrace = next; +} + +static void +ao_mca_poll_common(ao_mca_t *mca, int what) +{ + ao_cpu_logout_t *acl = &mca->ao_mca_logout[AO_MCA_LOGOUT_POLLER]; + int i, n, fatal; + + if (mca->ao_mca_flags & AO_MCA_F_UNFAULTING) { + mca->ao_mca_flags &= ~AO_MCA_F_UNFAULTING; + ao_mca_poll_trace(mca, AO_MPT_WHAT_UNFAULTING, 0); + + /* + * On the first poll after re-enabling a faulty CPU we clear + * the status registers; see ao_faulted_exit() for more info. + */ + if (what == AO_MPT_WHAT_CYC_ERR) { + for (i = 0; i < AMD_MCA_BANK_COUNT; i++) + wrmsr(ao_bank_regs[i].abr_status, 0); + return; + } + } + + fatal = ao_mca_logout(acl, NULL, &n); + ao_mca_poll_trace(mca, what, n); + + if (fatal && cmi_panic_on_uncorrectable_error) + fm_panic("Unrecoverable Machine-Check Exception"); +} + +static void +ao_mca_poll_cyclic(void *arg) +{ + ao_data_t *ao = arg; + + if (ao != NULL && mutex_tryenter(&ao->ao_mca.ao_mca_poll_lock)) { + ao_mca_poll_common(&ao->ao_mca, AO_MPT_WHAT_CYC_ERR); + mutex_exit(&ao->ao_mca.ao_mca_poll_lock); + } +} + +void +ao_mca_poke(void *arg) +{ + ao_data_t *ao = arg; + + mutex_enter(&ao->ao_mca.ao_mca_poll_lock); + ao_mca_poll_common(&ao->ao_mca, AO_MPT_WHAT_POKE_ERR); + mutex_exit(&ao->ao_mca.ao_mca_poll_lock); +} + +/*ARGSUSED*/ +static void +ao_mca_poll_online(void *arg, cpu_t *cpu, cyc_handler_t *cyh, cyc_time_t *cyt) +{ + cyt->cyt_when = 0; + cyh->cyh_level = CY_LOW_LEVEL; + + /* + * If the CPU coming on-line isn't supported by this CPU module, then + * disable the cylic by cranking cyt_interval and setting arg to NULL. + */ + if (cpu->cpu_m.mcpu_cmi != NULL && + cpu->cpu_m.mcpu_cmi->cmi_ops != &_cmi_ops) { + cyt->cyt_interval = INT64_MAX; + cyh->cyh_func = ao_mca_poll_cyclic; + cyh->cyh_arg = NULL; + } else { + cyt->cyt_interval = ao_mca_poll_interval; + cyh->cyh_func = ao_mca_poll_cyclic; + cyh->cyh_arg = cpu->cpu_m.mcpu_cmidata; + } +} + +/*ARGSUSED*/ +static void +ao_mca_poll_offline(void *arg, cpu_t *cpu, void *cyh_arg) +{ + /* nothing to do here */ +} + +void +ao_mca_poll_init(ao_mca_t *mca) +{ + mutex_init(&mca->ao_mca_poll_lock, NULL, MUTEX_DRIVER, NULL); + + if (ao_mca_poll_trace_always) { + mca->ao_mca_poll_trace = + kmem_zalloc(sizeof (ao_mca_poll_trace_t) * + ao_mca_poll_trace_nent, KM_SLEEP); + mca->ao_mca_poll_curtrace = 0; + } +} + +void +ao_mca_poll_start(void) +{ + cyc_omni_handler_t cyo; + + if (ao_mca_poll_interval == 0) + return; /* if manually tuned to zero, disable polling */ + + cyo.cyo_online = ao_mca_poll_online; + cyo.cyo_offline = ao_mca_poll_offline; + cyo.cyo_arg = NULL; + + mutex_enter(&cpu_lock); + ao_mca_poll_cycid = cyclic_add_omni(&cyo); + mutex_exit(&cpu_lock); +} diff --git a/usr/src/uts/i86pc/cpu/generic_cpu/gcpu.h b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu.h new file mode 100644 index 0000000000..f330920591 --- /dev/null +++ b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu.h @@ -0,0 +1,72 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _GCPU_H +#define _GCPU_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/cpu_module.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct gcpu_mca_bank { + uint_t bank_ctl; /* MCi_CTL MSR */ + uint_t bank_status; /* MCi_STATUS MSR */ + uint_t bank_addr; /* MCi_ADDR MSR */ + uint_t bank_misc; /* MCi_MISC MSR */ +} gcpu_mca_bank_t; + +typedef struct gcpu_mca_data { + uint64_t bank_status_data; /* MCi_STATUS value from exception */ + uint64_t bank_addr_data; /* MCi_ADDR value from exception */ + uint64_t bank_misc_data; /* MCi_MISC value from exception */ +} gcpu_mca_data_t; + +typedef struct gcpu_mca { + const gcpu_mca_bank_t *gcpu_mca_banks; + gcpu_mca_data_t *gcpu_mca_data; + uint_t gcpu_mca_nbanks; +} gcpu_mca_t; + +typedef struct gcpu_data { + gcpu_mca_t gcpu_mca; +} gcpu_data_t; + +struct regs; + +extern void gcpu_mca_init(void *); +extern int gcpu_mca_trap(void *, struct regs *); + +#ifdef __cplusplus +} +#endif + +#endif /* _GCPU_H */ diff --git a/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_main.c b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_main.c new file mode 100644 index 0000000000..68b3d8221a --- /dev/null +++ b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_main.c @@ -0,0 +1,125 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Generic x86 CPU Module + * + * This CPU module is used for generic x86 CPUs when Solaris has no other + * CPU-specific support module available. Code in this module should be the + * absolute bare-bones support and must be cognizant of both Intel and AMD etc. + */ + +#include <sys/types.h> +#include <sys/cpu_module_impl.h> +#include <sys/cpuvar.h> +#include <sys/kmem.h> +#include <sys/modctl.h> + +#include "gcpu.h" + +/*ARGSUSED*/ +static void +gcpu_nop(void *data) +{ +} + +static int +gcpu_notsup(void) +{ + return (ENOTSUP); +} + +static int +gcpu_nil(void) +{ + return (0); +} + +/*ARGSUSED*/ +static int +gcpu_init(cpu_t *cpu, void **datap) +{ + *datap = kmem_zalloc(sizeof (gcpu_data_t), KM_SLEEP); + return (0); +} + +static void +gcpu_fini(void *data) +{ + gcpu_data_t *dp = data; + + kmem_free(dp->gcpu_mca.gcpu_mca_data, + dp->gcpu_mca.gcpu_mca_nbanks * sizeof (gcpu_mca_data_t)); + + kmem_free(dp, sizeof (gcpu_data_t)); +} + +const cmi_ops_t _cmi_ops = { + gcpu_init, /* cmi_init */ + gcpu_nop, /* cmi_post_init */ + gcpu_fini, /* cmi_fini */ + gcpu_nop, /* cmi_faulted_enter */ + gcpu_nop, /* cmi_faulted_exit */ + (int (*)())gcpu_nil, /* cmi_scrubber_enable */ + gcpu_mca_init, /* cmi_mca_init */ + gcpu_mca_trap, /* cmi_mca_trap */ + (int (*)())gcpu_notsup, /* cmi_mca_inject */ + gcpu_nop, /* cmi_mca_poke */ + (void (*)())gcpu_nop, /* cmi_mc_register */ + (const cmi_mc_ops_t *(*)())gcpu_nop /* cmi_mc_getops */ +}; + +static struct modlcpu modlcpu = { + &mod_cpuops, + "Generic x86 CPU Module" +}; + +static struct modlinkage modlinkage = { + MODREV_1, + (void *)&modlcpu, + NULL +}; + +int +_init(void) +{ + return (mod_install(&modlinkage)); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + +int +_fini(void) +{ + return (mod_remove(&modlinkage)); +} diff --git a/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_mca.c b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_mca.c new file mode 100644 index 0000000000..3793ff1087 --- /dev/null +++ b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_mca.c @@ -0,0 +1,230 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/mca_x86.h> +#include <sys/cpu_module_impl.h> +#include <sys/cmn_err.h> +#include <sys/cpuvar.h> +#include <sys/x86_archext.h> +#include <sys/controlregs.h> +#include <sys/sysmacros.h> +#include <sys/regset.h> +#include <sys/privregs.h> +#include <sys/systm.h> +#include <sys/types.h> +#include <sys/log.h> +#include <sys/psw.h> + +#include "gcpu.h" + +/* + * x86 architecture standard banks for IA32 and compatible processors. These + * are effectively the lowest common denominators for the MCA architecture. + */ +static const gcpu_mca_bank_t gcpu_mca_banks_ia32[] = { +{ IA32_MSR_MC0_CTL, IA32_MSR_MC0_STATUS, IA32_MSR_MC0_ADDR, IA32_MSR_MC0_MISC }, +{ IA32_MSR_MC1_CTL, IA32_MSR_MC1_STATUS, IA32_MSR_MC1_ADDR, IA32_MSR_MC1_MISC }, +{ IA32_MSR_MC2_CTL, IA32_MSR_MC2_STATUS, IA32_MSR_MC2_ADDR, IA32_MSR_MC2_MISC }, +{ IA32_MSR_MC3_CTL, IA32_MSR_MC3_STATUS, IA32_MSR_MC3_ADDR, IA32_MSR_MC3_MISC }, +}; + +/* + * The P6-family processors have a different layout for their banks. Note that + * MC4 comes *before* MC3 by design here (Intel's design that is, not ours). + */ +static const gcpu_mca_bank_t gcpu_mca_banks_p6[] = { +{ P6_MSR_MC0_CTL, P6_MSR_MC0_STATUS, P6_MSR_MC0_ADDR, P6_MSR_MC0_MISC }, +{ P6_MSR_MC1_CTL, P6_MSR_MC1_STATUS, P6_MSR_MC1_ADDR, P6_MSR_MC1_MISC }, +{ P6_MSR_MC2_CTL, P6_MSR_MC2_STATUS, P6_MSR_MC2_ADDR, P6_MSR_MC2_MISC }, +{ P6_MSR_MC4_CTL, P6_MSR_MC4_STATUS, P6_MSR_MC4_ADDR, P6_MSR_MC4_MISC }, +{ P6_MSR_MC3_CTL, P6_MSR_MC3_STATUS, P6_MSR_MC3_ADDR, P6_MSR_MC3_MISC }, +}; + +/* + * Initialize the Machine Check Architecture (MCA) for a generic x86 CPU. + * Refer to the IA-32 Intel Architecture Software Developer's Manual, + * Volume 3: System Programming Guide, Section 14.5 for more information. + */ +void +gcpu_mca_init(void *data) +{ + gcpu_data_t *gcpu = data; + gcpu_mca_t *mca = &gcpu->gcpu_mca; + cpu_t *cp = CPU; + + uint64_t cap; + uint_t nbanks; + int i; + + /* + * We're only prepared to handle processors that have an MCG_CAP + * register. P5, K6, and earlier processors, which have their own + * more primitive way of doing machine checks, are not supported. + */ + ASSERT(x86_feature & X86_MCA); + cap = rdmsr(IA32_MSR_MCG_CAP); + + if (!(cap & MCG_CAP_CTL_P)) + return; /* do nothing if IA32_MCG_CTL register is missing */ + + if (strcmp(cpuid_getvendorstr(cp), "GenuineIntel") == 0 && + cpuid_getfamily(cp) == 6) { + mca->gcpu_mca_banks = gcpu_mca_banks_p6; + mca->gcpu_mca_nbanks = sizeof (gcpu_mca_banks_p6) / + sizeof (gcpu_mca_bank_t); + } else { + mca->gcpu_mca_banks = gcpu_mca_banks_ia32; + mca->gcpu_mca_nbanks = sizeof (gcpu_mca_banks_ia32) / + sizeof (gcpu_mca_bank_t); + } + + mca->gcpu_mca_data = kmem_alloc( + mca->gcpu_mca_nbanks * sizeof (gcpu_mca_data_t), KM_SLEEP); + + /* + * Unlike AMD's approach of assigning one MCG_CTL bit to each machine + * check register bank, Intel doesn't describe the layout of MCG_CTL or + * promise that each bit corresponds to a bank. The generic guidance + * is simply to write all ones to MCG_CTL, enabling everything that is + * present (h/w ignores writes to the undefined bit positions). The + * code right now only handles the original four banks or the P6 banks, + * so we may enable more than we know how to read on a future CPU. + * This code can be enhanced to dynamically allocate bank state based + * upon MCG_CAP.Count if RAS ever becomes important on non-AMD CPUs. + */ + nbanks = cap & MCG_CAP_COUNT_MASK; + mca->gcpu_mca_nbanks = MIN(nbanks, mca->gcpu_mca_nbanks); + wrmsr(IA32_MSR_MCG_CTL, 0ULL); /* disable features while we configure */ + + for (i = 0; i < mca->gcpu_mca_nbanks; i++) { + const gcpu_mca_bank_t *bank = &mca->gcpu_mca_banks[i]; + wrmsr(bank->bank_ctl, -1ULL); + wrmsr(bank->bank_status, 0ULL); + } + + wrmsr(IA32_MSR_MCG_CTL, -1ULL); /* enable all machine-check features */ + setcr4(getcr4() | CR4_MCE); /* enable machine-check exceptions */ +} + +/* + * Initialize the Machine Check Architecture (MCA) for a generic x86 CPU. + * Refer to the IA-32 Intel Architecture Software Developer's Manual, + * Volume 3: System Programming Guide, Section 14.7 for more information. + */ +int +gcpu_mca_trap(void *data, struct regs *rp) +{ + gcpu_data_t *gcpu = data; + gcpu_mca_t *mca = &gcpu->gcpu_mca; + uint64_t gstatus = rdmsr(IA32_MSR_MCG_STATUS); + int i, fatal = !(gstatus & MCG_STATUS_RIPV); + + if (!(gstatus & MCG_STATUS_MCIP)) + return (0); /* spurious machine check trap */ + + /* + * Read out the bank status values, and the address and misc registers + * if they are valid. Update our fatal status based on each bank. + * Clear the MCG_STATUS register when we're done reading the h/w state. + */ + for (i = 0; i < mca->gcpu_mca_nbanks; i++) { + const gcpu_mca_bank_t *bank = &mca->gcpu_mca_banks[i]; + gcpu_mca_data_t *data = &mca->gcpu_mca_data[i]; + uint64_t bstatus = rdmsr(bank->bank_status); + + data->bank_status_data = bstatus; + data->bank_addr_data = 0; + data->bank_misc_data = 0; + + if (!(bstatus & MSR_MC_STATUS_VAL)) + continue; + + if (bstatus & MSR_MC_STATUS_ADDRV) + data->bank_addr_data = rdmsr(bank->bank_addr); + if (bstatus & MSR_MC_STATUS_MISCV) + data->bank_misc_data = rdmsr(bank->bank_misc); + + if (bstatus & (MSR_MC_STATUS_PCC | MSR_MC_STATUS_O)) + fatal = 1; /* context corrupt or overflow */ + + wrmsr(bank->bank_status, 0ULL); + } + + wrmsr(IA32_MSR_MCG_STATUS, 0); + + log_enter(); + + if (gstatus & MCG_STATUS_EIPV) { + cmn_err(CE_WARN, "Machine-Check Exception at 0x%lx in %s mode", + (ulong_t)rp->r_pc, USERMODE(rp->r_cs) ? "user" : "kernel"); + } else { + cmn_err(CE_WARN, "Machine-Check Exception in %s mode", + USERMODE(rp->r_cs) ? "user" : "kernel"); + } + + /* + * Now go back through our saved state and report it using cmn_err(). + * We don't bother attempting any kind of decoding here as the actual + * values are entirely specific to the actual processor in use. We + * could break out the generic bit-fields, but you're only here if + * we didn't care enough to implement FMA support for this processor. + */ + for (i = 0; i < mca->gcpu_mca_nbanks; i++) { + gcpu_mca_data_t *bank = &mca->gcpu_mca_data[i]; + uint64_t bstatus = bank->bank_status_data; + + if (!(bstatus & MSR_MC_STATUS_VAL)) + continue; + + switch (bstatus & (MSR_MC_STATUS_ADDRV | MSR_MC_STATUS_MISCV)) { + case MSR_MC_STATUS_ADDRV | MSR_MC_STATUS_MISCV: + cmn_err(CE_WARN, "%d STAT 0x%016llx ADDR 0x%016llx " + "MISC 0x%016llx", i, (u_longlong_t)bstatus, + (u_longlong_t)bank->bank_addr_data, + (u_longlong_t)bank->bank_misc_data); + break; + case MSR_MC_STATUS_ADDRV: + cmn_err(CE_WARN, "%d STAT 0x%016llx ADDR 0x%016llx", + i, (u_longlong_t)bstatus, + (u_longlong_t)bank->bank_addr_data); + break; + case MSR_MC_STATUS_MISCV: + cmn_err(CE_WARN, "%d STAT 0x%016llx MISC 0x%016llx", + i, (u_longlong_t)bstatus, + (u_longlong_t)bank->bank_misc_data); + break; + default: + cmn_err(CE_WARN, "%d STAT 0x%016llx", + i, (u_longlong_t)bstatus); + } + } + + log_exit(); + return (fatal); +} diff --git a/usr/src/uts/i86pc/cpu/scripts/Makefile b/usr/src/uts/i86pc/cpu/scripts/Makefile new file mode 100644 index 0000000000..f3509aa90e --- /dev/null +++ b/usr/src/uts/i86pc/cpu/scripts/Makefile @@ -0,0 +1,50 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +PERLFILES= \ + ao_gendisp + +include ../../../Makefile.uts + +OWNER= root +GROUP= bin + +.KEEP_STATE: + +all install setup: $(PERLFILES) + +clean: + $(RM) $(PERLFILES) + +include ../../../Makefile.targ + +%: %.pl + $(RM) $@ + cat $< > $@ + chmod +x $@ diff --git a/usr/src/uts/i86pc/cpu/scripts/ao_gendisp.pl b/usr/src/uts/i86pc/cpu/scripts/ao_gendisp.pl new file mode 100644 index 0000000000..9d8b24e539 --- /dev/null +++ b/usr/src/uts/i86pc/cpu/scripts/ao_gendisp.pl @@ -0,0 +1,370 @@ +#!/bin/perl +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +use strict; +use File::Basename; + +my $PROGNAME = basename($0); + +my ($funcunit, $error); +my @funcunits = (); + +my $state = "initial"; + +sub usage() { + print STDERR "Usage: $PROGNAME inputfile\n"; + exit(2); +} + +sub bail() { + print STDERR "$PROGNAME: ", join(" ", @_), "\n"; + exit(1); +} + +sub parsebail() { + print STDERR "$PROGNAME: $::infile: $.: ", join(" ", @_), "\n"; + exit(1); +} + +sub print_header() { + print "#include \"ao_mca_disp.h\"\n\n"; +} + +sub print_footer() { + print "const ao_error_disp_t *ao_error_disp[] = {\n"; + + foreach my $name (@funcunits) { + print "\t$name,\n"; + } + + print "};\n"; +} + +sub funcunit_begin() { + my $arrnm = "ao_error_disp_" . $_[0]; + print "static const ao_error_disp_t " . $arrnm . "[] = {\n"; + + @funcunits = (@funcunits, $arrnm); +} + +sub funcunit_end() { + print "\tNULL\n};\n\n"; +} + +sub error_begin() { + my ($ereport_name) = @_; + + $ereport_name =~ tr/[a-z]./[A-Z]_/; + my $flags_name = $ereport_name; + $flags_name =~ s/EREPORT_/EREPORT_PAYLOAD_FLAGS_/; + + print "\tFM_$ereport_name,\n\tFM_$flags_name,\n"; +} + +sub error_end() { + print "\t},\n\n"; +} + +sub print_bits() { + my $name = $_[0]; + my @bits = @_[1..$#_]; + + if (@bits == 0) { + print "\t0,"; + } elsif (@bits == 1) { + print "\t$bits[0],"; + } else { + print "\t( ", join(" | ", @bits), " ),"; + } + + print " /* $name */\n"; +} + +sub field_burst() { + my ($field, $valuesref, $name, $prefix) = @_; + + if ($field eq "-") { + return (); + } + + map { + if (!defined ${$valuesref}{$_}) { + &parsebail("unknown $name value `$_'"); + } + $_ = ${$valuesref}{$_}; + tr/[a-z]/[A-Z]/; + $prefix . "_" . $_; + } split(/\//, $field); +} + +sub bin2dec() { + my $bin = $_[0]; + my $dec = 0; + + foreach my $bit (split(//, $bin)) { + $dec = $dec * 2 + ($bit eq "1" ? 1 : 0); + } + + $dec; +} + +sub state_funcunit() { + my $val = $_[0]; + + if (defined $::funcunit) { + &funcunit_end(); + } + + $::funcunit = $val; + undef $::error; + &funcunit_begin($::funcunit); +} + +sub state_desc() { + my $desc = $_[0]; + + print "\t/* $desc */\n\t{\n"; +} + +sub state_error() { + $::error = $_[0]; + &error_begin($::error); +} + +sub state_mask_on() { + @::mask_on = map { tr/[a-z]/[A-Z]/; $_; } split(/,\s*/, $_[0]); +} + +sub state_mask_off() { + my @mask_off = map { tr/[a-z]/[A-Z]/; $_; } split(/,\s*/, $_[0]); + + &print_bits("mask", @::mask_on, @mask_off); + &print_bits("mask_res", @::mask_on); +} + +sub state_code() { + my ($ext, $type, $pp, $t, $r4, $ii, $ll, $tt) = split(/\s+/, $_[0]); + + my %tt_values = ( instr => 1, data => 1, gen => 1, '-' => 1 ); + my %ll_values = ( l0 => 1, l1 => 1, l2 => 1, lg => 1 ); + + my %r4_values = ( + gen => 'gen', + rd => 'rd', + wr => 'wr', + drd => 'drd', + dwr => 'dwr', + ird => 'ird', + pf => 'prefetch', + ev => 'evict', + snp => 'snoop', + '-' => '-'); + + my %pp_values = ( + src => 'src', + rsp => 'rsp', + obs => 'obs', + gen => 'gen', + '-' => '-' ); + + my %t_values = ( 0 => 1, 1 => 1, '-' => 1 ); + + my %ii_values = ( + mem => 'mem', + io => 'io', + gen => 'gen', + '-' => '-' ); + + if (!defined $tt_values{$tt}) { + &parsebail("unknown tt value `$tt'"); + } + + if (!defined $ll_values{$ll}) { + &parsebail("unknown ll value `$ll'"); + } + + my @r4 = &field_burst($r4, \%r4_values, "r4", "AO_MCA_R4_BIT"); + + my @pp = ($pp eq '-') ? () : + &field_burst($pp, \%pp_values, "pp", "AO_MCA_PP_BIT"); + + if (!defined $t_values{$t}) { + &parsebail("unknown t value `$t'"); + } + + my @ii = ($ii eq '-') ? () : + &field_burst($ii, \%ii_values, "ii", "AO_MCA_II_BIT"); + + map { + tr/[a-z]/[A-Z]/; + } ($ii, $ll, $tt); + + if ($type eq "bus") { + if ($pp eq "-" || $t eq "-" || $r4 eq "-" || $ii eq "-" || + $ll eq "-" || + $tt ne "-") { + &parsebail("invalid members for bus code type"); + } + + print "\tAMD_ERRCODE_MKBUS(" . + "0, " . # pp + "AMD_ERRCODE_T_" . ($t ? "TIMEOUT" : "NONE") . ", " . + "0, " . # r4 + "0, " . # ii + "AMD_ERRCODE_LL_$ll),\n"; + + } elsif ($type eq "mem") { + if ($r4 eq "-" || $tt eq "-" || $ll eq "-" || + $pp ne "-" || $t ne "-" || $ii ne "-") { + &parsebail("invalid members for mem code type"); + } + + print "\tAMD_ERRCODE_MKMEM(" . + "0, " . # r4 + "AMD_ERRCODE_TT_$tt, " . + "AMD_ERRCODE_LL_$ll),\n"; + + } elsif ($type eq "tlb") { + if ($tt eq "-" || $ll eq "-" || + $r4 ne "-" || $pp ne "-" || $t ne "-" || $ii ne "-") { + &parsebail("invalid members for tlb code type"); + } + + print "\tAMD_ERRCODE_MKTLB(" . + "AMD_ERRCODE_TT_$tt, " . + "AMD_ERRCODE_LL_$ll),\n"; + } else { + &parsebail("unknown code type `$type'"); + } + + print "\t" . &bin2dec($ext) . ", /* ext code $ext */\n"; + + &print_bits("pp_bits", @pp); + &print_bits("ii_bits", @ii); + &print_bits("r4_bits", @r4); +} + +sub state_panic() { + my $val = $_[0]; + + if ($val eq "") { + print "\t0, /* panic_when */\n"; + } else { + $val =~ tr/[a-z]/[A-Z]/; + print "\tAO_AED_PANIC_$val,\n"; + } +} + +sub state_flags() { + my @flags = split(/,\s*/, $_[0]); + + @flags = map { tr/[a-z]/[A-Z]/; "AO_AED_F_" . $_; } @flags; + + &print_bits("flags", @flags); +} + +my %stateparse = ( + funcunit => [ \&state_funcunit, "desc" ], + desc => [ \&state_desc, "error" ], + error => [ \&state_error, "mask on" ], + 'mask on' => [ \&state_mask_on, "mask off" ], + 'mask off' => [ \&state_mask_off, "code" ], + code => [ \&state_code, "panic" ], + panic => [ \&state_panic, "flags" ], + flags => [ \&state_flags, "initial" ] +); + +usage unless (@ARGV == 1); + +my $infile = $ARGV[0]; +open(INFILE, "<$infile") || &bail("failed to open $infile: $!"); + +&print_header(); + +while (<INFILE>) { + chop; + + /^#/ && next; + /^$/ && next; + + if (!/^\s*(\S[^=]*\S)\s*=\s*(\S.*)?$/) { + &parsebail("failed to parse"); + } + + my ($keyword, $val) = ($1, $2); + + if ($state eq "initial") { + if ($keyword eq "funcunit") { + $state = "funcunit"; + } elsif ($keyword eq "desc") { + $state = "desc"; + } else { + &parsebail("unexpected keyword $keyword between " . + "errors"); + } + + } elsif ($state eq "desc") { + if ($keyword eq "funcunit") { + $state = "funcunit"; + } + } + + if ($keyword ne $state) { + &parsebail("keyword `$keyword' invalid here; expected `$state'"); + } + + if (!defined $stateparse{$state}) { + &parsebail("attempt to transition to invalid state `$state'"); + } + + my ($handler, $next) = @{$stateparse{$state}}; + + &{$handler}($val); + + $state = $next; + + if ($state eq "initial") { + &error_end(); + } +} + +close(INFILE); + +if ($state ne "initial" && $state ne "desc") { + &bail("input file ended prematurely"); +} + +if (defined $::funcunit) { + &funcunit_end(); +} else { + &bail("no functional units defined"); +} + +&print_footer; diff --git a/usr/src/uts/i86pc/generic_cpu/Makefile b/usr/src/uts/i86pc/generic_cpu/Makefile new file mode 100644 index 0000000000..f23d9dd369 --- /dev/null +++ b/usr/src/uts/i86pc/generic_cpu/Makefile @@ -0,0 +1,82 @@ +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = cpu.generic +# +OBJECTS = $(CPU_GCPU_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(CPU_GCPU_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_PSM_CPU_DIR)/$(MODULE) + +# +# Include common rules. +# +include ../cpu/Makefile.cpu + +# +# Our lint library has a different name from that of the module we build. +# +LINT_MODULE = generic_cpu + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(LINT_MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +# +# Include common targets. +# +include ../Makefile.targ diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T1000/Makefile b/usr/src/uts/i86pc/io/mc/mc-amd.conf index 39217c3e28..066b704525 100644 --- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T1000/Makefile +++ b/usr/src/uts/i86pc/io/mc/mc-amd.conf @@ -19,14 +19,13 @@ # # CDDL HEADER END # - # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -#pragma ident "%Z%%M% %I% %E% SMI" +# ident "%Z%%M% %I% %E% SMI" +# -TOPOSUBDIR = SUNW,Sun-Fire-T1000 -TOPOFILES = platform.topo +name="mc-amd" parent="pseudo"; -include ../../Makefile.com +ddi-forceattach=1; diff --git a/usr/src/uts/i86pc/io/mc/mcamd.h b/usr/src/uts/i86pc/io/mc/mcamd.h new file mode 100644 index 0000000000..330ecfa5b5 --- /dev/null +++ b/usr/src/uts/i86pc/io/mc/mcamd.h @@ -0,0 +1,192 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _MCAMD_H +#define _MCAMD_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/chip.h> +#include <sys/ksynch.h> +#include <sys/mc_amd.h> +#include <mcamd_api.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * PCI configuration space functions for the memory controller. Note that + * the function numbers here also serve as the mc_func indices in the mc_t. + */ +#define MC_FUNC_HTCONFIG 0 /* unused */ +#define MC_FUNC_HTCONFIG_BINDNM "pci1022,1100" /* unused */ +#define MC_FUNC_ADDRMAP 1 +#define MC_FUNC_ADDRMAP_BINDNM "pci1022,1101" +#define MC_FUNC_DRAMCTL 2 +#define MC_FUNC_DRAMCTL_BINDNM "pci1022,1102" + +/* + * The memory controller driver attaches to several device nodes, but publishes + * a single minor node. We need to ensure that the minor node can be + * consistently mapped back to a single (and the same) device node, so we need + * to pick one to be used. We'll use the DRAM Controller device node, as it'll + * be the last to be attached. + */ +#define MC_FUNC_DEVIMAP MC_FUNC_DRAMCTL + +#define MC_FUNC_NUM 3 + +/* + * The following define the offsets at which various MC registers are + * accessed in PCI config space. For defines describing the register + * structure see mc_amd.h. + */ + +/* + * BKDG 3.29 section 3.4 - MC DRAM base and limit addresses, hole offset. + */ +#define MC_AM_REG_NODE_NUM 8 /* Number of DRAM nodes */ +#define MC_AM_REG_DRAMBASE_0 0x40 /* Offset for DRAM Base 0 */ +#define MC_AM_REG_DRAMLIM_0 0x44 /* Offset for DRAM Limit 0 */ +#define MC_AM_REG_DRAM_INCR 8 /* incr between base/limit pairs */ +#define MC_AM_REG_HOLEADDR 0xf0 /* DRAM Hole Address Register */ + +/* + * BKDG 3.29 section 3.5 - DRAM contoller chip-select base, mask, + * DRAM bank address mapping, DRAM configuration. + */ +#define MC_DC_REG_CS_INCR 4 /* incr for CS base and mask */ +#define MC_DC_REG_CSBASE_0 0x40 /* 0x40 - 0x5c */ +#define MC_DC_REG_CSMASK_0 0x60 /* 0x60 - 0x7c */ +#define MC_DC_REG_BANKADDRMAP 0x80 +#define MC_DC_REG_DRAMCFGLO 0x90 +#define MC_DC_REG_DRAMCFGHI 0x94 + +typedef struct mc_func { + uint_t mcf_instance; + dev_info_t *mcf_devi; +} mc_func_t; + +typedef struct mc_dimm mc_dimm_t; +typedef struct mc_cs mc_cs_t; +typedef struct mc mc_t; + +typedef uint64_t mc_prop_t; /* see mcamd_get_numprop */ + +/* + * Node types for mch_type below. These are used in array indexing. + */ +#define MC_NT_MC 0 +#define MC_NT_CS 1 +#define MC_NT_DIMM 2 +#define MC_NT_NTYPES 3 + +typedef struct mc_hdr { + uint_t mch_type; + union { + mc_t *_mch_mc; + mc_cs_t *_mch_cs; + } _mch_ptr; +} mc_hdr_t; + +#define mch_mc _mch_ptr._mch_mc + +struct mc_dimm { + mc_hdr_t mcd_hdr; /* id, pointer to parent */ + mc_dimm_t *mcd_next; /* next dimm for this MC */ + mc_cs_t *mcd_cs[MC_CHIP_DIMMRANKMAX]; /* associated chip-selects */ + mc_prop_t mcd_num; /* dimm number */ +}; + +#define mcd_mc mcd_hdr.mch_mc + +struct mc_cs { + mc_hdr_t mccs_hdr; /* id, pointer to parent */ + mc_cs_t *mccs_next; /* Next chip-select of MC */ + mc_dimm_t *mccs_dimm[MC_CHIP_DIMMPERCS]; /* dimms for this cs */ + mc_prop_t mccs_num; /* Chip-select number */ + mc_prop_t mccs_base; /* DRAM CS Base */ + mc_prop_t mccs_mask; /* DRAM CS Mask */ + mc_prop_t mccs_size; /* Chip-select bank size */ + mc_prop_t mccs_dimmnums[MC_CHIP_DIMMPERCS]; +}; + +#define mccs_mc mccs_hdr.mch_mc + +typedef struct mc_props { + mc_dimm_t *mcp_dimmlist; /* List of all logical DIMMs, */ + mc_dimm_t *mcp_dimmlast; /* linked via mcd_mcnext */ + mc_prop_t mcp_num; /* Associated *chip* number */ + mc_prop_t mcp_rev; /* Chip revision (MC_REV_*) */ + mc_prop_t mcp_base; /* base address for mc's drams */ + mc_prop_t mcp_lim; /* limit address for mc's drams */ + mc_prop_t mcp_dramcfg; /* DRAM config hi, DRAM config lo */ + mc_prop_t mcp_dramhole; /* DRAM Hole Address Register */ + mc_prop_t mcp_ilen; /* interleave enable */ + mc_prop_t mcp_ilsel; /* interleave select */ + mc_prop_t mcp_csbankmap; /* chip-select bank mapping reg */ + mc_prop_t mcp_accwidth; /* dram access width (64 or 128) */ + mc_prop_t mcp_csbank_intlv; /* cs bank interleave factor */ + mc_prop_t mcp_disabled_cs; /* # banks with CSBE clear */ +} mc_props_t; + +struct mc { + mc_hdr_t mc_hdr; /* id */ + struct mc *mc_next; /* linear, doubly-linked list */ + const char *mc_revname; /* revision name string */ + uint_t mc_ref; /* reference (attach) count */ + mc_func_t mc_funcs[MC_FUNC_NUM]; /* Instance, devinfo, ... */ + chip_t *mc_chip; /* Associated chip */ + mc_cs_t *mc_cslist; /* All active chip-selects */ + mc_cs_t *mc_cslast; /* End of chip-select list */ + mc_props_t mc_props; /* Properties */ + nvlist_t *mc_nvl; /* nvlist for export */ + char *mc_snapshot; /* packed nvlist for libmc */ + size_t mc_snapshotsz; /* packed nvlist buffer size */ + uint_t mc_snapshotgen; /* snapshot generation number */ +}; + +typedef struct mcamd_hdl { + int mcamd_errno; + int mcamd_debug; +} mcamd_hdl_t; + +extern mc_t *mc_list; +extern krwlock_t mc_lock; + +extern void mcamd_mkhdl(mcamd_hdl_t *); +extern void mcamd_mc_register(struct cpu *); + +#ifdef __cplusplus +} +#endif + +#endif /* _MCAMD_H */ diff --git a/usr/src/uts/i86pc/io/mc/mcamd_drv.c b/usr/src/uts/i86pc/io/mc/mcamd_drv.c new file mode 100644 index 0000000000..0b0c04a1d4 --- /dev/null +++ b/usr/src/uts/i86pc/io/mc/mcamd_drv.c @@ -0,0 +1,999 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/conf.h> +#include <sys/ddi.h> +#include <sys/ddifm.h> +#include <sys/sunddi.h> +#include <sys/sunndi.h> +#include <sys/stat.h> +#include <sys/modctl.h> +#include <sys/types.h> +#include <sys/mc.h> +#include <sys/cpuvar.h> +#include <sys/cmn_err.h> +#include <sys/kmem.h> +#include <sys/cred.h> +#include <sys/ksynch.h> +#include <sys/rwlock.h> +#include <sys/chip.h> +#include <sys/open.h> +#include <sys/policy.h> +#include <sys/machsystm.h> +#include <sys/x86_archext.h> +#include <sys/cpu_module.h> +#include <sys/mc_amd.h> + +#include <mcamd.h> +#include <mcamd_api.h> + +int mc_quadranksupport = 0; /* set to 1 for a MB with quad rank support */ + +mc_t *mc_list; +krwlock_t mc_lock; +int mc_hold_attached = 1; + +static void +mc_snapshot_destroy(mc_t *mc) +{ + ASSERT(RW_LOCK_HELD(&mc_lock)); + + if (mc->mc_snapshot == NULL) + return; + + kmem_free(mc->mc_snapshot, mc->mc_snapshotsz); + mc->mc_snapshot = NULL; + mc->mc_snapshotgen++; +} + +static int +mc_snapshot_update(mc_t *mc) +{ + ASSERT(RW_LOCK_HELD(&mc_lock)); + + if (mc->mc_snapshot != NULL) + return (0); + + if (nvlist_pack(mc->mc_nvl, &mc->mc_snapshot, &mc->mc_snapshotsz, + NV_ENCODE_XDR, KM_SLEEP) != 0) + return (-1); + + return (0); +} + +static mc_t * +mc_lookup_func(dev_info_t *dip, int instance, mc_func_t **funcp) +{ + mc_t *mc; + int i; + + ASSERT(RW_LOCK_HELD(&mc_lock)); + + for (mc = mc_list; mc != NULL; mc = mc->mc_next) { + for (i = 0; i < MC_FUNC_NUM; i++) { + mc_func_t *func = &mc->mc_funcs[i]; + if ((dip != NULL && func->mcf_devi == dip) || + (dip == NULL && func->mcf_instance == instance)) { + if (funcp != NULL) + *funcp = func; + return (mc); + } + } + } + + return (NULL); +} + +static mc_t * +mc_lookup_by_devi(dev_info_t *dip, mc_func_t **funcp) +{ + return (mc_lookup_func(dip, 0, funcp)); +} + +static mc_t * +mc_lookup_by_instance(int instance, mc_func_t **funcp) +{ + return (mc_lookup_func(NULL, instance, funcp)); +} + +static mc_t * +mc_lookup_by_chipid(int chipid) +{ + mc_t *mc; + + ASSERT(RW_LOCK_HELD(&mc_lock)); + + for (mc = mc_list; mc != NULL; mc = mc->mc_next) { + if (mc->mc_chip->chip_id == chipid) + return (mc); + } + + return (NULL); +} + +typedef struct mc_rev_map { + uint_t rm_family; + uint_t rm_modello; + uint_t rm_modelhi; + uint_t rm_rev; + const char *rm_name; +} mc_rev_map_t; + +static const mc_rev_map_t mc_rev_map[] = { + { 0xf, 0x00, 0x0f, MC_REV_PRE_D, "B/C/CG" }, + { 0xf, 0x10, 0x1f, MC_REV_D_E, "D" }, + { 0xf, 0x20, 0x3f, MC_REV_D_E, "E" }, + { 0xf, 0x40, 0x5f, MC_REV_F, "F" }, + { 0, 0, 0, MC_REV_UNKNOWN, NULL } +}; + +static const mc_rev_map_t * +mc_revision(chip_t *chp) +{ + int rmn = sizeof (mc_rev_map) / sizeof (mc_rev_map[0]); + const mc_rev_map_t *rm; + uint8_t family, model; + + if (chp == NULL) + return (&mc_rev_map[rmn - 1]); + + /* + * For the moment, we assume that both cores in multi-core chips will + * be of the same revision, so we'll confine our revision check to + * the first CPU pointed to by this chip. + */ + family = cpuid_getfamily(chp->chip_cpus); + model = cpuid_getmodel(chp->chip_cpus); + + for (rm = mc_rev_map; rm->rm_rev != MC_REV_UNKNOWN; rm++) { + if (family == rm->rm_family && model >= rm->rm_modello && + model <= rm->rm_modelhi) + break; + } + + return (rm); +} + +static void +mc_prop_read_pair(ddi_acc_handle_t cfghdl, uint32_t *r1, off_t r1addr, + uint32_t *r2, off_t r2addr, int n, off_t incr) +{ + int i; + + for (i = 0; i < n; i++, r1addr += incr, r2addr += incr) { + r1[i] = pci_config_get32(cfghdl, r1addr); + r2[i] = pci_config_get32(cfghdl, r2addr); + } +} + +static void +mc_nvl_add_prop(nvlist_t *nvl, void *node, uint_t code) +{ + int valfound; + uint64_t value; + const char *name = mcamd_get_propname(code); + + valfound = mcamd_get_numprop(NULL, (mcamd_node_t *)node, code, &value); + + ASSERT(name != NULL && valfound); + if (name != NULL && valfound) + (void) nvlist_add_uint64(nvl, name, value); +} + +static nvlist_t * +mc_nvl_create(mc_t *mc) +{ + mc_cs_t *mccs = mc->mc_cslist; + nvlist_t *cslist[MC_CHIP_NCS], *dimmlist[MC_CHIP_NDIMM]; + nvlist_t *mcnvl; + mc_dimm_t *mcd; + int nelem, i; + + (void) nvlist_alloc(&mcnvl, NV_UNIQUE_NAME, KM_SLEEP); + (void) nvlist_add_string(mcnvl, "revname", mc->mc_revname); + + mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_NUM); + mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_REV); + mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_BASE_ADDR); + mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_LIM_ADDR); + mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_DRAM_CONFIG); + mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_DRAM_HOLE); + mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_DRAM_ILEN); + mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_DRAM_ILSEL); + mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_CSBANKMAP); + mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_ACCESS_WIDTH); + mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_CSBANK_INTLV); + mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_DISABLED_CS); + + for (nelem = 0; mccs != NULL; mccs = mccs->mccs_next, nelem++) { + nvlist_t **csp = &cslist[nelem]; + + (void) nvlist_alloc(csp, NV_UNIQUE_NAME, KM_SLEEP); + mc_nvl_add_prop(*csp, mccs, MCAMD_PROP_NUM); + mc_nvl_add_prop(*csp, mccs, MCAMD_PROP_BASE_ADDR); + mc_nvl_add_prop(*csp, mccs, MCAMD_PROP_MASK); + mc_nvl_add_prop(*csp, mccs, MCAMD_PROP_SIZE); + + if (mccs->mccs_dimmnums[0] != -1) + mc_nvl_add_prop(*csp, mccs, MCAMD_PROP_LODIMM); + if (mccs->mccs_dimmnums[1] != -1) + mc_nvl_add_prop(*csp, mccs, MCAMD_PROP_UPDIMM); + } + + (void) nvlist_add_nvlist_array(mcnvl, "cslist", cslist, nelem); + for (i = 0; i < nelem; i++) + nvlist_free(cslist[i]); + + for (nelem = 0, mcd = mc->mc_props.mcp_dimmlist; mcd != NULL; + mcd = mcd->mcd_next, nelem++) { + nvlist_t **dimmp = &dimmlist[nelem]; + int ncs = 0; + uint64_t csnums[MC_CHIP_DIMMRANKMAX]; + + (void) nvlist_alloc(dimmp, NV_UNIQUE_NAME, KM_SLEEP); + + mc_nvl_add_prop(*dimmp, mcd, MCAMD_PROP_NUM); + + for (i = 0; i < MC_CHIP_DIMMRANKMAX; i++) { + if (mcd->mcd_cs[i] != NULL) + csnums[ncs++] = mcd->mcd_cs[i]->mccs_num; + } + + (void) nvlist_add_uint64_array(*dimmp, "csnums", csnums, ncs); + } + + (void) nvlist_add_nvlist_array(mcnvl, "dimmlist", dimmlist, nelem); + for (i = 0; i < nelem; i++) + nvlist_free(dimmlist[i]); + + return (mcnvl); +} + +static void +mc_dimm_csadd(mc_dimm_t *mcd, mc_cs_t *mccs) +{ + int i; + + for (i = 0; i < MC_CHIP_DIMMRANKMAX; i++) { + if (mcd->mcd_cs[i] == NULL) { + mcd->mcd_cs[i] = mccs; + break; + } + } + ASSERT(i != MC_CHIP_DIMMRANKMAX); +} + +static mc_dimm_t * +mc_dimm_create(mc_t *mc, mc_cs_t *mccs, uint_t num) +{ + mc_dimm_t *mcd = kmem_zalloc(sizeof (mc_dimm_t), KM_SLEEP); + + mcd->mcd_hdr.mch_type = MC_NT_DIMM; + mcd->mcd_mc = mc; + mcd->mcd_num = num; + mc_dimm_csadd(mcd, mccs); + + return (mcd); +} + +/* + * A chip-select is associated with up to 2 dimms, and a single dimm may + * have up to 4 associated chip-selects (in the presence of quad-rank support + * on the motherboard). How we number our dimms is determined by the MC + * config. This function may be called by multiple chip-selects for the + * same dimm(s). + */ +static void +mc_cs_dimmlist_create(mc_t *mc, mc_cs_t *mccs, uint_t *dimm_nums, int ndimm) +{ + mc_dimm_t *mcd; + mc_props_t *mcp = &mc->mc_props; + int i; + int nfound = 0; + + /* + * Has some other chip-select already created this dimm or dimms? + */ + for (mcd = mcp->mcp_dimmlist; mcd != NULL; mcd = mcd->mcd_next) { + for (i = 0; i < ndimm; i++) { + if (mcd->mcd_num == dimm_nums[i]) { + mccs->mccs_dimm[i] = mcd; + mccs->mccs_dimmnums[i] = mcd->mcd_num; + mc_dimm_csadd(mcd, mccs); + nfound++; + } + } + } + ASSERT(nfound == 0 || nfound == ndimm); + if (nfound == ndimm) + return; + + for (i = 0; i < ndimm; i++) { + mcd = mccs->mccs_dimm[i] = + mc_dimm_create(mc, mccs, dimm_nums[i]); + + mccs->mccs_dimmnums[i] = mcd->mcd_num; + + if (mcp->mcp_dimmlist == NULL) + mcp->mcp_dimmlist = mcd; + else + mcp->mcp_dimmlast->mcd_next = mcd; + mcp->mcp_dimmlast = mcd; + } + +} + +/* + * A placeholder for a future implementation that works this out from + * smbios or SPD information. For now we will return a value that + * can be tuned in /etc/system, and the default will cover current Sun systems. + */ +/*ARGSUSED*/ +static int +mc_config_quadranksupport(mc_t *mc) +{ + return (mc_quadranksupport != 0); +} + +/* + * Create the DIMM structure for this MC. There are a number of unkowns, + * such as the number of DIMM slots for this MC, the number of chip-select + * ranks supported for each DIMM, how the slots are labelled etc. + * + * SMBIOS information can help with some of this (if the bios implementation is + * complete and accurate, which is often not the case): + * + * . A record is required for each SMB_TYPE_MEMDEVICE slot, whether populated + * or not. The record should reference the associated SMB_TYPE_MEMARRAY, + * so we can figure out the number of slots for each MC. In practice some + * smbios implementations attribute all slots (from multiple chips) to + * a single memory array. + * + * . SMB_TYPE_MEMDEVICEMAP records indicate how a particular SMB_TYPE_MEMDEVICE + * has been mapped. Some smbios implementation produce rubbish here, or get + * confused when cs bank interleaving is enabled or disabled, but we can + * perform some validation of the information before using it. The record + * information is not well suited to handling cs bank interleaving since + * it really only provides for a device to have a few contiguos mappings + * and with cs interleave we have lots of little chunks interleaved across + * the devices. If we assume that the bios has followed the BKDG algorithm + * for setting up cs interleaving (which involves assinging contiguous + * and adjacent ranges to the chip selects and then swapping some + * base and mask hi and lo bits) then we can attempt to interpret the + * DEVICEMAP records as being the addresses prior to swapping address/mask + * bits to establish the interleave - that seems to cover at least some + * smbios implementations. Even if that assumption appears good it is + * also not clear which MEMDEVICE records correspond to LODIMMs and which + * to UPDIMMs in a DIMM pair (128 bit MC mode) - we have to interpret the + * Device Locator and Bank Locator labels. + * + * We also do not know how many chip-select banks reside on individual + * DIMMs. For instance we cannot distinguish a system that supports 8 + * DIMMs slots per chip (one CS line each, thereby supporting only single-rank + * DIMMs) vs a system that has just 4 slots per chip and which routes + * 2 CS lines to each pair (thereby supporting dual rank DIMMs). In each + * we would discover 8 active chip-selects. + * + * So the task of establishing the real DIMM configuration is complex, likely + * requiring some combination of good SMBIOS data and perhaps our own access + * to SPD information. Instead we opt for a canonical numbering scheme, + * derived from the 'AMD Athlon (TM) 64 FX and AMD Opteron (TM) Processors + * Motherboard Design Guide' (AMD publication #25180). + */ +static void +mc_dimmlist_create(mc_t *mc) +{ + int mcmode; + mc_cs_t *mccs; + int quadrank = mc_config_quadranksupport(mc); + uint_t dimm_nums[MC_CHIP_DIMMPERCS]; + int ldimmno; /* logical DIMM pair number, 0 .. 3 */ + + mcmode = mc->mc_props.mcp_dramcfg & MC_DC_DCFG_128 ? 128 : 64; + + for (mccs = mc->mc_cslist; mccs != NULL; mccs = mccs->mccs_next) { + if (quadrank) { + /* + * Quad-rank support. We assume that any of cs# + * 4/5/6/6 that we have discovered active are routed + * for quad rank support as described in the MB + * design guide: + * DIMM0: CS# 0, 1, 4 and 5 + * DIMM1: CS# 2, 3, 6 and 7 + */ + ldimmno = (mccs->mccs_num % 4) /2; + } else { + /* + * DIMM0: CS# 0 and 1 + * DIMM1: CS# 2 and 3 + * DIMM2: CS# 4 and 5 + * DIMM3: CS# 6 and 7 + */ + ldimmno = mccs->mccs_num / 2; + } + + if (mcmode == 128) { + /* 128-bit data width mode - dimms present in pairs */ + dimm_nums[0] = ldimmno * 2; /* LODIMM */ + dimm_nums[1] = ldimmno * 2 + 1; /* UPDIMM */ + } else { + /* 64-bit data width mode - only even numbered dimms */ + dimm_nums[0] = ldimmno * 2; /* LODIMM */ + } + mc_cs_dimmlist_create(mc, mccs, dimm_nums, + mcmode == 128 ? 2 : 1); + } +} + +static mc_cs_t * +mc_cs_create(mc_t *mc, uint_t num, uint64_t base, uint64_t mask, size_t sz) +{ + mc_cs_t *mccs = kmem_zalloc(sizeof (mc_cs_t), KM_SLEEP); + + mccs->mccs_hdr.mch_type = MC_NT_CS; + mccs->mccs_mc = mc; + mccs->mccs_num = num; + mccs->mccs_base = base; + mccs->mccs_mask = mask; + mccs->mccs_size = sz; + + return (mccs); +} + +/* + * Function 1 Configuration - Address Map (see BKDG 3.4.4 DRAM Address Map) + * + * Read the Function 1 Address Map for each potential DRAM node. The Base + * Address for a node gives the starting system address mapped at that node, + * and the limit gives the last valid address mapped at that node. Regions for + * different nodes should not overlap, unless node-interleaving is enabled. + * The base register also indicates the node-interleaving settings (IntlvEn). + * The limit register includes IntlvSel which determines which 4K blocks will + * be routed to this node and the destination node ID for addresses that fall + * within the [base, limit] range - this must match the pair number. + */ +static void +mc_mkprops_addrmap(ddi_acc_handle_t cfghdl, mc_t *mc) +{ + uint32_t base[MC_AM_REG_NODE_NUM], lim[MC_AM_REG_NODE_NUM]; + mc_props_t *mcp = &mc->mc_props; + int i; + + mc_prop_read_pair(cfghdl, base, MC_AM_REG_DRAMBASE_0, lim, + MC_AM_REG_DRAMLIM_0, MC_AM_REG_NODE_NUM, MC_AM_REG_DRAM_INCR); + + for (i = 0; i < MC_AM_REG_NODE_NUM; i++) { + /* + * Don't create properties for empty nodes. + */ + if ((lim[i] & MC_AM_DL_DRAMLIM_MASK) == 0) + continue; + + /* + * Don't create properties for DIMM ranges that aren't local + * to this node. + */ + if ((lim[i] & MC_AM_DL_DSTNODE_MASK) != mc->mc_chip->chip_id) + continue; + + mcp->mcp_base = MC_AM_DB_DRAMBASE(base[i]); + mcp->mcp_lim = MC_AM_DL_DRAMLIM(lim[i]); + mcp->mcp_ilen = (base[i] & MC_AM_DB_INTLVEN_MASK) >> + MC_AM_DB_INTLVEN_SHIFT; + mcp->mcp_ilsel = (lim[i] & MC_AM_DL_INTLVSEL_MASK) >> + MC_AM_DL_INTLVSEL_SHIFT; + } + + /* + * The Function 1 DRAM Hole Address Register tells us which node(s) + * own the DRAM space that is hoisted above 4GB, together with the + * hole base and offset for this node. + */ + mcp->mcp_dramhole = pci_config_get32(cfghdl, MC_AM_REG_HOLEADDR); +} + +/* + * Function 2 configuration - DRAM Controller + */ +static void +mc_mkprops_dramctl(ddi_acc_handle_t cfghdl, mc_t *mc) +{ + uint32_t base[MC_CHIP_NCS], mask[MC_CHIP_NCS]; + uint64_t dramcfg; + mc_props_t *mcp = &mc->mc_props; + int wide = 0; /* 128-bit access mode? */ + int i; + mcamd_hdl_t hdl; + + mcamd_mkhdl(&hdl); /* to call into common code */ + + /* + * Read Function 2 DRAM Configuration High and Low registers and + * weld them together into a 64-bit value. The High component + * is mostly concerned with memory clocks etc and we'll not have + * any use for that. The Low component tells us if ECC is enabled, + * if we're in 64- or 128-bit MC mode, how the upper chip-selects + * are mapped, which chip-select pairs are using x4 parts, etc. + */ + dramcfg = pci_config_get32(cfghdl, MC_DC_REG_DRAMCFGLO) | + ((uint64_t)pci_config_get32(cfghdl, MC_DC_REG_DRAMCFGHI) << 32); + wide = dramcfg & MC_DC_DCFG_128; + + mcp->mcp_dramcfg = dramcfg; + mcp->mcp_accwidth = wide ? 128 : 64; + + /* + * Read Function 2 DRAM Bank Address Mapping. This tells us + * whether bank swizzle mode is enabled, and also encodes + * the type of DIMM module in use for each chip-select pair. + */ + mcp->mcp_csbankmap = pci_config_get32(cfghdl, MC_DC_REG_BANKADDRMAP); + + /* + * Read Function 2 Configuration Registers for DRAM CS Base 0 thru 7 + * and DRAM CS Mask 0 thru 7. The Base registers give us the + * BaseAddrHi and BaseAddrLo from which the base can be constructed, + * and whether this chip-select bank is enabled (CSBE). The + * Mask registers give us AddrMaskHi and AddrMaskLo from which + * a full mask can be constructed. + */ + mc_prop_read_pair(cfghdl, base, MC_DC_REG_CSBASE_0, mask, + MC_DC_REG_CSMASK_0, MC_CHIP_NCS, MC_DC_REG_CS_INCR); + + /* + * Create a cs node for each enabled chip-select + */ + for (i = 0; i < MC_CHIP_NCS; i++) { + mc_cs_t *mccs; + uint64_t csmask; + size_t sz; + + if (!(base[i] & MC_DC_CSB_CSBE)) { + mcp->mcp_disabled_cs++; + continue; + } + + if (mcamd_cs_size(&hdl, (mcamd_node_t *)mc, i, &sz) < 0) + continue; + + csmask = MC_DC_CSM_CSMASK(mask[i]); + mccs = mc_cs_create(mc, i, MC_DC_CSB_CSBASE(base[i]), csmask, + sz); + + if (mc->mc_cslist == NULL) + mc->mc_cslist = mccs; + else + mc->mc_cslast->mccs_next = mccs; + mc->mc_cslast = mccs; + + /* + * Check for cs bank interleaving - some bits clear in the + * lower mask. All banks must/will have the same lomask bits + * if cs interleaving is active. + */ + if (!mcp->mcp_csbank_intlv) { + int bitno, ibits = 0; + for (bitno = MC_DC_CSM_MASKLO_LOBIT; + bitno <= MC_DC_CSM_MASKLO_HIBIT; bitno++) { + if (!(csmask & (1 << bitno))) + ibits++; + } + if (ibits > 0) + mcp->mcp_csbank_intlv = 1 << ibits; + } + } + + /* + * Now that we have discovered all active chip-selects we attempt + * to divine the associated DIMM configuration. + */ + mc_dimmlist_create(mc); +} + +typedef struct mc_bind_map { + const char *bm_bindnm; /* attachment binding name */ + uint_t bm_func; /* PCI config space function number for bind */ + const char *bm_model; /* value for device node model property */ + void (*bm_mkprops)(ddi_acc_handle_t, mc_t *); +} mc_bind_map_t; + +static const mc_bind_map_t mc_bind_map[] = { + { MC_FUNC_HTCONFIG_BINDNM, MC_FUNC_HTCONFIG, + "AMD Memory Controller (HT Configuration)", NULL }, + { MC_FUNC_ADDRMAP_BINDNM, MC_FUNC_ADDRMAP, + "AMD Memory Controller (Address Map)", mc_mkprops_addrmap }, + { MC_FUNC_DRAMCTL_BINDNM, MC_FUNC_DRAMCTL, + "AMD Memory Controller (DRAM Controller & HT Trace)", + mc_mkprops_dramctl }, + NULL +}; + +/*ARGSUSED*/ +static int +mc_open(dev_t *devp, int flag, int otyp, cred_t *credp) +{ + if (otyp != OTYP_CHR) + return (EINVAL); + + rw_enter(&mc_lock, RW_READER); + if (mc_lookup_by_chipid(getminor(*devp)) == NULL) { + rw_exit(&mc_lock); + return (EINVAL); + } + rw_exit(&mc_lock); + + return (0); +} + +/*ARGSUSED*/ +static int +mc_close(dev_t dev, int flag, int otyp, cred_t *credp) +{ + return (0); +} + +/*ARGSUSED*/ +static int +mc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) +{ + int rc = 0; + mc_t *mc; + + if (cmd != MC_IOC_SNAPSHOT_INFO && cmd != MC_IOC_SNAPSHOT) + return (EINVAL); + + rw_enter(&mc_lock, RW_READER); + + if ((mc = mc_lookup_by_chipid(getminor(dev))) == NULL) { + rw_exit(&mc_lock); + return (EINVAL); + } + + if (mc_snapshot_update(mc) < 0) { + rw_exit(&mc_lock); + return (EIO); + } + + switch (cmd) { + case MC_IOC_SNAPSHOT_INFO: { + mc_snapshot_info_t mcs; + + mcs.mcs_size = mc->mc_snapshotsz; + mcs.mcs_gen = mc->mc_snapshotgen; + + if (ddi_copyout(&mcs, (void *)arg, sizeof (mc_snapshot_info_t), + mode) < 0) + rc = EFAULT; + break; + } + + case MC_IOC_SNAPSHOT: + if (ddi_copyout(mc->mc_snapshot, (void *)arg, mc->mc_snapshotsz, + mode) < 0) + rc = EFAULT; + break; + } + + rw_exit(&mc_lock); + + return (rc); +} + +static struct cb_ops mc_cb_ops = { + mc_open, + mc_close, + nodev, /* not a block driver */ + nodev, /* no print routine */ + nodev, /* no dump routine */ + nodev, /* no read routine */ + nodev, /* no write routine */ + mc_ioctl, + nodev, /* no devmap routine */ + nodev, /* no mmap routine */ + nodev, /* no segmap routine */ + nochpoll, /* no chpoll routine */ + ddi_prop_op, + 0, /* not a STREAMS driver */ + D_NEW | D_MP, /* safe for multi-thread/multi-processor */ +}; + +/*ARGSUSED*/ +static int +mc_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) +{ + int rc = DDI_SUCCESS; + mc_t *mc; + + if (infocmd != DDI_INFO_DEVT2DEVINFO && + infocmd != DDI_INFO_DEVT2INSTANCE) { + *result = NULL; + return (DDI_FAILURE); + } + + rw_enter(&mc_lock, RW_READER); + + if ((mc = mc_lookup_by_chipid(getminor((dev_t)arg))) == NULL || + mc->mc_funcs[MC_FUNC_DEVIMAP].mcf_devi == NULL) { + rc = DDI_FAILURE; + } else if (infocmd == DDI_INFO_DEVT2DEVINFO) { + *result = mc->mc_funcs[MC_FUNC_DEVIMAP].mcf_devi; + } else { + *result = (void *)(uintptr_t) + mc->mc_funcs[MC_FUNC_DEVIMAP].mcf_instance; + } + + rw_exit(&mc_lock); + + return (rc); +} + +/*ARGSUSED2*/ +static int +mc_fm_handle(dev_info_t *dip, ddi_fm_error_t *fmerr, const void *arg) +{ + pci_ereport_post(dip, fmerr, NULL); + return (DDI_FM_NONFATAL); +} + +static void +mc_fm_init(dev_info_t *dip) +{ + int fmcap = DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE; + ddi_fm_init(dip, &fmcap, NULL); + pci_ereport_setup(dip); + ddi_fm_handler_register(dip, mc_fm_handle, NULL); +} + +static void +mc_fm_fini(dev_info_t *dip) +{ + pci_ereport_teardown(dip); + ddi_fm_fini(dip); +} + +static mc_t * +mc_create(chipid_t chipid) +{ + chip_t *chp = chip_lookup(chipid); + const mc_rev_map_t *rmp = mc_revision(chp); + mc_t *mc; + + ASSERT(RW_WRITE_HELD(&mc_lock)); + + if (chp == NULL || rmp->rm_rev == MC_REV_UNKNOWN) + return (NULL); + + mc = kmem_zalloc(sizeof (mc_t), KM_SLEEP); + mc->mc_hdr.mch_type = MC_NT_MC; + mc->mc_chip = chp; + mc->mc_props.mcp_rev = rmp->rm_rev; + mc->mc_revname = rmp->rm_name; + mc->mc_props.mcp_num = mc->mc_chip->chip_id; + + mc->mc_next = mc_list; + mc_list = mc; + + return (mc); +} + +static int +mc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) +{ + ddi_acc_handle_t hdl; + const mc_bind_map_t *bm; + const char *bindnm; + char *unitstr = NULL; + long unitaddr; + int chipid, func, rc; + cpu_t *cpu; + mc_t *mc; + + if (cmd != DDI_ATTACH) + return (DDI_FAILURE); + + bindnm = ddi_binding_name(dip); + for (bm = mc_bind_map; bm->bm_bindnm != NULL; bm++) { + if (strcmp(bindnm, bm->bm_bindnm) == 0) { + func = bm->bm_func; + break; + } + } + + if (bm->bm_bindnm == NULL) + return (DDI_FAILURE); + + /* + * We need the device number, which corresponds to the processor node + * number plus 24. The node number can then be used to associate this + * memory controller device with a given processor chip. + */ + (void) ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, + "unit-address", &unitstr); + rc = ddi_strtol(unitstr, NULL, 16, &unitaddr); + ASSERT(rc == 0 && unitaddr >= MC_AMD_DEV_OFFSET); + if (rc != 0 || unitaddr < MC_AMD_DEV_OFFSET) { + cmn_err(CE_WARN, "failed to parse unit address %s for %s\n", + unitstr, bindnm); + return (DDI_FAILURE); + } + + chipid = unitaddr - MC_AMD_DEV_OFFSET; + + rw_enter(&mc_lock, RW_WRITER); + + for (mc = mc_list; mc != NULL; mc = mc->mc_next) { + if (mc->mc_chip->chip_id == chipid) + break; + } + + /* Integrate this memory controller device into existing set */ + if (mc == NULL) { + mc = mc_create(chipid); + + if (mc == NULL) { + /* + * We don't complain here because this is a legitimate + * path for MP systems. On those machines, we'll attach + * before all CPUs have been initialized, and thus the + * chip verification in mc_create will fail. We'll be + * reattached later for those CPUs. + */ + rw_exit(&mc_lock); + return (DDI_FAILURE); + } + } else { + mc_snapshot_destroy(mc); + } + + /* Beyond this point, we're committed to creating this node */ + + mc_fm_init(dip); + + ASSERT(mc->mc_funcs[func].mcf_devi == NULL); + mc->mc_funcs[func].mcf_devi = dip; + mc->mc_funcs[func].mcf_instance = ddi_get_instance(dip); + + mc->mc_ref++; + + rw_downgrade(&mc_lock); + + /* + * Add the common properties to this node, and then add any properties + * that are specific to this node based upon its configuration space. + */ + (void) ddi_prop_update_string(DDI_DEV_T_NONE, + dip, "model", (char *)bm->bm_model); + + (void) ddi_prop_update_int(DDI_DEV_T_NONE, + dip, "chip-id", mc->mc_chip->chip_id); + + if (bm->bm_mkprops != NULL && + pci_config_setup(dip, &hdl) == DDI_SUCCESS) { + bm->bm_mkprops(hdl, mc); + pci_config_teardown(&hdl); + } + + /* + * If this is the last node to be attached for this memory controller, + * so create the minor node and set up the properties. + */ + if (func == MC_FUNC_DEVIMAP) { + mc_props_t *mcp = &mc->mc_props; + + if (ddi_create_minor_node(dip, "mc-amd", S_IFCHR, + mc->mc_chip->chip_id, "ddi_mem_ctrl", 0) != DDI_SUCCESS) { + cmn_err(CE_WARN, "failed to create minor node for chip " + "%u memory controller\n", mc->mc_chip->chip_id); + } + + /* + * Register the memory controller for every CPU of this chip. + * Then attempt to enable h/w memory scrubbers for this node. + * If we are successful, disable the software memory scrubber. + */ + mutex_enter(&cpu_lock); + + cpu = mc->mc_chip->chip_cpus; + rc = cmi_scrubber_enable(cpu, mcp->mcp_base, mcp->mcp_ilen); + + do { + mcamd_mc_register(cpu); + cpu = cpu->cpu_next_chip; + } while (cpu != mc->mc_chip->chip_cpus); + + mutex_exit(&cpu_lock); + + if (rc) + memscrub_disable(); + } + + nvlist_free(mc->mc_nvl); + mc->mc_nvl = mc_nvl_create(mc); + + rw_exit(&mc_lock); + return (DDI_SUCCESS); +} + +/*ARGSUSED*/ +static int +mc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +{ + return (DDI_FAILURE); +} + +static struct dev_ops mc_ops = { + DEVO_REV, /* devo_rev */ + 0, /* devo_refcnt */ + mc_getinfo, /* devo_getinfo */ + nulldev, /* devo_identify */ + nulldev, /* devo_probe */ + mc_attach, /* devo_attach */ + mc_detach, /* devo_detach */ + nodev, /* devo_reset */ + &mc_cb_ops, /* devo_cb_ops */ + NULL, /* devo_bus_ops */ + NULL /* devo_power */ +}; + +static struct modldrv modldrv = { + &mod_driverops, + "Memory Controller for AMD processors", + &mc_ops +}; + +static struct modlinkage modlinkage = { + MODREV_1, + (void *)&modldrv, + NULL +}; + +int +_init(void) +{ + rw_init(&mc_lock, NULL, RW_DRIVER, NULL); + return (mod_install(&modlinkage)); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + +int +_fini(void) +{ + int rc; + + if ((rc = mod_remove(&modlinkage)) != 0) + return (rc); + + rw_destroy(&mc_lock); + return (0); +} diff --git a/usr/src/uts/i86pc/io/mc/mcamd_off.in b/usr/src/uts/i86pc/io/mc/mcamd_off.in new file mode 100644 index 0000000000..8e6a8dbc5e --- /dev/null +++ b/usr/src/uts/i86pc/io/mc/mcamd_off.in @@ -0,0 +1,55 @@ +\ +\ CDDL HEADER START +\ +\ The contents of this file are subject to the terms of the +\ Common Development and Distribution License, Version 1.0 only +\ (the "License"). You may not use this file except in compliance +\ with the License. +\ +\ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +\ or http://www.opensolaris.org/os/licensing. +\ See the License for the specific language governing permissions +\ and limitations under the License. +\ +\ When distributing Covered Code, include this CDDL HEADER in each +\ file and include the License file at usr/src/OPENSOLARIS.LICENSE. +\ If applicable, add the following below this CDDL HEADER, with the +\ fields enclosed by brackets "[]" replaced with your own identifying +\ information: Portions Copyright [yyyy] [name of copyright owner] +\ +\ CDDL HEADER END +\ + +#pragma ident "%Z%%M% %I% %E% SMI" + +\ +\ Copyright 2006 Sun Microsystems, Inc. All rights reserved. +\ Use is subject to license terms. +\ + +#include <mcamd.h> + +mc_t + mc_props.mcp_num MCAMD_MC_OFF_NUM + mc_props.mcp_rev MCAMD_MC_OFF_REV + mc_props.mcp_base MCAMD_MC_OFF_BASE_ADDR + mc_props.mcp_lim MCAMD_MC_OFF_LIM_ADDR + mc_props.mcp_dramcfg MCAMD_MC_OFF_DRAMCFG + mc_props.mcp_dramhole MCAMD_MC_OFF_DRAMHOLE + mc_props.mcp_ilen MCAMD_MC_OFF_DRAM_ILEN + mc_props.mcp_ilsel MCAMD_MC_OFF_DRAM_ILSEL + mc_props.mcp_csbankmap MCAMD_MC_OFF_CSBANKMAP + mc_props.mcp_accwidth MCAMD_MC_OFF_ACCWIDTH + mc_props.mcp_csbank_intlv MCAMD_MC_OFF_CSBANK_INTLV + mc_props.mcp_disabled_cs MCAMD_MC_OFF_DISABLED_CS + +mc_cs_t + mccs_num MCAMD_CS_OFF_NUM + mccs_base MCAMD_CS_OFF_BASE_ADDR + mccs_mask MCAMD_CS_OFF_MASK + mccs_size MCAMD_CS_OFF_SIZE + mccs_dimmnums MCAMD_CS_OFF_DIMMNUMS + +mc_dimm_t + mcd_num MCAMD_DIMM_OFF_NUM + diff --git a/usr/src/uts/i86pc/io/mc/mcamd_subr.c b/usr/src/uts/i86pc/io/mc/mcamd_subr.c new file mode 100644 index 0000000000..4537de771b --- /dev/null +++ b/usr/src/uts/i86pc/io/mc/mcamd_subr.c @@ -0,0 +1,442 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Stub routines used to link in files from $SRC/common/mc + */ + +#include <sys/types.h> +#include <sys/cmn_err.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/varargs.h> +#include <sys/cpu_module_impl.h> +#include <sys/fm/protocol.h> +#include <sys/mc.h> + +#include <mcamd.h> +#include <mcamd_off.h> + +int mcamd_debug = 0; /* see mcamd_api.h for MCAMD_DBG_* values */ + +struct mc_propmap { + uint_t mcpm_code; + uint_t mcpm_offset; +}; + +static uint_t +nodetype(mcamd_node_t *node) +{ + mc_hdr_t *mch = (mc_hdr_t *)node; + return (mch->mch_type); +} + +static void * +node2type(mcamd_node_t *node, int type) +{ + mc_hdr_t *mch = (mc_hdr_t *)node; + ASSERT(mch->mch_type == type); + return (mch); +} + +/* + * Iterate over all memory controllers. + */ +/*ARGSUSED*/ +mcamd_node_t * +mcamd_mc_next(mcamd_hdl_t *hdl, mcamd_node_t *root, mcamd_node_t *last) +{ + mc_t *mc; + + ASSERT(RW_LOCK_HELD(&mc_lock)); + + if (last == NULL) + return ((mcamd_node_t *)mc_list); + + mc = node2type(last, MC_NT_MC); + + return ((mcamd_node_t *)mc->mc_next); +} + +/* + * Iterate over all chip-selects of a MC or all chip-selects of a DIMM + * depending on the node type of 'node'. In the DIMM case we do not + * have a linked list of associated chip-selects but an array of pointer + * to them. + */ +/*ARGSUSED*/ +mcamd_node_t * +mcamd_cs_next(mcamd_hdl_t *hdl, mcamd_node_t *node, mcamd_node_t *last) +{ + uint_t nt = nodetype(node); + mc_t *mc; + mc_cs_t *mccs; + mc_dimm_t *mcd; + int i; + void *retval; + + ASSERT(nt == MC_NT_MC || nt == MC_NT_DIMM); + + if (last == NULL) { + switch (nt) { + case MC_NT_MC: + mc = node2type(node, MC_NT_MC); + retval = mc->mc_cslist; + break; + case MC_NT_DIMM: + mcd = node2type(node, MC_NT_DIMM); + retval = mcd->mcd_cs[0]; + break; + } + } else { + mccs = node2type(last, MC_NT_CS); + + switch (nt) { + case MC_NT_MC: + retval = mccs->mccs_next; + break; + case MC_NT_DIMM: + mcd = node2type(node, MC_NT_DIMM); + for (i = 0; i < MC_CHIP_DIMMRANKMAX; i++) { + if (mcd->mcd_cs[i] == mccs) + break; + } + if (i == MC_CHIP_DIMMRANKMAX) + cmn_err(CE_PANIC, "Bad last value for " + "mcamd_cs_next"); + + if (i == MC_CHIP_DIMMRANKMAX - 1) + retval = NULL; + else + retval = mcd->mcd_cs[i + 1]; + break; + } + } + + return ((mcamd_node_t *)retval); +} + +/* + * Iterate over all DIMMs of an MC or all DIMMs of a chip-select depending + * on the node type of 'node'. In the chip-select case we don not have + * a linked list of associated DIMMs but an array of pointers to them. + */ +/*ARGSUSED*/ +mcamd_node_t * +mcamd_dimm_next(mcamd_hdl_t *hdl, mcamd_node_t *node, mcamd_node_t *last) +{ + uint_t nt = nodetype(node); + mc_t *mc; + mc_cs_t *mccs; + mc_dimm_t *mcd; + int i; + void *retval; + + ASSERT(nt == MC_NT_MC || nt == MC_NT_CS); + + if (last == NULL) { + switch (nt) { + case MC_NT_MC: + mc = node2type(node, MC_NT_MC); + retval = mc->mc_props.mcp_dimmlist; + break; + case MC_NT_CS: + mccs = node2type(node, MC_NT_CS); + retval = mccs->mccs_dimm[0]; + break; + } + } else { + mcd = node2type(last, MC_NT_DIMM); + + switch (nt) { + case MC_NT_MC: + retval = mcd->mcd_next; + break; + case MC_NT_CS: + mccs = node2type(node, MC_NT_CS); + for (i = 0; i < MC_CHIP_DIMMPERCS; i++) { + if (mccs->mccs_dimm[i] == mcd) + break; + } + if (i == MC_CHIP_DIMMPERCS) + cmn_err(CE_PANIC, "Bad last value for " + "mcamd_dimm_next"); + + if (i == MC_CHIP_DIMMPERCS - 1) + retval = NULL; + else + retval = mccs->mccs_dimm[i + 1]; + break; + } + } + + return ((mcamd_node_t *)retval); +} + +/*ARGSUSED*/ +mcamd_node_t * +mcamd_cs_mc(mcamd_hdl_t *hdl, mcamd_node_t *csnode) +{ + mc_cs_t *mccs = node2type(csnode, MC_NT_CS); + return ((mcamd_node_t *)mccs->mccs_mc); +} + +/*ARGSUSED*/ +mcamd_node_t * +mcamd_dimm_mc(mcamd_hdl_t *hdl, mcamd_node_t *dnode) +{ + mc_dimm_t *mcd = node2type(dnode, MC_NT_DIMM); + return ((mcamd_node_t *)mcd->mcd_mc); +} + +/* + * Node properties. A property is accessed through a property number code; + * we search these tables for a match (choosing table from node type) and + * return the uint64_t property at the indicated offset into the node + * structure. All properties must be of type uint64_t. It is assumed that + * property lookup does not have to be super-fast - we search linearly + * down the (small) lists. + */ +static const struct mc_propmap mcamd_mc_propmap[] = { + { MCAMD_PROP_NUM, MCAMD_MC_OFF_NUM }, + { MCAMD_PROP_REV, MCAMD_MC_OFF_REV }, + { MCAMD_PROP_BASE_ADDR, MCAMD_MC_OFF_BASE_ADDR }, + { MCAMD_PROP_LIM_ADDR, MCAMD_MC_OFF_LIM_ADDR }, + { MCAMD_PROP_DRAM_CONFIG, MCAMD_MC_OFF_DRAMCFG }, + { MCAMD_PROP_DRAM_HOLE, MCAMD_MC_OFF_DRAMHOLE }, + { MCAMD_PROP_DRAM_ILEN, MCAMD_MC_OFF_DRAM_ILEN }, + { MCAMD_PROP_DRAM_ILSEL, MCAMD_MC_OFF_DRAM_ILSEL }, + { MCAMD_PROP_CSBANKMAP, MCAMD_MC_OFF_CSBANKMAP }, + { MCAMD_PROP_ACCESS_WIDTH, MCAMD_MC_OFF_ACCWIDTH }, + { MCAMD_PROP_CSBANK_INTLV, MCAMD_MC_OFF_CSBANK_INTLV }, + { MCAMD_PROP_DISABLED_CS, MCAMD_MC_OFF_DISABLED_CS } +}; + +static const struct mc_propmap mcamd_cs_propmap[] = { + { MCAMD_PROP_NUM, MCAMD_CS_OFF_NUM }, + { MCAMD_PROP_BASE_ADDR, MCAMD_CS_OFF_BASE_ADDR }, + { MCAMD_PROP_MASK, MCAMD_CS_OFF_MASK }, + { MCAMD_PROP_SIZE, MCAMD_CS_OFF_SIZE }, + { MCAMD_PROP_LODIMM, MCAMD_CS_OFF_DIMMNUMS }, + { MCAMD_PROP_UPDIMM, MCAMD_CS_OFF_DIMMNUMS + + MCAMD_CS_OFF_DIMMNUMS_INCR } +}; + +static const struct mc_propmap mcamd_dimm_propmap[] = { + { MCAMD_PROP_NUM, MCAMD_DIMM_OFF_NUM }, +}; + +/*ARGSUSED*/ +int +mcamd_get_numprop(mcamd_hdl_t *hdl, mcamd_node_t *node, uint_t code, + uint64_t *valp) +{ + int i; + mc_hdr_t *mch = (mc_hdr_t *)node; + int nt = mch->mch_type; + int found = 0; + const struct mc_propmap *pmp; + struct mcamd_nt_props { + const struct mc_propmap *props; + int numprops; + } props[] = { + { mcamd_mc_propmap, /* MC_NT_MC */ + sizeof (mcamd_mc_propmap) / sizeof (struct mc_propmap) }, + { mcamd_cs_propmap, /* MC_NT_CS */ + sizeof (mcamd_cs_propmap) / sizeof (struct mc_propmap) }, + { mcamd_dimm_propmap, /* MC_NT_DIMM */ + sizeof (mcamd_dimm_propmap) / sizeof (struct mc_propmap) }, + }; + + if (mch->mch_type < MC_NT_NTYPES) { + for (i = 0, pmp = props[nt].props; i < props[nt].numprops; + i++, pmp++) { + if (pmp->mcpm_code == code) { + found = 1; + break; + } + } + } + + ASSERT(found); + if (found) { + *valp = *(uint64_t *)((uintptr_t)node + pmp->mcpm_offset); + } + + return (found == 1); +} + +int +mcamd_errno(mcamd_hdl_t *mcamd) +{ + return (mcamd->mcamd_errno); +} + +int +mcamd_set_errno(mcamd_hdl_t *mcamd, int err) +{ + mcamd->mcamd_errno = err; + return (-1); +} + +void +mcamd_dprintf(mcamd_hdl_t *mcamd, int mask, const char *fmt, ...) +{ + va_list ap; + + if (!(mcamd->mcamd_debug & mask)) + return; + + va_start(ap, fmt); + vcmn_err(mask & MCAMD_DBG_ERR ? CE_WARN : CE_NOTE, fmt, ap); + va_end(ap); +} + +void +mcamd_mkhdl(mcamd_hdl_t *hdl) +{ + hdl->mcamd_errno = 0; + hdl->mcamd_debug = mcamd_debug; +} + +/*ARGSUSED*/ +static int +mcamd_patounum_wrap(void *arg, uint64_t pa, uint32_t synd, int syndtype, + mc_unum_t *unump) +{ + mcamd_hdl_t mcamd; + int rc; + + mcamd_mkhdl(&mcamd); + + rw_enter(&mc_lock, RW_READER); + + rc = mcamd_patounum(&mcamd, + (mcamd_node_t *)mc_list, pa, synd, syndtype, unump); + +#ifdef DEBUG + /* + * Apply the reverse operation to verify the result. If there is + * a problem complain but continue. + */ + if (rc == 0 && MCAMD_RC_OFFSET_VALID(unump->unum_offset)) { + uint64_t rpa; + if (mcamd_unumtopa(&mcamd, (mcamd_node_t *)mc_list, unump, + &rpa) != 0 || rpa != pa) { + mcamd_dprintf(&mcamd, MCAMD_DBG_ERR, + "mcamd_patounum_wrap: offset calculation " + "verification for PA 0x%llx failed\n", pa); + } + } +#endif + rw_exit(&mc_lock); + + return (rc == 0); +} + +static int +fmri2unum(nvlist_t *nvl, mc_unum_t *unump) +{ + int i; + uint64_t offset; + nvlist_t *fu, **hcl; + uint_t npr; + + if (nvlist_lookup_nvlist(nvl, FM_FMRI_MEM_UNUM "-fmri", &fu) != 0 || + nvlist_lookup_uint64(nvl, FM_FMRI_MEM_OFFSET, &offset) != 0|| + nvlist_lookup_nvlist_array(fu, FM_FMRI_HC_LIST, &hcl, &npr) != 0) + return (0); + + + bzero(unump, sizeof (mc_unum_t)); + for (i = 0; i < MC_UNUM_NDIMM; i++) + unump->unum_dimms[i] = -1; + + for (i = 0; i < npr; i++) { + char *hcnm, *hcid; + long v; + + if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &hcnm) != 0 || + nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &hcid) != 0 || + ddi_strtol(hcid, NULL, 0, &v) != 0) + return (0); + + if (strcmp(hcnm, "motherboard") == 0) + unump->unum_board = (int)v; + else if (strcmp(hcnm, "chip") == 0) + unump->unum_chip = (int)v; + else if (strcmp(hcnm, "memory-controller") == 0) + unump->unum_mc = (int)v; + else if (strcmp(hcnm, "chip-select") == 0) + unump->unum_cs = (int)v; + else if (strcmp(hcnm, "dimm") == 0) + unump->unum_dimms[0] = (int)v; + } + + unump->unum_offset = offset; + + return (1); +} + +/*ARGSUSED*/ +static int +mcamd_unumtopa_wrap(void *arg, mc_unum_t *unump, nvlist_t *nvl, uint64_t *pap) +{ + mcamd_hdl_t mcamd; + int rc; + mc_unum_t unum; + + if (unump != NULL && nvl != NULL) + return (0); + + if (unump == NULL) { + if (!fmri2unum(nvl, &unum)) + return (0); + unump = &unum; + } + + mcamd_mkhdl(&mcamd); + + rw_enter(&mc_lock, RW_READER); + rc = mcamd_unumtopa(&mcamd, (mcamd_node_t *)mc_list, unump, pap); + rw_exit(&mc_lock); + + return (rc == 0); +} + +static const cmi_mc_ops_t mcamd_mc_ops = { + mcamd_patounum_wrap, + mcamd_unumtopa_wrap +}; + +void +mcamd_mc_register(cpu_t *cp) +{ + cmi_mc_register(cp, &mcamd_mc_ops, NULL); +} diff --git a/usr/src/uts/i86pc/io/rootnex.c b/usr/src/uts/i86pc/io/rootnex.c index 69789f49a7..741b405669 100644 --- a/usr/src/uts/i86pc/io/rootnex.c +++ b/usr/src/uts/i86pc/io/rootnex.c @@ -63,7 +63,6 @@ #include <sys/rootnex.h> #include <vm/hat_i86.h> - /* * enable/disable extra checking of function parameters. Useful for debugging * drivers. @@ -82,6 +81,9 @@ int rootnex_unbind_verify_buffer = 0; int rootnex_sync_check_parms = 0; #endif +/* Master Abort and Target Abort panic flag */ +int rootnex_fm_ma_ta_panic_flag = 0; + /* Semi-temporary patchables to phase in bug fixes, test drivers, etc. */ int rootnex_bind_fail = 1; int rootnex_bind_warn = 1; @@ -321,6 +323,8 @@ static int rootnex_maxxfer_window_boundary(ddi_dma_impl_t *hp, static int rootnex_valid_sync_parms(ddi_dma_impl_t *hp, rootnex_window_t *win, off_t offset, size_t size, uint_t cache_flags); static int rootnex_verify_buffer(rootnex_dma_t *dma); +static int rootnex_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr, + const void *no_used); /* @@ -365,6 +369,7 @@ _fini(void) static int rootnex_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { + int fmcap; int e; @@ -385,12 +390,24 @@ rootnex_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) rootnex_state = kmem_zalloc(sizeof (rootnex_state_t), KM_SLEEP); rootnex_state->r_dip = dip; + rootnex_state->r_err_ibc = (ddi_iblock_cookie_t)ipltospl(15); rootnex_state->r_reserved_msg_printed = B_FALSE; rootnex_cnt = &rootnex_state->r_counters[0]; mutex_init(&rootnex_state->r_peekpoke_mutex, NULL, MUTEX_SPIN, (void *)ipltospl(15)); + /* + * Set minimum fm capability level for i86pc platforms and then + * initialize error handling. Since we're the rootnex, we don't + * care what's returned in the fmcap field. + */ + ddi_system_fmcap = DDI_FM_ERRCB_CAPABLE; + fmcap = ddi_system_fmcap; + ddi_fm_init(dip, &fmcap, &rootnex_state->r_err_ibc); + if (fmcap & DDI_FM_ERRCB_CAPABLE) + ddi_fm_handler_register(dip, rootnex_fm_callback, NULL); + /* initialize DMA related state */ e = rootnex_dma_init(); if (e != DDI_SUCCESS) { @@ -4407,3 +4424,10 @@ rootnex_dma_mctl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle, return (DDI_FAILURE); #endif /* defined(__amd64) */ } + +/*ARGSUSED*/ +static int +rootnex_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *no_used) +{ + return (rootnex_fm_ma_ta_panic_flag ? DDI_FM_FATAL : DDI_FM_NONFATAL); +} diff --git a/usr/src/uts/i86pc/mc-amd/Makefile b/usr/src/uts/i86pc/mc-amd/Makefile new file mode 100644 index 0000000000..d7c876fa41 --- /dev/null +++ b/usr/src/uts/i86pc/mc-amd/Makefile @@ -0,0 +1,97 @@ +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = mc-amd +# +OBJECTS = $(MCAMD_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(MCAMD_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_PSM_DRV_DIR)/$(MODULE) +SRCDIR = $(UTSBASE)/i86pc/io/mc +CONF_SRCDIR = $(UTSBASE)/i86pc/io/mc + +MCAMD_OFF_H = $(OBJS_DIR)/mcamd_off.h +MCAMD_OFF_SRC = $(SRCDIR)/mcamd_off.in + +# +# Include common rules. +# +include ../cpu/Makefile.cpu + +# +# Define targets +# +ALL_TARGET = $(BINARY) $(SRC_CONFFILE) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) + +# +# Overrides and additions +# +CPPFLAGS += -I$(SRCDIR) -I$(OBJS_DIR) -I$(SRC)/common/mc/mc-amd +CLEANFILES += $(MCAMD_OFF_H) +CLOBBERFILES += $(MCAMD_OFF_H) + +$(OBJECTS): $(MCAMD_OFF_H) + +# +# Create mcamd_off.h +# +$(MCAMD_OFF_H): $(MCAMD_OFF_SRC) + $(OFFSETS_CREATE) <$(MCAMD_OFF_SRC) >$@ + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +# +# Include common targets. +# +include ../Makefile.targ diff --git a/usr/src/uts/i86pc/os/cmi.c b/usr/src/uts/i86pc/os/cmi.c new file mode 100644 index 0000000000..236b3c44a8 --- /dev/null +++ b/usr/src/uts/i86pc/os/cmi.c @@ -0,0 +1,299 @@ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Public interface to routines implemented by CPU modules + */ + +#include <sys/x86_archext.h> +#include <sys/cpu_module_impl.h> +#include <sys/fm/util.h> +#include <sys/reboot.h> +#include <sys/modctl.h> +#include <sys/param.h> +#include <sys/cmn_err.h> +#include <sys/systm.h> +#include <sys/types.h> + +#define CPUMOD_SUBDIR "cpu" +#define CPUMOD_PREFIX "cpu" + +#define CMI_OPS(cpu) \ + (cpu)->cpu_m.mcpu_cmi->cmi_ops +#define CMI_DATA(cpu) \ + (cpu)->cpu_m.mcpu_cmidata + +/* + * If cleared for debugging, we will suppress panicking on fatal hardware + * errors. This should *only* be used for debugging; it use can and will + * cause data corruption if actual hardware errors are detected by the system. + */ +int cmi_panic_on_uncorrectable_error = 1; + +static cmi_t *cmi_list; +static kmutex_t cmi_load_lock; + +static int +cmi_cpu_match(cpu_t *c1, cpu_t *c2) +{ + return (cpuid_getfamily(c1) == cpuid_getfamily(c2) && + cpuid_getmodel(c1) == cpuid_getmodel(c2) && + cpuid_getstep(c1) == cpuid_getstep(c2) && + strcmp(cpuid_getvendorstr(c1), cpuid_getvendorstr(c2)) == 0); +} + +static cmi_t * +cmi_load_modctl(modctl_t *modp) +{ + uintptr_t ops; + cmi_t *cmi; + + ASSERT(MUTEX_HELD(&cmi_load_lock)); + + for (cmi = cmi_list; cmi != NULL; cmi = cmi->cmi_next) { + if (cmi->cmi_modp == modp) + return (cmi); + } + + if ((ops = modlookup_by_modctl(modp, "_cmi_ops")) == NULL) { + cmn_err(CE_WARN, "CPU module %s is invalid: no _cmi_ops " + "found\n", modp->mod_modname); + return (NULL); + } + + /* + * Hold the module in memory. We call to CPU modules without using the + * stubs mechanism, so these modules must be manually held in memory. + * The mod_ref acts as if another loaded module has a dependency on us. + */ + mutex_enter(&mod_lock); + modp->mod_ref++; + mutex_exit(&mod_lock); + + cmi = kmem_zalloc(sizeof (cmi_t), KM_SLEEP); + cmi->cmi_ops = (const cmi_ops_t *)ops; + cmi->cmi_modp = modp; + + cmi->cmi_next = cmi_list; + cmi_list = cmi; + + return (cmi); +} + +static cmi_t * +cmi_load_module(cpu_t *cp) +{ + modctl_t *modp; + cmi_t *cmi; + int i, modid; + uint_t s[3]; + + /* + * Look to see if we've already got a module loaded for a CPU just + * like this one. If we do, then we'll re-use it. + */ + ASSERT(MUTEX_HELD(&cmi_load_lock)); + mutex_enter(&cpu_lock); + + for (i = 0; i < NCPU; i++) { + cpu_t *cp2 = cpu[i]; + + if (cp2 != NULL && cp2 != cp && + cp2->cpu_m.mcpu_cmi != NULL && cmi_cpu_match(cp, cp2)) { + mutex_exit(&cpu_lock); + return (cp2->cpu_m.mcpu_cmi); + } + } + + mutex_exit(&cpu_lock); + + /* + * If we can't find a match, attempt to load the appropriate module. + * If that also fails, try to load the generic CPU module. + */ + s[0] = cpuid_getfamily(cp); + s[1] = cpuid_getmodel(cp); + s[2] = cpuid_getstep(cp); + + modid = modload_qualified(CPUMOD_SUBDIR, CPUMOD_PREFIX, + cpuid_getvendorstr(cp), ".", s, sizeof (s) / sizeof (s[0])); + + if (modid == -1) + modid = modload(CPUMOD_SUBDIR, CPUMOD_PREFIX ".generic"); + + if (modid == -1) + return (NULL); + + modp = mod_hold_by_id(modid); + cmi = cmi_load_modctl(modp); + mod_release_mod(modp); + + return (cmi); +} + +static cmi_t * +cmi_load_generic(void) +{ + modctl_t *modp; + cmi_t *cmi; + int modid; + + if ((modid = modload(CPUMOD_SUBDIR, CPUMOD_PREFIX ".generic")) == -1) + return (NULL); + + modp = mod_hold_by_id(modid); + cmi = cmi_load_modctl(modp); + mod_release_mod(modp); + + return (cmi); +} + +/* + * Load a CPU module for the specified CPU, and then call its cmi_init routine. + * If the module returns ENOTSUP, try using the generic CPU module instead. + * If all else fails, we return -1 and the caller will panic or halt. + */ +int +cmi_load(cpu_t *cp) +{ + int err = ENOENT; + cmi_t *cmi; + void *data; + + mutex_enter(&cmi_load_lock); + + if ((cmi = cmi_load_module(cp)) == NULL || ( + (err = cmi->cmi_ops->cmi_init(cp, &data)) != 0 && err != ENOTSUP)) { + cmn_err(CE_WARN, "CPU module %s failed to init CPU %d: err=%d", + cmi ? cmi->cmi_modp->mod_modname : "<>", cp->cpu_id, err); + mutex_exit(&cmi_load_lock); + return (-1); + } + + if (err != 0 && ((cmi = cmi_load_generic()) == NULL || + (err = cmi->cmi_ops->cmi_init(cp, &data)) != 0)) { + cmn_err(CE_WARN, "CPU module %s failed to init CPU %d: err=%d", + cmi ? cmi->cmi_modp->mod_modname : "<>", cp->cpu_id, err); + mutex_exit(&cmi_load_lock); + return (-1); + } + + ASSERT(cp->cpu_m.mcpu_cmi == NULL); + cp->cpu_m.mcpu_cmi = cmi; + cp->cpu_m.mcpu_cmidata = data; + + cmi->cmi_refcnt++; + mutex_exit(&cmi_load_lock); + + if (boothowto & RB_VERBOSE) { + printf("cpuid %d: initialized cpumod: %s\n", + cp->cpu_id, cmi->cmi_modp->mod_modname); + } + + return (0); +} + +void +cmi_init(void) +{ + if (cmi_load(CPU) < 0) + panic("failed to load module for CPU %u", CPU->cpu_id); +} + +void +cmi_post_init(void) +{ + CMI_OPS(CPU)->cmi_post_init(CMI_DATA(CPU)); +} + +void +cmi_faulted_enter(cpu_t *cp) +{ + CMI_OPS(cp)->cmi_faulted_enter(CMI_DATA(cp)); +} + +void +cmi_faulted_exit(cpu_t *cp) +{ + CMI_OPS(cp)->cmi_faulted_exit(CMI_DATA(cp)); +} + +int +cmi_scrubber_enable(cpu_t *cp, uint64_t base, uint64_t ilen) +{ + return (CMI_OPS(cp)->cmi_scrubber_enable(CMI_DATA(cp), base, ilen)); +} + +void +cmi_mca_init(void) +{ + CMI_OPS(CPU)->cmi_mca_init(CMI_DATA(CPU)); +} + +void +cmi_mca_trap(struct regs *rp) +{ + if (CMI_OPS(CPU)->cmi_mca_trap(CMI_DATA(CPU), rp)) { + if (cmi_panic_on_uncorrectable_error) + fm_panic("Unrecoverable Machine-Check Exception"); + else + cmn_err(CE_WARN, "suppressing panic from fatal #mc"); + } +} + +int +cmi_mca_inject(cmi_mca_regs_t *regs, uint_t nregs) +{ + int err; + + kpreempt_disable(); + err = CMI_OPS(CPU)->cmi_mca_inject(CMI_DATA(CPU), regs, nregs); + kpreempt_enable(); + + return (err); +} + +void +cmi_mca_poke(void) +{ + CMI_OPS(CPU)->cmi_mca_poke(CMI_DATA(CPU)); +} + +void +cmi_mc_register(cpu_t *cp, const cmi_mc_ops_t *mcops, void *mcdata) +{ + CMI_OPS(cp)->cmi_mc_register(CMI_DATA(cp), mcops, mcdata); +} + +int +cmi_mc_patounum(uint64_t pa, uint32_t synd, int syndtype, mc_unum_t *up) +{ + const struct cmi_mc_ops *mcops; + cpu_t *cp = CPU; + + if (CMI_OPS(cp) == NULL || + (mcops = CMI_OPS(cp)->cmi_mc_getops(CMI_DATA(cp))) == NULL) + return (-1); /* not registered yet */ + + return (mcops->cmi_mc_patounum(CMI_DATA(cp), pa, synd, syndtype, up)); +} + +int +cmi_mc_unumtopa(mc_unum_t *up, nvlist_t *nvl, uint64_t *pap) +{ + const struct cmi_mc_ops *mcops; + cpu_t *cp = CPU; + + if (up != NULL && nvl != NULL) + return (-1); /* only convert from one or the other form */ + + if (CMI_OPS(cp) == NULL || + (mcops = CMI_OPS(cp)->cmi_mc_getops(CMI_DATA(cp))) == NULL) + return (-1); /* not registered yet */ + + return (mcops->cmi_mc_unumtopa(CMI_DATA(cp), up, nvl, pap)); +} diff --git a/usr/src/uts/i86pc/os/cpuid.c b/usr/src/uts/i86pc/os/cpuid.c index a16c5a6298..739700125a 100644 --- a/usr/src/uts/i86pc/os/cpuid.c +++ b/usr/src/uts/i86pc/os/cpuid.c @@ -2628,9 +2628,12 @@ add_cpunode2devtree(processorid_t cpu_id, struct cpuid_info *cpi) "chunks", CPI_CHUNKS(cpi)); (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, "apic-id", CPI_APIC_ID(cpi)); - if (cpi->cpi_chipid >= 0) + if (cpi->cpi_chipid >= 0) { (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, "chip#", cpi->cpi_chipid); + (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, + "clog#", cpi->cpi_clogid); + } } /* cpuid-features */ diff --git a/usr/src/uts/i86pc/os/memscrub.c b/usr/src/uts/i86pc/os/memscrub.c index 6dd21e302f..2e73a2a694 100644 --- a/usr/src/uts/i86pc/os/memscrub.c +++ b/usr/src/uts/i86pc/os/memscrub.c @@ -19,8 +19,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -129,6 +130,7 @@ static void *memscrub_pte; * we can patch these defaults in /etc/system if necessary */ uint_t disable_memscrub = 0; +static uint_t disable_memscrub_quietly = 0; pgcnt_t memscrub_min_pages = MEMSCRUB_MIN_PAGES; pgcnt_t memscrub_span_pages = MEMSCRUB_DFL_SPAN_PAGES; time_t memscrub_period_sec = MEMSCRUB_DFL_PERIOD_SEC; @@ -150,6 +152,7 @@ static uint_t memscrub_phys_pages; static kcondvar_t memscrub_cv; static kmutex_t memscrub_lock; + /* * memscrub_lock protects memscrub_memlist */ @@ -199,6 +202,16 @@ memscrub_init() TS_RUN, memscrub_thread_pri); } +/* + * Function to cause the software memscrubber to exit quietly if the + * platform support has located a hardware scrubber and enabled it. + */ +void +memscrub_disable(void) +{ + disable_memscrub_quietly = 1; +} + #ifdef MEMSCRUB_DEBUG void memscrub_printmemlist(char *title, struct memlist *listp) @@ -267,7 +280,7 @@ memscrubber() deadline = gethrestime_sec() + memscrub_delay_start_sec; for (;;) { - if (disable_memscrub) + if (disable_memscrub || disable_memscrub_quietly) break; mutex_enter(&memscrub_lock); @@ -317,7 +330,7 @@ memscrubber() pgcnt_t pages = memscrub_span_pages; uint64_t address = mlp_next_addr; - if (disable_memscrub) + if (disable_memscrub || disable_memscrub_quietly) break; mutex_enter(&memscrub_lock); @@ -379,7 +392,8 @@ memscrubber() memscrub_exit: - cmn_err(CE_NOTE, "memory scrubber exiting."); + if (!disable_memscrub_quietly) + cmn_err(CE_NOTE, "memory scrubber exiting."); cv_destroy(&memscrub_cv); diff --git a/usr/src/uts/i86pc/os/mp_startup.c b/usr/src/uts/i86pc/os/mp_startup.c index f98a787266..a0809d99fe 100644 --- a/usr/src/uts/i86pc/os/mp_startup.c +++ b/usr/src/uts/i86pc/os/mp_startup.c @@ -64,6 +64,7 @@ #include <vm/hat_i86.h> #include <sys/memnode.h> #include <sys/pci_cfgspace.h> +#include <sys/cpu_module.h> struct cpu cpus[1]; /* CPU data */ struct cpu *cpu[NCPU] = {&cpus[0]}; /* pointers to all CPUs */ @@ -1024,11 +1025,6 @@ mp_startup(void) */ if (x86_feature & X86_MTRR) mtrr_sync(); - /* - * Enable machine check architecture - */ - if (x86_feature & X86_MCA) - setup_mca(); /* * Initialize this CPU's syscall handlers @@ -1102,6 +1098,18 @@ mp_startup(void) (void) spl0(); /* enable interrupts */ + /* + * Set up the CPU module for this CPU. This can't be done before + * this CPU is made CPU_READY, because we may (in heterogeneous systems) + * need to go load another CPU module. The act of attempting to load + * a module may trigger a cross-call, which will ASSERT unless this + * cpu is CPU_READY. + */ + cmi_init(); + + if (x86_feature & X86_MCA) + cmi_mca_init(); + if (boothowto & RB_DEBUG) kdi_dvec_cpu_init(cp); @@ -1238,15 +1246,17 @@ mp_unmap_warm_reset_vector(ushort_t *warm_reset_vector) psm_unmap_phys((caddr_t)warm_reset_vector, sizeof (ushort_t *)); } -/*ARGSUSED*/ void mp_cpu_faulted_enter(struct cpu *cp) -{} +{ + cmi_faulted_enter(cp); +} -/*ARGSUSED*/ void mp_cpu_faulted_exit(struct cpu *cp) -{} +{ + cmi_faulted_exit(cp); +} /* * The following two routines are used as context operators on threads belonging diff --git a/usr/src/uts/i86pc/os/startup.c b/usr/src/uts/i86pc/os/startup.c index 091fb331e3..1766aa0d81 100644 --- a/usr/src/uts/i86pc/os/startup.c +++ b/usr/src/uts/i86pc/os/startup.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -123,6 +123,7 @@ #include <sys/cpc_impl.h> #include <sys/chip.h> #include <sys/x86_archext.h> +#include <sys/cpu_module.h> #include <sys/smbios.h> extern void progressbar_init(void); @@ -1289,11 +1290,6 @@ startup_modules(void) mod_setup(); /* - * Setup machine check architecture on P6 - */ - setup_mca(); - - /* * Initialize system parameters. */ param_init(); @@ -1337,6 +1333,19 @@ startup_modules(void) * then invoke bus specific code to probe devices. */ setup_ddi(); + + /* + * Set up the CPU module subsystem. Modifies the device tree, so it + * must be done after setup_ddi(). + */ + cmi_init(); + + /* + * Initialize the MCA handlers + */ + if (x86_feature & X86_MCA) + cmi_mca_init(); + /* * Fake a prom tree such that /dev/openprom continues to work */ @@ -1879,6 +1888,11 @@ post_startup(void) memscrub_init(); /* + * Complete CPU module initialization + */ + cmi_post_init(); + + /* * Perform forceloading tasks for /etc/system. */ (void) mod_sysctl(SYS_FORCELOAD, NULL); @@ -2379,86 +2393,6 @@ uint64_t mtrrdef, pat_attr_reg; */ int enable_relaxed_mtrr = 0; -/* - * These must serve for Pentium, Pentium Pro (P6/Pentium II/Pentium III) - * and Pentium 4, and yes, they are named 0, 1, 2, 4, 3 in ascending - * address order (starting from 0x400). The Pentium 4 only implements - * 4 sets, and while they are named 0-3 in the doc, the corresponding - * names for P6 are 0,1,2,4. So define these arrays in address order - * so that they work for both pre-Pentium4 and Pentium 4 processors. - */ - -static uint_t mci_ctl[] = {REG_MC0_CTL, REG_MC1_CTL, REG_MC2_CTL, - REG_MC4_CTL, REG_MC3_CTL}; -static uint_t mci_status[] = {REG_MC0_STATUS, REG_MC1_STATUS, REG_MC2_STATUS, - REG_MC4_STATUS, REG_MC3_STATUS}; -static uint_t mci_addr[] = {REG_MC0_ADDR, REG_MC1_ADDR, REG_MC2_ADDR, - REG_MC4_ADDR, REG_MC3_ADDR}; -static int mca_cnt; - - -void -setup_mca() -{ - int i; - uint64_t mca_cap; - - if (!(x86_feature & X86_MCA)) - return; - mca_cap = rdmsr(REG_MCG_CAP); - if (mca_cap & MCG_CAP_CTL_P) - wrmsr(REG_MCG_CTL, -1ULL); /* all ones */ - mca_cnt = mca_cap & MCG_CAP_COUNT_MASK; - if (mca_cnt > P6_MCG_CAP_COUNT) - mca_cnt = P6_MCG_CAP_COUNT; - for (i = 1; i < mca_cnt; i++) - wrmsr(mci_ctl[i], -1ULL); /* all ones */ - for (i = 0; i < mca_cnt; i++) - wrmsr(mci_status[i], 0ULL); - setcr4(getcr4() | CR4_MCE); - -} - -int -mca_exception(struct regs *rp) -{ - uint64_t status, addr; - int i, ret = 1, errcode, mserrcode; - - status = rdmsr(REG_MCG_STATUS); - if (status & MCG_STATUS_RIPV) - ret = 0; - if (status & MCG_STATUS_EIPV) - cmn_err(CE_WARN, "MCE at 0x%lx", rp->r_pc); - wrmsr(REG_MCG_STATUS, 0ULL); - for (i = 0; i < mca_cnt; i++) { - status = rdmsr(mci_status[i]); - /* - * If status register not valid skip this bank - */ - if (!(status & MCI_STATUS_VAL)) - continue; - errcode = status & MCI_STATUS_ERRCODE; - mserrcode = (status >> MSERRCODE_SHFT) & MCI_STATUS_ERRCODE; - if (status & MCI_STATUS_ADDRV) { - /* - * If mci_addr contains the address where - * error occurred, display the address - */ - addr = rdmsr(mci_addr[i]); - cmn_err(CE_WARN, "MCE: Bank %d: error code 0x%x:"\ - "addr = 0x%" PRIx64 ", model errcode = 0x%x", i, - errcode, addr, mserrcode); - } else { - cmn_err(CE_WARN, - "MCE: Bank %d: error code 0x%x, mserrcode = 0x%x", - i, errcode, mserrcode); - } - wrmsr(mci_status[i], 0ULL); - } - return (ret); -} - void setup_mtrr() { diff --git a/usr/src/uts/i86pc/os/trap.c b/usr/src/uts/i86pc/os/trap.c index da416edeea..37a38b9a80 100644 --- a/usr/src/uts/i86pc/os/trap.c +++ b/usr/src/uts/i86pc/os/trap.c @@ -497,15 +497,6 @@ trap(struct regs *rp, caddr_t addr, processorid_t cpuid) } switch (type) { - - case T_MCE: /* Machine check exception */ - case T_MCE + USER: - if (x86_feature & X86_MCA) { - if (mca_exception(rp)) - (void) die(type, rp, addr, cpuid); - type &= ~USER; - goto cleanup; - } default: if (type & USER) { if (tudebug) diff --git a/usr/src/uts/i86pc/sys/cpu_module.h b/usr/src/uts/i86pc/sys/cpu_module.h new file mode 100644 index 0000000000..8bd9c488a7 --- /dev/null +++ b/usr/src/uts/i86pc/sys/cpu_module.h @@ -0,0 +1,69 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_CPU_MODULE_H +#define _SYS_CPU_MODULE_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/cpuvar.h> +#include <sys/nvpair.h> +#include <sys/mc.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct regs; +struct cmi_mc_ops; + +typedef struct cmi_mca_regs { + uint_t cmr_msrnum; + uint64_t cmr_msrval; +} cmi_mca_regs_t; + +extern void cmi_init(void); +extern void cmi_post_init(void); + +extern void cmi_faulted_enter(struct cpu *); +extern void cmi_faulted_exit(struct cpu *); +extern int cmi_scrubber_enable(struct cpu *, uint64_t, uint64_t); + +extern void cmi_mca_init(void); +extern int cmi_mca_inject(cmi_mca_regs_t *, uint_t); +extern void cmi_mca_poke(void); + +extern void cmi_mc_register(struct cpu *, const struct cmi_mc_ops *, void *); +extern int cmi_mc_patounum(uint64_t, uint32_t, int, mc_unum_t *); +extern int cmi_mc_unumtopa(mc_unum_t *, nvlist_t *, uint64_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_CPU_MODULE_H */ diff --git a/usr/src/uts/i86pc/sys/cpu_module_impl.h b/usr/src/uts/i86pc/sys/cpu_module_impl.h new file mode 100644 index 0000000000..7bdd6de7ce --- /dev/null +++ b/usr/src/uts/i86pc/sys/cpu_module_impl.h @@ -0,0 +1,74 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_CPU_MODULE_IMPL_H +#define _SYS_CPU_MODULE_IMPL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/cpu_module.h> +#include <sys/cpuvar.h> +#include <sys/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct cmi_mc_ops { + int (*cmi_mc_patounum)(void *, uint64_t, uint32_t, int, mc_unum_t *); + int (*cmi_mc_unumtopa)(void *, mc_unum_t *, nvlist_t *, uint64_t *); +} cmi_mc_ops_t; + +typedef struct cmi_ops { + int (*cmi_init)(cpu_t *, void **); + void (*cmi_post_init)(void *); + void (*cmi_fini)(void *); + void (*cmi_faulted_enter)(void *); + void (*cmi_faulted_exit)(void *); + int (*cmi_scrubber_enable)(void *, uint64_t, uint64_t); + void (*cmi_mca_init)(void *); + int (*cmi_mca_trap)(void *, struct regs *); + int (*cmi_mca_inject)(void *, cmi_mca_regs_t *, uint_t); + void (*cmi_mca_poke)(void *); + void (*cmi_mc_register)(void *, const cmi_mc_ops_t *, void *); + const struct cmi_mc_ops *(*cmi_mc_getops)(void *); +} cmi_ops_t; + +typedef struct cmi { + struct cmi *cmi_next; + const cmi_ops_t *cmi_ops; + struct modctl *cmi_modp; + uint_t cmi_refcnt; +} cmi_t; + +extern int cmi_panic_on_uncorrectable_error; + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_CPU_MODULE_IMPL_H */ diff --git a/usr/src/uts/i86pc/sys/machcpuvar.h b/usr/src/uts/i86pc/sys/machcpuvar.h index 9e355d4b49..f339b97951 100644 --- a/usr/src/uts/i86pc/sys/machcpuvar.h +++ b/usr/src/uts/i86pc/sys/machcpuvar.h @@ -52,7 +52,8 @@ extern "C" { */ typedef void *cpu_pri_lev_t; -struct cpuid_info; /* (deliberately not visible here) */ +struct cpuid_info; +struct cmi; struct machcpu { /* define all the x_call stuff */ @@ -91,6 +92,8 @@ struct machcpu { uint64_t pil_high_start[HIGH_LEVELS]; uint64_t intrstat[PIL_MAX + 1][2]; struct cpuid_info *mcpu_cpi; + struct cmi *mcpu_cmi; /* CPU module state */ + void *mcpu_cmidata; #if defined(__amd64) greg_t mcpu_rtmp_rsp; /* syscall: temporary %rsp stash */ greg_t mcpu_rtmp_r15; /* syscall: temporary %r15 stash */ diff --git a/usr/src/uts/i86pc/sys/machsystm.h b/usr/src/uts/i86pc/sys/machsystm.h index 0732c4fde2..8dc5c5414b 100644 --- a/usr/src/uts/i86pc/sys/machsystm.h +++ b/usr/src/uts/i86pc/sys/machsystm.h @@ -86,7 +86,9 @@ extern void get_system_configuration(void); extern void mmu_init(void); extern int cpuid2nodeid(int); extern void map_kaddr(caddr_t, pfn_t, int, int); + extern void memscrub_init(void); +extern void memscrub_disable(void); extern unsigned int microdata; extern int use_mp; diff --git a/usr/src/uts/i86pc/sys/rootnex.h b/usr/src/uts/i86pc/sys/rootnex.h index 4236730776..96600248eb 100644 --- a/usr/src/uts/i86pc/sys/rootnex.h +++ b/usr/src/uts/i86pc/sys/rootnex.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -325,14 +325,15 @@ typedef enum { * r_counters - profile/performance counters */ typedef struct rootnex_state_s { - uint_t r_prealloc_cookies; - uint_t r_prealloc_size; - kmem_cache_t *r_dmahdl_cache; - uintptr_t r_dvma_call_list_id; - kmutex_t r_peekpoke_mutex; - dev_info_t *r_dip; - boolean_t r_reserved_msg_printed; - uint64_t r_counters[ROOTNEX_CNT_LAST]; + uint_t r_prealloc_cookies; + uint_t r_prealloc_size; + kmem_cache_t *r_dmahdl_cache; + uintptr_t r_dvma_call_list_id; + kmutex_t r_peekpoke_mutex; + dev_info_t *r_dip; + ddi_iblock_cookie_t r_err_ibc; + boolean_t r_reserved_msg_printed; + uint64_t r_counters[ROOTNEX_CNT_LAST]; } rootnex_state_t; diff --git a/usr/src/uts/i86pc/vm/hat_kdi.c b/usr/src/uts/i86pc/vm/hat_kdi.c index 61d26bb28f..acdc2ddbb9 100644 --- a/usr/src/uts/i86pc/vm/hat_kdi.c +++ b/usr/src/uts/i86pc/vm/hat_kdi.c @@ -19,8 +19,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -32,6 +33,7 @@ * operations may be performed. */ +#include <sys/cpuvar.h> #include <sys/kdi_impl.h> #include <sys/errno.h> #include <sys/systm.h> diff --git a/usr/src/uts/intel/ia32/ml/exception.s b/usr/src/uts/intel/ia32/ml/exception.s index fce42f797b..5886ab532c 100644 --- a/usr/src/uts/intel/ia32/ml/exception.s +++ b/usr/src/uts/intel/ia32/ml/exception.s @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -943,14 +943,47 @@ check_for_user_address: /* * #MC */ + .globl cmi_mca_trap /* see uts/i86pc/os/cmi.c */ + +#if defined(__amd64) + ENTRY_NP(mcetrap) TRAP_NOERR(T_MCE) /* $18 */ -#if defined(__amd64) SET_CPU_GSBASE -#endif - jmp cmninttrap + INTR_PUSH + + TRACE_PTR(%rdi, %rbx, %ebx, %rcx, $TT_TRAP) + TRACE_REGS(%rdi, %rsp, %rbx, %rcx) + TRACE_STAMP(%rdi) + + DISABLE_INTR_FLAGS + movq %rsp, %rbp + + movq %rsp, %rdi /* arg0 = struct regs *rp */ + call cmi_mca_trap /* cmi_mca_trap(rp); */ + + jmp _sys_rtt SET_SIZE(mcetrap) +#else + + ENTRY_NP(mcetrap) + TRAP_NOERR(T_MCE) /* $18 */ + INTR_PUSH + + DISABLE_INTR_FLAGS + movl %esp, %ebp + + movl %esp, %ecx + pushl %ecx /* arg0 = struct regs *rp */ + call cmi_mca_trap /* cmi_mca_trap(rp) */ + addl $4, %esp /* pop arg0 */ + + jmp _sys_rtt + SET_SIZE(mcetrap) + +#endif + /* * #XF */ diff --git a/usr/src/uts/intel/ia32/ml/i86_subr.s b/usr/src/uts/intel/ia32/ml/i86_subr.s index 4c75164e50..5a164b1088 100644 --- a/usr/src/uts/intel/ia32/ml/i86_subr.s +++ b/usr/src/uts/intel/ia32/ml/i86_subr.s @@ -1999,23 +1999,43 @@ repoutsd(int port, uint32_t *addr, int count) #endif /* __lint */ /* + * void int3(void) + * void int18(void) * void int20(void) */ #if defined(__lint) void +int3(void) +{} + +void +int18(void) +{} + +void int20(void) {} #else /* __lint */ + ENTRY(int3) + int $T_BPTFLT + ret + SET_SIZE(int3) + + ENTRY(int18) + int $T_MCE + ret + SET_SIZE(int18) + ENTRY(int20) movl boothowto, %eax andl $RB_DEBUG, %eax jz 1f - int $20 + int $T_DBGENTR 1: rep; ret /* use 2 byte return instruction when branch target */ /* AMD Software Optimization Guide - Section 6.2 */ diff --git a/usr/src/uts/intel/ia32/sys/trap.h b/usr/src/uts/intel/ia32/sys/trap.h index 44a22bcd51..9eafa6b197 100644 --- a/usr/src/uts/intel/ia32/sys/trap.h +++ b/usr/src/uts/intel/ia32/sys/trap.h @@ -24,7 +24,7 @@ /* All Rights Reserved */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -58,7 +58,7 @@ extern "C" { #define T_PGFLT 0xe /* #pf page fault */ #define T_EXTERRFLT 0x10 /* #mf x87 FPU error fault */ #define T_ALIGNMENT 0x11 /* #ac alignment check error */ -#define T_MCE 0x12 /* #mc machine check exception (P6 only) */ +#define T_MCE 0x12 /* #mc machine check exception */ #define T_SIMDFPE 0x13 /* #xm SSE/SSE exception */ #define T_DBGENTR 0x14 /* debugger entry */ #define T_ENDPERR 0x21 /* emulated extension error flt */ diff --git a/usr/src/uts/intel/mm/Makefile b/usr/src/uts/intel/mm/Makefile index 729ed50b4d..8efea6da29 100644 --- a/usr/src/uts/intel/mm/Makefile +++ b/usr/src/uts/intel/mm/Makefile @@ -22,7 +22,7 @@ # # uts/intel/mm/Makefile # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #pragma ident "%Z%%M% %I% %E% SMI" @@ -51,6 +51,8 @@ CONF_SRCDIR = $(UTSBASE)/common/io # include $(UTSBASE)/intel/Makefile.intel +CPPFLAGS += -I$(UTSBASE)/i86pc + # # Define targets # diff --git a/usr/src/uts/intel/os/driver_aliases b/usr/src/uts/intel/os/driver_aliases index d5b27e5095..0e95977131 100644 --- a/usr/src/uts/intel/os/driver_aliases +++ b/usr/src/uts/intel/os/driver_aliases @@ -26,3 +26,5 @@ mpt "pci1000,50" mpt "pci1000,56" mpt "pci1000,58" ibd "ib.ipib" +mc-amd "pci1022,1101" +mc-amd "pci1022,1102" diff --git a/usr/src/uts/intel/os/name_to_major b/usr/src/uts/intel/os/name_to_major index 72b3a3ab6f..6ee2d75b26 100644 --- a/usr/src/uts/intel/os/name_to_major +++ b/usr/src/uts/intel/os/name_to_major @@ -119,4 +119,5 @@ zfs 182 npe 183 pcie_pci 184 kssl 185 +mc-amd 186 did 239 diff --git a/usr/src/uts/intel/sys/Makefile b/usr/src/uts/intel/sys/Makefile index 31cb0ddb03..de2867be84 100644 --- a/usr/src/uts/intel/sys/Makefile +++ b/usr/src/uts/intel/sys/Makefile @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -55,6 +55,11 @@ HDRS = \ machlock.h \ machsig.h \ machtypes.h \ + mc.h \ + mc_amd.h \ + mca_amd.h \ + mca_x86.h \ + memtest.h \ mii.h \ miipriv.h \ mmu.h \ diff --git a/usr/src/uts/intel/sys/archsystm.h b/usr/src/uts/intel/sys/archsystm.h index 76c33e8c05..5ed70f0cb2 100644 --- a/usr/src/uts/intel/sys/archsystm.h +++ b/usr/src/uts/intel/sys/archsystm.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -60,6 +60,8 @@ extern void tenmicrosec(void); extern void restore_int_flag(int); extern int clear_int_flag(void); +extern void int3(void); +extern void int18(void); extern void int20(void); #if defined(__amd64) diff --git a/usr/src/uts/intel/sys/controlregs.h b/usr/src/uts/intel/sys/controlregs.h index b0001c62be..5863b0c201 100644 --- a/usr/src/uts/intel/sys/controlregs.h +++ b/usr/src/uts/intel/sys/controlregs.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -145,7 +145,8 @@ extern "C" { #define MSR_AMD_HWCR 0xc0010015 -#define AMD_HWCR_FFDIS 0x40 /* set to disable TLB Flush Filter */ +#define AMD_HWCR_FFDIS 0x00040 /* disable TLB Flush Filter */ +#define AMD_HWCR_MCI_STATUS_WREN 0x40000 /* enable write of MCi_STATUS */ /* AMD's NorthBridge Config MSR, SHOULD ONLY BE WRITTEN TO BY BIOS */ diff --git a/usr/src/uts/intel/sys/fm/cpu/AMD.h b/usr/src/uts/intel/sys/fm/cpu/AMD.h new file mode 100644 index 0000000000..bb7aa427e5 --- /dev/null +++ b/usr/src/uts/intel/sys/fm/cpu/AMD.h @@ -0,0 +1,223 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_FM_CPU_AMD_H +#define _SYS_FM_CPU_AMD_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Ereport class subcategory for AMD processors */ +#define FM_EREPORT_CPU_AMD "amd" + +/* + * Ereport payload definitions + */ +#define FM_EREPORT_PAYLOAD_NAME_BANK_STAT "bank-status" +#define FM_EREPORT_PAYLOAD_NAME_BANK_NUM "bank-number" +#define FM_EREPORT_PAYLOAD_NAME_ADDR "addr" +#define FM_EREPORT_PAYLOAD_NAME_ADDR_VALID "addr-valid" +#define FM_EREPORT_PAYLOAD_NAME_SYND "syndrome" +#define FM_EREPORT_PAYLOAD_NAME_SYND_TYPE "syndrome-type" +#define FM_EREPORT_PAYLOAD_NAME_IP "ip" +#define FM_EREPORT_PAYLOAD_NAME_PRIV "privileged" +#define FM_EREPORT_PAYLOAD_NAME_RESOURCE "resource" + +#define FM_EREPORT_PAYLOAD_FLAG_BANK_STAT 0x0000000000000001 +#define FM_EREPORT_PAYLOAD_FLAG_BANK_NUM 0x0000000000000002 +#define FM_EREPORT_PAYLOAD_FLAG_ADDR 0x0000000000000004 +#define FM_EREPORT_PAYLOAD_FLAG_ADDR_VALID 0x0000000000000008 +#define FM_EREPORT_PAYLOAD_FLAG_SYND 0x0000000000000010 +#define FM_EREPORT_PAYLOAD_FLAG_SYND_TYPE 0x0000000000000020 +#define FM_EREPORT_PAYLOAD_FLAG_IP 0x0000000000000040 +#define FM_EREPORT_PAYLOAD_FLAG_PRIV 0x0000000000000080 +#define FM_EREPORT_PAYLOAD_FLAG_RESOURCE 0x0000000000000100 +#define FM_EREPORT_PAYLOAD_FLAG_STACK 0x0000000000000200 + +#define FM_EREPORT_PAYLOAD_FLAGS_BANK \ + (FM_EREPORT_PAYLOAD_FLAG_BANK_STAT | FM_EREPORT_PAYLOAD_FLAG_BANK_NUM) +#define FM_EREPORT_PAYLOAD_FLAGS_ADDR \ + (FM_EREPORT_PAYLOAD_FLAG_ADDR | FM_EREPORT_PAYLOAD_FLAG_ADDR_VALID) +#define FM_EREPORT_PAYLOAD_FLAGS_SYND \ + (FM_EREPORT_PAYLOAD_FLAG_SYND | FM_EREPORT_PAYLOAD_FLAG_SYND_TYPE) +#define FM_EREPORT_PAYLOAD_FLAGS_RESOURCE \ + (FM_EREPORT_PAYLOAD_FLAG_RESOURCE) +#define FM_EREPORT_PAYLOAD_FLAGS_COMMON \ + (FM_EREPORT_PAYLOAD_FLAGS_BANK | FM_EREPORT_PAYLOAD_FLAG_IP | \ + FM_EREPORT_PAYLOAD_FLAG_PRIV) +#define FM_EREPORT_PAYLOAD_FLAGS_NB \ + (FM_EREPORT_PAYLOAD_FLAG_STACK) + +#define FM_EREPORT_PAYLOAD_FLAGS_1(f1) \ + (FM_EREPORT_PAYLOAD_FLAGS_COMMON | FM_EREPORT_PAYLOAD_FLAGS_##f1) +#define FM_EREPORT_PAYLOAD_FLAGS_2(f1, f2) \ + (FM_EREPORT_PAYLOAD_FLAGS_COMMON | FM_EREPORT_PAYLOAD_FLAGS_##f1 | \ + FM_EREPORT_PAYLOAD_FLAGS_##f2) +#define FM_EREPORT_PAYLOAD_FLAGS_3(f1, f2, f3) \ + (FM_EREPORT_PAYLOAD_FLAGS_COMMON | FM_EREPORT_PAYLOAD_FLAGS_##f1 | \ + FM_EREPORT_PAYLOAD_FLAGS_##f2 | FM_EREPORT_PAYLOAD_FLAGS_##f3) + +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_INF_SYS_ECC1 \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_INF_L2_ECC1 \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_INF_SYS_ECCM \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_INF_L2_ECCM \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_DATA_ECC1 \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_DATA_ECC1_UC \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_DATA_ECCM \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_TAG_PAR \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_STAG_PAR \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_L1TLB_PAR \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_L2TLB_PAR \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) + +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_INF_SYS_ECC1 \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_INF_L2_ECC1 \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_INF_SYS_ECCM \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_INF_L2_ECCM \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_DATA_PAR \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_TAG_PAR \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_STAG_PAR \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_L1TLB_PAR \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_L2TLB_PAR \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_RDDE \ + FM_EREPORT_PAYLOAD_FLAGS_COMMON + +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_BU_L2D_ECC1 \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_BU_L2D_ECCM \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_BU_L2T_PAR \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_BU_L2T_ECC1 \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_BU_L2T_ECCM \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_BU_S_RDE \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_BU_S_ECC1 \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_BU_S_ECCM \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND) + +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_LS_S_RDE \ + FM_EREPORT_PAYLOAD_FLAGS_COMMON + +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_NB_MEM_CE \ + FM_EREPORT_PAYLOAD_FLAGS_3(ADDR, SYND, RESOURCE) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_NB_MEM_UE \ + FM_EREPORT_PAYLOAD_FLAGS_3(ADDR, SYND, RESOURCE) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_NB_HT_CRC \ + FM_EREPORT_PAYLOAD_FLAGS_COMMON +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_NB_HT_SYNC \ + FM_EREPORT_PAYLOAD_FLAGS_COMMON +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_NB_MA \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, NB) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_NB_TA \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, NB) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_NB_GART_WALK \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_NB_RMW \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_NB_WDOG \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) + +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_UNKNOWN \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) + +#define FM_EREPORT_CPU_AMD_DC_INF_SYS_ECC1 "dc.inf_sys_ecc1" +#define FM_EREPORT_CPU_AMD_DC_INF_SYS_ECCM "dc.inf_sys_eccm" +#define FM_EREPORT_CPU_AMD_DC_INF_L2_ECC1 "dc.inf_l2_ecc1" +#define FM_EREPORT_CPU_AMD_DC_INF_L2_ECCM "dc.inf_l2_eccm" +#define FM_EREPORT_CPU_AMD_DC_DATA_ECC1 "dc.data_ecc1" +#define FM_EREPORT_CPU_AMD_DC_DATA_ECC1_UC "dc.data_ecc1_uc" +#define FM_EREPORT_CPU_AMD_DC_DATA_ECCM "dc.data_eccm" +#define FM_EREPORT_CPU_AMD_DC_TAG_PAR "dc.tag_par" +#define FM_EREPORT_CPU_AMD_DC_STAG_PAR "dc.stag_par" +#define FM_EREPORT_CPU_AMD_DC_L1TLB_PAR "dc.l1tlb_par" +#define FM_EREPORT_CPU_AMD_DC_L2TLB_PAR "dc.l2tlb_par" + +#define FM_EREPORT_CPU_AMD_IC_INF_SYS_ECC1 "ic.inf_sys_ecc1" +#define FM_EREPORT_CPU_AMD_IC_INF_SYS_ECCM "ic.inf_sys_eccm" +#define FM_EREPORT_CPU_AMD_IC_INF_L2_ECC1 "ic.inf_l2_ecc1" +#define FM_EREPORT_CPU_AMD_IC_INF_L2_ECCM "ic.inf_l2_eccm" +#define FM_EREPORT_CPU_AMD_IC_DATA_PAR "ic.data_par" +#define FM_EREPORT_CPU_AMD_IC_TAG_PAR "ic.tag_par" +#define FM_EREPORT_CPU_AMD_IC_STAG_PAR "ic.stag_par" +#define FM_EREPORT_CPU_AMD_IC_L1TLB_PAR "ic.l1tlb_par" +#define FM_EREPORT_CPU_AMD_IC_L2TLB_PAR "ic.l2tlb_par" +#define FM_EREPORT_CPU_AMD_IC_RDDE "ic.rdde" + +#define FM_EREPORT_CPU_AMD_BU_L2D_ECC1 "bu.l2d_ecc1" +#define FM_EREPORT_CPU_AMD_BU_L2D_ECCM "bu.l2d_eccm" +#define FM_EREPORT_CPU_AMD_BU_L2T_PAR "bu.l2t_par" +#define FM_EREPORT_CPU_AMD_BU_L2T_ECC1 "bu.l2t_ecc1" +#define FM_EREPORT_CPU_AMD_BU_L2T_ECCM "bu.l2t_eccm" +#define FM_EREPORT_CPU_AMD_BU_S_RDE "bu.s_rde" +#define FM_EREPORT_CPU_AMD_BU_S_ECC1 "bu.s_ecc1" +#define FM_EREPORT_CPU_AMD_BU_S_ECCM "bu.s_eccm" + +#define FM_EREPORT_CPU_AMD_LS_S_RDE "ls.s_rde" + +#define FM_EREPORT_CPU_AMD_NB_MEM_CE "nb.mem_ce" +#define FM_EREPORT_CPU_AMD_NB_MEM_UE "nb.mem_ue" +#define FM_EREPORT_CPU_AMD_NB_HT_CRC "nb.ht_crc" +#define FM_EREPORT_CPU_AMD_NB_HT_SYNC "nb.ht_sync" +#define FM_EREPORT_CPU_AMD_NB_MA "nb.ma" +#define FM_EREPORT_CPU_AMD_NB_TA "nb.ta" +#define FM_EREPORT_CPU_AMD_NB_GART_WALK "nb.gart_walk" +#define FM_EREPORT_CPU_AMD_NB_RMW "nb.rmw" +#define FM_EREPORT_CPU_AMD_NB_WDOG "nb.wdog" + +#define FM_EREPORT_CPU_AMD_UNKNOWN "unknown" + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_FM_CPU_AMD_H */ diff --git a/usr/src/uts/intel/sys/mc.h b/usr/src/uts/intel/sys/mc.h new file mode 100644 index 0000000000..416f323c86 --- /dev/null +++ b/usr/src/uts/intel/sys/mc.h @@ -0,0 +1,80 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_MC_H +#define _SYS_MC_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Public interfaces exposed by the memory controller driver + */ + +#include <sys/cpuvar.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define MC_UNUM_NAMLEN 192 +#define MC_UNUM_NDIMM 8 + +typedef struct mc_unum { + int unum_board; + int unum_chip; + int unum_mc; + int unum_cs; + uint64_t unum_offset; + int unum_dimms[MC_UNUM_NDIMM]; +} mc_unum_t; + +#define MC_AMD_DEV_OFFSET 24 /* node ID + offset == PCI dev num */ + +#define MC_IOC (0x4d43 << 16) +#define MC_IOC_SNAPSHOT_INFO (MC_IOC | 1) +#define MC_IOC_SNAPSHOT (MC_IOC | 2) + +/* + * Prior to requesting a copy of the snapshot, consumers are advised to request + * information regarding the snapshot. An mc_snapshot_info_t will be returned, + * containing the snapshot size as well as the snapshot generation number. Note + * that, due to the potentially dynamic nature of the system, the snapshot may + * change at any time. As such, the information in the mc_snapshot_info_t may + * be out of date by the time it is used. The generation number is used to + * track snapshot changes. That is, the generation number will be updated each + * time the source data for the snapshot is updated. The consumer should not + * attach any meaning to the magnitude of a generation number change, and pay + * attention only to the fact that the number has changed. + */ +typedef struct mc_snapshot_info { + uint32_t mcs_size; /* snapshot size */ + uint_t mcs_gen; /* snapshot generation number */ +} mc_snapshot_info_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_MC_H */ diff --git a/usr/src/uts/intel/sys/mc_amd.h b/usr/src/uts/intel/sys/mc_amd.h new file mode 100644 index 0000000000..fba266b14f --- /dev/null +++ b/usr/src/uts/intel/sys/mc_amd.h @@ -0,0 +1,195 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _MC_AMD_H +#define _MC_AMD_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Definitions describing various memory controller constant properties and + * the structure of configuration registers. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Configuration constants + */ +#define MC_CHIP_NDIMM 8 /* max dimms per MC */ +#define MC_CHIP_NCS 8 /* number of chip-selects per MC */ +#define MC_CHIP_DIMMRANKMAX 4 /* largest number of ranks per dimm */ +#define MC_CHIP_DIMMPERCS 2 /* max number of dimms per cs */ +#define MC_CHIP_DIMMPAIR(csnum) (csnum / MC_CHIP_DIMMPERCS) + +/* + * Encoding of chip version variations that we need to distinguish + */ +#define MC_REV_UNKNOWN -1u /* unknown AMD revision */ +#define MC_REV_PRE_D 0 /* B/C/CG */ +#define MC_REV_D_E 1 /* D or E */ +#define MC_REV_F 2 /* F */ + +/* + * BKDG 3.29 section 3.4.4.1 - DRAM base i registers + */ +#define MC_AM_DB_DRAMBASE_MASK 0xffff0000 +#define MC_AM_DB_DRAMBASE_LSHFT 8 +#define MC_AM_DB_DRAMBASE(regval) \ + (((uint64_t)(regval) & MC_AM_DB_DRAMBASE_MASK) << \ + MC_AM_DB_DRAMBASE_LSHFT) +#define MC_AM_DB_INTLVEN_MASK 0x00000700 +#define MC_AM_DB_INTLVEN_SHIFT 8 +#define MC_AM_DB_WE 0x00000002 +#define MC_AM_DB_RE 0x00000001 + +/* + * BKDG 3.29 section 3.4.4.2 - DRAM limit i registers + */ +#define MC_AM_DL_DRAMLIM_MASK 0xffff0000 +#define MC_AM_DL_DRAMLIM_SHIFT 16 +#define MC_AM_DL_DRAMLIM_LSHFT 8 +#define MC_AM_DL_DRAMLIM(regval) \ + ((((uint64_t)(regval) & MC_AM_DL_DRAMLIM_MASK) << \ + MC_AM_DL_DRAMLIM_LSHFT) | ((regval) ? \ + ((1 << (MC_AM_DL_DRAMLIM_SHIFT + MC_AM_DL_DRAMLIM_LSHFT)) - 1) : 0)) +#define MC_AM_DL_INTLVSEL_MASK 0x00000700 +#define MC_AM_DL_INTLVSEL_SHIFT 8 +#define MC_AM_DL_DSTNODE_MASK 0x00000007 + +/* + * BKDG 3.29 section 3.5.4 - DRAM CS Base Address Registers. + * + * MC_DC_CSB_CSBASE combines the BaseAddrHi and BaseAddrLo into a single + * uint64_t, shifting them into the dram address bits they describe. + */ +#define MC_DC_CSB_BASEHI_MASK 0xffe00000 +#define MC_DC_CSB_BASEHI_LSHFT 4 + +#define MC_DC_CSB_BASELO_MASK 0x0000fe00 +#define MC_DC_CSB_BASELO_LSHFT 4 + +#define MC_DC_CSB_CSBASE(regval) \ + ((((uint64_t)(regval) & MC_DC_CSB_BASEHI_MASK) << \ + MC_DC_CSB_BASEHI_LSHFT) | (((uint64_t)(regval) & \ + MC_DC_CSB_BASELO_MASK) << MC_DC_CSB_BASELO_LSHFT)) + +#define MC_DC_CSB_CSBE 0x00000001 + +/* + * BKDG 3.29 section 3.5.5 - DRAM CS Mask Registers. + * + * MC_DC_CSM_CSMASK combines the AddrMaskHi and AddrMaskLo into a single + * uint64_t, shifting them into the dram address bit positions they mask. + * It also fills the gaps between high and low mask and below the low mask. + * MC_DC_CSM_UNMASKED_BITS indicates the number of high dram address bits + * above MC_DC_CSM_MASKHI_HIBIT that cannot be masked. + */ +#define MC_DC_CSM_MASKHI_MASK 0x3fe00000 +#define MC_DC_CSM_MASKHI_LSHFT 4 +#define MC_DC_CSM_MASKHI_LOBIT 25 +#define MC_DC_CSM_MASKHI_HIBIT 33 + +#define MC_DC_CSM_MASKLO_MASK 0x0000fe00 +#define MC_DC_CSM_MASKLO_LOBIT 13 +#define MC_DC_CSM_MASKLO_HIBIT 19 +#define MC_DC_CSM_MASKLO_LSHFT 4 + +#define MC_DC_CSM_MASKFILL 0x1f01fff /* [24:20] and [12:0] */ + +#define MC_DC_CSM_UNMASKED_BITS 2 + +#define MC_DC_CSM_CSMASK(regval) \ + ((((uint64_t)(regval) & MC_DC_CSM_MASKHI_MASK) << \ + MC_DC_CSM_MASKHI_LSHFT) | (((uint64_t)(regval) & \ + MC_DC_CSM_MASKLO_MASK) << MC_DC_CSM_MASKLO_LSHFT) | \ + MC_DC_CSM_MASKFILL) + +/* + * BKDG 3.29 section 3.5.6 - DRAM Bank Address Mapping Register + */ +#define MC_DC_BAM_CSBANK_MASK 0x0000000f +#define MC_DC_BAM_CSBANK_SHIFT 4 +#define MC_DC_BAM_CSBANK_SWIZZLE 0x40000000 + +/* + * BKDG 3.29 section 3.4.8 - DRAM Hole register, revs E and later + */ +#define MC_DC_HOLE_VALID 0x00000001 +#define MC_DC_HOLE_OFFSET_MASK 0x0000ff00 +#define MC_DC_HOLE_OFFSET_LSHIFT 16 + +/* + * BKDG 3.29 section 3.5.11 - DRAM configuration high and low registers. + * The following defines may be applied to a uint64_t made by + * concatenating those two 32-bit registers. + */ +#define MC_DC_DCFG_DLL_DIS 0x0000000000000001 +#define MC_DC_DCFG_D_DRV 0x0000000000000002 +#define MC_DC_DCFG_QFC_EN 0x0000000000000004 +#define MC_DC_DCFG_DISDQSYS 0x0000000000000008 +#define MC_DC_DCFG_BURST2OPT 0x0000000000000020 +#define MC_DC_DCFG_MOD64BITMUX 0x0000000000000040 +#define MC_DC_DCFG_PWRDWNTRIEN 0x0000000000000080 /* >= rev E */ +#define MC_DC_DCFG_SCRATCHBIT 0x0000000000000080 /* <= rev D */ +#define MC_DC_DCFG_DRAMINIT 0x0000000000000100 +#define MC_DC_DCFG_DUALDIMMEN 0x0000000000000200 +#define MC_DC_DCFG_DRAMENABLE 0x0000000000000400 +#define MC_DC_DCFG_MEMCLRSTATUS 0x0000000000000800 +#define MC_DC_DCFG_ESR 0x0000000000001000 +#define MC_DC_DCFG_SR_S 0x0000000000002000 +#define MC_DC_DCFG_RDWRQBYP_MASK 0x000000000000c000 +#define MC_DC_DCFG_128 0x0000000000010000 +#define MC_DC_DCFG_DIMMECEN 0x0000000000020000 +#define MC_DC_DCFG_UNBUFFDIMM 0x0000000000040000 +#define MC_DC_DCFG_32BYTEEN 0x0000000000080000 +#define MC_DC_DCFG_X4DIMMS_MASK 0x0000000000f00000 +#define MC_DC_DCFG_X4DIMMS_SHIFT 20 +#define MC_DC_DCFG_DISINRCVRS 0x0000000001000000 +#define MC_DC_DCFG_BYPMAX_MASK 0x000000000e000000 +#define MC_DC_DCFG_EN2T 0x0000000010000000 +#define MC_DC_DCFG_UPPERCSMAP 0x0000000020000000 +#define MC_DC_DCFG_PWRDOWNCTL_MASK 0x00000000c0000000 +#define MC_DC_DCFG_ASYNCLAT_MASK 0x0000000f00000000 +#define MC_DC_DCFG_RDPREAMBLE_MASK 0x00000f0000000000 +#define MC_DC_DCFG_MEMDQDRVSTREN_MASK 0x0000600000000000 +#define MC_DC_DCFG_DISABLEJITTER 0x0000800000000000 +#define MC_DC_DCFG_ILD_LMT_MASK 0x0007000000000000 +#define MC_DC_DCFG_ECC_EN 0x0008000000000000 +#define MC_DC_DCFG_MEMCLK_MASK 0x0070000000000000 +#define MC_DC_DCFG_MCR 0x0200000000000000 +#define MC_DC_DCFG_MC0_EN 0x0400000000000000 +#define MC_DC_DCFG_MC1_EN 0x0800000000000000 +#define MC_DC_DCFG_MC2_EN 0x1000000000000000 +#define MC_DC_DCFG_MC3_EN 0x2000000000000000 +#define MC_DC_DCFG_ODDDIVISORCORRECT 0x8000000000000000 + +#ifdef __cplusplus +} +#endif + +#endif /* _MC_AMD_H */ diff --git a/usr/src/uts/intel/sys/mca_amd.h b/usr/src/uts/intel/sys/mca_amd.h new file mode 100644 index 0000000000..21524f8713 --- /dev/null +++ b/usr/src/uts/intel/sys/mca_amd.h @@ -0,0 +1,418 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_MCA_AMD_H +#define _SYS_MCA_AMD_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Constants the Memory Check Architecture as implemented on AMD CPUs. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define AMD_MSR_MCG_CAP 0x179 +#define AMD_MSR_MCG_STATUS 0x17a +#define AMD_MSR_MCG_CTL 0x17b + +#define AMD_MCA_BANK_DC 0 /* Data Cache */ +#define AMD_MCA_BANK_IC 1 /* Instruction Cache */ +#define AMD_MCA_BANK_BU 2 /* Bus Unit */ +#define AMD_MCA_BANK_LS 3 /* Load/Store Unit */ +#define AMD_MCA_BANK_NB 4 /* Northbridge */ +#define AMD_MCA_BANK_COUNT 5 + +#define AMD_MSR_DC_CTL 0x400 +#define AMD_MSR_DC_MASK 0xc0010044 +#define AMD_MSR_DC_STATUS 0x401 +#define AMD_MSR_DC_ADDR 0x402 + +#define AMD_MSR_IC_CTL 0x404 +#define AMD_MSR_IC_MASK 0xc0010045 +#define AMD_MSR_IC_STATUS 0x405 +#define AMD_MSR_IC_ADDR 0x406 + +#define AMD_MSR_BU_CTL 0x408 +#define AMD_MSR_BU_MASK 0xc0010046 +#define AMD_MSR_BU_STATUS 0x409 +#define AMD_MSR_BU_ADDR 0x40a + +#define AMD_MSR_LS_CTL 0x40c +#define AMD_MSR_LS_MASK 0xc0010047 +#define AMD_MSR_LS_STATUS 0x40d +#define AMD_MSR_LS_ADDR 0x40e + +#define AMD_MSR_NB_CTL 0x410 +#define AMD_MSR_NB_MASK 0xc0010048 +#define AMD_MSR_NB_STATUS 0x411 +#define AMD_MSR_NB_ADDR 0x412 + +#define AMD_MCG_EN_DC 0x01 +#define AMD_MCG_EN_IC 0x02 +#define AMD_MCG_EN_BU 0x04 +#define AMD_MCG_EN_LS 0x08 +#define AMD_MCG_EN_NB 0x10 +#define AMD_MCG_EN_ALL \ + (AMD_MCG_EN_DC | AMD_MCG_EN_IC | AMD_MCG_EN_BU | AMD_MCG_EN_LS | \ + AMD_MCG_EN_NB) + +/* + * Data Cache (DC) bank error-detection enabling bits and CTL register + * initializer value. + */ + +#define AMD_DC_EN_ECCI 0x00000001ULL +#define AMD_DC_EN_ECCM 0x00000002ULL +#define AMD_DC_EN_DECC 0x00000004ULL +#define AMD_DC_EN_DMTP 0x00000008ULL +#define AMD_DC_EN_DSTP 0x00000010ULL +#define AMD_DC_EN_L1TP 0x00000020ULL +#define AMD_DC_EN_L2TP 0x00000040ULL + +#define AMD_DC_CTL_INIT \ + (AMD_DC_EN_ECCI | AMD_DC_EN_ECCM | AMD_DC_EN_DECC | AMD_DC_EN_DMTP | \ + AMD_DC_EN_DSTP | AMD_DC_EN_L1TP | AMD_DC_EN_L2TP) + +/* + * Instruction Cache (IC) bank error-detection enabling bits and CTL register + * initializer value. + * + * The Northbridge will handle Read Data errors. Our initializer will enable + * all but the RDDE detector. + */ + +#define AMD_IC_EN_ECCI 0x00000001ULL +#define AMD_IC_EN_ECCM 0x00000002ULL +#define AMD_IC_EN_IDP 0x00000004ULL +#define AMD_IC_EN_IMTP 0x00000008ULL +#define AMD_IC_EN_ISTP 0x00000010ULL +#define AMD_IC_EN_L1TP 0x00000020ULL +#define AMD_IC_EN_L2TP 0x00000040ULL +#define AMD_IC_EN_RDDE 0x00000200ULL + +#define AMD_IC_CTL_INIT \ + (AMD_IC_EN_ECCI | AMD_IC_EN_ECCM | AMD_IC_EN_IDP | AMD_IC_EN_IMTP | \ + AMD_IC_EN_ISTP | AMD_IC_EN_L1TP | AMD_IC_EN_L2TP) + +/* + * Bus Unit (BU) bank error-detection enabling bits and CTL register + * initializer value. + * + * The Northbridge will handle Read Data errors. Our initializer will enable + * all but the S_RDE_* detectors. + */ + +#define AMD_BU_EN_S_RDE_HP 0x00000001ULL +#define AMD_BU_EN_S_RDE_TLB 0x00000002ULL +#define AMD_BU_EN_S_RDE_ALL 0x00000004ULL +#define AMD_BU_EN_S_ECC1_TLB 0x00000008ULL +#define AMD_BU_EN_S_ECC1_HP 0x00000010ULL +#define AMD_BU_EN_S_ECCM_TLB 0x00000020ULL +#define AMD_BU_EN_S_ECCM_HP 0x00000040ULL +#define AMD_BU_EN_L2T_PAR_ICDC 0x00000080ULL +#define AMD_BU_EN_L2T_PAR_TLB 0x00000100ULL +#define AMD_BU_EN_L2T_PAR_SNP 0x00000200ULL +#define AMD_BU_EN_L2T_PAR_CPB 0x00000400ULL +#define AMD_BU_EN_L2T_PAR_SCR 0x00000800ULL +#define AMD_BU_EN_L2D_ECC1_TLB 0x00001000ULL +#define AMD_BU_EN_L2D_ECC1_SNP 0x00002000ULL +#define AMD_BU_EN_L2D_ECC1_CPB 0x00004000ULL +#define AMD_BU_EN_L2D_ECCM_TLB 0x00008000ULL +#define AMD_BU_EN_L2D_ECCM_SNP 0x00010000ULL +#define AMD_BU_EN_L2D_ECCM_CPB 0x00020000ULL +#define AMD_BU_EN_L2T_ECC1_SCR 0x00040000ULL +#define AMD_BU_EN_L2T_ECCM_SCR 0x00080000ULL + +#define AMD_BU_CTL_INIT \ + (AMD_BU_EN_S_ECC1_TLB | AMD_BU_EN_S_ECC1_HP | \ + AMD_BU_EN_S_ECCM_TLB | AMD_BU_EN_S_ECCM_HP | \ + AMD_BU_EN_L2T_PAR_ICDC | AMD_BU_EN_L2T_PAR_TLB | \ + AMD_BU_EN_L2T_PAR_SNP | AMD_BU_EN_L2T_PAR_CPB | \ + AMD_BU_EN_L2T_PAR_SCR | AMD_BU_EN_L2D_ECC1_TLB | \ + AMD_BU_EN_L2D_ECC1_SNP | AMD_BU_EN_L2D_ECC1_CPB | \ + AMD_BU_EN_L2D_ECCM_TLB | AMD_BU_EN_L2D_ECCM_SNP | \ + AMD_BU_EN_L2D_ECCM_CPB | AMD_BU_EN_L2T_ECC1_SCR | \ + AMD_BU_EN_L2T_ECCM_SCR) + +/* + * Load/Store (LS) bank error-detection enabling bits and CTL register + * initializer value. + * + * The Northbridge will handle Read Data errors. That's the only type of + * error the LS unit can detect at present, so we won't be enabling any + * LS detectors. + */ + +#define AMD_LS_EN_S_RDE_S 0x00000001ULL +#define AMD_LS_EN_S_RDE_L 0x00000002ULL + +#define AMD_LS_CTL_INIT 0ULL + +/* + * The Northbridge (NB) is configured using both the standard MCA CTL register + * and a NB-specific configuration register (NB CFG). The AMD_NB_EN_* macros + * are the detector enabling bits for the NB MCA CTL register. The + * AMD_NB_CFG_* bits are for the NB CFG register. + * + * The CTL register can be initialized statically, but portions of the NB CFG + * register must be initialized based on the current machine's configuration. + * + * The MCA NB Control Register maps to MC4_CTL[31:0]. + * + */ +#define AMD_NB_EN_CORRECC 0x00000001 +#define AMD_NB_EN_UNCORRECC 0x00000002 +#define AMD_NB_EN_CRCERR0 0x00000004 +#define AMD_NB_EN_CRCERR1 0x00000008 +#define AMD_NB_EN_CRCERR2 0x00000010 +#define AMD_NB_EN_SYNCPKT0 0x00000020 +#define AMD_NB_EN_SYNCPKT1 0x00000040 +#define AMD_NB_EN_SYNCPKT2 0x00000080 +#define AMD_NB_EN_MSTRABRT 0x00000100 +#define AMD_NB_EN_TGTABRT 0x00000200 +#define AMD_NB_EN_GARTTBLWK 0x00000400 +#define AMD_NB_EN_ATOMICRMW 0x00000800 +#define AMD_NB_EN_WCHDOGTMR 0x00001000 + +#define AMD_NB_CTL_INIT /* All but GARTTBLWK */ \ + (AMD_NB_EN_CORRECC | AMD_NB_EN_UNCORRECC | \ + AMD_NB_EN_CRCERR0 | AMD_NB_EN_CRCERR1 | AMD_NB_EN_CRCERR2 | \ + AMD_NB_EN_SYNCPKT0 | AMD_NB_EN_SYNCPKT1 | AMD_NB_EN_SYNCPKT2 | \ + AMD_NB_EN_MSTRABRT | AMD_NB_EN_TGTABRT | \ + AMD_NB_EN_ATOMICRMW | AMD_NB_EN_WCHDOGTMR) + +#define AMD_NB_CFG_CPUECCERREN 0x00000001 +#define AMD_NB_CFG_CPURDDATERREN 0x00000002 +#define AMD_NB_CFG_SYNCONUCECCEN 0x00000004 +#define AMD_NB_CFG_SYNCPKTGENDIS 0x00000008 +#define AMD_NB_CFG_SYNCPKTPROPDIS 0x00000010 +#define AMD_NB_CFG_IOMSTABORTDIS 0x00000020 +#define AMD_NB_CFG_CPUERRDIS 0x00000040 +#define AMD_NB_CFG_IOERRDIS 0x00000080 +#define AMD_NB_CFG_WDOGTMRDIS 0x00000100 +#define AMD_NB_CFG_SYNCONWDOGEN 0x00100000 +#define AMD_NB_CFG_SYNCONANYERREN 0x00200000 +#define AMD_NB_CFG_ECCEN 0x00400000 +#define AMD_NB_CFG_CHIPKILLECCEN 0x00800000 +#define AMD_NB_CFG_IORDDATERREN 0x01000000 +#define AMD_NB_CFG_DISPCICFGCPUERRRSP 0x02000000 +#define AMD_NB_CFG_NBMCATOMSTCPUEN 0x08000000 + +#define AMD_NB_CFG_WDOGTMRCNTSEL_4095 0x00000000 +#define AMD_NB_CFG_WDOGTMRCNTSEL_2047 0x00000200 +#define AMD_NB_CFG_WDOGTMRCNTSEL_1023 0x00000400 +#define AMD_NB_CFG_WDOGTMRCNTSEL_511 0x00000600 +#define AMD_NB_CFG_WDOGTMRCNTSEL_255 0x00000800 +#define AMD_NB_CFG_WDOGTMRCNTSEL_127 0x00000a00 +#define AMD_NB_CFG_WDOGTMRCNTSEL_63 0x00000c00 +#define AMD_NB_CFG_WDOGTMRCNTSEL_31 0x00000e00 +#define AMD_NB_CFG_WDOGTMRCNTSEL_MASK 0x00000e00 +#define AMD_NB_CFG_WDOGTMRCNTSEL_SHIFT 9 + +#define AMD_NB_CFG_WDOGTMRBASESEL_1MS 0x00000000 +#define AMD_NB_CFG_WDOGTMRBASESEL_1US 0x00001000 +#define AMD_NB_CFG_WDOGTMRBASESEL_5NS 0x00002000 +#define AMD_NB_CFG_WDOGTMRBASESEL_MASK 0x00003000 +#define AMD_NB_CFG_WDOGTMRBASESEL_SHIFT 12 + +#define AMD_NB_CFG_LDTLINKSEL_MASK 0x0000c000 +#define AMD_NB_CFG_LDTLINKSEL_SHIFT 14 + +#define AMD_NB_CFG_GENCRCERRBYTE0 0x00010000 +#define AMD_NB_CFG_GENCRCERRBYTE1 0x00020000 + +/* Generic bank status register bits */ +#define AMD_BANK_STAT_VALID 0x8000000000000000 +#define AMD_BANK_STAT_OVER 0x4000000000000000 +#define AMD_BANK_STAT_UC 0x2000000000000000 +#define AMD_BANK_STAT_EN 0x1000000000000000 +#define AMD_BANK_STAT_MISCV 0x0800000000000000 +#define AMD_BANK_STAT_ADDRV 0x0400000000000000 +#define AMD_BANK_STAT_PCC 0x0200000000000000 + +#define AMD_BANK_STAT_CECC 0x0000400000000000 +#define AMD_BANK_STAT_UECC 0x0000200000000000 +#define AMD_BANK_STAT_SCRUB 0x0000010000000000 + +#define AMD_BANK_STAT_SYND_MASK 0x007f800000000000 /* syndrome[7:0] */ +#define AMD_BANK_STAT_SYND_SHIFT 47 + +#define AMD_BANK_SYND(stat) \ + (((stat) & AMD_BANK_STAT_SYND_MASK) >> AMD_BANK_STAT_SYND_SHIFT) +#define AMD_BANK_MKSYND(synd) \ + (((uint64_t)(synd) << AMD_BANK_STAT_SYND_SHIFT) & \ + AMD_BANK_STAT_SYND_MASK) + +/* northbridge (NB) status registers */ + +#define AMD_NB_FUNC 3 +#define AMD_NB_REG_CFG 0x44 +#define AMD_NB_REG_STLO 0x48 /* alias: NB_STATUS[0:31] */ +#define AMD_NB_REG_STHI 0x4c /* alias: NB_STATUS[32:63] */ +#define AMD_NB_REG_ADDRLO 0x50 /* alias: NB_ADDR[0:31] */ +#define AMD_NB_REG_ADDRHI 0x54 /* alias: NB_ADDR[32:63] */ + +#define AMD_NB_REG_SCRUBCTL 0x58 +#define AMD_NB_REG_SCRUBADDR_LO 0x5c +#define AMD_NB_REG_SCRUBADDR_HI 0x60 + +#define AMD_NB_STAT_LDTLINK_MASK 0x0000007000000000 +#define AMD_NB_STAT_LDTLINK_SHIFT 4 +#define AMD_NB_STAT_ERRCPU1 0x0000000200000000 +#define AMD_NB_STAT_ERRCPU0 0x0000000100000000 +#define AMD_NB_STAT_CKSYND_MASK 0x00000000ff000000 /* syndrome[15:8] */ +#define AMD_NB_STAT_CKSYND_SHIFT (24 - 8) /* shift [31:24] to [15:8] */ + +#define AMD_NB_STAT_CKSYND(stat) \ + ((((stat) & AMD_NB_STAT_CKSYND_MASK) >> AMD_NB_STAT_CKSYND_SHIFT) | \ + AMD_BANK_SYND((stat))) + +#define AMD_NB_STAT_MKCKSYND(synd) \ + ((((uint64_t)(synd) << AMD_NB_STAT_CKSYND_SHIFT) & \ + AMD_NB_STAT_CKSYND_MASK) | AMD_BANK_MKSYND(synd)) + +#define AMD_ERRCODE_MASK 0x000000000000ffff +#define AMD_ERREXT_MASK 0x00000000000f0000 +#define AMD_ERREXT_SHIFT 16 + +#define AMD_ERRCODE_TT_MASK 0x000c +#define AMD_ERRCODE_TT_SHIFT 2 +#define AMD_ERRCODE_TT_INSTR 0x0 +#define AMD_ERRCODE_TT_DATA 0x1 +#define AMD_ERRCODE_TT_GEN 0x2 + +#define AMD_ERRCODE_LL_MASK 0x0003 +#define AMD_ERRCODE_LL_L0 0x0 +#define AMD_ERRCODE_LL_L1 0x1 +#define AMD_ERRCODE_LL_L2 0x2 +#define AMD_ERRCODE_LL_LG 0x3 + +#define AMD_ERRCODE_R4_MASK 0x00f0 +#define AMD_ERRCODE_R4_SHIFT 4 +#define AMD_ERRCODE_R4_GEN 0x0 +#define AMD_ERRCODE_R4_RD 0x1 +#define AMD_ERRCODE_R4_WR 0x2 +#define AMD_ERRCODE_R4_DRD 0x3 +#define AMD_ERRCODE_R4_DWR 0x4 +#define AMD_ERRCODE_R4_IRD 0x5 +#define AMD_ERRCODE_R4_PREFETCH 0x6 +#define AMD_ERRCODE_R4_EVICT 0x7 +#define AMD_ERRCODE_R4_SNOOP 0x8 + +#define AMD_ERRCODE_PP_MASK 0x0600 +#define AMD_ERRCODE_PP_SHIFT 9 +#define AMD_ERRCODE_PP_SRC 0x0 +#define AMD_ERRCODE_PP_RSP 0x1 +#define AMD_ERRCODE_PP_OBS 0x2 +#define AMD_ERRCODE_PP_GEN 0x3 + +#define AMD_ERRCODE_T_MASK 0x0100 +#define AMD_ERRCODE_T_SHIFT 8 +#define AMD_ERRCODE_T_NONE 0x0 +#define AMD_ERRCODE_T_TIMEOUT 0x1 + +#define AMD_ERRCODE_II_MASK 0x000c +#define AMD_ERRCODE_II_SHIFT 2 +#define AMD_ERRCODE_II_MEM 0x0 +#define AMD_ERRCODE_II_IO 0x2 +#define AMD_ERRCODE_II_GEN 0x3 + +#define AMD_ERRCODE_TLB_BIT 4 +#define AMD_ERRCODE_MEM_BIT 8 +#define AMD_ERRCODE_BUS_BIT 11 + +#define AMD_ERRCODE_TLB_MASK 0xfff0 +#define AMD_ERRCODE_TLB_VAL 0x0010 +#define AMD_ERRCODE_MEM_MASK 0xff00 +#define AMD_ERRCODE_MEM_VAL 0x0100 +#define AMD_ERRCODE_BUS_MASK 0xf800 +#define AMD_ERRCODE_BUS_VAL 0x0800 + +#define AMD_ERRCODE_MKTLB(tt, ll) \ + (AMD_ERRCODE_TLB_VAL | \ + (((tt) << AMD_ERRCODE_TT_SHIFT) & AMD_ERRCODE_TT_MASK) | \ + ((ll) & AMD_ERRCODE_LL_MASK)) +#define AMD_ERRCODE_ISTLB(code) \ + (((code) & AMD_ERRCODE_TLB_MASK) == AMD_ERRCODE_TLB_VAL) + +#define AMD_ERRCODE_MKMEM(r4, tt, ll) \ + (AMD_ERRCODE_MEM_VAL | \ + (((r4) << AMD_ERRCODE_R4_SHIFT) & AMD_ERRCODE_R4_MASK) | \ + (((tt) << AMD_ERRCODE_TT_SHIFT) & AMD_ERRCODE_TT_MASK) | \ + ((ll) & AMD_ERRCODE_LL_MASK)) +#define AMD_ERRCODE_ISMEM(code) \ + (((code) & AMD_ERRCODE_MEM_MASK) == AMD_ERRCODE_MEM_VAL) + +#define AMD_ERRCODE_MKBUS(pp, t, r4, ii, ll) \ + (AMD_ERRCODE_BUS_VAL | \ + (((pp) << AMD_ERRCODE_PP_SHIFT) & AMD_ERRCODE_PP_MASK) | \ + (((t) << AMD_ERRCODE_T_SHIFT) & AMD_ERRCODE_T_MASK) | \ + (((r4) << AMD_ERRCODE_R4_SHIFT) & AMD_ERRCODE_R4_MASK) | \ + (((ii) << AMD_ERRCODE_II_SHIFT) & AMD_ERRCODE_II_MASK) | \ + ((ll) & AMD_ERRCODE_LL_MASK)) +#define AMD_ERRCODE_ISBUS(code) \ + (((code) & AMD_ERRCODE_BUS_MASK) == AMD_ERRCODE_BUS_VAL) + +#define AMD_NB_ADDRLO_MASK 0xfffffff8 +#define AMD_NB_ADDRHI_MASK 0x000000ff + +#define AMD_SYNDTYPE_ECC 0 +#define AMD_SYNDTYPE_CHIPKILL 1 + +#define AMD_NB_SCRUBCTL_DRAM_MASK 0x0000001f +#define AMD_NB_SCRUBCTL_DRAM_SHIFT 0 +#define AMD_NB_SCRUBCTL_L2_MASK 0x00001f00 +#define AMD_NB_SCRUBCTL_L2_SHIFT 8 +#define AMD_NB_SCRUBCTL_DC_MASK 0x001f0000 +#define AMD_NB_SCRUBCTL_DC_SHIFT 16 + +#define AMD_NB_SCRUBCTL_RATE_NONE 0 +#define AMD_NB_SCRUBCTL_RATE_MAX 0x16 + +#define AMD_NB_SCRUBADDR_LO_MASK 0xffffffc0 +#define AMD_NB_SCRUBADDR_LO_SCRUBREDIREN 0x1 +#define AMD_NB_SCRUBADDR_HI_MASK 0x000000ff + +#define AMD_NB_SCRUBADDR_MKLO(addr) \ + ((addr) & AMD_NB_SCRUBADDR_LO_MASK) + +#define AMD_NB_SCRUBADDR_MKHI(addr) \ + (((addr) >> 32) & AMD_NB_SCRUBADDR_HI_MASK) + +#define AMD_NB_MKSCRUBCTL(dc, l2, dr) ( \ + (((dc) << AMD_NB_SCRUBCTL_DC_SHIFT) & AMD_NB_SCRUBCTL_DC_MASK) | \ + (((l2) << AMD_NB_SCRUBCTL_L2_SHIFT) & AMD_NB_SCRUBCTL_L2_MASK) | \ + (((dr) << AMD_NB_SCRUBCTL_DRAM_SHIFT) & AMD_NB_SCRUBCTL_DRAM_MASK)) + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_MCA_AMD_H */ diff --git a/usr/src/uts/intel/sys/mca_x86.h b/usr/src/uts/intel/sys/mca_x86.h new file mode 100644 index 0000000000..78066bdc63 --- /dev/null +++ b/usr/src/uts/intel/sys/mca_x86.h @@ -0,0 +1,126 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_MCA_X86_H +#define _SYS_MCA_X86_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Constants for the Memory Check Architecture as implemented on generic x86 + * CPUs. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Intel has defined a number of MSRs as part of the IA32 architecture. The + * MCG registers are part of that set, as are the first four banks (0-3) as + * implemented by the P4 processor. Bank MSRs were laid out slightly + * differently on the P6 family of processors, and thus have their own #defines + * following the architecture-generic ones. + */ +#define IA32_MSR_MCG_CAP 0x179 +#define IA32_MSR_MCG_STATUS 0x17a +#define IA32_MSR_MCG_CTL 0x17b + +#define MCG_CAP_COUNT_MASK 0x000000ffULL +#define MCG_CAP_CTL_P 0x00000100ULL +#define MCG_CAP_EXT_P 0x00000200ULL +#define MCG_CAP_EXT_CNT_MASK 0x00ff0000ULL +#define MCG_CAP_EXT_CNT_SHIFT 16 + +#define MCG_STATUS_RIPV 0x01 +#define MCG_STATUS_EIPV 0x02 +#define MCG_STATUS_MCIP 0x04 + +#define IA32_MSR_MC0_CTL 0x400 +#define IA32_MSR_MC0_STATUS 0x401 +#define IA32_MSR_MC0_ADDR 0x402 +#define IA32_MSR_MC0_MISC 0x403 + +#define IA32_MSR_MC1_CTL 0x404 +#define IA32_MSR_MC1_STATUS 0x405 +#define IA32_MSR_MC1_ADDR 0x406 +#define IA32_MSR_MC1_MISC 0x407 + +#define IA32_MSR_MC2_CTL 0x408 +#define IA32_MSR_MC2_STATUS 0x409 +#define IA32_MSR_MC2_ADDR 0x40a +#define IA32_MSR_MC2_MISC 0x40b + +#define IA32_MSR_MC3_CTL 0x40c +#define IA32_MSR_MC3_STATUS 0x40d +#define IA32_MSR_MC3_ADDR 0x40e +#define IA32_MSR_MC3_MISC 0x40f + +#define MSR_MC_STATUS_VAL 0x8000000000000000ULL +#define MSR_MC_STATUS_O 0x4000000000000000ULL +#define MSR_MC_STATUS_UC 0x2000000000000000ULL +#define MSR_MC_STATUS_EN 0x1000000000000000ULL +#define MSR_MC_STATUS_MISCV 0x0800000000000000ULL +#define MSR_MC_STATUS_ADDRV 0x0400000000000000ULL +#define MSR_MC_STATUS_PCC 0x0200000000000000ULL +#define MSR_MC_STATUS_OTHER_MASK 0x01ffffff00000000ULL +#define MSR_MC_STATUS_OTHER_SHIFT 32 +#define MSR_MC_STATUS_MSERR_MASK 0x00000000ffff0000ULL +#define MSR_MC_STATUS_MSERR_SHIFT 16 +#define MSR_MC_STATUS_MCAERR_MASK 0x000000000000ffffULL + +/* + * P6 MCA bank MSRs. Note that the ordering is 0, 1, 2, *4*, 3. Yes, really. + */ +#define P6_MSR_MC0_CTL 0x400 +#define P6_MSR_MC0_STATUS 0x401 +#define P6_MSR_MC0_ADDR 0x402 +#define P6_MSR_MC0_MISC 0x403 + +#define P6_MSR_MC1_CTL 0x404 +#define P6_MSR_MC1_STATUS 0x405 +#define P6_MSR_MC1_ADDR 0x406 +#define P6_MSR_MC1_MISC 0x407 + +#define P6_MSR_MC2_CTL 0x408 +#define P6_MSR_MC2_STATUS 0x409 +#define P6_MSR_MC2_ADDR 0x40a +#define P6_MSR_MC2_MISC 0x40b + +#define P6_MSR_MC4_CTL 0x40c +#define P6_MSR_MC4_STATUS 0x40d +#define P6_MSR_MC4_ADDR 0x40e +#define P6_MSR_MC4_MISC 0x40f + +#define P6_MSR_MC3_CTL 0x410 +#define P6_MSR_MC3_STATUS 0x411 +#define P6_MSR_MC3_ADDR 0x412 +#define P6_MSR_MC3_MISC 0x413 + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_MCA_X86_H */ diff --git a/usr/src/uts/intel/sys/memtest.h b/usr/src/uts/intel/sys/memtest.h new file mode 100644 index 0000000000..8e9d4fc8ef --- /dev/null +++ b/usr/src/uts/intel/sys/memtest.h @@ -0,0 +1,126 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _MEMTEST_H +#define _MEMTEST_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Interfaces for the memory error injection driver (memtest). This driver is + * intended for use only by mtst. + */ + +#include <sys/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define MEMTEST_DEVICE "/devices/pseudo/memtest@0:memtest" + +#define MEMTEST_VERSION 1 + +#define MEMTESTIOC ('M' << 8) +#define MEMTESTIOC_INQUIRE (MEMTESTIOC | 0) +#define MEMTESTIOC_CONFIG (MEMTESTIOC | 1) +#define MEMTESTIOC_INJECT (MEMTESTIOC | 2) +#define MEMTESTIOC_MEMREQ (MEMTESTIOC | 3) +#define MEMTESTIOC_MEMREL (MEMTESTIOC | 4) + +#define MEMTEST_F_DEBUG 0x1 + +typedef struct memtest_inq { + uint_t minq_version; /* [out] driver version */ +} memtest_inq_t; + +/* + * Used by the userland injector to request a memory region from the driver. + * This region (or a portion thereof) will be used for the error. The caller + * is expected to fill in the restrictions, if any, that are to be applied to + * the region. If the driver cannot allocate a region that meets the supplied + * restrictions, the ioctl will fail. Upon success, all members will be filled + * in with values that reflect the allocated area. + */ + +#define MEMTEST_MEMREQ_MAXNUM 5 /* maximum number of open allocations */ +#define MEMTEST_MEMREQ_MAXSIZE 8192 /* maximum size of each allocation */ + +#define MEMTEST_MEMREQ_UNSPEC ((uint64_t)-1) + +typedef struct memtest_memreq { + int mreq_cpuid; /* cpu restriction (opt, -1 if unset) */ + uint32_t mreq_size; /* size of allocation */ + uint64_t mreq_vaddr; /* [out] VA of allocation */ + uint64_t mreq_paddr; /* [out] PA of allocation */ +} memtest_memreq_t; + +/* + * Arrays of statements are passed to the memtest driver for error injection. + */ +#define MEMTEST_INJECT_MAXNUM 20 /* Max # of stmts per INJECT ioctl */ + +#define MEMTEST_INJ_STMT_MSR 0x1 /* an MSR to be written */ +#define MEMTEST_INJ_STMT_PCICFG 0x2 /* address in PCI config space */ +#define MEMTEST_INJ_STMT_INT 0x3 /* a specific interrupt to be raised */ +#define MEMTEST_INJ_STMT_POLL 0x4 /* tell CPU module to poll for CEs */ + +/* Must be kept in sync with mtst_inj_statement in mtst_cpumod_api.h */ +typedef struct memtest_inj_stmt { + int mis_cpuid; /* target CPU for statement */ + uint_t mis_type; /* MEMTEST_INJ_STMT_* */ + union { + struct { /* MEMTEST_INJ_STMT_MSR */ + uint32_t _mis_msrnum; /* MSR number */ + uint32_t _mis_pad; /* reserved */ + uint64_t _mis_msrval; /* value for MSR */ + } _mis_msr; + struct { /* MEMTEST_INJ_STMT_PCICFG */ + uint32_t _mis_pciaddr; /* address in config space */ + uint32_t _mis_pcival; /* value for PCI config reg */ + } _mis_pci; + uint8_t _mis_int; /* MEMTEST_INJ_STMT_INT; int num */ + } _mis_data; +} memtest_inj_stmt_t; + +#define mis_msrnum _mis_data._mis_msr._mis_msrnum +#define mis_msrval _mis_data._mis_msr._mis_msrval +#define mis_pciaddr _mis_data._mis_pci._mis_pciaddr +#define mis_pcival _mis_data._mis_pci._mis_pcival +#define mis_int _mis_data._mis_int + +typedef struct memtest_inject { + int mi_nstmts; + uint32_t mi_pad; + memtest_inj_stmt_t mi_stmts[1]; +} memtest_inject_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _MEMTEST_H */ diff --git a/usr/src/uts/intel/sys/x86_archext.h b/usr/src/uts/intel/sys/x86_archext.h index 4b93663dbd..2f52d6ee4b 100644 --- a/usr/src/uts/intel/sys/x86_archext.h +++ b/usr/src/uts/intel/sys/x86_archext.h @@ -262,54 +262,7 @@ extern "C" { #define MSR_PRP4_LBSTK_TO_14 0x6ce #define MSR_PRP4_LBSTK_TO_15 0x6cf -#define REG_MCG_CAP 0x179 -#define REG_MCG_STATUS 0x17a -#define REG_MCG_CTL 0x17b - -#define REG_MC0_CTL 0x400 -#define REG_MC0_STATUS 0x401 -#define REG_MC0_ADDR 0x402 -#define REG_MC0_MISC 0x403 -#define REG_MC1_CTL 0x404 -#define REG_MC1_STATUS 0x405 -#define REG_MC1_ADDR 0x406 -#define REG_MC1_MISC 0x407 -#define REG_MC2_CTL 0x408 -#define REG_MC2_STATUS 0x409 -#define REG_MC2_ADDR 0x40a -#define REG_MC2_MISC 0x40b -#define REG_MC4_CTL 0x40c -#define REG_MC4_STATUS 0x40d -#define REG_MC4_ADDR 0x40e -#define REG_MC4_MISC 0x40f -#define REG_MC3_CTL 0x410 -#define REG_MC3_STATUS 0x411 -#define REG_MC3_ADDR 0x412 -#define REG_MC3_MISC 0x413 - -#define P6_MCG_CAP_COUNT 5 -#define MCG_CAP_COUNT_MASK 0xff -#define MCG_CAP_CTL_P 0x100 - -#define MCG_STATUS_RIPV 0x01 -#define MCG_STATUS_EIPV 0x02 -#define MCG_STATUS_MCIP 0x04 - -#define MCG_CTL_VALUE 0xffffffff - #define MCI_CTL_VALUE 0xffffffff -#define MCI_STATUS_ERRCODE 0xffff -#define MCI_STATUS_MSERRCODE 0xffff0000 -#define MCI_STATUS_PCC ((long long)0x200000000000000) -#define MCI_STATUS_ADDRV ((long long)0x400000000000000) -#define MCI_STATUS_MISCV ((long long)0x800000000000000) -#define MCI_STATUS_EN ((long long)0x1000000000000000) -#define MCI_STATUS_UC ((long long)0x2000000000000000) -#define MCI_STATUS_O ((long long)0x4000000000000000) -#define MCI_STATUS_VAL ((long long)0x8000000000000000) - -#define MSERRCODE_SHFT 16 - #define MTRRTYPE_MASK 0xff @@ -437,6 +390,8 @@ typedef struct mtrrvar { #define X86_VENDOR_TM 9 /* GenuineTMx86 */ #define X86_VENDOR_NSC 10 /* Geode by NSC */ +#define X86_VENDOR_STRLEN 13 /* vendor string max len + \0 */ + #if !defined(_ASM) #if defined(_KERNEL) || defined(_KMEMUSER) @@ -471,8 +426,6 @@ struct cpuid_regs { extern uint64_t rdmsr(uint_t); extern void wrmsr(uint_t, const uint64_t); extern void invalidate_cache(void); -struct regs; -extern int mca_exception(struct regs *); extern ulong_t getcr4(void); extern void setcr4(ulong_t); extern void mtrr_sync(void); diff --git a/usr/src/uts/sparc/sys/Makefile b/usr/src/uts/sparc/sys/Makefile index 88221c9101..72c122f969 100644 --- a/usr/src/uts/sparc/sys/Makefile +++ b/usr/src/uts/sparc/sys/Makefile @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -59,19 +59,37 @@ HDRS= \ vmparam.h \ sysconfig_impl.h -FPUHDRS= fpu_simulator.h fpusystm.h globals.h ieee.h +FPUHDRS= \ + fpu_simulator.h \ + fpusystm.h \ + globals.h \ + ieee.h + +FMCPUHDRS= \ + UltraSPARC-II.h \ + UltraSPARC-III.h \ + UltraSPARC-T1.h ROOTDIR= $(ROOT)/usr/include/sys -ROOTDIRS= $(ROOTDIR) $(ROOTDIR)/fpu +ROOTDIRS= \ + $(ROOTDIR) \ + $(ROOTDIR)/fm/cpu \ + $(ROOTDIR)/fpu ROOTHDRS= $(HDRS:%=$(ROOTDIR)/%) ROOTFPUHDRS= $(FPUHDRS:%=$(ROOTDIR)/fpu/%) +ROOTFMCPUHDRS= $(FMCPUHDRS:%=$(ROOTDIR)/fm/cpu/%) fpu/%.check: fpu/%.h $(DOT_H_CHECK) -CHECKHDRS= $(HDRS:%.h=%.check) \ - $(FPUHDRS:%.h=fpu/%.check) +fm/cpu/%.check: fm/cpu/%.h + $(DOT_H_CHECK) + +CHECKHDRS= \ + $(HDRS:%.h=%.check) \ + $(FPUHDRS:%.h=fpu/%.check) \ + $(FMCPUHDRS:%.h=fm/cpu/%.check) # install rules $(ROOTDIR)/%: % @@ -80,11 +98,14 @@ $(ROOTDIR)/%: % $(ROOTDIR)/fpu/%: fpu/% $(INS.file) +$(ROOTDIR)/fm/cpu/%: fm/cpu/% + $(INS.file) + .KEEP_STATE: -.PARALLEL: $(CHECKHDRS) $(ROOTHDRS) $(ROOTFPUHDRS) +.PARALLEL: $(CHECKHDRS) $(ROOTHDRS) $(ROOTFPUHDRS) $(ROOTFMCPUHDRS) -install_h: $(ROOTDIRS) .WAIT $(ROOTHDRS) $(ROOTFPUHDRS) +install_h: $(ROOTDIRS) .WAIT $(ROOTHDRS) $(ROOTFPUHDRS) $(ROOTFMCPUHDRS) $(ROOTDIRS): $(INS.dir) diff --git a/usr/src/uts/common/sys/fm/cpu/UltraSPARC-II.h b/usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-II.h index c6013c9515..c6013c9515 100644 --- a/usr/src/uts/common/sys/fm/cpu/UltraSPARC-II.h +++ b/usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-II.h diff --git a/usr/src/uts/common/sys/fm/cpu/UltraSPARC-III.h b/usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-III.h index 6422868396..6422868396 100644 --- a/usr/src/uts/common/sys/fm/cpu/UltraSPARC-III.h +++ b/usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-III.h diff --git a/usr/src/uts/common/sys/fm/cpu/UltraSPARC-T1.h b/usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-T1.h index e6ffdfe922..e6ffdfe922 100644 --- a/usr/src/uts/common/sys/fm/cpu/UltraSPARC-T1.h +++ b/usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-T1.h diff --git a/usr/src/uts/sun4u/cpu/us3_common.c b/usr/src/uts/sun4u/cpu/us3_common.c index f503c84984..6d1a99fa7b 100644 --- a/usr/src/uts/sun4u/cpu/us3_common.c +++ b/usr/src/uts/sun4u/cpu/us3_common.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -6400,13 +6400,14 @@ void cpu_ereport_post(struct async_flt *aflt) { char *cpu_type, buf[FM_MAX_CLASS]; + char sbuf[21]; /* sizeof (UINT64_MAX) + '\0' */ nv_alloc_t *nva = NULL; nvlist_t *ereport, *detector, *resource; errorq_elem_t *eqep; ch_async_flt_t *ch_flt = (ch_async_flt_t *)aflt; char unum[UNUM_NAMLEN]; int len = 0; - uint8_t msg_type; + uint8_t msg_type, mask; plat_ecc_ch_async_flt_t plat_ecc_ch_flt; if (aflt->flt_panic || panicstr) { @@ -6447,9 +6448,11 @@ cpu_ereport_post(struct async_flt *aflt) cpu_type = FM_EREPORT_CPU_UNSUPPORTED; break; } + mask = cpunodes[aflt->flt_inst].version; + (void) snprintf(sbuf, sizeof (sbuf), "%llX", + (u_longlong_t)cpunodes[aflt->flt_inst].device_id); (void) fm_fmri_cpu_set(detector, FM_CPU_SCHEME_VERSION, NULL, - aflt->flt_inst, (uint8_t)cpunodes[aflt->flt_inst].version, - cpunodes[aflt->flt_inst].device_id); + aflt->flt_inst, &mask, (const char *)sbuf); /* * Encode all the common data into the ereport. |