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 <unistd.h>
28 #include <fcntl.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include <string.h>
33 #include <strings.h>
34 #include <limits.h>
35 #include <alloca.h>
36 #include <kstat.h>
37 #include <errno.h>
38 #include <libnvpair.h>
39 #include <sys/types.h>
40 #include <sys/bitmap.h>
41 #include <sys/processor.h>
42 #include <sys/param.h>
43 #include <sys/fm/protocol.h>
44 #include <sys/systeminfo.h>
45 #include <sys/mc.h>
46 #include <sys/mc_amd.h>
47 #include <sys/mc_intel.h>
48 #include <sys/devfm.h>
49 #include <fm/fmd_agent.h>
50 #include <fm/topo_mod.h>
51 
52 #include "chip.h"
53 
54 #define	MAX_DIMMNUM	7
55 #define	MAX_CSNUM	7
56 
57 /*
58  * Enumerates the processing chips, or sockets, (as distinct from cores) in a
59  * system.  For each chip found, the necessary nodes (one or more cores, and
60  * possibly a memory controller) are constructed underneath.
61  */
62 
63 static int chip_enum(topo_mod_t *, tnode_t *, const char *,
64     topo_instance_t, topo_instance_t, void *, void *);
65 
66 static const topo_modops_t chip_ops =
67 	{ chip_enum, NULL};
68 static const topo_modinfo_t chip_info =
69 	{ CHIP_NODE_NAME, FM_FMRI_SCHEME_HC, CHIP_VERSION, &chip_ops };
70 
71 static const topo_pgroup_info_t chip_pgroup =
72 	{ PGNAME(CHIP), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
73 
74 static const topo_pgroup_info_t core_pgroup =
75 	{ PGNAME(CORE), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
76 
77 static const topo_pgroup_info_t strand_pgroup =
78 	{ PGNAME(STRAND), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
79 
80 static const topo_method_t chip_methods[] = {
81 	{ SIMPLE_CHIP_LBL, "Property method", 0,
82 	    TOPO_STABILITY_INTERNAL, simple_chip_label},
83 	{ G4_CHIP_LBL, "Property method", 0,
84 	    TOPO_STABILITY_INTERNAL, g4_chip_label},
85 	{ A4FPLUS_CHIP_LBL, "Property method", 0,
86 	    TOPO_STABILITY_INTERNAL, a4fplus_chip_label},
87 	{ FSB2_CHIP_LBL, "Property method", 0,
88 	    TOPO_STABILITY_INTERNAL, fsb2_chip_label},
89 	{ NULL }
90 };
91 
92 static const topo_method_t strands_retire_methods[] = {
93 	{ TOPO_METH_RETIRE, TOPO_METH_RETIRE_DESC,
94 	    TOPO_METH_RETIRE_VERSION, TOPO_STABILITY_INTERNAL,
95 	    retire_strands },
96 	{ TOPO_METH_UNRETIRE, TOPO_METH_UNRETIRE_DESC,
97 	    TOPO_METH_UNRETIRE_VERSION, TOPO_STABILITY_INTERNAL,
98 	    unretire_strands },
99 	{ TOPO_METH_SERVICE_STATE, TOPO_METH_SERVICE_STATE_DESC,
100 	    TOPO_METH_SERVICE_STATE_VERSION, TOPO_STABILITY_INTERNAL,
101 	    service_state_strands },
102 	{ TOPO_METH_UNUSABLE, TOPO_METH_UNUSABLE_DESC,
103 	    TOPO_METH_UNUSABLE_VERSION, TOPO_STABILITY_INTERNAL,
104 	    unusable_strands },
105 	{ NULL }
106 };
107 
108 int
109 _topo_init(topo_mod_t *mod)
110 {
111 	if (getenv("TOPOCHIPDBG"))
112 		topo_mod_setdebug(mod);
113 	topo_mod_dprintf(mod, "initializing chip enumerator\n");
114 
115 	if (topo_mod_register(mod, &chip_info, TOPO_VERSION) != 0) {
116 		whinge(mod, NULL, "failed to register hc: "
117 		    "%s\n", topo_mod_errmsg(mod));
118 		return (-1); /* mod errno set */
119 	}
120 
121 	return (0);
122 }
123 
124 void
125 _topo_fini(topo_mod_t *mod)
126 {
127 	topo_mod_unregister(mod);
128 }
129 
130 boolean_t
131 is_xpv(void)
132 {
133 	static int r = -1;
134 	char platform[MAXNAMELEN];
135 
136 	if (r != -1)
137 		return (r == 0);
138 
139 	(void) sysinfo(SI_PLATFORM, platform, sizeof (platform));
140 	r = strcmp(platform, "i86xpv");
141 	return (r == 0);
142 }
143 
144 static tnode_t *
145 create_node(topo_mod_t *mod, tnode_t *pnode, nvlist_t *auth, char *name,
146     topo_instance_t inst, uint16_t smbios_id)
147 {
148 	nvlist_t *fmri;
149 	tnode_t *cnode;
150 
151 	if (mkrsrc(mod, pnode, name, inst, auth, &fmri) != 0) {
152 		whinge(mod, NULL, "create_node: mkrsrc failed\n");
153 		return (NULL);
154 	}
155 
156 	if (FM_AWARE_SMBIOS(mod)) {
157 		id_t phys_cpu_smbid;
158 		int perr = 0;
159 		const char *serial = NULL;
160 		const char *part = NULL;
161 		const char *rev = NULL;
162 
163 		phys_cpu_smbid = smbios_id;
164 		serial = chip_serial_smbios_get(mod, phys_cpu_smbid);
165 		part = chip_part_smbios_get(mod, phys_cpu_smbid);
166 		rev = chip_rev_smbios_get(mod, phys_cpu_smbid);
167 
168 		perr += nvlist_add_string(fmri, FM_FMRI_HC_SERIAL_ID,
169 		    serial);
170 		perr += nvlist_add_string(fmri, FM_FMRI_HC_PART,
171 		    part);
172 		perr += nvlist_add_string(fmri, FM_FMRI_HC_REVISION,
173 		    rev);
174 
175 		if (perr != 0)
176 			whinge(mod, NULL,
177 			    "create_node: nvlist_add_string failed\n");
178 
179 		topo_mod_strfree(mod, (char *)serial);
180 		topo_mod_strfree(mod, (char *)part);
181 		topo_mod_strfree(mod, (char *)rev);
182 	}
183 
184 	cnode = topo_node_bind(mod, pnode, name, inst, fmri);
185 
186 	nvlist_free(fmri);
187 	if (cnode == NULL) {
188 		whinge(mod, NULL, "create_node: node bind failed"
189 		    " for %s %d\n", name, (int)inst);
190 	}
191 
192 	return (cnode);
193 }
194 
195 static int
196 create_strand(topo_mod_t *mod, tnode_t *pnode, nvlist_t *cpu,
197     nvlist_t *auth, uint16_t chip_smbiosid)
198 {
199 	tnode_t *strand;
200 	int32_t strandid, cpuid;
201 	int err, perr, nerr = 0;
202 	nvlist_t *fmri;
203 	char *serial = NULL;
204 	char *part = NULL;
205 	char *rev = NULL;
206 
207 	if ((err = nvlist_lookup_int32(cpu, FM_PHYSCPU_INFO_STRAND_ID,
208 	    &strandid)) != 0) {
209 		whinge(mod, NULL, "create_strand: lookup strand_id failed: "
210 		    "%s\n", strerror(err));
211 		return (-1);
212 	}
213 
214 	if ((strand = topo_node_lookup(pnode, STRAND_NODE_NAME, strandid))
215 	    != NULL) {
216 		whinge(mod, NULL, "create_strand: duplicate tuple found\n");
217 		return (-1);
218 	}
219 
220 	if ((strand = create_node(mod, pnode, auth, STRAND_NODE_NAME,
221 	    strandid, chip_smbiosid)) == NULL)
222 		return (-1);
223 
224 	/*
225 	 * Inherit FRU from core node, in native use cpu scheme ASRU,
226 	 * in xpv, use hc scheme ASRU.
227 	 */
228 	(void) topo_node_fru_set(strand, NULL, 0, &perr);
229 	/*
230 	 * From the inherited FRU, extract the Serial
231 	 * number(if SMBIOS donates) and set it in the ASRU
232 	 */
233 	if (FM_AWARE_SMBIOS(mod)) {
234 		char *val = NULL;
235 
236 		if (topo_prop_get_fmri(strand, TOPO_PGROUP_PROTOCOL,
237 		    TOPO_PROP_RESOURCE, &fmri, &err) != 0)
238 			whinge(mod, NULL,
239 			    "create_strand: topo_prop_get_fmri failed\n");
240 		if (nvlist_lookup_string(fmri, FM_FMRI_HC_SERIAL_ID, &val) != 0)
241 			whinge(mod, NULL,
242 			    "create_strand: nvlist_lookup_string failed: \n");
243 		else
244 			serial = topo_mod_strdup(mod, val);
245 		nvlist_free(fmri);
246 	}
247 	if (is_xpv()) {
248 		if (topo_node_resource(strand, &fmri, &err) == -1) {
249 			whinge(mod, &nerr, "create_strand: "
250 			    "topo_node_resource failed\n");
251 		} else {
252 			if (FM_AWARE_SMBIOS(mod))
253 				(void) nvlist_add_string(fmri,
254 				    FM_FMRI_HC_SERIAL_ID, serial);
255 			(void) topo_node_asru_set(strand, fmri, 0, &err);
256 			nvlist_free(fmri);
257 		}
258 	} else {
259 		if (nvlist_lookup_int32(cpu, STRAND_CPU_ID, &cpuid) != 0) {
260 			whinge(mod, &nerr, "create_strand: lookup cpuid "
261 			    "failed\n");
262 		} else {
263 			if ((fmri = cpu_fmri_create(mod, cpuid, serial, 0))
264 			    != NULL) {
265 				(void) topo_node_asru_set(strand, fmri,
266 				    0, &err);
267 				nvlist_free(fmri);
268 			} else {
269 				whinge(mod, &nerr, "create_strand: "
270 				    "cpu_fmri_create() failed\n");
271 			}
272 		}
273 	}
274 
275 	if (topo_method_register(mod, strand, strands_retire_methods) < 0)
276 		whinge(mod, &nerr, "create_strand: "
277 		    "topo_method_register failed\n");
278 
279 	(void) topo_pgroup_create(strand, &strand_pgroup, &err);
280 	nerr -= add_nvlist_longprops(mod, strand, cpu, PGNAME(STRAND), NULL,
281 	    STRAND_CHIP_ID, STRAND_CORE_ID, STRAND_CPU_ID, NULL);
282 
283 	if (FM_AWARE_SMBIOS(mod)) {
284 		(void) topo_node_label_set(strand, NULL, &perr);
285 
286 		if (topo_node_resource(strand, &fmri, &perr) != 0) {
287 			whinge(mod, &nerr, "create_strand: "
288 			    "topo_node_resource failed\n");
289 			perr = 0;
290 		}
291 
292 		perr += nvlist_lookup_string(fmri,
293 		    FM_FMRI_HC_PART, &part);
294 		perr += nvlist_lookup_string(fmri,
295 		    FM_FMRI_HC_REVISION, &rev);
296 
297 		if (perr != 0) {
298 			whinge(mod, NULL,
299 			    "create_strand: nvlist_lookup_string failed\n");
300 			perr = 0;
301 		}
302 
303 		perr += topo_prop_set_string(strand, PGNAME(STRAND),
304 		    FM_FMRI_HC_SERIAL_ID, TOPO_PROP_IMMUTABLE, serial, &perr);
305 		perr += topo_prop_set_string(strand, PGNAME(STRAND),
306 		    FM_FMRI_HC_PART, TOPO_PROP_IMMUTABLE, part, &perr);
307 		perr += topo_prop_set_string(strand, PGNAME(STRAND),
308 		    FM_FMRI_HC_REVISION, TOPO_PROP_IMMUTABLE, rev, &perr);
309 
310 		if (perr != 0)
311 			whinge(mod, NULL, "create_strand: topo_prop_set_string"
312 			    "failed\n");
313 
314 		nvlist_free(fmri);
315 		topo_mod_strfree(mod, serial);
316 	}
317 
318 	return (err == 0 && nerr == 0 ? 0 : -1);
319 }
320 
321 static int
322 create_core(topo_mod_t *mod, tnode_t *pnode, nvlist_t *cpu,
323     nvlist_t *auth, uint16_t chip_smbiosid)
324 {
325 	tnode_t *core;
326 	int32_t coreid, cpuid;
327 	int err, perr, nerr = 0;
328 	nvlist_t *fmri;
329 	char *serial = NULL;
330 	char *part = NULL;
331 	char *rev = NULL;
332 
333 	if ((err = nvlist_lookup_int32(cpu, FM_PHYSCPU_INFO_CORE_ID, &coreid))
334 	    != 0) {
335 		whinge(mod, NULL, "create_core: lookup core_id failed: %s\n",
336 		    strerror(err));
337 		return (-1);
338 	}
339 	if ((core = topo_node_lookup(pnode, CORE_NODE_NAME, coreid)) == NULL) {
340 		if ((core = create_node(mod, pnode, auth, CORE_NODE_NAME,
341 		    coreid, chip_smbiosid)) == NULL)
342 			return (-1);
343 
344 		/*
345 		 * Inherit FRU from the chip node, for native, we use hc
346 		 * scheme ASRU for the core node.
347 		 */
348 		(void) topo_node_fru_set(core, NULL, 0, &perr);
349 		/*
350 		 * From the inherited FRU, extract the Serial
351 		 * number if SMBIOS donates and set it in the ASRU
352 		 */
353 		if (FM_AWARE_SMBIOS(mod)) {
354 			char *val = NULL;
355 
356 			if (topo_node_resource(core, &fmri, &err) != 0)
357 				whinge(mod, NULL,
358 				    "create_core: topo_prop_get_fmri failed\n");
359 			if (nvlist_lookup_string(fmri, FM_FMRI_HC_SERIAL_ID,
360 			    &val) != 0)
361 				whinge(mod, NULL, "create_core:"
362 				    "nvlist_lookup_string failed\n");
363 			else
364 				serial = topo_mod_strdup(mod, val);
365 			nvlist_free(fmri);
366 		}
367 		if (is_xpv()) {
368 			if (topo_node_resource(core, &fmri, &err) == -1) {
369 				whinge(mod, &nerr, "create_core: "
370 				    "topo_node_resource failed\n");
371 			} else {
372 				if (FM_AWARE_SMBIOS(mod))
373 					(void) nvlist_add_string(fmri,
374 					    FM_FMRI_HC_SERIAL_ID, serial);
375 				(void) topo_node_asru_set(core, fmri, 0, &err);
376 				nvlist_free(fmri);
377 			}
378 		}
379 		if (topo_method_register(mod, core, strands_retire_methods) < 0)
380 			whinge(mod, &nerr, "create_core: "
381 			    "topo_method_register failed\n");
382 
383 		(void) topo_pgroup_create(core, &core_pgroup, &err);
384 		nerr -= add_nvlist_longprop(mod, core, cpu, PGNAME(CORE),
385 		    CORE_CHIP_ID, NULL);
386 
387 		if (topo_node_range_create(mod, core, STRAND_NODE_NAME,
388 		    0, 255) != 0)
389 			return (-1);
390 	}
391 
392 	if (!is_xpv()) {
393 		/*
394 		 * In native mode, we're in favor of cpu scheme ASRU for
395 		 * printing reason.  More work needs to be done to support
396 		 * multi-strand cpu: the ASRU will be a list of cpuid then.
397 		 */
398 		if (nvlist_lookup_int32(cpu, STRAND_CPU_ID, &cpuid) != 0) {
399 			whinge(mod, &nerr, "create_core: lookup cpuid "
400 			    "failed\n");
401 		} else {
402 			if ((fmri = cpu_fmri_create(mod, cpuid, serial, 0))
403 			    != NULL) {
404 				(void) topo_node_asru_set(core, fmri, 0, &err);
405 				nvlist_free(fmri);
406 			} else {
407 				whinge(mod, &nerr, "create_core: "
408 				    "cpu_fmri_create() failed\n");
409 			}
410 		}
411 	}
412 
413 	if (FM_AWARE_SMBIOS(mod)) {
414 		(void) topo_node_label_set(core, NULL, &perr);
415 
416 		if (topo_node_resource(core, &fmri, &perr) != 0) {
417 			whinge(mod, &nerr, "create_core: "
418 			    "topo_node_resource failed\n");
419 			perr = 0;
420 		}
421 
422 		perr += nvlist_lookup_string(fmri,
423 		    FM_FMRI_HC_PART, &part);
424 		perr += nvlist_lookup_string(fmri,
425 		    FM_FMRI_HC_REVISION, &rev);
426 
427 		if (perr != 0) {
428 			whinge(mod, NULL,
429 			    "create_core: nvlist_lookup_string failed\n");
430 			perr = 0;
431 		}
432 
433 		perr += topo_prop_set_string(core, PGNAME(CORE),
434 		    FM_FMRI_HC_SERIAL_ID, TOPO_PROP_IMMUTABLE, serial, &perr);
435 		perr += topo_prop_set_string(core, PGNAME(CORE),
436 		    FM_FMRI_HC_PART, TOPO_PROP_IMMUTABLE, part, &perr);
437 		perr += topo_prop_set_string(core, PGNAME(CORE),
438 		    FM_FMRI_HC_REVISION, TOPO_PROP_IMMUTABLE, rev, &perr);
439 
440 		if (perr != 0)
441 			whinge(mod, NULL, "create_core: topo_prop_set_string"
442 			    "failed\n");
443 
444 		nvlist_free(fmri);
445 		topo_mod_strfree(mod, serial);
446 	}
447 
448 	err = create_strand(mod, core, cpu, auth, chip_smbiosid);
449 
450 	return (err == 0 && nerr == 0 ? 0 : -1);
451 }
452 
453 static int
454 create_chip(topo_mod_t *mod, tnode_t *pnode, topo_instance_t min,
455     topo_instance_t max, nvlist_t *cpu, nvlist_t *auth,
456     int mc_offchip)
457 {
458 	tnode_t *chip;
459 	int32_t chipid;
460 	nvlist_t *fmri = NULL;
461 	int err, perr, nerr = 0;
462 	int32_t fms[3];
463 	const char *vendor;
464 	boolean_t create_mc = B_FALSE;
465 	uint16_t smbios_id;
466 
467 	/*
468 	 * /dev/fm will export the chipid based on SMBIOS' ordering
469 	 * of Type-4 structures, if SMBIOS meets FMA needs
470 	 */
471 	if ((err = nvlist_lookup_int32(cpu, FM_PHYSCPU_INFO_CHIP_ID, &chipid))
472 	    != 0) {
473 		whinge(mod, &nerr, "create_chip: lookup chip_id failed: %s\n",
474 		    strerror(err));
475 		return (-1);
476 	}
477 
478 	if (chipid < min || chipid > max)
479 		return (-1);
480 
481 	if (FM_AWARE_SMBIOS(mod)) {
482 		if ((err = nvlist_lookup_uint16(cpu,
483 		    FM_PHYSCPU_INFO_SMBIOS_ID, &smbios_id)) != 0) {
484 			whinge(mod, NULL,
485 			    "create_chip: lookup smbios_id failed"
486 			    ": enumerating x86pi & chip topology, but"
487 			    " no Chip properties from SMBIOS"
488 			    " - err msg : %s\n", strerror(err));
489 			/*
490 			 * Lets reset the module specific
491 			 * data to NULL, overriding any
492 			 * SMBIOS capability encoded earlier.
493 			 * This will fail all subsequent
494 			 * FM_AWARE_SMBIOS checks.
495 			 */
496 			topo_mod_setspecific(mod, NULL);
497 		}
498 	}
499 
500 	if ((chip = topo_node_lookup(pnode, CHIP_NODE_NAME, chipid)) == NULL) {
501 		if ((chip = create_node(mod, pnode, auth, CHIP_NODE_NAME,
502 		    chipid, smbios_id)) == NULL)
503 			return (-1);
504 		/*
505 		 * Do not register XML map methods if SMBIOS can provide
506 		 * serial, part, revision & label
507 		 */
508 		if (!FM_AWARE_SMBIOS(mod)) {
509 			if (topo_method_register(mod, chip, chip_methods) < 0)
510 				whinge(mod, &nerr, "create_chip: "
511 				    "topo_method_register failed\n");
512 		}
513 
514 		(void) topo_pgroup_create(chip, &chip_pgroup, &err);
515 		nerr -= add_nvlist_strprop(mod, chip, cpu, PGNAME(CHIP),
516 		    CHIP_VENDOR_ID, &vendor);
517 		nerr -= add_nvlist_longprops(mod, chip, cpu, PGNAME(CHIP),
518 		    fms, CHIP_FAMILY, CHIP_MODEL, CHIP_STEPPING, NULL);
519 
520 		if (FM_AWARE_SMBIOS(mod)) {
521 			int fru = 0;
522 			char *serial = NULL;
523 			char *part = NULL;
524 			char *rev = NULL;
525 			char *label;
526 
527 			fru = chip_fru_smbios_get(mod, smbios_id);
528 			/*
529 			 * Chip is not a FRU, set the FRU fmri of parent node
530 			 */
531 			if (topo_node_resource(chip, &fmri, &perr) != 0)
532 				whinge(mod, &nerr, "create_chip: "
533 				    "topo_node_resource failed\n");
534 			if (!fru) {
535 				(void) topo_node_fru_set(chip, NULL, 0, &perr);
536 				label = NULL;
537 			} else {
538 				label = (char *)chip_label_smbios_get(mod,
539 				    pnode, smbios_id, NULL);
540 
541 				if (topo_node_fru_set(chip, fmri, 0, &perr)
542 				    != 0) {
543 					whinge(mod, NULL, "create_chip: "
544 					    "topo_node_fru_set failed\n");
545 					perr = 0;
546 				}
547 			}
548 
549 			perr += nvlist_lookup_string(fmri,
550 			    FM_FMRI_HC_SERIAL_ID, &serial);
551 			perr += nvlist_lookup_string(fmri,
552 			    FM_FMRI_HC_PART, &part);
553 			perr += nvlist_lookup_string(fmri,
554 			    FM_FMRI_HC_REVISION, &rev);
555 
556 			if (perr != 0) {
557 				whinge(mod, NULL,
558 				    "create_chip: nvlist_lookup_string"
559 				    "failed\n");
560 				perr = 0;
561 			}
562 
563 			perr += topo_prop_set_string(chip, PGNAME(CHIP),
564 			    FM_FMRI_HC_SERIAL_ID, TOPO_PROP_IMMUTABLE,
565 			    serial, &perr);
566 			perr += topo_prop_set_string(chip, PGNAME(CHIP),
567 			    FM_FMRI_HC_PART, TOPO_PROP_IMMUTABLE,
568 			    part, &perr);
569 			perr += topo_prop_set_string(chip, PGNAME(CHIP),
570 			    FM_FMRI_HC_REVISION, TOPO_PROP_IMMUTABLE,
571 			    rev, &perr);
572 
573 			if (perr != 0)
574 				whinge(mod, NULL,
575 				    "create_chip: topo_prop_set_string"
576 				    "failed\n");
577 
578 			nvlist_free(fmri);
579 
580 			if (topo_node_label_set(chip, label, &perr)
581 			    == -1) {
582 				whinge(mod, NULL, "create_chip: "
583 				    "topo_node_label_set failed\n");
584 			}
585 			topo_mod_strfree(mod, label);
586 
587 		} else {
588 			if (topo_node_resource(chip, &fmri, &err) == -1) {
589 				whinge(mod, &nerr, "create_chip: "
590 				    "topo_node_resource failed\n");
591 			} else {
592 				(void) topo_node_fru_set(chip, fmri, 0, &perr);
593 				nvlist_free(fmri);
594 			}
595 		}
596 
597 		if (topo_method_register(mod, chip, strands_retire_methods) < 0)
598 			whinge(mod, &nerr, "create_chip: "
599 			    "topo_method_register failed\n");
600 
601 		if (topo_node_range_create(mod, chip, CORE_NODE_NAME,
602 		    0, 255) != 0)
603 			return (-1);
604 
605 		create_mc = B_TRUE;
606 	}
607 
608 	if (FM_AWARE_SMBIOS(mod)) {
609 		int status = 0;
610 		/*
611 		 * STATUS
612 		 * CPU Socket Populated
613 		 * CPU Socket Unpopulated
614 		 * Populated : Enabled
615 		 * Populated : Disabled by BIOS (Setup)
616 		 * Populated : Disabled by BIOS (Error)
617 		 * Populated : Idle
618 		 *
619 		 * Enumerate core & strand only for Populated : Enabled
620 		 * Enumerate Off-Chip Memory Controller only for
621 		 * Populated : Enabled
622 		 */
623 
624 		status = chip_status_smbios_get(mod, (id_t)smbios_id);
625 		if (!status) {
626 			whinge(mod, NULL, "create_chip: "
627 			    "CPU Socket is not populated or is disabled\n");
628 			return (0);
629 		}
630 	}
631 
632 	err = create_core(mod, chip, cpu, auth, smbios_id);
633 
634 	/*
635 	 * Create memory-controller node under a chip for architectures
636 	 * that may have on-chip memory-controller(s).
637 	 * If SMBIOS meets FMA needs, when Multi-Chip-Module is
638 	 * addressed, mc instances should be derived from SMBIOS
639 	 */
640 	if (create_mc) {
641 		if (strcmp(vendor, "AuthenticAMD") == 0)
642 			amd_mc_create(mod, smbios_id, chip, MCT_NODE_NAME, auth,
643 			    fms[0], fms[1], fms[2], &nerr);
644 		else if (!mc_offchip) {
645 			onchip_mc_create(mod, smbios_id, chip,
646 			    MCT_NODE_NAME, auth);
647 		}
648 	}
649 
650 	return (err == 0 && nerr == 0 ? 0 : -1);
651 }
652 
653 /*ARGSUSED*/
654 static int
655 create_chips(topo_mod_t *mod, tnode_t *pnode, const char *name,
656     topo_instance_t min, topo_instance_t max, void *arg, nvlist_t *auth,
657     int mc_offchip)
658 {
659 	fmd_agent_hdl_t *hdl;
660 	nvlist_t **cpus;
661 	int nerr = 0;
662 	uint_t i, ncpu;
663 
664 	if (strcmp(name, CHIP_NODE_NAME) != 0)
665 		return (0);
666 
667 	if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) == NULL)
668 		return (-1);
669 	if (fmd_agent_physcpu_info(hdl, &cpus, &ncpu) != 0) {
670 		whinge(mod, NULL, "create_chip: fmd_agent_physcpu_info "
671 		    "failed: %s\n", fmd_agent_errmsg(hdl));
672 		fmd_agent_close(hdl);
673 		return (-1);
674 	}
675 	fmd_agent_close(hdl);
676 
677 	for (i = 0; i < ncpu; i++) {
678 		nerr -= create_chip(mod, pnode, min, max, cpus[i], auth,
679 		    mc_offchip);
680 		nvlist_free(cpus[i]);
681 	}
682 	umem_free(cpus, sizeof (nvlist_t *) * ncpu);
683 
684 	if (nerr == 0) {
685 		return (0);
686 	} else {
687 		(void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
688 		return (-1);
689 	}
690 }
691 
692 /*ARGSUSED*/
693 static int
694 chip_enum(topo_mod_t *mod, tnode_t *pnode, const char *name,
695     topo_instance_t min, topo_instance_t max, void *arg, void *smbios_enabled)
696 {
697 	int rv = 0;
698 	nvlist_t *auth = NULL;
699 	int offchip_mc;
700 	char buf[BUFSIZ];
701 	const char *dom0 = "control_d";
702 
703 	/*
704 	 * Create nothing if we're running in domU.
705 	 */
706 	if (sysinfo(SI_PLATFORM, buf, sizeof (buf)) == -1)
707 		return (-1);
708 
709 	if (strncmp(buf, "i86pc", sizeof (buf)) != 0 &&
710 	    strncmp(buf, "i86xpv", sizeof (buf)) != 0)
711 		return (0);
712 
713 	if (strncmp(buf, "i86xpv", sizeof (buf)) == 0) {
714 		int fd = open("/dev/xen/domcaps", O_RDONLY);
715 
716 		if (fd != -1) {
717 			if (read(fd, buf, sizeof (buf)) <= 0 ||
718 			    strncmp(buf, dom0, strlen(dom0)) != 0) {
719 				(void) close(fd);
720 				return (0);
721 			}
722 			(void) close(fd);
723 		}
724 	}
725 
726 	/*
727 	 * Set Chip Enumerator Module's private data with the value passed by
728 	 * x86pi Enumerator, defining SMBIOS capabilities
729 	 */
730 	topo_mod_setspecific(mod, smbios_enabled);
731 
732 	if (FM_AWARE_SMBIOS(mod))
733 		if (init_chip_smbios(mod) != 0) {
734 			whinge(mod, NULL,
735 			    "init_chip_smbios() failed, "
736 			    " enumerating x86pi & chip topology, but no"
737 			    " CPU & Memory properties will be"
738 			    " derived from SMBIOS\n");
739 			/*
740 			 * Lets reset the module specific
741 			 * data to NULL, overriding any
742 			 * SMBIOS capability encoded earlier.
743 			 * This will fail all subsequent
744 			 * FM_AWARE_SMBIOS checks.
745 			 */
746 			topo_mod_setspecific(mod, NULL);
747 		}
748 
749 	auth = topo_mod_auth(mod, pnode);
750 
751 	offchip_mc = mc_offchip_open();
752 	if (strcmp(name, CHIP_NODE_NAME) == 0)
753 		rv = create_chips(mod, pnode, name, min, max, NULL, auth,
754 		    offchip_mc);
755 
756 	if (offchip_mc)
757 		(void) mc_offchip_create(mod, pnode, "memory-controller", auth);
758 
759 	nvlist_free(auth);
760 
761 	return (rv);
762 }
763