Beispiel #1
0
static int
amd_dramchan_create(topo_mod_t *mod, tnode_t *pnode, const char *name,
    nvlist_t *auth)
{
	tnode_t *chnode;
	nvlist_t *fmri;
	char *socket;
	int i, nchan;
	nvlist_t *pfmri = NULL;
	int err, nerr = 0;

	/*
	 * We will enumerate the number of channels present even if only
	 * channel A is in use (i.e., running in 64-bit mode).  Only
	 * the socket 754 package has a single channel.
	 */
	if (topo_prop_get_string(pnode, PGNAME(MCT), "socket",
	    &socket, &err) == 0 && strcmp(socket, "Socket 754") == 0)
		nchan = 1;
	else
		nchan = 2;

	topo_mod_strfree(mod, socket);

	if (topo_node_range_create(mod, pnode, name, 0, nchan - 1) < 0)
		return (-1);

	(void) topo_node_fru(pnode, &pfmri, NULL, &err);

	for (i = 0; i < nchan; i++) {
		if (mkrsrc(mod, pnode, name, i, auth, &fmri) != 0) {
			whinge(mod, &nerr, "amd_dramchan_create: mkrsrc "
			    "failed\n");
			continue;
		}

		if ((chnode = topo_node_bind(mod, pnode, name, i, fmri))
		    == NULL) {
			nvlist_free(fmri);
			whinge(mod, &nerr, "amd_dramchan_create: node bind "
			    "failed\n");
			continue;
		}

		(void) topo_node_asru_set(chnode, fmri, 0, &err);
		if (pfmri)
			(void) topo_node_fru_set(chnode, pfmri, 0, &err);

		nvlist_free(fmri);

		(void) topo_pgroup_create(chnode, &chan_pgroup, &err);

		(void) topo_prop_set_string(chnode, PGNAME(CHAN), "channel",
		    TOPO_PROP_IMMUTABLE, i == 0 ? "A" : "B", &err);
	}
	nvlist_free(pfmri);

	return (nerr == 0 ? 0 : -1);
}
Beispiel #2
0
int
disk_mptsas_find_disk(topo_mod_t *mod, tnode_t *baynode, char **sas_address)
{
	char *devctl = NULL;
	uint32_t enclosure, slot;
	int err;
	char *elem, *lastp;
	int ret = -1;

	/*
	 * Get the required properties from the node.  These come from
	 * the static XML mapping.
	 */
	if (topo_prop_get_string(baynode, TOPO_PGROUP_BINDING,
	    TOPO_BINDING_DEVCTL, &devctl, &err) != 0 ||
	    topo_prop_get_uint32(baynode, TOPO_PGROUP_BINDING,
	    TOPO_BINDING_ENCLOSURE, &enclosure, &err) != 0 ||
	    topo_prop_get_uint32(baynode, TOPO_PGROUP_BINDING,
	    TOPO_BINDING_SLOT, &slot, &err) != 0) {
		if (devctl != NULL)
			topo_mod_strfree(mod, devctl);
		topo_mod_dprintf(mod, "bay node was missing mpt_sas binding "
		    "properties\n");
		return (-1);
	}

	/*
	 * devctl is a (potentially) pipe-separated list of different device
	 * paths to try.
	 */
	if ((elem = topo_mod_strsplit(mod, devctl, "|", &lastp)) != NULL) {
		boolean_t done = B_FALSE;
		do {
			topo_mod_dprintf(mod, "trying mpt_sas instance at %s\n",
			    elem);

			ret = get_sas_address(mod, elem, enclosure,
			    slot, sas_address);

			/*
			 * Only try further devctl paths from the list if this
			 * one was not found:
			 */
			if (ret == 0 || errno != ENOENT) {
				done = B_TRUE;
			} else {
				topo_mod_dprintf(mod, "instance not found\n");
			}

			topo_mod_strfree(mod, elem);

		} while (!done && (elem = topo_mod_strsplit(mod, NULL, "|",
		    &lastp)) != NULL);
	}

	topo_mod_strfree(mod, devctl);
	return (ret);
}
Beispiel #3
0
static topo_mod_t *
hb_enumr_load(topo_mod_t *mp, tnode_t *parent)
{
	topo_mod_t *rp = NULL;
	char *plat, *mach;
	char *hbpath;
	char *rootdir;
	int err;

	plat = mach = NULL;

	if (topo_prop_get_string(parent,
	    TOPO_PGROUP_SYSTEM, TOPO_PROP_PLATFORM, &plat, &err) < 0) {
		(void) topo_mod_seterrno(mp, err);
		return (NULL);
	}
	if (topo_prop_get_string(parent,
	    TOPO_PGROUP_SYSTEM, TOPO_PROP_MACHINE, &mach, &err) < 0) {
		(void) topo_mod_seterrno(mp, err);
		return (NULL);
	}
	hbpath = topo_mod_alloc(mp, PATH_MAX);
	rootdir = topo_mod_rootdir(mp);
	(void) snprintf(hbpath,
	    PATH_MAX, PATH_TO_HB_ENUM, rootdir ? rootdir : "", plat);

	if ((rp = topo_mod_load(mp, hbpath)) == NULL) {
		topo_mod_dprintf(mp,
		    "%s enumerator could not load %s.\n", IOBOARD, hbpath);
		(void) snprintf(hbpath,
		    PATH_MAX, PATH_TO_HB_ENUM, rootdir ? rootdir : "", mach);
		if ((rp = topo_mod_load(mp, hbpath)) == NULL) {
			topo_mod_dprintf(mp,
			    "%s enumerator could not load %s.\n",
			    IOBOARD, hbpath);
		}
	}
	topo_mod_strfree(mp, plat);
	topo_mod_strfree(mp, mach);
	topo_mod_free(mp, hbpath, PATH_MAX);
	return (rp);
}
Beispiel #4
0
static topo_mod_t *
module_load(topo_mod_t *mp, tnode_t *parent, const char *name)
{
	topo_mod_t *rp = NULL;
	char *plat, *mach;
	char *path;
	char *rootdir;
	int err;

	plat = mach = NULL;

	if (topo_prop_get_string(parent,
	    TOPO_PGROUP_SYSTEM, TOPO_PROP_PLATFORM, &plat, &err) < 0) {
		(void) topo_mod_seterrno(mp, err);
		return (NULL);
	}
	if (topo_prop_get_string(parent,
	    TOPO_PGROUP_SYSTEM, TOPO_PROP_MACHINE, &mach, &err) < 0) {
		(void) topo_mod_seterrno(mp, err);
		return (NULL);
	}
	path = topo_mod_alloc(mp, PATH_MAX);
	rootdir = topo_mod_rootdir(mp);
	(void) snprintf(path, PATH_MAX,
	    PATH_TEMPLATE, rootdir ? rootdir : "", plat, name);

	if ((rp = topo_mod_load(mp, path)) == NULL) {
		topo_mod_dprintf(mp, "Unable to load %s.\n", path);
		(void) snprintf(path, PATH_MAX,
		    PATH_TEMPLATE, rootdir ? rootdir : "", mach, name);
		if ((rp = topo_mod_load(mp, path)) == NULL)
			topo_mod_dprintf(mp, "Unable to load %s.\n", path);
	}
	topo_mod_strfree(mp, plat);
	topo_mod_strfree(mp, mach);
	topo_mod_free(mp, path, PATH_MAX);
	return (rp);
}
Beispiel #5
0
int
pcifn_enum(topo_mod_t *mp, tnode_t *parent)
{
	char *ccstr;
	int rv = 0;
	int i, e;
	uint_t cc;
	topo_mod_t *child_mod;

	topo_mod_dprintf(mp, "Enumerating beneath pci(ex) function.\n");

	/*
	 * Extract the class code of the PCI function and make sure
	 * it matches the type that the module cares about.
	 */
	if (topo_prop_get_string(parent,
	    TOPO_PGROUP_PCI, TOPO_PROP_CLASS, &ccstr, &e) < 0)
		return (0);
	if (sscanf(ccstr, "%x", &cc) != 1) {
		topo_mod_strfree(mp, ccstr);
		return (0);
	}
	topo_mod_strfree(mp, ccstr);
	cc = cc >> 16;

	for (i = 0; i < Pcifn_enumerator_count; i++) {

		if (cc != Pcifn_enumerators[i].pfne_class)
			continue;

		child_mod = module_load(mp, parent,
		    Pcifn_enumerators[i].pfne_modname);

		if (child_mod) {
			rv = module_run(mp, parent,
			    &Pcifn_enumerators[i]) != 0 ? -1 : 0;
			topo_mod_unload(child_mod);
		}
	}
	return (rv);
}
Beispiel #6
0
static int
topo_add_bay(topo_hdl_t *thp, tnode_t *node, walk_diskmon_t *wdp)
{
	diskmon_t *target_diskp = wdp->target;
	nvlist_t	*nvlp = find_disk_monitor_private_pgroup(node);
	nvlist_t	*prop_nvlp;
	nvpair_t	*nvp = NULL;
	char		*prop_name, *prop_value;
#define	PNAME_MAX 128
	char		pname[PNAME_MAX];
	char		msgbuf[MAX_CONF_MSG_LEN];
	char		*indicator_name, *indicator_action;
	char		*indrule_states, *indrule_actions;
	int		err = 0, i;
	conf_err_t	conferr;
	boolean_t	conf_failure = B_FALSE;
	char		*unadj_physid = NULL;
	char		physid[MAXPATHLEN];
	char		*label;
	nvlist_t	*diskprops = NULL;
	char		*cstr = NULL;
	indicator_t	*indp = NULL;
	indrule_t	*indrp = NULL;
	void		*p;
	diskmon_t	*diskp;
	void		*ptr;

	/* No private properties -- just ignore the port */
	if (nvlp == NULL)
		return (0);

	/*
	 * Look for a diskmon based on this node's FMRI string.
	 * Once a diskmon has been created, it's not re-created.  This is
	 * essential for the times when the tree-walk is called after a
	 * disk is inserted (or removed) -- in that case, the disk node
	 * handler simply updates the FRU information in the diskmon.
	 */
	if ((p = fmri2ptr(thp, node, &cstr, &err)) != NULL) {

		diskp = (diskmon_t *)p;

		/*
		 * Delete the FRU information from the diskmon.  If a disk
		 * is connected, its FRU information will be refreshed by
		 * the disk node code.
		 */
		if (diskp->frup && (target_diskp == NULL ||
		    diskp == target_diskp)) {
			dm_assert(pthread_mutex_lock(&diskp->fru_mutex) == 0);
			dmfru_free(diskp->frup);
			diskp->frup = NULL;
			dm_assert(pthread_mutex_unlock(&diskp->fru_mutex) == 0);
		}

		wdp->pfmri = cstr;
		nvlist_free(nvlp);
		return (0);
	}

	/*
	 * Determine the physical path to the attachment point
	 */
	if (topo_prop_get_string(node, TOPO_PGROUP_IO,
	    TOPO_IO_AP_PATH, &unadj_physid, &err) == 0) {

		adjust_dynamic_ap(unadj_physid, physid);
		topo_hdl_strfree(thp, unadj_physid);
	} else {

		/* unadj_physid cannot have been allocated */
		if (cstr)
			dstrfree(cstr);
		nvlist_free(nvlp);
		return (-1);
	}

	/*
	 */

	/*
	 * Process the properties.  If we encounter a property that
	 * is not an indicator name, action, or rule, add it to the
	 * disk's props list.
	 */

	/* Process indicators */
	i = 0;
	indicator_name = NULL;
	indicator_action = NULL;
	do {
		if (indicator_name != NULL && indicator_action != NULL) {

			if (topoprop_indicator_add(&indp, indicator_name,
			    indicator_action) != 0) {

				conf_failure = B_TRUE;
			}

			topo_hdl_strfree(thp, indicator_name);
			topo_hdl_strfree(thp, indicator_action);
		}

		(void) snprintf(pname, PNAME_MAX, BAY_IND_NAME "-%d", i);
		if (topo_prop_get_string(node, DISK_MONITOR_PROPERTIES,
		    pname, &indicator_name, &err) != 0)
			break;

		(void) snprintf(pname, PNAME_MAX, BAY_IND_ACTION "-%d", i);
		if (topo_prop_get_string(node, DISK_MONITOR_PROPERTIES,
		    pname, &indicator_action, &err) != 0)
			break;

		i++;
	} while (!conf_failure && indicator_name != NULL &&
	    indicator_action != NULL);

	if (!conf_failure && indp != NULL &&
	    (conferr = check_inds(indp)) != E_NO_ERROR) {
		conf_error_msg(conferr, msgbuf, MAX_CONF_MSG_LEN, NULL);
		log_msg(MM_CONF, "%s: Not adding disk to list\n", msgbuf);
		conf_failure = B_TRUE;
	}

	/* Process state rules and indicator actions */
	i = 0;
	indrule_states = NULL;
	indrule_actions = NULL;
	do {
		if (indrule_states != NULL && indrule_actions != NULL) {

			if (topoprop_indrule_add(&indrp, indrule_states,
			    indrule_actions) != 0) {

				conf_failure = B_TRUE;
			}

			topo_hdl_strfree(thp, indrule_states);
			topo_hdl_strfree(thp, indrule_actions);
		}

		(void) snprintf(pname, PNAME_MAX, BAY_INDRULE_STATES "-%d", i);
		if (topo_prop_get_string(node, DISK_MONITOR_PROPERTIES,
		    pname, &indrule_states, &err) != 0)
			break;

		(void) snprintf(pname, PNAME_MAX, BAY_INDRULE_ACTIONS "-%d",
		    i);
		if (topo_prop_get_string(node, DISK_MONITOR_PROPERTIES,
		    pname, &indrule_actions, &err) != 0)
			break;

		i++;
	} while (!conf_failure && indrule_states != NULL &&
	    indrule_actions != NULL);

	if (!conf_failure && indrp != NULL && indp != NULL &&
	    ((conferr = check_indrules(indrp, (state_transition_t **)&ptr))
	    != E_NO_ERROR ||
	    (conferr = check_consistent_ind_indrules(indp, indrp,
	    (ind_action_t **)&ptr)) != E_NO_ERROR)) {

		conf_error_msg(conferr, msgbuf, MAX_CONF_MSG_LEN, ptr);
		log_msg(MM_CONF, "%s: Not adding disk to list\n", msgbuf);
		conf_failure = B_TRUE;

	}

	/*
	 * Now collect miscellaneous properties.
	 * Each property is stored as an embedded nvlist named
	 * TOPO_PROP_VAL.  The property name is stored in the value for
	 * key=TOPO_PROP_VAL_NAME and the property's value is
	 * stored in the value for key=TOPO_PROP_VAL_VAL.  This is all
	 * necessary so we can subtractively decode the properties that
	 * we do not directly handle (so that these properties are added to
	 * the per-disk properties nvlist), increasing flexibility.
	 */
	(void) nvlist_alloc(&diskprops, NV_UNIQUE_NAME, 0);
	while ((nvp = nvlist_next_nvpair(nvlp, nvp)) != NULL) {
		/* Only care about embedded nvlists named TOPO_PROP_VAL */
		if (nvpair_type(nvp) != DATA_TYPE_NVLIST ||
		    strcmp(nvpair_name(nvp), TOPO_PROP_VAL) != 0 ||
		    nvpair_value_nvlist(nvp, &prop_nvlp) != 0)
			continue;

		if (nonunique_nvlist_lookup_string(prop_nvlp,
		    TOPO_PROP_VAL_NAME, &prop_name) != 0)
			continue;

		/* Filter out indicator properties */
		if (strstr(prop_name, BAY_IND_NAME) != NULL ||
		    strstr(prop_name, BAY_IND_ACTION) != NULL ||
		    strstr(prop_name, BAY_INDRULE_STATES) != NULL ||
		    strstr(prop_name, BAY_INDRULE_ACTIONS) != NULL)
			continue;

		if (nonunique_nvlist_lookup_string(prop_nvlp, TOPO_PROP_VAL_VAL,
		    &prop_value) != 0)
			continue;

		/* Add the property to the disk's prop list: */
		if (nvlist_add_string(diskprops, prop_name, prop_value) != 0)
			log_msg(MM_TOPO,
			    "Could not add disk property `%s' with "
			    "value `%s'\n", prop_name, prop_value);
	}

	nvlist_free(nvlp);

	if (cstr != NULL) {
		namevalpr_t nvpr;
		nvlist_t *dmap_nvl;

		nvpr.name = DISK_AP_PROP_APID;
		nvpr.value = strncmp(physid, "/devices", 8) == 0 ?
		    (physid + 8) : physid;

		/*
		 * Set the diskmon's location to the value in this port's label.
		 * If there's a disk plugged in, the location will be updated
		 * to be the disk label (e.g. HD_ID_00).  Until a disk is
		 * inserted, though, there won't be a disk libtopo node
		 * created.
		 */

		/* Pass physid without the leading "/devices": */
		dmap_nvl = namevalpr_to_nvlist(&nvpr);

		diskp = new_diskmon(dmap_nvl, indp, indrp, diskprops);

		if (topo_node_label(node, &label, &err) == 0) {
			diskp->location = dstrdup(label);
			topo_hdl_strfree(thp, label);
		} else
			diskp->location = dstrdup("unknown location");

		if (!conf_failure && diskp != NULL) {
			/* Add this diskmon to the disk list */
			cfgdata_add_diskmon(config_data, diskp);
			if (nvlist_add_uint64(g_topo2diskmon, cstr,
			    (uint64_t)(uintptr_t)diskp) != 0) {
				log_msg(MM_TOPO,
				    "Could not add pointer to nvlist "
				    "for `%s'!\n", cstr);
			}
		} else if (diskp != NULL) {
			diskmon_free(diskp);
		} else {
			if (dmap_nvl)
				nvlist_free(dmap_nvl);
			if (indp)
				ind_free(indp);
			if (indrp)
				indrule_free(indrp);
			if (diskprops)
				nvlist_free(diskprops);
		}

		wdp->pfmri = cstr;
	}


	return (0);
}
Beispiel #7
0
static int
topo_add_disk(topo_hdl_t *thp, tnode_t *node, walk_diskmon_t *wdp)
{
	diskmon_t *target_diskp = wdp->target;
	char		*devpath = NULL;
	char		*capacity = NULL;
	char		*firmrev = NULL;
	char		*serial = NULL;
	char		*manuf = NULL;
	char		*model = NULL;
	char		*label;
	uint64_t	ptr = 0;
	int		err;
	dm_fru_t	*frup;
	diskmon_t	*diskp;

	if (wdp->pfmri == NULL) {
		log_msg(MM_TOPO, "No diskmon for parent of node %p.\n", node);
		return (0);
	}

	if (nvlist_lookup_uint64(g_topo2diskmon, wdp->pfmri, &ptr) != 0) {
		log_msg(MM_TOPO, "No diskmon for %s: parent of node %p.\n",
		    wdp->pfmri, node);
		dstrfree(wdp->pfmri);
		/* Skip this disk: */
		return (0);
	}

	dstrfree(wdp->pfmri);
	wdp->pfmri = NULL;

	diskp = (diskmon_t *)(uintptr_t)ptr;

	/* If we were called upon to update a particular disk, do it */
	if (target_diskp != NULL && diskp != target_diskp) {
		return (0);
	}

	/*
	 * Update the diskmon's location field with the disk's label
	 */
	if (diskp->location)
		dstrfree(diskp->location);
	if (topo_node_label(node, &label, &err) == 0) {
		diskp->location = dstrdup(label);
		topo_hdl_strfree(thp, label);
	} else
		diskp->location = dstrdup("unknown location");

	/*
	 * Check for a device path property (if the disk is configured,
	 * it will be present) and add it to the diskmon's properties)
	 */
	if (topo_prop_get_string(node, TOPO_PGROUP_IO, TOPO_IO_DEV_PATH,
	    &devpath, &err) == 0) {
		char devp[PATH_MAX];
		/*
		 * Consumers of the DISK_PROP_DEVPATH property expect a raw
		 * minor device node
		 */
		(void) snprintf(devp, PATH_MAX, "%s:q,raw", devpath);
		(void) nvlist_add_string(diskp->props, DISK_PROP_DEVPATH,
		    devp);
		topo_hdl_strfree(thp, devpath);
	}

	/*
	 * Add the logical disk node, if it exists
	 */
	if (topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
	    TOPO_STORAGE_LOGICAL_DISK_NAME, &devpath, &err) == 0) {
		(void) nvlist_add_string(diskp->props, DISK_PROP_LOGNAME,
		    devpath);
		topo_hdl_strfree(thp, devpath);
	}

	/*
	 * Add the FRU information (if present in the node) to the diskmon's
	 * fru data structure:
	 */
	(void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
	    TOPO_STORAGE_MODEL, &model, &err);

	(void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
	    TOPO_STORAGE_MANUFACTURER, &manuf, &err);

	(void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
	    TOPO_STORAGE_SERIAL_NUM, &serial, &err);

	(void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
	    TOPO_STORAGE_FIRMWARE_REV, &firmrev, &err);

	(void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
	    TOPO_STORAGE_CAPACITY, &capacity, &err);

	frup = new_dmfru(manuf, model, firmrev, serial,
	    capacity == NULL ? 0 : strtoull(capacity, 0, 0));

	if (model)
		topo_hdl_strfree(thp, model);
	if (manuf)
		topo_hdl_strfree(thp, manuf);
	if (serial)
		topo_hdl_strfree(thp, serial);
	if (firmrev)
		topo_hdl_strfree(thp, firmrev);
	if (capacity)
		topo_hdl_strfree(thp, capacity);

	/* Add the fru information to the diskmon: */
	dm_assert(pthread_mutex_lock(&diskp->fru_mutex) == 0);
	dm_assert(diskp->frup == NULL);
	diskp->frup = frup;
	dm_assert(pthread_mutex_unlock(&diskp->fru_mutex) == 0);

	return (0);
}
Beispiel #8
0
static int
topo_add_disk(topo_hdl_t *thp, tnode_t *node, diskmon_t *target_diskp)
{
	nvlist_t	*fmri = NULL;
	nvlist_t	*asru_fmri;
	nvlist_t	*fru_fmri;
	char		*devpath = NULL;
	char		*capacity = NULL;
	char		*firmrev = NULL;
	char		*serial = NULL;
	char		*manuf = NULL;
	char		*model = NULL;
	char		*cstr = NULL;
	char		*buf;
	char		*label;
	char		*p;
	uint64_t	ptr = 0;
	int		buflen;
	int		err;
	int		orig_cstr_len;
	dm_fru_t	*frup;
	diskmon_t	*diskp;

	/*
	 * Match this node to a disk in the configuration by looking at
	 * our parent's fmri (and do that by getting our FMRI and chopping
	 * off the last part).
	 */
	if (topo_node_resource(node, &fmri, &err) != 0) {
		log_msg(MM_TOPO, "topo_add_disk: Could not generate FMRI for "
		    "node %p!\n", (void *)node);
		return (-1);
	}

	if (topo_fmri_nvl2str(thp, fmri, &cstr, &err) != 0) {
		log_msg(MM_TOPO, "topo_add_disk: Could not create string for "
		    "node %p's FMRI!\n", (void *)node);
		nvlist_free(fmri);
		return (-1);
	}

	nvlist_free(fmri);

	/*
	 * Chop off all but last path (since there's no way to get
	 * the node's parent in the libtopo API).
	 */
	orig_cstr_len = strlen(cstr) + 1;
	p = strrchr(cstr, '/');
	dm_assert(p != NULL);
	*p = 0;
	if (nvlist_lookup_uint64(g_topo2diskmon, cstr, &ptr) != 0) {
		log_msg(MM_TOPO, "No diskmon for parent of node %p.\n", node);
		topo_hdl_free(thp, cstr, orig_cstr_len);
		/* Skip this disk: */
		return (0);
	}

	topo_hdl_free(thp, cstr, orig_cstr_len);

	diskp = (diskmon_t *)(uintptr_t)ptr;

	/* If we were called upon to update a particular disk, do it */
	if (target_diskp != NULL && diskp != target_diskp) {
		return (0);
	}

	/*
	 * Update the diskmon's ASRU and FRU with our information (this
	 * information is cached in the diskmon so we don't have to do a
	 * time-consuming topo traversal when we get an ereport).
	 */
	if (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU,
	    &asru_fmri, &err) == 0) {
		diskmon_add_asru(diskp, asru_fmri);
		nvlist_free(asru_fmri);
	}
	if (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU,
	    &fru_fmri, &err) == 0) {
		diskmon_add_fru(diskp, fru_fmri);
		nvlist_free(fru_fmri);
	}
	if (topo_node_resource(node, &fmri, &err) == 0) {
		diskmon_add_disk_fmri(diskp, fmri);
		nvlist_free(fmri);
	}

	/*
	 * Update the diskmon's location field with the disk's label
	 */
	if (diskp->location)
		dstrfree(diskp->location);
	if (topo_node_label(node, &label, &err) == 0) {
		diskp->location = dstrdup(label);
		topo_hdl_strfree(thp, label);
	} else
		diskp->location = dstrdup("unknown location");

	/*
	 * Check for a device path property (if the disk is configured,
	 * it will be present) and add it to the diskmon's properties)
	 */
	if (topo_prop_get_string(node, TOPO_PGROUP_IO, TOPO_IO_DEV_PATH,
	    &devpath, &err) == 0) {
		char devp[PATH_MAX];
		/*
		 * Consumers of the DISK_PROP_DEVPATH property expect a raw
		 * minor device node
		 */
		(void) snprintf(devp, PATH_MAX, "%s:q,raw", devpath);
		(void) nvlist_add_string(diskp->props, DISK_PROP_DEVPATH,
		    devp);
		topo_hdl_strfree(thp, devpath);
	}

	/*
	 * Add the logical disk node, if it exists
	 */
	if (topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
	    TOPO_STORAGE_LOGICAL_DISK_NAME, &devpath, &err) == 0) {
		(void) nvlist_add_string(diskp->props, DISK_PROP_LOGNAME,
		    devpath);
		topo_hdl_strfree(thp, devpath);
	}

	/*
	 * Add the FRU information (if present in the node) to the diskmon's
	 * fru data structure:
	 */
	(void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
	    TOPO_STORAGE_MODEL, &model, &err);

	(void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
	    TOPO_STORAGE_MANUFACTURER, &manuf, &err);

	(void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
	    TOPO_STORAGE_SERIAL_NUM, &serial, &err);

	(void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
	    TOPO_STORAGE_FIRMWARE_REV, &firmrev, &err);

	(void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
	    TOPO_STORAGE_CAPACITY, &capacity, &err);

	frup = new_dmfru(manuf, model, firmrev, serial,
	    capacity == NULL ? 0 : strtoull(capacity, 0, 0));

	/*
	 * Update the disk's resource FMRI with the
	 * SunService-required members:
	 * FM_FMRI_HC_SERIAL_ID, FM_FMRI_HC_PART, and
	 * FM_FMRI_HC_REVISION
	 */
	(void) nvlist_add_string(diskp->disk_res_fmri,
	    FM_FMRI_HC_SERIAL_ID, serial);

	transform_model_string(manuf, model, &buf, &buflen);

	(void) nvlist_add_string(diskp->disk_res_fmri,
	    FM_FMRI_HC_PART, buf);

	/*
	 * Add the serial number to the ASRU so that when the resource
	 * is marked faulty in the fmd resource cache, the hc scheme
	 * plugin can detect when the disk is no longer installed (and so,
	 * can clear the faulty state automatically across fmd restarts).
	 *
	 * The serial number is only updated when a disk comes online
	 * because that's when the disk node exists in the topo tree.
	 * It's ok to keep a stale value in the ASRU when the disk is removed
	 * because it's only used as part of fault creation when the disk
	 * is configured (online), at which point it will be updated with
	 * the (current) serial number of the disk inserted.
	 */
	(void) nvlist_add_string(diskp->asru_fmri,
	    FM_FMRI_HC_SERIAL_ID, serial);

	dfree(buf, buflen);

	(void) nvlist_add_string(diskp->disk_res_fmri,
	    FM_FMRI_HC_REVISION, firmrev);

	if (model) {
		topo_hdl_strfree(thp, model);
	}

	if (manuf) {
		topo_hdl_strfree(thp, manuf);
	}

	if (serial) {
		topo_hdl_strfree(thp, serial);
	}

	if (firmrev) {
		topo_hdl_strfree(thp, firmrev);
	}

	if (capacity) {
		topo_hdl_strfree(thp, capacity);
	}

	/* Add the fru information to the diskmon: */
	dm_assert(pthread_mutex_lock(&diskp->fru_mutex) == 0);
	dm_assert(diskp->frup == NULL);
	diskp->frup = frup;
	dm_assert(pthread_mutex_unlock(&diskp->fru_mutex) == 0);

	return (0);
}
static int
mptsas_led_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
    nvlist_t *in, nvlist_t **nvout)
{
	int err, ret = 0;
	tnode_t *pnode = topo_node_parent(node);
	uint32_t type, ledmode = 0;
	nvlist_t *pargs, *nvl;
	char *driver = NULL, *devctl = NULL;
	uint32_t enclosure, slot;
	uint8_t mptsas_led;
	boolean_t set;

	if (vers > TOPO_METH_MPTSAS_LED_MODE_VERSION)
		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));

	if (topo_prop_get_string(pnode, TOPO_PGROUP_BINDING,
	    TOPO_BINDING_DRIVER, &driver, &err) != 0 ||
	    strcmp("mpt_sas", driver) != 0) {
		topo_mod_dprintf(mod, "%s: Facility driver was not mpt_sas",
		    __func__);
		ret = topo_mod_seterrno(mod, EMOD_NVL_INVAL);
		goto out;
	}
	if (topo_prop_get_uint32(node, TOPO_PGROUP_FACILITY, TOPO_FACILITY_TYPE,
	    &type, &err) != 0) {
		topo_mod_dprintf(mod, "%s: Failed to lookup %s property "
		    "(%s)", __func__, TOPO_FACILITY_TYPE, topo_strerror(err));
		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
	}
	switch (type) {
	case (TOPO_LED_TYPE_SERVICE):
		mptsas_led = MPTSAS_LEDCTL_LED_FAIL;
		break;
	case (TOPO_LED_TYPE_LOCATE):
		mptsas_led = MPTSAS_LEDCTL_LED_IDENT;
		break;
	case (TOPO_LED_TYPE_OK2RM):
		mptsas_led = MPTSAS_LEDCTL_LED_OK2RM;
		break;
	default:
		topo_mod_dprintf(mod, "%s: Invalid LED type: 0x%x\n", __func__,
		    type);
		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
	}
	if (topo_prop_get_string(pnode, TOPO_PGROUP_BINDING,
	    TOPO_BINDING_DEVCTL, &devctl, &err) != 0 ||
	    topo_prop_get_uint32(pnode, TOPO_PGROUP_BINDING,
	    TOPO_BINDING_ENCLOSURE, &enclosure, &err) != 0 ||
	    topo_prop_get_uint32(pnode, TOPO_PGROUP_BINDING,
	    TOPO_BINDING_SLOT, &slot, &err) != 0) {
		topo_mod_dprintf(mod, "%s: Facility was missing mpt_sas binding"
		    " properties\n", __func__);
		ret = topo_mod_seterrno(mod, EMOD_NVL_INVAL);
		goto out;
	}

	if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
	    nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
		/*
		 * Set the LED mode
		 */
		set = B_TRUE;
		if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
		    &ledmode)) != 0) {
			topo_mod_dprintf(mod, "%s: Failed to lookup %s nvpair "
			    "(%s)\n", __func__, TOPO_PROP_VAL_VAL,
			    strerror(ret));
			ret = topo_mod_seterrno(mod, EMOD_NVL_INVAL);
			goto out;
		}
		topo_mod_dprintf(mod, "%s: Setting LED mode to %s\n", __func__,
		    ledmode ? "ON" : "OFF");
	} else {
		/*
		 * Get the LED mode
		 */
		set = B_FALSE;
		topo_mod_dprintf(mod, "%s: Getting LED mode\n", __func__);
	}

	if (do_led_control(mod, devctl, enclosure, slot, mptsas_led, &ledmode,
	    set) != 0) {
		topo_mod_dprintf(mod, "%s: do_led_control failed", __func__);
		ret = topo_mod_seterrno(mod, EMOD_UNKNOWN);
		goto out;
	}

	if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
	    nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) {
		topo_mod_dprintf(mod, "%s: Failed to allocate 'out' nvlist\n",
		    __func__);
		nvlist_free(nvl);
		ret = topo_mod_seterrno(mod, EMOD_NOMEM);
		goto out;
	}
	*nvout = nvl;

out:
	if (driver != NULL)
		topo_mod_strfree(mod, driver);
	if (devctl != NULL)
		topo_mod_strfree(mod, devctl);
	return (ret);
}
Beispiel #10
0
/*
 * Query the current disk status. If successful, the disk status is returned
 * as an nvlist consisting of at least the following members:
 *
 *	protocol	string		Supported protocol (currently "scsi")
 *
 *	status		nvlist		Arbitrary protocol-specific information
 *					about the current state of the disk.
 *
 *	faults		nvlist		A list of supported faults. Each
 *					element of this list is a boolean value.
 *					An element's existence indicates that
 *					the drive supports detecting this fault,
 *					and the value indicates the current
 *					state of the fault.
 *
 *	<fault-name>	nvlist		For each fault named in 'faults', a
 *					nvlist describing protocol-specific
 *					attributes of the fault.
 *
 * This method relies on the libdiskstatus library to query this information.
 */
static int
disk_status(topo_mod_t *mod, tnode_t *nodep, topo_version_t vers,
    nvlist_t *in_nvl, nvlist_t **out_nvl)
{
	disk_status_t	*dsp;
	char		*devpath, *fullpath;
	size_t		pathlen;
	nvlist_t	*status;
	int		err;

	*out_nvl = NULL;

	if (vers != TOPO_METH_DISK_STATUS_VERSION)
		return (topo_mod_seterrno(mod, EMOD_VER_NEW));

	/*
	 * If the caller specifies the "path" parameter, then this indicates
	 * that we should use this instead of deriving it from the topo node
	 * itself.
	 */
	if (nvlist_lookup_string(in_nvl, "path", &fullpath) == 0) {
		devpath = NULL;
	} else {
		/*
		 * Get the /devices path and attempt to open the disk status
		 * handle.
		 */
		if (topo_prop_get_string(nodep, TOPO_PGROUP_IO,
		    TOPO_IO_DEV_PATH, &devpath, &err) != 0)
			return (topo_mod_seterrno(mod, EMOD_METHOD_NOTSUP));

		/*
		 * Note that sizeof(string) includes the terminating NULL byte
		 */
		pathlen = strlen(devpath) + sizeof ("/devices") +
		    sizeof (PHYS_EXTN) - 1;

		if ((fullpath = topo_mod_alloc(mod, pathlen)) == NULL)
			return (topo_mod_seterrno(mod, EMOD_NOMEM));

		(void) snprintf(fullpath, pathlen, "/devices%s%s", devpath,
		    PHYS_EXTN);

		topo_mod_strfree(mod, devpath);
	}

	if ((dsp = disk_status_open(fullpath, &err)) == NULL) {
		if (devpath)
			topo_mod_free(mod, fullpath, pathlen);
		return (topo_mod_seterrno(mod, err == EDS_NOMEM ?
		    EMOD_NOMEM : EMOD_METHOD_NOTSUP));
	}

	if (devpath)
		topo_mod_free(mod, fullpath, pathlen);

	if ((status = disk_status_get(dsp)) == NULL) {
		err = (disk_status_errno(dsp) == EDS_NOMEM ?
		    EMOD_NOMEM : EMOD_METHOD_NOTSUP);
		disk_status_close(dsp);
		return (topo_mod_seterrno(mod, err));
	}

	*out_nvl = status;
	disk_status_close(dsp);
	return (0);
}
Beispiel #11
0
/*ARGSUSED*/
static int
do_slot_mapping_cb(topo_hdl_t *thp, tnode_t *node, void *arg)
{
	int err, ret;
	nvlist_t *rsrc = NULL;
	const char *match = arg;
	char *s, *fmri = NULL;
	char *didstr = NULL, *driver = NULL, *vidstr = NULL;
	boolean_t printed = B_FALSE;

	ret = TOPO_WALK_NEXT;
	if (topo_node_resource(node, &rsrc, &err) < 0)
		goto next;
	if (topo_fmri_nvl2str(thp, rsrc, &fmri, &err) < 0)
		goto next;

	if ((s = strstr(fmri, match)) == NULL)
		goto next;
	if (s[strlen(match)] != '\0')
		goto next;

	/* At this point we think we've found a match */
	ret = TOPO_WALK_TERMINATE;
	if (topo_prop_get_string(node, TOPO_PGROUP_IO, TOPO_IO_DRIVER, &driver,
	    &err) != 0)
		driver = NULL;

	if (topo_prop_get_string(node, TOPO_PGROUP_PCI, TOPO_PCI_VENDID,
	    &vidstr, &err) != 0)
		goto next;

	if (topo_prop_get_string(node, TOPO_PGROUP_PCI, TOPO_PCI_DEVID,
	    &didstr, &err) != 0)
		goto next;

	if (prt_php != NULL) {
		long vid, did;

		vid = strtol(vidstr, NULL, 16);
		did = strtol(didstr, NULL, 16);
		if (vid >= 0 && vid <= UINT16_MAX &&
		    did >= 0 && did <= UINT16_MAX) {
			pcidb_device_t *pdev;

			pdev = pcidb_lookup_device(prt_php, vid, did);
			if (pdev != NULL) {
				pcidb_vendor_t *pvend;
				pvend = pcidb_device_vendor(pdev);
				(void) printf(gettext(", %s %s (%s)"),
				    pcidb_vendor_name(pvend),
				    pcidb_device_name(pdev),
				    driver != NULL ? driver : "<unknown>");
				printed = B_TRUE;
			}
		}
	}

	if (printed == B_FALSE) {
		(void) printf(gettext(", pci%s,%s (%s)"), vidstr, didstr,
		    driver != NULL ? driver : "<unknown>");
	}
next:
	topo_hdl_strfree(thp, didstr);
	topo_hdl_strfree(thp, driver);
	topo_hdl_strfree(thp, vidstr);
	topo_hdl_strfree(thp, fmri);
	nvlist_free(rsrc);
	return (ret);
}
Beispiel #12
0
int
platform_pci_fru(topo_mod_t *mod, tnode_t *node, nvlist_t *in,
    nvlist_t **out)
{
	int err = 0;
	uint64_t ptr;
	did_t *dp, *pdp;
	tnode_t *pnode;
	char *nm, *plat, *pp, **cp;
	char *label;
	int found_t1plat = 0;
	uchar_t *loc;
	int locsiz;

	topo_mod_dprintf(mod, "entering platform_pci_fru\n");

	if (topo_prop_get_string(node, FM_FMRI_AUTHORITY,
	    FM_FMRI_AUTH_PRODUCT, &plat, &err) < 0) {
		(void) topo_mod_seterrno(mod, err);
		return (-1);
	}
	/* Delete the "SUNW," */
	pp = strchr(plat, ',');
	if (pp == NULL)
		pp = plat;
	else
		++pp;

	/* Is this an UltraSPARC-T1 platform? */
	cp = usT1_plats;
	while ((*cp != NULL) && (found_t1plat == 0)) {
		if (strcmp(pp, *cp) == 0)
			found_t1plat = 1;
		cp++;
	}

	topo_mod_strfree(mod, plat);

	/*
	 * On UltraSPARC-T1 systems, use the legacy hc scheme on
	 * the adapter slots to ensure ALOM on the SP can interpret
	 * the FRU correctly. For everything else, follow the normal
	 * code flow
	 */
	if (found_t1plat) {
		*out = NULL;
		nm = topo_node_name(node);
		if (strcmp(nm, PCI_DEVICE) != 0 &&
		    strcmp(nm, PCIEX_DEVICE) != 0 &&
		    strcmp(nm, PCIEX_BUS) != 0)
			return (0);

		if (nvlist_lookup_uint64(in, "nv1", &ptr) != 0) {
			topo_mod_dprintf(mod, "label method argument "
			    "not found.\n");
			return (-1);
		}
		dp = (did_t *)(uintptr_t)ptr;
		pnode = did_gettnode(dp);
		pdp = did_find(mod, topo_node_getspecific(pnode));

		/*
		 * Is there a slotname associated with the device?
		 */
		if ((label = pci_slot_label_lookup(mod, pnode, dp, pdp))
		    != NULL) {
			nvlist_t *rnvl;
			char buf[PATH_MAX];

			(void) snprintf(buf, PATH_MAX, "hc:///component=%s",
			    label);
			if (topo_mod_str2nvl(mod, buf, &rnvl) < 0)
				return (-1);
			*out = rnvl;
		}
		return (0);
	} else if (di_bytes_get(mod, topo_node_getspecific(node),
	    PI_PROP_CHASSIS_LOCATION_NAME, &locsiz, &loc) == 0 && locsiz > 0) {
		/*
		 * We have crossed a FRU boundary and need to find the parent
		 * node with this location and set our FMRI to that value.
		 */
		return (platform_pci_fru_location(mod, node, loc, locsiz));
	} else {
		return (pci_fru_compute(mod, node, in, out));
	}
}
Beispiel #13
0
static int
xaui_label_set(topo_mod_t *mod, tnode_t *node, topo_instance_t n, void *priv)
{
	const char *label = NULL;
	char *plat, *pp;
	int err;
	int i, p;

	(void) xaui_get_pri_label(mod, n, priv, (char **)&label);
	if (label == NULL) {
		topo_mod_dprintf(mod, "no PRI node for label\n");
		if (Phyxaui_Names == NULL)
			return (-1);

		if (topo_prop_get_string(node,
		    FM_FMRI_AUTHORITY, FM_FMRI_AUTH_PRODUCT, &plat, &err) < 0) {
			return (topo_mod_seterrno(mod, err));
		}
		/*
		 * Trim SUNW, from the platform name
		 */
		pp = strchr(plat, ',');
		if (pp == NULL)
			pp = plat;
		else
			++pp;

		for (p = 0; p < Phyxaui_Names->psn_nplats; p++) {
			if (strcmp(Phyxaui_Names->psn_names[p].pnm_platform,
			    pp) != 0)
				continue;
			for (i = 0; i < Phyxaui_Names->psn_names[p].pnm_nnames;
			    i++) {
				physnm_t ps;
				ps = Phyxaui_Names->psn_names[p].pnm_names[i];
				if (ps.ps_num == n) {
					label = ps.ps_label;
					break;
				}
			}
			break;
		}
		topo_mod_strfree(mod, plat);
	}

	if (label != NULL) {
		if (topo_prop_set_string(node, TOPO_PGROUP_PROTOCOL,
		    TOPO_PROP_LABEL, TOPO_PROP_IMMUTABLE,
		    label, &err) != 0) {
			if (freeprilabel == 1) {
				topo_mod_strfree(mod, (char *)label);
			}
			return (topo_mod_seterrno(mod, err));
		}
		if (freeprilabel == 1) {
			topo_mod_strfree(mod, (char *)label);
		}
	}

	return (0);
}
Beispiel #14
0
static int
xml_read(topo_hdl_t *hp, ttree_t *tp)
{
	topo_file_t *tfp;
	char *pplat, *pmach;
	int err, e;
	char _topo_file[MAXNAMELEN * 2];
	char _topo_path[PATH_MAX];


	tfp = (topo_file_t *)tp->tt_file;

	(void) snprintf(_topo_file,
	    2 * MAXNAMELEN, TOPO_DEFAULT_FILE, tp->tt_scheme);

	/*
	 * Look for a platform-specific topology file first
	 */
	e = topo_prop_get_string(tp->tt_root, TOPO_PGROUP_SYSTEM,
	    TOPO_PROP_PLATFORM, &pplat, &err);
	if (e < 0)
		return (topo_hdl_seterrno(hp, err));
	(void) snprintf(_topo_path, PATH_MAX, PLATFORM_TOPO_PATH,
	    hp->th_rootdir, pplat, _topo_file);

	tfp->tf_fileinfo =
	    topo_xml_read(tfp->tf_mod, _topo_path, tp->tt_scheme);
	if (tfp->tf_fileinfo != NULL) {
		topo_hdl_strfree(hp, pplat);
		return (0);
	}

	topo_dprintf(TOPO_DBG_MOD, "failed to load topology file %s: %s\n",
	    _topo_path, topo_strerror(topo_hdl_errno(hp)));

	/*
	 * No luck with the platform-specific file, how about a
	 * machine-specific one?
	 */
	e = topo_prop_get_string(tp->tt_root, TOPO_PGROUP_SYSTEM,
	    TOPO_PROP_MACHINE, &pmach, &err);
	if (e < 0) {
		topo_hdl_strfree(hp, pplat);
		return (topo_hdl_seterrno(hp, err));
	}
	/*
	 * Don't waste time trying to open the same file twice in the
	 * cases where the platform name is identical to the machine
	 * name
	 */
	if (strcmp(pplat, pmach) != 0) {
		(void) snprintf(_topo_path, PATH_MAX, PLATFORM_TOPO_PATH,
		    hp->th_rootdir, pmach, _topo_file);
		tfp->tf_fileinfo =
		    topo_xml_read(tfp->tf_mod, _topo_path, tp->tt_scheme);
	}
	if (tfp->tf_fileinfo != NULL) {
		topo_hdl_strfree(hp, pplat);
		topo_hdl_strfree(hp, pmach);
		return (0);
	} else {
		topo_dprintf(TOPO_DBG_MOD,
		    "failed to load topology file %s: %s\n",
		    _topo_path, topo_strerror(topo_hdl_errno(hp)));
	}
	topo_hdl_strfree(hp, pplat);
	topo_hdl_strfree(hp, pmach);
	(void) snprintf(_topo_path, PATH_MAX, COMMON_TOPO_PATH,
	    hp->th_rootdir, _topo_file);
	tfp->tf_fileinfo =
	    topo_xml_read(tfp->tf_mod, _topo_path, tp->tt_scheme);
	if (tfp->tf_fileinfo == NULL) {
		topo_dprintf(TOPO_DBG_MOD,
		    "failed to load topology file %s: %s\n",
		    _topo_path, topo_strerror(topo_hdl_errno(hp)));
		return (topo_hdl_seterrno(hp, ETOPO_FILE_NOENT));
	}
	return (0);
}