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