|
|
1.1 ! root 1: /* ! 2: * Copyright (C) 2009 Fen Systems Ltd <[email protected]>. ! 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 <ipxe/iobuf.h> ! 37: #include <ipxe/xfer.h> ! 38: #include <ipxe/process.h> ! 39: #include <ipxe/infiniband.h> ! 40: #include <ipxe/ib_cm.h> ! 41: #include <ipxe/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 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: union ib_gid dgid; ! 84: /** Service ID */ ! 85: union ib_guid 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: intf_shutdown ( &cmrc->xfer, rc ); ! 139: ! 140: /* Schedule shutdown process */ ! 141: process_add ( &cmrc->shutdown ); ! 142: } ! 143: ! 144: /** ! 145: * Handle change of CMRC connection status ! 146: * ! 147: * @v ibdev Infiniband device ! 148: * @v qp Queue pair ! 149: * @v conn Connection ! 150: * @v rc_cm Connection status code ! 151: * @v private_data Private data, if available ! 152: * @v private_data_len Length of private data ! 153: */ ! 154: static void ib_cmrc_changed ( struct ib_device *ibdev __unused, ! 155: struct ib_queue_pair *qp, ! 156: struct ib_connection *conn __unused, int rc_cm, ! 157: void *private_data, size_t private_data_len ) { ! 158: struct ib_cmrc_connection *cmrc = ib_qp_get_ownerdata ( qp ); ! 159: int rc_xfer; ! 160: ! 161: /* Record connection status */ ! 162: if ( rc_cm == 0 ) { ! 163: DBGC ( cmrc, "CMRC %p connected\n", cmrc ); ! 164: cmrc->connected = 1; ! 165: } else { ! 166: DBGC ( cmrc, "CMRC %p disconnected: %s\n", ! 167: cmrc, strerror ( rc_cm ) ); ! 168: cmrc->connected = 0; ! 169: } ! 170: ! 171: /* Pass up any private data */ ! 172: DBGC2 ( cmrc, "CMRC %p received private data:\n", cmrc ); ! 173: DBGC2_HDA ( cmrc, 0, private_data, private_data_len ); ! 174: if ( private_data && ! 175: ( rc_xfer = xfer_deliver_raw ( &cmrc->xfer, private_data, ! 176: private_data_len ) ) != 0 ) { ! 177: DBGC ( cmrc, "CMRC %p could not deliver private data: %s\n", ! 178: cmrc, strerror ( rc_xfer ) ); ! 179: ib_cmrc_close ( cmrc, rc_xfer ); ! 180: return; ! 181: } ! 182: ! 183: /* If we are disconnected, close the upper connection */ ! 184: if ( rc_cm != 0 ) { ! 185: ib_cmrc_close ( cmrc, rc_cm ); ! 186: return; ! 187: } ! 188: } ! 189: ! 190: /** CMRC connection operations */ ! 191: static struct ib_connection_operations ib_cmrc_conn_op = { ! 192: .changed = ib_cmrc_changed, ! 193: }; ! 194: ! 195: /** ! 196: * Handle CMRC send completion ! 197: * ! 198: * @v ibdev Infiniband device ! 199: * @v qp Queue pair ! 200: * @v iobuf I/O buffer ! 201: * @v rc Completion status code ! 202: */ ! 203: static void ib_cmrc_complete_send ( struct ib_device *ibdev __unused, ! 204: struct ib_queue_pair *qp, ! 205: struct io_buffer *iobuf, int rc ) { ! 206: struct ib_cmrc_connection *cmrc = ib_qp_get_ownerdata ( qp ); ! 207: ! 208: /* Free the completed I/O buffer */ ! 209: free_iob ( iobuf ); ! 210: ! 211: /* Close the connection on any send errors */ ! 212: if ( rc != 0 ) { ! 213: DBGC ( cmrc, "CMRC %p send error: %s\n", ! 214: cmrc, strerror ( rc ) ); ! 215: ib_cmrc_close ( cmrc, rc ); ! 216: return; ! 217: } ! 218: } ! 219: ! 220: /** ! 221: * Handle CMRC receive completion ! 222: * ! 223: * @v ibdev Infiniband device ! 224: * @v qp Queue pair ! 225: * @v av Address vector, or NULL ! 226: * @v iobuf I/O buffer ! 227: * @v rc Completion status code ! 228: */ ! 229: static void ib_cmrc_complete_recv ( struct ib_device *ibdev __unused, ! 230: struct ib_queue_pair *qp, ! 231: struct ib_address_vector *av __unused, ! 232: struct io_buffer *iobuf, int rc ) { ! 233: struct ib_cmrc_connection *cmrc = ib_qp_get_ownerdata ( qp ); ! 234: ! 235: /* Close the connection on any receive errors */ ! 236: if ( rc != 0 ) { ! 237: DBGC ( cmrc, "CMRC %p receive error: %s\n", ! 238: cmrc, strerror ( rc ) ); ! 239: free_iob ( iobuf ); ! 240: ib_cmrc_close ( cmrc, rc ); ! 241: return; ! 242: } ! 243: ! 244: DBGC2 ( cmrc, "CMRC %p received:\n", cmrc ); ! 245: DBGC2_HDA ( cmrc, 0, iobuf->data, iob_len ( iobuf ) ); ! 246: ! 247: /* Pass up data */ ! 248: if ( ( rc = xfer_deliver_iob ( &cmrc->xfer, iobuf ) ) != 0 ) { ! 249: DBGC ( cmrc, "CMRC %p could not deliver data: %s\n", ! 250: cmrc, strerror ( rc ) ); ! 251: ib_cmrc_close ( cmrc, rc ); ! 252: return; ! 253: } ! 254: } ! 255: ! 256: /** Infiniband CMRC completion operations */ ! 257: static struct ib_completion_queue_operations ib_cmrc_completion_ops = { ! 258: .complete_send = ib_cmrc_complete_send, ! 259: .complete_recv = ib_cmrc_complete_recv, ! 260: }; ! 261: ! 262: /** ! 263: * Send data via CMRC ! 264: * ! 265: * @v cmrc CMRC connection ! 266: * @v iobuf Datagram I/O buffer ! 267: * @v meta Data transfer metadata ! 268: * @ret rc Return status code ! 269: */ ! 270: static int ib_cmrc_xfer_deliver ( struct ib_cmrc_connection *cmrc, ! 271: struct io_buffer *iobuf, ! 272: struct xfer_metadata *meta __unused ) { ! 273: int rc; ! 274: ! 275: /* If no connection has yet been attempted, send this datagram ! 276: * as the CM REQ private data. Otherwise, send it via the QP. ! 277: */ ! 278: if ( ! cmrc->connected ) { ! 279: ! 280: /* Abort if we have already sent a CM connection request */ ! 281: if ( cmrc->conn ) { ! 282: DBGC ( cmrc, "CMRC %p attempt to send before " ! 283: "connection is complete\n", cmrc ); ! 284: rc = -EIO; ! 285: goto out; ! 286: } ! 287: ! 288: /* Send via CM connection request */ ! 289: cmrc->conn = ib_create_conn ( cmrc->ibdev, cmrc->qp, ! 290: &cmrc->dgid, &cmrc->service_id, ! 291: iobuf->data, iob_len ( iobuf ), ! 292: &ib_cmrc_conn_op ); ! 293: if ( ! cmrc->conn ) { ! 294: DBGC ( cmrc, "CMRC %p could not connect\n", cmrc ); ! 295: rc = -ENOMEM; ! 296: goto out; ! 297: } ! 298: ! 299: } else { ! 300: ! 301: /* Send via QP */ ! 302: if ( ( rc = ib_post_send ( cmrc->ibdev, cmrc->qp, NULL, ! 303: iob_disown ( iobuf ) ) ) != 0 ) { ! 304: DBGC ( cmrc, "CMRC %p could not send: %s\n", ! 305: cmrc, strerror ( rc ) ); ! 306: goto out; ! 307: } ! 308: ! 309: } ! 310: return 0; ! 311: ! 312: out: ! 313: /* Free the I/O buffer if necessary */ ! 314: free_iob ( iobuf ); ! 315: ! 316: /* Close the connection on any errors */ ! 317: if ( rc != 0 ) ! 318: ib_cmrc_close ( cmrc, rc ); ! 319: ! 320: return rc; ! 321: } ! 322: ! 323: /** ! 324: * Check CMRC flow control window ! 325: * ! 326: * @v cmrc CMRC connection ! 327: * @ret len Length of window ! 328: */ ! 329: static size_t ib_cmrc_xfer_window ( struct ib_cmrc_connection *cmrc ) { ! 330: ! 331: /* We indicate a window only when we are successfully ! 332: * connected. ! 333: */ ! 334: return ( cmrc->connected ? IB_MAX_PAYLOAD_SIZE : 0 ); ! 335: } ! 336: ! 337: /** ! 338: * Identify device underlying CMRC connection ! 339: * ! 340: * @v cmrc CMRC connection ! 341: * @ret device Underlying device ! 342: */ ! 343: static struct device * ! 344: ib_cmrc_identify_device ( struct ib_cmrc_connection *cmrc ) { ! 345: return cmrc->ibdev->dev; ! 346: } ! 347: ! 348: /** CMRC data transfer interface operations */ ! 349: static struct interface_operation ib_cmrc_xfer_operations[] = { ! 350: INTF_OP ( xfer_deliver, struct ib_cmrc_connection *, ! 351: ib_cmrc_xfer_deliver ), ! 352: INTF_OP ( xfer_window, struct ib_cmrc_connection *, ! 353: ib_cmrc_xfer_window ), ! 354: INTF_OP ( intf_close, struct ib_cmrc_connection *, ib_cmrc_close ), ! 355: INTF_OP ( identify_device, struct ib_cmrc_connection *, ! 356: ib_cmrc_identify_device ), ! 357: }; ! 358: ! 359: /** CMRC data transfer interface descriptor */ ! 360: static struct interface_descriptor ib_cmrc_xfer_desc = ! 361: INTF_DESC ( struct ib_cmrc_connection, xfer, ib_cmrc_xfer_operations ); ! 362: ! 363: /** ! 364: * Open CMRC connection ! 365: * ! 366: * @v xfer Data transfer interface ! 367: * @v ibdev Infiniband device ! 368: * @v dgid Destination GID ! 369: * @v service_id Service ID ! 370: * @ret rc Returns status code ! 371: */ ! 372: int ib_cmrc_open ( struct interface *xfer, struct ib_device *ibdev, ! 373: union ib_gid *dgid, union ib_guid *service_id ) { ! 374: struct ib_cmrc_connection *cmrc; ! 375: int rc; ! 376: ! 377: /* Allocate and initialise structure */ ! 378: cmrc = zalloc ( sizeof ( *cmrc ) ); ! 379: if ( ! cmrc ) { ! 380: rc = -ENOMEM; ! 381: goto err_alloc; ! 382: } ! 383: ref_init ( &cmrc->refcnt, NULL ); ! 384: intf_init ( &cmrc->xfer, &ib_cmrc_xfer_desc, &cmrc->refcnt ); ! 385: cmrc->ibdev = ibdev; ! 386: memcpy ( &cmrc->dgid, dgid, sizeof ( cmrc->dgid ) ); ! 387: memcpy ( &cmrc->service_id, service_id, sizeof ( cmrc->service_id ) ); ! 388: process_init_stopped ( &cmrc->shutdown, ib_cmrc_shutdown, ! 389: &cmrc->refcnt ); ! 390: ! 391: /* Open Infiniband device */ ! 392: if ( ( rc = ib_open ( ibdev ) ) != 0 ) { ! 393: DBGC ( cmrc, "CMRC %p could not open device: %s\n", ! 394: cmrc, strerror ( rc ) ); ! 395: goto err_open; ! 396: } ! 397: ! 398: /* Create completion queue */ ! 399: cmrc->cq = ib_create_cq ( ibdev, IB_CMRC_NUM_CQES, ! 400: &ib_cmrc_completion_ops ); ! 401: if ( ! cmrc->cq ) { ! 402: DBGC ( cmrc, "CMRC %p could not create completion queue\n", ! 403: cmrc ); ! 404: rc = -ENOMEM; ! 405: goto err_create_cq; ! 406: } ! 407: ! 408: /* Create queue pair */ ! 409: cmrc->qp = ib_create_qp ( ibdev, IB_QPT_RC, IB_CMRC_NUM_SEND_WQES, ! 410: cmrc->cq, IB_CMRC_NUM_RECV_WQES, cmrc->cq ); ! 411: if ( ! cmrc->qp ) { ! 412: DBGC ( cmrc, "CMRC %p could not create queue pair\n", cmrc ); ! 413: rc = -ENOMEM; ! 414: goto err_create_qp; ! 415: } ! 416: ib_qp_set_ownerdata ( cmrc->qp, cmrc ); ! 417: DBGC ( cmrc, "CMRC %p using QPN %lx\n", cmrc, cmrc->qp->qpn ); ! 418: ! 419: /* Attach to parent interface, transfer reference (implicitly) ! 420: * to our shutdown process, and return. ! 421: */ ! 422: intf_plug_plug ( &cmrc->xfer, xfer ); ! 423: return 0; ! 424: ! 425: ib_destroy_qp ( ibdev, cmrc->qp ); ! 426: err_create_qp: ! 427: ib_destroy_cq ( ibdev, cmrc->cq ); ! 428: err_create_cq: ! 429: ib_close ( ibdev ); ! 430: err_open: ! 431: ref_put ( &cmrc->refcnt ); ! 432: err_alloc: ! 433: return rc; ! 434: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.