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