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