1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <errno.h> 30 #include <kstat.h> 31 #include <limits.h> 32 #include <strings.h> 33 #include <unistd.h> 34 #include <fm/topo_mod.h> 35 #include <sys/fm/protocol.h> 36 37 #include <topo_error.h> 38 39 static int mem_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, 40 topo_instance_t, void *); 41 static void mem_release(topo_mod_t *, tnode_t *); 42 static int mem_nvl2str(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 43 nvlist_t **); 44 static int mem_str2nvl(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 45 nvlist_t **); 46 static int mem_present(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 47 nvlist_t **); 48 static int mem_contains(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 49 nvlist_t **); 50 static int mem_unusable(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 51 nvlist_t **); 52 static int mem_expand(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 53 nvlist_t **); 54 static int mem_asru(topo_mod_t *, tnode_t *, topo_version_t, 55 nvlist_t *, nvlist_t **); 56 57 #define MEM_VERSION TOPO_VERSION 58 59 static const topo_method_t mem_methods[] = { 60 { TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION, 61 TOPO_STABILITY_INTERNAL, mem_nvl2str }, 62 { TOPO_METH_STR2NVL, TOPO_METH_STR2NVL_DESC, TOPO_METH_STR2NVL_VERSION, 63 TOPO_STABILITY_INTERNAL, mem_str2nvl }, 64 { TOPO_METH_PRESENT, TOPO_METH_PRESENT_DESC, TOPO_METH_PRESENT_VERSION, 65 TOPO_STABILITY_INTERNAL, mem_present }, 66 { TOPO_METH_CONTAINS, TOPO_METH_CONTAINS_DESC, 67 TOPO_METH_CONTAINS_VERSION, TOPO_STABILITY_INTERNAL, mem_contains }, 68 { TOPO_METH_UNUSABLE, TOPO_METH_UNUSABLE_DESC, 69 TOPO_METH_UNUSABLE_VERSION, TOPO_STABILITY_INTERNAL, mem_unusable }, 70 { TOPO_METH_EXPAND, TOPO_METH_UNUSABLE_DESC, 71 TOPO_METH_EXPAND_VERSION, TOPO_STABILITY_INTERNAL, mem_expand }, 72 { TOPO_METH_ASRU_COMPUTE, TOPO_METH_ASRU_COMPUTE_DESC, 73 TOPO_METH_ASRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL, mem_asru }, 74 { NULL } 75 }; 76 77 static const topo_modinfo_t mem_info = 78 { "mem", MEM_VERSION, mem_enum, mem_release }; 79 80 void 81 mem_init(topo_mod_t *mod) 82 { 83 84 topo_mod_setdebug(mod, TOPO_DBG_ALL); 85 topo_mod_dprintf(mod, "initializing mem builtin\n"); 86 87 if (topo_mod_register(mod, &mem_info, NULL) != 0) { 88 topo_mod_dprintf(mod, "failed to register mem_info: " 89 "%s\n", topo_mod_errmsg(mod)); 90 return; 91 } 92 } 93 94 void 95 mem_fini(topo_mod_t *mod) 96 { 97 topo_mod_unregister(mod); 98 } 99 100 /*ARGSUSED*/ 101 static int 102 mem_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, 103 topo_instance_t min, topo_instance_t max, void *arg) 104 { 105 (void) topo_method_register(mod, pnode, mem_methods); 106 107 return (0); 108 } 109 110 static void 111 mem_release(topo_mod_t *mod, tnode_t *node) 112 { 113 topo_method_unregister_all(mod, node); 114 } 115 116 /*ARGSUSED*/ 117 static int 118 mem_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version, 119 nvlist_t *in, nvlist_t **out) 120 { 121 const char *format; 122 nvlist_t *nvl; 123 uint64_t val; 124 char *buf, *unum; 125 size_t len; 126 int err; 127 128 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0) 129 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 130 131 if (nvlist_lookup_string(in, FM_FMRI_MEM_UNUM, &unum) != 0) { 132 nvlist_free(nvl); 133 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 134 } 135 136 /* 137 * If we have a DIMM offset, include it in the string. If we have a 138 * PA then use that. Otherwise just format the unum element. 139 */ 140 if (nvlist_lookup_uint64(nvl, FM_FMRI_MEM_OFFSET, &val) == 0) { 141 format = FM_FMRI_SCHEME_MEM ":///" 142 FM_FMRI_MEM_UNUM "=%1$s/" FM_FMRI_MEM_OFFSET "=%2$llx"; 143 } else if (nvlist_lookup_uint64(nvl, FM_FMRI_MEM_PHYSADDR, &val) == 0) { 144 format = FM_FMRI_SCHEME_MEM ":///" 145 FM_FMRI_MEM_UNUM "=%1$s/" FM_FMRI_MEM_PHYSADDR "=%2$llx"; 146 } else 147 format = FM_FMRI_SCHEME_MEM ":///" FM_FMRI_MEM_UNUM "=%1$s"; 148 149 len = snprintf(NULL, 0, format, unum, val); 150 buf = topo_mod_zalloc(mod, len); 151 152 if (buf == NULL) { 153 nvlist_free(nvl); 154 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 155 } 156 157 (void) snprintf(buf, len, format, unum, val); 158 err = nvlist_add_string(nvl, "fmri-string", buf); 159 topo_mod_free(mod, buf, len); 160 161 if (err != 0) { 162 nvlist_free(nvl); 163 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 164 } 165 166 *out = nvl; 167 return (0); 168 } 169 170 /*ARGSUSED*/ 171 static int 172 mem_str2nvl(topo_mod_t *mod, tnode_t *node, topo_version_t version, 173 nvlist_t *in, nvlist_t **out) 174 { 175 return (-1); 176 } 177 178 /*ARGSUSED*/ 179 static int 180 mem_present(topo_mod_t *mod, tnode_t *node, topo_version_t version, 181 nvlist_t *in, nvlist_t **out) 182 { 183 return (-1); 184 } 185 186 /*ARGSUSED*/ 187 static int 188 mem_contains(topo_mod_t *mod, tnode_t *node, topo_version_t version, 189 nvlist_t *in, nvlist_t **out) 190 { 191 return (-1); 192 } 193 194 /*ARGSUSED*/ 195 static int 196 mem_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t version, 197 nvlist_t *in, nvlist_t **out) 198 { 199 return (-1); 200 } 201 202 /*ARGSUSED*/ 203 static int 204 mem_expand(topo_mod_t *mod, tnode_t *node, topo_version_t version, 205 nvlist_t *in, nvlist_t **out) 206 { 207 return (-1); 208 } 209 210 /*ARGSUSED*/ 211 static int 212 mem_asru(topo_mod_t *mod, tnode_t *node, topo_version_t version, 213 nvlist_t *in, nvlist_t **out) 214 { 215 int err; 216 uint64_t pa = 0, offset = 0; 217 int incl_pa = 0, incl_offset = 0; 218 nvlist_t *hcsp = NULL; 219 nvlist_t *asru; 220 char *cstr; 221 222 if (nvlist_lookup_nvlist(in, FM_FMRI_HC_SPECIFIC, &hcsp) == 0) { 223 incl_pa = (nvlist_lookup_uint64(hcsp, 224 "asru-"FM_FMRI_MEM_PHYSADDR, &pa) == 0); 225 incl_offset = (nvlist_lookup_uint64(hcsp, 226 "asru-"FM_FMRI_MEM_OFFSET, &offset) == 0); 227 } 228 229 if (topo_fmri_nvl2str(topo_mod_handle(mod), in, &cstr, &err) < 0) 230 return (topo_mod_seterrno(mod, err)); 231 232 if (topo_mod_nvalloc(mod, &asru, NV_UNIQUE_NAME) != 0) { 233 topo_mod_strfree(mod, cstr); 234 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 235 } 236 err = nvlist_add_uint8(asru, FM_VERSION, FM_MEM_SCHEME_VERSION); 237 err |= nvlist_add_string(asru, FM_FMRI_SCHEME, FM_FMRI_SCHEME_MEM); 238 err |= nvlist_add_string(asru, FM_FMRI_MEM_UNUM, cstr); 239 if (incl_pa) 240 err |= nvlist_add_uint64(asru, FM_FMRI_MEM_PHYSADDR, pa); 241 if (incl_offset) 242 err |= nvlist_add_uint64(asru, FM_FMRI_MEM_OFFSET, offset); 243 topo_mod_strfree(mod, cstr); 244 if (err != 0) { 245 nvlist_free(asru); 246 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 247 } 248 249 *out = asru; 250 251 return (0); 252 } 253