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 } 793