14df55fdeSJanie Lu /*
24df55fdeSJanie Lu  * CDDL HEADER START
34df55fdeSJanie Lu  *
44df55fdeSJanie Lu  * The contents of this file are subject to the terms of the
54df55fdeSJanie Lu  * Common Development and Distribution License (the "License").
64df55fdeSJanie Lu  * You may not use this file except in compliance with the License.
74df55fdeSJanie Lu  *
84df55fdeSJanie Lu  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94df55fdeSJanie Lu  * or http://www.opensolaris.org/os/licensing.
104df55fdeSJanie Lu  * See the License for the specific language governing permissions
114df55fdeSJanie Lu  * and limitations under the License.
124df55fdeSJanie Lu  *
134df55fdeSJanie Lu  * When distributing Covered Code, include this CDDL HEADER in each
144df55fdeSJanie Lu  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154df55fdeSJanie Lu  * If applicable, add the following below this CDDL HEADER, with the
164df55fdeSJanie Lu  * fields enclosed by brackets "[]" replaced with your own identifying
174df55fdeSJanie Lu  * information: Portions Copyright [yyyy] [name of copyright owner]
184df55fdeSJanie Lu  *
194df55fdeSJanie Lu  * CDDL HEADER END
204df55fdeSJanie Lu  */
214df55fdeSJanie Lu 
224df55fdeSJanie Lu /*
234f764f91SCheng Sean Ye  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24*ffb64830SJordan Paige Hendricks  * Copyright 2019 Joyent, Inc.
254df55fdeSJanie Lu  */
264df55fdeSJanie Lu #include <strings.h>
274df55fdeSJanie Lu #include <fm/topo_hc.h>
284df55fdeSJanie Lu #include <sys/fm/util.h>
294df55fdeSJanie Lu #include <libxml/xpath.h>
304df55fdeSJanie Lu #include <libxml/parser.h>
314df55fdeSJanie Lu #include <libxml/xpathInternals.h>
324df55fdeSJanie Lu #include <libxml/tree.h>
334df55fdeSJanie Lu 
344df55fdeSJanie Lu #include "fabric-xlate.h"
354df55fdeSJanie Lu 
364df55fdeSJanie Lu #define	HAS_PROP(node, name) xmlHasProp(node, (const xmlChar *)name)
374df55fdeSJanie Lu #define	GET_PROP(node, name) ((char *)xmlGetProp(node, (const xmlChar *)name))
384df55fdeSJanie Lu #define	FREE_PROP(prop) xmlFree((xmlChar *)prop)
394df55fdeSJanie Lu 
404df55fdeSJanie Lu extern xmlXPathContextPtr fab_xpathCtx;
414df55fdeSJanie Lu 
424df55fdeSJanie Lu /* ARGSUSED */
434df55fdeSJanie Lu int
fab_prep_basic_erpt(fmd_hdl_t * hdl,nvlist_t * nvl,nvlist_t * erpt,boolean_t isRC)444df55fdeSJanie Lu fab_prep_basic_erpt(fmd_hdl_t *hdl, nvlist_t *nvl, nvlist_t *erpt,
454df55fdeSJanie Lu     boolean_t isRC)
464df55fdeSJanie Lu {
474df55fdeSJanie Lu 	uint64_t	*now;
484df55fdeSJanie Lu 	uint64_t	ena;
494df55fdeSJanie Lu 	uint_t		nelem;
504df55fdeSJanie Lu 	nvlist_t	*detector, *new_detector;
514df55fdeSJanie Lu 	char		rcpath[255];
524df55fdeSJanie Lu 	int		err = 0;
534df55fdeSJanie Lu 
544df55fdeSJanie Lu 	/* Grab the tod, ena and detector(FMRI) */
554df55fdeSJanie Lu 	err |= nvlist_lookup_uint64_array(nvl, "__tod", &now, &nelem);
564df55fdeSJanie Lu 	err |= nvlist_lookup_uint64(nvl, "ena", &ena);
574df55fdeSJanie Lu 	err |= nvlist_lookup_nvlist(nvl, FM_EREPORT_DETECTOR, &detector);
584df55fdeSJanie Lu 	if (err)
594df55fdeSJanie Lu 		return (err);
604df55fdeSJanie Lu 
614df55fdeSJanie Lu 	/* Make a copy of the detector */
624df55fdeSJanie Lu 	err = nvlist_dup(detector, &new_detector, NV_UNIQUE_NAME);
634df55fdeSJanie Lu 	if (err)
644df55fdeSJanie Lu 		return (err);
654df55fdeSJanie Lu 
664df55fdeSJanie Lu 	/* Copy the tod and ena to erpt */
674df55fdeSJanie Lu 	(void) nvlist_add_uint64(erpt, FM_EREPORT_ENA, ena);
684df55fdeSJanie Lu 	(void) nvlist_add_uint64_array(erpt, "__tod", now, nelem);
694df55fdeSJanie Lu 
704df55fdeSJanie Lu 	/*
714df55fdeSJanie Lu 	 * Create the correct ROOT FMRI from PCIe leaf fabric ereports.	 Used
724df55fdeSJanie Lu 	 * only by fab_prep_fake_rc_erpt.  See the fab_pciex_fake_rc_erpt_tbl
734df55fdeSJanie Lu 	 * comments for more information.
744df55fdeSJanie Lu 	 */
754df55fdeSJanie Lu 	if (isRC && fab_get_rcpath(hdl, nvl, rcpath)) {
764df55fdeSJanie Lu 		/* Create the correct PCIe RC new_detector aka FMRI */
774df55fdeSJanie Lu 		(void) nvlist_remove(new_detector, FM_FMRI_DEV_PATH,
784df55fdeSJanie Lu 		    DATA_TYPE_STRING);
794df55fdeSJanie Lu 		(void) nvlist_add_string(new_detector, FM_FMRI_DEV_PATH,
804df55fdeSJanie Lu 		    rcpath);
814df55fdeSJanie Lu 	}
824df55fdeSJanie Lu 
834df55fdeSJanie Lu 	/* Copy the FMRI to erpt */
844df55fdeSJanie Lu 	(void) nvlist_add_nvlist(erpt, FM_EREPORT_DETECTOR, new_detector);
854df55fdeSJanie Lu 
864df55fdeSJanie Lu 	nvlist_free(new_detector);
874df55fdeSJanie Lu 	return (err);
884df55fdeSJanie Lu }
894df55fdeSJanie Lu 
904df55fdeSJanie Lu void
fab_send_tgt_erpt(fmd_hdl_t * hdl,fab_data_t * data,const char * class,boolean_t isPrimary)914df55fdeSJanie Lu fab_send_tgt_erpt(fmd_hdl_t *hdl, fab_data_t *data, const char *class,
924df55fdeSJanie Lu     boolean_t isPrimary)
934df55fdeSJanie Lu {
944df55fdeSJanie Lu 	nvlist_t	*nvl = data->nvl;
954df55fdeSJanie Lu 	nvlist_t	*erpt;
964df55fdeSJanie Lu 	char		*fmri = NULL;
974df55fdeSJanie Lu 	uint32_t	tgt_trans;
984df55fdeSJanie Lu 	uint64_t	tgt_addr;
994df55fdeSJanie Lu 	uint16_t	tgt_bdf;
1004df55fdeSJanie Lu 
1014df55fdeSJanie Lu 	if (isPrimary) {
1024df55fdeSJanie Lu 		tgt_trans = data->pcie_ue_tgt_trans;
1034df55fdeSJanie Lu 		tgt_addr = data->pcie_ue_tgt_addr;
1044df55fdeSJanie Lu 		tgt_bdf = data->pcie_ue_tgt_bdf;
1054df55fdeSJanie Lu 	} else {
1064df55fdeSJanie Lu 		tgt_trans = data->pcie_sue_tgt_trans;
1074df55fdeSJanie Lu 		tgt_addr = data->pcie_sue_tgt_addr;
1084df55fdeSJanie Lu 		tgt_bdf = data->pcie_sue_tgt_bdf;
1094df55fdeSJanie Lu 	}
1104df55fdeSJanie Lu 
1114df55fdeSJanie Lu 	fmd_hdl_debug(hdl, "Sending Target Ereport: "
1124df55fdeSJanie Lu 	    "type 0x%x addr 0x%llx fltbdf 0x%x\n",
1134df55fdeSJanie Lu 	    tgt_trans, tgt_addr, tgt_bdf);
1144df55fdeSJanie Lu 
1154df55fdeSJanie Lu 	if (!tgt_trans)
1164df55fdeSJanie Lu 		return;
1174df55fdeSJanie Lu 
1184df55fdeSJanie Lu 	if ((tgt_trans == PF_ADDR_PIO) && tgt_addr)
1194df55fdeSJanie Lu 		fmri = fab_find_addr(hdl, nvl, tgt_addr);
1204df55fdeSJanie Lu 	else if ((tgt_trans == PF_ADDR_CFG || (tgt_trans == PF_ADDR_DMA)) &&
1214df55fdeSJanie Lu 	    tgt_bdf)
1224df55fdeSJanie Lu 		fmri = fab_find_bdf(hdl, nvl, tgt_bdf);
1234df55fdeSJanie Lu 
1244df55fdeSJanie Lu 	if (fmri) {
1254df55fdeSJanie Lu 		uint64_t	*now;
1264df55fdeSJanie Lu 		uint64_t	ena;
1274df55fdeSJanie Lu 		uint_t		nelem;
1284df55fdeSJanie Lu 		nvlist_t	*detector;
1294df55fdeSJanie Lu 		int		err = 0;
1304df55fdeSJanie Lu 
1314df55fdeSJanie Lu 		/* Allocate space for new erpt */
1324df55fdeSJanie Lu 		if (nvlist_alloc(&erpt, NV_UNIQUE_NAME, 0) != 0)
1334df55fdeSJanie Lu 			goto done;
1344df55fdeSJanie Lu 
1354df55fdeSJanie Lu 		/* Generate the target ereport class */
1364df55fdeSJanie Lu 		(void) snprintf(fab_buf, FM_MAX_CLASS, "ereport.io.%s.%s",
1374df55fdeSJanie Lu 		    PCI_ERROR_SUBCLASS, class);
1384df55fdeSJanie Lu 		(void) nvlist_add_string(erpt, FM_CLASS, fab_buf);
1394df55fdeSJanie Lu 
1404df55fdeSJanie Lu 		/* Grab the tod, ena and detector(FMRI) */
1414df55fdeSJanie Lu 		err |= nvlist_lookup_uint64_array(nvl, "__tod", &now, &nelem);
1424df55fdeSJanie Lu 		err |= nvlist_lookup_uint64(nvl, "ena", &ena);
1434df55fdeSJanie Lu 
1444df55fdeSJanie Lu 		/* Copy the tod and ena to erpt */
1454df55fdeSJanie Lu 		(void) nvlist_add_uint64(erpt, FM_EREPORT_ENA, ena);
1464df55fdeSJanie Lu 		(void) nvlist_add_uint64_array(erpt, "__tod", now, nelem);
1474df55fdeSJanie Lu 
1484df55fdeSJanie Lu 		/* Create the correct FMRI */
1494df55fdeSJanie Lu 		if (nvlist_alloc(&detector, NV_UNIQUE_NAME, 0) != 0) {
1504df55fdeSJanie Lu 			nvlist_free(erpt);
1514df55fdeSJanie Lu 			goto done;
1524df55fdeSJanie Lu 		}
1534df55fdeSJanie Lu 		(void) nvlist_add_uint8(detector, FM_VERSION,
1544df55fdeSJanie Lu 		    FM_DEV_SCHEME_VERSION);
1554df55fdeSJanie Lu 		(void) nvlist_add_string(detector, FM_FMRI_SCHEME,
1564df55fdeSJanie Lu 		    FM_FMRI_SCHEME_DEV);
1574df55fdeSJanie Lu 		(void) nvlist_add_string(detector, FM_FMRI_DEV_PATH, fmri);
1584df55fdeSJanie Lu 		(void) nvlist_add_nvlist(erpt, FM_EREPORT_DETECTOR, detector);
1594df55fdeSJanie Lu 		nvlist_free(detector);
1604df55fdeSJanie Lu 
1614df55fdeSJanie Lu 		/* Add the address payload */
1624df55fdeSJanie Lu 		(void) nvlist_add_uint64(erpt, PCI_PA, tgt_addr);
1634df55fdeSJanie Lu 
1644df55fdeSJanie Lu 		fmd_hdl_debug(hdl, "Sending target ereport: %s 0x%x\n",
1654df55fdeSJanie Lu 		    fab_buf, tgt_addr);
1664df55fdeSJanie Lu 		fmd_xprt_post(hdl, fab_fmd_xprt, erpt, 0);
1674df55fdeSJanie Lu 		if (fmd_xprt_error(hdl, fab_fmd_xprt))
1684df55fdeSJanie Lu 			goto done;
1694df55fdeSJanie Lu 		fmd_hdl_strfree(hdl, fmri);
1704df55fdeSJanie Lu 	} else {
1714df55fdeSJanie Lu 		fmd_hdl_debug(hdl,
1724df55fdeSJanie Lu 		    "Cannot find Target FMRI addr:0x%llx bdf 0x%x\n",
1734df55fdeSJanie Lu 		    tgt_addr, tgt_bdf);
1744df55fdeSJanie Lu 	}
1754df55fdeSJanie Lu 
1764df55fdeSJanie Lu 	return;
1774df55fdeSJanie Lu done:
1784df55fdeSJanie Lu 	if (fmri)
1794df55fdeSJanie Lu 		xmlFree(fmri);
1804df55fdeSJanie Lu 	fmd_hdl_debug(hdl, "Failed to send Target PCI ereport\n");
1814df55fdeSJanie Lu }
1824df55fdeSJanie Lu 
1834df55fdeSJanie Lu void
fab_send_erpt(fmd_hdl_t * hdl,fab_data_t * data,fab_err_tbl_t * tbl)1844df55fdeSJanie Lu fab_send_erpt(fmd_hdl_t *hdl, fab_data_t *data, fab_err_tbl_t *tbl)
1854df55fdeSJanie Lu {
1864df55fdeSJanie Lu 	fab_erpt_tbl_t	*erpt_tbl, *entry;
1874df55fdeSJanie Lu 	nvlist_t	*erpt;
1884df55fdeSJanie Lu 	uint32_t	reg;
189*ffb64830SJordan Paige Hendricks 	int		err;
1904df55fdeSJanie Lu 
1914df55fdeSJanie Lu 	erpt_tbl = tbl->erpt_tbl;
1924df55fdeSJanie Lu 	if (tbl->reg_size == 16) {
1934df55fdeSJanie Lu 		reg = (uint32_t)*((uint16_t *)
1944df55fdeSJanie Lu 		    ((uint32_t)data + tbl->reg_offset));
1954df55fdeSJanie Lu 	} else {
1964df55fdeSJanie Lu 		reg = *((uint32_t *)((uint32_t)data + tbl->reg_offset));
1974df55fdeSJanie Lu 	}
1984df55fdeSJanie Lu 
1994df55fdeSJanie Lu 	for (entry = erpt_tbl; entry->err_class; entry++) {
2004df55fdeSJanie Lu 		if (!(reg & entry->reg_bit))
2014df55fdeSJanie Lu 			continue;
2024df55fdeSJanie Lu 
2034df55fdeSJanie Lu 		if (nvlist_alloc(&erpt, NV_UNIQUE_NAME, 0) != 0)
2044df55fdeSJanie Lu 			goto done;
205*ffb64830SJordan Paige Hendricks 
206*ffb64830SJordan Paige Hendricks 		err = tbl->fab_prep(hdl, data, erpt, entry);
207*ffb64830SJordan Paige Hendricks 		if (err != 0 && err != PF_EREPORT_IGNORE) {
2084df55fdeSJanie Lu 			fmd_hdl_debug(hdl, "Prepping ereport failed: "
2094df55fdeSJanie Lu 			    "class = %s\n", entry->err_class);
2104df55fdeSJanie Lu 			nvlist_free(erpt);
2114df55fdeSJanie Lu 			continue;
2124df55fdeSJanie Lu 		}
2134df55fdeSJanie Lu 
214036ec191SCheng Sean Ye 		if (data->pcie_rp_send_all) {
215036ec191SCheng Sean Ye 			fab_send_erpt_all_rps(hdl, erpt);
216036ec191SCheng Sean Ye 			nvlist_free(erpt);
217036ec191SCheng Sean Ye 			return;
218036ec191SCheng Sean Ye 		}
219036ec191SCheng Sean Ye 
2204df55fdeSJanie Lu 		fmd_hdl_debug(hdl, "Sending ereport: %s 0x%x\n", fab_buf, reg);
2214df55fdeSJanie Lu 		fmd_xprt_post(hdl, fab_fmd_xprt, erpt, 0);
2224df55fdeSJanie Lu 		if (fmd_xprt_error(hdl, fab_fmd_xprt)) {
2234df55fdeSJanie Lu 			fmd_hdl_debug(hdl, "Failed to send PCI ereport\n");
2244df55fdeSJanie Lu 			return;
2254df55fdeSJanie Lu 		}
2264df55fdeSJanie Lu 	}
2274df55fdeSJanie Lu 
2284df55fdeSJanie Lu 	return;
2294df55fdeSJanie Lu done:
2304df55fdeSJanie Lu 	fmd_hdl_debug(hdl, "Failed  to send PCI ereport\n");
2314df55fdeSJanie Lu }
2324df55fdeSJanie Lu 
2334df55fdeSJanie Lu char *
fab_xpath_query(fmd_hdl_t * hdl,const char * query)2344df55fdeSJanie Lu fab_xpath_query(fmd_hdl_t *hdl, const char *query)
2354df55fdeSJanie Lu {
2364df55fdeSJanie Lu 	xmlXPathObjectPtr xpathObj;
2374df55fdeSJanie Lu 	xmlNodeSetPtr nodes;
2384df55fdeSJanie Lu 	char *temp, *res;
2394df55fdeSJanie Lu 
2404df55fdeSJanie Lu 	fmd_hdl_debug(hdl, "xpathObj query %s\n", query);
2414df55fdeSJanie Lu 
2424df55fdeSJanie Lu 	xpathObj = xmlXPathEvalExpression((const xmlChar *)query,
2434df55fdeSJanie Lu 	    fab_xpathCtx);
2444df55fdeSJanie Lu 
2454df55fdeSJanie Lu 	if (xpathObj == NULL)
2464df55fdeSJanie Lu 		return (NULL);
2474df55fdeSJanie Lu 
2484df55fdeSJanie Lu 	fmd_hdl_debug(hdl, "xpathObj 0x%p type %d\n", xpathObj,
2494df55fdeSJanie Lu 	    xpathObj->type);
2504df55fdeSJanie Lu 	nodes = xpathObj->nodesetval;
2514df55fdeSJanie Lu 
2524df55fdeSJanie Lu 	if (nodes) {
2534df55fdeSJanie Lu 		temp = (char *)xmlNodeGetContent(nodes->nodeTab[0]);
2544df55fdeSJanie Lu 		fmd_hdl_debug(hdl, "query result: %s\n", temp);
2554df55fdeSJanie Lu 		res = fmd_hdl_strdup(hdl, temp, FMD_SLEEP);
2564df55fdeSJanie Lu 		xmlFree(temp);
2574df55fdeSJanie Lu 		xmlXPathFreeObject(xpathObj);
2584df55fdeSJanie Lu 		return (res);
2594df55fdeSJanie Lu 	}
2604df55fdeSJanie Lu 	xmlXPathFreeObject(xpathObj);
2614df55fdeSJanie Lu 	return (NULL);
2624df55fdeSJanie Lu }
2634df55fdeSJanie Lu 
2644df55fdeSJanie Lu #define	FAB_HC2DEV_QUERY_SIZE_MIN 160
2654df55fdeSJanie Lu #define	FAB_HC2DEV_QUERY_SIZE(sz) \
2664df55fdeSJanie Lu 	((sz + FAB_HC2DEV_QUERY_SIZE_MIN) * sizeof (char))
2674df55fdeSJanie Lu 
2684df55fdeSJanie Lu /*
2694df55fdeSJanie Lu  * hc_path is in form of "/motherboard=0/hostbridge=0/pciexrc=0"
2704df55fdeSJanie Lu  */
2714df55fdeSJanie Lu boolean_t
fab_hc2dev(fmd_hdl_t * hdl,const char * hc_path,char ** dev_path)2724df55fdeSJanie Lu fab_hc2dev(fmd_hdl_t *hdl, const char *hc_path, char **dev_path)
2734df55fdeSJanie Lu {
2744df55fdeSJanie Lu 	char *query;
2754df55fdeSJanie Lu 	uint_t len = FAB_HC2DEV_QUERY_SIZE_MIN + strlen(hc_path);
2764df55fdeSJanie Lu 
2774df55fdeSJanie Lu 	query = fmd_hdl_alloc(hdl, len, FMD_SLEEP);
2784df55fdeSJanie Lu 	(void) snprintf(query, len, "//propval[@name='resource' and contains("
2794df55fdeSJanie Lu 	    "substring(@value, string-length(@value) - %d + 1), '%s')]"
2804df55fdeSJanie Lu 	    "/parent::*/following-sibling::*/propval[@name='dev']/@value",
2814df55fdeSJanie Lu 	    strlen(hc_path) + 1, hc_path);
2824df55fdeSJanie Lu 
2834df55fdeSJanie Lu 	*dev_path = fab_xpath_query(hdl, query);
2844df55fdeSJanie Lu 
2854df55fdeSJanie Lu 	fmd_hdl_free(hdl, query, len);
2864df55fdeSJanie Lu 
2874df55fdeSJanie Lu 	return (*dev_path != NULL);
2884df55fdeSJanie Lu }
2894df55fdeSJanie Lu 
2904df55fdeSJanie Lu static boolean_t
fab_hc_path(fmd_hdl_t * hdl,nvlist_t * detector,char ** hcpath,size_t * lenp)2914df55fdeSJanie Lu fab_hc_path(fmd_hdl_t *hdl, nvlist_t *detector, char **hcpath, size_t *lenp)
2924df55fdeSJanie Lu {
2934df55fdeSJanie Lu 	char c, *name, *id, *buf;
2944df55fdeSJanie Lu 	uint_t i, size;
2954df55fdeSJanie Lu 	nvlist_t **hcl;
2964df55fdeSJanie Lu 	size_t len = 0, buf_size = 0;
2974df55fdeSJanie Lu 
2984df55fdeSJanie Lu 	if (nvlist_lookup_nvlist_array(detector, FM_FMRI_HC_LIST, &hcl,
2994df55fdeSJanie Lu 	    &size) != 0)
3004df55fdeSJanie Lu 		return (B_FALSE);
3014df55fdeSJanie Lu 
3024df55fdeSJanie Lu 	for (i = 0; i < size; i++) {
3034df55fdeSJanie Lu 		if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &name) != 0)
3044df55fdeSJanie Lu 			return (B_FALSE);
3054df55fdeSJanie Lu 		if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &id) != 0)
3064df55fdeSJanie Lu 			return (B_FALSE);
3074df55fdeSJanie Lu 		buf_size += snprintf(&c, 1, "/%s=%s", name, id);
3084df55fdeSJanie Lu 	}
3094df55fdeSJanie Lu 
3104df55fdeSJanie Lu 	buf_size++;
3114df55fdeSJanie Lu 	buf = fmd_hdl_alloc(hdl, buf_size, FMD_SLEEP);
3124df55fdeSJanie Lu 
3134df55fdeSJanie Lu 	for (i = 0; i < size; i++) {
3144df55fdeSJanie Lu 		(void) nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &name);
3154df55fdeSJanie Lu 		(void) nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &id);
3164df55fdeSJanie Lu 		len += snprintf(buf + len, buf_size - len, "/%s=%s", name, id);
3174df55fdeSJanie Lu 	}
3184df55fdeSJanie Lu 
3194df55fdeSJanie Lu 	*hcpath = buf;
3204df55fdeSJanie Lu 	*lenp = buf_size;
3214df55fdeSJanie Lu 
3224df55fdeSJanie Lu 	return (B_TRUE);
3234df55fdeSJanie Lu }
3244df55fdeSJanie Lu 
3254df55fdeSJanie Lu boolean_t
fab_hc2dev_nvl(fmd_hdl_t * hdl,nvlist_t * detector,char ** dev_path)3264df55fdeSJanie Lu fab_hc2dev_nvl(fmd_hdl_t *hdl, nvlist_t *detector, char **dev_path)
3274df55fdeSJanie Lu {
3284df55fdeSJanie Lu 	char *hcl;
3294df55fdeSJanie Lu 	size_t len;
3304df55fdeSJanie Lu 
3314df55fdeSJanie Lu 	if (! fab_hc_path(hdl, detector, &hcl, &len))
3324df55fdeSJanie Lu 		return (B_FALSE);
3334df55fdeSJanie Lu 
3344df55fdeSJanie Lu 	(void) fab_hc2dev(hdl, hcl, dev_path);
3354df55fdeSJanie Lu 
3364df55fdeSJanie Lu 	fmd_hdl_free(hdl, hcl, len);
3374df55fdeSJanie Lu 
3384df55fdeSJanie Lu 	return (*dev_path != NULL);
3394df55fdeSJanie Lu }
3404df55fdeSJanie Lu 
3414df55fdeSJanie Lu boolean_t
fab_get_hcpath(fmd_hdl_t * hdl,nvlist_t * nvl,char ** hcpath,size_t * len)3424df55fdeSJanie Lu fab_get_hcpath(fmd_hdl_t *hdl, nvlist_t *nvl, char **hcpath, size_t *len)
3434df55fdeSJanie Lu {
3444df55fdeSJanie Lu 	nvlist_t *detector;
3454df55fdeSJanie Lu 	char *scheme;
3464df55fdeSJanie Lu 
3474df55fdeSJanie Lu 	if (nvlist_lookup_nvlist(nvl, FM_EREPORT_DETECTOR, &detector) != 0 ||
3484df55fdeSJanie Lu 	    nvlist_lookup_string(detector, FM_FMRI_SCHEME, &scheme) != 0 ||
3494df55fdeSJanie Lu 	    ! STRCMP(scheme, FM_FMRI_SCHEME_HC))
3504df55fdeSJanie Lu 		return (B_FALSE);
3514df55fdeSJanie Lu 
3524df55fdeSJanie Lu 	return (fab_hc_path(hdl, detector, hcpath, len));
3534df55fdeSJanie Lu }
3544df55fdeSJanie Lu 
3554df55fdeSJanie Lu char *
fab_find_rppath_by_df(fmd_hdl_t * hdl,nvlist_t * nvl,uint8_t df)3564df55fdeSJanie Lu fab_find_rppath_by_df(fmd_hdl_t *hdl, nvlist_t *nvl, uint8_t df)
3574df55fdeSJanie Lu {
3584df55fdeSJanie Lu 	char	query[500];
3594df55fdeSJanie Lu 	char	str[10];
3604df55fdeSJanie Lu 	char	*hcpath;
3614df55fdeSJanie Lu 	size_t	len;
3624df55fdeSJanie Lu 
3634df55fdeSJanie Lu 	(void) snprintf(str, sizeof (str), "%0hhx", df);
3644df55fdeSJanie Lu 
3654df55fdeSJanie Lu 	/*
3664df55fdeSJanie Lu 	 * get the string form of the hc detector, eg
3674df55fdeSJanie Lu 	 * /chassis=0/motherboard=0/hostbridge=0
3684df55fdeSJanie Lu 	 */
3694df55fdeSJanie Lu 	if (!fab_get_hcpath(hdl, nvl, &hcpath, &len))
3704df55fdeSJanie Lu 		return (NULL);
3714df55fdeSJanie Lu 
3724df55fdeSJanie Lu 	/*
3734df55fdeSJanie Lu 	 * Explanation of the XSL XPATH Query
3744df55fdeSJanie Lu 	 * Line 1: Look at all nodes with the node name "propval"
3754df55fdeSJanie Lu 	 * Line 2: See if the "BDF" of the node matches DF
3764df55fdeSJanie Lu 	 * Line 3-4: See if the the node is pciexrc
3774df55fdeSJanie Lu 	 * Line 5-6: See if the "ASRU" contains root complex
3784df55fdeSJanie Lu 	 * Line 7-8: Go up one level and get prop value of io/dev
3794df55fdeSJanie Lu 	 */
3804df55fdeSJanie Lu 	(void) snprintf(query, sizeof (query), "//propval["
3814df55fdeSJanie Lu 	    "@name='BDF' and contains(substring(@value, "
3824df55fdeSJanie Lu 	    "string-length(@value) - 1), '%s')]"
3834df55fdeSJanie Lu 	    "/parent::*/parent::*/propgroup[@name='pci']/propval"
3844df55fdeSJanie Lu 	    "[@name='extended-capabilities' and @value='%s']"
3854df55fdeSJanie Lu 	    "/parent::*/parent::*/propgroup[@name='protocol']"
3864df55fdeSJanie Lu 	    "/propval[@name='resource' and contains(@value, '%s')]"
3874df55fdeSJanie Lu 	    "/parent::*/parent::*/propgroup[@name='io']"
3884df55fdeSJanie Lu 	    "/propval[@name='dev']/@value", str, PCIEX_ROOT, hcpath);
3894df55fdeSJanie Lu 
3904df55fdeSJanie Lu 	fmd_hdl_free(hdl, hcpath, len);
3914df55fdeSJanie Lu 
3924df55fdeSJanie Lu 	return (fab_xpath_query(hdl, query));
3934df55fdeSJanie Lu }
3944df55fdeSJanie Lu 
3954df55fdeSJanie Lu char *
fab_find_rppath_by_devbdf(fmd_hdl_t * hdl,nvlist_t * nvl,pcie_req_id_t bdf)3964df55fdeSJanie Lu fab_find_rppath_by_devbdf(fmd_hdl_t *hdl, nvlist_t *nvl, pcie_req_id_t bdf)
3974df55fdeSJanie Lu {
3984df55fdeSJanie Lu 	xmlXPathObjectPtr xpathObj;
3994df55fdeSJanie Lu 	xmlNodeSetPtr nodes;
4004df55fdeSJanie Lu 	xmlNodePtr devNode;
401*ffb64830SJordan Paige Hendricks 	char	*retval, *temp;
4024df55fdeSJanie Lu 	char	query[500];
4034df55fdeSJanie Lu 	int	i, size, bus, dev, fn;
4044df55fdeSJanie Lu 	char	*hcpath;
4054df55fdeSJanie Lu 	size_t	len;
4064df55fdeSJanie Lu 
4074df55fdeSJanie Lu 	if (bdf != (uint16_t)-1) {
4084df55fdeSJanie Lu 		bus = (bdf & PCIE_REQ_ID_BUS_MASK) >> PCIE_REQ_ID_BUS_SHIFT;
4094df55fdeSJanie Lu 		dev = (bdf & PCIE_REQ_ID_DEV_MASK) >> PCIE_REQ_ID_DEV_SHIFT;
4104df55fdeSJanie Lu 		fn = (bdf & PCIE_REQ_ID_FUNC_MASK) >> PCIE_REQ_ID_FUNC_SHIFT;
4114df55fdeSJanie Lu 	}
4124df55fdeSJanie Lu 
4134df55fdeSJanie Lu 	/*
4144df55fdeSJanie Lu 	 * get the string form of the hc detector, eg
4154df55fdeSJanie Lu 	 * /chassis=0/motherboard=0/hostbridge=0
4164df55fdeSJanie Lu 	 */
4174df55fdeSJanie Lu 	if (!fab_get_hcpath(hdl, nvl, &hcpath, &len))
4184df55fdeSJanie Lu 		goto fail;
4194df55fdeSJanie Lu 
4204df55fdeSJanie Lu 	/*
4214df55fdeSJanie Lu 	 * Explanation of the XSL XPATH Query
4224df55fdeSJanie Lu 	 * Line 1: Look at all nodes with the node name "propval"
4234df55fdeSJanie Lu 	 * Line 2-3: See if the "value" of the node ends with correct PCIEx BDF
4244df55fdeSJanie Lu 	 * Line 4-5: See if the "value" of the node ends with correct PCI BDF
4254df55fdeSJanie Lu 	 * Line 6: Go up one level to the parent of the current node
4264df55fdeSJanie Lu 	 * Line 7: See if child node contains "ASRU" with the same PCIe Root
4274df55fdeSJanie Lu 	 * Line 8: Go up see all the ancestors
4284df55fdeSJanie Lu 	 */
4294df55fdeSJanie Lu 	(void) snprintf(query, sizeof (query), "//propval["
4304df55fdeSJanie Lu 	    "contains(substring(@value, string-length(@value) - 34), "
4314df55fdeSJanie Lu 	    "'pciexbus=%d/pciexdev=%d/pciexfn=%d') or "
4324df55fdeSJanie Lu 	    "contains(substring(@value, string-length(@value) - 28), "
4334df55fdeSJanie Lu 	    "'pcibus=%d/pcidev=%d/pcifn=%d')"
4344df55fdeSJanie Lu 	    "]/parent::"
4354df55fdeSJanie Lu 	    "*/propval[@name='resource' and contains(@value, '%s')]"
4364df55fdeSJanie Lu 	    "/ancestor::*",
4374df55fdeSJanie Lu 	    bus, dev, fn, bus, dev, fn, hcpath);
4384df55fdeSJanie Lu 
4394df55fdeSJanie Lu 	fmd_hdl_free(hdl, hcpath, len);
4404df55fdeSJanie Lu 
4414df55fdeSJanie Lu 	fmd_hdl_debug(hdl, "xpathObj query %s\n", query);
4424df55fdeSJanie Lu 
4434df55fdeSJanie Lu 	xpathObj = xmlXPathEvalExpression((const xmlChar *)query, fab_xpathCtx);
4444df55fdeSJanie Lu 
4454df55fdeSJanie Lu 	if (xpathObj == NULL)
4464df55fdeSJanie Lu 		goto fail;
4474df55fdeSJanie Lu 
4484df55fdeSJanie Lu 	nodes = xpathObj->nodesetval;
4494df55fdeSJanie Lu 	size = (nodes) ? nodes->nodeNr : 0;
4504df55fdeSJanie Lu 
4514df55fdeSJanie Lu 	fmd_hdl_debug(hdl, "xpathObj 0x%p type %d size %d\n",
4524df55fdeSJanie Lu 	    xpathObj, xpathObj->type, size);
4534df55fdeSJanie Lu 
4544df55fdeSJanie Lu 	for (i = 0; i < size; i++) {
4554df55fdeSJanie Lu 		devNode = nodes->nodeTab[i];
4564df55fdeSJanie Lu 		if (STRCMP(devNode->name, "range") &&
4574df55fdeSJanie Lu 		    HAS_PROP(devNode, "name")) {
4584df55fdeSJanie Lu 			char *tprop = GET_PROP(devNode, "name");
4594df55fdeSJanie Lu 
4604df55fdeSJanie Lu 			/* find "range name='pciexrc'" in ancestors */
4614df55fdeSJanie Lu 			if (STRCMP(tprop, PCIEX_ROOT)) {
4624df55fdeSJanie Lu 				/* go down to the pciexrc instance node */
4634df55fdeSJanie Lu 				FREE_PROP(tprop);
4644df55fdeSJanie Lu 				devNode = nodes->nodeTab[i+1];
4654df55fdeSJanie Lu 				goto found;
4664df55fdeSJanie Lu 			}
4674df55fdeSJanie Lu 			FREE_PROP(tprop);
4684df55fdeSJanie Lu 		}
4694df55fdeSJanie Lu 	}
4704df55fdeSJanie Lu 	goto fail;
4714df55fdeSJanie Lu 
4724df55fdeSJanie Lu found:
4734df55fdeSJanie Lu 	/* Traverse down the xml tree to find the right propgroup */
4744df55fdeSJanie Lu 	for (devNode = devNode->children; devNode; devNode = devNode->next) {
4754df55fdeSJanie Lu 		if (STRCMP(devNode->name, "propgroup")) {
4764df55fdeSJanie Lu 			char *tprop = GET_PROP(devNode, "name");
4774df55fdeSJanie Lu 
4784df55fdeSJanie Lu 			if (STRCMP(tprop, "io")) {
4794df55fdeSJanie Lu 				FREE_PROP(tprop);
4804df55fdeSJanie Lu 				goto propgroup;
4814df55fdeSJanie Lu 			}
4824df55fdeSJanie Lu 			FREE_PROP(tprop);
4834df55fdeSJanie Lu 		}
4844df55fdeSJanie Lu 	}
4854df55fdeSJanie Lu 	goto fail;
4864df55fdeSJanie Lu 
4874df55fdeSJanie Lu propgroup:
4884df55fdeSJanie Lu 	/* Retrive the "dev" propval and return */
4894df55fdeSJanie Lu 	for (devNode = devNode->children; devNode; devNode = devNode->next) {
4904df55fdeSJanie Lu 		if (STRCMP(devNode->name, "propval")) {
4914df55fdeSJanie Lu 			char *tprop = GET_PROP(devNode, "name");
4924df55fdeSJanie Lu 
4934df55fdeSJanie Lu 			if (STRCMP(tprop, "dev")) {
4944df55fdeSJanie Lu 				temp = GET_PROP(devNode, "value");
4954df55fdeSJanie Lu 				retval = fmd_hdl_strdup(hdl, temp, FMD_SLEEP);
4964df55fdeSJanie Lu 				fmd_hdl_debug(hdl, "RP Path: %s\n", retval);
4974df55fdeSJanie Lu 				xmlFree(temp);
4984df55fdeSJanie Lu 				xmlXPathFreeObject(xpathObj);
4994df55fdeSJanie Lu 			}
5004df55fdeSJanie Lu 			FREE_PROP(tprop);
5014df55fdeSJanie Lu 
5024df55fdeSJanie Lu 			return (retval);
5034df55fdeSJanie Lu 		}
5044df55fdeSJanie Lu 	}
5054df55fdeSJanie Lu fail:
5064df55fdeSJanie Lu 	if (xpathObj != NULL)
5074df55fdeSJanie Lu 		xmlXPathFreeObject(xpathObj);
5084df55fdeSJanie Lu 	return (NULL);
5094df55fdeSJanie Lu }
5104df55fdeSJanie Lu 
5114f764f91SCheng Sean Ye char *
fab_find_rppath_by_devpath(fmd_hdl_t * hdl,const char * devpath)5124f764f91SCheng Sean Ye fab_find_rppath_by_devpath(fmd_hdl_t *hdl, const char *devpath)
5134f764f91SCheng Sean Ye {
5144f764f91SCheng Sean Ye 	char	query[500];
5154f764f91SCheng Sean Ye 
5164f764f91SCheng Sean Ye 	/*
5174f764f91SCheng Sean Ye 	 * Explanation of the XSL XPATH Query
5184f764f91SCheng Sean Ye 	 * Line 1: Look at all nodes with the node name "propval"
5194f764f91SCheng Sean Ye 	 * Line 2: See if the node is pciexrc
5204f764f91SCheng Sean Ye 	 * Line 3: Go up to the io pgroup
5214f764f91SCheng Sean Ye 	 * Line 4: See if the "dev" prop is parent of devpath
5224f764f91SCheng Sean Ye 	 * Line 5: Get the 'dev' prop
5234f764f91SCheng Sean Ye 	 */
5244f764f91SCheng Sean Ye 	(void) snprintf(query, sizeof (query), "//propval"
5254f764f91SCheng Sean Ye 	    "[@name='extended-capabilities' and @value='%s']"
5264f764f91SCheng Sean Ye 	    "/parent::*/parent::*/propgroup[@name='io']"
5274f764f91SCheng Sean Ye 	    "/propval[@name='dev' and starts-with('%s', concat(@value, '/'))]"
5284f764f91SCheng Sean Ye 	    "/@value", PCIEX_ROOT, devpath);
5294f764f91SCheng Sean Ye 
5304f764f91SCheng Sean Ye 	return (fab_xpath_query(hdl, query));
5314f764f91SCheng Sean Ye }
5324f764f91SCheng Sean Ye 
5334df55fdeSJanie Lu /* ARGSUSED */
5344df55fdeSJanie Lu boolean_t
fab_get_rcpath(fmd_hdl_t * hdl,nvlist_t * nvl,char * rcpath)5354df55fdeSJanie Lu fab_get_rcpath(fmd_hdl_t *hdl, nvlist_t *nvl, char *rcpath)
5364df55fdeSJanie Lu {
5374df55fdeSJanie Lu 	nvlist_t	*detector;
5384df55fdeSJanie Lu 	char		*path, *scheme;
5394df55fdeSJanie Lu 
5404df55fdeSJanie Lu 	if (nvlist_lookup_nvlist(nvl, FM_EREPORT_DETECTOR, &detector) != 0)
5414df55fdeSJanie Lu 		goto fail;
5424df55fdeSJanie Lu 	if (nvlist_lookup_string(detector, FM_FMRI_SCHEME, &scheme) != 0)
5434df55fdeSJanie Lu 		goto fail;
5444df55fdeSJanie Lu 
5454df55fdeSJanie Lu 	if (STRCMP(scheme, FM_FMRI_SCHEME_DEV)) {
5464df55fdeSJanie Lu 		if (nvlist_lookup_string(detector, FM_FMRI_DEV_PATH,
5474df55fdeSJanie Lu 		    &path) != 0)
5484df55fdeSJanie Lu 			goto fail;
5494df55fdeSJanie Lu 		(void) strncpy(rcpath, path, FM_MAX_CLASS);
5504df55fdeSJanie Lu 	} else if (STRCMP(scheme, FM_FMRI_SCHEME_HC)) {
5514df55fdeSJanie Lu 		/*
5524df55fdeSJanie Lu 		 * This should only occur for ereports that come from the RC
5534df55fdeSJanie Lu 		 * itself.  In this case convert HC scheme to dev path.
5544df55fdeSJanie Lu 		 */
5554df55fdeSJanie Lu 		if (fab_hc2dev_nvl(hdl, detector, &path)) {
5564df55fdeSJanie Lu 			(void) strncpy(rcpath, path, FM_MAX_CLASS);
5574df55fdeSJanie Lu 			fmd_hdl_strfree(hdl, path);
5584df55fdeSJanie Lu 		} else {
5594df55fdeSJanie Lu 			goto fail;
5604df55fdeSJanie Lu 		}
5614df55fdeSJanie Lu 	} else {
5624df55fdeSJanie Lu 		return (B_FALSE);
5634df55fdeSJanie Lu 	}
5644df55fdeSJanie Lu 
5654df55fdeSJanie Lu 	/*
5664df55fdeSJanie Lu 	 * Extract the RC path by taking the first device in the dev path
5674df55fdeSJanie Lu 	 *
5684df55fdeSJanie Lu 	 * /pci@0,0/pci8086,3605@2/pci8086,3500@0/pci8086,3514@1/pci8086,105e@0
5694df55fdeSJanie Lu 	 * - to -
5704df55fdeSJanie Lu 	 * /pci@0,0
5714df55fdeSJanie Lu 	 */
5724df55fdeSJanie Lu 	path = strchr(rcpath + 1, '/');
5734df55fdeSJanie Lu 	if (path)
5744df55fdeSJanie Lu 		path[0] = '\0';
5754df55fdeSJanie Lu 
5764df55fdeSJanie Lu 	return (B_TRUE);
5774df55fdeSJanie Lu fail:
5784df55fdeSJanie Lu 	return (B_FALSE);
5794df55fdeSJanie Lu }
5804df55fdeSJanie Lu 
5814df55fdeSJanie Lu char *
fab_find_bdf(fmd_hdl_t * hdl,nvlist_t * nvl,pcie_req_id_t bdf)5824df55fdeSJanie Lu fab_find_bdf(fmd_hdl_t *hdl, nvlist_t *nvl, pcie_req_id_t bdf)
5834df55fdeSJanie Lu {
584*ffb64830SJordan Paige Hendricks 	char	*retval;
5854df55fdeSJanie Lu 	char	query[500];
5864df55fdeSJanie Lu 	int	bus, dev, fn;
5874df55fdeSJanie Lu 	char	rcpath[255];
5884df55fdeSJanie Lu 
5894df55fdeSJanie Lu 	if (bdf != (uint16_t)-1) {
5904df55fdeSJanie Lu 		bus = (bdf & PCIE_REQ_ID_BUS_MASK) >> PCIE_REQ_ID_BUS_SHIFT;
5914df55fdeSJanie Lu 		dev = (bdf & PCIE_REQ_ID_DEV_MASK) >> PCIE_REQ_ID_DEV_SHIFT;
5924df55fdeSJanie Lu 		fn = (bdf & PCIE_REQ_ID_FUNC_MASK) >> PCIE_REQ_ID_FUNC_SHIFT;
5934df55fdeSJanie Lu 	}
5944df55fdeSJanie Lu 
5954df55fdeSJanie Lu 	if (!fab_get_rcpath(hdl, nvl, rcpath))
5964df55fdeSJanie Lu 		goto fail;
5974df55fdeSJanie Lu 
5984df55fdeSJanie Lu 	/*
5994df55fdeSJanie Lu 	 * Explanation of the XSL XPATH Query
6004df55fdeSJanie Lu 	 * Line 1: Look at all nodes with the node name "propval"
6014df55fdeSJanie Lu 	 * Line 2-3: See if the "value" of the node ends with correct PCIEx BDF
6024df55fdeSJanie Lu 	 * Line 4-5: See if the "value" of the node ends with correct PCI BDF
6034df55fdeSJanie Lu 	 * Line 6: Go up one level to the parent of the current node
6044df55fdeSJanie Lu 	 * Line 7: See if child node contains "ASRU" with the same PCIe Root
6054df55fdeSJanie Lu 	 * Line 8: Traverse up the parent and the other siblings and look for
6064df55fdeSJanie Lu 	 *	   the io "propgroup" and get the value of the dev "propval"
6074df55fdeSJanie Lu 	 */
6084df55fdeSJanie Lu 	(void) snprintf(query, sizeof (query), "//propval["
6094df55fdeSJanie Lu 	    "contains(substring(@value, string-length(@value) - 34), "
6104df55fdeSJanie Lu 	    "'pciexbus=%d/pciexdev=%d/pciexfn=%d') or "
6114df55fdeSJanie Lu 	    "contains(substring(@value, string-length(@value) - 28), "
6124df55fdeSJanie Lu 	    "'pcibus=%d/pcidev=%d/pcifn=%d')"
6134df55fdeSJanie Lu 	    "]/parent::"
6144df55fdeSJanie Lu 	    "*/propval[@name='ASRU' and contains(@value, '%s')]"
6154df55fdeSJanie Lu 	    "/parent::*/following-sibling::*[@name='io']/propval[@name='dev']/"
6164df55fdeSJanie Lu 	    "@value", bus, dev, fn, bus, dev, fn, rcpath);
6174df55fdeSJanie Lu 
6184df55fdeSJanie Lu 	retval = fab_xpath_query(hdl, query);
6194df55fdeSJanie Lu 	if (retval) {
6204df55fdeSJanie Lu 		fmd_hdl_debug(hdl, "BDF Dev Path: %s\n", retval);
6214df55fdeSJanie Lu 		return (retval);
6224df55fdeSJanie Lu 	}
6234df55fdeSJanie Lu fail:
6244df55fdeSJanie Lu 	return (NULL);
6254df55fdeSJanie Lu }
6264df55fdeSJanie Lu 
6274df55fdeSJanie Lu char *
fab_find_addr(fmd_hdl_t * hdl,nvlist_t * nvl,uint64_t addr)6284df55fdeSJanie Lu fab_find_addr(fmd_hdl_t *hdl, nvlist_t *nvl, uint64_t addr)
6294df55fdeSJanie Lu {
6304df55fdeSJanie Lu 	xmlXPathObjectPtr xpathObj;
6314df55fdeSJanie Lu 	xmlNodeSetPtr nodes;
6324df55fdeSJanie Lu 	xmlNodePtr devNode;
6334df55fdeSJanie Lu 	char *retval, *temp;
6344df55fdeSJanie Lu 	char query[500];
6354df55fdeSJanie Lu 	int size, i, j;
6364df55fdeSJanie Lu 	uint32_t prop[50];
6374df55fdeSJanie Lu 	char *token;
6384df55fdeSJanie Lu 	pci_regspec_t *assign_p;
6394df55fdeSJanie Lu 	uint64_t low, hi;
6404df55fdeSJanie Lu 	char rcpath[255];
6414df55fdeSJanie Lu 
6424df55fdeSJanie Lu 	if (!fab_get_rcpath(hdl, nvl, rcpath))
6434df55fdeSJanie Lu 		goto fail;
6444df55fdeSJanie Lu 
6454df55fdeSJanie Lu 	(void) snprintf(query, sizeof (query), "//propval["
6464df55fdeSJanie Lu 	    "@name='ASRU' and contains(@value, '%s')]/"
6474df55fdeSJanie Lu 	    "parent::*/following-sibling::*[@name='pci']/"
6484df55fdeSJanie Lu 	    "propval[@name='assigned-addresses']", rcpath);
6494df55fdeSJanie Lu 
6504df55fdeSJanie Lu 	fmd_hdl_debug(hdl, "xpathObj query %s\n", query);
6514df55fdeSJanie Lu 
6524df55fdeSJanie Lu 	xpathObj = xmlXPathEvalExpression((const xmlChar *)query, fab_xpathCtx);
6534df55fdeSJanie Lu 
6544df55fdeSJanie Lu 	if (xpathObj == NULL)
6554df55fdeSJanie Lu 		goto fail;
6564df55fdeSJanie Lu 
6574df55fdeSJanie Lu 	fmd_hdl_debug(hdl, "xpathObj 0x%p type %d\n", xpathObj, xpathObj->type);
6584df55fdeSJanie Lu 
6594df55fdeSJanie Lu 	nodes = xpathObj->nodesetval;
6604df55fdeSJanie Lu 	size = (nodes) ? nodes->nodeNr : 0;
6614df55fdeSJanie Lu 
6624df55fdeSJanie Lu 	/* Decode the list of assigned addresses xml nodes for each device */
6634df55fdeSJanie Lu 	for (i = 0; i < size; i++) {
6644df55fdeSJanie Lu 		char *tprop;
6654df55fdeSJanie Lu 
6664df55fdeSJanie Lu 		devNode = nodes->nodeTab[i];
6674df55fdeSJanie Lu 		if (!HAS_PROP(devNode, "value"))
6684df55fdeSJanie Lu 			continue;
6694df55fdeSJanie Lu 
6704df55fdeSJanie Lu 		/* Convert "string" assigned-addresses to pci_regspec_t */
6714df55fdeSJanie Lu 		j = 0;
6724df55fdeSJanie Lu 		tprop = GET_PROP(devNode, "value");
6734df55fdeSJanie Lu 		for (token = strtok(tprop, " "); token;
6744df55fdeSJanie Lu 		    token = strtok(NULL, " ")) {
6754df55fdeSJanie Lu 			prop[j++] = strtoul(token, (char **)NULL, 16);
6764df55fdeSJanie Lu 		}
6774df55fdeSJanie Lu 		prop[j] = (uint32_t)-1;
6784df55fdeSJanie Lu 		FREE_PROP(tprop);
6794df55fdeSJanie Lu 
6804df55fdeSJanie Lu 		/* Check if address belongs to this device */
6814df55fdeSJanie Lu 		for (assign_p = (pci_regspec_t *)prop;
6824df55fdeSJanie Lu 		    assign_p->pci_phys_hi != (uint_t)-1; assign_p++) {
6834df55fdeSJanie Lu 			low = assign_p->pci_phys_low;
6844df55fdeSJanie Lu 			hi = low + assign_p->pci_size_low;
6854df55fdeSJanie Lu 			if ((addr < hi) && (addr >= low)) {
6864df55fdeSJanie Lu 				fmd_hdl_debug(hdl, "Found Address\n");
6874df55fdeSJanie Lu 				goto found;
6884df55fdeSJanie Lu 			}
6894df55fdeSJanie Lu 		}
6904df55fdeSJanie Lu 	}
6914df55fdeSJanie Lu 	goto fail;
6924df55fdeSJanie Lu 
6934df55fdeSJanie Lu found:
6944df55fdeSJanie Lu 	/* Traverse up the xml tree and back down to find the right propgroup */
6954df55fdeSJanie Lu 	for (devNode = devNode->parent->parent->children;
6964df55fdeSJanie Lu 	    devNode; devNode = devNode->next) {
6974df55fdeSJanie Lu 		char	*tprop;
6984df55fdeSJanie Lu 
6994df55fdeSJanie Lu 		tprop = GET_PROP(devNode, "name");
7004df55fdeSJanie Lu 		if (STRCMP(devNode->name, "propgroup") &&
7014df55fdeSJanie Lu 		    STRCMP(tprop, "io")) {
7024df55fdeSJanie Lu 			FREE_PROP(tprop);
7034df55fdeSJanie Lu 			goto propgroup;
7044df55fdeSJanie Lu 		}
7054df55fdeSJanie Lu 		FREE_PROP(tprop);
7064df55fdeSJanie Lu 	}
7074df55fdeSJanie Lu 	goto fail;
7084df55fdeSJanie Lu 
7094df55fdeSJanie Lu propgroup:
7104df55fdeSJanie Lu 	/* Retrive the "dev" propval and return */
7114df55fdeSJanie Lu 	for (devNode = devNode->children; devNode; devNode = devNode->next) {
712*ffb64830SJordan Paige Hendricks 		char	*tprop;
7134df55fdeSJanie Lu 
7144df55fdeSJanie Lu 		tprop = GET_PROP(devNode, "name");
7154df55fdeSJanie Lu 		if (STRCMP(devNode->name, "propval") &&
7164df55fdeSJanie Lu 		    STRCMP(tprop, "dev")) {
7174df55fdeSJanie Lu 			FREE_PROP(tprop);
7184df55fdeSJanie Lu 			temp = GET_PROP(devNode, "value");
7194df55fdeSJanie Lu 			retval = fmd_hdl_strdup(hdl, temp, FMD_SLEEP);
7204df55fdeSJanie Lu 			fmd_hdl_debug(hdl, "Addr Dev Path: %s\n", retval);
7214df55fdeSJanie Lu 			xmlFree(temp);
7224df55fdeSJanie Lu 			xmlXPathFreeObject(xpathObj);
7234df55fdeSJanie Lu 			return (retval);
7244df55fdeSJanie Lu 		}
7254df55fdeSJanie Lu 		FREE_PROP(tprop);
7264df55fdeSJanie Lu 	}
7274df55fdeSJanie Lu fail:
7284df55fdeSJanie Lu 	if (xpathObj != NULL)
7294df55fdeSJanie Lu 		xmlXPathFreeObject(xpathObj);
7304df55fdeSJanie Lu 	return (NULL);
7314df55fdeSJanie Lu }
7324df55fdeSJanie Lu 
7334df55fdeSJanie Lu void
fab_pr(fmd_hdl_t * hdl,fmd_event_t * ep,nvlist_t * nvl)7344df55fdeSJanie Lu fab_pr(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl)
7354df55fdeSJanie Lu {
7364df55fdeSJanie Lu 	nvpair_t *nvp;
7374df55fdeSJanie Lu 
7384df55fdeSJanie Lu 	for (nvp = nvlist_next_nvpair(nvl, NULL);
7394df55fdeSJanie Lu 	    nvp != NULL;
7404df55fdeSJanie Lu 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
7414df55fdeSJanie Lu 
7424df55fdeSJanie Lu 		data_type_t type = nvpair_type(nvp);
7434df55fdeSJanie Lu 		const char *name = nvpair_name(nvp);
7444df55fdeSJanie Lu 
7454df55fdeSJanie Lu 		boolean_t b;
7464df55fdeSJanie Lu 		uint8_t i8;
7474df55fdeSJanie Lu 		uint16_t i16;
7484df55fdeSJanie Lu 		uint32_t i32;
7494df55fdeSJanie Lu 		uint64_t i64;
7504df55fdeSJanie Lu 		char *str;
7514df55fdeSJanie Lu 		nvlist_t *cnv;
7524df55fdeSJanie Lu 
7534df55fdeSJanie Lu 		nvlist_t **nvlarr;
7544df55fdeSJanie Lu 		uint_t arrsize;
7554df55fdeSJanie Lu 		int arri;
7564df55fdeSJanie Lu 
7574df55fdeSJanie Lu 
7584df55fdeSJanie Lu 		if (STRCMP(name, FM_CLASS))
7594df55fdeSJanie Lu 			continue; /* already printed by caller */
7604df55fdeSJanie Lu 
7614df55fdeSJanie Lu 		fmd_hdl_debug(hdl, " %s=", name);
7624df55fdeSJanie Lu 
7634df55fdeSJanie Lu 		switch (type) {
7644df55fdeSJanie Lu 		case DATA_TYPE_BOOLEAN:
7654df55fdeSJanie Lu 			fmd_hdl_debug(hdl, "DATA_TYPE_BOOLEAN 1");
7664df55fdeSJanie Lu 			break;
7674df55fdeSJanie Lu 
7684df55fdeSJanie Lu 		case DATA_TYPE_BOOLEAN_VALUE:
7694df55fdeSJanie Lu 			(void) nvpair_value_boolean_value(nvp, &b);
7704df55fdeSJanie Lu 			fmd_hdl_debug(hdl, "DATA_TYPE_BOOLEAN_VALUE %d",
7714df55fdeSJanie Lu 			    b ? "1" : "0");
7724df55fdeSJanie Lu 			break;
7734df55fdeSJanie Lu 
7744df55fdeSJanie Lu 		case DATA_TYPE_BYTE:
7754df55fdeSJanie Lu 			(void) nvpair_value_byte(nvp, &i8);
7764df55fdeSJanie Lu 			fmd_hdl_debug(hdl, "DATA_TYPE_BYTE 0x%x", i8);
7774df55fdeSJanie Lu 			break;
7784df55fdeSJanie Lu 
7794df55fdeSJanie Lu 		case DATA_TYPE_INT8:
7804df55fdeSJanie Lu 			(void) nvpair_value_int8(nvp, (void *)&i8);
7814df55fdeSJanie Lu 			fmd_hdl_debug(hdl, "DATA_TYPE_INT8 0x%x", i8);
7824df55fdeSJanie Lu 			break;
7834df55fdeSJanie Lu 
7844df55fdeSJanie Lu 		case DATA_TYPE_UINT8:
7854df55fdeSJanie Lu 			(void) nvpair_value_uint8(nvp, &i8);
7864df55fdeSJanie Lu 			fmd_hdl_debug(hdl, "DATA_TYPE_UINT8 0x%x", i8);
7874df55fdeSJanie Lu 			break;
7884df55fdeSJanie Lu 
7894df55fdeSJanie Lu 		case DATA_TYPE_INT16:
7904df55fdeSJanie Lu 			(void) nvpair_value_int16(nvp, (void *)&i16);
7914df55fdeSJanie Lu 			fmd_hdl_debug(hdl, "DATA_TYPE_INT16 0x%x", i16);
7924df55fdeSJanie Lu 			break;
7934df55fdeSJanie Lu 
7944df55fdeSJanie Lu 		case DATA_TYPE_UINT16:
7954df55fdeSJanie Lu 			(void) nvpair_value_uint16(nvp, &i16);
7964df55fdeSJanie Lu 			fmd_hdl_debug(hdl, "DATA_TYPE_UINT16 0x%x", i16);
7974df55fdeSJanie Lu 			break;
7984df55fdeSJanie Lu 
7994df55fdeSJanie Lu 		case DATA_TYPE_INT32:
8004df55fdeSJanie Lu 			(void) nvpair_value_int32(nvp, (void *)&i32);
8014df55fdeSJanie Lu 			fmd_hdl_debug(hdl, "DATA_TYPE_INT32 0x%x", i32);
8024df55fdeSJanie Lu 			break;
8034df55fdeSJanie Lu 
8044df55fdeSJanie Lu 		case DATA_TYPE_UINT32:
8054df55fdeSJanie Lu 			(void) nvpair_value_uint32(nvp, &i32);
8064df55fdeSJanie Lu 			fmd_hdl_debug(hdl, "DATA_TYPE_UINT32 0x%x", i32);
8074df55fdeSJanie Lu 			break;
8084df55fdeSJanie Lu 
8094df55fdeSJanie Lu 		case DATA_TYPE_INT64:
8104df55fdeSJanie Lu 			(void) nvpair_value_int64(nvp, (void *)&i64);
8114df55fdeSJanie Lu 			fmd_hdl_debug(hdl, "DATA_TYPE_INT64 0x%llx",
8124df55fdeSJanie Lu 			    (u_longlong_t)i64);
8134df55fdeSJanie Lu 			break;
8144df55fdeSJanie Lu 
8154df55fdeSJanie Lu 		case DATA_TYPE_UINT64:
8164df55fdeSJanie Lu 			(void) nvpair_value_uint64(nvp, &i64);
8174df55fdeSJanie Lu 			fmd_hdl_debug(hdl, "DATA_TYPE_UINT64 0x%llx",
8184df55fdeSJanie Lu 			    (u_longlong_t)i64);
8194df55fdeSJanie Lu 			break;
8204df55fdeSJanie Lu 
8214df55fdeSJanie Lu 		case DATA_TYPE_HRTIME:
8224df55fdeSJanie Lu 			(void) nvpair_value_hrtime(nvp, (void *)&i64);
8234df55fdeSJanie Lu 			fmd_hdl_debug(hdl, "DATA_TYPE_HRTIME 0x%llx",
8244df55fdeSJanie Lu 			    (u_longlong_t)i64);
8254df55fdeSJanie Lu 			break;
8264df55fdeSJanie Lu 
8274df55fdeSJanie Lu 		case DATA_TYPE_STRING:
8284df55fdeSJanie Lu 			(void) nvpair_value_string(nvp, &str);
8294df55fdeSJanie Lu 			fmd_hdl_debug(hdl, "DATA_TYPE_STRING \"%s\"",
8304df55fdeSJanie Lu 			    str ? str : "<NULL>");
8314df55fdeSJanie Lu 			break;
8324df55fdeSJanie Lu 
8334df55fdeSJanie Lu 		case DATA_TYPE_NVLIST:
8344df55fdeSJanie Lu 			fmd_hdl_debug(hdl, "[");
8354df55fdeSJanie Lu 			(void) nvpair_value_nvlist(nvp, &cnv);
8364df55fdeSJanie Lu 			fab_pr(hdl, NULL, cnv);
8374df55fdeSJanie Lu 			fmd_hdl_debug(hdl, " ]");
8384df55fdeSJanie Lu 			break;
8394df55fdeSJanie Lu 
8404df55fdeSJanie Lu 		case DATA_TYPE_BOOLEAN_ARRAY:
8414df55fdeSJanie Lu 		case DATA_TYPE_BYTE_ARRAY:
8424df55fdeSJanie Lu 		case DATA_TYPE_INT8_ARRAY:
8434df55fdeSJanie Lu 		case DATA_TYPE_UINT8_ARRAY:
8444df55fdeSJanie Lu 		case DATA_TYPE_INT16_ARRAY:
8454df55fdeSJanie Lu 		case DATA_TYPE_UINT16_ARRAY:
8464df55fdeSJanie Lu 		case DATA_TYPE_INT32_ARRAY:
8474df55fdeSJanie Lu 		case DATA_TYPE_UINT32_ARRAY:
8484df55fdeSJanie Lu 		case DATA_TYPE_INT64_ARRAY:
8494df55fdeSJanie Lu 		case DATA_TYPE_UINT64_ARRAY:
8504df55fdeSJanie Lu 		case DATA_TYPE_STRING_ARRAY:
8514df55fdeSJanie Lu 			fmd_hdl_debug(hdl, "[...]");
8524df55fdeSJanie Lu 			break;
8534df55fdeSJanie Lu 		case DATA_TYPE_NVLIST_ARRAY:
8544df55fdeSJanie Lu 			arrsize = 0;
8554df55fdeSJanie Lu 			(void) nvpair_value_nvlist_array(nvp, &nvlarr,
8564df55fdeSJanie Lu 			    &arrsize);
8574df55fdeSJanie Lu 
8584df55fdeSJanie Lu 			for (arri = 0; arri < arrsize; arri++) {
8594df55fdeSJanie Lu 				fab_pr(hdl, ep, nvlarr[arri]);
8604df55fdeSJanie Lu 			}
8614df55fdeSJanie Lu 
8624df55fdeSJanie Lu 			break;
8634df55fdeSJanie Lu 		case DATA_TYPE_UNKNOWN:
8644df55fdeSJanie Lu 			fmd_hdl_debug(hdl, "<unknown>");
8654df55fdeSJanie Lu 			break;
8664df55fdeSJanie Lu 		}
8674df55fdeSJanie Lu 	}
8684df55fdeSJanie Lu }
869b344f6b3Sgongtian zhao - Sun Microsystems - Beijing China 
870b344f6b3Sgongtian zhao - Sun Microsystems - Beijing China char *
fab_get_rpdev(fmd_hdl_t * hdl)871b344f6b3Sgongtian zhao - Sun Microsystems - Beijing China fab_get_rpdev(fmd_hdl_t *hdl)
872b344f6b3Sgongtian zhao - Sun Microsystems - Beijing China {
873*ffb64830SJordan Paige Hendricks 	char	*retval;
874*ffb64830SJordan Paige Hendricks 	char	query[500];
875b344f6b3Sgongtian zhao - Sun Microsystems - Beijing China 
876b344f6b3Sgongtian zhao - Sun Microsystems - Beijing China 	(void) snprintf(query, sizeof (query), "//propval["
877b344f6b3Sgongtian zhao - Sun Microsystems - Beijing China 	    "@name='extended-capabilities' and contains(@value, '%s')]"
878b344f6b3Sgongtian zhao - Sun Microsystems - Beijing China 	    "/parent::*/parent::*/propgroup[@name='io']"
879b344f6b3Sgongtian zhao - Sun Microsystems - Beijing China 	    "/propval[@name='dev']/@value", PCIEX_ROOT);
880b344f6b3Sgongtian zhao - Sun Microsystems - Beijing China 
881b344f6b3Sgongtian zhao - Sun Microsystems - Beijing China 	retval = fab_xpath_query(hdl, query);
882b344f6b3Sgongtian zhao - Sun Microsystems - Beijing China 	if (retval) {
883b344f6b3Sgongtian zhao - Sun Microsystems - Beijing China 		fmd_hdl_debug(hdl, "Root port path is %s\n", retval);
884b344f6b3Sgongtian zhao - Sun Microsystems - Beijing China 		return (retval);
885b344f6b3Sgongtian zhao - Sun Microsystems - Beijing China 	}
886b344f6b3Sgongtian zhao - Sun Microsystems - Beijing China 
887b344f6b3Sgongtian zhao - Sun Microsystems - Beijing China 	return (NULL);
888b344f6b3Sgongtian zhao - Sun Microsystems - Beijing China }
889036ec191SCheng Sean Ye 
890036ec191SCheng Sean Ye void
fab_send_erpt_all_rps(fmd_hdl_t * hdl,nvlist_t * erpt)891036ec191SCheng Sean Ye fab_send_erpt_all_rps(fmd_hdl_t *hdl, nvlist_t *erpt)
892036ec191SCheng Sean Ye {
893036ec191SCheng Sean Ye 	xmlXPathObjectPtr xpathObj;
894036ec191SCheng Sean Ye 	xmlNodeSetPtr nodes;
895*ffb64830SJordan Paige Hendricks 	char	*rppath, *hbpath;
896*ffb64830SJordan Paige Hendricks 	char	query[600];
897036ec191SCheng Sean Ye 	nvlist_t *detector, *nvl;
898036ec191SCheng Sean Ye 	uint_t	i, size;
899036ec191SCheng Sean Ye 	size_t len;
900036ec191SCheng Sean Ye 
901036ec191SCheng Sean Ye 	/* get hostbridge's path */
902036ec191SCheng Sean Ye 	if (!fab_get_hcpath(hdl, erpt, &hbpath, &len)) {
903036ec191SCheng Sean Ye 		fmd_hdl_debug(hdl,
904036ec191SCheng Sean Ye 		    "fab_send_erpt_on_all_rps: fab_get_hcpath() failed.\n");
905036ec191SCheng Sean Ye 		return;
906036ec191SCheng Sean Ye 	}
907036ec191SCheng Sean Ye 
908036ec191SCheng Sean Ye 	(void) snprintf(query, sizeof (query), "//propval["
909036ec191SCheng Sean Ye 	    "@name='extended-capabilities' and contains(@value, '%s')]"
910036ec191SCheng Sean Ye 	    "/parent::*/parent::*/propgroup[@name='protocol']"
911036ec191SCheng Sean Ye 	    "/propval[@name='resource' and contains(@value, '%s/')"
912036ec191SCheng Sean Ye 	    "]/parent::*/parent::*/propgroup[@name='io']"
913036ec191SCheng Sean Ye 	    "/propval[@name='dev']/@value", PCIEX_ROOT, hbpath);
914036ec191SCheng Sean Ye 
915036ec191SCheng Sean Ye 	fmd_hdl_free(hdl, hbpath, len);
916036ec191SCheng Sean Ye 
917036ec191SCheng Sean Ye 	fmd_hdl_debug(hdl, "xpathObj query %s\n", query);
918036ec191SCheng Sean Ye 
919036ec191SCheng Sean Ye 	xpathObj = xmlXPathEvalExpression((const xmlChar *)query, fab_xpathCtx);
920036ec191SCheng Sean Ye 
921036ec191SCheng Sean Ye 	if (xpathObj == NULL)
922036ec191SCheng Sean Ye 		return;
923036ec191SCheng Sean Ye 
924036ec191SCheng Sean Ye 	nodes = xpathObj->nodesetval;
925036ec191SCheng Sean Ye 	size = (nodes) ? nodes->nodeNr : 0;
926036ec191SCheng Sean Ye 
927036ec191SCheng Sean Ye 	fmd_hdl_debug(hdl, "xpathObj 0x%p type %d size %d\n",
928036ec191SCheng Sean Ye 	    xpathObj, xpathObj->type, size);
929036ec191SCheng Sean Ye 
930036ec191SCheng Sean Ye 	for (i = 0; i < size; i++) {
931036ec191SCheng Sean Ye 		rppath = (char *)xmlNodeGetContent(nodes->nodeTab[i]);
932036ec191SCheng Sean Ye 		fmd_hdl_debug(hdl, "query result: %s\n", rppath);
933036ec191SCheng Sean Ye 
934036ec191SCheng Sean Ye 		nvl = detector = NULL;
935036ec191SCheng Sean Ye 		if (nvlist_dup(erpt, &nvl, NV_UNIQUE_NAME) != 0 ||
936036ec191SCheng Sean Ye 		    nvlist_alloc(&detector, NV_UNIQUE_NAME, 0) != 0) {
937036ec191SCheng Sean Ye 			xmlFree(rppath);
938036ec191SCheng Sean Ye 			nvlist_free(nvl);
939036ec191SCheng Sean Ye 			continue;
940036ec191SCheng Sean Ye 		}
941036ec191SCheng Sean Ye 
942036ec191SCheng Sean Ye 		/*
943036ec191SCheng Sean Ye 		 * set the detector in the original ereport to the root port
944036ec191SCheng Sean Ye 		 */
945036ec191SCheng Sean Ye 		(void) nvlist_add_string(detector, FM_VERSION,
946036ec191SCheng Sean Ye 		    FM_DEV_SCHEME_VERSION);
947036ec191SCheng Sean Ye 		(void) nvlist_add_string(detector, FM_FMRI_SCHEME,
948036ec191SCheng Sean Ye 		    FM_FMRI_SCHEME_DEV);
949036ec191SCheng Sean Ye 		(void) nvlist_add_string(detector, FM_FMRI_DEV_PATH,
950036ec191SCheng Sean Ye 		    rppath);
951036ec191SCheng Sean Ye 		(void) nvlist_remove_all(nvl, FM_EREPORT_DETECTOR);
952036ec191SCheng Sean Ye 		(void) nvlist_add_nvlist(nvl, FM_EREPORT_DETECTOR,
953036ec191SCheng Sean Ye 		    detector);
954036ec191SCheng Sean Ye 		nvlist_free(detector);
955036ec191SCheng Sean Ye 		xmlFree(rppath);
956036ec191SCheng Sean Ye 
957036ec191SCheng Sean Ye 		fmd_hdl_debug(hdl, "Sending ereport: %s\n", fab_buf);
958036ec191SCheng Sean Ye 		fmd_xprt_post(hdl, fab_fmd_xprt, nvl, 0);
959036ec191SCheng Sean Ye 		if (fmd_xprt_error(hdl, fab_fmd_xprt))
960036ec191SCheng Sean Ye 			fmd_hdl_debug(hdl,
961036ec191SCheng Sean Ye 			    "Failed to send PCI ereport\n");
962036ec191SCheng Sean Ye 	}
963036ec191SCheng Sean Ye 
964036ec191SCheng Sean Ye 	xmlXPathFreeObject(xpathObj);
965036ec191SCheng Sean Ye }
966