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