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
free_allocated_mem(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
del_plugout_mmodgrp(picl_nodehdl_t mch)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
find_mem_mod_grp_hdl(int id,picl_nodehdl_t * mmodgrph)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
undo_phymem_tree(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
add_mem_banks(picl_nodehdl_t msegh,int fd,struct mc_segment * mcseg)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
undo_logical_tree(int nsegments)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
create_logical_tree(picl_nodehdl_t memh,int fd)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
add_mem_modules(picl_nodehdl_t mmodgrph,struct mc_devgrp * mcdevgrp)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
create_physical_tree(picl_nodehdl_t mch,void * args)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
find_mc_create_tree(picl_nodehdl_t rooth,int fd)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
init_mc(void)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
piclmemcfg_register(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
piclmemcfg_init(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
piclmemcfg_fini(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
piclmemcfg_evhandler(const char * ename,const void * earg,size_t size,void * cookie)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