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