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 /*
  23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * Gathers properties exported by libtopo and uses them to construct diskmon
  29  * data structures, which hold the configuration information for the
  30  * DE.
  31  */
  32 
  33 #include <limits.h>
  34 #include <stdio.h>
  35 #include <stdlib.h>
  36 #include <string.h>
  37 #include <strings.h>
  38 #include <ctype.h>
  39 #include <pthread.h>
  40 #include <libnvpair.h>
  41 #include <config_admin.h>
  42 #include <sys/fm/protocol.h>
  43 #include <fm/libtopo.h>
  44 #include <fm/topo_hc.h>
  45 
  46 #include "disk.h"
  47 #include "disk_monitor.h"
  48 #include "hotplug_mgr.h"
  49 #include "topo_gather.h"
  50 
  51 #define TOPO_PGROUP_IO          "io"    /* duplicated from did_props.h */
  52 #define MAX_CONF_MSG_LEN        256
  53 
  54 static nvlist_t *g_topo2diskmon = NULL;
  55 
  56 /*
  57  * The following function template is required for nvlists that were
  58  * create with no flags (so there can be multiple identical name or name-value
  59  * pairs).  The function defined below returns the first match for the name
  60  * provided.
  61  */
  62 #define NONUNIQUE_NVLIST_FN(suffix, type, atype) \
  63 static int                                                              \
  64 nonunique_nvlist_lookup_##suffix(nvlist_t *nvlp, const char *n, atype *rpp) \
  65 {                                                                       \
  66         nvpair_t *nvp = NULL;                                           \
  67         while ((nvp = nvlist_next_nvpair(nvlp, nvp)) != NULL) {         \
  68                 if (nvpair_type(nvp) != type)                           \
  69                         continue;                                       \
  70                 if (strcmp(nvpair_name(nvp), n) == 0)                   \
  71                         return (nvpair_value_##suffix(nvp, rpp));       \
  72         }                                                               \
  73         return (ENOENT);                                                \
  74 }
  75 
  76 NONUNIQUE_NVLIST_FN(string, DATA_TYPE_STRING, char *)
  77 
  78 static diskmon_t *
  79 dm_fmristring_to_diskmon(char *str)
  80 {
  81         diskmon_t *p = NULL;
  82         uint64_t u64val;
  83         char ch;
  84         char *lastsl = strrchr(str, '/');
  85 
  86         ch = *lastsl;
  87         *lastsl = 0;
  88 
  89         if (nvlist_lookup_uint64(g_topo2diskmon, str, &u64val) == 0) {
  90 
  91                 p = (diskmon_t *)(uintptr_t)u64val;
  92         }
  93 
  94         *lastsl = ch;
  95 
  96         return (p);
  97 }
  98 
  99 diskmon_t *
 100 dm_fmri_to_diskmon(fmd_hdl_t *hdl, nvlist_t *fmri)
 101 {
 102         topo_hdl_t *thdl;
 103         nvlist_t *dupfmri;
 104         diskmon_t *diskp;
 105         char *buf;
 106         int err;
 107 
 108         if (nvlist_dup(fmri, &dupfmri, 0) != 0)
 109                 return (NULL);
 110 
 111         (void) nvlist_remove(dupfmri, FM_FMRI_HC_REVISION, DATA_TYPE_STRING);
 112         (void) nvlist_remove(dupfmri, FM_FMRI_HC_SERIAL_ID, DATA_TYPE_STRING);
 113         (void) nvlist_remove(dupfmri, FM_FMRI_HC_PART, DATA_TYPE_STRING);
 114 
 115         thdl = fmd_hdl_topo_hold(hdl, TOPO_VERSION);
 116         if (topo_fmri_nvl2str(thdl, dupfmri, &buf, &err) != 0) {
 117                 fmd_hdl_topo_rele(hdl, thdl);
 118                 nvlist_free(dupfmri);
 119                 return (NULL);
 120         }
 121         fmd_hdl_topo_rele(hdl, thdl);
 122 
 123         diskp = dm_fmristring_to_diskmon(buf);
 124 
 125         nvlist_free(dupfmri);
 126         topo_hdl_strfree(thdl, buf);
 127 
 128         return (diskp);
 129 }
 130 
 131 static nvlist_t *
 132 find_disk_monitor_private_pgroup(tnode_t *node)
 133 {
 134         int err;
 135         nvlist_t *list_of_lists, *nvlp, *dupnvlp;
 136         nvlist_t *disk_monitor_pgrp = NULL;
 137         nvpair_t *nvp = NULL;
 138         char *pgroup_name;
 139 
 140         /*
 141          * topo_prop_get_all() returns an nvlist that contains other
 142          * nvlists (some of which are property groups).  Since the private
 143          * property group we need will be among the list of property
 144          * groups returned (hopefully), we need to walk the list of nvlists
 145          * in the topo node's properties to find the property groups, then
 146          * check inside each embedded nvlist to see if it's the pgroup we're
 147          * looking for.
 148          */
 149         if ((list_of_lists = topo_prop_getprops(node, &err)) != NULL) {
 150                 /*
 151                  * Go through the list of nvlists, looking for the
 152                  * property group we need.
 153                  */
 154                 while ((nvp = nvlist_next_nvpair(list_of_lists, nvp)) != NULL) {
 155 
 156                         if (nvpair_type(nvp) != DATA_TYPE_NVLIST ||
 157                             strcmp(nvpair_name(nvp), TOPO_PROP_GROUP) != 0 ||
 158                             nvpair_value_nvlist(nvp, &nvlp) != 0)
 159                                 continue;
 160 
 161                         dm_assert(nvlp != NULL);
 162                         pgroup_name = NULL;
 163 
 164                         if (nonunique_nvlist_lookup_string(nvlp,
 165                             TOPO_PROP_GROUP_NAME, &pgroup_name) != 0 ||
 166                             strcmp(pgroup_name, DISK_MONITOR_PROPERTIES) != 0)
 167                                 continue;
 168                         else {
 169                                 /*
 170                                  * Duplicate the nvlist so that when the
 171                                  * master nvlist is freed (below), we will
 172                                  * still refer to allocated memory.
 173                                  */
 174                                 if (nvlist_dup(nvlp, &dupnvlp, 0) == 0)
 175                                         disk_monitor_pgrp = dupnvlp;
 176                                 else
 177                                         disk_monitor_pgrp = NULL;
 178                                 break;
 179                         }
 180                 }
 181 
 182                 nvlist_free(list_of_lists);
 183         }
 184 
 185         return (disk_monitor_pgrp);
 186 }
 187 
 188 /*
 189  * Look up the FMRI corresponding to the node in the global
 190  * hash table and return the pointer stored (if any).  Save the
 191  * FMRI string in *str if str is non-NULL.
 192  */
 193 static void *
 194 fmri2ptr(topo_hdl_t *thp, tnode_t *node, char **str, int *err)
 195 {
 196         nvlist_t        *fmri = NULL;
 197         char            *cstr = NULL;
 198         uint64_t        u64val;
 199         void            *p = NULL;
 200 
 201         if (topo_node_resource(node, &fmri, err) != 0)
 202                 return (NULL);
 203 
 204         if (topo_fmri_nvl2str(thp, fmri, &cstr, err) != 0) {
 205                 nvlist_free(fmri);
 206                 return (NULL);
 207         }
 208 
 209         if (nvlist_lookup_uint64(g_topo2diskmon, cstr, &u64val) == 0) {
 210 
 211                 p = (void *)(uintptr_t)u64val;
 212         }
 213 
 214         nvlist_free(fmri);
 215         if (str != NULL)
 216                 *str = dstrdup(cstr);
 217         topo_hdl_strfree(thp, cstr);
 218         return (p);
 219 }
 220 
 221 typedef struct walk_diskmon {
 222         diskmon_t *target;
 223         char *pfmri;
 224 } walk_diskmon_t;
 225 
 226 static int
 227 topo_add_disk(topo_hdl_t *thp, tnode_t *node, walk_diskmon_t *wdp)
 228 {
 229         diskmon_t *target_diskp = wdp->target;
 230         char            *devpath = NULL;
 231         char            *capacity = NULL;
 232         char            *firmrev = NULL;
 233         char            *serial = NULL;
 234         char            *manuf = NULL;
 235         char            *model = NULL;
 236         char            *label;
 237         uint64_t        ptr = 0;
 238         int             err;
 239         dm_fru_t        *frup;
 240         diskmon_t       *diskp;
 241 
 242         if (wdp->pfmri == NULL) {
 243                 log_msg(MM_TOPO, "No diskmon for parent of node %p.\n", node);
 244                 return (0);
 245         }
 246 
 247         if (nvlist_lookup_uint64(g_topo2diskmon, wdp->pfmri, &ptr) != 0) {
 248                 log_msg(MM_TOPO, "No diskmon for %s: parent of node %p.\n",
 249                     wdp->pfmri, node);
 250                 dstrfree(wdp->pfmri);
 251                 /* Skip this disk: */
 252                 return (0);
 253         }
 254 
 255         dstrfree(wdp->pfmri);
 256         wdp->pfmri = NULL;
 257 
 258         diskp = (diskmon_t *)(uintptr_t)ptr;
 259 
 260         /* If we were called upon to update a particular disk, do it */
 261         if (target_diskp != NULL && diskp != target_diskp) {
 262                 return (0);
 263         }
 264 
 265         /*
 266          * Update the diskmon's location field with the disk's label
 267          */
 268         if (diskp->location)
 269                 dstrfree(diskp->location);
 270         if (topo_node_label(node, &label, &err) == 0) {
 271                 diskp->location = dstrdup(label);
 272                 topo_hdl_strfree(thp, label);
 273         } else
 274                 diskp->location = dstrdup("unknown location");
 275 
 276         /*
 277          * Check for a device path property (if the disk is configured,
 278          * it will be present) and add it to the diskmon's properties)
 279          */
 280         if (topo_prop_get_string(node, TOPO_PGROUP_IO, TOPO_IO_DEV_PATH,
 281             &devpath, &err) == 0) {
 282                 char devp[PATH_MAX];
 283                 /*
 284                  * Consumers of the DISK_PROP_DEVPATH property expect a raw
 285                  * minor device node
 286                  */
 287                 (void) snprintf(devp, PATH_MAX, "%s:q,raw", devpath);
 288                 (void) nvlist_add_string(diskp->props, DISK_PROP_DEVPATH,
 289                     devp);
 290                 topo_hdl_strfree(thp, devpath);
 291         }
 292 
 293         /*
 294          * Add the logical disk node, if it exists
 295          */
 296         if (topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
 297             TOPO_STORAGE_LOGICAL_DISK_NAME, &devpath, &err) == 0) {
 298                 (void) nvlist_add_string(diskp->props, DISK_PROP_LOGNAME,
 299                     devpath);
 300                 topo_hdl_strfree(thp, devpath);
 301         }
 302 
 303         /*
 304          * Add the FRU information (if present in the node) to the diskmon's
 305          * fru data structure:
 306          */
 307         (void) topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
 308             TOPO_STORAGE_MODEL, &model, &err);
 309 
 310         (void) topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
 311             TOPO_STORAGE_MANUFACTURER, &manuf, &err);
 312 
 313         (void) topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
 314             TOPO_STORAGE_SERIAL_NUM, &serial, &err);
 315 
 316         (void) topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
 317             TOPO_STORAGE_FIRMWARE_REV, &firmrev, &err);
 318 
 319         (void) topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
 320             TOPO_STORAGE_CAPACITY, &capacity, &err);
 321 
 322         frup = new_dmfru(manuf != NULL ? manuf : "", model != NULL ? model : "",
 323             firmrev != NULL ? firmrev : "", serial != NULL ? serial : "",
 324             capacity == NULL ? 0 : strtoull(capacity, 0, 0));
 325 
 326         if (model)
 327                 topo_hdl_strfree(thp, model);
 328         if (manuf)
 329                 topo_hdl_strfree(thp, manuf);
 330         if (serial)
 331                 topo_hdl_strfree(thp, serial);
 332         if (firmrev)
 333                 topo_hdl_strfree(thp, firmrev);
 334         if (capacity)
 335                 topo_hdl_strfree(thp, capacity);
 336 
 337         /* Add the fru information to the diskmon: */
 338         dm_assert(pthread_mutex_lock(&diskp->fru_mutex) == 0);
 339         dm_assert(diskp->frup == NULL);
 340         diskp->frup = frup;
 341         dm_assert(pthread_mutex_unlock(&diskp->fru_mutex) == 0);
 342 
 343         return (0);
 344 }
 345 
 346 static int
 347 indicator_breakup(char *identifier, ind_state_t *state, char **name)
 348 {
 349         if (identifier[0] != '+' && identifier[0] != '-') {
 350                 log_msg(MM_CONF, "Invalid indicator name `%s'\n", identifier);
 351                 return (-1);
 352         }
 353 
 354         *state = (identifier[0] == '+') ? INDICATOR_ON : INDICATOR_OFF;
 355         *name = &identifier[1];
 356         return (0);
 357 }
 358 
 359 static int
 360 topoprop_indicator_add(indicator_t **indp, char *ind_name, char *ind_action)
 361 {
 362         /* The Indicator name is of the form: "[+-][A-Za-z][A-Za-z0-9]+" */
 363         indicator_t *newindp;
 364         ind_state_t state;
 365         char *name;
 366 
 367         if (indicator_breakup(ind_name, &state, &name) != 0)
 368                 return (-1);
 369         newindp = new_indicator(state, name, ind_action);
 370 
 371         link_indicator(indp, newindp);
 372 
 373         return (0);
 374 }
 375 
 376 static hotplug_state_t
 377 str2dmstate(char *str)
 378 {
 379         if (strcasecmp("configured", str) == 0) {
 380                 return (HPS_CONFIGURED);
 381         } else if (strcasecmp("unconfigured", str) == 0) {
 382                 return (HPS_UNCONFIGURED);
 383         } else if (strcasecmp("absent", str) == 0) {
 384                 return (HPS_ABSENT);
 385         } else if (strcasecmp("present", str) == 0) {
 386                 return (HPS_PRESENT);
 387         } else
 388                 return (HPS_UNKNOWN);
 389 }
 390 
 391 static int
 392 topoprop_indrule_add(indrule_t **indrp, char *sts, char *acts)
 393 {
 394         ind_action_t            *indactp = NULL;
 395         ind_state_t             state;
 396         char                    *name, *lasts, *p;
 397         int                     stateslen = strlen(sts) + 1;
 398         int                     actionslen = strlen(acts) + 1;
 399         char                    *states = dstrdup(sts);
 400         char                    *actions = dstrdup(acts);
 401         state_transition_t      strans;
 402         boolean_t               failed = B_FALSE;
 403         conf_err_t              err;
 404         char                    msgbuf[MAX_CONF_MSG_LEN];
 405 
 406         /* The state string is of the form "{STATE}>{STATE}" */
 407         p = strchr(states, '>');
 408         dm_assert(p != NULL);
 409         *p = 0;
 410         strans.begin = str2dmstate(states);
 411         *p = '>';
 412         strans.end = str2dmstate(p + 1);
 413 
 414         if (strans.begin == HPS_UNKNOWN || strans.end == HPS_UNKNOWN) {
 415                 log_msg(MM_CONF, "Invalid states property `%s'\n", sts);
 416                 failed = B_TRUE;
 417         } else if ((err = check_state_transition(strans.begin, strans.end))
 418             != E_NO_ERROR) {
 419                 conf_error_msg(err, msgbuf, MAX_CONF_MSG_LEN, &strans);
 420                 log_msg(MM_CONF, "%s: Not adding disk to list!\n", msgbuf);
 421                 failed = B_TRUE;
 422         }
 423 
 424         /* Actions are of the form "{ACTION}[&{ACTION}]" */
 425         if (!failed && (p = strtok_r(actions, "&", &lasts)) != NULL) {
 426                 /* At least 2 tokens */
 427                 do {
 428                         if (indicator_breakup(p, &state, &name) != 0) {
 429                                 failed = B_TRUE;
 430                                 break;
 431                         }
 432 
 433                         link_indaction(&indactp, new_indaction(state, name));
 434 
 435                 } while ((p = strtok_r(NULL, "&", &lasts)) != NULL);
 436         } else if (!failed) {
 437                 /* One token */
 438                 if (indicator_breakup(actions, &state, &name) != 0)
 439                         return (-1);
 440                 indactp = new_indaction(state, name);
 441         }
 442 
 443         dfree(states, stateslen);
 444         dfree(actions, actionslen);
 445 
 446         if (!failed && (err = check_indactions(indactp)) != E_NO_ERROR) {
 447                 conf_error_msg(err, msgbuf, MAX_CONF_MSG_LEN, NULL);
 448                 log_msg(MM_CONF, "%s: Not adding disk to list!\n", msgbuf);
 449                 failed = B_TRUE;
 450         }
 451 
 452         if (failed) {
 453                 indaction_free(indactp);
 454                 return (-1);
 455         } else
 456                 link_indrule(indrp, new_indrule(&strans, indactp));
 457         return (0);
 458 }
 459 
 460 
 461 static int
 462 topo_add_bay(topo_hdl_t *thp, tnode_t *node, walk_diskmon_t *wdp)
 463 {
 464         diskmon_t *target_diskp = wdp->target;
 465         nvlist_t        *nvlp = find_disk_monitor_private_pgroup(node);
 466         nvlist_t        *prop_nvlp;
 467         nvpair_t        *nvp = NULL;
 468         char            *prop_name, *prop_value;
 469 #define PNAME_MAX 128
 470         char            pname[PNAME_MAX];
 471         char            msgbuf[MAX_CONF_MSG_LEN];
 472         char            *indicator_name, *indicator_action;
 473         char            *indrule_states, *indrule_actions;
 474         int             err = 0, i;
 475         conf_err_t      conferr;
 476         boolean_t       conf_failure = B_FALSE;
 477         char            *unadj_physid = NULL;
 478         char            physid[MAXPATHLEN];
 479         char            *label;
 480         nvlist_t        *diskprops = NULL;
 481         char            *cstr = NULL;
 482         indicator_t     *indp = NULL;
 483         indrule_t       *indrp = NULL;
 484         void            *p;
 485         diskmon_t       *diskp;
 486         void            *ptr;
 487 
 488         /* No private properties -- just ignore the port */
 489         if (nvlp == NULL)
 490                 return (0);
 491 
 492         /*
 493          * Look for a diskmon based on this node's FMRI string.
 494          * Once a diskmon has been created, it's not re-created.  This is
 495          * essential for the times when the tree-walk is called after a
 496          * disk is inserted (or removed) -- in that case, the disk node
 497          * handler simply updates the FRU information in the diskmon.
 498          */
 499         if ((p = fmri2ptr(thp, node, &cstr, &err)) != NULL) {
 500 
 501                 diskp = (diskmon_t *)p;
 502 
 503                 /*
 504                  * Delete the FRU information from the diskmon.  If a disk
 505                  * is connected, its FRU information will be refreshed by
 506                  * the disk node code.
 507                  */
 508                 if (diskp->frup && (target_diskp == NULL ||
 509                     diskp == target_diskp)) {
 510                         dm_assert(pthread_mutex_lock(&diskp->fru_mutex) == 0);
 511                         dmfru_free(diskp->frup);
 512                         diskp->frup = NULL;
 513                         dm_assert(pthread_mutex_unlock(&diskp->fru_mutex) == 0);
 514                 }
 515 
 516                 wdp->pfmri = cstr;
 517                 nvlist_free(nvlp);
 518                 return (0);
 519         }
 520 
 521         /*
 522          * Determine the physical path to the attachment point
 523          */
 524         if (topo_prop_get_string(node, TOPO_PGROUP_IO,
 525             TOPO_IO_AP_PATH, &unadj_physid, &err) == 0) {
 526 
 527                 adjust_dynamic_ap(unadj_physid, physid);
 528                 topo_hdl_strfree(thp, unadj_physid);
 529         } else {
 530 
 531                 /* unadj_physid cannot have been allocated */
 532                 if (cstr)
 533                         dstrfree(cstr);
 534                 nvlist_free(nvlp);
 535                 return (-1);
 536         }
 537 
 538         /*
 539          */
 540 
 541         /*
 542          * Process the properties.  If we encounter a property that
 543          * is not an indicator name, action, or rule, add it to the
 544          * disk's props list.
 545          */
 546 
 547         /* Process indicators */
 548         i = 0;
 549         indicator_name = NULL;
 550         indicator_action = NULL;
 551         do {
 552                 if (indicator_name != NULL && indicator_action != NULL) {
 553 
 554                         if (topoprop_indicator_add(&indp, indicator_name,
 555                             indicator_action) != 0) {
 556 
 557                                 conf_failure = B_TRUE;
 558                         }
 559 
 560                         topo_hdl_strfree(thp, indicator_name);
 561                         topo_hdl_strfree(thp, indicator_action);
 562                 }
 563 
 564                 (void) snprintf(pname, PNAME_MAX, BAY_IND_NAME "-%d", i);
 565                 if (topo_prop_get_string(node, DISK_MONITOR_PROPERTIES,
 566                     pname, &indicator_name, &err) != 0)
 567                         break;
 568 
 569                 (void) snprintf(pname, PNAME_MAX, BAY_IND_ACTION "-%d", i);
 570                 if (topo_prop_get_string(node, DISK_MONITOR_PROPERTIES,
 571                     pname, &indicator_action, &err) != 0)
 572                         break;
 573 
 574                 i++;
 575         } while (!conf_failure && indicator_name != NULL &&
 576             indicator_action != NULL);
 577 
 578         if (!conf_failure && indp != NULL &&
 579             (conferr = check_inds(indp)) != E_NO_ERROR) {
 580                 conf_error_msg(conferr, msgbuf, MAX_CONF_MSG_LEN, NULL);
 581                 log_msg(MM_CONF, "%s: Not adding disk to list\n", msgbuf);
 582                 conf_failure = B_TRUE;
 583         }
 584 
 585         /* Process state rules and indicator actions */
 586         i = 0;
 587         indrule_states = NULL;
 588         indrule_actions = NULL;
 589         do {
 590                 if (indrule_states != NULL && indrule_actions != NULL) {
 591 
 592                         if (topoprop_indrule_add(&indrp, indrule_states,
 593                             indrule_actions) != 0) {
 594 
 595                                 conf_failure = B_TRUE;
 596                         }
 597 
 598                         topo_hdl_strfree(thp, indrule_states);
 599                         topo_hdl_strfree(thp, indrule_actions);
 600                 }
 601 
 602                 (void) snprintf(pname, PNAME_MAX, BAY_INDRULE_STATES "-%d", i);
 603                 if (topo_prop_get_string(node, DISK_MONITOR_PROPERTIES,
 604                     pname, &indrule_states, &err) != 0)
 605                         break;
 606 
 607                 (void) snprintf(pname, PNAME_MAX, BAY_INDRULE_ACTIONS "-%d",
 608                     i);
 609                 if (topo_prop_get_string(node, DISK_MONITOR_PROPERTIES,
 610                     pname, &indrule_actions, &err) != 0)
 611                         break;
 612 
 613                 i++;
 614         } while (!conf_failure && indrule_states != NULL &&
 615             indrule_actions != NULL);
 616 
 617         if (!conf_failure && indrp != NULL && indp != NULL &&
 618             ((conferr = check_indrules(indrp, (state_transition_t **)&ptr))
 619             != E_NO_ERROR ||
 620             (conferr = check_consistent_ind_indrules(indp, indrp,
 621             (ind_action_t **)&ptr)) != E_NO_ERROR)) {
 622 
 623                 conf_error_msg(conferr, msgbuf, MAX_CONF_MSG_LEN, ptr);
 624                 log_msg(MM_CONF, "%s: Not adding disk to list\n", msgbuf);
 625                 conf_failure = B_TRUE;
 626 
 627         }
 628 
 629         /*
 630          * Now collect miscellaneous properties.
 631          * Each property is stored as an embedded nvlist named
 632          * TOPO_PROP_VAL.  The property name is stored in the value for
 633          * key=TOPO_PROP_VAL_NAME and the property's value is
 634          * stored in the value for key=TOPO_PROP_VAL_VAL.  This is all
 635          * necessary so we can subtractively decode the properties that
 636          * we do not directly handle (so that these properties are added to
 637          * the per-disk properties nvlist), increasing flexibility.
 638          */
 639         (void) nvlist_alloc(&diskprops, NV_UNIQUE_NAME, 0);
 640         while ((nvp = nvlist_next_nvpair(nvlp, nvp)) != NULL) {
 641                 /* Only care about embedded nvlists named TOPO_PROP_VAL */
 642                 if (nvpair_type(nvp) != DATA_TYPE_NVLIST ||
 643                     strcmp(nvpair_name(nvp), TOPO_PROP_VAL) != 0 ||
 644                     nvpair_value_nvlist(nvp, &prop_nvlp) != 0)
 645                         continue;
 646 
 647                 if (nonunique_nvlist_lookup_string(prop_nvlp,
 648                     TOPO_PROP_VAL_NAME, &prop_name) != 0)
 649                         continue;
 650 
 651                 /* Filter out indicator properties */
 652                 if (strstr(prop_name, BAY_IND_NAME) != NULL ||
 653                     strstr(prop_name, BAY_IND_ACTION) != NULL ||
 654                     strstr(prop_name, BAY_INDRULE_STATES) != NULL ||
 655                     strstr(prop_name, BAY_INDRULE_ACTIONS) != NULL)
 656                         continue;
 657 
 658                 if (nonunique_nvlist_lookup_string(prop_nvlp, TOPO_PROP_VAL_VAL,
 659                     &prop_value) != 0)
 660                         continue;
 661 
 662                 /* Add the property to the disk's prop list: */
 663                 if (nvlist_add_string(diskprops, prop_name, prop_value) != 0)
 664                         log_msg(MM_TOPO,
 665                             "Could not add disk property `%s' with "
 666                             "value `%s'\n", prop_name, prop_value);
 667         }
 668 
 669         nvlist_free(nvlp);
 670 
 671         if (cstr != NULL) {
 672                 namevalpr_t nvpr;
 673                 nvlist_t *dmap_nvl;
 674 
 675                 nvpr.name = DISK_AP_PROP_APID;
 676                 nvpr.value = strncmp(physid, "/devices", 8) == 0 ?
 677                     (physid + 8) : physid;
 678 
 679                 /*
 680                  * Set the diskmon's location to the value in this port's label.
 681                  * If there's a disk plugged in, the location will be updated
 682                  * to be the disk label (e.g. HD_ID_00).  Until a disk is
 683                  * inserted, though, there won't be a disk libtopo node
 684                  * created.
 685                  */
 686 
 687                 /* Pass physid without the leading "/devices": */
 688                 dmap_nvl = namevalpr_to_nvlist(&nvpr);
 689 
 690                 diskp = new_diskmon(dmap_nvl, indp, indrp, diskprops);
 691 
 692                 if (topo_node_label(node, &label, &err) == 0) {
 693                         diskp->location = dstrdup(label);
 694                         topo_hdl_strfree(thp, label);
 695                 } else
 696                         diskp->location = dstrdup("unknown location");
 697 
 698                 if (!conf_failure && diskp != NULL) {
 699                         /* Add this diskmon to the disk list */
 700                         cfgdata_add_diskmon(config_data, diskp);
 701                         if (nvlist_add_uint64(g_topo2diskmon, cstr,
 702                             (uint64_t)(uintptr_t)diskp) != 0) {
 703                                 log_msg(MM_TOPO,
 704                                     "Could not add pointer to nvlist "
 705                                     "for `%s'!\n", cstr);
 706                         }
 707                 } else if (diskp != NULL) {
 708                         diskmon_free(diskp);
 709                 } else {
 710                         nvlist_free(dmap_nvl);
 711                         if (indp)
 712                                 ind_free(indp);
 713                         if (indrp)
 714                                 indrule_free(indrp);
 715                         nvlist_free(diskprops);
 716                 }
 717 
 718                 wdp->pfmri = cstr;
 719         }
 720 
 721 
 722         return (0);
 723 }
 724 
 725 /*ARGSUSED*/
 726 static int
 727 gather_topo_cfg(topo_hdl_t *thp, tnode_t *node, void *arg)
 728 {
 729         char *nodename = topo_node_name(node);
 730         if (strcmp(DISK, nodename) == 0)
 731                 return (topo_add_disk(thp, node, (walk_diskmon_t *)arg)
 732                     ? TOPO_WALK_ERR : TOPO_WALK_NEXT);
 733         else if (strcmp(BAY, nodename) == 0)
 734                 return (topo_add_bay(thp, node, (walk_diskmon_t *)arg)
 735                     ? TOPO_WALK_ERR : TOPO_WALK_NEXT);
 736 
 737         return (TOPO_WALK_NEXT);
 738 }
 739 
 740 
 741 /*ARGSUSED*/
 742 int
 743 update_configuration_from_topo(fmd_hdl_t *hdl, diskmon_t *diskp)
 744 {
 745         int err;
 746         topo_hdl_t *thp;
 747         topo_walk_t *twp;
 748         walk_diskmon_t wd;
 749 
 750         if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL) {
 751                 return (TOPO_OPEN_ERROR);
 752         }
 753 
 754         wd.target = diskp;
 755         wd.pfmri = NULL;
 756         if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC, gather_topo_cfg,
 757             &wd, &err)) == NULL) {
 758                 fmd_hdl_topo_rele(hdl, thp);
 759                 return (err ? TOPO_WALK_INIT_ERROR : TOPO_SUCCESS);
 760         }
 761 
 762         if (topo_walk_step(twp, TOPO_WALK_CHILD) == TOPO_WALK_ERR) {
 763 
 764                 topo_walk_fini(twp);
 765                 if (wd.pfmri != NULL)
 766                         dstrfree(wd.pfmri);
 767 
 768                 fmd_hdl_topo_rele(hdl, thp);
 769                 return (TOPO_WALK_ERROR);
 770         }
 771 
 772         topo_walk_fini(twp);
 773         fmd_hdl_topo_rele(hdl, thp);
 774         if (wd.pfmri != NULL)
 775                 dstrfree(wd.pfmri);
 776 
 777         return (TOPO_SUCCESS);
 778 }
 779 
 780 int
 781 init_configuration_from_topo(void)
 782 {
 783         return (nvlist_alloc(&g_topo2diskmon, NV_UNIQUE_NAME, 0));
 784 }
 785 
 786 void
 787 fini_configuration_from_topo(void)
 788 {
 789         if (g_topo2diskmon) {
 790                 nvlist_free(g_topo2diskmon);
 791         }
 792 }