xref: /onnv-gate/usr/src/cmd/fm/modules/common/fabric-xlate/fx_subr.c (revision 12132:11fecf096087)
111304SJanie.Lu@Sun.COM /*
211304SJanie.Lu@Sun.COM  * CDDL HEADER START
311304SJanie.Lu@Sun.COM  *
411304SJanie.Lu@Sun.COM  * The contents of this file are subject to the terms of the
511304SJanie.Lu@Sun.COM  * Common Development and Distribution License (the "License").
611304SJanie.Lu@Sun.COM  * You may not use this file except in compliance with the License.
711304SJanie.Lu@Sun.COM  *
811304SJanie.Lu@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911304SJanie.Lu@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1011304SJanie.Lu@Sun.COM  * See the License for the specific language governing permissions
1111304SJanie.Lu@Sun.COM  * and limitations under the License.
1211304SJanie.Lu@Sun.COM  *
1311304SJanie.Lu@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1411304SJanie.Lu@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511304SJanie.Lu@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1611304SJanie.Lu@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1711304SJanie.Lu@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1811304SJanie.Lu@Sun.COM  *
1911304SJanie.Lu@Sun.COM  * CDDL HEADER END
2011304SJanie.Lu@Sun.COM  */
2111304SJanie.Lu@Sun.COM 
2211304SJanie.Lu@Sun.COM /*
23*12132SSean.Ye@Sun.COM  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2411304SJanie.Lu@Sun.COM  */
2511304SJanie.Lu@Sun.COM #include <strings.h>
2611304SJanie.Lu@Sun.COM #include <fm/topo_hc.h>
2711304SJanie.Lu@Sun.COM #include <sys/fm/util.h>
2811304SJanie.Lu@Sun.COM #include <libxml/xpath.h>
2911304SJanie.Lu@Sun.COM #include <libxml/parser.h>
3011304SJanie.Lu@Sun.COM #include <libxml/xpathInternals.h>
3111304SJanie.Lu@Sun.COM #include <libxml/tree.h>
3211304SJanie.Lu@Sun.COM 
3311304SJanie.Lu@Sun.COM #include "fabric-xlate.h"
3411304SJanie.Lu@Sun.COM 
3511304SJanie.Lu@Sun.COM #define	HAS_PROP(node, name) xmlHasProp(node, (const xmlChar *)name)
3611304SJanie.Lu@Sun.COM #define	GET_PROP(node, name) ((char *)xmlGetProp(node, (const xmlChar *)name))
3711304SJanie.Lu@Sun.COM #define	FREE_PROP(prop) xmlFree((xmlChar *)prop)
3811304SJanie.Lu@Sun.COM 
3911304SJanie.Lu@Sun.COM extern xmlXPathContextPtr fab_xpathCtx;
4011304SJanie.Lu@Sun.COM 
4111304SJanie.Lu@Sun.COM /* ARGSUSED */
4211304SJanie.Lu@Sun.COM int
fab_prep_basic_erpt(fmd_hdl_t * hdl,nvlist_t * nvl,nvlist_t * erpt,boolean_t isRC)4311304SJanie.Lu@Sun.COM fab_prep_basic_erpt(fmd_hdl_t *hdl, nvlist_t *nvl, nvlist_t *erpt,
4411304SJanie.Lu@Sun.COM     boolean_t isRC)
4511304SJanie.Lu@Sun.COM {
4611304SJanie.Lu@Sun.COM 	uint64_t	*now;
4711304SJanie.Lu@Sun.COM 	uint64_t	ena;
4811304SJanie.Lu@Sun.COM 	uint_t		nelem;
4911304SJanie.Lu@Sun.COM 	nvlist_t	*detector, *new_detector;
5011304SJanie.Lu@Sun.COM 	char		rcpath[255];
5111304SJanie.Lu@Sun.COM 	int		err = 0;
5211304SJanie.Lu@Sun.COM 
5311304SJanie.Lu@Sun.COM 	/* Grab the tod, ena and detector(FMRI) */
5411304SJanie.Lu@Sun.COM 	err |= nvlist_lookup_uint64_array(nvl, "__tod", &now, &nelem);
5511304SJanie.Lu@Sun.COM 	err |= nvlist_lookup_uint64(nvl, "ena", &ena);
5611304SJanie.Lu@Sun.COM 	err |= nvlist_lookup_nvlist(nvl, FM_EREPORT_DETECTOR, &detector);
5711304SJanie.Lu@Sun.COM 	if (err)
5811304SJanie.Lu@Sun.COM 		return (err);
5911304SJanie.Lu@Sun.COM 
6011304SJanie.Lu@Sun.COM 	/* Make a copy of the detector */
6111304SJanie.Lu@Sun.COM 	err = nvlist_dup(detector, &new_detector, NV_UNIQUE_NAME);
6211304SJanie.Lu@Sun.COM 	if (err)
6311304SJanie.Lu@Sun.COM 		return (err);
6411304SJanie.Lu@Sun.COM 
6511304SJanie.Lu@Sun.COM 	/* Copy the tod and ena to erpt */
6611304SJanie.Lu@Sun.COM 	(void) nvlist_add_uint64(erpt, FM_EREPORT_ENA, ena);
6711304SJanie.Lu@Sun.COM 	(void) nvlist_add_uint64_array(erpt, "__tod", now, nelem);
6811304SJanie.Lu@Sun.COM 
6911304SJanie.Lu@Sun.COM 	/*
7011304SJanie.Lu@Sun.COM 	 * Create the correct ROOT FMRI from PCIe leaf fabric ereports.	 Used
7111304SJanie.Lu@Sun.COM 	 * only by fab_prep_fake_rc_erpt.  See the fab_pciex_fake_rc_erpt_tbl
7211304SJanie.Lu@Sun.COM 	 * comments for more information.
7311304SJanie.Lu@Sun.COM 	 */
7411304SJanie.Lu@Sun.COM 	if (isRC && fab_get_rcpath(hdl, nvl, rcpath)) {
7511304SJanie.Lu@Sun.COM 		/* Create the correct PCIe RC new_detector aka FMRI */
7611304SJanie.Lu@Sun.COM 		(void) nvlist_remove(new_detector, FM_FMRI_DEV_PATH,
7711304SJanie.Lu@Sun.COM 		    DATA_TYPE_STRING);
7811304SJanie.Lu@Sun.COM 		(void) nvlist_add_string(new_detector, FM_FMRI_DEV_PATH,
7911304SJanie.Lu@Sun.COM 		    rcpath);
8011304SJanie.Lu@Sun.COM 	}
8111304SJanie.Lu@Sun.COM 
8211304SJanie.Lu@Sun.COM 	/* Copy the FMRI to erpt */
8311304SJanie.Lu@Sun.COM 	(void) nvlist_add_nvlist(erpt, FM_EREPORT_DETECTOR, new_detector);
8411304SJanie.Lu@Sun.COM 
8511304SJanie.Lu@Sun.COM 	nvlist_free(new_detector);
8611304SJanie.Lu@Sun.COM 	return (err);
8711304SJanie.Lu@Sun.COM }
8811304SJanie.Lu@Sun.COM 
8911304SJanie.Lu@Sun.COM void
fab_send_tgt_erpt(fmd_hdl_t * hdl,fab_data_t * data,const char * class,boolean_t isPrimary)9011304SJanie.Lu@Sun.COM fab_send_tgt_erpt(fmd_hdl_t *hdl, fab_data_t *data, const char *class,
9111304SJanie.Lu@Sun.COM     boolean_t isPrimary)
9211304SJanie.Lu@Sun.COM {
9311304SJanie.Lu@Sun.COM 	nvlist_t	*nvl = data->nvl;
9411304SJanie.Lu@Sun.COM 	nvlist_t	*erpt;
9511304SJanie.Lu@Sun.COM 	char		*fmri = NULL;
9611304SJanie.Lu@Sun.COM 	uint32_t	tgt_trans;
9711304SJanie.Lu@Sun.COM 	uint64_t	tgt_addr;
9811304SJanie.Lu@Sun.COM 	uint16_t	tgt_bdf;
9911304SJanie.Lu@Sun.COM 
10011304SJanie.Lu@Sun.COM 	if (isPrimary) {
10111304SJanie.Lu@Sun.COM 		tgt_trans = data->pcie_ue_tgt_trans;
10211304SJanie.Lu@Sun.COM 		tgt_addr = data->pcie_ue_tgt_addr;
10311304SJanie.Lu@Sun.COM 		tgt_bdf = data->pcie_ue_tgt_bdf;
10411304SJanie.Lu@Sun.COM 	} else {
10511304SJanie.Lu@Sun.COM 		tgt_trans = data->pcie_sue_tgt_trans;
10611304SJanie.Lu@Sun.COM 		tgt_addr = data->pcie_sue_tgt_addr;
10711304SJanie.Lu@Sun.COM 		tgt_bdf = data->pcie_sue_tgt_bdf;
10811304SJanie.Lu@Sun.COM 	}
10911304SJanie.Lu@Sun.COM 
11011304SJanie.Lu@Sun.COM 	fmd_hdl_debug(hdl, "Sending Target Ereport: "
11111304SJanie.Lu@Sun.COM 	    "type 0x%x addr 0x%llx fltbdf 0x%x\n",
11211304SJanie.Lu@Sun.COM 	    tgt_trans, tgt_addr, tgt_bdf);
11311304SJanie.Lu@Sun.COM 
11411304SJanie.Lu@Sun.COM 	if (!tgt_trans)
11511304SJanie.Lu@Sun.COM 		return;
11611304SJanie.Lu@Sun.COM 
11711304SJanie.Lu@Sun.COM 	if ((tgt_trans == PF_ADDR_PIO) && tgt_addr)
11811304SJanie.Lu@Sun.COM 		fmri = fab_find_addr(hdl, nvl, tgt_addr);
11911304SJanie.Lu@Sun.COM 	else if ((tgt_trans == PF_ADDR_CFG || (tgt_trans == PF_ADDR_DMA)) &&
12011304SJanie.Lu@Sun.COM 	    tgt_bdf)
12111304SJanie.Lu@Sun.COM 		fmri = fab_find_bdf(hdl, nvl, tgt_bdf);
12211304SJanie.Lu@Sun.COM 
12311304SJanie.Lu@Sun.COM 	if (fmri) {
12411304SJanie.Lu@Sun.COM 		uint64_t	*now;
12511304SJanie.Lu@Sun.COM 		uint64_t	ena;
12611304SJanie.Lu@Sun.COM 		uint_t		nelem;
12711304SJanie.Lu@Sun.COM 		nvlist_t	*detector;
12811304SJanie.Lu@Sun.COM 		int		err = 0;
12911304SJanie.Lu@Sun.COM 
13011304SJanie.Lu@Sun.COM 		/* Allocate space for new erpt */
13111304SJanie.Lu@Sun.COM 		if (nvlist_alloc(&erpt, NV_UNIQUE_NAME, 0) != 0)
13211304SJanie.Lu@Sun.COM 			goto done;
13311304SJanie.Lu@Sun.COM 
13411304SJanie.Lu@Sun.COM 		/* Generate the target ereport class */
13511304SJanie.Lu@Sun.COM 		(void) snprintf(fab_buf, FM_MAX_CLASS, "ereport.io.%s.%s",
13611304SJanie.Lu@Sun.COM 		    PCI_ERROR_SUBCLASS, class);
13711304SJanie.Lu@Sun.COM 		(void) nvlist_add_string(erpt, FM_CLASS, fab_buf);
13811304SJanie.Lu@Sun.COM 
13911304SJanie.Lu@Sun.COM 		/* Grab the tod, ena and detector(FMRI) */
14011304SJanie.Lu@Sun.COM 		err |= nvlist_lookup_uint64_array(nvl, "__tod", &now, &nelem);
14111304SJanie.Lu@Sun.COM 		err |= nvlist_lookup_uint64(nvl, "ena", &ena);
14211304SJanie.Lu@Sun.COM 
14311304SJanie.Lu@Sun.COM 		/* Copy the tod and ena to erpt */
14411304SJanie.Lu@Sun.COM 		(void) nvlist_add_uint64(erpt, FM_EREPORT_ENA, ena);
14511304SJanie.Lu@Sun.COM 		(void) nvlist_add_uint64_array(erpt, "__tod", now, nelem);
14611304SJanie.Lu@Sun.COM 
14711304SJanie.Lu@Sun.COM 		/* Create the correct FMRI */
14811304SJanie.Lu@Sun.COM 		if (nvlist_alloc(&detector, NV_UNIQUE_NAME, 0) != 0) {
14911304SJanie.Lu@Sun.COM 			nvlist_free(erpt);
15011304SJanie.Lu@Sun.COM 			goto done;
15111304SJanie.Lu@Sun.COM 		}
15211304SJanie.Lu@Sun.COM 		(void) nvlist_add_uint8(detector, FM_VERSION,
15311304SJanie.Lu@Sun.COM 		    FM_DEV_SCHEME_VERSION);
15411304SJanie.Lu@Sun.COM 		(void) nvlist_add_string(detector, FM_FMRI_SCHEME,
15511304SJanie.Lu@Sun.COM 		    FM_FMRI_SCHEME_DEV);
15611304SJanie.Lu@Sun.COM 		(void) nvlist_add_string(detector, FM_FMRI_DEV_PATH, fmri);
15711304SJanie.Lu@Sun.COM 		(void) nvlist_add_nvlist(erpt, FM_EREPORT_DETECTOR, detector);
15811304SJanie.Lu@Sun.COM 		nvlist_free(detector);
15911304SJanie.Lu@Sun.COM 
16011304SJanie.Lu@Sun.COM 		/* Add the address payload */
16111304SJanie.Lu@Sun.COM 		(void) nvlist_add_uint64(erpt, PCI_PA, tgt_addr);
16211304SJanie.Lu@Sun.COM 
16311304SJanie.Lu@Sun.COM 		fmd_hdl_debug(hdl, "Sending target ereport: %s 0x%x\n",
16411304SJanie.Lu@Sun.COM 		    fab_buf, tgt_addr);
16511304SJanie.Lu@Sun.COM 		fmd_xprt_post(hdl, fab_fmd_xprt, erpt, 0);
16611304SJanie.Lu@Sun.COM 		if (fmd_xprt_error(hdl, fab_fmd_xprt))
16711304SJanie.Lu@Sun.COM 			goto done;
16811304SJanie.Lu@Sun.COM 		fmd_hdl_strfree(hdl, fmri);
16911304SJanie.Lu@Sun.COM 	} else {
17011304SJanie.Lu@Sun.COM 		fmd_hdl_debug(hdl,
17111304SJanie.Lu@Sun.COM 		    "Cannot find Target FMRI addr:0x%llx bdf 0x%x\n",
17211304SJanie.Lu@Sun.COM 		    tgt_addr, tgt_bdf);
17311304SJanie.Lu@Sun.COM 	}
17411304SJanie.Lu@Sun.COM 
17511304SJanie.Lu@Sun.COM 	return;
17611304SJanie.Lu@Sun.COM done:
17711304SJanie.Lu@Sun.COM 	if (fmri)
17811304SJanie.Lu@Sun.COM 		xmlFree(fmri);
17911304SJanie.Lu@Sun.COM 	fmd_hdl_debug(hdl, "Failed to send Target PCI ereport\n");
18011304SJanie.Lu@Sun.COM }
18111304SJanie.Lu@Sun.COM 
18211304SJanie.Lu@Sun.COM void
fab_send_erpt(fmd_hdl_t * hdl,fab_data_t * data,fab_err_tbl_t * tbl)18311304SJanie.Lu@Sun.COM fab_send_erpt(fmd_hdl_t *hdl, fab_data_t *data, fab_err_tbl_t *tbl)
18411304SJanie.Lu@Sun.COM {
18511304SJanie.Lu@Sun.COM 	fab_erpt_tbl_t	*erpt_tbl, *entry;
18611304SJanie.Lu@Sun.COM 	nvlist_t	*erpt;
18711304SJanie.Lu@Sun.COM 	uint32_t	reg;
18811304SJanie.Lu@Sun.COM 
18911304SJanie.Lu@Sun.COM 	erpt_tbl = tbl->erpt_tbl;
19011304SJanie.Lu@Sun.COM 	if (tbl->reg_size == 16) {
19111304SJanie.Lu@Sun.COM 		reg = (uint32_t)*((uint16_t *)
19211304SJanie.Lu@Sun.COM 		    ((uint32_t)data + tbl->reg_offset));
19311304SJanie.Lu@Sun.COM 	} else {
19411304SJanie.Lu@Sun.COM 		reg = *((uint32_t *)((uint32_t)data + tbl->reg_offset));
19511304SJanie.Lu@Sun.COM 	}
19611304SJanie.Lu@Sun.COM 
19711304SJanie.Lu@Sun.COM 	for (entry = erpt_tbl; entry->err_class; entry++) {
19811304SJanie.Lu@Sun.COM 		if (!(reg & entry->reg_bit))
19911304SJanie.Lu@Sun.COM 			continue;
20011304SJanie.Lu@Sun.COM 
20111304SJanie.Lu@Sun.COM 		if (nvlist_alloc(&erpt, NV_UNIQUE_NAME, 0) != 0)
20211304SJanie.Lu@Sun.COM 			goto done;
20311304SJanie.Lu@Sun.COM 		if (tbl->fab_prep(hdl, data, erpt, entry) != 0) {
20411304SJanie.Lu@Sun.COM 			fmd_hdl_debug(hdl, "Prepping ereport failed: "
20511304SJanie.Lu@Sun.COM 			    "class = %s\n", entry->err_class);
20611304SJanie.Lu@Sun.COM 			nvlist_free(erpt);
20711304SJanie.Lu@Sun.COM 			continue;
20811304SJanie.Lu@Sun.COM 		}
20911304SJanie.Lu@Sun.COM 
21011862SSean.Ye@Sun.COM 		if (data->pcie_rp_send_all) {
21111862SSean.Ye@Sun.COM 			fab_send_erpt_all_rps(hdl, erpt);
21211862SSean.Ye@Sun.COM 			nvlist_free(erpt);
21311862SSean.Ye@Sun.COM 			return;
21411862SSean.Ye@Sun.COM 		}
21511862SSean.Ye@Sun.COM 
21611304SJanie.Lu@Sun.COM 		fmd_hdl_debug(hdl, "Sending ereport: %s 0x%x\n", fab_buf, reg);
21711304SJanie.Lu@Sun.COM 		fmd_xprt_post(hdl, fab_fmd_xprt, erpt, 0);
21811304SJanie.Lu@Sun.COM 		if (fmd_xprt_error(hdl, fab_fmd_xprt)) {
21911304SJanie.Lu@Sun.COM 			fmd_hdl_debug(hdl, "Failed to send PCI ereport\n");
22011304SJanie.Lu@Sun.COM 			return;
22111304SJanie.Lu@Sun.COM 		}
22211304SJanie.Lu@Sun.COM 	}
22311304SJanie.Lu@Sun.COM 
22411304SJanie.Lu@Sun.COM 	return;
22511304SJanie.Lu@Sun.COM done:
22611304SJanie.Lu@Sun.COM 	fmd_hdl_debug(hdl, "Failed  to send PCI ereport\n");
22711304SJanie.Lu@Sun.COM }
22811304SJanie.Lu@Sun.COM 
22911304SJanie.Lu@Sun.COM char *
fab_xpath_query(fmd_hdl_t * hdl,const char * query)23011304SJanie.Lu@Sun.COM fab_xpath_query(fmd_hdl_t *hdl, const char *query)
23111304SJanie.Lu@Sun.COM {
23211304SJanie.Lu@Sun.COM 	xmlXPathObjectPtr xpathObj;
23311304SJanie.Lu@Sun.COM 	xmlNodeSetPtr nodes;
23411304SJanie.Lu@Sun.COM 	char *temp, *res;
23511304SJanie.Lu@Sun.COM 
23611304SJanie.Lu@Sun.COM 	fmd_hdl_debug(hdl, "xpathObj query %s\n", query);
23711304SJanie.Lu@Sun.COM 
23811304SJanie.Lu@Sun.COM 	xpathObj = xmlXPathEvalExpression((const xmlChar *)query,
23911304SJanie.Lu@Sun.COM 	    fab_xpathCtx);
24011304SJanie.Lu@Sun.COM 
24111304SJanie.Lu@Sun.COM 	if (xpathObj == NULL)
24211304SJanie.Lu@Sun.COM 		return (NULL);
24311304SJanie.Lu@Sun.COM 
24411304SJanie.Lu@Sun.COM 	fmd_hdl_debug(hdl, "xpathObj 0x%p type %d\n", xpathObj,
24511304SJanie.Lu@Sun.COM 	    xpathObj->type);
24611304SJanie.Lu@Sun.COM 	nodes = xpathObj->nodesetval;
24711304SJanie.Lu@Sun.COM 
24811304SJanie.Lu@Sun.COM 	if (nodes) {
24911304SJanie.Lu@Sun.COM 		temp = (char *)xmlNodeGetContent(nodes->nodeTab[0]);
25011304SJanie.Lu@Sun.COM 		fmd_hdl_debug(hdl, "query result: %s\n", temp);
25111304SJanie.Lu@Sun.COM 		res = fmd_hdl_strdup(hdl, temp, FMD_SLEEP);
25211304SJanie.Lu@Sun.COM 		xmlFree(temp);
25311304SJanie.Lu@Sun.COM 		xmlXPathFreeObject(xpathObj);
25411304SJanie.Lu@Sun.COM 		return (res);
25511304SJanie.Lu@Sun.COM 	}
25611304SJanie.Lu@Sun.COM 	xmlXPathFreeObject(xpathObj);
25711304SJanie.Lu@Sun.COM 	return (NULL);
25811304SJanie.Lu@Sun.COM }
25911304SJanie.Lu@Sun.COM 
26011304SJanie.Lu@Sun.COM #define	FAB_HC2DEV_QUERY_SIZE_MIN 160
26111304SJanie.Lu@Sun.COM #define	FAB_HC2DEV_QUERY_SIZE(sz) \
26211304SJanie.Lu@Sun.COM 	((sz + FAB_HC2DEV_QUERY_SIZE_MIN) * sizeof (char))
26311304SJanie.Lu@Sun.COM 
26411304SJanie.Lu@Sun.COM /*
26511304SJanie.Lu@Sun.COM  * hc_path is in form of "/motherboard=0/hostbridge=0/pciexrc=0"
26611304SJanie.Lu@Sun.COM  */
26711304SJanie.Lu@Sun.COM boolean_t
fab_hc2dev(fmd_hdl_t * hdl,const char * hc_path,char ** dev_path)26811304SJanie.Lu@Sun.COM fab_hc2dev(fmd_hdl_t *hdl, const char *hc_path, char **dev_path)
26911304SJanie.Lu@Sun.COM {
27011304SJanie.Lu@Sun.COM 	char *query;
27111304SJanie.Lu@Sun.COM 	uint_t len = FAB_HC2DEV_QUERY_SIZE_MIN + strlen(hc_path);
27211304SJanie.Lu@Sun.COM 
27311304SJanie.Lu@Sun.COM 	query = fmd_hdl_alloc(hdl, len, FMD_SLEEP);
27411304SJanie.Lu@Sun.COM 	(void) snprintf(query, len, "//propval[@name='resource' and contains("
27511304SJanie.Lu@Sun.COM 	    "substring(@value, string-length(@value) - %d + 1), '%s')]"
27611304SJanie.Lu@Sun.COM 	    "/parent::*/following-sibling::*/propval[@name='dev']/@value",
27711304SJanie.Lu@Sun.COM 	    strlen(hc_path) + 1, hc_path);
27811304SJanie.Lu@Sun.COM 
27911304SJanie.Lu@Sun.COM 	*dev_path = fab_xpath_query(hdl, query);
28011304SJanie.Lu@Sun.COM 
28111304SJanie.Lu@Sun.COM 	fmd_hdl_free(hdl, query, len);
28211304SJanie.Lu@Sun.COM 
28311304SJanie.Lu@Sun.COM 	return (*dev_path != NULL);
28411304SJanie.Lu@Sun.COM }
28511304SJanie.Lu@Sun.COM 
28611304SJanie.Lu@Sun.COM static boolean_t
fab_hc_path(fmd_hdl_t * hdl,nvlist_t * detector,char ** hcpath,size_t * lenp)28711304SJanie.Lu@Sun.COM fab_hc_path(fmd_hdl_t *hdl, nvlist_t *detector, char **hcpath, size_t *lenp)
28811304SJanie.Lu@Sun.COM {
28911304SJanie.Lu@Sun.COM 	char c, *name, *id, *buf;
29011304SJanie.Lu@Sun.COM 	uint_t i, size;
29111304SJanie.Lu@Sun.COM 	nvlist_t **hcl;
29211304SJanie.Lu@Sun.COM 	size_t len = 0, buf_size = 0;
29311304SJanie.Lu@Sun.COM 
29411304SJanie.Lu@Sun.COM 	if (nvlist_lookup_nvlist_array(detector, FM_FMRI_HC_LIST, &hcl,
29511304SJanie.Lu@Sun.COM 	    &size) != 0)
29611304SJanie.Lu@Sun.COM 		return (B_FALSE);
29711304SJanie.Lu@Sun.COM 
29811304SJanie.Lu@Sun.COM 	for (i = 0; i < size; i++) {
29911304SJanie.Lu@Sun.COM 		if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &name) != 0)
30011304SJanie.Lu@Sun.COM 			return (B_FALSE);
30111304SJanie.Lu@Sun.COM 		if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &id) != 0)
30211304SJanie.Lu@Sun.COM 			return (B_FALSE);
30311304SJanie.Lu@Sun.COM 		buf_size += snprintf(&c, 1, "/%s=%s", name, id);
30411304SJanie.Lu@Sun.COM 	}
30511304SJanie.Lu@Sun.COM 
30611304SJanie.Lu@Sun.COM 	buf_size++;
30711304SJanie.Lu@Sun.COM 	buf = fmd_hdl_alloc(hdl, buf_size, FMD_SLEEP);
30811304SJanie.Lu@Sun.COM 
30911304SJanie.Lu@Sun.COM 	for (i = 0; i < size; i++) {
31011304SJanie.Lu@Sun.COM 		(void) nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &name);
31111304SJanie.Lu@Sun.COM 		(void) nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &id);
31211304SJanie.Lu@Sun.COM 		len += snprintf(buf + len, buf_size - len, "/%s=%s", name, id);
31311304SJanie.Lu@Sun.COM 	}
31411304SJanie.Lu@Sun.COM 
31511304SJanie.Lu@Sun.COM 	*hcpath = buf;
31611304SJanie.Lu@Sun.COM 	*lenp = buf_size;
31711304SJanie.Lu@Sun.COM 
31811304SJanie.Lu@Sun.COM 	return (B_TRUE);
31911304SJanie.Lu@Sun.COM }
32011304SJanie.Lu@Sun.COM 
32111304SJanie.Lu@Sun.COM boolean_t
fab_hc2dev_nvl(fmd_hdl_t * hdl,nvlist_t * detector,char ** dev_path)32211304SJanie.Lu@Sun.COM fab_hc2dev_nvl(fmd_hdl_t *hdl, nvlist_t *detector, char **dev_path)
32311304SJanie.Lu@Sun.COM {
32411304SJanie.Lu@Sun.COM 	char *hcl;
32511304SJanie.Lu@Sun.COM 	size_t len;
32611304SJanie.Lu@Sun.COM 
32711304SJanie.Lu@Sun.COM 	if (! fab_hc_path(hdl, detector, &hcl, &len))
32811304SJanie.Lu@Sun.COM 		return (B_FALSE);
32911304SJanie.Lu@Sun.COM 
33011304SJanie.Lu@Sun.COM 	(void) fab_hc2dev(hdl, hcl, dev_path);
33111304SJanie.Lu@Sun.COM 
33211304SJanie.Lu@Sun.COM 	fmd_hdl_free(hdl, hcl, len);
33311304SJanie.Lu@Sun.COM 
33411304SJanie.Lu@Sun.COM 	return (*dev_path != NULL);
33511304SJanie.Lu@Sun.COM }
33611304SJanie.Lu@Sun.COM 
33711304SJanie.Lu@Sun.COM boolean_t
fab_get_hcpath(fmd_hdl_t * hdl,nvlist_t * nvl,char ** hcpath,size_t * len)33811304SJanie.Lu@Sun.COM fab_get_hcpath(fmd_hdl_t *hdl, nvlist_t *nvl, char **hcpath, size_t *len)
33911304SJanie.Lu@Sun.COM {
34011304SJanie.Lu@Sun.COM 	nvlist_t *detector;
34111304SJanie.Lu@Sun.COM 	char *scheme;
34211304SJanie.Lu@Sun.COM 
34311304SJanie.Lu@Sun.COM 	if (nvlist_lookup_nvlist(nvl, FM_EREPORT_DETECTOR, &detector) != 0 ||
34411304SJanie.Lu@Sun.COM 	    nvlist_lookup_string(detector, FM_FMRI_SCHEME, &scheme) != 0 ||
34511304SJanie.Lu@Sun.COM 	    ! STRCMP(scheme, FM_FMRI_SCHEME_HC))
34611304SJanie.Lu@Sun.COM 		return (B_FALSE);
34711304SJanie.Lu@Sun.COM 
34811304SJanie.Lu@Sun.COM 	return (fab_hc_path(hdl, detector, hcpath, len));
34911304SJanie.Lu@Sun.COM }
35011304SJanie.Lu@Sun.COM 
35111304SJanie.Lu@Sun.COM char *
fab_find_rppath_by_df(fmd_hdl_t * hdl,nvlist_t * nvl,uint8_t df)35211304SJanie.Lu@Sun.COM fab_find_rppath_by_df(fmd_hdl_t *hdl, nvlist_t *nvl, uint8_t df)
35311304SJanie.Lu@Sun.COM {
35411304SJanie.Lu@Sun.COM 	char	query[500];
35511304SJanie.Lu@Sun.COM 	char	str[10];
35611304SJanie.Lu@Sun.COM 	char	*hcpath;
35711304SJanie.Lu@Sun.COM 	size_t	len;
35811304SJanie.Lu@Sun.COM 
35911304SJanie.Lu@Sun.COM 	(void) snprintf(str, sizeof (str), "%0hhx", df);
36011304SJanie.Lu@Sun.COM 
36111304SJanie.Lu@Sun.COM 	/*
36211304SJanie.Lu@Sun.COM 	 * get the string form of the hc detector, eg
36311304SJanie.Lu@Sun.COM 	 * /chassis=0/motherboard=0/hostbridge=0
36411304SJanie.Lu@Sun.COM 	 */
36511304SJanie.Lu@Sun.COM 	if (!fab_get_hcpath(hdl, nvl, &hcpath, &len))
36611304SJanie.Lu@Sun.COM 		return (NULL);
36711304SJanie.Lu@Sun.COM 
36811304SJanie.Lu@Sun.COM 	/*
36911304SJanie.Lu@Sun.COM 	 * Explanation of the XSL XPATH Query
37011304SJanie.Lu@Sun.COM 	 * Line 1: Look at all nodes with the node name "propval"
37111304SJanie.Lu@Sun.COM 	 * Line 2: See if the "BDF" of the node matches DF
37211304SJanie.Lu@Sun.COM 	 * Line 3-4: See if the the node is pciexrc
37311304SJanie.Lu@Sun.COM 	 * Line 5-6: See if the "ASRU" contains root complex
37411304SJanie.Lu@Sun.COM 	 * Line 7-8: Go up one level and get prop value of io/dev
37511304SJanie.Lu@Sun.COM 	 */
37611304SJanie.Lu@Sun.COM 	(void) snprintf(query, sizeof (query), "//propval["
37711304SJanie.Lu@Sun.COM 	    "@name='BDF' and contains(substring(@value, "
37811304SJanie.Lu@Sun.COM 	    "string-length(@value) - 1), '%s')]"
37911304SJanie.Lu@Sun.COM 	    "/parent::*/parent::*/propgroup[@name='pci']/propval"
38011304SJanie.Lu@Sun.COM 	    "[@name='extended-capabilities' and @value='%s']"
38111304SJanie.Lu@Sun.COM 	    "/parent::*/parent::*/propgroup[@name='protocol']"
38211304SJanie.Lu@Sun.COM 	    "/propval[@name='resource' and contains(@value, '%s')]"
38311304SJanie.Lu@Sun.COM 	    "/parent::*/parent::*/propgroup[@name='io']"
38411304SJanie.Lu@Sun.COM 	    "/propval[@name='dev']/@value", str, PCIEX_ROOT, hcpath);
38511304SJanie.Lu@Sun.COM 
38611304SJanie.Lu@Sun.COM 	fmd_hdl_free(hdl, hcpath, len);
38711304SJanie.Lu@Sun.COM 
38811304SJanie.Lu@Sun.COM 	return (fab_xpath_query(hdl, query));
38911304SJanie.Lu@Sun.COM }
39011304SJanie.Lu@Sun.COM 
39111304SJanie.Lu@Sun.COM char *
fab_find_rppath_by_devbdf(fmd_hdl_t * hdl,nvlist_t * nvl,pcie_req_id_t bdf)39211304SJanie.Lu@Sun.COM fab_find_rppath_by_devbdf(fmd_hdl_t *hdl, nvlist_t *nvl, pcie_req_id_t bdf)
39311304SJanie.Lu@Sun.COM {
39411304SJanie.Lu@Sun.COM 	xmlXPathObjectPtr xpathObj;
39511304SJanie.Lu@Sun.COM 	xmlNodeSetPtr nodes;
39611304SJanie.Lu@Sun.COM 	xmlNodePtr devNode;
39711304SJanie.Lu@Sun.COM 	char 	*retval, *temp;
39811304SJanie.Lu@Sun.COM 	char	query[500];
39911304SJanie.Lu@Sun.COM 	int	i, size, bus, dev, fn;
40011304SJanie.Lu@Sun.COM 	char	*hcpath;
40111304SJanie.Lu@Sun.COM 	size_t	len;
40211304SJanie.Lu@Sun.COM 
40311304SJanie.Lu@Sun.COM 	if (bdf != (uint16_t)-1) {
40411304SJanie.Lu@Sun.COM 		bus = (bdf & PCIE_REQ_ID_BUS_MASK) >> PCIE_REQ_ID_BUS_SHIFT;
40511304SJanie.Lu@Sun.COM 		dev = (bdf & PCIE_REQ_ID_DEV_MASK) >> PCIE_REQ_ID_DEV_SHIFT;
40611304SJanie.Lu@Sun.COM 		fn = (bdf & PCIE_REQ_ID_FUNC_MASK) >> PCIE_REQ_ID_FUNC_SHIFT;
40711304SJanie.Lu@Sun.COM 	}
40811304SJanie.Lu@Sun.COM 
40911304SJanie.Lu@Sun.COM 	/*
41011304SJanie.Lu@Sun.COM 	 * get the string form of the hc detector, eg
41111304SJanie.Lu@Sun.COM 	 * /chassis=0/motherboard=0/hostbridge=0
41211304SJanie.Lu@Sun.COM 	 */
41311304SJanie.Lu@Sun.COM 	if (!fab_get_hcpath(hdl, nvl, &hcpath, &len))
41411304SJanie.Lu@Sun.COM 		goto fail;
41511304SJanie.Lu@Sun.COM 
41611304SJanie.Lu@Sun.COM 	/*
41711304SJanie.Lu@Sun.COM 	 * Explanation of the XSL XPATH Query
41811304SJanie.Lu@Sun.COM 	 * Line 1: Look at all nodes with the node name "propval"
41911304SJanie.Lu@Sun.COM 	 * Line 2-3: See if the "value" of the node ends with correct PCIEx BDF
42011304SJanie.Lu@Sun.COM 	 * Line 4-5: See if the "value" of the node ends with correct PCI BDF
42111304SJanie.Lu@Sun.COM 	 * Line 6: Go up one level to the parent of the current node
42211304SJanie.Lu@Sun.COM 	 * Line 7: See if child node contains "ASRU" with the same PCIe Root
42311304SJanie.Lu@Sun.COM 	 * Line 8: Go up see all the ancestors
42411304SJanie.Lu@Sun.COM 	 */
42511304SJanie.Lu@Sun.COM 	(void) snprintf(query, sizeof (query), "//propval["
42611304SJanie.Lu@Sun.COM 	    "contains(substring(@value, string-length(@value) - 34), "
42711304SJanie.Lu@Sun.COM 	    "'pciexbus=%d/pciexdev=%d/pciexfn=%d') or "
42811304SJanie.Lu@Sun.COM 	    "contains(substring(@value, string-length(@value) - 28), "
42911304SJanie.Lu@Sun.COM 	    "'pcibus=%d/pcidev=%d/pcifn=%d')"
43011304SJanie.Lu@Sun.COM 	    "]/parent::"
43111304SJanie.Lu@Sun.COM 	    "*/propval[@name='resource' and contains(@value, '%s')]"
43211304SJanie.Lu@Sun.COM 	    "/ancestor::*",
43311304SJanie.Lu@Sun.COM 	    bus, dev, fn, bus, dev, fn, hcpath);
43411304SJanie.Lu@Sun.COM 
43511304SJanie.Lu@Sun.COM 	fmd_hdl_free(hdl, hcpath, len);
43611304SJanie.Lu@Sun.COM 
43711304SJanie.Lu@Sun.COM 	fmd_hdl_debug(hdl, "xpathObj query %s\n", query);
43811304SJanie.Lu@Sun.COM 
43911304SJanie.Lu@Sun.COM 	xpathObj = xmlXPathEvalExpression((const xmlChar *)query, fab_xpathCtx);
44011304SJanie.Lu@Sun.COM 
44111304SJanie.Lu@Sun.COM 	if (xpathObj == NULL)
44211304SJanie.Lu@Sun.COM 		goto fail;
44311304SJanie.Lu@Sun.COM 
44411304SJanie.Lu@Sun.COM 	nodes = xpathObj->nodesetval;
44511304SJanie.Lu@Sun.COM 	size = (nodes) ? nodes->nodeNr : 0;
44611304SJanie.Lu@Sun.COM 
44711304SJanie.Lu@Sun.COM 	fmd_hdl_debug(hdl, "xpathObj 0x%p type %d size %d\n",
44811304SJanie.Lu@Sun.COM 	    xpathObj, xpathObj->type, size);
44911304SJanie.Lu@Sun.COM 
45011304SJanie.Lu@Sun.COM 	for (i = 0; i < size; i++) {
45111304SJanie.Lu@Sun.COM 		devNode = nodes->nodeTab[i];
45211304SJanie.Lu@Sun.COM 		if (STRCMP(devNode->name, "range") &&
45311304SJanie.Lu@Sun.COM 		    HAS_PROP(devNode, "name")) {
45411304SJanie.Lu@Sun.COM 			char *tprop = GET_PROP(devNode, "name");
45511304SJanie.Lu@Sun.COM 
45611304SJanie.Lu@Sun.COM 			/* find "range name='pciexrc'" in ancestors */
45711304SJanie.Lu@Sun.COM 			if (STRCMP(tprop, PCIEX_ROOT)) {
45811304SJanie.Lu@Sun.COM 				/* go down to the pciexrc instance node */
45911304SJanie.Lu@Sun.COM 				FREE_PROP(tprop);
46011304SJanie.Lu@Sun.COM 				devNode = nodes->nodeTab[i+1];
46111304SJanie.Lu@Sun.COM 				goto found;
46211304SJanie.Lu@Sun.COM 			}
46311304SJanie.Lu@Sun.COM 			FREE_PROP(tprop);
46411304SJanie.Lu@Sun.COM 		}
46511304SJanie.Lu@Sun.COM 	}
46611304SJanie.Lu@Sun.COM 	goto fail;
46711304SJanie.Lu@Sun.COM 
46811304SJanie.Lu@Sun.COM found:
46911304SJanie.Lu@Sun.COM 	/* Traverse down the xml tree to find the right propgroup */
47011304SJanie.Lu@Sun.COM 	for (devNode = devNode->children; devNode; devNode = devNode->next) {
47111304SJanie.Lu@Sun.COM 		if (STRCMP(devNode->name, "propgroup")) {
47211304SJanie.Lu@Sun.COM 			char *tprop = GET_PROP(devNode, "name");
47311304SJanie.Lu@Sun.COM 
47411304SJanie.Lu@Sun.COM 			if (STRCMP(tprop, "io")) {
47511304SJanie.Lu@Sun.COM 				FREE_PROP(tprop);
47611304SJanie.Lu@Sun.COM 				goto propgroup;
47711304SJanie.Lu@Sun.COM 			}
47811304SJanie.Lu@Sun.COM 			FREE_PROP(tprop);
47911304SJanie.Lu@Sun.COM 		}
48011304SJanie.Lu@Sun.COM 	}
48111304SJanie.Lu@Sun.COM 	goto fail;
48211304SJanie.Lu@Sun.COM 
48311304SJanie.Lu@Sun.COM propgroup:
48411304SJanie.Lu@Sun.COM 	/* Retrive the "dev" propval and return */
48511304SJanie.Lu@Sun.COM 	for (devNode = devNode->children; devNode; devNode = devNode->next) {
48611304SJanie.Lu@Sun.COM 		if (STRCMP(devNode->name, "propval")) {
48711304SJanie.Lu@Sun.COM 			char *tprop = GET_PROP(devNode, "name");
48811304SJanie.Lu@Sun.COM 
48911304SJanie.Lu@Sun.COM 			if (STRCMP(tprop, "dev")) {
49011304SJanie.Lu@Sun.COM 				temp = GET_PROP(devNode, "value");
49111304SJanie.Lu@Sun.COM 				retval = fmd_hdl_strdup(hdl, temp, FMD_SLEEP);
49211304SJanie.Lu@Sun.COM 				fmd_hdl_debug(hdl, "RP Path: %s\n", retval);
49311304SJanie.Lu@Sun.COM 				xmlFree(temp);
49411304SJanie.Lu@Sun.COM 				xmlXPathFreeObject(xpathObj);
49511304SJanie.Lu@Sun.COM 			}
49611304SJanie.Lu@Sun.COM 			FREE_PROP(tprop);
49711304SJanie.Lu@Sun.COM 
49811304SJanie.Lu@Sun.COM 			return (retval);
49911304SJanie.Lu@Sun.COM 		}
50011304SJanie.Lu@Sun.COM 	}
50111304SJanie.Lu@Sun.COM fail:
50211304SJanie.Lu@Sun.COM 	if (xpathObj != NULL)
50311304SJanie.Lu@Sun.COM 		xmlXPathFreeObject(xpathObj);
50411304SJanie.Lu@Sun.COM 	return (NULL);
50511304SJanie.Lu@Sun.COM }
50611304SJanie.Lu@Sun.COM 
507*12132SSean.Ye@Sun.COM char *
fab_find_rppath_by_devpath(fmd_hdl_t * hdl,const char * devpath)508*12132SSean.Ye@Sun.COM fab_find_rppath_by_devpath(fmd_hdl_t *hdl, const char *devpath)
509*12132SSean.Ye@Sun.COM {
510*12132SSean.Ye@Sun.COM 	char	query[500];
511*12132SSean.Ye@Sun.COM 
512*12132SSean.Ye@Sun.COM 	/*
513*12132SSean.Ye@Sun.COM 	 * Explanation of the XSL XPATH Query
514*12132SSean.Ye@Sun.COM 	 * Line 1: Look at all nodes with the node name "propval"
515*12132SSean.Ye@Sun.COM 	 * Line 2: See if the node is pciexrc
516*12132SSean.Ye@Sun.COM 	 * Line 3: Go up to the io pgroup
517*12132SSean.Ye@Sun.COM 	 * Line 4: See if the "dev" prop is parent of devpath
518*12132SSean.Ye@Sun.COM 	 * Line 5: Get the 'dev' prop
519*12132SSean.Ye@Sun.COM 	 */
520*12132SSean.Ye@Sun.COM 	(void) snprintf(query, sizeof (query), "//propval"
521*12132SSean.Ye@Sun.COM 	    "[@name='extended-capabilities' and @value='%s']"
522*12132SSean.Ye@Sun.COM 	    "/parent::*/parent::*/propgroup[@name='io']"
523*12132SSean.Ye@Sun.COM 	    "/propval[@name='dev' and starts-with('%s', concat(@value, '/'))]"
524*12132SSean.Ye@Sun.COM 	    "/@value", PCIEX_ROOT, devpath);
525*12132SSean.Ye@Sun.COM 
526*12132SSean.Ye@Sun.COM 	return (fab_xpath_query(hdl, query));
527*12132SSean.Ye@Sun.COM }
528*12132SSean.Ye@Sun.COM 
52911304SJanie.Lu@Sun.COM /* ARGSUSED */
53011304SJanie.Lu@Sun.COM boolean_t
fab_get_rcpath(fmd_hdl_t * hdl,nvlist_t * nvl,char * rcpath)53111304SJanie.Lu@Sun.COM fab_get_rcpath(fmd_hdl_t *hdl, nvlist_t *nvl, char *rcpath)
53211304SJanie.Lu@Sun.COM {
53311304SJanie.Lu@Sun.COM 	nvlist_t	*detector;
53411304SJanie.Lu@Sun.COM 	char		*path, *scheme;
53511304SJanie.Lu@Sun.COM 
53611304SJanie.Lu@Sun.COM 	if (nvlist_lookup_nvlist(nvl, FM_EREPORT_DETECTOR, &detector) != 0)
53711304SJanie.Lu@Sun.COM 		goto fail;
53811304SJanie.Lu@Sun.COM 	if (nvlist_lookup_string(detector, FM_FMRI_SCHEME, &scheme) != 0)
53911304SJanie.Lu@Sun.COM 		goto fail;
54011304SJanie.Lu@Sun.COM 
54111304SJanie.Lu@Sun.COM 	if (STRCMP(scheme, FM_FMRI_SCHEME_DEV)) {
54211304SJanie.Lu@Sun.COM 		if (nvlist_lookup_string(detector, FM_FMRI_DEV_PATH,
54311304SJanie.Lu@Sun.COM 		    &path) != 0)
54411304SJanie.Lu@Sun.COM 			goto fail;
54511304SJanie.Lu@Sun.COM 		(void) strncpy(rcpath, path, FM_MAX_CLASS);
54611304SJanie.Lu@Sun.COM 	} else if (STRCMP(scheme, FM_FMRI_SCHEME_HC)) {
54711304SJanie.Lu@Sun.COM 		/*
54811304SJanie.Lu@Sun.COM 		 * This should only occur for ereports that come from the RC
54911304SJanie.Lu@Sun.COM 		 * itself.  In this case convert HC scheme to dev path.
55011304SJanie.Lu@Sun.COM 		 */
55111304SJanie.Lu@Sun.COM 		if (fab_hc2dev_nvl(hdl, detector, &path)) {
55211304SJanie.Lu@Sun.COM 			(void) strncpy(rcpath, path, FM_MAX_CLASS);
55311304SJanie.Lu@Sun.COM 			fmd_hdl_strfree(hdl, path);
55411304SJanie.Lu@Sun.COM 		} else {
55511304SJanie.Lu@Sun.COM 			goto fail;
55611304SJanie.Lu@Sun.COM 		}
55711304SJanie.Lu@Sun.COM 	} else {
55811304SJanie.Lu@Sun.COM 		return (B_FALSE);
55911304SJanie.Lu@Sun.COM 	}
56011304SJanie.Lu@Sun.COM 
56111304SJanie.Lu@Sun.COM 	/*
56211304SJanie.Lu@Sun.COM 	 * Extract the RC path by taking the first device in the dev path
56311304SJanie.Lu@Sun.COM 	 *
56411304SJanie.Lu@Sun.COM 	 * /pci@0,0/pci8086,3605@2/pci8086,3500@0/pci8086,3514@1/pci8086,105e@0
56511304SJanie.Lu@Sun.COM 	 * - to -
56611304SJanie.Lu@Sun.COM 	 * /pci@0,0
56711304SJanie.Lu@Sun.COM 	 */
56811304SJanie.Lu@Sun.COM 	path = strchr(rcpath + 1, '/');
56911304SJanie.Lu@Sun.COM 	if (path)
57011304SJanie.Lu@Sun.COM 		path[0] = '\0';
57111304SJanie.Lu@Sun.COM 
57211304SJanie.Lu@Sun.COM 	return (B_TRUE);
57311304SJanie.Lu@Sun.COM fail:
57411304SJanie.Lu@Sun.COM 	return (B_FALSE);
57511304SJanie.Lu@Sun.COM }
57611304SJanie.Lu@Sun.COM 
57711304SJanie.Lu@Sun.COM char *
fab_find_bdf(fmd_hdl_t * hdl,nvlist_t * nvl,pcie_req_id_t bdf)57811304SJanie.Lu@Sun.COM fab_find_bdf(fmd_hdl_t *hdl, nvlist_t *nvl, pcie_req_id_t bdf)
57911304SJanie.Lu@Sun.COM {
58011304SJanie.Lu@Sun.COM 	char 	*retval;
58111304SJanie.Lu@Sun.COM 	char	query[500];
58211304SJanie.Lu@Sun.COM 	int	bus, dev, fn;
58311304SJanie.Lu@Sun.COM 	char	rcpath[255];
58411304SJanie.Lu@Sun.COM 
58511304SJanie.Lu@Sun.COM 	if (bdf != (uint16_t)-1) {
58611304SJanie.Lu@Sun.COM 		bus = (bdf & PCIE_REQ_ID_BUS_MASK) >> PCIE_REQ_ID_BUS_SHIFT;
58711304SJanie.Lu@Sun.COM 		dev = (bdf & PCIE_REQ_ID_DEV_MASK) >> PCIE_REQ_ID_DEV_SHIFT;
58811304SJanie.Lu@Sun.COM 		fn = (bdf & PCIE_REQ_ID_FUNC_MASK) >> PCIE_REQ_ID_FUNC_SHIFT;
58911304SJanie.Lu@Sun.COM 	}
59011304SJanie.Lu@Sun.COM 
59111304SJanie.Lu@Sun.COM 	if (!fab_get_rcpath(hdl, nvl, rcpath))
59211304SJanie.Lu@Sun.COM 		goto fail;
59311304SJanie.Lu@Sun.COM 
59411304SJanie.Lu@Sun.COM 	/*
59511304SJanie.Lu@Sun.COM 	 * Explanation of the XSL XPATH Query
59611304SJanie.Lu@Sun.COM 	 * Line 1: Look at all nodes with the node name "propval"
59711304SJanie.Lu@Sun.COM 	 * Line 2-3: See if the "value" of the node ends with correct PCIEx BDF
59811304SJanie.Lu@Sun.COM 	 * Line 4-5: See if the "value" of the node ends with correct PCI BDF
59911304SJanie.Lu@Sun.COM 	 * Line 6: Go up one level to the parent of the current node
60011304SJanie.Lu@Sun.COM 	 * Line 7: See if child node contains "ASRU" with the same PCIe Root
60111304SJanie.Lu@Sun.COM 	 * Line 8: Traverse up the parent and the other siblings and look for
60211304SJanie.Lu@Sun.COM 	 *	   the io "propgroup" and get the value of the dev "propval"
60311304SJanie.Lu@Sun.COM 	 */
60411304SJanie.Lu@Sun.COM 	(void) snprintf(query, sizeof (query), "//propval["
60511304SJanie.Lu@Sun.COM 	    "contains(substring(@value, string-length(@value) - 34), "
60611304SJanie.Lu@Sun.COM 	    "'pciexbus=%d/pciexdev=%d/pciexfn=%d') or "
60711304SJanie.Lu@Sun.COM 	    "contains(substring(@value, string-length(@value) - 28), "
60811304SJanie.Lu@Sun.COM 	    "'pcibus=%d/pcidev=%d/pcifn=%d')"
60911304SJanie.Lu@Sun.COM 	    "]/parent::"
61011304SJanie.Lu@Sun.COM 	    "*/propval[@name='ASRU' and contains(@value, '%s')]"
61111304SJanie.Lu@Sun.COM 	    "/parent::*/following-sibling::*[@name='io']/propval[@name='dev']/"
61211304SJanie.Lu@Sun.COM 	    "@value", bus, dev, fn, bus, dev, fn, rcpath);
61311304SJanie.Lu@Sun.COM 
61411304SJanie.Lu@Sun.COM 	retval = fab_xpath_query(hdl, query);
61511304SJanie.Lu@Sun.COM 	if (retval) {
61611304SJanie.Lu@Sun.COM 		fmd_hdl_debug(hdl, "BDF Dev Path: %s\n", retval);
61711304SJanie.Lu@Sun.COM 		return (retval);
61811304SJanie.Lu@Sun.COM 	}
61911304SJanie.Lu@Sun.COM fail:
62011304SJanie.Lu@Sun.COM 	return (NULL);
62111304SJanie.Lu@Sun.COM }
62211304SJanie.Lu@Sun.COM 
62311304SJanie.Lu@Sun.COM char *
fab_find_addr(fmd_hdl_t * hdl,nvlist_t * nvl,uint64_t addr)62411304SJanie.Lu@Sun.COM fab_find_addr(fmd_hdl_t *hdl, nvlist_t *nvl, uint64_t addr)
62511304SJanie.Lu@Sun.COM {
62611304SJanie.Lu@Sun.COM 	xmlXPathObjectPtr xpathObj;
62711304SJanie.Lu@Sun.COM 	xmlNodeSetPtr nodes;
62811304SJanie.Lu@Sun.COM 	xmlNodePtr devNode;
62911304SJanie.Lu@Sun.COM 	char *retval, *temp;
63011304SJanie.Lu@Sun.COM 	char query[500];
63111304SJanie.Lu@Sun.COM 	int size, i, j;
63211304SJanie.Lu@Sun.COM 	uint32_t prop[50];
63311304SJanie.Lu@Sun.COM 	char *token;
63411304SJanie.Lu@Sun.COM 	pci_regspec_t *assign_p;
63511304SJanie.Lu@Sun.COM 	uint64_t low, hi;
63611304SJanie.Lu@Sun.COM 	char rcpath[255];
63711304SJanie.Lu@Sun.COM 
63811304SJanie.Lu@Sun.COM 	if (!fab_get_rcpath(hdl, nvl, rcpath))
63911304SJanie.Lu@Sun.COM 		goto fail;
64011304SJanie.Lu@Sun.COM 
64111304SJanie.Lu@Sun.COM 	(void) snprintf(query, sizeof (query), "//propval["
64211304SJanie.Lu@Sun.COM 	    "@name='ASRU' and contains(@value, '%s')]/"
64311304SJanie.Lu@Sun.COM 	    "parent::*/following-sibling::*[@name='pci']/"
64411304SJanie.Lu@Sun.COM 	    "propval[@name='assigned-addresses']", rcpath);
64511304SJanie.Lu@Sun.COM 
64611304SJanie.Lu@Sun.COM 	fmd_hdl_debug(hdl, "xpathObj query %s\n", query);
64711304SJanie.Lu@Sun.COM 
64811304SJanie.Lu@Sun.COM 	xpathObj = xmlXPathEvalExpression((const xmlChar *)query, fab_xpathCtx);
64911304SJanie.Lu@Sun.COM 
65011304SJanie.Lu@Sun.COM 	if (xpathObj == NULL)
65111304SJanie.Lu@Sun.COM 		goto fail;
65211304SJanie.Lu@Sun.COM 
65311304SJanie.Lu@Sun.COM 	fmd_hdl_debug(hdl, "xpathObj 0x%p type %d\n", xpathObj, xpathObj->type);
65411304SJanie.Lu@Sun.COM 
65511304SJanie.Lu@Sun.COM 	nodes = xpathObj->nodesetval;
65611304SJanie.Lu@Sun.COM 	size = (nodes) ? nodes->nodeNr : 0;
65711304SJanie.Lu@Sun.COM 
65811304SJanie.Lu@Sun.COM 	/* Decode the list of assigned addresses xml nodes for each device */
65911304SJanie.Lu@Sun.COM 	for (i = 0; i < size; i++) {
66011304SJanie.Lu@Sun.COM 		char *tprop;
66111304SJanie.Lu@Sun.COM 
66211304SJanie.Lu@Sun.COM 		devNode = nodes->nodeTab[i];
66311304SJanie.Lu@Sun.COM 		if (!HAS_PROP(devNode, "value"))
66411304SJanie.Lu@Sun.COM 			continue;
66511304SJanie.Lu@Sun.COM 
66611304SJanie.Lu@Sun.COM 		/* Convert "string" assigned-addresses to pci_regspec_t */
66711304SJanie.Lu@Sun.COM 		j = 0;
66811304SJanie.Lu@Sun.COM 		tprop = GET_PROP(devNode, "value");
66911304SJanie.Lu@Sun.COM 		for (token = strtok(tprop, " "); token;
67011304SJanie.Lu@Sun.COM 		    token = strtok(NULL, " ")) {
67111304SJanie.Lu@Sun.COM 			prop[j++] = strtoul(token, (char **)NULL, 16);
67211304SJanie.Lu@Sun.COM 		}
67311304SJanie.Lu@Sun.COM 		prop[j] = (uint32_t)-1;
67411304SJanie.Lu@Sun.COM 		FREE_PROP(tprop);
67511304SJanie.Lu@Sun.COM 
67611304SJanie.Lu@Sun.COM 		/* Check if address belongs to this device */
67711304SJanie.Lu@Sun.COM 		for (assign_p = (pci_regspec_t *)prop;
67811304SJanie.Lu@Sun.COM 		    assign_p->pci_phys_hi != (uint_t)-1; assign_p++) {
67911304SJanie.Lu@Sun.COM 			low = assign_p->pci_phys_low;
68011304SJanie.Lu@Sun.COM 			hi = low + assign_p->pci_size_low;
68111304SJanie.Lu@Sun.COM 			if ((addr < hi) && (addr >= low)) {
68211304SJanie.Lu@Sun.COM 				fmd_hdl_debug(hdl, "Found Address\n");
68311304SJanie.Lu@Sun.COM 				goto found;
68411304SJanie.Lu@Sun.COM 			}
68511304SJanie.Lu@Sun.COM 		}
68611304SJanie.Lu@Sun.COM 	}
68711304SJanie.Lu@Sun.COM 	goto fail;
68811304SJanie.Lu@Sun.COM 
68911304SJanie.Lu@Sun.COM found:
69011304SJanie.Lu@Sun.COM 	/* Traverse up the xml tree and back down to find the right propgroup */
69111304SJanie.Lu@Sun.COM 	for (devNode = devNode->parent->parent->children;
69211304SJanie.Lu@Sun.COM 	    devNode; devNode = devNode->next) {
69311304SJanie.Lu@Sun.COM 		char	*tprop;
69411304SJanie.Lu@Sun.COM 
69511304SJanie.Lu@Sun.COM 		tprop = GET_PROP(devNode, "name");
69611304SJanie.Lu@Sun.COM 		if (STRCMP(devNode->name, "propgroup") &&
69711304SJanie.Lu@Sun.COM 		    STRCMP(tprop, "io")) {
69811304SJanie.Lu@Sun.COM 			FREE_PROP(tprop);
69911304SJanie.Lu@Sun.COM 			goto propgroup;
70011304SJanie.Lu@Sun.COM 		}
70111304SJanie.Lu@Sun.COM 		FREE_PROP(tprop);
70211304SJanie.Lu@Sun.COM 	}
70311304SJanie.Lu@Sun.COM 	goto fail;
70411304SJanie.Lu@Sun.COM 
70511304SJanie.Lu@Sun.COM propgroup:
70611304SJanie.Lu@Sun.COM 	/* Retrive the "dev" propval and return */
70711304SJanie.Lu@Sun.COM 	for (devNode = devNode->children; devNode; devNode = devNode->next) {
70811304SJanie.Lu@Sun.COM 		char 	*tprop;
70911304SJanie.Lu@Sun.COM 
71011304SJanie.Lu@Sun.COM 		tprop = GET_PROP(devNode, "name");
71111304SJanie.Lu@Sun.COM 		if (STRCMP(devNode->name, "propval") &&
71211304SJanie.Lu@Sun.COM 		    STRCMP(tprop, "dev")) {
71311304SJanie.Lu@Sun.COM 			FREE_PROP(tprop);
71411304SJanie.Lu@Sun.COM 			temp = GET_PROP(devNode, "value");
71511304SJanie.Lu@Sun.COM 			retval = fmd_hdl_strdup(hdl, temp, FMD_SLEEP);
71611304SJanie.Lu@Sun.COM 			fmd_hdl_debug(hdl, "Addr Dev Path: %s\n", retval);
71711304SJanie.Lu@Sun.COM 			xmlFree(temp);
71811304SJanie.Lu@Sun.COM 			xmlXPathFreeObject(xpathObj);
71911304SJanie.Lu@Sun.COM 			return (retval);
72011304SJanie.Lu@Sun.COM 		}
72111304SJanie.Lu@Sun.COM 		FREE_PROP(tprop);
72211304SJanie.Lu@Sun.COM 	}
72311304SJanie.Lu@Sun.COM fail:
72411304SJanie.Lu@Sun.COM 	if (xpathObj != NULL)
72511304SJanie.Lu@Sun.COM 		xmlXPathFreeObject(xpathObj);
72611304SJanie.Lu@Sun.COM 	return (NULL);
72711304SJanie.Lu@Sun.COM }
72811304SJanie.Lu@Sun.COM 
72911304SJanie.Lu@Sun.COM void
fab_pr(fmd_hdl_t * hdl,fmd_event_t * ep,nvlist_t * nvl)73011304SJanie.Lu@Sun.COM fab_pr(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl)
73111304SJanie.Lu@Sun.COM {
73211304SJanie.Lu@Sun.COM 	nvpair_t *nvp;
73311304SJanie.Lu@Sun.COM 
73411304SJanie.Lu@Sun.COM 	for (nvp = nvlist_next_nvpair(nvl, NULL);
73511304SJanie.Lu@Sun.COM 	    nvp != NULL;
73611304SJanie.Lu@Sun.COM 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
73711304SJanie.Lu@Sun.COM 
73811304SJanie.Lu@Sun.COM 		data_type_t type = nvpair_type(nvp);
73911304SJanie.Lu@Sun.COM 		const char *name = nvpair_name(nvp);
74011304SJanie.Lu@Sun.COM 
74111304SJanie.Lu@Sun.COM 		boolean_t b;
74211304SJanie.Lu@Sun.COM 		uint8_t i8;
74311304SJanie.Lu@Sun.COM 		uint16_t i16;
74411304SJanie.Lu@Sun.COM 		uint32_t i32;
74511304SJanie.Lu@Sun.COM 		uint64_t i64;
74611304SJanie.Lu@Sun.COM 		char *str;
74711304SJanie.Lu@Sun.COM 		nvlist_t *cnv;
74811304SJanie.Lu@Sun.COM 
74911304SJanie.Lu@Sun.COM 		nvlist_t **nvlarr;
75011304SJanie.Lu@Sun.COM 		uint_t arrsize;
75111304SJanie.Lu@Sun.COM 		int arri;
75211304SJanie.Lu@Sun.COM 
75311304SJanie.Lu@Sun.COM 
75411304SJanie.Lu@Sun.COM 		if (STRCMP(name, FM_CLASS))
75511304SJanie.Lu@Sun.COM 			continue; /* already printed by caller */
75611304SJanie.Lu@Sun.COM 
75711304SJanie.Lu@Sun.COM 		fmd_hdl_debug(hdl, " %s=", name);
75811304SJanie.Lu@Sun.COM 
75911304SJanie.Lu@Sun.COM 		switch (type) {
76011304SJanie.Lu@Sun.COM 		case DATA_TYPE_BOOLEAN:
76111304SJanie.Lu@Sun.COM 			fmd_hdl_debug(hdl, "DATA_TYPE_BOOLEAN 1");
76211304SJanie.Lu@Sun.COM 			break;
76311304SJanie.Lu@Sun.COM 
76411304SJanie.Lu@Sun.COM 		case DATA_TYPE_BOOLEAN_VALUE:
76511304SJanie.Lu@Sun.COM 			(void) nvpair_value_boolean_value(nvp, &b);
76611304SJanie.Lu@Sun.COM 			fmd_hdl_debug(hdl, "DATA_TYPE_BOOLEAN_VALUE %d",
76711304SJanie.Lu@Sun.COM 			    b ? "1" : "0");
76811304SJanie.Lu@Sun.COM 			break;
76911304SJanie.Lu@Sun.COM 
77011304SJanie.Lu@Sun.COM 		case DATA_TYPE_BYTE:
77111304SJanie.Lu@Sun.COM 			(void) nvpair_value_byte(nvp, &i8);
77211304SJanie.Lu@Sun.COM 			fmd_hdl_debug(hdl, "DATA_TYPE_BYTE 0x%x", i8);
77311304SJanie.Lu@Sun.COM 			break;
77411304SJanie.Lu@Sun.COM 
77511304SJanie.Lu@Sun.COM 		case DATA_TYPE_INT8:
77611304SJanie.Lu@Sun.COM 			(void) nvpair_value_int8(nvp, (void *)&i8);
77711304SJanie.Lu@Sun.COM 			fmd_hdl_debug(hdl, "DATA_TYPE_INT8 0x%x", i8);
77811304SJanie.Lu@Sun.COM 			break;
77911304SJanie.Lu@Sun.COM 
78011304SJanie.Lu@Sun.COM 		case DATA_TYPE_UINT8:
78111304SJanie.Lu@Sun.COM 			(void) nvpair_value_uint8(nvp, &i8);
78211304SJanie.Lu@Sun.COM 			fmd_hdl_debug(hdl, "DATA_TYPE_UINT8 0x%x", i8);
78311304SJanie.Lu@Sun.COM 			break;
78411304SJanie.Lu@Sun.COM 
78511304SJanie.Lu@Sun.COM 		case DATA_TYPE_INT16:
78611304SJanie.Lu@Sun.COM 			(void) nvpair_value_int16(nvp, (void *)&i16);
78711304SJanie.Lu@Sun.COM 			fmd_hdl_debug(hdl, "DATA_TYPE_INT16 0x%x", i16);
78811304SJanie.Lu@Sun.COM 			break;
78911304SJanie.Lu@Sun.COM 
79011304SJanie.Lu@Sun.COM 		case DATA_TYPE_UINT16:
79111304SJanie.Lu@Sun.COM 			(void) nvpair_value_uint16(nvp, &i16);
79211304SJanie.Lu@Sun.COM 			fmd_hdl_debug(hdl, "DATA_TYPE_UINT16 0x%x", i16);
79311304SJanie.Lu@Sun.COM 			break;
79411304SJanie.Lu@Sun.COM 
79511304SJanie.Lu@Sun.COM 		case DATA_TYPE_INT32:
79611304SJanie.Lu@Sun.COM 			(void) nvpair_value_int32(nvp, (void *)&i32);
79711304SJanie.Lu@Sun.COM 			fmd_hdl_debug(hdl, "DATA_TYPE_INT32 0x%x", i32);
79811304SJanie.Lu@Sun.COM 			break;
79911304SJanie.Lu@Sun.COM 
80011304SJanie.Lu@Sun.COM 		case DATA_TYPE_UINT32:
80111304SJanie.Lu@Sun.COM 			(void) nvpair_value_uint32(nvp, &i32);
80211304SJanie.Lu@Sun.COM 			fmd_hdl_debug(hdl, "DATA_TYPE_UINT32 0x%x", i32);
80311304SJanie.Lu@Sun.COM 			break;
80411304SJanie.Lu@Sun.COM 
80511304SJanie.Lu@Sun.COM 		case DATA_TYPE_INT64:
80611304SJanie.Lu@Sun.COM 			(void) nvpair_value_int64(nvp, (void *)&i64);
80711304SJanie.Lu@Sun.COM 			fmd_hdl_debug(hdl, "DATA_TYPE_INT64 0x%llx",
80811304SJanie.Lu@Sun.COM 			    (u_longlong_t)i64);
80911304SJanie.Lu@Sun.COM 			break;
81011304SJanie.Lu@Sun.COM 
81111304SJanie.Lu@Sun.COM 		case DATA_TYPE_UINT64:
81211304SJanie.Lu@Sun.COM 			(void) nvpair_value_uint64(nvp, &i64);
81311304SJanie.Lu@Sun.COM 			fmd_hdl_debug(hdl, "DATA_TYPE_UINT64 0x%llx",
81411304SJanie.Lu@Sun.COM 			    (u_longlong_t)i64);
81511304SJanie.Lu@Sun.COM 			break;
81611304SJanie.Lu@Sun.COM 
81711304SJanie.Lu@Sun.COM 		case DATA_TYPE_HRTIME:
81811304SJanie.Lu@Sun.COM 			(void) nvpair_value_hrtime(nvp, (void *)&i64);
81911304SJanie.Lu@Sun.COM 			fmd_hdl_debug(hdl, "DATA_TYPE_HRTIME 0x%llx",
82011304SJanie.Lu@Sun.COM 			    (u_longlong_t)i64);
82111304SJanie.Lu@Sun.COM 			break;
82211304SJanie.Lu@Sun.COM 
82311304SJanie.Lu@Sun.COM 		case DATA_TYPE_STRING:
82411304SJanie.Lu@Sun.COM 			(void) nvpair_value_string(nvp, &str);
82511304SJanie.Lu@Sun.COM 			fmd_hdl_debug(hdl, "DATA_TYPE_STRING \"%s\"",
82611304SJanie.Lu@Sun.COM 			    str ? str : "<NULL>");
82711304SJanie.Lu@Sun.COM 			break;
82811304SJanie.Lu@Sun.COM 
82911304SJanie.Lu@Sun.COM 		case DATA_TYPE_NVLIST:
83011304SJanie.Lu@Sun.COM 			fmd_hdl_debug(hdl, "[");
83111304SJanie.Lu@Sun.COM 			(void) nvpair_value_nvlist(nvp, &cnv);
83211304SJanie.Lu@Sun.COM 			fab_pr(hdl, NULL, cnv);
83311304SJanie.Lu@Sun.COM 			fmd_hdl_debug(hdl, " ]");
83411304SJanie.Lu@Sun.COM 			break;
83511304SJanie.Lu@Sun.COM 
83611304SJanie.Lu@Sun.COM 		case DATA_TYPE_BOOLEAN_ARRAY:
83711304SJanie.Lu@Sun.COM 		case DATA_TYPE_BYTE_ARRAY:
83811304SJanie.Lu@Sun.COM 		case DATA_TYPE_INT8_ARRAY:
83911304SJanie.Lu@Sun.COM 		case DATA_TYPE_UINT8_ARRAY:
84011304SJanie.Lu@Sun.COM 		case DATA_TYPE_INT16_ARRAY:
84111304SJanie.Lu@Sun.COM 		case DATA_TYPE_UINT16_ARRAY:
84211304SJanie.Lu@Sun.COM 		case DATA_TYPE_INT32_ARRAY:
84311304SJanie.Lu@Sun.COM 		case DATA_TYPE_UINT32_ARRAY:
84411304SJanie.Lu@Sun.COM 		case DATA_TYPE_INT64_ARRAY:
84511304SJanie.Lu@Sun.COM 		case DATA_TYPE_UINT64_ARRAY:
84611304SJanie.Lu@Sun.COM 		case DATA_TYPE_STRING_ARRAY:
84711304SJanie.Lu@Sun.COM 			fmd_hdl_debug(hdl, "[...]");
84811304SJanie.Lu@Sun.COM 			break;
84911304SJanie.Lu@Sun.COM 		case DATA_TYPE_NVLIST_ARRAY:
85011304SJanie.Lu@Sun.COM 			arrsize = 0;
85111304SJanie.Lu@Sun.COM 			(void) nvpair_value_nvlist_array(nvp, &nvlarr,
85211304SJanie.Lu@Sun.COM 			    &arrsize);
85311304SJanie.Lu@Sun.COM 
85411304SJanie.Lu@Sun.COM 			for (arri = 0; arri < arrsize; arri++) {
85511304SJanie.Lu@Sun.COM 				fab_pr(hdl, ep, nvlarr[arri]);
85611304SJanie.Lu@Sun.COM 			}
85711304SJanie.Lu@Sun.COM 
85811304SJanie.Lu@Sun.COM 			break;
85911304SJanie.Lu@Sun.COM 		case DATA_TYPE_UNKNOWN:
86011304SJanie.Lu@Sun.COM 			fmd_hdl_debug(hdl, "<unknown>");
86111304SJanie.Lu@Sun.COM 			break;
86211304SJanie.Lu@Sun.COM 		}
86311304SJanie.Lu@Sun.COM 	}
86411304SJanie.Lu@Sun.COM }
86511503SGongtian.Zhao@Sun.COM 
86611503SGongtian.Zhao@Sun.COM char *
fab_get_rpdev(fmd_hdl_t * hdl)86711503SGongtian.Zhao@Sun.COM fab_get_rpdev(fmd_hdl_t *hdl)
86811503SGongtian.Zhao@Sun.COM {
86911503SGongtian.Zhao@Sun.COM 	char 	*retval;
87011503SGongtian.Zhao@Sun.COM 	char 	query[500];
87111503SGongtian.Zhao@Sun.COM 
87211503SGongtian.Zhao@Sun.COM 	(void) snprintf(query, sizeof (query), "//propval["
87311503SGongtian.Zhao@Sun.COM 	    "@name='extended-capabilities' and contains(@value, '%s')]"
87411503SGongtian.Zhao@Sun.COM 	    "/parent::*/parent::*/propgroup[@name='io']"
87511503SGongtian.Zhao@Sun.COM 	    "/propval[@name='dev']/@value", PCIEX_ROOT);
87611503SGongtian.Zhao@Sun.COM 
87711503SGongtian.Zhao@Sun.COM 	retval = fab_xpath_query(hdl, query);
87811503SGongtian.Zhao@Sun.COM 	if (retval) {
87911503SGongtian.Zhao@Sun.COM 		fmd_hdl_debug(hdl, "Root port path is %s\n", retval);
88011503SGongtian.Zhao@Sun.COM 		return (retval);
88111503SGongtian.Zhao@Sun.COM 	}
88211503SGongtian.Zhao@Sun.COM 
88311503SGongtian.Zhao@Sun.COM 	return (NULL);
88411503SGongtian.Zhao@Sun.COM }
88511862SSean.Ye@Sun.COM 
88611862SSean.Ye@Sun.COM void
fab_send_erpt_all_rps(fmd_hdl_t * hdl,nvlist_t * erpt)88711862SSean.Ye@Sun.COM fab_send_erpt_all_rps(fmd_hdl_t *hdl, nvlist_t *erpt)
88811862SSean.Ye@Sun.COM {
88911862SSean.Ye@Sun.COM 	xmlXPathObjectPtr xpathObj;
89011862SSean.Ye@Sun.COM 	xmlNodeSetPtr nodes;
89111862SSean.Ye@Sun.COM 	char 	*rppath, *hbpath;
89211862SSean.Ye@Sun.COM 	char 	query[600];
89311862SSean.Ye@Sun.COM 	nvlist_t *detector, *nvl;
89411862SSean.Ye@Sun.COM 	uint_t	i, size;
89511862SSean.Ye@Sun.COM 	size_t len;
89611862SSean.Ye@Sun.COM 
89711862SSean.Ye@Sun.COM 	/* get hostbridge's path */
89811862SSean.Ye@Sun.COM 	if (!fab_get_hcpath(hdl, erpt, &hbpath, &len)) {
89911862SSean.Ye@Sun.COM 		fmd_hdl_debug(hdl,
90011862SSean.Ye@Sun.COM 		    "fab_send_erpt_on_all_rps: fab_get_hcpath() failed.\n");
90111862SSean.Ye@Sun.COM 		return;
90211862SSean.Ye@Sun.COM 	}
90311862SSean.Ye@Sun.COM 
90411862SSean.Ye@Sun.COM 	(void) snprintf(query, sizeof (query), "//propval["
90511862SSean.Ye@Sun.COM 	    "@name='extended-capabilities' and contains(@value, '%s')]"
90611862SSean.Ye@Sun.COM 	    "/parent::*/parent::*/propgroup[@name='protocol']"
90711862SSean.Ye@Sun.COM 	    "/propval[@name='resource' and contains(@value, '%s/')"
90811862SSean.Ye@Sun.COM 	    "]/parent::*/parent::*/propgroup[@name='io']"
90911862SSean.Ye@Sun.COM 	    "/propval[@name='dev']/@value", PCIEX_ROOT, hbpath);
91011862SSean.Ye@Sun.COM 
91111862SSean.Ye@Sun.COM 	fmd_hdl_free(hdl, hbpath, len);
91211862SSean.Ye@Sun.COM 
91311862SSean.Ye@Sun.COM 	fmd_hdl_debug(hdl, "xpathObj query %s\n", query);
91411862SSean.Ye@Sun.COM 
91511862SSean.Ye@Sun.COM 	xpathObj = xmlXPathEvalExpression((const xmlChar *)query, fab_xpathCtx);
91611862SSean.Ye@Sun.COM 
91711862SSean.Ye@Sun.COM 	if (xpathObj == NULL)
91811862SSean.Ye@Sun.COM 		return;
91911862SSean.Ye@Sun.COM 
92011862SSean.Ye@Sun.COM 	nodes = xpathObj->nodesetval;
92111862SSean.Ye@Sun.COM 	size = (nodes) ? nodes->nodeNr : 0;
92211862SSean.Ye@Sun.COM 
92311862SSean.Ye@Sun.COM 	fmd_hdl_debug(hdl, "xpathObj 0x%p type %d size %d\n",
92411862SSean.Ye@Sun.COM 	    xpathObj, xpathObj->type, size);
92511862SSean.Ye@Sun.COM 
92611862SSean.Ye@Sun.COM 	for (i = 0; i < size; i++) {
92711862SSean.Ye@Sun.COM 		rppath = (char *)xmlNodeGetContent(nodes->nodeTab[i]);
92811862SSean.Ye@Sun.COM 		fmd_hdl_debug(hdl, "query result: %s\n", rppath);
92911862SSean.Ye@Sun.COM 
93011862SSean.Ye@Sun.COM 		nvl = detector = NULL;
93111862SSean.Ye@Sun.COM 		if (nvlist_dup(erpt, &nvl, NV_UNIQUE_NAME) != 0 ||
93211862SSean.Ye@Sun.COM 		    nvlist_alloc(&detector, NV_UNIQUE_NAME, 0) != 0) {
93311862SSean.Ye@Sun.COM 			xmlFree(rppath);
93411862SSean.Ye@Sun.COM 			nvlist_free(nvl);
93511862SSean.Ye@Sun.COM 			continue;
93611862SSean.Ye@Sun.COM 		}
93711862SSean.Ye@Sun.COM 
93811862SSean.Ye@Sun.COM 		/*
93911862SSean.Ye@Sun.COM 		 * set the detector in the original ereport to the root port
94011862SSean.Ye@Sun.COM 		 */
94111862SSean.Ye@Sun.COM 		(void) nvlist_add_string(detector, FM_VERSION,
94211862SSean.Ye@Sun.COM 		    FM_DEV_SCHEME_VERSION);
94311862SSean.Ye@Sun.COM 		(void) nvlist_add_string(detector, FM_FMRI_SCHEME,
94411862SSean.Ye@Sun.COM 		    FM_FMRI_SCHEME_DEV);
94511862SSean.Ye@Sun.COM 		(void) nvlist_add_string(detector, FM_FMRI_DEV_PATH,
94611862SSean.Ye@Sun.COM 		    rppath);
94711862SSean.Ye@Sun.COM 		(void) nvlist_remove_all(nvl, FM_EREPORT_DETECTOR);
94811862SSean.Ye@Sun.COM 		(void) nvlist_add_nvlist(nvl, FM_EREPORT_DETECTOR,
94911862SSean.Ye@Sun.COM 		    detector);
95011862SSean.Ye@Sun.COM 		nvlist_free(detector);
95111862SSean.Ye@Sun.COM 		xmlFree(rppath);
95211862SSean.Ye@Sun.COM 
95311862SSean.Ye@Sun.COM 		fmd_hdl_debug(hdl, "Sending ereport: %s\n", fab_buf);
95411862SSean.Ye@Sun.COM 		fmd_xprt_post(hdl, fab_fmd_xprt, nvl, 0);
95511862SSean.Ye@Sun.COM 		if (fmd_xprt_error(hdl, fab_fmd_xprt))
95611862SSean.Ye@Sun.COM 			fmd_hdl_debug(hdl,
95711862SSean.Ye@Sun.COM 			    "Failed to send PCI ereport\n");
95811862SSean.Ye@Sun.COM 	}
95911862SSean.Ye@Sun.COM 
96011862SSean.Ye@Sun.COM 	xmlXPathFreeObject(xpathObj);
96111862SSean.Ye@Sun.COM }
962