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