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