root/usr/src/uts/common/sys/sunldi_impl.h
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */
/*
 * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
 */

#ifndef _SYS_SUNLDI_IMPL_H
#define _SYS_SUNLDI_IMPL_H

#ifdef __cplusplus
extern "C" {
#endif

#include <sys/dditypes.h>
#include <sys/vnode.h>

/*
 * NOTE
 *
 * The contents of this file are private to this implementation
 * of Solaris and are subject to change at any time without notice.
 *
 * Applications and drivers using these interfaces will fail
 * to run on future releases.
 */

/*
 * LDI hash definitions
 */
#define LH_HASH_SZ      32
#define LI_HASH_SZ      32

/*
 * Obsolete LDI event interfaces are available for now but are deprecated and a
 * warning will be issued to consumers.
 */
#define LDI_OBSOLETE_EVENT      1

/*
 * Flag for LDI handle's lh_flags field
 */
#define LH_FLAGS_NOTIFY 0x0001          /* invoked in context of a notify */

/*
 * LDI initialization function
 */
void ldi_init(void);

/*
 * LDI streams linking interfaces
 */
extern int ldi_mlink_lh(vnode_t *, int, intptr_t, cred_t *, int *);
extern int ldi_mlink_fp(struct stdata *, struct file *, int, int);
extern int ldi_munlink_fp(struct stdata *, struct file *, int);

/*
 * LDI module identifier
 */
struct ldi_ident {
        /* protected by ldi_ident_hash_lock */
        struct ldi_ident                *li_next;
        uint_t                          li_ref;

        /* unique/static fields in the ident */
        char                            li_modname[MODMAXNAMELEN];
        modid_t                         li_modid;
        major_t                         li_major;
        dev_info_t                      *li_dip;
        dev_t                           li_dev;
};

/*
 * LDI handle
 */
struct ldi_handle {
        /* protected by ldi_handle_hash_lock */
        struct ldi_handle               *lh_next;
        uint_t                          lh_ref;
        uint_t                          lh_flags;

        /* unique/static fields in the handle */
        uint_t                          lh_type;
        struct ldi_ident                *lh_ident;
        vnode_t                         *lh_vp;

#ifdef  LDI_OBSOLETE_EVENT
        /* fields protected by lh_lock */
        kmutex_t                        lh_lock[1];
        struct ldi_event                *lh_events;
#endif
};

/*
 * LDI event information
 */
#ifdef  LDI_OBSOLETE_EVENT
typedef struct ldi_event {
        /* fields protected by le_lhp->lh_lock */
        struct ldi_event        *le_next;
        struct ldi_event        *le_prev;

        /* unique/static fields in the handle */
        struct ldi_handle       *le_lhp;
        void                    (*le_handler)();
        void                    *le_arg;
        ddi_callback_id_t       le_id;
} ldi_event_t;
#endif

typedef struct ldi_ev_callback_impl {
        struct ldi_handle       *lec_lhp;
        dev_info_t              *lec_dip;
        dev_t                   lec_dev;
        int                     lec_spec;
        int                     (*lec_notify)();
        void                    (*lec_finalize)();
        void                    *lec_arg;
        void                    *lec_cookie;
        void                    *lec_id;
        list_node_t             lec_list;
} ldi_ev_callback_impl_t;

/*
 * Members of "struct ldi_ev_callback_list" are protected by their le_lock
 * member.  The struct is currently only used once, as a file-level global,
 * and the locking protocol is currently implemented in ldi_ev_lock() and
 * ldi_ev_unlock().
 *
 * When delivering events to subscribers, ldi_invoke_notify() and
 * ldi_invoke_finalize() will walk the list of callbacks: le_head.  It is
 * possible that an invoked callback function will need to unregister an
 * arbitrary number of callbacks from this list.
 *
 * To enable ldi_ev_remove_callbacks() to remove elements from the list
 * without breaking the walk-in-progress, we store the next element in the
 * walk direction on the struct as le_walker_next and le_walker_prev.
 */
struct ldi_ev_callback_list {
        kmutex_t                le_lock;
        kcondvar_t              le_cv;
        int                     le_busy;
        void                    *le_thread;
        list_t                  le_head;
        ldi_ev_callback_impl_t  *le_walker_next;
        ldi_ev_callback_impl_t  *le_walker_prev;
};

int ldi_invoke_notify(dev_info_t *dip, dev_t dev, int spec_type, char *event,
    void *ev_data);
void ldi_invoke_finalize(dev_info_t *dip, dev_t dev, int spec_type, char *event,
    int ldi_result, void *ev_data);
int e_ddi_offline_notify(dev_info_t *dip);
void e_ddi_offline_finalize(dev_info_t *dip, int result);


/*
 * LDI device usage interfaces
 *
 * ldi_usage_count(), ldi_usage_walker(), and ldi_usage_t
 *
 * These functions are used by the devinfo driver and fuser to get a
 * device usage information from the LDI. These functions along with
 * the ldi_usage_t data structure allow these other subsystems to have
 * no knowledge of how the LDI stores it's internal state.
 *
 * ldi_usage_count() provides an count of how many kernel
 *      device clients currently exist.
 *
 * ldi_usage_walker() reports all kernel device usage information.
 */
#define LDI_USAGE_CONTINUE      0
#define LDI_USAGE_TERMINATE     1

typedef struct ldi_usage {
        /*
         * information about the kernel subsystem that is accessing
         * the target device
         */
        modid_t         src_modid;
        char            *src_name;
        dev_info_t      *src_dip;
        dev_t           src_devt;

        /*
         * information about the target device that is open
         */
        modid_t         tgt_modid;
        char            *tgt_name;
        dev_info_t      *tgt_dip;
        dev_t           tgt_devt;
        int             tgt_spec_type;
} ldi_usage_t;

int ldi_usage_count();
void ldi_usage_walker(void *arg,
    int (*callback)(const ldi_usage_t *ldi_usage, void *arg));

#ifdef __cplusplus
}
#endif

#endif  /* _SYS_SUNLDI_IMPL_H */