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