view usr/src/lib/fm/topo/modules/sun4v/niu/niu.c @ 5060:222c7d448cfc

6505251 NIU FMA needs to diagnose XAUI and XFP faults 6558331 Should add detailed error info to ddi_fm_ereport_post 6559504 nxge_ipp_eccue_valid_check causes FMA errors 6562470 fm capabilities passed to ddi_fm_init should be set properly 6564290 Unused function nxge_fm_npi_error_handler should be deleted 6579032 When jumbo frame is enabled, nxge driver does not set the size of the incoming frame correctly. 6597303 XFP in the topology should be common instead of sun4v only 6597306 Fail to enumerate xaui and xfp when the the NIU is not nxge instance 0 or 1 6600077 _topo_init of xfp.c should return int intead of void
author yc148097
date Sun, 16 Sep 2007 21:47:51 -0700
parents 08f66ac41653
children b264f2cec470
line wrap: on
line source

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <string.h>
#include <fm/topo_mod.h>
#include <fm/topo_hc.h>
#include <libdevinfo.h>
#include <limits.h>
#include <sys/fm/protocol.h>
#include <sys/param.h>
#include <sys/systeminfo.h>
#include <assert.h>
#include <stdlib.h>

/*
 * niu.c
 *	sun4v specific niu enumerators
 */

#ifdef __cplusplus
extern "C" {
#endif

#define	NIU_VERSION	TOPO_VERSION
#define	NIUFN_MAX	2
#define	XAUI_MAX	1	/* max number of XAUIs per niufn */

static int niu_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t,
		    topo_instance_t, void *, void *);

static const topo_modops_t niu_ops =
	{ niu_enum, NULL };

const topo_modinfo_t niu_info =
	{NIU, FM_FMRI_SCHEME_HC, NIU_VERSION, &niu_ops};

static const topo_pgroup_info_t io_pgroup =
	{ TOPO_PGROUP_IO, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };

/*ARGSUSED*/
void
_topo_init(topo_mod_t *mod, topo_version_t version)
{
	/*
	 * Turn on module debugging output
	 */
	if (getenv("TOPONIUDBG") != NULL)
		topo_mod_setdebug(mod);
	topo_mod_dprintf(mod, "initializing niu enumerator\n");

	if (topo_mod_register(mod, &niu_info, TOPO_VERSION) < 0) {
		topo_mod_dprintf(mod, "niu registration failed: %s\n",
		    topo_mod_errmsg(mod));
		return; /* mod errno already set */
	}
	topo_mod_dprintf(mod, "NIU enumr initd\n");
}

void
_topo_fini(topo_mod_t *mod)
{
	topo_mod_unregister(mod);
}
static int
devprop_set(tnode_t *tn, di_node_t dn,
	const char *tpgrp, const char *tpnm, topo_mod_t *mod)
{
	char *path;
	int err, e;

	if ((path = di_devfs_path(dn)) == NULL) {
		topo_mod_dprintf(mod, "NULL di_devfs_path.\n");
		return (topo_mod_seterrno(mod, ETOPO_PROP_NOENT));
	}
	e = topo_prop_set_string(tn, tpgrp, tpnm, TOPO_PROP_IMMUTABLE,
	    path, &err);
	di_devfs_path_free(path);
	if (e != 0)
		return (topo_mod_seterrno(mod, err));
	return (0);
}
/*ARGSUSED*/
static int
driverprop_set(tnode_t *tn, di_node_t dn,
	const char *tpgrp, const char *tpnm, topo_mod_t *mod)
{
	char *dnm;
	int err;

	if ((dnm = di_driver_name(dn)) == NULL)
		return (0);
	if (topo_prop_set_string(tn,
	    tpgrp, tpnm, TOPO_PROP_IMMUTABLE, dnm, &err) < 0)
		return (topo_mod_seterrno(mod, err));
	return (0);
}
/*ARGSUSED*/
static int
moduleprop_set(tnode_t *tn, di_node_t dn,
	const char *tpgrp, const char *tpnm, topo_mod_t *mod)
{
	nvlist_t *module;
	char *dnm;
	int err;

	if ((dnm = di_driver_name(dn)) == NULL)
		return (0);

	if ((module = topo_mod_modfmri(mod, FM_MOD_SCHEME_VERSION, dnm))
	    == NULL)
		return (0); /* driver maybe detached, return success */

	if (topo_prop_set_fmri(tn, tpgrp, tpnm, TOPO_PROP_IMMUTABLE, module,
	    &err) < 0) {
		nvlist_free(module);
		return (topo_mod_seterrno(mod, err));
	}
	nvlist_free(module);
	return (0);
}
static tnode_t *
niu_tnode_create(topo_mod_t *mod, tnode_t *parent,
    const char *name, topo_instance_t i, void *priv)
{
	int err;
	nvlist_t *fmri;
	tnode_t *ntn;
	nvlist_t *auth = topo_mod_auth(mod, parent);

	fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, name, i,
	    NULL, auth, NULL, NULL, NULL);
	nvlist_free(auth);

	if (fmri == NULL) {
		topo_mod_dprintf(mod,
		    "Unable to make nvlist for %s bind: %s.\n",
		    name, topo_mod_errmsg(mod));
		return (NULL);
	}

	ntn = topo_node_bind(mod, parent, name, i, fmri);
	if (ntn == NULL) {
		topo_mod_dprintf(mod,
		    "topo_node_bind (%s%d/%s%d) failed: %s\n",
		    topo_node_name(parent), topo_node_instance(parent),
		    name, i,
		    topo_strerror(topo_mod_errno(mod)));
		nvlist_free(fmri);
		return (NULL);
	}
	nvlist_free(fmri);
	topo_node_setspecific(ntn, priv);

	if (topo_pgroup_create(ntn, &io_pgroup, &err) == 0) {
		(void) devprop_set(ntn, priv, TOPO_PGROUP_IO, TOPO_IO_DEV, mod);
		(void) driverprop_set(ntn, priv, TOPO_PGROUP_IO, TOPO_IO_DRIVER,
		    mod);
		(void) moduleprop_set(ntn, priv, TOPO_PGROUP_IO, TOPO_IO_MODULE,
		    mod);
	}
	return (ntn);
}
static int
niu_asru_set(tnode_t *tn, di_node_t dn, topo_mod_t *mod)
{
	char *path;
	nvlist_t *fmri;
	int e;

	if ((path = di_devfs_path(dn)) != NULL) {
		fmri = topo_mod_devfmri(mod, FM_DEV_SCHEME_VERSION, path, NULL);
		if (fmri == NULL) {
			topo_mod_dprintf(mod,
			    "dev:///%s fmri creation failed.\n", path);
			di_devfs_path_free(path);
			return (-1);
		}
		di_devfs_path_free(path);
	} else {
		topo_mod_dprintf(mod, "NULL di_devfs_path.\n");
		if (topo_prop_get_fmri(tn, TOPO_PGROUP_PROTOCOL,
		    TOPO_PROP_RESOURCE, &fmri, &e) < 0)
			return (topo_mod_seterrno(mod, e));
	}
	if (topo_node_asru_set(tn, fmri, 0, &e) < 0) {
		nvlist_free(fmri);
		return (topo_mod_seterrno(mod, e));
	}
	nvlist_free(fmri);
	return (0);
}

/*ARGSUSED*/
static tnode_t *
niu_declare(tnode_t *parent, const char *name, topo_instance_t i,
	void *priv, topo_mod_t *mod)
{
	tnode_t *ntn;
	int err;

	if ((ntn = niu_tnode_create(mod, parent, name, 0, priv)) == NULL) {
		topo_mod_dprintf(mod, "%s ntn = NULL\n", name);
		return (NULL);
	}

	/* inherit FRU from parent */
	(void) topo_node_fru_set(ntn, NULL, 0, &err);
	/* inherit parent's label */
	if (topo_node_label_set(ntn, NULL, &err) < 0) {
		topo_mod_dprintf(mod, "niu label error %d\n", err);
	}
	/* set ASRU */
	(void) niu_asru_set(ntn, priv, mod);

	return (ntn);
}


/*ARGSUSED*/
static tnode_t *
niufn_declare(tnode_t *parent, const char *name, topo_instance_t i,
	void *priv, topo_mod_t *mod)
{
	tnode_t *ntn;
	int err;

	if ((ntn = niu_tnode_create(mod, parent, name, i, priv)) == NULL)
		return (NULL);

	/* inherit FRU from parent */
	(void) topo_node_fru_set(ntn, NULL, 0, &err);
	/* inherit parent's label */
	(void) topo_node_label_set(ntn, NULL, &err);

	/* set ASRU */
	(void) niu_asru_set(ntn, priv, mod);

	if (topo_node_range_create(mod, ntn, XAUI,
	    0, XAUI_MAX) < 0) {
		topo_node_unbind(ntn);
		topo_mod_dprintf(mod, "child_range_add of XAUI"
		    "failed: %s\n",
		    topo_strerror(topo_mod_errno(mod)));
		return (NULL); /* mod_errno already set */
	}
	return (ntn);
}

static int
niufn_instantiate(tnode_t *parent, const char *name, di_node_t pnode,
	topo_mod_t *mod)
{
	di_node_t sib;
	tnode_t *ntn;
	topo_instance_t inst;

	if (strcmp(name, NIUFN) != 0) {
		topo_mod_dprintf(mod,
		    "Currently only know how to enumerate %s components.\n",
		    NIUFN);
		return (0);
	}

	sib = di_child_node(pnode);
	while (sib != DI_NODE_NIL) {
		inst = strtoul(di_bus_addr(sib), NULL, 10);
		if ((ntn = niufn_declare(parent, NIUFN, inst, sib, mod))
		    == NULL) {
			topo_mod_dprintf(mod, "Enumeration of %s=%d "
			    "failed: %s\n", NIUFN, inst,
			    topo_strerror(topo_mod_errno(mod)));
			return (-1);
		}
		if (topo_mod_enumerate(mod,
		    ntn, XAUI, XAUI, inst, inst, sib) != 0) {
			return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
		}
		sib = di_sibling_node(sib);
	}
	return (0);
}

static topo_mod_t *
xaui_enum_load(topo_mod_t *mp)
{
	topo_mod_t *rp = NULL;

	if ((rp = topo_mod_load(mp, XAUI, TOPO_VERSION)) == NULL) {
		topo_mod_dprintf(mp,
		    "%s enumerator could not load %s enum.\n", NIU, XAUI);
	}
	return (rp);
}
/*ARGSUSED*/
static int
niu_enum(topo_mod_t *mod, tnode_t *rnode, const char *name,
	topo_instance_t min, topo_instance_t max, void *arg, void *notused)
{
	tnode_t *niun;
	di_node_t devtree;
	di_node_t dnode;

	if (strcmp(name, NIU) != 0) {
		topo_mod_dprintf(mod,
		    "Currently only know how to enumerate %s components.\n",
		    NIU);
		return (0);
	}

	if ((devtree = topo_mod_devinfo(mod)) == DI_NODE_NIL) {
		topo_mod_dprintf(mod, "devinfo init failed.");
		return (-1);
	}
	/*
	 * Load XAUI Enum
	 */
	if (xaui_enum_load(mod) == NULL)
		return (-1);

	dnode = di_drv_first_node("niumx", devtree);
	if (dnode != DI_NODE_NIL) {
		niun = niu_declare(rnode, name, 0, dnode, mod);
		if (niun == NULL) {
			topo_mod_dprintf(mod, "Enumeration of niu failed: %s\n",
			    topo_strerror(topo_mod_errno(mod)));
			return (-1); /* mod_errno already set */
		}
		if (topo_node_range_create(mod, niun, NIUFN,
		    0, NIUFN_MAX) < 0) {
			topo_node_unbind(niun);
			topo_mod_dprintf(mod, "child_range_add of NIUFN"
			    "failed: %s\n",
			    topo_strerror(topo_mod_errno(mod)));
			return (-1); /* mod_errno already set */
		}
		if (niufn_instantiate(niun, NIUFN, dnode, mod) < 0) {
			topo_mod_dprintf(mod, "Enumeration of niufn "
			    "failed %s\n",
			    topo_strerror(topo_mod_errno(mod)));
		}
	}
	if (di_drv_next_node(dnode) != DI_NODE_NIL)
		topo_mod_dprintf(mod,
		    "Currently only know how to enumerate one niu "
		    "components.\n");

	return (0);
}