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