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