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