xref: /illumos-gate/usr/src/cmd/picl/plugins/common/memcfg/piclmemcfg_comm.c (revision 503609a9497e27f206d815a06ce90a747d2ce573)
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  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * This plugin creates memory configuration nodes and properties in the
28  * PICL tree for Cheetah platforms.
29  *
30  * Subtree of memory-controller in the physical aspect.
31  * memory-controller --- memory-module-group --- memory-module
32  *
33  * Subtree of memory in the logical aspect.
34  * memory --- memory-segment --- memory-bank
35  * Add property _memory-module-group_ at memory-segment referring to the
36  * memory-module-group if InterleaveFactor is one, or at memory-bank
37  * if InterleaveFactor is greater than one.
38  *
39  * Undo strategy:
40  * Create all nodes and properties, or none if it fails in physical and
41  * logical memory tree respectively. It keeps on creating logic
42  * memory tree although it falis on physical logic tree, but no link to
43  * memory module group.
44  *
45  * NOTE:
46  * It depends on PICL devtree plugin and currently
47  * there is no refresh routine for DR.
48  */
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <unistd.h>
53 #include <alloca.h>
54 #include <syslog.h>
55 #include <string.h>
56 #include <libintl.h>
57 #include <picl.h>
58 #include <picltree.h>
59 #include <fcntl.h>
60 #include <errno.h>
61 #include <sys/types.h>
62 #include <dirent.h>
63 #include <sys/stat.h>
64 #include <mc.h>
65 #include <libnvpair.h>
66 #include <limits.h>
67 #include "piclmemcfg.h"
68 
69 /*
70  * Plugin registration entry points
71  */
72 static	void	piclmemcfg_register(void);
73 static	void	piclmemcfg_init(void);
74 static	void	piclmemcfg_fini(void);
75 
76 /*
77  * PICL event handler
78  */
79 static void  piclmemcfg_evhandler(const char *ename, const void *earg,
80 		size_t size, void *cookie);
81 
82 #pragma	init(piclmemcfg_register)
83 
84 static picld_plugin_reg_t  my_reg_info = {
85 	PICLD_PLUGIN_VERSION_1,
86 	PICLD_PLUGIN_NON_CRITICAL,
87 	"SUNW_piclmemcfg",
88 	piclmemcfg_init,
89 	piclmemcfg_fini
90 };
91 
92 /*
93  * Log message texts
94  */
95 #define	EM_INIT_FAILED		gettext("SUNW_piclmemcfg init failed!\n")
96 #define	EM_PHYSIC_MEM_TREE_FAILED	\
97 	gettext("SUNW_piclmemcfg physical memory tree failed!\n")
98 #define	EM_LOGIC_MEM_TREE_FAILED		\
99 	gettext("SUNW_piclmemcfg logical memory tree failed!\n")
100 
101 #define	EM_INIT_MC_FAILED	\
102 	gettext("SUNW_piclmemcfg init mc failed!\n")
103 
104 /*
105  * Global variables for Memory Controllers
106  */
107 #define	MC_DIR	"/dev/mc/"
108 
109 static int	nsegments;	/* The number of memory segments */
110 static int	nbanks;		/* The max. number of banks per segment */
111 static int	ndevgrps;	/* The max. number of device groups per mc */
112 static int	ndevs;		/* The max. number of devices per dev group */
113 static int	transfersize;
114 
115 static picl_nodehdl_t	*msegh_info;
116 
117 /*
118  * Memory-module-group node handle list, a singal linking list, where
119  * memory module group id is the key to match.
120  *
121  * It is allocated and added to the head of list, and freed as well.
122  * The mmgh field is cleared if failure is encountered in the physical
123  * memory tree.
124  *
125  * This list is accessed in the logical memory tree, and allocated memory
126  * is released at the end of plugin.
127  */
128 typedef struct memmodgrp_info {
129 	int			mmgid;
130 	struct memmodgrp_info	*next;
131 	picl_nodehdl_t		mmgh;
132 	picl_nodehdl_t		mch;
133 } mmodgrp_info_t;
134 
135 static	mmodgrp_info_t		*head2mmodgrp;
136 
137 /*
138  * Release the allocated memory of mmodgrp_info
139  */
140 static void
141 free_allocated_mem(void)
142 {
143 	mmodgrp_info_t		*mmghdl, *currmmghdl;
144 
145 	mmghdl = head2mmodgrp;
146 
147 	while (mmghdl) {
148 		currmmghdl = mmghdl;
149 		mmghdl = mmghdl->next;
150 		free(currmmghdl);
151 	}
152 
153 	head2mmodgrp = NULL;
154 }
155 
156 /*
157  * Delete nodes whose MC is gone at mmodgrp_info
158  */
159 static void
160 del_plugout_mmodgrp(picl_nodehdl_t mch)
161 {
162 	mmodgrp_info_t		*mmghdl, *prevmmghdl, *nextmmghdl;
163 
164 	for (mmghdl = head2mmodgrp, prevmmghdl = NULL; mmghdl != NULL;
165 	    mmghdl = nextmmghdl) {
166 		nextmmghdl = mmghdl->next;
167 		if (mmghdl->mch == mch) {
168 			if (prevmmghdl == NULL)
169 				/* we are at the head */
170 				head2mmodgrp = nextmmghdl;
171 			else
172 				prevmmghdl->next = nextmmghdl;
173 			free(mmghdl);
174 		} else
175 			prevmmghdl = mmghdl;
176 	}
177 }
178 
179 /*
180  * Search the memory module group node in the mmodgrp_info by global id.
181  * The matched memory-module-group node handle will be assigned to
182  * the second parameter.
183  */
184 static int
185 find_mem_mod_grp_hdl(int id, picl_nodehdl_t *mmodgrph)
186 {
187 	mmodgrp_info_t		*mmghdl;
188 	int			err = PICL_FAILURE;
189 
190 	mmghdl = head2mmodgrp;
191 
192 	while (mmghdl) {
193 		if ((mmghdl->mmgh) && (mmghdl->mmgid == id)) {
194 			*mmodgrph = mmghdl->mmgh;
195 			err = PICL_SUCCESS;
196 			break;
197 		}
198 		mmghdl = mmghdl->next;
199 	}
200 
201 	return (err);
202 }
203 
204 /*
205  * Delete nodes and properties created in the physical memory tree.
206  */
207 static void
208 undo_phymem_tree(void)
209 {
210 	mmodgrp_info_t		*mmghdl;
211 
212 	mmghdl = head2mmodgrp;
213 
214 	while (mmghdl) {
215 		/*
216 		 * Delete nodes and properties of memory-module-group(s)
217 		 */
218 		if (mmghdl->mmgh == NULL)
219 			continue;
220 
221 		(void) ptree_delete_node(mmghdl->mmgh);
222 		(void) ptree_destroy_node(mmghdl->mmgh);
223 
224 		/*
225 		 * Clear out the saved node handle of memory module group
226 		 * so that logic memory tree won't link to it.
227 		 */
228 		mmghdl->mch = mmghdl->mmgh = NULL;
229 		mmghdl = mmghdl->next;
230 	}
231 }
232 
233 /*
234  * Create all memory-banks under the given memory-segment.
235  */
236 static int
237 add_mem_banks(picl_nodehdl_t msegh, int fd, struct mc_segment *mcseg)
238 {
239 	int			i;
240 	int			err = PICL_SUCCESS;
241 	static picl_nodehdl_t	mmodgrph;
242 	picl_prophdl_t		bankh;
243 	ptree_propinfo_t	propinfo;
244 	struct mc_bank		mcbank;
245 	char			propname[PICL_CLASSNAMELEN_MAX];
246 
247 	/*
248 	 * Get all bank information via ioctl
249 	 */
250 	for (i = 0; i < mcseg->nbanks; i++) {
251 		mcbank.id = mcseg->bankids[i].globalid;
252 		if (ioctl(fd, MCIOC_BANK, &mcbank) == -1)
253 			return (PICL_FAILURE);
254 
255 		/*
256 		 * Create memory-bank node under memory-segment node
257 		 */
258 		err = ptree_create_and_add_node(msegh, PICL_NAME_MEMORY_BANK,
259 		    PICL_CLASS_MEMORY_BANK, &bankh);
260 		if (err != PICL_SUCCESS)
261 			break;
262 
263 		/*
264 		 * Add property, Size to memory-bank node
265 		 */
266 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
267 		    PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (mcbank.size),
268 		    PICL_PROP_SIZE, NULL, NULL);
269 		if (err != PICL_SUCCESS)
270 			break;
271 
272 		err = ptree_create_and_add_prop(bankh, &propinfo, &mcbank.size,
273 		    NULL);
274 		if (err != PICL_SUCCESS)
275 			break;
276 
277 		/*
278 		 * Add property, AddressMask to memory-bank node
279 		 */
280 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
281 		    PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (mcbank.mask),
282 		    PICL_PROP_ADDRESSMASK, NULL, NULL);
283 		if (err != PICL_SUCCESS)
284 			break;
285 
286 		err = ptree_create_and_add_prop(bankh, &propinfo, &mcbank.mask,
287 		    NULL);
288 		if (err != PICL_SUCCESS)
289 			break;
290 
291 		/*
292 		 * Add property, AddressMatch to memory-bank node
293 		 */
294 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
295 		    PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (mcbank.match),
296 		    PICL_PROP_ADDRESSMATCH, NULL, NULL);
297 		if (err != PICL_SUCCESS)
298 			break;
299 
300 		err = ptree_create_and_add_prop(bankh, &propinfo,
301 		    &mcbank.match, NULL);
302 		if (err != PICL_SUCCESS)
303 			break;
304 
305 		/*
306 		 * Add global id of bank to property, ID memory-bank node
307 		 */
308 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
309 		    PICL_PTYPE_INT, PICL_READ, sizeof (mcbank.id), PICL_PROP_ID,
310 		    NULL, NULL);
311 		if (err != PICL_SUCCESS)
312 			break;
313 
314 		err = ptree_create_and_add_prop(bankh, &propinfo, &mcbank.id,
315 		    NULL);
316 		if (err != PICL_SUCCESS)
317 			break;
318 
319 		/*
320 		 * Add property, _memory-module-group_ to memory-bank node
321 		 */
322 		if ((find_mem_mod_grp_hdl(mcbank.devgrpid.globalid,
323 		    &mmodgrph)) != PICL_SUCCESS)
324 			continue;
325 
326 		/*
327 		 * The number of memory modules > 1 means there needs
328 		 * memory module group, and then refers to it. Otherwise,
329 		 * it refers to memory module node handle instead.
330 		 */
331 		(void) strlcpy(propname, (ndevs > 1 ?
332 		    PICL_REFPROP_MEMORY_MODULE_GROUP :
333 		    PICL_REFPROP_MEMORY_MODULE), PICL_CLASSNAMELEN_MAX);
334 
335 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
336 		    PICL_PTYPE_REFERENCE, PICL_READ, sizeof (picl_nodehdl_t),
337 		    propname, NULL, NULL);
338 		if (err != PICL_SUCCESS)
339 			break;
340 
341 		err = ptree_create_and_add_prop(bankh, &propinfo, &mmodgrph,
342 		    NULL);
343 		if (err != PICL_SUCCESS)
344 			break;
345 	}
346 	return (PICL_SUCCESS);
347 }
348 
349 static void
350 undo_logical_tree(int nsegments)
351 {
352 	int	i;
353 	/*
354 	 * Undo in the logical memory tree
355 	 */
356 	for (i = 0; i < nsegments; i++) {
357 		(void) ptree_delete_node(msegh_info[i]);
358 		(void) ptree_destroy_node(msegh_info[i]);
359 	}
360 }
361 
362 /*
363  * Create logical memory tree
364  * memory --- memory-segment --- memory-bank
365  * Get information via ioctl of memory control driver
366  */
367 static int
368 create_logical_tree(picl_nodehdl_t memh, int fd)
369 {
370 	int			i;
371 	int			err = PICL_SUCCESS;
372 	picl_nodehdl_t		msegh;
373 	ptree_propinfo_t	propinfo;
374 	struct mc_memory	*mcmem;
375 	struct mc_segment	*mcseg;
376 	picl_prophdl_t		proph;
377 	uint64_t		memsize = 0;
378 
379 	/*
380 	 * allocate memory for mc_memory where nsegmentids are various
381 	 */
382 	if ((mcmem = alloca((nsegments - 1) * sizeof (mcmem->segmentids[0]) +
383 	    sizeof (*mcmem))) == NULL)
384 		return (PICL_FAILURE);
385 
386 	mcmem->nsegments = nsegments;
387 
388 	/*
389 	 * Get logical memory information
390 	 */
391 	if (ioctl(fd, MCIOC_MEM, mcmem) == -1)
392 		return (PICL_FAILURE);
393 
394 	/*
395 	 * allocate memory for mc_segment where nbanks are various
396 	 */
397 	if ((mcseg = alloca((nbanks - 1) * sizeof (mcseg->bankids[0]) +
398 	    sizeof (*mcseg))) == NULL)
399 		return (PICL_FAILURE);
400 
401 	/*
402 	 * Get all segments to create memory-segment nodes and
403 	 * add properties.
404 	 */
405 	for (i = 0; i < nsegments; i++) {
406 		mcseg->id = mcmem->segmentids[i].globalid;
407 		mcseg->nbanks = nbanks;
408 
409 		if (ioctl(fd, MCIOC_SEG, mcseg) == -1)
410 			break;
411 
412 		/*
413 		 * Create memory-segment node under memory node
414 		 */
415 		err = ptree_create_and_add_node(memh, PICL_NAME_MEMORY_SEGMENT,
416 		    PICL_CLASS_MEMORY_SEGMENT, &msegh);
417 		if (err != PICL_SUCCESS)
418 			break;
419 
420 		msegh_info[i] = msegh;
421 
422 		/*
423 		 * Add property, Size to memory-segment node
424 		 */
425 		if ((ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
426 		    PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (mcseg->size),
427 		    PICL_PROP_SIZE, NULL, NULL)) != PICL_SUCCESS)
428 		if (err != PICL_SUCCESS)
429 			break;
430 
431 		memsize += mcseg->size;
432 		err = ptree_create_and_add_prop(msegh, &propinfo, &mcseg->size,
433 		    NULL);
434 		if (err != PICL_SUCCESS)
435 			break;
436 
437 		/*
438 		 * Add property, BaseAddress to memory-segment node
439 		 */
440 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
441 		    PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (mcseg->base),
442 		    PICL_PROP_BASEADDRESS, NULL, NULL);
443 		if (err != PICL_SUCCESS)
444 			break;
445 
446 		err = ptree_create_and_add_prop(msegh, &propinfo, &mcseg->base,
447 		    NULL);
448 		if (err != PICL_SUCCESS)
449 			break;
450 
451 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
452 		    PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (mcseg->ifactor),
453 		    PICL_PROP_INTERLEAVE_FACTOR, NULL, NULL);
454 		if (err != PICL_SUCCESS)
455 			break;
456 
457 		err = ptree_create_and_add_prop(msegh, &propinfo,
458 		    &mcseg->ifactor, NULL);
459 		if (err != PICL_SUCCESS)
460 			break;
461 
462 		err = add_mem_banks(msegh, fd, mcseg);
463 		if (err != PICL_SUCCESS)
464 			break;
465 	}
466 
467 	if (err != PICL_SUCCESS) {
468 		undo_logical_tree(nsegments);
469 		return (err);
470 	}
471 
472 	err = ptree_get_prop_by_name(memh, PICL_PROP_SIZE, &proph);
473 	if (err == PICL_SUCCESS) {	/* update the value */
474 		err = ptree_update_propval(proph, &memsize, sizeof (memsize));
475 		return (err);
476 	}
477 
478 	/*
479 	 * Add the size property
480 	 */
481 	(void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
482 	    PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (memsize),
483 	    PICL_PROP_SIZE, NULL, NULL);
484 	err = ptree_create_and_add_prop(memh, &propinfo, &memsize, NULL);
485 
486 	return (err);
487 }
488 
489 /*
490  * Add memory-module nodes and properties at each enabled memory-module-group.
491  * The formula of unique id is (id of the given memory module group *
492  * max number of memory modules per memory module group) + index
493  * of memory modules in this memory module group
494  */
495 static int
496 add_mem_modules(picl_nodehdl_t mmodgrph, struct mc_devgrp *mcdevgrp)
497 {
498 	uint64_t		size;
499 	picl_nodehdl_t		dimmh;
500 	ptree_propinfo_t	propinfo;
501 	int			i;
502 	int			err = PICL_SUCCESS;
503 
504 	size = mcdevgrp->size / mcdevgrp->ndevices;
505 
506 	/*
507 	 * Get all memory-modules of the given memory-module-group
508 	 */
509 	for (i = 0; i < mcdevgrp->ndevices; i++) {
510 		/*
511 		 * Create memory-module node under memory-module-group
512 		 */
513 		err = ptree_create_and_add_node(mmodgrph,
514 		    PICL_NAME_MEMORY_MODULE, PICL_CLASS_MEMORY_MODULE, &dimmh);
515 		if (err != PICL_SUCCESS)
516 			break;
517 
518 		/*
519 		 * Add property, Size to memory-module-group node
520 		 */
521 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
522 		    PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (size),
523 		    PICL_PROP_SIZE, NULL, NULL);
524 		if (err != PICL_SUCCESS)
525 			break;
526 
527 		err = ptree_create_and_add_prop(dimmh, &propinfo, &size, NULL);
528 		if (err != PICL_SUCCESS)
529 			break;
530 
531 		/*
532 		 * Add property, ID to memory-module-group node
533 		 */
534 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
535 		    PICL_PTYPE_INT, PICL_READ, sizeof (i), PICL_PROP_ID,
536 		    NULL, NULL);
537 		if (err != PICL_SUCCESS)
538 			break;
539 
540 		err = ptree_create_and_add_prop(dimmh, &propinfo, &i,
541 		    NULL);
542 		if (err != PICL_SUCCESS)
543 			break;
544 	}
545 	return (err);
546 }
547 
548 /*
549  * Create the subtree at every enabled Memory Controller where size of
550  * memory module group is greater than zero.
551  * Get information via ioctl of memory control driver
552  */
553 static int
554 create_physical_tree(picl_nodehdl_t mch, void *args)
555 {
556 	int			i, portid;
557 	int			err = PICL_SUCCESS;
558 	mmodgrp_info_t		*mmghdl;
559 	picl_nodehdl_t		mmodgrph;
560 	ptree_propinfo_t	propinfo;
561 	struct mc_control 	*mccontrol;
562 	struct mc_devgrp 	mcdevgrp;
563 	int			fd;
564 
565 	fd = (int)args;
566 	/*
567 	 * Get portid of memory-controller as the key to get its
568 	 * configuration via ioctl.
569 	 */
570 	err = ptree_get_propval_by_name(mch, OBP_PROP_PORTID, &portid,
571 	    sizeof (portid));
572 	if (err != PICL_SUCCESS)
573 		return (err);
574 
575 	if ((mccontrol = alloca((ndevgrps - 1) *
576 	    sizeof (mccontrol->devgrpids[0]) + sizeof (*mccontrol))) == NULL)
577 		return (PICL_FAILURE);
578 
579 	mccontrol->id = portid;
580 	mccontrol->ndevgrps = ndevgrps;
581 
582 	if (ioctl(fd, MCIOC_CONTROL, mccontrol) == -1) {
583 		if (errno == EINVAL)
584 			return (PICL_WALK_CONTINUE);
585 		else
586 			return (PICL_FAILURE);
587 	}
588 
589 	/*
590 	 * If returned ndevgrps is zero, Memory Controller is disable, and
591 	 * skip it.
592 	 */
593 	if (mccontrol->ndevgrps == 0)
594 		return (PICL_WALK_CONTINUE);
595 
596 	/*
597 	 * Get all memory module groups of the given memory controller.
598 	 */
599 	for (i = 0; i < mccontrol->ndevgrps; i++) {
600 		int	mmglocalid = mccontrol->devgrpids[i].localid;
601 
602 		mcdevgrp.id = mccontrol->devgrpids[i].globalid;
603 
604 		if (ioctl(fd, MCIOC_DEVGRP, &mcdevgrp) == -1)
605 			return (PICL_FAILURE);
606 
607 		/*
608 		 * Node doesn't need to be created if size is 0, i.e.
609 		 * there is no memory dimm at slot.
610 		 */
611 		if (mcdevgrp.size == 0)
612 			continue;
613 
614 		/*
615 		 * Create memory-module-group node under memory-controller
616 		 */
617 		err = ptree_create_and_add_node(mch, PICL_NAME_MEM_MOD_GROUP,
618 		    PICL_CLASS_MEMORY_MODULE_GROUP, &mmodgrph);
619 		if (err != PICL_SUCCESS)
620 			break;
621 
622 		/*
623 		 * Allocate space for mmodgrp_info to save the information
624 		 * so that it is easier to do the undo and setup of the
625 		 * reference property in logical memory tree.
626 		 */
627 		if ((mmghdl = malloc(sizeof (*mmghdl))) == NULL)
628 			return (PICL_FAILURE);
629 
630 		/*
631 		 * Save the information and add it to the beginnong of list.
632 		 */
633 		mmghdl->mmgid = mcdevgrp.id;
634 		mmghdl->mmgh = mmodgrph;
635 		mmghdl->mch = mch;
636 		mmghdl->next = head2mmodgrp;
637 
638 		head2mmodgrp = mmghdl;
639 
640 		/*
641 		 * Add property, Size to memory-module-group node
642 		 */
643 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
644 		    PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (mcdevgrp.size),
645 		    PICL_PROP_SIZE, NULL, NULL);
646 		if (err != PICL_SUCCESS)
647 			break;
648 
649 		err = ptree_create_and_add_prop(mmodgrph, &propinfo,
650 		    &mcdevgrp.size, NULL);
651 		if (err != PICL_SUCCESS)
652 			break;
653 
654 		/*
655 		 * Add property, ID to memory-module-group node
656 		 */
657 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
658 		    PICL_PTYPE_INT, PICL_READ, sizeof (mmglocalid),
659 		    PICL_PROP_ID, NULL, NULL);
660 		if (err != PICL_SUCCESS)
661 			break;
662 
663 		err = ptree_create_and_add_prop(mmodgrph, &propinfo,
664 		    &mmglocalid, NULL);
665 		if (err != PICL_SUCCESS)
666 			break;
667 
668 		/*
669 		 * Create all memory-module nodes and properties.
670 		 */
671 		err = add_mem_modules(mmodgrph, &mcdevgrp);
672 		if (err != PICL_SUCCESS)
673 			break;
674 	}
675 
676 	if (err == PICL_SUCCESS)
677 		return (PICL_WALK_CONTINUE);
678 	return (err);
679 }
680 
681 /*
682  * Create physical memory tree
683  * memory-controller --- memory-module-group --- memory-module
684  *
685  * It searches all memory-controller nodes in the whole devtree.
686  * It returns failure if encountering error in physical tree.
687  */
688 static int
689 find_mc_create_tree(picl_nodehdl_t rooth, int fd)
690 {
691 	int		err;
692 
693 	err = ptree_walk_tree_by_class(rooth, PICL_CLASS_MEMORY_CONTROLLER,
694 	    (void *)fd, create_physical_tree);
695 	return (err);
696 }
697 
698 static int
699 init_mc(void)
700 {
701 	struct mc_memconf	mcmemconf;
702 	int			fd;
703 	DIR			*dirp;
704 	struct dirent		*retp;
705 	char			path[PATH_MAX];
706 	int 			found = 0;
707 	int			valid_entry = 0;
708 
709 	/* open the directory */
710 	if ((dirp = opendir(MC_DIR)) == NULL) {
711 		/*
712 		 * As not all platforms have mc drivers that create the
713 		 * /dev/mc directory, print a message only if there is
714 		 * an entry found on which the open failed.
715 		 */
716 		if (errno != ENOENT)
717 			syslog(LOG_ERR, EM_INIT_MC_FAILED);
718 		return (-1);
719 	}
720 
721 	/* start searching this directory */
722 	while ((retp = readdir(dirp)) != NULL) {
723 		/* skip . .. etc... */
724 		if (strcmp(retp->d_name, ".") == 0 ||
725 		    strcmp(retp->d_name, "..") == 0)
726 			continue;
727 
728 		(void) strcpy(path, MC_DIR);
729 		(void) strcat(path, retp->d_name);
730 		/* open the memory controller driver */
731 		if ((fd = open(path, O_RDONLY, 0)) != -1) {
732 			found = 1;
733 			break;
734 		}
735 		if (errno != ENOENT)
736 			valid_entry = 1;
737 	}
738 	(void) closedir(dirp);
739 
740 	if (!found) {
741 		if (valid_entry)
742 			syslog(LOG_ERR, EM_INIT_MC_FAILED);
743 		return (-1);
744 	}
745 
746 	/*
747 	 * Initialize some global variables via ioctl
748 	 */
749 	if (ioctl(fd, MCIOC_MEMCONF, &mcmemconf) == -1) {
750 		(void) close(fd);
751 		return (-1);
752 	}
753 
754 	nsegments = mcmemconf.nsegments;
755 	nbanks = mcmemconf.nbanks;
756 	ndevgrps = mcmemconf.ndevgrps;
757 	ndevs = mcmemconf.ndevs;
758 	transfersize = mcmemconf.xfer_size;
759 
760 	return (fd);
761 }
762 
763 /*
764  * executed as part of .init when the plugin is dlopen()ed
765  */
766 void
767 piclmemcfg_register(void)
768 {
769 	(void) picld_plugin_register(&my_reg_info);
770 }
771 
772 /*
773  * init entry point of the plugin
774  * Creates the PICL nodes and properties in the physical and logical aspects.
775  */
776 void
777 piclmemcfg_init(void)
778 {
779 	picl_nodehdl_t		plfh;
780 	picl_nodehdl_t		memh;
781 	ptree_propinfo_t	propinfo;
782 	int			fd, err;
783 
784 	/*
785 	 * Initialize the header pointer of mmodgrp_info list
786 	 */
787 	head2mmodgrp = NULL;
788 	msegh_info = NULL;
789 
790 	if ((fd = init_mc()) < 0)
791 		return;
792 
793 	/*
794 	 * allocate memory to save memory-segment node handles. Thus,
795 	 * it is easier to delete them if it fails.
796 	 */
797 	if ((msegh_info = malloc(nsegments * sizeof (picl_nodehdl_t))) ==
798 	    NULL) {
799 		syslog(LOG_ERR, EM_INIT_FAILED);
800 		(void) close(fd);
801 		return;
802 	}
803 
804 	/*
805 	 * find platform node
806 	 */
807 	if ((ptree_get_node_by_path(PLATFORM_PATH, &plfh)) != PICL_SUCCESS) {
808 		syslog(LOG_ERR, EM_INIT_FAILED);
809 		(void) close(fd);
810 		return;
811 	}
812 
813 	/*
814 	 * Find the memory node
815 	 */
816 	if ((ptree_get_node_by_path(MEMORY_PATH, &memh)) != PICL_SUCCESS) {
817 		syslog(LOG_ERR, EM_INIT_FAILED);
818 		(void) close(fd);
819 		return;
820 	}
821 
822 	/*
823 	 * Create subtree of memory-controller in the physical aspect.
824 	 * memory-controller --- memory-module-group --- memory-module
825 	 */
826 	err = find_mc_create_tree(plfh, fd);
827 
828 	if (err != PICL_SUCCESS) {
829 		undo_phymem_tree();
830 		syslog(LOG_ERR, EM_PHYSIC_MEM_TREE_FAILED);
831 	}
832 
833 	/*
834 	 * Add property, TransferSize to memory node
835 	 */
836 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
837 	    PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (transfersize),
838 	    PICL_PROP_TRANSFER_SIZE, NULL, NULL);
839 	if (err != PICL_SUCCESS) {
840 		(void) close(fd);
841 		return;
842 	}
843 
844 	err = ptree_create_and_add_prop(memh, &propinfo,
845 	    &transfersize, NULL);
846 	if (err != PICL_SUCCESS) {
847 		(void) close(fd);
848 		return;
849 	}
850 
851 	/*
852 	 * Create subtree of memory in the logical aspect.
853 	 * memory --- memory-segment --- memory-bank
854 	 */
855 	if ((create_logical_tree(memh, fd)) != PICL_SUCCESS) {
856 		syslog(LOG_ERR, EM_LOGIC_MEM_TREE_FAILED);
857 		undo_logical_tree(nsegments);
858 	}
859 
860 	(void) close(fd);
861 	(void) ptree_register_handler(PICLEVENT_MC_ADDED,
862 	    piclmemcfg_evhandler, NULL);
863 	(void) ptree_register_handler(PICLEVENT_MC_REMOVED,
864 	    piclmemcfg_evhandler, NULL);
865 }
866 
867 /*
868  * fini entry point of the plugin
869  */
870 void
871 piclmemcfg_fini(void)
872 {
873 	(void) ptree_unregister_handler(PICLEVENT_MC_ADDED,
874 	    piclmemcfg_evhandler, NULL);
875 	(void) ptree_unregister_handler(PICLEVENT_MC_REMOVED,
876 	    piclmemcfg_evhandler, NULL);
877 	/*
878 	 * Release all the allocated memory for global structures
879 	 */
880 	free_allocated_mem();
881 	if (msegh_info)
882 		free(msegh_info);
883 }
884 
885 /*
886  * Event handler of this plug-in
887  */
888 /*ARGSUSED*/
889 static void
890 piclmemcfg_evhandler(const char *ename, const void *earg, size_t size,
891     void *cookie)
892 {
893 	int		err;
894 	int		fd;
895 	picl_nodehdl_t	memh;
896 	picl_nodehdl_t	nodeh;
897 	int		old_nsegs;
898 	nvlist_t	*nvlp;
899 
900 	memh = NULL;
901 	if (nvlist_unpack((char *)earg, size, &nvlp, NULL))
902 		return;
903 
904 	if (nvlist_lookup_uint64(nvlp, PICLEVENTARG_NODEHANDLE, &nodeh)) {
905 		nvlist_free(nvlp);
906 		return;
907 	}
908 	nvlist_free(nvlp);
909 
910 	/*
911 	 * get the memory node
912 	 */
913 	err = ptree_get_node_by_path(MEMORY_PATH, &memh);
914 	if (err != PICL_SUCCESS)
915 		return;
916 
917 	/*
918 	 * nsegments won't be overwritten until init_mc succeeds
919 	 */
920 	old_nsegs = nsegments;
921 	if ((fd = init_mc()) < 0)
922 		return;
923 
924 	if (strcmp(ename, PICLEVENT_MC_ADDED) == 0)
925 		(void) create_physical_tree(nodeh, (void *)fd);
926 	else if (strcmp(ename, PICLEVENT_MC_REMOVED) == 0)
927 		/*
928 		 * Delete the entry at the list only since class at PICL is
929 		 * deleted in devtree plugin.
930 		 */
931 		(void) del_plugout_mmodgrp(nodeh);
932 
933 	(void) undo_logical_tree(old_nsegs);
934 	free(msegh_info);
935 
936 	/*
937 	 * allocate memory to save memory-segment node handles. Thus,
938 	 * it is easier to delete them if it fails.
939 	 */
940 	if ((msegh_info = malloc(nsegments * sizeof (picl_nodehdl_t))) ==
941 	    NULL) {
942 		(void) close(fd);
943 		return;
944 	}
945 
946 	(void) create_logical_tree(memh, fd);
947 
948 	(void) close(fd);
949 }
950