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