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) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25 #include <fm/libtopo.h>
26 #include <sys/fm/util.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <sys/errno.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <pthread.h>
33
34 #include <libxml/tree.h>
35 #include <libxml/parser.h>
36 #include <libxml/xpathInternals.h>
37
38 #include "fabric-xlate.h"
39
40 #define XMLTOPOFILE "/var/run/fab-xlate-topo.xml"
41
42 fmd_xprt_t *fab_fmd_xprt; /* FMD transport layer handle */
43 char fab_buf[FM_MAX_CLASS];
44
45 /* Static FM Topo XML Format and XML XPath Context */
46 static xmlDocPtr fab_doc = NULL;
47 xmlXPathContextPtr fab_xpathCtx = NULL;
48 static int fab_valid_topo = 0;
49 static pthread_mutex_t fab_lock = PTHREAD_MUTEX_INITIALIZER;
50
51 static void
fab_update_topo(fmd_hdl_t * hdl)52 fab_update_topo(fmd_hdl_t *hdl)
53 {
54 topo_hdl_t *thp = NULL;
55 FILE *fp = NULL;
56 int err = 0;
57 int fd = -1;
58
59 /* Open the temporary file with proper ownership */
60 while (fd == -1) {
61 if ((unlink(XMLTOPOFILE) == -1) && (errno != ENOENT)) {
62 fmd_hdl_debug(hdl, "Failed to remove XML topo file\n");
63 return;
64 }
65 fd = open(XMLTOPOFILE, O_RDWR | O_CREAT | O_EXCL, 0600);
66 if ((fd == -1) && (errno != EEXIST)) {
67 fmd_hdl_debug(hdl, "Failed to create XML topo file\n");
68 return;
69 }
70 }
71
72 /* Associate a stream with the temporary file */
73 if ((fp = fdopen(fd, "w")) == NULL) {
74 fmd_hdl_debug(hdl, "Failed to open XML topo file\n");
75 goto cleanup;
76 }
77
78 /* Hold topology */
79 if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL) {
80 fmd_hdl_debug(hdl, "Failed to hold topo\n");
81 goto cleanup;
82 }
83
84 /* Print topology to XML file */
85 if (topo_xml_print(thp, fp, FM_FMRI_SCHEME_HC, &err) < 0) {
86 fmd_hdl_debug(hdl, "Failed to get XML topo\n");
87 fmd_hdl_topo_rele(hdl, thp);
88 goto cleanup;
89 }
90
91 /* Release topology */
92 fmd_hdl_topo_rele(hdl, thp);
93
94 /* Reload topology from XML file */
95 if (fab_xpathCtx)
96 xmlXPathFreeContext(fab_xpathCtx);
97 if (fab_doc)
98 xmlFreeDoc(fab_doc);
99 fab_doc = xmlParseFile(XMLTOPOFILE);
100 fab_xpathCtx = xmlXPathNewContext(fab_doc);
101 fab_set_fake_rp(hdl);
102 fab_valid_topo = 1;
103
104 cleanup:
105 if (fp != NULL)
106 (void) fclose(fp);
107 else if (fd != -1)
108 (void) close(fd);
109 (void) unlink(XMLTOPOFILE);
110 }
111
112 /*ARGSUSED*/
113 static void
fab_recv(fmd_hdl_t * hdl,fmd_event_t * ep,nvlist_t * nvl,const char * class)114 fab_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
115 {
116 nvlist_t *new_nvl;
117
118 (void) pthread_mutex_lock(&fab_lock);
119 if (!fab_valid_topo)
120 fab_update_topo(hdl);
121 (void) pthread_mutex_unlock(&fab_lock);
122
123 if (nvlist_dup(nvl, &new_nvl, NV_UNIQUE_NAME) != 0) {
124 fmd_hdl_error(hdl, "failed to duplicate event");
125 return;
126 }
127
128 if (fmd_nvl_class_match(hdl, new_nvl, "ereport.io.pci.fabric")) {
129 fab_xlate_fabric_erpts(hdl, new_nvl, class);
130 } else {
131 fab_pr(hdl, ep, new_nvl);
132 if (fmd_nvl_class_match(hdl, new_nvl,
133 "ereport.io.pciex.rc.epkt")) {
134 fab_xlate_epkt_erpts(hdl, new_nvl, class);
135 } else {
136 fab_xlate_fire_erpts(hdl, new_nvl, class);
137 }
138 }
139
140 nvlist_free(new_nvl);
141 }
142
143 /* ARGSUSED */
144 static void
fab_topo(fmd_hdl_t * hdl,topo_hdl_t * topo)145 fab_topo(fmd_hdl_t *hdl, topo_hdl_t *topo)
146 {
147 (void) pthread_mutex_lock(&fab_lock);
148 fab_valid_topo = 0;
149 (void) pthread_mutex_unlock(&fab_lock);
150 }
151
152 static const fmd_hdl_ops_t fmd_ops = {
153 fab_recv, /* fmdo_recv */
154 NULL, /* fmdo_timeout */
155 NULL, /* fmdo_close */
156 NULL, /* fmdo_stats */
157 NULL, /* fmdo_gc */
158 NULL, /* fmdo_send */
159 fab_topo, /* fmdo_topo */
160 };
161
162 static const fmd_hdl_info_t fmd_info = {
163 "Fabric Ereport Translater", "1.0", &fmd_ops, NULL
164 };
165
166 void
_fmd_init(fmd_hdl_t * hdl)167 _fmd_init(fmd_hdl_t *hdl)
168 {
169 if (fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info) != 0)
170 return;
171
172 /* Init libxml */
173 xmlInitParser();
174
175 fab_fmd_xprt = fmd_xprt_open(hdl, FMD_XPRT_RDONLY, NULL, NULL);
176 fmd_hdl_debug(hdl, "Fabric Translater Started\n");
177
178 fab_setup_master_table();
179 }
180
181 void
_fmd_fini(fmd_hdl_t * hdl)182 _fmd_fini(fmd_hdl_t *hdl)
183 {
184 /* Fini xpath */
185 if (fab_xpathCtx)
186 xmlXPathFreeContext(fab_xpathCtx);
187 /* Free xml document */
188 if (fab_doc)
189 xmlFreeDoc(fab_doc);
190 /* Fini libxml */
191 xmlCleanupParser();
192
193 fmd_xprt_close(hdl, fab_fmd_xprt);
194 }
195