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 /*
  23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 #ifndef _SYS_IB_CLIENTS_OF_SOL_OFS_SOL_CMA_H
  27 #define _SYS_IB_CLIENTS_OF_SOL_OFS_SOL_CMA_H
  28 
  29 #ifdef __cplusplus
  30 extern "C" {
  31 #endif
  32 
  33 #include <sys/sysmacros.h>
  34 
  35 #include <sys/ib/clients/of/sol_ofs/sol_ofs_common.h>
  36 #include <sys/ib/clients/of/rdma/rdma_cm.h>
  37 #include <sys/ib/clients/of/sol_ofs/sol_ib_cma.h> /* Transport Specific */
  38 
  39 
  40 #define IS_UDP_CMID(idp)        ((idp)->ps == RDMA_PS_UDP || \
  41         (idp)->ps == RDMA_PS_IPOIB)
  42 #define IS_VALID_SOCKADDR(sockaddrp) \
  43         ((sockaddrp)->sa_family == AF_INET || \
  44         (sockaddrp)->sa_family == AF_INET6)
  45 
  46 /*
  47  * Global structure which contains information about all
  48  * CMIDs, which have called rdma_listen().
  49  */
  50 typedef struct sol_cma_glbl_listen_s {
  51         avl_node_t      cma_listen_node;
  52 
  53         uint64_t        cma_listen_chan_sid;
  54         void            *cma_listen_clnt_hdl;
  55         void            *cma_listen_svc_hdl;
  56         genlist_t       cma_listen_chan_list;
  57 } sol_cma_glbl_listen_t;
  58 
  59 /* State of the RDMA-CM ID */
  60 typedef enum {
  61         SOL_CMA_CHAN_IDLE,
  62         SOL_CMA_CHAN_BOUND,
  63         SOL_CMA_CHAN_ADDR_QUERY,
  64         SOL_CMA_CHAN_ADDR_BOUND,
  65         SOL_CMA_CHAN_ADDR_RESLVD,
  66         SOL_CMA_CHAN_ROUTE_QUERY,
  67         SOL_CMA_CHAN_ROUTE_RESLVD,
  68 
  69         SOL_CMA_CHAN_EVENT_NOTIFIED,
  70 
  71         SOL_CMA_CHAN_CONNECT,
  72         SOL_CMA_CHAN_LISTEN,
  73         SOL_CMA_CHAN_DISCONNECT,
  74         SOL_CMA_CHAN_ACCEPT,
  75         SOL_CMA_CHAN_REJECT,
  76 
  77         SOL_CMA_CHAN_DESTROYING,
  78         SOL_CMA_CHAN_DESTROY_PENDING,
  79         SOL_CMA_CHAN_DESTROY_WAIT,
  80 
  81         SOL_CMA_CHAN_HCA_DOWN,
  82         SOL_CMA_CHAN_PORT_DOWN
  83 } cma_chan_state_t;
  84 
  85 typedef struct listen_info_s {
  86         uint8_t                 listen_is_root;
  87 
  88         /* For Root CMIDs, pointer to global listen info */
  89         genlist_entry_t         *listen_entry;
  90         sol_cma_glbl_listen_t   *chan_glbl_listen_info;
  91 
  92         /*
  93          * For EP CMIDs, pointer to ib_device and root CMID
  94          * for HCA DR
  95          */
  96         genlist_entry_t         *listen_ep_dev_entry;
  97         genlist_entry_t         *listen_ep_root_entry;
  98         struct ib_device        *listen_ep_device;
  99 
 100         /*
 101          * Count & list of EPs for this listen_info.
 102          * This is 0, if listen_is_root is 0.
 103          */
 104         uint32_t                listen_eps;
 105         genlist_t               listen_list;
 106 
 107         /* Transport Specific */
 108         union {
 109                 /* For Root CMID */
 110                 ibt_srv_hdl_t   _listen_srv_hdl;
 111 
 112                 /* For Endpoint CMID */
 113                 ibt_sbind_hdl_t _listen_sbind_hdl;
 114         } un_listen;
 115 #define listen_ib_srv_hdl       un_listen._listen_srv_hdl
 116 #define listen_ib_sbind_hdl     un_listen._listen_sbind_hdl
 117 } sol_cma_listen_info_t;
 118 
 119 typedef enum {
 120         SOL_CMA_XPORT_NONE = 0,
 121         SOL_CMA_XPORT_IB,
 122         SOL_CMA_XPORT_IWARP
 123 } sol_cma_xport_type_t;
 124 
 125 /*
 126  * This is used to track the state of a client side CMID.
 127  *      CONNECT_NONE    Server side CMID, or CMID for which
 128  *                      rdma_connect() has not been called.
 129  *
 130  *      CLIENT_NONE     Client side CMID for which connection
 131  *                      has been torn down.
 132  *
 133  *                      For UDP it also represents connection
 134  *                      established (no more IBTF CM events
 135  *                      expected).
 136  *
 137  *      INITIATED       rdma_connect() has been called not yet
 138  *                      established.
 139  *
 140  *      ESTABLISHED     Client CMID has connection established.
 141  */
 142 typedef enum {
 143         SOL_CMA_CONNECT_NONE = 0,
 144         SOL_CMA_CONNECT_CLIENT_NONE,
 145         SOL_CMA_CONNECT_INITIATED,
 146         SOL_CMA_CONNECT_ESTABLISHED,
 147 } sol_cma_connect_flag_t;
 148 
 149 /*
 150  * This is used to track the state of CMIDs created for Connection
 151  * Requests and listening CMID.
 152  *
 153  *      NONE            Client CMID, listen CMID with no REQs yet.
 154  *
 155  *      SERVER_DONE     REQ CMID connection done, no more events.
 156  *
 157  *                      For listening CMID all REQ CMIDs have events
 158  *                      completed.
 159  *
 160  *      CREATED         listening CMID with > 1 REQ CMID with events
 161  *                      pending.
 162  *
 163  *      QUEUED          REQ CMID in REQ AVL tree of listening CMID
 164  *
 165  *      ACCEPTED        REQ CMID accepted and in ACPT AVL tree of the
 166  *                      listening CMID.
 167  */
 168 typedef enum {
 169         REQ_CMID_NONE = 0,
 170         REQ_CMID_SERVER_NONE,
 171         REQ_CMID_CREATED,
 172         REQ_CMID_QUEUED,
 173         REQ_CMID_NOTIFIED,
 174         REQ_CMID_ACCEPTED,
 175 } cma_req_cmid_state_t;
 176 
 177 #define SOL_IS_SERVER_CMID(chanp)       \
 178         ((chanp)->chan_req_state != REQ_CMID_NONE)
 179 #define SOL_IS_CLIENT_CMID(chanp)       \
 180         ((chanp)->chan_connect_flag != SOL_CMA_CONNECT_NONE)
 181 
 182 #define REQ_CMID_IN_REQ_AVL_TREE(chanp) \
 183         ((chanp)->chan_req_state == REQ_CMID_QUEUED ||       \
 184         (chanp)->chan_req_state == REQ_CMID_NOTIFIED)
 185 #define SOL_CMID_CLOSE_REQUIRED(chanp)          \
 186         ((chanp)->chan_connect_flag == SOL_CMA_CONNECT_INITIATED ||  \
 187         (chanp)->chan_connect_flag == SOL_CMA_CONNECT_ESTABLISHED || \
 188         (chanp)->chan_req_state == REQ_CMID_ACCEPTED)
 189 #define SOL_CMAID_CONNECTED(chanp)      \
 190         (SOL_CMID_CLOSE_REQUIRED(chanp) ||      \
 191         (chanp)->chan_req_state  ==  REQ_CMID_NOTIFIED)
 192 
 193 /*
 194  * CMID_DESTROYED       - Flag to indicate rdma_destroy_id has been
 195  *                      called for this CMID
 196  *
 197  * EVENT_PROGRESS       - RDMACM Event for this CMID been passed to
 198  *                      the sol_ofs client.
 199  *
 200  * API_PROGRESS         - rdma_resolve_addr() / rdma_resolve_route() /
 201  *                      rdma_listen() is in progress.
 202  */
 203 #define SOL_CMA_CALLER_CMID_DESTROYED           0x01
 204 #define SOL_CMA_CALLER_EVENT_PROGRESS           0x02
 205 #define SOL_CMA_CALLER_API_PROGRESS             0x04
 206 
 207 typedef struct {
 208         struct rdma_cm_id       chan_rdma_cm;
 209 
 210         /*
 211          * Below are all CMA Channel specific fields required in Solaris,
 212          * apart from rdma_cm_id.
 213          */
 214 
 215         /* AVL Tree for REQs and EST CMIDs */
 216         avl_node_t              chan_req_avl_node;
 217         avl_node_t              chan_acpt_avl_node;
 218         avl_tree_t              chan_req_avl_tree;
 219         avl_tree_t              chan_acpt_avl_tree;
 220 
 221         /*
 222          * chan_req_cnt -
 223          *      REQ CMIDs created not yet notified to client
 224          * chan_total_req_cnt -
 225          *      REQ CMIDs created not destroy_id(0 not called.
 226          */
 227         uint64_t                chan_req_cnt;
 228         uint64_t                chan_req_total_cnt;
 229 
 230 
 231         /* State for Server side and client side CMIDs */
 232         cma_req_cmid_state_t    chan_req_state;
 233         sol_cma_connect_flag_t  chan_connect_flag;
 234 
 235         kmutex_t                chan_mutex;
 236         kcondvar_t              chan_destroy_cv;
 237         cma_chan_state_t        chan_state;
 238         uint8_t                 chan_cmid_destroy_state;
 239 
 240         /*
 241          * Transport type for the rdma_id, IB or IWARP. This is set to
 242          * NONE, when the transport type is not yet determined.
 243          */
 244         sol_cma_xport_type_t    chan_xport_type;
 245 
 246         /*
 247          * Passed from sol_ofs consumer, using the rdma_map_id2clnthdl
 248          * and rdma_map_id2qphdl
 249          */
 250         void                    *chan_ib_client_hdl;
 251         void                    *chan_iw_client_hdl;
 252         void                    *chan_qp_hdl;
 253 
 254         /* Data for root / endpoint CM ID. */
 255         sol_cma_listen_info_t   *chan_listenp;
 256 
 257         /* Ptr to the root CMID for Endpoint & Req CMID */
 258         struct rdma_cm_id       *listen_root;
 259 #define CHAN_LISTEN_LIST(chanp) (((chanp)->chan_listenp)->listen_list)
 260 #define CHAN_LISTEN_ROOT(chanp) ((chanp)->listen_root)
 261 
 262         struct rdma_conn_param  chan_param;
 263 
 264         /* Session ID for completion */
 265         void                    *chan_session_id;
 266 
 267         uint32_t                chan_qp_num;
 268         uint8_t                 chan_is_srq;
 269 
 270         union {
 271                 ibcma_chan_t    chan_ib_xport;
 272         } un_xport;     /* Transport specific fields */
 273 #define chan_ib                 un_xport.chan_ib_xport
 274 } sol_cma_chan_t;
 275 
 276 void ibcma_append_listen_list(struct rdma_cm_id *);
 277 #ifdef  IWARP_SUPPORT
 278 void iwcma_append_listen_list(struct rdma_cm_id *);
 279 #endif
 280 
 281 
 282 extern void cma_generate_event(struct rdma_cm_id *, enum rdma_cm_event_type,
 283     int, struct rdma_conn_param *, struct rdma_ud_param *);
 284 extern struct ib_device *sol_cma_acquire_device(ib_guid_t);
 285 
 286 static inline int
 287 sol_cma_any_addr(struct sockaddr *addr)
 288 {
 289         ASSERT(addr);
 290         if (addr->sa_family == AF_INET) {
 291                 struct sockaddr_in      *in_addr;
 292                 in_addr = (struct sockaddr_in *)addr;
 293 
 294                 return (in_addr->sin_addr.s_addr == INADDR_ANY);
 295         } else if (addr->sa_family == AF_INET6) {
 296                 struct sockaddr_in6     *in6_addr;
 297                 in6_addr = (struct sockaddr_in6 *)addr;
 298 
 299                 return (IN6_IS_ADDR_UNSPECIFIED(&(in6_addr->sin6_addr)));
 300         }
 301         return (0);
 302 }
 303 
 304 static inline struct rdma_cm_id *
 305 cma_create_new_id(struct rdma_cm_id *srcid)
 306 {
 307         struct  rdma_cm_id      *newid;
 308         sol_cma_chan_t          *new_chanp, *src_chanp;
 309 
 310         newid = rdma_create_id(srcid->event_handler, srcid->context,
 311             srcid->ps);
 312         if (newid == NULL)
 313                 return (newid);
 314 
 315         if (srcid->device) {
 316                 newid->device =
 317                     sol_cma_acquire_device(srcid->device->node_guid);
 318         }
 319         bcopy(&((srcid->route).addr), &((newid->route).addr),
 320             sizeof (struct rdma_addr));
 321         if ((srcid->route).num_paths) {
 322                 int     num_paths;
 323 
 324                 num_paths = (newid->route).num_paths =
 325                     (srcid->route).num_paths;
 326                 (newid->route).path_rec = kmem_zalloc(num_paths *
 327                     sizeof (struct ib_sa_path_rec), KM_SLEEP);
 328                 bcopy(&((srcid->route).path_rec),
 329                     &((newid->route).path_rec),
 330                     num_paths * sizeof (struct ib_sa_path_rec));
 331         }
 332         newid->port_num = srcid->port_num;
 333 
 334         new_chanp = (sol_cma_chan_t *)newid;
 335         src_chanp = (sol_cma_chan_t *)srcid;
 336         new_chanp->chan_state = src_chanp->chan_state;
 337         new_chanp->chan_xport_type = src_chanp->chan_xport_type;
 338         if (CHAN_LISTEN_ROOT(src_chanp))
 339                 CHAN_LISTEN_ROOT(new_chanp) =  CHAN_LISTEN_ROOT(src_chanp);
 340         else
 341                 CHAN_LISTEN_ROOT(new_chanp) = srcid;
 342         return (newid);
 343 }
 344 
 345 
 346 static inline struct rdma_cm_id *
 347 cma_get_req_idp(struct rdma_cm_id *root_idp, void *qp_hdl)
 348 {
 349         struct rdma_cm_id       *req_idp;
 350         sol_cma_chan_t          *root_chanp;
 351 
 352         root_chanp = (sol_cma_chan_t *)root_idp;
 353         ASSERT(MUTEX_HELD(&root_chanp->chan_mutex));
 354         req_idp = (struct rdma_cm_id *)avl_find(
 355             &root_chanp->chan_req_avl_tree, (void *)qp_hdl, NULL);
 356         return (req_idp);
 357 }
 358 
 359 static inline struct rdma_cm_id *
 360 cma_get_acpt_idp(struct rdma_cm_id *root_idp, void *qp_hdl)
 361 {
 362         struct rdma_cm_id       *acpt_idp;
 363         sol_cma_chan_t          *root_chanp;
 364 
 365         root_chanp = (sol_cma_chan_t *)root_idp;
 366         ASSERT(MUTEX_HELD(&root_chanp->chan_mutex));
 367         acpt_idp = (struct rdma_cm_id *)avl_find(
 368             &root_chanp->chan_acpt_avl_tree, (void *)qp_hdl, NULL);
 369         return (acpt_idp);
 370 }
 371 #ifdef __cplusplus
 372 }
 373 #endif
 374 
 375 #endif  /* _SYS_IB_CLIENTS_OF_SOL_OFS_SOL_CMA_H */