14582Scth /*
24582Scth * CDDL HEADER START
34582Scth *
44582Scth * The contents of this file are subject to the terms of the
54582Scth * Common Development and Distribution License (the "License").
64582Scth * You may not use this file except in compliance with the License.
74582Scth *
84582Scth * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94582Scth * or http://www.opensolaris.org/os/licensing.
104582Scth * See the License for the specific language governing permissions
114582Scth * and limitations under the License.
124582Scth *
134582Scth * When distributing Covered Code, include this CDDL HEADER in each
144582Scth * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154582Scth * If applicable, add the following below this CDDL HEADER, with the
164582Scth * fields enclosed by brackets "[]" replaced with your own identifying
174582Scth * information: Portions Copyright [yyyy] [name of copyright owner]
184582Scth *
194582Scth * CDDL HEADER END
204582Scth */
214582Scth
224582Scth /*
236640Scth * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
244582Scth * Use is subject to license terms.
254582Scth */
264582Scth
274582Scth /*
284582Scth * Gathers properties exported by libtopo and uses them to construct diskmon
294582Scth * data structures, which hold the configuration information for the
304582Scth * DE.
314582Scth */
324582Scth
334582Scth #include <limits.h>
344582Scth #include <stdio.h>
354582Scth #include <stdlib.h>
364582Scth #include <string.h>
374582Scth #include <strings.h>
384582Scth #include <ctype.h>
394582Scth #include <pthread.h>
404582Scth #include <libnvpair.h>
414582Scth #include <config_admin.h>
424582Scth #include <sys/fm/protocol.h>
434582Scth #include <fm/libtopo.h>
444582Scth #include <fm/topo_hc.h>
454582Scth
464582Scth #include "disk.h"
474582Scth #include "disk_monitor.h"
485117Smyers #include "hotplug_mgr.h"
494582Scth #include "topo_gather.h"
504582Scth
514582Scth #define TOPO_PGROUP_IO "io" /* duplicated from did_props.h */
524582Scth #define MAX_CONF_MSG_LEN 256
534582Scth
544582Scth static nvlist_t *g_topo2diskmon = NULL;
554582Scth
564582Scth /*
574582Scth * The following function template is required for nvlists that were
584582Scth * create with no flags (so there can be multiple identical name or name-value
594582Scth * pairs). The function defined below returns the first match for the name
604582Scth * provided.
614582Scth */
624582Scth #define NONUNIQUE_NVLIST_FN(suffix, type, atype) \
634582Scth static int \
644582Scth nonunique_nvlist_lookup_##suffix(nvlist_t *nvlp, const char *n, atype *rpp) \
654582Scth { \
664582Scth nvpair_t *nvp = NULL; \
674582Scth while ((nvp = nvlist_next_nvpair(nvlp, nvp)) != NULL) { \
684582Scth if (nvpair_type(nvp) != type) \
694582Scth continue; \
704582Scth if (strcmp(nvpair_name(nvp), n) == 0) \
714582Scth return (nvpair_value_##suffix(nvp, rpp)); \
724582Scth } \
734582Scth return (ENOENT); \
744582Scth }
754582Scth
NONUNIQUE_NVLIST_FN(string,DATA_TYPE_STRING,char *)764582Scth NONUNIQUE_NVLIST_FN(string, DATA_TYPE_STRING, char *)
774582Scth
784582Scth static diskmon_t *
794582Scth dm_fmristring_to_diskmon(char *str)
804582Scth {
814582Scth diskmon_t *p = NULL;
824582Scth uint64_t u64val;
834582Scth char ch;
844582Scth char *lastsl = strrchr(str, '/');
854582Scth
864582Scth ch = *lastsl;
874582Scth *lastsl = 0;
884582Scth
894582Scth if (nvlist_lookup_uint64(g_topo2diskmon, str, &u64val) == 0) {
904582Scth
914582Scth p = (diskmon_t *)(uintptr_t)u64val;
924582Scth }
934582Scth
944582Scth *lastsl = ch;
954582Scth
964582Scth return (p);
974582Scth }
984582Scth
994582Scth diskmon_t *
dm_fmri_to_diskmon(fmd_hdl_t * hdl,nvlist_t * fmri)1004582Scth dm_fmri_to_diskmon(fmd_hdl_t *hdl, nvlist_t *fmri)
1014582Scth {
1024582Scth topo_hdl_t *thdl;
1034582Scth nvlist_t *dupfmri;
1044582Scth diskmon_t *diskp;
1054582Scth char *buf;
1064582Scth int err;
1074582Scth
1084582Scth if (nvlist_dup(fmri, &dupfmri, 0) != 0)
1094582Scth return (NULL);
1104582Scth
1114582Scth (void) nvlist_remove(dupfmri, FM_FMRI_HC_REVISION, DATA_TYPE_STRING);
1124582Scth (void) nvlist_remove(dupfmri, FM_FMRI_HC_SERIAL_ID, DATA_TYPE_STRING);
1134582Scth (void) nvlist_remove(dupfmri, FM_FMRI_HC_PART, DATA_TYPE_STRING);
1144582Scth
1154582Scth thdl = fmd_hdl_topo_hold(hdl, TOPO_VERSION);
1164582Scth if (topo_fmri_nvl2str(thdl, dupfmri, &buf, &err) != 0) {
1174582Scth fmd_hdl_topo_rele(hdl, thdl);
1184582Scth nvlist_free(dupfmri);
1194582Scth return (NULL);
1204582Scth }
1214582Scth fmd_hdl_topo_rele(hdl, thdl);
1224582Scth
1234582Scth diskp = dm_fmristring_to_diskmon(buf);
1244582Scth
1254582Scth nvlist_free(dupfmri);
1264582Scth topo_hdl_strfree(thdl, buf);
1274582Scth
1284582Scth return (diskp);
1294582Scth }
1304582Scth
1314582Scth static nvlist_t *
find_disk_monitor_private_pgroup(tnode_t * node)1324582Scth find_disk_monitor_private_pgroup(tnode_t *node)
1334582Scth {
1344582Scth int err;
1354582Scth nvlist_t *list_of_lists, *nvlp, *dupnvlp;
1364582Scth nvlist_t *disk_monitor_pgrp = NULL;
1374582Scth nvpair_t *nvp = NULL;
1384582Scth char *pgroup_name;
1394582Scth
1404582Scth /*
1414582Scth * topo_prop_get_all() returns an nvlist that contains other
1424582Scth * nvlists (some of which are property groups). Since the private
1434582Scth * property group we need will be among the list of property
1444582Scth * groups returned (hopefully), we need to walk the list of nvlists
1454582Scth * in the topo node's properties to find the property groups, then
1464582Scth * check inside each embedded nvlist to see if it's the pgroup we're
1474582Scth * looking for.
1484582Scth */
1494582Scth if ((list_of_lists = topo_prop_getprops(node, &err)) != NULL) {
1504582Scth /*
1514582Scth * Go through the list of nvlists, looking for the
1524582Scth * property group we need.
1534582Scth */
1544582Scth while ((nvp = nvlist_next_nvpair(list_of_lists, nvp)) != NULL) {
1554582Scth
1564582Scth if (nvpair_type(nvp) != DATA_TYPE_NVLIST ||
1574582Scth strcmp(nvpair_name(nvp), TOPO_PROP_GROUP) != 0 ||
1584582Scth nvpair_value_nvlist(nvp, &nvlp) != 0)
1594582Scth continue;
1604582Scth
1614582Scth dm_assert(nvlp != NULL);
1624582Scth pgroup_name = NULL;
1634582Scth
1644582Scth if (nonunique_nvlist_lookup_string(nvlp,
1654582Scth TOPO_PROP_GROUP_NAME, &pgroup_name) != 0 ||
1664582Scth strcmp(pgroup_name, DISK_MONITOR_PROPERTIES) != 0)
1674582Scth continue;
1684582Scth else {
1694582Scth /*
1704582Scth * Duplicate the nvlist so that when the
1714582Scth * master nvlist is freed (below), we will
1724582Scth * still refer to allocated memory.
1734582Scth */
1744582Scth if (nvlist_dup(nvlp, &dupnvlp, 0) == 0)
1754582Scth disk_monitor_pgrp = dupnvlp;
1764582Scth else
1774582Scth disk_monitor_pgrp = NULL;
1784582Scth break;
1794582Scth }
1804582Scth }
1814582Scth
1824582Scth nvlist_free(list_of_lists);
1834582Scth }
1844582Scth
1854582Scth return (disk_monitor_pgrp);
1864582Scth }
1874582Scth
1884582Scth /*
1894582Scth * Look up the FMRI corresponding to the node in the global
1904582Scth * hash table and return the pointer stored (if any). Save the
1914582Scth * FMRI string in *str if str is non-NULL.
1924582Scth */
1934582Scth static void *
fmri2ptr(topo_hdl_t * thp,tnode_t * node,char ** str,int * err)1944582Scth fmri2ptr(topo_hdl_t *thp, tnode_t *node, char **str, int *err)
1954582Scth {
1964582Scth nvlist_t *fmri = NULL;
1974582Scth char *cstr = NULL;
1984582Scth uint64_t u64val;
1994582Scth void *p = NULL;
2004582Scth
2014582Scth if (topo_node_resource(node, &fmri, err) != 0)
2024582Scth return (NULL);
2034582Scth
2044582Scth if (topo_fmri_nvl2str(thp, fmri, &cstr, err) != 0) {
2054582Scth nvlist_free(fmri);
2064582Scth return (NULL);
2074582Scth }
2084582Scth
2094582Scth if (nvlist_lookup_uint64(g_topo2diskmon, cstr, &u64val) == 0) {
2104582Scth
2114582Scth p = (void *)(uintptr_t)u64val;
2124582Scth }
2134582Scth
2144582Scth nvlist_free(fmri);
2154582Scth if (str != NULL)
2164582Scth *str = dstrdup(cstr);
2174582Scth topo_hdl_strfree(thp, cstr);
2184582Scth return (p);
2194582Scth }
2204582Scth
2214582Scth typedef struct walk_diskmon {
2224582Scth diskmon_t *target;
2234582Scth char *pfmri;
2244582Scth } walk_diskmon_t;
2254582Scth
2264582Scth static int
topo_add_disk(topo_hdl_t * thp,tnode_t * node,walk_diskmon_t * wdp)2274582Scth topo_add_disk(topo_hdl_t *thp, tnode_t *node, walk_diskmon_t *wdp)
2284582Scth {
2294582Scth diskmon_t *target_diskp = wdp->target;
2304582Scth char *devpath = NULL;
2314582Scth char *capacity = NULL;
2324582Scth char *firmrev = NULL;
2334582Scth char *serial = NULL;
2344582Scth char *manuf = NULL;
2354582Scth char *model = NULL;
2364582Scth char *label;
2374582Scth uint64_t ptr = 0;
2384582Scth int err;
2394582Scth dm_fru_t *frup;
2404582Scth diskmon_t *diskp;
2414582Scth
2424582Scth if (wdp->pfmri == NULL) {
2434582Scth log_msg(MM_TOPO, "No diskmon for parent of node %p.\n", node);
2444582Scth return (0);
2454582Scth }
2464582Scth
2474582Scth if (nvlist_lookup_uint64(g_topo2diskmon, wdp->pfmri, &ptr) != 0) {
2484582Scth log_msg(MM_TOPO, "No diskmon for %s: parent of node %p.\n",
2494582Scth wdp->pfmri, node);
2504582Scth dstrfree(wdp->pfmri);
2514582Scth /* Skip this disk: */
2524582Scth return (0);
2534582Scth }
2544582Scth
2554582Scth dstrfree(wdp->pfmri);
2564582Scth wdp->pfmri = NULL;
2574582Scth
2584582Scth diskp = (diskmon_t *)(uintptr_t)ptr;
2594582Scth
2604582Scth /* If we were called upon to update a particular disk, do it */
2614582Scth if (target_diskp != NULL && diskp != target_diskp) {
2624582Scth return (0);
2634582Scth }
2644582Scth
2654582Scth /*
2664582Scth * Update the diskmon's location field with the disk's label
2674582Scth */
2684582Scth if (diskp->location)
2694582Scth dstrfree(diskp->location);
2704582Scth if (topo_node_label(node, &label, &err) == 0) {
2714582Scth diskp->location = dstrdup(label);
2724582Scth topo_hdl_strfree(thp, label);
2734582Scth } else
2744582Scth diskp->location = dstrdup("unknown location");
2754582Scth
2764582Scth /*
2774582Scth * Check for a device path property (if the disk is configured,
2784582Scth * it will be present) and add it to the diskmon's properties)
2794582Scth */
2804582Scth if (topo_prop_get_string(node, TOPO_PGROUP_IO, TOPO_IO_DEV_PATH,
2814582Scth &devpath, &err) == 0) {
2824582Scth char devp[PATH_MAX];
2834582Scth /*
2844582Scth * Consumers of the DISK_PROP_DEVPATH property expect a raw
2854582Scth * minor device node
2864582Scth */
2874582Scth (void) snprintf(devp, PATH_MAX, "%s:q,raw", devpath);
2884582Scth (void) nvlist_add_string(diskp->props, DISK_PROP_DEVPATH,
2894582Scth devp);
2904582Scth topo_hdl_strfree(thp, devpath);
2914582Scth }
2924582Scth
2934582Scth /*
2944582Scth * Add the logical disk node, if it exists
2954582Scth */
2966640Scth if (topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
2974582Scth TOPO_STORAGE_LOGICAL_DISK_NAME, &devpath, &err) == 0) {
2984582Scth (void) nvlist_add_string(diskp->props, DISK_PROP_LOGNAME,
2994582Scth devpath);
3004582Scth topo_hdl_strfree(thp, devpath);
3014582Scth }
3024582Scth
3034582Scth /*
3044582Scth * Add the FRU information (if present in the node) to the diskmon's
3054582Scth * fru data structure:
3064582Scth */
3076640Scth (void) topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
3084582Scth TOPO_STORAGE_MODEL, &model, &err);
3094582Scth
3106640Scth (void) topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
3114582Scth TOPO_STORAGE_MANUFACTURER, &manuf, &err);
3124582Scth
3136640Scth (void) topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
3144582Scth TOPO_STORAGE_SERIAL_NUM, &serial, &err);
3154582Scth
3166640Scth (void) topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
3174582Scth TOPO_STORAGE_FIRMWARE_REV, &firmrev, &err);
3184582Scth
3196640Scth (void) topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
3204582Scth TOPO_STORAGE_CAPACITY, &capacity, &err);
3214582Scth
322*7913SStephen.Hanson@Sun.COM frup = new_dmfru(manuf != NULL ? manuf : "", model != NULL ? model : "",
323*7913SStephen.Hanson@Sun.COM firmrev != NULL ? firmrev : "", serial != NULL ? serial : "",
3244582Scth capacity == NULL ? 0 : strtoull(capacity, 0, 0));
3254582Scth
3264582Scth if (model)
3274582Scth topo_hdl_strfree(thp, model);
3284582Scth if (manuf)
3294582Scth topo_hdl_strfree(thp, manuf);
3304582Scth if (serial)
3314582Scth topo_hdl_strfree(thp, serial);
3324582Scth if (firmrev)
3334582Scth topo_hdl_strfree(thp, firmrev);
3344582Scth if (capacity)
3354582Scth topo_hdl_strfree(thp, capacity);
3364582Scth
3374582Scth /* Add the fru information to the diskmon: */
3384582Scth dm_assert(pthread_mutex_lock(&diskp->fru_mutex) == 0);
3394582Scth dm_assert(diskp->frup == NULL);
3404582Scth diskp->frup = frup;
3414582Scth dm_assert(pthread_mutex_unlock(&diskp->fru_mutex) == 0);
3424582Scth
3434582Scth return (0);
3444582Scth }
3454582Scth
3464582Scth static int
indicator_breakup(char * identifier,ind_state_t * state,char ** name)3474582Scth indicator_breakup(char *identifier, ind_state_t *state, char **name)
3484582Scth {
3494582Scth if (identifier[0] != '+' && identifier[0] != '-') {
3504582Scth log_msg(MM_CONF, "Invalid indicator name `%s'\n", identifier);
3514582Scth return (-1);
3524582Scth }
3534582Scth
3544582Scth *state = (identifier[0] == '+') ? INDICATOR_ON : INDICATOR_OFF;
3554582Scth *name = &identifier[1];
3564582Scth return (0);
3574582Scth }
3584582Scth
3594582Scth static int
topoprop_indicator_add(indicator_t ** indp,char * ind_name,char * ind_action)3604582Scth topoprop_indicator_add(indicator_t **indp, char *ind_name, char *ind_action)
3614582Scth {
3624582Scth /* The Indicator name is of the form: "[+-][A-Za-z][A-Za-z0-9]+" */
3634582Scth indicator_t *newindp;
3644582Scth ind_state_t state;
3654582Scth char *name;
3664582Scth
3674582Scth if (indicator_breakup(ind_name, &state, &name) != 0)
3684582Scth return (-1);
3694582Scth newindp = new_indicator(state, name, ind_action);
3704582Scth
3714582Scth link_indicator(indp, newindp);
3724582Scth
3734582Scth return (0);
3744582Scth }
3754582Scth
3764582Scth static hotplug_state_t
str2dmstate(char * str)3774582Scth str2dmstate(char *str)
3784582Scth {
3794582Scth if (strcasecmp("configured", str) == 0) {
3804582Scth return (HPS_CONFIGURED);
3814582Scth } else if (strcasecmp("unconfigured", str) == 0) {
3824582Scth return (HPS_UNCONFIGURED);
3834582Scth } else if (strcasecmp("absent", str) == 0) {
3844582Scth return (HPS_ABSENT);
3854582Scth } else if (strcasecmp("present", str) == 0) {
3864582Scth return (HPS_PRESENT);
3874582Scth } else
3884582Scth return (HPS_UNKNOWN);
3894582Scth }
3904582Scth
3914582Scth static int
topoprop_indrule_add(indrule_t ** indrp,char * sts,char * acts)3924582Scth topoprop_indrule_add(indrule_t **indrp, char *sts, char *acts)
3934582Scth {
3944582Scth ind_action_t *indactp = NULL;
3954582Scth ind_state_t state;
3964582Scth char *name, *lasts, *p;
3974582Scth int stateslen = strlen(sts) + 1;
3984582Scth int actionslen = strlen(acts) + 1;
3994582Scth char *states = dstrdup(sts);
4004582Scth char *actions = dstrdup(acts);
4014582Scth state_transition_t strans;
4024582Scth boolean_t failed = B_FALSE;
4034582Scth conf_err_t err;
4044582Scth char msgbuf[MAX_CONF_MSG_LEN];
4054582Scth
4064582Scth /* The state string is of the form "{STATE}>{STATE}" */
4074582Scth p = strchr(states, '>');
4084582Scth dm_assert(p != NULL);
4094582Scth *p = 0;
4104582Scth strans.begin = str2dmstate(states);
4114582Scth *p = '>';
4124582Scth strans.end = str2dmstate(p + 1);
4134582Scth
4144582Scth if (strans.begin == HPS_UNKNOWN || strans.end == HPS_UNKNOWN) {
4154582Scth log_msg(MM_CONF, "Invalid states property `%s'\n", sts);
4164582Scth failed = B_TRUE;
4174582Scth } else if ((err = check_state_transition(strans.begin, strans.end))
4184582Scth != E_NO_ERROR) {
4194582Scth conf_error_msg(err, msgbuf, MAX_CONF_MSG_LEN, &strans);
4204582Scth log_msg(MM_CONF, "%s: Not adding disk to list!\n", msgbuf);
4214582Scth failed = B_TRUE;
4224582Scth }
4234582Scth
4244582Scth /* Actions are of the form "{ACTION}[&{ACTION}]" */
4254582Scth if (!failed && (p = strtok_r(actions, "&", &lasts)) != NULL) {
4264582Scth /* At least 2 tokens */
4274582Scth do {
4284582Scth if (indicator_breakup(p, &state, &name) != 0) {
4294582Scth failed = B_TRUE;
4304582Scth break;
4314582Scth }
4324582Scth
4334582Scth link_indaction(&indactp, new_indaction(state, name));
4344582Scth
4354582Scth } while ((p = strtok_r(NULL, "&", &lasts)) != NULL);
4364582Scth } else if (!failed) {
4374582Scth /* One token */
4384582Scth if (indicator_breakup(actions, &state, &name) != 0)
4394582Scth return (-1);
4404582Scth indactp = new_indaction(state, name);
4414582Scth }
4424582Scth
4434582Scth dfree(states, stateslen);
4444582Scth dfree(actions, actionslen);
4454582Scth
4464582Scth if (!failed && (err = check_indactions(indactp)) != E_NO_ERROR) {
4474582Scth conf_error_msg(err, msgbuf, MAX_CONF_MSG_LEN, NULL);
4484582Scth log_msg(MM_CONF, "%s: Not adding disk to list!\n", msgbuf);
4494582Scth failed = B_TRUE;
4504582Scth }
4514582Scth
4524582Scth if (failed) {
4534582Scth indaction_free(indactp);
4544582Scth return (-1);
4554582Scth } else
4564582Scth link_indrule(indrp, new_indrule(&strans, indactp));
4574582Scth return (0);
4584582Scth }
4594582Scth
4604582Scth
4614582Scth static int
topo_add_bay(topo_hdl_t * thp,tnode_t * node,walk_diskmon_t * wdp)4624582Scth topo_add_bay(topo_hdl_t *thp, tnode_t *node, walk_diskmon_t *wdp)
4634582Scth {
4644582Scth diskmon_t *target_diskp = wdp->target;
4654582Scth nvlist_t *nvlp = find_disk_monitor_private_pgroup(node);
4664582Scth nvlist_t *prop_nvlp;
4674582Scth nvpair_t *nvp = NULL;
4684582Scth char *prop_name, *prop_value;
4694582Scth #define PNAME_MAX 128
4704582Scth char pname[PNAME_MAX];
4714582Scth char msgbuf[MAX_CONF_MSG_LEN];
4724582Scth char *indicator_name, *indicator_action;
4734582Scth char *indrule_states, *indrule_actions;
4744582Scth int err = 0, i;
4754582Scth conf_err_t conferr;
4764582Scth boolean_t conf_failure = B_FALSE;
4775117Smyers char *unadj_physid = NULL;
4785117Smyers char physid[MAXPATHLEN];
4794582Scth char *label;
4804582Scth nvlist_t *diskprops = NULL;
4814582Scth char *cstr = NULL;
4824582Scth indicator_t *indp = NULL;
4834582Scth indrule_t *indrp = NULL;
4844582Scth void *p;
4854582Scth diskmon_t *diskp;
4864582Scth void *ptr;
4874582Scth
4884582Scth /* No private properties -- just ignore the port */
4894582Scth if (nvlp == NULL)
4904582Scth return (0);
4914582Scth
4924582Scth /*
4934582Scth * Look for a diskmon based on this node's FMRI string.
4944582Scth * Once a diskmon has been created, it's not re-created. This is
4954582Scth * essential for the times when the tree-walk is called after a
4964582Scth * disk is inserted (or removed) -- in that case, the disk node
4974582Scth * handler simply updates the FRU information in the diskmon.
4984582Scth */
4994582Scth if ((p = fmri2ptr(thp, node, &cstr, &err)) != NULL) {
5004582Scth
5014582Scth diskp = (diskmon_t *)p;
5024582Scth
5034582Scth /*
5044582Scth * Delete the FRU information from the diskmon. If a disk
5054582Scth * is connected, its FRU information will be refreshed by
5064582Scth * the disk node code.
5074582Scth */
5084582Scth if (diskp->frup && (target_diskp == NULL ||
5094582Scth diskp == target_diskp)) {
5104582Scth dm_assert(pthread_mutex_lock(&diskp->fru_mutex) == 0);
5114582Scth dmfru_free(diskp->frup);
5124582Scth diskp->frup = NULL;
5134582Scth dm_assert(pthread_mutex_unlock(&diskp->fru_mutex) == 0);
5144582Scth }
5154582Scth
5164582Scth wdp->pfmri = cstr;
5174582Scth nvlist_free(nvlp);
5184582Scth return (0);
5194582Scth }
5204582Scth
5214582Scth /*
5224582Scth * Determine the physical path to the attachment point
5234582Scth */
5244582Scth if (topo_prop_get_string(node, TOPO_PGROUP_IO,
5255117Smyers TOPO_IO_AP_PATH, &unadj_physid, &err) == 0) {
5264582Scth
5275117Smyers adjust_dynamic_ap(unadj_physid, physid);
5285117Smyers topo_hdl_strfree(thp, unadj_physid);
5295117Smyers } else {
5305117Smyers
5315117Smyers /* unadj_physid cannot have been allocated */
5324582Scth if (cstr)
5334582Scth dstrfree(cstr);
5344582Scth nvlist_free(nvlp);
5354582Scth return (-1);
5364582Scth }
5374582Scth
5384582Scth /*
5395117Smyers */
5405117Smyers
5415117Smyers /*
5424582Scth * Process the properties. If we encounter a property that
5434582Scth * is not an indicator name, action, or rule, add it to the
5444582Scth * disk's props list.
5454582Scth */
5464582Scth
5474582Scth /* Process indicators */
5484582Scth i = 0;
5494582Scth indicator_name = NULL;
5504582Scth indicator_action = NULL;
5514582Scth do {
5524582Scth if (indicator_name != NULL && indicator_action != NULL) {
5534582Scth
5544582Scth if (topoprop_indicator_add(&indp, indicator_name,
5554582Scth indicator_action) != 0) {
5564582Scth
5574582Scth conf_failure = B_TRUE;
5584582Scth }
5594582Scth
5604582Scth topo_hdl_strfree(thp, indicator_name);
5614582Scth topo_hdl_strfree(thp, indicator_action);
5624582Scth }
5634582Scth
5644582Scth (void) snprintf(pname, PNAME_MAX, BAY_IND_NAME "-%d", i);
5654582Scth if (topo_prop_get_string(node, DISK_MONITOR_PROPERTIES,
5664582Scth pname, &indicator_name, &err) != 0)
5674582Scth break;
5684582Scth
5694582Scth (void) snprintf(pname, PNAME_MAX, BAY_IND_ACTION "-%d", i);
5704582Scth if (topo_prop_get_string(node, DISK_MONITOR_PROPERTIES,
5714582Scth pname, &indicator_action, &err) != 0)
5724582Scth break;
5734582Scth
5744582Scth i++;
5754582Scth } while (!conf_failure && indicator_name != NULL &&
5764582Scth indicator_action != NULL);
5774582Scth
5784582Scth if (!conf_failure && indp != NULL &&
5794582Scth (conferr = check_inds(indp)) != E_NO_ERROR) {
5804582Scth conf_error_msg(conferr, msgbuf, MAX_CONF_MSG_LEN, NULL);
5814582Scth log_msg(MM_CONF, "%s: Not adding disk to list\n", msgbuf);
5824582Scth conf_failure = B_TRUE;
5834582Scth }
5844582Scth
5854582Scth /* Process state rules and indicator actions */
5864582Scth i = 0;
5874582Scth indrule_states = NULL;
5884582Scth indrule_actions = NULL;
5894582Scth do {
5904582Scth if (indrule_states != NULL && indrule_actions != NULL) {
5914582Scth
5924582Scth if (topoprop_indrule_add(&indrp, indrule_states,
5934582Scth indrule_actions) != 0) {
5944582Scth
5954582Scth conf_failure = B_TRUE;
5964582Scth }
5974582Scth
5984582Scth topo_hdl_strfree(thp, indrule_states);
5994582Scth topo_hdl_strfree(thp, indrule_actions);
6004582Scth }
6014582Scth
6024582Scth (void) snprintf(pname, PNAME_MAX, BAY_INDRULE_STATES "-%d", i);
6034582Scth if (topo_prop_get_string(node, DISK_MONITOR_PROPERTIES,
6044582Scth pname, &indrule_states, &err) != 0)
6054582Scth break;
6064582Scth
6074582Scth (void) snprintf(pname, PNAME_MAX, BAY_INDRULE_ACTIONS "-%d",
6084582Scth i);
6094582Scth if (topo_prop_get_string(node, DISK_MONITOR_PROPERTIES,
6104582Scth pname, &indrule_actions, &err) != 0)
6114582Scth break;
6124582Scth
6134582Scth i++;
6144582Scth } while (!conf_failure && indrule_states != NULL &&
6154582Scth indrule_actions != NULL);
6164582Scth
6174582Scth if (!conf_failure && indrp != NULL && indp != NULL &&
6184582Scth ((conferr = check_indrules(indrp, (state_transition_t **)&ptr))
6194582Scth != E_NO_ERROR ||
6204582Scth (conferr = check_consistent_ind_indrules(indp, indrp,
6214582Scth (ind_action_t **)&ptr)) != E_NO_ERROR)) {
6224582Scth
6234582Scth conf_error_msg(conferr, msgbuf, MAX_CONF_MSG_LEN, ptr);
6244582Scth log_msg(MM_CONF, "%s: Not adding disk to list\n", msgbuf);
6254582Scth conf_failure = B_TRUE;
6264582Scth
6274582Scth }
6284582Scth
6294582Scth /*
6304582Scth * Now collect miscellaneous properties.
6314582Scth * Each property is stored as an embedded nvlist named
6324582Scth * TOPO_PROP_VAL. The property name is stored in the value for
6334582Scth * key=TOPO_PROP_VAL_NAME and the property's value is
6344582Scth * stored in the value for key=TOPO_PROP_VAL_VAL. This is all
6354582Scth * necessary so we can subtractively decode the properties that
6364582Scth * we do not directly handle (so that these properties are added to
6374582Scth * the per-disk properties nvlist), increasing flexibility.
6384582Scth */
6394582Scth (void) nvlist_alloc(&diskprops, NV_UNIQUE_NAME, 0);
6404582Scth while ((nvp = nvlist_next_nvpair(nvlp, nvp)) != NULL) {
6414582Scth /* Only care about embedded nvlists named TOPO_PROP_VAL */
6424582Scth if (nvpair_type(nvp) != DATA_TYPE_NVLIST ||
6434582Scth strcmp(nvpair_name(nvp), TOPO_PROP_VAL) != 0 ||
6444582Scth nvpair_value_nvlist(nvp, &prop_nvlp) != 0)
6454582Scth continue;
6464582Scth
6474582Scth if (nonunique_nvlist_lookup_string(prop_nvlp,
6484582Scth TOPO_PROP_VAL_NAME, &prop_name) != 0)
6494582Scth continue;
6504582Scth
6514582Scth /* Filter out indicator properties */
6524582Scth if (strstr(prop_name, BAY_IND_NAME) != NULL ||
6534582Scth strstr(prop_name, BAY_IND_ACTION) != NULL ||
6544582Scth strstr(prop_name, BAY_INDRULE_STATES) != NULL ||
6554582Scth strstr(prop_name, BAY_INDRULE_ACTIONS) != NULL)
6564582Scth continue;
6574582Scth
6584582Scth if (nonunique_nvlist_lookup_string(prop_nvlp, TOPO_PROP_VAL_VAL,
6594582Scth &prop_value) != 0)
6604582Scth continue;
6614582Scth
6624582Scth /* Add the property to the disk's prop list: */
6634582Scth if (nvlist_add_string(diskprops, prop_name, prop_value) != 0)
6644582Scth log_msg(MM_TOPO,
6654582Scth "Could not add disk property `%s' with "
6664582Scth "value `%s'\n", prop_name, prop_value);
6674582Scth }
6684582Scth
6694582Scth nvlist_free(nvlp);
6704582Scth
6714582Scth if (cstr != NULL) {
6724582Scth namevalpr_t nvpr;
6734582Scth nvlist_t *dmap_nvl;
6744582Scth
6754582Scth nvpr.name = DISK_AP_PROP_APID;
6764582Scth nvpr.value = strncmp(physid, "/devices", 8) == 0 ?
6774582Scth (physid + 8) : physid;
6784582Scth
6794582Scth /*
6804582Scth * Set the diskmon's location to the value in this port's label.
6814582Scth * If there's a disk plugged in, the location will be updated
6824582Scth * to be the disk label (e.g. HD_ID_00). Until a disk is
6834582Scth * inserted, though, there won't be a disk libtopo node
6844582Scth * created.
6854582Scth */
6864582Scth
6874582Scth /* Pass physid without the leading "/devices": */
6884582Scth dmap_nvl = namevalpr_to_nvlist(&nvpr);
6894582Scth
6904582Scth diskp = new_diskmon(dmap_nvl, indp, indrp, diskprops);
6914582Scth
6924582Scth if (topo_node_label(node, &label, &err) == 0) {
6934582Scth diskp->location = dstrdup(label);
6944582Scth topo_hdl_strfree(thp, label);
6954582Scth } else
6964582Scth diskp->location = dstrdup("unknown location");
6974582Scth
6984582Scth if (!conf_failure && diskp != NULL) {
6994582Scth /* Add this diskmon to the disk list */
7004582Scth cfgdata_add_diskmon(config_data, diskp);
7014582Scth if (nvlist_add_uint64(g_topo2diskmon, cstr,
7024582Scth (uint64_t)(uintptr_t)diskp) != 0) {
7034582Scth log_msg(MM_TOPO,
7044582Scth "Could not add pointer to nvlist "
7054582Scth "for `%s'!\n", cstr);
7064582Scth }
7074582Scth } else if (diskp != NULL) {
7084582Scth diskmon_free(diskp);
7094582Scth } else {
7104582Scth if (dmap_nvl)
7114582Scth nvlist_free(dmap_nvl);
7124582Scth if (indp)
7134582Scth ind_free(indp);
7144582Scth if (indrp)
7154582Scth indrule_free(indrp);
7164582Scth if (diskprops)
7174582Scth nvlist_free(diskprops);
7184582Scth }
7194582Scth
7204582Scth wdp->pfmri = cstr;
7214582Scth }
7224582Scth
7234582Scth
7244582Scth return (0);
7254582Scth }
7264582Scth
7274582Scth /*ARGSUSED*/
7284582Scth static int
gather_topo_cfg(topo_hdl_t * thp,tnode_t * node,void * arg)7294582Scth gather_topo_cfg(topo_hdl_t *thp, tnode_t *node, void *arg)
7304582Scth {
7314582Scth char *nodename = topo_node_name(node);
7324582Scth if (strcmp(DISK, nodename) == 0)
7334582Scth return (topo_add_disk(thp, node, (walk_diskmon_t *)arg)
7344582Scth ? TOPO_WALK_ERR : TOPO_WALK_NEXT);
7354582Scth else if (strcmp(BAY, nodename) == 0)
7364582Scth return (topo_add_bay(thp, node, (walk_diskmon_t *)arg)
7374582Scth ? TOPO_WALK_ERR : TOPO_WALK_NEXT);
7384582Scth
7394582Scth return (TOPO_WALK_NEXT);
7404582Scth }
7414582Scth
7424582Scth
7434582Scth /*ARGSUSED*/
7444582Scth int
update_configuration_from_topo(fmd_hdl_t * hdl,diskmon_t * diskp)7454582Scth update_configuration_from_topo(fmd_hdl_t *hdl, diskmon_t *diskp)
7464582Scth {
7474582Scth int err;
7484582Scth topo_hdl_t *thp;
7494582Scth topo_walk_t *twp;
7504582Scth walk_diskmon_t wd;
7514582Scth
7524582Scth if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL) {
7534582Scth return (TOPO_OPEN_ERROR);
7544582Scth }
7554582Scth
7564582Scth wd.target = diskp;
7574582Scth wd.pfmri = NULL;
7584582Scth if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC, gather_topo_cfg,
7594582Scth &wd, &err)) == NULL) {
7604582Scth fmd_hdl_topo_rele(hdl, thp);
7614582Scth return (err ? TOPO_WALK_INIT_ERROR : TOPO_SUCCESS);
7624582Scth }
7634582Scth
7644582Scth if (topo_walk_step(twp, TOPO_WALK_CHILD) == TOPO_WALK_ERR) {
7654582Scth
7664582Scth topo_walk_fini(twp);
7674582Scth if (wd.pfmri != NULL)
7684582Scth dstrfree(wd.pfmri);
7694582Scth
7704582Scth fmd_hdl_topo_rele(hdl, thp);
7714582Scth return (TOPO_WALK_ERROR);
7724582Scth }
7734582Scth
7744582Scth topo_walk_fini(twp);
7754582Scth fmd_hdl_topo_rele(hdl, thp);
7764582Scth if (wd.pfmri != NULL)
7774582Scth dstrfree(wd.pfmri);
7784582Scth
7794582Scth return (TOPO_SUCCESS);
7804582Scth }
7814582Scth
7824582Scth int
init_configuration_from_topo(void)7834582Scth init_configuration_from_topo(void)
7844582Scth {
7854582Scth return (nvlist_alloc(&g_topo2diskmon, NV_UNIQUE_NAME, 0));
7864582Scth }
7874582Scth
7884582Scth void
fini_configuration_from_topo(void)7894582Scth fini_configuration_from_topo(void)
7904582Scth {
7914582Scth if (g_topo2diskmon) {
7924582Scth nvlist_free(g_topo2diskmon);
7934582Scth }
7944582Scth }
795