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_PROCNODE_ID, STRAND_CORE_ID, STRAND_CPU_ID,
282 	    NULL);
283 
284 	if (FM_AWARE_SMBIOS(mod)) {
285 		(void) topo_node_label_set(strand, NULL, &perr);
286 
287 		if (topo_node_resource(strand, &fmri, &perr) != 0) {
288 			whinge(mod, &nerr, "create_strand: "
289 			    "topo_node_resource failed\n");
290 			perr = 0;
291 		}
292 
293 		perr += nvlist_lookup_string(fmri,
294 		    FM_FMRI_HC_PART, &part);
295 		perr += nvlist_lookup_string(fmri,
296 		    FM_FMRI_HC_REVISION, &rev);
297 
298 		if (perr != 0) {
299 			whinge(mod, NULL,
300 			    "create_strand: nvlist_lookup_string failed\n");
301 			perr = 0;
302 		}
303 
304 		perr += topo_prop_set_string(strand, PGNAME(STRAND),
305 		    FM_FMRI_HC_SERIAL_ID, TOPO_PROP_IMMUTABLE, serial, &perr);
306 		perr += topo_prop_set_string(strand, PGNAME(STRAND),
307 		    FM_FMRI_HC_PART, TOPO_PROP_IMMUTABLE, part, &perr);
308 		perr += topo_prop_set_string(strand, PGNAME(STRAND),
309 		    FM_FMRI_HC_REVISION, TOPO_PROP_IMMUTABLE, rev, &perr);
310 
311 		if (perr != 0)
312 			whinge(mod, NULL, "create_strand: topo_prop_set_string"
313 			    "failed\n");
314 
315 		nvlist_free(fmri);
316 		topo_mod_strfree(mod, serial);
317 	}
318 
319 	return (err == 0 && nerr == 0 ? 0 : -1);
320 }
321 
322 static int
323 create_core(topo_mod_t *mod, tnode_t *pnode, nvlist_t *cpu,
324     nvlist_t *auth, uint16_t chip_smbiosid)
325 {
326 	tnode_t *core;
327 	int32_t coreid, cpuid;
328 	int err, perr, nerr = 0;
329 	nvlist_t *fmri;
330 	char *serial = NULL;
331 	char *part = NULL;
332 	char *rev = NULL;
333 
334 	if ((err = nvlist_lookup_int32(cpu, FM_PHYSCPU_INFO_CORE_ID, &coreid))
335 	    != 0) {
336 		whinge(mod, NULL, "create_core: lookup core_id failed: %s\n",
337 		    strerror(err));
338 		return (-1);
339 	}
340 	if ((core = topo_node_lookup(pnode, CORE_NODE_NAME, coreid)) == NULL) {
341 		if ((core = create_node(mod, pnode, auth, CORE_NODE_NAME,
342 		    coreid, chip_smbiosid)) == NULL)
343 			return (-1);
344 
345 		/*
346 		 * Inherit FRU from the chip node, for native, we use hc
347 		 * scheme ASRU for the core node.
348 		 */
349 		(void) topo_node_fru_set(core, NULL, 0, &perr);
350 		/*
351 		 * From the inherited FRU, extract the Serial
352 		 * number if SMBIOS donates and set it in the ASRU
353 		 */
354 		if (FM_AWARE_SMBIOS(mod)) {
355 			char *val = NULL;
356 
357 			if (topo_node_resource(core, &fmri, &err) != 0)
358 				whinge(mod, NULL,
359 				    "create_core: topo_prop_get_fmri failed\n");
360 			if (nvlist_lookup_string(fmri, FM_FMRI_HC_SERIAL_ID,
361 			    &val) != 0)
362 				whinge(mod, NULL, "create_core:"
363 				    "nvlist_lookup_string failed\n");
364 			else
365 				serial = topo_mod_strdup(mod, val);
366 			nvlist_free(fmri);
367 		}
368 		if (is_xpv()) {
369 			if (topo_node_resource(core, &fmri, &err) == -1) {
370 				whinge(mod, &nerr, "create_core: "
371 				    "topo_node_resource failed\n");
372 			} else {
373 				if (FM_AWARE_SMBIOS(mod))
374 					(void) nvlist_add_string(fmri,
375 					    FM_FMRI_HC_SERIAL_ID, serial);
376 				(void) topo_node_asru_set(core, fmri, 0, &err);
377 				nvlist_free(fmri);
378 			}
379 		}
380 		if (topo_method_register(mod, core, strands_retire_methods) < 0)
381 			whinge(mod, &nerr, "create_core: "
382 			    "topo_method_register failed\n");
383 
384 		(void) topo_pgroup_create(core, &core_pgroup, &err);
385 		nerr -= add_nvlist_longprops(mod, core, cpu, PGNAME(CORE), NULL,
386 		    CORE_CHIP_ID, CORE_PROCNODE_ID, NULL);
387 
388 		if (topo_node_range_create(mod, core, STRAND_NODE_NAME,
389 		    0, 255) != 0)
390 			return (-1);
391 	}
392 
393 	if (!is_xpv()) {
394 		/*
395 		 * In native mode, we're in favor of cpu scheme ASRU for
396 		 * printing reason.  More work needs to be done to support
397 		 * multi-strand cpu: the ASRU will be a list of cpuid then.
398 		 */
399 		if (nvlist_lookup_int32(cpu, STRAND_CPU_ID, &cpuid) != 0) {
400 			whinge(mod, &nerr, "create_core: lookup cpuid "
401 			    "failed\n");
402 		} else {
403 			if ((fmri = cpu_fmri_create(mod, cpuid, serial, 0))
404 			    != NULL) {
405 				(void) topo_node_asru_set(core, fmri, 0, &err);
406 				nvlist_free(fmri);
407 			} else {
408 				whinge(mod, &nerr, "create_core: "
409 				    "cpu_fmri_create() failed\n");
410 			}
411 		}
412 	}
413 
414 	if (FM_AWARE_SMBIOS(mod)) {
415 		(void) topo_node_label_set(core, NULL, &perr);
416 
417 		if (topo_node_resource(core, &fmri, &perr) != 0) {
418 			whinge(mod, &nerr, "create_core: "
419 			    "topo_node_resource failed\n");
420 			perr = 0;
421 		}
422 
423 		perr += nvlist_lookup_string(fmri,
424 		    FM_FMRI_HC_PART, &part);
425 		perr += nvlist_lookup_string(fmri,
426 		    FM_FMRI_HC_REVISION, &rev);
427 
428 		if (perr != 0) {
429 			whinge(mod, NULL,
430 			    "create_core: nvlist_lookup_string failed\n");
431 			perr = 0;
432 		}
433 
434 		perr += topo_prop_set_string(core, PGNAME(CORE),
435 		    FM_FMRI_HC_SERIAL_ID, TOPO_PROP_IMMUTABLE, serial, &perr);
436 		perr += topo_prop_set_string(core, PGNAME(CORE),
437 		    FM_FMRI_HC_PART, TOPO_PROP_IMMUTABLE, part, &perr);
438 		perr += topo_prop_set_string(core, PGNAME(CORE),
439 		    FM_FMRI_HC_REVISION, TOPO_PROP_IMMUTABLE, rev, &perr);
440 
441 		if (perr != 0)
442 			whinge(mod, NULL, "create_core: topo_prop_set_string"
443 			    "failed\n");
444 
445 		nvlist_free(fmri);
446 		topo_mod_strfree(mod, serial);
447 	}
448 
449 	err = create_strand(mod, core, cpu, auth, chip_smbiosid);
450 
451 	return (err == 0 && nerr == 0 ? 0 : -1);
452 }
453 
454 static int
455 create_chip(topo_mod_t *mod, tnode_t *pnode, topo_instance_t min,
456     topo_instance_t max, nvlist_t *cpu, nvlist_t *auth,
457     int mc_offchip)
458 {
459 	tnode_t *chip;
460 	nvlist_t *fmri = NULL;
461 	int err, perr, nerr = 0;
462 	int32_t chipid, procnodeid, procnodes_per_pkg;
463 	const char *vendor;
464 	int32_t family, model;
465 	boolean_t create_mc = B_FALSE;
466 	uint16_t smbios_id;
467 
468 	/*
469 	 * /dev/fm will export the chipid based on SMBIOS' ordering
470 	 * of Type-4 structures, if SMBIOS meets FMA needs
471 	 */
472 	err = nvlist_lookup_pairs(cpu, 0,
473 	    FM_PHYSCPU_INFO_CHIP_ID, DATA_TYPE_INT32, &chipid,
474 	    FM_PHYSCPU_INFO_NPROCNODES, DATA_TYPE_INT32, &procnodes_per_pkg,
475 	    FM_PHYSCPU_INFO_PROCNODE_ID, DATA_TYPE_INT32, &procnodeid,
476 	    FM_PHYSCPU_INFO_VENDOR_ID, DATA_TYPE_STRING, &vendor,
477 	    FM_PHYSCPU_INFO_FAMILY, DATA_TYPE_INT32, &family,
478 	    FM_PHYSCPU_INFO_MODEL, DATA_TYPE_INT32, &model,
479 	    NULL);
480 
481 	if (err) {
482 		whinge(mod, NULL, "create_chip: lookup failed: %s\n",
483 		    strerror(err));
484 		return (-1);
485 	}
486 
487 	if (chipid < min || chipid > max)
488 		return (-1);
489 
490 	if (FM_AWARE_SMBIOS(mod)) {
491 		if ((err = nvlist_lookup_uint16(cpu,
492 		    FM_PHYSCPU_INFO_SMBIOS_ID, &smbios_id)) != 0) {
493 			whinge(mod, NULL,
494 			    "create_chip: lookup smbios_id failed"
495 			    ": enumerating x86pi & chip topology, but"
496 			    " no Chip properties from SMBIOS"
497 			    " - err msg : %s\n", strerror(err));
498 			/*
499 			 * Lets reset the module specific
500 			 * data to NULL, overriding any
501 			 * SMBIOS capability encoded earlier.
502 			 * This will fail all subsequent
503 			 * FM_AWARE_SMBIOS checks.
504 			 */
505 			topo_mod_setspecific(mod, NULL);
506 		}
507 	}
508 
509 	if ((chip = topo_node_lookup(pnode, CHIP_NODE_NAME, chipid)) == NULL) {
510 		if ((chip = create_node(mod, pnode, auth, CHIP_NODE_NAME,
511 		    chipid, smbios_id)) == NULL)
512 			return (-1);
513 		/*
514 		 * Do not register XML map methods if SMBIOS can provide
515 		 * serial, part, revision & label
516 		 */
517 		if (!FM_AWARE_SMBIOS(mod)) {
518 			if (topo_method_register(mod, chip, chip_methods) < 0)
519 				whinge(mod, &nerr, "create_chip: "
520 				    "topo_method_register failed\n");
521 		}
522 
523 		(void) topo_pgroup_create(chip, &chip_pgroup, &err);
524 		nerr -= add_nvlist_strprop(mod, chip, cpu, PGNAME(CHIP),
525 		    CHIP_VENDOR_ID, NULL);
526 		nerr -= add_nvlist_longprops(mod, chip, cpu, PGNAME(CHIP),
527 		    NULL, CHIP_FAMILY, CHIP_MODEL, CHIP_STEPPING, NULL);
528 
529 		if (FM_AWARE_SMBIOS(mod)) {
530 			int fru = 0;
531 			char *serial = NULL;
532 			char *part = NULL;
533 			char *rev = NULL;
534 			char *label;
535 
536 			fru = chip_fru_smbios_get(mod, smbios_id);
537 			/*
538 			 * Chip is not a FRU, set the FRU fmri of parent node
539 			 */
540 			if (topo_node_resource(chip, &fmri, &perr) != 0)
541 				whinge(mod, &nerr, "create_chip: "
542 				    "topo_node_resource failed\n");
543 			if (!fru) {
544 				(void) topo_node_fru_set(chip, NULL, 0, &perr);
545 				label = NULL;
546 			} else {
547 				label = (char *)chip_label_smbios_get(mod,
548 				    pnode, smbios_id, NULL);
549 
550 				if (topo_node_fru_set(chip, fmri, 0, &perr)
551 				    != 0) {
552 					whinge(mod, NULL, "create_chip: "
553 					    "topo_node_fru_set failed\n");
554 					perr = 0;
555 				}
556 			}
557 
558 			perr += nvlist_lookup_string(fmri,
559 			    FM_FMRI_HC_SERIAL_ID, &serial);
560 			perr += nvlist_lookup_string(fmri,
561 			    FM_FMRI_HC_PART, &part);
562 			perr += nvlist_lookup_string(fmri,
563 			    FM_FMRI_HC_REVISION, &rev);
564 
565 			if (perr != 0) {
566 				whinge(mod, NULL,
567 				    "create_chip: nvlist_lookup_string"
568 				    "failed\n");
569 				perr = 0;
570 			}
571 
572 			perr += topo_prop_set_string(chip, PGNAME(CHIP),
573 			    FM_FMRI_HC_SERIAL_ID, TOPO_PROP_IMMUTABLE,
574 			    serial, &perr);
575 			perr += topo_prop_set_string(chip, PGNAME(CHIP),
576 			    FM_FMRI_HC_PART, TOPO_PROP_IMMUTABLE,
577 			    part, &perr);
578 			perr += topo_prop_set_string(chip, PGNAME(CHIP),
579 			    FM_FMRI_HC_REVISION, TOPO_PROP_IMMUTABLE,
580 			    rev, &perr);
581 
582 			if (perr != 0)
583 				whinge(mod, NULL,
584 				    "create_chip: topo_prop_set_string"
585 				    "failed\n");
586 
587 			nvlist_free(fmri);
588 
589 			if (topo_node_label_set(chip, label, &perr)
590 			    == -1) {
591 				whinge(mod, NULL, "create_chip: "
592 				    "topo_node_label_set failed\n");
593 			}
594 			topo_mod_strfree(mod, label);
595 
596 		} else {
597 			if (topo_node_resource(chip, &fmri, &err) == -1) {
598 				whinge(mod, &nerr, "create_chip: "
599 				    "topo_node_resource failed\n");
600 			} else {
601 				(void) topo_node_fru_set(chip, fmri, 0, &perr);
602 				nvlist_free(fmri);
603 			}
604 		}
605 
606 		if (topo_method_register(mod, chip, strands_retire_methods) < 0)
607 			whinge(mod, &nerr, "create_chip: "
608 			    "topo_method_register failed\n");
609 
610 		if (topo_node_range_create(mod, chip, CORE_NODE_NAME, 0, 255))
611 			return (-1);
612 
613 		if (strcmp(vendor, "AuthenticAMD") == 0) {
614 			if (topo_node_range_create(mod, chip, MCT_NODE_NAME,
615 			    0, 255))
616 				return (-1);
617 		}
618 
619 		create_mc = B_TRUE;
620 	}
621 
622 	if (FM_AWARE_SMBIOS(mod)) {
623 		int status = 0;
624 		/*
625 		 * STATUS
626 		 * CPU Socket Populated
627 		 * CPU Socket Unpopulated
628 		 * Populated : Enabled
629 		 * Populated : Disabled by BIOS (Setup)
630 		 * Populated : Disabled by BIOS (Error)
631 		 * Populated : Idle
632 		 *
633 		 * Enumerate core & strand only for Populated : Enabled
634 		 * Enumerate Off-Chip Memory Controller only for
635 		 * Populated : Enabled
636 		 */
637 
638 		status = chip_status_smbios_get(mod, (id_t)smbios_id);
639 		if (!status) {
640 			whinge(mod, NULL, "create_chip: "
641 			    "CPU Socket is not populated or is disabled\n");
642 			return (0);
643 		}
644 	}
645 
646 	err = create_core(mod, chip, cpu, auth, smbios_id);
647 
648 	/*
649 	 * Create memory-controller node under a chip for architectures
650 	 * that may have on-chip memory-controller(s).
651 	 * If SMBIOS meets FMA needs, when Multi-Chip-Module is
652 	 * addressed, mc instances should be derived from SMBIOS
653 	 */
654 	if (strcmp(vendor, "AuthenticAMD") == 0) {
655 		amd_mc_create(mod, smbios_id, chip, MCT_NODE_NAME, auth,
656 		    procnodeid, procnodes_per_pkg, family, model, &nerr);
657 	} else if (create_mc && !mc_offchip)
658 		onchip_mc_create(mod, smbios_id, chip, MCT_NODE_NAME, auth);
659 
660 	return (err == 0 && nerr == 0 ? 0 : -1);
661 }
662 
663 /*ARGSUSED*/
664 static int
665 create_chips(topo_mod_t *mod, tnode_t *pnode, const char *name,
666     topo_instance_t min, topo_instance_t max, void *arg, nvlist_t *auth,
667     int mc_offchip)
668 {
669 	fmd_agent_hdl_t *hdl;
670 	nvlist_t **cpus;
671 	int nerr = 0;
672 	uint_t i, ncpu;
673 
674 	if (strcmp(name, CHIP_NODE_NAME) != 0)
675 		return (0);
676 
677 	if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) == NULL)
678 		return (-1);
679 	if (fmd_agent_physcpu_info(hdl, &cpus, &ncpu) != 0) {
680 		whinge(mod, NULL, "create_chip: fmd_agent_physcpu_info "
681 		    "failed: %s\n", fmd_agent_errmsg(hdl));
682 		fmd_agent_close(hdl);
683 		return (-1);
684 	}
685 	fmd_agent_close(hdl);
686 
687 	for (i = 0; i < ncpu; i++) {
688 		nerr -= create_chip(mod, pnode, min, max, cpus[i], auth,
689 		    mc_offchip);
690 		nvlist_free(cpus[i]);
691 	}
692 	umem_free(cpus, sizeof (nvlist_t *) * ncpu);
693 
694 	if (nerr == 0) {
695 		return (0);
696 	} else {
697 		(void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
698 		return (-1);
699 	}
700 }
701 
702 /*ARGSUSED*/
703 static int
704 chip_enum(topo_mod_t *mod, tnode_t *pnode, const char *name,
705     topo_instance_t min, topo_instance_t max, void *arg, void *smbios_enabled)
706 {
707 	int rv = 0;
708 	nvlist_t *auth = NULL;
709 	int offchip_mc;
710 	char buf[BUFSIZ];
711 	const char *dom0 = "control_d";
712 
713 	/*
714 	 * Create nothing if we're running in domU.
715 	 */
716 	if (sysinfo(SI_PLATFORM, buf, sizeof (buf)) == -1)
717 		return (-1);
718 
719 	if (strncmp(buf, "i86pc", sizeof (buf)) != 0 &&
720 	    strncmp(buf, "i86xpv", sizeof (buf)) != 0)
721 		return (0);
722 
723 	if (strncmp(buf, "i86xpv", sizeof (buf)) == 0) {
724 		int fd = open("/dev/xen/domcaps", O_RDONLY);
725 
726 		if (fd != -1) {
727 			if (read(fd, buf, sizeof (buf)) <= 0 ||
728 			    strncmp(buf, dom0, strlen(dom0)) != 0) {
729 				(void) close(fd);
730 				return (0);
731 			}
732 			(void) close(fd);
733 		}
734 	}
735 
736 	/*
737 	 * Set Chip Enumerator Module's private data with the value passed by
738 	 * x86pi Enumerator, defining SMBIOS capabilities
739 	 */
740 	topo_mod_setspecific(mod, smbios_enabled);
741 
742 	if (FM_AWARE_SMBIOS(mod))
743 		if (init_chip_smbios(mod) != 0) {
744 			whinge(mod, NULL,
745 			    "init_chip_smbios() failed, "
746 			    " enumerating x86pi & chip topology, but no"
747 			    " CPU & Memory properties will be"
748 			    " derived from SMBIOS\n");
749 			/*
750 			 * Lets reset the module specific
751 			 * data to NULL, overriding any
752 			 * SMBIOS capability encoded earlier.
753 			 * This will fail all subsequent
754 			 * FM_AWARE_SMBIOS checks.
755 			 */
756 			topo_mod_setspecific(mod, NULL);
757 		}
758 
759 	auth = topo_mod_auth(mod, pnode);
760 
761 	offchip_mc = mc_offchip_open();
762 	if (strcmp(name, CHIP_NODE_NAME) == 0)
763 		rv = create_chips(mod, pnode, name, min, max, NULL, auth,
764 		    offchip_mc);
765 
766 	if (offchip_mc)
767 		(void) mc_offchip_create(mod, pnode, "memory-controller", auth);
768 
769 	nvlist_free(auth);
770 
771 	return (rv);
772 }
773