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_method.h> 38 #include <mem.h> 39 40 static int mem_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, 41 topo_instance_t, void *, 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_fmri_create(topo_mod_t *, tnode_t *, topo_version_t, 46 nvlist_t *, nvlist_t **); 47 48 static const topo_method_t mem_methods[] = { 49 { TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION, 50 TOPO_STABILITY_INTERNAL, mem_nvl2str }, 51 { TOPO_METH_FMRI, TOPO_METH_FMRI_DESC, TOPO_METH_FMRI_VERSION, 52 TOPO_STABILITY_INTERNAL, mem_fmri_create }, 53 { NULL } 54 }; 55 56 static const topo_modops_t mem_ops = 57 { mem_enum, mem_release }; 58 static const topo_modinfo_t mem_info = 59 { "mem", FM_FMRI_SCHEME_MEM, MEM_VERSION, &mem_ops }; 60 61 int 62 mem_init(topo_mod_t *mod, topo_version_t version) 63 { 64 65 topo_mod_setdebug(mod); 66 topo_mod_dprintf(mod, "initializing mem builtin\n"); 67 68 if (version != MEM_VERSION) 69 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 70 71 if (topo_mod_register(mod, &mem_info, TOPO_VERSION) != 0) { 72 topo_mod_dprintf(mod, "failed to register mem_info: " 73 "%s\n", topo_mod_errmsg(mod)); 74 return (-1); /* mod errno already set */ 75 } 76 77 return (0); 78 } 79 80 void 81 mem_fini(topo_mod_t *mod) 82 { 83 topo_mod_unregister(mod); 84 } 85 86 /*ARGSUSED*/ 87 static int 88 mem_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, 89 topo_instance_t min, topo_instance_t max, void *notused1, void *notused2) 90 { 91 (void) topo_method_register(mod, pnode, mem_methods); 92 93 return (0); 94 } 95 96 static void 97 mem_release(topo_mod_t *mod, tnode_t *node) 98 { 99 topo_method_unregister_all(mod, node); 100 } 101 102 /*ARGSUSED*/ 103 static int 104 mem_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version, 105 nvlist_t *in, nvlist_t **out) 106 { 107 const char *format; 108 nvlist_t *nvl; 109 uint64_t val; 110 char *buf, *unum; 111 size_t len; 112 int err; 113 114 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0) 115 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 116 117 if (nvlist_lookup_string(in, FM_FMRI_MEM_UNUM, &unum) != 0) { 118 nvlist_free(nvl); 119 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 120 } 121 122 /* 123 * If we have a DIMM offset, include it in the string. If we have a 124 * PA then use that. Otherwise just format the unum element. 125 */ 126 if (nvlist_lookup_uint64(in, FM_FMRI_MEM_OFFSET, &val) == 0) { 127 format = FM_FMRI_SCHEME_MEM ":///%1$s/" 128 FM_FMRI_MEM_OFFSET "=%2$llx"; 129 } else if (nvlist_lookup_uint64(in, FM_FMRI_MEM_PHYSADDR, &val) == 0) { 130 format = FM_FMRI_SCHEME_MEM ":///%1$s/" 131 FM_FMRI_MEM_PHYSADDR "=%2$llx"; 132 } else 133 format = FM_FMRI_SCHEME_MEM ":///" "%1$s"; 134 135 /* 136 * If we have a well-formed unum we step over the hc:// and 137 * authority prefix 138 */ 139 if (strncmp(unum, "hc://", 5) == 0) { 140 unum += 5; 141 unum = strchr(unum, '/'); 142 ++unum; 143 } 144 145 len = snprintf(NULL, 0, format, unum, val) + 1; 146 buf = topo_mod_zalloc(mod, len); 147 148 if (buf == NULL) { 149 nvlist_free(nvl); 150 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 151 } 152 153 (void) snprintf(buf, len, format, unum, val); 154 err = nvlist_add_string(nvl, "fmri-string", buf); 155 topo_mod_free(mod, buf, len); 156 157 if (err != 0) { 158 nvlist_free(nvl); 159 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 160 } 161 162 *out = nvl; 163 return (0); 164 } 165 166 static nvlist_t * 167 mem_fmri(topo_mod_t *mod, uint64_t pa, uint64_t offset, char *unum, int flags) 168 { 169 int err; 170 nvlist_t *asru; 171 172 if (topo_mod_nvalloc(mod, &asru, NV_UNIQUE_NAME) != 0) 173 return (NULL); 174 175 /* 176 * If we have a well-formed unum we step over the hc:/// and 177 * authority prefix 178 */ 179 if (strncmp(unum, "hc://", 5) == 0) { 180 char *tstr; 181 182 tstr = strchr(unum, '/'); 183 unum = ++tstr; 184 } 185 186 err = nvlist_add_uint8(asru, FM_VERSION, FM_MEM_SCHEME_VERSION); 187 err |= nvlist_add_string(asru, FM_FMRI_SCHEME, FM_FMRI_SCHEME_MEM); 188 err |= nvlist_add_string(asru, FM_FMRI_MEM_UNUM, unum); 189 if (flags & TOPO_MEMFMRI_PA) 190 err |= nvlist_add_uint64(asru, FM_FMRI_MEM_PHYSADDR, pa); 191 if (flags & TOPO_MEMFMRI_OFFSET) 192 err |= nvlist_add_uint64(asru, FM_FMRI_MEM_OFFSET, offset); 193 194 if (err != 0) { 195 nvlist_free(asru); 196 return (NULL); 197 } 198 199 return (asru); 200 } 201 202 /*ARGSUSED*/ 203 static int 204 mem_fmri_create(topo_mod_t *mod, tnode_t *node, topo_version_t version, 205 nvlist_t *in, nvlist_t **out) 206 { 207 uint64_t pa = 0, offset = 0; 208 int flags = 0; 209 nvlist_t *asru; 210 char *unum; 211 212 if (nvlist_lookup_uint64(in, FM_FMRI_MEM_PHYSADDR, &pa) == 0) 213 flags |= TOPO_MEMFMRI_PA; 214 if (nvlist_lookup_uint64(in, FM_FMRI_MEM_OFFSET, &offset) == 0) 215 flags |= TOPO_MEMFMRI_OFFSET; 216 if (nvlist_lookup_string(in, FM_FMRI_MEM_UNUM, &unum) != 0) 217 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 218 219 asru = mem_fmri(mod, pa, offset, unum, flags); 220 221 if (asru == NULL) 222 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 223 224 *out = asru; 225 226 return (0); 227 } 228