xref: /illumos-gate/usr/src/cmd/fm/modules/common/fabric-xlate/fx_subr.c (revision 8fd04b8338ed5093ec2d1e668fa620b7de44c177)
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 		fmd_hdl_debug(hdl, "Sending ereport: %s 0x%x\n", fab_buf, reg);
212 		fmd_xprt_post(hdl, fab_fmd_xprt, erpt, 0);
213 		if (fmd_xprt_error(hdl, fab_fmd_xprt)) {
214 			fmd_hdl_debug(hdl, "Failed to send PCI ereport\n");
215 			return;
216 		}
217 	}
218 
219 	return;
220 done:
221 	fmd_hdl_debug(hdl, "Failed  to send PCI ereport\n");
222 }
223 
224 char *
225 fab_xpath_query(fmd_hdl_t *hdl, const char *query)
226 {
227 	xmlXPathObjectPtr xpathObj;
228 	xmlNodeSetPtr nodes;
229 	char *temp, *res;
230 
231 	fmd_hdl_debug(hdl, "xpathObj query %s\n", query);
232 
233 	xpathObj = xmlXPathEvalExpression((const xmlChar *)query,
234 	    fab_xpathCtx);
235 
236 	if (xpathObj == NULL)
237 		return (NULL);
238 
239 	fmd_hdl_debug(hdl, "xpathObj 0x%p type %d\n", xpathObj,
240 	    xpathObj->type);
241 	nodes = xpathObj->nodesetval;
242 
243 	if (nodes) {
244 		temp = (char *)xmlNodeGetContent(nodes->nodeTab[0]);
245 		fmd_hdl_debug(hdl, "query result: %s\n", temp);
246 		res = fmd_hdl_strdup(hdl, temp, FMD_SLEEP);
247 		xmlFree(temp);
248 		xmlXPathFreeObject(xpathObj);
249 		return (res);
250 	}
251 	xmlXPathFreeObject(xpathObj);
252 	return (NULL);
253 }
254 
255 #define	FAB_HC2DEV_QUERY_SIZE_MIN 160
256 #define	FAB_HC2DEV_QUERY_SIZE(sz) \
257 	((sz + FAB_HC2DEV_QUERY_SIZE_MIN) * sizeof (char))
258 
259 /*
260  * hc_path is in form of "/motherboard=0/hostbridge=0/pciexrc=0"
261  */
262 boolean_t
263 fab_hc2dev(fmd_hdl_t *hdl, const char *hc_path, char **dev_path)
264 {
265 	char *query;
266 	uint_t len = FAB_HC2DEV_QUERY_SIZE_MIN + strlen(hc_path);
267 
268 	query = fmd_hdl_alloc(hdl, len, FMD_SLEEP);
269 	(void) snprintf(query, len, "//propval[@name='resource' and contains("
270 	    "substring(@value, string-length(@value) - %d + 1), '%s')]"
271 	    "/parent::*/following-sibling::*/propval[@name='dev']/@value",
272 	    strlen(hc_path) + 1, hc_path);
273 
274 	*dev_path = fab_xpath_query(hdl, query);
275 
276 	fmd_hdl_free(hdl, query, len);
277 
278 	return (*dev_path != NULL);
279 }
280 
281 static boolean_t
282 fab_hc_path(fmd_hdl_t *hdl, nvlist_t *detector, char **hcpath, size_t *lenp)
283 {
284 	char c, *name, *id, *buf;
285 	uint_t i, size;
286 	nvlist_t **hcl;
287 	size_t len = 0, buf_size = 0;
288 
289 	if (nvlist_lookup_nvlist_array(detector, FM_FMRI_HC_LIST, &hcl,
290 	    &size) != 0)
291 		return (B_FALSE);
292 
293 	for (i = 0; i < size; i++) {
294 		if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &name) != 0)
295 			return (B_FALSE);
296 		if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &id) != 0)
297 			return (B_FALSE);
298 		buf_size += snprintf(&c, 1, "/%s=%s", name, id);
299 	}
300 
301 	buf_size++;
302 	buf = fmd_hdl_alloc(hdl, buf_size, FMD_SLEEP);
303 
304 	for (i = 0; i < size; i++) {
305 		(void) nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &name);
306 		(void) nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &id);
307 		len += snprintf(buf + len, buf_size - len, "/%s=%s", name, id);
308 	}
309 
310 	*hcpath = buf;
311 	*lenp = buf_size;
312 
313 	return (B_TRUE);
314 }
315 
316 boolean_t
317 fab_hc2dev_nvl(fmd_hdl_t *hdl, nvlist_t *detector, char **dev_path)
318 {
319 	char *hcl;
320 	size_t len;
321 
322 	if (! fab_hc_path(hdl, detector, &hcl, &len))
323 		return (B_FALSE);
324 
325 	(void) fab_hc2dev(hdl, hcl, dev_path);
326 
327 	fmd_hdl_free(hdl, hcl, len);
328 
329 	return (*dev_path != NULL);
330 }
331 
332 boolean_t
333 fab_get_hcpath(fmd_hdl_t *hdl, nvlist_t *nvl, char **hcpath, size_t *len)
334 {
335 	nvlist_t *detector;
336 	char *scheme;
337 
338 	if (nvlist_lookup_nvlist(nvl, FM_EREPORT_DETECTOR, &detector) != 0 ||
339 	    nvlist_lookup_string(detector, FM_FMRI_SCHEME, &scheme) != 0 ||
340 	    ! STRCMP(scheme, FM_FMRI_SCHEME_HC))
341 		return (B_FALSE);
342 
343 	return (fab_hc_path(hdl, detector, hcpath, len));
344 }
345 
346 char *
347 fab_find_rppath_by_df(fmd_hdl_t *hdl, nvlist_t *nvl, uint8_t df)
348 {
349 	char	query[500];
350 	char	str[10];
351 	char	*hcpath;
352 	size_t	len;
353 
354 	(void) snprintf(str, sizeof (str), "%0hhx", df);
355 
356 	/*
357 	 * get the string form of the hc detector, eg
358 	 * /chassis=0/motherboard=0/hostbridge=0
359 	 */
360 	if (!fab_get_hcpath(hdl, nvl, &hcpath, &len))
361 		return (NULL);
362 
363 	/*
364 	 * Explanation of the XSL XPATH Query
365 	 * Line 1: Look at all nodes with the node name "propval"
366 	 * Line 2: See if the "BDF" of the node matches DF
367 	 * Line 3-4: See if the the node is pciexrc
368 	 * Line 5-6: See if the "ASRU" contains root complex
369 	 * Line 7-8: Go up one level and get prop value of io/dev
370 	 */
371 	(void) snprintf(query, sizeof (query), "//propval["
372 	    "@name='BDF' and contains(substring(@value, "
373 	    "string-length(@value) - 1), '%s')]"
374 	    "/parent::*/parent::*/propgroup[@name='pci']/propval"
375 	    "[@name='extended-capabilities' and @value='%s']"
376 	    "/parent::*/parent::*/propgroup[@name='protocol']"
377 	    "/propval[@name='resource' and contains(@value, '%s')]"
378 	    "/parent::*/parent::*/propgroup[@name='io']"
379 	    "/propval[@name='dev']/@value", str, PCIEX_ROOT, hcpath);
380 
381 	fmd_hdl_free(hdl, hcpath, len);
382 
383 	return (fab_xpath_query(hdl, query));
384 }
385 
386 char *
387 fab_find_rppath_by_devbdf(fmd_hdl_t *hdl, nvlist_t *nvl, pcie_req_id_t bdf)
388 {
389 	xmlXPathObjectPtr xpathObj;
390 	xmlNodeSetPtr nodes;
391 	xmlNodePtr devNode;
392 	char 	*retval, *temp;
393 	char	query[500];
394 	int	i, size, bus, dev, fn;
395 	char	*hcpath;
396 	size_t	len;
397 
398 	if (bdf != (uint16_t)-1) {
399 		bus = (bdf & PCIE_REQ_ID_BUS_MASK) >> PCIE_REQ_ID_BUS_SHIFT;
400 		dev = (bdf & PCIE_REQ_ID_DEV_MASK) >> PCIE_REQ_ID_DEV_SHIFT;
401 		fn = (bdf & PCIE_REQ_ID_FUNC_MASK) >> PCIE_REQ_ID_FUNC_SHIFT;
402 	}
403 
404 	/*
405 	 * get the string form of the hc detector, eg
406 	 * /chassis=0/motherboard=0/hostbridge=0
407 	 */
408 	if (!fab_get_hcpath(hdl, nvl, &hcpath, &len))
409 		goto fail;
410 
411 	/*
412 	 * Explanation of the XSL XPATH Query
413 	 * Line 1: Look at all nodes with the node name "propval"
414 	 * Line 2-3: See if the "value" of the node ends with correct PCIEx BDF
415 	 * Line 4-5: See if the "value" of the node ends with correct PCI BDF
416 	 * Line 6: Go up one level to the parent of the current node
417 	 * Line 7: See if child node contains "ASRU" with the same PCIe Root
418 	 * Line 8: Go up see all the ancestors
419 	 */
420 	(void) snprintf(query, sizeof (query), "//propval["
421 	    "contains(substring(@value, string-length(@value) - 34), "
422 	    "'pciexbus=%d/pciexdev=%d/pciexfn=%d') or "
423 	    "contains(substring(@value, string-length(@value) - 28), "
424 	    "'pcibus=%d/pcidev=%d/pcifn=%d')"
425 	    "]/parent::"
426 	    "*/propval[@name='resource' and contains(@value, '%s')]"
427 	    "/ancestor::*",
428 	    bus, dev, fn, bus, dev, fn, hcpath);
429 
430 	fmd_hdl_free(hdl, hcpath, len);
431 
432 	fmd_hdl_debug(hdl, "xpathObj query %s\n", query);
433 
434 	xpathObj = xmlXPathEvalExpression((const xmlChar *)query, fab_xpathCtx);
435 
436 	if (xpathObj == NULL)
437 		goto fail;
438 
439 	nodes = xpathObj->nodesetval;
440 	size = (nodes) ? nodes->nodeNr : 0;
441 
442 	fmd_hdl_debug(hdl, "xpathObj 0x%p type %d size %d\n",
443 	    xpathObj, xpathObj->type, size);
444 
445 	for (i = 0; i < size; i++) {
446 		devNode = nodes->nodeTab[i];
447 		if (STRCMP(devNode->name, "range") &&
448 		    HAS_PROP(devNode, "name")) {
449 			char *tprop = GET_PROP(devNode, "name");
450 
451 			/* find "range name='pciexrc'" in ancestors */
452 			if (STRCMP(tprop, PCIEX_ROOT)) {
453 				/* go down to the pciexrc instance node */
454 				FREE_PROP(tprop);
455 				devNode = nodes->nodeTab[i+1];
456 				goto found;
457 			}
458 			FREE_PROP(tprop);
459 		}
460 	}
461 	goto fail;
462 
463 found:
464 	/* Traverse down the xml tree to find the right propgroup */
465 	for (devNode = devNode->children; devNode; devNode = devNode->next) {
466 		if (STRCMP(devNode->name, "propgroup")) {
467 			char *tprop = GET_PROP(devNode, "name");
468 
469 			if (STRCMP(tprop, "io")) {
470 				FREE_PROP(tprop);
471 				goto propgroup;
472 			}
473 			FREE_PROP(tprop);
474 		}
475 	}
476 	goto fail;
477 
478 propgroup:
479 	/* Retrive the "dev" propval and return */
480 	for (devNode = devNode->children; devNode; devNode = devNode->next) {
481 		if (STRCMP(devNode->name, "propval")) {
482 			char *tprop = GET_PROP(devNode, "name");
483 
484 			if (STRCMP(tprop, "dev")) {
485 				temp = GET_PROP(devNode, "value");
486 				retval = fmd_hdl_strdup(hdl, temp, FMD_SLEEP);
487 				fmd_hdl_debug(hdl, "RP Path: %s\n", retval);
488 				xmlFree(temp);
489 				xmlXPathFreeObject(xpathObj);
490 			}
491 			FREE_PROP(tprop);
492 
493 			return (retval);
494 		}
495 	}
496 fail:
497 	if (xpathObj != NULL)
498 		xmlXPathFreeObject(xpathObj);
499 	return (NULL);
500 }
501 
502 /* ARGSUSED */
503 boolean_t
504 fab_get_rcpath(fmd_hdl_t *hdl, nvlist_t *nvl, char *rcpath)
505 {
506 	nvlist_t	*detector;
507 	char		*path, *scheme;
508 
509 	if (nvlist_lookup_nvlist(nvl, FM_EREPORT_DETECTOR, &detector) != 0)
510 		goto fail;
511 	if (nvlist_lookup_string(detector, FM_FMRI_SCHEME, &scheme) != 0)
512 		goto fail;
513 
514 	if (STRCMP(scheme, FM_FMRI_SCHEME_DEV)) {
515 		if (nvlist_lookup_string(detector, FM_FMRI_DEV_PATH,
516 		    &path) != 0)
517 			goto fail;
518 		(void) strncpy(rcpath, path, FM_MAX_CLASS);
519 	} else if (STRCMP(scheme, FM_FMRI_SCHEME_HC)) {
520 		/*
521 		 * This should only occur for ereports that come from the RC
522 		 * itself.  In this case convert HC scheme to dev path.
523 		 */
524 		if (fab_hc2dev_nvl(hdl, detector, &path)) {
525 			(void) strncpy(rcpath, path, FM_MAX_CLASS);
526 			fmd_hdl_strfree(hdl, path);
527 		} else {
528 			goto fail;
529 		}
530 	} else {
531 		return (B_FALSE);
532 	}
533 
534 	/*
535 	 * Extract the RC path by taking the first device in the dev path
536 	 *
537 	 * /pci@0,0/pci8086,3605@2/pci8086,3500@0/pci8086,3514@1/pci8086,105e@0
538 	 * - to -
539 	 * /pci@0,0
540 	 */
541 	path = strchr(rcpath + 1, '/');
542 	if (path)
543 		path[0] = '\0';
544 
545 	return (B_TRUE);
546 fail:
547 	return (B_FALSE);
548 }
549 
550 char *
551 fab_find_bdf(fmd_hdl_t *hdl, nvlist_t *nvl, pcie_req_id_t bdf)
552 {
553 	char 	*retval;
554 	char	query[500];
555 	int	bus, dev, fn;
556 	char	rcpath[255];
557 
558 	if (bdf != (uint16_t)-1) {
559 		bus = (bdf & PCIE_REQ_ID_BUS_MASK) >> PCIE_REQ_ID_BUS_SHIFT;
560 		dev = (bdf & PCIE_REQ_ID_DEV_MASK) >> PCIE_REQ_ID_DEV_SHIFT;
561 		fn = (bdf & PCIE_REQ_ID_FUNC_MASK) >> PCIE_REQ_ID_FUNC_SHIFT;
562 	}
563 
564 	if (!fab_get_rcpath(hdl, nvl, rcpath))
565 		goto fail;
566 
567 	/*
568 	 * Explanation of the XSL XPATH Query
569 	 * Line 1: Look at all nodes with the node name "propval"
570 	 * Line 2-3: See if the "value" of the node ends with correct PCIEx BDF
571 	 * Line 4-5: See if the "value" of the node ends with correct PCI BDF
572 	 * Line 6: Go up one level to the parent of the current node
573 	 * Line 7: See if child node contains "ASRU" with the same PCIe Root
574 	 * Line 8: Traverse up the parent and the other siblings and look for
575 	 *	   the io "propgroup" and get the value of the dev "propval"
576 	 */
577 	(void) snprintf(query, sizeof (query), "//propval["
578 	    "contains(substring(@value, string-length(@value) - 34), "
579 	    "'pciexbus=%d/pciexdev=%d/pciexfn=%d') or "
580 	    "contains(substring(@value, string-length(@value) - 28), "
581 	    "'pcibus=%d/pcidev=%d/pcifn=%d')"
582 	    "]/parent::"
583 	    "*/propval[@name='ASRU' and contains(@value, '%s')]"
584 	    "/parent::*/following-sibling::*[@name='io']/propval[@name='dev']/"
585 	    "@value", bus, dev, fn, bus, dev, fn, rcpath);
586 
587 	retval = fab_xpath_query(hdl, query);
588 	if (retval) {
589 		fmd_hdl_debug(hdl, "BDF Dev Path: %s\n", retval);
590 		return (retval);
591 	}
592 fail:
593 	return (NULL);
594 }
595 
596 char *
597 fab_find_addr(fmd_hdl_t *hdl, nvlist_t *nvl, uint64_t addr)
598 {
599 	xmlXPathObjectPtr xpathObj;
600 	xmlNodeSetPtr nodes;
601 	xmlNodePtr devNode;
602 	char *retval, *temp;
603 	char query[500];
604 	int size, i, j;
605 	uint32_t prop[50];
606 	char *token;
607 	pci_regspec_t *assign_p;
608 	uint64_t low, hi;
609 	char rcpath[255];
610 
611 	if (!fab_get_rcpath(hdl, nvl, rcpath))
612 		goto fail;
613 
614 	(void) snprintf(query, sizeof (query), "//propval["
615 	    "@name='ASRU' and contains(@value, '%s')]/"
616 	    "parent::*/following-sibling::*[@name='pci']/"
617 	    "propval[@name='assigned-addresses']", rcpath);
618 
619 	fmd_hdl_debug(hdl, "xpathObj query %s\n", query);
620 
621 	xpathObj = xmlXPathEvalExpression((const xmlChar *)query, fab_xpathCtx);
622 
623 	if (xpathObj == NULL)
624 		goto fail;
625 
626 	fmd_hdl_debug(hdl, "xpathObj 0x%p type %d\n", xpathObj, xpathObj->type);
627 
628 	nodes = xpathObj->nodesetval;
629 	size = (nodes) ? nodes->nodeNr : 0;
630 
631 	/* Decode the list of assigned addresses xml nodes for each device */
632 	for (i = 0; i < size; i++) {
633 		char *tprop;
634 
635 		devNode = nodes->nodeTab[i];
636 		if (!HAS_PROP(devNode, "value"))
637 			continue;
638 
639 		/* Convert "string" assigned-addresses to pci_regspec_t */
640 		j = 0;
641 		tprop = GET_PROP(devNode, "value");
642 		for (token = strtok(tprop, " "); token;
643 		    token = strtok(NULL, " ")) {
644 			prop[j++] = strtoul(token, (char **)NULL, 16);
645 		}
646 		prop[j] = (uint32_t)-1;
647 		FREE_PROP(tprop);
648 
649 		/* Check if address belongs to this device */
650 		for (assign_p = (pci_regspec_t *)prop;
651 		    assign_p->pci_phys_hi != (uint_t)-1; assign_p++) {
652 			low = assign_p->pci_phys_low;
653 			hi = low + assign_p->pci_size_low;
654 			if ((addr < hi) && (addr >= low)) {
655 				fmd_hdl_debug(hdl, "Found Address\n");
656 				goto found;
657 			}
658 		}
659 	}
660 	goto fail;
661 
662 found:
663 	/* Traverse up the xml tree and back down to find the right propgroup */
664 	for (devNode = devNode->parent->parent->children;
665 	    devNode; devNode = devNode->next) {
666 		char	*tprop;
667 
668 		tprop = GET_PROP(devNode, "name");
669 		if (STRCMP(devNode->name, "propgroup") &&
670 		    STRCMP(tprop, "io")) {
671 			FREE_PROP(tprop);
672 			goto propgroup;
673 		}
674 		FREE_PROP(tprop);
675 	}
676 	goto fail;
677 
678 propgroup:
679 	/* Retrive the "dev" propval and return */
680 	for (devNode = devNode->children; devNode; devNode = devNode->next) {
681 		char 	*tprop;
682 
683 		tprop = GET_PROP(devNode, "name");
684 		if (STRCMP(devNode->name, "propval") &&
685 		    STRCMP(tprop, "dev")) {
686 			FREE_PROP(tprop);
687 			temp = GET_PROP(devNode, "value");
688 			retval = fmd_hdl_strdup(hdl, temp, FMD_SLEEP);
689 			fmd_hdl_debug(hdl, "Addr Dev Path: %s\n", retval);
690 			xmlFree(temp);
691 			xmlXPathFreeObject(xpathObj);
692 			return (retval);
693 		}
694 		FREE_PROP(tprop);
695 	}
696 fail:
697 	if (xpathObj != NULL)
698 		xmlXPathFreeObject(xpathObj);
699 	return (NULL);
700 }
701 
702 void
703 fab_pr(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl)
704 {
705 	nvpair_t *nvp;
706 
707 	for (nvp = nvlist_next_nvpair(nvl, NULL);
708 	    nvp != NULL;
709 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
710 
711 		data_type_t type = nvpair_type(nvp);
712 		const char *name = nvpair_name(nvp);
713 
714 		boolean_t b;
715 		uint8_t i8;
716 		uint16_t i16;
717 		uint32_t i32;
718 		uint64_t i64;
719 		char *str;
720 		nvlist_t *cnv;
721 
722 		nvlist_t **nvlarr;
723 		uint_t arrsize;
724 		int arri;
725 
726 
727 		if (STRCMP(name, FM_CLASS))
728 			continue; /* already printed by caller */
729 
730 		fmd_hdl_debug(hdl, " %s=", name);
731 
732 		switch (type) {
733 		case DATA_TYPE_BOOLEAN:
734 			fmd_hdl_debug(hdl, "DATA_TYPE_BOOLEAN 1");
735 			break;
736 
737 		case DATA_TYPE_BOOLEAN_VALUE:
738 			(void) nvpair_value_boolean_value(nvp, &b);
739 			fmd_hdl_debug(hdl, "DATA_TYPE_BOOLEAN_VALUE %d",
740 			    b ? "1" : "0");
741 			break;
742 
743 		case DATA_TYPE_BYTE:
744 			(void) nvpair_value_byte(nvp, &i8);
745 			fmd_hdl_debug(hdl, "DATA_TYPE_BYTE 0x%x", i8);
746 			break;
747 
748 		case DATA_TYPE_INT8:
749 			(void) nvpair_value_int8(nvp, (void *)&i8);
750 			fmd_hdl_debug(hdl, "DATA_TYPE_INT8 0x%x", i8);
751 			break;
752 
753 		case DATA_TYPE_UINT8:
754 			(void) nvpair_value_uint8(nvp, &i8);
755 			fmd_hdl_debug(hdl, "DATA_TYPE_UINT8 0x%x", i8);
756 			break;
757 
758 		case DATA_TYPE_INT16:
759 			(void) nvpair_value_int16(nvp, (void *)&i16);
760 			fmd_hdl_debug(hdl, "DATA_TYPE_INT16 0x%x", i16);
761 			break;
762 
763 		case DATA_TYPE_UINT16:
764 			(void) nvpair_value_uint16(nvp, &i16);
765 			fmd_hdl_debug(hdl, "DATA_TYPE_UINT16 0x%x", i16);
766 			break;
767 
768 		case DATA_TYPE_INT32:
769 			(void) nvpair_value_int32(nvp, (void *)&i32);
770 			fmd_hdl_debug(hdl, "DATA_TYPE_INT32 0x%x", i32);
771 			break;
772 
773 		case DATA_TYPE_UINT32:
774 			(void) nvpair_value_uint32(nvp, &i32);
775 			fmd_hdl_debug(hdl, "DATA_TYPE_UINT32 0x%x", i32);
776 			break;
777 
778 		case DATA_TYPE_INT64:
779 			(void) nvpair_value_int64(nvp, (void *)&i64);
780 			fmd_hdl_debug(hdl, "DATA_TYPE_INT64 0x%llx",
781 			    (u_longlong_t)i64);
782 			break;
783 
784 		case DATA_TYPE_UINT64:
785 			(void) nvpair_value_uint64(nvp, &i64);
786 			fmd_hdl_debug(hdl, "DATA_TYPE_UINT64 0x%llx",
787 			    (u_longlong_t)i64);
788 			break;
789 
790 		case DATA_TYPE_HRTIME:
791 			(void) nvpair_value_hrtime(nvp, (void *)&i64);
792 			fmd_hdl_debug(hdl, "DATA_TYPE_HRTIME 0x%llx",
793 			    (u_longlong_t)i64);
794 			break;
795 
796 		case DATA_TYPE_STRING:
797 			(void) nvpair_value_string(nvp, &str);
798 			fmd_hdl_debug(hdl, "DATA_TYPE_STRING \"%s\"",
799 			    str ? str : "<NULL>");
800 			break;
801 
802 		case DATA_TYPE_NVLIST:
803 			fmd_hdl_debug(hdl, "[");
804 			(void) nvpair_value_nvlist(nvp, &cnv);
805 			fab_pr(hdl, NULL, cnv);
806 			fmd_hdl_debug(hdl, " ]");
807 			break;
808 
809 		case DATA_TYPE_BOOLEAN_ARRAY:
810 		case DATA_TYPE_BYTE_ARRAY:
811 		case DATA_TYPE_INT8_ARRAY:
812 		case DATA_TYPE_UINT8_ARRAY:
813 		case DATA_TYPE_INT16_ARRAY:
814 		case DATA_TYPE_UINT16_ARRAY:
815 		case DATA_TYPE_INT32_ARRAY:
816 		case DATA_TYPE_UINT32_ARRAY:
817 		case DATA_TYPE_INT64_ARRAY:
818 		case DATA_TYPE_UINT64_ARRAY:
819 		case DATA_TYPE_STRING_ARRAY:
820 			fmd_hdl_debug(hdl, "[...]");
821 			break;
822 		case DATA_TYPE_NVLIST_ARRAY:
823 			arrsize = 0;
824 			(void) nvpair_value_nvlist_array(nvp, &nvlarr,
825 			    &arrsize);
826 
827 			for (arri = 0; arri < arrsize; arri++) {
828 				fab_pr(hdl, ep, nvlarr[arri]);
829 			}
830 
831 			break;
832 		case DATA_TYPE_UNKNOWN:
833 			fmd_hdl_debug(hdl, "<unknown>");
834 			break;
835 		}
836 	}
837 }
838 
839 char *
840 fab_get_rpdev(fmd_hdl_t *hdl)
841 {
842 	char 	*retval;
843 	char 	query[500];
844 
845 	(void) snprintf(query, sizeof (query), "//propval["
846 	    "@name='extended-capabilities' and contains(@value, '%s')]"
847 	    "/parent::*/parent::*/propgroup[@name='io']"
848 	    "/propval[@name='dev']/@value", PCIEX_ROOT);
849 
850 	retval = fab_xpath_query(hdl, query);
851 	if (retval) {
852 		fmd_hdl_debug(hdl, "Root port path is %s\n", retval);
853 		return (retval);
854 	}
855 
856 	return (NULL);
857 }
858