summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcindi <none@none>2006-02-11 15:36:52 -0800
committercindi <none@none>2006-02-11 15:36:52 -0800
commit7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fe (patch)
tree6d2238a19328181f6effdcd9f45c17b71b905c87
parent25145214af3b4b0be324f9115e4aee99f1e31edf (diff)
downloadillumos-joyent-7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fe.tar.gz
PSARC 2006/020 FMA for Athlon 64 and Opteron Processors
PSARC 2006/028 eversholt language enhancements 6181364 Eversholt needs method to revise value of a fault's property 6183842 eft can construct extra propagations in the instance tree 6187143 eversholt needs to use fmd_case_add_serd() to add counted ereports against open case 6232253 wildcarding may not pick up matches buried in config path 6284455 eversholt wildcarding and vertical expansion have trouble working together 6298484 properties are not auto-converting to integers in eversholt constraints 6298972 eversholt should be able to mark faults as no-message like the cpumem DE 6298974 nested SERD engines don't work 6298981 eft memory usage could improve by caching common constraint expressions 6323319 call() is not allowing string-valued returns 6323322 a global variable should be allowed as the RHS of an nvpair 6323393 eversholt caches a little too much info when caching constraints 6323554 eversholt type conversion can cause core dump 6328144 libexacct leaks like a really big sieve when faced with non-exacct input 6331093 payloadprop should be able to read and interpret hc scheme fmris 6332245 payloadprop() returns cached value from existing FME when not appropriate 6333617 eversholt should have way to check if a global is defined 6346926 eversholt needs a way to maintain diagnosis statistics 6359264 Provide FMA support for AMD64 processors 6363503 Can not register error handler callbacks for root node 6366821 cpu scheme serial number should be a string 6367031 eft.so leaks memory 6370284 cpumem-diagnosis checks the asru version against FM_EREPORT_VERSION instead of FM_CPU_SCHEME_VERSION 6377319 eft could close cases for resources already in the faulty state 6379498 fmd dies on assertion failure when repairing an fmd module 6381022 fmd_case_insert_event() should reject duplicates and save memory --HG-- rename : usr/src/cmd/fm/schemes/cpu/Makefile.targ => deleted_files/usr/src/cmd/fm/schemes/cpu/Makefile.targ rename : usr/src/cmd/fm/schemes/mem/Makefile.targ => deleted_files/usr/src/cmd/fm/schemes/mem/Makefile.targ rename : usr/src/cmd/fm/topo/Makefile => deleted_files/usr/src/cmd/fm/topo.1/Makefile rename : usr/src/cmd/fm/topo/Makefile.rootdirs => deleted_files/usr/src/cmd/fm/topo.1/Makefile.rootdirs rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T1000/Makefile => deleted_files/usr/src/cmd/fm/topo/files.1/sparc/SUNW,Sun-Fire-T1000/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T1000/platform.topo => deleted_files/usr/src/cmd/fm/topo/files.1/sparc/SUNW,Sun-Fire-T1000/platform.topo rename : usr/src/cmd/fm/topo/files/Makefile => deleted_files/usr/src/cmd/fm/topo/files/Makefile rename : usr/src/cmd/fm/topo/files/Makefile.com => deleted_files/usr/src/cmd/fm/topo/files/Makefile.com rename : usr/src/cmd/fm/topo/files/Makefile.link => deleted_files/usr/src/cmd/fm/topo/files/Makefile.link rename : usr/src/cmd/fm/topo/files/i386/Makefile => deleted_files/usr/src/cmd/fm/topo/files/i386/Makefile rename : usr/src/cmd/fm/topo/files/sparc/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,A70/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,A70/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,A70/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,A70/platform.topo rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/platform.topo rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-240/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-240/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-440/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-440/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/platform.topo rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/platform.topo rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T4/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T4/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/platform.topo rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/platform.topo rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/platform.topo rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/platform.topo rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2000/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2000/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/platform.topo rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/platform.topo rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-280R/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-280R/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/platform.topo rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/platform.topo rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/pcidev.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/pcidev.topo rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/pciexdev.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/pciexdev.topo rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/platform.topo rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V210/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V210/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V215/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V215/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/platform.topo rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V245/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V245/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V245/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V245/platform.topo rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V250/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V250/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/platform.topo rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V445/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V445/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V445/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V445/platform.topo rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V490/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V490/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V890/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V890/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/platform.topo rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/platform.topo rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/platform.topo rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/platform.topo rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/platform.topo rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/platform.topo rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/platform.topo rename : usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/Makefile rename : usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/platform.topo rename : usr/src/cmd/fm/topo/plugins/Makefile => deleted_files/usr/src/cmd/fm/topo/plugins/Makefile rename : usr/src/cmd/fm/topo/plugins/Makefile.plugin => deleted_files/usr/src/cmd/fm/topo/plugins/Makefile.plugin rename : usr/src/cmd/fm/topo/plugins/Makefile.topoonly => deleted_files/usr/src/cmd/fm/topo/plugins/Makefile.topoonly rename : usr/src/cmd/fm/topo/plugins/common/Makefile => deleted_files/usr/src/cmd/fm/topo/plugins/common/Makefile rename : usr/src/cmd/fm/topo/plugins/common/pcibus/Makefile => deleted_files/usr/src/cmd/fm/topo/plugins/common/pcibus/Makefile rename : usr/src/cmd/fm/topo/plugins/common/pcibus/enumpci.h => deleted_files/usr/src/cmd/fm/topo/plugins/common/pcibus/enumpci.h rename : usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.c => deleted_files/usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.c rename : usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.topo => deleted_files/usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.topo rename : usr/src/cmd/fm/topo/plugins/common/pciexbus/Makefile => deleted_files/usr/src/cmd/fm/topo/plugins/common/pciexbus/Makefile rename : usr/src/cmd/fm/topo/plugins/common/pciexbus/pciexbus.topo => deleted_files/usr/src/cmd/fm/topo/plugins/common/pciexbus/pciexbus.topo rename : usr/src/cmd/fm/topo/plugins/common/pciexrc/Makefile => deleted_files/usr/src/cmd/fm/topo/plugins/common/pciexrc/Makefile rename : usr/src/cmd/fm/topo/plugins/common/pciexrc/pciexrc.topo => deleted_files/usr/src/cmd/fm/topo/plugins/common/pciexrc/pciexrc.topo rename : usr/src/cmd/fm/topo/plugins/common/cpu/Makefile => deleted_files/usr/src/cmd/fm/topo/plugins/sparc/cpu/Makefile rename : usr/src/cmd/fm/topo/plugins/common/cpu/cpu.c => deleted_files/usr/src/cmd/fm/topo/plugins/sparc/cpu/cpu.c rename : usr/src/cmd/fm/topo/plugins/common/cpu/cpu.topo => deleted_files/usr/src/cmd/fm/topo/plugins/sparc/cpu/cpu.topo rename : usr/src/lib/fm/libtopo/Makefile => deleted_files/usr/src/lib/fm/libtopo/Makefile rename : usr/src/lib/fm/libtopo/Makefile.com => deleted_files/usr/src/lib/fm/libtopo/Makefile.com rename : usr/src/lib/fm/libtopo/amd64/Makefile => deleted_files/usr/src/lib/fm/libtopo/amd64/Makefile rename : usr/src/lib/fm/libtopo/common/libtopo.h => deleted_files/usr/src/lib/fm/libtopo/common/libtopo.h rename : usr/src/lib/fm/libtopo/common/libtopo_enum.h => deleted_files/usr/src/lib/fm/libtopo/common/libtopo_enum.h rename : usr/src/lib/fm/libtopo/common/llib-ltopo => deleted_files/usr/src/lib/fm/libtopo/common/llib-ltopo rename : usr/src/lib/fm/libtopo/common/topo.c => deleted_files/usr/src/lib/fm/libtopo/common/topo.c rename : usr/src/lib/fm/libtopo/common/topo_enum.c => deleted_files/usr/src/lib/fm/libtopo/common/topo_enum.c rename : usr/src/lib/fm/libtopo/common/topo_enum.h => deleted_files/usr/src/lib/fm/libtopo/common/topo_enum.h rename : usr/src/lib/fm/libtopo/common/topo_hash.c => deleted_files/usr/src/lib/fm/libtopo/common/topo_hash.c rename : usr/src/lib/fm/libtopo/common/topo_hcfmri.c => deleted_files/usr/src/lib/fm/libtopo/common/topo_hcfmri.c rename : usr/src/lib/fm/libtopo/common/topo_hcpath.c => deleted_files/usr/src/lib/fm/libtopo/common/topo_hcpath.c rename : usr/src/lib/fm/libtopo/common/topo_impl.h => deleted_files/usr/src/lib/fm/libtopo/common/topo_impl.h rename : usr/src/lib/fm/libtopo/common/topo_mem.c => deleted_files/usr/src/lib/fm/libtopo/common/topo_mem.c rename : usr/src/lib/fm/libtopo/common/topo_out.c => deleted_files/usr/src/lib/fm/libtopo/common/topo_out.c rename : usr/src/lib/fm/libtopo/common/topo_parse.c => deleted_files/usr/src/lib/fm/libtopo/common/topo_parse.c rename : usr/src/lib/fm/libtopo/common/topo_paths.c => deleted_files/usr/src/lib/fm/libtopo/common/topo_paths.c rename : usr/src/lib/fm/libtopo/common/topo_pkg.c => deleted_files/usr/src/lib/fm/libtopo/common/topo_pkg.c rename : usr/src/lib/fm/libtopo/common/topo_prop.c => deleted_files/usr/src/lib/fm/libtopo/common/topo_prop.c rename : usr/src/lib/fm/libtopo/common/topo_traverse.c => deleted_files/usr/src/lib/fm/libtopo/common/topo_traverse.c rename : usr/src/lib/fm/libtopo/i386/Makefile => deleted_files/usr/src/lib/fm/libtopo/i386/Makefile rename : usr/src/lib/fm/libtopo/sparc/Makefile => deleted_files/usr/src/lib/fm/libtopo/sparc/Makefile rename : usr/src/lib/fm/libtopo/sparcv9/Makefile => deleted_files/usr/src/lib/fm/libtopo/sparcv9/Makefile rename : usr/src/lib/fm/libtopo/spec/Makefile => deleted_files/usr/src/lib/fm/libtopo/spec/Makefile rename : usr/src/lib/fm/libtopo/spec/Makefile.targ => deleted_files/usr/src/lib/fm/libtopo/spec/Makefile.targ rename : usr/src/lib/fm/libtopo/spec/amd64/Makefile => deleted_files/usr/src/lib/fm/libtopo/spec/amd64/Makefile rename : usr/src/lib/fm/libtopo/spec/i386/Makefile => deleted_files/usr/src/lib/fm/libtopo/spec/i386/Makefile rename : usr/src/lib/fm/libtopo/spec/sparc/Makefile => deleted_files/usr/src/lib/fm/libtopo/spec/sparc/Makefile rename : usr/src/lib/fm/libtopo/spec/sparcv9/Makefile => deleted_files/usr/src/lib/fm/libtopo/spec/sparcv9/Makefile rename : usr/src/lib/fm/libtopo/spec/topo.spec => deleted_files/usr/src/lib/fm/libtopo/spec/topo.spec rename : usr/src/lib/fm/libtopo/spec/versions => deleted_files/usr/src/lib/fm/libtopo/spec/versions rename : usr/src/cmd/fm/topo/prtopo/Makefile => usr/src/cmd/fm/fmtopo/Makefile rename : usr/src/cmd/fm/topo/prtopo/Makefile.com => usr/src/cmd/fm/fmtopo/Makefile.com rename : usr/src/cmd/fm/topo/prtopo/common/prtopo.c => usr/src/cmd/fm/fmtopo/common/fmtopo.c rename : usr/src/cmd/fm/topo/prtopo/i386/Makefile => usr/src/cmd/fm/fmtopo/i386/Makefile rename : usr/src/cmd/fm/topo/prtopo/sparc/Makefile => usr/src/cmd/fm/fmtopo/sparc/Makefile rename : usr/src/cmd/fm/schemes/cpu/cpu_mdesc.c => usr/src/cmd/fm/schemes/cpu/sparc/cpu_mdesc.c rename : usr/src/cmd/fm/schemes/cpu/cpu.h => usr/src/cmd/fm/schemes/cpu/sparc/cpu_mdesc.h rename : usr/src/cmd/fm/schemes/mem/mem_disc.c => usr/src/cmd/fm/schemes/mem/sparc/mem_disc.c rename : usr/src/uts/common/sys/fm/cpu/UltraSPARC-II.h => usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-II.h rename : usr/src/uts/common/sys/fm/cpu/UltraSPARC-III.h => usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-III.h rename : usr/src/uts/common/sys/fm/cpu/UltraSPARC-T1.h => usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-T1.h
-rw-r--r--deleted_files/usr/src/cmd/fm/schemes/cpu/Makefile.targ (renamed from usr/src/cmd/fm/schemes/cpu/Makefile.targ)0
-rw-r--r--deleted_files/usr/src/cmd/fm/schemes/mem/Makefile.targ (renamed from usr/src/cmd/fm/schemes/mem/Makefile.targ)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo.1/Makefile32
-rw-r--r--deleted_files/usr/src/cmd/fm/topo.1/Makefile.rootdirs (renamed from usr/src/cmd/fm/topo/Makefile.rootdirs)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files.1/sparc/SUNW,Sun-Fire-T1000/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T1000/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files.1/sparc/SUNW,Sun-Fire-T1000/platform.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T1000/platform.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/Makefile (renamed from usr/src/cmd/fm/topo/files/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/Makefile.com (renamed from usr/src/cmd/fm/topo/files/Makefile.com)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/Makefile.link (renamed from usr/src/cmd/fm/topo/files/Makefile.link)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/i386/Makefile (renamed from usr/src/cmd/fm/topo/plugins/common/Makefile)3
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,A70/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,A70/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,A70/platform.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,A70/platform.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/platform.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/platform.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-240/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-240/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-440/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-440/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/platform.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/platform.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/platform.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/platform.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T4/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T4/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/platform.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/platform.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/platform.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/platform.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/platform.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/platform.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/platform.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/platform.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2000/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2000/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/platform.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/platform.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/platform.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/platform.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-280R/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-280R/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/platform.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/platform.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/platform.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/platform.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/pcidev.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/pcidev.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/pciexdev.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/pciexdev.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/platform.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/platform.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V210/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V210/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V215/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V215/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/platform.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/platform.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V245/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V245/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V245/platform.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V245/platform.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V250/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V250/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/platform.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/platform.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V445/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V445/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V445/platform.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V445/platform.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V490/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V490/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V890/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V890/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/platform.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/platform.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/platform.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/platform.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/platform.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/platform.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/platform.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/platform.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/platform.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/platform.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/platform.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/platform.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/platform.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/platform.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/Makefile (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/platform.topo (renamed from usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/platform.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/plugins/Makefile (renamed from usr/src/cmd/fm/topo/prtopo/Makefile)8
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/plugins/Makefile.plugin (renamed from usr/src/cmd/fm/topo/plugins/Makefile.plugin)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/plugins/Makefile.topoonly (renamed from usr/src/cmd/fm/topo/plugins/Makefile.topoonly)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/plugins/common/Makefile (renamed from usr/src/cmd/fm/topo/files/i386/Makefile)8
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/plugins/common/pcibus/Makefile (renamed from usr/src/cmd/fm/topo/plugins/common/pcibus/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/plugins/common/pcibus/enumpci.h (renamed from usr/src/cmd/fm/topo/plugins/common/pcibus/enumpci.h)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.c (renamed from usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.c)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.topo (renamed from usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/plugins/common/pciexbus/Makefile (renamed from usr/src/cmd/fm/topo/plugins/common/pciexbus/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/plugins/common/pciexbus/pciexbus.topo (renamed from usr/src/cmd/fm/topo/plugins/common/pciexbus/pciexbus.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/plugins/common/pciexrc/Makefile (renamed from usr/src/cmd/fm/topo/plugins/common/pciexrc/Makefile)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/plugins/common/pciexrc/pciexrc.topo (renamed from usr/src/cmd/fm/topo/plugins/common/pciexrc/pciexrc.topo)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/plugins/sparc/cpu/Makefile (renamed from usr/src/cmd/fm/topo/plugins/common/cpu/Makefile)2
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/plugins/sparc/cpu/cpu.c (renamed from usr/src/cmd/fm/topo/plugins/common/cpu/cpu.c)0
-rw-r--r--deleted_files/usr/src/cmd/fm/topo/plugins/sparc/cpu/cpu.topo (renamed from usr/src/cmd/fm/topo/plugins/common/cpu/cpu.topo)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/Makefile (renamed from usr/src/lib/fm/libtopo/Makefile)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/Makefile.com (renamed from usr/src/lib/fm/libtopo/Makefile.com)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/amd64/Makefile (renamed from usr/src/lib/fm/libtopo/amd64/Makefile)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/common/libtopo.h (renamed from usr/src/lib/fm/libtopo/common/libtopo.h)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/common/libtopo_enum.h (renamed from usr/src/lib/fm/libtopo/common/libtopo_enum.h)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/common/llib-ltopo (renamed from usr/src/lib/fm/libtopo/common/llib-ltopo)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/common/topo.c (renamed from usr/src/lib/fm/libtopo/common/topo.c)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/common/topo_enum.c (renamed from usr/src/lib/fm/libtopo/common/topo_enum.c)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/common/topo_enum.h (renamed from usr/src/lib/fm/libtopo/common/topo_enum.h)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/common/topo_hash.c (renamed from usr/src/lib/fm/libtopo/common/topo_hash.c)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/common/topo_hcfmri.c (renamed from usr/src/lib/fm/libtopo/common/topo_hcfmri.c)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/common/topo_hcpath.c (renamed from usr/src/lib/fm/libtopo/common/topo_hcpath.c)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/common/topo_impl.h (renamed from usr/src/lib/fm/libtopo/common/topo_impl.h)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/common/topo_mem.c (renamed from usr/src/lib/fm/libtopo/common/topo_mem.c)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/common/topo_out.c (renamed from usr/src/lib/fm/libtopo/common/topo_out.c)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/common/topo_parse.c (renamed from usr/src/lib/fm/libtopo/common/topo_parse.c)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/common/topo_paths.c (renamed from usr/src/lib/fm/libtopo/common/topo_paths.c)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/common/topo_pkg.c (renamed from usr/src/lib/fm/libtopo/common/topo_pkg.c)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/common/topo_prop.c (renamed from usr/src/lib/fm/libtopo/common/topo_prop.c)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/common/topo_traverse.c (renamed from usr/src/lib/fm/libtopo/common/topo_traverse.c)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/i386/Makefile (renamed from usr/src/lib/fm/libtopo/i386/Makefile)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/sparc/Makefile (renamed from usr/src/lib/fm/libtopo/sparc/Makefile)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/sparcv9/Makefile (renamed from usr/src/lib/fm/libtopo/sparcv9/Makefile)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/spec/Makefile (renamed from usr/src/lib/fm/libtopo/spec/Makefile)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/spec/Makefile.targ (renamed from usr/src/lib/fm/libtopo/spec/Makefile.targ)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/spec/amd64/Makefile (renamed from usr/src/lib/fm/libtopo/spec/amd64/Makefile)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/spec/i386/Makefile (renamed from usr/src/lib/fm/libtopo/spec/i386/Makefile)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/spec/sparc/Makefile (renamed from usr/src/lib/fm/libtopo/spec/sparc/Makefile)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/spec/sparcv9/Makefile (renamed from usr/src/lib/fm/libtopo/spec/sparcv9/Makefile)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/spec/topo.spec (renamed from usr/src/lib/fm/libtopo/spec/topo.spec)0
-rw-r--r--deleted_files/usr/src/lib/fm/libtopo/spec/versions (renamed from usr/src/lib/fm/libtopo/spec/versions)0
-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/Makefile31
-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/Makefile)4
-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/sparc/Makefile)4
-rw-r--r--usr/src/cmd/fm/fmtopo/sparc/Makefile (renamed from usr/src/cmd/fm/topo/prtopo/i386/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/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/Makefile41
-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/topo/Makefile30
-rw-r--r--usr/src/lib/fm/topo/Makefile.rootdirs62
-rw-r--r--usr/src/lib/fm/topo/files/Makefile33
-rw-r--r--usr/src/lib/fm/topo/files/Makefile.file63
-rw-r--r--usr/src/lib/fm/topo/files/SUNW,Sun-Fire-15000/Makefile34
-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/Makefile64
-rw-r--r--usr/src/lib/fm/topo/libtopo/Makefile.com107
-rw-r--r--usr/src/lib/fm/topo/libtopo/amd64/Makefile32
-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-ltopo32
-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/Makefile31
-rw-r--r--usr/src/lib/fm/topo/libtopo/sparc/Makefile31
-rw-r--r--usr/src/lib/fm/topo/libtopo/sparcv9/Makefile32
-rw-r--r--usr/src/lib/fm/topo/libtopo/spec/Makefile28
-rw-r--r--usr/src/lib/fm/topo/libtopo/spec/Makefile.targ32
-rw-r--r--usr/src/lib/fm/topo/libtopo/spec/amd64/Makefile36
-rw-r--r--usr/src/lib/fm/topo/libtopo/spec/i386/Makefile35
-rw-r--r--usr/src/lib/fm/topo/libtopo/spec/sparc/Makefile35
-rw-r--r--usr/src/lib/fm/topo/libtopo/spec/sparcv9/Makefile36
-rw-r--r--usr/src/lib/fm/topo/libtopo/spec/topo.spec377
-rw-r--r--usr/src/lib/fm/topo/libtopo/spec/versions41
-rw-r--r--usr/src/lib/fm/topo/modules/Makefile33
-rw-r--r--usr/src/lib/fm/topo/modules/Makefile.plugin113
-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.h82
-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/plugins/Makefile)12
-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.chip42
-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.hb44
-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/Makefile30
-rw-r--r--usr/src/lib/fm/topo/modules/sun4u/hostbridge/Makefile30
-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/Makefile30
-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_com52
-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.conf31
-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
473 files changed, 35310 insertions, 2090 deletions
diff --git a/usr/src/cmd/fm/schemes/cpu/Makefile.targ b/deleted_files/usr/src/cmd/fm/schemes/cpu/Makefile.targ
index 9a6d4cc380..9a6d4cc380 100644
--- a/usr/src/cmd/fm/schemes/cpu/Makefile.targ
+++ b/deleted_files/usr/src/cmd/fm/schemes/cpu/Makefile.targ
diff --git a/usr/src/cmd/fm/schemes/mem/Makefile.targ b/deleted_files/usr/src/cmd/fm/schemes/mem/Makefile.targ
index 9a6d4cc380..9a6d4cc380 100644
--- a/usr/src/cmd/fm/schemes/mem/Makefile.targ
+++ b/deleted_files/usr/src/cmd/fm/schemes/mem/Makefile.targ
diff --git a/deleted_files/usr/src/cmd/fm/topo.1/Makefile b/deleted_files/usr/src/cmd/fm/topo.1/Makefile
new file mode 100644
index 0000000000..3d47f31c28
--- /dev/null
+++ b/deleted_files/usr/src/cmd/fm/topo.1/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, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: 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 = prtopo
+
+.PARALLEL: $(SUBDIRS)
+
+include ../Makefile.subdirs
diff --git a/usr/src/cmd/fm/topo/Makefile.rootdirs b/deleted_files/usr/src/cmd/fm/topo.1/Makefile.rootdirs
index a5dd325bde..a5dd325bde 100644
--- a/usr/src/cmd/fm/topo/Makefile.rootdirs
+++ b/deleted_files/usr/src/cmd/fm/topo.1/Makefile.rootdirs
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T1000/Makefile b/deleted_files/usr/src/cmd/fm/topo/files.1/sparc/SUNW,Sun-Fire-T1000/Makefile
index 39217c3e28..39217c3e28 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T1000/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files.1/sparc/SUNW,Sun-Fire-T1000/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T1000/platform.topo b/deleted_files/usr/src/cmd/fm/topo/files.1/sparc/SUNW,Sun-Fire-T1000/platform.topo
index e86aa70120..e86aa70120 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T1000/platform.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files.1/sparc/SUNW,Sun-Fire-T1000/platform.topo
diff --git a/usr/src/cmd/fm/topo/files/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/Makefile
index 574ce9e926..574ce9e926 100644
--- a/usr/src/cmd/fm/topo/files/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/Makefile
diff --git a/usr/src/cmd/fm/topo/files/Makefile.com b/deleted_files/usr/src/cmd/fm/topo/files/Makefile.com
index 94c89d5321..94c89d5321 100644
--- a/usr/src/cmd/fm/topo/files/Makefile.com
+++ b/deleted_files/usr/src/cmd/fm/topo/files/Makefile.com
diff --git a/usr/src/cmd/fm/topo/files/Makefile.link b/deleted_files/usr/src/cmd/fm/topo/files/Makefile.link
index 3b5c1edf6a..3b5c1edf6a 100644
--- a/usr/src/cmd/fm/topo/files/Makefile.link
+++ b/deleted_files/usr/src/cmd/fm/topo/files/Makefile.link
diff --git a/usr/src/cmd/fm/topo/plugins/common/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/i386/Makefile
index 0fe2af7cd4..9243dc07ad 100644
--- a/usr/src/cmd/fm/topo/plugins/common/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/i386/Makefile
@@ -20,11 +20,12 @@
# 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
+SUBDIRS=i86pc
include ../../../Makefile.subdirs
diff --git a/usr/src/cmd/fm/topo/files/sparc/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/Makefile
index 7bbb0e2e99..7bbb0e2e99 100644
--- a/usr/src/cmd/fm/topo/files/sparc/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,A70/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,A70/Makefile
index 3a8d5d0672..3a8d5d0672 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,A70/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,A70/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,A70/platform.topo b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,A70/platform.topo
index b55863c221..b55863c221 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,A70/platform.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,A70/platform.topo
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/Makefile
index 17a2ca9c00..17a2ca9c00 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/platform.topo b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/platform.topo
index 5cd6976d77..5cd6976d77 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/platform.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/platform.topo
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-240/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-240/Makefile
index 04a6489a52..04a6489a52 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-240/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-240/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-440/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-440/Makefile
index 192b58a8ce..192b58a8ce 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-440/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-440/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/Makefile
index 8609abc0a4..8609abc0a4 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/platform.topo b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/platform.topo
index 33ccefd72b..33ccefd72b 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/platform.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/platform.topo
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/Makefile
index b4cd75dcb4..b4cd75dcb4 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/platform.topo b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/platform.topo
index b6b3b2ab7c..b6b3b2ab7c 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/platform.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/platform.topo
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T4/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T4/Makefile
index 26472c41cc..26472c41cc 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T4/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T4/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/Makefile
index b932fafe47..b932fafe47 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/platform.topo b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/platform.topo
index af945e81f1..af945e81f1 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/platform.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/platform.topo
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/Makefile
index 623338e2b0..623338e2b0 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/platform.topo b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/platform.topo
index b6b3b2ab7c..b6b3b2ab7c 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/platform.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/platform.topo
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/Makefile
index f3d82206fb..f3d82206fb 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/platform.topo b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/platform.topo
index d00b1b193a..d00b1b193a 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/platform.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/platform.topo
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/Makefile
index e8ccdf4f45..e8ccdf4f45 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/platform.topo b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/platform.topo
index c0c66425fc..c0c66425fc 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/platform.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/platform.topo
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2000/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2000/Makefile
index 5b5b83a1e3..5b5b83a1e3 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2000/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2000/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/Makefile
index 1d199d3dc3..1d199d3dc3 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/platform.topo b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/platform.topo
index 3aff5d0863..3aff5d0863 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/platform.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/platform.topo
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/Makefile
index 8708fe41ef..8708fe41ef 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/platform.topo b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/platform.topo
index 7965029b45..7965029b45 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/platform.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/platform.topo
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-280R/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-280R/Makefile
index fc151bb329..fc151bb329 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-280R/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-280R/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/Makefile
index c2cf89171c..c2cf89171c 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/platform.topo b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/platform.topo
index 7510d663ec..7510d663ec 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/platform.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/platform.topo
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/Makefile
index 55f1ec0243..55f1ec0243 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/platform.topo b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/platform.topo
index 3cb91171c7..3cb91171c7 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/platform.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/platform.topo
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/Makefile
index d1ca0989ed..d1ca0989ed 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/pcidev.topo b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/pcidev.topo
index d66742bb72..d66742bb72 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/pcidev.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/pcidev.topo
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/pciexdev.topo b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/pciexdev.topo
index f111eb5edf..f111eb5edf 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/pciexdev.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/pciexdev.topo
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/platform.topo b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/platform.topo
index 7eadf1e78e..7eadf1e78e 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/platform.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/platform.topo
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V210/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V210/Makefile
index 900733d401..900733d401 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V210/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V210/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V215/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V215/Makefile
index 4a575514e1..4a575514e1 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V215/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V215/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/Makefile
index 0e3b2b181d..0e3b2b181d 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/platform.topo b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/platform.topo
index fc729ba5d0..fc729ba5d0 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/platform.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/platform.topo
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V245/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V245/Makefile
index 55fe0e0381..55fe0e0381 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V245/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V245/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V245/platform.topo b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V245/platform.topo
index 6624b54bba..6624b54bba 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V245/platform.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V245/platform.topo
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V250/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V250/Makefile
index 1ddc691c28..1ddc691c28 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V250/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V250/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/Makefile
index e97ffd76d4..e97ffd76d4 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/platform.topo b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/platform.topo
index f82ed5372f..f82ed5372f 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/platform.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/platform.topo
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V445/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V445/Makefile
index 30c479d087..30c479d087 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V445/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V445/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V445/platform.topo b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V445/platform.topo
index 0658cf339a..0658cf339a 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V445/platform.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V445/platform.topo
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V490/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V490/Makefile
index 0e4595998e..0e4595998e 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V490/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V490/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V890/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V890/Makefile
index e341194dcf..e341194dcf 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V890/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V890/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/Makefile
index f7f91392d7..f7f91392d7 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/platform.topo b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/platform.topo
index 7e50119475..7e50119475 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/platform.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/platform.topo
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/Makefile
index 305b3afe74..305b3afe74 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/platform.topo b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/platform.topo
index 37f4a5facf..37f4a5facf 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/platform.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/platform.topo
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/Makefile
index 922adf3f93..922adf3f93 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/platform.topo b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/platform.topo
index 489190b024..489190b024 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/platform.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/platform.topo
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/Makefile
index 52d0dae65c..52d0dae65c 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/platform.topo b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/platform.topo
index 11da242e85..11da242e85 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/platform.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/platform.topo
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/Makefile
index 15f0f384d3..15f0f384d3 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/platform.topo b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/platform.topo
index 6bd0e748f7..6bd0e748f7 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/platform.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/platform.topo
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/Makefile
index 418ac83ea9..418ac83ea9 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/platform.topo b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/platform.topo
index e647ce28c6..e647ce28c6 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/platform.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/platform.topo
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/Makefile
index e65a1cc3c2..e65a1cc3c2 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/platform.topo b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/platform.topo
index 440d76e7eb..440d76e7eb 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/platform.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/platform.topo
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/Makefile b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/Makefile
index bc3a4649a8..bc3a4649a8 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/Makefile
diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/platform.topo b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/platform.topo
index b16b0379a4..b16b0379a4 100644
--- a/usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/platform.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/platform.topo
diff --git a/usr/src/cmd/fm/topo/prtopo/Makefile b/deleted_files/usr/src/cmd/fm/topo/plugins/Makefile
index 18bde5d7dc..46cebd242c 100644
--- a/usr/src/cmd/fm/topo/prtopo/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/plugins/Makefile
@@ -20,15 +20,13 @@
# CDDL HEADER END
#
#
-# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
-debug := TARGET += debug
+SUBDIRS = common $(MACH)
-SUBDIRS = $(MACH)
-
-debug: $(SUBDIRS)
+.PARALLEL: $(SUBDIRS)
include ../../Makefile.subdirs
diff --git a/usr/src/cmd/fm/topo/plugins/Makefile.plugin b/deleted_files/usr/src/cmd/fm/topo/plugins/Makefile.plugin
index c0db88713a..c0db88713a 100644
--- a/usr/src/cmd/fm/topo/plugins/Makefile.plugin
+++ b/deleted_files/usr/src/cmd/fm/topo/plugins/Makefile.plugin
diff --git a/usr/src/cmd/fm/topo/plugins/Makefile.topoonly b/deleted_files/usr/src/cmd/fm/topo/plugins/Makefile.topoonly
index 9661ae784a..9661ae784a 100644
--- a/usr/src/cmd/fm/topo/plugins/Makefile.topoonly
+++ b/deleted_files/usr/src/cmd/fm/topo/plugins/Makefile.topoonly
diff --git a/usr/src/cmd/fm/topo/files/i386/Makefile b/deleted_files/usr/src/cmd/fm/topo/plugins/common/Makefile
index 53c91fb757..a77c1c1884 100644
--- a/usr/src/cmd/fm/topo/files/i386/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/plugins/common/Makefile
@@ -20,12 +20,14 @@
# CDDL HEADER END
#
#
-#
-# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
-SUBDIRS=
+SUBDIRS = \
+ pcibus \
+ pciexbus \
+ pciexrc
include ../../../Makefile.subdirs
diff --git a/usr/src/cmd/fm/topo/plugins/common/pcibus/Makefile b/deleted_files/usr/src/cmd/fm/topo/plugins/common/pcibus/Makefile
index 88e0e82d4e..88e0e82d4e 100644
--- a/usr/src/cmd/fm/topo/plugins/common/pcibus/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/plugins/common/pcibus/Makefile
diff --git a/usr/src/cmd/fm/topo/plugins/common/pcibus/enumpci.h b/deleted_files/usr/src/cmd/fm/topo/plugins/common/pcibus/enumpci.h
index e998bb5603..e998bb5603 100644
--- a/usr/src/cmd/fm/topo/plugins/common/pcibus/enumpci.h
+++ b/deleted_files/usr/src/cmd/fm/topo/plugins/common/pcibus/enumpci.h
diff --git a/usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.c b/deleted_files/usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.c
index 934dbb4a24..934dbb4a24 100644
--- a/usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.c
+++ b/deleted_files/usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.c
diff --git a/usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.topo b/deleted_files/usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.topo
index 76d51514e7..76d51514e7 100644
--- a/usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.topo
diff --git a/usr/src/cmd/fm/topo/plugins/common/pciexbus/Makefile b/deleted_files/usr/src/cmd/fm/topo/plugins/common/pciexbus/Makefile
index be0539f7ef..be0539f7ef 100644
--- a/usr/src/cmd/fm/topo/plugins/common/pciexbus/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/plugins/common/pciexbus/Makefile
diff --git a/usr/src/cmd/fm/topo/plugins/common/pciexbus/pciexbus.topo b/deleted_files/usr/src/cmd/fm/topo/plugins/common/pciexbus/pciexbus.topo
index ca5b09a73e..ca5b09a73e 100644
--- a/usr/src/cmd/fm/topo/plugins/common/pciexbus/pciexbus.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/plugins/common/pciexbus/pciexbus.topo
diff --git a/usr/src/cmd/fm/topo/plugins/common/pciexrc/Makefile b/deleted_files/usr/src/cmd/fm/topo/plugins/common/pciexrc/Makefile
index a92a602f48..a92a602f48 100644
--- a/usr/src/cmd/fm/topo/plugins/common/pciexrc/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/plugins/common/pciexrc/Makefile
diff --git a/usr/src/cmd/fm/topo/plugins/common/pciexrc/pciexrc.topo b/deleted_files/usr/src/cmd/fm/topo/plugins/common/pciexrc/pciexrc.topo
index 897abf307a..897abf307a 100644
--- a/usr/src/cmd/fm/topo/plugins/common/pciexrc/pciexrc.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/plugins/common/pciexrc/pciexrc.topo
diff --git a/usr/src/cmd/fm/topo/plugins/common/cpu/Makefile b/deleted_files/usr/src/cmd/fm/topo/plugins/sparc/cpu/Makefile
index 266924d296..0211b98e42 100644
--- a/usr/src/cmd/fm/topo/plugins/common/cpu/Makefile
+++ b/deleted_files/usr/src/cmd/fm/topo/plugins/sparc/cpu/Makefile
@@ -20,7 +20,7 @@
# CDDL HEADER END
#
#
-# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
diff --git a/usr/src/cmd/fm/topo/plugins/common/cpu/cpu.c b/deleted_files/usr/src/cmd/fm/topo/plugins/sparc/cpu/cpu.c
index 77c81f601e..77c81f601e 100644
--- a/usr/src/cmd/fm/topo/plugins/common/cpu/cpu.c
+++ b/deleted_files/usr/src/cmd/fm/topo/plugins/sparc/cpu/cpu.c
diff --git a/usr/src/cmd/fm/topo/plugins/common/cpu/cpu.topo b/deleted_files/usr/src/cmd/fm/topo/plugins/sparc/cpu/cpu.topo
index 5089cf3883..5089cf3883 100644
--- a/usr/src/cmd/fm/topo/plugins/common/cpu/cpu.topo
+++ b/deleted_files/usr/src/cmd/fm/topo/plugins/sparc/cpu/cpu.topo
diff --git a/usr/src/lib/fm/libtopo/Makefile b/deleted_files/usr/src/lib/fm/libtopo/Makefile
index 8e4e1333c1..8e4e1333c1 100644
--- a/usr/src/lib/fm/libtopo/Makefile
+++ b/deleted_files/usr/src/lib/fm/libtopo/Makefile
diff --git a/usr/src/lib/fm/libtopo/Makefile.com b/deleted_files/usr/src/lib/fm/libtopo/Makefile.com
index e040b41286..e040b41286 100644
--- a/usr/src/lib/fm/libtopo/Makefile.com
+++ b/deleted_files/usr/src/lib/fm/libtopo/Makefile.com
diff --git a/usr/src/lib/fm/libtopo/amd64/Makefile b/deleted_files/usr/src/lib/fm/libtopo/amd64/Makefile
index 07fe45208f..07fe45208f 100644
--- a/usr/src/lib/fm/libtopo/amd64/Makefile
+++ b/deleted_files/usr/src/lib/fm/libtopo/amd64/Makefile
diff --git a/usr/src/lib/fm/libtopo/common/libtopo.h b/deleted_files/usr/src/lib/fm/libtopo/common/libtopo.h
index 99b8930285..99b8930285 100644
--- a/usr/src/lib/fm/libtopo/common/libtopo.h
+++ b/deleted_files/usr/src/lib/fm/libtopo/common/libtopo.h
diff --git a/usr/src/lib/fm/libtopo/common/libtopo_enum.h b/deleted_files/usr/src/lib/fm/libtopo/common/libtopo_enum.h
index bd83ea7961..bd83ea7961 100644
--- a/usr/src/lib/fm/libtopo/common/libtopo_enum.h
+++ b/deleted_files/usr/src/lib/fm/libtopo/common/libtopo_enum.h
diff --git a/usr/src/lib/fm/libtopo/common/llib-ltopo b/deleted_files/usr/src/lib/fm/libtopo/common/llib-ltopo
index f1f4120dfd..f1f4120dfd 100644
--- a/usr/src/lib/fm/libtopo/common/llib-ltopo
+++ b/deleted_files/usr/src/lib/fm/libtopo/common/llib-ltopo
diff --git a/usr/src/lib/fm/libtopo/common/topo.c b/deleted_files/usr/src/lib/fm/libtopo/common/topo.c
index a24a685caa..a24a685caa 100644
--- a/usr/src/lib/fm/libtopo/common/topo.c
+++ b/deleted_files/usr/src/lib/fm/libtopo/common/topo.c
diff --git a/usr/src/lib/fm/libtopo/common/topo_enum.c b/deleted_files/usr/src/lib/fm/libtopo/common/topo_enum.c
index a5e80cc1ed..a5e80cc1ed 100644
--- a/usr/src/lib/fm/libtopo/common/topo_enum.c
+++ b/deleted_files/usr/src/lib/fm/libtopo/common/topo_enum.c
diff --git a/usr/src/lib/fm/libtopo/common/topo_enum.h b/deleted_files/usr/src/lib/fm/libtopo/common/topo_enum.h
index f2cdc15b25..f2cdc15b25 100644
--- a/usr/src/lib/fm/libtopo/common/topo_enum.h
+++ b/deleted_files/usr/src/lib/fm/libtopo/common/topo_enum.h
diff --git a/usr/src/lib/fm/libtopo/common/topo_hash.c b/deleted_files/usr/src/lib/fm/libtopo/common/topo_hash.c
index adfeb5a6a2..adfeb5a6a2 100644
--- a/usr/src/lib/fm/libtopo/common/topo_hash.c
+++ b/deleted_files/usr/src/lib/fm/libtopo/common/topo_hash.c
diff --git a/usr/src/lib/fm/libtopo/common/topo_hcfmri.c b/deleted_files/usr/src/lib/fm/libtopo/common/topo_hcfmri.c
index 471e54476e..471e54476e 100644
--- a/usr/src/lib/fm/libtopo/common/topo_hcfmri.c
+++ b/deleted_files/usr/src/lib/fm/libtopo/common/topo_hcfmri.c
diff --git a/usr/src/lib/fm/libtopo/common/topo_hcpath.c b/deleted_files/usr/src/lib/fm/libtopo/common/topo_hcpath.c
index b48800f700..b48800f700 100644
--- a/usr/src/lib/fm/libtopo/common/topo_hcpath.c
+++ b/deleted_files/usr/src/lib/fm/libtopo/common/topo_hcpath.c
diff --git a/usr/src/lib/fm/libtopo/common/topo_impl.h b/deleted_files/usr/src/lib/fm/libtopo/common/topo_impl.h
index 47655fd774..47655fd774 100644
--- a/usr/src/lib/fm/libtopo/common/topo_impl.h
+++ b/deleted_files/usr/src/lib/fm/libtopo/common/topo_impl.h
diff --git a/usr/src/lib/fm/libtopo/common/topo_mem.c b/deleted_files/usr/src/lib/fm/libtopo/common/topo_mem.c
index 8898f03e07..8898f03e07 100644
--- a/usr/src/lib/fm/libtopo/common/topo_mem.c
+++ b/deleted_files/usr/src/lib/fm/libtopo/common/topo_mem.c
diff --git a/usr/src/lib/fm/libtopo/common/topo_out.c b/deleted_files/usr/src/lib/fm/libtopo/common/topo_out.c
index 7bd2d902e1..7bd2d902e1 100644
--- a/usr/src/lib/fm/libtopo/common/topo_out.c
+++ b/deleted_files/usr/src/lib/fm/libtopo/common/topo_out.c
diff --git a/usr/src/lib/fm/libtopo/common/topo_parse.c b/deleted_files/usr/src/lib/fm/libtopo/common/topo_parse.c
index ccec7bb60e..ccec7bb60e 100644
--- a/usr/src/lib/fm/libtopo/common/topo_parse.c
+++ b/deleted_files/usr/src/lib/fm/libtopo/common/topo_parse.c
diff --git a/usr/src/lib/fm/libtopo/common/topo_paths.c b/deleted_files/usr/src/lib/fm/libtopo/common/topo_paths.c
index 796a3c7ce5..796a3c7ce5 100644
--- a/usr/src/lib/fm/libtopo/common/topo_paths.c
+++ b/deleted_files/usr/src/lib/fm/libtopo/common/topo_paths.c
diff --git a/usr/src/lib/fm/libtopo/common/topo_pkg.c b/deleted_files/usr/src/lib/fm/libtopo/common/topo_pkg.c
index 557f41f8f9..557f41f8f9 100644
--- a/usr/src/lib/fm/libtopo/common/topo_pkg.c
+++ b/deleted_files/usr/src/lib/fm/libtopo/common/topo_pkg.c
diff --git a/usr/src/lib/fm/libtopo/common/topo_prop.c b/deleted_files/usr/src/lib/fm/libtopo/common/topo_prop.c
index 7cfe59ee81..7cfe59ee81 100644
--- a/usr/src/lib/fm/libtopo/common/topo_prop.c
+++ b/deleted_files/usr/src/lib/fm/libtopo/common/topo_prop.c
diff --git a/usr/src/lib/fm/libtopo/common/topo_traverse.c b/deleted_files/usr/src/lib/fm/libtopo/common/topo_traverse.c
index 0afcac88c2..0afcac88c2 100644
--- a/usr/src/lib/fm/libtopo/common/topo_traverse.c
+++ b/deleted_files/usr/src/lib/fm/libtopo/common/topo_traverse.c
diff --git a/usr/src/lib/fm/libtopo/i386/Makefile b/deleted_files/usr/src/lib/fm/libtopo/i386/Makefile
index 905c136359..905c136359 100644
--- a/usr/src/lib/fm/libtopo/i386/Makefile
+++ b/deleted_files/usr/src/lib/fm/libtopo/i386/Makefile
diff --git a/usr/src/lib/fm/libtopo/sparc/Makefile b/deleted_files/usr/src/lib/fm/libtopo/sparc/Makefile
index 65682c4299..65682c4299 100644
--- a/usr/src/lib/fm/libtopo/sparc/Makefile
+++ b/deleted_files/usr/src/lib/fm/libtopo/sparc/Makefile
diff --git a/usr/src/lib/fm/libtopo/sparcv9/Makefile b/deleted_files/usr/src/lib/fm/libtopo/sparcv9/Makefile
index 98cef7b91a..98cef7b91a 100644
--- a/usr/src/lib/fm/libtopo/sparcv9/Makefile
+++ b/deleted_files/usr/src/lib/fm/libtopo/sparcv9/Makefile
diff --git a/usr/src/lib/fm/libtopo/spec/Makefile b/deleted_files/usr/src/lib/fm/libtopo/spec/Makefile
index babb709ad7..babb709ad7 100644
--- a/usr/src/lib/fm/libtopo/spec/Makefile
+++ b/deleted_files/usr/src/lib/fm/libtopo/spec/Makefile
diff --git a/usr/src/lib/fm/libtopo/spec/Makefile.targ b/deleted_files/usr/src/lib/fm/libtopo/spec/Makefile.targ
index 50e80a5d55..50e80a5d55 100644
--- a/usr/src/lib/fm/libtopo/spec/Makefile.targ
+++ b/deleted_files/usr/src/lib/fm/libtopo/spec/Makefile.targ
diff --git a/usr/src/lib/fm/libtopo/spec/amd64/Makefile b/deleted_files/usr/src/lib/fm/libtopo/spec/amd64/Makefile
index 2445e1779f..2445e1779f 100644
--- a/usr/src/lib/fm/libtopo/spec/amd64/Makefile
+++ b/deleted_files/usr/src/lib/fm/libtopo/spec/amd64/Makefile
diff --git a/usr/src/lib/fm/libtopo/spec/i386/Makefile b/deleted_files/usr/src/lib/fm/libtopo/spec/i386/Makefile
index 684c03a198..684c03a198 100644
--- a/usr/src/lib/fm/libtopo/spec/i386/Makefile
+++ b/deleted_files/usr/src/lib/fm/libtopo/spec/i386/Makefile
diff --git a/usr/src/lib/fm/libtopo/spec/sparc/Makefile b/deleted_files/usr/src/lib/fm/libtopo/spec/sparc/Makefile
index 281960b060..281960b060 100644
--- a/usr/src/lib/fm/libtopo/spec/sparc/Makefile
+++ b/deleted_files/usr/src/lib/fm/libtopo/spec/sparc/Makefile
diff --git a/usr/src/lib/fm/libtopo/spec/sparcv9/Makefile b/deleted_files/usr/src/lib/fm/libtopo/spec/sparcv9/Makefile
index 9f9cb6ace4..9f9cb6ace4 100644
--- a/usr/src/lib/fm/libtopo/spec/sparcv9/Makefile
+++ b/deleted_files/usr/src/lib/fm/libtopo/spec/sparcv9/Makefile
diff --git a/usr/src/lib/fm/libtopo/spec/topo.spec b/deleted_files/usr/src/lib/fm/libtopo/spec/topo.spec
index cf47f3b17c..cf47f3b17c 100644
--- a/usr/src/lib/fm/libtopo/spec/topo.spec
+++ b/deleted_files/usr/src/lib/fm/libtopo/spec/topo.spec
diff --git a/usr/src/lib/fm/libtopo/spec/versions b/deleted_files/usr/src/lib/fm/libtopo/spec/versions
index de52db1857..de52db1857 100644
--- a/usr/src/lib/fm/libtopo/spec/versions
+++ b/deleted_files/usr/src/lib/fm/libtopo/spec/versions
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/eversholt/files/i386/i86pc/Makefile b/usr/src/cmd/fm/eversholt/files/i386/i86pc/Makefile
new file mode 100644
index 0000000000..0f12c27e70
--- /dev/null
+++ b/usr/src/cmd/fm/eversholt/files/i386/i86pc/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"
+
+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/Makefile b/usr/src/cmd/fm/fmtopo/Makefile
index b8d2a772bb..2e8360f71f 100644
--- a/usr/src/cmd/fm/topo/Makefile
+++ b/usr/src/cmd/fm/fmtopo/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 = $(MACH)
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/sparc/Makefile b/usr/src/cmd/fm/fmtopo/i386/Makefile
index 617fb6a35b..719d6803ef 100644
--- a/usr/src/cmd/fm/topo/prtopo/sparc/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/i386/Makefile b/usr/src/cmd/fm/fmtopo/sparc/Makefile
index 617fb6a35b..719d6803ef 100644
--- a/usr/src/cmd/fm/topo/prtopo/i386/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/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/mdb/i86pc/modules/amd_opteron/ia32/Makefile b/usr/src/cmd/mdb/i86pc/modules/amd_opteron/ia32/Makefile
new file mode 100644
index 0000000000..9f6cd0fe8e
--- /dev/null
+++ b/usr/src/cmd/mdb/i86pc/modules/amd_opteron/ia32/Makefile
@@ -0,0 +1,41 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: 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 ../../../../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/topo/Makefile b/usr/src/lib/fm/topo/Makefile
new file mode 100644
index 0000000000..6d0f9d2e68
--- /dev/null
+++ b/usr/src/lib/fm/topo/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"
+
+SUBDIRS = libtopo modules files
+
+include ../Makefile.subdirs
diff --git a/usr/src/lib/fm/topo/Makefile.rootdirs b/usr/src/lib/fm/topo/Makefile.rootdirs
new file mode 100644
index 0000000000..6cb20f44ba
--- /dev/null
+++ b/usr/src/lib/fm/topo/Makefile.rootdirs
@@ -0,0 +1,62 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: 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"
+
+#
+# Define the transitive set of rules to create a common module's install dir
+# within the proto area. This is used by all Makefile.<class> files.
+#
+$(ROOT)/usr/lib/fm:
+ $(INS.dir)
+
+$(ROOT)/usr/lib/fm/topo: $(ROOT)/usr/lib/fm
+ $(INS.dir)
+
+$(ROOT)/usr/lib/fm/topo/%: $(ROOT)/usr/lib/fm/topo
+ $(INS.dir)
+
+#
+# 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/lib/fm/topo/files/Makefile b/usr/src/lib/fm/topo/files/Makefile
new file mode 100644
index 0000000000..8a76e32968
--- /dev/null
+++ b/usr/src/lib/fm/topo/files/Makefile
@@ -0,0 +1,33 @@
+#
+# 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"
+
+sparc_SUBDIRS = sun4u sun4v SUNW,Sun-Fire SUNW,Sun-Fire-T200 SUNW,Sun-Fire-15000
+i386_SUBDIRS = i86pc
+
+SUBDIRS = $($(MACH)_SUBDIRS)
+
+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/lib/fm/topo/files/SUNW,Sun-Fire-15000/Makefile b/usr/src/lib/fm/topo/files/SUNW,Sun-Fire-15000/Makefile
new file mode 100644
index 0000000000..c876d2ff4a
--- /dev/null
+++ b/usr/src/lib/fm/topo/files/SUNW,Sun-Fire-15000/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-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/topo/libtopo/Makefile b/usr/src/lib/fm/topo/libtopo/Makefile
new file mode 100644
index 0000000000..506f95de93
--- /dev/null
+++ b/usr/src/lib/fm/topo/libtopo/Makefile
@@ -0,0 +1,64 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: 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
+
+FMHDRS = libtopo.h topo_mod.h
+HDRDIR = common
+
+MACH_SUBDIRS = $(MACH)
+
+SUBDIRS = $(MACH)
+
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber: spec .WAIT $(SUBDIRS)
+
+install: install_h spec .WAIT $(SUBDIRS)
+
+lint: $(SUBDIRS)
+
+install_h: $(ROOTFMHDRS)
+
+check: $(CHECKHDRS)
+
+spec $(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+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/topo/libtopo/amd64/Makefile b/usr/src/lib/fm/topo/libtopo/amd64/Makefile
new file mode 100644
index 0000000000..15debba846
--- /dev/null
+++ b/usr/src/lib/fm/topo/libtopo/amd64/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, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: 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/amd64
+include ../Makefile.com
+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/topo/libtopo/common/llib-ltopo b/usr/src/lib/fm/topo/libtopo/common/llib-ltopo
new file mode 100644
index 0000000000..b6b2228c63
--- /dev/null
+++ b/usr/src/lib/fm/topo/libtopo/common/llib-ltopo
@@ -0,0 +1,32 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: 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"
+
+/*LINTLIBRARY*/
+/*PROTOLIB1*/
+
+#include <fm/libtopo.h>
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/topo/libtopo/i386/Makefile b/usr/src/lib/fm/topo/libtopo/i386/Makefile
new file mode 100644
index 0000000000..c4b1489ab7
--- /dev/null
+++ b/usr/src/lib/fm/topo/libtopo/i386/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"
+
+MAPDIR = ../spec/i386
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/fm/topo/libtopo/sparc/Makefile b/usr/src/lib/fm/topo/libtopo/sparc/Makefile
new file mode 100644
index 0000000000..a925bc82f9
--- /dev/null
+++ b/usr/src/lib/fm/topo/libtopo/sparc/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"
+
+MAPDIR = ../spec/sparc
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
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/topo/libtopo/spec/Makefile b/usr/src/lib/fm/topo/libtopo/spec/Makefile
new file mode 100644
index 0000000000..1208d7a09f
--- /dev/null
+++ b/usr/src/lib/fm/topo/libtopo/spec/Makefile
@@ -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 $(SRC)/lib/Makefile.spec.arch
diff --git a/usr/src/lib/fm/topo/libtopo/spec/Makefile.targ b/usr/src/lib/fm/topo/libtopo/spec/Makefile.targ
new file mode 100644
index 0000000000..e1102bd53f
--- /dev/null
+++ b/usr/src/lib/fm/topo/libtopo/spec/Makefile.targ
@@ -0,0 +1,32 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: 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"
+
+.KEEP_STATE:
+
+LIBRARY = libtopo.a
+VERS = .1
+OBJECTS = topo.o
diff --git a/usr/src/lib/fm/topo/libtopo/spec/amd64/Makefile b/usr/src/lib/fm/topo/libtopo/spec/amd64/Makefile
new file mode 100644
index 0000000000..a04ea5eb47
--- /dev/null
+++ b/usr/src/lib/fm/topo/libtopo/spec/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"
+
+# To enable apptrace, comment out the next line
+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/topo/libtopo/spec/i386/Makefile b/usr/src/lib/fm/topo/libtopo/spec/i386/Makefile
new file mode 100644
index 0000000000..afd97ec009
--- /dev/null
+++ b/usr/src/lib/fm/topo/libtopo/spec/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"
+
+# To enable apptrace, comment out the next line
+DISABLE_APPTRACE= $(POUND_SIGN)
+
+include ../Makefile.targ
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.spec
+
+$(DISABLE_APPTRACE)install: $(ROOTABILIB)
diff --git a/usr/src/lib/fm/topo/libtopo/spec/sparc/Makefile b/usr/src/lib/fm/topo/libtopo/spec/sparc/Makefile
new file mode 100644
index 0000000000..afd97ec009
--- /dev/null
+++ b/usr/src/lib/fm/topo/libtopo/spec/sparc/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"
+
+# To enable apptrace, comment out the next line
+DISABLE_APPTRACE= $(POUND_SIGN)
+
+include ../Makefile.targ
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.spec
+
+$(DISABLE_APPTRACE)install: $(ROOTABILIB)
diff --git a/usr/src/lib/fm/topo/libtopo/spec/sparcv9/Makefile b/usr/src/lib/fm/topo/libtopo/spec/sparcv9/Makefile
new file mode 100644
index 0000000000..a04ea5eb47
--- /dev/null
+++ b/usr/src/lib/fm/topo/libtopo/spec/sparcv9/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"
+
+# To enable apptrace, comment out the next line
+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/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/topo/libtopo/spec/versions b/usr/src/lib/fm/topo/libtopo/spec/versions
new file mode 100644
index 0000000000..7a65542162
--- /dev/null
+++ b/usr/src/lib/fm/topo/libtopo/spec/versions
@@ -0,0 +1,41 @@
+#
+# 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"
+
+i386 {
+ SUNWprivate;
+}
+
+amd64 {
+ SUNWprivate;
+}
+
+sparc {
+ SUNWprivate;
+}
+
+sparcv9 {
+ SUNWprivate;
+}
diff --git a/usr/src/lib/fm/topo/modules/Makefile b/usr/src/lib/fm/topo/modules/Makefile
new file mode 100644
index 0000000000..97ab5867d8
--- /dev/null
+++ b/usr/src/lib/fm/topo/modules/Makefile
@@ -0,0 +1,33 @@
+#
+# 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"
+
+sparc_SUBDIRS = sun4u sun4v SUNW,Sun-Fire SUNW,Sun-Fire-15000
+i386_SUBDIRS = i86pc
+
+SUBDIRS = $($(MACH)_SUBDIRS)
+
+include ../../Makefile.subdirs
diff --git a/usr/src/lib/fm/topo/modules/Makefile.plugin b/usr/src/lib/fm/topo/modules/Makefile.plugin
new file mode 100644
index 0000000000..e711bbd58d
--- /dev/null
+++ b/usr/src/lib/fm/topo/modules/Makefile.plugin
@@ -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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+.KEEP_STATE:
+.SUFFIXES:
+
+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)
+OBJS = $(SRCS:%.c=%.o)
+
+#
+# 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_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)
+
+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)
+
+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 += $(ZIGNORE) -M$(APIMAP)
+LDLIBS += -L$(ROOTLIBDIR)/fm -R/usr/lib/fm -ltopo -lnvpair -lc
+
+all: $(PROG)
+
+.NO_PARALLEL:
+.PARALLEL: $(OBJS) $(LINTFILES)
+
+$(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) $(CLEANFILES)
+
+clobber: clean
+ $(RM) $(PROG)
+
+%.ln: ../../common/%.c
+ $(LINT.c) -c $<
+
+%.ln: %.c
+ $(LINT.c) -c $<
+
+lint: $(LINTFILES)
+ $(LINT) $(LINTFLAGS) $(LINTFILES) $(LDLIBS)
+
+check: $(CHECKHDRS)
+
+install_h:
+
+$(ROOTPROG): $$(@D) $(PROG)
+ $(RM) $@; $(INS) -s -m 0555 -f $(@D) $(PROG)
+
+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/lib/fm/topo/modules/common/pcibus.h b/usr/src/lib/fm/topo/modules/common/pcibus.h
new file mode 100644
index 0000000000..684da57886
--- /dev/null
+++ b/usr/src/lib/fm/topo/modules/common/pcibus.h
@@ -0,0 +1,82 @@
+/*
+ * 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 _PCIBUS_H
+#define _PCIBUS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/pci.h>
+#include <fm/topo_mod.h>
+#include <fm/libtopo.h>
+#include <libdevinfo.h>
+
+#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"
+#define PCIEX_BUS "pciexbus"
+#define PCIEX_DEVICE "pciexdev"
+#define PCIEX_FUNCTION "pciexfn"
+
+#define PCIEXTYPE "pciex"
+#define PCITYPE "pci"
+
+#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)
+
+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);
+
+extern di_prom_handle_t Promtree;
+extern topo_mod_t *PciHdl;
+extern const topo_method_t Pci_methods[];
+
+#ifdef __cplusplus
+}
+#endif
+
+#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/plugins/Makefile b/usr/src/lib/fm/topo/modules/i86pc/chip/Makefile
index f4530bfceb..2a2d40c922 100644
--- a/usr/src/cmd/fm/topo/plugins/Makefile
+++ b/usr/src/lib/fm/topo/modules/i86pc/chip/Makefile
@@ -20,14 +20,16 @@
# 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 =
-i386_SUBDIRS =
+MODULE = chip
+ARCH = i86pc
+CLASS = arch
+MODULESRCS = chip.c
-SUBDIRS = common $($(MACH)_SUBDIRS)
+include ../../Makefile.plugin
-include ../../Makefile.subdirs
+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/lib/fm/topo/modules/sun4/chip/Makefile.chip b/usr/src/lib/fm/topo/modules/sun4/chip/Makefile.chip
new file mode 100644
index 0000000000..1b59cc44cf
--- /dev/null
+++ b/usr/src/lib/fm/topo/modules/sun4/chip/Makefile.chip
@@ -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 = 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/lib/fm/topo/modules/sun4/hostbridge/Makefile.hb b/usr/src/lib/fm/topo/modules/sun4/hostbridge/Makefile.hb
new file mode 100644
index 0000000000..ccd5d4ec9a
--- /dev/null
+++ b/usr/src/lib/fm/topo/modules/sun4/hostbridge/Makefile.hb
@@ -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 = 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/lib/fm/topo/modules/sun4u/chip/Makefile b/usr/src/lib/fm/topo/modules/sun4u/chip/Makefile
new file mode 100644
index 0000000000..de6828189a
--- /dev/null
+++ b/usr/src/lib/fm/topo/modules/sun4u/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 = sun4u
+
+include ../../sun4/chip/Makefile.chip
diff --git a/usr/src/lib/fm/topo/modules/sun4u/hostbridge/Makefile b/usr/src/lib/fm/topo/modules/sun4u/hostbridge/Makefile
new file mode 100644
index 0000000000..d270d2f950
--- /dev/null
+++ b/usr/src/lib/fm/topo/modules/sun4u/hostbridge/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"
+
+ARCH = sun4u
+
+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/lib/fm/topo/modules/sun4v/hostbridge/Makefile b/usr/src/lib/fm/topo/modules/sun4v/hostbridge/Makefile
new file mode 100644
index 0000000000..862782dd5b
--- /dev/null
+++ b/usr/src/lib/fm/topo/modules/sun4v/hostbridge/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"
+
+ARCH = sun4v
+
+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/pkgdefs/SUNWonmtst.i/prototype_com b/usr/src/pkgdefs/SUNWonmtst.i/prototype_com
new file mode 100644
index 0000000000..70b07b42ed
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWonmtst.i/prototype_com
@@ -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.
+#
+#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
+
+# packaging files
+i pkginfo
+i copyright
+i depend
+i postinstall
+i preremove
+#
+# source locations relative to the prototype file
+#
+# SUNWonmtst.i
+#
+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/uts/i86pc/io/mc/mc-amd.conf b/usr/src/uts/i86pc/io/mc/mc-amd.conf
new file mode 100644
index 0000000000..066b704525
--- /dev/null
+++ b/usr/src/uts/i86pc/io/mc/mc-amd.conf
@@ -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"
+#
+
+name="mc-amd" parent="pseudo";
+
+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.