root/usr/src/uts/common/sys/ib/clients/of/sol_umad/sol_umad.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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
 */

#ifndef _SYS_IB_CLIENTS_OF_SOL_UMAD_SOL_UMAD_H
#define _SYS_IB_CLIENTS_OF_SOL_UMAD_SOL_UMAD_H

#ifdef __cplusplus
extern "C" {
#endif

/*
 * map between minor node #s and HCA indexes and Port #s. This leaves
 * room for 16 boards with up to 16 ports each.
 */
#define GET_UMAD_MINOR(node, port)   ((node << 4) | port)
#define GET_ISSM_MINOR(node, port)   ((node << 4) | port | 0x8000)
#define GET_NODE(minor) ((minor >> 4) & 0xf)
#define GET_PORT(minor) ((minor) & 0xf)
#define ISSM_MINOR(minor) (minor & 0x8000)
#define GET_UCTX(minor) (minor >> 8)
#define GET_NEW_UCTX_MINOR(minor, uctxnum) ((uctxnum << 8) | minor)

/* UMAD KA instance, only one instance allowed */
#define UMAD_INSTANCE   0

#define MAX_UCTX        16      /* Maximum number of contexts. */

typedef struct umad_port_info_s umad_port_info_t;

/*
 * User context. One per open file descriptor.
 */
typedef struct umad_uctx_s {
        kmutex_t                uctx_lock;      /* protects agent_list */
        umad_port_info_t        *uctx_port;
        struct pollhead         uctx_pollhead;
        llist_head_t            uctx_agent_list; /* list of agents registered */
        kmutex_t                uctx_recv_lock; /* protects recv_list below */
        genlist_t               uctx_recv_list; /* Queue of received MADs */
        kcondvar_t              uctx_recv_cv;   /* wait on for received data */
} umad_uctx_t;

typedef struct umad_agent_s {
        llist_head_t            agent_list;
        struct ib_user_mad_reg_req agent_req;   /* Params given during */
                                                /* registration */
        struct ibmf_reg_info    *agent_reg;     /* IBMF information */
        umad_uctx_t             *agent_uctx;    /* User context to which */
                                                /* this agent belongs. */
        int                     agent_outstanding_msgs; /* # of msgs waiting */
                                                        /* for a response */
        kmutex_t                agent_lock;     /* protects this structure */
        int                     agent_flags;
        kcondvar_t              agent_cv;       /* used to wake up unregister */
} umad_agent_t;

enum umad_agent_flags {
        UMAD_AGENT_UNREGISTERING        = 1 << 0,
        UMAD_HANDLING_ASYNC             = 1 << 1
};

typedef struct umad_hca_info_s {
        ib_guid_t               hca_guid;
        ibt_hca_hdl_t           hca_handle;
        ibt_hca_attr_t          hca_attr;
        uint8_t                 hca_nports;
        umad_port_info_t        *hca_ports;
} umad_hca_info_t;

struct umad_port_info_s {
        kmutex_t                port_lock;
        const umad_hca_info_t   *port_hca;      /* backpointer to hca */
        unsigned int            port_minor_name; /* number in device name. */
        uint8_t                 port_num;
        ib_guid_t               port_guid;
        int                     port_issm_open_cnt;
        ib_lid_t                port_lid;
        bool                    port_has_umad_minor_node;
        bool                    port_has_issm_minor_node;
        llist_head_t            port_ibmf_regs;
};

typedef struct umad_info_s {
        dev_info_t              *info_dip;      /* back pointer to devinfo */
        kmutex_t                info_mutex;     /* protects this device */
        ibt_clnt_hdl_t          info_clnt_hdl;
        uint32_t                info_hca_count;
        ib_guid_t               *info_hca_guids;
        umad_hca_info_t         *info_hcas;     /* hca list */
        umad_uctx_t             *info_uctx[MAX_UCTX];
} umad_info_t;


typedef struct ib_umad_msg_s {
        struct ib_user_mad_hdr  umad_msg_hdr;
        ibmf_msg_t              *umad_msg_ibmf_msg;
} ib_umad_msg_t;

/*
 * A UMAD we send is linked to a user context.
 */
struct umad_send {
        struct umad_agent_s     *send_agent;    /* agent that sent the MAD */
        size_t                  send_len;
        uint8_t                 send_umad[];    /* MAD from userspace */
};

struct ibmf_reg_info {
        ibmf_handle_t   ibmf_reg_handle;
        unsigned int    ibmf_reg_refcnt;
        umad_uctx_t     *ibmf_reg_uctx;
        kmutex_t        ibmf_reg_lock;
        kcondvar_t      ibmf_cv;
        unsigned int    ibmf_flags;
        enum _ibmf_client_type_t        ibmf_class;
};

/* Flags values for ibmf_flags above */
enum ibmf_flag_values {
        UMAD_IBMF_UNREGISTERING = 1 << 0
};

static inline int
is_supported_mad_method(int nr, void *addr)
{
        return (1 & (((uint32_t *)addr)[nr >> 5] >> (nr & 31)));
}

static int umad_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
static int umad_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
static int umad_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
                        void **resultp);
static int umad_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
                        int flags, char *name, caddr_t valuep,
                        int *lengthp);
static int umad_open(dev_t *devp, int flag, int otyp, cred_t *cred);
static int umad_close(dev_t dev, int flag, int otyp, cred_t *cred);
static int umad_read(dev_t dev, struct uio *uiop, cred_t *credp);
static int umad_write(dev_t dev, struct uio *uiop, cred_t *credp);
static int umad_poll(dev_t dev, short events, int anyyet,
                        short *reventsp, struct pollhead **phpp);
static int umad_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
                        cred_t *credp, int *rvalp);

static void umad_async_handler(void *private, ibt_hca_hdl_t hca_hdl,
                        ibt_async_code_t code,
                        ibt_async_event_t *event);
static int umad_register(struct ib_user_mad_reg_req *req,
                                        umad_uctx_t *uctx);
static int umad_unregister(struct ib_user_mad_reg_req *agent,
                                        umad_uctx_t *uctx);
static void umad_unsolicited_cb(ibmf_handle_t ibmf_handle,
                                        ibmf_msg_t *msgp, void *args);
#ifdef __cplusplus
}
#endif

#endif /* _SYS_IB_CLIENTS_OF_SOL_UMAD_SOL_UMAD_H */