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