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 /* 22*10942STom.Pothier@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237532SSean.Ye@Sun.COM * Use is subject to license terms. 247532SSean.Ye@Sun.COM */ 257532SSean.Ye@Sun.COM 267532SSean.Ye@Sun.COM #include <sys/stat.h> 277532SSean.Ye@Sun.COM #include <sys/types.h> 287532SSean.Ye@Sun.COM #include <sys/param.h> 297532SSean.Ye@Sun.COM #include <sys/cred.h> 307532SSean.Ye@Sun.COM #include <sys/policy.h> 317532SSean.Ye@Sun.COM #include <sys/file.h> 327532SSean.Ye@Sun.COM #include <sys/errno.h> 337532SSean.Ye@Sun.COM #include <sys/modctl.h> 347532SSean.Ye@Sun.COM #include <sys/ddi.h> 357532SSean.Ye@Sun.COM #include <sys/sunddi.h> 367532SSean.Ye@Sun.COM #include <sys/conf.h> 377532SSean.Ye@Sun.COM #include <sys/debug.h> 387532SSean.Ye@Sun.COM #include <sys/systeminfo.h> 397532SSean.Ye@Sun.COM 407532SSean.Ye@Sun.COM #include <sys/fm/protocol.h> 417532SSean.Ye@Sun.COM #include <sys/devfm.h> 427532SSean.Ye@Sun.COM 437532SSean.Ye@Sun.COM extern int fm_get_paddr(nvlist_t *, uint64_t *); 447532SSean.Ye@Sun.COM #if defined(__x86) 457532SSean.Ye@Sun.COM extern int fm_ioctl_physcpu_info(int, nvlist_t *, nvlist_t **); 467532SSean.Ye@Sun.COM extern int fm_ioctl_cpu_retire(int, nvlist_t *, nvlist_t **); 47*10942STom.Pothier@Sun.COM extern int fm_ioctl_gentopo_legacy(int, nvlist_t *, nvlist_t **); 487532SSean.Ye@Sun.COM #endif /* __x86 */ 497532SSean.Ye@Sun.COM 507532SSean.Ye@Sun.COM static int fm_ioctl_versions(int, nvlist_t *, nvlist_t **); 517532SSean.Ye@Sun.COM static int fm_ioctl_page_retire(int, nvlist_t *, nvlist_t **); 527532SSean.Ye@Sun.COM 537532SSean.Ye@Sun.COM /* 547532SSean.Ye@Sun.COM * The driver's capabilities are strictly versioned, allowing userland patching 557532SSean.Ye@Sun.COM * without a reboot. The userland should start with a FM_VERSIONS ioctl to 567532SSean.Ye@Sun.COM * query the versions of the kernel interfaces, then it's all userland's 577532SSean.Ye@Sun.COM * responsibility to prepare arguments etc to match the current kenrel. 587532SSean.Ye@Sun.COM * The version of FM_VERSIONS itself is FM_DRV_VERSION. 597532SSean.Ye@Sun.COM */ 607532SSean.Ye@Sun.COM typedef struct fm_version { 617532SSean.Ye@Sun.COM char *interface; /* interface name */ 627532SSean.Ye@Sun.COM uint32_t version; /* interface version */ 637532SSean.Ye@Sun.COM } fm_vers_t; 647532SSean.Ye@Sun.COM 657532SSean.Ye@Sun.COM typedef struct fm_subroutine { 667532SSean.Ye@Sun.COM int cmd; /* ioctl cmd */ 677532SSean.Ye@Sun.COM boolean_t priv; /* require privilege */ 687532SSean.Ye@Sun.COM char *version; /* version name */ 697532SSean.Ye@Sun.COM int (*func)(int, nvlist_t *, nvlist_t **); /* handler */ 707532SSean.Ye@Sun.COM } fm_subr_t; 717532SSean.Ye@Sun.COM 727532SSean.Ye@Sun.COM static const fm_vers_t fm_versions[] = { 737532SSean.Ye@Sun.COM { FM_VERSIONS_VERSION, FM_DRV_VERSION }, 747532SSean.Ye@Sun.COM { FM_PAGE_OP_VERSION, 1 }, 757532SSean.Ye@Sun.COM { FM_CPU_OP_VERSION, 1 }, 767532SSean.Ye@Sun.COM { FM_CPU_INFO_VERSION, 1 }, 77*10942STom.Pothier@Sun.COM { FM_TOPO_LEGACY_VERSION, 1 }, 787532SSean.Ye@Sun.COM { NULL, 0 } 797532SSean.Ye@Sun.COM }; 807532SSean.Ye@Sun.COM 817532SSean.Ye@Sun.COM static const fm_subr_t fm_subrs[] = { 827532SSean.Ye@Sun.COM { FM_IOC_VERSIONS, B_FALSE, FM_VERSIONS_VERSION, fm_ioctl_versions }, 837532SSean.Ye@Sun.COM { FM_IOC_PAGE_RETIRE, B_TRUE, FM_PAGE_OP_VERSION, 847532SSean.Ye@Sun.COM fm_ioctl_page_retire }, 857532SSean.Ye@Sun.COM { FM_IOC_PAGE_STATUS, B_FALSE, FM_PAGE_OP_VERSION, 867532SSean.Ye@Sun.COM fm_ioctl_page_retire }, 877532SSean.Ye@Sun.COM { FM_IOC_PAGE_UNRETIRE, B_TRUE, FM_PAGE_OP_VERSION, 887532SSean.Ye@Sun.COM fm_ioctl_page_retire }, 897532SSean.Ye@Sun.COM #if defined(__x86) 907532SSean.Ye@Sun.COM { FM_IOC_PHYSCPU_INFO, B_FALSE, FM_CPU_INFO_VERSION, 917532SSean.Ye@Sun.COM fm_ioctl_physcpu_info }, 927532SSean.Ye@Sun.COM { FM_IOC_CPU_RETIRE, B_TRUE, FM_CPU_OP_VERSION, 937532SSean.Ye@Sun.COM fm_ioctl_cpu_retire }, 947532SSean.Ye@Sun.COM { FM_IOC_CPU_STATUS, B_FALSE, FM_CPU_OP_VERSION, 957532SSean.Ye@Sun.COM fm_ioctl_cpu_retire }, 967532SSean.Ye@Sun.COM { FM_IOC_CPU_UNRETIRE, B_TRUE, FM_CPU_OP_VERSION, 977532SSean.Ye@Sun.COM fm_ioctl_cpu_retire }, 98*10942STom.Pothier@Sun.COM { FM_IOC_GENTOPO_LEGACY, B_FALSE, FM_TOPO_LEGACY_VERSION, 99*10942STom.Pothier@Sun.COM fm_ioctl_gentopo_legacy }, 1007532SSean.Ye@Sun.COM #endif /* __x86 */ 1017532SSean.Ye@Sun.COM { -1, B_FALSE, NULL, NULL }, 1027532SSean.Ye@Sun.COM }; 1037532SSean.Ye@Sun.COM 1047532SSean.Ye@Sun.COM static dev_info_t *fm_dip; 1057532SSean.Ye@Sun.COM static boolean_t is_i86xpv; 1067532SSean.Ye@Sun.COM static nvlist_t *fm_vers_nvl; 1077532SSean.Ye@Sun.COM 1087532SSean.Ye@Sun.COM static int 1097532SSean.Ye@Sun.COM fm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 1107532SSean.Ye@Sun.COM { 1117532SSean.Ye@Sun.COM switch (cmd) { 1127532SSean.Ye@Sun.COM case DDI_ATTACH: 1137532SSean.Ye@Sun.COM if (ddi_create_minor_node(dip, ddi_get_name(dip), S_IFCHR, 1147532SSean.Ye@Sun.COM ddi_get_instance(dip), DDI_PSEUDO, 0) != DDI_SUCCESS) { 1157532SSean.Ye@Sun.COM ddi_remove_minor_node(dip, NULL); 1167532SSean.Ye@Sun.COM return (DDI_FAILURE); 1177532SSean.Ye@Sun.COM } 1187532SSean.Ye@Sun.COM fm_dip = dip; 1197532SSean.Ye@Sun.COM is_i86xpv = (strcmp(platform, "i86xpv") == 0); 1207532SSean.Ye@Sun.COM break; 1217532SSean.Ye@Sun.COM case DDI_RESUME: 1227532SSean.Ye@Sun.COM break; 1237532SSean.Ye@Sun.COM default: 1247532SSean.Ye@Sun.COM return (DDI_FAILURE); 1257532SSean.Ye@Sun.COM } 1267532SSean.Ye@Sun.COM return (DDI_SUCCESS); 1277532SSean.Ye@Sun.COM } 1287532SSean.Ye@Sun.COM 1297532SSean.Ye@Sun.COM static int 1307532SSean.Ye@Sun.COM fm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 1317532SSean.Ye@Sun.COM { 1327532SSean.Ye@Sun.COM int ret = DDI_SUCCESS; 1337532SSean.Ye@Sun.COM 1347532SSean.Ye@Sun.COM switch (cmd) { 1357532SSean.Ye@Sun.COM case DDI_DETACH: 1367532SSean.Ye@Sun.COM ddi_remove_minor_node(dip, NULL); 1377532SSean.Ye@Sun.COM fm_dip = NULL; 1387532SSean.Ye@Sun.COM break; 1397532SSean.Ye@Sun.COM default: 1407532SSean.Ye@Sun.COM ret = DDI_FAILURE; 1417532SSean.Ye@Sun.COM } 1427532SSean.Ye@Sun.COM return (ret); 1437532SSean.Ye@Sun.COM } 1447532SSean.Ye@Sun.COM 1457532SSean.Ye@Sun.COM /*ARGSUSED*/ 1467532SSean.Ye@Sun.COM static int 1477532SSean.Ye@Sun.COM fm_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 1487532SSean.Ye@Sun.COM { 1497532SSean.Ye@Sun.COM int error; 1507532SSean.Ye@Sun.COM 1517532SSean.Ye@Sun.COM switch (infocmd) { 1527532SSean.Ye@Sun.COM case DDI_INFO_DEVT2DEVINFO: 1537532SSean.Ye@Sun.COM *result = fm_dip; 1547532SSean.Ye@Sun.COM error = DDI_SUCCESS; 1557532SSean.Ye@Sun.COM break; 1567532SSean.Ye@Sun.COM case DDI_INFO_DEVT2INSTANCE: 1577532SSean.Ye@Sun.COM *result = NULL; 1587532SSean.Ye@Sun.COM error = DDI_SUCCESS; 1597532SSean.Ye@Sun.COM break; 1607532SSean.Ye@Sun.COM default: 1617532SSean.Ye@Sun.COM error = DDI_FAILURE; 1627532SSean.Ye@Sun.COM } 1637532SSean.Ye@Sun.COM return (error); 1647532SSean.Ye@Sun.COM } 1657532SSean.Ye@Sun.COM 1667532SSean.Ye@Sun.COM /*ARGSUSED1*/ 1677532SSean.Ye@Sun.COM static int 1687532SSean.Ye@Sun.COM fm_open(dev_t *devp, int flag, int typ, struct cred *cred) 1697532SSean.Ye@Sun.COM { 1707532SSean.Ye@Sun.COM if (typ != OTYP_CHR) 1717532SSean.Ye@Sun.COM return (EINVAL); 1727532SSean.Ye@Sun.COM if (getminor(*devp) != 0) 1737532SSean.Ye@Sun.COM return (ENXIO); 1747532SSean.Ye@Sun.COM 1757532SSean.Ye@Sun.COM return (0); 1767532SSean.Ye@Sun.COM } 1777532SSean.Ye@Sun.COM 1787532SSean.Ye@Sun.COM /*ARGSUSED*/ 1797532SSean.Ye@Sun.COM static int 1807532SSean.Ye@Sun.COM fm_ioctl_versions(int cmd, nvlist_t *invl, nvlist_t **onvlp) 1817532SSean.Ye@Sun.COM { 1827532SSean.Ye@Sun.COM nvlist_t *nvl; 1837532SSean.Ye@Sun.COM int err; 1847532SSean.Ye@Sun.COM 1857532SSean.Ye@Sun.COM if ((err = nvlist_dup(fm_vers_nvl, &nvl, KM_SLEEP)) == 0) 1867532SSean.Ye@Sun.COM *onvlp = nvl; 1877532SSean.Ye@Sun.COM 1887532SSean.Ye@Sun.COM return (err); 1897532SSean.Ye@Sun.COM } 1907532SSean.Ye@Sun.COM 1917532SSean.Ye@Sun.COM /* 1927532SSean.Ye@Sun.COM * Given a mem-scheme FMRI for a page, execute the given page retire 1937532SSean.Ye@Sun.COM * command on it. 1947532SSean.Ye@Sun.COM */ 1957532SSean.Ye@Sun.COM /*ARGSUSED*/ 1967532SSean.Ye@Sun.COM static int 1977532SSean.Ye@Sun.COM fm_ioctl_page_retire(int cmd, nvlist_t *invl, nvlist_t **onvlp) 1987532SSean.Ye@Sun.COM { 1997532SSean.Ye@Sun.COM uint64_t pa; 2007532SSean.Ye@Sun.COM nvlist_t *fmri; 2017532SSean.Ye@Sun.COM int err; 2027532SSean.Ye@Sun.COM 2037532SSean.Ye@Sun.COM if (is_i86xpv) 2047532SSean.Ye@Sun.COM return (ENOTSUP); 2057532SSean.Ye@Sun.COM 2067532SSean.Ye@Sun.COM if ((err = nvlist_lookup_nvlist(invl, FM_PAGE_RETIRE_FMRI, &fmri)) 2077532SSean.Ye@Sun.COM != 0) 2087532SSean.Ye@Sun.COM return (err); 2097532SSean.Ye@Sun.COM 2107532SSean.Ye@Sun.COM if ((err = fm_get_paddr(fmri, &pa)) != 0) 2117532SSean.Ye@Sun.COM return (err); 2127532SSean.Ye@Sun.COM 2137532SSean.Ye@Sun.COM switch (cmd) { 2147532SSean.Ye@Sun.COM case FM_IOC_PAGE_STATUS: 2157532SSean.Ye@Sun.COM return (page_retire_check(pa, NULL)); 2167532SSean.Ye@Sun.COM 2177532SSean.Ye@Sun.COM case FM_IOC_PAGE_RETIRE: 2187532SSean.Ye@Sun.COM return (page_retire(pa, PR_FMA)); 2197532SSean.Ye@Sun.COM 2207532SSean.Ye@Sun.COM case FM_IOC_PAGE_UNRETIRE: 2217532SSean.Ye@Sun.COM return (page_unretire(pa)); 2227532SSean.Ye@Sun.COM } 2237532SSean.Ye@Sun.COM 2247532SSean.Ye@Sun.COM return (ENOTTY); 2257532SSean.Ye@Sun.COM } 2267532SSean.Ye@Sun.COM 2277532SSean.Ye@Sun.COM /*ARGSUSED*/ 2287532SSean.Ye@Sun.COM static int 2297532SSean.Ye@Sun.COM fm_ioctl(dev_t dev, int cmd, intptr_t data, int flag, cred_t *cred, int *rvalp) 2307532SSean.Ye@Sun.COM { 2317532SSean.Ye@Sun.COM char *buf; 2327532SSean.Ye@Sun.COM int err; 2337532SSean.Ye@Sun.COM uint_t model; 2347532SSean.Ye@Sun.COM const fm_subr_t *subr; 2357532SSean.Ye@Sun.COM uint32_t vers; 2367532SSean.Ye@Sun.COM fm_ioc_data_t fid; 2377532SSean.Ye@Sun.COM nvlist_t *invl = NULL, *onvl = NULL; 2387532SSean.Ye@Sun.COM #ifdef _MULTI_DATAMODEL 2397532SSean.Ye@Sun.COM fm_ioc_data32_t fid32; 2407532SSean.Ye@Sun.COM #endif 2417532SSean.Ye@Sun.COM 2427532SSean.Ye@Sun.COM if (getminor(dev) != 0) 2437532SSean.Ye@Sun.COM return (ENXIO); 2447532SSean.Ye@Sun.COM 2457532SSean.Ye@Sun.COM for (subr = fm_subrs; subr->cmd != cmd; subr++) 2467532SSean.Ye@Sun.COM if (subr->cmd == -1) 2477532SSean.Ye@Sun.COM return (ENOTTY); 2487532SSean.Ye@Sun.COM 2497532SSean.Ye@Sun.COM if (subr->priv && (flag & FWRITE) == 0 && 2507532SSean.Ye@Sun.COM secpolicy_sys_config(CRED(), 0) != 0) 2517532SSean.Ye@Sun.COM return (EPERM); 2527532SSean.Ye@Sun.COM 2537532SSean.Ye@Sun.COM model = ddi_model_convert_from(flag & FMODELS); 2547532SSean.Ye@Sun.COM 2557532SSean.Ye@Sun.COM switch (model) { 2567532SSean.Ye@Sun.COM #ifdef _MULTI_DATAMODEL 2577532SSean.Ye@Sun.COM case DDI_MODEL_ILP32: 2587532SSean.Ye@Sun.COM if (ddi_copyin((void *)data, &fid32, 2597532SSean.Ye@Sun.COM sizeof (fm_ioc_data32_t), flag) != 0) 2607532SSean.Ye@Sun.COM return (EFAULT); 2617532SSean.Ye@Sun.COM fid.fid_version = fid32.fid_version; 2627532SSean.Ye@Sun.COM fid.fid_insz = fid32.fid_insz; 2637532SSean.Ye@Sun.COM fid.fid_inbuf = (caddr_t)(uintptr_t)fid32.fid_inbuf; 2647532SSean.Ye@Sun.COM fid.fid_outsz = fid32.fid_outsz; 2657532SSean.Ye@Sun.COM fid.fid_outbuf = (caddr_t)(uintptr_t)fid32.fid_outbuf; 2667532SSean.Ye@Sun.COM break; 2677532SSean.Ye@Sun.COM #endif /* _MULTI_DATAMODEL */ 2687532SSean.Ye@Sun.COM case DDI_MODEL_NONE: 2697532SSean.Ye@Sun.COM default: 2707532SSean.Ye@Sun.COM if (ddi_copyin((void *)data, &fid, sizeof (fm_ioc_data_t), 2717532SSean.Ye@Sun.COM flag) != 0) 2727532SSean.Ye@Sun.COM return (EFAULT); 2737532SSean.Ye@Sun.COM } 2747532SSean.Ye@Sun.COM 2757532SSean.Ye@Sun.COM if (nvlist_lookup_uint32(fm_vers_nvl, subr->version, &vers) != 0 || 2767532SSean.Ye@Sun.COM fid.fid_version != vers) 2777532SSean.Ye@Sun.COM return (ENOTSUP); 2787532SSean.Ye@Sun.COM 2797532SSean.Ye@Sun.COM if (fid.fid_insz > FM_IOC_MAXBUFSZ) 2807532SSean.Ye@Sun.COM return (ENAMETOOLONG); 2817532SSean.Ye@Sun.COM if (fid.fid_outsz > FM_IOC_MAXBUFSZ) 2827532SSean.Ye@Sun.COM return (EINVAL); 2837532SSean.Ye@Sun.COM 2847532SSean.Ye@Sun.COM /* 2857532SSean.Ye@Sun.COM * Copy in and unpack the input nvlist. 2867532SSean.Ye@Sun.COM */ 2877532SSean.Ye@Sun.COM if (fid.fid_insz != 0 && fid.fid_inbuf != (caddr_t)0) { 2887532SSean.Ye@Sun.COM buf = kmem_alloc(fid.fid_insz, KM_SLEEP); 2897532SSean.Ye@Sun.COM if (ddi_copyin(fid.fid_inbuf, buf, fid.fid_insz, flag) != 0) { 2907532SSean.Ye@Sun.COM kmem_free(buf, fid.fid_insz); 2917532SSean.Ye@Sun.COM return (EFAULT); 2927532SSean.Ye@Sun.COM } 2937532SSean.Ye@Sun.COM err = nvlist_unpack(buf, fid.fid_insz, &invl, KM_SLEEP); 2947532SSean.Ye@Sun.COM kmem_free(buf, fid.fid_insz); 2957532SSean.Ye@Sun.COM if (err != 0) 2967532SSean.Ye@Sun.COM return (err); 2977532SSean.Ye@Sun.COM } 2987532SSean.Ye@Sun.COM 2997532SSean.Ye@Sun.COM err = subr->func(cmd, invl, &onvl); 3007532SSean.Ye@Sun.COM 3017532SSean.Ye@Sun.COM if (invl != NULL) 3027532SSean.Ye@Sun.COM nvlist_free(invl); 3037532SSean.Ye@Sun.COM 3047532SSean.Ye@Sun.COM if (err != 0) { 3057532SSean.Ye@Sun.COM if (onvl != NULL) 3067532SSean.Ye@Sun.COM nvlist_free(onvl); 3077532SSean.Ye@Sun.COM return (err); 3087532SSean.Ye@Sun.COM } 3097532SSean.Ye@Sun.COM 3107532SSean.Ye@Sun.COM /* 3117532SSean.Ye@Sun.COM * If the output nvlist contains any data, pack it and copyout. 3127532SSean.Ye@Sun.COM */ 3137532SSean.Ye@Sun.COM if (onvl != NULL) { 3147532SSean.Ye@Sun.COM size_t sz; 3157532SSean.Ye@Sun.COM 3167532SSean.Ye@Sun.COM if ((err = nvlist_size(onvl, &sz, NV_ENCODE_NATIVE)) != 0) { 3177532SSean.Ye@Sun.COM nvlist_free(onvl); 3187532SSean.Ye@Sun.COM return (err); 3197532SSean.Ye@Sun.COM } 3207532SSean.Ye@Sun.COM if (sz > fid.fid_outsz) { 3217532SSean.Ye@Sun.COM nvlist_free(onvl); 3227532SSean.Ye@Sun.COM return (ENAMETOOLONG); 3237532SSean.Ye@Sun.COM } 3247532SSean.Ye@Sun.COM 3257532SSean.Ye@Sun.COM buf = kmem_alloc(sz, KM_SLEEP); 3267532SSean.Ye@Sun.COM if ((err = nvlist_pack(onvl, &buf, &sz, NV_ENCODE_NATIVE, 3277532SSean.Ye@Sun.COM KM_SLEEP)) != 0) { 3287532SSean.Ye@Sun.COM kmem_free(buf, sz); 3297532SSean.Ye@Sun.COM nvlist_free(onvl); 3307532SSean.Ye@Sun.COM return (err); 3317532SSean.Ye@Sun.COM } 3327532SSean.Ye@Sun.COM nvlist_free(onvl); 3337532SSean.Ye@Sun.COM if (ddi_copyout(buf, fid.fid_outbuf, sz, flag) != 0) { 3347532SSean.Ye@Sun.COM kmem_free(buf, sz); 3357532SSean.Ye@Sun.COM return (EFAULT); 3367532SSean.Ye@Sun.COM } 3377532SSean.Ye@Sun.COM kmem_free(buf, sz); 3387532SSean.Ye@Sun.COM fid.fid_outsz = sz; 3397532SSean.Ye@Sun.COM 3407532SSean.Ye@Sun.COM switch (model) { 3417532SSean.Ye@Sun.COM #ifdef _MULTI_DATAMODEL 3427532SSean.Ye@Sun.COM case DDI_MODEL_ILP32: 3437532SSean.Ye@Sun.COM fid32.fid_outsz = (size32_t)fid.fid_outsz; 3447532SSean.Ye@Sun.COM if (ddi_copyout(&fid32, (void *)data, 3457532SSean.Ye@Sun.COM sizeof (fm_ioc_data32_t), flag) != 0) 3467532SSean.Ye@Sun.COM return (EFAULT); 3477532SSean.Ye@Sun.COM break; 3487532SSean.Ye@Sun.COM #endif /* _MULTI_DATAMODEL */ 3497532SSean.Ye@Sun.COM case DDI_MODEL_NONE: 3507532SSean.Ye@Sun.COM default: 3517532SSean.Ye@Sun.COM if (ddi_copyout(&fid, (void *)data, 3527532SSean.Ye@Sun.COM sizeof (fm_ioc_data_t), flag) != 0) 3537532SSean.Ye@Sun.COM return (EFAULT); 3547532SSean.Ye@Sun.COM } 3557532SSean.Ye@Sun.COM } 3567532SSean.Ye@Sun.COM 3577532SSean.Ye@Sun.COM return (err); 3587532SSean.Ye@Sun.COM } 3597532SSean.Ye@Sun.COM 3607532SSean.Ye@Sun.COM static struct cb_ops fm_cb_ops = { 3617532SSean.Ye@Sun.COM fm_open, /* open */ 3627532SSean.Ye@Sun.COM nulldev, /* close */ 3637532SSean.Ye@Sun.COM nodev, /* strategy */ 3647532SSean.Ye@Sun.COM nodev, /* print */ 3657532SSean.Ye@Sun.COM nodev, /* dump */ 3667532SSean.Ye@Sun.COM nodev, /* read */ 3677532SSean.Ye@Sun.COM nodev, /* write */ 3687532SSean.Ye@Sun.COM fm_ioctl, /* ioctl */ 3697532SSean.Ye@Sun.COM nodev, /* devmap */ 3707532SSean.Ye@Sun.COM nodev, /* mmap */ 3717532SSean.Ye@Sun.COM nodev, /* segmap */ 3727532SSean.Ye@Sun.COM nochpoll, /* poll */ 3737532SSean.Ye@Sun.COM ddi_prop_op, /* prop_op */ 3747532SSean.Ye@Sun.COM NULL, /* streamtab */ 3757532SSean.Ye@Sun.COM D_NEW | D_MP | D_64BIT | D_U64BIT 3767532SSean.Ye@Sun.COM }; 3777532SSean.Ye@Sun.COM 3787532SSean.Ye@Sun.COM static struct dev_ops fm_ops = { 3797532SSean.Ye@Sun.COM DEVO_REV, /* devo_rev, */ 3807532SSean.Ye@Sun.COM 0, /* refcnt */ 3817532SSean.Ye@Sun.COM fm_info, /* get_dev_info */ 3827532SSean.Ye@Sun.COM nulldev, /* identify */ 3837532SSean.Ye@Sun.COM nulldev, /* probe */ 3847532SSean.Ye@Sun.COM fm_attach, /* attach */ 3857532SSean.Ye@Sun.COM fm_detach, /* detach */ 3867532SSean.Ye@Sun.COM nodev, /* reset */ 3877532SSean.Ye@Sun.COM &fm_cb_ops, /* driver operations */ 3887532SSean.Ye@Sun.COM (struct bus_ops *)0 /* bus operations */ 3897532SSean.Ye@Sun.COM }; 3907532SSean.Ye@Sun.COM 3917532SSean.Ye@Sun.COM static struct modldrv modldrv = { 3927532SSean.Ye@Sun.COM &mod_driverops, "fault management driver", &fm_ops, 3937532SSean.Ye@Sun.COM }; 3947532SSean.Ye@Sun.COM 3957532SSean.Ye@Sun.COM static struct modlinkage modlinkage = { 3967532SSean.Ye@Sun.COM MODREV_1, &modldrv, NULL 3977532SSean.Ye@Sun.COM }; 3987532SSean.Ye@Sun.COM 3997532SSean.Ye@Sun.COM int 4007532SSean.Ye@Sun.COM _init(void) 4017532SSean.Ye@Sun.COM { 4027532SSean.Ye@Sun.COM const fm_vers_t *p; 4037532SSean.Ye@Sun.COM int ret; 4047532SSean.Ye@Sun.COM 4057532SSean.Ye@Sun.COM 4067532SSean.Ye@Sun.COM if ((ret = mod_install(&modlinkage)) == 0) { 4077532SSean.Ye@Sun.COM (void) nvlist_alloc(&fm_vers_nvl, NV_UNIQUE_NAME, KM_SLEEP); 4087532SSean.Ye@Sun.COM for (p = fm_versions; p->interface != NULL; p++) 4097532SSean.Ye@Sun.COM (void) nvlist_add_uint32(fm_vers_nvl, p->interface, 4107532SSean.Ye@Sun.COM p->version); 4117532SSean.Ye@Sun.COM } 4127532SSean.Ye@Sun.COM 4137532SSean.Ye@Sun.COM return (ret); 4147532SSean.Ye@Sun.COM } 4157532SSean.Ye@Sun.COM 4167532SSean.Ye@Sun.COM int 4177532SSean.Ye@Sun.COM _info(struct modinfo *modinfop) 4187532SSean.Ye@Sun.COM { 4197532SSean.Ye@Sun.COM return (mod_info(&modlinkage, modinfop)); 4207532SSean.Ye@Sun.COM } 4217532SSean.Ye@Sun.COM 4227532SSean.Ye@Sun.COM int 4237532SSean.Ye@Sun.COM _fini(void) 4247532SSean.Ye@Sun.COM { 4257532SSean.Ye@Sun.COM int ret; 4267532SSean.Ye@Sun.COM 4277532SSean.Ye@Sun.COM if ((ret = mod_remove(&modlinkage)) == 0) { 4287532SSean.Ye@Sun.COM if (fm_vers_nvl != NULL) 4297532SSean.Ye@Sun.COM nvlist_free(fm_vers_nvl); 4307532SSean.Ye@Sun.COM } 4317532SSean.Ye@Sun.COM 4327532SSean.Ye@Sun.COM return (ret); 4337532SSean.Ye@Sun.COM } 434