00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 FILE_LICENCE ( GPL2_OR_LATER );
00020
00021 #include <stdint.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <byteswap.h>
00025 #include <errno.h>
00026 #include <assert.h>
00027 #include <gpxe/infiniband.h>
00028 #include <gpxe/ib_mi.h>
00029 #include <gpxe/ib_pathrec.h>
00030 #include <gpxe/ib_cm.h>
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 static LIST_HEAD ( ib_cm_conns );
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051 static int ib_cm_send_rtu ( struct ib_device *ibdev,
00052 struct ib_mad_interface *mi,
00053 struct ib_connection *conn,
00054 struct ib_address_vector *av ) {
00055 union ib_mad mad;
00056 struct ib_cm_ready_to_use *ready =
00057 &mad.cm.cm_data.ready_to_use;
00058 int rc;
00059
00060
00061 memset ( &mad, 0, sizeof ( mad ) );
00062 mad.hdr.mgmt_class = IB_MGMT_CLASS_CM;
00063 mad.hdr.class_version = IB_CM_CLASS_VERSION;
00064 mad.hdr.method = IB_MGMT_METHOD_SEND;
00065 mad.hdr.attr_id = htons ( IB_CM_ATTR_READY_TO_USE );
00066 ready->local_id = htonl ( conn->local_id );
00067 ready->remote_id = htonl ( conn->remote_id );
00068 if ( ( rc = ib_mi_send ( ibdev, mi, &mad, av ) ) != 0 ){
00069 DBGC ( conn, "CM %p could not send RTU: %s\n",
00070 conn, strerror ( rc ) );
00071 return rc;
00072 }
00073
00074 return 0;
00075 }
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090 static void ib_cm_connect_rep ( struct ib_device *ibdev,
00091 struct ib_mad_interface *mi,
00092 union ib_mad *mad,
00093 struct ib_address_vector *av ) {
00094 struct ib_cm_connect_reply *connect_rep =
00095 &mad->cm.cm_data.connect_reply;
00096 struct ib_connection *conn;
00097 int rc;
00098
00099
00100 list_for_each_entry ( conn, &ib_cm_conns, list ) {
00101 if ( ntohl ( connect_rep->remote_id ) != conn->local_id )
00102 continue;
00103
00104 if ( ( rc = ib_cm_send_rtu ( ibdev, mi, conn, av ) ) != 0 ) {
00105
00106 return;
00107 }
00108 return;
00109 }
00110
00111 DBG ( "CM unidentified connection %08x\n",
00112 ntohl ( connect_rep->remote_id ) );
00113 }
00114
00115
00116 struct ib_mad_agent ib_cm_agent[] __ib_mad_agent = {
00117 {
00118 .mgmt_class = IB_MGMT_CLASS_CM,
00119 .class_version = IB_CM_CLASS_VERSION,
00120 .attr_id = htons ( IB_CM_ATTR_CONNECT_REPLY ),
00121 .handle = ib_cm_connect_rep,
00122 },
00123 };
00124
00125
00126
00127
00128
00129
00130
00131 static int ib_cm_rejection_reason_to_rc ( uint16_t reason ) {
00132 switch ( reason ) {
00133 case htons ( IB_CM_REJECT_BAD_SERVICE_ID ) :
00134 return -ENODEV;
00135 case htons ( IB_CM_REJECT_STALE_CONN ) :
00136 return -EALREADY;
00137 case htons ( IB_CM_REJECT_CONSUMER ) :
00138 return -ENOTTY;
00139 default:
00140 return -EPERM;
00141 }
00142 }
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154 static void ib_cm_req_complete ( struct ib_device *ibdev,
00155 struct ib_mad_interface *mi,
00156 struct ib_mad_transaction *madx,
00157 int rc, union ib_mad *mad,
00158 struct ib_address_vector *av ) {
00159 struct ib_connection *conn = ib_madx_get_ownerdata ( madx );
00160 struct ib_queue_pair *qp = conn->qp;
00161 struct ib_cm_common *common = &mad->cm.cm_data.common;
00162 struct ib_cm_connect_reply *connect_rep =
00163 &mad->cm.cm_data.connect_reply;
00164 struct ib_cm_connect_reject *connect_rej =
00165 &mad->cm.cm_data.connect_reject;
00166 void *private_data = NULL;
00167 size_t private_data_len = 0;
00168
00169
00170 if ( ( rc == 0 ) && ( mad->hdr.status != htons ( IB_MGMT_STATUS_OK ) ))
00171 rc = -EIO;
00172 if ( rc != 0 ) {
00173 DBGC ( conn, "CM %p connection request failed: %s\n",
00174 conn, strerror ( rc ) );
00175 goto out;
00176 }
00177
00178
00179 conn->remote_id = ntohl ( common->local_id );
00180
00181
00182 switch ( mad->hdr.attr_id ) {
00183
00184 case htons ( IB_CM_ATTR_CONNECT_REPLY ) :
00185
00186 qp->av.qpn = ( ntohl ( connect_rep->local_qpn ) >> 8 );
00187 qp->send.psn = ( ntohl ( connect_rep->starting_psn ) >> 8 );
00188 private_data = &connect_rep->private_data;
00189 private_data_len = sizeof ( connect_rep->private_data );
00190 DBGC ( conn, "CM %p connected to QPN %lx PSN %x\n",
00191 conn, qp->av.qpn, qp->send.psn );
00192
00193
00194 if ( ( rc = ib_modify_qp ( ibdev, qp ) ) != 0 ) {
00195 DBGC ( conn, "CM %p could not modify queue pair: %s\n",
00196 conn, strerror ( rc ) );
00197 goto out;
00198 }
00199
00200
00201 if ( ( rc = ib_cm_send_rtu ( ibdev, mi, conn, av ) ) != 0 ) {
00202
00203 rc = 0;
00204 }
00205 break;
00206
00207 case htons ( IB_CM_ATTR_CONNECT_REJECT ) :
00208
00209 DBGC ( conn, "CM %p connection rejected (reason %d)\n",
00210 conn, ntohs ( connect_rej->reason ) );
00211
00212 if ( connect_rej->reason == htons ( IB_CM_REJECT_CONSUMER ) ) {
00213 private_data = &connect_rej->private_data;
00214 private_data_len = sizeof (connect_rej->private_data);
00215 }
00216 rc = ib_cm_rejection_reason_to_rc ( connect_rej->reason );
00217 break;
00218
00219 default:
00220 DBGC ( conn, "CM %p unexpected response (attribute %04x)\n",
00221 conn, ntohs ( mad->hdr.attr_id ) );
00222 rc = -ENOTSUP;
00223 break;
00224 }
00225
00226 out:
00227
00228 ib_destroy_madx ( ibdev, ibdev->gsi, madx );
00229 conn->madx = NULL;
00230
00231
00232 conn->op->changed ( ibdev, qp, conn, rc, private_data,
00233 private_data_len );
00234 }
00235
00236
00237 static struct ib_mad_transaction_operations ib_cm_req_op = {
00238 .complete = ib_cm_req_complete,
00239 };
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249 static void ib_cm_path_complete ( struct ib_device *ibdev,
00250 struct ib_path *path, int rc,
00251 struct ib_address_vector *av ) {
00252 struct ib_connection *conn = ib_path_get_ownerdata ( path );
00253 struct ib_queue_pair *qp = conn->qp;
00254 union ib_mad mad;
00255 struct ib_cm_connect_request *connect_req =
00256 &mad.cm.cm_data.connect_request;
00257 size_t private_data_len;
00258
00259
00260 if ( rc != 0 ) {
00261 DBGC ( conn, "CM %p path lookup failed: %s\n",
00262 conn, strerror ( rc ) );
00263 conn->op->changed ( ibdev, qp, conn, rc, NULL, 0 );
00264 goto out;
00265 }
00266
00267
00268 memcpy ( &qp->av, av, sizeof ( qp->av ) );
00269
00270
00271 memset ( &mad, 0, sizeof ( mad ) );
00272 mad.hdr.mgmt_class = IB_MGMT_CLASS_CM;
00273 mad.hdr.class_version = IB_CM_CLASS_VERSION;
00274 mad.hdr.method = IB_MGMT_METHOD_SEND;
00275 mad.hdr.attr_id = htons ( IB_CM_ATTR_CONNECT_REQUEST );
00276 connect_req->local_id = htonl ( conn->local_id );
00277 memcpy ( &connect_req->service_id, &conn->service_id,
00278 sizeof ( connect_req->service_id ) );
00279 ib_get_hca_info ( ibdev, &connect_req->local_ca );
00280 connect_req->local_qpn__responder_resources =
00281 htonl ( ( qp->qpn << 8 ) | 1 );
00282 connect_req->local_eecn__initiator_depth = htonl ( ( 0 << 8 ) | 1 );
00283 connect_req->remote_eecn__remote_timeout__service_type__ee_flow_ctrl =
00284 htonl ( ( 0x14 << 3 ) | ( IB_CM_TRANSPORT_RC << 1 ) |
00285 ( 0 << 0 ) );
00286 connect_req->starting_psn__local_timeout__retry_count =
00287 htonl ( ( qp->recv.psn << 8 ) | ( 0x14 << 3 ) |
00288 ( 0x07 << 0 ) );
00289 connect_req->pkey = htons ( ibdev->pkey );
00290 connect_req->payload_mtu__rdc_exists__rnr_retry =
00291 ( ( IB_MTU_2048 << 4 ) | ( 1 << 3 ) | ( 0x07 << 0 ) );
00292 connect_req->max_cm_retries__srq =
00293 ( ( 0x0f << 4 ) | ( 0 << 3 ) );
00294 connect_req->primary.local_lid = htons ( ibdev->lid );
00295 connect_req->primary.remote_lid = htons ( conn->qp->av.lid );
00296 memcpy ( &connect_req->primary.local_gid, &ibdev->gid,
00297 sizeof ( connect_req->primary.local_gid ) );
00298 memcpy ( &connect_req->primary.remote_gid, &conn->qp->av.gid,
00299 sizeof ( connect_req->primary.remote_gid ) );
00300 connect_req->primary.flow_label__rate =
00301 htonl ( ( 0 << 12 ) | ( conn->qp->av.rate << 0 ) );
00302 connect_req->primary.hop_limit = 0;
00303 connect_req->primary.sl__subnet_local =
00304 ( ( conn->qp->av.sl << 4 ) | ( 1 << 3 ) );
00305 connect_req->primary.local_ack_timeout = ( 0x13 << 3 );
00306 private_data_len = conn->private_data_len;
00307 if ( private_data_len > sizeof ( connect_req->private_data ) )
00308 private_data_len = sizeof ( connect_req->private_data );
00309 memcpy ( &connect_req->private_data, &conn->private_data,
00310 private_data_len );
00311
00312
00313 av->qpn = IB_QPN_GSI;
00314 av->qkey = IB_QKEY_GSI;
00315 conn->madx = ib_create_madx ( ibdev, ibdev->gsi, &mad, av,
00316 &ib_cm_req_op );
00317 if ( ! conn->madx ) {
00318 DBGC ( conn, "CM %p could not create connection request\n",
00319 conn );
00320 conn->op->changed ( ibdev, qp, conn, rc, NULL, 0 );
00321 goto out;
00322 }
00323 ib_madx_set_ownerdata ( conn->madx, conn );
00324
00325 out:
00326
00327 ib_destroy_path ( ibdev, path );
00328 conn->path = NULL;
00329 }
00330
00331
00332 static struct ib_path_operations ib_cm_path_op = {
00333 .complete = ib_cm_path_complete,
00334 };
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348 struct ib_connection *
00349 ib_create_conn ( struct ib_device *ibdev, struct ib_queue_pair *qp,
00350 struct ib_gid *dgid, struct ib_gid_half *service_id,
00351 void *private_data, size_t private_data_len,
00352 struct ib_connection_operations *op ) {
00353 struct ib_connection *conn;
00354
00355
00356 conn = zalloc ( sizeof ( *conn ) + private_data_len );
00357 if ( ! conn )
00358 goto err_alloc_conn;
00359 conn->ibdev = ibdev;
00360 conn->qp = qp;
00361 memset ( &qp->av, 0, sizeof ( qp->av ) );
00362 qp->av.gid_present = 1;
00363 memcpy ( &qp->av.gid, dgid, sizeof ( qp->av.gid ) );
00364 conn->local_id = random();
00365 memcpy ( &conn->service_id, service_id, sizeof ( conn->service_id ) );
00366 conn->op = op;
00367 conn->private_data_len = private_data_len;
00368 memcpy ( &conn->private_data, private_data, private_data_len );
00369
00370
00371 conn->path = ib_create_path ( ibdev, &qp->av, &ib_cm_path_op );
00372 if ( ! conn->path )
00373 goto err_create_path;
00374 ib_path_set_ownerdata ( conn->path, conn );
00375
00376
00377 list_add ( &conn->list, &ib_cm_conns );
00378
00379 DBGC ( conn, "CM %p created for IBDEV %p QPN %lx\n",
00380 conn, ibdev, qp->qpn );
00381 DBGC ( conn, "CM %p connecting to %08x:%08x:%08x:%08x %08x:%08x\n",
00382 conn, ntohl ( dgid->u.dwords[0] ), ntohl ( dgid->u.dwords[1] ),
00383 ntohl ( dgid->u.dwords[2] ), ntohl ( dgid->u.dwords[3] ),
00384 ntohl ( service_id->u.dwords[0] ),
00385 ntohl ( service_id->u.dwords[1] ) );
00386
00387 return conn;
00388
00389 ib_destroy_path ( ibdev, conn->path );
00390 err_create_path:
00391 free ( conn );
00392 err_alloc_conn:
00393 return NULL;
00394 }
00395
00396
00397
00398
00399
00400
00401
00402
00403 void ib_destroy_conn ( struct ib_device *ibdev,
00404 struct ib_queue_pair *qp __unused,
00405 struct ib_connection *conn ) {
00406
00407 list_del ( &conn->list );
00408 if ( conn->madx )
00409 ib_destroy_madx ( ibdev, ibdev->gsi, conn->madx );
00410 if ( conn->path )
00411 ib_destroy_path ( ibdev, conn->path );
00412 free ( conn );
00413 }