1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <sys/types.h> 30*0Sstevel@tonic-gate #include <sys/param.h> 31*0Sstevel@tonic-gate #include <sys/systm.h> 32*0Sstevel@tonic-gate #include <sys/buf.h> 33*0Sstevel@tonic-gate #include <sys/uio.h> 34*0Sstevel@tonic-gate #include <sys/cred.h> 35*0Sstevel@tonic-gate #include <sys/poll.h> 36*0Sstevel@tonic-gate #include <sys/mman.h> 37*0Sstevel@tonic-gate #include <sys/kmem.h> 38*0Sstevel@tonic-gate #include <sys/model.h> 39*0Sstevel@tonic-gate #include <sys/file.h> 40*0Sstevel@tonic-gate #include <sys/proc.h> 41*0Sstevel@tonic-gate #include <sys/open.h> 42*0Sstevel@tonic-gate #include <sys/user.h> 43*0Sstevel@tonic-gate #include <sys/t_lock.h> 44*0Sstevel@tonic-gate #include <sys/vm.h> 45*0Sstevel@tonic-gate #include <sys/stat.h> 46*0Sstevel@tonic-gate #include <vm/hat.h> 47*0Sstevel@tonic-gate #include <vm/seg.h> 48*0Sstevel@tonic-gate #include <vm/as.h> 49*0Sstevel@tonic-gate #include <sys/cmn_err.h> 50*0Sstevel@tonic-gate #include <sys/debug.h> 51*0Sstevel@tonic-gate #include <sys/avintr.h> 52*0Sstevel@tonic-gate #include <sys/autoconf.h> 53*0Sstevel@tonic-gate #include <sys/sunddi.h> 54*0Sstevel@tonic-gate #include <sys/esunddi.h> 55*0Sstevel@tonic-gate #include <sys/sunndi.h> 56*0Sstevel@tonic-gate #include <sys/ddi.h> 57*0Sstevel@tonic-gate #include <sys/kstat.h> 58*0Sstevel@tonic-gate #include <sys/conf.h> 59*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h> /* include implementation structure defs */ 60*0Sstevel@tonic-gate #include <sys/ndi_impldefs.h> 61*0Sstevel@tonic-gate #include <sys/hwconf.h> 62*0Sstevel@tonic-gate #include <sys/pathname.h> 63*0Sstevel@tonic-gate #include <sys/modctl.h> 64*0Sstevel@tonic-gate #include <sys/epm.h> 65*0Sstevel@tonic-gate #include <sys/devctl.h> 66*0Sstevel@tonic-gate #include <sys/callb.h> 67*0Sstevel@tonic-gate #include <sys/bootconf.h> 68*0Sstevel@tonic-gate #include <sys/dacf_impl.h> 69*0Sstevel@tonic-gate #include <sys/nvpair.h> 70*0Sstevel@tonic-gate #include <sys/sunmdi.h> 71*0Sstevel@tonic-gate #include <sys/fs/dv_node.h> 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate #ifdef __sparc 74*0Sstevel@tonic-gate #include <sys/archsystm.h> /* getpil/setpil */ 75*0Sstevel@tonic-gate #include <sys/membar.h> /* membar_sync */ 76*0Sstevel@tonic-gate #endif 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate /* 79*0Sstevel@tonic-gate * ndi property handling 80*0Sstevel@tonic-gate */ 81*0Sstevel@tonic-gate int 82*0Sstevel@tonic-gate ndi_prop_update_int(dev_t match_dev, dev_info_t *dip, 83*0Sstevel@tonic-gate char *name, int data) 84*0Sstevel@tonic-gate { 85*0Sstevel@tonic-gate return (ddi_prop_update_common(match_dev, dip, 86*0Sstevel@tonic-gate DDI_PROP_HW_DEF | DDI_PROP_TYPE_INT | DDI_PROP_DONTSLEEP, 87*0Sstevel@tonic-gate name, &data, 1, ddi_prop_fm_encode_ints)); 88*0Sstevel@tonic-gate } 89*0Sstevel@tonic-gate 90*0Sstevel@tonic-gate int 91*0Sstevel@tonic-gate ndi_prop_update_int64(dev_t match_dev, dev_info_t *dip, 92*0Sstevel@tonic-gate char *name, int64_t data) 93*0Sstevel@tonic-gate { 94*0Sstevel@tonic-gate return (ddi_prop_update_common(match_dev, dip, 95*0Sstevel@tonic-gate DDI_PROP_HW_DEF | DDI_PROP_TYPE_INT64 | DDI_PROP_DONTSLEEP, 96*0Sstevel@tonic-gate name, &data, 1, ddi_prop_fm_encode_int64)); 97*0Sstevel@tonic-gate } 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate int 100*0Sstevel@tonic-gate ndi_prop_create_boolean(dev_t match_dev, dev_info_t *dip, 101*0Sstevel@tonic-gate char *name) 102*0Sstevel@tonic-gate { 103*0Sstevel@tonic-gate return (ddi_prop_update_common(match_dev, dip, 104*0Sstevel@tonic-gate DDI_PROP_HW_DEF | DDI_PROP_TYPE_ANY | DDI_PROP_DONTSLEEP, 105*0Sstevel@tonic-gate name, NULL, 0, ddi_prop_fm_encode_bytes)); 106*0Sstevel@tonic-gate } 107*0Sstevel@tonic-gate 108*0Sstevel@tonic-gate int 109*0Sstevel@tonic-gate ndi_prop_update_int_array(dev_t match_dev, dev_info_t *dip, 110*0Sstevel@tonic-gate char *name, int *data, uint_t nelements) 111*0Sstevel@tonic-gate { 112*0Sstevel@tonic-gate return (ddi_prop_update_common(match_dev, dip, 113*0Sstevel@tonic-gate DDI_PROP_HW_DEF | DDI_PROP_TYPE_INT | DDI_PROP_DONTSLEEP, 114*0Sstevel@tonic-gate name, data, nelements, ddi_prop_fm_encode_ints)); 115*0Sstevel@tonic-gate } 116*0Sstevel@tonic-gate 117*0Sstevel@tonic-gate int 118*0Sstevel@tonic-gate ndi_prop_update_int64_array(dev_t match_dev, dev_info_t *dip, 119*0Sstevel@tonic-gate char *name, int64_t *data, uint_t nelements) 120*0Sstevel@tonic-gate { 121*0Sstevel@tonic-gate return (ddi_prop_update_common(match_dev, dip, 122*0Sstevel@tonic-gate DDI_PROP_HW_DEF | DDI_PROP_TYPE_INT64 | DDI_PROP_DONTSLEEP, 123*0Sstevel@tonic-gate name, data, nelements, ddi_prop_fm_encode_int64)); 124*0Sstevel@tonic-gate } 125*0Sstevel@tonic-gate 126*0Sstevel@tonic-gate int 127*0Sstevel@tonic-gate ndi_prop_update_string(dev_t match_dev, dev_info_t *dip, 128*0Sstevel@tonic-gate char *name, char *data) 129*0Sstevel@tonic-gate { 130*0Sstevel@tonic-gate return (ddi_prop_update_common(match_dev, dip, 131*0Sstevel@tonic-gate DDI_PROP_HW_DEF | DDI_PROP_TYPE_STRING | DDI_PROP_DONTSLEEP, 132*0Sstevel@tonic-gate name, &data, 1, ddi_prop_fm_encode_string)); 133*0Sstevel@tonic-gate } 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate int 136*0Sstevel@tonic-gate ndi_prop_update_string_array(dev_t match_dev, dev_info_t *dip, 137*0Sstevel@tonic-gate char *name, char **data, uint_t nelements) 138*0Sstevel@tonic-gate { 139*0Sstevel@tonic-gate return (ddi_prop_update_common(match_dev, dip, 140*0Sstevel@tonic-gate DDI_PROP_HW_DEF | DDI_PROP_TYPE_STRING | DDI_PROP_DONTSLEEP, 141*0Sstevel@tonic-gate name, data, nelements, 142*0Sstevel@tonic-gate ddi_prop_fm_encode_strings)); 143*0Sstevel@tonic-gate } 144*0Sstevel@tonic-gate 145*0Sstevel@tonic-gate int 146*0Sstevel@tonic-gate ndi_prop_update_byte_array(dev_t match_dev, dev_info_t *dip, 147*0Sstevel@tonic-gate char *name, uchar_t *data, uint_t nelements) 148*0Sstevel@tonic-gate { 149*0Sstevel@tonic-gate if (nelements == 0) 150*0Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 151*0Sstevel@tonic-gate 152*0Sstevel@tonic-gate return (ddi_prop_update_common(match_dev, dip, 153*0Sstevel@tonic-gate DDI_PROP_HW_DEF | DDI_PROP_TYPE_BYTE | DDI_PROP_DONTSLEEP, 154*0Sstevel@tonic-gate name, data, nelements, ddi_prop_fm_encode_bytes)); 155*0Sstevel@tonic-gate } 156*0Sstevel@tonic-gate 157*0Sstevel@tonic-gate int 158*0Sstevel@tonic-gate ndi_prop_remove(dev_t dev, dev_info_t *dip, char *name) 159*0Sstevel@tonic-gate { 160*0Sstevel@tonic-gate return (ddi_prop_remove_common(dev, dip, name, DDI_PROP_HW_DEF)); 161*0Sstevel@tonic-gate } 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate void 164*0Sstevel@tonic-gate ndi_prop_remove_all(dev_info_t *dip) 165*0Sstevel@tonic-gate { 166*0Sstevel@tonic-gate ddi_prop_remove_all_common(dip, (int)DDI_PROP_HW_DEF); 167*0Sstevel@tonic-gate } 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate /* 170*0Sstevel@tonic-gate * Post an event notification to nexus driver responsible for handling 171*0Sstevel@tonic-gate * the event. The responsible nexus is defined in the cookie passed in as 172*0Sstevel@tonic-gate * the third parameter. 173*0Sstevel@tonic-gate * The dip parameter is an artifact of an older implementation in which all 174*0Sstevel@tonic-gate * requests to remove an eventcall would bubble up the tree. Today, this 175*0Sstevel@tonic-gate * parameter is ignored. 176*0Sstevel@tonic-gate * Input Parameters: 177*0Sstevel@tonic-gate * dip - Ignored. 178*0Sstevel@tonic-gate * rdip - device driver posting the event 179*0Sstevel@tonic-gate * cookie - valid ddi_eventcookie_t, obtained by caller prior to 180*0Sstevel@tonic-gate * invocation of this routine 181*0Sstevel@tonic-gate * impl_data - used by framework 182*0Sstevel@tonic-gate */ 183*0Sstevel@tonic-gate /*ARGSUSED*/ 184*0Sstevel@tonic-gate int 185*0Sstevel@tonic-gate ndi_post_event(dev_info_t *dip, dev_info_t *rdip, 186*0Sstevel@tonic-gate ddi_eventcookie_t cookie, void *impl_data) 187*0Sstevel@tonic-gate { 188*0Sstevel@tonic-gate dev_info_t *ddip; 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gate ASSERT(cookie); 191*0Sstevel@tonic-gate ddip = NDI_EVENT_DDIP(cookie); 192*0Sstevel@tonic-gate 193*0Sstevel@tonic-gate /* 194*0Sstevel@tonic-gate * perform sanity checks. These conditions should never be true. 195*0Sstevel@tonic-gate */ 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate ASSERT(DEVI(ddip)->devi_ops->devo_bus_ops != NULL); 198*0Sstevel@tonic-gate ASSERT(DEVI(ddip)->devi_ops->devo_bus_ops->busops_rev >= BUSO_REV_6); 199*0Sstevel@tonic-gate ASSERT(DEVI(ddip)->devi_ops->devo_bus_ops->bus_post_event != NULL); 200*0Sstevel@tonic-gate 201*0Sstevel@tonic-gate /* 202*0Sstevel@tonic-gate * post the event to the responsible ancestor 203*0Sstevel@tonic-gate */ 204*0Sstevel@tonic-gate return ((*(DEVI(ddip)->devi_ops->devo_bus_ops->bus_post_event)) 205*0Sstevel@tonic-gate (ddip, rdip, cookie, impl_data)); 206*0Sstevel@tonic-gate } 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gate /* 209*0Sstevel@tonic-gate * Calls the bus nexus driver's implementation of the 210*0Sstevel@tonic-gate * (*bus_remove_eventcall)() interface. 211*0Sstevel@tonic-gate */ 212*0Sstevel@tonic-gate int 213*0Sstevel@tonic-gate ndi_busop_remove_eventcall(dev_info_t *ddip, ddi_callback_id_t id) 214*0Sstevel@tonic-gate { 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gate ASSERT(id); 217*0Sstevel@tonic-gate /* check for a correct revno before calling up the device tree. */ 218*0Sstevel@tonic-gate ASSERT(DEVI(ddip)->devi_ops->devo_bus_ops != NULL); 219*0Sstevel@tonic-gate ASSERT(DEVI(ddip)->devi_ops->devo_bus_ops->busops_rev >= BUSO_REV_6); 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate if (DEVI(ddip)->devi_ops->devo_bus_ops->bus_remove_eventcall == NULL) 222*0Sstevel@tonic-gate return (DDI_FAILURE); 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate /* 225*0Sstevel@tonic-gate * request responsible nexus to remove the eventcall 226*0Sstevel@tonic-gate */ 227*0Sstevel@tonic-gate return ((*(DEVI(ddip)->devi_ops->devo_bus_ops->bus_remove_eventcall)) 228*0Sstevel@tonic-gate (ddip, id)); 229*0Sstevel@tonic-gate } 230*0Sstevel@tonic-gate 231*0Sstevel@tonic-gate /* 232*0Sstevel@tonic-gate * Calls the bus nexus driver's implementation of the 233*0Sstevel@tonic-gate * (*bus_add_eventcall)() interface. The dip parameter is an 234*0Sstevel@tonic-gate * artifact of an older implementation in which all requests to 235*0Sstevel@tonic-gate * add an eventcall would bubble up the tree. Today, this parameter is 236*0Sstevel@tonic-gate * ignored. 237*0Sstevel@tonic-gate */ 238*0Sstevel@tonic-gate /*ARGSUSED*/ 239*0Sstevel@tonic-gate int 240*0Sstevel@tonic-gate ndi_busop_add_eventcall(dev_info_t *dip, dev_info_t *rdip, 241*0Sstevel@tonic-gate ddi_eventcookie_t cookie, void (*callback)(), void *arg, 242*0Sstevel@tonic-gate ddi_callback_id_t *cb_id) 243*0Sstevel@tonic-gate { 244*0Sstevel@tonic-gate dev_info_t *ddip = (dev_info_t *)NDI_EVENT_DDIP(cookie); 245*0Sstevel@tonic-gate 246*0Sstevel@tonic-gate /* 247*0Sstevel@tonic-gate * check for a correct revno before calling up the device tree. 248*0Sstevel@tonic-gate */ 249*0Sstevel@tonic-gate ASSERT(DEVI(ddip)->devi_ops->devo_bus_ops != NULL); 250*0Sstevel@tonic-gate ASSERT(DEVI(ddip)->devi_ops->devo_bus_ops->busops_rev >= BUSO_REV_6); 251*0Sstevel@tonic-gate 252*0Sstevel@tonic-gate if (DEVI(ddip)->devi_ops->devo_bus_ops->bus_add_eventcall == NULL) 253*0Sstevel@tonic-gate return (DDI_FAILURE); 254*0Sstevel@tonic-gate 255*0Sstevel@tonic-gate /* 256*0Sstevel@tonic-gate * request responsible ancestor to add the eventcall 257*0Sstevel@tonic-gate */ 258*0Sstevel@tonic-gate return ((*(DEVI(ddip)->devi_ops->devo_bus_ops->bus_add_eventcall)) 259*0Sstevel@tonic-gate (ddip, rdip, cookie, callback, arg, cb_id)); 260*0Sstevel@tonic-gate } 261*0Sstevel@tonic-gate 262*0Sstevel@tonic-gate /* 263*0Sstevel@tonic-gate * Calls the bus nexus driver's implementation of the 264*0Sstevel@tonic-gate * (*bus_get_eventcookie)() interface up the device tree hierarchy. 265*0Sstevel@tonic-gate */ 266*0Sstevel@tonic-gate int 267*0Sstevel@tonic-gate ndi_busop_get_eventcookie(dev_info_t *dip, dev_info_t *rdip, char *name, 268*0Sstevel@tonic-gate ddi_eventcookie_t *event_cookiep) 269*0Sstevel@tonic-gate { 270*0Sstevel@tonic-gate dev_info_t *pdip = (dev_info_t *)DEVI(dip)->devi_parent; 271*0Sstevel@tonic-gate 272*0Sstevel@tonic-gate /* Can not be called from rootnex. */ 273*0Sstevel@tonic-gate ASSERT(pdip); 274*0Sstevel@tonic-gate 275*0Sstevel@tonic-gate /* 276*0Sstevel@tonic-gate * check for a correct revno before calling up the device tree. 277*0Sstevel@tonic-gate */ 278*0Sstevel@tonic-gate ASSERT(DEVI(pdip)->devi_ops->devo_bus_ops != NULL); 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gate if ((DEVI(pdip)->devi_ops->devo_bus_ops->busops_rev < BUSO_REV_6) || 281*0Sstevel@tonic-gate (DEVI(pdip)->devi_ops->devo_bus_ops->bus_get_eventcookie == NULL)) { 282*0Sstevel@tonic-gate #ifdef DEBUG 283*0Sstevel@tonic-gate if ((DEVI(pdip)->devi_ops->devo_bus_ops->busops_rev >= 284*0Sstevel@tonic-gate BUSO_REV_3) && 285*0Sstevel@tonic-gate (DEVI(pdip)->devi_ops->devo_bus_ops->bus_get_eventcookie)) { 286*0Sstevel@tonic-gate cmn_err(CE_WARN, 287*0Sstevel@tonic-gate "Warning: %s%d busops_rev=%d no longer supported" 288*0Sstevel@tonic-gate " by the NDI event framework.\nBUSO_REV_6 or " 289*0Sstevel@tonic-gate "greater must be used.", 290*0Sstevel@tonic-gate DEVI(pdip)->devi_binding_name, 291*0Sstevel@tonic-gate DEVI(pdip)->devi_instance, 292*0Sstevel@tonic-gate DEVI(pdip)->devi_ops->devo_bus_ops->busops_rev); 293*0Sstevel@tonic-gate } 294*0Sstevel@tonic-gate #endif /* DEBUG */ 295*0Sstevel@tonic-gate 296*0Sstevel@tonic-gate return (ndi_busop_get_eventcookie(pdip, rdip, name, 297*0Sstevel@tonic-gate event_cookiep)); 298*0Sstevel@tonic-gate } 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate return ((*(DEVI(pdip)->devi_ops->devo_bus_ops->bus_get_eventcookie)) 301*0Sstevel@tonic-gate (pdip, rdip, name, event_cookiep)); 302*0Sstevel@tonic-gate } 303*0Sstevel@tonic-gate 304*0Sstevel@tonic-gate /* 305*0Sstevel@tonic-gate * Copy in the devctl IOCTL data and return a handle to 306*0Sstevel@tonic-gate * the data. 307*0Sstevel@tonic-gate */ 308*0Sstevel@tonic-gate int 309*0Sstevel@tonic-gate ndi_dc_allochdl(void *iocarg, struct devctl_iocdata **rdcp) 310*0Sstevel@tonic-gate { 311*0Sstevel@tonic-gate struct devctl_iocdata *dcp; 312*0Sstevel@tonic-gate char *cpybuf; 313*0Sstevel@tonic-gate 314*0Sstevel@tonic-gate ASSERT(rdcp != NULL); 315*0Sstevel@tonic-gate 316*0Sstevel@tonic-gate dcp = kmem_zalloc(sizeof (*dcp), KM_SLEEP); 317*0Sstevel@tonic-gate 318*0Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 319*0Sstevel@tonic-gate if (copyin(iocarg, dcp, sizeof (*dcp)) != 0) { 320*0Sstevel@tonic-gate kmem_free(dcp, sizeof (*dcp)); 321*0Sstevel@tonic-gate return (NDI_FAULT); 322*0Sstevel@tonic-gate } 323*0Sstevel@tonic-gate } 324*0Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 325*0Sstevel@tonic-gate else { 326*0Sstevel@tonic-gate struct devctl_iocdata32 dcp32; 327*0Sstevel@tonic-gate 328*0Sstevel@tonic-gate if (copyin(iocarg, &dcp32, sizeof (dcp32)) != 0) { 329*0Sstevel@tonic-gate kmem_free(dcp, sizeof (*dcp)); 330*0Sstevel@tonic-gate return (NDI_FAULT); 331*0Sstevel@tonic-gate } 332*0Sstevel@tonic-gate dcp->cmd = (uint_t)dcp32.cmd; 333*0Sstevel@tonic-gate dcp->flags = (uint_t)dcp32.flags; 334*0Sstevel@tonic-gate dcp->cpyout_buf = (uint_t *)(uintptr_t)dcp32.cpyout_buf; 335*0Sstevel@tonic-gate dcp->nvl_user = (nvlist_t *)(uintptr_t)dcp32.nvl_user; 336*0Sstevel@tonic-gate dcp->nvl_usersz = (size_t)dcp32.nvl_usersz; 337*0Sstevel@tonic-gate dcp->c_nodename = (char *)(uintptr_t)dcp32.c_nodename; 338*0Sstevel@tonic-gate dcp->c_unitaddr = (char *)(uintptr_t)dcp32.c_unitaddr; 339*0Sstevel@tonic-gate } 340*0Sstevel@tonic-gate #endif 341*0Sstevel@tonic-gate if (dcp->c_nodename != NULL) { 342*0Sstevel@tonic-gate cpybuf = kmem_alloc(MAXNAMELEN, KM_SLEEP); 343*0Sstevel@tonic-gate if (copyinstr(dcp->c_nodename, cpybuf, MAXNAMELEN, 0) != 0) { 344*0Sstevel@tonic-gate kmem_free(cpybuf, MAXNAMELEN); 345*0Sstevel@tonic-gate kmem_free(dcp, sizeof (*dcp)); 346*0Sstevel@tonic-gate return (NDI_FAULT); 347*0Sstevel@tonic-gate } 348*0Sstevel@tonic-gate cpybuf[MAXNAMELEN - 1] = '\0'; 349*0Sstevel@tonic-gate dcp->c_nodename = cpybuf; 350*0Sstevel@tonic-gate } 351*0Sstevel@tonic-gate 352*0Sstevel@tonic-gate if (dcp->c_unitaddr != NULL) { 353*0Sstevel@tonic-gate cpybuf = kmem_alloc(MAXNAMELEN, KM_SLEEP); 354*0Sstevel@tonic-gate if (copyinstr(dcp->c_unitaddr, cpybuf, MAXNAMELEN, 0) != 0) { 355*0Sstevel@tonic-gate kmem_free(cpybuf, MAXNAMELEN); 356*0Sstevel@tonic-gate if (dcp->c_nodename != NULL) 357*0Sstevel@tonic-gate kmem_free(dcp->c_nodename, MAXNAMELEN); 358*0Sstevel@tonic-gate kmem_free(dcp, sizeof (*dcp)); 359*0Sstevel@tonic-gate return (NDI_FAULT); 360*0Sstevel@tonic-gate } 361*0Sstevel@tonic-gate cpybuf[MAXNAMELEN - 1] = '\0'; 362*0Sstevel@tonic-gate dcp->c_unitaddr = cpybuf; 363*0Sstevel@tonic-gate } 364*0Sstevel@tonic-gate 365*0Sstevel@tonic-gate /* 366*0Sstevel@tonic-gate * copyin and unpack a user defined nvlist if one was passed 367*0Sstevel@tonic-gate */ 368*0Sstevel@tonic-gate if (dcp->nvl_user != NULL) { 369*0Sstevel@tonic-gate cpybuf = kmem_alloc(dcp->nvl_usersz, KM_SLEEP); 370*0Sstevel@tonic-gate if (copyin(dcp->nvl_user, cpybuf, dcp->nvl_usersz) != 0) { 371*0Sstevel@tonic-gate kmem_free(cpybuf, dcp->nvl_usersz); 372*0Sstevel@tonic-gate if (dcp->c_nodename != NULL) 373*0Sstevel@tonic-gate kmem_free(dcp->c_nodename, MAXNAMELEN); 374*0Sstevel@tonic-gate if (dcp->c_unitaddr != NULL) 375*0Sstevel@tonic-gate kmem_free(dcp->c_unitaddr, MAXNAMELEN); 376*0Sstevel@tonic-gate kmem_free(dcp, sizeof (*dcp)); 377*0Sstevel@tonic-gate return (NDI_FAULT); 378*0Sstevel@tonic-gate } 379*0Sstevel@tonic-gate 380*0Sstevel@tonic-gate if (nvlist_unpack(cpybuf, dcp->nvl_usersz, &dcp->nvl_user, 381*0Sstevel@tonic-gate KM_SLEEP)) { 382*0Sstevel@tonic-gate kmem_free(cpybuf, dcp->nvl_usersz); 383*0Sstevel@tonic-gate if (dcp->c_nodename != NULL) 384*0Sstevel@tonic-gate kmem_free(dcp->c_nodename, MAXNAMELEN); 385*0Sstevel@tonic-gate if (dcp->c_unitaddr != NULL) 386*0Sstevel@tonic-gate kmem_free(dcp->c_unitaddr, MAXNAMELEN); 387*0Sstevel@tonic-gate kmem_free(dcp, sizeof (*dcp)); 388*0Sstevel@tonic-gate return (NDI_FAULT); 389*0Sstevel@tonic-gate } 390*0Sstevel@tonic-gate /* 391*0Sstevel@tonic-gate * free the buffer containing the packed nvlist 392*0Sstevel@tonic-gate */ 393*0Sstevel@tonic-gate kmem_free(cpybuf, dcp->nvl_usersz); 394*0Sstevel@tonic-gate 395*0Sstevel@tonic-gate } 396*0Sstevel@tonic-gate 397*0Sstevel@tonic-gate *rdcp = dcp; 398*0Sstevel@tonic-gate return (NDI_SUCCESS); 399*0Sstevel@tonic-gate } 400*0Sstevel@tonic-gate 401*0Sstevel@tonic-gate /* 402*0Sstevel@tonic-gate * free all space allocated to a handle. 403*0Sstevel@tonic-gate */ 404*0Sstevel@tonic-gate void 405*0Sstevel@tonic-gate ndi_dc_freehdl(struct devctl_iocdata *dcp) 406*0Sstevel@tonic-gate { 407*0Sstevel@tonic-gate ASSERT(dcp != NULL); 408*0Sstevel@tonic-gate 409*0Sstevel@tonic-gate if (dcp->c_nodename != NULL) 410*0Sstevel@tonic-gate kmem_free(dcp->c_nodename, MAXNAMELEN); 411*0Sstevel@tonic-gate 412*0Sstevel@tonic-gate if (dcp->c_unitaddr != NULL) 413*0Sstevel@tonic-gate kmem_free(dcp->c_unitaddr, MAXNAMELEN); 414*0Sstevel@tonic-gate 415*0Sstevel@tonic-gate if (dcp->nvl_user != NULL) 416*0Sstevel@tonic-gate nvlist_free(dcp->nvl_user); 417*0Sstevel@tonic-gate 418*0Sstevel@tonic-gate kmem_free(dcp, sizeof (*dcp)); 419*0Sstevel@tonic-gate } 420*0Sstevel@tonic-gate 421*0Sstevel@tonic-gate char * 422*0Sstevel@tonic-gate ndi_dc_getname(struct devctl_iocdata *dcp) 423*0Sstevel@tonic-gate { 424*0Sstevel@tonic-gate ASSERT(dcp != NULL); 425*0Sstevel@tonic-gate return (dcp->c_nodename); 426*0Sstevel@tonic-gate 427*0Sstevel@tonic-gate } 428*0Sstevel@tonic-gate 429*0Sstevel@tonic-gate char * 430*0Sstevel@tonic-gate ndi_dc_getaddr(struct devctl_iocdata *dcp) 431*0Sstevel@tonic-gate { 432*0Sstevel@tonic-gate ASSERT(dcp != NULL); 433*0Sstevel@tonic-gate return (dcp->c_unitaddr); 434*0Sstevel@tonic-gate } 435*0Sstevel@tonic-gate 436*0Sstevel@tonic-gate nvlist_t * 437*0Sstevel@tonic-gate ndi_dc_get_ap_data(struct devctl_iocdata *dcp) 438*0Sstevel@tonic-gate { 439*0Sstevel@tonic-gate ASSERT(dcp != NULL); 440*0Sstevel@tonic-gate 441*0Sstevel@tonic-gate return (dcp->nvl_user); 442*0Sstevel@tonic-gate } 443*0Sstevel@tonic-gate 444*0Sstevel@tonic-gate /* 445*0Sstevel@tonic-gate * Transition the child named by "devname@devaddr" to the online state. 446*0Sstevel@tonic-gate * For use by a driver's DEVCTL_DEVICE_ONLINE handler. 447*0Sstevel@tonic-gate */ 448*0Sstevel@tonic-gate int 449*0Sstevel@tonic-gate ndi_devctl_device_online(dev_info_t *dip, struct devctl_iocdata *dcp, 450*0Sstevel@tonic-gate uint_t flags) 451*0Sstevel@tonic-gate { 452*0Sstevel@tonic-gate int rval; 453*0Sstevel@tonic-gate char *name; 454*0Sstevel@tonic-gate dev_info_t *rdip; 455*0Sstevel@tonic-gate 456*0Sstevel@tonic-gate if (ndi_dc_getname(dcp) == NULL || ndi_dc_getaddr(dcp) == NULL) 457*0Sstevel@tonic-gate return (EINVAL); 458*0Sstevel@tonic-gate 459*0Sstevel@tonic-gate name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 460*0Sstevel@tonic-gate (void) snprintf(name, MAXNAMELEN, "%s@%s", 461*0Sstevel@tonic-gate ndi_dc_getname(dcp), ndi_dc_getaddr(dcp)); 462*0Sstevel@tonic-gate 463*0Sstevel@tonic-gate if ((rval = ndi_devi_config_one(dip, name, &rdip, 464*0Sstevel@tonic-gate flags | NDI_DEVI_ONLINE | NDI_CONFIG)) == NDI_SUCCESS) { 465*0Sstevel@tonic-gate ndi_rele_devi(rdip); 466*0Sstevel@tonic-gate 467*0Sstevel@tonic-gate /* 468*0Sstevel@tonic-gate * Invalidate devfs cached directory contents. For the checks 469*0Sstevel@tonic-gate * in the "if" condition see the comment in ndi_devi_online(). 470*0Sstevel@tonic-gate */ 471*0Sstevel@tonic-gate if (i_ddi_node_state(dip) == DS_READY && !DEVI_BUSY_OWNED(dip)) 472*0Sstevel@tonic-gate (void) devfs_clean(dip, NULL, 0); 473*0Sstevel@tonic-gate 474*0Sstevel@tonic-gate } else if (rval == NDI_BUSY) { 475*0Sstevel@tonic-gate rval = EBUSY; 476*0Sstevel@tonic-gate } else if (rval == NDI_FAILURE) { 477*0Sstevel@tonic-gate rval = EIO; 478*0Sstevel@tonic-gate } 479*0Sstevel@tonic-gate 480*0Sstevel@tonic-gate NDI_DEBUG(flags, (CE_CONT, "%s%d: online: %s: %s\n", 481*0Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), name, 482*0Sstevel@tonic-gate ((rval == NDI_SUCCESS) ? "ok" : "failed"))); 483*0Sstevel@tonic-gate 484*0Sstevel@tonic-gate kmem_free(name, MAXNAMELEN); 485*0Sstevel@tonic-gate 486*0Sstevel@tonic-gate return (rval); 487*0Sstevel@tonic-gate } 488*0Sstevel@tonic-gate 489*0Sstevel@tonic-gate /* 490*0Sstevel@tonic-gate * Transition the child named by "devname@devaddr" to the offline state. 491*0Sstevel@tonic-gate * For use by a driver's DEVCTL_DEVICE_OFFLINE handler. 492*0Sstevel@tonic-gate */ 493*0Sstevel@tonic-gate int 494*0Sstevel@tonic-gate ndi_devctl_device_offline(dev_info_t *dip, struct devctl_iocdata *dcp, 495*0Sstevel@tonic-gate uint_t flags) 496*0Sstevel@tonic-gate { 497*0Sstevel@tonic-gate int rval; 498*0Sstevel@tonic-gate char *name; 499*0Sstevel@tonic-gate 500*0Sstevel@tonic-gate if (ndi_dc_getname(dcp) == NULL || ndi_dc_getaddr(dcp) == NULL) 501*0Sstevel@tonic-gate return (EINVAL); 502*0Sstevel@tonic-gate 503*0Sstevel@tonic-gate name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 504*0Sstevel@tonic-gate (void) snprintf(name, MAXNAMELEN, "%s@%s", 505*0Sstevel@tonic-gate ndi_dc_getname(dcp), ndi_dc_getaddr(dcp)); 506*0Sstevel@tonic-gate 507*0Sstevel@tonic-gate rval = devfs_clean(dip, name, DV_CLEAN_FORCE); 508*0Sstevel@tonic-gate if (rval) { 509*0Sstevel@tonic-gate rval = EBUSY; 510*0Sstevel@tonic-gate } else { 511*0Sstevel@tonic-gate rval = ndi_devi_unconfig_one(dip, name, NULL, 512*0Sstevel@tonic-gate flags | NDI_DEVI_OFFLINE); 513*0Sstevel@tonic-gate 514*0Sstevel@tonic-gate if (rval == NDI_BUSY) { 515*0Sstevel@tonic-gate rval = EBUSY; 516*0Sstevel@tonic-gate } else if (rval == NDI_FAILURE) { 517*0Sstevel@tonic-gate rval = EIO; 518*0Sstevel@tonic-gate } 519*0Sstevel@tonic-gate } 520*0Sstevel@tonic-gate 521*0Sstevel@tonic-gate NDI_DEBUG(flags, (CE_CONT, "%s%d: offline: %s: %s\n", 522*0Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), name, 523*0Sstevel@tonic-gate (rval == NDI_SUCCESS) ? "ok" : "failed")); 524*0Sstevel@tonic-gate 525*0Sstevel@tonic-gate kmem_free(name, MAXNAMELEN); 526*0Sstevel@tonic-gate 527*0Sstevel@tonic-gate return (rval); 528*0Sstevel@tonic-gate } 529*0Sstevel@tonic-gate 530*0Sstevel@tonic-gate /* 531*0Sstevel@tonic-gate * Remove the child named by "devname@devaddr". 532*0Sstevel@tonic-gate * For use by a driver's DEVCTL_DEVICE_REMOVE handler. 533*0Sstevel@tonic-gate */ 534*0Sstevel@tonic-gate int 535*0Sstevel@tonic-gate ndi_devctl_device_remove(dev_info_t *dip, struct devctl_iocdata *dcp, 536*0Sstevel@tonic-gate uint_t flags) 537*0Sstevel@tonic-gate { 538*0Sstevel@tonic-gate int rval; 539*0Sstevel@tonic-gate char *name; 540*0Sstevel@tonic-gate 541*0Sstevel@tonic-gate if (ndi_dc_getname(dcp) == NULL || ndi_dc_getaddr(dcp) == NULL) 542*0Sstevel@tonic-gate return (EINVAL); 543*0Sstevel@tonic-gate 544*0Sstevel@tonic-gate name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 545*0Sstevel@tonic-gate (void) snprintf(name, MAXNAMELEN, "%s@%s", 546*0Sstevel@tonic-gate ndi_dc_getname(dcp), ndi_dc_getaddr(dcp)); 547*0Sstevel@tonic-gate 548*0Sstevel@tonic-gate (void) devfs_clean(dip, name, DV_CLEAN_FORCE); 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gate rval = ndi_devi_unconfig_one(dip, name, NULL, flags | NDI_DEVI_REMOVE); 551*0Sstevel@tonic-gate 552*0Sstevel@tonic-gate if (rval == NDI_BUSY) { 553*0Sstevel@tonic-gate rval = EBUSY; 554*0Sstevel@tonic-gate } else if (rval == NDI_FAILURE) { 555*0Sstevel@tonic-gate rval = EIO; 556*0Sstevel@tonic-gate } 557*0Sstevel@tonic-gate 558*0Sstevel@tonic-gate NDI_DEBUG(flags, (CE_CONT, "%s%d: remove: %s: %s\n", 559*0Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), name, 560*0Sstevel@tonic-gate (rval == NDI_SUCCESS) ? "ok" : "failed")); 561*0Sstevel@tonic-gate 562*0Sstevel@tonic-gate kmem_free(name, MAXNAMELEN); 563*0Sstevel@tonic-gate 564*0Sstevel@tonic-gate return (rval); 565*0Sstevel@tonic-gate } 566*0Sstevel@tonic-gate 567*0Sstevel@tonic-gate /* 568*0Sstevel@tonic-gate * Return devctl state of the child named by "name@addr". 569*0Sstevel@tonic-gate * For use by a driver's DEVCTL_DEVICE_GETSTATE handler. 570*0Sstevel@tonic-gate */ 571*0Sstevel@tonic-gate int 572*0Sstevel@tonic-gate ndi_devctl_device_getstate(dev_info_t *parent, struct devctl_iocdata *dcp, 573*0Sstevel@tonic-gate uint_t *state) 574*0Sstevel@tonic-gate { 575*0Sstevel@tonic-gate dev_info_t *dip; 576*0Sstevel@tonic-gate char *name, *addr; 577*0Sstevel@tonic-gate char *devname; 578*0Sstevel@tonic-gate int devnamelen; 579*0Sstevel@tonic-gate int circ; 580*0Sstevel@tonic-gate 581*0Sstevel@tonic-gate if (parent == NULL || 582*0Sstevel@tonic-gate ((name = ndi_dc_getname(dcp)) == NULL) || 583*0Sstevel@tonic-gate ((addr = ndi_dc_getaddr(dcp)) == NULL)) 584*0Sstevel@tonic-gate return (NDI_FAILURE); 585*0Sstevel@tonic-gate 586*0Sstevel@tonic-gate devnamelen = strlen(name) + strlen(addr) + 2; 587*0Sstevel@tonic-gate devname = kmem_alloc(devnamelen, KM_SLEEP); 588*0Sstevel@tonic-gate if (strlen(addr) > 0) { 589*0Sstevel@tonic-gate (void) snprintf(devname, devnamelen, "%s@%s", name, addr); 590*0Sstevel@tonic-gate } else { 591*0Sstevel@tonic-gate (void) snprintf(devname, devnamelen, "%s", name); 592*0Sstevel@tonic-gate } 593*0Sstevel@tonic-gate 594*0Sstevel@tonic-gate ndi_devi_enter(parent, &circ); 595*0Sstevel@tonic-gate 596*0Sstevel@tonic-gate dip = ndi_devi_findchild(parent, devname); 597*0Sstevel@tonic-gate kmem_free(devname, devnamelen); 598*0Sstevel@tonic-gate 599*0Sstevel@tonic-gate if (dip == NULL) { 600*0Sstevel@tonic-gate ndi_devi_exit(parent, circ); 601*0Sstevel@tonic-gate return (NDI_FAILURE); 602*0Sstevel@tonic-gate } 603*0Sstevel@tonic-gate 604*0Sstevel@tonic-gate mutex_enter(&(DEVI(dip)->devi_lock)); 605*0Sstevel@tonic-gate if (DEVI_IS_DEVICE_OFFLINE(dip)) { 606*0Sstevel@tonic-gate *state = DEVICE_OFFLINE; 607*0Sstevel@tonic-gate } else if (DEVI_IS_DEVICE_DOWN(dip)) { 608*0Sstevel@tonic-gate *state = DEVICE_DOWN; 609*0Sstevel@tonic-gate } else { 610*0Sstevel@tonic-gate *state = DEVICE_ONLINE; 611*0Sstevel@tonic-gate if (devi_stillreferenced(dip) == DEVI_REFERENCED) 612*0Sstevel@tonic-gate *state |= DEVICE_BUSY; 613*0Sstevel@tonic-gate } 614*0Sstevel@tonic-gate 615*0Sstevel@tonic-gate mutex_exit(&(DEVI(dip)->devi_lock)); 616*0Sstevel@tonic-gate ndi_devi_exit(parent, circ); 617*0Sstevel@tonic-gate 618*0Sstevel@tonic-gate return (NDI_SUCCESS); 619*0Sstevel@tonic-gate } 620*0Sstevel@tonic-gate 621*0Sstevel@tonic-gate /* 622*0Sstevel@tonic-gate * return the current state of the device "dip" 623*0Sstevel@tonic-gate * 624*0Sstevel@tonic-gate * recommend using ndi_devctl_ioctl() or 625*0Sstevel@tonic-gate * ndi_devctl_device_getstate() instead 626*0Sstevel@tonic-gate */ 627*0Sstevel@tonic-gate int 628*0Sstevel@tonic-gate ndi_dc_return_dev_state(dev_info_t *dip, struct devctl_iocdata *dcp) 629*0Sstevel@tonic-gate { 630*0Sstevel@tonic-gate dev_info_t *pdip; 631*0Sstevel@tonic-gate uint_t devstate = 0; 632*0Sstevel@tonic-gate int circ; 633*0Sstevel@tonic-gate 634*0Sstevel@tonic-gate if ((dip == NULL) || (dcp == NULL)) 635*0Sstevel@tonic-gate return (NDI_FAILURE); 636*0Sstevel@tonic-gate 637*0Sstevel@tonic-gate pdip = ddi_get_parent(dip); 638*0Sstevel@tonic-gate 639*0Sstevel@tonic-gate ndi_devi_enter(pdip, &circ); 640*0Sstevel@tonic-gate mutex_enter(&(DEVI(dip)->devi_lock)); 641*0Sstevel@tonic-gate if (DEVI_IS_DEVICE_OFFLINE(dip)) { 642*0Sstevel@tonic-gate devstate = DEVICE_OFFLINE; 643*0Sstevel@tonic-gate } else if (DEVI_IS_DEVICE_DOWN(dip)) { 644*0Sstevel@tonic-gate devstate = DEVICE_DOWN; 645*0Sstevel@tonic-gate } else { 646*0Sstevel@tonic-gate devstate = DEVICE_ONLINE; 647*0Sstevel@tonic-gate if (devi_stillreferenced(dip) == DEVI_REFERENCED) 648*0Sstevel@tonic-gate devstate |= DEVICE_BUSY; 649*0Sstevel@tonic-gate } 650*0Sstevel@tonic-gate 651*0Sstevel@tonic-gate mutex_exit(&(DEVI(dip)->devi_lock)); 652*0Sstevel@tonic-gate ndi_devi_exit(pdip, circ); 653*0Sstevel@tonic-gate 654*0Sstevel@tonic-gate if (copyout(&devstate, dcp->cpyout_buf, sizeof (uint_t)) != 0) 655*0Sstevel@tonic-gate return (NDI_FAULT); 656*0Sstevel@tonic-gate 657*0Sstevel@tonic-gate return (NDI_SUCCESS); 658*0Sstevel@tonic-gate } 659*0Sstevel@tonic-gate 660*0Sstevel@tonic-gate /* 661*0Sstevel@tonic-gate * Return device's bus state 662*0Sstevel@tonic-gate * For use by a driver's DEVCTL_BUS_GETSTATE handler. 663*0Sstevel@tonic-gate */ 664*0Sstevel@tonic-gate int 665*0Sstevel@tonic-gate ndi_devctl_bus_getstate(dev_info_t *dip, struct devctl_iocdata *dcp, 666*0Sstevel@tonic-gate uint_t *state) 667*0Sstevel@tonic-gate { 668*0Sstevel@tonic-gate if ((dip == NULL) || (dcp == NULL)) 669*0Sstevel@tonic-gate return (NDI_FAILURE); 670*0Sstevel@tonic-gate 671*0Sstevel@tonic-gate return (ndi_get_bus_state(dip, state)); 672*0Sstevel@tonic-gate } 673*0Sstevel@tonic-gate 674*0Sstevel@tonic-gate /* 675*0Sstevel@tonic-gate * Generic devctl ioctl handler 676*0Sstevel@tonic-gate */ 677*0Sstevel@tonic-gate int 678*0Sstevel@tonic-gate ndi_devctl_ioctl(dev_info_t *dip, int cmd, intptr_t arg, int mode, uint_t flags) 679*0Sstevel@tonic-gate { 680*0Sstevel@tonic-gate _NOTE(ARGUNUSED(mode)) 681*0Sstevel@tonic-gate struct devctl_iocdata *dcp; 682*0Sstevel@tonic-gate uint_t state; 683*0Sstevel@tonic-gate int rval = ENOTTY; 684*0Sstevel@tonic-gate 685*0Sstevel@tonic-gate /* 686*0Sstevel@tonic-gate * read devctl ioctl data 687*0Sstevel@tonic-gate */ 688*0Sstevel@tonic-gate if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS) 689*0Sstevel@tonic-gate return (EFAULT); 690*0Sstevel@tonic-gate 691*0Sstevel@tonic-gate switch (cmd) { 692*0Sstevel@tonic-gate 693*0Sstevel@tonic-gate case DEVCTL_BUS_GETSTATE: 694*0Sstevel@tonic-gate rval = ndi_devctl_bus_getstate(dip, dcp, &state); 695*0Sstevel@tonic-gate if (rval == NDI_SUCCESS) { 696*0Sstevel@tonic-gate if (copyout(&state, dcp->cpyout_buf, 697*0Sstevel@tonic-gate sizeof (uint_t)) != 0) 698*0Sstevel@tonic-gate rval = NDI_FAULT; 699*0Sstevel@tonic-gate } 700*0Sstevel@tonic-gate break; 701*0Sstevel@tonic-gate 702*0Sstevel@tonic-gate case DEVCTL_DEVICE_ONLINE: 703*0Sstevel@tonic-gate rval = ndi_devctl_device_online(dip, dcp, flags); 704*0Sstevel@tonic-gate break; 705*0Sstevel@tonic-gate 706*0Sstevel@tonic-gate case DEVCTL_DEVICE_OFFLINE: 707*0Sstevel@tonic-gate rval = ndi_devctl_device_offline(dip, dcp, flags); 708*0Sstevel@tonic-gate break; 709*0Sstevel@tonic-gate 710*0Sstevel@tonic-gate case DEVCTL_DEVICE_GETSTATE: 711*0Sstevel@tonic-gate rval = ndi_devctl_device_getstate(dip, dcp, &state); 712*0Sstevel@tonic-gate if (rval == NDI_SUCCESS) { 713*0Sstevel@tonic-gate if (copyout(&state, dcp->cpyout_buf, 714*0Sstevel@tonic-gate sizeof (uint_t)) != 0) 715*0Sstevel@tonic-gate rval = NDI_FAULT; 716*0Sstevel@tonic-gate } 717*0Sstevel@tonic-gate break; 718*0Sstevel@tonic-gate 719*0Sstevel@tonic-gate case DEVCTL_DEVICE_REMOVE: 720*0Sstevel@tonic-gate rval = ndi_devctl_device_remove(dip, dcp, flags); 721*0Sstevel@tonic-gate break; 722*0Sstevel@tonic-gate 723*0Sstevel@tonic-gate case DEVCTL_BUS_DEV_CREATE: 724*0Sstevel@tonic-gate rval = ndi_dc_devi_create(dcp, dip, 0, NULL); 725*0Sstevel@tonic-gate break; 726*0Sstevel@tonic-gate 727*0Sstevel@tonic-gate /* 728*0Sstevel@tonic-gate * ioctls for which a generic implementation makes no sense 729*0Sstevel@tonic-gate */ 730*0Sstevel@tonic-gate case DEVCTL_BUS_RESET: 731*0Sstevel@tonic-gate case DEVCTL_BUS_RESETALL: 732*0Sstevel@tonic-gate case DEVCTL_DEVICE_RESET: 733*0Sstevel@tonic-gate case DEVCTL_AP_CONNECT: 734*0Sstevel@tonic-gate case DEVCTL_AP_DISCONNECT: 735*0Sstevel@tonic-gate case DEVCTL_AP_INSERT: 736*0Sstevel@tonic-gate case DEVCTL_AP_REMOVE: 737*0Sstevel@tonic-gate case DEVCTL_AP_CONFIGURE: 738*0Sstevel@tonic-gate case DEVCTL_AP_UNCONFIGURE: 739*0Sstevel@tonic-gate case DEVCTL_AP_GETSTATE: 740*0Sstevel@tonic-gate case DEVCTL_AP_CONTROL: 741*0Sstevel@tonic-gate case DEVCTL_BUS_QUIESCE: 742*0Sstevel@tonic-gate case DEVCTL_BUS_UNQUIESCE: 743*0Sstevel@tonic-gate rval = ENOTSUP; 744*0Sstevel@tonic-gate break; 745*0Sstevel@tonic-gate } 746*0Sstevel@tonic-gate 747*0Sstevel@tonic-gate ndi_dc_freehdl(dcp); 748*0Sstevel@tonic-gate return (rval); 749*0Sstevel@tonic-gate } 750*0Sstevel@tonic-gate 751*0Sstevel@tonic-gate /* 752*0Sstevel@tonic-gate * Copyout the state of the Attachment Point "ap" to the requesting 753*0Sstevel@tonic-gate * user process. 754*0Sstevel@tonic-gate */ 755*0Sstevel@tonic-gate int 756*0Sstevel@tonic-gate ndi_dc_return_ap_state(devctl_ap_state_t *ap, struct devctl_iocdata *dcp) 757*0Sstevel@tonic-gate { 758*0Sstevel@tonic-gate if ((ap == NULL) || (dcp == NULL)) 759*0Sstevel@tonic-gate return (NDI_FAILURE); 760*0Sstevel@tonic-gate 761*0Sstevel@tonic-gate 762*0Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 763*0Sstevel@tonic-gate if (copyout(ap, dcp->cpyout_buf, 764*0Sstevel@tonic-gate sizeof (devctl_ap_state_t)) != 0) 765*0Sstevel@tonic-gate return (NDI_FAULT); 766*0Sstevel@tonic-gate } 767*0Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 768*0Sstevel@tonic-gate else { 769*0Sstevel@tonic-gate struct devctl_ap_state32 ap_state32; 770*0Sstevel@tonic-gate 771*0Sstevel@tonic-gate ap_state32.ap_rstate = ap->ap_rstate; 772*0Sstevel@tonic-gate ap_state32.ap_ostate = ap->ap_ostate; 773*0Sstevel@tonic-gate ap_state32.ap_condition = ap->ap_condition; 774*0Sstevel@tonic-gate ap_state32.ap_error_code = ap->ap_error_code; 775*0Sstevel@tonic-gate ap_state32.ap_in_transition = ap->ap_in_transition; 776*0Sstevel@tonic-gate ap_state32.ap_last_change = (time32_t)ap->ap_last_change; 777*0Sstevel@tonic-gate if (copyout(&ap_state32, dcp->cpyout_buf, 778*0Sstevel@tonic-gate sizeof (devctl_ap_state32_t)) != 0) 779*0Sstevel@tonic-gate return (NDI_FAULT); 780*0Sstevel@tonic-gate } 781*0Sstevel@tonic-gate #endif 782*0Sstevel@tonic-gate 783*0Sstevel@tonic-gate return (NDI_SUCCESS); 784*0Sstevel@tonic-gate } 785*0Sstevel@tonic-gate 786*0Sstevel@tonic-gate /* 787*0Sstevel@tonic-gate * Copyout the bus state of the bus nexus device "dip" to the requesting 788*0Sstevel@tonic-gate * user process. 789*0Sstevel@tonic-gate */ 790*0Sstevel@tonic-gate int 791*0Sstevel@tonic-gate ndi_dc_return_bus_state(dev_info_t *dip, struct devctl_iocdata *dcp) 792*0Sstevel@tonic-gate { 793*0Sstevel@tonic-gate uint_t devstate = 0; 794*0Sstevel@tonic-gate 795*0Sstevel@tonic-gate if ((dip == NULL) || (dcp == NULL)) 796*0Sstevel@tonic-gate return (NDI_FAILURE); 797*0Sstevel@tonic-gate 798*0Sstevel@tonic-gate if (ndi_get_bus_state(dip, &devstate) != NDI_SUCCESS) 799*0Sstevel@tonic-gate return (NDI_FAILURE); 800*0Sstevel@tonic-gate 801*0Sstevel@tonic-gate if (copyout(&devstate, dcp->cpyout_buf, sizeof (uint_t)) != 0) 802*0Sstevel@tonic-gate return (NDI_FAULT); 803*0Sstevel@tonic-gate 804*0Sstevel@tonic-gate return (NDI_SUCCESS); 805*0Sstevel@tonic-gate } 806*0Sstevel@tonic-gate 807*0Sstevel@tonic-gate static int 808*0Sstevel@tonic-gate i_dc_devi_create(struct devctl_iocdata *, dev_info_t *, dev_info_t **); 809*0Sstevel@tonic-gate 810*0Sstevel@tonic-gate /* 811*0Sstevel@tonic-gate * create a child device node given the property definitions 812*0Sstevel@tonic-gate * supplied by the userland process 813*0Sstevel@tonic-gate */ 814*0Sstevel@tonic-gate int 815*0Sstevel@tonic-gate ndi_dc_devi_create(struct devctl_iocdata *dcp, dev_info_t *pdip, int flags, 816*0Sstevel@tonic-gate dev_info_t **rdip) 817*0Sstevel@tonic-gate { 818*0Sstevel@tonic-gate dev_info_t *cdip; 819*0Sstevel@tonic-gate int rv, circular = 0; 820*0Sstevel@tonic-gate char devnm[MAXNAMELEN]; 821*0Sstevel@tonic-gate int nmlen; 822*0Sstevel@tonic-gate 823*0Sstevel@tonic-gate /* 824*0Sstevel@tonic-gate * The child device may have been pre-constructed by an earlier 825*0Sstevel@tonic-gate * call to this function with the flag DEVCTL_CONSTRUCT set. 826*0Sstevel@tonic-gate */ 827*0Sstevel@tonic-gate 828*0Sstevel@tonic-gate if ((cdip = (rdip != NULL) ? *rdip : NULL) == NULL) 829*0Sstevel@tonic-gate if ((rv = i_dc_devi_create(dcp, pdip, &cdip)) != 0) 830*0Sstevel@tonic-gate return (rv); 831*0Sstevel@tonic-gate 832*0Sstevel@tonic-gate ASSERT(cdip != NULL); 833*0Sstevel@tonic-gate 834*0Sstevel@tonic-gate /* 835*0Sstevel@tonic-gate * Return the device node partially constructed if the 836*0Sstevel@tonic-gate * DEVCTL_CONSTRUCT flag is set. 837*0Sstevel@tonic-gate */ 838*0Sstevel@tonic-gate if (flags & DEVCTL_CONSTRUCT) { 839*0Sstevel@tonic-gate if (rdip == NULL) { 840*0Sstevel@tonic-gate (void) ndi_devi_free(cdip); 841*0Sstevel@tonic-gate return (EINVAL); 842*0Sstevel@tonic-gate } 843*0Sstevel@tonic-gate *rdip = cdip; 844*0Sstevel@tonic-gate return (0); 845*0Sstevel@tonic-gate } 846*0Sstevel@tonic-gate 847*0Sstevel@tonic-gate /* 848*0Sstevel@tonic-gate * Bring the node up to a named but OFFLINE state. The calling 849*0Sstevel@tonic-gate * application will need to manage the node from here on. 850*0Sstevel@tonic-gate */ 851*0Sstevel@tonic-gate if (dcp->flags & DEVCTL_OFFLINE) { 852*0Sstevel@tonic-gate /* 853*0Sstevel@tonic-gate * hand set the OFFLINE flag to prevent any asynchronous 854*0Sstevel@tonic-gate * autoconfiguration operations from attaching this node. 855*0Sstevel@tonic-gate */ 856*0Sstevel@tonic-gate DEVI(cdip)->devi_state |= DEVI_DEVICE_OFFLINE; 857*0Sstevel@tonic-gate rv = ndi_devi_bind_driver(cdip, flags); 858*0Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 859*0Sstevel@tonic-gate (void) ndi_devi_offline(cdip, NDI_DEVI_REMOVE); 860*0Sstevel@tonic-gate return (ENXIO); 861*0Sstevel@tonic-gate } 862*0Sstevel@tonic-gate 863*0Sstevel@tonic-gate /* 864*0Sstevel@tonic-gate * remove the dev_info node if it failed to bind to a 865*0Sstevel@tonic-gate * driver above. 866*0Sstevel@tonic-gate */ 867*0Sstevel@tonic-gate if (i_ddi_node_state(cdip) < DS_BOUND) { 868*0Sstevel@tonic-gate (void) ndi_devi_offline(cdip, NDI_DEVI_REMOVE); 869*0Sstevel@tonic-gate return (ENXIO); 870*0Sstevel@tonic-gate } 871*0Sstevel@tonic-gate 872*0Sstevel@tonic-gate /* 873*0Sstevel@tonic-gate * add the node to the per-driver list and INITCHILD it 874*0Sstevel@tonic-gate * to give it a name. 875*0Sstevel@tonic-gate */ 876*0Sstevel@tonic-gate ndi_devi_enter(pdip, &circular); 877*0Sstevel@tonic-gate if ((rv = ddi_initchild(pdip, cdip)) != DDI_SUCCESS) { 878*0Sstevel@tonic-gate (void) ndi_devi_offline(cdip, NDI_DEVI_REMOVE); 879*0Sstevel@tonic-gate ndi_devi_exit(pdip, circular); 880*0Sstevel@tonic-gate return (EINVAL); 881*0Sstevel@tonic-gate } 882*0Sstevel@tonic-gate ndi_devi_exit(pdip, circular); 883*0Sstevel@tonic-gate 884*0Sstevel@tonic-gate } else { 885*0Sstevel@tonic-gate /* 886*0Sstevel@tonic-gate * Attempt to bring the device ONLINE. If the request to 887*0Sstevel@tonic-gate * fails, remove the dev_info node. 888*0Sstevel@tonic-gate */ 889*0Sstevel@tonic-gate if (ndi_devi_online(cdip, NDI_ONLINE_ATTACH) != NDI_SUCCESS) { 890*0Sstevel@tonic-gate (void) ndi_devi_offline(cdip, NDI_DEVI_REMOVE); 891*0Sstevel@tonic-gate return (ENXIO); 892*0Sstevel@tonic-gate } 893*0Sstevel@tonic-gate 894*0Sstevel@tonic-gate /* 895*0Sstevel@tonic-gate * if the node was successfully added but there was 896*0Sstevel@tonic-gate * no driver available for the device, remove the node 897*0Sstevel@tonic-gate */ 898*0Sstevel@tonic-gate if (i_ddi_node_state(cdip) < DS_BOUND) { 899*0Sstevel@tonic-gate (void) ndi_devi_offline(cdip, NDI_DEVI_REMOVE); 900*0Sstevel@tonic-gate return (ENODEV); 901*0Sstevel@tonic-gate } 902*0Sstevel@tonic-gate } 903*0Sstevel@tonic-gate 904*0Sstevel@tonic-gate /* 905*0Sstevel@tonic-gate * return a handle to the child device 906*0Sstevel@tonic-gate * copy out the name of the newly attached child device if 907*0Sstevel@tonic-gate * the IOCTL request has provided a copyout buffer. 908*0Sstevel@tonic-gate */ 909*0Sstevel@tonic-gate if (rdip != NULL) 910*0Sstevel@tonic-gate *rdip = cdip; 911*0Sstevel@tonic-gate 912*0Sstevel@tonic-gate if (dcp->cpyout_buf == NULL) 913*0Sstevel@tonic-gate return (0); 914*0Sstevel@tonic-gate 915*0Sstevel@tonic-gate ASSERT(ddi_node_name(cdip) != NULL); 916*0Sstevel@tonic-gate ASSERT(ddi_get_name_addr(cdip) != NULL); 917*0Sstevel@tonic-gate 918*0Sstevel@tonic-gate nmlen = snprintf(devnm, MAXNAMELEN, "%s@%s", 919*0Sstevel@tonic-gate ddi_node_name(cdip), ddi_get_name_addr(cdip)); 920*0Sstevel@tonic-gate 921*0Sstevel@tonic-gate if (copyout(&devnm, dcp->cpyout_buf, nmlen) != 0) { 922*0Sstevel@tonic-gate (void) ndi_devi_offline(cdip, NDI_DEVI_REMOVE); 923*0Sstevel@tonic-gate return (EFAULT); 924*0Sstevel@tonic-gate } 925*0Sstevel@tonic-gate return (0); 926*0Sstevel@tonic-gate } 927*0Sstevel@tonic-gate 928*0Sstevel@tonic-gate static int 929*0Sstevel@tonic-gate i_dc_devi_create(struct devctl_iocdata *dcp, dev_info_t *pdip, 930*0Sstevel@tonic-gate dev_info_t **rdip) 931*0Sstevel@tonic-gate { 932*0Sstevel@tonic-gate 933*0Sstevel@tonic-gate dev_info_t *cdip; 934*0Sstevel@tonic-gate char *cname = NULL; 935*0Sstevel@tonic-gate nvlist_t *nvlp = dcp->nvl_user; 936*0Sstevel@tonic-gate nvpair_t *npp; 937*0Sstevel@tonic-gate char *np; 938*0Sstevel@tonic-gate int rv = 0; 939*0Sstevel@tonic-gate 940*0Sstevel@tonic-gate ASSERT(rdip != NULL && *rdip == NULL); 941*0Sstevel@tonic-gate 942*0Sstevel@tonic-gate if ((nvlp == NULL) || 943*0Sstevel@tonic-gate (nvlist_lookup_string(nvlp, DC_DEVI_NODENAME, &cname) != 0)) 944*0Sstevel@tonic-gate return (EINVAL); 945*0Sstevel@tonic-gate 946*0Sstevel@tonic-gate /* 947*0Sstevel@tonic-gate * construct a new dev_info node with a user-provided nodename 948*0Sstevel@tonic-gate */ 949*0Sstevel@tonic-gate ndi_devi_alloc_sleep(pdip, cname, (dnode_t)DEVI_SID_NODEID, &cdip); 950*0Sstevel@tonic-gate 951*0Sstevel@tonic-gate /* 952*0Sstevel@tonic-gate * create hardware properties for each member in the property 953*0Sstevel@tonic-gate * list. 954*0Sstevel@tonic-gate */ 955*0Sstevel@tonic-gate for (npp = nvlist_next_nvpair(nvlp, NULL); (npp != NULL && !rv); 956*0Sstevel@tonic-gate npp = nvlist_next_nvpair(nvlp, npp)) { 957*0Sstevel@tonic-gate 958*0Sstevel@tonic-gate np = nvpair_name(npp); 959*0Sstevel@tonic-gate 960*0Sstevel@tonic-gate /* 961*0Sstevel@tonic-gate * skip the nodename property 962*0Sstevel@tonic-gate */ 963*0Sstevel@tonic-gate if (strcmp(np, DC_DEVI_NODENAME) == 0) 964*0Sstevel@tonic-gate continue; 965*0Sstevel@tonic-gate 966*0Sstevel@tonic-gate switch (nvpair_type(npp)) { 967*0Sstevel@tonic-gate 968*0Sstevel@tonic-gate case DATA_TYPE_INT32: { 969*0Sstevel@tonic-gate int32_t prop_val; 970*0Sstevel@tonic-gate 971*0Sstevel@tonic-gate if ((rv = nvpair_value_int32(npp, &prop_val)) != 0) 972*0Sstevel@tonic-gate break; 973*0Sstevel@tonic-gate 974*0Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cdip, np, 975*0Sstevel@tonic-gate (int)prop_val); 976*0Sstevel@tonic-gate break; 977*0Sstevel@tonic-gate } 978*0Sstevel@tonic-gate 979*0Sstevel@tonic-gate case DATA_TYPE_STRING: { 980*0Sstevel@tonic-gate char *prop_val; 981*0Sstevel@tonic-gate 982*0Sstevel@tonic-gate if ((rv = nvpair_value_string(npp, &prop_val)) != 0) 983*0Sstevel@tonic-gate break; 984*0Sstevel@tonic-gate 985*0Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, cdip, 986*0Sstevel@tonic-gate np, prop_val); 987*0Sstevel@tonic-gate break; 988*0Sstevel@tonic-gate } 989*0Sstevel@tonic-gate 990*0Sstevel@tonic-gate case DATA_TYPE_BYTE_ARRAY: { 991*0Sstevel@tonic-gate uchar_t *val; 992*0Sstevel@tonic-gate uint_t nelms; 993*0Sstevel@tonic-gate 994*0Sstevel@tonic-gate if ((rv = nvpair_value_byte_array(npp, &val, 995*0Sstevel@tonic-gate &nelms)) != 0) 996*0Sstevel@tonic-gate break; 997*0Sstevel@tonic-gate 998*0Sstevel@tonic-gate (void) ndi_prop_update_byte_array(DDI_DEV_T_NONE, 999*0Sstevel@tonic-gate cdip, np, (uchar_t *)val, nelms); 1000*0Sstevel@tonic-gate break; 1001*0Sstevel@tonic-gate } 1002*0Sstevel@tonic-gate 1003*0Sstevel@tonic-gate case DATA_TYPE_INT32_ARRAY: { 1004*0Sstevel@tonic-gate int32_t *val; 1005*0Sstevel@tonic-gate uint_t nelms; 1006*0Sstevel@tonic-gate 1007*0Sstevel@tonic-gate if ((rv = nvpair_value_int32_array(npp, &val, 1008*0Sstevel@tonic-gate &nelms)) != 0) 1009*0Sstevel@tonic-gate break; 1010*0Sstevel@tonic-gate 1011*0Sstevel@tonic-gate (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, 1012*0Sstevel@tonic-gate cdip, np, val, nelms); 1013*0Sstevel@tonic-gate break; 1014*0Sstevel@tonic-gate } 1015*0Sstevel@tonic-gate 1016*0Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY: { 1017*0Sstevel@tonic-gate char **val; 1018*0Sstevel@tonic-gate uint_t nelms; 1019*0Sstevel@tonic-gate 1020*0Sstevel@tonic-gate if ((rv = nvpair_value_string_array(npp, &val, 1021*0Sstevel@tonic-gate &nelms)) != 0) 1022*0Sstevel@tonic-gate break; 1023*0Sstevel@tonic-gate 1024*0Sstevel@tonic-gate (void) ndi_prop_update_string_array(DDI_DEV_T_NONE, 1025*0Sstevel@tonic-gate cdip, np, val, nelms); 1026*0Sstevel@tonic-gate break; 1027*0Sstevel@tonic-gate } 1028*0Sstevel@tonic-gate 1029*0Sstevel@tonic-gate /* 1030*0Sstevel@tonic-gate * unsupported property data type 1031*0Sstevel@tonic-gate */ 1032*0Sstevel@tonic-gate default: 1033*0Sstevel@tonic-gate rv = EINVAL; 1034*0Sstevel@tonic-gate } 1035*0Sstevel@tonic-gate } 1036*0Sstevel@tonic-gate 1037*0Sstevel@tonic-gate /* 1038*0Sstevel@tonic-gate * something above failed 1039*0Sstevel@tonic-gate * destroy the partially child device and abort the request 1040*0Sstevel@tonic-gate */ 1041*0Sstevel@tonic-gate if (rv != 0) { 1042*0Sstevel@tonic-gate (void) ndi_devi_free(cdip); 1043*0Sstevel@tonic-gate return (rv); 1044*0Sstevel@tonic-gate } 1045*0Sstevel@tonic-gate 1046*0Sstevel@tonic-gate *rdip = cdip; 1047*0Sstevel@tonic-gate return (0); 1048*0Sstevel@tonic-gate } 1049*0Sstevel@tonic-gate 1050*0Sstevel@tonic-gate /* 1051*0Sstevel@tonic-gate * return current soft bus state of bus nexus "dip" 1052*0Sstevel@tonic-gate */ 1053*0Sstevel@tonic-gate int 1054*0Sstevel@tonic-gate ndi_get_bus_state(dev_info_t *dip, uint_t *rstate) 1055*0Sstevel@tonic-gate { 1056*0Sstevel@tonic-gate if (dip == NULL || rstate == NULL) 1057*0Sstevel@tonic-gate return (NDI_FAILURE); 1058*0Sstevel@tonic-gate 1059*0Sstevel@tonic-gate if (DEVI(dip)->devi_ops->devo_bus_ops == NULL) 1060*0Sstevel@tonic-gate return (NDI_FAILURE); 1061*0Sstevel@tonic-gate 1062*0Sstevel@tonic-gate mutex_enter(&(DEVI(dip)->devi_lock)); 1063*0Sstevel@tonic-gate if (DEVI_IS_BUS_QUIESCED(dip)) 1064*0Sstevel@tonic-gate *rstate = BUS_QUIESCED; 1065*0Sstevel@tonic-gate else if (DEVI_IS_BUS_DOWN(dip)) 1066*0Sstevel@tonic-gate *rstate = BUS_SHUTDOWN; 1067*0Sstevel@tonic-gate else 1068*0Sstevel@tonic-gate *rstate = BUS_ACTIVE; 1069*0Sstevel@tonic-gate mutex_exit(&(DEVI(dip)->devi_lock)); 1070*0Sstevel@tonic-gate return (NDI_SUCCESS); 1071*0Sstevel@tonic-gate } 1072*0Sstevel@tonic-gate 1073*0Sstevel@tonic-gate /* 1074*0Sstevel@tonic-gate * Set the soft state of bus nexus "dip" 1075*0Sstevel@tonic-gate */ 1076*0Sstevel@tonic-gate int 1077*0Sstevel@tonic-gate ndi_set_bus_state(dev_info_t *dip, uint_t state) 1078*0Sstevel@tonic-gate { 1079*0Sstevel@tonic-gate int rv = NDI_SUCCESS; 1080*0Sstevel@tonic-gate 1081*0Sstevel@tonic-gate if (dip == NULL) 1082*0Sstevel@tonic-gate return (NDI_FAILURE); 1083*0Sstevel@tonic-gate 1084*0Sstevel@tonic-gate mutex_enter(&(DEVI(dip)->devi_lock)); 1085*0Sstevel@tonic-gate 1086*0Sstevel@tonic-gate switch (state) { 1087*0Sstevel@tonic-gate case BUS_QUIESCED: 1088*0Sstevel@tonic-gate DEVI_SET_BUS_QUIESCE(dip); 1089*0Sstevel@tonic-gate break; 1090*0Sstevel@tonic-gate 1091*0Sstevel@tonic-gate case BUS_ACTIVE: 1092*0Sstevel@tonic-gate DEVI_SET_BUS_ACTIVE(dip); 1093*0Sstevel@tonic-gate DEVI_SET_BUS_UP(dip); 1094*0Sstevel@tonic-gate break; 1095*0Sstevel@tonic-gate 1096*0Sstevel@tonic-gate case BUS_SHUTDOWN: 1097*0Sstevel@tonic-gate DEVI_SET_BUS_DOWN(dip); 1098*0Sstevel@tonic-gate break; 1099*0Sstevel@tonic-gate 1100*0Sstevel@tonic-gate default: 1101*0Sstevel@tonic-gate rv = NDI_FAILURE; 1102*0Sstevel@tonic-gate } 1103*0Sstevel@tonic-gate 1104*0Sstevel@tonic-gate mutex_exit(&(DEVI(dip)->devi_lock)); 1105*0Sstevel@tonic-gate return (rv); 1106*0Sstevel@tonic-gate } 1107*0Sstevel@tonic-gate 1108*0Sstevel@tonic-gate /* 1109*0Sstevel@tonic-gate * These dummy functions are obsolete and may be removed. 1110*0Sstevel@tonic-gate * Retained for existing driver compatibility only. 1111*0Sstevel@tonic-gate * Drivers should be fixed not to use these functions. 1112*0Sstevel@tonic-gate * Don't write new code using these obsolete interfaces. 1113*0Sstevel@tonic-gate */ 1114*0Sstevel@tonic-gate /*ARGSUSED*/ 1115*0Sstevel@tonic-gate void 1116*0Sstevel@tonic-gate i_ndi_block_device_tree_changes(uint_t *lkcnt) /* obsolete */ 1117*0Sstevel@tonic-gate { 1118*0Sstevel@tonic-gate /* obsolete dummy function */ 1119*0Sstevel@tonic-gate } 1120*0Sstevel@tonic-gate 1121*0Sstevel@tonic-gate /*ARGSUSED*/ 1122*0Sstevel@tonic-gate void 1123*0Sstevel@tonic-gate i_ndi_allow_device_tree_changes(uint_t lkcnt) /* obsolete */ 1124*0Sstevel@tonic-gate { 1125*0Sstevel@tonic-gate /* obsolete dummy function */ 1126*0Sstevel@tonic-gate } 1127*0Sstevel@tonic-gate 1128*0Sstevel@tonic-gate /* 1129*0Sstevel@tonic-gate * Single thread entry into per-driver list 1130*0Sstevel@tonic-gate */ 1131*0Sstevel@tonic-gate /*ARGSUSED*/ 1132*0Sstevel@tonic-gate void 1133*0Sstevel@tonic-gate e_ddi_enter_driver_list(struct devnames *dnp, int *listcnt) /* obsolete */ 1134*0Sstevel@tonic-gate { 1135*0Sstevel@tonic-gate /* obsolete dummy function */ 1136*0Sstevel@tonic-gate } 1137*0Sstevel@tonic-gate 1138*0Sstevel@tonic-gate /* 1139*0Sstevel@tonic-gate * release the per-driver list 1140*0Sstevel@tonic-gate */ 1141*0Sstevel@tonic-gate /*ARGSUSED*/ 1142*0Sstevel@tonic-gate void 1143*0Sstevel@tonic-gate e_ddi_exit_driver_list(struct devnames *dnp, int listcnt) /* obsolete */ 1144*0Sstevel@tonic-gate { 1145*0Sstevel@tonic-gate /* obsolete dummy function */ 1146*0Sstevel@tonic-gate } 1147*0Sstevel@tonic-gate 1148*0Sstevel@tonic-gate /* 1149*0Sstevel@tonic-gate * Attempt to enter driver list 1150*0Sstevel@tonic-gate */ 1151*0Sstevel@tonic-gate /*ARGSUSED*/ 1152*0Sstevel@tonic-gate int 1153*0Sstevel@tonic-gate e_ddi_tryenter_driver_list(struct devnames *dnp, int *listcnt) /* obsolete */ 1154*0Sstevel@tonic-gate { 1155*0Sstevel@tonic-gate return (1); /* obsolete dummy function */ 1156*0Sstevel@tonic-gate } 1157*0Sstevel@tonic-gate 1158*0Sstevel@tonic-gate /* 1159*0Sstevel@tonic-gate * ndi event handling support functions: 1160*0Sstevel@tonic-gate * The NDI event support model is as follows: 1161*0Sstevel@tonic-gate * 1162*0Sstevel@tonic-gate * The nexus driver defines a set of events using some static structures (so 1163*0Sstevel@tonic-gate * these structures can be shared by all instances of the nexus driver). 1164*0Sstevel@tonic-gate * The nexus driver allocates an event handle and binds the event set 1165*0Sstevel@tonic-gate * to this handle. The nexus driver's event busop functions can just 1166*0Sstevel@tonic-gate * call the appropriate NDI event support function using this handle 1167*0Sstevel@tonic-gate * as the first argument. 1168*0Sstevel@tonic-gate * 1169*0Sstevel@tonic-gate * The reasoning for tying events to the device tree is that the entity 1170*0Sstevel@tonic-gate * generating the callback will typically be one of the device driver's 1171*0Sstevel@tonic-gate * ancestors in the tree. 1172*0Sstevel@tonic-gate */ 1173*0Sstevel@tonic-gate static int ndi_event_debug = 0; 1174*0Sstevel@tonic-gate 1175*0Sstevel@tonic-gate #ifdef DEBUG 1176*0Sstevel@tonic-gate #define NDI_EVENT_DEBUG ndi_event_debug 1177*0Sstevel@tonic-gate #endif /* DEBUG */ 1178*0Sstevel@tonic-gate 1179*0Sstevel@tonic-gate /* 1180*0Sstevel@tonic-gate * allocate a new ndi event handle 1181*0Sstevel@tonic-gate */ 1182*0Sstevel@tonic-gate int 1183*0Sstevel@tonic-gate ndi_event_alloc_hdl(dev_info_t *dip, ddi_iblock_cookie_t cookie, 1184*0Sstevel@tonic-gate ndi_event_hdl_t *handle, uint_t flag) 1185*0Sstevel@tonic-gate { 1186*0Sstevel@tonic-gate struct ndi_event_hdl *ndi_event_hdl; 1187*0Sstevel@tonic-gate 1188*0Sstevel@tonic-gate ndi_event_hdl = kmem_zalloc(sizeof (struct ndi_event_hdl), 1189*0Sstevel@tonic-gate ((flag & NDI_NOSLEEP) ? KM_NOSLEEP : KM_SLEEP)); 1190*0Sstevel@tonic-gate 1191*0Sstevel@tonic-gate if (!ndi_event_hdl) { 1192*0Sstevel@tonic-gate return (NDI_FAILURE); 1193*0Sstevel@tonic-gate } 1194*0Sstevel@tonic-gate 1195*0Sstevel@tonic-gate ndi_event_hdl->ndi_evthdl_dip = dip; 1196*0Sstevel@tonic-gate ndi_event_hdl->ndi_evthdl_iblock_cookie = cookie; 1197*0Sstevel@tonic-gate mutex_init(&ndi_event_hdl->ndi_evthdl_mutex, NULL, 1198*0Sstevel@tonic-gate MUTEX_DRIVER, (void *)cookie); 1199*0Sstevel@tonic-gate 1200*0Sstevel@tonic-gate mutex_init(&ndi_event_hdl->ndi_evthdl_cb_mutex, NULL, 1201*0Sstevel@tonic-gate MUTEX_DRIVER, (void *)cookie); 1202*0Sstevel@tonic-gate 1203*0Sstevel@tonic-gate *handle = (ndi_event_hdl_t)ndi_event_hdl; 1204*0Sstevel@tonic-gate 1205*0Sstevel@tonic-gate return (NDI_SUCCESS); 1206*0Sstevel@tonic-gate } 1207*0Sstevel@tonic-gate 1208*0Sstevel@tonic-gate /* 1209*0Sstevel@tonic-gate * free the ndi event handle 1210*0Sstevel@tonic-gate */ 1211*0Sstevel@tonic-gate int 1212*0Sstevel@tonic-gate ndi_event_free_hdl(ndi_event_hdl_t handle) 1213*0Sstevel@tonic-gate { 1214*0Sstevel@tonic-gate struct ndi_event_hdl *ndi_event_hdl = (struct ndi_event_hdl *)handle; 1215*0Sstevel@tonic-gate ndi_event_cookie_t *cookie; 1216*0Sstevel@tonic-gate ndi_event_cookie_t *free; 1217*0Sstevel@tonic-gate 1218*0Sstevel@tonic-gate ASSERT(handle); 1219*0Sstevel@tonic-gate 1220*0Sstevel@tonic-gate mutex_enter(&ndi_event_hdl->ndi_evthdl_mutex); 1221*0Sstevel@tonic-gate mutex_enter(&ndi_event_hdl->ndi_evthdl_cb_mutex); 1222*0Sstevel@tonic-gate 1223*0Sstevel@tonic-gate cookie = ndi_event_hdl->ndi_evthdl_cookie_list; 1224*0Sstevel@tonic-gate 1225*0Sstevel@tonic-gate /* deallocate all defined cookies */ 1226*0Sstevel@tonic-gate while (cookie != NULL) { 1227*0Sstevel@tonic-gate ASSERT(cookie->callback_list == NULL); 1228*0Sstevel@tonic-gate free = cookie; 1229*0Sstevel@tonic-gate cookie = cookie->next_cookie; 1230*0Sstevel@tonic-gate 1231*0Sstevel@tonic-gate kmem_free(free, sizeof (ndi_event_cookie_t)); 1232*0Sstevel@tonic-gate } 1233*0Sstevel@tonic-gate 1234*0Sstevel@tonic-gate 1235*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_cb_mutex); 1236*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_mutex); 1237*0Sstevel@tonic-gate 1238*0Sstevel@tonic-gate /* destroy mutexes */ 1239*0Sstevel@tonic-gate mutex_destroy(&ndi_event_hdl->ndi_evthdl_mutex); 1240*0Sstevel@tonic-gate mutex_destroy(&ndi_event_hdl->ndi_evthdl_cb_mutex); 1241*0Sstevel@tonic-gate 1242*0Sstevel@tonic-gate /* free event handle */ 1243*0Sstevel@tonic-gate kmem_free(ndi_event_hdl, sizeof (struct ndi_event_hdl)); 1244*0Sstevel@tonic-gate 1245*0Sstevel@tonic-gate return (NDI_SUCCESS); 1246*0Sstevel@tonic-gate } 1247*0Sstevel@tonic-gate 1248*0Sstevel@tonic-gate 1249*0Sstevel@tonic-gate /* 1250*0Sstevel@tonic-gate * ndi_event_bind_set() adds a set of events to the NDI event 1251*0Sstevel@tonic-gate * handle. 1252*0Sstevel@tonic-gate * 1253*0Sstevel@tonic-gate * Events generated by high level interrupts should not 1254*0Sstevel@tonic-gate * be mixed in the same event set with events generated by 1255*0Sstevel@tonic-gate * normal interrupts or kernel events. 1256*0Sstevel@tonic-gate * 1257*0Sstevel@tonic-gate * This function can be called multiple times to bind 1258*0Sstevel@tonic-gate * additional sets to the event handle. 1259*0Sstevel@tonic-gate * However, events generated by high level interrupts cannot 1260*0Sstevel@tonic-gate * be bound to a handle that already has bound events generated 1261*0Sstevel@tonic-gate * by normal interrupts or from kernel context and vice versa. 1262*0Sstevel@tonic-gate */ 1263*0Sstevel@tonic-gate int 1264*0Sstevel@tonic-gate ndi_event_bind_set(ndi_event_hdl_t handle, 1265*0Sstevel@tonic-gate ndi_event_set_t *ndi_events, 1266*0Sstevel@tonic-gate uint_t flag) 1267*0Sstevel@tonic-gate { 1268*0Sstevel@tonic-gate struct ndi_event_hdl *ndi_event_hdl; 1269*0Sstevel@tonic-gate ndi_event_cookie_t *next, *prev, *new_cookie; 1270*0Sstevel@tonic-gate uint_t i, len; 1271*0Sstevel@tonic-gate uint_t dup = 0; 1272*0Sstevel@tonic-gate uint_t high_plevels, other_plevels; 1273*0Sstevel@tonic-gate ndi_event_definition_t *ndi_event_defs; 1274*0Sstevel@tonic-gate 1275*0Sstevel@tonic-gate int km_flag = ((flag & NDI_NOSLEEP) ? KM_NOSLEEP : KM_SLEEP); 1276*0Sstevel@tonic-gate 1277*0Sstevel@tonic-gate ASSERT(handle); 1278*0Sstevel@tonic-gate ASSERT(ndi_events); 1279*0Sstevel@tonic-gate 1280*0Sstevel@tonic-gate /* 1281*0Sstevel@tonic-gate * binding must be performed during attach/detach 1282*0Sstevel@tonic-gate */ 1283*0Sstevel@tonic-gate if (!DEVI_IS_ATTACHING(handle->ndi_evthdl_dip) && 1284*0Sstevel@tonic-gate !DEVI_IS_DETACHING(handle->ndi_evthdl_dip)) { 1285*0Sstevel@tonic-gate cmn_err(CE_WARN, "ndi_event_bind_set must be called within " 1286*0Sstevel@tonic-gate "attach or detach"); 1287*0Sstevel@tonic-gate return (NDI_FAILURE); 1288*0Sstevel@tonic-gate } 1289*0Sstevel@tonic-gate 1290*0Sstevel@tonic-gate /* 1291*0Sstevel@tonic-gate * if it is not the correct version or the event set is 1292*0Sstevel@tonic-gate * empty, bail out 1293*0Sstevel@tonic-gate */ 1294*0Sstevel@tonic-gate if (ndi_events->ndi_events_version != NDI_EVENTS_REV1) 1295*0Sstevel@tonic-gate return (NDI_FAILURE); 1296*0Sstevel@tonic-gate 1297*0Sstevel@tonic-gate ndi_event_hdl = (struct ndi_event_hdl *)handle; 1298*0Sstevel@tonic-gate ndi_event_defs = ndi_events->ndi_event_defs; 1299*0Sstevel@tonic-gate high_plevels = other_plevels = 0; 1300*0Sstevel@tonic-gate 1301*0Sstevel@tonic-gate mutex_enter(&ndi_event_hdl->ndi_evthdl_mutex); 1302*0Sstevel@tonic-gate 1303*0Sstevel@tonic-gate /* check for mixing events at high level with the other types */ 1304*0Sstevel@tonic-gate for (i = 0; i < ndi_events->ndi_n_events; i++) { 1305*0Sstevel@tonic-gate if (ndi_event_defs[i].ndi_event_plevel == EPL_HIGHLEVEL) { 1306*0Sstevel@tonic-gate high_plevels++; 1307*0Sstevel@tonic-gate } else { 1308*0Sstevel@tonic-gate other_plevels++; 1309*0Sstevel@tonic-gate } 1310*0Sstevel@tonic-gate } 1311*0Sstevel@tonic-gate 1312*0Sstevel@tonic-gate /* 1313*0Sstevel@tonic-gate * bail out if high level events are mixed with other types in this 1314*0Sstevel@tonic-gate * event set or the set is incompatible with the set in the handle 1315*0Sstevel@tonic-gate */ 1316*0Sstevel@tonic-gate if ((high_plevels && other_plevels) || 1317*0Sstevel@tonic-gate (other_plevels && ndi_event_hdl->ndi_evthdl_high_plevels) || 1318*0Sstevel@tonic-gate (high_plevels && ndi_event_hdl->ndi_evthdl_other_plevels)) { 1319*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_mutex); 1320*0Sstevel@tonic-gate 1321*0Sstevel@tonic-gate return (NDI_FAILURE); 1322*0Sstevel@tonic-gate } 1323*0Sstevel@tonic-gate 1324*0Sstevel@tonic-gate /* 1325*0Sstevel@tonic-gate * check for duplicate events in both the existing handle 1326*0Sstevel@tonic-gate * and the event set, add events if not duplicates 1327*0Sstevel@tonic-gate */ 1328*0Sstevel@tonic-gate next = ndi_event_hdl->ndi_evthdl_cookie_list; 1329*0Sstevel@tonic-gate for (i = 0; i < ndi_events->ndi_n_events; i++) { 1330*0Sstevel@tonic-gate while (next != NULL) { 1331*0Sstevel@tonic-gate len = strlen(NDI_EVENT_NAME(next)) + 1; 1332*0Sstevel@tonic-gate if (strncmp(NDI_EVENT_NAME(next), 1333*0Sstevel@tonic-gate ndi_event_defs[i].ndi_event_name, len) == 0) { 1334*0Sstevel@tonic-gate dup = 1; 1335*0Sstevel@tonic-gate break; 1336*0Sstevel@tonic-gate } 1337*0Sstevel@tonic-gate 1338*0Sstevel@tonic-gate prev = next; 1339*0Sstevel@tonic-gate next = next->next_cookie; 1340*0Sstevel@tonic-gate } 1341*0Sstevel@tonic-gate 1342*0Sstevel@tonic-gate if (dup == 0) { 1343*0Sstevel@tonic-gate new_cookie = kmem_zalloc(sizeof (ndi_event_cookie_t), 1344*0Sstevel@tonic-gate km_flag); 1345*0Sstevel@tonic-gate 1346*0Sstevel@tonic-gate if (!new_cookie) 1347*0Sstevel@tonic-gate return (NDI_FAILURE); 1348*0Sstevel@tonic-gate 1349*0Sstevel@tonic-gate if (ndi_event_hdl->ndi_evthdl_n_events == 0) { 1350*0Sstevel@tonic-gate ndi_event_hdl->ndi_evthdl_cookie_list = 1351*0Sstevel@tonic-gate new_cookie; 1352*0Sstevel@tonic-gate } else { 1353*0Sstevel@tonic-gate prev->next_cookie = new_cookie; 1354*0Sstevel@tonic-gate } 1355*0Sstevel@tonic-gate 1356*0Sstevel@tonic-gate ndi_event_hdl->ndi_evthdl_n_events++; 1357*0Sstevel@tonic-gate 1358*0Sstevel@tonic-gate /* 1359*0Sstevel@tonic-gate * set up new cookie 1360*0Sstevel@tonic-gate */ 1361*0Sstevel@tonic-gate new_cookie->definition = &ndi_event_defs[i]; 1362*0Sstevel@tonic-gate new_cookie->ddip = ndi_event_hdl->ndi_evthdl_dip; 1363*0Sstevel@tonic-gate 1364*0Sstevel@tonic-gate } else { 1365*0Sstevel@tonic-gate /* 1366*0Sstevel@tonic-gate * event not added, must correct plevel numbers 1367*0Sstevel@tonic-gate */ 1368*0Sstevel@tonic-gate if (ndi_event_defs[i].ndi_event_plevel == 1369*0Sstevel@tonic-gate EPL_HIGHLEVEL) { 1370*0Sstevel@tonic-gate high_plevels--; 1371*0Sstevel@tonic-gate } else { 1372*0Sstevel@tonic-gate other_plevels--; 1373*0Sstevel@tonic-gate } 1374*0Sstevel@tonic-gate } 1375*0Sstevel@tonic-gate 1376*0Sstevel@tonic-gate dup = 0; 1377*0Sstevel@tonic-gate next = ndi_event_hdl->ndi_evthdl_cookie_list; 1378*0Sstevel@tonic-gate prev = NULL; 1379*0Sstevel@tonic-gate 1380*0Sstevel@tonic-gate } 1381*0Sstevel@tonic-gate 1382*0Sstevel@tonic-gate ndi_event_hdl->ndi_evthdl_high_plevels += high_plevels; 1383*0Sstevel@tonic-gate ndi_event_hdl->ndi_evthdl_other_plevels += other_plevels; 1384*0Sstevel@tonic-gate 1385*0Sstevel@tonic-gate ASSERT((ndi_event_hdl->ndi_evthdl_high_plevels == 0) || 1386*0Sstevel@tonic-gate (ndi_event_hdl->ndi_evthdl_other_plevels == 0)); 1387*0Sstevel@tonic-gate 1388*0Sstevel@tonic-gate #ifdef NDI_EVENT_DEBUG 1389*0Sstevel@tonic-gate if (ndi_event_debug) { 1390*0Sstevel@tonic-gate ndi_event_dump_hdl(ndi_event_hdl, "ndi_event_bind_set"); 1391*0Sstevel@tonic-gate } 1392*0Sstevel@tonic-gate #endif /* NDI_EVENT_DEBUG */ 1393*0Sstevel@tonic-gate 1394*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_mutex); 1395*0Sstevel@tonic-gate 1396*0Sstevel@tonic-gate return (NDI_SUCCESS); 1397*0Sstevel@tonic-gate } 1398*0Sstevel@tonic-gate 1399*0Sstevel@tonic-gate /* 1400*0Sstevel@tonic-gate * ndi_event_unbind_set() unbinds a set of events, previously 1401*0Sstevel@tonic-gate * bound using ndi_event_bind_set(), from the NDI event 1402*0Sstevel@tonic-gate * handle. 1403*0Sstevel@tonic-gate * 1404*0Sstevel@tonic-gate * This routine will unbind all events in the event set. If an event, 1405*0Sstevel@tonic-gate * specified in the event set, is not found in the handle, this 1406*0Sstevel@tonic-gate * routine will proceed onto the next member of the set as if the event 1407*0Sstevel@tonic-gate * was never specified. 1408*0Sstevel@tonic-gate * 1409*0Sstevel@tonic-gate * The event set may be a subset of the set of events that 1410*0Sstevel@tonic-gate * was previously bound to the handle. For example, events 1411*0Sstevel@tonic-gate * can be individually unbound. 1412*0Sstevel@tonic-gate * 1413*0Sstevel@tonic-gate * An event cannot be unbound if callbacks are still 1414*0Sstevel@tonic-gate * registered against the event. 1415*0Sstevel@tonic-gate */ 1416*0Sstevel@tonic-gate /*ARGSUSED*/ 1417*0Sstevel@tonic-gate int 1418*0Sstevel@tonic-gate ndi_event_unbind_set(ndi_event_hdl_t handle, ndi_event_set_t *ndi_events, 1419*0Sstevel@tonic-gate uint_t flag) 1420*0Sstevel@tonic-gate { 1421*0Sstevel@tonic-gate ndi_event_definition_t *ndi_event_defs; 1422*0Sstevel@tonic-gate int len; 1423*0Sstevel@tonic-gate uint_t i; 1424*0Sstevel@tonic-gate int rval; 1425*0Sstevel@tonic-gate ndi_event_cookie_t *cookie_list; 1426*0Sstevel@tonic-gate ndi_event_cookie_t *prev = NULL; 1427*0Sstevel@tonic-gate 1428*0Sstevel@tonic-gate ASSERT(ndi_events); 1429*0Sstevel@tonic-gate ASSERT(handle); 1430*0Sstevel@tonic-gate 1431*0Sstevel@tonic-gate /* 1432*0Sstevel@tonic-gate * binding must be performed during attach/detac 1433*0Sstevel@tonic-gate */ 1434*0Sstevel@tonic-gate if (!DEVI_IS_ATTACHING(handle->ndi_evthdl_dip) && 1435*0Sstevel@tonic-gate !DEVI_IS_DETACHING(handle->ndi_evthdl_dip)) { 1436*0Sstevel@tonic-gate cmn_err(CE_WARN, "ndi_event_bind_set must be called within " 1437*0Sstevel@tonic-gate "attach or detach"); 1438*0Sstevel@tonic-gate return (NDI_FAILURE); 1439*0Sstevel@tonic-gate } 1440*0Sstevel@tonic-gate 1441*0Sstevel@tonic-gate /* bail out if ndi_event_set is outdated */ 1442*0Sstevel@tonic-gate if (ndi_events->ndi_events_version != NDI_EVENTS_REV1) { 1443*0Sstevel@tonic-gate return (NDI_FAILURE); 1444*0Sstevel@tonic-gate } 1445*0Sstevel@tonic-gate 1446*0Sstevel@tonic-gate ASSERT(ndi_events->ndi_event_defs); 1447*0Sstevel@tonic-gate 1448*0Sstevel@tonic-gate ndi_event_defs = ndi_events->ndi_event_defs; 1449*0Sstevel@tonic-gate 1450*0Sstevel@tonic-gate mutex_enter(&handle->ndi_evthdl_mutex); 1451*0Sstevel@tonic-gate mutex_enter(&handle->ndi_evthdl_cb_mutex); 1452*0Sstevel@tonic-gate 1453*0Sstevel@tonic-gate /* 1454*0Sstevel@tonic-gate * Verify that all events in the event set are eligible 1455*0Sstevel@tonic-gate * for unbinding(ie. there are no outstanding callbacks). 1456*0Sstevel@tonic-gate * If any one of the events are ineligible, fail entire 1457*0Sstevel@tonic-gate * operation. 1458*0Sstevel@tonic-gate */ 1459*0Sstevel@tonic-gate 1460*0Sstevel@tonic-gate for (i = 0; i < ndi_events->ndi_n_events; i++) { 1461*0Sstevel@tonic-gate cookie_list = handle->ndi_evthdl_cookie_list; 1462*0Sstevel@tonic-gate while (cookie_list != NULL) { 1463*0Sstevel@tonic-gate len = strlen(NDI_EVENT_NAME(cookie_list)) + 1; 1464*0Sstevel@tonic-gate if (strncmp(NDI_EVENT_NAME(cookie_list), 1465*0Sstevel@tonic-gate ndi_event_defs[i].ndi_event_name, len) == 0) { 1466*0Sstevel@tonic-gate 1467*0Sstevel@tonic-gate ASSERT(cookie_list->callback_list == NULL); 1468*0Sstevel@tonic-gate if (cookie_list->callback_list) { 1469*0Sstevel@tonic-gate rval = NDI_FAILURE; 1470*0Sstevel@tonic-gate goto done; 1471*0Sstevel@tonic-gate } 1472*0Sstevel@tonic-gate break; 1473*0Sstevel@tonic-gate } else { 1474*0Sstevel@tonic-gate cookie_list = cookie_list->next_cookie; 1475*0Sstevel@tonic-gate } 1476*0Sstevel@tonic-gate } 1477*0Sstevel@tonic-gate } 1478*0Sstevel@tonic-gate 1479*0Sstevel@tonic-gate /* 1480*0Sstevel@tonic-gate * remove all events found within the handle 1481*0Sstevel@tonic-gate * If an event is not found, this function will proceed as if the event 1482*0Sstevel@tonic-gate * was never specified. 1483*0Sstevel@tonic-gate */ 1484*0Sstevel@tonic-gate 1485*0Sstevel@tonic-gate for (i = 0; i < ndi_events->ndi_n_events; i++) { 1486*0Sstevel@tonic-gate cookie_list = handle->ndi_evthdl_cookie_list; 1487*0Sstevel@tonic-gate prev = NULL; 1488*0Sstevel@tonic-gate while (cookie_list != NULL) { 1489*0Sstevel@tonic-gate len = strlen(NDI_EVENT_NAME(cookie_list)) + 1; 1490*0Sstevel@tonic-gate if (strncmp(NDI_EVENT_NAME(cookie_list), 1491*0Sstevel@tonic-gate ndi_event_defs[i].ndi_event_name, len) == 0) { 1492*0Sstevel@tonic-gate 1493*0Sstevel@tonic-gate /* 1494*0Sstevel@tonic-gate * can not unbind an event definition with 1495*0Sstevel@tonic-gate * outstanding callbacks 1496*0Sstevel@tonic-gate */ 1497*0Sstevel@tonic-gate if (cookie_list->callback_list) { 1498*0Sstevel@tonic-gate rval = NDI_FAILURE; 1499*0Sstevel@tonic-gate goto done; 1500*0Sstevel@tonic-gate } 1501*0Sstevel@tonic-gate 1502*0Sstevel@tonic-gate /* remove this cookie from the list */ 1503*0Sstevel@tonic-gate if (prev != NULL) { 1504*0Sstevel@tonic-gate prev->next_cookie = 1505*0Sstevel@tonic-gate cookie_list->next_cookie; 1506*0Sstevel@tonic-gate } else { 1507*0Sstevel@tonic-gate handle->ndi_evthdl_cookie_list = 1508*0Sstevel@tonic-gate cookie_list->next_cookie; 1509*0Sstevel@tonic-gate } 1510*0Sstevel@tonic-gate 1511*0Sstevel@tonic-gate /* adjust plevel counts */ 1512*0Sstevel@tonic-gate if (NDI_EVENT_PLEVEL(cookie_list) == 1513*0Sstevel@tonic-gate EPL_HIGHLEVEL) { 1514*0Sstevel@tonic-gate handle->ndi_evthdl_high_plevels--; 1515*0Sstevel@tonic-gate } else { 1516*0Sstevel@tonic-gate handle->ndi_evthdl_other_plevels--; 1517*0Sstevel@tonic-gate } 1518*0Sstevel@tonic-gate 1519*0Sstevel@tonic-gate /* adjust cookie count */ 1520*0Sstevel@tonic-gate handle->ndi_evthdl_n_events--; 1521*0Sstevel@tonic-gate 1522*0Sstevel@tonic-gate /* free the cookie */ 1523*0Sstevel@tonic-gate kmem_free(cookie_list, 1524*0Sstevel@tonic-gate sizeof (ndi_event_cookie_t)); 1525*0Sstevel@tonic-gate 1526*0Sstevel@tonic-gate cookie_list = handle->ndi_evthdl_cookie_list; 1527*0Sstevel@tonic-gate break; 1528*0Sstevel@tonic-gate 1529*0Sstevel@tonic-gate } else { 1530*0Sstevel@tonic-gate prev = cookie_list; 1531*0Sstevel@tonic-gate cookie_list = cookie_list->next_cookie; 1532*0Sstevel@tonic-gate } 1533*0Sstevel@tonic-gate 1534*0Sstevel@tonic-gate } 1535*0Sstevel@tonic-gate 1536*0Sstevel@tonic-gate } 1537*0Sstevel@tonic-gate 1538*0Sstevel@tonic-gate #ifdef NDI_EVENT_DEBUG 1539*0Sstevel@tonic-gate if (ndi_event_debug) { 1540*0Sstevel@tonic-gate ndi_event_dump_hdl(handle, "ndi_event_unbind_set"); 1541*0Sstevel@tonic-gate } 1542*0Sstevel@tonic-gate #endif /* NDI_EVENT_DEBUG */ 1543*0Sstevel@tonic-gate 1544*0Sstevel@tonic-gate rval = NDI_SUCCESS; 1545*0Sstevel@tonic-gate 1546*0Sstevel@tonic-gate done: 1547*0Sstevel@tonic-gate mutex_exit(&handle->ndi_evthdl_cb_mutex); 1548*0Sstevel@tonic-gate mutex_exit(&handle->ndi_evthdl_mutex); 1549*0Sstevel@tonic-gate 1550*0Sstevel@tonic-gate return (rval); 1551*0Sstevel@tonic-gate } 1552*0Sstevel@tonic-gate 1553*0Sstevel@tonic-gate /* 1554*0Sstevel@tonic-gate * ndi_event_retrieve_cookie(): 1555*0Sstevel@tonic-gate * Return an event cookie for eventname if this nexus driver 1556*0Sstevel@tonic-gate * has defined the named event. The event cookie returned 1557*0Sstevel@tonic-gate * by this function is used to register callback handlers 1558*0Sstevel@tonic-gate * for the event. 1559*0Sstevel@tonic-gate * 1560*0Sstevel@tonic-gate * ndi_event_retrieve_cookie() is intended to be used in the 1561*0Sstevel@tonic-gate * nexus driver's bus_get_eventcookie busop routine. 1562*0Sstevel@tonic-gate * 1563*0Sstevel@tonic-gate * If the event is not defined by this bus nexus driver, and flag 1564*0Sstevel@tonic-gate * does not include NDI_EVENT_NOPASS, then ndi_event_retrieve_cookie() 1565*0Sstevel@tonic-gate * will pass the request up the device tree hierarchy by calling 1566*0Sstevel@tonic-gate * ndi_busop_get_eventcookie(9N). 1567*0Sstevel@tonic-gate * If the event is not defined by this bus nexus driver, and flag 1568*0Sstevel@tonic-gate * does include NDI_EVENT_NOPASS, ndi_event_retrieve_cookie() 1569*0Sstevel@tonic-gate * will return NDI_FAILURE. The caller may then determine what further 1570*0Sstevel@tonic-gate * action to take, such as using a different handle, passing the 1571*0Sstevel@tonic-gate * request up the device tree using ndi_busop_get_eventcookie(9N), 1572*0Sstevel@tonic-gate * or returning the failure to the caller, thus blocking the 1573*0Sstevel@tonic-gate * progress of the request up the tree. 1574*0Sstevel@tonic-gate */ 1575*0Sstevel@tonic-gate int 1576*0Sstevel@tonic-gate ndi_event_retrieve_cookie(ndi_event_hdl_t handle, 1577*0Sstevel@tonic-gate dev_info_t *rdip, 1578*0Sstevel@tonic-gate char *eventname, 1579*0Sstevel@tonic-gate ddi_eventcookie_t *cookiep, 1580*0Sstevel@tonic-gate uint_t flag) 1581*0Sstevel@tonic-gate { 1582*0Sstevel@tonic-gate struct ndi_event_hdl *ndi_event_hdl = (struct ndi_event_hdl *)handle; 1583*0Sstevel@tonic-gate int len; 1584*0Sstevel@tonic-gate ndi_event_cookie_t *cookie_list; 1585*0Sstevel@tonic-gate 1586*0Sstevel@tonic-gate mutex_enter(&ndi_event_hdl->ndi_evthdl_mutex); 1587*0Sstevel@tonic-gate 1588*0Sstevel@tonic-gate cookie_list = ndi_event_hdl->ndi_evthdl_cookie_list; 1589*0Sstevel@tonic-gate /* 1590*0Sstevel@tonic-gate * search the cookie list for the event name and return 1591*0Sstevel@tonic-gate * cookie if found. 1592*0Sstevel@tonic-gate */ 1593*0Sstevel@tonic-gate while (cookie_list != NULL) { 1594*0Sstevel@tonic-gate 1595*0Sstevel@tonic-gate len = strlen(NDI_EVENT_NAME(cookie_list)) + 1; 1596*0Sstevel@tonic-gate if (strncmp(NDI_EVENT_NAME(cookie_list), eventname, 1597*0Sstevel@tonic-gate len) == 0) { 1598*0Sstevel@tonic-gate *cookiep = (ddi_eventcookie_t)cookie_list; 1599*0Sstevel@tonic-gate 1600*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_mutex); 1601*0Sstevel@tonic-gate return (NDI_SUCCESS); 1602*0Sstevel@tonic-gate } 1603*0Sstevel@tonic-gate 1604*0Sstevel@tonic-gate cookie_list = cookie_list->next_cookie; 1605*0Sstevel@tonic-gate } 1606*0Sstevel@tonic-gate 1607*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_mutex); 1608*0Sstevel@tonic-gate /* 1609*0Sstevel@tonic-gate * event was not found, pass up or return failure 1610*0Sstevel@tonic-gate */ 1611*0Sstevel@tonic-gate if ((flag & NDI_EVENT_NOPASS) == 0) { 1612*0Sstevel@tonic-gate return (ndi_busop_get_eventcookie( 1613*0Sstevel@tonic-gate ndi_event_hdl->ndi_evthdl_dip, rdip, 1614*0Sstevel@tonic-gate eventname, cookiep)); 1615*0Sstevel@tonic-gate } else { 1616*0Sstevel@tonic-gate return (NDI_FAILURE); 1617*0Sstevel@tonic-gate } 1618*0Sstevel@tonic-gate } 1619*0Sstevel@tonic-gate 1620*0Sstevel@tonic-gate /* 1621*0Sstevel@tonic-gate * check whether this nexus defined this event and look up attributes 1622*0Sstevel@tonic-gate */ 1623*0Sstevel@tonic-gate static int 1624*0Sstevel@tonic-gate ndi_event_is_defined(ndi_event_hdl_t handle, 1625*0Sstevel@tonic-gate ddi_eventcookie_t cookie, int *attributes) 1626*0Sstevel@tonic-gate { 1627*0Sstevel@tonic-gate 1628*0Sstevel@tonic-gate struct ndi_event_hdl *ndi_event_hdl = (struct ndi_event_hdl *)handle; 1629*0Sstevel@tonic-gate ndi_event_cookie_t *cookie_list; 1630*0Sstevel@tonic-gate 1631*0Sstevel@tonic-gate ASSERT(mutex_owned(&handle->ndi_evthdl_mutex)); 1632*0Sstevel@tonic-gate 1633*0Sstevel@tonic-gate cookie_list = ndi_event_hdl->ndi_evthdl_cookie_list; 1634*0Sstevel@tonic-gate while (cookie_list != NULL) { 1635*0Sstevel@tonic-gate if (cookie_list == NDI_EVENT(cookie)) { 1636*0Sstevel@tonic-gate if (attributes) 1637*0Sstevel@tonic-gate *attributes = 1638*0Sstevel@tonic-gate NDI_EVENT_ATTRIBUTES(cookie_list); 1639*0Sstevel@tonic-gate 1640*0Sstevel@tonic-gate return (NDI_SUCCESS); 1641*0Sstevel@tonic-gate } 1642*0Sstevel@tonic-gate 1643*0Sstevel@tonic-gate cookie_list = cookie_list->next_cookie; 1644*0Sstevel@tonic-gate } 1645*0Sstevel@tonic-gate 1646*0Sstevel@tonic-gate return (NDI_FAILURE); 1647*0Sstevel@tonic-gate } 1648*0Sstevel@tonic-gate 1649*0Sstevel@tonic-gate /* 1650*0Sstevel@tonic-gate * ndi_event_add_callback(): adds an event callback registration 1651*0Sstevel@tonic-gate * to the event cookie defining this event. 1652*0Sstevel@tonic-gate * 1653*0Sstevel@tonic-gate * Refer also to bus_add_eventcall(9n) and ndi_busop_add_eventcall(9n). 1654*0Sstevel@tonic-gate * 1655*0Sstevel@tonic-gate * ndi_event_add_callback(9n) is intended to be used in 1656*0Sstevel@tonic-gate * the nexus driver's bus_add_eventcall(9n) busop function. 1657*0Sstevel@tonic-gate * 1658*0Sstevel@tonic-gate * If the event is not defined by this bus nexus driver, 1659*0Sstevel@tonic-gate * ndi_event_add_callback() will return NDI_FAILURE. 1660*0Sstevel@tonic-gate */ 1661*0Sstevel@tonic-gate int 1662*0Sstevel@tonic-gate ndi_event_add_callback(ndi_event_hdl_t handle, dev_info_t *child_dip, 1663*0Sstevel@tonic-gate ddi_eventcookie_t cookie, 1664*0Sstevel@tonic-gate void (*event_callback)(dev_info_t *, 1665*0Sstevel@tonic-gate ddi_eventcookie_t, void *arg, void *impldata), 1666*0Sstevel@tonic-gate void *arg, 1667*0Sstevel@tonic-gate uint_t flag, 1668*0Sstevel@tonic-gate ddi_callback_id_t *cb_id) 1669*0Sstevel@tonic-gate { 1670*0Sstevel@tonic-gate struct ndi_event_hdl *ndi_event_hdl = (struct ndi_event_hdl *)handle; 1671*0Sstevel@tonic-gate int km_flag = ((flag & NDI_NOSLEEP) ? KM_NOSLEEP : KM_SLEEP); 1672*0Sstevel@tonic-gate ndi_event_callbacks_t *cb; 1673*0Sstevel@tonic-gate 1674*0Sstevel@tonic-gate mutex_enter(&ndi_event_hdl->ndi_evthdl_mutex); 1675*0Sstevel@tonic-gate 1676*0Sstevel@tonic-gate /* 1677*0Sstevel@tonic-gate * if the event was not bound to this handle, return failure 1678*0Sstevel@tonic-gate */ 1679*0Sstevel@tonic-gate if (ndi_event_is_defined(handle, cookie, NULL) != NDI_SUCCESS) { 1680*0Sstevel@tonic-gate 1681*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_mutex); 1682*0Sstevel@tonic-gate return (NDI_FAILURE); 1683*0Sstevel@tonic-gate 1684*0Sstevel@tonic-gate } 1685*0Sstevel@tonic-gate 1686*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_mutex); 1687*0Sstevel@tonic-gate 1688*0Sstevel@tonic-gate /* 1689*0Sstevel@tonic-gate * allocate space for a callback structure 1690*0Sstevel@tonic-gate */ 1691*0Sstevel@tonic-gate cb = kmem_zalloc(sizeof (ndi_event_callbacks_t), km_flag); 1692*0Sstevel@tonic-gate if (cb == NULL) { 1693*0Sstevel@tonic-gate return (NDI_FAILURE); 1694*0Sstevel@tonic-gate } 1695*0Sstevel@tonic-gate 1696*0Sstevel@tonic-gate mutex_enter(&ndi_event_hdl->ndi_evthdl_mutex); 1697*0Sstevel@tonic-gate 1698*0Sstevel@tonic-gate /* initialize callback structure */ 1699*0Sstevel@tonic-gate cb->ndi_evtcb_dip = child_dip; 1700*0Sstevel@tonic-gate cb->ndi_evtcb_callback = event_callback; 1701*0Sstevel@tonic-gate cb->ndi_evtcb_arg = arg; 1702*0Sstevel@tonic-gate cb->ndi_evtcb_cookie = cookie; 1703*0Sstevel@tonic-gate cb->devname = (char *)ddi_driver_name(child_dip); 1704*0Sstevel@tonic-gate 1705*0Sstevel@tonic-gate *cb_id = (ddi_callback_id_t)cb; 1706*0Sstevel@tonic-gate mutex_enter(&ndi_event_hdl->ndi_evthdl_cb_mutex); 1707*0Sstevel@tonic-gate 1708*0Sstevel@tonic-gate /* add this callback structure to the list */ 1709*0Sstevel@tonic-gate if (NDI_EVENT(cookie)->callback_list) { 1710*0Sstevel@tonic-gate cb->ndi_evtcb_next = NDI_EVENT(cookie)->callback_list; 1711*0Sstevel@tonic-gate NDI_EVENT(cookie)->callback_list->ndi_evtcb_prev = cb; 1712*0Sstevel@tonic-gate NDI_EVENT(cookie)->callback_list = cb; 1713*0Sstevel@tonic-gate } else { 1714*0Sstevel@tonic-gate NDI_EVENT(cookie)->callback_list = cb; 1715*0Sstevel@tonic-gate } 1716*0Sstevel@tonic-gate #ifdef NDI_EVENT_DEBUG 1717*0Sstevel@tonic-gate if (ndi_event_debug) { 1718*0Sstevel@tonic-gate ndi_event_dump_hdl(ndi_event_hdl, "ndi_event_add_callback"); 1719*0Sstevel@tonic-gate } 1720*0Sstevel@tonic-gate #endif /* NDI_EVENT_DEBUG */ 1721*0Sstevel@tonic-gate 1722*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_cb_mutex); 1723*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_mutex); 1724*0Sstevel@tonic-gate 1725*0Sstevel@tonic-gate return (NDI_SUCCESS); 1726*0Sstevel@tonic-gate } 1727*0Sstevel@tonic-gate 1728*0Sstevel@tonic-gate /* 1729*0Sstevel@tonic-gate * ndi_event_remove_callback(): 1730*0Sstevel@tonic-gate * 1731*0Sstevel@tonic-gate * ndi_event_remove_callback() removes a callback that was 1732*0Sstevel@tonic-gate * previously registered using ndi_event_add_callback(9N). 1733*0Sstevel@tonic-gate * Refer also to bus_remove_eventcall(9n) and 1734*0Sstevel@tonic-gate * ndi_busop_remove_eventcall(9n). 1735*0Sstevel@tonic-gate * ndi_event_remove_callback(9n) is intended to be used in 1736*0Sstevel@tonic-gate * the nexus driver's bus_remove_eventcall (9n) busop function. 1737*0Sstevel@tonic-gate * If the event is not defined by this bus nexus driver, 1738*0Sstevel@tonic-gate * ndi_event_remove_callback() will return NDI_FAILURE. 1739*0Sstevel@tonic-gate */ 1740*0Sstevel@tonic-gate static void do_ndi_event_remove_callback(struct ndi_event_hdl *ndi_event_hdl, 1741*0Sstevel@tonic-gate ddi_callback_id_t cb_id); 1742*0Sstevel@tonic-gate 1743*0Sstevel@tonic-gate int 1744*0Sstevel@tonic-gate ndi_event_remove_callback(ndi_event_hdl_t handle, ddi_callback_id_t cb_id) 1745*0Sstevel@tonic-gate { 1746*0Sstevel@tonic-gate struct ndi_event_hdl *ndi_event_hdl = (struct ndi_event_hdl *)handle; 1747*0Sstevel@tonic-gate 1748*0Sstevel@tonic-gate ASSERT(cb_id); 1749*0Sstevel@tonic-gate 1750*0Sstevel@tonic-gate mutex_enter(&ndi_event_hdl->ndi_evthdl_mutex); 1751*0Sstevel@tonic-gate mutex_enter(&ndi_event_hdl->ndi_evthdl_cb_mutex); 1752*0Sstevel@tonic-gate 1753*0Sstevel@tonic-gate do_ndi_event_remove_callback(ndi_event_hdl, cb_id); 1754*0Sstevel@tonic-gate 1755*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_cb_mutex); 1756*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_mutex); 1757*0Sstevel@tonic-gate 1758*0Sstevel@tonic-gate return (NDI_SUCCESS); 1759*0Sstevel@tonic-gate } 1760*0Sstevel@tonic-gate 1761*0Sstevel@tonic-gate /*ARGSUSED*/ 1762*0Sstevel@tonic-gate static void 1763*0Sstevel@tonic-gate do_ndi_event_remove_callback(struct ndi_event_hdl *ndi_event_hdl, 1764*0Sstevel@tonic-gate ddi_callback_id_t cb_id) 1765*0Sstevel@tonic-gate { 1766*0Sstevel@tonic-gate ndi_event_callbacks_t *cb = (ndi_event_callbacks_t *)cb_id; 1767*0Sstevel@tonic-gate ASSERT(cb); 1768*0Sstevel@tonic-gate 1769*0Sstevel@tonic-gate ASSERT(mutex_owned(&ndi_event_hdl->ndi_evthdl_mutex)); 1770*0Sstevel@tonic-gate ASSERT(mutex_owned(&ndi_event_hdl->ndi_evthdl_cb_mutex)); 1771*0Sstevel@tonic-gate 1772*0Sstevel@tonic-gate /* remove from callback linked list */ 1773*0Sstevel@tonic-gate if (cb->ndi_evtcb_prev) { 1774*0Sstevel@tonic-gate cb->ndi_evtcb_prev->ndi_evtcb_next = cb->ndi_evtcb_next; 1775*0Sstevel@tonic-gate } 1776*0Sstevel@tonic-gate 1777*0Sstevel@tonic-gate if (cb->ndi_evtcb_next) { 1778*0Sstevel@tonic-gate cb->ndi_evtcb_next->ndi_evtcb_prev = cb->ndi_evtcb_prev; 1779*0Sstevel@tonic-gate } 1780*0Sstevel@tonic-gate 1781*0Sstevel@tonic-gate if (NDI_EVENT(cb->ndi_evtcb_cookie)->callback_list == cb) { 1782*0Sstevel@tonic-gate NDI_EVENT(cb->ndi_evtcb_cookie)->callback_list = 1783*0Sstevel@tonic-gate cb->ndi_evtcb_next; 1784*0Sstevel@tonic-gate } 1785*0Sstevel@tonic-gate 1786*0Sstevel@tonic-gate kmem_free(cb, sizeof (ndi_event_callbacks_t)); 1787*0Sstevel@tonic-gate } 1788*0Sstevel@tonic-gate 1789*0Sstevel@tonic-gate /* 1790*0Sstevel@tonic-gate * ndi_event_run_callbacks() performs event callbacks for the event 1791*0Sstevel@tonic-gate * specified by cookie, if this is among those bound to the 1792*0Sstevel@tonic-gate * supplied handle. 1793*0Sstevel@tonic-gate * If the event is among those bound to the handle, none, 1794*0Sstevel@tonic-gate * some, or all of the handlers registered for the event 1795*0Sstevel@tonic-gate * will be called, according to the delivery attributes of 1796*0Sstevel@tonic-gate * the event. 1797*0Sstevel@tonic-gate * If the event attributes include NDI_EVENT_POST_TO_ALL 1798*0Sstevel@tonic-gate * (the default), all the handlers for the event will be 1799*0Sstevel@tonic-gate * called in an unspecified order. 1800*0Sstevel@tonic-gate * If the event attributes include NDI_EVENT_POST_TO_TGT, only 1801*0Sstevel@tonic-gate * the handlers (if any) registered by the driver identified by 1802*0Sstevel@tonic-gate * rdip will be called. 1803*0Sstevel@tonic-gate * If the event identified by cookie is not bound to the handle, 1804*0Sstevel@tonic-gate * NDI_FAILURE will be returned. 1805*0Sstevel@tonic-gate */ 1806*0Sstevel@tonic-gate int 1807*0Sstevel@tonic-gate ndi_event_run_callbacks(ndi_event_hdl_t handle, dev_info_t *child_dip, 1808*0Sstevel@tonic-gate ddi_eventcookie_t cookie, void *bus_impldata) 1809*0Sstevel@tonic-gate { 1810*0Sstevel@tonic-gate struct ndi_event_hdl *ndi_event_hdl = (struct ndi_event_hdl *)handle; 1811*0Sstevel@tonic-gate ndi_event_callbacks_t *next, *cb; 1812*0Sstevel@tonic-gate int attributes; 1813*0Sstevel@tonic-gate 1814*0Sstevel@tonic-gate mutex_enter(&ndi_event_hdl->ndi_evthdl_mutex); 1815*0Sstevel@tonic-gate 1816*0Sstevel@tonic-gate /* if this is not our event, fail */ 1817*0Sstevel@tonic-gate if (ndi_event_is_defined(handle, cookie, &attributes) != 1818*0Sstevel@tonic-gate NDI_SUCCESS) { 1819*0Sstevel@tonic-gate 1820*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_mutex); 1821*0Sstevel@tonic-gate return (NDI_FAILURE); 1822*0Sstevel@tonic-gate } 1823*0Sstevel@tonic-gate 1824*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_mutex); 1825*0Sstevel@tonic-gate 1826*0Sstevel@tonic-gate #ifdef NDI_EVENT_DEBUG 1827*0Sstevel@tonic-gate if (ndi_event_debug) { 1828*0Sstevel@tonic-gate cmn_err(CE_CONT, "ndi_event_run_callbacks:\n\t" 1829*0Sstevel@tonic-gate "producer dip=%p (%s%d): cookie = %p, name = %s\n", 1830*0Sstevel@tonic-gate (void *)ndi_event_hdl->ndi_evthdl_dip, 1831*0Sstevel@tonic-gate ddi_node_name(ndi_event_hdl->ndi_evthdl_dip), 1832*0Sstevel@tonic-gate ddi_get_instance(ndi_event_hdl->ndi_evthdl_dip), 1833*0Sstevel@tonic-gate (void *)cookie, 1834*0Sstevel@tonic-gate ndi_event_cookie_to_name(handle, cookie)); 1835*0Sstevel@tonic-gate } 1836*0Sstevel@tonic-gate #endif /* #ifdef NDI_EVENT_DEBUG */ 1837*0Sstevel@tonic-gate 1838*0Sstevel@tonic-gate 1839*0Sstevel@tonic-gate /* 1840*0Sstevel@tonic-gate * The callback handlers may call conversion functions. The conversion 1841*0Sstevel@tonic-gate * functions may hold the ndi_evthdl_mutex during execution. Thus, to 1842*0Sstevel@tonic-gate * avoid a recursive mutex problem, only the ndi_evthdl_cb_mutex is 1843*0Sstevel@tonic-gate * held. The ndi_evthdl_mutex is not held when running the callbacks. 1844*0Sstevel@tonic-gate */ 1845*0Sstevel@tonic-gate mutex_enter(&ndi_event_hdl->ndi_evthdl_cb_mutex); 1846*0Sstevel@tonic-gate 1847*0Sstevel@tonic-gate /* perform callbacks */ 1848*0Sstevel@tonic-gate next = NDI_EVENT(cookie)->callback_list; 1849*0Sstevel@tonic-gate while (next != NULL) { 1850*0Sstevel@tonic-gate 1851*0Sstevel@tonic-gate cb = next; 1852*0Sstevel@tonic-gate next = next->ndi_evtcb_next; 1853*0Sstevel@tonic-gate 1854*0Sstevel@tonic-gate ASSERT(cb->ndi_evtcb_cookie == cookie); 1855*0Sstevel@tonic-gate 1856*0Sstevel@tonic-gate if (attributes == NDI_EVENT_POST_TO_TGT && 1857*0Sstevel@tonic-gate child_dip != cb->ndi_evtcb_dip) { 1858*0Sstevel@tonic-gate continue; 1859*0Sstevel@tonic-gate } 1860*0Sstevel@tonic-gate 1861*0Sstevel@tonic-gate cb->ndi_evtcb_callback(cb->ndi_evtcb_dip, cb->ndi_evtcb_cookie, 1862*0Sstevel@tonic-gate cb->ndi_evtcb_arg, bus_impldata); 1863*0Sstevel@tonic-gate 1864*0Sstevel@tonic-gate #ifdef NDI_EVENT_DEBUG 1865*0Sstevel@tonic-gate if (ndi_event_debug) { 1866*0Sstevel@tonic-gate cmn_err(CE_CONT, 1867*0Sstevel@tonic-gate "\t\tconsumer dip=%p (%s%d)\n", 1868*0Sstevel@tonic-gate (void *)cb->ndi_evtcb_dip, 1869*0Sstevel@tonic-gate ddi_node_name(cb->ndi_evtcb_dip), 1870*0Sstevel@tonic-gate ddi_get_instance(cb->ndi_evtcb_dip)); 1871*0Sstevel@tonic-gate } 1872*0Sstevel@tonic-gate #endif 1873*0Sstevel@tonic-gate 1874*0Sstevel@tonic-gate } 1875*0Sstevel@tonic-gate 1876*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_cb_mutex); 1877*0Sstevel@tonic-gate 1878*0Sstevel@tonic-gate #ifdef NDI_EVENT_DEBUG 1879*0Sstevel@tonic-gate if (ndi_event_debug) { 1880*0Sstevel@tonic-gate mutex_enter(&ndi_event_hdl->ndi_evthdl_mutex); 1881*0Sstevel@tonic-gate ndi_event_dump_hdl(ndi_event_hdl, "ndi_event_run_callbacks"); 1882*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_mutex); 1883*0Sstevel@tonic-gate } 1884*0Sstevel@tonic-gate #endif /* NDI_EVENT_DEBUG */ 1885*0Sstevel@tonic-gate 1886*0Sstevel@tonic-gate return (NDI_SUCCESS); 1887*0Sstevel@tonic-gate } 1888*0Sstevel@tonic-gate 1889*0Sstevel@tonic-gate 1890*0Sstevel@tonic-gate /* 1891*0Sstevel@tonic-gate * perform one callback for a specified cookie and just one target 1892*0Sstevel@tonic-gate */ 1893*0Sstevel@tonic-gate int 1894*0Sstevel@tonic-gate ndi_event_do_callback(ndi_event_hdl_t handle, dev_info_t *child_dip, 1895*0Sstevel@tonic-gate ddi_eventcookie_t cookie, void *bus_impldata) 1896*0Sstevel@tonic-gate { 1897*0Sstevel@tonic-gate struct ndi_event_hdl *ndi_event_hdl = (struct ndi_event_hdl *)handle; 1898*0Sstevel@tonic-gate ndi_event_callbacks_t *next, *cb; 1899*0Sstevel@tonic-gate int attributes; 1900*0Sstevel@tonic-gate 1901*0Sstevel@tonic-gate mutex_enter(&ndi_event_hdl->ndi_evthdl_mutex); 1902*0Sstevel@tonic-gate 1903*0Sstevel@tonic-gate /* if this is not our event, fail */ 1904*0Sstevel@tonic-gate if (ndi_event_is_defined(handle, cookie, &attributes) != 1905*0Sstevel@tonic-gate NDI_SUCCESS) { 1906*0Sstevel@tonic-gate 1907*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_mutex); 1908*0Sstevel@tonic-gate 1909*0Sstevel@tonic-gate return (NDI_FAILURE); 1910*0Sstevel@tonic-gate } 1911*0Sstevel@tonic-gate 1912*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_mutex); 1913*0Sstevel@tonic-gate 1914*0Sstevel@tonic-gate #ifdef NDI_EVENT_DEBUG 1915*0Sstevel@tonic-gate if (ndi_event_debug) { 1916*0Sstevel@tonic-gate cmn_err(CE_CONT, "ndi_event_run_callbacks:\n\t" 1917*0Sstevel@tonic-gate "producer dip=%p (%s%d): cookie = %p, name = %s\n", 1918*0Sstevel@tonic-gate (void *)ndi_event_hdl->ndi_evthdl_dip, 1919*0Sstevel@tonic-gate ddi_node_name(ndi_event_hdl->ndi_evthdl_dip), 1920*0Sstevel@tonic-gate ddi_get_instance(ndi_event_hdl->ndi_evthdl_dip), 1921*0Sstevel@tonic-gate (void *)cookie, 1922*0Sstevel@tonic-gate ndi_event_cookie_to_name(handle, cookie)); 1923*0Sstevel@tonic-gate } 1924*0Sstevel@tonic-gate #endif 1925*0Sstevel@tonic-gate 1926*0Sstevel@tonic-gate 1927*0Sstevel@tonic-gate /* 1928*0Sstevel@tonic-gate * we only grab the cb mutex because the callback handlers 1929*0Sstevel@tonic-gate * may call the conversion functions which would cause a recursive 1930*0Sstevel@tonic-gate * mutex problem 1931*0Sstevel@tonic-gate */ 1932*0Sstevel@tonic-gate mutex_enter(&ndi_event_hdl->ndi_evthdl_cb_mutex); 1933*0Sstevel@tonic-gate 1934*0Sstevel@tonic-gate /* perform callbacks */ 1935*0Sstevel@tonic-gate for (next = NDI_EVENT(cookie)->callback_list; next != NULL; ) { 1936*0Sstevel@tonic-gate cb = next; 1937*0Sstevel@tonic-gate next = next->ndi_evtcb_next; 1938*0Sstevel@tonic-gate 1939*0Sstevel@tonic-gate if (cb->ndi_evtcb_dip == child_dip) { 1940*0Sstevel@tonic-gate cb->ndi_evtcb_callback(cb->ndi_evtcb_dip, 1941*0Sstevel@tonic-gate cb->ndi_evtcb_cookie, cb->ndi_evtcb_arg, 1942*0Sstevel@tonic-gate bus_impldata); 1943*0Sstevel@tonic-gate 1944*0Sstevel@tonic-gate #ifdef NDI_EVENT_DEBUG 1945*0Sstevel@tonic-gate if (ndi_event_debug) { 1946*0Sstevel@tonic-gate cmn_err(CE_CONT, 1947*0Sstevel@tonic-gate "\t\tconsumer dip=%p (%s%d)\n", 1948*0Sstevel@tonic-gate (void *)cb->ndi_evtcb_dip, 1949*0Sstevel@tonic-gate ddi_node_name(cb->ndi_evtcb_dip), 1950*0Sstevel@tonic-gate ddi_get_instance(cb->ndi_evtcb_dip)); 1951*0Sstevel@tonic-gate } 1952*0Sstevel@tonic-gate #endif 1953*0Sstevel@tonic-gate break; 1954*0Sstevel@tonic-gate } 1955*0Sstevel@tonic-gate } 1956*0Sstevel@tonic-gate 1957*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_cb_mutex); 1958*0Sstevel@tonic-gate 1959*0Sstevel@tonic-gate #ifdef NDI_EVENT_DEBUG 1960*0Sstevel@tonic-gate if (ndi_event_debug) { 1961*0Sstevel@tonic-gate mutex_enter(&ndi_event_hdl->ndi_evthdl_mutex); 1962*0Sstevel@tonic-gate ndi_event_dump_hdl(ndi_event_hdl, "ndi_event_run_callbacks"); 1963*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_mutex); 1964*0Sstevel@tonic-gate } 1965*0Sstevel@tonic-gate #endif /* NDI_EVENT_DEBUG */ 1966*0Sstevel@tonic-gate 1967*0Sstevel@tonic-gate return (NDI_SUCCESS); 1968*0Sstevel@tonic-gate } 1969*0Sstevel@tonic-gate 1970*0Sstevel@tonic-gate 1971*0Sstevel@tonic-gate /* 1972*0Sstevel@tonic-gate * ndi_event_tag_to_cookie: utility function to find an event cookie 1973*0Sstevel@tonic-gate * given an event tag 1974*0Sstevel@tonic-gate */ 1975*0Sstevel@tonic-gate ddi_eventcookie_t 1976*0Sstevel@tonic-gate ndi_event_tag_to_cookie(ndi_event_hdl_t handle, int event_tag) 1977*0Sstevel@tonic-gate { 1978*0Sstevel@tonic-gate struct ndi_event_hdl *ndi_event_hdl = (struct ndi_event_hdl *)handle; 1979*0Sstevel@tonic-gate ndi_event_cookie_t *list; 1980*0Sstevel@tonic-gate 1981*0Sstevel@tonic-gate mutex_enter(&ndi_event_hdl->ndi_evthdl_mutex); 1982*0Sstevel@tonic-gate 1983*0Sstevel@tonic-gate list = ndi_event_hdl->ndi_evthdl_cookie_list; 1984*0Sstevel@tonic-gate while (list != NULL) { 1985*0Sstevel@tonic-gate if (NDI_EVENT_TAG(list) == event_tag) { 1986*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_mutex); 1987*0Sstevel@tonic-gate return ((ddi_eventcookie_t)list); 1988*0Sstevel@tonic-gate } 1989*0Sstevel@tonic-gate 1990*0Sstevel@tonic-gate list = list->next_cookie; 1991*0Sstevel@tonic-gate } 1992*0Sstevel@tonic-gate 1993*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_mutex); 1994*0Sstevel@tonic-gate return (NULL); 1995*0Sstevel@tonic-gate } 1996*0Sstevel@tonic-gate 1997*0Sstevel@tonic-gate /* 1998*0Sstevel@tonic-gate * ndi_event_cookie_to_tag: utility function to find a event tag 1999*0Sstevel@tonic-gate * given an event_cookie 2000*0Sstevel@tonic-gate */ 2001*0Sstevel@tonic-gate int 2002*0Sstevel@tonic-gate ndi_event_cookie_to_tag(ndi_event_hdl_t handle, ddi_eventcookie_t cookie) 2003*0Sstevel@tonic-gate { 2004*0Sstevel@tonic-gate struct ndi_event_hdl *ndi_event_hdl = (struct ndi_event_hdl *)handle; 2005*0Sstevel@tonic-gate ndi_event_cookie_t *list; 2006*0Sstevel@tonic-gate 2007*0Sstevel@tonic-gate mutex_enter(&ndi_event_hdl->ndi_evthdl_mutex); 2008*0Sstevel@tonic-gate 2009*0Sstevel@tonic-gate list = ndi_event_hdl->ndi_evthdl_cookie_list; 2010*0Sstevel@tonic-gate 2011*0Sstevel@tonic-gate while (list != NULL) { 2012*0Sstevel@tonic-gate if ((ddi_eventcookie_t)list == cookie) { 2013*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_mutex); 2014*0Sstevel@tonic-gate return (NDI_EVENT_TAG(list)); 2015*0Sstevel@tonic-gate } 2016*0Sstevel@tonic-gate 2017*0Sstevel@tonic-gate list = list->next_cookie; 2018*0Sstevel@tonic-gate } 2019*0Sstevel@tonic-gate 2020*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_mutex); 2021*0Sstevel@tonic-gate return (NDI_FAILURE); 2022*0Sstevel@tonic-gate 2023*0Sstevel@tonic-gate } 2024*0Sstevel@tonic-gate 2025*0Sstevel@tonic-gate /* 2026*0Sstevel@tonic-gate * ndi_event_cookie_to_name: utility function to find an event name 2027*0Sstevel@tonic-gate * given an event_cookie 2028*0Sstevel@tonic-gate */ 2029*0Sstevel@tonic-gate char * 2030*0Sstevel@tonic-gate ndi_event_cookie_to_name(ndi_event_hdl_t handle, ddi_eventcookie_t cookie) 2031*0Sstevel@tonic-gate { 2032*0Sstevel@tonic-gate struct ndi_event_hdl *ndi_event_hdl = (struct ndi_event_hdl *)handle; 2033*0Sstevel@tonic-gate ndi_event_cookie_t *list; 2034*0Sstevel@tonic-gate 2035*0Sstevel@tonic-gate mutex_enter(&ndi_event_hdl->ndi_evthdl_mutex); 2036*0Sstevel@tonic-gate 2037*0Sstevel@tonic-gate list = ndi_event_hdl->ndi_evthdl_cookie_list; 2038*0Sstevel@tonic-gate 2039*0Sstevel@tonic-gate while (list != NULL) { 2040*0Sstevel@tonic-gate if (list == NDI_EVENT(cookie)) { 2041*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_mutex); 2042*0Sstevel@tonic-gate return (NDI_EVENT_NAME(list)); 2043*0Sstevel@tonic-gate } 2044*0Sstevel@tonic-gate 2045*0Sstevel@tonic-gate list = list->next_cookie; 2046*0Sstevel@tonic-gate } 2047*0Sstevel@tonic-gate 2048*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_mutex); 2049*0Sstevel@tonic-gate return (NULL); 2050*0Sstevel@tonic-gate } 2051*0Sstevel@tonic-gate 2052*0Sstevel@tonic-gate /* 2053*0Sstevel@tonic-gate * ndi_event_tag_to_name: utility function to find an event name 2054*0Sstevel@tonic-gate * given an event tag 2055*0Sstevel@tonic-gate */ 2056*0Sstevel@tonic-gate char * 2057*0Sstevel@tonic-gate ndi_event_tag_to_name(ndi_event_hdl_t handle, int event_tag) 2058*0Sstevel@tonic-gate { 2059*0Sstevel@tonic-gate struct ndi_event_hdl *ndi_event_hdl = (struct ndi_event_hdl *)handle; 2060*0Sstevel@tonic-gate ndi_event_cookie_t *list; 2061*0Sstevel@tonic-gate 2062*0Sstevel@tonic-gate mutex_enter(&ndi_event_hdl->ndi_evthdl_mutex); 2063*0Sstevel@tonic-gate 2064*0Sstevel@tonic-gate list = ndi_event_hdl->ndi_evthdl_cookie_list; 2065*0Sstevel@tonic-gate 2066*0Sstevel@tonic-gate while (list) { 2067*0Sstevel@tonic-gate if (NDI_EVENT_TAG(list) == event_tag) { 2068*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_mutex); 2069*0Sstevel@tonic-gate return (NDI_EVENT_NAME(list)); 2070*0Sstevel@tonic-gate } 2071*0Sstevel@tonic-gate 2072*0Sstevel@tonic-gate list = list->next_cookie; 2073*0Sstevel@tonic-gate } 2074*0Sstevel@tonic-gate 2075*0Sstevel@tonic-gate mutex_exit(&ndi_event_hdl->ndi_evthdl_mutex); 2076*0Sstevel@tonic-gate 2077*0Sstevel@tonic-gate return (NULL); 2078*0Sstevel@tonic-gate } 2079*0Sstevel@tonic-gate 2080*0Sstevel@tonic-gate #ifdef NDI_EVENT_DEBUG 2081*0Sstevel@tonic-gate void 2082*0Sstevel@tonic-gate ndi_event_dump_hdl(struct ndi_event_hdl *hdl, char *location) 2083*0Sstevel@tonic-gate { 2084*0Sstevel@tonic-gate 2085*0Sstevel@tonic-gate 2086*0Sstevel@tonic-gate ndi_event_callbacks_t *next; 2087*0Sstevel@tonic-gate ndi_event_cookie_t *list; 2088*0Sstevel@tonic-gate 2089*0Sstevel@tonic-gate ASSERT(mutex_owned(&hdl->ndi_evthdl_mutex)); 2090*0Sstevel@tonic-gate list = hdl->ndi_evthdl_cookie_list; 2091*0Sstevel@tonic-gate 2092*0Sstevel@tonic-gate cmn_err(CE_CONT, "%s: event handle (%p): dip = %p (%s%d)\n", 2093*0Sstevel@tonic-gate location, (void *)hdl, 2094*0Sstevel@tonic-gate (void *)hdl->ndi_evthdl_dip, 2095*0Sstevel@tonic-gate ddi_node_name(hdl->ndi_evthdl_dip), 2096*0Sstevel@tonic-gate ddi_get_instance(hdl->ndi_evthdl_dip)); 2097*0Sstevel@tonic-gate cmn_err(CE_CONT, "\thigh=%d other=%d n=%d\n", 2098*0Sstevel@tonic-gate hdl->ndi_evthdl_high_plevels, 2099*0Sstevel@tonic-gate hdl->ndi_evthdl_other_plevels, 2100*0Sstevel@tonic-gate hdl->ndi_evthdl_n_events); 2101*0Sstevel@tonic-gate 2102*0Sstevel@tonic-gate 2103*0Sstevel@tonic-gate cmn_err(CE_CONT, "\tevent cookies:\n"); 2104*0Sstevel@tonic-gate while (list) { 2105*0Sstevel@tonic-gate cmn_err(CE_CONT, 2106*0Sstevel@tonic-gate "\t\ttag=%d name=%s p=%d a=%x dd=%p\n", 2107*0Sstevel@tonic-gate NDI_EVENT_TAG(list), 2108*0Sstevel@tonic-gate NDI_EVENT_NAME(list), 2109*0Sstevel@tonic-gate NDI_EVENT_PLEVEL(list), 2110*0Sstevel@tonic-gate NDI_EVENT_ATTRIBUTES(list), 2111*0Sstevel@tonic-gate (void *)NDI_EVENT_DDIP(list)); 2112*0Sstevel@tonic-gate cmn_err(CE_CONT, "\t\tcallbacks:\n"); 2113*0Sstevel@tonic-gate for (next = list->callback_list; next != NULL; 2114*0Sstevel@tonic-gate next = next->ndi_evtcb_next) { 2115*0Sstevel@tonic-gate cmn_err(CE_CONT, 2116*0Sstevel@tonic-gate "\t\t dip=%p (%s%d) cookie=%p arg=%p\n", 2117*0Sstevel@tonic-gate (void*)next->ndi_evtcb_dip, 2118*0Sstevel@tonic-gate ddi_driver_name(next->ndi_evtcb_dip), 2119*0Sstevel@tonic-gate ddi_get_instance(next->ndi_evtcb_dip), 2120*0Sstevel@tonic-gate (void *)next->ndi_evtcb_cookie, 2121*0Sstevel@tonic-gate next->ndi_evtcb_arg); 2122*0Sstevel@tonic-gate } 2123*0Sstevel@tonic-gate 2124*0Sstevel@tonic-gate list = list->next_cookie; 2125*0Sstevel@tonic-gate } 2126*0Sstevel@tonic-gate 2127*0Sstevel@tonic-gate cmn_err(CE_CONT, "\n"); 2128*0Sstevel@tonic-gate } 2129*0Sstevel@tonic-gate #endif 2130*0Sstevel@tonic-gate 2131*0Sstevel@tonic-gate int 2132*0Sstevel@tonic-gate ndi_dev_is_prom_node(dev_info_t *dip) 2133*0Sstevel@tonic-gate { 2134*0Sstevel@tonic-gate return (DEVI(dip)->devi_node_class == DDI_NC_PROM); 2135*0Sstevel@tonic-gate } 2136*0Sstevel@tonic-gate 2137*0Sstevel@tonic-gate int 2138*0Sstevel@tonic-gate ndi_dev_is_pseudo_node(dev_info_t *dip) 2139*0Sstevel@tonic-gate { 2140*0Sstevel@tonic-gate /* 2141*0Sstevel@tonic-gate * NOTE: this does NOT mean the pseudo branch of the device tree, 2142*0Sstevel@tonic-gate * it means the node was created by software (DEVI_SID_NODEID | 2143*0Sstevel@tonic-gate * DEVI_PSEUDO_NODEID) instead of being generated from a PROM node. 2144*0Sstevel@tonic-gate */ 2145*0Sstevel@tonic-gate return (DEVI(dip)->devi_node_class == DDI_NC_PSEUDO); 2146*0Sstevel@tonic-gate } 2147*0Sstevel@tonic-gate 2148*0Sstevel@tonic-gate int 2149*0Sstevel@tonic-gate ndi_dev_is_persistent_node(dev_info_t *dip) 2150*0Sstevel@tonic-gate { 2151*0Sstevel@tonic-gate return ((DEVI(dip)->devi_node_attributes & DDI_PERSISTENT) != 0); 2152*0Sstevel@tonic-gate } 2153*0Sstevel@tonic-gate 2154*0Sstevel@tonic-gate int 2155*0Sstevel@tonic-gate i_ndi_dev_is_auto_assigned_node(dev_info_t *dip) 2156*0Sstevel@tonic-gate { 2157*0Sstevel@tonic-gate return ((DEVI(dip)->devi_node_attributes & 2158*0Sstevel@tonic-gate DDI_AUTO_ASSIGNED_NODEID) != 0); 2159*0Sstevel@tonic-gate } 2160*0Sstevel@tonic-gate 2161*0Sstevel@tonic-gate void 2162*0Sstevel@tonic-gate i_ndi_set_node_class(dev_info_t *dip, ddi_node_class_t c) 2163*0Sstevel@tonic-gate { 2164*0Sstevel@tonic-gate DEVI(dip)->devi_node_class = c; 2165*0Sstevel@tonic-gate } 2166*0Sstevel@tonic-gate 2167*0Sstevel@tonic-gate ddi_node_class_t 2168*0Sstevel@tonic-gate i_ndi_get_node_class(dev_info_t *dip) 2169*0Sstevel@tonic-gate { 2170*0Sstevel@tonic-gate return (DEVI(dip)->devi_node_class); 2171*0Sstevel@tonic-gate } 2172*0Sstevel@tonic-gate 2173*0Sstevel@tonic-gate void 2174*0Sstevel@tonic-gate i_ndi_set_node_attributes(dev_info_t *dip, int p) 2175*0Sstevel@tonic-gate { 2176*0Sstevel@tonic-gate DEVI(dip)->devi_node_attributes = p; 2177*0Sstevel@tonic-gate } 2178*0Sstevel@tonic-gate 2179*0Sstevel@tonic-gate int 2180*0Sstevel@tonic-gate i_ndi_get_node_attributes(dev_info_t *dip) 2181*0Sstevel@tonic-gate { 2182*0Sstevel@tonic-gate return (DEVI(dip)->devi_node_attributes); 2183*0Sstevel@tonic-gate } 2184*0Sstevel@tonic-gate 2185*0Sstevel@tonic-gate void 2186*0Sstevel@tonic-gate i_ndi_set_nodeid(dev_info_t *dip, int n) 2187*0Sstevel@tonic-gate { 2188*0Sstevel@tonic-gate DEVI(dip)->devi_nodeid = n; 2189*0Sstevel@tonic-gate } 2190*0Sstevel@tonic-gate 2191*0Sstevel@tonic-gate void 2192*0Sstevel@tonic-gate ndi_set_acc_fault(ddi_acc_handle_t ah) 2193*0Sstevel@tonic-gate { 2194*0Sstevel@tonic-gate i_ddi_acc_set_fault(ah); 2195*0Sstevel@tonic-gate } 2196*0Sstevel@tonic-gate 2197*0Sstevel@tonic-gate void 2198*0Sstevel@tonic-gate ndi_clr_acc_fault(ddi_acc_handle_t ah) 2199*0Sstevel@tonic-gate { 2200*0Sstevel@tonic-gate i_ddi_acc_clr_fault(ah); 2201*0Sstevel@tonic-gate } 2202*0Sstevel@tonic-gate 2203*0Sstevel@tonic-gate void 2204*0Sstevel@tonic-gate ndi_set_dma_fault(ddi_dma_handle_t dh) 2205*0Sstevel@tonic-gate { 2206*0Sstevel@tonic-gate i_ddi_dma_set_fault(dh); 2207*0Sstevel@tonic-gate } 2208*0Sstevel@tonic-gate 2209*0Sstevel@tonic-gate void 2210*0Sstevel@tonic-gate ndi_clr_dma_fault(ddi_dma_handle_t dh) 2211*0Sstevel@tonic-gate { 2212*0Sstevel@tonic-gate i_ddi_dma_clr_fault(dh); 2213*0Sstevel@tonic-gate } 2214*0Sstevel@tonic-gate 2215*0Sstevel@tonic-gate /* 2216*0Sstevel@tonic-gate * The default fault-handler, called when the event posted by 2217*0Sstevel@tonic-gate * ddi_dev_report_fault() reaches rootnex. 2218*0Sstevel@tonic-gate */ 2219*0Sstevel@tonic-gate static void 2220*0Sstevel@tonic-gate i_ddi_fault_handler(dev_info_t *dip, struct ddi_fault_event_data *fedp) 2221*0Sstevel@tonic-gate { 2222*0Sstevel@tonic-gate ASSERT(fedp); 2223*0Sstevel@tonic-gate 2224*0Sstevel@tonic-gate mutex_enter(&(DEVI(dip)->devi_lock)); 2225*0Sstevel@tonic-gate if (!DEVI_IS_DEVICE_OFFLINE(dip)) { 2226*0Sstevel@tonic-gate switch (fedp->f_impact) { 2227*0Sstevel@tonic-gate case DDI_SERVICE_LOST: 2228*0Sstevel@tonic-gate DEVI_SET_DEVICE_DOWN(dip); 2229*0Sstevel@tonic-gate break; 2230*0Sstevel@tonic-gate 2231*0Sstevel@tonic-gate case DDI_SERVICE_DEGRADED: 2232*0Sstevel@tonic-gate DEVI_SET_DEVICE_DEGRADED(dip); 2233*0Sstevel@tonic-gate break; 2234*0Sstevel@tonic-gate 2235*0Sstevel@tonic-gate case DDI_SERVICE_UNAFFECTED: 2236*0Sstevel@tonic-gate default: 2237*0Sstevel@tonic-gate break; 2238*0Sstevel@tonic-gate 2239*0Sstevel@tonic-gate case DDI_SERVICE_RESTORED: 2240*0Sstevel@tonic-gate DEVI_SET_DEVICE_UP(dip); 2241*0Sstevel@tonic-gate break; 2242*0Sstevel@tonic-gate } 2243*0Sstevel@tonic-gate } 2244*0Sstevel@tonic-gate mutex_exit(&(DEVI(dip)->devi_lock)); 2245*0Sstevel@tonic-gate } 2246*0Sstevel@tonic-gate 2247*0Sstevel@tonic-gate /* 2248*0Sstevel@tonic-gate * The default fault-logger, called when the event posted by 2249*0Sstevel@tonic-gate * ddi_dev_report_fault() reaches rootnex. 2250*0Sstevel@tonic-gate */ 2251*0Sstevel@tonic-gate /*ARGSUSED*/ 2252*0Sstevel@tonic-gate static void 2253*0Sstevel@tonic-gate i_ddi_fault_logger(dev_info_t *rdip, struct ddi_fault_event_data *fedp) 2254*0Sstevel@tonic-gate { 2255*0Sstevel@tonic-gate ddi_devstate_t newstate; 2256*0Sstevel@tonic-gate const char *action; 2257*0Sstevel@tonic-gate const char *servstate; 2258*0Sstevel@tonic-gate const char *location; 2259*0Sstevel@tonic-gate int bad; 2260*0Sstevel@tonic-gate int changed; 2261*0Sstevel@tonic-gate int level; 2262*0Sstevel@tonic-gate int still; 2263*0Sstevel@tonic-gate 2264*0Sstevel@tonic-gate ASSERT(fedp); 2265*0Sstevel@tonic-gate 2266*0Sstevel@tonic-gate bad = 0; 2267*0Sstevel@tonic-gate switch (fedp->f_location) { 2268*0Sstevel@tonic-gate case DDI_DATAPATH_FAULT: 2269*0Sstevel@tonic-gate location = "in datapath to"; 2270*0Sstevel@tonic-gate break; 2271*0Sstevel@tonic-gate case DDI_DEVICE_FAULT: 2272*0Sstevel@tonic-gate location = "in"; 2273*0Sstevel@tonic-gate break; 2274*0Sstevel@tonic-gate case DDI_EXTERNAL_FAULT: 2275*0Sstevel@tonic-gate location = "external to"; 2276*0Sstevel@tonic-gate break; 2277*0Sstevel@tonic-gate default: 2278*0Sstevel@tonic-gate location = "somewhere near"; 2279*0Sstevel@tonic-gate bad = 1; 2280*0Sstevel@tonic-gate break; 2281*0Sstevel@tonic-gate } 2282*0Sstevel@tonic-gate 2283*0Sstevel@tonic-gate newstate = ddi_get_devstate(fedp->f_dip); 2284*0Sstevel@tonic-gate switch (newstate) { 2285*0Sstevel@tonic-gate case DDI_DEVSTATE_OFFLINE: 2286*0Sstevel@tonic-gate servstate = "unavailable"; 2287*0Sstevel@tonic-gate break; 2288*0Sstevel@tonic-gate case DDI_DEVSTATE_DOWN: 2289*0Sstevel@tonic-gate servstate = "unavailable"; 2290*0Sstevel@tonic-gate break; 2291*0Sstevel@tonic-gate case DDI_DEVSTATE_QUIESCED: 2292*0Sstevel@tonic-gate servstate = "suspended"; 2293*0Sstevel@tonic-gate break; 2294*0Sstevel@tonic-gate case DDI_DEVSTATE_DEGRADED: 2295*0Sstevel@tonic-gate servstate = "degraded"; 2296*0Sstevel@tonic-gate break; 2297*0Sstevel@tonic-gate default: 2298*0Sstevel@tonic-gate servstate = "available"; 2299*0Sstevel@tonic-gate break; 2300*0Sstevel@tonic-gate } 2301*0Sstevel@tonic-gate 2302*0Sstevel@tonic-gate changed = (newstate != fedp->f_oldstate); 2303*0Sstevel@tonic-gate level = (newstate < fedp->f_oldstate) ? CE_WARN : CE_NOTE; 2304*0Sstevel@tonic-gate switch (fedp->f_impact) { 2305*0Sstevel@tonic-gate case DDI_SERVICE_LOST: 2306*0Sstevel@tonic-gate case DDI_SERVICE_DEGRADED: 2307*0Sstevel@tonic-gate case DDI_SERVICE_UNAFFECTED: 2308*0Sstevel@tonic-gate /* fault detected; service [still] <servstate> */ 2309*0Sstevel@tonic-gate action = "fault detected"; 2310*0Sstevel@tonic-gate still = !changed; 2311*0Sstevel@tonic-gate break; 2312*0Sstevel@tonic-gate 2313*0Sstevel@tonic-gate case DDI_SERVICE_RESTORED: 2314*0Sstevel@tonic-gate if (newstate != DDI_DEVSTATE_UP) { 2315*0Sstevel@tonic-gate /* fault cleared; service still <servstate> */ 2316*0Sstevel@tonic-gate action = "fault cleared"; 2317*0Sstevel@tonic-gate still = 1; 2318*0Sstevel@tonic-gate } else if (changed) { 2319*0Sstevel@tonic-gate /* fault cleared; service <servstate> */ 2320*0Sstevel@tonic-gate action = "fault cleared"; 2321*0Sstevel@tonic-gate still = 0; 2322*0Sstevel@tonic-gate } else { 2323*0Sstevel@tonic-gate /* no fault; service <servstate> */ 2324*0Sstevel@tonic-gate action = "no fault"; 2325*0Sstevel@tonic-gate still = 0; 2326*0Sstevel@tonic-gate } 2327*0Sstevel@tonic-gate break; 2328*0Sstevel@tonic-gate 2329*0Sstevel@tonic-gate default: 2330*0Sstevel@tonic-gate bad = 1; 2331*0Sstevel@tonic-gate break; 2332*0Sstevel@tonic-gate } 2333*0Sstevel@tonic-gate 2334*0Sstevel@tonic-gate cmn_err(level, "!%s%d: %s %s device; service %s%s"+(bad|changed), 2335*0Sstevel@tonic-gate ddi_driver_name(fedp->f_dip), 2336*0Sstevel@tonic-gate ddi_get_instance(fedp->f_dip), 2337*0Sstevel@tonic-gate bad ? "invalid report of fault" : action, 2338*0Sstevel@tonic-gate location, still ? "still " : "", servstate); 2339*0Sstevel@tonic-gate 2340*0Sstevel@tonic-gate cmn_err(level, "!%s%d: %s"+(bad|changed), 2341*0Sstevel@tonic-gate ddi_driver_name(fedp->f_dip), 2342*0Sstevel@tonic-gate ddi_get_instance(fedp->f_dip), 2343*0Sstevel@tonic-gate fedp->f_message); 2344*0Sstevel@tonic-gate } 2345*0Sstevel@tonic-gate 2346*0Sstevel@tonic-gate /* 2347*0Sstevel@tonic-gate * Platform-settable pointers to fault handler and logger functions. 2348*0Sstevel@tonic-gate * These are called by the default rootnex event-posting code when 2349*0Sstevel@tonic-gate * a fault event reaches rootnex. 2350*0Sstevel@tonic-gate */ 2351*0Sstevel@tonic-gate void (*plat_fault_handler)(dev_info_t *, struct ddi_fault_event_data *) = 2352*0Sstevel@tonic-gate i_ddi_fault_handler; 2353*0Sstevel@tonic-gate void (*plat_fault_logger)(dev_info_t *, struct ddi_fault_event_data *) = 2354*0Sstevel@tonic-gate i_ddi_fault_logger; 2355*0Sstevel@tonic-gate 2356*0Sstevel@tonic-gate /* 2357*0Sstevel@tonic-gate * Rootnex event definitions ... 2358*0Sstevel@tonic-gate */ 2359*0Sstevel@tonic-gate enum rootnex_event_tags { 2360*0Sstevel@tonic-gate ROOTNEX_FAULT_EVENT 2361*0Sstevel@tonic-gate }; 2362*0Sstevel@tonic-gate static ndi_event_hdl_t rootnex_event_hdl; 2363*0Sstevel@tonic-gate static ndi_event_definition_t rootnex_event_set[] = { 2364*0Sstevel@tonic-gate { 2365*0Sstevel@tonic-gate ROOTNEX_FAULT_EVENT, 2366*0Sstevel@tonic-gate DDI_DEVI_FAULT_EVENT, 2367*0Sstevel@tonic-gate EPL_INTERRUPT, 2368*0Sstevel@tonic-gate NDI_EVENT_POST_TO_ALL 2369*0Sstevel@tonic-gate } 2370*0Sstevel@tonic-gate }; 2371*0Sstevel@tonic-gate static ndi_event_set_t rootnex_events = { 2372*0Sstevel@tonic-gate NDI_EVENTS_REV1, 2373*0Sstevel@tonic-gate sizeof (rootnex_event_set) / sizeof (rootnex_event_set[0]), 2374*0Sstevel@tonic-gate rootnex_event_set 2375*0Sstevel@tonic-gate }; 2376*0Sstevel@tonic-gate 2377*0Sstevel@tonic-gate /* 2378*0Sstevel@tonic-gate * Initialize rootnex event handle 2379*0Sstevel@tonic-gate */ 2380*0Sstevel@tonic-gate void 2381*0Sstevel@tonic-gate i_ddi_rootnex_init_events(dev_info_t *dip) 2382*0Sstevel@tonic-gate { 2383*0Sstevel@tonic-gate if (ndi_event_alloc_hdl(dip, (ddi_iblock_cookie_t)(LOCK_LEVEL-1), 2384*0Sstevel@tonic-gate &rootnex_event_hdl, NDI_SLEEP) == NDI_SUCCESS) { 2385*0Sstevel@tonic-gate if (ndi_event_bind_set(rootnex_event_hdl, 2386*0Sstevel@tonic-gate &rootnex_events, NDI_SLEEP) != NDI_SUCCESS) { 2387*0Sstevel@tonic-gate (void) ndi_event_free_hdl(rootnex_event_hdl); 2388*0Sstevel@tonic-gate rootnex_event_hdl = NULL; 2389*0Sstevel@tonic-gate } 2390*0Sstevel@tonic-gate } 2391*0Sstevel@tonic-gate } 2392*0Sstevel@tonic-gate 2393*0Sstevel@tonic-gate /* 2394*0Sstevel@tonic-gate * Event-handling functions for rootnex 2395*0Sstevel@tonic-gate * These provide the standard implementation of fault handling 2396*0Sstevel@tonic-gate */ 2397*0Sstevel@tonic-gate /*ARGSUSED*/ 2398*0Sstevel@tonic-gate int 2399*0Sstevel@tonic-gate i_ddi_rootnex_get_eventcookie(dev_info_t *dip, dev_info_t *rdip, 2400*0Sstevel@tonic-gate char *eventname, ddi_eventcookie_t *cookiep) 2401*0Sstevel@tonic-gate { 2402*0Sstevel@tonic-gate if (rootnex_event_hdl == NULL) 2403*0Sstevel@tonic-gate return (NDI_FAILURE); 2404*0Sstevel@tonic-gate return (ndi_event_retrieve_cookie(rootnex_event_hdl, rdip, eventname, 2405*0Sstevel@tonic-gate cookiep, NDI_EVENT_NOPASS)); 2406*0Sstevel@tonic-gate } 2407*0Sstevel@tonic-gate 2408*0Sstevel@tonic-gate /*ARGSUSED*/ 2409*0Sstevel@tonic-gate int 2410*0Sstevel@tonic-gate i_ddi_rootnex_add_eventcall(dev_info_t *dip, dev_info_t *rdip, 2411*0Sstevel@tonic-gate ddi_eventcookie_t eventid, void (*handler)(dev_info_t *dip, 2412*0Sstevel@tonic-gate ddi_eventcookie_t event, void *arg, void *impl_data), void *arg, 2413*0Sstevel@tonic-gate ddi_callback_id_t *cb_id) 2414*0Sstevel@tonic-gate { 2415*0Sstevel@tonic-gate if (rootnex_event_hdl == NULL) 2416*0Sstevel@tonic-gate return (NDI_FAILURE); 2417*0Sstevel@tonic-gate return (ndi_event_add_callback(rootnex_event_hdl, rdip, 2418*0Sstevel@tonic-gate eventid, handler, arg, NDI_SLEEP, cb_id)); 2419*0Sstevel@tonic-gate } 2420*0Sstevel@tonic-gate 2421*0Sstevel@tonic-gate /*ARGSUSED*/ 2422*0Sstevel@tonic-gate int 2423*0Sstevel@tonic-gate i_ddi_rootnex_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id) 2424*0Sstevel@tonic-gate { 2425*0Sstevel@tonic-gate if (rootnex_event_hdl == NULL) 2426*0Sstevel@tonic-gate return (NDI_FAILURE); 2427*0Sstevel@tonic-gate 2428*0Sstevel@tonic-gate return (ndi_event_remove_callback(rootnex_event_hdl, cb_id)); 2429*0Sstevel@tonic-gate } 2430*0Sstevel@tonic-gate 2431*0Sstevel@tonic-gate /*ARGSUSED*/ 2432*0Sstevel@tonic-gate int 2433*0Sstevel@tonic-gate i_ddi_rootnex_post_event(dev_info_t *dip, dev_info_t *rdip, 2434*0Sstevel@tonic-gate ddi_eventcookie_t eventid, void *impl_data) 2435*0Sstevel@tonic-gate { 2436*0Sstevel@tonic-gate int tag; 2437*0Sstevel@tonic-gate 2438*0Sstevel@tonic-gate if (rootnex_event_hdl == NULL) 2439*0Sstevel@tonic-gate return (NDI_FAILURE); 2440*0Sstevel@tonic-gate 2441*0Sstevel@tonic-gate tag = ndi_event_cookie_to_tag(rootnex_event_hdl, eventid); 2442*0Sstevel@tonic-gate if (tag == ROOTNEX_FAULT_EVENT) { 2443*0Sstevel@tonic-gate (*plat_fault_handler)(rdip, impl_data); 2444*0Sstevel@tonic-gate (*plat_fault_logger)(rdip, impl_data); 2445*0Sstevel@tonic-gate } 2446*0Sstevel@tonic-gate return (ndi_event_run_callbacks(rootnex_event_hdl, rdip, 2447*0Sstevel@tonic-gate eventid, impl_data)); 2448*0Sstevel@tonic-gate } 2449