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