1 /* 2 * Copyright (C) 2009 Fen Systems Ltd <mbrown (at) fensystems.co.uk>. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided with the 15 * distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 21 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 28 * OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 FILE_LICENCE ( BSD2 ); 32 33 #include <stdlib.h> 34 #include <string.h> 35 #include <errno.h> 36 #include <gpxe/iobuf.h> 37 #include <gpxe/xfer.h> 38 #include <gpxe/process.h> 39 #include <gpxe/infiniband.h> 40 #include <gpxe/ib_cm.h> 41 #include <gpxe/ib_cmrc.h> 42 43 /** 44 * @file 45 * 46 * Infiniband Communication-managed Reliable Connections 47 * 48 */ 49 50 /** CMRC number of send WQEs 51 * 52 * This is a policy decision. 53 */ 54 #define IB_CMRC_NUM_SEND_WQES 4 55 56 /** CMRC number of receive WQEs 57 * 58 * This is a policy decision. 59 */ 60 #define IB_CMRC_NUM_RECV_WQES 2 61 62 /** CMRC number of completion queue entries 63 * 64 * This is a policy decision 65 */ 66 #define IB_CMRC_NUM_CQES 8 67 68 /** An Infiniband Communication-Managed Reliable Connection */ 69 struct ib_cmrc_connection { 70 /** Reference count */ 71 struct refcnt refcnt; 72 /** Data transfer interface */ 73 struct xfer_interface xfer; 74 /** Infiniband device */ 75 struct ib_device *ibdev; 76 /** Completion queue */ 77 struct ib_completion_queue *cq; 78 /** Queue pair */ 79 struct ib_queue_pair *qp; 80 /** Connection */ 81 struct ib_connection *conn; 82 /** Destination GID */ 83 struct ib_gid dgid; 84 /** Service ID */ 85 struct ib_gid_half service_id; 86 /** QP is connected */ 87 int connected; 88 /** Shutdown process */ 89 struct process shutdown; 90 }; 91 92 /** 93 * Shut down CMRC connection gracefully 94 * 95 * @v process Process 96 * 97 * The Infiniband data structures are not reference-counted or 98 * guarded. It is therefore unsafe to shut them down while we may be 99 * in the middle of a callback from the Infiniband stack (e.g. in a 100 * receive completion handler). 101 * 102 * This shutdown process will run some time after the call to 103 * ib_cmrc_close(), after control has returned out of the Infiniband 104 * core, and will shut down the Infiniband interfaces cleanly. 105 * 106 * The shutdown process holds an implicit reference on the CMRC 107 * connection, ensuring that the structure is not freed before the 108 * shutdown process has run. 109 */ 110 static void ib_cmrc_shutdown ( struct process *process ) { 111 struct ib_cmrc_connection *cmrc = 112 container_of ( process, struct ib_cmrc_connection, shutdown ); 113 114 DBGC ( cmrc, "CMRC %p shutting down\n", cmrc ); 115 116 /* Shut down Infiniband interface */ 117 ib_destroy_conn ( cmrc->ibdev, cmrc->qp, cmrc->conn ); 118 ib_destroy_qp ( cmrc->ibdev, cmrc->qp ); 119 ib_destroy_cq ( cmrc->ibdev, cmrc->cq ); 120 ib_close ( cmrc->ibdev ); 121 122 /* Remove process from run queue */ 123 process_del ( &cmrc->shutdown ); 124 125 /* Drop the remaining reference */ 126 ref_put ( &cmrc->refcnt ); 127 } 128 129 /** 130 * Close CMRC connection 131 * 132 * @v cmrc Communication-Managed Reliable Connection 133 * @v rc Reason for close 134 */ 135 static void ib_cmrc_close ( struct ib_cmrc_connection *cmrc, int rc ) { 136 137 /* Close data transfer interface */ 138 xfer_nullify ( &cmrc->xfer ); 139 xfer_close ( &cmrc->xfer, rc ); 140 141 /* Schedule shutdown process */ 142 process_add ( &cmrc->shutdown ); 143 } 144 145 /** 146 * Handle change of CMRC connection status 147 * 148 * @v ibdev Infiniband device 149 * @v qp Queue pair 150 * @v conn Connection 151 * @v rc_cm Connection status code 152 * @v private_data Private data, if available 153 * @v private_data_len Length of private data 154 */ 155 static void ib_cmrc_changed ( struct ib_device *ibdev __unused, 156 struct ib_queue_pair *qp, 157 struct ib_connection *conn __unused, int rc_cm, 158 void *private_data, size_t private_data_len ) { 159 struct ib_cmrc_connection *cmrc = ib_qp_get_ownerdata ( qp ); 160 int rc_xfer; 161 162 /* Record connection status */ 163 if ( rc_cm == 0 ) { 164 DBGC ( cmrc, "CMRC %p connected\n", cmrc ); 165 cmrc->connected = 1; 166 } else { 167 DBGC ( cmrc, "CMRC %p disconnected: %s\n", 168 cmrc, strerror ( rc_cm ) ); 169 cmrc->connected = 0; 170 } 171 172 /* Pass up any private data */ 173 DBGC2 ( cmrc, "CMRC %p received private data:\n", cmrc ); 174 DBGC2_HDA ( cmrc, 0, private_data, private_data_len ); 175 if ( private_data && 176 ( rc_xfer = xfer_deliver_raw ( &cmrc->xfer, private_data, 177 private_data_len ) ) != 0 ) { 178 DBGC ( cmrc, "CMRC %p could not deliver private data: %s\n", 179 cmrc, strerror ( rc_xfer ) ); 180 ib_cmrc_close ( cmrc, rc_xfer ); 181 return; 182 } 183 184 /* If we are disconnected, close the upper connection */ 185 if ( rc_cm != 0 ) { 186 ib_cmrc_close ( cmrc, rc_cm ); 187 return; 188 } 189 } 190 191 /** CMRC connection operations */ 192 static struct ib_connection_operations ib_cmrc_conn_op = { 193 .changed = ib_cmrc_changed, 194 }; 195 196 /** 197 * Handle CMRC send completion 198 * 199 * @v ibdev Infiniband device 200 * @v qp Queue pair 201 * @v iobuf I/O buffer 202 * @v rc Completion status code 203 */ 204 static void ib_cmrc_complete_send ( struct ib_device *ibdev __unused, 205 struct ib_queue_pair *qp, 206 struct io_buffer *iobuf, int rc ) { 207 struct ib_cmrc_connection *cmrc = ib_qp_get_ownerdata ( qp ); 208 209 /* Free the completed I/O buffer */ 210 free_iob ( iobuf ); 211 212 /* Close the connection on any send errors */ 213 if ( rc != 0 ) { 214 DBGC ( cmrc, "CMRC %p send error: %s\n", 215 cmrc, strerror ( rc ) ); 216 ib_cmrc_close ( cmrc, rc ); 217 return; 218 } 219 } 220 221 /** 222 * Handle CMRC receive completion 223 * 224 * @v ibdev Infiniband device 225 * @v qp Queue pair 226 * @v av Address vector, or NULL 227 * @v iobuf I/O buffer 228 * @v rc Completion status code 229 */ 230 static void ib_cmrc_complete_recv ( struct ib_device *ibdev __unused, 231 struct ib_queue_pair *qp, 232 struct ib_address_vector *av __unused, 233 struct io_buffer *iobuf, int rc ) { 234 struct ib_cmrc_connection *cmrc = ib_qp_get_ownerdata ( qp ); 235 236 /* Close the connection on any receive errors */ 237 if ( rc != 0 ) { 238 DBGC ( cmrc, "CMRC %p receive error: %s\n", 239 cmrc, strerror ( rc ) ); 240 free_iob ( iobuf ); 241 ib_cmrc_close ( cmrc, rc ); 242 return; 243 } 244 245 DBGC2 ( cmrc, "CMRC %p received:\n", cmrc ); 246 DBGC2_HDA ( cmrc, 0, iobuf->data, iob_len ( iobuf ) ); 247 248 /* Pass up data */ 249 if ( ( rc = xfer_deliver_iob ( &cmrc->xfer, iobuf ) ) != 0 ) { 250 DBGC ( cmrc, "CMRC %p could not deliver data: %s\n", 251 cmrc, strerror ( rc ) ); 252 ib_cmrc_close ( cmrc, rc ); 253 return; 254 } 255 } 256 257 /** Infiniband CMRC completion operations */ 258 static struct ib_completion_queue_operations ib_cmrc_completion_ops = { 259 .complete_send = ib_cmrc_complete_send, 260 .complete_recv = ib_cmrc_complete_recv, 261 }; 262 263 /** 264 * Send data via CMRC 265 * 266 * @v xfer Data transfer interface 267 * @v iobuf Datagram I/O buffer 268 * @v meta Data transfer metadata 269 * @ret rc Return status code 270 */ 271 static int ib_cmrc_xfer_deliver_iob ( struct xfer_interface *xfer, 272 struct io_buffer *iobuf, 273 struct xfer_metadata *meta __unused ) { 274 struct ib_cmrc_connection *cmrc = 275 container_of ( xfer, struct ib_cmrc_connection, xfer ); 276 int rc; 277 278 /* If no connection has yet been attempted, send this datagram 279 * as the CM REQ private data. Otherwise, send it via the QP. 280 */ 281 if ( ! cmrc->connected ) { 282 283 /* Abort if we have already sent a CM connection request */ 284 if ( cmrc->conn ) { 285 DBGC ( cmrc, "CMRC %p attempt to send before " 286 "connection is complete\n", cmrc ); 287 rc = -EIO; 288 goto out; 289 } 290 291 /* Send via CM connection request */ 292 cmrc->conn = ib_create_conn ( cmrc->ibdev, cmrc->qp, 293 &cmrc->dgid, &cmrc->service_id, 294 iobuf->data, iob_len ( iobuf ), 295 &ib_cmrc_conn_op ); 296 if ( ! cmrc->conn ) { 297 DBGC ( cmrc, "CMRC %p could not connect\n", cmrc ); 298 rc = -ENOMEM; 299 goto out; 300 } 301 302 } else { 303 304 /* Send via QP */ 305 if ( ( rc = ib_post_send ( cmrc->ibdev, cmrc->qp, NULL, 306 iob_disown ( iobuf ) ) ) != 0 ) { 307 DBGC ( cmrc, "CMRC %p could not send: %s\n", 308 cmrc, strerror ( rc ) ); 309 goto out; 310 } 311 312 } 313 return 0; 314 315 out: 316 /* Free the I/O buffer if necessary */ 317 free_iob ( iobuf ); 318 319 /* Close the connection on any errors */ 320 if ( rc != 0 ) 321 ib_cmrc_close ( cmrc, rc ); 322 323 return rc; 324 } 325 326 /** 327 * Check CMRC flow control window 328 * 329 * @v xfer Data transfer interface 330 * @ret len Length of window 331 */ 332 static size_t ib_cmrc_xfer_window ( struct xfer_interface *xfer ) { 333 struct ib_cmrc_connection *cmrc = 334 container_of ( xfer, struct ib_cmrc_connection, xfer ); 335 336 /* We indicate a window only when we are successfully 337 * connected. 338 */ 339 return ( cmrc->connected ? IB_MAX_PAYLOAD_SIZE : 0 ); 340 } 341 342 /** 343 * Close CMRC data-transfer interface 344 * 345 * @v xfer Data transfer interface 346 * @v rc Reason for close 347 */ 348 static void ib_cmrc_xfer_close ( struct xfer_interface *xfer, int rc ) { 349 struct ib_cmrc_connection *cmrc = 350 container_of ( xfer, struct ib_cmrc_connection, xfer ); 351 352 DBGC ( cmrc, "CMRC %p closed: %s\n", cmrc, strerror ( rc ) ); 353 ib_cmrc_close ( cmrc, rc ); 354 } 355 356 /** CMRC data transfer interface operations */ 357 static struct xfer_interface_operations ib_cmrc_xfer_operations = { 358 .close = ib_cmrc_xfer_close, 359 .vredirect = ignore_xfer_vredirect, 360 .window = ib_cmrc_xfer_window, 361 .alloc_iob = default_xfer_alloc_iob, 362 .deliver_iob = ib_cmrc_xfer_deliver_iob, 363 .deliver_raw = xfer_deliver_as_iob, 364 }; 365 366 /** 367 * Open CMRC connection 368 * 369 * @v xfer Data transfer interface 370 * @v ibdev Infiniband device 371 * @v dgid Destination GID 372 * @v service_id Service ID 373 * @ret rc Returns status code 374 */ 375 int ib_cmrc_open ( struct xfer_interface *xfer, struct ib_device *ibdev, 376 struct ib_gid *dgid, struct ib_gid_half *service_id ) { 377 struct ib_cmrc_connection *cmrc; 378 int rc; 379 380 /* Allocate and initialise structure */ 381 cmrc = zalloc ( sizeof ( *cmrc ) ); 382 if ( ! cmrc ) { 383 rc = -ENOMEM; 384 goto err_alloc; 385 } 386 xfer_init ( &cmrc->xfer, &ib_cmrc_xfer_operations, &cmrc->refcnt ); 387 cmrc->ibdev = ibdev; 388 memcpy ( &cmrc->dgid, dgid, sizeof ( cmrc->dgid ) ); 389 memcpy ( &cmrc->service_id, service_id, sizeof ( cmrc->service_id ) ); 390 process_init_stopped ( &cmrc->shutdown, ib_cmrc_shutdown, 391 &cmrc->refcnt ); 392 393 /* Open Infiniband device */ 394 if ( ( rc = ib_open ( ibdev ) ) != 0 ) { 395 DBGC ( cmrc, "CMRC %p could not open device: %s\n", 396 cmrc, strerror ( rc ) ); 397 goto err_open; 398 } 399 400 /* Create completion queue */ 401 cmrc->cq = ib_create_cq ( ibdev, IB_CMRC_NUM_CQES, 402 &ib_cmrc_completion_ops ); 403 if ( ! cmrc->cq ) { 404 DBGC ( cmrc, "CMRC %p could not create completion queue\n", 405 cmrc ); 406 rc = -ENOMEM; 407 goto err_create_cq; 408 } 409 410 /* Create queue pair */ 411 cmrc->qp = ib_create_qp ( ibdev, IB_QPT_RC, IB_CMRC_NUM_SEND_WQES, 412 cmrc->cq, IB_CMRC_NUM_RECV_WQES, cmrc->cq ); 413 if ( ! cmrc->qp ) { 414 DBGC ( cmrc, "CMRC %p could not create queue pair\n", cmrc ); 415 rc = -ENOMEM; 416 goto err_create_qp; 417 } 418 ib_qp_set_ownerdata ( cmrc->qp, cmrc ); 419 DBGC ( cmrc, "CMRC %p using QPN %lx\n", cmrc, cmrc->qp->qpn ); 420 421 /* Attach to parent interface, transfer reference (implicitly) 422 * to our shutdown process, and return. 423 */ 424 xfer_plug_plug ( &cmrc->xfer, xfer ); 425 return 0; 426 427 ib_destroy_qp ( ibdev, cmrc->qp ); 428 err_create_qp: 429 ib_destroy_cq ( ibdev, cmrc->cq ); 430 err_create_cq: 431 ib_close ( ibdev ); 432 err_open: 433 ref_put ( &cmrc->refcnt ); 434 err_alloc: 435 return rc; 436 } 437