1*20c794b3Sgavinm /*
2*20c794b3Sgavinm  * CDDL HEADER START
3*20c794b3Sgavinm  *
4*20c794b3Sgavinm  * The contents of this file are subject to the terms of the
5*20c794b3Sgavinm  * Common Development and Distribution License (the "License").
6*20c794b3Sgavinm  * You may not use this file except in compliance with the License.
7*20c794b3Sgavinm  *
8*20c794b3Sgavinm  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*20c794b3Sgavinm  * or http://www.opensolaris.org/os/licensing.
10*20c794b3Sgavinm  * See the License for the specific language governing permissions
11*20c794b3Sgavinm  * and limitations under the License.
12*20c794b3Sgavinm  *
13*20c794b3Sgavinm  * When distributing Covered Code, include this CDDL HEADER in each
14*20c794b3Sgavinm  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*20c794b3Sgavinm  * If applicable, add the following below this CDDL HEADER, with the
16*20c794b3Sgavinm  * fields enclosed by brackets "[]" replaced with your own identifying
17*20c794b3Sgavinm  * information: Portions Copyright [yyyy] [name of copyright owner]
18*20c794b3Sgavinm  *
19*20c794b3Sgavinm  * CDDL HEADER END
20*20c794b3Sgavinm  */
21*20c794b3Sgavinm 
22*20c794b3Sgavinm /*
23*20c794b3Sgavinm  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24*20c794b3Sgavinm  * Use is subject to license terms.
25*20c794b3Sgavinm  */
26*20c794b3Sgavinm 
27*20c794b3Sgavinm #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*20c794b3Sgavinm 
29*20c794b3Sgavinm #include <unistd.h>
30*20c794b3Sgavinm #include <stdio.h>
31*20c794b3Sgavinm #include <stdlib.h>
32*20c794b3Sgavinm #include <stdarg.h>
33*20c794b3Sgavinm #include <string.h>
34*20c794b3Sgavinm #include <strings.h>
35*20c794b3Sgavinm #include <limits.h>
36*20c794b3Sgavinm #include <alloca.h>
37*20c794b3Sgavinm #include <kstat.h>
38*20c794b3Sgavinm #include <fcntl.h>
39*20c794b3Sgavinm #include <errno.h>
40*20c794b3Sgavinm #include <libnvpair.h>
41*20c794b3Sgavinm #include <sys/types.h>
42*20c794b3Sgavinm #include <sys/bitmap.h>
43*20c794b3Sgavinm #include <sys/processor.h>
44*20c794b3Sgavinm #include <sys/param.h>
45*20c794b3Sgavinm #include <sys/fm/protocol.h>
46*20c794b3Sgavinm #include <sys/systeminfo.h>
47*20c794b3Sgavinm #include <sys/mc.h>
48*20c794b3Sgavinm #include <sys/mc_amd.h>
49*20c794b3Sgavinm #include <sys/mc_intel.h>
50*20c794b3Sgavinm #include <fm/topo_mod.h>
51*20c794b3Sgavinm 
52*20c794b3Sgavinm #include "chip.h"
53*20c794b3Sgavinm 
54*20c794b3Sgavinm #ifndef MAX
55*20c794b3Sgavinm #define	MAX(a, b)	((a) > (b) ? (a) : (b))
56*20c794b3Sgavinm #endif
57*20c794b3Sgavinm 
58*20c794b3Sgavinm static const topo_pgroup_info_t dimm_channel_pgroup =
59*20c794b3Sgavinm 	{ PGNAME(CHAN), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
60*20c794b3Sgavinm static const topo_pgroup_info_t dimm_pgroup =
61*20c794b3Sgavinm 	{ PGNAME(DIMM), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
62*20c794b3Sgavinm static const topo_pgroup_info_t rank_pgroup =
63*20c794b3Sgavinm 	{ PGNAME(RANK), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
64*20c794b3Sgavinm static const topo_pgroup_info_t mc_pgroup =
65*20c794b3Sgavinm 	{ PGNAME(MCT), TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
66*20c794b3Sgavinm static const topo_method_t rank_methods[] = {
67*20c794b3Sgavinm 	{ TOPO_METH_ASRU_COMPUTE, TOPO_METH_ASRU_COMPUTE_DESC,
68*20c794b3Sgavinm 	    TOPO_METH_ASRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL,
69*20c794b3Sgavinm 	    mem_asru_compute },
70*20c794b3Sgavinm 	{ NULL }
71*20c794b3Sgavinm };
72*20c794b3Sgavinm 
73*20c794b3Sgavinm static const topo_method_t dimm_methods[] = {
74*20c794b3Sgavinm 	{ SIMPLE_DIMM_LBL, "Property method", 0, TOPO_STABILITY_INTERNAL,
75*20c794b3Sgavinm 	    simple_dimm_label},
76*20c794b3Sgavinm 	{ SIMPLE_DIMM_LBL_MP, "Property method", 0, TOPO_STABILITY_INTERNAL,
77*20c794b3Sgavinm 	    simple_dimm_label_mp},
78*20c794b3Sgavinm 	{ SEQ_DIMM_LBL, "Property method", 0, TOPO_STABILITY_INTERNAL,
79*20c794b3Sgavinm 	    seq_dimm_label},
80*20c794b3Sgavinm 	{ NULL }
81*20c794b3Sgavinm };
82*20c794b3Sgavinm 
83*20c794b3Sgavinm static int mc_fd;
84*20c794b3Sgavinm 
85*20c794b3Sgavinm int
86*20c794b3Sgavinm mc_offchip_open()
87*20c794b3Sgavinm {
88*20c794b3Sgavinm 	mc_fd = open("/dev/mc/mc", O_RDONLY);
89*20c794b3Sgavinm 	return (mc_fd != -1);
90*20c794b3Sgavinm }
91*20c794b3Sgavinm 
92*20c794b3Sgavinm void
93*20c794b3Sgavinm mc_add_ranks(topo_mod_t *mod, tnode_t *dnode, nvlist_t *auth, int dimm,
94*20c794b3Sgavinm     nvlist_t **ranks_nvp, int nranks, char *serial, char *part, char *rev)
95*20c794b3Sgavinm {
96*20c794b3Sgavinm 	int i;
97*20c794b3Sgavinm 	int rank;
98*20c794b3Sgavinm 	tnode_t *rnode;
99*20c794b3Sgavinm 	nvpair_t *nvp;
100*20c794b3Sgavinm 	nvlist_t *fmri;
101*20c794b3Sgavinm 	int err = 0;
102*20c794b3Sgavinm 
103*20c794b3Sgavinm 	rank = dimm * 2;
104*20c794b3Sgavinm 	if (topo_node_range_create(mod, dnode, RANK, rank,
105*20c794b3Sgavinm 	    rank + nranks - 1) < 0) {
106*20c794b3Sgavinm 		whinge(mod, NULL, "mc_add_dimms: node range create failed"
107*20c794b3Sgavinm 		    " for rank\n");
108*20c794b3Sgavinm 		return;
109*20c794b3Sgavinm 	}
110*20c794b3Sgavinm 	for (i = 0; i < nranks; i++) {
111*20c794b3Sgavinm 		fmri = topo_mod_hcfmri(mod, dnode, FM_HC_SCHEME_VERSION,
112*20c794b3Sgavinm 		    RANK, rank, NULL, auth, part, rev, serial);
113*20c794b3Sgavinm 		if (fmri == NULL) {
114*20c794b3Sgavinm 			whinge(mod, NULL,
115*20c794b3Sgavinm 			    "mc_add_ranks: topo_mod_hcfmri failed\n");
116*20c794b3Sgavinm 			return;
117*20c794b3Sgavinm 		}
118*20c794b3Sgavinm 		if ((rnode = topo_node_bind(mod, dnode, RANK, rank,
119*20c794b3Sgavinm 		    fmri)) == NULL) {
120*20c794b3Sgavinm 			nvlist_free(fmri);
121*20c794b3Sgavinm 			whinge(mod, NULL, "mc_add_ranks: node bind failed"
122*20c794b3Sgavinm 			    " for ranks\n");
123*20c794b3Sgavinm 			return;
124*20c794b3Sgavinm 		}
125*20c794b3Sgavinm 		(void) topo_node_fru_set(rnode, NULL, 0, &err);
126*20c794b3Sgavinm 
127*20c794b3Sgavinm 		if (topo_method_register(mod, rnode, rank_methods) < 0)
128*20c794b3Sgavinm 			whinge(mod, &err, "rank_create: "
129*20c794b3Sgavinm 			    "topo_method_register failed");
130*20c794b3Sgavinm 
131*20c794b3Sgavinm 		(void) topo_node_asru_set(rnode, fmri, TOPO_ASRU_COMPUTE, &err);
132*20c794b3Sgavinm 
133*20c794b3Sgavinm 		nvlist_free(fmri);
134*20c794b3Sgavinm 
135*20c794b3Sgavinm 		(void) topo_pgroup_create(rnode, &rank_pgroup, &err);
136*20c794b3Sgavinm 		for (nvp = nvlist_next_nvpair(ranks_nvp[i], NULL); nvp != NULL;
137*20c794b3Sgavinm 		    nvp = nvlist_next_nvpair(ranks_nvp[i], nvp)) {
138*20c794b3Sgavinm 			(void) nvprop_add(mod, nvp, PGNAME(RANK), rnode);
139*20c794b3Sgavinm 		}
140*20c794b3Sgavinm 		rank++;
141*20c794b3Sgavinm 	}
142*20c794b3Sgavinm }
143*20c794b3Sgavinm 
144*20c794b3Sgavinm static void
145*20c794b3Sgavinm mc_add_dimms(topo_mod_t *mod, tnode_t *pnode, nvlist_t *auth,
146*20c794b3Sgavinm     nvlist_t **nvl, uint_t ndimms)
147*20c794b3Sgavinm {
148*20c794b3Sgavinm 	int i;
149*20c794b3Sgavinm 	nvlist_t *fmri;
150*20c794b3Sgavinm 	tnode_t *dnode;
151*20c794b3Sgavinm 	nvpair_t *nvp;
152*20c794b3Sgavinm 	int err;
153*20c794b3Sgavinm 	nvlist_t **ranks_nvp;
154*20c794b3Sgavinm 	uint_t nranks = 0;
155*20c794b3Sgavinm 	char *serial = NULL;
156*20c794b3Sgavinm 	char *part = NULL;
157*20c794b3Sgavinm 	char *rev = NULL;
158*20c794b3Sgavinm 	char *label = NULL;
159*20c794b3Sgavinm 	char *name;
160*20c794b3Sgavinm 
161*20c794b3Sgavinm 	if (topo_node_range_create(mod, pnode, DIMM, 0, ndimms-1) < 0) {
162*20c794b3Sgavinm 		whinge(mod, NULL,
163*20c794b3Sgavinm 		    "mc_add_dimms: node range create failed\n");
164*20c794b3Sgavinm 		return;
165*20c794b3Sgavinm 	}
166*20c794b3Sgavinm 	for (i = 0; i < ndimms; i++) {
167*20c794b3Sgavinm 		for (nvp = nvlist_next_nvpair(nvl[i], NULL); nvp != NULL;
168*20c794b3Sgavinm 		    nvp = nvlist_next_nvpair(nvl[i], nvp)) {
169*20c794b3Sgavinm 			name = nvpair_name(nvp);
170*20c794b3Sgavinm 			if (strcmp(name, MCINTEL_NVLIST_RANKS) == 0) {
171*20c794b3Sgavinm 				(void) nvpair_value_nvlist_array(nvp,
172*20c794b3Sgavinm 				    &ranks_nvp, &nranks);
173*20c794b3Sgavinm 			} else if (strcmp(name, FM_FMRI_HC_SERIAL_ID) == 0) {
174*20c794b3Sgavinm 				(void) nvpair_value_string(nvp, &serial);
175*20c794b3Sgavinm 			} else if (strcmp(name, FM_FMRI_HC_PART) == 0) {
176*20c794b3Sgavinm 				(void) nvpair_value_string(nvp, &part);
177*20c794b3Sgavinm 			} else if (strcmp(name, FM_FMRI_HC_REVISION) == 0) {
178*20c794b3Sgavinm 				(void) nvpair_value_string(nvp, &rev);
179*20c794b3Sgavinm 			} else if (strcmp(name, FM_FAULT_FRU_LABEL) == 0) {
180*20c794b3Sgavinm 				(void) nvpair_value_string(nvp, &label);
181*20c794b3Sgavinm 			}
182*20c794b3Sgavinm 		}
183*20c794b3Sgavinm 		fmri = NULL;
184*20c794b3Sgavinm 		fmri = topo_mod_hcfmri(mod, pnode, FM_HC_SCHEME_VERSION,
185*20c794b3Sgavinm 		    DIMM, i, NULL, auth, part, rev, serial);
186*20c794b3Sgavinm 		if (fmri == NULL) {
187*20c794b3Sgavinm 			whinge(mod, NULL,
188*20c794b3Sgavinm 			    "mc_add_dimms: topo_mod_hcfmri failed\n");
189*20c794b3Sgavinm 			return;
190*20c794b3Sgavinm 		}
191*20c794b3Sgavinm 		if ((dnode = topo_node_bind(mod, pnode, DIMM, i,
192*20c794b3Sgavinm 		    fmri)) == NULL) {
193*20c794b3Sgavinm 			nvlist_free(fmri);
194*20c794b3Sgavinm 			whinge(mod, NULL, "mc_add_dimms: node bind failed"
195*20c794b3Sgavinm 			    " for dimm\n");
196*20c794b3Sgavinm 			return;
197*20c794b3Sgavinm 		}
198*20c794b3Sgavinm 
199*20c794b3Sgavinm 		if (topo_method_register(mod, dnode, dimm_methods) < 0)
200*20c794b3Sgavinm 			whinge(mod, NULL, "mc_add_dimms: "
201*20c794b3Sgavinm 			    "topo_method_register failed");
202*20c794b3Sgavinm 
203*20c794b3Sgavinm 		(void) topo_node_fru_set(dnode, fmri, 0, &err);
204*20c794b3Sgavinm 		nvlist_free(fmri);
205*20c794b3Sgavinm 		(void) topo_pgroup_create(dnode, &dimm_pgroup, &err);
206*20c794b3Sgavinm 
207*20c794b3Sgavinm 		for (nvp = nvlist_next_nvpair(nvl[i], NULL); nvp != NULL;
208*20c794b3Sgavinm 		    nvp = nvlist_next_nvpair(nvl[i], nvp)) {
209*20c794b3Sgavinm 			name = nvpair_name(nvp);
210*20c794b3Sgavinm 			if (strcmp(name, MCINTEL_NVLIST_RANKS) != 0 &&
211*20c794b3Sgavinm 			    strcmp(name, FM_FAULT_FRU_LABEL) != 0) {
212*20c794b3Sgavinm 				(void) nvprop_add(mod, nvp, PGNAME(DIMM),
213*20c794b3Sgavinm 				    dnode);
214*20c794b3Sgavinm 			}
215*20c794b3Sgavinm 		}
216*20c794b3Sgavinm 		if (label)
217*20c794b3Sgavinm 			(void) topo_node_label_set(dnode, label, &err);
218*20c794b3Sgavinm 
219*20c794b3Sgavinm 		if (nranks) {
220*20c794b3Sgavinm 			mc_add_ranks(mod, dnode, auth, i, ranks_nvp, nranks,
221*20c794b3Sgavinm 			    serial, part, rev);
222*20c794b3Sgavinm 		}
223*20c794b3Sgavinm 	}
224*20c794b3Sgavinm }
225*20c794b3Sgavinm 
226*20c794b3Sgavinm static int
227*20c794b3Sgavinm mc_add_channel(topo_mod_t *mod, tnode_t *pnode, int channel, nvlist_t *auth,
228*20c794b3Sgavinm     nvlist_t *nvl)
229*20c794b3Sgavinm {
230*20c794b3Sgavinm 	tnode_t *mc_channel;
231*20c794b3Sgavinm 	nvlist_t *fmri;
232*20c794b3Sgavinm 	nvlist_t **dimm_nvl;
233*20c794b3Sgavinm 	uint_t ndimms;
234*20c794b3Sgavinm 	int err;
235*20c794b3Sgavinm 
236*20c794b3Sgavinm 	if (mkrsrc(mod, pnode, DRAMCHANNEL, channel, auth, &fmri) != 0) {
237*20c794b3Sgavinm 		whinge(mod, NULL, "mc_add_channel: mkrsrc failed\n");
238*20c794b3Sgavinm 		return (-1);
239*20c794b3Sgavinm 	}
240*20c794b3Sgavinm 	if ((mc_channel = topo_node_bind(mod, pnode, DRAMCHANNEL, channel,
241*20c794b3Sgavinm 	    fmri)) == NULL) {
242*20c794b3Sgavinm 		whinge(mod, NULL, "mc_add_channel: node bind failed for %s\n",
243*20c794b3Sgavinm 		    DRAMCHANNEL);
244*20c794b3Sgavinm 		nvlist_free(fmri);
245*20c794b3Sgavinm 		return (-1);
246*20c794b3Sgavinm 	}
247*20c794b3Sgavinm 	(void) topo_node_fru_set(mc_channel, NULL, 0, &err);
248*20c794b3Sgavinm 	nvlist_free(fmri);
249*20c794b3Sgavinm 	(void) topo_pgroup_create(mc_channel, &dimm_channel_pgroup, &err);
250*20c794b3Sgavinm 	if (nvlist_lookup_nvlist_array(nvl, MCINTEL_NVLIST_DIMMS, &dimm_nvl,
251*20c794b3Sgavinm 	    &ndimms) == 0) {
252*20c794b3Sgavinm 		mc_add_dimms(mod, mc_channel, auth, dimm_nvl, ndimms);
253*20c794b3Sgavinm 	}
254*20c794b3Sgavinm 	return (0);
255*20c794b3Sgavinm }
256*20c794b3Sgavinm 
257*20c794b3Sgavinm static int
258*20c794b3Sgavinm mc_nb_create(topo_mod_t *mod, tnode_t *pnode, const char *name, nvlist_t *auth,
259*20c794b3Sgavinm     nvlist_t *nvl)
260*20c794b3Sgavinm {
261*20c794b3Sgavinm 	int err;
262*20c794b3Sgavinm 	int i, j;
263*20c794b3Sgavinm 	int channel;
264*20c794b3Sgavinm 	int nmc;
265*20c794b3Sgavinm 	tnode_t *mcnode;
266*20c794b3Sgavinm 	nvlist_t *fmri;
267*20c794b3Sgavinm 	nvlist_t **channel_nvl;
268*20c794b3Sgavinm 	uint_t nchannels;
269*20c794b3Sgavinm 
270*20c794b3Sgavinm 	if (nvlist_lookup_nvlist_array(nvl, MCINTEL_NVLIST_MC, &channel_nvl,
271*20c794b3Sgavinm 	    &nchannels) != 0) {
272*20c794b3Sgavinm 		whinge(mod, NULL,
273*20c794b3Sgavinm 		    "mc_nb_create: failed to find channel information\n");
274*20c794b3Sgavinm 		return (-1);
275*20c794b3Sgavinm 	}
276*20c794b3Sgavinm 	nmc = nchannels / 2;
277*20c794b3Sgavinm 	if (topo_node_range_create(mod, pnode, name, 0, nmc-1) < 0) {
278*20c794b3Sgavinm 		whinge(mod, NULL,
279*20c794b3Sgavinm 		    "mc_nb_create: node range create failed\n");
280*20c794b3Sgavinm 		return (-1);
281*20c794b3Sgavinm 	}
282*20c794b3Sgavinm 	channel = 0;
283*20c794b3Sgavinm 	for (i = 0; i < nmc; i++) {
284*20c794b3Sgavinm 		if (mkrsrc(mod, pnode, name, i, auth, &fmri) != 0) {
285*20c794b3Sgavinm 			whinge(mod, NULL, "mc_nb_create: mkrsrc failed\n");
286*20c794b3Sgavinm 			return (-1);
287*20c794b3Sgavinm 		}
288*20c794b3Sgavinm 		if ((mcnode = topo_node_bind(mod, pnode, name, i,
289*20c794b3Sgavinm 		    fmri)) == NULL) {
290*20c794b3Sgavinm 			whinge(mod, NULL, "chip_create: node bind failed"
291*20c794b3Sgavinm 			    " for memory-controller\n");
292*20c794b3Sgavinm 			nvlist_free(fmri);
293*20c794b3Sgavinm 			return (-1);
294*20c794b3Sgavinm 		}
295*20c794b3Sgavinm 
296*20c794b3Sgavinm 		(void) topo_node_fru_set(mcnode, NULL, 0, &err);
297*20c794b3Sgavinm 		nvlist_free(fmri);
298*20c794b3Sgavinm 		(void) topo_pgroup_create(mcnode, &mc_pgroup, &err);
299*20c794b3Sgavinm 
300*20c794b3Sgavinm 		if (topo_node_range_create(mod, mcnode, DRAMCHANNEL, channel,
301*20c794b3Sgavinm 		    channel + 1) < 0) {
302*20c794b3Sgavinm 			whinge(mod, NULL,
303*20c794b3Sgavinm 			    "mc_nb_create: channel node range create failed\n");
304*20c794b3Sgavinm 			return (-1);
305*20c794b3Sgavinm 		}
306*20c794b3Sgavinm 		for (j = 0; j < 2; j++) {
307*20c794b3Sgavinm 			if (mc_add_channel(mod, mcnode, channel, auth,
308*20c794b3Sgavinm 			    channel_nvl[channel]) < 0) {
309*20c794b3Sgavinm 				return (-1);
310*20c794b3Sgavinm 			}
311*20c794b3Sgavinm 			channel++;
312*20c794b3Sgavinm 		}
313*20c794b3Sgavinm 	}
314*20c794b3Sgavinm 
315*20c794b3Sgavinm 	return (NULL);
316*20c794b3Sgavinm }
317*20c794b3Sgavinm 
318*20c794b3Sgavinm int
319*20c794b3Sgavinm mc_offchip_create(topo_mod_t *mod, tnode_t *pnode, const char *name,
320*20c794b3Sgavinm     nvlist_t *auth)
321*20c794b3Sgavinm {
322*20c794b3Sgavinm 	mc_snapshot_info_t mcs;
323*20c794b3Sgavinm 	void *buf = NULL;
324*20c794b3Sgavinm 	nvlist_t *nvl;
325*20c794b3Sgavinm 	uint8_t ver;
326*20c794b3Sgavinm 	int rc;
327*20c794b3Sgavinm 
328*20c794b3Sgavinm 	if (ioctl(mc_fd, MC_IOC_SNAPSHOT_INFO, &mcs) == -1 ||
329*20c794b3Sgavinm 	    (buf = topo_mod_alloc(mod, mcs.mcs_size)) == NULL ||
330*20c794b3Sgavinm 	    ioctl(mc_fd, MC_IOC_SNAPSHOT, buf) == -1) {
331*20c794b3Sgavinm 
332*20c794b3Sgavinm 		whinge(mod, NULL, "mc failed to snapshot %s\n",
333*20c794b3Sgavinm 		    strerror(errno));
334*20c794b3Sgavinm 
335*20c794b3Sgavinm 		free(buf);
336*20c794b3Sgavinm 		(void) close(mc_fd);
337*20c794b3Sgavinm 		return (NULL);
338*20c794b3Sgavinm 	}
339*20c794b3Sgavinm 	(void) close(mc_fd);
340*20c794b3Sgavinm 	(void) nvlist_unpack(buf, mcs.mcs_size, &nvl, 0);
341*20c794b3Sgavinm 	topo_mod_free(mod, buf, mcs.mcs_size);
342*20c794b3Sgavinm 
343*20c794b3Sgavinm 	if (nvlist_lookup_uint8(nvl, MCINTEL_NVLIST_VERSTR, &ver) != 0) {
344*20c794b3Sgavinm 		whinge(mod, NULL, "mc nvlist is not versioned\n");
345*20c794b3Sgavinm 		nvlist_free(nvl);
346*20c794b3Sgavinm 		return (NULL);
347*20c794b3Sgavinm 	} else if (ver != MCINTEL_NVLIST_VERS0) {
348*20c794b3Sgavinm 		whinge(mod, NULL, "mc nvlist version mismatch\n");
349*20c794b3Sgavinm 		nvlist_free(nvl);
350*20c794b3Sgavinm 		return (NULL);
351*20c794b3Sgavinm 	}
352*20c794b3Sgavinm 
353*20c794b3Sgavinm 	rc = mc_nb_create(mod, pnode, name, auth, nvl);
354*20c794b3Sgavinm 
355*20c794b3Sgavinm 	nvlist_free(nvl);
356*20c794b3Sgavinm 	return (rc);
357*20c794b3Sgavinm }
358