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 *
imc_dump_sad(imc_sad_t * sad)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 *
imc_dump_tad(imc_tad_t * tad)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 *
imc_dump_channel(imc_channel_t * chan)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 *
imc_dump_mc(imc_mc_t * mc)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 *
imc_dump_socket(imc_socket_t * sock)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 *
imc_dump_decoder(imc_t * imc)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
imc_restore_sad(nvlist_t * nvl,imc_sad_t * sad)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
imc_restore_tad(nvlist_t * nvl,imc_tad_t * tad)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
imc_restore_channel(nvlist_t * nvl,imc_channel_t * chan)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
imc_restore_mc(nvlist_t * nvl,imc_mc_t * mc)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
imc_restore_socket(nvlist_t * nvl,imc_socket_t * sock)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
imc_restore_decoder(nvlist_t * nvl,imc_t * imc)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