Home | History | Annotate | Download | only in niu
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include <string.h>
     28 #include <fm/topo_mod.h>
     29 #include <fm/topo_hc.h>
     30 #include <libdevinfo.h>
     31 #include <limits.h>
     32 #include <sys/fm/protocol.h>
     33 #include <sys/param.h>
     34 #include <sys/systeminfo.h>
     35 #include <assert.h>
     36 #include <stdlib.h>
     37 
     38 /*
     39  * niu.c
     40  *	sun4v specific niu enumerators
     41  */
     42 
     43 #ifdef __cplusplus
     44 extern "C" {
     45 #endif
     46 
     47 #define	NIU_VERSION	TOPO_VERSION
     48 #define	NIUFN_MAX	2
     49 #define	XAUI_MAX	1	/* max number of XAUIs per niufn */
     50 
     51 static int niu_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t,
     52 		    topo_instance_t, void *, void *);
     53 
     54 static const topo_modops_t niu_ops =
     55 	{ niu_enum, NULL };
     56 
     57 const topo_modinfo_t niu_info =
     58 	{NIU, FM_FMRI_SCHEME_HC, NIU_VERSION, &niu_ops};
     59 
     60 static const topo_pgroup_info_t io_pgroup =
     61 	{ TOPO_PGROUP_IO, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
     62 
     63 /*ARGSUSED*/
     64 void
     65 _topo_init(topo_mod_t *mod, topo_version_t version)
     66 {
     67 	/*
     68 	 * Turn on module debugging output
     69 	 */
     70 	if (getenv("TOPONIUDBG") != NULL)
     71 		topo_mod_setdebug(mod);
     72 	topo_mod_dprintf(mod, "initializing niu enumerator\n");
     73 
     74 	if (topo_mod_register(mod, &niu_info, TOPO_VERSION) < 0) {
     75 		topo_mod_dprintf(mod, "niu registration failed: %s\n",
     76 		    topo_mod_errmsg(mod));
     77 		return; /* mod errno already set */
     78 	}
     79 	topo_mod_dprintf(mod, "NIU enumr initd\n");
     80 }
     81 
     82 void
     83 _topo_fini(topo_mod_t *mod)
     84 {
     85 	topo_mod_unregister(mod);
     86 }
     87 static int
     88 devprop_set(tnode_t *tn, di_node_t dn,
     89 	const char *tpgrp, const char *tpnm, topo_mod_t *mod)
     90 {
     91 	char *path;
     92 	int err, e;
     93 
     94 	if ((path = di_devfs_path(dn)) == NULL) {
     95 		topo_mod_dprintf(mod, "NULL di_devfs_path.\n");
     96 		return (topo_mod_seterrno(mod, ETOPO_PROP_NOENT));
     97 	}
     98 	e = topo_prop_set_string(tn, tpgrp, tpnm, TOPO_PROP_IMMUTABLE,
     99 	    path, &err);
    100 	di_devfs_path_free(path);
    101 	if (e != 0)
    102 		return (topo_mod_seterrno(mod, err));
    103 	return (0);
    104 }
    105 /*ARGSUSED*/
    106 static int
    107 driverprop_set(tnode_t *tn, di_node_t dn,
    108 	const char *tpgrp, const char *tpnm, topo_mod_t *mod)
    109 {
    110 	char *dnm;
    111 	int err;
    112 
    113 	if ((dnm = di_driver_name(dn)) == NULL)
    114 		return (0);
    115 	if (topo_prop_set_string(tn,
    116 	    tpgrp, tpnm, TOPO_PROP_IMMUTABLE, dnm, &err) < 0)
    117 		return (topo_mod_seterrno(mod, err));
    118 	return (0);
    119 }
    120 /*ARGSUSED*/
    121 static int
    122 moduleprop_set(tnode_t *tn, di_node_t dn,
    123 	const char *tpgrp, const char *tpnm, topo_mod_t *mod)
    124 {
    125 	nvlist_t *module;
    126 	char *dnm;
    127 	int err;
    128 
    129 	if ((dnm = di_driver_name(dn)) == NULL)
    130 		return (0);
    131 
    132 	if ((module = topo_mod_modfmri(mod, FM_MOD_SCHEME_VERSION, dnm))
    133 	    == NULL)
    134 		return (0); /* driver maybe detached, return success */
    135 
    136 	if (topo_prop_set_fmri(tn, tpgrp, tpnm, TOPO_PROP_IMMUTABLE, module,
    137 	    &err) < 0) {
    138 		nvlist_free(module);
    139 		return (topo_mod_seterrno(mod, err));
    140 	}
    141 	nvlist_free(module);
    142 	return (0);
    143 }
    144 static tnode_t *
    145 niu_tnode_create(topo_mod_t *mod, tnode_t *parent,
    146     const char *name, topo_instance_t i, void *priv)
    147 {
    148 	int err;
    149 	nvlist_t *fmri;
    150 	tnode_t *ntn;
    151 	nvlist_t *auth = topo_mod_auth(mod, parent);
    152 
    153 	fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, name, i,
    154 	    NULL, auth, NULL, NULL, NULL);
    155 	nvlist_free(auth);
    156 
    157 	if (fmri == NULL) {
    158 		topo_mod_dprintf(mod,
    159 		    "Unable to make nvlist for %s bind: %s.\n",
    160 		    name, topo_mod_errmsg(mod));
    161 		return (NULL);
    162 	}
    163 
    164 	ntn = topo_node_bind(mod, parent, name, i, fmri);
    165 	if (ntn == NULL) {
    166 		topo_mod_dprintf(mod,
    167 		    "topo_node_bind (%s%d/%s%d) failed: %s\n",
    168 		    topo_node_name(parent), topo_node_instance(parent),
    169 		    name, i,
    170 		    topo_strerror(topo_mod_errno(mod)));
    171 		nvlist_free(fmri);
    172 		return (NULL);
    173 	}
    174 	nvlist_free(fmri);
    175 	topo_node_setspecific(ntn, priv);
    176 
    177 	if (topo_pgroup_create(ntn, &io_pgroup, &err) == 0) {
    178 		(void) devprop_set(ntn, priv, TOPO_PGROUP_IO, TOPO_IO_DEV, mod);
    179 		(void) driverprop_set(ntn, priv, TOPO_PGROUP_IO, TOPO_IO_DRIVER,
    180 		    mod);
    181 		(void) moduleprop_set(ntn, priv, TOPO_PGROUP_IO, TOPO_IO_MODULE,
    182 		    mod);
    183 	}
    184 	return (ntn);
    185 }
    186 static int
    187 niu_asru_set(tnode_t *tn, di_node_t dn, topo_mod_t *mod)
    188 {
    189 	char *path;
    190 	nvlist_t *fmri;
    191 	int e;
    192 
    193 	if ((path = di_devfs_path(dn)) != NULL) {
    194 		fmri = topo_mod_devfmri(mod, FM_DEV_SCHEME_VERSION, path, NULL);
    195 		if (fmri == NULL) {
    196 			topo_mod_dprintf(mod,
    197 			    "dev:///%s fmri creation failed.\n", path);
    198 			di_devfs_path_free(path);
    199 			return (-1);
    200 		}
    201 		di_devfs_path_free(path);
    202 	} else {
    203 		topo_mod_dprintf(mod, "NULL di_devfs_path.\n");
    204 		if (topo_prop_get_fmri(tn, TOPO_PGROUP_PROTOCOL,
    205 		    TOPO_PROP_RESOURCE, &fmri, &e) < 0)
    206 			return (topo_mod_seterrno(mod, e));
    207 	}
    208 	if (topo_node_asru_set(tn, fmri, 0, &e) < 0) {
    209 		nvlist_free(fmri);
    210 		return (topo_mod_seterrno(mod, e));
    211 	}
    212 	nvlist_free(fmri);
    213 	return (0);
    214 }
    215 
    216 /*ARGSUSED*/
    217 static tnode_t *
    218 niu_declare(tnode_t *parent, const char *name, topo_instance_t i,
    219 	void *priv, topo_mod_t *mod)
    220 {
    221 	tnode_t *ntn;
    222 	int err;
    223 
    224 	if ((ntn = niu_tnode_create(mod, parent, name, 0, priv)) == NULL) {
    225 		topo_mod_dprintf(mod, "%s ntn = NULL\n", name);
    226 		return (NULL);
    227 	}
    228 
    229 	/* inherit FRU from parent */
    230 	(void) topo_node_fru_set(ntn, NULL, 0, &err);
    231 	/* inherit parent's label */
    232 	if (topo_node_label_set(ntn, NULL, &err) < 0) {
    233 		topo_mod_dprintf(mod, "niu label error %d\n", err);
    234 	}
    235 	/* set ASRU */
    236 	(void) niu_asru_set(ntn, priv, mod);
    237 
    238 	return (ntn);
    239 }
    240 
    241 
    242 /*ARGSUSED*/
    243 static tnode_t *
    244 niufn_declare(tnode_t *parent, const char *name, topo_instance_t i,
    245 	void *priv, topo_mod_t *mod)
    246 {
    247 	tnode_t *ntn;
    248 	int err;
    249 
    250 	if ((ntn = niu_tnode_create(mod, parent, name, i, priv)) == NULL)
    251 		return (NULL);
    252 
    253 	/* inherit FRU from parent */
    254 	(void) topo_node_fru_set(ntn, NULL, 0, &err);
    255 	/* inherit parent's label */
    256 	(void) topo_node_label_set(ntn, NULL, &err);
    257 
    258 	/* set ASRU */
    259 	(void) niu_asru_set(ntn, priv, mod);
    260 
    261 	if (topo_node_range_create(mod, ntn, XAUI, 0, XAUI_MAX) < 0) {
    262 		topo_node_unbind(ntn);
    263 		topo_mod_dprintf(mod, "child_range_add of XAUI"
    264 		    "failed: %s\n",
    265 		    topo_strerror(topo_mod_errno(mod)));
    266 		return (NULL); /* mod_errno already set */
    267 	}
    268 	return (ntn);
    269 }
    270 
    271 /*
    272  * Get the NIU/Neptune ethernet function number from the reg property
    273  */
    274 static int
    275 niufn_instance_get(topo_mod_t *mod, di_node_t node, topo_instance_t *inst)
    276 {
    277 	di_prom_handle_t phan;
    278 	int rval, *intp;
    279 
    280 	*inst = (topo_instance_t)0;
    281 	rval = -1;
    282 	if ((phan = topo_mod_prominfo(mod)) != DI_PROM_HANDLE_NIL) {
    283 		rval = di_prom_prop_lookup_ints(phan, node,
    284 		    DI_PROP_REG, &intp);
    285 	}
    286 	if (rval < 0) {
    287 		rval = di_prop_lookup_ints(DDI_DEV_T_ANY, node,
    288 		    DI_PROP_REG, &intp);
    289 		if (rval < 0)
    290 			return (-1);
    291 	}
    292 	*inst = (topo_instance_t)intp[0];
    293 
    294 	return (0);
    295 }
    296 
    297 static int
    298 niufn_instantiate(tnode_t *parent, const char *name, di_node_t pnode,
    299 	topo_mod_t *mod)
    300 {
    301 	di_node_t sib;
    302 	tnode_t *ntn;
    303 	topo_instance_t inst;
    304 
    305 	if (strcmp(name, NIUFN) != 0) {
    306 		topo_mod_dprintf(mod,
    307 		    "Currently only know how to enumerate %s components.\n",
    308 		    NIUFN);
    309 		return (0);
    310 	}
    311 
    312 	sib = di_child_node(pnode);
    313 	while (sib != DI_NODE_NIL) {
    314 		if (niufn_instance_get(mod, sib, &inst) != 0) {
    315 			topo_mod_dprintf(mod, "Enumeration of %s "
    316 			    "instance failed.\n", NIUFN);
    317 			sib = di_sibling_node(sib);
    318 			continue;
    319 		}
    320 		if ((ntn = niufn_declare(parent, NIUFN, inst, sib, mod))
    321 		    == NULL) {
    322 			topo_mod_dprintf(mod, "Enumeration of %s=%d "
    323 			    "failed: %s\n", NIUFN, inst,
    324 			    topo_strerror(topo_mod_errno(mod)));
    325 			return (-1);
    326 		}
    327 		if (topo_mod_enumerate(mod,
    328 		    ntn, XAUI, XAUI, inst, inst, sib) != 0) {
    329 			return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
    330 		}
    331 		sib = di_sibling_node(sib);
    332 	}
    333 	return (0);
    334 }
    335 
    336 static topo_mod_t *
    337 xaui_enum_load(topo_mod_t *mp)
    338 {
    339 	topo_mod_t *rp = NULL;
    340 
    341 	if ((rp = topo_mod_load(mp, XAUI, TOPO_VERSION)) == NULL) {
    342 		topo_mod_dprintf(mp,
    343 		    "%s enumerator could not load %s enum.\n", NIU, XAUI);
    344 	}
    345 	return (rp);
    346 }
    347 /*ARGSUSED*/
    348 static int
    349 niu_enum(topo_mod_t *mod, tnode_t *rnode, const char *name,
    350 	topo_instance_t min, topo_instance_t max, void *arg, void *notused)
    351 {
    352 	tnode_t *niun;
    353 	di_node_t devtree;
    354 	di_node_t dnode;
    355 
    356 	if (strcmp(name, NIU) != 0) {
    357 		topo_mod_dprintf(mod,
    358 		    "Currently only know how to enumerate %s components.\n",
    359 		    NIU);
    360 		return (0);
    361 	}
    362 
    363 	if ((devtree = topo_mod_devinfo(mod)) == DI_NODE_NIL) {
    364 		topo_mod_dprintf(mod, "devinfo init failed.");
    365 		return (-1);
    366 	}
    367 
    368 	/*
    369 	 * Load XAUI Enum
    370 	 */
    371 	if (xaui_enum_load(mod) == NULL)
    372 		return (-1);
    373 
    374 	dnode = di_drv_first_node("niumx", devtree);
    375 	if (dnode != DI_NODE_NIL) {
    376 		niun = niu_declare(rnode, name, 0, dnode, mod);
    377 		if (niun == NULL) {
    378 			topo_mod_dprintf(mod, "Enumeration of niu failed: %s\n",
    379 			    topo_strerror(topo_mod_errno(mod)));
    380 			return (-1); /* mod_errno already set */
    381 		}
    382 		if (topo_node_range_create(mod, niun, NIUFN,
    383 		    0, NIUFN_MAX) < 0) {
    384 			topo_node_unbind(niun);
    385 			topo_mod_dprintf(mod, "child_range_add of NIUFN"
    386 			    "failed: %s\n",
    387 			    topo_strerror(topo_mod_errno(mod)));
    388 			return (-1); /* mod_errno already set */
    389 		}
    390 		if (niufn_instantiate(niun, NIUFN, dnode, mod) < 0) {
    391 			topo_mod_dprintf(mod, "Enumeration of niufn "
    392 			    "failed %s\n",
    393 			    topo_strerror(topo_mod_errno(mod)));
    394 		}
    395 	}
    396 	if (di_drv_next_node(dnode) != DI_NODE_NIL)
    397 		topo_mod_dprintf(mod,
    398 		    "Currently only know how to enumerate one niu "
    399 		    "components.\n");
    400 
    401 	return (0);
    402 }
    403