xref: /illumos-gate/usr/src/cmd/fm/modules/common/cpumem-retire/cma_main.c (revision 334edc4840d12dfd25a5559468cdd15a375cd111)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <cma.h>
30 
31 #include <strings.h>
32 #include <errno.h>
33 #include <time.h>
34 #include <fm/fmd_api.h>
35 #include <sys/fm/protocol.h>
36 #include <sys/systeminfo.h>
37 #include <sys/utsname.h>
38 
39 #ifdef sun4v
40 #include <sys/fm/ldom.h>
41 
42 static fmd_hdl_t *init_hdl;
43 ldom_hdl_t *cma_lhp;
44 #endif
45 
46 extern const char *fmd_fmri_get_platform();
47 
48 cma_t cma;
49 
50 cma_stats_t cma_stats = {
51 	{ "cpu_flts", FMD_TYPE_UINT64, "cpu faults resolved" },
52 	{ "cpu_repairs", FMD_TYPE_UINT64, "cpu faults repaired" },
53 	{ "cpu_fails", FMD_TYPE_UINT64, "cpu faults unresolveable" },
54 	{ "cpu_blfails", FMD_TYPE_UINT64, "failed cpu blacklists" },
55 	{ "cpu_supp", FMD_TYPE_UINT64, "cpu offlines suppressed" },
56 	{ "cpu_blsupp", FMD_TYPE_UINT64, "cpu blacklists suppressed" },
57 	{ "page_flts", FMD_TYPE_UINT64, "page faults resolved" },
58 	{ "page_repairs", FMD_TYPE_UINT64, "page faults repaired" },
59 	{ "page_fails", FMD_TYPE_UINT64, "page faults unresolveable" },
60 	{ "page_supp", FMD_TYPE_UINT64, "page retires suppressed" },
61 	{ "page_nonent", FMD_TYPE_UINT64, "retires for non-existent fmris" },
62 	{ "page_retmax", FMD_TYPE_UINT64, "hit max retries for page retire" },
63 	{ "bad_flts", FMD_TYPE_UINT64, "invalid fault events received" },
64 	{ "nop_flts", FMD_TYPE_UINT64, "inapplicable fault events received" },
65 	{ "auto_flts", FMD_TYPE_UINT64, "auto-close faults received" }
66 };
67 
68 typedef struct cma_subscriber {
69 	const char *subr_class;
70 	const char *subr_sname;
71 	uint_t subr_svers;
72 	int (*subr_func)(fmd_hdl_t *, nvlist_t *, nvlist_t *, const char *,
73 	    boolean_t);
74 } cma_subscriber_t;
75 
76 static const cma_subscriber_t cma_subrs[] = {
77 #if defined(sun4v)
78 	{ "fault.memory.page", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION,
79 	    cma_page_retire },
80 	{ "fault.memory.dimm", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION,
81 	    NULL },
82 	{ "fault.memory.dimm_sb", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION,
83 	    NULL },
84 	{ "fault.memory.dimm_ck", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION,
85 	    NULL },
86 	{ "fault.memory.dimm_ue", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION,
87 	    NULL },
88 	{ "fault.memory.bank", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION,
89 	    NULL },
90 	{ "fault.memory.datapath", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION,
91 	    NULL },
92 	{ "fault.memory.link-c", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION,
93 	    NULL },
94 	{ "fault.memory.link-u", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION,
95 	    NULL },
96 	{ "fault.memory.link-f", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION,
97 	    NULL },
98 
99 	/*
100 	 * The following ultraSPARC-T1/T2 faults do NOT retire a cpu thread,
101 	 * and therefore must be intercepted before
102 	 * the default "fault.cpu.*" dispatch to cma_cpu_retire.
103 	 */
104 	{ "fault.cpu.*.l2cachedata", FM_FMRI_SCHEME_CPU,
105 	    FM_CPU_SCHEME_VERSION, NULL },
106 	{ "fault.cpu.*.l2cachetag", FM_FMRI_SCHEME_CPU,
107 	    FM_CPU_SCHEME_VERSION, NULL },
108 	{ "fault.cpu.*.l2cachectl", FM_FMRI_SCHEME_CPU,
109 	    FM_CPU_SCHEME_VERSION, NULL },
110 	{ "fault.cpu.*.l2data-c", FM_FMRI_SCHEME_CPU,
111 	    FM_CPU_SCHEME_VERSION, NULL },
112 	{ "fault.cpu.*.l2data-u", FM_FMRI_SCHEME_CPU,
113 	    FM_CPU_SCHEME_VERSION, NULL },
114 	{ "fault.cpu.*.mau", FM_FMRI_SCHEME_CPU,
115 	    FM_CPU_SCHEME_VERSION, NULL },
116 	{ "fault.cpu.*.lfu-u", FM_FMRI_SCHEME_CPU,
117 	    FM_CPU_SCHEME_VERSION, NULL },
118 	{ "fault.cpu.*.lfu-f", FM_FMRI_SCHEME_CPU,
119 	    FM_CPU_SCHEME_VERSION, NULL },
120 	{ "fault.cpu.*.lfu-p", FM_FMRI_SCHEME_CPU,
121 	    FM_CPU_SCHEME_VERSION, NULL },
122 	{ "fault.cpu.*", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION,
123 	    cma_cpu_retire },
124 #elif defined(opl)
125 	{ "fault.memory.page", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION,
126 	    cma_page_retire },
127 	{ "fault.memory.dimm", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION,
128 	    NULL },
129 	{ "fault.memory.bank", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION,
130 	    NULL },
131 	{ "fault.cpu.SPARC64-VI.*", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION,
132 	    cma_cpu_retire },
133 	{ "fault.cpu.SPARC64-VII.*", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION,
134 	    cma_cpu_retire },
135 	{ "fault.chassis.SPARC-Enterprise.cpu.SPARC64-VI.core.se",
136 		FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, cma_cpu_hc_retire },
137 	{ "fault.chassis.SPARC-Enterprise.cpu.SPARC64-VI.core.se-offlinereq",
138 		FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, cma_cpu_hc_retire },
139 	{ "fault.chassis.SPARC-Enterprise.cpu.SPARC64-VI.core.ce",
140 		FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, cma_cpu_hc_retire },
141 	{ "fault.chassis.SPARC-Enterprise.cpu.SPARC64-VI.core.ce-offlinereq",
142 		FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, cma_cpu_hc_retire },
143 	{ "fault.chassis.SPARC-Enterprise.cpu.SPARC64-VII.core.se",
144 		FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, cma_cpu_hc_retire },
145 	{ "fault.chassis.SPARC-Enterprise.cpu.SPARC64-VII.core.se-offlinereq",
146 		FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, cma_cpu_hc_retire },
147 	{ "fault.chassis.SPARC-Enterprise.cpu.SPARC64-VII.core.ce",
148 		FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, cma_cpu_hc_retire },
149 	{ "fault.chassis.SPARC-Enterprise.cpu.SPARC64-VII.core.ce-offlinereq",
150 		FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, cma_cpu_hc_retire },
151 #else /* Generic */
152 	{ "fault.memory.page", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION,
153 	    cma_page_retire },
154 	{ "fault.memory.page_sb", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION,
155 	    cma_page_retire },
156 	{ "fault.memory.page_ck", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION,
157 	    cma_page_retire },
158 	{ "fault.memory.page_ue", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION,
159 	    cma_page_retire },
160 	{ "fault.memory.generic-x86.page_ce", FM_FMRI_SCHEME_MEM,
161 	    FM_MEM_SCHEME_VERSION, cma_page_retire },
162 	{ "fault.memory.generic-x86.page_ue", FM_FMRI_SCHEME_MEM,
163 	    FM_MEM_SCHEME_VERSION, cma_page_retire },
164 	{ "fault.memory.intel.page_ce", FM_FMRI_SCHEME_MEM,
165 	    FM_MEM_SCHEME_VERSION, cma_page_retire },
166 	{ "fault.memory.intel.page_ue", FM_FMRI_SCHEME_MEM,
167 	    FM_MEM_SCHEME_VERSION, cma_page_retire },
168 	{ "fault.memory.dimm", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION,
169 	    NULL },
170 	{ "fault.memory.dimm_sb", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION,
171 	    NULL },
172 	{ "fault.memory.dimm_ck", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION,
173 	    NULL },
174 	{ "fault.memory.dimm_ue", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION,
175 	    NULL },
176 	{ "fault.memory.generic-x86.dimm_ce", FM_FMRI_SCHEME_MEM,
177 	    FM_MEM_SCHEME_VERSION, NULL },
178 	{ "fault.memory.generic-x86.dimm_ue", FM_FMRI_SCHEME_MEM,
179 	    FM_MEM_SCHEME_VERSION, NULL },
180 	{ "fault.memory.intel.dimm_ce", FM_FMRI_SCHEME_MEM,
181 	    FM_MEM_SCHEME_VERSION, NULL },
182 	{ "fault.memory.intel.dimm_ue", FM_FMRI_SCHEME_MEM,
183 	    FM_MEM_SCHEME_VERSION, NULL },
184 	{ "fault.memory.intel.fbd.*", FM_FMRI_SCHEME_HC,
185 	    FM_HC_SCHEME_VERSION, NULL },
186 	{ "fault.memory.dimm_testfail", FM_FMRI_SCHEME_MEM,
187 	    FM_MEM_SCHEME_VERSION, NULL },
188 	{ "fault.memory.bank", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION,
189 	    NULL },
190 	{ "fault.memory.datapath", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION,
191 	    NULL },
192 
193 	/*
194 	 * The following faults do NOT retire a cpu thread,
195 	 * and therefore must be intercepted before
196 	 * the default "fault.cpu.*" dispatch to cma_cpu_retire.
197 	 */
198 	{ "fault.cpu.ultraSPARC-T1.freg", FM_FMRI_SCHEME_CPU,
199 	    FM_CPU_SCHEME_VERSION, NULL },
200 	{ "fault.cpu.ultraSPARC-T1.l2cachedata", FM_FMRI_SCHEME_CPU,
201 	    FM_CPU_SCHEME_VERSION, NULL },
202 	{ "fault.cpu.ultraSPARC-T1.l2cachetag", FM_FMRI_SCHEME_CPU,
203 	    FM_CPU_SCHEME_VERSION, NULL },
204 	{ "fault.cpu.ultraSPARC-T1.l2cachectl", FM_FMRI_SCHEME_CPU,
205 	    FM_CPU_SCHEME_VERSION, NULL },
206 	{ "fault.cpu.ultraSPARC-T1.mau", FM_FMRI_SCHEME_CPU,
207 	    FM_CPU_SCHEME_VERSION, NULL },
208 	{ "fault.cpu.amd.dramchannel", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION,
209 	    NULL },
210 	{ "fault.cpu.generic-x86.bus_interconnect_memory", FM_FMRI_SCHEME_CPU,
211 	    FM_CPU_SCHEME_VERSION, NULL },
212 	{ "fault.cpu.generic-x86.bus_interconnect_io", FM_FMRI_SCHEME_CPU,
213 	    FM_CPU_SCHEME_VERSION, NULL },
214 	{ "fault.cpu.generic-x86.bus_interconnect", FM_FMRI_SCHEME_CPU,
215 	    FM_CPU_SCHEME_VERSION, NULL },
216 	{ "fault.cpu.intel.bus_interconnect_memory", FM_FMRI_SCHEME_CPU,
217 	    FM_CPU_SCHEME_VERSION, NULL },
218 	{ "fault.cpu.intel.bus_interconnect_io", FM_FMRI_SCHEME_CPU,
219 	    FM_CPU_SCHEME_VERSION, NULL },
220 	{ "fault.cpu.intel.bus_interconnect", FM_FMRI_SCHEME_CPU,
221 	    FM_CPU_SCHEME_VERSION, NULL },
222 	{ "fault.cpu.intel.nb.*", FM_FMRI_SCHEME_HC,
223 	    FM_HC_SCHEME_VERSION, NULL },
224 	{ "fault.cpu.intel.dma", FM_FMRI_SCHEME_HC,
225 	    FM_HC_SCHEME_VERSION, NULL },
226 	{ "fault.cpu.intel.dma", FM_FMRI_SCHEME_CPU,
227 	    FM_CPU_SCHEME_VERSION, NULL },
228 	/*
229 	 * Default "fault.cpu.*" for "mem" scheme ASRU dispatch.
230 	 */
231 	{ "fault.cpu.*", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION,
232 	    cma_cpu_retire },
233 #endif
234 	{ NULL, NULL, 0, NULL }
235 };
236 
237 static const cma_subscriber_t *
238 nvl2subr(fmd_hdl_t *hdl, nvlist_t *nvl, nvlist_t **asrup)
239 {
240 	const cma_subscriber_t *sp;
241 	nvlist_t *asru;
242 	char *scheme;
243 	uint8_t version;
244 	char *fltclass = "(unknown)";
245 
246 	if (nvlist_lookup_nvlist(nvl, FM_FAULT_ASRU, &asru) != 0 ||
247 	    nvlist_lookup_string(asru, FM_FMRI_SCHEME, &scheme) != 0 ||
248 	    nvlist_lookup_uint8(asru, FM_VERSION, &version) != 0) {
249 		cma_stats.bad_flts.fmds_value.ui64++;
250 		return (NULL);
251 	}
252 
253 	for (sp = cma_subrs; sp->subr_class != NULL; sp++) {
254 		if (fmd_nvl_class_match(hdl, nvl, sp->subr_class) &&
255 		    strcmp(scheme, sp->subr_sname) == 0 &&
256 		    version <= sp->subr_svers) {
257 			*asrup = asru;
258 			return (sp);
259 		}
260 	}
261 
262 	(void) nvlist_lookup_string(nvl, FM_CLASS, &fltclass);
263 	fmd_hdl_error(hdl, "No handling disposition for %s with asru in "
264 	    "scheme \"%s\"\n", fltclass, scheme);
265 	cma_stats.nop_flts.fmds_value.ui64++;
266 	return (NULL);
267 }
268 
269 static void
270 cma_recv_list(fmd_hdl_t *hdl, nvlist_t *nvl, boolean_t repair)
271 {
272 	char *uuid = NULL;
273 	nvlist_t **nva;
274 	uint_t nvc = 0;
275 	uint_t keepopen;
276 	int err = 0;
277 
278 	err |= nvlist_lookup_string(nvl, FM_SUSPECT_UUID, &uuid);
279 	err |= nvlist_lookup_nvlist_array(nvl, FM_SUSPECT_FAULT_LIST,
280 	    &nva, &nvc);
281 	if (err != 0) {
282 		cma_stats.bad_flts.fmds_value.ui64++;
283 		return;
284 	}
285 
286 	keepopen = nvc;
287 	while (nvc-- != 0 && (repair || !fmd_case_uuclosed(hdl, uuid))) {
288 		nvlist_t *nvl = *nva++;
289 		const cma_subscriber_t *subr;
290 		nvlist_t *asru;
291 
292 		if ((subr = nvl2subr(hdl, nvl, &asru)) == NULL)
293 			continue;
294 
295 		/*
296 		 * A handler returns CMA_RA_SUCCESS to indicate that
297 		 * from this suspects  point-of-view the case may be
298 		 * closed, CMA_RA_FAILURE otherwise.
299 		 * A handler must not close the case itself.
300 		 */
301 		if (subr->subr_func != NULL) {
302 			err = subr->subr_func(hdl, nvl, asru, uuid, repair);
303 
304 			if (err == CMA_RA_SUCCESS)
305 				keepopen--;
306 		}
307 	}
308 
309 	if (!keepopen && !repair)
310 		fmd_case_uuclose(hdl, uuid);
311 }
312 
313 static void
314 cma_recv_one(fmd_hdl_t *hdl, nvlist_t *nvl)
315 {
316 	const cma_subscriber_t *subr;
317 	nvlist_t *asru;
318 
319 	if ((subr = nvl2subr(hdl, nvl, &asru)) == NULL)
320 		return;
321 
322 	if (subr->subr_func != NULL)
323 		(void) subr->subr_func(hdl, nvl, asru, NULL, 0);
324 }
325 
326 /*ARGSUSED*/
327 static void
328 cma_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
329 {
330 	boolean_t repair = B_FALSE;
331 
332 	fmd_hdl_debug(hdl, "received %s\n", class);
333 
334 	if (strcmp(class, FM_LIST_SUSPECT_CLASS) == 0 ||
335 	    (repair = (strcmp(class, FM_LIST_REPAIRED_CLASS) == 0)))
336 		cma_recv_list(hdl, nvl, repair);
337 	else
338 		cma_recv_one(hdl, nvl);
339 }
340 
341 /*ARGSUSED*/
342 static void
343 cma_timeout(fmd_hdl_t *hdl, id_t id, void *arg)
344 {
345 	if (id == cma.cma_page_timerid)
346 		cma_page_retry(hdl);
347 #ifdef sun4v
348 	/*
349 	 * cpu offline/online needs to be retried on sun4v because
350 	 * ldom request can be asynchronous.
351 	 */
352 	else if (id == cma.cma_cpu_timerid)
353 		cma_cpu_retry(hdl);
354 #endif
355 }
356 
357 #ifdef sun4v
358 static void *
359 cma_init_alloc(size_t size)
360 {
361 	return (fmd_hdl_alloc(init_hdl, size, FMD_SLEEP));
362 }
363 
364 static void
365 cma_init_free(void *addr, size_t size)
366 {
367 	fmd_hdl_free(init_hdl, addr, size);
368 }
369 #endif
370 
371 static const fmd_hdl_ops_t fmd_ops = {
372 	cma_recv,	/* fmdo_recv */
373 	cma_timeout,	/* fmdo_timeout */
374 	NULL,		/* fmdo_close */
375 	NULL,		/* fmdo_stats */
376 	NULL,		/* fmdo_gc */
377 };
378 
379 static const fmd_prop_t fmd_props[] = {
380 	{ "cpu_tries", FMD_TYPE_UINT32, "10" },
381 	{ "cpu_delay", FMD_TYPE_TIME, "1sec" },
382 #ifdef sun4v
383 	{ "cpu_ret_mindelay", FMD_TYPE_TIME, "5sec" },
384 	{ "cpu_ret_maxdelay", FMD_TYPE_TIME, "5min" },
385 #endif /* sun4v */
386 	{ "cpu_offline_enable", FMD_TYPE_BOOL, "true" },
387 	{ "cpu_online_enable", FMD_TYPE_BOOL, "true" },
388 	{ "cpu_forced_offline", FMD_TYPE_BOOL, "true" },
389 #ifdef opl
390 	{ "cpu_blacklist_enable", FMD_TYPE_BOOL, "false" },
391 	{ "cpu_unblacklist_enable", FMD_TYPE_BOOL, "false" },
392 #else
393 	{ "cpu_blacklist_enable", FMD_TYPE_BOOL, "true" },
394 	{ "cpu_unblacklist_enable", FMD_TYPE_BOOL, "true" },
395 #endif /* opl */
396 	{ "page_ret_mindelay", FMD_TYPE_TIME, "1sec" },
397 	{ "page_ret_maxdelay", FMD_TYPE_TIME, "5min" },
398 	{ "page_retire_enable", FMD_TYPE_BOOL, "true" },
399 	{ "page_unretire_enable", FMD_TYPE_BOOL, "true" },
400 #ifdef i386
401 	/*
402 	 * On i386, leaving cases open while we retry the
403 	 * retire can cause the eft module to use large amounts
404 	 * of memory.  Until eft is fixed, we set a maximum number
405 	 * of retries on page retires, after which the case will
406 	 * be closed.
407 	 */
408 	{ "page_retire_maxretries", FMD_TYPE_UINT32, "5" },
409 #else
410 	{ "page_retire_maxretries", FMD_TYPE_UINT32, "0" },
411 #endif	/* i386 */
412 	{ NULL, 0, NULL }
413 };
414 
415 static const fmd_hdl_info_t fmd_info = {
416 	"CPU/Memory Retire Agent", CMA_VERSION, &fmd_ops, fmd_props
417 };
418 
419 void
420 _fmd_init(fmd_hdl_t *hdl)
421 {
422 	hrtime_t nsec;
423 #ifdef i386
424 	/*
425 	 * Abort the cpumem-retire module if Solaris is running under the Xen
426 	 * hypervisor.
427 	 */
428 	if (strcmp(fmd_fmri_get_platform(), "i86xpv") == 0)
429 		return;
430 #endif
431 
432 	if (fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info) != 0)
433 		return; /* invalid data in configuration file */
434 
435 	fmd_hdl_subscribe(hdl, "list.repaired");
436 	fmd_hdl_subscribe(hdl, "fault.cpu.*");
437 	fmd_hdl_subscribe(hdl, "fault.memory.*");
438 #ifdef opl
439 	fmd_hdl_subscribe(hdl, "fault.chassis.SPARC-Enterprise.cpu.*");
440 #endif
441 
442 	(void) fmd_stat_create(hdl, FMD_STAT_NOALLOC, sizeof (cma_stats) /
443 	    sizeof (fmd_stat_t), (fmd_stat_t *)&cma_stats);
444 
445 	cma.cma_cpu_tries = fmd_prop_get_int32(hdl, "cpu_tries");
446 
447 	nsec = fmd_prop_get_int64(hdl, "cpu_delay");
448 	cma.cma_cpu_delay.tv_sec = nsec / NANOSEC;
449 	cma.cma_cpu_delay.tv_nsec = nsec % NANOSEC;
450 
451 	cma.cma_page_mindelay = fmd_prop_get_int64(hdl, "page_ret_mindelay");
452 	cma.cma_page_maxdelay = fmd_prop_get_int64(hdl, "page_ret_maxdelay");
453 
454 #ifdef sun4v
455 	cma.cma_cpu_mindelay = fmd_prop_get_int64(hdl, "cpu_ret_mindelay");
456 	cma.cma_cpu_maxdelay = fmd_prop_get_int64(hdl, "cpu_ret_maxdelay");
457 #endif
458 
459 	cma.cma_cpu_dooffline = fmd_prop_get_int32(hdl, "cpu_offline_enable");
460 	cma.cma_cpu_forcedoffline = fmd_prop_get_int32(hdl,
461 	    "cpu_forced_offline");
462 	cma.cma_cpu_doonline = fmd_prop_get_int32(hdl, "cpu_online_enable");
463 	cma.cma_cpu_doblacklist = fmd_prop_get_int32(hdl,
464 	    "cpu_blacklist_enable");
465 	cma.cma_cpu_dounblacklist = fmd_prop_get_int32(hdl,
466 	    "cpu_unblacklist_enable");
467 	cma.cma_page_doretire = fmd_prop_get_int32(hdl, "page_retire_enable");
468 	cma.cma_page_dounretire = fmd_prop_get_int32(hdl,
469 	    "page_unretire_enable");
470 	cma.cma_page_maxretries =
471 	    fmd_prop_get_int32(hdl, "page_retire_maxretries");
472 
473 	if (cma.cma_page_maxdelay < cma.cma_page_mindelay)
474 		fmd_hdl_abort(hdl, "page retirement delays conflict\n");
475 
476 #ifdef sun4v
477 	init_hdl = hdl;
478 	cma_lhp = ldom_init(cma_init_alloc, cma_init_free);
479 #endif
480 }
481 
482 void
483 _fmd_fini(fmd_hdl_t *hdl)
484 {
485 #ifdef sun4v
486 	ldom_fini(cma_lhp);
487 	cma_cpu_fini(hdl);
488 #endif
489 	cma_page_fini(hdl);
490 }
491