Print this page
patch tsoome-feedback
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/fm/libfmd_agent/common/fmd_agent.c
+++ new/usr/src/lib/fm/libfmd_agent/common/fmd_agent.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 /*
28 28 * libfmd_agent contains the low-level operations that needed by the fmd
29 29 * agents, such as page operations (status/retire/unretire), cpu operations
30 30 * (status/online/offline), etc.
31 31 *
32 32 * Some operations are implemented by /dev/fm ioctls. Those ioctls are
33 33 * heavily versioned to allow userland patching without requiring a reboot
34 34 * to get a matched /dev/fm. All the ioctls use packed nvlist to interact
35 35 * between userland and kernel. (see fmd_agent_nvl_ioctl()).
36 36 */
37 37
38 38 #include <fcntl.h>
39 39 #include <errno.h>
40 40 #include <unistd.h>
41 41 #include <strings.h>
42 42 #include <libnvpair.h>
43 43 #include <string.h>
44 44 #include <sys/types.h>
45 45 #include <sys/devfm.h>
46 46 #include <fmd_agent_impl.h>
47 47
48 48 int
49 49 fmd_agent_errno(fmd_agent_hdl_t *hdl)
50 50 {
51 51 return (hdl->agent_errno);
52 52 }
53 53
54 54 int
55 55 fmd_agent_seterrno(fmd_agent_hdl_t *hdl, int err)
56 56 {
57 57 hdl->agent_errno = err;
58 58 return (-1);
59 59 }
60 60
61 61 const char *
62 62 fmd_agent_strerr(int err)
63 63 {
64 64 return (strerror(err));
65 65 }
66 66
↓ open down ↓ |
66 lines elided |
↑ open up ↑ |
67 67 const char *
68 68 fmd_agent_errmsg(fmd_agent_hdl_t *hdl)
69 69 {
70 70 return (fmd_agent_strerr(hdl->agent_errno));
71 71 }
72 72
73 73 static int
74 74 cleanup_set_errno(fmd_agent_hdl_t *hdl, nvlist_t *innvl, nvlist_t *outnvl,
75 75 int err)
76 76 {
77 - if (innvl != NULL)
78 - nvlist_free(innvl);
79 - if (outnvl != NULL)
80 - nvlist_free(outnvl);
77 + nvlist_free(innvl);
78 + nvlist_free(outnvl);
81 79 return (fmd_agent_seterrno(hdl, err));
82 80 }
83 81
84 82 /*
85 83 * Perform /dev/fm ioctl. The input and output data are represented by
86 84 * name-value lists (nvlists).
87 85 */
88 86 int
89 87 fmd_agent_nvl_ioctl(fmd_agent_hdl_t *hdl, int cmd, uint32_t ver,
90 88 nvlist_t *innvl, nvlist_t **outnvlp)
91 89 {
92 90 fm_ioc_data_t fid;
93 91 int err = 0;
94 92 char *inbuf = NULL, *outbuf = NULL;
95 93 size_t insz = 0, outsz = 0;
96 94
97 95 if (innvl != NULL) {
98 96 if ((err = nvlist_size(innvl, &insz, NV_ENCODE_NATIVE)) != 0)
99 97 return (err);
100 98 if (insz > FM_IOC_MAXBUFSZ)
101 99 return (ENAMETOOLONG);
102 100 if ((inbuf = umem_alloc(insz, UMEM_DEFAULT)) == NULL)
103 101 return (errno);
104 102
105 103 if ((err = nvlist_pack(innvl, &inbuf, &insz,
106 104 NV_ENCODE_NATIVE, 0)) != 0) {
107 105 umem_free(inbuf, insz);
108 106 return (err);
109 107 }
110 108 }
111 109
112 110 if (outnvlp != NULL) {
113 111 outsz = FM_IOC_OUT_BUFSZ;
114 112 }
115 113 for (;;) {
116 114 if (outnvlp != NULL) {
117 115 outbuf = umem_alloc(outsz, UMEM_DEFAULT);
118 116 if (outbuf == NULL) {
119 117 err = errno;
120 118 break;
121 119 }
122 120 }
123 121
124 122 fid.fid_version = ver;
125 123 fid.fid_insz = insz;
126 124 fid.fid_inbuf = inbuf;
127 125 fid.fid_outsz = outsz;
128 126 fid.fid_outbuf = outbuf;
129 127
130 128 if (ioctl(hdl->agent_devfd, cmd, &fid) < 0) {
131 129 if (errno == ENAMETOOLONG && outsz != 0 &&
132 130 outsz < (FM_IOC_OUT_MAXBUFSZ / 2)) {
133 131 umem_free(outbuf, outsz);
134 132 outsz *= 2;
135 133 outbuf = umem_alloc(outsz, UMEM_DEFAULT);
136 134 if (outbuf == NULL) {
137 135 err = errno;
138 136 break;
139 137 }
140 138 } else {
141 139 err = errno;
142 140 break;
143 141 }
144 142 } else if (outnvlp != NULL) {
145 143 err = nvlist_unpack(fid.fid_outbuf, fid.fid_outsz,
146 144 outnvlp, 0);
147 145 break;
148 146 } else {
149 147 break;
150 148 }
151 149 }
152 150
153 151 if (inbuf != NULL)
154 152 umem_free(inbuf, insz);
155 153 if (outbuf != NULL)
156 154 umem_free(outbuf, outsz);
157 155
158 156 return (err);
159 157 }
160 158
161 159 /*
162 160 * Open /dev/fm and return a handle. ver is the overall interface version.
163 161 */
164 162 static fmd_agent_hdl_t *
165 163 fmd_agent_open_dev(int ver, int mode)
166 164 {
167 165 fmd_agent_hdl_t *hdl;
168 166 int fd, err;
169 167 nvlist_t *nvl;
170 168
171 169 if ((fd = open("/dev/fm", mode)) < 0)
172 170 return (NULL); /* errno is set for us */
173 171
174 172 if ((hdl = umem_alloc(sizeof (fmd_agent_hdl_t),
175 173 UMEM_DEFAULT)) == NULL) {
176 174 err = errno;
177 175 (void) close(fd);
178 176 errno = err;
179 177 return (NULL);
180 178 }
181 179
182 180 hdl->agent_devfd = fd;
183 181 hdl->agent_version = ver;
184 182
185 183 /*
186 184 * Get the individual interface versions.
187 185 */
188 186 if ((err = fmd_agent_nvl_ioctl(hdl, FM_IOC_VERSIONS, ver, NULL, &nvl))
189 187 < 0) {
190 188 (void) close(fd);
191 189 umem_free(hdl, sizeof (fmd_agent_hdl_t));
192 190 errno = err;
193 191 return (NULL);
194 192 }
195 193
196 194 hdl->agent_ioc_versions = nvl;
197 195 return (hdl);
198 196 }
199 197
200 198 fmd_agent_hdl_t *
201 199 fmd_agent_open(int ver)
202 200 {
203 201 if (ver > FMD_AGENT_VERSION) {
204 202 errno = ENOTSUP;
205 203 return (NULL);
206 204 }
207 205 return (fmd_agent_open_dev(ver, O_RDONLY));
208 206 }
209 207
210 208 void
211 209 fmd_agent_close(fmd_agent_hdl_t *hdl)
212 210 {
213 211 (void) close(hdl->agent_devfd);
214 212 nvlist_free(hdl->agent_ioc_versions);
215 213 umem_free(hdl, sizeof (fmd_agent_hdl_t));
216 214 }
217 215
218 216 /*
219 217 * Given a interface name, return the kernel interface version.
220 218 */
221 219 int
222 220 fmd_agent_version(fmd_agent_hdl_t *hdl, const char *op, uint32_t *verp)
223 221 {
224 222 int err;
225 223
226 224 err = nvlist_lookup_uint32(hdl->agent_ioc_versions,
227 225 op, verp);
228 226
229 227 if (err != 0) {
230 228 errno = err;
231 229 return (-1);
232 230 }
233 231 return (0);
234 232 }
235 233
236 234 static int
237 235 fmd_agent_pageop_v1(fmd_agent_hdl_t *hdl, int cmd, nvlist_t *fmri)
238 236 {
239 237 int err;
240 238 nvlist_t *nvl = NULL;
241 239
242 240 if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0)) != 0 ||
243 241 (err = nvlist_add_nvlist(nvl, FM_PAGE_RETIRE_FMRI, fmri)) != 0 ||
244 242 (err = fmd_agent_nvl_ioctl(hdl, cmd, 1, nvl, NULL)) != 0)
245 243 return (cleanup_set_errno(hdl, nvl, NULL, err));
246 244
247 245 nvlist_free(nvl);
248 246 return (0);
249 247 }
250 248
251 249 static int
252 250 fmd_agent_pageop(fmd_agent_hdl_t *hdl, int cmd, nvlist_t *fmri)
253 251 {
254 252 uint32_t ver;
255 253
256 254 if (fmd_agent_version(hdl, FM_PAGE_OP_VERSION, &ver) == -1)
257 255 return (fmd_agent_seterrno(hdl, errno));
258 256
259 257 switch (ver) {
260 258 case 1:
261 259 return (fmd_agent_pageop_v1(hdl, cmd, fmri));
262 260
263 261 default:
264 262 return (fmd_agent_seterrno(hdl, ENOTSUP));
265 263 }
266 264 }
267 265
268 266 int
269 267 fmd_agent_page_retire(fmd_agent_hdl_t *hdl, nvlist_t *fmri)
270 268 {
271 269 int rc = fmd_agent_pageop(hdl, FM_IOC_PAGE_RETIRE, fmri);
272 270 int err = fmd_agent_errno(hdl);
273 271
274 272 /*
275 273 * FM_IOC_PAGE_RETIRE ioctl returns:
276 274 * 0 - success in retiring page
277 275 * -1, errno = EIO - page is already retired
278 276 * -1, errno = EAGAIN - page is scheduled for retirement
279 277 * -1, errno = EINVAL - page fmri is invalid
280 278 * -1, errno = any else - error
281 279 */
282 280 if (rc == 0 || err == EIO || err == EINVAL) {
283 281 if (rc == 0)
284 282 (void) fmd_agent_seterrno(hdl, 0);
285 283 return (FMD_AGENT_RETIRE_DONE);
286 284 }
287 285 if (err == EAGAIN)
288 286 return (FMD_AGENT_RETIRE_ASYNC);
289 287
290 288 return (FMD_AGENT_RETIRE_FAIL);
291 289 }
292 290
293 291 int
294 292 fmd_agent_page_unretire(fmd_agent_hdl_t *hdl, nvlist_t *fmri)
295 293 {
296 294 int rc = fmd_agent_pageop(hdl, FM_IOC_PAGE_UNRETIRE, fmri);
297 295 int err = fmd_agent_errno(hdl);
298 296
299 297 /*
300 298 * FM_IOC_PAGE_UNRETIRE ioctl returns:
301 299 * 0 - success in unretiring page
302 300 * -1, errno = EIO - page is already unretired
303 301 * -1, errno = EAGAIN - page couldn't be locked, still retired
304 302 * -1, errno = EINVAL - page fmri is invalid
305 303 * -1, errno = any else - error
306 304 */
307 305 if (rc == 0 || err == EIO || err == EINVAL) {
308 306 if (rc == 0)
309 307 (void) fmd_agent_seterrno(hdl, 0);
310 308 return (FMD_AGENT_RETIRE_DONE);
311 309 }
312 310
313 311 return (FMD_AGENT_RETIRE_FAIL);
314 312 }
315 313
316 314 int
317 315 fmd_agent_page_isretired(fmd_agent_hdl_t *hdl, nvlist_t *fmri)
318 316 {
319 317 int rc = fmd_agent_pageop(hdl, FM_IOC_PAGE_STATUS, fmri);
320 318 int err = fmd_agent_errno(hdl);
321 319
322 320 /*
323 321 * FM_IOC_PAGE_STATUS returns:
324 322 * 0 - page is retired
325 323 * -1, errno = EAGAIN - page is scheduled for retirement
326 324 * -1, errno = EIO - page not scheduled for retirement
327 325 * -1, errno = EINVAL - page fmri is invalid
328 326 * -1, errno = any else - error
329 327 */
330 328 if (rc == 0 || err == EINVAL) {
331 329 if (rc == 0)
332 330 (void) fmd_agent_seterrno(hdl, 0);
333 331 return (FMD_AGENT_RETIRE_DONE);
334 332 }
335 333 if (err == EAGAIN)
336 334 return (FMD_AGENT_RETIRE_ASYNC);
337 335
338 336 return (FMD_AGENT_RETIRE_FAIL);
339 337 }
↓ open down ↓ |
249 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX