|
|
1.1 ! root 1: /* ! 2: * Copyright (C) 2009 Michael Brown <[email protected]>. ! 3: * ! 4: * This program is free software; you can redistribute it and/or ! 5: * modify it under the terms of the GNU General Public License as ! 6: * published by the Free Software Foundation; either version 2 of the ! 7: * License, or any later version. ! 8: * ! 9: * This program is distributed in the hope that it will be useful, but ! 10: * WITHOUT ANY WARRANTY; without even the implied warranty of ! 11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 12: * General Public License for more details. ! 13: * ! 14: * You should have received a copy of the GNU General Public License ! 15: * along with this program; if not, write to the Free Software ! 16: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ! 17: */ ! 18: ! 19: FILE_LICENCE ( GPL2_OR_LATER ); ! 20: ! 21: #include <stdint.h> ! 22: #include <stdlib.h> ! 23: #include <string.h> ! 24: #include <byteswap.h> ! 25: #include <errno.h> ! 26: #include <ipxe/infiniband.h> ! 27: #include <ipxe/ib_mi.h> ! 28: #include <ipxe/ib_pathrec.h> ! 29: ! 30: /** @file ! 31: * ! 32: * Infiniband path lookups ! 33: * ! 34: */ ! 35: ! 36: /** ! 37: * Handle path transaction completion ! 38: * ! 39: * @v ibdev Infiniband device ! 40: * @v mi Management interface ! 41: * @v madx Management transaction ! 42: * @v rc Status code ! 43: * @v mad Received MAD (or NULL on error) ! 44: * @v av Source address vector (or NULL on error) ! 45: */ ! 46: static void ib_path_complete ( struct ib_device *ibdev, ! 47: struct ib_mad_interface *mi, ! 48: struct ib_mad_transaction *madx, ! 49: int rc, union ib_mad *mad, ! 50: struct ib_address_vector *av __unused ) { ! 51: struct ib_path *path = ib_madx_get_ownerdata ( madx ); ! 52: union ib_gid *dgid = &path->av.gid; ! 53: struct ib_path_record *pathrec = &mad->sa.sa_data.path_record; ! 54: ! 55: /* Report failures */ ! 56: if ( ( rc == 0 ) && ( mad->hdr.status != htons ( IB_MGMT_STATUS_OK ) )) ! 57: rc = -ENETUNREACH; ! 58: if ( rc != 0 ) { ! 59: DBGC ( ibdev, "IBDEV %p path lookup for " IB_GID_FMT ! 60: " failed: %s\n", ! 61: ibdev, IB_GID_ARGS ( dgid ), strerror ( rc ) ); ! 62: goto out; ! 63: } ! 64: ! 65: /* Extract values from MAD */ ! 66: path->av.lid = ntohs ( pathrec->dlid ); ! 67: path->av.sl = ( pathrec->reserved__sl & 0x0f ); ! 68: path->av.rate = ( pathrec->rate_selector__rate & 0x3f ); ! 69: DBGC ( ibdev, "IBDEV %p path to " IB_GID_FMT " is %04x sl %d rate " ! 70: "%d\n", ibdev, IB_GID_ARGS ( dgid ), path->av.lid, path->av.sl, ! 71: path->av.rate ); ! 72: ! 73: out: ! 74: /* Destroy the completed transaction */ ! 75: ib_destroy_madx ( ibdev, mi, madx ); ! 76: path->madx = NULL; ! 77: ! 78: /* Hand off to upper completion handler */ ! 79: path->op->complete ( ibdev, path, rc, &path->av ); ! 80: } ! 81: ! 82: /** Path transaction completion operations */ ! 83: static struct ib_mad_transaction_operations ib_path_op = { ! 84: .complete = ib_path_complete, ! 85: }; ! 86: ! 87: /** ! 88: * Create path ! 89: * ! 90: * @v ibdev Infiniband device ! 91: * @v av Address vector to complete ! 92: * @v op Path operations ! 93: * @ret path Path ! 94: */ ! 95: struct ib_path * ! 96: ib_create_path ( struct ib_device *ibdev, struct ib_address_vector *av, ! 97: struct ib_path_operations *op ) { ! 98: struct ib_path *path; ! 99: union ib_mad mad; ! 100: struct ib_mad_sa *sa = &mad.sa; ! 101: ! 102: /* Allocate and initialise structure */ ! 103: path = zalloc ( sizeof ( *path ) ); ! 104: if ( ! path ) ! 105: goto err_alloc_path; ! 106: path->ibdev = ibdev; ! 107: memcpy ( &path->av, av, sizeof ( path->av ) ); ! 108: path->op = op; ! 109: ! 110: /* Construct path request */ ! 111: memset ( sa, 0, sizeof ( *sa ) ); ! 112: sa->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM; ! 113: sa->mad_hdr.class_version = IB_SA_CLASS_VERSION; ! 114: sa->mad_hdr.method = IB_MGMT_METHOD_GET; ! 115: sa->mad_hdr.attr_id = htons ( IB_SA_ATTR_PATH_REC ); ! 116: sa->sa_hdr.comp_mask[1] = ! 117: htonl ( IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID ); ! 118: memcpy ( &sa->sa_data.path_record.dgid, &path->av.gid, ! 119: sizeof ( sa->sa_data.path_record.dgid ) ); ! 120: memcpy ( &sa->sa_data.path_record.sgid, &ibdev->gid, ! 121: sizeof ( sa->sa_data.path_record.sgid ) ); ! 122: ! 123: /* Create management transaction */ ! 124: path->madx = ib_create_madx ( ibdev, ibdev->gsi, &mad, NULL, ! 125: &ib_path_op ); ! 126: if ( ! path->madx ) ! 127: goto err_create_madx; ! 128: ib_madx_set_ownerdata ( path->madx, path ); ! 129: ! 130: return path; ! 131: ! 132: ib_destroy_madx ( ibdev, ibdev->gsi, path->madx ); ! 133: err_create_madx: ! 134: free ( path ); ! 135: err_alloc_path: ! 136: return NULL; ! 137: } ! 138: ! 139: /** ! 140: * Destroy path ! 141: * ! 142: * @v ibdev Infiniband device ! 143: * @v path Path ! 144: */ ! 145: void ib_destroy_path ( struct ib_device *ibdev, struct ib_path *path ) { ! 146: ! 147: if ( path->madx ) ! 148: ib_destroy_madx ( ibdev, ibdev->gsi, path->madx ); ! 149: free ( path ); ! 150: } ! 151: ! 152: /** Number of path cache entries ! 153: * ! 154: * Must be a power of two. ! 155: */ ! 156: #define IB_NUM_CACHED_PATHS 4 ! 157: ! 158: /** A cached path */ ! 159: struct ib_cached_path { ! 160: /** Path */ ! 161: struct ib_path *path; ! 162: }; ! 163: ! 164: /** Path cache */ ! 165: static struct ib_cached_path ib_path_cache[IB_NUM_CACHED_PATHS]; ! 166: ! 167: /** Oldest path cache entry index */ ! 168: static unsigned int ib_path_cache_idx; ! 169: ! 170: /** ! 171: * Find path cache entry ! 172: * ! 173: * @v ibdev Infiniband device ! 174: * @v dgid Destination GID ! 175: * @ret path Path cache entry, or NULL ! 176: */ ! 177: static struct ib_cached_path * ! 178: ib_find_path_cache_entry ( struct ib_device *ibdev, union ib_gid *dgid ) { ! 179: struct ib_cached_path *cached; ! 180: unsigned int i; ! 181: ! 182: for ( i = 0 ; i < IB_NUM_CACHED_PATHS ; i++ ) { ! 183: cached = &ib_path_cache[i]; ! 184: if ( ! cached->path ) ! 185: continue; ! 186: if ( cached->path->ibdev != ibdev ) ! 187: continue; ! 188: if ( memcmp ( &cached->path->av.gid, dgid, ! 189: sizeof ( cached->path->av.gid ) ) != 0 ) ! 190: continue; ! 191: return cached; ! 192: } ! 193: ! 194: return NULL; ! 195: } ! 196: ! 197: /** ! 198: * Handle cached path transaction completion ! 199: * ! 200: * @v ibdev Infiniband device ! 201: * @v path Path ! 202: * @v rc Status code ! 203: * @v av Address vector, or NULL on error ! 204: */ ! 205: static void ib_cached_path_complete ( struct ib_device *ibdev, ! 206: struct ib_path *path, int rc, ! 207: struct ib_address_vector *av __unused ) { ! 208: struct ib_cached_path *cached = ib_path_get_ownerdata ( path ); ! 209: ! 210: /* If the transaction failed, erase the cache entry */ ! 211: if ( rc != 0 ) { ! 212: /* Destroy the old cache entry */ ! 213: ib_destroy_path ( ibdev, path ); ! 214: memset ( cached, 0, sizeof ( *cached ) ); ! 215: return; ! 216: } ! 217: ! 218: /* Do not destroy the completed transaction; we still need to ! 219: * refer to the resolved path. ! 220: */ ! 221: } ! 222: ! 223: /** Cached path transaction completion operations */ ! 224: static struct ib_path_operations ib_cached_path_op = { ! 225: .complete = ib_cached_path_complete, ! 226: }; ! 227: ! 228: /** ! 229: * Resolve path ! 230: * ! 231: * @v ibdev Infiniband device ! 232: * @v av Address vector to complete ! 233: * @ret rc Return status code ! 234: * ! 235: * This provides a non-transactional way to resolve a path, via a ! 236: * cache similar to ARP. ! 237: */ ! 238: int ib_resolve_path ( struct ib_device *ibdev, struct ib_address_vector *av ) { ! 239: union ib_gid *gid = &av->gid; ! 240: struct ib_cached_path *cached; ! 241: unsigned int cache_idx; ! 242: ! 243: /* Sanity check */ ! 244: if ( ! av->gid_present ) { ! 245: DBGC ( ibdev, "IBDEV %p attempt to look up path without GID\n", ! 246: ibdev ); ! 247: return -EINVAL; ! 248: } ! 249: ! 250: /* Look in cache for a matching entry */ ! 251: cached = ib_find_path_cache_entry ( ibdev, gid ); ! 252: if ( cached && cached->path->av.lid ) { ! 253: /* Populated entry found */ ! 254: av->lid = cached->path->av.lid; ! 255: av->rate = cached->path->av.rate; ! 256: av->sl = cached->path->av.sl; ! 257: DBGC2 ( ibdev, "IBDEV %p cache hit for " IB_GID_FMT "\n", ! 258: ibdev, IB_GID_ARGS ( gid ) ); ! 259: return 0; ! 260: } ! 261: DBGC ( ibdev, "IBDEV %p cache miss for " IB_GID_FMT "%s\n", ibdev, ! 262: IB_GID_ARGS ( gid ), ( cached ? " (in progress)" : "" ) ); ! 263: ! 264: /* If lookup is already in progress, do nothing */ ! 265: if ( cached ) ! 266: return -ENOENT; ! 267: ! 268: /* Locate a new cache entry to use */ ! 269: cache_idx = ( (ib_path_cache_idx++) % IB_NUM_CACHED_PATHS ); ! 270: cached = &ib_path_cache[cache_idx]; ! 271: ! 272: /* Destroy the old cache entry */ ! 273: if ( cached->path ) ! 274: ib_destroy_path ( ibdev, cached->path ); ! 275: memset ( cached, 0, sizeof ( *cached ) ); ! 276: ! 277: /* Create new path */ ! 278: cached->path = ib_create_path ( ibdev, av, &ib_cached_path_op ); ! 279: if ( ! cached->path ) { ! 280: DBGC ( ibdev, "IBDEV %p could not create path\n", ! 281: ibdev ); ! 282: return -ENOMEM; ! 283: } ! 284: ib_path_set_ownerdata ( cached->path, cached ); ! 285: ! 286: /* Not found yet */ ! 287: return -ENOENT; ! 288: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.