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
fab_prep_basic_erpt(fmd_hdl_t * hdl,nvlist_t * nvl,nvlist_t * erpt,boolean_t isRC)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
fab_send_tgt_erpt(fmd_hdl_t * hdl,fab_data_t * data,const char * class,boolean_t isPrimary)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
fab_send_erpt(fmd_hdl_t * hdl,fab_data_t * data,fab_err_tbl_t * tbl)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 *
fab_xpath_query(fmd_hdl_t * hdl,const char * query)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
fab_hc2dev(fmd_hdl_t * hdl,const char * hc_path,char ** dev_path)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
fab_hc_path(fmd_hdl_t * hdl,nvlist_t * detector,char ** hcpath,size_t * lenp)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
fab_hc2dev_nvl(fmd_hdl_t * hdl,nvlist_t * detector,char ** dev_path)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
fab_get_hcpath(fmd_hdl_t * hdl,nvlist_t * nvl,char ** hcpath,size_t * len)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 *
fab_find_rppath_by_df(fmd_hdl_t * hdl,nvlist_t * nvl,uint8_t df)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 *
fab_find_rppath_by_devbdf(fmd_hdl_t * hdl,nvlist_t * nvl,pcie_req_id_t bdf)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 *
fab_find_rppath_by_devpath(fmd_hdl_t * hdl,const char * devpath)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
fab_get_rcpath(fmd_hdl_t * hdl,nvlist_t * nvl,char * rcpath)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 *
fab_find_bdf(fmd_hdl_t * hdl,nvlist_t * nvl,pcie_req_id_t bdf)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 *
fab_find_addr(fmd_hdl_t * hdl,nvlist_t * nvl,uint64_t addr)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
fab_pr(fmd_hdl_t * hdl,fmd_event_t * ep,nvlist_t * nvl)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 *
fab_get_rpdev(fmd_hdl_t * hdl)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
fab_send_erpt_all_rps(fmd_hdl_t * hdl,nvlist_t * erpt)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