120c794b3Sgavinm /*
220c794b3Sgavinm  * CDDL HEADER START
320c794b3Sgavinm  *
420c794b3Sgavinm  * The contents of this file are subject to the terms of the
520c794b3Sgavinm  * Common Development and Distribution License (the "License").
620c794b3Sgavinm  * You may not use this file except in compliance with the License.
720c794b3Sgavinm  *
820c794b3Sgavinm  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
920c794b3Sgavinm  * or http://www.opensolaris.org/os/licensing.
1020c794b3Sgavinm  * See the License for the specific language governing permissions
1120c794b3Sgavinm  * and limitations under the License.
1220c794b3Sgavinm  *
1320c794b3Sgavinm  * When distributing Covered Code, include this CDDL HEADER in each
1420c794b3Sgavinm  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1520c794b3Sgavinm  * If applicable, add the following below this CDDL HEADER, with the
1620c794b3Sgavinm  * fields enclosed by brackets "[]" replaced with your own identifying
1720c794b3Sgavinm  * information: Portions Copyright [yyyy] [name of copyright owner]
1820c794b3Sgavinm  *
1920c794b3Sgavinm  * CDDL HEADER END
2020c794b3Sgavinm  */
2120c794b3Sgavinm 
2220c794b3Sgavinm /*
23efd31e1dSTrang Do  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2420c794b3Sgavinm  */
2520c794b3Sgavinm 
2620c794b3Sgavinm /*
2720c794b3Sgavinm  * AMD memory enumeration
2820c794b3Sgavinm  */
2920c794b3Sgavinm 
3020c794b3Sgavinm #include <sys/types.h>
3120c794b3Sgavinm #include <unistd.h>
3220c794b3Sgavinm #include <stropts.h>
3320c794b3Sgavinm #include <sys/fm/protocol.h>
3420c794b3Sgavinm #include <sys/mc.h>
3520c794b3Sgavinm #include <sys/mc_amd.h>
3620c794b3Sgavinm #include <fm/topo_mod.h>
3720c794b3Sgavinm #include <strings.h>
3820c794b3Sgavinm #include <sys/stat.h>
3920c794b3Sgavinm #include <fcntl.h>
4020c794b3Sgavinm 
4120c794b3Sgavinm #include "chip.h"
4220c794b3Sgavinm 
4320c794b3Sgavinm #define	MAX_CHANNUM	1
4420c794b3Sgavinm #define	MAX_DIMMNUM	7
4520c794b3Sgavinm #define	MAX_CSNUM	7
4620c794b3Sgavinm 
4720c794b3Sgavinm static const topo_pgroup_info_t cs_pgroup =
4820c794b3Sgavinm 	{ PGNAME(CS), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
4920c794b3Sgavinm static const topo_pgroup_info_t dimm_pgroup =
5020c794b3Sgavinm 	{ PGNAME(DIMM), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
5120c794b3Sgavinm static const topo_pgroup_info_t mc_pgroup =
5220c794b3Sgavinm 	{ PGNAME(MCT), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
5320c794b3Sgavinm static const topo_pgroup_info_t rank_pgroup =
5420c794b3Sgavinm 	{ PGNAME(RANK), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
5520c794b3Sgavinm static const topo_pgroup_info_t chan_pgroup =
5620c794b3Sgavinm 	{ PGNAME(CHAN), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
5720c794b3Sgavinm 
5820c794b3Sgavinm static const topo_method_t dimm_methods[] = {
5920c794b3Sgavinm 	{ SIMPLE_DIMM_LBL, "Property method", 0,
6020c794b3Sgavinm 	    TOPO_STABILITY_INTERNAL, simple_dimm_label},
6120c794b3Sgavinm 	{ SIMPLE_DIMM_LBL_MP, "Property method", 0,
6220c794b3Sgavinm 	    TOPO_STABILITY_INTERNAL, simple_dimm_label_mp},
6320c794b3Sgavinm 	{ SEQ_DIMM_LBL, "Property method", 0,
6420c794b3Sgavinm 	    TOPO_STABILITY_INTERNAL, seq_dimm_label},
652cb5535aSrobj 	{ G4_DIMM_LBL, "Property method", 0,
662cb5535aSrobj 	    TOPO_STABILITY_INTERNAL, g4_dimm_label},
67918a0d8aSrobj 	{ G12F_DIMM_LBL, "Property method", 0,
68918a0d8aSrobj 	    TOPO_STABILITY_INTERNAL, g12f_dimm_label},
692cb5535aSrobj 	{ GET_DIMM_SERIAL, "Property method", 0,
702cb5535aSrobj 	    TOPO_STABILITY_INTERNAL, get_dimm_serial},
7120c794b3Sgavinm 	{ NULL }
7220c794b3Sgavinm };
7320c794b3Sgavinm 
74e4b86885SCheng Sean Ye const topo_method_t rank_methods[] = {
7520c794b3Sgavinm 	{ TOPO_METH_ASRU_COMPUTE, TOPO_METH_ASRU_COMPUTE_DESC,
7620c794b3Sgavinm 	    TOPO_METH_ASRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL,
7720c794b3Sgavinm 	    mem_asru_compute },
782cb5535aSrobj 	{ TOPO_METH_PRESENT, TOPO_METH_PRESENT_DESC,
792cb5535aSrobj 	    TOPO_METH_PRESENT_VERSION, TOPO_STABILITY_INTERNAL,
802cb5535aSrobj 	    rank_fmri_present },
8125c6ff4bSstephh 	{ TOPO_METH_REPLACED, TOPO_METH_REPLACED_DESC,
8225c6ff4bSstephh 	    TOPO_METH_REPLACED_VERSION, TOPO_STABILITY_INTERNAL,
8325c6ff4bSstephh 	    rank_fmri_replaced },
8420c794b3Sgavinm 	{ NULL }
8520c794b3Sgavinm };
8620c794b3Sgavinm 
87e4b86885SCheng Sean Ye const topo_method_t ntv_page_retire_methods[] = {
88e4b86885SCheng Sean Ye 	{ TOPO_METH_RETIRE, TOPO_METH_RETIRE_DESC,
89e4b86885SCheng Sean Ye 	    TOPO_METH_RETIRE_VERSION, TOPO_STABILITY_INTERNAL,
90e4b86885SCheng Sean Ye 	    ntv_page_retire },
91e4b86885SCheng Sean Ye 	{ TOPO_METH_UNRETIRE, TOPO_METH_UNRETIRE_DESC,
92e4b86885SCheng Sean Ye 	    TOPO_METH_UNRETIRE_VERSION, TOPO_STABILITY_INTERNAL,
93e4b86885SCheng Sean Ye 	    ntv_page_unretire },
94e4b86885SCheng Sean Ye 	{ TOPO_METH_SERVICE_STATE, TOPO_METH_SERVICE_STATE_DESC,
95e4b86885SCheng Sean Ye 	    TOPO_METH_SERVICE_STATE_VERSION, TOPO_STABILITY_INTERNAL,
96e4b86885SCheng Sean Ye 	    ntv_page_service_state },
97e4b86885SCheng Sean Ye 	{ NULL }
98e4b86885SCheng Sean Ye };
99e4b86885SCheng Sean Ye 
100074bb90dSTom Pothier /*
101074bb90dSTom Pothier  * Serials, Labels are obtained from SMBIOS, so
102074bb90dSTom Pothier  * we leave out the related methods, any other
103074bb90dSTom Pothier  * methods that will be added to gen_cs_methods
104074bb90dSTom Pothier  * should be added to x86pi_gen_cs_methods too
105074bb90dSTom Pothier  */
106074bb90dSTom Pothier static const topo_method_t x86pi_gen_cs_methods[] = {
107074bb90dSTom Pothier 	{ TOPO_METH_ASRU_COMPUTE, TOPO_METH_ASRU_COMPUTE_DESC,
108074bb90dSTom Pothier 	    TOPO_METH_ASRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL,
109074bb90dSTom Pothier 	    mem_asru_compute },
110074bb90dSTom Pothier 	{ NULL }
111074bb90dSTom Pothier };
112074bb90dSTom Pothier 
11320c794b3Sgavinm static const topo_method_t gen_cs_methods[] = {
11420c794b3Sgavinm 	{ TOPO_METH_ASRU_COMPUTE, TOPO_METH_ASRU_COMPUTE_DESC,
11520c794b3Sgavinm 	    TOPO_METH_ASRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL,
11620c794b3Sgavinm 	    mem_asru_compute },
1175108f83cSrobj 	{ SIMPLE_CS_LBL_MP, "Property method", 0,
1185108f83cSrobj 	    TOPO_STABILITY_INTERNAL, simple_cs_label_mp},
11988045cffSRobert Johnston 	{ GET_DIMM_SERIAL, "Property method", 0,
12088045cffSRobert Johnston 	    TOPO_STABILITY_INTERNAL, get_dimm_serial},
12120c794b3Sgavinm 	{ NULL }
12220c794b3Sgavinm };
12320c794b3Sgavinm 
12420c794b3Sgavinm static nvlist_t *cs_fmri[MC_CHIP_NCS];
12520c794b3Sgavinm 
12620c794b3Sgavinm /*
12720c794b3Sgavinm  * Called when there is no memory-controller driver to provide topology
12820c794b3Sgavinm  * information.  Generate a maximal memory topology that is appropriate
12920c794b3Sgavinm  * for the chip revision.  The memory-controller node has already been
13020c794b3Sgavinm  * bound as mcnode, and the parent of that is cnode.
13120c794b3Sgavinm  *
13220c794b3Sgavinm  * We create a tree of dram-channel and chip-select nodes below the
13320c794b3Sgavinm  * memory-controller node.  There will be two dram channels and 8 chip-selects
13420c794b3Sgavinm  * below each, regardless of actual socket type, processor revision and so on.
1358031591dSSrihari Venkatesan  * This is adequate for generic diagnosis up to family 0x10 revision D.
13620c794b3Sgavinm  */
13720c794b3Sgavinm /*ARGSUSED*/
13820c794b3Sgavinm static int
amd_generic_mc_create(topo_mod_t * mod,uint16_t smbid,tnode_t * cnode,tnode_t * mcnode,int family,int model,nvlist_t * auth)139074bb90dSTom Pothier amd_generic_mc_create(topo_mod_t *mod, uint16_t smbid, tnode_t *cnode,
1408031591dSSrihari Venkatesan     tnode_t *mcnode, int family, int model, nvlist_t *auth)
14120c794b3Sgavinm {
14220c794b3Sgavinm 	int chan, cs;
14320c794b3Sgavinm 
14420c794b3Sgavinm 	/*
14520c794b3Sgavinm 	 * Elsewhere we have already returned for families less than 0xf.
14620c794b3Sgavinm 	 * This "generic" topology is adequate for all of family 0xf and
14721ad40f5SJens Elkner 	 * for revisions A to E of family 0x10 (for the list of models
148b8201470SSrihari Venkatesan 	 * in each revision, refer to usr/src/uts/i86pc/os/cpuid_subr.c).
14921ad40f5SJens Elkner 	 * We cover all family 0x10 models, till model 10.
15020c794b3Sgavinm 	 */
15121ad40f5SJens Elkner 	if (family > 0x10 || (family == 0x10 && model > 10))
15220c794b3Sgavinm 		return (1);
15320c794b3Sgavinm 
15420c794b3Sgavinm 	if (topo_node_range_create(mod, mcnode, CHAN_NODE_NAME, 0,
15520c794b3Sgavinm 	    MAX_CHANNUM) < 0) {
15620c794b3Sgavinm 		whinge(mod, NULL, "amd_generic_mc_create: range create for "
15720c794b3Sgavinm 		    "channels failed\n");
15820c794b3Sgavinm 		return (-1);
15920c794b3Sgavinm 	}
16020c794b3Sgavinm 
16120c794b3Sgavinm 	for (chan = 0; chan <= MAX_CHANNUM; chan++) {
16220c794b3Sgavinm 		tnode_t *chnode;
16320c794b3Sgavinm 		nvlist_t *fmri;
16420c794b3Sgavinm 		int err;
16520c794b3Sgavinm 
16620c794b3Sgavinm 		if (mkrsrc(mod, mcnode, CHAN_NODE_NAME, chan, auth,
16720c794b3Sgavinm 		    &fmri) != 0) {
16820c794b3Sgavinm 			whinge(mod, NULL, "amd_generic_mc_create: mkrsrc "
16920c794b3Sgavinm 			    "failed\n");
17020c794b3Sgavinm 			return (-1);
17120c794b3Sgavinm 		}
17220c794b3Sgavinm 
17320c794b3Sgavinm 		if ((chnode = topo_node_bind(mod, mcnode, CHAN_NODE_NAME,
17420c794b3Sgavinm 		    chan, fmri)) == NULL) {
17520c794b3Sgavinm 			nvlist_free(fmri);
17620c794b3Sgavinm 			whinge(mod, NULL, "amd_generic_mc_create: node "
17720c794b3Sgavinm 			    "bind failed\n");
17820c794b3Sgavinm 			return (-1);
17920c794b3Sgavinm 		}
18020c794b3Sgavinm 
18120c794b3Sgavinm 		nvlist_free(fmri);
18220c794b3Sgavinm 
18320c794b3Sgavinm 		(void) topo_pgroup_create(chnode, &chan_pgroup, &err);
18420c794b3Sgavinm 
18520c794b3Sgavinm 		(void) topo_prop_set_string(chnode, PGNAME(CHAN), "channel",
18620c794b3Sgavinm 		    TOPO_PROP_IMMUTABLE, chan == 0 ? "A" : "B", &err);
18720c794b3Sgavinm 
188074bb90dSTom Pothier 		if (FM_AWARE_SMBIOS(mod)) {
189074bb90dSTom Pothier 			if (topo_node_label_set(chnode, NULL, &err) == -1)
190074bb90dSTom Pothier 				whinge(mod, NULL, "amd_generic_mc_create: "
191074bb90dSTom Pothier 				    "topo_node_label_set\n");
192074bb90dSTom Pothier 			if (topo_node_fru_set(chnode, NULL, 0, &err) != 0)
193074bb90dSTom Pothier 				whinge(mod, NULL, "amd_generic_mc_create: "
194074bb90dSTom Pothier 				    "topo_node_fru_set failed\n");
195074bb90dSTom Pothier 		}
196074bb90dSTom Pothier 
19720c794b3Sgavinm 		if (topo_node_range_create(mod, chnode, CS_NODE_NAME,
19820c794b3Sgavinm 		    0, MAX_CSNUM) < 0) {
19920c794b3Sgavinm 			whinge(mod, NULL, "amd_generic_mc_create: "
20020c794b3Sgavinm 			    "range create for cs failed\n");
20120c794b3Sgavinm 			return (-1);
20220c794b3Sgavinm 		}
20320c794b3Sgavinm 
20420c794b3Sgavinm 		for (cs = 0; cs <= MAX_CSNUM; cs++) {
20520c794b3Sgavinm 			tnode_t *csnode;
20620c794b3Sgavinm 
20720c794b3Sgavinm 			if (mkrsrc(mod, chnode, CS_NODE_NAME, cs, auth,
20820c794b3Sgavinm 			    &fmri) != 0) {
20920c794b3Sgavinm 				whinge(mod, NULL, "amd_generic_mc_create: "
21020c794b3Sgavinm 				    "mkrsrc for cs failed\n");
21120c794b3Sgavinm 				return (-1);
21220c794b3Sgavinm 			}
21320c794b3Sgavinm 
21420c794b3Sgavinm 			if ((csnode = topo_node_bind(mod, chnode, CS_NODE_NAME,
21520c794b3Sgavinm 			    cs, fmri)) == NULL) {
21620c794b3Sgavinm 				nvlist_free(fmri);
21720c794b3Sgavinm 				whinge(mod, NULL, "amd_generic_mc_create: "
21820c794b3Sgavinm 				    "bind for cs failed\n");
21920c794b3Sgavinm 				return (-1);
22020c794b3Sgavinm 			}
22120c794b3Sgavinm 
22220c794b3Sgavinm 			/*
22320c794b3Sgavinm 			 * Dynamic ASRU for page faults within a chip-select.
22420c794b3Sgavinm 			 * The topology does not represent pages (there are
22520c794b3Sgavinm 			 * too many) so when a page is faulted we generate
22620c794b3Sgavinm 			 * an ASRU to represent the individual page.
227074bb90dSTom Pothier 			 * If SMBIOS meets FMA needs, derive labels & serials
228074bb90dSTom Pothier 			 * for DIMMS and apply to chip-select nodes.
229074bb90dSTom Pothier 			 * If deriving from SMBIOS, skip IPMI
23020c794b3Sgavinm 			 */
231074bb90dSTom Pothier 			if (FM_AWARE_SMBIOS(mod)) {
232074bb90dSTom Pothier 				if (topo_method_register(mod, csnode,
233074bb90dSTom Pothier 				    x86pi_gen_cs_methods) < 0)
234074bb90dSTom Pothier 					whinge(mod, NULL,
235074bb90dSTom Pothier 					    "amd_generic_mc_create: "
236074bb90dSTom Pothier 					    "method registration failed\n");
237074bb90dSTom Pothier 			} else {
238074bb90dSTom Pothier 				if (topo_method_register(mod, csnode,
239074bb90dSTom Pothier 				    gen_cs_methods) < 0)
240074bb90dSTom Pothier 					whinge(mod, NULL,
241074bb90dSTom Pothier 					    "amd_generic_mc_create: method"
242074bb90dSTom Pothier 					    "registration failed\n");
243074bb90dSTom Pothier 			}
24420c794b3Sgavinm 
24520c794b3Sgavinm 			(void) topo_node_asru_set(csnode, fmri,
24620c794b3Sgavinm 			    TOPO_ASRU_COMPUTE, &err);
24720c794b3Sgavinm 			nvlist_free(fmri);
248074bb90dSTom Pothier 
249074bb90dSTom Pothier 			/*
250074bb90dSTom Pothier 			 * If SMBIOS meets FMA needs, set DIMM as the FRU for
251074bb90dSTom Pothier 			 * the chip-select node. Use the channel & chip-select
252074bb90dSTom Pothier 			 * numbers to get the DIMM instance.
253074bb90dSTom Pothier 			 * Send via inst : dram channel number
254074bb90dSTom Pothier 			 * Receive via inst : dimm instance
255074bb90dSTom Pothier 			 */
256074bb90dSTom Pothier 			if (FM_AWARE_SMBIOS(mod)) {
257074bb90dSTom Pothier 				int inst;
258074bb90dSTom Pothier 				id_t dimm_smbid;
259074bb90dSTom Pothier 				const char *serial;
260074bb90dSTom Pothier 				const char *part;
261074bb90dSTom Pothier 				const char *rev;
262074bb90dSTom Pothier 				char *label;
263074bb90dSTom Pothier 
264074bb90dSTom Pothier 				(void) topo_pgroup_create(csnode,
265074bb90dSTom Pothier 				    &cs_pgroup, &err);
266074bb90dSTom Pothier 				inst = chan;
267efd31e1dSTrang Do 				dimm_smbid = memnode_to_smbiosid(mod, smbid,
268074bb90dSTom Pothier 				    CS_NODE_NAME, cs, &inst);
269074bb90dSTom Pothier 				serial = chip_serial_smbios_get(mod,
270074bb90dSTom Pothier 				    dimm_smbid);
271074bb90dSTom Pothier 				part = chip_part_smbios_get(mod,
272074bb90dSTom Pothier 				    dimm_smbid);
273074bb90dSTom Pothier 				rev = chip_rev_smbios_get(mod, dimm_smbid);
274074bb90dSTom Pothier 				label = (char *)chip_label_smbios_get(mod,
275074bb90dSTom Pothier 				    chnode, dimm_smbid, NULL);
276074bb90dSTom Pothier 
277074bb90dSTom Pothier 				(void) topo_prop_set_string(csnode, PGNAME(CS),
278074bb90dSTom Pothier 				    FM_FMRI_HC_SERIAL_ID, TOPO_PROP_IMMUTABLE,
279074bb90dSTom Pothier 				    serial, &err);
280074bb90dSTom Pothier 				(void) topo_prop_set_string(csnode, PGNAME(CS),
281074bb90dSTom Pothier 				    FM_FMRI_HC_PART, TOPO_PROP_IMMUTABLE,
282074bb90dSTom Pothier 				    part, &err);
283074bb90dSTom Pothier 				(void) topo_prop_set_string(csnode, PGNAME(CS),
284074bb90dSTom Pothier 				    FM_FMRI_HC_REVISION, TOPO_PROP_IMMUTABLE,
285074bb90dSTom Pothier 				    rev, &err);
286074bb90dSTom Pothier 
287074bb90dSTom Pothier 				/*
288074bb90dSTom Pothier 				 * We apply DIMM labels to chip-select nodes,
289074bb90dSTom Pothier 				 * FRU for chip-selects should be DIMMs, and
290074bb90dSTom Pothier 				 * we do not derive dimm nodes for Family 0x10
291074bb90dSTom Pothier 				 * so FRU fmri is NULL, but FRU Labels are set,
292074bb90dSTom Pothier 				 * the FRU labels point to the DIMM.
293074bb90dSTom Pothier 				 */
294074bb90dSTom Pothier 				(void) topo_node_label_set(csnode, label, &err);
295074bb90dSTom Pothier 				topo_mod_strfree(mod, label);
296074bb90dSTom Pothier 			}
29720c794b3Sgavinm 		}
29820c794b3Sgavinm 	}
29920c794b3Sgavinm 
30020c794b3Sgavinm 	return (0);
30120c794b3Sgavinm }
30220c794b3Sgavinm 
30320c794b3Sgavinm static nvlist_t *
amd_lookup_by_mcid(topo_mod_t * mod,topo_instance_t id)30420c794b3Sgavinm amd_lookup_by_mcid(topo_mod_t *mod, topo_instance_t id)
30520c794b3Sgavinm {
30620c794b3Sgavinm 	mc_snapshot_info_t mcs;
30720c794b3Sgavinm 	void *buf = NULL;
30820c794b3Sgavinm 	uint8_t ver;
30920c794b3Sgavinm 
31020c794b3Sgavinm 	nvlist_t *nvl = NULL;
31120c794b3Sgavinm 	char path[64];
31220c794b3Sgavinm 	int fd, err;
31320c794b3Sgavinm 
31420c794b3Sgavinm 	(void) snprintf(path, sizeof (path), "/dev/mc/mc%d", id);
31520c794b3Sgavinm 	fd = open(path, O_RDONLY);
31620c794b3Sgavinm 
31720c794b3Sgavinm 	if (fd == -1) {
31820c794b3Sgavinm 		/*
31920c794b3Sgavinm 		 * Some v20z and v40z systems may have had the 3rd-party
32020c794b3Sgavinm 		 * NWSnps packagae installed which installs a /dev/mc
32120c794b3Sgavinm 		 * link.  So try again via /devices.
32220c794b3Sgavinm 		 */
32320c794b3Sgavinm 		(void) snprintf(path, sizeof (path),
32420c794b3Sgavinm 		    "/devices/pci@0,0/pci1022,1102@%x,2:mc-amd",
32520c794b3Sgavinm 		    MC_AMD_DEV_OFFSET + id);
32620c794b3Sgavinm 		fd = open(path, O_RDONLY);
32720c794b3Sgavinm 	}
32820c794b3Sgavinm 
32920c794b3Sgavinm 	if (fd == -1)
33020c794b3Sgavinm 		return (NULL);	/* do not whinge */
33120c794b3Sgavinm 
33220c794b3Sgavinm 	if (ioctl(fd, MC_IOC_SNAPSHOT_INFO, &mcs) == -1 ||
33320c794b3Sgavinm 	    (buf = topo_mod_alloc(mod, mcs.mcs_size)) == NULL ||
33420c794b3Sgavinm 	    ioctl(fd, MC_IOC_SNAPSHOT, buf) == -1) {
33520c794b3Sgavinm 
33620c794b3Sgavinm 		whinge(mod, NULL, "mc failed to snapshot %s: %s\n",
33720c794b3Sgavinm 		    path, strerror(errno));
33820c794b3Sgavinm 
33920c794b3Sgavinm 		free(buf);
34020c794b3Sgavinm 		(void) close(fd);
34120c794b3Sgavinm 		return (NULL);
34220c794b3Sgavinm 	}
34320c794b3Sgavinm 
34420c794b3Sgavinm 	(void) close(fd);
34520c794b3Sgavinm 	err = nvlist_unpack(buf, mcs.mcs_size, &nvl, 0);
34620c794b3Sgavinm 	topo_mod_free(mod, buf, mcs.mcs_size);
34720c794b3Sgavinm 
34820c794b3Sgavinm 	if (nvlist_lookup_uint8(nvl, MC_NVLIST_VERSTR, &ver) != 0) {
34920c794b3Sgavinm 		whinge(mod, NULL, "mc nvlist is not versioned\n");
35020c794b3Sgavinm 		nvlist_free(nvl);
35120c794b3Sgavinm 		return (NULL);
35220c794b3Sgavinm 	} else if (ver != MC_NVLIST_VERS1) {
35320c794b3Sgavinm 		whinge(mod, NULL, "mc nvlist version mismatch\n");
35420c794b3Sgavinm 		nvlist_free(nvl);
35520c794b3Sgavinm 		return (NULL);
35620c794b3Sgavinm 	}
35720c794b3Sgavinm 
35820c794b3Sgavinm 	return (err ? NULL : nvl);
35920c794b3Sgavinm }
36020c794b3Sgavinm 
36120c794b3Sgavinm int
amd_rank_create(topo_mod_t * mod,tnode_t * pnode,nvlist_t * dimmnvl,nvlist_t * auth)36220c794b3Sgavinm amd_rank_create(topo_mod_t *mod, tnode_t *pnode, nvlist_t *dimmnvl,
36320c794b3Sgavinm     nvlist_t *auth)
36420c794b3Sgavinm {
36520c794b3Sgavinm 	uint64_t *csnumarr;
36620c794b3Sgavinm 	char **csnamearr;
36720c794b3Sgavinm 	uint_t ncs, ncsname;
36820c794b3Sgavinm 	tnode_t *ranknode;
36920c794b3Sgavinm 	nvlist_t *fmri, *pfmri = NULL;
37020c794b3Sgavinm 	uint64_t dsz, rsz;
37120c794b3