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