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 <gpxe/infiniband.h>
00027 #include <gpxe/ib_mi.h>
00028 #include <gpxe/ib_pathrec.h>
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 static void ib_path_complete ( struct ib_device *ibdev,
00047 struct ib_mad_interface *mi,
00048 struct ib_mad_transaction *madx,
00049 int rc, union ib_mad *mad,
00050 struct ib_address_vector *av __unused ) {
00051 struct ib_path *path = ib_madx_get_ownerdata ( madx );
00052 struct ib_gid *dgid = &path->av.gid;
00053 struct ib_path_record *pathrec = &mad->sa.sa_data.path_record;
00054
00055
00056 if ( ( rc == 0 ) && ( mad->hdr.status != htons ( IB_MGMT_STATUS_OK ) ))
00057 rc = -ENETUNREACH;
00058 if ( rc != 0 ) {
00059 DBGC ( ibdev, "IBDEV %p path lookup for %08x:%08x:%08x:%08x "
00060 "failed: %s\n", ibdev, htonl ( dgid->u.dwords[0] ),
00061 htonl ( dgid->u.dwords[1] ),
00062 htonl ( dgid->u.dwords[2] ),
00063 htonl ( dgid->u.dwords[3] ), strerror ( rc ) );
00064 goto out;
00065 }
00066
00067
00068 path->av.lid = ntohs ( pathrec->dlid );
00069 path->av.sl = ( pathrec->reserved__sl & 0x0f );
00070 path->av.rate = ( pathrec->rate_selector__rate & 0x3f );
00071 DBGC ( ibdev, "IBDEV %p path to %08x:%08x:%08x:%08x is %04x sl %d "
00072 "rate %d\n", ibdev, htonl ( dgid->u.dwords[0] ),
00073 htonl ( dgid->u.dwords[1] ), htonl ( dgid->u.dwords[2] ),
00074 htonl ( dgid->u.dwords[3] ), path->av.lid, path->av.sl,
00075 path->av.rate );
00076
00077 out:
00078
00079 ib_destroy_madx ( ibdev, mi, madx );
00080 path->madx = NULL;
00081
00082
00083 path->op->complete ( ibdev, path, rc, &path->av );
00084 }
00085
00086
00087 static struct ib_mad_transaction_operations ib_path_op = {
00088 .complete = ib_path_complete,
00089 };
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099 struct ib_path *
00100 ib_create_path ( struct ib_device *ibdev, struct ib_address_vector *av,
00101 struct ib_path_operations *op ) {
00102 struct ib_path *path;
00103 union ib_mad mad;
00104 struct ib_mad_sa *sa = &mad.sa;
00105
00106
00107 path = zalloc ( sizeof ( *path ) );
00108 if ( ! path )
00109 goto err_alloc_path;
00110 path->ibdev = ibdev;
00111 memcpy ( &path->av, av, sizeof ( path->av ) );
00112 path->op = op;
00113
00114
00115 memset ( sa, 0, sizeof ( *sa ) );
00116 sa->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM;
00117 sa->mad_hdr.class_version = IB_SA_CLASS_VERSION;
00118 sa->mad_hdr.method = IB_MGMT_METHOD_GET;
00119 sa->mad_hdr.attr_id = htons ( IB_SA_ATTR_PATH_REC );
00120 sa->sa_hdr.comp_mask[1] =
00121 htonl ( IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID );
00122 memcpy ( &sa->sa_data.path_record.dgid, &path->av.gid,
00123 sizeof ( sa->sa_data.path_record.dgid ) );
00124 memcpy ( &sa->sa_data.path_record.sgid, &ibdev->gid,
00125 sizeof ( sa->sa_data.path_record.sgid ) );
00126
00127
00128 path->madx = ib_create_madx ( ibdev, ibdev->gsi, &mad, NULL,
00129 &ib_path_op );
00130 if ( ! path->madx )
00131 goto err_create_madx;
00132 ib_madx_set_ownerdata ( path->madx, path );
00133
00134 return path;
00135
00136 ib_destroy_madx ( ibdev, ibdev->gsi, path->madx );
00137 err_create_madx:
00138 free ( path );
00139 err_alloc_path:
00140 return NULL;
00141 }
00142
00143
00144
00145
00146
00147
00148
00149 void ib_destroy_path ( struct ib_device *ibdev, struct ib_path *path ) {
00150
00151 if ( path->madx )
00152 ib_destroy_madx ( ibdev, ibdev->gsi, path->madx );
00153 free ( path );
00154 }
00155
00156
00157
00158
00159
00160 #define IB_NUM_CACHED_PATHS 4
00161
00162
00163 struct ib_cached_path {
00164
00165 struct ib_path *path;
00166 };
00167
00168
00169 static struct ib_cached_path ib_path_cache[IB_NUM_CACHED_PATHS];
00170
00171
00172 static unsigned int ib_path_cache_idx;
00173
00174
00175
00176
00177
00178
00179
00180
00181 static struct ib_cached_path *
00182 ib_find_path_cache_entry ( struct ib_device *ibdev, struct ib_gid *dgid ) {
00183 struct ib_cached_path *cached;
00184 unsigned int i;
00185
00186 for ( i = 0 ; i < IB_NUM_CACHED_PATHS ; i++ ) {
00187 cached = &ib_path_cache[i];
00188 if ( ! cached->path )
00189 continue;
00190 if ( cached->path->ibdev != ibdev )
00191 continue;
00192 if ( memcmp ( &cached->path->av.gid, dgid,
00193 sizeof ( cached->path->av.gid ) ) != 0 )
00194 continue;
00195 return cached;
00196 }
00197
00198 return NULL;
00199 }
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209 static void ib_cached_path_complete ( struct ib_device *ibdev,
00210 struct ib_path *path, int rc,
00211 struct ib_address_vector *av __unused ) {
00212 struct ib_cached_path *cached = ib_path_get_ownerdata ( path );
00213
00214
00215 if ( rc != 0 ) {
00216
00217 ib_destroy_path ( ibdev, path );
00218 memset ( cached, 0, sizeof ( *cached ) );
00219 return;
00220 }
00221
00222
00223
00224
00225 }
00226
00227
00228 static struct ib_path_operations ib_cached_path_op = {
00229 .complete = ib_cached_path_complete,
00230 };
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242 int ib_resolve_path ( struct ib_device *ibdev, struct ib_address_vector *av ) {
00243 struct ib_gid *gid = &av->gid;
00244 struct ib_cached_path *cached;
00245 unsigned int cache_idx;
00246
00247
00248 if ( ! av->gid_present ) {
00249 DBGC ( ibdev, "IBDEV %p attempt to look up path "
00250 "without GID\n", ibdev );
00251 return -EINVAL;
00252 }
00253
00254
00255 cached = ib_find_path_cache_entry ( ibdev, gid );
00256 if ( cached && cached->path->av.lid ) {
00257
00258 av->lid = cached->path->av.lid;
00259 av->rate = cached->path->av.rate;
00260 av->sl = cached->path->av.sl;
00261 DBGC2 ( ibdev, "IBDEV %p cache hit for %08x:%08x:%08x:%08x\n",
00262 ibdev, htonl ( gid->u.dwords[0] ),
00263 htonl ( gid->u.dwords[1] ), htonl ( gid->u.dwords[2] ),
00264 htonl ( gid->u.dwords[3] ) );
00265 return 0;
00266 }
00267 DBGC ( ibdev, "IBDEV %p cache miss for %08x:%08x:%08x:%08x%s\n",
00268 ibdev, htonl ( gid->u.dwords[0] ), htonl ( gid->u.dwords[1] ),
00269 htonl ( gid->u.dwords[2] ), htonl ( gid->u.dwords[3] ),
00270 ( cached ? " (in progress)" : "" ) );
00271
00272
00273 if ( cached )
00274 return -ENOENT;
00275
00276
00277 cache_idx = ( (ib_path_cache_idx++) % IB_NUM_CACHED_PATHS );
00278 cached = &ib_path_cache[cache_idx];
00279
00280
00281 if ( cached->path )
00282 ib_destroy_path ( ibdev, cached->path );
00283 memset ( cached, 0, sizeof ( *cached ) );
00284
00285
00286 cached->path = ib_create_path ( ibdev, av, &ib_cached_path_op );
00287 if ( ! cached->path ) {
00288 DBGC ( ibdev, "IBDEV %p could not create path\n",
00289 ibdev );
00290 return -ENOMEM;
00291 }
00292 ib_path_set_ownerdata ( cached->path, cached );
00293
00294
00295 return -ENOENT;
00296 }