11898Shueston /*
21898Shueston  * CDDL HEADER START
31898Shueston  *
41898Shueston  * The contents of this file are subject to the terms of the
51898Shueston  * Common Development and Distribution License (the "License").
61898Shueston  * You may not use this file except in compliance with the License.
71898Shueston  *
81898Shueston  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91898Shueston  * or http://www.opensolaris.org/os/licensing.
101898Shueston  * See the License for the specific language governing permissions
111898Shueston  * and limitations under the License.
121898Shueston  *
131898Shueston  * When distributing Covered Code, include this CDDL HEADER in each
141898Shueston  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151898Shueston  * If applicable, add the following below this CDDL HEADER, with the
161898Shueston  * fields enclosed by brackets "[]" replaced with your own identifying
171898Shueston  * information: Portions Copyright [yyyy] [name of copyright owner]
181898Shueston  *
191898Shueston  * CDDL HEADER END
201898Shueston  */
211898Shueston 
221898Shueston /*
23*11583SSurya.Prakki@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
241898Shueston  * Use is subject to license terms.
251898Shueston  */
261898Shueston 
271898Shueston #include <string.h>
281898Shueston #include <strings.h>
291898Shueston #include <libdevinfo.h>
301898Shueston #include <fm/topo_mod.h>
313062Scindi #include <fm/topo_hc.h>
321898Shueston #include <sys/fm/protocol.h>
331898Shueston #include "opl_topo.h"
341898Shueston 
353062Scindi static const topo_pgroup_info_t io_pgroup =
363062Scindi 	{ TOPO_PGROUP_IO, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
373062Scindi static const topo_pgroup_info_t pci_pgroup =
383062Scindi 	{ TOPO_PGROUP_PCI, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
392499Shueston 
402499Shueston /*
411898Shueston  * Check the root complex device node for a slot-names property.
421898Shueston  */
431898Shueston const char *
opl_get_slot_name(topo_mod_t * mod,di_node_t n)443062Scindi opl_get_slot_name(topo_mod_t *mod, di_node_t n)
451898Shueston {
463062Scindi 	di_prom_handle_t ptp = DI_PROM_HANDLE_NIL;
471898Shueston 	di_prom_prop_t pp = DI_PROM_PROP_NIL;
481898Shueston 	uchar_t *buf;
491898Shueston 
503062Scindi 	if ((ptp = topo_mod_prominfo(mod)) == DI_PROM_PROP_NIL)
513062Scindi 		return (NULL);
523062Scindi 
533062Scindi 	for (pp = di_prom_prop_next(ptp, n, pp);
541898Shueston 	    pp != DI_PROM_PROP_NIL;
553062Scindi 	    pp = di_prom_prop_next(ptp, n, pp)) {
561898Shueston 		if (strcmp(di_prom_prop_name(pp), OPL_SLOT_NAMES) == 0) {
571898Shueston 			if (di_prom_prop_data(pp, &buf) <= sizeof (uint32_t))
581898Shueston 				continue;
591898Shueston 			return ((const char *)&buf[4]);
601898Shueston 		}
611898Shueston 	}
621898Shueston 	return (NULL);
631898Shueston }
641898Shueston 
651898Shueston static tnode_t *
opl_node_create(topo_mod_t * mp,tnode_t * parent,const char * name,int inst,void * priv)661898Shueston opl_node_create(topo_mod_t *mp, tnode_t *parent, const char *name, int inst,
671898Shueston     void *priv)
681898Shueston {
691898Shueston 	tnode_t *node;
701898Shueston 	nvlist_t *fmri;
713062Scindi 	nvlist_t *auth = topo_mod_auth(mp, parent);
721898Shueston 
731898Shueston 	if (parent == NULL || inst < 0) {
741898Shueston 		return (NULL);
751898Shueston 	}
761898Shueston 
771898Shueston 	/* Create FMRI */
783062Scindi 	if ((fmri = topo_mod_hcfmri(mp, parent, FM_HC_SCHEME_VERSION, name,
793062Scindi 	    inst, NULL, auth, NULL, NULL, NULL)) == NULL) {
803062Scindi 		topo_mod_dprintf(mp, "create of tnode for %s failed: %s",
811898Shueston 		    name, topo_strerror(topo_mod_errno(mp)));
823062Scindi 		nvlist_free(auth);
831898Shueston 		return (NULL);
841898Shueston 	}
853062Scindi 	nvlist_free(auth);
861898Shueston 
871898Shueston 	/* Create and bind node  */
883062Scindi 	node = topo_node_bind(mp, parent, name, inst, fmri);
891898Shueston 	if (node == NULL) {
901898Shueston 		nvlist_free(fmri);
912499Shueston 		topo_mod_dprintf(mp, "unable to bind root complex: %s\n",
921898Shueston 		    topo_strerror(topo_mod_errno(mp)));
931898Shueston 		return (NULL); /* mod_errno already set */
941898Shueston 	}
953062Scindi 
961898Shueston 	nvlist_free(fmri);
973062Scindi 	topo_node_setspecific(node, priv);
982499Shueston 
991898Shueston 	return (node);
1001898Shueston }
1011898Shueston 
1021898Shueston /*
1031898Shueston  * Create a root complex node.
1041898Shueston  */
1051898Shueston static tnode_t *
opl_rc_node_create(topo_mod_t * mp,tnode_t * parent,di_node_t dnode,int inst)1063062Scindi opl_rc_node_create(topo_mod_t *mp, tnode_t *parent, di_node_t dnode, int inst)
1071898Shueston {
1081898Shueston 	int err;
1091898Shueston 	tnode_t *rcn;
1101898Shueston 	const char *slot_name;
1112499Shueston 	char *dnpath;
1123323Scindi 	nvlist_t *mod;
1131898Shueston 
1143062Scindi 	rcn = opl_node_create(mp, parent, PCIEX_ROOT, inst, (void *)dnode);
1151898Shueston 	if (rcn == NULL) {
1161898Shueston 		return (NULL);
1171898Shueston 	}
1181898Shueston 
1191898Shueston 	/*
1201898Shueston 	 * If this root complex connects to a slot, it will have a
1211898Shueston 	 * slot-names property.
1221898Shueston 	 */
1233062Scindi 	slot_name = opl_get_slot_name(mp, dnode);
1241898Shueston 	if (slot_name) {
1251898Shueston 		char fru_str[64];
1261898Shueston 		nvlist_t *fru_fmri;
1271898Shueston 		/* Add FRU fmri */
1285017Seschrock 		(void) snprintf(fru_str, sizeof (fru_str), "hc:///component=%s",
1291898Shueston 		    slot_name);
1303062Scindi 		if (topo_mod_str2nvl(mp, fru_str, &fru_fmri) == 0) {
1311898Shueston 			(void) topo_node_fru_set(rcn, fru_fmri, 0, &err);
1321898Shueston 			nvlist_free(fru_fmri);
1331898Shueston 		}
1341898Shueston 		/* Add label */
1351898Shueston 		(void) topo_node_label_set(rcn, (char *)slot_name, &err);
1361898Shueston 	} else {
1371898Shueston 		/* Inherit parent FRU's label */
1381898Shueston 		(void) topo_node_fru_set(rcn, NULL, 0, &err);
1391898Shueston 		(void) topo_node_label_set(rcn, NULL, &err);
1401898Shueston 	}
1412499Shueston 
1422499Shueston 	/*
1432499Shueston 	 * Set ASRU to be the dev-scheme ASRU
1442499Shueston 	 */
1452499Shueston 	if ((dnpath = di_devfs_path(dnode)) != NULL) {
1462499Shueston 		nvlist_t *fmri;
1473062Scindi 
1483062Scindi 		fmri = topo_mod_devfmri(mp, FM_DEV_SCHEME_VERSION,
1493062Scindi 		    dnpath, NULL);
1502499Shueston 		if (fmri == NULL) {
1512499Shueston 			topo_mod_dprintf(mp,
1522499Shueston 			    "dev:///%s fmri creation failed.\n",
1532499Shueston 			    dnpath);
154*11583SSurya.Prakki@Sun.COM 			(void) topo_mod_seterrno(mp, err);
1552499Shueston 			di_devfs_path_free(dnpath);
1562499Shueston 			return (NULL);
1572499Shueston 		}
1582499Shueston 		if (topo_node_asru_set(rcn, fmri, 0, &err) < 0) {
1592499Shueston 			topo_mod_dprintf(mp, "topo_node_asru_set failed\n");
160*11583SSurya.Prakki@Sun.COM 			(void) topo_mod_seterrno(mp, err);
1612499Shueston 			nvlist_free(fmri);
1622499Shueston 			di_devfs_path_free(dnpath);
1632499Shueston 			return (NULL);
1642499Shueston 		}
1652499Shueston 		nvlist_free(fmri);
1662499Shueston 	} else {
1672499Shueston 		topo_mod_dprintf(mp, "NULL di_devfs_path.\n");
1682499Shueston 	}
1692499Shueston 
1702499Shueston 	/*
1712499Shueston 	 * Set pciexrc properties for root complex nodes
1722499Shueston 	 */
1732499Shueston 
1742499Shueston 	/* Add the io and pci property groups */
1753062Scindi 	if (topo_pgroup_create(rcn, &io_pgroup, &err) < 0) {
1762499Shueston 		topo_mod_dprintf(mp, "topo_pgroup_create failed\n");
1772499Shueston 		di_devfs_path_free(dnpath);
178*11583SSurya.Prakki@Sun.COM 		(void) topo_mod_seterrno(mp, err);
1792499Shueston 		return (NULL);
1802499Shueston 	}
1813062Scindi 	if (topo_pgroup_create(rcn, &pci_pgroup, &err) < 0) {
1822499Shueston 		topo_mod_dprintf(mp, "topo_pgroup_create failed\n");
1832499Shueston 		di_devfs_path_free(dnpath);
184*11583SSurya.Prakki@Sun.COM 		(void) topo_mod_seterrno(mp, err);
1852499Shueston 		return (NULL);
1862499Shueston 	}
1872499Shueston 	/* Add the devfs path property */
1882499Shueston 	if (dnpath) {
1893062Scindi 		if (topo_prop_set_string(rcn, TOPO_PGROUP_IO, TOPO_IO_DEV,
1903062Scindi 		    TOPO_PROP_IMMUTABLE, dnpath, &err) != 0) {
1912499Shueston 			topo_mod_dprintf(mp, "Failed to set DEV property\n");
1922499Shueston 			di_devfs_path_free(dnpath);
193*11583SSurya.Prakki@Sun.COM 			(void) topo_mod_seterrno(mp, err);
1942499Shueston 		}
1952499Shueston 		di_devfs_path_free(dnpath);
1962499Shueston 	}
1972499Shueston 	/* Oberon device type is always "pciex" */
1983062Scindi 	if (topo_prop_set_string(rcn, TOPO_PGROUP_IO, TOPO_IO_DEVTYPE,
1993062Scindi 	    TOPO_PROP_IMMUTABLE, OPL_PX_DEVTYPE, &err) != 0) {
2002499Shueston 		topo_mod_dprintf(mp, "Failed to set DEVTYPE property\n");
2012499Shueston 	}
2022499Shueston 	/* Oberon driver is always "px" */
2033062Scindi 	if (topo_prop_set_string(rcn, TOPO_PGROUP_IO, TOPO_IO_DRIVER,
2043062Scindi 	    TOPO_PROP_IMMUTABLE, OPL_PX_DRV, &err) != 0) {
2052499Shueston 		topo_mod_dprintf(mp, "Failed to set DRIVER property\n");
2062499Shueston 	}
2073323Scindi 	if ((mod = topo_mod_modfmri(mp, FM_MOD_SCHEME_VERSION, OPL_PX_DRV))
2083323Scindi 	    == NULL || topo_prop_set_fmri(rcn, TOPO_PGROUP_IO,
2093323Scindi 	    TOPO_IO_MODULE, TOPO_PROP_IMMUTABLE, mod,  &err) != 0) {
2103323Scindi 		topo_mod_dprintf(mp, "Failed to set MODULE property\n");
2113323Scindi 	}
2123323Scindi 	if (mod != NULL)
2133323Scindi 		nvlist_free(mod);
2143323Scindi 
2152499Shueston 	/* This is a PCIEX Root Complex */
2163062Scindi 	if (topo_prop_set_string(rcn, TOPO_PGROUP_PCI, TOPO_PCI_EXCAP,
2173062Scindi 	    TOPO_PROP_IMMUTABLE, PCIEX_ROOT, &err) != 0) {
2182499Shueston 		topo_mod_dprintf(mp, "Failed to set EXCAP property\n");
2192499Shueston 	}
2202499Shueston 	/* BDF of Oberon root complex is constant */
2212499Shueston 	if (topo_prop_set_string(rcn, TOPO_PGROUP_PCI,
2223062Scindi 	    TOPO_PCI_BDF, TOPO_PROP_IMMUTABLE, OPL_PX_BDF, &err) != 0) {
2232499Shueston 		topo_mod_dprintf(mp, "Failed to set EXCAP property\n");
2242499Shueston 	}
2252499Shueston 
2261898Shueston 	/* Make room for children */
227*11583SSurya.Prakki@Sun.COM 	(void) topo_node_range_create(mp, rcn, PCIEX_BUS, 0, OPL_BUS_MAX);
2281898Shueston 	return (rcn);
2291898Shueston }
2301898Shueston 
2311898Shueston /*
2321898Shueston  * Create a hostbridge node.
2331898Shueston  */
2341898Shueston static tnode_t *
opl_hb_node_create(topo_mod_t * mp,tnode_t * parent,int inst)2351898Shueston opl_hb_node_create(topo_mod_t *mp, tnode_t *parent, int inst)
2361898Shueston {
2371898Shueston 	int err;
2381898Shueston 	tnode_t *hbn;
2391898Shueston 
2401898Shueston 	hbn = opl_node_create(mp, parent, HOSTBRIDGE, inst, NULL);
2411898Shueston 	if (hbn == NULL) {
2421898Shueston 		return (NULL);
2431898Shueston 	}
2441898Shueston 
2451898Shueston 	/* Inherit parent FRU's label */
2461898Shueston 	(void) topo_node_fru_set(hbn, NULL, 0, &err);
2471898Shueston 	(void) topo_node_label_set(hbn, NULL, &err);
2481898Shueston 
2491898Shueston 	/* Make room for children */
250*11583SSurya.Prakki@Sun.COM 	(void) topo_node_range_create(mp, hbn, PCIEX_ROOT, 0, OPL_RC_MAX);
2511898Shueston 
2521898Shueston 	return (hbn);
2531898Shueston }
2541898Shueston 
2551898Shueston /*
2561898Shueston  * opl_hb_enum gets the ioboard instance passed in, and determines the
2571898Shueston  * hostbridge and root complex instances numbers based on the bus addresses.
2581898Shueston  */
2591898Shueston int
opl_hb_enum(topo_mod_t * mp,const ioboard_contents_t * iob,tnode_t * ion,int brd)2601898Shueston opl_hb_enum(topo_mod_t *mp, const ioboard_contents_t *iob, tnode_t *ion,
2613062Scindi     int brd)
2621898Shueston {
2631898Shueston 	int hb;
2641898Shueston 	int rc;
2651898Shueston 	di_node_t p;
2661898Shueston 	tnode_t *hbnode;
2671898Shueston 	tnode_t *rcnode;
2681898Shueston 	topo_mod_t *pcimod;
2691898Shueston 
2701898Shueston 	/* Load the pcibus module. We'll need it later. */
2713062Scindi 	pcimod = topo_mod_load(mp, PCI_BUS, PCI_BUS_VERS);
2721898Shueston 	if (pcimod == NULL) {
2732499Shueston 		topo_mod_dprintf(mp, "can't load pcibus module: %s\n",
2741898Shueston 		    topo_strerror(topo_mod_errno(mp)));
2751898Shueston 		return (-1);
2761898Shueston 	}
2771898Shueston 
2781898Shueston 	/* For each hostbridge on an ioboard... */
2791898Shueston 	for (hb = 0; hb < OPL_HB_MAX; hb++) {
2801898Shueston 		hbnode = NULL;
2811898Shueston 		/* For each root complex in a hostbridge... */
2821898Shueston 		for (rc = 0; rc < OPL_RC_MAX; rc++) {
2831898Shueston 			p = iob->rcs[hb][rc];
2841898Shueston 			/* If no root complex, continue */
2851898Shueston 			if (p == DI_NODE_NIL) {
2861898Shueston 				continue;
2871898Shueston 			}
2881898Shueston 
2891898Shueston 			/* The root complex exists! */
2901898Shueston 			topo_mod_dprintf(mp, "declaring "
2911898Shueston 			    "/chassis=0/ioboard=%d/hostbridge=%d/pciexrc=%d\n",
2921898Shueston 			    brd, hb, rc);
2931898Shueston 
2941898Shueston 			/*
2951898Shueston 			 * If we haven't created a hostbridge node yet, do it
2961898Shueston 			 * now.
2971898Shueston 			 */
2981898Shueston 			if (hbnode == NULL) {
2991898Shueston 				hbnode = opl_hb_node_create(mp, ion, hb);
3001898Shueston 				if (hbnode == NULL) {
3011898Shueston 					topo_mod_dprintf(mp,
3022499Shueston 					    "unable to create hbnode: %s\n",
3031898Shueston 					    topo_strerror(topo_mod_errno(mp)));
3042027Ssethg 					topo_mod_unload(pcimod);
3051898Shueston 					return (-1);
3061898Shueston 				}
3071898Shueston 
3081898Shueston 			}
3091898Shueston 
3101898Shueston 			/* Create the root complex node */
3113062Scindi 			rcnode = opl_rc_node_create(mp, hbnode, p, rc);
3121898Shueston 			if (rcnode == NULL) {
3131898Shueston 				topo_mod_dprintf(mp,
3142499Shueston 				    "unable to create rcnode: %s\n",
3151898Shueston 				    topo_strerror(topo_mod_errno(mp)));
3162027Ssethg 				topo_mod_unload(pcimod);
3171898Shueston 				return (-1);
3181898Shueston 			}
3191898Shueston 
3201898Shueston 			/* Enumerate pcibus nodes under the root complex */
3211898Shueston 			if (topo_mod_enumerate(pcimod, rcnode,
3223062Scindi 			    PCI_BUS, PCIEX_BUS, 0, 255, NULL) != 0) {
3231898Shueston 				topo_mod_dprintf(mp,
3242499Shueston 				    "error enumerating pcibus: %s\n",
3251898Shueston 				    topo_strerror(topo_mod_errno(mp)));
3262027Ssethg 				topo_mod_unload(pcimod);
3271898Shueston 				return (-1);
3281898Shueston 			}
3291898Shueston 		}
3301898Shueston 	}
3312027Ssethg 	topo_mod_unload(pcimod);
3321898Shueston 	return (0);
3331898Shueston }
334