120c794b3Sgavinm /* 220c794b3Sgavinm * CDDL HEADER START 320c794b3Sgavinm * 420c794b3Sgavinm * The contents of this file are subject to the terms of the 520c794b3Sgavinm * Common Development and Distribution License (the "License"). 620c794b3Sgavinm * You may not use this file except in compliance with the License. 720c794b3Sgavinm * 820c794b3Sgavinm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 920c794b3Sgavinm * or http://www.opensolaris.org/os/licensing. 1020c794b3Sgavinm * See the License for the specific language governing permissions 1120c794b3Sgavinm * and limitations under the License. 1220c794b3Sgavinm * 1320c794b3Sgavinm * When distributing Covered Code, include this CDDL HEADER in each 1420c794b3Sgavinm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1520c794b3Sgavinm * If applicable, add the following below this CDDL HEADER, with the 1620c794b3Sgavinm * fields enclosed by brackets "[]" replaced with your own identifying 1720c794b3Sgavinm * information: Portions Copyright [yyyy] [name of copyright owner] 1820c794b3Sgavinm * 1920c794b3Sgavinm * CDDL HEADER END 2020c794b3Sgavinm */ 2120c794b3Sgavinm 2220c794b3Sgavinm /* 23*e3d60c9bSAdrian Frost * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 2420c794b3Sgavinm * Use is subject to license terms. 2520c794b3Sgavinm */ 2620c794b3Sgavinm 2720c794b3Sgavinm #include <unistd.h> 2820c794b3Sgavinm #include <stdio.h> 2920c794b3Sgavinm #include <stdlib.h> 3020c794b3Sgavinm #include <stdarg.h> 3120c794b3Sgavinm #include <string.h> 3220c794b3Sgavinm #include <strings.h> 3320c794b3Sgavinm #include <limits.h> 3420c794b3Sgavinm #include <alloca.h> 3520c794b3Sgavinm #include <kstat.h> 3620c794b3Sgavinm #include <fcntl.h> 3720c794b3Sgavinm #include <errno.h> 3820c794b3Sgavinm #include <libnvpair.h> 3920c794b3Sgavinm #include <sys/types.h> 4020c794b3Sgavinm #include <sys/bitmap.h> 4120c794b3Sgavinm #include <sys/processor.h> 4220c794b3Sgavinm #include <sys/param.h> 4320c794b3Sgavinm #include <sys/fm/protocol.h> 4420c794b3Sgavinm #include <sys/systeminfo.h> 4520c794b3Sgavinm #include <sys/mc.h> 4620c794b3Sgavinm #include <sys/mc_amd.h> 4720c794b3Sgavinm #include <sys/mc_intel.h> 4820c794b3Sgavinm #include <fm/topo_mod.h> 4920c794b3Sgavinm 5020c794b3Sgavinm #include "chip.h" 5120c794b3Sgavinm 5220c794b3Sgavinm #ifndef MAX 5320c794b3Sgavinm #define MAX(a, b) ((a) > (b) ? (a) : (b)) 5420c794b3Sgavinm #endif 5520c794b3Sgavinm 5620c794b3Sgavinm static const topo_pgroup_info_t dimm_channel_pgroup = 5720c794b3Sgavinm { PGNAME(CHAN), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 5820c794b3Sgavinm static const topo_pgroup_info_t dimm_pgroup = 5920c794b3Sgavinm { PGNAME(DIMM), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 6020c794b3Sgavinm static const topo_pgroup_info_t rank_pgroup = 6120c794b3Sgavinm { PGNAME(RANK), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 6220c794b3Sgavinm static const topo_pgroup_info_t mc_pgroup = 6320c794b3Sgavinm { PGNAME(MCT), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 6420c794b3Sgavinm static const topo_method_t rank_methods[] = { 6520c794b3Sgavinm { TOPO_METH_ASRU_COMPUTE, TOPO_METH_ASRU_COMPUTE_DESC, 6620c794b3Sgavinm TOPO_METH_ASRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL, 6720c794b3Sgavinm mem_asru_compute }, 6820c794b3Sgavinm { NULL } 6920c794b3Sgavinm }; 7020c794b3Sgavinm 7120c794b3Sgavinm static const topo_method_t dimm_methods[] = { 7220c794b3Sgavinm { SIMPLE_DIMM_LBL, "Property method", 0, TOPO_STABILITY_INTERNAL, 7320c794b3Sgavinm simple_dimm_label}, 7420c794b3Sgavinm { SIMPLE_DIMM_LBL_MP, "Property method", 0, TOPO_STABILITY_INTERNAL, 7520c794b3Sgavinm simple_dimm_label_mp}, 7620c794b3Sgavinm { SEQ_DIMM_LBL, "Property method", 0, TOPO_STABILITY_INTERNAL, 7720c794b3Sgavinm seq_dimm_label}, 7820c794b3Sgavinm { NULL } 7920c794b3Sgavinm }; 8020c794b3Sgavinm 8120c794b3Sgavinm static int mc_fd; 8220c794b3Sgavinm 8320c794b3Sgavinm int 8420c794b3Sgavinm mc_offchip_open() 8520c794b3Sgavinm { 8620c794b3Sgavinm mc_fd = open("/dev/mc/mc", O_RDONLY); 8720c794b3Sgavinm return (mc_fd != -1); 8820c794b3Sgavinm } 8920c794b3Sgavinm 90*e3d60c9bSAdrian Frost static int 91*e3d60c9bSAdrian Frost mc_onchip(topo_instance_t id) 92*e3d60c9bSAdrian Frost { 93*e3d60c9bSAdrian Frost char path[64]; 94*e3d60c9bSAdrian Frost 95*e3d60c9bSAdrian Frost (void) snprintf(path, sizeof (path), "/dev/mc/mc%d", id); 96*e3d60c9bSAdrian Frost mc_fd = open(path, O_RDONLY); 97*e3d60c9bSAdrian Frost return (mc_fd != -1); 98*e3d60c9bSAdrian Frost } 99*e3d60c9bSAdrian Frost 10020c794b3Sgavinm void 10120c794b3Sgavinm mc_add_ranks(topo_mod_t *mod, tnode_t *dnode, nvlist_t *auth, int dimm, 102*e3d60c9bSAdrian Frost nvlist_t **ranks_nvp, int nranks, char *serial, char *part, char *rev, 103*e3d60c9bSAdrian Frost int maxranks) 10420c794b3Sgavinm { 10520c794b3Sgavinm int i; 10620c794b3Sgavinm int rank; 10720c794b3Sgavinm tnode_t *rnode; 10820c794b3Sgavinm nvpair_t *nvp; 10920c794b3Sgavinm nvlist_t *fmri; 11020c794b3Sgavinm int err = 0; 11120c794b3Sgavinm 112*e3d60c9bSAdrian Frost rank = dimm * maxranks; 11320c794b3Sgavinm if (topo_node_range_create(mod, dnode, RANK, rank, 11420c794b3Sgavinm rank + nranks - 1) < 0) { 11520c794b3Sgavinm whinge(mod, NULL, "mc_add_dimms: node range create failed" 11620c794b3Sgavinm " for rank\n"); 11720c794b3Sgavinm return; 11820c794b3Sgavinm } 11920c794b3Sgavinm for (i = 0; i < nranks; i++) { 12020c794b3Sgavinm fmri = topo_mod_hcfmri(mod, dnode, FM_HC_SCHEME_VERSION, 12120c794b3Sgavinm RANK, rank, NULL, auth, part, rev, serial); 12220c794b3Sgavinm if (fmri == NULL) { 12320c794b3Sgavinm whinge(mod, NULL, 12420c794b3Sgavinm "mc_add_ranks: topo_mod_hcfmri failed\n"); 12520c794b3Sgavinm return; 12620c794b3Sgavinm } 12720c794b3Sgavinm if ((rnode = topo_node_bind(mod, dnode, RANK, rank, 12820c794b3Sgavinm fmri)) == NULL) { 12920c794b3Sgavinm nvlist_free(fmri); 13020c794b3Sgavinm whinge(mod, NULL, "mc_add_ranks: node bind failed" 13120c794b3Sgavinm " for ranks\n"); 13220c794b3Sgavinm return; 13320c794b3Sgavinm } 13420c794b3Sgavinm (void) topo_node_fru_set(rnode, NULL, 0, &err); 13520c794b3Sgavinm 13620c794b3Sgavinm if (topo_method_register(mod, rnode, rank_methods) < 0) 13720c794b3Sgavinm whinge(mod, &err, "rank_create: " 13820c794b3Sgavinm "topo_method_register failed"); 13920c794b3Sgavinm 14020c794b3Sgavinm (void) topo_node_asru_set(rnode, fmri, TOPO_ASRU_COMPUTE, &err); 14120c794b3Sgavinm 14220c794b3Sgavinm nvlist_free(fmri); 14320c794b3Sgavinm 14420c794b3Sgavinm (void) topo_pgroup_create(rnode, &rank_pgroup, &err); 14520c794b3Sgavinm for (nvp = nvlist_next_nvpair(ranks_nvp[i], NULL); nvp != NULL; 14620c794b3Sgavinm nvp = nvlist_next_nvpair(ranks_nvp[i], nvp)) { 14720c794b3Sgavinm (void) nvprop_add(mod, nvp, PGNAME(RANK), rnode); 14820c794b3Sgavinm } 14920c794b3Sgavinm rank++; 15020c794b3Sgavinm } 15120c794b3Sgavinm } 15220c794b3Sgavinm 15320c794b3Sgavinm static void 15420c794b3Sgavinm mc_add_dimms(topo_mod_t *mod, tnode_t *pnode, nvlist_t *auth, 155*e3d60c9bSAdrian Frost nvlist_t **nvl, uint_t ndimms, int maxranks) 15620c794b3Sgavinm { 15720c794b3Sgavinm int i; 15820c794b3Sgavinm nvlist_t *fmri; 15920c794b3Sgavinm tnode_t *dnode; 16020c794b3Sgavinm nvpair_t *nvp; 16120c794b3Sgavinm int err; 16220c794b3Sgavinm nvlist_t **ranks_nvp; 16320c794b3Sgavinm uint_t nranks = 0; 16420c794b3Sgavinm char *serial = NULL; 16520c794b3Sgavinm char *part = NULL; 16620c794b3Sgavinm char *rev = NULL; 16720c794b3Sgavinm char *label = NULL; 16820c794b3Sgavinm char *name; 16920c794b3Sgavinm 17020c794b3Sgavinm if (topo_node_range_create(mod, pnode, DIMM, 0, ndimms-1) < 0) { 17120c794b3Sgavinm whinge(mod, NULL, 17220c794b3Sgavinm "mc_add_dimms: node range create failed\n"); 17320c794b3Sgavinm return; 17420c794b3Sgavinm } 17520c794b3Sgavinm for (i = 0; i < ndimms; i++) { 17620c794b3Sgavinm for (nvp = nvlist_next_nvpair(nvl[i], NULL); nvp != NULL; 17720c794b3Sgavinm nvp = nvlist_next_nvpair(nvl[i], nvp)) { 17820c794b3Sgavinm name = nvpair_name(nvp); 17920c794b3Sgavinm if (strcmp(name, MCINTEL_NVLIST_RANKS) == 0) { 18020c794b3Sgavinm (void) nvpair_value_nvlist_array(nvp, 18120c794b3Sgavinm &ranks_nvp, &nranks); 18220c794b3Sgavinm } else if (strcmp(name, FM_FMRI_HC_SERIAL_ID) == 0) { 18320c794b3Sgavinm (void) nvpair_value_string(nvp, &serial); 18420c794b3Sgavinm } else if (strcmp(name, FM_FMRI_HC_PART) == 0) { 18520c794b3Sgavinm (void) nvpair_value_string(nvp, &part); 18620c794b3Sgavinm } else if (strcmp(name, FM_FMRI_HC_REVISION) == 0) { 18720c794b3Sgavinm (void) nvpair_value_string(nvp, &rev); 18820c794b3Sgavinm } else if (strcmp(name, FM_FAULT_FRU_LABEL) == 0) { 18920c794b3Sgavinm (void) nvpair_value_string(nvp, &label); 19020c794b3Sgavinm } 19120c794b3Sgavinm } 19220c794b3Sgavinm fmri = NULL; 19320c794b3Sgavinm fmri = topo_mod_hcfmri(mod, pnode, FM_HC_SCHEME_VERSION, 19420c794b3Sgavinm DIMM, i, NULL, auth, part, rev, serial); 19520c794b3Sgavinm if (fmri == NULL) { 19620c794b3Sgavinm whinge(mod, NULL, 19720c794b3Sgavinm "mc_add_dimms: topo_mod_hcfmri failed\n"); 19820c794b3Sgavinm return; 19920c794b3Sgavinm } 20020c794b3Sgavinm if ((dnode = topo_node_bind(mod, pnode, DIMM, i, 20120c794b3Sgavinm fmri)) == NULL) { 20220c794b3Sgavinm nvlist_free(fmri); 20320c794b3Sgavinm whinge(mod, NULL, "mc_add_dimms: node bind failed" 20420c794b3Sgavinm " for dimm\n"); 20520c794b3Sgavinm return; 20620c794b3Sgavinm } 20720c794b3Sgavinm 20820c794b3Sgavinm if (topo_method_register(mod, dnode, dimm_methods) < 0) 20920c794b3Sgavinm whinge(mod, NULL, "mc_add_dimms: " 21020c794b3Sgavinm "topo_method_register failed"); 21120c794b3Sgavinm 21220c794b3Sgavinm (void) topo_node_fru_set(dnode, fmri, 0, &err); 21320c794b3Sgavinm nvlist_free(fmri); 21420c794b3Sgavinm (void) topo_pgroup_create(dnode, &dimm_pgroup, &err); 21520c794b3Sgavinm 21620c794b3Sgavinm for (nvp = nvlist_next_nvpair(nvl[i], NULL); nvp != NULL; 21720c794b3Sgavinm nvp = nvlist_next_nvpair(nvl[i], nvp)) { 21820c794b3Sgavinm name = nvpair_name(nvp); 21920c794b3Sgavinm if (strcmp(name, MCINTEL_NVLIST_RANKS) != 0 && 22020c794b3Sgavinm strcmp(name, FM_FAULT_FRU_LABEL) != 0) { 22120c794b3Sgavinm (void) nvprop_add(mod, nvp, PGNAME(DIMM), 22220c794b3Sgavinm dnode); 22320c794b3Sgavinm } 22420c794b3Sgavinm } 22520c794b3Sgavinm if (label) 22620c794b3Sgavinm (void) topo_node_label_set(dnode, label, &err); 22720c794b3Sgavinm 22820c794b3Sgavinm if (nranks) { 22920c794b3Sgavinm mc_add_ranks(mod, dnode, auth, i, ranks_nvp, nranks, 230*e3d60c9bSAdrian Frost serial, part, rev, maxranks); 23120c794b3Sgavinm } 23220c794b3Sgavinm } 23320c794b3Sgavinm } 23420c794b3Sgavinm 23520c794b3Sgavinm static int 23620c794b3Sgavinm mc_add_channel(topo_mod_t *mod, tnode_t *pnode, int channel, nvlist_t *auth, 237*e3d60c9bSAdrian Frost nvlist_t *nvl, int maxranks) 23820c794b3Sgavinm { 23920c794b3Sgavinm tnode_t *mc_channel; 24020c794b3Sgavinm nvlist_t *fmri; 24120c794b3Sgavinm nvlist_t **dimm_nvl; 242*e3d60c9bSAdrian Frost nvpair_t *nvp; 243*e3d60c9bSAdrian Frost char *name; 24420c794b3Sgavinm uint_t ndimms; 24520c794b3Sgavinm int err; 24620c794b3Sgavinm 24720c794b3Sgavinm if (mkrsrc(mod, pnode, DRAMCHANNEL, channel, auth, &fmri) != 0) { 24820c794b3Sgavinm whinge(mod, NULL, "mc_add_channel: mkrsrc failed\n"); 24920c794b3Sgavinm return (-1); 25020c794b3Sgavinm } 25120c794b3Sgavinm if ((mc_channel = topo_node_bind(mod, pnode, DRAMCHANNEL, channel, 25220c794b3Sgavinm fmri)) == NULL) { 25320c794b3Sgavinm whinge(mod, NULL, "mc_add_channel: node bind failed for %s\n", 25420c794b3Sgavinm DRAMCHANNEL); 25520c794b3Sgavinm nvlist_free(fmri); 25620c794b3Sgavinm return (-1); 25720c794b3Sgavinm } 25820c794b3Sgavinm (void) topo_node_fru_set(mc_channel, NULL, 0, &err); 25920c794b3Sgavinm nvlist_free(fmri); 26020c794b3Sgavinm (void) topo_pgroup_create(mc_channel, &dimm_channel_pgroup, &err); 26120c794b3Sgavinm if (nvlist_lookup_nvlist_array(nvl, MCINTEL_NVLIST_DIMMS, &dimm_nvl, 26220c794b3Sgavinm &ndimms) == 0) { 263*e3d60c9bSAdrian Frost mc_add_dimms(mod, mc_channel, auth, dimm_nvl, ndimms, maxranks); 264*e3d60c9bSAdrian Frost } 265*e3d60c9bSAdrian Frost for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 266*e3d60c9bSAdrian Frost nvp = nvlist_next_nvpair(nvl, nvp)) { 267*e3d60c9bSAdrian Frost name = nvpair_name(nvp); 268*e3d60c9bSAdrian Frost if (strcmp(name, MCINTEL_NVLIST_DIMMS) != 0) { 269*e3d60c9bSAdrian Frost (void) nvprop_add(mod, nvp, PGNAME(CHAN), 270*e3d60c9bSAdrian Frost mc_channel); 271*e3d60c9bSAdrian Frost } 27220c794b3Sgavinm } 27320c794b3Sgavinm return (0); 27420c794b3Sgavinm } 27520c794b3Sgavinm 27620c794b3Sgavinm static int 27720c794b3Sgavinm mc_nb_create(topo_mod_t *mod, tnode_t *pnode, const char *name, nvlist_t *auth, 27820c794b3Sgavinm nvlist_t *nvl) 27920c794b3Sgavinm { 28020c794b3Sgavinm int err; 28120c794b3Sgavinm int i, j; 28220c794b3Sgavinm int channel; 283*e3d60c9bSAdrian Frost uint8_t nmc; 284*e3d60c9bSAdrian Frost uint8_t maxranks; 28520c794b3Sgavinm tnode_t *mcnode; 28620c794b3Sgavinm nvlist_t *fmri; 28720c794b3Sgavinm nvlist_t **channel_nvl; 288*e3d60c9bSAdrian Frost nvpair_t *nvp; 289*e3d60c9bSAdrian Frost char *pname; 29020c794b3Sgavinm uint_t nchannels; 29120c794b3Sgavinm 29220c794b3Sgavinm if (nvlist_lookup_nvlist_array(nvl, MCINTEL_NVLIST_MC, &channel_nvl, 29320c794b3Sgavinm &nchannels) != 0) { 29420c794b3Sgavinm whinge(mod, NULL, 29520c794b3Sgavinm "mc_nb_create: failed to find channel information\n"); 29620c794b3Sgavinm return (-1); 29720c794b3Sgavinm } 298*e3d60c9bSAdrian Frost if (nvlist_lookup_uint8(nvl, MCINTEL_NVLIST_NMEM, &nmc) != 0) { 299*e3d60c9bSAdrian Frost /* 300*e3d60c9bSAdrian Frost * if number of memory controllers is not specified then there 301*e3d60c9bSAdrian Frost * are two channels per controller and the nchannels is total 302*e3d60c9bSAdrian Frost * we will set up nmc as number of controllers and convert 303*e3d60c9bSAdrian Frost * nchannels to channels per controller 304*e3d60c9bSAdrian Frost */ 305*e3d60c9bSAdrian Frost nmc = nchannels / 2; 306*e3d60c9bSAdrian Frost nchannels = nchannels / nmc; 307*e3d60c9bSAdrian Frost } 308*e3d60c9bSAdrian Frost if (nvlist_lookup_uint8(nvl, MCINTEL_NVLIST_NRANKS, &maxranks) != 0) 309*e3d60c9bSAdrian Frost maxranks = 2; 31020c794b3Sgavinm if (topo_node_range_create(mod, pnode, name, 0, nmc-1) < 0) { 31120c794b3Sgavinm whinge(mod, NULL, 31220c794b3Sgavinm "mc_nb_create: node range create failed\n"); 31320c794b3Sgavinm return (-1); 31420c794b3Sgavinm } 31520c794b3Sgavinm channel = 0; 31620c794b3Sgavinm for (i = 0; i < nmc; i++) { 31720c794b3Sgavinm if (mkrsrc(mod, pnode, name, i, auth, &fmri) != 0) { 31820c794b3Sgavinm whinge(mod, NULL, "mc_nb_create: mkrsrc failed\n"); 31920c794b3Sgavinm return (-1); 32020c794b3Sgavinm } 32120c794b3Sgavinm if ((mcnode = topo_node_bind(mod, pnode, name, i, 32220c794b3Sgavinm fmri)) == NULL) { 323*e3d60c9bSAdrian Frost whinge(mod, NULL, "mc_nb_create: node bind failed" 32420c794b3Sgavinm " for memory-controller\n"); 32520c794b3Sgavinm nvlist_free(fmri); 32620c794b3Sgavinm return (-1); 32720c794b3Sgavinm } 32820c794b3Sgavinm 32920c794b3Sgavinm (void) topo_node_fru_set(mcnode, NULL, 0, &err); 33020c794b3Sgavinm nvlist_free(fmri); 33120c794b3Sgavinm (void) topo_pgroup_create(mcnode, &mc_pgroup, &err); 33220c794b3Sgavinm 33320c794b3Sgavinm if (topo_node_range_create(mod, mcnode, DRAMCHANNEL, channel, 334*e3d60c9bSAdrian Frost channel + nchannels - 1) < 0) { 33520c794b3Sgavinm whinge(mod, NULL, 33620c794b3Sgavinm "mc_nb_create: channel node range create failed\n"); 33720c794b3Sgavinm return (-1); 33820c794b3Sgavinm } 339*e3d60c9bSAdrian Frost for (j = 0; j < nchannels; j++) { 34020c794b3Sgavinm if (mc_add_channel(mod, mcnode, channel, auth, 341*e3d60c9bSAdrian Frost channel_nvl[channel], maxranks) < 0) { 34220c794b3Sgavinm return (-1); 34320c794b3Sgavinm } 34420c794b3Sgavinm channel++; 34520c794b3Sgavinm } 346*e3d60c9bSAdrian Frost for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 347*e3d60c9bSAdrian Frost nvp = nvlist_next_nvpair(nvl, nvp)) { 348*e3d60c9bSAdrian Frost pname = nvpair_name(nvp); 349*e3d60c9bSAdrian Frost if (strcmp(pname, MCINTEL_NVLIST_MC) != 0 && 350*e3d60c9bSAdrian Frost strcmp(pname, MCINTEL_NVLIST_NMEM) != 0 && 351*e3d60c9bSAdrian Frost strcmp(pname, MCINTEL_NVLIST_NRANKS) != 0 && 352*e3d60c9bSAdrian Frost strcmp(pname, MCINTEL_NVLIST_VERSTR) != 0 && 353*e3d60c9bSAdrian Frost strcmp(pname, MCINTEL_NVLIST_MEM) != 0) { 354*e3d60c9bSAdrian Frost (void) nvprop_add(mod, nvp, PGNAME(MCT), 355*e3d60c9bSAdrian Frost mcnode); 356*e3d60c9bSAdrian Frost } 357*e3d60c9bSAdrian Frost } 35820c794b3Sgavinm } 35920c794b3Sgavinm 36020c794b3Sgavinm return (NULL); 36120c794b3Sgavinm } 36220c794b3Sgavinm 36320c794b3Sgavinm int 364*e3d60c9bSAdrian Frost mc_node_create(topo_mod_t *mod, tnode_t *pnode, const char *name, 36520c794b3Sgavinm nvlist_t *auth) 36620c794b3Sgavinm { 36720c794b3Sgavinm mc_snapshot_info_t mcs; 36820c794b3Sgavinm void *buf = NULL; 36920c794b3Sgavinm nvlist_t *nvl; 37020c794b3Sgavinm uint8_t ver; 37120c794b3Sgavinm int rc; 37220c794b3Sgavinm 37320c794b3Sgavinm if (ioctl(mc_fd, MC_IOC_SNAPSHOT_INFO, &mcs) == -1 || 37420c794b3Sgavinm (buf = topo_mod_alloc(mod, mcs.mcs_size)) == NULL || 37520c794b3Sgavinm ioctl(mc_fd, MC_IOC_SNAPSHOT, buf) == -1) { 37620c794b3Sgavinm 37720c794b3Sgavinm whinge(mod, NULL, "mc failed to snapshot %s\n", 37820c794b3Sgavinm strerror(errno)); 37920c794b3Sgavinm 38020c794b3Sgavinm free(buf); 38120c794b3Sgavinm (void) close(mc_fd); 38220c794b3Sgavinm return (NULL); 38320c794b3Sgavinm } 38420c794b3Sgavinm (void) close(mc_fd); 38520c794b3Sgavinm (void) nvlist_unpack(buf, mcs.mcs_size, &nvl, 0); 38620c794b3Sgavinm topo_mod_free(mod, buf, mcs.mcs_size); 38720c794b3Sgavinm 38820c794b3Sgavinm if (nvlist_lookup_uint8(nvl, MCINTEL_NVLIST_VERSTR, &ver) != 0) { 38920c794b3Sgavinm whinge(mod, NULL, "mc nvlist is not versioned\n"); 39020c794b3Sgavinm nvlist_free(nvl); 39120c794b3Sgavinm return (NULL); 39220c794b3Sgavinm } else if (ver != MCINTEL_NVLIST_VERS0) { 39320c794b3Sgavinm whinge(mod, NULL, "mc nvlist version mismatch\n"); 39420c794b3Sgavinm nvlist_free(nvl); 39520c794b3Sgavinm return (NULL); 39620c794b3Sgavinm } 39720c794b3Sgavinm 39820c794b3Sgavinm rc = mc_nb_create(mod, pnode, name, auth, nvl); 39920c794b3Sgavinm 40020c794b3Sgavinm nvlist_free(nvl); 40120c794b3Sgavinm return (rc); 40220c794b3Sgavinm } 403*e3d60c9bSAdrian Frost 404*e3d60c9bSAdrian Frost void 405*e3d60c9bSAdrian Frost onchip_mc_create(topo_mod_t *mod, tnode_t *pnode, const char *name, 406*e3d60c9bSAdrian Frost nvlist_t *auth) 407*e3d60c9bSAdrian Frost { 408*e3d60c9bSAdrian Frost if (mc_onchip(topo_node_instance(pnode))) 409*e3d60c9bSAdrian Frost (void) mc_node_create(mod, pnode, name, auth); 410*e3d60c9bSAdrian Frost } 411*e3d60c9bSAdrian Frost 412*e3d60c9bSAdrian Frost int 413*e3d60c9bSAdrian Frost mc_offchip_create(topo_mod_t *mod, tnode_t *pnode, const char *name, 414*e3d60c9bSAdrian Frost nvlist_t *auth) 415*e3d60c9bSAdrian Frost { 416*e3d60c9bSAdrian Frost return (mc_node_create(mod, pnode, name, auth)); 417*e3d60c9bSAdrian Frost } 418