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