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 == NULL)
 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 = NULL;
 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 = NULL;
 903         if (nvlist_unpack((char *)earg, size, &nvlp, NULL))
 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 }