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