1*20c794b3Sgavinm /* 2*20c794b3Sgavinm * CDDL HEADER START 3*20c794b3Sgavinm * 4*20c794b3Sgavinm * The contents of this file are subject to the terms of the 5*20c794b3Sgavinm * Common Development and Distribution License (the "License"). 6*20c794b3Sgavinm * You may not use this file except in compliance with the License. 7*20c794b3Sgavinm * 8*20c794b3Sgavinm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*20c794b3Sgavinm * or http://www.opensolaris.org/os/licensing. 10*20c794b3Sgavinm * See the License for the specific language governing permissions 11*20c794b3Sgavinm * and limitations under the License. 12*20c794b3Sgavinm * 13*20c794b3Sgavinm * When distributing Covered Code, include this CDDL HEADER in each 14*20c794b3Sgavinm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*20c794b3Sgavinm * If applicable, add the following below this CDDL HEADER, with the 16*20c794b3Sgavinm * fields enclosed by brackets "[]" replaced with your own identifying 17*20c794b3Sgavinm * information: Portions Copyright [yyyy] [name of copyright owner] 18*20c794b3Sgavinm * 19*20c794b3Sgavinm * CDDL HEADER END 20*20c794b3Sgavinm */ 21*20c794b3Sgavinm 22*20c794b3Sgavinm /* 23*20c794b3Sgavinm * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24*20c794b3Sgavinm * Use is subject to license terms. 25*20c794b3Sgavinm */ 26*20c794b3Sgavinm 27*20c794b3Sgavinm #pragma ident "%Z%%M% %I% %E% SMI" 28*20c794b3Sgavinm 29*20c794b3Sgavinm #include <unistd.h> 30*20c794b3Sgavinm #include <stdio.h> 31*20c794b3Sgavinm #include <stdlib.h> 32*20c794b3Sgavinm #include <stdarg.h> 33*20c794b3Sgavinm #include <string.h> 34*20c794b3Sgavinm #include <strings.h> 35*20c794b3Sgavinm #include <limits.h> 36*20c794b3Sgavinm #include <alloca.h> 37*20c794b3Sgavinm #include <kstat.h> 38*20c794b3Sgavinm #include <fcntl.h> 39*20c794b3Sgavinm #include <errno.h> 40*20c794b3Sgavinm #include <libnvpair.h> 41*20c794b3Sgavinm #include <sys/types.h> 42*20c794b3Sgavinm #include <sys/bitmap.h> 43*20c794b3Sgavinm #include <sys/processor.h> 44*20c794b3Sgavinm #include <sys/param.h> 45*20c794b3Sgavinm #include <sys/fm/protocol.h> 46*20c794b3Sgavinm #include <sys/systeminfo.h> 47*20c794b3Sgavinm #include <sys/mc.h> 48*20c794b3Sgavinm #include <sys/mc_amd.h> 49*20c794b3Sgavinm #include <sys/mc_intel.h> 50*20c794b3Sgavinm #include <fm/topo_mod.h> 51*20c794b3Sgavinm 52*20c794b3Sgavinm #include "chip.h" 53*20c794b3Sgavinm 54*20c794b3Sgavinm #ifndef MAX 55*20c794b3Sgavinm #define MAX(a, b) ((a) > (b) ? (a) : (b)) 56*20c794b3Sgavinm #endif 57*20c794b3Sgavinm 58*20c794b3Sgavinm static const topo_pgroup_info_t dimm_channel_pgroup = 59*20c794b3Sgavinm { PGNAME(CHAN), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 60*20c794b3Sgavinm static const topo_pgroup_info_t dimm_pgroup = 61*20c794b3Sgavinm { PGNAME(DIMM), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 62*20c794b3Sgavinm static const topo_pgroup_info_t rank_pgroup = 63*20c794b3Sgavinm { PGNAME(RANK), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 64*20c794b3Sgavinm static const topo_pgroup_info_t mc_pgroup = 65*20c794b3Sgavinm { PGNAME(MCT), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 66*20c794b3Sgavinm static const topo_method_t rank_methods[] = { 67*20c794b3Sgavinm { TOPO_METH_ASRU_COMPUTE, TOPO_METH_ASRU_COMPUTE_DESC, 68*20c794b3Sgavinm TOPO_METH_ASRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL, 69*20c794b3Sgavinm mem_asru_compute }, 70*20c794b3Sgavinm { NULL } 71*20c794b3Sgavinm }; 72*20c794b3Sgavinm 73*20c794b3Sgavinm static const topo_method_t dimm_methods[] = { 74*20c794b3Sgavinm { SIMPLE_DIMM_LBL, "Property method", 0, TOPO_STABILITY_INTERNAL, 75*20c794b3Sgavinm simple_dimm_label}, 76*20c794b3Sgavinm { SIMPLE_DIMM_LBL_MP, "Property method", 0, TOPO_STABILITY_INTERNAL, 77*20c794b3Sgavinm simple_dimm_label_mp}, 78*20c794b3Sgavinm { SEQ_DIMM_LBL, "Property method", 0, TOPO_STABILITY_INTERNAL, 79*20c794b3Sgavinm seq_dimm_label}, 80*20c794b3Sgavinm { NULL } 81*20c794b3Sgavinm }; 82*20c794b3Sgavinm 83*20c794b3Sgavinm static int mc_fd; 84*20c794b3Sgavinm 85*20c794b3Sgavinm int 86*20c794b3Sgavinm mc_offchip_open() 87*20c794b3Sgavinm { 88*20c794b3Sgavinm mc_fd = open("/dev/mc/mc", O_RDONLY); 89*20c794b3Sgavinm return (mc_fd != -1); 90*20c794b3Sgavinm } 91*20c794b3Sgavinm 92*20c794b3Sgavinm void 93*20c794b3Sgavinm mc_add_ranks(topo_mod_t *mod, tnode_t *dnode, nvlist_t *auth, int dimm, 94*20c794b3Sgavinm nvlist_t **ranks_nvp, int nranks, char *serial, char *part, char *rev) 95*20c794b3Sgavinm { 96*20c794b3Sgavinm int i; 97*20c794b3Sgavinm int rank; 98*20c794b3Sgavinm tnode_t *rnode; 99*20c794b3Sgavinm nvpair_t *nvp; 100*20c794b3Sgavinm nvlist_t *fmri; 101*20c794b3Sgavinm int err = 0; 102*20c794b3Sgavinm 103*20c794b3Sgavinm rank = dimm * 2; 104*20c794b3Sgavinm if (topo_node_range_create(mod, dnode, RANK, rank, 105*20c794b3Sgavinm rank + nranks - 1) < 0) { 106*20c794b3Sgavinm whinge(mod, NULL, "mc_add_dimms: node range create failed" 107*20c794b3Sgavinm " for rank\n"); 108*20c794b3Sgavinm return; 109*20c794b3Sgavinm } 110*20c794b3Sgavinm for (i = 0; i < nranks; i++) { 111*20c794b3Sgavinm fmri = topo_mod_hcfmri(mod, dnode, FM_HC_SCHEME_VERSION, 112*20c794b3Sgavinm RANK, rank, NULL, auth, part, rev, serial); 113*20c794b3Sgavinm if (fmri == NULL) { 114*20c794b3Sgavinm whinge(mod, NULL, 115*20c794b3Sgavinm "mc_add_ranks: topo_mod_hcfmri failed\n"); 116*20c794b3Sgavinm return; 117*20c794b3Sgavinm } 118*20c794b3Sgavinm if ((rnode = topo_node_bind(mod, dnode, RANK, rank, 119*20c794b3Sgavinm fmri)) == NULL) { 120*20c794b3Sgavinm nvlist_free(fmri); 121*20c794b3Sgavinm whinge(mod, NULL, "mc_add_ranks: node bind failed" 122*20c794b3Sgavinm " for ranks\n"); 123*20c794b3Sgavinm return; 124*20c794b3Sgavinm } 125*20c794b3Sgavinm (void) topo_node_fru_set(rnode, NULL, 0, &err); 126*20c794b3Sgavinm 127*20c794b3Sgavinm if (topo_method_register(mod, rnode, rank_methods) < 0) 128*20c794b3Sgavinm whinge(mod, &err, "rank_create: " 129*20c794b3Sgavinm "topo_method_register failed"); 130*20c794b3Sgavinm 131*20c794b3Sgavinm (void) topo_node_asru_set(rnode, fmri, TOPO_ASRU_COMPUTE, &err); 132*20c794b3Sgavinm 133*20c794b3Sgavinm nvlist_free(fmri); 134*20c794b3Sgavinm 135*20c794b3Sgavinm (void) topo_pgroup_create(rnode, &rank_pgroup, &err); 136*20c794b3Sgavinm for (nvp = nvlist_next_nvpair(ranks_nvp[i], NULL); nvp != NULL; 137*20c794b3Sgavinm nvp = nvlist_next_nvpair(ranks_nvp[i], nvp)) { 138*20c794b3Sgavinm (void) nvprop_add(mod, nvp, PGNAME(RANK), rnode); 139*20c794b3Sgavinm } 140*20c794b3Sgavinm rank++; 141*20c794b3Sgavinm } 142*20c794b3Sgavinm } 143*20c794b3Sgavinm 144*20c794b3Sgavinm static void 145*20c794b3Sgavinm mc_add_dimms(topo_mod_t *mod, tnode_t *pnode, nvlist_t *auth, 146*20c794b3Sgavinm nvlist_t **nvl, uint_t ndimms) 147*20c794b3Sgavinm { 148*20c794b3Sgavinm int i; 149*20c794b3Sgavinm nvlist_t *fmri; 150*20c794b3Sgavinm tnode_t *dnode; 151*20c794b3Sgavinm nvpair_t *nvp; 152*20c794b3Sgavinm int err; 153*20c794b3Sgavinm nvlist_t **ranks_nvp; 154*20c794b3Sgavinm uint_t nranks = 0; 155*20c794b3Sgavinm char *serial = NULL; 156*20c794b3Sgavinm char *part = NULL; 157*20c794b3Sgavinm char *rev = NULL; 158*20c794b3Sgavinm char *label = NULL; 159*20c794b3Sgavinm char *name; 160*20c794b3Sgavinm 161*20c794b3Sgavinm if (topo_node_range_create(mod, pnode, DIMM, 0, ndimms-1) < 0) { 162*20c794b3Sgavinm whinge(mod, NULL, 163*20c794b3Sgavinm "mc_add_dimms: node range create failed\n"); 164*20c794b3Sgavinm return; 165*20c794b3Sgavinm } 166*20c794b3Sgavinm for (i = 0; i < ndimms; i++) { 167*20c794b3Sgavinm for (nvp = nvlist_next_nvpair(nvl[i], NULL); nvp != NULL; 168*20c794b3Sgavinm nvp = nvlist_next_nvpair(nvl[i], nvp)) { 169*20c794b3Sgavinm name = nvpair_name(nvp); 170*20c794b3Sgavinm if (strcmp(name, MCINTEL_NVLIST_RANKS) == 0) { 171*20c794b3Sgavinm (void) nvpair_value_nvlist_array(nvp, 172*20c794b3Sgavinm &ranks_nvp, &nranks); 173*20c794b3Sgavinm } else if (strcmp(name, FM_FMRI_HC_SERIAL_ID) == 0) { 174*20c794b3Sgavinm (void) nvpair_value_string(nvp, &serial); 175*20c794b3Sgavinm } else if (strcmp(name, FM_FMRI_HC_PART) == 0) { 176*20c794b3Sgavinm (void) nvpair_value_string(nvp, &part); 177*20c794b3Sgavinm } else if (strcmp(name, FM_FMRI_HC_REVISION) == 0) { 178*20c794b3Sgavinm (void) nvpair_value_string(nvp, &rev); 179*20c794b3Sgavinm } else if (strcmp(name, FM_FAULT_FRU_LABEL) == 0) { 180*20c794b3Sgavinm (void) nvpair_value_string(nvp, &label); 181*20c794b3Sgavinm } 182*20c794b3Sgavinm } 183*20c794b3Sgavinm fmri = NULL; 184*20c794b3Sgavinm fmri = topo_mod_hcfmri(mod, pnode, FM_HC_SCHEME_VERSION, 185*20c794b3Sgavinm DIMM, i, NULL, auth, part, rev, serial); 186*20c794b3Sgavinm if (fmri == NULL) { 187*20c794b3Sgavinm whinge(mod, NULL, 188*20c794b3Sgavinm "mc_add_dimms: topo_mod_hcfmri failed\n"); 189*20c794b3Sgavinm return; 190*20c794b3Sgavinm } 191*20c794b3Sgavinm if ((dnode = topo_node_bind(mod, pnode, DIMM, i, 192*20c794b3Sgavinm fmri)) == NULL) { 193*20c794b3Sgavinm nvlist_free(fmri); 194*20c794b3Sgavinm whinge(mod, NULL, "mc_add_dimms: node bind failed" 195*20c794b3Sgavinm " for dimm\n"); 196*20c794b3Sgavinm return; 197*20c794b3Sgavinm } 198*20c794b3Sgavinm 199*20c794b3Sgavinm if (topo_method_register(mod, dnode, dimm_methods) < 0) 200*20c794b3Sgavinm whinge(mod, NULL, "mc_add_dimms: " 201*20c794b3Sgavinm "topo_method_register failed"); 202*20c794b3Sgavinm 203*20c794b3Sgavinm (void) topo_node_fru_set(dnode, fmri, 0, &err); 204*20c794b3Sgavinm nvlist_free(fmri); 205*20c794b3Sgavinm (void) topo_pgroup_create(dnode, &dimm_pgroup, &err); 206*20c794b3Sgavinm 207*20c794b3Sgavinm for (nvp = nvlist_next_nvpair(nvl[i], NULL); nvp != NULL; 208*20c794b3Sgavinm nvp = nvlist_next_nvpair(nvl[i], nvp)) { 209*20c794b3Sgavinm name = nvpair_name(nvp); 210*20c794b3Sgavinm if (strcmp(name, MCINTEL_NVLIST_RANKS) != 0 && 211*20c794b3Sgavinm strcmp(name, FM_FAULT_FRU_LABEL) != 0) { 212*20c794b3Sgavinm (void) nvprop_add(mod, nvp, PGNAME(DIMM), 213*20c794b3Sgavinm dnode); 214*20c794b3Sgavinm } 215*20c794b3Sgavinm } 216*20c794b3Sgavinm if (label) 217*20c794b3Sgavinm (void) topo_node_label_set(dnode, label, &err); 218*20c794b3Sgavinm 219*20c794b3Sgavinm if (nranks) { 220*20c794b3Sgavinm mc_add_ranks(mod, dnode, auth, i, ranks_nvp, nranks, 221*20c794b3Sgavinm serial, part, rev); 222*20c794b3Sgavinm } 223*20c794b3Sgavinm } 224*20c794b3Sgavinm } 225*20c794b3Sgavinm 226*20c794b3Sgavinm static int 227*20c794b3Sgavinm mc_add_channel(topo_mod_t *mod, tnode_t *pnode, int channel, nvlist_t *auth, 228*20c794b3Sgavinm nvlist_t *nvl) 229*20c794b3Sgavinm { 230*20c794b3Sgavinm tnode_t *mc_channel; 231*20c794b3Sgavinm nvlist_t *fmri; 232*20c794b3Sgavinm nvlist_t **dimm_nvl; 233*20c794b3Sgavinm uint_t ndimms; 234*20c794b3Sgavinm int err; 235*20c794b3Sgavinm 236*20c794b3Sgavinm if (mkrsrc(mod, pnode, DRAMCHANNEL, channel, auth, &fmri) != 0) { 237*20c794b3Sgavinm whinge(mod, NULL, "mc_add_channel: mkrsrc failed\n"); 238*20c794b3Sgavinm return (-1); 239*20c794b3Sgavinm } 240*20c794b3Sgavinm if ((mc_channel = topo_node_bind(mod, pnode, DRAMCHANNEL, channel, 241*20c794b3Sgavinm fmri)) == NULL) { 242*20c794b3Sgavinm whinge(mod, NULL, "mc_add_channel: node bind failed for %s\n", 243*20c794b3Sgavinm DRAMCHANNEL); 244*20c794b3Sgavinm nvlist_free(fmri); 245*20c794b3Sgavinm return (-1); 246*20c794b3Sgavinm } 247*20c794b3Sgavinm (void) topo_node_fru_set(mc_channel, NULL, 0, &err); 248*20c794b3Sgavinm nvlist_free(fmri); 249*20c794b3Sgavinm (void) topo_pgroup_create(mc_channel, &dimm_channel_pgroup, &err); 250*20c794b3Sgavinm if (nvlist_lookup_nvlist_array(nvl, MCINTEL_NVLIST_DIMMS, &dimm_nvl, 251*20c794b3Sgavinm &ndimms) == 0) { 252*20c794b3Sgavinm mc_add_dimms(mod, mc_channel, auth, dimm_nvl, ndimms); 253*20c794b3Sgavinm } 254*20c794b3Sgavinm return (0); 255*20c794b3Sgavinm } 256*20c794b3Sgavinm 257*20c794b3Sgavinm static int 258*20c794b3Sgavinm mc_nb_create(topo_mod_t *mod, tnode_t *pnode, const char *name, nvlist_t *auth, 259*20c794b3Sgavinm nvlist_t *nvl) 260*20c794b3Sgavinm { 261*20c794b3Sgavinm int err; 262*20c794b3Sgavinm int i, j; 263*20c794b3Sgavinm int channel; 264*20c794b3Sgavinm int nmc; 265*20c794b3Sgavinm tnode_t *mcnode; 266*20c794b3Sgavinm nvlist_t *fmri; 267*20c794b3Sgavinm nvlist_t **channel_nvl; 268*20c794b3Sgavinm uint_t nchannels; 269*20c794b3Sgavinm 270*20c794b3Sgavinm if (nvlist_lookup_nvlist_array(nvl, MCINTEL_NVLIST_MC, &channel_nvl, 271*20c794b3Sgavinm &nchannels) != 0) { 272*20c794b3Sgavinm whinge(mod, NULL, 273*20c794b3Sgavinm "mc_nb_create: failed to find channel information\n"); 274*20c794b3Sgavinm return (-1); 275*20c794b3Sgavinm } 276*20c794b3Sgavinm nmc = nchannels / 2; 277*20c794b3Sgavinm if (topo_node_range_create(mod, pnode, name, 0, nmc-1) < 0) { 278*20c794b3Sgavinm whinge(mod, NULL, 279*20c794b3Sgavinm "mc_nb_create: node range create failed\n"); 280*20c794b3Sgavinm return (-1); 281*20c794b3Sgavinm } 282*20c794b3Sgavinm channel = 0; 283*20c794b3Sgavinm for (i = 0; i < nmc; i++) { 284*20c794b3Sgavinm if (mkrsrc(mod, pnode, name, i, auth, &fmri) != 0) { 285*20c794b3Sgavinm whinge(mod, NULL, "mc_nb_create: mkrsrc failed\n"); 286*20c794b3Sgavinm return (-1); 287*20c794b3Sgavinm } 288*20c794b3Sgavinm if ((mcnode = topo_node_bind(mod, pnode, name, i, 289*20c794b3Sgavinm fmri)) == NULL) { 290*20c794b3Sgavinm whinge(mod, NULL, "chip_create: node bind failed" 291*20c794b3Sgavinm " for memory-controller\n"); 292*20c794b3Sgavinm nvlist_free(fmri); 293*20c794b3Sgavinm return (-1); 294*20c794b3Sgavinm } 295*20c794b3Sgavinm 296*20c794b3Sgavinm (void) topo_node_fru_set(mcnode, NULL, 0, &err); 297*20c794b3Sgavinm nvlist_free(fmri); 298*20c794b3Sgavinm (void) topo_pgroup_create(mcnode, &mc_pgroup, &err); 299*20c794b3Sgavinm 300*20c794b3Sgavinm if (topo_node_range_create(mod, mcnode, DRAMCHANNEL, channel, 301*20c794b3Sgavinm channel + 1) < 0) { 302*20c794b3Sgavinm whinge(mod, NULL, 303*20c794b3Sgavinm "mc_nb_create: channel node range create failed\n"); 304*20c794b3Sgavinm return (-1); 305*20c794b3Sgavinm } 306*20c794b3Sgavinm for (j = 0; j < 2; j++) { 307*20c794b3Sgavinm if (mc_add_channel(mod, mcnode, channel, auth, 308*20c794b3Sgavinm channel_nvl[channel]) < 0) { 309*20c794b3Sgavinm return (-1); 310*20c794b3Sgavinm } 311*20c794b3Sgavinm channel++; 312*20c794b3Sgavinm } 313*20c794b3Sgavinm } 314*20c794b3Sgavinm 315*20c794b3Sgavinm return (NULL); 316*20c794b3Sgavinm } 317*20c794b3Sgavinm 318*20c794b3Sgavinm int 319*20c794b3Sgavinm mc_offchip_create(topo_mod_t *mod, tnode_t *pnode, const char *name, 320*20c794b3Sgavinm nvlist_t *auth) 321*20c794b3Sgavinm { 322*20c794b3Sgavinm mc_snapshot_info_t mcs; 323*20c794b3Sgavinm void *buf = NULL; 324*20c794b3Sgavinm nvlist_t *nvl; 325*20c794b3Sgavinm uint8_t ver; 326*20c794b3Sgavinm int rc; 327*20c794b3Sgavinm 328*20c794b3Sgavinm if (ioctl(mc_fd, MC_IOC_SNAPSHOT_INFO, &mcs) == -1 || 329*20c794b3Sgavinm (buf = topo_mod_alloc(mod, mcs.mcs_size)) == NULL || 330*20c794b3Sgavinm ioctl(mc_fd, MC_IOC_SNAPSHOT, buf) == -1) { 331*20c794b3Sgavinm 332*20c794b3Sgavinm whinge(mod, NULL, "mc failed to snapshot %s\n", 333*20c794b3Sgavinm strerror(errno)); 334*20c794b3Sgavinm 335*20c794b3Sgavinm free(buf); 336*20c794b3Sgavinm (void) close(mc_fd); 337*20c794b3Sgavinm return (NULL); 338*20c794b3Sgavinm } 339*20c794b3Sgavinm (void) close(mc_fd); 340*20c794b3Sgavinm (void) nvlist_unpack(buf, mcs.mcs_size, &nvl, 0); 341*20c794b3Sgavinm topo_mod_free(mod, buf, mcs.mcs_size); 342*20c794b3Sgavinm 343*20c794b3Sgavinm if (nvlist_lookup_uint8(nvl, MCINTEL_NVLIST_VERSTR, &ver) != 0) { 344*20c794b3Sgavinm whinge(mod, NULL, "mc nvlist is not versioned\n"); 345*20c794b3Sgavinm nvlist_free(nvl); 346*20c794b3Sgavinm return (NULL); 347*20c794b3Sgavinm } else if (ver != MCINTEL_NVLIST_VERS0) { 348*20c794b3Sgavinm whinge(mod, NULL, "mc nvlist version mismatch\n"); 349*20c794b3Sgavinm nvlist_free(nvl); 350*20c794b3Sgavinm return (NULL); 351*20c794b3Sgavinm } 352*20c794b3Sgavinm 353*20c794b3Sgavinm rc = mc_nb_create(mod, pnode, name, auth, nvl); 354*20c794b3Sgavinm 355*20c794b3Sgavinm nvlist_free(nvl); 356*20c794b3Sgavinm return (rc); 357*20c794b3Sgavinm } 358