1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 /*
  26  * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
  27  */
  28 
  29 #ifndef _SYS_SUNLDI_IMPL_H
  30 #define _SYS_SUNLDI_IMPL_H
  31 
  32 #ifdef __cplusplus
  33 extern "C" {
  34 #endif
  35 
  36 #include <sys/dditypes.h>
  37 #include <sys/vnode.h>
  38 
  39 /*
  40  * NOTE
  41  *
  42  * The contents of this file are private to this implementation
  43  * of Solaris and are subject to change at any time without notice.
  44  *
  45  * Applications and drivers using these interfaces will fail
  46  * to run on future releases.
  47  */
  48 
  49 /*
  50  * LDI hash definitions
  51  */
  52 #define LH_HASH_SZ      32
  53 #define LI_HASH_SZ      32
  54 
  55 /*
  56  * Obsolete LDI event interfaces are available for now but are deprecated and a
  57  * warning will be issued to consumers.
  58  */
  59 #define LDI_OBSOLETE_EVENT      1
  60 
  61 /*
  62  * Flag for LDI handle's lh_flags field
  63  */
  64 #define LH_FLAGS_NOTIFY 0x0001          /* invoked in context of a notify */
  65 #define LH_FLAGS_NOTIFY_NOTIFY 0x0002   /* processed once in notify loop */
  66 #define LH_FLAGS_NOTIFY_FINALIZE 0x0004 /* processed once in finalize loop */
  67 
  68 /*
  69  * LDI initialization function
  70  */
  71 void ldi_init(void);
  72 
  73 /*
  74  * LDI streams linking interfaces
  75  */
  76 extern int ldi_mlink_lh(vnode_t *, int, intptr_t, cred_t *, int *);
  77 extern void ldi_mlink_fp(struct stdata *, struct file *, int, int);
  78 extern void ldi_munlink_fp(struct stdata *, struct file *, int);
  79 
  80 /*
  81  * LDI module identifier
  82  */
  83 struct ldi_ident {
  84         /* protected by ldi_ident_hash_lock */
  85         struct ldi_ident                *li_next;
  86         uint_t                          li_ref;
  87 
  88         /* unique/static fields in the ident */
  89         char                            li_modname[MODMAXNAMELEN];
  90         modid_t                         li_modid;
  91         major_t                         li_major;
  92         dev_info_t                      *li_dip;
  93         dev_t                           li_dev;
  94 };
  95 
  96 /*
  97  * LDI handle
  98  */
  99 struct ldi_handle {
 100         /* protected by ldi_handle_hash_lock */
 101         struct ldi_handle               *lh_next;
 102         uint_t                          lh_ref;
 103         uint_t                          lh_flags;
 104 
 105         /* unique/static fields in the handle */
 106         uint_t                          lh_type;
 107         struct ldi_ident                *lh_ident;
 108         vnode_t                         *lh_vp;
 109 
 110 #ifdef  LDI_OBSOLETE_EVENT
 111         /* fields protected by lh_lock */
 112         kmutex_t                        lh_lock[1];
 113         struct ldi_event                *lh_events;
 114 #endif
 115 };
 116 
 117 /*
 118  * LDI event information
 119  */
 120 #ifdef  LDI_OBSOLETE_EVENT
 121 typedef struct ldi_event {
 122         /* fields protected by le_lhp->lh_lock */
 123         struct ldi_event        *le_next;
 124         struct ldi_event        *le_prev;
 125 
 126         /* unique/static fields in the handle */
 127         struct ldi_handle       *le_lhp;
 128         void                    (*le_handler)();
 129         void                    *le_arg;
 130         ddi_callback_id_t       le_id;
 131 } ldi_event_t;
 132 #endif
 133 
 134 typedef struct ldi_ev_callback_impl {
 135         struct ldi_handle       *lec_lhp;
 136         dev_info_t              *lec_dip;
 137         dev_t                   lec_dev;
 138         int                     lec_spec;
 139         int                     (*lec_notify)();
 140         void                    (*lec_finalize)();
 141         void                    *lec_arg;
 142         void                    *lec_cookie;
 143         void                    *lec_id;
 144         list_node_t             lec_list;
 145 } ldi_ev_callback_impl_t;
 146 
 147 /*
 148  * Members of "struct ldi_ev_callback_list" are protected by their le_lock
 149  * member.  The struct is currently only used once, as a file-level global,
 150  * and the locking protocol is currently implemented in ldi_ev_lock() and
 151  * ldi_ev_unlock().
 152  *
 153  * When delivering events to subscribers, ldi_invoke_notify() and
 154  * ldi_invoke_finalize() will walk the list of callbacks: le_head.  It is
 155  * possible that an invoked callback function will need to unregister an
 156  * arbitrary number of callbacks from this list.
 157  *
 158  * To enable ldi_ev_remove_callbacks() to remove elements from the list
 159  * without breaking the walk-in-progress, we store the next element in the
 160  * walk direction on the struct as le_walker_next and le_walker_prev.
 161  */
 162 struct ldi_ev_callback_list {
 163         kmutex_t                le_lock;
 164         kcondvar_t              le_cv;
 165         int                     le_busy;
 166         void                    *le_thread;
 167         list_t                  le_head;
 168         ldi_ev_callback_impl_t  *le_walker_next;
 169         ldi_ev_callback_impl_t  *le_walker_prev;
 170 };
 171 
 172 int ldi_invoke_notify(dev_info_t *dip, dev_t dev, int spec_type, char *event,
 173     void *ev_data);
 174 void ldi_invoke_finalize(dev_info_t *dip, dev_t dev, int spec_type, char *event,
 175     int ldi_result, void *ev_data);
 176 int e_ddi_offline_notify(dev_info_t *dip);
 177 void e_ddi_offline_finalize(dev_info_t *dip, int result);
 178 
 179 
 180 /*
 181  * LDI device usage interfaces
 182  *
 183  * ldi_usage_count(), ldi_usage_walker(), and ldi_usage_t
 184  *
 185  * These functions are used by the devinfo driver and fuser to get a
 186  * device usage information from the LDI. These functions along with
 187  * the ldi_usage_t data structure allow these other subsystems to have
 188  * no knowledge of how the LDI stores it's internal state.
 189  *
 190  * ldi_usage_count() provides an count of how many kernel
 191  *      device clients currently exist.
 192  *
 193  * ldi_usage_walker() reports all kernel device usage information.
 194  */
 195 #define LDI_USAGE_CONTINUE      0
 196 #define LDI_USAGE_TERMINATE     1
 197 
 198 typedef struct ldi_usage {
 199         /*
 200          * information about the kernel subsystem that is accessing
 201          * the target device
 202          */
 203         modid_t         src_modid;
 204         char            *src_name;
 205         dev_info_t      *src_dip;
 206         dev_t           src_devt;
 207 
 208         /*
 209          * information about the target device that is open
 210          */
 211         modid_t         tgt_modid;
 212         char            *tgt_name;
 213         dev_info_t      *tgt_dip;
 214         dev_t           tgt_devt;
 215         int             tgt_spec_type;
 216 } ldi_usage_t;
 217 
 218 int ldi_usage_count();
 219 void ldi_usage_walker(void *arg,
 220     int (*callback)(const ldi_usage_t *ldi_usage, void *arg));
 221 
 222 #ifdef __cplusplus
 223 }
 224 #endif
 225 
 226 #endif  /* _SYS_SUNLDI_IMPL_H */