summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/Makefile.lint4
-rw-r--r--usr/src/cmd/Makefile4
-rw-r--r--usr/src/cmd/devfsadm/i386/misc_link_i386.c42
-rw-r--r--usr/src/cmd/fm/Makefile6
-rw-r--r--usr/src/cmd/fm/dicts/AMD.dict47
-rw-r--r--usr/src/cmd/fm/dicts/AMD.po299
-rw-r--r--usr/src/cmd/fm/dicts/Makefile8
-rw-r--r--usr/src/cmd/fm/eversholt/common/check.c96
-rw-r--r--usr/src/cmd/fm/eversholt/common/esclex.c3
-rw-r--r--usr/src/cmd/fm/eversholt/common/escparse.y19
-rw-r--r--usr/src/cmd/fm/eversholt/common/literals.h14
-rw-r--r--usr/src/cmd/fm/eversholt/common/ptree.c15
-rw-r--r--usr/src/cmd/fm/eversholt/common/ptree.h3
-rw-r--r--usr/src/cmd/fm/eversholt/common/stats.c13
-rw-r--r--usr/src/cmd/fm/eversholt/common/stats.h3
-rw-r--r--usr/src/cmd/fm/eversholt/common/tree.c73
-rw-r--r--usr/src/cmd/fm/eversholt/common/tree.h8
-rw-r--r--usr/src/cmd/fm/eversholt/common/version.h4
-rw-r--r--usr/src/cmd/fm/eversholt/files/i386/Makefile5
-rw-r--r--usr/src/cmd/fm/eversholt/files/i386/i86pc/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V245/Makefile)4
-rw-r--r--usr/src/cmd/fm/eversholt/files/i386/i86pc/amd64.esc841
-rw-r--r--usr/src/cmd/fm/fmd/Makefile.fmd4
-rw-r--r--usr/src/cmd/fm/fmd/common/fmd.c34
-rw-r--r--usr/src/cmd/fm/fmd/common/fmd.h4
-rw-r--r--usr/src/cmd/fm/fmd/common/fmd_api.c56
-rw-r--r--usr/src/cmd/fm/fmd/common/fmd_api.h6
-rw-r--r--usr/src/cmd/fm/fmd/common/fmd_api.map8
-rw-r--r--usr/src/cmd/fm/fmd/common/fmd_asru.c6
-rw-r--r--usr/src/cmd/fm/fmd/common/fmd_case.c51
-rw-r--r--usr/src/cmd/fm/fmd/common/fmd_case.h5
-rw-r--r--usr/src/cmd/fm/fmd/common/fmd_conf.c31
-rw-r--r--usr/src/cmd/fm/fmd/common/fmd_conf.h3
-rw-r--r--usr/src/cmd/fm/fmd/common/fmd_error.h4
-rw-r--r--usr/src/cmd/fm/fmd/common/fmd_fmri.c11
-rw-r--r--usr/src/cmd/fm/fmd/common/fmd_fmri.h6
-rw-r--r--usr/src/cmd/fm/fmd/common/fmd_fmri.map3
-rw-r--r--usr/src/cmd/fm/fmd/common/fmd_protocol.c25
-rw-r--r--usr/src/cmd/fm/fmd/common/fmd_sysevent.c3
-rw-r--r--usr/src/cmd/fm/fmdump/Makefile.com4
-rw-r--r--usr/src/cmd/fm/fmdump/common/fault.c36
-rw-r--r--usr/src/cmd/fm/fmdump/common/fmdump.c3
-rw-r--r--usr/src/cmd/fm/fmdump/common/fmdump.h4
-rw-r--r--usr/src/cmd/fm/fmdump/common/scheme.c19
-rw-r--r--usr/src/cmd/fm/fminject/Makefile.com8
-rw-r--r--usr/src/cmd/fm/fminject/common/inj.h27
-rw-r--r--usr/src/cmd/fm/fminject/common/inj_decl.c10
-rw-r--r--usr/src/cmd/fm/fminject/common/inj_defn.c19
-rw-r--r--usr/src/cmd/fm/fminject/common/inj_grammar.y23
-rw-r--r--usr/src/cmd/fm/fminject/common/inj_lex.l6
-rw-r--r--usr/src/cmd/fm/fminject/common/inj_util.c8
-rw-r--r--usr/src/cmd/fm/fmtopo/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V445/Makefile)5
-rw-r--r--usr/src/cmd/fm/fmtopo/Makefile.com (renamed from usr/src/cmd/fm/topo/prtopo/Makefile.com)71
-rw-r--r--usr/src/cmd/fm/fmtopo/common/fmtopo.c315
-rw-r--r--usr/src/cmd/fm/fmtopo/i386/Makefile (renamed from usr/src/cmd/fm/topo/prtopo/i386/Makefile)4
-rw-r--r--usr/src/cmd/fm/fmtopo/sparc/Makefile (renamed from usr/src/cmd/fm/topo/prtopo/sparc/Makefile)4
-rw-r--r--usr/src/cmd/fm/modules/Makefile.plugin4
-rw-r--r--usr/src/cmd/fm/modules/common/cpumem-retire/Makefile4
-rw-r--r--usr/src/cmd/fm/modules/common/cpumem-retire/cma.h4
-rw-r--r--usr/src/cmd/fm/modules/common/cpumem-retire/cma_main.c25
-rw-r--r--usr/src/cmd/fm/modules/common/cpumem-retire/cma_page.c92
-rw-r--r--usr/src/cmd/fm/modules/common/eversholt/Makefile8
-rw-r--r--usr/src/cmd/fm/modules/common/eversholt/eft.c17
-rw-r--r--usr/src/cmd/fm/modules/common/eversholt/eft.conf11
-rw-r--r--usr/src/cmd/fm/modules/common/eversholt/eval.c281
-rw-r--r--usr/src/cmd/fm/modules/common/eversholt/fme.c1190
-rw-r--r--usr/src/cmd/fm/modules/common/eversholt/fme.h13
-rw-r--r--usr/src/cmd/fm/modules/common/eversholt/iexpr.c290
-rw-r--r--usr/src/cmd/fm/modules/common/eversholt/iexpr.h48
-rw-r--r--usr/src/cmd/fm/modules/common/eversholt/ipath.c31
-rw-r--r--usr/src/cmd/fm/modules/common/eversholt/ipath.h3
-rw-r--r--usr/src/cmd/fm/modules/common/eversholt/itree.c33
-rw-r--r--usr/src/cmd/fm/modules/common/eversholt/itree.h40
-rw-r--r--usr/src/cmd/fm/modules/common/eversholt/platform.c1257
-rw-r--r--usr/src/cmd/fm/modules/common/eversholt/platform.h8
-rw-r--r--usr/src/cmd/fm/modules/common/eversholt/stats.c27
-rw-r--r--usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_cpu.c5
-rw-r--r--usr/src/cmd/fm/modules/sun4u/cpumem-diagnosis/cmd_dp.c8
-rw-r--r--usr/src/cmd/fm/schemes/Makefile9
-rw-r--r--usr/src/cmd/fm/schemes/Makefile.targ21
-rw-r--r--usr/src/cmd/fm/schemes/cpu/amd64/Makefile7
-rw-r--r--usr/src/cmd/fm/schemes/cpu/cpu.c149
-rw-r--r--usr/src/cmd/fm/schemes/cpu/i386/Makefile7
-rw-r--r--usr/src/cmd/fm/schemes/cpu/sparc/Makefile9
-rw-r--r--usr/src/cmd/fm/schemes/cpu/sparc/cpu_mdesc.c (renamed from usr/src/cmd/fm/schemes/cpu/cpu_mdesc.c)32
-rw-r--r--usr/src/cmd/fm/schemes/cpu/sparc/cpu_mdesc.h (renamed from usr/src/cmd/fm/schemes/cpu/cpu.h)9
-rw-r--r--usr/src/cmd/fm/schemes/cpu/sparcv9/Makefile8
-rw-r--r--usr/src/cmd/fm/schemes/mem/Makefile.com3
-rw-r--r--usr/src/cmd/fm/schemes/mem/amd64/Makefile36
-rw-r--r--usr/src/cmd/fm/schemes/mem/i386/Makefile35
-rw-r--r--usr/src/cmd/fm/schemes/mem/i386/mem_disc.c39
-rw-r--r--usr/src/cmd/fm/schemes/mem/mem.c169
-rw-r--r--usr/src/cmd/fm/schemes/mem/mem.h12
-rw-r--r--usr/src/cmd/fm/schemes/mem/mem_unum.c37
-rw-r--r--usr/src/cmd/fm/schemes/mem/sparc/Makefile5
-rw-r--r--usr/src/cmd/fm/schemes/mem/sparc/mem_disc.c (renamed from usr/src/cmd/fm/schemes/mem/mem_disc.c)46
-rw-r--r--usr/src/cmd/fm/schemes/mem/sparcv9/Makefile5
-rw-r--r--usr/src/cmd/fm/topo/files/Makefile30
-rw-r--r--usr/src/cmd/fm/topo/files/Makefile.link48
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/Makefile55
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,A70/Makefile55
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,A70/platform.topo302
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/Makefile31
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/platform.topo48
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-240/Makefile32
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-440/Makefile32
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/Makefile30
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/platform.topo42
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/Makefile31
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/platform.topo31
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T4/Makefile32
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/Makefile31
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/platform.topo36
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/Makefile31
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/platform.topo31
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/Makefile31
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/platform.topo36
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/Makefile31
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/platform.topo34
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2000/Makefile32
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/Makefile31
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/platform.topo42
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/Makefile31
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/platform.topo917
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-280R/Makefile32
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/Makefile31
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/platform.topo46
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/Makefile31
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/platform.topo54
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/Makefile32
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/platform.topo323
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V210/Makefile32
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/Makefile31
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/platform.topo45
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V250/Makefile32
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/Makefile31
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/platform.topo48
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V490/Makefile32
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V890/Makefile32
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/Makefile31
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/platform.topo356
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/Makefile31
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/platform.topo42
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/Makefile31
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/platform.topo34
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/Makefile31
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/platform.topo52
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/Makefile31
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/platform.topo34
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/Makefile31
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/platform.topo38
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/Makefile31
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/platform.topo40
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/Makefile31
-rw-r--r--usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/platform.topo32
-rw-r--r--usr/src/cmd/fm/topo/plugins/Makefile33
-rw-r--r--usr/src/cmd/fm/topo/plugins/Makefile.topoonly54
-rw-r--r--usr/src/cmd/fm/topo/plugins/common/Makefile30
-rw-r--r--usr/src/cmd/fm/topo/plugins/common/cpu/cpu.c162
-rw-r--r--usr/src/cmd/fm/topo/plugins/common/cpu/cpu.topo27
-rw-r--r--usr/src/cmd/fm/topo/plugins/common/pcibus/Makefile34
-rw-r--r--usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.c1356
-rw-r--r--usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.topo29
-rw-r--r--usr/src/cmd/fm/topo/plugins/common/pciexbus/Makefile31
-rw-r--r--usr/src/cmd/fm/topo/plugins/common/pciexbus/pciexbus.topo29
-rw-r--r--usr/src/cmd/fm/topo/plugins/common/pciexrc/Makefile31
-rw-r--r--usr/src/cmd/fm/topo/plugins/common/pciexrc/pciexrc.topo30
-rw-r--r--usr/src/cmd/fm/topo/prtopo/Makefile34
-rw-r--r--usr/src/cmd/fm/topo/prtopo/common/prtopo.c318
-rw-r--r--usr/src/cmd/mdb/common/kmdb/kmdb_kvm.c4
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_module_load.c26
-rw-r--r--usr/src/cmd/mdb/common/modules/mpxio/main.h4
-rw-r--r--usr/src/cmd/mdb/i86pc/modules/Makefile9
-rw-r--r--usr/src/cmd/mdb/i86pc/modules/amd_opteron/Makefile31
-rw-r--r--usr/src/cmd/mdb/i86pc/modules/amd_opteron/amd64/Makefile42
-rw-r--r--usr/src/cmd/mdb/i86pc/modules/amd_opteron/ao.c279
-rw-r--r--usr/src/cmd/mdb/i86pc/modules/amd_opteron/ia32/Makefile (renamed from usr/src/cmd/fm/topo/files/Makefile.com)30
-rw-r--r--usr/src/cmd/mdb/intel/kmdb/kvm_isadep.c103
-rw-r--r--usr/src/cmd/mdb/intel/kmdb/kvm_isadep.h5
-rw-r--r--usr/src/common/mc/mc-amd/Makefile.mcamd37
-rw-r--r--usr/src/common/mc/mc-amd/mcamd_api.h218
-rw-r--r--usr/src/common/mc/mc-amd/mcamd_err.c63
-rw-r--r--usr/src/common/mc/mc-amd/mcamd_err.h54
-rw-r--r--usr/src/common/mc/mc-amd/mcamd_misc.c65
-rw-r--r--usr/src/common/mc/mc-amd/mcamd_patounum.c552
-rw-r--r--usr/src/common/mc/mc-amd/mcamd_rowcol.c573
-rw-r--r--usr/src/common/mc/mc-amd/mcamd_rowcol_impl.h132
-rw-r--r--usr/src/common/mc/mc-amd/mcamd_rowcol_tbl.c591
-rw-r--r--usr/src/common/mc/mc-amd/mcamd_synd.c281
-rw-r--r--usr/src/common/mc/mc-amd/mcamd_unumtopa.c139
-rw-r--r--usr/src/lib/fm/Makefile16
-rw-r--r--usr/src/lib/fm/Makefile.lib8
-rw-r--r--usr/src/lib/fm/Makefile.targ8
-rw-r--r--usr/src/lib/fm/libtopo/Makefile.com72
-rw-r--r--usr/src/lib/fm/libtopo/common/libtopo.h309
-rw-r--r--usr/src/lib/fm/libtopo/common/libtopo_enum.h114
-rw-r--r--usr/src/lib/fm/libtopo/common/topo.c206
-rw-r--r--usr/src/lib/fm/libtopo/common/topo_enum.c329
-rw-r--r--usr/src/lib/fm/libtopo/common/topo_enum.h94
-rw-r--r--usr/src/lib/fm/libtopo/common/topo_hash.c375
-rw-r--r--usr/src/lib/fm/libtopo/common/topo_hcfmri.c127
-rw-r--r--usr/src/lib/fm/libtopo/common/topo_hcpath.c199
-rw-r--r--usr/src/lib/fm/libtopo/common/topo_impl.h180
-rw-r--r--usr/src/lib/fm/libtopo/common/topo_mem.c144
-rw-r--r--usr/src/lib/fm/libtopo/common/topo_out.c117
-rw-r--r--usr/src/lib/fm/libtopo/common/topo_parse.c616
-rw-r--r--usr/src/lib/fm/libtopo/common/topo_paths.c135
-rw-r--r--usr/src/lib/fm/libtopo/common/topo_pkg.c372
-rw-r--r--usr/src/lib/fm/libtopo/common/topo_prop.c264
-rw-r--r--usr/src/lib/fm/libtopo/common/topo_traverse.c149
-rw-r--r--usr/src/lib/fm/libtopo/sparcv9/Makefile32
-rw-r--r--usr/src/lib/fm/libtopo/spec/topo.spec145
-rw-r--r--usr/src/lib/fm/topo/Makefile (renamed from usr/src/cmd/fm/topo/Makefile)4
-rw-r--r--usr/src/lib/fm/topo/Makefile.rootdirs (renamed from usr/src/cmd/fm/topo/Makefile.rootdirs)30
-rw-r--r--usr/src/lib/fm/topo/files/Makefile (renamed from usr/src/cmd/fm/schemes/cpu/Makefile.targ)11
-rw-r--r--usr/src/lib/fm/topo/files/Makefile.file63
-rw-r--r--usr/src/lib/fm/topo/files/SUNW,Sun-Fire-15000/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V245/platform.topo)13
-rw-r--r--usr/src/lib/fm/topo/files/SUNW,Sun-Fire-15000/hc-topology.xml48
-rw-r--r--usr/src/lib/fm/topo/files/SUNW,Sun-Fire-T200/Makefile34
-rw-r--r--usr/src/lib/fm/topo/files/SUNW,Sun-Fire-T200/hc-topology.xml74
-rw-r--r--usr/src/lib/fm/topo/files/SUNW,Sun-Fire/Makefile34
-rw-r--r--usr/src/lib/fm/topo/files/SUNW,Sun-Fire/hc-topology.xml48
-rw-r--r--usr/src/lib/fm/topo/files/common/topology.dtd.1295
-rw-r--r--usr/src/lib/fm/topo/files/i86pc/Makefile34
-rw-r--r--usr/src/lib/fm/topo/files/i86pc/hc-topology.xml50
-rw-r--r--usr/src/lib/fm/topo/files/sun4u/Makefile34
-rw-r--r--usr/src/lib/fm/topo/files/sun4u/hc-topology.xml50
-rw-r--r--usr/src/lib/fm/topo/files/sun4v/Makefile34
-rw-r--r--usr/src/lib/fm/topo/files/sun4v/hc-topology.xml62
-rw-r--r--usr/src/lib/fm/topo/libtopo/Makefile (renamed from usr/src/lib/fm/libtopo/Makefile)13
-rw-r--r--usr/src/lib/fm/topo/libtopo/Makefile.com107
-rw-r--r--usr/src/lib/fm/topo/libtopo/amd64/Makefile (renamed from usr/src/lib/fm/libtopo/amd64/Makefile)4
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/cpu.c433
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/cpu.h43
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/hc.c776
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/hc.h43
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/hc_canon.h71
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/libtopo.h218
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/llib-ltopo (renamed from usr/src/lib/fm/libtopo/common/llib-ltopo)2
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/mem.c250
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/mkerror.sh135
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/mod.c271
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/pkg.c233
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_alloc.c97
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_alloc.h50
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_builtin.c138
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_builtin.h72
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_error.h116
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_file.c169
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_file.h59
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_fmri.c481
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_list.c185
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_list.h61
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_method.c251
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_mod.c281
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_mod.h184
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_mod.map67
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_module.c406
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_module.h105
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_node.c502
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_nvl.c70
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_parse.c229
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_parse.h159
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_prop.c676
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_prop.h78
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_protocol.c239
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_protocol.h48
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_rtld.c112
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_snap.c563
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_string.c256
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_string.h52
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_subr.c163
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_subr.h72
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_tree.c207
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_tree.h151
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_xml.c1080
-rw-r--r--usr/src/lib/fm/topo/libtopo/i386/Makefile (renamed from usr/src/lib/fm/libtopo/i386/Makefile)2
-rw-r--r--usr/src/lib/fm/topo/libtopo/sparc/Makefile (renamed from usr/src/lib/fm/libtopo/sparc/Makefile)2
-rw-r--r--usr/src/lib/fm/topo/libtopo/sparcv9/Makefile32
-rw-r--r--usr/src/lib/fm/topo/libtopo/spec/Makefile (renamed from usr/src/lib/fm/libtopo/spec/Makefile)2
-rw-r--r--usr/src/lib/fm/topo/libtopo/spec/Makefile.targ (renamed from usr/src/lib/fm/libtopo/spec/Makefile.targ)2
-rw-r--r--usr/src/lib/fm/topo/libtopo/spec/amd64/Makefile (renamed from usr/src/lib/fm/libtopo/spec/amd64/Makefile)3
-rw-r--r--usr/src/lib/fm/topo/libtopo/spec/i386/Makefile (renamed from usr/src/lib/fm/libtopo/spec/i386/Makefile)2
-rw-r--r--usr/src/lib/fm/topo/libtopo/spec/sparc/Makefile (renamed from usr/src/lib/fm/libtopo/spec/sparc/Makefile)4
-rw-r--r--usr/src/lib/fm/topo/libtopo/spec/sparcv9/Makefile (renamed from usr/src/lib/fm/libtopo/spec/sparcv9/Makefile)4
-rw-r--r--usr/src/lib/fm/topo/libtopo/spec/topo.spec377
-rw-r--r--usr/src/lib/fm/topo/libtopo/spec/versions (renamed from usr/src/lib/fm/libtopo/spec/versions)2
-rw-r--r--usr/src/lib/fm/topo/modules/Makefile (renamed from usr/src/cmd/fm/schemes/mem/Makefile.targ)11
-rw-r--r--usr/src/lib/fm/topo/modules/Makefile.plugin (renamed from usr/src/cmd/fm/topo/plugins/Makefile.plugin)70
-rw-r--r--usr/src/lib/fm/topo/modules/SUNW,Sun-Fire-15000/Makefile32
-rw-r--r--usr/src/lib/fm/topo/modules/SUNW,Sun-Fire-15000/ioboard/Makefile30
-rw-r--r--usr/src/lib/fm/topo/modules/SUNW,Sun-Fire-15000/ioboard/iob_platform.c144
-rw-r--r--usr/src/lib/fm/topo/modules/SUNW,Sun-Fire/Makefile32
-rw-r--r--usr/src/lib/fm/topo/modules/SUNW,Sun-Fire/ioboard/Makefile30
-rw-r--r--usr/src/lib/fm/topo/modules/SUNW,Sun-Fire/ioboard/iob_platform.c144
-rw-r--r--usr/src/lib/fm/topo/modules/common/did.c530
-rw-r--r--usr/src/lib/fm/topo/modules/common/did.h74
-rw-r--r--usr/src/lib/fm/topo/modules/common/did_hash.c156
-rw-r--r--usr/src/lib/fm/topo/modules/common/did_impl.h113
-rw-r--r--usr/src/lib/fm/topo/modules/common/did_props.c676
-rw-r--r--usr/src/lib/fm/topo/modules/common/did_props.h94
-rw-r--r--usr/src/lib/fm/topo/modules/common/hostbridge.c418
-rw-r--r--usr/src/lib/fm/topo/modules/common/hostbridge.h80
-rw-r--r--usr/src/lib/fm/topo/modules/common/pcibus.c530
-rw-r--r--usr/src/lib/fm/topo/modules/common/pcibus.h (renamed from usr/src/cmd/fm/topo/plugins/common/pcibus/enumpci.h)65
-rw-r--r--usr/src/lib/fm/topo/modules/common/pcibus_labels.c203
-rw-r--r--usr/src/lib/fm/topo/modules/common/pcibus_labels.h110
-rw-r--r--usr/src/lib/fm/topo/modules/common/util.c138
-rw-r--r--usr/src/lib/fm/topo/modules/common/util.h50
-rw-r--r--usr/src/lib/fm/topo/modules/i86pc/Makefile32
-rw-r--r--usr/src/lib/fm/topo/modules/i86pc/chip/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V215/Makefile)11
-rw-r--r--usr/src/lib/fm/topo/modules/i86pc/chip/chip.c689
-rw-r--r--usr/src/lib/fm/topo/modules/i86pc/chip/chip.h70
-rw-r--r--usr/src/lib/fm/topo/modules/i86pc/hostbridge/Makefile35
-rw-r--r--usr/src/lib/fm/topo/modules/i86pc/hostbridge/hb_i86pc.c127
-rw-r--r--usr/src/lib/fm/topo/modules/i86pc/pcibus/Makefile37
-rw-r--r--usr/src/lib/fm/topo/modules/i86pc/pcibus/pci_i86pc.c42
-rw-r--r--usr/src/lib/fm/topo/modules/sun4/chip/Makefile.chip (renamed from usr/src/cmd/fm/topo/plugins/common/cpu/Makefile)16
-rw-r--r--usr/src/lib/fm/topo/modules/sun4/chip/chip.c285
-rw-r--r--usr/src/lib/fm/topo/modules/sun4/hostbridge/Makefile.hb (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V445/platform.topo)31
-rw-r--r--usr/src/lib/fm/topo/modules/sun4/hostbridge/hb_sun4.c308
-rw-r--r--usr/src/lib/fm/topo/modules/sun4/hostbridge/hb_sun4.h63
-rw-r--r--usr/src/lib/fm/topo/modules/sun4/ioboard/Makefile.iob44
-rw-r--r--usr/src/lib/fm/topo/modules/sun4/ioboard/ioboard.c349
-rw-r--r--usr/src/lib/fm/topo/modules/sun4/ioboard/ioboard.h65
-rw-r--r--usr/src/lib/fm/topo/modules/sun4u/Makefile32
-rw-r--r--usr/src/lib/fm/topo/modules/sun4u/chip/Makefile (renamed from usr/src/cmd/fm/topo/files/i386/Makefile)7
-rw-r--r--usr/src/lib/fm/topo/modules/sun4u/hostbridge/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/pcidev.topo)8
-rw-r--r--usr/src/lib/fm/topo/modules/sun4u/hostbridge/hb_sun4u.c186
-rw-r--r--usr/src/lib/fm/topo/modules/sun4u/pcibus/Makefile37
-rw-r--r--usr/src/lib/fm/topo/modules/sun4u/pcibus/pci_sun4u.c43
-rw-r--r--usr/src/lib/fm/topo/modules/sun4u/pcibus/pci_sun4u.h64
-rw-r--r--usr/src/lib/fm/topo/modules/sun4v/Makefile30
-rw-r--r--usr/src/lib/fm/topo/modules/sun4v/chip/Makefile30
-rw-r--r--usr/src/lib/fm/topo/modules/sun4v/hostbridge/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/pciexdev.topo)8
-rw-r--r--usr/src/lib/fm/topo/modules/sun4v/hostbridge/hb_sun4v.c98
-rw-r--r--usr/src/lib/fm/topo/modules/sun4v/pcibus/Makefile37
-rw-r--r--usr/src/lib/fm/topo/modules/sun4v/pcibus/pci_sun4v.c43
-rw-r--r--usr/src/lib/fm/topo/modules/sun4v/pcibus/pci_sun4v.h81
-rw-r--r--usr/src/lib/libexacct/common/exacct_ops.c3
-rw-r--r--usr/src/pkgdefs/Makefile1
-rw-r--r--usr/src/pkgdefs/SUNW0on/prototype_com1
-rw-r--r--usr/src/pkgdefs/SUNWcakr.i/prototype_com47
-rw-r--r--usr/src/pkgdefs/SUNWfmd/prototype_com18
-rw-r--r--usr/src/pkgdefs/SUNWfmd/prototype_i38627
-rw-r--r--usr/src/pkgdefs/SUNWfmd/prototype_sparc105
-rw-r--r--usr/src/pkgdefs/SUNWhea/prototype_i3866
-rw-r--r--usr/src/pkgdefs/SUNWmdb/prototype_i38612
-rw-r--r--usr/src/pkgdefs/SUNWmdbr/prototype_i38612
-rw-r--r--usr/src/pkgdefs/SUNWonfmes/prototype_com5
-rw-r--r--usr/src/pkgdefs/SUNWonfmes/prototype_i3865
-rw-r--r--usr/src/pkgdefs/SUNWonmtst.i/Makefile38
-rw-r--r--usr/src/pkgdefs/SUNWonmtst.i/pkginfo.tmpl54
-rw-r--r--usr/src/pkgdefs/SUNWonmtst.i/postinstall36
-rw-r--r--usr/src/pkgdefs/SUNWonmtst.i/preremove35
-rw-r--r--usr/src/pkgdefs/SUNWonmtst.i/prototype_com (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T1000/platform.topo)53
-rw-r--r--usr/src/pkgdefs/SUNWonmtst.i/prototype_i38666
-rw-r--r--usr/src/pkgdefs/SUNWonmtst.u/pkginfo.tmpl10
-rw-r--r--usr/src/pkgdefs/SUNWonmtst.v/pkginfo.tmpl10
-rw-r--r--usr/src/tools/scripts/bfu.sh10
-rw-r--r--usr/src/tools/scripts/check_rtime.pl3
-rw-r--r--usr/src/uts/Makefile.targ5
-rw-r--r--usr/src/uts/common/io/mem.c62
-rw-r--r--usr/src/uts/common/krtld/kobj.c4
-rw-r--r--usr/src/uts/common/krtld/kobj_stubs.c4
-rw-r--r--usr/src/uts/common/os/chip.c12
-rw-r--r--usr/src/uts/common/os/cpu.c52
-rw-r--r--usr/src/uts/common/os/ddifm.c29
-rw-r--r--usr/src/uts/common/os/fm.c184
-rw-r--r--usr/src/uts/common/os/kcpc.c44
-rw-r--r--usr/src/uts/common/os/modconf.c7
-rw-r--r--usr/src/uts/common/os/modctl.c97
-rw-r--r--usr/src/uts/common/os/panic.c3
-rw-r--r--usr/src/uts/common/os/policy.c8
-rw-r--r--usr/src/uts/common/sys/Makefile13
-rw-r--r--usr/src/uts/common/sys/chip.h1
-rw-r--r--usr/src/uts/common/sys/dumphdr.h3
-rw-r--r--usr/src/uts/common/sys/fm/protocol.h15
-rw-r--r--usr/src/uts/common/sys/fm/util.h10
-rw-r--r--usr/src/uts/common/sys/kobj.h4
-rw-r--r--usr/src/uts/common/sys/mem.h10
-rw-r--r--usr/src/uts/common/sys/modctl.h51
-rw-r--r--usr/src/uts/common/sys/policy.h3
-rw-r--r--usr/src/uts/i86pc/Makefile16
-rw-r--r--usr/src/uts/i86pc/Makefile.files9
-rw-r--r--usr/src/uts/i86pc/Makefile.i86pc.shared14
-rw-r--r--usr/src/uts/i86pc/Makefile.rules42
-rw-r--r--usr/src/uts/i86pc/Makefile.workarounds10
-rw-r--r--usr/src/uts/i86pc/amd_opteron/Makefile105
-rw-r--r--usr/src/uts/i86pc/cpu/Makefile.cpu28
-rw-r--r--usr/src/uts/i86pc/cpu/Makefile.files37
-rw-r--r--usr/src/uts/i86pc/cpu/amd_opteron/ao.h235
-rw-r--r--usr/src/uts/i86pc/cpu/amd_opteron/ao_cpu.c203
-rw-r--r--usr/src/uts/i86pc/cpu/amd_opteron/ao_main.c135
-rw-r--r--usr/src/uts/i86pc/cpu/amd_opteron/ao_mc.c72
-rw-r--r--usr/src/uts/i86pc/cpu/amd_opteron/ao_mca.c811
-rw-r--r--usr/src/uts/i86pc/cpu/amd_opteron/ao_mca_disp.h67
-rw-r--r--usr/src/uts/i86pc/cpu/amd_opteron/ao_mca_disp.in778
-rw-r--r--usr/src/uts/i86pc/cpu/amd_opteron/ao_poll.c194
-rw-r--r--usr/src/uts/i86pc/cpu/generic_cpu/gcpu.h72
-rw-r--r--usr/src/uts/i86pc/cpu/generic_cpu/gcpu_main.c125
-rw-r--r--usr/src/uts/i86pc/cpu/generic_cpu/gcpu_mca.c230
-rw-r--r--usr/src/uts/i86pc/cpu/scripts/Makefile50
-rw-r--r--usr/src/uts/i86pc/cpu/scripts/ao_gendisp.pl370
-rw-r--r--usr/src/uts/i86pc/generic_cpu/Makefile82
-rw-r--r--usr/src/uts/i86pc/io/mc/mc-amd.conf (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T1000/Makefile)9
-rw-r--r--usr/src/uts/i86pc/io/mc/mcamd.h192
-rw-r--r--usr/src/uts/i86pc/io/mc/mcamd_drv.c999
-rw-r--r--usr/src/uts/i86pc/io/mc/mcamd_off.in55
-rw-r--r--usr/src/uts/i86pc/io/mc/mcamd_subr.c442
-rw-r--r--usr/src/uts/i86pc/io/rootnex.c26
-rw-r--r--usr/src/uts/i86pc/mc-amd/Makefile97
-rw-r--r--usr/src/uts/i86pc/os/cmi.c299
-rw-r--r--usr/src/uts/i86pc/os/cpuid.c5
-rw-r--r--usr/src/uts/i86pc/os/memscrub.c22
-rw-r--r--usr/src/uts/i86pc/os/mp_startup.c28
-rw-r--r--usr/src/uts/i86pc/os/startup.c106
-rw-r--r--usr/src/uts/i86pc/os/trap.c9
-rw-r--r--usr/src/uts/i86pc/sys/cpu_module.h69
-rw-r--r--usr/src/uts/i86pc/sys/cpu_module_impl.h74
-rw-r--r--usr/src/uts/i86pc/sys/machcpuvar.h5
-rw-r--r--usr/src/uts/i86pc/sys/machsystm.h2
-rw-r--r--usr/src/uts/i86pc/sys/rootnex.h19
-rw-r--r--usr/src/uts/i86pc/vm/hat_kdi.c4
-rw-r--r--usr/src/uts/intel/ia32/ml/exception.s41
-rw-r--r--usr/src/uts/intel/ia32/ml/i86_subr.s22
-rw-r--r--usr/src/uts/intel/ia32/sys/trap.h4
-rw-r--r--usr/src/uts/intel/mm/Makefile4
-rw-r--r--usr/src/uts/intel/os/driver_aliases2
-rw-r--r--usr/src/uts/intel/os/name_to_major1
-rw-r--r--usr/src/uts/intel/sys/Makefile7
-rw-r--r--usr/src/uts/intel/sys/archsystm.h4
-rw-r--r--usr/src/uts/intel/sys/controlregs.h5
-rw-r--r--usr/src/uts/intel/sys/fm/cpu/AMD.h223
-rw-r--r--usr/src/uts/intel/sys/mc.h80
-rw-r--r--usr/src/uts/intel/sys/mc_amd.h195
-rw-r--r--usr/src/uts/intel/sys/mca_amd.h418
-rw-r--r--usr/src/uts/intel/sys/mca_x86.h126
-rw-r--r--usr/src/uts/intel/sys/memtest.h126
-rw-r--r--usr/src/uts/intel/sys/x86_archext.h51
-rw-r--r--usr/src/uts/sparc/sys/Makefile35
-rw-r--r--usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-II.h (renamed from usr/src/uts/common/sys/fm/cpu/UltraSPARC-II.h)0
-rw-r--r--usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-III.h (renamed from usr/src/uts/common/sys/fm/cpu/UltraSPARC-III.h)0
-rw-r--r--usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-T1.h (renamed from usr/src/uts/common/sys/fm/cpu/UltraSPARC-T1.h)0
-rw-r--r--usr/src/uts/sun4u/cpu/us3_common.c11
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, &reg, 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, &reg, 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, &reg) < 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.