xref: /illumos-gate/usr/src/lib/fm/topo/libtopo/common/mem.c (revision 0eb822a1)
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(nvl, 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(nvl, 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