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 */
72static	void	piclmemcfg_register(void);
73static	void	piclmemcfg_init(void);
74static	void	piclmemcfg_fini(void);
75
76/*
77 * PICL event handler
78 */
79static void  piclmemcfg_evhandler(const char *ename, const void *earg,
80		size_t size, void *cookie);
81
82#pragma	init(piclmemcfg_register)
83
84static 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
109static int	nsegments;	/* The number of memory segments */
110static int	nbanks;		/* The max. number of banks per segment */
111static int	ndevgrps;	/* The max. number of device groups per mc */
112static int	ndevs;		/* The max. number of devices per dev group */
113static int	transfersize;
114
115static 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 */
128typedef 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
135static	mmodgrp_info_t		*head2mmodgrp;
136
137/*
138 * Release the allocated memory of mmodgrp_info
139 */
140static void
141free_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 */
159static void
160del_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 */
184static int
185find_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 */
207static void
208undo_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 */
236static int
237add_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
349static void
350undo_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 */
367static int
368create_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 */
495static int
496add_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 */
553static int
554create_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 */
688static int
689find_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
698static int
699init_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 */
766void
767piclmemcfg_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 */
776void
777piclmemcfg_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 */
870void
871piclmemcfg_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*/
889static void
890piclmemcfg_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