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