e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye/*
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * CDDL HEADER START
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye *
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * The contents of this file are subject to the terms of the
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * Common Development and Distribution License (the "License").
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * You may not use this file except in compliance with the License.
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye *
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * or http://www.opensolaris.org/os/licensing.
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * See the License for the specific language governing permissions
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * and limitations under the License.
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye *
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * When distributing Covered Code, include this CDDL HEADER in each
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * If applicable, add the following below this CDDL HEADER, with the
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * fields enclosed by brackets "[]" replaced with your own identifying
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * information: Portions Copyright [yyyy] [name of copyright owner]
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye *
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * CDDL HEADER END
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye/*
074bb90d80fdbeb2d04a8450a55ecbc96de28785Tom Pothier * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * Use is subject to license terms.
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#include <sys/stat.h>
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#include <sys/types.h>
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#include <sys/param.h>
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#include <sys/cred.h>
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#include <sys/policy.h>
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#include <sys/file.h>
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#include <sys/errno.h>
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#include <sys/modctl.h>
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#include <sys/ddi.h>
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#include <sys/sunddi.h>
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#include <sys/conf.h>
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#include <sys/debug.h>
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#include <sys/systeminfo.h>
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#include <sys/fm/protocol.h>
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#include <sys/devfm.h>
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yeextern int fm_get_paddr(nvlist_t *, uint64_t *);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#if defined(__x86)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yeextern int fm_ioctl_physcpu_info(int, nvlist_t *, nvlist_t **);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yeextern int fm_ioctl_cpu_retire(int, nvlist_t *, nvlist_t **);
074bb90d80fdbeb2d04a8450a55ecbc96de28785Tom Pothierextern int fm_ioctl_gentopo_legacy(int, nvlist_t *, nvlist_t **);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#endif /* __x86 */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yestatic int fm_ioctl_versions(int, nvlist_t *, nvlist_t **);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yestatic int fm_ioctl_page_retire(int, nvlist_t *, nvlist_t **);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye/*
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * The driver's capabilities are strictly versioned, allowing userland patching
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * without a reboot. The userland should start with a FM_VERSIONS ioctl to
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * query the versions of the kernel interfaces, then it's all userland's
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * responsibility to prepare arguments etc to match the current kenrel.
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * The version of FM_VERSIONS itself is FM_DRV_VERSION.
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yetypedef struct fm_version {
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye char *interface; /* interface name */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye uint32_t version; /* interface version */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye} fm_vers_t;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yetypedef struct fm_subroutine {
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye int cmd; /* ioctl cmd */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye boolean_t priv; /* require privilege */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye char *version; /* version name */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye int (*func)(int, nvlist_t *, nvlist_t **); /* handler */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye} fm_subr_t;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yestatic const fm_vers_t fm_versions[] = {
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye { FM_VERSIONS_VERSION, FM_DRV_VERSION },
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye { FM_PAGE_OP_VERSION, 1 },
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye { FM_CPU_OP_VERSION, 1 },
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye { FM_CPU_INFO_VERSION, 1 },
074bb90d80fdbeb2d04a8450a55ecbc96de28785Tom Pothier { FM_TOPO_LEGACY_VERSION, 1 },
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye { NULL, 0 }
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye};
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yestatic const fm_subr_t fm_subrs[] = {
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye { FM_IOC_VERSIONS, B_FALSE, FM_VERSIONS_VERSION, fm_ioctl_versions },
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye { FM_IOC_PAGE_RETIRE, B_TRUE, FM_PAGE_OP_VERSION,
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye fm_ioctl_page_retire },
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye { FM_IOC_PAGE_STATUS, B_FALSE, FM_PAGE_OP_VERSION,
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye fm_ioctl_page_retire },
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye { FM_IOC_PAGE_UNRETIRE, B_TRUE, FM_PAGE_OP_VERSION,
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye fm_ioctl_page_retire },
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#if defined(__x86)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye { FM_IOC_PHYSCPU_INFO, B_FALSE, FM_CPU_INFO_VERSION,
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye fm_ioctl_physcpu_info },
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye { FM_IOC_CPU_RETIRE, B_TRUE, FM_CPU_OP_VERSION,
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye fm_ioctl_cpu_retire },
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye { FM_IOC_CPU_STATUS, B_FALSE, FM_CPU_OP_VERSION,
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye fm_ioctl_cpu_retire },
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye { FM_IOC_CPU_UNRETIRE, B_TRUE, FM_CPU_OP_VERSION,
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye fm_ioctl_cpu_retire },
074bb90d80fdbeb2d04a8450a55ecbc96de28785Tom Pothier { FM_IOC_GENTOPO_LEGACY, B_FALSE, FM_TOPO_LEGACY_VERSION,
074bb90d80fdbeb2d04a8450a55ecbc96de28785Tom Pothier fm_ioctl_gentopo_legacy },
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#endif /* __x86 */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye { -1, B_FALSE, NULL, NULL },
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye};
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yestatic dev_info_t *fm_dip;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yestatic boolean_t is_i86xpv;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yestatic nvlist_t *fm_vers_nvl;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yestatic int
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yefm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye{
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye switch (cmd) {
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye case DDI_ATTACH:
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if (ddi_create_minor_node(dip, ddi_get_name(dip), S_IFCHR,
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye ddi_get_instance(dip), DDI_PSEUDO, 0) != DDI_SUCCESS) {
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye ddi_remove_minor_node(dip, NULL);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (DDI_FAILURE);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye }
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye fm_dip = dip;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye is_i86xpv = (strcmp(platform, "i86xpv") == 0);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye break;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye case DDI_RESUME:
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye break;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye default:
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (DDI_FAILURE);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye }
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (DDI_SUCCESS);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye}
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yestatic int
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yefm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye{
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye int ret = DDI_SUCCESS;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye switch (cmd) {
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye case DDI_DETACH:
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye ddi_remove_minor_node(dip, NULL);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye fm_dip = NULL;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye break;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye default:
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye ret = DDI_FAILURE;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye }
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (ret);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye}
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye/*ARGSUSED*/
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yestatic int
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yefm_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye{
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye int error;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye switch (infocmd) {
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye case DDI_INFO_DEVT2DEVINFO:
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye *result = fm_dip;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye error = DDI_SUCCESS;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye break;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye case DDI_INFO_DEVT2INSTANCE:
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye *result = NULL;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye error = DDI_SUCCESS;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye break;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye default:
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye error = DDI_FAILURE;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye }
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (error);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye}
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye/*ARGSUSED1*/
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yestatic int
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yefm_open(dev_t *devp, int flag, int typ, struct cred *cred)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye{
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if (typ != OTYP_CHR)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (EINVAL);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if (getminor(*devp) != 0)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (ENXIO);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (0);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye}
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye/*ARGSUSED*/
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yestatic int
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yefm_ioctl_versions(int cmd, nvlist_t *invl, nvlist_t **onvlp)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye{
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye nvlist_t *nvl;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye int err;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if ((err = nvlist_dup(fm_vers_nvl, &nvl, KM_SLEEP)) == 0)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye *onvlp = nvl;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (err);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye}
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye/*
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * Given a mem-scheme FMRI for a page, execute the given page retire
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * command on it.
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye/*ARGSUSED*/
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yestatic int
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yefm_ioctl_page_retire(int cmd, nvlist_t *invl, nvlist_t **onvlp)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye{
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye uint64_t pa;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye nvlist_t *fmri;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye int err;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if (is_i86xpv)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (ENOTSUP);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if ((err = nvlist_lookup_nvlist(invl, FM_PAGE_RETIRE_FMRI, &fmri))
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye != 0)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (err);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if ((err = fm_get_paddr(fmri, &pa)) != 0)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (err);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye switch (cmd) {
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye case FM_IOC_PAGE_STATUS:
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (page_retire_check(pa, NULL));
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye case FM_IOC_PAGE_RETIRE:
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (page_retire(pa, PR_FMA));
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye case FM_IOC_PAGE_UNRETIRE:
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (page_unretire(pa));
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye }
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (ENOTTY);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye}
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye/*ARGSUSED*/
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yestatic int
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yefm_ioctl(dev_t dev, int cmd, intptr_t data, int flag, cred_t *cred, int *rvalp)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye{
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye char *buf;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye int err;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye uint_t model;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye const fm_subr_t *subr;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye uint32_t vers;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye fm_ioc_data_t fid;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye nvlist_t *invl = NULL, *onvl = NULL;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#ifdef _MULTI_DATAMODEL
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye fm_ioc_data32_t fid32;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#endif
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if (getminor(dev) != 0)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (ENXIO);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye for (subr = fm_subrs; subr->cmd != cmd; subr++)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if (subr->cmd == -1)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (ENOTTY);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if (subr->priv && (flag & FWRITE) == 0 &&
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye secpolicy_sys_config(CRED(), 0) != 0)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (EPERM);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye model = ddi_model_convert_from(flag & FMODELS);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye switch (model) {
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#ifdef _MULTI_DATAMODEL
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye case DDI_MODEL_ILP32:
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if (ddi_copyin((void *)data, &fid32,
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye sizeof (fm_ioc_data32_t), flag) != 0)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (EFAULT);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye fid.fid_version = fid32.fid_version;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye fid.fid_insz = fid32.fid_insz;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye fid.fid_inbuf = (caddr_t)(uintptr_t)fid32.fid_inbuf;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye fid.fid_outsz = fid32.fid_outsz;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye fid.fid_outbuf = (caddr_t)(uintptr_t)fid32.fid_outbuf;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye break;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#endif /* _MULTI_DATAMODEL */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye case DDI_MODEL_NONE:
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye default:
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if (ddi_copyin((void *)data, &fid, sizeof (fm_ioc_data_t),
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye flag) != 0)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (EFAULT);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye }
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if (nvlist_lookup_uint32(fm_vers_nvl, subr->version, &vers) != 0 ||
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye fid.fid_version != vers)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (ENOTSUP);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if (fid.fid_insz > FM_IOC_MAXBUFSZ)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (ENAMETOOLONG);
211eb17a9612ace1f2dee156ee66d097e28d9faaAdrian Frost if (fid.fid_outsz > FM_IOC_OUT_MAXBUFSZ)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (EINVAL);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye /*
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * Copy in and unpack the input nvlist.
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if (fid.fid_insz != 0 && fid.fid_inbuf != (caddr_t)0) {
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye buf = kmem_alloc(fid.fid_insz, KM_SLEEP);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if (ddi_copyin(fid.fid_inbuf, buf, fid.fid_insz, flag) != 0) {
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye kmem_free(buf, fid.fid_insz);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (EFAULT);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye }
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye err = nvlist_unpack(buf, fid.fid_insz, &invl, KM_SLEEP);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye kmem_free(buf, fid.fid_insz);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if (err != 0)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (err);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye }
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye err = subr->func(cmd, invl, &onvl);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
aab83bb83be7342f6cfccaed8d5fe0b2f404855dJosef 'Jeff' Sipek nvlist_free(invl);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if (err != 0) {
aab83bb83be7342f6cfccaed8d5fe0b2f404855dJosef 'Jeff' Sipek nvlist_free(onvl);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (err);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye }
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye /*
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * If the output nvlist contains any data, pack it and copyout.
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if (onvl != NULL) {
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye size_t sz;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if ((err = nvlist_size(onvl, &sz, NV_ENCODE_NATIVE)) != 0) {
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye nvlist_free(onvl);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (err);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye }
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if (sz > fid.fid_outsz) {
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye nvlist_free(onvl);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (ENAMETOOLONG);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye }
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye buf = kmem_alloc(sz, KM_SLEEP);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if ((err = nvlist_pack(onvl, &buf, &sz, NV_ENCODE_NATIVE,
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye KM_SLEEP)) != 0) {
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye kmem_free(buf, sz);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye nvlist_free(onvl);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (err);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye }
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye nvlist_free(onvl);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if (ddi_copyout(buf, fid.fid_outbuf, sz, flag) != 0) {
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye kmem_free(buf, sz);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (EFAULT);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye }
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye kmem_free(buf, sz);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye fid.fid_outsz = sz;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye switch (model) {
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#ifdef _MULTI_DATAMODEL
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye case DDI_MODEL_ILP32:
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye fid32.fid_outsz = (size32_t)fid.fid_outsz;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if (ddi_copyout(&fid32, (void *)data,
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye sizeof (fm_ioc_data32_t), flag) != 0)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (EFAULT);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye break;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#endif /* _MULTI_DATAMODEL */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye case DDI_MODEL_NONE:
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye default:
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if (ddi_copyout(&fid, (void *)data,
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye sizeof (fm_ioc_data_t), flag) != 0)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (EFAULT);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye }
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye }
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (err);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye}
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yestatic struct cb_ops fm_cb_ops = {
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye fm_open, /* open */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye nulldev, /* close */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye nodev, /* strategy */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye nodev, /* print */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye nodev, /* dump */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye nodev, /* read */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye nodev, /* write */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye fm_ioctl, /* ioctl */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye nodev, /* devmap */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye nodev, /* mmap */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye nodev, /* segmap */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye nochpoll, /* poll */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye ddi_prop_op, /* prop_op */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye NULL, /* streamtab */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye D_NEW | D_MP | D_64BIT | D_U64BIT
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye};
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yestatic struct dev_ops fm_ops = {
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye DEVO_REV, /* devo_rev, */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye 0, /* refcnt */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye fm_info, /* get_dev_info */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye nulldev, /* identify */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye nulldev, /* probe */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye fm_attach, /* attach */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye fm_detach, /* detach */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye nodev, /* reset */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye &fm_cb_ops, /* driver operations */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye (struct bus_ops *)0 /* bus operations */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye};
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yestatic struct modldrv modldrv = {
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye &mod_driverops, "fault management driver", &fm_ops,
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye};
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yestatic struct modlinkage modlinkage = {
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye MODREV_1, &modldrv, NULL
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye};
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yeint
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye_init(void)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye{
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye const fm_vers_t *p;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye int ret;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if ((ret = mod_install(&modlinkage)) == 0) {
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye (void) nvlist_alloc(&fm_vers_nvl, NV_UNIQUE_NAME, KM_SLEEP);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye for (p = fm_versions; p->interface != NULL; p++)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye (void) nvlist_add_uint32(fm_vers_nvl, p->interface,
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye p->version);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye }
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (ret);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye}
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yeint
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye_info(struct modinfo *modinfop)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye{
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (mod_info(&modlinkage, modinfop));
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye}
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yeint
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye_fini(void)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye{
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye int ret;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if ((ret = mod_remove(&modlinkage)) == 0) {
aab83bb83be7342f6cfccaed8d5fe0b2f404855dJosef 'Jeff' Sipek nvlist_free(fm_vers_nvl);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye }
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return (ret);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye}