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