1*7532SSean.Ye@Sun.COM /* 2*7532SSean.Ye@Sun.COM * CDDL HEADER START 3*7532SSean.Ye@Sun.COM * 4*7532SSean.Ye@Sun.COM * The contents of this file are subject to the terms of the 5*7532SSean.Ye@Sun.COM * Common Development and Distribution License (the "License"). 6*7532SSean.Ye@Sun.COM * You may not use this file except in compliance with the License. 7*7532SSean.Ye@Sun.COM * 8*7532SSean.Ye@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*7532SSean.Ye@Sun.COM * or http://www.opensolaris.org/os/licensing. 10*7532SSean.Ye@Sun.COM * See the License for the specific language governing permissions 11*7532SSean.Ye@Sun.COM * and limitations under the License. 12*7532SSean.Ye@Sun.COM * 13*7532SSean.Ye@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 14*7532SSean.Ye@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*7532SSean.Ye@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 16*7532SSean.Ye@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 17*7532SSean.Ye@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 18*7532SSean.Ye@Sun.COM * 19*7532SSean.Ye@Sun.COM * CDDL HEADER END 20*7532SSean.Ye@Sun.COM */ 21*7532SSean.Ye@Sun.COM /* 22*7532SSean.Ye@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23*7532SSean.Ye@Sun.COM * Use is subject to license terms. 24*7532SSean.Ye@Sun.COM */ 25*7532SSean.Ye@Sun.COM 26*7532SSean.Ye@Sun.COM #include <sys/stat.h> 27*7532SSean.Ye@Sun.COM #include <sys/types.h> 28*7532SSean.Ye@Sun.COM #include <sys/param.h> 29*7532SSean.Ye@Sun.COM #include <sys/cred.h> 30*7532SSean.Ye@Sun.COM #include <sys/policy.h> 31*7532SSean.Ye@Sun.COM #include <sys/file.h> 32*7532SSean.Ye@Sun.COM #include <sys/errno.h> 33*7532SSean.Ye@Sun.COM #include <sys/modctl.h> 34*7532SSean.Ye@Sun.COM #include <sys/ddi.h> 35*7532SSean.Ye@Sun.COM #include <sys/sunddi.h> 36*7532SSean.Ye@Sun.COM #include <sys/conf.h> 37*7532SSean.Ye@Sun.COM #include <sys/debug.h> 38*7532SSean.Ye@Sun.COM #include <sys/systeminfo.h> 39*7532SSean.Ye@Sun.COM 40*7532SSean.Ye@Sun.COM #include <sys/fm/protocol.h> 41*7532SSean.Ye@Sun.COM #include <sys/devfm.h> 42*7532SSean.Ye@Sun.COM 43*7532SSean.Ye@Sun.COM extern int fm_get_paddr(nvlist_t *, uint64_t *); 44*7532SSean.Ye@Sun.COM #if defined(__x86) 45*7532SSean.Ye@Sun.COM extern int fm_ioctl_physcpu_info(int, nvlist_t *, nvlist_t **); 46*7532SSean.Ye@Sun.COM extern int fm_ioctl_cpu_retire(int, nvlist_t *, nvlist_t **); 47*7532SSean.Ye@Sun.COM #endif /* __x86 */ 48*7532SSean.Ye@Sun.COM 49*7532SSean.Ye@Sun.COM static int fm_ioctl_versions(int, nvlist_t *, nvlist_t **); 50*7532SSean.Ye@Sun.COM static int fm_ioctl_page_retire(int, nvlist_t *, nvlist_t **); 51*7532SSean.Ye@Sun.COM 52*7532SSean.Ye@Sun.COM /* 53*7532SSean.Ye@Sun.COM * The driver's capabilities are strictly versioned, allowing userland patching 54*7532SSean.Ye@Sun.COM * without a reboot. The userland should start with a FM_VERSIONS ioctl to 55*7532SSean.Ye@Sun.COM * query the versions of the kernel interfaces, then it's all userland's 56*7532SSean.Ye@Sun.COM * responsibility to prepare arguments etc to match the current kenrel. 57*7532SSean.Ye@Sun.COM * The version of FM_VERSIONS itself is FM_DRV_VERSION. 58*7532SSean.Ye@Sun.COM */ 59*7532SSean.Ye@Sun.COM typedef struct fm_version { 60*7532SSean.Ye@Sun.COM char *interface; /* interface name */ 61*7532SSean.Ye@Sun.COM uint32_t version; /* interface version */ 62*7532SSean.Ye@Sun.COM } fm_vers_t; 63*7532SSean.Ye@Sun.COM 64*7532SSean.Ye@Sun.COM typedef struct fm_subroutine { 65*7532SSean.Ye@Sun.COM int cmd; /* ioctl cmd */ 66*7532SSean.Ye@Sun.COM boolean_t priv; /* require privilege */ 67*7532SSean.Ye@Sun.COM char *version; /* version name */ 68*7532SSean.Ye@Sun.COM int (*func)(int, nvlist_t *, nvlist_t **); /* handler */ 69*7532SSean.Ye@Sun.COM } fm_subr_t; 70*7532SSean.Ye@Sun.COM 71*7532SSean.Ye@Sun.COM static const fm_vers_t fm_versions[] = { 72*7532SSean.Ye@Sun.COM { FM_VERSIONS_VERSION, FM_DRV_VERSION }, 73*7532SSean.Ye@Sun.COM { FM_PAGE_OP_VERSION, 1 }, 74*7532SSean.Ye@Sun.COM { FM_CPU_OP_VERSION, 1 }, 75*7532SSean.Ye@Sun.COM { FM_CPU_INFO_VERSION, 1 }, 76*7532SSean.Ye@Sun.COM { NULL, 0 } 77*7532SSean.Ye@Sun.COM }; 78*7532SSean.Ye@Sun.COM 79*7532SSean.Ye@Sun.COM static const fm_subr_t fm_subrs[] = { 80*7532SSean.Ye@Sun.COM { FM_IOC_VERSIONS, B_FALSE, FM_VERSIONS_VERSION, fm_ioctl_versions }, 81*7532SSean.Ye@Sun.COM { FM_IOC_PAGE_RETIRE, B_TRUE, FM_PAGE_OP_VERSION, 82*7532SSean.Ye@Sun.COM fm_ioctl_page_retire }, 83*7532SSean.Ye@Sun.COM { FM_IOC_PAGE_STATUS, B_FALSE, FM_PAGE_OP_VERSION, 84*7532SSean.Ye@Sun.COM fm_ioctl_page_retire }, 85*7532SSean.Ye@Sun.COM { FM_IOC_PAGE_UNRETIRE, B_TRUE, FM_PAGE_OP_VERSION, 86*7532SSean.Ye@Sun.COM fm_ioctl_page_retire }, 87*7532SSean.Ye@Sun.COM #if defined(__x86) 88*7532SSean.Ye@Sun.COM { FM_IOC_PHYSCPU_INFO, B_FALSE, FM_CPU_INFO_VERSION, 89*7532SSean.Ye@Sun.COM fm_ioctl_physcpu_info }, 90*7532SSean.Ye@Sun.COM { FM_IOC_CPU_RETIRE, B_TRUE, FM_CPU_OP_VERSION, 91*7532SSean.Ye@Sun.COM fm_ioctl_cpu_retire }, 92*7532SSean.Ye@Sun.COM { FM_IOC_CPU_STATUS, B_FALSE, FM_CPU_OP_VERSION, 93*7532SSean.Ye@Sun.COM fm_ioctl_cpu_retire }, 94*7532SSean.Ye@Sun.COM { FM_IOC_CPU_UNRETIRE, B_TRUE, FM_CPU_OP_VERSION, 95*7532SSean.Ye@Sun.COM fm_ioctl_cpu_retire }, 96*7532SSean.Ye@Sun.COM #endif /* __x86 */ 97*7532SSean.Ye@Sun.COM { -1, B_FALSE, NULL, NULL }, 98*7532SSean.Ye@Sun.COM }; 99*7532SSean.Ye@Sun.COM 100*7532SSean.Ye@Sun.COM static dev_info_t *fm_dip; 101*7532SSean.Ye@Sun.COM static boolean_t is_i86xpv; 102*7532SSean.Ye@Sun.COM static nvlist_t *fm_vers_nvl; 103*7532SSean.Ye@Sun.COM 104*7532SSean.Ye@Sun.COM static int 105*7532SSean.Ye@Sun.COM fm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 106*7532SSean.Ye@Sun.COM { 107*7532SSean.Ye@Sun.COM switch (cmd) { 108*7532SSean.Ye@Sun.COM case DDI_ATTACH: 109*7532SSean.Ye@Sun.COM if (ddi_create_minor_node(dip, ddi_get_name(dip), S_IFCHR, 110*7532SSean.Ye@Sun.COM ddi_get_instance(dip), DDI_PSEUDO, 0) != DDI_SUCCESS) { 111*7532SSean.Ye@Sun.COM ddi_remove_minor_node(dip, NULL); 112*7532SSean.Ye@Sun.COM return (DDI_FAILURE); 113*7532SSean.Ye@Sun.COM } 114*7532SSean.Ye@Sun.COM fm_dip = dip; 115*7532SSean.Ye@Sun.COM is_i86xpv = (strcmp(platform, "i86xpv") == 0); 116*7532SSean.Ye@Sun.COM break; 117*7532SSean.Ye@Sun.COM case DDI_RESUME: 118*7532SSean.Ye@Sun.COM break; 119*7532SSean.Ye@Sun.COM default: 120*7532SSean.Ye@Sun.COM return (DDI_FAILURE); 121*7532SSean.Ye@Sun.COM } 122*7532SSean.Ye@Sun.COM return (DDI_SUCCESS); 123*7532SSean.Ye@Sun.COM } 124*7532SSean.Ye@Sun.COM 125*7532SSean.Ye@Sun.COM static int 126*7532SSean.Ye@Sun.COM fm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 127*7532SSean.Ye@Sun.COM { 128*7532SSean.Ye@Sun.COM int ret = DDI_SUCCESS; 129*7532SSean.Ye@Sun.COM 130*7532SSean.Ye@Sun.COM switch (cmd) { 131*7532SSean.Ye@Sun.COM case DDI_DETACH: 132*7532SSean.Ye@Sun.COM ddi_remove_minor_node(dip, NULL); 133*7532SSean.Ye@Sun.COM fm_dip = NULL; 134*7532SSean.Ye@Sun.COM break; 135*7532SSean.Ye@Sun.COM default: 136*7532SSean.Ye@Sun.COM ret = DDI_FAILURE; 137*7532SSean.Ye@Sun.COM } 138*7532SSean.Ye@Sun.COM return (ret); 139*7532SSean.Ye@Sun.COM } 140*7532SSean.Ye@Sun.COM 141*7532SSean.Ye@Sun.COM /*ARGSUSED*/ 142*7532SSean.Ye@Sun.COM static int 143*7532SSean.Ye@Sun.COM fm_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 144*7532SSean.Ye@Sun.COM { 145*7532SSean.Ye@Sun.COM int error; 146*7532SSean.Ye@Sun.COM 147*7532SSean.Ye@Sun.COM switch (infocmd) { 148*7532SSean.Ye@Sun.COM case DDI_INFO_DEVT2DEVINFO: 149*7532SSean.Ye@Sun.COM *result = fm_dip; 150*7532SSean.Ye@Sun.COM error = DDI_SUCCESS; 151*7532SSean.Ye@Sun.COM break; 152*7532SSean.Ye@Sun.COM case DDI_INFO_DEVT2INSTANCE: 153*7532SSean.Ye@Sun.COM *result = NULL; 154*7532SSean.Ye@Sun.COM error = DDI_SUCCESS; 155*7532SSean.Ye@Sun.COM break; 156*7532SSean.Ye@Sun.COM default: 157*7532SSean.Ye@Sun.COM error = DDI_FAILURE; 158*7532SSean.Ye@Sun.COM } 159*7532SSean.Ye@Sun.COM return (error); 160*7532SSean.Ye@Sun.COM } 161*7532SSean.Ye@Sun.COM 162*7532SSean.Ye@Sun.COM /*ARGSUSED1*/ 163*7532SSean.Ye@Sun.COM static int 164*7532SSean.Ye@Sun.COM fm_open(dev_t *devp, int flag, int typ, struct cred *cred) 165*7532SSean.Ye@Sun.COM { 166*7532SSean.Ye@Sun.COM if (typ != OTYP_CHR) 167*7532SSean.Ye@Sun.COM return (EINVAL); 168*7532SSean.Ye@Sun.COM if (getminor(*devp) != 0) 169*7532SSean.Ye@Sun.COM return (ENXIO); 170*7532SSean.Ye@Sun.COM 171*7532SSean.Ye@Sun.COM return (0); 172*7532SSean.Ye@Sun.COM } 173*7532SSean.Ye@Sun.COM 174*7532SSean.Ye@Sun.COM /*ARGSUSED*/ 175*7532SSean.Ye@Sun.COM static int 176*7532SSean.Ye@Sun.COM fm_ioctl_versions(int cmd, nvlist_t *invl, nvlist_t **onvlp) 177*7532SSean.Ye@Sun.COM { 178*7532SSean.Ye@Sun.COM nvlist_t *nvl; 179*7532SSean.Ye@Sun.COM int err; 180*7532SSean.Ye@Sun.COM 181*7532SSean.Ye@Sun.COM if ((err = nvlist_dup(fm_vers_nvl, &nvl, KM_SLEEP)) == 0) 182*7532SSean.Ye@Sun.COM *onvlp = nvl; 183*7532SSean.Ye@Sun.COM 184*7532SSean.Ye@Sun.COM return (err); 185*7532SSean.Ye@Sun.COM } 186*7532SSean.Ye@Sun.COM 187*7532SSean.Ye@Sun.COM /* 188*7532SSean.Ye@Sun.COM * Given a mem-scheme FMRI for a page, execute the given page retire 189*7532SSean.Ye@Sun.COM * command on it. 190*7532SSean.Ye@Sun.COM */ 191*7532SSean.Ye@Sun.COM /*ARGSUSED*/ 192*7532SSean.Ye@Sun.COM static int 193*7532SSean.Ye@Sun.COM fm_ioctl_page_retire(int cmd, nvlist_t *invl, nvlist_t **onvlp) 194*7532SSean.Ye@Sun.COM { 195*7532SSean.Ye@Sun.COM uint64_t pa; 196*7532SSean.Ye@Sun.COM nvlist_t *fmri; 197*7532SSean.Ye@Sun.COM int err; 198*7532SSean.Ye@Sun.COM 199*7532SSean.Ye@Sun.COM if (is_i86xpv) 200*7532SSean.Ye@Sun.COM return (ENOTSUP); 201*7532SSean.Ye@Sun.COM 202*7532SSean.Ye@Sun.COM if ((err = nvlist_lookup_nvlist(invl, FM_PAGE_RETIRE_FMRI, &fmri)) 203*7532SSean.Ye@Sun.COM != 0) 204*7532SSean.Ye@Sun.COM return (err); 205*7532SSean.Ye@Sun.COM 206*7532SSean.Ye@Sun.COM if ((err = fm_get_paddr(fmri, &pa)) != 0) 207*7532SSean.Ye@Sun.COM return (err); 208*7532SSean.Ye@Sun.COM 209*7532SSean.Ye@Sun.COM switch (cmd) { 210*7532SSean.Ye@Sun.COM case FM_IOC_PAGE_STATUS: 211*7532SSean.Ye@Sun.COM return (page_retire_check(pa, NULL)); 212*7532SSean.Ye@Sun.COM 213*7532SSean.Ye@Sun.COM case FM_IOC_PAGE_RETIRE: 214*7532SSean.Ye@Sun.COM return (page_retire(pa, PR_FMA)); 215*7532SSean.Ye@Sun.COM 216*7532SSean.Ye@Sun.COM case FM_IOC_PAGE_UNRETIRE: 217*7532SSean.Ye@Sun.COM return (page_unretire(pa)); 218*7532SSean.Ye@Sun.COM } 219*7532SSean.Ye@Sun.COM 220*7532SSean.Ye@Sun.COM return (ENOTTY); 221*7532SSean.Ye@Sun.COM } 222*7532SSean.Ye@Sun.COM 223*7532SSean.Ye@Sun.COM /*ARGSUSED*/ 224*7532SSean.Ye@Sun.COM static int 225*7532SSean.Ye@Sun.COM fm_ioctl(dev_t dev, int cmd, intptr_t data, int flag, cred_t *cred, int *rvalp) 226*7532SSean.Ye@Sun.COM { 227*7532SSean.Ye@Sun.COM char *buf; 228*7532SSean.Ye@Sun.COM int err; 229*7532SSean.Ye@Sun.COM uint_t model; 230*7532SSean.Ye@Sun.COM const fm_subr_t *subr; 231*7532SSean.Ye@Sun.COM uint32_t vers; 232*7532SSean.Ye@Sun.COM fm_ioc_data_t fid; 233*7532SSean.Ye@Sun.COM nvlist_t *invl = NULL, *onvl = NULL; 234*7532SSean.Ye@Sun.COM #ifdef _MULTI_DATAMODEL 235*7532SSean.Ye@Sun.COM fm_ioc_data32_t fid32; 236*7532SSean.Ye@Sun.COM #endif 237*7532SSean.Ye@Sun.COM 238*7532SSean.Ye@Sun.COM if (getminor(dev) != 0) 239*7532SSean.Ye@Sun.COM return (ENXIO); 240*7532SSean.Ye@Sun.COM 241*7532SSean.Ye@Sun.COM for (subr = fm_subrs; subr->cmd != cmd; subr++) 242*7532SSean.Ye@Sun.COM if (subr->cmd == -1) 243*7532SSean.Ye@Sun.COM return (ENOTTY); 244*7532SSean.Ye@Sun.COM 245*7532SSean.Ye@Sun.COM if (subr->priv && (flag & FWRITE) == 0 && 246*7532SSean.Ye@Sun.COM secpolicy_sys_config(CRED(), 0) != 0) 247*7532SSean.Ye@Sun.COM return (EPERM); 248*7532SSean.Ye@Sun.COM 249*7532SSean.Ye@Sun.COM model = ddi_model_convert_from(flag & FMODELS); 250*7532SSean.Ye@Sun.COM 251*7532SSean.Ye@Sun.COM switch (model) { 252*7532SSean.Ye@Sun.COM #ifdef _MULTI_DATAMODEL 253*7532SSean.Ye@Sun.COM case DDI_MODEL_ILP32: 254*7532SSean.Ye@Sun.COM if (ddi_copyin((void *)data, &fid32, 255*7532SSean.Ye@Sun.COM sizeof (fm_ioc_data32_t), flag) != 0) 256*7532SSean.Ye@Sun.COM return (EFAULT); 257*7532SSean.Ye@Sun.COM fid.fid_version = fid32.fid_version; 258*7532SSean.Ye@Sun.COM fid.fid_insz = fid32.fid_insz; 259*7532SSean.Ye@Sun.COM fid.fid_inbuf = (caddr_t)(uintptr_t)fid32.fid_inbuf; 260*7532SSean.Ye@Sun.COM fid.fid_outsz = fid32.fid_outsz; 261*7532SSean.Ye@Sun.COM fid.fid_outbuf = (caddr_t)(uintptr_t)fid32.fid_outbuf; 262*7532SSean.Ye@Sun.COM break; 263*7532SSean.Ye@Sun.COM #endif /* _MULTI_DATAMODEL */ 264*7532SSean.Ye@Sun.COM case DDI_MODEL_NONE: 265*7532SSean.Ye@Sun.COM default: 266*7532SSean.Ye@Sun.COM if (ddi_copyin((void *)data, &fid, sizeof (fm_ioc_data_t), 267*7532SSean.Ye@Sun.COM flag) != 0) 268*7532SSean.Ye@Sun.COM return (EFAULT); 269*7532SSean.Ye@Sun.COM } 270*7532SSean.Ye@Sun.COM 271*7532SSean.Ye@Sun.COM if (nvlist_lookup_uint32(fm_vers_nvl, subr->version, &vers) != 0 || 272*7532SSean.Ye@Sun.COM fid.fid_version != vers) 273*7532SSean.Ye@Sun.COM return (ENOTSUP); 274*7532SSean.Ye@Sun.COM 275*7532SSean.Ye@Sun.COM if (fid.fid_insz > FM_IOC_MAXBUFSZ) 276*7532SSean.Ye@Sun.COM return (ENAMETOOLONG); 277*7532SSean.Ye@Sun.COM if (fid.fid_outsz > FM_IOC_MAXBUFSZ) 278*7532SSean.Ye@Sun.COM return (EINVAL); 279*7532SSean.Ye@Sun.COM 280*7532SSean.Ye@Sun.COM /* 281*7532SSean.Ye@Sun.COM * Copy in and unpack the input nvlist. 282*7532SSean.Ye@Sun.COM */ 283*7532SSean.Ye@Sun.COM if (fid.fid_insz != 0 && fid.fid_inbuf != (caddr_t)0) { 284*7532SSean.Ye@Sun.COM buf = kmem_alloc(fid.fid_insz, KM_SLEEP); 285*7532SSean.Ye@Sun.COM if (ddi_copyin(fid.fid_inbuf, buf, fid.fid_insz, flag) != 0) { 286*7532SSean.Ye@Sun.COM kmem_free(buf, fid.fid_insz); 287*7532SSean.Ye@Sun.COM return (EFAULT); 288*7532SSean.Ye@Sun.COM } 289*7532SSean.Ye@Sun.COM err = nvlist_unpack(buf, fid.fid_insz, &invl, KM_SLEEP); 290*7532SSean.Ye@Sun.COM kmem_free(buf, fid.fid_insz); 291*7532SSean.Ye@Sun.COM if (err != 0) 292*7532SSean.Ye@Sun.COM return (err); 293*7532SSean.Ye@Sun.COM } 294*7532SSean.Ye@Sun.COM 295*7532SSean.Ye@Sun.COM err = subr->func(cmd, invl, &onvl); 296*7532SSean.Ye@Sun.COM 297*7532SSean.Ye@Sun.COM if (invl != NULL) 298*7532SSean.Ye@Sun.COM nvlist_free(invl); 299*7532SSean.Ye@Sun.COM 300*7532SSean.Ye@Sun.COM if (err != 0) { 301*7532SSean.Ye@Sun.COM if (onvl != NULL) 302*7532SSean.Ye@Sun.COM nvlist_free(onvl); 303*7532SSean.Ye@Sun.COM return (err); 304*7532SSean.Ye@Sun.COM } 305*7532SSean.Ye@Sun.COM 306*7532SSean.Ye@Sun.COM /* 307*7532SSean.Ye@Sun.COM * If the output nvlist contains any data, pack it and copyout. 308*7532SSean.Ye@Sun.COM */ 309*7532SSean.Ye@Sun.COM if (onvl != NULL) { 310*7532SSean.Ye@Sun.COM size_t sz; 311*7532SSean.Ye@Sun.COM 312*7532SSean.Ye@Sun.COM if ((err = nvlist_size(onvl, &sz, NV_ENCODE_NATIVE)) != 0) { 313*7532SSean.Ye@Sun.COM nvlist_free(onvl); 314*7532SSean.Ye@Sun.COM return (err); 315*7532SSean.Ye@Sun.COM } 316*7532SSean.Ye@Sun.COM if (sz > fid.fid_outsz) { 317*7532SSean.Ye@Sun.COM nvlist_free(onvl); 318*7532SSean.Ye@Sun.COM return (ENAMETOOLONG); 319*7532SSean.Ye@Sun.COM } 320*7532SSean.Ye@Sun.COM 321*7532SSean.Ye@Sun.COM buf = kmem_alloc(sz, KM_SLEEP); 322*7532SSean.Ye@Sun.COM if ((err = nvlist_pack(onvl, &buf, &sz, NV_ENCODE_NATIVE, 323*7532SSean.Ye@Sun.COM KM_SLEEP)) != 0) { 324*7532SSean.Ye@Sun.COM kmem_free(buf, sz); 325*7532SSean.Ye@Sun.COM nvlist_free(onvl); 326*7532SSean.Ye@Sun.COM return (err); 327*7532SSean.Ye@Sun.COM } 328*7532SSean.Ye@Sun.COM nvlist_free(onvl); 329*7532SSean.Ye@Sun.COM if (ddi_copyout(buf, fid.fid_outbuf, sz, flag) != 0) { 330*7532SSean.Ye@Sun.COM kmem_free(buf, sz); 331*7532SSean.Ye@Sun.COM return (EFAULT); 332*7532SSean.Ye@Sun.COM } 333*7532SSean.Ye@Sun.COM kmem_free(buf, sz); 334*7532SSean.Ye@Sun.COM fid.fid_outsz = sz; 335*7532SSean.Ye@Sun.COM 336*7532SSean.Ye@Sun.COM switch (model) { 337*7532SSean.Ye@Sun.COM #ifdef _MULTI_DATAMODEL 338*7532SSean.Ye@Sun.COM case DDI_MODEL_ILP32: 339*7532SSean.Ye@Sun.COM fid32.fid_outsz = (size32_t)fid.fid_outsz; 340*7532SSean.Ye@Sun.COM if (ddi_copyout(&fid32, (void *)data, 341*7532SSean.Ye@Sun.COM sizeof (fm_ioc_data32_t), flag) != 0) 342*7532SSean.Ye@Sun.COM return (EFAULT); 343*7532SSean.Ye@Sun.COM break; 344*7532SSean.Ye@Sun.COM #endif /* _MULTI_DATAMODEL */ 345*7532SSean.Ye@Sun.COM case DDI_MODEL_NONE: 346*7532SSean.Ye@Sun.COM default: 347*7532SSean.Ye@Sun.COM if (ddi_copyout(&fid, (void *)data, 348*7532SSean.Ye@Sun.COM sizeof (fm_ioc_data_t), flag) != 0) 349*7532SSean.Ye@Sun.COM return (EFAULT); 350*7532SSean.Ye@Sun.COM } 351*7532SSean.Ye@Sun.COM } 352*7532SSean.Ye@Sun.COM 353*7532SSean.Ye@Sun.COM return (err); 354*7532SSean.Ye@Sun.COM } 355*7532SSean.Ye@Sun.COM 356*7532SSean.Ye@Sun.COM static struct cb_ops fm_cb_ops = { 357*7532SSean.Ye@Sun.COM fm_open, /* open */ 358*7532SSean.Ye@Sun.COM nulldev, /* close */ 359*7532SSean.Ye@Sun.COM nodev, /* strategy */ 360*7532SSean.Ye@Sun.COM nodev, /* print */ 361*7532SSean.Ye@Sun.COM nodev, /* dump */ 362*7532SSean.Ye@Sun.COM nodev, /* read */ 363*7532SSean.Ye@Sun.COM nodev, /* write */ 364*7532SSean.Ye@Sun.COM fm_ioctl, /* ioctl */ 365*7532SSean.Ye@Sun.COM nodev, /* devmap */ 366*7532SSean.Ye@Sun.COM nodev, /* mmap */ 367*7532SSean.Ye@Sun.COM nodev, /* segmap */ 368*7532SSean.Ye@Sun.COM nochpoll, /* poll */ 369*7532SSean.Ye@Sun.COM ddi_prop_op, /* prop_op */ 370*7532SSean.Ye@Sun.COM NULL, /* streamtab */ 371*7532SSean.Ye@Sun.COM D_NEW | D_MP | D_64BIT | D_U64BIT 372*7532SSean.Ye@Sun.COM }; 373*7532SSean.Ye@Sun.COM 374*7532SSean.Ye@Sun.COM static struct dev_ops fm_ops = { 375*7532SSean.Ye@Sun.COM DEVO_REV, /* devo_rev, */ 376*7532SSean.Ye@Sun.COM 0, /* refcnt */ 377*7532SSean.Ye@Sun.COM fm_info, /* get_dev_info */ 378*7532SSean.Ye@Sun.COM nulldev, /* identify */ 379*7532SSean.Ye@Sun.COM nulldev, /* probe */ 380*7532SSean.Ye@Sun.COM fm_attach, /* attach */ 381*7532SSean.Ye@Sun.COM fm_detach, /* detach */ 382*7532SSean.Ye@Sun.COM nodev, /* reset */ 383*7532SSean.Ye@Sun.COM &fm_cb_ops, /* driver operations */ 384*7532SSean.Ye@Sun.COM (struct bus_ops *)0 /* bus operations */ 385*7532SSean.Ye@Sun.COM }; 386*7532SSean.Ye@Sun.COM 387*7532SSean.Ye@Sun.COM static struct modldrv modldrv = { 388*7532SSean.Ye@Sun.COM &mod_driverops, "fault management driver", &fm_ops, 389*7532SSean.Ye@Sun.COM }; 390*7532SSean.Ye@Sun.COM 391*7532SSean.Ye@Sun.COM static struct modlinkage modlinkage = { 392*7532SSean.Ye@Sun.COM MODREV_1, &modldrv, NULL 393*7532SSean.Ye@Sun.COM }; 394*7532SSean.Ye@Sun.COM 395*7532SSean.Ye@Sun.COM int 396*7532SSean.Ye@Sun.COM _init(void) 397*7532SSean.Ye@Sun.COM { 398*7532SSean.Ye@Sun.COM const fm_vers_t *p; 399*7532SSean.Ye@Sun.COM int ret; 400*7532SSean.Ye@Sun.COM 401*7532SSean.Ye@Sun.COM 402*7532SSean.Ye@Sun.COM if ((ret = mod_install(&modlinkage)) == 0) { 403*7532SSean.Ye@Sun.COM (void) nvlist_alloc(&fm_vers_nvl, NV_UNIQUE_NAME, KM_SLEEP); 404*7532SSean.Ye@Sun.COM for (p = fm_versions; p->interface != NULL; p++) 405*7532SSean.Ye@Sun.COM (void) nvlist_add_uint32(fm_vers_nvl, p->interface, 406*7532SSean.Ye@Sun.COM p->version); 407*7532SSean.Ye@Sun.COM } 408*7532SSean.Ye@Sun.COM 409*7532SSean.Ye@Sun.COM return (ret); 410*7532SSean.Ye@Sun.COM } 411*7532SSean.Ye@Sun.COM 412*7532SSean.Ye@Sun.COM int 413*7532SSean.Ye@Sun.COM _info(struct modinfo *modinfop) 414*7532SSean.Ye@Sun.COM { 415*7532SSean.Ye@Sun.COM return (mod_info(&modlinkage, modinfop)); 416*7532SSean.Ye@Sun.COM } 417*7532SSean.Ye@Sun.COM 418*7532SSean.Ye@Sun.COM int 419*7532SSean.Ye@Sun.COM _fini(void) 420*7532SSean.Ye@Sun.COM { 421*7532SSean.Ye@Sun.COM int ret; 422*7532SSean.Ye@Sun.COM 423*7532SSean.Ye@Sun.COM if ((ret = mod_remove(&modlinkage)) == 0) { 424*7532SSean.Ye@Sun.COM if (fm_vers_nvl != NULL) 425*7532SSean.Ye@Sun.COM nvlist_free(fm_vers_nvl); 426*7532SSean.Ye@Sun.COM } 427*7532SSean.Ye@Sun.COM 428*7532SSean.Ye@Sun.COM return (ret); 429*7532SSean.Ye@Sun.COM } 430