fabric-xlate.c revision c333dd99c762d509c7eb6cce222221958e23b4c8
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <assert.h>
#include <stddef.h>
#include <strings.h>
#include <sys/nvpair_impl.h>
#include <libxml/xpathInternals.h>
/* PCI-E config space data for error handling and fabric ereports */
typedef struct fab_data {
/* Original ereport NVL */
/* Device Information */
/* Ereport Information */
/* Error Registers */
} fab_data_t;
/*
* These values are used for the xxx_tgt_trans value in fab_data_t. They are
* originally set in pcie_fault.c and originally defined in pcie_impl.h.
*/
#define PF_ADDR_DMA (1 << 0)
typedef struct fab_erpt_tbl {
const char *err_class; /* Final Ereport Class */
/* Pointer to function that prepares the ereport body */
const char *tgt_class; /* Target Ereport Class */
typedef struct fab_err_tbl {
/* Pointer to function that prepares the ereport body */
fab_erpt_tbl_t *);
typedef struct fab_fire_tbl {
const char *err_class;
/* Static FM Topo XML Format and XML XPath Context */
static int fab_valid_topo = 0;
#define XMLTOPOFILE "/tmp/fab-xlate-topo.xml"
/* Functions that convert ereports to a common C data structure */
fab_data_t *data);
/* Common functions for sending translated ereports */
/*
* Common functions for converting pci.fabric classes of
* ereports
*/
/* Functions for converting fire specific error registers */
const char *class);
const char *class);
const char *class);
const char *class);
/* Main functions for converting "fabric" ereports */
/*
* Translation tables for converting "fabric" error bits into "pci" ereports.
* <Ereport Class Name>, <Error Bit Mask>, <Preparation Function>
*/
/* MACRO for table entries with no TGT ereports */
/* Translate Fabric ereports to ereport.io.pci.* */
static fab_erpt_tbl_t fab_pci_erpt_tbl[] = {
};
/* Translate Fabric ereports to ereport.io.pci.sec-* */
static fab_erpt_tbl_t fab_pci_bdg_erpt_tbl[] = {
#ifdef sparc
#endif
};
/* Translate Fabric ereports to ereport.io.pci.dto */
static fab_erpt_tbl_t fab_pci_bdg_ctl_erpt_tbl[] = {
};
/* Translate Fabric ereports to ereport.io.pciex.* */
static fab_erpt_tbl_t fab_pcie_ce_erpt_tbl[] = {
};
/* Translate Fabric ereports to ereport.io.pciex.* */
static fab_erpt_tbl_t fab_pcie_ue_erpt_tbl[] = {
#ifdef sparc
#endif
};
/* Translate Fabric ereports to ereport.io.pciex.* */
static fab_erpt_tbl_t fab_pcie_sue_erpt_tbl[] = {
#ifdef sparc
#endif
};
/* Translate Fabric ereports to ereport.io.pcix.* */
static fab_erpt_tbl_t fab_pcix_erpt_tbl[] = {
};
/* Translate Fabric ereports to ereport.io.pcix.sec-* */
static fab_erpt_tbl_t fab_pcix_bdg_sec_erpt_tbl[] = {
};
/* Translate Fabric ereports to ereport.io.pciex.* */
static fab_erpt_tbl_t fab_pcie_nadv_erpt_tbl[] = {
#ifdef sparc
#endif
};
/* Translate Fabric ereports to ereport.io.pciex.* */
static fab_erpt_tbl_t fab_pcie_rc_erpt_tbl[] = {
};
/*
* Translate Fabric ereports to pseudo ereport.io.pciex.* RC Fabric Messages.
* If the RP is not a PCIe compliant RP or does not support AER, rely on the
* leaf fabric ereport to help create a xxx_MSG ereport coming from the RC.
*/
static fab_erpt_tbl_t fab_pcie_fake_rc_erpt_tbl[] = {
};
static fab_err_tbl_t *fab_master_err_tbl;
/*
* Translation tables for converting fire error bits into "pci" ereports.
* <Fire Bit>
* <pci ereport Class>
* <pci error status reg>
* <pci bridge status reg>
* <pci target class>
*/
static fab_fire_tbl_t fab_fire_pec_ue_tbl[] = {
};
static fab_fire_tbl_t fab_fire_pec_ce_tbl[] = {
};
/*
* need to decode the tlp log.
*/
#define FAB_FIRE_WUCRUC(fb) \
static fab_fire_tbl_t fab_fire_pec_oe_tbl[] = {
};
#define FAB_FIRE_DMC(fb) \
#define FAB_N2_DMU(fb) \
static fab_fire_tbl_t fab_fire_dmc_tbl[] = {
FAB_N2_DMU("iotsbdesc_inv"),
FAB_N2_DMU("sun4v_adj_va_uf"),
FAB_N2_DMU("sun4v_inv_pg_sz"),
FAB_N2_DMU("sun4v_key_err"),
FAB_N2_DMU("sun4v_va_oor"),
};
static char fab_buf[FM_MAX_CLASS];
/* ARGSUSED */
static void
/* Generic PCI device information */
/* Misc ereport information */
/* PCI registers */
/* PCI bridge registers */
/* PCIx registers */
/* PCIx ECC Registers */
/* PCIx ECC Bridge Registers */
/* PCIx Bridge */
/* PCIe registers */
/* PCIe AER registers */
/* PCIe BDG AER registers */
/* PCIe RP registers */
/* PCIe RP AER registers */
/*
* If the system has a PCIe complaint RP with AER, turn off translating
* fake RP ereports.
*/
if (fab_xlate_fake_rp &&
}
/* ARGSUSED */
static void
/* Always Root Complex */
}
/* ARGSUSED */
static int
char rcpath[255];
int err = 0;
/* Grab the tod, ena and detector(FMRI) */
/* Make a copy of the detector */
/* Copy the tod and ena to erpt */
/*
* Create the correct ROOT FMRI from PCIe leaf fabric ereports. Used
* only by fab_prep_fake_rc_erpt. See the fab_pciex_fake_rc_erpt_tbl
* comments for more information.
*/
if (isRC) {
/* Create the correct PCIe RC new_detector aka FMRI */
rcpath);
}
/* Copy the FMRI to erpt */
return (err);
}
static void
{
if (isPrimary) {
} else {
}
"type 0x%x addr 0x%llx fltbdf 0x%x\n",
if (!tgt_trans)
return;
if (fmri) {
int err = 0;
/* Allocate space for new erpt */
/* Generate the target ereport class */
/* Grab the tod, ena and detector(FMRI) */
/* Copy the tod and ena to erpt */
/* Create the correct FMRI */
/* Add the address payload */
} else {
tgt_addr);
}
}
static void
{
} else {
}
continue;
continue;
}
return;
}
}
}
static int
{
/* Generate an ereport for this error bit. */
return (err);
}
static int
{
/* Generate an ereport for this error bit. */
return (err);
}
static int
{
/* Generate an ereport for this error bit. */
return (err);
}
static int
{
/* Generate an ereport for this error bit. */
return (err);
}
static int
{
/* Generate an ereport for this error bit. */
} else {
}
}
return (err);
}
static int
{
/* Generate an ereport for this error bit. */
} else {
}
}
return (err);
}
static int
{
int err = 0;
/* Only send if this is not a bridge */
return (1);
/* Generate an ereport for this error bit. */
return (err);
}
static void
{
switch (ecc_phase) {
case PCI_PCIX_ECC_PHASE_NOERR:
break;
case PCI_PCIX_ECC_PHASE_FADDR:
case PCI_PCIX_ECC_PHASE_SADDR:
"%s.%s", PCIX_ERROR_SUBCLASS,
break;
case PCI_PCIX_ECC_PHASE_ATTR:
"%s.%s", PCIX_ERROR_SUBCLASS,
break;
"%s.%s", PCIX_ERROR_SUBCLASS,
break;
}
if (ecc_phase) {
data->pcix_command);
}
"%s.%s", PCIX_ERROR_SUBCLASS,
data->pcix_command);
}
}
static int
{
/* Generate an ereport for this error bit. */
return (err);
}
static int
{
/* Generate an ereport for this error bit. */
return (err);
}
static void
{
switch (ecc_phase) {
case PCI_PCIX_ECC_PHASE_NOERR:
break;
case PCI_PCIX_ECC_PHASE_FADDR:
case PCI_PCIX_ECC_PHASE_SADDR:
break;
case PCI_PCIX_ECC_PHASE_ATTR:
break;
break;
}
if (ecc_phase) {
}
}
}
static int
{
int err = 0;
/* Don't send this for PCI device, Root Ports, or PCIe with AER */
return (1);
/* Generate an ereport for this error bit. */
return (err);
}
static int
{
int err = 0;
return (-1);
/* Only send a FE Msg if the 1st UE error is FE */
if (!(status & PCIE_AER_RE_STS_FIRST_UC_FATAL))
return (-1);
else
isFE = 1;
/* Only send a NFE Msg is the 1st UE error is NFE */
return (-1);
else
isNFE = 1;
/* Generate an ereport for this error bit. */
}
}
return (err);
}
static int
{
uint32_t rc_err_sts = 0;
int err = 0;
/*
* Don't send this for PCI device or Root Ports. Only send it on
* systems with non-compliant RPs.
*/
return (-1);
/* Generate an ereport for this error bit. */
/* Send PCIe RC Ereports */
}
}
}
}
if (!(rc_err_sts & PCIE_AER_RE_STS_MUL_FE_NFE_RCVD)) {
}
return (err);
}
static int
const char *class)
{
goto send;
}
return (0);
send:
/* Fill in the device status register */
/* Fill in the AER CE register */
}
return (1);
}
static int
const char *class)
{
goto send;
}
return (0);
send:
/* Fill in PCI Status Register */
/* Fill in the device status register */
else
/* Fill in the AER UE register */
}
/* Fill in the AER Control register */
data->pcie_adv_ctl++)
}
/* If CTO create target information */
}
}
case PCIE_TLP_TYPE_IO:
case PCIE_TLP_TYPE_MEM:
case PCIE_TLP_TYPE_MEMLK:
} else {
}
break;
case PCIE_TLP_TYPE_CFG0:
case PCIE_TLP_TYPE_CFG1:
break;
}
}
/* Fill in the AER Header registers */
}
}
return (1);
}
static int
const char *class)
{
goto send;
}
return (0);
send:
/* Fill in PCI Status Register */
} else {
}
}
case PCIE_CPL_STS_UR:
data->pci_err_status = 0;
break;
case PCIE_CPL_STS_CA:
data->pci_err_status = 0;
break;
}
}
}
/* Fill in the device status register */
else
/* Fill in the AER UE register */
return (1);
}
static int
const char *class)
{
goto send;
}
return (0);
send:
/* Fill in PCI Status Register */
/* Fill in the device status register */
/* Fill in the AER UE register */
/* Fill in the AER Control register */
/* Fill in the AER Header registers */
/* Get the trans type */
/* Get the req id */
}
/* Get the address */
}
return (1);
}
static void
{
/* Go through the error logs and send the relavant reports */
}
/* Send PCI-X ECC Ereports */
}
static void
const char *class)
{
return;
return;
return;
return;
}
}
static void
{
int err = 0;
}
}
/* Load xml document */
/* Init xpath */
fab_valid_topo = 1;
}
/* ARGSUSED */
static void
char *path;
int i;
(rcpath[i] != '\0'); i++);
rcpath[i] = '\0';
}
static char *
char query[500];
char rcpath[255];
}
/*
* Explanation of the XSL XPATH Query
* Line 1: Look at all nodes with the node name "propval"
* Line 2-3: See if the "value" of the node ends with correct PCIEx BDF
* Line 4-5: See if the "value" of the node ends with correct PCI BDF
* Line 6: Go up one level to the parent of the current node
* Line 7: See if child node contains "ASRU" with the same PCIe Root
* Line 8: Traverse up the parent and the other siblings and look for
* the io "propgroup" and get the value of the dev "propval"
*/
"contains(substring(@value, string-length(@value) - 34), "
"contains(substring(@value, string-length(@value) - 28), "
"]/parent::"
"*/propval[@name='ASRU' and contains(@value, '%s')]"
"/parent::*/following-sibling::*[@name='io']/propval[@name='dev']/"
if (nodes) {
}
return (NULL);
}
static char *
char query[500];
int size, i, j;
char *token;
char rcpath[255];
"@name='ASRU' and contains(@value, '%s')]/"
"parent::*/following-sibling::*[@name='pci']/"
"propval[@name='assigned-addresses']", rcpath);
/* Decode the list of assigned addresses xml nodes for each device */
for (i = 0; i < size; i++) {
continue;
/* Convert "string" assigned-addresses to pci_regspec_t */
j = 0;
}
/* Check if address belongs to this device */
goto found;
}
}
}
return (NULL);
/* Traverse up the xml tree and back down to find the right propgroup */
goto propgroup;
}
return (NULL);
/* Retrive the "dev" propval and return */
}
}
return (NULL);
}
static void
boolean_t b;
char *str;
int arri;
continue; /* already printed by caller */
switch (type) {
case DATA_TYPE_BOOLEAN:
break;
case DATA_TYPE_BOOLEAN_VALUE:
(void) nvpair_value_boolean_value(nvp, &b);
b ? "1" : "0");
break;
case DATA_TYPE_BYTE:
break;
case DATA_TYPE_INT8:
break;
case DATA_TYPE_UINT8:
break;
case DATA_TYPE_INT16:
break;
case DATA_TYPE_UINT16:
break;
case DATA_TYPE_INT32:
break;
case DATA_TYPE_UINT32:
break;
case DATA_TYPE_INT64:
(u_longlong_t)i64);
break;
case DATA_TYPE_UINT64:
(u_longlong_t)i64);
break;
case DATA_TYPE_HRTIME:
(u_longlong_t)i64);
break;
case DATA_TYPE_STRING:
break;
case DATA_TYPE_NVLIST:
break;
case DATA_TYPE_BOOLEAN_ARRAY:
case DATA_TYPE_BYTE_ARRAY:
case DATA_TYPE_INT8_ARRAY:
case DATA_TYPE_UINT8_ARRAY:
case DATA_TYPE_INT16_ARRAY:
case DATA_TYPE_UINT16_ARRAY:
case DATA_TYPE_INT32_ARRAY:
case DATA_TYPE_UINT32_ARRAY:
case DATA_TYPE_INT64_ARRAY:
case DATA_TYPE_UINT64_ARRAY:
case DATA_TYPE_STRING_ARRAY:
break;
case DATA_TYPE_NVLIST_ARRAY:
arrsize = 0;
&arrsize);
}
break;
case DATA_TYPE_UNKNOWN:
break;
}
}
}
/*ARGSUSED*/
static void
{
fab_data_t fab_data = {0};
if (!fab_valid_topo)
} else {
}
}
/* ARGSUSED */
static void
{
fab_valid_topo = 0;
}
static const fmd_hdl_ops_t fmd_ops = {
fab_recv, /* fmdo_recv */
NULL, /* fmdo_timeout */
NULL, /* fmdo_close */
NULL, /* fmdo_stats */
NULL, /* fmdo_gc */
NULL, /* fmdo_send */
fab_topo, /* fmdo_topo */
};
static const fmd_hdl_info_t fmd_info = {
};
void
{
return;
/* Init libxml */
/* Setup the master error table */
sizeof (fab_err_tbl_t));
}
void
{
/* Fini xpath */
if (fab_xpathCtx)
/* Free xml document */
if (fab_doc)
/* Fini libxml */
}