xref: /illumos-gate/usr/src/cmd/fm/modules/common/fabric-xlate/fx_subr.c (revision fb2a9bae0030340ad72b9c26ba1ffee2ee3cafec)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 #include <strings.h>
27 #include <fm/topo_hc.h>
28 #include <sys/fm/util.h>
29 #include <libxml/xpath.h>
30 #include <libxml/parser.h>
31 #include <libxml/xpathInternals.h>
32 #include <libxml/tree.h>
33 
34 #include "fabric-xlate.h"
35 
36 #define	HAS_PROP(node, name) xmlHasProp(node, (const xmlChar *)name)
37 #define	GET_PROP(node, name) ((char *)xmlGetProp(node, (const xmlChar *)name))
38 #define	FREE_PROP(prop) xmlFree((xmlChar *)prop)
39 
40 extern xmlXPathContextPtr fab_xpathCtx;
41 
42 /* ARGSUSED */
43 int
44 fab_prep_basic_erpt(fmd_hdl_t *hdl, nvlist_t *nvl, nvlist_t *erpt,
45     boolean_t isRC)
46 {
47 	uint64_t	*now;
48 	uint64_t	ena;
49 	uint_t		nelem;
50 	nvlist_t	*detector, *new_detector;
51 	char		rcpath[255];
52 	int		err = 0;
53 
54 	/* Grab the tod, ena and detector(FMRI) */
55 	err |= nvlist_lookup_uint64_array(nvl, "__tod", &now, &nelem);
56 	err |= nvlist_lookup_uint64(nvl, "ena", &ena);
57 	err |= nvlist_lookup_nvlist(nvl, FM_EREPORT_DETECTOR, &detector);
58 	if (err)
59 		return (err);
60 
61 	/* Make a copy of the detector */
62 	err = nvlist_dup(detector, &new_detector, NV_UNIQUE_NAME);
63 	if (err)
64 		return (err);
65 
66 	/* Copy the tod and ena to erpt */
67 	(void) nvlist_add_uint64(erpt, FM_EREPORT_ENA, ena);
68 	(void) nvlist_add_uint64_array(erpt, "__tod", now, nelem);
69 
70 	/*
71 	 * Create the correct ROOT FMRI from PCIe leaf fabric ereports.	 Used
72 	 * only by fab_prep_fake_rc_erpt.  See the fab_pciex_fake_rc_erpt_tbl
73 	 * comments for more information.
74 	 */
75 	if (isRC && fab_get_rcpath(hdl, nvl, rcpath)) {
76 		/* Create the correct PCIe RC new_detector aka FMRI */
77 		(void) nvlist_remove(new_detector, FM_FMRI_DEV_PATH,
78 		    DATA_TYPE_STRING);
79 		(void) nvlist_add_string(new_detector, FM_FMRI_DEV_PATH,
80 		    rcpath);
81 	}
82 
83 	/* Copy the FMRI to erpt */
84 	(void) nvlist_add_nvlist(erpt, FM_EREPORT_DETECTOR, new_detector);
85 
86 	nvlist_free(new_detector);
87 	return (err);
88 }
89 
90 void
91 fab_send_tgt_erpt(fmd_hdl_t *hdl, fab_data_t *data, const char *class,
92     boolean_t isPrimary)
93 {
94 	nvlist_t	*nvl = data->nvl;
95 	nvlist_t	*erpt;
96 	char		*fmri = NULL;
97 	uint32_t	tgt_trans;
98 	uint64_t	tgt_addr;
99 	uint16_t	tgt_bdf;
100 
101 	if (isPrimary) {
102 		tgt_trans = data->pcie_ue_tgt_trans;
103 		tgt_addr = data->pcie_ue_tgt_addr;
104 		tgt_bdf = data->pcie_ue_tgt_bdf;
105 	} else {
106 		tgt_trans = data->pcie_sue_tgt_trans;
107 		tgt_addr = data->pcie_sue_tgt_addr;
108 		tgt_bdf = data->pcie_sue_tgt_bdf;
109 	}
110 
111 	fmd_hdl_debug(hdl, "Sending Target Ereport: "
112 	    "type 0x%x addr 0x%llx fltbdf 0x%x\n",
113 	    tgt_trans, tgt_addr, tgt_bdf);
114 
115 	if (!tgt_trans)
116 		return;
117 
118 	if ((tgt_trans == PF_ADDR_PIO) && tgt_addr)
119 		fmri = fab_find_addr(hdl, nvl, tgt_addr);
120 	else if ((tgt_trans == PF_ADDR_CFG || (tgt_trans == PF_ADDR_DMA)) &&
121 	    tgt_bdf)
122 		fmri = fab_find_bdf(hdl, nvl, tgt_bdf);
123 
124 	if (fmri) {
125 		uint64_t	*now;
126 		uint64_t	ena;
127 		uint_t		nelem;
128 		nvlist_t	*detector;
129 		int		err = 0;
130 
131 		/* Allocate space for new erpt */
132 		if (nvlist_alloc(&erpt, NV_UNIQUE_NAME, 0) != 0)
133 			goto done;
134 
135 		/* Generate the target ereport class */
136 		(void) snprintf(fab_buf, FM_MAX_CLASS, "ereport.io.%s.%s",
137 		    PCI_ERROR_SUBCLASS, class);
138 		(void) nvlist_add_string(erpt, FM_CLASS, fab_buf);
139 
140 		/* Grab the tod, ena and detector(FMRI) */
141 		err |= nvlist_lookup_uint64_array(nvl, "__tod", &now, &nelem);
142 		err |= nvlist_lookup_uint64(nvl, "ena", &ena);
143 
144 		/* Copy the tod and ena to erpt */
145 		(void) nvlist_add_uint64(erpt, FM_EREPORT_ENA, ena);
146 		(void) nvlist_add_uint64_array(erpt, "__tod", now, nelem);
147 
148 		/* Create the correct FMRI */
149 		if (nvlist_alloc(&detector, NV_UNIQUE_NAME, 0) != 0) {
150 			nvlist_free(erpt);
151 			goto done;
152 		}
153 		(void) nvlist_add_uint8(detector, FM_VERSION,
154 		    FM_DEV_SCHEME_VERSION);
155 		(void) nvlist_add_string(detector, FM_FMRI_SCHEME,
156 		    FM_FMRI_SCHEME_DEV);
157 		(void) nvlist_add_string(detector, FM_FMRI_DEV_PATH, fmri);
158 		(void) nvlist_add_nvlist(erpt, FM_EREPORT_DETECTOR, detector);
159 		nvlist_free(detector);
160 
161 		/* Add the address payload */
162 		(void) nvlist_add_uint64(erpt, PCI_PA, tgt_addr);
163 
164 		fmd_hdl_debug(hdl, "Sending target ereport: %s 0x%x\n",
165 		    fab_buf, tgt_addr);
166 		fmd_xprt_post(hdl, fab_fmd_xprt, erpt, 0);
167 		if (fmd_xprt_error(hdl, fab_fmd_xprt))
168 			goto done;
169 		fmd_hdl_strfree(hdl, fmri);
170 	} else {
171 		fmd_hdl_debug(hdl,
172 		    "Cannot find Target FMRI addr:0x%llx bdf 0x%x\n",
173 		    tgt_addr, tgt_bdf);
174 	}
175 
176 	return;
177 done:
178 	if (fmri)
179 		xmlFree(fmri);
180 	fmd_hdl_debug(hdl, "Failed to send Target PCI ereport\n");
181 }
182 
183 void
184 fab_send_erpt(fmd_hdl_t *hdl, fab_data_t *data, fab_err_tbl_t *tbl)
185 {
186 	fab_erpt_tbl_t	*erpt_tbl, *entry;
187 	nvlist_t	*erpt;
188 	uint32_t	reg;
189 
190 	erpt_tbl = tbl->erpt_tbl;
191 	if (tbl->reg_size == 16) {
192 		reg = (uint32_t)*((uint16_t *)
193 		    ((uint32_t)data + tbl->reg_offset));
194 	} else {
195 		reg = *((uint32_t *)((uint32_t)data + tbl->reg_offset));
196 	}
197 
198 	for (entry = erpt_tbl; entry->err_class; entry++) {
199 		if (!(reg & entry->reg_bit))
200 			continue;
201 
202 		if (nvlist_alloc(&erpt, NV_UNIQUE_NAME, 0) != 0)
203 			goto done;
204 		if (tbl->fab_prep(hdl, data, erpt, entry) != 0) {
205 			fmd_hdl_debug(hdl, "Prepping ereport failed: "
206 			    "class = %s\n", entry->err_class);
207 			nvlist_free(erpt);
208 			continue;
209 		}
210 
211 		if (data->pcie_rp_send_all) {
212 			fab_send_erpt_all_rps(hdl, erpt);
213 			nvlist_free(erpt);
214 			return;
215 		}
216 
217 		fmd_hdl_debug(hdl, "Sending ereport: %s 0x%x\n", fab_buf, reg);
218 		fmd_xprt_post(hdl, fab_fmd_xprt, erpt, 0);
219 		if (fmd_xprt_error(hdl, fab_fmd_xprt)) {
220 			fmd_hdl_debug(hdl, "Failed to send PCI ereport\n");
221 			return;
222 		}
223 	}
224 
225 	return;
226 done:
227 	fmd_hdl_debug(hdl, "Failed  to send PCI ereport\n");
228 }
229 
230 char *
231 fab_xpath_query(fmd_hdl_t *hdl, const char *query)
232 {
233 	xmlXPathObjectPtr xpathObj;
234 	xmlNodeSetPtr nodes;
235 	char *temp, *res;
236 
237 	fmd_hdl_debug(hdl, "xpathObj query %s\n", query);
238 
239 	xpathObj = xmlXPathEvalExpression((const xmlChar *)query,
240 	    fab_xpathCtx);
241 
242 	if (xpathObj == NULL)
243 		return (NULL);
244 
245 	fmd_hdl_debug(hdl, "xpathObj 0x%p type %d\n", xpathObj,
246 	    xpathObj->type);
247 	nodes = xpathObj->nodesetval;
248 
249 	if (nodes) {
250 		temp = (char *)xmlNodeGetContent(nodes->nodeTab[0]);
251 		fmd_hdl_debug(hdl, "query result: %s\n", temp);
252 		res = fmd_hdl_strdup(hdl, temp, FMD_SLEEP);
253 		xmlFree(temp);
254 		xmlXPathFreeObject(xpathObj);
255 		return (res);
256 	}
257 	xmlXPathFreeObject(xpathObj);
258 	return (NULL);
259 }
260 
261 #define	FAB_HC2DEV_QUERY_SIZE_MIN 160
262 #define	FAB_HC2DEV_QUERY_SIZE(sz) \
263 	((sz + FAB_HC2DEV_QUERY_SIZE_MIN) * sizeof (char))
264 
265 /*
266  * hc_path is in form of "/motherboard=0/hostbridge=0/pciexrc=0"
267  */
268 boolean_t
269 fab_hc2dev(fmd_hdl_t *hdl, const char *hc_path, char **dev_path)
270 {
271 	char *query;
272 	uint_t len = FAB_HC2DEV_QUERY_SIZE_MIN + strlen(hc_path);
273 
274 	query = fmd_hdl_alloc(hdl, len, FMD_SLEEP);
275 	(void) snprintf(query, len, "//propval[@name='resource' and contains("
276 	    "substring(@value, string-length(@value) - %d + 1), '%s')]"
277 	    "/parent::*/following-sibling::*/propval[@name='dev']/@value",
278 	    strlen(hc_path) + 1, hc_path);
279 
280 	*dev_path = fab_xpath_query(hdl, query);
281 
282 	fmd_hdl_free(hdl, query, len);
283 
284 	return (*dev_path != NULL);
285 }
286 
287 static boolean_t
288 fab_hc_path(fmd_hdl_t *hdl, nvlist_t *detector, char **hcpath, size_t *lenp)
289 {
290 	char c, *name, *id, *buf;
291 	uint_t i, size;
292 	nvlist_t **hcl;
293 	size_t len = 0, buf_size = 0;
294 
295 	if (nvlist_lookup_nvlist_array(detector, FM_FMRI_HC_LIST, &hcl,
296 	    &size) != 0)
297 		return (B_FALSE);
298 
299 	for (i = 0; i < size; i++) {
300 		if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &name) != 0)
301 			return (B_FALSE);
302 		if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &id) != 0)
303 			return (B_FALSE);
304 		buf_size += snprintf(&c, 1, "/%s=%s", name, id);
305 	}
306 
307 	buf_size++;
308 	buf = fmd_hdl_alloc(hdl, buf_size, FMD_SLEEP);
309 
310 	for (i = 0; i < size; i++) {
311 		(void) nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &name);
312 		(void) nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &id);
313 		len += snprintf(buf + len, buf_size - len, "/%s=%s", name, id);
314 	}
315 
316 	*hcpath = buf;
317 	*lenp = buf_size;
318 
319 	return (B_TRUE);
320 }
321 
322 boolean_t
323 fab_hc2dev_nvl(fmd_hdl_t *hdl, nvlist_t *detector, char **dev_path)
324 {
325 	char *hcl;
326 	size_t len;
327 
328 	if (! fab_hc_path(hdl, detector, &hcl, &len))
329 		return (B_FALSE);
330 
331 	(void) fab_hc2dev(hdl, hcl, dev_path);
332 
333 	fmd_hdl_free(hdl, hcl, len);
334 
335 	return (*dev_path != NULL);
336 }
337 
338 boolean_t
339 fab_get_hcpath(fmd_hdl_t *hdl, nvlist_t *nvl, char **hcpath, size_t *len)
340 {
341 	nvlist_t *detector;
342 	char *scheme;
343 
344 	if (nvlist_lookup_nvlist(nvl, FM_EREPORT_DETECTOR, &detector) != 0 ||
345 	    nvlist_lookup_string(detector, FM_FMRI_SCHEME, &scheme) != 0 ||
346 	    ! STRCMP(scheme, FM_FMRI_SCHEME_HC))
347 		return (B_FALSE);
348 
349 	return (fab_hc_path(hdl, detector, hcpath, len));
350 }
351 
352 char *
353 fab_find_rppath_by_df(fmd_hdl_t *hdl, nvlist_t *nvl, uint8_t df)
354 {
355 	char	query[500];
356 	char	str[10];
357 	char	*hcpath;
358 	size_t	len;
359 
360 	(void) snprintf(str, sizeof (str), "%0hhx", df);
361 
362 	/*
363 	 * get the string form of the hc detector, eg
364 	 * /chassis=0/motherboard=0/hostbridge=0
365 	 */
366 	if (!fab_get_hcpath(hdl, nvl, &hcpath, &len))
367 		return (NULL);
368 
369 	/*
370 	 * Explanation of the XSL XPATH Query
371 	 * Line 1: Look at all nodes with the node name "propval"
372 	 * Line 2: See if the "BDF" of the node matches DF
373 	 * Line 3-4: See if the the node is pciexrc
374 	 * Line 5-6: See if the "ASRU" contains root complex
375 	 * Line 7-8: Go up one level and get prop value of io/dev
376 	 */
377 	(void) snprintf(query, sizeof (query), "//propval["
378 	    "@name='BDF' and contains(substring(@value, "
379 	    "string-length(@value) - 1), '%s')]"
380 	    "/parent::*/parent::*/propgroup[@name='pci']/propval"
381 	    "[@name='extended-capabilities' and @value='%s']"
382 	    "/parent::*/parent::*/propgroup[@name='protocol']"
383 	    "/propval[@name='resource' and contains(@value, '%s')]"
384 	    "/parent::*/parent::*/propgroup[@name='io']"
385 	    "/propval[@name='dev']/@value", str, PCIEX_ROOT, hcpath);
386 
387 	fmd_hdl_free(hdl, hcpath, len);
388 
389 	return (fab_xpath_query(hdl, query));
390 }
391 
392 char *
393 fab_find_rppath_by_devbdf(fmd_hdl_t *hdl, nvlist_t *nvl, pcie_req_id_t bdf)
394 {
395 	xmlXPathObjectPtr xpathObj;
396 	xmlNodeSetPtr nodes;
397 	xmlNodePtr devNode;
398 	char 	*retval, *temp;
399 	char	query[500];
400 	int	i, size, bus, dev, fn;
401 	char	*hcpath;
402 	size_t	len;
403 
404 	if (bdf != (uint16_t)-1) {
405 		bus = (bdf & PCIE_REQ_ID_BUS_MASK) >> PCIE_REQ_ID_BUS_SHIFT;
406 		dev = (bdf & PCIE_REQ_ID_DEV_MASK) >> PCIE_REQ_ID_DEV_SHIFT;
407 		fn = (bdf & PCIE_REQ_ID_FUNC_MASK) >> PCIE_REQ_ID_FUNC_SHIFT;
408 	}
409 
410 	/*
411 	 * get the string form of the hc detector, eg
412 	 * /chassis=0/motherboard=0/hostbridge=0
413 	 */
414 	if (!fab_get_hcpath(hdl, nvl, &hcpath, &len))
415 		goto fail;
416 
417 	/*
418 	 * Explanation of the XSL XPATH Query
419 	 * Line 1: Look at all nodes with the node name "propval"
420 	 * Line 2-3: See if the "value" of the node ends with correct PCIEx BDF
421 	 * Line 4-5: See if the "value" of the node ends with correct PCI BDF
422 	 * Line 6: Go up one level to the parent of the current node
423 	 * Line 7: See if child node contains "ASRU" with the same PCIe Root
424 	 * Line 8: Go up see all the ancestors
425 	 */
426 	(void) snprintf(query, sizeof (query), "//propval["
427 	    "contains(substring(@value, string-length(@value) - 34), "
428 	    "'pciexbus=%d/pciexdev=%d/pciexfn=%d') or "
429 	    "contains(substring(@value, string-length(@value) - 28), "
430 	    "'pcibus=%d/pcidev=%d/pcifn=%d')"
431 	    "]/parent::"
432 	    "*/propval[@name='resource' and contains(@value, '%s')]"
433 	    "/ancestor::*",
434 	    bus, dev, fn, bus, dev, fn, hcpath);
435 
436 	fmd_hdl_free(hdl, hcpath, len);
437 
438 	fmd_hdl_debug(hdl, "xpathObj query %s\n", query);
439 
440 	xpathObj = xmlXPathEvalExpression((const xmlChar *)query, fab_xpathCtx);
441 
442 	if (xpathObj == NULL)
443 		goto fail;
444 
445 	nodes = xpathObj->nodesetval;
446 	size = (nodes) ? nodes->nodeNr : 0;
447 
448 	fmd_hdl_debug(hdl, "xpathObj 0x%p type %d size %d\n",
449 	    xpathObj, xpathObj->type, size);
450 
451 	for (i = 0; i < size; i++) {
452 		devNode = nodes->nodeTab[i];
453 		if (STRCMP(devNode->name, "range") &&
454 		    HAS_PROP(devNode, "name")) {
455 			char *tprop = GET_PROP(devNode, "name");
456 
457 			/* find "range name='pciexrc'" in ancestors */
458 			if (STRCMP(tprop, PCIEX_ROOT)) {
459 				/* go down to the pciexrc instance node */
460 				FREE_PROP(tprop);
461 				devNode = nodes->nodeTab[i+1];
462 				goto found;
463 			}
464 			FREE_PROP(tprop);
465 		}
466 	}
467 	goto fail;
468 
469 found:
470 	/* Traverse down the xml tree to find the right propgroup */
471 	for (devNode = devNode->children; devNode; devNode = devNode->next) {
472 		if (STRCMP(devNode->name, "propgroup")) {
473 			char *tprop = GET_PROP(devNode, "name");
474 
475 			if (STRCMP(tprop, "io")) {
476 				FREE_PROP(tprop);
477 				goto propgroup;
478 			}
479 			FREE_PROP(tprop);
480 		}
481 	}
482 	goto fail;
483 
484 propgroup:
485 	/* Retrive the "dev" propval and return */
486 	for (devNode = devNode->children; devNode; devNode = devNode->next) {
487 		if (STRCMP(devNode->name, "propval")) {
488 			char *tprop = GET_PROP(devNode, "name");
489 
490 			if (STRCMP(tprop, "dev")) {
491 				temp = GET_PROP(devNode, "value");
492 				retval = fmd_hdl_strdup(hdl, temp, FMD_SLEEP);
493 				fmd_hdl_debug(hdl, "RP Path: %s\n", retval);
494 				xmlFree(temp);
495 				xmlXPathFreeObject(xpathObj);
496 			}
497 			FREE_PROP(tprop);
498 
499 			return (retval);
500 		}
501 	}
502 fail:
503 	if (xpathObj != NULL)
504 		xmlXPathFreeObject(xpathObj);
505 	return (NULL);
506 }
507 
508 /* ARGSUSED */
509 boolean_t
510 fab_get_rcpath(fmd_hdl_t *hdl, nvlist_t *nvl, char *rcpath)
511 {
512 	nvlist_t	*detector;
513 	char		*path, *scheme;
514 
515 	if (nvlist_lookup_nvlist(nvl, FM_EREPORT_DETECTOR, &detector) != 0)
516 		goto fail;
517 	if (nvlist_lookup_string(detector, FM_FMRI_SCHEME, &scheme) != 0)
518 		goto fail;
519 
520 	if (STRCMP(scheme, FM_FMRI_SCHEME_DEV)) {
521 		if (nvlist_lookup_string(detector, FM_FMRI_DEV_PATH,
522 		    &path) != 0)
523 			goto fail;
524 		(void) strncpy(rcpath, path, FM_MAX_CLASS);
525 	} else if (STRCMP(scheme, FM_FMRI_SCHEME_HC)) {
526 		/*
527 		 * This should only occur for ereports that come from the RC
528 		 * itself.  In this case convert HC scheme to dev path.
529 		 */
530 		if (fab_hc2dev_nvl(hdl, detector, &path)) {
531 			(void) strncpy(rcpath, path, FM_MAX_CLASS);
532 			fmd_hdl_strfree(hdl, path);
533 		} else {
534 			goto fail;
535 		}
536 	} else {
537 		return (B_FALSE);
538 	}
539 
540 	/*
541 	 * Extract the RC path by taking the first device in the dev path
542 	 *
543 	 * /pci@0,0/pci8086,3605@2/pci8086,3500@0/pci8086,3514@1/pci8086,105e@0
544 	 * - to -
545 	 * /pci@0,0
546 	 */
547 	path = strchr(rcpath + 1, '/');
548 	if (path)
549 		path[0] = '\0';
550 
551 	return (B_TRUE);
552 fail:
553 	return (B_FALSE);
554 }
555 
556 char *
557 fab_find_bdf(fmd_hdl_t *hdl, nvlist_t *nvl, pcie_req_id_t bdf)
558 {
559 	char 	*retval;
560 	char	query[500];
561 	int	bus, dev, fn;
562 	char	rcpath[255];
563 
564 	if (bdf != (uint16_t)-1) {
565 		bus = (bdf & PCIE_REQ_ID_BUS_MASK) >> PCIE_REQ_ID_BUS_SHIFT;
566 		dev = (bdf & PCIE_REQ_ID_DEV_MASK) >> PCIE_REQ_ID_DEV_SHIFT;
567 		fn = (bdf & PCIE_REQ_ID_FUNC_MASK) >> PCIE_REQ_ID_FUNC_SHIFT;
568 	}
569 
570 	if (!fab_get_rcpath(hdl, nvl, rcpath))
571 		goto fail;
572 
573 	/*
574 	 * Explanation of the XSL XPATH Query
575 	 * Line 1: Look at all nodes with the node name "propval"
576 	 * Line 2-3: See if the "value" of the node ends with correct PCIEx BDF
577 	 * Line 4-5: See if the "value" of the node ends with correct PCI BDF
578 	 * Line 6: Go up one level to the parent of the current node
579 	 * Line 7: See if child node contains "ASRU" with the same PCIe Root
580 	 * Line 8: Traverse up the parent and the other siblings and look for
581 	 *	   the io "propgroup" and get the value of the dev "propval"
582 	 */
583 	(void) snprintf(query, sizeof (query), "//propval["
584 	    "contains(substring(@value, string-length(@value) - 34), "
585 	    "'pciexbus=%d/pciexdev=%d/pciexfn=%d') or "
586 	    "contains(substring(@value, string-length(@value) - 28), "
587 	    "'pcibus=%d/pcidev=%d/pcifn=%d')"
588 	    "]/parent::"
589 	    "*/propval[@name='ASRU' and contains(@value, '%s')]"
590 	    "/parent::*/following-sibling::*[@name='io']/propval[@name='dev']/"
591 	    "@value", bus, dev, fn, bus, dev, fn, rcpath);
592 
593 	retval = fab_xpath_query(hdl, query);
594 	if (retval) {
595 		fmd_hdl_debug(hdl, "BDF Dev Path: %s\n", retval);
596 		return (retval);
597 	}
598 fail:
599 	return (NULL);
600 }
601 
602 char *
603 fab_find_addr(fmd_hdl_t *hdl, nvlist_t *nvl, uint64_t addr)
604 {
605 	xmlXPathObjectPtr xpathObj;
606 	xmlNodeSetPtr nodes;
607 	xmlNodePtr devNode;
608 	char *retval, *temp;
609 	char query[500];
610 	int size, i, j;
611 	uint32_t prop[50];
612 	char *token;
613 	pci_regspec_t *assign_p;
614 	uint64_t low, hi;
615 	char rcpath[255];
616 
617 	if (!fab_get_rcpath(hdl, nvl, rcpath))
618 		goto fail;
619 
620 	(void) snprintf(query, sizeof (query), "//propval["
621 	    "@name='ASRU' and contains(@value, '%s')]/"
622 	    "parent::*/following-sibling::*[@name='pci']/"
623 	    "propval[@name='assigned-addresses']", rcpath);
624 
625 	fmd_hdl_debug(hdl, "xpathObj query %s\n", query);
626 
627 	xpathObj = xmlXPathEvalExpression((const xmlChar *)query, fab_xpathCtx);
628 
629 	if (xpathObj == NULL)
630 		goto fail;
631 
632 	fmd_hdl_debug(hdl, "xpathObj 0x%p type %d\n", xpathObj, xpathObj->type);
633 
634 	nodes = xpathObj->nodesetval;
635 	size = (nodes) ? nodes->nodeNr : 0;
636 
637 	/* Decode the list of assigned addresses xml nodes for each device */
638 	for (i = 0; i < size; i++) {
639 		char *tprop;
640 
641 		devNode = nodes->nodeTab[i];
642 		if (!HAS_PROP(devNode, "value"))
643 			continue;
644 
645 		/* Convert "string" assigned-addresses to pci_regspec_t */
646 		j = 0;
647 		tprop = GET_PROP(devNode, "value");
648 		for (token = strtok(tprop, " "); token;
649 		    token = strtok(NULL, " ")) {
650 			prop[j++] = strtoul(token, (char **)NULL, 16);
651 		}
652 		prop[j] = (uint32_t)-1;
653 		FREE_PROP(tprop);
654 
655 		/* Check if address belongs to this device */
656 		for (assign_p = (pci_regspec_t *)prop;
657 		    assign_p->pci_phys_hi != (uint_t)-1; assign_p++) {
658 			low = assign_p->pci_phys_low;
659 			hi = low + assign_p->pci_size_low;
660 			if ((addr < hi) && (addr >= low)) {
661 				fmd_hdl_debug(hdl, "Found Address\n");
662 				goto found;
663 			}
664 		}
665 	}
666 	goto fail;
667 
668 found:
669 	/* Traverse up the xml tree and back down to find the right propgroup */
670 	for (devNode = devNode->parent->parent->children;
671 	    devNode; devNode = devNode->next) {
672 		char	*tprop;
673 
674 		tprop = GET_PROP(devNode, "name");
675 		if (STRCMP(devNode->name, "propgroup") &&
676 		    STRCMP(tprop, "io")) {
677 			FREE_PROP(tprop);
678 			goto propgroup;
679 		}
680 		FREE_PROP(tprop);
681 	}
682 	goto fail;
683 
684 propgroup:
685 	/* Retrive the "dev" propval and return */
686 	for (devNode = devNode->children; devNode; devNode = devNode->next) {
687 		char 	*tprop;
688 
689 		tprop = GET_PROP(devNode, "name");
690 		if (STRCMP(devNode->name, "propval") &&
691 		    STRCMP(tprop, "dev")) {
692 			FREE_PROP(tprop);
693 			temp = GET_PROP(devNode, "value");
694 			retval = fmd_hdl_strdup(hdl, temp, FMD_SLEEP);
695 			fmd_hdl_debug(hdl, "Addr Dev Path: %s\n", retval);
696 			xmlFree(temp);
697 			xmlXPathFreeObject(xpathObj);
698 			return (retval);
699 		}
700 		FREE_PROP(tprop);
701 	}
702 fail:
703 	if (xpathObj != NULL)
704 		xmlXPathFreeObject(xpathObj);
705 	return (NULL);
706 }
707 
708 void
709 fab_pr(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl)
710 {
711 	nvpair_t *nvp;
712 
713 	for (nvp = nvlist_next_nvpair(nvl, NULL);
714 	    nvp != NULL;
715 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
716 
717 		data_type_t type = nvpair_type(nvp);
718 		const char *name = nvpair_name(nvp);
719 
720 		boolean_t b;
721 		uint8_t i8;
722 		uint16_t i16;
723 		uint32_t i32;
724 		uint64_t i64;
725 		char *str;
726 		nvlist_t *cnv;
727 
728 		nvlist_t **nvlarr;
729 		uint_t arrsize;
730 		int arri;
731 
732 
733 		if (STRCMP(name, FM_CLASS))
734 			continue; /* already printed by caller */
735 
736 		fmd_hdl_debug(hdl, " %s=", name);
737 
738 		switch (type) {
739 		case DATA_TYPE_BOOLEAN:
740 			fmd_hdl_debug(hdl, "DATA_TYPE_BOOLEAN 1");
741 			break;
742 
743 		case DATA_TYPE_BOOLEAN_VALUE:
744 			(void) nvpair_value_boolean_value(nvp, &b);
745 			fmd_hdl_debug(hdl, "DATA_TYPE_BOOLEAN_VALUE %d",
746 			    b ? "1" : "0");
747 			break;
748 
749 		case DATA_TYPE_BYTE:
750 			(void) nvpair_value_byte(nvp, &i8);
751 			fmd_hdl_debug(hdl, "DATA_TYPE_BYTE 0x%x", i8);
752 			break;
753 
754 		case DATA_TYPE_INT8:
755 			(void) nvpair_value_int8(nvp, (void *)&i8);
756 			fmd_hdl_debug(hdl, "DATA_TYPE_INT8 0x%x", i8);
757 			break;
758 
759 		case DATA_TYPE_UINT8:
760 			(void) nvpair_value_uint8(nvp, &i8);
761 			fmd_hdl_debug(hdl, "DATA_TYPE_UINT8 0x%x", i8);
762 			break;
763 
764 		case DATA_TYPE_INT16:
765 			(void) nvpair_value_int16(nvp, (void *)&i16);
766 			fmd_hdl_debug(hdl, "DATA_TYPE_INT16 0x%x", i16);
767 			break;
768 
769 		case DATA_TYPE_UINT16:
770 			(void) nvpair_value_uint16(nvp, &i16);
771 			fmd_hdl_debug(hdl, "DATA_TYPE_UINT16 0x%x", i16);
772 			break;
773 
774 		case DATA_TYPE_INT32:
775 			(void) nvpair_value_int32(nvp, (void *)&i32);
776 			fmd_hdl_debug(hdl, "DATA_TYPE_INT32 0x%x", i32);
777 			break;
778 
779 		case DATA_TYPE_UINT32:
780 			(void) nvpair_value_uint32(nvp, &i32);
781 			fmd_hdl_debug(hdl, "DATA_TYPE_UINT32 0x%x", i32);
782 			break;
783 
784 		case DATA_TYPE_INT64:
785 			(void) nvpair_value_int64(nvp, (void *)&i64);
786 			fmd_hdl_debug(hdl, "DATA_TYPE_INT64 0x%llx",
787 			    (u_longlong_t)i64);
788 			break;
789 
790 		case DATA_TYPE_UINT64:
791 			(void) nvpair_value_uint64(nvp, &i64);
792 			fmd_hdl_debug(hdl, "DATA_TYPE_UINT64 0x%llx",
793 			    (u_longlong_t)i64);
794 			break;
795 
796 		case DATA_TYPE_HRTIME:
797 			(void) nvpair_value_hrtime(nvp, (void *)&i64);
798 			fmd_hdl_debug(hdl, "DATA_TYPE_HRTIME 0x%llx",
799 			    (u_longlong_t)i64);
800 			break;
801 
802 		case DATA_TYPE_STRING:
803 			(void) nvpair_value_string(nvp, &str);
804 			fmd_hdl_debug(hdl, "DATA_TYPE_STRING \"%s\"",
805 			    str ? str : "<NULL>");
806 			break;
807 
808 		case DATA_TYPE_NVLIST:
809 			fmd_hdl_debug(hdl, "[");
810 			(void) nvpair_value_nvlist(nvp, &cnv);
811 			fab_pr(hdl, NULL, cnv);
812 			fmd_hdl_debug(hdl, " ]");
813 			break;
814 
815 		case DATA_TYPE_BOOLEAN_ARRAY:
816 		case DATA_TYPE_BYTE_ARRAY:
817 		case DATA_TYPE_INT8_ARRAY:
818 		case DATA_TYPE_UINT8_ARRAY:
819 		case DATA_TYPE_INT16_ARRAY:
820 		case DATA_TYPE_UINT16_ARRAY:
821 		case DATA_TYPE_INT32_ARRAY:
822 		case DATA_TYPE_UINT32_ARRAY:
823 		case DATA_TYPE_INT64_ARRAY:
824 		case DATA_TYPE_UINT64_ARRAY:
825 		case DATA_TYPE_STRING_ARRAY:
826 			fmd_hdl_debug(hdl, "[...]");
827 			break;
828 		case DATA_TYPE_NVLIST_ARRAY:
829 			arrsize = 0;
830 			(void) nvpair_value_nvlist_array(nvp, &nvlarr,
831 			    &arrsize);
832 
833 			for (arri = 0; arri < arrsize; arri++) {
834 				fab_pr(hdl, ep, nvlarr[arri]);
835 			}
836 
837 			break;
838 		case DATA_TYPE_UNKNOWN:
839 			fmd_hdl_debug(hdl, "<unknown>");
840 			break;
841 		}
842 	}
843 }
844 
845 char *
846 fab_get_rpdev(fmd_hdl_t *hdl)
847 {
848 	char 	*retval;
849 	char 	query[500];
850 
851 	(void) snprintf(query, sizeof (query), "//propval["
852 	    "@name='extended-capabilities' and contains(@value, '%s')]"
853 	    "/parent::*/parent::*/propgroup[@name='io']"
854 	    "/propval[@name='dev']/@value", PCIEX_ROOT);
855 
856 	retval = fab_xpath_query(hdl, query);
857 	if (retval) {
858 		fmd_hdl_debug(hdl, "Root port path is %s\n", retval);
859 		return (retval);
860 	}
861 
862 	return (NULL);
863 }
864 
865 void
866 fab_send_erpt_all_rps(fmd_hdl_t *hdl, nvlist_t *erpt)
867 {
868 	xmlXPathObjectPtr xpathObj;
869 	xmlNodeSetPtr nodes;
870 	char 	*rppath, *hbpath;
871 	char 	query[600];
872 	nvlist_t *detector, *nvl;
873 	uint_t	i, size;
874 	size_t len;
875 
876 	/* get hostbridge's path */
877 	if (!fab_get_hcpath(hdl, erpt, &hbpath, &len)) {
878 		fmd_hdl_debug(hdl,
879 		    "fab_send_erpt_on_all_rps: fab_get_hcpath() failed.\n");
880 		return;
881 	}
882 
883 	(void) snprintf(query, sizeof (query), "//propval["
884 	    "@name='extended-capabilities' and contains(@value, '%s')]"
885 	    "/parent::*/parent::*/propgroup[@name='protocol']"
886 	    "/propval[@name='resource' and contains(@value, '%s/')"
887 	    "]/parent::*/parent::*/propgroup[@name='io']"
888 	    "/propval[@name='dev']/@value", PCIEX_ROOT, hbpath);
889 
890 	fmd_hdl_free(hdl, hbpath, len);
891 
892 	fmd_hdl_debug(hdl, "xpathObj query %s\n", query);
893 
894 	xpathObj = xmlXPathEvalExpression((const xmlChar *)query, fab_xpathCtx);
895 
896 	if (xpathObj == NULL)
897 		return;
898 
899 	nodes = xpathObj->nodesetval;
900 	size = (nodes) ? nodes->nodeNr : 0;
901 
902 	fmd_hdl_debug(hdl, "xpathObj 0x%p type %d size %d\n",
903 	    xpathObj, xpathObj->type, size);
904 
905 	for (i = 0; i < size; i++) {
906 		rppath = (char *)xmlNodeGetContent(nodes->nodeTab[i]);
907 		fmd_hdl_debug(hdl, "query result: %s\n", rppath);
908 
909 		nvl = detector = NULL;
910 		if (nvlist_dup(erpt, &nvl, NV_UNIQUE_NAME) != 0 ||
911 		    nvlist_alloc(&detector, NV_UNIQUE_NAME, 0) != 0) {
912 			xmlFree(rppath);
913 			nvlist_free(nvl);
914 			continue;
915 		}
916 
917 		/*
918 		 * set the detector in the original ereport to the root port
919 		 */
920 		(void) nvlist_add_string(detector, FM_VERSION,
921 		    FM_DEV_SCHEME_VERSION);
922 		(void) nvlist_add_string(detector, FM_FMRI_SCHEME,
923 		    FM_FMRI_SCHEME_DEV);
924 		(void) nvlist_add_string(detector, FM_FMRI_DEV_PATH,
925 		    rppath);
926 		(void) nvlist_remove_all(nvl, FM_EREPORT_DETECTOR);
927 		(void) nvlist_add_nvlist(nvl, FM_EREPORT_DETECTOR,
928 		    detector);
929 		nvlist_free(detector);
930 		xmlFree(rppath);
931 
932 		fmd_hdl_debug(hdl, "Sending ereport: %s\n", fab_buf);
933 		fmd_xprt_post(hdl, fab_fmd_xprt, nvl, 0);
934 		if (fmd_xprt_error(hdl, fab_fmd_xprt))
935 			fmd_hdl_debug(hdl,
936 			    "Failed to send PCI ereport\n");
937 	}
938 
939 	xmlXPathFreeObject(xpathObj);
940 }
941