xref: /illumos-gate/usr/src/common/mc/imc/imc_dump.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2019 Joyent, Inc.
14  */
15 
16 /*
17  * This implements logic to allow us to dump IMC data for decoding purposes,
18  * such that we can later encode it elsewhere. In general, dumping is done by
19  * the kernel and reconstituting this data is done by user land.
20  */
21 
22 #include "imc.h"
23 
24 #ifndef _KERNEL
25 #include <stdint.h>
26 #include <strings.h>
27 #endif	/* !_KERNEL */
28 
29 
30 static nvlist_t *
31 imc_dump_sad(imc_sad_t *sad)
32 {
33 	uint_t i;
34 	nvlist_t *nvl;
35 	nvlist_t *rules[IMC_MAX_SAD_RULES];
36 	nvlist_t *routes[IMC_MAX_SAD_MCROUTES];
37 
38 	nvl = fnvlist_alloc();
39 	fnvlist_add_uint32(nvl, "isad_flags", sad->isad_flags);
40 	fnvlist_add_uint32(nvl, "isad_valid", sad->isad_valid);
41 	fnvlist_add_uint64(nvl, "isad_tolm", sad->isad_tolm);
42 	fnvlist_add_uint64(nvl, "isad_tohm", sad->isad_tohm);
43 
44 	for (i = 0; i < sad->isad_nrules; i++) {
45 		nvlist_t *n = fnvlist_alloc();
46 		imc_sad_rule_t *r = &sad->isad_rules[i];
47 
48 		fnvlist_add_boolean_value(n, "isr_enable", r->isr_enable);
49 		fnvlist_add_boolean_value(n, "isr_a7mode", r->isr_a7mode);
50 		fnvlist_add_boolean_value(n, "isr_need_mod3", r->isr_need_mod3);
51 		fnvlist_add_uint64(n, "isr_limit", r->isr_limit);
52 		fnvlist_add_uint32(n, "isr_type", r->isr_type);
53 		fnvlist_add_uint32(n, "isr_imode", r->isr_imode);
54 		fnvlist_add_uint32(n, "isr_mod_mode", r->isr_mod_mode);
55 		fnvlist_add_uint32(n, "isr_mod_type", r->isr_mod_type);
56 		fnvlist_add_uint8_array(n, "isr_targets", r->isr_targets,
57 		    r->isr_ntargets);
58 
59 		rules[i] = n;
60 	}
61 	fnvlist_add_nvlist_array(nvl, "isad_rules", rules, sad->isad_nrules);
62 	for (i = 0; i < sad->isad_nrules; i++) {
63 		nvlist_free(rules[i]);
64 	}
65 
66 	if (sad->isad_mcroute.ismc_nroutes == 0) {
67 		return (nvl);
68 	}
69 
70 	for (i = 0; i <  sad->isad_mcroute.ismc_nroutes; i++) {
71 		nvlist_t *r = fnvlist_alloc();
72 		imc_sad_mcroute_entry_t *e =
73 		    &sad->isad_mcroute.ismc_mcroutes[i];
74 
75 		fnvlist_add_uint8(r, "ismce_imc", e->ismce_imc);
76 		fnvlist_add_uint8(r, "ismce_pchannel", e->ismce_pchannel);
77 		routes[i] = r;
78 	}
79 	fnvlist_add_nvlist_array(nvl, "isad_mcroute", routes, i);
80 	for (i = 0; i <  sad->isad_mcroute.ismc_nroutes; i++) {
81 		nvlist_free(routes[i]);
82 	}
83 
84 	return (nvl);
85 }
86 
87 static nvlist_t *
88 imc_dump_tad(imc_tad_t *tad)
89 {
90 	uint_t i;
91 	nvlist_t *nvl;
92 	nvlist_t *rules[IMC_MAX_TAD_RULES];
93 
94 	nvl = fnvlist_alloc();
95 	fnvlist_add_uint32(nvl, "itad_valid", tad->itad_valid);
96 	fnvlist_add_uint32(nvl, "itad_flags", tad->itad_flags);
97 	for (i = 0; i < tad->itad_nrules; i++) {
98 		nvlist_t *t = fnvlist_alloc();
99 		imc_tad_rule_t *r = &tad->itad_rules[i];
100 
101 		fnvlist_add_uint64(t, "itr_base", r->itr_base);
102 		fnvlist_add_uint64(t, "itr_limit", r->itr_limit);
103 		fnvlist_add_uint8(t, "itr_sock_way", r->itr_sock_way);
104 		fnvlist_add_uint8(t, "itr_chan_way", r->itr_chan_way);
105 		fnvlist_add_uint32(t, "itr_sock_gran", r->itr_sock_gran);
106 		fnvlist_add_uint32(t, "itr_chan_gran", r->itr_chan_gran);
107 		fnvlist_add_uint8_array(t, "itr_targets", r->itr_targets,
108 		    r->itr_ntargets);
109 
110 		rules[i] = t;
111 	}
112 	fnvlist_add_nvlist_array(nvl, "itad_rules", rules, tad->itad_nrules);
113 	for (i = 0; i < tad->itad_nrules; i++) {
114 		nvlist_free(rules[i]);
115 	}
116 
117 	return (nvl);
118 }
119 
120 static nvlist_t *
121 imc_dump_channel(imc_channel_t *chan)
122 {
123 	uint_t i;
124 	nvlist_t *nvl;
125 	nvlist_t *dimms[IMC_MAX_DIMMPERCHAN];
126 	nvlist_t *ranks[IMC_MAX_RANK_WAYS];
127 
128 	nvl = fnvlist_alloc();
129 	fnvlist_add_uint32(nvl, "ich_valid", chan->ich_valid);
130 	for (i = 0; i < chan->ich_ndimms; i++) {
131 		nvlist_t *d = fnvlist_alloc();
132 		imc_dimm_t *dimm = &chan->ich_dimms[i];
133 
134 		fnvlist_add_uint32(d, "idimm_valid", dimm->idimm_valid);
135 		fnvlist_add_boolean_value(d, "idimm_present",
136 		    dimm->idimm_present);
137 		if (!dimm->idimm_present)
138 			goto add;
139 
140 		fnvlist_add_uint8(d, "idimm_nbanks", dimm->idimm_nbanks);
141 		fnvlist_add_uint8(d, "idimm_nranks", dimm->idimm_nranks);
142 		fnvlist_add_uint8(d, "idimm_width", dimm->idimm_width);
143 		fnvlist_add_uint8(d, "idimm_density", dimm->idimm_density);
144 		fnvlist_add_uint8(d, "idimm_nrows", dimm->idimm_nrows);
145 		fnvlist_add_uint8(d, "idimm_ncolumns", dimm->idimm_ncolumns);
146 		fnvlist_add_uint64(d, "idimm_size", dimm->idimm_size);
147 add:
148 		dimms[i] = d;
149 	}
150 	fnvlist_add_nvlist_array(nvl, "ich_dimms", dimms, i);
151 	for (i = 0; i < chan->ich_ndimms; i++) {
152 		nvlist_free(dimms[i]);
153 	}
154 
155 	fnvlist_add_uint64_array(nvl, "ich_tad_offsets", chan->ich_tad_offsets,
156 	    chan->ich_ntad_offsets);
157 
158 	for (i = 0; i < chan->ich_nrankileaves; i++) {
159 		uint_t j;
160 		nvlist_t *r = fnvlist_alloc();
161 		nvlist_t *ileaves[IMC_MAX_RANK_INTERLEAVES];
162 		imc_rank_ileave_t *rank = &chan->ich_rankileaves[i];
163 
164 		fnvlist_add_boolean_value(r, "irle_enabled",
165 		    rank->irle_enabled);
166 		fnvlist_add_uint8(r, "irle_nways", rank->irle_nways);
167 		fnvlist_add_uint8(r, "irle_nwaysbits", rank->irle_nwaysbits);
168 		fnvlist_add_uint64(r, "irle_limit", rank->irle_limit);
169 
170 		for (j = 0; j < rank->irle_nentries; j++) {
171 			nvlist_t *e = fnvlist_alloc();
172 
173 			fnvlist_add_uint8(e, "irle_target",
174 			    rank->irle_entries[j].irle_target);
175 			fnvlist_add_uint64(e, "irle_offset",
176 			    rank->irle_entries[j].irle_offset);
177 			ileaves[j] = e;
178 		}
179 		fnvlist_add_nvlist_array(r, "irle_entries", ileaves, j);
180 		for (j = 0; j < rank->irle_nentries; j++) {
181 			nvlist_free(ileaves[j]);
182 		}
183 
184 		ranks[i] = r;
185 	}
186 	fnvlist_add_nvlist_array(nvl, "ich_rankileaves", ranks, i);
187 	for (i = 0; i < chan->ich_nrankileaves; i++) {
188 		nvlist_free(ranks[i]);
189 	}
190 
191 	return (nvl);
192 }
193 
194 static nvlist_t *
195 imc_dump_mc(imc_mc_t *mc)
196 {
197 	uint_t i;
198 	nvlist_t *nvl;
199 	nvlist_t *channels[IMC_MAX_CHANPERMC];
200 
201 	nvl = fnvlist_alloc();
202 	fnvlist_add_boolean_value(nvl, "icn_ecc", mc->icn_ecc);
203 	fnvlist_add_boolean_value(nvl, "icn_lockstep", mc->icn_lockstep);
204 	fnvlist_add_boolean_value(nvl, "icn_closed", mc->icn_closed);
205 	fnvlist_add_uint32(nvl, "icn_dimm_type", mc->icn_dimm_type);
206 
207 	for (i = 0; i < mc->icn_nchannels; i++) {
208 		channels[i] = imc_dump_channel(&mc->icn_channels[i]);
209 	}
210 	fnvlist_add_nvlist_array(nvl, "icn_channels", channels, i);
211 	for (i = 0; i < mc->icn_nchannels; i++) {
212 		nvlist_free(channels[i]);
213 	}
214 
215 	return (nvl);
216 }
217 
218 static nvlist_t *
219 imc_dump_socket(imc_socket_t *sock)
220 {
221 	uint_t i;
222 	nvlist_t *nvl, *sad;
223 	nvlist_t *tad[IMC_MAX_TAD];
224 	nvlist_t *mc[IMC_MAX_IMCPERSOCK];
225 
226 	nvl = fnvlist_alloc();
227 
228 	sad = imc_dump_sad(&sock->isock_sad);
229 	fnvlist_add_nvlist(nvl, "isock_sad", sad);
230 	nvlist_free(sad);
231 
232 	for (i = 0; i < sock->isock_ntad; i++) {
233 		tad[i] = imc_dump_tad(&sock->isock_tad[i]);
234 	}
235 	fnvlist_add_nvlist_array(nvl, "isock_tad", tad, i);
236 	for (i = 0; i < sock->isock_ntad; i++) {
237 		fnvlist_free(tad[i]);
238 	}
239 
240 	fnvlist_add_uint32(nvl, "isock_nodeid", sock->isock_nodeid);
241 
242 	for (i = 0; i  < sock->isock_nimc; i++) {
243 		mc[i] = imc_dump_mc(&sock->isock_imcs[i]);
244 	}
245 	fnvlist_add_nvlist_array(nvl, "isock_imcs", mc, i);
246 	for (i = 0; i < sock->isock_nimc; i++) {
247 		fnvlist_free(mc[i]);
248 	}
249 	return (nvl);
250 }
251 
252 nvlist_t *
253 imc_dump_decoder(imc_t *imc)
254 {
255 	uint_t i;
256 	nvlist_t *nvl, *invl;
257 	nvlist_t *sockets[IMC_MAX_SOCKETS];
258 
259 	nvl = fnvlist_alloc();
260 	fnvlist_add_uint32(nvl, "mc_dump_version", 0);
261 	fnvlist_add_string(nvl, "mc_dump_driver", "imc");
262 
263 	invl = fnvlist_alloc();
264 	fnvlist_add_uint32(invl, "imc_gen", imc->imc_gen);
265 
266 	for (i = 0; i < imc->imc_nsockets; i++) {
267 		sockets[i] = imc_dump_socket(&imc->imc_sockets[i]);
268 	}
269 	fnvlist_add_nvlist_array(invl, "imc_sockets", sockets, i);
270 	fnvlist_add_nvlist(nvl, "imc", invl);
271 
272 	for (i = 0; i < imc->imc_nsockets; i++) {
273 		nvlist_free(sockets[i]);
274 	}
275 	nvlist_free(invl);
276 
277 	return (nvl);
278 }
279 
280 static boolean_t
281 imc_restore_sad(nvlist_t *nvl, imc_sad_t *sad)
282 {
283 	nvlist_t **rules, **routes;
284 	uint_t i, nroutes;
285 
286 	if (nvlist_lookup_uint32(nvl, "isad_flags", &sad->isad_flags) != 0 ||
287 	    nvlist_lookup_uint32(nvl, "isad_valid", &sad->isad_valid) != 0 ||
288 	    nvlist_lookup_uint64(nvl, "isad_tolm", &sad->isad_tolm) != 0 ||
289 	    nvlist_lookup_uint64(nvl, "isad_tohm", &sad->isad_tohm) != 0 ||
290 	    nvlist_lookup_nvlist_array(nvl, "isad_rules",
291 	    &rules, &sad->isad_nrules) != 0) {
292 		return (B_FALSE);
293 	}
294 
295 	for (i = 0; i < sad->isad_nrules; i++) {
296 		imc_sad_rule_t *r = &sad->isad_rules[i];
297 		uint8_t *targs;
298 
299 		if (nvlist_lookup_boolean_value(rules[i], "isr_enable",
300 		    &r->isr_enable) != 0 ||
301 		    nvlist_lookup_boolean_value(rules[i], "isr_a7mode",
302 		    &r->isr_a7mode) != 0 ||
303 		    nvlist_lookup_boolean_value(rules[i], "isr_need_mod3",
304 		    &r->isr_need_mod3) != 0 ||
305 		    nvlist_lookup_uint64(rules[i], "isr_limit",
306 		    &r->isr_limit) != 0 ||
307 		    nvlist_lookup_uint32(rules[i], "isr_type",
308 		    &r->isr_type) != 0 ||
309 		    nvlist_lookup_uint32(rules[i], "isr_imode",
310 		    &r->isr_imode) != 0 ||
311 		    nvlist_lookup_uint32(rules[i], "isr_mod_mode",
312 		    &r->isr_mod_mode) != 0 ||
313 		    nvlist_lookup_uint32(rules[i], "isr_mod_type",
314 		    &r->isr_mod_type) != 0 ||
315 		    nvlist_lookup_uint8_array(rules[i], "isr_targets", &targs,
316 		    &r->isr_ntargets) != 0 ||
317 		    r->isr_ntargets > IMC_MAX_SAD_RULES) {
318 			return (B_FALSE);
319 		}
320 
321 		bcopy(targs, r->isr_targets, r->isr_ntargets *
322 		    sizeof (uint8_t));
323 	}
324 
325 	/*
326 	 * The mcroutes entry right now is only included conditionally.
327 	 */
328 	if (nvlist_lookup_nvlist_array(nvl, "isad_mcroute", &routes,
329 	    &nroutes) == 0) {
330 		if (nroutes > IMC_MAX_SAD_MCROUTES)
331 			return (B_FALSE);
332 		sad->isad_mcroute.ismc_nroutes = nroutes;
333 		for (i = 0; i < nroutes; i++) {
334 			imc_sad_mcroute_entry_t *r =
335 			    &sad->isad_mcroute.ismc_mcroutes[i];
336 			if (nvlist_lookup_uint8(routes[i], "ismce_imc",
337 			    &r->ismce_imc) != 0 ||
338 			    nvlist_lookup_uint8(routes[i], "ismce_pchannel",
339 			    &r->ismce_pchannel) != 0) {
340 				return (B_FALSE);
341 			}
342 		}
343 	}
344 
345 	return (B_TRUE);
346 }
347 
348 static boolean_t
349 imc_restore_tad(nvlist_t *nvl, imc_tad_t *tad)
350 {
351 	nvlist_t **rules;
352 
353 	if (nvlist_lookup_uint32(nvl, "itad_valid", &tad->itad_valid) != 0 ||
354 	    nvlist_lookup_uint32(nvl, "itad_flags", &tad->itad_flags) != 0 ||
355 	    nvlist_lookup_nvlist_array(nvl, "itad_rules", &rules,
356 	    &tad->itad_nrules) != 0 || tad->itad_nrules > IMC_MAX_TAD_RULES) {
357 		return (B_FALSE);
358 	}
359 
360 	for (uint_t i = 0; i < tad->itad_nrules; i++) {
361 		imc_tad_rule_t *r = &tad->itad_rules[i];
362 		uint8_t *targs;
363 
364 		if (nvlist_lookup_uint64(rules[i], "itr_base",
365 		    &r->itr_base) != 0 ||
366 		    nvlist_lookup_uint64(rules[i], "itr_limit",
367 		    &r->itr_limit) != 0 ||
368 		    nvlist_lookup_uint8(rules[i], "itr_sock_way",
369 		    &r->itr_sock_way) != 0 ||
370 		    nvlist_lookup_uint8(rules[i], "itr_chan_way",
371 		    &r->itr_chan_way) != 0 ||
372 		    nvlist_lookup_uint32(rules[i], "itr_sock_gran",
373 		    &r->itr_sock_gran) != 0 ||
374 		    nvlist_lookup_uint32(rules[i], "itr_chan_gran",
375 		    &r->itr_chan_gran) != 0 ||
376 		    nvlist_lookup_uint8_array(rules[i], "itr_targets",
377 		    &targs, &r->itr_ntargets) != 0 ||
378 		    r->itr_ntargets > IMC_MAX_TAD_TARGETS) {
379 			return (B_FALSE);
380 		}
381 
382 		bcopy(targs, r->itr_targets, r->itr_ntargets *
383 		    sizeof (uint8_t));
384 	}
385 
386 	return (B_TRUE);
387 }
388 
389 static boolean_t
390 imc_restore_channel(nvlist_t *nvl, imc_channel_t *chan)
391 {
392 	nvlist_t **dimms, **rir;
393 	uint64_t *tadoff;
394 
395 	if (nvlist_lookup_uint32(nvl, "ich_valid", &chan->ich_valid) != 0 ||
396 	    nvlist_lookup_nvlist_array(nvl, "ich_dimms", &dimms,
397 	    &chan->ich_ndimms) != 0 ||
398 	    chan->ich_ndimms > IMC_MAX_DIMMPERCHAN ||
399 	    nvlist_lookup_uint64_array(nvl, "ich_tad_offsets", &tadoff,
400 	    &chan->ich_ntad_offsets) != 0 ||
401 	    chan->ich_ntad_offsets > IMC_MAX_TAD_RULES ||
402 	    nvlist_lookup_nvlist_array(nvl, "ich_rankileaves", &rir,
403 	    &chan->ich_nrankileaves) != 0 ||
404 	    chan->ich_nrankileaves > IMC_MAX_RANK_WAYS) {
405 		return (B_FALSE);
406 	}
407 
408 	for (uint_t i = 0; i < chan->ich_ndimms; i++) {
409 		imc_dimm_t *d = &chan->ich_dimms[i];
410 
411 		if (nvlist_lookup_uint32(dimms[i], "idimm_valid",
412 		    &d->idimm_valid) != 0 ||
413 		    nvlist_lookup_boolean_value(dimms[i], "idimm_present",
414 		    &d->idimm_present) != 0) {
415 			return (B_FALSE);
416 		}
417 
418 		if (!d->idimm_present)
419 			continue;
420 
421 		if (nvlist_lookup_uint8(dimms[i], "idimm_nbanks",
422 		    &d->idimm_nbanks) != 0 ||
423 		    nvlist_lookup_uint8(dimms[i], "idimm_nranks",
424 		    &d->idimm_nranks) != 0 ||
425 		    nvlist_lookup_uint8(dimms[i], "idimm_width",
426 		    &d->idimm_width) != 0 ||
427 		    nvlist_lookup_uint8(dimms[i], "idimm_density",
428 		    &d->idimm_density) != 0 ||
429 		    nvlist_lookup_uint8(dimms[i], "idimm_nrows",
430 		    &d->idimm_nrows) != 0 ||
431 		    nvlist_lookup_uint8(dimms[i], "idimm_ncolumns",
432 		    &d->idimm_ncolumns) != 0 ||
433 		    nvlist_lookup_uint64(dimms[i], "idimm_size",
434 		    &d->idimm_size) != 0) {
435 			return (B_FALSE);
436 		}
437 	}
438 
439 	bcopy(tadoff, chan->ich_tad_offsets, chan->ich_ntad_offsets *
440 	    sizeof (uint64_t));
441 
442 	for (uint_t i = 0; i < chan->ich_nrankileaves; i++) {
443 		nvlist_t **ileaves;
444 		imc_rank_ileave_t *r = &chan->ich_rankileaves[i];
445 
446 		if (nvlist_lookup_boolean_value(rir[i], "irle_enabled",
447 		    &r->irle_enabled) != 0 ||
448 		    nvlist_lookup_uint8(rir[i], "irle_nways",
449 		    &r->irle_nways) != 0 ||
450 		    nvlist_lookup_uint8(rir[i], "irle_nwaysbits",
451 		    &r->irle_nwaysbits) != 0 ||
452 		    nvlist_lookup_uint64(rir[i], "irle_limit",
453 		    &r->irle_limit) != 0 ||
454 		    nvlist_lookup_nvlist_array(rir[i], "irle_entries",
455 		    &ileaves, &r->irle_nentries) != 0 ||
456 		    r->irle_nentries > IMC_MAX_RANK_INTERLEAVES) {
457 			return (B_FALSE);
458 		}
459 
460 		for (uint_t j = 0; j < r->irle_nentries; j++) {
461 			imc_rank_ileave_entry_t *ril = &r->irle_entries[j];
462 
463 			if (nvlist_lookup_uint8(ileaves[j], "irle_target",
464 			    &ril->irle_target) != 0 ||
465 			    nvlist_lookup_uint64(ileaves[j], "irle_offset",
466 			    &ril->irle_offset) != 0) {
467 				return (B_FALSE);
468 			}
469 		}
470 	}
471 
472 	return (B_TRUE);
473 }
474 
475 static boolean_t
476 imc_restore_mc(nvlist_t *nvl, imc_mc_t *mc)
477 {
478 	nvlist_t **channels;
479 
480 	if (nvlist_lookup_boolean_value(nvl, "icn_ecc", &mc->icn_ecc) != 0 ||
481 	    nvlist_lookup_boolean_value(nvl, "icn_lockstep",
482 	    &mc->icn_lockstep) != 0 ||
483 	    nvlist_lookup_boolean_value(nvl, "icn_closed",
484 	    &mc->icn_closed) != 0 ||
485 	    nvlist_lookup_uint32(nvl, "icn_dimm_type",
486 	    &mc->icn_dimm_type) != 0 ||
487 	    nvlist_lookup_nvlist_array(nvl, "icn_channels", &channels,
488 	    &mc->icn_nchannels) != 0 || mc->icn_nchannels > IMC_MAX_CHANPERMC) {
489 		return (B_FALSE);
490 	}
491 
492 	for (uint_t i = 0; i < mc->icn_nchannels; i++) {
493 		if (!imc_restore_channel(channels[i], &mc->icn_channels[i])) {
494 			return (B_FALSE);
495 		}
496 	}
497 
498 	return (B_TRUE);
499 }
500 
501 static boolean_t
502 imc_restore_socket(nvlist_t *nvl, imc_socket_t *sock)
503 {
504 	uint_t i;
505 	nvlist_t *sad, **tads, **imcs;
506 
507 	if (nvlist_lookup_nvlist(nvl, "isock_sad", &sad) != 0 ||
508 	    nvlist_lookup_nvlist_array(nvl, "isock_tad", &tads,
509 	    &sock->isock_ntad) != 0 ||
510 	    nvlist_lookup_uint32(nvl, "isock_nodeid",
511 	    &sock->isock_nodeid) != 0 ||
512 	    nvlist_lookup_nvlist_array(nvl, "isock_imcs", &imcs,
513 	    &sock->isock_nimc) != 0 ||
514 	    sock->isock_ntad > IMC_MAX_TAD ||
515 	    sock->isock_nimc > IMC_MAX_IMCPERSOCK) {
516 		return (B_FALSE);
517 	}
518 
519 	if (!imc_restore_sad(sad, &sock->isock_sad)) {
520 		return (B_FALSE);
521 	}
522 
523 	for (i = 0; i < sock->isock_ntad; i++) {
524 		if (!imc_restore_tad(tads[i], &sock->isock_tad[i])) {
525 			return (B_FALSE);
526 		}
527 	}
528 
529 	for (i = 0; i < sock->isock_nimc; i++) {
530 		if (!imc_restore_mc(imcs[i], &sock->isock_imcs[i])) {
531 			return (B_FALSE);
532 		}
533 	}
534 
535 	return (B_TRUE);
536 }
537 
538 boolean_t
539 imc_restore_decoder(nvlist_t *nvl, imc_t *imc)
540 {
541 	uint_t i;
542 	uint32_t vers;
543 	nvlist_t *invl, **socks;
544 	char *driver;
545 
546 	bzero(imc, sizeof (imc_t));
547 
548 	if (nvlist_lookup_uint32(nvl, "mc_dump_version", &vers) != 0 ||
549 	    vers != 0 ||
550 	    nvlist_lookup_string(nvl, "mc_dump_driver", &driver) != 0 ||
551 	    strcmp(driver, "imc") != 0 ||
552 	    nvlist_lookup_nvlist(nvl, "imc", &invl) != 0) {
553 		return (B_FALSE);
554 	}
555 
556 	if (nvlist_lookup_uint32(invl, "imc_gen", &imc->imc_gen) != 0 ||
557 	    nvlist_lookup_nvlist_array(invl, "imc_sockets", &socks,
558 	    &imc->imc_nsockets) != 0 ||
559 	    imc->imc_nsockets > IMC_MAX_SOCKETS) {
560 		return (B_FALSE);
561 	}
562 
563 	for (i = 0; i < imc->imc_nsockets; i++) {
564 		if (!imc_restore_socket(socks[i], &imc->imc_sockets[i]))
565 			return (B_FALSE);
566 	}
567 
568 	return (B_TRUE);
569 }
570