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