1e4b86885SCheng Sean Ye /*
2e4b86885SCheng Sean Ye * CDDL HEADER START
3e4b86885SCheng Sean Ye *
4e4b86885SCheng Sean Ye * The contents of this file are subject to the terms of the
5e4b86885SCheng Sean Ye * Common Development and Distribution License (the "License").
6e4b86885SCheng Sean Ye * You may not use this file except in compliance with the License.
7e4b86885SCheng Sean Ye *
8e4b86885SCheng Sean Ye * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9e4b86885SCheng Sean Ye * or http://www.opensolaris.org/os/licensing.
10e4b86885SCheng Sean Ye * See the License for the specific language governing permissions
11e4b86885SCheng Sean Ye * and limitations under the License.
12e4b86885SCheng Sean Ye *
13e4b86885SCheng Sean Ye * When distributing Covered Code, include this CDDL HEADER in each
14e4b86885SCheng Sean Ye * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15e4b86885SCheng Sean Ye * If applicable, add the following below this CDDL HEADER, with the
16e4b86885SCheng Sean Ye * fields enclosed by brackets "[]" replaced with your own identifying
17e4b86885SCheng Sean Ye * information: Portions Copyright [yyyy] [name of copyright owner]
18e4b86885SCheng Sean Ye *
19e4b86885SCheng Sean Ye * CDDL HEADER END
20e4b86885SCheng Sean Ye */
21e4b86885SCheng Sean Ye
22e4b86885SCheng Sean Ye /*
23211eb17aSAdrian Frost * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24e4b86885SCheng Sean Ye * Use is subject to license terms.
25e4b86885SCheng Sean Ye */
26e4b86885SCheng Sean Ye
27*dd23d762SRobert Mustacchi /*
28*dd23d762SRobert Mustacchi * Copyright 2023 Oxide Computer Company
29*dd23d762SRobert Mustacchi */
30*dd23d762SRobert Mustacchi
31e4b86885SCheng Sean Ye /*
32e4b86885SCheng Sean Ye * libfmd_agent contains the low-level operations that needed by the fmd
33e4b86885SCheng Sean Ye * agents, such as page operations (status/retire/unretire), cpu operations
34e4b86885SCheng Sean Ye * (status/online/offline), etc.
35e4b86885SCheng Sean Ye *
36e4b86885SCheng Sean Ye * Some operations are implemented by /dev/fm ioctls. Those ioctls are
37e4b86885SCheng Sean Ye * heavily versioned to allow userland patching without requiring a reboot
38e4b86885SCheng Sean Ye * to get a matched /dev/fm. All the ioctls use packed nvlist to interact
39e4b86885SCheng Sean Ye * between userland and kernel. (see fmd_agent_nvl_ioctl()).
40e4b86885SCheng Sean Ye */
41e4b86885SCheng Sean Ye
42e4b86885SCheng Sean Ye #include <fcntl.h>
43e4b86885SCheng Sean Ye #include <errno.h>
44e4b86885SCheng Sean Ye #include <unistd.h>
45e4b86885SCheng Sean Ye #include <strings.h>
46e4b86885SCheng Sean Ye #include <libnvpair.h>
47e4b86885SCheng Sean Ye #include <string.h>
48e4b86885SCheng Sean Ye #include <sys/types.h>
49e4b86885SCheng Sean Ye #include <sys/devfm.h>
50e4b86885SCheng Sean Ye #include <fmd_agent_impl.h>
51e4b86885SCheng Sean Ye
52e4b86885SCheng Sean Ye int
fmd_agent_errno(fmd_agent_hdl_t * hdl)53e4b86885SCheng Sean Ye fmd_agent_errno(fmd_agent_hdl_t *hdl)
54e4b86885SCheng Sean Ye {
55e4b86885SCheng Sean Ye return (hdl->agent_errno);
56e4b86885SCheng Sean Ye }
57e4b86885SCheng Sean Ye
58e4b86885SCheng Sean Ye int
fmd_agent_seterrno(fmd_agent_hdl_t * hdl,int err)59e4b86885SCheng Sean Ye fmd_agent_seterrno(fmd_agent_hdl_t *hdl, int err)
60e4b86885SCheng Sean Ye {
61e4b86885SCheng Sean Ye hdl->agent_errno = err;
62e4b86885SCheng Sean Ye return (-1);
63e4b86885SCheng Sean Ye }
64e4b86885SCheng Sean Ye
65e4b86885SCheng Sean Ye const char *
fmd_agent_strerr(int err)66e4b86885SCheng Sean Ye fmd_agent_strerr(int err)
67e4b86885SCheng Sean Ye {
68e4b86885SCheng Sean Ye return (strerror(err));
69e4b86885SCheng Sean Ye }
70e4b86885SCheng Sean Ye
71e4b86885SCheng Sean Ye const char *
fmd_agent_errmsg(fmd_agent_hdl_t * hdl)72e4b86885SCheng Sean Ye fmd_agent_errmsg(fmd_agent_hdl_t *hdl)
73e4b86885SCheng Sean Ye {
74e4b86885SCheng Sean Ye return (fmd_agent_strerr(hdl->agent_errno));
75e4b86885SCheng Sean Ye }
76e4b86885SCheng Sean Ye
77e4b86885SCheng Sean Ye static int
cleanup_set_errno(fmd_agent_hdl_t * hdl,nvlist_t * innvl,nvlist_t * outnvl,int err)78e4b86885SCheng Sean Ye cleanup_set_errno(fmd_agent_hdl_t *hdl, nvlist_t *innvl, nvlist_t *outnvl,
79e4b86885SCheng Sean Ye int err)
80e4b86885SCheng Sean Ye {
81aab83bb8SJosef 'Jeff' Sipek nvlist_free(innvl);
82aab83bb8SJosef 'Jeff' Sipek nvlist_free(outnvl);
83e4b86885SCheng Sean Ye return (fmd_agent_seterrno(hdl, err));
84e4b86885SCheng Sean Ye }
85e4b86885SCheng Sean Ye
86e4b86885SCheng Sean Ye /*
87e4b86885SCheng Sean Ye * Perform /dev/fm ioctl. The input and output data are represented by
88e4b86885SCheng Sean Ye * name-value lists (nvlists).
89e4b86885SCheng Sean Ye */
90e4b86885SCheng Sean Ye int
fmd_agent_nvl_ioctl(fmd_agent_hdl_t * hdl,int cmd,uint32_t ver,nvlist_t * innvl,nvlist_t ** outnvlp)91e4b86885SCheng Sean Ye fmd_agent_nvl_ioctl(fmd_agent_hdl_t *hdl, int cmd, uint32_t ver,
92e4b86885SCheng Sean Ye nvlist_t *innvl, nvlist_t **outnvlp)
93e4b86885SCheng Sean Ye {
94e4b86885SCheng Sean Ye fm_ioc_data_t fid;
95e4b86885SCheng Sean Ye int err = 0;
96e4b86885SCheng Sean Ye char *inbuf = NULL, *outbuf = NULL;
97e4b86885SCheng Sean Ye size_t insz = 0, outsz = 0;
98e4b86885SCheng Sean Ye
99e4b86885SCheng Sean Ye if (innvl != NULL) {
100e4b86885SCheng Sean Ye if ((err = nvlist_size(innvl, &insz, NV_ENCODE_NATIVE)) != 0)
101e4b86885SCheng Sean Ye return (err);
102e4b86885SCheng Sean Ye if (insz > FM_IOC_MAXBUFSZ)
103e4b86885SCheng Sean Ye return (ENAMETOOLONG);
104e4b86885SCheng Sean Ye if ((inbuf = umem_alloc(insz, UMEM_DEFAULT)) == NULL)
105e4b86885SCheng Sean Ye return (errno);
106e4b86885SCheng Sean Ye
107e4b86885SCheng Sean Ye if ((err = nvlist_pack(innvl, &inbuf, &insz,
108e4b86885SCheng Sean Ye NV_ENCODE_NATIVE, 0)) != 0) {
109e4b86885SCheng Sean Ye umem_free(inbuf, insz);
110e4b86885SCheng Sean Ye return (err);
111e4b86885SCheng Sean Ye }
112e4b86885SCheng Sean Ye }
113e4b86885SCheng Sean Ye
114e4b86885SCheng Sean Ye if (outnvlp != NULL) {
115211eb17aSAdrian Frost outsz = FM_IOC_OUT_BUFSZ;
116e4b86885SCheng Sean Ye }
117211eb17aSAdrian Frost for (;;) {
118211eb17aSAdrian Frost if (outnvlp != NULL) {
119211eb17aSAdrian Frost outbuf = umem_alloc(outsz, UMEM_DEFAULT);
120211eb17aSAdrian Frost if (outbuf == NULL) {
121211eb17aSAdrian Frost err = errno;
122211eb17aSAdrian Frost break;
123211eb17aSAdrian Frost }
124211eb17aSAdrian Frost }
125e4b86885SCheng Sean Ye
126211eb17aSAdrian Frost fid.fid_version = ver;
127211eb17aSAdrian Frost fid.fid_insz = insz;
128211eb17aSAdrian Frost fid.fid_inbuf = inbuf;
129211eb17aSAdrian Frost fid.fid_outsz = outsz;
130211eb17aSAdrian Frost fid.fid_outbuf = outbuf;
131e4b86885SCheng Sean Ye
132211eb17aSAdrian Frost if (ioctl(hdl->agent_devfd, cmd, &fid) < 0) {
133211eb17aSAdrian Frost if (errno == ENAMETOOLONG && outsz != 0 &&
134*dd23d762SRobert Mustacchi outsz <= (FM_IOC_OUT_MAXBUFSZ / 2)) {
135211eb17aSAdrian Frost umem_free(outbuf, outsz);
13692f54928SYuri Pankov outbuf = NULL;
137211eb17aSAdrian Frost outsz *= 2;
138211eb17aSAdrian Frost } else {
139211eb17aSAdrian Frost err = errno;
140211eb17aSAdrian Frost break;
141211eb17aSAdrian Frost }
142211eb17aSAdrian Frost } else if (outnvlp != NULL) {
143211eb17aSAdrian Frost err = nvlist_unpack(fid.fid_outbuf, fid.fid_outsz,
144211eb17aSAdrian Frost outnvlp, 0);
145211eb17aSAdrian Frost break;
146211eb17aSAdrian Frost } else {
147211eb17aSAdrian Frost break;
148211eb17aSAdrian Frost }
149211eb17aSAdrian Frost }
150e4b86885SCheng Sean Ye
151e4b86885SCheng Sean Ye if (inbuf != NULL)
152e4b86885SCheng Sean Ye umem_free(inbuf, insz);
153e4b86885SCheng Sean Ye if (outbuf != NULL)
154e4b86885SCheng Sean Ye umem_free(outbuf, outsz);
155e4b86885SCheng Sean Ye
156e4b86885SCheng Sean Ye return (err);
157e4b86885SCheng Sean Ye }
158e4b86885SCheng Sean Ye
159e4b86885SCheng Sean Ye /*
160e4b86885SCheng Sean Ye * Open /dev/fm and return a handle. ver is the overall interface version.
161e4b86885SCheng Sean Ye */
162e4b86885SCheng Sean Ye static fmd_agent_hdl_t *
fmd_agent_open_dev(int ver,int mode)163e4b86885SCheng Sean Ye fmd_agent_open_dev(int ver, int mode)
164e4b86885SCheng Sean Ye {
165e4b86885SCheng Sean Ye fmd_agent_hdl_t *hdl;
166e4b86885SCheng Sean Ye int fd, err;
167e4b86885SCheng Sean Ye nvlist_t *nvl;
168e4b86885SCheng Sean Ye
169e4b86885SCheng Sean Ye if ((fd = open("/dev/fm", mode)) < 0)
170e4b86885SCheng Sean Ye return (NULL); /* errno is set for us */
171e4b86885SCheng Sean Ye
172e4b86885SCheng Sean Ye if ((hdl = umem_alloc(sizeof (fmd_agent_hdl_t),
173e4b86885SCheng Sean Ye UMEM_DEFAULT)) == NULL) {
174e4b86885SCheng Sean Ye err = errno;
175e4b86885SCheng Sean Ye (void) close(fd);
176e4b86885SCheng Sean Ye errno = err;
177e4b86885SCheng Sean Ye return (NULL);
178e4b86885SCheng Sean Ye }
179e4b86885SCheng Sean Ye
180e4b86885SCheng Sean Ye hdl->agent_devfd = fd;
181e4b86885SCheng Sean Ye hdl->agent_version = ver;
182e4b86885SCheng Sean Ye
183e4b86885SCheng Sean Ye /*
184e4b86885SCheng Sean Ye * Get the individual interface versions.
185e4b86885SCheng Sean Ye */
186e4b86885SCheng Sean Ye if ((err = fmd_agent_nvl_ioctl(hdl, FM_IOC_VERSIONS, ver, NULL, &nvl))
187e4b86885SCheng Sean Ye < 0) {
188e4b86885SCheng Sean Ye (void) close(fd);
189e4b86885SCheng Sean Ye umem_free(hdl, sizeof (fmd_agent_hdl_t));
190e4b86885SCheng Sean Ye errno = err;
191e4b86885SCheng Sean Ye return (NULL);
192e4b86885SCheng Sean Ye }
193e4b86885SCheng Sean Ye
194e4b86885SCheng Sean Ye hdl->agent_ioc_versions = nvl;
195e4b86885SCheng Sean Ye return (hdl);
196e4b86885SCheng Sean Ye }
197e4b86885SCheng Sean Ye
198e4b86885SCheng Sean Ye fmd_agent_hdl_t *
fmd_agent_open(int ver)199e4b86885SCheng Sean Ye fmd_agent_open(int ver)
200e4b86885SCheng Sean Ye {
201e4b86885SCheng Sean Ye if (ver > FMD_AGENT_VERSION) {
202e4b86885SCheng Sean Ye errno = ENOTSUP;
203e4b86885SCheng Sean Ye return (NULL);
204e4b86885SCheng Sean Ye }
205e4b86885SCheng Sean Ye return (fmd_agent_open_dev(ver, O_RDONLY));
206e4b86885SCheng Sean Ye }
207e4b86885SCheng Sean Ye
208e4b86885SCheng Sean Ye void
fmd_agent_close(fmd_agent_hdl_t * hdl)209e4b86885SCheng Sean Ye fmd_agent_close(fmd_agent_hdl_t *hdl)
210e4b86885SCheng Sean Ye {
211e4b86885SCheng Sean Ye (void) close(hdl->agent_devfd);
212e4b86885SCheng Sean Ye nvlist_free(hdl->agent_ioc_versions);
213e4b86885SCheng Sean Ye umem_free(hdl, sizeof (fmd_agent_hdl_t));
214e4b86885SCheng Sean Ye }
215e4b86885SCheng Sean Ye
216e4b86885SCheng Sean Ye /*
217e4b86885SCheng Sean Ye * Given a interface name, return the kernel interface version.
218e4b86885SCheng Sean Ye */
219e4b86885SCheng Sean Ye int
fmd_agent_version(fmd_agent_hdl_t * hdl,const char * op,uint32_t * verp)220e4b86885SCheng Sean Ye fmd_agent_version(fmd_agent_hdl_t *hdl, const char *op, uint32_t *verp)
221e4b86885SCheng Sean Ye {
222e4b86885SCheng Sean Ye int err;
223e4b86885SCheng Sean Ye
224e4b86885SCheng Sean Ye err = nvlist_lookup_uint32(hdl->agent_ioc_versions,
225e4b86885SCheng Sean Ye op, verp);
226e4b86885SCheng Sean Ye
227e4b86885SCheng Sean Ye if (err != 0) {
228e4b86885SCheng Sean Ye errno = err;
229e4b86885SCheng Sean Ye return (-1);
230e4b86885SCheng Sean Ye }
231e4b86885SCheng Sean Ye return (0);
232e4b86885SCheng Sean Ye }
233e4b86885SCheng Sean Ye
234e4b86885SCheng Sean Ye static int
fmd_agent_pageop_v1(fmd_agent_hdl_t * hdl,int cmd,nvlist_t * fmri)235e4b86885SCheng Sean Ye fmd_agent_pageop_v1(fmd_agent_hdl_t *hdl, int cmd, nvlist_t *fmri)
236e4b86885SCheng Sean Ye {
237e4b86885SCheng Sean Ye int err;
238e4b86885SCheng Sean Ye nvlist_t *nvl = NULL;
239e4b86885SCheng Sean Ye
240e4b86885SCheng Sean Ye if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0)) != 0 ||
241e4b86885SCheng Sean Ye (err = nvlist_add_nvlist(nvl, FM_PAGE_RETIRE_FMRI, fmri)) != 0 ||
242e4b86885SCheng Sean Ye (err = fmd_agent_nvl_ioctl(hdl, cmd, 1, nvl, NULL)) != 0)
243e4b86885SCheng Sean Ye return (cleanup_set_errno(hdl, nvl, NULL, err));
244e4b86885SCheng Sean Ye
245e4b86885SCheng Sean Ye nvlist_free(nvl);
246e4b86885SCheng Sean Ye return (0);
247e4b86885SCheng Sean Ye }
248e4b86885SCheng Sean Ye
249e4b86885SCheng Sean Ye static int
fmd_agent_pageop(fmd_agent_hdl_t * hdl,int cmd,nvlist_t * fmri)250e4b86885SCheng Sean Ye fmd_agent_pageop(fmd_agent_hdl_t *hdl, int cmd, nvlist_t *fmri)
251e4b86885SCheng Sean Ye {
252e4b86885SCheng Sean Ye uint32_t ver;
253e4b86885SCheng Sean Ye
254e4b86885SCheng Sean Ye if (fmd_agent_version(hdl, FM_PAGE_OP_VERSION, &ver) == -1)
255e4b86885SCheng Sean Ye return (fmd_agent_seterrno(hdl, errno));
256e4b86885SCheng Sean Ye
257e4b86885SCheng Sean Ye switch (ver) {
258e4b86885SCheng Sean Ye case 1:
259e4b86885SCheng Sean Ye return (fmd_agent_pageop_v1(hdl, cmd, fmri));
260e4b86885SCheng Sean Ye
261e4b86885SCheng Sean Ye default:
262e4b86885SCheng Sean Ye return (fmd_agent_seterrno(hdl, ENOTSUP));
263e4b86885SCheng Sean Ye }
264e4b86885SCheng Sean Ye }
265e4b86885SCheng Sean Ye
266e4b86885SCheng Sean Ye int
fmd_agent_page_retire(fmd_agent_hdl_t * hdl,nvlist_t * fmri)267e4b86885SCheng Sean Ye fmd_agent_page_retire(fmd_agent_hdl_t *hdl, nvlist_t *fmri)
268e4b86885SCheng Sean Ye {
269e4b86885SCheng Sean Ye int rc = fmd_agent_pageop(hdl, FM_IOC_PAGE_RETIRE, fmri);
270e4b86885SCheng Sean Ye int err = fmd_agent_errno(hdl);
271e4b86885SCheng Sean Ye
272e4b86885SCheng Sean Ye /*
273e4b86885SCheng Sean Ye * FM_IOC_PAGE_RETIRE ioctl returns:
274e4b86885SCheng Sean Ye * 0 - success in retiring page
275e4b86885SCheng Sean Ye * -1, errno = EIO - page is already retired
276e4b86885SCheng Sean Ye * -1, errno = EAGAIN - page is scheduled for retirement
2771db96d3bSCheng Sean Ye * -1, errno = EINVAL - page fmri is invalid
278e4b86885SCheng Sean Ye * -1, errno = any else - error
279e4b86885SCheng Sean Ye */
280e4b86885SCheng Sean Ye if (rc == 0 || err == EIO || err == EINVAL) {
281e4b86885SCheng Sean Ye if (rc == 0)
282e4b86885SCheng Sean Ye (void) fmd_agent_seterrno(hdl, 0);
283e4b86885SCheng Sean Ye return (FMD_AGENT_RETIRE_DONE);
284e4b86885SCheng Sean Ye }
285e4b86885SCheng Sean Ye if (err == EAGAIN)
286e4b86885SCheng Sean Ye return (FMD_AGENT_RETIRE_ASYNC);
287e4b86885SCheng Sean Ye
288e4b86885SCheng Sean Ye return (FMD_AGENT_RETIRE_FAIL);
289e4b86885SCheng Sean Ye }
290e4b86885SCheng Sean Ye
291e4b86885SCheng Sean Ye int
fmd_agent_page_unretire(fmd_agent_hdl_t * hdl,nvlist_t * fmri)292e4b86885SCheng Sean Ye fmd_agent_page_unretire(fmd_agent_hdl_t *hdl, nvlist_t *fmri)
293e4b86885SCheng Sean Ye {
294e4b86885SCheng Sean Ye int rc = fmd_agent_pageop(hdl, FM_IOC_PAGE_UNRETIRE, fmri);
295e4b86885SCheng Sean Ye int err = fmd_agent_errno(hdl);
296e4b86885SCheng Sean Ye
297e4b86885SCheng Sean Ye /*
298e4b86885SCheng Sean Ye * FM_IOC_PAGE_UNRETIRE ioctl returns:
299e4b86885SCheng Sean Ye * 0 - success in unretiring page
300e4b86885SCheng Sean Ye * -1, errno = EIO - page is already unretired
301e4b86885SCheng Sean Ye * -1, errno = EAGAIN - page couldn't be locked, still retired
3021db96d3bSCheng Sean Ye * -1, errno = EINVAL - page fmri is invalid
303e4b86885SCheng Sean Ye * -1, errno = any else - error
304e4b86885SCheng Sean Ye */
3051db96d3bSCheng Sean Ye if (rc == 0 || err == EIO || err == EINVAL) {
306e4b86885SCheng Sean Ye if (rc == 0)
307e4b86885SCheng Sean Ye (void) fmd_agent_seterrno(hdl, 0);
308e4b86885SCheng Sean Ye return (FMD_AGENT_RETIRE_DONE);
309e4b86885SCheng Sean Ye }
310e4b86885SCheng Sean Ye
311e4b86885SCheng Sean Ye return (FMD_AGENT_RETIRE_FAIL);
312e4b86885SCheng Sean Ye }
313e4b86885SCheng Sean Ye
314e4b86885SCheng Sean Ye int
fmd_agent_page_isretired(fmd_agent_hdl_t * hdl,nvlist_t * fmri)315e4b86885SCheng Sean Ye fmd_agent_page_isretired(fmd_agent_hdl_t *hdl, nvlist_t *fmri)
316e4b86885SCheng Sean Ye {
317e4b86885SCheng Sean Ye int rc = fmd_agent_pageop(hdl, FM_IOC_PAGE_STATUS, fmri);
318e4b86885SCheng Sean Ye int err = fmd_agent_errno(hdl);
319e4b86885SCheng Sean Ye
320e4b86885SCheng Sean Ye /*
321e4b86885SCheng Sean Ye * FM_IOC_PAGE_STATUS returns:
322e4b86885SCheng Sean Ye * 0 - page is retired
323e4b86885SCheng Sean Ye * -1, errno = EAGAIN - page is scheduled for retirement
324e4b86885SCheng Sean Ye * -1, errno = EIO - page not scheduled for retirement
3251db96d3bSCheng Sean Ye * -1, errno = EINVAL - page fmri is invalid
326e4b86885SCheng Sean Ye * -1, errno = any else - error
327e4b86885SCheng Sean Ye */
328e4b86885SCheng Sean Ye if (rc == 0 || err == EINVAL) {
329e4b86885SCheng Sean Ye if (rc == 0)
330e4b86885SCheng Sean Ye (void) fmd_agent_seterrno(hdl, 0);
331e4b86885SCheng Sean Ye return (FMD_AGENT_RETIRE_DONE);
332e4b86885SCheng Sean Ye }
333e4b86885SCheng Sean Ye if (err == EAGAIN)
334e4b86885SCheng Sean Ye return (FMD_AGENT_RETIRE_ASYNC);
335e4b86885SCheng Sean Ye
336e4b86885SCheng Sean Ye return (FMD_AGENT_RETIRE_FAIL);
337e4b86885SCheng Sean Ye }
338*dd23d762SRobert Mustacchi
339*dd23d762SRobert Mustacchi void
fmd_agent_cache_info_free(fmd_agent_hdl_t * hdl __unused,fmd_agent_cpu_cache_list_t * cache)340*dd23d762SRobert Mustacchi fmd_agent_cache_info_free(fmd_agent_hdl_t *hdl __unused,
341*dd23d762SRobert Mustacchi fmd_agent_cpu_cache_list_t *cache)
342*dd23d762SRobert Mustacchi {
343*dd23d762SRobert Mustacchi for (uint_t cpuno = 0; cpuno < cache->fmc_ncpus; cpuno++) {
344*dd23d762SRobert Mustacchi fmd_agent_cpu_cache_t *cpu_cache = &cache->fmc_cpus[cpuno];
345*dd23d762SRobert Mustacchi
346*dd23d762SRobert Mustacchi if (cpu_cache->fmcc_caches == NULL)
347*dd23d762SRobert Mustacchi continue;
348*dd23d762SRobert Mustacchi
349*dd23d762SRobert Mustacchi for (uint_t cacheno = 0; cacheno < cpu_cache->fmcc_ncaches;
350*dd23d762SRobert Mustacchi cacheno++) {
351*dd23d762SRobert Mustacchi nvlist_free(cpu_cache->fmcc_caches[cacheno]);
352*dd23d762SRobert Mustacchi }
353*dd23d762SRobert Mustacchi
354*dd23d762SRobert Mustacchi umem_free(cpu_cache->fmcc_caches, sizeof (nvlist_t *) *
355*dd23d762SRobert Mustacchi cpu_cache->fmcc_ncaches);
356*dd23d762SRobert Mustacchi cpu_cache->fmcc_caches = NULL;
357*dd23d762SRobert Mustacchi }
358*dd23d762SRobert Mustacchi
359*dd23d762SRobert Mustacchi if (cache->fmc_cpus != NULL) {
360*dd23d762SRobert Mustacchi umem_free(cache->fmc_cpus, sizeof (fmd_agent_cpu_cache_t) *
361*dd23d762SRobert Mustacchi cache->fmc_ncpus);
362*dd23d762SRobert Mustacchi cache->fmc_cpus = NULL;
363*dd23d762SRobert Mustacchi cache->fmc_ncpus = 0;
364*dd23d762SRobert Mustacchi }
365*dd23d762SRobert Mustacchi }
366*dd23d762SRobert Mustacchi
367*dd23d762SRobert Mustacchi static int
fmd_agent_cache_info_pop_cpu(fmd_agent_cpu_cache_list_t * cache,nvlist_t * cpu_nvl,uint_t cpuno)368*dd23d762SRobert Mustacchi fmd_agent_cache_info_pop_cpu(fmd_agent_cpu_cache_list_t *cache,
369*dd23d762SRobert Mustacchi nvlist_t *cpu_nvl, uint_t cpuno)
370*dd23d762SRobert Mustacchi {
371*dd23d762SRobert Mustacchi int ret;
372*dd23d762SRobert Mustacchi char cpustr[32];
373*dd23d762SRobert Mustacchi nvlist_t **cache_nvls;
374*dd23d762SRobert Mustacchi uint_t ncache_nvls;
375*dd23d762SRobert Mustacchi fmd_agent_cpu_cache_t *cpu = &cache->fmc_cpus[cpuno];
376*dd23d762SRobert Mustacchi
377*dd23d762SRobert Mustacchi (void) snprintf(cpustr, sizeof (cpustr), "%u", cpuno);
378*dd23d762SRobert Mustacchi if ((ret = nvlist_lookup_nvlist_array(cpu_nvl, cpustr, &cache_nvls,
379*dd23d762SRobert Mustacchi &ncache_nvls)) != 0) {
380*dd23d762SRobert Mustacchi return (ret);
381*dd23d762SRobert Mustacchi }
382*dd23d762SRobert Mustacchi
383*dd23d762SRobert Mustacchi if (ncache_nvls == 0) {
384*dd23d762SRobert Mustacchi cpu->fmcc_ncaches = 0;
385*dd23d762SRobert Mustacchi cpu->fmcc_caches = NULL;
386*dd23d762SRobert Mustacchi return (0);
387*dd23d762SRobert Mustacchi }
388*dd23d762SRobert Mustacchi
389*dd23d762SRobert Mustacchi cpu->fmcc_caches = umem_zalloc(sizeof (nvlist_t *) * ncache_nvls,
390*dd23d762SRobert Mustacchi UMEM_DEFAULT);
391*dd23d762SRobert Mustacchi if (cpu->fmcc_caches == NULL) {
392*dd23d762SRobert Mustacchi return (errno);
393*dd23d762SRobert Mustacchi }
394*dd23d762SRobert Mustacchi cpu->fmcc_ncaches = ncache_nvls;
395*dd23d762SRobert Mustacchi for (uint_t i = 0; i < cpu->fmcc_ncaches; i++) {
396*dd23d762SRobert Mustacchi ret = nvlist_dup(cache_nvls[i], &cpu->fmcc_caches[i], 0);
397*dd23d762SRobert Mustacchi if (ret != 0) {
398*dd23d762SRobert Mustacchi return (ret);
399*dd23d762SRobert Mustacchi }
400*dd23d762SRobert Mustacchi }
401*dd23d762SRobert Mustacchi
402*dd23d762SRobert Mustacchi return (0);
403*dd23d762SRobert Mustacchi }
404*dd23d762SRobert Mustacchi
405*dd23d762SRobert Mustacchi int
fmd_agent_cache_info(fmd_agent_hdl_t * hdl,fmd_agent_cpu_cache_list_t * cache)406*dd23d762SRobert Mustacchi fmd_agent_cache_info(fmd_agent_hdl_t *hdl, fmd_agent_cpu_cache_list_t *cache)
407*dd23d762SRobert Mustacchi {
408*dd23d762SRobert Mustacchi int err, ret = 0;
409*dd23d762SRobert Mustacchi uint32_t ncpus;
410*dd23d762SRobert Mustacchi nvlist_t *nvl = NULL;
411*dd23d762SRobert Mustacchi
412*dd23d762SRobert Mustacchi bzero(cache, sizeof (fmd_agent_cpu_cache_list_t));
413*dd23d762SRobert Mustacchi if ((err = fmd_agent_nvl_ioctl(hdl, FM_IOC_CACHE_INFO, 1, NULL,
414*dd23d762SRobert Mustacchi &nvl)) != 0) {
415*dd23d762SRobert Mustacchi ret = fmd_agent_seterrno(hdl, err);
416*dd23d762SRobert Mustacchi goto out;
417*dd23d762SRobert Mustacchi }
418*dd23d762SRobert Mustacchi
419*dd23d762SRobert Mustacchi if ((err = nvlist_lookup_uint32(nvl, FM_CACHE_INFO_NCPUS, &ncpus)) !=
420*dd23d762SRobert Mustacchi 0) {
421*dd23d762SRobert Mustacchi ret = fmd_agent_seterrno(hdl, err);
422*dd23d762SRobert Mustacchi goto out;
423*dd23d762SRobert Mustacchi }
424*dd23d762SRobert Mustacchi
425*dd23d762SRobert Mustacchi cache->fmc_cpus = umem_zalloc(sizeof (fmd_agent_cpu_cache_t) * ncpus,
426*dd23d762SRobert Mustacchi UMEM_DEFAULT);
427*dd23d762SRobert Mustacchi if (cache->fmc_cpus == NULL) {
428*dd23d762SRobert Mustacchi ret = fmd_agent_seterrno(hdl, errno);
429*dd23d762SRobert Mustacchi goto out;
430*dd23d762SRobert Mustacchi }
431*dd23d762SRobert Mustacchi cache->fmc_ncpus = ncpus;
432*dd23d762SRobert Mustacchi for (uint_t i = 0; i < cache->fmc_ncpus; i++) {
433*dd23d762SRobert Mustacchi if ((err = fmd_agent_cache_info_pop_cpu(cache, nvl, i)) != 0) {
434*dd23d762SRobert Mustacchi ret = fmd_agent_seterrno(hdl, errno);
435*dd23d762SRobert Mustacchi goto out;
436*dd23d762SRobert Mustacchi }
437*dd23d762SRobert Mustacchi
438*dd23d762SRobert Mustacchi }
439*dd23d762SRobert Mustacchi out:
440*dd23d762SRobert Mustacchi if (ret != 0) {
441*dd23d762SRobert Mustacchi fmd_agent_cache_info_free(hdl, cache);
442*dd23d762SRobert Mustacchi }
443*dd23d762SRobert Mustacchi nvlist_free(nvl);
444*dd23d762SRobert Mustacchi return (ret);
445*dd23d762SRobert Mustacchi }
446