16d65bee7SRob Johnston /*
26d65bee7SRob Johnston  * This file and its contents are supplied under the terms of the
36d65bee7SRob Johnston  * Common Development and Distribution License ("CDDL"), version 1.0.
46d65bee7SRob Johnston  * You may only use this file in accordance with the terms of version
56d65bee7SRob Johnston  * 1.0 of the CDDL.
66d65bee7SRob Johnston  *
76d65bee7SRob Johnston  * A full copy of the text of the CDDL should have accompanied this
86d65bee7SRob Johnston  * source.  A copy of the CDDL is also available via the Internet at
96d65bee7SRob Johnston  * http://www.illumos.org/license/CDDL.
106d65bee7SRob Johnston  */
116d65bee7SRob Johnston 
126d65bee7SRob Johnston /*
138abca89fSRob Johnston  * Copyright (c) 2019, Joyent, Inc.
146d65bee7SRob Johnston  */
156d65bee7SRob Johnston 
166d65bee7SRob Johnston #include <assert.h>
176d65bee7SRob Johnston #include <fcntl.h>
186d65bee7SRob Johnston #include <fm/libtopo.h>
196d65bee7SRob Johnston #include <fm/topo_mod.h>
208abca89fSRob Johnston #include <fm/topo_method.h>
216d65bee7SRob Johnston #ifdef	__x86
226d65bee7SRob Johnston #include <sys/mc.h>
236d65bee7SRob Johnston #endif
246d65bee7SRob Johnston #include <sys/fm/protocol.h>
256d65bee7SRob Johnston #include <string.h>
266d65bee7SRob Johnston #include <unistd.h>
276d65bee7SRob Johnston 
286d65bee7SRob Johnston typedef struct smb_enum_data {
296d65bee7SRob Johnston 	topo_mod_t	*sme_mod;
306d65bee7SRob Johnston 	tnode_t		*sme_pnode;
316d65bee7SRob Johnston 	tnode_t		*sme_slotnode;
326d65bee7SRob Johnston 	topo_instance_t	sme_slot_inst;
336d65bee7SRob Johnston 	topo_instance_t	sme_slot_maxinst;
346d65bee7SRob Johnston 	smbios_info_t	*sme_smb_info;
356d65bee7SRob Johnston 	char		*sme_slot_form;
366d65bee7SRob Johnston } smb_enum_data_t;
376d65bee7SRob Johnston 
388abca89fSRob Johnston static const topo_method_t slot_methods[] = {
398abca89fSRob Johnston 	{ TOPO_METH_OCCUPIED, TOPO_METH_OCCUPIED_DESC,
408abca89fSRob Johnston 	    TOPO_METH_OCCUPIED_VERSION, TOPO_STABILITY_INTERNAL,
418abca89fSRob Johnston 	    topo_mod_hc_occupied },
428abca89fSRob Johnston 	{ NULL }
438abca89fSRob Johnston };
448abca89fSRob Johnston 
456d65bee7SRob Johnston /*
466d65bee7SRob Johnston  * This function serves two purposes.  It filters out memory devices that
476d65bee7SRob Johnston  * don't have a formfactor that represents a reasonably modern DIMM-like
486d65bee7SRob Johnston  * device (and hence not a device we're interested in enumerating).  It also
496d65bee7SRob Johnston  * converts the numeric SMBIOS type representation to a more generic TOPO dimm
506d65bee7SRob Johnston  * type.
516d65bee7SRob Johnston  *
526d65bee7SRob Johnston  * Caller must free the returned string.
536d65bee7SRob Johnston  */
546d65bee7SRob Johnston static char *
distill_dimm_form(topo_mod_t * mod,smbios_memdevice_t * smb_md)556d65bee7SRob Johnston distill_dimm_form(topo_mod_t *mod, smbios_memdevice_t *smb_md)
566d65bee7SRob Johnston {
576d65bee7SRob Johnston 	switch (smb_md->smbmd_form) {
586d65bee7SRob Johnston 	case (SMB_MDFF_DIMM):
596d65bee7SRob Johnston 		return (topo_mod_strdup(mod, TOPO_DIMM_SLOT_FORM_DIMM));
606d65bee7SRob Johnston 	case (SMB_MDFF_SODIMM):
616d65bee7SRob Johnston 		return (topo_mod_strdup(mod, TOPO_DIMM_SLOT_FORM_SODIMM));
626d65bee7SRob Johnston 	case (SMB_MDFF_FBDIMM):
636d65bee7SRob Johnston 		return (topo_mod_strdup(mod, TOPO_DIMM_SLOT_FORM_FBDIMM));
646d65bee7SRob Johnston 	default:
656d65bee7SRob Johnston 		topo_mod_dprintf(mod, "skipping device with form factor 0x%x",
666d65bee7SRob Johnston 		    smb_md->smbmd_form);
676d65bee7SRob Johnston 		return (NULL);
686d65bee7SRob Johnston 	}
696d65bee7SRob Johnston }
706d65bee7SRob Johnston 
716d65bee7SRob Johnston static char *
smbios2topotype(topo_mod_t * mod,uint8_t type)726d65bee7SRob Johnston smbios2topotype(topo_mod_t *mod, uint8_t type)
736d65bee7SRob Johnston {
746d65bee7SRob Johnston 	switch (type) {
756d65bee7SRob Johnston 	case (SMB_MDT_DDR):
766d65bee7SRob Johnston 		return (topo_mod_strdup(mod, TOPO_DIMM_TYPE_DDR));
776d65bee7SRob Johnston 	case (SMB_MDT_DDR2):
786d65bee7SRob Johnston 	case (SMB_MDT_DDR2FBDIMM):
796d65bee7SRob Johnston 		return (topo_mod_strdup(mod, TOPO_DIMM_TYPE_DDR2));
806d65bee7SRob Johnston 	case (SMB_MDT_DDR3):
816d65bee7SRob Johnston 		return (topo_mod_strdup(mod, TOPO_DIMM_TYPE_DDR3));
826d65bee7SRob Johnston 	case (SMB_MDT_DDR4):
836d65bee7SRob Johnston 		return (topo_mod_strdup(mod, TOPO_DIMM_TYPE_DDR4));
84*7c0da522SRobert Mustacchi 	case (SMB_MDT_DDR5):
85*7c0da522SRobert Mustacchi 		return (topo_mod_strdup(mod, TOPO_DIMM_TYPE_DDR5));
866d65bee7SRob Johnston 	case (SMB_MDT_LPDDR):
876d65bee7SRob Johnston 		return (topo_mod_strdup(mod, TOPO_DIMM_TYPE_LPDDR));
886d65bee7SRob Johnston 	case (SMB_MDT_LPDDR2):
896d65bee7SRob Johnston 		return (topo_mod_strdup(mod, TOPO_DIMM_TYPE_LPDDR2));
906d65bee7SRob Johnston 	case (SMB_MDT_LPDDR3):
916d65bee7SRob Johnston 		return (topo_mod_strdup(mod, TOPO_DIMM_TYPE_LPDDR3));
926d65bee7SRob Johnston 	case (SMB_MDT_LPDDR4):
936d65bee7SRob Johnston 		return (topo_mod_strdup(mod, TOPO_DIMM_TYPE_LPDDR4));
94*7c0da522SRobert Mustacchi 	case (SMB_MDT_LPDDR5):
95*7c0da522SRobert Mustacchi 		return (topo_mod_strdup(mod, TOPO_DIMM_TYPE_LPDDR5));
966d65bee7SRob Johnston 	default:
976d65bee7SRob Johnston 		return (topo_mod_strdup(mod, TOPO_DIMM_TYPE_UNKNOWN));
986d65bee7SRob Johnston 	}
996d65bee7SRob Johnston }
1006d65bee7SRob Johnston 
1016d65bee7SRob Johnston static boolean_t
is_valid_string(const char * str)1026d65bee7SRob Johnston is_valid_string(const char *str)
1036d65bee7SRob Johnston {
1046d65bee7SRob Johnston 	if (strcmp(str, SMB_DEFAULT1) != 0 && strcmp(str, SMB_DEFAULT2) != 0 &&
1058522c52aSRob Johnston 	    strcmp(str, SMB_DEFAULT3) != 0 && strlen(str) > 0)
1066d65bee7SRob Johnston 		return (B_TRUE);
1076d65bee7SRob Johnston 
1086d65bee7SRob Johnston 	return (B_FALSE);
1096d65bee7SRob Johnston }
1106d65bee7SRob Johnston 
1116d65bee7SRob Johnston static tnode_t *
smbios_make_slot(smb_enum_data_t * smed,smbios_memdevice_t * smb_md)1126d65bee7SRob Johnston smbios_make_slot(smb_enum_data_t *smed, smbios_memdevice_t *smb_md)
1136d65bee7SRob Johnston {
1146d65bee7SRob Johnston 	nvlist_t *auth, *fmri;
1156d65bee7SRob Johnston 	tnode_t *slotnode;
1166d65bee7SRob Johnston 	topo_mod_t *mod = smed->sme_mod;
1176d65bee7SRob Johnston 	topo_pgroup_info_t pgi;
1186d65bee7SRob Johnston 	int err;
1196d65bee7SRob Johnston 
1206d65bee7SRob Johnston 	if ((auth = topo_mod_auth(mod, smed->sme_pnode)) == NULL) {
1216d65bee7SRob Johnston 		topo_mod_dprintf(mod, "topo_mod_auth() failed: %s",
1226d65bee7SRob Johnston 		    topo_mod_errmsg(mod));
1236d65bee7SRob Johnston 		/* errno set */
1246d65bee7SRob Johnston 		return (NULL);
1256d65bee7SRob Johnston 	}
1266d65bee7SRob Johnston 
1276d65bee7SRob Johnston 	if ((fmri = topo_mod_hcfmri(mod, smed->sme_pnode, FM_HC_SCHEME_VERSION,
1286d65bee7SRob Johnston 	    SLOT, smed->sme_slot_inst, NULL, auth, NULL, NULL, NULL)) ==
1296d65bee7SRob Johnston 	    NULL) {
1306d65bee7SRob Johnston 		nvlist_free(auth);
1316d65bee7SRob Johnston 		topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s",
1326d65bee7SRob Johnston 		    topo_mod_errmsg(mod));
1336d65bee7SRob Johnston 		/* errno set */
1346d65bee7SRob Johnston 		return (NULL);
1356d65bee7SRob Johnston 	}
1366d65bee7SRob Johnston 	if ((slotnode = topo_node_bind(mod, smed->sme_pnode, SLOT,
1376d65bee7SRob Johnston 	    smed->sme_slot_inst, fmri)) == NULL) {
1388522c52aSRob Johnston 		nvlist_free(auth);
1396d65bee7SRob Johnston 		nvlist_free(fmri);
1406d65bee7SRob Johnston 		topo_mod_dprintf(mod, "topo_node_bind() failed: %s",
1416d65bee7SRob Johnston 		    topo_mod_errmsg(mod));
1426d65bee7SRob Johnston 		/* errno set */
1436d65bee7SRob Johnston 		return (NULL);
1446d65bee7SRob Johnston 	}
1456d65bee7SRob Johnston 	nvlist_free(fmri);
1466d65bee7SRob Johnston 	fmri = NULL;
1476d65bee7SRob Johnston 
1488522c52aSRob Johnston 	/* Create authority and system pgroups */
1498522c52aSRob Johnston 	topo_pgroup_hcset(slotnode, auth);
1508522c52aSRob Johnston 	nvlist_free(auth);
1518522c52aSRob Johnston 
1526d65bee7SRob Johnston 	if (topo_node_label_set(slotnode, (char *)smb_md->smbmd_dloc, &err) !=
1536d65bee7SRob Johnston 	    0) {
1546597d6fcSRobert Mustacchi 		topo_mod_dprintf(mod, "failed to set label on %s=%" PRIu64
1556597d6fcSRobert Mustacchi 		    ": %s", SLOT, smed->sme_slot_inst, topo_strerror(err));
1566d65bee7SRob Johnston 		(void) topo_mod_seterrno(mod, err);
1576d65bee7SRob Johnston 		return (NULL);
1586d65bee7SRob Johnston 	}
1596d65bee7SRob Johnston 	if (topo_node_fru(smed->sme_pnode, &fmri, NULL, &err) != 0 ||
1605cc5d5ceSToomas Soome 	    topo_node_fru_set(slotnode, fmri, 0, &err) != 0) {
1616597d6fcSRobert Mustacchi 		topo_mod_dprintf(mod, "failed to set FRU on %s=%" PRIu64 ": %s",
1626597d6fcSRobert Mustacchi 		    SLOT, smed->sme_slot_inst, topo_strerror(err));
1636d65bee7SRob Johnston 		nvlist_free(fmri);
1646d65bee7SRob Johnston 		(void) topo_mod_seterrno(mod, err);
1656d65bee7SRob Johnston 		return (NULL);
1666d65bee7SRob Johnston 	}
1676d65bee7SRob Johnston 	nvlist_free(fmri);
1686d65bee7SRob Johnston 
1698abca89fSRob Johnston 	if (topo_method_register(mod, slotnode, slot_methods) != 0) {
1708abca89fSRob Johnston 		topo_mod_dprintf(mod, "topo_method_register() failed on "
1716597d6fcSRobert Mustacchi 		    "%s=%" PRIu64 ": %s", SLOT, smed->sme_slot_inst,
1728abca89fSRob Johnston 		    topo_mod_errmsg(mod));
1738abca89fSRob Johnston 		/* errno set */
1748abca89fSRob Johnston 		return (NULL);
1758abca89fSRob Johnston 	}
1768abca89fSRob Johnston 
1776d65bee7SRob Johnston 	pgi.tpi_name = TOPO_PGROUP_SLOT;
1786d65bee7SRob Johnston 	pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
1796d65bee7SRob Johnston 	pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
1806d65bee7SRob Johnston 	pgi.tpi_version = TOPO_VERSION;
1816d65bee7SRob Johnston 	if (topo_pgroup_create(slotnode, &pgi, &err) != 0 ||
1826d65bee7SRob Johnston 	    topo_prop_set_uint32(slotnode, TOPO_PGROUP_SLOT,
1836d65bee7SRob Johnston 	    TOPO_PROP_SLOT_TYPE, TOPO_PROP_IMMUTABLE, TOPO_SLOT_TYPE_DIMM,
1846d65bee7SRob Johnston 	    &err)) {
1856d65bee7SRob Johnston 		topo_mod_dprintf(mod, "failed to create slot properties: %s",
1866d65bee7SRob Johnston 		    topo_strerror(err));
1876d65bee7SRob Johnston 		(void) topo_mod_seterrno(mod, err);
1886d65bee7SRob Johnston 		return (NULL);
1896d65bee7SRob Johnston 	}
1906d65bee7SRob Johnston 
1916d65bee7SRob Johnston 	pgi.tpi_name = TOPO_PGROUP_DIMM_SLOT;
1926d65bee7SRob Johnston 	pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
1936d65bee7SRob Johnston 	pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
1946d65bee7SRob Johnston 	pgi.tpi_version = TOPO_VERSION;
1956d65bee7SRob Johnston 	if (topo_pgroup_create(slotnode, &pgi, &err) != 0 ||
1966d65bee7SRob Johnston 	    topo_prop_set_string(slotnode, TOPO_PGROUP_DIMM_SLOT,
1976d65bee7SRob Johnston 	    TOPO_PROP_DIMM_SLOT_FORM, TOPO_PROP_IMMUTABLE, smed->sme_slot_form,
1986d65bee7SRob Johnston 	    &err)) {
1996d65bee7SRob Johnston 		topo_mod_dprintf(mod, "failed to create slot properties: %s",
2006d65bee7SRob Johnston 		    topo_strerror(err));
2016d65bee7SRob Johnston 		(void) topo_mod_seterrno(mod, err);
2026d65bee7SRob Johnston 		return (NULL);
2036d65bee7SRob Johnston 	}
2046d65bee7SRob Johnston 	return (slotnode);
2056d65bee7SRob Johnston }
2066d65bee7SRob Johnston 
2076d65bee7SRob Johnston static tnode_t *
smbios_make_dimm(smb_enum_data_t * smed,smbios_memdevice_t * smb_md)2086d65bee7SRob Johnston smbios_make_dimm(smb_enum_data_t *smed, smbios_memdevice_t *smb_md)
2096d65bee7SRob Johnston {
2106d65bee7SRob Johnston 	nvlist_t *auth, *fmri;
2116d65bee7SRob Johnston 	smbios_info_t *smb_info = smed->sme_smb_info;
2126d65bee7SRob Johnston 	tnode_t *slotnode = smed->sme_slotnode;
2136d65bee7SRob Johnston 	tnode_t *dimmnode, *ret = NULL;
2146d65bee7SRob Johnston 	topo_mod_t *mod = smed->sme_mod;
2156d65bee7SRob Johnston 	topo_pgroup_info_t pgi;
2166d65bee7SRob Johnston 	const char *part = NULL, *rev = NULL, *serial = NULL;
2176d65bee7SRob Johnston 	char *type, *manuf = NULL, *prod = NULL, *asset = NULL, *loc = NULL;
2186d65bee7SRob Johnston 	int err, rc = 0;
2196d65bee7SRob Johnston 
2206d65bee7SRob Johnston 	if ((auth = topo_mod_auth(mod, slotnode)) == NULL) {
2216d65bee7SRob Johnston 		topo_mod_dprintf(mod, "topo_mod_auth() failed: %s",
2226d65bee7SRob Johnston 		    topo_mod_errmsg(mod));
2236d65bee7SRob Johnston 		/* errno set */
2246d65bee7SRob Johnston 		return (NULL);
2256d65bee7SRob Johnston 	}
2266d65bee7SRob Johnston 
2276d65bee7SRob Johnston 	if (smed->sme_smb_info != NULL) {
2286d65bee7SRob Johnston 		if (is_valid_string(smb_info->smbi_part) == B_TRUE)
2296d65bee7SRob Johnston 			part = smb_info->smbi_part;
2306d65bee7SRob Johnston 		if (is_valid_string(smb_info->smbi_version) == B_TRUE)
2316d65bee7SRob Johnston 			rev = smb_info->smbi_version;
2326d65bee7SRob Johnston 		if (is_valid_string(smb_info->smbi_serial) == B_TRUE)
2336d65bee7SRob Johnston 			serial = smb_info->smbi_serial;
2346d65bee7SRob Johnston 		if (is_valid_string(smb_info->smbi_manufacturer) == B_TRUE)
2356d65bee7SRob Johnston 			manuf = topo_mod_clean_str(mod,
2366d65bee7SRob Johnston 			    smb_info->smbi_manufacturer);
2376d65bee7SRob Johnston 		if (is_valid_string(smb_info->smbi_product) == B_TRUE)
2386d65bee7SRob Johnston 			prod = topo_mod_clean_str(mod, smb_info->smbi_product);
2396d65bee7SRob Johnston 		if (is_valid_string(smb_info->smbi_asset) == B_TRUE)
2406d65bee7SRob Johnston 			asset = topo_mod_clean_str(mod, smb_info->smbi_asset);
2416d65bee7SRob Johnston 		if (is_valid_string(smb_info->smbi_location) == B_TRUE)
2426d65bee7SRob Johnston 			loc = topo_mod_clean_str(mod, smb_info->smbi_location);
2436d65bee7SRob Johnston 	}
2446d65bee7SRob Johnston 
2456d65bee7SRob Johnston 	if ((fmri = topo_mod_hcfmri(mod, slotnode, FM_HC_SCHEME_VERSION,
2466d65bee7SRob Johnston 	    DIMM, 0, NULL, auth, part, rev, serial)) == NULL) {
2476d65bee7SRob Johnston 		nvlist_free(auth);
2486d65bee7SRob Johnston 		topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s",
2496d65bee7SRob Johnston 		    topo_mod_errmsg(mod));
2506d65bee7SRob Johnston 		/* errno set */
2516d65bee7SRob Johnston 		goto err;
2526d65bee7SRob Johnston 	}
2536d65bee7SRob Johnston 
2546d65bee7SRob Johnston 	if (topo_node_range_create(mod, slotnode, DIMM, 0, 0) < 0 ||
2556d65bee7SRob Johnston 	    (dimmnode = topo_node_bind(mod, slotnode, DIMM, 0, fmri)) ==
2566d65bee7SRob Johnston 	    NULL) {
2578522c52aSRob Johnston 		nvlist_free(auth);
2586d65bee7SRob Johnston 		nvlist_free(fmri);
2596d65bee7SRob Johnston 		topo_mod_dprintf(mod, "failed to bind dimm node: %s",
2606d65bee7SRob Johnston 		    topo_mod_errmsg(mod));
2616d65bee7SRob Johnston 		/* errno set */
2626d65bee7SRob Johnston 		goto err;
2636d65bee7SRob Johnston 	}
2646d65bee7SRob Johnston 
2658522c52aSRob Johnston 	/* Create authority and system pgroups */
2668522c52aSRob Johnston 	topo_pgroup_hcset(dimmnode, auth);
2678522c52aSRob Johnston 	nvlist_free(auth);
2688522c52aSRob Johnston 
2695cc5d5ceSToomas Soome 	if (topo_node_fru_set(dimmnode, fmri, 0, &err) != 0) {
2706d65bee7SRob Johnston 		topo_mod_dprintf(mod, "failed to set FRU on %s: %s",
2716d65bee7SRob Johnston 		    DIMM, topo_strerror(err));
2726d65bee7SRob Johnston 		nvlist_free(fmri);
2736d65bee7SRob Johnston 		(void) topo_mod_seterrno(mod, err);
2746d65bee7SRob Johnston 		goto err;
2756d65bee7SRob Johnston 	}
2766d65bee7SRob Johnston 	nvlist_free(fmri);
2776d65bee7SRob Johnston 
2786d65bee7SRob Johnston 	if (topo_node_label_set(dimmnode, (char *)smb_md->smbmd_dloc, &err) !=
2796d65bee7SRob Johnston 	    0) {
2806d65bee7SRob Johnston 		topo_mod_dprintf(mod, "failed to set label on %s: %s",
2816d65bee7SRob Johnston 		    DIMM, topo_strerror(err));
2826d65bee7SRob Johnston 		(void) topo_mod_seterrno(mod, err);
2836d65bee7SRob Johnston 		goto err;
2846d65bee7SRob Johnston 	}
2856d65bee7SRob Johnston 
2866d65bee7SRob Johnston 	pgi.tpi_name = TOPO_PGROUP_DIMM_PROPS;
2876d65bee7SRob Johnston 	pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
2886d65bee7SRob Johnston 	pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
2896d65bee7SRob Johnston 	pgi.tpi_version = TOPO_VERSION;
2906d65bee7SRob Johnston 	if (topo_pgroup_create(dimmnode, &pgi, &err) != 0) {
2916d65bee7SRob Johnston 		(void) topo_mod_seterrno(mod, err);
2926d65bee7SRob Johnston 		goto err;
2936d65bee7SRob Johnston 	}
2946d65bee7SRob Johnston 
2956d65bee7SRob Johnston 	rc += topo_prop_set_uint64(dimmnode, TOPO_PGROUP_DIMM_PROPS, "size",
2966d65bee7SRob Johnston 	    TOPO_PROP_IMMUTABLE, smb_md->smbmd_size, &err);
2976d65bee7SRob Johnston 	if (rc == 0 && (type = smbios2topotype(mod, smb_md->smbmd_type)) !=
2986d65bee7SRob Johnston 	    NULL) {
2996d65bee7SRob Johnston 		rc += topo_prop_set_string(dimmnode, TOPO_PGROUP_DIMM_PROPS,
3006d65bee7SRob Johnston 		    "type", TOPO_PROP_IMMUTABLE, type, &err);
3016d65bee7SRob Johnston 		topo_mod_strfree(mod, type);
3026d65bee7SRob Johnston 	}
3036d65bee7SRob Johnston 	if (rc == 0 && smb_md->smbmd_set != 0 && smb_md->smbmd_set != 0xFF)
3046d65bee7SRob Johnston 		rc += topo_prop_set_uint32(dimmnode, TOPO_PGROUP_DIMM_PROPS,
3056d65bee7SRob Johnston 		    "set", TOPO_PROP_IMMUTABLE, smb_md->smbmd_set, &err);
3066d65bee7SRob Johnston 	if (rc == 0 && smb_md->smbmd_rank != 0)
3076d65bee7SRob Johnston 		rc += topo_prop_set_uint32(dimmnode, TOPO_PGROUP_DIMM_PROPS,
3086d65bee7SRob Johnston 		    "rank", TOPO_PROP_IMMUTABLE, smb_md->smbmd_rank, &err);
3096d65bee7SRob Johnston 	if (rc == 0 && smb_md->smbmd_clkspeed != 0)
3106d65bee7SRob Johnston 		rc += topo_prop_set_uint32(dimmnode, TOPO_PGROUP_DIMM_PROPS,
3116d65bee7SRob Johnston 		    "configured-speed", TOPO_PROP_IMMUTABLE,
3126d65bee7SRob Johnston 		    smb_md->smbmd_clkspeed, &err);
3136d65bee7SRob Johnston 	if (rc == 0 && smb_md->smbmd_speed != 0)
3146d65bee7SRob Johnston 		rc += topo_prop_set_uint32(dimmnode, TOPO_PGROUP_DIMM_PROPS,
3156d65bee7SRob Johnston 		    "maximum-speed", TOPO_PROP_IMMUTABLE, smb_md->smbmd_speed,
3166d65bee7SRob Johnston 		    &err);
3176d65bee7SRob Johnston 	if (rc == 0 && smb_md->smbmd_maxvolt != 0)
3186d65bee7SRob Johnston 		rc += topo_prop_set_double(dimmnode, TOPO_PGROUP_DIMM_PROPS,
3196d65bee7SRob Johnston 		    "maximum-voltage", TOPO_PROP_IMMUTABLE,
320b723bda3SRobert Mustacchi 		    (smb_md->smbmd_maxvolt / 1000.0), &err);
3216d65bee7SRob Johnston 	if (rc == 0 && smb_md->smbmd_minvolt != 0)
3226d65bee7SRob Johnston 		rc += topo_prop_set_double(dimmnode, TOPO_PGROUP_DIMM_PROPS,
3236d65bee7SRob Johnston 		    "minimum-voltage", TOPO_PROP_IMMUTABLE,
324b723bda3SRobert Mustacchi 		    (smb_md->smbmd_minvolt / 1000.0), &err);
3256d65bee7SRob Johnston 	if (rc == 0 && smb_md->smbmd_confvolt != 0)
3266d65bee7SRob Johnston 		rc += topo_prop_set_double(dimmnode, TOPO_PGROUP_DIMM_PROPS,
3276d65bee7SRob Johnston 		    "configured-voltage", TOPO_PROP_IMMUTABLE,
328b723bda3SRobert Mustacchi 		    (smb_md->smbmd_confvolt / 1000.0), &err);
3296d65bee7SRob Johnston 	if (rc == 0 && manuf != NULL)
3306d65bee7SRob Johnston 		rc += topo_prop_set_string(dimmnode, TOPO_PGROUP_DIMM_PROPS,
3316d65bee7SRob Johnston 		    "manufacturer", TOPO_PROP_IMMUTABLE, manuf, &err);
3326d65bee7SRob Johnston 	if (rc == 0 && prod != NULL)
3336d65bee7SRob Johnston 		rc += topo_prop_set_string(dimmnode, TOPO_PGROUP_DIMM_PROPS,
3346d65bee7SRob Johnston 		    "product", TOPO_PROP_IMMUTABLE, prod, &err);
3356d65bee7SRob Johnston 	if (rc == 0 && asset != NULL)
3366d65bee7SRob Johnston 		rc += topo_prop_set_string(dimmnode, TOPO_PGROUP_DIMM_PROPS,
3376d65bee7SRob Johnston 		    "asset-tag", TOPO_PROP_IMMUTABLE, asset, &err);
3386d65bee7SRob Johnston 	if (rc == 0 && loc != NULL)
3396d65bee7SRob Johnston 		rc += topo_prop_set_string(dimmnode, TOPO_PGROUP_DIMM_PROPS,
3406d65bee7SRob Johnston 		    "location", TOPO_PROP_IMMUTABLE, loc, &err);
3416d65bee7SRob Johnston 
3426d65bee7SRob Johnston 	if (rc != 0) {
3436d65bee7SRob Johnston 		topo_mod_dprintf(mod, "error setting properties on %s node",
3446d65bee7SRob Johnston 		    DIMM);
3456d65bee7SRob Johnston 		(void) topo_mod_seterrno(mod, err);
3466d65bee7SRob Johnston 		goto err;
3476d65bee7SRob Johnston 	}
3486d65bee7SRob Johnston 	ret = dimmnode;
3496d65bee7SRob Johnston err:
3506d65bee7SRob Johnston 	topo_mod_strfree(mod, manuf);
3516d65bee7SRob Johnston 	topo_mod_strfree(mod, prod);
3526d65bee7SRob Johnston 	topo_mod_strfree(mod, asset);
3536d65bee7SRob Johnston 	topo_mod_strfree(mod, loc);
3546d65bee7SRob Johnston 	return (ret);
3556d65bee7SRob Johnston }
3566d65bee7SRob Johnston 
3576d65bee7SRob Johnston static int
smbios_enum_memory(smbios_hdl_t * shp,const smbios_struct_t * sp,void * arg)3586d65bee7SRob Johnston smbios_enum_memory(smbios_hdl_t *shp, const smbios_struct_t *sp, void *arg)
3596d65bee7SRob Johnston {
3606d65bee7SRob Johnston 	smbios_info_t smb_info;
3616d65bee7SRob Johnston 	smbios_memdevice_t smb_md;
3626d65bee7SRob Johnston 	smb_enum_data_t *smed = arg;
3636d65bee7SRob Johnston 	topo_mod_t *mod = smed->sme_mod;
3646d65bee7SRob Johnston 	tnode_t *slotnode;
3656d65bee7SRob Johnston 
3666d65bee7SRob Johnston 	if (sp->smbstr_type != SMB_TYPE_MEMDEVICE)
3676d65bee7SRob Johnston 		return (0);
3686d65bee7SRob Johnston 
3696d65bee7SRob Johnston 	if (smbios_info_memdevice(shp, sp->smbstr_id, &smb_md) != 0) {
3706d65bee7SRob Johnston 		topo_mod_dprintf(mod, "libsmbios error");
3716d65bee7SRob Johnston 		return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
3726d65bee7SRob Johnston 	}
3736d65bee7SRob Johnston 
3746d65bee7SRob Johnston 	/*
3756d65bee7SRob Johnston 	 * SMB_TYPE_MEMDEVICE records can also be used to represent memory
3766d65bee7SRob Johnston 	 * that come in non-DIMM form factors. If we encounter something like
3776d65bee7SRob Johnston 	 * that, then we skip over it.
3786d65bee7SRob Johnston 	 */
3796d65bee7SRob Johnston 	if ((smed->sme_slot_form = distill_dimm_form(mod, &smb_md)) == NULL)
3806d65bee7SRob Johnston 		return (0);
3816d65bee7SRob Johnston 
3826d65bee7SRob Johnston 	if ((slotnode = smbios_make_slot(smed, &smb_md)) == NULL) {
3836d65bee7SRob Johnston 		topo_mod_dprintf(mod, "failed to create %s node", SLOT);
3846d65bee7SRob Johnston 		topo_mod_strfree(mod, smed->sme_slot_form);
3856d65bee7SRob Johnston 		/* errno set */
3866d65bee7SRob Johnston 		return (-1);
3876d65bee7SRob Johnston 	}
3886d65bee7SRob Johnston 	topo_mod_strfree(mod, smed->sme_slot_form);
3896d65bee7SRob Johnston 	smed->sme_slotnode = slotnode;
3906d65bee7SRob Johnston 
3916d65bee7SRob Johnston 	/*
3926d65bee7SRob Johnston 	 * A size of zero indicates that the DIMM slot is not populated, so
3936d65bee7SRob Johnston 	 * we skip creating a child dimm node and return.
3946d65bee7SRob Johnston 	 */
3956d65bee7SRob Johnston 	if (smb_md.smbmd_size == 0) {
3966d65bee7SRob Johnston 		smed->sme_slot_inst++;
3976d65bee7SRob Johnston 		return (0);
3986d65bee7SRob Johnston 	}
3996d65bee7SRob Johnston 
4006d65bee7SRob Johnston 	if (smbios_info_common(shp, sp->smbstr_id, &smb_info) == 0)
4016d65bee7SRob Johnston 		smed->sme_smb_info = &smb_info;
4026d65bee7SRob Johnston 
4036d65bee7SRob Johnston 	if (smbios_make_dimm(smed, &smb_md) == NULL) {
4046d65bee7SRob Johnston 		topo_mod_dprintf(mod, "failed to create %s node", DIMM);
4056d65bee7SRob Johnston 		/* errno set */
4066d65bee7SRob Johnston 		return (-1);
4076d65bee7SRob Johnston 	}
4086d65bee7SRob Johnston 	/*
4096d65bee7SRob Johnston 	 * If we've exceeded our max inst then return non-zero to cause
4106d65bee7SRob Johnston 	 * the walk to terminate.
4116d65bee7SRob Johnston 	 */
4126d65bee7SRob Johnston 	if (++smed->sme_slot_inst > smed->sme_slot_maxinst)
4136d65bee7SRob Johnston 		return (1);
4146d65bee7SRob Johnston 
4156d65bee7SRob Johnston 	return (0);
4166d65bee7SRob Johnston }
4176d65bee7SRob Johnston 
4188522c52aSRob Johnston static int
smbios_enum_motherboard(smbios_hdl_t * shp,smb_enum_data_t * smed)4198522c52aSRob Johnston smbios_enum_motherboard(smbios_hdl_t *shp, smb_enum_data_t *smed)
4208522c52aSRob Johnston {
4218522c52aSRob Johnston 	smbios_struct_t sp;
4228522c52aSRob Johnston 	smbios_bboard_t smb_mb;
4238522c52aSRob Johnston 	smbios_bios_t smb_bios;
4248522c52aSRob Johnston 	smbios_info_t smb_info;
4258522c52aSRob Johnston 	const char *part = NULL, *rev = NULL, *serial = NULL;
4268522c52aSRob Johnston 	char *manuf = NULL, *prod = NULL, *asset = NULL;
4278522c52aSRob Johnston 	char *bios_vendor = NULL, *bios_rev = NULL, *bios_reldate = NULL;
4288522c52aSRob Johnston 	nvlist_t *auth, *fmri;
4298522c52aSRob Johnston 	topo_mod_t *mod = smed->sme_mod;
4308522c52aSRob Johnston 	tnode_t *mbnode;
4318522c52aSRob Johnston 	topo_pgroup_info_t pgi;
4328522c52aSRob Johnston 	int rc = 0, err;
4338522c52aSRob Johnston 
4348522c52aSRob Johnston 	if (smbios_lookup_type(shp, SMB_TYPE_BASEBOARD, &sp) == 0 &&
4358522c52aSRob Johnston 	    smbios_info_bboard(shp, sp.smbstr_id, &smb_mb) == 0 &&
4368522c52aSRob Johnston 	    smbios_info_common(shp, sp.smbstr_id, &smb_info) == 0) {
4378522c52aSRob Johnston 		if (is_valid_string(smb_info.smbi_part) == B_TRUE)
4388522c52aSRob Johnston 			part = smb_info.smbi_part;
4398522c52aSRob Johnston 		if (is_valid_string(smb_info.smbi_version) == B_TRUE)
4408522c52aSRob Johnston 			rev = smb_info.smbi_version;
4418522c52aSRob Johnston 		if (is_valid_string(smb_info.smbi_serial) == B_TRUE)
4428522c52aSRob Johnston 			serial = smb_info.smbi_serial;
4438522c52aSRob Johnston 		if (is_valid_string(smb_info.smbi_manufacturer) == B_TRUE)
4448522c52aSRob Johnston 			manuf = topo_mod_clean_str(mod,
4458522c52aSRob Johnston 			    smb_info.smbi_manufacturer);
4468522c52aSRob Johnston 		if (is_valid_string(smb_info.smbi_product) == B_TRUE)
4478522c52aSRob Johnston 			prod = topo_mod_clean_str(mod, smb_info.smbi_product);
4488522c52aSRob Johnston 		if (is_valid_string(smb_info.smbi_asset) == B_TRUE)
4498522c52aSRob Johnston 			asset = topo_mod_clean_str(mod, smb_info.smbi_asset);
4508522c52aSRob Johnston 	}
4518522c52aSRob Johnston 	if (smbios_lookup_type(shp, SMB_TYPE_BIOS, &sp) == 0 &&
4528522c52aSRob Johnston 	    smbios_info_bios(shp, &smb_bios) == 0) {
4538522c52aSRob Johnston 		if (is_valid_string(smb_bios.smbb_vendor) == B_TRUE)
4548522c52aSRob Johnston 			bios_vendor = topo_mod_clean_str(mod,
4558522c52aSRob Johnston 			    smb_bios.smbb_vendor);
4568522c52aSRob Johnston 		if (is_valid_string(smb_bios.smbb_version) == B_TRUE)
4578522c52aSRob Johnston 			bios_rev = topo_mod_clean_str(mod,
4588522c52aSRob Johnston 			    smb_bios.smbb_version);
4598522c52aSRob Johnston 		if (is_valid_string(smb_bios.smbb_reldate) == B_TRUE)
4608522c52aSRob Johnston 			bios_reldate = topo_mod_clean_str(mod,
4618522c52aSRob Johnston 			    smb_bios.smbb_reldate);
4628522c52aSRob Johnston 	}
4638522c52aSRob Johnston 	if ((auth = topo_mod_auth(mod, smed->sme_pnode)) == NULL) {
4648522c52aSRob Johnston 		topo_mod_dprintf(mod, "topo_mod_auth() failed: %s",
4658522c52aSRob Johnston 		    topo_mod_errmsg(mod));
4668522c52aSRob Johnston 		/* errno set */
4678522c52aSRob Johnston 		goto err;
4688522c52aSRob Johnston 	}
4698522c52aSRob Johnston 
4708522c52aSRob Johnston 	if ((fmri = topo_mod_hcfmri(mod, NULL, FM_HC_SCHEME_VERSION,
4718522c52aSRob Johnston 	    MOTHERBOARD, 0, NULL, auth, part, rev, serial)) ==
4728522c52aSRob Johnston 	    NULL) {
4738522c52aSRob Johnston 		nvlist_free(auth);
4748522c52aSRob Johnston 		topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s",
4758522c52aSRob Johnston 		    topo_mod_errmsg(mod));
4768522c52aSRob Johnston 		/* errno set */
4778522c52aSRob Johnston 		goto err;
4788522c52aSRob Johnston 	}
4798522c52aSRob Johnston 
4808522c52aSRob Johnston 	if ((mbnode = topo_node_bind(mod, smed->sme_pnode, MOTHERBOARD, 0,
4818522c52aSRob Johnston 	    fmri)) == NULL) {
4828522c52aSRob Johnston 		nvlist_free(auth);
4838522c52aSRob Johnston 		nvlist_free(fmri);
4848522c52aSRob Johnston 		topo_mod_dprintf(mod, "topo_node_bind() failed: %s",
4858522c52aSRob Johnston 		    topo_mod_errmsg(mod));
4868522c52aSRob Johnston 		/* errno set */
4878522c52aSRob Johnston 		goto err;
4888522c52aSRob Johnston 	}
4898522c52aSRob Johnston 
4908522c52aSRob Johnston 	/* Create authority and system pgroups */
4918522c52aSRob Johnston 	topo_pgroup_hcset(mbnode, auth);
4928522c52aSRob Johnston 	nvlist_free(auth);
4938522c52aSRob Johnston 
4945cc5d5ceSToomas Soome 	if (topo_node_fru_set(mbnode, fmri, 0, &err) != 0) {
4958522c52aSRob Johnston 		topo_mod_dprintf(mod, "failed to set FRU on %s: %s",
4968522c52aSRob Johnston 		    MOTHERBOARD, topo_strerror(err));
4978522c52aSRob Johnston 		nvlist_free(fmri);
4988522c52aSRob Johnston 		(void) topo_mod_seterrno(mod, err);
4998522c52aSRob Johnston 		goto err;
5008522c52aSRob Johnston 	}
5018522c52aSRob Johnston 	nvlist_free(fmri);
5028522c52aSRob Johnston 	fmri = NULL;
5038522c52aSRob Johnston 
5048522c52aSRob Johnston 	if (topo_node_label_set(mbnode, "MB", &err) != 0) {
5058522c52aSRob Johnston 		topo_mod_dprintf(mod, "failed to set label on %s: %s",
5068522c52aSRob Johnston 		    MOTHERBOARD, topo_strerror(err));
5078522c52aSRob Johnston 		(void) topo_mod_seterrno(mod, err);
5088522c52aSRob Johnston 		goto err;
5098522c52aSRob Johnston 	}
5108522c52aSRob Johnston 
5118522c52aSRob Johnston 	pgi.tpi_name = TOPO_PGROUP_MOTHERBOARD;
5128522c52aSRob Johnston 	pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
5138522c52aSRob Johnston 	pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
5148522c52aSRob Johnston 	pgi.tpi_version = TOPO_VERSION;
5158522c52aSRob Johnston 	rc = topo_pgroup_create(mbnode, &pgi, &err);
5168522c52aSRob Johnston 
5178522c52aSRob Johnston 	if (rc == 0 && manuf != NULL)
5188522c52aSRob Johnston 		rc += topo_prop_set_string(mbnode, TOPO_PGROUP_MOTHERBOARD,
5198522c52aSRob Johnston 		    TOPO_PROP_MB_MANUFACTURER, TOPO_PROP_IMMUTABLE, manuf,
5208522c52aSRob Johnston 		    &err);
5218522c52aSRob Johnston 	if (rc == 0 && prod != NULL)
5228522c52aSRob Johnston 		rc += topo_prop_set_string(mbnode, TOPO_PGROUP_MOTHERBOARD,
5238522c52aSRob Johnston 		    TOPO_PROP_MB_PRODUCT, TOPO_PROP_IMMUTABLE, prod, &err);
5248522c52aSRob Johnston 	if (rc == 0 && asset != NULL)
5258522c52aSRob Johnston 		rc += topo_prop_set_string(mbnode, TOPO_PGROUP_MOTHERBOARD,
5268522c52aSRob Johnston 		    TOPO_PROP_MB_ASSET, TOPO_PROP_IMMUTABLE, asset, &err);
5278522c52aSRob Johnston 
5288522c52aSRob Johnston 	if (rc != 0) {
5298522c52aSRob Johnston 		topo_mod_dprintf(mod, "error setting properties on %s node",
5308522c52aSRob Johnston 		    MOTHERBOARD);
5318522c52aSRob Johnston 		(void) topo_mod_seterrno(mod, err);
5328522c52aSRob Johnston 		goto err;
5338522c52aSRob Johnston 	}
534508a0e8cSRob Johnston 	/*
535508a0e8cSRob Johnston 	 * If we were able to gleen the BIOS version from SMBIOS, then set
536508a0e8cSRob Johnston 	 * up a UFM node to capture that information.
537508a0e8cSRob Johnston 	 */
538508a0e8cSRob Johnston 	if (bios_rev != NULL) {
539508a0e8cSRob Johnston 		topo_ufm_slot_info_t slotinfo = { 0 };
540508a0e8cSRob Johnston 		nvlist_t *extra;
541508a0e8cSRob Johnston 
542508a0e8cSRob Johnston 		slotinfo.usi_version = bios_rev;
543508a0e8cSRob Johnston 		slotinfo.usi_active = B_TRUE;
544508a0e8cSRob Johnston 		slotinfo.usi_mode = TOPO_UFM_SLOT_MODE_NONE;
545508a0e8cSRob Johnston 
546508a0e8cSRob Johnston 		if (bios_vendor != NULL || bios_reldate != NULL) {
547508a0e8cSRob Johnston 			if (nvlist_alloc(&extra, NV_UNIQUE_NAME, 0) != 0) {
548508a0e8cSRob Johnston 				goto err;
549508a0e8cSRob Johnston 			}
550508a0e8cSRob Johnston 			if (bios_vendor != NULL && nvlist_add_string(extra,
551508a0e8cSRob Johnston 			    TOPO_PROP_MB_FIRMWARE_VENDOR, bios_vendor) != 0) {
552508a0e8cSRob Johnston 				nvlist_free(extra);
553508a0e8cSRob Johnston 				goto err;
554508a0e8cSRob Johnston 			}
555508a0e8cSRob Johnston 			if (bios_reldate != NULL && nvlist_add_string(extra,
556508a0e8cSRob Johnston 			    TOPO_PROP_MB_FIRMWARE_RELDATE, bios_reldate) !=
557508a0e8cSRob Johnston 			    0) {
558508a0e8cSRob Johnston 				nvlist_free(extra);
559508a0e8cSRob Johnston 				goto err;
560508a0e8cSRob Johnston 			}
561508a0e8cSRob Johnston 			slotinfo.usi_extra = extra;
562508a0e8cSRob Johnston 		}
563508a0e8cSRob Johnston 		if (topo_node_range_create(mod, mbnode, UFM, 0, 0) != 0) {
564508a0e8cSRob Johnston 			topo_mod_dprintf(mod, "failed to create %s range",
565508a0e8cSRob Johnston 			    UFM);
566508a0e8cSRob Johnston 			nvlist_free(extra);
567508a0e8cSRob Johnston 			goto err;
568508a0e8cSRob Johnston 		}
569744642a2SRobert Mustacchi 		(void) topo_mod_create_ufm(mod, mbnode, 0, "BIOS", &slotinfo);
570508a0e8cSRob Johnston 		nvlist_free(extra);
571508a0e8cSRob Johnston 	}
572508a0e8cSRob Johnston 
5738522c52aSRob Johnston err:
5748522c52aSRob Johnston 	topo_mod_strfree(mod, manuf);
5758522c52aSRob Johnston 	topo_mod_strfree(mod, prod);
5768522c52aSRob Johnston 	topo_mod_strfree(mod, asset);
5778522c52aSRob Johnston 	topo_mod_strfree(mod, bios_vendor);
5788522c52aSRob Johnston 	topo_mod_strfree(mod, bios_rev);
5798522c52aSRob Johnston 	topo_mod_strfree(mod, bios_reldate);
5808522c52aSRob Johnston 
5818522c52aSRob Johnston 	return (0);
5828522c52aSRob Johnston }
5838522c52aSRob Johnston 
5846d65bee7SRob Johnston /*
5856d65bee7SRob Johnston  * A system with a functional memory controller driver will have one mc device
5866d65bee7SRob Johnston  * node per chip instance, starting at instance 0.  The driver provides an
5876d65bee7SRob Johnston  * ioctl interface for retrieving a snapshot of the system's memory topology.
5886d65bee7SRob Johnston  * If we're able to issue this ioctl on one of the mc device nodes then we'll
5896d65bee7SRob Johnston  * return B_TRUE, indicating that this system has a minimally functional memory
5906d65bee7SRob Johnston  * controller driver.
5916d65bee7SRob Johnston  */
5926d65bee7SRob Johnston static boolean_t
has_mc_driver()5936d65bee7SRob Johnston has_mc_driver()
5946d65bee7SRob Johnston {
5956d65bee7SRob Johnston #ifdef	__x86
5966d65bee7SRob Johnston 	int mc_fd;
5976d65bee7SRob Johnston 	mc_snapshot_info_t mcs;
5986d65bee7SRob Johnston 
5996d65bee7SRob Johnston 	if ((mc_fd = open("/dev/mc/mc0", O_RDONLY)) < 0)
6006d65bee7SRob Johnston 		return (B_FALSE);
6016d65bee7SRob Johnston 
6026d65bee7SRob Johnston 	if (ioctl(mc_fd, MC_IOC_SNAPSHOT_INFO, &mcs) < 0) {
6036d65bee7SRob Johnston 		(void) close(mc_fd);
6046d65bee7SRob Johnston 		return (B_FALSE);
6056d65bee7SRob Johnston 	}
6066d65bee7SRob Johnston 	(void) close(mc_fd);
6076d65bee7SRob Johnston 	return (B_TRUE);
6086d65bee7SRob Johnston #else
6096d65bee7SRob Johnston 	return (B_TRUE);
6106d65bee7SRob Johnston #endif
6116d65bee7SRob Johnston }
6126d65bee7SRob Johnston 
6136d65bee7SRob Johnston /*ARGSUSED*/
6146d65bee7SRob Johnston static int
smbios_enum(topo_mod_t * mod,tnode_t * rnode,const char * name,topo_instance_t min,topo_instance_t max,void * arg,void * unused)6156d65bee7SRob Johnston smbios_enum(topo_mod_t *mod, tnode_t *rnode, const char *name,
6166d65bee7SRob Johnston     topo_instance_t min, topo_instance_t max, void *arg, void *unused)
6176d65bee7SRob Johnston {
6186d65bee7SRob Johnston 	smbios_hdl_t *smbh;
6196d65bee7SRob Johnston 	smb_enum_data_t smed = { 0 };
6206d65bee7SRob Johnston 
6216d65bee7SRob Johnston 	if ((smbh = topo_mod_smbios(mod)) == NULL) {
6226d65bee7SRob Johnston 		topo_mod_dprintf(mod, "failed to get libsmbios handle");
6236d65bee7SRob Johnston 		return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
6246d65bee7SRob Johnston 	}
6256d65bee7SRob Johnston 	smed.sme_mod = mod;
6266d65bee7SRob Johnston 	smed.sme_pnode = rnode;
6276d65bee7SRob Johnston 	smed.sme_slot_inst = min;
6286d65bee7SRob Johnston 	smed.sme_slot_maxinst = max;
6296d65bee7SRob Johnston 
6306d65bee7SRob Johnston 	/*
6316d65bee7SRob Johnston 	 * Currently we only support enumerating dimm-slot and dimm nodes, but
6326d65bee7SRob Johnston 	 * this module could be expanded in the future to enumerate other
6336d65bee7SRob Johnston 	 * hardware components from SMBIOS.
6346d65bee7SRob Johnston 	 */
6356d65bee7SRob Johnston 	if (strcmp(name, SLOT) == 0) {
6366d65bee7SRob Johnston 		/*
6376d65bee7SRob Johnston 		 * If the system has a functional memory controller driver then
6386d65bee7SRob Johnston 		 * we'll assume that it has responsibility for enumerating the
6396d65bee7SRob Johnston 		 * memory topology.
6406d65bee7SRob Johnston 		 */
6416d65bee7SRob Johnston 		if (has_mc_driver() == B_TRUE)
6426d65bee7SRob Johnston 			return (0);
6436d65bee7SRob Johnston 		if (smbios_iter(smbh, smbios_enum_memory, &smed) < 0)
6446d65bee7SRob Johnston 			/* errno set */
6456d65bee7SRob Johnston 			return (-1);
6468522c52aSRob Johnston 	} else if (strcmp(name, MOTHERBOARD) == 0) {
6478522c52aSRob Johnston 		if (smbios_enum_motherboard(smbh, &smed) < 0)
6488522c52aSRob Johnston 			/* errno set */
6498522c52aSRob Johnston 			return (-1);
6506d65bee7SRob Johnston 	} else {
6516d65bee7SRob Johnston 		topo_mod_dprintf(mod, "smbios_enum() invoked for unsupported "
6526d65bee7SRob Johnston 		    "node type: %s", name);
6536d65bee7SRob Johnston 		return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
6546d65bee7SRob Johnston 	}
6556d65bee7SRob Johnston 	return (0);
6566d65bee7SRob Johnston }
6576d65bee7SRob Johnston 
6586d65bee7SRob Johnston const topo_modops_t smbios_ops = { smbios_enum, NULL };
6596d65bee7SRob Johnston 
6606d65bee7SRob Johnston const topo_modinfo_t smbios_info =
6616d65bee7SRob Johnston 	{ "smbios", FM_FMRI_SCHEME_HC, TOPO_VERSION, &smbios_ops };
6626d65bee7SRob Johnston 
6636d65bee7SRob Johnston /*ARGSUSED*/
6646d65bee7SRob Johnston int
_topo_init(topo_mod_t * mod,topo_version_t version)6656d65bee7SRob Johnston _topo_init(topo_mod_t *mod, topo_version_t version)
6666d65bee7SRob Johnston {
6676d65bee7SRob Johnston 	if (getenv("TOPOSMBIOSDEBUG") != NULL)
6686d65bee7SRob Johnston 		topo_mod_setdebug(mod);
6696d65bee7SRob Johnston 
6706d65bee7SRob Johnston 	if (topo_mod_register(mod, &smbios_info, TOPO_VERSION) != 0) {
6716d65bee7SRob Johnston 		topo_mod_dprintf(mod, "module registration failed: %s\n",
6726d65bee7SRob Johnston 		    topo_mod_errmsg(mod));
6736d65bee7SRob Johnston 		/* errno set */
6746d65bee7SRob Johnston 		return (-1);
6756d65bee7SRob Johnston 	}
6766d65bee7SRob Johnston 
6776d65bee7SRob Johnston 	topo_mod_dprintf(mod, "SMBIOS enumerator initialized\n");
6786d65bee7SRob Johnston 	return (0);
6796d65bee7SRob Johnston }
6806d65bee7SRob Johnston 
6816d65bee7SRob Johnston void
_topo_fini(topo_mod_t * mod)6826d65bee7SRob Johnston _topo_fini(topo_mod_t *mod)
6836d65bee7SRob Johnston {
6846d65bee7SRob Johnston 	topo_mod_unregister(mod);
6856d65bee7SRob Johnston }
686