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