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 <errno.h>
00025 #include <stdio.h>
00026 #include <unistd.h>
00027 #include <byteswap.h>
00028 #include <gpxe/infiniband.h>
00029 #include <gpxe/iobuf.h>
00030 #include <gpxe/ib_mi.h>
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 #define IB_MI_NUM_SEND_WQES 4
00044
00045
00046
00047
00048
00049 #define IB_MI_NUM_RECV_WQES 2
00050
00051
00052
00053
00054
00055 #define IB_MI_NUM_CQES 8
00056
00057
00058 #define IB_MI_TID_MAGIC ( ( 'g' << 24 ) | ( 'P' << 16 ) | ( 'X' << 8 ) | 'E' )
00059
00060
00061 static unsigned int next_tid;
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072 static int ib_mi_handle ( struct ib_device *ibdev,
00073 struct ib_mad_interface *mi,
00074 union ib_mad *mad,
00075 struct ib_address_vector *av ) {
00076 struct ib_mad_hdr *hdr = &mad->hdr;
00077 struct ib_mad_transaction *madx;
00078 struct ib_mad_agent *agent;
00079
00080
00081 list_for_each_entry ( madx, &mi->madx, list ) {
00082 if ( memcmp ( &hdr->tid, &madx->mad.hdr.tid,
00083 sizeof ( hdr->tid ) ) != 0 )
00084 continue;
00085
00086 madx->op->complete ( ibdev, mi, madx, 0, mad, av );
00087 return 0;
00088 }
00089
00090
00091 for_each_table_entry ( agent, IB_MAD_AGENTS ) {
00092 if ( ( ( agent->mgmt_class & IB_MGMT_CLASS_MASK ) !=
00093 ( hdr->mgmt_class & IB_MGMT_CLASS_MASK ) ) ||
00094 ( agent->class_version != hdr->class_version ) ||
00095 ( agent->attr_id != hdr->attr_id ) )
00096 continue;
00097
00098 agent->handle ( ibdev, mi, mad, av );
00099 return 0;
00100 }
00101
00102
00103 DBGC ( mi, "MI %p RX TID %08x%08x ignored\n",
00104 mi, ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ) );
00105 return -ENOTSUP;
00106 }
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118 static void ib_mi_complete_recv ( struct ib_device *ibdev,
00119 struct ib_queue_pair *qp,
00120 struct ib_address_vector *av,
00121 struct io_buffer *iobuf, int rc ) {
00122 struct ib_mad_interface *mi = ib_qp_get_ownerdata ( qp );
00123 union ib_mad *mad;
00124 struct ib_mad_hdr *hdr;
00125
00126
00127 if ( rc != 0 ) {
00128 DBGC ( mi, "MI %p RX error: %s\n", mi, strerror ( rc ) );
00129 goto out;
00130 }
00131
00132
00133 if ( iob_len ( iobuf ) != sizeof ( *mad ) ) {
00134 DBGC ( mi, "MI %p RX bad size (%zd bytes)\n",
00135 mi, iob_len ( iobuf ) );
00136 DBGC_HDA ( mi, 0, iobuf->data, iob_len ( iobuf ) );
00137 goto out;
00138 }
00139 mad = iobuf->data;
00140 hdr = &mad->hdr;
00141 if ( hdr->base_version != IB_MGMT_BASE_VERSION ) {
00142 DBGC ( mi, "MI %p RX unsupported base version %x\n",
00143 mi, hdr->base_version );
00144 DBGC_HDA ( mi, 0, mad, sizeof ( *mad ) );
00145 goto out;
00146 }
00147 DBGC ( mi, "MI %p RX TID %08x%08x (%02x,%02x,%02x,%04x) status "
00148 "%04x\n", mi, ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ),
00149 hdr->mgmt_class, hdr->class_version, hdr->method,
00150 ntohs ( hdr->attr_id ), ntohs ( hdr->status ) );
00151 DBGC2_HDA ( mi, 0, mad, sizeof ( *mad ) );
00152
00153
00154 if ( ( rc = ib_mi_handle ( ibdev, mi, mad, av ) ) != 0 )
00155 goto out;
00156
00157 out:
00158 free_iob ( iobuf );
00159 }
00160
00161
00162 static struct ib_completion_queue_operations ib_mi_completion_ops = {
00163 .complete_recv = ib_mi_complete_recv,
00164 };
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175 int ib_mi_send ( struct ib_device *ibdev, struct ib_mad_interface *mi,
00176 union ib_mad *mad, struct ib_address_vector *av ) {
00177 struct ib_mad_hdr *hdr = &mad->hdr;
00178 struct io_buffer *iobuf;
00179 int rc;
00180
00181
00182 hdr->base_version = IB_MGMT_BASE_VERSION;
00183 if ( ( hdr->tid[0] == 0 ) && ( hdr->tid[1] == 0 ) ) {
00184 hdr->tid[0] = htonl ( IB_MI_TID_MAGIC );
00185 hdr->tid[1] = htonl ( ++next_tid );
00186 }
00187 DBGC ( mi, "MI %p TX TID %08x%08x (%02x,%02x,%02x,%04x) status "
00188 "%04x\n", mi, ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ),
00189 hdr->mgmt_class, hdr->class_version, hdr->method,
00190 ntohs ( hdr->attr_id ), ntohs ( hdr->status ) );
00191 DBGC2_HDA ( mi, 0, mad, sizeof ( *mad ) );
00192
00193
00194 if ( hdr->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE ) {
00195 struct ib_mad_smp *smp = &mad->smp;
00196 unsigned int hop_pointer;
00197 unsigned int hop_count;
00198
00199 smp->mad_hdr.status |= htons ( IB_SMP_STATUS_D_INBOUND );
00200 hop_pointer = smp->mad_hdr.class_specific.smp.hop_pointer;
00201 hop_count = smp->mad_hdr.class_specific.smp.hop_count;
00202 assert ( hop_count == hop_pointer );
00203 if ( hop_pointer < ( sizeof ( smp->return_path.hops ) /
00204 sizeof ( smp->return_path.hops[0] ) ) ) {
00205 smp->return_path.hops[hop_pointer] = ibdev->port;
00206 } else {
00207 DBGC ( mi, "MI %p TX TID %08x%08x invalid hop pointer "
00208 "%d\n", mi, ntohl ( hdr->tid[0] ),
00209 ntohl ( hdr->tid[1] ), hop_pointer );
00210 return -EINVAL;
00211 }
00212 }
00213
00214
00215 iobuf = alloc_iob ( sizeof ( *mad ) );
00216 if ( ! iobuf ) {
00217 DBGC ( mi, "MI %p could not allocate buffer for TID "
00218 "%08x%08x\n",
00219 mi, ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ) );
00220 return -ENOMEM;
00221 }
00222 memcpy ( iob_put ( iobuf, sizeof ( *mad ) ), mad, sizeof ( *mad ) );
00223
00224
00225 if ( ( rc = ib_post_send ( ibdev, mi->qp, av, iobuf ) ) != 0 ) {
00226 DBGC ( mi, "MI %p TX TID %08x%08x failed: %s\n",
00227 mi, ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ),
00228 strerror ( rc ) );
00229 free_iob ( iobuf );
00230 return rc;
00231 }
00232
00233 return 0;
00234 }
00235
00236
00237
00238
00239
00240
00241
00242 static void ib_mi_timer_expired ( struct retry_timer *timer, int expired ) {
00243 struct ib_mad_transaction *madx =
00244 container_of ( timer, struct ib_mad_transaction, timer );
00245 struct ib_mad_interface *mi = madx->mi;
00246 struct ib_device *ibdev = mi->ibdev;
00247 struct ib_mad_hdr *hdr = &madx->mad.hdr;
00248
00249
00250 if ( expired ) {
00251 DBGC ( mi, "MI %p abandoning TID %08x%08x\n",
00252 mi, ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ) );
00253 madx->op->complete ( ibdev, mi, madx, -ETIMEDOUT, NULL, NULL );
00254 return;
00255 }
00256
00257
00258 start_timer ( timer );
00259
00260
00261 ib_mi_send ( ibdev, mi, &madx->mad, &madx->av );
00262 }
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274 struct ib_mad_transaction *
00275 ib_create_madx ( struct ib_device *ibdev, struct ib_mad_interface *mi,
00276 union ib_mad *mad, struct ib_address_vector *av,
00277 struct ib_mad_transaction_operations *op ) {
00278 struct ib_mad_transaction *madx;
00279
00280
00281 madx = zalloc ( sizeof ( *madx ) );
00282 if ( ! madx )
00283 return NULL;
00284 madx->mi = mi;
00285 madx->timer.expired = ib_mi_timer_expired;
00286 madx->op = op;
00287
00288
00289 if ( av ) {
00290 memcpy ( &madx->av, av, sizeof ( madx->av ) );
00291 } else {
00292 madx->av.lid = ibdev->sm_lid;
00293 madx->av.sl = ibdev->sm_sl;
00294 madx->av.qpn = IB_QPN_GSI;
00295 madx->av.qkey = IB_QKEY_GSI;
00296 }
00297
00298
00299 memcpy ( &madx->mad, mad, sizeof ( madx->mad ) );
00300
00301
00302 list_add ( &madx->list, &mi->madx );
00303 start_timer_nodelay ( &madx->timer );
00304
00305 return madx;
00306 }
00307
00308
00309
00310
00311
00312
00313
00314
00315 void ib_destroy_madx ( struct ib_device *ibdev __unused,
00316 struct ib_mad_interface *mi __unused,
00317 struct ib_mad_transaction *madx ) {
00318
00319
00320 stop_timer ( &madx->timer );
00321 list_del ( &madx->list );
00322
00323
00324 free ( madx );
00325 }
00326
00327
00328
00329
00330
00331
00332
00333
00334 struct ib_mad_interface * ib_create_mi ( struct ib_device *ibdev,
00335 enum ib_queue_pair_type type ) {
00336 struct ib_mad_interface *mi;
00337 int rc;
00338
00339
00340 mi = zalloc ( sizeof ( *mi ) );
00341 if ( ! mi )
00342 goto err_alloc;
00343 mi->ibdev = ibdev;
00344 INIT_LIST_HEAD ( &mi->madx );
00345
00346
00347 mi->cq = ib_create_cq ( ibdev, IB_MI_NUM_CQES, &ib_mi_completion_ops );
00348 if ( ! mi->cq ) {
00349 DBGC ( mi, "MI %p could not allocate completion queue\n", mi );
00350 goto err_create_cq;
00351 }
00352
00353
00354 mi->qp = ib_create_qp ( ibdev, type, IB_MI_NUM_SEND_WQES, mi->cq,
00355 IB_MI_NUM_RECV_WQES, mi->cq );
00356 if ( ! mi->qp ) {
00357 DBGC ( mi, "MI %p could not allocate queue pair\n", mi );
00358 goto err_create_qp;
00359 }
00360 ib_qp_set_ownerdata ( mi->qp, mi );
00361 DBGC ( mi, "MI %p (%s) running on QPN %#lx\n",
00362 mi, ( ( type == IB_QPT_SMI ) ? "SMI" : "GSI" ), mi->qp->qpn );
00363
00364
00365 mi->qp->qkey = ( ( type == IB_QPT_SMI ) ? IB_QKEY_SMI : IB_QKEY_GSI );
00366 if ( ( rc = ib_modify_qp ( ibdev, mi->qp ) ) != 0 ) {
00367 DBGC ( mi, "MI %p could not set queue key: %s\n",
00368 mi, strerror ( rc ) );
00369 goto err_modify_qp;
00370 }
00371
00372
00373 ib_refill_recv ( ibdev, mi->qp );
00374 return mi;
00375
00376 err_modify_qp:
00377 ib_destroy_qp ( ibdev, mi->qp );
00378 err_create_qp:
00379 ib_destroy_cq ( ibdev, mi->cq );
00380 err_create_cq:
00381 free ( mi );
00382 err_alloc:
00383 return NULL;
00384 }
00385
00386
00387
00388
00389
00390
00391 void ib_destroy_mi ( struct ib_device *ibdev, struct ib_mad_interface *mi ) {
00392 struct ib_mad_transaction *madx;
00393 struct ib_mad_transaction *tmp;
00394
00395
00396 list_for_each_entry_safe ( madx, tmp, &mi->madx, list ) {
00397 DBGC ( mi, "MI %p destroyed while TID %08x%08x in progress\n",
00398 mi, ntohl ( madx->mad.hdr.tid[0] ),
00399 ntohl ( madx->mad.hdr.tid[1] ) );
00400 madx->op->complete ( ibdev, mi, madx, -ECANCELED, NULL, NULL );
00401 }
00402
00403 ib_destroy_qp ( ibdev, mi->qp );
00404 ib_destroy_cq ( ibdev, mi->cq );
00405 free ( mi );
00406 }