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