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 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <strings.h>
30 #include <sys/types.h>
31 #include <fm/topo_mod.h>
32 #include <fm/topo_hc.h>
33 #include <sys/fm/protocol.h>
34 
35 #include <unistd.h>
36 #include <sys/param.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include <umem.h>
40 
41 #include <cpu_mdesc.h>
42 
43 
44 /*
45  * Enumerates the processing chips, or sockets, (as distinct from cores) in a
46  * system.  For each chip found, the necessary nodes (one or more cores, and
47  * possibly a memory controller) are constructed underneath.
48  */
49 
50 #define	CHIP_VERSION	TOPO_VERSION
51 #define	CPU_NODE_NAME	"cpu"
52 #define	CHIP_NODE_NAME	"chip"
53 
54 extern topo_method_t pi_cpu_methods[];
55 
56 /* Forward declaration */
57 static int chip_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t,
58     topo_instance_t, void *, void *);
59 static void chip_release(topo_mod_t *, tnode_t *);
60 
61 static const topo_modops_t chip_ops =
62 	{ chip_enum, chip_release };
63 static const topo_modinfo_t chip_info =
64 	{ "chip", FM_FMRI_SCHEME_HC, CHIP_VERSION, &chip_ops };
65 
66 
67 static const topo_pgroup_info_t chip_auth_pgroup = {
68 	FM_FMRI_AUTHORITY,
69 	TOPO_STABILITY_PRIVATE,
70 	TOPO_STABILITY_PRIVATE,
71 	1
72 };
73 
74 int
_topo_init(topo_mod_t * mod)75 _topo_init(topo_mod_t *mod)
76 {
77 	md_info_t *chip;
78 
79 	if (getenv("TOPOCHIPDBG"))
80 		topo_mod_setdebug(mod);
81 	topo_mod_dprintf(mod, "initializing chip enumerator\n");
82 
83 	if ((chip = topo_mod_zalloc(mod, sizeof (md_info_t))) == NULL)
84 		return (-1);
85 
86 	if (cpu_mdesc_init(mod, chip) != 0) {
87 		topo_mod_dprintf(mod, "failed to get cpus from the PRI/MD\n");
88 		topo_mod_free(mod, chip, sizeof (md_info_t));
89 		return (-1);
90 	}
91 
92 	topo_mod_setspecific(mod, (void *)chip);
93 
94 	if (topo_mod_register(mod, &chip_info, TOPO_VERSION) != 0) {
95 		topo_mod_dprintf(mod, "failed to register hc: "
96 		    "%s\n", topo_mod_errmsg(mod));
97 		cpu_mdesc_fini(mod, chip);
98 		topo_mod_free(mod, chip, sizeof (md_info_t));
99 		return (-1);
100 	}
101 
102 	topo_mod_dprintf(mod, "chip enumerator inited\n");
103 
104 	return (0);
105 }
106 
107 void
_topo_fini(topo_mod_t * mod)108 _topo_fini(topo_mod_t *mod)
109 {
110 	md_info_t *chip;
111 
112 	chip = (md_info_t *)topo_mod_getspecific(mod);
113 
114 	cpu_mdesc_fini(mod, chip);
115 
116 	topo_mod_free(mod, chip, sizeof (md_info_t));
117 
118 	topo_mod_unregister(mod);
119 }
120 
121 static tnode_t *
chip_tnode_create(topo_mod_t * mod,tnode_t * parent,const char * name,topo_instance_t i,char * serial,nvlist_t * fru,char * label,void * priv)122 chip_tnode_create(topo_mod_t *mod, tnode_t *parent,
123     const char *name, topo_instance_t i, char *serial,
124     nvlist_t *fru, char *label, void *priv)
125 {
126 	int err;
127 	nvlist_t *fmri;
128 	tnode_t *ntn;
129 	char *prod = NULL, *psn = NULL, *csn = NULL, *server = NULL;
130 	nvlist_t *auth = NULL;
131 
132 	if (topo_mod_nvalloc(mod, &auth, NV_UNIQUE_NAME) == 0) {
133 		if (topo_prop_get_string(parent, FM_FMRI_AUTHORITY,
134 		    FM_FMRI_AUTH_PRODUCT, &prod, &err) == 0) {
135 			(void) nvlist_add_string(auth, FM_FMRI_AUTH_PRODUCT,
136 			    prod);
137 			topo_mod_strfree(mod, prod);
138 		}
139 		if (topo_prop_get_string(parent, FM_FMRI_AUTHORITY,
140 		    FM_FMRI_AUTH_PRODUCT_SN, &psn, &err) == 0) {
141 			(void) nvlist_add_string(auth, FM_FMRI_AUTH_PRODUCT_SN,
142 			    psn);
143 			topo_mod_strfree(mod, psn);
144 		}
145 		if (topo_prop_get_string(parent, FM_FMRI_AUTHORITY,
146 		    FM_FMRI_AUTH_SERVER, &server, &err) == 0) {
147 			(void) nvlist_add_string(auth, FM_FMRI_AUTH_SERVER,
148 			    server);
149 			topo_mod_strfree(mod, server);
150 		}
151 		if (topo_prop_get_string(parent, FM_FMRI_AUTHORITY,
152 		    FM_FMRI_AUTH_CHASSIS, &csn, &err) == 0) {
153 			(void) nvlist_add_string(auth, FM_FMRI_AUTH_CHASSIS,
154 			    csn);
155 			topo_mod_strfree(mod, csn);
156 		}
157 	}
158 
159 
160 	fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, name, i,
161 	    NULL, auth, NULL, NULL, serial);
162 	nvlist_free(auth);
163 	if (fmri == NULL) {
164 		topo_mod_dprintf(mod,
165 		    "Unable to make nvlist for %s bind: %s.\n",
166 		    name, topo_mod_errmsg(mod));
167 		return (NULL);
168 	}
169 
170 	ntn = topo_node_bind(mod, parent, name, i, fmri);
171 	if (ntn == NULL) {
172 		topo_mod_dprintf(mod,
173 		    "topo_node_bind (%s%d/%s%d) failed: %s\n",
174 		    topo_node_name(parent), topo_node_instance(parent),
175 		    name, i,
176 		    topo_strerror(topo_mod_errno(mod)));
177 		nvlist_free(fmri);
178 		return (NULL);
179 	}
180 	nvlist_free(fmri);
181 	topo_node_setspecific(ntn, priv);
182 
183 	if (topo_pgroup_create(ntn, &chip_auth_pgroup, &err) == 0) {
184 		(void) topo_prop_inherit(ntn, FM_FMRI_AUTHORITY,
185 		    FM_FMRI_AUTH_PRODUCT, &err);
186 		(void) topo_prop_inherit(ntn, FM_FMRI_AUTHORITY,
187 		    FM_FMRI_AUTH_PRODUCT_SN, &err);
188 		(void) topo_prop_inherit(ntn, FM_FMRI_AUTHORITY,
189 		    FM_FMRI_AUTH_CHASSIS, &err);
190 		(void) topo_prop_inherit(ntn, FM_FMRI_AUTHORITY,
191 		    FM_FMRI_AUTH_SERVER, &err);
192 	}
193 
194 	/* Inherit the Label FRU fields from the parent */
195 	(void) topo_node_label_set(ntn, label, &err);
196 	(void) topo_node_fru_set(ntn, fru, 0, &err);
197 
198 	/* Register retire methods */
199 	if (topo_method_register(mod, ntn, pi_cpu_methods) < 0)
200 		topo_mod_dprintf(mod, "Unsable to register retire methods "
201 		    "for %s%d/%s%d: %s\n",
202 		    topo_node_name(parent), topo_node_instance(parent),
203 		    name, i, topo_mod_errmsg(mod));
204 
205 	return (ntn);
206 }
207 
208 static nvlist_t *
cpu_fmri_create(topo_mod_t * mod,uint32_t cpuid,char * serial,uint8_t cpumask)209 cpu_fmri_create(topo_mod_t *mod, uint32_t cpuid, char *serial, uint8_t cpumask)
210 {
211 	int err;
212 	nvlist_t *fmri;
213 
214 	if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0)
215 		return (NULL);
216 	err = nvlist_add_uint8(fmri, FM_VERSION, FM_CPU_SCHEME_VERSION);
217 	err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU);
218 	err |= nvlist_add_uint32(fmri, FM_FMRI_CPU_ID, cpuid);
219 	err |= nvlist_add_uint8(fmri, FM_FMRI_CPU_MASK, cpumask);
220 	if (serial != NULL)
221 		err |= nvlist_add_string(fmri, FM_FMRI_CPU_SERIAL_ID, serial);
222 	if (err != 0) {
223 		nvlist_free(fmri);
224 		(void) topo_mod_seterrno(mod, EMOD_FMRI_NVL);
225 		return (NULL);
226 	}
227 
228 	return (fmri);
229 }
230 
231 /*ARGSUSED*/
232 static int
cpu_create(topo_mod_t * mod,tnode_t * rnode,const char * name,md_info_t * chip,uint64_t serial)233 cpu_create(topo_mod_t *mod, tnode_t *rnode, const char *name, md_info_t *chip,
234     uint64_t serial)
235 {
236 	int i;
237 	int min = -1;
238 	int max = -1;
239 	int err;
240 	int nerr = 0;
241 	int pid;
242 	char sbuf[32];
243 	tnode_t *cnode;
244 	nvlist_t *asru;
245 	md_cpumap_t *mcmp;
246 
247 	topo_mod_dprintf(mod, "enumerating cpus\n");
248 
249 	/*
250 	 * find the min/max id of cpus per this cmp and create a cpu range
251 	 */
252 	for (i = 0, mcmp = chip->cpus; i < chip->ncpus; i++, mcmp++) {
253 		if (mcmp->cpumap_serialno != serial)
254 			continue;
255 		if ((min < 0) || (mcmp->cpumap_pid < min))
256 			min = mcmp->cpumap_pid;
257 		if ((max < 0) || (mcmp->cpumap_pid > max))
258 			max = mcmp->cpumap_pid;
259 	}
260 	if (min < 0 || max < 0) {
261 		topo_mod_dprintf(mod, "Invalid cpu range(%d,%d)\n", min, max);
262 		return (-1);
263 	}
264 	if (topo_node_range_create(mod, rnode, name, 0, max+1) < 0) {
265 		topo_mod_dprintf(mod, "failed to create cpu range[0,%d]: %s\n",
266 		    max, topo_mod_errmsg(mod));
267 		return (-1);
268 	}
269 
270 	(void) snprintf(sbuf, sizeof (sbuf), "%llx", serial);
271 
272 	/*
273 	 * Create the cpu[i] nodes of a given cmp i
274 	 */
275 	for (i = 0, mcmp = chip->cpus; i < chip->ncpus; i++, mcmp++) {
276 
277 		if (mcmp->cpumap_serialno == 0 ||
278 		    mcmp->cpumap_serialno != serial) {
279 			continue;
280 		}
281 
282 		/* physical cpuid */
283 		pid = mcmp->cpumap_pid;
284 		cnode = chip_tnode_create(mod, rnode, name,
285 		    (topo_instance_t)pid, sbuf, NULL, NULL, NULL);
286 		if (cnode == NULL) {
287 			topo_mod_dprintf(mod,
288 			    "failed to create a cpu=%d node: %s\n",
289 			    pid, topo_mod_errmsg(mod));
290 			nerr++;
291 			continue;
292 		}
293 
294 		if ((asru = cpu_fmri_create(mod, pid, sbuf, 0)) != NULL) {
295 			(void) topo_node_asru_set(cnode, asru, 0, &err);
296 			nvlist_free(asru);
297 		} else {
298 			nerr++;
299 		}
300 	}
301 
302 	if (nerr != 0)
303 		(void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
304 
305 	return (0);
306 }
307 
308 static int
dimm_instantiate(tnode_t * parent,const char * name,topo_mod_t * mod)309 dimm_instantiate(tnode_t *parent, const char *name, topo_mod_t *mod)
310 {
311 	if (strcmp(name, CHIP) != 0) {
312 		topo_mod_dprintf(mod,
313 		    "Currently only know how to enumerate %s components.\n",
314 		    CHIP);
315 		return (0);
316 	}
317 	topo_mod_dprintf(mod,
318 	    "Calling dimm_enum\n");
319 	if (topo_mod_enumerate(mod,
320 	    parent, DIMM, DIMM, 0, 0, NULL) != 0) {
321 		return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
322 	}
323 	return (0);
324 }
325 
326 static topo_mod_t *
dimm_enum_load(topo_mod_t * mp)327 dimm_enum_load(topo_mod_t *mp)
328 {
329 	topo_mod_t *rp = NULL;
330 
331 	topo_mod_dprintf(mp, "dimm_enum_load: %s\n", CHIP);
332 	if ((rp = topo_mod_load(mp, DIMM, TOPO_VERSION)) == NULL) {
333 		topo_mod_dprintf(mp,
334 		    "%s enumerator could not load %s enum. (%d: %s)\n",
335 		    CHIP, DIMM, errno, strerror(errno));
336 	}
337 	topo_mod_dprintf(mp, "dimm_enum_load(EXIT): %s, rp=%p\n", CHIP, rp);
338 	return (rp);
339 }
340 
341 /*ARGSUSED*/
342 static int
chip_create(topo_mod_t * mod,tnode_t * rnode,const char * name,topo_instance_t min,topo_instance_t max,md_info_t * chip)343 chip_create(topo_mod_t *mod, tnode_t *rnode, const char *name,
344     topo_instance_t min, topo_instance_t max, md_info_t *chip)
345 {
346 	int nerr = 0;
347 	int err;
348 	int i;
349 	char sbuf[32];
350 	tnode_t *cnode;
351 	nvlist_t *fru = NULL;
352 	char *label = NULL;
353 	md_proc_t *procp;
354 
355 	topo_mod_dprintf(mod, "enumerating cmp chip\n");
356 	if (min > max) {
357 		topo_mod_dprintf(mod, "Invalid chip range(%d,%d)\n", min, max);
358 		return (-1);
359 	}
360 
361 	if (dimm_enum_load(mod) == NULL)
362 		return (-1);
363 
364 	/*
365 	 * Create the chip[i] nodes, one for each CMP chip uniquely identified
366 	 * by the serial number.
367 	 */
368 	for (i = min; i <= max; i++) {
369 
370 		/* Skip the processors with no serial number */
371 		if ((procp = cpu_find_proc(chip, i)) == NULL) {
372 			continue;
373 		}
374 		if (procp->serialno == 0) {
375 			continue;
376 		}
377 
378 		(void) snprintf(sbuf, sizeof (sbuf), "%llx", procp->serialno);
379 		topo_mod_dprintf(mod, "node chip[%d], sn=%s\n", i, sbuf);
380 
381 		cnode = chip_tnode_create(mod, rnode, name, (topo_instance_t)i,
382 		    sbuf, fru, label, NULL);
383 		if (cnode == NULL) {
384 			topo_mod_dprintf(mod, "failed to create a chip node: "
385 			    "%s\n", topo_mod_errmsg(mod));
386 			nerr++;
387 			continue;
388 		}
389 
390 		/* Enumerate all cpu strands of this CMP chip */
391 		err = cpu_create(mod, cnode, CPU_NODE_NAME, chip,
392 		    procp->serialno);
393 		if (err != 0) {
394 			nerr++;
395 		}
396 
397 		/* Enumerate all DIMMs belonging to this chip */
398 		if (dimm_instantiate(cnode, CHIP, mod) < 0) {
399 			topo_mod_dprintf(mod, "Enumeration of dimm "
400 			    "failed %s\n", topo_mod_errmsg(mod));
401 			return (-1);
402 		}
403 	}
404 
405 	if (nerr != 0)
406 		(void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
407 
408 	return (0);
409 }
410 
411 /*ARGSUSED*/
412 static int
chip_enum(topo_mod_t * mod,tnode_t * rnode,const char * name,topo_instance_t min,topo_instance_t max,void * arg,void * notused)413 chip_enum(topo_mod_t *mod, tnode_t *rnode, const char *name,
414     topo_instance_t min, topo_instance_t max, void *arg, void *notused)
415 {
416 	md_info_t *chip = (md_info_t *)arg;
417 
418 	if (strcmp(name, CHIP_NODE_NAME) == 0)
419 		return (chip_create(mod, rnode, name, min, max, chip));
420 
421 	return (0);
422 }
423 
424 /*ARGSUSED*/
425 static void
chip_release(topo_mod_t * mp,tnode_t * node)426 chip_release(topo_mod_t *mp, tnode_t *node)
427 {
428 }
429