ib_cmrc.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2009 Fen Systems Ltd <mbrown@fensystems.co.uk>.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  *   Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  *
00012  *   Redistributions in binary form must reproduce the above copyright
00013  *   notice, this list of conditions and the following disclaimer in
00014  *   the documentation and/or other materials provided with the
00015  *   distribution.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00018  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00021  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
00022  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00023  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00024  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00025  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
00026  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00027  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
00028  * OF THE POSSIBILITY OF SUCH DAMAGE.
00029  */
00030 
00031 FILE_LICENCE ( BSD2 );
00032 
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <errno.h>
00036 #include <gpxe/iobuf.h>
00037 #include <gpxe/xfer.h>
00038 #include <gpxe/process.h>
00039 #include <gpxe/infiniband.h>
00040 #include <gpxe/ib_cm.h>
00041 #include <gpxe/ib_cmrc.h>
00042 
00043 /**
00044  * @file
00045  *
00046  * Infiniband Communication-managed Reliable Connections
00047  *
00048  */
00049 
00050 /** CMRC number of send WQEs
00051  *
00052  * This is a policy decision.
00053  */
00054 #define IB_CMRC_NUM_SEND_WQES 4
00055 
00056 /** CMRC number of receive WQEs
00057  *
00058  * This is a policy decision.
00059  */
00060 #define IB_CMRC_NUM_RECV_WQES 2
00061 
00062 /** CMRC number of completion queue entries
00063  *
00064  * This is a policy decision
00065  */
00066 #define IB_CMRC_NUM_CQES 8
00067 
00068 /** An Infiniband Communication-Managed Reliable Connection */
00069 struct ib_cmrc_connection {
00070         /** Reference count */
00071         struct refcnt refcnt;
00072         /** Data transfer interface */
00073         struct xfer_interface xfer;
00074         /** Infiniband device */
00075         struct ib_device *ibdev;
00076         /** Completion queue */
00077         struct ib_completion_queue *cq;
00078         /** Queue pair */
00079         struct ib_queue_pair *qp;
00080         /** Connection */
00081         struct ib_connection *conn;
00082         /** Destination GID */
00083         struct ib_gid dgid;
00084         /** Service ID */
00085         struct ib_gid_half service_id;
00086         /** QP is connected */
00087         int connected;
00088         /** Shutdown process */
00089         struct process shutdown;
00090 };
00091 
00092 /**
00093  * Shut down CMRC connection gracefully
00094  *
00095  * @v process           Process
00096  *
00097  * The Infiniband data structures are not reference-counted or
00098  * guarded.  It is therefore unsafe to shut them down while we may be
00099  * in the middle of a callback from the Infiniband stack (e.g. in a
00100  * receive completion handler).
00101  *
00102  * This shutdown process will run some time after the call to
00103  * ib_cmrc_close(), after control has returned out of the Infiniband
00104  * core, and will shut down the Infiniband interfaces cleanly.
00105  *
00106  * The shutdown process holds an implicit reference on the CMRC
00107  * connection, ensuring that the structure is not freed before the
00108  * shutdown process has run.
00109  */
00110 static void ib_cmrc_shutdown ( struct process *process ) {
00111         struct ib_cmrc_connection *cmrc =
00112                 container_of ( process, struct ib_cmrc_connection, shutdown );
00113 
00114         DBGC ( cmrc, "CMRC %p shutting down\n", cmrc );
00115 
00116         /* Shut down Infiniband interface */
00117         ib_destroy_conn ( cmrc->ibdev, cmrc->qp, cmrc->conn );
00118         ib_destroy_qp ( cmrc->ibdev, cmrc->qp );
00119         ib_destroy_cq ( cmrc->ibdev, cmrc->cq );
00120         ib_close ( cmrc->ibdev );
00121 
00122         /* Remove process from run queue */
00123         process_del ( &cmrc->shutdown );
00124 
00125         /* Drop the remaining reference */
00126         ref_put ( &cmrc->refcnt );
00127 }
00128 
00129 /**
00130  * Close CMRC connection
00131  *
00132  * @v cmrc              Communication-Managed Reliable Connection
00133  * @v rc                Reason for close
00134  */
00135 static void ib_cmrc_close ( struct ib_cmrc_connection *cmrc, int rc ) {
00136 
00137         /* Close data transfer interface */
00138         xfer_nullify ( &cmrc->xfer );
00139         xfer_close ( &cmrc->xfer, rc );
00140 
00141         /* Schedule shutdown process */
00142         process_add ( &cmrc->shutdown );
00143 }
00144 
00145 /**
00146  * Handle change of CMRC connection status
00147  *
00148  * @v ibdev             Infiniband device
00149  * @v qp                Queue pair
00150  * @v conn              Connection
00151  * @v rc_cm             Connection status code
00152  * @v private_data      Private data, if available
00153  * @v private_data_len  Length of private data
00154  */
00155 static void ib_cmrc_changed ( struct ib_device *ibdev __unused,
00156                               struct ib_queue_pair *qp,
00157                               struct ib_connection *conn __unused, int rc_cm,
00158                               void *private_data, size_t private_data_len ) {
00159         struct ib_cmrc_connection *cmrc = ib_qp_get_ownerdata ( qp );
00160         int rc_xfer;
00161 
00162         /* Record connection status */
00163         if ( rc_cm == 0 ) {
00164                 DBGC ( cmrc, "CMRC %p connected\n", cmrc );
00165                 cmrc->connected = 1;
00166         } else {
00167                 DBGC ( cmrc, "CMRC %p disconnected: %s\n",
00168                        cmrc, strerror ( rc_cm ) );
00169                 cmrc->connected = 0;
00170         }
00171 
00172         /* Pass up any private data */
00173         DBGC2 ( cmrc, "CMRC %p received private data:\n", cmrc );
00174         DBGC2_HDA ( cmrc, 0, private_data, private_data_len );
00175         if ( private_data &&
00176              ( rc_xfer = xfer_deliver_raw ( &cmrc->xfer, private_data,
00177                                             private_data_len ) ) != 0 ) {
00178                 DBGC ( cmrc, "CMRC %p could not deliver private data: %s\n",
00179                        cmrc, strerror ( rc_xfer ) );
00180                 ib_cmrc_close ( cmrc, rc_xfer );
00181                 return;
00182         }
00183 
00184         /* If we are disconnected, close the upper connection */
00185         if ( rc_cm != 0 ) {
00186                 ib_cmrc_close ( cmrc, rc_cm );
00187                 return;
00188         }
00189 }
00190 
00191 /** CMRC connection operations */
00192 static struct ib_connection_operations ib_cmrc_conn_op = {
00193         .changed = ib_cmrc_changed,
00194 };
00195 
00196 /**
00197  * Handle CMRC send completion
00198  *
00199  * @v ibdev             Infiniband device
00200  * @v qp                Queue pair
00201  * @v iobuf             I/O buffer
00202  * @v rc                Completion status code
00203  */
00204 static void ib_cmrc_complete_send ( struct ib_device *ibdev __unused,
00205                                     struct ib_queue_pair *qp,
00206                                     struct io_buffer *iobuf, int rc ) {
00207         struct ib_cmrc_connection *cmrc = ib_qp_get_ownerdata ( qp );
00208 
00209         /* Free the completed I/O buffer */
00210         free_iob ( iobuf );
00211 
00212         /* Close the connection on any send errors */
00213         if ( rc != 0 ) {
00214                 DBGC ( cmrc, "CMRC %p send error: %s\n",
00215                        cmrc, strerror ( rc ) );
00216                 ib_cmrc_close ( cmrc, rc );
00217                 return;
00218         }
00219 }
00220 
00221 /**
00222  * Handle CMRC receive completion
00223  *
00224  * @v ibdev             Infiniband device
00225  * @v qp                Queue pair
00226  * @v av                Address vector, or NULL
00227  * @v iobuf             I/O buffer
00228  * @v rc                Completion status code
00229  */
00230 static void ib_cmrc_complete_recv ( struct ib_device *ibdev __unused,
00231                                     struct ib_queue_pair *qp,
00232                                     struct ib_address_vector *av __unused,
00233                                     struct io_buffer *iobuf, int rc ) {
00234         struct ib_cmrc_connection *cmrc = ib_qp_get_ownerdata ( qp );
00235 
00236         /* Close the connection on any receive errors */
00237         if ( rc != 0 ) {
00238                 DBGC ( cmrc, "CMRC %p receive error: %s\n",
00239                        cmrc, strerror ( rc ) );
00240                 free_iob ( iobuf );
00241                 ib_cmrc_close ( cmrc, rc );
00242                 return;
00243         }
00244 
00245         DBGC2 ( cmrc, "CMRC %p received:\n", cmrc );
00246         DBGC2_HDA ( cmrc, 0, iobuf->data, iob_len ( iobuf ) );
00247 
00248         /* Pass up data */
00249         if ( ( rc = xfer_deliver_iob ( &cmrc->xfer, iobuf ) ) != 0 ) {
00250                 DBGC ( cmrc, "CMRC %p could not deliver data: %s\n",
00251                        cmrc, strerror ( rc ) );
00252                 ib_cmrc_close ( cmrc, rc );
00253                 return;
00254         }
00255 }
00256 
00257 /** Infiniband CMRC completion operations */
00258 static struct ib_completion_queue_operations ib_cmrc_completion_ops = {
00259         .complete_send = ib_cmrc_complete_send,
00260         .complete_recv = ib_cmrc_complete_recv,
00261 };
00262 
00263 /**
00264  * Send data via CMRC
00265  *
00266  * @v xfer              Data transfer interface
00267  * @v iobuf             Datagram I/O buffer
00268  * @v meta              Data transfer metadata
00269  * @ret rc              Return status code
00270  */
00271 static int ib_cmrc_xfer_deliver_iob ( struct xfer_interface *xfer,
00272                                       struct io_buffer *iobuf,
00273                                       struct xfer_metadata *meta __unused ) {
00274         struct ib_cmrc_connection *cmrc =
00275                 container_of ( xfer, struct ib_cmrc_connection, xfer );
00276         int rc;
00277 
00278         /* If no connection has yet been attempted, send this datagram
00279          * as the CM REQ private data.  Otherwise, send it via the QP.
00280          */
00281         if ( ! cmrc->connected ) {
00282 
00283                 /* Abort if we have already sent a CM connection request */
00284                 if ( cmrc->conn ) {
00285                         DBGC ( cmrc, "CMRC %p attempt to send before "
00286                                "connection is complete\n", cmrc );
00287                         rc = -EIO;
00288                         goto out;
00289                 }
00290 
00291                 /* Send via CM connection request */
00292                 cmrc->conn = ib_create_conn ( cmrc->ibdev, cmrc->qp,
00293                                               &cmrc->dgid, &cmrc->service_id,
00294                                               iobuf->data, iob_len ( iobuf ),
00295                                               &ib_cmrc_conn_op );
00296                 if ( ! cmrc->conn ) {
00297                         DBGC ( cmrc, "CMRC %p could not connect\n", cmrc );
00298                         rc = -ENOMEM;
00299                         goto out;
00300                 }
00301 
00302         } else {
00303 
00304                 /* Send via QP */
00305                 if ( ( rc = ib_post_send ( cmrc->ibdev, cmrc->qp, NULL,
00306                                            iob_disown ( iobuf ) ) ) != 0 ) {
00307                         DBGC ( cmrc, "CMRC %p could not send: %s\n",
00308                                cmrc, strerror ( rc ) );
00309                         goto out;
00310                 }
00311 
00312         }
00313         return 0;
00314 
00315  out:
00316         /* Free the I/O buffer if necessary */
00317         free_iob ( iobuf );
00318 
00319         /* Close the connection on any errors */
00320         if ( rc != 0 )
00321                 ib_cmrc_close ( cmrc, rc );
00322 
00323         return rc;
00324 }
00325 
00326 /**
00327  * Check CMRC flow control window
00328  *
00329  * @v xfer              Data transfer interface
00330  * @ret len             Length of window
00331  */
00332 static size_t ib_cmrc_xfer_window ( struct xfer_interface *xfer ) {
00333         struct ib_cmrc_connection *cmrc =
00334                 container_of ( xfer, struct ib_cmrc_connection, xfer );
00335 
00336         /* We indicate a window only when we are successfully
00337          * connected.
00338          */
00339         return ( cmrc->connected ? IB_MAX_PAYLOAD_SIZE : 0 );
00340 }
00341 
00342 /**
00343  * Close CMRC data-transfer interface
00344  *
00345  * @v xfer              Data transfer interface
00346  * @v rc                Reason for close
00347  */
00348 static void ib_cmrc_xfer_close ( struct xfer_interface *xfer, int rc ) {
00349         struct ib_cmrc_connection *cmrc =
00350                 container_of ( xfer, struct ib_cmrc_connection, xfer );
00351 
00352         DBGC ( cmrc, "CMRC %p closed: %s\n", cmrc, strerror ( rc ) );
00353         ib_cmrc_close ( cmrc, rc );
00354 }
00355 
00356 /** CMRC data transfer interface operations */
00357 static struct xfer_interface_operations ib_cmrc_xfer_operations = {
00358         .close          = ib_cmrc_xfer_close,
00359         .vredirect      = ignore_xfer_vredirect,
00360         .window         = ib_cmrc_xfer_window,
00361         .alloc_iob      = default_xfer_alloc_iob,
00362         .deliver_iob    = ib_cmrc_xfer_deliver_iob,
00363         .deliver_raw    = xfer_deliver_as_iob,
00364 };
00365 
00366 /**
00367  * Open CMRC connection
00368  *
00369  * @v xfer              Data transfer interface
00370  * @v ibdev             Infiniband device
00371  * @v dgid              Destination GID
00372  * @v service_id        Service ID
00373  * @ret rc              Returns status code
00374  */
00375 int ib_cmrc_open ( struct xfer_interface *xfer, struct ib_device *ibdev,
00376                    struct ib_gid *dgid, struct ib_gid_half *service_id ) {
00377         struct ib_cmrc_connection *cmrc;
00378         int rc;
00379 
00380         /* Allocate and initialise structure */
00381         cmrc = zalloc ( sizeof ( *cmrc ) );
00382         if ( ! cmrc ) {
00383                 rc = -ENOMEM;
00384                 goto err_alloc;
00385         }
00386         xfer_init ( &cmrc->xfer, &ib_cmrc_xfer_operations, &cmrc->refcnt );
00387         cmrc->ibdev = ibdev;
00388         memcpy ( &cmrc->dgid, dgid, sizeof ( cmrc->dgid ) );
00389         memcpy ( &cmrc->service_id, service_id, sizeof ( cmrc->service_id ) );
00390         process_init_stopped ( &cmrc->shutdown, ib_cmrc_shutdown,
00391                                &cmrc->refcnt );
00392 
00393         /* Open Infiniband device */
00394         if ( ( rc = ib_open ( ibdev ) ) != 0 ) {
00395                 DBGC ( cmrc, "CMRC %p could not open device: %s\n",
00396                        cmrc, strerror ( rc ) );
00397                 goto err_open;
00398         }
00399 
00400         /* Create completion queue */
00401         cmrc->cq = ib_create_cq ( ibdev, IB_CMRC_NUM_CQES,
00402                                   &ib_cmrc_completion_ops );
00403         if ( ! cmrc->cq ) {
00404                 DBGC ( cmrc, "CMRC %p could not create completion queue\n",
00405                        cmrc );
00406                 rc = -ENOMEM;
00407                 goto err_create_cq;
00408         }
00409 
00410         /* Create queue pair */
00411         cmrc->qp = ib_create_qp ( ibdev, IB_QPT_RC, IB_CMRC_NUM_SEND_WQES,
00412                                   cmrc->cq, IB_CMRC_NUM_RECV_WQES, cmrc->cq );
00413         if ( ! cmrc->qp ) {
00414                 DBGC ( cmrc, "CMRC %p could not create queue pair\n", cmrc );
00415                 rc = -ENOMEM;
00416                 goto err_create_qp;
00417         }
00418         ib_qp_set_ownerdata ( cmrc->qp, cmrc );
00419         DBGC ( cmrc, "CMRC %p using QPN %lx\n", cmrc, cmrc->qp->qpn );
00420 
00421         /* Attach to parent interface, transfer reference (implicitly)
00422          * to our shutdown process, and return.
00423          */
00424         xfer_plug_plug ( &cmrc->xfer, xfer );
00425         return 0;
00426 
00427         ib_destroy_qp ( ibdev, cmrc->qp );
00428  err_create_qp:
00429         ib_destroy_cq ( ibdev, cmrc->cq );
00430  err_create_cq:
00431         ib_close ( ibdev );
00432  err_open:
00433         ref_put ( &cmrc->refcnt );
00434  err_alloc:
00435         return rc;
00436 }

Generated on Tue Apr 6 20:01:10 2010 for gPXE by  doxygen 1.5.7.1