17532SSean.Ye@Sun.COM /*
27532SSean.Ye@Sun.COM * CDDL HEADER START
37532SSean.Ye@Sun.COM *
47532SSean.Ye@Sun.COM * The contents of this file are subject to the terms of the
57532SSean.Ye@Sun.COM * Common Development and Distribution License (the "License").
67532SSean.Ye@Sun.COM * You may not use this file except in compliance with the License.
77532SSean.Ye@Sun.COM *
87532SSean.Ye@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97532SSean.Ye@Sun.COM * or http://www.opensolaris.org/os/licensing.
107532SSean.Ye@Sun.COM * See the License for the specific language governing permissions
117532SSean.Ye@Sun.COM * and limitations under the License.
127532SSean.Ye@Sun.COM *
137532SSean.Ye@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
147532SSean.Ye@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157532SSean.Ye@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
167532SSean.Ye@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
177532SSean.Ye@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
187532SSean.Ye@Sun.COM *
197532SSean.Ye@Sun.COM * CDDL HEADER END
207532SSean.Ye@Sun.COM */
217532SSean.Ye@Sun.COM
227532SSean.Ye@Sun.COM /*
23*11264SAdrian.Frost@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
247532SSean.Ye@Sun.COM * Use is subject to license terms.
257532SSean.Ye@Sun.COM */
267532SSean.Ye@Sun.COM
277532SSean.Ye@Sun.COM /*
287532SSean.Ye@Sun.COM * libfmd_agent contains the low-level operations that needed by the fmd
297532SSean.Ye@Sun.COM * agents, such as page operations (status/retire/unretire), cpu operations
307532SSean.Ye@Sun.COM * (status/online/offline), etc.
317532SSean.Ye@Sun.COM *
327532SSean.Ye@Sun.COM * Some operations are implemented by /dev/fm ioctls. Those ioctls are
337532SSean.Ye@Sun.COM * heavily versioned to allow userland patching without requiring a reboot
347532SSean.Ye@Sun.COM * to get a matched /dev/fm. All the ioctls use packed nvlist to interact
357532SSean.Ye@Sun.COM * between userland and kernel. (see fmd_agent_nvl_ioctl()).
367532SSean.Ye@Sun.COM */
377532SSean.Ye@Sun.COM
387532SSean.Ye@Sun.COM #include <fcntl.h>
397532SSean.Ye@Sun.COM #include <errno.h>
407532SSean.Ye@Sun.COM #include <unistd.h>
417532SSean.Ye@Sun.COM #include <strings.h>
427532SSean.Ye@Sun.COM #include <libnvpair.h>
437532SSean.Ye@Sun.COM #include <string.h>
447532SSean.Ye@Sun.COM #include <sys/types.h>
457532SSean.Ye@Sun.COM #include <sys/devfm.h>
467532SSean.Ye@Sun.COM #include <fmd_agent_impl.h>
477532SSean.Ye@Sun.COM
487532SSean.Ye@Sun.COM int
fmd_agent_errno(fmd_agent_hdl_t * hdl)497532SSean.Ye@Sun.COM fmd_agent_errno(fmd_agent_hdl_t *hdl)
507532SSean.Ye@Sun.COM {
517532SSean.Ye@Sun.COM return (hdl->agent_errno);
527532SSean.Ye@Sun.COM }
537532SSean.Ye@Sun.COM
547532SSean.Ye@Sun.COM int
fmd_agent_seterrno(fmd_agent_hdl_t * hdl,int err)557532SSean.Ye@Sun.COM fmd_agent_seterrno(fmd_agent_hdl_t *hdl, int err)
567532SSean.Ye@Sun.COM {
577532SSean.Ye@Sun.COM hdl->agent_errno = err;
587532SSean.Ye@Sun.COM return (-1);
597532SSean.Ye@Sun.COM }
607532SSean.Ye@Sun.COM
617532SSean.Ye@Sun.COM const char *
fmd_agent_strerr(int err)627532SSean.Ye@Sun.COM fmd_agent_strerr(int err)
637532SSean.Ye@Sun.COM {
647532SSean.Ye@Sun.COM return (strerror(err));
657532SSean.Ye@Sun.COM }
667532SSean.Ye@Sun.COM
677532SSean.Ye@Sun.COM const char *
fmd_agent_errmsg(fmd_agent_hdl_t * hdl)687532SSean.Ye@Sun.COM fmd_agent_errmsg(fmd_agent_hdl_t *hdl)
697532SSean.Ye@Sun.COM {
707532SSean.Ye@Sun.COM return (fmd_agent_strerr(hdl->agent_errno));
717532SSean.Ye@Sun.COM }
727532SSean.Ye@Sun.COM
737532SSean.Ye@Sun.COM static int
cleanup_set_errno(fmd_agent_hdl_t * hdl,nvlist_t * innvl,nvlist_t * outnvl,int err)747532SSean.Ye@Sun.COM cleanup_set_errno(fmd_agent_hdl_t *hdl, nvlist_t *innvl, nvlist_t *outnvl,
757532SSean.Ye@Sun.COM int err)
767532SSean.Ye@Sun.COM {
777532SSean.Ye@Sun.COM if (innvl != NULL)
787532SSean.Ye@Sun.COM nvlist_free(innvl);
797532SSean.Ye@Sun.COM if (outnvl != NULL)
807532SSean.Ye@Sun.COM nvlist_free(outnvl);
817532SSean.Ye@Sun.COM return (fmd_agent_seterrno(hdl, err));
827532SSean.Ye@Sun.COM }
837532SSean.Ye@Sun.COM
847532SSean.Ye@Sun.COM /*
857532SSean.Ye@Sun.COM * Perform /dev/fm ioctl. The input and output data are represented by
867532SSean.Ye@Sun.COM * name-value lists (nvlists).
877532SSean.Ye@Sun.COM */
887532SSean.Ye@Sun.COM int
fmd_agent_nvl_ioctl(fmd_agent_hdl_t * hdl,int cmd,uint32_t ver,nvlist_t * innvl,nvlist_t ** outnvlp)897532SSean.Ye@Sun.COM fmd_agent_nvl_ioctl(fmd_agent_hdl_t *hdl, int cmd, uint32_t ver,
907532SSean.Ye@Sun.COM nvlist_t *innvl, nvlist_t **outnvlp)
917532SSean.Ye@Sun.COM {
927532SSean.Ye@Sun.COM fm_ioc_data_t fid;
937532SSean.Ye@Sun.COM int err = 0;
947532SSean.Ye@Sun.COM char *inbuf = NULL, *outbuf = NULL;
957532SSean.Ye@Sun.COM size_t insz = 0, outsz = 0;
967532SSean.Ye@Sun.COM
977532SSean.Ye@Sun.COM if (innvl != NULL) {
987532SSean.Ye@Sun.COM if ((err = nvlist_size(innvl, &insz, NV_ENCODE_NATIVE)) != 0)
997532SSean.Ye@Sun.COM return (err);
1007532SSean.Ye@Sun.COM if (insz > FM_IOC_MAXBUFSZ)
1017532SSean.Ye@Sun.COM return (ENAMETOOLONG);
1027532SSean.Ye@Sun.COM if ((inbuf = umem_alloc(insz, UMEM_DEFAULT)) == NULL)
1037532SSean.Ye@Sun.COM return (errno);
1047532SSean.Ye@Sun.COM
1057532SSean.Ye@Sun.COM if ((err = nvlist_pack(innvl, &inbuf, &insz,
1067532SSean.Ye@Sun.COM NV_ENCODE_NATIVE, 0)) != 0) {
1077532SSean.Ye@Sun.COM umem_free(inbuf, insz);
1087532SSean.Ye@Sun.COM return (err);
1097532SSean.Ye@Sun.COM }
1107532SSean.Ye@Sun.COM }
1117532SSean.Ye@Sun.COM
1127532SSean.Ye@Sun.COM if (outnvlp != NULL) {
113*11264SAdrian.Frost@Sun.COM outsz = FM_IOC_OUT_BUFSZ;
114*11264SAdrian.Frost@Sun.COM }
115*11264SAdrian.Frost@Sun.COM for (;;) {
116*11264SAdrian.Frost@Sun.COM if (outnvlp != NULL) {
117*11264SAdrian.Frost@Sun.COM outbuf = umem_alloc(outsz, UMEM_DEFAULT);
118*11264SAdrian.Frost@Sun.COM if (outbuf == NULL) {
119*11264SAdrian.Frost@Sun.COM err = errno;
120*11264SAdrian.Frost@Sun.COM break;
121*11264SAdrian.Frost@Sun.COM }
122*11264SAdrian.Frost@Sun.COM }
123*11264SAdrian.Frost@Sun.COM
124*11264SAdrian.Frost@Sun.COM fid.fid_version = ver;
125*11264SAdrian.Frost@Sun.COM fid.fid_insz = insz;
126*11264SAdrian.Frost@Sun.COM fid.fid_inbuf = inbuf;
127*11264SAdrian.Frost@Sun.COM fid.fid_outsz = outsz;
128*11264SAdrian.Frost@Sun.COM fid.fid_outbuf = outbuf;
129*11264SAdrian.Frost@Sun.COM
130*11264SAdrian.Frost@Sun.COM if (ioctl(hdl->agent_devfd, cmd, &fid) < 0) {
131*11264SAdrian.Frost@Sun.COM if (errno == ENAMETOOLONG && outsz != 0 &&
132*11264SAdrian.Frost@Sun.COM outsz < (FM_IOC_OUT_MAXBUFSZ / 2)) {
133*11264SAdrian.Frost@Sun.COM umem_free(outbuf, outsz);
134*11264SAdrian.Frost@Sun.COM outsz *= 2;
135*11264SAdrian.Frost@Sun.COM outbuf = umem_alloc(outsz, UMEM_DEFAULT);
136*11264SAdrian.Frost@Sun.COM if (outbuf == NULL) {
137*11264SAdrian.Frost@Sun.COM err = errno;
138*11264SAdrian.Frost@Sun.COM break;
139*11264SAdrian.Frost@Sun.COM }
140*11264SAdrian.Frost@Sun.COM } else {
141*11264SAdrian.Frost@Sun.COM err = errno;
142*11264SAdrian.Frost@Sun.COM break;
143*11264SAdrian.Frost@Sun.COM }
144*11264SAdrian.Frost@Sun.COM } else if (outnvlp != NULL) {
145*11264SAdrian.Frost@Sun.COM err = nvlist_unpack(fid.fid_outbuf, fid.fid_outsz,
146*11264SAdrian.Frost@Sun.COM outnvlp, 0);
147*11264SAdrian.Frost@Sun.COM break;
148*11264SAdrian.Frost@Sun.COM } else {
149*11264SAdrian.Frost@Sun.COM break;
1507532SSean.Ye@Sun.COM }
1517532SSean.Ye@Sun.COM }
1527532SSean.Ye@Sun.COM
1537532SSean.Ye@Sun.COM if (inbuf != NULL)
1547532SSean.Ye@Sun.COM umem_free(inbuf, insz);
1557532SSean.Ye@Sun.COM if (outbuf != NULL)
1567532SSean.Ye@Sun.COM umem_free(outbuf, outsz);
1577532SSean.Ye@Sun.COM
1587532SSean.Ye@Sun.COM return (err);
1597532SSean.Ye@Sun.COM }
1607532SSean.Ye@Sun.COM
1617532SSean.Ye@Sun.COM /*
1627532SSean.Ye@Sun.COM * Open /dev/fm and return a handle. ver is the overall interface version.
1637532SSean.Ye@Sun.COM */
1647532SSean.Ye@Sun.COM static fmd_agent_hdl_t *
fmd_agent_open_dev(int ver,int mode)1657532SSean.Ye@Sun.COM fmd_agent_open_dev(int ver, int mode)
1667532SSean.Ye@Sun.COM {
1677532SSean.Ye@Sun.COM fmd_agent_hdl_t *hdl;
1687532SSean.Ye@Sun.COM int fd, err;
1697532SSean.Ye@Sun.COM nvlist_t *nvl;
1707532SSean.Ye@Sun.COM
1717532SSean.Ye@Sun.COM if ((fd = open("/dev/fm", mode)) < 0)
1727532SSean.Ye@Sun.COM return (NULL); /* errno is set for us */
1737532SSean.Ye@Sun.COM
1747532SSean.Ye@Sun.COM if ((hdl = umem_alloc(sizeof (fmd_agent_hdl_t),
1757532SSean.Ye@Sun.COM UMEM_DEFAULT)) == NULL) {
1767532SSean.Ye@Sun.COM err = errno;
1777532SSean.Ye@Sun.COM (void) close(fd);
1787532SSean.Ye@Sun.COM errno = err;
1797532SSean.Ye@Sun.COM return (NULL);
1807532SSean.Ye@Sun.COM }
1817532SSean.Ye@Sun.COM
1827532SSean.Ye@Sun.COM hdl->agent_devfd = fd;
1837532SSean.Ye@Sun.COM hdl->agent_version = ver;
1847532SSean.Ye@Sun.COM
1857532SSean.Ye@Sun.COM /*
1867532SSean.Ye@Sun.COM * Get the individual interface versions.
1877532SSean.Ye@Sun.COM */
1887532SSean.Ye@Sun.COM if ((err = fmd_agent_nvl_ioctl(hdl, FM_IOC_VERSIONS, ver, NULL, &nvl))
1897532SSean.Ye@Sun.COM < 0) {
1907532SSean.Ye@Sun.COM (void) close(fd);
1917532SSean.Ye@Sun.COM umem_free(hdl, sizeof (fmd_agent_hdl_t));
1927532SSean.Ye@Sun.COM errno = err;
1937532SSean.Ye@Sun.COM return (NULL);
1947532SSean.Ye@Sun.COM }
1957532SSean.Ye@Sun.COM
1967532SSean.Ye@Sun.COM hdl->agent_ioc_versions = nvl;
1977532SSean.Ye@Sun.COM return (hdl);
1987532SSean.Ye@Sun.COM }
1997532SSean.Ye@Sun.COM
2007532SSean.Ye@Sun.COM fmd_agent_hdl_t *
fmd_agent_open(int ver)2017532SSean.Ye@Sun.COM fmd_agent_open(int ver)
2027532SSean.Ye@Sun.COM {
2037532SSean.Ye@Sun.COM if (ver > FMD_AGENT_VERSION) {
2047532SSean.Ye@Sun.COM errno = ENOTSUP;
2057532SSean.Ye@Sun.COM return (NULL);
2067532SSean.Ye@Sun.COM }
2077532SSean.Ye@Sun.COM return (fmd_agent_open_dev(ver, O_RDONLY));
2087532SSean.Ye@Sun.COM }
2097532SSean.Ye@Sun.COM
2107532SSean.Ye@Sun.COM void
fmd_agent_close(fmd_agent_hdl_t * hdl)2117532SSean.Ye@Sun.COM fmd_agent_close(fmd_agent_hdl_t *hdl)
2127532SSean.Ye@Sun.COM {
2137532SSean.Ye@Sun.COM (void) close(hdl->agent_devfd);
2147532SSean.Ye@Sun.COM nvlist_free(hdl->agent_ioc_versions);
2157532SSean.Ye@Sun.COM umem_free(hdl, sizeof (fmd_agent_hdl_t));
2167532SSean.Ye@Sun.COM }
2177532SSean.Ye@Sun.COM
2187532SSean.Ye@Sun.COM /*
2197532SSean.Ye@Sun.COM * Given a interface name, return the kernel interface version.
2207532SSean.Ye@Sun.COM */
2217532SSean.Ye@Sun.COM int
fmd_agent_version(fmd_agent_hdl_t * hdl,const char * op,uint32_t * verp)2227532SSean.Ye@Sun.COM fmd_agent_version(fmd_agent_hdl_t *hdl, const char *op, uint32_t *verp)
2237532SSean.Ye@Sun.COM {
2247532SSean.Ye@Sun.COM int err;
2257532SSean.Ye@Sun.COM
2267532SSean.Ye@Sun.COM err = nvlist_lookup_uint32(hdl->agent_ioc_versions,
2277532SSean.Ye@Sun.COM op, verp);
2287532SSean.Ye@Sun.COM
2297532SSean.Ye@Sun.COM if (err != 0) {
2307532SSean.Ye@Sun.COM errno = err;
2317532SSean.Ye@Sun.COM return (-1);
2327532SSean.Ye@Sun.COM }
2337532SSean.Ye@Sun.COM return (0);
2347532SSean.Ye@Sun.COM }
2357532SSean.Ye@Sun.COM
2367532SSean.Ye@Sun.COM static int
fmd_agent_pageop_v1(fmd_agent_hdl_t * hdl,int cmd,nvlist_t * fmri)2377532SSean.Ye@Sun.COM fmd_agent_pageop_v1(fmd_agent_hdl_t *hdl, int cmd, nvlist_t *fmri)
2387532SSean.Ye@Sun.COM {
2397532SSean.Ye@Sun.COM int err;
2407532SSean.Ye@Sun.COM nvlist_t *nvl = NULL;
2417532SSean.Ye@Sun.COM
2427532SSean.Ye@Sun.COM if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0)) != 0 ||
2437532SSean.Ye@Sun.COM (err = nvlist_add_nvlist(nvl, FM_PAGE_RETIRE_FMRI, fmri)) != 0 ||
2447532SSean.Ye@Sun.COM (err = fmd_agent_nvl_ioctl(hdl, cmd, 1, nvl, NULL)) != 0)
2457532SSean.Ye@Sun.COM return (cleanup_set_errno(hdl, nvl, NULL, err));
2467532SSean.Ye@Sun.COM
2477532SSean.Ye@Sun.COM nvlist_free(nvl);
2487532SSean.Ye@Sun.COM return (0);
2497532SSean.Ye@Sun.COM }
2507532SSean.Ye@Sun.COM
2517532SSean.Ye@Sun.COM static int
fmd_agent_pageop(fmd_agent_hdl_t * hdl,int cmd,nvlist_t * fmri)2527532SSean.Ye@Sun.COM fmd_agent_pageop(fmd_agent_hdl_t *hdl, int cmd, nvlist_t *fmri)
2537532SSean.Ye@Sun.COM {
2547532SSean.Ye@Sun.COM uint32_t ver;
2557532SSean.Ye@Sun.COM
2567532SSean.Ye@Sun.COM if (fmd_agent_version(hdl, FM_PAGE_OP_VERSION, &ver) == -1)
2577532SSean.Ye@Sun.COM return (fmd_agent_seterrno(hdl, errno));
2587532SSean.Ye@Sun.COM
2597532SSean.Ye@Sun.COM switch (ver) {
2607532SSean.Ye@Sun.COM case 1:
2617532SSean.Ye@Sun.COM return (fmd_agent_pageop_v1(hdl, cmd, fmri));
2627532SSean.Ye@Sun.COM
2637532SSean.Ye@Sun.COM default:
2647532SSean.Ye@Sun.COM return (fmd_agent_seterrno(hdl, ENOTSUP));
2657532SSean.Ye@Sun.COM }
2667532SSean.Ye@Sun.COM }
2677532SSean.Ye@Sun.COM
2687532SSean.Ye@Sun.COM int
fmd_agent_page_retire(fmd_agent_hdl_t * hdl,nvlist_t * fmri)2697532SSean.Ye@Sun.COM fmd_agent_page_retire(fmd_agent_hdl_t *hdl, nvlist_t *fmri)
2707532SSean.Ye@Sun.COM {
2717532SSean.Ye@Sun.COM int rc = fmd_agent_pageop(hdl, FM_IOC_PAGE_RETIRE, fmri);
2727532SSean.Ye@Sun.COM int err = fmd_agent_errno(hdl);
2737532SSean.Ye@Sun.COM
2747532SSean.Ye@Sun.COM /*
2757532SSean.Ye@Sun.COM * FM_IOC_PAGE_RETIRE ioctl returns:
2767532SSean.Ye@Sun.COM * 0 - success in retiring page
2777532SSean.Ye@Sun.COM * -1, errno = EIO - page is already retired
2787532SSean.Ye@Sun.COM * -1, errno = EAGAIN - page is scheduled for retirement
2798074SSean.Ye@Sun.COM * -1, errno = EINVAL - page fmri is invalid
2807532SSean.Ye@Sun.COM * -1, errno = any else - error
2817532SSean.Ye@Sun.COM */
2827532SSean.Ye@Sun.COM if (rc == 0 || err == EIO || err == EINVAL) {
2837532SSean.Ye@Sun.COM if (rc == 0)
2847532SSean.Ye@Sun.COM (void) fmd_agent_seterrno(hdl, 0);
2857532SSean.Ye@Sun.COM return (FMD_AGENT_RETIRE_DONE);
2867532SSean.Ye@Sun.COM }
2877532SSean.Ye@Sun.COM if (err == EAGAIN)
2887532SSean.Ye@Sun.COM return (FMD_AGENT_RETIRE_ASYNC);
2897532SSean.Ye@Sun.COM
2907532SSean.Ye@Sun.COM return (FMD_AGENT_RETIRE_FAIL);
2917532SSean.Ye@Sun.COM }
2927532SSean.Ye@Sun.COM
2937532SSean.Ye@Sun.COM int
fmd_agent_page_unretire(fmd_agent_hdl_t * hdl,nvlist_t * fmri)2947532SSean.Ye@Sun.COM fmd_agent_page_unretire(fmd_agent_hdl_t *hdl, nvlist_t *fmri)
2957532SSean.Ye@Sun.COM {
2967532SSean.Ye@Sun.COM int rc = fmd_agent_pageop(hdl, FM_IOC_PAGE_UNRETIRE, fmri);
2977532SSean.Ye@Sun.COM int err = fmd_agent_errno(hdl);
2987532SSean.Ye@Sun.COM
2997532SSean.Ye@Sun.COM /*
3007532SSean.Ye@Sun.COM * FM_IOC_PAGE_UNRETIRE ioctl returns:
3017532SSean.Ye@Sun.COM * 0 - success in unretiring page
3027532SSean.Ye@Sun.COM * -1, errno = EIO - page is already unretired
3037532SSean.Ye@Sun.COM * -1, errno = EAGAIN - page couldn't be locked, still retired
3048074SSean.Ye@Sun.COM * -1, errno = EINVAL - page fmri is invalid
3057532SSean.Ye@Sun.COM * -1, errno = any else - error
3067532SSean.Ye@Sun.COM */
3078074SSean.Ye@Sun.COM if (rc == 0 || err == EIO || err == EINVAL) {
3087532SSean.Ye@Sun.COM if (rc == 0)
3097532SSean.Ye@Sun.COM (void) fmd_agent_seterrno(hdl, 0);
3107532SSean.Ye@Sun.COM return (FMD_AGENT_RETIRE_DONE);
3117532SSean.Ye@Sun.COM }
3127532SSean.Ye@Sun.COM
3137532SSean.Ye@Sun.COM return (FMD_AGENT_RETIRE_FAIL);
3147532SSean.Ye@Sun.COM }
3157532SSean.Ye@Sun.COM
3167532SSean.Ye@Sun.COM int
fmd_agent_page_isretired(fmd_agent_hdl_t * hdl,nvlist_t * fmri)3177532SSean.Ye@Sun.COM fmd_agent_page_isretired(fmd_agent_hdl_t *hdl, nvlist_t *fmri)
3187532SSean.Ye@Sun.COM {
3197532SSean.Ye@Sun.COM int rc = fmd_agent_pageop(hdl, FM_IOC_PAGE_STATUS, fmri);
3207532SSean.Ye@Sun.COM int err = fmd_agent_errno(hdl);
3217532SSean.Ye@Sun.COM
3227532SSean.Ye@Sun.COM /*
3237532SSean.Ye@Sun.COM * FM_IOC_PAGE_STATUS returns:
3247532SSean.Ye@Sun.COM * 0 - page is retired
3257532SSean.Ye@Sun.COM * -1, errno = EAGAIN - page is scheduled for retirement
3267532SSean.Ye@Sun.COM * -1, errno = EIO - page not scheduled for retirement
3278074SSean.Ye@Sun.COM * -1, errno = EINVAL - page fmri is invalid
3287532SSean.Ye@Sun.COM * -1, errno = any else - error
3297532SSean.Ye@Sun.COM */
3307532SSean.Ye@Sun.COM if (rc == 0 || err == EINVAL) {
3317532SSean.Ye@Sun.COM if (rc == 0)
3327532SSean.Ye@Sun.COM (void) fmd_agent_seterrno(hdl, 0);
3337532SSean.Ye@Sun.COM return (FMD_AGENT_RETIRE_DONE);
3347532SSean.Ye@Sun.COM }
3357532SSean.Ye@Sun.COM if (err == EAGAIN)
3367532SSean.Ye@Sun.COM return (FMD_AGENT_RETIRE_ASYNC);
3377532SSean.Ye@Sun.COM
3387532SSean.Ye@Sun.COM return (FMD_AGENT_RETIRE_FAIL);
3397532SSean.Ye@Sun.COM }
340