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 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 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 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 * 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 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 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 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 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 * 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 * 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 * 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 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 * 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 * 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 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 * 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 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